xref: /original-bsd/sys/vax/vax/tu.c (revision fbed46ce)
1 /*	tu.c	82/01/17	4.4	*/
2 
3 #if defined(VAX750) || defined(VAX7ZZ)
4 /*
5  * TU58 DECtape II device driver
6  *
7  * Bill Shannon - DEC - 01/12/81
8  *
9  * This driver controls the console TU58s on a VAX-11/750 or VAX-11/7ZZ.
10  * It could be easily modified for a Unibus TU58.  The TU58
11  * is treated as a block device (only).  Error detection and
12  * recovery is almost non-existant.  It is assumed that the
13  * TU58 will follow the RSP protocol exactly, very few protocol
14  * errors are checked for.  It is assumed that the 750 uses standard
15  * RSP while the 7ZZ uses Modified RSP (MRSP).  At the time when 750's
16  * are converted to MRSP (by replacing EPROMS in the TU58), the tests
17  * based on MRSP can be removed.
18  */
19 #define	NTU	((cpu == VAX_750) ? 1 : 2)
20 
21 #define	MRSP	(cpu != VAX_750)
22 
23 #include "../h/param.h"
24 #include "../h/systm.h"
25 #include "../h/buf.h"
26 #include "../h/conf.h"
27 #include "../h/dir.h"
28 #include "../h/user.h"
29 #include "../h/mtpr.h"
30 #include "../h/cpu.h"
31 
32 #define	printd	if(tudebug) printf
33 #ifdef	printd
34 int	tudebug;	/* printd */
35 #endif	printd
36 
37 #define	NTUBLK	512		/* number of blocks on a TU58 cassette */
38 
39 #define	TUIPL	((cpu == VAX_750) ? 0x17 : 0x14)
40 
41 /*
42  * Device register bits
43  */
44 #define	READY	0200		/* transmitter ready */
45 #define	DONE	0200		/* receiver done */
46 #define	IE	0100		/* interrupt enable */
47 #define	BREAK	1		/* send break */
48 
49 /*
50  * Structure of a command packet
51  */
52 struct packet {
53 	u_char	pk_flag;	/* indicates packet type (cmd, data, etc.) */
54 	u_char	pk_mcount;	/* length of packet (bytes) */
55 	u_char	pk_op;		/* operation to perform (read, write, etc.) */
56 	char	pk_mod;		/* modifier for op or returned status */
57 	u_char	pk_unit;	/* unit number */
58 	u_char	pk_sw;		/* switches */
59 	u_short	pk_seq;		/* sequence number, always zero */
60 	u_short	pk_count;	/* requested byte count for read or write */
61 	u_short	pk_block;	/* block number for read, write, or seek */
62 	u_short	pk_chksum;	/* checksum, by words with end around carry */
63 };
64 
65 struct packet tucmd;		/* a command sent to the TU58 */
66 struct packet tudata;		/* a command or data returned from TU58 */
67 
68 /*
69  * State information
70  */
71 struct tu {
72 	u_char	*rbptr;		/* pointer to buffer for read */
73 	int	rcnt;		/* how much to read */
74 	u_char	*wbptr;		/* pointer to buffer for write */
75 	int	wcnt;		/* how much to write */
76 	int	state;		/* current state of tansfer operation */
77 	int	flag;		/* read in progress flag */
78 	char	*addr;		/* real buffer data address */
79 	int	count;		/* real requested count */
80 	int	serrs;		/* count of soft errors */
81 	int	cerrs;		/* count of checksum errors */
82 	int	herrs;		/* count of hard errors */
83 } tu;
84 
85 /*
86  * States
87  */
88 #define	INIT1	0		/* sending nulls */
89 #define	INIT2	1		/* sending inits */
90 #define	IDLE	2		/* initialized, no transfer in progress */
91 #define	SENDH	3		/* sending header */
92 #define	SENDD	4		/* sending data */
93 #define	SENDC	5		/* sending checksum */
94 #define	SENDR	6		/* sending read command packet */
95 #define	SENDW	7		/* sending write command packet */
96 #define	GETH	8		/* reading header */
97 #define	GETD	9		/* reading data */
98 #define	GETC	10		/* reading checksum */
99 #define	GET	11		/* reading an entire packet */
100 #define	WAIT	12		/* waiting for continue */
101 
102 /*
103  * Packet Flags
104  */
105 #define	TUF_DATA	1		/* data packet */
106 #define	TUF_CMD		2		/* command packet */
107 #define	TUF_INITF	4		/* initialize */
108 #define	TUF_CONT	020		/* continue */
109 #define	TUF_XOFF	023		/* flow control */
110 
111 /*
112  * Op Codes
113  */
114 #define	TUOP_INIT	1		/* initialize */
115 #define	TUOP_READ	2		/* read block */
116 #define	TUOP_WRITE	3		/* write block */
117 #define	TUOP_SEEK	5		/* seek to block */
118 #define TUOP_DIAGNOSE	7		/* run micro-diagnostics */
119 #define	TUOP_END	0100		/* end packet */
120 
121 /*
122  * Switches
123  */
124 #define	TUSW_MRSP	010		/* use Modified RSP */
125 
126 u_char	tunull[2] = { 0, 0 };	/* nulls to send for initialization */
127 u_char	tuinit[2] = { TUF_INITF, TUF_INITF };	/* inits to send */
128 
129 int	tutimer = 0;
130 
131 struct buf tutab;		/* I/O queue header */
132 
133 /*
134  * Open the TU58
135  */
136 /*ARGSUSED*/
137 tuopen(dev, flag)
138 {
139 	extern int tuwatch();
140 	register s;
141 
142 #ifdef lint
143 	turintr(); tuwintr();
144 #endif
145 	if (minor(dev) >= NTU) {
146 		u.u_error = ENXIO;
147 		return;
148 	}
149 	if (tutimer == 0) {
150 		tutimer++;
151 		timeout(tuwatch, (caddr_t)0, hz);
152 	}
153 	s = splx(TUIPL);
154 	if (tu.state != IDLE) {
155 		tureset();
156 		sleep((caddr_t)&tu, PZERO);
157 		tutab.b_active = NULL;
158 		if (tu.state != IDLE) {		/* couldn't initialize */
159 			u.u_error = ENXIO;
160 			tu.state = INIT1;
161 			tu.rcnt = tu.wcnt = 0;
162 			mtpr(CSTS, 0);
163 			mtpr(CSRS, 0);
164 		}
165 	} else
166 		mtpr(CSRS, IE);
167 	splx(s);
168 }
169 
170 /*
171  * Close the TU58
172  */
173 tuclose(dev)
174 {
175 
176 	if (tutab.b_active == 0) {
177 		mtpr(CSRS, 0);
178 		tutimer = 0;
179 	}
180 	if (tu.serrs + tu.cerrs + tu.herrs != 0) {	/* any errors ? */
181 		uprintf("tu%d: %d soft errors, %d chksum errors, %d hard errors\n",
182 			minor(dev), tu.serrs, tu.cerrs, tu.herrs);
183 		tu.serrs = tu.cerrs = tu.herrs = 0;
184 	}
185 }
186 
187 /*
188  * Reset the TU58
189  */
190 tureset()
191 {
192 
193 	tu.state = INIT1;
194 	tu.wbptr = tunull;
195 	tu.wcnt = sizeof tunull;
196 	tucmd.pk_flag = TUF_CMD;
197 	tucmd.pk_mcount = sizeof tucmd - 4;
198 	tucmd.pk_mod = 0;
199 	tucmd.pk_seq = 0;
200 	tucmd.pk_sw = MRSP ? TUSW_MRSP : 0;
201 	tutab.b_active++;
202 	mtpr(CSRS, 0);
203 	mtpr(CSTS, IE|BREAK);
204 	tuxintr();		/* start output */
205 	return;
206 }
207 
208 /*
209  * Strategy routine for block I/O
210  */
211 tustrategy(bp)
212 	register struct buf *bp;
213 {
214 	register int s;
215 
216 	if (bp->b_blkno >= NTUBLK) {	/* block number out of range? */
217 		bp->b_flags |= B_ERROR;
218 		iodone(bp);
219 		return;
220 	}
221 	bp->av_forw = NULL;
222 	s = splx(TUIPL);
223 	if (tutab.b_actf == NULL)
224 		tutab.b_actf = bp;
225 	else
226 		tutab.b_actl->av_forw = bp;
227 	tutab.b_actl = bp;
228 	if (tutab.b_active == NULL)
229 		tustart();
230 	splx(s);
231 }
232 
233 /*
234  * Start the transfer
235  */
236 tustart()
237 {
238 	register struct buf *bp;
239 
240 	if ((bp = tutab.b_actf) == NULL)
241 		return;
242 	if (tu.state != IDLE) {
243 		tureset();
244 		return;
245 	}
246 	tutab.b_active++;
247 	tutab.b_errcnt = 0;
248 	tucmd.pk_op = bp->b_flags&B_READ ? TUOP_READ : TUOP_WRITE;
249 	tucmd.pk_unit = minor(bp->b_dev);
250 	tucmd.pk_count = tu.count = bp->b_bcount;
251 	tucmd.pk_block = bp->b_blkno;
252 	tucmd.pk_chksum =
253 	    tuchk(*((short *)&tucmd), (caddr_t)&tucmd.pk_op,
254 		(int)tucmd.pk_mcount);
255 	tu.state = bp->b_flags&B_READ ? SENDR : SENDW;
256 	tu.addr = bp->b_un.b_addr;
257 	tu.count = bp->b_bcount;
258 	tu.wbptr = (u_char *)&tucmd;
259 	tu.wcnt = sizeof tucmd;
260 	tuxintr();
261 }
262 
263 /*
264  * TU58 receiver interrupt
265  */
266 turintr()
267 {
268 	register struct buf *bp;
269 	register int c;
270 
271 	c = mfpr(CSRD)&0xff;		/* get the char, clear the interrupt */
272 	if (MRSP) {
273 		while ((mfpr(CSTS)&READY) == 0)
274 			;
275 		mtpr(CSTD, TUF_CONT);	/* ACK */
276 	}
277 	if (tu.rcnt) {			/* still waiting for data? */
278 		*tu.rbptr++ = c;	/* yup, put it there */
279 		if (--tu.rcnt)		/* decrement count, any left? */
280 			return;		/* get some more */
281 	}
282 
283 	/*
284 	 * We got all the data we were expecting for now,
285 	 * switch on the state of the transfer.
286 	 */
287 	switch(tu.state) {
288 
289 	case INIT2:
290 		if (c == TUF_CONT)	/* did we get the expected continue? */
291 			tu.state = IDLE;
292 		else
293 			tu.state = INIT1;	/* bad news... */
294 		tu.flag = 0;
295 		wakeup((caddr_t)&tu);
296 		tustart();
297 		break;
298 
299 	case WAIT:			/* waiting for continue */
300 		if (c != TUF_CONT) {
301 			tu.state = INIT1;	/* bad news... */
302 			break;
303 		}
304 		tu.flag = 0;
305 		tudata.pk_flag = TUF_DATA;
306 		tudata.pk_mcount = MIN(128, tu.count);
307 		tudata.pk_chksum =
308 		    tuchk(*((short *)&tudata), (caddr_t)tu.addr,
309 			(int)tudata.pk_mcount);
310 		tu.state = SENDH;
311 		tu.wbptr = (u_char *)&tudata;
312 		tu.wcnt = 2;
313 		tuxintr();
314 		break;
315 
316 	case GETH:		/* got header, get data */
317 		if (tudata.pk_flag == TUF_DATA)		/* data message? */
318 			tu.rbptr = (u_char *)tu.addr;	/* yes put in buffer */
319 		tu.rcnt = tudata.pk_mcount;		/* amount to get */
320 		tu.state = GETD;
321 		break;
322 
323 	case GETD:		/* got data, get checksum */
324 		tu.rbptr = (u_char *)&tudata.pk_chksum;
325 		tu.rcnt = sizeof tudata.pk_chksum;
326 		tu.state = GETC;
327 		break;
328 
329 	case GET:
330 	case GETC:		/* got entire packet */
331 #ifdef notdef
332 		if (tudata.pk_chksum !=
333 		    tuchk(*((short *)&tudata),
334 		     tudata.pk_flag == TUF_DATA ? tu.addr : &tudata.pk_op,
335 		     (int)tudata.pk_mcount))
336 			tu.cerrs++;
337 #endif
338 		if (tudata.pk_flag == TUF_DATA) {
339 			/* data packet, advance to next */
340 			tu.addr += tudata.pk_mcount;
341 			tu.count -= tudata.pk_mcount;
342 			tu.state = GETH;
343 			tu.rbptr = (u_char *)&tudata;	/* next packet */
344 			tu.rcnt = 2;
345 		} else if (tudata.pk_flag==TUF_CMD && tudata.pk_op==TUOP_END) {
346 			/* end packet, idle and reenable transmitter */
347 			tu.state = IDLE;
348 			tu.flag = 0;
349 			mtpr(CSTS, IE);
350 			printd("ON ");
351 			if ((bp = tutab.b_actf) == NULL) {
352 				printf("tu: no bp!\n");
353 				printf("active %d\n", tutab.b_active);
354 				tustart();
355 				return;
356 			}
357 			if (tudata.pk_mod < 0) {	/* hard error */
358 				bp->b_flags |= B_ERROR;
359 				tu.herrs++;
360 				harderr(bp, "tu");
361 				printf("  pk_mod %d\n", -tudata.pk_mod);
362 			} else if (tudata.pk_mod > 0)	/* soft error */
363 				tu.serrs++;
364 			tutab.b_active = NULL;
365 			tutab.b_actf = bp->av_forw;
366 			bp->b_resid = tu.count;
367 			iodone(bp);
368 			tustart();
369 		} else {
370 			printf("neither data nor end: %o %o\n",
371 			    tudata.pk_flag&0xff, tudata.pk_op&0xff);
372 			mtpr(CSRS, 0);		/* flush the rest */
373 			tu.state = INIT1;
374 		}
375 		break;
376 
377 	case IDLE:
378 	case INIT1:
379 		break;
380 
381 	default:
382 		if (c == TUF_INITF) {
383 			printf("TU protocol error, state %d\n", tu.state);
384 			printf("%o %d %d\n",
385 			    tucmd.pk_op, tucmd.pk_count, tucmd.pk_block);
386 			tutab.b_active = NULL;
387 			if (bp = tutab.b_actf) {
388 				bp->b_flags |= B_ERROR;
389 				tutab.b_actf = bp->av_forw;
390 				iodone(bp);
391 			}
392 			tu.state = INIT1;
393 		} else {
394 			printf("TU receive state error %d %o\n", tu.state, c);
395 		/*	tu.state = INIT1; */
396 			wakeup((caddr_t)&tu);
397 		}
398 	}
399 }
400 
401 /*
402  * TU58 transmitter interrupt
403  */
404 tuxintr()
405 {
406 
407 top:
408 	if (tu.wcnt) {
409 		/* still stuff to send, send one byte */
410 		while ((mfpr(CSTS) & READY) == 0)
411 			;
412 		mtpr(CSTD, *tu.wbptr++);
413 		tu.wcnt--;
414 		return;
415 	}
416 
417 	/*
418 	 * Last message byte was sent out.
419 	 * Switch on state of transfer.
420 	 */
421 	printd("tuxintr: state %d\n", tu.state);
422 	switch(tu.state) {
423 
424 	case INIT1:		/* two nulls sent, remove break, send inits */
425 		mtpr(CSTS, IE);
426 		printd("ON2 ");
427 		tu.state = INIT2;
428 		tu.wbptr = tuinit;
429 		tu.wcnt = sizeof tuinit;
430 		goto top;
431 
432 	case INIT2:		/* inits sent, wait for continue */
433 		(void) mfpr(CSRD);
434 		mtpr(CSRS, IE);
435 		tu.flag = 1;
436 		break;
437 
438 	case IDLE:		/* stray interrupt? */
439 		break;
440 
441 	case SENDR:		/* read cmd packet sent, get ready for data */
442 		tu.state = GETH;
443 		tu.rbptr = (u_char *)&tudata;
444 		tu.rcnt = 2;
445 		tu.flag = 1;
446 		mtpr(CSTS, 0);	/* disable transmitter interrupts */
447 		printd("OFF ");
448 		break;
449 
450 	case SENDW:		/* write cmd packet sent, wait for continue */
451 		tu.state = WAIT;
452 		tu.flag = 1;
453 		if ((mfpr(CSRS)&IE) == 0) {
454 			printf("NO IE\n");
455 			mtpr(CSRS, IE);
456 		}
457 		break;
458 
459 	case SENDH:		/* header sent, send data */
460 		tu.state = SENDD;
461 		tu.wbptr = (u_char *)tu.addr;
462 		tu.wcnt = tudata.pk_mcount;
463 		goto top;
464 
465 	case SENDD:		/* data sent, send checksum */
466 		tu.state = SENDC;
467 		tu.wbptr = (u_char *)&tudata.pk_chksum;
468 		tu.wcnt = sizeof tudata.pk_chksum;
469 		goto top;
470 
471 	case SENDC:		/* checksum sent, wait for continue */
472 		tu.addr += tudata.pk_mcount;	/* update buffer address */
473 		tu.count -= tudata.pk_mcount;	/* and count */
474 		if (tu.count == 0) {		/* all done? */
475 			tu.state = GET;		/* set up to get end packet */
476 			tu.rbptr = (u_char *)&tudata;
477 			tu.rcnt = sizeof tudata;
478 			tu.flag = 1;
479 			mtpr(CSTS, 0);
480 			printd("OFF2 ");
481 		} else {
482 			tu.state = WAIT;	/* wait for continue */
483 			tu.flag = 1;
484 		}
485 		break;
486 
487 	default:	/* random interrupt, probably from MRSP ACK */
488 		break;
489 	}
490 	printd("  new state %d\n", tu.state);
491 }
492 
493 /*
494  * Compute checksum TU58 fashion
495  *
496  * *** WARNING ***
497  * This procedure is not in C because
498  * it has to be fast and it is hard to
499  * do add-carry in C.  Sorry.
500  */
501 tuchk(word0, wp, n)
502 	register int word0;	/* known to be r11 */
503 	register caddr_t wp;	/* known to be r10 */
504 	register int n;		/* known to be r9 */
505 {
506 #ifdef lint
507 	/* for some reason ARGSUSED doesn't work to quiet lint */
508 	word0 = 0; n = word0; word0 = n;
509 	wp = 0; wp = wp;
510 #endif
511 
512 	asm("loop:");
513 	asm("	addw2	(r10)+,r11");	/* add a word to sum */
514 	asm("	adwc	$0,r11");	/* add in carry, end-around */
515 	asm("	acbl	$2,$-2,r9,loop");	/* done yet? */
516 	asm("	blbc	r9,ok");	/* odd byte count? */
517 	asm("	movzbw	(r10),r10");	/* yes, get last byte */
518 	asm("	addw2	r10,r11");	/* add it in */
519 	asm("	adwc	$0,r11");	/* and the carry */
520 	asm("ok:");
521 	asm("	movl	r11,r0");	/* return sum */
522 #ifdef lint
523 	return (0);
524 #endif
525 }
526 
527 tuwatch()
528 {
529 	register int s;
530 	register struct buf *bp;
531 
532 	if (tutimer == 0) {
533 		tu.flag = 0;
534 		return;
535 	}
536 	if (tu.flag)
537 		tu.flag++;
538 	if (tu.flag > 40) {
539 		printf("tu: read stalled\n");
540 		printf("%X %X %X %X %X %X %X %X\n", tu.rbptr, tu.rcnt,
541 		tu.wbptr, tu.wcnt, tu.state, tu.flag, tu.addr, tu.count);
542 		tu.flag = 0;
543 		s = splx(TUIPL);
544 		(void) mfpr(CSRD);
545 		mtpr(CSRS, IE);		/* in case we were flushing */
546 		mtpr(CSTS, IE);
547 		tu.state = IDLE;
548 		if (tutab.b_active) {
549 			if (++tutab.b_errcnt > 1) {
550 				if (bp = tutab.b_actf) {
551 					bp->b_flags |= B_ERROR;
552 					iodone(bp);
553 				}
554 			} else
555 				tustart();
556 		} else
557 			wakeup((caddr_t)&tu);
558 		splx(s);
559 	}
560 	timeout(tuwatch, (caddr_t)0, hz);
561 }
562 #endif
563