123349Smckusick /* 229246Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323349Smckusick * All rights reserved. The Berkeley software License Agreement 423349Smckusick * specifies the terms and conditions for redistribution. 523349Smckusick * 6*32579Sbostic * @(#)ts.c 7.3 (Berkeley) 11/03/87 723349Smckusick */ 81900Swnj 91941Swnj #include "ts.h" 101900Swnj #if NTS > 0 111900Swnj /* 121900Swnj * TS11 tape driver 133244Swnj * 14*32579Sbostic * NB: This driver takes advantage of the fact that there is only one 15*32579Sbostic * drive per controller. 16*32579Sbostic * 173244Swnj * TODO: 18*32579Sbostic * test dump code 191900Swnj */ 2017080Sbloom #include "param.h" 2117080Sbloom #include "systm.h" 2217080Sbloom #include "buf.h" 2317080Sbloom #include "dir.h" 2417080Sbloom #include "conf.h" 2517080Sbloom #include "user.h" 2617080Sbloom #include "file.h" 2717080Sbloom #include "map.h" 2817080Sbloom #include "vm.h" 2917080Sbloom #include "ioctl.h" 3017080Sbloom #include "mtio.h" 3117080Sbloom #include "cmap.h" 3217080Sbloom #include "uio.h" 3318322Sralph #include "tty.h" 3430917Skarels #include "syslog.h" 351900Swnj 3630917Skarels #include "../machine/pte.h" 378480Sroot #include "../vax/cpu.h" 3817080Sbloom #include "ubareg.h" 3917080Sbloom #include "ubavar.h" 4017080Sbloom #include "tsreg.h" 411900Swnj 423244Swnj /* 433244Swnj * There is a ctsbuf per tape controller. 443244Swnj * It is used as the token to pass to the internal routines 453244Swnj * to execute tape ioctls. 463244Swnj * In particular, when the tape is rewinding on close we release 473244Swnj * the user process but any further attempts to use the tape drive 483244Swnj * before the rewind completes will hang waiting for ctsbuf. 493244Swnj */ 503244Swnj struct buf ctsbuf[NTS]; 511900Swnj 523244Swnj /* 533244Swnj * Raw tape operations use rtsbuf. The driver 543244Swnj * notices when rtsbuf is being used and allows the user 553244Swnj * program to continue after errors and read records 563244Swnj * not of the standard length (BSIZE). 573244Swnj */ 583244Swnj struct buf rtsbuf[NTS]; 591900Swnj 603244Swnj /* 613244Swnj * Driver unibus interface routines and variables. 623244Swnj */ 633244Swnj int tsprobe(), tsslave(), tsattach(), tsdgo(), tsintr(); 643244Swnj struct uba_ctlr *tsminfo[NTS]; 653244Swnj struct uba_device *tsdinfo[NTS]; 665693Sroot struct buf tsutab[NTS]; 673244Swnj u_short tsstd[] = { 0772520, 0 }; 68*32579Sbostic /* need all these even though controller == drive */ 693244Swnj struct uba_driver zsdriver = 70*32579Sbostic { tsprobe, tsslave, tsattach, tsdgo, tsstd, "ts", tsdinfo, "zs", tsminfo }; 711900Swnj 723244Swnj /* bits in minor device */ 733244Swnj #define TSUNIT(dev) (minor(dev)&03) 743244Swnj #define T_NOREWIND 04 75*32579Sbostic #define T_1600BPI 010 761900Swnj 773244Swnj #define INF (daddr_t)1000000L 781900Swnj 793244Swnj /* 803244Swnj * Software state per tape transport. 813244Swnj * Also contains hardware state in message packets. 823244Swnj * 833244Swnj * 1. A tape drive is a unique-open device; we refuse opens when it is already. 843244Swnj * 2. We keep track of the current position on a block tape and seek 853244Swnj * before operations by forward/back spacing if necessary. 863244Swnj * 3. We remember if the last operation was a write on a tape, so if a tape 873244Swnj * is open read write and the last thing done is a write we can 883244Swnj * write a standard end of tape mark (two eofs). 893244Swnj * 4. We remember the status registers after the last command, using 903244Swnj * then internally and returning them to the SENSE ioctl. 913244Swnj */ 92*32579Sbostic struct ts_tsdata { /* data shared with ts11 controller */ 93*32579Sbostic struct ts_cmd t_cmd; /* the command packet (must be first) */ 94*32579Sbostic struct ts_sts t_sts; /* status packet, for returned status */ 95*32579Sbostic struct ts_char t_char; /* characteristics packet */ 96*32579Sbostic }; 973244Swnj struct ts_softc { 983244Swnj char sc_openf; /* lock against multiple opens */ 993244Swnj char sc_lastiow; /* last op was a write */ 1003327Swnj short sc_resid; /* copy of last bc */ 1013244Swnj daddr_t sc_blkno; /* block number, for block device tape */ 1023244Swnj daddr_t sc_nxrec; /* position of end of tape, if known */ 103*32579Sbostic struct ts_tsdata sc_ts;/* command and status packets */ 104*32579Sbostic struct ts_tsdata *sc_ubaddr; /* Unibus address of tsdata structure */ 1055697Sroot u_short sc_uba; /* Unibus addr of cmd pkt for tsdb */ 106*32579Sbostic short sc_density; /* value |'ed into char_mode for TC13 density */ 10718322Sralph struct tty *sc_ttyp; /* record user's tty for errors */ 10830917Skarels int sc_blks; /* number of I/O operations since open */ 10930917Skarels int sc_softerrs; /* number of soft I/O errors since open */ 1103244Swnj } ts_softc[NTS]; 1111900Swnj 1123244Swnj /* 1133244Swnj * States for um->um_tab.b_active, the per controller state flag. 1143244Swnj * This is used to sequence control in the driver. 1153244Swnj */ 1163244Swnj #define SSEEK 1 /* seeking */ 1173244Swnj #define SIO 2 /* doing seq i/o */ 1183244Swnj #define SCOM 3 /* sending control command */ 1193244Swnj #define SREW 4 /* sending a drive rewind */ 1201900Swnj 1213244Swnj /* 1223244Swnj * Determine if there is a controller for 1233244Swnj * a ts at address reg. Our goal is to make the 1243244Swnj * device interrupt. 1253244Swnj */ 1263985Sroot /*ARGSUSED*/ 127*32579Sbostic tsprobe(reg, ctlr, um) 1283244Swnj caddr_t reg; 129*32579Sbostic int ctlr; 130*32579Sbostic struct uba_ctlr *um; 1313244Swnj { 1323244Swnj register int br, cvec; /* must be r11,r10; value-result */ 133*32579Sbostic register struct tsdevice *addr = (struct tsdevice *)reg; 134*32579Sbostic register struct ts_softc *sc; 135*32579Sbostic register int i; 136*32579Sbostic int a; 1371900Swnj 1383244Swnj #ifdef lint 1393244Swnj br = 0; cvec = br; br = cvec; 1404937Swnj tsintr(0); 1413244Swnj #endif 142*32579Sbostic addr->tssr = 0; /* initialize subsystem */ 1435693Sroot DELAY(100); 144*32579Sbostic if ((addr->tssr & TS_NBA) == 0) 145*32579Sbostic return (0); 146*32579Sbostic 147*32579Sbostic /* 148*32579Sbostic * Make it interrupt. 149*32579Sbostic * TS_SETCHR|TS_IE alone refuses to interrupt for me. 150*32579Sbostic */ 151*32579Sbostic sc = &ts_softc[ctlr]; 152*32579Sbostic tsmap(sc, numuba, &a); 153*32579Sbostic i = (int)&sc->sc_ubaddr->t_char; 154*32579Sbostic sc->sc_ts.t_cmd.c_loba = i; 155*32579Sbostic sc->sc_ts.t_cmd.c_hiba = (i >> 16) & 3; 156*32579Sbostic sc->sc_ts.t_cmd.c_size = sizeof(struct ts_char); 157*32579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_SETCHR; 158*32579Sbostic sc->sc_ts.t_char.char_addr = (int)&sc->sc_ubaddr->t_sts; 159*32579Sbostic sc->sc_ts.t_char.char_size = sizeof(struct ts_sts); 160*32579Sbostic sc->sc_ts.t_char.char_mode = 0; /* mode is unimportant */ 161*32579Sbostic addr->tsdb = sc->sc_uba; 162*32579Sbostic DELAY(20000); 163*32579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_IE | TS_SENSE; 164*32579Sbostic sc->sc_ts.t_cmd.c_repcnt = 1; 165*32579Sbostic addr->tsdb = sc->sc_uba; 166*32579Sbostic DELAY(20000); 167*32579Sbostic /* should have interrupted by now */ 168*32579Sbostic 169*32579Sbostic if (cvec == 0 || cvec == 0x200) /* no interrupt */ 170*32579Sbostic ubarelse(numuba, &a); 171*32579Sbostic 1727407Skre return (sizeof (struct tsdevice)); 1733244Swnj } 1741900Swnj 1753244Swnj /* 176*32579Sbostic * Map in the command, status, and characteristics packet. We 177*32579Sbostic * make them contiguous to keep overhead down. This also sets 178*32579Sbostic * sc_uba (which then never changes). 179*32579Sbostic */ 180*32579Sbostic tsmap(sc, uban, a) 181*32579Sbostic register struct ts_softc *sc; 182*32579Sbostic int uban, *a; 183*32579Sbostic { 184*32579Sbostic register int i; 185*32579Sbostic 186*32579Sbostic i = uballoc(uban, (caddr_t)&sc->sc_ts, sizeof(sc->sc_ts), 0); 187*32579Sbostic if (a != NULL) 188*32579Sbostic *a = i; 189*32579Sbostic i = UBAI_ADDR(i); 190*32579Sbostic sc->sc_ubaddr = (struct ts_tsdata *)i; 191*32579Sbostic /* 192*32579Sbostic * Note that i == the Unibus address of the command packet, 193*32579Sbostic * and that it is a multiple of 4 (guaranteed by the compiler). 194*32579Sbostic */ 195*32579Sbostic sc->sc_uba = i + ((i >> 16) & 3); 196*32579Sbostic } 197*32579Sbostic 198*32579Sbostic /* 1993244Swnj * TS11 only supports one drive per controller; 2003244Swnj * check for ui_slave == 0. 2013244Swnj */ 2023244Swnj /*ARGSUSED*/ 2033244Swnj tsslave(ui, reg) 2043244Swnj struct uba_device *ui; 2053244Swnj caddr_t reg; 2063244Swnj { 2071900Swnj 208*32579Sbostic return (ui->ui_slave == 0); /* non-zero slave not allowed */ 2093244Swnj } 2101900Swnj 2113244Swnj /* 2123244Swnj * Record attachment of the unit to the controller. 2133244Swnj */ 2143244Swnj /*ARGSUSED*/ 2153244Swnj tsattach(ui) 2163244Swnj struct uba_device *ui; 2173244Swnj { 2181900Swnj 219*32579Sbostic /* void */ 2203244Swnj } 2211900Swnj 2223244Swnj /* 2233244Swnj * Open the device. Tapes are unique open 2243244Swnj * devices, so we refuse if it is already open. 2253244Swnj */ 2261900Swnj tsopen(dev, flag) 2273244Swnj dev_t dev; 2283244Swnj int flag; 2291900Swnj { 230*32579Sbostic register int tsunit = TSUNIT(dev); 2313244Swnj register struct uba_device *ui; 2323244Swnj register struct ts_softc *sc; 2331900Swnj 234*32579Sbostic if (tsunit >= NTS || (ui = tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) 2358575Sroot return (ENXIO); 236*32579Sbostic if ((sc = &ts_softc[ui->ui_ctlr])->sc_openf) 23725054Skarels return (EBUSY); 23830917Skarels sc->sc_openf = 1; 239*32579Sbostic sc->sc_density = (minor(dev) & T_1600BPI) ? TS_NRZI : 0; 240*32579Sbostic tscommand(dev, TS_SENSE, 1); 241*32579Sbostic if (ctsbuf[tsunit].b_flags & B_ERROR) 242*32579Sbostic /* 243*32579Sbostic * Try it again in case it went off-line 244*32579Sbostic */ 245*32579Sbostic tscommand(dev, TS_SENSE, 1); 246*32579Sbostic if (tsinit(ui->ui_ctlr)) { 24730917Skarels sc->sc_openf = 0; 2488575Sroot return (ENXIO); 24930917Skarels } 250*32579Sbostic if ((sc->sc_ts.t_sts.s_xs0&TS_ONL) == 0) { 25130917Skarels sc->sc_openf = 0; 2523711Sroot uprintf("ts%d: not online\n", tsunit); 2538575Sroot return (EIO); 2541900Swnj } 255*32579Sbostic if ((flag&FWRITE) && (sc->sc_ts.t_sts.s_xs0&TS_WLK)) { 25630917Skarels sc->sc_openf = 0; 2573711Sroot uprintf("ts%d: no write ring\n", tsunit); 2588575Sroot return (EIO); 2593711Sroot } 2603244Swnj sc->sc_blkno = (daddr_t)0; 2613244Swnj sc->sc_nxrec = INF; 2623244Swnj sc->sc_lastiow = 0; 26330917Skarels sc->sc_blks = 0; 26430917Skarels sc->sc_softerrs = 0; 26518322Sralph sc->sc_ttyp = u.u_ttyp; 2668575Sroot return (0); 2671900Swnj } 2681900Swnj 2693244Swnj /* 2703244Swnj * Close tape device. 2713244Swnj * 2723244Swnj * If tape was open for writing or last operation was 2733244Swnj * a write, then write two EOF's and backspace over the last one. 2743244Swnj * Unless this is a non-rewinding special file, rewind the tape. 2753244Swnj * Make the tape available to others. 2763244Swnj */ 2771900Swnj tsclose(dev, flag) 2783244Swnj register dev_t dev; 279*32579Sbostic register int flag; 2801900Swnj { 2813244Swnj register struct ts_softc *sc = &ts_softc[TSUNIT(dev)]; 2821900Swnj 2833244Swnj if (flag == FWRITE || (flag&FWRITE) && sc->sc_lastiow) { 2843244Swnj tscommand(dev, TS_WEOF, 1); 2853244Swnj tscommand(dev, TS_WEOF, 1); 2863244Swnj tscommand(dev, TS_SREV, 1); 2871900Swnj } 2883244Swnj if ((minor(dev)&T_NOREWIND) == 0) 2893244Swnj /* 2903244Swnj * 0 count means don't hang waiting for rewind complete 2913244Swnj * rather ctsbuf stays busy until the operation completes 2923244Swnj * preventing further opens from completing by 2933244Swnj * preventing a TS_SENSE from completing. 2943244Swnj */ 2953244Swnj tscommand(dev, TS_REW, 0); 29630917Skarels if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100) 29730917Skarels log(LOG_INFO, "ts%d: %d soft errors in %d blocks\n", 29830917Skarels TSUNIT(dev), sc->sc_softerrs, sc->sc_blks); 2993244Swnj sc->sc_openf = 0; 3001900Swnj } 3011900Swnj 3023244Swnj /* 303*32579Sbostic * Initialize a TS11. Set device characteristics. 3043244Swnj */ 305*32579Sbostic tsinit(ctlr) 306*32579Sbostic register int ctlr; 3071900Swnj { 308*32579Sbostic register struct ts_softc *sc = &ts_softc[ctlr]; 309*32579Sbostic register struct uba_ctlr *um = tsminfo[ctlr]; 3105693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 3113244Swnj register int i; 3123244Swnj 313*32579Sbostic if (addr->tssr & (TS_NBA|TS_OFL) || sc->sc_ts.t_sts.s_xs0 & TS_BOT) { 3143244Swnj addr->tssr = 0; /* subsystem initialize */ 3153244Swnj tswait(addr); 316*32579Sbostic i = (int)&sc->sc_ubaddr->t_char; 317*32579Sbostic sc->sc_ts.t_cmd.c_loba = i; 318*32579Sbostic sc->sc_ts.t_cmd.c_hiba = (i >> 16) & 3; 319*32579Sbostic sc->sc_ts.t_cmd.c_size = sizeof(struct ts_char); 320*32579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_SETCHR; 321*32579Sbostic sc->sc_ts.t_char.char_addr = (int)&sc->sc_ubaddr->t_sts; 322*32579Sbostic sc->sc_ts.t_char.char_size = sizeof(struct ts_sts); 323*32579Sbostic sc->sc_ts.t_char.char_mode = TS_ESS | TS_EAI | TS_ERI | 324*32579Sbostic /* TS_ENB | */ sc->sc_density; 3253244Swnj addr->tsdb = sc->sc_uba; 3263244Swnj tswait(addr); 3273327Swnj if (addr->tssr & TS_NBA) 3283327Swnj return(1); 3293244Swnj } 3303244Swnj return(0); 3313244Swnj } 3323244Swnj 3333244Swnj /* 3343244Swnj * Execute a command on the tape drive 3353244Swnj * a specified number of times. 3363244Swnj */ 3373244Swnj tscommand(dev, com, count) 3383244Swnj dev_t dev; 3393244Swnj int com, count; 3403244Swnj { 3411900Swnj register struct buf *bp; 3425438Sroot register int s; 343*32579Sbostic int didsleep = 0; 3441900Swnj 3453244Swnj bp = &ctsbuf[TSUNIT(dev)]; 3465438Sroot s = spl5(); 3473244Swnj while (bp->b_flags&B_BUSY) { 3483244Swnj /* 3493244Swnj * This special check is because B_BUSY never 3503244Swnj * gets cleared in the non-waiting rewind case. 3513244Swnj */ 3523244Swnj if (bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 3533244Swnj break; 3541900Swnj bp->b_flags |= B_WANTED; 3551900Swnj sleep((caddr_t)bp, PRIBIO); 356*32579Sbostic didsleep = 1; 3571900Swnj } 3583244Swnj bp->b_flags = B_BUSY|B_READ; 3595438Sroot splx(s); 360*32579Sbostic if (didsleep) 361*32579Sbostic (void) tsinit(tsdinfo[TSUNIT(dev)]->ui_ctlr); 3623244Swnj bp->b_dev = dev; 3633244Swnj bp->b_repcnt = count; 3643244Swnj bp->b_command = com; 3651900Swnj bp->b_blkno = 0; 3661900Swnj tsstrategy(bp); 3673244Swnj /* 3683244Swnj * In case of rewind from close, don't wait. 3693244Swnj * This is the only case where count can be 0. 3703244Swnj */ 3713244Swnj if (count == 0) 3723244Swnj return; 373*32579Sbostic biowait(bp); 3743244Swnj if (bp->b_flags&B_WANTED) 3751900Swnj wakeup((caddr_t)bp); 3763244Swnj bp->b_flags &= B_ERROR; 3771900Swnj } 3781900Swnj 3793244Swnj /* 3803244Swnj * Queue a tape operation. 3813244Swnj */ 3821900Swnj tsstrategy(bp) 3833244Swnj register struct buf *bp; 3841900Swnj { 385*32579Sbostic register int tsunit = TSUNIT(bp->b_dev); 3863244Swnj register struct uba_ctlr *um; 3873327Swnj register struct buf *dp; 388*32579Sbostic int s; 3891900Swnj 3903244Swnj /* 3913244Swnj * Put transfer at end of controller queue 3923244Swnj */ 3931900Swnj bp->av_forw = NULL; 3943244Swnj um = tsdinfo[tsunit]->ui_mi; 395*32579Sbostic dp = &tsutab[tsunit]; 3965438Sroot s = spl5(); 3973327Swnj if (dp->b_actf == NULL) 3983327Swnj dp->b_actf = bp; 3991900Swnj else 4003327Swnj dp->b_actl->av_forw = bp; 4013327Swnj dp->b_actl = bp; 4023327Swnj um->um_tab.b_actf = um->um_tab.b_actl = dp; 4033244Swnj /* 4043244Swnj * If the controller is not busy, get 4053244Swnj * it going. 4063244Swnj */ 4073244Swnj if (um->um_tab.b_active == 0) 4083244Swnj tsstart(um); 4095438Sroot splx(s); 4101900Swnj } 4111900Swnj 4123244Swnj /* 4133244Swnj * Start activity on a ts controller. 4143244Swnj */ 4153244Swnj tsstart(um) 4163244Swnj register struct uba_ctlr *um; 4171900Swnj { 4181900Swnj register struct buf *bp; 4195693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 4203244Swnj register struct ts_softc *sc; 4213244Swnj register struct uba_device *ui; 422*32579Sbostic register int tsunit; 423*32579Sbostic int cmd; 4241900Swnj daddr_t blkno; 4251900Swnj 4263244Swnj /* 4273244Swnj * Start the controller if there is something for it to do. 4283244Swnj */ 4293244Swnj loop: 4303327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 4311900Swnj return; 4323244Swnj tsunit = TSUNIT(bp->b_dev); 4333244Swnj ui = tsdinfo[tsunit]; 4343244Swnj sc = &ts_softc[tsunit]; 4353244Swnj /* 4363244Swnj * Default is that last command was NOT a write command; 437*32579Sbostic * if we finish a write command we will notice this in tsintr(). 4383244Swnj */ 4393656Swnj sc->sc_lastiow = 0; 4403244Swnj if (sc->sc_openf < 0 || (addr->tssr&TS_OFL)) { 4413244Swnj /* 4423244Swnj * Have had a hard error on a non-raw tape 4433244Swnj * or the tape unit is now unavailable 4443244Swnj * (e.g. taken off line). 4453244Swnj */ 4463244Swnj bp->b_flags |= B_ERROR; 4473244Swnj goto next; 4483244Swnj } 449*32579Sbostic if (bp == &ctsbuf[tsunit]) { 4503244Swnj /* 4513244Swnj * Execute control operation with the specified count. 4523244Swnj */ 4533244Swnj um->um_tab.b_active = 4543244Swnj bp->b_command == TS_REW ? SREW : SCOM; 455*32579Sbostic sc->sc_ts.t_cmd.c_repcnt = bp->b_repcnt; 4563244Swnj goto dobpcmd; 4573244Swnj } 4583244Swnj /* 459*32579Sbostic * For raw I/O, save the current block 460*32579Sbostic * number in case we have to retry. 4613244Swnj */ 462*32579Sbostic if (bp == &rtsbuf[tsunit]) { 463*32579Sbostic if (um->um_tab.b_errcnt == 0) 464*32579Sbostic sc->sc_blkno = bdbtofsb(bp->b_blkno); 465*32579Sbostic } else { 4663244Swnj /* 467*32579Sbostic * Handle boundary cases for operation 468*32579Sbostic * on non-raw tapes. 4693244Swnj */ 470*32579Sbostic if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 471*32579Sbostic /* 472*32579Sbostic * Can't read past known end-of-file. 473*32579Sbostic */ 474*32579Sbostic bp->b_flags |= B_ERROR; 475*32579Sbostic bp->b_error = ENXIO; 476*32579Sbostic goto next; 477*32579Sbostic } 478*32579Sbostic if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && 479*32579Sbostic bp->b_flags&B_READ) { 480*32579Sbostic /* 481*32579Sbostic * Reading at end of file returns 0 bytes. 482*32579Sbostic */ 483*32579Sbostic bp->b_resid = bp->b_bcount; 484*32579Sbostic clrbuf(bp); 485*32579Sbostic goto next; 486*32579Sbostic } 487*32579Sbostic if ((bp->b_flags&B_READ) == 0) 488*32579Sbostic /* 489*32579Sbostic * Writing sets EOF 490*32579Sbostic */ 491*32579Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; 4923244Swnj } 493*32579Sbostic 4943244Swnj /* 4953244Swnj * If the data transfer command is in the correct place, 4963244Swnj * set up all the registers except the csr, and give 4973244Swnj * control over to the UNIBUS adapter routines, to 4983244Swnj * wait for resources to start the i/o. 4993244Swnj */ 5007383Ssam if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { 501*32579Sbostic sc->sc_ts.t_cmd.c_size = bp->b_bcount; 5023244Swnj if ((bp->b_flags&B_READ) == 0) 5033244Swnj cmd = TS_WCOM; 5041900Swnj else 5053244Swnj cmd = TS_RCOM; 5063244Swnj if (um->um_tab.b_errcnt) 5073244Swnj cmd |= TS_RETRY; 5083244Swnj um->um_tab.b_active = SIO; 509*32579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_IE | cmd; 5103244Swnj (void) ubago(ui); 5113244Swnj return; 5123244Swnj } 5133244Swnj /* 5143244Swnj * Tape positioned incorrectly; 5153244Swnj * set to seek forwards or backwards to the correct spot. 5163244Swnj * This happens for raw tapes only on error retries. 5173244Swnj */ 5183244Swnj um->um_tab.b_active = SSEEK; 5197383Ssam if (blkno < bdbtofsb(bp->b_blkno)) { 5203244Swnj bp->b_command = TS_SFORW; 521*32579Sbostic sc->sc_ts.t_cmd.c_repcnt = bdbtofsb(bp->b_blkno) - blkno; 5221900Swnj } else { 5233244Swnj bp->b_command = TS_SREV; 524*32579Sbostic sc->sc_ts.t_cmd.c_repcnt = blkno - bdbtofsb(bp->b_blkno); 5251900Swnj } 5263244Swnj dobpcmd: 5273244Swnj /* 5283244Swnj * Do the command in bp. 5293244Swnj */ 530*32579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_IE | bp->b_command; 5313244Swnj addr->tsdb = sc->sc_uba; 5321900Swnj return; 5331900Swnj 5343244Swnj next: 5353244Swnj /* 5363244Swnj * Done with this operation due to error or 5373244Swnj * the fact that it doesn't do anything. 5383244Swnj * Release UBA resources (if any), dequeue 5393244Swnj * the transfer and continue processing this slave. 5403244Swnj */ 5413244Swnj if (um->um_ubinfo) 5423244Swnj ubadone(um); 5433244Swnj um->um_tab.b_errcnt = 0; 5443327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 545*32579Sbostic biodone(bp); 5461900Swnj goto loop; 5471900Swnj } 5481900Swnj 5493244Swnj /* 5503244Swnj * The UNIBUS resources we needed have been 5513244Swnj * allocated to us; start the device. 5523244Swnj */ 5533244Swnj tsdgo(um) 5543244Swnj register struct uba_ctlr *um; 5551900Swnj { 5563244Swnj register struct ts_softc *sc = &ts_softc[um->um_ctlr]; 5573327Swnj register int i; 5583244Swnj 55926139Skarels /* 56026139Skarels * The uba code uses byte-offset mode if using bdp; 56126139Skarels * mask off the low bit here. 56226139Skarels */ 563*32579Sbostic i = UBAI_ADDR(um->um_ubinfo); 56426139Skarels if (UBAI_BDP(um->um_ubinfo)) 56526139Skarels i &= ~1; 566*32579Sbostic sc->sc_ts.t_cmd.c_loba = i; 567*32579Sbostic sc->sc_ts.t_cmd.c_hiba = (i >> 16) & 3; 568*32579Sbostic ((struct tsdevice *)um->um_addr)->tsdb = sc->sc_uba; 5693244Swnj } 5703244Swnj 5713244Swnj /* 5723244Swnj * Ts interrupt routine. 5733244Swnj */ 5743244Swnj /*ARGSUSED*/ 575*32579Sbostic tsintr(tsunit) 576*32579Sbostic register int tsunit; 5773244Swnj { 5781900Swnj register struct buf *bp; 579*32579Sbostic register struct uba_ctlr *um; 5805693Sroot register struct tsdevice *addr; 5813244Swnj register struct ts_softc *sc; 582*32579Sbostic register int state; 583*32579Sbostic 58427253Skridle #if VAX630 585*32579Sbostic (void) spl5(); 58627253Skridle #endif 587*32579Sbostic um = tsdinfo[tsunit]->ui_mi; 5883327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 5891900Swnj return; 590*32579Sbostic addr = (struct tsdevice *)um->um_addr; 5913244Swnj /* 5923244Swnj * If last command was a rewind, and tape is still 5933244Swnj * rewinding, wait for the rewind complete interrupt. 5943244Swnj * 5953244Swnj * SHOULD NEVER GET AN INTERRUPT IN THIS STATE. 5963244Swnj */ 5973244Swnj if (um->um_tab.b_active == SREW) { 5983244Swnj um->um_tab.b_active = SCOM; 5993244Swnj if ((addr->tssr&TS_SSR) == 0) 6003244Swnj return; 6013244Swnj } 6023244Swnj /* 6033244Swnj * An operation completed... record status 6043244Swnj */ 605*32579Sbostic sc = &ts_softc[um->um_ctlr]; 6063244Swnj if ((bp->b_flags & B_READ) == 0) 6073244Swnj sc->sc_lastiow = 1; 6083244Swnj state = um->um_tab.b_active; 6093244Swnj /* 6103244Swnj * Check for errors. 6113244Swnj */ 6123244Swnj if (addr->tssr&TS_SC) { 6133244Swnj switch (addr->tssr & TS_TC) { 6143244Swnj case TS_UNREC: /* unrecoverable */ 6153244Swnj case TS_FATAL: /* fatal error */ 6163244Swnj case TS_RECNM: /* recoverable, no motion */ 6173244Swnj break; 618*32579Sbostic case TS_ATTN: /* attention */ 619*32579Sbostic if (sc->sc_ts.t_sts.s_xs0 & TS_VCK) { 620*32579Sbostic /* volume check - may have changed tapes */ 621*32579Sbostic bp->b_flags |= B_ERROR; 622*32579Sbostic goto ignoreerr; 623*32579Sbostic } 624*32579Sbostic break; 6251900Swnj 6263244Swnj case TS_SUCC: /* success termination */ 627*32579Sbostic printf("ts%d: success\n", tsunit); 6283244Swnj goto ignoreerr; 6291900Swnj 6303244Swnj case TS_ALERT: /* tape status alert */ 6313244Swnj /* 6323244Swnj * If we hit the end of the tape file, 6333244Swnj * update our position. 6343244Swnj */ 635*32579Sbostic if (sc->sc_ts.t_sts.s_xs0 & (TS_TMK|TS_EOT)) { 636*32579Sbostic tsseteof(bp); /* set blkno and nxrec */ 637*32579Sbostic state = SCOM; /* force completion */ 6383244Swnj /* 6393244Swnj * Stuff bc so it will be unstuffed correctly 6403244Swnj * later to get resid. 6413244Swnj */ 642*32579Sbostic sc->sc_ts.t_sts.s_rbpcr = bp->b_bcount; 6433244Swnj goto opdone; 6443244Swnj } 6453244Swnj /* 646*32579Sbostic * If we were reading raw tape and the record was too 647*32579Sbostic * long or too short, we don't consider this an error. 6483244Swnj */ 649*32579Sbostic if (bp == &rtsbuf[tsunit] && bp->b_flags&B_READ && 650*32579Sbostic sc->sc_ts.t_sts.s_xs0&(TS_RLS|TS_RLL)) 6513244Swnj goto ignoreerr; 652*32579Sbostic /* FALLTHROUGH */ 653*32579Sbostic 6543244Swnj case TS_RECOV: /* recoverable, tape moved */ 6553244Swnj /* 6563244Swnj * If this was an i/o operation retry up to 8 times. 6573244Swnj */ 658*32579Sbostic if (state == SIO) { 6593244Swnj if (++um->um_tab.b_errcnt < 7) { 6603244Swnj ubadone(um); 6613244Swnj goto opcont; 6623244Swnj } else 6633244Swnj sc->sc_blkno++; 6643244Swnj } else { 6653244Swnj /* 6663244Swnj * Non-i/o errors on non-raw tape 6673244Swnj * cause it to close. 6683244Swnj */ 669*32579Sbostic if (sc->sc_openf > 0 && bp != &rtsbuf[tsunit]) 6703244Swnj sc->sc_openf = -1; 6713244Swnj } 6721900Swnj break; 6733244Swnj 6743244Swnj case TS_REJECT: /* function reject */ 675*32579Sbostic if (state == SIO && sc->sc_ts.t_sts.s_xs0 & TS_WLE) 67618322Sralph tprintf(sc->sc_ttyp, "ts%d: write locked\n", 677*32579Sbostic tsunit); 678*32579Sbostic if ((sc->sc_ts.t_sts.s_xs0 & TS_ONL) == 0) 67918322Sralph tprintf(sc->sc_ttyp, "ts%d: offline\n", 680*32579Sbostic tsunit); 6811900Swnj break; 6821900Swnj } 6833244Swnj /* 6843244Swnj * Couldn't recover error 6853244Swnj */ 686*32579Sbostic tprintf(sc->sc_ttyp, "ts%d: hard error bn%d tssr=%b xs0=%b", 687*32579Sbostic tsunit, bp->b_blkno, addr->tssr, TSSR_BITS, 688*32579Sbostic sc->sc_ts.t_sts.s_xs0, TSXS0_BITS); 689*32579Sbostic if (sc->sc_ts.t_sts.s_xs1) 690*32579Sbostic tprintf(sc->sc_ttyp, " xs1=%b", sc->sc_ts.t_sts.s_xs1, 69118322Sralph TSXS1_BITS); 692*32579Sbostic if (sc->sc_ts.t_sts.s_xs2) 693*32579Sbostic tprintf(sc->sc_ttyp, " xs2=%b", sc->sc_ts.t_sts.s_xs2, 69418322Sralph TSXS2_BITS); 695*32579Sbostic if (sc->sc_ts.t_sts.s_xs3) 696*32579Sbostic tprintf(sc->sc_ttyp, " xs3=%b", sc->sc_ts.t_sts.s_xs3, 69718322Sralph TSXS3_BITS); 69818322Sralph tprintf(sc->sc_ttyp, "\n"); 6993244Swnj bp->b_flags |= B_ERROR; 7003244Swnj goto opdone; 7013244Swnj } 7023244Swnj /* 7033244Swnj * Advance tape control FSM. 7043244Swnj */ 7053244Swnj ignoreerr: 7063244Swnj switch (state) { 7071900Swnj 7083244Swnj case SIO: 7093244Swnj /* 7103244Swnj * Read/write increments tape block number 7113244Swnj */ 7123244Swnj sc->sc_blkno++; 71330917Skarels sc->sc_blks++; 71430917Skarels if (um->um_tab.b_errcnt) 71530917Skarels sc->sc_softerrs++; 7163244Swnj goto opdone; 7171900Swnj 7181900Swnj case SCOM: 7193244Swnj /* 7203244Swnj * For forward/backward space record update current position. 7213244Swnj */ 722*32579Sbostic if (bp == &ctsbuf[tsunit]) 723*32579Sbostic switch ((int)bp->b_command) { 7241900Swnj 725*32579Sbostic case TS_SFORW: 726*32579Sbostic sc->sc_blkno += bp->b_repcnt; 727*32579Sbostic break; 7281900Swnj 729*32579Sbostic case TS_SREV: 730*32579Sbostic sc->sc_blkno -= bp->b_repcnt; 731*32579Sbostic break; 732*32579Sbostic } 7333244Swnj goto opdone; 7343244Swnj 7353244Swnj case SSEEK: 7367383Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno); 7373244Swnj goto opcont; 7383244Swnj 7391900Swnj default: 7403244Swnj panic("tsintr"); 7411900Swnj } 7423244Swnj opdone: 7433244Swnj /* 7443244Swnj * Reset error count and remove 7453244Swnj * from device queue. 7463244Swnj */ 7473244Swnj um->um_tab.b_errcnt = 0; 7483327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 749*32579Sbostic bp->b_resid = sc->sc_ts.t_sts.s_rbpcr; 7503244Swnj ubadone(um); 751*32579Sbostic biodone(bp); 752*32579Sbostic if (um->um_tab.b_actf->b_actf == 0) { 753*32579Sbostic um->um_tab.b_active = 0; 7543244Swnj return; 755*32579Sbostic } 7563244Swnj opcont: 7573244Swnj tsstart(um); 7583244Swnj } 7593244Swnj 7603244Swnj tsseteof(bp) 7613244Swnj register struct buf *bp; 7623244Swnj { 7633244Swnj register int tsunit = TSUNIT(bp->b_dev); 764*32579Sbostic register struct ts_softc *sc = &ts_softc[tsdinfo[tsunit]->ui_ctlr]; 7653244Swnj 766*32579Sbostic if (bp == &ctsbuf[tsunit]) { 7677383Ssam if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 7683244Swnj /* reversing */ 769*32579Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) - 770*32579Sbostic sc->sc_ts.t_sts.s_rbpcr; 7713244Swnj sc->sc_blkno = sc->sc_nxrec; 7723244Swnj } else { 7733244Swnj /* spacing forward */ 774*32579Sbostic sc->sc_blkno = bdbtofsb(bp->b_blkno) + 775*32579Sbostic sc->sc_ts.t_sts.s_rbpcr; 7763244Swnj sc->sc_nxrec = sc->sc_blkno - 1; 7771900Swnj } 7783244Swnj return; 7793244Swnj } 7803244Swnj /* eof on read */ 7817383Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno); 7821900Swnj } 7831900Swnj 7847733Sroot tsread(dev, uio) 7853244Swnj dev_t dev; 7867733Sroot struct uio *uio; 7871900Swnj { 7883244Swnj 7898164Sroot return (physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_READ, minphys, uio)); 7901900Swnj } 7911900Swnj 7927841Sroot tswrite(dev, uio) 7933244Swnj dev_t dev; 7947841Sroot struct uio *uio; 7951900Swnj { 7963244Swnj 7978164Sroot return (physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_WRITE, minphys, uio)); 7981900Swnj } 7991900Swnj 8003244Swnj tsreset(uban) 8013244Swnj int uban; 8021918Swnj { 8033244Swnj register struct uba_ctlr *um; 8045693Sroot register struct uba_device *ui; 8055693Sroot register struct buf *dp; 806*32579Sbostic register int ts11, i; 8071918Swnj 8083244Swnj for (ts11 = 0; ts11 < NTS; ts11++) { 8093244Swnj if ((um = tsminfo[ts11]) == 0 || um->um_alive == 0 || 810*32579Sbostic um->um_ubanum != uban) 8113244Swnj continue; 8123244Swnj printf(" ts%d", ts11); 8133244Swnj um->um_tab.b_active = 0; 8143244Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 8155693Sroot if (ts_softc[ts11].sc_openf > 0) 8165693Sroot ts_softc[ts11].sc_openf = -1; 8173244Swnj if (um->um_ubinfo) { 818*32579Sbostic printf("<%d>", UBAI_BDP(um->um_ubinfo)); 8199356Ssam um->um_ubinfo = 0; 8203244Swnj } 821*32579Sbostic /* 822*32579Sbostic * tsdinfo should be 1-to-1 with tsminfo, but someone 823*32579Sbostic * might have screwed up the config file: 824*32579Sbostic */ 825*32579Sbostic for (i = 0; i < NTS; i++) { 826*32579Sbostic if ((ui = tsdinfo[i]) != NULL && 827*32579Sbostic ui->ui_alive && ui->ui_mi == um) { 828*32579Sbostic um->um_tab.b_actf = um->um_tab.b_actl = 829*32579Sbostic &tsutab[i]; 830*32579Sbostic break; 831*32579Sbostic } 8325693Sroot } 833*32579Sbostic tsmap(&ts_softc[ts11], uban, (int *)NULL); 8343989Sroot (void) tsinit(ts11); 8353244Swnj tsstart(um); 8361918Swnj } 8371918Swnj } 8381918Swnj 8393244Swnj /*ARGSUSED*/ 8407633Ssam tsioctl(dev, cmd, data, flag) 8417633Ssam caddr_t data; 8423244Swnj dev_t dev; 8431918Swnj { 8443244Swnj int tsunit = TSUNIT(dev); 845*32579Sbostic register struct ts_softc *sc = &ts_softc[tsdinfo[tsunit]->ui_ctlr]; 8463244Swnj register struct buf *bp = &ctsbuf[TSUNIT(dev)]; 847*32579Sbostic register int callcount; 8483244Swnj int fcount; 8497633Ssam struct mtop *mtop; 8507633Ssam struct mtget *mtget; 8513244Swnj /* we depend of the values and order of the MT codes here */ 852*32579Sbostic static int tsops[] = 8533656Swnj {TS_WEOF,TS_SFORWF,TS_SREVF,TS_SFORW,TS_SREV,TS_REW,TS_OFFL,TS_SENSE}; 8541918Swnj 8553244Swnj switch (cmd) { 8567633Ssam 8573244Swnj case MTIOCTOP: /* tape operation */ 8587633Ssam mtop = (struct mtop *)data; 8598575Sroot switch (mtop->mt_op) { 8607633Ssam 8613244Swnj case MTWEOF: 8627633Ssam callcount = mtop->mt_count; 8633244Swnj fcount = 1; 8643244Swnj break; 8657633Ssam 8663244Swnj case MTFSF: case MTBSF: 8673244Swnj case MTFSR: case MTBSR: 8683244Swnj callcount = 1; 8697633Ssam fcount = mtop->mt_count; 8703244Swnj break; 8717633Ssam 8723244Swnj case MTREW: case MTOFFL: case MTNOP: 8733244Swnj callcount = 1; 8743244Swnj fcount = 1; 8753244Swnj break; 8767633Ssam 8773244Swnj default: 8788575Sroot return (ENXIO); 8793244Swnj } 8808575Sroot if (callcount <= 0 || fcount <= 0) 8818575Sroot return (EINVAL); 8823244Swnj while (--callcount >= 0) { 8837633Ssam tscommand(dev, tsops[mtop->mt_op], fcount); 8847633Ssam if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) && 8858611Sroot bp->b_resid) 8868575Sroot return (EIO); 887*32579Sbostic if ((bp->b_flags&B_ERROR) || 888*32579Sbostic sc->sc_ts.t_sts.s_xs0&TS_BOT) 8893244Swnj break; 8903244Swnj } 8918649Sroot return (geterror(bp)); 8927633Ssam 8933244Swnj case MTIOCGET: 8947633Ssam mtget = (struct mtget *)data; 8957633Ssam mtget->mt_dsreg = 0; 896*32579Sbostic mtget->mt_erreg = sc->sc_ts.t_sts.s_xs0; 8977633Ssam mtget->mt_resid = sc->sc_resid; 8987633Ssam mtget->mt_type = MT_ISTS; 8998575Sroot break; 9007633Ssam 9013244Swnj default: 9028575Sroot return (ENXIO); 9033244Swnj } 9048575Sroot return (0); 9051918Swnj } 9061918Swnj 9073244Swnj #define DBSIZE 20 9083244Swnj 909*32579Sbostic tsdump(dev) 910*32579Sbostic dev_t dev; 9111918Swnj { 9123244Swnj register struct uba_device *ui; 913*32579Sbostic register struct uba_regs *uba; 9145693Sroot register struct tsdevice *addr; 915*32579Sbostic register int i; 916*32579Sbostic register struct pte *io; 917*32579Sbostic int blk, num, unit, reg, start; 918*32579Sbostic u_short db; 919*32579Sbostic struct ts_tsdata *tc, *tc_ubaddr; 9201918Swnj 921*32579Sbostic unit = TSUNIT(dev); 922*32579Sbostic if (unit >= NTS) 923*32579Sbostic return (ENXIO); 9243244Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 925*32579Sbostic ui = phys(tsdinfo[unit], struct uba_device *); 926*32579Sbostic if (ui->ui_alive == 0) 9273244Swnj return (ENXIO); 928*32579Sbostic uba = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 929*32579Sbostic ubainit(uba); 9305693Sroot addr = (struct tsdevice *)ui->ui_physaddr; 931*32579Sbostic 932*32579Sbostic /* map a ts_tsdata structure */ 933*32579Sbostic tc = phys(&ts_softc[0].sc_ts, struct ts_tsdata *); 934*32579Sbostic num = btoc(sizeof(struct ts_tsdata)) + 1; 935*32579Sbostic io = &uba->uba_map[reg = NUBMREG - num]; 936*32579Sbostic for (i = 0; i < num; i++) 937*32579Sbostic *(int *)io++ = UBAMR_MRV | (btop(tc) + i); 938*32579Sbostic i = (((int)tc & PGOFSET) | (reg << 9)); 939*32579Sbostic tc_ubaddr = (struct ts_tsdata *)i; 940*32579Sbostic db = i + ((i >> 16) & 3); 941*32579Sbostic 942*32579Sbostic /* init the drive */ 9433244Swnj addr->tssr = 0; 9443244Swnj tswait(addr); 945*32579Sbostic if ((addr->tssr & (TS_NBA|TS_OFL)) != TS_NBA) 946*32579Sbostic return (EFAULT); 947*32579Sbostic 948*32579Sbostic /* set characteristics */ 949*32579Sbostic i = (int)&tc_ubaddr->t_char; 950*32579Sbostic tc->t_cmd.c_loba = i; 951*32579Sbostic tc->t_cmd.c_hiba = (i >> 16) & 3; 952*32579Sbostic tc->t_cmd.c_size = sizeof(struct ts_char); 953*32579Sbostic tc->t_cmd.c_cmd = TS_ACK | TS_CVC | TS_SETCHR; 954*32579Sbostic tc->t_char.char_addr = (int)&tc_ubaddr->t_sts; 955*32579Sbostic tc->t_char.char_size = sizeof(struct ts_sts); 956*32579Sbostic tc->t_char.char_mode = TS_ESS; 957*32579Sbostic addr->tsdb = db; 958*32579Sbostic tswait(addr); 959*32579Sbostic if (addr->tssr & TS_NBA) 960*32579Sbostic return (ENXIO); 961*32579Sbostic 962*32579Sbostic /* dump */ 963*32579Sbostic tc->t_cmd.c_cmd = TS_ACK | TS_WCOM; 964*32579Sbostic tc->t_cmd.c_repcnt = 1; 965*32579Sbostic num = maxfree; 966*32579Sbostic for (start = 0, num = maxfree; num > 0; start += blk, num -= blk) { 9673244Swnj blk = num > DBSIZE ? DBSIZE : num; 968*32579Sbostic io = uba->uba_map; 969*32579Sbostic for (i = 0; i < blk; i++) 970*32579Sbostic *(int *)io++ = UBAMR_MRV | (1 << UBAMR_DPSHIFT) | 971*32579Sbostic (start + i); 972*32579Sbostic *(int *)io = 0; 973*32579Sbostic addr->tsdb = db; 974*32579Sbostic tswait(addr); 9753244Swnj } 976*32579Sbostic 977*32579Sbostic /* eof */ 978*32579Sbostic tc->t_cmd.c_cmd = TS_WEOF; 979*32579Sbostic addr->tsdb = db; 9803244Swnj tswait(addr); 981*32579Sbostic addr->tsdb = db; 982*32579Sbostic tswait(addr); 983*32579Sbostic 9843244Swnj if (addr->tssr&TS_SC) 9853244Swnj return (EIO); 9863244Swnj addr->tssr = 0; 9873244Swnj tswait(addr); 9883244Swnj return (0); 9891918Swnj } 9901918Swnj 9913244Swnj tswait(addr) 9925693Sroot register struct tsdevice *addr; 9931918Swnj { 9941918Swnj 995*32579Sbostic while ((addr->tssr & TS_SSR) == 0) 996*32579Sbostic /* void */; 9971918Swnj } 9981918Swnj 999*32579Sbostic #endif /* NTS > 0 */ 1000