xref: /csrg-svn/sys/vax/mba/ht.c (revision 2926)
11936Swnj #include "ht.h"
21563Sbill #if NHT > 0
322Sbill /*
4*2926Swnj  * TM03/TU?? tape driver
522Sbill  */
622Sbill #include "../h/param.h"
722Sbill #include "../h/systm.h"
822Sbill #include "../h/buf.h"
922Sbill #include "../h/conf.h"
1022Sbill #include "../h/dir.h"
1122Sbill #include "../h/file.h"
1222Sbill #include "../h/user.h"
1322Sbill #include "../h/map.h"
14420Sbill #include "../h/pte.h"
1522Sbill #include "../h/mba.h"
16*2926Swnj #include "../h/mtio.h"
17*2926Swnj #include "../h/ioctl.h"
181917Swnj #include "../h/cmap.h"
1922Sbill 
20*2926Swnj #include "../h/htreg.h"
2122Sbill 
22*2926Swnj struct	buf	rhtbuf[NHT];
23*2926Swnj struct	buf	chtbuf[NHT];
2422Sbill 
25*2926Swnj short	httypes[] =
26*2926Swnj 	{ MBDT_TE16, MBDT_TU45, MBDT_TU77, 0 };
27*2926Swnj struct	mba_info *htinfo[NHT];
28*2926Swnj int	htdkinit(), htustart(), htndtint(), htdtint();
29*2926Swnj struct	mba_driver htdriver =
30*2926Swnj 	{ htdkinit, htustart, 0, htdtint, htndtint, httypes, htinfo };
3122Sbill 
32*2926Swnj #define MASKREG(r)	((r) & 0xffff)
3322Sbill 
34*2926Swnj /* bits in minor device */
35*2926Swnj #define HTUNIT(dev)	(minor(dev)&03)
36*2926Swnj #define	H_NOREWIND	04
37*2926Swnj #define	H_1600BPI	08
3822Sbill 
39*2926Swnj #define	INF	(daddr_t)1000000L	/* a block number that wont exist */
40*2926Swnj 
41*2926Swnj struct	ht_softc {
42*2926Swnj 	char	sc_openf;
43*2926Swnj 	char	sc_flags;
44*2926Swnj 	daddr_t	sc_blkno;
45*2926Swnj 	daddr_t	sc_nxrec;
46*2926Swnj 	u_short	sc_erreg;
47*2926Swnj 	u_short	sc_dsreg;
48*2926Swnj 	short	sc_resid;
49*2926Swnj 	short	sc_dens;
50*2926Swnj } ht_softc[NHT];
51*2926Swnj 
52*2926Swnj /*
53*2926Swnj  * States for b_active for device.
54*2926Swnj  */
5522Sbill #define	SIO	1
5622Sbill #define	SSFOR	2
5722Sbill #define	SSREV	3
5822Sbill #define	SRETRY	4
5922Sbill #define	SCOM	5
6022Sbill #define	SOK	6
61*2926Swnj #define	SEOF	7
6222Sbill 
63*2926Swnj /*
64*2926Swnj  * Bits for sc_flags.
65*2926Swnj  */
66*2926Swnj #define	H_WRITTEN 1	/* last operation was a write */
67*2926Swnj #define H_ERASED  2	/* last write retry was an erase gap */
68*2926Swnj #define H_REWIND  4	/* last unit start was a rewind */
6922Sbill 
70*2926Swnj /*ARGSUSED*/
71*2926Swnj htdkinit(mi)
72*2926Swnj 	struct mba_info *mi;
73*2926Swnj {
74*2926Swnj 
75*2926Swnj }
76*2926Swnj 
7722Sbill htopen(dev, flag)
78*2926Swnj 	dev_t dev;
79*2926Swnj 	int flag;
8022Sbill {
81*2926Swnj 	register int unit;
82*2926Swnj 	register struct mba_info *mi;
83*2926Swnj 	register struct ht_softc *sc;
8422Sbill 
85*2926Swnj 	unit = HTUNIT(dev);
86*2926Swnj 	if (unit >= NHT || (sc = &ht_softc[unit])->sc_openf ||
87*2926Swnj 	    (mi = htinfo[unit]) == 0 || mi->mi_alive == 0) {
8822Sbill 		u.u_error = ENXIO;
8922Sbill 		return;
9022Sbill 	}
91*2926Swnj 	/*
92*2926Swnj 	 * The NOP below serves two purposes:
93*2926Swnj 	 * 1. To get a recent copy of the status registers.
94*2926Swnj 	 * 2. To ensure that any outstanding rewinds are truly finished
95*2926Swnj 	 *	so that the test for BOT is valid.
96*2926Swnj 	 */
97*2926Swnj 	htcommand(dev, HT_SENSE, 1);
98*2926Swnj 	if ((sc->sc_dsreg & HTDS_MOL) == 0 ||
99*2926Swnj 	   (flag & (FREAD|FWRITE)) == FWRITE && sc->sc_dsreg&HTDS_WRL) {
100*2926Swnj 		u.u_error = EIO;
101*2926Swnj 		return;
102*2926Swnj 	}
103*2926Swnj 	sc->sc_dens =
104*2926Swnj 	    ((minor(dev)&H_1600BPI)?HTTC_1600BPI:HTTC_800BPI)|HTTC_PDP11|unit;
105*2926Swnj 	sc->sc_openf = 1;
106*2926Swnj 	sc->sc_blkno = (daddr_t)0;
107*2926Swnj 	sc->sc_nxrec = INF;
108*2926Swnj 	sc->sc_flags = 0;
10922Sbill }
11022Sbill 
11122Sbill htclose(dev, flag)
112*2926Swnj 	register dev_t dev;
113*2926Swnj 	register flag;
11422Sbill {
115*2926Swnj 	register struct ht_softc *sc = &ht_softc[HTUNIT(dev)];
11622Sbill 
117*2926Swnj 	if (flag == FWRITE || ((flag&FWRITE) && (sc->sc_flags&H_WRITTEN))) {
118*2926Swnj 		htcommand(dev, HT_WEOF, 1);
119*2926Swnj 		htcommand(dev, HT_WEOF, 1);
120*2926Swnj 		htcommand(dev, HT_SREV, 1);
12122Sbill 	}
122*2926Swnj 	if ((minor(dev)&H_NOREWIND) == 0)
123*2926Swnj 		/* 0 as third arg means don't wait */
124*2926Swnj 		htcommand(dev, HT_REW, 0);
125*2926Swnj 	sc->sc_openf = 0;
12622Sbill }
12722Sbill 
128*2926Swnj /*
129*2926Swnj  * Do a non-data-transfer command.
130*2926Swnj  *
131*2926Swnj  * N.B.: Count should be zero ONLY for rewind during close.
132*2926Swnj  */
133*2926Swnj htcommand(dev, com, count)
134*2926Swnj 	dev_t dev;
135*2926Swnj 	int com, count;
13622Sbill {
13722Sbill 	register struct buf *bp;
13822Sbill 
139*2926Swnj 	bp = &chtbuf[HTUNIT(dev)];
140128Sbill 	(void) spl5();
141*2926Swnj 	/*
142*2926Swnj 	 * The B_DONE test is to allow the rewind on close not to wait at
143*2926Swnj 	 * all.  We just must make sure that it was an asynchronous rewind,
144*2926Swnj 	 * otherwise if it isn't we might wake up before the process
145*2926Swnj 	 * waiting for the command (we are waiting for the buffer here).
146*2926Swnj 	 */
147*2926Swnj 	while (bp->b_flags&B_BUSY) {
148*2926Swnj 		if (bp->b_flags&B_DONE && bp->b_repcnt == 0)
149*2926Swnj 			break;
15022Sbill 		bp->b_flags |= B_WANTED;
15122Sbill 		sleep((caddr_t)bp, PRIBIO);
15222Sbill 	}
153*2926Swnj 	bp->b_flags = B_BUSY;
154128Sbill 	(void) spl0();
15522Sbill 	bp->b_dev = dev;
156*2926Swnj 	bp->b_command = com;
157*2926Swnj 	bp->b_repcnt = count;
15822Sbill 	bp->b_blkno = 0;
15922Sbill 	htstrategy(bp);
160*2926Swnj 	if (count == 0)
161*2926Swnj 		return;
16222Sbill 	iowait(bp);
163*2926Swnj 	if (bp->b_flags&B_WANTED)
16422Sbill 		wakeup((caddr_t)bp);
165*2926Swnj 	bp->b_flags &= B_ERROR;
16622Sbill }
16722Sbill 
16822Sbill htstrategy(bp)
169*2926Swnj 	register struct buf *bp;
17022Sbill {
171*2926Swnj 	register int unit = HTUNIT(bp->b_dev);
172*2926Swnj 	register struct mba_info *mi;
173*2926Swnj 	register struct buf *dp;
174*2926Swnj 	register struct ht_softc *sc = &ht_softc[unit];
17522Sbill 
17622Sbill 	bp->av_forw = NULL;
177*2926Swnj 	dp = &mi->mi_tab;
178128Sbill 	(void) spl5();
179*2926Swnj 	if (dp->b_actf == NULL)
180*2926Swnj 		dp->b_actf = bp;
18122Sbill 	else
182*2926Swnj 		dp->b_actl->av_forw = bp;
183*2926Swnj 	dp->b_actl = bp;
184*2926Swnj 	if (dp->b_active == 0)
185*2926Swnj 		mbustart(mi);
186128Sbill 	(void) spl0();
18722Sbill }
18822Sbill 
189*2926Swnj htustart(mi)
190*2926Swnj 	register struct mba_info *mi;
19122Sbill {
192*2926Swnj 	register struct htdevice *htaddr =
193*2926Swnj 	    (struct htdevice *)mi->mi_drv;
194*2926Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
195*2926Swnj 	int unit = HTUNIT(bp->b_dev);
196*2926Swnj 	register struct ht_softc *sc = &ht_softc[unit];
19722Sbill 	daddr_t blkno;
19822Sbill 
199*2926Swnj 	htaddr->httc = sc->sc_dens;
200*2926Swnj 	sc->sc_dsreg = htaddr->htds;
201*2926Swnj 	sc->sc_erreg = htaddr->hter;
202*2926Swnj 	sc->sc_resid = htaddr->htfc;
203*2926Swnj 	sc->sc_flags &= ~(H_WRITTEN|H_REWIND);
204*2926Swnj 	if ((htaddr->htdt & HTDT_SPR) == 0 || (htaddr->htds & HTDS_MOL) == 0)
205*2926Swnj 		if (sc->sc_openf > 0)
206*2926Swnj 			sc->sc_openf = -1;
207*2926Swnj 	if (sc->sc_openf < 0) {
208*2926Swnj 		bp->b_flags |= B_ERROR;
209*2926Swnj 		return (MBU_NEXT);
210*2926Swnj 	}
211*2926Swnj 	if (bp != &chtbuf[unit]) {
212*2926Swnj 		if (dbtofsb(bp->b_blkno) > sc->sc_nxrec) {
213*2926Swnj 			bp->b_flags |= B_ERROR;
214*2926Swnj 			bp->b_error = ENXIO;
21522Sbill 			goto next;
216*2926Swnj 		} else if (dbtofsb(bp->b_blkno) == sc->sc_nxrec &&
217*2926Swnj 		    bp->b_flags&B_READ) {
218*2926Swnj 			bp->b_resid = bp->b_bcount;
219*2926Swnj 			clrbuf(bp);
220*2926Swnj 			goto next;
221*2926Swnj 		} else if ((bp->b_flags&B_READ)==0)
222*2926Swnj 			sc->sc_nxrec = dbtofsb(bp->b_blkno) + 1;
223*2926Swnj 	} else {
224*2926Swnj 		if (bp->b_command == HT_SENSE)
225*2926Swnj 			return (MBU_NEXT);
226*2926Swnj 		if (bp->b_command == HT_REW)
227*2926Swnj 			sc->sc_flags |= H_REWIND;
228*2926Swnj 		else
229*2926Swnj 			htaddr->htfc = -bp->b_bcount;
230*2926Swnj 		htaddr->htcs1 = bp->b_command|HT_GO;
231*2926Swnj 		return (MBU_STARTED);
232*2926Swnj 	}
233*2926Swnj 	if ((blkno = sc->sc_blkno) == dbtofsb(bp->b_blkno)) {
234*2926Swnj 		htaddr->htfc = -bp->b_bcount;
235*2926Swnj 		if ((bp->b_flags&B_READ) == 0) {
236*2926Swnj 			if (mi->mi_tab.b_errcnt)
237*2926Swnj 				if (sc->sc_flags & H_ERASED)
238*2926Swnj 					sc->sc_flags &= ~H_ERASED;
239*2926Swnj 				else {
240*2926Swnj 					sc->sc_flags |= H_ERASED;
241*2926Swnj 					htaddr->htcs1 = HT_ERASE | HT_GO;
242*2926Swnj 					return (MBU_STARTED);
243*2926Swnj 				}
244*2926Swnj 			if (htaddr->htds & HTDS_EOT) {
245*2926Swnj 				bp->b_resid = bp->b_bcount;
246*2926Swnj 				return (MBU_NEXT);
247*2926Swnj 			}
24822Sbill 		}
249*2926Swnj 		return (MBU_DODATA);
25022Sbill 	}
251*2926Swnj 	if (blkno < dbtofsb(bp->b_blkno)) {
252*2926Swnj 		htaddr->htfc = blkno - dbtofsb(bp->b_blkno);
253*2926Swnj 		htaddr->htcs1 = HT_SFORW|HT_GO;
25422Sbill 	} else {
255*2926Swnj 		htaddr->htfc = dbtofsb(bp->b_blkno) - blkno;
256*2926Swnj 		htaddr->htcs1 = HT_SREV|HT_GO;
25722Sbill 	}
258*2926Swnj 	return (MBU_STARTED);
259*2926Swnj next:
26022Sbill 	iodone(bp);
261*2926Swnj 	return (MBU_NEXT);
26222Sbill }
26322Sbill 
264*2926Swnj /*
265*2926Swnj  * data transfer interrupt - must be read or write
266*2926Swnj  */
26722Sbill /*ARGSUSED*/
268*2926Swnj htdtint(mi, mbasr)
269*2926Swnj 	register struct mba_info *mi;
270*2926Swnj 	int mbasr;
27122Sbill {
272*2926Swnj 	register struct htdevice *htaddr = (struct htdevice *)mi->mi_drv;
273*2926Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
274*2926Swnj 	register struct ht_softc *sc;
275*2926Swnj 	int ds, er;
27622Sbill 
277*2926Swnj 	if (bp == NULL)
27822Sbill 		return;
279*2926Swnj 	sc = &ht_softc[HTUNIT(bp->b_dev)];
280*2926Swnj 	ds = sc->sc_dsreg = MASKREG(htaddr->htds);
281*2926Swnj 	er = sc->sc_erreg = MASKREG(htaddr->hter);
282*2926Swnj 	sc->sc_resid = MASKREG(htaddr->htfc);
283*2926Swnj 	sc->sc_blkno++;
284*2926Swnj 	if((bp->b_flags & B_READ) == 0)
285*2926Swnj 		sc->sc_flags |= H_WRITTEN;
286*2926Swnj 	if ((ds&(HTDS_ERR|HTDS_MOL)) != HTDS_MOL ||
287*2926Swnj 	    mbasr & MBAEBITS) {
288*2926Swnj 		htaddr->htcs1 = HT_DCLR|HT_GO;
289*2926Swnj 		if (bp == &rhtbuf[HTUNIT(bp->b_dev)])
290*2926Swnj 			er &= ~HTER_FCE;
291*2926Swnj 		if (bp->b_flags & B_READ && ds & HTDS_PES)
292*2926Swnj 			er &= ~(HTER_CSITM|HTER_CORCRC);
293*2926Swnj 		if (er&HTER_HARD ||
294*2926Swnj 		    mbasr&MBAEBITS || (ds&HTDS_MOL) == 0 ||
295*2926Swnj 		    sc->sc_erreg && ++mi->mi_tab.b_errcnt >= 7) {
296*2926Swnj 			if ((ds & HTDS_MOL) == 0 && sc->sc_openf > 0)
297*2926Swnj 				sc->sc_openf = -1;
298*2926Swnj 			printf("ht%d: hard error bn%d mbasr=%b er=%b\n",
299*2926Swnj 			    HTUNIT(bp->b_dev), bp->b_blkno,
300*2926Swnj 			    mbasr, mbasr_bits,
301*2926Swnj 			    MASKREG(htaddr->hter), HTER_BITS);
30222Sbill 			bp->b_flags |= B_ERROR;
303*2926Swnj 			return (MBD_DONE);
30422Sbill 		}
305*2926Swnj 		if (er)
306*2926Swnj 			return (MBD_RETRY);
30722Sbill 	}
308*2926Swnj 	bp->b_resid = 0;
309*2926Swnj 	if (bp->b_flags & B_READ)
310*2926Swnj 		if (ds&HTDS_TM) {		/* must be a read, right? */
311*2926Swnj 			bp->b_resid = bp->b_bcount;
312*2926Swnj 			sc->sc_nxrec = dbtofsb(bp->b_blkno);
313*2926Swnj 		} else if(bp->b_bcount > MASKREG(htaddr->htfc))
314*2926Swnj 			bp->b_resid = bp->b_bcount - MASKREG(htaddr->htfc);
315*2926Swnj 	return (MBD_DONE);
316*2926Swnj }
31722Sbill 
318*2926Swnj /*
319*2926Swnj  * non-data-transfer interrupt
320*2926Swnj  */
321*2926Swnj htndtint(mi)
322*2926Swnj 	register struct mba_info *mi;
323*2926Swnj {
324*2926Swnj 	register struct htdevice *htaddr = (struct htdevice *)mi->mi_drv;
325*2926Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
326*2926Swnj 	register struct ht_softc *sc;
327*2926Swnj 	int er, ds, fc;
32822Sbill 
329*2926Swnj 	if (bp == NULL)
33022Sbill 		return;
331*2926Swnj 	sc = &ht_softc[HTUNIT(bp->b_dev)];
332*2926Swnj 	ds = sc->sc_dsreg = MASKREG(htaddr->htds);
333*2926Swnj 	er = sc->sc_erreg = MASKREG(htaddr->hter);
334*2926Swnj 	sc->sc_resid = MASKREG(htaddr->htfc);
335*2926Swnj 	if (sc->sc_erreg)
336*2926Swnj 		htaddr->htcs1 = HT_DCLR|HT_GO;
337*2926Swnj 	if (bp == &chtbuf[HTUNIT(bp->b_dev)]) {
338*2926Swnj 		if (bp->b_command == HT_REWOFFL)
339*2926Swnj 			/* offline is on purpose; don't do anything special */
340*2926Swnj 			ds |= HTDS_MOL;
341*2926Swnj 		else if (bp->b_resid == HT_SREV &&
342*2926Swnj 		    er == (HTER_NEF|HTER_FCE) &&
343*2926Swnj 		    ds&HTDS_BOT && bp->b_bcount == INF)
344*2926Swnj 			er &= ~HTER_NEF;
345*2926Swnj 		er &= ~HTER_FCE;
346*2926Swnj 		if (er == 0)
347*2926Swnj 			ds &= ~HTDS_ERR;
34822Sbill 	}
349*2926Swnj 	if ((ds & (HTDS_ERR|HTDS_MOL)) != HTDS_MOL) {
350*2926Swnj 		if ((ds & HTDS_MOL) == 0 && sc->sc_openf > 0)
351*2926Swnj 			sc->sc_openf = -1;
352*2926Swnj 		printf("ht%d: hard error bn%d er=%b ds=%b\n",
353*2926Swnj 		    HTUNIT(bp->b_dev), bp->b_blkno,
354*2926Swnj 		    sc->sc_erreg, HTER_BITS, sc->sc_dsreg, HTDS_BITS);
355*2926Swnj 		bp->b_flags |= B_ERROR;
356*2926Swnj 		return (MBN_DONE);
357*2926Swnj 	}
358*2926Swnj 	if (bp == &chtbuf[HTUNIT(bp->b_dev)]) {
359*2926Swnj 		if (sc->sc_flags & H_REWIND)
360*2926Swnj 			return (ds & HTDS_BOT ? MBN_DONE : MBN_RETRY);
361*2926Swnj 		bp->b_resid = -sc->sc_resid;
362*2926Swnj 		return (MBN_DONE);
363*2926Swnj 	}
364*2926Swnj 	if (ds & HTDS_TM)
365*2926Swnj 		if (sc->sc_blkno > dbtofsb(bp->b_blkno)) {/* reversing */
366*2926Swnj 			sc->sc_nxrec = dbtofsb(bp->b_blkno) - fc;
367*2926Swnj 			sc->sc_blkno = sc->sc_nxrec;
368*2926Swnj 		} else {			/* spacing forward */
369*2926Swnj 			sc->sc_blkno = dbtofsb(bp->b_blkno) + fc;
370*2926Swnj 			sc->sc_nxrec = sc->sc_blkno - 1;
371*2926Swnj 		}
372*2926Swnj 	else
373*2926Swnj 		sc->sc_blkno = dbtofsb(bp->b_blkno);
374*2926Swnj 	return (MBN_RETRY);
37522Sbill }
37622Sbill 
37722Sbill htread(dev)
378*2926Swnj 	dev_t dev;
37922Sbill {
380*2926Swnj 
38122Sbill 	htphys(dev);
382*2926Swnj 	if (u.u_error)
383*2926Swnj 		return;
384*2926Swnj 	physio(htstrategy, &rhtbuf[HTUNIT(dev)], dev, B_READ, minphys);
38522Sbill }
38622Sbill 
38722Sbill htwrite(dev)
38822Sbill {
389*2926Swnj 
39022Sbill 	htphys(dev);
391*2926Swnj 	if (u.u_error)
392*2926Swnj 		return;
393*2926Swnj 	physio(htstrategy, &rhtbuf[HTUNIT(dev)], dev, B_WRITE, minphys);
39422Sbill }
39522Sbill 
39622Sbill htphys(dev)
397*2926Swnj 	dev_t dev;
39822Sbill {
399*2926Swnj 	register int unit;
400*2926Swnj 	register struct ht_softc *sc;
40122Sbill 	daddr_t a;
40222Sbill 
403*2926Swnj 	unit = HTUNIT(dev);
404*2926Swnj 	if (unit >= NHT) {
405*2926Swnj 		u.u_error = ENXIO;
406*2926Swnj 		return;
40722Sbill 	}
408*2926Swnj 	a = u.u_offset >> 9;
409*2926Swnj 	sc = &ht_softc[unit];
410*2926Swnj 	sc->sc_blkno = dbtofsb(a);
411*2926Swnj 	sc->sc_nxrec = dbtofsb(a)+1;
41222Sbill }
4131917Swnj 
414*2926Swnj /*ARGSUSED*/
415*2926Swnj htioctl(dev, cmd, addr, flag)
416*2926Swnj 	dev_t dev;
417*2926Swnj 	int cmd;
418*2926Swnj 	caddr_t addr;
419*2926Swnj 	int flag;
420*2926Swnj {
421*2926Swnj 	register unit = HTUNIT(dev);
422*2926Swnj 	register struct ht_softc *sc = &ht_softc[unit];
423*2926Swnj 	register struct buf *bp = &chtbuf[unit];
424*2926Swnj 	register callcount;
425*2926Swnj 	int fcount;
426*2926Swnj 	struct mtop mtop;
427*2926Swnj 	struct mtget mtget;
428*2926Swnj 	/* we depend of the values and order of the MT codes here */
429*2926Swnj 	static htops[] =
430*2926Swnj    {HT_WEOF,HT_SFORW,HT_SREV,HT_SFORW,HT_SREV,HT_REW,HT_REWOFFL,HT_SENSE};
4311917Swnj 
432*2926Swnj 	switch (cmd) {
433*2926Swnj 		case MTIOCTOP:	/* tape operation */
434*2926Swnj 		if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
435*2926Swnj 			u.u_error = EFAULT;
436*2926Swnj 			return;
437*2926Swnj 		}
438*2926Swnj 		switch(mtop.mt_op) {
439*2926Swnj 		case MTWEOF:
440*2926Swnj 			callcount = mtop.mt_count;
441*2926Swnj 			fcount = 1;
442*2926Swnj 			break;
443*2926Swnj 		case MTFSF: case MTBSF:
444*2926Swnj 			callcount = mtop.mt_count;
445*2926Swnj 			fcount = INF;
446*2926Swnj 			break;
447*2926Swnj 		case MTFSR: case MTBSR:
448*2926Swnj 			callcount = 1;
449*2926Swnj 			fcount = mtop.mt_count;
450*2926Swnj 			break;
451*2926Swnj 		case MTREW: case MTOFFL:
452*2926Swnj 			callcount = 1;
453*2926Swnj 			fcount = 1;
454*2926Swnj 			break;
455*2926Swnj 		default:
456*2926Swnj 			u.u_error = ENXIO;
457*2926Swnj 			return;
458*2926Swnj 		}
459*2926Swnj 		if (callcount <= 0 || fcount <= 0) {
460*2926Swnj 			u.u_error = ENXIO;
461*2926Swnj 			return;
462*2926Swnj 		}
463*2926Swnj 		while (--callcount >= 0) {
464*2926Swnj 			htcommand(dev, htops[mtop.mt_op], fcount);
465*2926Swnj 			if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
466*2926Swnj 			    bp->b_resid) {
467*2926Swnj 				u.u_error = EIO;
468*2926Swnj 				break;
469*2926Swnj 			}
470*2926Swnj 			if ((chtbuf[HTUNIT(bp->b_dev)].b_flags&B_ERROR) ||
471*2926Swnj 			    sc->sc_dsreg&HTDS_BOT)
472*2926Swnj 				break;
473*2926Swnj 		}
474*2926Swnj 		geterror(bp);
475*2926Swnj 		return;
476*2926Swnj 	case MTIOCGET:
477*2926Swnj 		mtget.mt_dsreg = sc->sc_dsreg;
478*2926Swnj 		mtget.mt_erreg = sc->sc_erreg;
479*2926Swnj 		mtget.mt_resid = sc->sc_resid;
480*2926Swnj 		if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
481*2926Swnj 			u.u_error = EFAULT;
482*2926Swnj 		return;
483*2926Swnj 	default:
484*2926Swnj 		u.u_error = ENXIO;
485*2926Swnj 	}
486*2926Swnj }
487*2926Swnj 
4881917Swnj #define	DBSIZE	20
4891917Swnj 
490*2926Swnj htdump()
4911917Swnj {
492*2926Swnj 	register struct mba_info *mi;
493*2926Swnj 	register struct mba_regs *mp;
494*2926Swnj 	register struct htdevice *htaddr;
495*2926Swnj 	int blk, num;
496*2926Swnj 	int start;
4971917Swnj 
498*2926Swnj 	start = 0;
499*2926Swnj 	num = maxfree;
500*2926Swnj #define	phys(a,b)		((b)((int)(a)&0x7fffffff))
501*2926Swnj 	if (htinfo[0] == 0)
502*2926Swnj 		return (ENXIO);
503*2926Swnj 	mi = phys(htinfo[0], struct mba_info *);
504*2926Swnj 	mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba;
505*2926Swnj #if VAX780
506*2926Swnj 	mbainit(mp);
507*2926Swnj 	htaddr = (struct htdevice *)&mp->mba_drv[mi->mi_drive];
508*2926Swnj 	htaddr->httc = HTTC_PDP11|HTTC_1600BPI;
509*2926Swnj 	htaddr->htcs1 = HT_DCLR|HT_GO;
5101917Swnj 	while (num > 0) {
5111917Swnj 		blk = num > DBSIZE ? DBSIZE : num;
512*2926Swnj 		htdwrite(start, blk, htaddr, mp);
513*2926Swnj 		start += blk;
5141917Swnj 		num -= blk;
5151917Swnj 	}
516*2926Swnj 	htwait(htaddr);
517*2926Swnj 	htaddr->htcs1 = HT_REW|HT_GO;
518*2926Swnj 	hteof(htaddr);
519*2926Swnj 	hteof(htaddr);
5201917Swnj }
5211917Swnj 
522*2926Swnj htdwrite(dbuf, num, htaddr, mp)
523*2926Swnj 	register dbuf, num;
524*2926Swnj 	register struct htdevice *htaddr;
525*2926Swnj 	struct mba_regs *mp;
5261917Swnj {
527*2926Swnj 	register struct pte *io;
5281917Swnj 	register int i;
5291917Swnj 
530*2926Swnj 	htwait(htaddr);
531*2926Swnj 	io = mp->mba_map;
5321917Swnj 	for (i = 0; i < num; i++)
533*2926Swnj 		*(int *)io++ = dbuf++ | PG_V;
534*2926Swnj 	htaddr->htfc = -(num*NBPG);
535*2926Swnj 	mp->mba_sr = -1;
536*2926Swnj 	mp->mba_bcr = -(num*NBPG);
537*2926Swnj 	mp->mba_var = 0;
538*2926Swnj 	htaddr->htcs1 = HT_WCOM|HT_GO;
5391917Swnj }
5401917Swnj 
541*2926Swnj htwait(htaddr)
542*2926Swnj 	struct htdevice *htaddr;
5431917Swnj {
5441917Swnj 	register s;
5451917Swnj 
5461917Swnj 	do
547*2926Swnj 		s = htaddr->htds;
548*2926Swnj 	while ((s & HTDS_DRY) == 0);
5491917Swnj }
5501917Swnj 
551*2926Swnj hteof(htaddr)
552*2926Swnj 	struct htdevice *htaddr;
5531917Swnj {
5541917Swnj 
555*2926Swnj 	htwait(htaddr);
556*2926Swnj 	htaddr->htcs1 = HT_WEOF|HT_GO;
5571917Swnj }
5581563Sbill #endif
559