📄 ts.c
字号:
/* * Tape positioned incorrectly; * set to seek forwards or backwards to the correct spot. * This happens for raw tapes only on error retries. */ um->um_tab.b_active = SSEEK; if (blkno < bdbtofsb(bp->b_blkno)) { bp->b_command = TS_SFORW; tc->c_repcnt = bdbtofsb(bp->b_blkno) - blkno; } else { bp->b_command = TS_SREV; tc->c_repcnt = blkno - bdbtofsb(bp->b_blkno); }dobpcmd: /* * Do the command in bp. */ tc->c_cmd = TS_ACK | TS_CVC | TS_IE | bp->b_command; addr->tsdb = sc->sc_uba; return;next: /* * Done with this operation due to error or * the fact that it doesn't do anything. * Release UBA resources (if any), dequeue * the transfer and continue processing this slave. */ if (um->um_ubinfo) ubadone(um); um->um_tab.b_errcnt = 0; um->um_tab.b_actf->b_actf = bp->av_forw; iodone(bp); goto loop;}/* * The BUS resources we needed have been * allocated to us; start the device. */tsdgo(um) register struct uba_ctlr *um;{ register struct tsdevice *addr = (struct tsdevice *)um->um_addr; register struct ts_softc *sc = &ts_softc[um->um_ctlr]; register int i; i = um->um_ubinfo & 0777776; /* odd address transfer fix */ sc->sc_cmd.c_loba = i; sc->sc_cmd.c_hiba = (i>>16)&3; addr->tsdb = sc->sc_uba;}/* * Ts interrupt routine. */tsintr(ts11) int ts11;{ register struct buf *bp; register struct uba_ctlr *um = tsminfo[ts11]; register struct tsdevice *addr; register struct ts_softc *sc; register int state; register int unit; if ((bp = um->um_tab.b_actf->b_actf) == NULL) return; unit = UNIT(bp->b_dev); addr = (struct tsdevice *)tsdinfo[unit]->ui_addr; /* * 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->tssr&TS_SSR) == 0) return; } /* * An operation completed... record status */ sc = &ts_softc[unit];#ifdef mips clean_dcache(PHYS_TO_K0(svtophy(&sc->sc_sts)), sizeof(struct ts_sts));#endif mips 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->tssr&TS_SC) { switch (addr->tssr & TS_TC) { case TS_UNREC: /* unrecoverable */ case TS_FATAL: /* fatal error */ case TS_ATTN: /* attention */ case TS_RECNM: /* recoverable, no motion */ break; case TS_SUCC: /* success termination */ goto ignoreerr; case TS_ALERT: /* tape status alert */ /* * If we hit the end-of-tape (EOT), * just return. */ if (sc->sc_sts.s_xs0 & TS_EOT) { sc->sc_flags |= DEV_EOM; goto opdone; } /* * If we hit a tapemark, * update our position. */ if (sc->sc_sts.s_xs0 & TS_TMK) { sc->sc_category_flags |= DEV_TPMARK; if (bp == &ctsbuf[unit]) { if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { /* reversing */ sc->sc_nxrec = bdbtofsb(bp->b_blkno) - sc->sc_sts.s_rbpcr; sc->sc_blkno = sc->sc_nxrec; } else { /* spacing forward */ sc->sc_blkno = bdbtofsb(bp->b_blkno) + sc->sc_sts.s_rbpcr; 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. */ sc->sc_sts.s_rbpcr = bp->b_bcount; goto opdone; } /* * If we were reading raw tape and the record was * too long or too short, then we don't consider * this an error. */ if (bp != &ctsbuf[unit] && (bp->b_flags&B_READ) && sc->sc_sts.s_xs0&(TS_RLS|TS_RLL)) { sc->sc_category_flags |= DEV_SHRTREC; goto ignoreerr; } case TS_RECOV: /* recoverable, tape moved */ /* * If this was an i/o operation retry 8 times. */ if (state==SIO) { if (++um->um_tab.b_errcnt < 7) { /* for soft error reporting - dallas */ if(ts_softerr) { mprintf("%s: unit#:%d soft err blk#:%d \ xs0:%b xs1:%b xs2:%b xs3:%b xs4:%b\n", sc->sc_device, unit, bp->b_blkno, sc->sc_sts.s_xs0, TSXS0_BITS, sc->sc_sts.s_xs1, TSXS1_BITS, sc->sc_sts.s_xs2, TSXS2_BITS, sc->sc_sts.s_xs3, TSXS3_BITS, sc->sc_sts.s_xs4, TSXS4_BITS); } sc->sc_softcnt++; ubadone(um); goto opcont; } else sc->sc_blkno++; } else { /* * Non-i/o errors on non-raw tape * cause it to close. */ if (sc->sc_openf>0 && bp == &ctsbuf[unit]) sc->sc_openf = -1; } break; case TS_REJECT: /* function reject */ if (state == SIO && sc->sc_sts.s_xs0 & TS_WLE) sc->sc_flags |= DEV_WRTLCK; if ((sc->sc_sts.s_xs0 & TS_ONL) == 0) sc->sc_flags |= DEV_OFFLINE; break; } /* * Couldn't recover error */ sc->sc_flags |= DEV_HARDERR; sc->sc_hardcnt++; mprintf("%s: unit#:%d hard err blk#:%d \ xs0:%b xs1:%b xs2:%b xs3:%b xs4:%b\n", sc->sc_device, unit, bp->b_blkno, sc->sc_sts.s_xs0, TSXS0_BITS, sc->sc_sts.s_xs1, TSXS1_BITS, sc->sc_sts.s_xs2, TSXS2_BITS, sc->sc_sts.s_xs3, TSXS3_BITS, sc->sc_sts.s_xs4, TSXS4_BITS); bp->b_flags |= B_ERROR; goto opdone; } /* * Advance tape control FSM. */ignoreerr: if (sc->sc_sts.s_xs0 & TS_EOT) { sc->sc_flags |= DEV_EOM; } switch (state) { case SIO: /* * Read/write increments tape block number */ sc->sc_blkno++; goto opdone; case SCOM: /* * For forw./back. space record update current position. */ if (bp == &ctsbuf[unit]) switch (bp->b_command) { case TS_SFORW: sc->sc_blkno += bp->b_repcnt; break; case TS_SREV: sc->sc_blkno -= bp->b_repcnt; break; } goto opdone; case SSEEK: sc->sc_blkno = bdbtofsb(bp->b_blkno); goto opcont; default: panic("tsintr"); }opdone: /* * Reset error count and remove * from device queue. */ sc->sc_flags |= DEV_DONE; um->um_tab.b_errcnt = 0; um->um_tab.b_actf->b_actf = bp->av_forw; bp->b_resid = sc->sc_sts.s_rbpcr; ubadone(um);/* hsieh - Due to the delay in processing large nbuf io (> 24k buffer) * with the bufflush routine we must see if there * is anything on the queue first and then start it. * We must keep the tape streaming. Thrashing occurs if tape * drive hit the next tape gap and we are still hanging in * the bufflush code. The problem is seen at buffer size greater * than 24kb system. Dallas suggested I kicked the controller * with next command before calling bufflush. */ if (um->um_tab.b_actf->b_actf != 0) tsstart(um);#ifdef mips if(cpu != DS_5800 && (bp->b_flags & B_READ)){ bufflush(bp); }#endif mips iodone(bp); return;opcont: tsstart(um);}tsread(dev, uio) register dev_t dev; register struct uio *uio;{ register int unit = UNIT(dev); return (physio(tsstrategy, &rtsbuf[unit], dev, B_READ, minphys, uio));}tswrite(dev, uio) register dev_t dev; register struct uio *uio;{ register int unit = UNIT(dev); return (physio(tsstrategy, &rtsbuf[unit], dev, B_WRITE, minphys, uio));}tsreset(uban) register int uban;{ register struct uba_ctlr *um; register struct uba_device *ui; register struct ts_softc *sc; register struct buf *dp; register ts11; for (ts11 = 0; ts11 < nNTS; ts11++) { if ((um = tsminfo[ts11]) == 0 || um->um_alive == 0 || um->um_ubanum != uban) continue; sc = &ts_softc[ts11]; mprintf("ts reset"); um->um_tab.b_active = 0; um->um_tab.b_actf = um->um_tab.b_actl = 0; if (sc->sc_openf > 0) sc->sc_openf = -1; if (um->um_ubinfo) { mprintf("<%d>", (um->um_ubinfo>>28)&0xf); um->um_ubinfo = 0; } if ((ui = tsdinfo[ts11]) && ui->ui_mi == um && ui->ui_alive) { dp = &tsutab[ts11]; 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; } sc->sc_mapped = 0; /* so it won't think * it is still * allocated * and tsinit will remap * itself */ (void) tsinit(ts11); tsstart(um); }}tsioctl(dev, cmd, data, flag) dev_t dev; register int cmd; caddr_t data; int flag;{ register struct uba_device *ui = tsdinfo[UNIT(dev)]; register struct ts_softc *sc = &ts_softc[UNIT(dev)]; register struct buf *bp = &ctsbuf[UNIT(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 tsops[] = { TS_WEOF, TS_SFORWF, TS_SREVF, TS_SFORW, TS_SREV, TS_REW, TS_OFFL, TS_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: 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_ts[unit] = 0; return(0); case MTDISEOT: dis_eot_ts[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) { tscommand(dev, tsops[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_sts.s_xs0 & TS_BOT) break; } return (geterror(bp)); case MTIOCGET: /* tape status */ mtget = (struct mtget *)data; mtget->mt_dsreg = 0; mtget->mt_erreg = sc->sc_sts.s_xs0; mtget->mt_resid = sc->sc_resid; mtget->mt_type = MT_ISTS; break; case DEVIOCGET: /* device status */ devget = (struct devget *)data; bzero(devget,sizeof(struct devget)); devget->category = DEV_TAPE; if(ui->ui_hd->uba_type & (UBAUVI|UBAUVII)) { devget->bus = DEV_QB; } else { devget->bus = DEV_UB; } switch (devget->bus) { case DEV_UB: if(sc->sc_sts.s_xs2 & TS_TU80) { bcopy(DEV_TUU80,devget->interface, strlen(DEV_TUU80)); } else { if (sc->sc_sts.s_xs4 & TS_HSP) { bcopy(DEV_TSU05, devget->interface, strlen(DEV_TSU05)); } else { bcopy(DEV_TSU11, devget->interface, strlen(DEV_TSU11)); } } break; case DEV_QB: bcopy(DEV_TSV05,devget->interface, strlen(DEV_TSV05)); break; } bcopy(sc->sc_device,devget->device, strlen(sc->sc_device)); /* t[su] */ 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 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 "ts" */ devget->unit_num = unit; /* which t[su]??*/ 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);}tsdump(){ register struct uba_device *ui; register struct uba_regs *up; register struct tsdevice *addr; register int blk; register int num; register int start; int ubatype; start = 0; num = maxfree; if (tsdinfo[0] == 0) return (ENXIO); ui = PHYS(tsdinfo[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(1000000); addr = (struct tsdevice *)ui->ui_physaddr; addr->tssr = 0; tswait(addr); while (num > 0) { blk = num > DBSIZE ? DBSIZE : num; tsdwrite(start, blk, addr, up); start += blk; num -= blk; } tseof(addr); tseof(addr); tswait(addr); if (addr->tssr&TS_SC) return (EIO); addr->tssr = 0; tswait(addr); return (0);}tsdwrite(dbuf, num, addr, up) register int dbuf; register int num; register struct tsdevice *addr; struct uba_regs *up;{ register struct pte *io; register struct ts_softc *sc = &ts_softc[0]; register int npf; tswait(addr); io = up->uba_map; npf = num+1; while (--npf != 0) *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); *(int *)io = 0; sc->sc_cmd.c_size = -(num*NBPG); /* byte count */ sc->sc_cmd.c_loba = 0; /* low buffer address */ sc->sc_cmd.c_hiba = 0; /* high buf. address */ sc->sc_cmd.c_cmd = TS_ACK | TS_CVC | TS_IE | TS_WCOM; /* doit */}tswait(addr) register struct tsdevice *addr;{ register volatile int s; do s = addr->tssr; while ((s & TS_SSR) == 0);}tseof(addr) register struct tsdevice *addr;{ register struct ts_softc *sc = &ts_softc[0]; tswait(addr); sc->sc_cmd.c_cmd = TS_ACK | TS_CVC | TS_IE | TS_WEOF; /* doit */}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -