xref: /csrg-svn/sys/vax/uba/ut.c (revision 4744)
1*4744Swnj /*	ut.c	4.1	81/11/04	*/
2*4744Swnj 
3*4744Swnj #include "ut.h"
4*4744Swnj #if NUT > 0
5*4744Swnj #define UTDEBUG	1
6*4744Swnj /*
7*4744Swnj  * System Industries Model 9700 Tape Drive
8*4744Swnj  *   emulates a TU45 on the UNIBUS
9*4744Swnj  *
10*4744Swnj  * TODO:
11*4744Swnj  *	check out attention processing
12*4744Swnj  *	try reset code and dump code
13*4744Swnj  */
14*4744Swnj #include "../h/param.h"
15*4744Swnj #include "../h/systm.h"
16*4744Swnj #include "../h/buf.h"
17*4744Swnj #include "../h/conf.h"
18*4744Swnj #include "../h/dir.h"
19*4744Swnj #include "../h/file.h"
20*4744Swnj #include "../h/user.h"
21*4744Swnj #include "../h/map.h"
22*4744Swnj #include "../h/pte.h"
23*4744Swnj #include "../h/ubareg.h"
24*4744Swnj #include "../h/ubavar.h"
25*4744Swnj #include "../h/mtio.h"
26*4744Swnj #include "../h/ioctl.h"
27*4744Swnj #include "../h/cmap.h"
28*4744Swnj #include "../h/cpu.h"
29*4744Swnj 
30*4744Swnj #include "../h/utreg.h"
31*4744Swnj 
32*4744Swnj struct	buf	rutbuf[NUT];	/* bufs for raw i/o */
33*4744Swnj struct	buf	cutbuf[NUT];	/* bufs for control operations */
34*4744Swnj struct	buf	tjutab[NTJ];	/* bufs for slave queue headers */
35*4744Swnj 
36*4744Swnj struct uba_ctlr *utminfo[NUT];
37*4744Swnj struct uba_device *tjdinfo[NTJ];
38*4744Swnj int utprobe(), utslave(), utattach(), utdgo();
39*4744Swnj u_short utstd[] = { 0772440, 0 };
40*4744Swnj struct uba_driver utdriver =
41*4744Swnj   { utprobe, utslave, utattach, utdgo, utstd, "tj", tjdinfo, "ut", utminfo, 0 };
42*4744Swnj 
43*4744Swnj /* bits in minor device */
44*4744Swnj #define	TJUNIT(dev)	(minor(dev)&03)
45*4744Swnj #define	T_NOREWIND	04
46*4744Swnj #define	T_1600BPI	010
47*4744Swnj #define	T_6250BPI	020
48*4744Swnj short	utdens[] = { UT_NRZI, UT_PE, UT_GCR, UT_NRZI };
49*4744Swnj 
50*4744Swnj /* slave to controller mapping table */
51*4744Swnj short	tjtout[NTJ];
52*4744Swnj #define UTUNIT(dev)	(tjtout[TJUNIT(dev)])
53*4744Swnj 
54*4744Swnj #define	INF	(daddr_t)1000000L	/* a block number that wont exist */
55*4744Swnj 
56*4744Swnj struct	tj_softc {
57*4744Swnj 	char	sc_openf;	/* exclusive open */
58*4744Swnj 	char	sc_lastiow;	/* last I/O operation was a write */
59*4744Swnj 	daddr_t	sc_blkno;	/* next block to transfer */
60*4744Swnj 	daddr_t	sc_nxrec;	/* next record on tape */
61*4744Swnj 	u_short	sc_erreg;	/* image of uter */
62*4744Swnj 	u_short	sc_dsreg;	/* image of utds */
63*4744Swnj 	short	sc_resid;	/* residual from transfer */
64*4744Swnj 	u_short	sc_dens;	/* sticky selected density */
65*4744Swnj } tj_softc[NTJ];
66*4744Swnj 
67*4744Swnj /*
68*4744Swnj  * Internal per/slave states found in sc_state
69*4744Swnj  */
70*4744Swnj #define	SSEEK		1	/* seeking */
71*4744Swnj #define	SIO		2	/* doing sequential I/O */
72*4744Swnj #define	SCOM		3	/* sending a control command */
73*4744Swnj #define	SREW		4	/* doing a rewind op */
74*4744Swnj 
75*4744Swnj #if UTDEBUG
76*4744Swnj int	utdebug;
77*4744Swnj #define printd	if (utdebug) printf
78*4744Swnj #else
79*4744Swnj #define	printd
80*4744Swnj #endif
81*4744Swnj 
82*4744Swnj /*
83*4744Swnj  * A NOP should get an interrupt back, if the
84*4744Swnj  *  device is there.
85*4744Swnj  */
86*4744Swnj utprobe(reg)
87*4744Swnj 	caddr_t reg;
88*4744Swnj {
89*4744Swnj 	register int br, cvec;
90*4744Swnj #ifdef lint
91*4744Swnj 	br=0; cvec=br; br=cvec;
92*4744Swnj #endif
93*4744Swnj 	((struct utdevice *) reg)->utcs1 = UT_IE|UT_NOP|UT_GO;
94*4744Swnj 	DELAY(10000);
95*4744Swnj 	((struct utdevice *) reg)->utcs1 = UT_CLEAR|UT_GO;
96*4744Swnj 	return(1);
97*4744Swnj }
98*4744Swnj 
99*4744Swnj /*ARGSUSED*/
100*4744Swnj utslave(ui, reg)
101*4744Swnj 	struct uba_device *ui;
102*4744Swnj 	caddr_t reg;
103*4744Swnj {
104*4744Swnj 	/*
105*4744Swnj 	 * A real TU45 would support the slave present bit
106*4744Swnj 	 * int the drive type register, but this thing doesn't,
107*4744Swnj 	 * so there's no way to determine if a slave is present or not.
108*4744Swnj 	 */
109*4744Swnj 	 return(1);
110*4744Swnj }
111*4744Swnj 
112*4744Swnj utattach(ui)
113*4744Swnj 	struct uba_device *ui;
114*4744Swnj {
115*4744Swnj 	tjtout[ui->ui_unit] = ui->ui_mi->um_ctlr;
116*4744Swnj }
117*4744Swnj 
118*4744Swnj /*
119*4744Swnj  * Open the device with exclusive access.
120*4744Swnj  */
121*4744Swnj utopen(dev, flag)
122*4744Swnj 	dev_t dev;
123*4744Swnj 	int flag;
124*4744Swnj {
125*4744Swnj 	register int tjunit = TJUNIT(dev);
126*4744Swnj 	register struct uba_device *ui;
127*4744Swnj 	register struct tj_softc *sc;
128*4744Swnj 	int olddens, dens;
129*4744Swnj 
130*4744Swnj 	if (tjunit >= NTJ || (sc = &tj_softc[tjunit])->sc_openf ||
131*4744Swnj 	    (ui = tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) {
132*4744Swnj 		u.u_error = ENXIO;
133*4744Swnj 		return;
134*4744Swnj 	}
135*4744Swnj 	olddens = sc->sc_dens;
136*4744Swnj 	dens = sc->sc_dens = utdens[(minor(dev)&(T_1600BPI|T_6250BPI))>>3]|
137*4744Swnj 				PDP11FMT|(ui->ui_slave&07);
138*4744Swnj get:
139*4744Swnj 	utcommand(dev, UT_SENSE, 1);
140*4744Swnj 	if (sc->sc_dsreg&UTDS_PIP) {
141*4744Swnj 		sleep((caddr_t) &lbolt, PZERO+1);
142*4744Swnj 		goto get;
143*4744Swnj 	}
144*4744Swnj 	sc->sc_dens = olddens;
145*4744Swnj 	if ((sc->sc_dsreg&UTDS_MOL) == 0) {
146*4744Swnj 		uprintf("tj%d: not online\n", tjunit);
147*4744Swnj 		u.u_error = EIO;
148*4744Swnj 		return;
149*4744Swnj 	}
150*4744Swnj 	if ((flag&FWRITE) && (sc->sc_dsreg&UTDS_WRL)) {
151*4744Swnj 		uprintf("tj%d: no write ring\n", tjunit);
152*4744Swnj 		u.u_error = EIO;
153*4744Swnj 		return;
154*4744Swnj 	}
155*4744Swnj 	if ((sc->sc_dsreg&UTDS_BOT) == 0 && (flag&FWRITE) &&
156*4744Swnj 	    dens != sc->sc_dens) {
157*4744Swnj 		uprintf("tj%d: can't change density in mid-tape\n", tjunit);
158*4744Swnj 		u.u_error = EIO;
159*4744Swnj 		return;
160*4744Swnj 	}
161*4744Swnj 	sc->sc_openf = 1;
162*4744Swnj 	sc->sc_blkno = (daddr_t)0;
163*4744Swnj 	sc->sc_nxrec = INF;
164*4744Swnj 	sc->sc_lastiow = 0;
165*4744Swnj 	sc->sc_dens = dens;
166*4744Swnj }
167*4744Swnj 
168*4744Swnj utclose(dev, flag)
169*4744Swnj 	register dev_t dev;
170*4744Swnj 	register flag;
171*4744Swnj {
172*4744Swnj 	register struct tj_softc *sc = &tj_softc[TJUNIT(dev)];
173*4744Swnj 
174*4744Swnj 	if (flag == FWRITE || ((flag&FWRITE) && sc->sc_lastiow)) {
175*4744Swnj 		utcommand(dev, UT_WEOF, 1);
176*4744Swnj 		utcommand(dev, UT_WEOF, 1);
177*4744Swnj 		utcommand(dev, UT_SREV, 1);
178*4744Swnj 	}
179*4744Swnj 	if ((minor(dev)&T_NOREWIND) == 0)
180*4744Swnj 		utcommand(dev, UT_REW, 0);
181*4744Swnj 	sc->sc_openf = 0;
182*4744Swnj }
183*4744Swnj 
184*4744Swnj utcommand(dev, com, count)
185*4744Swnj 	dev_t dev;
186*4744Swnj 	int com, count;
187*4744Swnj {
188*4744Swnj 	register struct buf *bp;
189*4744Swnj 
190*4744Swnj 	bp = &cutbuf[UTUNIT(dev)];
191*4744Swnj 	(void) spl5();
192*4744Swnj 	while (bp->b_flags&B_BUSY) {
193*4744Swnj 		if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE))
194*4744Swnj 			break;
195*4744Swnj 		bp->b_flags |= B_WANTED;
196*4744Swnj 		sleep((caddr_t)bp, PRIBIO);
197*4744Swnj 	}
198*4744Swnj 	bp->b_flags = B_BUSY|B_READ;
199*4744Swnj 	(void) spl0();
200*4744Swnj 	bp->b_dev = dev;
201*4744Swnj 	bp->b_command = com;
202*4744Swnj 	bp->b_repcnt = count;
203*4744Swnj 	bp->b_blkno = 0;
204*4744Swnj 	utstrategy(bp);
205*4744Swnj 	if (count == 0)
206*4744Swnj 		return;
207*4744Swnj 	iowait(bp);
208*4744Swnj 	if (bp->b_flags&B_WANTED)
209*4744Swnj 		wakeup((caddr_t)bp);
210*4744Swnj 	bp->b_flags &= B_ERROR;
211*4744Swnj }
212*4744Swnj 
213*4744Swnj /*
214*4744Swnj  * Queue a tape operation.
215*4744Swnj  */
216*4744Swnj utstrategy(bp)
217*4744Swnj 	register struct buf *bp;
218*4744Swnj {
219*4744Swnj 	int tjunit = TJUNIT(bp->b_dev);
220*4744Swnj 	register struct uba_ctlr *um;
221*4744Swnj 	register struct buf *dp;
222*4744Swnj 
223*4744Swnj 	/*
224*4744Swnj 	 * Put transfer at end of unit queue
225*4744Swnj 	 */
226*4744Swnj 	dp = &tjutab[tjunit];
227*4744Swnj 	bp->av_forw = NULL;
228*4744Swnj 	(void) spl5();
229*4744Swnj 	if (dp->b_actf == NULL) {
230*4744Swnj 		dp->b_actf = bp;
231*4744Swnj 		/*
232*4744Swnj 		 * Transport not active, so...
233*4744Swnj 		 * put at end of controller queue
234*4744Swnj 		 */
235*4744Swnj 		dp->b_forw = NULL;
236*4744Swnj 		um = tjdinfo[tjunit]->ui_mi;
237*4744Swnj 		if (um->um_tab.b_actf == NULL)
238*4744Swnj 			um->um_tab.b_actf = dp;
239*4744Swnj 		else
240*4744Swnj 			um->um_tab.b_actl->b_forw = dp;
241*4744Swnj 		um->um_tab.b_actl = dp;
242*4744Swnj 	} else
243*4744Swnj 		dp->b_actl->av_forw = bp;
244*4744Swnj 	dp->b_actl = bp;
245*4744Swnj 	/*
246*4744Swnj 	 * If the controller is not busy, set it going.
247*4744Swnj 	 */
248*4744Swnj 	if (um->um_tab.b_active == 0)
249*4744Swnj 		utstart(um);
250*4744Swnj 	(void) spl0();
251*4744Swnj }
252*4744Swnj 
253*4744Swnj utstart(um)
254*4744Swnj 	register struct uba_ctlr *um;
255*4744Swnj {
256*4744Swnj 	register struct utdevice *utaddr;
257*4744Swnj 	register struct buf *bp, *dp;
258*4744Swnj 	register struct tj_softc *sc;
259*4744Swnj 	struct uba_device *ui;
260*4744Swnj 	int tjunit;
261*4744Swnj 	daddr_t blkno;
262*4744Swnj 
263*4744Swnj loop:
264*4744Swnj 	/*
265*4744Swnj 	 * Scan controller queue looking for units with
266*4744Swnj 	 * transaction queues to dispatch
267*4744Swnj 	 */
268*4744Swnj 	if ((dp = um->um_tab.b_actf) == NULL)
269*4744Swnj 		return;
270*4744Swnj 	if ((bp = dp->b_actf) == NULL) {
271*4744Swnj 		um->um_tab.b_actf = dp->b_forw;
272*4744Swnj 		goto loop;
273*4744Swnj 	}
274*4744Swnj 	utaddr = (struct utdevice *)um->um_addr;
275*4744Swnj 	tjunit = TJUNIT(bp->b_dev);
276*4744Swnj 	ui = tjdinfo[tjunit];
277*4744Swnj 	sc = &tj_softc[tjunit];
278*4744Swnj 	/* note slave select, density, and format were merged on open */
279*4744Swnj 	utaddr->uttc = sc->sc_dens;
280*4744Swnj 	sc->sc_dsreg = utaddr->utds;
281*4744Swnj 	sc->sc_erreg = utaddr->uter;
282*4744Swnj 	sc->sc_resid = utaddr->utwc;
283*4744Swnj 	/*
284*4744Swnj 	 * Default is that last command was NOT a write command;
285*4744Swnj 	 * if we do a write command we will notice this in utintr().
286*4744Swnj 	 */
287*4744Swnj 	sc->sc_lastiow = 0;
288*4744Swnj 	printd("utstart: openf=%d ds=%b\n", sc->sc_openf, utaddr->utds,
289*4744Swnj 		UTDS_BITS);
290*4744Swnj 	if (sc->sc_openf < 0 || (utaddr->utds&UTDS_MOL) == 0) {
291*4744Swnj 		/*
292*4744Swnj 		 * Have had a hard error on a non-raw tape
293*4744Swnj 		 * or the tape unit is now unavailable
294*4744Swnj 		 * (e.g. taken off line).
295*4744Swnj 		 */
296*4744Swnj 		bp->b_flags |= B_ERROR;
297*4744Swnj 		goto next;
298*4744Swnj 	}
299*4744Swnj 	if (bp == &cutbuf[UTUNIT(bp->b_dev)]) {
300*4744Swnj 		/*
301*4744Swnj 		 * Execute a control operation with the specified
302*4744Swnj 		 * count.
303*4744Swnj 		 */
304*4744Swnj 		if (bp->b_command == UT_SENSE)
305*4744Swnj 			goto next;
306*4744Swnj 		/*
307*4744Swnj 		 * Set next state; handle timeouts
308*4744Swnj 		 */
309*4744Swnj 		if (bp->b_command == UT_REW)
310*4744Swnj 			um->um_tab.b_active = SREW;
311*4744Swnj 		else
312*4744Swnj 			um->um_tab.b_active = SCOM;
313*4744Swnj 		/* NOTE: this depends on the ut command values */
314*4744Swnj 		if (bp->b_command >= UT_SFORW && bp->b_command <= UT_SREVF)
315*4744Swnj 			utaddr->utfc = bp->b_repcnt;
316*4744Swnj 		goto dobpcmd;
317*4744Swnj 	}
318*4744Swnj 	/*
319*4744Swnj 	 * The following checks boundary conditions for operations
320*4744Swnj 	 * on non-raw tapes.  On raw tapes the initialization of
321*4744Swnj 	 * sc->sc_nxrec by utphys causes them to be skipped normally
322*4744Swnj 	 * (except in the case of retries).
323*4744Swnj 	 */
324*4744Swnj 	if (dbtofsb(bp->b_blkno) > sc->sc_nxrec) {
325*4744Swnj 		/* can't read past end of file */
326*4744Swnj 		bp->b_flags |= B_ERROR;
327*4744Swnj 		bp->b_error = ENXIO;
328*4744Swnj 		goto next;
329*4744Swnj 	}
330*4744Swnj 	if (dbtofsb(bp->b_blkno) == sc->sc_nxrec && (bp->b_flags&B_READ)) {
331*4744Swnj 		/* read at eof returns 0 count */
332*4744Swnj 		bp->b_resid = bp->b_bcount;
333*4744Swnj 		clrbuf(bp);
334*4744Swnj 		goto next;
335*4744Swnj 	}
336*4744Swnj 	if ((bp->b_flags&B_READ) == 0)
337*4744Swnj 		sc->sc_nxrec = dbtofsb(bp->b_blkno)+1;
338*4744Swnj 	/*
339*4744Swnj 	 * If the tape is correctly positioned, set up all the
340*4744Swnj 	 * registers but the csr, and give control over to the
341*4744Swnj 	 * UNIBUS adaptor routines, to wait for resources to
342*4744Swnj 	 * start I/O.
343*4744Swnj 	 */
344*4744Swnj 	if ((blkno = sc->sc_blkno) == dbtofsb(bp->b_blkno)) {
345*4744Swnj 		utaddr->utwc = -(((bp->b_bcount)+1)>>1);
346*4744Swnj 		if ((bp->b_flags&B_READ) == 0) {
347*4744Swnj 			/*
348*4744Swnj 			 * On write error retries erase the
349*4744Swnj 			 * inter-record gap
350*4744Swnj 			 */
351*4744Swnj 			if (um->um_tab.b_errcnt)
352*4744Swnj 				um->um_cmd = UT_ERASE;
353*4744Swnj 			else
354*4744Swnj 				um->um_cmd = UT_WCOM;
355*4744Swnj 		} else
356*4744Swnj 			um->um_cmd = UT_RCOM;
357*4744Swnj 		um->um_tab.b_active = SIO;
358*4744Swnj 		(void) ubago(ui);
359*4744Swnj 		return;
360*4744Swnj 	}
361*4744Swnj 	/*
362*4744Swnj 	 * Tape positioned incorrectly; seek forwards or
363*4744Swnj 	 * backwards to the correct spot.  This happens for
364*4744Swnj 	 * raw tapes only on error retries.
365*4744Swnj 	 */
366*4744Swnj 	printd("utstart: seek, blkno=%d dbtofsb=%d\n", blkno,
367*4744Swnj 		dbtofsb(bp->b_blkno));
368*4744Swnj 	um->um_tab.b_active = SSEEK;
369*4744Swnj 	if (blkno < dbtofsb(bp->b_blkno)) {
370*4744Swnj 		utaddr->utfc = blkno - dbtofsb(bp->b_blkno);
371*4744Swnj 		bp->b_command = UT_SFORW;
372*4744Swnj 	} else {
373*4744Swnj 		utaddr->utfc = dbtofsb(bp->b_blkno) - blkno;
374*4744Swnj 		bp->b_command = UT_SREV;
375*4744Swnj 	}
376*4744Swnj 
377*4744Swnj dobpcmd:
378*4744Swnj 	/*
379*4744Swnj 	 * Perform the command setup in bp.
380*4744Swnj 	 */
381*4744Swnj 	printd("utstart: dobpcmd\n");
382*4744Swnj 	utaddr->utcs1 = bp->b_command|UT_IE|UT_GO;
383*4744Swnj 	return;
384*4744Swnj next:
385*4744Swnj 	/*
386*4744Swnj 	 * Advance to the next command in the slave queue,
387*4744Swnj 	 * posting notice and releasing resources as needed.
388*4744Swnj 	 */
389*4744Swnj 	printd("utstart: next\n");
390*4744Swnj 	if (um->um_ubinfo)
391*4744Swnj 		ubadone(um);
392*4744Swnj 	um->um_tab.b_errcnt = 0;
393*4744Swnj 	dp->b_actf = bp->av_forw;
394*4744Swnj 	iodone(bp);
395*4744Swnj 	goto loop;
396*4744Swnj }
397*4744Swnj 
398*4744Swnj /*
399*4744Swnj  * Start operation on controller --
400*4744Swnj  * UNIBUS resources have been allocated.
401*4744Swnj  */
402*4744Swnj utdgo(um)
403*4744Swnj 	register struct uba_ctlr *um;
404*4744Swnj {
405*4744Swnj 	register struct utdevice *addr = (struct utdevice *)um->um_addr;
406*4744Swnj 
407*4744Swnj 	addr->utba = (u_short) um->um_ubinfo;
408*4744Swnj 	addr->utcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x30)|UT_IE|UT_GO;
409*4744Swnj 	printd("utdgo: cs1=%b\n", addr->utcs1, UT_BITS);
410*4744Swnj }
411*4744Swnj 
412*4744Swnj /*
413*4744Swnj  * Ut interrupt handler
414*4744Swnj  */
415*4744Swnj /*ARGSUSED*/
416*4744Swnj utintr(ut11)
417*4744Swnj 	int ut11;
418*4744Swnj {
419*4744Swnj 	struct buf *dp;
420*4744Swnj 	register struct buf *bp;
421*4744Swnj 	register struct uba_ctlr *um = utminfo[ut11];
422*4744Swnj 	register struct utdevice *addr;
423*4744Swnj 	register struct tj_softc *sc;
424*4744Swnj 	int tjunit;
425*4744Swnj 	register state;
426*4744Swnj 
427*4744Swnj 	if ((dp = um->um_tab.b_actf) == NULL)
428*4744Swnj 		return;
429*4744Swnj 	bp = dp->b_actf;
430*4744Swnj 	tjunit = TJUNIT(bp->b_dev);
431*4744Swnj 	addr = (struct utdevice *)tjdinfo[tjunit]->ui_addr;
432*4744Swnj 	sc = &tj_softc[tjunit];
433*4744Swnj 	/*
434*4744Swnj 	 * Record status...
435*4744Swnj 	 */
436*4744Swnj 	sc->sc_dsreg = addr->utds;
437*4744Swnj 	sc->sc_erreg = addr->uter;
438*4744Swnj 	sc->sc_resid = addr->utwc;
439*4744Swnj 	printd("utintr: state=%d cs1=%b cs2=%b ds=%b er=%b\n",
440*4744Swnj 		um->um_tab.b_active,
441*4744Swnj 		((struct utdevice *) addr)->utcs1, UT_BITS,
442*4744Swnj 		((struct utdevice *) addr)->utcs2, UTCS2_BITS,
443*4744Swnj 		((struct utdevice *) addr)->utds, UTDS_BITS,
444*4744Swnj 		((struct utdevice *) addr)->uter, UTER_BITS);
445*4744Swnj 	/*
446*4744Swnj 	 * Check for stray attentions from slaves going online, offline,
447*4744Swnj 	 * or a completing rewind.  (The rewind started interrupt
448*4744Swnj 	 * satisfied the requestor of the rewind.)
449*4744Swnj 	 */
450*4744Swnj 	if (((addr->utcs1&(UT_SC|UT_TRE)) == UT_SC) &&
451*4744Swnj 	    (addr->utds&UTDS_ERR) == 0) {
452*4744Swnj 		addr->utas = 0xff;	/* writing a 1 clears attention */
453*4744Swnj 		/*
454*4744Swnj 		 * If we're doing a rewind and we're at the beginning
455*4744Swnj 		 * of tape, then the attention and the rewind
456*4744Swnj 		 * command may complete at the same time -- resulting in only
457*4744Swnj 		 * one interrupt.  In this case, simulate things to look like
458*4744Swnj 		 * the attention was the command complete.
459*4744Swnj 		 */
460*4744Swnj 		if (bp->b_command != UT_REW && bp->b_command != UT_REWOFFL)
461*4744Swnj 			return;
462*4744Swnj 		if ((addr->utds&UTDS_BOT) == 0)
463*4744Swnj 			return;
464*4744Swnj 		um->um_tab.b_active = SCOM;
465*4744Swnj 	}
466*4744Swnj 	if((bp->b_flags&B_READ) == 0)
467*4744Swnj 		sc->sc_lastiow = 1;
468*4744Swnj 	state = um->um_tab.b_active;
469*4744Swnj 	um->um_tab.b_active = 0;
470*4744Swnj 	/*
471*4744Swnj 	 * Check for errors...
472*4744Swnj 	 */
473*4744Swnj 	if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) {
474*4744Swnj #ifdef notdef
475*4744Swnj 		/*
476*4744Swnj 		 * if this bit were emulated, it would allow us to wait
477*4744Swnj 		 * for the transport to settle
478*4744Swnj 		 */
479*4744Swnj 		while (addr->utds&UTDS_SDWN)
480*4744Swnj 			;
481*4744Swnj #endif
482*4744Swnj 		/*
483*4744Swnj 		 * If we hit the end of tape, update our position
484*4744Swnj 		 */
485*4744Swnj 		if (addr->utds&UTDS_EOT) {
486*4744Swnj 			/*
487*4744Swnj 			 * Set blkno and nxrec on sensing end of tape.
488*4744Swnj 			 */
489*4744Swnj 			if (bp == &cutbuf[UTUNIT(bp->b_dev)]) {
490*4744Swnj 				if (sc->sc_blkno > dbtofsb(bp->b_blkno)) {
491*4744Swnj 					/* reversing */
492*4744Swnj 					sc->sc_nxrec =
493*4744Swnj 					      dbtofsb(bp->b_blkno) - addr->utfc;
494*4744Swnj 					sc->sc_blkno = sc->sc_nxrec;
495*4744Swnj 				} else {
496*4744Swnj 					/* spacing forward */
497*4744Swnj 					sc->sc_blkno =
498*4744Swnj 					      dbtofsb(bp->b_blkno) + addr->utfc;
499*4744Swnj 					sc->sc_nxrec = sc->sc_blkno-1;
500*4744Swnj 				}
501*4744Swnj 			} else		/* eof on read */
502*4744Swnj 				sc->sc_nxrec = dbtofsb(bp->b_blkno);
503*4744Swnj 			state = SCOM;		/* force completion */
504*4744Swnj 			addr->utcs1 = UT_CLEAR|UT_GO;
505*4744Swnj 			/*
506*4744Swnj 			 * Stuff fc so that it will be unstuffed correctly
507*4744Swnj 			 * later to get the residual.
508*4744Swnj 			 */
509*4744Swnj 			addr->utfc = -bp->b_bcount;
510*4744Swnj 			goto opdone;
511*4744Swnj 		}
512*4744Swnj 		addr->utcs1 = UT_CLEAR|UT_GO;	/* must clear ERR bit */
513*4744Swnj 		/*
514*4744Swnj 		 * If we were reading from a raw tape and the only error
515*4744Swnj 		 * was that the record was too long, then we don't consider
516*4744Swnj 		 * this an error.
517*4744Swnj 		 */
518*4744Swnj 		if (bp == &rutbuf[UTUNIT(bp->b_dev)] && (bp->b_flags&B_READ) &&
519*4744Swnj 		    (sc->sc_erreg&UTER_FCE))
520*4744Swnj 			goto ignoreerr;
521*4744Swnj 		/*
522*4744Swnj 		 * Retry soft errors up to 8 times
523*4744Swnj 		 */
524*4744Swnj 		if ((sc->sc_erreg&UTER_HARD) == 0 && state == SIO) {
525*4744Swnj 			if (++um->um_tab.b_errcnt < 7) {
526*4744Swnj 				sc->sc_blkno++;
527*4744Swnj 				ubadone(um);
528*4744Swnj 				goto opcont;
529*4744Swnj 			}
530*4744Swnj 		} else
531*4744Swnj 			/*
532*4744Swnj 			 * Hard or non-I/O errors on non-raw tape
533*4744Swnj 			 * cause it to close.
534*4744Swnj 			 */
535*4744Swnj 			if (sc->sc_openf > 0 && bp != &rutbuf[UTUNIT(bp->b_dev)])
536*4744Swnj 				sc->sc_openf = -1;
537*4744Swnj 		/*
538*4744Swnj 		 * Couldn't recover error.
539*4744Swnj 		 */
540*4744Swnj 		printf("ut%d: hard error bn%d er=%b cs2=%b\n", tjunit,
541*4744Swnj 			bp->b_blkno, sc->sc_erreg, UTER_BITS,
542*4744Swnj 			addr->utcs2, UTCS2_BITS);
543*4744Swnj 		bp->b_flags |= B_ERROR;
544*4744Swnj 		goto opdone;
545*4744Swnj 	}
546*4744Swnj ignoreerr:
547*4744Swnj 	/*
548*4744Swnj 	 * Advance tape control FSM.
549*4744Swnj 	 */
550*4744Swnj 	switch (state) {
551*4744Swnj 
552*4744Swnj 	case SIO:		/* read/write increments tape block # */
553*4744Swnj 		sc->sc_blkno++;
554*4744Swnj 		goto opdone;
555*4744Swnj 
556*4744Swnj 	case SCOM:		/* forw/rev space updates current position */
557*4744Swnj 		if (bp == &cutbuf[UTUNIT(bp->b_dev)])
558*4744Swnj 		switch (bp->b_command) {
559*4744Swnj 
560*4744Swnj 		case UT_SFORW:
561*4744Swnj 			sc->sc_blkno -= bp->b_repcnt;
562*4744Swnj 			break;
563*4744Swnj 
564*4744Swnj 		case UT_SREV:
565*4744Swnj 			sc->sc_blkno += bp->b_repcnt;
566*4744Swnj 			break;
567*4744Swnj 		}
568*4744Swnj 		goto opdone;
569*4744Swnj 
570*4744Swnj 	case SSEEK:
571*4744Swnj 		sc->sc_blkno = dbtofsb(bp->b_blkno);
572*4744Swnj 		goto opcont;
573*4744Swnj 
574*4744Swnj 	default:
575*4744Swnj 		panic("utintr");
576*4744Swnj 	}
577*4744Swnj 
578*4744Swnj opdone:
579*4744Swnj 	/*
580*4744Swnj 	 * Reset error count and remove
581*4744Swnj 	 * from device queue
582*4744Swnj 	 */
583*4744Swnj 	um->um_tab.b_errcnt = 0;
584*4744Swnj 	dp->b_actf = bp->b_forw;
585*4744Swnj 	ubadone(um);
586*4744Swnj 	iodone(bp);
587*4744Swnj 	/*
588*4744Swnj 	 * Circulate slave to end of controller queue
589*4744Swnj 	 * to give other slaves a chance
590*4744Swnj 	 */
591*4744Swnj 	um->um_tab.b_actf = dp->b_forw;
592*4744Swnj 	if (dp->b_actf) {
593*4744Swnj 		dp->b_forw = NULL;
594*4744Swnj 		if (um->um_tab.b_actf == NULL)
595*4744Swnj 			um->um_tab.b_actf = dp;
596*4744Swnj 		else
597*4744Swnj 			um->um_tab.b_actl->b_forw = dp;
598*4744Swnj 		um->um_tab.b_actl = dp;
599*4744Swnj 	}
600*4744Swnj 	if (um->um_tab.b_actf == 0)
601*4744Swnj 		return;
602*4744Swnj opcont:
603*4744Swnj 	utstart(um);
604*4744Swnj }
605*4744Swnj 
606*4744Swnj /*
607*4744Swnj  * Raw interface for a read
608*4744Swnj  */
609*4744Swnj utread(dev)
610*4744Swnj 	dev_t dev;
611*4744Swnj {
612*4744Swnj 	utphys(dev);
613*4744Swnj 	if (u.u_error)
614*4744Swnj 		return;
615*4744Swnj 	physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_READ, minphys);
616*4744Swnj }
617*4744Swnj 
618*4744Swnj /*
619*4744Swnj  * Raw interface for a write
620*4744Swnj  */
621*4744Swnj utwrite(dev)
622*4744Swnj {
623*4744Swnj 	utphys(dev);
624*4744Swnj 	if (u.u_error)
625*4744Swnj 		return;
626*4744Swnj 	physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_WRITE, minphys);
627*4744Swnj }
628*4744Swnj 
629*4744Swnj /*
630*4744Swnj  * Check for valid device number dev and update our notion
631*4744Swnj  * of where we are on the tape
632*4744Swnj  */
633*4744Swnj utphys(dev)
634*4744Swnj 	dev_t dev;
635*4744Swnj {
636*4744Swnj 	register int tjunit = TJUNIT(dev);
637*4744Swnj 	register struct tj_softc *sc;
638*4744Swnj 	register struct uba_device *ui;
639*4744Swnj 	register daddr_t a;
640*4744Swnj 
641*4744Swnj 	if (tjunit >= NTJ || (ui=tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) {
642*4744Swnj 		u.u_error = ENXIO;
643*4744Swnj 		return;
644*4744Swnj 	}
645*4744Swnj 	a = u.u_offset >> 9;
646*4744Swnj 	sc = &tj_softc[tjunit];
647*4744Swnj 	sc->sc_blkno = dbtofsb(a);
648*4744Swnj 	sc->sc_nxrec = dbtofsb(a)+1;
649*4744Swnj }
650*4744Swnj 
651*4744Swnj /*ARGSUSED*/
652*4744Swnj utioctl(dev, cmd, addr, flag)
653*4744Swnj 	dev_t dev;
654*4744Swnj 	caddr_t addr;
655*4744Swnj {
656*4744Swnj 	register struct tj_softc *sc = &tj_softc[TJUNIT(dev)];
657*4744Swnj 	register struct buf *bp = &cutbuf[UTUNIT(dev)];
658*4744Swnj 	register callcount;
659*4744Swnj 	int fcount;
660*4744Swnj 	struct mtop mtop;
661*4744Swnj 	struct mtget mtget;
662*4744Swnj 	/* we depend of the values and order of the MT codes here */
663*4744Swnj 	static utops[] =
664*4744Swnj       {UT_WEOF,UT_SFORWF,UT_SREVF,UT_SFORW,UT_SREV,UT_REW,UT_REWOFFL,UT_SENSE};
665*4744Swnj 
666*4744Swnj 	switch (cmd) {
667*4744Swnj 
668*4744Swnj 	case MTIOCTOP:
669*4744Swnj 		if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
670*4744Swnj 			u.u_error = EFAULT;
671*4744Swnj 			return;
672*4744Swnj 		}
673*4744Swnj 		switch(mtop.mt_op) {
674*4744Swnj 
675*4744Swnj 		case MTWEOF:
676*4744Swnj 			callcount = mtop.mt_count;
677*4744Swnj 			fcount = 1;
678*4744Swnj 			break;
679*4744Swnj 
680*4744Swnj 		case MTFSF: case MTBSF:
681*4744Swnj 		case MTFSR: case MTBSR:
682*4744Swnj 			callcount = 1;
683*4744Swnj 			fcount = mtop.mt_count;
684*4744Swnj 			break;
685*4744Swnj 
686*4744Swnj 		case MTREW: case MTOFFL: case MTNOP:
687*4744Swnj 			callcount = 1;
688*4744Swnj 			fcount = 1;
689*4744Swnj 			break;
690*4744Swnj 
691*4744Swnj 		default:
692*4744Swnj 			u.u_error = ENXIO;
693*4744Swnj 			return;
694*4744Swnj 		}
695*4744Swnj 		if (callcount <= 0 || fcount <= 0) {
696*4744Swnj 			u.u_error = ENXIO;
697*4744Swnj 			return;
698*4744Swnj 		}
699*4744Swnj 		while (--callcount >= 0) {
700*4744Swnj 			utcommand(dev, utops[mtop.mt_op], fcount);
701*4744Swnj 			if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
702*4744Swnj 			    bp->b_resid) {
703*4744Swnj 				u.u_error = EIO;
704*4744Swnj 				break;
705*4744Swnj 			}
706*4744Swnj 			if ((bp->b_flags&B_ERROR) || (sc->sc_dsreg&UTDS_BOT))
707*4744Swnj 				break;
708*4744Swnj 		}
709*4744Swnj 		geterror(bp);
710*4744Swnj 		return;
711*4744Swnj 
712*4744Swnj 	case MTIOCGET:
713*4744Swnj 		mtget.mt_dsreg = sc->sc_dsreg;
714*4744Swnj 		mtget.mt_erreg = sc->sc_erreg;
715*4744Swnj 		mtget.mt_resid = sc->sc_resid;
716*4744Swnj 		mtget.mt_type = MT_ISUT;
717*4744Swnj 		if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
718*4744Swnj 			u.u_error = EFAULT;
719*4744Swnj 		return;
720*4744Swnj 
721*4744Swnj 	default:
722*4744Swnj 		u.u_error = ENXIO;
723*4744Swnj 	}
724*4744Swnj }
725*4744Swnj 
726*4744Swnj utreset(uban)
727*4744Swnj 	int uban;
728*4744Swnj {
729*4744Swnj 	register struct uba_ctlr *um;
730*4744Swnj 	register ut11, tjunit;
731*4744Swnj 	register struct uba_device *ui;
732*4744Swnj 	register struct buf *dp;
733*4744Swnj 
734*4744Swnj 	for (ut11 = 0; ut11 < NUT; ut11++) {
735*4744Swnj 		if ((um = utminfo[ut11]) == 0 || um->um_alive == 0 ||
736*4744Swnj 		   um->um_ubanum != uban)
737*4744Swnj 			continue;
738*4744Swnj 		printf(" ut%d", ut11);
739*4744Swnj 		um->um_tab.b_active = 0;
740*4744Swnj 		um->um_tab.b_actf = um->um_tab.b_actl = 0;
741*4744Swnj 		if (um->um_ubinfo) {
742*4744Swnj 			printf("<%d>", (um->um_ubinfo>>28)&0xf);
743*4744Swnj 			ubadone(um);
744*4744Swnj 		}
745*4744Swnj 		((struct utdevice *)(um->um_addr))->utcs1 = UT_CLEAR|UT_GO;
746*4744Swnj 		for (tjunit = 0; tjunit < NTJ; tjunit++) {
747*4744Swnj 			if ((ui = tjdinfo[tjunit]) == 0 || ui->ui_mi != um ||
748*4744Swnj 			    ui->ui_alive == 0)
749*4744Swnj 				continue;
750*4744Swnj 			dp = &tjutab[tjunit];
751*4744Swnj 			dp->b_active = 0;
752*4744Swnj 			dp->b_forw = 0;
753*4744Swnj 			if (um->um_tab.b_actf == NULL)
754*4744Swnj 				um->um_tab.b_actf = dp;
755*4744Swnj 			else
756*4744Swnj 				um->um_tab.b_actl->b_forw = dp;
757*4744Swnj 			um->um_tab.b_actl = dp;
758*4744Swnj 			if (tj_softc[tjunit].sc_openf > 0)
759*4744Swnj 				tj_softc[tjunit].sc_openf = -1;
760*4744Swnj 		}
761*4744Swnj 		utstart(um);
762*4744Swnj 	}
763*4744Swnj }
764*4744Swnj 
765*4744Swnj /*
766*4744Swnj  * Do a stand-alone core dump to tape --
767*4744Swnj  * from here down, routines are used only in dump context
768*4744Swnj  */
769*4744Swnj #define	DBSIZE	20
770*4744Swnj 
771*4744Swnj utdump()
772*4744Swnj {
773*4744Swnj 	register struct uba_device *ui;
774*4744Swnj 	register struct uba_regs *up;
775*4744Swnj 	register struct utdevice *utaddr;
776*4744Swnj 	int blk, num = maxfree;
777*4744Swnj 	int start = 0;
778*4744Swnj 
779*4744Swnj #define	phys(a,b)		((b)((int)(a)&0x7fffffff))
780*4744Swnj 	if (tjdinfo[0] == 0)
781*4744Swnj 		return (ENXIO);
782*4744Swnj 	ui = phys(tjdinfo[0], struct uba_device *);
783*4744Swnj 	up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba;
784*4744Swnj 	ubainit();
785*4744Swnj 	DELAY(1000000);
786*4744Swnj 	utwait(utaddr);
787*4744Swnj 	utaddr = (struct utdevice *)ui->ui_physaddr;
788*4744Swnj 	/* do it at 1600 bpi so tape can be read on other machines */
789*4744Swnj 	utaddr->uttc = UT_PE|PDP11FMT;	/* implicit slave 0 or-ed in */
790*4744Swnj 	utaddr->utcs1 = UT_CLEAR|UT_GO;
791*4744Swnj 	while (num > 0) {
792*4744Swnj 		blk = num > DBSIZE ? DBSIZE : num;
793*4744Swnj 		utdwrite(start, blk, utaddr, up);
794*4744Swnj 		start += blk;
795*4744Swnj 		num -= blk;
796*4744Swnj 	}
797*4744Swnj 	uteof(utaddr);
798*4744Swnj 	uteof(utaddr);
799*4744Swnj 	utwait(utaddr);
800*4744Swnj 	if (utaddr->utds&UTDS_ERR)
801*4744Swnj 		return(EIO);
802*4744Swnj 	utaddr->utcs1 = UT_REW|UT_GO;
803*4744Swnj 	return (0);
804*4744Swnj }
805*4744Swnj 
806*4744Swnj utdwrite(dbuf, num, utaddr, up)
807*4744Swnj 	register dbuf, num;
808*4744Swnj 	register struct utdevice *utaddr;
809*4744Swnj 	struct uba_regs *up;
810*4744Swnj {
811*4744Swnj 	register struct pte *io;
812*4744Swnj 	register int npf;
813*4744Swnj 
814*4744Swnj 	utwait(utaddr);
815*4744Swnj 	io = up->uba_map;
816*4744Swnj 	npf = num + 1;
817*4744Swnj 	while (--npf != 0)
818*4744Swnj 		*(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV);
819*4744Swnj 	*(int *)io = 0;
820*4744Swnj 	utaddr->utwc = -((num*NBPG)<<1);
821*4744Swnj 	utaddr->utba = 0;
822*4744Swnj 	utaddr->utcs1 = UT_WCOM|UT_GO;
823*4744Swnj }
824*4744Swnj 
825*4744Swnj utwait(utaddr)
826*4744Swnj 	struct utdevice *utaddr;
827*4744Swnj {
828*4744Swnj 	register s;
829*4744Swnj 
830*4744Swnj 	do
831*4744Swnj 		s = utaddr->utds;
832*4744Swnj 	while ((s&UTDS_DRY) == 0);
833*4744Swnj }
834*4744Swnj 
835*4744Swnj uteof(utaddr)
836*4744Swnj 	struct utdevice *utaddr;
837*4744Swnj {
838*4744Swnj 
839*4744Swnj 	utwait(utaddr);
840*4744Swnj 	utaddr->utcs1 = UT_WEOF|UT_GO;
841*4744Swnj }
842*4744Swnj #endif
843