date and time created 83/04/08 11:16:39 by helge
[unix-history] / usr / src / sys / vax / uba / uu.c
CommitLineData
2a6e4a22
HS
1/* tu.c 4.13 83/02/10 */
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/kernel.h"
24
25#include "../vax/cpu.h"
26#include "../vax/mtpr.h"
27
28#define printd if(tudebug) printf
29#ifdef printd
30int tudebug; /* printd */
31#endif printd
32
33#define NTU ((cpu == VAX_750) ? 1 : 2)
34#define DNUM 01 /* mask for drive number (should match NTU) */
35#if !defined(MRSP) || lint
36#define MRSP (cpu != VAX_750)
37#endif
38#define NTUBLK 512 /* number of blocks on a TU58 cassette */
39#define WRV 02 /* bit in minor dev => write w. read verify */
40#define NTUQ 2 /* # of blocks which can be queued up */
41#define TUIPL ((cpu == VAX_750) ? 0x17 : 0x14)
42
43/*
44 * Device register bits
45 */
46#define READY 0200 /* transmitter ready */
47#define DONE 0200 /* receiver done */
48#define IE 0100 /* interrupt enable */
49#define BREAK 1 /* send break */
50
51/*
52 * Structure of a command packet
53 */
54struct packet {
55 u_char pk_flag; /* indicates packet type (cmd, data, etc.) */
56 u_char pk_mcount; /* length of packet (bytes) */
57 u_char pk_op; /* operation to perform (read, write, etc.) */
58 u_char pk_mod; /* modifier for op or returned status */
59 u_char pk_unit; /* unit number */
60 u_char pk_sw; /* switches */
61 u_short pk_seq; /* sequence number, always zero */
62 u_short pk_count; /* requested byte count for read or write */
63 u_short pk_block; /* block number for read, write, or seek */
64 u_short pk_chksum; /* checksum, by words with end around carry */
65};
66
67struct packet tucmd; /* a command sent to the TU58 */
68struct packet tudata; /* a command or data returned from TU58 */
69
70/*
71 * State information
72 */
73struct tu {
74 u_char *tu_rbptr; /* pointer to buffer for read */
75 int tu_rcnt; /* how much to read */
76 u_char *tu_wbptr; /* pointer to buffer for write */
77 int tu_wcnt; /* how much to write */
78 int tu_state; /* current tu_state of tansfer operation */
79 int tu_flag; /* read in progress flag */
80 char *tu_addr; /* real buffer data address */
81 int tu_count; /* real requested count */
82 int tu_serrs; /* count of soft errors */
83 int tu_cerrs; /* count of checksum errors */
84 int tu_herrs; /* count of hard errors */
85 char tu_dopen[2]; /* drive is open */
86} tu;
87
88/*
89 * States
90 */
91#define TUS_INIT1 0 /* sending nulls */
92#define TUS_INIT2 1 /* sending inits */
93#define TUS_IDLE 2 /* initialized, no transfer in progress */
94#define TUS_SENDH 3 /* sending header */
95#define TUS_SENDD 4 /* sending data */
96#define TUS_SENDC 5 /* sending checksum */
97#define TUS_SENDR 6 /* sending read command packet */
98#define TUS_SENDW 7 /* sending write command packet */
99#define TUS_GETH 8 /* reading header */
100#define TUS_GETD 9 /* reading data */
101#define TUS_GETC 10 /* reading checksum */
102#define TUS_GET 11 /* reading an entire packet */
103#define TUS_WAIT 12 /* waiting for continue */
104
105#define TUS_NSTATES 13
106char *tustates[TUS_NSTATES] = {
107 "INIT1", "INIT2", "IDLE", "SENDH", "SENDD", "SENDC", "SENDR",
108 "SENDW", "GETH", "GETD", "GETC", "GET", "WAIT"
109};
110#define printstate(state) \
111 if ((state) < TUS_NSTATES) \
112 printf("%s", tustates[(state)]); \
113 else \
114 printf("%d", (state));
115
116/*
117 * Packet Flags
118 */
119#define TUF_DATA 1 /* data packet */
120#define TUF_CMD 2 /* command packet */
121#define TUF_INITF 4 /* initialize */
122#define TUF_CONT 020 /* continue */
123#define TUF_XOFF 023 /* flow control */
124
125/*
126 * Op Codes
127 */
128#define TUOP_INIT 1 /* initialize */
129#define TUOP_READ 2 /* read block */
130#define TUOP_WRITE 3 /* write block */
131#define TUOP_SEEK 5 /* seek to block */
132#define TUOP_DIAGNOSE 7 /* run micro-diagnostics */
133#define TUOP_END 0100 /* end packet */
134
135/*
136 * Mod Flags
137 */
138#define TUMD_WRV 1 /* write with read verify */
139
140/*
141 * Switches
142 */
143#define TUSW_MRSP 010 /* use Modified RSP */
144
145u_char tunull[2] = { 0, 0 }; /* nulls to send for initialization */
146u_char tuinit[2] = { TUF_INITF, TUF_INITF }; /* inits to send */
147static char pcnt[2]; /* pee/vee counters */
148int tutimer = 0;
149struct buf tutab; /* I/O queue header */
150
151/*
152 * Open the TU58
153 */
154/*ARGSUSED*/
155tuopen(dev, flag)
156{
157 extern int tuwatch();
158 register s;
159
160#ifdef lint
161 turintr(); tuwintr();
162#endif
163 if ((minor(dev)&DNUM) >= NTU || tu.tu_dopen[minor(dev)&DNUM])
164 return (ENXIO);
165 if (tutimer == 0) {
166 tutimer++;
167 timeout(tuwatch, (caddr_t)0, hz);
168 }
169 tu.tu_dopen[minor(dev)&DNUM]++;
170 s = splx(TUIPL);
171 /*
172 * If the cassette's already initialized,
173 * just enable interrupts and return.
174 */
175 if (tu.tu_state == TUS_IDLE) {
176 mtpr(CSRS, IE);
177 splx(s);
178 return (0);
179 }
180
181 /*
182 * Must initialize, reset the cassette
183 * and wait for things to settle down.
184 */
185 tureset();
186 sleep((caddr_t)&tu, PZERO+1);
187 tutab.b_active = NULL;
188 if (tu.tu_state != TUS_IDLE) {
189 u.u_error = ENXIO;
190 tu.tu_state = TUS_INIT1;
191 tu.tu_dopen[minor(dev)&DNUM] = 0;
192 tu.tu_rcnt = tu.tu_wcnt = 0;
193 mtpr(CSTS, 0);
194 mtpr(CSRS, 0);
195 }
196 splx(s);
197 return (0);
198}
199
200/*
201 * Close the TU58
202 */
203tuclose(dev)
204{
205
206 if (tutab.b_active == 0) {
207 mtpr(CSRS, 0);
208 tutimer = 0;
209 }
210 if (tu.tu_serrs + tu.tu_cerrs + tu.tu_herrs != 0) {
211 /*
212 * A tu58 is like nothing ever seen before;
213 * I guess this is appropriate then...
214 */
215 uprintf(
216 "tu%d: %d soft errors, %d chksum errors, %d hard errors\n",
217 minor(dev), tu.tu_serrs, tu.tu_cerrs, tu.tu_herrs);
218 tu.tu_serrs = tu.tu_cerrs = tu.tu_herrs = 0;
219 }
220 tu.tu_dopen[minor(dev)&DNUM] = 0;
221}
222
223/*
224 * Reset the TU58
225 */
226tureset()
227{
228
229 tu.tu_state = TUS_INIT1;
230 tu.tu_wbptr = tunull;
231 tu.tu_wcnt = sizeof (tunull);
232 tucmd.pk_flag = TUF_CMD;
233 tucmd.pk_mcount = sizeof (tucmd) - 4;
234 tucmd.pk_mod = 0;
235 tucmd.pk_seq = 0;
236 tucmd.pk_sw = MRSP ? TUSW_MRSP : 0;
237 tutab.b_active++;
238 mtpr(CSRS, 0);
239 mtpr(CSTS, IE|BREAK);
240 tuxintr(); /* start output */
241}
242
243/*
244 * Strategy routine for block I/O
245 */
246tustrategy(bp)
247 register struct buf *bp;
248{
249 register int s;
250
251 if (bp->b_blkno >= NTUBLK) {
252 bp->b_flags |= B_ERROR;
253 iodone(bp);
254 return;
255 }
256 if ((bp->b_flags&B_READ) == 0)
257 tu_pee(&pcnt[minor(bp->b_dev)&DNUM]);
258 bp->av_forw = NULL;
259 s = splx(TUIPL);
260 if (tutab.b_actf == NULL)
261 tutab.b_actf = bp;
262 else
263 tutab.b_actl->av_forw = bp;
264 tutab.b_actl = bp;
265 if (tutab.b_active == NULL)
266 tustart();
267 splx(s);
268}
269
270/*
271 * Start the transfer
272 */
273tustart()
274{
275 register struct buf *bp;
276
277 if ((bp = tutab.b_actf) == NULL)
278 return;
279 if (tu.tu_state != TUS_IDLE) {
280 tureset();
281 return;
282 }
283 tutab.b_active++;
284 tutab.b_errcnt = 0;
285 tucmd.pk_op = bp->b_flags&B_READ ? TUOP_READ : TUOP_WRITE;
286 tucmd.pk_mod = ((bp->b_flags&B_READ) == 0 && (minor(bp->b_dev)&WRV)) ?
287 TUMD_WRV : 0;
288 tucmd.pk_unit = (minor(bp->b_dev)&DNUM);
289 tucmd.pk_sw = MRSP ? TUSW_MRSP : 0;
290 tucmd.pk_count = tu.tu_count = bp->b_bcount;
291 tucmd.pk_block = bp->b_blkno;
292 tucmd.pk_chksum =
293 tuchk(*((short *)&tucmd), (u_short *)&tucmd.pk_op,
294 (int)tucmd.pk_mcount);
295 tu.tu_state = bp->b_flags&B_READ ? TUS_SENDR : TUS_SENDW;
296 tu.tu_addr = bp->b_un.b_addr;
297 tu.tu_count = bp->b_bcount;
298 tu.tu_wbptr = (u_char *)&tucmd;
299 tu.tu_wcnt = sizeof (tucmd);
300 tuxintr();
301}
302
303/*
304 * TU58 receiver interrupt
305 */
306turintr()
307{
308 register struct buf *bp;
309 register int c;
310
311 c = mfpr(CSRD)&0xff; /* get the char, clear the interrupt */
312 if (MRSP) {
313 while ((mfpr(CSTS)&READY) == 0)
314 ;
315 mtpr(CSTD, TUF_CONT); /* ACK */
316 }
317 if (tu.tu_rcnt) { /* still waiting for data? */
318 *tu.tu_rbptr++ = c; /* yup, put it there */
319 if (--tu.tu_rcnt) /* decrement count, any left? */
320 return; /* get some more */
321 }
322
323 /*
324 * We got all the data we were expecting for now,
325 * switch on the tu_state of the transfer.
326 */
327 switch(tu.tu_state) {
328
329 /*
330 * If we get an unexpected "continue",
331 * start all over again...
332 */
333 case TUS_INIT2:
334 tu.tu_state = c == TUF_CONT ? TUS_IDLE : TUS_INIT1;
335 tu.tu_flag = 0;
336 wakeup((caddr_t)&tu);
337 tustart();
338 break;
339
340 /*
341 * Only transition from this state
342 * is on a "continue", so if we don't
343 * get it, reset the world.
344 */
345 case TUS_WAIT: /* waiting for continue */
346 if (c != TUF_CONT) {
347 tu.tu_state = TUS_INIT1;
348 break;
349 }
350 tu.tu_flag = 0;
351 tudata.pk_flag = TUF_DATA;
352 tudata.pk_mcount = MIN(128, tu.tu_count);
353 tudata.pk_chksum =
354 tuchk(*((short *)&tudata), (u_short *)tu.tu_addr,
355 (int)tudata.pk_mcount);
356 tu.tu_state = TUS_SENDH;
357 tu.tu_wbptr = (u_char *)&tudata;
358 tu.tu_wcnt = 2;
359 tuxintr();
360 break;
361
362 case TUS_SENDW:
363 if (c != TUF_CONT)
364 goto bad;
365 tureset();
366 break;
367
368 /*
369 * Got header, now get data; amount to
370 * fetch is include in packet.
371 */
372 case TUS_GETH:
373 if (tudata.pk_flag == TUF_DATA)
374 tu.tu_rbptr = (u_char *)tu.tu_addr;
375 tu.tu_rcnt = tudata.pk_mcount;
376 tu.tu_state = TUS_GETD;
377 break;
378
379 /*
380 * Got the data, now fetch the checksum.
381 */
382 case TUS_GETD:
383 tu.tu_rbptr = (u_char *)&tudata.pk_chksum;
384 tu.tu_rcnt = sizeof (tudata.pk_chksum);
385 tu.tu_state = TUS_GETC;
386 break;
387
388 case TUS_GET:
389 case TUS_GETC:
390 /* got entire packet */
391#ifdef notdef
392 if (tudata.pk_chksum !=
393 tuchk(*((short *)&tudata), (u_short *)
394 (tudata.pk_flag == TUF_DATA ? tu.tu_addr : &tudata.pk_op),
395 (int)tudata.pk_mcount))
396 tu.tu_cerrs++;
397#endif
398 if (tudata.pk_flag == TUF_DATA) {
399 /* data packet, advance to next */
400 tu.tu_addr += tudata.pk_mcount;
401 tu.tu_count -= tudata.pk_mcount;
402 tu.tu_state = TUS_GETH;
403 tu.tu_rbptr = (u_char *)&tudata; /* next packet */
404 tu.tu_rcnt = 2;
405 } else if (tudata.pk_flag==TUF_CMD && tudata.pk_op==TUOP_END) {
406 /* end packet, idle and reenable transmitter */
407 tu.tu_state = TUS_IDLE;
408 tu.tu_flag = 0;
409 mtpr(CSTS, IE);
410 printd("ON ");
411 if ((bp = tutab.b_actf) == NULL) {
412 printf("tu: no bp, active %d\n",tutab.b_active);
413 tustart();
414 return;
415 }
416 if (tudata.pk_mod > 1) { /* hard error */
417 bp->b_flags |= B_ERROR;
418 tu.tu_herrs++;
419 harderr(bp, "tu");
420 printf(" pk_mod %o\n", tudata.pk_mod&0377);
421 } else if (tudata.pk_mod != 0) /* soft error */
422 tu.tu_serrs++;
423 tutab.b_active = NULL;
424 tutab.b_actf = bp->av_forw;
425 bp->b_resid = tu.tu_count;
426 if ((bp->b_flags&B_READ) == 0)
427 tu_vee(&pcnt[minor(bp->b_dev)&DNUM]);
428 iodone(bp);
429 tustart();
430 } else {
431 printf("neither data nor end: %o %o\n",
432 tudata.pk_flag&0xff, tudata.pk_op&0xff);
433 mtpr(CSRS, 0); /* flush the rest */
434 tu.tu_state = TUS_INIT1;
435 }
436 break;
437
438 case TUS_IDLE:
439 case TUS_INIT1:
440 break;
441
442 default:
443bad:
444 if (c == TUF_INITF) {
445 printf("tu protocol error, state=");
446 printstate(tu.tu_state);
447 printf(", op=%x, cnt=%d, block=%d\n",
448 tucmd.pk_op, tucmd.pk_count, tucmd.pk_block);
449 tutab.b_active = NULL;
450 if (bp = tutab.b_actf) {
451 bp->b_flags |= B_ERROR;
452 tutab.b_actf = bp->av_forw;
453 if ((bp->b_flags&B_READ) == 0)
454 tu_vee(&pcnt[minor(bp->b_dev)&DNUM]);
455 iodone(bp);
456 }
457 tu.tu_state = TUS_INIT1;
458 } else {
459 printf("tu receive state error, state=");
460 printf(", byte=%x\n", c);
461#ifdef notdef
462 tu.tu_state = TUS_INIT1; */
463#endif
464 wakeup((caddr_t)&tu);
465 }
466 }
467}
468
469/*
470 * TU58 transmitter interrupt
471 */
472tuxintr()
473{
474
475top:
476 if (tu.tu_wcnt) {
477 /* still stuff to send, send one byte */
478 while ((mfpr(CSTS) & READY) == 0)
479 ;
480 mtpr(CSTD, *tu.tu_wbptr++);
481 tu.tu_wcnt--;
482 return;
483 }
484
485 /*
486 * Last message byte was sent out.
487 * Switch on tu_state of transfer.
488 */
489 if (tudebug) {
490 printf("tuxintr: state=");
491 printstate(tu.tu_state);
492 }
493 switch(tu.tu_state) {
494
495 /*
496 * Two nulls have been sent, remove break, and send inits
497 */
498 case TUS_INIT1:
499 mtpr(CSTS, IE);
500 printd("ON2 ");
501 tu.tu_state = TUS_INIT2;
502 tu.tu_wbptr = tuinit;
503 tu.tu_wcnt = sizeof (tuinit);
504 goto top;
505
506 /*
507 * Inits have been sent, wait for a continue msg.
508 */
509 case TUS_INIT2:
510 (void) mfpr(CSRD);
511 mtpr(CSRS, IE);
512 tu.tu_flag = 1;
513 break;
514
515 case TUS_IDLE: /* stray interrupt? */
516 break;
517
518 /*
519 * Read cmd packet sent, get ready for data
520 */
521 case TUS_SENDR:
522 tu.tu_state = TUS_GETH;
523 tu.tu_rbptr = (u_char *)&tudata;
524 tu.tu_rcnt = 2;
525 tu.tu_flag = 1;
526 mtpr(CSTS, 0); /* disable transmitter interrupts */
527 printd("OFF ");
528 break;
529
530 /*
531 * Write cmd packet sent, wait for continue
532 */
533 case TUS_SENDW:
534 tu.tu_state = TUS_WAIT;
535 tu.tu_flag = 1;
536 if ((mfpr(CSRS)&IE) == 0) {
537 printf("NO IE\n");
538 mtpr(CSRS, IE);
539 }
540 break;
541
542 /*
543 * Header sent, send data.
544 */
545 case TUS_SENDH:
546 tu.tu_state = TUS_SENDD;
547 tu.tu_wbptr = (u_char *)tu.tu_addr;
548 tu.tu_wcnt = tudata.pk_mcount;
549 goto top;
550
551 /*
552 * Data sent, follow with checksum.
553 */
554 case TUS_SENDD:
555 tu.tu_state = TUS_SENDC;
556 tu.tu_wbptr = (u_char *)&tudata.pk_chksum;
557 tu.tu_wcnt = sizeof tudata.pk_chksum;
558 goto top;
559
560 /*
561 * Checksum sent, wait for continue.
562 */
563 case TUS_SENDC:
564 /*
565 * Updata buffer address and count.
566 */
567 tu.tu_addr += tudata.pk_mcount;
568 tu.tu_count -= tudata.pk_mcount;
569 if (tu.tu_count) {
570 tu.tu_state = TUS_WAIT;
571 tu.tu_flag = 1;
572 break;
573 }
574
575 /*
576 * End of transmission, get ready for end packet.
577 */
578 tu.tu_state = TUS_GET;
579 tu.tu_rbptr = (u_char *)&tudata;
580 tu.tu_rcnt = sizeof (tudata);
581 tu.tu_flag = 1;
582 mtpr(CSTS, 0);
583 printd("OFF2 ");
584 break;
585
586 /*
587 * Random interrupt, probably from MRSP ACK
588 */
589 default:
590 break;
591 }
592 if (tudebug) {
593 printd(" new tu_state=");
594 printstate(tu.tu_state);
595 }
596}
597
598/*
599 * Compute checksum TU58 fashion
600 */
601#ifdef lint
602tuchk(word, cp, n)
603 register word;
604 register unsigned short *cp;
605 int n;
606{
607 register int c = n >> 1;
608 register long temp;
609
610 do {
611 temp = *cp++; /* temp, only because vax cc won't *r++ */
612 word += temp;
613 } while (--c > 0);
614 if (n & 1)
615 word += *(unsigned char *)cp;
616 while (word & 0xffff0000)
617 word = (word & 0xffff) + ((word >> 16) & 0xffff);
618 return (word);
619}
620#else
621tuchk(word0, wp, n)
622 register int word0; /* r11 */
623 register char *wp; /* r10 */
624 register int n; /* r9 */
625{
626 asm("loop:");
627 asm(" addw2 (r10)+,r11"); /* add a word to sum */
628 asm(" adwc $0,r11"); /* add in carry, end-around */
629 asm(" acbl $2,$-2,r9,loop"); /* done yet? */
630 asm(" blbc r9,ok"); /* odd byte count? */
631 asm(" movzbw (r10),r10"); /* yes, get last byte */
632 asm(" addw2 r10,r11"); /* add it in */
633 asm(" adwc $0,r11"); /* and the carry */
634 asm("ok:");
635 asm(" movl r11,r0"); /* return sum */
636}
637#endif
638
639tuwatch()
640{
641 register int s;
642 register struct buf *bp;
643
644 if (tutimer == 0) {
645 tu.tu_flag = 0;
646 return;
647 }
648 if (tu.tu_flag)
649 tu.tu_flag++;
650 if (tu.tu_flag <= 40) {
651 timeout(tuwatch, (caddr_t)0, hz);
652 return;
653 }
654 printf("tu: read stalled\n");
655 printf("%X %X %X %X %X %X %X %X\n", tu.tu_rbptr, tu.tu_rcnt,
656 tu.tu_wbptr, tu.tu_wcnt, tu.tu_state, tu.tu_flag,
657 tu.tu_addr, tu.tu_count);
658 tu.tu_flag = 0;
659 s = splx(TUIPL);
660 (void) mfpr(CSRD);
661 mtpr(CSRS, IE); /* in case we were flushing */
662 mtpr(CSTS, IE);
663 tu.tu_state = TUS_IDLE;
664 if (!tutab.b_active) {
665 wakeup((caddr_t)&tu);
666 goto retry;
667 }
668 if (++tutab.b_errcnt <= 1) {
669 tustart();
670 goto retry;
671 }
672 if (bp = tutab.b_actf) {
673 bp->b_flags |= B_ERROR;
674 if ((bp->b_flags&B_READ) == 0)
675 tu_vee(&pcnt[minor(bp->b_dev)&DNUM]);
676 iodone(bp);
677 }
678retry:
679 splx(s);
680 timeout(tuwatch, (caddr_t)0, hz);
681}
682
683tu_pee(cp)
684 char *cp;
685{
686 register int s;
687
688 s = splx(TUIPL);
689 if (++(*cp) > NTUQ)
690 sleep(cp, PRIBIO);
691 splx(s);
692}
693
694tu_vee(cp)
695 char *cp;
696{
697 register int s;
698
699 s = splx(TUIPL);
700 if (--(*cp) <= NTUQ)
701 wakeup(cp);
702 splx(s);
703}
704#endif