📄 rl.c
字号:
{ register struct rldevice *rladdr = (struct rldevice *)um->um_addr; rldwait(rladdr); /* DS - Add drive ready test */ rladdr->rlba = um->um_ubinfo; rladdr->rlcs = um->um_cmd|((um->um_ubinfo>>12)&RL_BAE);}/* * Handle a disk interrupt. */rlintr(rl21) int rl21;{ register struct uba_ctlr *um = rlminfo[rl21]; register struct uba_device *ui; register struct rldevice *rladdr = (struct rldevice *)um->um_addr; register struct buf *bp, *dp; register struct rl_softc *sc = &rl_softc[um->um_ctlr]; int unit; struct rl_stat *st = &rl_stat[um->um_ctlr]; int as = sc->rl_softas, status; sc->rl_wticks = 0; sc->rl_softas = 0; dp = um->um_tab.b_actf; bp = dp->b_actf; ui = rldinfo[dkunit(bp)]; dk_busy &= ~(1 << ui->ui_dk); /* * Check for and process errors on * either the drive or the controller. */ if (rladdr->rlcs & RL_ERR) { u_short err; rlwait(rladdr); err = rladdr->rlcs; /* get status and reset controller */ rladdr->rlda.getstat = RL_GSTAT; rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT; rlwait(rladdr); status = rladdr->rlmp.getstat; /* reset drive */ rladdr->rlda.getstat = RL_RESET; rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/ rlwait(rladdr); if ((status & RLMP_WL) == RLMP_WL) { /* * Give up on write protected devices * immediately. */ bp->b_flags |= B_ERROR; sc->sc_flags[ui->ui_unit] |= DEV_WRTLCK; } else if (++um->um_tab.b_errcnt > 10) { /* * After 10 retries give up. */ harderr(bp, "rl"); sc->sc_hardcnt[ui->ui_unit]++; sc->sc_flags[ui->ui_unit] |= DEV_HARDERR; mprintf("%s: unit#:%d hard err blk#:%d cs:%b mp:%b\n", sc->sc_device[ui->ui_unit], ui->ui_unit, bp->b_blkno, err, RLCS_BITS, status, RLER_BITS); bp->b_flags |= B_ERROR; } else { sc->sc_softcnt[ui->ui_unit]++; sc->sc_flags[ui->ui_unit] |= DEV_SOFTERR; um->um_tab.b_active = 0; /* force retry */ } /* determine disk position */ rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR; rlwait(rladdr); /* save disk drive position */ st->rl_cyl[ui->ui_slave] = (rladdr->rlmp.readhdr & 0177700) >> 6; } /* * If still ``active'', then don't need any more retries. */ if (um->um_tab.b_active) { /* RL02 check if more data from previous request */ if ((bp->b_flags & B_ERROR) == 0 && (int)(st->rl_bleft -= st->rl_bpart) > 0) { /* * The following code was modeled from the rk07 * driver when an ECC error occured. It has to * fix the bits then restart the transfer which is * what we have to do (restart transfer). */ int reg, npf, o, cmd, ubaddr, diff, head; /* seek to next head/track */ /* increment head and/or cylinder */ st->rl_cylnhd++; diff = (st->rl_cyl[ui->ui_slave] >> 1) - (st->rl_cylnhd >> 1); st->rl_cyl[ui->ui_slave] = st->rl_cylnhd; head = st->rl_cylnhd & 1; rlwait(rladdr); if (diff < 0) rladdr->rlda.seek = -diff << 7 | RLDA_HGH | head << 4; else rladdr->rlda.seek = diff << 7 | RLDA_LOW | head << 4; rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK; npf = btop( bp->b_bcount - st->rl_bleft ); reg = btop(um->um_ubinfo&0x3ffff) + npf; o = (int)bp->b_un.b_addr & PGOFSET; ubapurge(um); um->um_tab.b_active++; rlwait(rladdr); rladdr->rlda.rw = st->rl_cylnhd << 6; if (st->rl_bleft < (st->rl_bpart = rl02.btrak)) st->rl_bpart = st->rl_bleft; rladdr->rlmp.rw = -(st->rl_bpart >> 1); cmd = (bp->b_flags&B_READ ? RL_READ : RL_WRITE) | RL_IE | (ui->ui_slave << 8); ubaddr = (int)ptob(reg) + o; cmd |= ((ubaddr >> 12) & RL_BAE); rladdr->rlba = ubaddr; rladdr->rlcs = cmd; /* since we clear the atten sum previously if we don't forget about it here we must set it back - dallas */ sc->rl_softas |= as; return; } um->um_tab.b_active = 0; um->um_tab.b_errcnt = 0; dp->b_active = 0; dp->b_errcnt = 0; /* "b_resid" words remaining after error */ bp->b_resid = st->rl_bleft; um->um_tab.b_actf = dp->b_forw; dp->b_actf = bp->av_forw; st->rl_dn = -1; st->rl_bpart = st->rl_bleft = 0; iodone(bp); /* * If this unit has more work to do, * then start it up right away. */ if (dp->b_actf) rlustart(ui); as &= ~(1<<ui->ui_slave); } else as |= (1<<ui->ui_slave); ubadone(um); /* reset state info */ st->rl_dn = -1; st->rl_cylnhd = st->rl_bpart = st->rl_bleft = 0; /* * Process other units which need attention. * For each unit which needs attention, call * the unit start routine to place the slave * on the controller device queue. */ while (unit = ffs(as)) { unit--; /* was 1 origin */ as &= ~(1<<unit); rlustart(rlip[rl21][unit]); } /* * If the controller is not transferring, but * there are devices ready to transfer, start * the controller. */ if (um->um_tab.b_actf && um->um_tab.b_active == 0) rlstart(um);}rldwait(rladdr) register struct rldevice *rladdr;{ register int totaldelay = 0; /* * Spin waiting for the DRDY bit to clear. Wait a maximum of * 10 seconds to prevent system hangs. */ while (((rladdr->rlcs & RL_DRDY) == 0) && (totaldelay <= 1000)) { totaldelay++; DELAY(10000); /* Wait .01 seconds - smallest allowable */ } if ((rldebug) && ((rladdr->rlcs & RL_DRDY) == 0)) { printf("rldwait: RL_DRDY failed to clear.\n"); }}rlwait(rladdr) register struct rldevice *rladdr;{ register int totaldelay = 0; /* * Spin waiting for the CRDY bit to clear. Wait a maximum of * 10 seconds to prevent system hangs. */ while (((rladdr->rlcs & RL_CRDY) == 0) && (totaldelay <= 1000)) { totaldelay++; DELAY(10000); /* Wait .01 seconds */ } if ((rldebug) && ((rladdr->rlcs & RL_CRDY) == 0)) { printf("rlwait: RL_CRDY failed to clear.\n"); }}rlread(dev, uio) register dev_t dev; register struct uio *uio;{ register int unit = minor(dev) >> 3; return (physio(rlstrategy, &rrlbuf[unit], dev, B_READ, minphys, uio));}rlwrite(dev, uio) register dev_t dev; register struct uio *uio;{ register int unit = minor(dev) >> 3; return (physio(rlstrategy, &rrlbuf[unit], dev, B_WRITE, minphys, uio));}/*ARGSUSED*/rlioctl(dev, cmd, data, flag) dev_t dev; int cmd; caddr_t data; int flag;{ register int unit = minor(dev) >> 3; register struct uba_device *ui = rldinfo[unit]; register struct pt *pt = (struct pt *)data; register struct rl_softc *sc = &rl_softc[ui->ui_ctlr]; struct dkop *dkop; struct dkget *dkget; struct devget *devget; register int i; int error; int nbpc; switch (cmd) { case DKIOCHDR: /* do header read/write */ break; case DIOCGETPT: /* 001 get partition table info */ /* * Do a structure copy into the user's data area */ *pt = rl_part[unit]; break; case DIOCDGTPT: /* 002 Return the default partition table /* * Get number bytes per cylinder group */ nbpc = rl02.nbpc; /* * Get and store the default block count and offset */ for( i = 0; i <= 7; i++ ) { pt->pt_part[i].pi_nblocks = rl02_sizes[i].nblocks; pt->pt_part[i].pi_blkoff = rl02_sizes[i].cyloff * nbpc; } break; case DIOCSETPT: /* 001 set the driver partition tables */ /* * Only super users can set the pack's partition * table */ if ( !suser() ) return(EACCES); /* * Don't mess with an offline disk. */ if (sc->sc_flags[ui->ui_unit] & DEV_OFFLINE) return(EIO); /* * Before we set the new partition tables make sure * that it will no corrupt any of the kernel data * structures */ if ( ( error = ptcmp( dev, &rl_part[unit], pt ) ) != 0 ) return(error); /* * Using the user's data to set the partition table * for the pack */ rl_part[unit] = *pt; /* * See if we need to update the superblock of the * "a" partition of this disk */ ssblk(dev,pt); /* * Just make sure that we set the valid bit */ rl_part[unit].pt_valid = PT_VALID; break; case DKIOCDOP: /* Disk operation */ if ( !suser() ) return(EACCES); break; case DKIOCGET: /* Get disk status */ break; case DEVIOCGET: /* Device status */ devget = (struct devget *)data; bzero(devget,sizeof(struct devget)); devget->category = DEV_DISK; /* Disk */ if(ui->ui_hd->uba_type & (UBAUVI|UBAUVII)) { devget->bus = DEV_QB; } else { devget->bus = DEV_UB; } switch (devget->bus) { case DEV_UB: bcopy(DEV_RLU211,devget->interface, strlen(DEV_RLU211)); /* RLU211 */ break; case DEV_QB: bcopy(DEV_RLV211,devget->interface, strlen(DEV_RLV211)); /* RLV211 */ break; } bcopy(sc->sc_device[ui->ui_unit], devget->device, strlen(sc->sc_device[ui->ui_unit])); /* RL02 */ devget->adpt_num = ui->ui_adpt; /* which adapter*/ devget->nexus_num = ui->ui_nexus; /* which nexus */ devget->bus_num = ui->ui_ubanum; /* which UBA/QB */ devget->ctlr_num = ui->ui_ctlr; /* which RL211 */ devget->slave_num = ui->ui_slave; /* which plug */ bcopy(ui->ui_driver->ud_dname, devget->dev_name, strlen(ui->ui_driver->ud_dname)); /* Ultrix "rl" */ devget->unit_num = unit; /* which rl?? */ devget->soft_count = sc->sc_softcnt[ui->ui_unit]; /* soft er. cnt.*/ devget->hard_count = sc->sc_hardcnt[ui->ui_unit]; /* hard er. cnt.*/ devget->stat = sc->sc_flags[ui->ui_unit]; /* status */ devget->category_stat = DEV_DISKPART; /* which prtn. */ break; default: return (ENXIO); } return(0);}/* * Reset driver after UBA init. * Cancel software state of all pending transfers * and restart all units and the controller. */rlreset(uban) int uban;{ register struct uba_ctlr *um; register struct uba_device *ui; register struct rldevice *rladdr; register struct rl_stat *st; register int rl21, unit; for (rl21 = 0; rl21 < nNHL; rl21++) { if ((um = rlminfo[rl21]) == 0 || um->um_ubanum != uban || um->um_alive == 0) continue; printf(" hl%d", rl21); rladdr = (struct rldevice *)um->um_addr; st = &rl_stat[rl21]; um->um_tab.b_active = 0; um->um_tab.b_actf = um->um_tab.b_actl = 0; if (um->um_ubinfo) { printf("<%d>", (um->um_ubinfo>>28)&0xf); um->um_ubinfo = 0; } /* reset controller */ st->rl_dn = -1; st->rl_cylnhd = 0; st->rl_bleft = 0; st->rl_bpart = 0; rlwait(rladdr); for (unit = 0; unit < nNRL; unit++) { rladdr->rlcs = (unit << 8) | RL_GETSTAT; rlwait(rladdr); /* Determine disk posistion */ rladdr->rlcs = (unit << 8) | RL_RHDR; rlwait(rladdr); /* save disk drive posistion */ st->rl_cyl[unit] = (rladdr->rlmp.readhdr & 0177700) >> 6; if ((ui = rldinfo[unit]) == 0) continue; if (ui->ui_alive == 0 || ui->ui_mi != um) continue; rlutab[unit].b_active = 0; rlustart(ui); } rlstart(um); }}/* * Wake up every second and if an interrupt is pending * but nothing has happened increment a counter. * If nothing happens for 20 seconds, reset the UNIBUS * and begin anew. */rlwatch(){ register struct uba_ctlr *um; register rl21, unit; register struct rl_softc *sc; timeout(rlwatch, (caddr_t)0, hz); for (rl21 = 0; rl21 < nNHL; rl21++) { um = rlminfo[rl21]; if (um == 0 || um->um_alive == 0) continue; sc = &rl_softc[rl21]; if (um->um_tab.b_active == 0) { for (unit = 0; unit < nNRL; unit++) if (rlutab[unit].b_active && rldinfo[unit]->ui_mi == um) goto active; sc->rl_wticks = 0; continue; }active: sc->rl_wticks++; if (sc->rl_wticks >= 20) { sc->rl_wticks = 0; printf("hl%d: lost interrupt\n", rl21); /* get rid of this - dallas ubareset(um->um_ubanum); */ printf("RESETING RL\n"); rlreset(um->um_ubanum); /* and do this */ } }}/*ARGSUSED*/rldump(dev) dev_t dev;{ /* should do a partial dump if possible. */}rlsize(dev) dev_t dev;{ register int unit = minor(dev) >> 3; register struct uba_device *ui; if (unit >= nNRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0) return (-1); /* * Sanity check 001 */ if ( rl_part[unit].pt_valid != PT_VALID ) panic("rlsize: invalid partition table "); return (rl_part[unit].pt_part[minor(dev) & 07].pi_nblocks); /*001*/}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -