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*52683Storek * @(#)ts.c 7.15 (Berkeley) 02/27/92
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 */
2045808Sbostic #include "sys/param.h"
2145808Sbostic #include "sys/systm.h"
2245808Sbostic #include "sys/buf.h"
2345808Sbostic #include "sys/conf.h"
2445808Sbostic #include "sys/errno.h"
2545808Sbostic #include "sys/file.h"
2645808Sbostic #include "sys/map.h"
2745808Sbostic #include "sys/vm.h"
2845808Sbostic #include "sys/ioctl.h"
2945808Sbostic #include "sys/mtio.h"
3045808Sbostic #include "sys/cmap.h"
3145808Sbostic #include "sys/uio.h"
3245808Sbostic #include "sys/syslog.h"
3345808Sbostic #include "sys/tprintf.h"
341900Swnj
3545808Sbostic #include "../include/pte.h"
3645808Sbostic #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*/
tsprobe(reg,ctlr,um)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;
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];
142*52683Storek tsmap(sc, numuba);
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);
157*52683Storek /*
158*52683Storek * The controller should have interrupted by now, but some do not,
159*52683Storek * even if the delays above are extended to many seconds. If the
160*52683Storek * vector is still unknown, we assume the drive is present at
161*52683Storek * the usual vector.
162*52683Storek */
163*52683Storek if (cvec == 0 || cvec == 0x200) {
164*52683Storek cvec = (int)reg & 7 ? 0260 : 0224;
165*52683Storek br = 0x15;
166*52683Storek }
167*52683Storek return (sizeof(struct tsdevice));
1683244Swnj }
1691900Swnj
1703244Swnj /*
17132579Sbostic * Map in the command, status, and characteristics packet. We
17232579Sbostic * make them contiguous to keep overhead down. This also sets
17332579Sbostic * sc_uba (which then never changes).
17432579Sbostic */
tsmap(sc,uban)175*52683Storek tsmap(sc, uban)
17632579Sbostic register struct ts_softc *sc;
177*52683Storek int uban;
17832579Sbostic {
17932579Sbostic register int i;
18032579Sbostic
18132579Sbostic i = uballoc(uban, (caddr_t)&sc->sc_ts, sizeof(sc->sc_ts), 0);
18232579Sbostic i = UBAI_ADDR(i);
18332579Sbostic sc->sc_ubaddr = (struct ts_tsdata *)i;
18432579Sbostic /*
18532579Sbostic * Note that i == the Unibus address of the command packet,
18632579Sbostic * and that it is a multiple of 4 (guaranteed by the compiler).
18732579Sbostic */
18832579Sbostic sc->sc_uba = i + ((i >> 16) & 3);
18932579Sbostic }
19032579Sbostic
19132579Sbostic /*
1923244Swnj * TS11 only supports one drive per controller;
1933244Swnj * check for ui_slave == 0.
1943244Swnj */
1953244Swnj /*ARGSUSED*/
1963244Swnj tsslave(ui, reg)
1973244Swnj struct uba_device *ui;
1983244Swnj caddr_t reg;
1993244Swnj {
2001900Swnj
20132579Sbostic return (ui->ui_slave == 0); /* non-zero slave not allowed */
2023244Swnj }
2031900Swnj
2043244Swnj /*
2053244Swnj * Record attachment of the unit to the controller.
2063244Swnj */
2073244Swnj /*ARGSUSED*/
2083244Swnj tsattach(ui)
2093244Swnj struct uba_device *ui;
2103244Swnj {
2111900Swnj
21232579Sbostic /* void */
2133244Swnj }
2141900Swnj
2153244Swnj /*
2163244Swnj * Open the device. Tapes are unique open
2173244Swnj * devices, so we refuse if it is already open.
2183244Swnj */
tsopen(dev,flag)2191900Swnj tsopen(dev, flag)
2203244Swnj dev_t dev;
2213244Swnj int flag;
2221900Swnj {
22332579Sbostic register int tsunit = TSUNIT(dev);
2243244Swnj register struct uba_device *ui;
2253244Swnj register struct ts_softc *sc;
2261900Swnj
22732579Sbostic if (tsunit >= NTS || (ui = tsdinfo[tsunit]) == 0 || ui->ui_alive == 0)
2288575Sroot return (ENXIO);
22932579Sbostic if ((sc = &ts_softc[ui->ui_ctlr])->sc_openf)
23025054Skarels return (EBUSY);
23130917Skarels sc->sc_openf = 1;
23232579Sbostic sc->sc_density = (minor(dev) & T_1600BPI) ? TS_NRZI : 0;
23332579Sbostic tscommand(dev, TS_SENSE, 1);
23432579Sbostic if (ctsbuf[tsunit].b_flags & B_ERROR)
23532579Sbostic /*
23632579Sbostic * Try it again in case it went off-line
23732579Sbostic */
23832579Sbostic tscommand(dev, TS_SENSE, 1);
23932579Sbostic if (tsinit(ui->ui_ctlr)) {
24030917Skarels sc->sc_openf = 0;
2418575Sroot return (ENXIO);
24230917Skarels }
24332579Sbostic if ((sc->sc_ts.t_sts.s_xs0&TS_ONL) == 0) {
24430917Skarels sc->sc_openf = 0;
2453711Sroot uprintf("ts%d: not online\n", tsunit);
2468575Sroot return (EIO);
2471900Swnj }
24832579Sbostic if ((flag&FWRITE) && (sc->sc_ts.t_sts.s_xs0&TS_WLK)) {
24930917Skarels sc->sc_openf = 0;
2503711Sroot uprintf("ts%d: no write ring\n", tsunit);
2518575Sroot return (EIO);
2523711Sroot }
2533244Swnj sc->sc_blkno = (daddr_t)0;
2543244Swnj sc->sc_nxrec = INF;
2553244Swnj sc->sc_lastiow = 0;
25630917Skarels sc->sc_blks = 0;
25730917Skarels sc->sc_softerrs = 0;
25844396Smarc sc->sc_tpr = tprintf_open();
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 */
tsclose(dev,flag)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);
29244396Smarc tprintf_close(sc->sc_tpr);
2933244Swnj sc->sc_openf = 0;
29440815Smarc return (0);
2951900Swnj }
2961900Swnj
2973244Swnj /*
29832579Sbostic * Initialize a TS11. Set device characteristics.
2993244Swnj */
tsinit(ctlr)30032579Sbostic tsinit(ctlr)
30132579Sbostic register int ctlr;
3021900Swnj {
30332579Sbostic register struct ts_softc *sc = &ts_softc[ctlr];
30432579Sbostic register struct uba_ctlr *um = tsminfo[ctlr];
3055693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr;
3063244Swnj register int i;
3073244Swnj
30832579Sbostic if (addr->tssr & (TS_NBA|TS_OFL) || sc->sc_ts.t_sts.s_xs0 & TS_BOT) {
3093244Swnj addr->tssr = 0; /* subsystem initialize */
3103244Swnj tswait(addr);
31132579Sbostic i = (int)&sc->sc_ubaddr->t_char;
31232579Sbostic sc->sc_ts.t_cmd.c_loba = i;
31332579Sbostic sc->sc_ts.t_cmd.c_hiba = (i >> 16) & 3;
31432579Sbostic sc->sc_ts.t_cmd.c_size = sizeof(struct ts_char);
31532579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_SETCHR;
31632579Sbostic sc->sc_ts.t_char.char_addr = (int)&sc->sc_ubaddr->t_sts;
31732579Sbostic sc->sc_ts.t_char.char_size = sizeof(struct ts_sts);
31832579Sbostic sc->sc_ts.t_char.char_mode = TS_ESS | TS_EAI | TS_ERI |
31932579Sbostic /* TS_ENB | */ sc->sc_density;
3203244Swnj addr->tsdb = sc->sc_uba;
3213244Swnj tswait(addr);
3223327Swnj if (addr->tssr & TS_NBA)
3233327Swnj return(1);
3243244Swnj }
3253244Swnj return(0);
3263244Swnj }
3273244Swnj
3283244Swnj /*
3293244Swnj * Execute a command on the tape drive
3303244Swnj * a specified number of times.
3313244Swnj */
tscommand(dev,com,count)3323244Swnj tscommand(dev, com, count)
3333244Swnj dev_t dev;
3343244Swnj int com, count;
3353244Swnj {
3361900Swnj register struct buf *bp;
3375438Sroot register int s;
33832579Sbostic int didsleep = 0;
3391900Swnj
3403244Swnj bp = &ctsbuf[TSUNIT(dev)];
3415438Sroot s = spl5();
3423244Swnj while (bp->b_flags&B_BUSY) {
3433244Swnj /*
3443244Swnj * This special check is because B_BUSY never
3453244Swnj * gets cleared in the non-waiting rewind case.
3463244Swnj */
3473244Swnj if (bp->b_repcnt == 0 && (bp->b_flags&B_DONE))
3483244Swnj break;
3491900Swnj bp->b_flags |= B_WANTED;
3501900Swnj sleep((caddr_t)bp, PRIBIO);
35132579Sbostic didsleep = 1;
3521900Swnj }
3533244Swnj bp->b_flags = B_BUSY|B_READ;
3545438Sroot splx(s);
35532579Sbostic if (didsleep)
35632579Sbostic (void) tsinit(tsdinfo[TSUNIT(dev)]->ui_ctlr);
3573244Swnj bp->b_dev = dev;
3583244Swnj bp->b_repcnt = count;
3593244Swnj bp->b_command = com;
3601900Swnj bp->b_blkno = 0;
3611900Swnj tsstrategy(bp);
3623244Swnj /*
3633244Swnj * In case of rewind from close, don't wait.
3643244Swnj * This is the only case where count can be 0.
3653244Swnj */
3663244Swnj if (count == 0)
3673244Swnj return;
36832579Sbostic biowait(bp);
3693244Swnj if (bp->b_flags&B_WANTED)
3701900Swnj wakeup((caddr_t)bp);
3713244Swnj bp->b_flags &= B_ERROR;
3721900Swnj }
3731900Swnj
3743244Swnj /*
3753244Swnj * Queue a tape operation.
3763244Swnj */
tsstrategy(bp)3771900Swnj tsstrategy(bp)
3783244Swnj register struct buf *bp;
3791900Swnj {
38032579Sbostic register int tsunit = TSUNIT(bp->b_dev);
3813244Swnj register struct uba_ctlr *um;
3823327Swnj register struct buf *dp;
38332579Sbostic int s;
3841900Swnj
3853244Swnj /*
3863244Swnj * Put transfer at end of controller queue
3873244Swnj */
3881900Swnj bp->av_forw = NULL;
3893244Swnj um = tsdinfo[tsunit]->ui_mi;
39032579Sbostic dp = &tsutab[tsunit];
3915438Sroot s = spl5();
3923327Swnj if (dp->b_actf == NULL)
3933327Swnj dp->b_actf = bp;
3941900Swnj else
3953327Swnj dp->b_actl->av_forw = bp;
3963327Swnj dp->b_actl = bp;
3973327Swnj um->um_tab.b_actf = um->um_tab.b_actl = dp;
3983244Swnj /*
3993244Swnj * If the controller is not busy, get
4003244Swnj * it going.
4013244Swnj */
4023244Swnj if (um->um_tab.b_active == 0)
4033244Swnj tsstart(um);
4045438Sroot splx(s);
4051900Swnj }
4061900Swnj
4073244Swnj /*
4083244Swnj * Start activity on a ts controller.
4093244Swnj */
tsstart(um)4103244Swnj tsstart(um)
4113244Swnj register struct uba_ctlr *um;
4121900Swnj {
4131900Swnj register struct buf *bp;
4145693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr;
4153244Swnj register struct ts_softc *sc;
4163244Swnj register struct uba_device *ui;
41732579Sbostic register int tsunit;
41832579Sbostic int cmd;
4191900Swnj daddr_t blkno;
4201900Swnj
4213244Swnj /*
4223244Swnj * Start the controller if there is something for it to do.
4233244Swnj */
4243244Swnj loop:
42532609Sbostic if ((bp = um->um_tab.b_actf->b_actf) == NULL) {
42632609Sbostic um->um_tab.b_active = 0;
4271900Swnj return;
42832609Sbostic }
4293244Swnj tsunit = TSUNIT(bp->b_dev);
4303244Swnj ui = tsdinfo[tsunit];
4313244Swnj sc = &ts_softc[tsunit];
4323244Swnj /*
4333244Swnj * Default is that last command was NOT a write command;
43432579Sbostic * if we finish a write command we will notice this in tsintr().
4353244Swnj */
4363656Swnj sc->sc_lastiow = 0;
4373244Swnj if (sc->sc_openf < 0 || (addr->tssr&TS_OFL)) {
4383244Swnj /*
4393244Swnj * Have had a hard error on a non-raw tape
4403244Swnj * or the tape unit is now unavailable
4413244Swnj * (e.g. taken off line).
4423244Swnj */
4433244Swnj bp->b_flags |= B_ERROR;
4443244Swnj goto next;
4453244Swnj }
44632579Sbostic if (bp == &ctsbuf[tsunit]) {
4473244Swnj /*
4483244Swnj * Execute control operation with the specified count.
4493244Swnj */
4503244Swnj um->um_tab.b_active =
4513244Swnj bp->b_command == TS_REW ? SREW : SCOM;
45232579Sbostic sc->sc_ts.t_cmd.c_repcnt = bp->b_repcnt;
4533244Swnj goto dobpcmd;
4543244Swnj }
4553244Swnj /*
45632579Sbostic * For raw I/O, save the current block
45732579Sbostic * number in case we have to retry.
4583244Swnj */
45934217Sbostic if (bp->b_flags & B_RAW) {
46032579Sbostic if (um->um_tab.b_errcnt == 0)
46132579Sbostic sc->sc_blkno = bdbtofsb(bp->b_blkno);
46232579Sbostic } else {
4633244Swnj /*
46432579Sbostic * Handle boundary cases for operation
46532579Sbostic * on non-raw tapes.
4663244Swnj */
46732579Sbostic if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) {
46832579Sbostic /*
46932579Sbostic * Can't read past known end-of-file.
47032579Sbostic */
47132579Sbostic bp->b_flags |= B_ERROR;
47232579Sbostic bp->b_error = ENXIO;
47332579Sbostic goto next;
47432579Sbostic }
47532579Sbostic if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec &&
47632579Sbostic bp->b_flags&B_READ) {
47732579Sbostic /*
47832579Sbostic * Reading at end of file returns 0 bytes.
47932579Sbostic */
48032579Sbostic bp->b_resid = bp->b_bcount;
48132579Sbostic clrbuf(bp);
48232579Sbostic goto next;
48332579Sbostic }
48432579Sbostic if ((bp->b_flags&B_READ) == 0)
48532579Sbostic /*
48632579Sbostic * Writing sets EOF
48732579Sbostic */
48832579Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1;
4893244Swnj }
49032579Sbostic
4913244Swnj /*
4923244Swnj * If the data transfer command is in the correct place,
4933244Swnj * set up all the registers except the csr, and give
4943244Swnj * control over to the UNIBUS adapter routines, to
4953244Swnj * wait for resources to start the i/o.
4963244Swnj */
4977383Ssam if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) {
49832579Sbostic sc->sc_ts.t_cmd.c_size = bp->b_bcount;
4993244Swnj if ((bp->b_flags&B_READ) == 0)
5003244Swnj cmd = TS_WCOM;
5011900Swnj else
5023244Swnj cmd = TS_RCOM;
5033244Swnj if (um->um_tab.b_errcnt)
5043244Swnj cmd |= TS_RETRY;
5053244Swnj um->um_tab.b_active = SIO;
50632579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_IE | cmd;
5073244Swnj (void) ubago(ui);
5083244Swnj return;
5093244Swnj }
5103244Swnj /*
5113244Swnj * Tape positioned incorrectly;
5123244Swnj * set to seek forwards or backwards to the correct spot.
5133244Swnj * This happens for raw tapes only on error retries.
5143244Swnj */
5153244Swnj um->um_tab.b_active = SSEEK;
5167383Ssam if (blkno < bdbtofsb(bp->b_blkno)) {
5173244Swnj bp->b_command = TS_SFORW;
51832579Sbostic sc->sc_ts.t_cmd.c_repcnt = bdbtofsb(bp->b_blkno) - blkno;
5191900Swnj } else {
5203244Swnj bp->b_command = TS_SREV;
52132579Sbostic sc->sc_ts.t_cmd.c_repcnt = blkno - bdbtofsb(bp->b_blkno);
5221900Swnj }
5233244Swnj dobpcmd:
5243244Swnj /*
5253244Swnj * Do the command in bp.
5263244Swnj */
52732579Sbostic sc->sc_ts.t_cmd.c_cmd = TS_ACK | TS_CVC | TS_IE | bp->b_command;
5283244Swnj addr->tsdb = sc->sc_uba;
5291900Swnj return;
5301900Swnj
5313244Swnj next:
5323244Swnj /*
5333244Swnj * Done with this operation due to error or
5343244Swnj * the fact that it doesn't do anything.
5353244Swnj * Release UBA resources (if any), dequeue
5363244Swnj * the transfer and continue processing this slave.
5373244Swnj */
5383244Swnj if (um->um_ubinfo)
5393244Swnj ubadone(um);
5403244Swnj um->um_tab.b_errcnt = 0;
5413327Swnj um->um_tab.b_actf->b_actf = bp->av_forw;
54232579Sbostic biodone(bp);
5431900Swnj goto loop;
5441900Swnj }
5451900Swnj
5463244Swnj /*
5473244Swnj * The UNIBUS resources we needed have been
5483244Swnj * allocated to us; start the device.
5493244Swnj */
tsdgo(um)5503244Swnj tsdgo(um)
5513244Swnj register struct uba_ctlr *um;
5521900Swnj {
5533244Swnj register struct ts_softc *sc = &ts_softc[um->um_ctlr];
5543327Swnj register int i;
5553244Swnj
55626139Skarels /*
55726139Skarels * The uba code uses byte-offset mode if using bdp;
55826139Skarels * mask off the low bit here.
55926139Skarels */
56032579Sbostic i = UBAI_ADDR(um->um_ubinfo);
56126139Skarels if (UBAI_BDP(um->um_ubinfo))
56226139Skarels i &= ~1;
56332579Sbostic sc->sc_ts.t_cmd.c_loba = i;
56432579Sbostic sc->sc_ts.t_cmd.c_hiba = (i >> 16) & 3;
56532579Sbostic ((struct tsdevice *)um->um_addr)->tsdb = sc->sc_uba;
5663244Swnj }
5673244Swnj
5683244Swnj /*
5693244Swnj * Ts interrupt routine.
5703244Swnj */
5713244Swnj /*ARGSUSED*/
tsintr(tsunit)57232579Sbostic tsintr(tsunit)
57332579Sbostic register int tsunit;
5743244Swnj {
5751900Swnj register struct buf *bp;
57632579Sbostic register struct uba_ctlr *um;
5775693Sroot register struct tsdevice *addr;
5783244Swnj register struct ts_softc *sc;
57932579Sbostic register int state;
58032579Sbostic
58135401Stef #ifdef QBA
58232579Sbostic (void) spl5();
58327253Skridle #endif
58432579Sbostic um = tsdinfo[tsunit]->ui_mi;
5853327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL)
5861900Swnj return;
58732579Sbostic addr = (struct tsdevice *)um->um_addr;
5883244Swnj /*
5893244Swnj * If last command was a rewind, and tape is still
5903244Swnj * rewinding, wait for the rewind complete interrupt.
5913244Swnj *
5923244Swnj * SHOULD NEVER GET AN INTERRUPT IN THIS STATE.
5933244Swnj */
5943244Swnj if (um->um_tab.b_active == SREW) {
5953244Swnj um->um_tab.b_active = SCOM;
5963244Swnj if ((addr->tssr&TS_SSR) == 0)
5973244Swnj return;
5983244Swnj }
5993244Swnj /*
6003244Swnj * An operation completed... record status
6013244Swnj */
60232579Sbostic sc = &ts_softc[um->um_ctlr];
6033244Swnj if ((bp->b_flags & B_READ) == 0)
6043244Swnj sc->sc_lastiow = 1;
6053244Swnj state = um->um_tab.b_active;
6063244Swnj /*
6073244Swnj * Check for errors.
6083244Swnj */
6093244Swnj if (addr->tssr&TS_SC) {
6103244Swnj switch (addr->tssr & TS_TC) {
6113244Swnj case TS_UNREC: /* unrecoverable */
6123244Swnj case TS_FATAL: /* fatal error */
6133244Swnj case TS_RECNM: /* recoverable, no motion */
6143244Swnj break;
61532579Sbostic case TS_ATTN: /* attention */
61632579Sbostic if (sc->sc_ts.t_sts.s_xs0 & TS_VCK) {
61732579Sbostic /* volume check - may have changed tapes */
61832579Sbostic bp->b_flags |= B_ERROR;
61932579Sbostic goto ignoreerr;
62032579Sbostic }
62132579Sbostic break;
6221900Swnj
6233244Swnj case TS_SUCC: /* success termination */
62432579Sbostic printf("ts%d: success\n", tsunit);
6253244Swnj goto ignoreerr;
6261900Swnj
6273244Swnj case TS_ALERT: /* tape status alert */
6283244Swnj /*
6293244Swnj * If we hit the end of the tape file,
6303244Swnj * update our position.
6313244Swnj */
63232579Sbostic if (sc->sc_ts.t_sts.s_xs0 & (TS_TMK|TS_EOT)) {
63332579Sbostic tsseteof(bp); /* set blkno and nxrec */
63432579Sbostic state = SCOM; /* force completion */
6353244Swnj /*
6363244Swnj * Stuff bc so it will be unstuffed correctly
6373244Swnj * later to get resid.
6383244Swnj */
63932579Sbostic sc->sc_ts.t_sts.s_rbpcr = bp->b_bcount;
6403244Swnj goto opdone;
6413244Swnj }
6423244Swnj /*
64332579Sbostic * If we were reading raw tape and the record was too
64432579Sbostic * long or too short, we don't consider this an error.
6453244Swnj */
64634217Sbostic if ((bp->b_flags & (B_READ|B_RAW)) == (B_READ|B_RAW) &&
64732579Sbostic sc->sc_ts.t_sts.s_xs0&(TS_RLS|TS_RLL))
6483244Swnj goto ignoreerr;
64932579Sbostic /* FALLTHROUGH */
65032579Sbostic
6513244Swnj case TS_RECOV: /* recoverable, tape moved */
6523244Swnj /*
6533244Swnj * If this was an i/o operation retry up to 8 times.
6543244Swnj */
65532579Sbostic if (state == SIO) {
6563244Swnj if (++um->um_tab.b_errcnt < 7) {
6573244Swnj ubadone(um);
6583244Swnj goto opcont;
6593244Swnj } else
6603244Swnj sc->sc_blkno++;
6613244Swnj } else {
6623244Swnj /*
6633244Swnj * Non-i/o errors on non-raw tape
6643244Swnj * cause it to close.
6653244Swnj */
66634217Sbostic if ((bp->b_flags&B_RAW) == 0 &&
66734217Sbostic sc->sc_openf > 0)
6683244Swnj sc->sc_openf = -1;
6693244Swnj }
6701900Swnj break;
6713244Swnj
6723244Swnj case TS_REJECT: /* function reject */
67332579Sbostic if (state == SIO && sc->sc_ts.t_sts.s_xs0 & TS_WLE)
67444396Smarc tprintf(sc->sc_tpr, "ts%d: write locked\n",
67532579Sbostic tsunit);
67632579Sbostic if ((sc->sc_ts.t_sts.s_xs0 & TS_ONL) == 0)
67744396Smarc tprintf(sc->sc_tpr, "ts%d: offline\n",
67832579Sbostic tsunit);
6791900Swnj break;
6801900Swnj }
6813244Swnj /*
6823244Swnj * Couldn't recover error
6833244Swnj */
68444396Smarc tprintf(sc->sc_tpr, "ts%d: hard error bn%d tssr=%b xs0=%b",
68532579Sbostic tsunit, bp->b_blkno, addr->tssr, TSSR_BITS,
68632579Sbostic sc->sc_ts.t_sts.s_xs0, TSXS0_BITS);
68732579Sbostic if (sc->sc_ts.t_sts.s_xs1)
68844396Smarc tprintf(sc->sc_tpr, " xs1=%b", sc->sc_ts.t_sts.s_xs1,
68918322Sralph TSXS1_BITS);
69032579Sbostic if (sc->sc_ts.t_sts.s_xs2)
69144396Smarc tprintf(sc->sc_tpr, " xs2=%b", sc->sc_ts.t_sts.s_xs2,
69218322Sralph TSXS2_BITS);
69332579Sbostic if (sc->sc_ts.t_sts.s_xs3)
69444396Smarc tprintf(sc->sc_tpr, " xs3=%b", sc->sc_ts.t_sts.s_xs3,
69518322Sralph TSXS3_BITS);
69644396Smarc tprintf(sc->sc_tpr, "\n");
6973244Swnj bp->b_flags |= B_ERROR;
6983244Swnj goto opdone;
6993244Swnj }
7003244Swnj /*
7013244Swnj * Advance tape control FSM.
7023244Swnj */
7033244Swnj ignoreerr:
7043244Swnj switch (state) {
7051900Swnj
7063244Swnj case SIO:
7073244Swnj /*
7083244Swnj * Read/write increments tape block number
7093244Swnj */
7103244Swnj sc->sc_blkno++;
71130917Skarels sc->sc_blks++;
71230917Skarels if (um->um_tab.b_errcnt)
71330917Skarels sc->sc_softerrs++;
7143244Swnj goto opdone;
7151900Swnj
7161900Swnj case SCOM:
7173244Swnj /*
7183244Swnj * For forward/backward space record update current position.
7193244Swnj */
72032579Sbostic if (bp == &ctsbuf[tsunit])
72132579Sbostic switch ((int)bp->b_command) {
7221900Swnj
72332579Sbostic case TS_SFORW:
72432579Sbostic sc->sc_blkno += bp->b_repcnt;
72532579Sbostic break;
7261900Swnj
72732579Sbostic case TS_SREV:
72832579Sbostic sc->sc_blkno -= bp->b_repcnt;
72932579Sbostic break;
73032579Sbostic }
7313244Swnj goto opdone;
7323244Swnj
7333244Swnj case SSEEK:
7347383Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno);
7353244Swnj goto opcont;
7363244Swnj
7371900Swnj default:
7383244Swnj panic("tsintr");
7391900Swnj }
7403244Swnj opdone:
7413244Swnj /*
7423244Swnj * Reset error count and remove
7433244Swnj * from device queue.
7443244Swnj */
7453244Swnj um->um_tab.b_errcnt = 0;
7463327Swnj um->um_tab.b_actf->b_actf = bp->av_forw;
74732579Sbostic bp->b_resid = sc->sc_ts.t_sts.s_rbpcr;
7483244Swnj ubadone(um);
74932579Sbostic biodone(bp);
75032579Sbostic if (um->um_tab.b_actf->b_actf == 0) {
75132579Sbostic um->um_tab.b_active = 0;
7523244Swnj return;
75332579Sbostic }
7543244Swnj opcont:
7553244Swnj tsstart(um);
7563244Swnj }
7573244Swnj
tsseteof(bp)7583244Swnj tsseteof(bp)
7593244Swnj register struct buf *bp;
7603244Swnj {
7613244Swnj register int tsunit = TSUNIT(bp->b_dev);
76232579Sbostic register struct ts_softc *sc = &ts_softc[tsdinfo[tsunit]->ui_ctlr];
7633244Swnj
76432579Sbostic if (bp == &ctsbuf[tsunit]) {
7657383Ssam if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) {
7663244Swnj /* reversing */
76732579Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) -
76832579Sbostic sc->sc_ts.t_sts.s_rbpcr;
7693244Swnj sc->sc_blkno = sc->sc_nxrec;
7703244Swnj } else {
7713244Swnj /* spacing forward */
77232579Sbostic sc->sc_blkno = bdbtofsb(bp->b_blkno) +
77332579Sbostic sc->sc_ts.t_sts.s_rbpcr;
7743244Swnj sc->sc_nxrec = sc->sc_blkno - 1;
7751900Swnj }
7763244Swnj return;
7773244Swnj }
7783244Swnj /* eof on read */
7797383Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno);
7801900Swnj }
7811900Swnj
tsreset(uban)7823244Swnj tsreset(uban)
7833244Swnj int uban;
7841918Swnj {
7853244Swnj register struct uba_ctlr *um;
7865693Sroot register struct uba_device *ui;
78732579Sbostic register int ts11, i;
7881918Swnj
7893244Swnj for (ts11 = 0; ts11 < NTS; ts11++) {
7903244Swnj if ((um = tsminfo[ts11]) == 0 || um->um_alive == 0 ||
79132579Sbostic um->um_ubanum != uban)
7923244Swnj continue;
7933244Swnj printf(" ts%d", ts11);
7943244Swnj um->um_tab.b_active = 0;
7953244Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0;
7965693Sroot if (ts_softc[ts11].sc_openf > 0)
7975693Sroot ts_softc[ts11].sc_openf = -1;
7983244Swnj if (um->um_ubinfo) {
79932579Sbostic printf("<%d>", UBAI_BDP(um->um_ubinfo));
8009356Ssam um->um_ubinfo = 0;
8013244Swnj }
80232579Sbostic /*
80332579Sbostic * tsdinfo should be 1-to-1 with tsminfo, but someone
80432579Sbostic * might have screwed up the config file:
80532579Sbostic */
80632579Sbostic for (i = 0; i < NTS; i++) {
80732579Sbostic if ((ui = tsdinfo[i]) != NULL &&
80832579Sbostic ui->ui_alive && ui->ui_mi == um) {
80932579Sbostic um->um_tab.b_actf = um->um_tab.b_actl =
81032579Sbostic &tsutab[i];
81132579Sbostic break;
81232579Sbostic }
8135693Sroot }
814*52683Storek tsmap(&ts_softc[ts11], uban);
8153989Sroot (void) tsinit(ts11);
8163244Swnj tsstart(um);
8171918Swnj }
8181918Swnj }
8191918Swnj
8203244Swnj /*ARGSUSED*/
tsioctl(dev,cmd,data,flag)8217633Ssam tsioctl(dev, cmd, data, flag)
8227633Ssam caddr_t data;
8233244Swnj dev_t dev;
8241918Swnj {
8253244Swnj int tsunit = TSUNIT(dev);
82632579Sbostic register struct ts_softc *sc = &ts_softc[tsdinfo[tsunit]->ui_ctlr];
8273244Swnj register struct buf *bp = &ctsbuf[TSUNIT(dev)];
82832579Sbostic register int callcount;
82940911Ssklower int fcount, error = 0;
8307633Ssam struct mtop *mtop;
8317633Ssam struct mtget *mtget;
8323244Swnj /* we depend of the values and order of the MT codes here */
83332579Sbostic static int tsops[] =
8343656Swnj {TS_WEOF,TS_SFORWF,TS_SREVF,TS_SFORW,TS_SREV,TS_REW,TS_OFFL,TS_SENSE};
8351918Swnj
8363244Swnj switch (cmd) {
8377633Ssam
8383244Swnj case MTIOCTOP: /* tape operation */
8397633Ssam mtop = (struct mtop *)data;
8408575Sroot switch (mtop->mt_op) {
8417633Ssam
8423244Swnj case MTWEOF:
8437633Ssam callcount = mtop->mt_count;
8443244Swnj fcount = 1;
8453244Swnj break;
8467633Ssam
8473244Swnj case MTFSF: case MTBSF:
8483244Swnj case MTFSR: case MTBSR:
8493244Swnj callcount = 1;
8507633Ssam fcount = mtop->mt_count;
8513244Swnj break;
8527633Ssam
8533244Swnj case MTREW: case MTOFFL: case MTNOP:
8543244Swnj callcount = 1;
8553244Swnj fcount = 1;
8563244Swnj break;
8577633Ssam
8583244Swnj default:
8598575Sroot return (ENXIO);
8603244Swnj }
8618575Sroot if (callcount <= 0 || fcount <= 0)
8628575Sroot return (EINVAL);
8633244Swnj while (--callcount >= 0) {
8647633Ssam tscommand(dev, tsops[mtop->mt_op], fcount);
8657633Ssam if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) &&
8668611Sroot bp->b_resid)
8678575Sroot return (EIO);
86832579Sbostic if ((bp->b_flags&B_ERROR) ||
86932579Sbostic sc->sc_ts.t_sts.s_xs0&TS_BOT)
8703244Swnj break;
8713244Swnj }
87240911Ssklower if (bp->b_flags&B_ERROR)
87340911Ssklower if ((error = bp->b_error)==0)
87440911Ssklower return (EIO);
87540911Ssklower return (error);
8767633Ssam
8773244Swnj case MTIOCGET:
8787633Ssam mtget = (struct mtget *)data;
8797633Ssam mtget->mt_dsreg = 0;
88032579Sbostic mtget->mt_erreg = sc->sc_ts.t_sts.s_xs0;
8817633Ssam mtget->mt_resid = sc->sc_resid;
8827633Ssam mtget->mt_type = MT_ISTS;
8838575Sroot break;
8847633Ssam
8853244Swnj default:
8868575Sroot return (ENXIO);
8873244Swnj }
8888575Sroot return (0);
8891918Swnj }
8901918Swnj
8913244Swnj #define DBSIZE 20
8923244Swnj
tsdump(dev)89332579Sbostic tsdump(dev)
89432579Sbostic dev_t dev;
8951918Swnj {
8963244Swnj register struct uba_device *ui;
89732579Sbostic register struct uba_regs *uba;
8985693Sroot register struct tsdevice *addr;
89932579Sbostic register int i;
90032579Sbostic register struct pte *io;
90132579Sbostic int blk, num, unit, reg, start;
90232579Sbostic u_short db;
90332579Sbostic struct ts_tsdata *tc, *tc_ubaddr;
9041918Swnj
90532579Sbostic unit = TSUNIT(dev);
90632579Sbostic if (unit >= NTS)
90732579Sbostic return (ENXIO);
9083244Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff))
90932579Sbostic ui = phys(tsdinfo[unit], struct uba_device *);
91032579Sbostic if (ui->ui_alive == 0)
9113244Swnj return (ENXIO);
91232579Sbostic uba = phys(ui->ui_hd, struct uba_hd *)->uh_physuba;
91332579Sbostic ubainit(uba);
9145693Sroot addr = (struct tsdevice *)ui->ui_physaddr;
91532579Sbostic
91632579Sbostic /* map a ts_tsdata structure */
91732579Sbostic tc = phys(&ts_softc[0].sc_ts, struct ts_tsdata *);
91832579Sbostic num = btoc(sizeof(struct ts_tsdata)) + 1;
91932579Sbostic io = &uba->uba_map[reg = NUBMREG - num];
92032579Sbostic for (i = 0; i < num; i++)
92132579Sbostic *(int *)io++ = UBAMR_MRV | (btop(tc) + i);
92232579Sbostic i = (((int)tc & PGOFSET) | (reg << 9));
92332579Sbostic tc_ubaddr = (struct ts_tsdata *)i;
92432579Sbostic db = i + ((i >> 16) & 3);
92532579Sbostic
92632579Sbostic /* init the drive */
9273244Swnj addr->tssr = 0;
9283244Swnj tswait(addr);
92932579Sbostic if ((addr->tssr & (TS_NBA|TS_OFL)) != TS_NBA)
93032579Sbostic return (EFAULT);
93132579Sbostic
93232579Sbostic /* set characteristics */
93332579Sbostic i = (int)&tc_ubaddr->t_char;
93432579Sbostic tc->t_cmd.c_loba = i;
93532579Sbostic tc->t_cmd.c_hiba = (i >> 16) & 3;
93632579Sbostic tc->t_cmd.c_size = sizeof(struct ts_char);
93732579Sbostic tc->t_cmd.c_cmd = TS_ACK | TS_CVC | TS_SETCHR;
93832579Sbostic tc->t_char.char_addr = (int)&tc_ubaddr->t_sts;
93932579Sbostic tc->t_char.char_size = sizeof(struct ts_sts);
94032579Sbostic tc->t_char.char_mode = TS_ESS;
94132579Sbostic addr->tsdb = db;
94232579Sbostic tswait(addr);
94332579Sbostic if (addr->tssr & TS_NBA)
94432579Sbostic return (ENXIO);
94532579Sbostic
94632579Sbostic /* dump */
94732579Sbostic tc->t_cmd.c_cmd = TS_ACK | TS_WCOM;
94832579Sbostic tc->t_cmd.c_repcnt = 1;
94932579Sbostic num = maxfree;
95032579Sbostic for (start = 0, num = maxfree; num > 0; start += blk, num -= blk) {
9513244Swnj blk = num > DBSIZE ? DBSIZE : num;
95232579Sbostic io = uba->uba_map;
95332579Sbostic for (i = 0; i < blk; i++)
95432579Sbostic *(int *)io++ = UBAMR_MRV | (1 << UBAMR_DPSHIFT) |
95532579Sbostic (start + i);
95632579Sbostic *(int *)io = 0;
95732579Sbostic addr->tsdb = db;
95832579Sbostic tswait(addr);
9593244Swnj }
96032579Sbostic
96132579Sbostic /* eof */
96232579Sbostic tc->t_cmd.c_cmd = TS_WEOF;
96332579Sbostic addr->tsdb = db;
9643244Swnj tswait(addr);
96532579Sbostic addr->tsdb = db;
96632579Sbostic tswait(addr);
96732579Sbostic
9683244Swnj if (addr->tssr&TS_SC)
9693244Swnj return (EIO);
9703244Swnj addr->tssr = 0;
9713244Swnj tswait(addr);
9723244Swnj return (0);
9731918Swnj }
9741918Swnj
tswait(addr)9753244Swnj tswait(addr)
9765693Sroot register struct tsdevice *addr;
9771918Swnj {
9781918Swnj
97932579Sbostic while ((addr->tssr & TS_SSR) == 0)
98032579Sbostic /* void */;
9811918Swnj }
9821918Swnj
98332579Sbostic #endif /* NTS > 0 */
984