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