xref: /csrg-svn/sys/vax/uba/ut.c (revision 30917)
123357Smckusick /*
229255Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323357Smckusick  * All rights reserved.  The Berkeley software License Agreement
423357Smckusick  * specifies the terms and conditions for redistribution.
523357Smckusick  *
6*30917Skarels  *	@(#)ut.c	7.2 (Berkeley) 04/17/87
723357Smckusick  */
84744Swnj 
94862Sroot #include "tj.h"
104744Swnj #if NUT > 0
114744Swnj /*
124744Swnj  * System Industries Model 9700 Tape Drive
134744Swnj  *   emulates a TU45 on the UNIBUS
144744Swnj  *
154744Swnj  * TODO:
164744Swnj  *	check out attention processing
174744Swnj  *	try reset code and dump code
184744Swnj  */
1917083Sbloom #include "param.h"
2017083Sbloom #include "systm.h"
2117083Sbloom #include "buf.h"
2217083Sbloom #include "conf.h"
2317083Sbloom #include "dir.h"
2417083Sbloom #include "file.h"
2517083Sbloom #include "user.h"
2617083Sbloom #include "map.h"
2717083Sbloom #include "ioctl.h"
2817083Sbloom #include "mtio.h"
2917083Sbloom #include "cmap.h"
3017083Sbloom #include "uio.h"
3117083Sbloom #include "kernel.h"
3218323Sralph #include "tty.h"
33*30917Skarels #include "syslog.h"
344744Swnj 
35*30917Skarels #include "../machine/pte.h"
368483Sroot #include "../vax/cpu.h"
3717083Sbloom #include "ubareg.h"
3817083Sbloom #include "ubavar.h"
3917083Sbloom #include "utreg.h"
404744Swnj 
414744Swnj struct	buf	rutbuf[NUT];	/* bufs for raw i/o */
424744Swnj struct	buf	cutbuf[NUT];	/* bufs for control operations */
434744Swnj struct	buf	tjutab[NTJ];	/* bufs for slave queue headers */
444744Swnj 
454744Swnj struct uba_ctlr *utminfo[NUT];
464744Swnj struct uba_device *tjdinfo[NTJ];
474833Swnj int utprobe(), utslave(), utattach(), utdgo(), utintr(), uttimer();
484744Swnj u_short utstd[] = { 0772440, 0 };
494744Swnj struct uba_driver utdriver =
504744Swnj   { utprobe, utslave, utattach, utdgo, utstd, "tj", tjdinfo, "ut", utminfo, 0 };
514744Swnj 
5211176Ssam #define	MASKREG(reg)	((reg)&0xffff)
5311176Ssam 
544744Swnj /* bits in minor device */
554744Swnj #define	TJUNIT(dev)	(minor(dev)&03)
564744Swnj #define	T_NOREWIND	04
574744Swnj #define	T_1600BPI	010
584744Swnj #define	T_6250BPI	020
594744Swnj short	utdens[] = { UT_NRZI, UT_PE, UT_GCR, UT_NRZI };
604744Swnj 
614744Swnj /* slave to controller mapping table */
624744Swnj short	tjtout[NTJ];
634744Swnj #define UTUNIT(dev)	(tjtout[TJUNIT(dev)])
644744Swnj 
654744Swnj #define	INF	(daddr_t)1000000L	/* a block number that wont exist */
664744Swnj 
674744Swnj struct	tj_softc {
684744Swnj 	char	sc_openf;	/* exclusive open */
694744Swnj 	char	sc_lastiow;	/* last I/O operation was a write */
704744Swnj 	daddr_t	sc_blkno;	/* next block to transfer */
714744Swnj 	daddr_t	sc_nxrec;	/* next record on tape */
724744Swnj 	u_short	sc_erreg;	/* image of uter */
734744Swnj 	u_short	sc_dsreg;	/* image of utds */
744746Ssam 	u_short	sc_resid;	/* residual from transfer */
754744Swnj 	u_short	sc_dens;	/* sticky selected density */
764833Swnj 	daddr_t	sc_timo;	/* time until timeout expires */
774833Swnj 	short	sc_tact;	/* timeout is active flag */
7818323Sralph 	struct	tty *sc_ttyp;	/* record user's tty for errors */
79*30917Skarels 	int	sc_blks;	/* number of I/O operations since open */
80*30917Skarels 	int	sc_softerrs;	/* number of soft I/O errors since open */
814744Swnj } tj_softc[NTJ];
824744Swnj 
834744Swnj /*
844744Swnj  * Internal per/slave states found in sc_state
854744Swnj  */
864744Swnj #define	SSEEK		1	/* seeking */
874744Swnj #define	SIO		2	/* doing sequential I/O */
884744Swnj #define	SCOM		3	/* sending a control command */
894744Swnj #define	SREW		4	/* doing a rewind op */
904746Ssam #define	SERASE		5	/* erase inter-record gap */
914746Ssam #define	SERASED		6	/* erased inter-record gap */
924744Swnj 
934941Swnj /*ARGSUSED*/
944744Swnj utprobe(reg)
954744Swnj 	caddr_t reg;
964744Swnj {
974744Swnj 	register int br, cvec;
984744Swnj #ifdef lint
994744Swnj 	br=0; cvec=br; br=cvec;
1004941Swnj 	utintr(0);
1014744Swnj #endif
1024746Ssam 	/*
1036954Sroot 	 * The SI documentation says you must set the RDY bit
1046954Sroot 	 * (even though it's read-only) to force an interrupt.
1054746Ssam 	 */
1066954Sroot 	((struct utdevice *) reg)->utcs1 = UT_IE|UT_NOP|UT_RDY;
1074744Swnj 	DELAY(10000);
1087405Skre 	return (sizeof (struct utdevice));
1094744Swnj }
1104744Swnj 
1114744Swnj /*ARGSUSED*/
1124744Swnj utslave(ui, reg)
1134744Swnj 	struct uba_device *ui;
1144744Swnj 	caddr_t reg;
1154744Swnj {
1164744Swnj 	/*
1174744Swnj 	 * A real TU45 would support the slave present bit
1184744Swnj 	 * int the drive type register, but this thing doesn't,
1194744Swnj 	 * so there's no way to determine if a slave is present or not.
1204744Swnj 	 */
1214744Swnj 	 return(1);
1224744Swnj }
1234744Swnj 
1244744Swnj utattach(ui)
1254744Swnj 	struct uba_device *ui;
1264744Swnj {
1274744Swnj 	tjtout[ui->ui_unit] = ui->ui_mi->um_ctlr;
1284744Swnj }
1294744Swnj 
1304744Swnj /*
1314744Swnj  * Open the device with exclusive access.
1324744Swnj  */
1334744Swnj utopen(dev, flag)
1344744Swnj 	dev_t dev;
1354744Swnj 	int flag;
1364744Swnj {
1374744Swnj 	register int tjunit = TJUNIT(dev);
1384744Swnj 	register struct uba_device *ui;
1394744Swnj 	register struct tj_softc *sc;
1404744Swnj 	int olddens, dens;
1415439Sroot 	register int s;
1424744Swnj 
14325053Skarels 	if (tjunit >= NTJ || (ui = tjdinfo[tjunit]) == 0 || ui->ui_alive == 0)
1448577Sroot 		return (ENXIO);
14525053Skarels 	if ((sc = &tj_softc[tjunit])->sc_openf)
14625053Skarels 		return (EBUSY);
147*30917Skarels 	sc->sc_openf = 1;
1484744Swnj 	olddens = sc->sc_dens;
1498577Sroot 	dens = sc->sc_dens =
1508577Sroot 	    utdens[(minor(dev)&(T_1600BPI|T_6250BPI))>>3]|
1518577Sroot 	      PDP11FMT|(ui->ui_slave&07);
1524744Swnj get:
1534744Swnj 	utcommand(dev, UT_SENSE, 1);
1544744Swnj 	if (sc->sc_dsreg&UTDS_PIP) {
1559174Ssam 		sleep((caddr_t)&lbolt, PZERO+1);
1564744Swnj 		goto get;
1574744Swnj 	}
1584744Swnj 	sc->sc_dens = olddens;
1594744Swnj 	if ((sc->sc_dsreg&UTDS_MOL) == 0) {
160*30917Skarels 		sc->sc_openf = 0;
1614744Swnj 		uprintf("tj%d: not online\n", tjunit);
1628577Sroot 		return (EIO);
1634744Swnj 	}
1644744Swnj 	if ((flag&FWRITE) && (sc->sc_dsreg&UTDS_WRL)) {
165*30917Skarels 		sc->sc_openf = 0;
1664744Swnj 		uprintf("tj%d: no write ring\n", tjunit);
1678577Sroot 		return (EIO);
1684744Swnj 	}
1694744Swnj 	if ((sc->sc_dsreg&UTDS_BOT) == 0 && (flag&FWRITE) &&
1704744Swnj 	    dens != sc->sc_dens) {
171*30917Skarels 		sc->sc_openf = 0;
1724744Swnj 		uprintf("tj%d: can't change density in mid-tape\n", tjunit);
1738577Sroot 		return (EIO);
1744744Swnj 	}
1754744Swnj 	sc->sc_blkno = (daddr_t)0;
1764744Swnj 	sc->sc_nxrec = INF;
1774744Swnj 	sc->sc_lastiow = 0;
178*30917Skarels 	sc->sc_blks = 0;
179*30917Skarels 	sc->sc_softerrs = 0;
1804744Swnj 	sc->sc_dens = dens;
18118323Sralph 	sc->sc_ttyp = u.u_ttyp;
1824746Ssam 	/*
1834746Ssam 	 * For 6250 bpi take exclusive use of the UNIBUS.
1844746Ssam 	 */
1854746Ssam 	ui->ui_driver->ud_xclu = (dens&(T_1600BPI|T_6250BPI)) == T_6250BPI;
18626374Skarels 	s = splclock();
1874833Swnj 	if (sc->sc_tact == 0) {
1884833Swnj 		sc->sc_timo = INF;
1894833Swnj 		sc->sc_tact = 1;
1904833Swnj 		timeout(uttimer, (caddr_t)dev, 5*hz);
1914833Swnj 	}
1925439Sroot 	splx(s);
1938577Sroot 	return (0);
1944744Swnj }
1954744Swnj 
1964744Swnj utclose(dev, flag)
1974744Swnj 	register dev_t dev;
1984744Swnj 	register flag;
1994744Swnj {
2004744Swnj 	register struct tj_softc *sc = &tj_softc[TJUNIT(dev)];
2014744Swnj 
2024744Swnj 	if (flag == FWRITE || ((flag&FWRITE) && sc->sc_lastiow)) {
2034744Swnj 		utcommand(dev, UT_WEOF, 1);
2044744Swnj 		utcommand(dev, UT_WEOF, 1);
2054744Swnj 		utcommand(dev, UT_SREV, 1);
2064744Swnj 	}
2074744Swnj 	if ((minor(dev)&T_NOREWIND) == 0)
2084744Swnj 		utcommand(dev, UT_REW, 0);
209*30917Skarels 	if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100)
210*30917Skarels 		log(LOG_INFO, "tj%d: %d soft errors in %d blocks\n",
211*30917Skarels 		    TJUNIT(dev), sc->sc_softerrs, sc->sc_blks);
2124744Swnj 	sc->sc_openf = 0;
2134744Swnj }
2144744Swnj 
2154744Swnj utcommand(dev, com, count)
2164744Swnj 	dev_t dev;
2174744Swnj 	int com, count;
2184744Swnj {
2194744Swnj 	register struct buf *bp;
2205439Sroot 	register int s;
2214744Swnj 
2224744Swnj 	bp = &cutbuf[UTUNIT(dev)];
2235439Sroot 	s = spl5();
2244744Swnj 	while (bp->b_flags&B_BUSY) {
2254744Swnj 		if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE))
2264744Swnj 			break;
2274744Swnj 		bp->b_flags |= B_WANTED;
2284744Swnj 		sleep((caddr_t)bp, PRIBIO);
2294744Swnj 	}
2304744Swnj 	bp->b_flags = B_BUSY|B_READ;
2315439Sroot 	splx(s);
2324744Swnj 	bp->b_dev = dev;
2334744Swnj 	bp->b_command = com;
2344744Swnj 	bp->b_repcnt = count;
2354744Swnj 	bp->b_blkno = 0;
2364744Swnj 	utstrategy(bp);
2374744Swnj 	if (count == 0)
2384744Swnj 		return;
2394744Swnj 	iowait(bp);
2404744Swnj 	if (bp->b_flags&B_WANTED)
2414744Swnj 		wakeup((caddr_t)bp);
2424744Swnj 	bp->b_flags &= B_ERROR;
2434744Swnj }
2444744Swnj 
2454744Swnj /*
2464744Swnj  * Queue a tape operation.
2474744Swnj  */
2484744Swnj utstrategy(bp)
2494744Swnj 	register struct buf *bp;
2504744Swnj {
2514744Swnj 	int tjunit = TJUNIT(bp->b_dev);
2524744Swnj 	register struct uba_ctlr *um;
2534744Swnj 	register struct buf *dp;
2544744Swnj 
2554744Swnj 	/*
2564744Swnj 	 * Put transfer at end of unit queue
2574744Swnj 	 */
2584744Swnj 	dp = &tjutab[tjunit];
2594744Swnj 	bp->av_forw = NULL;
26017433Skarels 	um = tjdinfo[tjunit]->ui_mi;
2614744Swnj 	(void) spl5();
2624744Swnj 	if (dp->b_actf == NULL) {
2634744Swnj 		dp->b_actf = bp;
2644744Swnj 		/*
2654744Swnj 		 * Transport not active, so...
2664744Swnj 		 * put at end of controller queue
2674744Swnj 		 */
2684744Swnj 		dp->b_forw = NULL;
2694744Swnj 		if (um->um_tab.b_actf == NULL)
2704744Swnj 			um->um_tab.b_actf = dp;
2714744Swnj 		else
2724744Swnj 			um->um_tab.b_actl->b_forw = dp;
2734744Swnj 		um->um_tab.b_actl = dp;
2744744Swnj 	} else
2754744Swnj 		dp->b_actl->av_forw = bp;
2764744Swnj 	dp->b_actl = bp;
2774744Swnj 	/*
2784744Swnj 	 * If the controller is not busy, set it going.
2794744Swnj 	 */
2804746Ssam 	if (um->um_tab.b_state == 0)
2814744Swnj 		utstart(um);
2824744Swnj 	(void) spl0();
2834744Swnj }
2844744Swnj 
2854744Swnj utstart(um)
2864744Swnj 	register struct uba_ctlr *um;
2874744Swnj {
2884746Ssam 	register struct utdevice *addr;
2894744Swnj 	register struct buf *bp, *dp;
2904744Swnj 	register struct tj_softc *sc;
2914744Swnj 	struct uba_device *ui;
2924744Swnj 	int tjunit;
2934744Swnj 	daddr_t blkno;
2944744Swnj 
2954744Swnj loop:
2964744Swnj 	/*
2974744Swnj 	 * Scan controller queue looking for units with
2984744Swnj 	 * transaction queues to dispatch
2994744Swnj 	 */
3004744Swnj 	if ((dp = um->um_tab.b_actf) == NULL)
3014744Swnj 		return;
3024744Swnj 	if ((bp = dp->b_actf) == NULL) {
3034744Swnj 		um->um_tab.b_actf = dp->b_forw;
3044744Swnj 		goto loop;
3054744Swnj 	}
3064746Ssam 	addr = (struct utdevice *)um->um_addr;
3074744Swnj 	tjunit = TJUNIT(bp->b_dev);
3084744Swnj 	ui = tjdinfo[tjunit];
3094744Swnj 	sc = &tj_softc[tjunit];
3104744Swnj 	/* note slave select, density, and format were merged on open */
3114746Ssam 	addr->uttc = sc->sc_dens;
3124746Ssam 	sc->sc_dsreg = addr->utds;
3134746Ssam 	sc->sc_erreg = addr->uter;
31411176Ssam 	sc->sc_resid = MASKREG(addr->utfc);
3154744Swnj 	/*
3164744Swnj 	 * Default is that last command was NOT a write command;
3174744Swnj 	 * if we do a write command we will notice this in utintr().
3184744Swnj 	 */
3194744Swnj 	sc->sc_lastiow = 0;
3204746Ssam 	if (sc->sc_openf < 0 || (addr->utds&UTDS_MOL) == 0) {
3214744Swnj 		/*
3224744Swnj 		 * Have had a hard error on a non-raw tape
3234744Swnj 		 * or the tape unit is now unavailable
3244744Swnj 		 * (e.g. taken off line).
3254744Swnj 		 */
3264744Swnj 		bp->b_flags |= B_ERROR;
3274744Swnj 		goto next;
3284744Swnj 	}
3294744Swnj 	if (bp == &cutbuf[UTUNIT(bp->b_dev)]) {
3304744Swnj 		/*
3314744Swnj 		 * Execute a control operation with the specified
3324744Swnj 		 * count.
3334744Swnj 		 */
3344744Swnj 		if (bp->b_command == UT_SENSE)
3354744Swnj 			goto next;
33611176Ssam 		if (bp->b_command == UT_SFORW && (addr->utds & UTDS_EOT)) {
33711176Ssam 			bp->b_resid = bp->b_bcount;
33811176Ssam 			goto next;
33911176Ssam 		}
3404744Swnj 		/*
3414744Swnj 		 * Set next state; handle timeouts
3424744Swnj 		 */
3434833Swnj 		if (bp->b_command == UT_REW) {
3444746Ssam 			um->um_tab.b_state = SREW;
3454833Swnj 			sc->sc_timo = 5*60;
3464833Swnj 		} else {
3474746Ssam 			um->um_tab.b_state = SCOM;
3484833Swnj 			sc->sc_timo = imin(imax(10*(int)-bp->b_repcnt,60),5*60);
3494833Swnj 		}
3504744Swnj 		/* NOTE: this depends on the ut command values */
3514744Swnj 		if (bp->b_command >= UT_SFORW && bp->b_command <= UT_SREVF)
3524746Ssam 			addr->utfc = -bp->b_repcnt;
3534744Swnj 		goto dobpcmd;
3544744Swnj 	}
3554744Swnj 	/*
3564744Swnj 	 * The following checks boundary conditions for operations
3574744Swnj 	 * on non-raw tapes.  On raw tapes the initialization of
3584744Swnj 	 * sc->sc_nxrec by utphys causes them to be skipped normally
3594744Swnj 	 * (except in the case of retries).
3604744Swnj 	 */
3617382Ssam 	if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) {
3624744Swnj 		/* can't read past end of file */
3634744Swnj 		bp->b_flags |= B_ERROR;
3644744Swnj 		bp->b_error = ENXIO;
3654744Swnj 		goto next;
3664744Swnj 	}
3677382Ssam 	if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && (bp->b_flags&B_READ)) {
3684744Swnj 		/* read at eof returns 0 count */
3694744Swnj 		bp->b_resid = bp->b_bcount;
3704744Swnj 		clrbuf(bp);
3714744Swnj 		goto next;
3724744Swnj 	}
3734744Swnj 	if ((bp->b_flags&B_READ) == 0)
3747382Ssam 		sc->sc_nxrec = bdbtofsb(bp->b_blkno)+1;
3754744Swnj 	/*
3764744Swnj 	 * If the tape is correctly positioned, set up all the
3774744Swnj 	 * registers but the csr, and give control over to the
3784744Swnj 	 * UNIBUS adaptor routines, to wait for resources to
3794744Swnj 	 * start I/O.
3804744Swnj 	 */
3817382Ssam 	if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) {
3824746Ssam 		addr->utwc = -(((bp->b_bcount)+1)>>1);
3834746Ssam 		addr->utfc = -bp->b_bcount;
3844744Swnj 		if ((bp->b_flags&B_READ) == 0) {
3854744Swnj 			/*
3864744Swnj 			 * On write error retries erase the
3874746Ssam 			 * inter-record gap before rewriting.
3884744Swnj 			 */
3894746Ssam 			if (um->um_tab.b_errcnt) {
3904746Ssam 				if (um->um_tab.b_state != SERASED) {
3914759Swnj 					um->um_tab.b_state = SERASE;
3924833Swnj 					sc->sc_timo = 60;
3934746Ssam 					addr->utcs1 = UT_ERASE|UT_IE|UT_GO;
3944746Ssam 					return;
3954746Ssam 				}
3964746Ssam 			}
39711176Ssam 			if (addr->utds & UTDS_EOT) {
39811176Ssam 				bp->b_resid = bp->b_bcount;
39911176Ssam 				um->um_tab.b_state = 0;
40011176Ssam 				goto next;
40111176Ssam 			}
4024746Ssam 			um->um_cmd = UT_WCOM;
4034744Swnj 		} else
4044744Swnj 			um->um_cmd = UT_RCOM;
4054833Swnj 		sc->sc_timo = 60;
4064746Ssam 		um->um_tab.b_state = SIO;
4074744Swnj 		(void) ubago(ui);
4084744Swnj 		return;
4094744Swnj 	}
4104744Swnj 	/*
4114744Swnj 	 * Tape positioned incorrectly; seek forwards or
4124744Swnj 	 * backwards to the correct spot.  This happens for
4134744Swnj 	 * raw tapes only on error retries.
4144744Swnj 	 */
4154746Ssam 	um->um_tab.b_state = SSEEK;
4167382Ssam 	if (blkno < bdbtofsb(bp->b_blkno)) {
4177382Ssam 		addr->utfc = blkno - bdbtofsb(bp->b_blkno);
4184744Swnj 		bp->b_command = UT_SFORW;
4194744Swnj 	} else {
4207382Ssam 		addr->utfc = bdbtofsb(bp->b_blkno) - blkno;
4214744Swnj 		bp->b_command = UT_SREV;
4224744Swnj 	}
4234833Swnj 	sc->sc_timo = imin(imax(10 * -addr->utfc, 60), 5*60);
4244744Swnj 
4254744Swnj dobpcmd:
4264744Swnj 	/*
4274744Swnj 	 * Perform the command setup in bp.
4284744Swnj 	 */
4294746Ssam 	addr->utcs1 = bp->b_command|UT_IE|UT_GO;
4304744Swnj 	return;
4314744Swnj next:
4324744Swnj 	/*
4334744Swnj 	 * Advance to the next command in the slave queue,
4344744Swnj 	 * posting notice and releasing resources as needed.
4354744Swnj 	 */
4364744Swnj 	if (um->um_ubinfo)
4374744Swnj 		ubadone(um);
4384744Swnj 	um->um_tab.b_errcnt = 0;
4394744Swnj 	dp->b_actf = bp->av_forw;
4404744Swnj 	iodone(bp);
4414744Swnj 	goto loop;
4424744Swnj }
4434744Swnj 
4444744Swnj /*
4454744Swnj  * Start operation on controller --
4464744Swnj  * UNIBUS resources have been allocated.
4474744Swnj  */
4484744Swnj utdgo(um)
4494744Swnj 	register struct uba_ctlr *um;
4504744Swnj {
4514744Swnj 	register struct utdevice *addr = (struct utdevice *)um->um_addr;
4524744Swnj 
4534744Swnj 	addr->utba = (u_short) um->um_ubinfo;
45411176Ssam 	addr->utcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300)|UT_IE|UT_GO;
4554744Swnj }
4564744Swnj 
4574744Swnj /*
4584744Swnj  * Ut interrupt handler
4594744Swnj  */
4604744Swnj /*ARGSUSED*/
4614744Swnj utintr(ut11)
4624744Swnj 	int ut11;
4634744Swnj {
4644744Swnj 	struct buf *dp;
4654744Swnj 	register struct buf *bp;
4664744Swnj 	register struct uba_ctlr *um = utminfo[ut11];
4674744Swnj 	register struct utdevice *addr;
4684744Swnj 	register struct tj_softc *sc;
4694746Ssam 	u_short tjunit, cs2, cs1;
4704744Swnj 	register state;
4714744Swnj 
4724744Swnj 	if ((dp = um->um_tab.b_actf) == NULL)
4734744Swnj 		return;
4744744Swnj 	bp = dp->b_actf;
4754744Swnj 	tjunit = TJUNIT(bp->b_dev);
4764744Swnj 	addr = (struct utdevice *)tjdinfo[tjunit]->ui_addr;
4774744Swnj 	sc = &tj_softc[tjunit];
4784744Swnj 	/*
4794744Swnj 	 * Record status...
4804744Swnj 	 */
4814877Ssam 	sc->sc_timo = INF;
4824744Swnj 	sc->sc_dsreg = addr->utds;
4834744Swnj 	sc->sc_erreg = addr->uter;
48411176Ssam 	sc->sc_resid = MASKREG(addr->utfc);
4854746Ssam 	if ((bp->b_flags&B_READ) == 0)
4864744Swnj 		sc->sc_lastiow = 1;
4874746Ssam 	state = um->um_tab.b_state;
4884746Ssam 	um->um_tab.b_state = 0;
4894744Swnj 	/*
4904744Swnj 	 * Check for errors...
4914744Swnj 	 */
4924744Swnj 	if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) {
4934744Swnj 		/*
4944759Swnj 		 * To clear the ERR bit, we must issue a drive clear
4954759Swnj 		 * command, and to clear the TRE bit we must set the
4964759Swnj 		 * controller clear bit.
4974759Swnj 		 */
4984759Swnj 		cs2 = addr->utcs2;
4994759Swnj 		if ((cs1 = addr->utcs1)&UT_TRE)
5004759Swnj 			addr->utcs2 |= UTCS2_CLR;
5014759Swnj 		/* is this dangerous ?? */
5024759Swnj 		while ((addr->utcs1&UT_RDY) == 0)
5034759Swnj 			;
5044759Swnj 		addr->utcs1 = UT_CLEAR|UT_GO;
5054759Swnj 		/*
50611176Ssam 		 * If we were reading at 1600 or 6250 bpi and the error
50711176Ssam 		 * was corrected, then don't consider this an error.
5084744Swnj 		 */
50911190Ssam 		if (sc->sc_erreg & UTER_COR && (bp->b_flags & B_READ) &&
51011176Ssam 		    (addr->uttc & UTTC_DEN) != UT_NRZI) {
51118323Sralph 			tprintf(sc->sc_ttyp,
51211176Ssam 			  "ut%d: soft error bn%d cs1=%b er=%b cs2=%b ds=%b\n",
51311176Ssam 			  tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg,
51411176Ssam 			  UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS);
51511176Ssam 			sc->sc_erreg &= ~UTER_COR;
5164744Swnj 		}
5174744Swnj 		/*
5184744Swnj 		 * If we were reading from a raw tape and the only error
5194744Swnj 		 * was that the record was too long, then we don't consider
5204744Swnj 		 * this an error.
5214744Swnj 		 */
5224744Swnj 		if (bp == &rutbuf[UTUNIT(bp->b_dev)] && (bp->b_flags&B_READ) &&
5234744Swnj 		    (sc->sc_erreg&UTER_FCE))
52411176Ssam 			sc->sc_erreg &= ~UTER_FCE;
52511197Slayer 		if (sc->sc_erreg == 0)
5264744Swnj 			goto ignoreerr;
5274744Swnj 		/*
52811176Ssam 		 * Fix up errors which occur due to backspacing
52911176Ssam 		 * "over" the front of the tape.
5304746Ssam 		 */
53111176Ssam 		if ((sc->sc_dsreg & UTDS_BOT) && bp->b_command == UT_SREV &&
5324746Ssam 		    ((sc->sc_erreg &= ~(UTER_NEF|UTER_FCE)) == 0))
5334746Ssam 			goto opdone;
5344746Ssam 		/*
5354744Swnj 		 * Retry soft errors up to 8 times
5364744Swnj 		 */
5374744Swnj 		if ((sc->sc_erreg&UTER_HARD) == 0 && state == SIO) {
5384744Swnj 			if (++um->um_tab.b_errcnt < 7) {
5394744Swnj 				sc->sc_blkno++;
5404744Swnj 				ubadone(um);
5414744Swnj 				goto opcont;
5424744Swnj 			}
54311176Ssam 		}
5444744Swnj 		/*
54511176Ssam 		 * Hard or non-I/O errors on non-raw tape
54611176Ssam 		 * cause it to close.
54711176Ssam 		 */
54811176Ssam 		if (sc->sc_openf > 0 && bp != &rutbuf[UTUNIT(bp->b_dev)])
54911176Ssam 			sc->sc_openf = -1;
55011176Ssam 		/*
5514744Swnj 		 * Couldn't recover error.
5524744Swnj 		 */
55318323Sralph 		tprintf(sc->sc_ttyp,
55418323Sralph 			"ut%d: hard error bn%d cs1=%b er=%b cs2=%b ds=%b\n",
5554746Ssam 			tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg,
5564746Ssam 			UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS);
5574744Swnj 		bp->b_flags |= B_ERROR;
5584744Swnj 		goto opdone;
5594744Swnj 	}
56011176Ssam 
5614744Swnj ignoreerr:
5624744Swnj 	/*
56311176Ssam 	 * If we hit a tape mark update our position.
56411176Ssam 	 */
56511176Ssam 	if (sc->sc_dsreg & UTDS_TM && bp->b_flags & B_READ) {
56611176Ssam 		/*
56711176Ssam 		 * Set blkno and nxrec
56811176Ssam 		 */
56911176Ssam 		if (bp == &cutbuf[UTUNIT(bp->b_dev)]) {
57011176Ssam 			if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) {
57111176Ssam 				sc->sc_nxrec =
57211176Ssam 				     bdbtofsb(bp->b_blkno) - addr->utfc;
57311176Ssam 				sc->sc_blkno = sc->sc_nxrec;
57411176Ssam 			} else {
57511176Ssam 				sc->sc_blkno =
57611176Ssam 				     bdbtofsb(bp->b_blkno) + addr->utfc;
57711176Ssam 				sc->sc_nxrec = sc->sc_blkno-1;
57811176Ssam 			}
57911176Ssam 		} else
58011176Ssam 			sc->sc_nxrec = bdbtofsb(bp->b_blkno);
58111176Ssam 		/*
58211176Ssam 		 * Note: if we get a tape mark on a read, the
58311176Ssam 		 * frame count register will be zero, so b_resid
58411176Ssam 		 * will be calculated correctly below.
58511176Ssam 		 */
58611176Ssam 		goto opdone;
58711176Ssam 	}
58811176Ssam 	/*
5894744Swnj 	 * Advance tape control FSM.
5904744Swnj 	 */
5914744Swnj 	switch (state) {
5924744Swnj 
5934744Swnj 	case SIO:		/* read/write increments tape block # */
5944744Swnj 		sc->sc_blkno++;
595*30917Skarels 		sc->sc_blks++;
596*30917Skarels 		if (um->um_tab.b_errcnt)
597*30917Skarels 			sc->sc_softerrs++;
5984746Ssam 		break;
5994744Swnj 
60011176Ssam 	case SCOM:		/* motion commands update current position */
6014744Swnj 		if (bp == &cutbuf[UTUNIT(bp->b_dev)])
60226296Skarels 		switch ((int)bp->b_command) {
6034744Swnj 
6044744Swnj 		case UT_SFORW:
6054744Swnj 			sc->sc_blkno -= bp->b_repcnt;
6064744Swnj 			break;
6074744Swnj 
6084744Swnj 		case UT_SREV:
6094744Swnj 			sc->sc_blkno += bp->b_repcnt;
6104744Swnj 			break;
61111176Ssam 
61211176Ssam 		case UT_REWOFFL:
61311176Ssam 			addr->utcs1 = UT_CLEAR|UT_GO;
61411176Ssam 			break;
6154744Swnj 		}
6164746Ssam 		break;
6174744Swnj 
6184744Swnj 	case SSEEK:
6197382Ssam 		sc->sc_blkno = bdbtofsb(bp->b_blkno);
6204744Swnj 		goto opcont;
6214744Swnj 
6224746Ssam 	case SERASE:
6234746Ssam 		/*
6244746Ssam 		 * Completed erase of the inter-record gap due to a
6254746Ssam 		 * write error; now retry the write operation.
6264746Ssam 		 */
6274746Ssam 		um->um_tab.b_state = SERASED;
6284746Ssam 		goto opcont;
6294746Ssam 
6304746Ssam 	case SREW:			/* clear attention bit */
6314746Ssam 		addr->utcs1 = UT_CLEAR|UT_GO;
6324746Ssam 		break;
6334746Ssam 
6344744Swnj 	default:
6354746Ssam 		printf("bad state %d\n", state);
6364744Swnj 		panic("utintr");
6374744Swnj 	}
6384744Swnj 
6394744Swnj opdone:
6404744Swnj 	/*
6414744Swnj 	 * Reset error count and remove
6424744Swnj 	 * from device queue
6434744Swnj 	 */
6444744Swnj 	um->um_tab.b_errcnt = 0;
6454746Ssam 	dp->b_actf = bp->av_forw;
64611176Ssam 	/*
64711176Ssam 	 * For read command, frame count register contains
64811176Ssam 	 * actual length of tape record.  Otherwise, it
64911176Ssam 	 * holds negative residual count.
65011176Ssam 	 */
65111176Ssam 	if (state == SIO && um->um_cmd == UT_RCOM) {
65211176Ssam 		bp->b_resid = 0;
65311176Ssam 		if (bp->b_bcount > MASKREG(addr->utfc))
65411176Ssam 			bp->b_resid = bp->b_bcount - MASKREG(addr->utfc);
65511176Ssam 	} else
65611176Ssam 		bp->b_resid = MASKREG(-addr->utfc);
6574744Swnj 	ubadone(um);
6584744Swnj 	iodone(bp);
6594744Swnj 	/*
6604744Swnj 	 * Circulate slave to end of controller queue
6614744Swnj 	 * to give other slaves a chance
6624744Swnj 	 */
6634744Swnj 	um->um_tab.b_actf = dp->b_forw;
6644744Swnj 	if (dp->b_actf) {
6654744Swnj 		dp->b_forw = NULL;
6664744Swnj 		if (um->um_tab.b_actf == NULL)
6674744Swnj 			um->um_tab.b_actf = dp;
6684744Swnj 		else
6694744Swnj 			um->um_tab.b_actl->b_forw = dp;
6704744Swnj 		um->um_tab.b_actl = dp;
6714744Swnj 	}
6724744Swnj 	if (um->um_tab.b_actf == 0)
6734744Swnj 		return;
6744744Swnj opcont:
6754744Swnj 	utstart(um);
6764744Swnj }
6774744Swnj 
6784744Swnj /*
6794833Swnj  * Watchdog timer routine.
6804833Swnj  */
6814833Swnj uttimer(dev)
6824833Swnj 	int dev;
6834833Swnj {
6844833Swnj 	register struct tj_softc *sc = &tj_softc[TJUNIT(dev)];
6854846Sroot 	register short x;
6864833Swnj 
6874833Swnj 	if (sc->sc_timo != INF && (sc->sc_timo -= 5) < 0) {
6884859Ssam 		printf("tj%d: lost interrupt\n", TJUNIT(dev));
6894833Swnj 		sc->sc_timo = INF;
6904846Sroot 		x = spl5();
6914833Swnj 		utintr(UTUNIT(dev));
6924846Sroot 		(void) splx(x);
6934833Swnj 	}
6944833Swnj 	timeout(uttimer, (caddr_t)dev, 5*hz);
6954833Swnj }
6964833Swnj 
6974833Swnj /*
6984744Swnj  * Raw interface for a read
6994744Swnj  */
7007736Sroot utread(dev, uio)
7014744Swnj 	dev_t dev;
7027736Sroot 	struct uio *uio;
7034744Swnj {
7048167Sroot 	int errno;
7057736Sroot 
7068167Sroot 	errno = utphys(dev, uio);
7078167Sroot 	if (errno)
7088167Sroot 		return (errno);
7098167Sroot 	return (physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_READ, minphys, uio));
7104744Swnj }
7114744Swnj 
7124744Swnj /*
7134744Swnj  * Raw interface for a write
7144744Swnj  */
7157847Sroot utwrite(dev, uio)
7167736Sroot 	dev_t dev;
7177847Sroot 	struct uio *uio;
7184744Swnj {
7198167Sroot 	int errno;
7208167Sroot 
7218167Sroot 	errno = utphys(dev, uio);
7228167Sroot 	if (errno)
7238167Sroot 		return (errno);
7248167Sroot 	return (physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_WRITE, minphys, uio));
7254744Swnj }
7264744Swnj 
7274744Swnj /*
7284744Swnj  * Check for valid device number dev and update our notion
7294744Swnj  * of where we are on the tape
7304744Swnj  */
7317736Sroot utphys(dev, uio)
7324744Swnj 	dev_t dev;
7337736Sroot 	struct uio *uio;
7344744Swnj {
7354744Swnj 	register int tjunit = TJUNIT(dev);
7364744Swnj 	register struct tj_softc *sc;
7374744Swnj 	register struct uba_device *ui;
7384744Swnj 
7397847Sroot 	if (tjunit >= NTJ || (ui=tjdinfo[tjunit]) == 0 || ui->ui_alive == 0)
7407847Sroot 		return (ENXIO);
7414744Swnj 	sc = &tj_softc[tjunit];
7427847Sroot 	sc->sc_blkno = bdbtofsb(uio->uio_offset>>9);
7434746Ssam 	sc->sc_nxrec = sc->sc_blkno+1;
7447847Sroot 	return (0);
7454744Swnj }
7464744Swnj 
7474744Swnj /*ARGSUSED*/
7487634Ssam utioctl(dev, cmd, data, flag)
7494744Swnj 	dev_t dev;
7507634Ssam 	caddr_t data;
7514744Swnj {
7524744Swnj 	register struct tj_softc *sc = &tj_softc[TJUNIT(dev)];
7534744Swnj 	register struct buf *bp = &cutbuf[UTUNIT(dev)];
7544744Swnj 	register callcount;
7554744Swnj 	int fcount;
7567634Ssam 	struct mtop *mtop;
7577634Ssam 	struct mtget *mtget;
7584744Swnj 	/* we depend of the values and order of the MT codes here */
7594744Swnj 	static utops[] =
7604744Swnj       {UT_WEOF,UT_SFORWF,UT_SREVF,UT_SFORW,UT_SREV,UT_REW,UT_REWOFFL,UT_SENSE};
7614744Swnj 
7624744Swnj 	switch (cmd) {
7634744Swnj 
7644744Swnj 	case MTIOCTOP:
7657634Ssam 		mtop = (struct mtop *)data;
7667634Ssam 		switch(mtop->mt_op) {
7674744Swnj 
7684744Swnj 		case MTWEOF:
76911413Ssam 		case MTFSF: case MTBSF:
77011413Ssam 		case MTFSR: case MTBSR:
7717634Ssam 			callcount = mtop->mt_count;
7724744Swnj 			fcount = 1;
7734744Swnj 			break;
7744744Swnj 
7754744Swnj 		case MTREW: case MTOFFL: case MTNOP:
7764744Swnj 			callcount = 1;
7774744Swnj 			fcount = 1;
7784744Swnj 			break;
7794744Swnj 
7804744Swnj 		default:
7818577Sroot 			return (ENXIO);
7824744Swnj 		}
7838577Sroot 		if (callcount <= 0 || fcount <= 0)
7848577Sroot 			return (EINVAL);
7854744Swnj 		while (--callcount >= 0) {
7867634Ssam 			utcommand(dev, utops[mtop->mt_op], fcount);
7874744Swnj 			if ((bp->b_flags&B_ERROR) || (sc->sc_dsreg&UTDS_BOT))
7884744Swnj 				break;
7894744Swnj 		}
7908650Sroot 		return (geterror(bp));
7914744Swnj 
7924744Swnj 	case MTIOCGET:
7937634Ssam 		mtget = (struct mtget *)data;
7947634Ssam 		mtget->mt_dsreg = sc->sc_dsreg;
7957634Ssam 		mtget->mt_erreg = sc->sc_erreg;
7967634Ssam 		mtget->mt_resid = sc->sc_resid;
7977634Ssam 		mtget->mt_type = MT_ISUT;
7988577Sroot 		break;
7994744Swnj 
8004744Swnj 	default:
8018577Sroot 		return (ENXIO);
8024744Swnj 	}
8038577Sroot 	return (0);
8044744Swnj }
8054744Swnj 
8064744Swnj utreset(uban)
8074744Swnj 	int uban;
8084744Swnj {
8094744Swnj 	register struct uba_ctlr *um;
8104744Swnj 	register ut11, tjunit;
8114744Swnj 	register struct uba_device *ui;
8124744Swnj 	register struct buf *dp;
8134744Swnj 
8144744Swnj 	for (ut11 = 0; ut11 < NUT; ut11++) {
8154744Swnj 		if ((um = utminfo[ut11]) == 0 || um->um_alive == 0 ||
8164744Swnj 		   um->um_ubanum != uban)
8174744Swnj 			continue;
8184744Swnj 		printf(" ut%d", ut11);
8194746Ssam 		um->um_tab.b_state = 0;
8204744Swnj 		um->um_tab.b_actf = um->um_tab.b_actl = 0;
8214744Swnj 		if (um->um_ubinfo) {
8224744Swnj 			printf("<%d>", (um->um_ubinfo>>28)&0xf);
8239358Ssam 			um->um_ubinfo = 0;
8244744Swnj 		}
8254744Swnj 		((struct utdevice *)(um->um_addr))->utcs1 = UT_CLEAR|UT_GO;
8264746Ssam 		((struct utdevice *)(um->um_addr))->utcs2 |= UTCS2_CLR;
8274744Swnj 		for (tjunit = 0; tjunit < NTJ; tjunit++) {
8284744Swnj 			if ((ui = tjdinfo[tjunit]) == 0 || ui->ui_mi != um ||
8294744Swnj 			    ui->ui_alive == 0)
8304744Swnj 				continue;
8314744Swnj 			dp = &tjutab[tjunit];
8324746Ssam 			dp->b_state = 0;
8334744Swnj 			dp->b_forw = 0;
8344744Swnj 			if (um->um_tab.b_actf == NULL)
8354744Swnj 				um->um_tab.b_actf = dp;
8364744Swnj 			else
8374744Swnj 				um->um_tab.b_actl->b_forw = dp;
8384744Swnj 			um->um_tab.b_actl = dp;
8394744Swnj 			if (tj_softc[tjunit].sc_openf > 0)
8404744Swnj 				tj_softc[tjunit].sc_openf = -1;
8414744Swnj 		}
8424744Swnj 		utstart(um);
8434744Swnj 	}
8444744Swnj }
8454744Swnj 
8464744Swnj /*
8474744Swnj  * Do a stand-alone core dump to tape --
8484744Swnj  * from here down, routines are used only in dump context
8494744Swnj  */
8504744Swnj #define	DBSIZE	20
8514744Swnj 
8524744Swnj utdump()
8534744Swnj {
8544744Swnj 	register struct uba_device *ui;
8554744Swnj 	register struct uba_regs *up;
8564746Ssam 	register struct utdevice *addr;
8574744Swnj 	int blk, num = maxfree;
8584744Swnj 	int start = 0;
8594744Swnj 
8604744Swnj #define	phys(a,b)		((b)((int)(a)&0x7fffffff))
8614744Swnj 	if (tjdinfo[0] == 0)
8624744Swnj 		return (ENXIO);
8634744Swnj 	ui = phys(tjdinfo[0], struct uba_device *);
8644744Swnj 	up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba;
8654941Swnj 	ubainit(up);
8664744Swnj 	DELAY(1000000);
8674941Swnj 	addr = (struct utdevice *)ui->ui_physaddr;
8684746Ssam 	utwait(addr);
8694746Ssam 	/*
8704746Ssam 	 * Be sure to set the appropriate density here.  We use
8714746Ssam 	 * 6250, but maybe it should be done at 1600 to insure the
8724746Ssam 	 * tape can be read by most any other tape drive available.
8734746Ssam 	 */
8744746Ssam 	addr->uttc = UT_GCR|PDP11FMT;	/* implicit slave 0 or-ed in */
8754746Ssam 	addr->utcs1 = UT_CLEAR|UT_GO;
8764744Swnj 	while (num > 0) {
8774744Swnj 		blk = num > DBSIZE ? DBSIZE : num;
8784746Ssam 		utdwrite(start, blk, addr, up);
8794746Ssam 		if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE))
8804746Ssam 			return(EIO);
8814744Swnj 		start += blk;
8824744Swnj 		num -= blk;
8834744Swnj 	}
8844746Ssam 	uteof(addr);
8854746Ssam 	uteof(addr);
8864746Ssam 	utwait(addr);
8874746Ssam 	if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE))
8884744Swnj 		return(EIO);
8894746Ssam 	addr->utcs1 = UT_REW|UT_GO;
8904744Swnj 	return (0);
8914744Swnj }
8924744Swnj 
8934746Ssam utdwrite(dbuf, num, addr, up)
8944744Swnj 	register dbuf, num;
8954746Ssam 	register struct utdevice *addr;
8964744Swnj 	struct uba_regs *up;
8974744Swnj {
8984744Swnj 	register struct pte *io;
8994744Swnj 	register int npf;
9004744Swnj 
9014746Ssam 	utwait(addr);
9024744Swnj 	io = up->uba_map;
9034744Swnj 	npf = num + 1;
9044744Swnj 	while (--npf != 0)
9054744Swnj 		*(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV);
9064744Swnj 	*(int *)io = 0;
9074746Ssam 	addr->utwc = -((num*NBPG)>>1);
9084746Ssam 	addr->utfc = -(num*NBPG);
9094746Ssam 	addr->utba = 0;
9104746Ssam 	addr->utcs1 = UT_WCOM|UT_GO;
9114744Swnj }
9124744Swnj 
9134746Ssam utwait(addr)
9144746Ssam 	struct utdevice *addr;
9154744Swnj {
9164744Swnj 	register s;
9174744Swnj 
9184744Swnj 	do
9194746Ssam 		s = addr->utds;
9204744Swnj 	while ((s&UTDS_DRY) == 0);
9214744Swnj }
9224744Swnj 
9234746Ssam uteof(addr)
9244746Ssam 	struct utdevice *addr;
9254744Swnj {
9264744Swnj 
9274746Ssam 	utwait(addr);
9284746Ssam 	addr->utcs1 = UT_WEOF|UT_GO;
9294744Swnj }
9304744Swnj #endif
931