xref: /csrg-svn/sys/vax/uba/tm.c (revision 2324)
1*2324Skre /*	tm.c	4.7	01/31/81	*/
21919Swnj 
31940Swnj #include "tm.h"
41919Swnj #if NTM > 0
51919Swnj /*
61919Swnj  * TM tape driver
71919Swnj  */
8*2324Skre #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"
211919Swnj 
221919Swnj struct device {
231919Swnj 	u_short	tmer;
241919Swnj 	u_short	tmcs;
251919Swnj 	short	tmbc;
261919Swnj 	u_short tmba;
271919Swnj 	short	tmdb;
281919Swnj 	short	tmrd;
291919Swnj };
301919Swnj 
311919Swnj #define	b_repcnt  b_bcount
321919Swnj #define	b_command b_resid
331919Swnj 
341919Swnj struct	buf	tmtab;
351919Swnj struct	buf	ctmbuf;
361919Swnj struct	buf	rtmbuf;
371919Swnj 
381919Swnj int	tm_ubinfo;
391919Swnj 
401919Swnj /* bits in minor device */
411919Swnj #define	T_NOREWIND	04
421919Swnj #define	T_1600BPI	08
431919Swnj 
441919Swnj #define	INF	(daddr_t)1000000L
451919Swnj 
461919Swnj /*
471919Swnj  * Really only handle one tape drive... if you have more than one,
481919Swnj  * you can make all these arrays and change the obvious things, but
491919Swnj  * it is not clear what happens when some drives are transferring while
501919Swnj  * others rewind, so we don't pretend that this driver handles multiple
511919Swnj  * tape drives.
521919Swnj  */
531919Swnj char	t_openf;
541919Swnj daddr_t	t_blkno;
551919Swnj char	t_flags;
561919Swnj daddr_t	t_nxrec;
571919Swnj u_short	t_erreg;
581919Swnj u_short	t_dsreg;
591919Swnj short	t_resid;
601919Swnj 
611919Swnj /* bits in tmcs */
621919Swnj #define	GO	01
631919Swnj #define	OFFL	0
641919Swnj #define	RCOM	02
651919Swnj #define	WCOM	04
661919Swnj #define	WEOF	06
671919Swnj #define	SFORW	010
681919Swnj #define	SREV	012
691919Swnj #define	WIRG	014
701919Swnj #define	REW	016
711919Swnj #define	IENABLE	0100
721919Swnj #define	CUR	0200
731919Swnj #define	NOP	IENABLE
741919Swnj #define	DCLR	010000
751919Swnj #define	D800	060000
761919Swnj #define	ERROR	0100000
771919Swnj 
781919Swnj /* bits in tmer */
791919Swnj #define	TUR	1
801919Swnj #define	RWS	02
811919Swnj #define	WRL	04
821919Swnj #define	SDWN	010
831919Swnj #define	BOT	040
841919Swnj #define	SELR	0100
851919Swnj #define	NXM	0200
861919Swnj #define	TMBTE	0400
871919Swnj #define	RLE	01000
881919Swnj #define	EOT	02000
891919Swnj #define	BGL	04000
901919Swnj #define	PAE	010000
911919Swnj #define	CRE	020000
921919Swnj #define	EOF	040000
931919Swnj #define	ILC	0100000
941919Swnj 
951919Swnj #define	HARD    (ILC|EOT)
961919Swnj #define	SOFT	(CRE|PAE|BGL|RLE|TMBTE|NXM)
971919Swnj 
981919Swnj #define	SSEEK	1		/* seeking */
991919Swnj #define	SIO	2		/* doing seq i/o */
1001919Swnj #define	SCOM	3		/* sending control command */
1011919Swnj 
1021919Swnj #define	LASTIOW 1		/* last op was a write */
1031919Swnj #define	WAITREW	2		/* someone is waiting for a rewind */
1041919Swnj 
1051919Swnj tmopen(dev, flag)
1061919Swnj 	dev_t dev;
1071919Swnj 	int flag;
1081919Swnj {
1091919Swnj 	register ds, unit;
1101919Swnj 
1111919Swnj 	tmtab.b_flags |= B_TAPE;
1121919Swnj 	unit = minor(dev)&03;
1131919Swnj 	if (unit >= NTM || t_openf) {
1141919Swnj 		u.u_error = ENXIO;		/* out of range or open */
1151919Swnj 		return;
1161919Swnj 	}
1171919Swnj 	tcommand(dev, NOP, 1);
1181919Swnj 	if ((t_erreg&SELR) == 0) {
1191919Swnj 		u.u_error = EIO;		/* offline */
1201919Swnj 		return;
1211919Swnj 	}
1221919Swnj 	t_openf = 1;
1231919Swnj 	if (t_erreg&RWS)
1241919Swnj 		tmwaitrws(dev);			/* wait for rewind complete */
1251919Swnj 	while (t_erreg&SDWN)
1261919Swnj 		tcommand(dev, NOP, 1);		/* await settle down */
1271919Swnj 	if ((t_erreg&TUR)==0 ||
1281919Swnj 	    ((flag&(FREAD|FWRITE)) == FWRITE && (t_erreg&WRL))) {
1291919Swnj 		TMADDR->tmcs = DCLR|GO;
1301919Swnj 		u.u_error = EIO;		/* offline or write protect */
1311919Swnj 	}
1321919Swnj 	if (u.u_error != 0) {
1331919Swnj 		t_openf = 0;
1341919Swnj 		return;
1351919Swnj 	}
1361919Swnj 	t_blkno = (daddr_t)0;
1371919Swnj 	t_nxrec = INF;
1381919Swnj 	t_flags = 0;
1391919Swnj 	t_openf = 1;
1401919Swnj }
1411919Swnj 
1421919Swnj tmwaitrws(dev)
1431919Swnj 	register dev;
1441919Swnj {
1451919Swnj 
1461919Swnj 	spl5();
1471919Swnj 	for (;;) {
1481928Swnj 		if ((TMADDR->tmer&RWS) == 0) {
1491919Swnj 			spl0();		/* rewind complete */
1501919Swnj 			return;
1511919Swnj 		}
1521919Swnj 		t_flags |= WAITREW;
1531919Swnj 		sleep((caddr_t)&t_flags, PRIBIO);
1541919Swnj 	}
1551919Swnj }
1561919Swnj 
1571919Swnj tmclose(dev, flag)
1581919Swnj 	register dev_t dev;
1591919Swnj 	register flag;
1601919Swnj {
1611919Swnj 
1621919Swnj 	if (flag == FWRITE || ((flag&FWRITE) && (t_flags&LASTIOW))) {
1631919Swnj 		tcommand(dev, WEOF, 1);
1641919Swnj 		tcommand(dev, WEOF, 1);
1651919Swnj 		tcommand(dev, SREV, 1);
1661919Swnj 	}
1671919Swnj 	if ((minor(dev)&T_NOREWIND) == 0)
1681919Swnj 		tcommand(dev, REW, 1);
1691919Swnj 	t_openf = 0;
1701919Swnj }
1711919Swnj 
1721919Swnj tcommand(dev, com, count)
1731919Swnj 	dev_t dev;
1741919Swnj 	int com, count;
1751919Swnj {
1761919Swnj 	register struct buf *bp;
1771919Swnj 
1781919Swnj 	bp = &ctmbuf;
1791919Swnj 	(void) spl5();
1801919Swnj 	while (bp->b_flags&B_BUSY) {
1811919Swnj 		bp->b_flags |= B_WANTED;
1821919Swnj 		sleep((caddr_t)bp, PRIBIO);
1831919Swnj 	}
1841919Swnj 	bp->b_flags = B_BUSY|B_READ;
1851919Swnj 	(void) spl0();
1861919Swnj 	bp->b_dev = dev;
1871919Swnj 	bp->b_repcnt = -count;
1881919Swnj 	bp->b_command = com;
1891919Swnj 	bp->b_blkno = 0;
1901919Swnj 	tmstrategy(bp);
1911919Swnj 	iowait(bp);
1921919Swnj 	if (bp->b_flags&B_WANTED)
1931919Swnj 		wakeup((caddr_t)bp);
1941919Swnj 	bp->b_flags &= B_ERROR;
1951919Swnj }
1961919Swnj 
1971919Swnj tmstrategy(bp)
1981919Swnj 	register struct buf *bp;
1991919Swnj {
2001919Swnj 	register daddr_t *p;
2011919Swnj 
2021928Swnj 	tmwaitrws(bp->b_dev);
2031919Swnj 	if (bp != &ctmbuf) {
2041919Swnj 		p = &t_nxrec;
2051919Swnj 		if (dbtofsb(bp->b_blkno) > *p) {
2061919Swnj 			bp->b_flags |= B_ERROR;
2071919Swnj 			bp->b_error = ENXIO;		/* past EOF */
2081919Swnj 			iodone(bp);
2091919Swnj 			return;
2101919Swnj 		} else if (dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) {
2111919Swnj 			bp->b_resid = bp->b_bcount;
2121919Swnj 			clrbuf(bp);			/* at EOF */
2131919Swnj 			iodone(bp);
2141919Swnj 			return;
2151919Swnj 		} else if ((bp->b_flags&B_READ) == 0)
2161919Swnj 			*p = dbtofsb(bp->b_blkno) + 1;	/* write sets EOF */
2171919Swnj 	}
2181919Swnj 	bp->av_forw = NULL;
2191919Swnj 	(void) spl5();
2201919Swnj 	if (tmtab.b_actf == NULL)
2211919Swnj 		tmtab.b_actf = bp;
2221919Swnj 	else
2231919Swnj 		tmtab.b_actl->av_forw = bp;
2241919Swnj 	tmtab.b_actl = bp;
2251919Swnj 	if (tmtab.b_active == 0)
2261919Swnj 		tmstart();
2271919Swnj 	(void) spl0();
2281919Swnj }
2291919Swnj 
2301919Swnj tmstart()
2311919Swnj {
2321919Swnj 	register struct buf *bp;
2331919Swnj 	register cmd;
2341919Swnj 	register daddr_t blkno;
2352054Swnj 	int s;
2361919Swnj 
2371919Swnj loop:
2381919Swnj 	if ((bp = tmtab.b_actf) == 0)
2391919Swnj 		return;
2401919Swnj 	t_dsreg = TMADDR->tmcs;
2411919Swnj 	t_erreg = TMADDR->tmer;
2421919Swnj 	t_resid = TMADDR->tmbc;
2431919Swnj 	t_flags &= ~LASTIOW;
2441919Swnj 	if (t_openf < 0 || (TMADDR->tmcs&CUR) == 0) {
2451919Swnj 		/* t_openf = -1; ??? */
2461919Swnj 		bp->b_flags |= B_ERROR;		/* hard error'ed or !SELR */
2471919Swnj 		goto next;
2481919Swnj 	}
2491919Swnj 	cmd = IENABLE | GO;
2501919Swnj 	if ((minor(bp->b_dev) & T_1600BPI) == 0)
2511919Swnj 		cmd |= D800;
2521919Swnj 	if (bp == &ctmbuf) {
2531919Swnj 		if (bp->b_command == NOP)
2541919Swnj 			goto next;		/* just get status */
2551919Swnj 		else {
2561919Swnj 			cmd |= bp->b_command;
2571919Swnj 			tmtab.b_active = SCOM;
2581919Swnj 			if (bp->b_command == SFORW || bp->b_command == SREV)
2591919Swnj 				TMADDR->tmbc = bp->b_repcnt;
2601919Swnj 			TMADDR->tmcs = cmd;
2611919Swnj 			return;
2621919Swnj 		}
2631919Swnj 	}
2641919Swnj 	if ((blkno = t_blkno) == dbtofsb(bp->b_blkno)) {
2651919Swnj 		TMADDR->tmbc = -bp->b_bcount;
2662054Swnj 		s = spl6();
2671919Swnj 		if (tm_ubinfo == 0)
2681919Swnj 			tm_ubinfo = ubasetup(bp,1);
2692054Swnj 		splx(s);
2701919Swnj 		if ((bp->b_flags&B_READ) == 0) {
2711919Swnj 			if (tmtab.b_errcnt)
2721919Swnj 				cmd |= WIRG;
2731919Swnj 			else
2741919Swnj 				cmd |= WCOM;
2751919Swnj 		} else
2761919Swnj 			cmd |= RCOM;
2771919Swnj 		cmd |= (tm_ubinfo >> 12) & 0x30;
2781919Swnj 		tmtab.b_active = SIO;
2791919Swnj 		TMADDR->tmba = tm_ubinfo;
2801919Swnj 		TMADDR->tmcs = cmd;
2811919Swnj 		return;
2821919Swnj 	}
2831919Swnj 	tmtab.b_active = SSEEK;
2841919Swnj 	if (blkno < dbtofsb(bp->b_blkno)) {
2851919Swnj 		cmd |= SFORW;
2861919Swnj 		TMADDR->tmbc = blkno - dbtofsb(bp->b_blkno);
2871919Swnj 	} else {
2881919Swnj 		cmd |= SREV;
2891919Swnj 		TMADDR->tmbc = dbtofsb(bp->b_blkno) - blkno;
2901919Swnj 	}
2911919Swnj 	TMADDR->tmcs = cmd;
2921919Swnj 	return;
2931919Swnj 
2941919Swnj next:
2952054Swnj 	ubarelse(&tm_ubinfo);
2961919Swnj 	tmtab.b_actf = bp->av_forw;
2971919Swnj 	iodone(bp);
2981919Swnj 	goto loop;
2991919Swnj }
3001919Swnj 
3011919Swnj tmintr()
3021919Swnj {
3031919Swnj 	register struct buf *bp;
3041919Swnj 	register state;
3051919Swnj 
3061919Swnj 	if (t_flags&WAITREW && (TMADDR->tmer&RWS) == 0) {
3071919Swnj 		t_flags &= ~WAITREW;
3081919Swnj 		wakeup((caddr_t)&t_flags);
3091919Swnj 	}
3101919Swnj 	if ((bp = tmtab.b_actf) == NULL)
3111919Swnj 		return;
3121919Swnj 	t_dsreg = TMADDR->tmcs;
3131919Swnj 	t_erreg = TMADDR->tmer;
3141919Swnj 	t_resid = TMADDR->tmbc;
3151919Swnj 	if ((bp->b_flags & B_READ) == 0)
3161919Swnj 		t_flags |= LASTIOW;
3171919Swnj 	state = tmtab.b_active;
3181919Swnj 	tmtab.b_active = 0;
3191919Swnj 	if (TMADDR->tmcs&ERROR) {
3201919Swnj 		while(TMADDR->tmer & SDWN)
3211919Swnj 			;			/* await settle down */
3221919Swnj 		if (TMADDR->tmer&EOF) {
3231919Swnj 			tmseteof(bp);	/* set blkno and nxrec */
3241919Swnj 			state = SCOM;
3251919Swnj 			TMADDR->tmbc = -bp->b_bcount;
3261919Swnj 			goto errout;
3271919Swnj 		}
3281919Swnj 		if ((bp->b_flags&B_READ) && (TMADDR->tmer&(HARD|SOFT)) == RLE)
3291919Swnj 			goto out;
3301919Swnj 		if ((TMADDR->tmer&HARD)==0 && state==SIO) {
3311928Swnj 			if (++tmtab.b_errcnt < 7) {
3321919Swnj 				if((TMADDR->tmer&SOFT) == NXM)
3331919Swnj 					printf("TM UBA late error\n");
3341919Swnj 				else
3351928Swnj 					t_blkno += 2;		/* ???????? */
3362054Swnj 				ubarelse(&tm_ubinfo);
3371919Swnj 				tmstart();
3381919Swnj 				return;
3391919Swnj 			}
3401919Swnj 		} else if (t_openf>0 && bp != &rtmbuf)
3411919Swnj 			t_openf = -1;
3421928Swnj 		deverror(bp, t_erreg, t_dsreg);
3431919Swnj 		bp->b_flags |= B_ERROR;
3441919Swnj 		state = SIO;
3451919Swnj 	}
3461919Swnj out:
3471919Swnj 	switch (state) {
3481919Swnj 
3491919Swnj 	case SIO:
3501919Swnj 		t_blkno++;
3511919Swnj 		/* fall into ... */
3521919Swnj 
3531919Swnj 	case SCOM:
3541919Swnj 		if (bp == &ctmbuf) {
3551919Swnj 			switch (bp->b_command) {
3561919Swnj 			case SFORW:
3571919Swnj 				t_blkno -= bp->b_repcnt;
3581919Swnj 				break;
3591919Swnj 
3601919Swnj 			case SREV:
3611919Swnj 				t_blkno += bp->b_repcnt;
3621919Swnj 				break;
3631919Swnj 
3641919Swnj 			default:
3651919Swnj 				if (++bp->b_repcnt < 0) {
3661919Swnj 					tmstart();	/* continue */
3671919Swnj 					return;
3681919Swnj 				}
3691919Swnj 			}
3701919Swnj 		}
3711919Swnj errout:
3721919Swnj 		tmtab.b_errcnt = 0;
3731919Swnj 		tmtab.b_actf = bp->av_forw;
3741919Swnj 		bp->b_resid = -TMADDR->tmbc;
3752054Swnj 		ubarelse(&tm_ubinfo);
3761919Swnj 		iodone(bp);
3771919Swnj 		break;
3781919Swnj 
3791919Swnj 	case SSEEK:
3801919Swnj 		t_blkno = dbtofsb(bp->b_blkno);
3811919Swnj 		break;
3821919Swnj 
3831919Swnj 	default:
3841919Swnj 		return;
3851919Swnj 	}
3861919Swnj 	tmstart();
3871919Swnj }
3881919Swnj 
3891919Swnj tmseteof(bp)
3901919Swnj 	register struct buf *bp;
3911919Swnj {
3921919Swnj 
3931919Swnj 	if (bp == &ctmbuf) {
3941919Swnj 		if (t_blkno > dbtofsb(bp->b_blkno)) {
3951919Swnj 			/* reversing */
3961919Swnj 			t_nxrec = dbtofsb(bp->b_blkno) - TMADDR->tmbc;
3971919Swnj 			t_blkno = t_nxrec;
3981919Swnj 		} else {
3991919Swnj 			/* spacing forward */
4001919Swnj 			t_blkno = dbtofsb(bp->b_blkno) + TMADDR->tmbc;
4011919Swnj 			t_nxrec = t_blkno - 1;
4021919Swnj 		}
4031919Swnj 		return;
4041919Swnj 	}
4051919Swnj 	/* eof on read */
4061919Swnj 	t_nxrec = dbtofsb(bp->b_blkno);
4071919Swnj }
4081919Swnj 
4091919Swnj tmread(dev)
4101919Swnj {
4111919Swnj 
4121919Swnj 	tmphys(dev);
4131919Swnj 	physio(tmstrategy, &rtmbuf, dev, B_READ, minphys);
4141919Swnj }
4151919Swnj 
4161919Swnj tmwrite(dev)
4171919Swnj {
4181919Swnj 
4191919Swnj 	tmphys(dev);
4201919Swnj 	physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys);
4211919Swnj }
4221919Swnj 
4231919Swnj tmphys(dev)
4241919Swnj {
4251919Swnj 	register daddr_t a;
4261919Swnj 
4271919Swnj 	a = dbtofsb(u.u_offset >> 9);
4281919Swnj 	t_blkno = a;
4291919Swnj 	t_nxrec = a + 1;
4301919Swnj }
4311919Swnj 
4321919Swnj /*ARGSUSED*/
4331919Swnj tmioctl(dev, cmd, addr, flag)
4341919Swnj 	caddr_t addr;
4351919Swnj 	dev_t dev;
4361919Swnj {
4371919Swnj 	register callcount;
4381919Swnj 	int fcount;
4391919Swnj 	struct mtop mtop;
4401919Swnj 	struct mtget mtget;
4411919Swnj 	/* we depend of the values and order of the MT codes here */
442*2324Skre 	static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL, NOP};
4431919Swnj 
4441919Swnj 	switch(cmd) {
4451919Swnj 		case MTIOCTOP:	/* tape operation */
4461919Swnj 		if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
4471919Swnj 			u.u_error = EFAULT;
4481919Swnj 			return;
4491919Swnj 		}
4501919Swnj 		switch(mtop.mt_op) {
4511919Swnj 		case MTWEOF: case MTFSF: case MTBSF:
4521919Swnj 			callcount = mtop.mt_count;
4531919Swnj 			fcount = INF;
4541919Swnj 			break;
4551919Swnj 		case MTFSR: case MTBSR:
4561919Swnj 			callcount = 1;
4571919Swnj 			fcount = mtop.mt_count;
4581919Swnj 			break;
459*2324Skre 		case MTREW: case MTOFFL: case MTNOP:
4601919Swnj 			callcount = 1;
4611919Swnj 			fcount = 1;
4621919Swnj 			break;
4631919Swnj 		default:
4641919Swnj 			u.u_error = ENXIO;
4651919Swnj 			return;
4661919Swnj 		}
4671919Swnj 		if (callcount <= 0 || fcount <= 0)
4681919Swnj 			u.u_error = ENXIO;
4691919Swnj 		else while (--callcount >= 0) {
4701919Swnj 			tcommand(dev, tmops[mtop.mt_op], fcount);
4711919Swnj 			if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
4721919Swnj 			    ctmbuf.b_resid) {
4731919Swnj 				u.u_error = EIO;
4741919Swnj 				break;
4751919Swnj 			}
4761919Swnj 			if ((ctmbuf.b_flags&B_ERROR) || t_erreg&BOT)
4771919Swnj 				break;
4781919Swnj 		}
4791919Swnj 		geterror(&ctmbuf);
4801919Swnj 		return;
4811919Swnj 	case MTIOCGET:
4821919Swnj 		mtget.mt_dsreg = t_dsreg;
4831919Swnj 		mtget.mt_erreg = t_erreg;
4841919Swnj 		mtget.mt_resid = t_resid;
4851919Swnj 		if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
4861919Swnj 			u.u_error = EFAULT;
4871919Swnj 		return;
4881919Swnj 	default:
4891919Swnj 		u.u_error = ENXIO;
4901919Swnj 	}
4911919Swnj }
4921919Swnj 
4931919Swnj #define	DBSIZE	20
4941919Swnj 
4951919Swnj twall(start, num)
4961919Swnj 	int start, num;
4971919Swnj {
4981919Swnj #if VAX==780
4991919Swnj 	register struct uba_regs *up = (struct uba_regs *)PHYSUBA0;
5001919Swnj #endif
5012297Swnj 	int blk, bdp;
5021919Swnj 
5031919Swnj #if VAX==780
5041919Swnj 	up->uba_cr = ADINIT;
5051919Swnj 	up->uba_cr = IFS|BRIE|USEFIE|SUEFIE;
5061919Swnj 	while ((up->uba_cnfgr & UBIC) == 0)
5071919Swnj 		;
5081919Swnj #endif
509*2324Skre 	DELAY(1000000);
510*2324Skre 	twait();
511*2324Skre 	TMPHYS->tmcs = DCLR | GO;
5121919Swnj 	while (num > 0) {
5131919Swnj 		blk = num > DBSIZE ? DBSIZE : num;
5141919Swnj 		tmdwrite(start, blk);
5151919Swnj 		start += blk;
5161919Swnj 		num -= blk;
5171919Swnj 	}
5182297Swnj 	bdp = 1;		/* crud to fool c compiler */
5192297Swnj 	((struct uba_regs *)PHYSUBA0)->uba_dpr[bdp] |= BNE;
5201919Swnj }
5211919Swnj 
5221919Swnj tmdwrite(buf, num)
5231919Swnj register buf, num;
5241919Swnj {
5251919Swnj 	register int *io, npf;
5262297Swnj 	int bdp;
5271928Swnj 
5282043Swnj 	twait();
5292297Swnj 	bdp = 1;		/* more dastardly tricks on pcc */
5302297Swnj 	((struct uba_regs *)PHYSUBA0)->uba_dpr[bdp] |= BNE;
5311919Swnj 	io = (int *)((struct uba_regs *)PHYSUBA0)->uba_map;
5321919Swnj 	npf = num+1;
5331928Swnj 	while (--npf != 0)
5341919Swnj 		 *io++ = (int)(buf++ | (1<<21) | MRV);
5351919Swnj 	*io = 0;
5361919Swnj 	TMPHYS->tmbc = -(num*NBPG);
5371919Swnj 	TMPHYS->tmba = 0;
538*2324Skre 	TMPHYS->tmcs = WCOM | GO;
5391919Swnj }
5401919Swnj 
5412043Swnj twait()
5421919Swnj {
5431928Swnj 	register s;
5441919Swnj 
5451919Swnj 	do
5461919Swnj 		s = TMPHYS->tmcs;
5471919Swnj 	while ((s & CUR) == 0);
5481919Swnj }
5491919Swnj 
5502043Swnj rewind()
5511919Swnj {
5521919Swnj 
5532043Swnj 	twait();
5541919Swnj 	TMPHYS->tmcs = REW | GO;
5551919Swnj }
5561919Swnj 
5572043Swnj teof()
5581919Swnj {
5591919Swnj 
5602043Swnj 	twait();
561*2324Skre 	TMPHYS->tmcs = WEOF | GO;
5621919Swnj }
5631919Swnj #endif
564