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*37511Smckusick * @(#)ts.c 7.7 (Berkeley) 04/25/89 723349Smckusick */ 81900Swnj 91941Swnj #include "ts.h" 101900Swnj #if NTS > 0 111900Swnj /* 121900Swnj * TS11 tape driver 133244Swnj * 1432579Sbostic * NB: This driver takes advantage of the fact that there is only one 1532579Sbostic * drive per controller. 1632579Sbostic * 173244Swnj * TODO: 1832579Sbostic * 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 36*37511Smckusick #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 * Driver unibus interface routines and variables. 543244Swnj */ 553244Swnj int tsprobe(), tsslave(), tsattach(), tsdgo(), tsintr(); 563244Swnj struct uba_ctlr *tsminfo[NTS]; 573244Swnj struct uba_device *tsdinfo[NTS]; 585693Sroot struct buf tsutab[NTS]; 593244Swnj u_short tsstd[] = { 0772520, 0 }; 6032579Sbostic /* need all these even though controller == drive */ 613244Swnj struct uba_driver zsdriver = 6232579Sbostic { tsprobe, tsslave, tsattach, tsdgo, tsstd, "ts", tsdinfo, "zs", tsminfo }; 631900Swnj 643244Swnj /* bits in minor device */ 653244Swnj #define TSUNIT(dev) (minor(dev)&03) 663244Swnj #define T_NOREWIND 04 6732579Sbostic #define T_1600BPI 010 681900Swnj 693244Swnj #define INF (daddr_t)1000000L 701900Swnj 713244Swnj /* 723244Swnj * Software state per tape transport. 733244Swnj * Also contains hardware state in message packets. 743244Swnj * 753244Swnj * 1. A tape drive is a unique-open device; we refuse opens when it is already. 763244Swnj * 2. We keep track of the current position on a block tape and seek 773244Swnj * before operations by forward/back spacing if necessary. 783244Swnj * 3. We remember if the last operation was a write on a tape, so if a tape 793244Swnj * is open read write and the last thing done is a write we can 803244Swnj * write a standard end of tape mark (two eofs). 813244Swnj * 4. We remember the status registers after the last command, using 823244Swnj * then internally and returning them to the SENSE ioctl. 833244Swnj */ 8432579Sbostic struct ts_tsdata { /* data shared with ts11 controller */ 8532579Sbostic struct ts_cmd t_cmd; /* the command packet (must be first) */ 8632579Sbostic struct ts_sts t_sts; /* status packet, for returned status */ 8732579Sbostic struct ts_char t_char; /* characteristics packet */ 8832579Sbostic }; 893244Swnj struct ts_softc { 903244Swnj char sc_openf; /* lock against multiple opens */ 913244Swnj char sc_lastiow; /* last op was a write */ 923327Swnj short sc_resid; /* copy of last bc */ 933244Swnj daddr_t sc_blkno; /* block number, for block device tape */ 943244Swnj daddr_t sc_nxrec; /* position of end of tape, if known */ 9532579Sbostic struct ts_tsdata sc_ts;/* command and status packets */ 9632579Sbostic struct ts_tsdata *sc_ubaddr; /* Unibus address of tsdata structure */ 975697Sroot u_short sc_uba; /* Unibus addr of cmd pkt for tsdb */ 9832579Sbostic short sc_density; /* value |'ed into char_mode for TC13 density */ 9918322Sralph struct tty *sc_ttyp; /* record user's tty for errors */ 10030917Skarels int sc_blks; /* number of I/O operations since open */ 10130917Skarels int sc_softerrs; /* number of soft I/O errors since open */ 1023244Swnj } ts_softc[NTS]; 1031900Swnj 1043244Swnj /* 1053244Swnj * States for um->um_tab.b_active, the per controller state flag. 1063244Swnj * This is used to sequence control in the driver. 1073244Swnj */ 1083244Swnj #define SSEEK 1 /* seeking */ 1093244Swnj #define SIO 2 /* doing seq i/o */ 1103244Swnj #define SCOM 3 /* sending control command */ 1113244Swnj #define SREW 4 /* sending a drive rewind */ 1121900Swnj 1133244Swnj /* 1143244Swnj * Determine if there is a controller for 1153244Swnj * a ts at address reg. Our goal is to make the 1163244Swnj * device interrupt. 1173244Swnj */ 1183985Sroot /*ARGSUSED*/ 11932579Sbostic tsprobe(reg, ctlr, um) 1203244Swnj caddr_t reg; 12132579Sbostic int ctlr; 12232579Sbostic struct uba_ctlr *um; 1233244Swnj { 1243244Swnj register int br, cvec; /* must be r11,r10; value-result */ 12532579Sbostic register struct tsdevice *addr = (struct tsdevice *)reg; 12632579Sbostic register struct ts_softc *sc; 12732579Sbostic register int i; 12832579Sbostic int a; 1291900Swnj 1303244Swnj #ifdef lint 1313244Swnj br = 0; cvec = br; br = cvec; 1324937Swnj tsintr(0); 1333244Swnj #endif 13432579Sbostic addr->tssr = 0; /* initialize subsystem */ 1355693Sroot DELAY(100); 13632579Sbostic if ((addr->tssr & TS_NBA) == 0) 13732579Sbostic return (0); 13832579Sbostic 13932579Sbostic /* 14032579Sbostic * Make it interrupt. 14132579Sbostic * TS_SETCHR|TS_IE alone refuses to interrupt for me. 14232579Sbostic */ 14332579Sbostic sc = &ts_softc[ctlr]; 14432579Sbostic tsmap(sc, numuba, &a); 14532579Sbostic i = (int)&sc->sc_ubaddr->t_char; 14632579Sbostic sc->sc_ts.t_cmd.c_loba = i; 14732579Sbostic sc->sc_ts.t_cmd.c_hiba = (i >> 16) & 3; 14832579Sbostic sc->sc_ts.t_cmd.c_size = sizeof(struct ts_char); 14932579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_SETCHR; 15032579Sbostic sc->sc_ts.t_char.char_addr = (int)&sc->sc_ubaddr->t_sts; 15132579Sbostic sc->sc_ts.t_char.char_size = sizeof(struct ts_sts); 15232579Sbostic sc->sc_ts.t_char.char_mode = 0; /* mode is unimportant */ 15332579Sbostic addr->tsdb = sc->sc_uba; 15432579Sbostic DELAY(20000); 15532579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_IE | TS_SENSE; 15632579Sbostic sc->sc_ts.t_cmd.c_repcnt = 1; 15732579Sbostic addr->tsdb = sc->sc_uba; 15832579Sbostic DELAY(20000); 15932579Sbostic /* should have interrupted by now */ 16032579Sbostic 16132579Sbostic if (cvec == 0 || cvec == 0x200) /* no interrupt */ 16232579Sbostic ubarelse(numuba, &a); 16332579Sbostic 1647407Skre return (sizeof (struct tsdevice)); 1653244Swnj } 1661900Swnj 1673244Swnj /* 16832579Sbostic * Map in the command, status, and characteristics packet. We 16932579Sbostic * make them contiguous to keep overhead down. This also sets 17032579Sbostic * sc_uba (which then never changes). 17132579Sbostic */ 17232579Sbostic tsmap(sc, uban, a) 17332579Sbostic register struct ts_softc *sc; 17432579Sbostic int uban, *a; 17532579Sbostic { 17632579Sbostic register int i; 17732579Sbostic 17832579Sbostic i = uballoc(uban, (caddr_t)&sc->sc_ts, sizeof(sc->sc_ts), 0); 17932579Sbostic if (a != NULL) 18032579Sbostic *a = i; 18132579Sbostic i = UBAI_ADDR(i); 18232579Sbostic sc->sc_ubaddr = (struct ts_tsdata *)i; 18332579Sbostic /* 18432579Sbostic * Note that i == the Unibus address of the command packet, 18532579Sbostic * and that it is a multiple of 4 (guaranteed by the compiler). 18632579Sbostic */ 18732579Sbostic sc->sc_uba = i + ((i >> 16) & 3); 18832579Sbostic } 18932579Sbostic 19032579Sbostic /* 1913244Swnj * TS11 only supports one drive per controller; 1923244Swnj * check for ui_slave == 0. 1933244Swnj */ 1943244Swnj /*ARGSUSED*/ 1953244Swnj tsslave(ui, reg) 1963244Swnj struct uba_device *ui; 1973244Swnj caddr_t reg; 1983244Swnj { 1991900Swnj 20032579Sbostic return (ui->ui_slave == 0); /* non-zero slave not allowed */ 2013244Swnj } 2021900Swnj 2033244Swnj /* 2043244Swnj * Record attachment of the unit to the controller. 2053244Swnj */ 2063244Swnj /*ARGSUSED*/ 2073244Swnj tsattach(ui) 2083244Swnj struct uba_device *ui; 2093244Swnj { 2101900Swnj 21132579Sbostic /* void */ 2123244Swnj } 2131900Swnj 2143244Swnj /* 2153244Swnj * Open the device. Tapes are unique open 2163244Swnj * devices, so we refuse if it is already open. 2173244Swnj */ 2181900Swnj tsopen(dev, flag) 2193244Swnj dev_t dev; 2203244Swnj int flag; 2211900Swnj { 22232579Sbostic register int tsunit = TSUNIT(dev); 2233244Swnj register struct uba_device *ui; 2243244Swnj register struct ts_softc *sc; 2251900Swnj 22632579Sbostic if (tsunit >= NTS || (ui = tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) 2278575Sroot return (ENXIO); 22832579Sbostic if ((sc = &ts_softc[ui->ui_ctlr])->sc_openf) 22925054Skarels return (EBUSY); 23030917Skarels sc->sc_openf = 1; 23132579Sbostic sc->sc_density = (minor(dev) & T_1600BPI) ? TS_NRZI : 0; 23232579Sbostic tscommand(dev, TS_SENSE, 1); 23332579Sbostic if (ctsbuf[tsunit].b_flags & B_ERROR) 23432579Sbostic /* 23532579Sbostic * Try it again in case it went off-line 23632579Sbostic */ 23732579Sbostic tscommand(dev, TS_SENSE, 1); 23832579Sbostic if (tsinit(ui->ui_ctlr)) { 23930917Skarels sc->sc_openf = 0; 2408575Sroot return (ENXIO); 24130917Skarels } 24232579Sbostic if ((sc->sc_ts.t_sts.s_xs0&TS_ONL) == 0) { 24330917Skarels sc->sc_openf = 0; 2443711Sroot uprintf("ts%d: not online\n", tsunit); 2458575Sroot return (EIO); 2461900Swnj } 24732579Sbostic if ((flag&FWRITE) && (sc->sc_ts.t_sts.s_xs0&TS_WLK)) { 24830917Skarels sc->sc_openf = 0; 2493711Sroot uprintf("ts%d: no write ring\n", tsunit); 2508575Sroot return (EIO); 2513711Sroot } 2523244Swnj sc->sc_blkno = (daddr_t)0; 2533244Swnj sc->sc_nxrec = INF; 2543244Swnj sc->sc_lastiow = 0; 25530917Skarels sc->sc_blks = 0; 25630917Skarels sc->sc_softerrs = 0; 25718322Sralph sc->sc_ttyp = u.u_ttyp; 2588575Sroot return (0); 2591900Swnj } 2601900Swnj 2613244Swnj /* 2623244Swnj * Close tape device. 2633244Swnj * 2643244Swnj * If tape was open for writing or last operation was 2653244Swnj * a write, then write two EOF's and backspace over the last one. 2663244Swnj * Unless this is a non-rewinding special file, rewind the tape. 2673244Swnj * Make the tape available to others. 2683244Swnj */ 2691900Swnj tsclose(dev, flag) 2703244Swnj register dev_t dev; 27132579Sbostic register int flag; 2721900Swnj { 2733244Swnj register struct ts_softc *sc = &ts_softc[TSUNIT(dev)]; 2741900Swnj 2753244Swnj if (flag == FWRITE || (flag&FWRITE) && sc->sc_lastiow) { 2763244Swnj tscommand(dev, TS_WEOF, 1); 2773244Swnj tscommand(dev, TS_WEOF, 1); 2783244Swnj tscommand(dev, TS_SREV, 1); 2791900Swnj } 2803244Swnj if ((minor(dev)&T_NOREWIND) == 0) 2813244Swnj /* 2823244Swnj * 0 count means don't hang waiting for rewind complete 2833244Swnj * rather ctsbuf stays busy until the operation completes 2843244Swnj * preventing further opens from completing by 2853244Swnj * preventing a TS_SENSE from completing. 2863244Swnj */ 2873244Swnj tscommand(dev, TS_REW, 0); 28830917Skarels if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100) 28930917Skarels log(LOG_INFO, "ts%d: %d soft errors in %d blocks\n", 29030917Skarels TSUNIT(dev), sc->sc_softerrs, sc->sc_blks); 2913244Swnj sc->sc_openf = 0; 2921900Swnj } 2931900Swnj 2943244Swnj /* 29532579Sbostic * Initialize a TS11. Set device characteristics. 2963244Swnj */ 29732579Sbostic tsinit(ctlr) 29832579Sbostic register int ctlr; 2991900Swnj { 30032579Sbostic register struct ts_softc *sc = &ts_softc[ctlr]; 30132579Sbostic register struct uba_ctlr *um = tsminfo[ctlr]; 3025693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 3033244Swnj register int i; 3043244Swnj 30532579Sbostic if (addr->tssr & (TS_NBA|TS_OFL) || sc->sc_ts.t_sts.s_xs0 & TS_BOT) { 3063244Swnj addr->tssr = 0; /* subsystem initialize */ 3073244Swnj tswait(addr); 30832579Sbostic i = (int)&sc->sc_ubaddr->t_char; 30932579Sbostic sc->sc_ts.t_cmd.c_loba = i; 31032579Sbostic sc->sc_ts.t_cmd.c_hiba = (i >> 16) & 3; 31132579Sbostic sc->sc_ts.t_cmd.c_size = sizeof(struct ts_char); 31232579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_SETCHR; 31332579Sbostic sc->sc_ts.t_char.char_addr = (int)&sc->sc_ubaddr->t_sts; 31432579Sbostic sc->sc_ts.t_char.char_size = sizeof(struct ts_sts); 31532579Sbostic sc->sc_ts.t_char.char_mode = TS_ESS | TS_EAI | TS_ERI | 31632579Sbostic /* TS_ENB | */ sc->sc_density; 3173244Swnj addr->tsdb = sc->sc_uba; 3183244Swnj tswait(addr); 3193327Swnj if (addr->tssr & TS_NBA) 3203327Swnj return(1); 3213244Swnj } 3223244Swnj return(0); 3233244Swnj } 3243244Swnj 3253244Swnj /* 3263244Swnj * Execute a command on the tape drive 3273244Swnj * a specified number of times. 3283244Swnj */ 3293244Swnj tscommand(dev, com, count) 3303244Swnj dev_t dev; 3313244Swnj int com, count; 3323244Swnj { 3331900Swnj register struct buf *bp; 3345438Sroot register int s; 33532579Sbostic int didsleep = 0; 3361900Swnj 3373244Swnj bp = &ctsbuf[TSUNIT(dev)]; 3385438Sroot s = spl5(); 3393244Swnj while (bp->b_flags&B_BUSY) { 3403244Swnj /* 3413244Swnj * This special check is because B_BUSY never 3423244Swnj * gets cleared in the non-waiting rewind case. 3433244Swnj */ 3443244Swnj if (bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 3453244Swnj break; 3461900Swnj bp->b_flags |= B_WANTED; 3471900Swnj sleep((caddr_t)bp, PRIBIO); 34832579Sbostic didsleep = 1; 3491900Swnj } 3503244Swnj bp->b_flags = B_BUSY|B_READ; 3515438Sroot splx(s); 35232579Sbostic if (didsleep) 35332579Sbostic (void) tsinit(tsdinfo[TSUNIT(dev)]->ui_ctlr); 3543244Swnj bp->b_dev = dev; 3553244Swnj bp->b_repcnt = count; 3563244Swnj bp->b_command = com; 3571900Swnj bp->b_blkno = 0; 3581900Swnj tsstrategy(bp); 3593244Swnj /* 3603244Swnj * In case of rewind from close, don't wait. 3613244Swnj * This is the only case where count can be 0. 3623244Swnj */ 3633244Swnj if (count == 0) 3643244Swnj return; 36532579Sbostic biowait(bp); 3663244Swnj if (bp->b_flags&B_WANTED) 3671900Swnj wakeup((caddr_t)bp); 3683244Swnj bp->b_flags &= B_ERROR; 3691900Swnj } 3701900Swnj 3713244Swnj /* 3723244Swnj * Queue a tape operation. 3733244Swnj */ 3741900Swnj tsstrategy(bp) 3753244Swnj register struct buf *bp; 3761900Swnj { 37732579Sbostic register int tsunit = TSUNIT(bp->b_dev); 3783244Swnj register struct uba_ctlr *um; 3793327Swnj register struct buf *dp; 38032579Sbostic int s; 3811900Swnj 3823244Swnj /* 3833244Swnj * Put transfer at end of controller queue 3843244Swnj */ 3851900Swnj bp->av_forw = NULL; 3863244Swnj um = tsdinfo[tsunit]->ui_mi; 38732579Sbostic dp = &tsutab[tsunit]; 3885438Sroot s = spl5(); 3893327Swnj if (dp->b_actf == NULL) 3903327Swnj dp->b_actf = bp; 3911900Swnj else 3923327Swnj dp->b_actl->av_forw = bp; 3933327Swnj dp->b_actl = bp; 3943327Swnj um->um_tab.b_actf = um->um_tab.b_actl = dp; 3953244Swnj /* 3963244Swnj * If the controller is not busy, get 3973244Swnj * it going. 3983244Swnj */ 3993244Swnj if (um->um_tab.b_active == 0) 4003244Swnj tsstart(um); 4015438Sroot splx(s); 4021900Swnj } 4031900Swnj 4043244Swnj /* 4053244Swnj * Start activity on a ts controller. 4063244Swnj */ 4073244Swnj tsstart(um) 4083244Swnj register struct uba_ctlr *um; 4091900Swnj { 4101900Swnj register struct buf *bp; 4115693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 4123244Swnj register struct ts_softc *sc; 4133244Swnj register struct uba_device *ui; 41432579Sbostic register int tsunit; 41532579Sbostic int cmd; 4161900Swnj daddr_t blkno; 4171900Swnj 4183244Swnj /* 4193244Swnj * Start the controller if there is something for it to do. 4203244Swnj */ 4213244Swnj loop: 42232609Sbostic if ((bp = um->um_tab.b_actf->b_actf) == NULL) { 42332609Sbostic um->um_tab.b_active = 0; 4241900Swnj return; 42532609Sbostic } 4263244Swnj tsunit = TSUNIT(bp->b_dev); 4273244Swnj ui = tsdinfo[tsunit]; 4283244Swnj sc = &ts_softc[tsunit]; 4293244Swnj /* 4303244Swnj * Default is that last command was NOT a write command; 43132579Sbostic * if we finish a write command we will notice this in tsintr(). 4323244Swnj */ 4333656Swnj sc->sc_lastiow = 0; 4343244Swnj if (sc->sc_openf < 0 || (addr->tssr&TS_OFL)) { 4353244Swnj /* 4363244Swnj * Have had a hard error on a non-raw tape 4373244Swnj * or the tape unit is now unavailable 4383244Swnj * (e.g. taken off line). 4393244Swnj */ 4403244Swnj bp->b_flags |= B_ERROR; 4413244Swnj goto next; 4423244Swnj } 44332579Sbostic if (bp == &ctsbuf[tsunit]) { 4443244Swnj /* 4453244Swnj * Execute control operation with the specified count. 4463244Swnj */ 4473244Swnj um->um_tab.b_active = 4483244Swnj bp->b_command == TS_REW ? SREW : SCOM; 44932579Sbostic sc->sc_ts.t_cmd.c_repcnt = bp->b_repcnt; 4503244Swnj goto dobpcmd; 4513244Swnj } 4523244Swnj /* 45332579Sbostic * For raw I/O, save the current block 45432579Sbostic * number in case we have to retry. 4553244Swnj */ 45634217Sbostic if (bp->b_flags & B_RAW) { 45732579Sbostic if (um->um_tab.b_errcnt == 0) 45832579Sbostic sc->sc_blkno = bdbtofsb(bp->b_blkno); 45932579Sbostic } else { 4603244Swnj /* 46132579Sbostic * Handle boundary cases for operation 46232579Sbostic * on non-raw tapes. 4633244Swnj */ 46432579Sbostic if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 46532579Sbostic /* 46632579Sbostic * Can't read past known end-of-file. 46732579Sbostic */ 46832579Sbostic bp->b_flags |= B_ERROR; 46932579Sbostic bp->b_error = ENXIO; 47032579Sbostic goto next; 47132579Sbostic } 47232579Sbostic if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && 47332579Sbostic bp->b_flags&B_READ) { 47432579Sbostic /* 47532579Sbostic * Reading at end of file returns 0 bytes. 47632579Sbostic */ 47732579Sbostic bp->b_resid = bp->b_bcount; 47832579Sbostic clrbuf(bp); 47932579Sbostic goto next; 48032579Sbostic } 48132579Sbostic if ((bp->b_flags&B_READ) == 0) 48232579Sbostic /* 48332579Sbostic * Writing sets EOF 48432579Sbostic */ 48532579Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; 4863244Swnj } 48732579Sbostic 4883244Swnj /* 4893244Swnj * If the data transfer command is in the correct place, 4903244Swnj * set up all the registers except the csr, and give 4913244Swnj * control over to the UNIBUS adapter routines, to 4923244Swnj * wait for resources to start the i/o. 4933244Swnj */ 4947383Ssam if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { 49532579Sbostic sc->sc_ts.t_cmd.c_size = bp->b_bcount; 4963244Swnj if ((bp->b_flags&B_READ) == 0) 4973244Swnj cmd = TS_WCOM; 4981900Swnj else 4993244Swnj cmd = TS_RCOM; 5003244Swnj if (um->um_tab.b_errcnt) 5013244Swnj cmd |= TS_RETRY; 5023244Swnj um->um_tab.b_active = SIO; 50332579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_IE | cmd; 5043244Swnj (void) ubago(ui); 5053244Swnj return; 5063244Swnj } 5073244Swnj /* 5083244Swnj * Tape positioned incorrectly; 5093244Swnj * set to seek forwards or backwards to the correct spot. 5103244Swnj * This happens for raw tapes only on error retries. 5113244Swnj */ 5123244Swnj um->um_tab.b_active = SSEEK; 5137383Ssam if (blkno < bdbtofsb(bp->b_blkno)) { 5143244Swnj bp->b_command = TS_SFORW; 51532579Sbostic sc->sc_ts.t_cmd.c_repcnt = bdbtofsb(bp->b_blkno) - blkno; 5161900Swnj } else { 5173244Swnj bp->b_command = TS_SREV; 51832579Sbostic sc->sc_ts.t_cmd.c_repcnt = blkno - bdbtofsb(bp->b_blkno); 5191900Swnj } 5203244Swnj dobpcmd: 5213244Swnj /* 5223244Swnj * Do the command in bp. 5233244Swnj */ 52432579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_IE | bp->b_command; 5253244Swnj addr->tsdb = sc->sc_uba; 5261900Swnj return; 5271900Swnj 5283244Swnj next: 5293244Swnj /* 5303244Swnj * Done with this operation due to error or 5313244Swnj * the fact that it doesn't do anything. 5323244Swnj * Release UBA resources (if any), dequeue 5333244Swnj * the transfer and continue processing this slave. 5343244Swnj */ 5353244Swnj if (um->um_ubinfo) 5363244Swnj ubadone(um); 5373244Swnj um->um_tab.b_errcnt = 0; 5383327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 53932579Sbostic biodone(bp); 5401900Swnj goto loop; 5411900Swnj } 5421900Swnj 5433244Swnj /* 5443244Swnj * The UNIBUS resources we needed have been 5453244Swnj * allocated to us; start the device. 5463244Swnj */ 5473244Swnj tsdgo(um) 5483244Swnj register struct uba_ctlr *um; 5491900Swnj { 5503244Swnj register struct ts_softc *sc = &ts_softc[um->um_ctlr]; 5513327Swnj register int i; 5523244Swnj 55326139Skarels /* 55426139Skarels * The uba code uses byte-offset mode if using bdp; 55526139Skarels * mask off the low bit here. 55626139Skarels */ 55732579Sbostic i = UBAI_ADDR(um->um_ubinfo); 55826139Skarels if (UBAI_BDP(um->um_ubinfo)) 55926139Skarels i &= ~1; 56032579Sbostic sc->sc_ts.t_cmd.c_loba = i; 56132579Sbostic sc->sc_ts.t_cmd.c_hiba = (i >> 16) & 3; 56232579Sbostic ((struct tsdevice *)um->um_addr)->tsdb = sc->sc_uba; 5633244Swnj } 5643244Swnj 5653244Swnj /* 5663244Swnj * Ts interrupt routine. 5673244Swnj */ 5683244Swnj /*ARGSUSED*/ 56932579Sbostic tsintr(tsunit) 57032579Sbostic register int tsunit; 5713244Swnj { 5721900Swnj register struct buf *bp; 57332579Sbostic register struct uba_ctlr *um; 5745693Sroot register struct tsdevice *addr; 5753244Swnj register struct ts_softc *sc; 57632579Sbostic register int state; 57732579Sbostic 57835401Stef #ifdef QBA 57932579Sbostic (void) spl5(); 58027253Skridle #endif 58132579Sbostic um = tsdinfo[tsunit]->ui_mi; 5823327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 5831900Swnj return; 58432579Sbostic addr = (struct tsdevice *)um->um_addr; 5853244Swnj /* 5863244Swnj * If last command was a rewind, and tape is still 5873244Swnj * rewinding, wait for the rewind complete interrupt. 5883244Swnj * 5893244Swnj * SHOULD NEVER GET AN INTERRUPT IN THIS STATE. 5903244Swnj */ 5913244Swnj if (um->um_tab.b_active == SREW) { 5923244Swnj um->um_tab.b_active = SCOM; 5933244Swnj if ((addr->tssr&TS_SSR) == 0) 5943244Swnj return; 5953244Swnj } 5963244Swnj /* 5973244Swnj * An operation completed... record status 5983244Swnj */ 59932579Sbostic sc = &ts_softc[um->um_ctlr]; 6003244Swnj if ((bp->b_flags & B_READ) == 0) 6013244Swnj sc->sc_lastiow = 1; 6023244Swnj state = um->um_tab.b_active; 6033244Swnj /* 6043244Swnj * Check for errors. 6053244Swnj */ 6063244Swnj if (addr->tssr&TS_SC) { 6073244Swnj switch (addr->tssr & TS_TC) { 6083244Swnj case TS_UNREC: /* unrecoverable */ 6093244Swnj case TS_FATAL: /* fatal error */ 6103244Swnj case TS_RECNM: /* recoverable, no motion */ 6113244Swnj break; 61232579Sbostic case TS_ATTN: /* attention */ 61332579Sbostic if (sc->sc_ts.t_sts.s_xs0 & TS_VCK) { 61432579Sbostic /* volume check - may have changed tapes */ 61532579Sbostic bp->b_flags |= B_ERROR; 61632579Sbostic goto ignoreerr; 61732579Sbostic } 61832579Sbostic break; 6191900Swnj 6203244Swnj case TS_SUCC: /* success termination */ 62132579Sbostic printf("ts%d: success\n", tsunit); 6223244Swnj goto ignoreerr; 6231900Swnj 6243244Swnj case TS_ALERT: /* tape status alert */ 6253244Swnj /* 6263244Swnj * If we hit the end of the tape file, 6273244Swnj * update our position. 6283244Swnj */ 62932579Sbostic if (sc->sc_ts.t_sts.s_xs0 & (TS_TMK|TS_EOT)) { 63032579Sbostic tsseteof(bp); /* set blkno and nxrec */ 63132579Sbostic state = SCOM; /* force completion */ 6323244Swnj /* 6333244Swnj * Stuff bc so it will be unstuffed correctly 6343244Swnj * later to get resid. 6353244Swnj */ 63632579Sbostic sc->sc_ts.t_sts.s_rbpcr = bp->b_bcount; 6373244Swnj goto opdone; 6383244Swnj } 6393244Swnj /* 64032579Sbostic * If we were reading raw tape and the record was too 64132579Sbostic * long or too short, we don't consider this an error. 6423244Swnj */ 64334217Sbostic if ((bp->b_flags & (B_READ|B_RAW)) == (B_READ|B_RAW) && 64432579Sbostic sc->sc_ts.t_sts.s_xs0&(TS_RLS|TS_RLL)) 6453244Swnj goto ignoreerr; 64632579Sbostic /* FALLTHROUGH */ 64732579Sbostic 6483244Swnj case TS_RECOV: /* recoverable, tape moved */ 6493244Swnj /* 6503244Swnj * If this was an i/o operation retry up to 8 times. 6513244Swnj */ 65232579Sbostic if (state == SIO) { 6533244Swnj if (++um->um_tab.b_errcnt < 7) { 6543244Swnj ubadone(um); 6553244Swnj goto opcont; 6563244Swnj } else 6573244Swnj sc->sc_blkno++; 6583244Swnj } else { 6593244Swnj /* 6603244Swnj * Non-i/o errors on non-raw tape 6613244Swnj * cause it to close. 6623244Swnj */ 66334217Sbostic if ((bp->b_flags&B_RAW) == 0 && 66434217Sbostic sc->sc_openf > 0) 6653244Swnj sc->sc_openf = -1; 6663244Swnj } 6671900Swnj break; 6683244Swnj 6693244Swnj case TS_REJECT: /* function reject */ 67032579Sbostic if (state == SIO && sc->sc_ts.t_sts.s_xs0 & TS_WLE) 67118322Sralph tprintf(sc->sc_ttyp, "ts%d: write locked\n", 67232579Sbostic tsunit); 67332579Sbostic if ((sc->sc_ts.t_sts.s_xs0 & TS_ONL) == 0) 67418322Sralph tprintf(sc->sc_ttyp, "ts%d: offline\n", 67532579Sbostic tsunit); 6761900Swnj break; 6771900Swnj } 6783244Swnj /* 6793244Swnj * Couldn't recover error 6803244Swnj */ 68132579Sbostic tprintf(sc->sc_ttyp, "ts%d: hard error bn%d tssr=%b xs0=%b", 68232579Sbostic tsunit, bp->b_blkno, addr->tssr, TSSR_BITS, 68332579Sbostic sc->sc_ts.t_sts.s_xs0, TSXS0_BITS); 68432579Sbostic if (sc->sc_ts.t_sts.s_xs1) 68532579Sbostic tprintf(sc->sc_ttyp, " xs1=%b", sc->sc_ts.t_sts.s_xs1, 68618322Sralph TSXS1_BITS); 68732579Sbostic if (sc->sc_ts.t_sts.s_xs2) 68832579Sbostic tprintf(sc->sc_ttyp, " xs2=%b", sc->sc_ts.t_sts.s_xs2, 68918322Sralph TSXS2_BITS); 69032579Sbostic if (sc->sc_ts.t_sts.s_xs3) 69132579Sbostic tprintf(sc->sc_ttyp, " xs3=%b", sc->sc_ts.t_sts.s_xs3, 69218322Sralph TSXS3_BITS); 69318322Sralph tprintf(sc->sc_ttyp, "\n"); 6943244Swnj bp->b_flags |= B_ERROR; 6953244Swnj goto opdone; 6963244Swnj } 6973244Swnj /* 6983244Swnj * Advance tape control FSM. 6993244Swnj */ 7003244Swnj ignoreerr: 7013244Swnj switch (state) { 7021900Swnj 7033244Swnj case SIO: 7043244Swnj /* 7053244Swnj * Read/write increments tape block number 7063244Swnj */ 7073244Swnj sc->sc_blkno++; 70830917Skarels sc->sc_blks++; 70930917Skarels if (um->um_tab.b_errcnt) 71030917Skarels sc->sc_softerrs++; 7113244Swnj goto opdone; 7121900Swnj 7131900Swnj case SCOM: 7143244Swnj /* 7153244Swnj * For forward/backward space record update current position. 7163244Swnj */ 71732579Sbostic if (bp == &ctsbuf[tsunit]) 71832579Sbostic switch ((int)bp->b_command) { 7191900Swnj 72032579Sbostic case TS_SFORW: 72132579Sbostic sc->sc_blkno += bp->b_repcnt; 72232579Sbostic break; 7231900Swnj 72432579Sbostic case TS_SREV: 72532579Sbostic sc->sc_blkno -= bp->b_repcnt; 72632579Sbostic break; 72732579Sbostic } 7283244Swnj goto opdone; 7293244Swnj 7303244Swnj case SSEEK: 7317383Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno); 7323244Swnj goto opcont; 7333244Swnj 7341900Swnj default: 7353244Swnj panic("tsintr"); 7361900Swnj } 7373244Swnj opdone: 7383244Swnj /* 7393244Swnj * Reset error count and remove 7403244Swnj * from device queue. 7413244Swnj */ 7423244Swnj um->um_tab.b_errcnt = 0; 7433327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 74432579Sbostic bp->b_resid = sc->sc_ts.t_sts.s_rbpcr; 7453244Swnj ubadone(um); 74632579Sbostic biodone(bp); 74732579Sbostic if (um->um_tab.b_actf->b_actf == 0) { 74832579Sbostic um->um_tab.b_active = 0; 7493244Swnj return; 75032579Sbostic } 7513244Swnj opcont: 7523244Swnj tsstart(um); 7533244Swnj } 7543244Swnj 7553244Swnj tsseteof(bp) 7563244Swnj register struct buf *bp; 7573244Swnj { 7583244Swnj register int tsunit = TSUNIT(bp->b_dev); 75932579Sbostic register struct ts_softc *sc = &ts_softc[tsdinfo[tsunit]->ui_ctlr]; 7603244Swnj 76132579Sbostic if (bp == &ctsbuf[tsunit]) { 7627383Ssam if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 7633244Swnj /* reversing */ 76432579Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) - 76532579Sbostic sc->sc_ts.t_sts.s_rbpcr; 7663244Swnj sc->sc_blkno = sc->sc_nxrec; 7673244Swnj } else { 7683244Swnj /* spacing forward */ 76932579Sbostic sc->sc_blkno = bdbtofsb(bp->b_blkno) + 77032579Sbostic sc->sc_ts.t_sts.s_rbpcr; 7713244Swnj sc->sc_nxrec = sc->sc_blkno - 1; 7721900Swnj } 7733244Swnj return; 7743244Swnj } 7753244Swnj /* eof on read */ 7767383Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno); 7771900Swnj } 7781900Swnj 7793244Swnj tsreset(uban) 7803244Swnj int uban; 7811918Swnj { 7823244Swnj register struct uba_ctlr *um; 7835693Sroot register struct uba_device *ui; 78432579Sbostic register int ts11, i; 7851918Swnj 7863244Swnj for (ts11 = 0; ts11 < NTS; ts11++) { 7873244Swnj if ((um = tsminfo[ts11]) == 0 || um->um_alive == 0 || 78832579Sbostic um->um_ubanum != uban) 7893244Swnj continue; 7903244Swnj printf(" ts%d", ts11); 7913244Swnj um->um_tab.b_active = 0; 7923244Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7935693Sroot if (ts_softc[ts11].sc_openf > 0) 7945693Sroot ts_softc[ts11].sc_openf = -1; 7953244Swnj if (um->um_ubinfo) { 79632579Sbostic printf("<%d>", UBAI_BDP(um->um_ubinfo)); 7979356Ssam um->um_ubinfo = 0; 7983244Swnj } 79932579Sbostic /* 80032579Sbostic * tsdinfo should be 1-to-1 with tsminfo, but someone 80132579Sbostic * might have screwed up the config file: 80232579Sbostic */ 80332579Sbostic for (i = 0; i < NTS; i++) { 80432579Sbostic if ((ui = tsdinfo[i]) != NULL && 80532579Sbostic ui->ui_alive && ui->ui_mi == um) { 80632579Sbostic um->um_tab.b_actf = um->um_tab.b_actl = 80732579Sbostic &tsutab[i]; 80832579Sbostic break; 80932579Sbostic } 8105693Sroot } 81132579Sbostic tsmap(&ts_softc[ts11], uban, (int *)NULL); 8123989Sroot (void) tsinit(ts11); 8133244Swnj tsstart(um); 8141918Swnj } 8151918Swnj } 8161918Swnj 8173244Swnj /*ARGSUSED*/ 8187633Ssam tsioctl(dev, cmd, data, flag) 8197633Ssam caddr_t data; 8203244Swnj dev_t dev; 8211918Swnj { 8223244Swnj int tsunit = TSUNIT(dev); 82332579Sbostic register struct ts_softc *sc = &ts_softc[tsdinfo[tsunit]->ui_ctlr]; 8243244Swnj register struct buf *bp = &ctsbuf[TSUNIT(dev)]; 82532579Sbostic register int callcount; 8263244Swnj int fcount; 8277633Ssam struct mtop *mtop; 8287633Ssam struct mtget *mtget; 8293244Swnj /* we depend of the values and order of the MT codes here */ 83032579Sbostic static int tsops[] = 8313656Swnj {TS_WEOF,TS_SFORWF,TS_SREVF,TS_SFORW,TS_SREV,TS_REW,TS_OFFL,TS_SENSE}; 8321918Swnj 8333244Swnj switch (cmd) { 8347633Ssam 8353244Swnj case MTIOCTOP: /* tape operation */ 8367633Ssam mtop = (struct mtop *)data; 8378575Sroot switch (mtop->mt_op) { 8387633Ssam 8393244Swnj case MTWEOF: 8407633Ssam callcount = mtop->mt_count; 8413244Swnj fcount = 1; 8423244Swnj break; 8437633Ssam 8443244Swnj case MTFSF: case MTBSF: 8453244Swnj case MTFSR: case MTBSR: 8463244Swnj callcount = 1; 8477633Ssam fcount = mtop->mt_count; 8483244Swnj break; 8497633Ssam 8503244Swnj case MTREW: case MTOFFL: case MTNOP: 8513244Swnj callcount = 1; 8523244Swnj fcount = 1; 8533244Swnj break; 8547633Ssam 8553244Swnj default: 8568575Sroot return (ENXIO); 8573244Swnj } 8588575Sroot if (callcount <= 0 || fcount <= 0) 8598575Sroot return (EINVAL); 8603244Swnj while (--callcount >= 0) { 8617633Ssam tscommand(dev, tsops[mtop->mt_op], fcount); 8627633Ssam if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) && 8638611Sroot bp->b_resid) 8648575Sroot return (EIO); 86532579Sbostic if ((bp->b_flags&B_ERROR) || 86632579Sbostic sc->sc_ts.t_sts.s_xs0&TS_BOT) 8673244Swnj break; 8683244Swnj } 8698649Sroot return (geterror(bp)); 8707633Ssam 8713244Swnj case MTIOCGET: 8727633Ssam mtget = (struct mtget *)data; 8737633Ssam mtget->mt_dsreg = 0; 87432579Sbostic mtget->mt_erreg = sc->sc_ts.t_sts.s_xs0; 8757633Ssam mtget->mt_resid = sc->sc_resid; 8767633Ssam mtget->mt_type = MT_ISTS; 8778575Sroot break; 8787633Ssam 8793244Swnj default: 8808575Sroot return (ENXIO); 8813244Swnj } 8828575Sroot return (0); 8831918Swnj } 8841918Swnj 8853244Swnj #define DBSIZE 20 8863244Swnj 88732579Sbostic tsdump(dev) 88832579Sbostic dev_t dev; 8891918Swnj { 8903244Swnj register struct uba_device *ui; 89132579Sbostic register struct uba_regs *uba; 8925693Sroot register struct tsdevice *addr; 89332579Sbostic register int i; 89432579Sbostic register struct pte *io; 89532579Sbostic int blk, num, unit, reg, start; 89632579Sbostic u_short db; 89732579Sbostic struct ts_tsdata *tc, *tc_ubaddr; 8981918Swnj 89932579Sbostic unit = TSUNIT(dev); 90032579Sbostic if (unit >= NTS) 90132579Sbostic return (ENXIO); 9023244Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 90332579Sbostic ui = phys(tsdinfo[unit], struct uba_device *); 90432579Sbostic if (ui->ui_alive == 0) 9053244Swnj return (ENXIO); 90632579Sbostic uba = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 90732579Sbostic ubainit(uba); 9085693Sroot addr = (struct tsdevice *)ui->ui_physaddr; 90932579Sbostic 91032579Sbostic /* map a ts_tsdata structure */ 91132579Sbostic tc = phys(&ts_softc[0].sc_ts, struct ts_tsdata *); 91232579Sbostic num = btoc(sizeof(struct ts_tsdata)) + 1; 91332579Sbostic io = &uba->uba_map[reg = NUBMREG - num]; 91432579Sbostic for (i = 0; i < num; i++) 91532579Sbostic *(int *)io++ = UBAMR_MRV | (btop(tc) + i); 91632579Sbostic i = (((int)tc & PGOFSET) | (reg << 9)); 91732579Sbostic tc_ubaddr = (struct ts_tsdata *)i; 91832579Sbostic db = i + ((i >> 16) & 3); 91932579Sbostic 92032579Sbostic /* init the drive */ 9213244Swnj addr->tssr = 0; 9223244Swnj tswait(addr); 92332579Sbostic if ((addr->tssr & (TS_NBA|TS_OFL)) != TS_NBA) 92432579Sbostic return (EFAULT); 92532579Sbostic 92632579Sbostic /* set characteristics */ 92732579Sbostic i = (int)&tc_ubaddr->t_char; 92832579Sbostic tc->t_cmd.c_loba = i; 92932579Sbostic tc->t_cmd.c_hiba = (i >> 16) & 3; 93032579Sbostic tc->t_cmd.c_size = sizeof(struct ts_char); 93132579Sbostic tc->t_cmd.c_cmd = TS_ACK | TS_CVC | TS_SETCHR; 93232579Sbostic tc->t_char.char_addr = (int)&tc_ubaddr->t_sts; 93332579Sbostic tc->t_char.char_size = sizeof(struct ts_sts); 93432579Sbostic tc->t_char.char_mode = TS_ESS; 93532579Sbostic addr->tsdb = db; 93632579Sbostic tswait(addr); 93732579Sbostic if (addr->tssr & TS_NBA) 93832579Sbostic return (ENXIO); 93932579Sbostic 94032579Sbostic /* dump */ 94132579Sbostic tc->t_cmd.c_cmd = TS_ACK | TS_WCOM; 94232579Sbostic tc->t_cmd.c_repcnt = 1; 94332579Sbostic num = maxfree; 94432579Sbostic for (start = 0, num = maxfree; num > 0; start += blk, num -= blk) { 9453244Swnj blk = num > DBSIZE ? DBSIZE : num; 94632579Sbostic io = uba->uba_map; 94732579Sbostic for (i = 0; i < blk; i++) 94832579Sbostic *(int *)io++ = UBAMR_MRV | (1 << UBAMR_DPSHIFT) | 94932579Sbostic (start + i); 95032579Sbostic *(int *)io = 0; 95132579Sbostic addr->tsdb = db; 95232579Sbostic tswait(addr); 9533244Swnj } 95432579Sbostic 95532579Sbostic /* eof */ 95632579Sbostic tc->t_cmd.c_cmd = TS_WEOF; 95732579Sbostic addr->tsdb = db; 9583244Swnj tswait(addr); 95932579Sbostic addr->tsdb = db; 96032579Sbostic tswait(addr); 96132579Sbostic 9623244Swnj if (addr->tssr&TS_SC) 9633244Swnj return (EIO); 9643244Swnj addr->tssr = 0; 9653244Swnj tswait(addr); 9663244Swnj return (0); 9671918Swnj } 9681918Swnj 9693244Swnj tswait(addr) 9705693Sroot register struct tsdevice *addr; 9711918Swnj { 9721918Swnj 97332579Sbostic while ((addr->tssr & TS_SSR) == 0) 97432579Sbostic /* void */; 9751918Swnj } 9761918Swnj 97732579Sbostic #endif /* NTS > 0 */ 978