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*30917Skarels * @(#)ts.c 7.2 (Berkeley) 04/17/87 723349Smckusick */ 81900Swnj 91941Swnj #include "ts.h" 101900Swnj #if NTS > 0 111900Swnj /* 121900Swnj * TS11 tape driver 133244Swnj * 143244Swnj * TODO: 155693Sroot * write dump code 161900Swnj */ 1717080Sbloom #include "param.h" 1817080Sbloom #include "systm.h" 1917080Sbloom #include "buf.h" 2017080Sbloom #include "dir.h" 2117080Sbloom #include "conf.h" 2217080Sbloom #include "user.h" 2317080Sbloom #include "file.h" 2417080Sbloom #include "map.h" 2517080Sbloom #include "vm.h" 2617080Sbloom #include "ioctl.h" 2717080Sbloom #include "mtio.h" 2817080Sbloom #include "cmap.h" 2917080Sbloom #include "uio.h" 3018322Sralph #include "tty.h" 31*30917Skarels #include "syslog.h" 321900Swnj 33*30917Skarels #include "../machine/pte.h" 348480Sroot #include "../vax/cpu.h" 3517080Sbloom #include "ubareg.h" 3617080Sbloom #include "ubavar.h" 3717080Sbloom #include "tsreg.h" 381900Swnj 393244Swnj /* 403244Swnj * There is a ctsbuf per tape controller. 413244Swnj * It is used as the token to pass to the internal routines 423244Swnj * to execute tape ioctls. 433244Swnj * In particular, when the tape is rewinding on close we release 443244Swnj * the user process but any further attempts to use the tape drive 453244Swnj * before the rewind completes will hang waiting for ctsbuf. 463244Swnj */ 473244Swnj struct buf ctsbuf[NTS]; 481900Swnj 493244Swnj /* 503244Swnj * Raw tape operations use rtsbuf. The driver 513244Swnj * notices when rtsbuf is being used and allows the user 523244Swnj * program to continue after errors and read records 533244Swnj * not of the standard length (BSIZE). 543244Swnj */ 553244Swnj struct buf rtsbuf[NTS]; 561900Swnj 573244Swnj /* 583244Swnj * Driver unibus interface routines and variables. 593244Swnj */ 603244Swnj int tsprobe(), tsslave(), tsattach(), tsdgo(), tsintr(); 613244Swnj struct uba_ctlr *tsminfo[NTS]; 623244Swnj struct uba_device *tsdinfo[NTS]; 635693Sroot struct buf tsutab[NTS]; 643244Swnj u_short tsstd[] = { 0772520, 0 }; 653244Swnj /*** PROBABLY DON'T NEED ALL THESE SINCE CONTROLLER == DRIVE ***/ 663244Swnj struct uba_driver zsdriver = 673327Swnj { tsprobe, tsslave, tsattach, tsdgo, tsstd, "ts", tsdinfo, "zs", tsminfo, 0 }; 681900Swnj 693244Swnj /* bits in minor device */ 703244Swnj #define TSUNIT(dev) (minor(dev)&03) 713244Swnj #define T_NOREWIND 04 721900Swnj 733244Swnj #define INF (daddr_t)1000000L 741900Swnj 753244Swnj /* 763244Swnj * Software state per tape transport. 773244Swnj * Also contains hardware state in message packets. 783244Swnj * 793244Swnj * 1. A tape drive is a unique-open device; we refuse opens when it is already. 803244Swnj * 2. We keep track of the current position on a block tape and seek 813244Swnj * before operations by forward/back spacing if necessary. 823244Swnj * 3. We remember if the last operation was a write on a tape, so if a tape 833244Swnj * is open read write and the last thing done is a write we can 843244Swnj * write a standard end of tape mark (two eofs). 853244Swnj * 4. We remember the status registers after the last command, using 863244Swnj * then internally and returning them to the SENSE ioctl. 873244Swnj */ 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 */ 945693Sroot struct ts_cmd sc_cmd; /* the command packet */ 955693Sroot struct ts_sts sc_sts; /* status packet, for returned status */ 965693Sroot struct ts_char sc_char; /* characteristics packet */ 975693Sroot struct ts_softc *sc_ubaddr; /* Unibus address of ts_softc structure */ 985697Sroot u_short sc_uba; /* Unibus addr of cmd pkt for tsdb */ 995693Sroot short sc_mapped; /* is ts_sfotc mapped in Unibus space? */ 10018322Sralph struct tty *sc_ttyp; /* record user's tty for errors */ 101*30917Skarels int sc_blks; /* number of I/O operations since open */ 102*30917Skarels int sc_softerrs; /* number of soft I/O errors since open */ 1033244Swnj } ts_softc[NTS]; 1041900Swnj 1053244Swnj /* 1063244Swnj * States for um->um_tab.b_active, the per controller state flag. 1073244Swnj * This is used to sequence control in the driver. 1083244Swnj */ 1093244Swnj #define SSEEK 1 /* seeking */ 1103244Swnj #define SIO 2 /* doing seq i/o */ 1113244Swnj #define SCOM 3 /* sending control command */ 1123244Swnj #define SREW 4 /* sending a drive rewind */ 1131900Swnj 1143244Swnj /* 1153244Swnj * Determine if there is a controller for 1163244Swnj * a ts at address reg. Our goal is to make the 1173244Swnj * device interrupt. 1183244Swnj */ 1193985Sroot /*ARGSUSED*/ 1203244Swnj tsprobe(reg) 1213244Swnj caddr_t reg; 1223244Swnj { 1233244Swnj register int br, cvec; /* must be r11,r10; value-result */ 1241900Swnj 1253244Swnj #ifdef lint 1263244Swnj br = 0; cvec = br; br = cvec; 1274937Swnj tsintr(0); 1283244Swnj #endif 1295693Sroot ((struct tsdevice *)reg)->tssr = 0; 1305693Sroot DELAY(100); 1315693Sroot if ((((struct tsdevice *)reg)->tssr & TS_NBA) == 0) 1325693Sroot return(0); 1335693Sroot /* IT'S TOO HARD TO MAKE THIS THING INTERRUPT JUST TO FIND ITS VECTOR */ 1345693Sroot cvec = ((unsigned)reg) & 07 ? 0260 : 0224; 1353244Swnj br = 0x15; 1367407Skre return (sizeof (struct tsdevice)); 1373244Swnj } 1381900Swnj 1393244Swnj /* 1403244Swnj * TS11 only supports one drive per controller; 1413244Swnj * check for ui_slave == 0. 1423244Swnj * 1433244Swnj * DO WE REALLY NEED THIS ROUTINE??? 1443244Swnj */ 1453244Swnj /*ARGSUSED*/ 1463244Swnj tsslave(ui, reg) 1473244Swnj struct uba_device *ui; 1483244Swnj caddr_t reg; 1493244Swnj { 1501900Swnj 1513244Swnj if (ui->ui_slave) /* non-zero slave not allowed */ 1523244Swnj return(0); 1533244Swnj return (1); 1543244Swnj } 1551900Swnj 1563244Swnj /* 1573244Swnj * Record attachment of the unit to the controller. 1583244Swnj * 1593244Swnj * SHOULD THIS ROUTINE DO ANYTHING??? 1603244Swnj */ 1613244Swnj /*ARGSUSED*/ 1623244Swnj tsattach(ui) 1633244Swnj struct uba_device *ui; 1643244Swnj { 1651900Swnj 1663244Swnj } 1671900Swnj 1683244Swnj /* 1693244Swnj * Open the device. Tapes are unique open 1703244Swnj * devices, so we refuse if it is already open. 1713244Swnj * We also check that a tape is available, and 1723244Swnj * don't block waiting here; if you want to wait 1733244Swnj * for a tape you should timeout in user code. 1743244Swnj */ 1751900Swnj tsopen(dev, flag) 1763244Swnj dev_t dev; 1773244Swnj int flag; 1781900Swnj { 1793244Swnj register int tsunit; 1803244Swnj register struct uba_device *ui; 1813244Swnj register struct ts_softc *sc; 1821900Swnj 1833244Swnj tsunit = TSUNIT(dev); 18425054Skarels if (tsunit>=NTS || (ui = tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) 1858575Sroot return (ENXIO); 18625054Skarels if ((sc = &ts_softc[tsunit])->sc_openf) 18725054Skarels return (EBUSY); 188*30917Skarels sc->sc_openf = 1; 189*30917Skarels if (tsinit(tsunit)) { 190*30917Skarels sc->sc_openf = 0; 1918575Sroot return (ENXIO); 192*30917Skarels } 1933244Swnj tscommand(dev, TS_SENSE, 1); 1943711Sroot if ((sc->sc_sts.s_xs0&TS_ONL) == 0) { 195*30917Skarels sc->sc_openf = 0; 1963711Sroot uprintf("ts%d: not online\n", tsunit); 1978575Sroot return (EIO); 1981900Swnj } 19924267Sbloom if ((flag&FWRITE) && (sc->sc_sts.s_xs0&TS_WLK)) { 200*30917Skarels sc->sc_openf = 0; 2013711Sroot uprintf("ts%d: no write ring\n", tsunit); 2028575Sroot return (EIO); 2033711Sroot } 2043244Swnj sc->sc_blkno = (daddr_t)0; 2053244Swnj sc->sc_nxrec = INF; 2063244Swnj sc->sc_lastiow = 0; 207*30917Skarels sc->sc_blks = 0; 208*30917Skarels sc->sc_softerrs = 0; 20918322Sralph sc->sc_ttyp = u.u_ttyp; 2108575Sroot return (0); 2111900Swnj } 2121900Swnj 2133244Swnj /* 2143244Swnj * Close tape device. 2153244Swnj * 2163244Swnj * If tape was open for writing or last operation was 2173244Swnj * a write, then write two EOF's and backspace over the last one. 2183244Swnj * Unless this is a non-rewinding special file, rewind the tape. 2193244Swnj * Make the tape available to others. 2203244Swnj */ 2211900Swnj tsclose(dev, flag) 2223244Swnj register dev_t dev; 2233244Swnj register flag; 2241900Swnj { 2253244Swnj register struct ts_softc *sc = &ts_softc[TSUNIT(dev)]; 2261900Swnj 2273244Swnj if (flag == FWRITE || (flag&FWRITE) && sc->sc_lastiow) { 2283244Swnj tscommand(dev, TS_WEOF, 1); 2293244Swnj tscommand(dev, TS_WEOF, 1); 2303244Swnj tscommand(dev, TS_SREV, 1); 2311900Swnj } 2323244Swnj if ((minor(dev)&T_NOREWIND) == 0) 2333244Swnj /* 2343244Swnj * 0 count means don't hang waiting for rewind complete 2353244Swnj * rather ctsbuf stays busy until the operation completes 2363244Swnj * preventing further opens from completing by 2373244Swnj * preventing a TS_SENSE from completing. 2383244Swnj */ 2393244Swnj tscommand(dev, TS_REW, 0); 240*30917Skarels if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100) 241*30917Skarels log(LOG_INFO, "ts%d: %d soft errors in %d blocks\n", 242*30917Skarels TSUNIT(dev), sc->sc_softerrs, sc->sc_blks); 2433244Swnj sc->sc_openf = 0; 2441900Swnj } 2451900Swnj 2463244Swnj /* 2473244Swnj * Initialize the TS11. Set up Unibus mapping for command 2483244Swnj * packets and set device characteristics. 2493244Swnj */ 2503244Swnj tsinit(unit) 2513244Swnj register int unit; 2521900Swnj { 2533244Swnj register struct ts_softc *sc = &ts_softc[unit]; 2543244Swnj register struct uba_ctlr *um = tsminfo[unit]; 2555693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 2563244Swnj register int i; 2573244Swnj 2583244Swnj /* 2593244Swnj * Map the command and message packets into Unibus 2603244Swnj * address space. We do all the command and message 2613244Swnj * packets at once to minimize the amount of Unibus 2623244Swnj * mapping necessary. 2633244Swnj */ 2645693Sroot if (sc->sc_mapped == 0) { 2655693Sroot ctsbuf[unit].b_un.b_addr = (caddr_t)sc; 2665693Sroot ctsbuf[unit].b_bcount = sizeof(*sc); 2673244Swnj i = ubasetup(um->um_ubanum, &ctsbuf[unit], 0); 2683244Swnj i &= 0777777; 2695693Sroot sc->sc_ubaddr = (struct ts_softc *)i; 2705693Sroot sc->sc_mapped++; 2713244Swnj } 2723244Swnj /* 2733244Swnj * Now initialize the TS11 controller. 2743244Swnj * Set the characteristics. 2753244Swnj */ 2763668Swnj if (addr->tssr & (TS_NBA|TS_OFL)) { 2773244Swnj addr->tssr = 0; /* subsystem initialize */ 2783244Swnj tswait(addr); 2795693Sroot i = (int)&sc->sc_ubaddr->sc_cmd; /* Unibus addr of cmd */ 2803244Swnj sc->sc_uba = (u_short)(i + ((i>>16)&3)); 2815693Sroot sc->sc_char.char_addr = (int)&sc->sc_ubaddr->sc_sts; 2823244Swnj sc->sc_char.char_size = sizeof(struct ts_sts); 2833244Swnj sc->sc_char.char_mode = TS_ESS; 2843244Swnj sc->sc_cmd.c_cmd = TS_ACK | TS_SETCHR; 2855693Sroot i = (int)&sc->sc_ubaddr->sc_char; 2863327Swnj sc->sc_cmd.c_loba = i; 2873327Swnj sc->sc_cmd.c_hiba = (i>>16)&3; 2883244Swnj sc->sc_cmd.c_size = sizeof(struct ts_char); 2893244Swnj addr->tsdb = sc->sc_uba; 2903244Swnj tswait(addr); 2913327Swnj if (addr->tssr & TS_NBA) 2923327Swnj return(1); 2933244Swnj } 2943244Swnj return(0); 2953244Swnj } 2963244Swnj 2973244Swnj /* 2983244Swnj * Execute a command on the tape drive 2993244Swnj * a specified number of times. 3003244Swnj */ 3013244Swnj tscommand(dev, com, count) 3023244Swnj dev_t dev; 3033244Swnj int com, count; 3043244Swnj { 3051900Swnj register struct buf *bp; 3065438Sroot register int s; 3071900Swnj 3083244Swnj bp = &ctsbuf[TSUNIT(dev)]; 3095438Sroot s = spl5(); 3103244Swnj while (bp->b_flags&B_BUSY) { 3113244Swnj /* 3123244Swnj * This special check is because B_BUSY never 3133244Swnj * gets cleared in the non-waiting rewind case. 3143244Swnj */ 3153244Swnj if (bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 3163244Swnj break; 3171900Swnj bp->b_flags |= B_WANTED; 3181900Swnj sleep((caddr_t)bp, PRIBIO); 3191900Swnj } 3203244Swnj bp->b_flags = B_BUSY|B_READ; 3215438Sroot splx(s); 3223244Swnj bp->b_dev = dev; 3233244Swnj bp->b_repcnt = count; 3243244Swnj bp->b_command = com; 3251900Swnj bp->b_blkno = 0; 3261900Swnj tsstrategy(bp); 3273244Swnj /* 3283244Swnj * In case of rewind from close, don't wait. 3293244Swnj * This is the only case where count can be 0. 3303244Swnj */ 3313244Swnj if (count == 0) 3323244Swnj return; 3331900Swnj iowait(bp); 3343244Swnj if (bp->b_flags&B_WANTED) 3351900Swnj wakeup((caddr_t)bp); 3363244Swnj bp->b_flags &= B_ERROR; 3371900Swnj } 3381900Swnj 3393244Swnj /* 3403244Swnj * Queue a tape operation. 3413244Swnj */ 3421900Swnj tsstrategy(bp) 3433244Swnj register struct buf *bp; 3441900Swnj { 3453244Swnj int tsunit = TSUNIT(bp->b_dev); 3463244Swnj register struct uba_ctlr *um; 3473327Swnj register struct buf *dp; 3485438Sroot register int s; 3491900Swnj 3503244Swnj /* 3513244Swnj * Put transfer at end of controller queue 3523244Swnj */ 3531900Swnj bp->av_forw = NULL; 3543244Swnj um = tsdinfo[tsunit]->ui_mi; 3555438Sroot s = spl5(); 3565693Sroot dp = &tsutab[tsunit]; 3573327Swnj if (dp->b_actf == NULL) 3583327Swnj dp->b_actf = bp; 3591900Swnj else 3603327Swnj dp->b_actl->av_forw = bp; 3613327Swnj dp->b_actl = bp; 3623327Swnj um->um_tab.b_actf = um->um_tab.b_actl = dp; 3633244Swnj /* 3643244Swnj * If the controller is not busy, get 3653244Swnj * it going. 3663244Swnj */ 3673244Swnj if (um->um_tab.b_active == 0) 3683244Swnj tsstart(um); 3695438Sroot splx(s); 3701900Swnj } 3711900Swnj 3723244Swnj /* 3733244Swnj * Start activity on a ts controller. 3743244Swnj */ 3753244Swnj tsstart(um) 3763244Swnj register struct uba_ctlr *um; 3771900Swnj { 3781900Swnj register struct buf *bp; 3795693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 3803244Swnj register struct ts_softc *sc; 3813244Swnj register struct ts_cmd *tc; 3823244Swnj register struct uba_device *ui; 3833244Swnj int tsunit, cmd; 3841900Swnj daddr_t blkno; 3851900Swnj 3863244Swnj /* 3873244Swnj * Start the controller if there is something for it to do. 3883244Swnj */ 3893244Swnj loop: 3903327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 3911900Swnj return; 3923244Swnj tsunit = TSUNIT(bp->b_dev); 3933244Swnj ui = tsdinfo[tsunit]; 3943244Swnj sc = &ts_softc[tsunit]; 3953244Swnj tc = &sc->sc_cmd; 3963244Swnj /* 3973244Swnj * Default is that last command was NOT a write command; 3983244Swnj * if we do a write command we will notice this in tsintr(). 3993244Swnj */ 4003656Swnj sc->sc_lastiow = 0; 4013244Swnj if (sc->sc_openf < 0 || (addr->tssr&TS_OFL)) { 4023244Swnj /* 4033244Swnj * Have had a hard error on a non-raw tape 4043244Swnj * or the tape unit is now unavailable 4053244Swnj * (e.g. taken off line). 4063244Swnj */ 4073244Swnj bp->b_flags |= B_ERROR; 4083244Swnj goto next; 4093244Swnj } 4103244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) { 4113244Swnj /* 4123244Swnj * Execute control operation with the specified count. 4133244Swnj */ 4143244Swnj um->um_tab.b_active = 4153244Swnj bp->b_command == TS_REW ? SREW : SCOM; 4163244Swnj tc->c_repcnt = bp->b_repcnt; 4173244Swnj goto dobpcmd; 4183244Swnj } 4193244Swnj /* 4203244Swnj * The following checks handle boundary cases for operation 4213244Swnj * on non-raw tapes. On raw tapes the initialization of 4223244Swnj * sc->sc_nxrec by tsphys causes them to be skipped normally 4233244Swnj * (except in the case of retries). 4243244Swnj */ 4257383Ssam if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 4263244Swnj /* 4273244Swnj * Can't read past known end-of-file. 4283244Swnj */ 4293244Swnj bp->b_flags |= B_ERROR; 4303244Swnj bp->b_error = ENXIO; 4313244Swnj goto next; 4323244Swnj } 4337383Ssam if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && 4343244Swnj bp->b_flags&B_READ) { 4353244Swnj /* 4363244Swnj * Reading at end of file returns 0 bytes. 4373244Swnj */ 4383244Swnj bp->b_resid = bp->b_bcount; 4393244Swnj clrbuf(bp); 4403244Swnj goto next; 4413244Swnj } 4423244Swnj if ((bp->b_flags&B_READ) == 0) 4433244Swnj /* 4443244Swnj * Writing sets EOF 4453244Swnj */ 4467383Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; 4473244Swnj /* 4483244Swnj * If the data transfer command is in the correct place, 4493244Swnj * set up all the registers except the csr, and give 4503244Swnj * control over to the UNIBUS adapter routines, to 4513244Swnj * wait for resources to start the i/o. 4523244Swnj */ 4537383Ssam if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { 4543244Swnj tc->c_size = bp->b_bcount; 4553244Swnj if ((bp->b_flags&B_READ) == 0) 4563244Swnj cmd = TS_WCOM; 4571900Swnj else 4583244Swnj cmd = TS_RCOM; 4593244Swnj if (um->um_tab.b_errcnt) 4603244Swnj cmd |= TS_RETRY; 4613244Swnj um->um_tab.b_active = SIO; 4623327Swnj tc->c_cmd = TS_ACK | TS_CVC | TS_IE | cmd; 4633244Swnj (void) ubago(ui); 4643244Swnj return; 4653244Swnj } 4663244Swnj /* 4673244Swnj * Tape positioned incorrectly; 4683244Swnj * set to seek forwards or backwards to the correct spot. 4693244Swnj * This happens for raw tapes only on error retries. 4703244Swnj */ 4713244Swnj um->um_tab.b_active = SSEEK; 4727383Ssam if (blkno < bdbtofsb(bp->b_blkno)) { 4733244Swnj bp->b_command = TS_SFORW; 4747383Ssam tc->c_repcnt = bdbtofsb(bp->b_blkno) - blkno; 4751900Swnj } else { 4763244Swnj bp->b_command = TS_SREV; 4777383Ssam tc->c_repcnt = blkno - bdbtofsb(bp->b_blkno); 4781900Swnj } 4793244Swnj dobpcmd: 4803244Swnj /* 4813244Swnj * Do the command in bp. 4823244Swnj */ 4833327Swnj tc->c_cmd = TS_ACK | TS_CVC | TS_IE | bp->b_command; 4843244Swnj addr->tsdb = sc->sc_uba; 4851900Swnj return; 4861900Swnj 4873244Swnj next: 4883244Swnj /* 4893244Swnj * Done with this operation due to error or 4903244Swnj * the fact that it doesn't do anything. 4913244Swnj * Release UBA resources (if any), dequeue 4923244Swnj * the transfer and continue processing this slave. 4933244Swnj */ 4943244Swnj if (um->um_ubinfo) 4953244Swnj ubadone(um); 4963244Swnj um->um_tab.b_errcnt = 0; 4973327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 4981900Swnj iodone(bp); 4991900Swnj goto loop; 5001900Swnj } 5011900Swnj 5023244Swnj /* 5033244Swnj * The UNIBUS resources we needed have been 5043244Swnj * allocated to us; start the device. 5053244Swnj */ 5063244Swnj tsdgo(um) 5073244Swnj register struct uba_ctlr *um; 5081900Swnj { 5095693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 5103244Swnj register struct ts_softc *sc = &ts_softc[um->um_ctlr]; 5113327Swnj register int i; 5123244Swnj 51326139Skarels /* 51426139Skarels * The uba code uses byte-offset mode if using bdp; 51526139Skarels * mask off the low bit here. 51626139Skarels */ 5173327Swnj i = um->um_ubinfo & 0777777; 51826139Skarels if (UBAI_BDP(um->um_ubinfo)) 51926139Skarels i &= ~1; 5203327Swnj sc->sc_cmd.c_loba = i; 5213327Swnj sc->sc_cmd.c_hiba = (i>>16)&3; 5223244Swnj addr->tsdb = sc->sc_uba; 5233244Swnj } 5243244Swnj 5253244Swnj /* 5263244Swnj * Ts interrupt routine. 5273244Swnj */ 5283244Swnj /*ARGSUSED*/ 5293244Swnj tsintr(ts11) 5303244Swnj int ts11; 5313244Swnj { 5321900Swnj register struct buf *bp; 5333244Swnj register struct uba_ctlr *um = tsminfo[ts11]; 5345693Sroot register struct tsdevice *addr; 5353244Swnj register struct ts_softc *sc; 5363244Swnj int tsunit; 5373244Swnj register state; 53827253Skridle #if VAX630 53927253Skridle spl5(); 54027253Skridle #endif 5413327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 5421900Swnj return; 5433244Swnj tsunit = TSUNIT(bp->b_dev); 5445693Sroot addr = (struct tsdevice *)tsdinfo[tsunit]->ui_addr; 5453244Swnj /* 5463244Swnj * If last command was a rewind, and tape is still 5473244Swnj * rewinding, wait for the rewind complete interrupt. 5483244Swnj * 5493244Swnj * SHOULD NEVER GET AN INTERRUPT IN THIS STATE. 5503244Swnj */ 5513244Swnj if (um->um_tab.b_active == SREW) { 5523244Swnj um->um_tab.b_active = SCOM; 5533244Swnj if ((addr->tssr&TS_SSR) == 0) 5543244Swnj return; 5553244Swnj } 5563244Swnj /* 5573244Swnj * An operation completed... record status 5583244Swnj */ 5593244Swnj sc = &ts_softc[tsunit]; 5603244Swnj if ((bp->b_flags & B_READ) == 0) 5613244Swnj sc->sc_lastiow = 1; 5623244Swnj state = um->um_tab.b_active; 5633244Swnj um->um_tab.b_active = 0; 5643244Swnj /* 5653244Swnj * Check for errors. 5663244Swnj */ 5673244Swnj if (addr->tssr&TS_SC) { 5683244Swnj switch (addr->tssr & TS_TC) { 5693244Swnj case TS_UNREC: /* unrecoverable */ 5703244Swnj case TS_FATAL: /* fatal error */ 5713244Swnj case TS_ATTN: /* attention (shouldn't happen) */ 5723244Swnj case TS_RECNM: /* recoverable, no motion */ 5733244Swnj break; 5741900Swnj 5753244Swnj case TS_SUCC: /* success termination */ 5763244Swnj printf("ts%d: success\n", TSUNIT(minor(bp->b_dev))); 5773244Swnj goto ignoreerr; 5781900Swnj 5793244Swnj case TS_ALERT: /* tape status alert */ 5803244Swnj /* 5813244Swnj * If we hit the end of the tape file, 5823244Swnj * update our position. 5833244Swnj */ 5843244Swnj if (sc->sc_sts.s_xs0 & (TS_TMK|TS_EOT)) { 5853244Swnj tsseteof(bp); /* set blkno and nxrec */ 5863244Swnj state = SCOM; /* force completion */ 5873244Swnj /* 5883244Swnj * Stuff bc so it will be unstuffed correctly 5893244Swnj * later to get resid. 5903244Swnj */ 5913244Swnj sc->sc_sts.s_rbpcr = bp->b_bcount; 5923244Swnj goto opdone; 5933244Swnj } 5943244Swnj /* 5953244Swnj * If we were reading raw tape and the record was too long 5963244Swnj * or too short, then we don't consider this an error. 5973244Swnj */ 5983244Swnj if (bp == &rtsbuf[TSUNIT(bp->b_dev)] && (bp->b_flags&B_READ) && 5993244Swnj sc->sc_sts.s_xs0&(TS_RLS|TS_RLL)) 6003244Swnj goto ignoreerr; 6013244Swnj case TS_RECOV: /* recoverable, tape moved */ 6023244Swnj /* 6033244Swnj * If this was an i/o operation retry up to 8 times. 6043244Swnj */ 6053244Swnj if (state==SIO) { 6063244Swnj if (++um->um_tab.b_errcnt < 7) { 6073244Swnj ubadone(um); 6083244Swnj goto opcont; 6093244Swnj } else 6103244Swnj sc->sc_blkno++; 6113244Swnj } else { 6123244Swnj /* 6133244Swnj * Non-i/o errors on non-raw tape 6143244Swnj * cause it to close. 6153244Swnj */ 6163244Swnj if (sc->sc_openf>0 && bp != &rtsbuf[TSUNIT(bp->b_dev)]) 6173244Swnj sc->sc_openf = -1; 6183244Swnj } 6191900Swnj break; 6203244Swnj 6213244Swnj case TS_REJECT: /* function reject */ 6223244Swnj if (state == SIO && sc->sc_sts.s_xs0 & TS_WLE) 62318322Sralph tprintf(sc->sc_ttyp, "ts%d: write locked\n", 62418322Sralph TSUNIT(bp->b_dev)); 6253244Swnj if ((sc->sc_sts.s_xs0 & TS_ONL) == 0) 62618322Sralph tprintf(sc->sc_ttyp, "ts%d: offline\n", 62718322Sralph TSUNIT(bp->b_dev)); 6281900Swnj break; 6291900Swnj } 6303244Swnj /* 6313244Swnj * Couldn't recover error 6323244Swnj */ 63318322Sralph tprintf(sc->sc_ttyp, "ts%d: hard error bn%d xs0=%b", 63418322Sralph TSUNIT(bp->b_dev), bp->b_blkno, sc->sc_sts.s_xs0, TSXS0_BITS); 6353647Swnj if (sc->sc_sts.s_xs1) 63618322Sralph tprintf(sc->sc_ttyp, " xs1=%b", sc->sc_sts.s_xs1, 63718322Sralph TSXS1_BITS); 6383647Swnj if (sc->sc_sts.s_xs2) 63918322Sralph tprintf(sc->sc_ttyp, " xs2=%b", sc->sc_sts.s_xs2, 64018322Sralph TSXS2_BITS); 6413647Swnj if (sc->sc_sts.s_xs3) 64218322Sralph tprintf(sc->sc_ttyp, " xs3=%b", sc->sc_sts.s_xs3, 64318322Sralph TSXS3_BITS); 64418322Sralph tprintf(sc->sc_ttyp, "\n"); 6453244Swnj bp->b_flags |= B_ERROR; 6463244Swnj goto opdone; 6473244Swnj } 6483244Swnj /* 6493244Swnj * Advance tape control FSM. 6503244Swnj */ 6513244Swnj ignoreerr: 6523244Swnj switch (state) { 6531900Swnj 6543244Swnj case SIO: 6553244Swnj /* 6563244Swnj * Read/write increments tape block number 6573244Swnj */ 6583244Swnj sc->sc_blkno++; 659*30917Skarels sc->sc_blks++; 660*30917Skarels if (um->um_tab.b_errcnt) 661*30917Skarels sc->sc_softerrs++; 6623244Swnj goto opdone; 6631900Swnj 6641900Swnj case SCOM: 6653244Swnj /* 6663244Swnj * For forward/backward space record update current position. 6673244Swnj */ 6683244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) 66926294Skarels switch ((int)bp->b_command) { 6701900Swnj 6713244Swnj case TS_SFORW: 6723244Swnj sc->sc_blkno += bp->b_repcnt; 6733244Swnj break; 6741900Swnj 6753244Swnj case TS_SREV: 6763244Swnj sc->sc_blkno -= bp->b_repcnt; 6773244Swnj break; 6783244Swnj } 6793244Swnj goto opdone; 6803244Swnj 6813244Swnj case SSEEK: 6827383Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno); 6833244Swnj goto opcont; 6843244Swnj 6851900Swnj default: 6863244Swnj panic("tsintr"); 6871900Swnj } 6883244Swnj opdone: 6893244Swnj /* 6903244Swnj * Reset error count and remove 6913244Swnj * from device queue. 6923244Swnj */ 6933244Swnj um->um_tab.b_errcnt = 0; 6943327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 6953244Swnj bp->b_resid = sc->sc_sts.s_rbpcr; 6963244Swnj ubadone(um); 6973244Swnj iodone(bp); 6983327Swnj if (um->um_tab.b_actf->b_actf == 0) 6993244Swnj return; 7003244Swnj opcont: 7013244Swnj tsstart(um); 7023244Swnj } 7033244Swnj 7043244Swnj tsseteof(bp) 7053244Swnj register struct buf *bp; 7063244Swnj { 7073244Swnj register int tsunit = TSUNIT(bp->b_dev); 7083244Swnj register struct ts_softc *sc = &ts_softc[tsunit]; 7093244Swnj 7103244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) { 7117383Ssam if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 7123244Swnj /* reversing */ 7137383Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno) - sc->sc_sts.s_rbpcr; 7143244Swnj sc->sc_blkno = sc->sc_nxrec; 7153244Swnj } else { 7163244Swnj /* spacing forward */ 7177383Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno) + sc->sc_sts.s_rbpcr; 7183244Swnj sc->sc_nxrec = sc->sc_blkno - 1; 7191900Swnj } 7203244Swnj return; 7213244Swnj } 7223244Swnj /* eof on read */ 7237383Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno); 7241900Swnj } 7251900Swnj 7267733Sroot tsread(dev, uio) 7273244Swnj dev_t dev; 7287733Sroot struct uio *uio; 7291900Swnj { 7308164Sroot int errno; 7313244Swnj 7328164Sroot errno = tsphys(dev, uio); 7338164Sroot if (errno) 7348164Sroot return (errno); 7358164Sroot return (physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_READ, minphys, uio)); 7361900Swnj } 7371900Swnj 7387841Sroot tswrite(dev, uio) 7393244Swnj dev_t dev; 7407841Sroot struct uio *uio; 7411900Swnj { 7428164Sroot int errno; 7433244Swnj 7448164Sroot errno = tsphys(dev, uio); 7458164Sroot if (errno) 7468164Sroot return (errno); 7478164Sroot return (physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_WRITE, minphys, uio)); 7481900Swnj } 7491900Swnj 7503244Swnj /* 7513244Swnj * Check that a raw device exists. 7523244Swnj * If it does, set up sc_blkno and sc_nxrec 7533244Swnj * so that the tape will appear positioned correctly. 7543244Swnj */ 7557733Sroot tsphys(dev, uio) 7563244Swnj dev_t dev; 7577733Sroot struct uio *uio; 7581900Swnj { 7593244Swnj register int tsunit = TSUNIT(dev); 7603244Swnj register daddr_t a; 7613244Swnj register struct ts_softc *sc; 7623244Swnj register struct uba_device *ui; 7631900Swnj 7647841Sroot if (tsunit >= NTS || (ui=tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) 7657733Sroot return (ENXIO); 7663244Swnj sc = &ts_softc[tsunit]; 7677841Sroot a = bdbtofsb(uio->uio_offset >> 9); 7683244Swnj sc->sc_blkno = a; 7693244Swnj sc->sc_nxrec = a + 1; 7707733Sroot return (0); 7711900Swnj } 7721918Swnj 7733244Swnj tsreset(uban) 7743244Swnj int uban; 7751918Swnj { 7763244Swnj register struct uba_ctlr *um; 7775693Sroot register struct uba_device *ui; 7785693Sroot register struct buf *dp; 7793244Swnj register ts11; 7801918Swnj 7813244Swnj for (ts11 = 0; ts11 < NTS; ts11++) { 7823244Swnj if ((um = tsminfo[ts11]) == 0 || um->um_alive == 0 || 7833244Swnj um->um_ubanum != uban) 7843244Swnj continue; 7853244Swnj printf(" ts%d", ts11); 7863244Swnj um->um_tab.b_active = 0; 7873244Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7885693Sroot if (ts_softc[ts11].sc_openf > 0) 7895693Sroot ts_softc[ts11].sc_openf = -1; 7903244Swnj if (um->um_ubinfo) { 7913244Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 7929356Ssam um->um_ubinfo = 0; 7933244Swnj } 7945693Sroot if ((ui = tsdinfo[ts11]) && ui->ui_mi == um && ui->ui_alive) { 7955693Sroot dp = &tsutab[ts11]; 7965693Sroot dp->b_active = 0; 7975693Sroot dp->b_forw = 0; 7985693Sroot if (um->um_tab.b_actf == NULL) 7995693Sroot um->um_tab.b_actf = dp; 8005693Sroot else 8015693Sroot um->um_tab.b_actl->b_forw = dp; 8025693Sroot um->um_tab.b_actl = dp; 8035693Sroot } 80417432Skarels ts_softc[ts11].sc_mapped = 0; 8053989Sroot (void) tsinit(ts11); 8063244Swnj tsstart(um); 8071918Swnj } 8081918Swnj } 8091918Swnj 8103244Swnj /*ARGSUSED*/ 8117633Ssam tsioctl(dev, cmd, data, flag) 8127633Ssam caddr_t data; 8133244Swnj dev_t dev; 8141918Swnj { 8153244Swnj int tsunit = TSUNIT(dev); 8163244Swnj register struct ts_softc *sc = &ts_softc[tsunit]; 8173244Swnj register struct buf *bp = &ctsbuf[TSUNIT(dev)]; 8183244Swnj register callcount; 8193244Swnj int fcount; 8207633Ssam struct mtop *mtop; 8217633Ssam struct mtget *mtget; 8223244Swnj /* we depend of the values and order of the MT codes here */ 8233244Swnj static tsops[] = 8243656Swnj {TS_WEOF,TS_SFORWF,TS_SREVF,TS_SFORW,TS_SREV,TS_REW,TS_OFFL,TS_SENSE}; 8251918Swnj 8263244Swnj switch (cmd) { 8277633Ssam 8283244Swnj case MTIOCTOP: /* tape operation */ 8297633Ssam mtop = (struct mtop *)data; 8308575Sroot switch (mtop->mt_op) { 8317633Ssam 8323244Swnj case MTWEOF: 8337633Ssam callcount = mtop->mt_count; 8343244Swnj fcount = 1; 8353244Swnj break; 8367633Ssam 8373244Swnj case MTFSF: case MTBSF: 8383244Swnj case MTFSR: case MTBSR: 8393244Swnj callcount = 1; 8407633Ssam fcount = mtop->mt_count; 8413244Swnj break; 8427633Ssam 8433244Swnj case MTREW: case MTOFFL: case MTNOP: 8443244Swnj callcount = 1; 8453244Swnj fcount = 1; 8463244Swnj break; 8477633Ssam 8483244Swnj default: 8498575Sroot return (ENXIO); 8503244Swnj } 8518575Sroot if (callcount <= 0 || fcount <= 0) 8528575Sroot return (EINVAL); 8533244Swnj while (--callcount >= 0) { 8547633Ssam tscommand(dev, tsops[mtop->mt_op], fcount); 8557633Ssam if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) && 8568611Sroot bp->b_resid) 8578575Sroot return (EIO); 8583244Swnj if ((bp->b_flags&B_ERROR) || sc->sc_sts.s_xs0&TS_BOT) 8593244Swnj break; 8603244Swnj } 8618649Sroot return (geterror(bp)); 8627633Ssam 8633244Swnj case MTIOCGET: 8647633Ssam mtget = (struct mtget *)data; 8657633Ssam mtget->mt_dsreg = 0; 8667633Ssam mtget->mt_erreg = sc->sc_sts.s_xs0; 8677633Ssam mtget->mt_resid = sc->sc_resid; 8687633Ssam mtget->mt_type = MT_ISTS; 8698575Sroot break; 8707633Ssam 8713244Swnj default: 8728575Sroot return (ENXIO); 8733244Swnj } 8748575Sroot return (0); 8751918Swnj } 8761918Swnj 8773244Swnj #define DBSIZE 20 8783244Swnj 8793244Swnj tsdump() 8801918Swnj { 8813244Swnj register struct uba_device *ui; 8823244Swnj register struct uba_regs *up; 8835693Sroot register struct tsdevice *addr; 8843244Swnj int blk, num; 8853244Swnj int start; 8861918Swnj 8873244Swnj start = 0; 8883244Swnj num = maxfree; 8893244Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 8903244Swnj if (tsdinfo[0] == 0) 8913244Swnj return (ENXIO); 8923244Swnj ui = phys(tsdinfo[0], struct uba_device *); 8933244Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 8948703Sroot ubainit(up); 8953244Swnj DELAY(1000000); 8965693Sroot addr = (struct tsdevice *)ui->ui_physaddr; 8973244Swnj addr->tssr = 0; 8983244Swnj tswait(addr); 8993244Swnj while (num > 0) { 9003244Swnj blk = num > DBSIZE ? DBSIZE : num; 9013244Swnj tsdwrite(start, blk, addr, up); 9023244Swnj start += blk; 9033244Swnj num -= blk; 9043244Swnj } 9053244Swnj tseof(addr); 9063244Swnj tseof(addr); 9073244Swnj tswait(addr); 9083244Swnj if (addr->tssr&TS_SC) 9093244Swnj return (EIO); 9103244Swnj addr->tssr = 0; 9113244Swnj tswait(addr); 9123244Swnj return (0); 9131918Swnj } 9141918Swnj 9153244Swnj tsdwrite(dbuf, num, addr, up) 9168635Sroot register int dbuf, num; 9175693Sroot register struct tsdevice *addr; 9183244Swnj struct uba_regs *up; 9191918Swnj { 9203244Swnj register struct pte *io; 9213244Swnj register int npf; 9221918Swnj 9233244Swnj tswait(addr); 9243244Swnj io = up->uba_map; 9253244Swnj npf = num+1; 9263244Swnj while (--npf != 0) 9273244Swnj *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); 9283244Swnj *(int *)io = 0; 9293244Swnj #ifdef notyet 9303244Swnj addr->tsbc = -(num*NBPG); 9313244Swnj addr->tsba = 0; 9323244Swnj addr->tscs = TS_WCOM | TM_GO; 9333244Swnj #endif 9341918Swnj } 9351918Swnj 9363244Swnj tswait(addr) 9375693Sroot register struct tsdevice *addr; 9381918Swnj { 9393244Swnj register s; 9401918Swnj 9413244Swnj do 9423244Swnj s = addr->tssr; 9433244Swnj while ((s & TS_SSR) == 0); 9441918Swnj } 9451918Swnj 9463244Swnj tseof(addr) 9475693Sroot struct tsdevice *addr; 9481918Swnj { 9491918Swnj 9503244Swnj tswait(addr); 9513244Swnj #ifdef notyet 9523244Swnj addr->tscs = TS_WEOF | TM_GO; 9533244Swnj #endif 9541918Swnj } 9551900Swnj #endif 956