xref: /original-bsd/sys/vax/mba/mt.c (revision c3f73f8c)
1 /*	mt.c	4.9	82/09/12	*/
2 
3 #include "mu.h"
4 #if NMT > 0
5 /*
6  * TM78/TU78 tape driver
7  *
8  *	Behavior in complex error situations is uncertain...
9  *
10  * TODO:
11  *	test error recovery
12  *	add odd byte count kludge from VMS driver
13  *	write dump routine
14  */
15 #include "../h/param.h"
16 #include "../h/systm.h"
17 #include "../h/buf.h"
18 #include "../h/conf.h"
19 #include "../h/dir.h"
20 #include "../h/file.h"
21 #include "../h/user.h"
22 #include "../h/map.h"
23 #include "../h/pte.h"
24 #include "../h/mbareg.h"
25 #include "../h/mbavar.h"
26 #include "../h/ioctl.h"
27 #include "../h/mtio.h"
28 #include "../h/cmap.h"
29 #include "../h/cpu.h"
30 #include "../h/uio.h"
31 
32 #include "../h/mtreg.h"
33 
34 struct	buf	rmtbuf[NMT];
35 struct	buf	cmtbuf[NMT];
36 
37 short	mttypes[] =
38 	{ MBDT_TU78, 0 };
39 struct	mba_device *mtinfo[NMT];
40 int	mtattach(), mtslave(), mtustart(), mtstart(), mtndtint(), mtdtint();
41 struct	mba_driver mtdriver =
42     { mtattach, mtslave, mtustart, mtstart, mtdtint, mtndtint,
43       mttypes, "mt", "mu", mtinfo };
44 
45 #define MASKREG(r)	((r) & 0xffff)
46 
47 /* bits in minor device */
48 #define	MUUNIT(dev)	(minor(dev)&03)
49 #define	H_NOREWIND	04
50 #define	H_6250BPI	08
51 
52 #define MTUNIT(dev)	(mutomt[MUUNIT(dev)])
53 
54 #define	INF	(daddr_t)1000000L	/* a block number that wont exist */
55 
56 struct	mu_softc {
57 	char	sc_openf;
58 	char	sc_flags;
59 	daddr_t	sc_blkno;
60 	daddr_t	sc_nxrec;
61 	u_short	sc_erreg;
62 	u_short	sc_dsreg;
63 	short	sc_resid;
64 	short	sc_dens;
65 	struct	mba_device *sc_mi;
66 	int	sc_slave;
67 } mu_softc[NMU];
68 short	mutomt[NMU];
69 
70 /*
71  * Bits for sc_flags.
72  */
73 #define	H_WRITTEN 1	/* last operation was a write */
74 
75 char	mtds_bits[] = MTDS_BITS;
76 
77 /*ARGSUSED*/
78 mtattach(mi)
79 	struct mba_device *mi;
80 {
81 #ifdef lint
82 	mtread(0, 0); mtwrite(0); mtioctl(0, 0, 0, 0);
83 #endif
84 }
85 
86 mtslave(mi, ms, sn)
87 	struct mba_device *mi;
88 	struct mba_slave *ms;
89 	int sn;
90 {
91 	register struct mu_softc *sc = &mu_softc[ms->ms_unit];
92 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
93 	int s = spl7(), rtn = 0;
94 
95 	mtaddr->mtas = -1;
96 	mtaddr->mtncs[sn] = MT_SENSE|MT_GO;
97 	while (mtaddr->mtas == 0)
98 		;
99 	if ((mtaddr->mtner & MTER_INTCODE) == MTER_DONE &&
100 	    (mtaddr->mtds & MTDS_PRES)) {
101 		sc->sc_mi = mi;
102 		sc->sc_slave = sn;
103 		mutomt[ms->ms_unit] = mi->mi_unit;
104 		rtn = 1;
105 	}
106 	mtaddr->mtas = mtaddr->mtas;
107 	splx(s);
108 	return (rtn);
109 }
110 
111 mtopen(dev, flag)
112 	dev_t dev;
113 	int flag;
114 {
115 	register int muunit;
116 	register struct mba_device *mi;
117 	register struct mu_softc *sc;
118 	int olddens, dens;
119 
120 	muunit = MUUNIT(dev);
121 	if (muunit >= NMU || (sc = &mu_softc[muunit])->sc_openf ||
122 	    (mi = mtinfo[MTUNIT(dev)]) == 0 || mi->mi_alive == 0) {
123 		u.u_error = ENXIO;
124 		return;
125 	}
126 	olddens = sc->sc_dens;
127 	dens = sc->sc_dens = (minor(dev)&H_6250BPI) ? MT_GCR : 0;
128 	mtcommand(dev, MT_SENSE, 1);
129 	sc->sc_dens = olddens;
130 	if ((sc->sc_dsreg & MTDS_ONL) == 0) {
131 		uprintf("mu%d: not online\n", muunit);
132 		u.u_error = EIO;
133 		return;
134 	}
135 	if ((flag&FWRITE) && (sc->sc_dsreg&MTDS_FPT)) {
136 		uprintf("mu%d: no write ring\n", muunit);
137 		u.u_error = EIO;
138 		return;
139 	}
140 	if ((sc->sc_dsreg & MTDS_BOT) == 0 && (flag&FWRITE) &&
141 	    dens != sc->sc_dens) {
142 		uprintf("mu%d: can't change density in mid-tape\n", muunit);
143 		u.u_error = EIO;
144 		return;
145 	}
146 	sc->sc_openf = 1;
147 	sc->sc_blkno = (daddr_t)0;
148 	sc->sc_nxrec = INF;
149 	sc->sc_flags = 0;
150 	sc->sc_dens = dens;
151 }
152 
153 mtclose(dev, flag)
154 	register dev_t dev;
155 	register flag;
156 {
157 	register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
158 
159 	if (flag == FWRITE || ((flag&FWRITE) && (sc->sc_flags&H_WRITTEN)))
160 		mtcommand(dev, MT_CLS|sc->sc_dens, 1);
161 	if ((minor(dev)&H_NOREWIND) == 0)
162 		mtcommand(dev, MT_REW, 0);
163 	sc->sc_openf = 0;
164 }
165 
166 mtcommand(dev, com, count)
167 	dev_t dev;
168 	int com, count;
169 {
170 	register struct buf *bp;
171 	register int s;
172 
173 	bp = &cmtbuf[MTUNIT(dev)];
174 	s = spl5();
175 	while (bp->b_flags&B_BUSY) {
176 		if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE))
177 			break;
178 		bp->b_flags |= B_WANTED;
179 		sleep((caddr_t)bp, PRIBIO);
180 	}
181 	bp->b_flags = B_BUSY|B_READ;
182 	splx(s);
183 	bp->b_dev = dev;
184 	bp->b_command = com;
185 	bp->b_repcnt = count;
186 	bp->b_blkno = 0;
187 	mtstrategy(bp);
188 	if (count == 0)
189 		return;
190 	iowait(bp);
191 	if (bp->b_flags&B_WANTED)
192 		wakeup((caddr_t)bp);
193 	bp->b_flags &= B_ERROR;
194 }
195 
196 mtstrategy(bp)
197 	register struct buf *bp;
198 {
199 	register struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)];
200 	register struct buf *dp;
201 	register int s;
202 
203 	bp->av_forw = NULL;
204 	dp = &mi->mi_tab;
205 	s = spl5();
206 	if (dp->b_actf == NULL)
207 		dp->b_actf = bp;
208 	else
209 		dp->b_actl->av_forw = bp;
210 	dp->b_actl = bp;
211 	if (dp->b_active == 0)
212 		mbustart(mi);
213 	splx(s);
214 }
215 
216 mtustart(mi)
217 	register struct mba_device *mi;
218 {
219 	register struct mtdevice *mtaddr =
220 	    (struct mtdevice *)mi->mi_drv;
221 	register struct buf *bp = mi->mi_tab.b_actf;
222 	register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
223 	daddr_t blkno;
224 
225 	sc->sc_flags &= ~H_WRITTEN;
226 	if (sc->sc_openf < 0) {
227 		bp->b_flags |= B_ERROR;
228 		return (MBU_NEXT);
229 	}
230 	if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) {
231 		if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) {
232 			bp->b_flags |= B_ERROR;
233 			bp->b_error = ENXIO;
234 			return (MBU_NEXT);
235 		}
236 		if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec &&
237 		    bp->b_flags&B_READ) {
238 			bp->b_resid = bp->b_bcount;
239 			clrbuf(bp);
240 			return (MBU_NEXT);
241 		}
242 		if ((bp->b_flags&B_READ)==0)
243 			sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1;
244 	} else {
245 		mtaddr->mtncs[MUUNIT(bp->b_dev)] =
246 			(bp->b_repcnt<<8)|bp->b_command|MT_GO;
247 		return (MBU_STARTED);
248 	}
249 	if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) {
250 		if (mi->mi_tab.b_errcnt == 2) {
251 			mtaddr->mtca = MUUNIT(bp->b_dev);
252 		} else {
253 			mtaddr->mtbc = bp->b_bcount;
254 			mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev);
255 		}
256 		return (MBU_DODATA);
257 	}
258 	if (blkno < bdbtofsb(bp->b_blkno))
259 		mtaddr->mtncs[MUUNIT(bp->b_dev)] =
260 		  (min((unsigned)(bdbtofsb(bp->b_blkno) - blkno), 0377) << 8) |
261 			MT_SFORW|MT_GO;
262 	else
263 		mtaddr->mtncs[MUUNIT(bp->b_dev)] =
264 		  (min((unsigned)(blkno - bdbtofsb(bp->b_blkno)), 0377) << 8) |
265 			MT_SREV|MT_GO;
266 	return (MBU_STARTED);
267 }
268 
269 mtstart(mi)
270 	register struct mba_device *mi;
271 {
272 	register struct buf *bp = mi->mi_tab.b_actf;
273 	register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
274 
275 	if (bp->b_flags & B_READ)
276 		if (mi->mi_tab.b_errcnt == 2)
277 			return(MT_READREV|MT_GO);
278 		else
279 			return(MT_READ|MT_GO);
280 	else
281 		return(MT_WRITE|sc->sc_dens|MT_GO);
282 }
283 
284 mtdtint(mi, mbsr)
285 	register struct mba_device *mi;
286 	int mbsr;
287 {
288 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
289 	register struct buf *bp = mi->mi_tab.b_actf;
290 	register struct mu_softc *sc;
291 
292 	/* I'M NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */
293 	if ((mtaddr->mtca&3) != MUUNIT(bp->b_dev)) {
294 		printf("mt: wrong unit!\n");
295 		mtaddr->mtca = MUUNIT(bp->b_dev);
296 	}
297 	sc = &mu_softc[MUUNIT(bp->b_dev)];
298 	sc->sc_erreg = mtaddr->mter;
299 	if((bp->b_flags & B_READ) == 0)
300 		sc->sc_flags |= H_WRITTEN;
301 	switch (sc->sc_erreg & MTER_INTCODE) {
302 	case MTER_DONE:
303 	case MTER_LONGREC:
304 		if (mi->mi_tab.b_errcnt != 2)
305 			sc->sc_blkno++;
306 		bp->b_resid = 0;
307 		break;
308 
309 	case MTER_NOTCAP:
310 		printf("mu%d: blank tape\n", MUUNIT(bp->b_dev));
311 		goto err;
312 
313 	case MTER_TM:
314 	case MTER_EOT:
315 		sc->sc_blkno++;
316 	err:
317 		bp->b_resid = bp->b_bcount;
318 		sc->sc_nxrec = bdbtofsb(bp->b_blkno);
319 		break;
320 
321 	case MTER_SHRTREC:
322 		sc->sc_blkno++;
323 		if (bp != &rmtbuf[MTUNIT(bp->b_dev)])
324 			bp->b_flags |= B_ERROR;
325 		if (mi->mi_tab.b_errcnt == 2)
326 			bp->b_bcount = bp->b_resid;	/* restore saved value */
327 		bp->b_resid = bp->b_bcount - mtaddr->mtbc;
328 		break;
329 
330 	case MTER_RDOPP:
331 		mi->mi_tab.b_errcnt = 2;	/* indicate "read opposite" */
332 		bp->b_resid = bp->b_bcount;	/* save it */
333 		bp->b_bcount = mtaddr->mtbc;	/* use this instead */
334 		return(MBD_RETRY);
335 
336 	case MTER_RETRY:
337 		mi->mi_tab.b_errcnt = 1;	/* indicate simple retry */
338 		return(MBD_RETRY);
339 
340 	case MTER_OFFLINE:
341 		if (sc->sc_openf > 0) {
342 			sc->sc_openf = -1;
343 			printf("mu%d: offline\n", MUUNIT(bp->b_dev));
344 		}
345 		bp->b_flags |= B_ERROR;
346 		break;
347 
348 	case MTER_FPT:
349 		printf("mu%d: no write ring\n", MUUNIT(bp->b_dev));
350 		bp->b_flags |= B_ERROR;
351 		break;
352 
353 	default:
354 		printf("mu%d: hard error bn%d mbsr=%b er=%x ds=%b\n",
355 		    MUUNIT(bp->b_dev), bp->b_blkno,
356 		    mbsr, mbsr_bits, sc->sc_erreg,
357 		    sc->sc_dsreg, mtds_bits);
358 		bp->b_flags |= B_ERROR;
359 		mtaddr->mtid = MTID_CLR;		/* reset the TM78 */
360 		DELAY(250);
361 		while ((mtaddr->mtid & MTID_RDY) == 0)	/* wait for it */
362 			;
363 		return (MBD_DONE);
364 	}
365 	/* CHECK FOR MBA ERROR WHEN NO OTHER ERROR INDICATED? */
366 	return (MBD_DONE);
367 }
368 
369 mtndtint(mi)
370 	register struct mba_device *mi;
371 {
372 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
373 	register struct buf *bp = mi->mi_tab.b_actf;
374 	register struct mu_softc *sc;
375 	int er, fc, unit;
376 
377 	unit = (mtaddr->mtner >> 8) & 3;
378 	er = MASKREG(mtaddr->mtner);
379 	/* WILL THIS OCCUR IF ANOTHER DRIVE COMES ONLINE? */
380 	if (bp == 0 || unit != MUUNIT(bp->b_dev)) {	/* consistency check */
381 		if ((er & MTER_INTCODE) != MTER_ONLINE)
382 			printf("mt: unit %d random interrupt\n", unit);
383 		return (MBN_SKIP);
384 	}
385 	if (bp == 0)
386 		return (MBN_SKIP);
387 	fc = (mtaddr->mtncs[unit] >> 8) & 0xff;
388 	sc = &mu_softc[unit];
389 	sc->sc_erreg = er;
390 	sc->sc_resid = fc;
391 	switch (er & MTER_INTCODE) {
392 	case MTER_DONE:
393 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) {
394 	done:
395 			if (bp->b_command == MT_SENSE)
396 				sc->sc_dsreg = MASKREG(mtaddr->mtds);
397 			bp->b_resid = fc;
398 			return (MBN_DONE);
399 		}
400 		/* this is UGLY!  (but is it correct?) */
401 		if ((fc = bdbtofsb(bp->b_blkno) - sc->sc_blkno) < 0)
402 			sc->sc_blkno -= MIN(0377, -fc);
403 		else
404 			sc->sc_blkno += MIN(0377, fc);
405 		return (MBN_RETRY);
406 
407 	case MTER_RWDING:
408 		return (MBN_SKIP);	/* ignore "rewind started" interrupt */
409 
410 	case MTER_NOTCAP:
411 		printf("mu%d: blank tape\n", MUUNIT(bp->b_dev));
412 
413 	case MTER_TM:
414 	case MTER_EOT:
415 	case MTER_LEOT:
416 		if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) {
417 			sc->sc_nxrec = bdbtofsb(bp->b_blkno) + fc;
418 			sc->sc_blkno = sc->sc_nxrec;
419 		} else {
420 			sc->sc_blkno = bdbtofsb(bp->b_blkno) - fc;
421 			sc->sc_nxrec = sc->sc_blkno - 1;
422 		}
423 		return (MBN_RETRY);
424 
425 	case MTER_FPT:
426 		printf("mu%d: no write ring\n", MUUNIT(bp->b_dev));
427 		bp->b_flags |= B_ERROR;
428 		return (MBN_DONE);
429 
430 	case MTER_OFFLINE:
431 		if (sc->sc_openf > 0) {
432 			sc->sc_openf = -1;
433 			printf("mu%d: offline\n", MUUNIT(bp->b_dev));
434 		}
435 		bp->b_flags |= B_ERROR;
436 		return (MBN_DONE);
437 
438 	case MTER_BOT:
439 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)])
440 			goto done;
441 		/* FALL THROUGH */
442 
443 	default:
444 		printf("mu%d: hard error bn%d er=%o ds=%b\n",
445 		    MUUNIT(bp->b_dev), bp->b_blkno,
446 		    sc->sc_erreg, sc->sc_dsreg, mtds_bits);
447 		mtaddr->mtid = MTID_CLR;		/* reset the TM78 */
448 		DELAY(250);
449 		while ((mtaddr->mtid & MTID_RDY) == 0)	/* wait for it */
450 			;
451 		bp->b_flags |= B_ERROR;
452 		return (MBN_DONE);
453 	}
454 	/* NOTREACHED */
455 }
456 
457 mtread(dev, uio)
458 	dev_t dev;
459 	struct uio *uio;
460 {
461 	int errno;
462 
463 	errno = mtphys(dev, uio);
464 	if (errno)
465 		return (errno);
466 	return (physio(mtstrategy, &rmtbuf[MTUNIT(dev)], dev, B_READ, minphys, uio));
467 }
468 
469 mtwrite(dev, uio)
470 	dev_t dev;
471 	struct uio *uio;
472 {
473 	int errno;
474 
475 	errno = mtphys(dev, uio);
476 	if (errno)
477 		return (errno);
478 	return (physio(mtstrategy, &rmtbuf[MTUNIT(dev)], dev, B_WRITE, minphys, uio));
479 }
480 
481 mtphys(dev, uio)
482 	dev_t dev;
483 	struct uio *uio;
484 {
485 	register int mtunit;
486 	register struct mu_softc *sc;
487 	register struct mba_device *mi;
488 	daddr_t a;
489 
490 	mtunit = MTUNIT(dev);
491 	if (mtunit >= NMT || (mi = mtinfo[mtunit]) == 0 || mi->mi_alive == 0)
492 		return (ENXIO);
493 	a = uio->uio_offset >> 9;
494 	sc = &mu_softc[MUUNIT(dev)];
495 	sc->sc_blkno = bdbtofsb(a);
496 	sc->sc_nxrec = bdbtofsb(a)+1;
497 	return (0);
498 }
499 
500 /*ARGSUSED*/
501 mtioctl(dev, cmd, data, flag)
502 	dev_t dev;
503 	int cmd;
504 	caddr_t data;
505 	int flag;
506 {
507 	register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
508 	register struct buf *bp = &cmtbuf[MTUNIT(dev)];
509 	register callcount;
510 	register int op;
511 	int fcount;
512 	struct mtop *mtop;
513 	struct mtget *mtget;
514 	/* we depend of the values and order of the MT codes here */
515 	static mtops[] =
516 	{MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE};
517 
518 	switch (cmd) {
519 
520 	case MTIOCTOP:	/* tape operation */
521 		mtop = (struct mtop *)mtop;
522 		switch(mtop->mt_op) {
523 
524 		case MTWEOF:
525 			callcount = mtop->mt_count;
526 			fcount = 1;
527 			break;
528 
529 		case MTFSF: case MTBSF:
530 			callcount = mtop->mt_count;
531 			fcount = 1;
532 			break;
533 
534 		case MTFSR: case MTBSR:
535 			callcount = 1;
536 			fcount = mtop->mt_count;
537 			break;
538 
539 		case MTREW: case MTOFFL:
540 			callcount = 1;
541 			fcount = 1;
542 			break;
543 
544 		default:
545 			u.u_error = ENXIO;
546 			return;
547 		}
548 		if (callcount <= 0 || fcount <= 0) {
549 			u.u_error = ENXIO;
550 			return;
551 		}
552 		op = mtops[mtop->mt_op];
553 		if (op == MT_WTM)
554 			op |= sc->sc_dens;
555 		while (--callcount >= 0) {
556 			register int n;
557 
558 			do {
559 				n = MIN(fcount, 0xff);
560 				mtcommand(dev, op, n);
561 				fcount -= n;
562 			} while (fcount);
563 			if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) &&
564 			    bp->b_resid) {
565 				u.u_error = EIO;
566 				break;
567 			}
568 			if (bp->b_flags&B_ERROR)
569 				break;
570 		}
571 		geterror(bp);
572 		return;
573 
574 	case MTIOCGET:
575 		mtget = (struct mtget *)data;
576 		mtget->mt_erreg = sc->sc_erreg;
577 		mtget->mt_resid = sc->sc_resid;
578 		mtcommand(dev, MT_SENSE, 1);	/* update drive status */
579 		mtget->mt_dsreg = sc->sc_dsreg;
580 		mtget->mt_type = MT_ISMT;
581 		return;
582 
583 	default:
584 		u.u_error = ENXIO;
585 	}
586 }
587 
588 #define	DBSIZE	20
589 
590 mtdump()
591 {
592 	register struct mba_device *mi;
593 	register struct mba_regs *mp;
594 	register struct mtdevice *mtaddr;
595 	int blk, num;
596 	int start;
597 
598 	start = 0;
599 	num = maxfree;
600 #define	phys(a,b)		((b)((int)(a)&0x7fffffff))
601 	if (mtinfo[0] == 0)
602 		return (ENXIO);
603 	mi = phys(mtinfo[0], struct mba_device *);
604 	mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba;
605 	mp->mba_cr = MBCR_IE;
606 #if lint
607 	blk = blk; num = num; start = start;
608 	return (0);
609 #endif
610 #ifdef notyet
611 	mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive];
612 	mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI;
613 	mtaddr->mtcs1 = MT_DCLR|MT_GO;
614 	while (num > 0) {
615 		blk = num > DBSIZE ? DBSIZE : num;
616 		mtdwrite(start, blk, mtaddr, mp);
617 		start += blk;
618 		num -= blk;
619 	}
620 	mteof(mtaddr);
621 	mteof(mtaddr);
622 	mtwait(mtaddr);
623 	if (mtaddr->mtds&MTDS_ERR)
624 		return (EIO);
625 	mtaddr->mtcs1 = MT_REW|MT_GO;
626 	return (0);
627 }
628 
629 mtdwrite(dbuf, num, mtaddr, mp)
630 	register dbuf, num;
631 	register struct mtdevice *mtaddr;
632 	struct mba_regs *mp;
633 {
634 	register struct pte *io;
635 	register int i;
636 
637 	mtwait(mtaddr);
638 	io = mp->mba_map;
639 	for (i = 0; i < num; i++)
640 		*(int *)io++ = dbuf++ | PG_V;
641 	mtaddr->mtfc = -(num*NBPG);
642 	mp->mba_sr = -1;
643 	mp->mba_bcr = -(num*NBPG);
644 	mp->mba_var = 0;
645 	mtaddr->mtcs1 = MT_WCOM|MT_GO;
646 }
647 
648 mtwait(mtaddr)
649 	struct mtdevice *mtaddr;
650 {
651 	register s;
652 
653 	do
654 		s = mtaddr->mtds;
655 	while ((s & MTDS_DRY) == 0);
656 }
657 
658 mteof(mtaddr)
659 	struct mtdevice *mtaddr;
660 {
661 
662 	mtwait(mtaddr);
663 	mtaddr->mtcs1 = MT_WEOF|MT_GO;
664 #endif notyet
665 }
666 #endif
667