📄 rd.c
字号:
register int unit;{ register struct buf *bp; register struct rd_softc *rs = &rd_softc[unit]; bp = rdtab[unit].b_actf; rs->sc_addr = bp->b_un.b_addr; rs->sc_resid = bp->b_bcount; if (hpibreq(&rs->sc_dq)) rdstart(unit);}struct buf *rdfinish(unit, rs, bp) int unit; register struct rd_softc *rs; register struct buf *bp;{ register struct buf *dp = &rdtab[unit]; dp->b_errcnt = 0; dp->b_actf = bp->b_actf; bp->b_resid = 0; biodone(bp); hpibfree(&rs->sc_dq); if (dp->b_actf) return(dp->b_actf); dp->b_active = 0; if (rs->sc_flags & RDF_WANTED) { rs->sc_flags &= ~RDF_WANTED; wakeup((caddr_t)dp); } return(NULL);}rdstart(unit) register int unit;{ register struct rd_softc *rs = &rd_softc[unit]; register struct buf *bp = rdtab[unit].b_actf; register struct hp_device *hp = rs->sc_hd; register int part;again:#ifdef DEBUG if (rddebug & RDB_FOLLOW) printf("rdstart(%d): bp %x, %c\n", unit, bp, (bp->b_flags & B_READ) ? 'R' : 'W');#endif part = rdpart(bp->b_dev); rs->sc_flags |= RDF_SEEK; rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit); rs->sc_ioc.c_volume = C_SVOL(0); rs->sc_ioc.c_saddr = C_SADDR; rs->sc_ioc.c_hiaddr = 0; rs->sc_ioc.c_addr = RDBTOS(bp->b_cylin); rs->sc_ioc.c_nop2 = C_NOP; rs->sc_ioc.c_slen = C_SLEN; rs->sc_ioc.c_len = rs->sc_resid; rs->sc_ioc.c_cmd = bp->b_flags & B_READ ? C_READ : C_WRITE;#ifdef DEBUG if (rddebug & RDB_IO) printf("rdstart: hpibsend(%x, %x, %x, %x, %x)\n", hp->hp_ctlr, hp->hp_slave, C_CMD, &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2);#endif if (hpibsend(hp->hp_ctlr, hp->hp_slave, C_CMD, &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2) == sizeof(rs->sc_ioc)-2) { if (hp->hp_dk >= 0) { dk_busy |= 1 << hp->hp_dk; dk_seek[hp->hp_dk]++; }#ifdef DEBUG if (rddebug & RDB_IO) printf("rdstart: hpibawait(%x)\n", hp->hp_ctlr);#endif hpibawait(hp->hp_ctlr); return; } /* * Experience has shown that the hpibwait in this hpibsend will * occasionally timeout. It appears to occur mostly on old 7914 * drives with full maintenance tracks. We should probably * integrate this with the backoff code in rderror. */#ifdef DEBUG if (rddebug & RDB_ERROR) printf("rd%d: rdstart: cmd %x adr %d blk %d len %d ecnt %d\n", unit, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr, bp->b_blkno, rs->sc_resid, rdtab[unit].b_errcnt); rdstats[unit].rdretries++;#endif rs->sc_flags &= ~RDF_SEEK; rdreset(rs, hp); if (rdtab[unit].b_errcnt++ < RDRETRY) goto again; printf("rd%d: rdstart err: cmd 0x%x sect %d blk %d len %d\n", unit, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr, bp->b_blkno, rs->sc_resid); bp->b_flags |= B_ERROR; bp->b_error = EIO; bp = rdfinish(unit, rs, bp); if (bp) { rs->sc_addr = bp->b_un.b_addr; rs->sc_resid = bp->b_bcount; if (hpibreq(&rs->sc_dq)) goto again; }}rdgo(unit) register int unit;{ register struct rd_softc *rs = &rd_softc[unit]; register struct hp_device *hp = rs->sc_hd; struct buf *bp = rdtab[unit].b_actf; if (hp->hp_dk >= 0) { dk_busy |= 1 << hp->hp_dk; dk_xfer[hp->hp_dk]++; dk_wds[hp->hp_dk] += rs->sc_resid >> 6; }#ifdef USELEDS if (inledcontrol == 0) ledcontrol(0, 0, LED_DISK);#endif hpibgo(hp->hp_ctlr, hp->hp_slave, C_EXEC, rs->sc_addr, rs->sc_resid, bp->b_flags & B_READ);}rdintr(unit) register int unit;{ register struct rd_softc *rs = &rd_softc[unit]; register struct buf *bp = rdtab[unit].b_actf; register struct hp_device *hp = rs->sc_hd; u_char stat = 13; /* in case hpibrecv fails */ int rv, restart; #ifdef DEBUG if (rddebug & RDB_FOLLOW) printf("rdintr(%d): bp %x, %c, flags %x\n", unit, bp, (bp->b_flags & B_READ) ? 'R' : 'W', rs->sc_flags); if (bp == NULL) { printf("rd%d: bp == NULL\n", unit); return; }#endif if (hp->hp_dk >= 0) dk_busy &= ~(1 << hp->hp_dk); if (rs->sc_flags & RDF_SEEK) { rs->sc_flags &= ~RDF_SEEK; if (hpibustart(hp->hp_ctlr)) rdgo(unit); return; } if ((rs->sc_flags & RDF_SWAIT) == 0) {#ifdef DEBUG rdstats[unit].rdpolltries++;#endif if (hpibpptest(hp->hp_ctlr, hp->hp_slave) == 0) {#ifdef DEBUG rdstats[unit].rdpollwaits++;#endif if (hp->hp_dk >= 0) dk_busy |= 1 << hp->hp_dk; rs->sc_flags |= RDF_SWAIT; hpibawait(hp->hp_ctlr); return; } } else rs->sc_flags &= ~RDF_SWAIT; rv = hpibrecv(hp->hp_ctlr, hp->hp_slave, C_QSTAT, &stat, 1); if (rv != 1 || stat) {#ifdef DEBUG if (rddebug & RDB_ERROR) printf("rdintr: recv failed or bad stat %d\n", stat);#endif restart = rderror(unit);#ifdef DEBUG rdstats[unit].rdretries++;#endif if (rdtab[unit].b_errcnt++ < RDRETRY) { if (restart) rdstart(unit); return; } bp->b_flags |= B_ERROR; bp->b_error = EIO; } if (rdfinish(unit, rs, bp)) rdustart(unit);}rdstatus(rs) register struct rd_softc *rs;{ register int c, s; u_char stat; int rv; c = rs->sc_hd->hp_ctlr; s = rs->sc_hd->hp_slave; rs->sc_rsc.c_unit = C_SUNIT(rs->sc_punit); rs->sc_rsc.c_sram = C_SRAM; rs->sc_rsc.c_ram = C_RAM; rs->sc_rsc.c_cmd = C_STATUS; bzero((caddr_t)&rs->sc_stat, sizeof(rs->sc_stat)); rv = hpibsend(c, s, C_CMD, &rs->sc_rsc, sizeof(rs->sc_rsc)); if (rv != sizeof(rs->sc_rsc)) {#ifdef DEBUG if (rddebug & RDB_STATUS) printf("rdstatus: send C_CMD failed %d != %d\n", rv, sizeof(rs->sc_rsc));#endif return(1); } rv = hpibrecv(c, s, C_EXEC, &rs->sc_stat, sizeof(rs->sc_stat)); if (rv != sizeof(rs->sc_stat)) {#ifdef DEBUG if (rddebug & RDB_STATUS) printf("rdstatus: send C_EXEC failed %d != %d\n", rv, sizeof(rs->sc_stat));#endif return(1); } rv = hpibrecv(c, s, C_QSTAT, &stat, 1); if (rv != 1 || stat) {#ifdef DEBUG if (rddebug & RDB_STATUS) printf("rdstatus: recv failed %d or bad stat %d\n", rv, stat);#endif return(1); } return(0);}/* * Deal with errors. * Returns 1 if request should be restarted, * 0 if we should just quietly give up. */rderror(unit) int unit;{ struct rd_softc *rs = &rd_softc[unit]; register struct rd_stat *sp; struct buf *bp; daddr_t hwbn, pbn; if (rdstatus(rs)) {#ifdef DEBUG printf("rd%d: couldn't get status\n", unit);#endif rdreset(rs, rs->sc_hd); return(1); } sp = &rs->sc_stat; if (sp->c_fef & FEF_REXMT) return(1); if (sp->c_fef & FEF_PF) { rdreset(rs, rs->sc_hd); return(1); } /* * Unit requests release for internal maintenance. * We just delay awhile and try again later. Use expontially * increasing backoff ala ethernet drivers since we don't really * know how long the maintenance will take. With RDWAITC and * RDRETRY as defined, the range is 1 to 32 seconds. */ if (sp->c_fef & FEF_IMR) { extern int hz; int rdtimo = RDWAITC << rdtab[unit].b_errcnt;#ifdef DEBUG printf("rd%d: internal maintenance, %d second timeout\n", unit, rdtimo); rdstats[unit].rdtimeouts++;#endif hpibfree(&rs->sc_dq); timeout(rdrestart, (void *)unit, rdtimo * hz); return(0); } /* * Only report error if we have reached the error reporting * threshhold. By default, this will only report after the * retry limit has been exceeded. */ if (rdtab[unit].b_errcnt < rderrthresh) return(1); /* * First conjure up the block number at which the error occured. * Note that not all errors report a block number, in that case * we just use b_blkno. */ bp = rdtab[unit].b_actf; pbn = rs->sc_info.ri_label.d_partitions[rdpart(bp->b_dev)].p_offset; if ((sp->c_fef & FEF_CU) || (sp->c_fef & FEF_DR) || (sp->c_ief & IEF_RRMASK)) { hwbn = RDBTOS(pbn + bp->b_blkno); pbn = bp->b_blkno; } else { hwbn = sp->c_blk; pbn = RDSTOB(hwbn) - pbn; } /* * Now output a generic message suitable for badsect. * Note that we don't use harderr cuz it just prints * out b_blkno which is just the beginning block number * of the transfer, not necessary where the error occured. */ printf("rd%d%c: hard error sn%d\n", rdunit(bp->b_dev), 'a'+rdpart(bp->b_dev), pbn); /* * Now report the status as returned by the hardware with * attempt at interpretation (unless debugging). */ printf("rd%d %s error:", unit, (bp->b_flags & B_READ) ? "read" : "write");#ifdef DEBUG if (rddebug & RDB_ERROR) { /* status info */ printf("\n volume: %d, unit: %d\n", (sp->c_vu>>4)&0xF, sp->c_vu&0xF); rdprinterr("reject", sp->c_ref, err_reject); rdprinterr("fault", sp->c_fef, err_fault); rdprinterr("access", sp->c_aef, err_access); rdprinterr("info", sp->c_ief, err_info); printf(" block: %d, P1-P10: ", hwbn); printf("%s", hexstr(*(u_int *)&sp->c_raw[0], 8)); printf("%s", hexstr(*(u_int *)&sp->c_raw[4], 8)); printf("%s\n", hexstr(*(u_short *)&sp->c_raw[8], 4)); /* command */ printf(" ioc: "); printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_pad, 8)); printf("%s", hexstr(*(u_short *)&rs->sc_ioc.c_hiaddr, 4)); printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_addr, 8)); printf("%s", hexstr(*(u_short *)&rs->sc_ioc.c_nop2, 4)); printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_len, 8)); printf("%s\n", hexstr(*(u_short *)&rs->sc_ioc.c_cmd, 4)); return(1); }#endif printf(" v%d u%d, R0x%x F0x%x A0x%x I0x%x\n", (sp->c_vu>>4)&0xF, sp->c_vu&0xF, sp->c_ref, sp->c_fef, sp->c_aef, sp->c_ief); printf("P1-P10: "); printf("%s", hexstr(*(u_int *)&sp->c_raw[0], 8)); printf("%s", hexstr(*(u_int *)&sp->c_raw[4], 8)); printf("%s\n", hexstr(*(u_short *)&sp->c_raw[8], 4)); return(1);}intrdread(dev, uio, flags) dev_t dev; struct uio *uio; int flags;{ return (physio(rdstrategy, NULL, dev, B_READ, minphys, uio));}intrdwrite(dev, uio, flags) dev_t dev; struct uio *uio; int flags;{ return (physio(rdstrategy, NULL, dev, B_WRITE, minphys, uio));}intrdioctl(dev, cmd, data, flag, p) dev_t dev; int cmd; caddr_t data; int flag; struct proc *p;{ int unit = rdunit(dev); register struct rd_softc *sc = &rd_softc[unit]; register struct disklabel *lp = &sc->sc_info.ri_label; int error, flags; switch (cmd) { case DIOCGDINFO: *(struct disklabel *)data = *lp; return (0); case DIOCGPART: ((struct partinfo *)data)->disklab = lp; ((struct partinfo *)data)->part = &lp->d_partitions[rdpart(dev)]; return (0); case DIOCWLABEL: if ((flag & FWRITE) == 0) return (EBADF); if (*(int *)data) sc->sc_flags |= RDF_WLABEL; else sc->sc_flags &= ~RDF_WLABEL; return (0); case DIOCSDINFO: if ((flag & FWRITE) == 0) return (EBADF); return (setdisklabel(lp, (struct disklabel *)data, (sc->sc_flags & RDF_WLABEL) ? 0 : sc->sc_info.ri_open)); case DIOCWDINFO: if ((flag & FWRITE) == 0) return (EBADF); error = setdisklabel(lp, (struct disklabel *)data, (sc->sc_flags & RDF_WLABEL) ? 0 : sc->sc_info.ri_open); if (error) return (error); flags = sc->sc_flags; sc->sc_flags = RDF_ALIVE | RDF_WLABEL; error = writedisklabel(rdlabdev(dev), rdstrategy, lp); sc->sc_flags = flags; return (error); } return(EINVAL);}intrdsize(dev) dev_t dev;{ register int unit = rdunit(dev); register struct rd_softc *rs = &rd_softc[unit]; int psize, didopen = 0; if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0) return(-1); /* * We get called very early on (via swapconf) * without the device being open so we may need * to handle it here. */ if (rs->sc_info.ri_open == 0) { if (rdopen(dev, FREAD|FWRITE, S_IFBLK, NULL)) return(-1); didopen = 1; } psize = rs->sc_info.ri_label.d_partitions[rdpart(dev)].p_size; if (didopen) (void) rdclose(dev, FREAD|FWRITE, S_IFBLK, NULL); return (psize);}#ifdef DEBUGrdprinterr(str, err, tab) char *str; short err; char *tab[];{ register int i; int printed; if (err == 0) return; printf(" %s error field:", str, err); printed = 0; for (i = 0; i < 16; i++) if (err & (0x8000 >> i)) printf("%s%s", printed++ ? " + " : " ", tab[i]); printf("\n");}#endif/* * Non-interrupt driven, non-dma dump routine. */intrddump(dev) dev_t dev;{ int part = rdpart(dev); int unit = rdunit(dev); register struct rd_softc *rs = &rd_softc[unit]; register struct hp_device *hp = rs->sc_hd; register struct partition *pinfo; register daddr_t baddr; register int maddr, pages, i; char stat; extern int lowram, dumpsize;#ifdef DEBUG extern int pmapdebug; pmapdebug = 0;#endif /* is drive ok? */ if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0) return (ENXIO); pinfo = &rs->sc_info.ri_label.d_partitions[part]; /* dump parameters in range? */ if (dumplo < 0 || dumplo >= pinfo->p_size || pinfo->p_fstype != FS_SWAP) return (EINVAL); pages = dumpsize; if (dumplo + ctod(pages) > pinfo->p_size) pages = dtoc(pinfo->p_size - dumplo); maddr = lowram; baddr = dumplo + pinfo->p_offset; /* HPIB idle? */ if (!hpibreq(&rs->sc_dq)) { hpibreset(hp->hp_ctlr); rdreset(rs, rs->sc_hd); printf("[ drive %d reset ] ", unit); } for (i = 0; i < pages; i++) {#define NPGMB (1024*1024/NBPG) /* print out how many Mbs we have dumped */ if (i && (i % NPGMB) == 0) printf("%d ", i / NPGMB);#undef NPBMG rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit); rs->sc_ioc.c_volume = C_SVOL(0); rs->sc_ioc.c_saddr = C_SADDR; rs->sc_ioc.c_hiaddr = 0; rs->sc_ioc.c_addr = RDBTOS(baddr); rs->sc_ioc.c_nop2 = C_NOP; rs->sc_ioc.c_slen = C_SLEN; rs->sc_ioc.c_len = NBPG; rs->sc_ioc.c_cmd = C_WRITE; hpibsend(hp->hp_ctlr, hp->hp_slave, C_CMD, &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2); if (hpibswait(hp->hp_ctlr, hp->hp_slave)) return (EIO); pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr, VM_PROT_READ, TRUE); hpibsend(hp->hp_ctlr, hp->hp_slave, C_EXEC, vmmap, NBPG); (void) hpibswait(hp->hp_ctlr, hp->hp_slave); hpibrecv(hp->hp_ctlr, hp->hp_slave, C_QSTAT, &stat, 1); if (stat) return (EIO); maddr += NBPG; baddr += ctod(1); } return (0);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -