xref: /csrg-svn/sys/vax/uba/tm.c (revision 2471)
1*2471Swnj /*	tm.c	4.12	02/17/81	*/
21919Swnj 
31940Swnj #include "tm.h"
4*2471Swnj #if NTM03 > 0
51919Swnj /*
61919Swnj  * TM tape driver
7*2471Swnj  *
8*2471Swnj  * THIS HANDLES ONLY ONE DRIVE ON ONE CONTROLER, AS WE HAVE NO
9*2471Swnj  * WAY TO TEST MULTIPLE TRANSPORTS.
101919Swnj  */
11*2471Swnj #define	DELAY(N)		{ register int d = N; while (--d > 0); }
121919Swnj #include "../h/param.h"
131919Swnj #include "../h/buf.h"
141919Swnj #include "../h/dir.h"
151919Swnj #include "../h/conf.h"
161919Swnj #include "../h/user.h"
171919Swnj #include "../h/file.h"
181919Swnj #include "../h/map.h"
191919Swnj #include "../h/pte.h"
201919Swnj #include "../h/uba.h"
211919Swnj #include "../h/mtio.h"
221919Swnj #include "../h/ioctl.h"
231919Swnj #include "../h/vm.h"
242363Swnj #include "../h/cmap.h"
252396Swnj #include "../h/cpu.h"
261919Swnj 
272396Swnj #include "../h/tmreg.h"
281919Swnj 
291919Swnj struct	buf	ctmbuf;
301919Swnj struct	buf	rtmbuf;
311919Swnj 
322396Swnj int	tmcntrlr(), tmslave(), tmdgo(), tmintr();
33*2471Swnj struct	uba_minfo *tmminfo[NTM03];
34*2471Swnj struct	uba_dinfo *tmdinfo[NTM11];
352458Swnj u_short	tmstd[] = { 0772520, 0 };
362396Swnj struct	uba_driver tmdriver =
372458Swnj 	{ tmcntrlr, tmslave, tmdgo, 0, tmstd, "tm", tmdinfo, tmminfo };
381919Swnj 
391919Swnj /* bits in minor device */
401919Swnj #define	T_NOREWIND	04
411919Swnj #define	T_1600BPI	08
421919Swnj 
431919Swnj #define	INF	(daddr_t)1000000L
441919Swnj 
45*2471Swnj struct	tm_softc {
46*2471Swnj 	char	sc_openf;
47*2471Swnj 	char	sc_flags;
48*2471Swnj 	daddr_t	sc_blkno;
49*2471Swnj 	daddr_t	sc_nxrec;
50*2471Swnj 	u_short	sc_erreg;
51*2471Swnj 	u_short	sc_dsreg;
52*2471Swnj 	short	sc_resid;
53*2471Swnj 	int	sc_ubinfo;
54*2471Swnj } tm_softc[NTM03];
551919Swnj 
561919Swnj #define	SSEEK	1		/* seeking */
571919Swnj #define	SIO	2		/* doing seq i/o */
581919Swnj #define	SCOM	3		/* sending control command */
591919Swnj 
601919Swnj #define	LASTIOW 1		/* last op was a write */
611919Swnj #define	WAITREW	2		/* someone is waiting for a rewind */
621919Swnj 
632426Skre /*
642426Skre  * Determine if there is a controller for
652426Skre  * a tm at address reg.  Our goal is to make the
662426Skre  * device interrupt.
672426Skre  */
682458Swnj tmcntrlr(um, reg)
692458Swnj 	struct uba_minfo *um;
702396Swnj 	caddr_t reg;
712396Swnj {
722458Swnj 	register int br, cvec;
732426Skre 
742396Swnj 	((struct device *)reg)->tmcs = IENABLE;
752396Swnj 	/*
762396Swnj 	 * If this is a tm03/tc11, it ought to have interrupted
772396Swnj 	 * by now, if it isn't (ie: it is a ts04) then we just
782458Swnj 	 * hope that it didn't interrupt, so autoconf will ignore it.
792458Swnj 	 * Just in case, we will reference one
802396Swnj 	 * of the more distant registers, and hope for a machine
812458Swnj 	 * check, or similar disaster if this is a ts.
82*2471Swnj 	 *
83*2471Swnj 	 * Note: on an 11/780, badaddr will just generate
84*2471Swnj 	 * a uba error for a ts; but our caller will notice that
85*2471Swnj 	 * so we won't check for it.
862396Swnj 	 */
872396Swnj 	if (badaddr(&((struct device *)reg)->tmrd, 2))
882458Swnj 		return (0);
892458Swnj 	return (1);
902396Swnj }
912396Swnj 
922396Swnj tmslave(ui, reg, slaveno)
932396Swnj 	struct uba_dinfo *ui;
942396Swnj 	caddr_t reg;
952396Swnj {
962458Swnj 
972396Swnj 	/*
982396Swnj 	 * Due to a design flaw, we cannot ascertain if the tape
992396Swnj 	 * exists or not unless it is on line - ie: unless a tape is
1002396Swnj 	 * mounted. This is too servere a restriction to bear.
1012396Swnj 	 * As we can only handle one tape, we might just as well insist
1022396Swnj 	 * that it be slave #0, and just assume that it exists.
1032396Swnj 	 * Something better will have to be done if you have two
1042396Swnj 	 * tapes on one controller, or two controllers
1052396Swnj 	 */
1062458Swnj 	if (slaveno != 0 || tmdinfo[0])
1072396Swnj 		return(0);
1082458Swnj 	return (1);
1092396Swnj }
1102396Swnj 
1111919Swnj tmopen(dev, flag)
1121919Swnj 	dev_t dev;
1131919Swnj 	int flag;
1141919Swnj {
1151919Swnj 	register ds, unit;
1162396Swnj 	register struct uba_dinfo *ui;
117*2471Swnj 	register struct tm_softc *sc = &tm_softc[0];
1181919Swnj 
1192458Swnj 	tmminfo[0]->um_tab.b_flags |= B_TAPE;
1201919Swnj 	unit = minor(dev)&03;
121*2471Swnj 	if (unit>=NTM11 || sc->sc_openf || (ui = tmdinfo[0]) == 0 || ui->ui_alive==0) {
1221919Swnj 		u.u_error = ENXIO;		/* out of range or open */
1231919Swnj 		return;
1241919Swnj 	}
1251919Swnj 	tcommand(dev, NOP, 1);
126*2471Swnj 	if ((sc->sc_erreg&SELR) == 0) {
127*2471Swnj 		u.u_error = EIO;
128*2471Swnj 		goto eio;
1291919Swnj 	}
130*2471Swnj 	sc->sc_openf = 1;
131*2471Swnj 	if (sc->sc_erreg&RWS)
1321919Swnj 		tmwaitrws(dev);			/* wait for rewind complete */
133*2471Swnj 	while (sc->sc_erreg&SDWN)
1341919Swnj 		tcommand(dev, NOP, 1);		/* await settle down */
135*2471Swnj 	if ((sc->sc_erreg&TUR)==0 ||
136*2471Swnj 	    ((flag&(FREAD|FWRITE)) == FWRITE && (sc->sc_erreg&WRL))) {
1372396Swnj 		((struct device *)ui->ui_addr)->tmcs = DCLR|GO;
1381919Swnj 		u.u_error = EIO;		/* offline or write protect */
1391919Swnj 	}
1401919Swnj 	if (u.u_error != 0) {
141*2471Swnj 		sc->sc_openf = 0;
142*2471Swnj 		if (u.u_error == EIO)
143*2471Swnj eio:
144*2471Swnj 			uprintf("tape offline or protected\n");
1451919Swnj 		return;
1461919Swnj 	}
147*2471Swnj 	sc->sc_blkno = (daddr_t)0;
148*2471Swnj 	sc->sc_nxrec = INF;
149*2471Swnj 	sc->sc_flags = 0;
150*2471Swnj 	sc->sc_openf = 1;
1511919Swnj }
1521919Swnj 
1531919Swnj tmwaitrws(dev)
1541919Swnj 	register dev;
1551919Swnj {
1562396Swnj 	register struct device *addr =
157*2471Swnj 	    (struct device *)tmdinfo[0]->ui_addr;
158*2471Swnj 	register struct tm_softc *sc = &tm_softc[0];
1591919Swnj 
1601919Swnj 	spl5();
1611919Swnj 	for (;;) {
1622396Swnj 		if ((addr->tmer&RWS) == 0) {
1631919Swnj 			spl0();		/* rewind complete */
1641919Swnj 			return;
1651919Swnj 		}
166*2471Swnj 		sc->sc_flags |= WAITREW;
167*2471Swnj 		sleep((caddr_t)&sc->sc_flags, PRIBIO);
1681919Swnj 	}
1691919Swnj }
1701919Swnj 
1711919Swnj tmclose(dev, flag)
1721919Swnj 	register dev_t dev;
1731919Swnj 	register flag;
1741919Swnj {
175*2471Swnj 	register struct tm_softc *sc = &tm_softc[0];
1761919Swnj 
177*2471Swnj 	if (flag == FWRITE || ((flag&FWRITE) && (sc->sc_flags&LASTIOW))) {
1781919Swnj 		tcommand(dev, WEOF, 1);
1791919Swnj 		tcommand(dev, WEOF, 1);
1801919Swnj 		tcommand(dev, SREV, 1);
1811919Swnj 	}
1821919Swnj 	if ((minor(dev)&T_NOREWIND) == 0)
1831919Swnj 		tcommand(dev, REW, 1);
184*2471Swnj 	sc->sc_openf = 0;
1851919Swnj }
1861919Swnj 
1871919Swnj tcommand(dev, com, count)
1881919Swnj 	dev_t dev;
1891919Swnj 	int com, count;
1901919Swnj {
1911919Swnj 	register struct buf *bp;
1921919Swnj 
1931919Swnj 	bp = &ctmbuf;
1941919Swnj 	(void) spl5();
1951919Swnj 	while (bp->b_flags&B_BUSY) {
1961919Swnj 		bp->b_flags |= B_WANTED;
1971919Swnj 		sleep((caddr_t)bp, PRIBIO);
1981919Swnj 	}
1991919Swnj 	bp->b_flags = B_BUSY|B_READ;
2001919Swnj 	(void) spl0();
2011919Swnj 	bp->b_dev = dev;
2021919Swnj 	bp->b_repcnt = -count;
2031919Swnj 	bp->b_command = com;
2041919Swnj 	bp->b_blkno = 0;
2051919Swnj 	tmstrategy(bp);
2061919Swnj 	iowait(bp);
2071919Swnj 	if (bp->b_flags&B_WANTED)
2081919Swnj 		wakeup((caddr_t)bp);
2091919Swnj 	bp->b_flags &= B_ERROR;
2101919Swnj }
2111919Swnj 
2121919Swnj tmstrategy(bp)
2131919Swnj 	register struct buf *bp;
2141919Swnj {
2151919Swnj 	register daddr_t *p;
2162458Swnj 	register struct buf *tmi;
2171919Swnj 
2181928Swnj 	tmwaitrws(bp->b_dev);
2191919Swnj 	if (bp != &ctmbuf) {
220*2471Swnj 		p = &tm_softc[0].sc_nxrec;
2211919Swnj 		if (dbtofsb(bp->b_blkno) > *p) {
2221919Swnj 			bp->b_flags |= B_ERROR;
2231919Swnj 			bp->b_error = ENXIO;		/* past EOF */
2241919Swnj 			iodone(bp);
2251919Swnj 			return;
2261919Swnj 		} else if (dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) {
2271919Swnj 			bp->b_resid = bp->b_bcount;
2281919Swnj 			clrbuf(bp);			/* at EOF */
2291919Swnj 			iodone(bp);
2301919Swnj 			return;
2311919Swnj 		} else if ((bp->b_flags&B_READ) == 0)
2321919Swnj 			*p = dbtofsb(bp->b_blkno) + 1;	/* write sets EOF */
2331919Swnj 	}
2341919Swnj 	bp->av_forw = NULL;
2351919Swnj 	(void) spl5();
2362458Swnj 	tmi = &tmminfo[0]->um_tab;
2372458Swnj 	if (tmi->b_actf == NULL)
2382458Swnj 		tmi->b_actf = bp;
2391919Swnj 	else
2402458Swnj 		tmi->b_actl->av_forw = bp;
2412458Swnj 	tmi->b_actl = bp;
2422458Swnj 	if (tmi->b_active == 0)
2431919Swnj 		tmstart();
2441919Swnj 	(void) spl0();
2451919Swnj }
2461919Swnj 
2471919Swnj tmstart()
2481919Swnj {
2491919Swnj 	register struct buf *bp;
250*2471Swnj 	register struct uba_minfo *um = tmminfo[0];
2512396Swnj 	register struct uba_dinfo *ui;
2522396Swnj 	register struct device *addr;
253*2471Swnj 	register struct tm_softc *sc = &tm_softc[0];
254*2471Swnj 	int cmd, s;
255*2471Swnj 	daddr_t blkno;
2561919Swnj 
2571919Swnj loop:
258*2471Swnj 	if ((bp = um->um_tab.b_actf) == 0)
2591919Swnj 		return;
260*2471Swnj 	ui = tmdinfo[0];
2612396Swnj 	addr = (struct device *)ui->ui_addr;
262*2471Swnj 	sc->sc_dsreg = addr->tmcs;
263*2471Swnj 	sc->sc_erreg = addr->tmer;
264*2471Swnj 	sc->sc_resid = addr->tmbc;
265*2471Swnj 	sc->sc_flags &= ~LASTIOW;
266*2471Swnj 	if (sc->sc_openf < 0 || (addr->tmcs&CUR) == 0) {
267*2471Swnj 		/* sc->sc_openf = -1; ??? */
2681919Swnj 		bp->b_flags |= B_ERROR;		/* hard error'ed or !SELR */
2691919Swnj 		goto next;
2701919Swnj 	}
2711919Swnj 	cmd = IENABLE | GO;
2721919Swnj 	if ((minor(bp->b_dev) & T_1600BPI) == 0)
2731919Swnj 		cmd |= D800;
2741919Swnj 	if (bp == &ctmbuf) {
2751919Swnj 		if (bp->b_command == NOP)
2761919Swnj 			goto next;		/* just get status */
2771919Swnj 		else {
2781919Swnj 			cmd |= bp->b_command;
279*2471Swnj 			um->um_tab.b_active = SCOM;
2801919Swnj 			if (bp->b_command == SFORW || bp->b_command == SREV)
2812396Swnj 				addr->tmbc = bp->b_repcnt;
2822396Swnj 			addr->tmcs = cmd;
2831919Swnj 			return;
2841919Swnj 		}
2851919Swnj 	}
286*2471Swnj 	if ((blkno = sc->sc_blkno) == dbtofsb(bp->b_blkno)) {
2872396Swnj 		addr->tmbc = -bp->b_bcount;
2882054Swnj 		s = spl6();
289*2471Swnj 		if (sc->sc_ubinfo == 0)
290*2471Swnj 			sc->sc_ubinfo = ubasetup(ui->ui_ubanum, bp, 1);
2912054Swnj 		splx(s);
2921919Swnj 		if ((bp->b_flags&B_READ) == 0) {
293*2471Swnj 			if (um->um_tab.b_errcnt)
2941919Swnj 				cmd |= WIRG;
2951919Swnj 			else
2961919Swnj 				cmd |= WCOM;
2971919Swnj 		} else
2981919Swnj 			cmd |= RCOM;
299*2471Swnj 		cmd |= (sc->sc_ubinfo >> 12) & 0x30;
300*2471Swnj 		um->um_tab.b_active = SIO;
301*2471Swnj 		addr->tmba = sc->sc_ubinfo;
3022396Swnj 		addr->tmcs = cmd;
3031919Swnj 		return;
3041919Swnj 	}
305*2471Swnj 	um->um_tab.b_active = SSEEK;
3061919Swnj 	if (blkno < dbtofsb(bp->b_blkno)) {
3071919Swnj 		cmd |= SFORW;
3082396Swnj 		addr->tmbc = blkno - dbtofsb(bp->b_blkno);
3091919Swnj 	} else {
3101919Swnj 		cmd |= SREV;
3112396Swnj 		addr->tmbc = dbtofsb(bp->b_blkno) - blkno;
3121919Swnj 	}
3132396Swnj 	addr->tmcs = cmd;
3141919Swnj 	return;
3151919Swnj 
3161919Swnj next:
317*2471Swnj 	ubarelse(ui->ui_ubanum, &sc->sc_ubinfo);
318*2471Swnj 	um->um_tab.b_actf = bp->av_forw;
3191919Swnj 	iodone(bp);
3201919Swnj 	goto loop;
3211919Swnj }
3221919Swnj 
3232396Swnj tmdgo()
3241919Swnj {
325*2471Swnj 
3262396Swnj }
3272396Swnj 
328*2471Swnj /*ARGSUSED*/
3292396Swnj tmintr(d)
330*2471Swnj 	int d;
3312396Swnj {
3321919Swnj 	register struct buf *bp;
333*2471Swnj 	register struct uba_minfo *um = tmminfo[0];
334*2471Swnj 	register struct device *addr = (struct device *)tmdinfo[0]->ui_addr;
335*2471Swnj 	register struct tm_softc *sc = &tm_softc[0];
3361919Swnj 	register state;
3371919Swnj 
338*2471Swnj 	if (sc->sc_flags&WAITREW && (addr->tmer&RWS) == 0) {
339*2471Swnj 		sc->sc_flags &= ~WAITREW;
340*2471Swnj 		wakeup((caddr_t)&sc->sc_flags);
3411919Swnj 	}
342*2471Swnj 	if ((bp = um->um_tab.b_actf) == NULL)
3431919Swnj 		return;
344*2471Swnj 	sc->sc_dsreg = addr->tmcs;
345*2471Swnj 	sc->sc_erreg = addr->tmer;
346*2471Swnj 	sc->sc_resid = addr->tmbc;
3471919Swnj 	if ((bp->b_flags & B_READ) == 0)
348*2471Swnj 		sc->sc_flags |= LASTIOW;
349*2471Swnj 	state = um->um_tab.b_active;
350*2471Swnj 	um->um_tab.b_active = 0;
3512396Swnj 	if (addr->tmcs&ERROR) {
3522396Swnj 		while(addr->tmer & SDWN)
3531919Swnj 			;			/* await settle down */
3542396Swnj 		if (addr->tmer&EOF) {
3551919Swnj 			tmseteof(bp);	/* set blkno and nxrec */
3561919Swnj 			state = SCOM;
3572396Swnj 			addr->tmbc = -bp->b_bcount;
3581919Swnj 			goto errout;
3591919Swnj 		}
3602396Swnj 		if ((bp->b_flags&B_READ) && (addr->tmer&(HARD|SOFT)) == RLE)
3611919Swnj 			goto out;
3622396Swnj 		if ((addr->tmer&HARD)==0 && state==SIO) {
363*2471Swnj 			if (++um->um_tab.b_errcnt < 7) {
3642396Swnj 				if((addr->tmer&SOFT) == NXM)
3651919Swnj 					printf("TM UBA late error\n");
366*2471Swnj 				sc->sc_blkno++;
367*2471Swnj 				ubarelse(um->um_ubanum, &sc->sc_ubinfo);
3681919Swnj 				tmstart();
3691919Swnj 				return;
3701919Swnj 			}
371*2471Swnj 		} else if (sc->sc_openf>0 && bp != &rtmbuf)
372*2471Swnj 			sc->sc_openf = -1;
373*2471Swnj 		deverror(bp, sc->sc_erreg, sc->sc_dsreg);
3741919Swnj 		bp->b_flags |= B_ERROR;
3751919Swnj 		state = SIO;
3761919Swnj 	}
3771919Swnj out:
3781919Swnj 	switch (state) {
3791919Swnj 
3801919Swnj 	case SIO:
381*2471Swnj 		sc->sc_blkno++;
3821919Swnj 		/* fall into ... */
3831919Swnj 
3841919Swnj 	case SCOM:
3851919Swnj 		if (bp == &ctmbuf) {
3861919Swnj 			switch (bp->b_command) {
3871919Swnj 			case SFORW:
388*2471Swnj 				sc->sc_blkno -= bp->b_repcnt;
3891919Swnj 				break;
3901919Swnj 
3911919Swnj 			case SREV:
392*2471Swnj 				sc->sc_blkno += bp->b_repcnt;
3931919Swnj 				break;
3941919Swnj 
3951919Swnj 			default:
3961919Swnj 				if (++bp->b_repcnt < 0) {
3971919Swnj 					tmstart();	/* continue */
3981919Swnj 					return;
3991919Swnj 				}
4001919Swnj 			}
4011919Swnj 		}
4021919Swnj errout:
403*2471Swnj 		um->um_tab.b_errcnt = 0;
404*2471Swnj 		um->um_tab.b_actf = bp->av_forw;
4052396Swnj 		bp->b_resid = -addr->tmbc;
406*2471Swnj 		ubarelse(um->um_ubanum, &sc->sc_ubinfo);
4071919Swnj 		iodone(bp);
4081919Swnj 		break;
4091919Swnj 
4101919Swnj 	case SSEEK:
411*2471Swnj 		sc->sc_blkno = dbtofsb(bp->b_blkno);
4121919Swnj 		break;
4131919Swnj 
4141919Swnj 	default:
4151919Swnj 		return;
4161919Swnj 	}
4171919Swnj 	tmstart();
4181919Swnj }
4191919Swnj 
4201919Swnj tmseteof(bp)
4211919Swnj 	register struct buf *bp;
4221919Swnj {
4232396Swnj 	register struct device *addr =
424*2471Swnj 	    (struct device *)tmdinfo[0]->ui_addr;
425*2471Swnj 	register struct tm_softc *sc = &tm_softc[0];
4261919Swnj 
4271919Swnj 	if (bp == &ctmbuf) {
428*2471Swnj 		if (sc->sc_blkno > dbtofsb(bp->b_blkno)) {
4291919Swnj 			/* reversing */
430*2471Swnj 			sc->sc_nxrec = dbtofsb(bp->b_blkno) - addr->tmbc;
431*2471Swnj 			sc->sc_blkno = sc->sc_nxrec;
4321919Swnj 		} else {
4331919Swnj 			/* spacing forward */
434*2471Swnj 			sc->sc_blkno = dbtofsb(bp->b_blkno) + addr->tmbc;
435*2471Swnj 			sc->sc_nxrec = sc->sc_blkno - 1;
4361919Swnj 		}
4371919Swnj 		return;
4381919Swnj 	}
4391919Swnj 	/* eof on read */
440*2471Swnj 	sc->sc_nxrec = dbtofsb(bp->b_blkno);
4411919Swnj }
4421919Swnj 
4431919Swnj tmread(dev)
4441919Swnj {
4451919Swnj 
4461919Swnj 	tmphys(dev);
4471919Swnj 	physio(tmstrategy, &rtmbuf, dev, B_READ, minphys);
4481919Swnj }
4491919Swnj 
4501919Swnj tmwrite(dev)
4511919Swnj {
4521919Swnj 
4531919Swnj 	tmphys(dev);
4541919Swnj 	physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys);
4551919Swnj }
4561919Swnj 
4571919Swnj tmphys(dev)
4581919Swnj {
4591919Swnj 	register daddr_t a;
460*2471Swnj 	register struct tm_softc *sc = &tm_softc[0];
4611919Swnj 
4621919Swnj 	a = dbtofsb(u.u_offset >> 9);
463*2471Swnj 	sc->sc_blkno = a;
464*2471Swnj 	sc->sc_nxrec = a + 1;
4651919Swnj }
4661919Swnj 
4671919Swnj /*ARGSUSED*/
4681919Swnj tmioctl(dev, cmd, addr, flag)
4691919Swnj 	caddr_t addr;
4701919Swnj 	dev_t dev;
4711919Swnj {
4721919Swnj 	register callcount;
473*2471Swnj 	register struct tm_softc *sc = &tm_softc[0];
4741919Swnj 	int fcount;
4751919Swnj 	struct mtop mtop;
4761919Swnj 	struct mtget mtget;
4771919Swnj 	/* we depend of the values and order of the MT codes here */
4782324Skre 	static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL, NOP};
4791919Swnj 
4801919Swnj 	switch(cmd) {
4811919Swnj 		case MTIOCTOP:	/* tape operation */
4821919Swnj 		if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
4831919Swnj 			u.u_error = EFAULT;
4841919Swnj 			return;
4851919Swnj 		}
4861919Swnj 		switch(mtop.mt_op) {
4871919Swnj 		case MTWEOF: case MTFSF: case MTBSF:
4881919Swnj 			callcount = mtop.mt_count;
4891919Swnj 			fcount = INF;
4901919Swnj 			break;
4911919Swnj 		case MTFSR: case MTBSR:
4921919Swnj 			callcount = 1;
4931919Swnj 			fcount = mtop.mt_count;
4941919Swnj 			break;
4952324Skre 		case MTREW: case MTOFFL: case MTNOP:
4961919Swnj 			callcount = 1;
4971919Swnj 			fcount = 1;
4981919Swnj 			break;
4991919Swnj 		default:
5001919Swnj 			u.u_error = ENXIO;
5011919Swnj 			return;
5021919Swnj 		}
5031919Swnj 		if (callcount <= 0 || fcount <= 0)
5041919Swnj 			u.u_error = ENXIO;
5051919Swnj 		else while (--callcount >= 0) {
5061919Swnj 			tcommand(dev, tmops[mtop.mt_op], fcount);
5071919Swnj 			if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
5081919Swnj 			    ctmbuf.b_resid) {
5091919Swnj 				u.u_error = EIO;
5101919Swnj 				break;
5111919Swnj 			}
512*2471Swnj 			if ((ctmbuf.b_flags&B_ERROR) ||
513*2471Swnj 			    sc->sc_erreg&BOT)
5141919Swnj 				break;
5151919Swnj 		}
5161919Swnj 		geterror(&ctmbuf);
5171919Swnj 		return;
5181919Swnj 	case MTIOCGET:
519*2471Swnj 		mtget.mt_dsreg = sc->sc_dsreg;
520*2471Swnj 		mtget.mt_erreg = sc->sc_erreg;
521*2471Swnj 		mtget.mt_resid = sc->sc_resid;
5221919Swnj 		if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
5231919Swnj 			u.u_error = EFAULT;
5241919Swnj 		return;
5251919Swnj 	default:
5261919Swnj 		u.u_error = ENXIO;
5271919Swnj 	}
5281919Swnj }
5291919Swnj 
5301919Swnj #define	DBSIZE	20
5311919Swnj 
5322363Swnj tmdump()
5332363Swnj {
5342396Swnj 	register struct uba_dinfo *ui;
5352396Swnj 	register struct uba_regs *up;
5362396Swnj 	register struct device *addr;
5372426Skre 	int blk, num;
5382426Skre 	int start;
5391919Swnj 
5402426Skre 	start = 0;
5412426Skre 	num = maxfree;
5422426Skre #define	phys(a,b)	((b)((int)(a)&0x7fffffff))
5432458Swnj 	if (tmdinfo[0] == 0) {
5442396Swnj 		printf("dna\n");
5452396Swnj 		return (-1);
5462396Swnj 	}
5472458Swnj 	ui = phys(tmdinfo[0], struct uba_dinfo *);
5482396Swnj 	up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba;
5492396Swnj #if VAX780
5502396Swnj 	if (cpu == VAX_780)
5512396Swnj 		ubainit(up);
5521919Swnj #endif
5532324Skre 	DELAY(1000000);
5542396Swnj 	addr = (struct device *)ui->ui_physaddr;
5552396Swnj 	tmwait(addr);
5562396Swnj 	addr->tmcs = DCLR | GO;
5571919Swnj 	while (num > 0) {
5581919Swnj 		blk = num > DBSIZE ? DBSIZE : num;
5592396Swnj 		tmdwrite(start, blk, addr, up);
5601919Swnj 		start += blk;
5611919Swnj 		num -= blk;
5621919Swnj 	}
5632426Skre 	tmeof(addr);
5642426Skre 	tmeof(addr);
5652426Skre 	tmwait(addr);
566*2471Swnj 	addr->tmcs = REW | GO;
567*2471Swnj 	tmwait(addr);
5682363Swnj 	return (0);
5691919Swnj }
5701919Swnj 
5712396Swnj tmdwrite(buf, num, addr, up)
5722396Swnj 	register buf, num;
5732396Swnj 	register struct device *addr;
5742396Swnj 	struct uba_regs *up;
5751919Swnj {
5762396Swnj 	register struct pte *io;
5772396Swnj 	register int npf;
5781928Swnj 
5792396Swnj 	tmwait(addr);
5802396Swnj 	io = up->uba_map;
5811919Swnj 	npf = num+1;
5821928Swnj 	while (--npf != 0)
5832396Swnj 		 *(int *)io++ = (buf++ | (1<<UBA_DPSHIFT) | UBA_MRV);
5842396Swnj 	*(int *)io = 0;
5852396Swnj 	addr->tmbc = -(num*NBPG);
5862396Swnj 	addr->tmba = 0;
5872396Swnj 	addr->tmcs = WCOM | GO;
5881919Swnj }
5891919Swnj 
5902396Swnj tmwait(addr)
5912396Swnj 	register struct device *addr;
5921919Swnj {
5931928Swnj 	register s;
5941919Swnj 
5951919Swnj 	do
5962396Swnj 		s = addr->tmcs;
5971919Swnj 	while ((s & CUR) == 0);
5981919Swnj }
5991919Swnj 
6002396Swnj tmeof(addr)
6012396Swnj 	struct device *addr;
6021919Swnj {
6031919Swnj 
6042396Swnj 	tmwait(addr);
6052396Swnj 	addr->tmcs = WEOF | GO;
6061919Swnj }
6071919Swnj #endif
608