drivers/scsi/fdomain.c

Source file repositories/reference/linux-study-clean/drivers/scsi/fdomain.c

File Facts

System
Linux kernel
Corpus path
drivers/scsi/fdomain.c
Extension
.c
Size
16698 bytes
Lines
609
Domain
Driver Families
Bucket
drivers/scsi
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct fdomain {
	int base;
	struct scsi_cmnd *cur_cmd;
	enum chip_type chip;
	struct work_struct work;
};

static struct scsi_pointer *fdomain_scsi_pointer(struct scsi_cmnd *cmd)
{
	return scsi_cmd_priv(cmd);
}

static inline void fdomain_make_bus_idle(struct fdomain *fd)
{
	outb(0, fd->base + REG_BCTL);
	outb(0, fd->base + REG_MCTL);
	if (fd->chip == tmc18c50 || fd->chip == tmc18c30)
		/* Clear forced intr. */
		outb(ACTL_RESET | ACTL_CLRFIRQ | PARITY_MASK,
		     fd->base + REG_ACTL);
	else
		outb(ACTL_RESET | PARITY_MASK, fd->base + REG_ACTL);
}

static enum chip_type fdomain_identify(int port)
{
	u16 id = inb(port + REG_ID_LSB) | inb(port + REG_ID_MSB) << 8;

	switch (id) {
	case 0x6127:
		return tmc1800;
	case 0x60e9: /* 18c50 or 18c30 */
		break;
	default:
		return unknown;
	}

	/* Try to toggle 32-bit mode. This only works on an 18c30 chip. */
	outb(CFG2_32BIT, port + REG_CFG2);
	if ((inb(port + REG_CFG2) & CFG2_32BIT)) {
		outb(0, port + REG_CFG2);
		if ((inb(port + REG_CFG2) & CFG2_32BIT) == 0)
			return tmc18c30;
	}
	/* If that failed, we are an 18c50. */
	return tmc18c50;
}

static int fdomain_test_loopback(int base)
{
	int i;

	for (i = 0; i < 255; i++) {
		outb(i, base + REG_LOOPBACK);
		if (inb(base + REG_LOOPBACK) != i)
			return 1;
	}

	return 0;
}

static void fdomain_reset(int base)
{
	outb(BCTL_RST, base + REG_BCTL);
	mdelay(20);
	outb(0, base + REG_BCTL);
	mdelay(1150);
	outb(0, base + REG_MCTL);
	outb(PARITY_MASK, base + REG_ACTL);
}

static int fdomain_select(struct Scsi_Host *sh, int target)
{
	int status;
	unsigned long timeout;
	struct fdomain *fd = shost_priv(sh);

	outb(BCTL_BUSEN | BCTL_SEL, fd->base + REG_BCTL);
	outb(BIT(sh->this_id) | BIT(target), fd->base + REG_SCSI_DATA_NOACK);

	/* Stop arbitration and enable parity */
	outb(PARITY_MASK, fd->base + REG_ACTL);

	timeout = 350;	/* 350 msec */

	do {
		status = inb(fd->base + REG_BSTAT);
		if (status & BSTAT_BSY) {
			/* Enable SCSI Bus */
			/* (on error, should make bus idle with 0) */

Annotation

Implementation Notes