|
|
1.1 root 1: /* tu.c 82/02/01 4.5 */
2:
3: #if defined(VAX750) || defined(VAX7ZZ)
4: /*
5: * TU58 DECtape II device driver
6: *
7: * This driver controls the console TU58s on a VAX-11/750 or VAX-11/7ZZ.
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 7ZZ 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: #define NTU ((cpu == VAX_750) ? 1 : 2)
18:
19: #define MRSP (cpu != VAX_750)
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/mtpr.h"
28: #include "../h/cpu.h"
29:
30: #define printd if(tudebug) printf
31: #ifdef printd
32: int tudebug; /* printd */
33: #endif printd
34:
35: #define NTUBLK 512 /* number of blocks on a TU58 cassette */
36:
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: 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: } tu;
82:
83: /*
84: * States
85: */
86: #define INIT1 0 /* sending nulls */
87: #define INIT2 1 /* sending inits */
88: #define IDLE 2 /* initialized, no transfer in progress */
89: #define SENDH 3 /* sending header */
90: #define SENDD 4 /* sending data */
91: #define SENDC 5 /* sending checksum */
92: #define SENDR 6 /* sending read command packet */
93: #define SENDW 7 /* sending write command packet */
94: #define GETH 8 /* reading header */
95: #define GETD 9 /* reading data */
96: #define GETC 10 /* reading checksum */
97: #define GET 11 /* reading an entire packet */
98: #define WAIT 12 /* waiting for continue */
99:
100: /*
101: * Packet Flags
102: */
103: #define TUF_DATA 1 /* data packet */
104: #define TUF_CMD 2 /* command packet */
105: #define TUF_INITF 4 /* initialize */
106: #define TUF_CONT 020 /* continue */
107: #define TUF_XOFF 023 /* flow control */
108:
109: /*
110: * Op Codes
111: */
112: #define TUOP_INIT 1 /* initialize */
113: #define TUOP_READ 2 /* read block */
114: #define TUOP_WRITE 3 /* write block */
115: #define TUOP_SEEK 5 /* seek to block */
116: #define TUOP_DIAGNOSE 7 /* run micro-diagnostics */
117: #define TUOP_END 0100 /* end packet */
118:
119: /*
120: * Switches
121: */
122: #define TUSW_MRSP 010 /* use Modified RSP */
123:
124: u_char tunull[2] = { 0, 0 }; /* nulls to send for initialization */
125: u_char tuinit[2] = { TUF_INITF, TUF_INITF }; /* inits to send */
126:
127: int tutimer = 0;
128:
129: struct buf tutab; /* I/O queue header */
130:
131: /*
132: * Open the TU58
133: */
134: /*ARGSUSED*/
135: tuopen(dev, flag)
136: {
137: extern int tuwatch();
138: register s;
139:
140: #ifdef lint
141: turintr(); tuwintr();
142: #endif
143: if (minor(dev) >= NTU) {
144: u.u_error = ENXIO;
145: return;
146: }
147: if (tutimer == 0) {
148: tutimer++;
149: timeout(tuwatch, (caddr_t)0, hz);
150: }
151: s = splx(TUIPL);
152: if (tu.state != IDLE) {
153: tureset();
154: sleep((caddr_t)&tu, PZERO);
155: tutab.b_active = NULL;
156: if (tu.state != IDLE) { /* couldn't initialize */
157: u.u_error = ENXIO;
158: tu.state = INIT1;
159: tu.rcnt = tu.wcnt = 0;
160: mtpr(CSTS, 0);
161: mtpr(CSRS, 0);
162: }
163: } else
164: mtpr(CSRS, IE);
165: splx(s);
166: }
167:
168: /*
169: * Close the TU58
170: */
171: tuclose(dev)
172: {
173:
174: if (tutab.b_active == 0) {
175: mtpr(CSRS, 0);
176: tutimer = 0;
177: }
178: if (tu.serrs + tu.cerrs + tu.herrs != 0) { /* any errors ? */
179: uprintf("tu%d: %d soft errors, %d chksum errors, %d hard errors\n",
180: minor(dev), tu.serrs, tu.cerrs, tu.herrs);
181: tu.serrs = tu.cerrs = tu.herrs = 0;
182: }
183: }
184:
185: /*
186: * Reset the TU58
187: */
188: tureset()
189: {
190:
191: tu.state = INIT1;
192: tu.wbptr = tunull;
193: tu.wcnt = sizeof tunull;
194: tucmd.pk_flag = TUF_CMD;
195: tucmd.pk_mcount = sizeof tucmd - 4;
196: tucmd.pk_mod = 0;
197: tucmd.pk_seq = 0;
198: tucmd.pk_sw = MRSP ? TUSW_MRSP : 0;
199: tutab.b_active++;
200: mtpr(CSRS, 0);
201: mtpr(CSTS, IE|BREAK);
202: tuxintr(); /* start output */
203: return;
204: }
205:
206: /*
207: * Strategy routine for block I/O
208: */
209: tustrategy(bp)
210: register struct buf *bp;
211: {
212: register int s;
213:
214: if (bp->b_blkno >= NTUBLK) { /* block number out of range? */
215: bp->b_flags |= B_ERROR;
216: iodone(bp);
217: return;
218: }
219: bp->av_forw = NULL;
220: s = splx(TUIPL);
221: if (tutab.b_actf == NULL)
222: tutab.b_actf = bp;
223: else
224: tutab.b_actl->av_forw = bp;
225: tutab.b_actl = bp;
226: if (tutab.b_active == NULL)
227: tustart();
228: splx(s);
229: }
230:
231: /*
232: * Start the transfer
233: */
234: tustart()
235: {
236: register struct buf *bp;
237:
238: if ((bp = tutab.b_actf) == NULL)
239: return;
240: if (tu.state != IDLE) {
241: tureset();
242: return;
243: }
244: tutab.b_active++;
245: tutab.b_errcnt = 0;
246: tucmd.pk_op = bp->b_flags&B_READ ? TUOP_READ : TUOP_WRITE;
247: tucmd.pk_unit = minor(bp->b_dev);
248: tucmd.pk_count = tu.count = bp->b_bcount;
249: tucmd.pk_block = bp->b_blkno;
250: tucmd.pk_chksum =
251: tuchk(*((short *)&tucmd), (caddr_t)&tucmd.pk_op,
252: (int)tucmd.pk_mcount);
253: tu.state = bp->b_flags&B_READ ? SENDR : SENDW;
254: tu.addr = bp->b_un.b_addr;
255: tu.count = bp->b_bcount;
256: tu.wbptr = (u_char *)&tucmd;
257: tu.wcnt = sizeof tucmd;
258: tuxintr();
259: }
260:
261: /*
262: * TU58 receiver interrupt
263: */
264: turintr()
265: {
266: register struct buf *bp;
267: register int c;
268:
269: c = mfpr(CSRD)&0xff; /* get the char, clear the interrupt */
270: if (MRSP) {
271: while ((mfpr(CSTS)&READY) == 0)
272: ;
273: mtpr(CSTD, TUF_CONT); /* ACK */
274: }
275: if (tu.rcnt) { /* still waiting for data? */
276: *tu.rbptr++ = c; /* yup, put it there */
277: if (--tu.rcnt) /* decrement count, any left? */
278: return; /* get some more */
279: }
280:
281: /*
282: * We got all the data we were expecting for now,
283: * switch on the state of the transfer.
284: */
285: switch(tu.state) {
286:
287: case INIT2:
288: if (c == TUF_CONT) /* did we get the expected continue? */
289: tu.state = IDLE;
290: else
291: tu.state = INIT1; /* bad news... */
292: tu.flag = 0;
293: wakeup((caddr_t)&tu);
294: tustart();
295: break;
296:
297: case WAIT: /* waiting for continue */
298: if (c != TUF_CONT) {
299: tu.state = INIT1; /* bad news... */
300: break;
301: }
302: tu.flag = 0;
303: tudata.pk_flag = TUF_DATA;
304: tudata.pk_mcount = MIN(128, tu.count);
305: tudata.pk_chksum =
306: tuchk(*((short *)&tudata), (caddr_t)tu.addr,
307: (int)tudata.pk_mcount);
308: tu.state = SENDH;
309: tu.wbptr = (u_char *)&tudata;
310: tu.wcnt = 2;
311: tuxintr();
312: break;
313:
314: case GETH: /* got header, get data */
315: if (tudata.pk_flag == TUF_DATA) /* data message? */
316: tu.rbptr = (u_char *)tu.addr; /* yes put in buffer */
317: tu.rcnt = tudata.pk_mcount; /* amount to get */
318: tu.state = GETD;
319: break;
320:
321: case GETD: /* got data, get checksum */
322: tu.rbptr = (u_char *)&tudata.pk_chksum;
323: tu.rcnt = sizeof tudata.pk_chksum;
324: tu.state = GETC;
325: break;
326:
327: case GET:
328: case GETC: /* got entire packet */
329: #ifdef notdef
330: if (tudata.pk_chksum !=
331: tuchk(*((short *)&tudata),
332: tudata.pk_flag == TUF_DATA ? tu.addr : &tudata.pk_op,
333: (int)tudata.pk_mcount))
334: tu.cerrs++;
335: #endif
336: if (tudata.pk_flag == TUF_DATA) {
337: /* data packet, advance to next */
338: tu.addr += tudata.pk_mcount;
339: tu.count -= tudata.pk_mcount;
340: tu.state = GETH;
341: tu.rbptr = (u_char *)&tudata; /* next packet */
342: tu.rcnt = 2;
343: } else if (tudata.pk_flag==TUF_CMD && tudata.pk_op==TUOP_END) {
344: /* end packet, idle and reenable transmitter */
345: tu.state = IDLE;
346: tu.flag = 0;
347: mtpr(CSTS, IE);
348: printd("ON ");
349: if ((bp = tutab.b_actf) == NULL) {
350: printf("tu: no bp!\n");
351: printf("active %d\n", tutab.b_active);
352: tustart();
353: return;
354: }
355: if (tudata.pk_mod < 0) { /* hard error */
356: bp->b_flags |= B_ERROR;
357: tu.herrs++;
358: harderr(bp, "tu");
359: printf(" pk_mod %d\n", -tudata.pk_mod);
360: } else if (tudata.pk_mod > 0) /* soft error */
361: tu.serrs++;
362: tutab.b_active = NULL;
363: tutab.b_actf = bp->av_forw;
364: bp->b_resid = tu.count;
365: iodone(bp);
366: tustart();
367: } else {
368: printf("neither data nor end: %o %o\n",
369: tudata.pk_flag&0xff, tudata.pk_op&0xff);
370: mtpr(CSRS, 0); /* flush the rest */
371: tu.state = INIT1;
372: }
373: break;
374:
375: case IDLE:
376: case INIT1:
377: break;
378:
379: default:
380: if (c == TUF_INITF) {
381: printf("TU protocol error, state %d\n", tu.state);
382: printf("%o %d %d\n",
383: tucmd.pk_op, tucmd.pk_count, tucmd.pk_block);
384: tutab.b_active = NULL;
385: if (bp = tutab.b_actf) {
386: bp->b_flags |= B_ERROR;
387: tutab.b_actf = bp->av_forw;
388: iodone(bp);
389: }
390: tu.state = INIT1;
391: } else {
392: printf("TU receive state error %d %o\n", tu.state, c);
393: /* tu.state = INIT1; */
394: wakeup((caddr_t)&tu);
395: }
396: }
397: }
398:
399: /*
400: * TU58 transmitter interrupt
401: */
402: tuxintr()
403: {
404:
405: top:
406: if (tu.wcnt) {
407: /* still stuff to send, send one byte */
408: while ((mfpr(CSTS) & READY) == 0)
409: ;
410: mtpr(CSTD, *tu.wbptr++);
411: tu.wcnt--;
412: return;
413: }
414:
415: /*
416: * Last message byte was sent out.
417: * Switch on state of transfer.
418: */
419: printd("tuxintr: state %d\n", tu.state);
420: switch(tu.state) {
421:
422: case INIT1: /* two nulls sent, remove break, send inits */
423: mtpr(CSTS, IE);
424: printd("ON2 ");
425: tu.state = INIT2;
426: tu.wbptr = tuinit;
427: tu.wcnt = sizeof tuinit;
428: goto top;
429:
430: case INIT2: /* inits sent, wait for continue */
431: (void) mfpr(CSRD);
432: mtpr(CSRS, IE);
433: tu.flag = 1;
434: break;
435:
436: case IDLE: /* stray interrupt? */
437: break;
438:
439: case SENDR: /* read cmd packet sent, get ready for data */
440: tu.state = GETH;
441: tu.rbptr = (u_char *)&tudata;
442: tu.rcnt = 2;
443: tu.flag = 1;
444: mtpr(CSTS, 0); /* disable transmitter interrupts */
445: printd("OFF ");
446: break;
447:
448: case SENDW: /* write cmd packet sent, wait for continue */
449: tu.state = WAIT;
450: tu.flag = 1;
451: if ((mfpr(CSRS)&IE) == 0) {
452: printf("NO IE\n");
453: mtpr(CSRS, IE);
454: }
455: break;
456:
457: case SENDH: /* header sent, send data */
458: tu.state = SENDD;
459: tu.wbptr = (u_char *)tu.addr;
460: tu.wcnt = tudata.pk_mcount;
461: goto top;
462:
463: case SENDD: /* data sent, send checksum */
464: tu.state = SENDC;
465: tu.wbptr = (u_char *)&tudata.pk_chksum;
466: tu.wcnt = sizeof tudata.pk_chksum;
467: goto top;
468:
469: case SENDC: /* checksum sent, wait for continue */
470: tu.addr += tudata.pk_mcount; /* update buffer address */
471: tu.count -= tudata.pk_mcount; /* and count */
472: if (tu.count == 0) { /* all done? */
473: tu.state = GET; /* set up to get end packet */
474: tu.rbptr = (u_char *)&tudata;
475: tu.rcnt = sizeof tudata;
476: tu.flag = 1;
477: mtpr(CSTS, 0);
478: printd("OFF2 ");
479: } else {
480: tu.state = WAIT; /* wait for continue */
481: tu.flag = 1;
482: }
483: break;
484:
485: default: /* random interrupt, probably from MRSP ACK */
486: break;
487: }
488: printd(" new state %d\n", tu.state);
489: }
490:
491: /*
492: * Compute checksum TU58 fashion
493: */
494: tuchk(word, cp, n)
495: register word;
496: register unsigned short *cp;
497: {
498: register c = n >> 1;
499: register long temp;
500:
501: do {
502: temp = *cp++; /* temp, only because vax cc won't *r++ */
503: word += temp;
504: } while (--c > 0);
505: if (n & 1)
506: word += *(unsigned char *)cp;
507: while (word & 0xFFFF0000)
508: word = (word & 0xFFFF) + (word >> 16);
509: return (word);
510: }
511:
512: tuwatch()
513: {
514: register int s;
515: register struct buf *bp;
516:
517: if (tutimer == 0) {
518: tu.flag = 0;
519: return;
520: }
521: if (tu.flag)
522: tu.flag++;
523: if (tu.flag > 40) {
524: printf("tu: read stalled\n");
525: printf("%X %X %X %X %X %X %X %X\n", tu.rbptr, tu.rcnt,
526: tu.wbptr, tu.wcnt, tu.state, tu.flag, tu.addr, tu.count);
527: tu.flag = 0;
528: s = splx(TUIPL);
529: (void) mfpr(CSRD);
530: mtpr(CSRS, IE); /* in case we were flushing */
531: mtpr(CSTS, IE);
532: tu.state = IDLE;
533: if (tutab.b_active) {
534: if (++tutab.b_errcnt > 1) {
535: if (bp = tutab.b_actf) {
536: bp->b_flags |= B_ERROR;
537: iodone(bp);
538: }
539: } else
540: tustart();
541: } else
542: wakeup((caddr_t)&tu);
543: splx(s);
544: }
545: timeout(tuwatch, (caddr_t)0, hz);
546: }
547: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.