1*2396Swnj /* tm.c 4.9 02/10/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" 22*2396Swnj #include "../h/cpu.h" 231919Swnj 24*2396Swnj #include "../h/tmreg.h" 251919Swnj 261919Swnj struct buf tmtab; 271919Swnj struct buf ctmbuf; 281919Swnj struct buf rtmbuf; 291919Swnj 30*2396Swnj int tmcntrlr(), tmslave(), tmdgo(), tmintr(); 31*2396Swnj struct uba_dinfo *tminfo[NTM]; 32*2396Swnj u_short tmstd[] = { 0 }; 33*2396Swnj int (*tmivec[])() = { tmintr, 0 }; 34*2396Swnj struct uba_driver tmdriver = 35*2396Swnj { tmcntrlr, tmslave, tmdgo, 0, 0, tmstd, tminfo, tmivec }; 361919Swnj int tm_ubinfo; 371919Swnj 381919Swnj /* bits in minor device */ 391919Swnj #define T_NOREWIND 04 401919Swnj #define T_1600BPI 08 411919Swnj 421919Swnj #define INF (daddr_t)1000000L 431919Swnj 441919Swnj /* 451919Swnj * Really only handle one tape drive... if you have more than one, 46*2396Swnj * you can put all these (and some of the above) in a structure, 47*2396Swnj * change the obvious things, and make tmslave smarter, but 481919Swnj * it is not clear what happens when some drives are transferring while 491919Swnj * others rewind, so we don't pretend that this driver handles multiple 501919Swnj * tape drives. 511919Swnj */ 521919Swnj char t_openf; 531919Swnj daddr_t t_blkno; 541919Swnj char t_flags; 551919Swnj daddr_t t_nxrec; 561919Swnj u_short t_erreg; 571919Swnj u_short t_dsreg; 581919Swnj short t_resid; 591919Swnj 601919Swnj #define SSEEK 1 /* seeking */ 611919Swnj #define SIO 2 /* doing seq i/o */ 621919Swnj #define SCOM 3 /* sending control command */ 631919Swnj 641919Swnj #define LASTIOW 1 /* last op was a write */ 651919Swnj #define WAITREW 2 /* someone is waiting for a rewind */ 661919Swnj 67*2396Swnj tmcntrlr(ui, reg) 68*2396Swnj struct uba_dinfo *ui; 69*2396Swnj caddr_t reg; 70*2396Swnj { 71*2396Swnj ((struct device *)reg)->tmcs = IENABLE; 72*2396Swnj /* 73*2396Swnj * If this is a tm03/tc11, it ought to have interrupted 74*2396Swnj * by now, if it isn't (ie: it is a ts04) then we just 75*2396Swnj * pray that it didn't interrupt, so autoconf will ignore it 76*2396Swnj * - just in case out prayers fail, we will reference one 77*2396Swnj * of the more distant registers, and hope for a machine 78*2396Swnj * check, or similar disaster 79*2396Swnj */ 80*2396Swnj if (badaddr(&((struct device *)reg)->tmrd, 2)) 81*2396Swnj return(0); 82*2396Swnj return(1); 83*2396Swnj } 84*2396Swnj 85*2396Swnj tmslave(ui, reg, slaveno) 86*2396Swnj struct uba_dinfo *ui; 87*2396Swnj caddr_t reg; 88*2396Swnj { 89*2396Swnj /* 90*2396Swnj * Due to a design flaw, we cannot ascertain if the tape 91*2396Swnj * exists or not unless it is on line - ie: unless a tape is 92*2396Swnj * mounted. This is too servere a restriction to bear. 93*2396Swnj * As we can only handle one tape, we might just as well insist 94*2396Swnj * that it be slave #0, and just assume that it exists. 95*2396Swnj * Something better will have to be done if you have two 96*2396Swnj * tapes on one controller, or two controllers 97*2396Swnj */ 98*2396Swnj if (slaveno != 0 || tminfo[0]) 99*2396Swnj return(0); 100*2396Swnj return(1); 101*2396Swnj } 102*2396Swnj 1031919Swnj tmopen(dev, flag) 1041919Swnj dev_t dev; 1051919Swnj int flag; 1061919Swnj { 1071919Swnj register ds, unit; 108*2396Swnj register struct uba_dinfo *ui; 1091919Swnj 1101919Swnj tmtab.b_flags |= B_TAPE; 1111919Swnj unit = minor(dev)&03; 112*2396Swnj if (unit>=NTM || t_openf || !(ui = tminfo[minor(dev)>>3])->ui_alive) { 1131919Swnj u.u_error = ENXIO; /* out of range or open */ 1141919Swnj return; 1151919Swnj } 1161919Swnj tcommand(dev, NOP, 1); 1171919Swnj if ((t_erreg&SELR) == 0) { 1181919Swnj u.u_error = EIO; /* offline */ 1191919Swnj return; 1201919Swnj } 1211919Swnj t_openf = 1; 1221919Swnj if (t_erreg&RWS) 1231919Swnj tmwaitrws(dev); /* wait for rewind complete */ 1241919Swnj while (t_erreg&SDWN) 1251919Swnj tcommand(dev, NOP, 1); /* await settle down */ 1261919Swnj if ((t_erreg&TUR)==0 || 1271919Swnj ((flag&(FREAD|FWRITE)) == FWRITE && (t_erreg&WRL))) { 128*2396Swnj ((struct device *)ui->ui_addr)->tmcs = DCLR|GO; 1291919Swnj u.u_error = EIO; /* offline or write protect */ 1301919Swnj } 1311919Swnj if (u.u_error != 0) { 1321919Swnj t_openf = 0; 1331919Swnj return; 1341919Swnj } 1351919Swnj t_blkno = (daddr_t)0; 1361919Swnj t_nxrec = INF; 1371919Swnj t_flags = 0; 1381919Swnj t_openf = 1; 1391919Swnj } 1401919Swnj 1411919Swnj tmwaitrws(dev) 1421919Swnj register dev; 1431919Swnj { 144*2396Swnj register struct device *addr = 145*2396Swnj (struct device *)tminfo[minor(dev)>>3]->ui_addr; 1461919Swnj 1471919Swnj spl5(); 1481919Swnj for (;;) { 149*2396Swnj if ((addr->tmer&RWS) == 0) { 1501919Swnj spl0(); /* rewind complete */ 1511919Swnj return; 1521919Swnj } 1531919Swnj t_flags |= WAITREW; 1541919Swnj sleep((caddr_t)&t_flags, PRIBIO); 1551919Swnj } 1561919Swnj } 1571919Swnj 1581919Swnj tmclose(dev, flag) 1591919Swnj register dev_t dev; 1601919Swnj register flag; 1611919Swnj { 1621919Swnj 1631919Swnj if (flag == FWRITE || ((flag&FWRITE) && (t_flags&LASTIOW))) { 1641919Swnj tcommand(dev, WEOF, 1); 1651919Swnj tcommand(dev, WEOF, 1); 1661919Swnj tcommand(dev, SREV, 1); 1671919Swnj } 1681919Swnj if ((minor(dev)&T_NOREWIND) == 0) 1691919Swnj tcommand(dev, REW, 1); 1701919Swnj t_openf = 0; 1711919Swnj } 1721919Swnj 1731919Swnj tcommand(dev, com, count) 1741919Swnj dev_t dev; 1751919Swnj int com, count; 1761919Swnj { 1771919Swnj register struct buf *bp; 1781919Swnj 1791919Swnj bp = &ctmbuf; 1801919Swnj (void) spl5(); 1811919Swnj while (bp->b_flags&B_BUSY) { 1821919Swnj bp->b_flags |= B_WANTED; 1831919Swnj sleep((caddr_t)bp, PRIBIO); 1841919Swnj } 1851919Swnj bp->b_flags = B_BUSY|B_READ; 1861919Swnj (void) spl0(); 1871919Swnj bp->b_dev = dev; 1881919Swnj bp->b_repcnt = -count; 1891919Swnj bp->b_command = com; 1901919Swnj bp->b_blkno = 0; 1911919Swnj tmstrategy(bp); 1921919Swnj iowait(bp); 1931919Swnj if (bp->b_flags&B_WANTED) 1941919Swnj wakeup((caddr_t)bp); 1951919Swnj bp->b_flags &= B_ERROR; 1961919Swnj } 1971919Swnj 1981919Swnj tmstrategy(bp) 1991919Swnj register struct buf *bp; 2001919Swnj { 2011919Swnj register daddr_t *p; 2021919Swnj 2031928Swnj tmwaitrws(bp->b_dev); 2041919Swnj if (bp != &ctmbuf) { 2051919Swnj p = &t_nxrec; 2061919Swnj if (dbtofsb(bp->b_blkno) > *p) { 2071919Swnj bp->b_flags |= B_ERROR; 2081919Swnj bp->b_error = ENXIO; /* past EOF */ 2091919Swnj iodone(bp); 2101919Swnj return; 2111919Swnj } else if (dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) { 2121919Swnj bp->b_resid = bp->b_bcount; 2131919Swnj clrbuf(bp); /* at EOF */ 2141919Swnj iodone(bp); 2151919Swnj return; 2161919Swnj } else if ((bp->b_flags&B_READ) == 0) 2171919Swnj *p = dbtofsb(bp->b_blkno) + 1; /* write sets EOF */ 2181919Swnj } 2191919Swnj bp->av_forw = NULL; 2201919Swnj (void) spl5(); 2211919Swnj if (tmtab.b_actf == NULL) 2221919Swnj tmtab.b_actf = bp; 2231919Swnj else 2241919Swnj tmtab.b_actl->av_forw = bp; 2251919Swnj tmtab.b_actl = bp; 2261919Swnj if (tmtab.b_active == 0) 2271919Swnj tmstart(); 2281919Swnj (void) spl0(); 2291919Swnj } 2301919Swnj 2311919Swnj tmstart() 2321919Swnj { 2331919Swnj register struct buf *bp; 234*2396Swnj register struct uba_dinfo *ui; 235*2396Swnj register struct device *addr; 2361919Swnj register cmd; 2371919Swnj register daddr_t blkno; 2382054Swnj int s; 2391919Swnj 2401919Swnj loop: 2411919Swnj if ((bp = tmtab.b_actf) == 0) 2421919Swnj return; 243*2396Swnj ui = tminfo[minor(bp->b_dev)>>3]; 244*2396Swnj addr = (struct device *)ui->ui_addr; 245*2396Swnj t_dsreg = addr->tmcs; 246*2396Swnj t_erreg = addr->tmer; 247*2396Swnj t_resid = addr->tmbc; 2481919Swnj t_flags &= ~LASTIOW; 249*2396Swnj if (t_openf < 0 || (addr->tmcs&CUR) == 0) { 2501919Swnj /* t_openf = -1; ??? */ 2511919Swnj bp->b_flags |= B_ERROR; /* hard error'ed or !SELR */ 2521919Swnj goto next; 2531919Swnj } 2541919Swnj cmd = IENABLE | GO; 2551919Swnj if ((minor(bp->b_dev) & T_1600BPI) == 0) 2561919Swnj cmd |= D800; 2571919Swnj if (bp == &ctmbuf) { 2581919Swnj if (bp->b_command == NOP) 2591919Swnj goto next; /* just get status */ 2601919Swnj else { 2611919Swnj cmd |= bp->b_command; 2621919Swnj tmtab.b_active = SCOM; 2631919Swnj if (bp->b_command == SFORW || bp->b_command == SREV) 264*2396Swnj addr->tmbc = bp->b_repcnt; 265*2396Swnj addr->tmcs = cmd; 2661919Swnj return; 2671919Swnj } 2681919Swnj } 2691919Swnj if ((blkno = t_blkno) == dbtofsb(bp->b_blkno)) { 270*2396Swnj addr->tmbc = -bp->b_bcount; 2712054Swnj s = spl6(); 2721919Swnj if (tm_ubinfo == 0) 273*2396Swnj tm_ubinfo = ubasetup(ui->ui_ubanum, bp, 1); 2742054Swnj splx(s); 2751919Swnj if ((bp->b_flags&B_READ) == 0) { 2761919Swnj if (tmtab.b_errcnt) 2771919Swnj cmd |= WIRG; 2781919Swnj else 2791919Swnj cmd |= WCOM; 2801919Swnj } else 2811919Swnj cmd |= RCOM; 2821919Swnj cmd |= (tm_ubinfo >> 12) & 0x30; 2831919Swnj tmtab.b_active = SIO; 284*2396Swnj addr->tmba = tm_ubinfo; 285*2396Swnj addr->tmcs = cmd; 2861919Swnj return; 2871919Swnj } 2881919Swnj tmtab.b_active = SSEEK; 2891919Swnj if (blkno < dbtofsb(bp->b_blkno)) { 2901919Swnj cmd |= SFORW; 291*2396Swnj addr->tmbc = blkno - dbtofsb(bp->b_blkno); 2921919Swnj } else { 2931919Swnj cmd |= SREV; 294*2396Swnj addr->tmbc = dbtofsb(bp->b_blkno) - blkno; 2951919Swnj } 296*2396Swnj addr->tmcs = cmd; 2971919Swnj return; 2981919Swnj 2991919Swnj next: 300*2396Swnj ubarelse(ui->ui_ubanum, &tm_ubinfo); 3011919Swnj tmtab.b_actf = bp->av_forw; 3021919Swnj iodone(bp); 3031919Swnj goto loop; 3041919Swnj } 3051919Swnj 306*2396Swnj tmdgo() 3071919Swnj { 308*2396Swnj } 309*2396Swnj 310*2396Swnj tmintr(d) 311*2396Swnj { 3121919Swnj register struct buf *bp; 313*2396Swnj register struct device *addr = (struct device *)tminfo[d]->ui_addr; 3141919Swnj register state; 3151919Swnj 316*2396Swnj if (t_flags&WAITREW && (addr->tmer&RWS) == 0) { 3171919Swnj t_flags &= ~WAITREW; 3181919Swnj wakeup((caddr_t)&t_flags); 3191919Swnj } 3201919Swnj if ((bp = tmtab.b_actf) == NULL) 3211919Swnj return; 322*2396Swnj t_dsreg = addr->tmcs; 323*2396Swnj t_erreg = addr->tmer; 324*2396Swnj t_resid = addr->tmbc; 3251919Swnj if ((bp->b_flags & B_READ) == 0) 3261919Swnj t_flags |= LASTIOW; 3271919Swnj state = tmtab.b_active; 3281919Swnj tmtab.b_active = 0; 329*2396Swnj if (addr->tmcs&ERROR) { 330*2396Swnj while(addr->tmer & SDWN) 3311919Swnj ; /* await settle down */ 332*2396Swnj if (addr->tmer&EOF) { 3331919Swnj tmseteof(bp); /* set blkno and nxrec */ 3341919Swnj state = SCOM; 335*2396Swnj addr->tmbc = -bp->b_bcount; 3361919Swnj goto errout; 3371919Swnj } 338*2396Swnj if ((bp->b_flags&B_READ) && (addr->tmer&(HARD|SOFT)) == RLE) 3391919Swnj goto out; 340*2396Swnj if ((addr->tmer&HARD)==0 && state==SIO) { 3411928Swnj if (++tmtab.b_errcnt < 7) { 342*2396Swnj if((addr->tmer&SOFT) == NXM) 3431919Swnj printf("TM UBA late error\n"); 3441919Swnj else 345*2396Swnj t_blkno++; 346*2396Swnj ubarelse(tminfo[d]->ui_ubanum, &tm_ubinfo); 3471919Swnj tmstart(); 3481919Swnj return; 3491919Swnj } 3501919Swnj } else if (t_openf>0 && bp != &rtmbuf) 3511919Swnj t_openf = -1; 3521928Swnj deverror(bp, t_erreg, t_dsreg); 3531919Swnj bp->b_flags |= B_ERROR; 3541919Swnj state = SIO; 3551919Swnj } 3561919Swnj out: 3571919Swnj switch (state) { 3581919Swnj 3591919Swnj case SIO: 3601919Swnj t_blkno++; 3611919Swnj /* fall into ... */ 3621919Swnj 3631919Swnj case SCOM: 3641919Swnj if (bp == &ctmbuf) { 3651919Swnj switch (bp->b_command) { 3661919Swnj case SFORW: 3671919Swnj t_blkno -= bp->b_repcnt; 3681919Swnj break; 3691919Swnj 3701919Swnj case SREV: 3711919Swnj t_blkno += bp->b_repcnt; 3721919Swnj break; 3731919Swnj 3741919Swnj default: 3751919Swnj if (++bp->b_repcnt < 0) { 3761919Swnj tmstart(); /* continue */ 3771919Swnj return; 3781919Swnj } 3791919Swnj } 3801919Swnj } 3811919Swnj errout: 3821919Swnj tmtab.b_errcnt = 0; 3831919Swnj tmtab.b_actf = bp->av_forw; 384*2396Swnj bp->b_resid = -addr->tmbc; 385*2396Swnj ubarelse(tminfo[d]->ui_ubanum, &tm_ubinfo); 3861919Swnj iodone(bp); 3871919Swnj break; 3881919Swnj 3891919Swnj case SSEEK: 3901919Swnj t_blkno = dbtofsb(bp->b_blkno); 3911919Swnj break; 3921919Swnj 3931919Swnj default: 3941919Swnj return; 3951919Swnj } 3961919Swnj tmstart(); 3971919Swnj } 3981919Swnj 3991919Swnj tmseteof(bp) 4001919Swnj register struct buf *bp; 4011919Swnj { 402*2396Swnj register struct device *addr = 403*2396Swnj (struct device *)tminfo[minor(bp->b_dev)>>3]->ui_addr; 4041919Swnj 4051919Swnj if (bp == &ctmbuf) { 4061919Swnj if (t_blkno > dbtofsb(bp->b_blkno)) { 4071919Swnj /* reversing */ 408*2396Swnj t_nxrec = dbtofsb(bp->b_blkno) - addr->tmbc; 4091919Swnj t_blkno = t_nxrec; 4101919Swnj } else { 4111919Swnj /* spacing forward */ 412*2396Swnj t_blkno = dbtofsb(bp->b_blkno) + addr->tmbc; 4131919Swnj t_nxrec = t_blkno - 1; 4141919Swnj } 4151919Swnj return; 4161919Swnj } 4171919Swnj /* eof on read */ 4181919Swnj t_nxrec = dbtofsb(bp->b_blkno); 4191919Swnj } 4201919Swnj 4211919Swnj tmread(dev) 4221919Swnj { 4231919Swnj 4241919Swnj tmphys(dev); 4251919Swnj physio(tmstrategy, &rtmbuf, dev, B_READ, minphys); 4261919Swnj } 4271919Swnj 4281919Swnj tmwrite(dev) 4291919Swnj { 4301919Swnj 4311919Swnj tmphys(dev); 4321919Swnj physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys); 4331919Swnj } 4341919Swnj 4351919Swnj tmphys(dev) 4361919Swnj { 4371919Swnj register daddr_t a; 4381919Swnj 4391919Swnj a = dbtofsb(u.u_offset >> 9); 4401919Swnj t_blkno = a; 4411919Swnj t_nxrec = a + 1; 4421919Swnj } 4431919Swnj 4441919Swnj /*ARGSUSED*/ 4451919Swnj tmioctl(dev, cmd, addr, flag) 4461919Swnj caddr_t addr; 4471919Swnj dev_t dev; 4481919Swnj { 4491919Swnj register callcount; 4501919Swnj int fcount; 4511919Swnj struct mtop mtop; 4521919Swnj struct mtget mtget; 4531919Swnj /* we depend of the values and order of the MT codes here */ 4542324Skre static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL, NOP}; 4551919Swnj 4561919Swnj switch(cmd) { 4571919Swnj case MTIOCTOP: /* tape operation */ 4581919Swnj if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) { 4591919Swnj u.u_error = EFAULT; 4601919Swnj return; 4611919Swnj } 4621919Swnj switch(mtop.mt_op) { 4631919Swnj case MTWEOF: case MTFSF: case MTBSF: 4641919Swnj callcount = mtop.mt_count; 4651919Swnj fcount = INF; 4661919Swnj break; 4671919Swnj case MTFSR: case MTBSR: 4681919Swnj callcount = 1; 4691919Swnj fcount = mtop.mt_count; 4701919Swnj break; 4712324Skre case MTREW: case MTOFFL: case MTNOP: 4721919Swnj callcount = 1; 4731919Swnj fcount = 1; 4741919Swnj break; 4751919Swnj default: 4761919Swnj u.u_error = ENXIO; 4771919Swnj return; 4781919Swnj } 4791919Swnj if (callcount <= 0 || fcount <= 0) 4801919Swnj u.u_error = ENXIO; 4811919Swnj else while (--callcount >= 0) { 4821919Swnj tcommand(dev, tmops[mtop.mt_op], fcount); 4831919Swnj if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) && 4841919Swnj ctmbuf.b_resid) { 4851919Swnj u.u_error = EIO; 4861919Swnj break; 4871919Swnj } 4881919Swnj if ((ctmbuf.b_flags&B_ERROR) || t_erreg&BOT) 4891919Swnj break; 4901919Swnj } 4911919Swnj geterror(&ctmbuf); 4921919Swnj return; 4931919Swnj case MTIOCGET: 4941919Swnj mtget.mt_dsreg = t_dsreg; 4951919Swnj mtget.mt_erreg = t_erreg; 4961919Swnj mtget.mt_resid = t_resid; 4971919Swnj if (copyout((caddr_t)&mtget, addr, sizeof(mtget))) 4981919Swnj u.u_error = EFAULT; 4991919Swnj return; 5001919Swnj default: 5011919Swnj u.u_error = ENXIO; 5021919Swnj } 5031919Swnj } 5041919Swnj 5051919Swnj #define DBSIZE 20 5061919Swnj 5072363Swnj tmdump() 5082363Swnj { 5092363Swnj 5102363Swnj tmwall((char *)0, maxfree); /* write out memory */ 5112363Swnj tmeof(); 5122363Swnj tmeof(); 5132363Swnj tmrewind(); 5142363Swnj tmwait(); 5152363Swnj } 5162363Swnj 5172363Swnj tmwall(start, num) 5181919Swnj int start, num; 5191919Swnj { 520*2396Swnj register struct uba_dinfo *ui; 521*2396Swnj register struct uba_regs *up; 522*2396Swnj register struct device *addr; 5232297Swnj int blk, bdp; 5241919Swnj 525*2396Swnj #define phys1(a,b) ((b)((int)(a)&0x7fffffff)) 526*2396Swnj #define phys(a,b) phys1(*phys1(&a, b*), b) 527*2396Swnj if (tminfo[0] == 0) { 528*2396Swnj printf("dna\n"); 529*2396Swnj return (-1); 530*2396Swnj } 531*2396Swnj ui = phys(tminfo[0], struct uba_dinfo *); 532*2396Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 533*2396Swnj #if VAX780 534*2396Swnj if (cpu == VAX_780) 535*2396Swnj ubainit(up); 5361919Swnj #endif 5372324Skre DELAY(1000000); 538*2396Swnj addr = (struct device *)ui->ui_physaddr; 539*2396Swnj tmwait(addr); 540*2396Swnj addr->tmcs = DCLR | GO; 5411919Swnj while (num > 0) { 5421919Swnj blk = num > DBSIZE ? DBSIZE : num; 543*2396Swnj tmdwrite(start, blk, addr, up); 5441919Swnj start += blk; 5451919Swnj num -= blk; 5461919Swnj } 5472297Swnj bdp = 1; /* crud to fool c compiler */ 548*2396Swnj up->uba_dpr[bdp] |= UBA_BNE; 5492363Swnj return (0); 5501919Swnj } 5511919Swnj 552*2396Swnj tmdwrite(buf, num, addr, up) 553*2396Swnj register buf, num; 554*2396Swnj register struct device *addr; 555*2396Swnj struct uba_regs *up; 5561919Swnj { 557*2396Swnj register struct pte *io; 558*2396Swnj register int npf; 5592297Swnj int bdp; 5601928Swnj 561*2396Swnj tmwait(addr); 5622297Swnj bdp = 1; /* more dastardly tricks on pcc */ 563*2396Swnj up->uba_dpr[bdp] |= UBA_BNE; 564*2396Swnj io = up->uba_map; 5651919Swnj npf = num+1; 5661928Swnj while (--npf != 0) 567*2396Swnj *(int *)io++ = (buf++ | (1<<UBA_DPSHIFT) | UBA_MRV); 568*2396Swnj *(int *)io = 0; 569*2396Swnj addr->tmbc = -(num*NBPG); 570*2396Swnj addr->tmba = 0; 571*2396Swnj addr->tmcs = WCOM | GO; 5721919Swnj } 5731919Swnj 574*2396Swnj tmwait(addr) 575*2396Swnj register struct device *addr; 5761919Swnj { 5771928Swnj register s; 5781919Swnj 5791919Swnj do 580*2396Swnj s = addr->tmcs; 5811919Swnj while ((s & CUR) == 0); 5821919Swnj } 5831919Swnj 584*2396Swnj tmrewind(addr) 585*2396Swnj struct device *addr; 5861919Swnj { 5871919Swnj 588*2396Swnj tmwait(addr); 589*2396Swnj addr->tmcs = REW | GO; 5901919Swnj } 5911919Swnj 592*2396Swnj tmeof(addr) 593*2396Swnj struct device *addr; 5941919Swnj { 5951919Swnj 596*2396Swnj tmwait(addr); 597*2396Swnj addr->tmcs = WEOF | GO; 5981919Swnj } 5991919Swnj #endif 600