1*3982Sroot /* ts.c 4.17 81/07/09 */ 21900Swnj 31941Swnj #include "ts.h" 43528Swnj #include "te.h" 51900Swnj #if NTS > 0 63647Swnj #if TSDEBUG 73327Swnj #define printd if(tsdebug)printf 83327Swnj int tsdebug; 93647Swnj #endif 101900Swnj /* 111900Swnj * TS11 tape driver 123244Swnj * 133244Swnj * TODO: 143244Swnj * test driver with more than one controller 153244Swnj * test reset code 163244Swnj * test dump code 173244Swnj * test rewinds without hanging in driver 183244Swnj * what happens if you offline tape during rewind? 193244Swnj * test using file system on tape 201900Swnj */ 211900Swnj #include "../h/param.h" 221900Swnj #include "../h/systm.h" 231900Swnj #include "../h/buf.h" 243244Swnj #include "../h/dir.h" 251900Swnj #include "../h/conf.h" 263244Swnj #include "../h/user.h" 271900Swnj #include "../h/file.h" 283244Swnj #include "../h/map.h" 291900Swnj #include "../h/pte.h" 301947Swnj #include "../h/vm.h" 313244Swnj #include "../h/ubareg.h" 323244Swnj #include "../h/ubavar.h" 333244Swnj #include "../h/mtio.h" 343244Swnj #include "../h/ioctl.h" 353244Swnj #include "../h/cmap.h" 363244Swnj #include "../h/cpu.h" 371900Swnj 383244Swnj #include "../h/tsreg.h" 391900Swnj 403244Swnj /* 413244Swnj * There is a ctsbuf per tape controller. 423244Swnj * It is used as the token to pass to the internal routines 433244Swnj * to execute tape ioctls. 443244Swnj * In particular, when the tape is rewinding on close we release 453244Swnj * the user process but any further attempts to use the tape drive 463244Swnj * before the rewind completes will hang waiting for ctsbuf. 473244Swnj */ 483244Swnj struct buf ctsbuf[NTS]; 491900Swnj 503244Swnj /* 513244Swnj * Raw tape operations use rtsbuf. The driver 523244Swnj * notices when rtsbuf is being used and allows the user 533244Swnj * program to continue after errors and read records 543244Swnj * not of the standard length (BSIZE). 553244Swnj */ 563244Swnj struct buf rtsbuf[NTS]; 571900Swnj 583244Swnj /* 593244Swnj * Driver unibus interface routines and variables. 603244Swnj */ 613244Swnj int tsprobe(), tsslave(), tsattach(), tsdgo(), tsintr(); 623244Swnj struct uba_ctlr *tsminfo[NTS]; 633244Swnj struct uba_device *tsdinfo[NTS]; 643327Swnj struct buf tsbuf[NTS]; 653244Swnj u_short tsstd[] = { 0772520, 0 }; 663244Swnj /*** PROBABLY DON'T NEED ALL THESE SINCE CONTROLLER == DRIVE ***/ 673244Swnj struct uba_driver zsdriver = 683327Swnj { tsprobe, tsslave, tsattach, tsdgo, tsstd, "ts", tsdinfo, "zs", tsminfo, 0 }; 691900Swnj 703244Swnj /* bits in minor device */ 713244Swnj #define TSUNIT(dev) (minor(dev)&03) 723244Swnj #define T_NOREWIND 04 731900Swnj 743244Swnj #define INF (daddr_t)1000000L 751900Swnj 763244Swnj /* 773244Swnj * Software state per tape transport. 783244Swnj * Also contains hardware state in message packets. 793244Swnj * 803244Swnj * 1. A tape drive is a unique-open device; we refuse opens when it is already. 813244Swnj * 2. We keep track of the current position on a block tape and seek 823244Swnj * before operations by forward/back spacing if necessary. 833244Swnj * 3. We remember if the last operation was a write on a tape, so if a tape 843244Swnj * is open read write and the last thing done is a write we can 853244Swnj * write a standard end of tape mark (two eofs). 863244Swnj * 4. We remember the status registers after the last command, using 873244Swnj * then internally and returning them to the SENSE ioctl. 883244Swnj */ 893244Swnj struct ts_softc { 903244Swnj char sc_openf; /* lock against multiple opens */ 913244Swnj char sc_lastiow; /* last op was a write */ 923327Swnj short sc_resid; /* copy of last bc */ 933244Swnj daddr_t sc_blkno; /* block number, for block device tape */ 943244Swnj daddr_t sc_nxrec; /* position of end of tape, if known */ 953244Swnj struct ts_cmd sc_cmd; /* the command packet - ADDR MUST BE 0 MOD 4 */ 963244Swnj struct ts_sts sc_sts; /* status packet, for returned status */ 973244Swnj struct ts_char sc_char; /* characteristics packet */ 983244Swnj u_short sc_uba; /* Unibus addr of cmd pkt for tsdb */ 993244Swnj } ts_softc[NTS]; 1001900Swnj 1013244Swnj struct ts_softc *ts_ubaddr; /* Unibus address of ts_softc */ 1021900Swnj 1033244Swnj /* 1043244Swnj * States for um->um_tab.b_active, the per controller state flag. 1053244Swnj * This is used to sequence control in the driver. 1063244Swnj */ 1073244Swnj #define SSEEK 1 /* seeking */ 1083244Swnj #define SIO 2 /* doing seq i/o */ 1093244Swnj #define SCOM 3 /* sending control command */ 1103244Swnj #define SREW 4 /* sending a drive rewind */ 1111900Swnj 1123520Sroot #if NTM > 0 1133520Sroot /* kludge... see tm.c */ 1143520Sroot extern havetm; 1153520Sroot #endif 1163244Swnj /* 1173244Swnj * Determine if there is a controller for 1183244Swnj * a ts at address reg. Our goal is to make the 1193244Swnj * device interrupt. 1203244Swnj */ 1213244Swnj tsprobe(reg) 1223244Swnj caddr_t reg; 1233244Swnj { 1243244Swnj register int br, cvec; /* must be r11,r10; value-result */ 1251900Swnj 1263244Swnj #ifdef lint 1273244Swnj br = 0; cvec = br; br = cvec; 1283244Swnj #endif 1293244Swnj /****************/ 1303244Swnj /* */ 1313244Swnj /* K L U D G E */ 1323244Swnj /* */ 1333244Swnj /****************/ 1341900Swnj 1353520Sroot #if NTM > 0 1363520Sroot if (havetm) 1373520Sroot return (0); 1383520Sroot #endif 1393244Swnj /* IT'S TOO HARD TO MAKE THIS THING INTERRUPT 1403244Swnj JUST TO FIND ITS VECTOR */ 1413244Swnj cvec = 0224; 1423244Swnj br = 0x15; 143*3982Sroot return (1); 1443244Swnj } 1451900Swnj 1463244Swnj /* 1473244Swnj * TS11 only supports one drive per controller; 1483244Swnj * check for ui_slave == 0. 1493244Swnj * 1503244Swnj * DO WE REALLY NEED THIS ROUTINE??? 1513244Swnj */ 1523244Swnj /*ARGSUSED*/ 1533244Swnj tsslave(ui, reg) 1543244Swnj struct uba_device *ui; 1553244Swnj caddr_t reg; 1563244Swnj { 1571900Swnj 1583244Swnj if (ui->ui_slave) /* non-zero slave not allowed */ 1593244Swnj return(0); 1603244Swnj return (1); 1613244Swnj } 1621900Swnj 1633244Swnj /* 1643244Swnj * Record attachment of the unit to the controller. 1653244Swnj * 1663244Swnj * SHOULD THIS ROUTINE DO ANYTHING??? 1673244Swnj */ 1683244Swnj /*ARGSUSED*/ 1693244Swnj tsattach(ui) 1703244Swnj struct uba_device *ui; 1713244Swnj { 1721900Swnj 1733244Swnj } 1741900Swnj 1753244Swnj /* 1763244Swnj * Open the device. Tapes are unique open 1773244Swnj * devices, so we refuse if it is already open. 1783244Swnj * We also check that a tape is available, and 1793244Swnj * don't block waiting here; if you want to wait 1803244Swnj * for a tape you should timeout in user code. 1813244Swnj */ 1821900Swnj tsopen(dev, flag) 1833244Swnj dev_t dev; 1843244Swnj int flag; 1851900Swnj { 1863244Swnj register int tsunit; 1873244Swnj register struct uba_device *ui; 1883244Swnj register struct ts_softc *sc; 1891900Swnj 1903244Swnj tsunit = TSUNIT(dev); 1913244Swnj if (tsunit>=NTS || (sc = &ts_softc[tsunit])->sc_openf || 1923244Swnj (ui = tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) { 1931900Swnj u.u_error = ENXIO; 1941900Swnj return; 1951900Swnj } 1963244Swnj if (tsinit(tsunit)) { 1971900Swnj u.u_error = ENXIO; 1983647Swnj #ifdef TSDEBUG 1993327Swnj printd("init failed\n"); 2003647Swnj #endif 2011900Swnj return; 2021900Swnj } 2033647Swnj #ifdef TSDEBUG 2043327Swnj printd("init ok\n"); 2053647Swnj #endif 2063244Swnj tscommand(dev, TS_SENSE, 1); 2073647Swnj #ifdef TSDEBUG 2083327Swnj printd("sense xs0 %o\n", sc->sc_sts.s_xs0); 2093647Swnj #endif 2103711Sroot if ((sc->sc_sts.s_xs0&TS_ONL) == 0) { 2113711Sroot uprintf("ts%d: not online\n", tsunit); 2123244Swnj u.u_error = EIO; 2133244Swnj return; 2141900Swnj } 2153718Sroot if ((flag&(FREAD|FWRITE)) == FWRITE && (sc->sc_sts.s_xs0&TS_WLK)) { 2163711Sroot uprintf("ts%d: no write ring\n", tsunit); 2173711Sroot u.u_error = EIO; 2183711Sroot return; 2193711Sroot } 2203244Swnj sc->sc_openf = 1; 2213244Swnj sc->sc_blkno = (daddr_t)0; 2223244Swnj sc->sc_nxrec = INF; 2233244Swnj sc->sc_lastiow = 0; 2241900Swnj } 2251900Swnj 2263244Swnj /* 2273244Swnj * Close tape device. 2283244Swnj * 2293244Swnj * If tape was open for writing or last operation was 2303244Swnj * a write, then write two EOF's and backspace over the last one. 2313244Swnj * Unless this is a non-rewinding special file, rewind the tape. 2323244Swnj * Make the tape available to others. 2333244Swnj */ 2341900Swnj tsclose(dev, flag) 2353244Swnj register dev_t dev; 2363244Swnj register flag; 2371900Swnj { 2383244Swnj register struct ts_softc *sc = &ts_softc[TSUNIT(dev)]; 2391900Swnj 2403244Swnj if (flag == FWRITE || (flag&FWRITE) && sc->sc_lastiow) { 2413244Swnj tscommand(dev, TS_WEOF, 1); 2423244Swnj tscommand(dev, TS_WEOF, 1); 2433244Swnj tscommand(dev, TS_SREV, 1); 2441900Swnj } 2453244Swnj if ((minor(dev)&T_NOREWIND) == 0) 2463244Swnj /* 2473244Swnj * 0 count means don't hang waiting for rewind complete 2483244Swnj * rather ctsbuf stays busy until the operation completes 2493244Swnj * preventing further opens from completing by 2503244Swnj * preventing a TS_SENSE from completing. 2513244Swnj */ 2523244Swnj tscommand(dev, TS_REW, 0); 2533244Swnj sc->sc_openf = 0; 2541900Swnj } 2551900Swnj 2563244Swnj /* 2573244Swnj * Initialize the TS11. Set up Unibus mapping for command 2583244Swnj * packets and set device characteristics. 2593244Swnj */ 2603244Swnj tsinit(unit) 2613244Swnj register int unit; 2621900Swnj { 2633244Swnj register struct ts_softc *sc = &ts_softc[unit]; 2643244Swnj register struct uba_ctlr *um = tsminfo[unit]; 2653244Swnj register struct device *addr = (struct device *)um->um_addr; 2663244Swnj register int i; 2673244Swnj 2683244Swnj /* 2693244Swnj * Map the command and message packets into Unibus 2703244Swnj * address space. We do all the command and message 2713244Swnj * packets at once to minimize the amount of Unibus 2723244Swnj * mapping necessary. 2733244Swnj */ 2743244Swnj if (ts_ubaddr == 0) { 2753244Swnj ctsbuf[unit].b_un.b_addr = (caddr_t)ts_softc; 2763244Swnj ctsbuf[unit].b_bcount = sizeof(ts_softc); 2773244Swnj i = ubasetup(um->um_ubanum, &ctsbuf[unit], 0); 2783244Swnj i &= 0777777; 2793244Swnj ts_ubaddr = (struct ts_softc *)i; 2803244Swnj /* MAKE SURE WE DON'T GET UNIBUS ADDRESS ZERO */ 2813244Swnj if (ts_ubaddr == 0) 2823244Swnj printf("ts%d: zero ubaddr\n", unit); 2833244Swnj } 2843244Swnj /* 2853244Swnj * Now initialize the TS11 controller. 2863244Swnj * Set the characteristics. 2873244Swnj */ 2883668Swnj if (addr->tssr & (TS_NBA|TS_OFL)) { 2893244Swnj addr->tssr = 0; /* subsystem initialize */ 2903244Swnj tswait(addr); 2913244Swnj i = (int)&ts_ubaddr[unit].sc_cmd; /* Unibus addr of cmd */ 2923327Swnj if (i&3) { 2933327Swnj printf("addr mod 4 != 0\n"); 2943327Swnj return(1); 2953327Swnj } 2963244Swnj sc->sc_uba = (u_short)(i + ((i>>16)&3)); 2973244Swnj sc->sc_char.char_addr = (int)&ts_ubaddr[unit].sc_sts; 2983244Swnj sc->sc_char.char_size = sizeof(struct ts_sts); 2993244Swnj sc->sc_char.char_mode = TS_ESS; 3003244Swnj sc->sc_cmd.c_cmd = TS_ACK | TS_SETCHR; 3013327Swnj i = (int)&ts_ubaddr[unit].sc_char; 3023327Swnj sc->sc_cmd.c_loba = i; 3033327Swnj sc->sc_cmd.c_hiba = (i>>16)&3; 3043244Swnj sc->sc_cmd.c_size = sizeof(struct ts_char); 3053244Swnj addr->tsdb = sc->sc_uba; 3063244Swnj tswait(addr); 3073327Swnj /* 3083327Swnj printd("%o %o %o %o %o %o %o %o\n", addr->tssr, sc->sc_sts.s_sts, sc->sc_sts.s_len, sc->sc_sts.s_rbpcr, sc->sc_sts.s_xs0, sc->sc_sts.s_xs1,sc->sc_sts.s_xs1,sc->sc_sts.s_xs2,sc->sc_sts.s_xs3); 3093327Swnj */ 3103327Swnj if (addr->tssr & TS_NBA) 3113327Swnj return(1); 3123244Swnj } 3133244Swnj return(0); 3143244Swnj } 3153244Swnj 3163244Swnj /* 3173244Swnj * Execute a command on the tape drive 3183244Swnj * a specified number of times. 3193244Swnj */ 3203244Swnj tscommand(dev, com, count) 3213244Swnj dev_t dev; 3223244Swnj int com, count; 3233244Swnj { 3241900Swnj register struct buf *bp; 3251900Swnj 3263244Swnj bp = &ctsbuf[TSUNIT(dev)]; 3273244Swnj (void) spl5(); 3283244Swnj while (bp->b_flags&B_BUSY) { 3293244Swnj /* 3303244Swnj * This special check is because B_BUSY never 3313244Swnj * gets cleared in the non-waiting rewind case. 3323244Swnj */ 3333244Swnj if (bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 3343244Swnj break; 3351900Swnj bp->b_flags |= B_WANTED; 3361900Swnj sleep((caddr_t)bp, PRIBIO); 3371900Swnj } 3383244Swnj bp->b_flags = B_BUSY|B_READ; 3393244Swnj (void) spl0(); 3403647Swnj #ifdef TSDEBUG 3413327Swnj printd("command %o dev %x count %d\n", com, dev, count); 3423647Swnj #endif 3433244Swnj bp->b_dev = dev; 3443244Swnj bp->b_repcnt = count; 3453244Swnj bp->b_command = com; 3461900Swnj bp->b_blkno = 0; 3471900Swnj tsstrategy(bp); 3483244Swnj /* 3493244Swnj * In case of rewind from close, don't wait. 3503244Swnj * This is the only case where count can be 0. 3513244Swnj */ 3523244Swnj if (count == 0) 3533244Swnj return; 3541900Swnj iowait(bp); 3553244Swnj if (bp->b_flags&B_WANTED) 3561900Swnj wakeup((caddr_t)bp); 3573244Swnj bp->b_flags &= B_ERROR; 3581900Swnj } 3591900Swnj 3603244Swnj /* 3613244Swnj * Queue a tape operation. 3623244Swnj */ 3631900Swnj tsstrategy(bp) 3643244Swnj register struct buf *bp; 3651900Swnj { 3663244Swnj int tsunit = TSUNIT(bp->b_dev); 3673244Swnj register struct uba_ctlr *um; 3683327Swnj register struct buf *dp; 3691900Swnj 3703244Swnj /* 3713244Swnj * Put transfer at end of controller queue 3723244Swnj */ 3731900Swnj bp->av_forw = NULL; 3743244Swnj um = tsdinfo[tsunit]->ui_mi; 3753327Swnj dp = &tsbuf[tsunit]; 3763244Swnj (void) spl5(); 3773327Swnj if (dp->b_actf == NULL) 3783327Swnj dp->b_actf = bp; 3791900Swnj else 3803327Swnj dp->b_actl->av_forw = bp; 3813327Swnj dp->b_actl = bp; 3823327Swnj um->um_tab.b_actf = um->um_tab.b_actl = dp; 3833244Swnj /* 3843244Swnj * If the controller is not busy, get 3853244Swnj * it going. 3863244Swnj */ 3873244Swnj if (um->um_tab.b_active == 0) 3883244Swnj tsstart(um); 3893244Swnj (void) spl0(); 3901900Swnj } 3911900Swnj 3923244Swnj /* 3933244Swnj * Start activity on a ts controller. 3943244Swnj */ 3953244Swnj tsstart(um) 3963244Swnj register struct uba_ctlr *um; 3971900Swnj { 3981900Swnj register struct buf *bp; 3993244Swnj register struct device *addr = (struct device *)um->um_addr; 4003244Swnj register struct ts_softc *sc; 4013244Swnj register struct ts_cmd *tc; 4023244Swnj register struct uba_device *ui; 4033244Swnj int tsunit, cmd; 4041900Swnj daddr_t blkno; 4051900Swnj 4063244Swnj /* 4073244Swnj * Start the controller if there is something for it to do. 4083244Swnj */ 4093244Swnj loop: 4103327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 4111900Swnj return; 4123244Swnj tsunit = TSUNIT(bp->b_dev); 4133244Swnj ui = tsdinfo[tsunit]; 4143244Swnj sc = &ts_softc[tsunit]; 4153244Swnj tc = &sc->sc_cmd; 4163244Swnj /* 4173244Swnj * Default is that last command was NOT a write command; 4183244Swnj * if we do a write command we will notice this in tsintr(). 4193244Swnj */ 4203656Swnj sc->sc_lastiow = 0; 4213244Swnj if (sc->sc_openf < 0 || (addr->tssr&TS_OFL)) { 4223244Swnj /* 4233244Swnj * Have had a hard error on a non-raw tape 4243244Swnj * or the tape unit is now unavailable 4253244Swnj * (e.g. taken off line). 4263244Swnj */ 4273244Swnj bp->b_flags |= B_ERROR; 4283244Swnj goto next; 4293244Swnj } 4303244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) { 4313244Swnj /* 4323244Swnj * Execute control operation with the specified count. 4333244Swnj */ 4343244Swnj um->um_tab.b_active = 4353244Swnj bp->b_command == TS_REW ? SREW : SCOM; 4363244Swnj tc->c_repcnt = bp->b_repcnt; 4373647Swnj #ifdef TSDEBUG 4383327Swnj printd("strat: do cmd\n"); 4393647Swnj #endif 4403244Swnj goto dobpcmd; 4413244Swnj } 4423244Swnj /* 4433244Swnj * The following checks handle boundary cases for operation 4443244Swnj * on non-raw tapes. On raw tapes the initialization of 4453244Swnj * sc->sc_nxrec by tsphys causes them to be skipped normally 4463244Swnj * (except in the case of retries). 4473244Swnj */ 4483244Swnj if (dbtofsb(bp->b_blkno) > sc->sc_nxrec) { 4493244Swnj /* 4503244Swnj * Can't read past known end-of-file. 4513244Swnj */ 4523244Swnj bp->b_flags |= B_ERROR; 4533244Swnj bp->b_error = ENXIO; 4543244Swnj goto next; 4553244Swnj } 4563244Swnj if (dbtofsb(bp->b_blkno) == sc->sc_nxrec && 4573244Swnj bp->b_flags&B_READ) { 4583244Swnj /* 4593244Swnj * Reading at end of file returns 0 bytes. 4603244Swnj */ 4613244Swnj bp->b_resid = bp->b_bcount; 4623244Swnj clrbuf(bp); 4633244Swnj goto next; 4643244Swnj } 4653244Swnj if ((bp->b_flags&B_READ) == 0) 4663244Swnj /* 4673244Swnj * Writing sets EOF 4683244Swnj */ 4693244Swnj sc->sc_nxrec = dbtofsb(bp->b_blkno) + 1; 4703244Swnj /* 4713244Swnj * If the data transfer command is in the correct place, 4723244Swnj * set up all the registers except the csr, and give 4733244Swnj * control over to the UNIBUS adapter routines, to 4743244Swnj * wait for resources to start the i/o. 4753244Swnj */ 4763244Swnj if ((blkno = sc->sc_blkno) == dbtofsb(bp->b_blkno)) { 4773244Swnj tc->c_size = bp->b_bcount; 4783244Swnj if ((bp->b_flags&B_READ) == 0) 4793244Swnj cmd = TS_WCOM; 4801900Swnj else 4813244Swnj cmd = TS_RCOM; 4823244Swnj if (um->um_tab.b_errcnt) 4833244Swnj cmd |= TS_RETRY; 4843244Swnj um->um_tab.b_active = SIO; 4853327Swnj tc->c_cmd = TS_ACK | TS_CVC | TS_IE | cmd; 4863647Swnj #ifdef TSDEBUG 4873327Swnj printd("r/w %o size %d\n", tc->c_cmd, tc->c_size); 4883647Swnj #endif 4893244Swnj (void) ubago(ui); 4903244Swnj return; 4913244Swnj } 4923244Swnj /* 4933244Swnj * Tape positioned incorrectly; 4943244Swnj * set to seek forwards or backwards to the correct spot. 4953244Swnj * This happens for raw tapes only on error retries. 4963244Swnj */ 4973244Swnj um->um_tab.b_active = SSEEK; 4983647Swnj #ifdef TSDEBUG 4993327Swnj printd("seek blkno %d b_blkno %d\n", blkno, bp->b_blkno); 5003647Swnj #endif 5013244Swnj if (blkno < dbtofsb(bp->b_blkno)) { 5023244Swnj bp->b_command = TS_SFORW; 5033244Swnj tc->c_repcnt = dbtofsb(bp->b_blkno) - blkno; 5041900Swnj } else { 5053244Swnj bp->b_command = TS_SREV; 5063244Swnj tc->c_repcnt = blkno - dbtofsb(bp->b_blkno); 5071900Swnj } 5083244Swnj dobpcmd: 5093244Swnj /* 5103244Swnj * Do the command in bp. 5113244Swnj */ 5123327Swnj tc->c_cmd = TS_ACK | TS_CVC | TS_IE | bp->b_command; 5133244Swnj addr->tsdb = sc->sc_uba; 5141900Swnj return; 5151900Swnj 5163244Swnj next: 5173244Swnj /* 5183244Swnj * Done with this operation due to error or 5193244Swnj * the fact that it doesn't do anything. 5203244Swnj * Release UBA resources (if any), dequeue 5213244Swnj * the transfer and continue processing this slave. 5223244Swnj */ 5233244Swnj if (um->um_ubinfo) 5243244Swnj ubadone(um); 5253244Swnj um->um_tab.b_errcnt = 0; 5263327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 5271900Swnj iodone(bp); 5281900Swnj goto loop; 5291900Swnj } 5301900Swnj 5313244Swnj /* 5323244Swnj * The UNIBUS resources we needed have been 5333244Swnj * allocated to us; start the device. 5343244Swnj */ 5353244Swnj tsdgo(um) 5363244Swnj register struct uba_ctlr *um; 5371900Swnj { 5383244Swnj register struct device *addr = (struct device *)um->um_addr; 5393244Swnj register struct ts_softc *sc = &ts_softc[um->um_ctlr]; 5403327Swnj register int i; 5413244Swnj 5423327Swnj i = um->um_ubinfo & 0777777; 5433647Swnj #ifdef TSDEBUG 5443327Swnj printd("dgo addr %o\n", i); 5453647Swnj #endif 5463327Swnj sc->sc_cmd.c_loba = i; 5473327Swnj sc->sc_cmd.c_hiba = (i>>16)&3; 5483244Swnj addr->tsdb = sc->sc_uba; 5493244Swnj } 5503244Swnj 5513244Swnj /* 5523244Swnj * Ts interrupt routine. 5533244Swnj */ 5543244Swnj /*ARGSUSED*/ 5553244Swnj tsintr(ts11) 5563244Swnj int ts11; 5573244Swnj { 5581900Swnj register struct buf *bp; 5593244Swnj register struct uba_ctlr *um = tsminfo[ts11]; 5603244Swnj register struct device *addr; 5613244Swnj register struct ts_softc *sc; 5623244Swnj int tsunit; 5633244Swnj register state; 5641900Swnj 5653647Swnj #ifdef TSDEBUG 5663327Swnj printd("intr\n"); 5673647Swnj #endif 5683327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 5691900Swnj return; 5703244Swnj tsunit = TSUNIT(bp->b_dev); 5713244Swnj addr = (struct device *)tsdinfo[tsunit]->ui_addr; 5723244Swnj /* 5733244Swnj * If last command was a rewind, and tape is still 5743244Swnj * rewinding, wait for the rewind complete interrupt. 5753244Swnj * 5763244Swnj * SHOULD NEVER GET AN INTERRUPT IN THIS STATE. 5773244Swnj */ 5783244Swnj if (um->um_tab.b_active == SREW) { 5793244Swnj um->um_tab.b_active = SCOM; 5803244Swnj if ((addr->tssr&TS_SSR) == 0) 5813244Swnj return; 5823244Swnj } 5833244Swnj /* 5843244Swnj * An operation completed... record status 5853244Swnj */ 5863647Swnj #ifdef TSDEBUG 5873327Swnj printd(" ok1\n"); 5883647Swnj #endif 5893244Swnj sc = &ts_softc[tsunit]; 5903244Swnj if ((bp->b_flags & B_READ) == 0) 5913244Swnj sc->sc_lastiow = 1; 5923244Swnj state = um->um_tab.b_active; 5933244Swnj um->um_tab.b_active = 0; 5943244Swnj /* 5953244Swnj * Check for errors. 5963244Swnj */ 5973244Swnj if (addr->tssr&TS_SC) { 5983244Swnj switch (addr->tssr & TS_TC) { 5993244Swnj case TS_UNREC: /* unrecoverable */ 6003244Swnj case TS_FATAL: /* fatal error */ 6013244Swnj case TS_ATTN: /* attention (shouldn't happen) */ 6023244Swnj case TS_RECNM: /* recoverable, no motion */ 6033244Swnj break; 6041900Swnj 6053244Swnj case TS_SUCC: /* success termination */ 6063244Swnj printf("ts%d: success\n", TSUNIT(minor(bp->b_dev))); 6073244Swnj goto ignoreerr; 6081900Swnj 6093244Swnj case TS_ALERT: /* tape status alert */ 6103244Swnj /* 6113244Swnj * If we hit the end of the tape file, 6123244Swnj * update our position. 6133244Swnj */ 6143244Swnj if (sc->sc_sts.s_xs0 & (TS_TMK|TS_EOT)) { 6153244Swnj tsseteof(bp); /* set blkno and nxrec */ 6163244Swnj state = SCOM; /* force completion */ 6173244Swnj /* 6183244Swnj * Stuff bc so it will be unstuffed correctly 6193244Swnj * later to get resid. 6203244Swnj */ 6213244Swnj sc->sc_sts.s_rbpcr = bp->b_bcount; 6223244Swnj goto opdone; 6233244Swnj } 6243244Swnj /* 6253244Swnj * If we were reading raw tape and the record was too long 6263244Swnj * or too short, then we don't consider this an error. 6273244Swnj */ 6283244Swnj if (bp == &rtsbuf[TSUNIT(bp->b_dev)] && (bp->b_flags&B_READ) && 6293244Swnj sc->sc_sts.s_xs0&(TS_RLS|TS_RLL)) 6303244Swnj goto ignoreerr; 6313244Swnj case TS_RECOV: /* recoverable, tape moved */ 6323244Swnj /* 6333244Swnj * If this was an i/o operation retry up to 8 times. 6343244Swnj */ 6353244Swnj if (state==SIO) { 6363244Swnj if (++um->um_tab.b_errcnt < 7) { 6373244Swnj ubadone(um); 6383244Swnj goto opcont; 6393244Swnj } else 6403244Swnj sc->sc_blkno++; 6413244Swnj } else { 6423244Swnj /* 6433244Swnj * Non-i/o errors on non-raw tape 6443244Swnj * cause it to close. 6453244Swnj */ 6463244Swnj if (sc->sc_openf>0 && bp != &rtsbuf[TSUNIT(bp->b_dev)]) 6473244Swnj sc->sc_openf = -1; 6483244Swnj } 6491900Swnj break; 6503244Swnj 6513244Swnj case TS_REJECT: /* function reject */ 6523244Swnj if (state == SIO && sc->sc_sts.s_xs0 & TS_WLE) 6533244Swnj printf("ts%d: write locked\n", TSUNIT(bp->b_dev)); 6543244Swnj if ((sc->sc_sts.s_xs0 & TS_ONL) == 0) 6553244Swnj printf("ts%d: offline\n", TSUNIT(bp->b_dev)); 6561900Swnj break; 6571900Swnj } 6583244Swnj /* 6593244Swnj * Couldn't recover error 6603244Swnj */ 6613647Swnj printf("ts%d: hard error bn%d xs0=%b", TSUNIT(bp->b_dev), 6623244Swnj bp->b_blkno, sc->sc_sts.s_xs0, TSXS0_BITS); 6633647Swnj if (sc->sc_sts.s_xs1) 6643647Swnj printf(" xs1=%b", sc->sc_sts.s_xs1, TSXS1_BITS); 6653647Swnj if (sc->sc_sts.s_xs2) 6663647Swnj printf(" xs2=%b", sc->sc_sts.s_xs2, TSXS2_BITS); 6673647Swnj if (sc->sc_sts.s_xs3) 6683647Swnj printf(" xs3=%b", sc->sc_sts.s_xs3, TSXS3_BITS); 6693647Swnj printf("\n"); 6703244Swnj bp->b_flags |= B_ERROR; 6713244Swnj goto opdone; 6723244Swnj } 6733244Swnj /* 6743244Swnj * Advance tape control FSM. 6753244Swnj */ 6763244Swnj ignoreerr: 6773244Swnj switch (state) { 6781900Swnj 6793244Swnj case SIO: 6803244Swnj /* 6813244Swnj * Read/write increments tape block number 6823244Swnj */ 6833244Swnj sc->sc_blkno++; 6843244Swnj goto opdone; 6851900Swnj 6861900Swnj case SCOM: 6873244Swnj /* 6883244Swnj * For forward/backward space record update current position. 6893244Swnj */ 6903244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) 6913244Swnj switch (bp->b_command) { 6921900Swnj 6933244Swnj case TS_SFORW: 6943244Swnj sc->sc_blkno += bp->b_repcnt; 6953244Swnj break; 6961900Swnj 6973244Swnj case TS_SREV: 6983244Swnj sc->sc_blkno -= bp->b_repcnt; 6993244Swnj break; 7003244Swnj } 7013244Swnj goto opdone; 7023244Swnj 7033244Swnj case SSEEK: 7043244Swnj sc->sc_blkno = dbtofsb(bp->b_blkno); 7053244Swnj goto opcont; 7063244Swnj 7071900Swnj default: 7083244Swnj panic("tsintr"); 7091900Swnj } 7103244Swnj opdone: 7113244Swnj /* 7123244Swnj * Reset error count and remove 7133244Swnj * from device queue. 7143244Swnj */ 7153244Swnj um->um_tab.b_errcnt = 0; 7163327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 7173244Swnj bp->b_resid = sc->sc_sts.s_rbpcr; 7183244Swnj ubadone(um); 7193647Swnj #ifdef TSDEBUG 7203327Swnj printd(" iodone\n"); 7213647Swnj #endif 7223244Swnj iodone(bp); 7233327Swnj if (um->um_tab.b_actf->b_actf == 0) 7243244Swnj return; 7253244Swnj opcont: 7263244Swnj tsstart(um); 7273244Swnj } 7283244Swnj 7293244Swnj tsseteof(bp) 7303244Swnj register struct buf *bp; 7313244Swnj { 7323244Swnj register int tsunit = TSUNIT(bp->b_dev); 7333244Swnj register struct ts_softc *sc = &ts_softc[tsunit]; 7343244Swnj 7353244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) { 7363244Swnj if (sc->sc_blkno > dbtofsb(bp->b_blkno)) { 7373244Swnj /* reversing */ 7383244Swnj sc->sc_nxrec = dbtofsb(bp->b_blkno) - sc->sc_sts.s_rbpcr; 7393244Swnj sc->sc_blkno = sc->sc_nxrec; 7403244Swnj } else { 7413244Swnj /* spacing forward */ 7423244Swnj sc->sc_blkno = dbtofsb(bp->b_blkno) + sc->sc_sts.s_rbpcr; 7433244Swnj sc->sc_nxrec = sc->sc_blkno - 1; 7441900Swnj } 7453244Swnj return; 7463244Swnj } 7473244Swnj /* eof on read */ 7483244Swnj sc->sc_nxrec = dbtofsb(bp->b_blkno); 7491900Swnj } 7501900Swnj 7511900Swnj tsread(dev) 7523244Swnj dev_t dev; 7531900Swnj { 7543244Swnj 7551900Swnj tsphys(dev); 7563244Swnj if (u.u_error) 7573244Swnj return; 7583244Swnj physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_READ, minphys); 7591900Swnj } 7601900Swnj 7611900Swnj tswrite(dev) 7623244Swnj dev_t dev; 7631900Swnj { 7643244Swnj 7651900Swnj tsphys(dev); 7663244Swnj if (u.u_error) 7673244Swnj return; 7683244Swnj physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_WRITE, minphys); 7691900Swnj } 7701900Swnj 7713244Swnj /* 7723244Swnj * Check that a raw device exists. 7733244Swnj * If it does, set up sc_blkno and sc_nxrec 7743244Swnj * so that the tape will appear positioned correctly. 7753244Swnj */ 7761900Swnj tsphys(dev) 7773244Swnj dev_t dev; 7781900Swnj { 7793244Swnj register int tsunit = TSUNIT(dev); 7803244Swnj register daddr_t a; 7813244Swnj register struct ts_softc *sc; 7823244Swnj register struct uba_device *ui; 7831900Swnj 7843244Swnj if (tsunit >= NTS || (ui=tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) { 7853244Swnj u.u_error = ENXIO; 7863244Swnj return; 7873244Swnj } 7883244Swnj sc = &ts_softc[tsunit]; 7893244Swnj a = dbtofsb(u.u_offset >> 9); 7903244Swnj sc->sc_blkno = a; 7913244Swnj sc->sc_nxrec = a + 1; 7921900Swnj } 7931918Swnj 7943244Swnj tsreset(uban) 7953244Swnj int uban; 7961918Swnj { 7973244Swnj register struct uba_ctlr *um; 7983244Swnj register ts11; 7993244Swnj register struct buf *dp; 8001918Swnj 8013244Swnj for (ts11 = 0; ts11 < NTS; ts11++) { 8023244Swnj if ((um = tsminfo[ts11]) == 0 || um->um_alive == 0 || 8033244Swnj um->um_ubanum != uban) 8043244Swnj continue; 8053244Swnj printf(" ts%d", ts11); 8063244Swnj um->um_tab.b_active = 0; 8073244Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 8083244Swnj ts_softc[ts11].sc_openf = -1; 8093244Swnj if (um->um_ubinfo) { 8103244Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 8113244Swnj ubadone(um); 8123244Swnj } 8133244Swnj tsinit(ts11); 8143244Swnj tsstart(um); 8151918Swnj } 8161918Swnj } 8171918Swnj 8183244Swnj /*ARGSUSED*/ 8193244Swnj tsioctl(dev, cmd, addr, flag) 8203244Swnj caddr_t addr; 8213244Swnj dev_t dev; 8221918Swnj { 8233244Swnj int tsunit = TSUNIT(dev); 8243244Swnj register struct ts_softc *sc = &ts_softc[tsunit]; 8253244Swnj register struct buf *bp = &ctsbuf[TSUNIT(dev)]; 8263244Swnj register callcount; 8273244Swnj int fcount; 8283244Swnj struct mtop mtop; 8293244Swnj struct mtget mtget; 8303244Swnj /* we depend of the values and order of the MT codes here */ 8313244Swnj static tsops[] = 8323656Swnj {TS_WEOF,TS_SFORWF,TS_SREVF,TS_SFORW,TS_SREV,TS_REW,TS_OFFL,TS_SENSE}; 8331918Swnj 8343244Swnj switch (cmd) { 8353244Swnj case MTIOCTOP: /* tape operation */ 8363244Swnj if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) { 8373244Swnj u.u_error = EFAULT; 8383244Swnj return; 8393244Swnj } 8403244Swnj switch(mtop.mt_op) { 8413244Swnj case MTWEOF: 8423244Swnj callcount = mtop.mt_count; 8433244Swnj fcount = 1; 8443244Swnj break; 8453244Swnj case MTFSF: case MTBSF: 8463244Swnj case MTFSR: case MTBSR: 8473244Swnj callcount = 1; 8483244Swnj fcount = mtop.mt_count; 8493244Swnj break; 8503244Swnj case MTREW: case MTOFFL: case MTNOP: 8513244Swnj callcount = 1; 8523244Swnj fcount = 1; 8533244Swnj break; 8543244Swnj default: 8553244Swnj u.u_error = ENXIO; 8563244Swnj return; 8573244Swnj } 8583244Swnj if (callcount <= 0 || fcount <= 0) { 8593244Swnj u.u_error = ENXIO; 8603244Swnj return; 8613244Swnj } 8623244Swnj while (--callcount >= 0) { 8633244Swnj tscommand(dev, tsops[mtop.mt_op], fcount); 8643244Swnj if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) && 8653244Swnj bp->b_resid) { 8663244Swnj u.u_error = EIO; 8673244Swnj break; 8683244Swnj } 8693244Swnj if ((bp->b_flags&B_ERROR) || sc->sc_sts.s_xs0&TS_BOT) 8703244Swnj break; 8713244Swnj } 8723244Swnj geterror(bp); 8733244Swnj return; 8743244Swnj case MTIOCGET: 8753244Swnj mtget.mt_dsreg = 0; 8763244Swnj mtget.mt_erreg = sc->sc_sts.s_xs0; 8773244Swnj mtget.mt_resid = sc->sc_resid; 8783480Stoy mtget.mt_type = MT_ISTS; 8793244Swnj if (copyout((caddr_t)&mtget, addr, sizeof(mtget))) 8803244Swnj u.u_error = EFAULT; 8813244Swnj return; 8823244Swnj default: 8833244Swnj u.u_error = ENXIO; 8843244Swnj } 8851918Swnj } 8861918Swnj 8873244Swnj #define DBSIZE 20 8883244Swnj 8893244Swnj tsdump() 8901918Swnj { 8913244Swnj register struct uba_device *ui; 8923244Swnj register struct uba_regs *up; 8933244Swnj register struct device *addr; 8943244Swnj int blk, num; 8953244Swnj int start; 8961918Swnj 8973244Swnj start = 0; 8983244Swnj num = maxfree; 8993244Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 9003244Swnj if (tsdinfo[0] == 0) 9013244Swnj return (ENXIO); 9023244Swnj ui = phys(tsdinfo[0], struct uba_device *); 9033244Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 9043327Swnj ubainit(up); 9053244Swnj DELAY(1000000); 9063244Swnj addr = (struct device *)ui->ui_physaddr; 9073244Swnj addr->tssr = 0; 9083244Swnj tswait(addr); 9093244Swnj while (num > 0) { 9103244Swnj blk = num > DBSIZE ? DBSIZE : num; 9113244Swnj tsdwrite(start, blk, addr, up); 9123244Swnj start += blk; 9133244Swnj num -= blk; 9143244Swnj } 9153244Swnj tseof(addr); 9163244Swnj tseof(addr); 9173244Swnj tswait(addr); 9183244Swnj if (addr->tssr&TS_SC) 9193244Swnj return (EIO); 9203244Swnj addr->tssr = 0; 9213244Swnj tswait(addr); 9223244Swnj return (0); 9231918Swnj } 9241918Swnj 9253244Swnj tsdwrite(dbuf, num, addr, up) 9263244Swnj register dbuf, num; 9273244Swnj register struct device *addr; 9283244Swnj struct uba_regs *up; 9291918Swnj { 9303244Swnj register struct pte *io; 9313244Swnj register int npf; 9321918Swnj 9333244Swnj tswait(addr); 9343244Swnj io = up->uba_map; 9353244Swnj npf = num+1; 9363244Swnj while (--npf != 0) 9373244Swnj *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); 9383244Swnj *(int *)io = 0; 9393244Swnj #ifdef notyet 9403244Swnj addr->tsbc = -(num*NBPG); 9413244Swnj addr->tsba = 0; 9423244Swnj addr->tscs = TS_WCOM | TM_GO; 9433244Swnj #endif 9441918Swnj } 9451918Swnj 9463244Swnj tswait(addr) 9473244Swnj register struct device *addr; 9481918Swnj { 9493244Swnj register s; 9501918Swnj 9513244Swnj do 9523244Swnj s = addr->tssr; 9533244Swnj while ((s & TS_SSR) == 0); 9541918Swnj } 9551918Swnj 9563244Swnj tseof(addr) 9573244Swnj struct device *addr; 9581918Swnj { 9591918Swnj 9603244Swnj tswait(addr); 9613244Swnj #ifdef notyet 9623244Swnj addr->tscs = TS_WEOF | TM_GO; 9633244Swnj #endif 9641918Swnj } 9651900Swnj #endif 966