📄 in2000.c
字号:
write_3393(hostdata,WD_SYNCHRONOUS_TRANSFER,hostdata->sync_xfer[cmd->target]); write_3393_count(hostdata,cmd->SCp.this_residual); write_3393(hostdata,WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_BUS); write1_io(0,IO_FIFO_WRITE); /* zero counter, assume write *//* Reading is easy. Just issue the command and return - we'll * get an interrupt later when we have actual data to worry about. */ if (data_in_dir) { write1_io(0,IO_FIFO_READ); if ((hostdata->level2 >= L2_DATA) || (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) { 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_TRANS_INFO); hostdata->fifo = FI_FIFO_READING; cmd->SCp.have_data_in = 0; return; }/* Writing is more involved - we'll start the WD chip and write as * much data to the fifo as we can right now. Later interrupts will * write any bytes that don't make it at this stage. */ if ((hostdata->level2 >= L2_DATA) || (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) { 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_TRANS_INFO); hostdata->fifo = FI_FIFO_WRITING; sp = (unsigned short *)cmd->SCp.ptr; if ((i = cmd->SCp.this_residual) > IN2000_FIFO_SIZE) i = IN2000_FIFO_SIZE; cmd->SCp.have_data_in = i; i >>= 1; /* Gulp. We assume this_residual is modulo 2 */ f = hostdata->io_base + IO_FIFO;#ifdef FAST_WRITE_IO FAST_WRITE2_IO();#else while (i--) 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 void in2000_intr (int irqnum, void * dev_id, struct pt_regs *ptregs){struct Scsi_Host *instance;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; for (instance = instance_list; instance; instance = instance->next) { if (instance->irq == irqnum) break; } if (!instance) { printk("*** Hmm... interrupts are screwed up! ***\n"); return; } hostdata = (struct IN2000_hostdata *)instance->hostdata;/* Get the spin_lock and disable further ints, for SMP */ CLISPIN_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 */ CLISPIN_UNLOCK(flags); return; }/* 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 */ CLISPIN_UNLOCK(flags); return; }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->target] &= ~(1 << cmd->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->lun); if (cmd->SCp.phase) hostdata->outgoing_msg[0] |= 0x40; if (hostdata->sync_stat[cmd->target] == SS_FIRST) {#ifdef SYNC_DEBUGprintk(" sending SDTR ");#endif hostdata->sync_stat[cmd->target] = 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -