1*17432Skarels /* ts.c 6.3 84/11/27 */ 21900Swnj 31941Swnj #include "ts.h" 41900Swnj #if NTS > 0 51900Swnj /* 61900Swnj * TS11 tape driver 73244Swnj * 83244Swnj * TODO: 95693Sroot * write dump code 101900Swnj */ 119779Ssam #include "../machine/pte.h" 129779Ssam 1317080Sbloom #include "param.h" 1417080Sbloom #include "systm.h" 1517080Sbloom #include "buf.h" 1617080Sbloom #include "dir.h" 1717080Sbloom #include "conf.h" 1817080Sbloom #include "user.h" 1917080Sbloom #include "file.h" 2017080Sbloom #include "map.h" 2117080Sbloom #include "vm.h" 2217080Sbloom #include "ioctl.h" 2317080Sbloom #include "mtio.h" 2417080Sbloom #include "cmap.h" 2517080Sbloom #include "uio.h" 261900Swnj 278480Sroot #include "../vax/cpu.h" 2817080Sbloom #include "ubareg.h" 2917080Sbloom #include "ubavar.h" 3017080Sbloom #include "tsreg.h" 311900Swnj 323244Swnj /* 333244Swnj * There is a ctsbuf per tape controller. 343244Swnj * It is used as the token to pass to the internal routines 353244Swnj * to execute tape ioctls. 363244Swnj * In particular, when the tape is rewinding on close we release 373244Swnj * the user process but any further attempts to use the tape drive 383244Swnj * before the rewind completes will hang waiting for ctsbuf. 393244Swnj */ 403244Swnj struct buf ctsbuf[NTS]; 411900Swnj 423244Swnj /* 433244Swnj * Raw tape operations use rtsbuf. The driver 443244Swnj * notices when rtsbuf is being used and allows the user 453244Swnj * program to continue after errors and read records 463244Swnj * not of the standard length (BSIZE). 473244Swnj */ 483244Swnj struct buf rtsbuf[NTS]; 491900Swnj 503244Swnj /* 513244Swnj * Driver unibus interface routines and variables. 523244Swnj */ 533244Swnj int tsprobe(), tsslave(), tsattach(), tsdgo(), tsintr(); 543244Swnj struct uba_ctlr *tsminfo[NTS]; 553244Swnj struct uba_device *tsdinfo[NTS]; 565693Sroot struct buf tsutab[NTS]; 573244Swnj u_short tsstd[] = { 0772520, 0 }; 583244Swnj /*** PROBABLY DON'T NEED ALL THESE SINCE CONTROLLER == DRIVE ***/ 593244Swnj struct uba_driver zsdriver = 603327Swnj { tsprobe, tsslave, tsattach, tsdgo, tsstd, "ts", tsdinfo, "zs", tsminfo, 0 }; 611900Swnj 623244Swnj /* bits in minor device */ 633244Swnj #define TSUNIT(dev) (minor(dev)&03) 643244Swnj #define T_NOREWIND 04 651900Swnj 663244Swnj #define INF (daddr_t)1000000L 671900Swnj 683244Swnj /* 693244Swnj * Software state per tape transport. 703244Swnj * Also contains hardware state in message packets. 713244Swnj * 723244Swnj * 1. A tape drive is a unique-open device; we refuse opens when it is already. 733244Swnj * 2. We keep track of the current position on a block tape and seek 743244Swnj * before operations by forward/back spacing if necessary. 753244Swnj * 3. We remember if the last operation was a write on a tape, so if a tape 763244Swnj * is open read write and the last thing done is a write we can 773244Swnj * write a standard end of tape mark (two eofs). 783244Swnj * 4. We remember the status registers after the last command, using 793244Swnj * then internally and returning them to the SENSE ioctl. 803244Swnj */ 813244Swnj struct ts_softc { 823244Swnj char sc_openf; /* lock against multiple opens */ 833244Swnj char sc_lastiow; /* last op was a write */ 843327Swnj short sc_resid; /* copy of last bc */ 853244Swnj daddr_t sc_blkno; /* block number, for block device tape */ 863244Swnj daddr_t sc_nxrec; /* position of end of tape, if known */ 875693Sroot struct ts_cmd sc_cmd; /* the command packet */ 885693Sroot struct ts_sts sc_sts; /* status packet, for returned status */ 895693Sroot struct ts_char sc_char; /* characteristics packet */ 905693Sroot struct ts_softc *sc_ubaddr; /* Unibus address of ts_softc structure */ 915697Sroot u_short sc_uba; /* Unibus addr of cmd pkt for tsdb */ 925693Sroot short sc_mapped; /* is ts_sfotc mapped in Unibus space? */ 933244Swnj } ts_softc[NTS]; 941900Swnj 953244Swnj /* 963244Swnj * States for um->um_tab.b_active, the per controller state flag. 973244Swnj * This is used to sequence control in the driver. 983244Swnj */ 993244Swnj #define SSEEK 1 /* seeking */ 1003244Swnj #define SIO 2 /* doing seq i/o */ 1013244Swnj #define SCOM 3 /* sending control command */ 1023244Swnj #define SREW 4 /* sending a drive rewind */ 1031900Swnj 1043244Swnj /* 1053244Swnj * Determine if there is a controller for 1063244Swnj * a ts at address reg. Our goal is to make the 1073244Swnj * device interrupt. 1083244Swnj */ 1093985Sroot /*ARGSUSED*/ 1103244Swnj tsprobe(reg) 1113244Swnj caddr_t reg; 1123244Swnj { 1133244Swnj register int br, cvec; /* must be r11,r10; value-result */ 1141900Swnj 1153244Swnj #ifdef lint 1163244Swnj br = 0; cvec = br; br = cvec; 1174937Swnj tsintr(0); 1183244Swnj #endif 1195693Sroot ((struct tsdevice *)reg)->tssr = 0; 1205693Sroot DELAY(100); 1215693Sroot if ((((struct tsdevice *)reg)->tssr & TS_NBA) == 0) 1225693Sroot return(0); 1235693Sroot /* IT'S TOO HARD TO MAKE THIS THING INTERRUPT JUST TO FIND ITS VECTOR */ 1245693Sroot cvec = ((unsigned)reg) & 07 ? 0260 : 0224; 1253244Swnj br = 0x15; 1267407Skre return (sizeof (struct tsdevice)); 1273244Swnj } 1281900Swnj 1293244Swnj /* 1303244Swnj * TS11 only supports one drive per controller; 1313244Swnj * check for ui_slave == 0. 1323244Swnj * 1333244Swnj * DO WE REALLY NEED THIS ROUTINE??? 1343244Swnj */ 1353244Swnj /*ARGSUSED*/ 1363244Swnj tsslave(ui, reg) 1373244Swnj struct uba_device *ui; 1383244Swnj caddr_t reg; 1393244Swnj { 1401900Swnj 1413244Swnj if (ui->ui_slave) /* non-zero slave not allowed */ 1423244Swnj return(0); 1433244Swnj return (1); 1443244Swnj } 1451900Swnj 1463244Swnj /* 1473244Swnj * Record attachment of the unit to the controller. 1483244Swnj * 1493244Swnj * SHOULD THIS ROUTINE DO ANYTHING??? 1503244Swnj */ 1513244Swnj /*ARGSUSED*/ 1523244Swnj tsattach(ui) 1533244Swnj struct uba_device *ui; 1543244Swnj { 1551900Swnj 1563244Swnj } 1571900Swnj 1583244Swnj /* 1593244Swnj * Open the device. Tapes are unique open 1603244Swnj * devices, so we refuse if it is already open. 1613244Swnj * We also check that a tape is available, and 1623244Swnj * don't block waiting here; if you want to wait 1633244Swnj * for a tape you should timeout in user code. 1643244Swnj */ 1651900Swnj tsopen(dev, flag) 1663244Swnj dev_t dev; 1673244Swnj int flag; 1681900Swnj { 1693244Swnj register int tsunit; 1703244Swnj register struct uba_device *ui; 1713244Swnj register struct ts_softc *sc; 1721900Swnj 1733244Swnj tsunit = TSUNIT(dev); 1743244Swnj if (tsunit>=NTS || (sc = &ts_softc[tsunit])->sc_openf || 1758575Sroot (ui = tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) 1768575Sroot return (ENXIO); 1778575Sroot if (tsinit(tsunit)) 1788575Sroot return (ENXIO); 1793244Swnj tscommand(dev, TS_SENSE, 1); 1803711Sroot if ((sc->sc_sts.s_xs0&TS_ONL) == 0) { 1813711Sroot uprintf("ts%d: not online\n", tsunit); 1828575Sroot return (EIO); 1831900Swnj } 1843718Sroot if ((flag&(FREAD|FWRITE)) == FWRITE && (sc->sc_sts.s_xs0&TS_WLK)) { 1853711Sroot uprintf("ts%d: no write ring\n", tsunit); 1868575Sroot return (EIO); 1873711Sroot } 1883244Swnj sc->sc_openf = 1; 1893244Swnj sc->sc_blkno = (daddr_t)0; 1903244Swnj sc->sc_nxrec = INF; 1913244Swnj sc->sc_lastiow = 0; 1928575Sroot return (0); 1931900Swnj } 1941900Swnj 1953244Swnj /* 1963244Swnj * Close tape device. 1973244Swnj * 1983244Swnj * If tape was open for writing or last operation was 1993244Swnj * a write, then write two EOF's and backspace over the last one. 2003244Swnj * Unless this is a non-rewinding special file, rewind the tape. 2013244Swnj * Make the tape available to others. 2023244Swnj */ 2031900Swnj tsclose(dev, flag) 2043244Swnj register dev_t dev; 2053244Swnj register flag; 2061900Swnj { 2073244Swnj register struct ts_softc *sc = &ts_softc[TSUNIT(dev)]; 2081900Swnj 2093244Swnj if (flag == FWRITE || (flag&FWRITE) && sc->sc_lastiow) { 2103244Swnj tscommand(dev, TS_WEOF, 1); 2113244Swnj tscommand(dev, TS_WEOF, 1); 2123244Swnj tscommand(dev, TS_SREV, 1); 2131900Swnj } 2143244Swnj if ((minor(dev)&T_NOREWIND) == 0) 2153244Swnj /* 2163244Swnj * 0 count means don't hang waiting for rewind complete 2173244Swnj * rather ctsbuf stays busy until the operation completes 2183244Swnj * preventing further opens from completing by 2193244Swnj * preventing a TS_SENSE from completing. 2203244Swnj */ 2213244Swnj tscommand(dev, TS_REW, 0); 2223244Swnj sc->sc_openf = 0; 2231900Swnj } 2241900Swnj 2253244Swnj /* 2263244Swnj * Initialize the TS11. Set up Unibus mapping for command 2273244Swnj * packets and set device characteristics. 2283244Swnj */ 2293244Swnj tsinit(unit) 2303244Swnj register int unit; 2311900Swnj { 2323244Swnj register struct ts_softc *sc = &ts_softc[unit]; 2333244Swnj register struct uba_ctlr *um = tsminfo[unit]; 2345693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 2353244Swnj register int i; 2363244Swnj 2373244Swnj /* 2383244Swnj * Map the command and message packets into Unibus 2393244Swnj * address space. We do all the command and message 2403244Swnj * packets at once to minimize the amount of Unibus 2413244Swnj * mapping necessary. 2423244Swnj */ 2435693Sroot if (sc->sc_mapped == 0) { 2445693Sroot ctsbuf[unit].b_un.b_addr = (caddr_t)sc; 2455693Sroot ctsbuf[unit].b_bcount = sizeof(*sc); 2463244Swnj i = ubasetup(um->um_ubanum, &ctsbuf[unit], 0); 2473244Swnj i &= 0777777; 2485693Sroot sc->sc_ubaddr = (struct ts_softc *)i; 2495693Sroot sc->sc_mapped++; 2503244Swnj } 2513244Swnj /* 2523244Swnj * Now initialize the TS11 controller. 2533244Swnj * Set the characteristics. 2543244Swnj */ 2553668Swnj if (addr->tssr & (TS_NBA|TS_OFL)) { 2563244Swnj addr->tssr = 0; /* subsystem initialize */ 2573244Swnj tswait(addr); 2585693Sroot i = (int)&sc->sc_ubaddr->sc_cmd; /* Unibus addr of cmd */ 2593244Swnj sc->sc_uba = (u_short)(i + ((i>>16)&3)); 2605693Sroot sc->sc_char.char_addr = (int)&sc->sc_ubaddr->sc_sts; 2613244Swnj sc->sc_char.char_size = sizeof(struct ts_sts); 2623244Swnj sc->sc_char.char_mode = TS_ESS; 2633244Swnj sc->sc_cmd.c_cmd = TS_ACK | TS_SETCHR; 2645693Sroot i = (int)&sc->sc_ubaddr->sc_char; 2653327Swnj sc->sc_cmd.c_loba = i; 2663327Swnj sc->sc_cmd.c_hiba = (i>>16)&3; 2673244Swnj sc->sc_cmd.c_size = sizeof(struct ts_char); 2683244Swnj addr->tsdb = sc->sc_uba; 2693244Swnj tswait(addr); 2703327Swnj if (addr->tssr & TS_NBA) 2713327Swnj return(1); 2723244Swnj } 2733244Swnj return(0); 2743244Swnj } 2753244Swnj 2763244Swnj /* 2773244Swnj * Execute a command on the tape drive 2783244Swnj * a specified number of times. 2793244Swnj */ 2803244Swnj tscommand(dev, com, count) 2813244Swnj dev_t dev; 2823244Swnj int com, count; 2833244Swnj { 2841900Swnj register struct buf *bp; 2855438Sroot register int s; 2861900Swnj 2873244Swnj bp = &ctsbuf[TSUNIT(dev)]; 2885438Sroot s = spl5(); 2893244Swnj while (bp->b_flags&B_BUSY) { 2903244Swnj /* 2913244Swnj * This special check is because B_BUSY never 2923244Swnj * gets cleared in the non-waiting rewind case. 2933244Swnj */ 2943244Swnj if (bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 2953244Swnj break; 2961900Swnj bp->b_flags |= B_WANTED; 2971900Swnj sleep((caddr_t)bp, PRIBIO); 2981900Swnj } 2993244Swnj bp->b_flags = B_BUSY|B_READ; 3005438Sroot splx(s); 3013244Swnj bp->b_dev = dev; 3023244Swnj bp->b_repcnt = count; 3033244Swnj bp->b_command = com; 3041900Swnj bp->b_blkno = 0; 3051900Swnj tsstrategy(bp); 3063244Swnj /* 3073244Swnj * In case of rewind from close, don't wait. 3083244Swnj * This is the only case where count can be 0. 3093244Swnj */ 3103244Swnj if (count == 0) 3113244Swnj return; 3121900Swnj iowait(bp); 3133244Swnj if (bp->b_flags&B_WANTED) 3141900Swnj wakeup((caddr_t)bp); 3153244Swnj bp->b_flags &= B_ERROR; 3161900Swnj } 3171900Swnj 3183244Swnj /* 3193244Swnj * Queue a tape operation. 3203244Swnj */ 3211900Swnj tsstrategy(bp) 3223244Swnj register struct buf *bp; 3231900Swnj { 3243244Swnj int tsunit = TSUNIT(bp->b_dev); 3253244Swnj register struct uba_ctlr *um; 3263327Swnj register struct buf *dp; 3275438Sroot register int s; 3281900Swnj 3293244Swnj /* 3303244Swnj * Put transfer at end of controller queue 3313244Swnj */ 3321900Swnj bp->av_forw = NULL; 3333244Swnj um = tsdinfo[tsunit]->ui_mi; 3345438Sroot s = spl5(); 3355693Sroot dp = &tsutab[tsunit]; 3363327Swnj if (dp->b_actf == NULL) 3373327Swnj dp->b_actf = bp; 3381900Swnj else 3393327Swnj dp->b_actl->av_forw = bp; 3403327Swnj dp->b_actl = bp; 3413327Swnj um->um_tab.b_actf = um->um_tab.b_actl = dp; 3423244Swnj /* 3433244Swnj * If the controller is not busy, get 3443244Swnj * it going. 3453244Swnj */ 3463244Swnj if (um->um_tab.b_active == 0) 3473244Swnj tsstart(um); 3485438Sroot splx(s); 3491900Swnj } 3501900Swnj 3513244Swnj /* 3523244Swnj * Start activity on a ts controller. 3533244Swnj */ 3543244Swnj tsstart(um) 3553244Swnj register struct uba_ctlr *um; 3561900Swnj { 3571900Swnj register struct buf *bp; 3585693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 3593244Swnj register struct ts_softc *sc; 3603244Swnj register struct ts_cmd *tc; 3613244Swnj register struct uba_device *ui; 3623244Swnj int tsunit, cmd; 3631900Swnj daddr_t blkno; 3641900Swnj 3653244Swnj /* 3663244Swnj * Start the controller if there is something for it to do. 3673244Swnj */ 3683244Swnj loop: 3693327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 3701900Swnj return; 3713244Swnj tsunit = TSUNIT(bp->b_dev); 3723244Swnj ui = tsdinfo[tsunit]; 3733244Swnj sc = &ts_softc[tsunit]; 3743244Swnj tc = &sc->sc_cmd; 3753244Swnj /* 3763244Swnj * Default is that last command was NOT a write command; 3773244Swnj * if we do a write command we will notice this in tsintr(). 3783244Swnj */ 3793656Swnj sc->sc_lastiow = 0; 3803244Swnj if (sc->sc_openf < 0 || (addr->tssr&TS_OFL)) { 3813244Swnj /* 3823244Swnj * Have had a hard error on a non-raw tape 3833244Swnj * or the tape unit is now unavailable 3843244Swnj * (e.g. taken off line). 3853244Swnj */ 3863244Swnj bp->b_flags |= B_ERROR; 3873244Swnj goto next; 3883244Swnj } 3893244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) { 3903244Swnj /* 3913244Swnj * Execute control operation with the specified count. 3923244Swnj */ 3933244Swnj um->um_tab.b_active = 3943244Swnj bp->b_command == TS_REW ? SREW : SCOM; 3953244Swnj tc->c_repcnt = bp->b_repcnt; 3963244Swnj goto dobpcmd; 3973244Swnj } 3983244Swnj /* 3993244Swnj * The following checks handle boundary cases for operation 4003244Swnj * on non-raw tapes. On raw tapes the initialization of 4013244Swnj * sc->sc_nxrec by tsphys causes them to be skipped normally 4023244Swnj * (except in the case of retries). 4033244Swnj */ 4047383Ssam if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 4053244Swnj /* 4063244Swnj * Can't read past known end-of-file. 4073244Swnj */ 4083244Swnj bp->b_flags |= B_ERROR; 4093244Swnj bp->b_error = ENXIO; 4103244Swnj goto next; 4113244Swnj } 4127383Ssam if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && 4133244Swnj bp->b_flags&B_READ) { 4143244Swnj /* 4153244Swnj * Reading at end of file returns 0 bytes. 4163244Swnj */ 4173244Swnj bp->b_resid = bp->b_bcount; 4183244Swnj clrbuf(bp); 4193244Swnj goto next; 4203244Swnj } 4213244Swnj if ((bp->b_flags&B_READ) == 0) 4223244Swnj /* 4233244Swnj * Writing sets EOF 4243244Swnj */ 4257383Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; 4263244Swnj /* 4273244Swnj * If the data transfer command is in the correct place, 4283244Swnj * set up all the registers except the csr, and give 4293244Swnj * control over to the UNIBUS adapter routines, to 4303244Swnj * wait for resources to start the i/o. 4313244Swnj */ 4327383Ssam if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { 4333244Swnj tc->c_size = bp->b_bcount; 4343244Swnj if ((bp->b_flags&B_READ) == 0) 4353244Swnj cmd = TS_WCOM; 4361900Swnj else 4373244Swnj cmd = TS_RCOM; 4383244Swnj if (um->um_tab.b_errcnt) 4393244Swnj cmd |= TS_RETRY; 4403244Swnj um->um_tab.b_active = SIO; 4413327Swnj tc->c_cmd = TS_ACK | TS_CVC | TS_IE | cmd; 4423244Swnj (void) ubago(ui); 4433244Swnj return; 4443244Swnj } 4453244Swnj /* 4463244Swnj * Tape positioned incorrectly; 4473244Swnj * set to seek forwards or backwards to the correct spot. 4483244Swnj * This happens for raw tapes only on error retries. 4493244Swnj */ 4503244Swnj um->um_tab.b_active = SSEEK; 4517383Ssam if (blkno < bdbtofsb(bp->b_blkno)) { 4523244Swnj bp->b_command = TS_SFORW; 4537383Ssam tc->c_repcnt = bdbtofsb(bp->b_blkno) - blkno; 4541900Swnj } else { 4553244Swnj bp->b_command = TS_SREV; 4567383Ssam tc->c_repcnt = blkno - bdbtofsb(bp->b_blkno); 4571900Swnj } 4583244Swnj dobpcmd: 4593244Swnj /* 4603244Swnj * Do the command in bp. 4613244Swnj */ 4623327Swnj tc->c_cmd = TS_ACK | TS_CVC | TS_IE | bp->b_command; 4633244Swnj addr->tsdb = sc->sc_uba; 4641900Swnj return; 4651900Swnj 4663244Swnj next: 4673244Swnj /* 4683244Swnj * Done with this operation due to error or 4693244Swnj * the fact that it doesn't do anything. 4703244Swnj * Release UBA resources (if any), dequeue 4713244Swnj * the transfer and continue processing this slave. 4723244Swnj */ 4733244Swnj if (um->um_ubinfo) 4743244Swnj ubadone(um); 4753244Swnj um->um_tab.b_errcnt = 0; 4763327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 4771900Swnj iodone(bp); 4781900Swnj goto loop; 4791900Swnj } 4801900Swnj 4813244Swnj /* 4823244Swnj * The UNIBUS resources we needed have been 4833244Swnj * allocated to us; start the device. 4843244Swnj */ 4853244Swnj tsdgo(um) 4863244Swnj register struct uba_ctlr *um; 4871900Swnj { 4885693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 4893244Swnj register struct ts_softc *sc = &ts_softc[um->um_ctlr]; 4903327Swnj register int i; 4913244Swnj 4923327Swnj i = um->um_ubinfo & 0777777; 4933327Swnj sc->sc_cmd.c_loba = i; 4943327Swnj sc->sc_cmd.c_hiba = (i>>16)&3; 4953244Swnj addr->tsdb = sc->sc_uba; 4963244Swnj } 4973244Swnj 4983244Swnj /* 4993244Swnj * Ts interrupt routine. 5003244Swnj */ 5013244Swnj /*ARGSUSED*/ 5023244Swnj tsintr(ts11) 5033244Swnj int ts11; 5043244Swnj { 5051900Swnj register struct buf *bp; 5063244Swnj register struct uba_ctlr *um = tsminfo[ts11]; 5075693Sroot register struct tsdevice *addr; 5083244Swnj register struct ts_softc *sc; 5093244Swnj int tsunit; 5103244Swnj register state; 5111900Swnj 5123327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 5131900Swnj return; 5143244Swnj tsunit = TSUNIT(bp->b_dev); 5155693Sroot addr = (struct tsdevice *)tsdinfo[tsunit]->ui_addr; 5163244Swnj /* 5173244Swnj * If last command was a rewind, and tape is still 5183244Swnj * rewinding, wait for the rewind complete interrupt. 5193244Swnj * 5203244Swnj * SHOULD NEVER GET AN INTERRUPT IN THIS STATE. 5213244Swnj */ 5223244Swnj if (um->um_tab.b_active == SREW) { 5233244Swnj um->um_tab.b_active = SCOM; 5243244Swnj if ((addr->tssr&TS_SSR) == 0) 5253244Swnj return; 5263244Swnj } 5273244Swnj /* 5283244Swnj * An operation completed... record status 5293244Swnj */ 5303244Swnj sc = &ts_softc[tsunit]; 5313244Swnj if ((bp->b_flags & B_READ) == 0) 5323244Swnj sc->sc_lastiow = 1; 5333244Swnj state = um->um_tab.b_active; 5343244Swnj um->um_tab.b_active = 0; 5353244Swnj /* 5363244Swnj * Check for errors. 5373244Swnj */ 5383244Swnj if (addr->tssr&TS_SC) { 5393244Swnj switch (addr->tssr & TS_TC) { 5403244Swnj case TS_UNREC: /* unrecoverable */ 5413244Swnj case TS_FATAL: /* fatal error */ 5423244Swnj case TS_ATTN: /* attention (shouldn't happen) */ 5433244Swnj case TS_RECNM: /* recoverable, no motion */ 5443244Swnj break; 5451900Swnj 5463244Swnj case TS_SUCC: /* success termination */ 5473244Swnj printf("ts%d: success\n", TSUNIT(minor(bp->b_dev))); 5483244Swnj goto ignoreerr; 5491900Swnj 5503244Swnj case TS_ALERT: /* tape status alert */ 5513244Swnj /* 5523244Swnj * If we hit the end of the tape file, 5533244Swnj * update our position. 5543244Swnj */ 5553244Swnj if (sc->sc_sts.s_xs0 & (TS_TMK|TS_EOT)) { 5563244Swnj tsseteof(bp); /* set blkno and nxrec */ 5573244Swnj state = SCOM; /* force completion */ 5583244Swnj /* 5593244Swnj * Stuff bc so it will be unstuffed correctly 5603244Swnj * later to get resid. 5613244Swnj */ 5623244Swnj sc->sc_sts.s_rbpcr = bp->b_bcount; 5633244Swnj goto opdone; 5643244Swnj } 5653244Swnj /* 5663244Swnj * If we were reading raw tape and the record was too long 5673244Swnj * or too short, then we don't consider this an error. 5683244Swnj */ 5693244Swnj if (bp == &rtsbuf[TSUNIT(bp->b_dev)] && (bp->b_flags&B_READ) && 5703244Swnj sc->sc_sts.s_xs0&(TS_RLS|TS_RLL)) 5713244Swnj goto ignoreerr; 5723244Swnj case TS_RECOV: /* recoverable, tape moved */ 5733244Swnj /* 5743244Swnj * If this was an i/o operation retry up to 8 times. 5753244Swnj */ 5763244Swnj if (state==SIO) { 5773244Swnj if (++um->um_tab.b_errcnt < 7) { 5783244Swnj ubadone(um); 5793244Swnj goto opcont; 5803244Swnj } else 5813244Swnj sc->sc_blkno++; 5823244Swnj } else { 5833244Swnj /* 5843244Swnj * Non-i/o errors on non-raw tape 5853244Swnj * cause it to close. 5863244Swnj */ 5873244Swnj if (sc->sc_openf>0 && bp != &rtsbuf[TSUNIT(bp->b_dev)]) 5883244Swnj sc->sc_openf = -1; 5893244Swnj } 5901900Swnj break; 5913244Swnj 5923244Swnj case TS_REJECT: /* function reject */ 5933244Swnj if (state == SIO && sc->sc_sts.s_xs0 & TS_WLE) 5943244Swnj printf("ts%d: write locked\n", TSUNIT(bp->b_dev)); 5953244Swnj if ((sc->sc_sts.s_xs0 & TS_ONL) == 0) 5963244Swnj printf("ts%d: offline\n", TSUNIT(bp->b_dev)); 5971900Swnj break; 5981900Swnj } 5993244Swnj /* 6003244Swnj * Couldn't recover error 6013244Swnj */ 6023647Swnj printf("ts%d: hard error bn%d xs0=%b", TSUNIT(bp->b_dev), 6033244Swnj bp->b_blkno, sc->sc_sts.s_xs0, TSXS0_BITS); 6043647Swnj if (sc->sc_sts.s_xs1) 6053647Swnj printf(" xs1=%b", sc->sc_sts.s_xs1, TSXS1_BITS); 6063647Swnj if (sc->sc_sts.s_xs2) 6073647Swnj printf(" xs2=%b", sc->sc_sts.s_xs2, TSXS2_BITS); 6083647Swnj if (sc->sc_sts.s_xs3) 6093647Swnj printf(" xs3=%b", sc->sc_sts.s_xs3, TSXS3_BITS); 6103647Swnj printf("\n"); 6113244Swnj bp->b_flags |= B_ERROR; 6123244Swnj goto opdone; 6133244Swnj } 6143244Swnj /* 6153244Swnj * Advance tape control FSM. 6163244Swnj */ 6173244Swnj ignoreerr: 6183244Swnj switch (state) { 6191900Swnj 6203244Swnj case SIO: 6213244Swnj /* 6223244Swnj * Read/write increments tape block number 6233244Swnj */ 6243244Swnj sc->sc_blkno++; 6253244Swnj goto opdone; 6261900Swnj 6271900Swnj case SCOM: 6283244Swnj /* 6293244Swnj * For forward/backward space record update current position. 6303244Swnj */ 6313244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) 6323244Swnj switch (bp->b_command) { 6331900Swnj 6343244Swnj case TS_SFORW: 6353244Swnj sc->sc_blkno += bp->b_repcnt; 6363244Swnj break; 6371900Swnj 6383244Swnj case TS_SREV: 6393244Swnj sc->sc_blkno -= bp->b_repcnt; 6403244Swnj break; 6413244Swnj } 6423244Swnj goto opdone; 6433244Swnj 6443244Swnj case SSEEK: 6457383Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno); 6463244Swnj goto opcont; 6473244Swnj 6481900Swnj default: 6493244Swnj panic("tsintr"); 6501900Swnj } 6513244Swnj opdone: 6523244Swnj /* 6533244Swnj * Reset error count and remove 6543244Swnj * from device queue. 6553244Swnj */ 6563244Swnj um->um_tab.b_errcnt = 0; 6573327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 6583244Swnj bp->b_resid = sc->sc_sts.s_rbpcr; 6593244Swnj ubadone(um); 6603244Swnj iodone(bp); 6613327Swnj if (um->um_tab.b_actf->b_actf == 0) 6623244Swnj return; 6633244Swnj opcont: 6643244Swnj tsstart(um); 6653244Swnj } 6663244Swnj 6673244Swnj tsseteof(bp) 6683244Swnj register struct buf *bp; 6693244Swnj { 6703244Swnj register int tsunit = TSUNIT(bp->b_dev); 6713244Swnj register struct ts_softc *sc = &ts_softc[tsunit]; 6723244Swnj 6733244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) { 6747383Ssam if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 6753244Swnj /* reversing */ 6767383Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno) - sc->sc_sts.s_rbpcr; 6773244Swnj sc->sc_blkno = sc->sc_nxrec; 6783244Swnj } else { 6793244Swnj /* spacing forward */ 6807383Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno) + sc->sc_sts.s_rbpcr; 6813244Swnj sc->sc_nxrec = sc->sc_blkno - 1; 6821900Swnj } 6833244Swnj return; 6843244Swnj } 6853244Swnj /* eof on read */ 6867383Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno); 6871900Swnj } 6881900Swnj 6897733Sroot tsread(dev, uio) 6903244Swnj dev_t dev; 6917733Sroot struct uio *uio; 6921900Swnj { 6938164Sroot int errno; 6943244Swnj 6958164Sroot errno = tsphys(dev, uio); 6968164Sroot if (errno) 6978164Sroot return (errno); 6988164Sroot return (physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_READ, minphys, uio)); 6991900Swnj } 7001900Swnj 7017841Sroot tswrite(dev, uio) 7023244Swnj dev_t dev; 7037841Sroot struct uio *uio; 7041900Swnj { 7058164Sroot int errno; 7063244Swnj 7078164Sroot errno = tsphys(dev, uio); 7088164Sroot if (errno) 7098164Sroot return (errno); 7108164Sroot return (physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_WRITE, minphys, uio)); 7111900Swnj } 7121900Swnj 7133244Swnj /* 7143244Swnj * Check that a raw device exists. 7153244Swnj * If it does, set up sc_blkno and sc_nxrec 7163244Swnj * so that the tape will appear positioned correctly. 7173244Swnj */ 7187733Sroot tsphys(dev, uio) 7193244Swnj dev_t dev; 7207733Sroot struct uio *uio; 7211900Swnj { 7223244Swnj register int tsunit = TSUNIT(dev); 7233244Swnj register daddr_t a; 7243244Swnj register struct ts_softc *sc; 7253244Swnj register struct uba_device *ui; 7261900Swnj 7277841Sroot if (tsunit >= NTS || (ui=tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) 7287733Sroot return (ENXIO); 7293244Swnj sc = &ts_softc[tsunit]; 7307841Sroot a = bdbtofsb(uio->uio_offset >> 9); 7313244Swnj sc->sc_blkno = a; 7323244Swnj sc->sc_nxrec = a + 1; 7337733Sroot return (0); 7341900Swnj } 7351918Swnj 7363244Swnj tsreset(uban) 7373244Swnj int uban; 7381918Swnj { 7393244Swnj register struct uba_ctlr *um; 7405693Sroot register struct uba_device *ui; 7415693Sroot register struct buf *dp; 7423244Swnj register ts11; 7431918Swnj 7443244Swnj for (ts11 = 0; ts11 < NTS; ts11++) { 7453244Swnj if ((um = tsminfo[ts11]) == 0 || um->um_alive == 0 || 7463244Swnj um->um_ubanum != uban) 7473244Swnj continue; 7483244Swnj printf(" ts%d", ts11); 7493244Swnj um->um_tab.b_active = 0; 7503244Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7515693Sroot if (ts_softc[ts11].sc_openf > 0) 7525693Sroot ts_softc[ts11].sc_openf = -1; 7533244Swnj if (um->um_ubinfo) { 7543244Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 7559356Ssam um->um_ubinfo = 0; 7563244Swnj } 7575693Sroot if ((ui = tsdinfo[ts11]) && ui->ui_mi == um && ui->ui_alive) { 7585693Sroot dp = &tsutab[ts11]; 7595693Sroot dp->b_active = 0; 7605693Sroot dp->b_forw = 0; 7615693Sroot if (um->um_tab.b_actf == NULL) 7625693Sroot um->um_tab.b_actf = dp; 7635693Sroot else 7645693Sroot um->um_tab.b_actl->b_forw = dp; 7655693Sroot um->um_tab.b_actl = dp; 7665693Sroot } 767*17432Skarels ts_softc[ts11].sc_mapped = 0; 7683989Sroot (void) tsinit(ts11); 7693244Swnj tsstart(um); 7701918Swnj } 7711918Swnj } 7721918Swnj 7733244Swnj /*ARGSUSED*/ 7747633Ssam tsioctl(dev, cmd, data, flag) 7757633Ssam caddr_t data; 7763244Swnj dev_t dev; 7771918Swnj { 7783244Swnj int tsunit = TSUNIT(dev); 7793244Swnj register struct ts_softc *sc = &ts_softc[tsunit]; 7803244Swnj register struct buf *bp = &ctsbuf[TSUNIT(dev)]; 7813244Swnj register callcount; 7823244Swnj int fcount; 7837633Ssam struct mtop *mtop; 7847633Ssam struct mtget *mtget; 7853244Swnj /* we depend of the values and order of the MT codes here */ 7863244Swnj static tsops[] = 7873656Swnj {TS_WEOF,TS_SFORWF,TS_SREVF,TS_SFORW,TS_SREV,TS_REW,TS_OFFL,TS_SENSE}; 7881918Swnj 7893244Swnj switch (cmd) { 7907633Ssam 7913244Swnj case MTIOCTOP: /* tape operation */ 7927633Ssam mtop = (struct mtop *)data; 7938575Sroot switch (mtop->mt_op) { 7947633Ssam 7953244Swnj case MTWEOF: 7967633Ssam callcount = mtop->mt_count; 7973244Swnj fcount = 1; 7983244Swnj break; 7997633Ssam 8003244Swnj case MTFSF: case MTBSF: 8013244Swnj case MTFSR: case MTBSR: 8023244Swnj callcount = 1; 8037633Ssam fcount = mtop->mt_count; 8043244Swnj break; 8057633Ssam 8063244Swnj case MTREW: case MTOFFL: case MTNOP: 8073244Swnj callcount = 1; 8083244Swnj fcount = 1; 8093244Swnj break; 8107633Ssam 8113244Swnj default: 8128575Sroot return (ENXIO); 8133244Swnj } 8148575Sroot if (callcount <= 0 || fcount <= 0) 8158575Sroot return (EINVAL); 8163244Swnj while (--callcount >= 0) { 8177633Ssam tscommand(dev, tsops[mtop->mt_op], fcount); 8187633Ssam if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) && 8198611Sroot bp->b_resid) 8208575Sroot return (EIO); 8213244Swnj if ((bp->b_flags&B_ERROR) || sc->sc_sts.s_xs0&TS_BOT) 8223244Swnj break; 8233244Swnj } 8248649Sroot return (geterror(bp)); 8257633Ssam 8263244Swnj case MTIOCGET: 8277633Ssam mtget = (struct mtget *)data; 8287633Ssam mtget->mt_dsreg = 0; 8297633Ssam mtget->mt_erreg = sc->sc_sts.s_xs0; 8307633Ssam mtget->mt_resid = sc->sc_resid; 8317633Ssam mtget->mt_type = MT_ISTS; 8328575Sroot break; 8337633Ssam 8343244Swnj default: 8358575Sroot return (ENXIO); 8363244Swnj } 8378575Sroot return (0); 8381918Swnj } 8391918Swnj 8403244Swnj #define DBSIZE 20 8413244Swnj 8423244Swnj tsdump() 8431918Swnj { 8443244Swnj register struct uba_device *ui; 8453244Swnj register struct uba_regs *up; 8465693Sroot register struct tsdevice *addr; 8473244Swnj int blk, num; 8483244Swnj int start; 8491918Swnj 8503244Swnj start = 0; 8513244Swnj num = maxfree; 8523244Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 8533244Swnj if (tsdinfo[0] == 0) 8543244Swnj return (ENXIO); 8553244Swnj ui = phys(tsdinfo[0], struct uba_device *); 8563244Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 8578703Sroot ubainit(up); 8583244Swnj DELAY(1000000); 8595693Sroot addr = (struct tsdevice *)ui->ui_physaddr; 8603244Swnj addr->tssr = 0; 8613244Swnj tswait(addr); 8623244Swnj while (num > 0) { 8633244Swnj blk = num > DBSIZE ? DBSIZE : num; 8643244Swnj tsdwrite(start, blk, addr, up); 8653244Swnj start += blk; 8663244Swnj num -= blk; 8673244Swnj } 8683244Swnj tseof(addr); 8693244Swnj tseof(addr); 8703244Swnj tswait(addr); 8713244Swnj if (addr->tssr&TS_SC) 8723244Swnj return (EIO); 8733244Swnj addr->tssr = 0; 8743244Swnj tswait(addr); 8753244Swnj return (0); 8761918Swnj } 8771918Swnj 8783244Swnj tsdwrite(dbuf, num, addr, up) 8798635Sroot register int dbuf, num; 8805693Sroot register struct tsdevice *addr; 8813244Swnj struct uba_regs *up; 8821918Swnj { 8833244Swnj register struct pte *io; 8843244Swnj register int npf; 8851918Swnj 8863244Swnj tswait(addr); 8873244Swnj io = up->uba_map; 8883244Swnj npf = num+1; 8893244Swnj while (--npf != 0) 8903244Swnj *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); 8913244Swnj *(int *)io = 0; 8923244Swnj #ifdef notyet 8933244Swnj addr->tsbc = -(num*NBPG); 8943244Swnj addr->tsba = 0; 8953244Swnj addr->tscs = TS_WCOM | TM_GO; 8963244Swnj #endif 8971918Swnj } 8981918Swnj 8993244Swnj tswait(addr) 9005693Sroot register struct tsdevice *addr; 9011918Swnj { 9023244Swnj register s; 9031918Swnj 9043244Swnj do 9053244Swnj s = addr->tssr; 9063244Swnj while ((s & TS_SSR) == 0); 9071918Swnj } 9081918Swnj 9093244Swnj tseof(addr) 9105693Sroot struct tsdevice *addr; 9111918Swnj { 9121918Swnj 9133244Swnj tswait(addr); 9143244Swnj #ifdef notyet 9153244Swnj addr->tscs = TS_WEOF | TM_GO; 9163244Swnj #endif 9171918Swnj } 9181900Swnj #endif 919