xref: /csrg-svn/sys/vax/mba/mt.c (revision 40733)
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*40733Skarels  *	@(#)mt.c	7.6 (Berkeley) 04/03/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 
2617119Sbloom #include "param.h"
2717119Sbloom #include "systm.h"
2817119Sbloom #include "buf.h"
2917119Sbloom #include "conf.h"
3017119Sbloom #include "file.h"
3117119Sbloom #include "user.h"
3217119Sbloom #include "map.h"
3317119Sbloom #include "ioctl.h"
3417119Sbloom #include "mtio.h"
3517119Sbloom #include "cmap.h"
3618324Sralph #include "tty.h"
3734221Sbostic #include "syslog.h"
384736Swnj 
3934221Sbostic #include "../vax/pte.h"
408471Sroot #include "../vax/cpu.h"
4117119Sbloom #include "mbareg.h"
4217119Sbloom #include "mbavar.h"
4317119Sbloom #include "mtreg.h"
444736Swnj 
4517214Smckusick #define MTTIMEOUT	10000		/* loop limit for controller test */
4617214Smckusick #define	INF		1000000L	/* a block number that won't exist */
4717214Smckusick #define MASKREG(r)	((r) & 0xffff)	/* the control registers have 16 bits */
484736Swnj 
4917214Smckusick /* Bits for sc_flags */
504736Swnj 
5117214Smckusick #define	H_WRITTEN	01		/* last operation was a write */
5217214Smckusick #define H_EOT		02		/* end of tape encountered */
5317214Smckusick #define H_IEOT		04		/* ignore EOT condition */
544736Swnj 
5534221Sbostic int	mt_do_readrev = 1;
5617214Smckusick 
5717214Smckusick /* Per unit status information */
5817214Smckusick 
594736Swnj struct	mu_softc {
6034221Sbostic 	char	sc_openf;	/* unit is open if != 0 */
6134221Sbostic 	char	sc_flags;	/* state flags */
6234221Sbostic 	daddr_t	sc_blkno;	/* current physical block number */
6334221Sbostic 	daddr_t	sc_nxrec;	/* firewall input block number */
6434221Sbostic 	u_short	sc_erreg;	/* copy of mter or mtner */
6534221Sbostic 	u_short	sc_dsreg;	/* copy of mtds */
6634221Sbostic 	short	sc_resid;	/* residual function count for ioctl */
6734221Sbostic 	short	sc_dens;	/* density code - MT_GCR or zero */
6834221Sbostic 	int	sc_i_mtas;	/* mtas at slave attach time */
6934221Sbostic 	int	sc_i_mtner;	/* mtner at slave attach time */
7034221Sbostic 	int	sc_i_mtds;	/* mtds at slave attach time */
7134221Sbostic 	struct	tty *sc_ttyp;	/* record user's tty for errors */
7234221Sbostic 	int	sc_blks;	/* number of I/O operations since open */
7334221Sbostic 	int	sc_softerrs;	/* number of soft I/O errors since open */
744736Swnj } mu_softc[NMU];
754736Swnj 
7617214Smckusick struct	buf	cmtbuf[NMT];		/* tape command buffer structures */
774736Swnj 
7834221Sbostic struct	mba_device *mtinfo[NMT];	/* unit to ctlr structures */
7934221Sbostic struct	mba_slave *muinfo[NMU];		/* unit to slave structures */
8034221Sbostic 
8117214Smckusick char	mtds_bits[] = MTDS_BITS;	/* mtds bit names for error messages */
8217214Smckusick short	mttypes[] = { MBDT_TU78, 0 };
834736Swnj 
8417214Smckusick int	mtattach(), mtslave(), mtustart(), mtstart(), mtndtint(), mtdtint();
8517214Smckusick struct	mba_driver mtdriver =
8617214Smckusick 	{ mtattach, mtslave, mtustart, mtstart, mtdtint, mtndtint,
8717214Smckusick 	  mttypes, "mt", "mu", mtinfo };
8817214Smckusick 
8934221Sbostic /* Bits in minor device */
9034221Sbostic #define	MUUNIT(dev)	(minor(dev)&03)
9134221Sbostic #define	H_NOREWIND	04
9234221Sbostic #define	H_6250BPI	010
9317214Smckusick 
9434221Sbostic #define MTUNIT(dev)	(muinfo[MUUNIT(dev)]->ms_ctlr)
9534221Sbostic 
9634221Sbostic void	mtcreset();
9734221Sbostic 
984736Swnj /*ARGSUSED*/
994736Swnj mtattach(mi)
1004736Swnj 	struct mba_device *mi;
1014736Swnj {
10234221Sbostic 
10334221Sbostic 	/* void */
1044736Swnj }
1054736Swnj 
1067431Skre mtslave(mi, ms, sn)
1074736Swnj 	struct mba_device *mi;
1084736Swnj 	struct mba_slave *ms;
1097431Skre 	int sn;
1104736Swnj {
1114736Swnj 	register struct mu_softc *sc = &mu_softc[ms->ms_unit];
1124736Swnj 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
11326377Skarels 	int s = spl5(), rtn = 0, i;
1144736Swnj 
11534221Sbostic 	/*
11634221Sbostic 	 * Just in case the controller is ill, reset it.  Then issue
11734221Sbostic 	 * a sense operation and wait about a second for it to respond.
11834221Sbostic 	 */
11917214Smckusick 	mtcreset(mtaddr);
1204736Swnj 	mtaddr->mtas = -1;
1217431Skre 	mtaddr->mtncs[sn] = MT_SENSE|MT_GO;
12234221Sbostic 	for (i = MTTIMEOUT; i > 0; i--) {
12317214Smckusick 		DELAY(50);
12417214Smckusick 		if (MASKREG(mtaddr->mtas) != 0)
12517214Smckusick 			break;
12617214Smckusick 	}
12717214Smckusick 	sc->sc_i_mtas = mtaddr->mtas;
12817214Smckusick 	sc->sc_i_mtner = mtaddr->mtner;
12917214Smckusick 	sc->sc_i_mtds = mtaddr->mtds;
13017214Smckusick 
13134221Sbostic 	/*
13234221Sbostic 	 * If no response, whimper.  If wrong response, call it an
13334221Sbostic 	 * unsolicited interrupt and use mtndtint to log and correct.
13434221Sbostic 	 * Otherwise, note whether this slave exists.
13534221Sbostic 	 */
13634221Sbostic 	if (i <= 0)
13717214Smckusick 		printf("mt: controller hung\n");
13834221Sbostic 	else if ((mtaddr->mtner & MTER_INTCODE) != MTER_DONE)
13917214Smckusick 		(void) mtndtint(mi);
14034654Skarels 	else if (mtaddr->mtds & MTDS_PRES) {
14134654Skarels 		muinfo[ms->ms_unit] = ms;
1424736Swnj 		rtn = 1;
14334654Skarels 	}
14417214Smckusick 
14534221Sbostic 	/* cancel the interrupt, then wait a little while for it to go away */
1464736Swnj 	mtaddr->mtas = mtaddr->mtas;
14717214Smckusick 	DELAY(10);
1484736Swnj 	splx(s);
1494736Swnj 	return (rtn);
1504736Swnj }
1514736Swnj 
1524736Swnj mtopen(dev, flag)
1534736Swnj 	dev_t dev;
1544736Swnj 	int flag;
1554736Swnj {
1564736Swnj 	register int muunit;
1574736Swnj 	register struct mu_softc *sc;
15834221Sbostic 	register struct mba_slave *ms;
1594736Swnj 
1604736Swnj 	muunit = MUUNIT(dev);
16134221Sbostic 	if (muunit >= NMU || (ms = muinfo[muunit]) == NULL ||
16234221Sbostic 	    ms->ms_alive == 0 || mtinfo[ms->ms_ctlr]->mi_alive == 0)
1638581Sroot 		return (ENXIO);
16417214Smckusick 	if ((sc = &mu_softc[muunit])->sc_openf)
16517214Smckusick 		return (EBUSY);
16634221Sbostic 	sc->sc_openf = 1;
16717214Smckusick 	sc->sc_dens = (minor(dev) & H_6250BPI) ? MT_GCR : 0;
1684736Swnj 	mtcommand(dev, MT_SENSE, 1);
1694736Swnj 	if ((sc->sc_dsreg & MTDS_ONL) == 0) {
1704736Swnj 		uprintf("mu%d: not online\n", muunit);
17134221Sbostic 		sc->sc_openf = 0;
1728581Sroot 		return (EIO);
1734736Swnj 	}
17417214Smckusick 	if ((sc->sc_dsreg & MTDS_AVAIL) == 0) {
17517214Smckusick 		uprintf("mu%d: not online (port selector)\n", muunit);
17634221Sbostic 		sc->sc_openf = 0;
17717214Smckusick 		return (EIO);
17817214Smckusick 	}
17917214Smckusick 	if ((flag & FWRITE) && (sc->sc_dsreg & MTDS_FPT)) {
1804736Swnj 		uprintf("mu%d: no write ring\n", muunit);
18134221Sbostic 		sc->sc_openf = 0;
1828581Sroot 		return (EIO);
1834736Swnj 	}
18434221Sbostic 	if ((sc->sc_dsreg & MTDS_BOT) == 0 && (flag & FWRITE) &&
18534221Sbostic 	    (sc->sc_dens == MT_GCR) != ((sc->sc_dsreg & MTDS_PE) == 0)) {
1864736Swnj 		uprintf("mu%d: can't change density in mid-tape\n", muunit);
18734221Sbostic 		sc->sc_openf = 0;
1888581Sroot 		return (EIO);
1894736Swnj 	}
1904736Swnj 	sc->sc_blkno = (daddr_t)0;
19117214Smckusick 
19234221Sbostic 	/*
19334221Sbostic 	 * Since cooked I/O may do a read-ahead before a write, trash
19434221Sbostic 	 * on a tape can make the first write fail.  Suppress the first
19534221Sbostic 	 * read-ahead unless definitely doing read-write.
19634221Sbostic 	 */
19734221Sbostic 	sc->sc_nxrec = ((flag & (FTRUNC | FWRITE)) == (FTRUNC | FWRITE)) ?
19834221Sbostic 	    (daddr_t)0 : (daddr_t)INF;
1994736Swnj 	sc->sc_flags = 0;
20034221Sbostic 	sc->sc_blks = 0;
20134221Sbostic 	sc->sc_softerrs = 0;
20218324Sralph 	sc->sc_ttyp = u.u_ttyp;
2038581Sroot 	return (0);
2044736Swnj }
2054736Swnj 
2064736Swnj mtclose(dev, flag)
2074736Swnj 	register dev_t dev;
20817214Smckusick 	register int flag;
2094736Swnj {
2104736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
2114736Swnj 
21234221Sbostic 	if ((flag & (FREAD | FWRITE)) == FWRITE ||
21334221Sbostic 	    ((flag & FWRITE) && (sc->sc_flags & H_WRITTEN)))
2144736Swnj 		mtcommand(dev, MT_CLS|sc->sc_dens, 1);
21517214Smckusick 	if ((minor(dev) & H_NOREWIND) == 0)
2164736Swnj 		mtcommand(dev, MT_REW, 0);
21734221Sbostic 	if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100)
21834221Sbostic 		log(LOG_INFO, "mu%d: %d soft errors in %d blocks\n",
21934221Sbostic 		    MUUNIT(dev), sc->sc_softerrs, sc->sc_blks);
2204736Swnj 	sc->sc_openf = 0;
221*40733Skarels 	return (0);
2224736Swnj }
2234736Swnj 
2244736Swnj mtcommand(dev, com, count)
2254736Swnj 	dev_t dev;
2264736Swnj 	int com, count;
2274736Swnj {
2284736Swnj 	register struct buf *bp;
22934221Sbostic 	int s;
2304736Swnj 
2314736Swnj 	bp = &cmtbuf[MTUNIT(dev)];
2325437Sroot 	s = spl5();
23317214Smckusick 	while (bp->b_flags & B_BUSY) {
23434221Sbostic 		if (bp->b_repcnt == 0 && (bp->b_flags & B_DONE))
2354736Swnj 			break;
2364736Swnj 		bp->b_flags |= B_WANTED;
2374736Swnj 		sleep((caddr_t)bp, PRIBIO);
2384736Swnj 	}
2394736Swnj 	bp->b_flags = B_BUSY|B_READ;
2405437Sroot 	splx(s);
2414736Swnj 	bp->b_dev = dev;
2424736Swnj 	bp->b_command = com;
2434736Swnj 	bp->b_repcnt = count;
2444736Swnj 	bp->b_blkno = 0;
24517214Smckusick 	bp->b_error = 0;
2464736Swnj 	mtstrategy(bp);
2474736Swnj 	if (count == 0)
2484736Swnj 		return;
24934221Sbostic 	biowait(bp);
25017214Smckusick 	if (bp->b_flags & B_WANTED)
2514736Swnj 		wakeup((caddr_t)bp);
2524736Swnj 	bp->b_flags &= B_ERROR;
2534736Swnj }
2544736Swnj 
2554736Swnj mtstrategy(bp)
2564736Swnj 	register struct buf *bp;
2574736Swnj {
2584736Swnj 	register struct buf *dp;
25934221Sbostic 	struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)];
26034221Sbostic 	int s;
2614736Swnj 
26234221Sbostic 	/*
26334221Sbostic 	 * If this is a data transfer operation, set the resid to a
26434221Sbostic 	 * default value (EOF) to simplify getting it right during
26534221Sbostic 	 * error recovery or bail out.
26634221Sbostic 	 */
26717214Smckusick 	if (bp != &cmtbuf[MTUNIT(bp->b_dev)])
26817214Smckusick 		bp->b_resid = bp->b_bcount;
26917214Smckusick 
27034221Sbostic 	/*
27134221Sbostic 	 * Link this request onto the end of the queue for this
27234221Sbostic 	 * controller, then start I/O if not already active.
27334221Sbostic 	 */
2744736Swnj 	bp->av_forw = NULL;
2754736Swnj 	dp = &mi->mi_tab;
2765437Sroot 	s = spl5();
2774736Swnj 	if (dp->b_actf == NULL)
2784736Swnj 		dp->b_actf = bp;
2794736Swnj 	else
2804736Swnj 		dp->b_actl->av_forw = bp;
2814736Swnj 	dp->b_actl = bp;
2824736Swnj 	if (dp->b_active == 0)
2834736Swnj 		mbustart(mi);
2845437Sroot 	splx(s);
2854736Swnj }
2864736Swnj 
2874736Swnj mtustart(mi)
2884736Swnj 	register struct mba_device *mi;
2894736Swnj {
29017214Smckusick 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
2914736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
2924736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
2934736Swnj 	daddr_t blkno;
29426377Skarels 	int count;
2954736Swnj 
2964736Swnj 	if (sc->sc_openf < 0) {
2974736Swnj 		bp->b_flags |= B_ERROR;
2984736Swnj 		return (MBU_NEXT);
2994736Swnj 	}
3004736Swnj 	if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) {
30134221Sbostic 		/*
30234221Sbostic 		 * Data transfer.  If write at end of tape,
30334221Sbostic 		 * signal "no space" unless suppressed
30434221Sbostic 		 * by MTIOCIEOT.
30534221Sbostic 		 */
30634221Sbostic 		if ((sc->sc_flags & (H_EOT | H_IEOT)) == H_EOT &&
30734221Sbostic 		    (bp->b_flags & B_READ) == 0) {
3084736Swnj 			bp->b_flags |= B_ERROR;
30917214Smckusick 			bp->b_error = ENOSPC;
3104736Swnj 			return (MBU_NEXT);
3114736Swnj 		}
31217214Smckusick 
31334221Sbostic 		if (bp->b_flags & B_RAW) {
31434221Sbostic 			/* raw transfer; never seek */
31534221Sbostic 			sc->sc_blkno = bdbtofsb(bp->b_blkno);
31634221Sbostic 			sc->sc_nxrec = sc->sc_blkno + 1;
31734221Sbostic 		} else {
31817214Smckusick 			/* seek beyond end of file */
31917214Smckusick 			if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) {
32017214Smckusick 				bp->b_flags |= B_ERROR;
32117214Smckusick 				bp->b_error = ENXIO;
32217214Smckusick 				return (MBU_NEXT);
32317214Smckusick 			}
32417214Smckusick 
32534221Sbostic 			/*
32634221Sbostic 			 * This should be end of file, but the buffer
32734221Sbostic 			 * system wants a one-block look-ahead.  Humor it.
32834221Sbostic 			 */
32934221Sbostic 			if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec &&
33034221Sbostic 			    bp->b_flags & B_READ) {
33134221Sbostic 				bp->b_resid = bp->b_bcount;
33217214Smckusick 				clrbuf(bp);
33317214Smckusick 				return (MBU_NEXT);
33417214Smckusick 			}
33517214Smckusick 
33617214Smckusick 			/* If writing, mark the next block invalid. */
33717214Smckusick 			if ((bp->b_flags & B_READ) == 0)
33817214Smckusick 				sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1;
3394736Swnj 		}
3404736Swnj 	} else {
34117214Smckusick 		/* It's a command, do it now. */
3424736Swnj 		mtaddr->mtncs[MUUNIT(bp->b_dev)] =
3434736Swnj 			(bp->b_repcnt<<8)|bp->b_command|MT_GO;
3444736Swnj 		return (MBU_STARTED);
3454736Swnj 	}
34617214Smckusick 
34734221Sbostic 	/*
34834221Sbostic 	 * If raw I/O, or if the tape is positioned correctly for
34934221Sbostic 	 * cooked I/O, set the byte count, unit number and repeat count
35034221Sbostic 	 * then tell the MASSBUS to proceed.  Note that a negative
35134221Sbostic 	 * bcount tells mbstart to map the buffer for "read backwards".
35234221Sbostic 	 */
35334221Sbostic 	if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) {
3544736Swnj 		if (mi->mi_tab.b_errcnt == 2) {
35534221Sbostic 			mtaddr->mtbc = -bp->b_bcount;
3564736Swnj 			mtaddr->mtca = MUUNIT(bp->b_dev);
3574736Swnj 		} else {
3584736Swnj 			mtaddr->mtbc = bp->b_bcount;
3594736Swnj 			mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev);
3604736Swnj 		}
3614736Swnj 		return (MBU_DODATA);
3624736Swnj 	}
36317214Smckusick 
36417214Smckusick 	/* Issue skip operations to position the next block for cooked I/O. */
36517214Smckusick 
3667380Ssam 	if (blkno < bdbtofsb(bp->b_blkno))
36734221Sbostic 		count = bdbtofsb(bp->b_blkno) - blkno;
3684736Swnj 	else
36934221Sbostic 		count = blkno - bdbtofsb(bp->b_blkno);
37034221Sbostic 	if ((unsigned)count > 0377)
37126377Skarels 		count = 0377;
37226377Skarels 	mtaddr->mtncs[MUUNIT(bp->b_dev)] = count | MT_SFORW|MT_GO;
3734736Swnj 	return (MBU_STARTED);
3744736Swnj }
3754736Swnj 
3764736Swnj mtstart(mi)
3774736Swnj 	register struct mba_device *mi;
3784736Swnj {
3794736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
3804736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
3814736Swnj 
3824736Swnj 	if (bp->b_flags & B_READ)
3834736Swnj 		if (mi->mi_tab.b_errcnt == 2)
38434221Sbostic 			return (MT_READREV|MT_GO);
3854736Swnj 		else
38634221Sbostic 			return (MT_READ|MT_GO);
3874736Swnj 	else
38834221Sbostic 		return (MT_WRITE|sc->sc_dens|MT_GO);
3894736Swnj }
3904736Swnj 
3914736Swnj mtdtint(mi, mbsr)
3924736Swnj 	register struct mba_device *mi;
3934736Swnj 	int mbsr;
3944736Swnj {
3954736Swnj 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
3964736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
3974736Swnj 	register struct mu_softc *sc;
39817214Smckusick 	register int er;
3994736Swnj 
40017214Smckusick 	/* I'M still NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */
40117214Smckusick 	if ((mtaddr->mtca & 3) != MUUNIT(bp->b_dev)) {
4024736Swnj 		printf("mt: wrong unit!\n");
4034736Swnj 		mtaddr->mtca = MUUNIT(bp->b_dev);
4044736Swnj 	}
40517214Smckusick 
40617214Smckusick 	er = MASKREG(mtaddr->mter);
4074736Swnj 	sc = &mu_softc[MUUNIT(bp->b_dev)];
40817214Smckusick 	sc->sc_erreg = er;
40917214Smckusick 	if (bp->b_flags & B_READ)
41017214Smckusick 		sc->sc_flags &= ~H_WRITTEN;
41117214Smckusick 	else
4124736Swnj 		sc->sc_flags |= H_WRITTEN;
41317214Smckusick 	switch (er & MTER_INTCODE) {
41417214Smckusick 
41517214Smckusick 	case MTER_EOT:
41617214Smckusick 		sc->sc_flags |= H_EOT;
41717214Smckusick 		/* fall into MTER_DONE */
41817214Smckusick 
4194736Swnj 	case MTER_DONE:
42017214Smckusick 		sc->sc_blkno++;
42117214Smckusick 		if (mi->mi_tab.b_errcnt == 2) {
42217214Smckusick 			bp->b_bcount = bp->b_resid;
42317214Smckusick 			bp->b_resid -= MASKREG(mtaddr->mtbc);
42434221Sbostic 			if (bp->b_resid > 0 && (bp->b_flags & B_RAW) == 0)
42517214Smckusick 				bp->b_flags |= B_ERROR;
42634221Sbostic 		} else
42717214Smckusick 			bp->b_resid = 0;
42817214Smckusick 		break;
42917214Smckusick 
43017214Smckusick 	case MTER_SHRTREC:
43117214Smckusick 		sc->sc_blkno++;
43217214Smckusick 		bp->b_bcount = bp->b_resid;
43317214Smckusick 		bp->b_resid -= MASKREG(mtaddr->mtbc);
43434221Sbostic 		if ((bp->b_flags & B_RAW) == 0)
43517214Smckusick 			bp->b_flags |= B_ERROR;
43617214Smckusick 		break;
43717214Smckusick 
43817214Smckusick 	case MTER_RETRY:
43934221Sbostic 		/*
44034221Sbostic 		 * Simple re-try.  Since resid is always a copy of the
44134221Sbostic 		 * original byte count, use it to restore the count.
44234221Sbostic 		 */
44317214Smckusick 		mi->mi_tab.b_errcnt = 1;
44417214Smckusick 		bp->b_bcount = bp->b_resid;
44534221Sbostic 		return (MBD_RETRY);
44617214Smckusick 
44717214Smckusick 	case MTER_RDOPP:
44834221Sbostic 		/*
44934221Sbostic 		 * The controller just decided to read it backwards.
45034221Sbostic 		 * If the controller returns a byte count of zero,
45134221Sbostic 		 * change it to 1, since zero encodes 65536, which
45234221Sbostic 		 * isn't quite what we had in mind.  The byte count
45334221Sbostic 		 * may be larger than the size of the input buffer, so
45434221Sbostic 		 * limit the count to the buffer size.  After
45534221Sbostic 		 * making the byte count reasonable, set bcount to the
45634221Sbostic 		 * negative of the controller's version of the byte
45734221Sbostic 		 * count so that the start address for the transfer is
45834221Sbostic 		 * set up correctly.
45934221Sbostic 		 */
46017214Smckusick 		if (mt_do_readrev) {
46117214Smckusick 			mi->mi_tab.b_errcnt = 2;
46217214Smckusick 			if ((bp->b_bcount = MASKREG(mtaddr->mtbc)) == 0)
46317214Smckusick 				bp->b_bcount = 1;
46417214Smckusick 			if (bp->b_bcount > bp->b_resid)
46517214Smckusick 				bp->b_bcount = bp->b_resid;
46617214Smckusick 			bp->b_bcount = -(bp->b_bcount);
46717214Smckusick 			return(MBD_RETRY);
46817214Smckusick 		} else if (MASKREG(mtaddr->mtbc) <= bp->b_resid) {
46917214Smckusick 			sc->sc_blkno++;
47017214Smckusick 			bp->b_bcount = bp->b_resid;
47117214Smckusick 			bp->b_resid -= MASKREG(mtaddr->mtbc);
47217214Smckusick 			bp->b_flags |= B_ERROR;
47317214Smckusick 			break;
47417214Smckusick 		}
47517214Smckusick 		bp->b_flags |= B_ERROR;
47617214Smckusick 		/* fall into MTER_LONGREC */
47717214Smckusick 
4784736Swnj 	case MTER_LONGREC:
47917214Smckusick 		sc->sc_blkno++;
48017214Smckusick 		bp->b_bcount = bp->b_resid;
4814736Swnj 		bp->b_resid = 0;
48217214Smckusick 		bp->b_error = ENOMEM;
48317214Smckusick 		bp->b_flags |= B_ERROR;
4844736Swnj 		break;
4854736Swnj 
4864736Swnj 	case MTER_NOTCAP:
4874736Swnj 		printf("mu%d: blank tape\n", MUUNIT(bp->b_dev));
4884736Swnj 		goto err;
4894736Swnj 
4904736Swnj 	case MTER_TM:
49134221Sbostic 		/*
49234221Sbostic 		 * End of file.  Since the default byte count has
49334221Sbostic 		 * already been set, just count the block and proceed.
49434221Sbostic 		 */
4954736Swnj 		sc->sc_blkno++;
4964736Swnj 	err:
49734221Sbostic 		sc->sc_nxrec = bdbtofsb(bp->b_blkno);
4984736Swnj 		break;
4994736Swnj 
5004736Swnj 	case MTER_OFFLINE:
5014736Swnj 		if (sc->sc_openf > 0) {
5024736Swnj 			sc->sc_openf = -1;
50334221Sbostic 			tprintf(sc->sc_ttyp, "mu%d: offline\n",
50434221Sbostic 			    MUUNIT(bp->b_dev));
5054736Swnj 		}
5064736Swnj 		bp->b_flags |= B_ERROR;
5074736Swnj 		break;
5084736Swnj 
50917214Smckusick 	case MTER_NOTAVL:
51017214Smckusick 		if (sc->sc_openf > 0) {
51117214Smckusick 			sc->sc_openf = -1;
51218324Sralph 			tprintf(sc->sc_ttyp, "mu%d: offline (port selector)\n",
51318324Sralph 			    MUUNIT(bp->b_dev));
51417214Smckusick 		}
51517214Smckusick 		bp->b_flags |= B_ERROR;
51617214Smckusick 		break;
51717214Smckusick 
5184736Swnj 	case MTER_FPT:
51934221Sbostic 		tprintf(sc->sc_ttyp, "mu%d: no write ring\n",
52034221Sbostic 		    MUUNIT(bp->b_dev));
5214736Swnj 		bp->b_flags |= B_ERROR;
5224736Swnj 		break;
5234736Swnj 
52417214Smckusick 	case MTER_UNREAD:
52517214Smckusick 		sc->sc_blkno++;
52617214Smckusick 		bp->b_bcount = bp->b_resid;
52717214Smckusick 		bp->b_resid -= MIN(MASKREG(mtaddr->mtbc), bp->b_bcount);
52817214Smckusick 
52934221Sbostic 		/* code 010 means a garbage record, nothing serious. */
53034221Sbostic 		if ((er & MTER_FAILCODE) == (010 << MTER_FSHIFT)) {
53134221Sbostic 			tprintf(sc->sc_ttyp,
53234221Sbostic 			    "mu%d: rn=%d bn=%d unreadable record\n",
53317214Smckusick 			    MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno);
53417214Smckusick 			bp->b_flags |= B_ERROR;
53517214Smckusick 			break;
53617214Smckusick 		}
53717214Smckusick 
53834221Sbostic 		/*
53934221Sbostic 		 * Anything else might be a hardware problem,
54034221Sbostic 		 * fall into the error report.
54134221Sbostic 		 */
54217214Smckusick 
5434736Swnj 	default:
54434221Sbostic 		/*
54534221Sbostic 		 * The bits in sc->sc_dsreg are from the last sense
54634221Sbostic 		 * command.  To get the most recent copy, you have to
54734221Sbostic 		 * do a sense at interrupt level, which requires nested
54834221Sbostic 		 * error processing.  This is a bit messy, so leave
54934221Sbostic 		 * well enough alone.
55034221Sbostic 		 */
55134221Sbostic 		tprintf(sc->sc_ttyp, "\
55234221Sbostic mu%d: hard error (data transfer) rn=%d bn=%d mbsr=%b er=0%o ds=%b\n",
55317214Smckusick 		    MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno,
55417214Smckusick 		    mbsr, mbsr_bits, er,
55517214Smckusick 		    MASKREG(sc->sc_dsreg), mtds_bits);
55617214Smckusick #ifdef MTLERRM
55734221Sbostic 		mtintfail(er);
55817214Smckusick #endif
5594736Swnj 		bp->b_flags |= B_ERROR;
56017214Smckusick 
56134221Sbostic 		/*
56234221Sbostic 		 * The TM78 manual says to reset the controller after
56334221Sbostic 		 * TM fault B or MASSBUS fault.
56434221Sbostic 		 */
56534221Sbostic 		if ((er & MTER_INTCODE) == MTER_TMFLTB ||
56634221Sbostic 		    (er & MTER_INTCODE) == MTER_MBFLT)
56717214Smckusick 			mtcreset(mtaddr);
5684736Swnj 	}
56917214Smckusick 
57034221Sbostic 	/*
57134221Sbostic 	 * Just in case some strange error slipped through (drive off
57234221Sbostic 	 * line during read-reverse error recovery comes to mind), make
57334221Sbostic 	 * sure the byte count is reasonable.
57434221Sbostic 	 */
57517214Smckusick 	if (bp->b_bcount < 0)
57617214Smckusick 		bp->b_bcount = bp->b_resid;
57734221Sbostic 
57834221Sbostic 	if ((bp->b_flags & B_ERROR) == 0) {
57934221Sbostic 		/* this counts reverse reads as soft errors */
58034221Sbostic 		sc->sc_blks++;
58134221Sbostic 		if (mi->mi_tab.b_errcnt) /* alternatively, if == 1 */
58234221Sbostic 			sc->sc_softerrs++;
58334221Sbostic 	}
5844736Swnj 	return (MBD_DONE);
5854736Swnj }
5864736Swnj 
5874736Swnj mtndtint(mi)
5884736Swnj 	register struct mba_device *mi;
5894736Swnj {
5904736Swnj 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
5914736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
5924736Swnj 	register struct mu_softc *sc;
59317214Smckusick 	register int er, fc;
59417214Smckusick 	int unit;
5954736Swnj 
5964736Swnj 	unit = (mtaddr->mtner >> 8) & 3;
5974736Swnj 	er = MASKREG(mtaddr->mtner);
59817214Smckusick 	sc = &mu_softc[unit];
59917214Smckusick 	sc->sc_erreg = er;
60017214Smckusick 
60117214Smckusick 	/* Check for unsolicited interrupts. */
60234221Sbostic 	if (bp == NULL || unit != MUUNIT(bp->b_dev)) {
60334221Sbostic 		if ((er & MTER_INTCODE) == MTER_ONLINE)
60434221Sbostic 			return (MBN_SKIP);
60517214Smckusick 
60634221Sbostic 		printf("mu%d: stray intr (non data transfer) er=0%o ds=%b\n",
60734221Sbostic 		    unit, er, MASKREG(sc->sc_dsreg), mtds_bits);
60817214Smckusick #ifdef MTLERRM
60934221Sbostic 		mtintfail(er);
61017214Smckusick #endif
61134221Sbostic 		if ((er & MTER_INTCODE) == MTER_TMFLTB ||
61234221Sbostic 		    (er & MTER_INTCODE) == MTER_MBFLT) {
61334221Sbostic 			/*
61434221Sbostic 			 * Reset the controller, then set error status
61534221Sbostic 			 * if there was anything active when the fault
61634221Sbostic 			 * occurred.  This may shoot an innocent
61734221Sbostic 			 * bystander, but it's better than letting
61834221Sbostic 			 * an error slip through.
61934221Sbostic 			 */
62034221Sbostic 			mtcreset(mtaddr);
62134221Sbostic 			if (bp != NULL) {
62234221Sbostic 				bp->b_flags |= B_ERROR;
62334221Sbostic 				return (MBN_DONE);
62417214Smckusick 			}
62517214Smckusick 		}
6264736Swnj 		return (MBN_SKIP);
6274736Swnj 	}
62817214Smckusick 
6294736Swnj 	fc = (mtaddr->mtncs[unit] >> 8) & 0xff;
6304736Swnj 	sc->sc_resid = fc;
63117214Smckusick 
63234221Sbostic 	/*
63334221Sbostic 	 * Clear the "written" flag after any operation that changes
63434221Sbostic 	 * the position of the tape.
63534221Sbostic 	 */
63634221Sbostic 	if (bp != &cmtbuf[MTUNIT(bp->b_dev)] || bp->b_command != MT_SENSE)
63717214Smckusick 		sc->sc_flags &= ~H_WRITTEN;
63817214Smckusick 
6394736Swnj 	switch (er & MTER_INTCODE) {
64017214Smckusick 
64117214Smckusick 	case MTER_EOT:
64217214Smckusick 		sc->sc_flags |= H_EOT;
64317214Smckusick 		/* fall into MTER_DONE */
64417214Smckusick 
6454736Swnj 	case MTER_DONE:
64617214Smckusick 		/* If this is a command buffer, just update the status.	*/
6474736Swnj 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) {
6484736Swnj 	done:
6494736Swnj 			if (bp->b_command == MT_SENSE)
6504736Swnj 				sc->sc_dsreg = MASKREG(mtaddr->mtds);
6514736Swnj 			return (MBN_DONE);
6524736Swnj 		}
65317214Smckusick 
65434221Sbostic 		/*
65534221Sbostic 		 * It's not a command buffer, must be a cooked I/O
65634221Sbostic 		 * skip operation (perhaps a shaky assumption, but it
65734221Sbostic 		 * wasn't my idea).
65834221Sbostic 		 */
6597380Ssam 		if ((fc = bdbtofsb(bp->b_blkno) - sc->sc_blkno) < 0)
6606186Ssam 			sc->sc_blkno -= MIN(0377, -fc);
6614736Swnj 		else
6626186Ssam 			sc->sc_blkno += MIN(0377, fc);
6634736Swnj 		return (MBN_RETRY);
6644736Swnj 
66517214Smckusick 	case MTER_ONLINE:		/* ddj -- shouldn't happen but did */
6664736Swnj 	case MTER_RWDING:
6674736Swnj 		return (MBN_SKIP);	/* ignore "rewind started" interrupt */
6684736Swnj 
6694736Swnj 	case MTER_NOTCAP:
67018324Sralph 		tprintf(sc->sc_ttyp, "mu%d: blank tape\n", MUUNIT(bp->b_dev));
67117214Smckusick 		bp->b_flags |= B_ERROR;
67217214Smckusick 		return (MBN_DONE);
6734736Swnj 
6744736Swnj 	case MTER_TM:
6754736Swnj 	case MTER_LEOT:
67634221Sbostic 		/*
67734221Sbostic 		 * For an ioctl skip operation, count a tape mark as
67834221Sbostic 		 * a record.  If there's anything left to do, update
67934221Sbostic 		 * the repeat count and re-start the command.
68034221Sbostic 		 */
68117214Smckusick 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) {
68217214Smckusick 			if ((sc->sc_resid = bp->b_repcnt = fc - 1) == 0)
68317214Smckusick 				return (MBN_DONE);
68417214Smckusick 			else
68517214Smckusick 				return (MBN_RETRY);
6864736Swnj 		} else {
68734221Sbostic 			/*
68834221Sbostic 			 * Cooked I/O again.  Just update the books and
68934221Sbostic 			 * wait for someone else to return end of file or
69034221Sbostic 			 * complain about a bad seek.
69134221Sbostic 			 */
69234221Sbostic 			if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) {
69334221Sbostic 				sc->sc_nxrec = bdbtofsb(bp->b_blkno) + fc - 1;
69434221Sbostic 				sc->sc_blkno = sc->sc_nxrec;
69534221Sbostic 			} else {
69634221Sbostic 				sc->sc_nxrec = bdbtofsb(bp->b_blkno) - fc;
69734221Sbostic 				sc->sc_blkno = sc->sc_nxrec + 1;
69834221Sbostic 			}
6994736Swnj 		}
7004736Swnj 		return (MBN_RETRY);
7014736Swnj 
7024736Swnj 	case MTER_FPT:
70334221Sbostic 		tprintf(sc->sc_ttyp, "mu%d: no write ring\n",
70434221Sbostic 		    MUUNIT(bp->b_dev));
7054736Swnj 		bp->b_flags |= B_ERROR;
7064736Swnj 		return (MBN_DONE);
7074736Swnj 
7084736Swnj 	case MTER_OFFLINE:
70917214Smckusick 		/* If `off line' was intentional, don't complain. */
71034221Sbostic 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)] &&
71134221Sbostic 		    bp->b_command == MT_UNLOAD)
71217214Smckusick 			return(MBN_DONE);
7134736Swnj 		if (sc->sc_openf > 0) {
7144736Swnj 			sc->sc_openf = -1;
71534221Sbostic 			tprintf(sc->sc_ttyp, "mu%d: offline\n",
71634221Sbostic 			    MUUNIT(bp->b_dev));
7174736Swnj 		}
7184736Swnj 		bp->b_flags |= B_ERROR;
7194736Swnj 		return (MBN_DONE);
7204736Swnj 
72117214Smckusick 	case MTER_NOTAVL:
72217214Smckusick 		if (sc->sc_openf > 0) {
72317214Smckusick 			sc->sc_openf = -1;
72434221Sbostic 			tprintf(sc->sc_ttyp, "mu%d: offline (port selector)\n",
72534221Sbostic 			    MUUNIT(bp->b_dev));
72617214Smckusick 		}
72717214Smckusick 		bp->b_flags |= B_ERROR;
72817214Smckusick 		return (MBN_DONE);
72917214Smckusick 
7304736Swnj 	case MTER_BOT:
7314736Swnj 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)])
7324736Swnj 			goto done;
73317214Smckusick 		/* fall through */
73417214Smckusick 
7354736Swnj 	default:
73634221Sbostic 		tprintf(sc->sc_ttyp, "\
73734221Sbostic mu%d: hard error (non data transfer) rn=%d bn=%d er=0%o ds=%b\n",
73817214Smckusick 		    MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno,
73917214Smckusick 		    er, MASKREG(sc->sc_dsreg), mtds_bits);
74017214Smckusick #ifdef MTLERRM
74134221Sbostic 		mtintfail(er);
74217214Smckusick #endif
74334221Sbostic 		if ((er & MTER_INTCODE) == MTER_TMFLTB ||
74434221Sbostic 		    (er & MTER_INTCODE) == MTER_MBFLT)
74517214Smckusick 			mtcreset(mtaddr);	/* reset the controller */
7464736Swnj 		bp->b_flags |= B_ERROR;
7474736Swnj 		return (MBN_DONE);
7484736Swnj 	}
7494736Swnj 	/* NOTREACHED */
7504736Swnj }
7514736Swnj 
75234221Sbostic void
75334221Sbostic mtcreset(mtaddr)
75417214Smckusick 	register struct mtdevice *mtaddr;
75517214Smckusick {
75617214Smckusick 	register int i;
75717214Smckusick 
75817214Smckusick 	mtaddr->mtid = MTID_CLR;		/* reset the TM78 */
75917214Smckusick 	DELAY(200);
76017214Smckusick 	for (i = MTTIMEOUT; i > 0; i--) {
76117214Smckusick 		DELAY(50);			/* don't nag */
76217214Smckusick 		if ((mtaddr->mtid & MTID_RDY) != 0)
76317214Smckusick 			return;			/* exit when ready */
76417214Smckusick 	}
76517214Smckusick 	printf("mt: controller hung\n");
76617214Smckusick }
76717214Smckusick 
7684736Swnj /*ARGSUSED*/
7697637Ssam mtioctl(dev, cmd, data, flag)
7704736Swnj 	dev_t dev;
7714736Swnj 	int cmd;
7727637Ssam 	caddr_t data;
7734736Swnj 	int flag;
7744736Swnj {
7754736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
7764736Swnj 	register struct buf *bp = &cmtbuf[MTUNIT(dev)];
77717214Smckusick 	register struct mtop *mtop;
77817214Smckusick 	register struct mtget *mtget;
77917214Smckusick 	int callcount, fcount;
78017214Smckusick 	int op;
78117214Smckusick 
78217214Smckusick 	/* We depend on the values and order of the MT codes here. */
78317214Smckusick 
7844736Swnj 	static mtops[] =
7854736Swnj 	{MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE};
7864736Swnj 
7874736Swnj 	switch (cmd) {
7887637Ssam 
78917214Smckusick 	/* tape operation */
79017214Smckusick 
79117214Smckusick 	case MTIOCTOP:
7928606Sroot 		mtop = (struct mtop *)data;
7938606Sroot 		switch (mtop->mt_op) {
7947637Ssam 
7954736Swnj 		case MTWEOF:
7967637Ssam 			callcount = mtop->mt_count;
7974736Swnj 			fcount = 1;
7984736Swnj 			break;
7997637Ssam 
8004736Swnj 		case MTFSF: case MTBSF:
8017637Ssam 			callcount = mtop->mt_count;
8024736Swnj 			fcount = 1;
8034736Swnj 			break;
8047637Ssam 
8054736Swnj 		case MTFSR: case MTBSR:
8064736Swnj 			callcount = 1;
8077637Ssam 			fcount = mtop->mt_count;
8084736Swnj 			break;
8097637Ssam 
8104736Swnj 		case MTREW: case MTOFFL:
8114736Swnj 			callcount = 1;
8124736Swnj 			fcount = 1;
8134736Swnj 			break;
8147637Ssam 
8154736Swnj 		default:
8168581Sroot 			return (ENXIO);
8174736Swnj 		}
81834221Sbostic 		if (callcount <= 0 || fcount <= 0)
8198581Sroot 			return (EINVAL);
8207637Ssam 		op = mtops[mtop->mt_op];
8214736Swnj 		if (op == MT_WTM)
8224736Swnj 			op |= sc->sc_dens;
8234736Swnj 		while (--callcount >= 0) {
82417214Smckusick 			register int n, fc = fcount;
8254736Swnj 
8264736Swnj 			do {
82717214Smckusick 				n = MIN(fc, 0xff);
8284736Swnj 				mtcommand(dev, op, n);
82917214Smckusick 				n -= sc->sc_resid;
83017214Smckusick 				fc -= n;
83117214Smckusick 				switch (mtop->mt_op) {
83217214Smckusick 
83317214Smckusick 				case MTWEOF:
83417214Smckusick 					sc->sc_blkno += (daddr_t)n;
83517214Smckusick 					sc->sc_nxrec = sc->sc_blkno - 1;
83617214Smckusick 					break;
83717214Smckusick 
83817214Smckusick 				case MTOFFL:
83917214Smckusick 				case MTREW:
84017214Smckusick 				case MTFSF:
84117214Smckusick 					sc->sc_blkno = (daddr_t)0;
84217214Smckusick 					sc->sc_nxrec = (daddr_t)INF;
84317214Smckusick 					break;
84417214Smckusick 
84517214Smckusick 				case MTBSF:
84617214Smckusick 					if (sc->sc_resid) {
84717214Smckusick 						sc->sc_blkno = (daddr_t)0;
84817214Smckusick 						sc->sc_nxrec = (daddr_t)INF;
84917214Smckusick 					} else {
85017214Smckusick 						sc->sc_blkno = (daddr_t)(-1);
85117214Smckusick 						sc->sc_nxrec = (daddr_t)(-1);
85217214Smckusick 					}
85317214Smckusick 					break;
85417214Smckusick 
85517214Smckusick 				case MTFSR:
85617214Smckusick 					sc->sc_blkno += (daddr_t)n;
85717214Smckusick 					break;
85817214Smckusick 
85917214Smckusick 				case MTBSR:
86017214Smckusick 					sc->sc_blkno -= (daddr_t)n;
86117214Smckusick 					break;
86217214Smckusick 				}
86317214Smckusick 				if (sc->sc_resid)
86417214Smckusick 					break;
86517214Smckusick 			} while (fc);
86617214Smckusick 			if (fc) {
86717214Smckusick 				sc->sc_resid = callcount + fc;
86834221Sbostic 				if (mtop->mt_op == MTFSR ||
86934221Sbostic 				    mtop->mt_op == MTBSR)
87017214Smckusick 					return (EIO);
87134221Sbostic 				break;
87217214Smckusick 			}
87317214Smckusick 			if (bp->b_flags & B_ERROR)
8744736Swnj 				break;
8754736Swnj 		}
8768712Sroot 		return (geterror(bp));
8777637Ssam 
87817214Smckusick 	/* tape status */
8794736Swnj 	case MTIOCGET:
8807637Ssam 		mtget = (struct mtget *)data;
8817637Ssam 		mtget->mt_erreg = sc->sc_erreg;
8827637Ssam 		mtget->mt_resid = sc->sc_resid;
8834736Swnj 		mtcommand(dev, MT_SENSE, 1);	/* update drive status */
8847637Ssam 		mtget->mt_dsreg = sc->sc_dsreg;
8857637Ssam 		mtget->mt_type = MT_ISMT;
8868581Sroot 		break;
8877637Ssam 
88817214Smckusick 	/* ignore EOT condition */
88917214Smckusick 	case MTIOCIEOT:
89017214Smckusick 		sc->sc_flags |= H_IEOT;
89117214Smckusick 		break;
89217214Smckusick 
89317214Smckusick 	/* enable EOT condition */
89417214Smckusick 	case MTIOCEEOT:
89517214Smckusick 		sc->sc_flags &= ~H_IEOT;
89617214Smckusick 		break;
89717214Smckusick 
8984736Swnj 	default:
8998581Sroot 		return (ENXIO);
9004736Swnj 	}
9018581Sroot 	return (0);
9024736Swnj }
9034736Swnj 
9044736Swnj #define	DBSIZE	20
9054736Swnj 
9064736Swnj mtdump()
9074736Swnj {
9084736Swnj 	register struct mba_device *mi;
9094736Swnj 	register struct mba_regs *mp;
9104736Swnj 	int blk, num;
9114736Swnj 	int start;
9124736Swnj 
9134736Swnj 	start = 0;
9144736Swnj 	num = maxfree;
9154736Swnj #define	phys(a,b)		((b)((int)(a)&0x7fffffff))
9164736Swnj 	if (mtinfo[0] == 0)
9174736Swnj 		return (ENXIO);
9184736Swnj 	mi = phys(mtinfo[0], struct mba_device *);
9194736Swnj 	mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba;
9204736Swnj 	mp->mba_cr = MBCR_IE;
9216186Ssam #if lint
9228606Sroot 	blk = 0; num = blk; start = num; blk = start;
9236186Ssam 	return (0);
9246186Ssam #endif
9256186Ssam #ifdef notyet
9264736Swnj 	mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive];
9274736Swnj 	mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI;
9284736Swnj 	mtaddr->mtcs1 = MT_DCLR|MT_GO;
9294736Swnj 	while (num > 0) {
9304736Swnj 		blk = num > DBSIZE ? DBSIZE : num;
9314736Swnj 		mtdwrite(start, blk, mtaddr, mp);
9324736Swnj 		start += blk;
9334736Swnj 		num -= blk;
9344736Swnj 	}
9354736Swnj 	mteof(mtaddr);
9364736Swnj 	mteof(mtaddr);
9374736Swnj 	mtwait(mtaddr);
9384736Swnj 	if (mtaddr->mtds&MTDS_ERR)
9394736Swnj 		return (EIO);
9404736Swnj 	mtaddr->mtcs1 = MT_REW|MT_GO;
9414736Swnj 	return (0);
9424736Swnj }
9434736Swnj 
9444736Swnj mtdwrite(dbuf, num, mtaddr, mp)
9454736Swnj 	register dbuf, num;
9464736Swnj 	register struct mtdevice *mtaddr;
9474736Swnj 	struct mba_regs *mp;
9484736Swnj {
9494736Swnj 	register struct pte *io;
9504736Swnj 	register int i;
9514736Swnj 
9524736Swnj 	mtwait(mtaddr);
9534736Swnj 	io = mp->mba_map;
9544736Swnj 	for (i = 0; i < num; i++)
9554736Swnj 		*(int *)io++ = dbuf++ | PG_V;
9564736Swnj 	mtaddr->mtfc = -(num*NBPG);
9574736Swnj 	mp->mba_sr = -1;
9584736Swnj 	mp->mba_bcr = -(num*NBPG);
9594736Swnj 	mp->mba_var = 0;
9604736Swnj 	mtaddr->mtcs1 = MT_WCOM|MT_GO;
9614736Swnj }
9624736Swnj 
9634736Swnj mtwait(mtaddr)
9644736Swnj 	struct mtdevice *mtaddr;
9654736Swnj {
9664736Swnj 	register s;
9674736Swnj 
9684736Swnj 	do
9694736Swnj 		s = mtaddr->mtds;
9704736Swnj 	while ((s & MTDS_DRY) == 0);
9714736Swnj }
9724736Swnj 
9734736Swnj mteof(mtaddr)
9744736Swnj 	struct mtdevice *mtaddr;
9754736Swnj {
9764736Swnj 
9774736Swnj 	mtwait(mtaddr);
9784736Swnj 	mtaddr->mtcs1 = MT_WEOF|MT_GO;
9794736Swnj #endif notyet
9804736Swnj }
98117214Smckusick 
98217214Smckusick #ifdef MTLERRM
98334221Sbostic /*
98434221Sbostic  * Failure messages for each failure code, per interrupt code.
98534221Sbostic  * Each table ends with a code of -1 as a default.
98634221Sbostic  */
98734221Sbostic struct fmesg {
98834221Sbostic 	int	f_code;
98934221Sbostic 	char	*f_mesg;
99034221Sbostic };
99117214Smckusick 
99234221Sbostic static char unclass[] = "unclassified failure code";
99317214Smckusick 
99434221Sbostic /* MTER_BOT */
99534221Sbostic static struct fmesg botmsg[] = {
99634221Sbostic 	01,	"tape was at BOT",
99734221Sbostic 	02,	"BOT seen after tape started",
99834221Sbostic 	03,	"ARA ID detected",
99934221Sbostic 	-1,	unclass
100034221Sbostic };
100117214Smckusick 
100234221Sbostic /* MTER_NOTRDY */
100334221Sbostic static struct fmesg notrdymsg[] = {
100434221Sbostic 	01,	"TU on-line but not ready",
100534221Sbostic 	02,	"fatal error has occurred",
100636548Sbostic 	03,	"access allowed but not ready",
100734221Sbostic 	-1,	unclass
100834221Sbostic };
100917214Smckusick 
101034221Sbostic /* MTER_NOTCAP */
101134221Sbostic static struct fmesg notcapmsg[] = {
101234221Sbostic 	01,	"no record found within 25 feet",
101334221Sbostic 	02,	"ID burst neither PE nor GCR",
101434221Sbostic 	03,	"ARA ID not found",
101534221Sbostic 	04,	"no gap found after ID burst",
101634221Sbostic 	-1,	unclass
101734221Sbostic };
101817214Smckusick 
101934221Sbostic /* MTER_LONGREC */
102034221Sbostic static struct fmesg longrecmsg[] = {
102134221Sbostic 	00,	"extended sense data not found",
102234221Sbostic 	01,	"extended sense data updated",
102334221Sbostic 	-1,	unclass
102434221Sbostic };
102517214Smckusick 
102634221Sbostic /* MTER_UNREAD, MTER_ERROR, MTER_EOTERR, MTER_BADTAPE */
102734221Sbostic static struct fmesg code22msg[] = {
102834221Sbostic 	01,	"GCR write error",
102934221Sbostic 	02,	"GCR read error",
103034221Sbostic 	03,	"PE read error",
103134221Sbostic 	04,	"PE write error",
103234221Sbostic 	05,	"at least 1 bit set in ECCSTA",
103334221Sbostic 	06,	"PE write error",
103434221Sbostic 	07,	"GCR write error",
103534221Sbostic 	010,	"RSTAT contains bad code",
103634221Sbostic 	011,	"PE write error",
103734221Sbostic 	012,	"MASSBUS parity error",
103834221Sbostic 	013,	"invalid data transferred",
103934221Sbostic 	-1,	unclass
104034221Sbostic };
104117214Smckusick 
104234221Sbostic /* MTER_TMFLTA */
104334221Sbostic static struct fmesg tmfltamsg[] = {
104434221Sbostic 	01,	"illegal command code",
104534221Sbostic 	02,	"DT command issued when NDT command active",
104634221Sbostic 	03,	"WMC error",
104734221Sbostic 	04,	"RUN not received from MASSBUS controller",
104834221Sbostic 	05,	"mismatch in command read - function routine",
104934221Sbostic 	06,	"ECC ROM parity error",
105034221Sbostic 	07,	"XMC ROM parity error",
105134221Sbostic 	010,	"mismatch in command read - ID burst command",
105234221Sbostic 	011,	"mismatch in command read - verify ARA burst command",
105334221Sbostic 	012,	"mismatch in command read - verify ARA ID command",
105434221Sbostic 	013,	"mismatch in command read - verify gap command",
105534221Sbostic 	014,	"mismatch in command read - read id burst command",
105634221Sbostic 	015,	"mismatch in command read - verify ARA ID command",
105734221Sbostic 	016,	"mismatch in command read - verify gap command",
105834221Sbostic 	017,	"mismatch in command read - find gap command",
105934221Sbostic 	020,	"WMC LEFT failed to set",
106034221Sbostic 	021,	"XL PE set in INTSTA register",
106134221Sbostic 	022,	"XMC DONE did not set",
106234221Sbostic 	023,	"WMC ROM PE or RD PE set in WMCERR register",
106334221Sbostic 	-1,	unclass
106434221Sbostic };
106517214Smckusick 
106634221Sbostic /* MTER_TUFLTA */
106734221Sbostic static struct fmesg tufltamsg[] = {
106834221Sbostic 	01,	"TU status parity error",
106934221Sbostic 	02,	"TU command parity error",
107034221Sbostic 	03,	"rewinding tape went offline",
107134221Sbostic 	04,	"tape went not ready during DSE",
107234221Sbostic 	05,	"TU CMD status changed during DSE",
107334221Sbostic 	06,	"TU never came up to speed",
107434221Sbostic 	07,	"TU velocity changed",
107534221Sbostic 	010,	"TU CMD did not load correctly to start tape motion",
107634221Sbostic 	011,	"TU CMD did not load correctly to set drive density",
107734221Sbostic 	012,	"TU CMD did not load correctly to start tape motion to write BOT ID",
107834221Sbostic 	013,	"TU CMD did not load correctly to backup tape to BOT after failing to write BOT ID",
107934221Sbostic 	014,	"failed to write density ID burst",
108034221Sbostic 	015,	"failed to write ARA burst",
108134221Sbostic 	016,	"failed to write ARA ID",
108234221Sbostic 	017,	"ARA error bit set in MTA status B register",
108334221Sbostic 	021,	"could not find a gap after ID code was written correctly",
108434221Sbostic 	022,	"TU CMD did not load correctly to start tape motion to read ID burst",
108534221Sbostic 	023,	"timeout looking for BOT after detecting ARA ID burst",
108634221Sbostic 	024,	"failed to write tape mark",
108734221Sbostic 	025,	"tape never came up to speed while trying to reposition for retry of writing tape mark",
108834221Sbostic 	026,	"TU CMD did not load correctly to start tape motion in erase gap routine",
108934221Sbostic 	027,	"could not detect a gap in in erase gap routine",
109034221Sbostic 	030,	"could not detect a gap after writing record",
109134221Sbostic 	031,	"read path terminated before entire record was written",
109234221Sbostic 	032,	"could not find a gap after writing record and read path terminated early",
109334221Sbostic 	033,	"TU CMD did not load correctly to backup for retry of write tape mark",
109434221Sbostic 	034,	"TU velocity changed after up to speed while trying to reposition for retry of writing tape mark",
109534221Sbostic 	035,	"TU CMD did not load correctly to backup to retry a load of BOT ID",
109634221Sbostic 	036,	"timeout looking for BOT after failing to write BOT ID",
109734221Sbostic 	037,	"TU velocity changed while writing PE gap before starting to write record",
109834221Sbostic 	040,	"TU CMD did not load correctly to set PE tape density at start of write BOT ID burst",
109934221Sbostic 	041,	"TU CMD did not load correctly to set GCR tape density after writing Density ID",
110034221Sbostic 	042,	"TU CMD did not load correctly to set PE tape density at start of read from BOT",
110134221Sbostic 	043,	"TU CMD did not load correctly to set GCR tape density after reading a GCR Density ID burst",
110234221Sbostic };
110317214Smckusick 
110434221Sbostic /* MTER_TMFLTB */
110534221Sbostic static char inlinetest[] = "inline test failed";
110634221Sbostic static struct fmesg tmfltbmsg[] = {
110734221Sbostic 	00,	"RST0 interrupt occurred with TM RDY set",
110834221Sbostic 	01,	"power failed to interrupt",
110934221Sbostic 	02,	"unknown interrupt on channel 5.5",
111034221Sbostic 	03,	"unknown interrupt on channel 6.5",
111134221Sbostic 	04,	"unknown interrupt on channel 7",
111234221Sbostic 	05,	"unknown interrupt on channel 7.5",
111334221Sbostic 	06,	"CAS contention retry count expired",
111434221Sbostic 	07,	"CAS contention error not retryable",
111534221Sbostic 	010,	"queue error, could not find queue entry",
111634221Sbostic 	011,	"queue entry already full",
111734221Sbostic 	012,	"8085 ROM parity error",
111834221Sbostic 	013,	inlinetest,
111934221Sbostic 	013,	inlinetest,
112034221Sbostic 	014,	inlinetest,
112134221Sbostic 	015,	inlinetest,
112234221Sbostic 	016,	inlinetest,
112334221Sbostic 	017,	inlinetest,
112434221Sbostic 	020,	inlinetest,
112534221Sbostic 	021,	inlinetest,
112634221Sbostic 	022,	inlinetest,
112734221Sbostic 	023,	inlinetest,
112834221Sbostic 	024,	inlinetest,
112934221Sbostic 	025,	inlinetest,
113034221Sbostic 	026,	inlinetest,
113134221Sbostic 	027,	inlinetest,
113234221Sbostic 	030,	inlinetest,
113334221Sbostic 	031,	inlinetest,
113434221Sbostic 	032,	inlinetest,
113534221Sbostic 	033,	inlinetest,
113634221Sbostic 	034,	inlinetest,
113734221Sbostic 	035,	inlinetest,
113834221Sbostic 	036,	inlinetest,
113934221Sbostic 	037,	inlinetest,
114034221Sbostic 	040,	inlinetest,
114134221Sbostic 	041,	inlinetest,
114234221Sbostic 	042,	inlinetest,
114334221Sbostic 	043,	inlinetest,
114434221Sbostic 	044,	inlinetest,
114536548Sbostic 	045,	inlinetest,
114634221Sbostic 	046,	inlinetest,
114734221Sbostic 	047,	inlinetest,
114834221Sbostic 	050,	inlinetest,
114934221Sbostic 	051,	inlinetest,
115034221Sbostic 	052,	inlinetest,
115134221Sbostic 	053,	inlinetest,
115234221Sbostic 	054,	inlinetest,
115334221Sbostic 	055,	inlinetest,
115434221Sbostic 	056,	inlinetest,
115534221Sbostic 	057,	inlinetest,
115634221Sbostic 	-1,	unclass
115734221Sbostic };
115817214Smckusick 
115934221Sbostic /* MTER_MBFLT */
116034221Sbostic static struct fmesg mbfltmsg[] = {
116134221Sbostic 	01,	"control bus parity error",
116234221Sbostic 	02,	"illegal register referenced",
116334221Sbostic 	-1,	unclass
116434221Sbostic };
116517214Smckusick 
116634221Sbostic /*
116734221Sbostic  * MTER_LEOT, MTER_RWDING, NTER_NOTAVL, MTER_NONEX, MTER_KEYFAIL,
116834221Sbostic  * and default: no failure message.
116934221Sbostic  */
117034221Sbostic static struct fmesg nullmsg[] = {
117134221Sbostic 	-1,	""
117234221Sbostic };
117317214Smckusick 
117434221Sbostic /*
117534221Sbostic  * Interrupt code table.
117634221Sbostic  */
117734221Sbostic static struct errmsg {
117834221Sbostic 	int	e_code;
117934221Sbostic 	char	*e_mesg;
118034221Sbostic 	struct	fmesg *e_fmesg;
118134221Sbostic } errmsg[] = {
118234221Sbostic 	MTER_BOT,	"unexpected BOT",	botmsg,
118334221Sbostic 	MTER_LEOT,	"unexpected LEOT",	nullmsg,
118434221Sbostic 	MTER_RWDING,	"tape rewinding",	nullmsg,
118534221Sbostic 	MTER_NOTRDY,	"drive not ready",	notrdymsg,
118634221Sbostic 	MTER_NOTAVL,	"drive not available",	nullmsg,
118734221Sbostic 	MTER_NONEX,	"unit does not exist",	nullmsg,
118834221Sbostic 	MTER_NOTCAP,	"not capable",		notcapmsg,
118934221Sbostic 	MTER_LONGREC,	"long record",		longrecmsg,
119034221Sbostic 	MTER_UNREAD,	"unreadable record",	code22msg,
119134221Sbostic 	MTER_ERROR,	"error",		code22msg,
119234221Sbostic 	MTER_EOTERR,	"EOT error",		code22msg,
119334221Sbostic 	MTER_BADTAPE,	"tape position lost",	code22msg,
119434221Sbostic 	MTER_TMFLTA,	"TM fault A",		tmfltamsg,
119534221Sbostic 	MTER_TUFLTA,	"TU fault A",		tufltamsg,
119634221Sbostic 	MTER_TMFLTB,	"TM fault B",		tmfltbmsg,
119734221Sbostic 	MTER_MBFLT,	"MB fault",		mbfltmsg,
119834221Sbostic 	MTER_KEYFAIL,	"keypad entry error",	nullmsg,
119934221Sbostic 	-1,		"unclassified error",	nullmsg
120034221Sbostic };
120117214Smckusick 
120234221Sbostic /*
120334221Sbostic  * Decode an interrupt-time failure.
120434221Sbostic  */
120534221Sbostic mtintfail(erreg)
120634221Sbostic 	int erreg;
120734221Sbostic {
120834221Sbostic 	register struct errmsg *e;
120934221Sbostic 	register struct fmesg *f;
121034221Sbostic 	register int ecode, fcode;
121117214Smckusick 
121234221Sbostic 	ecode = erreg & MTER_INTCODE;
121334221Sbostic 	fcode = (erreg & MTER_FAILCODE) >> MTER_FSHIFT;
121434221Sbostic 	for (e = errmsg; e->e_code >= 0; e++)
121534221Sbostic 		if (e->e_code == ecode)
121617214Smckusick 			break;
121734221Sbostic 	for (f = e->e_fmesg; f->f_code >= 0; f++)
121834221Sbostic 		if (f->f_code == fcode)
121917214Smckusick 			break;
122034221Sbostic 	printf("    interrupt code = 0%o <%s>\n", ecode, e->e_mesg);
122134221Sbostic 	printf("    failure code = 0%o <%s>\n", fcode, f->f_mesg);
122217214Smckusick }
122334221Sbostic #endif /* MTLERRM */
122434221Sbostic #endif /* NMT > 0 */
1225