xref: /csrg-svn/sys/vax/mba/mt.c (revision 4736)
1*4736Swnj /*	mt.c	4.1	81/11/04	*/
2*4736Swnj 
3*4736Swnj #include "mu.h"
4*4736Swnj #if NMT > 0
5*4736Swnj /*
6*4736Swnj  * TM78/TU78 tape driver
7*4736Swnj  *
8*4736Swnj  *	Behavior in complex error situations is uncertain...
9*4736Swnj  *
10*4736Swnj  * TODO:
11*4736Swnj  *	test error recovery
12*4736Swnj  *	add odd byte count kludge from VMS driver
13*4736Swnj  *	write dump routine
14*4736Swnj  */
15*4736Swnj #include "../h/param.h"
16*4736Swnj #include "../h/systm.h"
17*4736Swnj #include "../h/buf.h"
18*4736Swnj #include "../h/conf.h"
19*4736Swnj #include "../h/dir.h"
20*4736Swnj #include "../h/file.h"
21*4736Swnj #include "../h/user.h"
22*4736Swnj #include "../h/map.h"
23*4736Swnj #include "../h/pte.h"
24*4736Swnj #include "../h/mbareg.h"
25*4736Swnj #include "../h/mbavar.h"
26*4736Swnj #include "../h/mtio.h"
27*4736Swnj #include "../h/ioctl.h"
28*4736Swnj #include "../h/cmap.h"
29*4736Swnj #include "../h/cpu.h"
30*4736Swnj 
31*4736Swnj #include "../h/mtreg.h"
32*4736Swnj 
33*4736Swnj struct	buf	rmtbuf[NMT];
34*4736Swnj struct	buf	cmtbuf[NMT];
35*4736Swnj 
36*4736Swnj short	mttypes[] =
37*4736Swnj 	{ MBDT_TU78, 0 };
38*4736Swnj struct	mba_device *mtinfo[NMT];
39*4736Swnj int	mtattach(), mtslave(), mtustart(), mtstart(), mtndtint(), mtdtint();
40*4736Swnj struct	mba_driver mtdriver =
41*4736Swnj     { mtattach, mtslave, mtustart, mtstart, mtdtint, mtndtint,
42*4736Swnj       mttypes, "mt", "mu", mtinfo };
43*4736Swnj 
44*4736Swnj #define MASKREG(r)	((r) & 0xffff)
45*4736Swnj 
46*4736Swnj /* bits in minor device */
47*4736Swnj #define	MUUNIT(dev)	(minor(dev)&03)
48*4736Swnj #define	H_NOREWIND	04
49*4736Swnj #define	H_6250BPI	08
50*4736Swnj 
51*4736Swnj #define MTUNIT(dev)	(mutomt[MUUNIT(dev)])
52*4736Swnj 
53*4736Swnj #define	INF	(daddr_t)1000000L	/* a block number that wont exist */
54*4736Swnj 
55*4736Swnj struct	mu_softc {
56*4736Swnj 	char	sc_openf;
57*4736Swnj 	char	sc_flags;
58*4736Swnj 	daddr_t	sc_blkno;
59*4736Swnj 	daddr_t	sc_nxrec;
60*4736Swnj 	u_short	sc_erreg;
61*4736Swnj 	u_short	sc_dsreg;
62*4736Swnj 	short	sc_resid;
63*4736Swnj 	short	sc_dens;
64*4736Swnj 	struct	mba_device *sc_mi;
65*4736Swnj 	int	sc_slave;
66*4736Swnj } mu_softc[NMU];
67*4736Swnj short	mutomt[NMU];
68*4736Swnj 
69*4736Swnj /*
70*4736Swnj  * Bits for sc_flags.
71*4736Swnj  */
72*4736Swnj #define	H_WRITTEN 1	/* last operation was a write */
73*4736Swnj 
74*4736Swnj char	mtds_bits[] = MTDS_BITS;
75*4736Swnj 
76*4736Swnj /*ARGSUSED*/
77*4736Swnj mtattach(mi)
78*4736Swnj 	struct mba_device *mi;
79*4736Swnj {
80*4736Swnj 
81*4736Swnj }
82*4736Swnj 
83*4736Swnj mtslave(mi, ms)
84*4736Swnj 	struct mba_device *mi;
85*4736Swnj 	struct mba_slave *ms;
86*4736Swnj {
87*4736Swnj 	register struct mu_softc *sc = &mu_softc[ms->ms_unit];
88*4736Swnj 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
89*4736Swnj 	int s = spl7(), rtn = 0;
90*4736Swnj 
91*4736Swnj 	mtaddr->mtas = -1;
92*4736Swnj 	mtaddr->mtncs[ms->ms_slave] = MT_SENSE|MT_GO;
93*4736Swnj 	while (mtaddr->mtas == 0)
94*4736Swnj 		;
95*4736Swnj 	if ((mtaddr->mtner & MTER_INTCODE) == MTER_DONE &&
96*4736Swnj 	    (mtaddr->mtds & MTDS_PRES)) {
97*4736Swnj 		sc->sc_mi = mi;
98*4736Swnj 		sc->sc_slave = ms->ms_slave;
99*4736Swnj 		mutomt[ms->ms_unit] = mi->mi_unit;
100*4736Swnj 		rtn = 1;
101*4736Swnj 	}
102*4736Swnj 	mtaddr->mtas = mtaddr->mtas;
103*4736Swnj 	splx(s);
104*4736Swnj 	return (rtn);
105*4736Swnj }
106*4736Swnj 
107*4736Swnj mtopen(dev, flag)
108*4736Swnj 	dev_t dev;
109*4736Swnj 	int flag;
110*4736Swnj {
111*4736Swnj 	register int muunit;
112*4736Swnj 	register struct mba_device *mi;
113*4736Swnj 	register struct mu_softc *sc;
114*4736Swnj 	int olddens, dens;
115*4736Swnj 
116*4736Swnj 	muunit = MUUNIT(dev);
117*4736Swnj 	if (muunit >= NMU || (sc = &mu_softc[muunit])->sc_openf ||
118*4736Swnj 	    (mi = mtinfo[MTUNIT(dev)]) == 0 || mi->mi_alive == 0) {
119*4736Swnj 		u.u_error = ENXIO;
120*4736Swnj 		return;
121*4736Swnj 	}
122*4736Swnj 	olddens = sc->sc_dens;
123*4736Swnj 	dens = sc->sc_dens = (minor(dev)&H_6250BPI) ? MT_GCR : 0;
124*4736Swnj 	mtcommand(dev, MT_SENSE, 1);
125*4736Swnj 	sc->sc_dens = olddens;
126*4736Swnj 	if ((sc->sc_dsreg & MTDS_ONL) == 0) {
127*4736Swnj 		uprintf("mu%d: not online\n", muunit);
128*4736Swnj 		u.u_error = EIO;
129*4736Swnj 		return;
130*4736Swnj 	}
131*4736Swnj 	if ((flag&FWRITE) && (sc->sc_dsreg&MTDS_FPT)) {
132*4736Swnj 		uprintf("mu%d: no write ring\n", muunit);
133*4736Swnj 		u.u_error = EIO;
134*4736Swnj 		return;
135*4736Swnj 	}
136*4736Swnj 	if ((sc->sc_dsreg & MTDS_BOT) == 0 && (flag&FWRITE) &&
137*4736Swnj 	    dens != sc->sc_dens) {
138*4736Swnj 		uprintf("mu%d: can't change density in mid-tape\n", muunit);
139*4736Swnj 		u.u_error = EIO;
140*4736Swnj 		return;
141*4736Swnj 	}
142*4736Swnj 	sc->sc_openf = 1;
143*4736Swnj 	sc->sc_blkno = (daddr_t)0;
144*4736Swnj 	sc->sc_nxrec = INF;
145*4736Swnj 	sc->sc_flags = 0;
146*4736Swnj 	sc->sc_dens = dens;
147*4736Swnj }
148*4736Swnj 
149*4736Swnj mtclose(dev, flag)
150*4736Swnj 	register dev_t dev;
151*4736Swnj 	register flag;
152*4736Swnj {
153*4736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
154*4736Swnj 
155*4736Swnj 	if (flag == FWRITE || ((flag&FWRITE) && (sc->sc_flags&H_WRITTEN)))
156*4736Swnj 		mtcommand(dev, MT_CLS|sc->sc_dens, 1);
157*4736Swnj 	if ((minor(dev)&H_NOREWIND) == 0)
158*4736Swnj 		mtcommand(dev, MT_REW, 0);
159*4736Swnj 	sc->sc_openf = 0;
160*4736Swnj }
161*4736Swnj 
162*4736Swnj mtcommand(dev, com, count)
163*4736Swnj 	dev_t dev;
164*4736Swnj 	int com, count;
165*4736Swnj {
166*4736Swnj 	register struct buf *bp;
167*4736Swnj 
168*4736Swnj 	bp = &cmtbuf[MTUNIT(dev)];
169*4736Swnj 	(void) spl5();
170*4736Swnj 	while (bp->b_flags&B_BUSY) {
171*4736Swnj 		if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE))
172*4736Swnj 			break;
173*4736Swnj 		bp->b_flags |= B_WANTED;
174*4736Swnj 		sleep((caddr_t)bp, PRIBIO);
175*4736Swnj 	}
176*4736Swnj 	bp->b_flags = B_BUSY|B_READ;
177*4736Swnj 	(void) spl0();
178*4736Swnj 	bp->b_dev = dev;
179*4736Swnj 	bp->b_command = com;
180*4736Swnj 	bp->b_repcnt = count;
181*4736Swnj 	bp->b_blkno = 0;
182*4736Swnj 	mtstrategy(bp);
183*4736Swnj 	if (count == 0)
184*4736Swnj 		return;
185*4736Swnj 	iowait(bp);
186*4736Swnj 	if (bp->b_flags&B_WANTED)
187*4736Swnj 		wakeup((caddr_t)bp);
188*4736Swnj 	bp->b_flags &= B_ERROR;
189*4736Swnj }
190*4736Swnj 
191*4736Swnj mtstrategy(bp)
192*4736Swnj 	register struct buf *bp;
193*4736Swnj {
194*4736Swnj 	register struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)];
195*4736Swnj 	register struct buf *dp;
196*4736Swnj 
197*4736Swnj 	bp->av_forw = NULL;
198*4736Swnj 	dp = &mi->mi_tab;
199*4736Swnj 	(void) spl5();
200*4736Swnj 	if (dp->b_actf == NULL)
201*4736Swnj 		dp->b_actf = bp;
202*4736Swnj 	else
203*4736Swnj 		dp->b_actl->av_forw = bp;
204*4736Swnj 	dp->b_actl = bp;
205*4736Swnj 	if (dp->b_active == 0)
206*4736Swnj 		mbustart(mi);
207*4736Swnj 	(void) spl0();
208*4736Swnj }
209*4736Swnj 
210*4736Swnj mtustart(mi)
211*4736Swnj 	register struct mba_device *mi;
212*4736Swnj {
213*4736Swnj 	register struct mtdevice *mtaddr =
214*4736Swnj 	    (struct mtdevice *)mi->mi_drv;
215*4736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
216*4736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
217*4736Swnj 	daddr_t blkno;
218*4736Swnj 
219*4736Swnj 	sc->sc_flags &= ~H_WRITTEN;
220*4736Swnj 	if (sc->sc_openf < 0) {
221*4736Swnj 		bp->b_flags |= B_ERROR;
222*4736Swnj 		return (MBU_NEXT);
223*4736Swnj 	}
224*4736Swnj 	if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) {
225*4736Swnj 		if (dbtofsb(bp->b_blkno) > sc->sc_nxrec) {
226*4736Swnj 			bp->b_flags |= B_ERROR;
227*4736Swnj 			bp->b_error = ENXIO;
228*4736Swnj 			return (MBU_NEXT);
229*4736Swnj 		}
230*4736Swnj 		if (dbtofsb(bp->b_blkno) == sc->sc_nxrec &&
231*4736Swnj 		    bp->b_flags&B_READ) {
232*4736Swnj 			bp->b_resid = bp->b_bcount;
233*4736Swnj 			clrbuf(bp);
234*4736Swnj 			return (MBU_NEXT);
235*4736Swnj 		}
236*4736Swnj 		if ((bp->b_flags&B_READ)==0)
237*4736Swnj 			sc->sc_nxrec = dbtofsb(bp->b_blkno) + 1;
238*4736Swnj 	} else {
239*4736Swnj 		mtaddr->mtncs[MUUNIT(bp->b_dev)] =
240*4736Swnj 			(bp->b_repcnt<<8)|bp->b_command|MT_GO;
241*4736Swnj 		return (MBU_STARTED);
242*4736Swnj 	}
243*4736Swnj 	if ((blkno = sc->sc_blkno) == dbtofsb(bp->b_blkno)) {
244*4736Swnj 		if (mi->mi_tab.b_errcnt == 2) {
245*4736Swnj 			mtaddr->mtca = MUUNIT(bp->b_dev);
246*4736Swnj 		} else {
247*4736Swnj 			mtaddr->mtbc = bp->b_bcount;
248*4736Swnj 			mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev);
249*4736Swnj 		}
250*4736Swnj 		return (MBU_DODATA);
251*4736Swnj 	}
252*4736Swnj 	if (blkno < dbtofsb(bp->b_blkno))
253*4736Swnj 		mtaddr->mtncs[MUUNIT(bp->b_dev)] =
254*4736Swnj 		  (min(dbtofsb(bp->b_blkno) - blkno, 0377)<<8)| MT_SFORW|MT_GO;
255*4736Swnj 	else
256*4736Swnj 		mtaddr->mtncs[MUUNIT(bp->b_dev)] =
257*4736Swnj 		  (min(blkno - dbtofsb(bp->b_blkno), 0377)<<8)| MT_SREV|MT_GO;
258*4736Swnj 	return (MBU_STARTED);
259*4736Swnj }
260*4736Swnj 
261*4736Swnj mtstart(mi)
262*4736Swnj 	register struct mba_device *mi;
263*4736Swnj {
264*4736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
265*4736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
266*4736Swnj 
267*4736Swnj 	if (bp->b_flags & B_READ)
268*4736Swnj 		if (mi->mi_tab.b_errcnt == 2)
269*4736Swnj 			return(MT_READREV|MT_GO);
270*4736Swnj 		else
271*4736Swnj 			return(MT_READ|MT_GO);
272*4736Swnj 	else
273*4736Swnj 		return(MT_WRITE|sc->sc_dens|MT_GO);
274*4736Swnj }
275*4736Swnj 
276*4736Swnj mtdtint(mi, mbsr)
277*4736Swnj 	register struct mba_device *mi;
278*4736Swnj 	int mbsr;
279*4736Swnj {
280*4736Swnj 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
281*4736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
282*4736Swnj 	register struct mu_softc *sc;
283*4736Swnj 
284*4736Swnj 	/* I'M NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */
285*4736Swnj 	if ((mtaddr->mtca&3) != MUUNIT(bp->b_dev)) {
286*4736Swnj 		printf("mt: wrong unit!\n");
287*4736Swnj 		mtaddr->mtca = MUUNIT(bp->b_dev);
288*4736Swnj 	}
289*4736Swnj 	sc = &mu_softc[MUUNIT(bp->b_dev)];
290*4736Swnj 	sc->sc_erreg = mtaddr->mter;
291*4736Swnj 	if((bp->b_flags & B_READ) == 0)
292*4736Swnj 		sc->sc_flags |= H_WRITTEN;
293*4736Swnj 	switch (sc->sc_erreg & MTER_INTCODE) {
294*4736Swnj 	case MTER_DONE:
295*4736Swnj 	case MTER_LONGREC:
296*4736Swnj 		if (mi->mi_tab.b_errcnt != 2)
297*4736Swnj 			sc->sc_blkno++;
298*4736Swnj 		bp->b_resid = 0;
299*4736Swnj 		break;
300*4736Swnj 
301*4736Swnj 	case MTER_NOTCAP:
302*4736Swnj 		printf("mu%d: blank tape\n", MUUNIT(bp->b_dev));
303*4736Swnj 		goto err;
304*4736Swnj 
305*4736Swnj 	case MTER_TM:
306*4736Swnj 	case MTER_EOT:
307*4736Swnj 		sc->sc_blkno++;
308*4736Swnj 	err:
309*4736Swnj 		bp->b_resid = bp->b_bcount;
310*4736Swnj 		sc->sc_nxrec = dbtofsb(bp->b_blkno);
311*4736Swnj 		break;
312*4736Swnj 
313*4736Swnj 	case MTER_SHRTREC:
314*4736Swnj 		sc->sc_blkno++;
315*4736Swnj 		if (bp != &rmtbuf[MTUNIT(bp->b_dev)])
316*4736Swnj 			bp->b_flags |= B_ERROR;
317*4736Swnj 		if (mi->mi_tab.b_errcnt == 2)
318*4736Swnj 			bp->b_bcount = bp->b_resid;	/* restore saved value */
319*4736Swnj 		bp->b_resid = bp->b_bcount - mtaddr->mtbc;
320*4736Swnj 		break;
321*4736Swnj 
322*4736Swnj 	case MTER_RDOPP:
323*4736Swnj 		mi->mi_tab.b_errcnt = 2;	/* indicate "read opposite" */
324*4736Swnj 		bp->b_resid = bp->b_bcount;	/* save it */
325*4736Swnj 		bp->b_bcount = mtaddr->mtbc;	/* use this instead */
326*4736Swnj 		return(MBD_RETRY);
327*4736Swnj 
328*4736Swnj 	case MTER_RETRY:
329*4736Swnj 		mi->mi_tab.b_errcnt = 1;	/* indicate simple retry */
330*4736Swnj 		return(MBD_RETRY);
331*4736Swnj 
332*4736Swnj 	case MTER_OFFLINE:
333*4736Swnj 		if (sc->sc_openf > 0) {
334*4736Swnj 			sc->sc_openf = -1;
335*4736Swnj 			printf("mu%d: offline\n", MUUNIT(bp->b_dev));
336*4736Swnj 		}
337*4736Swnj 		bp->b_flags |= B_ERROR;
338*4736Swnj 		break;
339*4736Swnj 
340*4736Swnj 	case MTER_FPT:
341*4736Swnj 		printf("mu%d: no write ring\n", MUUNIT(bp->b_dev));
342*4736Swnj 		bp->b_flags |= B_ERROR;
343*4736Swnj 		break;
344*4736Swnj 
345*4736Swnj 	default:
346*4736Swnj 		printf("mu%d: hard error bn%d mbsr=%b er=%x ds=%b\n",
347*4736Swnj 		    MUUNIT(bp->b_dev), bp->b_blkno,
348*4736Swnj 		    mbsr, mbsr_bits, sc->sc_erreg,
349*4736Swnj 		    sc->sc_dsreg, mtds_bits);
350*4736Swnj 		bp->b_flags |= B_ERROR;
351*4736Swnj 		mtaddr->mtid = MTID_CLR;		/* reset the TM78 */
352*4736Swnj 		DELAY(250);
353*4736Swnj 		while ((mtaddr->mtid & MTID_RDY) == 0)	/* wait for it */
354*4736Swnj 			;
355*4736Swnj 		return (MBD_DONE);
356*4736Swnj 	}
357*4736Swnj 	/* CHECK FOR MBA ERROR WHEN NO OTHER ERROR INDICATED? */
358*4736Swnj 	return (MBD_DONE);
359*4736Swnj }
360*4736Swnj 
361*4736Swnj mtndtint(mi)
362*4736Swnj 	register struct mba_device *mi;
363*4736Swnj {
364*4736Swnj 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
365*4736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
366*4736Swnj 	register struct mu_softc *sc;
367*4736Swnj 	int er, fc, unit;
368*4736Swnj 
369*4736Swnj 	unit = (mtaddr->mtner >> 8) & 3;
370*4736Swnj 	er = MASKREG(mtaddr->mtner);
371*4736Swnj 	/* WILL THIS OCCUR IF ANOTHER DRIVE COMES ONLINE? */
372*4736Swnj 	if (bp == 0 || unit != MUUNIT(bp->b_dev)) {	/* consistency check */
373*4736Swnj 		if ((er & MTER_INTCODE) != MTER_ONLINE)
374*4736Swnj 			printf("mt: unit %d random interrupt\n", unit);
375*4736Swnj 		return (MBN_SKIP);
376*4736Swnj 	}
377*4736Swnj 	if (bp == 0)
378*4736Swnj 		return (MBN_SKIP);
379*4736Swnj 	fc = (mtaddr->mtncs[unit] >> 8) & 0xff;
380*4736Swnj 	sc = &mu_softc[unit];
381*4736Swnj 	sc->sc_erreg = er;
382*4736Swnj 	sc->sc_resid = fc;
383*4736Swnj 	switch (er & MTER_INTCODE) {
384*4736Swnj 	case MTER_DONE:
385*4736Swnj 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) {
386*4736Swnj 	done:
387*4736Swnj 			if (bp->b_command == MT_SENSE)
388*4736Swnj 				sc->sc_dsreg = MASKREG(mtaddr->mtds);
389*4736Swnj 			bp->b_resid = fc;
390*4736Swnj 			return (MBN_DONE);
391*4736Swnj 		}
392*4736Swnj 		/* this is UGLY!  (but is it correct?) */
393*4736Swnj 		if ((fc = dbtofsb(bp->b_blkno) - sc->sc_blkno) < 0)
394*4736Swnj 			sc->sc_blkno -= min(0377, -fc);
395*4736Swnj 		else
396*4736Swnj 			sc->sc_blkno += min(0377, fc);
397*4736Swnj 		return (MBN_RETRY);
398*4736Swnj 
399*4736Swnj 	case MTER_RWDING:
400*4736Swnj 		return (MBN_SKIP);	/* ignore "rewind started" interrupt */
401*4736Swnj 
402*4736Swnj 	case MTER_NOTCAP:
403*4736Swnj 		printf("mu%d: blank tape\n", MUUNIT(bp->b_dev));
404*4736Swnj 
405*4736Swnj 	case MTER_TM:
406*4736Swnj 	case MTER_EOT:
407*4736Swnj 	case MTER_LEOT:
408*4736Swnj 		if (sc->sc_blkno > dbtofsb(bp->b_blkno)) {
409*4736Swnj 			sc->sc_nxrec = dbtofsb(bp->b_blkno) + fc;
410*4736Swnj 			sc->sc_blkno = sc->sc_nxrec;
411*4736Swnj 		} else {
412*4736Swnj 			sc->sc_blkno = dbtofsb(bp->b_blkno) - fc;
413*4736Swnj 			sc->sc_nxrec = sc->sc_blkno - 1;
414*4736Swnj 		}
415*4736Swnj 		return (MBN_RETRY);
416*4736Swnj 
417*4736Swnj 	case MTER_FPT:
418*4736Swnj 		printf("mu%d: no write ring\n", MUUNIT(bp->b_dev));
419*4736Swnj 		bp->b_flags |= B_ERROR;
420*4736Swnj 		return (MBN_DONE);
421*4736Swnj 
422*4736Swnj 	case MTER_OFFLINE:
423*4736Swnj 		if (sc->sc_openf > 0) {
424*4736Swnj 			sc->sc_openf = -1;
425*4736Swnj 			printf("mu%d: offline\n", MUUNIT(bp->b_dev));
426*4736Swnj 		}
427*4736Swnj 		bp->b_flags |= B_ERROR;
428*4736Swnj 		return (MBN_DONE);
429*4736Swnj 
430*4736Swnj 	case MTER_BOT:
431*4736Swnj 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)])
432*4736Swnj 			goto done;
433*4736Swnj 		/* FALL THROUGH */
434*4736Swnj 
435*4736Swnj 	default:
436*4736Swnj 		printf("mu%d: hard error bn%d er=%o ds=%b\n",
437*4736Swnj 		    MUUNIT(bp->b_dev), bp->b_blkno,
438*4736Swnj 		    sc->sc_erreg, sc->sc_dsreg, mtds_bits);
439*4736Swnj 		mtaddr->mtid = MTID_CLR;		/* reset the TM78 */
440*4736Swnj 		DELAY(250);
441*4736Swnj 		while ((mtaddr->mtid & MTID_RDY) == 0)	/* wait for it */
442*4736Swnj 			;
443*4736Swnj 		bp->b_flags |= B_ERROR;
444*4736Swnj 		return (MBN_DONE);
445*4736Swnj 	}
446*4736Swnj 	/* NOTREACHED */
447*4736Swnj }
448*4736Swnj 
449*4736Swnj mtread(dev)
450*4736Swnj 	dev_t dev;
451*4736Swnj {
452*4736Swnj 
453*4736Swnj 	mtphys(dev);
454*4736Swnj 	if (u.u_error)
455*4736Swnj 		return;
456*4736Swnj 	physio(mtstrategy, &rmtbuf[MTUNIT(dev)], dev, B_READ, minphys);
457*4736Swnj }
458*4736Swnj 
459*4736Swnj mtwrite(dev)
460*4736Swnj {
461*4736Swnj 
462*4736Swnj 	mtphys(dev);
463*4736Swnj 	if (u.u_error)
464*4736Swnj 		return;
465*4736Swnj 	physio(mtstrategy, &rmtbuf[MTUNIT(dev)], dev, B_WRITE, minphys);
466*4736Swnj }
467*4736Swnj 
468*4736Swnj mtphys(dev)
469*4736Swnj 	dev_t dev;
470*4736Swnj {
471*4736Swnj 	register int mtunit;
472*4736Swnj 	register struct mu_softc *sc;
473*4736Swnj 	register struct mba_device *mi;
474*4736Swnj 	daddr_t a;
475*4736Swnj 
476*4736Swnj 	mtunit = MTUNIT(dev);
477*4736Swnj 	if (mtunit >= NMT || (mi = mtinfo[mtunit]) == 0 || mi->mi_alive == 0) {
478*4736Swnj 		u.u_error = ENXIO;
479*4736Swnj 		return;
480*4736Swnj 	}
481*4736Swnj 	a = u.u_offset >> 9;
482*4736Swnj 	sc = &mu_softc[MUUNIT(dev)];
483*4736Swnj 	sc->sc_blkno = dbtofsb(a);
484*4736Swnj 	sc->sc_nxrec = dbtofsb(a)+1;
485*4736Swnj }
486*4736Swnj 
487*4736Swnj /*ARGSUSED*/
488*4736Swnj mtioctl(dev, cmd, addr, flag)
489*4736Swnj 	dev_t dev;
490*4736Swnj 	int cmd;
491*4736Swnj 	caddr_t addr;
492*4736Swnj 	int flag;
493*4736Swnj {
494*4736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
495*4736Swnj 	register struct buf *bp = &cmtbuf[MTUNIT(dev)];
496*4736Swnj 	register callcount;
497*4736Swnj 	register int n, op;
498*4736Swnj 	int fcount;
499*4736Swnj 	struct mtop mtop;
500*4736Swnj 	struct mtget mtget;
501*4736Swnj 	/* we depend of the values and order of the MT codes here */
502*4736Swnj 	static mtops[] =
503*4736Swnj 	{MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE};
504*4736Swnj 
505*4736Swnj 	switch (cmd) {
506*4736Swnj 		case MTIOCTOP:	/* tape operation */
507*4736Swnj 		if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
508*4736Swnj 			u.u_error = EFAULT;
509*4736Swnj 			return;
510*4736Swnj 		}
511*4736Swnj 		switch(mtop.mt_op) {
512*4736Swnj 		case MTWEOF:
513*4736Swnj 			callcount = mtop.mt_count;
514*4736Swnj 			fcount = 1;
515*4736Swnj 			break;
516*4736Swnj 		case MTFSF: case MTBSF:
517*4736Swnj 			callcount = mtop.mt_count;
518*4736Swnj 			fcount = 1;
519*4736Swnj 			break;
520*4736Swnj 		case MTFSR: case MTBSR:
521*4736Swnj 			callcount = 1;
522*4736Swnj 			fcount = mtop.mt_count;
523*4736Swnj 			break;
524*4736Swnj 		case MTREW: case MTOFFL:
525*4736Swnj 			callcount = 1;
526*4736Swnj 			fcount = 1;
527*4736Swnj 			break;
528*4736Swnj 		default:
529*4736Swnj 			u.u_error = ENXIO;
530*4736Swnj 			return;
531*4736Swnj 		}
532*4736Swnj 		if (callcount <= 0 || fcount <= 0) {
533*4736Swnj 			u.u_error = ENXIO;
534*4736Swnj 			return;
535*4736Swnj 		}
536*4736Swnj 		op = mtops[mtop.mt_op];
537*4736Swnj 		if (op == MT_WTM)
538*4736Swnj 			op |= sc->sc_dens;
539*4736Swnj 		while (--callcount >= 0) {
540*4736Swnj 			register int n;
541*4736Swnj 
542*4736Swnj 			do {
543*4736Swnj 				n = min(fcount, 0xff);
544*4736Swnj 				mtcommand(dev, op, n);
545*4736Swnj 				fcount -= n;
546*4736Swnj 			} while (fcount);
547*4736Swnj 			if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
548*4736Swnj 			    bp->b_resid) {
549*4736Swnj 				u.u_error = EIO;
550*4736Swnj 				break;
551*4736Swnj 			}
552*4736Swnj 			if (bp->b_flags&B_ERROR)
553*4736Swnj 				break;
554*4736Swnj 		}
555*4736Swnj 		geterror(bp);
556*4736Swnj 		return;
557*4736Swnj 	case MTIOCGET:
558*4736Swnj 		mtget.mt_erreg = sc->sc_erreg;
559*4736Swnj 		mtget.mt_resid = sc->sc_resid;
560*4736Swnj 		mtcommand(dev, MT_SENSE, 1);	/* update drive status */
561*4736Swnj 		mtget.mt_dsreg = sc->sc_dsreg;
562*4736Swnj 		mtget.mt_type = MT_ISMT;
563*4736Swnj 		if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
564*4736Swnj 			u.u_error = EFAULT;
565*4736Swnj 		return;
566*4736Swnj 	default:
567*4736Swnj 		u.u_error = ENXIO;
568*4736Swnj 	}
569*4736Swnj }
570*4736Swnj 
571*4736Swnj #define	DBSIZE	20
572*4736Swnj 
573*4736Swnj mtdump()
574*4736Swnj {
575*4736Swnj 	register struct mba_device *mi;
576*4736Swnj 	register struct mba_regs *mp;
577*4736Swnj 	register struct mtdevice *mtaddr;
578*4736Swnj 	int blk, num;
579*4736Swnj 	int start;
580*4736Swnj 
581*4736Swnj 	start = 0;
582*4736Swnj 	num = maxfree;
583*4736Swnj #define	phys(a,b)		((b)((int)(a)&0x7fffffff))
584*4736Swnj 	if (mtinfo[0] == 0)
585*4736Swnj 		return (ENXIO);
586*4736Swnj 	mi = phys(mtinfo[0], struct mba_device *);
587*4736Swnj 	mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba;
588*4736Swnj 	mp->mba_cr = MBCR_IE;
589*4736Swnj 	mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive];
590*4736Swnj #ifdef notyet
591*4736Swnj 	mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI;
592*4736Swnj 	mtaddr->mtcs1 = MT_DCLR|MT_GO;
593*4736Swnj 	while (num > 0) {
594*4736Swnj 		blk = num > DBSIZE ? DBSIZE : num;
595*4736Swnj 		mtdwrite(start, blk, mtaddr, mp);
596*4736Swnj 		start += blk;
597*4736Swnj 		num -= blk;
598*4736Swnj 	}
599*4736Swnj 	mteof(mtaddr);
600*4736Swnj 	mteof(mtaddr);
601*4736Swnj 	mtwait(mtaddr);
602*4736Swnj 	if (mtaddr->mtds&MTDS_ERR)
603*4736Swnj 		return (EIO);
604*4736Swnj 	mtaddr->mtcs1 = MT_REW|MT_GO;
605*4736Swnj 	return (0);
606*4736Swnj }
607*4736Swnj 
608*4736Swnj mtdwrite(dbuf, num, mtaddr, mp)
609*4736Swnj 	register dbuf, num;
610*4736Swnj 	register struct mtdevice *mtaddr;
611*4736Swnj 	struct mba_regs *mp;
612*4736Swnj {
613*4736Swnj 	register struct pte *io;
614*4736Swnj 	register int i;
615*4736Swnj 
616*4736Swnj 	mtwait(mtaddr);
617*4736Swnj 	io = mp->mba_map;
618*4736Swnj 	for (i = 0; i < num; i++)
619*4736Swnj 		*(int *)io++ = dbuf++ | PG_V;
620*4736Swnj 	mtaddr->mtfc = -(num*NBPG);
621*4736Swnj 	mp->mba_sr = -1;
622*4736Swnj 	mp->mba_bcr = -(num*NBPG);
623*4736Swnj 	mp->mba_var = 0;
624*4736Swnj 	mtaddr->mtcs1 = MT_WCOM|MT_GO;
625*4736Swnj }
626*4736Swnj 
627*4736Swnj mtwait(mtaddr)
628*4736Swnj 	struct mtdevice *mtaddr;
629*4736Swnj {
630*4736Swnj 	register s;
631*4736Swnj 
632*4736Swnj 	do
633*4736Swnj 		s = mtaddr->mtds;
634*4736Swnj 	while ((s & MTDS_DRY) == 0);
635*4736Swnj }
636*4736Swnj 
637*4736Swnj mteof(mtaddr)
638*4736Swnj 	struct mtdevice *mtaddr;
639*4736Swnj {
640*4736Swnj 
641*4736Swnj 	mtwait(mtaddr);
642*4736Swnj 	mtaddr->mtcs1 = MT_WEOF|MT_GO;
643*4736Swnj #endif notyet
644*4736Swnj }
645*4736Swnj #endif
646