1*5693Sroot /* ts.c 4.22 82/02/03 */ 21900Swnj 31941Swnj #include "ts.h" 41900Swnj #if NTS > 0 51900Swnj /* 61900Swnj * TS11 tape driver 73244Swnj * 83244Swnj * TODO: 9*5693Sroot * 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" 233244Swnj #include "../h/mtio.h" 243244Swnj #include "../h/ioctl.h" 253244Swnj #include "../h/cmap.h" 263244Swnj #include "../h/cpu.h" 271900Swnj 283244Swnj #include "../h/tsreg.h" 291900Swnj 303244Swnj /* 313244Swnj * There is a ctsbuf per tape controller. 323244Swnj * It is used as the token to pass to the internal routines 333244Swnj * to execute tape ioctls. 343244Swnj * In particular, when the tape is rewinding on close we release 353244Swnj * the user process but any further attempts to use the tape drive 363244Swnj * before the rewind completes will hang waiting for ctsbuf. 373244Swnj */ 383244Swnj struct buf ctsbuf[NTS]; 391900Swnj 403244Swnj /* 413244Swnj * Raw tape operations use rtsbuf. The driver 423244Swnj * notices when rtsbuf is being used and allows the user 433244Swnj * program to continue after errors and read records 443244Swnj * not of the standard length (BSIZE). 453244Swnj */ 463244Swnj struct buf rtsbuf[NTS]; 471900Swnj 483244Swnj /* 493244Swnj * Driver unibus interface routines and variables. 503244Swnj */ 513244Swnj int tsprobe(), tsslave(), tsattach(), tsdgo(), tsintr(); 523244Swnj struct uba_ctlr *tsminfo[NTS]; 533244Swnj struct uba_device *tsdinfo[NTS]; 54*5693Sroot struct buf tsutab[NTS]; 553244Swnj u_short tsstd[] = { 0772520, 0 }; 563244Swnj /*** PROBABLY DON'T NEED ALL THESE SINCE CONTROLLER == DRIVE ***/ 573244Swnj struct uba_driver zsdriver = 583327Swnj { tsprobe, tsslave, tsattach, tsdgo, tsstd, "ts", tsdinfo, "zs", tsminfo, 0 }; 591900Swnj 603244Swnj /* bits in minor device */ 613244Swnj #define TSUNIT(dev) (minor(dev)&03) 623244Swnj #define T_NOREWIND 04 631900Swnj 643244Swnj #define INF (daddr_t)1000000L 651900Swnj 663244Swnj /* 673244Swnj * Software state per tape transport. 683244Swnj * Also contains hardware state in message packets. 693244Swnj * 703244Swnj * 1. A tape drive is a unique-open device; we refuse opens when it is already. 713244Swnj * 2. We keep track of the current position on a block tape and seek 723244Swnj * before operations by forward/back spacing if necessary. 733244Swnj * 3. We remember if the last operation was a write on a tape, so if a tape 743244Swnj * is open read write and the last thing done is a write we can 753244Swnj * write a standard end of tape mark (two eofs). 763244Swnj * 4. We remember the status registers after the last command, using 773244Swnj * then internally and returning them to the SENSE ioctl. 783244Swnj */ 793244Swnj struct ts_softc { 803244Swnj char sc_openf; /* lock against multiple opens */ 813244Swnj char sc_lastiow; /* last op was a write */ 823327Swnj short sc_resid; /* copy of last bc */ 833244Swnj daddr_t sc_blkno; /* block number, for block device tape */ 843244Swnj daddr_t sc_nxrec; /* position of end of tape, if known */ 85*5693Sroot struct ts_cmd sc_cmd; /* the command packet */ 86*5693Sroot struct ts_sts sc_sts; /* status packet, for returned status */ 87*5693Sroot struct ts_char sc_char; /* characteristics packet */ 88*5693Sroot struct ts_softc *sc_ubaddr; /* Unibus address of ts_softc structure */ 89*5693Sroot short sc_mapped; /* is ts_sfotc mapped in Unibus space? */ 903244Swnj } ts_softc[NTS]; 911900Swnj 923244Swnj /* 933244Swnj * States for um->um_tab.b_active, the per controller state flag. 943244Swnj * This is used to sequence control in the driver. 953244Swnj */ 963244Swnj #define SSEEK 1 /* seeking */ 973244Swnj #define SIO 2 /* doing seq i/o */ 983244Swnj #define SCOM 3 /* sending control command */ 993244Swnj #define SREW 4 /* sending a drive rewind */ 1001900Swnj 1013244Swnj /* 1023244Swnj * Determine if there is a controller for 1033244Swnj * a ts at address reg. Our goal is to make the 1043244Swnj * device interrupt. 1053244Swnj */ 1063985Sroot /*ARGSUSED*/ 1073244Swnj tsprobe(reg) 1083244Swnj caddr_t reg; 1093244Swnj { 1103244Swnj register int br, cvec; /* must be r11,r10; value-result */ 1111900Swnj 1123244Swnj #ifdef lint 1133244Swnj br = 0; cvec = br; br = cvec; 1144937Swnj tsintr(0); 1153244Swnj #endif 116*5693Sroot ((struct tsdevice *)reg)->tssr = 0; 117*5693Sroot DELAY(100); 118*5693Sroot if ((((struct tsdevice *)reg)->tssr & TS_NBA) == 0) 119*5693Sroot return(0); 120*5693Sroot /* IT'S TOO HARD TO MAKE THIS THING INTERRUPT JUST TO FIND ITS VECTOR */ 121*5693Sroot cvec = ((unsigned)reg) & 07 ? 0260 : 0224; 1223244Swnj br = 0x15; 1233982Sroot return (1); 1243244Swnj } 1251900Swnj 1263244Swnj /* 1273244Swnj * TS11 only supports one drive per controller; 1283244Swnj * check for ui_slave == 0. 1293244Swnj * 1303244Swnj * DO WE REALLY NEED THIS ROUTINE??? 1313244Swnj */ 1323244Swnj /*ARGSUSED*/ 1333244Swnj tsslave(ui, reg) 1343244Swnj struct uba_device *ui; 1353244Swnj caddr_t reg; 1363244Swnj { 1371900Swnj 1383244Swnj if (ui->ui_slave) /* non-zero slave not allowed */ 1393244Swnj return(0); 1403244Swnj return (1); 1413244Swnj } 1421900Swnj 1433244Swnj /* 1443244Swnj * Record attachment of the unit to the controller. 1453244Swnj * 1463244Swnj * SHOULD THIS ROUTINE DO ANYTHING??? 1473244Swnj */ 1483244Swnj /*ARGSUSED*/ 1493244Swnj tsattach(ui) 1503244Swnj struct uba_device *ui; 1513244Swnj { 1521900Swnj 1533244Swnj } 1541900Swnj 1553244Swnj /* 1563244Swnj * Open the device. Tapes are unique open 1573244Swnj * devices, so we refuse if it is already open. 1583244Swnj * We also check that a tape is available, and 1593244Swnj * don't block waiting here; if you want to wait 1603244Swnj * for a tape you should timeout in user code. 1613244Swnj */ 1621900Swnj tsopen(dev, flag) 1633244Swnj dev_t dev; 1643244Swnj int flag; 1651900Swnj { 1663244Swnj register int tsunit; 1673244Swnj register struct uba_device *ui; 1683244Swnj register struct ts_softc *sc; 1691900Swnj 1703244Swnj tsunit = TSUNIT(dev); 1713244Swnj if (tsunit>=NTS || (sc = &ts_softc[tsunit])->sc_openf || 1723244Swnj (ui = tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) { 1731900Swnj u.u_error = ENXIO; 1741900Swnj return; 1751900Swnj } 1763244Swnj if (tsinit(tsunit)) { 1771900Swnj u.u_error = ENXIO; 1781900Swnj return; 1791900Swnj } 1803244Swnj tscommand(dev, TS_SENSE, 1); 1813711Sroot if ((sc->sc_sts.s_xs0&TS_ONL) == 0) { 1823711Sroot uprintf("ts%d: not online\n", tsunit); 1833244Swnj u.u_error = EIO; 1843244Swnj return; 1851900Swnj } 1863718Sroot if ((flag&(FREAD|FWRITE)) == FWRITE && (sc->sc_sts.s_xs0&TS_WLK)) { 1873711Sroot uprintf("ts%d: no write ring\n", tsunit); 1883711Sroot u.u_error = EIO; 1893711Sroot return; 1903711Sroot } 1913244Swnj sc->sc_openf = 1; 1923244Swnj sc->sc_blkno = (daddr_t)0; 1933244Swnj sc->sc_nxrec = INF; 1943244Swnj sc->sc_lastiow = 0; 1951900Swnj } 1961900Swnj 1973244Swnj /* 1983244Swnj * Close tape device. 1993244Swnj * 2003244Swnj * If tape was open for writing or last operation was 2013244Swnj * a write, then write two EOF's and backspace over the last one. 2023244Swnj * Unless this is a non-rewinding special file, rewind the tape. 2033244Swnj * Make the tape available to others. 2043244Swnj */ 2051900Swnj tsclose(dev, flag) 2063244Swnj register dev_t dev; 2073244Swnj register flag; 2081900Swnj { 2093244Swnj register struct ts_softc *sc = &ts_softc[TSUNIT(dev)]; 2101900Swnj 2113244Swnj if (flag == FWRITE || (flag&FWRITE) && sc->sc_lastiow) { 2123244Swnj tscommand(dev, TS_WEOF, 1); 2133244Swnj tscommand(dev, TS_WEOF, 1); 2143244Swnj tscommand(dev, TS_SREV, 1); 2151900Swnj } 2163244Swnj if ((minor(dev)&T_NOREWIND) == 0) 2173244Swnj /* 2183244Swnj * 0 count means don't hang waiting for rewind complete 2193244Swnj * rather ctsbuf stays busy until the operation completes 2203244Swnj * preventing further opens from completing by 2213244Swnj * preventing a TS_SENSE from completing. 2223244Swnj */ 2233244Swnj tscommand(dev, TS_REW, 0); 2243244Swnj sc->sc_openf = 0; 2251900Swnj } 2261900Swnj 2273244Swnj /* 2283244Swnj * Initialize the TS11. Set up Unibus mapping for command 2293244Swnj * packets and set device characteristics. 2303244Swnj */ 2313244Swnj tsinit(unit) 2323244Swnj register int unit; 2331900Swnj { 2343244Swnj register struct ts_softc *sc = &ts_softc[unit]; 2353244Swnj register struct uba_ctlr *um = tsminfo[unit]; 236*5693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 2373244Swnj register int i; 2383244Swnj 2393244Swnj /* 2403244Swnj * Map the command and message packets into Unibus 2413244Swnj * address space. We do all the command and message 2423244Swnj * packets at once to minimize the amount of Unibus 2433244Swnj * mapping necessary. 2443244Swnj */ 245*5693Sroot if (sc->sc_mapped == 0) { 246*5693Sroot ctsbuf[unit].b_un.b_addr = (caddr_t)sc; 247*5693Sroot ctsbuf[unit].b_bcount = sizeof(*sc); 2483244Swnj i = ubasetup(um->um_ubanum, &ctsbuf[unit], 0); 2493244Swnj i &= 0777777; 250*5693Sroot sc->sc_ubaddr = (struct ts_softc *)i; 251*5693Sroot sc->sc_mapped++; 2523244Swnj } 2533244Swnj /* 2543244Swnj * Now initialize the TS11 controller. 2553244Swnj * Set the characteristics. 2563244Swnj */ 2573668Swnj if (addr->tssr & (TS_NBA|TS_OFL)) { 2583244Swnj addr->tssr = 0; /* subsystem initialize */ 2593244Swnj tswait(addr); 260*5693Sroot i = (int)&sc->sc_ubaddr->sc_cmd; /* Unibus addr of cmd */ 2613244Swnj sc->sc_uba = (u_short)(i + ((i>>16)&3)); 262*5693Sroot sc->sc_char.char_addr = (int)&sc->sc_ubaddr->sc_sts; 2633244Swnj sc->sc_char.char_size = sizeof(struct ts_sts); 2643244Swnj sc->sc_char.char_mode = TS_ESS; 2653244Swnj sc->sc_cmd.c_cmd = TS_ACK | TS_SETCHR; 266*5693Sroot i = (int)&sc->sc_ubaddr->sc_char; 2673327Swnj sc->sc_cmd.c_loba = i; 2683327Swnj sc->sc_cmd.c_hiba = (i>>16)&3; 2693244Swnj sc->sc_cmd.c_size = sizeof(struct ts_char); 2703244Swnj addr->tsdb = sc->sc_uba; 2713244Swnj tswait(addr); 2723327Swnj if (addr->tssr & TS_NBA) 2733327Swnj return(1); 2743244Swnj } 2753244Swnj return(0); 2763244Swnj } 2773244Swnj 2783244Swnj /* 2793244Swnj * Execute a command on the tape drive 2803244Swnj * a specified number of times. 2813244Swnj */ 2823244Swnj tscommand(dev, com, count) 2833244Swnj dev_t dev; 2843244Swnj int com, count; 2853244Swnj { 2861900Swnj register struct buf *bp; 2875438Sroot register int s; 2881900Swnj 2893244Swnj bp = &ctsbuf[TSUNIT(dev)]; 2905438Sroot s = spl5(); 2913244Swnj while (bp->b_flags&B_BUSY) { 2923244Swnj /* 2933244Swnj * This special check is because B_BUSY never 2943244Swnj * gets cleared in the non-waiting rewind case. 2953244Swnj */ 2963244Swnj if (bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 2973244Swnj break; 2981900Swnj bp->b_flags |= B_WANTED; 2991900Swnj sleep((caddr_t)bp, PRIBIO); 3001900Swnj } 3013244Swnj bp->b_flags = B_BUSY|B_READ; 3025438Sroot splx(s); 3033244Swnj bp->b_dev = dev; 3043244Swnj bp->b_repcnt = count; 3053244Swnj bp->b_command = com; 3061900Swnj bp->b_blkno = 0; 3071900Swnj tsstrategy(bp); 3083244Swnj /* 3093244Swnj * In case of rewind from close, don't wait. 3103244Swnj * This is the only case where count can be 0. 3113244Swnj */ 3123244Swnj if (count == 0) 3133244Swnj return; 3141900Swnj iowait(bp); 3153244Swnj if (bp->b_flags&B_WANTED) 3161900Swnj wakeup((caddr_t)bp); 3173244Swnj bp->b_flags &= B_ERROR; 3181900Swnj } 3191900Swnj 3203244Swnj /* 3213244Swnj * Queue a tape operation. 3223244Swnj */ 3231900Swnj tsstrategy(bp) 3243244Swnj register struct buf *bp; 3251900Swnj { 3263244Swnj int tsunit = TSUNIT(bp->b_dev); 3273244Swnj register struct uba_ctlr *um; 3283327Swnj register struct buf *dp; 3295438Sroot register int s; 3301900Swnj 3313244Swnj /* 3323244Swnj * Put transfer at end of controller queue 3333244Swnj */ 3341900Swnj bp->av_forw = NULL; 3353244Swnj um = tsdinfo[tsunit]->ui_mi; 3365438Sroot s = spl5(); 337*5693Sroot dp = &tsutab[tsunit]; 3383327Swnj if (dp->b_actf == NULL) 3393327Swnj dp->b_actf = bp; 3401900Swnj else 3413327Swnj dp->b_actl->av_forw = bp; 3423327Swnj dp->b_actl = bp; 3433327Swnj um->um_tab.b_actf = um->um_tab.b_actl = dp; 3443244Swnj /* 3453244Swnj * If the controller is not busy, get 3463244Swnj * it going. 3473244Swnj */ 3483244Swnj if (um->um_tab.b_active == 0) 3493244Swnj tsstart(um); 3505438Sroot splx(s); 3511900Swnj } 3521900Swnj 3533244Swnj /* 3543244Swnj * Start activity on a ts controller. 3553244Swnj */ 3563244Swnj tsstart(um) 3573244Swnj register struct uba_ctlr *um; 3581900Swnj { 3591900Swnj register struct buf *bp; 360*5693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 3613244Swnj register struct ts_softc *sc; 3623244Swnj register struct ts_cmd *tc; 3633244Swnj register struct uba_device *ui; 3643244Swnj int tsunit, cmd; 3651900Swnj daddr_t blkno; 3661900Swnj 3673244Swnj /* 3683244Swnj * Start the controller if there is something for it to do. 3693244Swnj */ 3703244Swnj loop: 3713327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 3721900Swnj return; 3733244Swnj tsunit = TSUNIT(bp->b_dev); 3743244Swnj ui = tsdinfo[tsunit]; 3753244Swnj sc = &ts_softc[tsunit]; 3763244Swnj tc = &sc->sc_cmd; 3773244Swnj /* 3783244Swnj * Default is that last command was NOT a write command; 3793244Swnj * if we do a write command we will notice this in tsintr(). 3803244Swnj */ 3813656Swnj sc->sc_lastiow = 0; 3823244Swnj if (sc->sc_openf < 0 || (addr->tssr&TS_OFL)) { 3833244Swnj /* 3843244Swnj * Have had a hard error on a non-raw tape 3853244Swnj * or the tape unit is now unavailable 3863244Swnj * (e.g. taken off line). 3873244Swnj */ 3883244Swnj bp->b_flags |= B_ERROR; 3893244Swnj goto next; 3903244Swnj } 3913244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) { 3923244Swnj /* 3933244Swnj * Execute control operation with the specified count. 3943244Swnj */ 3953244Swnj um->um_tab.b_active = 3963244Swnj bp->b_command == TS_REW ? SREW : SCOM; 3973244Swnj tc->c_repcnt = bp->b_repcnt; 3983244Swnj goto dobpcmd; 3993244Swnj } 4003244Swnj /* 4013244Swnj * The following checks handle boundary cases for operation 4023244Swnj * on non-raw tapes. On raw tapes the initialization of 4033244Swnj * sc->sc_nxrec by tsphys causes them to be skipped normally 4043244Swnj * (except in the case of retries). 4053244Swnj */ 4063244Swnj if (dbtofsb(bp->b_blkno) > sc->sc_nxrec) { 4073244Swnj /* 4083244Swnj * Can't read past known end-of-file. 4093244Swnj */ 4103244Swnj bp->b_flags |= B_ERROR; 4113244Swnj bp->b_error = ENXIO; 4123244Swnj goto next; 4133244Swnj } 4143244Swnj if (dbtofsb(bp->b_blkno) == sc->sc_nxrec && 4153244Swnj bp->b_flags&B_READ) { 4163244Swnj /* 4173244Swnj * Reading at end of file returns 0 bytes. 4183244Swnj */ 4193244Swnj bp->b_resid = bp->b_bcount; 4203244Swnj clrbuf(bp); 4213244Swnj goto next; 4223244Swnj } 4233244Swnj if ((bp->b_flags&B_READ) == 0) 4243244Swnj /* 4253244Swnj * Writing sets EOF 4263244Swnj */ 4273244Swnj sc->sc_nxrec = dbtofsb(bp->b_blkno) + 1; 4283244Swnj /* 4293244Swnj * If the data transfer command is in the correct place, 4303244Swnj * set up all the registers except the csr, and give 4313244Swnj * control over to the UNIBUS adapter routines, to 4323244Swnj * wait for resources to start the i/o. 4333244Swnj */ 4343244Swnj if ((blkno = sc->sc_blkno) == dbtofsb(bp->b_blkno)) { 4353244Swnj tc->c_size = bp->b_bcount; 4363244Swnj if ((bp->b_flags&B_READ) == 0) 4373244Swnj cmd = TS_WCOM; 4381900Swnj else 4393244Swnj cmd = TS_RCOM; 4403244Swnj if (um->um_tab.b_errcnt) 4413244Swnj cmd |= TS_RETRY; 4423244Swnj um->um_tab.b_active = SIO; 4433327Swnj tc->c_cmd = TS_ACK | TS_CVC | TS_IE | cmd; 4443244Swnj (void) ubago(ui); 4453244Swnj return; 4463244Swnj } 4473244Swnj /* 4483244Swnj * Tape positioned incorrectly; 4493244Swnj * set to seek forwards or backwards to the correct spot. 4503244Swnj * This happens for raw tapes only on error retries. 4513244Swnj */ 4523244Swnj um->um_tab.b_active = SSEEK; 4533244Swnj if (blkno < dbtofsb(bp->b_blkno)) { 4543244Swnj bp->b_command = TS_SFORW; 4553244Swnj tc->c_repcnt = dbtofsb(bp->b_blkno) - blkno; 4561900Swnj } else { 4573244Swnj bp->b_command = TS_SREV; 4583244Swnj tc->c_repcnt = blkno - dbtofsb(bp->b_blkno); 4591900Swnj } 4603244Swnj dobpcmd: 4613244Swnj /* 4623244Swnj * Do the command in bp. 4633244Swnj */ 4643327Swnj tc->c_cmd = TS_ACK | TS_CVC | TS_IE | bp->b_command; 4653244Swnj addr->tsdb = sc->sc_uba; 4661900Swnj return; 4671900Swnj 4683244Swnj next: 4693244Swnj /* 4703244Swnj * Done with this operation due to error or 4713244Swnj * the fact that it doesn't do anything. 4723244Swnj * Release UBA resources (if any), dequeue 4733244Swnj * the transfer and continue processing this slave. 4743244Swnj */ 4753244Swnj if (um->um_ubinfo) 4763244Swnj ubadone(um); 4773244Swnj um->um_tab.b_errcnt = 0; 4783327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 4791900Swnj iodone(bp); 4801900Swnj goto loop; 4811900Swnj } 4821900Swnj 4833244Swnj /* 4843244Swnj * The UNIBUS resources we needed have been 4853244Swnj * allocated to us; start the device. 4863244Swnj */ 4873244Swnj tsdgo(um) 4883244Swnj register struct uba_ctlr *um; 4891900Swnj { 490*5693Sroot register struct tsdevice *addr = (struct tsdevice *)um->um_addr; 4913244Swnj register struct ts_softc *sc = &ts_softc[um->um_ctlr]; 4923327Swnj register int i; 4933244Swnj 4943327Swnj i = um->um_ubinfo & 0777777; 4953327Swnj sc->sc_cmd.c_loba = i; 4963327Swnj sc->sc_cmd.c_hiba = (i>>16)&3; 4973244Swnj addr->tsdb = sc->sc_uba; 4983244Swnj } 4993244Swnj 5003244Swnj /* 5013244Swnj * Ts interrupt routine. 5023244Swnj */ 5033244Swnj /*ARGSUSED*/ 5043244Swnj tsintr(ts11) 5053244Swnj int ts11; 5063244Swnj { 5071900Swnj register struct buf *bp; 5083244Swnj register struct uba_ctlr *um = tsminfo[ts11]; 509*5693Sroot register struct tsdevice *addr; 5103244Swnj register struct ts_softc *sc; 5113244Swnj int tsunit; 5123244Swnj register state; 5131900Swnj 5143327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 5151900Swnj return; 5163244Swnj tsunit = TSUNIT(bp->b_dev); 517*5693Sroot addr = (struct tsdevice *)tsdinfo[tsunit]->ui_addr; 5183244Swnj /* 5193244Swnj * If last command was a rewind, and tape is still 5203244Swnj * rewinding, wait for the rewind complete interrupt. 5213244Swnj * 5223244Swnj * SHOULD NEVER GET AN INTERRUPT IN THIS STATE. 5233244Swnj */ 5243244Swnj if (um->um_tab.b_active == SREW) { 5253244Swnj um->um_tab.b_active = SCOM; 5263244Swnj if ((addr->tssr&TS_SSR) == 0) 5273244Swnj return; 5283244Swnj } 5293244Swnj /* 5303244Swnj * An operation completed... record status 5313244Swnj */ 5323244Swnj sc = &ts_softc[tsunit]; 5333244Swnj if ((bp->b_flags & B_READ) == 0) 5343244Swnj sc->sc_lastiow = 1; 5353244Swnj state = um->um_tab.b_active; 5363244Swnj um->um_tab.b_active = 0; 5373244Swnj /* 5383244Swnj * Check for errors. 5393244Swnj */ 5403244Swnj if (addr->tssr&TS_SC) { 5413244Swnj switch (addr->tssr & TS_TC) { 5423244Swnj case TS_UNREC: /* unrecoverable */ 5433244Swnj case TS_FATAL: /* fatal error */ 5443244Swnj case TS_ATTN: /* attention (shouldn't happen) */ 5453244Swnj case TS_RECNM: /* recoverable, no motion */ 5463244Swnj break; 5471900Swnj 5483244Swnj case TS_SUCC: /* success termination */ 5493244Swnj printf("ts%d: success\n", TSUNIT(minor(bp->b_dev))); 5503244Swnj goto ignoreerr; 5511900Swnj 5523244Swnj case TS_ALERT: /* tape status alert */ 5533244Swnj /* 5543244Swnj * If we hit the end of the tape file, 5553244Swnj * update our position. 5563244Swnj */ 5573244Swnj if (sc->sc_sts.s_xs0 & (TS_TMK|TS_EOT)) { 5583244Swnj tsseteof(bp); /* set blkno and nxrec */ 5593244Swnj state = SCOM; /* force completion */ 5603244Swnj /* 5613244Swnj * Stuff bc so it will be unstuffed correctly 5623244Swnj * later to get resid. 5633244Swnj */ 5643244Swnj sc->sc_sts.s_rbpcr = bp->b_bcount; 5653244Swnj goto opdone; 5663244Swnj } 5673244Swnj /* 5683244Swnj * If we were reading raw tape and the record was too long 5693244Swnj * or too short, then we don't consider this an error. 5703244Swnj */ 5713244Swnj if (bp == &rtsbuf[TSUNIT(bp->b_dev)] && (bp->b_flags&B_READ) && 5723244Swnj sc->sc_sts.s_xs0&(TS_RLS|TS_RLL)) 5733244Swnj goto ignoreerr; 5743244Swnj case TS_RECOV: /* recoverable, tape moved */ 5753244Swnj /* 5763244Swnj * If this was an i/o operation retry up to 8 times. 5773244Swnj */ 5783244Swnj if (state==SIO) { 5793244Swnj if (++um->um_tab.b_errcnt < 7) { 5803244Swnj ubadone(um); 5813244Swnj goto opcont; 5823244Swnj } else 5833244Swnj sc->sc_blkno++; 5843244Swnj } else { 5853244Swnj /* 5863244Swnj * Non-i/o errors on non-raw tape 5873244Swnj * cause it to close. 5883244Swnj */ 5893244Swnj if (sc->sc_openf>0 && bp != &rtsbuf[TSUNIT(bp->b_dev)]) 5903244Swnj sc->sc_openf = -1; 5913244Swnj } 5921900Swnj break; 5933244Swnj 5943244Swnj case TS_REJECT: /* function reject */ 5953244Swnj if (state == SIO && sc->sc_sts.s_xs0 & TS_WLE) 5963244Swnj printf("ts%d: write locked\n", TSUNIT(bp->b_dev)); 5973244Swnj if ((sc->sc_sts.s_xs0 & TS_ONL) == 0) 5983244Swnj printf("ts%d: offline\n", TSUNIT(bp->b_dev)); 5991900Swnj break; 6001900Swnj } 6013244Swnj /* 6023244Swnj * Couldn't recover error 6033244Swnj */ 6043647Swnj printf("ts%d: hard error bn%d xs0=%b", TSUNIT(bp->b_dev), 6053244Swnj bp->b_blkno, sc->sc_sts.s_xs0, TSXS0_BITS); 6063647Swnj if (sc->sc_sts.s_xs1) 6073647Swnj printf(" xs1=%b", sc->sc_sts.s_xs1, TSXS1_BITS); 6083647Swnj if (sc->sc_sts.s_xs2) 6093647Swnj printf(" xs2=%b", sc->sc_sts.s_xs2, TSXS2_BITS); 6103647Swnj if (sc->sc_sts.s_xs3) 6113647Swnj printf(" xs3=%b", sc->sc_sts.s_xs3, TSXS3_BITS); 6123647Swnj printf("\n"); 6133244Swnj bp->b_flags |= B_ERROR; 6143244Swnj goto opdone; 6153244Swnj } 6163244Swnj /* 6173244Swnj * Advance tape control FSM. 6183244Swnj */ 6193244Swnj ignoreerr: 6203244Swnj switch (state) { 6211900Swnj 6223244Swnj case SIO: 6233244Swnj /* 6243244Swnj * Read/write increments tape block number 6253244Swnj */ 6263244Swnj sc->sc_blkno++; 6273244Swnj goto opdone; 6281900Swnj 6291900Swnj case SCOM: 6303244Swnj /* 6313244Swnj * For forward/backward space record update current position. 6323244Swnj */ 6333244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) 6343244Swnj switch (bp->b_command) { 6351900Swnj 6363244Swnj case TS_SFORW: 6373244Swnj sc->sc_blkno += bp->b_repcnt; 6383244Swnj break; 6391900Swnj 6403244Swnj case TS_SREV: 6413244Swnj sc->sc_blkno -= bp->b_repcnt; 6423244Swnj break; 6433244Swnj } 6443244Swnj goto opdone; 6453244Swnj 6463244Swnj case SSEEK: 6473244Swnj sc->sc_blkno = dbtofsb(bp->b_blkno); 6483244Swnj goto opcont; 6493244Swnj 6501900Swnj default: 6513244Swnj panic("tsintr"); 6521900Swnj } 6533244Swnj opdone: 6543244Swnj /* 6553244Swnj * Reset error count and remove 6563244Swnj * from device queue. 6573244Swnj */ 6583244Swnj um->um_tab.b_errcnt = 0; 6593327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 6603244Swnj bp->b_resid = sc->sc_sts.s_rbpcr; 6613244Swnj ubadone(um); 6623244Swnj iodone(bp); 6633327Swnj if (um->um_tab.b_actf->b_actf == 0) 6643244Swnj return; 6653244Swnj opcont: 6663244Swnj tsstart(um); 6673244Swnj } 6683244Swnj 6693244Swnj tsseteof(bp) 6703244Swnj register struct buf *bp; 6713244Swnj { 6723244Swnj register int tsunit = TSUNIT(bp->b_dev); 6733244Swnj register struct ts_softc *sc = &ts_softc[tsunit]; 6743244Swnj 6753244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) { 6763244Swnj if (sc->sc_blkno > dbtofsb(bp->b_blkno)) { 6773244Swnj /* reversing */ 6783244Swnj sc->sc_nxrec = dbtofsb(bp->b_blkno) - sc->sc_sts.s_rbpcr; 6793244Swnj sc->sc_blkno = sc->sc_nxrec; 6803244Swnj } else { 6813244Swnj /* spacing forward */ 6823244Swnj sc->sc_blkno = dbtofsb(bp->b_blkno) + sc->sc_sts.s_rbpcr; 6833244Swnj sc->sc_nxrec = sc->sc_blkno - 1; 6841900Swnj } 6853244Swnj return; 6863244Swnj } 6873244Swnj /* eof on read */ 6883244Swnj sc->sc_nxrec = dbtofsb(bp->b_blkno); 6891900Swnj } 6901900Swnj 6911900Swnj tsread(dev) 6923244Swnj dev_t dev; 6931900Swnj { 6943244Swnj 6951900Swnj tsphys(dev); 6963244Swnj if (u.u_error) 6973244Swnj return; 6983244Swnj physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_READ, minphys); 6991900Swnj } 7001900Swnj 7011900Swnj tswrite(dev) 7023244Swnj dev_t dev; 7031900Swnj { 7043244Swnj 7051900Swnj tsphys(dev); 7063244Swnj if (u.u_error) 7073244Swnj return; 7083244Swnj physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_WRITE, minphys); 7091900Swnj } 7101900Swnj 7113244Swnj /* 7123244Swnj * Check that a raw device exists. 7133244Swnj * If it does, set up sc_blkno and sc_nxrec 7143244Swnj * so that the tape will appear positioned correctly. 7153244Swnj */ 7161900Swnj tsphys(dev) 7173244Swnj dev_t dev; 7181900Swnj { 7193244Swnj register int tsunit = TSUNIT(dev); 7203244Swnj register daddr_t a; 7213244Swnj register struct ts_softc *sc; 7223244Swnj register struct uba_device *ui; 7231900Swnj 7243244Swnj if (tsunit >= NTS || (ui=tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) { 7253244Swnj u.u_error = ENXIO; 7263244Swnj return; 7273244Swnj } 7283244Swnj sc = &ts_softc[tsunit]; 7293244Swnj a = dbtofsb(u.u_offset >> 9); 7303244Swnj sc->sc_blkno = a; 7313244Swnj sc->sc_nxrec = a + 1; 7321900Swnj } 7331918Swnj 7343244Swnj tsreset(uban) 7353244Swnj int uban; 7361918Swnj { 7373244Swnj register struct uba_ctlr *um; 738*5693Sroot register struct uba_device *ui; 739*5693Sroot register struct buf *dp; 7403244Swnj register ts11; 7411918Swnj 7423244Swnj for (ts11 = 0; ts11 < NTS; ts11++) { 7433244Swnj if ((um = tsminfo[ts11]) == 0 || um->um_alive == 0 || 7443244Swnj um->um_ubanum != uban) 7453244Swnj continue; 7463244Swnj printf(" ts%d", ts11); 7473244Swnj um->um_tab.b_active = 0; 7483244Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 749*5693Sroot if (ts_softc[ts11].sc_openf > 0) 750*5693Sroot ts_softc[ts11].sc_openf = -1; 7513244Swnj if (um->um_ubinfo) { 7523244Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 7533244Swnj ubadone(um); 7543244Swnj } 755*5693Sroot if ((ui = tsdinfo[ts11]) && ui->ui_mi == um && ui->ui_alive) { 756*5693Sroot dp = &tsutab[ts11]; 757*5693Sroot dp->b_active = 0; 758*5693Sroot dp->b_forw = 0; 759*5693Sroot if (um->um_tab.b_actf == NULL) 760*5693Sroot um->um_tab.b_actf = dp; 761*5693Sroot else 762*5693Sroot um->um_tab.b_actl->b_forw = dp; 763*5693Sroot um->um_tab.b_actl = dp; 764*5693Sroot } 7653989Sroot (void) tsinit(ts11); 7663244Swnj tsstart(um); 7671918Swnj } 7681918Swnj } 7691918Swnj 7703244Swnj /*ARGSUSED*/ 7713244Swnj tsioctl(dev, cmd, addr, flag) 7723244Swnj caddr_t addr; 7733244Swnj dev_t dev; 7741918Swnj { 7753244Swnj int tsunit = TSUNIT(dev); 7763244Swnj register struct ts_softc *sc = &ts_softc[tsunit]; 7773244Swnj register struct buf *bp = &ctsbuf[TSUNIT(dev)]; 7783244Swnj register callcount; 7793244Swnj int fcount; 7803244Swnj struct mtop mtop; 7813244Swnj struct mtget mtget; 7823244Swnj /* we depend of the values and order of the MT codes here */ 7833244Swnj static tsops[] = 7843656Swnj {TS_WEOF,TS_SFORWF,TS_SREVF,TS_SFORW,TS_SREV,TS_REW,TS_OFFL,TS_SENSE}; 7851918Swnj 7863244Swnj switch (cmd) { 7873244Swnj case MTIOCTOP: /* tape operation */ 7883244Swnj if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) { 7893244Swnj u.u_error = EFAULT; 7903244Swnj return; 7913244Swnj } 7923244Swnj switch(mtop.mt_op) { 7933244Swnj case MTWEOF: 7943244Swnj callcount = mtop.mt_count; 7953244Swnj fcount = 1; 7963244Swnj break; 7973244Swnj case MTFSF: case MTBSF: 7983244Swnj case MTFSR: case MTBSR: 7993244Swnj callcount = 1; 8003244Swnj fcount = mtop.mt_count; 8013244Swnj break; 8023244Swnj case MTREW: case MTOFFL: case MTNOP: 8033244Swnj callcount = 1; 8043244Swnj fcount = 1; 8053244Swnj break; 8063244Swnj default: 8073244Swnj u.u_error = ENXIO; 8083244Swnj return; 8093244Swnj } 8103244Swnj if (callcount <= 0 || fcount <= 0) { 8113244Swnj u.u_error = ENXIO; 8123244Swnj return; 8133244Swnj } 8143244Swnj while (--callcount >= 0) { 8153244Swnj tscommand(dev, tsops[mtop.mt_op], fcount); 8163244Swnj if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) && 8173244Swnj bp->b_resid) { 8183244Swnj u.u_error = EIO; 8193244Swnj break; 8203244Swnj } 8213244Swnj if ((bp->b_flags&B_ERROR) || sc->sc_sts.s_xs0&TS_BOT) 8223244Swnj break; 8233244Swnj } 8243244Swnj geterror(bp); 8253244Swnj return; 8263244Swnj case MTIOCGET: 8273244Swnj mtget.mt_dsreg = 0; 8283244Swnj mtget.mt_erreg = sc->sc_sts.s_xs0; 8293244Swnj mtget.mt_resid = sc->sc_resid; 8303480Stoy mtget.mt_type = MT_ISTS; 8313244Swnj if (copyout((caddr_t)&mtget, addr, sizeof(mtget))) 8323244Swnj u.u_error = EFAULT; 8333244Swnj return; 8343244Swnj default: 8353244Swnj u.u_error = ENXIO; 8363244Swnj } 8371918Swnj } 8381918Swnj 8393244Swnj #define DBSIZE 20 8403244Swnj 8413244Swnj tsdump() 8421918Swnj { 8433244Swnj register struct uba_device *ui; 8443244Swnj register struct uba_regs *up; 845*5693Sroot register struct tsdevice *addr; 8463244Swnj int blk, num; 8473244Swnj int start; 8481918Swnj 8493244Swnj start = 0; 8503244Swnj num = maxfree; 8513244Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 8523244Swnj if (tsdinfo[0] == 0) 8533244Swnj return (ENXIO); 8543244Swnj ui = phys(tsdinfo[0], struct uba_device *); 8553244Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 8563327Swnj ubainit(up); 8573244Swnj DELAY(1000000); 858*5693Sroot addr = (struct tsdevice *)ui->ui_physaddr; 8593244Swnj addr->tssr = 0; 8603244Swnj tswait(addr); 8613244Swnj while (num > 0) { 8623244Swnj blk = num > DBSIZE ? DBSIZE : num; 8633244Swnj tsdwrite(start, blk, addr, up); 8643244Swnj start += blk; 8653244Swnj num -= blk; 8663244Swnj } 8673244Swnj tseof(addr); 8683244Swnj tseof(addr); 8693244Swnj tswait(addr); 8703244Swnj if (addr->tssr&TS_SC) 8713244Swnj return (EIO); 8723244Swnj addr->tssr = 0; 8733244Swnj tswait(addr); 8743244Swnj return (0); 8751918Swnj } 8761918Swnj 8773244Swnj tsdwrite(dbuf, num, addr, up) 8783244Swnj register dbuf, num; 879*5693Sroot register struct tsdevice *addr; 8803244Swnj struct uba_regs *up; 8811918Swnj { 8823244Swnj register struct pte *io; 8833244Swnj register int npf; 8841918Swnj 8853244Swnj tswait(addr); 8863244Swnj io = up->uba_map; 8873244Swnj npf = num+1; 8883244Swnj while (--npf != 0) 8893244Swnj *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); 8903244Swnj *(int *)io = 0; 8913244Swnj #ifdef notyet 8923244Swnj addr->tsbc = -(num*NBPG); 8933244Swnj addr->tsba = 0; 8943244Swnj addr->tscs = TS_WCOM | TM_GO; 8953244Swnj #endif 8961918Swnj } 8971918Swnj 8983244Swnj tswait(addr) 899*5693Sroot register struct tsdevice *addr; 9001918Swnj { 9013244Swnj register s; 9021918Swnj 9033244Swnj do 9043244Swnj s = addr->tssr; 9053244Swnj while ((s & TS_SSR) == 0); 9061918Swnj } 9071918Swnj 9083244Swnj tseof(addr) 909*5693Sroot struct tsdevice *addr; 9101918Swnj { 9111918Swnj 9123244Swnj tswait(addr); 9133244Swnj #ifdef notyet 9143244Swnj addr->tscs = TS_WEOF | TM_GO; 9153244Swnj #endif 9161918Swnj } 9171900Swnj #endif 918