📄 ncr5380.c
字号:
* 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. */#ifdef USLEEP hostdata->select_time = 0; /* we count the clock ticks at which we polled */ hostdata->selecting = cmd;part2: /* RvC: here we enter after a sleeping period, or immediately after execution of part 1 we poll only once ech clock tick */ value = NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO); if (!value && (hostdata->select_time < 25)) { /* RvC: we still must wait for a device response */ hostdata->select_time++; /* after 25 ticks the device has failed */ hostdata->time_expires = jiffies + 1; NCR5380_set_timer(instance); return 0; /* RvC: we return here with hostdata->selecting set, to go to sleep */ } hostdata->selecting = 0; /* clear this pointer, because we passed the waiting period */#else spin_unlock_irq(&io_request_lock); while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO))); spin_lock_irq(&io_request_lock);#endif 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; } /* * No less than two deskew delays after the initiator detects the * BSY signal is true, it shall release the SEL signal and may * change the DATA BUS. -wingel */ udelay(1); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); if (!(NCR5380_read(STATUS_REG) & SR_BSY)) { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); if (hostdata->targets_present & (1 << cmd->target)) { printk("scsi%d : weirdness\n", instance->host_no); if (hostdata->restart_select) printk("\trestart select\n");#if (NDEBUG & NDEBUG_SELECTION) NCR5380_print(instance);#endif NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return -1; } cmd->result = DID_BAD_TARGET << 16;#ifdef NCR5380_STATS collect_stats(hostdata, cmd);#endif cmd->scsi_done(cmd); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);#if (NDEBUG & NDEBUG_SELECTION) printk("scsi%d : target did not respond within 250ms\n", instance->host_no);#endif NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return 0; } hostdata->targets_present |= (1 << cmd->target); /* * Since we followed the SCSI spec, and raised ATN while SEL * was true but before BSY was false during selection, the information * transfer phase should be a MESSAGE OUT phase so that we can send the * IDENTIFY message. * * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG * message (2 bytes) with a tag ID that we increment with every command * until it wraps back to 0. * * XXX - it turns out that there are some broken SCSI-II devices, * which claim to support tagged queuing but fail when more than * some number of commands are issued at once. */ /* Wait for start of REQ/ACK handshake */#ifdef NCR_TIMEOUT { unsigned long timeout = jiffies + NCR_TIMEOUT; spin_unlock_irq(&io_request_lock); while (!(NCR5380_read(STATUS_REG) & SR_REQ) && 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", instance->host_no, __LINE__); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return -1; } }#else /* NCR_TIMEOUT */ while (!(NCR5380_read(STATUS_REG) & SR_REQ));#endif /* def NCR_TIMEOUT */#if (NDEBUG & NDEBUG_SELECTION) printk("scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->target);#endif tmp[0] = IDENTIFY(((instance->irq == IRQ_NONE) ? 0 : 1), cmd->lun);#ifdef SCSI2 if (cmd->device->tagged_queue && (tag != TAG_NONE)) { tmp[1] = SIMPLE_QUEUE_TAG; if (tag == TAG_NEXT) { /* 0 is TAG_NONE, used to imply no tag for this command */ if (cmd->device->current_tag == 0) cmd->device->current_tag = 1; cmd->tag = cmd->device->current_tag; cmd->device->current_tag++; } else cmd->tag = (unsigned char) tag; tmp[2] = cmd->tag; hostdata->last_message = SIMPLE_QUEUE_TAG; len = 3; } else#endif /* def SCSI2 */ { len = 1; cmd->tag = 0; } /* Send message(s) */ data = tmp; phase = PHASE_MSGOUT; NCR5380_transfer_pio(instance, &phase, &len, &data);#if (NDEBUG & NDEBUG_SELECTION) printk("scsi%d : nexus established.\n", instance->host_no);#endif /* XXX need to handle errors here */ hostdata->connected = cmd;#ifdef SCSI2 if (!cmd->device->tagged_queue)#endif hostdata->busy[cmd->target] |= (1 << cmd->lun); initialize_SCp(cmd); return 0;}/* * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, * unsigned char *phase, int *count, unsigned char **data) * * Purpose : transfers data in given phase using polled I/O * * Inputs : instance - instance of driver, *phase - pointer to * what phase is expected, *count - pointer to number of * bytes to transfer, **data - pointer to data pointer. * * Returns : -1 when different phase is entered without transferring * maximum number of bytes, 0 if all bytes or transfered or exit * is in same phase. * * Also, *phase, *count, *data are modified in place. * * XXX Note : handling for bus free may be useful. *//* * Note : this code is not as quick as it could be, however it * IS 100% reliable, and for the actual data transfer where speed * counts, we will always do a pseudo DMA or DMA transfer. */static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) { NCR5380_local_declare(); register unsigned char p = *phase, tmp; register int c = *count; register unsigned char *d = *data;#ifdef USLEEP /* * RvC: some administrative data to process polling time */ int break_allowed = 0; struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;#endif NCR5380_setup(instance);#if (NDEBUG & NDEBUG_PIO) if (!(p & SR_IO)) printk("scsi%d : pio write %d bytes\n", instance->host_no, c); else printk("scsi%d : pio read %d bytes\n", instance->host_no, c);#endif /* * The NCR5380 chip will only drive the SCSI bus when the * phase specified in the appropriate bits of the TARGET COMMAND * REGISTER match the STATUS REGISTER */ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));#ifdef USLEEP /* RvC: don't know if this is necessary, but other SCSI I/O is short * so breaks are not necessary there */ if ((p == PHASE_DATAIN) || (p == PHASE_DATAOUT)) { break_allowed = 1; }#endif do { /* * Wait for assertion of REQ, after which the phase bits will be * valid */#ifdef USLEEP /* RvC: we simply poll once, after that we stop temporarily * and let the device buffer fill up * if breaking is not allowed, we keep polling as long as needed */ while ( !((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) && !break_allowed ); if (!(tmp & SR_REQ)) { /* timeout condition */ hostdata->time_expires = jiffies + USLEEP_SLEEP; NCR5380_set_timer (instance); break; }#else while ( !((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) ); #endif#if (NDEBUG & NDEBUG_HANDSHAKE) printk("scsi%d : REQ detected\n", instance->host_no);#endif /* Check for phase mismatch */ if ((tmp & PHASE_MASK) != p) {#if (NDEBUG & NDEBUG_PIO) printk("scsi%d : phase mismatch\n", instance->host_no); NCR5380_print_phase(instance);#endif break; } /* Do actual transfer from SCSI bus to / from memory */ if (!(p & SR_IO)) NCR5380_write(OUTPUT_DATA_REG, *d); else *d = NCR5380_read(CURRENT_SCSI_DATA_REG); ++d; /* * The SCSI standard suggests that in MSGOUT phase, the initiator * should drop ATN on the last byte of the message phase * after REQ has been asserted for the handshake but before * the initiator raises ACK. */ if (!(p & SR_IO)) { if (!((p & SR_MSG) && c > 1)) { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);#if (NDEBUG & NDEBUG_PIO) NCR5380_print(instance);#endif NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ACK); } else { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN);#if (NDEBUG & NDEBUG_PIO) NCR5380_print(instance);#endif NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); } } else {#if (NDEBUG & NDEBUG_PIO) NCR5380_print(instance);#endif NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); } while (NCR5380_read(STATUS_REG) & SR_REQ);#if (NDEBUG & NDEBUG_HANDSHAKE) printk("scsi%d : req false, handshake complete\n", instance->host_no);#endif/* * We have several special cases to consider during REQ/ACK handshaking : * 1. We were in MSGOUT phase, and we are on the last byte of the * message. ATN must be dropped as ACK is dropped. * * 2. We are in a MSGIN phase, and we are on the last byte of the * message. We must exit with ACK asserted, so that the calling * code may raise ATN before dropping ACK to reject the message. * * 3. ACK and ATN are clear and the target may proceed as normal. */ if (!(p == PHASE_MSGIN && c == 1)) { if (p == PHASE_MSGOUT && c > 1) NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); else NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); } } while (--c);#if (NDEBUG & NDEBUG_PIO) printk("scsi%d : residual %d\n", instance->host_no, c);#endif *count = c; *data = d; tmp = NCR5380_read(STATUS_REG); if (tmp & SR_REQ) *phase = tmp & PHASE_MASK; else *phase = PHASE_UNKNOWN; if (!c || (*phase == p)) return 0; else return -1;}static void do_reset(struct Scsi_Host *host) { unsigned long flags; NCR5380_local_declare(); NCR5380_setup(host); save_flags(flags); cli(); NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); udelay(25); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); restore_flags(flags);} /* * Function : do_abort (Scsi_Host *host) * * Purpose : abort the currently established nexus. Should only be * called from a routine which can drop into a * * Returns : 0 on success, -1 on failure. */ static int do_abort(struct Scsi_Host *host) { NCR5380_local_declare(); unsigned char tmp, *msgptr, phase; int len; NCR5380_setup(host); /* Request message out phase */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); /* * Wait for the target to indicate a valid phase by asserting * REQ. Once this happens, we'll have either a MSGOUT phase * and can immediately send the ABORT message, or we'll have some * other phase and will have to source/sink data. * * We really don't care what value was on the bus or what value * the target sees, so we just handshake. */ while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ); NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); if ((tmp & PHASE_MASK) != PHASE_MSGOUT) { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); while (NCR5380_read(STATUS_REG) & SR_REQ); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); } tmp = ABORT; msgptr = &tmp; len = 1; phase = PHASE_MSGOUT; NCR5380_transfer_pio(host, &phase, &len, &msgptr); /* * If we got here, and the command completed successfully, * we're about to go into bus free state. */ return len ? -1 : 0;}#if defined(REAL_DMA) || defined(PSEUDO_DMA) || defined (REAL_DMA_POLL)/* * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -