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*40911Ssklower * @(#)ts.c 7.11 (Berkeley) 04/12/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 "user.h" 2540905Ssklower #include "proc.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 3637511Smckusick #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 */ 9940815Smarc caddr_t sc_ctty; /* user's controlling tty (vnode) */ 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; 25740815Smarc sc->sc_ctty = (caddr_t)(u.u_procp->p_flag&SCTTY ? 25840815Smarc u.u_procp->p_session->s_ttyvp : 0); 2598575Sroot return (0); 2601900Swnj } 2611900Swnj 2623244Swnj /* 2633244Swnj * Close tape device. 2643244Swnj * 2653244Swnj * If tape was open for writing or last operation was 2663244Swnj * a write, then write two EOF's and backspace over the last one. 2673244Swnj * Unless this is a non-rewinding special file, rewind the tape. 2683244Swnj * Make the tape available to others. 2693244Swnj */ 2701900Swnj tsclose(dev, flag) 2713244Swnj register dev_t dev; 27232579Sbostic register int flag; 2731900Swnj { 2743244Swnj register struct ts_softc *sc = &ts_softc[TSUNIT(dev)]; 2751900Swnj 2763244Swnj if (flag == FWRITE || (flag&FWRITE) && sc->sc_lastiow) { 2773244Swnj tscommand(dev, TS_WEOF, 1); 2783244Swnj tscommand(dev, TS_WEOF, 1); 2793244Swnj tscommand(dev, TS_SREV, 1); 2801900Swnj } 2813244Swnj if ((minor(dev)&T_NOREWIND) == 0) 2823244Swnj /* 2833244Swnj * 0 count means don't hang waiting for rewind complete 2843244Swnj * rather ctsbuf stays busy until the operation completes 2853244Swnj * preventing further opens from completing by 2863244Swnj * preventing a TS_SENSE from completing. 2873244Swnj */ 2883244Swnj tscommand(dev, TS_REW, 0); 28930917Skarels if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100) 29030917Skarels log(LOG_INFO, "ts%d: %d soft errors in %d blocks\n", 29130917Skarels TSUNIT(dev), sc->sc_softerrs, sc->sc_blks); 2923244Swnj sc->sc_openf = 0; 29340815Smarc return (0); 2941900Swnj } 2951900Swnj 2963244Swnj /* 29732579Sbostic * Initialize a TS11. Set device characteristics. 2983244Swnj */ 29932579Sbostic tsinit(ctlr) 30032579Sbostic register int ctlr; 3011900Swnj { 30232579Sbostic register struct ts_softc *sc = &ts_softc[ctlr]; 30332579Sbostic register struct uba_ctlr *um = tsminfo[ctlr]; 3045693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 3053244Swnj register int i; 3063244Swnj 30732579Sbostic if (addr->tssr & (TS_NBA|TS_OFL) || sc->sc_ts.t_sts.s_xs0 & TS_BOT) { 3083244Swnj addr->tssr = 0; /* subsystem initialize */ 3093244Swnj tswait(addr); 31032579Sbostic i = (int)&sc->sc_ubaddr->t_char; 31132579Sbostic sc->sc_ts.t_cmd.c_loba = i; 31232579Sbostic sc->sc_ts.t_cmd.c_hiba = (i >> 16) & 3; 31332579Sbostic sc->sc_ts.t_cmd.c_size = sizeof(struct ts_char); 31432579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_SETCHR; 31532579Sbostic sc->sc_ts.t_char.char_addr = (int)&sc->sc_ubaddr->t_sts; 31632579Sbostic sc->sc_ts.t_char.char_size = sizeof(struct ts_sts); 31732579Sbostic sc->sc_ts.t_char.char_mode = TS_ESS | TS_EAI | TS_ERI | 31832579Sbostic /* TS_ENB | */ sc->sc_density; 3193244Swnj addr->tsdb = sc->sc_uba; 3203244Swnj tswait(addr); 3213327Swnj if (addr->tssr & TS_NBA) 3223327Swnj return(1); 3233244Swnj } 3243244Swnj return(0); 3253244Swnj } 3263244Swnj 3273244Swnj /* 3283244Swnj * Execute a command on the tape drive 3293244Swnj * a specified number of times. 3303244Swnj */ 3313244Swnj tscommand(dev, com, count) 3323244Swnj dev_t dev; 3333244Swnj int com, count; 3343244Swnj { 3351900Swnj register struct buf *bp; 3365438Sroot register int s; 33732579Sbostic int didsleep = 0; 3381900Swnj 3393244Swnj bp = &ctsbuf[TSUNIT(dev)]; 3405438Sroot s = spl5(); 3413244Swnj while (bp->b_flags&B_BUSY) { 3423244Swnj /* 3433244Swnj * This special check is because B_BUSY never 3443244Swnj * gets cleared in the non-waiting rewind case. 3453244Swnj */ 3463244Swnj if (bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 3473244Swnj break; 3481900Swnj bp->b_flags |= B_WANTED; 3491900Swnj sleep((caddr_t)bp, PRIBIO); 35032579Sbostic didsleep = 1; 3511900Swnj } 3523244Swnj bp->b_flags = B_BUSY|B_READ; 3535438Sroot splx(s); 35432579Sbostic if (didsleep) 35532579Sbostic (void) tsinit(tsdinfo[TSUNIT(dev)]->ui_ctlr); 3563244Swnj bp->b_dev = dev; 3573244Swnj bp->b_repcnt = count; 3583244Swnj bp->b_command = com; 3591900Swnj bp->b_blkno = 0; 3601900Swnj tsstrategy(bp); 3613244Swnj /* 3623244Swnj * In case of rewind from close, don't wait. 3633244Swnj * This is the only case where count can be 0. 3643244Swnj */ 3653244Swnj if (count == 0) 3663244Swnj return; 36732579Sbostic biowait(bp); 3683244Swnj if (bp->b_flags&B_WANTED) 3691900Swnj wakeup((caddr_t)bp); 3703244Swnj bp->b_flags &= B_ERROR; 3711900Swnj } 3721900Swnj 3733244Swnj /* 3743244Swnj * Queue a tape operation. 3753244Swnj */ 3761900Swnj tsstrategy(bp) 3773244Swnj register struct buf *bp; 3781900Swnj { 37932579Sbostic register int tsunit = TSUNIT(bp->b_dev); 3803244Swnj register struct uba_ctlr *um; 3813327Swnj register struct buf *dp; 38232579Sbostic int s; 3831900Swnj 3843244Swnj /* 3853244Swnj * Put transfer at end of controller queue 3863244Swnj */ 3871900Swnj bp->av_forw = NULL; 3883244Swnj um = tsdinfo[tsunit]->ui_mi; 38932579Sbostic dp = &tsutab[tsunit]; 3905438Sroot s = spl5(); 3913327Swnj if (dp->b_actf == NULL) 3923327Swnj dp->b_actf = bp; 3931900Swnj else 3943327Swnj dp->b_actl->av_forw = bp; 3953327Swnj dp->b_actl = bp; 3963327Swnj um->um_tab.b_actf = um->um_tab.b_actl = dp; 3973244Swnj /* 3983244Swnj * If the controller is not busy, get 3993244Swnj * it going. 4003244Swnj */ 4013244Swnj if (um->um_tab.b_active == 0) 4023244Swnj tsstart(um); 4035438Sroot splx(s); 4041900Swnj } 4051900Swnj 4063244Swnj /* 4073244Swnj * Start activity on a ts controller. 4083244Swnj */ 4093244Swnj tsstart(um) 4103244Swnj register struct uba_ctlr *um; 4111900Swnj { 4121900Swnj register struct buf *bp; 4135693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 4143244Swnj register struct ts_softc *sc; 4153244Swnj register struct uba_device *ui; 41632579Sbostic register int tsunit; 41732579Sbostic int cmd; 4181900Swnj daddr_t blkno; 4191900Swnj 4203244Swnj /* 4213244Swnj * Start the controller if there is something for it to do. 4223244Swnj */ 4233244Swnj loop: 42432609Sbostic if ((bp = um->um_tab.b_actf->b_actf) == NULL) { 42532609Sbostic um->um_tab.b_active = 0; 4261900Swnj return; 42732609Sbostic } 4283244Swnj tsunit = TSUNIT(bp->b_dev); 4293244Swnj ui = tsdinfo[tsunit]; 4303244Swnj sc = &ts_softc[tsunit]; 4313244Swnj /* 4323244Swnj * Default is that last command was NOT a write command; 43332579Sbostic * if we finish a write command we will notice this in tsintr(). 4343244Swnj */ 4353656Swnj sc->sc_lastiow = 0; 4363244Swnj if (sc->sc_openf < 0 || (addr->tssr&TS_OFL)) { 4373244Swnj /* 4383244Swnj * Have had a hard error on a non-raw tape 4393244Swnj * or the tape unit is now unavailable 4403244Swnj * (e.g. taken off line). 4413244Swnj */ 4423244Swnj bp->b_flags |= B_ERROR; 4433244Swnj goto next; 4443244Swnj } 44532579Sbostic if (bp == &ctsbuf[tsunit]) { 4463244Swnj /* 4473244Swnj * Execute control operation with the specified count. 4483244Swnj */ 4493244Swnj um->um_tab.b_active = 4503244Swnj bp->b_command == TS_REW ? SREW : SCOM; 45132579Sbostic sc->sc_ts.t_cmd.c_repcnt = bp->b_repcnt; 4523244Swnj goto dobpcmd; 4533244Swnj } 4543244Swnj /* 45532579Sbostic * For raw I/O, save the current block 45632579Sbostic * number in case we have to retry. 4573244Swnj */ 45834217Sbostic if (bp->b_flags & B_RAW) { 45932579Sbostic if (um->um_tab.b_errcnt == 0) 46032579Sbostic sc->sc_blkno = bdbtofsb(bp->b_blkno); 46132579Sbostic } else { 4623244Swnj /* 46332579Sbostic * Handle boundary cases for operation 46432579Sbostic * on non-raw tapes. 4653244Swnj */ 46632579Sbostic if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 46732579Sbostic /* 46832579Sbostic * Can't read past known end-of-file. 46932579Sbostic */ 47032579Sbostic bp->b_flags |= B_ERROR; 47132579Sbostic bp->b_error = ENXIO; 47232579Sbostic goto next; 47332579Sbostic } 47432579Sbostic if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && 47532579Sbostic bp->b_flags&B_READ) { 47632579Sbostic /* 47732579Sbostic * Reading at end of file returns 0 bytes. 47832579Sbostic */ 47932579Sbostic bp->b_resid = bp->b_bcount; 48032579Sbostic clrbuf(bp); 48132579Sbostic goto next; 48232579Sbostic } 48332579Sbostic if ((bp->b_flags&B_READ) == 0) 48432579Sbostic /* 48532579Sbostic * Writing sets EOF 48632579Sbostic */ 48732579Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; 4883244Swnj } 48932579Sbostic 4903244Swnj /* 4913244Swnj * If the data transfer command is in the correct place, 4923244Swnj * set up all the registers except the csr, and give 4933244Swnj * control over to the UNIBUS adapter routines, to 4943244Swnj * wait for resources to start the i/o. 4953244Swnj */ 4967383Ssam if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { 49732579Sbostic sc->sc_ts.t_cmd.c_size = bp->b_bcount; 4983244Swnj if ((bp->b_flags&B_READ) == 0) 4993244Swnj cmd = TS_WCOM; 5001900Swnj else 5013244Swnj cmd = TS_RCOM; 5023244Swnj if (um->um_tab.b_errcnt) 5033244Swnj cmd |= TS_RETRY; 5043244Swnj um->um_tab.b_active = SIO; 50532579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_IE | cmd; 5063244Swnj (void) ubago(ui); 5073244Swnj return; 5083244Swnj } 5093244Swnj /* 5103244Swnj * Tape positioned incorrectly; 5113244Swnj * set to seek forwards or backwards to the correct spot. 5123244Swnj * This happens for raw tapes only on error retries. 5133244Swnj */ 5143244Swnj um->um_tab.b_active = SSEEK; 5157383Ssam if (blkno < bdbtofsb(bp->b_blkno)) { 5163244Swnj bp->b_command = TS_SFORW; 51732579Sbostic sc->sc_ts.t_cmd.c_repcnt = bdbtofsb(bp->b_blkno) - blkno; 5181900Swnj } else { 5193244Swnj bp->b_command = TS_SREV; 52032579Sbostic sc->sc_ts.t_cmd.c_repcnt = blkno - bdbtofsb(bp->b_blkno); 5211900Swnj } 5223244Swnj dobpcmd: 5233244Swnj /* 5243244Swnj * Do the command in bp. 5253244Swnj */ 52632579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_IE | bp->b_command; 5273244Swnj addr->tsdb = sc->sc_uba; 5281900Swnj return; 5291900Swnj 5303244Swnj next: 5313244Swnj /* 5323244Swnj * Done with this operation due to error or 5333244Swnj * the fact that it doesn't do anything. 5343244Swnj * Release UBA resources (if any), dequeue 5353244Swnj * the transfer and continue processing this slave. 5363244Swnj */ 5373244Swnj if (um->um_ubinfo) 5383244Swnj ubadone(um); 5393244Swnj um->um_tab.b_errcnt = 0; 5403327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 54132579Sbostic biodone(bp); 5421900Swnj goto loop; 5431900Swnj } 5441900Swnj 5453244Swnj /* 5463244Swnj * The UNIBUS resources we needed have been 5473244Swnj * allocated to us; start the device. 5483244Swnj */ 5493244Swnj tsdgo(um) 5503244Swnj register struct uba_ctlr *um; 5511900Swnj { 5523244Swnj register struct ts_softc *sc = &ts_softc[um->um_ctlr]; 5533327Swnj register int i; 5543244Swnj 55526139Skarels /* 55626139Skarels * The uba code uses byte-offset mode if using bdp; 55726139Skarels * mask off the low bit here. 55826139Skarels */ 55932579Sbostic i = UBAI_ADDR(um->um_ubinfo); 56026139Skarels if (UBAI_BDP(um->um_ubinfo)) 56126139Skarels i &= ~1; 56232579Sbostic sc->sc_ts.t_cmd.c_loba = i; 56332579Sbostic sc->sc_ts.t_cmd.c_hiba = (i >> 16) & 3; 56432579Sbostic ((struct tsdevice *)um->um_addr)->tsdb = sc->sc_uba; 5653244Swnj } 5663244Swnj 5673244Swnj /* 5683244Swnj * Ts interrupt routine. 5693244Swnj */ 5703244Swnj /*ARGSUSED*/ 57132579Sbostic tsintr(tsunit) 57232579Sbostic register int tsunit; 5733244Swnj { 5741900Swnj register struct buf *bp; 57532579Sbostic register struct uba_ctlr *um; 5765693Sroot register struct tsdevice *addr; 5773244Swnj register struct ts_softc *sc; 57832579Sbostic register int state; 57932579Sbostic 58035401Stef #ifdef QBA 58132579Sbostic (void) spl5(); 58227253Skridle #endif 58332579Sbostic um = tsdinfo[tsunit]->ui_mi; 5843327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 5851900Swnj return; 58632579Sbostic addr = (struct tsdevice *)um->um_addr; 5873244Swnj /* 5883244Swnj * If last command was a rewind, and tape is still 5893244Swnj * rewinding, wait for the rewind complete interrupt. 5903244Swnj * 5913244Swnj * SHOULD NEVER GET AN INTERRUPT IN THIS STATE. 5923244Swnj */ 5933244Swnj if (um->um_tab.b_active == SREW) { 5943244Swnj um->um_tab.b_active = SCOM; 5953244Swnj if ((addr->tssr&TS_SSR) == 0) 5963244Swnj return; 5973244Swnj } 5983244Swnj /* 5993244Swnj * An operation completed... record status 6003244Swnj */ 60132579Sbostic sc = &ts_softc[um->um_ctlr]; 6023244Swnj if ((bp->b_flags & B_READ) == 0) 6033244Swnj sc->sc_lastiow = 1; 6043244Swnj state = um->um_tab.b_active; 6053244Swnj /* 6063244Swnj * Check for errors. 6073244Swnj */ 6083244Swnj if (addr->tssr&TS_SC) { 6093244Swnj switch (addr->tssr & TS_TC) { 6103244Swnj case TS_UNREC: /* unrecoverable */ 6113244Swnj case TS_FATAL: /* fatal error */ 6123244Swnj case TS_RECNM: /* recoverable, no motion */ 6133244Swnj break; 61432579Sbostic case TS_ATTN: /* attention */ 61532579Sbostic if (sc->sc_ts.t_sts.s_xs0 & TS_VCK) { 61632579Sbostic /* volume check - may have changed tapes */ 61732579Sbostic bp->b_flags |= B_ERROR; 61832579Sbostic goto ignoreerr; 61932579Sbostic } 62032579Sbostic break; 6211900Swnj 6223244Swnj case TS_SUCC: /* success termination */ 62332579Sbostic printf("ts%d: success\n", tsunit); 6243244Swnj goto ignoreerr; 6251900Swnj 6263244Swnj case TS_ALERT: /* tape status alert */ 6273244Swnj /* 6283244Swnj * If we hit the end of the tape file, 6293244Swnj * update our position. 6303244Swnj */ 63132579Sbostic if (sc->sc_ts.t_sts.s_xs0 & (TS_TMK|TS_EOT)) { 63232579Sbostic tsseteof(bp); /* set blkno and nxrec */ 63332579Sbostic state = SCOM; /* force completion */ 6343244Swnj /* 6353244Swnj * Stuff bc so it will be unstuffed correctly 6363244Swnj * later to get resid. 6373244Swnj */ 63832579Sbostic sc->sc_ts.t_sts.s_rbpcr = bp->b_bcount; 6393244Swnj goto opdone; 6403244Swnj } 6413244Swnj /* 64232579Sbostic * If we were reading raw tape and the record was too 64332579Sbostic * long or too short, we don't consider this an error. 6443244Swnj */ 64534217Sbostic if ((bp->b_flags & (B_READ|B_RAW)) == (B_READ|B_RAW) && 64632579Sbostic sc->sc_ts.t_sts.s_xs0&(TS_RLS|TS_RLL)) 6473244Swnj goto ignoreerr; 64832579Sbostic /* FALLTHROUGH */ 64932579Sbostic 6503244Swnj case TS_RECOV: /* recoverable, tape moved */ 6513244Swnj /* 6523244Swnj * If this was an i/o operation retry up to 8 times. 6533244Swnj */ 65432579Sbostic if (state == SIO) { 6553244Swnj if (++um->um_tab.b_errcnt < 7) { 6563244Swnj ubadone(um); 6573244Swnj goto opcont; 6583244Swnj } else 6593244Swnj sc->sc_blkno++; 6603244Swnj } else { 6613244Swnj /* 6623244Swnj * Non-i/o errors on non-raw tape 6633244Swnj * cause it to close. 6643244Swnj */ 66534217Sbostic if ((bp->b_flags&B_RAW) == 0 && 66634217Sbostic sc->sc_openf > 0) 6673244Swnj sc->sc_openf = -1; 6683244Swnj } 6691900Swnj break; 6703244Swnj 6713244Swnj case TS_REJECT: /* function reject */ 67232579Sbostic if (state == SIO && sc->sc_ts.t_sts.s_xs0 & TS_WLE) 67340815Smarc tprintf(sc->sc_ctty, "ts%d: write locked\n", 67432579Sbostic tsunit); 67532579Sbostic if ((sc->sc_ts.t_sts.s_xs0 & TS_ONL) == 0) 67640815Smarc tprintf(sc->sc_ctty, "ts%d: offline\n", 67732579Sbostic tsunit); 6781900Swnj break; 6791900Swnj } 6803244Swnj /* 6813244Swnj * Couldn't recover error 6823244Swnj */ 68340815Smarc tprintf(sc->sc_ctty, "ts%d: hard error bn%d tssr=%b xs0=%b", 68432579Sbostic tsunit, bp->b_blkno, addr->tssr, TSSR_BITS, 68532579Sbostic sc->sc_ts.t_sts.s_xs0, TSXS0_BITS); 68632579Sbostic if (sc->sc_ts.t_sts.s_xs1) 68740815Smarc tprintf(sc->sc_ctty, " xs1=%b", sc->sc_ts.t_sts.s_xs1, 68818322Sralph TSXS1_BITS); 68932579Sbostic if (sc->sc_ts.t_sts.s_xs2) 69040815Smarc tprintf(sc->sc_ctty, " xs2=%b", sc->sc_ts.t_sts.s_xs2, 69118322Sralph TSXS2_BITS); 69232579Sbostic if (sc->sc_ts.t_sts.s_xs3) 69340815Smarc tprintf(sc->sc_ctty, " xs3=%b", sc->sc_ts.t_sts.s_xs3, 69418322Sralph TSXS3_BITS); 69540815Smarc tprintf(sc->sc_ctty, "\n"); 6963244Swnj bp->b_flags |= B_ERROR; 6973244Swnj goto opdone; 6983244Swnj } 6993244Swnj /* 7003244Swnj * Advance tape control FSM. 7013244Swnj */ 7023244Swnj ignoreerr: 7033244Swnj switch (state) { 7041900Swnj 7053244Swnj case SIO: 7063244Swnj /* 7073244Swnj * Read/write increments tape block number 7083244Swnj */ 7093244Swnj sc->sc_blkno++; 71030917Skarels sc->sc_blks++; 71130917Skarels if (um->um_tab.b_errcnt) 71230917Skarels sc->sc_softerrs++; 7133244Swnj goto opdone; 7141900Swnj 7151900Swnj case SCOM: 7163244Swnj /* 7173244Swnj * For forward/backward space record update current position. 7183244Swnj */ 71932579Sbostic if (bp == &ctsbuf[tsunit]) 72032579Sbostic switch ((int)bp->b_command) { 7211900Swnj 72232579Sbostic case TS_SFORW: 72332579Sbostic sc->sc_blkno += bp->b_repcnt; 72432579Sbostic break; 7251900Swnj 72632579Sbostic case TS_SREV: 72732579Sbostic sc->sc_blkno -= bp->b_repcnt; 72832579Sbostic break; 72932579Sbostic } 7303244Swnj goto opdone; 7313244Swnj 7323244Swnj case SSEEK: 7337383Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno); 7343244Swnj goto opcont; 7353244Swnj 7361900Swnj default: 7373244Swnj panic("tsintr"); 7381900Swnj } 7393244Swnj opdone: 7403244Swnj /* 7413244Swnj * Reset error count and remove 7423244Swnj * from device queue. 7433244Swnj */ 7443244Swnj um->um_tab.b_errcnt = 0; 7453327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 74632579Sbostic bp->b_resid = sc->sc_ts.t_sts.s_rbpcr; 7473244Swnj ubadone(um); 74832579Sbostic biodone(bp); 74932579Sbostic if (um->um_tab.b_actf->b_actf == 0) { 75032579Sbostic um->um_tab.b_active = 0; 7513244Swnj return; 75232579Sbostic } 7533244Swnj opcont: 7543244Swnj tsstart(um); 7553244Swnj } 7563244Swnj 7573244Swnj tsseteof(bp) 7583244Swnj register struct buf *bp; 7593244Swnj { 7603244Swnj register int tsunit = TSUNIT(bp->b_dev); 76132579Sbostic register struct ts_softc *sc = &ts_softc[tsdinfo[tsunit]->ui_ctlr]; 7623244Swnj 76332579Sbostic if (bp == &ctsbuf[tsunit]) { 7647383Ssam if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 7653244Swnj /* reversing */ 76632579Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) - 76732579Sbostic sc->sc_ts.t_sts.s_rbpcr; 7683244Swnj sc->sc_blkno = sc->sc_nxrec; 7693244Swnj } else { 7703244Swnj /* spacing forward */ 77132579Sbostic sc->sc_blkno = bdbtofsb(bp->b_blkno) + 77232579Sbostic sc->sc_ts.t_sts.s_rbpcr; 7733244Swnj sc->sc_nxrec = sc->sc_blkno - 1; 7741900Swnj } 7753244Swnj return; 7763244Swnj } 7773244Swnj /* eof on read */ 7787383Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno); 7791900Swnj } 7801900Swnj 7813244Swnj tsreset(uban) 7823244Swnj int uban; 7831918Swnj { 7843244Swnj register struct uba_ctlr *um; 7855693Sroot register struct uba_device *ui; 78632579Sbostic register int ts11, i; 7871918Swnj 7883244Swnj for (ts11 = 0; ts11 < NTS; ts11++) { 7893244Swnj if ((um = tsminfo[ts11]) == 0 || um->um_alive == 0 || 79032579Sbostic um->um_ubanum != uban) 7913244Swnj continue; 7923244Swnj printf(" ts%d", ts11); 7933244Swnj um->um_tab.b_active = 0; 7943244Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7955693Sroot if (ts_softc[ts11].sc_openf > 0) 7965693Sroot ts_softc[ts11].sc_openf = -1; 7973244Swnj if (um->um_ubinfo) { 79832579Sbostic printf("<%d>", UBAI_BDP(um->um_ubinfo)); 7999356Ssam um->um_ubinfo = 0; 8003244Swnj } 80132579Sbostic /* 80232579Sbostic * tsdinfo should be 1-to-1 with tsminfo, but someone 80332579Sbostic * might have screwed up the config file: 80432579Sbostic */ 80532579Sbostic for (i = 0; i < NTS; i++) { 80632579Sbostic if ((ui = tsdinfo[i]) != NULL && 80732579Sbostic ui->ui_alive && ui->ui_mi == um) { 80832579Sbostic um->um_tab.b_actf = um->um_tab.b_actl = 80932579Sbostic &tsutab[i]; 81032579Sbostic break; 81132579Sbostic } 8125693Sroot } 81332579Sbostic tsmap(&ts_softc[ts11], uban, (int *)NULL); 8143989Sroot (void) tsinit(ts11); 8153244Swnj tsstart(um); 8161918Swnj } 8171918Swnj } 8181918Swnj 8193244Swnj /*ARGSUSED*/ 8207633Ssam tsioctl(dev, cmd, data, flag) 8217633Ssam caddr_t data; 8223244Swnj dev_t dev; 8231918Swnj { 8243244Swnj int tsunit = TSUNIT(dev); 82532579Sbostic register struct ts_softc *sc = &ts_softc[tsdinfo[tsunit]->ui_ctlr]; 8263244Swnj register struct buf *bp = &ctsbuf[TSUNIT(dev)]; 82732579Sbostic register int callcount; 828*40911Ssklower int fcount, error = 0; 8297633Ssam struct mtop *mtop; 8307633Ssam struct mtget *mtget; 8313244Swnj /* we depend of the values and order of the MT codes here */ 83232579Sbostic static int tsops[] = 8333656Swnj {TS_WEOF,TS_SFORWF,TS_SREVF,TS_SFORW,TS_SREV,TS_REW,TS_OFFL,TS_SENSE}; 8341918Swnj 8353244Swnj switch (cmd) { 8367633Ssam 8373244Swnj case MTIOCTOP: /* tape operation */ 8387633Ssam mtop = (struct mtop *)data; 8398575Sroot switch (mtop->mt_op) { 8407633Ssam 8413244Swnj case MTWEOF: 8427633Ssam callcount = mtop->mt_count; 8433244Swnj fcount = 1; 8443244Swnj break; 8457633Ssam 8463244Swnj case MTFSF: case MTBSF: 8473244Swnj case MTFSR: case MTBSR: 8483244Swnj callcount = 1; 8497633Ssam fcount = mtop->mt_count; 8503244Swnj break; 8517633Ssam 8523244Swnj case MTREW: case MTOFFL: case MTNOP: 8533244Swnj callcount = 1; 8543244Swnj fcount = 1; 8553244Swnj break; 8567633Ssam 8573244Swnj default: 8588575Sroot return (ENXIO); 8593244Swnj } 8608575Sroot if (callcount <= 0 || fcount <= 0) 8618575Sroot return (EINVAL); 8623244Swnj while (--callcount >= 0) { 8637633Ssam tscommand(dev, tsops[mtop->mt_op], fcount); 8647633Ssam if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) && 8658611Sroot bp->b_resid) 8668575Sroot return (EIO); 86732579Sbostic if ((bp->b_flags&B_ERROR) || 86832579Sbostic sc->sc_ts.t_sts.s_xs0&TS_BOT) 8693244Swnj break; 8703244Swnj } 871*40911Ssklower if (bp->b_flags&B_ERROR) 872*40911Ssklower if ((error = bp->b_error)==0) 873*40911Ssklower return (EIO); 874*40911Ssklower return (error); 8757633Ssam 8763244Swnj case MTIOCGET: 8777633Ssam mtget = (struct mtget *)data; 8787633Ssam mtget->mt_dsreg = 0; 87932579Sbostic mtget->mt_erreg = sc->sc_ts.t_sts.s_xs0; 8807633Ssam mtget->mt_resid = sc->sc_resid; 8817633Ssam mtget->mt_type = MT_ISTS; 8828575Sroot break; 8837633Ssam 8843244Swnj default: 8858575Sroot return (ENXIO); 8863244Swnj } 8878575Sroot return (0); 8881918Swnj } 8891918Swnj 8903244Swnj #define DBSIZE 20 8913244Swnj 89232579Sbostic tsdump(dev) 89332579Sbostic dev_t dev; 8941918Swnj { 8953244Swnj register struct uba_device *ui; 89632579Sbostic register struct uba_regs *uba; 8975693Sroot register struct tsdevice *addr; 89832579Sbostic register int i; 89932579Sbostic register struct pte *io; 90032579Sbostic int blk, num, unit, reg, start; 90132579Sbostic u_short db; 90232579Sbostic struct ts_tsdata *tc, *tc_ubaddr; 9031918Swnj 90432579Sbostic unit = TSUNIT(dev); 90532579Sbostic if (unit >= NTS) 90632579Sbostic return (ENXIO); 9073244Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 90832579Sbostic ui = phys(tsdinfo[unit], struct uba_device *); 90932579Sbostic if (ui->ui_alive == 0) 9103244Swnj return (ENXIO); 91132579Sbostic uba = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 91232579Sbostic ubainit(uba); 9135693Sroot addr = (struct tsdevice *)ui->ui_physaddr; 91432579Sbostic 91532579Sbostic /* map a ts_tsdata structure */ 91632579Sbostic tc = phys(&ts_softc[0].sc_ts, struct ts_tsdata *); 91732579Sbostic num = btoc(sizeof(struct ts_tsdata)) + 1; 91832579Sbostic io = &uba->uba_map[reg = NUBMREG - num]; 91932579Sbostic for (i = 0; i < num; i++) 92032579Sbostic *(int *)io++ = UBAMR_MRV | (btop(tc) + i); 92132579Sbostic i = (((int)tc & PGOFSET) | (reg << 9)); 92232579Sbostic tc_ubaddr = (struct ts_tsdata *)i; 92332579Sbostic db = i + ((i >> 16) & 3); 92432579Sbostic 92532579Sbostic /* init the drive */ 9263244Swnj addr->tssr = 0; 9273244Swnj tswait(addr); 92832579Sbostic if ((addr->tssr & (TS_NBA|TS_OFL)) != TS_NBA) 92932579Sbostic return (EFAULT); 93032579Sbostic 93132579Sbostic /* set characteristics */ 93232579Sbostic i = (int)&tc_ubaddr->t_char; 93332579Sbostic tc->t_cmd.c_loba = i; 93432579Sbostic tc->t_cmd.c_hiba = (i >> 16) & 3; 93532579Sbostic tc->t_cmd.c_size = sizeof(struct ts_char); 93632579Sbostic tc->t_cmd.c_cmd = TS_ACK | TS_CVC | TS_SETCHR; 93732579Sbostic tc->t_char.char_addr = (int)&tc_ubaddr->t_sts; 93832579Sbostic tc->t_char.char_size = sizeof(struct ts_sts); 93932579Sbostic tc->t_char.char_mode = TS_ESS; 94032579Sbostic addr->tsdb = db; 94132579Sbostic tswait(addr); 94232579Sbostic if (addr->tssr & TS_NBA) 94332579Sbostic return (ENXIO); 94432579Sbostic 94532579Sbostic /* dump */ 94632579Sbostic tc->t_cmd.c_cmd = TS_ACK | TS_WCOM; 94732579Sbostic tc->t_cmd.c_repcnt = 1; 94832579Sbostic num = maxfree; 94932579Sbostic for (start = 0, num = maxfree; num > 0; start += blk, num -= blk) { 9503244Swnj blk = num > DBSIZE ? DBSIZE : num; 95132579Sbostic io = uba->uba_map; 95232579Sbostic for (i = 0; i < blk; i++) 95332579Sbostic *(int *)io++ = UBAMR_MRV | (1 << UBAMR_DPSHIFT) | 95432579Sbostic (start + i); 95532579Sbostic *(int *)io = 0; 95632579Sbostic addr->tsdb = db; 95732579Sbostic tswait(addr); 9583244Swnj } 95932579Sbostic 96032579Sbostic /* eof */ 96132579Sbostic tc->t_cmd.c_cmd = TS_WEOF; 96232579Sbostic addr->tsdb = db; 9633244Swnj tswait(addr); 96432579Sbostic addr->tsdb = db; 96532579Sbostic tswait(addr); 96632579Sbostic 9673244Swnj if (addr->tssr&TS_SC) 9683244Swnj return (EIO); 9693244Swnj addr->tssr = 0; 9703244Swnj tswait(addr); 9713244Swnj return (0); 9721918Swnj } 9731918Swnj 9743244Swnj tswait(addr) 9755693Sroot register struct tsdevice *addr; 9761918Swnj { 9771918Swnj 97832579Sbostic while ((addr->tssr & TS_SSR) == 0) 97932579Sbostic /* void */; 9801918Swnj } 9811918Swnj 98232579Sbostic #endif /* NTS > 0 */ 983