📄 sii.c
字号:
/* send a reject message */ regs->data = SCSI_MESSAGE_REJECT; regs->comm = SII_INXFER | SII_ATN | (regs->cstat & SII_STATE_MSK) | SII_MSG_OUT_PHASE; MachEmptyWriteBuffer(); /* wait for XFER complete */ SII_WAIT_UNTIL(dstat, regs->dstat, (dstat & (SII_DNE | SII_PHASE_MSK)) == (SII_DNE | SII_MSG_OUT_PHASE), SII_WAIT_COUNT, i); if ((dstat & (SII_DNE | SII_PHASE_MSK)) != (SII_DNE | SII_MSG_OUT_PHASE)) break; regs->dstat = SII_DNE; MachEmptyWriteBuffer(); } break; case SCSI_SAVE_DATA_POINTER: case SCSI_RESTORE_POINTERS: /* wait a short time for another msg */ SII_WAIT_UNTIL(dstat, regs->dstat, dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i); if (dstat & (SII_CI | SII_DI)) {#ifdef DEBUG if (sii_debug > 4) printf("cnt %d\n", i);#endif goto again; } break; case SCSI_DISCONNECT: state->prevComm = comm;#ifdef DEBUG if (sii_debug > 4) printf("disconn %d ", sc->sc_target);#endif /* * Wait a short time for disconnect. * Don't be fooled if SII_BER happens first. * Note: a reselect may happen here. */ SII_WAIT_UNTIL(cstat, regs->cstat, cstat & (SII_RST | SII_SCH), SII_WAIT_COUNT, i); if ((cstat & (SII_RST | SII_SCH | SII_STATE_MSK)) != SII_SCH) {#ifdef DEBUG if (sii_debug > 4) printf("cnt %d\n", i);#endif dstat = regs->dstat; goto again; } regs->cstat = SII_SCH | SII_BER; regs->comm = 0; MachEmptyWriteBuffer(); sc->sc_target = -1; /* * Double check that we didn't miss a state * change between seeing it and clearing * the SII_SCH bit. */ i = regs->cstat; if (!(i & SII_SCH) && (i & SII_STATE_MSK) != (cstat & SII_STATE_MSK)) sii_StateChg(sc, i); break; case SCSI_MESSAGE_REJECT: printf("sii%d: device %d: message reject.\n", sc - sii_softc, sc->sc_target); goto abort; default: if (!(msg & SCSI_IDENTIFY)) { printf("sii%d: device %d: couldn't handle message 0x%x... ignoring.\n", sc - sii_softc, sc->sc_target, msg);#ifdef DEBUG sii_DumpLog();#endif break; } /* may want to check LUN some day */ /* wait a short time for another msg */ SII_WAIT_UNTIL(dstat, regs->dstat, dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i); if (dstat & (SII_CI | SII_DI)) {#ifdef DEBUG if (sii_debug > 4) printf("cnt %d\n", i);#endif goto again; } } break; case SII_MSG_OUT_PHASE:#ifdef DEBUG if (sii_debug > 4) printf("MsgOut\n");#endif regs->data = SCSI_NO_OP; regs->comm = SII_INXFER | (comm & SII_STATE_MSK) | SII_MSG_OUT_PHASE; MachEmptyWriteBuffer(); /* wait a short time for XFER complete */ SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE, SII_WAIT_COUNT, i);#ifdef DEBUG if (sii_debug > 4) printf("ds %x i %d\n", dstat, i);#endif /* just clear the DNE bit and check errors later */ if (dstat & SII_DNE) { regs->dstat = SII_DNE; MachEmptyWriteBuffer(); } break; default: printf("sii%d: Couldn't handle phase %d... ignoring.\n", sc - sii_softc, dstat & SII_PHASE_MSK); } }#ifdef DEBUG if (sii_debug > 3) printf("\n");#endif /* * Check to make sure we won't be interrupted again. * Deglitch dstat register. */ msg = regs->dstat; while (msg != (dstat = regs->dstat)) msg = dstat; if (dstat & (SII_CI | SII_DI)) goto again; if (sc->sc_target < 0) { /* look for another device that is ready */ for (i = 0; i < SII_NCMD; i++) { /* don't restart a disconnected command */ if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm) continue; sii_StartCmd(sc, i); break; } } return;abort: /* jump here to abort the current command */ printf("sii%d: device %d: current command terminated\n", sc - sii_softc, sc->sc_target);#ifdef DEBUG sii_DumpLog();#endif if ((cstat = regs->cstat) & SII_CON) { /* try to send an abort msg for awhile */ regs->dstat = SII_DNE; regs->data = SCSI_ABORT; regs->comm = SII_INXFER | SII_ATN | (cstat & SII_STATE_MSK) | SII_MSG_OUT_PHASE; MachEmptyWriteBuffer(); SII_WAIT_UNTIL(dstat, regs->dstat, (dstat & (SII_DNE | SII_PHASE_MSK)) == (SII_DNE | SII_MSG_OUT_PHASE), 2 * SII_WAIT_COUNT, i);#ifdef DEBUG if (sii_debug > 0) printf("Abort: cs %x ds %x i %d\n", cstat, dstat, i);#endif if (dstat & (SII_DNE | SII_PHASE_MSK) == (SII_DNE | SII_MSG_OUT_PHASE)) { /* disconnect if command in progress */ regs->comm = SII_DISCON; MachEmptyWriteBuffer(); SII_WAIT_UNTIL(cstat, regs->cstat, !(cstat & SII_CON), SII_WAIT_COUNT, i); } } else {#ifdef DEBUG if (sii_debug > 0) printf("Abort: cs %x\n", cstat);#endif } regs->cstat = 0xffff; regs->dstat = 0xffff; regs->comm = 0; MachEmptyWriteBuffer(); i = sc->sc_target; sc->sc_target = -1; sii_CmdDone(sc, i, EIO);#ifdef DEBUG if (sii_debug > 4) printf("sii_DoIntr: after CmdDone target %d\n", sc->sc_target);#endif}static voidsii_StateChg(sc, cstat) register struct siisoftc *sc; register unsigned cstat;{ register SIIRegs *regs = sc->sc_regs; register State *state; register int i;#ifdef DEBUG if (sii_debug > 4) printf("SCH: ");#endif switch (cstat & SII_STATE_MSK) { case 0: /* disconnect */ i = sc->sc_target; sc->sc_target = -1;#ifdef DEBUG if (sii_debug > 4) printf("disconn %d ", i);#endif if (i >= 0 && !sc->sc_st[i].prevComm) { printf("sii%d: device %d: spurrious disconnect (%d)\n", sc - sii_softc, i, regs->slcsr); sc->sc_st[i].prevComm = 0; } break; case SII_CON: /* connected as initiator */ i = regs->slcsr; if (sc->sc_target == i) break; printf("sii%d: device %d: connect to device %d??\n", sc - sii_softc, sc->sc_target, i); sc->sc_target = i; break; case SII_DST: /* * Wait for CON to become valid, * chip is slow sometimes. */ SII_WAIT_UNTIL(cstat, regs->cstat, cstat & SII_CON, SII_WAIT_COUNT, i); if (!(cstat & SII_CON)) panic("sii resel"); /* FALLTHROUGH */ case SII_CON | SII_DST: /* * Its a reselection. Save the ID and wait for * interrupts to tell us what to do next * (should be MSG_IN of IDENTIFY). * NOTE: sc_target may be >= 0 if we were in * the process of trying to start a command * and were reselected before the select * command finished. */ sc->sc_target = i = regs->destat; regs->comm = SII_CON | SII_DST | SII_MSG_IN_PHASE; MachEmptyWriteBuffer(); state = &sc->sc_st[i]; if (!state->prevComm) { printf("sii%d: device %d: spurrious reselection\n", sc - sii_softc, i); break; } state->prevComm = 0;#ifdef DEBUG if (sii_debug > 4) printf("resel %d ", sc->sc_target);#endif break;#ifdef notyet case SII_DST | SII_TGT: case SII_CON | SII_DST | SII_TGT: /* connected as target */ printf("sii%d: Selected by device %d as target!!\n", sc - sii_softc, regs->destat); regs->comm = SII_DISCON; MachEmptyWriteBuffer(); SII_WAIT_UNTIL(!(regs->cstat & SII_CON), SII_WAIT_COUNT, i); regs->cstat = 0xffff; regs->dstat = 0xffff; regs->comm = 0; break;#endif default: printf("sii%d: Unknown state change (cs %x)!!\n", sc - sii_softc, cstat);#ifdef DEBUG sii_DumpLog();#endif }}/* * Read one byte of data. */static intsii_GetByte(regs, phase) register SIIRegs *regs; int phase;{ register unsigned dstat; register unsigned state;#ifdef PROGXFER register unsigned data; dstat = regs->dstat; state = regs->cstat & SII_STATE_MSK; regs->dmctrl = 0; if (!(dstat & SII_IBF) || (dstat & SII_MIS)) { regs->comm = state | phase; MachEmptyWriteBuffer(); /* wait a short time for IBF */ SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_IBF, SII_WAIT_COUNT, i);#ifdef DEBUG if (!(dstat & SII_IBF)) printf("status no IBF\n");#endif } data = regs->data; if (regs->dstat & SII_DNE) { /* XXX */ printf("sii_GetByte: DNE set 5\n"); sii_DumpLog(); regs->dstat = SII_DNE; } regs->comm = SII_INXFER | state | phase; MachEmptyWriteBuffer(); /* wait a short time for XFER complete */ SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE, SII_WAIT_COUNT, i); if ((dstat & (SII_DNE | SII_IPE)) != SII_DNE) {#ifdef DEBUG if (sii_debug > 4) printf("cnt0 %d\n", i);#endif printf("MsgIn %x ?? ds %x cm %x i %d\n", data, dstat, comm, i); /* XXX */ sii_DumpLog(); /* XXX */ panic("status"); /* XXX */ goto again; } /* clear the DNE, other errors handled later */ regs->dstat = SII_DNE; MachEmptyWriteBuffer(); return (data);#else /* PROGXFER */ register int i; state = regs->cstat & SII_STATE_MSK; regs->dmctrl = 0; if (regs->dstat & SII_DNE) { printf("sii_GetByte: DNE cs %x ds %x cm %x\n", regs->cstat, regs->dstat, regs->comm); /* XXX */ regs->dstat = SII_DNE; } regs->dmaddrl = ((u_short)SII_BUF_ADDR >> 1); regs->dmaddrh = ((u_short)SII_BUF_ADDR >> 17) & 03; regs->dmlotc = 1; regs->comm = SII_DMA | SII_INXFER | state | phase; MachEmptyWriteBuffer(); /* wait a short time for XFER complete */ SII_WAIT_UNTIL(dstat, regs->dstat, (dstat & (SII_DNE | SII_TCZ)) == (SII_DNE | SII_TCZ), SII_WAIT_COUNT, i); if ((dstat & (SII_DNE | SII_TCZ | SII_IPE)) != (SII_DNE | SII_TCZ)) { printf("sii_GetByte: cs %x ds %x cm %x i %d lotc %d\n", regs->cstat, dstat, regs->comm, i, regs->dmlotc); /* XXX */ sii_DumpLog(); /* XXX */ return (-1); } /* clear the DNE, other errors handled later */ regs->dstat = SII_DNE; MachEmptyWriteBuffer(); /* return one byte of data (optimized CopyFromBuffer()) */ return (*(volatile u_short *)SII_BUF_ADDR & 0xFF);#endif /* PROGXFER */}/* * Exchange messages to initiate synchronous data transfers. */static voidsii_DoSync(regs, state) register SIIRegs *regs; register State *state;{ register unsigned dstat; register int i; unsigned len; printf("sii_DoSync: per %d req/ack %d\n", sii_buf[3], sii_buf[4]); /* XXX */ len = sii_buf[4]; if (len > 3) len = 3; /* SII chip can only handle 3 max */ sii_buf[0] = SCSI_EXTENDED_MSG; sii_buf[1] = 3; /* message length */ sii_buf[2] = SCSI_SYNCHRONOUS_XFER; sii_buf[4] = len; CopyToBuffer((u_short *)sii_buf, (volatile u_short *)SII_BUF_ADDR, 5); regs->dmaddrl = ((u_short)SII_BUF_ADDR >> 1); regs->dmaddrh = ((u_short)SII_BUF_ADDR >> 17) & 03; regs->dmlotc = 5; regs->comm = SII_DMA | SII_INXFER | SII_ATN | (regs->cstat & SII_STATE_MSK) | SII_MSG_OUT_PHASE; MachEmptyWriteBuffer(); /* wait a short time for XFER complete */ SII_WAIT_UNTIL(dstat, regs->dstat, (dstat & (SII_DNE | SII_TCZ)) == (SII_DNE | SII_TCZ), SII_WAIT_COUNT, i); if ((dstat & (SII_DNE | SII_TCZ)) != (SII_DNE | SII_TCZ)) { printf("sii_DoSync: ds %x cm %x i %d lotc %d\n", dstat, regs->comm, i, regs->dmlotc); /* XXX */ sii_DumpLog(); /* XXX */ return; } /* clear the DNE, other errors handled later */ regs->dstat = SII_DNE; regs->comm = regs->comm & SII_STATE_MSK; MachEmptyWriteBuffer(); state->dmaReqAck = len;}/* * Issue the sequence of commands to the controller to start DMA. * NOTE: the data buffer should be word-aligned for DMA out. */static voidsii_StartDMA(regs, phase, dmaAddr, size) register SIIRegs *regs; /* which SII to use */ int phase; /* phase to send/receive data */ u_short *dmaAddr; /* DMA buffer address */ int size; /* # of bytes to transfer */{ if (regs->dstat & SII_DNE) { /* XXX */ printf("sii_StartDMA: DNE set\n"); sii_DumpLog(); regs->dstat = SII_DNE; } regs->dmaddrl = ((unsigned)dmaAddr >> 1); regs->dmaddrh = ((unsigned)dmaAddr >> 17) & 03; regs->dmlotc = size; regs->comm = SII_DMA | SII_INXFER | (regs->cstat & SII_STATE_MSK) | phase; MachEmptyWriteBuffer();#ifdef DEBUG if (sii_debug > 5) { printf("sii_StartDMA: cs 0x%x, ds 0x%x, cm 0x%x, size %d\n", regs->cstat, regs->dstat, regs->comm, size); }#endif}/* * Call the device driver's 'done' routine to let it know the command is done. * The 'done' routine may try to start another command. * To be fair, we should start pending commands for other devices * before allowing the same device to start another command. */static voidsii_CmdDone(sc, target, error) register struct siisoftc *sc; /* which SII to use */ int target; /* which device is done */ int error; /* error code if any errors */{ register ScsiCmd *scsicmd; register int i; scsicmd = sc->sc_cmd[target];#ifdef DIAGNOSTIC if (target < 0 || !scsicmd) panic("sii_CmdDone");#endif sc->sc_cmd[target] = (ScsiCmd *)0;#ifdef DEBUG if (sii_debug > 1) { printf("sii_CmdDone: %s target %d cmd %x err %d resid %d\n", scsicmd->sd->sd_driver->d_name, target, scsicmd->cmd[0], error, sc->sc_st[target].buflen); }#endif /* look for another device that is ready */ for (i = 0; i < SII_NCMD; i++) { /* don't restart a disconnected command */ if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm) continue; sii_StartCmd(sc, i); break; } (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, error, sc->sc_st[target].buflen, sc->sc_st[target].statusByte);}#ifdef DEBUGsii_DumpLog(){ register struct sii_log *lp; printf("sii: cmd %x bn %d cnt %d\n", sii_debug_cmd, sii_debug_bn, sii_debug_sz); lp = sii_logp; do { printf("target %d cs %x ds %x cm %x msg %x\n", lp->target, lp->cstat, lp->dstat, lp->comm, lp->msg); if (++lp >= &sii_log[NLOG]) lp = sii_log; } while (lp != sii_logp);}#endif#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -