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