?? ncr5380.c
字號:
/* Wait for start of REQ/ACK handshake */ while (!(NCR5380_read(STATUS_REG) & SR_REQ));#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 (scsi_devices[cmd->index].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 (scsi_devices[cmd->index].current_tag == 0) scsi_devices[cmd->index].current_tag = 1; cmd->tag = scsi_devices[cmd->index].current_tag; scsi_devices[cmd->index].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 (!scsi_devices[cmd->index].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 enterred without transfering * 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; NCR5380_setup(instance); /* * 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)); do { /* * Wait for assertion of REQ, after which the phase bits will be * valid */ while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));#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 if (!(p == PHASE_MSGOUT && c > 1)) NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); else NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); } 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;}#if defined(REAL_DMA) || defined(PSEUDO_DMA) || defined (REAL_DMA_POLL)/* * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, * unsigned char *phase, int *count, unsigned char **data) * * Purpose : transfers data in given phase using either real * or pseudo DMA. * * 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 enterred without transfering * maximum number of bytes, 0 if all bytes or transfered or exit * is in same phase. * * Also, *phase, *count, *data are modified in place. * */static int NCR5380_transfer_dma (struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) { NCR5380_local_declare(); register int c = *count; register unsigned char p = *phase; register unsigned char *d = *data; unsigned char tmp; int foo;#if defined(REAL_DMA_POLL) int cnt, toPIO; unsigned char saved_data = 0, overrun = 0, residue;#endif struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; NCR5380_setup(instance); if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { *phase = tmp; return -1; }#if defined(REAL_DMA) || defined(REAL_DMA_POLL) #ifdef READ_OVERRUNS if (p & SR_IO) { c -= 2; }#endif#if (NDEBUG & NDEBUG_DMA) printk("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d);#endif hostdata->dma_len = (p & SR_IO) ? NCR5380_dma_read_setup(instance, d, c) : NCR5380_dma_write_setup(instance, d, c);#endif NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));#ifdef REAL_DMA NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);#elif defined(REAL_DMA_POLL) NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);#else /* * Note : on my sample board, watch-dog timeouts occured when interrupts * were not disabled for the duration of a single DMA transfer, from * before the setting of DMA mode to after transfer of the last byte. */#if defined(PSEUDO_DMA) && !defined(UNSAFE) cli();#endif NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);#endif /* def REAL_DMA */#if (NDEBUG & NDEBUG_DMA) & 0 printk("scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG));#endif if (p & SR_IO) NCR5380_write(START_DMA_INITIATOR_RECIEVE_REG, 0); else { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); NCR5380_write(START_DMA_SEND_REG, 0); }#if defined(REAL_DMA_POLL) do { tmp = NCR5380_read(BUS_AND_STATUS_REG); } while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | BASR_END_DMA_TRANSFER)));/* At this point, either we've completed DMA, or we have a phase mismatch, or we've unexpectedly lost BUSY (which is a real error). For write DMAs, we want to wait until the last byte has been transferred out over the bus before we turn off DMA mode. Alas, there seems to be no terribly good way of doing this on a 5380 under all conditions. For non-scatter-gather operations, we can wait until REQ and ACK both go false, or until a phase mismatch occurs. Gather-writes are nastier, since the device will be expecting more data than we are prepared to send it, and REQ will remain asserted. On a 53C8[01] we could test LAST BIT SENT to assure transfer (I imagine this is precisely why this signal was added to the newer chips) but on the older 538[01] this signal does not exist. The workaround for this lack is a watchdog; we bail out of the wait-loop after a modest amount of wait-time if the usual exit conditions are not met. Not a terribly clean or correct solution :-% Reads are equally tricky due to a nasty characteristic of the NCR5380. If the chip is in DMA mode for an READ, it will respond to a target's REQ by latching the SCSI data into the INPUT DATA register and asserting ACK, even if it has _already_ been notified by the DMA controller that the current DMA transfer has completed! If the NCR5380 is then taken out of DMA mode, this already-acknowledged byte is lost. This is not a problem for "one DMA transfer per command" reads, because the situation will never arise... either all of the data is DMA'ed properly, or the target switches to MESSAGE IN phase to signal a disconnection (either operation bringing the DMA to a clean halt). However, in order to handle scatter-reads, we must work around the problem. The chosen fix is to DMA N-2 bytes, then check for the condition before taking the NCR5380 out of DMA mode. One or two extra bytes are tranferred via PIO as necessary to fill out the original request.*/ if (p & SR_IO) {#ifdef READ_OVERRUNS udelay(10); if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH|BASR_ACK)) == (BASR_PHASE_MATCH | BASR_ACK))) { saved_data = NCR5380_read(INPUT_DATA_REGISTER); overrun = 1; }#endif } else { int limit = 100; while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || (NCR5380_read(STATUS_REG) & SR_REQ)) { if (!(tmp & BASR_PHASE_MATCH)) break; if (--limit < 0) break; } }#if (NDEBUG & NDEBUG_DMA) printk("scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", instance->host_no, tmp, NCR5380_read(STATUS_REG));#endif NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); residue = NCR5380_dma_residual(instance); c -= residue; *count -= c; *data += c; *phase = NCR5380_read(STATUS_REG) & PHASE_MASK;#ifdef READ_OVERRUNS if (*phase == p && (p & SR_IO) && residue == 0) { if (overrun) {#if (NDEBUG & NDEBUG_DMA) printk("Got an input overrun, using saved byte\n");#endif **data = saved_data; *data += 1; *count -= 1; cnt = toPIO = 1; } else { printk("No overrun??\n"); cnt = toPIO = 2; }#if (NDEBUG & NDEBUG_DMA) printk("Doing %d-byte PIO to 0x%X\n", cnt, *data);#endif NCR5380_transfer_pio(instance, phase, &cnt, data); *count -= toPIO - cnt; }#endif #if (NDEBUG & NDEBUG_DMA) printk("Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", *data, *count, *(*data+*count-1), *(*data+*count));#endif return 0; #elif defined(REAL_DMA) return 0;#else /* defined(REAL_DMA_POLL) */ if (p & SR_IO) { if (!(foo = NCR5380_pread(instance, d, c - 1))) { /* * We can't disable DMA mode after successfully transfering * what we plan to be the last byte, since that would open up * a race condition where if the target asserted REQ before * we got the DMA mode reset, the NCR5380 would have latched * an additional byte into the INPUT DATA register and we'd * have dropped it. * * The workarround was to transfer one fewer bytes than we * intended to with the pseudo-DMA read function, wait for * the chip to latch the last byte, read it, and then disable * pseudo-DMA mode. * * After REQ is asserted, the NCR5380 asserts DRQ and ACK. * REQ is deasserted when ACK is asserted, and not reasserted * until ACK goes false. Since the NCR5380 won't lower ACK * until DACK is asserted, which won't happen unless we twiddle * the DMA port or we take the NCR5380 out of DMA mode, we * can gurantee that we won't handshake another extra * byte. */ while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)); /* Wait for clean handshake */ while (NCR5380_read(STATUS_REG) & SR_REQ); d[c - 1] = NCR5380_read(INPUT_DATA_REG); } } else { int timeout; if (!(foo = NCR5380_pwrite(instance, d, c))) { /* * Wait for the last byte to be sent. If REQ is being asserted for * the byte we're interested, we'll ACK it and it will go false. */ if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) { timeout = 20000;#if 1
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -