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

📄 in2000.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 * status byte is stored. */   cmd->SCp.Status = ILLEGAL_STATUS_BYTE;/* We need to disable interrupts before messing with the input * queue and calling in2000_execute(). */   save_flags(flags);   cli();   /*    * Add the cmd to the end of 'input_Q'. Note that REQUEST_SENSE    * commands are added to the head of the queue so that the desired    * sense data is not lost before REQUEST_SENSE executes.    */   if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) {      cmd->host_scribble = (uchar *)hostdata->input_Q;      hostdata->input_Q = cmd;      }   else {   /* find the end of the queue */      for (tmp=(Scsi_Cmnd *)hostdata->input_Q; tmp->host_scribble;            tmp=(Scsi_Cmnd *)tmp->host_scribble)         ;      tmp->host_scribble = (uchar *)cmd;      }/* We know that there's at least one command in 'input_Q' now. * Go see if any of them are runnable! */   in2000_execute(cmd->host);DB(DB_QUEUE_COMMAND,printk(")Q-%ld ",cmd->pid))   restore_flags(flags);   return 0;}/* * This routine attempts to start a scsi command. If the host_card is * already connected, we give up immediately. Otherwise, look through * the input_Q, using the first command we find that's intended * for a currently non-busy target/lun. * Note that this function is always called with interrupts already * disabled (either from in2000_queuecommand() or in2000_intr()). */static void in2000_execute (struct Scsi_Host *instance){struct IN2000_hostdata *hostdata;Scsi_Cmnd *cmd, *prev;int i;unsigned short *sp;unsigned short f;unsigned short flushbuf[16];   hostdata = (struct IN2000_hostdata *)instance->hostdata;DB(DB_EXECUTE,printk("EX("))   if (hostdata->selecting || hostdata->connected) {DB(DB_EXECUTE,printk(")EX-0 "))      return;      }    /*     * Search through the input_Q for a command destined     * for an idle target/lun.     */   cmd = (Scsi_Cmnd *)hostdata->input_Q;   prev = 0;   while (cmd) {      if (!(hostdata->busy[cmd->target] & (1 << cmd->lun)))         break;      prev = cmd;      cmd = (Scsi_Cmnd *)cmd->host_scribble;      }   /* quit if queue empty or all possible targets are busy */   if (!cmd) {DB(DB_EXECUTE,printk(")EX-1 "))      return;      }   /*  remove command from queue */      if (prev)      prev->host_scribble = cmd->host_scribble;   else      hostdata->input_Q = (Scsi_Cmnd *)cmd->host_scribble;#ifdef PROC_STATISTICS   hostdata->cmd_cnt[cmd->target]++;#endif/* * Start the selection process */   if (is_dir_out(cmd))      write_3393(hostdata,WD_DESTINATION_ID, cmd->target);   else      write_3393(hostdata,WD_DESTINATION_ID, cmd->target | DSTID_DPD);/* Now we need to figure out whether or not this command is a good * candidate for disconnect/reselect. We guess to the best of our * ability, based on a set of hierarchical rules. When several * devices are operating simultaneously, disconnects are usually * an advantage. In a single device system, or if only 1 device * is being accessed, transfers usually go faster if disconnects * are not allowed: * * + Commands should NEVER disconnect if hostdata->disconnect = *   DIS_NEVER (this holds for tape drives also), and ALWAYS *   disconnect if hostdata->disconnect = DIS_ALWAYS. * + Tape drive commands should always be allowed to disconnect. * + Disconnect should be allowed if disconnected_Q isn't empty. * + Commands should NOT disconnect if input_Q is empty. * + Disconnect should be allowed if there are commands in input_Q *   for a different target/lun. In this case, the other commands *   should be made disconnect-able, if not already. * * I know, I know - this code would flunk me out of any * "C Programming 101" class ever offered. But it's easy * to change around and experiment with for now. */   cmd->SCp.phase = 0;  /* assume no disconnect */   if (hostdata->disconnect == DIS_NEVER)      goto no;   if (hostdata->disconnect == DIS_ALWAYS)      goto yes;   if (cmd->device->type == 1)   /* tape drive? */      goto yes;   if (hostdata->disconnected_Q) /* other commands disconnected? */      goto yes;   if (!(hostdata->input_Q))     /* input_Q empty? */      goto no;   for (prev=(Scsi_Cmnd *)hostdata->input_Q; prev;         prev=(Scsi_Cmnd *)prev->host_scribble) {      if ((prev->target != cmd->target) || (prev->lun != cmd->lun)) {         for (prev=(Scsi_Cmnd *)hostdata->input_Q; prev;               prev=(Scsi_Cmnd *)prev->host_scribble)            prev->SCp.phase = 1;         goto yes;         }      }   goto no;yes:   cmd->SCp.phase = 1;#ifdef PROC_STATISTICS   hostdata->disc_allowed_cnt[cmd->target]++;#endifno:   write_3393(hostdata,WD_SOURCE_ID,((cmd->SCp.phase)?SRCID_ER:0));   write_3393(hostdata,WD_TARGET_LUN, cmd->lun);   write_3393(hostdata,WD_SYNCHRONOUS_TRANSFER,hostdata->sync_xfer[cmd->target]);   hostdata->busy[cmd->target] |= (1 << cmd->lun);   if ((hostdata->level2 <= L2_NONE) ||       (hostdata->sync_stat[cmd->target] == SS_UNSET)) {         /*          * Do a 'Select-With-ATN' command. This will end with          * one of the following interrupts:          *    CSR_RESEL_AM:  failure - can try again later.          *    CSR_TIMEOUT:   failure - give up.          *    CSR_SELECT:    success - proceed.          */      hostdata->selecting = cmd;/* Every target has its own synchronous transfer setting, kept in * the sync_xfer array, and a corresponding status byte in sync_stat[]. * Each target's sync_stat[] entry is initialized to SS_UNSET, and its * sync_xfer[] entry is initialized to the default/safe value. SS_UNSET * means that the parameters are undetermined as yet, and that we * need to send an SDTR message to this device after selection is * complete. We set SS_FIRST to tell the interrupt routine to do so, * unless we don't want to even _try_ synchronous transfers: In this * case we set SS_SET to make the defaults final. */      if (hostdata->sync_stat[cmd->target] == SS_UNSET) {         if (hostdata->sync_off & (1 << cmd->target))            hostdata->sync_stat[cmd->target] = SS_SET;         else            hostdata->sync_stat[cmd->target] = SS_FIRST;         }      hostdata->state = S_SELECTING;      write_3393_count(hostdata,0); /* this guarantees a DATA_PHASE interrupt */      write_3393_cmd(hostdata,WD_CMD_SEL_ATN);      }   else {         /*          * Do a 'Select-With-ATN-Xfer' command. This will end with          * one of the following interrupts:          *    CSR_RESEL_AM:  failure - can try again later.          *    CSR_TIMEOUT:   failure - give up.          *    anything else: success - proceed.          */      hostdata->connected = cmd;      write_3393(hostdata,WD_COMMAND_PHASE, 0);   /* copy command_descriptor_block into WD chip    * (take advantage of auto-incrementing)    */      write1_io(WD_CDB_1, IO_WD_ADDR);      for (i=0; i<cmd->cmd_len; i++)         write1_io(cmd->cmnd[i], IO_WD_DATA);   /* The wd33c93 only knows about Group 0, 1, and 5 commands when    * it's doing a 'select-and-transfer'. To be safe, we write the    * size of the CDB into the OWN_ID register for every case. This    * way there won't be problems with vendor-unique, audio, etc.    */      write_3393(hostdata, WD_OWN_ID, cmd->cmd_len);   /* When doing a non-disconnect command, we can save ourselves a DATA    * phase interrupt later by setting everything up now. With writes we    * need to pre-fill the fifo; if there's room for the 32 flush bytes,    * put them in there too - that'll avoid a fifo interrupt. Reads are    * somewhat simpler.    * KLUDGE NOTE: It seems that you can't completely fill the fifo here:    * This results in the IO_FIFO_COUNT register rolling over to zero,    * and apparently the gate array logic sees this as empty, not full,    * so the 3393 chip is never signalled to start reading from the    * fifo. Or maybe it's seen as a permanent fifo interrupt condition.    * Regardless, we fix this by temporarily pretending that the fifo    * is 16 bytes smaller. (I see now that the old driver has a comment    * about "don't fill completely" in an analogous place - must be the    * same deal.) This results in CDROM, swap partitions, and tape drives    * needing an extra interrupt per write command - I think we can live    * with that!    */      if (!(cmd->SCp.phase)) {         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);  /* clear fifo counter, write mode */         if (is_dir_out(cmd)) {            hostdata->fifo = FI_FIFO_WRITING;            if ((i = cmd->SCp.this_residual) > (IN2000_FIFO_SIZE - 16) )               i = IN2000_FIFO_SIZE - 16;            cmd->SCp.have_data_in = i;    /* this much data in fifo */            i >>= 1;                      /* Gulp. Assuming modulo 2. */            sp = (unsigned short *)cmd->SCp.ptr;            f = hostdata->io_base + IO_FIFO;#ifdef FAST_WRITE_IO            FAST_WRITE2_IO();#else            while (i--)               write2_io(*sp++,IO_FIFO);#endif      /* Is there room for the flush bytes? */            if (cmd->SCp.have_data_in <= ((IN2000_FIFO_SIZE - 16) - 32)) {               sp = flushbuf;               i = 16;#ifdef FAST_WRITE_IO               FAST_WRITE2_IO();#else               while (i--)                  write2_io(0,IO_FIFO);#endif               }            }         else {            write1_io(0, IO_FIFO_READ);   /* put fifo in read mode */            hostdata->fifo = FI_FIFO_READING;            cmd->SCp.have_data_in = 0;    /* nothing transfered yet */            }         }      else {         write_3393_count(hostdata,0); /* this guarantees a DATA_PHASE interrupt */         }      hostdata->state = S_RUNNING_LEVEL2;      write_3393_cmd(hostdata,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%ld)EX-2 ",(cmd->SCp.phase)?"d:":"",cmd->pid))}static void transfer_pio(uchar *buf, int cnt,                  int data_in_dir, struct IN2000_hostdata *hostdata){uchar asr;DB(DB_TRANSFER,printk("(%p,%d,%s)",buf,cnt,data_in_dir?"in":"out"))   write_3393(hostdata,WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);   write_3393_count(hostdata,cnt);   write_3393_cmd(hostdata,WD_CMD_TRANS_INFO);   if (data_in_dir) {      do {         asr = READ_AUX_STAT();         if (asr & ASR_DBR)            *buf++ = read_3393(hostdata,WD_DATA);         } while (!(asr & ASR_INT));      }   else {      do {         asr = READ_AUX_STAT();         if (asr & ASR_DBR)            write_3393(hostdata,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(Scsi_Cmnd *cmd, int data_in_dir){struct IN2000_hostdata *hostdata;unsigned short *sp;unsigned short f;int i;   hostdata = (struct IN2000_hostdata *)cmd->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 (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {      ++cmd->SCp.buffer;      --cmd->SCp.buffers_residual;      cmd->SCp.this_residual = cmd->SCp.buffer->length;      cmd->SCp.ptr = cmd->SCp.buffer->address;      }/* Set up hardware registers */

⌨️ 快捷键说明

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