123349Smckusick /* 223349Smckusick * Copyright (c) 1982 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*27253Skridle * @(#)ts.c 6.10 (Berkeley) 04/22/86 723349Smckusick */ 81900Swnj 91941Swnj #include "ts.h" 101900Swnj #if NTS > 0 111900Swnj /* 121900Swnj * TS11 tape driver 133244Swnj * 143244Swnj * TODO: 155693Sroot * write dump code 161900Swnj */ 179779Ssam #include "../machine/pte.h" 189779Ssam 1917080Sbloom #include "param.h" 2017080Sbloom #include "systm.h" 2117080Sbloom #include "buf.h" 2217080Sbloom #include "dir.h" 2317080Sbloom #include "conf.h" 2417080Sbloom #include "user.h" 2517080Sbloom #include "file.h" 2617080Sbloom #include "map.h" 2717080Sbloom #include "vm.h" 2817080Sbloom #include "ioctl.h" 2917080Sbloom #include "mtio.h" 3017080Sbloom #include "cmap.h" 3117080Sbloom #include "uio.h" 3218322Sralph #include "tty.h" 331900Swnj 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 */ 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*/ 1183244Swnj tsprobe(reg) 1193244Swnj caddr_t reg; 1203244Swnj { 1213244Swnj register int br, cvec; /* must be r11,r10; value-result */ 1221900Swnj 1233244Swnj #ifdef lint 1243244Swnj br = 0; cvec = br; br = cvec; 1254937Swnj tsintr(0); 1263244Swnj #endif 1275693Sroot ((struct tsdevice *)reg)->tssr = 0; 1285693Sroot DELAY(100); 1295693Sroot if ((((struct tsdevice *)reg)->tssr & TS_NBA) == 0) 1305693Sroot return(0); 1315693Sroot /* IT'S TOO HARD TO MAKE THIS THING INTERRUPT JUST TO FIND ITS VECTOR */ 1325693Sroot cvec = ((unsigned)reg) & 07 ? 0260 : 0224; 1333244Swnj br = 0x15; 1347407Skre return (sizeof (struct tsdevice)); 1353244Swnj } 1361900Swnj 1373244Swnj /* 1383244Swnj * TS11 only supports one drive per controller; 1393244Swnj * check for ui_slave == 0. 1403244Swnj * 1413244Swnj * DO WE REALLY NEED THIS ROUTINE??? 1423244Swnj */ 1433244Swnj /*ARGSUSED*/ 1443244Swnj tsslave(ui, reg) 1453244Swnj struct uba_device *ui; 1463244Swnj caddr_t reg; 1473244Swnj { 1481900Swnj 1493244Swnj if (ui->ui_slave) /* non-zero slave not allowed */ 1503244Swnj return(0); 1513244Swnj return (1); 1523244Swnj } 1531900Swnj 1543244Swnj /* 1553244Swnj * Record attachment of the unit to the controller. 1563244Swnj * 1573244Swnj * SHOULD THIS ROUTINE DO ANYTHING??? 1583244Swnj */ 1593244Swnj /*ARGSUSED*/ 1603244Swnj tsattach(ui) 1613244Swnj struct uba_device *ui; 1623244Swnj { 1631900Swnj 1643244Swnj } 1651900Swnj 1663244Swnj /* 1673244Swnj * Open the device. Tapes are unique open 1683244Swnj * devices, so we refuse if it is already open. 1693244Swnj * We also check that a tape is available, and 1703244Swnj * don't block waiting here; if you want to wait 1713244Swnj * for a tape you should timeout in user code. 1723244Swnj */ 1731900Swnj tsopen(dev, flag) 1743244Swnj dev_t dev; 1753244Swnj int flag; 1761900Swnj { 1773244Swnj register int tsunit; 1783244Swnj register struct uba_device *ui; 1793244Swnj register struct ts_softc *sc; 1801900Swnj 1813244Swnj tsunit = TSUNIT(dev); 18225054Skarels if (tsunit>=NTS || (ui = tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) 1838575Sroot return (ENXIO); 18425054Skarels if ((sc = &ts_softc[tsunit])->sc_openf) 18525054Skarels return (EBUSY); 1868575Sroot if (tsinit(tsunit)) 1878575Sroot return (ENXIO); 1883244Swnj tscommand(dev, TS_SENSE, 1); 1893711Sroot if ((sc->sc_sts.s_xs0&TS_ONL) == 0) { 1903711Sroot uprintf("ts%d: not online\n", tsunit); 1918575Sroot return (EIO); 1921900Swnj } 19324267Sbloom if ((flag&FWRITE) && (sc->sc_sts.s_xs0&TS_WLK)) { 1943711Sroot uprintf("ts%d: no write ring\n", tsunit); 1958575Sroot return (EIO); 1963711Sroot } 1973244Swnj sc->sc_openf = 1; 1983244Swnj sc->sc_blkno = (daddr_t)0; 1993244Swnj sc->sc_nxrec = INF; 2003244Swnj sc->sc_lastiow = 0; 20118322Sralph sc->sc_ttyp = u.u_ttyp; 2028575Sroot return (0); 2031900Swnj } 2041900Swnj 2053244Swnj /* 2063244Swnj * Close tape device. 2073244Swnj * 2083244Swnj * If tape was open for writing or last operation was 2093244Swnj * a write, then write two EOF's and backspace over the last one. 2103244Swnj * Unless this is a non-rewinding special file, rewind the tape. 2113244Swnj * Make the tape available to others. 2123244Swnj */ 2131900Swnj tsclose(dev, flag) 2143244Swnj register dev_t dev; 2153244Swnj register flag; 2161900Swnj { 2173244Swnj register struct ts_softc *sc = &ts_softc[TSUNIT(dev)]; 2181900Swnj 2193244Swnj if (flag == FWRITE || (flag&FWRITE) && sc->sc_lastiow) { 2203244Swnj tscommand(dev, TS_WEOF, 1); 2213244Swnj tscommand(dev, TS_WEOF, 1); 2223244Swnj tscommand(dev, TS_SREV, 1); 2231900Swnj } 2243244Swnj if ((minor(dev)&T_NOREWIND) == 0) 2253244Swnj /* 2263244Swnj * 0 count means don't hang waiting for rewind complete 2273244Swnj * rather ctsbuf stays busy until the operation completes 2283244Swnj * preventing further opens from completing by 2293244Swnj * preventing a TS_SENSE from completing. 2303244Swnj */ 2313244Swnj tscommand(dev, TS_REW, 0); 2323244Swnj sc->sc_openf = 0; 2331900Swnj } 2341900Swnj 2353244Swnj /* 2363244Swnj * Initialize the TS11. Set up Unibus mapping for command 2373244Swnj * packets and set device characteristics. 2383244Swnj */ 2393244Swnj tsinit(unit) 2403244Swnj register int unit; 2411900Swnj { 2423244Swnj register struct ts_softc *sc = &ts_softc[unit]; 2433244Swnj register struct uba_ctlr *um = tsminfo[unit]; 2445693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 2453244Swnj register int i; 2463244Swnj 2473244Swnj /* 2483244Swnj * Map the command and message packets into Unibus 2493244Swnj * address space. We do all the command and message 2503244Swnj * packets at once to minimize the amount of Unibus 2513244Swnj * mapping necessary. 2523244Swnj */ 2535693Sroot if (sc->sc_mapped == 0) { 2545693Sroot ctsbuf[unit].b_un.b_addr = (caddr_t)sc; 2555693Sroot ctsbuf[unit].b_bcount = sizeof(*sc); 2563244Swnj i = ubasetup(um->um_ubanum, &ctsbuf[unit], 0); 2573244Swnj i &= 0777777; 2585693Sroot sc->sc_ubaddr = (struct ts_softc *)i; 2595693Sroot sc->sc_mapped++; 2603244Swnj } 2613244Swnj /* 2623244Swnj * Now initialize the TS11 controller. 2633244Swnj * Set the characteristics. 2643244Swnj */ 2653668Swnj if (addr->tssr & (TS_NBA|TS_OFL)) { 2663244Swnj addr->tssr = 0; /* subsystem initialize */ 2673244Swnj tswait(addr); 2685693Sroot i = (int)&sc->sc_ubaddr->sc_cmd; /* Unibus addr of cmd */ 2693244Swnj sc->sc_uba = (u_short)(i + ((i>>16)&3)); 2705693Sroot sc->sc_char.char_addr = (int)&sc->sc_ubaddr->sc_sts; 2713244Swnj sc->sc_char.char_size = sizeof(struct ts_sts); 2723244Swnj sc->sc_char.char_mode = TS_ESS; 2733244Swnj sc->sc_cmd.c_cmd = TS_ACK | TS_SETCHR; 2745693Sroot i = (int)&sc->sc_ubaddr->sc_char; 2753327Swnj sc->sc_cmd.c_loba = i; 2763327Swnj sc->sc_cmd.c_hiba = (i>>16)&3; 2773244Swnj sc->sc_cmd.c_size = sizeof(struct ts_char); 2783244Swnj addr->tsdb = sc->sc_uba; 2793244Swnj tswait(addr); 2803327Swnj if (addr->tssr & TS_NBA) 2813327Swnj return(1); 2823244Swnj } 2833244Swnj return(0); 2843244Swnj } 2853244Swnj 2863244Swnj /* 2873244Swnj * Execute a command on the tape drive 2883244Swnj * a specified number of times. 2893244Swnj */ 2903244Swnj tscommand(dev, com, count) 2913244Swnj dev_t dev; 2923244Swnj int com, count; 2933244Swnj { 2941900Swnj register struct buf *bp; 2955438Sroot register int s; 2961900Swnj 2973244Swnj bp = &ctsbuf[TSUNIT(dev)]; 2985438Sroot s = spl5(); 2993244Swnj while (bp->b_flags&B_BUSY) { 3003244Swnj /* 3013244Swnj * This special check is because B_BUSY never 3023244Swnj * gets cleared in the non-waiting rewind case. 3033244Swnj */ 3043244Swnj if (bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 3053244Swnj break; 3061900Swnj bp->b_flags |= B_WANTED; 3071900Swnj sleep((caddr_t)bp, PRIBIO); 3081900Swnj } 3093244Swnj bp->b_flags = B_BUSY|B_READ; 3105438Sroot splx(s); 3113244Swnj bp->b_dev = dev; 3123244Swnj bp->b_repcnt = count; 3133244Swnj bp->b_command = com; 3141900Swnj bp->b_blkno = 0; 3151900Swnj tsstrategy(bp); 3163244Swnj /* 3173244Swnj * In case of rewind from close, don't wait. 3183244Swnj * This is the only case where count can be 0. 3193244Swnj */ 3203244Swnj if (count == 0) 3213244Swnj return; 3221900Swnj iowait(bp); 3233244Swnj if (bp->b_flags&B_WANTED) 3241900Swnj wakeup((caddr_t)bp); 3253244Swnj bp->b_flags &= B_ERROR; 3261900Swnj } 3271900Swnj 3283244Swnj /* 3293244Swnj * Queue a tape operation. 3303244Swnj */ 3311900Swnj tsstrategy(bp) 3323244Swnj register struct buf *bp; 3331900Swnj { 3343244Swnj int tsunit = TSUNIT(bp->b_dev); 3353244Swnj register struct uba_ctlr *um; 3363327Swnj register struct buf *dp; 3375438Sroot register int s; 3381900Swnj 3393244Swnj /* 3403244Swnj * Put transfer at end of controller queue 3413244Swnj */ 3421900Swnj bp->av_forw = NULL; 3433244Swnj um = tsdinfo[tsunit]->ui_mi; 3445438Sroot s = spl5(); 3455693Sroot dp = &tsutab[tsunit]; 3463327Swnj if (dp->b_actf == NULL) 3473327Swnj dp->b_actf = bp; 3481900Swnj else 3493327Swnj dp->b_actl->av_forw = bp; 3503327Swnj dp->b_actl = bp; 3513327Swnj um->um_tab.b_actf = um->um_tab.b_actl = dp; 3523244Swnj /* 3533244Swnj * If the controller is not busy, get 3543244Swnj * it going. 3553244Swnj */ 3563244Swnj if (um->um_tab.b_active == 0) 3573244Swnj tsstart(um); 3585438Sroot splx(s); 3591900Swnj } 3601900Swnj 3613244Swnj /* 3623244Swnj * Start activity on a ts controller. 3633244Swnj */ 3643244Swnj tsstart(um) 3653244Swnj register struct uba_ctlr *um; 3661900Swnj { 3671900Swnj register struct buf *bp; 3685693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 3693244Swnj register struct ts_softc *sc; 3703244Swnj register struct ts_cmd *tc; 3713244Swnj register struct uba_device *ui; 3723244Swnj int tsunit, cmd; 3731900Swnj daddr_t blkno; 3741900Swnj 3753244Swnj /* 3763244Swnj * Start the controller if there is something for it to do. 3773244Swnj */ 3783244Swnj loop: 3793327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 3801900Swnj return; 3813244Swnj tsunit = TSUNIT(bp->b_dev); 3823244Swnj ui = tsdinfo[tsunit]; 3833244Swnj sc = &ts_softc[tsunit]; 3843244Swnj tc = &sc->sc_cmd; 3853244Swnj /* 3863244Swnj * Default is that last command was NOT a write command; 3873244Swnj * if we do a write command we will notice this in tsintr(). 3883244Swnj */ 3893656Swnj sc->sc_lastiow = 0; 3903244Swnj if (sc->sc_openf < 0 || (addr->tssr&TS_OFL)) { 3913244Swnj /* 3923244Swnj * Have had a hard error on a non-raw tape 3933244Swnj * or the tape unit is now unavailable 3943244Swnj * (e.g. taken off line). 3953244Swnj */ 3963244Swnj bp->b_flags |= B_ERROR; 3973244Swnj goto next; 3983244Swnj } 3993244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) { 4003244Swnj /* 4013244Swnj * Execute control operation with the specified count. 4023244Swnj */ 4033244Swnj um->um_tab.b_active = 4043244Swnj bp->b_command == TS_REW ? SREW : SCOM; 4053244Swnj tc->c_repcnt = bp->b_repcnt; 4063244Swnj goto dobpcmd; 4073244Swnj } 4083244Swnj /* 4093244Swnj * The following checks handle boundary cases for operation 4103244Swnj * on non-raw tapes. On raw tapes the initialization of 4113244Swnj * sc->sc_nxrec by tsphys causes them to be skipped normally 4123244Swnj * (except in the case of retries). 4133244Swnj */ 4147383Ssam if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 4153244Swnj /* 4163244Swnj * Can't read past known end-of-file. 4173244Swnj */ 4183244Swnj bp->b_flags |= B_ERROR; 4193244Swnj bp->b_error = ENXIO; 4203244Swnj goto next; 4213244Swnj } 4227383Ssam if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && 4233244Swnj bp->b_flags&B_READ) { 4243244Swnj /* 4253244Swnj * Reading at end of file returns 0 bytes. 4263244Swnj */ 4273244Swnj bp->b_resid = bp->b_bcount; 4283244Swnj clrbuf(bp); 4293244Swnj goto next; 4303244Swnj } 4313244Swnj if ((bp->b_flags&B_READ) == 0) 4323244Swnj /* 4333244Swnj * Writing sets EOF 4343244Swnj */ 4357383Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; 4363244Swnj /* 4373244Swnj * If the data transfer command is in the correct place, 4383244Swnj * set up all the registers except the csr, and give 4393244Swnj * control over to the UNIBUS adapter routines, to 4403244Swnj * wait for resources to start the i/o. 4413244Swnj */ 4427383Ssam if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { 4433244Swnj tc->c_size = bp->b_bcount; 4443244Swnj if ((bp->b_flags&B_READ) == 0) 4453244Swnj cmd = TS_WCOM; 4461900Swnj else 4473244Swnj cmd = TS_RCOM; 4483244Swnj if (um->um_tab.b_errcnt) 4493244Swnj cmd |= TS_RETRY; 4503244Swnj um->um_tab.b_active = SIO; 4513327Swnj tc->c_cmd = TS_ACK | TS_CVC | TS_IE | cmd; 4523244Swnj (void) ubago(ui); 4533244Swnj return; 4543244Swnj } 4553244Swnj /* 4563244Swnj * Tape positioned incorrectly; 4573244Swnj * set to seek forwards or backwards to the correct spot. 4583244Swnj * This happens for raw tapes only on error retries. 4593244Swnj */ 4603244Swnj um->um_tab.b_active = SSEEK; 4617383Ssam if (blkno < bdbtofsb(bp->b_blkno)) { 4623244Swnj bp->b_command = TS_SFORW; 4637383Ssam tc->c_repcnt = bdbtofsb(bp->b_blkno) - blkno; 4641900Swnj } else { 4653244Swnj bp->b_command = TS_SREV; 4667383Ssam tc->c_repcnt = blkno - bdbtofsb(bp->b_blkno); 4671900Swnj } 4683244Swnj dobpcmd: 4693244Swnj /* 4703244Swnj * Do the command in bp. 4713244Swnj */ 4723327Swnj tc->c_cmd = TS_ACK | TS_CVC | TS_IE | bp->b_command; 4733244Swnj addr->tsdb = sc->sc_uba; 4741900Swnj return; 4751900Swnj 4763244Swnj next: 4773244Swnj /* 4783244Swnj * Done with this operation due to error or 4793244Swnj * the fact that it doesn't do anything. 4803244Swnj * Release UBA resources (if any), dequeue 4813244Swnj * the transfer and continue processing this slave. 4823244Swnj */ 4833244Swnj if (um->um_ubinfo) 4843244Swnj ubadone(um); 4853244Swnj um->um_tab.b_errcnt = 0; 4863327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 4871900Swnj iodone(bp); 4881900Swnj goto loop; 4891900Swnj } 4901900Swnj 4913244Swnj /* 4923244Swnj * The UNIBUS resources we needed have been 4933244Swnj * allocated to us; start the device. 4943244Swnj */ 4953244Swnj tsdgo(um) 4963244Swnj register struct uba_ctlr *um; 4971900Swnj { 4985693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 4993244Swnj register struct ts_softc *sc = &ts_softc[um->um_ctlr]; 5003327Swnj register int i; 5013244Swnj 50226139Skarels /* 50326139Skarels * The uba code uses byte-offset mode if using bdp; 50426139Skarels * mask off the low bit here. 50526139Skarels */ 5063327Swnj i = um->um_ubinfo & 0777777; 50726139Skarels if (UBAI_BDP(um->um_ubinfo)) 50826139Skarels i &= ~1; 5093327Swnj sc->sc_cmd.c_loba = i; 5103327Swnj sc->sc_cmd.c_hiba = (i>>16)&3; 5113244Swnj addr->tsdb = sc->sc_uba; 5123244Swnj } 5133244Swnj 5143244Swnj /* 5153244Swnj * Ts interrupt routine. 5163244Swnj */ 5173244Swnj /*ARGSUSED*/ 5183244Swnj tsintr(ts11) 5193244Swnj int ts11; 5203244Swnj { 5211900Swnj register struct buf *bp; 5223244Swnj register struct uba_ctlr *um = tsminfo[ts11]; 5235693Sroot register struct tsdevice *addr; 5243244Swnj register struct ts_softc *sc; 5253244Swnj int tsunit; 5263244Swnj register state; 527*27253Skridle #if VAX630 528*27253Skridle spl5(); 529*27253Skridle #endif 5303327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 5311900Swnj return; 5323244Swnj tsunit = TSUNIT(bp->b_dev); 5335693Sroot addr = (struct tsdevice *)tsdinfo[tsunit]->ui_addr; 5343244Swnj /* 5353244Swnj * If last command was a rewind, and tape is still 5363244Swnj * rewinding, wait for the rewind complete interrupt. 5373244Swnj * 5383244Swnj * SHOULD NEVER GET AN INTERRUPT IN THIS STATE. 5393244Swnj */ 5403244Swnj if (um->um_tab.b_active == SREW) { 5413244Swnj um->um_tab.b_active = SCOM; 5423244Swnj if ((addr->tssr&TS_SSR) == 0) 5433244Swnj return; 5443244Swnj } 5453244Swnj /* 5463244Swnj * An operation completed... record status 5473244Swnj */ 5483244Swnj sc = &ts_softc[tsunit]; 5493244Swnj if ((bp->b_flags & B_READ) == 0) 5503244Swnj sc->sc_lastiow = 1; 5513244Swnj state = um->um_tab.b_active; 5523244Swnj um->um_tab.b_active = 0; 5533244Swnj /* 5543244Swnj * Check for errors. 5553244Swnj */ 5563244Swnj if (addr->tssr&TS_SC) { 5573244Swnj switch (addr->tssr & TS_TC) { 5583244Swnj case TS_UNREC: /* unrecoverable */ 5593244Swnj case TS_FATAL: /* fatal error */ 5603244Swnj case TS_ATTN: /* attention (shouldn't happen) */ 5613244Swnj case TS_RECNM: /* recoverable, no motion */ 5623244Swnj break; 5631900Swnj 5643244Swnj case TS_SUCC: /* success termination */ 5653244Swnj printf("ts%d: success\n", TSUNIT(minor(bp->b_dev))); 5663244Swnj goto ignoreerr; 5671900Swnj 5683244Swnj case TS_ALERT: /* tape status alert */ 5693244Swnj /* 5703244Swnj * If we hit the end of the tape file, 5713244Swnj * update our position. 5723244Swnj */ 5733244Swnj if (sc->sc_sts.s_xs0 & (TS_TMK|TS_EOT)) { 5743244Swnj tsseteof(bp); /* set blkno and nxrec */ 5753244Swnj state = SCOM; /* force completion */ 5763244Swnj /* 5773244Swnj * Stuff bc so it will be unstuffed correctly 5783244Swnj * later to get resid. 5793244Swnj */ 5803244Swnj sc->sc_sts.s_rbpcr = bp->b_bcount; 5813244Swnj goto opdone; 5823244Swnj } 5833244Swnj /* 5843244Swnj * If we were reading raw tape and the record was too long 5853244Swnj * or too short, then we don't consider this an error. 5863244Swnj */ 5873244Swnj if (bp == &rtsbuf[TSUNIT(bp->b_dev)] && (bp->b_flags&B_READ) && 5883244Swnj sc->sc_sts.s_xs0&(TS_RLS|TS_RLL)) 5893244Swnj goto ignoreerr; 5903244Swnj case TS_RECOV: /* recoverable, tape moved */ 5913244Swnj /* 5923244Swnj * If this was an i/o operation retry up to 8 times. 5933244Swnj */ 5943244Swnj if (state==SIO) { 5953244Swnj if (++um->um_tab.b_errcnt < 7) { 5963244Swnj ubadone(um); 5973244Swnj goto opcont; 5983244Swnj } else 5993244Swnj sc->sc_blkno++; 6003244Swnj } else { 6013244Swnj /* 6023244Swnj * Non-i/o errors on non-raw tape 6033244Swnj * cause it to close. 6043244Swnj */ 6053244Swnj if (sc->sc_openf>0 && bp != &rtsbuf[TSUNIT(bp->b_dev)]) 6063244Swnj sc->sc_openf = -1; 6073244Swnj } 6081900Swnj break; 6093244Swnj 6103244Swnj case TS_REJECT: /* function reject */ 6113244Swnj if (state == SIO && sc->sc_sts.s_xs0 & TS_WLE) 61218322Sralph tprintf(sc->sc_ttyp, "ts%d: write locked\n", 61318322Sralph TSUNIT(bp->b_dev)); 6143244Swnj if ((sc->sc_sts.s_xs0 & TS_ONL) == 0) 61518322Sralph tprintf(sc->sc_ttyp, "ts%d: offline\n", 61618322Sralph TSUNIT(bp->b_dev)); 6171900Swnj break; 6181900Swnj } 6193244Swnj /* 6203244Swnj * Couldn't recover error 6213244Swnj */ 62218322Sralph tprintf(sc->sc_ttyp, "ts%d: hard error bn%d xs0=%b", 62318322Sralph TSUNIT(bp->b_dev), bp->b_blkno, sc->sc_sts.s_xs0, TSXS0_BITS); 6243647Swnj if (sc->sc_sts.s_xs1) 62518322Sralph tprintf(sc->sc_ttyp, " xs1=%b", sc->sc_sts.s_xs1, 62618322Sralph TSXS1_BITS); 6273647Swnj if (sc->sc_sts.s_xs2) 62818322Sralph tprintf(sc->sc_ttyp, " xs2=%b", sc->sc_sts.s_xs2, 62918322Sralph TSXS2_BITS); 6303647Swnj if (sc->sc_sts.s_xs3) 63118322Sralph tprintf(sc->sc_ttyp, " xs3=%b", sc->sc_sts.s_xs3, 63218322Sralph TSXS3_BITS); 63318322Sralph tprintf(sc->sc_ttyp, "\n"); 6343244Swnj bp->b_flags |= B_ERROR; 6353244Swnj goto opdone; 6363244Swnj } 6373244Swnj /* 6383244Swnj * Advance tape control FSM. 6393244Swnj */ 6403244Swnj ignoreerr: 6413244Swnj switch (state) { 6421900Swnj 6433244Swnj case SIO: 6443244Swnj /* 6453244Swnj * Read/write increments tape block number 6463244Swnj */ 6473244Swnj sc->sc_blkno++; 6483244Swnj goto opdone; 6491900Swnj 6501900Swnj case SCOM: 6513244Swnj /* 6523244Swnj * For forward/backward space record update current position. 6533244Swnj */ 6543244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) 65526294Skarels switch ((int)bp->b_command) { 6561900Swnj 6573244Swnj case TS_SFORW: 6583244Swnj sc->sc_blkno += bp->b_repcnt; 6593244Swnj break; 6601900Swnj 6613244Swnj case TS_SREV: 6623244Swnj sc->sc_blkno -= bp->b_repcnt; 6633244Swnj break; 6643244Swnj } 6653244Swnj goto opdone; 6663244Swnj 6673244Swnj case SSEEK: 6687383Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno); 6693244Swnj goto opcont; 6703244Swnj 6711900Swnj default: 6723244Swnj panic("tsintr"); 6731900Swnj } 6743244Swnj opdone: 6753244Swnj /* 6763244Swnj * Reset error count and remove 6773244Swnj * from device queue. 6783244Swnj */ 6793244Swnj um->um_tab.b_errcnt = 0; 6803327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 6813244Swnj bp->b_resid = sc->sc_sts.s_rbpcr; 6823244Swnj ubadone(um); 6833244Swnj iodone(bp); 6843327Swnj if (um->um_tab.b_actf->b_actf == 0) 6853244Swnj return; 6863244Swnj opcont: 6873244Swnj tsstart(um); 6883244Swnj } 6893244Swnj 6903244Swnj tsseteof(bp) 6913244Swnj register struct buf *bp; 6923244Swnj { 6933244Swnj register int tsunit = TSUNIT(bp->b_dev); 6943244Swnj register struct ts_softc *sc = &ts_softc[tsunit]; 6953244Swnj 6963244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) { 6977383Ssam if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 6983244Swnj /* reversing */ 6997383Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno) - sc->sc_sts.s_rbpcr; 7003244Swnj sc->sc_blkno = sc->sc_nxrec; 7013244Swnj } else { 7023244Swnj /* spacing forward */ 7037383Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno) + sc->sc_sts.s_rbpcr; 7043244Swnj sc->sc_nxrec = sc->sc_blkno - 1; 7051900Swnj } 7063244Swnj return; 7073244Swnj } 7083244Swnj /* eof on read */ 7097383Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno); 7101900Swnj } 7111900Swnj 7127733Sroot tsread(dev, uio) 7133244Swnj dev_t dev; 7147733Sroot struct uio *uio; 7151900Swnj { 7168164Sroot int errno; 7173244Swnj 7188164Sroot errno = tsphys(dev, uio); 7198164Sroot if (errno) 7208164Sroot return (errno); 7218164Sroot return (physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_READ, minphys, uio)); 7221900Swnj } 7231900Swnj 7247841Sroot tswrite(dev, uio) 7253244Swnj dev_t dev; 7267841Sroot struct uio *uio; 7271900Swnj { 7288164Sroot int errno; 7293244Swnj 7308164Sroot errno = tsphys(dev, uio); 7318164Sroot if (errno) 7328164Sroot return (errno); 7338164Sroot return (physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_WRITE, minphys, uio)); 7341900Swnj } 7351900Swnj 7363244Swnj /* 7373244Swnj * Check that a raw device exists. 7383244Swnj * If it does, set up sc_blkno and sc_nxrec 7393244Swnj * so that the tape will appear positioned correctly. 7403244Swnj */ 7417733Sroot tsphys(dev, uio) 7423244Swnj dev_t dev; 7437733Sroot struct uio *uio; 7441900Swnj { 7453244Swnj register int tsunit = TSUNIT(dev); 7463244Swnj register daddr_t a; 7473244Swnj register struct ts_softc *sc; 7483244Swnj register struct uba_device *ui; 7491900Swnj 7507841Sroot if (tsunit >= NTS || (ui=tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) 7517733Sroot return (ENXIO); 7523244Swnj sc = &ts_softc[tsunit]; 7537841Sroot a = bdbtofsb(uio->uio_offset >> 9); 7543244Swnj sc->sc_blkno = a; 7553244Swnj sc->sc_nxrec = a + 1; 7567733Sroot return (0); 7571900Swnj } 7581918Swnj 7593244Swnj tsreset(uban) 7603244Swnj int uban; 7611918Swnj { 7623244Swnj register struct uba_ctlr *um; 7635693Sroot register struct uba_device *ui; 7645693Sroot register struct buf *dp; 7653244Swnj register ts11; 7661918Swnj 7673244Swnj for (ts11 = 0; ts11 < NTS; ts11++) { 7683244Swnj if ((um = tsminfo[ts11]) == 0 || um->um_alive == 0 || 7693244Swnj um->um_ubanum != uban) 7703244Swnj continue; 7713244Swnj printf(" ts%d", ts11); 7723244Swnj um->um_tab.b_active = 0; 7733244Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7745693Sroot if (ts_softc[ts11].sc_openf > 0) 7755693Sroot ts_softc[ts11].sc_openf = -1; 7763244Swnj if (um->um_ubinfo) { 7773244Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 7789356Ssam um->um_ubinfo = 0; 7793244Swnj } 7805693Sroot if ((ui = tsdinfo[ts11]) && ui->ui_mi == um && ui->ui_alive) { 7815693Sroot dp = &tsutab[ts11]; 7825693Sroot dp->b_active = 0; 7835693Sroot dp->b_forw = 0; 7845693Sroot if (um->um_tab.b_actf == NULL) 7855693Sroot um->um_tab.b_actf = dp; 7865693Sroot else 7875693Sroot um->um_tab.b_actl->b_forw = dp; 7885693Sroot um->um_tab.b_actl = dp; 7895693Sroot } 79017432Skarels ts_softc[ts11].sc_mapped = 0; 7913989Sroot (void) tsinit(ts11); 7923244Swnj tsstart(um); 7931918Swnj } 7941918Swnj } 7951918Swnj 7963244Swnj /*ARGSUSED*/ 7977633Ssam tsioctl(dev, cmd, data, flag) 7987633Ssam caddr_t data; 7993244Swnj dev_t dev; 8001918Swnj { 8013244Swnj int tsunit = TSUNIT(dev); 8023244Swnj register struct ts_softc *sc = &ts_softc[tsunit]; 8033244Swnj register struct buf *bp = &ctsbuf[TSUNIT(dev)]; 8043244Swnj register callcount; 8053244Swnj int fcount; 8067633Ssam struct mtop *mtop; 8077633Ssam struct mtget *mtget; 8083244Swnj /* we depend of the values and order of the MT codes here */ 8093244Swnj static tsops[] = 8103656Swnj {TS_WEOF,TS_SFORWF,TS_SREVF,TS_SFORW,TS_SREV,TS_REW,TS_OFFL,TS_SENSE}; 8111918Swnj 8123244Swnj switch (cmd) { 8137633Ssam 8143244Swnj case MTIOCTOP: /* tape operation */ 8157633Ssam mtop = (struct mtop *)data; 8168575Sroot switch (mtop->mt_op) { 8177633Ssam 8183244Swnj case MTWEOF: 8197633Ssam callcount = mtop->mt_count; 8203244Swnj fcount = 1; 8213244Swnj break; 8227633Ssam 8233244Swnj case MTFSF: case MTBSF: 8243244Swnj case MTFSR: case MTBSR: 8253244Swnj callcount = 1; 8267633Ssam fcount = mtop->mt_count; 8273244Swnj break; 8287633Ssam 8293244Swnj case MTREW: case MTOFFL: case MTNOP: 8303244Swnj callcount = 1; 8313244Swnj fcount = 1; 8323244Swnj break; 8337633Ssam 8343244Swnj default: 8358575Sroot return (ENXIO); 8363244Swnj } 8378575Sroot if (callcount <= 0 || fcount <= 0) 8388575Sroot return (EINVAL); 8393244Swnj while (--callcount >= 0) { 8407633Ssam tscommand(dev, tsops[mtop->mt_op], fcount); 8417633Ssam if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) && 8428611Sroot bp->b_resid) 8438575Sroot return (EIO); 8443244Swnj if ((bp->b_flags&B_ERROR) || sc->sc_sts.s_xs0&TS_BOT) 8453244Swnj break; 8463244Swnj } 8478649Sroot return (geterror(bp)); 8487633Ssam 8493244Swnj case MTIOCGET: 8507633Ssam mtget = (struct mtget *)data; 8517633Ssam mtget->mt_dsreg = 0; 8527633Ssam mtget->mt_erreg = sc->sc_sts.s_xs0; 8537633Ssam mtget->mt_resid = sc->sc_resid; 8547633Ssam mtget->mt_type = MT_ISTS; 8558575Sroot break; 8567633Ssam 8573244Swnj default: 8588575Sroot return (ENXIO); 8593244Swnj } 8608575Sroot return (0); 8611918Swnj } 8621918Swnj 8633244Swnj #define DBSIZE 20 8643244Swnj 8653244Swnj tsdump() 8661918Swnj { 8673244Swnj register struct uba_device *ui; 8683244Swnj register struct uba_regs *up; 8695693Sroot register struct tsdevice *addr; 8703244Swnj int blk, num; 8713244Swnj int start; 8721918Swnj 8733244Swnj start = 0; 8743244Swnj num = maxfree; 8753244Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 8763244Swnj if (tsdinfo[0] == 0) 8773244Swnj return (ENXIO); 8783244Swnj ui = phys(tsdinfo[0], struct uba_device *); 8793244Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 8808703Sroot ubainit(up); 8813244Swnj DELAY(1000000); 8825693Sroot addr = (struct tsdevice *)ui->ui_physaddr; 8833244Swnj addr->tssr = 0; 8843244Swnj tswait(addr); 8853244Swnj while (num > 0) { 8863244Swnj blk = num > DBSIZE ? DBSIZE : num; 8873244Swnj tsdwrite(start, blk, addr, up); 8883244Swnj start += blk; 8893244Swnj num -= blk; 8903244Swnj } 8913244Swnj tseof(addr); 8923244Swnj tseof(addr); 8933244Swnj tswait(addr); 8943244Swnj if (addr->tssr&TS_SC) 8953244Swnj return (EIO); 8963244Swnj addr->tssr = 0; 8973244Swnj tswait(addr); 8983244Swnj return (0); 8991918Swnj } 9001918Swnj 9013244Swnj tsdwrite(dbuf, num, addr, up) 9028635Sroot register int dbuf, num; 9035693Sroot register struct tsdevice *addr; 9043244Swnj struct uba_regs *up; 9051918Swnj { 9063244Swnj register struct pte *io; 9073244Swnj register int npf; 9081918Swnj 9093244Swnj tswait(addr); 9103244Swnj io = up->uba_map; 9113244Swnj npf = num+1; 9123244Swnj while (--npf != 0) 9133244Swnj *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); 9143244Swnj *(int *)io = 0; 9153244Swnj #ifdef notyet 9163244Swnj addr->tsbc = -(num*NBPG); 9173244Swnj addr->tsba = 0; 9183244Swnj addr->tscs = TS_WCOM | TM_GO; 9193244Swnj #endif 9201918Swnj } 9211918Swnj 9223244Swnj tswait(addr) 9235693Sroot register struct tsdevice *addr; 9241918Swnj { 9253244Swnj register s; 9261918Swnj 9273244Swnj do 9283244Swnj s = addr->tssr; 9293244Swnj while ((s & TS_SSR) == 0); 9301918Swnj } 9311918Swnj 9323244Swnj tseof(addr) 9335693Sroot struct tsdevice *addr; 9341918Swnj { 9351918Swnj 9363244Swnj tswait(addr); 9373244Swnj #ifdef notyet 9383244Swnj addr->tscs = TS_WEOF | TM_GO; 9393244Swnj #endif 9401918Swnj } 9411900Swnj #endif 942