📄 mac_ncr5380.c
字号:
HOSTNO, cmd->target); tmp[0] = IDENTIFY(1, cmd->lun);#ifdef SUPPORT_TAGS if (cmd->tag != TAG_NONE) { tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG; tmp[2] = cmd->tag; len = 3; } else len = 1;#else len = 1; cmd->tag=0;#endif /* SUPPORT_TAGS */ /* Send message(s) */ data = tmp; phase = PHASE_MSGOUT; NCR5380_transfer_pio(instance, &phase, &len, &data); SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO); /* XXX need to handle errors here */ hostdata->connected = cmd;#ifndef SUPPORT_TAGS hostdata->busy[cmd->target] |= (1 << cmd->lun);#endif 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 are 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){ register unsigned char p = *phase, tmp; register int c = *count; register unsigned char *d = *data; /* * 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)); HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO); /* Check for phase mismatch */ if ((tmp & PHASE_MASK) != p) { PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO); NCR_PRINT_PHASE(NDEBUG_PIO); 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); NCR_PRINT(NDEBUG_PIO); 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); NCR_PRINT(NDEBUG_PIO); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); } } else { NCR_PRINT(NDEBUG_PIO); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); } while (NCR5380_read(STATUS_REG) & SR_REQ); HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO);/* * 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); PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c); *count = c; *data = d; tmp = NCR5380_read(STATUS_REG); /* The phase read from the bus is valid if either REQ is (already) * asserted or if ACK hasn't been released yet. The latter is the case if * we're in MSGIN and all wanted bytes have been received. */ if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0)) *phase = tmp & PHASE_MASK; else *phase = PHASE_UNKNOWN; if (!c || (*phase == p)) return 0; else return -1;}/* * 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) { unsigned char tmp, *msgptr, phase; int len; /* 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)/* * 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 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. * */static int NCR5380_transfer_dma( struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data){ SETUP_HOSTDATA(instance); register int c = *count; register unsigned char p = *phase; register unsigned char *d = *data; register int foo; unsigned char tmp; unsigned long flags; if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { *phase = tmp; return -1; } if (mac_read_overruns && (p & SR_IO)) { c -= mac_read_overruns; } DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n", HOSTNO, (p & SR_IO) ? "reading" : "writing", c, (p & SR_IO) ? "to" : "from", d); 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);#else /* PSEUDO_DMA! */#if defined(PSEUDO_DMA) && !defined(UNSAFE) save_flags(flags); cli();#endif /* KLL May need eop and parity in 53c400 */ if (hostdata->flags & FLAG_NCR53C400) NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_PAR_CHECK | MR_ENABLE_PAR_INTR | MR_ENABLE_EOP_INTR | MR_DMA_MODE | MR_MONITOR_BSY); else#ifndef EMULATE_PSEUDO_DMA NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);#else NCR5380_write(MODE_REG, MR_BASE);#endif#endif /* def REAL_DMA */#ifdef REAL_DMA /* On the Medusa, it is a must to initialize the DMA before * starting the NCR. This is also the cleaner way for the TT. */ save_flags(flags); cli(); hostdata->dma_len = (p & SR_IO) ? NCR5380_dma_read_setup(instance, d, c) : NCR5380_dma_write_setup(instance, d, c); restore_flags(flags);#endif /* def REAL_DMA */#ifndef EMULATE_PSEUDO_DMA if (p & SR_IO) NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); else { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); NCR5380_write(START_DMA_SEND_REG, 0); }#else hostdata->dma_len = c;#endif#if defined(REAL_DMA) return 0;#else /* defined(PSEUDO_DMA) */ if (p & SR_IO) {#ifdef DMA_WORKS_RIGHT foo = NCR5380_pread(instance, d, c);#else int diff = 1; if (hostdata->flags & FLAG_NCR53C400) { diff=0; } if (!(foo = NCR5380_pread(instance, d, c - diff))) { /* * We can't disable DMA mode after successfully transferring * 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 workaround 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 guarantee that we won't handshake another extra * byte. */ if (!(hostdata->flags & FLAG_NCR53C400)) { 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); } }#endif } else {#ifdef DMA_WORKS_RIGHT foo = NCR5380_pwrite(instance, d, c);#else int timeout;#if (NDEBUG & NDEBUG_C400_PWRITE) printk("About to pwrite %d bytes\n", c);#endif 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#if 1 while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH));#else if (NCR5380_read(STATUS_REG) & SR_REQ) { for (; timeout && !(NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); --timeout); for (; timeout && (NCR5380_read(STATUS_REG) & SR_REQ); --timeout); } #endif #if (NDEBUG & NDEBUG_LAST_BYTE_SENT) if (!timeout) printk("scsi%d : timed out on last byte\n", instance->host_no);#endif if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) { hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT; if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) { hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT;#if (NDEBUG & NDEBUG_LAST_BYTE_SENT) printk("scsi%d : last bit sent works\n", instance->host_no);#endif } } } else {#if (NDEBUG & NDEBUG_C400_PWRITE) printk("Waiting for LASTBYTE\n");#endif while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT));#if (NDEBUG & NDEBUG_C400_PWRITE) printk("Got LASTBYTE\n");#endif }#else udelay (5);#endif }#endif } NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -