xref: /csrg-svn/sys/vax/mba/mt.c (revision 34221)
123315Smckusick /*
229271Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323315Smckusick  * All rights reserved.  The Berkeley software License Agreement
423315Smckusick  * specifies the terms and conditions for redistribution.
523315Smckusick  *
6*34221Sbostic  *	@(#)mt.c	7.2 (Berkeley) 05/06/88
723315Smckusick  */
84736Swnj 
94736Swnj #include "mu.h"
104736Swnj #if NMT > 0
114736Swnj /*
124736Swnj  * TM78/TU78 tape driver
134736Swnj  *
1417214Smckusick  *	Original author - ?
1517214Smckusick  *	Most error recovery bug fixes - ggs (ulysses!ggs)
16*34221Sbostic  *	`read reverse' error recovery - ggs (ulysses!ggs)
174736Swnj  *
1817214Smckusick  * OPTIONS:
1917214Smckusick  *	MTLERRM - Long error message text - twd, Brown University
2017214Smckusick  *
214736Swnj  * TODO:
2217214Smckusick  *	Add odd byte count kludge from VMS driver (?)
2317214Smckusick  *	Write dump routine
244736Swnj  */
2517214Smckusick 
2617119Sbloom #include "param.h"
2717119Sbloom #include "systm.h"
2817119Sbloom #include "buf.h"
2917119Sbloom #include "conf.h"
3017119Sbloom #include "dir.h"
3117119Sbloom #include "file.h"
3217119Sbloom #include "user.h"
3317119Sbloom #include "map.h"
3417119Sbloom #include "ioctl.h"
3517119Sbloom #include "mtio.h"
3617119Sbloom #include "cmap.h"
3717119Sbloom #include "uio.h"
3818324Sralph #include "tty.h"
39*34221Sbostic #include "syslog.h"
404736Swnj 
41*34221Sbostic #include "../vax/pte.h"
428471Sroot #include "../vax/cpu.h"
4317119Sbloom #include "mbareg.h"
4417119Sbloom #include "mbavar.h"
4517119Sbloom #include "mtreg.h"
464736Swnj 
4717214Smckusick #define MTTIMEOUT	10000		/* loop limit for controller test */
4817214Smckusick #define	INF		1000000L	/* a block number that won't exist */
4917214Smckusick #define MASKREG(r)	((r) & 0xffff)	/* the control registers have 16 bits */
504736Swnj 
5117214Smckusick /* Bits for sc_flags */
524736Swnj 
5317214Smckusick #define	H_WRITTEN	01		/* last operation was a write */
5417214Smckusick #define H_EOT		02		/* end of tape encountered */
5517214Smckusick #define H_IEOT		04		/* ignore EOT condition */
564736Swnj 
57*34221Sbostic int	mt_do_readrev = 1;
5817214Smckusick 
5917214Smckusick /* Per unit status information */
6017214Smckusick 
614736Swnj struct	mu_softc {
62*34221Sbostic 	char	sc_openf;	/* unit is open if != 0 */
63*34221Sbostic 	char	sc_flags;	/* state flags */
64*34221Sbostic 	daddr_t	sc_blkno;	/* current physical block number */
65*34221Sbostic 	daddr_t	sc_nxrec;	/* firewall input block number */
66*34221Sbostic 	u_short	sc_erreg;	/* copy of mter or mtner */
67*34221Sbostic 	u_short	sc_dsreg;	/* copy of mtds */
68*34221Sbostic 	short	sc_resid;	/* residual function count for ioctl */
69*34221Sbostic 	short	sc_dens;	/* density code - MT_GCR or zero */
70*34221Sbostic 	int	sc_i_mtas;	/* mtas at slave attach time */
71*34221Sbostic 	int	sc_i_mtner;	/* mtner at slave attach time */
72*34221Sbostic 	int	sc_i_mtds;	/* mtds at slave attach time */
73*34221Sbostic 	struct	tty *sc_ttyp;	/* record user's tty for errors */
74*34221Sbostic 	int	sc_blks;	/* number of I/O operations since open */
75*34221Sbostic 	int	sc_softerrs;	/* number of soft I/O errors since open */
764736Swnj } mu_softc[NMU];
774736Swnj 
7817214Smckusick struct	buf	cmtbuf[NMT];		/* tape command buffer structures */
794736Swnj 
80*34221Sbostic struct	mba_device *mtinfo[NMT];	/* unit to ctlr structures */
81*34221Sbostic struct	mba_slave *muinfo[NMU];		/* unit to slave structures */
82*34221Sbostic 
8317214Smckusick char	mtds_bits[] = MTDS_BITS;	/* mtds bit names for error messages */
8417214Smckusick short	mttypes[] = { MBDT_TU78, 0 };
854736Swnj 
8617214Smckusick int	mtattach(), mtslave(), mtustart(), mtstart(), mtndtint(), mtdtint();
8717214Smckusick struct	mba_driver mtdriver =
8817214Smckusick 	{ mtattach, mtslave, mtustart, mtstart, mtdtint, mtndtint,
8917214Smckusick 	  mttypes, "mt", "mu", mtinfo };
9017214Smckusick 
91*34221Sbostic /* Bits in minor device */
92*34221Sbostic #define	MUUNIT(dev)	(minor(dev)&03)
93*34221Sbostic #define	H_NOREWIND	04
94*34221Sbostic #define	H_6250BPI	010
9517214Smckusick 
96*34221Sbostic #define MTUNIT(dev)	(muinfo[MUUNIT(dev)]->ms_ctlr)
97*34221Sbostic 
98*34221Sbostic void	mtcreset();
99*34221Sbostic 
1004736Swnj /*ARGSUSED*/
1014736Swnj mtattach(mi)
1024736Swnj 	struct mba_device *mi;
1034736Swnj {
104*34221Sbostic 
105*34221Sbostic 	/* void */
1064736Swnj }
1074736Swnj 
1087431Skre mtslave(mi, ms, sn)
1094736Swnj 	struct mba_device *mi;
1104736Swnj 	struct mba_slave *ms;
1117431Skre 	int sn;
1124736Swnj {
1134736Swnj 	register struct mu_softc *sc = &mu_softc[ms->ms_unit];
1144736Swnj 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
11526377Skarels 	int s = spl5(), rtn = 0, i;
1164736Swnj 
117*34221Sbostic 	/*
118*34221Sbostic 	 * Just in case the controller is ill, reset it.  Then issue
119*34221Sbostic 	 * a sense operation and wait about a second for it to respond.
120*34221Sbostic 	 */
12117214Smckusick 	mtcreset(mtaddr);
1224736Swnj 	mtaddr->mtas = -1;
1237431Skre 	mtaddr->mtncs[sn] = MT_SENSE|MT_GO;
124*34221Sbostic 	for (i = MTTIMEOUT; i > 0; i--) {
12517214Smckusick 		DELAY(50);
12617214Smckusick 		if (MASKREG(mtaddr->mtas) != 0)
12717214Smckusick 			break;
12817214Smckusick 	}
12917214Smckusick 	sc->sc_i_mtas = mtaddr->mtas;
13017214Smckusick 	sc->sc_i_mtner = mtaddr->mtner;
13117214Smckusick 	sc->sc_i_mtds = mtaddr->mtds;
13217214Smckusick 
133*34221Sbostic 	/*
134*34221Sbostic 	 * If no response, whimper.  If wrong response, call it an
135*34221Sbostic 	 * unsolicited interrupt and use mtndtint to log and correct.
136*34221Sbostic 	 * Otherwise, note whether this slave exists.
137*34221Sbostic 	 */
138*34221Sbostic 	if (i <= 0)
13917214Smckusick 		printf("mt: controller hung\n");
140*34221Sbostic 	else if ((mtaddr->mtner & MTER_INTCODE) != MTER_DONE)
14117214Smckusick 		(void) mtndtint(mi);
142*34221Sbostic 	else if (mtaddr->mtds & MTDS_PRES)
1434736Swnj 		rtn = 1;
14417214Smckusick 
145*34221Sbostic 	/* cancel the interrupt, then wait a little while for it to go away */
1464736Swnj 	mtaddr->mtas = mtaddr->mtas;
14717214Smckusick 	DELAY(10);
1484736Swnj 	splx(s);
1494736Swnj 	return (rtn);
1504736Swnj }
1514736Swnj 
1524736Swnj mtopen(dev, flag)
1534736Swnj 	dev_t dev;
1544736Swnj 	int flag;
1554736Swnj {
1564736Swnj 	register int muunit;
1574736Swnj 	register struct mu_softc *sc;
158*34221Sbostic 	register struct mba_slave *ms;
1594736Swnj 
1604736Swnj 	muunit = MUUNIT(dev);
161*34221Sbostic 	if (muunit >= NMU || (ms = muinfo[muunit]) == NULL ||
162*34221Sbostic 	    ms->ms_alive == 0 || mtinfo[ms->ms_ctlr]->mi_alive == 0)
1638581Sroot 		return (ENXIO);
16417214Smckusick 	if ((sc = &mu_softc[muunit])->sc_openf)
16517214Smckusick 		return (EBUSY);
166*34221Sbostic 	sc->sc_openf = 1;
16717214Smckusick 	sc->sc_dens = (minor(dev) & H_6250BPI) ? MT_GCR : 0;
1684736Swnj 	mtcommand(dev, MT_SENSE, 1);
1694736Swnj 	if ((sc->sc_dsreg & MTDS_ONL) == 0) {
1704736Swnj 		uprintf("mu%d: not online\n", muunit);
171*34221Sbostic 		sc->sc_openf = 0;
1728581Sroot 		return (EIO);
1734736Swnj 	}
17417214Smckusick 	if ((sc->sc_dsreg & MTDS_AVAIL) == 0) {
17517214Smckusick 		uprintf("mu%d: not online (port selector)\n", muunit);
176*34221Sbostic 		sc->sc_openf = 0;
17717214Smckusick 		return (EIO);
17817214Smckusick 	}
17917214Smckusick 	if ((flag & FWRITE) && (sc->sc_dsreg & MTDS_FPT)) {
1804736Swnj 		uprintf("mu%d: no write ring\n", muunit);
181*34221Sbostic 		sc->sc_openf = 0;
1828581Sroot 		return (EIO);
1834736Swnj 	}
184*34221Sbostic 	if ((sc->sc_dsreg & MTDS_BOT) == 0 && (flag & FWRITE) &&
185*34221Sbostic 	    (sc->sc_dens == MT_GCR) != ((sc->sc_dsreg & MTDS_PE) == 0)) {
1864736Swnj 		uprintf("mu%d: can't change density in mid-tape\n", muunit);
187*34221Sbostic 		sc->sc_openf = 0;
1888581Sroot 		return (EIO);
1894736Swnj 	}
1904736Swnj 	sc->sc_blkno = (daddr_t)0;
19117214Smckusick 
192*34221Sbostic 	/*
193*34221Sbostic 	 * Since cooked I/O may do a read-ahead before a write, trash
194*34221Sbostic 	 * on a tape can make the first write fail.  Suppress the first
195*34221Sbostic 	 * read-ahead unless definitely doing read-write.
196*34221Sbostic 	 */
197*34221Sbostic 	sc->sc_nxrec = ((flag & (FTRUNC | FWRITE)) == (FTRUNC | FWRITE)) ?
198*34221Sbostic 	    (daddr_t)0 : (daddr_t)INF;
1994736Swnj 	sc->sc_flags = 0;
200*34221Sbostic 	sc->sc_blks = 0;
201*34221Sbostic 	sc->sc_softerrs = 0;
20218324Sralph 	sc->sc_ttyp = u.u_ttyp;
2038581Sroot 	return (0);
2044736Swnj }
2054736Swnj 
2064736Swnj mtclose(dev, flag)
2074736Swnj 	register dev_t dev;
20817214Smckusick 	register int flag;
2094736Swnj {
2104736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
2114736Swnj 
212*34221Sbostic 	if ((flag & (FREAD | FWRITE)) == FWRITE ||
213*34221Sbostic 	    ((flag & FWRITE) && (sc->sc_flags & H_WRITTEN)))
2144736Swnj 		mtcommand(dev, MT_CLS|sc->sc_dens, 1);
21517214Smckusick 	if ((minor(dev) & H_NOREWIND) == 0)
2164736Swnj 		mtcommand(dev, MT_REW, 0);
217*34221Sbostic 	if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100)
218*34221Sbostic 		log(LOG_INFO, "mu%d: %d soft errors in %d blocks\n",
219*34221Sbostic 		    MUUNIT(dev), sc->sc_softerrs, sc->sc_blks);
2204736Swnj 	sc->sc_openf = 0;
2214736Swnj }
2224736Swnj 
2234736Swnj mtcommand(dev, com, count)
2244736Swnj 	dev_t dev;
2254736Swnj 	int com, count;
2264736Swnj {
2274736Swnj 	register struct buf *bp;
228*34221Sbostic 	int s;
2294736Swnj 
2304736Swnj 	bp = &cmtbuf[MTUNIT(dev)];
2315437Sroot 	s = spl5();
23217214Smckusick 	while (bp->b_flags & B_BUSY) {
233*34221Sbostic 		if (bp->b_repcnt == 0 && (bp->b_flags & B_DONE))
2344736Swnj 			break;
2354736Swnj 		bp->b_flags |= B_WANTED;
2364736Swnj 		sleep((caddr_t)bp, PRIBIO);
2374736Swnj 	}
2384736Swnj 	bp->b_flags = B_BUSY|B_READ;
2395437Sroot 	splx(s);
2404736Swnj 	bp->b_dev = dev;
2414736Swnj 	bp->b_command = com;
2424736Swnj 	bp->b_repcnt = count;
2434736Swnj 	bp->b_blkno = 0;
24417214Smckusick 	bp->b_error = 0;
2454736Swnj 	mtstrategy(bp);
2464736Swnj 	if (count == 0)
2474736Swnj 		return;
248*34221Sbostic 	biowait(bp);
24917214Smckusick 	if (bp->b_flags & B_WANTED)
2504736Swnj 		wakeup((caddr_t)bp);
2514736Swnj 	bp->b_flags &= B_ERROR;
2524736Swnj }
2534736Swnj 
2544736Swnj mtstrategy(bp)
2554736Swnj 	register struct buf *bp;
2564736Swnj {
2574736Swnj 	register struct buf *dp;
258*34221Sbostic 	struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)];
259*34221Sbostic 	int s;
2604736Swnj 
261*34221Sbostic 	/*
262*34221Sbostic 	 * If this is a data transfer operation, set the resid to a
263*34221Sbostic 	 * default value (EOF) to simplify getting it right during
264*34221Sbostic 	 * error recovery or bail out.
265*34221Sbostic 	 */
26617214Smckusick 	if (bp != &cmtbuf[MTUNIT(bp->b_dev)])
26717214Smckusick 		bp->b_resid = bp->b_bcount;
26817214Smckusick 
269*34221Sbostic 	/*
270*34221Sbostic 	 * Link this request onto the end of the queue for this
271*34221Sbostic 	 * controller, then start I/O if not already active.
272*34221Sbostic 	 */
2734736Swnj 	bp->av_forw = NULL;
2744736Swnj 	dp = &mi->mi_tab;
2755437Sroot 	s = spl5();
2764736Swnj 	if (dp->b_actf == NULL)
2774736Swnj 		dp->b_actf = bp;
2784736Swnj 	else
2794736Swnj 		dp->b_actl->av_forw = bp;
2804736Swnj 	dp->b_actl = bp;
2814736Swnj 	if (dp->b_active == 0)
2824736Swnj 		mbustart(mi);
2835437Sroot 	splx(s);
2844736Swnj }
2854736Swnj 
2864736Swnj mtustart(mi)
2874736Swnj 	register struct mba_device *mi;
2884736Swnj {
28917214Smckusick 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
2904736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
2914736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
2924736Swnj 	daddr_t blkno;
29326377Skarels 	int count;
2944736Swnj 
2954736Swnj 	if (sc->sc_openf < 0) {
2964736Swnj 		bp->b_flags |= B_ERROR;
2974736Swnj 		return (MBU_NEXT);
2984736Swnj 	}
2994736Swnj 	if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) {
300*34221Sbostic 		/*
301*34221Sbostic 		 * Data transfer.  If write at end of tape,
302*34221Sbostic 		 * signal "no space" unless suppressed
303*34221Sbostic 		 * by MTIOCIEOT.
304*34221Sbostic 		 */
305*34221Sbostic 		if ((sc->sc_flags & (H_EOT | H_IEOT)) == H_EOT &&
306*34221Sbostic 		    (bp->b_flags & B_READ) == 0) {
3074736Swnj 			bp->b_flags |= B_ERROR;
30817214Smckusick 			bp->b_error = ENOSPC;
3094736Swnj 			return (MBU_NEXT);
3104736Swnj 		}
31117214Smckusick 
312*34221Sbostic 		if (bp->b_flags & B_RAW) {
313*34221Sbostic 			/* raw transfer; never seek */
314*34221Sbostic 			sc->sc_blkno = bdbtofsb(bp->b_blkno);
315*34221Sbostic 			sc->sc_nxrec = sc->sc_blkno + 1;
316*34221Sbostic 		} else {
31717214Smckusick 			/* seek beyond end of file */
31817214Smckusick 			if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) {
31917214Smckusick 				bp->b_flags |= B_ERROR;
32017214Smckusick 				bp->b_error = ENXIO;
32117214Smckusick 				return (MBU_NEXT);
32217214Smckusick 			}
32317214Smckusick 
324*34221Sbostic 			/*
325*34221Sbostic 			 * This should be end of file, but the buffer
326*34221Sbostic 			 * system wants a one-block look-ahead.  Humor it.
327*34221Sbostic 			 */
328*34221Sbostic 			if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec &&
329*34221Sbostic 			    bp->b_flags & B_READ) {
330*34221Sbostic 				bp->b_resid = bp->b_bcount;
33117214Smckusick 				clrbuf(bp);
33217214Smckusick 				return (MBU_NEXT);
33317214Smckusick 			}
33417214Smckusick 
33517214Smckusick 			/* If writing, mark the next block invalid. */
33617214Smckusick 			if ((bp->b_flags & B_READ) == 0)
33717214Smckusick 				sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1;
3384736Swnj 		}
3394736Swnj 	} else {
34017214Smckusick 		/* It's a command, do it now. */
3414736Swnj 		mtaddr->mtncs[MUUNIT(bp->b_dev)] =
3424736Swnj 			(bp->b_repcnt<<8)|bp->b_command|MT_GO;
3434736Swnj 		return (MBU_STARTED);
3444736Swnj 	}
34517214Smckusick 
346*34221Sbostic 	/*
347*34221Sbostic 	 * If raw I/O, or if the tape is positioned correctly for
348*34221Sbostic 	 * cooked I/O, set the byte count, unit number and repeat count
349*34221Sbostic 	 * then tell the MASSBUS to proceed.  Note that a negative
350*34221Sbostic 	 * bcount tells mbstart to map the buffer for "read backwards".
351*34221Sbostic 	 */
352*34221Sbostic 	if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) {
3534736Swnj 		if (mi->mi_tab.b_errcnt == 2) {
354*34221Sbostic 			mtaddr->mtbc = -bp->b_bcount;
3554736Swnj 			mtaddr->mtca = MUUNIT(bp->b_dev);
3564736Swnj 		} else {
3574736Swnj 			mtaddr->mtbc = bp->b_bcount;
3584736Swnj 			mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev);
3594736Swnj 		}
3604736Swnj 		return (MBU_DODATA);
3614736Swnj 	}
36217214Smckusick 
36317214Smckusick 	/* Issue skip operations to position the next block for cooked I/O. */
36417214Smckusick 
3657380Ssam 	if (blkno < bdbtofsb(bp->b_blkno))
366*34221Sbostic 		count = bdbtofsb(bp->b_blkno) - blkno;
3674736Swnj 	else
368*34221Sbostic 		count = blkno - bdbtofsb(bp->b_blkno);
369*34221Sbostic 	if ((unsigned)count > 0377)
37026377Skarels 		count = 0377;
37126377Skarels 	mtaddr->mtncs[MUUNIT(bp->b_dev)] = count | MT_SFORW|MT_GO;
3724736Swnj 	return (MBU_STARTED);
3734736Swnj }
3744736Swnj 
3754736Swnj mtstart(mi)
3764736Swnj 	register struct mba_device *mi;
3774736Swnj {
3784736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
3794736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
3804736Swnj 
3814736Swnj 	if (bp->b_flags & B_READ)
3824736Swnj 		if (mi->mi_tab.b_errcnt == 2)
383*34221Sbostic 			return (MT_READREV|MT_GO);
3844736Swnj 		else
385*34221Sbostic 			return (MT_READ|MT_GO);
3864736Swnj 	else
387*34221Sbostic 		return (MT_WRITE|sc->sc_dens|MT_GO);
3884736Swnj }
3894736Swnj 
3904736Swnj mtdtint(mi, mbsr)
3914736Swnj 	register struct mba_device *mi;
3924736Swnj 	int mbsr;
3934736Swnj {
3944736Swnj 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
3954736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
3964736Swnj 	register struct mu_softc *sc;
39717214Smckusick 	register int er;
3984736Swnj 
39917214Smckusick 	/* I'M still NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */
40017214Smckusick 	if ((mtaddr->mtca & 3) != MUUNIT(bp->b_dev)) {
4014736Swnj 		printf("mt: wrong unit!\n");
4024736Swnj 		mtaddr->mtca = MUUNIT(bp->b_dev);
4034736Swnj 	}
40417214Smckusick 
40517214Smckusick 	er = MASKREG(mtaddr->mter);
4064736Swnj 	sc = &mu_softc[MUUNIT(bp->b_dev)];
40717214Smckusick 	sc->sc_erreg = er;
40817214Smckusick 	if (bp->b_flags & B_READ)
40917214Smckusick 		sc->sc_flags &= ~H_WRITTEN;
41017214Smckusick 	else
4114736Swnj 		sc->sc_flags |= H_WRITTEN;
41217214Smckusick 	switch (er & MTER_INTCODE) {
41317214Smckusick 
41417214Smckusick 	case MTER_EOT:
41517214Smckusick 		sc->sc_flags |= H_EOT;
41617214Smckusick 		/* fall into MTER_DONE */
41717214Smckusick 
4184736Swnj 	case MTER_DONE:
41917214Smckusick 		sc->sc_blkno++;
42017214Smckusick 		if (mi->mi_tab.b_errcnt == 2) {
42117214Smckusick 			bp->b_bcount = bp->b_resid;
42217214Smckusick 			bp->b_resid -= MASKREG(mtaddr->mtbc);
423*34221Sbostic 			if (bp->b_resid > 0 && (bp->b_flags & B_RAW) == 0)
42417214Smckusick 				bp->b_flags |= B_ERROR;
425*34221Sbostic 		} else
42617214Smckusick 			bp->b_resid = 0;
42717214Smckusick 		break;
42817214Smckusick 
42917214Smckusick 	case MTER_SHRTREC:
43017214Smckusick 		sc->sc_blkno++;
43117214Smckusick 		bp->b_bcount = bp->b_resid;
43217214Smckusick 		bp->b_resid -= MASKREG(mtaddr->mtbc);
433*34221Sbostic 		if ((bp->b_flags & B_RAW) == 0)
43417214Smckusick 			bp->b_flags |= B_ERROR;
43517214Smckusick 		break;
43617214Smckusick 
43717214Smckusick 	case MTER_RETRY:
438*34221Sbostic 		/*
439*34221Sbostic 		 * Simple re-try.  Since resid is always a copy of the
440*34221Sbostic 		 * original byte count, use it to restore the count.
441*34221Sbostic 		 */
44217214Smckusick 		mi->mi_tab.b_errcnt = 1;
44317214Smckusick 		bp->b_bcount = bp->b_resid;
444*34221Sbostic 		return (MBD_RETRY);
44517214Smckusick 
44617214Smckusick 	case MTER_RDOPP:
447*34221Sbostic 		/*
448*34221Sbostic 		 * The controller just decided to read it backwards.
449*34221Sbostic 		 * If the controller returns a byte count of zero,
450*34221Sbostic 		 * change it to 1, since zero encodes 65536, which
451*34221Sbostic 		 * isn't quite what we had in mind.  The byte count
452*34221Sbostic 		 * may be larger than the size of the input buffer, so
453*34221Sbostic 		 * limit the count to the buffer size.  After
454*34221Sbostic 		 * making the byte count reasonable, set bcount to the
455*34221Sbostic 		 * negative of the controller's version of the byte
456*34221Sbostic 		 * count so that the start address for the transfer is
457*34221Sbostic 		 * set up correctly.
458*34221Sbostic 		 */
45917214Smckusick 		if (mt_do_readrev) {
46017214Smckusick 			mi->mi_tab.b_errcnt = 2;
46117214Smckusick 			if ((bp->b_bcount = MASKREG(mtaddr->mtbc)) == 0)
46217214Smckusick 				bp->b_bcount = 1;
46317214Smckusick 			if (bp->b_bcount > bp->b_resid)
46417214Smckusick 				bp->b_bcount = bp->b_resid;
46517214Smckusick 			bp->b_bcount = -(bp->b_bcount);
46617214Smckusick 			return(MBD_RETRY);
46717214Smckusick 		} else if (MASKREG(mtaddr->mtbc) <= bp->b_resid) {
46817214Smckusick 			sc->sc_blkno++;
46917214Smckusick 			bp->b_bcount = bp->b_resid;
47017214Smckusick 			bp->b_resid -= MASKREG(mtaddr->mtbc);
47117214Smckusick 			bp->b_flags |= B_ERROR;
47217214Smckusick 			break;
47317214Smckusick 		}
47417214Smckusick 		bp->b_flags |= B_ERROR;
47517214Smckusick 		/* fall into MTER_LONGREC */
47617214Smckusick 
4774736Swnj 	case MTER_LONGREC:
47817214Smckusick 		sc->sc_blkno++;
47917214Smckusick 		bp->b_bcount = bp->b_resid;
4804736Swnj 		bp->b_resid = 0;
48117214Smckusick 		bp->b_error = ENOMEM;
48217214Smckusick 		bp->b_flags |= B_ERROR;
4834736Swnj 		break;
4844736Swnj 
4854736Swnj 	case MTER_NOTCAP:
4864736Swnj 		printf("mu%d: blank tape\n", MUUNIT(bp->b_dev));
4874736Swnj 		goto err;
4884736Swnj 
4894736Swnj 	case MTER_TM:
490*34221Sbostic 		/*
491*34221Sbostic 		 * End of file.  Since the default byte count has
492*34221Sbostic 		 * already been set, just count the block and proceed.
493*34221Sbostic 		 */
4944736Swnj 		sc->sc_blkno++;
4954736Swnj 	err:
496*34221Sbostic 		sc->sc_nxrec = bdbtofsb(bp->b_blkno);
4974736Swnj 		break;
4984736Swnj 
4994736Swnj 	case MTER_OFFLINE:
5004736Swnj 		if (sc->sc_openf > 0) {
5014736Swnj 			sc->sc_openf = -1;
502*34221Sbostic 			tprintf(sc->sc_ttyp, "mu%d: offline\n",
503*34221Sbostic 			    MUUNIT(bp->b_dev));
5044736Swnj 		}
5054736Swnj 		bp->b_flags |= B_ERROR;
5064736Swnj 		break;
5074736Swnj 
50817214Smckusick 	case MTER_NOTAVL:
50917214Smckusick 		if (sc->sc_openf > 0) {
51017214Smckusick 			sc->sc_openf = -1;
51118324Sralph 			tprintf(sc->sc_ttyp, "mu%d: offline (port selector)\n",
51218324Sralph 			    MUUNIT(bp->b_dev));
51317214Smckusick 		}
51417214Smckusick 		bp->b_flags |= B_ERROR;
51517214Smckusick 		break;
51617214Smckusick 
5174736Swnj 	case MTER_FPT:
518*34221Sbostic 		tprintf(sc->sc_ttyp, "mu%d: no write ring\n",
519*34221Sbostic 		    MUUNIT(bp->b_dev));
5204736Swnj 		bp->b_flags |= B_ERROR;
5214736Swnj 		break;
5224736Swnj 
52317214Smckusick 	case MTER_UNREAD:
52417214Smckusick 		sc->sc_blkno++;
52517214Smckusick 		bp->b_bcount = bp->b_resid;
52617214Smckusick 		bp->b_resid -= MIN(MASKREG(mtaddr->mtbc), bp->b_bcount);
52717214Smckusick 
528*34221Sbostic 		/* code 010 means a garbage record, nothing serious. */
529*34221Sbostic 		if ((er & MTER_FAILCODE) == (010 << MTER_FSHIFT)) {
530*34221Sbostic 			tprintf(sc->sc_ttyp,
531*34221Sbostic 			    "mu%d: rn=%d bn=%d unreadable record\n",
53217214Smckusick 			    MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno);
53317214Smckusick 			bp->b_flags |= B_ERROR;
53417214Smckusick 			break;
53517214Smckusick 		}
53617214Smckusick 
537*34221Sbostic 		/*
538*34221Sbostic 		 * Anything else might be a hardware problem,
539*34221Sbostic 		 * fall into the error report.
540*34221Sbostic 		 */
54117214Smckusick 
5424736Swnj 	default:
543*34221Sbostic 		/*
544*34221Sbostic 		 * The bits in sc->sc_dsreg are from the last sense
545*34221Sbostic 		 * command.  To get the most recent copy, you have to
546*34221Sbostic 		 * do a sense at interrupt level, which requires nested
547*34221Sbostic 		 * error processing.  This is a bit messy, so leave
548*34221Sbostic 		 * well enough alone.
549*34221Sbostic 		 */
550*34221Sbostic 		tprintf(sc->sc_ttyp, "\
551*34221Sbostic mu%d: hard error (data transfer) rn=%d bn=%d mbsr=%b er=0%o ds=%b\n",
55217214Smckusick 		    MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno,
55317214Smckusick 		    mbsr, mbsr_bits, er,
55417214Smckusick 		    MASKREG(sc->sc_dsreg), mtds_bits);
55517214Smckusick #ifdef MTLERRM
556*34221Sbostic 		mtintfail(er);
55717214Smckusick #endif
5584736Swnj 		bp->b_flags |= B_ERROR;
55917214Smckusick 
560*34221Sbostic 		/*
561*34221Sbostic 		 * The TM78 manual says to reset the controller after
562*34221Sbostic 		 * TM fault B or MASSBUS fault.
563*34221Sbostic 		 */
564*34221Sbostic 		if ((er & MTER_INTCODE) == MTER_TMFLTB ||
565*34221Sbostic 		    (er & MTER_INTCODE) == MTER_MBFLT)
56617214Smckusick 			mtcreset(mtaddr);
5674736Swnj 	}
56817214Smckusick 
569*34221Sbostic 	/*
570*34221Sbostic 	 * Just in case some strange error slipped through (drive off
571*34221Sbostic 	 * line during read-reverse error recovery comes to mind), make
572*34221Sbostic 	 * sure the byte count is reasonable.
573*34221Sbostic 	 */
57417214Smckusick 	if (bp->b_bcount < 0)
57517214Smckusick 		bp->b_bcount = bp->b_resid;
576*34221Sbostic 
577*34221Sbostic 	if ((bp->b_flags & B_ERROR) == 0) {
578*34221Sbostic 		/* this counts reverse reads as soft errors */
579*34221Sbostic 		sc->sc_blks++;
580*34221Sbostic 		if (mi->mi_tab.b_errcnt) /* alternatively, if == 1 */
581*34221Sbostic 			sc->sc_softerrs++;
582*34221Sbostic 	}
5834736Swnj 	return (MBD_DONE);
5844736Swnj }
5854736Swnj 
5864736Swnj mtndtint(mi)
5874736Swnj 	register struct mba_device *mi;
5884736Swnj {
5894736Swnj 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
5904736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
5914736Swnj 	register struct mu_softc *sc;
59217214Smckusick 	register int er, fc;
59317214Smckusick 	int unit;
5944736Swnj 
5954736Swnj 	unit = (mtaddr->mtner >> 8) & 3;
5964736Swnj 	er = MASKREG(mtaddr->mtner);
59717214Smckusick 	sc = &mu_softc[unit];
59817214Smckusick 	sc->sc_erreg = er;
59917214Smckusick 
60017214Smckusick 	/* Check for unsolicited interrupts. */
601*34221Sbostic 	if (bp == NULL || unit != MUUNIT(bp->b_dev)) {
602*34221Sbostic 		if ((er & MTER_INTCODE) == MTER_ONLINE)
603*34221Sbostic 			return (MBN_SKIP);
60417214Smckusick 
605*34221Sbostic 		printf("mu%d: stray intr (non data transfer) er=0%o ds=%b\n",
606*34221Sbostic 		    unit, er, MASKREG(sc->sc_dsreg), mtds_bits);
60717214Smckusick #ifdef MTLERRM
608*34221Sbostic 		mtintfail(er);
60917214Smckusick #endif
610*34221Sbostic 		if ((er & MTER_INTCODE) == MTER_TMFLTB ||
611*34221Sbostic 		    (er & MTER_INTCODE) == MTER_MBFLT) {
612*34221Sbostic 			/*
613*34221Sbostic 			 * Reset the controller, then set error status
614*34221Sbostic 			 * if there was anything active when the fault
615*34221Sbostic 			 * occurred.  This may shoot an innocent
616*34221Sbostic 			 * bystander, but it's better than letting
617*34221Sbostic 			 * an error slip through.
618*34221Sbostic 			 */
619*34221Sbostic 			mtcreset(mtaddr);
620*34221Sbostic 			if (bp != NULL) {
621*34221Sbostic 				bp->b_flags |= B_ERROR;
622*34221Sbostic 				return (MBN_DONE);
62317214Smckusick 			}
62417214Smckusick 		}
6254736Swnj 		return (MBN_SKIP);
6264736Swnj 	}
62717214Smckusick 
6284736Swnj 	fc = (mtaddr->mtncs[unit] >> 8) & 0xff;
6294736Swnj 	sc->sc_resid = fc;
63017214Smckusick 
631*34221Sbostic 	/*
632*34221Sbostic 	 * Clear the "written" flag after any operation that changes
633*34221Sbostic 	 * the position of the tape.
634*34221Sbostic 	 */
635*34221Sbostic 	if (bp != &cmtbuf[MTUNIT(bp->b_dev)] || bp->b_command != MT_SENSE)
63617214Smckusick 		sc->sc_flags &= ~H_WRITTEN;
63717214Smckusick 
6384736Swnj 	switch (er & MTER_INTCODE) {
63917214Smckusick 
64017214Smckusick 	case MTER_EOT:
64117214Smckusick 		sc->sc_flags |= H_EOT;
64217214Smckusick 		/* fall into MTER_DONE */
64317214Smckusick 
6444736Swnj 	case MTER_DONE:
64517214Smckusick 		/* If this is a command buffer, just update the status.	*/
6464736Swnj 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) {
6474736Swnj 	done:
6484736Swnj 			if (bp->b_command == MT_SENSE)
6494736Swnj 				sc->sc_dsreg = MASKREG(mtaddr->mtds);
6504736Swnj 			return (MBN_DONE);
6514736Swnj 		}
65217214Smckusick 
653*34221Sbostic 		/*
654*34221Sbostic 		 * It's not a command buffer, must be a cooked I/O
655*34221Sbostic 		 * skip operation (perhaps a shaky assumption, but it
656*34221Sbostic 		 * wasn't my idea).
657*34221Sbostic 		 */
6587380Ssam 		if ((fc = bdbtofsb(bp->b_blkno) - sc->sc_blkno) < 0)
6596186Ssam 			sc->sc_blkno -= MIN(0377, -fc);
6604736Swnj 		else
6616186Ssam 			sc->sc_blkno += MIN(0377, fc);
6624736Swnj 		return (MBN_RETRY);
6634736Swnj 
66417214Smckusick 	case MTER_ONLINE:		/* ddj -- shouldn't happen but did */
6654736Swnj 	case MTER_RWDING:
6664736Swnj 		return (MBN_SKIP);	/* ignore "rewind started" interrupt */
6674736Swnj 
6684736Swnj 	case MTER_NOTCAP:
66918324Sralph 		tprintf(sc->sc_ttyp, "mu%d: blank tape\n", MUUNIT(bp->b_dev));
67017214Smckusick 		bp->b_flags |= B_ERROR;
67117214Smckusick 		return (MBN_DONE);
6724736Swnj 
6734736Swnj 	case MTER_TM:
6744736Swnj 	case MTER_LEOT:
675*34221Sbostic 		/*
676*34221Sbostic 		 * For an ioctl skip operation, count a tape mark as
677*34221Sbostic 		 * a record.  If there's anything left to do, update
678*34221Sbostic 		 * the repeat count and re-start the command.
679*34221Sbostic 		 */
68017214Smckusick 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) {
68117214Smckusick 			if ((sc->sc_resid = bp->b_repcnt = fc - 1) == 0)
68217214Smckusick 				return (MBN_DONE);
68317214Smckusick 			else
68417214Smckusick 				return (MBN_RETRY);
6854736Swnj 		} else {
686*34221Sbostic 			/*
687*34221Sbostic 			 * Cooked I/O again.  Just update the books and
688*34221Sbostic 			 * wait for someone else to return end of file or
689*34221Sbostic 			 * complain about a bad seek.
690*34221Sbostic 			 */
691*34221Sbostic 			if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) {
692*34221Sbostic 				sc->sc_nxrec = bdbtofsb(bp->b_blkno) + fc - 1;
693*34221Sbostic 				sc->sc_blkno = sc->sc_nxrec;
694*34221Sbostic 			} else {
695*34221Sbostic 				sc->sc_nxrec = bdbtofsb(bp->b_blkno) - fc;
696*34221Sbostic 				sc->sc_blkno = sc->sc_nxrec + 1;
697*34221Sbostic 			}
6984736Swnj 		}
6994736Swnj 		return (MBN_RETRY);
7004736Swnj 
7014736Swnj 	case MTER_FPT:
702*34221Sbostic 		tprintf(sc->sc_ttyp, "mu%d: no write ring\n",
703*34221Sbostic 		    MUUNIT(bp->b_dev));
7044736Swnj 		bp->b_flags |= B_ERROR;
7054736Swnj 		return (MBN_DONE);
7064736Swnj 
7074736Swnj 	case MTER_OFFLINE:
70817214Smckusick 		/* If `off line' was intentional, don't complain. */
709*34221Sbostic 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)] &&
710*34221Sbostic 		    bp->b_command == MT_UNLOAD)
71117214Smckusick 			return(MBN_DONE);
7124736Swnj 		if (sc->sc_openf > 0) {
7134736Swnj 			sc->sc_openf = -1;
714*34221Sbostic 			tprintf(sc->sc_ttyp, "mu%d: offline\n",
715*34221Sbostic 			    MUUNIT(bp->b_dev));
7164736Swnj 		}
7174736Swnj 		bp->b_flags |= B_ERROR;
7184736Swnj 		return (MBN_DONE);
7194736Swnj 
72017214Smckusick 	case MTER_NOTAVL:
72117214Smckusick 		if (sc->sc_openf > 0) {
72217214Smckusick 			sc->sc_openf = -1;
723*34221Sbostic 			tprintf(sc->sc_ttyp, "mu%d: offline (port selector)\n",
724*34221Sbostic 			    MUUNIT(bp->b_dev));
72517214Smckusick 		}
72617214Smckusick 		bp->b_flags |= B_ERROR;
72717214Smckusick 		return (MBN_DONE);
72817214Smckusick 
7294736Swnj 	case MTER_BOT:
7304736Swnj 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)])
7314736Swnj 			goto done;
73217214Smckusick 		/* fall through */
73317214Smckusick 
7344736Swnj 	default:
735*34221Sbostic 		tprintf(sc->sc_ttyp, "\
736*34221Sbostic mu%d: hard error (non data transfer) rn=%d bn=%d er=0%o ds=%b\n",
73717214Smckusick 		    MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno,
73817214Smckusick 		    er, MASKREG(sc->sc_dsreg), mtds_bits);
73917214Smckusick #ifdef MTLERRM
740*34221Sbostic 		mtintfail(er);
74117214Smckusick #endif
742*34221Sbostic 		if ((er & MTER_INTCODE) == MTER_TMFLTB ||
743*34221Sbostic 		    (er & MTER_INTCODE) == MTER_MBFLT)
74417214Smckusick 			mtcreset(mtaddr);	/* reset the controller */
7454736Swnj 		bp->b_flags |= B_ERROR;
7464736Swnj 		return (MBN_DONE);
7474736Swnj 	}
7484736Swnj 	/* NOTREACHED */
7494736Swnj }
7504736Swnj 
751*34221Sbostic void
752*34221Sbostic mtcreset(mtaddr)
75317214Smckusick 	register struct mtdevice *mtaddr;
75417214Smckusick {
75517214Smckusick 	register int i;
75617214Smckusick 
75717214Smckusick 	mtaddr->mtid = MTID_CLR;		/* reset the TM78 */
75817214Smckusick 	DELAY(200);
75917214Smckusick 	for (i = MTTIMEOUT; i > 0; i--) {
76017214Smckusick 		DELAY(50);			/* don't nag */
76117214Smckusick 		if ((mtaddr->mtid & MTID_RDY) != 0)
76217214Smckusick 			return;			/* exit when ready */
76317214Smckusick 	}
76417214Smckusick 	printf("mt: controller hung\n");
76517214Smckusick }
76617214Smckusick 
7674736Swnj /*ARGSUSED*/
7687637Ssam mtioctl(dev, cmd, data, flag)
7694736Swnj 	dev_t dev;
7704736Swnj 	int cmd;
7717637Ssam 	caddr_t data;
7724736Swnj 	int flag;
7734736Swnj {
7744736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
7754736Swnj 	register struct buf *bp = &cmtbuf[MTUNIT(dev)];
77617214Smckusick 	register struct mtop *mtop;
77717214Smckusick 	register struct mtget *mtget;
77817214Smckusick 	int callcount, fcount;
77917214Smckusick 	int op;
78017214Smckusick 
78117214Smckusick 	/* We depend on the values and order of the MT codes here. */
78217214Smckusick 
7834736Swnj 	static mtops[] =
7844736Swnj 	{MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE};
7854736Swnj 
7864736Swnj 	switch (cmd) {
7877637Ssam 
78817214Smckusick 	/* tape operation */
78917214Smckusick 
79017214Smckusick 	case MTIOCTOP:
7918606Sroot 		mtop = (struct mtop *)data;
7928606Sroot 		switch (mtop->mt_op) {
7937637Ssam 
7944736Swnj 		case MTWEOF:
7957637Ssam 			callcount = mtop->mt_count;
7964736Swnj 			fcount = 1;
7974736Swnj 			break;
7987637Ssam 
7994736Swnj 		case MTFSF: case MTBSF:
8007637Ssam 			callcount = mtop->mt_count;
8014736Swnj 			fcount = 1;
8024736Swnj 			break;
8037637Ssam 
8044736Swnj 		case MTFSR: case MTBSR:
8054736Swnj 			callcount = 1;
8067637Ssam 			fcount = mtop->mt_count;
8074736Swnj 			break;
8087637Ssam 
8094736Swnj 		case MTREW: case MTOFFL:
8104736Swnj 			callcount = 1;
8114736Swnj 			fcount = 1;
8124736Swnj 			break;
8137637Ssam 
8144736Swnj 		default:
8158581Sroot 			return (ENXIO);
8164736Swnj 		}
817*34221Sbostic 		if (callcount <= 0 || fcount <= 0)
8188581Sroot 			return (EINVAL);
8197637Ssam 		op = mtops[mtop->mt_op];
8204736Swnj 		if (op == MT_WTM)
8214736Swnj 			op |= sc->sc_dens;
8224736Swnj 		while (--callcount >= 0) {
82317214Smckusick 			register int n, fc = fcount;
8244736Swnj 
8254736Swnj 			do {
82617214Smckusick 				n = MIN(fc, 0xff);
8274736Swnj 				mtcommand(dev, op, n);
82817214Smckusick 				n -= sc->sc_resid;
82917214Smckusick 				fc -= n;
83017214Smckusick 				switch (mtop->mt_op) {
83117214Smckusick 
83217214Smckusick 				case MTWEOF:
83317214Smckusick 					sc->sc_blkno += (daddr_t)n;
83417214Smckusick 					sc->sc_nxrec = sc->sc_blkno - 1;
83517214Smckusick 					break;
83617214Smckusick 
83717214Smckusick 				case MTOFFL:
83817214Smckusick 				case MTREW:
83917214Smckusick 				case MTFSF:
84017214Smckusick 					sc->sc_blkno = (daddr_t)0;
84117214Smckusick 					sc->sc_nxrec = (daddr_t)INF;
84217214Smckusick 					break;
84317214Smckusick 
84417214Smckusick 				case MTBSF:
84517214Smckusick 					if (sc->sc_resid) {
84617214Smckusick 						sc->sc_blkno = (daddr_t)0;
84717214Smckusick 						sc->sc_nxrec = (daddr_t)INF;
84817214Smckusick 					} else {
84917214Smckusick 						sc->sc_blkno = (daddr_t)(-1);
85017214Smckusick 						sc->sc_nxrec = (daddr_t)(-1);
85117214Smckusick 					}
85217214Smckusick 					break;
85317214Smckusick 
85417214Smckusick 				case MTFSR:
85517214Smckusick 					sc->sc_blkno += (daddr_t)n;
85617214Smckusick 					break;
85717214Smckusick 
85817214Smckusick 				case MTBSR:
85917214Smckusick 					sc->sc_blkno -= (daddr_t)n;
86017214Smckusick 					break;
86117214Smckusick 				}
86217214Smckusick 				if (sc->sc_resid)
86317214Smckusick 					break;
86417214Smckusick 			} while (fc);
86517214Smckusick 			if (fc) {
86617214Smckusick 				sc->sc_resid = callcount + fc;
867*34221Sbostic 				if (mtop->mt_op == MTFSR ||
868*34221Sbostic 				    mtop->mt_op == MTBSR)
86917214Smckusick 					return (EIO);
870*34221Sbostic 				break;
87117214Smckusick 			}
87217214Smckusick 			if (bp->b_flags & B_ERROR)
8734736Swnj 				break;
8744736Swnj 		}
8758712Sroot 		return (geterror(bp));
8767637Ssam 
87717214Smckusick 	/* tape status */
8784736Swnj 	case MTIOCGET:
8797637Ssam 		mtget = (struct mtget *)data;
8807637Ssam 		mtget->mt_erreg = sc->sc_erreg;
8817637Ssam 		mtget->mt_resid = sc->sc_resid;
8824736Swnj 		mtcommand(dev, MT_SENSE, 1);	/* update drive status */
8837637Ssam 		mtget->mt_dsreg = sc->sc_dsreg;
8847637Ssam 		mtget->mt_type = MT_ISMT;
8858581Sroot 		break;
8867637Ssam 
88717214Smckusick 	/* ignore EOT condition */
88817214Smckusick 	case MTIOCIEOT:
88917214Smckusick 		sc->sc_flags |= H_IEOT;
89017214Smckusick 		break;
89117214Smckusick 
89217214Smckusick 	/* enable EOT condition */
89317214Smckusick 	case MTIOCEEOT:
89417214Smckusick 		sc->sc_flags &= ~H_IEOT;
89517214Smckusick 		break;
89617214Smckusick 
8974736Swnj 	default:
8988581Sroot 		return (ENXIO);
8994736Swnj 	}
9008581Sroot 	return (0);
9014736Swnj }
9024736Swnj 
9034736Swnj #define	DBSIZE	20
9044736Swnj 
9054736Swnj mtdump()
9064736Swnj {
9074736Swnj 	register struct mba_device *mi;
9084736Swnj 	register struct mba_regs *mp;
9094736Swnj 	int blk, num;
9104736Swnj 	int start;
9114736Swnj 
9124736Swnj 	start = 0;
9134736Swnj 	num = maxfree;
9144736Swnj #define	phys(a,b)		((b)((int)(a)&0x7fffffff))
9154736Swnj 	if (mtinfo[0] == 0)
9164736Swnj 		return (ENXIO);
9174736Swnj 	mi = phys(mtinfo[0], struct mba_device *);
9184736Swnj 	mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba;
9194736Swnj 	mp->mba_cr = MBCR_IE;
9206186Ssam #if lint
9218606Sroot 	blk = 0; num = blk; start = num; blk = start;
9226186Ssam 	return (0);
9236186Ssam #endif
9246186Ssam #ifdef notyet
9254736Swnj 	mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive];
9264736Swnj 	mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI;
9274736Swnj 	mtaddr->mtcs1 = MT_DCLR|MT_GO;
9284736Swnj 	while (num > 0) {
9294736Swnj 		blk = num > DBSIZE ? DBSIZE : num;
9304736Swnj 		mtdwrite(start, blk, mtaddr, mp);
9314736Swnj 		start += blk;
9324736Swnj 		num -= blk;
9334736Swnj 	}
9344736Swnj 	mteof(mtaddr);
9354736Swnj 	mteof(mtaddr);
9364736Swnj 	mtwait(mtaddr);
9374736Swnj 	if (mtaddr->mtds&MTDS_ERR)
9384736Swnj 		return (EIO);
9394736Swnj 	mtaddr->mtcs1 = MT_REW|MT_GO;
9404736Swnj 	return (0);
9414736Swnj }
9424736Swnj 
9434736Swnj mtdwrite(dbuf, num, mtaddr, mp)
9444736Swnj 	register dbuf, num;
9454736Swnj 	register struct mtdevice *mtaddr;
9464736Swnj 	struct mba_regs *mp;
9474736Swnj {
9484736Swnj 	register struct pte *io;
9494736Swnj 	register int i;
9504736Swnj 
9514736Swnj 	mtwait(mtaddr);
9524736Swnj 	io = mp->mba_map;
9534736Swnj 	for (i = 0; i < num; i++)
9544736Swnj 		*(int *)io++ = dbuf++ | PG_V;
9554736Swnj 	mtaddr->mtfc = -(num*NBPG);
9564736Swnj 	mp->mba_sr = -1;
9574736Swnj 	mp->mba_bcr = -(num*NBPG);
9584736Swnj 	mp->mba_var = 0;
9594736Swnj 	mtaddr->mtcs1 = MT_WCOM|MT_GO;
9604736Swnj }
9614736Swnj 
9624736Swnj mtwait(mtaddr)
9634736Swnj 	struct mtdevice *mtaddr;
9644736Swnj {
9654736Swnj 	register s;
9664736Swnj 
9674736Swnj 	do
9684736Swnj 		s = mtaddr->mtds;
9694736Swnj 	while ((s & MTDS_DRY) == 0);
9704736Swnj }
9714736Swnj 
9724736Swnj mteof(mtaddr)
9734736Swnj 	struct mtdevice *mtaddr;
9744736Swnj {
9754736Swnj 
9764736Swnj 	mtwait(mtaddr);
9774736Swnj 	mtaddr->mtcs1 = MT_WEOF|MT_GO;
9784736Swnj #endif notyet
9794736Swnj }
98017214Smckusick 
98117214Smckusick #ifdef MTLERRM
982*34221Sbostic /*
983*34221Sbostic  * Failure messages for each failure code, per interrupt code.
984*34221Sbostic  * Each table ends with a code of -1 as a default.
985*34221Sbostic  */
986*34221Sbostic struct fmesg {
987*34221Sbostic 	int	f_code;
988*34221Sbostic 	char	*f_mesg;
989*34221Sbostic };
99017214Smckusick 
991*34221Sbostic static char unclass[] = "unclassified failure code";
99217214Smckusick 
993*34221Sbostic /* MTER_BOT */
994*34221Sbostic static struct fmesg botmsg[] = {
995*34221Sbostic 	01,	"tape was at BOT",
996*34221Sbostic 	02,	"BOT seen after tape started",
997*34221Sbostic 	03,	"ARA ID detected",
998*34221Sbostic 	-1,	unclass
999*34221Sbostic };
100017214Smckusick 
1001*34221Sbostic /* MTER_NOTRDY */
1002*34221Sbostic static struct fmesg notrdymsg[] = {
1003*34221Sbostic 	01,	"TU on-line but not ready",
1004*34221Sbostic 	02,	"fatal error has occurred",
1005*34221Sbostic 	03,	"access allowed by not really"
1006*34221Sbostic 	-1,	unclass
1007*34221Sbostic };
100817214Smckusick 
1009*34221Sbostic /* MTER_NOTCAP */
1010*34221Sbostic static struct fmesg notcapmsg[] = {
1011*34221Sbostic 	01,	"no record found within 25 feet",
1012*34221Sbostic 	02,	"ID burst neither PE nor GCR",
1013*34221Sbostic 	03,	"ARA ID not found",
1014*34221Sbostic 	04,	"no gap found after ID burst",
1015*34221Sbostic 	-1,	unclass
1016*34221Sbostic };
101717214Smckusick 
1018*34221Sbostic /* MTER_LONGREC */
1019*34221Sbostic static struct fmesg longrecmsg[] = {
1020*34221Sbostic 	00,	"extended sense data not found",
1021*34221Sbostic 	01,	"extended sense data updated",
1022*34221Sbostic 	-1,	unclass
1023*34221Sbostic };
102417214Smckusick 
1025*34221Sbostic /* MTER_UNREAD, MTER_ERROR, MTER_EOTERR, MTER_BADTAPE */
1026*34221Sbostic static struct fmesg code22msg[] = {
1027*34221Sbostic 	01,	"GCR write error",
1028*34221Sbostic 	02,	"GCR read error",
1029*34221Sbostic 	03,	"PE read error",
1030*34221Sbostic 	04,	"PE write error",
1031*34221Sbostic 	05,	"at least 1 bit set in ECCSTA",
1032*34221Sbostic 	06,	"PE write error",
1033*34221Sbostic 	07,	"GCR write error",
1034*34221Sbostic 	010,	"RSTAT contains bad code",
1035*34221Sbostic 	011,	"PE write error",
1036*34221Sbostic 	012,	"MASSBUS parity error",
1037*34221Sbostic 	013,	"invalid data transferred",
1038*34221Sbostic 	-1,	unclass
1039*34221Sbostic };
104017214Smckusick 
1041*34221Sbostic /* MTER_TMFLTA */
1042*34221Sbostic static struct fmesg tmfltamsg[] = {
1043*34221Sbostic 	01,	"illegal command code",
1044*34221Sbostic 	02,	"DT command issued when NDT command active",
1045*34221Sbostic 	03,	"WMC error",
1046*34221Sbostic 	04,	"RUN not received from MASSBUS controller",
1047*34221Sbostic 	05,	"mismatch in command read - function routine",
1048*34221Sbostic 	06,	"ECC ROM parity error",
1049*34221Sbostic 	07,	"XMC ROM parity error",
1050*34221Sbostic 	010,	"mismatch in command read - ID burst command",
1051*34221Sbostic 	011,	"mismatch in command read - verify ARA burst command",
1052*34221Sbostic 	012,	"mismatch in command read - verify ARA ID command",
1053*34221Sbostic 	013,	"mismatch in command read - verify gap command",
1054*34221Sbostic 	014,	"mismatch in command read - read id burst command",
1055*34221Sbostic 	015,	"mismatch in command read - verify ARA ID command",
1056*34221Sbostic 	016,	"mismatch in command read - verify gap command",
1057*34221Sbostic 	017,	"mismatch in command read - find gap command",
1058*34221Sbostic 	020,	"WMC LEFT failed to set",
1059*34221Sbostic 	021,	"XL PE set in INTSTA register",
1060*34221Sbostic 	022,	"XMC DONE did not set",
1061*34221Sbostic 	023,	"WMC ROM PE or RD PE set in WMCERR register",
1062*34221Sbostic 	-1,	unclass
1063*34221Sbostic };
106417214Smckusick 
1065*34221Sbostic /* MTER_TUFLTA */
1066*34221Sbostic static struct fmesg tufltamsg[] = {
1067*34221Sbostic 	01,	"TU status parity error",
1068*34221Sbostic 	02,	"TU command parity error",
1069*34221Sbostic 	03,	"rewinding tape went offline",
1070*34221Sbostic 	04,	"tape went not ready during DSE",
1071*34221Sbostic 	05,	"TU CMD status changed during DSE",
1072*34221Sbostic 	06,	"TU never came up to speed",
1073*34221Sbostic 	07,	"TU velocity changed",
1074*34221Sbostic 	010,	"TU CMD did not load correctly to start tape motion",
1075*34221Sbostic 	011,	"TU CMD did not load correctly to set drive density",
1076*34221Sbostic 	012,	"TU CMD did not load correctly to start tape motion to write BOT ID",
1077*34221Sbostic 	013,	"TU CMD did not load correctly to backup tape to BOT after failing to write BOT ID",
1078*34221Sbostic 	014,	"failed to write density ID burst",
1079*34221Sbostic 	015,	"failed to write ARA burst",
1080*34221Sbostic 	016,	"failed to write ARA ID",
1081*34221Sbostic 	017,	"ARA error bit set in MTA status B register",
1082*34221Sbostic 	021,	"could not find a gap after ID code was written correctly",
1083*34221Sbostic 	022,	"TU CMD did not load correctly to start tape motion to read ID burst",
1084*34221Sbostic 	023,	"timeout looking for BOT after detecting ARA ID burst",
1085*34221Sbostic 	024,	"failed to write tape mark",
1086*34221Sbostic 	025,	"tape never came up to speed while trying to reposition for retry of writing tape mark",
1087*34221Sbostic 	026,	"TU CMD did not load correctly to start tape motion in erase gap routine",
1088*34221Sbostic 	027,	"could not detect a gap in in erase gap routine",
1089*34221Sbostic 	030,	"could not detect a gap after writing record",
1090*34221Sbostic 	031,	"read path terminated before entire record was written",
1091*34221Sbostic 	032,	"could not find a gap after writing record and read path terminated early",
1092*34221Sbostic 	033,	"TU CMD did not load correctly to backup for retry of write tape mark",
1093*34221Sbostic 	034,	"TU velocity changed after up to speed while trying to reposition for retry of writing tape mark",
1094*34221Sbostic 	035,	"TU CMD did not load correctly to backup to retry a load of BOT ID",
1095*34221Sbostic 	036,	"timeout looking for BOT after failing to write BOT ID",
1096*34221Sbostic 	037,	"TU velocity changed while writing PE gap before starting to write record",
1097*34221Sbostic 	040,	"TU CMD did not load correctly to set PE tape density at start of write BOT ID burst",
1098*34221Sbostic 	041,	"TU CMD did not load correctly to set GCR tape density after writing Density ID",
1099*34221Sbostic 	042,	"TU CMD did not load correctly to set PE tape density at start of read from BOT",
1100*34221Sbostic 	043,	"TU CMD did not load correctly to set GCR tape density after reading a GCR Density ID burst",
1101*34221Sbostic };
110217214Smckusick 
1103*34221Sbostic /* MTER_TMFLTB */
1104*34221Sbostic static char inlinetest[] = "inline test failed";
1105*34221Sbostic static struct fmesg tmfltbmsg[] = {
1106*34221Sbostic 	00,	"RST0 interrupt occurred with TM RDY set",
1107*34221Sbostic 	01,	"power failed to interrupt",
1108*34221Sbostic 	02,	"unknown interrupt on channel 5.5",
1109*34221Sbostic 	03,	"unknown interrupt on channel 6.5",
1110*34221Sbostic 	04,	"unknown interrupt on channel 7",
1111*34221Sbostic 	05,	"unknown interrupt on channel 7.5",
1112*34221Sbostic 	06,	"CAS contention retry count expired",
1113*34221Sbostic 	07,	"CAS contention error not retryable",
1114*34221Sbostic 	010,	"queue error, could not find queue entry",
1115*34221Sbostic 	011,	"queue entry already full",
1116*34221Sbostic 	012,	"8085 ROM parity error",
1117*34221Sbostic 	013,	inlinetest,
1118*34221Sbostic 	013,	inlinetest,
1119*34221Sbostic 	014,	inlinetest,
1120*34221Sbostic 	015,	inlinetest,
1121*34221Sbostic 	016,	inlinetest,
1122*34221Sbostic 	017,	inlinetest,
1123*34221Sbostic 	020,	inlinetest,
1124*34221Sbostic 	021,	inlinetest,
1125*34221Sbostic 	022,	inlinetest,
1126*34221Sbostic 	023,	inlinetest,
1127*34221Sbostic 	024,	inlinetest,
1128*34221Sbostic 	025,	inlinetest,
1129*34221Sbostic 	026,	inlinetest,
1130*34221Sbostic 	027,	inlinetest,
1131*34221Sbostic 	030,	inlinetest,
1132*34221Sbostic 	031,	inlinetest,
1133*34221Sbostic 	032,	inlinetest,
1134*34221Sbostic 	033,	inlinetest,
1135*34221Sbostic 	034,	inlinetest,
1136*34221Sbostic 	035,	inlinetest,
1137*34221Sbostic 	036,	inlinetest,
1138*34221Sbostic 	037,	inlinetest,
1139*34221Sbostic 	040,	inlinetest,
1140*34221Sbostic 	041,	inlinetest,
1141*34221Sbostic 	042,	inlinetest,
1142*34221Sbostic 	043,	inlinetest,
1143*34221Sbostic 	044,	inlinetest,
1144*34221Sbostic 	045,	inlinetest
1145*34221Sbostic 	046,	inlinetest,
1146*34221Sbostic 	047,	inlinetest,
1147*34221Sbostic 	050,	inlinetest,
1148*34221Sbostic 	051,	inlinetest,
1149*34221Sbostic 	052,	inlinetest,
1150*34221Sbostic 	053,	inlinetest,
1151*34221Sbostic 	054,	inlinetest,
1152*34221Sbostic 	055,	inlinetest,
1153*34221Sbostic 	056,	inlinetest,
1154*34221Sbostic 	057,	inlinetest,
1155*34221Sbostic 	-1,	unclass
1156*34221Sbostic };
115717214Smckusick 
1158*34221Sbostic /* MTER_MBFLT */
1159*34221Sbostic static struct fmesg mbfltmsg[] = {
1160*34221Sbostic 	01,	"control bus parity error",
1161*34221Sbostic 	02,	"illegal register referenced",
1162*34221Sbostic 	-1,	unclass
1163*34221Sbostic };
116417214Smckusick 
1165*34221Sbostic /*
1166*34221Sbostic  * MTER_LEOT, MTER_RWDING, NTER_NOTAVL, MTER_NONEX, MTER_KEYFAIL,
1167*34221Sbostic  * and default: no failure message.
1168*34221Sbostic  */
1169*34221Sbostic static struct fmesg nullmsg[] = {
1170*34221Sbostic 	-1,	""
1171*34221Sbostic };
117217214Smckusick 
1173*34221Sbostic /*
1174*34221Sbostic  * Interrupt code table.
1175*34221Sbostic  */
1176*34221Sbostic static struct errmsg {
1177*34221Sbostic 	int	e_code;
1178*34221Sbostic 	char	*e_mesg;
1179*34221Sbostic 	struct	fmesg *e_fmesg;
1180*34221Sbostic } errmsg[] = {
1181*34221Sbostic 	MTER_BOT,	"unexpected BOT",	botmsg,
1182*34221Sbostic 	MTER_LEOT,	"unexpected LEOT",	nullmsg,
1183*34221Sbostic 	MTER_RWDING,	"tape rewinding",	nullmsg,
1184*34221Sbostic 	MTER_NOTRDY,	"drive not ready",	notrdymsg,
1185*34221Sbostic 	MTER_NOTAVL,	"drive not available",	nullmsg,
1186*34221Sbostic 	MTER_NONEX,	"unit does not exist",	nullmsg,
1187*34221Sbostic 	MTER_NOTCAP,	"not capable",		notcapmsg,
1188*34221Sbostic 	MTER_LONGREC,	"long record",		longrecmsg,
1189*34221Sbostic 	MTER_UNREAD,	"unreadable record",	code22msg,
1190*34221Sbostic 	MTER_ERROR,	"error",		code22msg,
1191*34221Sbostic 	MTER_EOTERR,	"EOT error",		code22msg,
1192*34221Sbostic 	MTER_BADTAPE,	"tape position lost",	code22msg,
1193*34221Sbostic 	MTER_TMFLTA,	"TM fault A",		tmfltamsg,
1194*34221Sbostic 	MTER_TUFLTA,	"TU fault A",		tufltamsg,
1195*34221Sbostic 	MTER_TMFLTB,	"TM fault B",		tmfltbmsg,
1196*34221Sbostic 	MTER_MBFLT,	"MB fault",		mbfltmsg,
1197*34221Sbostic 	MTER_KEYFAIL,	"keypad entry error",	nullmsg,
1198*34221Sbostic 	-1,		"unclassified error",	nullmsg
1199*34221Sbostic };
120017214Smckusick 
1201*34221Sbostic /*
1202*34221Sbostic  * Decode an interrupt-time failure.
1203*34221Sbostic  */
1204*34221Sbostic mtintfail(erreg)
1205*34221Sbostic 	int erreg;
1206*34221Sbostic {
1207*34221Sbostic 	register struct errmsg *e;
1208*34221Sbostic 	register struct fmesg *f;
1209*34221Sbostic 	register int ecode, fcode;
121017214Smckusick 
1211*34221Sbostic 	ecode = erreg & MTER_INTCODE;
1212*34221Sbostic 	fcode = (erreg & MTER_FAILCODE) >> MTER_FSHIFT;
1213*34221Sbostic 	for (e = errmsg; e->e_code >= 0; e++)
1214*34221Sbostic 		if (e->e_code == ecode)
121517214Smckusick 			break;
1216*34221Sbostic 	for (f = e->e_fmesg; f->f_code >= 0; f++)
1217*34221Sbostic 		if (f->f_code == fcode)
121817214Smckusick 			break;
1219*34221Sbostic 	printf("    interrupt code = 0%o <%s>\n", ecode, e->e_mesg);
1220*34221Sbostic 	printf("    failure code = 0%o <%s>\n", fcode, f->f_mesg);
122117214Smckusick }
1222*34221Sbostic #endif /* MTLERRM */
1223*34221Sbostic #endif /* NMT > 0 */
1224