|
|
1.1 ! root 1: /* ut.c 6.1 83/07/29 */ ! 2: ! 3: #include "tj.h" ! 4: #if NUT > 0 ! 5: /* ! 6: * System Industries Model 9700 Tape Drive ! 7: * emulates a TU45 on the UNIBUS ! 8: * ! 9: * TODO: ! 10: * check out attention processing ! 11: * try reset code and dump code ! 12: */ ! 13: #include "../machine/pte.h" ! 14: ! 15: #include "../h/param.h" ! 16: #include "../h/systm.h" ! 17: #include "../h/buf.h" ! 18: #include "../h/conf.h" ! 19: #include "../h/dir.h" ! 20: #include "../h/file.h" ! 21: #include "../h/user.h" ! 22: #include "../h/map.h" ! 23: #include "../h/ioctl.h" ! 24: #include "../h/mtio.h" ! 25: #include "../h/cmap.h" ! 26: #include "../h/uio.h" ! 27: #include "../h/kernel.h" ! 28: ! 29: #include "../vax/cpu.h" ! 30: #include "../vaxuba/ubareg.h" ! 31: #include "../vaxuba/ubavar.h" ! 32: #include "../vaxuba/utreg.h" ! 33: ! 34: struct buf rutbuf[NUT]; /* bufs for raw i/o */ ! 35: struct buf cutbuf[NUT]; /* bufs for control operations */ ! 36: struct buf tjutab[NTJ]; /* bufs for slave queue headers */ ! 37: ! 38: struct uba_ctlr *utminfo[NUT]; ! 39: struct uba_device *tjdinfo[NTJ]; ! 40: int utprobe(), utslave(), utattach(), utdgo(), utintr(), uttimer(); ! 41: u_short utstd[] = { 0772440, 0 }; ! 42: struct uba_driver utdriver = ! 43: { utprobe, utslave, utattach, utdgo, utstd, "tj", tjdinfo, "ut", utminfo, 0 }; ! 44: ! 45: #define MASKREG(reg) ((reg)&0xffff) ! 46: ! 47: /* bits in minor device */ ! 48: #define TJUNIT(dev) (minor(dev)&03) ! 49: #define T_NOREWIND 04 ! 50: #define T_1600BPI 010 ! 51: #define T_6250BPI 020 ! 52: short utdens[] = { UT_NRZI, UT_PE, UT_GCR, UT_NRZI }; ! 53: ! 54: /* slave to controller mapping table */ ! 55: short tjtout[NTJ]; ! 56: #define UTUNIT(dev) (tjtout[TJUNIT(dev)]) ! 57: ! 58: #define INF (daddr_t)1000000L /* a block number that wont exist */ ! 59: ! 60: struct tj_softc { ! 61: char sc_openf; /* exclusive open */ ! 62: char sc_lastiow; /* last I/O operation was a write */ ! 63: daddr_t sc_blkno; /* next block to transfer */ ! 64: daddr_t sc_nxrec; /* next record on tape */ ! 65: u_short sc_erreg; /* image of uter */ ! 66: u_short sc_dsreg; /* image of utds */ ! 67: u_short sc_resid; /* residual from transfer */ ! 68: u_short sc_dens; /* sticky selected density */ ! 69: daddr_t sc_timo; /* time until timeout expires */ ! 70: short sc_tact; /* timeout is active flag */ ! 71: } tj_softc[NTJ]; ! 72: ! 73: /* ! 74: * Internal per/slave states found in sc_state ! 75: */ ! 76: #define SSEEK 1 /* seeking */ ! 77: #define SIO 2 /* doing sequential I/O */ ! 78: #define SCOM 3 /* sending a control command */ ! 79: #define SREW 4 /* doing a rewind op */ ! 80: #define SERASE 5 /* erase inter-record gap */ ! 81: #define SERASED 6 /* erased inter-record gap */ ! 82: ! 83: /*ARGSUSED*/ ! 84: utprobe(reg) ! 85: caddr_t reg; ! 86: { ! 87: register int br, cvec; ! 88: #ifdef lint ! 89: br=0; cvec=br; br=cvec; ! 90: utintr(0); ! 91: #endif ! 92: /* ! 93: * The SI documentation says you must set the RDY bit ! 94: * (even though it's read-only) to force an interrupt. ! 95: */ ! 96: ((struct utdevice *) reg)->utcs1 = UT_IE|UT_NOP|UT_RDY; ! 97: DELAY(10000); ! 98: return (sizeof (struct utdevice)); ! 99: } ! 100: ! 101: /*ARGSUSED*/ ! 102: utslave(ui, reg) ! 103: struct uba_device *ui; ! 104: caddr_t reg; ! 105: { ! 106: /* ! 107: * A real TU45 would support the slave present bit ! 108: * int the drive type register, but this thing doesn't, ! 109: * so there's no way to determine if a slave is present or not. ! 110: */ ! 111: return(1); ! 112: } ! 113: ! 114: utattach(ui) ! 115: struct uba_device *ui; ! 116: { ! 117: tjtout[ui->ui_unit] = ui->ui_mi->um_ctlr; ! 118: } ! 119: ! 120: /* ! 121: * Open the device with exclusive access. ! 122: */ ! 123: utopen(dev, flag) ! 124: dev_t dev; ! 125: int flag; ! 126: { ! 127: register int tjunit = TJUNIT(dev); ! 128: register struct uba_device *ui; ! 129: register struct tj_softc *sc; ! 130: int olddens, dens; ! 131: register int s; ! 132: ! 133: if (tjunit >= NTJ || (sc = &tj_softc[tjunit])->sc_openf || ! 134: (ui = tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) ! 135: return (ENXIO); ! 136: olddens = sc->sc_dens; ! 137: dens = sc->sc_dens = ! 138: utdens[(minor(dev)&(T_1600BPI|T_6250BPI))>>3]| ! 139: PDP11FMT|(ui->ui_slave&07); ! 140: get: ! 141: utcommand(dev, UT_SENSE, 1); ! 142: if (sc->sc_dsreg&UTDS_PIP) { ! 143: sleep((caddr_t)&lbolt, PZERO+1); ! 144: goto get; ! 145: } ! 146: sc->sc_dens = olddens; ! 147: if ((sc->sc_dsreg&UTDS_MOL) == 0) { ! 148: uprintf("tj%d: not online\n", tjunit); ! 149: return (EIO); ! 150: } ! 151: if ((flag&FWRITE) && (sc->sc_dsreg&UTDS_WRL)) { ! 152: uprintf("tj%d: no write ring\n", tjunit); ! 153: return (EIO); ! 154: } ! 155: if ((sc->sc_dsreg&UTDS_BOT) == 0 && (flag&FWRITE) && ! 156: dens != sc->sc_dens) { ! 157: uprintf("tj%d: can't change density in mid-tape\n", tjunit); ! 158: return (EIO); ! 159: } ! 160: sc->sc_openf = 1; ! 161: sc->sc_blkno = (daddr_t)0; ! 162: sc->sc_nxrec = INF; ! 163: sc->sc_lastiow = 0; ! 164: sc->sc_dens = dens; ! 165: /* ! 166: * For 6250 bpi take exclusive use of the UNIBUS. ! 167: */ ! 168: ui->ui_driver->ud_xclu = (dens&(T_1600BPI|T_6250BPI)) == T_6250BPI; ! 169: s = spl6(); ! 170: if (sc->sc_tact == 0) { ! 171: sc->sc_timo = INF; ! 172: sc->sc_tact = 1; ! 173: timeout(uttimer, (caddr_t)dev, 5*hz); ! 174: } ! 175: splx(s); ! 176: return (0); ! 177: } ! 178: ! 179: utclose(dev, flag) ! 180: register dev_t dev; ! 181: register flag; ! 182: { ! 183: register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; ! 184: ! 185: if (flag == FWRITE || ((flag&FWRITE) && sc->sc_lastiow)) { ! 186: utcommand(dev, UT_WEOF, 1); ! 187: utcommand(dev, UT_WEOF, 1); ! 188: utcommand(dev, UT_SREV, 1); ! 189: } ! 190: if ((minor(dev)&T_NOREWIND) == 0) ! 191: utcommand(dev, UT_REW, 0); ! 192: sc->sc_openf = 0; ! 193: } ! 194: ! 195: utcommand(dev, com, count) ! 196: dev_t dev; ! 197: int com, count; ! 198: { ! 199: register struct buf *bp; ! 200: register int s; ! 201: ! 202: bp = &cutbuf[UTUNIT(dev)]; ! 203: s = spl5(); ! 204: while (bp->b_flags&B_BUSY) { ! 205: if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) ! 206: break; ! 207: bp->b_flags |= B_WANTED; ! 208: sleep((caddr_t)bp, PRIBIO); ! 209: } ! 210: bp->b_flags = B_BUSY|B_READ; ! 211: splx(s); ! 212: bp->b_dev = dev; ! 213: bp->b_command = com; ! 214: bp->b_repcnt = count; ! 215: bp->b_blkno = 0; ! 216: utstrategy(bp); ! 217: if (count == 0) ! 218: return; ! 219: iowait(bp); ! 220: if (bp->b_flags&B_WANTED) ! 221: wakeup((caddr_t)bp); ! 222: bp->b_flags &= B_ERROR; ! 223: } ! 224: ! 225: /* ! 226: * Queue a tape operation. ! 227: */ ! 228: utstrategy(bp) ! 229: register struct buf *bp; ! 230: { ! 231: int tjunit = TJUNIT(bp->b_dev); ! 232: register struct uba_ctlr *um; ! 233: register struct buf *dp; ! 234: ! 235: /* ! 236: * Put transfer at end of unit queue ! 237: */ ! 238: dp = &tjutab[tjunit]; ! 239: bp->av_forw = NULL; ! 240: (void) spl5(); ! 241: if (dp->b_actf == NULL) { ! 242: dp->b_actf = bp; ! 243: /* ! 244: * Transport not active, so... ! 245: * put at end of controller queue ! 246: */ ! 247: dp->b_forw = NULL; ! 248: um = tjdinfo[tjunit]->ui_mi; ! 249: if (um->um_tab.b_actf == NULL) ! 250: um->um_tab.b_actf = dp; ! 251: else ! 252: um->um_tab.b_actl->b_forw = dp; ! 253: um->um_tab.b_actl = dp; ! 254: } else ! 255: dp->b_actl->av_forw = bp; ! 256: dp->b_actl = bp; ! 257: /* ! 258: * If the controller is not busy, set it going. ! 259: */ ! 260: if (um->um_tab.b_state == 0) ! 261: utstart(um); ! 262: (void) spl0(); ! 263: } ! 264: ! 265: utstart(um) ! 266: register struct uba_ctlr *um; ! 267: { ! 268: register struct utdevice *addr; ! 269: register struct buf *bp, *dp; ! 270: register struct tj_softc *sc; ! 271: struct uba_device *ui; ! 272: int tjunit; ! 273: daddr_t blkno; ! 274: ! 275: loop: ! 276: /* ! 277: * Scan controller queue looking for units with ! 278: * transaction queues to dispatch ! 279: */ ! 280: if ((dp = um->um_tab.b_actf) == NULL) ! 281: return; ! 282: if ((bp = dp->b_actf) == NULL) { ! 283: um->um_tab.b_actf = dp->b_forw; ! 284: goto loop; ! 285: } ! 286: addr = (struct utdevice *)um->um_addr; ! 287: tjunit = TJUNIT(bp->b_dev); ! 288: ui = tjdinfo[tjunit]; ! 289: sc = &tj_softc[tjunit]; ! 290: /* note slave select, density, and format were merged on open */ ! 291: addr->uttc = sc->sc_dens; ! 292: sc->sc_dsreg = addr->utds; ! 293: sc->sc_erreg = addr->uter; ! 294: sc->sc_resid = MASKREG(addr->utfc); ! 295: /* ! 296: * Default is that last command was NOT a write command; ! 297: * if we do a write command we will notice this in utintr(). ! 298: */ ! 299: sc->sc_lastiow = 0; ! 300: if (sc->sc_openf < 0 || (addr->utds&UTDS_MOL) == 0) { ! 301: /* ! 302: * Have had a hard error on a non-raw tape ! 303: * or the tape unit is now unavailable ! 304: * (e.g. taken off line). ! 305: */ ! 306: bp->b_flags |= B_ERROR; ! 307: goto next; ! 308: } ! 309: if (bp == &cutbuf[UTUNIT(bp->b_dev)]) { ! 310: /* ! 311: * Execute a control operation with the specified ! 312: * count. ! 313: */ ! 314: if (bp->b_command == UT_SENSE) ! 315: goto next; ! 316: if (bp->b_command == UT_SFORW && (addr->utds & UTDS_EOT)) { ! 317: bp->b_resid = bp->b_bcount; ! 318: goto next; ! 319: } ! 320: /* ! 321: * Set next state; handle timeouts ! 322: */ ! 323: if (bp->b_command == UT_REW) { ! 324: um->um_tab.b_state = SREW; ! 325: sc->sc_timo = 5*60; ! 326: } else { ! 327: um->um_tab.b_state = SCOM; ! 328: sc->sc_timo = imin(imax(10*(int)-bp->b_repcnt,60),5*60); ! 329: } ! 330: /* NOTE: this depends on the ut command values */ ! 331: if (bp->b_command >= UT_SFORW && bp->b_command <= UT_SREVF) ! 332: addr->utfc = -bp->b_repcnt; ! 333: goto dobpcmd; ! 334: } ! 335: /* ! 336: * The following checks boundary conditions for operations ! 337: * on non-raw tapes. On raw tapes the initialization of ! 338: * sc->sc_nxrec by utphys causes them to be skipped normally ! 339: * (except in the case of retries). ! 340: */ ! 341: if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { ! 342: /* can't read past end of file */ ! 343: bp->b_flags |= B_ERROR; ! 344: bp->b_error = ENXIO; ! 345: goto next; ! 346: } ! 347: if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && (bp->b_flags&B_READ)) { ! 348: /* read at eof returns 0 count */ ! 349: bp->b_resid = bp->b_bcount; ! 350: clrbuf(bp); ! 351: goto next; ! 352: } ! 353: if ((bp->b_flags&B_READ) == 0) ! 354: sc->sc_nxrec = bdbtofsb(bp->b_blkno)+1; ! 355: /* ! 356: * If the tape is correctly positioned, set up all the ! 357: * registers but the csr, and give control over to the ! 358: * UNIBUS adaptor routines, to wait for resources to ! 359: * start I/O. ! 360: */ ! 361: if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { ! 362: addr->utwc = -(((bp->b_bcount)+1)>>1); ! 363: addr->utfc = -bp->b_bcount; ! 364: if ((bp->b_flags&B_READ) == 0) { ! 365: /* ! 366: * On write error retries erase the ! 367: * inter-record gap before rewriting. ! 368: */ ! 369: if (um->um_tab.b_errcnt) { ! 370: if (um->um_tab.b_state != SERASED) { ! 371: um->um_tab.b_state = SERASE; ! 372: sc->sc_timo = 60; ! 373: addr->utcs1 = UT_ERASE|UT_IE|UT_GO; ! 374: return; ! 375: } ! 376: } ! 377: if (addr->utds & UTDS_EOT) { ! 378: bp->b_resid = bp->b_bcount; ! 379: um->um_tab.b_state = 0; ! 380: goto next; ! 381: } ! 382: um->um_cmd = UT_WCOM; ! 383: } else ! 384: um->um_cmd = UT_RCOM; ! 385: sc->sc_timo = 60; ! 386: um->um_tab.b_state = SIO; ! 387: (void) ubago(ui); ! 388: return; ! 389: } ! 390: /* ! 391: * Tape positioned incorrectly; seek forwards or ! 392: * backwards to the correct spot. This happens for ! 393: * raw tapes only on error retries. ! 394: */ ! 395: um->um_tab.b_state = SSEEK; ! 396: if (blkno < bdbtofsb(bp->b_blkno)) { ! 397: addr->utfc = blkno - bdbtofsb(bp->b_blkno); ! 398: bp->b_command = UT_SFORW; ! 399: } else { ! 400: addr->utfc = bdbtofsb(bp->b_blkno) - blkno; ! 401: bp->b_command = UT_SREV; ! 402: } ! 403: sc->sc_timo = imin(imax(10 * -addr->utfc, 60), 5*60); ! 404: ! 405: dobpcmd: ! 406: /* ! 407: * Perform the command setup in bp. ! 408: */ ! 409: addr->utcs1 = bp->b_command|UT_IE|UT_GO; ! 410: return; ! 411: next: ! 412: /* ! 413: * Advance to the next command in the slave queue, ! 414: * posting notice and releasing resources as needed. ! 415: */ ! 416: if (um->um_ubinfo) ! 417: ubadone(um); ! 418: um->um_tab.b_errcnt = 0; ! 419: dp->b_actf = bp->av_forw; ! 420: iodone(bp); ! 421: goto loop; ! 422: } ! 423: ! 424: /* ! 425: * Start operation on controller -- ! 426: * UNIBUS resources have been allocated. ! 427: */ ! 428: utdgo(um) ! 429: register struct uba_ctlr *um; ! 430: { ! 431: register struct utdevice *addr = (struct utdevice *)um->um_addr; ! 432: ! 433: addr->utba = (u_short) um->um_ubinfo; ! 434: addr->utcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300)|UT_IE|UT_GO; ! 435: } ! 436: ! 437: /* ! 438: * Ut interrupt handler ! 439: */ ! 440: /*ARGSUSED*/ ! 441: utintr(ut11) ! 442: int ut11; ! 443: { ! 444: struct buf *dp; ! 445: register struct buf *bp; ! 446: register struct uba_ctlr *um = utminfo[ut11]; ! 447: register struct utdevice *addr; ! 448: register struct tj_softc *sc; ! 449: u_short tjunit, cs2, cs1; ! 450: register state; ! 451: ! 452: if ((dp = um->um_tab.b_actf) == NULL) ! 453: return; ! 454: bp = dp->b_actf; ! 455: tjunit = TJUNIT(bp->b_dev); ! 456: addr = (struct utdevice *)tjdinfo[tjunit]->ui_addr; ! 457: sc = &tj_softc[tjunit]; ! 458: /* ! 459: * Record status... ! 460: */ ! 461: sc->sc_timo = INF; ! 462: sc->sc_dsreg = addr->utds; ! 463: sc->sc_erreg = addr->uter; ! 464: sc->sc_resid = MASKREG(addr->utfc); ! 465: if ((bp->b_flags&B_READ) == 0) ! 466: sc->sc_lastiow = 1; ! 467: state = um->um_tab.b_state; ! 468: um->um_tab.b_state = 0; ! 469: /* ! 470: * Check for errors... ! 471: */ ! 472: if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) { ! 473: /* ! 474: * To clear the ERR bit, we must issue a drive clear ! 475: * command, and to clear the TRE bit we must set the ! 476: * controller clear bit. ! 477: */ ! 478: cs2 = addr->utcs2; ! 479: if ((cs1 = addr->utcs1)&UT_TRE) ! 480: addr->utcs2 |= UTCS2_CLR; ! 481: /* is this dangerous ?? */ ! 482: while ((addr->utcs1&UT_RDY) == 0) ! 483: ; ! 484: addr->utcs1 = UT_CLEAR|UT_GO; ! 485: /* ! 486: * If we were reading at 1600 or 6250 bpi and the error ! 487: * was corrected, then don't consider this an error. ! 488: */ ! 489: if (sc->sc_erreg & UTER_COR && (bp->b_flags & B_READ) && ! 490: (addr->uttc & UTTC_DEN) != UT_NRZI) { ! 491: printf( ! 492: "ut%d: soft error bn%d cs1=%b er=%b cs2=%b ds=%b\n", ! 493: tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg, ! 494: UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS); ! 495: sc->sc_erreg &= ~UTER_COR; ! 496: } ! 497: /* ! 498: * If we were reading from a raw tape and the only error ! 499: * was that the record was too long, then we don't consider ! 500: * this an error. ! 501: */ ! 502: if (bp == &rutbuf[UTUNIT(bp->b_dev)] && (bp->b_flags&B_READ) && ! 503: (sc->sc_erreg&UTER_FCE)) ! 504: sc->sc_erreg &= ~UTER_FCE; ! 505: if (sc->sc_erreg == 0) ! 506: goto ignoreerr; ! 507: /* ! 508: * Fix up errors which occur due to backspacing ! 509: * "over" the front of the tape. ! 510: */ ! 511: if ((sc->sc_dsreg & UTDS_BOT) && bp->b_command == UT_SREV && ! 512: ((sc->sc_erreg &= ~(UTER_NEF|UTER_FCE)) == 0)) ! 513: goto opdone; ! 514: /* ! 515: * Retry soft errors up to 8 times ! 516: */ ! 517: if ((sc->sc_erreg&UTER_HARD) == 0 && state == SIO) { ! 518: if (++um->um_tab.b_errcnt < 7) { ! 519: sc->sc_blkno++; ! 520: ubadone(um); ! 521: goto opcont; ! 522: } ! 523: } ! 524: /* ! 525: * Hard or non-I/O errors on non-raw tape ! 526: * cause it to close. ! 527: */ ! 528: if (sc->sc_openf > 0 && bp != &rutbuf[UTUNIT(bp->b_dev)]) ! 529: sc->sc_openf = -1; ! 530: /* ! 531: * Couldn't recover error. ! 532: */ ! 533: printf("ut%d: hard error bn%d cs1=%b er=%b cs2=%b ds=%b\n", ! 534: tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg, ! 535: UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS); ! 536: bp->b_flags |= B_ERROR; ! 537: goto opdone; ! 538: } ! 539: ! 540: ignoreerr: ! 541: /* ! 542: * If we hit a tape mark update our position. ! 543: */ ! 544: if (sc->sc_dsreg & UTDS_TM && bp->b_flags & B_READ) { ! 545: /* ! 546: * Set blkno and nxrec ! 547: */ ! 548: if (bp == &cutbuf[UTUNIT(bp->b_dev)]) { ! 549: if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { ! 550: sc->sc_nxrec = ! 551: bdbtofsb(bp->b_blkno) - addr->utfc; ! 552: sc->sc_blkno = sc->sc_nxrec; ! 553: } else { ! 554: sc->sc_blkno = ! 555: bdbtofsb(bp->b_blkno) + addr->utfc; ! 556: sc->sc_nxrec = sc->sc_blkno-1; ! 557: } ! 558: } else ! 559: sc->sc_nxrec = bdbtofsb(bp->b_blkno); ! 560: /* ! 561: * Note: if we get a tape mark on a read, the ! 562: * frame count register will be zero, so b_resid ! 563: * will be calculated correctly below. ! 564: */ ! 565: goto opdone; ! 566: } ! 567: /* ! 568: * Advance tape control FSM. ! 569: */ ! 570: switch (state) { ! 571: ! 572: case SIO: /* read/write increments tape block # */ ! 573: sc->sc_blkno++; ! 574: break; ! 575: ! 576: case SCOM: /* motion commands update current position */ ! 577: if (bp == &cutbuf[UTUNIT(bp->b_dev)]) ! 578: switch (bp->b_command) { ! 579: ! 580: case UT_SFORW: ! 581: sc->sc_blkno -= bp->b_repcnt; ! 582: break; ! 583: ! 584: case UT_SREV: ! 585: sc->sc_blkno += bp->b_repcnt; ! 586: break; ! 587: ! 588: case UT_REWOFFL: ! 589: addr->utcs1 = UT_CLEAR|UT_GO; ! 590: break; ! 591: } ! 592: break; ! 593: ! 594: case SSEEK: ! 595: sc->sc_blkno = bdbtofsb(bp->b_blkno); ! 596: goto opcont; ! 597: ! 598: case SERASE: ! 599: /* ! 600: * Completed erase of the inter-record gap due to a ! 601: * write error; now retry the write operation. ! 602: */ ! 603: um->um_tab.b_state = SERASED; ! 604: goto opcont; ! 605: ! 606: case SREW: /* clear attention bit */ ! 607: addr->utcs1 = UT_CLEAR|UT_GO; ! 608: break; ! 609: ! 610: default: ! 611: printf("bad state %d\n", state); ! 612: panic("utintr"); ! 613: } ! 614: ! 615: opdone: ! 616: /* ! 617: * Reset error count and remove ! 618: * from device queue ! 619: */ ! 620: um->um_tab.b_errcnt = 0; ! 621: dp->b_actf = bp->av_forw; ! 622: /* ! 623: * For read command, frame count register contains ! 624: * actual length of tape record. Otherwise, it ! 625: * holds negative residual count. ! 626: */ ! 627: if (state == SIO && um->um_cmd == UT_RCOM) { ! 628: bp->b_resid = 0; ! 629: if (bp->b_bcount > MASKREG(addr->utfc)) ! 630: bp->b_resid = bp->b_bcount - MASKREG(addr->utfc); ! 631: } else ! 632: bp->b_resid = MASKREG(-addr->utfc); ! 633: ubadone(um); ! 634: iodone(bp); ! 635: /* ! 636: * Circulate slave to end of controller queue ! 637: * to give other slaves a chance ! 638: */ ! 639: um->um_tab.b_actf = dp->b_forw; ! 640: if (dp->b_actf) { ! 641: dp->b_forw = NULL; ! 642: if (um->um_tab.b_actf == NULL) ! 643: um->um_tab.b_actf = dp; ! 644: else ! 645: um->um_tab.b_actl->b_forw = dp; ! 646: um->um_tab.b_actl = dp; ! 647: } ! 648: if (um->um_tab.b_actf == 0) ! 649: return; ! 650: opcont: ! 651: utstart(um); ! 652: } ! 653: ! 654: /* ! 655: * Watchdog timer routine. ! 656: */ ! 657: uttimer(dev) ! 658: int dev; ! 659: { ! 660: register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; ! 661: register short x; ! 662: ! 663: if (sc->sc_timo != INF && (sc->sc_timo -= 5) < 0) { ! 664: printf("tj%d: lost interrupt\n", TJUNIT(dev)); ! 665: sc->sc_timo = INF; ! 666: x = spl5(); ! 667: utintr(UTUNIT(dev)); ! 668: (void) splx(x); ! 669: } ! 670: timeout(uttimer, (caddr_t)dev, 5*hz); ! 671: } ! 672: ! 673: /* ! 674: * Raw interface for a read ! 675: */ ! 676: utread(dev, uio) ! 677: dev_t dev; ! 678: struct uio *uio; ! 679: { ! 680: int errno; ! 681: ! 682: errno = utphys(dev, uio); ! 683: if (errno) ! 684: return (errno); ! 685: return (physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_READ, minphys, uio)); ! 686: } ! 687: ! 688: /* ! 689: * Raw interface for a write ! 690: */ ! 691: utwrite(dev, uio) ! 692: dev_t dev; ! 693: struct uio *uio; ! 694: { ! 695: int errno; ! 696: ! 697: errno = utphys(dev, uio); ! 698: if (errno) ! 699: return (errno); ! 700: return (physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_WRITE, minphys, uio)); ! 701: } ! 702: ! 703: /* ! 704: * Check for valid device number dev and update our notion ! 705: * of where we are on the tape ! 706: */ ! 707: utphys(dev, uio) ! 708: dev_t dev; ! 709: struct uio *uio; ! 710: { ! 711: register int tjunit = TJUNIT(dev); ! 712: register struct tj_softc *sc; ! 713: register struct uba_device *ui; ! 714: ! 715: if (tjunit >= NTJ || (ui=tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) ! 716: return (ENXIO); ! 717: sc = &tj_softc[tjunit]; ! 718: sc->sc_blkno = bdbtofsb(uio->uio_offset>>9); ! 719: sc->sc_nxrec = sc->sc_blkno+1; ! 720: return (0); ! 721: } ! 722: ! 723: /*ARGSUSED*/ ! 724: utioctl(dev, cmd, data, flag) ! 725: dev_t dev; ! 726: caddr_t data; ! 727: { ! 728: register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; ! 729: register struct buf *bp = &cutbuf[UTUNIT(dev)]; ! 730: register callcount; ! 731: int fcount; ! 732: struct mtop *mtop; ! 733: struct mtget *mtget; ! 734: /* we depend of the values and order of the MT codes here */ ! 735: static utops[] = ! 736: {UT_WEOF,UT_SFORWF,UT_SREVF,UT_SFORW,UT_SREV,UT_REW,UT_REWOFFL,UT_SENSE}; ! 737: ! 738: switch (cmd) { ! 739: ! 740: case MTIOCTOP: ! 741: mtop = (struct mtop *)data; ! 742: switch(mtop->mt_op) { ! 743: ! 744: case MTWEOF: ! 745: case MTFSF: case MTBSF: ! 746: case MTFSR: case MTBSR: ! 747: callcount = mtop->mt_count; ! 748: fcount = 1; ! 749: break; ! 750: ! 751: case MTREW: case MTOFFL: case MTNOP: ! 752: callcount = 1; ! 753: fcount = 1; ! 754: break; ! 755: ! 756: default: ! 757: return (ENXIO); ! 758: } ! 759: if (callcount <= 0 || fcount <= 0) ! 760: return (EINVAL); ! 761: while (--callcount >= 0) { ! 762: utcommand(dev, utops[mtop->mt_op], fcount); ! 763: if ((bp->b_flags&B_ERROR) || (sc->sc_dsreg&UTDS_BOT)) ! 764: break; ! 765: } ! 766: return (geterror(bp)); ! 767: ! 768: case MTIOCGET: ! 769: mtget = (struct mtget *)data; ! 770: mtget->mt_dsreg = sc->sc_dsreg; ! 771: mtget->mt_erreg = sc->sc_erreg; ! 772: mtget->mt_resid = sc->sc_resid; ! 773: mtget->mt_type = MT_ISUT; ! 774: break; ! 775: ! 776: default: ! 777: return (ENXIO); ! 778: } ! 779: return (0); ! 780: } ! 781: ! 782: utreset(uban) ! 783: int uban; ! 784: { ! 785: register struct uba_ctlr *um; ! 786: register ut11, tjunit; ! 787: register struct uba_device *ui; ! 788: register struct buf *dp; ! 789: ! 790: for (ut11 = 0; ut11 < NUT; ut11++) { ! 791: if ((um = utminfo[ut11]) == 0 || um->um_alive == 0 || ! 792: um->um_ubanum != uban) ! 793: continue; ! 794: printf(" ut%d", ut11); ! 795: um->um_tab.b_state = 0; ! 796: um->um_tab.b_actf = um->um_tab.b_actl = 0; ! 797: if (um->um_ubinfo) { ! 798: printf("<%d>", (um->um_ubinfo>>28)&0xf); ! 799: um->um_ubinfo = 0; ! 800: } ! 801: ((struct utdevice *)(um->um_addr))->utcs1 = UT_CLEAR|UT_GO; ! 802: ((struct utdevice *)(um->um_addr))->utcs2 |= UTCS2_CLR; ! 803: for (tjunit = 0; tjunit < NTJ; tjunit++) { ! 804: if ((ui = tjdinfo[tjunit]) == 0 || ui->ui_mi != um || ! 805: ui->ui_alive == 0) ! 806: continue; ! 807: dp = &tjutab[tjunit]; ! 808: dp->b_state = 0; ! 809: dp->b_forw = 0; ! 810: if (um->um_tab.b_actf == NULL) ! 811: um->um_tab.b_actf = dp; ! 812: else ! 813: um->um_tab.b_actl->b_forw = dp; ! 814: um->um_tab.b_actl = dp; ! 815: if (tj_softc[tjunit].sc_openf > 0) ! 816: tj_softc[tjunit].sc_openf = -1; ! 817: } ! 818: utstart(um); ! 819: } ! 820: } ! 821: ! 822: /* ! 823: * Do a stand-alone core dump to tape -- ! 824: * from here down, routines are used only in dump context ! 825: */ ! 826: #define DBSIZE 20 ! 827: ! 828: utdump() ! 829: { ! 830: register struct uba_device *ui; ! 831: register struct uba_regs *up; ! 832: register struct utdevice *addr; ! 833: int blk, num = maxfree; ! 834: int start = 0; ! 835: ! 836: #define phys(a,b) ((b)((int)(a)&0x7fffffff)) ! 837: if (tjdinfo[0] == 0) ! 838: return (ENXIO); ! 839: ui = phys(tjdinfo[0], struct uba_device *); ! 840: up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; ! 841: ubainit(up); ! 842: DELAY(1000000); ! 843: addr = (struct utdevice *)ui->ui_physaddr; ! 844: utwait(addr); ! 845: /* ! 846: * Be sure to set the appropriate density here. We use ! 847: * 6250, but maybe it should be done at 1600 to insure the ! 848: * tape can be read by most any other tape drive available. ! 849: */ ! 850: addr->uttc = UT_GCR|PDP11FMT; /* implicit slave 0 or-ed in */ ! 851: addr->utcs1 = UT_CLEAR|UT_GO; ! 852: while (num > 0) { ! 853: blk = num > DBSIZE ? DBSIZE : num; ! 854: utdwrite(start, blk, addr, up); ! 855: if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) ! 856: return(EIO); ! 857: start += blk; ! 858: num -= blk; ! 859: } ! 860: uteof(addr); ! 861: uteof(addr); ! 862: utwait(addr); ! 863: if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) ! 864: return(EIO); ! 865: addr->utcs1 = UT_REW|UT_GO; ! 866: return (0); ! 867: } ! 868: ! 869: utdwrite(dbuf, num, addr, up) ! 870: register dbuf, num; ! 871: register struct utdevice *addr; ! 872: struct uba_regs *up; ! 873: { ! 874: register struct pte *io; ! 875: register int npf; ! 876: ! 877: utwait(addr); ! 878: io = up->uba_map; ! 879: npf = num + 1; ! 880: while (--npf != 0) ! 881: *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); ! 882: *(int *)io = 0; ! 883: addr->utwc = -((num*NBPG)>>1); ! 884: addr->utfc = -(num*NBPG); ! 885: addr->utba = 0; ! 886: addr->utcs1 = UT_WCOM|UT_GO; ! 887: } ! 888: ! 889: utwait(addr) ! 890: struct utdevice *addr; ! 891: { ! 892: register s; ! 893: ! 894: do ! 895: s = addr->utds; ! 896: while ((s&UTDS_DRY) == 0); ! 897: } ! 898: ! 899: uteof(addr) ! 900: struct utdevice *addr; ! 901: { ! 902: ! 903: utwait(addr); ! 904: addr->utcs1 = UT_WEOF|UT_GO; ! 905: } ! 906: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.