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