1*2426Skre /* tm.c 4.10 02/15/81 */ 21919Swnj 31940Swnj #include "tm.h" 41919Swnj #if NTM > 0 51919Swnj /* 61919Swnj * TM tape driver 71919Swnj */ 82324Skre #define DELAY(N) { register int d; d = N; while (--d > 0); } 91919Swnj #include "../h/param.h" 101919Swnj #include "../h/buf.h" 111919Swnj #include "../h/dir.h" 121919Swnj #include "../h/conf.h" 131919Swnj #include "../h/user.h" 141919Swnj #include "../h/file.h" 151919Swnj #include "../h/map.h" 161919Swnj #include "../h/pte.h" 171919Swnj #include "../h/uba.h" 181919Swnj #include "../h/mtio.h" 191919Swnj #include "../h/ioctl.h" 201919Swnj #include "../h/vm.h" 212363Swnj #include "../h/cmap.h" 222396Swnj #include "../h/cpu.h" 231919Swnj 242396Swnj #include "../h/tmreg.h" 251919Swnj 261919Swnj struct buf tmtab; 271919Swnj struct buf ctmbuf; 281919Swnj struct buf rtmbuf; 291919Swnj 302396Swnj int tmcntrlr(), tmslave(), tmdgo(), tmintr(); 312396Swnj struct uba_dinfo *tminfo[NTM]; 32*2426Skre extern u_short tmstd[]; 332396Swnj struct uba_driver tmdriver = 34*2426Skre { tmcntrlr, tmslave, tmdgo, 4, 0, tmstd, "tm", tminfo }; 351919Swnj int tm_ubinfo; 361919Swnj 371919Swnj /* bits in minor device */ 381919Swnj #define T_NOREWIND 04 391919Swnj #define T_1600BPI 08 401919Swnj 411919Swnj #define INF (daddr_t)1000000L 421919Swnj 431919Swnj /* 441919Swnj * Really only handle one tape drive... if you have more than one, 452396Swnj * you can put all these (and some of the above) in a structure, 462396Swnj * change the obvious things, and make tmslave smarter, but 471919Swnj * it is not clear what happens when some drives are transferring while 481919Swnj * others rewind, so we don't pretend that this driver handles multiple 491919Swnj * tape drives. 501919Swnj */ 511919Swnj char t_openf; 521919Swnj daddr_t t_blkno; 531919Swnj char t_flags; 541919Swnj daddr_t t_nxrec; 551919Swnj u_short t_erreg; 561919Swnj u_short t_dsreg; 571919Swnj short t_resid; 581919Swnj 591919Swnj #define SSEEK 1 /* seeking */ 601919Swnj #define SIO 2 /* doing seq i/o */ 611919Swnj #define SCOM 3 /* sending control command */ 621919Swnj 631919Swnj #define LASTIOW 1 /* last op was a write */ 641919Swnj #define WAITREW 2 /* someone is waiting for a rewind */ 651919Swnj 66*2426Skre /* 67*2426Skre * Determine if there is a controller for 68*2426Skre * a tm at address reg. Our goal is to make the 69*2426Skre * device interrupt. 70*2426Skre * THE ARGUMENT UI IS OBSOLETE 71*2426Skre */ 722396Swnj tmcntrlr(ui, reg) 732396Swnj struct uba_dinfo *ui; 742396Swnj caddr_t reg; 752396Swnj { 76*2426Skre 772396Swnj ((struct device *)reg)->tmcs = IENABLE; 782396Swnj /* 792396Swnj * If this is a tm03/tc11, it ought to have interrupted 802396Swnj * by now, if it isn't (ie: it is a ts04) then we just 812396Swnj * pray that it didn't interrupt, so autoconf will ignore it 822396Swnj * - just in case out prayers fail, we will reference one 832396Swnj * of the more distant registers, and hope for a machine 842396Swnj * check, or similar disaster 852396Swnj */ 862396Swnj if (badaddr(&((struct device *)reg)->tmrd, 2)) 872396Swnj return(0); 882396Swnj return(1); 892396Swnj } 902396Swnj 912396Swnj tmslave(ui, reg, slaveno) 922396Swnj struct uba_dinfo *ui; 932396Swnj caddr_t reg; 942396Swnj { 952396Swnj /* 962396Swnj * Due to a design flaw, we cannot ascertain if the tape 972396Swnj * exists or not unless it is on line - ie: unless a tape is 982396Swnj * mounted. This is too servere a restriction to bear. 992396Swnj * As we can only handle one tape, we might just as well insist 1002396Swnj * that it be slave #0, and just assume that it exists. 1012396Swnj * Something better will have to be done if you have two 1022396Swnj * tapes on one controller, or two controllers 1032396Swnj */ 104*2426Skre printf("tm: sl %d - tmi %x\n", slaveno, tminfo[0]); 1052396Swnj if (slaveno != 0 || tminfo[0]) 1062396Swnj return(0); 1072396Swnj return(1); 1082396Swnj } 1092396Swnj 1101919Swnj tmopen(dev, flag) 1111919Swnj dev_t dev; 1121919Swnj int flag; 1131919Swnj { 1141919Swnj register ds, unit; 1152396Swnj register struct uba_dinfo *ui; 1161919Swnj 1171919Swnj tmtab.b_flags |= B_TAPE; 1181919Swnj unit = minor(dev)&03; 119*2426Skre if (unit>=NTM || t_openf || !(ui = tminfo[minor(dev)&03])->ui_alive) { 1201919Swnj u.u_error = ENXIO; /* out of range or open */ 1211919Swnj return; 1221919Swnj } 1231919Swnj tcommand(dev, NOP, 1); 1241919Swnj if ((t_erreg&SELR) == 0) { 1251919Swnj u.u_error = EIO; /* offline */ 1261919Swnj return; 1271919Swnj } 1281919Swnj t_openf = 1; 1291919Swnj if (t_erreg&RWS) 1301919Swnj tmwaitrws(dev); /* wait for rewind complete */ 1311919Swnj while (t_erreg&SDWN) 1321919Swnj tcommand(dev, NOP, 1); /* await settle down */ 1331919Swnj if ((t_erreg&TUR)==0 || 1341919Swnj ((flag&(FREAD|FWRITE)) == FWRITE && (t_erreg&WRL))) { 1352396Swnj ((struct device *)ui->ui_addr)->tmcs = DCLR|GO; 1361919Swnj u.u_error = EIO; /* offline or write protect */ 1371919Swnj } 1381919Swnj if (u.u_error != 0) { 1391919Swnj t_openf = 0; 1401919Swnj return; 1411919Swnj } 1421919Swnj t_blkno = (daddr_t)0; 1431919Swnj t_nxrec = INF; 1441919Swnj t_flags = 0; 1451919Swnj t_openf = 1; 1461919Swnj } 1471919Swnj 1481919Swnj tmwaitrws(dev) 1491919Swnj register dev; 1501919Swnj { 1512396Swnj register struct device *addr = 152*2426Skre (struct device *)tminfo[minor(dev)&03]->ui_addr; 1531919Swnj 1541919Swnj spl5(); 1551919Swnj for (;;) { 1562396Swnj if ((addr->tmer&RWS) == 0) { 1571919Swnj spl0(); /* rewind complete */ 1581919Swnj return; 1591919Swnj } 1601919Swnj t_flags |= WAITREW; 1611919Swnj sleep((caddr_t)&t_flags, PRIBIO); 1621919Swnj } 1631919Swnj } 1641919Swnj 1651919Swnj tmclose(dev, flag) 1661919Swnj register dev_t dev; 1671919Swnj register flag; 1681919Swnj { 1691919Swnj 1701919Swnj if (flag == FWRITE || ((flag&FWRITE) && (t_flags&LASTIOW))) { 1711919Swnj tcommand(dev, WEOF, 1); 1721919Swnj tcommand(dev, WEOF, 1); 1731919Swnj tcommand(dev, SREV, 1); 1741919Swnj } 1751919Swnj if ((minor(dev)&T_NOREWIND) == 0) 1761919Swnj tcommand(dev, REW, 1); 1771919Swnj t_openf = 0; 1781919Swnj } 1791919Swnj 1801919Swnj tcommand(dev, com, count) 1811919Swnj dev_t dev; 1821919Swnj int com, count; 1831919Swnj { 1841919Swnj register struct buf *bp; 1851919Swnj 1861919Swnj bp = &ctmbuf; 1871919Swnj (void) spl5(); 1881919Swnj while (bp->b_flags&B_BUSY) { 1891919Swnj bp->b_flags |= B_WANTED; 1901919Swnj sleep((caddr_t)bp, PRIBIO); 1911919Swnj } 1921919Swnj bp->b_flags = B_BUSY|B_READ; 1931919Swnj (void) spl0(); 1941919Swnj bp->b_dev = dev; 1951919Swnj bp->b_repcnt = -count; 1961919Swnj bp->b_command = com; 1971919Swnj bp->b_blkno = 0; 1981919Swnj tmstrategy(bp); 1991919Swnj iowait(bp); 2001919Swnj if (bp->b_flags&B_WANTED) 2011919Swnj wakeup((caddr_t)bp); 2021919Swnj bp->b_flags &= B_ERROR; 2031919Swnj } 2041919Swnj 2051919Swnj tmstrategy(bp) 2061919Swnj register struct buf *bp; 2071919Swnj { 2081919Swnj register daddr_t *p; 2091919Swnj 2101928Swnj tmwaitrws(bp->b_dev); 2111919Swnj if (bp != &ctmbuf) { 2121919Swnj p = &t_nxrec; 2131919Swnj if (dbtofsb(bp->b_blkno) > *p) { 2141919Swnj bp->b_flags |= B_ERROR; 2151919Swnj bp->b_error = ENXIO; /* past EOF */ 2161919Swnj iodone(bp); 2171919Swnj return; 2181919Swnj } else if (dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) { 2191919Swnj bp->b_resid = bp->b_bcount; 2201919Swnj clrbuf(bp); /* at EOF */ 2211919Swnj iodone(bp); 2221919Swnj return; 2231919Swnj } else if ((bp->b_flags&B_READ) == 0) 2241919Swnj *p = dbtofsb(bp->b_blkno) + 1; /* write sets EOF */ 2251919Swnj } 2261919Swnj bp->av_forw = NULL; 2271919Swnj (void) spl5(); 2281919Swnj if (tmtab.b_actf == NULL) 2291919Swnj tmtab.b_actf = bp; 2301919Swnj else 2311919Swnj tmtab.b_actl->av_forw = bp; 2321919Swnj tmtab.b_actl = bp; 2331919Swnj if (tmtab.b_active == 0) 2341919Swnj tmstart(); 2351919Swnj (void) spl0(); 2361919Swnj } 2371919Swnj 2381919Swnj tmstart() 2391919Swnj { 2401919Swnj register struct buf *bp; 2412396Swnj register struct uba_dinfo *ui; 2422396Swnj register struct device *addr; 2431919Swnj register cmd; 2441919Swnj register daddr_t blkno; 2452054Swnj int s; 2461919Swnj 2471919Swnj loop: 2481919Swnj if ((bp = tmtab.b_actf) == 0) 2491919Swnj return; 250*2426Skre ui = tminfo[minor(bp->b_dev)&03]; 2512396Swnj addr = (struct device *)ui->ui_addr; 2522396Swnj t_dsreg = addr->tmcs; 2532396Swnj t_erreg = addr->tmer; 2542396Swnj t_resid = addr->tmbc; 2551919Swnj t_flags &= ~LASTIOW; 2562396Swnj if (t_openf < 0 || (addr->tmcs&CUR) == 0) { 2571919Swnj /* t_openf = -1; ??? */ 2581919Swnj bp->b_flags |= B_ERROR; /* hard error'ed or !SELR */ 2591919Swnj goto next; 2601919Swnj } 2611919Swnj cmd = IENABLE | GO; 2621919Swnj if ((minor(bp->b_dev) & T_1600BPI) == 0) 2631919Swnj cmd |= D800; 2641919Swnj if (bp == &ctmbuf) { 2651919Swnj if (bp->b_command == NOP) 2661919Swnj goto next; /* just get status */ 2671919Swnj else { 2681919Swnj cmd |= bp->b_command; 2691919Swnj tmtab.b_active = SCOM; 2701919Swnj if (bp->b_command == SFORW || bp->b_command == SREV) 2712396Swnj addr->tmbc = bp->b_repcnt; 2722396Swnj addr->tmcs = cmd; 2731919Swnj return; 2741919Swnj } 2751919Swnj } 2761919Swnj if ((blkno = t_blkno) == dbtofsb(bp->b_blkno)) { 2772396Swnj addr->tmbc = -bp->b_bcount; 2782054Swnj s = spl6(); 2791919Swnj if (tm_ubinfo == 0) 2802396Swnj tm_ubinfo = ubasetup(ui->ui_ubanum, bp, 1); 2812054Swnj splx(s); 2821919Swnj if ((bp->b_flags&B_READ) == 0) { 2831919Swnj if (tmtab.b_errcnt) 2841919Swnj cmd |= WIRG; 2851919Swnj else 2861919Swnj cmd |= WCOM; 2871919Swnj } else 2881919Swnj cmd |= RCOM; 2891919Swnj cmd |= (tm_ubinfo >> 12) & 0x30; 2901919Swnj tmtab.b_active = SIO; 2912396Swnj addr->tmba = tm_ubinfo; 2922396Swnj addr->tmcs = cmd; 2931919Swnj return; 2941919Swnj } 2951919Swnj tmtab.b_active = SSEEK; 2961919Swnj if (blkno < dbtofsb(bp->b_blkno)) { 2971919Swnj cmd |= SFORW; 2982396Swnj addr->tmbc = blkno - dbtofsb(bp->b_blkno); 2991919Swnj } else { 3001919Swnj cmd |= SREV; 3012396Swnj addr->tmbc = dbtofsb(bp->b_blkno) - blkno; 3021919Swnj } 3032396Swnj addr->tmcs = cmd; 3041919Swnj return; 3051919Swnj 3061919Swnj next: 3072396Swnj ubarelse(ui->ui_ubanum, &tm_ubinfo); 3081919Swnj tmtab.b_actf = bp->av_forw; 3091919Swnj iodone(bp); 3101919Swnj goto loop; 3111919Swnj } 3121919Swnj 3132396Swnj tmdgo() 3141919Swnj { 3152396Swnj } 3162396Swnj 3172396Swnj tmintr(d) 3182396Swnj { 3191919Swnj register struct buf *bp; 3202396Swnj register struct device *addr = (struct device *)tminfo[d]->ui_addr; 3211919Swnj register state; 3221919Swnj 3232396Swnj if (t_flags&WAITREW && (addr->tmer&RWS) == 0) { 3241919Swnj t_flags &= ~WAITREW; 3251919Swnj wakeup((caddr_t)&t_flags); 3261919Swnj } 3271919Swnj if ((bp = tmtab.b_actf) == NULL) 3281919Swnj return; 3292396Swnj t_dsreg = addr->tmcs; 3302396Swnj t_erreg = addr->tmer; 3312396Swnj t_resid = addr->tmbc; 3321919Swnj if ((bp->b_flags & B_READ) == 0) 3331919Swnj t_flags |= LASTIOW; 3341919Swnj state = tmtab.b_active; 3351919Swnj tmtab.b_active = 0; 3362396Swnj if (addr->tmcs&ERROR) { 3372396Swnj while(addr->tmer & SDWN) 3381919Swnj ; /* await settle down */ 3392396Swnj if (addr->tmer&EOF) { 3401919Swnj tmseteof(bp); /* set blkno and nxrec */ 3411919Swnj state = SCOM; 3422396Swnj addr->tmbc = -bp->b_bcount; 3431919Swnj goto errout; 3441919Swnj } 3452396Swnj if ((bp->b_flags&B_READ) && (addr->tmer&(HARD|SOFT)) == RLE) 3461919Swnj goto out; 3472396Swnj if ((addr->tmer&HARD)==0 && state==SIO) { 3481928Swnj if (++tmtab.b_errcnt < 7) { 3492396Swnj if((addr->tmer&SOFT) == NXM) 3501919Swnj printf("TM UBA late error\n"); 351*2426Skre t_blkno++; 3522396Swnj ubarelse(tminfo[d]->ui_ubanum, &tm_ubinfo); 3531919Swnj tmstart(); 3541919Swnj return; 3551919Swnj } 3561919Swnj } else if (t_openf>0 && bp != &rtmbuf) 3571919Swnj t_openf = -1; 3581928Swnj deverror(bp, t_erreg, t_dsreg); 3591919Swnj bp->b_flags |= B_ERROR; 3601919Swnj state = SIO; 3611919Swnj } 3621919Swnj out: 3631919Swnj switch (state) { 3641919Swnj 3651919Swnj case SIO: 3661919Swnj t_blkno++; 3671919Swnj /* fall into ... */ 3681919Swnj 3691919Swnj case SCOM: 3701919Swnj if (bp == &ctmbuf) { 3711919Swnj switch (bp->b_command) { 3721919Swnj case SFORW: 3731919Swnj t_blkno -= bp->b_repcnt; 3741919Swnj break; 3751919Swnj 3761919Swnj case SREV: 3771919Swnj t_blkno += bp->b_repcnt; 3781919Swnj break; 3791919Swnj 3801919Swnj default: 3811919Swnj if (++bp->b_repcnt < 0) { 3821919Swnj tmstart(); /* continue */ 3831919Swnj return; 3841919Swnj } 3851919Swnj } 3861919Swnj } 3871919Swnj errout: 3881919Swnj tmtab.b_errcnt = 0; 3891919Swnj tmtab.b_actf = bp->av_forw; 3902396Swnj bp->b_resid = -addr->tmbc; 3912396Swnj ubarelse(tminfo[d]->ui_ubanum, &tm_ubinfo); 3921919Swnj iodone(bp); 3931919Swnj break; 3941919Swnj 3951919Swnj case SSEEK: 3961919Swnj t_blkno = dbtofsb(bp->b_blkno); 3971919Swnj break; 3981919Swnj 3991919Swnj default: 4001919Swnj return; 4011919Swnj } 4021919Swnj tmstart(); 4031919Swnj } 4041919Swnj 4051919Swnj tmseteof(bp) 4061919Swnj register struct buf *bp; 4071919Swnj { 4082396Swnj register struct device *addr = 409*2426Skre (struct device *)tminfo[minor(bp->b_dev)&03]->ui_addr; 4101919Swnj 4111919Swnj if (bp == &ctmbuf) { 4121919Swnj if (t_blkno > dbtofsb(bp->b_blkno)) { 4131919Swnj /* reversing */ 4142396Swnj t_nxrec = dbtofsb(bp->b_blkno) - addr->tmbc; 4151919Swnj t_blkno = t_nxrec; 4161919Swnj } else { 4171919Swnj /* spacing forward */ 4182396Swnj t_blkno = dbtofsb(bp->b_blkno) + addr->tmbc; 4191919Swnj t_nxrec = t_blkno - 1; 4201919Swnj } 4211919Swnj return; 4221919Swnj } 4231919Swnj /* eof on read */ 4241919Swnj t_nxrec = dbtofsb(bp->b_blkno); 4251919Swnj } 4261919Swnj 4271919Swnj tmread(dev) 4281919Swnj { 4291919Swnj 4301919Swnj tmphys(dev); 4311919Swnj physio(tmstrategy, &rtmbuf, dev, B_READ, minphys); 4321919Swnj } 4331919Swnj 4341919Swnj tmwrite(dev) 4351919Swnj { 4361919Swnj 4371919Swnj tmphys(dev); 4381919Swnj physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys); 4391919Swnj } 4401919Swnj 4411919Swnj tmphys(dev) 4421919Swnj { 4431919Swnj register daddr_t a; 4441919Swnj 4451919Swnj a = dbtofsb(u.u_offset >> 9); 4461919Swnj t_blkno = a; 4471919Swnj t_nxrec = a + 1; 4481919Swnj } 4491919Swnj 4501919Swnj /*ARGSUSED*/ 4511919Swnj tmioctl(dev, cmd, addr, flag) 4521919Swnj caddr_t addr; 4531919Swnj dev_t dev; 4541919Swnj { 4551919Swnj register callcount; 4561919Swnj int fcount; 4571919Swnj struct mtop mtop; 4581919Swnj struct mtget mtget; 4591919Swnj /* we depend of the values and order of the MT codes here */ 4602324Skre static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL, NOP}; 4611919Swnj 4621919Swnj switch(cmd) { 4631919Swnj case MTIOCTOP: /* tape operation */ 4641919Swnj if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) { 4651919Swnj u.u_error = EFAULT; 4661919Swnj return; 4671919Swnj } 4681919Swnj switch(mtop.mt_op) { 4691919Swnj case MTWEOF: case MTFSF: case MTBSF: 4701919Swnj callcount = mtop.mt_count; 4711919Swnj fcount = INF; 4721919Swnj break; 4731919Swnj case MTFSR: case MTBSR: 4741919Swnj callcount = 1; 4751919Swnj fcount = mtop.mt_count; 4761919Swnj break; 4772324Skre case MTREW: case MTOFFL: case MTNOP: 4781919Swnj callcount = 1; 4791919Swnj fcount = 1; 4801919Swnj break; 4811919Swnj default: 4821919Swnj u.u_error = ENXIO; 4831919Swnj return; 4841919Swnj } 4851919Swnj if (callcount <= 0 || fcount <= 0) 4861919Swnj u.u_error = ENXIO; 4871919Swnj else while (--callcount >= 0) { 4881919Swnj tcommand(dev, tmops[mtop.mt_op], fcount); 4891919Swnj if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) && 4901919Swnj ctmbuf.b_resid) { 4911919Swnj u.u_error = EIO; 4921919Swnj break; 4931919Swnj } 4941919Swnj if ((ctmbuf.b_flags&B_ERROR) || t_erreg&BOT) 4951919Swnj break; 4961919Swnj } 4971919Swnj geterror(&ctmbuf); 4981919Swnj return; 4991919Swnj case MTIOCGET: 5001919Swnj mtget.mt_dsreg = t_dsreg; 5011919Swnj mtget.mt_erreg = t_erreg; 5021919Swnj mtget.mt_resid = t_resid; 5031919Swnj if (copyout((caddr_t)&mtget, addr, sizeof(mtget))) 5041919Swnj u.u_error = EFAULT; 5051919Swnj return; 5061919Swnj default: 5071919Swnj u.u_error = ENXIO; 5081919Swnj } 5091919Swnj } 5101919Swnj 5111919Swnj #define DBSIZE 20 5121919Swnj 5132363Swnj tmdump() 5142363Swnj { 5152396Swnj register struct uba_dinfo *ui; 5162396Swnj register struct uba_regs *up; 5172396Swnj register struct device *addr; 518*2426Skre int blk, num; 519*2426Skre int start; 5201919Swnj 521*2426Skre start = 0; 522*2426Skre num = maxfree; 523*2426Skre #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 5242396Swnj if (tminfo[0] == 0) { 5252396Swnj printf("dna\n"); 5262396Swnj return (-1); 5272396Swnj } 5282396Swnj ui = phys(tminfo[0], struct uba_dinfo *); 5292396Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 5302396Swnj #if VAX780 5312396Swnj if (cpu == VAX_780) 5322396Swnj ubainit(up); 5331919Swnj #endif 5342324Skre DELAY(1000000); 5352396Swnj addr = (struct device *)ui->ui_physaddr; 5362396Swnj tmwait(addr); 5372396Swnj addr->tmcs = DCLR | GO; 5381919Swnj while (num > 0) { 5391919Swnj blk = num > DBSIZE ? DBSIZE : num; 5402396Swnj tmdwrite(start, blk, addr, up); 5411919Swnj start += blk; 5421919Swnj num -= blk; 5431919Swnj } 544*2426Skre tmwait(addr); 545*2426Skre tmeof(addr); 546*2426Skre tmeof(addr); 547*2426Skre tmrewind(addr); 548*2426Skre tmwait(addr); 5492363Swnj return (0); 5501919Swnj } 5511919Swnj 5522396Swnj tmdwrite(buf, num, addr, up) 5532396Swnj register buf, num; 5542396Swnj register struct device *addr; 5552396Swnj struct uba_regs *up; 5561919Swnj { 5572396Swnj register struct pte *io; 5582396Swnj register int npf; 5591928Swnj 5602396Swnj tmwait(addr); 5612396Swnj io = up->uba_map; 5621919Swnj npf = num+1; 5631928Swnj while (--npf != 0) 5642396Swnj *(int *)io++ = (buf++ | (1<<UBA_DPSHIFT) | UBA_MRV); 5652396Swnj *(int *)io = 0; 5662396Swnj addr->tmbc = -(num*NBPG); 5672396Swnj addr->tmba = 0; 5682396Swnj addr->tmcs = WCOM | GO; 5691919Swnj } 5701919Swnj 5712396Swnj tmwait(addr) 5722396Swnj register struct device *addr; 5731919Swnj { 5741928Swnj register s; 5751919Swnj 5761919Swnj do 5772396Swnj s = addr->tmcs; 5781919Swnj while ((s & CUR) == 0); 5791919Swnj } 5801919Swnj 5812396Swnj tmrewind(addr) 5822396Swnj struct device *addr; 5831919Swnj { 5841919Swnj 5852396Swnj tmwait(addr); 5862396Swnj addr->tmcs = REW | GO; 5871919Swnj } 5881919Swnj 5892396Swnj tmeof(addr) 5902396Swnj struct device *addr; 5911919Swnj { 5921919Swnj 5932396Swnj tmwait(addr); 5942396Swnj addr->tmcs = WEOF | GO; 5951919Swnj } 5961919Swnj #endif 597