1*3528Swnj /* ts.c 4.11 81/04/15 */ 21900Swnj 31941Swnj #include "ts.h" 4*3528Swnj #include "te.h" 51900Swnj #if NTS > 0 63327Swnj #define printd if(tsdebug)printf 73327Swnj int tsdebug; 81900Swnj /* 91900Swnj * TS11 tape driver 103244Swnj * 113244Swnj * TODO: 123244Swnj * test driver with more than one controller 133244Swnj * test reset code 143244Swnj * test dump code 153244Swnj * test rewinds without hanging in driver 163244Swnj * what happens if you offline tape during rewind? 173244Swnj * test using file system on tape 181900Swnj */ 191900Swnj #include "../h/param.h" 201900Swnj #include "../h/systm.h" 211900Swnj #include "../h/buf.h" 223244Swnj #include "../h/dir.h" 231900Swnj #include "../h/conf.h" 243244Swnj #include "../h/user.h" 251900Swnj #include "../h/file.h" 263244Swnj #include "../h/map.h" 271900Swnj #include "../h/pte.h" 281947Swnj #include "../h/vm.h" 293244Swnj #include "../h/ubareg.h" 303244Swnj #include "../h/ubavar.h" 313244Swnj #include "../h/mtio.h" 323244Swnj #include "../h/ioctl.h" 333244Swnj #include "../h/cmap.h" 343244Swnj #include "../h/cpu.h" 351900Swnj 363244Swnj #include "../h/tsreg.h" 371900Swnj 383244Swnj /* 393244Swnj * There is a ctsbuf per tape controller. 403244Swnj * It is used as the token to pass to the internal routines 413244Swnj * to execute tape ioctls. 423244Swnj * In particular, when the tape is rewinding on close we release 433244Swnj * the user process but any further attempts to use the tape drive 443244Swnj * before the rewind completes will hang waiting for ctsbuf. 453244Swnj */ 463244Swnj struct buf ctsbuf[NTS]; 471900Swnj 483244Swnj /* 493244Swnj * Raw tape operations use rtsbuf. The driver 503244Swnj * notices when rtsbuf is being used and allows the user 513244Swnj * program to continue after errors and read records 523244Swnj * not of the standard length (BSIZE). 533244Swnj */ 543244Swnj struct buf rtsbuf[NTS]; 551900Swnj 563244Swnj /* 573244Swnj * Driver unibus interface routines and variables. 583244Swnj */ 593244Swnj int tsprobe(), tsslave(), tsattach(), tsdgo(), tsintr(); 603244Swnj struct uba_ctlr *tsminfo[NTS]; 613244Swnj struct uba_device *tsdinfo[NTS]; 623327Swnj struct buf tsbuf[NTS]; 633244Swnj u_short tsstd[] = { 0772520, 0 }; 643244Swnj /*** PROBABLY DON'T NEED ALL THESE SINCE CONTROLLER == DRIVE ***/ 653244Swnj struct uba_driver zsdriver = 663327Swnj { tsprobe, tsslave, tsattach, tsdgo, tsstd, "ts", tsdinfo, "zs", tsminfo, 0 }; 671900Swnj 683244Swnj /* bits in minor device */ 693244Swnj #define TSUNIT(dev) (minor(dev)&03) 703244Swnj #define T_NOREWIND 04 711900Swnj 723244Swnj #define INF (daddr_t)1000000L 731900Swnj 743244Swnj /* 753244Swnj * Software state per tape transport. 763244Swnj * Also contains hardware state in message packets. 773244Swnj * 783244Swnj * 1. A tape drive is a unique-open device; we refuse opens when it is already. 793244Swnj * 2. We keep track of the current position on a block tape and seek 803244Swnj * before operations by forward/back spacing if necessary. 813244Swnj * 3. We remember if the last operation was a write on a tape, so if a tape 823244Swnj * is open read write and the last thing done is a write we can 833244Swnj * write a standard end of tape mark (two eofs). 843244Swnj * 4. We remember the status registers after the last command, using 853244Swnj * then internally and returning them to the SENSE ioctl. 863244Swnj */ 873244Swnj struct ts_softc { 883244Swnj char sc_openf; /* lock against multiple opens */ 893244Swnj char sc_lastiow; /* last op was a write */ 903327Swnj short sc_resid; /* copy of last bc */ 913244Swnj daddr_t sc_blkno; /* block number, for block device tape */ 923244Swnj daddr_t sc_nxrec; /* position of end of tape, if known */ 933244Swnj struct ts_cmd sc_cmd; /* the command packet - ADDR MUST BE 0 MOD 4 */ 943244Swnj struct ts_sts sc_sts; /* status packet, for returned status */ 953244Swnj struct ts_char sc_char; /* characteristics packet */ 963244Swnj u_short sc_uba; /* Unibus addr of cmd pkt for tsdb */ 973244Swnj } ts_softc[NTS]; 981900Swnj 993244Swnj struct ts_softc *ts_ubaddr; /* Unibus address of ts_softc */ 1001900Swnj 1013244Swnj /* 1023244Swnj * States for um->um_tab.b_active, the per controller state flag. 1033244Swnj * This is used to sequence control in the driver. 1043244Swnj */ 1053244Swnj #define SSEEK 1 /* seeking */ 1063244Swnj #define SIO 2 /* doing seq i/o */ 1073244Swnj #define SCOM 3 /* sending control command */ 1083244Swnj #define SREW 4 /* sending a drive rewind */ 1091900Swnj 1103520Sroot #if NTM > 0 1113520Sroot /* kludge... see tm.c */ 1123520Sroot extern havetm; 1133520Sroot #endif 1143244Swnj /* 1153244Swnj * Determine if there is a controller for 1163244Swnj * a ts at address reg. Our goal is to make the 1173244Swnj * device interrupt. 1183244Swnj */ 1193244Swnj tsprobe(reg) 1203244Swnj caddr_t reg; 1213244Swnj { 1223244Swnj register int br, cvec; /* must be r11,r10; value-result */ 1231900Swnj 1243244Swnj #ifdef lint 1253244Swnj br = 0; cvec = br; br = cvec; 1263244Swnj #endif 1273244Swnj /****************/ 1283244Swnj /* */ 1293244Swnj /* K L U D G E */ 1303244Swnj /* */ 1313244Swnj /****************/ 1321900Swnj 1333520Sroot #if NTM > 0 1343520Sroot if (havetm) 1353520Sroot return (0); 1363520Sroot #endif 1373244Swnj /* IT'S TOO HARD TO MAKE THIS THING INTERRUPT 1383244Swnj JUST TO FIND ITS VECTOR */ 1393244Swnj cvec = 0224; 1403244Swnj br = 0x15; 1413244Swnj } 1421900Swnj 1433244Swnj /* 1443244Swnj * TS11 only supports one drive per controller; 1453244Swnj * check for ui_slave == 0. 1463244Swnj * 1473244Swnj * DO WE REALLY NEED THIS ROUTINE??? 1483244Swnj */ 1493244Swnj /*ARGSUSED*/ 1503244Swnj tsslave(ui, reg) 1513244Swnj struct uba_device *ui; 1523244Swnj caddr_t reg; 1533244Swnj { 1541900Swnj 1553244Swnj if (ui->ui_slave) /* non-zero slave not allowed */ 1563244Swnj return(0); 1573244Swnj return (1); 1583244Swnj } 1591900Swnj 1603244Swnj /* 1613244Swnj * Record attachment of the unit to the controller. 1623244Swnj * 1633244Swnj * SHOULD THIS ROUTINE DO ANYTHING??? 1643244Swnj */ 1653244Swnj /*ARGSUSED*/ 1663244Swnj tsattach(ui) 1673244Swnj struct uba_device *ui; 1683244Swnj { 1691900Swnj 1703244Swnj } 1711900Swnj 1723244Swnj /* 1733244Swnj * Open the device. Tapes are unique open 1743244Swnj * devices, so we refuse if it is already open. 1753244Swnj * We also check that a tape is available, and 1763244Swnj * don't block waiting here; if you want to wait 1773244Swnj * for a tape you should timeout in user code. 1783244Swnj */ 1791900Swnj tsopen(dev, flag) 1803244Swnj dev_t dev; 1813244Swnj int flag; 1821900Swnj { 1833244Swnj register int tsunit; 1843244Swnj register struct uba_device *ui; 1853244Swnj register struct ts_softc *sc; 1861900Swnj 1873244Swnj tsunit = TSUNIT(dev); 1883244Swnj if (tsunit>=NTS || (sc = &ts_softc[tsunit])->sc_openf || 1893244Swnj (ui = tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) { 1901900Swnj u.u_error = ENXIO; 1911900Swnj return; 1921900Swnj } 1933244Swnj if (tsinit(tsunit)) { 1941900Swnj u.u_error = ENXIO; 1953327Swnj printd("init failed\n"); 1961900Swnj return; 1971900Swnj } 1983327Swnj printd("init ok\n"); 1993244Swnj tscommand(dev, TS_SENSE, 1); 2003327Swnj printd("sense xs0 %o\n", sc->sc_sts.s_xs0); 2013244Swnj if ((sc->sc_sts.s_xs0&TS_ONL) == 0 || ((flag&(FREAD|FWRITE)) == 2023244Swnj FWRITE && (sc->sc_sts.s_xs0&TS_WLK))) { 2033244Swnj /* 2043244Swnj * Not online or write locked. 2053244Swnj */ 2063244Swnj u.u_error = EIO; 2073244Swnj return; 2081900Swnj } 2093244Swnj sc->sc_openf = 1; 2103244Swnj sc->sc_blkno = (daddr_t)0; 2113244Swnj sc->sc_nxrec = INF; 2123244Swnj sc->sc_lastiow = 0; 2131900Swnj } 2141900Swnj 2153244Swnj /* 2163244Swnj * Close tape device. 2173244Swnj * 2183244Swnj * If tape was open for writing or last operation was 2193244Swnj * a write, then write two EOF's and backspace over the last one. 2203244Swnj * Unless this is a non-rewinding special file, rewind the tape. 2213244Swnj * Make the tape available to others. 2223244Swnj */ 2231900Swnj tsclose(dev, flag) 2243244Swnj register dev_t dev; 2253244Swnj register flag; 2261900Swnj { 2273244Swnj register struct ts_softc *sc = &ts_softc[TSUNIT(dev)]; 2281900Swnj 2293244Swnj if (flag == FWRITE || (flag&FWRITE) && sc->sc_lastiow) { 2303244Swnj tscommand(dev, TS_WEOF, 1); 2313244Swnj tscommand(dev, TS_WEOF, 1); 2323244Swnj tscommand(dev, TS_SREV, 1); 2331900Swnj } 2343244Swnj if ((minor(dev)&T_NOREWIND) == 0) 2353244Swnj /* 2363244Swnj * 0 count means don't hang waiting for rewind complete 2373244Swnj * rather ctsbuf stays busy until the operation completes 2383244Swnj * preventing further opens from completing by 2393244Swnj * preventing a TS_SENSE from completing. 2403244Swnj */ 2413244Swnj tscommand(dev, TS_REW, 0); 2423244Swnj sc->sc_openf = 0; 2431900Swnj } 2441900Swnj 2453244Swnj /* 2463244Swnj * Initialize the TS11. Set up Unibus mapping for command 2473244Swnj * packets and set device characteristics. 2483244Swnj */ 2493244Swnj tsinit(unit) 2503244Swnj register int unit; 2511900Swnj { 2523244Swnj register struct ts_softc *sc = &ts_softc[unit]; 2533244Swnj register struct uba_ctlr *um = tsminfo[unit]; 2543244Swnj register struct device *addr = (struct device *)um->um_addr; 2553244Swnj register int i; 2563244Swnj 2573244Swnj /* 2583244Swnj * Map the command and message packets into Unibus 2593244Swnj * address space. We do all the command and message 2603244Swnj * packets at once to minimize the amount of Unibus 2613244Swnj * mapping necessary. 2623244Swnj */ 2633244Swnj if (ts_ubaddr == 0) { 2643244Swnj ctsbuf[unit].b_un.b_addr = (caddr_t)ts_softc; 2653244Swnj ctsbuf[unit].b_bcount = sizeof(ts_softc); 2663244Swnj i = ubasetup(um->um_ubanum, &ctsbuf[unit], 0); 2673244Swnj i &= 0777777; 2683244Swnj ts_ubaddr = (struct ts_softc *)i; 2693244Swnj /* MAKE SURE WE DON'T GET UNIBUS ADDRESS ZERO */ 2703244Swnj if (ts_ubaddr == 0) 2713244Swnj printf("ts%d: zero ubaddr\n", unit); 2723244Swnj } 2733244Swnj /* 2743244Swnj * Now initialize the TS11 controller. 2753244Swnj * Set the characteristics. 2763244Swnj */ 2773244Swnj if (addr->tssr & TS_NBA) { 2783244Swnj addr->tssr = 0; /* subsystem initialize */ 2793244Swnj tswait(addr); 2803244Swnj i = (int)&ts_ubaddr[unit].sc_cmd; /* Unibus addr of cmd */ 2813327Swnj if (i&3) { 2823327Swnj printf("addr mod 4 != 0\n"); 2833327Swnj return(1); 2843327Swnj } 2853244Swnj sc->sc_uba = (u_short)(i + ((i>>16)&3)); 2863244Swnj sc->sc_char.char_addr = (int)&ts_ubaddr[unit].sc_sts; 2873244Swnj sc->sc_char.char_size = sizeof(struct ts_sts); 2883244Swnj sc->sc_char.char_mode = TS_ESS; 2893244Swnj sc->sc_cmd.c_cmd = TS_ACK | TS_SETCHR; 2903327Swnj i = (int)&ts_ubaddr[unit].sc_char; 2913327Swnj sc->sc_cmd.c_loba = i; 2923327Swnj sc->sc_cmd.c_hiba = (i>>16)&3; 2933244Swnj sc->sc_cmd.c_size = sizeof(struct ts_char); 2943244Swnj addr->tsdb = sc->sc_uba; 2953244Swnj tswait(addr); 2963327Swnj /* 2973327Swnj 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); 2983327Swnj */ 2993327Swnj if (addr->tssr & TS_NBA) 3003327Swnj return(1); 3013244Swnj } 3023244Swnj return(0); 3033244Swnj } 3043244Swnj 3053244Swnj /* 3063244Swnj * Execute a command on the tape drive 3073244Swnj * a specified number of times. 3083244Swnj */ 3093244Swnj tscommand(dev, com, count) 3103244Swnj dev_t dev; 3113244Swnj int com, count; 3123244Swnj { 3131900Swnj register struct buf *bp; 3141900Swnj 3153244Swnj bp = &ctsbuf[TSUNIT(dev)]; 3163244Swnj (void) spl5(); 3173244Swnj while (bp->b_flags&B_BUSY) { 3183244Swnj /* 3193244Swnj * This special check is because B_BUSY never 3203244Swnj * gets cleared in the non-waiting rewind case. 3213244Swnj */ 3223244Swnj if (bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 3233244Swnj break; 3241900Swnj bp->b_flags |= B_WANTED; 3251900Swnj sleep((caddr_t)bp, PRIBIO); 3261900Swnj } 3273244Swnj bp->b_flags = B_BUSY|B_READ; 3283244Swnj (void) spl0(); 3293327Swnj printd("command %o dev %x count %d\n", com, dev, count); 3303244Swnj bp->b_dev = dev; 3313244Swnj bp->b_repcnt = count; 3323244Swnj bp->b_command = com; 3331900Swnj bp->b_blkno = 0; 3341900Swnj tsstrategy(bp); 3353244Swnj /* 3363244Swnj * In case of rewind from close, don't wait. 3373244Swnj * This is the only case where count can be 0. 3383244Swnj */ 3393244Swnj if (count == 0) 3403244Swnj return; 3411900Swnj iowait(bp); 3423244Swnj if (bp->b_flags&B_WANTED) 3431900Swnj wakeup((caddr_t)bp); 3443244Swnj bp->b_flags &= B_ERROR; 3451900Swnj } 3461900Swnj 3473244Swnj /* 3483244Swnj * Queue a tape operation. 3493244Swnj */ 3501900Swnj tsstrategy(bp) 3513244Swnj register struct buf *bp; 3521900Swnj { 3533244Swnj int tsunit = TSUNIT(bp->b_dev); 3543244Swnj register struct uba_ctlr *um; 3553327Swnj register struct buf *dp; 3561900Swnj 3573244Swnj /* 3583244Swnj * Put transfer at end of controller queue 3593244Swnj */ 3601900Swnj bp->av_forw = NULL; 3613244Swnj um = tsdinfo[tsunit]->ui_mi; 3623327Swnj dp = &tsbuf[tsunit]; 3633244Swnj (void) spl5(); 3643327Swnj if (dp->b_actf == NULL) 3653327Swnj dp->b_actf = bp; 3661900Swnj else 3673327Swnj dp->b_actl->av_forw = bp; 3683327Swnj dp->b_actl = bp; 3693327Swnj um->um_tab.b_actf = um->um_tab.b_actl = dp; 3703244Swnj /* 3713244Swnj * If the controller is not busy, get 3723244Swnj * it going. 3733244Swnj */ 3743244Swnj if (um->um_tab.b_active == 0) 3753244Swnj tsstart(um); 3763244Swnj (void) spl0(); 3771900Swnj } 3781900Swnj 3793244Swnj /* 3803244Swnj * Start activity on a ts controller. 3813244Swnj */ 3823244Swnj tsstart(um) 3833244Swnj register struct uba_ctlr *um; 3841900Swnj { 3851900Swnj register struct buf *bp; 3863244Swnj register struct device *addr = (struct device *)um->um_addr; 3873244Swnj register struct ts_softc *sc; 3883244Swnj register struct ts_cmd *tc; 3893244Swnj register struct uba_device *ui; 3903244Swnj int tsunit, cmd; 3911900Swnj daddr_t blkno; 3921900Swnj 3933244Swnj /* 3943244Swnj * Start the controller if there is something for it to do. 3953244Swnj */ 3963244Swnj loop: 3973327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 3981900Swnj return; 3993244Swnj tsunit = TSUNIT(bp->b_dev); 4003244Swnj ui = tsdinfo[tsunit]; 4013244Swnj sc = &ts_softc[tsunit]; 4023244Swnj tc = &sc->sc_cmd; 4033244Swnj /* 4043244Swnj * Default is that last command was NOT a write command; 4053244Swnj * if we do a write command we will notice this in tsintr(). 4063244Swnj */ 4073244Swnj sc->sc_lastiow = 1; 4083244Swnj if (sc->sc_openf < 0 || (addr->tssr&TS_OFL)) { 4093244Swnj /* 4103244Swnj * Have had a hard error on a non-raw tape 4113244Swnj * or the tape unit is now unavailable 4123244Swnj * (e.g. taken off line). 4133244Swnj */ 4143244Swnj bp->b_flags |= B_ERROR; 4153244Swnj goto next; 4163244Swnj } 4173244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) { 4183244Swnj /* 4193244Swnj * Execute control operation with the specified count. 4203244Swnj */ 4213244Swnj um->um_tab.b_active = 4223244Swnj bp->b_command == TS_REW ? SREW : SCOM; 4233244Swnj tc->c_repcnt = bp->b_repcnt; 4243327Swnj printd("strat: do cmd\n"); 4253244Swnj goto dobpcmd; 4263244Swnj } 4273244Swnj /* 4283244Swnj * The following checks handle boundary cases for operation 4293244Swnj * on non-raw tapes. On raw tapes the initialization of 4303244Swnj * sc->sc_nxrec by tsphys causes them to be skipped normally 4313244Swnj * (except in the case of retries). 4323244Swnj */ 4333244Swnj if (dbtofsb(bp->b_blkno) > sc->sc_nxrec) { 4343244Swnj /* 4353244Swnj * Can't read past known end-of-file. 4363244Swnj */ 4373244Swnj bp->b_flags |= B_ERROR; 4383244Swnj bp->b_error = ENXIO; 4393244Swnj goto next; 4403244Swnj } 4413244Swnj if (dbtofsb(bp->b_blkno) == sc->sc_nxrec && 4423244Swnj bp->b_flags&B_READ) { 4433244Swnj /* 4443244Swnj * Reading at end of file returns 0 bytes. 4453244Swnj */ 4463244Swnj bp->b_resid = bp->b_bcount; 4473244Swnj clrbuf(bp); 4483244Swnj goto next; 4493244Swnj } 4503244Swnj if ((bp->b_flags&B_READ) == 0) 4513244Swnj /* 4523244Swnj * Writing sets EOF 4533244Swnj */ 4543244Swnj sc->sc_nxrec = dbtofsb(bp->b_blkno) + 1; 4553244Swnj /* 4563244Swnj * If the data transfer command is in the correct place, 4573244Swnj * set up all the registers except the csr, and give 4583244Swnj * control over to the UNIBUS adapter routines, to 4593244Swnj * wait for resources to start the i/o. 4603244Swnj */ 4613244Swnj if ((blkno = sc->sc_blkno) == dbtofsb(bp->b_blkno)) { 4623244Swnj tc->c_size = bp->b_bcount; 4633244Swnj if ((bp->b_flags&B_READ) == 0) 4643244Swnj cmd = TS_WCOM; 4651900Swnj else 4663244Swnj cmd = TS_RCOM; 4673244Swnj if (um->um_tab.b_errcnt) 4683244Swnj cmd |= TS_RETRY; 4693244Swnj um->um_tab.b_active = SIO; 4703327Swnj tc->c_cmd = TS_ACK | TS_CVC | TS_IE | cmd; 4713327Swnj printd("r/w %o size %d\n", tc->c_cmd, tc->c_size); 4723244Swnj (void) ubago(ui); 4733244Swnj return; 4743244Swnj } 4753244Swnj /* 4763244Swnj * Tape positioned incorrectly; 4773244Swnj * set to seek forwards or backwards to the correct spot. 4783244Swnj * This happens for raw tapes only on error retries. 4793244Swnj */ 4803244Swnj um->um_tab.b_active = SSEEK; 4813327Swnj printd("seek blkno %d b_blkno %d\n", blkno, bp->b_blkno); 4823244Swnj if (blkno < dbtofsb(bp->b_blkno)) { 4833244Swnj bp->b_command = TS_SFORW; 4843244Swnj tc->c_repcnt = dbtofsb(bp->b_blkno) - blkno; 4851900Swnj } else { 4863244Swnj bp->b_command = TS_SREV; 4873244Swnj tc->c_repcnt = blkno - dbtofsb(bp->b_blkno); 4881900Swnj } 4893244Swnj dobpcmd: 4903244Swnj /* 4913244Swnj * Do the command in bp. 4923244Swnj */ 4933327Swnj tc->c_cmd = TS_ACK | TS_CVC | TS_IE | bp->b_command; 4943244Swnj addr->tsdb = sc->sc_uba; 4951900Swnj return; 4961900Swnj 4973244Swnj next: 4983244Swnj /* 4993244Swnj * Done with this operation due to error or 5003244Swnj * the fact that it doesn't do anything. 5013244Swnj * Release UBA resources (if any), dequeue 5023244Swnj * the transfer and continue processing this slave. 5033244Swnj */ 5043244Swnj if (um->um_ubinfo) 5053244Swnj ubadone(um); 5063244Swnj um->um_tab.b_errcnt = 0; 5073327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 5081900Swnj iodone(bp); 5091900Swnj goto loop; 5101900Swnj } 5111900Swnj 5123244Swnj /* 5133244Swnj * The UNIBUS resources we needed have been 5143244Swnj * allocated to us; start the device. 5153244Swnj */ 5163244Swnj tsdgo(um) 5173244Swnj register struct uba_ctlr *um; 5181900Swnj { 5193244Swnj register struct device *addr = (struct device *)um->um_addr; 5203244Swnj register struct ts_softc *sc = &ts_softc[um->um_ctlr]; 5213327Swnj register int i; 5223244Swnj 5233327Swnj i = um->um_ubinfo & 0777777; 5243327Swnj printd("dgo addr %o\n", i); 5253327Swnj sc->sc_cmd.c_loba = i; 5263327Swnj sc->sc_cmd.c_hiba = (i>>16)&3; 5273244Swnj addr->tsdb = sc->sc_uba; 5283244Swnj } 5293244Swnj 5303244Swnj /* 5313244Swnj * Ts interrupt routine. 5323244Swnj */ 5333244Swnj /*ARGSUSED*/ 5343244Swnj tsintr(ts11) 5353244Swnj int ts11; 5363244Swnj { 5371900Swnj register struct buf *bp; 5383244Swnj register struct uba_ctlr *um = tsminfo[ts11]; 5393244Swnj register struct device *addr; 5403244Swnj register struct ts_softc *sc; 5413244Swnj int tsunit; 5423244Swnj register state; 5431900Swnj 5443327Swnj printd("intr\n"); 5453327Swnj if ((bp = um->um_tab.b_actf->b_actf) == NULL) 5461900Swnj return; 5473244Swnj tsunit = TSUNIT(bp->b_dev); 5483244Swnj addr = (struct device *)tsdinfo[tsunit]->ui_addr; 5493244Swnj /* 5503244Swnj * If last command was a rewind, and tape is still 5513244Swnj * rewinding, wait for the rewind complete interrupt. 5523244Swnj * 5533244Swnj * SHOULD NEVER GET AN INTERRUPT IN THIS STATE. 5543244Swnj */ 5553244Swnj if (um->um_tab.b_active == SREW) { 5563244Swnj um->um_tab.b_active = SCOM; 5573244Swnj if ((addr->tssr&TS_SSR) == 0) 5583244Swnj return; 5593244Swnj } 5603244Swnj /* 5613244Swnj * An operation completed... record status 5623244Swnj */ 5633327Swnj printd(" ok1\n"); 5643244Swnj sc = &ts_softc[tsunit]; 5653244Swnj if ((bp->b_flags & B_READ) == 0) 5663244Swnj sc->sc_lastiow = 1; 5673244Swnj state = um->um_tab.b_active; 5683244Swnj um->um_tab.b_active = 0; 5693244Swnj /* 5703244Swnj * Check for errors. 5713244Swnj */ 5723244Swnj if (addr->tssr&TS_SC) { 5733244Swnj switch (addr->tssr & TS_TC) { 5743244Swnj case TS_UNREC: /* unrecoverable */ 5753244Swnj case TS_FATAL: /* fatal error */ 5763244Swnj case TS_ATTN: /* attention (shouldn't happen) */ 5773244Swnj case TS_RECNM: /* recoverable, no motion */ 5783244Swnj break; 5791900Swnj 5803244Swnj case TS_SUCC: /* success termination */ 5813244Swnj printf("ts%d: success\n", TSUNIT(minor(bp->b_dev))); 5823244Swnj goto ignoreerr; 5831900Swnj 5843244Swnj case TS_ALERT: /* tape status alert */ 5853244Swnj /* 5863244Swnj * If we hit the end of the tape file, 5873244Swnj * update our position. 5883244Swnj */ 5893244Swnj if (sc->sc_sts.s_xs0 & (TS_TMK|TS_EOT)) { 5903244Swnj tsseteof(bp); /* set blkno and nxrec */ 5913244Swnj state = SCOM; /* force completion */ 5923244Swnj /* 5933244Swnj * Stuff bc so it will be unstuffed correctly 5943244Swnj * later to get resid. 5953244Swnj */ 5963244Swnj sc->sc_sts.s_rbpcr = bp->b_bcount; 5973244Swnj goto opdone; 5983244Swnj } 5993244Swnj /* 6003244Swnj * If we were reading raw tape and the record was too long 6013244Swnj * or too short, then we don't consider this an error. 6023244Swnj */ 6033244Swnj if (bp == &rtsbuf[TSUNIT(bp->b_dev)] && (bp->b_flags&B_READ) && 6043244Swnj sc->sc_sts.s_xs0&(TS_RLS|TS_RLL)) 6053244Swnj goto ignoreerr; 6063244Swnj case TS_RECOV: /* recoverable, tape moved */ 6073244Swnj /* 6083244Swnj * If this was an i/o operation retry up to 8 times. 6093244Swnj */ 6103244Swnj if (state==SIO) { 6113244Swnj if (++um->um_tab.b_errcnt < 7) { 6123244Swnj ubadone(um); 6133244Swnj goto opcont; 6143244Swnj } else 6153244Swnj sc->sc_blkno++; 6163244Swnj } else { 6173244Swnj /* 6183244Swnj * Non-i/o errors on non-raw tape 6193244Swnj * cause it to close. 6203244Swnj */ 6213244Swnj if (sc->sc_openf>0 && bp != &rtsbuf[TSUNIT(bp->b_dev)]) 6223244Swnj sc->sc_openf = -1; 6233244Swnj } 6241900Swnj break; 6253244Swnj 6263244Swnj case TS_REJECT: /* function reject */ 6273244Swnj if (state == SIO && sc->sc_sts.s_xs0 & TS_WLE) 6283244Swnj printf("ts%d: write locked\n", TSUNIT(bp->b_dev)); 6293244Swnj if ((sc->sc_sts.s_xs0 & TS_ONL) == 0) 6303244Swnj printf("ts%d: offline\n", TSUNIT(bp->b_dev)); 6311900Swnj break; 6321900Swnj } 6333244Swnj /* 6343244Swnj * Couldn't recover error 6353244Swnj */ 6363244Swnj printf("ts%d: hard error bn%d xs0=%b\n", TSUNIT(bp->b_dev), 6373244Swnj bp->b_blkno, sc->sc_sts.s_xs0, TSXS0_BITS); 6383244Swnj bp->b_flags |= B_ERROR; 6393244Swnj goto opdone; 6403244Swnj } 6413244Swnj /* 6423244Swnj * Advance tape control FSM. 6433244Swnj */ 6443244Swnj ignoreerr: 6453244Swnj switch (state) { 6461900Swnj 6473244Swnj case SIO: 6483244Swnj /* 6493244Swnj * Read/write increments tape block number 6503244Swnj */ 6513244Swnj sc->sc_blkno++; 6523244Swnj goto opdone; 6531900Swnj 6541900Swnj case SCOM: 6553244Swnj /* 6563244Swnj * For forward/backward space record update current position. 6573244Swnj */ 6583244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) 6593244Swnj switch (bp->b_command) { 6601900Swnj 6613244Swnj case TS_SFORW: 6623244Swnj sc->sc_blkno += bp->b_repcnt; 6633244Swnj break; 6641900Swnj 6653244Swnj case TS_SREV: 6663244Swnj sc->sc_blkno -= bp->b_repcnt; 6673244Swnj break; 6683244Swnj } 6693244Swnj goto opdone; 6703244Swnj 6713244Swnj case SSEEK: 6723244Swnj sc->sc_blkno = dbtofsb(bp->b_blkno); 6733244Swnj goto opcont; 6743244Swnj 6751900Swnj default: 6763244Swnj panic("tsintr"); 6771900Swnj } 6783244Swnj opdone: 6793244Swnj /* 6803244Swnj * Reset error count and remove 6813244Swnj * from device queue. 6823244Swnj */ 6833244Swnj um->um_tab.b_errcnt = 0; 6843327Swnj um->um_tab.b_actf->b_actf = bp->av_forw; 6853244Swnj bp->b_resid = sc->sc_sts.s_rbpcr; 6863244Swnj ubadone(um); 6873327Swnj printd(" iodone\n"); 6883244Swnj iodone(bp); 6893327Swnj if (um->um_tab.b_actf->b_actf == 0) 6903244Swnj return; 6913244Swnj opcont: 6923244Swnj tsstart(um); 6933244Swnj } 6943244Swnj 6953244Swnj tsseteof(bp) 6963244Swnj register struct buf *bp; 6973244Swnj { 6983244Swnj register int tsunit = TSUNIT(bp->b_dev); 6993244Swnj register struct ts_softc *sc = &ts_softc[tsunit]; 7003244Swnj 7013244Swnj if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) { 7023244Swnj if (sc->sc_blkno > dbtofsb(bp->b_blkno)) { 7033244Swnj /* reversing */ 7043244Swnj sc->sc_nxrec = dbtofsb(bp->b_blkno) - sc->sc_sts.s_rbpcr; 7053244Swnj sc->sc_blkno = sc->sc_nxrec; 7063244Swnj } else { 7073244Swnj /* spacing forward */ 7083244Swnj sc->sc_blkno = dbtofsb(bp->b_blkno) + sc->sc_sts.s_rbpcr; 7093244Swnj sc->sc_nxrec = sc->sc_blkno - 1; 7101900Swnj } 7113244Swnj return; 7123244Swnj } 7133244Swnj /* eof on read */ 7143244Swnj sc->sc_nxrec = dbtofsb(bp->b_blkno); 7151900Swnj } 7161900Swnj 7171900Swnj tsread(dev) 7183244Swnj dev_t dev; 7191900Swnj { 7203244Swnj 7211900Swnj tsphys(dev); 7223244Swnj if (u.u_error) 7233244Swnj return; 7243244Swnj physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_READ, minphys); 7251900Swnj } 7261900Swnj 7271900Swnj tswrite(dev) 7283244Swnj dev_t dev; 7291900Swnj { 7303244Swnj 7311900Swnj tsphys(dev); 7323244Swnj if (u.u_error) 7333244Swnj return; 7343244Swnj physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_WRITE, minphys); 7351900Swnj } 7361900Swnj 7373244Swnj /* 7383244Swnj * Check that a raw device exists. 7393244Swnj * If it does, set up sc_blkno and sc_nxrec 7403244Swnj * so that the tape will appear positioned correctly. 7413244Swnj */ 7421900Swnj tsphys(dev) 7433244Swnj dev_t dev; 7441900Swnj { 7453244Swnj register int tsunit = TSUNIT(dev); 7463244Swnj register daddr_t a; 7473244Swnj register struct ts_softc *sc; 7483244Swnj register struct uba_device *ui; 7491900Swnj 7503244Swnj if (tsunit >= NTS || (ui=tsdinfo[tsunit]) == 0 || ui->ui_alive == 0) { 7513244Swnj u.u_error = ENXIO; 7523244Swnj return; 7533244Swnj } 7543244Swnj sc = &ts_softc[tsunit]; 7553244Swnj a = dbtofsb(u.u_offset >> 9); 7563244Swnj sc->sc_blkno = a; 7573244Swnj sc->sc_nxrec = a + 1; 7581900Swnj } 7591918Swnj 7603244Swnj tsreset(uban) 7613244Swnj int uban; 7621918Swnj { 7633244Swnj register struct uba_ctlr *um; 7643244Swnj register ts11; 7653244Swnj register struct buf *dp; 7661918Swnj 7673244Swnj for (ts11 = 0; ts11 < NTS; ts11++) { 7683244Swnj if ((um = tsminfo[ts11]) == 0 || um->um_alive == 0 || 7693244Swnj um->um_ubanum != uban) 7703244Swnj continue; 7713244Swnj printf(" ts%d", ts11); 7723244Swnj um->um_tab.b_active = 0; 7733244Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7743244Swnj ts_softc[ts11].sc_openf = -1; 7753244Swnj if (um->um_ubinfo) { 7763244Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 7773244Swnj ubadone(um); 7783244Swnj } 7793244Swnj tsinit(ts11); 7803244Swnj tsstart(um); 7811918Swnj } 7821918Swnj } 7831918Swnj 7843244Swnj /*ARGSUSED*/ 7853244Swnj tsioctl(dev, cmd, addr, flag) 7863244Swnj caddr_t addr; 7873244Swnj dev_t dev; 7881918Swnj { 7893244Swnj int tsunit = TSUNIT(dev); 7903244Swnj register struct ts_softc *sc = &ts_softc[tsunit]; 7913244Swnj register struct buf *bp = &ctsbuf[TSUNIT(dev)]; 7923244Swnj register callcount; 7933244Swnj int fcount; 7943244Swnj struct mtop mtop; 7953244Swnj struct mtget mtget; 7963244Swnj /* we depend of the values and order of the MT codes here */ 7973244Swnj static tsops[] = 7983244Swnj {TS_WEOF,TS_SFORW,TS_SREV,TS_SFORWF,TS_SREVF,TS_REW,TS_OFFL,TS_SENSE}; 7991918Swnj 8003244Swnj switch (cmd) { 8013244Swnj case MTIOCTOP: /* tape operation */ 8023244Swnj if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) { 8033244Swnj u.u_error = EFAULT; 8043244Swnj return; 8053244Swnj } 8063244Swnj switch(mtop.mt_op) { 8073244Swnj case MTWEOF: 8083244Swnj callcount = mtop.mt_count; 8093244Swnj fcount = 1; 8103244Swnj break; 8113244Swnj case MTFSF: case MTBSF: 8123244Swnj case MTFSR: case MTBSR: 8133244Swnj callcount = 1; 8143244Swnj fcount = mtop.mt_count; 8153244Swnj break; 8163244Swnj case MTREW: case MTOFFL: case MTNOP: 8173244Swnj callcount = 1; 8183244Swnj fcount = 1; 8193244Swnj break; 8203244Swnj default: 8213244Swnj u.u_error = ENXIO; 8223244Swnj return; 8233244Swnj } 8243244Swnj if (callcount <= 0 || fcount <= 0) { 8253244Swnj u.u_error = ENXIO; 8263244Swnj return; 8273244Swnj } 8283244Swnj while (--callcount >= 0) { 8293244Swnj tscommand(dev, tsops[mtop.mt_op], fcount); 8303244Swnj if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) && 8313244Swnj bp->b_resid) { 8323244Swnj u.u_error = EIO; 8333244Swnj break; 8343244Swnj } 8353244Swnj if ((bp->b_flags&B_ERROR) || sc->sc_sts.s_xs0&TS_BOT) 8363244Swnj break; 8373244Swnj } 8383244Swnj geterror(bp); 8393244Swnj return; 8403244Swnj case MTIOCGET: 8413244Swnj mtget.mt_dsreg = 0; 8423244Swnj mtget.mt_erreg = sc->sc_sts.s_xs0; 8433244Swnj mtget.mt_resid = sc->sc_resid; 8443480Stoy mtget.mt_type = MT_ISTS; 8453244Swnj if (copyout((caddr_t)&mtget, addr, sizeof(mtget))) 8463244Swnj u.u_error = EFAULT; 8473244Swnj return; 8483244Swnj default: 8493244Swnj u.u_error = ENXIO; 8503244Swnj } 8511918Swnj } 8521918Swnj 8533244Swnj #define DBSIZE 20 8543244Swnj 8553244Swnj tsdump() 8561918Swnj { 8573244Swnj register struct uba_device *ui; 8583244Swnj register struct uba_regs *up; 8593244Swnj register struct device *addr; 8603244Swnj int blk, num; 8613244Swnj int start; 8621918Swnj 8633244Swnj start = 0; 8643244Swnj num = maxfree; 8653244Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 8663244Swnj if (tsdinfo[0] == 0) 8673244Swnj return (ENXIO); 8683244Swnj ui = phys(tsdinfo[0], struct uba_device *); 8693244Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 8703327Swnj ubainit(up); 8713244Swnj DELAY(1000000); 8723244Swnj addr = (struct device *)ui->ui_physaddr; 8733244Swnj addr->tssr = 0; 8743244Swnj tswait(addr); 8753244Swnj while (num > 0) { 8763244Swnj blk = num > DBSIZE ? DBSIZE : num; 8773244Swnj tsdwrite(start, blk, addr, up); 8783244Swnj start += blk; 8793244Swnj num -= blk; 8803244Swnj } 8813244Swnj tseof(addr); 8823244Swnj tseof(addr); 8833244Swnj tswait(addr); 8843244Swnj if (addr->tssr&TS_SC) 8853244Swnj return (EIO); 8863244Swnj addr->tssr = 0; 8873244Swnj tswait(addr); 8883244Swnj return (0); 8891918Swnj } 8901918Swnj 8913244Swnj tsdwrite(dbuf, num, addr, up) 8923244Swnj register dbuf, num; 8933244Swnj register struct device *addr; 8943244Swnj struct uba_regs *up; 8951918Swnj { 8963244Swnj register struct pte *io; 8973244Swnj register int npf; 8981918Swnj 8993244Swnj tswait(addr); 9003244Swnj io = up->uba_map; 9013244Swnj npf = num+1; 9023244Swnj while (--npf != 0) 9033244Swnj *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); 9043244Swnj *(int *)io = 0; 9053244Swnj #ifdef notyet 9063244Swnj addr->tsbc = -(num*NBPG); 9073244Swnj addr->tsba = 0; 9083244Swnj addr->tscs = TS_WCOM | TM_GO; 9093244Swnj #endif 9101918Swnj } 9111918Swnj 9123244Swnj tswait(addr) 9133244Swnj register struct device *addr; 9141918Swnj { 9153244Swnj register s; 9161918Swnj 9173244Swnj do 9183244Swnj s = addr->tssr; 9193244Swnj while ((s & TS_SSR) == 0); 9201918Swnj } 9211918Swnj 9223244Swnj tseof(addr) 9233244Swnj struct device *addr; 9241918Swnj { 9251918Swnj 9263244Swnj tswait(addr); 9273244Swnj #ifdef notyet 9283244Swnj addr->tscs = TS_WEOF | TM_GO; 9293244Swnj #endif 9301918Swnj } 9311900Swnj #endif 932