|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: *
6: * @(#)tu.c 7.4 (Berkeley) 4/12/90
7: */
8:
9: #if defined(VAX750) || defined(VAX730)
10: /*
11: * TU58 DECtape II device driver
12: *
13: * TU58 console cassette driver (for VAX-11/750 or VAX-11/730).
14: * The TU58 is treated as a block device (only). Error detection and
15: * recovery is not extensive, but sufficient for most situations. It is
16: * assumed that the TU58 will follow the RSP (or MRSP) protocol exactly,
17: * very few protocol errors are checked for. It is also assumed that
18: * the 730 uses Modified RSP (MRSP), while the 750 may use either RSP
19: * or MRSP depending on whether defined(MRSP) is true or not.
20: * In the case of a 750 without MRSP, the only way for the CPU to
21: * keep up with the tu58 is to lock out virtually everything else.
22: *
23: * NOTE: Reading large amounts of data from the tu58 is likely
24: * to crash your system if you are running multiuser.
25: * ******FOR SINGLE USER USE ONLY*****
26: */
27: #include "param.h"
28: #include "systm.h"
29: #include "buf.h"
30: #include "conf.h"
31: #include "user.h"
32: #include "kernel.h"
33:
34: #include "cpu.h"
35: #include "mtpr.h"
36: #include "rsp.h"
37:
38: #define printd if(tudebug) printf
39: #ifdef printd
40: int tudebug; /* printd */
41: #endif printd
42:
43: #define NTU ((cpu == VAX_750) ? 1 : 2)
44: #define DNUM 01 /* mask for drive number (should match NTU) */
45: #define NTUBLK 512 /* number of blocks on a TU58 cassette */
46: #define WRV 02 /* bit in minor dev => write w. read verify */
47: #define NTUQ 2 /* # of blocks which can be queued up */
48: #define spltu() ((cpu == VAX_750) ? spl7() : spl4())
49:
50: #ifndef MRSP
51: #define MRSP (cpu != VAX_750)
52: #endif
53:
54: /*
55: * State information
56: */
57: struct tu {
58: u_char *tu_rbptr; /* pointer to buffer for read */
59: int tu_rcnt; /* how much to read */
60: u_char *tu_wbptr; /* pointer to buffer for write */
61: int tu_wcnt; /* how much to write */
62: int tu_state; /* current state of tansfer operation */
63: int tu_flag; /* read in progress flag */
64: char *tu_addr; /* real buffer data address */
65: int tu_count; /* real requested count */
66: int tu_serrs; /* count of soft errors */
67: int tu_cerrs; /* count of checksum errors */
68: int tu_herrs; /* count of hard errors */
69: char tu_dopen[2]; /* drive is open */
70: } tu;
71:
72:
73: /*
74: * Device register bits
75: */
76: #define READY 0200 /* transmitter ready */
77: #define DONE 0200 /* receiver done */
78: #define IE 0100 /* interrupt enable */
79: #define BREAK 1 /* send break */
80:
81: struct packet tucmd; /* a command sent to the TU58 */
82: struct packet tudata; /* a command or data returned from TU58 */
83:
84: char *tustates[TUS_NSTATES] = {
85: "INIT1", "INIT2", "IDLE", "SENDH", "SENDD", "SENDC", "SENDR",
86: "SENDW", "GETH", "GETD", "GETC", "GET", "WAIT", "RCVERR", "CHKERR"
87: };
88:
89: u_char tunull[2] = { 0, 0 }; /* nulls to send for initialization */
90: u_char tuinit[2] = { TUF_INITF, TUF_INITF }; /* inits to send */
91: static char tu_pcnt[2]; /* pee/vee counters */
92: int tutimer = 0;
93: int tuwake();
94: struct buf tutab; /* I/O queue header */
95:
96: /*
97: * Open the TU58
98: */
99: /*ARGSUSED*/
100: tuopen(dev, flag)
101: {
102: extern int tuwatch();
103: register s;
104: int error;
105:
106: #ifdef lint
107: turintr(); tuwintr();
108: #endif
109: if ((minor(dev)&DNUM) >= NTU)
110: return (ENXIO);
111: if (tu.tu_dopen[minor(dev)&DNUM])
112: return (EBUSY);
113: if (tutimer++ == 0)
114: timeout(tuwatch, (caddr_t)0, hz);
115:
116: s = spltu();
117: tu.tu_dopen[minor(dev)&DNUM]++;
118: /*
119: * If the cassette's already initialized,
120: * just enable interrupts and return.
121: */
122: if (tu.tu_state == TUS_IDLE) {
123: mtpr(CSRS, IE);
124: goto ok;
125: }
126:
127: /*
128: * Must initialize, reset the cassette
129: * and wait for things to settle down.
130: */
131: tureset();
132: if (error = tsleep((caddr_t)&tu, (PZERO + 1) | PCATCH,
133: devopn, 0)) {
134: splx(s);
135: return (error);
136: }
137: tutab.b_active = NULL;
138: if (tu.tu_state != TUS_IDLE) {
139: tu.tu_state = TUS_INIT1;
140: tu.tu_dopen[minor(dev)&DNUM] = 0;
141: tu.tu_rcnt = tu.tu_wcnt = 0;
142: mtpr(CSTS, 0);
143: mtpr(CSRS, 0);
144: splx(s);
145: return (EIO);
146: }
147: ok:
148: splx(s);
149: return (0);
150: }
151:
152: /*
153: * Close the TU58, but make sure all
154: * outstanding i/o is complete first..
155: */
156: /* ARGSUSED */
157: tuclose(dev, flag)
158: dev_t dev;
159: int flag;
160: {
161: int s, unit = minor(dev);
162: struct buf *bp, *last = NULL;
163:
164: s = spltu();
165: while (tu_pcnt[unit])
166: sleep(&tu_pcnt[unit], PRIBIO);
167: /*
168: * No more writes are pending, scan the
169: * buffer queue for oustanding reads from
170: * this unit.
171: */
172: for (bp = tutab.b_actf; bp; bp = bp->b_actf) {
173: if (bp->b_dev == dev)
174: last = bp;
175: }
176: if (last) {
177: last->b_flags |= B_CALL;
178: last->b_iodone = tuwake;
179: sleep((caddr_t)last, PRIBIO);
180: }
181: tu.tu_dopen[unit&DNUM] = 0;
182: if (!tu.tu_dopen[0] && !tu.tu_dopen[1]) {
183: tutimer = 0;
184: mtpr(CSRS, 0);
185: tu.tu_flag = 0;
186: }
187: splx(s);
188: }
189:
190: tuwake(bp)
191: struct buf *bp;
192: {
193: wakeup((caddr_t)bp);
194: }
195:
196: /*
197: * Reset the TU58
198: */
199: tureset()
200: {
201:
202: mtpr(CSRS, 0);
203: tu.tu_state = TUS_INIT1;
204: tu.tu_wbptr = tunull;
205: tu.tu_wcnt = sizeof (tunull);
206: tucmd.pk_flag = TUF_CMD;
207: tucmd.pk_mcount = sizeof (tucmd) - 4;
208: tucmd.pk_mod = 0;
209: tucmd.pk_seq = 0;
210: tucmd.pk_sw = MRSP ? TUSW_MRSP : 0;
211: tutab.b_active++;
212: mtpr(CSTS, IE | BREAK);
213: tuxintr(); /* start output */
214: }
215:
216: /*
217: * Strategy routine for block I/O
218: */
219: tustrategy(bp)
220: register struct buf *bp;
221: {
222: register int s;
223:
224: if (bp->b_blkno >= NTUBLK) {
225: bp->b_flags |= B_ERROR;
226: iodone(bp);
227: return;
228: }
229: if ((bp->b_flags&B_READ) == 0)
230: tu_pee(&tu_pcnt[minor(bp->b_dev)&DNUM]);
231: bp->av_forw = NULL;
232: s = spltu();
233: if (tutab.b_actf == NULL)
234: tutab.b_actf = bp;
235: else
236: tutab.b_actl->av_forw = bp;
237: tutab.b_actl = bp;
238: if (tutab.b_active == NULL)
239: tustart();
240: splx(s);
241: }
242:
243: /*
244: * Start the transfer
245: */
246: tustart()
247: {
248: register struct buf *bp;
249: int s;
250:
251: if ((bp = tutab.b_actf) == NULL)
252: return;
253: s = spltu();
254: if (tu.tu_state != TUS_IDLE) {
255: tureset();
256: splx(s);
257: return;
258: }
259: tutab.b_active++;
260: tutab.b_errcnt = 0;
261: tucmd.pk_op = bp->b_flags&B_READ ? TUOP_READ : TUOP_WRITE;
262: tucmd.pk_mod = ((bp->b_flags&B_READ) == 0 && (minor(bp->b_dev)&WRV)) ?
263: TUMD_WRV : 0;
264: tucmd.pk_unit = (minor(bp->b_dev)&DNUM);
265: tucmd.pk_sw = MRSP ? TUSW_MRSP : 0;
266: tucmd.pk_count = tu.tu_count = bp->b_bcount;
267: tucmd.pk_block = bp->b_blkno;
268: tucmd.pk_chksum =
269: tuchk(*((short *)&tucmd), (u_short *)&tucmd.pk_op,
270: (int)tucmd.pk_mcount);
271: tu.tu_state = bp->b_flags&B_READ ? TUS_SENDR : TUS_SENDW;
272: tu.tu_addr = bp->b_un.b_addr;
273: tu.tu_wbptr = (u_char *)&tucmd;
274: tu.tu_wcnt = sizeof (tucmd);
275: tuxintr();
276: splx(s);
277: }
278:
279: /*
280: * TU58 receiver interrupt
281: */
282: turintr()
283: {
284: register struct buf *bp;
285: register int c;
286:
287: c = mfpr(CSRD)&0xff;
288: if (MRSP) {
289: while ((mfpr(CSTS)&READY) == 0)
290: ;
291: mtpr(CSTD, TUF_CONT); /* ACK */
292: if (tu.tu_rcnt) {
293: *tu.tu_rbptr++ = c;
294: if (--tu.tu_rcnt)
295: return;
296: }
297: }
298:
299: /*
300: * Switch on the state of the transfer.
301: */
302: switch(tu.tu_state) {
303:
304: /*
305: * Probably an overrun error,
306: * cannot happen if MRSP is used
307: */
308: case TUS_RCVERR:
309: mtpr(CSRS, 0); /* flush */
310: printf("overrun error, transfer restarted\n"); /* DEBUG */
311: tu.tu_serrs++;
312: tu_restart();
313: break;
314:
315: /*
316: * If we get an unexpected "continue",
317: * start all over again...
318: */
319: case TUS_INIT2:
320: tu.tu_state = c == TUF_CONT ? TUS_IDLE : TUS_INIT1;
321: tu.tu_flag = 0;
322: wakeup((caddr_t)&tu);
323: tustart();
324: break;
325:
326: /*
327: * Only transition from this state
328: * is on a "continue", so if we don't
329: * get it, reset the world.
330: */
331: case TUS_WAIT: /* waiting for continue */
332: switch(c) {
333: case TUF_CONT: /* got the expected continue */
334: tu.tu_flag = 0;
335: tudata.pk_flag = TUF_DATA;
336: tudata.pk_mcount = MIN(128, tu.tu_count);
337: tudata.pk_chksum =
338: tuchk(*((short *)&tudata), (u_short *)tu.tu_addr,
339: (int)tudata.pk_mcount);
340: tu.tu_state = TUS_SENDH;
341: tu.tu_wbptr = (u_char *)&tudata;
342: tu.tu_wcnt = 2;
343: tuxintr();
344: break;
345:
346: case TUF_CMD: /* sending us an END packet...error */
347: tu.tu_state = TUS_GET;
348: tu.tu_rbptr = (u_char *) &tudata;
349: tu.tu_rcnt = sizeof (tudata) - 1;
350: tu.tu_flag = 1;
351: mtpr (CSTS, 0);
352: *tu.tu_rbptr = c;
353: break;
354:
355: case TUF_INITF:
356: tureset();
357: break;
358:
359: default: /* something random...bad news */
360: tu.tu_state = TUS_INIT1;
361: break;
362: }
363: break;
364:
365: case TUS_SENDW:
366: if (c != TUF_CONT && c != TUF_INITF)
367: goto bad;
368: tureset();
369: break;
370:
371: /*
372: * Got header, now get data; amount to
373: * fetch is included in packet.
374: */
375: case TUS_GETH:
376: if (MRSP && (tudata.pk_flag == TUF_DATA))
377: tu.tu_rbptr = (u_char *)tu.tu_addr;
378: tu.tu_rcnt = tudata.pk_mcount;
379: tu.tu_state = TUS_GETD;
380: break;
381:
382: /*
383: * Got the data, now fetch the checksum.
384: */
385: case TUS_GETD:
386: tu.tu_rbptr = (u_char *)&tudata.pk_chksum;
387: tu.tu_rcnt = sizeof (tudata.pk_chksum);
388: tu.tu_state = TUS_GETC;
389: break;
390:
391: case TUS_CHKERR: /* from tudma only */
392: tu.tu_cerrs++;
393: goto tus_get;
394:
395: case TUS_GET:
396: if (MRSP)
397: /*
398: * The checksum has already been calculated and
399: * verified in the pseudo DMA routine
400: */
401: goto tus_get;
402:
403: case TUS_GETC:
404: /* got entire packet */
405: if (tudata.pk_chksum !=
406: tuchk(*((short *)&tudata), (u_short *)
407: (tudata.pk_flag == TUF_DATA ?
408: (u_short *) tu.tu_addr : (u_short *)&tudata.pk_op),
409: (int)tudata.pk_mcount))
410: tu.tu_cerrs++;
411: tus_get:
412: if (tudata.pk_flag == TUF_DATA) {
413: /* data packet, advance to next */
414: tu.tu_addr += tudata.pk_mcount;
415: tu.tu_count -= tudata.pk_mcount;
416: tu.tu_state = TUS_GETH;
417: tu.tu_rbptr = (u_char *)&tudata; /* next packet */
418: tu.tu_rcnt = 2;
419: } else if (tudata.pk_flag==TUF_CMD && tudata.pk_op==TUOP_END) {
420: /* end packet, idle and reenable transmitter */
421: tu.tu_state = TUS_IDLE;
422: tu.tu_flag = 0;
423: mtpr(CSTS, IE);
424: printd("ON ");
425: if ((bp = tutab.b_actf) == NULL) {
426: printf("tu%d: no bp, active %d\n",
427: tudata.pk_unit, tutab.b_active);
428: tustart();
429: return;
430: }
431: if (tudata.pk_mod > 1) { /* hard error */
432: bp->b_flags |= B_ERROR;
433: tu.tu_herrs++;
434: printf("tu%d: hard error bn%d,",
435: minor(bp->b_dev)&DNUM, bp->b_blkno);
436: printf(" pk_mod %o\n", tudata.pk_mod&0377);
437: } else if (tudata.pk_mod != 0) /* soft error */
438: tu.tu_serrs++;
439: tutab.b_active = NULL;
440: tutab.b_actf = bp->av_forw;
441: bp->b_resid = tu.tu_count;
442: if ((bp->b_flags&B_READ) == 0)
443: tu_vee(&tu_pcnt[minor(bp->b_dev)&DNUM]);
444: iodone(bp);
445: tustart();
446: } else {
447: /*
448: * Neither data nor end: data was lost
449: * somehow, restart the transfer
450: */
451: mtpr(CSRS, 0); /* flush the rest */
452: tu_restart();
453: tu.tu_serrs++;
454: }
455: break;
456:
457: case TUS_IDLE:
458: case TUS_INIT1:
459: break;
460:
461: default:
462: bad:
463: if (c == TUF_INITF) {
464: printf("tu%d protocol error, state=",
465: (int)tudata.pk_unit);
466: printstate(tu.tu_state);
467: printf(", op=%x, cnt=%d, block=%d\n",
468: tucmd.pk_op, tucmd.pk_count, tucmd.pk_block);
469: tutab.b_active = NULL;
470: if (bp = tutab.b_actf) {
471: bp->b_flags |= B_ERROR;
472: tutab.b_actf = bp->av_forw;
473: if ((bp->b_flags&B_READ) == 0)
474: tu_vee(&tu_pcnt[minor(bp->b_dev)&DNUM]);
475: iodone(bp);
476: }
477: tu.tu_state = TUS_INIT1;
478: } else {
479: printf("tu%d: receive state error, state=",
480: (int)tudata.pk_unit);
481: printstate(tu.tu_state);
482: printf(", byte=%x\n", c & 0xff);
483: if (tutab.b_actf)
484: tu_restart();
485: else
486: wakeup((caddr_t)&tu);
487: }
488: }
489: }
490:
491: /*
492: * TU58 transmitter interrupt
493: */
494: tuxintr()
495: {
496:
497: top:
498: if (tu.tu_wcnt) {
499: /* still stuff to send, send one byte */
500: while ((mfpr(CSTS) & READY) == 0)
501: ;
502: mtpr(CSTD, *tu.tu_wbptr++);
503: tu.tu_wcnt--;
504: return;
505: }
506:
507: /*
508: * Last message byte was sent out.
509: * Switch on state of transfer.
510: */
511: if (tudebug) {
512: printf("tuxintr: state=");
513: printstate(tu.tu_state);
514: }
515: switch(tu.tu_state) {
516:
517: /*
518: * Two nulls have been sent, remove break, and send inits
519: */
520: case TUS_INIT1:
521: mtpr(CSTS, IE);
522: printd("ON2 ");
523: tu.tu_state = TUS_INIT2;
524: tu.tu_wbptr = tuinit;
525: tu.tu_wcnt = sizeof (tuinit);
526: goto top;
527:
528: /*
529: * Inits have been sent, wait for a continue msg.
530: */
531: case TUS_INIT2:
532: (void) mfpr(CSRD);
533: mtpr(CSRS, IE);
534: tu.tu_flag = 1;
535: break;
536:
537: /*
538: * Read cmd packet sent, get ready for data
539: */
540: case TUS_SENDR:
541: tu.tu_state = TUS_GETH;
542: tu.tu_rbptr = (u_char *)&tudata;
543: tu.tu_rcnt = 2;
544: tu.tu_flag = 1;
545: mtpr(CSTS, 0); /* disable transmitter interrupts */
546: printd("OFF ");
547: break;
548:
549: /*
550: * Write cmd packet sent, wait for continue
551: */
552: case TUS_SENDW:
553: tu.tu_state = TUS_WAIT;
554: tu.tu_flag = 1;
555: if ((mfpr(CSRS)&IE) == 0) {
556: printf("NO IE\n");
557: mtpr(CSRS, IE);
558: }
559: break;
560:
561: /*
562: * Header sent, send data.
563: */
564: case TUS_SENDH:
565: tu.tu_state = TUS_SENDD;
566: tu.tu_wbptr = (u_char *)tu.tu_addr;
567: tu.tu_wcnt = tudata.pk_mcount;
568: goto top;
569:
570: /*
571: * Data sent, follow with checksum.
572: */
573: case TUS_SENDD:
574: tu.tu_state = TUS_SENDC;
575: tu.tu_wbptr = (u_char *)&tudata.pk_chksum;
576: tu.tu_wcnt = sizeof tudata.pk_chksum;
577: goto top;
578:
579: /*
580: * Checksum sent, wait for continue.
581: */
582: case TUS_SENDC:
583: /*
584: * Updata buffer address and count.
585: */
586: tu.tu_addr += tudata.pk_mcount;
587: tu.tu_count -= tudata.pk_mcount;
588: if (tu.tu_count) {
589: tu.tu_state = TUS_WAIT;
590: tu.tu_flag = 1;
591: break;
592: }
593:
594: /*
595: * End of transmission, get ready for end packet.
596: */
597: tu.tu_state = TUS_GET;
598: tu.tu_rbptr = (u_char *)&tudata;
599: tu.tu_rcnt = sizeof (tudata);
600: tu.tu_flag = 1;
601: mtpr(CSTS, 0);
602: printd("OFF2 ");
603: break;
604:
605: /*
606: * Random interrupt, probably from MRSP ACK
607: */
608: case TUS_IDLE:
609:
610: default:
611: break;
612:
613: }
614: if (tudebug) {
615: printd(" new tu_state=");
616: printstate(tu.tu_state);
617: }
618: }
619:
620: /*
621: * Compute checksum TU58 fashion
622: */
623: #ifdef lint
624: tuchk(word, cp, n)
625: register word;
626: register unsigned short *cp;
627: int n;
628: {
629: register int c = n >> 1;
630: register long temp;
631:
632: do {
633: temp = *cp++; /* temp, only because vax cc won't *r++ */
634: word += temp;
635: } while (--c > 0);
636: if (n & 1)
637: word += *(unsigned char *)cp;
638: while (word & 0xffff0000)
639: word = (word & 0xffff) + ((word >> 16) & 0xffff);
640: return (word);
641: }
642: #else
643: tuchk(word0, wp, n)
644: register int word0; /* r11 */
645: register u_short *wp; /* r10 */
646: register int n; /* r9 */
647: {
648: asm("loop:");
649: asm(" addw2 (r10)+,r11"); /* add a word to sum */
650: asm(" adwc $0,r11"); /* add in carry, end-around */
651: asm(" acbl $2,$-2,r9,loop"); /* done yet? */
652: asm(" blbc r9,ok"); /* odd byte count? */
653: asm(" movzbw (r10),r10"); /* yes, get last byte */
654: asm(" addw2 r10,r11"); /* add it in */
655: asm(" adwc $0,r11"); /* and the carry */
656: asm("ok:");
657: asm(" movl r11,r0"); /* return sum */
658: }
659: #endif
660:
661: tuwatch()
662: {
663: register int s;
664: register struct buf *bp;
665:
666: if (tutimer == 0)
667: return;
668:
669: if (tu.tu_flag == 0) { /* if no read in progress - skip */
670: timeout(tuwatch, (caddr_t)0, hz);
671: return;
672: }
673: if (tu.tu_flag++ <= 40) {
674: timeout(tuwatch, (caddr_t)0, hz);
675: return;
676: }
677: printf("tu%d: read stalled\n", tudata.pk_unit);
678: #ifdef TUDEBUG
679: printf("%X %X %X %X %X %X %X %X\n", tu.tu_rbptr, tu.tu_rcnt,
680: tu.tu_wbptr, tu.tu_wcnt, tu.tu_state, tu.tu_flag,
681: tu.tu_addr, tu.tu_count);
682: #endif
683: s = spltu();
684: tu.tu_flag = 0;
685: (void) mfpr(CSRD);
686: mtpr(CSRS, IE); /* in case we were flushing */
687: mtpr(CSTS, IE);
688: tu.tu_state = TUS_IDLE;
689: if (!tutab.b_active) {
690: wakeup((caddr_t)&tu);
691: goto retry;
692: }
693: if (++tutab.b_errcnt <= 1) {
694: tustart();
695: goto retry;
696: }
697: if (bp = tutab.b_actf) {
698: bp->b_flags |= B_ERROR;
699: if ((bp->b_flags&B_READ) == 0)
700: tu_vee(&tu_pcnt[minor(bp->b_dev)&DNUM]);
701: iodone(bp);
702: }
703: retry:
704: splx(s);
705: timeout(tuwatch, (caddr_t)0, hz);
706: }
707:
708: tu_pee(cp)
709: char *cp;
710: {
711: register int s;
712:
713: s = spltu();
714: if (++(*cp) > NTUQ)
715: sleep(cp, PRIBIO);
716: splx(s);
717: }
718:
719: tu_vee(cp)
720: char *cp;
721: {
722: register int s;
723:
724: s = spltu();
725: if (--(*cp) <= NTUQ)
726: wakeup(cp);
727: splx(s);
728: }
729:
730: tu_restart()
731: {
732: tureset();
733: timeout(tustart, (caddr_t)0, hz * 3);
734: }
735:
736: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.