1*2982Swnj /* tm.c 4.23 03/07/81 */ 21919Swnj 32709Swnj #include "te.h" 42630Swnj #if NTM > 0 52670Swnj int tmgapsdcnt; /* DEBUG */ 61919Swnj /* 72630Swnj * TM11/TE10 tape driver 82471Swnj * 92928Swnj * Todo: 102928Swnj * Test driver with more than one slave 112928Swnj * Test reset code 122928Swnj * Do rewinds without hanging in driver 131919Swnj */ 142471Swnj #define DELAY(N) { register int d = N; while (--d > 0); } 151919Swnj #include "../h/param.h" 161919Swnj #include "../h/buf.h" 171919Swnj #include "../h/dir.h" 181919Swnj #include "../h/conf.h" 191919Swnj #include "../h/user.h" 201919Swnj #include "../h/file.h" 211919Swnj #include "../h/map.h" 221919Swnj #include "../h/pte.h" 232574Swnj #include "../h/vm.h" 24*2982Swnj #include "../h/ubareg.h" 25*2982Swnj #include "../h/ubavar.h" 261919Swnj #include "../h/mtio.h" 271919Swnj #include "../h/ioctl.h" 282363Swnj #include "../h/cmap.h" 292396Swnj #include "../h/cpu.h" 301919Swnj 312396Swnj #include "../h/tmreg.h" 321919Swnj 332630Swnj struct buf ctmbuf[NTE]; 342630Swnj struct buf rtmbuf[NTE]; 351919Swnj 362608Swnj int tmprobe(), tmslave(), tmattach(), tmdgo(), tmintr(); 37*2982Swnj struct uba_ctlr *tmminfo[NTM]; 38*2982Swnj struct uba_device *tmdinfo[NTE]; 392630Swnj struct buf tmutab[NTE]; 402608Swnj #ifdef notyet 41*2982Swnj struct uba_device *tmip[NTM][4]; 422608Swnj #endif 432458Swnj u_short tmstd[] = { 0772520, 0 }; 442396Swnj struct uba_driver tmdriver = 452630Swnj { tmprobe, tmslave, tmattach, tmdgo, tmstd, "te", tmdinfo, "tm", tmminfo, 0 }; 461919Swnj 471919Swnj /* bits in minor device */ 482608Swnj #define TMUNIT(dev) (minor(dev)&03) 491919Swnj #define T_NOREWIND 04 501919Swnj #define T_1600BPI 08 511919Swnj 521919Swnj #define INF (daddr_t)1000000L 531919Swnj 542608Swnj /* 552608Swnj * Software state per tape transport. 562608Swnj */ 572471Swnj struct tm_softc { 582608Swnj char sc_openf; /* lock against multiple opens */ 592608Swnj char sc_lastiow; /* last op was a write */ 602608Swnj daddr_t sc_blkno; /* block number, for block device tape */ 612608Swnj daddr_t sc_nxrec; /* desired block position */ 622608Swnj u_short sc_erreg; /* copy of last erreg */ 632608Swnj u_short sc_dsreg; /* copy of last dsreg */ 642608Swnj short sc_resid; /* copy of last bc */ 652928Swnj #ifdef notdef 662670Swnj short sc_lastcmd; /* last command to handle direction changes */ 672928Swnj #endif 682630Swnj } tm_softc[NTM]; 691919Swnj 702608Swnj /* 712608Swnj * States for um->um_tab.b_active, the 722608Swnj * per controller state flag. 732608Swnj */ 741919Swnj #define SSEEK 1 /* seeking */ 751919Swnj #define SIO 2 /* doing seq i/o */ 761919Swnj #define SCOM 3 /* sending control command */ 772608Swnj #define SREW 4 /* sending a drive rewind */ 781919Swnj 792608Swnj /* WE CURRENTLY HANDLE REWINDS PRIMITIVELY, BUSYING OUT THE CONTROLLER */ 802608Swnj /* DURING THE REWIND... IF WE EVER GET TWO TRANSPORTS, WE CAN DEBUG MORE */ 812608Swnj /* SOPHISTICATED LOGIC... THIS SIMPLE CODE AT LEAST MAY WORK. */ 821919Swnj 832426Skre /* 842426Skre * Determine if there is a controller for 852426Skre * a tm at address reg. Our goal is to make the 862426Skre * device interrupt. 872426Skre */ 882608Swnj tmprobe(reg) 892396Swnj caddr_t reg; 902396Swnj { 912458Swnj register int br, cvec; 922426Skre 932608Swnj #ifdef lint 942608Swnj br = 0; br = cvec; cvec = br; 952608Swnj #endif 962608Swnj ((struct device *)reg)->tmcs = TM_IE; 972396Swnj /* 982630Swnj * If this is a tm11, it ought to have interrupted 992396Swnj * by now, if it isn't (ie: it is a ts04) then we just 1002458Swnj * hope that it didn't interrupt, so autoconf will ignore it. 1012458Swnj * Just in case, we will reference one 1022396Swnj * of the more distant registers, and hope for a machine 1032458Swnj * check, or similar disaster if this is a ts. 1042471Swnj * 1052471Swnj * Note: on an 11/780, badaddr will just generate 1062471Swnj * a uba error for a ts; but our caller will notice that 1072471Swnj * so we won't check for it. 1082396Swnj */ 1092396Swnj if (badaddr(&((struct device *)reg)->tmrd, 2)) 1102458Swnj return (0); 1112458Swnj return (1); 1122396Swnj } 1132396Swnj 1142608Swnj /* 1152608Swnj * Due to a design flaw, we cannot ascertain if the tape 1162608Swnj * exists or not unless it is on line - ie: unless a tape is 1172608Swnj * mounted. This is too servere a restriction to bear, 1182608Swnj * so all units are assumed to exist. 1192608Swnj */ 1202608Swnj /*ARGSUSED*/ 1212574Swnj tmslave(ui, reg) 122*2982Swnj struct uba_device *ui; 1232396Swnj caddr_t reg; 1242396Swnj { 1252458Swnj 1262458Swnj return (1); 1272396Swnj } 1282396Swnj 1292608Swnj /* 1302608Swnj * Record attachment of the unit to the controller port. 1312608Swnj */ 1322608Swnj /*ARGSUSED*/ 1332608Swnj tmattach(ui) 134*2982Swnj struct uba_device *ui; 1352608Swnj { 1362608Swnj 1372608Swnj #ifdef notyet 1382608Swnj tmip[ui->ui_ctlr][ui->ui_slave] = ui; 1392608Swnj #endif 1402608Swnj } 1412608Swnj 1422608Swnj /* 1432608Swnj * Open the device. Tapes are unique open 1442608Swnj * devices, so we refuse if it is already open. 1452608Swnj * We also check that a tape is available, and 1462608Swnj * don't block waiting here. 1472608Swnj */ 1481919Swnj tmopen(dev, flag) 1491919Swnj dev_t dev; 1501919Swnj int flag; 1511919Swnj { 1522608Swnj register int unit; 153*2982Swnj register struct uba_device *ui; 1542608Swnj register struct tm_softc *sc; 1551919Swnj 1562608Swnj unit = TMUNIT(dev); 1572630Swnj if (unit>=NTE || (sc = &tm_softc[unit])->sc_openf || 1582608Swnj (ui = tmdinfo[unit]) == 0 || ui->ui_alive == 0) { 1592608Swnj u.u_error = ENXIO; 1601919Swnj return; 1611919Swnj } 1622608Swnj tmcommand(dev, TM_SENSE, 1); 1632928Swnj if ((sc->sc_erreg&(TM_SELR|TM_TUR)) != (TM_SELR|TM_TUR) || 1642928Swnj (flag&(FREAD|FWRITE)) == FWRITE && sc->sc_erreg&TM_WRL) { 1652471Swnj u.u_error = EIO; 1662608Swnj return; 1671919Swnj } 1682608Swnj sc->sc_openf = 1; 1692471Swnj sc->sc_blkno = (daddr_t)0; 1702471Swnj sc->sc_nxrec = INF; 1712608Swnj sc->sc_lastiow = 0; 1721919Swnj } 1731919Swnj 1742608Swnj /* 1752608Swnj * Close tape device. 1762608Swnj * 1772608Swnj * If tape was open for writing or last operation was 1782608Swnj * a write, then write two EOF's and backspace over the last one. 1792608Swnj * Unless this is a non-rewinding special file, rewind the tape. 1802608Swnj * Make the tape available to others. 1812608Swnj */ 1821919Swnj tmclose(dev, flag) 1831919Swnj register dev_t dev; 1841919Swnj register flag; 1851919Swnj { 1862608Swnj register struct tm_softc *sc = &tm_softc[TMUNIT(dev)]; 1871919Swnj 1882608Swnj if (flag == FWRITE || (flag&FWRITE) && sc->sc_lastiow) { 1892608Swnj tmcommand(dev, TM_WEOF, 1); 1902608Swnj tmcommand(dev, TM_WEOF, 1); 1912608Swnj tmcommand(dev, TM_SREV, 1); 1921919Swnj } 1931919Swnj if ((minor(dev)&T_NOREWIND) == 0) 1942608Swnj tmcommand(dev, TM_REW, 1); 1952471Swnj sc->sc_openf = 0; 1961919Swnj } 1971919Swnj 1982608Swnj /* 1992608Swnj * Execute a command on the tape drive 2002608Swnj * a specified number of times. 2012608Swnj */ 2022574Swnj tmcommand(dev, com, count) 2031919Swnj dev_t dev; 2041919Swnj int com, count; 2051919Swnj { 2061919Swnj register struct buf *bp; 2071919Swnj 2082608Swnj bp = &ctmbuf[TMUNIT(dev)]; 2091919Swnj (void) spl5(); 2101919Swnj while (bp->b_flags&B_BUSY) { 2111919Swnj bp->b_flags |= B_WANTED; 2121919Swnj sleep((caddr_t)bp, PRIBIO); 2131919Swnj } 2141919Swnj bp->b_flags = B_BUSY|B_READ; 2151919Swnj (void) spl0(); 2161919Swnj bp->b_dev = dev; 2171919Swnj bp->b_repcnt = -count; 2181919Swnj bp->b_command = com; 2191919Swnj bp->b_blkno = 0; 2201919Swnj tmstrategy(bp); 2211919Swnj iowait(bp); 2221919Swnj if (bp->b_flags&B_WANTED) 2231919Swnj wakeup((caddr_t)bp); 2241919Swnj bp->b_flags &= B_ERROR; 2251919Swnj } 2261919Swnj 2272608Swnj /* 2282608Swnj * Decipher a tape operation and do what is needed 2292608Swnj * to see that it happens. 2302608Swnj */ 2311919Swnj tmstrategy(bp) 2321919Swnj register struct buf *bp; 2331919Swnj { 2342608Swnj int unit = TMUNIT(bp->b_dev); 235*2982Swnj register struct uba_ctlr *um; 2362608Swnj register struct buf *dp; 2372608Swnj register struct tm_softc *sc = &tm_softc[unit]; 2381919Swnj 2392608Swnj /* 2402608Swnj * Put transfer at end of unit queue 2412608Swnj */ 2422608Swnj dp = &tmutab[unit]; 2431919Swnj bp->av_forw = NULL; 2441919Swnj (void) spl5(); 2452608Swnj if (dp->b_actf == NULL) { 2462608Swnj dp->b_actf = bp; 2472608Swnj /* 2482608Swnj * Transport not already active... 2492608Swnj * put at end of controller queue. 2502608Swnj */ 2512608Swnj dp->b_forw = NULL; 2522608Swnj um = tmdinfo[unit]->ui_mi; 2532608Swnj if (um->um_tab.b_actf == NULL) 2542608Swnj um->um_tab.b_actf = dp; 2552608Swnj else 2562608Swnj um->um_tab.b_actl->b_forw = dp; 2572608Swnj um->um_tab.b_actl = dp; 2582608Swnj } else 2592608Swnj dp->b_actl->av_forw = bp; 2602608Swnj dp->b_actl = bp; 2612608Swnj /* 2622608Swnj * If the controller is not busy, get 2632608Swnj * it going. 2642608Swnj */ 2652608Swnj if (um->um_tab.b_active == 0) 2662608Swnj tmstart(um); 2671919Swnj (void) spl0(); 2681919Swnj } 2691919Swnj 2702608Swnj /* 2712608Swnj * Start activity on a tm controller. 2722608Swnj */ 2732608Swnj tmstart(um) 274*2982Swnj register struct uba_ctlr *um; 2751919Swnj { 2762608Swnj register struct buf *bp, *dp; 2772608Swnj register struct device *addr = (struct device *)um->um_addr; 2782608Swnj register struct tm_softc *sc; 279*2982Swnj register struct uba_device *ui; 2802608Swnj int unit, cmd; 2812471Swnj daddr_t blkno; 2821919Swnj 2832608Swnj /* 2842608Swnj * Look for an idle transport on the controller. 2852608Swnj */ 2861919Swnj loop: 2872608Swnj if ((dp = um->um_tab.b_actf) == NULL) 2881919Swnj return; 2892608Swnj if ((bp = dp->b_actf) == NULL) { 2902608Swnj um->um_tab.b_actf = dp->b_forw; 2912608Swnj goto loop; 2922608Swnj } 2932608Swnj unit = TMUNIT(bp->b_dev); 2942608Swnj ui = tmdinfo[unit]; 2952608Swnj /* 2962608Swnj * Record pre-transfer status (e.g. for TM_SENSE) 2972608Swnj */ 2982608Swnj sc = &tm_softc[unit]; 2992608Swnj addr = (struct device *)um->um_addr; 3002608Swnj addr->tmcs = (ui->ui_slave << 8); 3012471Swnj sc->sc_dsreg = addr->tmcs; 3022471Swnj sc->sc_erreg = addr->tmer; 3032471Swnj sc->sc_resid = addr->tmbc; 3042608Swnj /* 3052608Swnj * Default is that last command was NOT a write command; 3062608Swnj * if we do a write command we will notice this in tmintr(). 3072608Swnj */ 3082608Swnj sc->sc_lastiow = 1; 3092608Swnj if (sc->sc_openf < 0 || (addr->tmcs&TM_CUR) == 0) { 3102608Swnj /* 3112608Swnj * Have had a hard error on this (non-raw) tape, 3122608Swnj * or the tape unit is now unavailable (e.g. taken off 3132608Swnj * line). 3142608Swnj */ 3152608Swnj bp->b_flags |= B_ERROR; 3161919Swnj goto next; 3171919Swnj } 3182608Swnj /* 3192608Swnj * If operation is not a control operation, 3202608Swnj * check for boundary conditions. 3212608Swnj */ 3222608Swnj if (bp != &ctmbuf[unit]) { 3232608Swnj if (dbtofsb(bp->b_blkno) > sc->sc_nxrec) { 3242608Swnj bp->b_flags |= B_ERROR; 3252608Swnj bp->b_error = ENXIO; /* past EOF */ 3262608Swnj goto next; 3271919Swnj } 3282608Swnj if (dbtofsb(bp->b_blkno) == sc->sc_nxrec && 3292608Swnj bp->b_flags&B_READ) { 3302608Swnj bp->b_resid = bp->b_bcount; 3312608Swnj clrbuf(bp); /* at EOF */ 3322608Swnj goto next; 3332608Swnj } 3342608Swnj if ((bp->b_flags&B_READ) == 0) 3352608Swnj /* write sets EOF */ 3362608Swnj sc->sc_nxrec = dbtofsb(bp->b_blkno) + 1; 3371919Swnj } 3382608Swnj /* 3392608Swnj * Set up the command, and then if this is a mt ioctl, 3402608Swnj * do the operation using, for TM_SFORW and TM_SREV, the specified 3412608Swnj * operation count. 3422608Swnj */ 3432608Swnj cmd = TM_IE | TM_GO | (ui->ui_slave << 8); 3442608Swnj if ((minor(bp->b_dev) & T_1600BPI) == 0) 3452608Swnj cmd |= TM_D800; 3462608Swnj if (bp == &ctmbuf[unit]) { 3472608Swnj if (bp->b_command == TM_SENSE) 3482608Swnj goto next; 3492608Swnj um->um_tab.b_active = 3502608Swnj bp->b_command == TM_REW ? SREW : SCOM; 3512608Swnj if (bp->b_command == TM_SFORW || bp->b_command == TM_SREV) 3522608Swnj addr->tmbc = bp->b_repcnt; 3532670Swnj goto dobpcmd; 3542608Swnj } 3552608Swnj /* 3562608Swnj * If the data transfer command is in the correct place, 3572608Swnj * set up all the registers except the csr, and give 3582608Swnj * control over to the UNIBUS adapter routines, to 3592608Swnj * wait for resources to start the i/o. 3602608Swnj */ 3612471Swnj if ((blkno = sc->sc_blkno) == dbtofsb(bp->b_blkno)) { 3622396Swnj addr->tmbc = -bp->b_bcount; 3631919Swnj if ((bp->b_flags&B_READ) == 0) { 3642471Swnj if (um->um_tab.b_errcnt) 3652608Swnj cmd |= TM_WIRG; 3661919Swnj else 3672608Swnj cmd |= TM_WCOM; 3681919Swnj } else 3692608Swnj cmd |= TM_RCOM; 3702471Swnj um->um_tab.b_active = SIO; 3712574Swnj um->um_cmd = cmd; 3722928Swnj #ifdef notdef 3732670Swnj if (tmreverseop(sc->sc_lastcmd)) 3742670Swnj while (addr->tmer & TM_SDWN) 3752670Swnj tmgapsdcnt++; 3762670Swnj sc->sc_lastcmd = TM_RCOM; /* will serve */ 3772928Swnj #endif 3782574Swnj ubago(ui); 3791919Swnj return; 3801919Swnj } 3812608Swnj /* 3822608Swnj * Block tape positioned incorrectly; 3832608Swnj * seek forwards or backwards to the correct spot. 3842608Swnj */ 3852471Swnj um->um_tab.b_active = SSEEK; 3861919Swnj if (blkno < dbtofsb(bp->b_blkno)) { 3872670Swnj bp->b_command = TM_SFORW; 3882396Swnj addr->tmbc = blkno - dbtofsb(bp->b_blkno); 3891919Swnj } else { 3902670Swnj bp->b_command = TM_SREV; 3912396Swnj addr->tmbc = dbtofsb(bp->b_blkno) - blkno; 3921919Swnj } 3932670Swnj dobpcmd: 3942928Swnj #ifdef notdef 3952670Swnj if (tmreverseop(sc->sc_lastcmd) != tmreverseop(bp->b_command)) 3962670Swnj while (addr->tmer & TM_SDWN) 3972670Swnj tmgapsdcnt++; 3982670Swnj sc->sc_lastcmd = bp->b_command; 3992928Swnj #endif 4002670Swnj addr->tmcs = (cmd | bp->b_command); 4011919Swnj return; 4021919Swnj 4031919Swnj next: 4042608Swnj /* 4052608Swnj * Done with this operation due to error or 4062608Swnj * the fact that it doesn't do anything. 4072608Swnj * Release UBA resources (if any), dequeue 4082608Swnj * the transfer and continue processing this slave. 4092608Swnj */ 4102608Swnj if (um->um_ubinfo) 4112617Swnj ubadone(um); 4122608Swnj um->um_tab.b_errcnt = 0; 4132608Swnj dp->b_actf = bp->av_forw; 4141919Swnj iodone(bp); 4151919Swnj goto loop; 4161919Swnj } 4171919Swnj 4182608Swnj /* 4192608Swnj * The UNIBUS resources we needed have been 4202608Swnj * allocated to us; start the device. 4212608Swnj */ 4222574Swnj tmdgo(um) 423*2982Swnj register struct uba_ctlr *um; 4241919Swnj { 4252574Swnj register struct device *addr = (struct device *)um->um_addr; 4262471Swnj 4272574Swnj addr->tmba = um->um_ubinfo; 4282574Swnj addr->tmcs = um->um_cmd | ((um->um_ubinfo >> 12) & 0x30); 4292396Swnj } 4302396Swnj 4312608Swnj /* 4322608Swnj * Tm interrupt routine. 4332608Swnj */ 4342471Swnj /*ARGSUSED*/ 4352630Swnj tmintr(tm11) 4362630Swnj int tm11; 4372396Swnj { 4382608Swnj struct buf *dp; 4391919Swnj register struct buf *bp; 440*2982Swnj register struct uba_ctlr *um = tmminfo[tm11]; 4412630Swnj register struct device *addr = (struct device *)tmdinfo[tm11]->ui_addr; 4422608Swnj register struct tm_softc *sc; 4432608Swnj int unit; 4441919Swnj register state; 4451919Swnj 4462608Swnj /* 4472608Swnj * If last command was a rewind, and tape is still 4482608Swnj * rewinding, wait for the rewind complete interrupt. 4492608Swnj */ 4502608Swnj if (um->um_tab.b_active == SREW) { 4512608Swnj um->um_tab.b_active = SCOM; 4522608Swnj if (addr->tmer&TM_RWS) 4532608Swnj return; 4541919Swnj } 4552608Swnj /* 4562608Swnj * An operation completed... record status 4572608Swnj */ 4582608Swnj if ((dp = um->um_tab.b_actf) == NULL) 4591919Swnj return; 4602608Swnj bp = dp->b_actf; 4612608Swnj unit = TMUNIT(bp->b_dev); 4622608Swnj sc = &tm_softc[unit]; 4632471Swnj sc->sc_dsreg = addr->tmcs; 4642471Swnj sc->sc_erreg = addr->tmer; 4652471Swnj sc->sc_resid = addr->tmbc; 4661919Swnj if ((bp->b_flags & B_READ) == 0) 4672608Swnj sc->sc_lastiow = 1; 4682471Swnj state = um->um_tab.b_active; 4692471Swnj um->um_tab.b_active = 0; 4702608Swnj /* 4712608Swnj * Check for errors. 4722608Swnj */ 4732608Swnj if (addr->tmcs&TM_ERR) { 4742608Swnj while (addr->tmer & TM_SDWN) 4751919Swnj ; /* await settle down */ 4762608Swnj /* 4772608Swnj * If we hit the end of the tape update our position. 4782608Swnj */ 4792608Swnj if (addr->tmer&TM_EOF) { 4802608Swnj tmseteof(bp); /* set blkno and nxrec */ 4812608Swnj state = SCOM; /* force completion */ 4822608Swnj /* 4832608Swnj * Stuff bc so it will be unstuffed correctly 4842608Swnj * later to get resid. 4852608Swnj */ 4862396Swnj addr->tmbc = -bp->b_bcount; 4872608Swnj goto opdone; 4881919Swnj } 4892608Swnj /* 4902608Swnj * If we were reading and the only error was that the 4912608Swnj * record was to long, then we don't consider this an error. 4922608Swnj */ 4932608Swnj if ((bp->b_flags&B_READ) && 4942608Swnj (addr->tmer&(TM_HARD|TM_SOFT)) == TM_RLE) 4952608Swnj goto ignoreerr; 4962608Swnj /* 4972608Swnj * If error is not hard, and this was an i/o operation 4982608Swnj * retry up to 8 times. 4992608Swnj */ 5002608Swnj if ((addr->tmer&TM_HARD)==0 && state==SIO) { 5012471Swnj if (++um->um_tab.b_errcnt < 7) { 5022471Swnj sc->sc_blkno++; 5032617Swnj ubadone(um); 5042608Swnj goto opcont; 5051919Swnj } 5062608Swnj } else 5072608Swnj /* 5082608Swnj * Hard or non-i/o errors on non-raw tape 5092608Swnj * cause it to close. 5102608Swnj */ 5112608Swnj if (sc->sc_openf>0 && bp != &rtmbuf[unit]) 5122608Swnj sc->sc_openf = -1; 5132608Swnj /* 5142608Swnj * Couldn't recover error 5152608Swnj */ 5162928Swnj printf("te%d: hard error bn%d er=%b\n", minor(bp->b_dev)&03, 5172928Swnj bp->b_blkno, sc->sc_erreg, TMEREG_BITS); 5181919Swnj bp->b_flags |= B_ERROR; 5192608Swnj goto opdone; 5201919Swnj } 5212608Swnj /* 5222608Swnj * Advance tape control FSM. 5232608Swnj */ 5242608Swnj ignoreerr: 5251919Swnj switch (state) { 5261919Swnj 5271919Swnj case SIO: 5282608Swnj /* 5292608Swnj * Read/write increments tape block number 5302608Swnj */ 5312471Swnj sc->sc_blkno++; 5322608Swnj goto opdone; 5331919Swnj 5341919Swnj case SCOM: 5352608Swnj /* 5362608Swnj * Unless special operation, op completed. 5372608Swnj */ 5382608Swnj if (bp != &ctmbuf[unit]) 5392608Swnj goto opdone; 5402608Swnj /* 5412608Swnj * Operation on block device... 5422608Swnj * iterate operations which don't repeat 5432608Swnj * for themselves in the hardware; for forward/ 5442608Swnj * backward space record update the current position. 5452608Swnj */ 5462608Swnj switch (bp->b_command) { 5471919Swnj 5482608Swnj case TM_SFORW: 5492608Swnj sc->sc_blkno -= bp->b_repcnt; 5502608Swnj goto opdone; 5511919Swnj 5522608Swnj case TM_SREV: 5532608Swnj sc->sc_blkno += bp->b_repcnt; 5542608Swnj goto opdone; 5552608Swnj 5562608Swnj default: 5572608Swnj if (++bp->b_repcnt < 0) 5582608Swnj goto opcont; 5592608Swnj goto opdone; 5601919Swnj } 5611919Swnj 5621919Swnj case SSEEK: 5632471Swnj sc->sc_blkno = dbtofsb(bp->b_blkno); 5642608Swnj goto opcont; 5651919Swnj 5661919Swnj default: 5672608Swnj panic("tmintr"); 5682608Swnj } 5692608Swnj opdone: 5702608Swnj /* 5712608Swnj * Reset error count and remove 5722608Swnj * from device queue. 5732608Swnj */ 5742608Swnj um->um_tab.b_errcnt = 0; 5752608Swnj dp->b_actf = bp->av_forw; 5762608Swnj bp->b_resid = -addr->tmbc; 5772617Swnj ubadone(um); 5782608Swnj iodone(bp); 5792608Swnj /* 5802608Swnj * Circulate slave to end of controller 5812608Swnj * queue to give other slaves a chance. 5822608Swnj */ 5832608Swnj um->um_tab.b_actf = dp->b_forw; 5842608Swnj if (dp->b_actf) { 5852608Swnj dp->b_forw = NULL; 5862608Swnj if (um->um_tab.b_actf == NULL) 5872608Swnj um->um_tab.b_actf = dp; 5882608Swnj else 5892608Swnj um->um_tab.b_actl->b_forw = dp; 5902608Swnj um->um_tab.b_actl = dp; 5912608Swnj } 5922608Swnj if (um->um_tab.b_actf == 0) 5931919Swnj return; 5942608Swnj opcont: 5952608Swnj tmstart(um); 5961919Swnj } 5971919Swnj 5981919Swnj tmseteof(bp) 5991919Swnj register struct buf *bp; 6001919Swnj { 6012608Swnj register int unit = TMUNIT(bp->b_dev); 6022396Swnj register struct device *addr = 6032608Swnj (struct device *)tmdinfo[unit]->ui_addr; 6042608Swnj register struct tm_softc *sc = &tm_softc[unit]; 6051919Swnj 6062608Swnj if (bp == &ctmbuf[unit]) { 6072471Swnj if (sc->sc_blkno > dbtofsb(bp->b_blkno)) { 6081919Swnj /* reversing */ 6092471Swnj sc->sc_nxrec = dbtofsb(bp->b_blkno) - addr->tmbc; 6102471Swnj sc->sc_blkno = sc->sc_nxrec; 6111919Swnj } else { 6121919Swnj /* spacing forward */ 6132471Swnj sc->sc_blkno = dbtofsb(bp->b_blkno) + addr->tmbc; 6142471Swnj sc->sc_nxrec = sc->sc_blkno - 1; 6151919Swnj } 6161919Swnj return; 6171919Swnj } 6181919Swnj /* eof on read */ 6192471Swnj sc->sc_nxrec = dbtofsb(bp->b_blkno); 6201919Swnj } 6211919Swnj 6221919Swnj tmread(dev) 6232608Swnj dev_t dev; 6241919Swnj { 6251919Swnj 6261919Swnj tmphys(dev); 627*2982Swnj if (u.u_error) 628*2982Swnj return; 6292608Swnj physio(tmstrategy, &rtmbuf[TMUNIT(dev)], dev, B_READ, minphys); 6301919Swnj } 6311919Swnj 6321919Swnj tmwrite(dev) 6332608Swnj dev_t dev; 6341919Swnj { 6351919Swnj 6361919Swnj tmphys(dev); 637*2982Swnj if (u.u_error) 638*2982Swnj return; 6392608Swnj physio(tmstrategy, &rtmbuf[TMUNIT(dev)], dev, B_WRITE, minphys); 6401919Swnj } 6411919Swnj 6421919Swnj tmphys(dev) 6432608Swnj dev_t dev; 6441919Swnj { 645*2982Swnj register int unit = TMUNIT(dev); 6461919Swnj register daddr_t a; 647*2982Swnj register struct tm_softc *sc; 6481919Swnj 649*2982Swnj if (unit >= NTM) { 650*2982Swnj u.u_error = ENXIO; 651*2982Swnj return; 652*2982Swnj } 653*2982Swnj sc = &tm_softc[TMUNIT(dev)]; 6541919Swnj a = dbtofsb(u.u_offset >> 9); 6552471Swnj sc->sc_blkno = a; 6562471Swnj sc->sc_nxrec = a + 1; 6571919Swnj } 6581919Swnj 6592608Swnj tmreset(uban) 6602608Swnj int uban; 6612608Swnj { 662*2982Swnj register struct uba_ctlr *um; 6632630Swnj register tm11, unit; 664*2982Swnj register struct uba_device *ui; 6652608Swnj register struct buf *dp; 6662608Swnj 6672630Swnj for (tm11 = 0; tm11 < NTM; tm11++) { 6682630Swnj if ((um = tmminfo[tm11]) == 0 || um->um_alive == 0 || 6692608Swnj um->um_ubanum != uban) 6702608Swnj continue; 6712928Swnj printf(" tm%d", tm11); 6722608Swnj um->um_tab.b_active = 0; 6732608Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 6742608Swnj if (um->um_ubinfo) { 6752608Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 6762617Swnj ubadone(um); 6772608Swnj } 6782608Swnj ((struct device *)(um->um_addr))->tmcs = TM_DCLR; 6792630Swnj for (unit = 0; unit < NTE; unit++) { 6802608Swnj if ((ui = tmdinfo[unit]) == 0) 6812608Swnj continue; 6822608Swnj if (ui->ui_alive == 0) 6832608Swnj continue; 6842608Swnj dp = &tmutab[unit]; 6852608Swnj dp->b_active = 0; 6862608Swnj dp->b_forw = 0; 6872608Swnj if (um->um_tab.b_actf == NULL) 6882608Swnj um->um_tab.b_actf = dp; 6892608Swnj else 6902608Swnj um->um_tab.b_actl->b_forw = dp; 6912608Swnj um->um_tab.b_actl = dp; 6922608Swnj tm_softc[unit].sc_openf = -1; 6932608Swnj } 6942608Swnj tmstart(um); 6952608Swnj } 6962608Swnj } 6972608Swnj 6981919Swnj /*ARGSUSED*/ 6991919Swnj tmioctl(dev, cmd, addr, flag) 7001919Swnj caddr_t addr; 7011919Swnj dev_t dev; 7021919Swnj { 7032608Swnj int unit = TMUNIT(dev); 7042608Swnj register struct tm_softc *sc = &tm_softc[unit]; 7052608Swnj register struct buf *bp = &ctmbuf[unit]; 7061919Swnj register callcount; 7071919Swnj int fcount; 7081919Swnj struct mtop mtop; 7091919Swnj struct mtget mtget; 7101919Swnj /* we depend of the values and order of the MT codes here */ 7112608Swnj static tmops[] = 7122608Swnj {TM_WEOF,TM_SFORW,TM_SREV,TM_SFORW,TM_SREV,TM_REW,TM_OFFL,TM_SENSE}; 7131919Swnj 7142608Swnj switch (cmd) { 7151919Swnj case MTIOCTOP: /* tape operation */ 7161919Swnj if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) { 7171919Swnj u.u_error = EFAULT; 7181919Swnj return; 7191919Swnj } 7201919Swnj switch(mtop.mt_op) { 7212608Swnj case MTWEOF: 7221919Swnj callcount = mtop.mt_count; 7232608Swnj fcount = 1; 7242608Swnj break; 7252608Swnj case MTFSF: case MTBSF: 7262608Swnj callcount = mtop.mt_count; 7271919Swnj fcount = INF; 7281919Swnj break; 7291919Swnj case MTFSR: case MTBSR: 7301919Swnj callcount = 1; 7311919Swnj fcount = mtop.mt_count; 7321919Swnj break; 7332324Skre case MTREW: case MTOFFL: case MTNOP: 7341919Swnj callcount = 1; 7351919Swnj fcount = 1; 7361919Swnj break; 7371919Swnj default: 7381919Swnj u.u_error = ENXIO; 7391919Swnj return; 7401919Swnj } 7412608Swnj if (callcount <= 0 || fcount <= 0) { 7421919Swnj u.u_error = ENXIO; 7432608Swnj return; 7442608Swnj } 7452608Swnj while (--callcount >= 0) { 7462574Swnj tmcommand(dev, tmops[mtop.mt_op], fcount); 7471919Swnj if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) && 7482608Swnj bp->b_resid) { 7491919Swnj u.u_error = EIO; 7501919Swnj break; 7511919Swnj } 7522608Swnj if ((bp->b_flags&B_ERROR) || sc->sc_erreg&TM_BOT) 7531919Swnj break; 7541919Swnj } 7552608Swnj geterror(bp); 7561919Swnj return; 7571919Swnj case MTIOCGET: 7582471Swnj mtget.mt_dsreg = sc->sc_dsreg; 7592471Swnj mtget.mt_erreg = sc->sc_erreg; 7602471Swnj mtget.mt_resid = sc->sc_resid; 7611919Swnj if (copyout((caddr_t)&mtget, addr, sizeof(mtget))) 7621919Swnj u.u_error = EFAULT; 7631919Swnj return; 7641919Swnj default: 7651919Swnj u.u_error = ENXIO; 7661919Swnj } 7671919Swnj } 7681919Swnj 7691919Swnj #define DBSIZE 20 7701919Swnj 7712363Swnj tmdump() 7722363Swnj { 773*2982Swnj register struct uba_device *ui; 7742396Swnj register struct uba_regs *up; 7752396Swnj register struct device *addr; 7762426Skre int blk, num; 7772426Skre int start; 7781919Swnj 7792426Skre start = 0; 7802426Skre num = maxfree; 7812426Skre #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 7822887Swnj if (tmdinfo[0] == 0) 7832887Swnj return (ENXIO); 784*2982Swnj ui = phys(tmdinfo[0], struct uba_device *); 7852396Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 7862396Swnj #if VAX780 7872396Swnj if (cpu == VAX_780) 7882396Swnj ubainit(up); 7891919Swnj #endif 7902324Skre DELAY(1000000); 7912396Swnj addr = (struct device *)ui->ui_physaddr; 7922396Swnj tmwait(addr); 7932608Swnj addr->tmcs = TM_DCLR | TM_GO; 7941919Swnj while (num > 0) { 7951919Swnj blk = num > DBSIZE ? DBSIZE : num; 7962396Swnj tmdwrite(start, blk, addr, up); 7971919Swnj start += blk; 7981919Swnj num -= blk; 7991919Swnj } 8002426Skre tmeof(addr); 8012426Skre tmeof(addr); 8022426Skre tmwait(addr); 8032887Swnj if (addr->tmcs&TM_ERR) 8042887Swnj return (EIO); 8052608Swnj addr->tmcs = TM_REW | TM_GO; 8062471Swnj tmwait(addr); 8072363Swnj return (0); 8081919Swnj } 8091919Swnj 8102608Swnj tmdwrite(dbuf, num, addr, up) 8112608Swnj register dbuf, num; 8122396Swnj register struct device *addr; 8132396Swnj struct uba_regs *up; 8141919Swnj { 8152396Swnj register struct pte *io; 8162396Swnj register int npf; 8171928Swnj 8182396Swnj tmwait(addr); 8192396Swnj io = up->uba_map; 8201919Swnj npf = num+1; 8211928Swnj while (--npf != 0) 822*2982Swnj *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); 8232396Swnj *(int *)io = 0; 8242396Swnj addr->tmbc = -(num*NBPG); 8252396Swnj addr->tmba = 0; 8262608Swnj addr->tmcs = TM_WCOM | TM_GO; 8271919Swnj } 8281919Swnj 8292396Swnj tmwait(addr) 8302396Swnj register struct device *addr; 8311919Swnj { 8321928Swnj register s; 8331919Swnj 8341919Swnj do 8352396Swnj s = addr->tmcs; 8362608Swnj while ((s & TM_CUR) == 0); 8371919Swnj } 8381919Swnj 8392396Swnj tmeof(addr) 8402396Swnj struct device *addr; 8411919Swnj { 8421919Swnj 8432396Swnj tmwait(addr); 8442608Swnj addr->tmcs = TM_WEOF | TM_GO; 8451919Swnj } 8461919Swnj #endif 847