📄 scsincr53c8xx.c
字号:
#ifdef WMR_DEBUG if (inchip) { IPRINT(PRINTPREFIX "%d/%d: write_mismatch_recover: DMA FIFO = %d\n", dsa->target, dsa->lun, inchip); }#endif if (n->sstat0 & (1 << 5)) { inchip++;#ifdef WMR_DEBUG IPRINT(PRINTPREFIX "%d/%d: write_mismatch_recover: SODL full\n", dsa->target, dsa->lun);#endif } if (n->sstat2 & (1 << 5)) { inchip++;#ifdef WMR_DEBUG IPRINT(PRINTPREFIX "%d/%d: write_mismatch_recover: SODL msb full\n", dsa->target, dsa->lun);#endif } if (n->sxfer & SYNCOFFMASK(c)) { /* synchronous SODR */ if (n->sstat0 & (1 << 6)) { inchip++;#ifdef WMR_DEBUG IPRINT(PRINTPREFIX "%d/%d: write_mismatch_recover: SODR full\n", dsa->target, dsa->lun);#endif } if (n->sstat2 & (1 << 6)) { inchip++;#ifdef WMR_DEBUG IPRINT(PRINTPREFIX "%d/%d: write_mismatch_recover: SODR msb full\n", dsa->target, dsa->lun);#endif } } /* clear the dma fifo */ n->ctest3 |= (1 << 2); /* wait till done */ while ((n->dstat & Dfe) == 0) ; return dbc + inchip;}static voidinterrupt(Ureg *ur, void *a){ int wakeme = 0, cont = -1; uchar istat, dstat; ushort sist; Controller *c = a; Ncr *n = c->n; Dsa *dsa; USED(ur); if (DEBUG(1)) IPRINT(PRINTPREFIX "int\n"); ilock(c); istat = n->istat; if (istat & Intf) { Dsa *d; int wokesomething = 0; if (DEBUG(1)) IPRINT(PRINTPREFIX "Intfly\n"); n->istat = Intf; /* search for structures in A_STATE_DONE */ for (d = KPTR(legetl(c->dsalist.head)); d; d = KPTR(legetl(d->next))) { if (d->stateb == A_STATE_DONE) { d->p9status = STATUS_COMPLETE | d->status; if (DEBUG(1)) IPRINT(PRINTPREFIX "waking up dsa %lux\n", (ulong)d); wakeup(d); wokesomething = 1; } } if (!wokesomething) IPRINT(PRINTPREFIX "nothing to wake up\n"); } if ((istat & (Sip | Dip)) == 0) { if (DEBUG(1)) IPRINT(PRINTPREFIX "int end %x\n", istat); iunlock(c); return; } sist = (n->sist1<<8)|n->sist0; /* BUG? can two-byte read be inconsistent? */ dstat = n->dstat; dsa = (Dsa *)DMASEG_TO_KADDR(legetl(n->dsa)); c->running = 0; if (dsa == nil || dsa == (Dsa *)-1) panic("53c8xx: dsa == %ld in interrupt; bad controller", (long)dsa); if (istat & Sip) { if (DEBUG(1)) IPRINT("sist = %.4x\n", sist); if (sist & 0x80) { ulong addr; ulong sa; ulong dbc; ulong tbc; int dmablks; ulong dmaaddr; addr = legetl(n->dsp); sa = addr - c->scriptpa; if (DEBUG(1) || DEBUG(2)) IPRINT(PRINTPREFIX "%d/%d: Phase Mismatch sa=%.8lux\n", dsa->target, dsa->lun, sa); /* * now recover */ if (sa == E_data_in_mismatch) { dbc = read_mismatch_recover(c, n, dsa); tbc = legetl(dsa->data_buf.dbc) - dbc; advancedata(&dsa->data_buf, tbc); if (DEBUG(1) || DEBUG(2)) IPRINT(PRINTPREFIX "%d/%d: transferred = %ld residue = %ld\n", dsa->target, dsa->lun, tbc, legetl(dsa->data_buf.dbc)); cont = E_to_decisions; } else if (sa == E_data_in_block_mismatch) { dbc = read_mismatch_recover(c, n, dsa); tbc = A_BSIZE - dbc; /* recover current state from registers */ dmablks = n->scratcha[2]; dmaaddr = legetl(n->scratchb); /* we have got to dmaaddr + tbc */ /* we have dmablks * A_BSIZE - tbc + residue left to do */ /* so remaining transfer is */ IPRINT("in_block_mismatch: dmaaddr = 0x%lux tbc=%lud dmablks=%d\n", dmaaddr, tbc, dmablks); calcblockdma(dsa, dmaaddr + tbc, dmablks * A_BSIZE - tbc + legetl(dsa->data_buf.dbc)); /* copy changes into scratch registers */ IPRINT("recalc: dmablks %d dmaaddr 0x%lx pa 0x%lx dbc %ld\n", dsa->dmablks, legetl(dsa->dmaaddr), legetl(dsa->data_buf.pa), legetl(dsa->data_buf.dbc)); n->scratcha[2] = dsa->dmablks; lesetl(n->scratchb, dsa->dmancr); cont = E_data_block_mismatch_recover; } else if (sa == E_data_out_mismatch) { dbc = write_mismatch_recover(c, n, dsa); tbc = legetl(dsa->data_buf.dbc) - dbc; advancedata(&dsa->data_buf, tbc); if (DEBUG(1) || DEBUG(2)) IPRINT(PRINTPREFIX "%d/%d: transferred = %ld residue = %ld\n", dsa->target, dsa->lun, tbc, legetl(dsa->data_buf.dbc)); cont = E_to_decisions; } else if (sa == E_data_out_block_mismatch) { dbc = write_mismatch_recover(c, n, dsa); tbc = legetl(dsa->data_buf.dbc) - dbc; /* recover current state from registers */ dmablks = n->scratcha[2]; dmaaddr = legetl(n->scratchb); /* we have got to dmaaddr + tbc */ /* we have dmablks blocks - tbc + residue left to do */ /* so remaining transfer is */ IPRINT("out_block_mismatch: dmaaddr = %lux tbc=%lud dmablks=%d\n", dmaaddr, tbc, dmablks); calcblockdma(dsa, dmaaddr + tbc, dmablks * A_BSIZE - tbc + legetl(dsa->data_buf.dbc)); /* copy changes into scratch registers */ n->scratcha[2] = dsa->dmablks; lesetl(n->scratchb, dsa->dmancr); cont = E_data_block_mismatch_recover; } else if (sa == E_id_out_mismatch) { /* * target switched phases while attention held during * message out. The possibilities are: * 1. It didn't like the last message. This is indicated * by the new phase being message_in. Use script to recover * * 2. It's not SCSI-II compliant. The new phase will be other * than message_in. We should also indicate that the device * is asynchronous, if it's the SDTR that got ignored * * For now, if the phase switch is not to message_in, and * and it happens after IDENTIFY and before SDTR, we * notify the negotiation state machine. */ ulong lim = legetl(dsa->msg_out_buf.dbc); uchar p = n->sstat1 & 7; dbc = write_mismatch_recover(c, n, dsa); tbc = lim - dbc; IPRINT(PRINTPREFIX "%d/%d: msg_out_mismatch: %lud/%lud sent, phase %s\n", dsa->target, dsa->lun, tbc, lim, phase[p]); if (p != MessageIn && tbc == 1) { msgsm(dsa, c, A_SIR_EV_PHASE_SWITCH_AFTER_ID, &cont, &wakeme); } else cont = E_id_out_mismatch_recover; } else if (sa == E_cmd_out_mismatch) { /* * probably the command count is longer than the device wants ... */ ulong lim = legetl(dsa->cmd_buf.dbc); uchar p = n->sstat1 & 7; dbc = write_mismatch_recover(c, n, dsa); tbc = lim - dbc; IPRINT(PRINTPREFIX "%d/%d: cmd_out_mismatch: %lud/%lud sent, phase %s\n", dsa->target, dsa->lun, tbc, lim, phase[p]); USED(p, tbc); cont = E_to_decisions; } else { IPRINT(PRINTPREFIX "%d/%d: ma sa=%.8lux wanted=%s got=%s\n", dsa->target, dsa->lun, sa, phase[n->dcmd & 7], phase[n->sstat1 & 7]); dumpncrregs(c, 1); dsa->p9status = STATUS_FAIL; /* chf */ wakeme = 1; } } /*else*/ if (sist & 0x400) { if (DEBUG(0)) IPRINT(PRINTPREFIX "%d/%d Sto\n", dsa->target, dsa->lun); dsa->p9status = STATUS_SELECTION_TIMEOUT; dsa->stateb = A_STATE_DONE; softreset(c); cont = E_issue_check; wakeme = 1; } if (sist & 0x1) { IPRINT(PRINTPREFIX "%d/%d: parity error\n", dsa->target, dsa->lun); dsa->parityerror = 1; } if (sist & 0x4) { IPRINT(PRINTPREFIX "%d/%d: unexpected disconnect\n", dsa->target, dsa->lun); dumpncrregs(c, 1); //wakeme = 1; dsa->p9status = STATUS_FAIL; } } if (istat & Dip) { if (DEBUG(1)) IPRINT("dstat = %.2x\n", dstat); /*else*/ if (dstat & Ssi) { ulong *p = DMASEG_TO_KADDR(legetl(n->dsp)); ulong w = (uchar *)p - (uchar *)c->script; IPRINT("[%lux]", w); USED(w); cont = -2; /* restart */ } if (dstat & Sir) { switch (legetl(n->dsps)) { case A_SIR_MSG_IO_COMPLETE: dsa->p9status = STATUS_COMPLETE | dsa->status; wakeme = 1; break; case A_SIR_MSG_SDTR: case A_SIR_MSG_WDTR: case A_SIR_MSG_REJECT: case A_SIR_EV_RESPONSE_OK: msgsm(dsa, c, legetl(n->dsps), &cont, &wakeme); break; case A_SIR_MSG_IGNORE_WIDE_RESIDUE: /* back up one in the data transfer */ IPRINT(PRINTPREFIX "%d/%d: ignore wide residue %d, WSR = %d\n", dsa->target, dsa->lun, n->scratcha[1], n->scntl2 & 1); if (dsa->dmablks == 0 && dsa->flag) IPRINT(PRINTPREFIX "%d/%d: transfer over; residue ignored\n", dsa->target, dsa->lun); else calcblockdma(dsa, legetl(dsa->dmaaddr) - 1, dsa->dmablks * A_BSIZE + legetl(dsa->data_buf.dbc) + 1); cont = -2; break; case A_SIR_ERROR_NOT_MSG_IN_AFTER_RESELECT: IPRINT(PRINTPREFIX "%d: not msg_in after reselect (%s)", n->ssid & SSIDMASK(c), phase[n->sstat1 & 7]); dsa = dsafind(c, n->ssid & SSIDMASK(c), -1, A_STATE_DISCONNECTED); dumpncrregs(c, 1); wakeme = 1; break; case A_SIR_NOTIFY_MSG_IN: IPRINT(PRINTPREFIX "%d/%d: msg_in %d\n", dsa->target, dsa->lun, n->sfbr); cont = -2; break; case A_SIR_NOTIFY_DISC: IPRINT(PRINTPREFIX "%d/%d: disconnect:", dsa->target, dsa->lun); goto dsadump; case A_SIR_NOTIFY_STATUS: IPRINT(PRINTPREFIX "%d/%d: status\n", dsa->target, dsa->lun); cont = -2; break; case A_SIR_NOTIFY_COMMAND: IPRINT(PRINTPREFIX "%d/%d: commands\n", dsa->target, dsa->lun); cont = -2; break; case A_SIR_NOTIFY_DATA_IN: IPRINT(PRINTPREFIX "%d/%d: data in a %lx b %lx\n", dsa->target, dsa->lun, legetl(n->scratcha), legetl(n->scratchb)); cont = -2; break; case A_SIR_NOTIFY_BLOCK_DATA_IN: IPRINT(PRINTPREFIX "%d/%d: block data in: a2 %x b %lx\n", dsa->target, dsa->lun, n->scratcha[2], legetl(n->scratchb)); cont = -2; break; case A_SIR_NOTIFY_DATA_OUT: IPRINT(PRINTPREFIX "%d/%d: data out\n", dsa->target, dsa->lun); cont = -2; break; case A_SIR_NOTIFY_DUMP: IPRINT(PRINTPREFIX "%d/%d: dump\n", dsa->target, dsa->lun); dumpncrregs(c, 1); cont = -2; break; case A_SIR_NOTIFY_DUMP2: IPRINT(PRINTPREFIX "%d/%d: dump2:", dsa->target, dsa->lun); IPRINT(" sa %lux", legetl(n->dsp) - c->scriptpa); IPRINT(" dsa %lux", legetl(n->dsa)); IPRINT(" sfbr %ux", n->sfbr); IPRINT(" a %lux", legetl(n->scratcha)); IPRINT(" b %lux", legetl(n->scratchb)); IPRINT(" ssid %ux", n->ssid); IPRINT("\n"); cont = -2; break; case A_SIR_NOTIFY_WAIT_RESELECT: IPRINT(PRINTPREFIX "wait reselect\n"); cont = -2; break; case A_SIR_NOTIFY_RESELECT: IPRINT(PRINTPREFIX "reselect: ssid %.2x sfbr %.2x at %ld\n", n->ssid, n->sfbr, TK2MS(m->ticks)); cont = -2; break; case A_SIR_NOTIFY_ISSUE: IPRINT(PRINTPREFIX "%d/%d: issue:", dsa->target, dsa->lun); dsadump: IPRINT(" tgt=%d", dsa->target); IPRINT(" time=%ld", TK2MS(m->ticks)); IPRINT("\n"); cont = -2; break; case A_SIR_NOTIFY_ISSUE_CHECK: IPRINT(PRINTPREFIX "issue check\n"); cont = -2; break; case A_SIR_NOTIFY_SIGP: IPRINT(PRINTPREFIX "responded to SIGP\n"); cont = -2; break; case A_SIR_NOTIFY_DUMP_NEXT_CODE: { ulong *dsp = DMASEG_TO_KADDR(legetl(n->dsp)); int x; IPRINT(PRINTPREFIX "code at %lux", dsp - c->script); for (x = 0; x < 6; x++) IPRINT(" %.8lux", dsp[x]); IPRINT("\n"); USED(dsp); cont = -2; break; } case A_SIR_NOTIFY_WSR: IPRINT(PRINTPREFIX "%d/%d: WSR set\n", dsa->target, dsa->lun); cont = -2; break; case A_SIR_NOTIFY_LOAD_SYNC: IPRINT(PRINTPREFIX "%d/%d: scntl=%.2x sxfer=%.2x\n", dsa->target, dsa->lun, n->scntl3, n->sxfer); cont = -2; break; case A_SIR_NOTIFY_RESELECTED_ON_SELECT: IPRINT(PRINTPREFIX "%d/%d: reselected during select\n", dsa->target, dsa->lun); cont = -2; break; default: IPRINT(PRINTPREFIX "%d/%d: script error %ld\n", dsa->target, dsa->lun, legetl(n->dsps)); dumpncrregs(c, 1); wakeme = 1; } } /*else*/ if (dstat & Iid) { ulong addr = legetl(n->dsp); ulong dbc = (n->dbc[2]<<16)|(n->dbc[1]<<8)|n->dbc[0]; IPRINT(PRINTPREFIX "%d/%d: Iid pa=%.8lux sa=%.8lux dbc=%lux\n", dsa->target, dsa->lun, addr, addr - c->scriptpa, dbc); addr = (ulong)DMASEG_TO_KADDR(addr); IPRINT("%.8lux %.8lux %.8lux\n", *(ulong *)(addr - 12), *(ulong *)(addr - 8), *(ulong *)(addr - 4)); USED(addr, dbc); if (dsa) dsa->p9status = STATUS_FAIL; wakeme = 1; } /*else*/ if (dstat & Bf) { if (dsa == nil) print(PRINTPREFIX "Bus Fault with dsa==0\n"); else { print(PRINTPREFIX "%d/%d: Bus Fault\n", dsa->target, dsa->lun); dsa->p9status = STATUS_FAIL; } dumpncrregs(c, 1); wakeme = 1; } } if (cont == -2) ncrcontinue(c); else if (cont >= 0) start(c, cont); if (wakeme && dsa){ if(dsa->p9status == 0xffff) dsa->p9status = STATUS_FAIL; wakeup(dsa); } iunlock(c); if (DEBUG(1)) { IPRINT(PRINTPREFIX "int end 1\n"); }}static intdone(void *arg){ return ((Dsa *)arg)->p9status != 0xffff;}static intxfunc(Controller *c, enum na_external x, unsigned long *v){ switch (x) { default: print("xfunc: can't find external %d\n", x); return 0; case X_scsi_id_buf: *v = offsetof(Dsa, scsi_id_buf[0]); break; case X_msg_out_buf: *v = offsetof(Dsa, msg_out_buf); break; case X_cmd_buf: *v = offsetof(Dsa, cmd_buf); break; case X_data_buf: *v = offsetof(Dsa, data_buf); break; case X_status_buf: *v = offsetof(Dsa, status_buf); break; case X_dsa_head: *v = DMASEG(&c->dsalist.head[0]); break; case X_ssid_mask: *v = SSIDMASK(c); break; } return 1;}static voidsetmovedata(Movedata *d, ulong pa, ulong bc){ d->pa[0] = pa; d->pa[1] = pa>>8; d->pa[2] = pa>>16; d->pa[3] = pa>>24; d->dbc[0] = bc; d->dbc[1] = bc>>8; d->dbc[2] = bc>>16; d->dbc[3] = bc>>24;}static voidadvancedata(Movedata *d, long v){ lesetl(d->pa, legetl(d->pa) + v); lesetl(d->dbc, legetl(d->dbc) - v);}static voiddumpwritedata(uchar *data, int datalen){ int i; uchar *bp; if (!DEBUG(0)){ USED(data, datalen); return; } if (datalen) { KPRINT(PRINTPREFIX "write:"); for (i = 0, bp = data; i < 50 && i < datalen; i++, bp++) KPRINT("%.2ux", *bp); if (i < datalen) { KPRINT("..."); } KPRINT("\n"); }}static voiddumpreaddata(uchar *data, int datalen){ int i; uchar *bp; if (!DEBUG(0)){ USED(data, datalen); return; } if (datalen) { KPRINT(PRINTPREFIX "read:"); for (i = 0, bp = data; i < 50 && i < datalen; i++, bp++) KPRINT("%.2ux", *bp); if (i < datalen) { KPRINT("..."); } KPRINT("\n"); }}static voidbusreset(Controller *c){ int x, ntarget; /* bus reset */ c->n->scntl1 |= (1 << 3); delay(500); c->n->scntl1 &= ~(1 << 3); if(!(c->v->feature & Wide)) ntarget = 8; else ntarget = MAXTARGET; for (x = 0; x < ntarget; x++) { setwide(0, c, x, 0);#ifndef ASYNC_ONLY c->s[x] = NeitherDone;#endif } c->capvalid = 0;}static voidreset(Controller *c){ /* should wakeup all pending tasks */ softreset(c); busreset(c);}static intio(Controller *c, uchar target, uchar lun, int rw, uchar *cmd, int cmdlen, uchar *data, int datalen,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -