📄 scsi_kzq.c
字号:
tmp_phase = kzqaddr->sii_dstat & SII_PHA_MSK; tmp_state = kzqaddr->sii_cstat & SII_STATE_MSK; kzqaddr->sii_comm = (tmp_state | tmp_phase | attn);#ifdef mips wbflush();#endif mips /* Send the data to the scsi bus using programmed IO */ if(kzq_use_programmed_io && (sc->sc_siireqack[targid] == 0)) { for(i=0; i<count; i++) { SZWAIT_UNTIL((kzqaddr->sii_dstat & SII_TBE),kzq_wait_count,retval); if (retval >= kzq_wait_count) { scsi_logerr(sc, 0, targid, SZ_ET_BUSERR, 0x4a, 0, SZ_HARDERR); PRINTD(targid, 0x10, ("kzq_senddata: SII_TBE not set\n")); return(SZ_RET_ABORT); } kzqaddr->sii_data = *data++; tmp_phase = kzqaddr->sii_dstat & SII_PHA_MSK; tmp_state = kzqaddr->sii_cstat & SII_STATE_MSK; kzqaddr->sii_comm = (SII_INXFER | tmp_state | tmp_phase);#ifdef mips wbflush();#endif mips } kzqaddr->sii_dstat = SII_DNE;#ifdef mips wbflush();#endif mips return(SZ_SUCCESS); } /* Send the data to the scsi bus using DMA */ else { u_short aligndata;#ifdef mips if((u_long)data & 0x1) { aligndata = (u_short)(*data & 0x00ff); (sc->wmbcopy)(&aligndata,(sc->sc_rambuff+sc->sc_siidboff[targid]),count); } else { (sc->wmbcopy)(data, (sc->sc_rambuff + sc->sc_siidboff[targid]), count); } kzqaddr->sii_dmaddrl = ((sc->sc_siidboff[targid]) & 0x0ffff); kzqaddr->sii_dmaddrh = ((((sc->sc_siidboff[targid]) & 0x0fffffff))>>16);wbflush();#endif mips kzqaddr->sii_dmlotc = count; kzqaddr->sii_comm = (SII_DMA | SII_INXFER | tmp_state | tmp_phase | attn);#ifdef mips wbflush();#endif mips /* Wait for DMA to complete */ SZWAIT_UNTIL((kzqaddr->sii_dstat & SII_DNE),kzq_wait_count,retval); kzqaddr->sii_comm &= ~(SII_INXFER | SII_DMA); kzqaddr->sii_dstat = SII_DNE;#ifdef mips wbflush();#endif mips if(retval >= kzq_wait_count) { return(SZ_RET_ABORT); } return(SZ_SUCCESS); }}/****************************************************************** * * Receive data from the scsi bus. * ******************************************************************/#ifdef ELDEBUG/* Set ID of target to cause buserr 0x49 (bus 0 only) *//* DOES NOT WORK because programmed I/O is never used in kzq_recvdata() */int sz_eldb_buserr49 = -1;#endif ELDEBUGkzq_recvdata(sc, data, count)register struct sz_softc *sc;u_char *data;int count;{ int cntlr = sc->sc_siinum; register struct kzq_regs *kzqaddr = (struct kzq_regs *)sc->sc_scsiaddr; int retval; int tmp_state; int tmp_phase; int i; int targid = kzq_getactive_target(sc); /* Move the SII to the new phase */ tmp_phase = kzqaddr->sii_dstat & SII_PHA_MSK; tmp_state = kzqaddr->sii_cstat & SII_STATE_MSK; kzqaddr->sii_comm = (tmp_state | tmp_phase);#ifdef mips wbflush();#endif mips /* Recieve the data from the scsi bus using programmed IO */ if(kzq_use_programmed_io && (sc->sc_siireqack[targid] == 0)) { for(i=0; i<count; i++) { SZWAIT_UNTIL((kzqaddr->sii_dstat & (SII_IBF|SII_MIS)), kzq_wait_count, retval);#ifdef ELDEBUG if ((sc->sc_curcmd[targid] == SZ_READ) && (cntlr == 0) && (targid == sz_eldb_buserr49)) { retval = kzq_wait_count + 1; sz_eldb_buserr49 = -1; }#endif ELDEBUG if (retval >= kzq_wait_count) { scsi_logerr(sc, 0, targid, SZ_ET_BUSERR, 0x49, 0, SZ_HARDERR); PRINTD(targid, 0x10, ("kzq_recvdata: SII_IBF not set\n")); return(SZ_RET_ABORT); } /* If a phase change occured then we are done */ if(kzqaddr->sii_dstat & SII_MIS) break; *data++ = kzqaddr->sii_data; tmp_phase = kzqaddr->sii_dstat & SII_PHA_MSK; tmp_state = kzqaddr->sii_cstat & SII_STATE_MSK; kzqaddr->sii_comm = (SII_INXFER | tmp_state | tmp_phase);#ifdef mips wbflush();#endif mips } kzqaddr->sii_comm &= ~SII_INXFER; kzqaddr->sii_dstat = SII_DNE;#ifdef mips wbflush();#endif mips return(SZ_SUCCESS); } /* Recieve the data from the scsi bus using DMA */ else {#ifdef vax kzqaddr->sii_dmaddrl = (sc->sc_siidboff[targid] & 0xffff); kzqaddr->sii_dmaddrh = (sc->sc_siidboff[targid] >> 16);#endif vax#ifdef mips kzqaddr->sii_dmaddrl = ((sc->sc_siidboff[targid]) & 0x0ffffff); kzqaddr->sii_dmaddrh = ((((sc->sc_siidboff[targid]) & 0x0fffffff))>>16); wbflush(); kzqaddr->sii_dmlotc = count; kzqaddr->sii_comm = (SII_DMA | SII_INXFER | tmp_state | tmp_phase); wbflush();#endif mips /* Wait for DMA to complete, MIS is also checked. If the target changes phases, this loop will not have to time out. */ SZWAIT_UNTIL((kzqaddr->sii_dstat & (SII_DNE|SII_MIS)), kzq_wait_count, retval); kzqaddr->sii_comm &= ~(SII_INXFER | SII_DMA); /* set DNE */ if(retval >= kzq_wait_count && !(kzqaddr->sii_dstat & SII_DNE)) { i = 10000; /* wait for DNE */ while(--i && ((kzqaddr->sii_dstat & SII_DNE) == 0)) ; kzqaddr->sii_dstat = SII_DNE; } else kzqaddr->sii_dstat = SII_DNE; kzqaddr->sii_dmlotc = 0;#ifdef mips wbflush();#endif mips if(retval >= kzq_wait_count && !(kzqaddr->sii_dstat & SII_MIS)) return(SZ_RET_ABORT); (sc->rmbcopy)((sc->sc_rambuff + sc->sc_siidboff[targid]), data, count);#ifdef mips wbflush();#endif mips return(SZ_SUCCESS); }}/****************************************************************** * * Clear all disconnected IO tasks due to a BUS RESET. * ******************************************************************/kzq_clear_discon_io_tasks(sc)register struct sz_softc *sc;{ int targid; int unit; struct buf *dp, *bp; PRINTD(targid, 0x10, ("kzq_clear_discon_io_tasks: scanning IDs\n")); /* Find out if any targets have I/O requests that disconnected */ for(targid=0; targid<NDPS; targid++) { if( sc->sc_siireqack[targid] !=0 )/* if set: need to renegotiate */ sc->sc_siisentsync[targid] = 0; if(targid == sc->sc_sysid) /* skip initiator */ continue; if(sc->sc_alive[targid] == 0) /* non existent target */ continue; unit = sc->sc_unit[targid]; dp = (struct buf *)&szutab[unit]; if(!dp->b_active) /* target not active */ continue; if (dp->b_actf == NULL) continue; /* no IO requests pending */ if(!(sc->sc_szflags[targid] & SZ_WAS_DISCON)) { sc->sc_resid[targid] = sc->sc_b_bcount[targid]; continue; /* was not disconnected */ } PRINTD(targid, 0x10, ("kzq_clear_discon_io_tasks: clearing ID %d\n", targid)); bp = dp->b_actf; dp->b_actf = bp->av_forw; dp->b_active = 0; bp->b_resid = sc->sc_resid[targid]; bp->b_flags |= B_ERROR; bp->b_error = EIO; biodone(bp); sc->sc_xstate[targid] = SZ_NEXT; sc->sc_xevent[targid] = SZ_BEGIN; }}/****************************************************************** * * Reset the SII chip. * ******************************************************************/kzq_reset(sc)register struct sz_softc *sc;{ int cntlr = sc->sc_siinum; register struct kzq_regs *kzqaddr = (struct kzq_regs *)sc->sc_scsiaddr; int targid; /* Reset the SII chip. */ kzqaddr->sii_comm = SII_CHRESET; /* SII is always ID 7, and set up max REQ/ACK offset. */ kzqaddr->sii_id = SII_ID_IO | sc->sc_sysid; /* Enable SII to drive SCSI bus. */ kzqaddr->sii_dictrl = SII_PRE; /* * Assert SCSI bus reset for at least 25 Usec to clear the * world. SII_RST is self clearing. */ kzqaddr->sii_comm = SII_RST; DELAY(25); /* * Clear any pending interrupts from the reset. */ kzqaddr->sii_cstat = kzqaddr->sii_cstat; kzqaddr->sii_dstat = kzqaddr->sii_dstat; /************************************************************/ /* */ /* Clear out KZQ DMA registers. */ /************************************************************/ kzqaddr->kzq_lbar = 0; kzqaddr->kzq_qbar = 0; kzqaddr->kzq_wc = 0; /* * Set up SII for SCSI parity checking, * Select Enable, Reselect Enable, and Interrupt Enable. */ kzqaddr->sii_csr = ( SII_RSE |SII_SLE | SII_PCE | SII_IE); /* * Clear all Active and Disconnected IO requests. */ kzq_clear_discon_io_tasks(sc); sc->sii_was_reset = 1; DELAY(sz_wait_for_devices * 1000000);}/****************************************************************** * * Reset all the SII controllers (crash dump reset only). * ******************************************************************/kzqreset(){#ifdef mips register struct sz_softc *sc = &sz_softc[0]; register struct kzq_regs *kzqaddr = (struct kzq_regs *)sc->sc_scsiaddr;#endif mips /* Reset the SII chip. */ kzqaddr->sii_comm = SII_CHRESET; /* SII is always ID 7, and set up max REQ/ACK offset. */ kzqaddr->sii_id = SII_ID_IO | sc->sc_sysid; /* Enable SII to drive SCSI bus. */ kzqaddr->sii_dictrl = SII_PRE; /* * Assert SCSI bus reset for at least 25 Usec to clear the * world. SII_RST is self clearing. */ kzqaddr->sii_comm = SII_RST; DELAY(25); /* * Clear any pending interrupts from the reset. */ kzqaddr->sii_cstat = kzqaddr->sii_cstat; kzqaddr->sii_dstat = kzqaddr->sii_dstat; /* * Set up SII for SCSI parity checking, * Select Enable, Reselect Enable, and Interrupt Enable. */ kzqaddr->sii_csr = ( SII_RSE |SII_SLE | SII_PCE | SII_IE); DELAY(5000000);}/****************************************************************** * * Handle interrupts from the SII chip. * ******************************************************************/#ifdef ELDEBUG/* Set to ID of target to log a parity error (bus 0 only) */int sz_eldb_parity = -1;/* Set to ID of target to log a reset detected error (bus 0 only) */int sz_eldb_busrst = -1;#endif ELDEBUGkzq_intr(cntlr)int cntlr;{ register struct sz_softc *sc = &sz_softc[cntlr]; register struct kzq_regs *kzqaddr = (struct kzq_regs *)sc->sc_scsiaddr; int targid, retval, timer; int dmacount, offset, tmp_phase, tmp_state; int handle_reselect; u_short cstat, dstat; int flags;#ifdef mips if(kzq_stray_intr[cntlr] != 1) { /* Stray interrupt on reboot */ /* Reset the SII chip. */ kzqaddr->sii_comm = SII_CHRESET; printf("kzq_intr: noprobe intr\n"); return; }#endif mips /* Initialize variables */ targid = kzq_getactive_target(sc);#ifdef vax sc->scsi_bus_idle = 0; sc->scsi_completed[targid] = 0;#endif vax handle_reselect = 0; /*the toggling of the IE bit in the csr is to allow the latched IRQ */ /* line to toggle. On the Ibus there is no latch, since it is based */ /* on levels. On the Qbus the transition is necessary. */ /* Thus the reset/set of the enable allows the latch to reflect */ /* the new incoming state and thus to pass that to the SII IRQ */ /* line. Without this toggle it is possible to miss an interrupt. */ kzqaddr->sii_csr &= ~SII_IE; /*reset/set IE to toggle kzq IRQ */ cstat = kzqaddr->sii_cstat; dstat = kzqaddr->sii_dstat; kzqaddr->sii_csr |= SII_IE; /* enable ints after grabbing regs */ /* Check for interrupt from a disconnected target */ if(targid == -1 || sc->sc_active == 0) { /* Check if there are valid interrupts pending */ if(cstat & (SII_CI|SII_DI)) { /* We must wait for a STATE CHANGE to occur first */ timer = 10000; while(--timer && ((kzqaddr->sii_cstat & SII_SCH) == 0)); if(timer == 0) {/*cprintf("timer expired in interrupt, cstat= %x, dstat= %x\n", cstat, dstat);*/ /* * Check if a reselect occurred without the STATE * CHANGE bit (SII_SCH) being set. This condition * can occur when a reselect immediately follows a * disconnect and therefore we only get one STATE * CHANGE interrupt. */ cstat = kzqaddr->sii_cstat; if((cstat & SII_DST_ONBUS) && (cstat & SII_CON)) handle_reselect = 1; else { if(cstat & SII_RST_ONBUS) { kzqaddr->sii_cstat &= ~SII_IE; kzqaddr->sii_cstat = SII_RST_ONBUS; kzqaddr->sii_cstat = SII_SCH; kzqaddr->sii_cstat = SII_IE;#ifdef mips wbflush();#endif mips } return; } } } /* No interrupts pending, spurious interrupt occurred */ else { PRINTD(0xFF, 0x1, ("kzq_intr: spurious interrupt from inactive target\n")); return; } }/*end of int from disconnected target.*/#ifdef ELDEBUG if ((sc->sc_curcmd[targid] == SZ_READ) && (cntlr == 0) && (targid == sz_eldb_parity)) { flags = SZ_HARDERR | SZ_LOGREGS; scsi_logerr(sc, 0, targid, SZ_ET_PARITY, 1, 0, flags); sz_eldb_parity = -1; } if ((sc->sc_curcmd[targid] == SZ_READ) && (cntlr == 0) && (targid == sz_eldb_busrst)) { scsi_logerr(sc, 0, -1, SZ_ET_BUSRST, 1, 0, SZ_HARDERR); sz_eldb_busrst = -1; goto HANDLE_ERROR; }#endif ELDEBUG XPRINTF(XPR_NFS, "intB: %x %x %x %x", sc->sc_siidmacount[targid],cstat,dstat,kzqaddr->sii_comm); offset = (sc->sc_bpcount[targid] - sc->sc_siidmacount[targid]); if(cstat & (SII_CI|SII_DI)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -