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