changed to F_ER codes. DLW
[unix-history] / usr / src / sys / vax / uba / tm.c
CommitLineData
e4271c68 1/* tm.c 4.13 %G% */
d75e5c3e 2
66b4fb09 3#include "tm.h"
7e00c42b 4#if NTM03 > 0
d75e5c3e
BJ
5/*
6 * TM tape driver
7e00c42b
BJ
7 *
8 * THIS HANDLES ONLY ONE DRIVE ON ONE CONTROLER, AS WE HAVE NO
9 * WAY TO TEST MULTIPLE TRANSPORTS.
d75e5c3e 10 */
7e00c42b 11#define DELAY(N) { register int d = N; while (--d > 0); }
d75e5c3e
BJ
12#include "../h/param.h"
13#include "../h/buf.h"
14#include "../h/dir.h"
15#include "../h/conf.h"
16#include "../h/user.h"
17#include "../h/file.h"
18#include "../h/map.h"
19#include "../h/pte.h"
e4271c68 20#include "../h/vm.h"
d75e5c3e
BJ
21#include "../h/uba.h"
22#include "../h/mtio.h"
23#include "../h/ioctl.h"
7455bf3e 24#include "../h/cmap.h"
3f3a34c3 25#include "../h/cpu.h"
d75e5c3e 26
3f3a34c3 27#include "../h/tmreg.h"
d75e5c3e 28
d75e5c3e
BJ
29struct buf ctmbuf;
30struct buf rtmbuf;
31
3f3a34c3 32int tmcntrlr(), tmslave(), tmdgo(), tmintr();
7e00c42b
BJ
33struct uba_minfo *tmminfo[NTM03];
34struct uba_dinfo *tmdinfo[NTM11];
d763a2b7 35u_short tmstd[] = { 0772520, 0 };
3f3a34c3 36struct uba_driver tmdriver =
e4271c68 37 { tmcntrlr, tmslave, tmdgo, 0, tmstd, "mt", tmdinfo, "tm", tmminfo };
d75e5c3e
BJ
38
39/* bits in minor device */
40#define T_NOREWIND 04
41#define T_1600BPI 08
42
43#define INF (daddr_t)1000000L
44
7e00c42b
BJ
45struct tm_softc {
46 char sc_openf;
47 char sc_flags;
48 daddr_t sc_blkno;
49 daddr_t sc_nxrec;
50 u_short sc_erreg;
51 u_short sc_dsreg;
52 short sc_resid;
7e00c42b 53} tm_softc[NTM03];
d75e5c3e 54
d75e5c3e
BJ
55#define SSEEK 1 /* seeking */
56#define SIO 2 /* doing seq i/o */
57#define SCOM 3 /* sending control command */
58
59#define LASTIOW 1 /* last op was a write */
60#define WAITREW 2 /* someone is waiting for a rewind */
61
5aa9d5ea
RE
62/*
63 * Determine if there is a controller for
64 * a tm at address reg. Our goal is to make the
65 * device interrupt.
5aa9d5ea 66 */
d763a2b7
BJ
67tmcntrlr(um, reg)
68 struct uba_minfo *um;
3f3a34c3
BJ
69 caddr_t reg;
70{
d763a2b7 71 register int br, cvec;
5aa9d5ea 72
3f3a34c3
BJ
73 ((struct device *)reg)->tmcs = IENABLE;
74 /*
75 * If this is a tm03/tc11, it ought to have interrupted
76 * by now, if it isn't (ie: it is a ts04) then we just
d763a2b7
BJ
77 * hope that it didn't interrupt, so autoconf will ignore it.
78 * Just in case, we will reference one
3f3a34c3 79 * of the more distant registers, and hope for a machine
d763a2b7 80 * check, or similar disaster if this is a ts.
7e00c42b
BJ
81 *
82 * Note: on an 11/780, badaddr will just generate
83 * a uba error for a ts; but our caller will notice that
84 * so we won't check for it.
3f3a34c3
BJ
85 */
86 if (badaddr(&((struct device *)reg)->tmrd, 2))
d763a2b7
BJ
87 return (0);
88 return (1);
3f3a34c3
BJ
89}
90
e4271c68 91tmslave(ui, reg)
3f3a34c3
BJ
92 struct uba_dinfo *ui;
93 caddr_t reg;
94{
d763a2b7 95
3f3a34c3
BJ
96 /*
97 * Due to a design flaw, we cannot ascertain if the tape
98 * exists or not unless it is on line - ie: unless a tape is
99 * mounted. This is too servere a restriction to bear.
100 * As we can only handle one tape, we might just as well insist
101 * that it be slave #0, and just assume that it exists.
102 * Something better will have to be done if you have two
103 * tapes on one controller, or two controllers
104 */
e4271c68 105 if (ui->ui_slave != 0 || tmdinfo[0])
3f3a34c3 106 return(0);
d763a2b7 107 return (1);
3f3a34c3
BJ
108}
109
d75e5c3e
BJ
110tmopen(dev, flag)
111 dev_t dev;
112 int flag;
113{
114 register ds, unit;
3f3a34c3 115 register struct uba_dinfo *ui;
7e00c42b 116 register struct tm_softc *sc = &tm_softc[0];
d75e5c3e 117
d763a2b7 118 tmminfo[0]->um_tab.b_flags |= B_TAPE;
d75e5c3e 119 unit = minor(dev)&03;
7e00c42b 120 if (unit>=NTM11 || sc->sc_openf || (ui = tmdinfo[0]) == 0 || ui->ui_alive==0) {
d75e5c3e
BJ
121 u.u_error = ENXIO; /* out of range or open */
122 return;
123 }
e4271c68 124 tmcommand(dev, NOP, 1);
7e00c42b
BJ
125 if ((sc->sc_erreg&SELR) == 0) {
126 u.u_error = EIO;
127 goto eio;
d75e5c3e 128 }
7e00c42b
BJ
129 sc->sc_openf = 1;
130 if (sc->sc_erreg&RWS)
d75e5c3e 131 tmwaitrws(dev); /* wait for rewind complete */
7e00c42b 132 while (sc->sc_erreg&SDWN)
e4271c68 133 tmcommand(dev, NOP, 1); /* await settle down */
7e00c42b
BJ
134 if ((sc->sc_erreg&TUR)==0 ||
135 ((flag&(FREAD|FWRITE)) == FWRITE && (sc->sc_erreg&WRL))) {
3f3a34c3 136 ((struct device *)ui->ui_addr)->tmcs = DCLR|GO;
d75e5c3e
BJ
137 u.u_error = EIO; /* offline or write protect */
138 }
139 if (u.u_error != 0) {
7e00c42b
BJ
140 sc->sc_openf = 0;
141 if (u.u_error == EIO)
142eio:
143 uprintf("tape offline or protected\n");
d75e5c3e
BJ
144 return;
145 }
7e00c42b
BJ
146 sc->sc_blkno = (daddr_t)0;
147 sc->sc_nxrec = INF;
148 sc->sc_flags = 0;
149 sc->sc_openf = 1;
d75e5c3e
BJ
150}
151
152tmwaitrws(dev)
153 register dev;
154{
3f3a34c3 155 register struct device *addr =
7e00c42b
BJ
156 (struct device *)tmdinfo[0]->ui_addr;
157 register struct tm_softc *sc = &tm_softc[0];
d75e5c3e
BJ
158
159 spl5();
160 for (;;) {
3f3a34c3 161 if ((addr->tmer&RWS) == 0) {
d75e5c3e
BJ
162 spl0(); /* rewind complete */
163 return;
164 }
7e00c42b
BJ
165 sc->sc_flags |= WAITREW;
166 sleep((caddr_t)&sc->sc_flags, PRIBIO);
d75e5c3e
BJ
167 }
168}
169
170tmclose(dev, flag)
171 register dev_t dev;
172 register flag;
173{
7e00c42b 174 register struct tm_softc *sc = &tm_softc[0];
d75e5c3e 175
7e00c42b 176 if (flag == FWRITE || ((flag&FWRITE) && (sc->sc_flags&LASTIOW))) {
e4271c68
BJ
177 tmcommand(dev, WEOF, 1);
178 tmcommand(dev, WEOF, 1);
179 tmcommand(dev, SREV, 1);
d75e5c3e
BJ
180 }
181 if ((minor(dev)&T_NOREWIND) == 0)
e4271c68 182 tmcommand(dev, REW, 1);
7e00c42b 183 sc->sc_openf = 0;
d75e5c3e
BJ
184}
185
e4271c68 186tmcommand(dev, com, count)
d75e5c3e
BJ
187 dev_t dev;
188 int com, count;
189{
190 register struct buf *bp;
191
192 bp = &ctmbuf;
193 (void) spl5();
194 while (bp->b_flags&B_BUSY) {
195 bp->b_flags |= B_WANTED;
196 sleep((caddr_t)bp, PRIBIO);
197 }
198 bp->b_flags = B_BUSY|B_READ;
199 (void) spl0();
200 bp->b_dev = dev;
201 bp->b_repcnt = -count;
202 bp->b_command = com;
203 bp->b_blkno = 0;
204 tmstrategy(bp);
205 iowait(bp);
206 if (bp->b_flags&B_WANTED)
207 wakeup((caddr_t)bp);
208 bp->b_flags &= B_ERROR;
209}
210
211tmstrategy(bp)
212 register struct buf *bp;
213{
214 register daddr_t *p;
d763a2b7 215 register struct buf *tmi;
d75e5c3e 216
0a51498e 217 tmwaitrws(bp->b_dev);
d75e5c3e 218 if (bp != &ctmbuf) {
7e00c42b 219 p = &tm_softc[0].sc_nxrec;
d75e5c3e
BJ
220 if (dbtofsb(bp->b_blkno) > *p) {
221 bp->b_flags |= B_ERROR;
222 bp->b_error = ENXIO; /* past EOF */
223 iodone(bp);
224 return;
225 } else if (dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) {
226 bp->b_resid = bp->b_bcount;
227 clrbuf(bp); /* at EOF */
228 iodone(bp);
229 return;
230 } else if ((bp->b_flags&B_READ) == 0)
231 *p = dbtofsb(bp->b_blkno) + 1; /* write sets EOF */
232 }
233 bp->av_forw = NULL;
234 (void) spl5();
d763a2b7
BJ
235 tmi = &tmminfo[0]->um_tab;
236 if (tmi->b_actf == NULL)
237 tmi->b_actf = bp;
d75e5c3e 238 else
d763a2b7
BJ
239 tmi->b_actl->av_forw = bp;
240 tmi->b_actl = bp;
241 if (tmi->b_active == 0)
d75e5c3e
BJ
242 tmstart();
243 (void) spl0();
244}
245
246tmstart()
247{
248 register struct buf *bp;
7e00c42b 249 register struct uba_minfo *um = tmminfo[0];
3f3a34c3
BJ
250 register struct uba_dinfo *ui;
251 register struct device *addr;
7e00c42b
BJ
252 register struct tm_softc *sc = &tm_softc[0];
253 int cmd, s;
254 daddr_t blkno;
d75e5c3e
BJ
255
256loop:
7e00c42b 257 if ((bp = um->um_tab.b_actf) == 0)
d75e5c3e 258 return;
7e00c42b 259 ui = tmdinfo[0];
3f3a34c3 260 addr = (struct device *)ui->ui_addr;
7e00c42b
BJ
261 sc->sc_dsreg = addr->tmcs;
262 sc->sc_erreg = addr->tmer;
263 sc->sc_resid = addr->tmbc;
264 sc->sc_flags &= ~LASTIOW;
265 if (sc->sc_openf < 0 || (addr->tmcs&CUR) == 0) {
266 /* sc->sc_openf = -1; ??? */
d75e5c3e
BJ
267 bp->b_flags |= B_ERROR; /* hard error'ed or !SELR */
268 goto next;
269 }
270 cmd = IENABLE | GO;
271 if ((minor(bp->b_dev) & T_1600BPI) == 0)
272 cmd |= D800;
273 if (bp == &ctmbuf) {
274 if (bp->b_command == NOP)
275 goto next; /* just get status */
276 else {
277 cmd |= bp->b_command;
7e00c42b 278 um->um_tab.b_active = SCOM;
d75e5c3e 279 if (bp->b_command == SFORW || bp->b_command == SREV)
3f3a34c3
BJ
280 addr->tmbc = bp->b_repcnt;
281 addr->tmcs = cmd;
d75e5c3e
BJ
282 return;
283 }
284 }
7e00c42b 285 if ((blkno = sc->sc_blkno) == dbtofsb(bp->b_blkno)) {
3f3a34c3 286 addr->tmbc = -bp->b_bcount;
d75e5c3e 287 if ((bp->b_flags&B_READ) == 0) {
7e00c42b 288 if (um->um_tab.b_errcnt)
d75e5c3e
BJ
289 cmd |= WIRG;
290 else
291 cmd |= WCOM;
292 } else
293 cmd |= RCOM;
7e00c42b 294 um->um_tab.b_active = SIO;
e4271c68
BJ
295 if (um->um_ubinfo)
296 panic("tmstart");
297 um->um_cmd = cmd;
298 ubago(ui);
299 splx(s);
d75e5c3e
BJ
300 return;
301 }
7e00c42b 302 um->um_tab.b_active = SSEEK;
d75e5c3e
BJ
303 if (blkno < dbtofsb(bp->b_blkno)) {
304 cmd |= SFORW;
3f3a34c3 305 addr->tmbc = blkno - dbtofsb(bp->b_blkno);
d75e5c3e
BJ
306 } else {
307 cmd |= SREV;
3f3a34c3 308 addr->tmbc = dbtofsb(bp->b_blkno) - blkno;
d75e5c3e 309 }
3f3a34c3 310 addr->tmcs = cmd;
d75e5c3e
BJ
311 return;
312
313next:
e4271c68 314 ubarelse(um->um_ubanum, &um->um_ubinfo);
7e00c42b 315 um->um_tab.b_actf = bp->av_forw;
d75e5c3e
BJ
316 iodone(bp);
317 goto loop;
318}
319
e4271c68
BJ
320tmdgo(um)
321 register struct uba_minfo *um;
3f3a34c3 322{
e4271c68 323 register struct device *addr = (struct device *)um->um_addr;
7e00c42b 324
e4271c68
BJ
325 printf("tmdgo %x %x\n", um->um_ubinfo, um->um_cmd);
326 addr->tmba = um->um_ubinfo;
327 addr->tmcs = um->um_cmd | ((um->um_ubinfo >> 12) & 0x30);
3f3a34c3
BJ
328}
329
7e00c42b 330/*ARGSUSED*/
3f3a34c3 331tmintr(d)
7e00c42b 332 int d;
d75e5c3e
BJ
333{
334 register struct buf *bp;
7e00c42b
BJ
335 register struct uba_minfo *um = tmminfo[0];
336 register struct device *addr = (struct device *)tmdinfo[0]->ui_addr;
337 register struct tm_softc *sc = &tm_softc[0];
d75e5c3e
BJ
338 register state;
339
e4271c68 340 printf("tmintr %x %x\n", um->um_tab.b_actf, um->um_tab.b_active);
7e00c42b
BJ
341 if (sc->sc_flags&WAITREW && (addr->tmer&RWS) == 0) {
342 sc->sc_flags &= ~WAITREW;
343 wakeup((caddr_t)&sc->sc_flags);
d75e5c3e 344 }
7e00c42b 345 if ((bp = um->um_tab.b_actf) == NULL)
d75e5c3e 346 return;
7e00c42b
BJ
347 sc->sc_dsreg = addr->tmcs;
348 sc->sc_erreg = addr->tmer;
349 sc->sc_resid = addr->tmbc;
d75e5c3e 350 if ((bp->b_flags & B_READ) == 0)
7e00c42b
BJ
351 sc->sc_flags |= LASTIOW;
352 state = um->um_tab.b_active;
353 um->um_tab.b_active = 0;
3f3a34c3
BJ
354 if (addr->tmcs&ERROR) {
355 while(addr->tmer & SDWN)
d75e5c3e 356 ; /* await settle down */
3f3a34c3 357 if (addr->tmer&EOF) {
d75e5c3e
BJ
358 tmseteof(bp); /* set blkno and nxrec */
359 state = SCOM;
3f3a34c3 360 addr->tmbc = -bp->b_bcount;
d75e5c3e
BJ
361 goto errout;
362 }
3f3a34c3 363 if ((bp->b_flags&B_READ) && (addr->tmer&(HARD|SOFT)) == RLE)
d75e5c3e 364 goto out;
3f3a34c3 365 if ((addr->tmer&HARD)==0 && state==SIO) {
7e00c42b 366 if (++um->um_tab.b_errcnt < 7) {
3f3a34c3 367 if((addr->tmer&SOFT) == NXM)
d75e5c3e 368 printf("TM UBA late error\n");
7e00c42b 369 sc->sc_blkno++;
e4271c68 370 ubarelse(um->um_ubanum, &um->um_ubinfo);
d75e5c3e
BJ
371 tmstart();
372 return;
373 }
7e00c42b
BJ
374 } else if (sc->sc_openf>0 && bp != &rtmbuf)
375 sc->sc_openf = -1;
376 deverror(bp, sc->sc_erreg, sc->sc_dsreg);
d75e5c3e
BJ
377 bp->b_flags |= B_ERROR;
378 state = SIO;
379 }
380out:
381 switch (state) {
382
383 case SIO:
7e00c42b 384 sc->sc_blkno++;
d75e5c3e
BJ
385 /* fall into ... */
386
387 case SCOM:
388 if (bp == &ctmbuf) {
389 switch (bp->b_command) {
390 case SFORW:
7e00c42b 391 sc->sc_blkno -= bp->b_repcnt;
d75e5c3e
BJ
392 break;
393
394 case SREV:
7e00c42b 395 sc->sc_blkno += bp->b_repcnt;
d75e5c3e
BJ
396 break;
397
398 default:
399 if (++bp->b_repcnt < 0) {
400 tmstart(); /* continue */
401 return;
402 }
403 }
404 }
405errout:
7e00c42b
BJ
406 um->um_tab.b_errcnt = 0;
407 um->um_tab.b_actf = bp->av_forw;
3f3a34c3 408 bp->b_resid = -addr->tmbc;
e4271c68 409 ubarelse(um->um_ubanum, &um->um_ubinfo);
d75e5c3e
BJ
410 iodone(bp);
411 break;
412
413 case SSEEK:
7e00c42b 414 sc->sc_blkno = dbtofsb(bp->b_blkno);
d75e5c3e
BJ
415 break;
416
417 default:
418 return;
419 }
420 tmstart();
421}
422
423tmseteof(bp)
424 register struct buf *bp;
425{
3f3a34c3 426 register struct device *addr =
7e00c42b
BJ
427 (struct device *)tmdinfo[0]->ui_addr;
428 register struct tm_softc *sc = &tm_softc[0];
d75e5c3e
BJ
429
430 if (bp == &ctmbuf) {
7e00c42b 431 if (sc->sc_blkno > dbtofsb(bp->b_blkno)) {
d75e5c3e 432 /* reversing */
7e00c42b
BJ
433 sc->sc_nxrec = dbtofsb(bp->b_blkno) - addr->tmbc;
434 sc->sc_blkno = sc->sc_nxrec;
d75e5c3e
BJ
435 } else {
436 /* spacing forward */
7e00c42b
BJ
437 sc->sc_blkno = dbtofsb(bp->b_blkno) + addr->tmbc;
438 sc->sc_nxrec = sc->sc_blkno - 1;
d75e5c3e
BJ
439 }
440 return;
441 }
442 /* eof on read */
7e00c42b 443 sc->sc_nxrec = dbtofsb(bp->b_blkno);
d75e5c3e
BJ
444}
445
446tmread(dev)
447{
448
449 tmphys(dev);
450 physio(tmstrategy, &rtmbuf, dev, B_READ, minphys);
451}
452
453tmwrite(dev)
454{
455
456 tmphys(dev);
457 physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys);
458}
459
460tmphys(dev)
461{
462 register daddr_t a;
7e00c42b 463 register struct tm_softc *sc = &tm_softc[0];
d75e5c3e
BJ
464
465 a = dbtofsb(u.u_offset >> 9);
7e00c42b
BJ
466 sc->sc_blkno = a;
467 sc->sc_nxrec = a + 1;
d75e5c3e
BJ
468}
469
470/*ARGSUSED*/
471tmioctl(dev, cmd, addr, flag)
472 caddr_t addr;
473 dev_t dev;
474{
475 register callcount;
7e00c42b 476 register struct tm_softc *sc = &tm_softc[0];
d75e5c3e
BJ
477 int fcount;
478 struct mtop mtop;
479 struct mtget mtget;
480 /* we depend of the values and order of the MT codes here */
77115c00 481 static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL, NOP};
d75e5c3e
BJ
482
483 switch(cmd) {
484 case MTIOCTOP: /* tape operation */
485 if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
486 u.u_error = EFAULT;
487 return;
488 }
489 switch(mtop.mt_op) {
490 case MTWEOF: case MTFSF: case MTBSF:
491 callcount = mtop.mt_count;
492 fcount = INF;
493 break;
494 case MTFSR: case MTBSR:
495 callcount = 1;
496 fcount = mtop.mt_count;
497 break;
77115c00 498 case MTREW: case MTOFFL: case MTNOP:
d75e5c3e
BJ
499 callcount = 1;
500 fcount = 1;
501 break;
502 default:
503 u.u_error = ENXIO;
504 return;
505 }
506 if (callcount <= 0 || fcount <= 0)
507 u.u_error = ENXIO;
508 else while (--callcount >= 0) {
e4271c68 509 tmcommand(dev, tmops[mtop.mt_op], fcount);
d75e5c3e
BJ
510 if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
511 ctmbuf.b_resid) {
512 u.u_error = EIO;
513 break;
514 }
7e00c42b
BJ
515 if ((ctmbuf.b_flags&B_ERROR) ||
516 sc->sc_erreg&BOT)
d75e5c3e
BJ
517 break;
518 }
519 geterror(&ctmbuf);
520 return;
521 case MTIOCGET:
7e00c42b
BJ
522 mtget.mt_dsreg = sc->sc_dsreg;
523 mtget.mt_erreg = sc->sc_erreg;
524 mtget.mt_resid = sc->sc_resid;
d75e5c3e
BJ
525 if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
526 u.u_error = EFAULT;
527 return;
528 default:
529 u.u_error = ENXIO;
530 }
531}
532
533#define DBSIZE 20
534
7455bf3e 535tmdump()
d75e5c3e 536{
3f3a34c3
BJ
537 register struct uba_dinfo *ui;
538 register struct uba_regs *up;
539 register struct device *addr;
5aa9d5ea
RE
540 int blk, num;
541 int start;
d75e5c3e 542
5aa9d5ea
RE
543 start = 0;
544 num = maxfree;
545#define phys(a,b) ((b)((int)(a)&0x7fffffff))
d763a2b7 546 if (tmdinfo[0] == 0) {
3f3a34c3
BJ
547 printf("dna\n");
548 return (-1);
549 }
d763a2b7 550 ui = phys(tmdinfo[0], struct uba_dinfo *);
3f3a34c3
BJ
551 up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba;
552#if VAX780
553 if (cpu == VAX_780)
554 ubainit(up);
d75e5c3e 555#endif
77115c00 556 DELAY(1000000);
3f3a34c3
BJ
557 addr = (struct device *)ui->ui_physaddr;
558 tmwait(addr);
559 addr->tmcs = DCLR | GO;
d75e5c3e
BJ
560 while (num > 0) {
561 blk = num > DBSIZE ? DBSIZE : num;
3f3a34c3 562 tmdwrite(start, blk, addr, up);
d75e5c3e
BJ
563 start += blk;
564 num -= blk;
565 }
5aa9d5ea
RE
566 tmeof(addr);
567 tmeof(addr);
7e00c42b
BJ
568 tmwait(addr);
569 addr->tmcs = REW | GO;
5aa9d5ea 570 tmwait(addr);
7455bf3e 571 return (0);
d75e5c3e
BJ
572}
573
3f3a34c3
BJ
574tmdwrite(buf, num, addr, up)
575 register buf, num;
576 register struct device *addr;
577 struct uba_regs *up;
d75e5c3e 578{
3f3a34c3
BJ
579 register struct pte *io;
580 register int npf;
0a51498e 581
3f3a34c3 582 tmwait(addr);
3f3a34c3 583 io = up->uba_map;
d75e5c3e 584 npf = num+1;
0a51498e 585 while (--npf != 0)
3f3a34c3
BJ
586 *(int *)io++ = (buf++ | (1<<UBA_DPSHIFT) | UBA_MRV);
587 *(int *)io = 0;
588 addr->tmbc = -(num*NBPG);
589 addr->tmba = 0;
590 addr->tmcs = WCOM | GO;
d75e5c3e
BJ
591}
592
3f3a34c3
BJ
593tmwait(addr)
594 register struct device *addr;
d75e5c3e 595{
0a51498e 596 register s;
d75e5c3e
BJ
597
598 do
3f3a34c3 599 s = addr->tmcs;
d75e5c3e
BJ
600 while ((s & CUR) == 0);
601}
602
3f3a34c3
BJ
603tmeof(addr)
604 struct device *addr;
d75e5c3e
BJ
605{
606
3f3a34c3
BJ
607 tmwait(addr);
608 addr->tmcs = WEOF | GO;
d75e5c3e
BJ
609}
610#endif