1*7733Sroot /* ts.c 4.27 82/08/13 */ 21900Swnj 31941Swnj #include "ts.h" 41900Swnj #if NTS > 0 51900Swnj /* 61900Swnj * TS11 tape driver 73244Swnj * 83244Swnj * TODO: 95693Sroot * write dump code 101900Swnj */ 111900Swnj #include "../h/param.h" 121900Swnj #include "../h/systm.h" 131900Swnj #include "../h/buf.h" 143244Swnj #include "../h/dir.h" 151900Swnj #include "../h/conf.h" 163244Swnj #include "../h/user.h" 171900Swnj #include "../h/file.h" 183244Swnj #include "../h/map.h" 191900Swnj #include "../h/pte.h" 201947Swnj #include "../h/vm.h" 213244Swnj #include "../h/ubareg.h" 223244Swnj #include "../h/ubavar.h" 237633Ssam #include "../h/ioctl.h" 243244Swnj #include "../h/mtio.h" 253244Swnj #include "../h/cmap.h" 263244Swnj #include "../h/cpu.h" 27*7733Sroot #include "../h/uio.h" 281900Swnj 293244Swnj #include "../h/tsreg.h" 301900Swnj 313244Swnj /* 323244Swnj * There is a ctsbuf per tape controller. 333244Swnj * It is used as the token to pass to the internal routines 343244Swnj * to execute tape ioctls. 353244Swnj * In particular, when the tape is rewinding on close we release 363244Swnj * the user process but any further attempts to use the tape drive 373244Swnj * before the rewind completes will hang waiting for ctsbuf. 383244Swnj */ 393244Swnj struct buf ctsbuf[NTS]; 401900Swnj 413244Swnj /* 423244Swnj * Raw tape operations use rtsbuf. The driver 433244Swnj * notices when rtsbuf is being used and allows the user 443244Swnj * program to continue after errors and read records 453244Swnj * not of the standard length (BSIZE). 463244Swnj */ 473244Swnj struct buf rtsbuf[NTS]; 481900Swnj 493244Swnj /* 503244Swnj * Driver unibus interface routines and variables. 513244Swnj */ 523244Swnj int tsprobe(), tsslave(), tsattach(), tsdgo(), tsintr(); 533244Swnj struct uba_ctlr *tsminfo[NTS]; 543244Swnj struct uba_device *tsdinfo[NTS]; 555693Sroot struct buf tsutab[NTS]; 563244Swnj u_short tsstd[] = { 0772520, 0 }; 573244Swnj /*** PROBABLY DON'T NEED ALL THESE SINCE CONTROLLER == DRIVE ***/ 583244Swnj struct uba_driver zsdriver = 593327Swnj { tsprobe, tsslave, tsattach, tsdgo, tsstd, "ts", tsdinfo, "zs", tsminfo, 0 }; 601900Swnj 613244Swnj /* bits in minor device */ 623244Swnj #define TSUNIT(dev) (minor(dev)&03) 633244Swnj #define T_NOREWIND 04 641900Swnj 653244Swnj #define INF (daddr_t)1000000L 661900Swnj 673244Swnj /* 683244Swnj * Software state per tape transport. 693244Swnj * Also contains hardware state in message packets. 703244Swnj * 713244Swnj * 1. A tape drive is a unique-open device; we refuse opens when it is already. 723244Swnj * 2. We keep track of the current position on a block tape and seek 733244Swnj * before operations by forward/back spacing if necessary. 743244Swnj * 3. We remember if the last operation was a write on a tape, so if a tape 753244Swnj * is open read write and the last thing done is a write we can 763244Swnj * write a standard end of tape mark (two eofs). 773244Swnj * 4. We remember the status registers after the last command, using 783244Swnj * then internally and returning them to the SENSE ioctl. 793244Swnj */ 803244Swnj struct ts_softc { 813244Swnj char sc_openf; /* lock against multiple opens */ 823244Swnj char sc_lastiow; /* last op was a write */ 833327Swnj short sc_resid; /* copy of last bc */ 843244Swnj daddr_t sc_blkno; /* block number, for block device tape */ 853244Swnj daddr_t sc_nxrec; /* position of end of tape, if known */ 865693Sroot struct ts_cmd sc_cmd; /* the command packet */ 875693Sroot struct ts_sts sc_sts; /* status packet, for returned status */ 885693Sroot struct ts_char sc_char; /* characteristics packet */ 895693Sroot struct ts_softc *sc_ubaddr; /* Unibus address of ts_softc structure */ 905697Sroot u_short sc_uba; /* Unibus addr of cmd pkt for tsdb */ 915693Sroot short sc_mapped; /* is ts_sfotc mapped in Unibus space? */ 923244Swnj } ts_softc[NTS]; 931900Swnj 943244Swnj /* 953244Swnj * States for um->um_tab.b_active, the per controller state flag. 963244Swnj * This is used to sequence control in the driver. 973244Swnj */ 983244Swnj #define SSEEK 1 /* seeking */ 993244Swnj #define SIO 2 /* doing seq i/o */ 1003244Swnj #define SCOM 3 /* sending control command */ 1013244Swnj #define SREW 4 /* sending a drive rewind */ 1021900Swnj 1033244Swnj /* 1043244Swnj * Determine if there is a controller for 1053244Swnj * a ts at address reg. Our goal is to make the 1063244Swnj * device interrupt. 1073244Swnj */ 1083985Sroot /*ARGSUSED*/ 1093244Swnj tsprobe(reg) 1103244Swnj caddr_t reg; 1113244Swnj { 1123244Swnj register int br, cvec; /* must be r11,r10; value-result */ 1131900Swnj 1143244Swnj #ifdef lint 1153244Swnj br = 0; cvec = br; br = cvec; 1164937Swnj tsintr(0); 1173244Swnj #endif 1185693Sroot ((struct tsdevice *)reg)->tssr = 0; 1195693Sroot DELAY(100); 1205693Sroot if ((((struct tsdevice *)reg)->tssr & TS_NBA) == 0) 1215693Sroot return(0); 1225693Sroot /* IT'S TOO HARD TO MAKE THIS THING INTERRUPT JUST TO FIND ITS VECTOR */ 1235693Sroot cvec = ((unsigned)reg) & 07 ? 0260 : 0224; 1243244Swnj br = 0x15; 1257407Skre return (sizeof (struct tsdevice)); 1263244Swnj } 1271900Swnj 1283244Swnj /* 1293244Swnj * TS11 only supports one drive per controller; 1303244Swnj * check for ui_slave == 0. 1313244Swnj * 1323244Swnj * DO WE REALLY NEED THIS ROUTINE??? 1333244Swnj */ 1343244Swnj /*ARGSUSED*/ 1353244Swnj tsslave(ui, reg) 1363244Swnj struct uba_device *ui; 1373244Swnj caddr_t reg; 1383244Swnj { 1391900Swnj 1403244Swnj if (ui->ui_slave) /* non-zero slave not allowed */ 1413244Swnj return(0); 1423244Swnj return (1); 1433244Swnj } 1441900Swnj 1453244Swnj /* 1463244Swnj * Record attachment of the unit to the controller. 1473244Swnj * 1483244Swnj * SHOULD THIS ROUTINE DO ANYTHING??? 1493244Swnj */ 1503244Swnj /*ARGSUSED*/ 1513244Swnj tsattach(ui) 1523244Swnj struct uba_device *ui; 1533244Swnj { 1541900Swnj 1553244Swnj } 1561900Swnj 1573244Swnj /* 1583244Swnj * Open the device. Tapes are unique open 1593244Swnj * devices, so we refuse if it is already open. 1603244Swnj * We also check that a tape is available, and 1613244Swnj * don't block waiting here; if you want to wait 1623244Swnj * for a tape you should timeout in user code. 1633244Swnj */ 1641900Swnj tsopen(dev, flag) 1653244Swnj dev_t dev; 1663244Swnj int flag; 1671900Swnj { 1683244Swnj register int tsunit; 1693244Swnj register struct uba_device *ui; 1703244Swnj register struct ts_softc *sc; 1711900Swnj 1723244Swnj tsunit = TSUNIT(dev); 1733244Swnj if (tsunit>=NTS || (sc = &ts_softc[tsunit])->sc_openf || 1743244Swnj (ui = tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) { 1751900Swnj u.u_error = ENXIO; 1761900Swnj return; 1771900Swnj } 1783244Swnj if (tsinit(tsunit)) { 1791900Swnj u.u_error = ENXIO; 1801900Swnj return; 1811900Swnj } 1823244Swnj tscommand(dev, TS_SENSE, 1); 1833711Sroot if ((sc->sc_sts.s_xs0&TS_ONL) == 0) { 1843711Sroot uprintf("ts%d: not online\n", tsunit); 1853244Swnj u.u_error = EIO; 1863244Swnj return; 1871900Swnj } 1883718Sroot if ((flag&(FREAD|FWRITE)) == FWRITE && (sc->sc_sts.s_xs0&TS_WLK)) { 1893711Sroot uprintf("ts%d: no write ring\n", tsunit); 1903711Sroot u.u_error = EIO; 1913711Sroot return; 1923711Sroot } 1933244Swnj sc->sc_openf = 1; 1943244Swnj sc->sc_blkno = (daddr_t)0; 1953244Swnj sc->sc_nxrec = INF; 1963244Swnj sc->sc_lastiow = 0; 1971900Swnj } 1981900Swnj 1993244Swnj /* 2003244Swnj * Close tape device. 2013244Swnj * 2023244Swnj * If tape was open for writing or last operation was 2033244Swnj * a write, then write two EOF's and backspace over the last one. 2043244Swnj * Unless this is a non-rewinding special file, rewind the tape. 2053244Swnj * Make the tape available to others. 2063244Swnj */ 2071900Swnj tsclose(dev, flag) 2083244Swnj register dev_t dev; 2093244Swnj register flag; 2101900Swnj { 2113244Swnj register struct ts_softc *sc = &ts_softc[TSUNIT(dev)]; 2121900Swnj 2133244Swnj if (flag == FWRITE || (flag&FWRITE) && sc->sc_lastiow) { 2143244Swnj tscommand(dev, TS_WEOF, 1); 2153244Swnj tscommand(dev, TS_WEOF, 1); 2163244Swnj tscommand(dev, TS_SREV, 1); 2171900Swnj } 2183244Swnj if ((minor(dev)&T_NOREWIND) == 0) 2193244Swnj /* 2203244Swnj * 0 count means don't hang waiting for rewind complete 2213244Swnj * rather ctsbuf stays busy until the operation completes 2223244Swnj * preventing further opens from completing by 2233244Swnj * preventing a TS_SENSE from completing. 2243244Swnj */ 2253244Swnj tscommand(dev, TS_REW, 0); 2263244Swnj sc->sc_openf = 0; 2271900Swnj } 2281900Swnj 2293244Swnj /* 2303244Swnj * Initialize the TS11. Set up Unibus mapping for command 2313244Swnj * packets and set device characteristics. 2323244Swnj */ 2333244Swnj tsinit(unit) 2343244Swnj register int unit; 2351900Swnj { 2363244Swnj register struct ts_softc *sc = &ts_softc[unit]; 2373244Swnj register struct uba_ctlr *um = tsminfo[unit]; 2385693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 2393244Swnj register int i; 2403244Swnj 2413244Swnj /* 2423244Swnj * Map the command and message packets into Unibus 2433244Swnj * address space. We do all the command and message 2443244Swnj * packets at once to minimize the amount of Unibus 2453244Swnj * mapping necessary. 2463244Swnj */ 2475693Sroot if (sc->sc_mapped == 0) { 2485693Sroot ctsbuf[unit].b_un.b_addr = (caddr_t)sc; 2495693Sroot ctsbuf[unit].b_bcount = sizeof(*sc); 2503244Swnj i = ubasetup(um->um_ubanum, &ctsbuf[unit], 0); 2513244Swnj i &= 0777777; 2525693Sroot sc->sc_ubaddr = (struct ts_softc *)i; 2535693Sroot sc->sc_mapped++; 2543244Swnj } 2553244Swnj /* 2563244Swnj * Now initialize the TS11 controller. 2573244Swnj * Set the characteristics. 2583244Swnj */ 2593668Swnj if (addr->tssr & (TS_NBA|TS_OFL)) { 2603244Swnj addr->tssr = 0; /* subsystem initialize */ 2613244Swnj tswait(addr); 2625693Sroot i = (int)&sc->sc_ubaddr->sc_cmd; /* Unibus addr of cmd */ 2633244Swnj sc->sc_uba = (u_short)(i + ((i>>16)&3)); 2645693Sroot sc->sc_char.char_addr = (int)&sc->sc_ubaddr->sc_sts; 2653244Swnj sc->sc_char.char_size = sizeof(struct ts_sts); 2663244Swnj sc->sc_char.char_mode = TS_ESS; 2673244Swnj sc->sc_cmd.c_cmd = TS_ACK | TS_SETCHR; 2685693Sroot i = (int)&sc->sc_ubaddr->sc_char; 2693327Swnj sc->sc_cmd.c_loba = i; 2703327Swnj sc->sc_cmd.c_hiba = (i>>16)&3; 2713244Swnj sc->sc_cmd.c_size = sizeof(struct ts_char); 2723244Swnj addr->tsdb = sc->sc_uba; 2733244Swnj tswait(addr); 2743327Swnj if (addr->tssr & TS_NBA) 2753327Swnj return(1); 2763244Swnj } 2773244Swnj return(0); 2783244Swnj } 2793244Swnj 2803244Swnj /* 2813244Swnj * Execute a command on the tape drive 2823244Swnj * a specified number of times. 2833244Swnj */ 2843244Swnj tscommand(dev, com, count) 2853244Swnj dev_t dev; 2863244Swnj int com, count; 2873244Swnj { 2881900Swnj register struct buf *bp; 2895438Sroot register int s; 2901900Swnj 2913244Swnj bp = &ctsbuf[TSUNIT(dev)]; 2925438Sroot s = spl5(); 2933244Swnj while (bp->b_flags&B_BUSY) { 2943244Swnj /* 2953244Swnj * This special check is because B_BUSY never 2963244Swnj * gets cleared in the non-waiting rewind case. 2973244Swnj */ 2983244Swnj if (bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 2993244Swnj break; 3001900Swnj bp->b_flags |= B_WANTED; 3011900Swnj sleep((caddr_t)bp, PRIBIO); 3021900Swnj } 3033244Swnj bp->b_flags = B_BUSY|B_READ; 3045438Sroot splx(s); 3053244Swnj bp->b_dev = dev; 3063244Swnj bp->b_repcnt = count; 3073244Swnj bp->b_command = com; 3081900Swnj bp->b_blkno = 0; 3091900Swnj tsstrategy(bp); 3103244Swnj /* 3113244Swnj * In case of rewind from close, don't wait. 3123244Swnj * This is the only case where count can be 0. 3133244Swnj */ 3143244Swnj if (count == 0) 3153244Swnj return; 3161900Swnj iowait(bp); 3173244Swnj if (bp->b_flags&B_WANTED) 3181900Swnj wakeup((caddr_t)bp); 3193244Swnj bp->b_flags &= B_ERROR; 3201900Swnj } 3211900Swnj 3223244Swnj /* 3233244Swnj * Queue a tape operation. 3243244Swnj */ 3251900Swnj tsstrategy(bp) 3263244Swnj register struct buf *bp; 3271900Swnj { 3283244Swnj int tsunit = TSUNIT(bp->b_dev); 3293244Swnj register struct uba_ctlr *um; 3303327Swnj register struct buf *dp; 3315438Sroot register int s; 3321900Swnj 3333244Swnj /* 3343244Swnj * Put transfer at end of controller queue 3353244Swnj */ 3361900Swnj bp->av_forw = NULL; 3373244Swnj um = tsdinfo[tsunit]->ui_mi; 3385438Sroot s = spl5(); 3395693Sroot dp = &tsutab[tsunit]; 3403327Swnj if (dp->b_actf == NULL) 3413327Swnj dp->b_actf = bp; 3421900Swnj else 3433327Swnj dp->b_actl->av_forw = bp; 3443327Swnj dp->b_actl = bp; 3453327Swnj um->um_tab.b_actf = um->um_tab.b_actl = dp; 3463244Swnj /* 3473244Swnj * If the controller is not busy, get 3483244Swnj * it going. 3493244Swnj */ 3503244Swnj if (um->um_tab.b_active == 0) 3513244Swnj tsstart(um); 3525438Sroot splx(s); 3531900Swnj } 3541900Swnj 3553244Swnj /* 3563244Swnj * Start activity on a ts controller. 3573244Swnj */ 3583244Swnj tsstart(um) 3593244Swnj register struct uba_ctlr *um; 3601900Swnj { 3611900Swnj register struct buf *bp; 3625693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 3633244Swnj register struct ts_softc *sc; 3643244Swnj register struct ts_cmd *tc; 3653244Swnj register struct uba_device *ui; 3663244Swnj int tsunit, cmd; 3671900Swnj daddr_t blkno; 3681900Swnj 3693244Swnj /* 3703244Swnj * Start the controller if there is something for it to do. 3713244Swnj */ 3723244Swnj loop: 3733327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 3741900Swnj return; 3753244Swnj tsunit = TSUNIT(bp->b_dev); 3763244Swnj ui = tsdinfo[tsunit]; 3773244Swnj sc = &ts_softc[tsunit]; 3783244Swnj tc = &sc->sc_cmd; 3793244Swnj /* 3803244Swnj * Default is that last command was NOT a write command; 3813244Swnj * if we do a write command we will notice this in tsintr(). 3823244Swnj */ 3833656Swnj sc->sc_lastiow = 0; 3843244Swnj if (sc->sc_openf < 0 || (addr->tssr&TS_OFL)) { 3853244Swnj /* 3863244Swnj * Have had a hard error on a non-raw tape 3873244Swnj * or the tape unit is now unavailable 3883244Swnj * (e.g. taken off line). 3893244Swnj */ 3903244Swnj bp->b_flags |= B_ERROR; 3913244Swnj goto next; 3923244Swnj } 3933244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) { 3943244Swnj /* 3953244Swnj * Execute control operation with the specified count. 3963244Swnj */ 3973244Swnj um->um_tab.b_active = 3983244Swnj bp->b_command == TS_REW ? SREW : SCOM; 3993244Swnj tc->c_repcnt = bp->b_repcnt; 4003244Swnj goto dobpcmd; 4013244Swnj } 4023244Swnj /* 4033244Swnj * The following checks handle boundary cases for operation 4043244Swnj * on non-raw tapes. On raw tapes the initialization of 4053244Swnj * sc->sc_nxrec by tsphys causes them to be skipped normally 4063244Swnj * (except in the case of retries). 4073244Swnj */ 4087383Ssam if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 4093244Swnj /* 4103244Swnj * Can't read past known end-of-file. 4113244Swnj */ 4123244Swnj bp->b_flags |= B_ERROR; 4133244Swnj bp->b_error = ENXIO; 4143244Swnj goto next; 4153244Swnj } 4167383Ssam if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && 4173244Swnj bp->b_flags&B_READ) { 4183244Swnj /* 4193244Swnj * Reading at end of file returns 0 bytes. 4203244Swnj */ 4213244Swnj bp->b_resid = bp->b_bcount; 4223244Swnj clrbuf(bp); 4233244Swnj goto next; 4243244Swnj } 4253244Swnj if ((bp->b_flags&B_READ) == 0) 4263244Swnj /* 4273244Swnj * Writing sets EOF 4283244Swnj */ 4297383Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; 4303244Swnj /* 4313244Swnj * If the data transfer command is in the correct place, 4323244Swnj * set up all the registers except the csr, and give 4333244Swnj * control over to the UNIBUS adapter routines, to 4343244Swnj * wait for resources to start the i/o. 4353244Swnj */ 4367383Ssam if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { 4373244Swnj tc->c_size = bp->b_bcount; 4383244Swnj if ((bp->b_flags&B_READ) == 0) 4393244Swnj cmd = TS_WCOM; 4401900Swnj else 4413244Swnj cmd = TS_RCOM; 4423244Swnj if (um->um_tab.b_errcnt) 4433244Swnj cmd |= TS_RETRY; 4443244Swnj um->um_tab.b_active = SIO; 4453327Swnj tc->c_cmd = TS_ACK | TS_CVC | TS_IE | cmd; 4463244Swnj (void) ubago(ui); 4473244Swnj return; 4483244Swnj } 4493244Swnj /* 4503244Swnj * Tape positioned incorrectly; 4513244Swnj * set to seek forwards or backwards to the correct spot. 4523244Swnj * This happens for raw tapes only on error retries. 4533244Swnj */ 4543244Swnj um->um_tab.b_active = SSEEK; 4557383Ssam if (blkno < bdbtofsb(bp->b_blkno)) { 4563244Swnj bp->b_command = TS_SFORW; 4577383Ssam tc->c_repcnt = bdbtofsb(bp->b_blkno) - blkno; 4581900Swnj } else { 4593244Swnj bp->b_command = TS_SREV; 4607383Ssam tc->c_repcnt = blkno - bdbtofsb(bp->b_blkno); 4611900Swnj } 4623244Swnj dobpcmd: 4633244Swnj /* 4643244Swnj * Do the command in bp. 4653244Swnj */ 4663327Swnj tc->c_cmd = TS_ACK | TS_CVC | TS_IE | bp->b_command; 4673244Swnj addr->tsdb = sc->sc_uba; 4681900Swnj return; 4691900Swnj 4703244Swnj next: 4713244Swnj /* 4723244Swnj * Done with this operation due to error or 4733244Swnj * the fact that it doesn't do anything. 4743244Swnj * Release UBA resources (if any), dequeue 4753244Swnj * the transfer and continue processing this slave. 4763244Swnj */ 4773244Swnj if (um->um_ubinfo) 4783244Swnj ubadone(um); 4793244Swnj um->um_tab.b_errcnt = 0; 4803327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 4811900Swnj iodone(bp); 4821900Swnj goto loop; 4831900Swnj } 4841900Swnj 4853244Swnj /* 4863244Swnj * The UNIBUS resources we needed have been 4873244Swnj * allocated to us; start the device. 4883244Swnj */ 4893244Swnj tsdgo(um) 4903244Swnj register struct uba_ctlr *um; 4911900Swnj { 4925693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 4933244Swnj register struct ts_softc *sc = &ts_softc[um->um_ctlr]; 4943327Swnj register int i; 4953244Swnj 4963327Swnj i = um->um_ubinfo & 0777777; 4973327Swnj sc->sc_cmd.c_loba = i; 4983327Swnj sc->sc_cmd.c_hiba = (i>>16)&3; 4993244Swnj addr->tsdb = sc->sc_uba; 5003244Swnj } 5013244Swnj 5023244Swnj /* 5033244Swnj * Ts interrupt routine. 5043244Swnj */ 5053244Swnj /*ARGSUSED*/ 5063244Swnj tsintr(ts11) 5073244Swnj int ts11; 5083244Swnj { 5091900Swnj register struct buf *bp; 5103244Swnj register struct uba_ctlr *um = tsminfo[ts11]; 5115693Sroot register struct tsdevice *addr; 5123244Swnj register struct ts_softc *sc; 5133244Swnj int tsunit; 5143244Swnj register state; 5151900Swnj 5163327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 5171900Swnj return; 5183244Swnj tsunit = TSUNIT(bp->b_dev); 5195693Sroot addr = (struct tsdevice *)tsdinfo[tsunit]->ui_addr; 5203244Swnj /* 5213244Swnj * If last command was a rewind, and tape is still 5223244Swnj * rewinding, wait for the rewind complete interrupt. 5233244Swnj * 5243244Swnj * SHOULD NEVER GET AN INTERRUPT IN THIS STATE. 5253244Swnj */ 5263244Swnj if (um->um_tab.b_active == SREW) { 5273244Swnj um->um_tab.b_active = SCOM; 5283244Swnj if ((addr->tssr&TS_SSR) == 0) 5293244Swnj return; 5303244Swnj } 5313244Swnj /* 5323244Swnj * An operation completed... record status 5333244Swnj */ 5343244Swnj sc = &ts_softc[tsunit]; 5353244Swnj if ((bp->b_flags & B_READ) == 0) 5363244Swnj sc->sc_lastiow = 1; 5373244Swnj state = um->um_tab.b_active; 5383244Swnj um->um_tab.b_active = 0; 5393244Swnj /* 5403244Swnj * Check for errors. 5413244Swnj */ 5423244Swnj if (addr->tssr&TS_SC) { 5433244Swnj switch (addr->tssr & TS_TC) { 5443244Swnj case TS_UNREC: /* unrecoverable */ 5453244Swnj case TS_FATAL: /* fatal error */ 5463244Swnj case TS_ATTN: /* attention (shouldn't happen) */ 5473244Swnj case TS_RECNM: /* recoverable, no motion */ 5483244Swnj break; 5491900Swnj 5503244Swnj case TS_SUCC: /* success termination */ 5513244Swnj printf("ts%d: success\n", TSUNIT(minor(bp->b_dev))); 5523244Swnj goto ignoreerr; 5531900Swnj 5543244Swnj case TS_ALERT: /* tape status alert */ 5553244Swnj /* 5563244Swnj * If we hit the end of the tape file, 5573244Swnj * update our position. 5583244Swnj */ 5593244Swnj if (sc->sc_sts.s_xs0 & (TS_TMK|TS_EOT)) { 5603244Swnj tsseteof(bp); /* set blkno and nxrec */ 5613244Swnj state = SCOM; /* force completion */ 5623244Swnj /* 5633244Swnj * Stuff bc so it will be unstuffed correctly 5643244Swnj * later to get resid. 5653244Swnj */ 5663244Swnj sc->sc_sts.s_rbpcr = bp->b_bcount; 5673244Swnj goto opdone; 5683244Swnj } 5693244Swnj /* 5703244Swnj * If we were reading raw tape and the record was too long 5713244Swnj * or too short, then we don't consider this an error. 5723244Swnj */ 5733244Swnj if (bp == &rtsbuf[TSUNIT(bp->b_dev)] && (bp->b_flags&B_READ) && 5743244Swnj sc->sc_sts.s_xs0&(TS_RLS|TS_RLL)) 5753244Swnj goto ignoreerr; 5763244Swnj case TS_RECOV: /* recoverable, tape moved */ 5773244Swnj /* 5783244Swnj * If this was an i/o operation retry up to 8 times. 5793244Swnj */ 5803244Swnj if (state==SIO) { 5813244Swnj if (++um->um_tab.b_errcnt < 7) { 5823244Swnj ubadone(um); 5833244Swnj goto opcont; 5843244Swnj } else 5853244Swnj sc->sc_blkno++; 5863244Swnj } else { 5873244Swnj /* 5883244Swnj * Non-i/o errors on non-raw tape 5893244Swnj * cause it to close. 5903244Swnj */ 5913244Swnj if (sc->sc_openf>0 && bp != &rtsbuf[TSUNIT(bp->b_dev)]) 5923244Swnj sc->sc_openf = -1; 5933244Swnj } 5941900Swnj break; 5953244Swnj 5963244Swnj case TS_REJECT: /* function reject */ 5973244Swnj if (state == SIO && sc->sc_sts.s_xs0 & TS_WLE) 5983244Swnj printf("ts%d: write locked\n", TSUNIT(bp->b_dev)); 5993244Swnj if ((sc->sc_sts.s_xs0 & TS_ONL) == 0) 6003244Swnj printf("ts%d: offline\n", TSUNIT(bp->b_dev)); 6011900Swnj break; 6021900Swnj } 6033244Swnj /* 6043244Swnj * Couldn't recover error 6053244Swnj */ 6063647Swnj printf("ts%d: hard error bn%d xs0=%b", TSUNIT(bp->b_dev), 6073244Swnj bp->b_blkno, sc->sc_sts.s_xs0, TSXS0_BITS); 6083647Swnj if (sc->sc_sts.s_xs1) 6093647Swnj printf(" xs1=%b", sc->sc_sts.s_xs1, TSXS1_BITS); 6103647Swnj if (sc->sc_sts.s_xs2) 6113647Swnj printf(" xs2=%b", sc->sc_sts.s_xs2, TSXS2_BITS); 6123647Swnj if (sc->sc_sts.s_xs3) 6133647Swnj printf(" xs3=%b", sc->sc_sts.s_xs3, TSXS3_BITS); 6143647Swnj printf("\n"); 6153244Swnj bp->b_flags |= B_ERROR; 6163244Swnj goto opdone; 6173244Swnj } 6183244Swnj /* 6193244Swnj * Advance tape control FSM. 6203244Swnj */ 6213244Swnj ignoreerr: 6223244Swnj switch (state) { 6231900Swnj 6243244Swnj case SIO: 6253244Swnj /* 6263244Swnj * Read/write increments tape block number 6273244Swnj */ 6283244Swnj sc->sc_blkno++; 6293244Swnj goto opdone; 6301900Swnj 6311900Swnj case SCOM: 6323244Swnj /* 6333244Swnj * For forward/backward space record update current position. 6343244Swnj */ 6353244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) 6363244Swnj switch (bp->b_command) { 6371900Swnj 6383244Swnj case TS_SFORW: 6393244Swnj sc->sc_blkno += bp->b_repcnt; 6403244Swnj break; 6411900Swnj 6423244Swnj case TS_SREV: 6433244Swnj sc->sc_blkno -= bp->b_repcnt; 6443244Swnj break; 6453244Swnj } 6463244Swnj goto opdone; 6473244Swnj 6483244Swnj case SSEEK: 6497383Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno); 6503244Swnj goto opcont; 6513244Swnj 6521900Swnj default: 6533244Swnj panic("tsintr"); 6541900Swnj } 6553244Swnj opdone: 6563244Swnj /* 6573244Swnj * Reset error count and remove 6583244Swnj * from device queue. 6593244Swnj */ 6603244Swnj um->um_tab.b_errcnt = 0; 6613327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 6623244Swnj bp->b_resid = sc->sc_sts.s_rbpcr; 6633244Swnj ubadone(um); 6643244Swnj iodone(bp); 6653327Swnj if (um->um_tab.b_actf->b_actf == 0) 6663244Swnj return; 6673244Swnj opcont: 6683244Swnj tsstart(um); 6693244Swnj } 6703244Swnj 6713244Swnj tsseteof(bp) 6723244Swnj register struct buf *bp; 6733244Swnj { 6743244Swnj register int tsunit = TSUNIT(bp->b_dev); 6753244Swnj register struct ts_softc *sc = &ts_softc[tsunit]; 6763244Swnj 6773244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) { 6787383Ssam if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 6793244Swnj /* reversing */ 6807383Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno) - sc->sc_sts.s_rbpcr; 6813244Swnj sc->sc_blkno = sc->sc_nxrec; 6823244Swnj } else { 6833244Swnj /* spacing forward */ 6847383Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno) + sc->sc_sts.s_rbpcr; 6853244Swnj sc->sc_nxrec = sc->sc_blkno - 1; 6861900Swnj } 6873244Swnj return; 6883244Swnj } 6893244Swnj /* eof on read */ 6907383Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno); 6911900Swnj } 6921900Swnj 693*7733Sroot tsread(dev, uio) 6943244Swnj dev_t dev; 695*7733Sroot struct uio *uio; 6961900Swnj { 6973244Swnj 698*7733Sroot u.u_error = tsphys(dev, uio); 6993244Swnj if (u.u_error) 7003244Swnj return; 701*7733Sroot physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_READ, minphys, uio); 7021900Swnj } 7031900Swnj 7041900Swnj tswrite(dev) 7053244Swnj dev_t dev; 7061900Swnj { 7073244Swnj 708*7733Sroot tsphys(dev, 0); 7093244Swnj if (u.u_error) 7103244Swnj return; 711*7733Sroot physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_WRITE, minphys, 0); 7121900Swnj } 7131900Swnj 7143244Swnj /* 7153244Swnj * Check that a raw device exists. 7163244Swnj * If it does, set up sc_blkno and sc_nxrec 7173244Swnj * so that the tape will appear positioned correctly. 7183244Swnj */ 719*7733Sroot tsphys(dev, uio) 7203244Swnj dev_t dev; 721*7733Sroot struct uio *uio; 7221900Swnj { 7233244Swnj register int tsunit = TSUNIT(dev); 7243244Swnj register daddr_t a; 7253244Swnj register struct ts_softc *sc; 7263244Swnj register struct uba_device *ui; 7271900Swnj 7283244Swnj if (tsunit >= NTS || (ui=tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) { 7293244Swnj u.u_error = ENXIO; 730*7733Sroot return (ENXIO); 7313244Swnj } 7323244Swnj sc = &ts_softc[tsunit]; 733*7733Sroot if (uio) 734*7733Sroot a = bdbtofsb(uio->uio_offset >> 9); 735*7733Sroot else 736*7733Sroot a = bdbtofsb(u.u_offset >> 9); 7373244Swnj sc->sc_blkno = a; 7383244Swnj sc->sc_nxrec = a + 1; 739*7733Sroot return (0); 7401900Swnj } 7411918Swnj 7423244Swnj tsreset(uban) 7433244Swnj int uban; 7441918Swnj { 7453244Swnj register struct uba_ctlr *um; 7465693Sroot register struct uba_device *ui; 7475693Sroot register struct buf *dp; 7483244Swnj register ts11; 7491918Swnj 7503244Swnj for (ts11 = 0; ts11 < NTS; ts11++) { 7513244Swnj if ((um = tsminfo[ts11]) == 0 || um->um_alive == 0 || 7523244Swnj um->um_ubanum != uban) 7533244Swnj continue; 7543244Swnj printf(" ts%d", ts11); 7553244Swnj um->um_tab.b_active = 0; 7563244Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7575693Sroot if (ts_softc[ts11].sc_openf > 0) 7585693Sroot ts_softc[ts11].sc_openf = -1; 7593244Swnj if (um->um_ubinfo) { 7603244Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 7613244Swnj ubadone(um); 7623244Swnj } 7635693Sroot if ((ui = tsdinfo[ts11]) && ui->ui_mi == um && ui->ui_alive) { 7645693Sroot dp = &tsutab[ts11]; 7655693Sroot dp->b_active = 0; 7665693Sroot dp->b_forw = 0; 7675693Sroot if (um->um_tab.b_actf == NULL) 7685693Sroot um->um_tab.b_actf = dp; 7695693Sroot else 7705693Sroot um->um_tab.b_actl->b_forw = dp; 7715693Sroot um->um_tab.b_actl = dp; 7725693Sroot } 7733989Sroot (void) tsinit(ts11); 7743244Swnj tsstart(um); 7751918Swnj } 7761918Swnj } 7771918Swnj 7783244Swnj /*ARGSUSED*/ 7797633Ssam tsioctl(dev, cmd, data, flag) 7807633Ssam caddr_t data; 7813244Swnj dev_t dev; 7821918Swnj { 7833244Swnj int tsunit = TSUNIT(dev); 7843244Swnj register struct ts_softc *sc = &ts_softc[tsunit]; 7853244Swnj register struct buf *bp = &ctsbuf[TSUNIT(dev)]; 7863244Swnj register callcount; 7873244Swnj int fcount; 7887633Ssam struct mtop *mtop; 7897633Ssam struct mtget *mtget; 7903244Swnj /* we depend of the values and order of the MT codes here */ 7913244Swnj static tsops[] = 7923656Swnj {TS_WEOF,TS_SFORWF,TS_SREVF,TS_SFORW,TS_SREV,TS_REW,TS_OFFL,TS_SENSE}; 7931918Swnj 7943244Swnj switch (cmd) { 7957633Ssam 7963244Swnj case MTIOCTOP: /* tape operation */ 7977633Ssam mtop = (struct mtop *)data; 7987633Ssam switch(mtop->mt_op) { 7997633Ssam 8003244Swnj case MTWEOF: 8017633Ssam callcount = mtop->mt_count; 8023244Swnj fcount = 1; 8033244Swnj break; 8047633Ssam 8053244Swnj case MTFSF: case MTBSF: 8063244Swnj case MTFSR: case MTBSR: 8073244Swnj callcount = 1; 8087633Ssam fcount = mtop->mt_count; 8093244Swnj break; 8107633Ssam 8113244Swnj case MTREW: case MTOFFL: case MTNOP: 8123244Swnj callcount = 1; 8133244Swnj fcount = 1; 8143244Swnj break; 8157633Ssam 8163244Swnj default: 8173244Swnj u.u_error = ENXIO; 8183244Swnj return; 8193244Swnj } 8203244Swnj if (callcount <= 0 || fcount <= 0) { 8213244Swnj u.u_error = ENXIO; 8223244Swnj return; 8233244Swnj } 8243244Swnj while (--callcount >= 0) { 8257633Ssam tscommand(dev, tsops[mtop->mt_op], fcount); 8267633Ssam if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) && 8273244Swnj bp->b_resid) { 8283244Swnj u.u_error = EIO; 8293244Swnj break; 8303244Swnj } 8313244Swnj if ((bp->b_flags&B_ERROR) || sc->sc_sts.s_xs0&TS_BOT) 8323244Swnj break; 8333244Swnj } 8343244Swnj geterror(bp); 8353244Swnj return; 8367633Ssam 8373244Swnj case MTIOCGET: 8387633Ssam mtget = (struct mtget *)data; 8397633Ssam mtget->mt_dsreg = 0; 8407633Ssam mtget->mt_erreg = sc->sc_sts.s_xs0; 8417633Ssam mtget->mt_resid = sc->sc_resid; 8427633Ssam mtget->mt_type = MT_ISTS; 8433244Swnj return; 8447633Ssam 8453244Swnj default: 8463244Swnj u.u_error = ENXIO; 8473244Swnj } 8481918Swnj } 8491918Swnj 8503244Swnj #define DBSIZE 20 8513244Swnj 8523244Swnj tsdump() 8531918Swnj { 8543244Swnj register struct uba_device *ui; 8553244Swnj register struct uba_regs *up; 8565693Sroot register struct tsdevice *addr; 8573244Swnj int blk, num; 8583244Swnj int start; 8591918Swnj 8603244Swnj start = 0; 8613244Swnj num = maxfree; 8623244Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 8633244Swnj if (tsdinfo[0] == 0) 8643244Swnj return (ENXIO); 8653244Swnj ui = phys(tsdinfo[0], struct uba_device *); 8663244Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 8673327Swnj ubainit(up); 8683244Swnj DELAY(1000000); 8695693Sroot addr = (struct tsdevice *)ui->ui_physaddr; 8703244Swnj addr->tssr = 0; 8713244Swnj tswait(addr); 8723244Swnj while (num > 0) { 8733244Swnj blk = num > DBSIZE ? DBSIZE : num; 8743244Swnj tsdwrite(start, blk, addr, up); 8753244Swnj start += blk; 8763244Swnj num -= blk; 8773244Swnj } 8783244Swnj tseof(addr); 8793244Swnj tseof(addr); 8803244Swnj tswait(addr); 8813244Swnj if (addr->tssr&TS_SC) 8823244Swnj return (EIO); 8833244Swnj addr->tssr = 0; 8843244Swnj tswait(addr); 8853244Swnj return (0); 8861918Swnj } 8871918Swnj 8883244Swnj tsdwrite(dbuf, num, addr, up) 8893244Swnj register dbuf, num; 8905693Sroot register struct tsdevice *addr; 8913244Swnj struct uba_regs *up; 8921918Swnj { 8933244Swnj register struct pte *io; 8943244Swnj register int npf; 8951918Swnj 8963244Swnj tswait(addr); 8973244Swnj io = up->uba_map; 8983244Swnj npf = num+1; 8993244Swnj while (--npf != 0) 9003244Swnj *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); 9013244Swnj *(int *)io = 0; 9023244Swnj #ifdef notyet 9033244Swnj addr->tsbc = -(num*NBPG); 9043244Swnj addr->tsba = 0; 9053244Swnj addr->tscs = TS_WCOM | TM_GO; 9063244Swnj #endif 9071918Swnj } 9081918Swnj 9093244Swnj tswait(addr) 9105693Sroot register struct tsdevice *addr; 9111918Swnj { 9123244Swnj register s; 9131918Swnj 9143244Swnj do 9153244Swnj s = addr->tssr; 9163244Swnj while ((s & TS_SSR) == 0); 9171918Swnj } 9181918Swnj 9193244Swnj tseof(addr) 9205693Sroot struct tsdevice *addr; 9211918Swnj { 9221918Swnj 9233244Swnj tswait(addr); 9243244Swnj #ifdef notyet 9253244Swnj addr->tscs = TS_WEOF | TM_GO; 9263244Swnj #endif 9271918Swnj } 9281900Swnj #endif 929