📄 scsi_kzq.c
字号:
sdp_match++; break; } } } /* * If the device name did not match call it RZxx or TZxx. * Use the UNKNOWN entry from scsi_devtab (if it exists), * otherwise use our internal UNKNOWN entry. */ if (!sdp_match) { if (usdp) sdp = usdp; else if (idp->perfdt == 0) sdp = &szp_rz_udt; else if (idp->perfdt == 1) sdp = &szp_tz_udt; else sdp = &szp_cz_udt; } /* * Update counters and set the pointer to the completion * handler. */ if (sdp->devtype & SZ_DISK){ szp_nrz++; sc->device_comp[targid] = rzcomplete; } if (sdp->devtype & SZ_TAPE){ szp_ntz++; sc->device_comp[targid] = tzcomplete; } if (sdp->devtype & SZ_CDROM){ szp_ncz++; sc->device_comp[targid] = rzcomplete; } if ((sdp->devtype == RX23) || (sdp->devtype == RX33)) { szp_nrx++; sc->sc_mc_cnt[targid] = 1; sc->device_comp[targid] = rzcomplete; } /* TODO: assumes length < 8 bytes */ bcopy(sdp->sysname, sc->sc_device[targid], strlen(sdp->sysname)); sc->sc_devtab[targid] = sdp; sc->sc_devtyp[targid] = sdp->devtype; sc->sc_dstp[targid] = sdp->disksize; /* * Act on the flags in device's scsi_devtab entry. */ if (sdp->flags & SCSI_TRYSYNC) sc->sc_siisentsync[targid] = 0; else sc->sc_siisentsync[targid] = 1; if (sdp->flags & SCSI_REQSNS) { sc->sc_curcmd[targid] = SZ_RQSNS; sz_bldpkt(sc, targid, SZ_RQSNS, 0, 1); kzq_scsistart(sc, targid, 0); } if (sdp->flags & SCSI_STARTUNIT) { /* * Send two start unit commands because a pending unit * attention may cause the first one to fail. We don't * for the drive to spin up here (happens in rzopen). */ sc->sc_curcmd[targid] = SZ_P_SSUNIT; sz_bldpkt(sc, targid, SZ_P_SSUNIT, 0, 1); kzq_scsistart(sc, targid, 0); kzq_scsistart(sc, targid, 0); } if (sdp->flags & SCSI_TESTUNITREADY) { sc->sc_curcmd[targid] = SZ_TUR; sz_bldpkt(sc, targid, SZ_TUR, 0, 1); kzq_scsistart(sc, targid, 0); } if (sdp->flags & SCSI_READCAPACITY) { sc->sc_curcmd[targid] = SZ_RDCAP; sz_bldpkt(sc, targid, SZ_RDCAP, 0, 1); kzq_scsistart(sc, targid, 0); } if (sdp->probedelay > 0) DELAY(sdp->probedelay); if (sdp->flags & SCSI_NODIAG) sz_unit_rcvdiag[(cntlr*NDPS)+targid] = 1; break; } /* end of switch */ /* * Just to be sure the bus is free after inquiry. * RRD40 may hold bus for a while. */ DELAY(kzq_wait_after_inquiry); } /* end of for loop */ /* * Clean out any left over interrupts. */ if (alive) { kzqaddr->sii_cstat = kzqaddr->sii_cstat; kzqaddr->sii_dstat = kzqaddr->sii_dstat; kzqaddr->sii_csr = ( SII_RSE | SII_SLE | SII_PCE | SII_IE);#ifdef mips wbflush();#endif mips } /* * TODO: should use map to allocate 128KB buffer * * If last (really 2nd) call to kzq_probe, * or only one controller configured, * assign 128K data buffer slots. * * 128K data buffer allocation strategy: * 1KB - SII controller for non READ/WRITE DMA transfers * 16KB - for each tape unit * 8KB - for each cdrom unit * ??KB - for each disk unit * ?? is what's left after tapes and cdroms divided by # of disks. * ?? must be >= 8KB, should be >= 16KB, if not reduce * number of cdroms to 2, then number of tapes to 2. * If that don't fix it panic! * In any "real" configuration, we should * never hit these limits. */ if ((nNKZQ == 1) || (kzq_firstcall == 0)) { dboff = 0x0; /* * Setup 128 byte ram buffer slots for each target to * be used for non READ/WRITE DMA Transfers on the SII. */ for(i=0; i<NDPS; i++) { sc->sc_siidboff[i] = dboff; dboff += 128; } dboff = 1024; /* determine rz slot size, must be > 16kb */ cz_slotsize = tz_slotsize = rz_slotsize = 16 * 1024; for (cntlr=0; cntlr<nNKZQ; cntlr++) { sc = &sz_softc[cntlr]; for (targid=0; targid<NDPS; targid++) { if (targid == sc->sc_sysid) continue; if (sc->sc_alive[targid] == 0) continue; sc->sc_dboff[targid][0] = dboff; sc->sc_dboff[targid][1] = dboff+KZQ_MAX_DMA_XFER_LENGTH; sc->sc_segcnt[targid] = 64 * 1024; /* Get rid of in freds code */ dboff += rz_slotsize; PRINTD(targid, 0x20, ("kzq_probe: cntlr=%d targid=%d devtype=%x ", cntlr, targid, sc->sc_devtyp[targid])); PRINTD(targid, 0x20, ("req/ack=%d slotsize=%d\n", sc->sc_siireqack[targid], sc->sc_segcnt[targid])); } } } if (kzq_firstcall) kzq_firstcall = 0;#ifdef SZDEBUG PRINTD(-1, 0x8, ("kzq_probe: done probing the SCSI bus\n")); if(kzq_debug_probe) { kzqdebug = save_kzqdebug; kzqtarget = save_kzqtarget; }#endif SZDEBUG#ifdef mips wbflush();#endif mips return(alive);}/****************************************************************** * * Start a SCSI operation on the SII chip. * ******************************************************************/kzq_scsistart(sc, targid, bp)register struct sz_softc *sc;int targid;register struct buf *bp;{ int cntlr = sc->sc_siinum; register struct kzq_regs *kzqaddr = (struct kzq_regs *)sc->sc_scsiaddr; volatile char *stv; int retval; int timer; int phase; u_short cstat, dstat; int flags; /* * If "bp" is "0" we use polled scsi mode, disallow reselect * attempts, and disable interrupts for all DMA transfers. We * poll for DMA completion instead of allowing interrupts. */ kzqaddr->sii_csr |= SII_SLE;#ifdef mips wbflush();#endif mips if(bp == (struct buf *)0) { kzqaddr->sii_csr &= ~(SII_RSE | SII_IE); sc->scsi_polled_mode = 1; } else { /* Have to clear out the rambuffer area. It is possible for a target to not not return all the requested bytes. We have to make sure that at least the extra bytes are cleared. */ if(sc->sc_rzspecial[targid]) { struct mode_sel_sns_params *msp; /* Some risk here using get_validbuf_kzq() w/out any error checking. It is probably low, at this point the target should not be doing anything, and ready for the upcomming command. Note: this should be moved into the DMA level code. */ msp = (struct mode_sel_sns_params *)sc->sc_rzparams[targid]; if(sc->sc_actcmd[targid] == SZ_MODSNS) { stv = sc->sc_rambuff + (sc->sc_dboff[targid][get_validbuf_kzq(sc, targid)] ); (sc->wmbzero)(stv, msp->msp_length); } } kzqaddr->sii_csr |= ( SII_RSE | SII_IE); sc->scsi_polled_mode = 0; }#ifdef mips wbflush();#endif mips /* Perform target arbitration and selection */ if((retval = kzq_select_target(sc, targid)) != SZ_SUCCESS) { return(retval); }BEGIN_LOOP: /* Loop through all bus phases until command complete */ sc->scsi_completed[targid] = 0; sc->scsi_bus_idle = 0; cstat = kzqaddr->sii_cstat; dstat = kzqaddr->sii_dstat; do {/*XPRINTF(XPR_NFS, "B: %x", sc->sc_siidmacount[targid],0,0,0);cprintf("B: %x %x", sc->sc_siidmacount[targid],bp,0,0);*/ if(cstat & (SII_CI|SII_DI)) { /* Check for a BUS ERROR */ if(cstat & SII_BER) { kzqaddr->sii_cstat = SII_BER;#ifdef mips wbflush();#endif mips } /* Check for a PARITY ERROR */ if(dstat & SII_IPE) { flags = SZ_HARDERR | SZ_LOGREGS; scsi_logerr(sc, 0, targid, SZ_ET_PARITY, 0, 0, flags); PRINTD(targid, 0x10, ("kzq_scsistart: scsi %d parity error\n", cntlr)); goto HANDLE_ABORT; } /* Check for a BUS RESET */ if(cstat & SII_RST_ONBUS) { kzqaddr->sii_cstat = SII_RST_ONBUS;#ifdef mips wbflush();#endif mips scsi_logerr(sc, 0, -1, SZ_ET_BUSRST, 0, 0, SZ_HARDERR); PRINTD(targid, 0x10, ("kzq_scsistart: scsi %d bus reset\n", cntlr)); goto HANDLE_ABORT; } /* Check for a STATE CHANGE */ if(cstat & SII_SCH) { /* If SZ_BUSYTARG is set, the target returned a BUSY status for the current command. The target has disconnected from the bus. Return SZ_IP, and allow the interrupt handler take care of the disconnect. */ if( bp && (sc->sc_szflags[targid] & SZ_BUSYTARG) ) { PRINTD(targid, 0x4, ("kzq_scsistart: target %d BUSY rtn SZ_IP\n", targid )); return(SZ_IP); } kzqaddr->sii_cstat = SII_SCH; /* clear the intr */#ifdef mips wbflush(); /* wait for write buffers */#endif mips if(kzq_state_change(sc, &targid) != SZ_SUCCESS) goto HANDLE_ABORT; } /* If disconnected and went to BUS FREE STATE then break */ if(sc->scsi_bus_idle) break; /* Check for a PHASE MISMATCH */ if(dstat & SII_MIS) { /* Check for a BUS ERROR */ if(cstat & SII_BER) { kzqaddr->sii_cstat = SII_BER;#ifdef mips wbflush();#endif mips } /* Always clear DID DMA flag on a phase change */ sc->sc_szflags[targid] &= ~SZ_DID_DMA; /* Handle the current bus phase */ if(kzq_phase_change(sc, dstat) != SZ_SUCCESS) goto HANDLE_ABORT; /* Wait for the next bus phase */ if(!sc->scsi_completed[targid] && !(sc->sc_szflags[targid] & (SZ_WAS_DISCON|SZ_DID_DMA))) { timer = 1000; while(--timer && !(kzqaddr->sii_dstat & SII_MIS)); dstat = kzqaddr->sii_dstat; if(!sc->scsi_polled_mode && (timer == 0) && !(dstat & (SII_CI|SII_DI)) && (sc->sc_actcmd[targid] != SZ_RQSNS)) { PRINTD(targid, 0x4, ("kzq_scsistart: SII_MIS didn't set rtn SZ_IP\n")); return(SZ_IP); } } } /* Check for fragmented DMA transfers (>8K) */ if(sc->scsi_polled_mode && !(dstat & SII_MIS) && (dstat & (SII_TBE|SII_IBF)) && ((sc->sc_fstate == SZ_DATAI_PHA) || (sc->sc_fstate == SZ_DATAO_PHA))) { /* Restart the DMA transfer */ if(!kzq_restartdma(sc)) goto HANDLE_ABORT; } /* Sometimes the target stays in the same phase */ if((dstat & (SII_IBF|SII_TBE)) && !(dstat & SII_MIS) && ((sc->sc_fstate != SZ_DATAI_PHA) && (sc->sc_fstate != SZ_DATAO_PHA))) { /* Check for a BUS ERROR */ if(cstat & SII_BER) { kzqaddr->sii_cstat = SII_BER;#ifdef mips wbflush();#endif mips } /* Handle the current bus phase */ if(kzq_phase_change(sc, dstat) != SZ_SUCCESS) goto HANDLE_ABORT; } } dstat = kzqaddr->sii_dstat; cstat = kzqaddr->sii_cstat; /* } while(sc->scsi_polled_mode && /* dont spin in here!!!! */ } while(!sc->scsi_bus_idle && !(sc->sc_szflags[targid] & (SZ_WAS_DISCON|SZ_DID_DMA)));/*XPRINTF(XPR_NFS, "E: %x", sc->sc_siidmacount[targid],0,0,0);cprintf("E: %x", sc->sc_siidmacount[targid],0,0,0);*/ /* * Check the status of the current SCSI operation. If the SCSI * operation completed or disconnected then start the next SCSI * operation, otherwise wait for the DMA to complete. * */ if(sc->scsi_bus_idle || (sc->sc_szflags[targid] & SZ_WAS_DISCON)) { if(sc->scsi_completed[targid]) { PRINTD(targid, 0x4, ("kzq_scsistart: COMMAND COMPLETED successfully\n")); sc->scsi_completed[targid] = 0; sc->sc_active = 0; if (sc->sc_szflags[targid] & SZ_BUSYTARG) { return(SZ_IP); } if(sc->sc_status[targid] == SZ_GOOD) { return(SZ_SUCCESS); } else { return(SZ_RET_ERR); } } else if(sc->sc_szflags[targid] & SZ_WAS_DISCON) { PRINTD(targid, 0x4, ("kzq_scsistart: COMMAND IN PROGRESS disconnected\n")); return(SZ_IP); } else { sc->sc_active = 0;#ifdef NO_TIMER /* JAG */ if(sc->sc_szflags[targid] & SZ_TIMERON) { untimeout(sii_timer, (caddr_t)sc->sc_unit[targid]); sc->sc_szflags[targid] &= ~SZ_TIMERON; }#endif NO_TIMER /* JAG */ return(SZ_RET_ERR); } } else if(sc->sc_szflags[targid] & SZ_DID_DMA) { /* Poll and busy wait for DMA completion */ if(sc->scsi_polled_mode) { PRINTD(targid, 0x4, ("kzq_scsistart: COMMAND IN PROGRESS dma poll mode\n")); kzqaddr->sii_csr &= ~SII_IE;#ifdef mips wbflush();#endif mips SZWAIT_UNTIL((kzqaddr->sii_dstat & SII_DNE),kzq_wait_count,retval);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -