drivers/scsi/wd33c93.c

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

File Facts

System
Linux kernel
Corpus path
drivers/scsi/wd33c93.c
Extension
.c
Size
65811 bytes
Lines
2146
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

if (scsi_pointer->phase == 0 && hostdata->no_dma == 0) {
			if (hostdata->dma_setup(cmd,
			    (cmd->sc_data_direction == DMA_TO_DEVICE) ?
			     DATA_OUT_DIR : DATA_IN_DIR))
				write_wd33c93_count(regs, 0);	/* guarantee a DATA_PHASE interrupt */
			else {
				write_wd33c93_count(regs,
						scsi_pointer->this_residual);
				write_wd33c93(regs, WD_CONTROL,
					      CTRL_IDI | CTRL_EDI | hostdata->dma_mode);
				hostdata->dma = D_DMA_RUNNING;
			}
		} else
			write_wd33c93_count(regs, 0);	/* guarantee a DATA_PHASE interrupt */

		hostdata->state = S_RUNNING_LEVEL2;
		write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
	}

	/*
	 * Since the SCSI bus can handle only 1 connection at a time,
	 * we get out of here now. If the selection fails, or when
	 * the command disconnects, we'll come back to this routine
	 * to search the input_Q again...
	 */

	DB(DB_EXECUTE,
	   printk("%s)EX-2 ", scsi_pointer->phase ? "d:" : ""))
}

static void
transfer_pio(const wd33c93_regs regs, uchar * buf, int cnt,
	     int data_in_dir, struct WD33C93_hostdata *hostdata)
{
	uchar asr;

	DB(DB_TRANSFER,
	   printk("(%p,%d,%s:", buf, cnt, data_in_dir ? "in" : "out"))

	write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
	write_wd33c93_count(regs, cnt);
	write_wd33c93_cmd(regs, WD_CMD_TRANS_INFO);
	if (data_in_dir) {
		do {
			asr = read_aux_stat(regs);
			if (asr & ASR_DBR)
				*buf++ = read_wd33c93(regs, WD_DATA);
		} while (!(asr & ASR_INT));
	} else {
		do {
			asr = read_aux_stat(regs);
			if (asr & ASR_DBR)
				write_wd33c93(regs, WD_DATA, *buf++);
		} while (!(asr & ASR_INT));
	}

	/* Note: we are returning with the interrupt UN-cleared.
	 * Since (presumably) an entire I/O operation has
	 * completed, the bus phase is probably different, and
	 * the interrupt routine will discover this when it
	 * responds to the uncleared int.
	 */

}

static void
transfer_bytes(const wd33c93_regs regs, struct scsi_cmnd *cmd,
		int data_in_dir)
{
	struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(cmd);
	struct WD33C93_hostdata *hostdata;
	unsigned long length;

	hostdata = (struct WD33C93_hostdata *) cmd->device->host->hostdata;

/* Normally, you'd expect 'this_residual' to be non-zero here.
 * In a series of scatter-gather transfers, however, this
 * routine will usually be called with 'this_residual' equal
 * to 0 and 'buffers_residual' non-zero. This means that a
 * previous transfer completed, clearing 'this_residual', and
 * now we need to setup the next scatter-gather buffer as the
 * source or destination for THIS transfer.
 */
	if (!scsi_pointer->this_residual && scsi_pointer->buffers_residual) {
		scsi_pointer->buffer = sg_next(scsi_pointer->buffer);
		--scsi_pointer->buffers_residual;
		scsi_pointer->this_residual = scsi_pointer->buffer->length;
		scsi_pointer->ptr = sg_virt(scsi_pointer->buffer);
	}
	if (!scsi_pointer->this_residual) /* avoid bogus setups */

Annotation

Implementation Notes