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