📄 ncr5380.c
字号:
/* * A successful selection is defined as one that * leaves us with the command connected and * in hostdata->connected, OR has terminated the * command. * * With successful commands, we fall through * and see if we can do an information transfer, * with failures we will restart. */#ifdef USLEEP hostdata->selecting = 0; /* RvC: have to preset this to indicate a new command is being performed */#endif if (!NCR5380_select(instance, tmp, /* * REQUEST SENSE commands are issued without tagged * queueing, even on SCSI-II devices because the * contingent allegiance condition exists for the * entire unit. */ (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) { break; } else { cli(); LIST(tmp, hostdata->issue_queue); tmp->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = tmp; done = 0; restore_flags(flags);#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES)) printk("scsi%d : main(): select() failed, returned to issue_queue\n", instance->host_no);#endif } } /* if target/lun is not busy */ } /* for */ } /* if (!hostdata->connected) */#ifdef USLEEP if (hostdata->selecting) { tmp = (Scsi_Cmnd *)hostdata->selecting; if (!NCR5380_select(instance, tmp, (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) { /* Ok ?? */ } else { /* RvC: device failed, so we wait a long time this is needed for Mustek scanners, that do not respond to commands immediately after a scan */ printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n", instance->host_no, tmp->target); cli(); LIST(tmp, hostdata->issue_queue); tmp->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = tmp; restore_flags(flags); hostdata->time_expires = jiffies + USLEEP_WAITLONG; NCR5380_set_timer (instance); } } /* if hostdata->selecting */#endif if (hostdata->connected#ifdef REAL_DMA && !hostdata->dmalen#endif#ifdef USLEEP && (!hostdata->time_expires || time_before_eq(hostdata->time_expires, jiffies))#endif ) { restore_flags(flags);#if (NDEBUG & NDEBUG_MAIN) printk("scsi%d : main() : performing information transfer\n", instance->host_no);#endif NCR5380_information_transfer(instance);#if (NDEBUG & NDEBUG_MAIN) printk("scsi%d : main() : done set false\n", instance->host_no);#endif done = 0; } else break; } /* for instance */ } while (!done); spin_lock_irq(&io_request_lock); /* cli();*/ main_running = 0;}#ifndef DONT_USE_INTR#include <linux/blk.h>#include <linux/spinlock.h>/* * Function : void NCR5380_intr (int irq) * * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses * from the disconnected queue, and restarting NCR5380_main() * as required. * * Inputs : int irq, irq that caused this interrupt. * */static void NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) { NCR5380_local_declare(); struct Scsi_Host *instance; int done; unsigned char basr; unsigned long flags; save_flags(flags); cli();#if (NDEBUG & NDEBUG_INTR) printk("scsi : NCR5380 irq %d triggered\n", irq);#endif do { done = 1; for (instance = first_instance; instance && (instance->hostt == the_template); instance = instance->next) if (instance->irq == irq) { /* Look for pending interrupts */ NCR5380_setup(instance); basr = NCR5380_read(BUS_AND_STATUS_REG); /* XXX dispatch to appropriate routine if found and done=0 */ if (basr & BASR_IRQ) {#if (NDEBUG & NDEBUG_INTR) NCR5380_print(instance);#endif if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { done = 0; restore_flags(flags);#if (NDEBUG & NDEBUG_INTR) printk("scsi%d : SEL interrupt\n", instance->host_no);#endif NCR5380_reselect(instance); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else if (basr & BASR_PARITY_ERROR) {#if (NDEBUG & NDEBUG_INTR) printk("scsi%d : PARITY interrupt\n", instance->host_no);#endif (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {#if (NDEBUG & NDEBUG_INTR) printk("scsi%d : RESET interrupt\n", instance->host_no);#endif (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else {/* * XXX the rest of the interrupt conditions should *only* occur during a * DMA transfer, which I haven't gotten around to fixing yet. */#if defined(REAL_DMA) /* * We should only get PHASE MISMATCH and EOP interrupts * if we have DMA enabled, so do a sanity check based on * the current setting of the MODE register. */ if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & BASR_END_DMA_TRANSFER) || !(basr & BASR_PHASE_MATCH))) { int transfered; if (!hostdata->connected) panic("scsi%d : received end of DMA interrupt with no connected cmd\n", instance->hostno); transfered = (hostdata->dmalen - NCR5380_dma_residual(instance)); hostdata->connected->SCp.this_residual -= transferred; hostdata->connected->SCp.ptr += transferred; hostdata->dmalen = 0; (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);#if NCR_TIMEOUT { unsigned long timeout = jiffies + NCR_TIMEOUT; spin_unlock_irq(&io_request_lock); while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK && time_before(jiffies, timeout)); spin_lock_irq(&io_request_lock); if (time_after_eq(jiffies, timeout) ) printk("scsi%d: timeout at NCR5380.c:%d\n", host->host_no, __LINE__); }#else /* NCR_TIMEOUT */ while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK);#endif NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); }#else#if (NDEBUG & NDEBUG_INTR) printk("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));#endif (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);#endif } } /* if BASR_IRQ */ if (!done) run_main(); } /* if (instance->irq == irq) */ } while (!done);}static void do_NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; spin_lock_irqsave(&io_request_lock, flags); NCR5380_intr(irq, dev_id, regs); spin_unlock_irqrestore(&io_request_lock, flags);}#endif#ifdef NCR5380_STATSstatic void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) {#ifdef NCR5380_STAT_LIMIT if (cmd->request_bufflen > NCR5380_STAT_LIMIT)#endif switch (cmd->cmnd[0]) { case WRITE: case WRITE_6: case WRITE_10: hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase); /*hostdata->bytes_write[cmd->target] += cmd->request_bufflen; */ hostdata->pendingw--; break; case READ: case READ_6: case READ_10: hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase); /*hostdata->bytes_read[cmd->target] += cmd->request_bufflen; */ hostdata->pendingr--; break; }}#endif/* * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, * int tag); * * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command, * including ARBITRATION, SELECTION, and initial message out for * IDENTIFY and queue messages. * * Inputs : instance - instantiation of the 5380 driver on which this * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for * the command that is presently connected. * * Returns : -1 if selection could not execute for some reason, * 0 if selection succeeded or failed because the target * did not respond. * * Side effects : * If bus busy, arbitration failed, etc, NCR5380_select() will exit * with registers as they should have been on entry - ie * SELECT_ENABLE will be set appropriately, the NCR5380 * will cease to drive any SCSI bus signals. * * If successful : I_T_L or I_T_L_Q nexus will be established, * instance->connected will be set to cmd. * SELECT interrupt will be disabled. * * If failed (no target) : cmd->scsi_done() will be called, and the * cmd->result host byte set to DID_BAD_TARGET. */static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) { NCR5380_local_declare(); struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; unsigned char tmp[3], phase; unsigned char *data; int len; unsigned long timeout; unsigned long flags;#ifdef USLEEP unsigned char value;#endif NCR5380_setup(instance);#ifdef USLEEP if (hostdata->selecting) { goto part2; /* RvC: sorry prof. Dijkstra, but it keeps the rest of the code nearly the same */ }#endif hostdata->restart_select = 0;#if defined (NDEBUG) && (NDEBUG & NDEBUG_ARBITRATION) NCR5380_print(instance); printk("scsi%d : starting arbitration, id = %d\n", instance->host_no, instance->this_id);#endif save_flags(flags); cli(); /* * Set the phase bits to 0, otherwise the NCR5380 won't drive the * data bus during SELECTION. */ NCR5380_write(TARGET_COMMAND_REG, 0); /* * Start arbitration. */ NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); NCR5380_write(MODE_REG, MR_ARBITRATE); restore_flags(flags); /* Wait for arbitration logic to complete */#if NCR_TIMEOUT { unsigned long timeout = jiffies + 2 * NCR_TIMEOUT; spin_unlock_irq(&io_request_lock); while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) && time_before(jiffies,timeout)); spin_lock_irq(&io_request_lock); if (time_after_eq(jiffies,timeout)) { printk("scsi: arbitration timeout at %d\n", __LINE__); NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return -1; } }#else /* NCR_TIMEOUT */ while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS));#endif#if (NDEBUG & NDEBUG_ARBITRATION) printk("scsi%d : arbitration complete\n", instance->host_no);/* Avoid GCC 2.4.5 asm needs to many reloads error */ __asm__("nop");#endif /* * The arbitration delay is 2.2us, but this is a minimum and there is * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate * the integral nature of udelay(). * */ udelay(3); /* Check for lost arbitration */ if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { NCR5380_write(MODE_REG, MR_BASE);#if (NDEBUG & NDEBUG_ARBITRATION) printk("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", instance->host_no);#endif return -1; } NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL); if (!(hostdata->flags & FLAG_DTC3181E) && /* RvC: DTC3181E has some trouble with this * so we simply removed it. Seems to work with * only Mustek scanner attached */ (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);#if (NDEBUG & NDEBUG_ARBITRATION) printk("scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n", instance->host_no);#endif return -1; } /* * Again, bus clear + bus settle time is 1.2us, however, this is * a minimum so we'll udelay ceil(1.2) */ udelay(2);#if (NDEBUG & NDEBUG_ARBITRATION) printk("scsi%d : won arbitration\n", instance->host_no);#endif /* * Now that we have won arbitration, start Selection process, asserting * the host and target ID's on the SCSI bus. */ NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target))); /* * Raise ATN while SEL is true before BSY goes false from arbitration, * since this is the only way to guarantee that we'll get a MESSAGE OUT * phase immediately after selection. */ NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL)); NCR5380_write(MODE_REG, MR_BASE); /* * Reselect interrupts must be turned off prior to the dropping of BSY, * otherwise we will trigger an interrupt. */ NCR5380_write(SELECT_ENABLE_REG, 0); /* * The initiator shall then wait at least two deskew delays and release * the BSY signal. */ udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ /* Reset BSY */ NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL)); /* * Something weird happens when we cease to drive BSY - looks * like the board/chip is letting us do another read before the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -