xref: /csrg-svn/sys/vax/mba/mt.c (revision 45802)
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*45802Sbostic  *	@(#)mt.c	7.9 (Berkeley) 12/16/90
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)
1634221Sbostic  *	`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 
26*45802Sbostic #include "sys/param.h"
27*45802Sbostic #include "sys/systm.h"
28*45802Sbostic #include "sys/buf.h"
29*45802Sbostic #include "sys/conf.h"
30*45802Sbostic #include "sys/file.h"
31*45802Sbostic #include "sys/user.h"
32*45802Sbostic #include "sys/proc.h"
33*45802Sbostic #include "sys/map.h"
34*45802Sbostic #include "sys/ioctl.h"
35*45802Sbostic #include "sys/mtio.h"
36*45802Sbostic #include "sys/cmap.h"
37*45802Sbostic #include "sys/tty.h"
38*45802Sbostic #include "sys/syslog.h"
394736Swnj 
40*45802Sbostic #include "../include/pte.h"
41*45802Sbostic #include "../include/cpu.h"
4217119Sbloom #include "mbareg.h"
4317119Sbloom #include "mbavar.h"
4417119Sbloom #include "mtreg.h"
454736Swnj 
4617214Smckusick #define MTTIMEOUT	10000		/* loop limit for controller test */
4717214Smckusick #define	INF		1000000L	/* a block number that won't exist */
4817214Smckusick #define MASKREG(r)	((r) & 0xffff)	/* the control registers have 16 bits */
494736Swnj 
5017214Smckusick /* Bits for sc_flags */
514736Swnj 
5217214Smckusick #define	H_WRITTEN	01		/* last operation was a write */
5317214Smckusick #define H_EOT		02		/* end of tape encountered */
5417214Smckusick #define H_IEOT		04		/* ignore EOT condition */
554736Swnj 
5634221Sbostic int	mt_do_readrev = 1;
5717214Smckusick 
5817214Smckusick /* Per unit status information */
5917214Smckusick 
604736Swnj struct	mu_softc {
6134221Sbostic 	char	sc_openf;	/* unit is open if != 0 */
6234221Sbostic 	char	sc_flags;	/* state flags */
6334221Sbostic 	daddr_t	sc_blkno;	/* current physical block number */
6434221Sbostic 	daddr_t	sc_nxrec;	/* firewall input block number */
6534221Sbostic 	u_short	sc_erreg;	/* copy of mter or mtner */
6634221Sbostic 	u_short	sc_dsreg;	/* copy of mtds */
6734221Sbostic 	short	sc_resid;	/* residual function count for ioctl */
6834221Sbostic 	short	sc_dens;	/* density code - MT_GCR or zero */
6934221Sbostic 	int	sc_i_mtas;	/* mtas at slave attach time */
7034221Sbostic 	int	sc_i_mtner;	/* mtner at slave attach time */
7134221Sbostic 	int	sc_i_mtds;	/* mtds at slave attach time */
7240899Ssklower 	caddr_t	sc_ctty;	/* record user's tty for errors */
7334221Sbostic 	int	sc_blks;	/* number of I/O operations since open */
7434221Sbostic 	int	sc_softerrs;	/* number of soft I/O errors since open */
754736Swnj } mu_softc[NMU];
764736Swnj 
7717214Smckusick struct	buf	cmtbuf[NMT];		/* tape command buffer structures */
784736Swnj 
7934221Sbostic struct	mba_device *mtinfo[NMT];	/* unit to ctlr structures */
8034221Sbostic struct	mba_slave *muinfo[NMU];		/* unit to slave structures */
8134221Sbostic 
8217214Smckusick char	mtds_bits[] = MTDS_BITS;	/* mtds bit names for error messages */
8317214Smckusick short	mttypes[] = { MBDT_TU78, 0 };
844736Swnj 
8517214Smckusick int	mtattach(), mtslave(), mtustart(), mtstart(), mtndtint(), mtdtint();
8617214Smckusick struct	mba_driver mtdriver =
8717214Smckusick 	{ mtattach, mtslave, mtustart, mtstart, mtdtint, mtndtint,
8817214Smckusick 	  mttypes, "mt", "mu", mtinfo };
8917214Smckusick 
9034221Sbostic /* Bits in minor device */
9134221Sbostic #define	MUUNIT(dev)	(minor(dev)&03)
9234221Sbostic #define	H_NOREWIND	04
9334221Sbostic #define	H_6250BPI	010
9417214Smckusick 
9534221Sbostic #define MTUNIT(dev)	(muinfo[MUUNIT(dev)]->ms_ctlr)
9634221Sbostic 
9734221Sbostic void	mtcreset();
9834221Sbostic 
994736Swnj /*ARGSUSED*/
1004736Swnj mtattach(mi)
1014736Swnj 	struct mba_device *mi;
1024736Swnj {
10334221Sbostic 
10434221Sbostic 	/* void */
1054736Swnj }
1064736Swnj 
1077431Skre mtslave(mi, ms, sn)
1084736Swnj 	struct mba_device *mi;
1094736Swnj 	struct mba_slave *ms;
1107431Skre 	int sn;
1114736Swnj {
1124736Swnj 	register struct mu_softc *sc = &mu_softc[ms->ms_unit];
1134736Swnj 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
11426377Skarels 	int s = spl5(), rtn = 0, i;
1154736Swnj 
11634221Sbostic 	/*
11734221Sbostic 	 * Just in case the controller is ill, reset it.  Then issue
11834221Sbostic 	 * a sense operation and wait about a second for it to respond.
11934221Sbostic 	 */
12017214Smckusick 	mtcreset(mtaddr);
1214736Swnj 	mtaddr->mtas = -1;
1227431Skre 	mtaddr->mtncs[sn] = MT_SENSE|MT_GO;
12334221Sbostic 	for (i = MTTIMEOUT; i > 0; i--) {
12417214Smckusick 		DELAY(50);
12517214Smckusick 		if (MASKREG(mtaddr->mtas) != 0)
12617214Smckusick 			break;
12717214Smckusick 	}
12817214Smckusick 	sc->sc_i_mtas = mtaddr->mtas;
12917214Smckusick 	sc->sc_i_mtner = mtaddr->mtner;
13017214Smckusick 	sc->sc_i_mtds = mtaddr->mtds;
13117214Smckusick 
13234221Sbostic 	/*
13334221Sbostic 	 * If no response, whimper.  If wrong response, call it an
13434221Sbostic 	 * unsolicited interrupt and use mtndtint to log and correct.
13534221Sbostic 	 * Otherwise, note whether this slave exists.
13634221Sbostic 	 */
13734221Sbostic 	if (i <= 0)
13817214Smckusick 		printf("mt: controller hung\n");
13934221Sbostic 	else if ((mtaddr->mtner & MTER_INTCODE) != MTER_DONE)
14017214Smckusick 		(void) mtndtint(mi);
14134654Skarels 	else if (mtaddr->mtds & MTDS_PRES) {
14234654Skarels 		muinfo[ms->ms_unit] = ms;
1434736Swnj 		rtn = 1;
14434654Skarels 	}
14517214Smckusick 
14634221Sbostic 	/* cancel the interrupt, then wait a little while for it to go away */
1474736Swnj 	mtaddr->mtas = mtaddr->mtas;
14817214Smckusick 	DELAY(10);
1494736Swnj 	splx(s);
1504736Swnj 	return (rtn);
1514736Swnj }
1524736Swnj 
1534736Swnj mtopen(dev, flag)
1544736Swnj 	dev_t dev;
1554736Swnj 	int flag;
1564736Swnj {
1574736Swnj 	register int muunit;
1584736Swnj 	register struct mu_softc *sc;
15934221Sbostic 	register struct mba_slave *ms;
1604736Swnj 
1614736Swnj 	muunit = MUUNIT(dev);
16234221Sbostic 	if (muunit >= NMU || (ms = muinfo[muunit]) == NULL ||
16334221Sbostic 	    ms->ms_alive == 0 || mtinfo[ms->ms_ctlr]->mi_alive == 0)
1648581Sroot 		return (ENXIO);
16517214Smckusick 	if ((sc = &mu_softc[muunit])->sc_openf)
16617214Smckusick 		return (EBUSY);
16734221Sbostic 	sc->sc_openf = 1;
16817214Smckusick 	sc->sc_dens = (minor(dev) & H_6250BPI) ? MT_GCR : 0;
1694736Swnj 	mtcommand(dev, MT_SENSE, 1);
1704736Swnj 	if ((sc->sc_dsreg & MTDS_ONL) == 0) {
1714736Swnj 		uprintf("mu%d: not online\n", muunit);
17234221Sbostic 		sc->sc_openf = 0;
1738581Sroot 		return (EIO);
1744736Swnj 	}
17517214Smckusick 	if ((sc->sc_dsreg & MTDS_AVAIL) == 0) {
17617214Smckusick 		uprintf("mu%d: not online (port selector)\n", muunit);
17734221Sbostic 		sc->sc_openf = 0;
17817214Smckusick 		return (EIO);
17917214Smckusick 	}
18017214Smckusick 	if ((flag & FWRITE) && (sc->sc_dsreg & MTDS_FPT)) {
1814736Swnj 		uprintf("mu%d: no write ring\n", muunit);
18234221Sbostic 		sc->sc_openf = 0;
1838581Sroot 		return (EIO);
1844736Swnj 	}
18534221Sbostic 	if ((sc->sc_dsreg & MTDS_BOT) == 0 && (flag & FWRITE) &&
18634221Sbostic 	    (sc->sc_dens == MT_GCR) != ((sc->sc_dsreg & MTDS_PE) == 0)) {
1874736Swnj 		uprintf("mu%d: can't change density in mid-tape\n", muunit);
18834221Sbostic 		sc->sc_openf = 0;
1898581Sroot 		return (EIO);
1904736Swnj 	}
1914736Swnj 	sc->sc_blkno = (daddr_t)0;
19217214Smckusick 
19334221Sbostic 	/*
19434221Sbostic 	 * Since cooked I/O may do a read-ahead before a write, trash
19534221Sbostic 	 * on a tape can make the first write fail.  Suppress the first
19634221Sbostic 	 * read-ahead unless definitely doing read-write.
19734221Sbostic 	 */
19834221Sbostic 	sc->sc_nxrec = ((flag & (FTRUNC | FWRITE)) == (FTRUNC | FWRITE)) ?
19934221Sbostic 	    (daddr_t)0 : (daddr_t)INF;
2004736Swnj 	sc->sc_flags = 0;
20134221Sbostic 	sc->sc_blks = 0;
20234221Sbostic 	sc->sc_softerrs = 0;
20340899Ssklower 	sc->sc_ctty = (caddr_t)(u.u_procp->p_flag&SCTTY ?
20440899Ssklower 			u.u_procp->p_session->s_ttyp : 0);
2058581Sroot 	return (0);
2064736Swnj }
2074736Swnj 
2084736Swnj mtclose(dev, flag)
2094736Swnj 	register dev_t dev;
21017214Smckusick 	register int flag;
2114736Swnj {
2124736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
2134736Swnj 
21434221Sbostic 	if ((flag & (FREAD | FWRITE)) == FWRITE ||
21534221Sbostic 	    ((flag & FWRITE) && (sc->sc_flags & H_WRITTEN)))
2164736Swnj 		mtcommand(dev, MT_CLS|sc->sc_dens, 1);
21717214Smckusick 	if ((minor(dev) & H_NOREWIND) == 0)
2184736Swnj 		mtcommand(dev, MT_REW, 0);
21934221Sbostic 	if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100)
22034221Sbostic 		log(LOG_INFO, "mu%d: %d soft errors in %d blocks\n",
22134221Sbostic 		    MUUNIT(dev), sc->sc_softerrs, sc->sc_blks);
2224736Swnj 	sc->sc_openf = 0;
22340733Skarels 	return (0);
2244736Swnj }
2254736Swnj 
2264736Swnj mtcommand(dev, com, count)
2274736Swnj 	dev_t dev;
2284736Swnj 	int com, count;
2294736Swnj {
2304736Swnj 	register struct buf *bp;
23134221Sbostic 	int s;
2324736Swnj 
2334736Swnj 	bp = &cmtbuf[MTUNIT(dev)];
2345437Sroot 	s = spl5();
23517214Smckusick 	while (bp->b_flags & B_BUSY) {
23634221Sbostic 		if (bp->b_repcnt == 0 && (bp->b_flags & B_DONE))
2374736Swnj 			break;
2384736Swnj 		bp->b_flags |= B_WANTED;
2394736Swnj 		sleep((caddr_t)bp, PRIBIO);
2404736Swnj 	}
2414736Swnj 	bp->b_flags = B_BUSY|B_READ;
2425437Sroot 	splx(s);
2434736Swnj 	bp->b_dev = dev;
2444736Swnj 	bp->b_command = com;
2454736Swnj 	bp->b_repcnt = count;
2464736Swnj 	bp->b_blkno = 0;
24717214Smckusick 	bp->b_error = 0;
2484736Swnj 	mtstrategy(bp);
2494736Swnj 	if (count == 0)
2504736Swnj 		return;
25134221Sbostic 	biowait(bp);
25217214Smckusick 	if (bp->b_flags & B_WANTED)
2534736Swnj 		wakeup((caddr_t)bp);
2544736Swnj 	bp->b_flags &= B_ERROR;
2554736Swnj }
2564736Swnj 
2574736Swnj mtstrategy(bp)
2584736Swnj 	register struct buf *bp;
2594736Swnj {
2604736Swnj 	register struct buf *dp;
26134221Sbostic 	struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)];
26234221Sbostic 	int s;
2634736Swnj 
26434221Sbostic 	/*
26534221Sbostic 	 * If this is a data transfer operation, set the resid to a
26634221Sbostic 	 * default value (EOF) to simplify getting it right during
26734221Sbostic 	 * error recovery or bail out.
26834221Sbostic 	 */
26917214Smckusick 	if (bp != &cmtbuf[MTUNIT(bp->b_dev)])
27017214Smckusick 		bp->b_resid = bp->b_bcount;
27117214Smckusick 
27234221Sbostic 	/*
27334221Sbostic 	 * Link this request onto the end of the queue for this
27434221Sbostic 	 * controller, then start I/O if not already active.
27534221Sbostic 	 */
2764736Swnj 	bp->av_forw = NULL;
2774736Swnj 	dp = &mi->mi_tab;
2785437Sroot 	s = spl5();
2794736Swnj 	if (dp->b_actf == NULL)
2804736Swnj 		dp->b_actf = bp;
2814736Swnj 	else
2824736Swnj 		dp->b_actl->av_forw = bp;
2834736Swnj 	dp->b_actl = bp;
2844736Swnj 	if (dp->b_active == 0)
2854736Swnj 		mbustart(mi);
2865437Sroot 	splx(s);
2874736Swnj }
2884736Swnj 
2894736Swnj mtustart(mi)
2904736Swnj 	register struct mba_device *mi;
2914736Swnj {
29217214Smckusick 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
2934736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
2944736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
2954736Swnj 	daddr_t blkno;
29626377Skarels 	int count;
2974736Swnj 
2984736Swnj 	if (sc->sc_openf < 0) {
2994736Swnj 		bp->b_flags |= B_ERROR;
3004736Swnj 		return (MBU_NEXT);
3014736Swnj 	}
3024736Swnj 	if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) {
30334221Sbostic 		/*
30434221Sbostic 		 * Data transfer.  If write at end of tape,
30534221Sbostic 		 * signal "no space" unless suppressed
30634221Sbostic 		 * by MTIOCIEOT.
30734221Sbostic 		 */
30834221Sbostic 		if ((sc->sc_flags & (H_EOT | H_IEOT)) == H_EOT &&
30934221Sbostic 		    (bp->b_flags & B_READ) == 0) {
3104736Swnj 			bp->b_flags |= B_ERROR;
31117214Smckusick 			bp->b_error = ENOSPC;
3124736Swnj 			return (MBU_NEXT);
3134736Swnj 		}
31417214Smckusick 
31534221Sbostic 		if (bp->b_flags & B_RAW) {
31634221Sbostic 			/* raw transfer; never seek */
31734221Sbostic 			sc->sc_blkno = bdbtofsb(bp->b_blkno);
31834221Sbostic 			sc->sc_nxrec = sc->sc_blkno + 1;
31934221Sbostic 		} else {
32017214Smckusick 			/* seek beyond end of file */
32117214Smckusick 			if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) {
32217214Smckusick 				bp->b_flags |= B_ERROR;
32317214Smckusick 				bp->b_error = ENXIO;
32417214Smckusick 				return (MBU_NEXT);
32517214Smckusick 			}
32617214Smckusick 
32734221Sbostic 			/*
32834221Sbostic 			 * This should be end of file, but the buffer
32934221Sbostic 			 * system wants a one-block look-ahead.  Humor it.
33034221Sbostic 			 */
33134221Sbostic 			if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec &&
33234221Sbostic 			    bp->b_flags & B_READ) {
33334221Sbostic 				bp->b_resid = bp->b_bcount;
33417214Smckusick 				clrbuf(bp);
33517214Smckusick 				return (MBU_NEXT);
33617214Smckusick 			}
33717214Smckusick 
33817214Smckusick 			/* If writing, mark the next block invalid. */
33917214Smckusick 			if ((bp->b_flags & B_READ) == 0)
34017214Smckusick 				sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1;
3414736Swnj 		}
3424736Swnj 	} else {
34317214Smckusick 		/* It's a command, do it now. */
3444736Swnj 		mtaddr->mtncs[MUUNIT(bp->b_dev)] =
3454736Swnj 			(bp->b_repcnt<<8)|bp->b_command|MT_GO;
3464736Swnj 		return (MBU_STARTED);
3474736Swnj 	}
34817214Smckusick 
34934221Sbostic 	/*
35034221Sbostic 	 * If raw I/O, or if the tape is positioned correctly for
35134221Sbostic 	 * cooked I/O, set the byte count, unit number and repeat count
35234221Sbostic 	 * then tell the MASSBUS to proceed.  Note that a negative
35334221Sbostic 	 * bcount tells mbstart to map the buffer for "read backwards".
35434221Sbostic 	 */
35534221Sbostic 	if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) {
3564736Swnj 		if (mi->mi_tab.b_errcnt == 2) {
35734221Sbostic 			mtaddr->mtbc = -bp->b_bcount;
3584736Swnj 			mtaddr->mtca = MUUNIT(bp->b_dev);
3594736Swnj 		} else {
3604736Swnj 			mtaddr->mtbc = bp->b_bcount;
3614736Swnj 			mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev);
3624736Swnj 		}
3634736Swnj 		return (MBU_DODATA);
3644736Swnj 	}
36517214Smckusick 
36617214Smckusick 	/* Issue skip operations to position the next block for cooked I/O. */
36717214Smckusick 
3687380Ssam 	if (blkno < bdbtofsb(bp->b_blkno))
36934221Sbostic 		count = bdbtofsb(bp->b_blkno) - blkno;
3704736Swnj 	else
37134221Sbostic 		count = blkno - bdbtofsb(bp->b_blkno);
37234221Sbostic 	if ((unsigned)count > 0377)
37326377Skarels 		count = 0377;
37426377Skarels 	mtaddr->mtncs[MUUNIT(bp->b_dev)] = count | MT_SFORW|MT_GO;
3754736Swnj 	return (MBU_STARTED);
3764736Swnj }
3774736Swnj 
3784736Swnj mtstart(mi)
3794736Swnj 	register struct mba_device *mi;
3804736Swnj {
3814736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
3824736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
3834736Swnj 
3844736Swnj 	if (bp->b_flags & B_READ)
3854736Swnj 		if (mi->mi_tab.b_errcnt == 2)
38634221Sbostic 			return (MT_READREV|MT_GO);
3874736Swnj 		else
38834221Sbostic 			return (MT_READ|MT_GO);
3894736Swnj 	else
39034221Sbostic 		return (MT_WRITE|sc->sc_dens|MT_GO);
3914736Swnj }
3924736Swnj 
3934736Swnj mtdtint(mi, mbsr)
3944736Swnj 	register struct mba_device *mi;
3954736Swnj 	int mbsr;
3964736Swnj {
3974736Swnj 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
3984736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
3994736Swnj 	register struct mu_softc *sc;
40017214Smckusick 	register int er;
4014736Swnj 
40217214Smckusick 	/* I'M still NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */
40317214Smckusick 	if ((mtaddr->mtca & 3) != MUUNIT(bp->b_dev)) {
4044736Swnj 		printf("mt: wrong unit!\n");
4054736Swnj 		mtaddr->mtca = MUUNIT(bp->b_dev);
4064736Swnj 	}
40717214Smckusick 
40817214Smckusick 	er = MASKREG(mtaddr->mter);
4094736Swnj 	sc = &mu_softc[MUUNIT(bp->b_dev)];
41017214Smckusick 	sc->sc_erreg = er;
41117214Smckusick 	if (bp->b_flags & B_READ)
41217214Smckusick 		sc->sc_flags &= ~H_WRITTEN;
41317214Smckusick 	else
4144736Swnj 		sc->sc_flags |= H_WRITTEN;
41517214Smckusick 	switch (er & MTER_INTCODE) {
41617214Smckusick 
41717214Smckusick 	case MTER_EOT:
41817214Smckusick 		sc->sc_flags |= H_EOT;
41917214Smckusick 		/* fall into MTER_DONE */
42017214Smckusick 
4214736Swnj 	case MTER_DONE:
42217214Smckusick 		sc->sc_blkno++;
42317214Smckusick 		if (mi->mi_tab.b_errcnt == 2) {
42417214Smckusick 			bp->b_bcount = bp->b_resid;
42517214Smckusick 			bp->b_resid -= MASKREG(mtaddr->mtbc);
42634221Sbostic 			if (bp->b_resid > 0 && (bp->b_flags & B_RAW) == 0)
42717214Smckusick 				bp->b_flags |= B_ERROR;
42834221Sbostic 		} else
42917214Smckusick 			bp->b_resid = 0;
43017214Smckusick 		break;
43117214Smckusick 
43217214Smckusick 	case MTER_SHRTREC:
43317214Smckusick 		sc->sc_blkno++;
43417214Smckusick 		bp->b_bcount = bp->b_resid;
43517214Smckusick 		bp->b_resid -= MASKREG(mtaddr->mtbc);
43634221Sbostic 		if ((bp->b_flags & B_RAW) == 0)
43717214Smckusick 			bp->b_flags |= B_ERROR;
43817214Smckusick 		break;
43917214Smckusick 
44017214Smckusick 	case MTER_RETRY:
44134221Sbostic 		/*
44234221Sbostic 		 * Simple re-try.  Since resid is always a copy of the
44334221Sbostic 		 * original byte count, use it to restore the count.
44434221Sbostic 		 */
44517214Smckusick 		mi->mi_tab.b_errcnt = 1;
44617214Smckusick 		bp->b_bcount = bp->b_resid;
44734221Sbostic 		return (MBD_RETRY);
44817214Smckusick 
44917214Smckusick 	case MTER_RDOPP:
45034221Sbostic 		/*
45134221Sbostic 		 * The controller just decided to read it backwards.
45234221Sbostic 		 * If the controller returns a byte count of zero,
45334221Sbostic 		 * change it to 1, since zero encodes 65536, which
45434221Sbostic 		 * isn't quite what we had in mind.  The byte count
45534221Sbostic 		 * may be larger than the size of the input buffer, so
45634221Sbostic 		 * limit the count to the buffer size.  After
45734221Sbostic 		 * making the byte count reasonable, set bcount to the
45834221Sbostic 		 * negative of the controller's version of the byte
45934221Sbostic 		 * count so that the start address for the transfer is
46034221Sbostic 		 * set up correctly.
46134221Sbostic 		 */
46217214Smckusick 		if (mt_do_readrev) {
46317214Smckusick 			mi->mi_tab.b_errcnt = 2;
46417214Smckusick 			if ((bp->b_bcount = MASKREG(mtaddr->mtbc)) == 0)
46517214Smckusick 				bp->b_bcount = 1;
46617214Smckusick 			if (bp->b_bcount > bp->b_resid)
46717214Smckusick 				bp->b_bcount = bp->b_resid;
46817214Smckusick 			bp->b_bcount = -(bp->b_bcount);
46917214Smckusick 			return(MBD_RETRY);
47017214Smckusick 		} else if (MASKREG(mtaddr->mtbc) <= bp->b_resid) {
47117214Smckusick 			sc->sc_blkno++;
47217214Smckusick 			bp->b_bcount = bp->b_resid;
47317214Smckusick 			bp->b_resid -= MASKREG(mtaddr->mtbc);
47417214Smckusick 			bp->b_flags |= B_ERROR;
47517214Smckusick 			break;
47617214Smckusick 		}
47717214Smckusick 		bp->b_flags |= B_ERROR;
47817214Smckusick 		/* fall into MTER_LONGREC */
47917214Smckusick 
4804736Swnj 	case MTER_LONGREC:
48117214Smckusick 		sc->sc_blkno++;
48217214Smckusick 		bp->b_bcount = bp->b_resid;
4834736Swnj 		bp->b_resid = 0;
48417214Smckusick 		bp->b_error = ENOMEM;
48517214Smckusick 		bp->b_flags |= B_ERROR;
4864736Swnj 		break;
4874736Swnj 
4884736Swnj 	case MTER_NOTCAP:
4894736Swnj 		printf("mu%d: blank tape\n", MUUNIT(bp->b_dev));
4904736Swnj 		goto err;
4914736Swnj 
4924736Swnj 	case MTER_TM:
49334221Sbostic 		/*
49434221Sbostic 		 * End of file.  Since the default byte count has
49534221Sbostic 		 * already been set, just count the block and proceed.
49634221Sbostic 		 */
4974736Swnj 		sc->sc_blkno++;
4984736Swnj 	err:
49934221Sbostic 		sc->sc_nxrec = bdbtofsb(bp->b_blkno);
5004736Swnj 		break;
5014736Swnj 
5024736Swnj 	case MTER_OFFLINE:
5034736Swnj 		if (sc->sc_openf > 0) {
5044736Swnj 			sc->sc_openf = -1;
50540899Ssklower 			tprintf(sc->sc_ctty, "mu%d: offline\n",
50634221Sbostic 			    MUUNIT(bp->b_dev));
5074736Swnj 		}
5084736Swnj 		bp->b_flags |= B_ERROR;
5094736Swnj 		break;
5104736Swnj 
51117214Smckusick 	case MTER_NOTAVL:
51217214Smckusick 		if (sc->sc_openf > 0) {
51317214Smckusick 			sc->sc_openf = -1;
51440899Ssklower 			tprintf(sc->sc_ctty, "mu%d: offline (port selector)\n",
51518324Sralph 			    MUUNIT(bp->b_dev));
51617214Smckusick 		}
51717214Smckusick 		bp->b_flags |= B_ERROR;
51817214Smckusick 		break;
51917214Smckusick 
5204736Swnj 	case MTER_FPT:
52140899Ssklower 		tprintf(sc->sc_ctty, "mu%d: no write ring\n",
52234221Sbostic 		    MUUNIT(bp->b_dev));
5234736Swnj 		bp->b_flags |= B_ERROR;
5244736Swnj 		break;
5254736Swnj 
52617214Smckusick 	case MTER_UNREAD:
52717214Smckusick 		sc->sc_blkno++;
52817214Smckusick 		bp->b_bcount = bp->b_resid;
52917214Smckusick 		bp->b_resid -= MIN(MASKREG(mtaddr->mtbc), bp->b_bcount);
53017214Smckusick 
53134221Sbostic 		/* code 010 means a garbage record, nothing serious. */
53234221Sbostic 		if ((er & MTER_FAILCODE) == (010 << MTER_FSHIFT)) {
53340899Ssklower 			tprintf(sc->sc_ctty,
53434221Sbostic 			    "mu%d: rn=%d bn=%d unreadable record\n",
53517214Smckusick 			    MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno);
53617214Smckusick 			bp->b_flags |= B_ERROR;
53717214Smckusick 			break;
53817214Smckusick 		}
53917214Smckusick 
54034221Sbostic 		/*
54134221Sbostic 		 * Anything else might be a hardware problem,
54234221Sbostic 		 * fall into the error report.
54334221Sbostic 		 */
54417214Smckusick 
5454736Swnj 	default:
54634221Sbostic 		/*
54734221Sbostic 		 * The bits in sc->sc_dsreg are from the last sense
54834221Sbostic 		 * command.  To get the most recent copy, you have to
54934221Sbostic 		 * do a sense at interrupt level, which requires nested
55034221Sbostic 		 * error processing.  This is a bit messy, so leave
55134221Sbostic 		 * well enough alone.
55234221Sbostic 		 */
55340899Ssklower 		tprintf(sc->sc_ctty, "\
55434221Sbostic mu%d: hard error (data transfer) rn=%d bn=%d mbsr=%b er=0%o ds=%b\n",
55517214Smckusick 		    MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno,
55617214Smckusick 		    mbsr, mbsr_bits, er,
55717214Smckusick 		    MASKREG(sc->sc_dsreg), mtds_bits);
55817214Smckusick #ifdef MTLERRM
55934221Sbostic 		mtintfail(er);
56017214Smckusick #endif
5614736Swnj 		bp->b_flags |= B_ERROR;
56217214Smckusick 
56334221Sbostic 		/*
56434221Sbostic 		 * The TM78 manual says to reset the controller after
56534221Sbostic 		 * TM fault B or MASSBUS fault.
56634221Sbostic 		 */
56734221Sbostic 		if ((er & MTER_INTCODE) == MTER_TMFLTB ||
56834221Sbostic 		    (er & MTER_INTCODE) == MTER_MBFLT)
56917214Smckusick 			mtcreset(mtaddr);
5704736Swnj 	}
57117214Smckusick 
57234221Sbostic 	/*
57334221Sbostic 	 * Just in case some strange error slipped through (drive off
57434221Sbostic 	 * line during read-reverse error recovery comes to mind), make
57534221Sbostic 	 * sure the byte count is reasonable.
57634221Sbostic 	 */
57717214Smckusick 	if (bp->b_bcount < 0)
57817214Smckusick 		bp->b_bcount = bp->b_resid;
57934221Sbostic 
58034221Sbostic 	if ((bp->b_flags & B_ERROR) == 0) {
58134221Sbostic 		/* this counts reverse reads as soft errors */
58234221Sbostic 		sc->sc_blks++;
58334221Sbostic 		if (mi->mi_tab.b_errcnt) /* alternatively, if == 1 */
58434221Sbostic 			sc->sc_softerrs++;
58534221Sbostic 	}
5864736Swnj 	return (MBD_DONE);
5874736Swnj }
5884736Swnj 
5894736Swnj mtndtint(mi)
5904736Swnj 	register struct mba_device *mi;
5914736Swnj {
5924736Swnj 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
5934736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
5944736Swnj 	register struct mu_softc *sc;
59517214Smckusick 	register int er, fc;
59617214Smckusick 	int unit;
5974736Swnj 
5984736Swnj 	unit = (mtaddr->mtner >> 8) & 3;
5994736Swnj 	er = MASKREG(mtaddr->mtner);
60017214Smckusick 	sc = &mu_softc[unit];
60117214Smckusick 	sc->sc_erreg = er;
60217214Smckusick 
60317214Smckusick 	/* Check for unsolicited interrupts. */
60434221Sbostic 	if (bp == NULL || unit != MUUNIT(bp->b_dev)) {
60534221Sbostic 		if ((er & MTER_INTCODE) == MTER_ONLINE)
60634221Sbostic 			return (MBN_SKIP);
60717214Smckusick 
60834221Sbostic 		printf("mu%d: stray intr (non data transfer) er=0%o ds=%b\n",
60934221Sbostic 		    unit, er, MASKREG(sc->sc_dsreg), mtds_bits);
61017214Smckusick #ifdef MTLERRM
61134221Sbostic 		mtintfail(er);
61217214Smckusick #endif
61334221Sbostic 		if ((er & MTER_INTCODE) == MTER_TMFLTB ||
61434221Sbostic 		    (er & MTER_INTCODE) == MTER_MBFLT) {
61534221Sbostic 			/*
61634221Sbostic 			 * Reset the controller, then set error status
61734221Sbostic 			 * if there was anything active when the fault
61834221Sbostic 			 * occurred.  This may shoot an innocent
61934221Sbostic 			 * bystander, but it's better than letting
62034221Sbostic 			 * an error slip through.
62134221Sbostic 			 */
62234221Sbostic 			mtcreset(mtaddr);
62334221Sbostic 			if (bp != NULL) {
62434221Sbostic 				bp->b_flags |= B_ERROR;
62534221Sbostic 				return (MBN_DONE);
62617214Smckusick 			}
62717214Smckusick 		}
6284736Swnj 		return (MBN_SKIP);
6294736Swnj 	}
63017214Smckusick 
6314736Swnj 	fc = (mtaddr->mtncs[unit] >> 8) & 0xff;
6324736Swnj 	sc->sc_resid = fc;
63317214Smckusick 
63434221Sbostic 	/*
63534221Sbostic 	 * Clear the "written" flag after any operation that changes
63634221Sbostic 	 * the position of the tape.
63734221Sbostic 	 */
63834221Sbostic 	if (bp != &cmtbuf[MTUNIT(bp->b_dev)] || bp->b_command != MT_SENSE)
63917214Smckusick 		sc->sc_flags &= ~H_WRITTEN;
64017214Smckusick 
6414736Swnj 	switch (er & MTER_INTCODE) {
64217214Smckusick 
64317214Smckusick 	case MTER_EOT:
64417214Smckusick 		sc->sc_flags |= H_EOT;
64517214Smckusick 		/* fall into MTER_DONE */
64617214Smckusick 
6474736Swnj 	case MTER_DONE:
64817214Smckusick 		/* If this is a command buffer, just update the status.	*/
6494736Swnj 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) {
6504736Swnj 	done:
6514736Swnj 			if (bp->b_command == MT_SENSE)
6524736Swnj 				sc->sc_dsreg = MASKREG(mtaddr->mtds);
6534736Swnj 			return (MBN_DONE);
6544736Swnj 		}
65517214Smckusick 
65634221Sbostic 		/*
65734221Sbostic 		 * It's not a command buffer, must be a cooked I/O
65834221Sbostic 		 * skip operation (perhaps a shaky assumption, but it
65934221Sbostic 		 * wasn't my idea).
66034221Sbostic 		 */
6617380Ssam 		if ((fc = bdbtofsb(bp->b_blkno) - sc->sc_blkno) < 0)
6626186Ssam 			sc->sc_blkno -= MIN(0377, -fc);
6634736Swnj 		else
6646186Ssam 			sc->sc_blkno += MIN(0377, fc);
6654736Swnj 		return (MBN_RETRY);
6664736Swnj 
66717214Smckusick 	case MTER_ONLINE:		/* ddj -- shouldn't happen but did */
6684736Swnj 	case MTER_RWDING:
6694736Swnj 		return (MBN_SKIP);	/* ignore "rewind started" interrupt */
6704736Swnj 
6714736Swnj 	case MTER_NOTCAP:
67240899Ssklower 		tprintf(sc->sc_ctty, "mu%d: blank tape\n", MUUNIT(bp->b_dev));
67317214Smckusick 		bp->b_flags |= B_ERROR;
67417214Smckusick 		return (MBN_DONE);
6754736Swnj 
6764736Swnj 	case MTER_TM:
6774736Swnj 	case MTER_LEOT:
67834221Sbostic 		/*
67934221Sbostic 		 * For an ioctl skip operation, count a tape mark as
68034221Sbostic 		 * a record.  If there's anything left to do, update
68134221Sbostic 		 * the repeat count and re-start the command.
68234221Sbostic 		 */
68317214Smckusick 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) {
68417214Smckusick 			if ((sc->sc_resid = bp->b_repcnt = fc - 1) == 0)
68517214Smckusick 				return (MBN_DONE);
68617214Smckusick 			else
68717214Smckusick 				return (MBN_RETRY);
6884736Swnj 		} else {
68934221Sbostic 			/*
69034221Sbostic 			 * Cooked I/O again.  Just update the books and
69134221Sbostic 			 * wait for someone else to return end of file or
69234221Sbostic 			 * complain about a bad seek.
69334221Sbostic 			 */
69434221Sbostic 			if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) {
69534221Sbostic 				sc->sc_nxrec = bdbtofsb(bp->b_blkno) + fc - 1;
69634221Sbostic 				sc->sc_blkno = sc->sc_nxrec;
69734221Sbostic 			} else {
69834221Sbostic 				sc->sc_nxrec = bdbtofsb(bp->b_blkno) - fc;
69934221Sbostic 				sc->sc_blkno = sc->sc_nxrec + 1;
70034221Sbostic 			}
7014736Swnj 		}
7024736Swnj 		return (MBN_RETRY);
7034736Swnj 
7044736Swnj 	case MTER_FPT:
70540899Ssklower 		tprintf(sc->sc_ctty, "mu%d: no write ring\n",
70634221Sbostic 		    MUUNIT(bp->b_dev));
7074736Swnj 		bp->b_flags |= B_ERROR;
7084736Swnj 		return (MBN_DONE);
7094736Swnj 
7104736Swnj 	case MTER_OFFLINE:
71117214Smckusick 		/* If `off line' was intentional, don't complain. */
71234221Sbostic 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)] &&
71334221Sbostic 		    bp->b_command == MT_UNLOAD)
71417214Smckusick 			return(MBN_DONE);
7154736Swnj 		if (sc->sc_openf > 0) {
7164736Swnj 			sc->sc_openf = -1;
71740899Ssklower 			tprintf(sc->sc_ctty, "mu%d: offline\n",
71834221Sbostic 			    MUUNIT(bp->b_dev));
7194736Swnj 		}
7204736Swnj 		bp->b_flags |= B_ERROR;
7214736Swnj 		return (MBN_DONE);
7224736Swnj 
72317214Smckusick 	case MTER_NOTAVL:
72417214Smckusick 		if (sc->sc_openf > 0) {
72517214Smckusick 			sc->sc_openf = -1;
72640899Ssklower 			tprintf(sc->sc_ctty, "mu%d: offline (port selector)\n",
72734221Sbostic 			    MUUNIT(bp->b_dev));
72817214Smckusick 		}
72917214Smckusick 		bp->b_flags |= B_ERROR;
73017214Smckusick 		return (MBN_DONE);
73117214Smckusick 
7324736Swnj 	case MTER_BOT:
7334736Swnj 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)])
7344736Swnj 			goto done;
73517214Smckusick 		/* fall through */
73617214Smckusick 
7374736Swnj 	default:
73840899Ssklower 		tprintf(sc->sc_ctty, "\
73934221Sbostic mu%d: hard error (non data transfer) rn=%d bn=%d er=0%o ds=%b\n",
74017214Smckusick 		    MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno,
74117214Smckusick 		    er, MASKREG(sc->sc_dsreg), mtds_bits);
74217214Smckusick #ifdef MTLERRM
74334221Sbostic 		mtintfail(er);
74417214Smckusick #endif
74534221Sbostic 		if ((er & MTER_INTCODE) == MTER_TMFLTB ||
74634221Sbostic 		    (er & MTER_INTCODE) == MTER_MBFLT)
74717214Smckusick 			mtcreset(mtaddr);	/* reset the controller */
7484736Swnj 		bp->b_flags |= B_ERROR;
7494736Swnj 		return (MBN_DONE);
7504736Swnj 	}
7514736Swnj 	/* NOTREACHED */
7524736Swnj }
7534736Swnj 
75434221Sbostic void
75534221Sbostic mtcreset(mtaddr)
75617214Smckusick 	register struct mtdevice *mtaddr;
75717214Smckusick {
75817214Smckusick 	register int i;
75917214Smckusick 
76017214Smckusick 	mtaddr->mtid = MTID_CLR;		/* reset the TM78 */
76117214Smckusick 	DELAY(200);
76217214Smckusick 	for (i = MTTIMEOUT; i > 0; i--) {
76317214Smckusick 		DELAY(50);			/* don't nag */
76417214Smckusick 		if ((mtaddr->mtid & MTID_RDY) != 0)
76517214Smckusick 			return;			/* exit when ready */
76617214Smckusick 	}
76717214Smckusick 	printf("mt: controller hung\n");
76817214Smckusick }
76917214Smckusick 
7704736Swnj /*ARGSUSED*/
7717637Ssam mtioctl(dev, cmd, data, flag)
7724736Swnj 	dev_t dev;
7734736Swnj 	int cmd;
7747637Ssam 	caddr_t data;
7754736Swnj 	int flag;
7764736Swnj {
7774736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
7784736Swnj 	register struct buf *bp = &cmtbuf[MTUNIT(dev)];
77917214Smckusick 	register struct mtop *mtop;
78017214Smckusick 	register struct mtget *mtget;
78140909Ssklower 	int callcount, fcount, error = 0;
78217214Smckusick 	int op;
78317214Smckusick 
78417214Smckusick 	/* We depend on the values and order of the MT codes here. */
78517214Smckusick 
7864736Swnj 	static mtops[] =
7874736Swnj 	{MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE};
7884736Swnj 
7894736Swnj 	switch (cmd) {
7907637Ssam 
79117214Smckusick 	/* tape operation */
79217214Smckusick 
79317214Smckusick 	case MTIOCTOP:
7948606Sroot 		mtop = (struct mtop *)data;
7958606Sroot 		switch (mtop->mt_op) {
7967637Ssam 
7974736Swnj 		case MTWEOF:
7987637Ssam 			callcount = mtop->mt_count;
7994736Swnj 			fcount = 1;
8004736Swnj 			break;
8017637Ssam 
8024736Swnj 		case MTFSF: case MTBSF:
8037637Ssam 			callcount = mtop->mt_count;
8044736Swnj 			fcount = 1;
8054736Swnj 			break;
8067637Ssam 
8074736Swnj 		case MTFSR: case MTBSR:
8084736Swnj 			callcount = 1;
8097637Ssam 			fcount = mtop->mt_count;
8104736Swnj 			break;
8117637Ssam 
8124736Swnj 		case MTREW: case MTOFFL:
8134736Swnj 			callcount = 1;
8144736Swnj 			fcount = 1;
8154736Swnj 			break;
8167637Ssam 
8174736Swnj 		default:
8188581Sroot 			return (ENXIO);
8194736Swnj 		}
82034221Sbostic 		if (callcount <= 0 || fcount <= 0)
8218581Sroot 			return (EINVAL);
8227637Ssam 		op = mtops[mtop->mt_op];
8234736Swnj 		if (op == MT_WTM)
8244736Swnj 			op |= sc->sc_dens;
8254736Swnj 		while (--callcount >= 0) {
82617214Smckusick 			register int n, fc = fcount;
8274736Swnj 
8284736Swnj 			do {
82917214Smckusick 				n = MIN(fc, 0xff);
8304736Swnj 				mtcommand(dev, op, n);
83117214Smckusick 				n -= sc->sc_resid;
83217214Smckusick 				fc -= n;
83317214Smckusick 				switch (mtop->mt_op) {
83417214Smckusick 
83517214Smckusick 				case MTWEOF:
83617214Smckusick 					sc->sc_blkno += (daddr_t)n;
83717214Smckusick 					sc->sc_nxrec = sc->sc_blkno - 1;
83817214Smckusick 					break;
83917214Smckusick 
84017214Smckusick 				case MTOFFL:
84117214Smckusick 				case MTREW:
84217214Smckusick 				case MTFSF:
84317214Smckusick 					sc->sc_blkno = (daddr_t)0;
84417214Smckusick 					sc->sc_nxrec = (daddr_t)INF;
84517214Smckusick 					break;
84617214Smckusick 
84717214Smckusick 				case MTBSF:
84817214Smckusick 					if (sc->sc_resid) {
84917214Smckusick 						sc->sc_blkno = (daddr_t)0;
85017214Smckusick 						sc->sc_nxrec = (daddr_t)INF;
85117214Smckusick 					} else {
85217214Smckusick 						sc->sc_blkno = (daddr_t)(-1);
85317214Smckusick 						sc->sc_nxrec = (daddr_t)(-1);
85417214Smckusick 					}
85517214Smckusick 					break;
85617214Smckusick 
85717214Smckusick 				case MTFSR:
85817214Smckusick 					sc->sc_blkno += (daddr_t)n;
85917214Smckusick 					break;
86017214Smckusick 
86117214Smckusick 				case MTBSR:
86217214Smckusick 					sc->sc_blkno -= (daddr_t)n;
86317214Smckusick 					break;
86417214Smckusick 				}
86517214Smckusick 				if (sc->sc_resid)
86617214Smckusick 					break;
86717214Smckusick 			} while (fc);
86817214Smckusick 			if (fc) {
86917214Smckusick 				sc->sc_resid = callcount + fc;
87034221Sbostic 				if (mtop->mt_op == MTFSR ||
87134221Sbostic 				    mtop->mt_op == MTBSR)
87217214Smckusick 					return (EIO);
87334221Sbostic 				break;
87417214Smckusick 			}
87517214Smckusick 			if (bp->b_flags & B_ERROR)
8764736Swnj 				break;
8774736Swnj 		}
87840909Ssklower 		if (bp->b_flags&B_ERROR)
87940909Ssklower 			if ((error = bp->b_error)==0)
88040909Ssklower 				return (EIO);
88140909Ssklower 		return (error);
8827637Ssam 
88317214Smckusick 	/* tape status */
8844736Swnj 	case MTIOCGET:
8857637Ssam 		mtget = (struct mtget *)data;
8867637Ssam 		mtget->mt_erreg = sc->sc_erreg;
8877637Ssam 		mtget->mt_resid = sc->sc_resid;
8884736Swnj 		mtcommand(dev, MT_SENSE, 1);	/* update drive status */
8897637Ssam 		mtget->mt_dsreg = sc->sc_dsreg;
8907637Ssam 		mtget->mt_type = MT_ISMT;
8918581Sroot 		break;
8927637Ssam 
89317214Smckusick 	/* ignore EOT condition */
89417214Smckusick 	case MTIOCIEOT:
89517214Smckusick 		sc->sc_flags |= H_IEOT;
89617214Smckusick 		break;
89717214Smckusick 
89817214Smckusick 	/* enable EOT condition */
89917214Smckusick 	case MTIOCEEOT:
90017214Smckusick 		sc->sc_flags &= ~H_IEOT;
90117214Smckusick 		break;
90217214Smckusick 
9034736Swnj 	default:
9048581Sroot 		return (ENXIO);
9054736Swnj 	}
9068581Sroot 	return (0);
9074736Swnj }
9084736Swnj 
9094736Swnj #define	DBSIZE	20
9104736Swnj 
9114736Swnj mtdump()
9124736Swnj {
9134736Swnj 	register struct mba_device *mi;
9144736Swnj 	register struct mba_regs *mp;
9154736Swnj 	int blk, num;
9164736Swnj 	int start;
9174736Swnj 
9184736Swnj 	start = 0;
9194736Swnj 	num = maxfree;
9204736Swnj #define	phys(a,b)		((b)((int)(a)&0x7fffffff))
9214736Swnj 	if (mtinfo[0] == 0)
9224736Swnj 		return (ENXIO);
9234736Swnj 	mi = phys(mtinfo[0], struct mba_device *);
9244736Swnj 	mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba;
9254736Swnj 	mp->mba_cr = MBCR_IE;
9266186Ssam #if lint
9278606Sroot 	blk = 0; num = blk; start = num; blk = start;
9286186Ssam 	return (0);
9296186Ssam #endif
9306186Ssam #ifdef notyet
9314736Swnj 	mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive];
9324736Swnj 	mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI;
9334736Swnj 	mtaddr->mtcs1 = MT_DCLR|MT_GO;
9344736Swnj 	while (num > 0) {
9354736Swnj 		blk = num > DBSIZE ? DBSIZE : num;
9364736Swnj 		mtdwrite(start, blk, mtaddr, mp);
9374736Swnj 		start += blk;
9384736Swnj 		num -= blk;
9394736Swnj 	}
9404736Swnj 	mteof(mtaddr);
9414736Swnj 	mteof(mtaddr);
9424736Swnj 	mtwait(mtaddr);
9434736Swnj 	if (mtaddr->mtds&MTDS_ERR)
9444736Swnj 		return (EIO);
9454736Swnj 	mtaddr->mtcs1 = MT_REW|MT_GO;
9464736Swnj 	return (0);
9474736Swnj }
9484736Swnj 
9494736Swnj mtdwrite(dbuf, num, mtaddr, mp)
9504736Swnj 	register dbuf, num;
9514736Swnj 	register struct mtdevice *mtaddr;
9524736Swnj 	struct mba_regs *mp;
9534736Swnj {
9544736Swnj 	register struct pte *io;
9554736Swnj 	register int i;
9564736Swnj 
9574736Swnj 	mtwait(mtaddr);
9584736Swnj 	io = mp->mba_map;
9594736Swnj 	for (i = 0; i < num; i++)
9604736Swnj 		*(int *)io++ = dbuf++ | PG_V;
9614736Swnj 	mtaddr->mtfc = -(num*NBPG);
9624736Swnj 	mp->mba_sr = -1;
9634736Swnj 	mp->mba_bcr = -(num*NBPG);
9644736Swnj 	mp->mba_var = 0;
9654736Swnj 	mtaddr->mtcs1 = MT_WCOM|MT_GO;
9664736Swnj }
9674736Swnj 
9684736Swnj mtwait(mtaddr)
9694736Swnj 	struct mtdevice *mtaddr;
9704736Swnj {
9714736Swnj 	register s;
9724736Swnj 
9734736Swnj 	do
9744736Swnj 		s = mtaddr->mtds;
9754736Swnj 	while ((s & MTDS_DRY) == 0);
9764736Swnj }
9774736Swnj 
9784736Swnj mteof(mtaddr)
9794736Swnj 	struct mtdevice *mtaddr;
9804736Swnj {
9814736Swnj 
9824736Swnj 	mtwait(mtaddr);
9834736Swnj 	mtaddr->mtcs1 = MT_WEOF|MT_GO;
9844736Swnj #endif notyet
9854736Swnj }
98617214Smckusick 
98717214Smckusick #ifdef MTLERRM
98834221Sbostic /*
98934221Sbostic  * Failure messages for each failure code, per interrupt code.
99034221Sbostic  * Each table ends with a code of -1 as a default.
99134221Sbostic  */
99234221Sbostic struct fmesg {
99334221Sbostic 	int	f_code;
99434221Sbostic 	char	*f_mesg;
99534221Sbostic };
99617214Smckusick 
99734221Sbostic static char unclass[] = "unclassified failure code";
99817214Smckusick 
99934221Sbostic /* MTER_BOT */
100034221Sbostic static struct fmesg botmsg[] = {
100134221Sbostic 	01,	"tape was at BOT",
100234221Sbostic 	02,	"BOT seen after tape started",
100334221Sbostic 	03,	"ARA ID detected",
100434221Sbostic 	-1,	unclass
100534221Sbostic };
100617214Smckusick 
100734221Sbostic /* MTER_NOTRDY */
100834221Sbostic static struct fmesg notrdymsg[] = {
100934221Sbostic 	01,	"TU on-line but not ready",
101034221Sbostic 	02,	"fatal error has occurred",
101136548Sbostic 	03,	"access allowed but not ready",
101234221Sbostic 	-1,	unclass
101334221Sbostic };
101417214Smckusick 
101534221Sbostic /* MTER_NOTCAP */
101634221Sbostic static struct fmesg notcapmsg[] = {
101734221Sbostic 	01,	"no record found within 25 feet",
101834221Sbostic 	02,	"ID burst neither PE nor GCR",
101934221Sbostic 	03,	"ARA ID not found",
102034221Sbostic 	04,	"no gap found after ID burst",
102134221Sbostic 	-1,	unclass
102234221Sbostic };
102317214Smckusick 
102434221Sbostic /* MTER_LONGREC */
102534221Sbostic static struct fmesg longrecmsg[] = {
102634221Sbostic 	00,	"extended sense data not found",
102734221Sbostic 	01,	"extended sense data updated",
102834221Sbostic 	-1,	unclass
102934221Sbostic };
103017214Smckusick 
103134221Sbostic /* MTER_UNREAD, MTER_ERROR, MTER_EOTERR, MTER_BADTAPE */
103234221Sbostic static struct fmesg code22msg[] = {
103334221Sbostic 	01,	"GCR write error",
103434221Sbostic 	02,	"GCR read error",
103534221Sbostic 	03,	"PE read error",
103634221Sbostic 	04,	"PE write error",
103734221Sbostic 	05,	"at least 1 bit set in ECCSTA",
103834221Sbostic 	06,	"PE write error",
103934221Sbostic 	07,	"GCR write error",
104034221Sbostic 	010,	"RSTAT contains bad code",
104134221Sbostic 	011,	"PE write error",
104234221Sbostic 	012,	"MASSBUS parity error",
104334221Sbostic 	013,	"invalid data transferred",
104434221Sbostic 	-1,	unclass
104534221Sbostic };
104617214Smckusick 
104734221Sbostic /* MTER_TMFLTA */
104834221Sbostic static struct fmesg tmfltamsg[] = {
104934221Sbostic 	01,	"illegal command code",
105034221Sbostic 	02,	"DT command issued when NDT command active",
105134221Sbostic 	03,	"WMC error",
105234221Sbostic 	04,	"RUN not received from MASSBUS controller",
105334221Sbostic 	05,	"mismatch in command read - function routine",
105434221Sbostic 	06,	"ECC ROM parity error",
105534221Sbostic 	07,	"XMC ROM parity error",
105634221Sbostic 	010,	"mismatch in command read - ID burst command",
105734221Sbostic 	011,	"mismatch in command read - verify ARA burst command",
105834221Sbostic 	012,	"mismatch in command read - verify ARA ID command",
105934221Sbostic 	013,	"mismatch in command read - verify gap command",
106034221Sbostic 	014,	"mismatch in command read - read id burst command",
106134221Sbostic 	015,	"mismatch in command read - verify ARA ID command",
106234221Sbostic 	016,	"mismatch in command read - verify gap command",
106334221Sbostic 	017,	"mismatch in command read - find gap command",
106434221Sbostic 	020,	"WMC LEFT failed to set",
106534221Sbostic 	021,	"XL PE set in INTSTA register",
106634221Sbostic 	022,	"XMC DONE did not set",
106734221Sbostic 	023,	"WMC ROM PE or RD PE set in WMCERR register",
106834221Sbostic 	-1,	unclass
106934221Sbostic };
107017214Smckusick 
107134221Sbostic /* MTER_TUFLTA */
107234221Sbostic static struct fmesg tufltamsg[] = {
107334221Sbostic 	01,	"TU status parity error",
107434221Sbostic 	02,	"TU command parity error",
107534221Sbostic 	03,	"rewinding tape went offline",
107634221Sbostic 	04,	"tape went not ready during DSE",
107734221Sbostic 	05,	"TU CMD status changed during DSE",
107834221Sbostic 	06,	"TU never came up to speed",
107934221Sbostic 	07,	"TU velocity changed",
108034221Sbostic 	010,	"TU CMD did not load correctly to start tape motion",
108134221Sbostic 	011,	"TU CMD did not load correctly to set drive density",
108234221Sbostic 	012,	"TU CMD did not load correctly to start tape motion to write BOT ID",
108334221Sbostic 	013,	"TU CMD did not load correctly to backup tape to BOT after failing to write BOT ID",
108434221Sbostic 	014,	"failed to write density ID burst",
108534221Sbostic 	015,	"failed to write ARA burst",
108634221Sbostic 	016,	"failed to write ARA ID",
108734221Sbostic 	017,	"ARA error bit set in MTA status B register",
108834221Sbostic 	021,	"could not find a gap after ID code was written correctly",
108934221Sbostic 	022,	"TU CMD did not load correctly to start tape motion to read ID burst",
109034221Sbostic 	023,	"timeout looking for BOT after detecting ARA ID burst",
109134221Sbostic 	024,	"failed to write tape mark",
109234221Sbostic 	025,	"tape never came up to speed while trying to reposition for retry of writing tape mark",
109334221Sbostic 	026,	"TU CMD did not load correctly to start tape motion in erase gap routine",
109434221Sbostic 	027,	"could not detect a gap in in erase gap routine",
109534221Sbostic 	030,	"could not detect a gap after writing record",
109634221Sbostic 	031,	"read path terminated before entire record was written",
109734221Sbostic 	032,	"could not find a gap after writing record and read path terminated early",
109834221Sbostic 	033,	"TU CMD did not load correctly to backup for retry of write tape mark",
109934221Sbostic 	034,	"TU velocity changed after up to speed while trying to reposition for retry of writing tape mark",
110034221Sbostic 	035,	"TU CMD did not load correctly to backup to retry a load of BOT ID",
110134221Sbostic 	036,	"timeout looking for BOT after failing to write BOT ID",
110234221Sbostic 	037,	"TU velocity changed while writing PE gap before starting to write record",
110334221Sbostic 	040,	"TU CMD did not load correctly to set PE tape density at start of write BOT ID burst",
110434221Sbostic 	041,	"TU CMD did not load correctly to set GCR tape density after writing Density ID",
110534221Sbostic 	042,	"TU CMD did not load correctly to set PE tape density at start of read from BOT",
110634221Sbostic 	043,	"TU CMD did not load correctly to set GCR tape density after reading a GCR Density ID burst",
110734221Sbostic };
110817214Smckusick 
110934221Sbostic /* MTER_TMFLTB */
111034221Sbostic static char inlinetest[] = "inline test failed";
111134221Sbostic static struct fmesg tmfltbmsg[] = {
111234221Sbostic 	00,	"RST0 interrupt occurred with TM RDY set",
111334221Sbostic 	01,	"power failed to interrupt",
111434221Sbostic 	02,	"unknown interrupt on channel 5.5",
111534221Sbostic 	03,	"unknown interrupt on channel 6.5",
111634221Sbostic 	04,	"unknown interrupt on channel 7",
111734221Sbostic 	05,	"unknown interrupt on channel 7.5",
111834221Sbostic 	06,	"CAS contention retry count expired",
111934221Sbostic 	07,	"CAS contention error not retryable",
112034221Sbostic 	010,	"queue error, could not find queue entry",
112134221Sbostic 	011,	"queue entry already full",
112234221Sbostic 	012,	"8085 ROM parity error",
112334221Sbostic 	013,	inlinetest,
112434221Sbostic 	013,	inlinetest,
112534221Sbostic 	014,	inlinetest,
112634221Sbostic 	015,	inlinetest,
112734221Sbostic 	016,	inlinetest,
112834221Sbostic 	017,	inlinetest,
112934221Sbostic 	020,	inlinetest,
113034221Sbostic 	021,	inlinetest,
113134221Sbostic 	022,	inlinetest,
113234221Sbostic 	023,	inlinetest,
113334221Sbostic 	024,	inlinetest,
113434221Sbostic 	025,	inlinetest,
113534221Sbostic 	026,	inlinetest,
113634221Sbostic 	027,	inlinetest,
113734221Sbostic 	030,	inlinetest,
113834221Sbostic 	031,	inlinetest,
113934221Sbostic 	032,	inlinetest,
114034221Sbostic 	033,	inlinetest,
114134221Sbostic 	034,	inlinetest,
114234221Sbostic 	035,	inlinetest,
114334221Sbostic 	036,	inlinetest,
114434221Sbostic 	037,	inlinetest,
114534221Sbostic 	040,	inlinetest,
114634221Sbostic 	041,	inlinetest,
114734221Sbostic 	042,	inlinetest,
114834221Sbostic 	043,	inlinetest,
114934221Sbostic 	044,	inlinetest,
115036548Sbostic 	045,	inlinetest,
115134221Sbostic 	046,	inlinetest,
115234221Sbostic 	047,	inlinetest,
115334221Sbostic 	050,	inlinetest,
115434221Sbostic 	051,	inlinetest,
115534221Sbostic 	052,	inlinetest,
115634221Sbostic 	053,	inlinetest,
115734221Sbostic 	054,	inlinetest,
115834221Sbostic 	055,	inlinetest,
115934221Sbostic 	056,	inlinetest,
116034221Sbostic 	057,	inlinetest,
116134221Sbostic 	-1,	unclass
116234221Sbostic };
116317214Smckusick 
116434221Sbostic /* MTER_MBFLT */
116534221Sbostic static struct fmesg mbfltmsg[] = {
116634221Sbostic 	01,	"control bus parity error",
116734221Sbostic 	02,	"illegal register referenced",
116834221Sbostic 	-1,	unclass
116934221Sbostic };
117017214Smckusick 
117134221Sbostic /*
117234221Sbostic  * MTER_LEOT, MTER_RWDING, NTER_NOTAVL, MTER_NONEX, MTER_KEYFAIL,
117334221Sbostic  * and default: no failure message.
117434221Sbostic  */
117534221Sbostic static struct fmesg nullmsg[] = {
117634221Sbostic 	-1,	""
117734221Sbostic };
117817214Smckusick 
117934221Sbostic /*
118034221Sbostic  * Interrupt code table.
118134221Sbostic  */
118234221Sbostic static struct errmsg {
118334221Sbostic 	int	e_code;
118434221Sbostic 	char	*e_mesg;
118534221Sbostic 	struct	fmesg *e_fmesg;
118634221Sbostic } errmsg[] = {
118734221Sbostic 	MTER_BOT,	"unexpected BOT",	botmsg,
118834221Sbostic 	MTER_LEOT,	"unexpected LEOT",	nullmsg,
118934221Sbostic 	MTER_RWDING,	"tape rewinding",	nullmsg,
119034221Sbostic 	MTER_NOTRDY,	"drive not ready",	notrdymsg,
119134221Sbostic 	MTER_NOTAVL,	"drive not available",	nullmsg,
119234221Sbostic 	MTER_NONEX,	"unit does not exist",	nullmsg,
119334221Sbostic 	MTER_NOTCAP,	"not capable",		notcapmsg,
119434221Sbostic 	MTER_LONGREC,	"long record",		longrecmsg,
119534221Sbostic 	MTER_UNREAD,	"unreadable record",	code22msg,
119634221Sbostic 	MTER_ERROR,	"error",		code22msg,
119734221Sbostic 	MTER_EOTERR,	"EOT error",		code22msg,
119834221Sbostic 	MTER_BADTAPE,	"tape position lost",	code22msg,
119934221Sbostic 	MTER_TMFLTA,	"TM fault A",		tmfltamsg,
120034221Sbostic 	MTER_TUFLTA,	"TU fault A",		tufltamsg,
120134221Sbostic 	MTER_TMFLTB,	"TM fault B",		tmfltbmsg,
120234221Sbostic 	MTER_MBFLT,	"MB fault",		mbfltmsg,
120334221Sbostic 	MTER_KEYFAIL,	"keypad entry error",	nullmsg,
120434221Sbostic 	-1,		"unclassified error",	nullmsg
120534221Sbostic };
120617214Smckusick 
120734221Sbostic /*
120834221Sbostic  * Decode an interrupt-time failure.
120934221Sbostic  */
121034221Sbostic mtintfail(erreg)
121134221Sbostic 	int erreg;
121234221Sbostic {
121334221Sbostic 	register struct errmsg *e;
121434221Sbostic 	register struct fmesg *f;
121534221Sbostic 	register int ecode, fcode;
121617214Smckusick 
121734221Sbostic 	ecode = erreg & MTER_INTCODE;
121834221Sbostic 	fcode = (erreg & MTER_FAILCODE) >> MTER_FSHIFT;
121934221Sbostic 	for (e = errmsg; e->e_code >= 0; e++)
122034221Sbostic 		if (e->e_code == ecode)
122117214Smckusick 			break;
122234221Sbostic 	for (f = e->e_fmesg; f->f_code >= 0; f++)
122334221Sbostic 		if (f->f_code == fcode)
122417214Smckusick 			break;
122534221Sbostic 	printf("    interrupt code = 0%o <%s>\n", ecode, e->e_mesg);
122634221Sbostic 	printf("    failure code = 0%o <%s>\n", fcode, f->f_mesg);
122717214Smckusick }
122834221Sbostic #endif /* MTLERRM */
122934221Sbostic #endif /* NMT > 0 */
1230