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