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