|
|
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.