📄 ncr5380.c
字号:
* * With successful commands, we fall through * and see if we can do an information transfer, * with failures we will restart. */ 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; sti();#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) */ if (hostdata->connected #ifdef REAL_DMA && !hostdata->dmalen#endif#ifdef USLEEP && (!hostdata->time_expires || hostdata->time_expires >= jiffies)#endif ) { sti();#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); main_running = 0;}#ifndef DONT_USE_INTR/* * 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;#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; sti();#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; while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK && jiffies < timeout) ; if (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);}#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; NCR5380_setup(instance); 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 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); sti(); /* Wait for arbitration logic to complete */#if NCR_TIMEOUT { unsigned long timeout = jiffies + 2*NCR_TIMEOUT; while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) && jiffies < timeout) ; if (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 (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 * appropriate propagation delay has expired, and we're confusing * a BSY signal from ourselves as the target's response to SELECTION. * * A small delay (the 'C++' frontend breaks the pipeline with an * unnecessary jump, making it work on my 386-33/Trantor T128, the * tighter 'C' code breaks and requires this) solves the problem - * the 1 us delay is arbitrary, and only used because this delay will * be the same on other platforms and since it works here, it should * work there. * * wingel suggests that this could be due to failing to wait * one deskew delay. */ udelay(1);#if (NDEBUG & NDEBUG_SELECTION) printk("scsi%d : selecting target %d\n", instance->host_no, cmd->target);#endif /* * The SCSI specification calls for a 250 ms timeout for the actual * selection. */ timeout = jiffies + 250*HZ/1000; /* * XXX very interesting - we're seeing a bounce where the BSY we * asserted is being reflected / still asserted (propagation delay?) * and it's detecting as true. Sigh. */ while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO))); if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); NCR5380_reselect(instance); printk ("scsi%d : reselection after won arbitration?\n", instance->host_no); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return -1; } /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -