in2000.c

来自「linux 内核源代码」· C语言 代码 · 共 2,045 行 · 第 1/5 页

C
2,045
字号
		write2_io(*sp++, IO_FIFO);#endif}/* We need to use spin_lock_irqsave() & spin_unlock_irqrestore() in this * function in order to work in an SMP environment. (I'd be surprised * if the driver is ever used by anyone on a real multi-CPU motherboard, * but it _does_ need to be able to compile and run in an SMP kernel.) */static irqreturn_t in2000_intr(int irqnum, void *dev_id){	struct Scsi_Host *instance = dev_id;	struct IN2000_hostdata *hostdata;	Scsi_Cmnd *patch, *cmd;	uchar asr, sr, phs, id, lun, *ucp, msg;	int i, j;	unsigned long length;	unsigned short *sp;	unsigned short f;	unsigned long flags;	hostdata = (struct IN2000_hostdata *) instance->hostdata;/* Get the spin_lock and disable further ints, for SMP */	spin_lock_irqsave(instance->host_lock, flags);#ifdef PROC_STATISTICS	hostdata->int_cnt++;#endif/* The IN2000 card has 2 interrupt sources OR'ed onto its IRQ line - the * WD3393 chip and the 2k fifo (which is actually a dual-port RAM combined * with a big logic array, so it's a little different than what you might * expect). As far as I know, there's no reason that BOTH can't be active * at the same time, but there's a problem: while we can read the 3393 * to tell if _it_ wants an interrupt, I don't know of a way to ask the * fifo the same question. The best we can do is check the 3393 and if * it _isn't_ the source of the interrupt, then we can be pretty sure * that the fifo is the culprit. *  UPDATE: I have it on good authority (Bill Earnest) that bit 0 of the *          IO_FIFO_COUNT register mirrors the fifo interrupt state. I *          assume that bit clear means interrupt active. As it turns *          out, the driver really doesn't need to check for this after *          all, so my remarks above about a 'problem' can safely be *          ignored. The way the logic is set up, there's no advantage *          (that I can see) to worrying about it. * * It seems that the fifo interrupt signal is negated when we extract * bytes during read or write bytes during write. *  - fifo will interrupt when data is moving from it to the 3393, and *    there are 31 (or less?) bytes left to go. This is sort of short- *    sighted: what if you don't WANT to do more? In any case, our *    response is to push more into the fifo - either actual data or *    dummy bytes if need be. Note that we apparently have to write at *    least 32 additional bytes to the fifo after an interrupt in order *    to get it to release the ones it was holding on to - writing fewer *    than 32 will result in another fifo int. *  UPDATE: Again, info from Bill Earnest makes this more understandable: *          32 bytes = two counts of the fifo counter register. He tells *          me that the fifo interrupt is a non-latching signal derived *          from a straightforward boolean interpretation of the 7 *          highest bits of the fifo counter and the fifo-read/fifo-write *          state. Who'd a thought? */	write1_io(0, IO_LED_ON);	asr = READ_AUX_STAT();	if (!(asr & ASR_INT)) {	/* no WD33c93 interrupt? *//* Ok. This is definitely a FIFO-only interrupt. * * If FI_FIFO_READING is set, there are up to 2048 bytes waiting to be read, * maybe more to come from the SCSI bus. Read as many as we can out of the * fifo and into memory at the location of SCp.ptr[SCp.have_data_in], and * update have_data_in afterwards. * * If we have FI_FIFO_WRITING, the FIFO has almost run out of bytes to move * into the WD3393 chip (I think the interrupt happens when there are 31 * bytes left, but it may be fewer...). The 3393 is still waiting, so we * shove some more into the fifo, which gets things moving again. If the * original SCSI command specified more than 2048 bytes, there may still * be some of that data left: fine - use it (from SCp.ptr[SCp.have_data_in]). * Don't forget to update have_data_in. If we've already written out the * entire buffer, feed 32 dummy bytes to the fifo - they're needed to * push out the remaining real data. *    (Big thanks to Bill Earnest for getting me out of the mud in here.) */		cmd = (Scsi_Cmnd *) hostdata->connected;	/* assume we're connected */		CHECK_NULL(cmd, "fifo_int")		    if (hostdata->fifo == FI_FIFO_READING) {			DB(DB_FIFO, printk("{R:%02x} ", read1_io(IO_FIFO_COUNT)))			    sp = (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);			i = read1_io(IO_FIFO_COUNT) & 0xfe;			i <<= 2;	/* # of words waiting in the fifo */			f = hostdata->io_base + IO_FIFO;#ifdef FAST_READ_IO			FAST_READ2_IO();#else			while (i--)				*sp++ = read2_io(IO_FIFO);#endif			i = sp - (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);			i <<= 1;			cmd->SCp.have_data_in += i;		}		else if (hostdata->fifo == FI_FIFO_WRITING) {			DB(DB_FIFO, printk("{W:%02x} ", read1_io(IO_FIFO_COUNT)))/* If all bytes have been written to the fifo, flush out the stragglers. * Note that while writing 16 dummy words seems arbitrary, we don't * have another choice that I can see. What we really want is to read * the 3393 transfer count register (that would tell us how many bytes * needed flushing), but the TRANSFER_INFO command hasn't completed * yet (not enough bytes!) and that register won't be accessible. So, * we use 16 words - a number obtained through trial and error. *  UPDATE: Bill says this is exactly what Always does, so there. *          More thanks due him for help in this section. */			    if (cmd->SCp.this_residual == cmd->SCp.have_data_in) {				i = 16;				while (i--)	/* write 32 dummy bytes */					write2_io(0, IO_FIFO);			}/* If there are still bytes left in the SCSI buffer, write as many as we * can out to the fifo. */			else {				sp = (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);				i = cmd->SCp.this_residual - cmd->SCp.have_data_in;	/* bytes yet to go */				j = read1_io(IO_FIFO_COUNT) & 0xfe;				j <<= 2;	/* how many words the fifo has room for */				if ((j << 1) > i)					j = (i >> 1);				while (j--)					write2_io(*sp++, IO_FIFO);				i = sp - (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);				i <<= 1;				cmd->SCp.have_data_in += i;			}		}		else {			printk("*** Spurious FIFO interrupt ***");		}		write1_io(0, IO_LED_OFF);/* release the SMP spin_lock and restore irq state */		spin_unlock_irqrestore(instance->host_lock, flags);		return IRQ_HANDLED;	}/* This interrupt was triggered by the WD33c93 chip. The fifo interrupt * may also be asserted, but we don't bother to check it: we get more * detailed info from FIFO_READING and FIFO_WRITING (see below). */	cmd = (Scsi_Cmnd *) hostdata->connected;	/* assume we're connected */	sr = read_3393(hostdata, WD_SCSI_STATUS);	/* clear the interrupt */	phs = read_3393(hostdata, WD_COMMAND_PHASE);	if (!cmd && (sr != CSR_RESEL_AM && sr != CSR_TIMEOUT && sr != CSR_SELECT)) {		printk("\nNR:wd-intr-1\n");		write1_io(0, IO_LED_OFF);/* release the SMP spin_lock and restore irq state */		spin_unlock_irqrestore(instance->host_lock, flags);		return IRQ_HANDLED;	}	DB(DB_INTR, printk("{%02x:%02x-", asr, sr))/* After starting a FIFO-based transfer, the next _WD3393_ interrupt is * guaranteed to be in response to the completion of the transfer. * If we were reading, there's probably data in the fifo that needs * to be copied into RAM - do that here. Also, we have to update * 'this_residual' and 'ptr' based on the contents of the * TRANSFER_COUNT register, in case the device decided to do an * intermediate disconnect (a device may do this if it has to * do a seek,  or just to be nice and let other devices have * some bus time during long transfers). * After doing whatever is necessary with the fifo, we go on and * service the WD3393 interrupt normally. */	    if (hostdata->fifo == FI_FIFO_READING) {/* buffer index = start-of-buffer + #-of-bytes-already-read */		sp = (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);/* bytes remaining in fifo = (total-wanted - #-not-got) - #-already-read */		i = (cmd->SCp.this_residual - read_3393_count(hostdata)) - cmd->SCp.have_data_in;		i >>= 1;	/* Gulp. We assume this will always be modulo 2 */		f = hostdata->io_base + IO_FIFO;#ifdef FAST_READ_IO		FAST_READ2_IO();#else		while (i--)			*sp++ = read2_io(IO_FIFO);#endif		hostdata->fifo = FI_FIFO_UNUSED;		length = cmd->SCp.this_residual;		cmd->SCp.this_residual = read_3393_count(hostdata);		cmd->SCp.ptr += (length - cmd->SCp.this_residual);		DB(DB_TRANSFER, printk("(%p,%d)", cmd->SCp.ptr, cmd->SCp.this_residual))	}	else if (hostdata->fifo == FI_FIFO_WRITING) {		hostdata->fifo = FI_FIFO_UNUSED;		length = cmd->SCp.this_residual;		cmd->SCp.this_residual = read_3393_count(hostdata);		cmd->SCp.ptr += (length - cmd->SCp.this_residual);		DB(DB_TRANSFER, printk("(%p,%d)", cmd->SCp.ptr, cmd->SCp.this_residual))	}/* Respond to the specific WD3393 interrupt - there are quite a few! */	switch (sr) {	case CSR_TIMEOUT:		DB(DB_INTR, printk("TIMEOUT"))		    if (hostdata->state == S_RUNNING_LEVEL2)			hostdata->connected = NULL;		else {			cmd = (Scsi_Cmnd *) hostdata->selecting;	/* get a valid cmd */			CHECK_NULL(cmd, "csr_timeout")			    hostdata->selecting = NULL;		}		cmd->result = DID_NO_CONNECT << 16;		hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);		hostdata->state = S_UNCONNECTED;		cmd->scsi_done(cmd);/* We are not connected to a target - check to see if there * are commands waiting to be executed. */		in2000_execute(instance);		break;/* Note: this interrupt should not occur in a LEVEL2 command */	case CSR_SELECT:		DB(DB_INTR, printk("SELECT"))		    hostdata->connected = cmd = (Scsi_Cmnd *) hostdata->selecting;		CHECK_NULL(cmd, "csr_select")		    hostdata->selecting = NULL;		/* construct an IDENTIFY message with correct disconnect bit */		hostdata->outgoing_msg[0] = (0x80 | 0x00 | cmd->device->lun);		if (cmd->SCp.phase)			hostdata->outgoing_msg[0] |= 0x40;		if (hostdata->sync_stat[cmd->device->id] == SS_FIRST) {#ifdef SYNC_DEBUG			printk(" sending SDTR ");#endif			hostdata->sync_stat[cmd->device->id] = SS_WAITING;			/* tack on a 2nd message to ask about synchronous transfers */			hostdata->outgoing_msg[1] = EXTENDED_MESSAGE;			hostdata->outgoing_msg[2] = 3;			hostdata->outgoing_msg[3] = EXTENDED_SDTR;			hostdata->outgoing_msg[4] = OPTIMUM_SX_PER / 4;			hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF;			hostdata->outgoing_len = 6;		} else			hostdata->outgoing_len = 1;		hostdata->state = S_CONNECTED;		break;	case CSR_XFER_DONE | PHS_DATA_IN:	case CSR_UNEXP | PHS_DATA_IN:	case CSR_SRV_REQ | PHS_DATA_IN:		DB(DB_INTR, printk("IN-%d.%d", cmd->SCp.this_residual, cmd->SCp.buffers_residual))		    transfer_bytes(cmd, DATA_IN_DIR);		if (hostdata->state != S_RUNNING_LEVEL2)			hostdata->state = S_CONNECTED;		break;	case CSR_XFER_DONE | PHS_DATA_OUT:	case CSR_UNEXP | PHS_DATA_OUT:	case CSR_SRV_REQ | PHS_DATA_OUT:		DB(DB_INTR, printk("OUT-%d.%d", cmd->SCp.this_residual, cmd->SCp.buffers_residual))		    transfer_bytes(cmd, DATA_OUT_DIR);		if (hostdata->state != S_RUNNING_LEVEL2)			hostdata->state = S_CONNECTED;		break;/* Note: this interrupt should not occur in a LEVEL2 command */	case CSR_XFER_DONE | PHS_COMMAND:	case CSR_UNEXP | PHS_COMMAND:	case CSR_SRV_REQ | PHS_COMMAND:		DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->serial_number))		    transfer_pio(cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata);		hostdata->state = S_CONNECTED;		break;	case CSR_XFER_DONE | PHS_STATUS:	case CSR_UNEXP | PHS_STATUS:	case CSR_SRV_REQ | PHS_STATUS:		DB(DB_INTR, printk("STATUS="))		    cmd->SCp.Status = read_1_byte(hostdata);		DB(DB_INTR, printk("%02x", cmd->SCp.Status))		    if (hostdata->level2 >= L2_BASIC) {			sr = read_3393(hostdata, WD_SCSI_STATUS);	/* clear interrupt */			hostdata->state = S_RUNNING_LEVEL2;			write_3393(hostdata, WD_COMMAND_PHASE, 0x50);			write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);		} else {			hostdata->state = S_CONNECTED;		}		break;	case CSR_XFER_DONE | PHS_MESS_IN:	case CSR_UNEXP | PHS_MESS_IN:	case CSR_SRV_REQ | PHS_MESS_IN:		DB(DB_INTR, printk("MSG_IN="))		    msg = read_1_byte(hostdata);		sr = read_3393(hostdata, WD_SCSI_STATUS);	/* clear interrupt */		hostdata->incoming_msg[hostdata->incoming_ptr] = msg;		if (hostdata->incoming_msg[0] == EXTENDED_MESSAGE)			msg = EXTENDED_MESSAGE;		else			hostdata->incoming_ptr = 0;		cmd->SCp.Message = msg;		switch (msg) {		case COMMAND_COMPLETE:			DB(DB_INTR, printk("CCMP-%ld", cmd->serial_number))			    write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);			hostdata->state = S_PRE_CMP_DISC;			break;		case SAVE_POINTERS:			DB(DB_INTR, printk("SDP"))			    write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);			hostdata->state = S_CONNECTED;			break;		case RESTORE_POINTERS:			DB(DB_INTR, printk("RDP"))			    if (hostdata->level2 >= L2_BASIC) {				write_3393(hostdata, WD_COMMAND_PHASE, 0x45);				write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);				hostdata->state = S_RUNNING_LEVEL2;			} else {				write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);				hostdata->state = S_CONNECTED;			}			break;		case DISCONNECT:			DB(DB_INTR, printk("DIS"))			    cmd->device->disconnect = 1;			write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);			hostdata->state = S_PRE_TMP_DISC;			break;		case MESSAGE_REJECT:			DB(DB_INTR, printk("REJ"))#ifdef SYNC_DEBUG			    printk("-REJ-");#endif			if (hostdata->sync_stat[cmd->device->id] == SS_WAITING)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?