xref: /csrg-svn/sys/vax/uba/tm.c (revision 2458)
1*2458Swnj /*	tm.c	4.11	02/16/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	ctmbuf;
271919Swnj struct	buf	rtmbuf;
281919Swnj 
292396Swnj int	tmcntrlr(), tmslave(), tmdgo(), tmintr();
30*2458Swnj struct	uba_dinfo *tmdinfo[NTM];
31*2458Swnj struct	uba_minfo *tmminfo[NTM];
32*2458Swnj u_short	tmstd[] = { 0772520, 0 };
332396Swnj struct	uba_driver tmdriver =
34*2458Swnj 	{ tmcntrlr, tmslave, tmdgo, 0, tmstd, "tm", tmdinfo, tmminfo };
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 
662426Skre /*
672426Skre  * Determine if there is a controller for
682426Skre  * a tm at address reg.  Our goal is to make the
692426Skre  * device interrupt.
702426Skre  */
71*2458Swnj tmcntrlr(um, reg)
72*2458Swnj 	struct uba_minfo *um;
732396Swnj 	caddr_t reg;
742396Swnj {
75*2458Swnj 	register int br, cvec;
762426Skre 
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
81*2458Swnj 	 * hope that it didn't interrupt, so autoconf will ignore it.
82*2458Swnj 	 * Just in case, we will reference one
832396Swnj 	 * of the more distant registers, and hope for a machine
84*2458Swnj 	 * check, or similar disaster if this is a ts.
852396Swnj 	 */
862396Swnj 	if (badaddr(&((struct device *)reg)->tmrd, 2))
87*2458Swnj 		return (0);
88*2458Swnj 	return (1);
892396Swnj }
902396Swnj 
912396Swnj tmslave(ui, reg, slaveno)
922396Swnj 	struct uba_dinfo *ui;
932396Swnj 	caddr_t reg;
942396Swnj {
95*2458Swnj 
962396Swnj 	/*
972396Swnj 	 * Due to a design flaw, we cannot ascertain if the tape
982396Swnj 	 * exists or not unless it is on line - ie: unless a tape is
992396Swnj 	 * mounted. This is too servere a restriction to bear.
1002396Swnj 	 * As we can only handle one tape, we might just as well insist
1012396Swnj 	 * that it be slave #0, and just assume that it exists.
1022396Swnj 	 * Something better will have to be done if you have two
1032396Swnj 	 * tapes on one controller, or two controllers
1042396Swnj 	 */
105*2458Swnj 	if (slaveno != 0 || tmdinfo[0])
1062396Swnj 		return(0);
107*2458Swnj 	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 
117*2458Swnj 	tmminfo[0]->um_tab.b_flags |= B_TAPE;
1181919Swnj 	unit = minor(dev)&03;
119*2458Swnj 	if (unit>=NTM || t_openf || !(ui = tmdinfo[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*2458Swnj 	    (struct device *)tmdinfo[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;
209*2458Swnj 	register struct buf *tmi;
2101919Swnj 
2111928Swnj 	tmwaitrws(bp->b_dev);
2121919Swnj 	if (bp != &ctmbuf) {
2131919Swnj 		p = &t_nxrec;
2141919Swnj 		if (dbtofsb(bp->b_blkno) > *p) {
2151919Swnj 			bp->b_flags |= B_ERROR;
2161919Swnj 			bp->b_error = ENXIO;		/* past EOF */
2171919Swnj 			iodone(bp);
2181919Swnj 			return;
2191919Swnj 		} else if (dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) {
2201919Swnj 			bp->b_resid = bp->b_bcount;
2211919Swnj 			clrbuf(bp);			/* at EOF */
2221919Swnj 			iodone(bp);
2231919Swnj 			return;
2241919Swnj 		} else if ((bp->b_flags&B_READ) == 0)
2251919Swnj 			*p = dbtofsb(bp->b_blkno) + 1;	/* write sets EOF */
2261919Swnj 	}
2271919Swnj 	bp->av_forw = NULL;
2281919Swnj 	(void) spl5();
229*2458Swnj 	tmi = &tmminfo[0]->um_tab;
230*2458Swnj 	if (tmi->b_actf == NULL)
231*2458Swnj 		tmi->b_actf = bp;
2321919Swnj 	else
233*2458Swnj 		tmi->b_actl->av_forw = bp;
234*2458Swnj 	tmi->b_actl = bp;
235*2458Swnj 	if (tmi->b_active == 0)
2361919Swnj 		tmstart();
2371919Swnj 	(void) spl0();
2381919Swnj }
2391919Swnj 
2401919Swnj tmstart()
2411919Swnj {
2421919Swnj 	register struct buf *bp;
2432396Swnj 	register struct uba_dinfo *ui;
2442396Swnj 	register struct device *addr;
2451919Swnj 	register cmd;
2461919Swnj 	register daddr_t blkno;
2472054Swnj 	int s;
2481919Swnj 
2491919Swnj loop:
250*2458Swnj 	if ((bp = tmminfo[0]->um_tab.b_actf) == 0)
2511919Swnj 		return;
252*2458Swnj 	ui = tmdinfo[minor(bp->b_dev)&03];
2532396Swnj 	addr = (struct device *)ui->ui_addr;
2542396Swnj 	t_dsreg = addr->tmcs;
2552396Swnj 	t_erreg = addr->tmer;
2562396Swnj 	t_resid = addr->tmbc;
2571919Swnj 	t_flags &= ~LASTIOW;
2582396Swnj 	if (t_openf < 0 || (addr->tmcs&CUR) == 0) {
2591919Swnj 		/* t_openf = -1; ??? */
2601919Swnj 		bp->b_flags |= B_ERROR;		/* hard error'ed or !SELR */
2611919Swnj 		goto next;
2621919Swnj 	}
2631919Swnj 	cmd = IENABLE | GO;
2641919Swnj 	if ((minor(bp->b_dev) & T_1600BPI) == 0)
2651919Swnj 		cmd |= D800;
2661919Swnj 	if (bp == &ctmbuf) {
2671919Swnj 		if (bp->b_command == NOP)
2681919Swnj 			goto next;		/* just get status */
2691919Swnj 		else {
2701919Swnj 			cmd |= bp->b_command;
271*2458Swnj 			tmminfo[0]->um_tab.b_active = SCOM;
2721919Swnj 			if (bp->b_command == SFORW || bp->b_command == SREV)
2732396Swnj 				addr->tmbc = bp->b_repcnt;
2742396Swnj 			addr->tmcs = cmd;
2751919Swnj 			return;
2761919Swnj 		}
2771919Swnj 	}
2781919Swnj 	if ((blkno = t_blkno) == dbtofsb(bp->b_blkno)) {
2792396Swnj 		addr->tmbc = -bp->b_bcount;
2802054Swnj 		s = spl6();
2811919Swnj 		if (tm_ubinfo == 0)
2822396Swnj 			tm_ubinfo = ubasetup(ui->ui_ubanum, bp, 1);
2832054Swnj 		splx(s);
2841919Swnj 		if ((bp->b_flags&B_READ) == 0) {
285*2458Swnj 			if (tmminfo[0]->um_tab.b_errcnt)
2861919Swnj 				cmd |= WIRG;
2871919Swnj 			else
2881919Swnj 				cmd |= WCOM;
2891919Swnj 		} else
2901919Swnj 			cmd |= RCOM;
2911919Swnj 		cmd |= (tm_ubinfo >> 12) & 0x30;
292*2458Swnj 		tmminfo[0]->um_tab.b_active = SIO;
2932396Swnj 		addr->tmba = tm_ubinfo;
2942396Swnj 		addr->tmcs = cmd;
2951919Swnj 		return;
2961919Swnj 	}
297*2458Swnj 	tmminfo[0]->um_tab.b_active = SSEEK;
2981919Swnj 	if (blkno < dbtofsb(bp->b_blkno)) {
2991919Swnj 		cmd |= SFORW;
3002396Swnj 		addr->tmbc = blkno - dbtofsb(bp->b_blkno);
3011919Swnj 	} else {
3021919Swnj 		cmd |= SREV;
3032396Swnj 		addr->tmbc = dbtofsb(bp->b_blkno) - blkno;
3041919Swnj 	}
3052396Swnj 	addr->tmcs = cmd;
3061919Swnj 	return;
3071919Swnj 
3081919Swnj next:
3092396Swnj 	ubarelse(ui->ui_ubanum, &tm_ubinfo);
310*2458Swnj 	tmminfo[0]->um_tab.b_actf = bp->av_forw;
3111919Swnj 	iodone(bp);
3121919Swnj 	goto loop;
3131919Swnj }
3141919Swnj 
3152396Swnj tmdgo()
3161919Swnj {
3172396Swnj }
3182396Swnj 
3192396Swnj tmintr(d)
3202396Swnj {
3211919Swnj 	register struct buf *bp;
322*2458Swnj 	register struct device *addr = (struct device *)tmdinfo[d]->ui_addr;
3231919Swnj 	register state;
3241919Swnj 
3252396Swnj 	if (t_flags&WAITREW && (addr->tmer&RWS) == 0) {
3261919Swnj 		t_flags &= ~WAITREW;
3271919Swnj 		wakeup((caddr_t)&t_flags);
3281919Swnj 	}
329*2458Swnj 	if ((bp = tmminfo[0]->um_tab.b_actf) == NULL)
3301919Swnj 		return;
3312396Swnj 	t_dsreg = addr->tmcs;
3322396Swnj 	t_erreg = addr->tmer;
3332396Swnj 	t_resid = addr->tmbc;
3341919Swnj 	if ((bp->b_flags & B_READ) == 0)
3351919Swnj 		t_flags |= LASTIOW;
336*2458Swnj 	state = tmminfo[0]->um_tab.b_active;
337*2458Swnj 	tmminfo[0]->um_tab.b_active = 0;
3382396Swnj 	if (addr->tmcs&ERROR) {
3392396Swnj 		while(addr->tmer & SDWN)
3401919Swnj 			;			/* await settle down */
3412396Swnj 		if (addr->tmer&EOF) {
3421919Swnj 			tmseteof(bp);	/* set blkno and nxrec */
3431919Swnj 			state = SCOM;
3442396Swnj 			addr->tmbc = -bp->b_bcount;
3451919Swnj 			goto errout;
3461919Swnj 		}
3472396Swnj 		if ((bp->b_flags&B_READ) && (addr->tmer&(HARD|SOFT)) == RLE)
3481919Swnj 			goto out;
3492396Swnj 		if ((addr->tmer&HARD)==0 && state==SIO) {
350*2458Swnj 			if (++tmminfo[0]->um_tab.b_errcnt < 7) {
3512396Swnj 				if((addr->tmer&SOFT) == NXM)
3521919Swnj 					printf("TM UBA late error\n");
3532426Skre 				t_blkno++;
354*2458Swnj 				ubarelse(tmdinfo[d]->ui_ubanum, &tm_ubinfo);
3551919Swnj 				tmstart();
3561919Swnj 				return;
3571919Swnj 			}
3581919Swnj 		} else if (t_openf>0 && bp != &rtmbuf)
3591919Swnj 			t_openf = -1;
3601928Swnj 		deverror(bp, t_erreg, t_dsreg);
3611919Swnj 		bp->b_flags |= B_ERROR;
3621919Swnj 		state = SIO;
3631919Swnj 	}
3641919Swnj out:
3651919Swnj 	switch (state) {
3661919Swnj 
3671919Swnj 	case SIO:
3681919Swnj 		t_blkno++;
3691919Swnj 		/* fall into ... */
3701919Swnj 
3711919Swnj 	case SCOM:
3721919Swnj 		if (bp == &ctmbuf) {
3731919Swnj 			switch (bp->b_command) {
3741919Swnj 			case SFORW:
3751919Swnj 				t_blkno -= bp->b_repcnt;
3761919Swnj 				break;
3771919Swnj 
3781919Swnj 			case SREV:
3791919Swnj 				t_blkno += bp->b_repcnt;
3801919Swnj 				break;
3811919Swnj 
3821919Swnj 			default:
3831919Swnj 				if (++bp->b_repcnt < 0) {
3841919Swnj 					tmstart();	/* continue */
3851919Swnj 					return;
3861919Swnj 				}
3871919Swnj 			}
3881919Swnj 		}
3891919Swnj errout:
390*2458Swnj 		tmminfo[0]->um_tab.b_errcnt = 0;
391*2458Swnj 		tmminfo[0]->um_tab.b_actf = bp->av_forw;
3922396Swnj 		bp->b_resid = -addr->tmbc;
393*2458Swnj 		ubarelse(tmdinfo[d]->ui_ubanum, &tm_ubinfo);
3941919Swnj 		iodone(bp);
3951919Swnj 		break;
3961919Swnj 
3971919Swnj 	case SSEEK:
3981919Swnj 		t_blkno = dbtofsb(bp->b_blkno);
3991919Swnj 		break;
4001919Swnj 
4011919Swnj 	default:
4021919Swnj 		return;
4031919Swnj 	}
4041919Swnj 	tmstart();
4051919Swnj }
4061919Swnj 
4071919Swnj tmseteof(bp)
4081919Swnj 	register struct buf *bp;
4091919Swnj {
4102396Swnj 	register struct device *addr =
411*2458Swnj 	    (struct device *)tmdinfo[minor(bp->b_dev)&03]->ui_addr;
4121919Swnj 
4131919Swnj 	if (bp == &ctmbuf) {
4141919Swnj 		if (t_blkno > dbtofsb(bp->b_blkno)) {
4151919Swnj 			/* reversing */
4162396Swnj 			t_nxrec = dbtofsb(bp->b_blkno) - addr->tmbc;
4171919Swnj 			t_blkno = t_nxrec;
4181919Swnj 		} else {
4191919Swnj 			/* spacing forward */
4202396Swnj 			t_blkno = dbtofsb(bp->b_blkno) + addr->tmbc;
4211919Swnj 			t_nxrec = t_blkno - 1;
4221919Swnj 		}
4231919Swnj 		return;
4241919Swnj 	}
4251919Swnj 	/* eof on read */
4261919Swnj 	t_nxrec = dbtofsb(bp->b_blkno);
4271919Swnj }
4281919Swnj 
4291919Swnj tmread(dev)
4301919Swnj {
4311919Swnj 
4321919Swnj 	tmphys(dev);
4331919Swnj 	physio(tmstrategy, &rtmbuf, dev, B_READ, minphys);
4341919Swnj }
4351919Swnj 
4361919Swnj tmwrite(dev)
4371919Swnj {
4381919Swnj 
4391919Swnj 	tmphys(dev);
4401919Swnj 	physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys);
4411919Swnj }
4421919Swnj 
4431919Swnj tmphys(dev)
4441919Swnj {
4451919Swnj 	register daddr_t a;
4461919Swnj 
4471919Swnj 	a = dbtofsb(u.u_offset >> 9);
4481919Swnj 	t_blkno = a;
4491919Swnj 	t_nxrec = a + 1;
4501919Swnj }
4511919Swnj 
4521919Swnj /*ARGSUSED*/
4531919Swnj tmioctl(dev, cmd, addr, flag)
4541919Swnj 	caddr_t addr;
4551919Swnj 	dev_t dev;
4561919Swnj {
4571919Swnj 	register callcount;
4581919Swnj 	int fcount;
4591919Swnj 	struct mtop mtop;
4601919Swnj 	struct mtget mtget;
4611919Swnj 	/* we depend of the values and order of the MT codes here */
4622324Skre 	static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL, NOP};
4631919Swnj 
4641919Swnj 	switch(cmd) {
4651919Swnj 		case MTIOCTOP:	/* tape operation */
4661919Swnj 		if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
4671919Swnj 			u.u_error = EFAULT;
4681919Swnj 			return;
4691919Swnj 		}
4701919Swnj 		switch(mtop.mt_op) {
4711919Swnj 		case MTWEOF: case MTFSF: case MTBSF:
4721919Swnj 			callcount = mtop.mt_count;
4731919Swnj 			fcount = INF;
4741919Swnj 			break;
4751919Swnj 		case MTFSR: case MTBSR:
4761919Swnj 			callcount = 1;
4771919Swnj 			fcount = mtop.mt_count;
4781919Swnj 			break;
4792324Skre 		case MTREW: case MTOFFL: case MTNOP:
4801919Swnj 			callcount = 1;
4811919Swnj 			fcount = 1;
4821919Swnj 			break;
4831919Swnj 		default:
4841919Swnj 			u.u_error = ENXIO;
4851919Swnj 			return;
4861919Swnj 		}
4871919Swnj 		if (callcount <= 0 || fcount <= 0)
4881919Swnj 			u.u_error = ENXIO;
4891919Swnj 		else while (--callcount >= 0) {
4901919Swnj 			tcommand(dev, tmops[mtop.mt_op], fcount);
4911919Swnj 			if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
4921919Swnj 			    ctmbuf.b_resid) {
4931919Swnj 				u.u_error = EIO;
4941919Swnj 				break;
4951919Swnj 			}
4961919Swnj 			if ((ctmbuf.b_flags&B_ERROR) || t_erreg&BOT)
4971919Swnj 				break;
4981919Swnj 		}
4991919Swnj 		geterror(&ctmbuf);
5001919Swnj 		return;
5011919Swnj 	case MTIOCGET:
5021919Swnj 		mtget.mt_dsreg = t_dsreg;
5031919Swnj 		mtget.mt_erreg = t_erreg;
5041919Swnj 		mtget.mt_resid = t_resid;
5051919Swnj 		if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
5061919Swnj 			u.u_error = EFAULT;
5071919Swnj 		return;
5081919Swnj 	default:
5091919Swnj 		u.u_error = ENXIO;
5101919Swnj 	}
5111919Swnj }
5121919Swnj 
5131919Swnj #define	DBSIZE	20
5141919Swnj 
5152363Swnj tmdump()
5162363Swnj {
5172396Swnj 	register struct uba_dinfo *ui;
5182396Swnj 	register struct uba_regs *up;
5192396Swnj 	register struct device *addr;
5202426Skre 	int blk, num;
5212426Skre 	int start;
5221919Swnj 
5232426Skre 	start = 0;
5242426Skre 	num = maxfree;
5252426Skre #define	phys(a,b)	((b)((int)(a)&0x7fffffff))
526*2458Swnj 	if (tmdinfo[0] == 0) {
5272396Swnj 		printf("dna\n");
5282396Swnj 		return (-1);
5292396Swnj 	}
530*2458Swnj 	ui = phys(tmdinfo[0], struct uba_dinfo *);
5312396Swnj 	up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba;
5322396Swnj #if VAX780
5332396Swnj 	if (cpu == VAX_780)
5342396Swnj 		ubainit(up);
5351919Swnj #endif
5362324Skre 	DELAY(1000000);
5372396Swnj 	addr = (struct device *)ui->ui_physaddr;
5382396Swnj 	tmwait(addr);
5392396Swnj 	addr->tmcs = DCLR | GO;
5401919Swnj 	while (num > 0) {
5411919Swnj 		blk = num > DBSIZE ? DBSIZE : num;
5422396Swnj 		tmdwrite(start, blk, addr, up);
5431919Swnj 		start += blk;
5441919Swnj 		num -= blk;
5451919Swnj 	}
5462426Skre 	tmwait(addr);
5472426Skre 	tmeof(addr);
5482426Skre 	tmeof(addr);
5492426Skre 	tmrewind(addr);
5502426Skre 	tmwait(addr);
5512363Swnj 	return (0);
5521919Swnj }
5531919Swnj 
5542396Swnj tmdwrite(buf, num, addr, up)
5552396Swnj 	register buf, num;
5562396Swnj 	register struct device *addr;
5572396Swnj 	struct uba_regs *up;
5581919Swnj {
5592396Swnj 	register struct pte *io;
5602396Swnj 	register int npf;
5611928Swnj 
5622396Swnj 	tmwait(addr);
5632396Swnj 	io = up->uba_map;
5641919Swnj 	npf = num+1;
5651928Swnj 	while (--npf != 0)
5662396Swnj 		 *(int *)io++ = (buf++ | (1<<UBA_DPSHIFT) | UBA_MRV);
5672396Swnj 	*(int *)io = 0;
5682396Swnj 	addr->tmbc = -(num*NBPG);
5692396Swnj 	addr->tmba = 0;
5702396Swnj 	addr->tmcs = WCOM | GO;
5711919Swnj }
5721919Swnj 
5732396Swnj tmwait(addr)
5742396Swnj 	register struct device *addr;
5751919Swnj {
5761928Swnj 	register s;
5771919Swnj 
5781919Swnj 	do
5792396Swnj 		s = addr->tmcs;
5801919Swnj 	while ((s & CUR) == 0);
5811919Swnj }
5821919Swnj 
5832396Swnj tmrewind(addr)
5842396Swnj 	struct device *addr;
5851919Swnj {
5861919Swnj 
5872396Swnj 	tmwait(addr);
5882396Swnj 	addr->tmcs = REW | GO;
5891919Swnj }
5901919Swnj 
5912396Swnj tmeof(addr)
5922396Swnj 	struct device *addr;
5931919Swnj {
5941919Swnj 
5952396Swnj 	tmwait(addr);
5962396Swnj 	addr->tmcs = WEOF | GO;
5971919Swnj }
5981919Swnj #endif
599