📄 idc.c
字号:
* If on cylinder, no need to seek. */ if (cyltrk.dar_dar == idccyl[ui->ui_unit].dar_dar) goto done; /* * RB80 can change heads (tracks) just by loading * the disk address register, perform optimization * here instead of doing a full seek. */ if (ui->ui_type && cyltrk.dar_cyl == idccyl[ui->ui_unit].dar_cyl) { idcaddr->idccsr = IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8); idcaddr->idcdar = cyltrk.dar_dar; idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar; goto done; } /* * Need to do a full seek. Select the unit, clear * its attention bit, set the command, load the * disk address register, and then go. */ idcaddr->idccsr = IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16)); idcaddr->idcdar = cyltrk.dar_dar; idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar;#ifdef IDCDEBUG printd(" seek");#endif IDCDEBUG idcaddr->idccsr = IDC_IE|IDC_SEEK|(unit<<8); if (ui->ui_dk >= 0) { dk_busy |= 1<<ui->ui_dk; dk_seek[ui->ui_dk]++; } /* * RB80's initiate seeks very quickly. Wait for it * to come ready rather than taking the interrupt. */ if (ui->ui_type) { if (idcwait(idcaddr, 10) == 0) return (1); idcaddr->idccsr &= ~IDC_ATTN; /* has the seek completed? */ if (idcaddr->idccsr & IDC_DRDY) {#ifdef IDCDEBUG printd(", drdy");#endif IDCDEBUG idcaddr->idccsr = IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16)); goto done; } }#ifdef IDCDEBUG printd(", idccsr = 0x%x\n", idcaddr->idccsr);#endif IDCDEBUG return (1);done: if (dp->b_active != 2) {#ifdef IDCDEBUG trace("!=2",dp->b_active);#endif IDCDEBUG dp->b_forw = NULL; if (um->um_tab.b_actf == NULL) um->um_tab.b_actf = dp; else {#ifdef IDCDEBUG trace("!NUL",um->um_tab.b_actl);#endif IDCDEBUG um->um_tab.b_actl->b_forw = dp; } um->um_tab.b_actl = dp; dp->b_active = 2; } sc->sc_flags[ui->ui_unit] |= DEV_DONE; return (0);}idcstart(um) register struct uba_ctlr *um;{ register struct buf *bp, *dp; register struct uba_device *ui; register struct idcdevice *idcaddr; register struct idc_softc *sc; struct idcst *st; daddr_t bn; int sn, tn, cmd;loop: if ((dp = um->um_tab.b_actf) == NULL) {#ifdef IDCDEBUG trace("nodp",um);#endif IDCDEBUG return (0); } if ((bp = dp->b_actf) == NULL) {#ifdef IDCDEBUG trace("nobp", dp);#endif IDCDEBUG um->um_tab.b_actf = dp->b_forw; goto loop; } um->um_tab.b_active = 1; ui = idcdinfo[dkunit(bp)]; bn = dkblock(bp);#ifdef IDCDEBUG trace("star",bp);#endif IDCDEBUG if (ui->ui_type == 0) bn *= 2; sc = &idc_softc; st = &idcst[ui->ui_type]; sn = bn%st->nspc; tn = sn/st->nsect; sn %= st->nsect; sc->sc_sect = sn; sc->sc_trk = tn; sc->sc_cyl = bp->b_cylin; idcaddr = (struct idcdevice *)ui->ui_addr;#ifdef IDCDEBUG printd("idcstart, unit %d, dar 0x%x", ui->ui_slave, sc->sc_dar);#endif IDCDEBUG if (bp->b_flags & B_READ) cmd = IDC_IE|IDC_READ|(ui->ui_slave<<8); else cmd = IDC_IE|IDC_WRITE|(ui->ui_slave<<8); idcaddr->idccsr = IDC_CRDY|cmd; if ((idcaddr->idccsr&IDC_DRDY) == 0) { mprintf("rb%d: not ready\n", dkunit(bp)); um->um_tab.b_active = 0; um->um_tab.b_errcnt = 0; dp->b_actf = bp->av_forw; dp->b_active = 0; bp->b_flags |= B_ERROR; iodone(bp); goto loop; } idccyl[ui->ui_unit].dar_dar = sc->sc_dar; idccyl[ui->ui_unit].dar_sect = 0; sn = (st->nsect - sn) * st->nbps; if (sn > bp->b_bcount) sn = bp->b_bcount; sc->sc_bcnt = sn; sc->sc_resid = bp->b_bcount; sc->sc_unit = ui->ui_slave;#ifdef IDCDEBUG printd(", bcr 0x%x, cmd 0x%x\n", sn, cmd);#endif IDCDEBUG um->um_cmd = cmd; (void) ubago(ui); return (1);}idcdgo(um) register struct uba_ctlr *um;{ register struct buf *bp; register struct uba_device *ui = idcdinfo[dkunit(bp)]; register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr; register struct idc_softc *sc = &idc_softc; /* * VERY IMPORTANT: must load registers in this order. */ idcaddr->idcbar = sc->sc_ubaddr = um->um_ubinfo&0x3ffff; idcaddr->idcbcr = -sc->sc_bcnt; idcaddr->idcdar = sc->sc_dar;#ifdef IDCDEBUG printd("idcdgo, ubinfo 0x%x, cmd 0x%x\n", um->um_ubinfo, um->um_cmd);#endif IDCDEBUG idcaddr->idccsr = um->um_cmd;#ifdef IDCDEBUG trace("go", um);#endif IDCDEBUG um->um_tab.b_active = 2; /*** CLEAR SPURIOUS ATTN ON R80? ***/}idcintr(idc) int idc;{ register struct uba_ctlr *um = idcminfo[idc]; register struct uba_device *ui; register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr; register struct idc_softc *sc = &idc_softc; register struct buf *bp, *dp; struct idcst *st; int unit, as, er, cmd, savcsr, ds = 0; savcsr = idcaddr->idccsr;#ifdef IDCDEBUG printd("idcintr, idccsr 0x%x", idcaddr->idccsr);#endif IDCDEBUGtop: idcwticks = 0;#ifdef IDCDEBUG trace("intr", um->um_tab.b_active);#endif IDCDEBUG if (um->um_tab.b_active == 2) { /* * Process a data transfer complete interrupt. */ um->um_tab.b_active = 1; dp = um->um_tab.b_actf; bp = dp->b_actf; ui = idcdinfo[dkunit(bp)]; unit = ui->ui_slave; st = &idcst[ui->ui_type]; idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8); if ((er = idcaddr->idccsr) & IDC_ERR) { if (er & IDC_DE) { idcaddr->idcmpr = IDCGS_GETSTAT; idcaddr->idccsr = IDC_GETSTAT|(unit<<8); (void) idcwait(idcaddr, 0); ds = idcaddr->idcmpr; idcaddr->idccsr = IDC_IE|IDC_CRDY|(1<<(unit+16)); }#ifdef IDCDEBUG printd(", er 0x%x, ds 0x%x", er, ds);#endif IDCDEBUG if (ds & IDCDS_WL) { sc->sc_flags[unit] |= DEV_WRTLCK; bp->b_flags |= B_ERROR; } else if (++um->um_tab.b_errcnt > 28 || er&IDC_HARD) {hard: harderr(bp, "rb"); sc->sc_hardcnt[unit]++; sc->sc_flags[unit] |= DEV_HARDERR; mprintf("%s: unit# %d: hard error block# %d\n csr=%b ds=%b\n", sc->sc_device[unit], ui->ui_unit, bp->b_blkno, er, IDCCSR_BITS, ds, ui->ui_type?IDCRB80DS_BITS:IDCRB02DS_BITS); bp->b_flags |= B_ERROR; } else if (er & IDC_DCK) { switch (er & IDC_ECS) { case IDC_ECS_NONE: break; case IDC_ECS_SOFT: idcecc(ui); sc->sc_softcnt[unit]++; sc->sc_flags[unit] |= DEV_SOFTERR; break; case IDC_ECS_HARD: default: goto hard; } } else /* recoverable error, set up for retry */ goto seek; } if ((sc->sc_resid -= sc->sc_bcnt) != 0) { sc->sc_ubaddr += sc->sc_bcnt; /* * Current transfer is complete, have * we overflowed to the next track? */ if ((sc->sc_sect += sc->sc_bcnt/st->nbps) == st->nsect) { sc->sc_sect = 0; if (++sc->sc_trk == st->ntrak) { sc->sc_trk = 0; sc->sc_cyl++; } else if (ui->ui_type) { /* * RB80 can change heads just by * loading the disk address register. */ idcaddr->idccsr = IDC_SEEK|IDC_CRDY| IDC_IE|(unit<<8);#ifdef IDCDEBUG printd(", change to track 0x%x", sc->sc_dar);#endif IDCDEBUG idcaddr->idcdar = sc->sc_dar; idccyl[ui->ui_unit].dar_dar = sc->sc_dar; idccyl[ui->ui_unit].dar_sect = 0; goto cont; } /* * Changing tracks on RB02 or cylinders * on RB80, start a seek. */seek: cmd = IDC_IE|IDC_SEEK|(unit<<8); idcaddr->idccsr = cmd|IDC_CRDY; idcaddr->idcdar = sc->sc_dar;#ifdef IDCDEBUG printd(", seek to 0x%x\n", sc->sc_dar);#endif IDCDEBUG idccyl[ui->ui_unit].dar_dar = sc->sc_dar; idccyl[ui->ui_unit].dar_sect = 0; sc->sc_bcnt = 0; idcaddr->idccsr = cmd; if (ui->ui_type) { if (idcwait(idcaddr, 10) == 0) return; idcaddr->idccsr &= ~IDC_ATTN; if (idcaddr->idccsr & IDC_DRDY) goto top; } } else { /* * Continue transfer on current track. */cont: sc->sc_bcnt = (st->nsect-sc->sc_sect)*st->nbps; if (sc->sc_bcnt > sc->sc_resid) sc->sc_bcnt = sc->sc_resid; if (bp->b_flags & B_READ) cmd = IDC_IE|IDC_READ|(unit<<8); else cmd = IDC_IE|IDC_WRITE|(unit<<8); idcaddr->idccsr = cmd|IDC_CRDY; idcaddr->idcbar = sc->sc_ubaddr; idcaddr->idcbcr = -sc->sc_bcnt; idcaddr->idcdar = sc->sc_dar;#ifdef IDCDEBUG printd(", continue I/O 0x%x, 0x%x\n", sc->sc_dar, sc->sc_bcnt);#endif IDCDEBUG idcaddr->idccsr = cmd; um->um_tab.b_active = 2; } return; } /* * Entire transfer is done, clean up. */ ubadone(um); dk_busy &= ~(1 << ui->ui_dk); um->um_tab.b_active = 0; um->um_tab.b_errcnt = 0; um->um_tab.b_actf = dp->b_forw; dp->b_active = 0; dp->b_errcnt = 0; dp->b_actf = bp->av_forw;#ifdef IDCDEBUG trace("done", dp); trace(&um->um_tab.b_actf, dp->b_actf);#endif IDCDEBUG bp->b_resid = sc->sc_resid;#ifdef IDCDEBUG printd(", iodone, resid 0x%x\n", bp->b_resid);#endif IDCDEBUG iodone(bp); if (dp->b_actf) if (idcustart(ui)) return; } else if (um->um_tab.b_active == 1) { /* * Got an interrupt while setting up for a command * or doing a mid-transfer seek. Save any attentions * for later and process a mid-transfer seek complete. */ as = idcaddr->idccsr; idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN); as = (as >> 16) & 0xf; dp = um->um_tab.b_actf; bp = dp->b_actf; ui = idcdinfo[dkunit(bp)]; unit = sc->sc_unit; sc->sc_softas |= as & ~(1<<unit); if (as & (1<<unit)) {#ifdef IDCDEBUG printd(", seek1 complete");#endif IDCDEBUG um->um_tab.b_active = 2; goto top; }#ifdef IDCDEBUG printd(", as1 %o\n", as);#endif IDCDEBUG return; } /* * Process any seek initiated or complete interrupts. */ if ((savcsr & IDC_OPI) && !(savcsr & IDC_DRDY)) { unit = ((savcsr & IDC_DS) >> 8); ui = idcdinfo[unit]; if (sc->sc_offline[ui->ui_unit]) { mprintf("%s: unit# %d: offline\n",sc->sc_device[unit], unit); } else { mprintf("%s: unit# %d: drive error: csr=%b\n", sc->sc_device[unit], unit, savcsr, IDCCSR_BITS); } dp = &idcutab[ui->ui_unit]; bp = dp->b_actf; dp->b_actf = bp->av_forw; dp->b_active = 0; bp->b_flags |= B_ERROR; iodone(bp); if (idcustart(ui)) { return; } } as = idcaddr->idccsr; idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN); as = ((as >> 16) & 0xf) | sc->sc_softas; sc->sc_softas = 0;#ifdef IDCDEBUG trace("as", as); printd(", as %o", as);#endif IDCDEBUG for (unit = 0; unit < nNRB; unit++) if (as & (1<<unit)) { as &= ~(1<<unit); idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8); ui = idcdinfo[unit]; if (ui) {#ifdef IDCDEBUG printd(", attn unit %d", unit);#endif IDCDEBUG if (idcaddr->idccsr & IDC_DRDY) { if (sc->sc_offline[ui->ui_unit]) { /* * read header to synch ucode * drive has be spun up */ idcaddr->idccsr = (ui->ui_slave<<8)|IDC_RHDR; (void) idcwait(idcaddr, 0); /* read the MPR twice */ if (idcaddr->idcmpr == idcaddr->idcmpr); /* reset the drive */ idcaddr->idcmpr = IDCGS_GETSTAT; idcaddr->idccsr = IDC_GETSTAT|(unit<<8); (void) idcwait(idcaddr, 0);#ifdef IDCDEBUG printd(", drive ready");#endif IDCDEBUG sc->sc_offline[ui->ui_unit] = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -