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