📄 sii.c
字号:
MachEmptyWriteBuffer();#ifdef DEBUG if (sii_logp > sii_log) sii_logp[-1].cstat = cstat; else sii_log[NLOG - 1].cstat = cstat;#endif /* check for a BUS RESET */ if (cstat & SII_RST) { printf("sii%d: SCSI bus reset!!\n", sc - sii_softc); /* need to flush disconnected commands */ for (i = 0; i < SII_NCMD; i++) { if (!sc->sc_cmd[i]) continue; sii_CmdDone(sc, i, EIO); } /* rearbitrate synchronous offset */ for (i = 0; i < SII_NCMD; i++) sc->sc_st[i].dmaReqAck = 0; sc->sc_target = -1; return; }#ifdef notdef /* * Check for a BUS ERROR. * According to DEC, this feature doesn't really work * and to just clear the bit if it's set. */ if (cstat & SII_BER) { }#endif /* check for state change */ if (cstat & SII_SCH) { sii_StateChg(sc, cstat); comm = regs->comm; } } /* check for DMA completion */ if (dstat & SII_DNE) { u_short *dma; char *buf; /* check for a PARITY ERROR */ if (dstat & SII_IPE) { printf("sii%d: Parity error!!\n", sc - sii_softc); goto abort; } /* * There is a race condition with SII_SCH. There is a short * window between the time a SII_SCH is seen after a disconnect * and when the SII_SCH is cleared. A reselect can happen * in this window and we will clear the SII_SCH without * processing the reconnect. */ if (sc->sc_target < 0) { cstat = regs->cstat; printf("sii%d: target %d DNE?? dev %d,%d cs %x\n", sc - sii_softc, sc->sc_target, regs->slcsr, regs->destat, cstat); /* XXX */ if (cstat & SII_DST) { sc->sc_target = regs->destat; state->prevComm = 0; } else panic("sc_target 1"); } state = &sc->sc_st[sc->sc_target]; /* dmalen = amount left to transfer, i = amount transfered */ i = state->dmalen; state->dmalen = 0; state->dmaCurPhase = -1;#ifdef DEBUG if (sii_debug > 4) { printf("DNE: amt %d ", i); if (!(dstat & SII_TCZ)) printf("no TCZ?? (%d) ", regs->dmlotc); } else if (!(dstat & SII_TCZ)) { printf("sii%d: device %d: no TCZ?? (%d)\n", sc - sii_softc, sc->sc_target, regs->dmlotc); sii_DumpLog(); /* XXX */ }#endif switch (comm & SII_PHASE_MSK) { case SII_CMD_PHASE: state->cmdlen -= i; break; case SII_DATA_IN_PHASE: /* check for more data for the same phase */ dma = state->dmaAddr[state->dmaBufIndex]; buf = state->buf; state->buf += i; state->buflen -= i; if (state->buflen > 0 && !(dstat & SII_MIS)) { int len; /* start reading next chunk */ len = state->buflen; if (len > SII_MAX_DMA_XFER_LENGTH) len = SII_MAX_DMA_XFER_LENGTH; state->dmaBufIndex = !state->dmaBufIndex; sii_StartDMA(regs, state->dmaCurPhase = SII_DATA_IN_PHASE, state->dmaAddr[state->dmaBufIndex], state->dmalen = len); dstat &= ~(SII_IBF | SII_TBE); } /* copy in the data */ CopyFromBuffer((volatile u_short *)dma, buf, i); break; case SII_DATA_OUT_PHASE: state->dmaBufIndex = !state->dmaBufIndex; state->buf += i; state->buflen -= i; /* check for more data for the same phase */ if (state->buflen <= 0 || (dstat & SII_MIS)) break; /* start next chunk */ i = state->buflen; if (i > SII_MAX_DMA_XFER_LENGTH) { sii_StartDMA(regs, state->dmaCurPhase = SII_DATA_OUT_PHASE, state->dmaAddr[state->dmaBufIndex], state->dmalen = SII_MAX_DMA_XFER_LENGTH); /* prepare for next chunk */ i -= SII_MAX_DMA_XFER_LENGTH; if (i > SII_MAX_DMA_XFER_LENGTH) i = SII_MAX_DMA_XFER_LENGTH; CopyToBuffer((u_short *)(state->buf + SII_MAX_DMA_XFER_LENGTH), (volatile u_short *) state->dmaAddr[!state->dmaBufIndex], i); } else { sii_StartDMA(regs, state->dmaCurPhase = SII_DATA_OUT_PHASE, state->dmaAddr[state->dmaBufIndex], state->dmalen = i); } dstat &= ~(SII_IBF | SII_TBE); break; default: printf("sii%d: device %d: unexpected DNE\n", sc - sii_softc, sc->sc_target);#ifdef DEBUG sii_DumpLog();#endif } } /* check for phase change or another MsgIn/Out */ if (dstat & (SII_MIS | SII_IBF | SII_TBE)) { /* * There is a race condition with SII_SCH. There is a short * window between the time a SII_SCH is seen after a disconnect * and when the SII_SCH is cleared. A reselect can happen * in this window and we will clear the SII_SCH without * processing the reconnect. */ if (sc->sc_target < 0) { cstat = regs->cstat; printf("sii%d: target %d MIS?? dev %d,%d cs %x ds %x\n", sc - sii_softc, sc->sc_target, regs->slcsr, regs->destat, cstat, dstat); /* XXX */ if (cstat & SII_DST) { sc->sc_target = regs->destat; state->prevComm = 0; } else panic("sc_target 2"); } state = &sc->sc_st[sc->sc_target]; switch (dstat & SII_PHASE_MSK) { case SII_CMD_PHASE: if (state->dmaPrevPhase >= 0) { /* restart DMA after disconnect/reconnect */ if (state->dmaPrevPhase != SII_CMD_PHASE) { printf("sii%d: device %d: dma reselect phase doesn't match\n", sc - sii_softc, sc->sc_target); goto abort; } state->dmaCurPhase = SII_CMD_PHASE; state->dmaPrevPhase = -1; regs->dmaddrl = state->dmaAddrL; regs->dmaddrh = state->dmaAddrH; regs->dmlotc = state->dmaCnt; if (state->dmaCnt & 1) regs->dmabyte = state->dmaByte; regs->comm = SII_DMA | SII_INXFER | (comm & SII_STATE_MSK) | SII_CMD_PHASE; MachEmptyWriteBuffer();#ifdef DEBUG if (sii_debug > 4) printf("Cmd dcnt %d dadr %x ", state->dmaCnt, (state->dmaAddrH << 16) | state->dmaAddrL);#endif } else { /* send command data */ i = state->cmdlen; if (i == 0) { printf("sii%d: device %d: cmd count exceeded\n", sc - sii_softc, sc->sc_target); goto abort; } CopyToBuffer((u_short *)state->cmd, (volatile u_short *)state->dmaAddr[0], i); sii_StartDMA(regs, state->dmaCurPhase = SII_CMD_PHASE, state->dmaAddr[0], state->dmalen = i); } /* wait a short time for XFER complete */ 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); else if (sii_debug > 0) printf("sii_DoIntr: cmd wait ds %x cnt %d\n", dstat, i);#endif goto again; } break; case SII_DATA_IN_PHASE: case SII_DATA_OUT_PHASE: regs->dmctrl = state->dmaReqAck; if (state->cmdlen > 0) { printf("sii%d: device %d: cmd %x: command data not all sent (%d) 1\n", sc - sii_softc, sc->sc_target, sc->sc_cmd[sc->sc_target]->cmd[0], state->cmdlen); state->cmdlen = 0;#ifdef DEBUG sii_DumpLog();#endif } if (state->dmaPrevPhase >= 0) { /* restart DMA after disconnect/reconnect */ if (state->dmaPrevPhase != (dstat & SII_PHASE_MSK)) { printf("sii%d: device %d: dma reselect phase doesn't match\n", sc - sii_softc, sc->sc_target); goto abort; } state->dmaCurPhase = state->dmaPrevPhase; state->dmaPrevPhase = -1; regs->dmaddrl = state->dmaAddrL; regs->dmaddrh = state->dmaAddrH; regs->dmlotc = state->dmaCnt; if (state->dmaCnt & 1) regs->dmabyte = state->dmaByte; regs->comm = SII_DMA | SII_INXFER | (comm & SII_STATE_MSK) | state->dmaCurPhase; MachEmptyWriteBuffer();#ifdef DEBUG if (sii_debug > 4) printf("Data %d dcnt %d dadr %x ", state->dmaDataPhase, state->dmaCnt, (state->dmaAddrH << 16) | state->dmaAddrL);#endif break; } if (state->dmaDataPhase != (dstat & SII_PHASE_MSK)) { printf("sii%d: device %d: cmd %x: dma phase doesn't match\n", sc - sii_softc, sc->sc_target, sc->sc_cmd[sc->sc_target]->cmd[0]); goto abort; }#ifdef DEBUG if (sii_debug > 4) { printf("Data %d ", state->dmaDataPhase); if (sii_debug > 5) printf("\n"); }#endif i = state->buflen; if (i == 0) { printf("sii%d: device %d: data count exceeded\n", sc - sii_softc, sc->sc_target); goto abort; } if (i > SII_MAX_DMA_XFER_LENGTH) i = SII_MAX_DMA_XFER_LENGTH; if ((dstat & SII_PHASE_MSK) == SII_DATA_IN_PHASE) { sii_StartDMA(regs, state->dmaCurPhase = SII_DATA_IN_PHASE, state->dmaAddr[state->dmaBufIndex], state->dmalen = i); break; } /* start first chunk */ if (state->flags & FIRST_DMA) { state->flags &= ~FIRST_DMA; CopyToBuffer((u_short *)state->buf, (volatile u_short *) state->dmaAddr[state->dmaBufIndex], i); } sii_StartDMA(regs, state->dmaCurPhase = SII_DATA_OUT_PHASE, state->dmaAddr[state->dmaBufIndex], state->dmalen = i); i = state->buflen - SII_MAX_DMA_XFER_LENGTH; if (i > 0) { /* prepare for next chunk */ if (i > SII_MAX_DMA_XFER_LENGTH) i = SII_MAX_DMA_XFER_LENGTH; CopyToBuffer((u_short *)(state->buf + SII_MAX_DMA_XFER_LENGTH), (volatile u_short *) state->dmaAddr[!state->dmaBufIndex], i); } break; case SII_STATUS_PHASE: if (state->cmdlen > 0) { printf("sii%d: device %d: cmd %x: command data not all sent (%d) 2\n", sc - sii_softc, sc->sc_target, sc->sc_cmd[sc->sc_target]->cmd[0], state->cmdlen); state->cmdlen = 0;#ifdef DEBUG sii_DumpLog();#endif } /* read amount transfered if DMA didn't finish */ if (state->dmalen > 0) { i = state->dmalen - regs->dmlotc; state->dmalen = 0; state->dmaCurPhase = -1; regs->dmlotc = 0; regs->comm = comm & (SII_STATE_MSK | SII_PHASE_MSK); MachEmptyWriteBuffer(); regs->dstat = SII_DNE; MachEmptyWriteBuffer();#ifdef DEBUG if (sii_debug > 4) printf("DMA amt %d ", i);#endif switch (comm & SII_PHASE_MSK) { case SII_DATA_IN_PHASE: /* copy in the data */ CopyFromBuffer((volatile u_short *) state->dmaAddr[state->dmaBufIndex], state->buf, i); case SII_CMD_PHASE: case SII_DATA_OUT_PHASE: state->buflen -= i; } } /* read a one byte status message */ state->statusByte = msg = sii_GetByte(regs, SII_STATUS_PHASE); if (msg < 0) { dstat = regs->dstat; goto again; }#ifdef DEBUG if (sii_debug > 4) printf("Status %x ", msg); if (sii_logp > sii_log) sii_logp[-1].msg = msg; else sii_log[NLOG - 1].msg = msg;#endif /* do a quick wait for COMMAND_COMPLETE */ 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("cnt2 %d\n", i);#endif goto again; } break; case SII_MSG_IN_PHASE: /* * Save DMA state if DMA didn't finish. * Be careful not to save state again after reconnect * and see RESTORE_POINTER message. * Note that the SII DMA address is not incremented * as DMA proceeds. */ if (state->dmaCurPhase > 0) { /* save dma registers */ state->dmaPrevPhase = state->dmaCurPhase; state->dmaCurPhase = -1; state->dmaCnt = i = regs->dmlotc; if (dstat & SII_OBB) state->dmaByte = regs->dmabyte; if (i == 0) i = SII_MAX_DMA_XFER_LENGTH; i = state->dmalen - i; /* note: no carry from dmaddrl to dmaddrh */ state->dmaAddrL = regs->dmaddrl + i; state->dmaAddrH = regs->dmaddrh; regs->comm = comm & (SII_STATE_MSK | SII_PHASE_MSK); MachEmptyWriteBuffer(); regs->dstat = SII_DNE; MachEmptyWriteBuffer();#ifdef DEBUG if (sii_debug > 4) { printf("SavP dcnt %d dadr %x ", state->dmaCnt, (state->dmaAddrH << 16) | state->dmaAddrL); if (((dstat & SII_OBB) != 0) ^ (state->dmaCnt & 1)) printf("OBB??? "); } else if (sii_debug > 0) { if (((dstat & SII_OBB) != 0) ^ (state->dmaCnt & 1)) { printf("sii_DoIntr: OBB??? ds %x cnt %d\n", dstat, state->dmaCnt); sii_DumpLog(); } }#endif } /* read a one byte message */ msg = sii_GetByte(regs, SII_MSG_IN_PHASE); if (msg < 0) { dstat = regs->dstat; goto again; }#ifdef DEBUG if (sii_debug > 4) printf("MsgIn %x ", msg); if (sii_logp > sii_log) sii_logp[-1].msg = msg; else sii_log[NLOG - 1].msg = msg;#endif /* process message */ switch (msg) { case SCSI_COMMAND_COMPLETE: msg = sc->sc_target; sc->sc_target = -1; /* * 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) { regs->cstat = SII_SCH | SII_BER; regs->comm = 0; MachEmptyWriteBuffer(); /* * 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); }#ifdef DEBUG if (sii_debug > 4) printf("cs %x\n", cstat);#endif sii_CmdDone(sc, msg, 0); break; case SCSI_EXTENDED_MSG: /* read the message length */ msg = sii_GetByte(regs, SII_MSG_IN_PHASE); if (msg < 0) { dstat = regs->dstat; goto again; } if (msg == 0) msg = 256; sii_StartDMA(regs, SII_MSG_IN_PHASE, (u_short *)SII_BUF_ADDR, msg); /* 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)) {#ifdef DEBUG if (sii_debug > 4) printf("cnt0 %d\n", i); else if (sii_debug > 0) printf("sii_DoIntr: emsg in ds %x cnt %d\n", dstat, i);#endif printf("sii: ds %x cm %x i %d lotc %d\n", dstat, comm, i, regs->dmlotc); /* XXX */ sii_DumpLog(); /* XXX */ goto again; } /* clear the DNE, other errors handled later */ regs->dstat = SII_DNE; MachEmptyWriteBuffer(); CopyFromBuffer((volatile u_short *)SII_BUF_ADDR, sii_buf + 2, msg); switch (sii_buf[2]) { case SCSI_MODIFY_DATA_PTR: i = (sii_buf[3] << 24) | (sii_buf[4] << 16) | (sii_buf[5] << 8) | sii_buf[6]; if (state->dmaPrevPhase >= 0) { state->dmaAddrL += i; state->dmaCnt -= i; } break; case SCSI_SYNCHRONOUS_XFER: sii_DoSync(regs, state); break; case SCSI_EXTENDED_IDENTIFY: case SCSI_WIDE_XFER: default: reject:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -