📄 ut.c
字号:
bp = dp->b_actf; utunit = UTUNIT(bp->b_dev); unit = UNIT(bp->b_dev); addr = (struct utdevice *)tjdinfo[unit]->ui_addr; sc = &tj_softc[unit]; /* * Record status... */ sc->sc_timo = INF; sc->sc_dsreg = addr->utds; sc->sc_erreg = addr->uter; sc->sc_resid = MASKREG(addr->utfc); if ((bp->b_flags&B_READ) == 0) sc->sc_flags |= DEV_WRITTEN; state = um->um_tab.b_state; um->um_tab.b_state = 0; /* * Check for errors... */ if ((addr->utds & UTDS_ERR) || (addr->utcs1 & UT_TRE)) { /* * To clear the ERR bit, we must issue a drive clear * command, and to clear the TRE bit we must set the * controller clear bit. */ cs2 = addr->utcs2; if ((cs1 = addr->utcs1)&UT_TRE) addr->utcs2 |= UTCS2_CLR; while ((addr->utcs1&UT_RDY) == 0) ; addr->utcs1 = UT_CLEAR|UT_GO; if (sc->sc_dsreg & UTDS_EOT) { sc->sc_flags |= DEV_EOM; goto opdone; } /* * If we were reading at 1600 or 6250 bpi and the error * was corrected, then don't consider this an error. */ if (sc->sc_erreg & UTER_COR && (bp->b_flags & B_READ) && (addr->uttc & UTTC_DEN) != UTTC_NRZI) { mprintf("%s: unit# %d: soft error block# %d\n", sc->sc_device, unit, bp->b_blkno); mprintf("utcs1=%b uter=%b utcs2=%b utds=%b\n", cs1, UT_BITS, sc->sc_erreg, UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS); sc->sc_erreg &= ~UTER_COR; } /* * If we were reading from a raw tape and the only error * was that the record was too long, then we don't * consider this an error. */ if (bp != &cutbuf[utunit] && (bp->b_flags&B_READ) && (sc->sc_erreg&UTER_FCE)) sc->sc_erreg &= ~UTER_FCE; if (sc->sc_erreg == 0) goto ignoreerr; /* * Fix up errors which occur due to backspacing * "over" the front of the tape. */ if ((sc->sc_dsreg & UTDS_BOT) && bp->b_command == UT_SREV && ((sc->sc_erreg &= ~(UTER_NEF|UTER_FCE)) == 0)) goto opdone; /* * Retry soft errors up to 8 times */ if ((sc->sc_erreg&UTER_HARD) == 0 && state == SIO) { if (++um->um_tab.b_errcnt < 7) { sc->sc_blkno++; sc->sc_flags |= DEV_RETRY; ubadone(um); goto opcont; } } /* * Hard or non-I/O errors on non-raw tape * cause it to close. */ if (sc->sc_openf > 0 && bp == &cutbuf[utunit]) sc->sc_openf = -1; /* * Couldn't recover error. */ sc->sc_flags |= DEV_HARDERR; mprintf("%s: unit# %d: hard error block# %d\n", sc->sc_device, unit, bp->b_blkno); mprintf("utcs1=%b uter=%b utcs2=%b utds=%b\n", cs1, UT_BITS, sc->sc_erreg, UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS); bp->b_flags |= B_ERROR; goto opdone; }ignoreerr: /* * If we hit EOT set flag. */ if (sc->sc_dsreg & UTDS_EOT) { sc->sc_flags |= DEV_EOM; } /* * If we hit a tape mark update our position. */ if (sc->sc_dsreg & UTDS_TM && bp->b_flags & B_READ) { sc->sc_category_flags |= DEV_TPMARK; /* * Set blkno and nxrec */ if (bp == &cutbuf[utunit]) { if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { sc->sc_nxrec = bdbtofsb(bp->b_blkno) - addr->utfc; sc->sc_blkno = sc->sc_nxrec; } else { sc->sc_blkno = bdbtofsb(bp->b_blkno) + addr->utfc; sc->sc_nxrec = sc->sc_blkno-1; } } else sc->sc_nxrec = bdbtofsb(bp->b_blkno); /* * Note: if we get a tape mark on a read, the * frame count register will be zero, so b_resid * will be calculated correctly below. */ goto opdone; } /* * Advance tape control FSM. */ switch (state) { case SIO: /* read/write increments tape block # */ sc->sc_blkno++; break; case SCOM: /* motion commands update position */ if (bp == &cutbuf[utunit]) switch (bp->b_command) { case UT_SFORW: sc->sc_blkno -= bp->b_repcnt; break; case UT_SREV: sc->sc_blkno += bp->b_repcnt; break; case UT_REWOFFL: addr->utcs1 = UT_CLEAR|UT_GO; break; } break; case SSEEK: sc->sc_blkno = bdbtofsb(bp->b_blkno); goto opcont; case SERASE: /* * Completed erase of the inter-record gap due to a * write error; now retry the write operation. */ um->um_tab.b_state = SERASED; goto opcont; case SREW: /* clear attention bit */ addr->utcs1 = UT_CLEAR|UT_GO; break; default: mprintf("bad state %d\n", state); panic("utintr"); }opdone: /* * Reset error count and remove * from device queue */ um->um_tab.b_errcnt = 0; dp->b_actf = bp->av_forw; sc->sc_flags |= DEV_DONE; /* * For read command, frame count register contains * actual length of tape record. Otherwise, it * holds negative residual count. */ if (state == SIO && um->um_cmd == UT_RCOM) { bp->b_resid = 0; if (bp->b_bcount > MASKREG(addr->utfc)) bp->b_resid = bp->b_bcount - MASKREG(addr->utfc); } else bp->b_resid = MASKREG(-addr->utfc); ubadone(um); iodone(bp); /* * Circulate slave to end of controller queue * to give other slaves a chance */ um->um_tab.b_actf = dp->b_forw; if (dp->b_actf) { dp->b_forw = NULL; if (um->um_tab.b_actf == NULL) um->um_tab.b_actf = dp; else um->um_tab.b_actl->b_forw = dp; um->um_tab.b_actl = dp; } if (um->um_tab.b_actf == 0) return;opcont: utstart(um);}/* * Watchdog timer routine. */uttimer(dev) register int dev;{ register struct tj_softc *sc = &tj_softc[UNIT(dev)]; register int utunit = UTUNIT(dev); register int unit = UNIT(dev); register short x; if (sc->sc_timo != INF && (sc->sc_timo -= 5) < 0) { mprintf("%s: unit# %d: lost interrupt\n", sc->sc_device, unit); sc->sc_timo = INF; x = spl5(); utintr(utunit); (void) splx(x); } timeout(uttimer, (caddr_t)dev, 5*hz);}/* * Raw interface for a read */utread(dev, uio) register dev_t dev; register struct uio *uio;{ register int utunit = UTUNIT(dev); return (physio(utstrategy, &rutbuf[utunit], dev, B_READ, minphys, uio));}/* * Raw interface for a write */utwrite(dev, uio) register dev_t dev; register struct uio *uio;{ register int utunit = UTUNIT(dev); return (physio(utstrategy, &rutbuf[utunit], dev, B_WRITE, minphys, uio));}utioctl(dev, cmd, data, flag) dev_t dev; register int cmd; caddr_t data; int flag;{ register struct uba_device *ui = tjdinfo[UTUNIT(dev)]; register struct tj_softc *sc = &tj_softc[UNIT(dev)]; register struct buf *bp = &cutbuf[UTUNIT(dev)]; register int callcount; register int fcount; struct mtop *mtop; struct mtget *mtget; struct devget *devget; int unit = UNIT(dev); /* we depend of the values and order of the MT codes here */ static utops[] = { UT_WEOF, UT_SFORWF, UT_SREVF, UT_SFORW, UT_SREV, UT_REW, UT_REWOFFL, UT_SENSE }; switch (cmd) { case MTIOCTOP: /* tape operation */ mtop = (struct mtop *)data; switch(mtop->mt_op) { case MTWEOF: case MTFSF: case MTBSF: case MTFSR: case MTBSR: callcount = mtop->mt_count; fcount = 1; break; case MTREW: case MTOFFL: sc->sc_flags &= ~DEV_EOM; callcount = 1; fcount = 1; break; case MTNOP: case MTCACHE: case MTNOCACHE: case MTCLX: case MTCLS: return(0); case MTCSE: sc->sc_flags |= DEV_CSE; sc->sc_category_flags &= ~DEV_TPMARK; return(0); case MTENAEOT: dis_eot_tj[unit] = 0; return(0); case MTDISEOT: dis_eot_tj[unit] = DISEOT; sc->sc_flags &= ~DEV_EOM; return(0); case MTFLUSH: /* * Flush controller's write back cache. Since this * driver can not support this functionality, return * ENXIO to indicate the lack of support. */ return (ENXIO); default: return (ENXIO); } if (callcount <= 0 || fcount <= 0) return (EINVAL); while (--callcount >= 0) { utcommand(dev, utops[mtop->mt_op], fcount); if ((bp->b_flags & B_ERROR) || (sc->sc_dsreg & UTDS_BOT)) break; } return (geterror(bp)); case MTIOCGET: /* tape status */ mtget = (struct mtget *)data; mtget->mt_dsreg = sc->sc_dsreg; mtget->mt_erreg = sc->sc_erreg; mtget->mt_resid = sc->sc_resid; mtget->mt_type = MT_ISUT; break; case DEVIOCGET: /* device status */ devget = (struct devget *)data; bzero(devget,sizeof(struct devget)); devget->category = DEV_TAPE; devget->bus = DEV_UB; bcopy(DEV_UNKNOWN,devget->interface, strlen(DEV_UNKNOWN)); bcopy(sc->sc_device,devget->device, strlen(sc->sc_device)); devget->adpt_num = ui->ui_adpt; /* which adapter*/ devget->nexus_num = ui->ui_nexus; /* which nexus */ devget->bus_num = ui->ui_ubanum; /* which UBA */ devget->ctlr_num = ui->ui_ctlr; /* which interf.*/ devget->slave_num = ui->ui_slave; /* which plug */ bcopy(ui->ui_driver->ud_dname, devget->dev_name, strlen(ui->ui_driver->ud_dname)); /* Ultrix "tj" */ devget->unit_num = unit; /* which tj?? */ devget->soft_count = sc->sc_softcnt; /* soft er. cnt.*/ devget->hard_count = sc->sc_hardcnt; /* hard er. cnt.*/ devget->stat = sc->sc_flags; /* status */ devget->category_stat = sc->sc_category_flags; /* c.st.*/ break; default: return (ENXIO); } return (0);}utreset(uban) register int uban;{ register struct uba_ctlr *um; register struct uba_device *ui; register struct buf *dp; register int ut11; register int unit; struct tj_softc *sc; for (ut11 = 0; ut11 < nNUT; ut11++) { if ((um = utminfo[ut11]) == 0 || um->um_alive == 0 || um->um_ubanum != uban) continue; um->um_tab.b_state = 0; um->um_tab.b_actf = um->um_tab.b_actl = 0; if (um->um_ubinfo) { mprintf("ut reset"); mprintf("<%d>", (um->um_ubinfo>>28)&0xf); um->um_ubinfo = 0; } ((struct utdevice *)(um->um_addr))->utcs1 = UT_CLEAR|UT_GO; ((struct utdevice *)(um->um_addr))->utcs2 |= UTCS2_CLR; for (unit = 0; unit < nNTJ; unit++) { if ((ui = tjdinfo[unit]) == 0 || ui->ui_mi != um || ui->ui_alive == 0) continue; sc = &tj_softc[unit]; dp = &tjutab[unit]; dp->b_state = 0; dp->b_forw = 0; if (um->um_tab.b_actf == NULL) um->um_tab.b_actf = dp; else um->um_tab.b_actl->b_forw = dp; um->um_tab.b_actl = dp; if (sc->sc_openf > 0) sc->sc_openf = -1; } utstart(um); }}/* * Do a stand-alone core dump to tape -- * from here down, routines are used only in dump context */utdump(){ register struct uba_device *ui; register struct uba_regs *up; register struct utdevice *addr; register int blk; register int num = maxfree; register int start = 0; int ubatype; if (tjdinfo[0] == 0) return (ENXIO); ui = PHYS(tjdinfo[0], struct uba_device *); up = PHYS(ui->ui_hd, struct uba_hd *)->uh_physuba; ubatype = PHYS(ui->ui_hd, struct uba_hd *)->uba_type; ubainit(up,ubatype); DELAY(500000); addr = (struct utdevice *)ui->ui_physaddr; utwait(addr); /* * Be sure to set the appropriate density here. We use * 6250, but maybe it should be done at 1600 to insure the * tape can be read by most any other tape drive available. */ addr->uttc = UTTC_GCR|UTTC_PDP11FMT; /* implicit slave 0 */ addr->utcs1 = UT_CLEAR|UT_GO; while (num > 0) { blk = num > DBSIZE ? DBSIZE : num; utdwrite(start, blk, addr, up); if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) return(EIO); start += blk; num -= blk; } uteof(addr); uteof(addr); utwait(addr); if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) return(EIO); addr->utcs1 = UT_REW|UT_GO; return (0);}utdwrite(dbuf, num, addr, up) register int dbuf; register int num; register struct utdevice *addr; register struct uba_regs *up;{ register struct pte *io; register int npf; utwait(addr); io = up->uba_map; npf = num + 1; while (--npf != 0) *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); *(int *)io = 0; addr->utwc = -((num*NBPG)>>1); addr->utfc = -(num*NBPG); addr->utba = 0; addr->utcs1 = UT_WCOM|UT_GO;}utwait(addr) register struct utdevice *addr;{ register int s; do s = addr->utds; while ((s&UTDS_DRY) == 0);}uteof(addr) register struct utdevice *addr;{ utwait(addr); addr->utcs1 = UT_WEOF|UT_GO;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -