xref: /csrg-svn/sys/vax/uba/tm.c (revision 2574)
1*2574Swnj /*	tm.c	4.13	02/19/81	*/
21919Swnj 
31940Swnj #include "tm.h"
42471Swnj #if NTM03 > 0
51919Swnj /*
61919Swnj  * TM tape driver
72471Swnj  *
82471Swnj  * THIS HANDLES ONLY ONE DRIVE ON ONE CONTROLER, AS WE HAVE NO
92471Swnj  * WAY TO TEST MULTIPLE TRANSPORTS.
101919Swnj  */
112471Swnj #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"
20*2574Swnj #include "../h/vm.h"
211919Swnj #include "../h/uba.h"
221919Swnj #include "../h/mtio.h"
231919Swnj #include "../h/ioctl.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();
332471Swnj struct	uba_minfo *tmminfo[NTM03];
342471Swnj struct	uba_dinfo *tmdinfo[NTM11];
352458Swnj u_short	tmstd[] = { 0772520, 0 };
362396Swnj struct	uba_driver tmdriver =
37*2574Swnj 	{ tmcntrlr, tmslave, tmdgo, 0, tmstd, "mt", tmdinfo, "tm", 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 
452471Swnj struct	tm_softc {
462471Swnj 	char	sc_openf;
472471Swnj 	char	sc_flags;
482471Swnj 	daddr_t	sc_blkno;
492471Swnj 	daddr_t	sc_nxrec;
502471Swnj 	u_short	sc_erreg;
512471Swnj 	u_short	sc_dsreg;
522471Swnj 	short	sc_resid;
532471Swnj } tm_softc[NTM03];
541919Swnj 
551919Swnj #define	SSEEK	1		/* seeking */
561919Swnj #define	SIO	2		/* doing seq i/o */
571919Swnj #define	SCOM	3		/* sending control command */
581919Swnj 
591919Swnj #define	LASTIOW 1		/* last op was a write */
601919Swnj #define	WAITREW	2		/* someone is waiting for a rewind */
611919Swnj 
622426Skre /*
632426Skre  * Determine if there is a controller for
642426Skre  * a tm at address reg.  Our goal is to make the
652426Skre  * device interrupt.
662426Skre  */
672458Swnj tmcntrlr(um, reg)
682458Swnj 	struct uba_minfo *um;
692396Swnj 	caddr_t reg;
702396Swnj {
712458Swnj 	register int br, cvec;
722426Skre 
732396Swnj 	((struct device *)reg)->tmcs = IENABLE;
742396Swnj 	/*
752396Swnj 	 * If this is a tm03/tc11, it ought to have interrupted
762396Swnj 	 * by now, if it isn't (ie: it is a ts04) then we just
772458Swnj 	 * hope that it didn't interrupt, so autoconf will ignore it.
782458Swnj 	 * Just in case, we will reference one
792396Swnj 	 * of the more distant registers, and hope for a machine
802458Swnj 	 * check, or similar disaster if this is a ts.
812471Swnj 	 *
822471Swnj 	 * Note: on an 11/780, badaddr will just generate
832471Swnj 	 * a uba error for a ts; but our caller will notice that
842471Swnj 	 * so we won't check for it.
852396Swnj 	 */
862396Swnj 	if (badaddr(&((struct device *)reg)->tmrd, 2))
872458Swnj 		return (0);
882458Swnj 	return (1);
892396Swnj }
902396Swnj 
91*2574Swnj tmslave(ui, reg)
922396Swnj 	struct uba_dinfo *ui;
932396Swnj 	caddr_t reg;
942396Swnj {
952458Swnj 
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*2574Swnj 	if (ui->ui_slave != 0 || tmdinfo[0])
1062396Swnj 		return(0);
1072458Swnj 	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;
1162471Swnj 	register struct tm_softc *sc = &tm_softc[0];
1171919Swnj 
1182458Swnj 	tmminfo[0]->um_tab.b_flags |= B_TAPE;
1191919Swnj 	unit = minor(dev)&03;
1202471Swnj 	if (unit>=NTM11 || sc->sc_openf || (ui = tmdinfo[0]) == 0 || ui->ui_alive==0) {
1211919Swnj 		u.u_error = ENXIO;		/* out of range or open */
1221919Swnj 		return;
1231919Swnj 	}
124*2574Swnj 	tmcommand(dev, NOP, 1);
1252471Swnj 	if ((sc->sc_erreg&SELR) == 0) {
1262471Swnj 		u.u_error = EIO;
1272471Swnj 		goto eio;
1281919Swnj 	}
1292471Swnj 	sc->sc_openf = 1;
1302471Swnj 	if (sc->sc_erreg&RWS)
1311919Swnj 		tmwaitrws(dev);			/* wait for rewind complete */
1322471Swnj 	while (sc->sc_erreg&SDWN)
133*2574Swnj 		tmcommand(dev, NOP, 1);		/* await settle down */
1342471Swnj 	if ((sc->sc_erreg&TUR)==0 ||
1352471Swnj 	    ((flag&(FREAD|FWRITE)) == FWRITE && (sc->sc_erreg&WRL))) {
1362396Swnj 		((struct device *)ui->ui_addr)->tmcs = DCLR|GO;
1371919Swnj 		u.u_error = EIO;		/* offline or write protect */
1381919Swnj 	}
1391919Swnj 	if (u.u_error != 0) {
1402471Swnj 		sc->sc_openf = 0;
1412471Swnj 		if (u.u_error == EIO)
1422471Swnj eio:
1432471Swnj 			uprintf("tape offline or protected\n");
1441919Swnj 		return;
1451919Swnj 	}
1462471Swnj 	sc->sc_blkno = (daddr_t)0;
1472471Swnj 	sc->sc_nxrec = INF;
1482471Swnj 	sc->sc_flags = 0;
1492471Swnj 	sc->sc_openf = 1;
1501919Swnj }
1511919Swnj 
1521919Swnj tmwaitrws(dev)
1531919Swnj 	register dev;
1541919Swnj {
1552396Swnj 	register struct device *addr =
1562471Swnj 	    (struct device *)tmdinfo[0]->ui_addr;
1572471Swnj 	register struct tm_softc *sc = &tm_softc[0];
1581919Swnj 
1591919Swnj 	spl5();
1601919Swnj 	for (;;) {
1612396Swnj 		if ((addr->tmer&RWS) == 0) {
1621919Swnj 			spl0();		/* rewind complete */
1631919Swnj 			return;
1641919Swnj 		}
1652471Swnj 		sc->sc_flags |= WAITREW;
1662471Swnj 		sleep((caddr_t)&sc->sc_flags, PRIBIO);
1671919Swnj 	}
1681919Swnj }
1691919Swnj 
1701919Swnj tmclose(dev, flag)
1711919Swnj 	register dev_t dev;
1721919Swnj 	register flag;
1731919Swnj {
1742471Swnj 	register struct tm_softc *sc = &tm_softc[0];
1751919Swnj 
1762471Swnj 	if (flag == FWRITE || ((flag&FWRITE) && (sc->sc_flags&LASTIOW))) {
177*2574Swnj 		tmcommand(dev, WEOF, 1);
178*2574Swnj 		tmcommand(dev, WEOF, 1);
179*2574Swnj 		tmcommand(dev, SREV, 1);
1801919Swnj 	}
1811919Swnj 	if ((minor(dev)&T_NOREWIND) == 0)
182*2574Swnj 		tmcommand(dev, REW, 1);
1832471Swnj 	sc->sc_openf = 0;
1841919Swnj }
1851919Swnj 
186*2574Swnj tmcommand(dev, com, count)
1871919Swnj 	dev_t dev;
1881919Swnj 	int com, count;
1891919Swnj {
1901919Swnj 	register struct buf *bp;
1911919Swnj 
1921919Swnj 	bp = &ctmbuf;
1931919Swnj 	(void) spl5();
1941919Swnj 	while (bp->b_flags&B_BUSY) {
1951919Swnj 		bp->b_flags |= B_WANTED;
1961919Swnj 		sleep((caddr_t)bp, PRIBIO);
1971919Swnj 	}
1981919Swnj 	bp->b_flags = B_BUSY|B_READ;
1991919Swnj 	(void) spl0();
2001919Swnj 	bp->b_dev = dev;
2011919Swnj 	bp->b_repcnt = -count;
2021919Swnj 	bp->b_command = com;
2031919Swnj 	bp->b_blkno = 0;
2041919Swnj 	tmstrategy(bp);
2051919Swnj 	iowait(bp);
2061919Swnj 	if (bp->b_flags&B_WANTED)
2071919Swnj 		wakeup((caddr_t)bp);
2081919Swnj 	bp->b_flags &= B_ERROR;
2091919Swnj }
2101919Swnj 
2111919Swnj tmstrategy(bp)
2121919Swnj 	register struct buf *bp;
2131919Swnj {
2141919Swnj 	register daddr_t *p;
2152458Swnj 	register struct buf *tmi;
2161919Swnj 
2171928Swnj 	tmwaitrws(bp->b_dev);
2181919Swnj 	if (bp != &ctmbuf) {
2192471Swnj 		p = &tm_softc[0].sc_nxrec;
2201919Swnj 		if (dbtofsb(bp->b_blkno) > *p) {
2211919Swnj 			bp->b_flags |= B_ERROR;
2221919Swnj 			bp->b_error = ENXIO;		/* past EOF */
2231919Swnj 			iodone(bp);
2241919Swnj 			return;
2251919Swnj 		} else if (dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) {
2261919Swnj 			bp->b_resid = bp->b_bcount;
2271919Swnj 			clrbuf(bp);			/* at EOF */
2281919Swnj 			iodone(bp);
2291919Swnj 			return;
2301919Swnj 		} else if ((bp->b_flags&B_READ) == 0)
2311919Swnj 			*p = dbtofsb(bp->b_blkno) + 1;	/* write sets EOF */
2321919Swnj 	}
2331919Swnj 	bp->av_forw = NULL;
2341919Swnj 	(void) spl5();
2352458Swnj 	tmi = &tmminfo[0]->um_tab;
2362458Swnj 	if (tmi->b_actf == NULL)
2372458Swnj 		tmi->b_actf = bp;
2381919Swnj 	else
2392458Swnj 		tmi->b_actl->av_forw = bp;
2402458Swnj 	tmi->b_actl = bp;
2412458Swnj 	if (tmi->b_active == 0)
2421919Swnj 		tmstart();
2431919Swnj 	(void) spl0();
2441919Swnj }
2451919Swnj 
2461919Swnj tmstart()
2471919Swnj {
2481919Swnj 	register struct buf *bp;
2492471Swnj 	register struct uba_minfo *um = tmminfo[0];
2502396Swnj 	register struct uba_dinfo *ui;
2512396Swnj 	register struct device *addr;
2522471Swnj 	register struct tm_softc *sc = &tm_softc[0];
2532471Swnj 	int cmd, s;
2542471Swnj 	daddr_t blkno;
2551919Swnj 
2561919Swnj loop:
2572471Swnj 	if ((bp = um->um_tab.b_actf) == 0)
2581919Swnj 		return;
2592471Swnj 	ui = tmdinfo[0];
2602396Swnj 	addr = (struct device *)ui->ui_addr;
2612471Swnj 	sc->sc_dsreg = addr->tmcs;
2622471Swnj 	sc->sc_erreg = addr->tmer;
2632471Swnj 	sc->sc_resid = addr->tmbc;
2642471Swnj 	sc->sc_flags &= ~LASTIOW;
2652471Swnj 	if (sc->sc_openf < 0 || (addr->tmcs&CUR) == 0) {
2662471Swnj 		/* sc->sc_openf = -1; ??? */
2671919Swnj 		bp->b_flags |= B_ERROR;		/* hard error'ed or !SELR */
2681919Swnj 		goto next;
2691919Swnj 	}
2701919Swnj 	cmd = IENABLE | GO;
2711919Swnj 	if ((minor(bp->b_dev) & T_1600BPI) == 0)
2721919Swnj 		cmd |= D800;
2731919Swnj 	if (bp == &ctmbuf) {
2741919Swnj 		if (bp->b_command == NOP)
2751919Swnj 			goto next;		/* just get status */
2761919Swnj 		else {
2771919Swnj 			cmd |= bp->b_command;
2782471Swnj 			um->um_tab.b_active = SCOM;
2791919Swnj 			if (bp->b_command == SFORW || bp->b_command == SREV)
2802396Swnj 				addr->tmbc = bp->b_repcnt;
2812396Swnj 			addr->tmcs = cmd;
2821919Swnj 			return;
2831919Swnj 		}
2841919Swnj 	}
2852471Swnj 	if ((blkno = sc->sc_blkno) == dbtofsb(bp->b_blkno)) {
2862396Swnj 		addr->tmbc = -bp->b_bcount;
2871919Swnj 		if ((bp->b_flags&B_READ) == 0) {
2882471Swnj 			if (um->um_tab.b_errcnt)
2891919Swnj 				cmd |= WIRG;
2901919Swnj 			else
2911919Swnj 				cmd |= WCOM;
2921919Swnj 		} else
2931919Swnj 			cmd |= RCOM;
2942471Swnj 		um->um_tab.b_active = SIO;
295*2574Swnj 		if (um->um_ubinfo)
296*2574Swnj 			panic("tmstart");
297*2574Swnj 		um->um_cmd = cmd;
298*2574Swnj 		ubago(ui);
299*2574Swnj 		splx(s);
3001919Swnj 		return;
3011919Swnj 	}
3022471Swnj 	um->um_tab.b_active = SSEEK;
3031919Swnj 	if (blkno < dbtofsb(bp->b_blkno)) {
3041919Swnj 		cmd |= SFORW;
3052396Swnj 		addr->tmbc = blkno - dbtofsb(bp->b_blkno);
3061919Swnj 	} else {
3071919Swnj 		cmd |= SREV;
3082396Swnj 		addr->tmbc = dbtofsb(bp->b_blkno) - blkno;
3091919Swnj 	}
3102396Swnj 	addr->tmcs = cmd;
3111919Swnj 	return;
3121919Swnj 
3131919Swnj next:
314*2574Swnj 	ubarelse(um->um_ubanum, &um->um_ubinfo);
3152471Swnj 	um->um_tab.b_actf = bp->av_forw;
3161919Swnj 	iodone(bp);
3171919Swnj 	goto loop;
3181919Swnj }
3191919Swnj 
320*2574Swnj tmdgo(um)
321*2574Swnj 	register struct uba_minfo *um;
3221919Swnj {
323*2574Swnj 	register struct device *addr = (struct device *)um->um_addr;
3242471Swnj 
325*2574Swnj 	printf("tmdgo %x %x\n", um->um_ubinfo, um->um_cmd);
326*2574Swnj 	addr->tmba = um->um_ubinfo;
327*2574Swnj 	addr->tmcs = um->um_cmd | ((um->um_ubinfo >> 12) & 0x30);
3282396Swnj }
3292396Swnj 
3302471Swnj /*ARGSUSED*/
3312396Swnj tmintr(d)
3322471Swnj 	int d;
3332396Swnj {
3341919Swnj 	register struct buf *bp;
3352471Swnj 	register struct uba_minfo *um = tmminfo[0];
3362471Swnj 	register struct device *addr = (struct device *)tmdinfo[0]->ui_addr;
3372471Swnj 	register struct tm_softc *sc = &tm_softc[0];
3381919Swnj 	register state;
3391919Swnj 
340*2574Swnj 	printf("tmintr %x %x\n", um->um_tab.b_actf, um->um_tab.b_active);
3412471Swnj 	if (sc->sc_flags&WAITREW && (addr->tmer&RWS) == 0) {
3422471Swnj 		sc->sc_flags &= ~WAITREW;
3432471Swnj 		wakeup((caddr_t)&sc->sc_flags);
3441919Swnj 	}
3452471Swnj 	if ((bp = um->um_tab.b_actf) == NULL)
3461919Swnj 		return;
3472471Swnj 	sc->sc_dsreg = addr->tmcs;
3482471Swnj 	sc->sc_erreg = addr->tmer;
3492471Swnj 	sc->sc_resid = addr->tmbc;
3501919Swnj 	if ((bp->b_flags & B_READ) == 0)
3512471Swnj 		sc->sc_flags |= LASTIOW;
3522471Swnj 	state = um->um_tab.b_active;
3532471Swnj 	um->um_tab.b_active = 0;
3542396Swnj 	if (addr->tmcs&ERROR) {
3552396Swnj 		while(addr->tmer & SDWN)
3561919Swnj 			;			/* await settle down */
3572396Swnj 		if (addr->tmer&EOF) {
3581919Swnj 			tmseteof(bp);	/* set blkno and nxrec */
3591919Swnj 			state = SCOM;
3602396Swnj 			addr->tmbc = -bp->b_bcount;
3611919Swnj 			goto errout;
3621919Swnj 		}
3632396Swnj 		if ((bp->b_flags&B_READ) && (addr->tmer&(HARD|SOFT)) == RLE)
3641919Swnj 			goto out;
3652396Swnj 		if ((addr->tmer&HARD)==0 && state==SIO) {
3662471Swnj 			if (++um->um_tab.b_errcnt < 7) {
3672396Swnj 				if((addr->tmer&SOFT) == NXM)
3681919Swnj 					printf("TM UBA late error\n");
3692471Swnj 				sc->sc_blkno++;
370*2574Swnj 				ubarelse(um->um_ubanum, &um->um_ubinfo);
3711919Swnj 				tmstart();
3721919Swnj 				return;
3731919Swnj 			}
3742471Swnj 		} else if (sc->sc_openf>0 && bp != &rtmbuf)
3752471Swnj 			sc->sc_openf = -1;
3762471Swnj 		deverror(bp, sc->sc_erreg, sc->sc_dsreg);
3771919Swnj 		bp->b_flags |= B_ERROR;
3781919Swnj 		state = SIO;
3791919Swnj 	}
3801919Swnj out:
3811919Swnj 	switch (state) {
3821919Swnj 
3831919Swnj 	case SIO:
3842471Swnj 		sc->sc_blkno++;
3851919Swnj 		/* fall into ... */
3861919Swnj 
3871919Swnj 	case SCOM:
3881919Swnj 		if (bp == &ctmbuf) {
3891919Swnj 			switch (bp->b_command) {
3901919Swnj 			case SFORW:
3912471Swnj 				sc->sc_blkno -= bp->b_repcnt;
3921919Swnj 				break;
3931919Swnj 
3941919Swnj 			case SREV:
3952471Swnj 				sc->sc_blkno += bp->b_repcnt;
3961919Swnj 				break;
3971919Swnj 
3981919Swnj 			default:
3991919Swnj 				if (++bp->b_repcnt < 0) {
4001919Swnj 					tmstart();	/* continue */
4011919Swnj 					return;
4021919Swnj 				}
4031919Swnj 			}
4041919Swnj 		}
4051919Swnj errout:
4062471Swnj 		um->um_tab.b_errcnt = 0;
4072471Swnj 		um->um_tab.b_actf = bp->av_forw;
4082396Swnj 		bp->b_resid = -addr->tmbc;
409*2574Swnj 		ubarelse(um->um_ubanum, &um->um_ubinfo);
4101919Swnj 		iodone(bp);
4111919Swnj 		break;
4121919Swnj 
4131919Swnj 	case SSEEK:
4142471Swnj 		sc->sc_blkno = dbtofsb(bp->b_blkno);
4151919Swnj 		break;
4161919Swnj 
4171919Swnj 	default:
4181919Swnj 		return;
4191919Swnj 	}
4201919Swnj 	tmstart();
4211919Swnj }
4221919Swnj 
4231919Swnj tmseteof(bp)
4241919Swnj 	register struct buf *bp;
4251919Swnj {
4262396Swnj 	register struct device *addr =
4272471Swnj 	    (struct device *)tmdinfo[0]->ui_addr;
4282471Swnj 	register struct tm_softc *sc = &tm_softc[0];
4291919Swnj 
4301919Swnj 	if (bp == &ctmbuf) {
4312471Swnj 		if (sc->sc_blkno > dbtofsb(bp->b_blkno)) {
4321919Swnj 			/* reversing */
4332471Swnj 			sc->sc_nxrec = dbtofsb(bp->b_blkno) - addr->tmbc;
4342471Swnj 			sc->sc_blkno = sc->sc_nxrec;
4351919Swnj 		} else {
4361919Swnj 			/* spacing forward */
4372471Swnj 			sc->sc_blkno = dbtofsb(bp->b_blkno) + addr->tmbc;
4382471Swnj 			sc->sc_nxrec = sc->sc_blkno - 1;
4391919Swnj 		}
4401919Swnj 		return;
4411919Swnj 	}
4421919Swnj 	/* eof on read */
4432471Swnj 	sc->sc_nxrec = dbtofsb(bp->b_blkno);
4441919Swnj }
4451919Swnj 
4461919Swnj tmread(dev)
4471919Swnj {
4481919Swnj 
4491919Swnj 	tmphys(dev);
4501919Swnj 	physio(tmstrategy, &rtmbuf, dev, B_READ, minphys);
4511919Swnj }
4521919Swnj 
4531919Swnj tmwrite(dev)
4541919Swnj {
4551919Swnj 
4561919Swnj 	tmphys(dev);
4571919Swnj 	physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys);
4581919Swnj }
4591919Swnj 
4601919Swnj tmphys(dev)
4611919Swnj {
4621919Swnj 	register daddr_t a;
4632471Swnj 	register struct tm_softc *sc = &tm_softc[0];
4641919Swnj 
4651919Swnj 	a = dbtofsb(u.u_offset >> 9);
4662471Swnj 	sc->sc_blkno = a;
4672471Swnj 	sc->sc_nxrec = a + 1;
4681919Swnj }
4691919Swnj 
4701919Swnj /*ARGSUSED*/
4711919Swnj tmioctl(dev, cmd, addr, flag)
4721919Swnj 	caddr_t addr;
4731919Swnj 	dev_t dev;
4741919Swnj {
4751919Swnj 	register callcount;
4762471Swnj 	register struct tm_softc *sc = &tm_softc[0];
4771919Swnj 	int fcount;
4781919Swnj 	struct mtop mtop;
4791919Swnj 	struct mtget mtget;
4801919Swnj 	/* we depend of the values and order of the MT codes here */
4812324Skre 	static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL, NOP};
4821919Swnj 
4831919Swnj 	switch(cmd) {
4841919Swnj 		case MTIOCTOP:	/* tape operation */
4851919Swnj 		if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
4861919Swnj 			u.u_error = EFAULT;
4871919Swnj 			return;
4881919Swnj 		}
4891919Swnj 		switch(mtop.mt_op) {
4901919Swnj 		case MTWEOF: case MTFSF: case MTBSF:
4911919Swnj 			callcount = mtop.mt_count;
4921919Swnj 			fcount = INF;
4931919Swnj 			break;
4941919Swnj 		case MTFSR: case MTBSR:
4951919Swnj 			callcount = 1;
4961919Swnj 			fcount = mtop.mt_count;
4971919Swnj 			break;
4982324Skre 		case MTREW: case MTOFFL: case MTNOP:
4991919Swnj 			callcount = 1;
5001919Swnj 			fcount = 1;
5011919Swnj 			break;
5021919Swnj 		default:
5031919Swnj 			u.u_error = ENXIO;
5041919Swnj 			return;
5051919Swnj 		}
5061919Swnj 		if (callcount <= 0 || fcount <= 0)
5071919Swnj 			u.u_error = ENXIO;
5081919Swnj 		else while (--callcount >= 0) {
509*2574Swnj 			tmcommand(dev, tmops[mtop.mt_op], fcount);
5101919Swnj 			if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
5111919Swnj 			    ctmbuf.b_resid) {
5121919Swnj 				u.u_error = EIO;
5131919Swnj 				break;
5141919Swnj 			}
5152471Swnj 			if ((ctmbuf.b_flags&B_ERROR) ||
5162471Swnj 			    sc->sc_erreg&BOT)
5171919Swnj 				break;
5181919Swnj 		}
5191919Swnj 		geterror(&ctmbuf);
5201919Swnj 		return;
5211919Swnj 	case MTIOCGET:
5222471Swnj 		mtget.mt_dsreg = sc->sc_dsreg;
5232471Swnj 		mtget.mt_erreg = sc->sc_erreg;
5242471Swnj 		mtget.mt_resid = sc->sc_resid;
5251919Swnj 		if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
5261919Swnj 			u.u_error = EFAULT;
5271919Swnj 		return;
5281919Swnj 	default:
5291919Swnj 		u.u_error = ENXIO;
5301919Swnj 	}
5311919Swnj }
5321919Swnj 
5331919Swnj #define	DBSIZE	20
5341919Swnj 
5352363Swnj tmdump()
5362363Swnj {
5372396Swnj 	register struct uba_dinfo *ui;
5382396Swnj 	register struct uba_regs *up;
5392396Swnj 	register struct device *addr;
5402426Skre 	int blk, num;
5412426Skre 	int start;
5421919Swnj 
5432426Skre 	start = 0;
5442426Skre 	num = maxfree;
5452426Skre #define	phys(a,b)	((b)((int)(a)&0x7fffffff))
5462458Swnj 	if (tmdinfo[0] == 0) {
5472396Swnj 		printf("dna\n");
5482396Swnj 		return (-1);
5492396Swnj 	}
5502458Swnj 	ui = phys(tmdinfo[0], struct uba_dinfo *);
5512396Swnj 	up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba;
5522396Swnj #if VAX780
5532396Swnj 	if (cpu == VAX_780)
5542396Swnj 		ubainit(up);
5551919Swnj #endif
5562324Skre 	DELAY(1000000);
5572396Swnj 	addr = (struct device *)ui->ui_physaddr;
5582396Swnj 	tmwait(addr);
5592396Swnj 	addr->tmcs = DCLR | GO;
5601919Swnj 	while (num > 0) {
5611919Swnj 		blk = num > DBSIZE ? DBSIZE : num;
5622396Swnj 		tmdwrite(start, blk, addr, up);
5631919Swnj 		start += blk;
5641919Swnj 		num -= blk;
5651919Swnj 	}
5662426Skre 	tmeof(addr);
5672426Skre 	tmeof(addr);
5682426Skre 	tmwait(addr);
5692471Swnj 	addr->tmcs = REW | GO;
5702471Swnj 	tmwait(addr);
5712363Swnj 	return (0);
5721919Swnj }
5731919Swnj 
5742396Swnj tmdwrite(buf, num, addr, up)
5752396Swnj 	register buf, num;
5762396Swnj 	register struct device *addr;
5772396Swnj 	struct uba_regs *up;
5781919Swnj {
5792396Swnj 	register struct pte *io;
5802396Swnj 	register int npf;
5811928Swnj 
5822396Swnj 	tmwait(addr);
5832396Swnj 	io = up->uba_map;
5841919Swnj 	npf = num+1;
5851928Swnj 	while (--npf != 0)
5862396Swnj 		 *(int *)io++ = (buf++ | (1<<UBA_DPSHIFT) | UBA_MRV);
5872396Swnj 	*(int *)io = 0;
5882396Swnj 	addr->tmbc = -(num*NBPG);
5892396Swnj 	addr->tmba = 0;
5902396Swnj 	addr->tmcs = WCOM | GO;
5911919Swnj }
5921919Swnj 
5932396Swnj tmwait(addr)
5942396Swnj 	register struct device *addr;
5951919Swnj {
5961928Swnj 	register s;
5971919Swnj 
5981919Swnj 	do
5992396Swnj 		s = addr->tmcs;
6001919Swnj 	while ((s & CUR) == 0);
6011919Swnj }
6021919Swnj 
6032396Swnj tmeof(addr)
6042396Swnj 	struct device *addr;
6051919Swnj {
6061919Swnj 
6072396Swnj 	tmwait(addr);
6082396Swnj 	addr->tmcs = WEOF | GO;
6091919Swnj }
6101919Swnj #endif
611