xref: /csrg-svn/sys/vax/mba/mt.c (revision 64634)
149439Sbostic /*-
249439Sbostic  * Copyright (c) 1982, 1986 The Regents of the University of California.
349439Sbostic  * All rights reserved.
423315Smckusick  *
549439Sbostic  * %sccs.include.proprietary.c%
649439Sbostic  *
7*64634Sbostic  *	@(#)mt.c	7.11 (Berkeley) 09/23/93
823315Smckusick  */
94736Swnj 
104736Swnj #include "mu.h"
114736Swnj #if NMT > 0
124736Swnj /*
134736Swnj  * TM78/TU78 tape driver
144736Swnj  *
1517214Smckusick  *	Original author - ?
1617214Smckusick  *	Most error recovery bug fixes - ggs (ulysses!ggs)
1734221Sbostic  *	`read reverse' error recovery - ggs (ulysses!ggs)
184736Swnj  *
1917214Smckusick  * OPTIONS:
2017214Smckusick  *	MTLERRM - Long error message text - twd, Brown University
2117214Smckusick  *
224736Swnj  * TODO:
2317214Smckusick  *	Add odd byte count kludge from VMS driver (?)
2417214Smckusick  *	Write dump routine
254736Swnj  */
2617214Smckusick 
2745802Sbostic #include "sys/param.h"
2845802Sbostic #include "sys/systm.h"
2945802Sbostic #include "sys/buf.h"
3045802Sbostic #include "sys/conf.h"
3145802Sbostic #include "sys/file.h"
3245802Sbostic #include "sys/user.h"
3345802Sbostic #include "sys/proc.h"
3445802Sbostic #include "sys/map.h"
3545802Sbostic #include "sys/ioctl.h"
3645802Sbostic #include "sys/mtio.h"
3745802Sbostic #include "sys/cmap.h"
3845802Sbostic #include "sys/tty.h"
3945802Sbostic #include "sys/syslog.h"
404736Swnj 
4145802Sbostic #include "../include/pte.h"
4245802Sbostic #include "../include/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 
5734221Sbostic int	mt_do_readrev = 1;
5817214Smckusick 
5917214Smckusick /* Per unit status information */
6017214Smckusick 
614736Swnj struct	mu_softc {
6234221Sbostic 	char	sc_openf;	/* unit is open if != 0 */
6334221Sbostic 	char	sc_flags;	/* state flags */
6434221Sbostic 	daddr_t	sc_blkno;	/* current physical block number */
6534221Sbostic 	daddr_t	sc_nxrec;	/* firewall input block number */
6634221Sbostic 	u_short	sc_erreg;	/* copy of mter or mtner */
6734221Sbostic 	u_short	sc_dsreg;	/* copy of mtds */
6834221Sbostic 	short	sc_resid;	/* residual function count for ioctl */
6934221Sbostic 	short	sc_dens;	/* density code - MT_GCR or zero */
7034221Sbostic 	int	sc_i_mtas;	/* mtas at slave attach time */
7134221Sbostic 	int	sc_i_mtner;	/* mtner at slave attach time */
7234221Sbostic 	int	sc_i_mtds;	/* mtds at slave attach time */
7340899Ssklower 	caddr_t	sc_ctty;	/* record user's tty for errors */
7434221Sbostic 	int	sc_blks;	/* number of I/O operations since open */
7534221Sbostic 	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 
8034221Sbostic struct	mba_device *mtinfo[NMT];	/* unit to ctlr structures */
8134221Sbostic struct	mba_slave *muinfo[NMU];		/* unit to slave structures */
8234221Sbostic 
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 
9134221Sbostic /* Bits in minor device */
9234221Sbostic #define	MUUNIT(dev)	(minor(dev)&03)
9334221Sbostic #define	H_NOREWIND	04
9434221Sbostic #define	H_6250BPI	010
9517214Smckusick 
9634221Sbostic #define MTUNIT(dev)	(muinfo[MUUNIT(dev)]->ms_ctlr)
9734221Sbostic 
9834221Sbostic void	mtcreset();
9934221Sbostic 
1004736Swnj /*ARGSUSED*/
1014736Swnj mtattach(mi)
1024736Swnj 	struct mba_device *mi;
1034736Swnj {
10434221Sbostic 
10534221Sbostic 	/* 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 
11734221Sbostic 	/*
11834221Sbostic 	 * Just in case the controller is ill, reset it.  Then issue
11934221Sbostic 	 * a sense operation and wait about a second for it to respond.
12034221Sbostic 	 */
12117214Smckusick 	mtcreset(mtaddr);
1224736Swnj 	mtaddr->mtas = -1;
1237431Skre 	mtaddr->mtncs[sn] = MT_SENSE|MT_GO;
12434221Sbostic 	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 
13334221Sbostic 	/*
13434221Sbostic 	 * If no response, whimper.  If wrong response, call it an
13534221Sbostic 	 * unsolicited interrupt and use mtndtint to log and correct.
13634221Sbostic 	 * Otherwise, note whether this slave exists.
13734221Sbostic 	 */
13834221Sbostic 	if (i <= 0)
13917214Smckusick 		printf("mt: controller hung\n");
14034221Sbostic 	else if ((mtaddr->mtner & MTER_INTCODE) != MTER_DONE)
14117214Smckusick 		(void) mtndtint(mi);
14234654Skarels 	else if (mtaddr->mtds & MTDS_PRES) {
14334654Skarels 		muinfo[ms->ms_unit] = ms;
1444736Swnj 		rtn = 1;
14534654Skarels 	}
14617214Smckusick 
14734221Sbostic 	/* cancel the interrupt, then wait a little while for it to go away */
1484736Swnj 	mtaddr->mtas = mtaddr->mtas;
14917214Smckusick 	DELAY(10);
1504736Swnj 	splx(s);
1514736Swnj 	return (rtn);
1524736Swnj }
1534736Swnj 
mtopen(dev,flag)1544736Swnj mtopen(dev, flag)
1554736Swnj 	dev_t dev;
1564736Swnj 	int flag;
1574736Swnj {
1584736Swnj 	register int muunit;
1594736Swnj 	register struct mu_softc *sc;
16034221Sbostic 	register struct mba_slave *ms;
1614736Swnj 
1624736Swnj 	muunit = MUUNIT(dev);
16334221Sbostic 	if (muunit >= NMU || (ms = muinfo[muunit]) == NULL ||
16434221Sbostic 	    ms->ms_alive == 0 || mtinfo[ms->ms_ctlr]->mi_alive == 0)
1658581Sroot 		return (ENXIO);
16617214Smckusick 	if ((sc = &mu_softc[muunit])->sc_openf)
16717214Smckusick 		return (EBUSY);
16834221Sbostic 	sc->sc_openf = 1;
16917214Smckusick 	sc->sc_dens = (minor(dev) & H_6250BPI) ? MT_GCR : 0;
1704736Swnj 	mtcommand(dev, MT_SENSE, 1);
1714736Swnj 	if ((sc->sc_dsreg & MTDS_ONL) == 0) {
1724736Swnj 		uprintf("mu%d: not online\n", muunit);
17334221Sbostic 		sc->sc_openf = 0;
1748581Sroot 		return (EIO);
1754736Swnj 	}
17617214Smckusick 	if ((sc->sc_dsreg & MTDS_AVAIL) == 0) {
17717214Smckusick 		uprintf("mu%d: not online (port selector)\n", muunit);
17834221Sbostic 		sc->sc_openf = 0;
17917214Smckusick 		return (EIO);
18017214Smckusick 	}
18117214Smckusick 	if ((flag & FWRITE) && (sc->sc_dsreg & MTDS_FPT)) {
1824736Swnj 		uprintf("mu%d: no write ring\n", muunit);
18334221Sbostic 		sc->sc_openf = 0;
1848581Sroot 		return (EIO);
1854736Swnj 	}
18634221Sbostic 	if ((sc->sc_dsreg & MTDS_BOT) == 0 && (flag & FWRITE) &&
18734221Sbostic 	    (sc->sc_dens == MT_GCR) != ((sc->sc_dsreg & MTDS_PE) == 0)) {
1884736Swnj 		uprintf("mu%d: can't change density in mid-tape\n", muunit);
18934221Sbostic 		sc->sc_openf = 0;
1908581Sroot 		return (EIO);
1914736Swnj 	}
1924736Swnj 	sc->sc_blkno = (daddr_t)0;
19317214Smckusick 
19434221Sbostic 	/*
19534221Sbostic 	 * Since cooked I/O may do a read-ahead before a write, trash
19634221Sbostic 	 * on a tape can make the first write fail.  Suppress the first
19734221Sbostic 	 * read-ahead unless definitely doing read-write.
19834221Sbostic 	 */
19934221Sbostic 	sc->sc_nxrec = ((flag & (FTRUNC | FWRITE)) == (FTRUNC | FWRITE)) ?
20034221Sbostic 	    (daddr_t)0 : (daddr_t)INF;
2014736Swnj 	sc->sc_flags = 0;
20234221Sbostic 	sc->sc_blks = 0;
20334221Sbostic 	sc->sc_softerrs = 0;
204*64634Sbostic 	sc->sc_ctty = (caddr_t)(u.u_procp->p_flag & P_CONTROLT ?
205*64634Sbostic 	    u.u_procp->p_session->s_ttyp : 0);
2068581Sroot 	return (0);
2074736Swnj }
2084736Swnj 
mtclose(dev,flag)2094736Swnj mtclose(dev, flag)
2104736Swnj 	register dev_t dev;
21117214Smckusick 	register int flag;
2124736Swnj {
2134736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
2144736Swnj 
21534221Sbostic 	if ((flag & (FREAD | FWRITE)) == FWRITE ||
21634221Sbostic 	    ((flag & FWRITE) && (sc->sc_flags & H_WRITTEN)))
2174736Swnj 		mtcommand(dev, MT_CLS|sc->sc_dens, 1);
21817214Smckusick 	if ((minor(dev) & H_NOREWIND) == 0)
2194736Swnj 		mtcommand(dev, MT_REW, 0);
22034221Sbostic 	if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100)
22134221Sbostic 		log(LOG_INFO, "mu%d: %d soft errors in %d blocks\n",
22234221Sbostic 		    MUUNIT(dev), sc->sc_softerrs, sc->sc_blks);
2234736Swnj 	sc->sc_openf = 0;
22440733Skarels 	return (0);
2254736Swnj }
2264736Swnj 
mtcommand(dev,com,count)2274736Swnj mtcommand(dev, com, count)
2284736Swnj 	dev_t dev;
2294736Swnj 	int com, count;
2304736Swnj {
2314736Swnj 	register struct buf *bp;
23234221Sbostic 	int s;
2334736Swnj 
2344736Swnj 	bp = &cmtbuf[MTUNIT(dev)];
2355437Sroot 	s = spl5();
23617214Smckusick 	while (bp->b_flags & B_BUSY) {
23734221Sbostic 		if (bp->b_repcnt == 0 && (bp->b_flags & B_DONE))
2384736Swnj 			break;
2394736Swnj 		bp->b_flags |= B_WANTED;
2404736Swnj 		sleep((caddr_t)bp, PRIBIO);
2414736Swnj 	}
2424736Swnj 	bp->b_flags = B_BUSY|B_READ;
2435437Sroot 	splx(s);
2444736Swnj 	bp->b_dev = dev;
2454736Swnj 	bp->b_command = com;
2464736Swnj 	bp->b_repcnt = count;
2474736Swnj 	bp->b_blkno = 0;
24817214Smckusick 	bp->b_error = 0;
2494736Swnj 	mtstrategy(bp);
2504736Swnj 	if (count == 0)
2514736Swnj 		return;
25234221Sbostic 	biowait(bp);
25317214Smckusick 	if (bp->b_flags & B_WANTED)
2544736Swnj 		wakeup((caddr_t)bp);
2554736Swnj 	bp->b_flags &= B_ERROR;
2564736Swnj }
2574736Swnj 
mtstrategy(bp)2584736Swnj mtstrategy(bp)
2594736Swnj 	register struct buf *bp;
2604736Swnj {
2614736Swnj 	register struct buf *dp;
26234221Sbostic 	struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)];
26334221Sbostic 	int s;
2644736Swnj 
26534221Sbostic 	/*
26634221Sbostic 	 * If this is a data transfer operation, set the resid to a
26734221Sbostic 	 * default value (EOF) to simplify getting it right during
26834221Sbostic 	 * error recovery or bail out.
26934221Sbostic 	 */
27017214Smckusick 	if (bp != &cmtbuf[MTUNIT(bp->b_dev)])
27117214Smckusick 		bp->b_resid = bp->b_bcount;
27217214Smckusick 
27334221Sbostic 	/*
27434221Sbostic 	 * Link this request onto the end of the queue for this
27534221Sbostic 	 * controller, then start I/O if not already active.
27634221Sbostic 	 */
2774736Swnj 	bp->av_forw = NULL;
2784736Swnj 	dp = &mi->mi_tab;
2795437Sroot 	s = spl5();
2804736Swnj 	if (dp->b_actf == NULL)
2814736Swnj 		dp->b_actf = bp;
2824736Swnj 	else
2834736Swnj 		dp->b_actl->av_forw = bp;
2844736Swnj 	dp->b_actl = bp;
2854736Swnj 	if (dp->b_active == 0)
2864736Swnj 		mbustart(mi);
2875437Sroot 	splx(s);
2884736Swnj }
2894736Swnj 
mtustart(mi)2904736Swnj mtustart(mi)
2914736Swnj 	register struct mba_device *mi;
2924736Swnj {
29317214Smckusick 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
2944736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
2954736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
2964736Swnj 	daddr_t blkno;
29726377Skarels 	int count;
2984736Swnj 
2994736Swnj 	if (sc->sc_openf < 0) {
3004736Swnj 		bp->b_flags |= B_ERROR;
3014736Swnj 		return (MBU_NEXT);
3024736Swnj 	}
3034736Swnj 	if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) {
30434221Sbostic 		/*
30534221Sbostic 		 * Data transfer.  If write at end of tape,
30634221Sbostic 		 * signal "no space" unless suppressed
30734221Sbostic 		 * by MTIOCIEOT.
30834221Sbostic 		 */
30934221Sbostic 		if ((sc->sc_flags & (H_EOT | H_IEOT)) == H_EOT &&
31034221Sbostic 		    (bp->b_flags & B_READ) == 0) {
3114736Swnj 			bp->b_flags |= B_ERROR;
31217214Smckusick 			bp->b_error = ENOSPC;
3134736Swnj 			return (MBU_NEXT);
3144736Swnj 		}
31517214Smckusick 
31634221Sbostic 		if (bp->b_flags & B_RAW) {
31734221Sbostic 			/* raw transfer; never seek */
31834221Sbostic 			sc->sc_blkno = bdbtofsb(bp->b_blkno);
31934221Sbostic 			sc->sc_nxrec = sc->sc_blkno + 1;
32034221Sbostic 		} else {
32117214Smckusick 			/* seek beyond end of file */
32217214Smckusick 			if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) {
32317214Smckusick 				bp->b_flags |= B_ERROR;
32417214Smckusick 				bp->b_error = ENXIO;
32517214Smckusick 				return (MBU_NEXT);
32617214Smckusick 			}
32717214Smckusick 
32834221Sbostic 			/*
32934221Sbostic 			 * This should be end of file, but the buffer
33034221Sbostic 			 * system wants a one-block look-ahead.  Humor it.
33134221Sbostic 			 */
33234221Sbostic 			if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec &&
33334221Sbostic 			    bp->b_flags & B_READ) {
33434221Sbostic 				bp->b_resid = bp->b_bcount;
33517214Smckusick 				clrbuf(bp);
33617214Smckusick 				return (MBU_NEXT);
33717214Smckusick 			}
33817214Smckusick 
33917214Smckusick 			/* If writing, mark the next block invalid. */
34017214Smckusick 			if ((bp->b_flags & B_READ) == 0)
34117214Smckusick 				sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1;
3424736Swnj 		}
3434736Swnj 	} else {
34417214Smckusick 		/* It's a command, do it now. */
3454736Swnj 		mtaddr->mtncs[MUUNIT(bp->b_dev)] =
3464736Swnj 			(bp->b_repcnt<<8)|bp->b_command|MT_GO;
3474736Swnj 		return (MBU_STARTED);
3484736Swnj 	}
34917214Smckusick 
35034221Sbostic 	/*
35134221Sbostic 	 * If raw I/O, or if the tape is positioned correctly for
35234221Sbostic 	 * cooked I/O, set the byte count, unit number and repeat count
35334221Sbostic 	 * then tell the MASSBUS to proceed.  Note that a negative
35434221Sbostic 	 * bcount tells mbstart to map the buffer for "read backwards".
35534221Sbostic 	 */
35634221Sbostic 	if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) {
3574736Swnj 		if (mi->mi_tab.b_errcnt == 2) {
35834221Sbostic 			mtaddr->mtbc = -bp->b_bcount;
3594736Swnj 			mtaddr->mtca = MUUNIT(bp->b_dev);
3604736Swnj 		} else {
3614736Swnj 			mtaddr->mtbc = bp->b_bcount;
3624736Swnj 			mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev);
3634736Swnj 		}
3644736Swnj 		return (MBU_DODATA);
3654736Swnj 	}
36617214Smckusick 
36717214Smckusick 	/* Issue skip operations to position the next block for cooked I/O. */
36817214Smckusick 
3697380Ssam 	if (blkno < bdbtofsb(bp->b_blkno))
37034221Sbostic 		count = bdbtofsb(bp->b_blkno) - blkno;
3714736Swnj 	else
37234221Sbostic 		count = blkno - bdbtofsb(bp->b_blkno);
37334221Sbostic 	if ((unsigned)count > 0377)
37426377Skarels 		count = 0377;
37526377Skarels 	mtaddr->mtncs[MUUNIT(bp->b_dev)] = count | MT_SFORW|MT_GO;
3764736Swnj 	return (MBU_STARTED);
3774736Swnj }
3784736Swnj 
mtstart(mi)3794736Swnj mtstart(mi)
3804736Swnj 	register struct mba_device *mi;
3814736Swnj {
3824736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
3834736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
3844736Swnj 
3854736Swnj 	if (bp->b_flags & B_READ)
3864736Swnj 		if (mi->mi_tab.b_errcnt == 2)
38734221Sbostic 			return (MT_READREV|MT_GO);
3884736Swnj 		else
38934221Sbostic 			return (MT_READ|MT_GO);
3904736Swnj 	else
39134221Sbostic 		return (MT_WRITE|sc->sc_dens|MT_GO);
3924736Swnj }
3934736Swnj 
mtdtint(mi,mbsr)3944736Swnj mtdtint(mi, mbsr)
3954736Swnj 	register struct mba_device *mi;
3964736Swnj 	int mbsr;
3974736Swnj {
3984736Swnj 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
3994736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
4004736Swnj 	register struct mu_softc *sc;
40117214Smckusick 	register int er;
4024736Swnj 
40317214Smckusick 	/* I'M still NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */
40417214Smckusick 	if ((mtaddr->mtca & 3) != MUUNIT(bp->b_dev)) {
4054736Swnj 		printf("mt: wrong unit!\n");
4064736Swnj 		mtaddr->mtca = MUUNIT(bp->b_dev);
4074736Swnj 	}
40817214Smckusick 
40917214Smckusick 	er = MASKREG(mtaddr->mter);
4104736Swnj 	sc = &mu_softc[MUUNIT(bp->b_dev)];
41117214Smckusick 	sc->sc_erreg = er;
41217214Smckusick 	if (bp->b_flags & B_READ)
41317214Smckusick 		sc->sc_flags &= ~H_WRITTEN;
41417214Smckusick 	else
4154736Swnj 		sc->sc_flags |= H_WRITTEN;
41617214Smckusick 	switch (er & MTER_INTCODE) {
41717214Smckusick 
41817214Smckusick 	case MTER_EOT:
41917214Smckusick 		sc->sc_flags |= H_EOT;
42017214Smckusick 		/* fall into MTER_DONE */
42117214Smckusick 
4224736Swnj 	case MTER_DONE:
42317214Smckusick 		sc->sc_blkno++;
42417214Smckusick 		if (mi->mi_tab.b_errcnt == 2) {
42517214Smckusick 			bp->b_bcount = bp->b_resid;
42617214Smckusick 			bp->b_resid -= MASKREG(mtaddr->mtbc);
42734221Sbostic 			if (bp->b_resid > 0 && (bp->b_flags & B_RAW) == 0)
42817214Smckusick 				bp->b_flags |= B_ERROR;
42934221Sbostic 		} else
43017214Smckusick 			bp->b_resid = 0;
43117214Smckusick 		break;
43217214Smckusick 
43317214Smckusick 	case MTER_SHRTREC:
43417214Smckusick 		sc->sc_blkno++;
43517214Smckusick 		bp->b_bcount = bp->b_resid;
43617214Smckusick 		bp->b_resid -= MASKREG(mtaddr->mtbc);
43734221Sbostic 		if ((bp->b_flags & B_RAW) == 0)
43817214Smckusick 			bp->b_flags |= B_ERROR;
43917214Smckusick 		break;
44017214Smckusick 
44117214Smckusick 	case MTER_RETRY:
44234221Sbostic 		/*
44334221Sbostic 		 * Simple re-try.  Since resid is always a copy of the
44434221Sbostic 		 * original byte count, use it to restore the count.
44534221Sbostic 		 */
44617214Smckusick 		mi->mi_tab.b_errcnt = 1;
44717214Smckusick 		bp->b_bcount = bp->b_resid;
44834221Sbostic 		return (MBD_RETRY);
44917214Smckusick 
45017214Smckusick 	case MTER_RDOPP:
45134221Sbostic 		/*
45234221Sbostic 		 * The controller just decided to read it backwards.
45334221Sbostic 		 * If the controller returns a byte count of zero,
45434221Sbostic 		 * change it to 1, since zero encodes 65536, which
45534221Sbostic 		 * isn't quite what we had in mind.  The byte count
45634221Sbostic 		 * may be larger than the size of the input buffer, so
45734221Sbostic 		 * limit the count to the buffer size.  After
45834221Sbostic 		 * making the byte count reasonable, set bcount to the
45934221Sbostic 		 * negative of the controller's version of the byte
46034221Sbostic 		 * count so that the start address for the transfer is
46134221Sbostic 		 * set up correctly.
46234221Sbostic 		 */
46317214Smckusick 		if (mt_do_readrev) {
46417214Smckusick 			mi->mi_tab.b_errcnt = 2;
46517214Smckusick 			if ((bp->b_bcount = MASKREG(mtaddr->mtbc)) == 0)
46617214Smckusick 				bp->b_bcount = 1;
46717214Smckusick 			if (bp->b_bcount > bp->b_resid)
46817214Smckusick 				bp->b_bcount = bp->b_resid;
46917214Smckusick 			bp->b_bcount = -(bp->b_bcount);
47017214Smckusick 			return(MBD_RETRY);
47117214Smckusick 		} else if (MASKREG(mtaddr->mtbc) <= bp->b_resid) {
47217214Smckusick 			sc->sc_blkno++;
47317214Smckusick 			bp->b_bcount = bp->b_resid;
47417214Smckusick 			bp->b_resid -= MASKREG(mtaddr->mtbc);
47517214Smckusick 			bp->b_flags |= B_ERROR;
47617214Smckusick 			break;
47717214Smckusick 		}
47817214Smckusick 		bp->b_flags |= B_ERROR;
47917214Smckusick 		/* fall into MTER_LONGREC */
48017214Smckusick 
4814736Swnj 	case MTER_LONGREC:
48217214Smckusick 		sc->sc_blkno++;
48317214Smckusick 		bp->b_bcount = bp->b_resid;
4844736Swnj 		bp->b_resid = 0;
48517214Smckusick 		bp->b_error = ENOMEM;
48617214Smckusick 		bp->b_flags |= B_ERROR;
4874736Swnj 		break;
4884736Swnj 
4894736Swnj 	case MTER_NOTCAP:
4904736Swnj 		printf("mu%d: blank tape\n", MUUNIT(bp->b_dev));
4914736Swnj 		goto err;
4924736Swnj 
4934736Swnj 	case MTER_TM:
49434221Sbostic 		/*
49534221Sbostic 		 * End of file.  Since the default byte count has
49634221Sbostic 		 * already been set, just count the block and proceed.
49734221Sbostic 		 */
4984736Swnj 		sc->sc_blkno++;
4994736Swnj 	err:
50034221Sbostic 		sc->sc_nxrec = bdbtofsb(bp->b_blkno);
5014736Swnj 		break;
5024736Swnj 
5034736Swnj 	case MTER_OFFLINE:
5044736Swnj 		if (sc->sc_openf > 0) {
5054736Swnj 			sc->sc_openf = -1;
50640899Ssklower 			tprintf(sc->sc_ctty, "mu%d: offline\n",
50734221Sbostic 			    MUUNIT(bp->b_dev));
5084736Swnj 		}
5094736Swnj 		bp->b_flags |= B_ERROR;
5104736Swnj 		break;
5114736Swnj 
51217214Smckusick 	case MTER_NOTAVL:
51317214Smckusick 		if (sc->sc_openf > 0) {
51417214Smckusick 			sc->sc_openf = -1;
51540899Ssklower 			tprintf(sc->sc_ctty, "mu%d: offline (port selector)\n",
51618324Sralph 			    MUUNIT(bp->b_dev));
51717214Smckusick 		}
51817214Smckusick 		bp->b_flags |= B_ERROR;
51917214Smckusick 		break;
52017214Smckusick 
5214736Swnj 	case MTER_FPT:
52240899Ssklower 		tprintf(sc->sc_ctty, "mu%d: no write ring\n",
52334221Sbostic 		    MUUNIT(bp->b_dev));
5244736Swnj 		bp->b_flags |= B_ERROR;
5254736Swnj 		break;
5264736Swnj 
52717214Smckusick 	case MTER_UNREAD:
52817214Smckusick 		sc->sc_blkno++;
52917214Smckusick 		bp->b_bcount = bp->b_resid;
53017214Smckusick 		bp->b_resid -= MIN(MASKREG(mtaddr->mtbc), bp->b_bcount);
53117214Smckusick 
53234221Sbostic 		/* code 010 means a garbage record, nothing serious. */
53334221Sbostic 		if ((er & MTER_FAILCODE) == (010 << MTER_FSHIFT)) {
53440899Ssklower 			tprintf(sc->sc_ctty,
53534221Sbostic 			    "mu%d: rn=%d bn=%d unreadable record\n",
53617214Smckusick 			    MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno);
53717214Smckusick 			bp->b_flags |= B_ERROR;
53817214Smckusick 			break;
53917214Smckusick 		}
54017214Smckusick 
54134221Sbostic 		/*
54234221Sbostic 		 * Anything else might be a hardware problem,
54334221Sbostic 		 * fall into the error report.
54434221Sbostic 		 */
54517214Smckusick 
5464736Swnj 	default:
54734221Sbostic 		/*
54834221Sbostic 		 * The bits in sc->sc_dsreg are from the last sense
54934221Sbostic 		 * command.  To get the most recent copy, you have to
55034221Sbostic 		 * do a sense at interrupt level, which requires nested
55134221Sbostic 		 * error processing.  This is a bit messy, so leave
55234221Sbostic 		 * well enough alone.
55334221Sbostic 		 */
55440899Ssklower 		tprintf(sc->sc_ctty, "\
55534221Sbostic mu%d: hard error (data transfer) rn=%d bn=%d mbsr=%b er=0%o ds=%b\n",
55617214Smckusick 		    MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno,
55717214Smckusick 		    mbsr, mbsr_bits, er,
55817214Smckusick 		    MASKREG(sc->sc_dsreg), mtds_bits);
55917214Smckusick #ifdef MTLERRM
56034221Sbostic 		mtintfail(er);
56117214Smckusick #endif
5624736Swnj 		bp->b_flags |= B_ERROR;
56317214Smckusick 
56434221Sbostic 		/*
56534221Sbostic 		 * The TM78 manual says to reset the controller after
56634221Sbostic 		 * TM fault B or MASSBUS fault.
56734221Sbostic 		 */
56834221Sbostic 		if ((er & MTER_INTCODE) == MTER_TMFLTB ||
56934221Sbostic 		    (er & MTER_INTCODE) == MTER_MBFLT)
57017214Smckusick 			mtcreset(mtaddr);
5714736Swnj 	}
57217214Smckusick 
57334221Sbostic 	/*
57434221Sbostic 	 * Just in case some strange error slipped through (drive off
57534221Sbostic 	 * line during read-reverse error recovery comes to mind), make
57634221Sbostic 	 * sure the byte count is reasonable.
57734221Sbostic 	 */
57817214Smckusick 	if (bp->b_bcount < 0)
57917214Smckusick 		bp->b_bcount = bp->b_resid;
58034221Sbostic 
58134221Sbostic 	if ((bp->b_flags & B_ERROR) == 0) {
58234221Sbostic 		/* this counts reverse reads as soft errors */
58334221Sbostic 		sc->sc_blks++;
58434221Sbostic 		if (mi->mi_tab.b_errcnt) /* alternatively, if == 1 */
58534221Sbostic 			sc->sc_softerrs++;
58634221Sbostic 	}
5874736Swnj 	return (MBD_DONE);
5884736Swnj }
5894736Swnj 
mtndtint(mi)5904736Swnj mtndtint(mi)
5914736Swnj 	register struct mba_device *mi;
5924736Swnj {
5934736Swnj 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
5944736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
5954736Swnj 	register struct mu_softc *sc;
59617214Smckusick 	register int er, fc;
59717214Smckusick 	int unit;
5984736Swnj 
5994736Swnj 	unit = (mtaddr->mtner >> 8) & 3;
6004736Swnj 	er = MASKREG(mtaddr->mtner);
60117214Smckusick 	sc = &mu_softc[unit];
60217214Smckusick 	sc->sc_erreg = er;
60317214Smckusick 
60417214Smckusick 	/* Check for unsolicited interrupts. */
60534221Sbostic 	if (bp == NULL || unit != MUUNIT(bp->b_dev)) {
60634221Sbostic 		if ((er & MTER_INTCODE) == MTER_ONLINE)
60734221Sbostic 			return (MBN_SKIP);
60817214Smckusick 
60934221Sbostic 		printf("mu%d: stray intr (non data transfer) er=0%o ds=%b\n",
61034221Sbostic 		    unit, er, MASKREG(sc->sc_dsreg), mtds_bits);
61117214Smckusick #ifdef MTLERRM
61234221Sbostic 		mtintfail(er);
61317214Smckusick #endif
61434221Sbostic 		if ((er & MTER_INTCODE) == MTER_TMFLTB ||
61534221Sbostic 		    (er & MTER_INTCODE) == MTER_MBFLT) {
61634221Sbostic 			/*
61734221Sbostic 			 * Reset the controller, then set error status
61834221Sbostic 			 * if there was anything active when the fault
61934221Sbostic 			 * occurred.  This may shoot an innocent
62034221Sbostic 			 * bystander, but it's better than letting
62134221Sbostic 			 * an error slip through.
62234221Sbostic 			 */
62334221Sbostic 			mtcreset(mtaddr);
62434221Sbostic 			if (bp != NULL) {
62534221Sbostic 				bp->b_flags |= B_ERROR;
62634221Sbostic 				return (MBN_DONE);
62717214Smckusick 			}
62817214Smckusick 		}
6294736Swnj 		return (MBN_SKIP);
6304736Swnj 	}
63117214Smckusick 
6324736Swnj 	fc = (mtaddr->mtncs[unit] >> 8) & 0xff;
6334736Swnj 	sc->sc_resid = fc;
63417214Smckusick 
63534221Sbostic 	/*
63634221Sbostic 	 * Clear the "written" flag after any operation that changes
63734221Sbostic 	 * the position of the tape.
63834221Sbostic 	 */
63934221Sbostic 	if (bp != &cmtbuf[MTUNIT(bp->b_dev)] || bp->b_command != MT_SENSE)
64017214Smckusick 		sc->sc_flags &= ~H_WRITTEN;
64117214Smckusick 
6424736Swnj 	switch (er & MTER_INTCODE) {
64317214Smckusick 
64417214Smckusick 	case MTER_EOT:
64517214Smckusick 		sc->sc_flags |= H_EOT;
64617214Smckusick 		/* fall into MTER_DONE */
64717214Smckusick 
6484736Swnj 	case MTER_DONE:
64917214Smckusick 		/* If this is a command buffer, just update the status.	*/
6504736Swnj 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) {
6514736Swnj 	done:
6524736Swnj 			if (bp->b_command == MT_SENSE)
6534736Swnj 				sc->sc_dsreg = MASKREG(mtaddr->mtds);
6544736Swnj 			return (MBN_DONE);
6554736Swnj 		}
65617214Smckusick 
65734221Sbostic 		/*
65834221Sbostic 		 * It's not a command buffer, must be a cooked I/O
65934221Sbostic 		 * skip operation (perhaps a shaky assumption, but it
66034221Sbostic 		 * wasn't my idea).
66134221Sbostic 		 */
6627380Ssam 		if ((fc = bdbtofsb(bp->b_blkno) - sc->sc_blkno) < 0)
6636186Ssam 			sc->sc_blkno -= MIN(0377, -fc);
6644736Swnj 		else
6656186Ssam 			sc->sc_blkno += MIN(0377, fc);
6664736Swnj 		return (MBN_RETRY);
6674736Swnj 
66817214Smckusick 	case MTER_ONLINE:		/* ddj -- shouldn't happen but did */
6694736Swnj 	case MTER_RWDING:
6704736Swnj 		return (MBN_SKIP);	/* ignore "rewind started" interrupt */
6714736Swnj 
6724736Swnj 	case MTER_NOTCAP:
67340899Ssklower 		tprintf(sc->sc_ctty, "mu%d: blank tape\n", MUUNIT(bp->b_dev));
67417214Smckusick 		bp->b_flags |= B_ERROR;
67517214Smckusick 		return (MBN_DONE);
6764736Swnj 
6774736Swnj 	case MTER_TM:
6784736Swnj 	case MTER_LEOT:
67934221Sbostic 		/*
68034221Sbostic 		 * For an ioctl skip operation, count a tape mark as
68134221Sbostic 		 * a record.  If there's anything left to do, update
68234221Sbostic 		 * the repeat count and re-start the command.
68334221Sbostic 		 */
68417214Smckusick 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) {
68517214Smckusick 			if ((sc->sc_resid = bp->b_repcnt = fc - 1) == 0)
68617214Smckusick 				return (MBN_DONE);
68717214Smckusick 			else
68817214Smckusick 				return (MBN_RETRY);
6894736Swnj 		} else {
69034221Sbostic 			/*
69134221Sbostic 			 * Cooked I/O again.  Just update the books and
69234221Sbostic 			 * wait for someone else to return end of file or
69334221Sbostic 			 * complain about a bad seek.
69434221Sbostic 			 */
69534221Sbostic 			if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) {
69634221Sbostic 				sc->sc_nxrec = bdbtofsb(bp->b_blkno) + fc - 1;
69734221Sbostic 				sc->sc_blkno = sc->sc_nxrec;
69834221Sbostic 			} else {
69934221Sbostic 				sc->sc_nxrec = bdbtofsb(bp->b_blkno) - fc;
70034221Sbostic 				sc->sc_blkno = sc->sc_nxrec + 1;
70134221Sbostic 			}
7024736Swnj 		}
7034736Swnj 		return (MBN_RETRY);
7044736Swnj 
7054736Swnj 	case MTER_FPT:
70640899Ssklower 		tprintf(sc->sc_ctty, "mu%d: no write ring\n",
70734221Sbostic 		    MUUNIT(bp->b_dev));
7084736Swnj 		bp->b_flags |= B_ERROR;
7094736Swnj 		return (MBN_DONE);
7104736Swnj 
7114736Swnj 	case MTER_OFFLINE:
71217214Smckusick 		/* If `off line' was intentional, don't complain. */
71334221Sbostic 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)] &&
71434221Sbostic 		    bp->b_command == MT_UNLOAD)
71517214Smckusick 			return(MBN_DONE);
7164736Swnj 		if (sc->sc_openf > 0) {
7174736Swnj 			sc->sc_openf = -1;
71840899Ssklower 			tprintf(sc->sc_ctty, "mu%d: offline\n",
71934221Sbostic 			    MUUNIT(bp->b_dev));
7204736Swnj 		}
7214736Swnj 		bp->b_flags |= B_ERROR;
7224736Swnj 		return (MBN_DONE);
7234736Swnj 
72417214Smckusick 	case MTER_NOTAVL:
72517214Smckusick 		if (sc->sc_openf > 0) {
72617214Smckusick 			sc->sc_openf = -1;
72740899Ssklower 			tprintf(sc->sc_ctty, "mu%d: offline (port selector)\n",
72834221Sbostic 			    MUUNIT(bp->b_dev));
72917214Smckusick 		}
73017214Smckusick 		bp->b_flags |= B_ERROR;
73117214Smckusick 		return (MBN_DONE);
73217214Smckusick 
7334736Swnj 	case MTER_BOT:
7344736Swnj 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)])
7354736Swnj 			goto done;
73617214Smckusick 		/* fall through */
73717214Smckusick 
7384736Swnj 	default:
73940899Ssklower 		tprintf(sc->sc_ctty, "\
74034221Sbostic mu%d: hard error (non data transfer) rn=%d bn=%d er=0%o ds=%b\n",
74117214Smckusick 		    MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno,
74217214Smckusick 		    er, MASKREG(sc->sc_dsreg), mtds_bits);
74317214Smckusick #ifdef MTLERRM
74434221Sbostic 		mtintfail(er);
74517214Smckusick #endif
74634221Sbostic 		if ((er & MTER_INTCODE) == MTER_TMFLTB ||
74734221Sbostic 		    (er & MTER_INTCODE) == MTER_MBFLT)
74817214Smckusick 			mtcreset(mtaddr);	/* reset the controller */
7494736Swnj 		bp->b_flags |= B_ERROR;
7504736Swnj 		return (MBN_DONE);
7514736Swnj 	}
7524736Swnj 	/* NOTREACHED */
7534736Swnj }
7544736Swnj 
75534221Sbostic void
mtcreset(mtaddr)75634221Sbostic mtcreset(mtaddr)
75717214Smckusick 	register struct mtdevice *mtaddr;
75817214Smckusick {
75917214Smckusick 	register int i;
76017214Smckusick 
76117214Smckusick 	mtaddr->mtid = MTID_CLR;		/* reset the TM78 */
76217214Smckusick 	DELAY(200);
76317214Smckusick 	for (i = MTTIMEOUT; i > 0; i--) {
76417214Smckusick 		DELAY(50);			/* don't nag */
76517214Smckusick 		if ((mtaddr->mtid & MTID_RDY) != 0)
76617214Smckusick 			return;			/* exit when ready */
76717214Smckusick 	}
76817214Smckusick 	printf("mt: controller hung\n");
76917214Smckusick }
77017214Smckusick 
7714736Swnj /*ARGSUSED*/
mtioctl(dev,cmd,data,flag)7727637Ssam mtioctl(dev, cmd, data, flag)
7734736Swnj 	dev_t dev;
7744736Swnj 	int cmd;
7757637Ssam 	caddr_t data;
7764736Swnj 	int flag;
7774736Swnj {
7784736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
7794736Swnj 	register struct buf *bp = &cmtbuf[MTUNIT(dev)];
78017214Smckusick 	register struct mtop *mtop;
78117214Smckusick 	register struct mtget *mtget;
78240909Ssklower 	int callcount, fcount, error = 0;
78317214Smckusick 	int op;
78417214Smckusick 
78517214Smckusick 	/* We depend on the values and order of the MT codes here. */
78617214Smckusick 
7874736Swnj 	static mtops[] =
7884736Swnj 	{MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE};
7894736Swnj 
7904736Swnj 	switch (cmd) {
7917637Ssam 
79217214Smckusick 	/* tape operation */
79317214Smckusick 
79417214Smckusick 	case MTIOCTOP:
7958606Sroot 		mtop = (struct mtop *)data;
7968606Sroot 		switch (mtop->mt_op) {
7977637Ssam 
7984736Swnj 		case MTWEOF:
7997637Ssam 			callcount = mtop->mt_count;
8004736Swnj 			fcount = 1;
8014736Swnj 			break;
8027637Ssam 
8034736Swnj 		case MTFSF: case MTBSF:
8047637Ssam 			callcount = mtop->mt_count;
8054736Swnj 			fcount = 1;
8064736Swnj 			break;
8077637Ssam 
8084736Swnj 		case MTFSR: case MTBSR:
8094736Swnj 			callcount = 1;
8107637Ssam 			fcount = mtop->mt_count;
8114736Swnj 			break;
8127637Ssam 
8134736Swnj 		case MTREW: case MTOFFL:
8144736Swnj 			callcount = 1;
8154736Swnj 			fcount = 1;
8164736Swnj 			break;
8177637Ssam 
8184736Swnj 		default:
8198581Sroot 			return (ENXIO);
8204736Swnj 		}
82134221Sbostic 		if (callcount <= 0 || fcount <= 0)
8228581Sroot 			return (EINVAL);
8237637Ssam 		op = mtops[mtop->mt_op];
8244736Swnj 		if (op == MT_WTM)
8254736Swnj 			op |= sc->sc_dens;
8264736Swnj 		while (--callcount >= 0) {
82717214Smckusick 			register int n, fc = fcount;
8284736Swnj 
8294736Swnj 			do {
83017214Smckusick 				n = MIN(fc, 0xff);
8314736Swnj 				mtcommand(dev, op, n);
83217214Smckusick 				n -= sc->sc_resid;
83317214Smckusick 				fc -= n;
83417214Smckusick 				switch (mtop->mt_op) {
83517214Smckusick 
83617214Smckusick 				case MTWEOF:
83717214Smckusick 					sc->sc_blkno += (daddr_t)n;
83817214Smckusick 					sc->sc_nxrec = sc->sc_blkno - 1;
83917214Smckusick 					break;
84017214Smckusick 
84117214Smckusick 				case MTOFFL:
84217214Smckusick 				case MTREW:
84317214Smckusick 				case MTFSF:
84417214Smckusick 					sc->sc_blkno = (daddr_t)0;
84517214Smckusick 					sc->sc_nxrec = (daddr_t)INF;
84617214Smckusick 					break;
84717214Smckusick 
84817214Smckusick 				case MTBSF:
84917214Smckusick 					if (sc->sc_resid) {
85017214Smckusick 						sc->sc_blkno = (daddr_t)0;
85117214Smckusick 						sc->sc_nxrec = (daddr_t)INF;
85217214Smckusick 					} else {
85317214Smckusick 						sc->sc_blkno = (daddr_t)(-1);
85417214Smckusick 						sc->sc_nxrec = (daddr_t)(-1);
85517214Smckusick 					}
85617214Smckusick 					break;
85717214Smckusick 
85817214Smckusick 				case MTFSR:
85917214Smckusick 					sc->sc_blkno += (daddr_t)n;
86017214Smckusick 					break;
86117214Smckusick 
86217214Smckusick 				case MTBSR:
86317214Smckusick 					sc->sc_blkno -= (daddr_t)n;
86417214Smckusick 					break;
86517214Smckusick 				}
86617214Smckusick 				if (sc->sc_resid)
86717214Smckusick 					break;
86817214Smckusick 			} while (fc);
86917214Smckusick 			if (fc) {
87017214Smckusick 				sc->sc_resid = callcount + fc;
87134221Sbostic 				if (mtop->mt_op == MTFSR ||
87234221Sbostic 				    mtop->mt_op == MTBSR)
87317214Smckusick 					return (EIO);
87434221Sbostic 				break;
87517214Smckusick 			}
87617214Smckusick 			if (bp->b_flags & B_ERROR)
8774736Swnj 				break;
8784736Swnj 		}
87940909Ssklower 		if (bp->b_flags&B_ERROR)
88040909Ssklower 			if ((error = bp->b_error)==0)
88140909Ssklower 				return (EIO);
88240909Ssklower 		return (error);
8837637Ssam 
88417214Smckusick 	/* tape status */
8854736Swnj 	case MTIOCGET:
8867637Ssam 		mtget = (struct mtget *)data;
8877637Ssam 		mtget->mt_erreg = sc->sc_erreg;
8887637Ssam 		mtget->mt_resid = sc->sc_resid;
8894736Swnj 		mtcommand(dev, MT_SENSE, 1);	/* update drive status */
8907637Ssam 		mtget->mt_dsreg = sc->sc_dsreg;
8917637Ssam 		mtget->mt_type = MT_ISMT;
8928581Sroot 		break;
8937637Ssam 
89417214Smckusick 	/* ignore EOT condition */
89517214Smckusick 	case MTIOCIEOT:
89617214Smckusick 		sc->sc_flags |= H_IEOT;
89717214Smckusick 		break;
89817214Smckusick 
89917214Smckusick 	/* enable EOT condition */
90017214Smckusick 	case MTIOCEEOT:
90117214Smckusick 		sc->sc_flags &= ~H_IEOT;
90217214Smckusick 		break;
90317214Smckusick 
9044736Swnj 	default:
9058581Sroot 		return (ENXIO);
9064736Swnj 	}
9078581Sroot 	return (0);
9084736Swnj }
9094736Swnj 
9104736Swnj #define	DBSIZE	20
9114736Swnj 
mtdump()9124736Swnj mtdump()
9134736Swnj {
9144736Swnj 	register struct mba_device *mi;
9154736Swnj 	register struct mba_regs *mp;
9164736Swnj 	int blk, num;
9174736Swnj 	int start;
9184736Swnj 
9194736Swnj 	start = 0;
9204736Swnj 	num = maxfree;
9214736Swnj #define	phys(a,b)		((b)((int)(a)&0x7fffffff))
9224736Swnj 	if (mtinfo[0] == 0)
9234736Swnj 		return (ENXIO);
9244736Swnj 	mi = phys(mtinfo[0], struct mba_device *);
9254736Swnj 	mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba;
9264736Swnj 	mp->mba_cr = MBCR_IE;
9276186Ssam #if lint
9288606Sroot 	blk = 0; num = blk; start = num; blk = start;
9296186Ssam 	return (0);
9306186Ssam #endif
9316186Ssam #ifdef notyet
9324736Swnj 	mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive];
9334736Swnj 	mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI;
9344736Swnj 	mtaddr->mtcs1 = MT_DCLR|MT_GO;
9354736Swnj 	while (num > 0) {
9364736Swnj 		blk = num > DBSIZE ? DBSIZE : num;
9374736Swnj 		mtdwrite(start, blk, mtaddr, mp);
9384736Swnj 		start += blk;
9394736Swnj 		num -= blk;
9404736Swnj 	}
9414736Swnj 	mteof(mtaddr);
9424736Swnj 	mteof(mtaddr);
9434736Swnj 	mtwait(mtaddr);
9444736Swnj 	if (mtaddr->mtds&MTDS_ERR)
9454736Swnj 		return (EIO);
9464736Swnj 	mtaddr->mtcs1 = MT_REW|MT_GO;
9474736Swnj 	return (0);
9484736Swnj }
9494736Swnj 
mtdwrite(dbuf,num,mtaddr,mp)9504736Swnj mtdwrite(dbuf, num, mtaddr, mp)
9514736Swnj 	register dbuf, num;
9524736Swnj 	register struct mtdevice *mtaddr;
9534736Swnj 	struct mba_regs *mp;
9544736Swnj {
9554736Swnj 	register struct pte *io;
9564736Swnj 	register int i;
9574736Swnj 
9584736Swnj 	mtwait(mtaddr);
9594736Swnj 	io = mp->mba_map;
9604736Swnj 	for (i = 0; i < num; i++)
9614736Swnj 		*(int *)io++ = dbuf++ | PG_V;
9624736Swnj 	mtaddr->mtfc = -(num*NBPG);
9634736Swnj 	mp->mba_sr = -1;
9644736Swnj 	mp->mba_bcr = -(num*NBPG);
9654736Swnj 	mp->mba_var = 0;
9664736Swnj 	mtaddr->mtcs1 = MT_WCOM|MT_GO;
9674736Swnj }
9684736Swnj 
9694736Swnj mtwait(mtaddr)
9704736Swnj 	struct mtdevice *mtaddr;
9714736Swnj {
9724736Swnj 	register s;
9734736Swnj 
9744736Swnj 	do
9754736Swnj 		s = mtaddr->mtds;
9764736Swnj 	while ((s & MTDS_DRY) == 0);
9774736Swnj }
9784736Swnj 
9794736Swnj mteof(mtaddr)
9804736Swnj 	struct mtdevice *mtaddr;
9814736Swnj {
9824736Swnj 
9834736Swnj 	mtwait(mtaddr);
9844736Swnj 	mtaddr->mtcs1 = MT_WEOF|MT_GO;
9854736Swnj #endif notyet
9864736Swnj }
98717214Smckusick 
98817214Smckusick #ifdef MTLERRM
98934221Sbostic /*
99034221Sbostic  * Failure messages for each failure code, per interrupt code.
99134221Sbostic  * Each table ends with a code of -1 as a default.
99234221Sbostic  */
99334221Sbostic struct fmesg {
99434221Sbostic 	int	f_code;
99534221Sbostic 	char	*f_mesg;
99634221Sbostic };
99717214Smckusick 
99834221Sbostic static char unclass[] = "unclassified failure code";
99917214Smckusick 
100034221Sbostic /* MTER_BOT */
100134221Sbostic static struct fmesg botmsg[] = {
100234221Sbostic 	01,	"tape was at BOT",
100334221Sbostic 	02,	"BOT seen after tape started",
100434221Sbostic 	03,	"ARA ID detected",
100534221Sbostic 	-1,	unclass
100634221Sbostic };
100717214Smckusick 
100834221Sbostic /* MTER_NOTRDY */
100934221Sbostic static struct fmesg notrdymsg[] = {
101034221Sbostic 	01,	"TU on-line but not ready",
101134221Sbostic 	02,	"fatal error has occurred",
101236548Sbostic 	03,	"access allowed but not ready",
101334221Sbostic 	-1,	unclass
101434221Sbostic };
101517214Smckusick 
101634221Sbostic /* MTER_NOTCAP */
101734221Sbostic static struct fmesg notcapmsg[] = {
101834221Sbostic 	01,	"no record found within 25 feet",
101934221Sbostic 	02,	"ID burst neither PE nor GCR",
102034221Sbostic 	03,	"ARA ID not found",
102134221Sbostic 	04,	"no gap found after ID burst",
102234221Sbostic 	-1,	unclass
102334221Sbostic };
102417214Smckusick 
102534221Sbostic /* MTER_LONGREC */
102634221Sbostic static struct fmesg longrecmsg[] = {
102734221Sbostic 	00,	"extended sense data not found",
102834221Sbostic 	01,	"extended sense data updated",
102934221Sbostic 	-1,	unclass
103034221Sbostic };
103117214Smckusick 
103234221Sbostic /* MTER_UNREAD, MTER_ERROR, MTER_EOTERR, MTER_BADTAPE */
103334221Sbostic static struct fmesg code22msg[] = {
103434221Sbostic 	01,	"GCR write error",
103534221Sbostic 	02,	"GCR read error",
103634221Sbostic 	03,	"PE read error",
103734221Sbostic 	04,	"PE write error",
103834221Sbostic 	05,	"at least 1 bit set in ECCSTA",
103934221Sbostic 	06,	"PE write error",
104034221Sbostic 	07,	"GCR write error",
104134221Sbostic 	010,	"RSTAT contains bad code",
104234221Sbostic 	011,	"PE write error",
104334221Sbostic 	012,	"MASSBUS parity error",
104434221Sbostic 	013,	"invalid data transferred",
104534221Sbostic 	-1,	unclass
104634221Sbostic };
104717214Smckusick 
104834221Sbostic /* MTER_TMFLTA */
104934221Sbostic static struct fmesg tmfltamsg[] = {
105034221Sbostic 	01,	"illegal command code",
105134221Sbostic 	02,	"DT command issued when NDT command active",
105234221Sbostic 	03,	"WMC error",
105334221Sbostic 	04,	"RUN not received from MASSBUS controller",
105434221Sbostic 	05,	"mismatch in command read - function routine",
105534221Sbostic 	06,	"ECC ROM parity error",
105634221Sbostic 	07,	"XMC ROM parity error",
105734221Sbostic 	010,	"mismatch in command read - ID burst command",
105834221Sbostic 	011,	"mismatch in command read - verify ARA burst command",
105934221Sbostic 	012,	"mismatch in command read - verify ARA ID command",
106034221Sbostic 	013,	"mismatch in command read - verify gap command",
106134221Sbostic 	014,	"mismatch in command read - read id burst command",
106234221Sbostic 	015,	"mismatch in command read - verify ARA ID command",
106334221Sbostic 	016,	"mismatch in command read - verify gap command",
106434221Sbostic 	017,	"mismatch in command read - find gap command",
106534221Sbostic 	020,	"WMC LEFT failed to set",
106634221Sbostic 	021,	"XL PE set in INTSTA register",
106734221Sbostic 	022,	"XMC DONE did not set",
106834221Sbostic 	023,	"WMC ROM PE or RD PE set in WMCERR register",
106934221Sbostic 	-1,	unclass
107034221Sbostic };
107117214Smckusick 
107234221Sbostic /* MTER_TUFLTA */
107334221Sbostic static struct fmesg tufltamsg[] = {
107434221Sbostic 	01,	"TU status parity error",
107534221Sbostic 	02,	"TU command parity error",
107634221Sbostic 	03,	"rewinding tape went offline",
107734221Sbostic 	04,	"tape went not ready during DSE",
107834221Sbostic 	05,	"TU CMD status changed during DSE",
107934221Sbostic 	06,	"TU never came up to speed",
108034221Sbostic 	07,	"TU velocity changed",
108134221Sbostic 	010,	"TU CMD did not load correctly to start tape motion",
108234221Sbostic 	011,	"TU CMD did not load correctly to set drive density",
108334221Sbostic 	012,	"TU CMD did not load correctly to start tape motion to write BOT ID",
108434221Sbostic 	013,	"TU CMD did not load correctly to backup tape to BOT after failing to write BOT ID",
108534221Sbostic 	014,	"failed to write density ID burst",
108634221Sbostic 	015,	"failed to write ARA burst",
108734221Sbostic 	016,	"failed to write ARA ID",
108834221Sbostic 	017,	"ARA error bit set in MTA status B register",
108934221Sbostic 	021,	"could not find a gap after ID code was written correctly",
109034221Sbostic 	022,	"TU CMD did not load correctly to start tape motion to read ID burst",
109134221Sbostic 	023,	"timeout looking for BOT after detecting ARA ID burst",
109234221Sbostic 	024,	"failed to write tape mark",
109334221Sbostic 	025,	"tape never came up to speed while trying to reposition for retry of writing tape mark",
109434221Sbostic 	026,	"TU CMD did not load correctly to start tape motion in erase gap routine",
109534221Sbostic 	027,	"could not detect a gap in in erase gap routine",
109634221Sbostic 	030,	"could not detect a gap after writing record",
109734221Sbostic 	031,	"read path terminated before entire record was written",
109834221Sbostic 	032,	"could not find a gap after writing record and read path terminated early",
109934221Sbostic 	033,	"TU CMD did not load correctly to backup for retry of write tape mark",
110034221Sbostic 	034,	"TU velocity changed after up to speed while trying to reposition for retry of writing tape mark",
110134221Sbostic 	035,	"TU CMD did not load correctly to backup to retry a load of BOT ID",
110234221Sbostic 	036,	"timeout looking for BOT after failing to write BOT ID",
110334221Sbostic 	037,	"TU velocity changed while writing PE gap before starting to write record",
110434221Sbostic 	040,	"TU CMD did not load correctly to set PE tape density at start of write BOT ID burst",
110534221Sbostic 	041,	"TU CMD did not load correctly to set GCR tape density after writing Density ID",
110634221Sbostic 	042,	"TU CMD did not load correctly to set PE tape density at start of read from BOT",
110734221Sbostic 	043,	"TU CMD did not load correctly to set GCR tape density after reading a GCR Density ID burst",
110834221Sbostic };
110917214Smckusick 
111034221Sbostic /* MTER_TMFLTB */
111134221Sbostic static char inlinetest[] = "inline test failed";
111234221Sbostic static struct fmesg tmfltbmsg[] = {
111334221Sbostic 	00,	"RST0 interrupt occurred with TM RDY set",
111434221Sbostic 	01,	"power failed to interrupt",
111534221Sbostic 	02,	"unknown interrupt on channel 5.5",
111634221Sbostic 	03,	"unknown interrupt on channel 6.5",
111734221Sbostic 	04,	"unknown interrupt on channel 7",
111834221Sbostic 	05,	"unknown interrupt on channel 7.5",
111934221Sbostic 	06,	"CAS contention retry count expired",
112034221Sbostic 	07,	"CAS contention error not retryable",
112134221Sbostic 	010,	"queue error, could not find queue entry",
112234221Sbostic 	011,	"queue entry already full",
112334221Sbostic 	012,	"8085 ROM parity error",
112434221Sbostic 	013,	inlinetest,
112534221Sbostic 	013,	inlinetest,
112634221Sbostic 	014,	inlinetest,
112734221Sbostic 	015,	inlinetest,
112834221Sbostic 	016,	inlinetest,
112934221Sbostic 	017,	inlinetest,
113034221Sbostic 	020,	inlinetest,
113134221Sbostic 	021,	inlinetest,
113234221Sbostic 	022,	inlinetest,
113334221Sbostic 	023,	inlinetest,
113434221Sbostic 	024,	inlinetest,
113534221Sbostic 	025,	inlinetest,
113634221Sbostic 	026,	inlinetest,
113734221Sbostic 	027,	inlinetest,
113834221Sbostic 	030,	inlinetest,
113934221Sbostic 	031,	inlinetest,
114034221Sbostic 	032,	inlinetest,
114134221Sbostic 	033,	inlinetest,
114234221Sbostic 	034,	inlinetest,
114334221Sbostic 	035,	inlinetest,
114434221Sbostic 	036,	inlinetest,
114534221Sbostic 	037,	inlinetest,
114634221Sbostic 	040,	inlinetest,
114734221Sbostic 	041,	inlinetest,
114834221Sbostic 	042,	inlinetest,
114934221Sbostic 	043,	inlinetest,
115034221Sbostic 	044,	inlinetest,
115136548Sbostic 	045,	inlinetest,
115234221Sbostic 	046,	inlinetest,
115334221Sbostic 	047,	inlinetest,
115434221Sbostic 	050,	inlinetest,
115534221Sbostic 	051,	inlinetest,
115634221Sbostic 	052,	inlinetest,
115734221Sbostic 	053,	inlinetest,
115834221Sbostic 	054,	inlinetest,
115934221Sbostic 	055,	inlinetest,
116034221Sbostic 	056,	inlinetest,
116134221Sbostic 	057,	inlinetest,
116234221Sbostic 	-1,	unclass
116334221Sbostic };
116417214Smckusick 
116534221Sbostic /* MTER_MBFLT */
116634221Sbostic static struct fmesg mbfltmsg[] = {
116734221Sbostic 	01,	"control bus parity error",
116834221Sbostic 	02,	"illegal register referenced",
116934221Sbostic 	-1,	unclass
117034221Sbostic };
117117214Smckusick 
117234221Sbostic /*
117334221Sbostic  * MTER_LEOT, MTER_RWDING, NTER_NOTAVL, MTER_NONEX, MTER_KEYFAIL,
117434221Sbostic  * and default: no failure message.
117534221Sbostic  */
117634221Sbostic static struct fmesg nullmsg[] = {
117734221Sbostic 	-1,	""
117834221Sbostic };
117917214Smckusick 
118034221Sbostic /*
118134221Sbostic  * Interrupt code table.
118234221Sbostic  */
118334221Sbostic static struct errmsg {
118434221Sbostic 	int	e_code;
118534221Sbostic 	char	*e_mesg;
118634221Sbostic 	struct	fmesg *e_fmesg;
118734221Sbostic } errmsg[] = {
118834221Sbostic 	MTER_BOT,	"unexpected BOT",	botmsg,
118934221Sbostic 	MTER_LEOT,	"unexpected LEOT",	nullmsg,
119034221Sbostic 	MTER_RWDING,	"tape rewinding",	nullmsg,
119134221Sbostic 	MTER_NOTRDY,	"drive not ready",	notrdymsg,
119234221Sbostic 	MTER_NOTAVL,	"drive not available",	nullmsg,
119334221Sbostic 	MTER_NONEX,	"unit does not exist",	nullmsg,
119434221Sbostic 	MTER_NOTCAP,	"not capable",		notcapmsg,
119534221Sbostic 	MTER_LONGREC,	"long record",		longrecmsg,
119634221Sbostic 	MTER_UNREAD,	"unreadable record",	code22msg,
119734221Sbostic 	MTER_ERROR,	"error",		code22msg,
119834221Sbostic 	MTER_EOTERR,	"EOT error",		code22msg,
119934221Sbostic 	MTER_BADTAPE,	"tape position lost",	code22msg,
120034221Sbostic 	MTER_TMFLTA,	"TM fault A",		tmfltamsg,
120134221Sbostic 	MTER_TUFLTA,	"TU fault A",		tufltamsg,
120234221Sbostic 	MTER_TMFLTB,	"TM fault B",		tmfltbmsg,
120334221Sbostic 	MTER_MBFLT,	"MB fault",		mbfltmsg,
120434221Sbostic 	MTER_KEYFAIL,	"keypad entry error",	nullmsg,
120534221Sbostic 	-1,		"unclassified error",	nullmsg
120634221Sbostic };
120717214Smckusick 
120834221Sbostic /*
120934221Sbostic  * Decode an interrupt-time failure.
121034221Sbostic  */
mtintfail(erreg)121134221Sbostic mtintfail(erreg)
121234221Sbostic 	int erreg;
121334221Sbostic {
121434221Sbostic 	register struct errmsg *e;
121534221Sbostic 	register struct fmesg *f;
121634221Sbostic 	register int ecode, fcode;
121717214Smckusick 
121834221Sbostic 	ecode = erreg & MTER_INTCODE;
121934221Sbostic 	fcode = (erreg & MTER_FAILCODE) >> MTER_FSHIFT;
122034221Sbostic 	for (e = errmsg; e->e_code >= 0; e++)
122134221Sbostic 		if (e->e_code == ecode)
122217214Smckusick 			break;
122334221Sbostic 	for (f = e->e_fmesg; f->f_code >= 0; f++)
122434221Sbostic 		if (f->f_code == fcode)
122517214Smckusick 			break;
122634221Sbostic 	printf("    interrupt code = 0%o <%s>\n", ecode, e->e_mesg);
122734221Sbostic 	printf("    failure code = 0%o <%s>\n", fcode, f->f_mesg);
122817214Smckusick }
122934221Sbostic #endif /* MTLERRM */
123034221Sbostic #endif /* NMT > 0 */
1231