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