xref: /csrg-svn/sys/vax/mba/mt.c (revision 8471)
1*8471Sroot /*	mt.c	4.10	82/10/10	*/
24736Swnj 
34736Swnj #include "mu.h"
44736Swnj #if NMT > 0
54736Swnj /*
64736Swnj  * TM78/TU78 tape driver
74736Swnj  *
84736Swnj  *	Behavior in complex error situations is uncertain...
94736Swnj  *
104736Swnj  * TODO:
114736Swnj  *	test error recovery
124736Swnj  *	add odd byte count kludge from VMS driver
134736Swnj  *	write dump routine
144736Swnj  */
154736Swnj #include "../h/param.h"
164736Swnj #include "../h/systm.h"
174736Swnj #include "../h/buf.h"
184736Swnj #include "../h/conf.h"
194736Swnj #include "../h/dir.h"
204736Swnj #include "../h/file.h"
214736Swnj #include "../h/user.h"
224736Swnj #include "../h/map.h"
234736Swnj #include "../h/pte.h"
247637Ssam #include "../h/ioctl.h"
254736Swnj #include "../h/mtio.h"
264736Swnj #include "../h/cmap.h"
277740Sroot #include "../h/uio.h"
284736Swnj 
29*8471Sroot #include "../vax/cpu.h"
30*8471Sroot #include "../vaxmba/mbareg.h"
31*8471Sroot #include "../vaxmba/mbavar.h"
32*8471Sroot #include "../vaxmba/mtreg.h"
334736Swnj 
344736Swnj struct	buf	rmtbuf[NMT];
354736Swnj struct	buf	cmtbuf[NMT];
364736Swnj 
374736Swnj short	mttypes[] =
384736Swnj 	{ MBDT_TU78, 0 };
394736Swnj struct	mba_device *mtinfo[NMT];
404736Swnj int	mtattach(), mtslave(), mtustart(), mtstart(), mtndtint(), mtdtint();
414736Swnj struct	mba_driver mtdriver =
424736Swnj     { mtattach, mtslave, mtustart, mtstart, mtdtint, mtndtint,
434736Swnj       mttypes, "mt", "mu", mtinfo };
444736Swnj 
454736Swnj #define MASKREG(r)	((r) & 0xffff)
464736Swnj 
474736Swnj /* bits in minor device */
484736Swnj #define	MUUNIT(dev)	(minor(dev)&03)
494736Swnj #define	H_NOREWIND	04
504736Swnj #define	H_6250BPI	08
514736Swnj 
524736Swnj #define MTUNIT(dev)	(mutomt[MUUNIT(dev)])
534736Swnj 
544736Swnj #define	INF	(daddr_t)1000000L	/* a block number that wont exist */
554736Swnj 
564736Swnj struct	mu_softc {
574736Swnj 	char	sc_openf;
584736Swnj 	char	sc_flags;
594736Swnj 	daddr_t	sc_blkno;
604736Swnj 	daddr_t	sc_nxrec;
614736Swnj 	u_short	sc_erreg;
624736Swnj 	u_short	sc_dsreg;
634736Swnj 	short	sc_resid;
644736Swnj 	short	sc_dens;
654736Swnj 	struct	mba_device *sc_mi;
664736Swnj 	int	sc_slave;
674736Swnj } mu_softc[NMU];
684736Swnj short	mutomt[NMU];
694736Swnj 
704736Swnj /*
714736Swnj  * Bits for sc_flags.
724736Swnj  */
734736Swnj #define	H_WRITTEN 1	/* last operation was a write */
744736Swnj 
754736Swnj char	mtds_bits[] = MTDS_BITS;
764736Swnj 
774736Swnj /*ARGSUSED*/
784736Swnj mtattach(mi)
794736Swnj 	struct mba_device *mi;
804736Swnj {
816186Ssam #ifdef lint
827740Sroot 	mtread(0, 0); mtwrite(0); mtioctl(0, 0, 0, 0);
836186Ssam #endif
844736Swnj }
854736Swnj 
867431Skre mtslave(mi, ms, sn)
874736Swnj 	struct mba_device *mi;
884736Swnj 	struct mba_slave *ms;
897431Skre 	int sn;
904736Swnj {
914736Swnj 	register struct mu_softc *sc = &mu_softc[ms->ms_unit];
924736Swnj 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
934736Swnj 	int s = spl7(), rtn = 0;
944736Swnj 
954736Swnj 	mtaddr->mtas = -1;
967431Skre 	mtaddr->mtncs[sn] = MT_SENSE|MT_GO;
974736Swnj 	while (mtaddr->mtas == 0)
984736Swnj 		;
994736Swnj 	if ((mtaddr->mtner & MTER_INTCODE) == MTER_DONE &&
1004736Swnj 	    (mtaddr->mtds & MTDS_PRES)) {
1014736Swnj 		sc->sc_mi = mi;
1027431Skre 		sc->sc_slave = sn;
1034736Swnj 		mutomt[ms->ms_unit] = mi->mi_unit;
1044736Swnj 		rtn = 1;
1054736Swnj 	}
1064736Swnj 	mtaddr->mtas = mtaddr->mtas;
1074736Swnj 	splx(s);
1084736Swnj 	return (rtn);
1094736Swnj }
1104736Swnj 
1114736Swnj mtopen(dev, flag)
1124736Swnj 	dev_t dev;
1134736Swnj 	int flag;
1144736Swnj {
1154736Swnj 	register int muunit;
1164736Swnj 	register struct mba_device *mi;
1174736Swnj 	register struct mu_softc *sc;
1184736Swnj 	int olddens, dens;
1194736Swnj 
1204736Swnj 	muunit = MUUNIT(dev);
1214736Swnj 	if (muunit >= NMU || (sc = &mu_softc[muunit])->sc_openf ||
1224736Swnj 	    (mi = mtinfo[MTUNIT(dev)]) == 0 || mi->mi_alive == 0) {
1234736Swnj 		u.u_error = ENXIO;
1244736Swnj 		return;
1254736Swnj 	}
1264736Swnj 	olddens = sc->sc_dens;
1274736Swnj 	dens = sc->sc_dens = (minor(dev)&H_6250BPI) ? MT_GCR : 0;
1284736Swnj 	mtcommand(dev, MT_SENSE, 1);
1294736Swnj 	sc->sc_dens = olddens;
1304736Swnj 	if ((sc->sc_dsreg & MTDS_ONL) == 0) {
1314736Swnj 		uprintf("mu%d: not online\n", muunit);
1324736Swnj 		u.u_error = EIO;
1334736Swnj 		return;
1344736Swnj 	}
1354736Swnj 	if ((flag&FWRITE) && (sc->sc_dsreg&MTDS_FPT)) {
1364736Swnj 		uprintf("mu%d: no write ring\n", muunit);
1374736Swnj 		u.u_error = EIO;
1384736Swnj 		return;
1394736Swnj 	}
1404736Swnj 	if ((sc->sc_dsreg & MTDS_BOT) == 0 && (flag&FWRITE) &&
1414736Swnj 	    dens != sc->sc_dens) {
1424736Swnj 		uprintf("mu%d: can't change density in mid-tape\n", muunit);
1434736Swnj 		u.u_error = EIO;
1444736Swnj 		return;
1454736Swnj 	}
1464736Swnj 	sc->sc_openf = 1;
1474736Swnj 	sc->sc_blkno = (daddr_t)0;
1484736Swnj 	sc->sc_nxrec = INF;
1494736Swnj 	sc->sc_flags = 0;
1504736Swnj 	sc->sc_dens = dens;
1514736Swnj }
1524736Swnj 
1534736Swnj mtclose(dev, flag)
1544736Swnj 	register dev_t dev;
1554736Swnj 	register flag;
1564736Swnj {
1574736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
1584736Swnj 
1594736Swnj 	if (flag == FWRITE || ((flag&FWRITE) && (sc->sc_flags&H_WRITTEN)))
1604736Swnj 		mtcommand(dev, MT_CLS|sc->sc_dens, 1);
1614736Swnj 	if ((minor(dev)&H_NOREWIND) == 0)
1624736Swnj 		mtcommand(dev, MT_REW, 0);
1634736Swnj 	sc->sc_openf = 0;
1644736Swnj }
1654736Swnj 
1664736Swnj mtcommand(dev, com, count)
1674736Swnj 	dev_t dev;
1684736Swnj 	int com, count;
1694736Swnj {
1704736Swnj 	register struct buf *bp;
1715437Sroot 	register int s;
1724736Swnj 
1734736Swnj 	bp = &cmtbuf[MTUNIT(dev)];
1745437Sroot 	s = spl5();
1754736Swnj 	while (bp->b_flags&B_BUSY) {
1764736Swnj 		if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE))
1774736Swnj 			break;
1784736Swnj 		bp->b_flags |= B_WANTED;
1794736Swnj 		sleep((caddr_t)bp, PRIBIO);
1804736Swnj 	}
1814736Swnj 	bp->b_flags = B_BUSY|B_READ;
1825437Sroot 	splx(s);
1834736Swnj 	bp->b_dev = dev;
1844736Swnj 	bp->b_command = com;
1854736Swnj 	bp->b_repcnt = count;
1864736Swnj 	bp->b_blkno = 0;
1874736Swnj 	mtstrategy(bp);
1884736Swnj 	if (count == 0)
1894736Swnj 		return;
1904736Swnj 	iowait(bp);
1914736Swnj 	if (bp->b_flags&B_WANTED)
1924736Swnj 		wakeup((caddr_t)bp);
1934736Swnj 	bp->b_flags &= B_ERROR;
1944736Swnj }
1954736Swnj 
1964736Swnj mtstrategy(bp)
1974736Swnj 	register struct buf *bp;
1984736Swnj {
1994736Swnj 	register struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)];
2004736Swnj 	register struct buf *dp;
2015437Sroot 	register int s;
2024736Swnj 
2034736Swnj 	bp->av_forw = NULL;
2044736Swnj 	dp = &mi->mi_tab;
2055437Sroot 	s = spl5();
2064736Swnj 	if (dp->b_actf == NULL)
2074736Swnj 		dp->b_actf = bp;
2084736Swnj 	else
2094736Swnj 		dp->b_actl->av_forw = bp;
2104736Swnj 	dp->b_actl = bp;
2114736Swnj 	if (dp->b_active == 0)
2124736Swnj 		mbustart(mi);
2135437Sroot 	splx(s);
2144736Swnj }
2154736Swnj 
2164736Swnj mtustart(mi)
2174736Swnj 	register struct mba_device *mi;
2184736Swnj {
2194736Swnj 	register struct mtdevice *mtaddr =
2204736Swnj 	    (struct mtdevice *)mi->mi_drv;
2214736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
2224736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
2234736Swnj 	daddr_t blkno;
2244736Swnj 
2254736Swnj 	sc->sc_flags &= ~H_WRITTEN;
2264736Swnj 	if (sc->sc_openf < 0) {
2274736Swnj 		bp->b_flags |= B_ERROR;
2284736Swnj 		return (MBU_NEXT);
2294736Swnj 	}
2304736Swnj 	if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) {
2317380Ssam 		if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) {
2324736Swnj 			bp->b_flags |= B_ERROR;
2334736Swnj 			bp->b_error = ENXIO;
2344736Swnj 			return (MBU_NEXT);
2354736Swnj 		}
2367380Ssam 		if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec &&
2374736Swnj 		    bp->b_flags&B_READ) {
2384736Swnj 			bp->b_resid = bp->b_bcount;
2394736Swnj 			clrbuf(bp);
2404736Swnj 			return (MBU_NEXT);
2414736Swnj 		}
2424736Swnj 		if ((bp->b_flags&B_READ)==0)
2437380Ssam 			sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1;
2444736Swnj 	} else {
2454736Swnj 		mtaddr->mtncs[MUUNIT(bp->b_dev)] =
2464736Swnj 			(bp->b_repcnt<<8)|bp->b_command|MT_GO;
2474736Swnj 		return (MBU_STARTED);
2484736Swnj 	}
2497380Ssam 	if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) {
2504736Swnj 		if (mi->mi_tab.b_errcnt == 2) {
2514736Swnj 			mtaddr->mtca = MUUNIT(bp->b_dev);
2524736Swnj 		} else {
2534736Swnj 			mtaddr->mtbc = bp->b_bcount;
2544736Swnj 			mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev);
2554736Swnj 		}
2564736Swnj 		return (MBU_DODATA);
2574736Swnj 	}
2587380Ssam 	if (blkno < bdbtofsb(bp->b_blkno))
2594736Swnj 		mtaddr->mtncs[MUUNIT(bp->b_dev)] =
2607380Ssam 		  (min((unsigned)(bdbtofsb(bp->b_blkno) - blkno), 0377) << 8) |
2616186Ssam 			MT_SFORW|MT_GO;
2624736Swnj 	else
2634736Swnj 		mtaddr->mtncs[MUUNIT(bp->b_dev)] =
2647380Ssam 		  (min((unsigned)(blkno - bdbtofsb(bp->b_blkno)), 0377) << 8) |
2656186Ssam 			MT_SREV|MT_GO;
2664736Swnj 	return (MBU_STARTED);
2674736Swnj }
2684736Swnj 
2694736Swnj mtstart(mi)
2704736Swnj 	register struct mba_device *mi;
2714736Swnj {
2724736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
2734736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
2744736Swnj 
2754736Swnj 	if (bp->b_flags & B_READ)
2764736Swnj 		if (mi->mi_tab.b_errcnt == 2)
2774736Swnj 			return(MT_READREV|MT_GO);
2784736Swnj 		else
2794736Swnj 			return(MT_READ|MT_GO);
2804736Swnj 	else
2814736Swnj 		return(MT_WRITE|sc->sc_dens|MT_GO);
2824736Swnj }
2834736Swnj 
2844736Swnj mtdtint(mi, mbsr)
2854736Swnj 	register struct mba_device *mi;
2864736Swnj 	int mbsr;
2874736Swnj {
2884736Swnj 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
2894736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
2904736Swnj 	register struct mu_softc *sc;
2914736Swnj 
2924736Swnj 	/* I'M NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */
2934736Swnj 	if ((mtaddr->mtca&3) != MUUNIT(bp->b_dev)) {
2944736Swnj 		printf("mt: wrong unit!\n");
2954736Swnj 		mtaddr->mtca = MUUNIT(bp->b_dev);
2964736Swnj 	}
2974736Swnj 	sc = &mu_softc[MUUNIT(bp->b_dev)];
2984736Swnj 	sc->sc_erreg = mtaddr->mter;
2994736Swnj 	if((bp->b_flags & B_READ) == 0)
3004736Swnj 		sc->sc_flags |= H_WRITTEN;
3014736Swnj 	switch (sc->sc_erreg & MTER_INTCODE) {
3024736Swnj 	case MTER_DONE:
3034736Swnj 	case MTER_LONGREC:
3044736Swnj 		if (mi->mi_tab.b_errcnt != 2)
3054736Swnj 			sc->sc_blkno++;
3064736Swnj 		bp->b_resid = 0;
3074736Swnj 		break;
3084736Swnj 
3094736Swnj 	case MTER_NOTCAP:
3104736Swnj 		printf("mu%d: blank tape\n", MUUNIT(bp->b_dev));
3114736Swnj 		goto err;
3124736Swnj 
3134736Swnj 	case MTER_TM:
3144736Swnj 	case MTER_EOT:
3154736Swnj 		sc->sc_blkno++;
3164736Swnj 	err:
3174736Swnj 		bp->b_resid = bp->b_bcount;
3187380Ssam 		sc->sc_nxrec = bdbtofsb(bp->b_blkno);
3194736Swnj 		break;
3204736Swnj 
3214736Swnj 	case MTER_SHRTREC:
3224736Swnj 		sc->sc_blkno++;
3234736Swnj 		if (bp != &rmtbuf[MTUNIT(bp->b_dev)])
3244736Swnj 			bp->b_flags |= B_ERROR;
3254736Swnj 		if (mi->mi_tab.b_errcnt == 2)
3264736Swnj 			bp->b_bcount = bp->b_resid;	/* restore saved value */
3274736Swnj 		bp->b_resid = bp->b_bcount - mtaddr->mtbc;
3284736Swnj 		break;
3294736Swnj 
3304736Swnj 	case MTER_RDOPP:
3314736Swnj 		mi->mi_tab.b_errcnt = 2;	/* indicate "read opposite" */
3324736Swnj 		bp->b_resid = bp->b_bcount;	/* save it */
3334736Swnj 		bp->b_bcount = mtaddr->mtbc;	/* use this instead */
3344736Swnj 		return(MBD_RETRY);
3354736Swnj 
3364736Swnj 	case MTER_RETRY:
3374736Swnj 		mi->mi_tab.b_errcnt = 1;	/* indicate simple retry */
3384736Swnj 		return(MBD_RETRY);
3394736Swnj 
3404736Swnj 	case MTER_OFFLINE:
3414736Swnj 		if (sc->sc_openf > 0) {
3424736Swnj 			sc->sc_openf = -1;
3434736Swnj 			printf("mu%d: offline\n", MUUNIT(bp->b_dev));
3444736Swnj 		}
3454736Swnj 		bp->b_flags |= B_ERROR;
3464736Swnj 		break;
3474736Swnj 
3484736Swnj 	case MTER_FPT:
3494736Swnj 		printf("mu%d: no write ring\n", MUUNIT(bp->b_dev));
3504736Swnj 		bp->b_flags |= B_ERROR;
3514736Swnj 		break;
3524736Swnj 
3534736Swnj 	default:
3544736Swnj 		printf("mu%d: hard error bn%d mbsr=%b er=%x ds=%b\n",
3554736Swnj 		    MUUNIT(bp->b_dev), bp->b_blkno,
3564736Swnj 		    mbsr, mbsr_bits, sc->sc_erreg,
3574736Swnj 		    sc->sc_dsreg, mtds_bits);
3584736Swnj 		bp->b_flags |= B_ERROR;
3594736Swnj 		mtaddr->mtid = MTID_CLR;		/* reset the TM78 */
3604736Swnj 		DELAY(250);
3614736Swnj 		while ((mtaddr->mtid & MTID_RDY) == 0)	/* wait for it */
3624736Swnj 			;
3634736Swnj 		return (MBD_DONE);
3644736Swnj 	}
3654736Swnj 	/* CHECK FOR MBA ERROR WHEN NO OTHER ERROR INDICATED? */
3664736Swnj 	return (MBD_DONE);
3674736Swnj }
3684736Swnj 
3694736Swnj mtndtint(mi)
3704736Swnj 	register struct mba_device *mi;
3714736Swnj {
3724736Swnj 	register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
3734736Swnj 	register struct buf *bp = mi->mi_tab.b_actf;
3744736Swnj 	register struct mu_softc *sc;
3754736Swnj 	int er, fc, unit;
3764736Swnj 
3774736Swnj 	unit = (mtaddr->mtner >> 8) & 3;
3784736Swnj 	er = MASKREG(mtaddr->mtner);
3794736Swnj 	/* WILL THIS OCCUR IF ANOTHER DRIVE COMES ONLINE? */
3804736Swnj 	if (bp == 0 || unit != MUUNIT(bp->b_dev)) {	/* consistency check */
3814736Swnj 		if ((er & MTER_INTCODE) != MTER_ONLINE)
3824736Swnj 			printf("mt: unit %d random interrupt\n", unit);
3834736Swnj 		return (MBN_SKIP);
3844736Swnj 	}
3854736Swnj 	if (bp == 0)
3864736Swnj 		return (MBN_SKIP);
3874736Swnj 	fc = (mtaddr->mtncs[unit] >> 8) & 0xff;
3884736Swnj 	sc = &mu_softc[unit];
3894736Swnj 	sc->sc_erreg = er;
3904736Swnj 	sc->sc_resid = fc;
3914736Swnj 	switch (er & MTER_INTCODE) {
3924736Swnj 	case MTER_DONE:
3934736Swnj 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) {
3944736Swnj 	done:
3954736Swnj 			if (bp->b_command == MT_SENSE)
3964736Swnj 				sc->sc_dsreg = MASKREG(mtaddr->mtds);
3974736Swnj 			bp->b_resid = fc;
3984736Swnj 			return (MBN_DONE);
3994736Swnj 		}
4004736Swnj 		/* this is UGLY!  (but is it correct?) */
4017380Ssam 		if ((fc = bdbtofsb(bp->b_blkno) - sc->sc_blkno) < 0)
4026186Ssam 			sc->sc_blkno -= MIN(0377, -fc);
4034736Swnj 		else
4046186Ssam 			sc->sc_blkno += MIN(0377, fc);
4054736Swnj 		return (MBN_RETRY);
4064736Swnj 
4074736Swnj 	case MTER_RWDING:
4084736Swnj 		return (MBN_SKIP);	/* ignore "rewind started" interrupt */
4094736Swnj 
4104736Swnj 	case MTER_NOTCAP:
4114736Swnj 		printf("mu%d: blank tape\n", MUUNIT(bp->b_dev));
4124736Swnj 
4134736Swnj 	case MTER_TM:
4144736Swnj 	case MTER_EOT:
4154736Swnj 	case MTER_LEOT:
4167380Ssam 		if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) {
4177380Ssam 			sc->sc_nxrec = bdbtofsb(bp->b_blkno) + fc;
4184736Swnj 			sc->sc_blkno = sc->sc_nxrec;
4194736Swnj 		} else {
4207380Ssam 			sc->sc_blkno = bdbtofsb(bp->b_blkno) - fc;
4214736Swnj 			sc->sc_nxrec = sc->sc_blkno - 1;
4224736Swnj 		}
4234736Swnj 		return (MBN_RETRY);
4244736Swnj 
4254736Swnj 	case MTER_FPT:
4264736Swnj 		printf("mu%d: no write ring\n", MUUNIT(bp->b_dev));
4274736Swnj 		bp->b_flags |= B_ERROR;
4284736Swnj 		return (MBN_DONE);
4294736Swnj 
4304736Swnj 	case MTER_OFFLINE:
4314736Swnj 		if (sc->sc_openf > 0) {
4324736Swnj 			sc->sc_openf = -1;
4334736Swnj 			printf("mu%d: offline\n", MUUNIT(bp->b_dev));
4344736Swnj 		}
4354736Swnj 		bp->b_flags |= B_ERROR;
4364736Swnj 		return (MBN_DONE);
4374736Swnj 
4384736Swnj 	case MTER_BOT:
4394736Swnj 		if (bp == &cmtbuf[MTUNIT(bp->b_dev)])
4404736Swnj 			goto done;
4414736Swnj 		/* FALL THROUGH */
4424736Swnj 
4434736Swnj 	default:
4444736Swnj 		printf("mu%d: hard error bn%d er=%o ds=%b\n",
4454736Swnj 		    MUUNIT(bp->b_dev), bp->b_blkno,
4464736Swnj 		    sc->sc_erreg, sc->sc_dsreg, mtds_bits);
4474736Swnj 		mtaddr->mtid = MTID_CLR;		/* reset the TM78 */
4484736Swnj 		DELAY(250);
4494736Swnj 		while ((mtaddr->mtid & MTID_RDY) == 0)	/* wait for it */
4504736Swnj 			;
4514736Swnj 		bp->b_flags |= B_ERROR;
4524736Swnj 		return (MBN_DONE);
4534736Swnj 	}
4544736Swnj 	/* NOTREACHED */
4554736Swnj }
4564736Swnj 
4577740Sroot mtread(dev, uio)
4584736Swnj 	dev_t dev;
4597740Sroot 	struct uio *uio;
4604736Swnj {
4618158Sroot 	int errno;
4624736Swnj 
4638158Sroot 	errno = mtphys(dev, uio);
4648158Sroot 	if (errno)
4658158Sroot 		return (errno);
4668158Sroot 	return (physio(mtstrategy, &rmtbuf[MTUNIT(dev)], dev, B_READ, minphys, uio));
4674736Swnj }
4684736Swnj 
4697833Sroot mtwrite(dev, uio)
4707833Sroot 	dev_t dev;
4717833Sroot 	struct uio *uio;
4724736Swnj {
4738158Sroot 	int errno;
4744736Swnj 
4758158Sroot 	errno = mtphys(dev, uio);
4768158Sroot 	if (errno)
4778158Sroot 		return (errno);
4788158Sroot 	return (physio(mtstrategy, &rmtbuf[MTUNIT(dev)], dev, B_WRITE, minphys, uio));
4794736Swnj }
4804736Swnj 
4817740Sroot mtphys(dev, uio)
4824736Swnj 	dev_t dev;
4837740Sroot 	struct uio *uio;
4844736Swnj {
4854736Swnj 	register int mtunit;
4864736Swnj 	register struct mu_softc *sc;
4874736Swnj 	register struct mba_device *mi;
4884736Swnj 	daddr_t a;
4894736Swnj 
4904736Swnj 	mtunit = MTUNIT(dev);
4917833Sroot 	if (mtunit >= NMT || (mi = mtinfo[mtunit]) == 0 || mi->mi_alive == 0)
4927740Sroot 		return (ENXIO);
4937833Sroot 	a = uio->uio_offset >> 9;
4944736Swnj 	sc = &mu_softc[MUUNIT(dev)];
4957380Ssam 	sc->sc_blkno = bdbtofsb(a);
4967380Ssam 	sc->sc_nxrec = bdbtofsb(a)+1;
4977740Sroot 	return (0);
4984736Swnj }
4994736Swnj 
5004736Swnj /*ARGSUSED*/
5017637Ssam mtioctl(dev, cmd, data, flag)
5024736Swnj 	dev_t dev;
5034736Swnj 	int cmd;
5047637Ssam 	caddr_t data;
5054736Swnj 	int flag;
5064736Swnj {
5074736Swnj 	register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
5084736Swnj 	register struct buf *bp = &cmtbuf[MTUNIT(dev)];
5094736Swnj 	register callcount;
5106186Ssam 	register int op;
5114736Swnj 	int fcount;
5127637Ssam 	struct mtop *mtop;
5137637Ssam 	struct mtget *mtget;
5144736Swnj 	/* we depend of the values and order of the MT codes here */
5154736Swnj 	static mtops[] =
5164736Swnj 	{MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE};
5174736Swnj 
5184736Swnj 	switch (cmd) {
5197637Ssam 
5207637Ssam 	case MTIOCTOP:	/* tape operation */
5217637Ssam 		mtop = (struct mtop *)mtop;
5227637Ssam 		switch(mtop->mt_op) {
5237637Ssam 
5244736Swnj 		case MTWEOF:
5257637Ssam 			callcount = mtop->mt_count;
5264736Swnj 			fcount = 1;
5274736Swnj 			break;
5287637Ssam 
5294736Swnj 		case MTFSF: case MTBSF:
5307637Ssam 			callcount = mtop->mt_count;
5314736Swnj 			fcount = 1;
5324736Swnj 			break;
5337637Ssam 
5344736Swnj 		case MTFSR: case MTBSR:
5354736Swnj 			callcount = 1;
5367637Ssam 			fcount = mtop->mt_count;
5374736Swnj 			break;
5387637Ssam 
5394736Swnj 		case MTREW: case MTOFFL:
5404736Swnj 			callcount = 1;
5414736Swnj 			fcount = 1;
5424736Swnj 			break;
5437637Ssam 
5444736Swnj 		default:
5454736Swnj 			u.u_error = ENXIO;
5464736Swnj 			return;
5474736Swnj 		}
5484736Swnj 		if (callcount <= 0 || fcount <= 0) {
5494736Swnj 			u.u_error = ENXIO;
5504736Swnj 			return;
5514736Swnj 		}
5527637Ssam 		op = mtops[mtop->mt_op];
5534736Swnj 		if (op == MT_WTM)
5544736Swnj 			op |= sc->sc_dens;
5554736Swnj 		while (--callcount >= 0) {
5564736Swnj 			register int n;
5574736Swnj 
5584736Swnj 			do {
5596186Ssam 				n = MIN(fcount, 0xff);
5604736Swnj 				mtcommand(dev, op, n);
5614736Swnj 				fcount -= n;
5624736Swnj 			} while (fcount);
5637637Ssam 			if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) &&
5644736Swnj 			    bp->b_resid) {
5654736Swnj 				u.u_error = EIO;
5664736Swnj 				break;
5674736Swnj 			}
5684736Swnj 			if (bp->b_flags&B_ERROR)
5694736Swnj 				break;
5704736Swnj 		}
5714736Swnj 		geterror(bp);
5724736Swnj 		return;
5737637Ssam 
5744736Swnj 	case MTIOCGET:
5757637Ssam 		mtget = (struct mtget *)data;
5767637Ssam 		mtget->mt_erreg = sc->sc_erreg;
5777637Ssam 		mtget->mt_resid = sc->sc_resid;
5784736Swnj 		mtcommand(dev, MT_SENSE, 1);	/* update drive status */
5797637Ssam 		mtget->mt_dsreg = sc->sc_dsreg;
5807637Ssam 		mtget->mt_type = MT_ISMT;
5814736Swnj 		return;
5827637Ssam 
5834736Swnj 	default:
5844736Swnj 		u.u_error = ENXIO;
5854736Swnj 	}
5864736Swnj }
5874736Swnj 
5884736Swnj #define	DBSIZE	20
5894736Swnj 
5904736Swnj mtdump()
5914736Swnj {
5924736Swnj 	register struct mba_device *mi;
5934736Swnj 	register struct mba_regs *mp;
5944736Swnj 	register struct mtdevice *mtaddr;
5954736Swnj 	int blk, num;
5964736Swnj 	int start;
5974736Swnj 
5984736Swnj 	start = 0;
5994736Swnj 	num = maxfree;
6004736Swnj #define	phys(a,b)		((b)((int)(a)&0x7fffffff))
6014736Swnj 	if (mtinfo[0] == 0)
6024736Swnj 		return (ENXIO);
6034736Swnj 	mi = phys(mtinfo[0], struct mba_device *);
6044736Swnj 	mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba;
6054736Swnj 	mp->mba_cr = MBCR_IE;
6066186Ssam #if lint
6076186Ssam 	blk = blk; num = num; start = start;
6086186Ssam 	return (0);
6096186Ssam #endif
6106186Ssam #ifdef notyet
6114736Swnj 	mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive];
6124736Swnj 	mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI;
6134736Swnj 	mtaddr->mtcs1 = MT_DCLR|MT_GO;
6144736Swnj 	while (num > 0) {
6154736Swnj 		blk = num > DBSIZE ? DBSIZE : num;
6164736Swnj 		mtdwrite(start, blk, mtaddr, mp);
6174736Swnj 		start += blk;
6184736Swnj 		num -= blk;
6194736Swnj 	}
6204736Swnj 	mteof(mtaddr);
6214736Swnj 	mteof(mtaddr);
6224736Swnj 	mtwait(mtaddr);
6234736Swnj 	if (mtaddr->mtds&MTDS_ERR)
6244736Swnj 		return (EIO);
6254736Swnj 	mtaddr->mtcs1 = MT_REW|MT_GO;
6264736Swnj 	return (0);
6274736Swnj }
6284736Swnj 
6294736Swnj mtdwrite(dbuf, num, mtaddr, mp)
6304736Swnj 	register dbuf, num;
6314736Swnj 	register struct mtdevice *mtaddr;
6324736Swnj 	struct mba_regs *mp;
6334736Swnj {
6344736Swnj 	register struct pte *io;
6354736Swnj 	register int i;
6364736Swnj 
6374736Swnj 	mtwait(mtaddr);
6384736Swnj 	io = mp->mba_map;
6394736Swnj 	for (i = 0; i < num; i++)
6404736Swnj 		*(int *)io++ = dbuf++ | PG_V;
6414736Swnj 	mtaddr->mtfc = -(num*NBPG);
6424736Swnj 	mp->mba_sr = -1;
6434736Swnj 	mp->mba_bcr = -(num*NBPG);
6444736Swnj 	mp->mba_var = 0;
6454736Swnj 	mtaddr->mtcs1 = MT_WCOM|MT_GO;
6464736Swnj }
6474736Swnj 
6484736Swnj mtwait(mtaddr)
6494736Swnj 	struct mtdevice *mtaddr;
6504736Swnj {
6514736Swnj 	register s;
6524736Swnj 
6534736Swnj 	do
6544736Swnj 		s = mtaddr->mtds;
6554736Swnj 	while ((s & MTDS_DRY) == 0);
6564736Swnj }
6574736Swnj 
6584736Swnj mteof(mtaddr)
6594736Swnj 	struct mtdevice *mtaddr;
6604736Swnj {
6614736Swnj 
6624736Swnj 	mtwait(mtaddr);
6634736Swnj 	mtaddr->mtcs1 = MT_WEOF|MT_GO;
6644736Swnj #endif notyet
6654736Swnj }
6664736Swnj #endif
667