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*45808Sbostic * @(#)ts.c 7.14 (Berkeley) 12/16/90 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 */ 20*45808Sbostic #include "sys/param.h" 21*45808Sbostic #include "sys/systm.h" 22*45808Sbostic #include "sys/buf.h" 23*45808Sbostic #include "sys/conf.h" 24*45808Sbostic #include "sys/errno.h" 25*45808Sbostic #include "sys/file.h" 26*45808Sbostic #include "sys/map.h" 27*45808Sbostic #include "sys/vm.h" 28*45808Sbostic #include "sys/ioctl.h" 29*45808Sbostic #include "sys/mtio.h" 30*45808Sbostic #include "sys/cmap.h" 31*45808Sbostic #include "sys/uio.h" 32*45808Sbostic #include "sys/syslog.h" 33*45808Sbostic #include "sys/tprintf.h" 341900Swnj 35*45808Sbostic #include "../include/pte.h" 36*45808Sbostic #include "../include/cpu.h" 3717080Sbloom #include "ubareg.h" 3817080Sbloom #include "ubavar.h" 3917080Sbloom #include "tsreg.h" 401900Swnj 413244Swnj /* 423244Swnj * There is a ctsbuf per tape controller. 433244Swnj * It is used as the token to pass to the internal routines 443244Swnj * to execute tape ioctls. 453244Swnj * In particular, when the tape is rewinding on close we release 463244Swnj * the user process but any further attempts to use the tape drive 473244Swnj * before the rewind completes will hang waiting for ctsbuf. 483244Swnj */ 493244Swnj struct buf ctsbuf[NTS]; 501900Swnj 513244Swnj /* 523244Swnj * Driver unibus interface routines and variables. 533244Swnj */ 543244Swnj int tsprobe(), tsslave(), tsattach(), tsdgo(), tsintr(); 553244Swnj struct uba_ctlr *tsminfo[NTS]; 563244Swnj struct uba_device *tsdinfo[NTS]; 575693Sroot struct buf tsutab[NTS]; 583244Swnj u_short tsstd[] = { 0772520, 0 }; 5932579Sbostic /* need all these even though controller == drive */ 603244Swnj struct uba_driver zsdriver = 6132579Sbostic { tsprobe, tsslave, tsattach, tsdgo, tsstd, "ts", tsdinfo, "zs", tsminfo }; 621900Swnj 633244Swnj /* bits in minor device */ 643244Swnj #define TSUNIT(dev) (minor(dev)&03) 653244Swnj #define T_NOREWIND 04 6632579Sbostic #define T_1600BPI 010 671900Swnj 683244Swnj #define INF (daddr_t)1000000L 691900Swnj 703244Swnj /* 713244Swnj * Software state per tape transport. 723244Swnj * Also contains hardware state in message packets. 733244Swnj * 743244Swnj * 1. A tape drive is a unique-open device; we refuse opens when it is already. 753244Swnj * 2. We keep track of the current position on a block tape and seek 763244Swnj * before operations by forward/back spacing if necessary. 773244Swnj * 3. We remember if the last operation was a write on a tape, so if a tape 783244Swnj * is open read write and the last thing done is a write we can 793244Swnj * write a standard end of tape mark (two eofs). 803244Swnj * 4. We remember the status registers after the last command, using 813244Swnj * then internally and returning them to the SENSE ioctl. 823244Swnj */ 8332579Sbostic struct ts_tsdata { /* data shared with ts11 controller */ 8432579Sbostic struct ts_cmd t_cmd; /* the command packet (must be first) */ 8532579Sbostic struct ts_sts t_sts; /* status packet, for returned status */ 8632579Sbostic struct ts_char t_char; /* characteristics packet */ 8732579Sbostic }; 883244Swnj struct ts_softc { 893244Swnj char sc_openf; /* lock against multiple opens */ 903244Swnj char sc_lastiow; /* last op was a write */ 913327Swnj short sc_resid; /* copy of last bc */ 923244Swnj daddr_t sc_blkno; /* block number, for block device tape */ 933244Swnj daddr_t sc_nxrec; /* position of end of tape, if known */ 9432579Sbostic struct ts_tsdata sc_ts;/* command and status packets */ 9532579Sbostic struct ts_tsdata *sc_ubaddr; /* Unibus address of tsdata structure */ 965697Sroot u_short sc_uba; /* Unibus addr of cmd pkt for tsdb */ 9732579Sbostic short sc_density; /* value |'ed into char_mode for TC13 density */ 9844396Smarc tpr_t sc_tpr; /* tprintf handle */ 9930917Skarels int sc_blks; /* number of I/O operations since open */ 10030917Skarels int sc_softerrs; /* number of soft I/O errors since open */ 1013244Swnj } ts_softc[NTS]; 1021900Swnj 1033244Swnj /* 1043244Swnj * States for um->um_tab.b_active, the per controller state flag. 1053244Swnj * This is used to sequence control in the driver. 1063244Swnj */ 1073244Swnj #define SSEEK 1 /* seeking */ 1083244Swnj #define SIO 2 /* doing seq i/o */ 1093244Swnj #define SCOM 3 /* sending control command */ 1103244Swnj #define SREW 4 /* sending a drive rewind */ 1111900Swnj 1123244Swnj /* 1133244Swnj * Determine if there is a controller for 1143244Swnj * a ts at address reg. Our goal is to make the 1153244Swnj * device interrupt. 1163244Swnj */ 1173985Sroot /*ARGSUSED*/ 11832579Sbostic tsprobe(reg, ctlr, um) 1193244Swnj caddr_t reg; 12032579Sbostic int ctlr; 12132579Sbostic struct uba_ctlr *um; 1223244Swnj { 1233244Swnj register int br, cvec; /* must be r11,r10; value-result */ 12432579Sbostic register struct tsdevice *addr = (struct tsdevice *)reg; 12532579Sbostic register struct ts_softc *sc; 12632579Sbostic register int i; 12732579Sbostic int a; 1281900Swnj 1293244Swnj #ifdef lint 1303244Swnj br = 0; cvec = br; br = cvec; 1314937Swnj tsintr(0); 1323244Swnj #endif 13332579Sbostic addr->tssr = 0; /* initialize subsystem */ 1345693Sroot DELAY(100); 13532579Sbostic if ((addr->tssr & TS_NBA) == 0) 13632579Sbostic return (0); 13732579Sbostic 13832579Sbostic /* 13932579Sbostic * Make it interrupt. 14032579Sbostic * TS_SETCHR|TS_IE alone refuses to interrupt for me. 14132579Sbostic */ 14232579Sbostic sc = &ts_softc[ctlr]; 14332579Sbostic tsmap(sc, numuba, &a); 14432579Sbostic i = (int)&sc->sc_ubaddr->t_char; 14532579Sbostic sc->sc_ts.t_cmd.c_loba = i; 14632579Sbostic sc->sc_ts.t_cmd.c_hiba = (i >> 16) & 3; 14732579Sbostic sc->sc_ts.t_cmd.c_size = sizeof(struct ts_char); 14832579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_SETCHR; 14932579Sbostic sc->sc_ts.t_char.char_addr = (int)&sc->sc_ubaddr->t_sts; 15032579Sbostic sc->sc_ts.t_char.char_size = sizeof(struct ts_sts); 15132579Sbostic sc->sc_ts.t_char.char_mode = 0; /* mode is unimportant */ 15232579Sbostic addr->tsdb = sc->sc_uba; 15332579Sbostic DELAY(20000); 15432579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_IE | TS_SENSE; 15532579Sbostic sc->sc_ts.t_cmd.c_repcnt = 1; 15632579Sbostic addr->tsdb = sc->sc_uba; 15732579Sbostic DELAY(20000); 15832579Sbostic /* should have interrupted by now */ 15932579Sbostic 16032579Sbostic if (cvec == 0 || cvec == 0x200) /* no interrupt */ 16132579Sbostic ubarelse(numuba, &a); 16232579Sbostic 1637407Skre return (sizeof (struct tsdevice)); 1643244Swnj } 1651900Swnj 1663244Swnj /* 16732579Sbostic * Map in the command, status, and characteristics packet. We 16832579Sbostic * make them contiguous to keep overhead down. This also sets 16932579Sbostic * sc_uba (which then never changes). 17032579Sbostic */ 17132579Sbostic tsmap(sc, uban, a) 17232579Sbostic register struct ts_softc *sc; 17332579Sbostic int uban, *a; 17432579Sbostic { 17532579Sbostic register int i; 17632579Sbostic 17732579Sbostic i = uballoc(uban, (caddr_t)&sc->sc_ts, sizeof(sc->sc_ts), 0); 17832579Sbostic if (a != NULL) 17932579Sbostic *a = i; 18032579Sbostic i = UBAI_ADDR(i); 18132579Sbostic sc->sc_ubaddr = (struct ts_tsdata *)i; 18232579Sbostic /* 18332579Sbostic * Note that i == the Unibus address of the command packet, 18432579Sbostic * and that it is a multiple of 4 (guaranteed by the compiler). 18532579Sbostic */ 18632579Sbostic sc->sc_uba = i + ((i >> 16) & 3); 18732579Sbostic } 18832579Sbostic 18932579Sbostic /* 1903244Swnj * TS11 only supports one drive per controller; 1913244Swnj * check for ui_slave == 0. 1923244Swnj */ 1933244Swnj /*ARGSUSED*/ 1943244Swnj tsslave(ui, reg) 1953244Swnj struct uba_device *ui; 1963244Swnj caddr_t reg; 1973244Swnj { 1981900Swnj 19932579Sbostic return (ui->ui_slave == 0); /* non-zero slave not allowed */ 2003244Swnj } 2011900Swnj 2023244Swnj /* 2033244Swnj * Record attachment of the unit to the controller. 2043244Swnj */ 2053244Swnj /*ARGSUSED*/ 2063244Swnj tsattach(ui) 2073244Swnj struct uba_device *ui; 2083244Swnj { 2091900Swnj 21032579Sbostic /* void */ 2113244Swnj } 2121900Swnj 2133244Swnj /* 2143244Swnj * Open the device. Tapes are unique open 2153244Swnj * devices, so we refuse if it is already open. 2163244Swnj */ 2171900Swnj tsopen(dev, flag) 2183244Swnj dev_t dev; 2193244Swnj int flag; 2201900Swnj { 22132579Sbostic register int tsunit = TSUNIT(dev); 2223244Swnj register struct uba_device *ui; 2233244Swnj register struct ts_softc *sc; 2241900Swnj 22532579Sbostic if (tsunit >= NTS || (ui = tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) 2268575Sroot return (ENXIO); 22732579Sbostic if ((sc = &ts_softc[ui->ui_ctlr])->sc_openf) 22825054Skarels return (EBUSY); 22930917Skarels sc->sc_openf = 1; 23032579Sbostic sc->sc_density = (minor(dev) & T_1600BPI) ? TS_NRZI : 0; 23132579Sbostic tscommand(dev, TS_SENSE, 1); 23232579Sbostic if (ctsbuf[tsunit].b_flags & B_ERROR) 23332579Sbostic /* 23432579Sbostic * Try it again in case it went off-line 23532579Sbostic */ 23632579Sbostic tscommand(dev, TS_SENSE, 1); 23732579Sbostic if (tsinit(ui->ui_ctlr)) { 23830917Skarels sc->sc_openf = 0; 2398575Sroot return (ENXIO); 24030917Skarels } 24132579Sbostic if ((sc->sc_ts.t_sts.s_xs0&TS_ONL) == 0) { 24230917Skarels sc->sc_openf = 0; 2433711Sroot uprintf("ts%d: not online\n", tsunit); 2448575Sroot return (EIO); 2451900Swnj } 24632579Sbostic if ((flag&FWRITE) && (sc->sc_ts.t_sts.s_xs0&TS_WLK)) { 24730917Skarels sc->sc_openf = 0; 2483711Sroot uprintf("ts%d: no write ring\n", tsunit); 2498575Sroot return (EIO); 2503711Sroot } 2513244Swnj sc->sc_blkno = (daddr_t)0; 2523244Swnj sc->sc_nxrec = INF; 2533244Swnj sc->sc_lastiow = 0; 25430917Skarels sc->sc_blks = 0; 25530917Skarels sc->sc_softerrs = 0; 25644396Smarc sc->sc_tpr = tprintf_open(); 2578575Sroot return (0); 2581900Swnj } 2591900Swnj 2603244Swnj /* 2613244Swnj * Close tape device. 2623244Swnj * 2633244Swnj * If tape was open for writing or last operation was 2643244Swnj * a write, then write two EOF's and backspace over the last one. 2653244Swnj * Unless this is a non-rewinding special file, rewind the tape. 2663244Swnj * Make the tape available to others. 2673244Swnj */ 2681900Swnj tsclose(dev, flag) 2693244Swnj register dev_t dev; 27032579Sbostic register int flag; 2711900Swnj { 2723244Swnj register struct ts_softc *sc = &ts_softc[TSUNIT(dev)]; 2731900Swnj 2743244Swnj if (flag == FWRITE || (flag&FWRITE) && sc->sc_lastiow) { 2753244Swnj tscommand(dev, TS_WEOF, 1); 2763244Swnj tscommand(dev, TS_WEOF, 1); 2773244Swnj tscommand(dev, TS_SREV, 1); 2781900Swnj } 2793244Swnj if ((minor(dev)&T_NOREWIND) == 0) 2803244Swnj /* 2813244Swnj * 0 count means don't hang waiting for rewind complete 2823244Swnj * rather ctsbuf stays busy until the operation completes 2833244Swnj * preventing further opens from completing by 2843244Swnj * preventing a TS_SENSE from completing. 2853244Swnj */ 2863244Swnj tscommand(dev, TS_REW, 0); 28730917Skarels if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100) 28830917Skarels log(LOG_INFO, "ts%d: %d soft errors in %d blocks\n", 28930917Skarels TSUNIT(dev), sc->sc_softerrs, sc->sc_blks); 29044396Smarc tprintf_close(sc->sc_tpr); 2913244Swnj sc->sc_openf = 0; 29240815Smarc return (0); 2931900Swnj } 2941900Swnj 2953244Swnj /* 29632579Sbostic * Initialize a TS11. Set device characteristics. 2973244Swnj */ 29832579Sbostic tsinit(ctlr) 29932579Sbostic register int ctlr; 3001900Swnj { 30132579Sbostic register struct ts_softc *sc = &ts_softc[ctlr]; 30232579Sbostic register struct uba_ctlr *um = tsminfo[ctlr]; 3035693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 3043244Swnj register int i; 3053244Swnj 30632579Sbostic if (addr->tssr & (TS_NBA|TS_OFL) || sc->sc_ts.t_sts.s_xs0 & TS_BOT) { 3073244Swnj addr->tssr = 0; /* subsystem initialize */ 3083244Swnj tswait(addr); 30932579Sbostic i = (int)&sc->sc_ubaddr->t_char; 31032579Sbostic sc->sc_ts.t_cmd.c_loba = i; 31132579Sbostic sc->sc_ts.t_cmd.c_hiba = (i >> 16) & 3; 31232579Sbostic sc->sc_ts.t_cmd.c_size = sizeof(struct ts_char); 31332579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_SETCHR; 31432579Sbostic sc->sc_ts.t_char.char_addr = (int)&sc->sc_ubaddr->t_sts; 31532579Sbostic sc->sc_ts.t_char.char_size = sizeof(struct ts_sts); 31632579Sbostic sc->sc_ts.t_char.char_mode = TS_ESS | TS_EAI | TS_ERI | 31732579Sbostic /* TS_ENB | */ sc->sc_density; 3183244Swnj addr->tsdb = sc->sc_uba; 3193244Swnj tswait(addr); 3203327Swnj if (addr->tssr & TS_NBA) 3213327Swnj return(1); 3223244Swnj } 3233244Swnj return(0); 3243244Swnj } 3253244Swnj 3263244Swnj /* 3273244Swnj * Execute a command on the tape drive 3283244Swnj * a specified number of times. 3293244Swnj */ 3303244Swnj tscommand(dev, com, count) 3313244Swnj dev_t dev; 3323244Swnj int com, count; 3333244Swnj { 3341900Swnj register struct buf *bp; 3355438Sroot register int s; 33632579Sbostic int didsleep = 0; 3371900Swnj 3383244Swnj bp = &ctsbuf[TSUNIT(dev)]; 3395438Sroot s = spl5(); 3403244Swnj while (bp->b_flags&B_BUSY) { 3413244Swnj /* 3423244Swnj * This special check is because B_BUSY never 3433244Swnj * gets cleared in the non-waiting rewind case. 3443244Swnj */ 3453244Swnj if (bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 3463244Swnj break; 3471900Swnj bp->b_flags |= B_WANTED; 3481900Swnj sleep((caddr_t)bp, PRIBIO); 34932579Sbostic didsleep = 1; 3501900Swnj } 3513244Swnj bp->b_flags = B_BUSY|B_READ; 3525438Sroot splx(s); 35332579Sbostic if (didsleep) 35432579Sbostic (void) tsinit(tsdinfo[TSUNIT(dev)]->ui_ctlr); 3553244Swnj bp->b_dev = dev; 3563244Swnj bp->b_repcnt = count; 3573244Swnj bp->b_command = com; 3581900Swnj bp->b_blkno = 0; 3591900Swnj tsstrategy(bp); 3603244Swnj /* 3613244Swnj * In case of rewind from close, don't wait. 3623244Swnj * This is the only case where count can be 0. 3633244Swnj */ 3643244Swnj if (count == 0) 3653244Swnj return; 36632579Sbostic biowait(bp); 3673244Swnj if (bp->b_flags&B_WANTED) 3681900Swnj wakeup((caddr_t)bp); 3693244Swnj bp->b_flags &= B_ERROR; 3701900Swnj } 3711900Swnj 3723244Swnj /* 3733244Swnj * Queue a tape operation. 3743244Swnj */ 3751900Swnj tsstrategy(bp) 3763244Swnj register struct buf *bp; 3771900Swnj { 37832579Sbostic register int tsunit = TSUNIT(bp->b_dev); 3793244Swnj register struct uba_ctlr *um; 3803327Swnj register struct buf *dp; 38132579Sbostic int s; 3821900Swnj 3833244Swnj /* 3843244Swnj * Put transfer at end of controller queue 3853244Swnj */ 3861900Swnj bp->av_forw = NULL; 3873244Swnj um = tsdinfo[tsunit]->ui_mi; 38832579Sbostic dp = &tsutab[tsunit]; 3895438Sroot s = spl5(); 3903327Swnj if (dp->b_actf == NULL) 3913327Swnj dp->b_actf = bp; 3921900Swnj else 3933327Swnj dp->b_actl->av_forw = bp; 3943327Swnj dp->b_actl = bp; 3953327Swnj um->um_tab.b_actf = um->um_tab.b_actl = dp; 3963244Swnj /* 3973244Swnj * If the controller is not busy, get 3983244Swnj * it going. 3993244Swnj */ 4003244Swnj if (um->um_tab.b_active == 0) 4013244Swnj tsstart(um); 4025438Sroot splx(s); 4031900Swnj } 4041900Swnj 4053244Swnj /* 4063244Swnj * Start activity on a ts controller. 4073244Swnj */ 4083244Swnj tsstart(um) 4093244Swnj register struct uba_ctlr *um; 4101900Swnj { 4111900Swnj register struct buf *bp; 4125693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 4133244Swnj register struct ts_softc *sc; 4143244Swnj register struct uba_device *ui; 41532579Sbostic register int tsunit; 41632579Sbostic int cmd; 4171900Swnj daddr_t blkno; 4181900Swnj 4193244Swnj /* 4203244Swnj * Start the controller if there is something for it to do. 4213244Swnj */ 4223244Swnj loop: 42332609Sbostic if ((bp = um->um_tab.b_actf->b_actf) == NULL) { 42432609Sbostic um->um_tab.b_active = 0; 4251900Swnj return; 42632609Sbostic } 4273244Swnj tsunit = TSUNIT(bp->b_dev); 4283244Swnj ui = tsdinfo[tsunit]; 4293244Swnj sc = &ts_softc[tsunit]; 4303244Swnj /* 4313244Swnj * Default is that last command was NOT a write command; 43232579Sbostic * if we finish a write command we will notice this in tsintr(). 4333244Swnj */ 4343656Swnj sc->sc_lastiow = 0; 4353244Swnj if (sc->sc_openf < 0 || (addr->tssr&TS_OFL)) { 4363244Swnj /* 4373244Swnj * Have had a hard error on a non-raw tape 4383244Swnj * or the tape unit is now unavailable 4393244Swnj * (e.g. taken off line). 4403244Swnj */ 4413244Swnj bp->b_flags |= B_ERROR; 4423244Swnj goto next; 4433244Swnj } 44432579Sbostic if (bp == &ctsbuf[tsunit]) { 4453244Swnj /* 4463244Swnj * Execute control operation with the specified count. 4473244Swnj */ 4483244Swnj um->um_tab.b_active = 4493244Swnj bp->b_command == TS_REW ? SREW : SCOM; 45032579Sbostic sc->sc_ts.t_cmd.c_repcnt = bp->b_repcnt; 4513244Swnj goto dobpcmd; 4523244Swnj } 4533244Swnj /* 45432579Sbostic * For raw I/O, save the current block 45532579Sbostic * number in case we have to retry. 4563244Swnj */ 45734217Sbostic if (bp->b_flags & B_RAW) { 45832579Sbostic if (um->um_tab.b_errcnt == 0) 45932579Sbostic sc->sc_blkno = bdbtofsb(bp->b_blkno); 46032579Sbostic } else { 4613244Swnj /* 46232579Sbostic * Handle boundary cases for operation 46332579Sbostic * on non-raw tapes. 4643244Swnj */ 46532579Sbostic if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 46632579Sbostic /* 46732579Sbostic * Can't read past known end-of-file. 46832579Sbostic */ 46932579Sbostic bp->b_flags |= B_ERROR; 47032579Sbostic bp->b_error = ENXIO; 47132579Sbostic goto next; 47232579Sbostic } 47332579Sbostic if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && 47432579Sbostic bp->b_flags&B_READ) { 47532579Sbostic /* 47632579Sbostic * Reading at end of file returns 0 bytes. 47732579Sbostic */ 47832579Sbostic bp->b_resid = bp->b_bcount; 47932579Sbostic clrbuf(bp); 48032579Sbostic goto next; 48132579Sbostic } 48232579Sbostic if ((bp->b_flags&B_READ) == 0) 48332579Sbostic /* 48432579Sbostic * Writing sets EOF 48532579Sbostic */ 48632579Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; 4873244Swnj } 48832579Sbostic 4893244Swnj /* 4903244Swnj * If the data transfer command is in the correct place, 4913244Swnj * set up all the registers except the csr, and give 4923244Swnj * control over to the UNIBUS adapter routines, to 4933244Swnj * wait for resources to start the i/o. 4943244Swnj */ 4957383Ssam if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { 49632579Sbostic sc->sc_ts.t_cmd.c_size = bp->b_bcount; 4973244Swnj if ((bp->b_flags&B_READ) == 0) 4983244Swnj cmd = TS_WCOM; 4991900Swnj else 5003244Swnj cmd = TS_RCOM; 5013244Swnj if (um->um_tab.b_errcnt) 5023244Swnj cmd |= TS_RETRY; 5033244Swnj um->um_tab.b_active = SIO; 50432579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_IE | cmd; 5053244Swnj (void) ubago(ui); 5063244Swnj return; 5073244Swnj } 5083244Swnj /* 5093244Swnj * Tape positioned incorrectly; 5103244Swnj * set to seek forwards or backwards to the correct spot. 5113244Swnj * This happens for raw tapes only on error retries. 5123244Swnj */ 5133244Swnj um->um_tab.b_active = SSEEK; 5147383Ssam if (blkno < bdbtofsb(bp->b_blkno)) { 5153244Swnj bp->b_command = TS_SFORW; 51632579Sbostic sc->sc_ts.t_cmd.c_repcnt = bdbtofsb(bp->b_blkno) - blkno; 5171900Swnj } else { 5183244Swnj bp->b_command = TS_SREV; 51932579Sbostic sc->sc_ts.t_cmd.c_repcnt = blkno - bdbtofsb(bp->b_blkno); 5201900Swnj } 5213244Swnj dobpcmd: 5223244Swnj /* 5233244Swnj * Do the command in bp. 5243244Swnj */ 52532579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_IE | bp->b_command; 5263244Swnj addr->tsdb = sc->sc_uba; 5271900Swnj return; 5281900Swnj 5293244Swnj next: 5303244Swnj /* 5313244Swnj * Done with this operation due to error or 5323244Swnj * the fact that it doesn't do anything. 5333244Swnj * Release UBA resources (if any), dequeue 5343244Swnj * the transfer and continue processing this slave. 5353244Swnj */ 5363244Swnj if (um->um_ubinfo) 5373244Swnj ubadone(um); 5383244Swnj um->um_tab.b_errcnt = 0; 5393327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 54032579Sbostic biodone(bp); 5411900Swnj goto loop; 5421900Swnj } 5431900Swnj 5443244Swnj /* 5453244Swnj * The UNIBUS resources we needed have been 5463244Swnj * allocated to us; start the device. 5473244Swnj */ 5483244Swnj tsdgo(um) 5493244Swnj register struct uba_ctlr *um; 5501900Swnj { 5513244Swnj register struct ts_softc *sc = &ts_softc[um->um_ctlr]; 5523327Swnj register int i; 5533244Swnj 55426139Skarels /* 55526139Skarels * The uba code uses byte-offset mode if using bdp; 55626139Skarels * mask off the low bit here. 55726139Skarels */ 55832579Sbostic i = UBAI_ADDR(um->um_ubinfo); 55926139Skarels if (UBAI_BDP(um->um_ubinfo)) 56026139Skarels i &= ~1; 56132579Sbostic sc->sc_ts.t_cmd.c_loba = i; 56232579Sbostic sc->sc_ts.t_cmd.c_hiba = (i >> 16) & 3; 56332579Sbostic ((struct tsdevice *)um->um_addr)->tsdb = sc->sc_uba; 5643244Swnj } 5653244Swnj 5663244Swnj /* 5673244Swnj * Ts interrupt routine. 5683244Swnj */ 5693244Swnj /*ARGSUSED*/ 57032579Sbostic tsintr(tsunit) 57132579Sbostic register int tsunit; 5723244Swnj { 5731900Swnj register struct buf *bp; 57432579Sbostic register struct uba_ctlr *um; 5755693Sroot register struct tsdevice *addr; 5763244Swnj register struct ts_softc *sc; 57732579Sbostic register int state; 57832579Sbostic 57935401Stef #ifdef QBA 58032579Sbostic (void) spl5(); 58127253Skridle #endif 58232579Sbostic um = tsdinfo[tsunit]->ui_mi; 5833327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 5841900Swnj return; 58532579Sbostic addr = (struct tsdevice *)um->um_addr; 5863244Swnj /* 5873244Swnj * If last command was a rewind, and tape is still 5883244Swnj * rewinding, wait for the rewind complete interrupt. 5893244Swnj * 5903244Swnj * SHOULD NEVER GET AN INTERRUPT IN THIS STATE. 5913244Swnj */ 5923244Swnj if (um->um_tab.b_active == SREW) { 5933244Swnj um->um_tab.b_active = SCOM; 5943244Swnj if ((addr->tssr&TS_SSR) == 0) 5953244Swnj return; 5963244Swnj } 5973244Swnj /* 5983244Swnj * An operation completed... record status 5993244Swnj */ 60032579Sbostic sc = &ts_softc[um->um_ctlr]; 6013244Swnj if ((bp->b_flags & B_READ) == 0) 6023244Swnj sc->sc_lastiow = 1; 6033244Swnj state = um->um_tab.b_active; 6043244Swnj /* 6053244Swnj * Check for errors. 6063244Swnj */ 6073244Swnj if (addr->tssr&TS_SC) { 6083244Swnj switch (addr->tssr & TS_TC) { 6093244Swnj case TS_UNREC: /* unrecoverable */ 6103244Swnj case TS_FATAL: /* fatal error */ 6113244Swnj case TS_RECNM: /* recoverable, no motion */ 6123244Swnj break; 61332579Sbostic case TS_ATTN: /* attention */ 61432579Sbostic if (sc->sc_ts.t_sts.s_xs0 & TS_VCK) { 61532579Sbostic /* volume check - may have changed tapes */ 61632579Sbostic bp->b_flags |= B_ERROR; 61732579Sbostic goto ignoreerr; 61832579Sbostic } 61932579Sbostic break; 6201900Swnj 6213244Swnj case TS_SUCC: /* success termination */ 62232579Sbostic printf("ts%d: success\n", tsunit); 6233244Swnj goto ignoreerr; 6241900Swnj 6253244Swnj case TS_ALERT: /* tape status alert */ 6263244Swnj /* 6273244Swnj * If we hit the end of the tape file, 6283244Swnj * update our position. 6293244Swnj */ 63032579Sbostic if (sc->sc_ts.t_sts.s_xs0 & (TS_TMK|TS_EOT)) { 63132579Sbostic tsseteof(bp); /* set blkno and nxrec */ 63232579Sbostic state = SCOM; /* force completion */ 6333244Swnj /* 6343244Swnj * Stuff bc so it will be unstuffed correctly 6353244Swnj * later to get resid. 6363244Swnj */ 63732579Sbostic sc->sc_ts.t_sts.s_rbpcr = bp->b_bcount; 6383244Swnj goto opdone; 6393244Swnj } 6403244Swnj /* 64132579Sbostic * If we were reading raw tape and the record was too 64232579Sbostic * long or too short, we don't consider this an error. 6433244Swnj */ 64434217Sbostic if ((bp->b_flags & (B_READ|B_RAW)) == (B_READ|B_RAW) && 64532579Sbostic sc->sc_ts.t_sts.s_xs0&(TS_RLS|TS_RLL)) 6463244Swnj goto ignoreerr; 64732579Sbostic /* FALLTHROUGH */ 64832579Sbostic 6493244Swnj case TS_RECOV: /* recoverable, tape moved */ 6503244Swnj /* 6513244Swnj * If this was an i/o operation retry up to 8 times. 6523244Swnj */ 65332579Sbostic if (state == SIO) { 6543244Swnj if (++um->um_tab.b_errcnt < 7) { 6553244Swnj ubadone(um); 6563244Swnj goto opcont; 6573244Swnj } else 6583244Swnj sc->sc_blkno++; 6593244Swnj } else { 6603244Swnj /* 6613244Swnj * Non-i/o errors on non-raw tape 6623244Swnj * cause it to close. 6633244Swnj */ 66434217Sbostic if ((bp->b_flags&B_RAW) == 0 && 66534217Sbostic sc->sc_openf > 0) 6663244Swnj sc->sc_openf = -1; 6673244Swnj } 6681900Swnj break; 6693244Swnj 6703244Swnj case TS_REJECT: /* function reject */ 67132579Sbostic if (state == SIO && sc->sc_ts.t_sts.s_xs0 & TS_WLE) 67244396Smarc tprintf(sc->sc_tpr, "ts%d: write locked\n", 67332579Sbostic tsunit); 67432579Sbostic if ((sc->sc_ts.t_sts.s_xs0 & TS_ONL) == 0) 67544396Smarc tprintf(sc->sc_tpr, "ts%d: offline\n", 67632579Sbostic tsunit); 6771900Swnj break; 6781900Swnj } 6793244Swnj /* 6803244Swnj * Couldn't recover error 6813244Swnj */ 68244396Smarc tprintf(sc->sc_tpr, "ts%d: hard error bn%d tssr=%b xs0=%b", 68332579Sbostic tsunit, bp->b_blkno, addr->tssr, TSSR_BITS, 68432579Sbostic sc->sc_ts.t_sts.s_xs0, TSXS0_BITS); 68532579Sbostic if (sc->sc_ts.t_sts.s_xs1) 68644396Smarc tprintf(sc->sc_tpr, " xs1=%b", sc->sc_ts.t_sts.s_xs1, 68718322Sralph TSXS1_BITS); 68832579Sbostic if (sc->sc_ts.t_sts.s_xs2) 68944396Smarc tprintf(sc->sc_tpr, " xs2=%b", sc->sc_ts.t_sts.s_xs2, 69018322Sralph TSXS2_BITS); 69132579Sbostic if (sc->sc_ts.t_sts.s_xs3) 69244396Smarc tprintf(sc->sc_tpr, " xs3=%b", sc->sc_ts.t_sts.s_xs3, 69318322Sralph TSXS3_BITS); 69444396Smarc tprintf(sc->sc_tpr, "\n"); 6953244Swnj bp->b_flags |= B_ERROR; 6963244Swnj goto opdone; 6973244Swnj } 6983244Swnj /* 6993244Swnj * Advance tape control FSM. 7003244Swnj */ 7013244Swnj ignoreerr: 7023244Swnj switch (state) { 7031900Swnj 7043244Swnj case SIO: 7053244Swnj /* 7063244Swnj * Read/write increments tape block number 7073244Swnj */ 7083244Swnj sc->sc_blkno++; 70930917Skarels sc->sc_blks++; 71030917Skarels if (um->um_tab.b_errcnt) 71130917Skarels sc->sc_softerrs++; 7123244Swnj goto opdone; 7131900Swnj 7141900Swnj case SCOM: 7153244Swnj /* 7163244Swnj * For forward/backward space record update current position. 7173244Swnj */ 71832579Sbostic if (bp == &ctsbuf[tsunit]) 71932579Sbostic switch ((int)bp->b_command) { 7201900Swnj 72132579Sbostic case TS_SFORW: 72232579Sbostic sc->sc_blkno += bp->b_repcnt; 72332579Sbostic break; 7241900Swnj 72532579Sbostic case TS_SREV: 72632579Sbostic sc->sc_blkno -= bp->b_repcnt; 72732579Sbostic break; 72832579Sbostic } 7293244Swnj goto opdone; 7303244Swnj 7313244Swnj case SSEEK: 7327383Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno); 7333244Swnj goto opcont; 7343244Swnj 7351900Swnj default: 7363244Swnj panic("tsintr"); 7371900Swnj } 7383244Swnj opdone: 7393244Swnj /* 7403244Swnj * Reset error count and remove 7413244Swnj * from device queue. 7423244Swnj */ 7433244Swnj um->um_tab.b_errcnt = 0; 7443327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 74532579Sbostic bp->b_resid = sc->sc_ts.t_sts.s_rbpcr; 7463244Swnj ubadone(um); 74732579Sbostic biodone(bp); 74832579Sbostic if (um->um_tab.b_actf->b_actf == 0) { 74932579Sbostic um->um_tab.b_active = 0; 7503244Swnj return; 75132579Sbostic } 7523244Swnj opcont: 7533244Swnj tsstart(um); 7543244Swnj } 7553244Swnj 7563244Swnj tsseteof(bp) 7573244Swnj register struct buf *bp; 7583244Swnj { 7593244Swnj register int tsunit = TSUNIT(bp->b_dev); 76032579Sbostic register struct ts_softc *sc = &ts_softc[tsdinfo[tsunit]->ui_ctlr]; 7613244Swnj 76232579Sbostic if (bp == &ctsbuf[tsunit]) { 7637383Ssam if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 7643244Swnj /* reversing */ 76532579Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) - 76632579Sbostic sc->sc_ts.t_sts.s_rbpcr; 7673244Swnj sc->sc_blkno = sc->sc_nxrec; 7683244Swnj } else { 7693244Swnj /* spacing forward */ 77032579Sbostic sc->sc_blkno = bdbtofsb(bp->b_blkno) + 77132579Sbostic sc->sc_ts.t_sts.s_rbpcr; 7723244Swnj sc->sc_nxrec = sc->sc_blkno - 1; 7731900Swnj } 7743244Swnj return; 7753244Swnj } 7763244Swnj /* eof on read */ 7777383Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno); 7781900Swnj } 7791900Swnj 7803244Swnj tsreset(uban) 7813244Swnj int uban; 7821918Swnj { 7833244Swnj register struct uba_ctlr *um; 7845693Sroot register struct uba_device *ui; 78532579Sbostic register int ts11, i; 7861918Swnj 7873244Swnj for (ts11 = 0; ts11 < NTS; ts11++) { 7883244Swnj if ((um = tsminfo[ts11]) == 0 || um->um_alive == 0 || 78932579Sbostic um->um_ubanum != uban) 7903244Swnj continue; 7913244Swnj printf(" ts%d", ts11); 7923244Swnj um->um_tab.b_active = 0; 7933244Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7945693Sroot if (ts_softc[ts11].sc_openf > 0) 7955693Sroot ts_softc[ts11].sc_openf = -1; 7963244Swnj if (um->um_ubinfo) { 79732579Sbostic printf("<%d>", UBAI_BDP(um->um_ubinfo)); 7989356Ssam um->um_ubinfo = 0; 7993244Swnj } 80032579Sbostic /* 80132579Sbostic * tsdinfo should be 1-to-1 with tsminfo, but someone 80232579Sbostic * might have screwed up the config file: 80332579Sbostic */ 80432579Sbostic for (i = 0; i < NTS; i++) { 80532579Sbostic if ((ui = tsdinfo[i]) != NULL && 80632579Sbostic ui->ui_alive && ui->ui_mi == um) { 80732579Sbostic um->um_tab.b_actf = um->um_tab.b_actl = 80832579Sbostic &tsutab[i]; 80932579Sbostic break; 81032579Sbostic } 8115693Sroot } 81232579Sbostic tsmap(&ts_softc[ts11], uban, (int *)NULL); 8133989Sroot (void) tsinit(ts11); 8143244Swnj tsstart(um); 8151918Swnj } 8161918Swnj } 8171918Swnj 8183244Swnj /*ARGSUSED*/ 8197633Ssam tsioctl(dev, cmd, data, flag) 8207633Ssam caddr_t data; 8213244Swnj dev_t dev; 8221918Swnj { 8233244Swnj int tsunit = TSUNIT(dev); 82432579Sbostic register struct ts_softc *sc = &ts_softc[tsdinfo[tsunit]->ui_ctlr]; 8253244Swnj register struct buf *bp = &ctsbuf[TSUNIT(dev)]; 82632579Sbostic register int callcount; 82740911Ssklower int fcount, error = 0; 8287633Ssam struct mtop *mtop; 8297633Ssam struct mtget *mtget; 8303244Swnj /* we depend of the values and order of the MT codes here */ 83132579Sbostic static int tsops[] = 8323656Swnj {TS_WEOF,TS_SFORWF,TS_SREVF,TS_SFORW,TS_SREV,TS_REW,TS_OFFL,TS_SENSE}; 8331918Swnj 8343244Swnj switch (cmd) { 8357633Ssam 8363244Swnj case MTIOCTOP: /* tape operation */ 8377633Ssam mtop = (struct mtop *)data; 8388575Sroot switch (mtop->mt_op) { 8397633Ssam 8403244Swnj case MTWEOF: 8417633Ssam callcount = mtop->mt_count; 8423244Swnj fcount = 1; 8433244Swnj break; 8447633Ssam 8453244Swnj case MTFSF: case MTBSF: 8463244Swnj case MTFSR: case MTBSR: 8473244Swnj callcount = 1; 8487633Ssam fcount = mtop->mt_count; 8493244Swnj break; 8507633Ssam 8513244Swnj case MTREW: case MTOFFL: case MTNOP: 8523244Swnj callcount = 1; 8533244Swnj fcount = 1; 8543244Swnj break; 8557633Ssam 8563244Swnj default: 8578575Sroot return (ENXIO); 8583244Swnj } 8598575Sroot if (callcount <= 0 || fcount <= 0) 8608575Sroot return (EINVAL); 8613244Swnj while (--callcount >= 0) { 8627633Ssam tscommand(dev, tsops[mtop->mt_op], fcount); 8637633Ssam if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) && 8648611Sroot bp->b_resid) 8658575Sroot return (EIO); 86632579Sbostic if ((bp->b_flags&B_ERROR) || 86732579Sbostic sc->sc_ts.t_sts.s_xs0&TS_BOT) 8683244Swnj break; 8693244Swnj } 87040911Ssklower if (bp->b_flags&B_ERROR) 87140911Ssklower if ((error = bp->b_error)==0) 87240911Ssklower return (EIO); 87340911Ssklower return (error); 8747633Ssam 8753244Swnj case MTIOCGET: 8767633Ssam mtget = (struct mtget *)data; 8777633Ssam mtget->mt_dsreg = 0; 87832579Sbostic mtget->mt_erreg = sc->sc_ts.t_sts.s_xs0; 8797633Ssam mtget->mt_resid = sc->sc_resid; 8807633Ssam mtget->mt_type = MT_ISTS; 8818575Sroot break; 8827633Ssam 8833244Swnj default: 8848575Sroot return (ENXIO); 8853244Swnj } 8868575Sroot return (0); 8871918Swnj } 8881918Swnj 8893244Swnj #define DBSIZE 20 8903244Swnj 89132579Sbostic tsdump(dev) 89232579Sbostic dev_t dev; 8931918Swnj { 8943244Swnj register struct uba_device *ui; 89532579Sbostic register struct uba_regs *uba; 8965693Sroot register struct tsdevice *addr; 89732579Sbostic register int i; 89832579Sbostic register struct pte *io; 89932579Sbostic int blk, num, unit, reg, start; 90032579Sbostic u_short db; 90132579Sbostic struct ts_tsdata *tc, *tc_ubaddr; 9021918Swnj 90332579Sbostic unit = TSUNIT(dev); 90432579Sbostic if (unit >= NTS) 90532579Sbostic return (ENXIO); 9063244Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 90732579Sbostic ui = phys(tsdinfo[unit], struct uba_device *); 90832579Sbostic if (ui->ui_alive == 0) 9093244Swnj return (ENXIO); 91032579Sbostic uba = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 91132579Sbostic ubainit(uba); 9125693Sroot addr = (struct tsdevice *)ui->ui_physaddr; 91332579Sbostic 91432579Sbostic /* map a ts_tsdata structure */ 91532579Sbostic tc = phys(&ts_softc[0].sc_ts, struct ts_tsdata *); 91632579Sbostic num = btoc(sizeof(struct ts_tsdata)) + 1; 91732579Sbostic io = &uba->uba_map[reg = NUBMREG - num]; 91832579Sbostic for (i = 0; i < num; i++) 91932579Sbostic *(int *)io++ = UBAMR_MRV | (btop(tc) + i); 92032579Sbostic i = (((int)tc & PGOFSET) | (reg << 9)); 92132579Sbostic tc_ubaddr = (struct ts_tsdata *)i; 92232579Sbostic db = i + ((i >> 16) & 3); 92332579Sbostic 92432579Sbostic /* init the drive */ 9253244Swnj addr->tssr = 0; 9263244Swnj tswait(addr); 92732579Sbostic if ((addr->tssr & (TS_NBA|TS_OFL)) != TS_NBA) 92832579Sbostic return (EFAULT); 92932579Sbostic 93032579Sbostic /* set characteristics */ 93132579Sbostic i = (int)&tc_ubaddr->t_char; 93232579Sbostic tc->t_cmd.c_loba = i; 93332579Sbostic tc->t_cmd.c_hiba = (i >> 16) & 3; 93432579Sbostic tc->t_cmd.c_size = sizeof(struct ts_char); 93532579Sbostic tc->t_cmd.c_cmd = TS_ACK | TS_CVC | TS_SETCHR; 93632579Sbostic tc->t_char.char_addr = (int)&tc_ubaddr->t_sts; 93732579Sbostic tc->t_char.char_size = sizeof(struct ts_sts); 93832579Sbostic tc->t_char.char_mode = TS_ESS; 93932579Sbostic addr->tsdb = db; 94032579Sbostic tswait(addr); 94132579Sbostic if (addr->tssr & TS_NBA) 94232579Sbostic return (ENXIO); 94332579Sbostic 94432579Sbostic /* dump */ 94532579Sbostic tc->t_cmd.c_cmd = TS_ACK | TS_WCOM; 94632579Sbostic tc->t_cmd.c_repcnt = 1; 94732579Sbostic num = maxfree; 94832579Sbostic for (start = 0, num = maxfree; num > 0; start += blk, num -= blk) { 9493244Swnj blk = num > DBSIZE ? DBSIZE : num; 95032579Sbostic io = uba->uba_map; 95132579Sbostic for (i = 0; i < blk; i++) 95232579Sbostic *(int *)io++ = UBAMR_MRV | (1 << UBAMR_DPSHIFT) | 95332579Sbostic (start + i); 95432579Sbostic *(int *)io = 0; 95532579Sbostic addr->tsdb = db; 95632579Sbostic tswait(addr); 9573244Swnj } 95832579Sbostic 95932579Sbostic /* eof */ 96032579Sbostic tc->t_cmd.c_cmd = TS_WEOF; 96132579Sbostic addr->tsdb = db; 9623244Swnj tswait(addr); 96332579Sbostic addr->tsdb = db; 96432579Sbostic tswait(addr); 96532579Sbostic 9663244Swnj if (addr->tssr&TS_SC) 9673244Swnj return (EIO); 9683244Swnj addr->tssr = 0; 9693244Swnj tswait(addr); 9703244Swnj return (0); 9711918Swnj } 9721918Swnj 9733244Swnj tswait(addr) 9745693Sroot register struct tsdevice *addr; 9751918Swnj { 9761918Swnj 97732579Sbostic while ((addr->tssr & TS_SSR) == 0) 97832579Sbostic /* void */; 9791918Swnj } 9801918Swnj 98132579Sbostic #endif /* NTS > 0 */ 982