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