|
|
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: * @(#)mt.c 7.3 (Berkeley) 6/6/88 ! 7: */ ! 8: ! 9: #include "mu.h" ! 10: #if NMT > 0 ! 11: /* ! 12: * TM78/TU78 tape driver ! 13: * ! 14: * Original author - ? ! 15: * Most error recovery bug fixes - ggs (ulysses!ggs) ! 16: * `read reverse' error recovery - ggs (ulysses!ggs) ! 17: * ! 18: * OPTIONS: ! 19: * MTLERRM - Long error message text - twd, Brown University ! 20: * ! 21: * TODO: ! 22: * Add odd byte count kludge from VMS driver (?) ! 23: * Write dump routine ! 24: */ ! 25: ! 26: #include "param.h" ! 27: #include "systm.h" ! 28: #include "buf.h" ! 29: #include "conf.h" ! 30: #include "dir.h" ! 31: #include "file.h" ! 32: #include "user.h" ! 33: #include "map.h" ! 34: #include "ioctl.h" ! 35: #include "mtio.h" ! 36: #include "cmap.h" ! 37: #include "uio.h" ! 38: #include "tty.h" ! 39: #include "syslog.h" ! 40: ! 41: #include "../vax/pte.h" ! 42: #include "../vax/cpu.h" ! 43: #include "mbareg.h" ! 44: #include "mbavar.h" ! 45: #include "mtreg.h" ! 46: ! 47: #define MTTIMEOUT 10000 /* loop limit for controller test */ ! 48: #define INF 1000000L /* a block number that won't exist */ ! 49: #define MASKREG(r) ((r) & 0xffff) /* the control registers have 16 bits */ ! 50: ! 51: /* Bits for sc_flags */ ! 52: ! 53: #define H_WRITTEN 01 /* last operation was a write */ ! 54: #define H_EOT 02 /* end of tape encountered */ ! 55: #define H_IEOT 04 /* ignore EOT condition */ ! 56: ! 57: int mt_do_readrev = 1; ! 58: ! 59: /* Per unit status information */ ! 60: ! 61: struct mu_softc { ! 62: char sc_openf; /* unit is open if != 0 */ ! 63: char sc_flags; /* state flags */ ! 64: daddr_t sc_blkno; /* current physical block number */ ! 65: daddr_t sc_nxrec; /* firewall input block number */ ! 66: u_short sc_erreg; /* copy of mter or mtner */ ! 67: u_short sc_dsreg; /* copy of mtds */ ! 68: short sc_resid; /* residual function count for ioctl */ ! 69: short sc_dens; /* density code - MT_GCR or zero */ ! 70: int sc_i_mtas; /* mtas at slave attach time */ ! 71: int sc_i_mtner; /* mtner at slave attach time */ ! 72: int sc_i_mtds; /* mtds at slave attach time */ ! 73: struct tty *sc_ttyp; /* record user's tty for errors */ ! 74: int sc_blks; /* number of I/O operations since open */ ! 75: int sc_softerrs; /* number of soft I/O errors since open */ ! 76: } mu_softc[NMU]; ! 77: ! 78: struct buf cmtbuf[NMT]; /* tape command buffer structures */ ! 79: ! 80: struct mba_device *mtinfo[NMT]; /* unit to ctlr structures */ ! 81: struct mba_slave *muinfo[NMU]; /* unit to slave structures */ ! 82: ! 83: char mtds_bits[] = MTDS_BITS; /* mtds bit names for error messages */ ! 84: short mttypes[] = { MBDT_TU78, 0 }; ! 85: ! 86: int mtattach(), mtslave(), mtustart(), mtstart(), mtndtint(), mtdtint(); ! 87: struct mba_driver mtdriver = ! 88: { mtattach, mtslave, mtustart, mtstart, mtdtint, mtndtint, ! 89: mttypes, "mt", "mu", mtinfo }; ! 90: ! 91: /* Bits in minor device */ ! 92: #define MUUNIT(dev) (minor(dev)&03) ! 93: #define H_NOREWIND 04 ! 94: #define H_6250BPI 010 ! 95: ! 96: #define MTUNIT(dev) (muinfo[MUUNIT(dev)]->ms_ctlr) ! 97: ! 98: void mtcreset(); ! 99: ! 100: /*ARGSUSED*/ ! 101: mtattach(mi) ! 102: struct mba_device *mi; ! 103: { ! 104: ! 105: /* void */ ! 106: } ! 107: ! 108: mtslave(mi, ms, sn) ! 109: struct mba_device *mi; ! 110: struct mba_slave *ms; ! 111: int sn; ! 112: { ! 113: register struct mu_softc *sc = &mu_softc[ms->ms_unit]; ! 114: register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; ! 115: int s = spl5(), rtn = 0, i; ! 116: ! 117: /* ! 118: * Just in case the controller is ill, reset it. Then issue ! 119: * a sense operation and wait about a second for it to respond. ! 120: */ ! 121: mtcreset(mtaddr); ! 122: mtaddr->mtas = -1; ! 123: mtaddr->mtncs[sn] = MT_SENSE|MT_GO; ! 124: for (i = MTTIMEOUT; i > 0; i--) { ! 125: DELAY(50); ! 126: if (MASKREG(mtaddr->mtas) != 0) ! 127: break; ! 128: } ! 129: sc->sc_i_mtas = mtaddr->mtas; ! 130: sc->sc_i_mtner = mtaddr->mtner; ! 131: sc->sc_i_mtds = mtaddr->mtds; ! 132: ! 133: /* ! 134: * If no response, whimper. If wrong response, call it an ! 135: * unsolicited interrupt and use mtndtint to log and correct. ! 136: * Otherwise, note whether this slave exists. ! 137: */ ! 138: if (i <= 0) ! 139: printf("mt: controller hung\n"); ! 140: else if ((mtaddr->mtner & MTER_INTCODE) != MTER_DONE) ! 141: (void) mtndtint(mi); ! 142: else if (mtaddr->mtds & MTDS_PRES) { ! 143: muinfo[ms->ms_unit] = ms; ! 144: rtn = 1; ! 145: } ! 146: ! 147: /* cancel the interrupt, then wait a little while for it to go away */ ! 148: mtaddr->mtas = mtaddr->mtas; ! 149: DELAY(10); ! 150: splx(s); ! 151: return (rtn); ! 152: } ! 153: ! 154: mtopen(dev, flag) ! 155: dev_t dev; ! 156: int flag; ! 157: { ! 158: register int muunit; ! 159: register struct mu_softc *sc; ! 160: register struct mba_slave *ms; ! 161: ! 162: muunit = MUUNIT(dev); ! 163: if (muunit >= NMU || (ms = muinfo[muunit]) == NULL || ! 164: ms->ms_alive == 0 || mtinfo[ms->ms_ctlr]->mi_alive == 0) ! 165: return (ENXIO); ! 166: if ((sc = &mu_softc[muunit])->sc_openf) ! 167: return (EBUSY); ! 168: sc->sc_openf = 1; ! 169: sc->sc_dens = (minor(dev) & H_6250BPI) ? MT_GCR : 0; ! 170: mtcommand(dev, MT_SENSE, 1); ! 171: if ((sc->sc_dsreg & MTDS_ONL) == 0) { ! 172: uprintf("mu%d: not online\n", muunit); ! 173: sc->sc_openf = 0; ! 174: return (EIO); ! 175: } ! 176: if ((sc->sc_dsreg & MTDS_AVAIL) == 0) { ! 177: uprintf("mu%d: not online (port selector)\n", muunit); ! 178: sc->sc_openf = 0; ! 179: return (EIO); ! 180: } ! 181: if ((flag & FWRITE) && (sc->sc_dsreg & MTDS_FPT)) { ! 182: uprintf("mu%d: no write ring\n", muunit); ! 183: sc->sc_openf = 0; ! 184: return (EIO); ! 185: } ! 186: if ((sc->sc_dsreg & MTDS_BOT) == 0 && (flag & FWRITE) && ! 187: (sc->sc_dens == MT_GCR) != ((sc->sc_dsreg & MTDS_PE) == 0)) { ! 188: uprintf("mu%d: can't change density in mid-tape\n", muunit); ! 189: sc->sc_openf = 0; ! 190: return (EIO); ! 191: } ! 192: sc->sc_blkno = (daddr_t)0; ! 193: ! 194: /* ! 195: * Since cooked I/O may do a read-ahead before a write, trash ! 196: * on a tape can make the first write fail. Suppress the first ! 197: * read-ahead unless definitely doing read-write. ! 198: */ ! 199: sc->sc_nxrec = ((flag & (FTRUNC | FWRITE)) == (FTRUNC | FWRITE)) ? ! 200: (daddr_t)0 : (daddr_t)INF; ! 201: sc->sc_flags = 0; ! 202: sc->sc_blks = 0; ! 203: sc->sc_softerrs = 0; ! 204: sc->sc_ttyp = u.u_ttyp; ! 205: return (0); ! 206: } ! 207: ! 208: mtclose(dev, flag) ! 209: register dev_t dev; ! 210: register int flag; ! 211: { ! 212: register struct mu_softc *sc = &mu_softc[MUUNIT(dev)]; ! 213: ! 214: if ((flag & (FREAD | FWRITE)) == FWRITE || ! 215: ((flag & FWRITE) && (sc->sc_flags & H_WRITTEN))) ! 216: mtcommand(dev, MT_CLS|sc->sc_dens, 1); ! 217: if ((minor(dev) & H_NOREWIND) == 0) ! 218: mtcommand(dev, MT_REW, 0); ! 219: if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100) ! 220: log(LOG_INFO, "mu%d: %d soft errors in %d blocks\n", ! 221: MUUNIT(dev), sc->sc_softerrs, sc->sc_blks); ! 222: sc->sc_openf = 0; ! 223: } ! 224: ! 225: mtcommand(dev, com, count) ! 226: dev_t dev; ! 227: int com, count; ! 228: { ! 229: register struct buf *bp; ! 230: int s; ! 231: ! 232: bp = &cmtbuf[MTUNIT(dev)]; ! 233: s = spl5(); ! 234: while (bp->b_flags & B_BUSY) { ! 235: if (bp->b_repcnt == 0 && (bp->b_flags & B_DONE)) ! 236: break; ! 237: bp->b_flags |= B_WANTED; ! 238: sleep((caddr_t)bp, PRIBIO); ! 239: } ! 240: bp->b_flags = B_BUSY|B_READ; ! 241: splx(s); ! 242: bp->b_dev = dev; ! 243: bp->b_command = com; ! 244: bp->b_repcnt = count; ! 245: bp->b_blkno = 0; ! 246: bp->b_error = 0; ! 247: mtstrategy(bp); ! 248: if (count == 0) ! 249: return; ! 250: biowait(bp); ! 251: if (bp->b_flags & B_WANTED) ! 252: wakeup((caddr_t)bp); ! 253: bp->b_flags &= B_ERROR; ! 254: } ! 255: ! 256: mtstrategy(bp) ! 257: register struct buf *bp; ! 258: { ! 259: register struct buf *dp; ! 260: struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)]; ! 261: int s; ! 262: ! 263: /* ! 264: * If this is a data transfer operation, set the resid to a ! 265: * default value (EOF) to simplify getting it right during ! 266: * error recovery or bail out. ! 267: */ ! 268: if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) ! 269: bp->b_resid = bp->b_bcount; ! 270: ! 271: /* ! 272: * Link this request onto the end of the queue for this ! 273: * controller, then start I/O if not already active. ! 274: */ ! 275: bp->av_forw = NULL; ! 276: dp = &mi->mi_tab; ! 277: s = spl5(); ! 278: if (dp->b_actf == NULL) ! 279: dp->b_actf = bp; ! 280: else ! 281: dp->b_actl->av_forw = bp; ! 282: dp->b_actl = bp; ! 283: if (dp->b_active == 0) ! 284: mbustart(mi); ! 285: splx(s); ! 286: } ! 287: ! 288: mtustart(mi) ! 289: register struct mba_device *mi; ! 290: { ! 291: register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; ! 292: register struct buf *bp = mi->mi_tab.b_actf; ! 293: register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)]; ! 294: daddr_t blkno; ! 295: int count; ! 296: ! 297: if (sc->sc_openf < 0) { ! 298: bp->b_flags |= B_ERROR; ! 299: return (MBU_NEXT); ! 300: } ! 301: if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) { ! 302: /* ! 303: * Data transfer. If write at end of tape, ! 304: * signal "no space" unless suppressed ! 305: * by MTIOCIEOT. ! 306: */ ! 307: if ((sc->sc_flags & (H_EOT | H_IEOT)) == H_EOT && ! 308: (bp->b_flags & B_READ) == 0) { ! 309: bp->b_flags |= B_ERROR; ! 310: bp->b_error = ENOSPC; ! 311: return (MBU_NEXT); ! 312: } ! 313: ! 314: if (bp->b_flags & B_RAW) { ! 315: /* raw transfer; never seek */ ! 316: sc->sc_blkno = bdbtofsb(bp->b_blkno); ! 317: sc->sc_nxrec = sc->sc_blkno + 1; ! 318: } else { ! 319: /* seek beyond end of file */ ! 320: if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { ! 321: bp->b_flags |= B_ERROR; ! 322: bp->b_error = ENXIO; ! 323: return (MBU_NEXT); ! 324: } ! 325: ! 326: /* ! 327: * This should be end of file, but the buffer ! 328: * system wants a one-block look-ahead. Humor it. ! 329: */ ! 330: if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && ! 331: bp->b_flags & B_READ) { ! 332: bp->b_resid = bp->b_bcount; ! 333: clrbuf(bp); ! 334: return (MBU_NEXT); ! 335: } ! 336: ! 337: /* If writing, mark the next block invalid. */ ! 338: if ((bp->b_flags & B_READ) == 0) ! 339: sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; ! 340: } ! 341: } else { ! 342: /* It's a command, do it now. */ ! 343: mtaddr->mtncs[MUUNIT(bp->b_dev)] = ! 344: (bp->b_repcnt<<8)|bp->b_command|MT_GO; ! 345: return (MBU_STARTED); ! 346: } ! 347: ! 348: /* ! 349: * If raw I/O, or if the tape is positioned correctly for ! 350: * cooked I/O, set the byte count, unit number and repeat count ! 351: * then tell the MASSBUS to proceed. Note that a negative ! 352: * bcount tells mbstart to map the buffer for "read backwards". ! 353: */ ! 354: if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { ! 355: if (mi->mi_tab.b_errcnt == 2) { ! 356: mtaddr->mtbc = -bp->b_bcount; ! 357: mtaddr->mtca = MUUNIT(bp->b_dev); ! 358: } else { ! 359: mtaddr->mtbc = bp->b_bcount; ! 360: mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev); ! 361: } ! 362: return (MBU_DODATA); ! 363: } ! 364: ! 365: /* Issue skip operations to position the next block for cooked I/O. */ ! 366: ! 367: if (blkno < bdbtofsb(bp->b_blkno)) ! 368: count = bdbtofsb(bp->b_blkno) - blkno; ! 369: else ! 370: count = blkno - bdbtofsb(bp->b_blkno); ! 371: if ((unsigned)count > 0377) ! 372: count = 0377; ! 373: mtaddr->mtncs[MUUNIT(bp->b_dev)] = count | MT_SFORW|MT_GO; ! 374: return (MBU_STARTED); ! 375: } ! 376: ! 377: mtstart(mi) ! 378: register struct mba_device *mi; ! 379: { ! 380: register struct buf *bp = mi->mi_tab.b_actf; ! 381: register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)]; ! 382: ! 383: if (bp->b_flags & B_READ) ! 384: if (mi->mi_tab.b_errcnt == 2) ! 385: return (MT_READREV|MT_GO); ! 386: else ! 387: return (MT_READ|MT_GO); ! 388: else ! 389: return (MT_WRITE|sc->sc_dens|MT_GO); ! 390: } ! 391: ! 392: mtdtint(mi, mbsr) ! 393: register struct mba_device *mi; ! 394: int mbsr; ! 395: { ! 396: register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; ! 397: register struct buf *bp = mi->mi_tab.b_actf; ! 398: register struct mu_softc *sc; ! 399: register int er; ! 400: ! 401: /* I'M still NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */ ! 402: if ((mtaddr->mtca & 3) != MUUNIT(bp->b_dev)) { ! 403: printf("mt: wrong unit!\n"); ! 404: mtaddr->mtca = MUUNIT(bp->b_dev); ! 405: } ! 406: ! 407: er = MASKREG(mtaddr->mter); ! 408: sc = &mu_softc[MUUNIT(bp->b_dev)]; ! 409: sc->sc_erreg = er; ! 410: if (bp->b_flags & B_READ) ! 411: sc->sc_flags &= ~H_WRITTEN; ! 412: else ! 413: sc->sc_flags |= H_WRITTEN; ! 414: switch (er & MTER_INTCODE) { ! 415: ! 416: case MTER_EOT: ! 417: sc->sc_flags |= H_EOT; ! 418: /* fall into MTER_DONE */ ! 419: ! 420: case MTER_DONE: ! 421: sc->sc_blkno++; ! 422: if (mi->mi_tab.b_errcnt == 2) { ! 423: bp->b_bcount = bp->b_resid; ! 424: bp->b_resid -= MASKREG(mtaddr->mtbc); ! 425: if (bp->b_resid > 0 && (bp->b_flags & B_RAW) == 0) ! 426: bp->b_flags |= B_ERROR; ! 427: } else ! 428: bp->b_resid = 0; ! 429: break; ! 430: ! 431: case MTER_SHRTREC: ! 432: sc->sc_blkno++; ! 433: bp->b_bcount = bp->b_resid; ! 434: bp->b_resid -= MASKREG(mtaddr->mtbc); ! 435: if ((bp->b_flags & B_RAW) == 0) ! 436: bp->b_flags |= B_ERROR; ! 437: break; ! 438: ! 439: case MTER_RETRY: ! 440: /* ! 441: * Simple re-try. Since resid is always a copy of the ! 442: * original byte count, use it to restore the count. ! 443: */ ! 444: mi->mi_tab.b_errcnt = 1; ! 445: bp->b_bcount = bp->b_resid; ! 446: return (MBD_RETRY); ! 447: ! 448: case MTER_RDOPP: ! 449: /* ! 450: * The controller just decided to read it backwards. ! 451: * If the controller returns a byte count of zero, ! 452: * change it to 1, since zero encodes 65536, which ! 453: * isn't quite what we had in mind. The byte count ! 454: * may be larger than the size of the input buffer, so ! 455: * limit the count to the buffer size. After ! 456: * making the byte count reasonable, set bcount to the ! 457: * negative of the controller's version of the byte ! 458: * count so that the start address for the transfer is ! 459: * set up correctly. ! 460: */ ! 461: if (mt_do_readrev) { ! 462: mi->mi_tab.b_errcnt = 2; ! 463: if ((bp->b_bcount = MASKREG(mtaddr->mtbc)) == 0) ! 464: bp->b_bcount = 1; ! 465: if (bp->b_bcount > bp->b_resid) ! 466: bp->b_bcount = bp->b_resid; ! 467: bp->b_bcount = -(bp->b_bcount); ! 468: return(MBD_RETRY); ! 469: } else if (MASKREG(mtaddr->mtbc) <= bp->b_resid) { ! 470: sc->sc_blkno++; ! 471: bp->b_bcount = bp->b_resid; ! 472: bp->b_resid -= MASKREG(mtaddr->mtbc); ! 473: bp->b_flags |= B_ERROR; ! 474: break; ! 475: } ! 476: bp->b_flags |= B_ERROR; ! 477: /* fall into MTER_LONGREC */ ! 478: ! 479: case MTER_LONGREC: ! 480: sc->sc_blkno++; ! 481: bp->b_bcount = bp->b_resid; ! 482: bp->b_resid = 0; ! 483: bp->b_error = ENOMEM; ! 484: bp->b_flags |= B_ERROR; ! 485: break; ! 486: ! 487: case MTER_NOTCAP: ! 488: printf("mu%d: blank tape\n", MUUNIT(bp->b_dev)); ! 489: goto err; ! 490: ! 491: case MTER_TM: ! 492: /* ! 493: * End of file. Since the default byte count has ! 494: * already been set, just count the block and proceed. ! 495: */ ! 496: sc->sc_blkno++; ! 497: err: ! 498: sc->sc_nxrec = bdbtofsb(bp->b_blkno); ! 499: break; ! 500: ! 501: case MTER_OFFLINE: ! 502: if (sc->sc_openf > 0) { ! 503: sc->sc_openf = -1; ! 504: tprintf(sc->sc_ttyp, "mu%d: offline\n", ! 505: MUUNIT(bp->b_dev)); ! 506: } ! 507: bp->b_flags |= B_ERROR; ! 508: break; ! 509: ! 510: case MTER_NOTAVL: ! 511: if (sc->sc_openf > 0) { ! 512: sc->sc_openf = -1; ! 513: tprintf(sc->sc_ttyp, "mu%d: offline (port selector)\n", ! 514: MUUNIT(bp->b_dev)); ! 515: } ! 516: bp->b_flags |= B_ERROR; ! 517: break; ! 518: ! 519: case MTER_FPT: ! 520: tprintf(sc->sc_ttyp, "mu%d: no write ring\n", ! 521: MUUNIT(bp->b_dev)); ! 522: bp->b_flags |= B_ERROR; ! 523: break; ! 524: ! 525: case MTER_UNREAD: ! 526: sc->sc_blkno++; ! 527: bp->b_bcount = bp->b_resid; ! 528: bp->b_resid -= MIN(MASKREG(mtaddr->mtbc), bp->b_bcount); ! 529: ! 530: /* code 010 means a garbage record, nothing serious. */ ! 531: if ((er & MTER_FAILCODE) == (010 << MTER_FSHIFT)) { ! 532: tprintf(sc->sc_ttyp, ! 533: "mu%d: rn=%d bn=%d unreadable record\n", ! 534: MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno); ! 535: bp->b_flags |= B_ERROR; ! 536: break; ! 537: } ! 538: ! 539: /* ! 540: * Anything else might be a hardware problem, ! 541: * fall into the error report. ! 542: */ ! 543: ! 544: default: ! 545: /* ! 546: * The bits in sc->sc_dsreg are from the last sense ! 547: * command. To get the most recent copy, you have to ! 548: * do a sense at interrupt level, which requires nested ! 549: * error processing. This is a bit messy, so leave ! 550: * well enough alone. ! 551: */ ! 552: tprintf(sc->sc_ttyp, "\ ! 553: mu%d: hard error (data transfer) rn=%d bn=%d mbsr=%b er=0%o ds=%b\n", ! 554: MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno, ! 555: mbsr, mbsr_bits, er, ! 556: MASKREG(sc->sc_dsreg), mtds_bits); ! 557: #ifdef MTLERRM ! 558: mtintfail(er); ! 559: #endif ! 560: bp->b_flags |= B_ERROR; ! 561: ! 562: /* ! 563: * The TM78 manual says to reset the controller after ! 564: * TM fault B or MASSBUS fault. ! 565: */ ! 566: if ((er & MTER_INTCODE) == MTER_TMFLTB || ! 567: (er & MTER_INTCODE) == MTER_MBFLT) ! 568: mtcreset(mtaddr); ! 569: } ! 570: ! 571: /* ! 572: * Just in case some strange error slipped through (drive off ! 573: * line during read-reverse error recovery comes to mind), make ! 574: * sure the byte count is reasonable. ! 575: */ ! 576: if (bp->b_bcount < 0) ! 577: bp->b_bcount = bp->b_resid; ! 578: ! 579: if ((bp->b_flags & B_ERROR) == 0) { ! 580: /* this counts reverse reads as soft errors */ ! 581: sc->sc_blks++; ! 582: if (mi->mi_tab.b_errcnt) /* alternatively, if == 1 */ ! 583: sc->sc_softerrs++; ! 584: } ! 585: return (MBD_DONE); ! 586: } ! 587: ! 588: mtndtint(mi) ! 589: register struct mba_device *mi; ! 590: { ! 591: register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; ! 592: register struct buf *bp = mi->mi_tab.b_actf; ! 593: register struct mu_softc *sc; ! 594: register int er, fc; ! 595: int unit; ! 596: ! 597: unit = (mtaddr->mtner >> 8) & 3; ! 598: er = MASKREG(mtaddr->mtner); ! 599: sc = &mu_softc[unit]; ! 600: sc->sc_erreg = er; ! 601: ! 602: /* Check for unsolicited interrupts. */ ! 603: if (bp == NULL || unit != MUUNIT(bp->b_dev)) { ! 604: if ((er & MTER_INTCODE) == MTER_ONLINE) ! 605: return (MBN_SKIP); ! 606: ! 607: printf("mu%d: stray intr (non data transfer) er=0%o ds=%b\n", ! 608: unit, er, MASKREG(sc->sc_dsreg), mtds_bits); ! 609: #ifdef MTLERRM ! 610: mtintfail(er); ! 611: #endif ! 612: if ((er & MTER_INTCODE) == MTER_TMFLTB || ! 613: (er & MTER_INTCODE) == MTER_MBFLT) { ! 614: /* ! 615: * Reset the controller, then set error status ! 616: * if there was anything active when the fault ! 617: * occurred. This may shoot an innocent ! 618: * bystander, but it's better than letting ! 619: * an error slip through. ! 620: */ ! 621: mtcreset(mtaddr); ! 622: if (bp != NULL) { ! 623: bp->b_flags |= B_ERROR; ! 624: return (MBN_DONE); ! 625: } ! 626: } ! 627: return (MBN_SKIP); ! 628: } ! 629: ! 630: fc = (mtaddr->mtncs[unit] >> 8) & 0xff; ! 631: sc->sc_resid = fc; ! 632: ! 633: /* ! 634: * Clear the "written" flag after any operation that changes ! 635: * the position of the tape. ! 636: */ ! 637: if (bp != &cmtbuf[MTUNIT(bp->b_dev)] || bp->b_command != MT_SENSE) ! 638: sc->sc_flags &= ~H_WRITTEN; ! 639: ! 640: switch (er & MTER_INTCODE) { ! 641: ! 642: case MTER_EOT: ! 643: sc->sc_flags |= H_EOT; ! 644: /* fall into MTER_DONE */ ! 645: ! 646: case MTER_DONE: ! 647: /* If this is a command buffer, just update the status. */ ! 648: if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) { ! 649: done: ! 650: if (bp->b_command == MT_SENSE) ! 651: sc->sc_dsreg = MASKREG(mtaddr->mtds); ! 652: return (MBN_DONE); ! 653: } ! 654: ! 655: /* ! 656: * It's not a command buffer, must be a cooked I/O ! 657: * skip operation (perhaps a shaky assumption, but it ! 658: * wasn't my idea). ! 659: */ ! 660: if ((fc = bdbtofsb(bp->b_blkno) - sc->sc_blkno) < 0) ! 661: sc->sc_blkno -= MIN(0377, -fc); ! 662: else ! 663: sc->sc_blkno += MIN(0377, fc); ! 664: return (MBN_RETRY); ! 665: ! 666: case MTER_ONLINE: /* ddj -- shouldn't happen but did */ ! 667: case MTER_RWDING: ! 668: return (MBN_SKIP); /* ignore "rewind started" interrupt */ ! 669: ! 670: case MTER_NOTCAP: ! 671: tprintf(sc->sc_ttyp, "mu%d: blank tape\n", MUUNIT(bp->b_dev)); ! 672: bp->b_flags |= B_ERROR; ! 673: return (MBN_DONE); ! 674: ! 675: case MTER_TM: ! 676: case MTER_LEOT: ! 677: /* ! 678: * For an ioctl skip operation, count a tape mark as ! 679: * a record. If there's anything left to do, update ! 680: * the repeat count and re-start the command. ! 681: */ ! 682: if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) { ! 683: if ((sc->sc_resid = bp->b_repcnt = fc - 1) == 0) ! 684: return (MBN_DONE); ! 685: else ! 686: return (MBN_RETRY); ! 687: } else { ! 688: /* ! 689: * Cooked I/O again. Just update the books and ! 690: * wait for someone else to return end of file or ! 691: * complain about a bad seek. ! 692: */ ! 693: if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { ! 694: sc->sc_nxrec = bdbtofsb(bp->b_blkno) + fc - 1; ! 695: sc->sc_blkno = sc->sc_nxrec; ! 696: } else { ! 697: sc->sc_nxrec = bdbtofsb(bp->b_blkno) - fc; ! 698: sc->sc_blkno = sc->sc_nxrec + 1; ! 699: } ! 700: } ! 701: return (MBN_RETRY); ! 702: ! 703: case MTER_FPT: ! 704: tprintf(sc->sc_ttyp, "mu%d: no write ring\n", ! 705: MUUNIT(bp->b_dev)); ! 706: bp->b_flags |= B_ERROR; ! 707: return (MBN_DONE); ! 708: ! 709: case MTER_OFFLINE: ! 710: /* If `off line' was intentional, don't complain. */ ! 711: if (bp == &cmtbuf[MTUNIT(bp->b_dev)] && ! 712: bp->b_command == MT_UNLOAD) ! 713: return(MBN_DONE); ! 714: if (sc->sc_openf > 0) { ! 715: sc->sc_openf = -1; ! 716: tprintf(sc->sc_ttyp, "mu%d: offline\n", ! 717: MUUNIT(bp->b_dev)); ! 718: } ! 719: bp->b_flags |= B_ERROR; ! 720: return (MBN_DONE); ! 721: ! 722: case MTER_NOTAVL: ! 723: if (sc->sc_openf > 0) { ! 724: sc->sc_openf = -1; ! 725: tprintf(sc->sc_ttyp, "mu%d: offline (port selector)\n", ! 726: MUUNIT(bp->b_dev)); ! 727: } ! 728: bp->b_flags |= B_ERROR; ! 729: return (MBN_DONE); ! 730: ! 731: case MTER_BOT: ! 732: if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) ! 733: goto done; ! 734: /* fall through */ ! 735: ! 736: default: ! 737: tprintf(sc->sc_ttyp, "\ ! 738: mu%d: hard error (non data transfer) rn=%d bn=%d er=0%o ds=%b\n", ! 739: MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno, ! 740: er, MASKREG(sc->sc_dsreg), mtds_bits); ! 741: #ifdef MTLERRM ! 742: mtintfail(er); ! 743: #endif ! 744: if ((er & MTER_INTCODE) == MTER_TMFLTB || ! 745: (er & MTER_INTCODE) == MTER_MBFLT) ! 746: mtcreset(mtaddr); /* reset the controller */ ! 747: bp->b_flags |= B_ERROR; ! 748: return (MBN_DONE); ! 749: } ! 750: /* NOTREACHED */ ! 751: } ! 752: ! 753: void ! 754: mtcreset(mtaddr) ! 755: register struct mtdevice *mtaddr; ! 756: { ! 757: register int i; ! 758: ! 759: mtaddr->mtid = MTID_CLR; /* reset the TM78 */ ! 760: DELAY(200); ! 761: for (i = MTTIMEOUT; i > 0; i--) { ! 762: DELAY(50); /* don't nag */ ! 763: if ((mtaddr->mtid & MTID_RDY) != 0) ! 764: return; /* exit when ready */ ! 765: } ! 766: printf("mt: controller hung\n"); ! 767: } ! 768: ! 769: /*ARGSUSED*/ ! 770: mtioctl(dev, cmd, data, flag) ! 771: dev_t dev; ! 772: int cmd; ! 773: caddr_t data; ! 774: int flag; ! 775: { ! 776: register struct mu_softc *sc = &mu_softc[MUUNIT(dev)]; ! 777: register struct buf *bp = &cmtbuf[MTUNIT(dev)]; ! 778: register struct mtop *mtop; ! 779: register struct mtget *mtget; ! 780: int callcount, fcount; ! 781: int op; ! 782: ! 783: /* We depend on the values and order of the MT codes here. */ ! 784: ! 785: static mtops[] = ! 786: {MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE}; ! 787: ! 788: switch (cmd) { ! 789: ! 790: /* tape operation */ ! 791: ! 792: case MTIOCTOP: ! 793: mtop = (struct mtop *)data; ! 794: switch (mtop->mt_op) { ! 795: ! 796: case MTWEOF: ! 797: callcount = mtop->mt_count; ! 798: fcount = 1; ! 799: break; ! 800: ! 801: case MTFSF: case MTBSF: ! 802: callcount = mtop->mt_count; ! 803: fcount = 1; ! 804: break; ! 805: ! 806: case MTFSR: case MTBSR: ! 807: callcount = 1; ! 808: fcount = mtop->mt_count; ! 809: break; ! 810: ! 811: case MTREW: case MTOFFL: ! 812: callcount = 1; ! 813: fcount = 1; ! 814: break; ! 815: ! 816: default: ! 817: return (ENXIO); ! 818: } ! 819: if (callcount <= 0 || fcount <= 0) ! 820: return (EINVAL); ! 821: op = mtops[mtop->mt_op]; ! 822: if (op == MT_WTM) ! 823: op |= sc->sc_dens; ! 824: while (--callcount >= 0) { ! 825: register int n, fc = fcount; ! 826: ! 827: do { ! 828: n = MIN(fc, 0xff); ! 829: mtcommand(dev, op, n); ! 830: n -= sc->sc_resid; ! 831: fc -= n; ! 832: switch (mtop->mt_op) { ! 833: ! 834: case MTWEOF: ! 835: sc->sc_blkno += (daddr_t)n; ! 836: sc->sc_nxrec = sc->sc_blkno - 1; ! 837: break; ! 838: ! 839: case MTOFFL: ! 840: case MTREW: ! 841: case MTFSF: ! 842: sc->sc_blkno = (daddr_t)0; ! 843: sc->sc_nxrec = (daddr_t)INF; ! 844: break; ! 845: ! 846: case MTBSF: ! 847: if (sc->sc_resid) { ! 848: sc->sc_blkno = (daddr_t)0; ! 849: sc->sc_nxrec = (daddr_t)INF; ! 850: } else { ! 851: sc->sc_blkno = (daddr_t)(-1); ! 852: sc->sc_nxrec = (daddr_t)(-1); ! 853: } ! 854: break; ! 855: ! 856: case MTFSR: ! 857: sc->sc_blkno += (daddr_t)n; ! 858: break; ! 859: ! 860: case MTBSR: ! 861: sc->sc_blkno -= (daddr_t)n; ! 862: break; ! 863: } ! 864: if (sc->sc_resid) ! 865: break; ! 866: } while (fc); ! 867: if (fc) { ! 868: sc->sc_resid = callcount + fc; ! 869: if (mtop->mt_op == MTFSR || ! 870: mtop->mt_op == MTBSR) ! 871: return (EIO); ! 872: break; ! 873: } ! 874: if (bp->b_flags & B_ERROR) ! 875: break; ! 876: } ! 877: return (geterror(bp)); ! 878: ! 879: /* tape status */ ! 880: case MTIOCGET: ! 881: mtget = (struct mtget *)data; ! 882: mtget->mt_erreg = sc->sc_erreg; ! 883: mtget->mt_resid = sc->sc_resid; ! 884: mtcommand(dev, MT_SENSE, 1); /* update drive status */ ! 885: mtget->mt_dsreg = sc->sc_dsreg; ! 886: mtget->mt_type = MT_ISMT; ! 887: break; ! 888: ! 889: /* ignore EOT condition */ ! 890: case MTIOCIEOT: ! 891: sc->sc_flags |= H_IEOT; ! 892: break; ! 893: ! 894: /* enable EOT condition */ ! 895: case MTIOCEEOT: ! 896: sc->sc_flags &= ~H_IEOT; ! 897: break; ! 898: ! 899: default: ! 900: return (ENXIO); ! 901: } ! 902: return (0); ! 903: } ! 904: ! 905: #define DBSIZE 20 ! 906: ! 907: mtdump() ! 908: { ! 909: register struct mba_device *mi; ! 910: register struct mba_regs *mp; ! 911: int blk, num; ! 912: int start; ! 913: ! 914: start = 0; ! 915: num = maxfree; ! 916: #define phys(a,b) ((b)((int)(a)&0x7fffffff)) ! 917: if (mtinfo[0] == 0) ! 918: return (ENXIO); ! 919: mi = phys(mtinfo[0], struct mba_device *); ! 920: mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba; ! 921: mp->mba_cr = MBCR_IE; ! 922: #if lint ! 923: blk = 0; num = blk; start = num; blk = start; ! 924: return (0); ! 925: #endif ! 926: #ifdef notyet ! 927: mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive]; ! 928: mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI; ! 929: mtaddr->mtcs1 = MT_DCLR|MT_GO; ! 930: while (num > 0) { ! 931: blk = num > DBSIZE ? DBSIZE : num; ! 932: mtdwrite(start, blk, mtaddr, mp); ! 933: start += blk; ! 934: num -= blk; ! 935: } ! 936: mteof(mtaddr); ! 937: mteof(mtaddr); ! 938: mtwait(mtaddr); ! 939: if (mtaddr->mtds&MTDS_ERR) ! 940: return (EIO); ! 941: mtaddr->mtcs1 = MT_REW|MT_GO; ! 942: return (0); ! 943: } ! 944: ! 945: mtdwrite(dbuf, num, mtaddr, mp) ! 946: register dbuf, num; ! 947: register struct mtdevice *mtaddr; ! 948: struct mba_regs *mp; ! 949: { ! 950: register struct pte *io; ! 951: register int i; ! 952: ! 953: mtwait(mtaddr); ! 954: io = mp->mba_map; ! 955: for (i = 0; i < num; i++) ! 956: *(int *)io++ = dbuf++ | PG_V; ! 957: mtaddr->mtfc = -(num*NBPG); ! 958: mp->mba_sr = -1; ! 959: mp->mba_bcr = -(num*NBPG); ! 960: mp->mba_var = 0; ! 961: mtaddr->mtcs1 = MT_WCOM|MT_GO; ! 962: } ! 963: ! 964: mtwait(mtaddr) ! 965: struct mtdevice *mtaddr; ! 966: { ! 967: register s; ! 968: ! 969: do ! 970: s = mtaddr->mtds; ! 971: while ((s & MTDS_DRY) == 0); ! 972: } ! 973: ! 974: mteof(mtaddr) ! 975: struct mtdevice *mtaddr; ! 976: { ! 977: ! 978: mtwait(mtaddr); ! 979: mtaddr->mtcs1 = MT_WEOF|MT_GO; ! 980: #endif notyet ! 981: } ! 982: ! 983: #ifdef MTLERRM ! 984: /* ! 985: * Failure messages for each failure code, per interrupt code. ! 986: * Each table ends with a code of -1 as a default. ! 987: */ ! 988: struct fmesg { ! 989: int f_code; ! 990: char *f_mesg; ! 991: }; ! 992: ! 993: static char unclass[] = "unclassified failure code"; ! 994: ! 995: /* MTER_BOT */ ! 996: static struct fmesg botmsg[] = { ! 997: 01, "tape was at BOT", ! 998: 02, "BOT seen after tape started", ! 999: 03, "ARA ID detected", ! 1000: -1, unclass ! 1001: }; ! 1002: ! 1003: /* MTER_NOTRDY */ ! 1004: static struct fmesg notrdymsg[] = { ! 1005: 01, "TU on-line but not ready", ! 1006: 02, "fatal error has occurred", ! 1007: 03, "access allowed by not really" ! 1008: -1, unclass ! 1009: }; ! 1010: ! 1011: /* MTER_NOTCAP */ ! 1012: static struct fmesg notcapmsg[] = { ! 1013: 01, "no record found within 25 feet", ! 1014: 02, "ID burst neither PE nor GCR", ! 1015: 03, "ARA ID not found", ! 1016: 04, "no gap found after ID burst", ! 1017: -1, unclass ! 1018: }; ! 1019: ! 1020: /* MTER_LONGREC */ ! 1021: static struct fmesg longrecmsg[] = { ! 1022: 00, "extended sense data not found", ! 1023: 01, "extended sense data updated", ! 1024: -1, unclass ! 1025: }; ! 1026: ! 1027: /* MTER_UNREAD, MTER_ERROR, MTER_EOTERR, MTER_BADTAPE */ ! 1028: static struct fmesg code22msg[] = { ! 1029: 01, "GCR write error", ! 1030: 02, "GCR read error", ! 1031: 03, "PE read error", ! 1032: 04, "PE write error", ! 1033: 05, "at least 1 bit set in ECCSTA", ! 1034: 06, "PE write error", ! 1035: 07, "GCR write error", ! 1036: 010, "RSTAT contains bad code", ! 1037: 011, "PE write error", ! 1038: 012, "MASSBUS parity error", ! 1039: 013, "invalid data transferred", ! 1040: -1, unclass ! 1041: }; ! 1042: ! 1043: /* MTER_TMFLTA */ ! 1044: static struct fmesg tmfltamsg[] = { ! 1045: 01, "illegal command code", ! 1046: 02, "DT command issued when NDT command active", ! 1047: 03, "WMC error", ! 1048: 04, "RUN not received from MASSBUS controller", ! 1049: 05, "mismatch in command read - function routine", ! 1050: 06, "ECC ROM parity error", ! 1051: 07, "XMC ROM parity error", ! 1052: 010, "mismatch in command read - ID burst command", ! 1053: 011, "mismatch in command read - verify ARA burst command", ! 1054: 012, "mismatch in command read - verify ARA ID command", ! 1055: 013, "mismatch in command read - verify gap command", ! 1056: 014, "mismatch in command read - read id burst command", ! 1057: 015, "mismatch in command read - verify ARA ID command", ! 1058: 016, "mismatch in command read - verify gap command", ! 1059: 017, "mismatch in command read - find gap command", ! 1060: 020, "WMC LEFT failed to set", ! 1061: 021, "XL PE set in INTSTA register", ! 1062: 022, "XMC DONE did not set", ! 1063: 023, "WMC ROM PE or RD PE set in WMCERR register", ! 1064: -1, unclass ! 1065: }; ! 1066: ! 1067: /* MTER_TUFLTA */ ! 1068: static struct fmesg tufltamsg[] = { ! 1069: 01, "TU status parity error", ! 1070: 02, "TU command parity error", ! 1071: 03, "rewinding tape went offline", ! 1072: 04, "tape went not ready during DSE", ! 1073: 05, "TU CMD status changed during DSE", ! 1074: 06, "TU never came up to speed", ! 1075: 07, "TU velocity changed", ! 1076: 010, "TU CMD did not load correctly to start tape motion", ! 1077: 011, "TU CMD did not load correctly to set drive density", ! 1078: 012, "TU CMD did not load correctly to start tape motion to write BOT ID", ! 1079: 013, "TU CMD did not load correctly to backup tape to BOT after failing to write BOT ID", ! 1080: 014, "failed to write density ID burst", ! 1081: 015, "failed to write ARA burst", ! 1082: 016, "failed to write ARA ID", ! 1083: 017, "ARA error bit set in MTA status B register", ! 1084: 021, "could not find a gap after ID code was written correctly", ! 1085: 022, "TU CMD did not load correctly to start tape motion to read ID burst", ! 1086: 023, "timeout looking for BOT after detecting ARA ID burst", ! 1087: 024, "failed to write tape mark", ! 1088: 025, "tape never came up to speed while trying to reposition for retry of writing tape mark", ! 1089: 026, "TU CMD did not load correctly to start tape motion in erase gap routine", ! 1090: 027, "could not detect a gap in in erase gap routine", ! 1091: 030, "could not detect a gap after writing record", ! 1092: 031, "read path terminated before entire record was written", ! 1093: 032, "could not find a gap after writing record and read path terminated early", ! 1094: 033, "TU CMD did not load correctly to backup for retry of write tape mark", ! 1095: 034, "TU velocity changed after up to speed while trying to reposition for retry of writing tape mark", ! 1096: 035, "TU CMD did not load correctly to backup to retry a load of BOT ID", ! 1097: 036, "timeout looking for BOT after failing to write BOT ID", ! 1098: 037, "TU velocity changed while writing PE gap before starting to write record", ! 1099: 040, "TU CMD did not load correctly to set PE tape density at start of write BOT ID burst", ! 1100: 041, "TU CMD did not load correctly to set GCR tape density after writing Density ID", ! 1101: 042, "TU CMD did not load correctly to set PE tape density at start of read from BOT", ! 1102: 043, "TU CMD did not load correctly to set GCR tape density after reading a GCR Density ID burst", ! 1103: }; ! 1104: ! 1105: /* MTER_TMFLTB */ ! 1106: static char inlinetest[] = "inline test failed"; ! 1107: static struct fmesg tmfltbmsg[] = { ! 1108: 00, "RST0 interrupt occurred with TM RDY set", ! 1109: 01, "power failed to interrupt", ! 1110: 02, "unknown interrupt on channel 5.5", ! 1111: 03, "unknown interrupt on channel 6.5", ! 1112: 04, "unknown interrupt on channel 7", ! 1113: 05, "unknown interrupt on channel 7.5", ! 1114: 06, "CAS contention retry count expired", ! 1115: 07, "CAS contention error not retryable", ! 1116: 010, "queue error, could not find queue entry", ! 1117: 011, "queue entry already full", ! 1118: 012, "8085 ROM parity error", ! 1119: 013, inlinetest, ! 1120: 013, inlinetest, ! 1121: 014, inlinetest, ! 1122: 015, inlinetest, ! 1123: 016, inlinetest, ! 1124: 017, inlinetest, ! 1125: 020, inlinetest, ! 1126: 021, inlinetest, ! 1127: 022, inlinetest, ! 1128: 023, inlinetest, ! 1129: 024, inlinetest, ! 1130: 025, inlinetest, ! 1131: 026, inlinetest, ! 1132: 027, inlinetest, ! 1133: 030, inlinetest, ! 1134: 031, inlinetest, ! 1135: 032, inlinetest, ! 1136: 033, inlinetest, ! 1137: 034, inlinetest, ! 1138: 035, inlinetest, ! 1139: 036, inlinetest, ! 1140: 037, inlinetest, ! 1141: 040, inlinetest, ! 1142: 041, inlinetest, ! 1143: 042, inlinetest, ! 1144: 043, inlinetest, ! 1145: 044, inlinetest, ! 1146: 045, inlinetest ! 1147: 046, inlinetest, ! 1148: 047, inlinetest, ! 1149: 050, inlinetest, ! 1150: 051, inlinetest, ! 1151: 052, inlinetest, ! 1152: 053, inlinetest, ! 1153: 054, inlinetest, ! 1154: 055, inlinetest, ! 1155: 056, inlinetest, ! 1156: 057, inlinetest, ! 1157: -1, unclass ! 1158: }; ! 1159: ! 1160: /* MTER_MBFLT */ ! 1161: static struct fmesg mbfltmsg[] = { ! 1162: 01, "control bus parity error", ! 1163: 02, "illegal register referenced", ! 1164: -1, unclass ! 1165: }; ! 1166: ! 1167: /* ! 1168: * MTER_LEOT, MTER_RWDING, NTER_NOTAVL, MTER_NONEX, MTER_KEYFAIL, ! 1169: * and default: no failure message. ! 1170: */ ! 1171: static struct fmesg nullmsg[] = { ! 1172: -1, "" ! 1173: }; ! 1174: ! 1175: /* ! 1176: * Interrupt code table. ! 1177: */ ! 1178: static struct errmsg { ! 1179: int e_code; ! 1180: char *e_mesg; ! 1181: struct fmesg *e_fmesg; ! 1182: } errmsg[] = { ! 1183: MTER_BOT, "unexpected BOT", botmsg, ! 1184: MTER_LEOT, "unexpected LEOT", nullmsg, ! 1185: MTER_RWDING, "tape rewinding", nullmsg, ! 1186: MTER_NOTRDY, "drive not ready", notrdymsg, ! 1187: MTER_NOTAVL, "drive not available", nullmsg, ! 1188: MTER_NONEX, "unit does not exist", nullmsg, ! 1189: MTER_NOTCAP, "not capable", notcapmsg, ! 1190: MTER_LONGREC, "long record", longrecmsg, ! 1191: MTER_UNREAD, "unreadable record", code22msg, ! 1192: MTER_ERROR, "error", code22msg, ! 1193: MTER_EOTERR, "EOT error", code22msg, ! 1194: MTER_BADTAPE, "tape position lost", code22msg, ! 1195: MTER_TMFLTA, "TM fault A", tmfltamsg, ! 1196: MTER_TUFLTA, "TU fault A", tufltamsg, ! 1197: MTER_TMFLTB, "TM fault B", tmfltbmsg, ! 1198: MTER_MBFLT, "MB fault", mbfltmsg, ! 1199: MTER_KEYFAIL, "keypad entry error", nullmsg, ! 1200: -1, "unclassified error", nullmsg ! 1201: }; ! 1202: ! 1203: /* ! 1204: * Decode an interrupt-time failure. ! 1205: */ ! 1206: mtintfail(erreg) ! 1207: int erreg; ! 1208: { ! 1209: register struct errmsg *e; ! 1210: register struct fmesg *f; ! 1211: register int ecode, fcode; ! 1212: ! 1213: ecode = erreg & MTER_INTCODE; ! 1214: fcode = (erreg & MTER_FAILCODE) >> MTER_FSHIFT; ! 1215: for (e = errmsg; e->e_code >= 0; e++) ! 1216: if (e->e_code == ecode) ! 1217: break; ! 1218: for (f = e->e_fmesg; f->f_code >= 0; f++) ! 1219: if (f->f_code == fcode) ! 1220: break; ! 1221: printf(" interrupt code = 0%o <%s>\n", ecode, e->e_mesg); ! 1222: printf(" failure code = 0%o <%s>\n", fcode, f->f_mesg); ! 1223: } ! 1224: #endif /* MTLERRM */ ! 1225: #endif /* NMT > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.