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*44396Smarc * @(#)ts.c 7.12 (Berkeley) 06/28/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 */ 2017080Sbloom #include "param.h" 2117080Sbloom #include "systm.h" 2217080Sbloom #include "buf.h" 2317080Sbloom #include "conf.h" 2417080Sbloom #include "file.h" 2517080Sbloom #include "map.h" 2617080Sbloom #include "vm.h" 2717080Sbloom #include "ioctl.h" 2817080Sbloom #include "mtio.h" 2917080Sbloom #include "cmap.h" 3017080Sbloom #include "uio.h" 3130917Skarels #include "syslog.h" 32*44396Smarc #include "tprintf.h" 331900Swnj 3437511Smckusick #include "machine/pte.h" 358480Sroot #include "../vax/cpu.h" 3617080Sbloom #include "ubareg.h" 3717080Sbloom #include "ubavar.h" 3817080Sbloom #include "tsreg.h" 391900Swnj 403244Swnj /* 413244Swnj * There is a ctsbuf per tape controller. 423244Swnj * It is used as the token to pass to the internal routines 433244Swnj * to execute tape ioctls. 443244Swnj * In particular, when the tape is rewinding on close we release 453244Swnj * the user process but any further attempts to use the tape drive 463244Swnj * before the rewind completes will hang waiting for ctsbuf. 473244Swnj */ 483244Swnj struct buf ctsbuf[NTS]; 491900Swnj 503244Swnj /* 513244Swnj * Driver unibus interface routines and variables. 523244Swnj */ 533244Swnj int tsprobe(), tsslave(), tsattach(), tsdgo(), tsintr(); 543244Swnj struct uba_ctlr *tsminfo[NTS]; 553244Swnj struct uba_device *tsdinfo[NTS]; 565693Sroot struct buf tsutab[NTS]; 573244Swnj u_short tsstd[] = { 0772520, 0 }; 5832579Sbostic /* need all these even though controller == drive */ 593244Swnj struct uba_driver zsdriver = 6032579Sbostic { tsprobe, tsslave, tsattach, tsdgo, tsstd, "ts", tsdinfo, "zs", tsminfo }; 611900Swnj 623244Swnj /* bits in minor device */ 633244Swnj #define TSUNIT(dev) (minor(dev)&03) 643244Swnj #define T_NOREWIND 04 6532579Sbostic #define T_1600BPI 010 661900Swnj 673244Swnj #define INF (daddr_t)1000000L 681900Swnj 693244Swnj /* 703244Swnj * Software state per tape transport. 713244Swnj * Also contains hardware state in message packets. 723244Swnj * 733244Swnj * 1. A tape drive is a unique-open device; we refuse opens when it is already. 743244Swnj * 2. We keep track of the current position on a block tape and seek 753244Swnj * before operations by forward/back spacing if necessary. 763244Swnj * 3. We remember if the last operation was a write on a tape, so if a tape 773244Swnj * is open read write and the last thing done is a write we can 783244Swnj * write a standard end of tape mark (two eofs). 793244Swnj * 4. We remember the status registers after the last command, using 803244Swnj * then internally and returning them to the SENSE ioctl. 813244Swnj */ 8232579Sbostic struct ts_tsdata { /* data shared with ts11 controller */ 8332579Sbostic struct ts_cmd t_cmd; /* the command packet (must be first) */ 8432579Sbostic struct ts_sts t_sts; /* status packet, for returned status */ 8532579Sbostic struct ts_char t_char; /* characteristics packet */ 8632579Sbostic }; 873244Swnj struct ts_softc { 883244Swnj char sc_openf; /* lock against multiple opens */ 893244Swnj char sc_lastiow; /* last op was a write */ 903327Swnj short sc_resid; /* copy of last bc */ 913244Swnj daddr_t sc_blkno; /* block number, for block device tape */ 923244Swnj daddr_t sc_nxrec; /* position of end of tape, if known */ 9332579Sbostic struct ts_tsdata sc_ts;/* command and status packets */ 9432579Sbostic struct ts_tsdata *sc_ubaddr; /* Unibus address of tsdata structure */ 955697Sroot u_short sc_uba; /* Unibus addr of cmd pkt for tsdb */ 9632579Sbostic short sc_density; /* value |'ed into char_mode for TC13 density */ 97*44396Smarc tpr_t sc_tpr; /* tprintf handle */ 9830917Skarels int sc_blks; /* number of I/O operations since open */ 9930917Skarels int sc_softerrs; /* number of soft I/O errors since open */ 1003244Swnj } ts_softc[NTS]; 1011900Swnj 1023244Swnj /* 1033244Swnj * States for um->um_tab.b_active, the per controller state flag. 1043244Swnj * This is used to sequence control in the driver. 1053244Swnj */ 1063244Swnj #define SSEEK 1 /* seeking */ 1073244Swnj #define SIO 2 /* doing seq i/o */ 1083244Swnj #define SCOM 3 /* sending control command */ 1093244Swnj #define SREW 4 /* sending a drive rewind */ 1101900Swnj 1113244Swnj /* 1123244Swnj * Determine if there is a controller for 1133244Swnj * a ts at address reg. Our goal is to make the 1143244Swnj * device interrupt. 1153244Swnj */ 1163985Sroot /*ARGSUSED*/ 11732579Sbostic tsprobe(reg, ctlr, um) 1183244Swnj caddr_t reg; 11932579Sbostic int ctlr; 12032579Sbostic struct uba_ctlr *um; 1213244Swnj { 1223244Swnj register int br, cvec; /* must be r11,r10; value-result */ 12332579Sbostic register struct tsdevice *addr = (struct tsdevice *)reg; 12432579Sbostic register struct ts_softc *sc; 12532579Sbostic register int i; 12632579Sbostic int a; 1271900Swnj 1283244Swnj #ifdef lint 1293244Swnj br = 0; cvec = br; br = cvec; 1304937Swnj tsintr(0); 1313244Swnj #endif 13232579Sbostic addr->tssr = 0; /* initialize subsystem */ 1335693Sroot DELAY(100); 13432579Sbostic if ((addr->tssr & TS_NBA) == 0) 13532579Sbostic return (0); 13632579Sbostic 13732579Sbostic /* 13832579Sbostic * Make it interrupt. 13932579Sbostic * TS_SETCHR|TS_IE alone refuses to interrupt for me. 14032579Sbostic */ 14132579Sbostic sc = &ts_softc[ctlr]; 14232579Sbostic tsmap(sc, numuba, &a); 14332579Sbostic i = (int)&sc->sc_ubaddr->t_char; 14432579Sbostic sc->sc_ts.t_cmd.c_loba = i; 14532579Sbostic sc->sc_ts.t_cmd.c_hiba = (i >> 16) & 3; 14632579Sbostic sc->sc_ts.t_cmd.c_size = sizeof(struct ts_char); 14732579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_SETCHR; 14832579Sbostic sc->sc_ts.t_char.char_addr = (int)&sc->sc_ubaddr->t_sts; 14932579Sbostic sc->sc_ts.t_char.char_size = sizeof(struct ts_sts); 15032579Sbostic sc->sc_ts.t_char.char_mode = 0; /* mode is unimportant */ 15132579Sbostic addr->tsdb = sc->sc_uba; 15232579Sbostic DELAY(20000); 15332579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_IE | TS_SENSE; 15432579Sbostic sc->sc_ts.t_cmd.c_repcnt = 1; 15532579Sbostic addr->tsdb = sc->sc_uba; 15632579Sbostic DELAY(20000); 15732579Sbostic /* should have interrupted by now */ 15832579Sbostic 15932579Sbostic if (cvec == 0 || cvec == 0x200) /* no interrupt */ 16032579Sbostic ubarelse(numuba, &a); 16132579Sbostic 1627407Skre return (sizeof (struct tsdevice)); 1633244Swnj } 1641900Swnj 1653244Swnj /* 16632579Sbostic * Map in the command, status, and characteristics packet. We 16732579Sbostic * make them contiguous to keep overhead down. This also sets 16832579Sbostic * sc_uba (which then never changes). 16932579Sbostic */ 17032579Sbostic tsmap(sc, uban, a) 17132579Sbostic register struct ts_softc *sc; 17232579Sbostic int uban, *a; 17332579Sbostic { 17432579Sbostic register int i; 17532579Sbostic 17632579Sbostic i = uballoc(uban, (caddr_t)&sc->sc_ts, sizeof(sc->sc_ts), 0); 17732579Sbostic if (a != NULL) 17832579Sbostic *a = i; 17932579Sbostic i = UBAI_ADDR(i); 18032579Sbostic sc->sc_ubaddr = (struct ts_tsdata *)i; 18132579Sbostic /* 18232579Sbostic * Note that i == the Unibus address of the command packet, 18332579Sbostic * and that it is a multiple of 4 (guaranteed by the compiler). 18432579Sbostic */ 18532579Sbostic sc->sc_uba = i + ((i >> 16) & 3); 18632579Sbostic } 18732579Sbostic 18832579Sbostic /* 1893244Swnj * TS11 only supports one drive per controller; 1903244Swnj * check for ui_slave == 0. 1913244Swnj */ 1923244Swnj /*ARGSUSED*/ 1933244Swnj tsslave(ui, reg) 1943244Swnj struct uba_device *ui; 1953244Swnj caddr_t reg; 1963244Swnj { 1971900Swnj 19832579Sbostic return (ui->ui_slave == 0); /* non-zero slave not allowed */ 1993244Swnj } 2001900Swnj 2013244Swnj /* 2023244Swnj * Record attachment of the unit to the controller. 2033244Swnj */ 2043244Swnj /*ARGSUSED*/ 2053244Swnj tsattach(ui) 2063244Swnj struct uba_device *ui; 2073244Swnj { 2081900Swnj 20932579Sbostic /* void */ 2103244Swnj } 2111900Swnj 2123244Swnj /* 2133244Swnj * Open the device. Tapes are unique open 2143244Swnj * devices, so we refuse if it is already open. 2153244Swnj */ 2161900Swnj tsopen(dev, flag) 2173244Swnj dev_t dev; 2183244Swnj int flag; 2191900Swnj { 22032579Sbostic register int tsunit = TSUNIT(dev); 2213244Swnj register struct uba_device *ui; 2223244Swnj register struct ts_softc *sc; 2231900Swnj 22432579Sbostic if (tsunit >= NTS || (ui = tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) 2258575Sroot return (ENXIO); 22632579Sbostic if ((sc = &ts_softc[ui->ui_ctlr])->sc_openf) 22725054Skarels return (EBUSY); 22830917Skarels sc->sc_openf = 1; 22932579Sbostic sc->sc_density = (minor(dev) & T_1600BPI) ? TS_NRZI : 0; 23032579Sbostic tscommand(dev, TS_SENSE, 1); 23132579Sbostic if (ctsbuf[tsunit].b_flags & B_ERROR) 23232579Sbostic /* 23332579Sbostic * Try it again in case it went off-line 23432579Sbostic */ 23532579Sbostic tscommand(dev, TS_SENSE, 1); 23632579Sbostic if (tsinit(ui->ui_ctlr)) { 23730917Skarels sc->sc_openf = 0; 2388575Sroot return (ENXIO); 23930917Skarels } 24032579Sbostic if ((sc->sc_ts.t_sts.s_xs0&TS_ONL) == 0) { 24130917Skarels sc->sc_openf = 0; 2423711Sroot uprintf("ts%d: not online\n", tsunit); 2438575Sroot return (EIO); 2441900Swnj } 24532579Sbostic if ((flag&FWRITE) && (sc->sc_ts.t_sts.s_xs0&TS_WLK)) { 24630917Skarels sc->sc_openf = 0; 2473711Sroot uprintf("ts%d: no write ring\n", tsunit); 2488575Sroot return (EIO); 2493711Sroot } 2503244Swnj sc->sc_blkno = (daddr_t)0; 2513244Swnj sc->sc_nxrec = INF; 2523244Swnj sc->sc_lastiow = 0; 25330917Skarels sc->sc_blks = 0; 25430917Skarels sc->sc_softerrs = 0; 255*44396Smarc sc->sc_tpr = tprintf_open(); 2568575Sroot return (0); 2571900Swnj } 2581900Swnj 2593244Swnj /* 2603244Swnj * Close tape device. 2613244Swnj * 2623244Swnj * If tape was open for writing or last operation was 2633244Swnj * a write, then write two EOF's and backspace over the last one. 2643244Swnj * Unless this is a non-rewinding special file, rewind the tape. 2653244Swnj * Make the tape available to others. 2663244Swnj */ 2671900Swnj tsclose(dev, flag) 2683244Swnj register dev_t dev; 26932579Sbostic register int flag; 2701900Swnj { 2713244Swnj register struct ts_softc *sc = &ts_softc[TSUNIT(dev)]; 2721900Swnj 2733244Swnj if (flag == FWRITE || (flag&FWRITE) && sc->sc_lastiow) { 2743244Swnj tscommand(dev, TS_WEOF, 1); 2753244Swnj tscommand(dev, TS_WEOF, 1); 2763244Swnj tscommand(dev, TS_SREV, 1); 2771900Swnj } 2783244Swnj if ((minor(dev)&T_NOREWIND) == 0) 2793244Swnj /* 2803244Swnj * 0 count means don't hang waiting for rewind complete 2813244Swnj * rather ctsbuf stays busy until the operation completes 2823244Swnj * preventing further opens from completing by 2833244Swnj * preventing a TS_SENSE from completing. 2843244Swnj */ 2853244Swnj tscommand(dev, TS_REW, 0); 28630917Skarels if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100) 28730917Skarels log(LOG_INFO, "ts%d: %d soft errors in %d blocks\n", 28830917Skarels TSUNIT(dev), sc->sc_softerrs, sc->sc_blks); 289*44396Smarc tprintf_close(sc->sc_tpr); 2903244Swnj sc->sc_openf = 0; 29140815Smarc return (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) 671*44396Smarc tprintf(sc->sc_tpr, "ts%d: write locked\n", 67232579Sbostic tsunit); 67332579Sbostic if ((sc->sc_ts.t_sts.s_xs0 & TS_ONL) == 0) 674*44396Smarc tprintf(sc->sc_tpr, "ts%d: offline\n", 67532579Sbostic tsunit); 6761900Swnj break; 6771900Swnj } 6783244Swnj /* 6793244Swnj * Couldn't recover error 6803244Swnj */ 681*44396Smarc tprintf(sc->sc_tpr, "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) 685*44396Smarc tprintf(sc->sc_tpr, " xs1=%b", sc->sc_ts.t_sts.s_xs1, 68618322Sralph TSXS1_BITS); 68732579Sbostic if (sc->sc_ts.t_sts.s_xs2) 688*44396Smarc tprintf(sc->sc_tpr, " xs2=%b", sc->sc_ts.t_sts.s_xs2, 68918322Sralph TSXS2_BITS); 69032579Sbostic if (sc->sc_ts.t_sts.s_xs3) 691*44396Smarc tprintf(sc->sc_tpr, " xs3=%b", sc->sc_ts.t_sts.s_xs3, 69218322Sralph TSXS3_BITS); 693*44396Smarc tprintf(sc->sc_tpr, "\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; 82640911Ssklower int fcount, error = 0; 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 } 86940911Ssklower if (bp->b_flags&B_ERROR) 87040911Ssklower if ((error = bp->b_error)==0) 87140911Ssklower return (EIO); 87240911Ssklower return (error); 8737633Ssam 8743244Swnj case MTIOCGET: 8757633Ssam mtget = (struct mtget *)data; 8767633Ssam mtget->mt_dsreg = 0; 87732579Sbostic mtget->mt_erreg = sc->sc_ts.t_sts.s_xs0; 8787633Ssam mtget->mt_resid = sc->sc_resid; 8797633Ssam mtget->mt_type = MT_ISTS; 8808575Sroot break; 8817633Ssam 8823244Swnj default: 8838575Sroot return (ENXIO); 8843244Swnj } 8858575Sroot return (0); 8861918Swnj } 8871918Swnj 8883244Swnj #define DBSIZE 20 8893244Swnj 89032579Sbostic tsdump(dev) 89132579Sbostic dev_t dev; 8921918Swnj { 8933244Swnj register struct uba_device *ui; 89432579Sbostic register struct uba_regs *uba; 8955693Sroot register struct tsdevice *addr; 89632579Sbostic register int i; 89732579Sbostic register struct pte *io; 89832579Sbostic int blk, num, unit, reg, start; 89932579Sbostic u_short db; 90032579Sbostic struct ts_tsdata *tc, *tc_ubaddr; 9011918Swnj 90232579Sbostic unit = TSUNIT(dev); 90332579Sbostic if (unit >= NTS) 90432579Sbostic return (ENXIO); 9053244Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 90632579Sbostic ui = phys(tsdinfo[unit], struct uba_device *); 90732579Sbostic if (ui->ui_alive == 0) 9083244Swnj return (ENXIO); 90932579Sbostic uba = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 91032579Sbostic ubainit(uba); 9115693Sroot addr = (struct tsdevice *)ui->ui_physaddr; 91232579Sbostic 91332579Sbostic /* map a ts_tsdata structure */ 91432579Sbostic tc = phys(&ts_softc[0].sc_ts, struct ts_tsdata *); 91532579Sbostic num = btoc(sizeof(struct ts_tsdata)) + 1; 91632579Sbostic io = &uba->uba_map[reg = NUBMREG - num]; 91732579Sbostic for (i = 0; i < num; i++) 91832579Sbostic *(int *)io++ = UBAMR_MRV | (btop(tc) + i); 91932579Sbostic i = (((int)tc & PGOFSET) | (reg << 9)); 92032579Sbostic tc_ubaddr = (struct ts_tsdata *)i; 92132579Sbostic db = i + ((i >> 16) & 3); 92232579Sbostic 92332579Sbostic /* init the drive */ 9243244Swnj addr->tssr = 0; 9253244Swnj tswait(addr); 92632579Sbostic if ((addr->tssr & (TS_NBA|TS_OFL)) != TS_NBA) 92732579Sbostic return (EFAULT); 92832579Sbostic 92932579Sbostic /* set characteristics */ 93032579Sbostic i = (int)&tc_ubaddr->t_char; 93132579Sbostic tc->t_cmd.c_loba = i; 93232579Sbostic tc->t_cmd.c_hiba = (i >> 16) & 3; 93332579Sbostic tc->t_cmd.c_size = sizeof(struct ts_char); 93432579Sbostic tc->t_cmd.c_cmd = TS_ACK | TS_CVC | TS_SETCHR; 93532579Sbostic tc->t_char.char_addr = (int)&tc_ubaddr->t_sts; 93632579Sbostic tc->t_char.char_size = sizeof(struct ts_sts); 93732579Sbostic tc->t_char.char_mode = TS_ESS; 93832579Sbostic addr->tsdb = db; 93932579Sbostic tswait(addr); 94032579Sbostic if (addr->tssr & TS_NBA) 94132579Sbostic return (ENXIO); 94232579Sbostic 94332579Sbostic /* dump */ 94432579Sbostic tc->t_cmd.c_cmd = TS_ACK | TS_WCOM; 94532579Sbostic tc->t_cmd.c_repcnt = 1; 94632579Sbostic num = maxfree; 94732579Sbostic for (start = 0, num = maxfree; num > 0; start += blk, num -= blk) { 9483244Swnj blk = num > DBSIZE ? DBSIZE : num; 94932579Sbostic io = uba->uba_map; 95032579Sbostic for (i = 0; i < blk; i++) 95132579Sbostic *(int *)io++ = UBAMR_MRV | (1 << UBAMR_DPSHIFT) | 95232579Sbostic (start + i); 95332579Sbostic *(int *)io = 0; 95432579Sbostic addr->tsdb = db; 95532579Sbostic tswait(addr); 9563244Swnj } 95732579Sbostic 95832579Sbostic /* eof */ 95932579Sbostic tc->t_cmd.c_cmd = TS_WEOF; 96032579Sbostic addr->tsdb = db; 9613244Swnj tswait(addr); 96232579Sbostic addr->tsdb = db; 96332579Sbostic tswait(addr); 96432579Sbostic 9653244Swnj if (addr->tssr&TS_SC) 9663244Swnj return (EIO); 9673244Swnj addr->tssr = 0; 9683244Swnj tswait(addr); 9693244Swnj return (0); 9701918Swnj } 9711918Swnj 9723244Swnj tswait(addr) 9735693Sroot register struct tsdevice *addr; 9741918Swnj { 9751918Swnj 97632579Sbostic while ((addr->tssr & TS_SSR) == 0) 97732579Sbostic /* void */; 9781918Swnj } 9791918Swnj 98032579Sbostic #endif /* NTS > 0 */ 981