📄 tm.c
字号:
* the transfer and continue processing this slave. */ if (um->um_ubinfo) ubadone(um); um->um_tab.b_errcnt = 0; dp->b_actf = bp->av_forw; iodone(bp); goto loop;}/* * The bus resources we needed have been * allocated to us; start the device. */tmdgo(um) register struct uba_ctlr *um;{ register struct tmdevice *addr = (struct tmdevice *)um->um_addr; addr->tmba = um->um_ubinfo; addr->tmcs = um->um_cmd | ((um->um_ubinfo >> 12) & 0x30);}/* * TM interrupt routine. */tmintr(tm11) int tm11;{ register struct buf *bp; register struct uba_ctlr *um = tmminfo[tm11]; register struct tmdevice *addr; register struct te_softc *sc; register int state; register struct buf *dp; int tmunit, unit; if ((dp = um->um_tab.b_actf) == NULL) return; bp = dp->b_actf; tmunit = TMUNIT(bp->b_dev); unit = UNIT(bp->b_dev); addr = (struct tmdevice *)tedinfo[unit]->ui_addr; sc = &te_softc[unit]; /* * If last command was a rewind, and tape is still * rewinding, wait for the rewind complete interrupt. */ if (um->um_tab.b_active == SREW) { um->um_tab.b_active = SCOM; if (addr->tmer&TMER_RWS) { sc->sc_timo = 5*60; /* 5 minutes */ return; } } /* * An operation completed... record status */ sc->sc_timo = INF; sc->sc_dsreg = addr->tmcs; sc->sc_erreg = addr->tmer; sc->sc_resid = addr->tmbc; if ((bp->b_flags & B_READ) == 0) sc->sc_flags |= DEV_WRITTEN; state = um->um_tab.b_active; um->um_tab.b_active = 0; /* * Check for errors. */ if (addr->tmcs & TM_ERR) { while (addr->tmer & TMER_SDWN) ; /* await settle down */ /* * If we hit end-of-tape (EOT), * just return. */ if (addr->tmer & TMER_EOT) { sc->sc_flags |= DEV_EOM; goto opdone; } /* * If we hit the end of the tape file, update position. */ if (addr->tmer & TMER_EOF) { sc->sc_category_flags |= DEV_TPMARK; if (bp == &ctmbuf[tmunit]) { if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { /* reversing */ sc->sc_nxrec = bdbtofsb(bp->b_blkno) - addr->tmbc; sc->sc_blkno = sc->sc_nxrec; } else { /* spacing forward */ sc->sc_blkno = bdbtofsb(bp->b_blkno) + addr->tmbc; sc->sc_nxrec = sc->sc_blkno - 1; } goto seteof; } /* eof on read */ sc->sc_nxrec = bdbtofsb(bp->b_blkno);seteof: state = SCOM; /* force completion */ /* * Stuff bc so it will be unstuffed correctly * later to get resid. */ addr->tmbc = -bp->b_bcount; goto opdone; } /* * If we were reading raw tape and the only error was * that the record was too long, then we don't consider * this an error. */ if (bp != &ctmbuf[tmunit] && (bp->b_flags&B_READ) && (addr->tmer&(TMER_HARD|TMER_SOFT)) == TMER_RLE) goto ignoreerr; /* * If error is not hard, and this was an i/o operation * retry up to 8 times. */ if ((addr->tmer&TMER_HARD)==0 && state==SIO) { if (++um->um_tab.b_errcnt < 7) { sc->sc_blkno++; ubadone(um); goto opcont; } } else /* * Hard or non-i/o errors on non-raw tape * cause it to close. */ if (sc->sc_openf>0 && bp == &ctmbuf[tmunit]) 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("tmer=%b\n", sc->sc_erreg, TMER_BITS); bp->b_flags |= B_ERROR; goto opdone; } /* * Advance tape control FSM. */ignoreerr: if (addr->tmer & TMER_EOT) { sc->sc_flags |= DEV_EOM; } switch (state) { case SIO: /* * Read/write increments tape block number */ sc->sc_blkno++; goto opdone; case SCOM: /* * For forward/backward space record update current * position. */ if (bp == &ctmbuf[tmunit]) switch (bp->b_command) { case TM_SFORW: sc->sc_blkno -= bp->b_repcnt; break; case TM_SREV: sc->sc_blkno += bp->b_repcnt; break; } goto opdone; case SSEEK: sc->sc_blkno = bdbtofsb(bp->b_blkno); goto opcont; default: panic("tmintr"); }opdone: /* * Reset error count and remove * from device queue. */ sc->sc_flags |= DEV_DONE; um->um_tab.b_errcnt = 0; dp->b_actf = bp->av_forw; /* * Check resid; watch out for resid >32767 (tmbc not negative). */ bp->b_resid = ((int) -addr->tmbc) & 0xffff; 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: tmstart(um);}tmtimer(dev) register int dev;{ register struct te_softc *sc = &te_softc[UNIT(dev)]; register int tmunit = TMUNIT(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(); tmintr(tmunit); (void) splx(x); } timeout(tmtimer, (caddr_t)dev, 5*hz);}tmread(dev, uio) register dev_t dev; register struct uio *uio;{ register int tmunit = TMUNIT(dev); return (physio(tmstrategy, &rtmbuf[tmunit], dev, B_READ, minphys, uio));}tmwrite(dev, uio) register dev_t dev; register struct uio *uio;{ register int tmunit = TMUNIT(dev); return (physio(tmstrategy, &rtmbuf[tmunit], dev, B_WRITE, minphys, uio));}tmioctl(dev, cmd, data, flag) dev_t dev; register int cmd; caddr_t data; int flag;{ register struct uba_device *ui = tedinfo[TMUNIT(dev)]; register struct te_softc *sc = &te_softc[UNIT(dev)]; register struct buf *bp = &ctmbuf[TMUNIT(dev)]; register 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 tmops[] = { TM_WEOF,TM_SFORW,TM_SREV,TM_SFORW, TM_SREV,TM_REW,TM_OFFL,TM_SENSE }; switch (cmd) { case MTIOCTOP: /* tape operation */ mtop = (struct mtop *)data; switch (mtop->mt_op) { case MTWEOF: callcount = mtop->mt_count; fcount = 1; break; case MTFSF: case MTBSF: callcount = mtop->mt_count; fcount = INF; break; case MTFSR: case MTBSR: callcount = 1; fcount = mtop->mt_count; 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_te[unit] = 0; return(0); case MTDISEOT: dis_eot_te[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) { tmcommand(dev, tmops[mtop->mt_op], fcount); if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) && bp->b_resid) return (EIO); if ((bp->b_flags & B_ERROR) || sc->sc_erreg & TMER_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_ISTM; 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 "te" */ devget->unit_num = unit; /* which te?? */ 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);}tmreset(uban) register int uban;{ register struct uba_ctlr *um; register struct uba_device *ui; register struct buf *dp; register int tm11; register int unit; struct te_softc *sc; for (tm11 = 0; tm11 < nNTM; tm11++) { if ((um = tmminfo[tm11]) == 0 || um->um_alive == 0 || um->um_ubanum != uban) continue; um->um_tab.b_active = 0; um->um_tab.b_actf = um->um_tab.b_actl = 0; if (um->um_ubinfo) { mprintf("tm reset"); mprintf("<%d>", (um->um_ubinfo>>28)&0xf); um->um_ubinfo = 0; } ((struct tmdevice *)(um->um_addr))->tmcs = TM_DCLR; for (unit = 0; unit < nNTE; unit++) { if ((ui = tedinfo[unit]) == 0 || ui->ui_mi != um || ui->ui_alive == 0) continue; sc = &te_softc[unit]; dp = &teutab[unit]; dp->b_active = 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; } tmstart(um); }}tmdump(){ register struct uba_device *ui; register struct uba_regs *up; register struct tmdevice *addr; register int blk; register int num = maxfree; register int start = 0; if (tedinfo[0] == 0) return (ENXIO); ui = PHYS(tedinfo[0], struct uba_device *); up = PHYS(ui->ui_hd, struct uba_hd *)->uh_physuba; ubainit(up); DELAY(500000); addr = (struct tmdevice *)ui->ui_physaddr; tmwait(addr); addr->tmcs = TM_DCLR | TM_GO; while (num > 0) { blk = num > DBSIZE ? DBSIZE : num; tmdwrite(start, blk, addr, up); start += blk; num -= blk; } tmeof(addr); tmeof(addr); tmwait(addr); if (addr->tmcs&TM_ERR) return (EIO); addr->tmcs = TM_REW | TM_GO; tmwait(addr); return (0);}tmdwrite(dbuf, num, addr, up) register int dbuf; register int num; register struct tmdevice *addr; register struct uba_regs *up;{ register struct pte *io; register int npf; tmwait(addr); io = up->uba_map; npf = num+1; while (--npf != 0) *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); *(int *)io = 0; addr->tmbc = -(num*NBPG); addr->tmba = 0; addr->tmcs = TM_WCOM | TM_GO;}tmwait(addr) register struct tmdevice *addr;{ register int s; do s = addr->tmcs; while ((s & TM_CUR) == 0);}tmeof(addr) register struct tmdevice *addr;{ tmwait(addr); addr->tmcs = TM_WEOF | TM_GO;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -