⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 in2000.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
   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 + -