xref: /csrg-svn/sys/vax/uba/ts.c (revision 1900)
1*1900Swnj /*	ts.c	4.1	12/17/80	*/
2*1900Swnj 
3*1900Swnj #include "../conf/ts.h"
4*1900Swnj #if NTS > 0
5*1900Swnj /*
6*1900Swnj  * TS11 tape driver
7*1900Swnj  */
8*1900Swnj 
9*1900Swnj #include "../h/param.h"
10*1900Swnj #include "../h/systm.h"
11*1900Swnj #include "../h/buf.h"
12*1900Swnj #include "../h/conf.h"
13*1900Swnj #include "../h/dir.h"
14*1900Swnj #include "../h/file.h"
15*1900Swnj #include "../h/user.h"
16*1900Swnj #include "../h/pte.h"
17*1900Swnj #include "../h/map.h"
18*1900Swnj #include "../h/uba.h"
19*1900Swnj 
20*1900Swnj typedef	unsigned short ushort;
21*1900Swnj 
22*1900Swnj struct	device {
23*1900Swnj 	ushort	tsdb;
24*1900Swnj 	ushort	tssr;
25*1900Swnj };
26*1900Swnj 
27*1900Swnj struct	buf	tstab;
28*1900Swnj struct	buf	rtsbuf;
29*1900Swnj struct	buf	ctsbuf;
30*1900Swnj 
31*1900Swnj #define	INF	1000000000
32*1900Swnj 
33*1900Swnj ushort	ts_uba;
34*1900Swnj long	ts_iouba;
35*1900Swnj char	ts_flags;
36*1900Swnj char	ts_openf;
37*1900Swnj daddr_t	ts_blkno;
38*1900Swnj daddr_t	ts_nxrec;
39*1900Swnj 
40*1900Swnj /* status message */
41*1900Swnj struct	sts {
42*1900Swnj 	ushort	s_sts;
43*1900Swnj 	ushort	len;
44*1900Swnj 	ushort	rbpcr;
45*1900Swnj 	ushort	xs0;
46*1900Swnj 	ushort	xs1;
47*1900Swnj 	ushort	xs2;
48*1900Swnj 	ushort	xs3;
49*1900Swnj };
50*1900Swnj 
51*1900Swnj /* Error codes in stat 0 */
52*1900Swnj #define	TMK	0100000
53*1900Swnj #define	RLS	040000
54*1900Swnj #define	ONL	0100
55*1900Swnj #define	WLE	04000
56*1900Swnj 
57*1900Swnj /* command message */
58*1900Swnj struct cmd {
59*1900Swnj 	ushort	c_cmd;
60*1900Swnj 	ushort	c_loba;
61*1900Swnj 	ushort	c_hiba;
62*1900Swnj 	ushort	c_size;
63*1900Swnj };
64*1900Swnj 
65*1900Swnj #define	ACK	0100000
66*1900Swnj #define	CVC	040000
67*1900Swnj #define	IE	0200
68*1900Swnj #define	READ	01
69*1900Swnj #define	REREAD	01001
70*1900Swnj 
71*1900Swnj #define	SETCHR	04
72*1900Swnj 
73*1900Swnj #define	WRITE	05
74*1900Swnj #define	REWRITE	01005
75*1900Swnj 
76*1900Swnj #define	SFORW	010
77*1900Swnj #define	SREV	0410
78*1900Swnj #define	REW	02010
79*1900Swnj 
80*1900Swnj #define	WTM	011
81*1900Swnj 
82*1900Swnj #define	GSTAT	017
83*1900Swnj 
84*1900Swnj /* characteristics data */
85*1900Swnj struct charac {
86*1900Swnj 	ushort	char_loba;
87*1900Swnj 	ushort	char_hiba;
88*1900Swnj 	ushort	char_size;
89*1900Swnj 	ushort	char_mode;
90*1900Swnj };
91*1900Swnj 
92*1900Swnj /* All the packets, collected */
93*1900Swnj struct tsmesg {
94*1900Swnj 	struct	cmd ts_cmd;
95*1900Swnj 	struct	sts ts_sts;
96*1900Swnj 	struct	charac ts_char;
97*1900Swnj 	int	align;		/* Should force alignment */
98*1900Swnj } ts;
99*1900Swnj 
100*1900Swnj /* Bits in (unibus) status register */
101*1900Swnj #define	SC	0100000
102*1900Swnj #define	SSR	0200
103*1900Swnj #define	OFL	0100
104*1900Swnj #define	NBA	02000
105*1900Swnj 
106*1900Swnj /* states */
107*1900Swnj #define	SIO	1
108*1900Swnj #define	SSFOR	2
109*1900Swnj #define	SSREV	3
110*1900Swnj #define SRETRY	4
111*1900Swnj #define SCOM	5
112*1900Swnj #define SOK	6
113*1900Swnj 
114*1900Swnj #define H_WRITTEN 1
115*1900Swnj 
116*1900Swnj tsopen(dev, flag)
117*1900Swnj {
118*1900Swnj 	register struct device *tsaddr = TSADDR;
119*1900Swnj 	static struct tsmesg *ubaddr;
120*1900Swnj 
121*1900Swnj 	tstab.b_flags |= B_TAPE;
122*1900Swnj 	if (ts_openf) {
123*1900Swnj 		u.u_error = ENXIO;
124*1900Swnj 		return;
125*1900Swnj 	}
126*1900Swnj 	if (ubaddr==0 || tsaddr->tssr&(OFL|NBA) || (tsaddr->tssr&SSR)==0) {
127*1900Swnj 		long i = 0;
128*1900Swnj 		tsaddr->tssr = 0;
129*1900Swnj 		while ((tsaddr->tssr & SSR)==0) {
130*1900Swnj 			if (++i > 1000000) {
131*1900Swnj 				printf("Tape unready\n");
132*1900Swnj 				u.u_error = ENXIO;
133*1900Swnj 				return;
134*1900Swnj 			}
135*1900Swnj 		}
136*1900Swnj 	}
137*1900Swnj 	if (tsaddr->tssr&OFL) {
138*1900Swnj 		printf("Tape offline\n");
139*1900Swnj 		u.u_error = ENXIO;
140*1900Swnj 		return;
141*1900Swnj 	}
142*1900Swnj 	if (tsaddr->tssr&NBA) {
143*1900Swnj 		ctsbuf.b_un.b_addr = (caddr_t) &ts;
144*1900Swnj 		ctsbuf.b_bcount = sizeof(ts);
145*1900Swnj 		if (ubaddr == 0)
146*1900Swnj 			ubaddr = (struct tsmesg *)ubasetup(&ctsbuf, 0);
147*1900Swnj 		ts_uba = (ushort)((long)ubaddr + (((long)ubaddr >> 16) & 03));
148*1900Swnj 		ts.ts_char.char_loba = (int)&ubaddr->ts_sts;
149*1900Swnj 		ts.ts_char.char_hiba = (ushort)((long)&ubaddr->ts_sts >> 16) & 03;
150*1900Swnj 		ts.ts_char.char_size = sizeof(ts.ts_sts);
151*1900Swnj 		ts.ts_char.char_mode = 0400;		/* Stop on 2 tape marks */
152*1900Swnj 		ts.ts_cmd.c_cmd = ACK + 04;	/* write characteristics */
153*1900Swnj 		ts.ts_cmd.c_loba = (int)&ubaddr->ts_char;
154*1900Swnj 		ts.ts_cmd.c_hiba = (ushort)((long)&ubaddr->ts_sts >> 16) & 03;
155*1900Swnj 		ts.ts_cmd.c_size = sizeof(ts.ts_sts);
156*1900Swnj 		tsaddr->tsdb = ts_uba;
157*1900Swnj 	}
158*1900Swnj 	ts_blkno = 0;
159*1900Swnj 	ts_nxrec = INF;
160*1900Swnj 	ts_flags = 0;
161*1900Swnj 	if (u.u_error==0)
162*1900Swnj 		ts_openf++;
163*1900Swnj }
164*1900Swnj 
165*1900Swnj tsclose(dev, flag)
166*1900Swnj {
167*1900Swnj 
168*1900Swnj 	if (flag == FWRITE || ((flag&FWRITE) && (ts_flags&H_WRITTEN))) {
169*1900Swnj 		tscommand(WTM);
170*1900Swnj 		tscommand(WTM);
171*1900Swnj 		tscommand(SREV);
172*1900Swnj 	}
173*1900Swnj 	if ((minor(dev)&4) == 0)
174*1900Swnj 		tscommand(REW);
175*1900Swnj 	ts_openf = 0;
176*1900Swnj }
177*1900Swnj 
178*1900Swnj tscommand(com)
179*1900Swnj {
180*1900Swnj 	register struct buf *bp;
181*1900Swnj 
182*1900Swnj 	bp = &ctsbuf;
183*1900Swnj 	spl5();
184*1900Swnj 	while(bp->b_flags&B_BUSY) {
185*1900Swnj 		bp->b_flags |= B_WANTED;
186*1900Swnj 		sleep((caddr_t)bp, PRIBIO);
187*1900Swnj 	}
188*1900Swnj 	spl0();
189*1900Swnj 	bp->b_resid = com;
190*1900Swnj 	bp->b_blkno = 0;
191*1900Swnj 	bp->b_flags = B_BUSY|B_READ;
192*1900Swnj 	tsstrategy(bp);
193*1900Swnj 	iowait(bp);
194*1900Swnj 	if(bp->b_flags&B_WANTED)
195*1900Swnj 		wakeup((caddr_t)bp);
196*1900Swnj 	bp->b_flags = 0;
197*1900Swnj 	return(bp->b_resid);
198*1900Swnj }
199*1900Swnj 
200*1900Swnj tsstrategy(bp)
201*1900Swnj register struct buf *bp;
202*1900Swnj {
203*1900Swnj 	register daddr_t *p;
204*1900Swnj 
205*1900Swnj 	if(bp != &ctsbuf) {
206*1900Swnj 		p = &ts_nxrec;
207*1900Swnj 		if(dbtofsb(bp->b_blkno) > *p) {
208*1900Swnj 			bp->b_flags |= B_ERROR;
209*1900Swnj 			bp->b_error = ENXIO;
210*1900Swnj 			iodone(bp);
211*1900Swnj 			return;
212*1900Swnj 		}
213*1900Swnj 		if(dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) {
214*1900Swnj 			bp->b_resid = bp->b_bcount;
215*1900Swnj 			iodone(bp);
216*1900Swnj 			return;
217*1900Swnj 		}
218*1900Swnj 		if ((bp->b_flags&B_READ)==0) {
219*1900Swnj 			*p = dbtofsb(bp->b_blkno) + 1;
220*1900Swnj 			ts_flags |= H_WRITTEN;
221*1900Swnj 		}
222*1900Swnj 	}
223*1900Swnj 	bp->av_forw = NULL;
224*1900Swnj 	spl5();
225*1900Swnj 	if (tstab.b_actf == NULL)
226*1900Swnj 		tstab.b_actf = bp;
227*1900Swnj 	else
228*1900Swnj 		tstab.b_actl->av_forw = bp;
229*1900Swnj 	tstab.b_actl = bp;
230*1900Swnj 	if (tstab.b_active==0)
231*1900Swnj 		tsstart();
232*1900Swnj 	spl0();
233*1900Swnj }
234*1900Swnj 
235*1900Swnj tsstart()
236*1900Swnj {
237*1900Swnj 	register struct buf *bp;
238*1900Swnj 	register struct device *tsaddr = TSADDR;
239*1900Swnj 	daddr_t blkno;
240*1900Swnj 
241*1900Swnj     loop:
242*1900Swnj 	if ((bp = tstab.b_actf) == NULL)
243*1900Swnj 		return;
244*1900Swnj 	blkno = ts_blkno;
245*1900Swnj 	if (ts_openf < 0 || dbtofsb(bp->b_blkno) > ts_nxrec)
246*1900Swnj 		goto abort;
247*1900Swnj 	if (bp == &ctsbuf) {
248*1900Swnj 		tstab.b_active = SCOM;
249*1900Swnj 		ts.ts_cmd.c_cmd = ACK+CVC+IE+bp->b_resid;
250*1900Swnj 		ts.ts_cmd.c_loba = 1;		/* count always 1 */
251*1900Swnj 	} else if (blkno == dbtofsb(bp->b_blkno)) {
252*1900Swnj 		tstab.b_active = SIO;
253*1900Swnj 		ts_iouba = ubasetup(bp, 1);
254*1900Swnj 		ts.ts_cmd.c_loba = (ushort)ts_iouba;
255*1900Swnj 		ts.ts_cmd.c_hiba = (ushort)(ts_iouba >> 16) & 03;
256*1900Swnj 		ts.ts_cmd.c_size = bp->b_bcount;
257*1900Swnj 		if(bp->b_flags & B_READ)
258*1900Swnj 			ts.ts_cmd.c_cmd = ACK+CVC+IE+READ;
259*1900Swnj 		else
260*1900Swnj 			ts.ts_cmd.c_cmd = ACK+CVC+IE+WRITE;
261*1900Swnj 	} else {
262*1900Swnj 		if (blkno < dbtofsb(bp->b_blkno)) {
263*1900Swnj 			tstab.b_active = SSFOR;
264*1900Swnj 			ts.ts_cmd.c_cmd = ACK+CVC+IE+SFORW;
265*1900Swnj 			ts.ts_cmd.c_loba = dbtofsb(bp->b_blkno) - blkno;
266*1900Swnj 		} else {
267*1900Swnj 			tstab.b_active = SSREV;
268*1900Swnj 			ts.ts_cmd.c_cmd = ACK+CVC+IE+SREV;
269*1900Swnj 			ts.ts_cmd.c_loba = blkno - dbtofsb(bp->b_blkno);
270*1900Swnj 		}
271*1900Swnj 	}
272*1900Swnj 	tsaddr->tsdb = ts_uba;
273*1900Swnj 	return;
274*1900Swnj 
275*1900Swnj     abort:
276*1900Swnj 	bp->b_flags |= B_ERROR;
277*1900Swnj 
278*1900Swnj     next:
279*1900Swnj 	tstab.b_active = 0;
280*1900Swnj 	tstab.b_actf = bp->av_forw;
281*1900Swnj 	iodone(bp);
282*1900Swnj 	goto loop;
283*1900Swnj }
284*1900Swnj 
285*1900Swnj tsintr()
286*1900Swnj {
287*1900Swnj 	register struct buf *bp;
288*1900Swnj 	register struct device *tsaddr = TSADDR;
289*1900Swnj 	register err, errclass, state;
290*1900Swnj 
291*1900Swnj 	if ((bp = tstab.b_actf)==NULL)
292*1900Swnj 		return;
293*1900Swnj 	state = tstab.b_active;
294*1900Swnj 	tstab.b_active = 0;
295*1900Swnj 	err = tsaddr->tssr & 016;
296*1900Swnj 	if ((tsaddr->tssr & SC) == 0)
297*1900Swnj 		err = 0;
298*1900Swnj 	errclass = 0;
299*1900Swnj 	switch (err) {
300*1900Swnj 	case 014:		/* unrecoverable */
301*1900Swnj 	case 016:		/* fatal */
302*1900Swnj 	case 002:		/* attention (shouldn't happen) */
303*1900Swnj 	case 012:		/* "recoverable", but shouldn't happen */
304*1900Swnj 		errclass = 2;
305*1900Swnj 		break;
306*1900Swnj 
307*1900Swnj 	case 0:			/* all OK */
308*1900Swnj 		break;
309*1900Swnj 
310*1900Swnj 	case 004:		/* status alert */
311*1900Swnj 		if (ts.ts_sts.xs0&RLS && bp==&rtsbuf)	/* short record */
312*1900Swnj 			break;
313*1900Swnj 		if (ts.ts_sts.xs0 & TMK) {		/* tape mark */
314*1900Swnj 			ts.ts_sts.rbpcr = bp->b_bcount;
315*1900Swnj 			break;
316*1900Swnj 		}
317*1900Swnj 		errclass = 1;
318*1900Swnj 		break;
319*1900Swnj 
320*1900Swnj 	case 010:		/* recoverable, tape moved */
321*1900Swnj 		if (state==SIO && ++bp->b_errcnt < 10) {
322*1900Swnj 			ts.ts_cmd.c_cmd |= 01000;	/* redo bit */
323*1900Swnj 			tstab.b_active = SIO;
324*1900Swnj 			tsaddr->tsdb = ts_uba;
325*1900Swnj 			return;
326*1900Swnj 		}
327*1900Swnj 		errclass = 1;
328*1900Swnj 		break;
329*1900Swnj 
330*1900Swnj 	case 006:		/* Function reject */
331*1900Swnj 		if (state==SIO && ts.ts_sts.xs0 & WLE)
332*1900Swnj 			printf("Tape needs a ring\n");
333*1900Swnj 		if ((ts.ts_sts.xs0&ONL) == 0)		/* tape offline */
334*1900Swnj 			printf("Tape offline\n");
335*1900Swnj 		errclass = 2;
336*1900Swnj 	}
337*1900Swnj 	if (errclass)
338*1900Swnj 		printf("tp: %o %o %o %o %o %o %o %o\n", tsaddr->tssr,
339*1900Swnj 		  ts.ts_sts.s_sts, ts.ts_sts.len, ts.ts_sts.rbpcr,
340*1900Swnj 		  ts.ts_sts.xs0, ts.ts_sts.xs1, ts.ts_sts.xs2, ts.ts_sts.xs3);
341*1900Swnj 	switch(state) {
342*1900Swnj 	case SIO:
343*1900Swnj 		ts_blkno++;
344*1900Swnj 		if (ts_iouba)
345*1900Swnj 			ubafree(ts_iouba);
346*1900Swnj 		else
347*1900Swnj 			printf("uba alloc botch\n");
348*1900Swnj 		ts_iouba = 0;
349*1900Swnj 	case SCOM:
350*1900Swnj 		tstab.b_errcnt = 0;
351*1900Swnj 		tstab.b_actf = bp->av_forw;
352*1900Swnj 		bp->b_resid = ts.ts_sts.rbpcr;
353*1900Swnj 		iodone(bp);
354*1900Swnj 		break;
355*1900Swnj 
356*1900Swnj 	case SSFOR:
357*1900Swnj 	case SSREV:
358*1900Swnj 		ts_blkno = dbtofsb(bp->b_blkno);
359*1900Swnj 		break;
360*1900Swnj 
361*1900Swnj 	default:
362*1900Swnj 		printf("Unknown tape interrupt\n");
363*1900Swnj 		errclass = 2;
364*1900Swnj 		break;
365*1900Swnj 	}
366*1900Swnj 	if (errclass > 1) {
367*1900Swnj 		while (bp = tstab.b_actf) {
368*1900Swnj 			bp->b_flags |= B_ERROR;
369*1900Swnj 			iodone(bp);
370*1900Swnj 			tstab.b_actf = bp->av_forw;
371*1900Swnj 		}
372*1900Swnj 	}
373*1900Swnj 	tsstart();
374*1900Swnj }
375*1900Swnj 
376*1900Swnj tsread(dev)
377*1900Swnj {
378*1900Swnj 	tsphys(dev);
379*1900Swnj 	physio(tsstrategy, &rtsbuf, dev, B_READ, minphys);
380*1900Swnj }
381*1900Swnj 
382*1900Swnj tswrite(dev)
383*1900Swnj {
384*1900Swnj 	tsphys(dev);
385*1900Swnj 	physio(tsstrategy, &rtsbuf, dev, B_WRITE, minphys);
386*1900Swnj }
387*1900Swnj 
388*1900Swnj tsphys(dev)
389*1900Swnj {
390*1900Swnj 	register unit;
391*1900Swnj 	daddr_t a;
392*1900Swnj 
393*1900Swnj 	a = u.u_offset >> 9;
394*1900Swnj 	ts_blkno = dbtofsb(a);
395*1900Swnj 	ts_nxrec = dbtofsb(a)+1;
396*1900Swnj }
397*1900Swnj #endif
398