xref: /original-bsd/sys/vax/uba/ut.c (revision 2ff170e0)
14861cf4eSmckusick /*
208aba3daSmckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
34861cf4eSmckusick  * All rights reserved.  The Berkeley software License Agreement
44861cf4eSmckusick  * specifies the terms and conditions for redistribution.
54861cf4eSmckusick  *
6*2ff170e0Sbostic  *	@(#)ut.c	7.12 (Berkeley) 12/16/90
74861cf4eSmckusick  */
8fc21f5deSwnj 
9cafa6dd3Sroot #include "tj.h"
10fc21f5deSwnj #if NUT > 0
11fc21f5deSwnj /*
12fc21f5deSwnj  * System Industries Model 9700 Tape Drive
13fc21f5deSwnj  *   emulates a TU45 on the UNIBUS
14fc21f5deSwnj  *
15fc21f5deSwnj  * TODO:
16fc21f5deSwnj  *	check out attention processing
17fc21f5deSwnj  *	try reset code and dump code
18fc21f5deSwnj  */
19*2ff170e0Sbostic #include "sys/param.h"
20*2ff170e0Sbostic #include "sys/systm.h"
21*2ff170e0Sbostic #include "sys/buf.h"
22*2ff170e0Sbostic #include "sys/conf.h"
23*2ff170e0Sbostic #include "sys/errno.h"
24*2ff170e0Sbostic #include "sys/file.h"
25*2ff170e0Sbostic #include "sys/map.h"
26*2ff170e0Sbostic #include "sys/ioctl.h"
27*2ff170e0Sbostic #include "sys/mtio.h"
28*2ff170e0Sbostic #include "sys/cmap.h"
29*2ff170e0Sbostic #include "sys/time.h"
30*2ff170e0Sbostic #include "sys/uio.h"
31*2ff170e0Sbostic #include "sys/kernel.h"
32*2ff170e0Sbostic #include "sys/syslog.h"
33*2ff170e0Sbostic #include "sys/tprintf.h"
34fc21f5deSwnj 
35*2ff170e0Sbostic #include "../include/pte.h"
36*2ff170e0Sbostic #include "../include/cpu.h"
372a3075abSbloom #include "ubareg.h"
382a3075abSbloom #include "ubavar.h"
392a3075abSbloom #include "utreg.h"
40fc21f5deSwnj 
41fc21f5deSwnj struct	buf	cutbuf[NUT];	/* bufs for control operations */
42fc21f5deSwnj struct	buf	tjutab[NTJ];	/* bufs for slave queue headers */
43fc21f5deSwnj 
44fc21f5deSwnj struct uba_ctlr *utminfo[NUT];
45fc21f5deSwnj struct uba_device *tjdinfo[NTJ];
46f67ff244Swnj int utprobe(), utslave(), utattach(), utdgo(), utintr(), uttimer();
47fc21f5deSwnj u_short utstd[] = { 0772440, 0 };
48fc21f5deSwnj struct uba_driver utdriver =
49fc21f5deSwnj   { utprobe, utslave, utattach, utdgo, utstd, "tj", tjdinfo, "ut", utminfo, 0 };
50fc21f5deSwnj 
519bc1f2fcSsam #define	MASKREG(reg)	((reg)&0xffff)
529bc1f2fcSsam 
53fc21f5deSwnj /* bits in minor device */
54fc21f5deSwnj #define	TJUNIT(dev)	(minor(dev)&03)
55fc21f5deSwnj #define	T_NOREWIND	04
56fc21f5deSwnj #define	T_1600BPI	010
57fc21f5deSwnj #define	T_6250BPI	020
58fc21f5deSwnj short	utdens[] = { UT_NRZI, UT_PE, UT_GCR, UT_NRZI };
59fc21f5deSwnj 
60fc21f5deSwnj /* slave to controller mapping table */
61fc21f5deSwnj short	tjtout[NTJ];
62fc21f5deSwnj #define UTUNIT(dev)	(tjtout[TJUNIT(dev)])
63fc21f5deSwnj 
64fc21f5deSwnj #define	INF	(daddr_t)1000000L	/* a block number that wont exist */
65fc21f5deSwnj 
66fc21f5deSwnj struct	tj_softc {
67fc21f5deSwnj 	char	sc_openf;	/* exclusive open */
68fc21f5deSwnj 	char	sc_lastiow;	/* last I/O operation was a write */
69fc21f5deSwnj 	daddr_t	sc_blkno;	/* next block to transfer */
70fc21f5deSwnj 	daddr_t	sc_nxrec;	/* next record on tape */
71fc21f5deSwnj 	u_short	sc_erreg;	/* image of uter */
72fc21f5deSwnj 	u_short	sc_dsreg;	/* image of utds */
730915afebSsam 	u_short	sc_resid;	/* residual from transfer */
74fc21f5deSwnj 	u_short	sc_dens;	/* sticky selected density */
75f67ff244Swnj 	daddr_t	sc_timo;	/* time until timeout expires */
76f67ff244Swnj 	short	sc_tact;	/* timeout is active flag */
770f129637Smarc 	tpr_t	sc_tpr;		/* tprintf handle */
78edb110f3Skarels 	int	sc_blks;	/* number of I/O operations since open */
79edb110f3Skarels 	int	sc_softerrs;	/* number of soft I/O errors since open */
80fc21f5deSwnj } tj_softc[NTJ];
81fc21f5deSwnj 
82fc21f5deSwnj /*
83fc21f5deSwnj  * Internal per/slave states found in sc_state
84fc21f5deSwnj  */
85fc21f5deSwnj #define	SSEEK		1	/* seeking */
86fc21f5deSwnj #define	SIO		2	/* doing sequential I/O */
87fc21f5deSwnj #define	SCOM		3	/* sending a control command */
88fc21f5deSwnj #define	SREW		4	/* doing a rewind op */
890915afebSsam #define	SERASE		5	/* erase inter-record gap */
900915afebSsam #define	SERASED		6	/* erased inter-record gap */
91fc21f5deSwnj 
92a0080991Swnj /*ARGSUSED*/
utprobe(reg)93fc21f5deSwnj utprobe(reg)
94fc21f5deSwnj 	caddr_t reg;
95fc21f5deSwnj {
96fc21f5deSwnj 	register int br, cvec;
97fc21f5deSwnj #ifdef lint
98fc21f5deSwnj 	br=0; cvec=br; br=cvec;
99a0080991Swnj 	utintr(0);
100fc21f5deSwnj #endif
1010915afebSsam 	/*
10215ced867Sroot 	 * The SI documentation says you must set the RDY bit
10315ced867Sroot 	 * (even though it's read-only) to force an interrupt.
1040915afebSsam 	 */
10515ced867Sroot 	((struct utdevice *) reg)->utcs1 = UT_IE|UT_NOP|UT_RDY;
106fc21f5deSwnj 	DELAY(10000);
10741ad7c0bSkre 	return (sizeof (struct utdevice));
108fc21f5deSwnj }
109fc21f5deSwnj 
110fc21f5deSwnj /*ARGSUSED*/
111fc21f5deSwnj utslave(ui, reg)
112fc21f5deSwnj 	struct uba_device *ui;
113fc21f5deSwnj 	caddr_t reg;
114fc21f5deSwnj {
115fc21f5deSwnj 	/*
116fc21f5deSwnj 	 * A real TU45 would support the slave present bit
117fc21f5deSwnj 	 * int the drive type register, but this thing doesn't,
118fc21f5deSwnj 	 * so there's no way to determine if a slave is present or not.
119fc21f5deSwnj 	 */
120fc21f5deSwnj 	 return(1);
121fc21f5deSwnj }
122fc21f5deSwnj 
123fc21f5deSwnj utattach(ui)
124fc21f5deSwnj 	struct uba_device *ui;
125fc21f5deSwnj {
126fc21f5deSwnj 	tjtout[ui->ui_unit] = ui->ui_mi->um_ctlr;
127fc21f5deSwnj }
128fc21f5deSwnj 
129fc21f5deSwnj /*
130fc21f5deSwnj  * Open the device with exclusive access.
131fc21f5deSwnj  */
utopen(dev,flag)132fc21f5deSwnj utopen(dev, flag)
133fc21f5deSwnj 	dev_t dev;
134fc21f5deSwnj 	int flag;
135fc21f5deSwnj {
136fc21f5deSwnj 	register int tjunit = TJUNIT(dev);
137fc21f5deSwnj 	register struct uba_device *ui;
138fc21f5deSwnj 	register struct tj_softc *sc;
139265c83f6Skarels 	int olddens, dens, error;
1409880da4dSroot 	register int s;
141fc21f5deSwnj 
142b6366aa5Skarels 	if (tjunit >= NTJ || (ui = tjdinfo[tjunit]) == 0 || ui->ui_alive == 0)
1438472374dSroot 		return (ENXIO);
144b6366aa5Skarels 	if ((sc = &tj_softc[tjunit])->sc_openf)
145b6366aa5Skarels 		return (EBUSY);
146edb110f3Skarels 	sc->sc_openf = 1;
147fc21f5deSwnj 	olddens = sc->sc_dens;
1488472374dSroot 	dens = sc->sc_dens =
1498472374dSroot 	    utdens[(minor(dev)&(T_1600BPI|T_6250BPI))>>3]|
150fc21f5deSwnj 	      PDP11FMT|(ui->ui_slave&07);
151fc21f5deSwnj get:
152fc21f5deSwnj 	utcommand(dev, UT_SENSE, 1);
153fc21f5deSwnj 	if (sc->sc_dsreg&UTDS_PIP) {
154265c83f6Skarels 		if (error = tsleep((caddr_t)&lbolt, (PZERO+1) | PCATCH,
155265c83f6Skarels 		    devopn, 0))
156265c83f6Skarels 			return (error);
157fc21f5deSwnj 		goto get;
158fc21f5deSwnj 	}
159fc21f5deSwnj 	sc->sc_dens = olddens;
160fc21f5deSwnj 	if ((sc->sc_dsreg&UTDS_MOL) == 0) {
161edb110f3Skarels 		sc->sc_openf = 0;
162fc21f5deSwnj 		uprintf("tj%d: not online\n", tjunit);
1638472374dSroot 		return (EIO);
164fc21f5deSwnj 	}
165fc21f5deSwnj 	if ((flag&FWRITE) && (sc->sc_dsreg&UTDS_WRL)) {
166edb110f3Skarels 		sc->sc_openf = 0;
167fc21f5deSwnj 		uprintf("tj%d: no write ring\n", tjunit);
1688472374dSroot 		return (EIO);
169fc21f5deSwnj 	}
170fc21f5deSwnj 	if ((sc->sc_dsreg&UTDS_BOT) == 0 && (flag&FWRITE) &&
171fc21f5deSwnj 	    dens != sc->sc_dens) {
172edb110f3Skarels 		sc->sc_openf = 0;
173fc21f5deSwnj 		uprintf("tj%d: can't change density in mid-tape\n", tjunit);
1748472374dSroot 		return (EIO);
175fc21f5deSwnj 	}
176fc21f5deSwnj 	sc->sc_blkno = (daddr_t)0;
177fc21f5deSwnj 	sc->sc_nxrec = INF;
178fc21f5deSwnj 	sc->sc_lastiow = 0;
179edb110f3Skarels 	sc->sc_blks = 0;
180edb110f3Skarels 	sc->sc_softerrs = 0;
181fc21f5deSwnj 	sc->sc_dens = dens;
1820f129637Smarc 	sc->sc_tpr = tprintf_open();
1830915afebSsam 	/*
1840915afebSsam 	 * For 6250 bpi take exclusive use of the UNIBUS.
1850915afebSsam 	 */
1860915afebSsam 	ui->ui_driver->ud_xclu = (dens&(T_1600BPI|T_6250BPI)) == T_6250BPI;
18787898daaSkarels 	s = splclock();
188f67ff244Swnj 	if (sc->sc_tact == 0) {
189f67ff244Swnj 		sc->sc_timo = INF;
190f67ff244Swnj 		sc->sc_tact = 1;
191f67ff244Swnj 		timeout(uttimer, (caddr_t)dev, 5*hz);
192f67ff244Swnj 	}
1939880da4dSroot 	splx(s);
1948472374dSroot 	return (0);
195fc21f5deSwnj }
196fc21f5deSwnj 
utclose(dev,flag)197fc21f5deSwnj utclose(dev, flag)
198fc21f5deSwnj 	register dev_t dev;
199fc21f5deSwnj 	register flag;
200fc21f5deSwnj {
201fc21f5deSwnj 	register struct tj_softc *sc = &tj_softc[TJUNIT(dev)];
202fc21f5deSwnj 
203fc21f5deSwnj 	if (flag == FWRITE || ((flag&FWRITE) && sc->sc_lastiow)) {
204fc21f5deSwnj 		utcommand(dev, UT_WEOF, 1);
205fc21f5deSwnj 		utcommand(dev, UT_WEOF, 1);
206fc21f5deSwnj 		utcommand(dev, UT_SREV, 1);
207fc21f5deSwnj 	}
208fc21f5deSwnj 	if ((minor(dev)&T_NOREWIND) == 0)
209fc21f5deSwnj 		utcommand(dev, UT_REW, 0);
210edb110f3Skarels 	if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100)
211edb110f3Skarels 		log(LOG_INFO, "tj%d: %d soft errors in %d blocks\n",
212edb110f3Skarels 		    TJUNIT(dev), sc->sc_softerrs, sc->sc_blks);
2130f129637Smarc 	tprintf_close(sc->sc_tpr);
214fc21f5deSwnj 	sc->sc_openf = 0;
215265c83f6Skarels 	return (0);
216fc21f5deSwnj }
217fc21f5deSwnj 
utcommand(dev,com,count)218fc21f5deSwnj utcommand(dev, com, count)
219fc21f5deSwnj 	dev_t dev;
220fc21f5deSwnj 	int com, count;
221fc21f5deSwnj {
222fc21f5deSwnj 	register struct buf *bp;
2239880da4dSroot 	register int s;
224fc21f5deSwnj 
225fc21f5deSwnj 	bp = &cutbuf[UTUNIT(dev)];
2269880da4dSroot 	s = spl5();
227fc21f5deSwnj 	while (bp->b_flags&B_BUSY) {
228fc21f5deSwnj 		if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE))
229fc21f5deSwnj 			break;
230fc21f5deSwnj 		bp->b_flags |= B_WANTED;
231fc21f5deSwnj 		sleep((caddr_t)bp, PRIBIO);
232fc21f5deSwnj 	}
233fc21f5deSwnj 	bp->b_flags = B_BUSY|B_READ;
2349880da4dSroot 	splx(s);
235fc21f5deSwnj 	bp->b_dev = dev;
236fc21f5deSwnj 	bp->b_command = com;
237fc21f5deSwnj 	bp->b_repcnt = count;
238fc21f5deSwnj 	bp->b_blkno = 0;
239fc21f5deSwnj 	utstrategy(bp);
240fc21f5deSwnj 	if (count == 0)
241fc21f5deSwnj 		return;
242fc21f5deSwnj 	iowait(bp);
243fc21f5deSwnj 	if (bp->b_flags&B_WANTED)
244fc21f5deSwnj 		wakeup((caddr_t)bp);
245fc21f5deSwnj 	bp->b_flags &= B_ERROR;
246fc21f5deSwnj }
247fc21f5deSwnj 
248fc21f5deSwnj /*
249fc21f5deSwnj  * Queue a tape operation.
250fc21f5deSwnj  */
utstrategy(bp)251fc21f5deSwnj utstrategy(bp)
252fc21f5deSwnj 	register struct buf *bp;
253fc21f5deSwnj {
254fc21f5deSwnj 	int tjunit = TJUNIT(bp->b_dev);
255fc21f5deSwnj 	register struct uba_ctlr *um;
256fc21f5deSwnj 	register struct buf *dp;
257e36db31eSbostic 	int s;
258fc21f5deSwnj 
259fc21f5deSwnj 	/*
260fc21f5deSwnj 	 * Put transfer at end of unit queue
261fc21f5deSwnj 	 */
262fc21f5deSwnj 	dp = &tjutab[tjunit];
263fc21f5deSwnj 	bp->av_forw = NULL;
2647243a881Skarels 	um = tjdinfo[tjunit]->ui_mi;
265e36db31eSbostic 	s = spl5();
266fc21f5deSwnj 	if (dp->b_actf == NULL) {
267fc21f5deSwnj 		dp->b_actf = bp;
268fc21f5deSwnj 		/*
269fc21f5deSwnj 		 * Transport not active, so...
270fc21f5deSwnj 		 * put at end of controller queue
271fc21f5deSwnj 		 */
272fc21f5deSwnj 		dp->b_forw = NULL;
273fc21f5deSwnj 		if (um->um_tab.b_actf == NULL)
274fc21f5deSwnj 			um->um_tab.b_actf = dp;
275fc21f5deSwnj 		else
276fc21f5deSwnj 			um->um_tab.b_actl->b_forw = dp;
277fc21f5deSwnj 		um->um_tab.b_actl = dp;
278fc21f5deSwnj 	} else
279fc21f5deSwnj 		dp->b_actl->av_forw = bp;
280fc21f5deSwnj 	dp->b_actl = bp;
281fc21f5deSwnj 	/*
282fc21f5deSwnj 	 * If the controller is not busy, set it going.
283fc21f5deSwnj 	 */
2840915afebSsam 	if (um->um_tab.b_state == 0)
285fc21f5deSwnj 		utstart(um);
286e36db31eSbostic 	splx(s);
287fc21f5deSwnj }
288fc21f5deSwnj 
utstart(um)289fc21f5deSwnj utstart(um)
290fc21f5deSwnj 	register struct uba_ctlr *um;
291fc21f5deSwnj {
2920915afebSsam 	register struct utdevice *addr;
293fc21f5deSwnj 	register struct buf *bp, *dp;
294fc21f5deSwnj 	register struct tj_softc *sc;
295fc21f5deSwnj 	struct uba_device *ui;
296fc21f5deSwnj 	int tjunit;
297fc21f5deSwnj 	daddr_t blkno;
298fc21f5deSwnj 
299fc21f5deSwnj loop:
300fc21f5deSwnj 	/*
301fc21f5deSwnj 	 * Scan controller queue looking for units with
302fc21f5deSwnj 	 * transaction queues to dispatch
303fc21f5deSwnj 	 */
304fc21f5deSwnj 	if ((dp = um->um_tab.b_actf) == NULL)
305fc21f5deSwnj 		return;
306fc21f5deSwnj 	if ((bp = dp->b_actf) == NULL) {
307fc21f5deSwnj 		um->um_tab.b_actf = dp->b_forw;
308fc21f5deSwnj 		goto loop;
309fc21f5deSwnj 	}
3100915afebSsam 	addr = (struct utdevice *)um->um_addr;
311fc21f5deSwnj 	tjunit = TJUNIT(bp->b_dev);
312fc21f5deSwnj 	ui = tjdinfo[tjunit];
313fc21f5deSwnj 	sc = &tj_softc[tjunit];
314fc21f5deSwnj 	/* note slave select, density, and format were merged on open */
3150915afebSsam 	addr->uttc = sc->sc_dens;
3160915afebSsam 	sc->sc_dsreg = addr->utds;
3170915afebSsam 	sc->sc_erreg = addr->uter;
3189bc1f2fcSsam 	sc->sc_resid = MASKREG(addr->utfc);
319fc21f5deSwnj 	/*
320fc21f5deSwnj 	 * Default is that last command was NOT a write command;
321fc21f5deSwnj 	 * if we do a write command we will notice this in utintr().
322fc21f5deSwnj 	 */
323fc21f5deSwnj 	sc->sc_lastiow = 0;
3240915afebSsam 	if (sc->sc_openf < 0 || (addr->utds&UTDS_MOL) == 0) {
325fc21f5deSwnj 		/*
326fc21f5deSwnj 		 * Have had a hard error on a non-raw tape
327fc21f5deSwnj 		 * or the tape unit is now unavailable
328fc21f5deSwnj 		 * (e.g. taken off line).
329fc21f5deSwnj 		 */
330fc21f5deSwnj 		bp->b_flags |= B_ERROR;
331fc21f5deSwnj 		goto next;
332fc21f5deSwnj 	}
333fc21f5deSwnj 	if (bp == &cutbuf[UTUNIT(bp->b_dev)]) {
334fc21f5deSwnj 		/*
335fc21f5deSwnj 		 * Execute a control operation with the specified
336fc21f5deSwnj 		 * count.
337fc21f5deSwnj 		 */
338fc21f5deSwnj 		if (bp->b_command == UT_SENSE)
339fc21f5deSwnj 			goto next;
3409bc1f2fcSsam 		if (bp->b_command == UT_SFORW && (addr->utds & UTDS_EOT)) {
3419bc1f2fcSsam 			bp->b_resid = bp->b_bcount;
3429bc1f2fcSsam 			goto next;
3439bc1f2fcSsam 		}
344fc21f5deSwnj 		/*
345fc21f5deSwnj 		 * Set next state; handle timeouts
346fc21f5deSwnj 		 */
347f67ff244Swnj 		if (bp->b_command == UT_REW) {
3480915afebSsam 			um->um_tab.b_state = SREW;
349f67ff244Swnj 			sc->sc_timo = 5*60;
350f67ff244Swnj 		} else {
3510915afebSsam 			um->um_tab.b_state = SCOM;
352f67ff244Swnj 			sc->sc_timo = imin(imax(10*(int)-bp->b_repcnt,60),5*60);
353f67ff244Swnj 		}
354fc21f5deSwnj 		/* NOTE: this depends on the ut command values */
355fc21f5deSwnj 		if (bp->b_command >= UT_SFORW && bp->b_command <= UT_SREVF)
3560915afebSsam 			addr->utfc = -bp->b_repcnt;
357fc21f5deSwnj 		goto dobpcmd;
358fc21f5deSwnj 	}
359fc21f5deSwnj 	/*
360e36db31eSbostic 	 * For raw I/O, save the current block
361e36db31eSbostic 	 * number in case we have to retry.
362e36db31eSbostic 	 */
363e36db31eSbostic 	if (bp->b_flags & B_RAW) {
364e36db31eSbostic 		if (um->um_tab.b_errcnt == 0) {
365e36db31eSbostic 			sc->sc_blkno = bdbtofsb(bp->b_blkno);
366e36db31eSbostic 			sc->sc_nxrec = sc->sc_blkno + 1;
367e36db31eSbostic 		}
368e36db31eSbostic 	}
369e36db31eSbostic 	else {
370e36db31eSbostic 		/*
371e36db31eSbostic 		 * Handle boundary cases for operation
372e36db31eSbostic 		 * on non-raw tapes.
373fc21f5deSwnj 		 */
37461993709Ssam 		if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) {
375fc21f5deSwnj 			/* can't read past end of file */
376fc21f5deSwnj 			bp->b_flags |= B_ERROR;
377fc21f5deSwnj 			bp->b_error = ENXIO;
378fc21f5deSwnj 			goto next;
379fc21f5deSwnj 		}
380e36db31eSbostic 		if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec &&
381e36db31eSbostic 		    (bp->b_flags&B_READ)) {
382e36db31eSbostic 			/*
383e36db31eSbostic 			 * Reading at end of file returns 0 bytes.
384e36db31eSbostic 			 */
385fc21f5deSwnj 			bp->b_resid = bp->b_bcount;
386fc21f5deSwnj 			clrbuf(bp);
387fc21f5deSwnj 			goto next;
388fc21f5deSwnj 		}
389fc21f5deSwnj 		if ((bp->b_flags&B_READ) == 0)
39061993709Ssam 			sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1;
391e36db31eSbostic 	}
392fc21f5deSwnj 	/*
393fc21f5deSwnj 	 * If the tape is correctly positioned, set up all the
394fc21f5deSwnj 	 * registers but the csr, and give control over to the
395fc21f5deSwnj 	 * UNIBUS adaptor routines, to wait for resources to
396fc21f5deSwnj 	 * start I/O.
397fc21f5deSwnj 	 */
39861993709Ssam 	if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) {
3990915afebSsam 		addr->utwc = -(((bp->b_bcount)+1)>>1);
4000915afebSsam 		addr->utfc = -bp->b_bcount;
401fc21f5deSwnj 		if ((bp->b_flags&B_READ) == 0) {
402fc21f5deSwnj 			/*
403fc21f5deSwnj 			 * On write error retries erase the
4040915afebSsam 			 * inter-record gap before rewriting.
405fc21f5deSwnj 			 */
4060915afebSsam 			if (um->um_tab.b_errcnt) {
4070915afebSsam 				if (um->um_tab.b_state != SERASED) {
408c987de64Swnj 					um->um_tab.b_state = SERASE;
409f67ff244Swnj 					sc->sc_timo = 60;
4100915afebSsam 					addr->utcs1 = UT_ERASE|UT_IE|UT_GO;
4110915afebSsam 					return;
4120915afebSsam 				}
4130915afebSsam 			}
4149bc1f2fcSsam 			if (addr->utds & UTDS_EOT) {
4159bc1f2fcSsam 				bp->b_resid = bp->b_bcount;
4169bc1f2fcSsam 				um->um_tab.b_state = 0;
4179bc1f2fcSsam 				goto next;
4189bc1f2fcSsam 			}
419fc21f5deSwnj 			um->um_cmd = UT_WCOM;
420fc21f5deSwnj 		} else
421fc21f5deSwnj 			um->um_cmd = UT_RCOM;
422f67ff244Swnj 		sc->sc_timo = 60;
4230915afebSsam 		um->um_tab.b_state = SIO;
424fc21f5deSwnj 		(void) ubago(ui);
425fc21f5deSwnj 		return;
426fc21f5deSwnj 	}
427fc21f5deSwnj 	/*
428fc21f5deSwnj 	 * Tape positioned incorrectly; seek forwards or
429fc21f5deSwnj 	 * backwards to the correct spot.  This happens for
430fc21f5deSwnj 	 * raw tapes only on error retries.
431fc21f5deSwnj 	 */
4320915afebSsam 	um->um_tab.b_state = SSEEK;
43361993709Ssam 	if (blkno < bdbtofsb(bp->b_blkno)) {
43461993709Ssam 		addr->utfc = blkno - bdbtofsb(bp->b_blkno);
435fc21f5deSwnj 		bp->b_command = UT_SFORW;
436fc21f5deSwnj 	} else {
43761993709Ssam 		addr->utfc = bdbtofsb(bp->b_blkno) - blkno;
438fc21f5deSwnj 		bp->b_command = UT_SREV;
439fc21f5deSwnj 	}
440f67ff244Swnj 	sc->sc_timo = imin(imax(10 * -addr->utfc, 60), 5*60);
441fc21f5deSwnj 
442fc21f5deSwnj dobpcmd:
443fc21f5deSwnj 	/*
444fc21f5deSwnj 	 * Perform the command setup in bp.
445fc21f5deSwnj 	 */
4460915afebSsam 	addr->utcs1 = bp->b_command|UT_IE|UT_GO;
447fc21f5deSwnj 	return;
448fc21f5deSwnj next:
449fc21f5deSwnj 	/*
450fc21f5deSwnj 	 * Advance to the next command in the slave queue,
451fc21f5deSwnj 	 * posting notice and releasing resources as needed.
452fc21f5deSwnj 	 */
453fc21f5deSwnj 	if (um->um_ubinfo)
454fc21f5deSwnj 		ubadone(um);
455fc21f5deSwnj 	um->um_tab.b_errcnt = 0;
456fc21f5deSwnj 	dp->b_actf = bp->av_forw;
457fc21f5deSwnj 	iodone(bp);
458fc21f5deSwnj 	goto loop;
459fc21f5deSwnj }
460fc21f5deSwnj 
461fc21f5deSwnj /*
462fc21f5deSwnj  * Start operation on controller --
463fc21f5deSwnj  * UNIBUS resources have been allocated.
464fc21f5deSwnj  */
utdgo(um)465fc21f5deSwnj utdgo(um)
466fc21f5deSwnj 	register struct uba_ctlr *um;
467fc21f5deSwnj {
468fc21f5deSwnj 	register struct utdevice *addr = (struct utdevice *)um->um_addr;
469fc21f5deSwnj 
470fc21f5deSwnj 	addr->utba = (u_short) um->um_ubinfo;
4719bc1f2fcSsam 	addr->utcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300)|UT_IE|UT_GO;
472fc21f5deSwnj }
473fc21f5deSwnj 
474fc21f5deSwnj /*
475fc21f5deSwnj  * Ut interrupt handler
476fc21f5deSwnj  */
477fc21f5deSwnj /*ARGSUSED*/
utintr(ut11)478fc21f5deSwnj utintr(ut11)
479fc21f5deSwnj 	int ut11;
480fc21f5deSwnj {
481fc21f5deSwnj 	struct buf *dp;
482fc21f5deSwnj 	register struct buf *bp;
483fc21f5deSwnj 	register struct uba_ctlr *um = utminfo[ut11];
484fc21f5deSwnj 	register struct utdevice *addr;
485fc21f5deSwnj 	register struct tj_softc *sc;
4860915afebSsam 	u_short tjunit, cs2, cs1;
487fc21f5deSwnj 	register state;
488fc21f5deSwnj 
489fc21f5deSwnj 	if ((dp = um->um_tab.b_actf) == NULL)
490fc21f5deSwnj 		return;
491fc21f5deSwnj 	bp = dp->b_actf;
492fc21f5deSwnj 	tjunit = TJUNIT(bp->b_dev);
493fc21f5deSwnj 	addr = (struct utdevice *)tjdinfo[tjunit]->ui_addr;
494fc21f5deSwnj 	sc = &tj_softc[tjunit];
495fc21f5deSwnj 	/*
496fc21f5deSwnj 	 * Record status...
497fc21f5deSwnj 	 */
4982b7d7f15Ssam 	sc->sc_timo = INF;
499fc21f5deSwnj 	sc->sc_dsreg = addr->utds;
500fc21f5deSwnj 	sc->sc_erreg = addr->uter;
5019bc1f2fcSsam 	sc->sc_resid = MASKREG(addr->utfc);
502fc21f5deSwnj 	if ((bp->b_flags&B_READ) == 0)
503fc21f5deSwnj 		sc->sc_lastiow = 1;
5040915afebSsam 	state = um->um_tab.b_state;
5050915afebSsam 	um->um_tab.b_state = 0;
506fc21f5deSwnj 	/*
507fc21f5deSwnj 	 * Check for errors...
508fc21f5deSwnj 	 */
509fc21f5deSwnj 	if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) {
510fc21f5deSwnj 		/*
511c987de64Swnj 		 * To clear the ERR bit, we must issue a drive clear
512c987de64Swnj 		 * command, and to clear the TRE bit we must set the
513c987de64Swnj 		 * controller clear bit.
514c987de64Swnj 		 */
515c987de64Swnj 		cs2 = addr->utcs2;
516c987de64Swnj 		if ((cs1 = addr->utcs1)&UT_TRE)
517c987de64Swnj 			addr->utcs2 |= UTCS2_CLR;
518c987de64Swnj 		/* is this dangerous ?? */
519c987de64Swnj 		while ((addr->utcs1&UT_RDY) == 0)
520c987de64Swnj 			;
521c987de64Swnj 		addr->utcs1 = UT_CLEAR|UT_GO;
522c987de64Swnj 		/*
5239bc1f2fcSsam 		 * If we were reading at 1600 or 6250 bpi and the error
5249bc1f2fcSsam 		 * was corrected, then don't consider this an error.
525fc21f5deSwnj 		 */
5264b8c1761Ssam 		if (sc->sc_erreg & UTER_COR && (bp->b_flags & B_READ) &&
5279bc1f2fcSsam 		    (addr->uttc & UTTC_DEN) != UT_NRZI) {
5280f129637Smarc 			tprintf(sc->sc_tpr,
5299bc1f2fcSsam 			  "ut%d: soft error bn%d cs1=%b er=%b cs2=%b ds=%b\n",
5309bc1f2fcSsam 			  tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg,
5319bc1f2fcSsam 			  UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS);
5329bc1f2fcSsam 			sc->sc_erreg &= ~UTER_COR;
5339bc1f2fcSsam 		}
5349bc1f2fcSsam 		/*
5359bc1f2fcSsam 		 * If we were reading from a raw tape and the only error
5369bc1f2fcSsam 		 * was that the record was too long, then we don't consider
5379bc1f2fcSsam 		 * this an error.
5389bc1f2fcSsam 		 */
539e36db31eSbostic 		if ((bp->b_flags & (B_READ|B_RAW)) == (B_READ|B_RAW) &&
5409bc1f2fcSsam 		    (sc->sc_erreg&UTER_FCE))
5419bc1f2fcSsam 			sc->sc_erreg &= ~UTER_FCE;
542c038478eSlayer 		if (sc->sc_erreg == 0)
5439bc1f2fcSsam 			goto ignoreerr;
5449bc1f2fcSsam 		/*
5459bc1f2fcSsam 		 * Fix up errors which occur due to backspacing
5469bc1f2fcSsam 		 * "over" the front of the tape.
5479bc1f2fcSsam 		 */
5489bc1f2fcSsam 		if ((sc->sc_dsreg & UTDS_BOT) && bp->b_command == UT_SREV &&
5499bc1f2fcSsam 		    ((sc->sc_erreg &= ~(UTER_NEF|UTER_FCE)) == 0))
5509bc1f2fcSsam 			goto opdone;
5519bc1f2fcSsam 		/*
5529bc1f2fcSsam 		 * Retry soft errors up to 8 times
5539bc1f2fcSsam 		 */
5549bc1f2fcSsam 		if ((sc->sc_erreg&UTER_HARD) == 0 && state == SIO) {
5559bc1f2fcSsam 			if (++um->um_tab.b_errcnt < 7) {
5569bc1f2fcSsam 				sc->sc_blkno++;
5579bc1f2fcSsam 				ubadone(um);
5589bc1f2fcSsam 				goto opcont;
5599bc1f2fcSsam 			}
5609bc1f2fcSsam 		}
5619bc1f2fcSsam 		/*
5629bc1f2fcSsam 		 * Hard or non-I/O errors on non-raw tape
5639bc1f2fcSsam 		 * cause it to close.
5649bc1f2fcSsam 		 */
565e36db31eSbostic 		if ((bp->b_flags&B_RAW) == 0 && sc->sc_openf > 0)
5669bc1f2fcSsam 			sc->sc_openf = -1;
5679bc1f2fcSsam 		/*
5689bc1f2fcSsam 		 * Couldn't recover error.
5699bc1f2fcSsam 		 */
5700f129637Smarc 		tprintf(sc->sc_tpr,
57141b6a802Sralph 			"ut%d: hard error bn%d cs1=%b er=%b cs2=%b ds=%b\n",
5729bc1f2fcSsam 			tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg,
5739bc1f2fcSsam 			UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS);
5749bc1f2fcSsam 		bp->b_flags |= B_ERROR;
5759bc1f2fcSsam 		goto opdone;
5769bc1f2fcSsam 	}
5779bc1f2fcSsam 
5789bc1f2fcSsam ignoreerr:
5799bc1f2fcSsam 	/*
5809bc1f2fcSsam 	 * If we hit a tape mark update our position.
5819bc1f2fcSsam 	 */
5829bc1f2fcSsam 	if (sc->sc_dsreg & UTDS_TM && bp->b_flags & B_READ) {
583fc21f5deSwnj 		/*
5840915afebSsam 		 * Set blkno and nxrec
585fc21f5deSwnj 		 */
586fc21f5deSwnj 		if (bp == &cutbuf[UTUNIT(bp->b_dev)]) {
58761993709Ssam 			if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) {
588fc21f5deSwnj 				sc->sc_nxrec =
58961993709Ssam 				     bdbtofsb(bp->b_blkno) - addr->utfc;
590fc21f5deSwnj 				sc->sc_blkno = sc->sc_nxrec;
591fc21f5deSwnj 			} else {
592fc21f5deSwnj 				sc->sc_blkno =
59361993709Ssam 				     bdbtofsb(bp->b_blkno) + addr->utfc;
594fc21f5deSwnj 				sc->sc_nxrec = sc->sc_blkno-1;
595fc21f5deSwnj 			}
5960915afebSsam 		} else
59761993709Ssam 			sc->sc_nxrec = bdbtofsb(bp->b_blkno);
598fc21f5deSwnj 		/*
5999bc1f2fcSsam 		 * Note: if we get a tape mark on a read, the
6009bc1f2fcSsam 		 * frame count register will be zero, so b_resid
6019bc1f2fcSsam 		 * will be calculated correctly below.
602fc21f5deSwnj 		 */
603fc21f5deSwnj 		goto opdone;
604fc21f5deSwnj 	}
605fc21f5deSwnj 	/*
606fc21f5deSwnj 	 * Advance tape control FSM.
607fc21f5deSwnj 	 */
608fc21f5deSwnj 	switch (state) {
609fc21f5deSwnj 
610fc21f5deSwnj 	case SIO:		/* read/write increments tape block # */
611fc21f5deSwnj 		sc->sc_blkno++;
612edb110f3Skarels 		sc->sc_blks++;
613edb110f3Skarels 		if (um->um_tab.b_errcnt)
614edb110f3Skarels 			sc->sc_softerrs++;
6150915afebSsam 		break;
616fc21f5deSwnj 
6179bc1f2fcSsam 	case SCOM:		/* motion commands update current position */
618fc21f5deSwnj 		if (bp == &cutbuf[UTUNIT(bp->b_dev)])
619f4d773b5Skarels 		switch ((int)bp->b_command) {
620fc21f5deSwnj 
621fc21f5deSwnj 		case UT_SFORW:
622fc21f5deSwnj 			sc->sc_blkno -= bp->b_repcnt;
623fc21f5deSwnj 			break;
624fc21f5deSwnj 
625fc21f5deSwnj 		case UT_SREV:
626fc21f5deSwnj 			sc->sc_blkno += bp->b_repcnt;
627fc21f5deSwnj 			break;
6289bc1f2fcSsam 
6299bc1f2fcSsam 		case UT_REWOFFL:
6309bc1f2fcSsam 			addr->utcs1 = UT_CLEAR|UT_GO;
6319bc1f2fcSsam 			break;
632fc21f5deSwnj 		}
6330915afebSsam 		break;
634fc21f5deSwnj 
635fc21f5deSwnj 	case SSEEK:
63661993709Ssam 		sc->sc_blkno = bdbtofsb(bp->b_blkno);
637fc21f5deSwnj 		goto opcont;
638fc21f5deSwnj 
6390915afebSsam 	case SERASE:
6400915afebSsam 		/*
6410915afebSsam 		 * Completed erase of the inter-record gap due to a
6420915afebSsam 		 * write error; now retry the write operation.
6430915afebSsam 		 */
6440915afebSsam 		um->um_tab.b_state = SERASED;
6450915afebSsam 		goto opcont;
6460915afebSsam 
6470915afebSsam 	case SREW:			/* clear attention bit */
6480915afebSsam 		addr->utcs1 = UT_CLEAR|UT_GO;
6490915afebSsam 		break;
6500915afebSsam 
651fc21f5deSwnj 	default:
6520915afebSsam 		printf("bad state %d\n", state);
653fc21f5deSwnj 		panic("utintr");
654fc21f5deSwnj 	}
655fc21f5deSwnj 
656fc21f5deSwnj opdone:
657fc21f5deSwnj 	/*
658fc21f5deSwnj 	 * Reset error count and remove
659fc21f5deSwnj 	 * from device queue
660fc21f5deSwnj 	 */
661fc21f5deSwnj 	um->um_tab.b_errcnt = 0;
6620915afebSsam 	dp->b_actf = bp->av_forw;
6639bc1f2fcSsam 	/*
6649bc1f2fcSsam 	 * For read command, frame count register contains
6659bc1f2fcSsam 	 * actual length of tape record.  Otherwise, it
6669bc1f2fcSsam 	 * holds negative residual count.
6679bc1f2fcSsam 	 */
6689bc1f2fcSsam 	if (state == SIO && um->um_cmd == UT_RCOM) {
6699bc1f2fcSsam 		bp->b_resid = 0;
6709bc1f2fcSsam 		if (bp->b_bcount > MASKREG(addr->utfc))
6719bc1f2fcSsam 			bp->b_resid = bp->b_bcount - MASKREG(addr->utfc);
6729bc1f2fcSsam 	} else
6739bc1f2fcSsam 		bp->b_resid = MASKREG(-addr->utfc);
674fc21f5deSwnj 	ubadone(um);
675fc21f5deSwnj 	iodone(bp);
676fc21f5deSwnj 	/*
677fc21f5deSwnj 	 * Circulate slave to end of controller queue
678fc21f5deSwnj 	 * to give other slaves a chance
679fc21f5deSwnj 	 */
680fc21f5deSwnj 	um->um_tab.b_actf = dp->b_forw;
681fc21f5deSwnj 	if (dp->b_actf) {
682fc21f5deSwnj 		dp->b_forw = NULL;
683fc21f5deSwnj 		if (um->um_tab.b_actf == NULL)
684fc21f5deSwnj 			um->um_tab.b_actf = dp;
685fc21f5deSwnj 		else
686fc21f5deSwnj 			um->um_tab.b_actl->b_forw = dp;
687fc21f5deSwnj 		um->um_tab.b_actl = dp;
688fc21f5deSwnj 	}
689fc21f5deSwnj 	if (um->um_tab.b_actf == 0)
690fc21f5deSwnj 		return;
691fc21f5deSwnj opcont:
692fc21f5deSwnj 	utstart(um);
693fc21f5deSwnj }
694fc21f5deSwnj 
695fc21f5deSwnj /*
696f67ff244Swnj  * Watchdog timer routine.
697f67ff244Swnj  */
uttimer(dev)698f67ff244Swnj uttimer(dev)
699f67ff244Swnj 	int dev;
700f67ff244Swnj {
701f67ff244Swnj 	register struct tj_softc *sc = &tj_softc[TJUNIT(dev)];
70284f2b0c6Sroot 	register short x;
703f67ff244Swnj 
704f67ff244Swnj 	if (sc->sc_timo != INF && (sc->sc_timo -= 5) < 0) {
70531dbde61Ssam 		printf("tj%d: lost interrupt\n", TJUNIT(dev));
706f67ff244Swnj 		sc->sc_timo = INF;
70784f2b0c6Sroot 		x = spl5();
708f67ff244Swnj 		utintr(UTUNIT(dev));
70984f2b0c6Sroot 		(void) splx(x);
710f67ff244Swnj 	}
711f67ff244Swnj 	timeout(uttimer, (caddr_t)dev, 5*hz);
712f67ff244Swnj }
713f67ff244Swnj 
714fc21f5deSwnj /*ARGSUSED*/
utioctl(dev,cmd,data,flag)715e708edeaSsam utioctl(dev, cmd, data, flag)
716fc21f5deSwnj 	dev_t dev;
717e708edeaSsam 	caddr_t data;
718fc21f5deSwnj {
719fc21f5deSwnj 	register struct tj_softc *sc = &tj_softc[TJUNIT(dev)];
720fc21f5deSwnj 	register struct buf *bp = &cutbuf[UTUNIT(dev)];
721fc21f5deSwnj 	register callcount;
7221ba79fc0Ssklower 	int fcount, error = 0;
723e708edeaSsam 	struct mtop *mtop;
724e708edeaSsam 	struct mtget *mtget;
725fc21f5deSwnj 	/* we depend of the values and order of the MT codes here */
726fc21f5deSwnj 	static utops[] =
727fc21f5deSwnj       {UT_WEOF,UT_SFORWF,UT_SREVF,UT_SFORW,UT_SREV,UT_REW,UT_REWOFFL,UT_SENSE};
728fc21f5deSwnj 
729fc21f5deSwnj 	switch (cmd) {
730fc21f5deSwnj 
731fc21f5deSwnj 	case MTIOCTOP:
732e708edeaSsam 		mtop = (struct mtop *)data;
733e708edeaSsam 		switch(mtop->mt_op) {
734fc21f5deSwnj 
735fc21f5deSwnj 		case MTWEOF:
736fc21f5deSwnj 		case MTFSF: case MTBSF:
737fc21f5deSwnj 		case MTFSR: case MTBSR:
7384b7e222eSsam 			callcount = mtop->mt_count;
7394b7e222eSsam 			fcount = 1;
740fc21f5deSwnj 			break;
741fc21f5deSwnj 
742fc21f5deSwnj 		case MTREW: case MTOFFL: case MTNOP:
743fc21f5deSwnj 			callcount = 1;
744fc21f5deSwnj 			fcount = 1;
745fc21f5deSwnj 			break;
746fc21f5deSwnj 
747fc21f5deSwnj 		default:
7488472374dSroot 			return (ENXIO);
749fc21f5deSwnj 		}
7508472374dSroot 		if (callcount <= 0 || fcount <= 0)
7518472374dSroot 			return (EINVAL);
752fc21f5deSwnj 		while (--callcount >= 0) {
753e708edeaSsam 			utcommand(dev, utops[mtop->mt_op], fcount);
754fc21f5deSwnj 			if ((bp->b_flags&B_ERROR) || (sc->sc_dsreg&UTDS_BOT))
755fc21f5deSwnj 				break;
756fc21f5deSwnj 		}
7571ba79fc0Ssklower 		if (bp->b_flags&B_ERROR)
7581ba79fc0Ssklower 			if ((error = bp->b_error)==0)
7591ba79fc0Ssklower 				return (EIO);
7601ba79fc0Ssklower 		return (error);
761fc21f5deSwnj 
762fc21f5deSwnj 	case MTIOCGET:
763e708edeaSsam 		mtget = (struct mtget *)data;
764e708edeaSsam 		mtget->mt_dsreg = sc->sc_dsreg;
765e708edeaSsam 		mtget->mt_erreg = sc->sc_erreg;
766e708edeaSsam 		mtget->mt_resid = sc->sc_resid;
767e708edeaSsam 		mtget->mt_type = MT_ISUT;
7688472374dSroot 		break;
769fc21f5deSwnj 
770fc21f5deSwnj 	default:
7718472374dSroot 		return (ENXIO);
772fc21f5deSwnj 	}
7738472374dSroot 	return (0);
774fc21f5deSwnj }
775fc21f5deSwnj 
utreset(uban)776fc21f5deSwnj utreset(uban)
777fc21f5deSwnj 	int uban;
778fc21f5deSwnj {
779fc21f5deSwnj 	register struct uba_ctlr *um;
780fc21f5deSwnj 	register ut11, tjunit;
781fc21f5deSwnj 	register struct uba_device *ui;
782fc21f5deSwnj 	register struct buf *dp;
783fc21f5deSwnj 
784fc21f5deSwnj 	for (ut11 = 0; ut11 < NUT; ut11++) {
785fc21f5deSwnj 		if ((um = utminfo[ut11]) == 0 || um->um_alive == 0 ||
786fc21f5deSwnj 		   um->um_ubanum != uban)
787fc21f5deSwnj 			continue;
788fc21f5deSwnj 		printf(" ut%d", ut11);
7890915afebSsam 		um->um_tab.b_state = 0;
790fc21f5deSwnj 		um->um_tab.b_actf = um->um_tab.b_actl = 0;
791fc21f5deSwnj 		if (um->um_ubinfo) {
792fc21f5deSwnj 			printf("<%d>", (um->um_ubinfo>>28)&0xf);
793e30cf4fbSsam 			um->um_ubinfo = 0;
794fc21f5deSwnj 		}
795fc21f5deSwnj 		((struct utdevice *)(um->um_addr))->utcs1 = UT_CLEAR|UT_GO;
7960915afebSsam 		((struct utdevice *)(um->um_addr))->utcs2 |= UTCS2_CLR;
797fc21f5deSwnj 		for (tjunit = 0; tjunit < NTJ; tjunit++) {
798fc21f5deSwnj 			if ((ui = tjdinfo[tjunit]) == 0 || ui->ui_mi != um ||
799fc21f5deSwnj 			    ui->ui_alive == 0)
800fc21f5deSwnj 				continue;
801fc21f5deSwnj 			dp = &tjutab[tjunit];
8020915afebSsam 			dp->b_state = 0;
803fc21f5deSwnj 			dp->b_forw = 0;
804fc21f5deSwnj 			if (um->um_tab.b_actf == NULL)
805fc21f5deSwnj 				um->um_tab.b_actf = dp;
806fc21f5deSwnj 			else
807fc21f5deSwnj 				um->um_tab.b_actl->b_forw = dp;
808fc21f5deSwnj 			um->um_tab.b_actl = dp;
809fc21f5deSwnj 			if (tj_softc[tjunit].sc_openf > 0)
810fc21f5deSwnj 				tj_softc[tjunit].sc_openf = -1;
811fc21f5deSwnj 		}
812fc21f5deSwnj 		utstart(um);
813fc21f5deSwnj 	}
814fc21f5deSwnj }
815fc21f5deSwnj 
816fc21f5deSwnj /*
817fc21f5deSwnj  * Do a stand-alone core dump to tape --
818fc21f5deSwnj  * from here down, routines are used only in dump context
819fc21f5deSwnj  */
820fc21f5deSwnj #define	DBSIZE	20
821fc21f5deSwnj 
utdump()822fc21f5deSwnj utdump()
823fc21f5deSwnj {
824fc21f5deSwnj 	register struct uba_device *ui;
825fc21f5deSwnj 	register struct uba_regs *up;
8260915afebSsam 	register struct utdevice *addr;
827fc21f5deSwnj 	int blk, num = maxfree;
828fc21f5deSwnj 	int start = 0;
829fc21f5deSwnj 
830fc21f5deSwnj #define	phys(a,b)		((b)((int)(a)&0x7fffffff))
831fc21f5deSwnj 	if (tjdinfo[0] == 0)
832fc21f5deSwnj 		return (ENXIO);
833fc21f5deSwnj 	ui = phys(tjdinfo[0], struct uba_device *);
834fc21f5deSwnj 	up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba;
835a0080991Swnj 	ubainit(up);
836fc21f5deSwnj 	DELAY(1000000);
8370915afebSsam 	addr = (struct utdevice *)ui->ui_physaddr;
838a0080991Swnj 	utwait(addr);
8390915afebSsam 	/*
8400915afebSsam 	 * Be sure to set the appropriate density here.  We use
8410915afebSsam 	 * 6250, but maybe it should be done at 1600 to insure the
8420915afebSsam 	 * tape can be read by most any other tape drive available.
8430915afebSsam 	 */
8440915afebSsam 	addr->uttc = UT_GCR|PDP11FMT;	/* implicit slave 0 or-ed in */
8450915afebSsam 	addr->utcs1 = UT_CLEAR|UT_GO;
846fc21f5deSwnj 	while (num > 0) {
847fc21f5deSwnj 		blk = num > DBSIZE ? DBSIZE : num;
8480915afebSsam 		utdwrite(start, blk, addr, up);
8490915afebSsam 		if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE))
8500915afebSsam 			return(EIO);
851fc21f5deSwnj 		start += blk;
852fc21f5deSwnj 		num -= blk;
853fc21f5deSwnj 	}
8540915afebSsam 	uteof(addr);
8550915afebSsam 	uteof(addr);
8560915afebSsam 	utwait(addr);
8570915afebSsam 	if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE))
858fc21f5deSwnj 		return(EIO);
8590915afebSsam 	addr->utcs1 = UT_REW|UT_GO;
860fc21f5deSwnj 	return (0);
861fc21f5deSwnj }
862fc21f5deSwnj 
utdwrite(dbuf,num,addr,up)8630915afebSsam utdwrite(dbuf, num, addr, up)
864fc21f5deSwnj 	register dbuf, num;
8650915afebSsam 	register struct utdevice *addr;
866fc21f5deSwnj 	struct uba_regs *up;
867fc21f5deSwnj {
868fc21f5deSwnj 	register struct pte *io;
869fc21f5deSwnj 	register int npf;
870fc21f5deSwnj 
8710915afebSsam 	utwait(addr);
872fc21f5deSwnj 	io = up->uba_map;
873fc21f5deSwnj 	npf = num + 1;
874fc21f5deSwnj 	while (--npf != 0)
875fc21f5deSwnj 		*(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV);
876fc21f5deSwnj 	*(int *)io = 0;
8770915afebSsam 	addr->utwc = -((num*NBPG)>>1);
8780915afebSsam 	addr->utfc = -(num*NBPG);
8790915afebSsam 	addr->utba = 0;
8800915afebSsam 	addr->utcs1 = UT_WCOM|UT_GO;
881fc21f5deSwnj }
882fc21f5deSwnj 
8830915afebSsam utwait(addr)
8840915afebSsam 	struct utdevice *addr;
885fc21f5deSwnj {
886fc21f5deSwnj 	register s;
887fc21f5deSwnj 
888fc21f5deSwnj 	do
8890915afebSsam 		s = addr->utds;
890fc21f5deSwnj 	while ((s&UTDS_DRY) == 0);
891fc21f5deSwnj }
892fc21f5deSwnj 
8930915afebSsam uteof(addr)
8940915afebSsam 	struct utdevice *addr;
895fc21f5deSwnj {
896fc21f5deSwnj 
8970915afebSsam 	utwait(addr);
8980915afebSsam 	addr->utcs1 = UT_WEOF|UT_GO;
899fc21f5deSwnj }
900fc21f5deSwnj #endif
901