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