|
|
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: * @(#)tm.c 7.4 (Berkeley) 5/6/88 ! 7: */ ! 8: ! 9: #include "te.h" ! 10: #include "ts.h" ! 11: #if NTE > 0 ! 12: /* ! 13: * TM11/TE10 tape driver ! 14: * ! 15: * TODO: ! 16: * test driver with more than one controller ! 17: * test reset code ! 18: * what happens if you offline tape during rewind? ! 19: * test using file system on tape ! 20: */ ! 21: #include "param.h" ! 22: #include "systm.h" ! 23: #include "buf.h" ! 24: #include "dir.h" ! 25: #include "conf.h" ! 26: #include "user.h" ! 27: #include "file.h" ! 28: #include "map.h" ! 29: #include "vm.h" ! 30: #include "ioctl.h" ! 31: #include "mtio.h" ! 32: #include "cmap.h" ! 33: #include "uio.h" ! 34: #include "kernel.h" ! 35: #include "tty.h" ! 36: #include "syslog.h" ! 37: ! 38: #include "../machine/pte.h" ! 39: #include "../vax/cpu.h" ! 40: #include "ubareg.h" ! 41: #include "ubavar.h" ! 42: #include "tmreg.h" ! 43: ! 44: /* ! 45: * There is a ctmbuf per tape controller. ! 46: * It is used as the token to pass to the internal routines ! 47: * to execute tape ioctls, and also acts as a lock on the slaves ! 48: * on the controller, since there is only one per controller. ! 49: * In particular, when the tape is rewinding on close we release ! 50: * the user process but any further attempts to use the tape drive ! 51: * before the rewind completes will hang waiting for ctmbuf. ! 52: */ ! 53: struct buf ctmbuf[NTM]; ! 54: ! 55: /* ! 56: * Driver unibus interface routines and variables. ! 57: */ ! 58: int tmprobe(), tmslave(), tmattach(), tmdgo(), tmintr(); ! 59: struct uba_ctlr *tmminfo[NTM]; ! 60: struct uba_device *tedinfo[NTE]; ! 61: struct buf teutab[NTE]; ! 62: short tetotm[NTE]; ! 63: u_short tmstd[] = { 0772520, 0 }; ! 64: struct uba_driver tmdriver = ! 65: { tmprobe, tmslave, tmattach, tmdgo, tmstd, "te", tedinfo, "tm", tmminfo, 0 }; ! 66: ! 67: /* bits in minor device */ ! 68: #define TEUNIT(dev) (minor(dev)&03) ! 69: #define TMUNIT(dev) (tetotm[TEUNIT(dev)]) ! 70: #define T_NOREWIND 04 ! 71: #define T_1600BPI 0x8 ! 72: ! 73: #define INF (daddr_t)1000000L ! 74: ! 75: /* ! 76: * Software state per tape transport. ! 77: * ! 78: * 1. A tape drive is a unique-open device; we refuse opens when it is already. ! 79: * 2. We keep track of the current position on a block tape and seek ! 80: * before operations by forward/back spacing if necessary. ! 81: * 3. We remember if the last operation was a write on a tape, so if a tape ! 82: * is open read write and the last thing done is a write we can ! 83: * write a standard end of tape mark (two eofs). ! 84: * 4. We remember the status registers after the last command, using ! 85: * then internally and returning them to the SENSE ioctl. ! 86: * 5. We remember the last density the tape was used at. If it is ! 87: * not a BOT when we start using it and we are writing, we don't ! 88: * let the density be changed. ! 89: */ ! 90: struct te_softc { ! 91: char sc_openf; /* lock against multiple opens */ ! 92: char sc_lastiow; /* last op was a write */ ! 93: daddr_t sc_blkno; /* block number, for block device tape */ ! 94: daddr_t sc_nxrec; /* position of end of tape, if known */ ! 95: u_short sc_erreg; /* copy of last erreg */ ! 96: u_short sc_ioerreg; /* copy of last erreg for I/O command */ ! 97: u_short sc_dsreg; /* copy of last dsreg */ ! 98: short sc_resid; /* copy of last bc */ ! 99: #ifdef unneeded ! 100: short sc_lastcmd; /* last command to handle direction changes */ ! 101: #endif ! 102: u_short sc_dens; /* prototype command with density info */ ! 103: short sc_tact; /* timeout is active */ ! 104: daddr_t sc_timo; /* time until timeout expires */ ! 105: int sc_blks; /* number of I/O operations since open */ ! 106: int sc_softerrs; /* number of soft I/O errors since open */ ! 107: struct tty *sc_ttyp; /* record user's tty for errors */ ! 108: } te_softc[NTE]; ! 109: #ifdef unneeded ! 110: int tmgapsdcnt; /* DEBUG */ ! 111: #endif ! 112: ! 113: /* ! 114: * States for um->um_tab.b_active, the per controller state flag. ! 115: * This is used to sequence control in the driver. ! 116: */ ! 117: #define SSEEK 1 /* seeking */ ! 118: #define SIO 2 /* doing seq i/o */ ! 119: #define SCOM 3 /* sending control command */ ! 120: #define SREW 4 /* sending a drive rewind */ ! 121: ! 122: /* ! 123: * Determine if there is a controller for ! 124: * a tm at address reg. Our goal is to make the ! 125: * device interrupt. ! 126: */ ! 127: tmprobe(reg) ! 128: caddr_t reg; ! 129: { ! 130: register int br, cvec; /* must be r11,r10; value-result */ ! 131: ! 132: #ifdef lint ! 133: br = 0; cvec = br; br = cvec; ! 134: tmintr(0); ! 135: #endif ! 136: ((struct tmdevice *)reg)->tmcs = TM_IE; ! 137: /* ! 138: * If this is a tm11, it ought to have interrupted ! 139: * by now, if it isn't (ie: it is a ts04) then we just ! 140: * hope that it didn't interrupt, so autoconf will ignore it. ! 141: * Just in case, we will reference one ! 142: * of the more distant registers, and hope for a machine ! 143: * check, or similar disaster if this is a ts. ! 144: * ! 145: * Note: on an 11/780, badaddr will just generate ! 146: * a uba error for a ts; but our caller will notice that ! 147: * so we won't check for it. ! 148: */ ! 149: if (badaddr((caddr_t)&((struct tmdevice *)reg)->tmrd, 2)) ! 150: return (0); ! 151: return (sizeof (struct tmdevice)); ! 152: } ! 153: ! 154: /* ! 155: * Due to a design flaw, we cannot ascertain if the tape ! 156: * exists or not unless it is on line - ie: unless a tape is ! 157: * mounted. This is too servere a restriction to bear, ! 158: * so all units are assumed to exist. ! 159: */ ! 160: /*ARGSUSED*/ ! 161: tmslave(ui, reg) ! 162: struct uba_device *ui; ! 163: caddr_t reg; ! 164: { ! 165: ! 166: return (1); ! 167: } ! 168: ! 169: /* ! 170: * Record attachment of the unit to the controller. ! 171: */ ! 172: /*ARGSUSED*/ ! 173: tmattach(ui) ! 174: struct uba_device *ui; ! 175: { ! 176: /* ! 177: * Tetotm is used in TMUNIT to index the ctmbuf ! 178: * array given a te unit number. ! 179: */ ! 180: tetotm[ui->ui_unit] = ui->ui_mi->um_ctlr; ! 181: } ! 182: ! 183: int tmtimer(); ! 184: /* ! 185: * Open the device. Tapes are unique open ! 186: * devices, so we refuse if it is already open. ! 187: * We also check that a tape is available, and ! 188: * don't block waiting here; if you want to wait ! 189: * for a tape you should timeout in user code. ! 190: */ ! 191: ! 192: #ifdef AVIV ! 193: int tmdens[4] = { 0x6000, 0x0000, 0x2000, 0 }; ! 194: #endif AVIV ! 195: int tmdiag; ! 196: ! 197: tmopen(dev, flag) ! 198: dev_t dev; ! 199: int flag; ! 200: { ! 201: register int teunit; ! 202: register struct uba_device *ui; ! 203: register struct te_softc *sc; ! 204: int olddens, dens; ! 205: int s; ! 206: ! 207: teunit = TEUNIT(dev); ! 208: if (teunit>=NTE || (ui = tedinfo[teunit]) == 0 || ui->ui_alive == 0) ! 209: return (ENXIO); ! 210: if ((sc = &te_softc[teunit])->sc_openf) ! 211: return (EBUSY); ! 212: sc->sc_openf = 1; ! 213: olddens = sc->sc_dens; ! 214: dens = TM_IE | TM_GO | (ui->ui_slave << 8); ! 215: #ifndef AVIV ! 216: if ((minor(dev) & T_1600BPI) == 0) ! 217: dens |= TM_D800; ! 218: #else AVIV ! 219: dens |= tmdens[(minor(dev)>>3)&03]; ! 220: #endif AVIV ! 221: sc->sc_dens = dens; ! 222: get: ! 223: tmcommand(dev, TM_SENSE, 1); ! 224: if (sc->sc_erreg&TMER_SDWN) { ! 225: sleep((caddr_t)&lbolt, PZERO+1); ! 226: goto get; ! 227: } ! 228: sc->sc_dens = olddens; ! 229: if ((sc->sc_erreg&(TMER_SELR|TMER_TUR)) != (TMER_SELR|TMER_TUR)) { ! 230: uprintf("te%d: not online\n", teunit); ! 231: sc->sc_openf = 0; ! 232: return (EIO); ! 233: } ! 234: if ((flag&FWRITE) && (sc->sc_erreg&TMER_WRL)) { ! 235: uprintf("te%d: no write ring\n", teunit); ! 236: sc->sc_openf = 0; ! 237: return (EIO); ! 238: } ! 239: if ((sc->sc_erreg&TMER_BOT) == 0 && (flag&FWRITE) && ! 240: dens != sc->sc_dens) { ! 241: uprintf("te%d: can't change density in mid-tape\n", teunit); ! 242: sc->sc_openf = 0; ! 243: return (EIO); ! 244: } ! 245: sc->sc_blkno = (daddr_t)0; ! 246: sc->sc_nxrec = INF; ! 247: sc->sc_lastiow = 0; ! 248: sc->sc_dens = dens; ! 249: sc->sc_blks = 0; ! 250: sc->sc_softerrs = 0; ! 251: sc->sc_ttyp = u.u_ttyp; ! 252: s = splclock(); ! 253: if (sc->sc_tact == 0) { ! 254: sc->sc_timo = INF; ! 255: sc->sc_tact = 1; ! 256: timeout(tmtimer, (caddr_t)dev, 5*hz); ! 257: } ! 258: splx(s); ! 259: return (0); ! 260: } ! 261: ! 262: /* ! 263: * Close tape device. ! 264: * ! 265: * If tape was open for writing or last operation was ! 266: * a write, then write two EOF's and backspace over the last one. ! 267: * Unless this is a non-rewinding special file, rewind the tape. ! 268: * Make the tape available to others. ! 269: */ ! 270: tmclose(dev, flag) ! 271: register dev_t dev; ! 272: register flag; ! 273: { ! 274: register struct te_softc *sc = &te_softc[TEUNIT(dev)]; ! 275: ! 276: if (flag == FWRITE || (flag&FWRITE) && sc->sc_lastiow) { ! 277: tmcommand(dev, TM_WEOF, 1); ! 278: tmcommand(dev, TM_WEOF, 1); ! 279: tmcommand(dev, TM_SREV, 1); ! 280: } ! 281: if ((minor(dev)&T_NOREWIND) == 0) ! 282: /* ! 283: * 0 count means don't hang waiting for rewind complete ! 284: * rather ctmbuf stays busy until the operation completes ! 285: * preventing further opens from completing by ! 286: * preventing a TM_SENSE from completing. ! 287: */ ! 288: tmcommand(dev, TM_REW, 0); ! 289: if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100) ! 290: log(LOG_INFO, "te%d: %d soft errors in %d blocks\n", ! 291: TEUNIT(dev), sc->sc_softerrs, sc->sc_blks); ! 292: sc->sc_openf = 0; ! 293: return (0); ! 294: } ! 295: ! 296: /* ! 297: * Execute a command on the tape drive ! 298: * a specified number of times. ! 299: */ ! 300: tmcommand(dev, com, count) ! 301: dev_t dev; ! 302: int com, count; ! 303: { ! 304: register struct buf *bp; ! 305: register int s; ! 306: ! 307: bp = &ctmbuf[TMUNIT(dev)]; ! 308: s = spl5(); ! 309: while (bp->b_flags&B_BUSY) { ! 310: /* ! 311: * This special check is because B_BUSY never ! 312: * gets cleared in the non-waiting rewind case. ! 313: */ ! 314: if (bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) ! 315: break; ! 316: bp->b_flags |= B_WANTED; ! 317: sleep((caddr_t)bp, PRIBIO); ! 318: } ! 319: bp->b_flags = B_BUSY|B_READ; ! 320: splx(s); ! 321: bp->b_dev = dev; ! 322: bp->b_repcnt = -count; ! 323: bp->b_command = com; ! 324: bp->b_blkno = 0; ! 325: tmstrategy(bp); ! 326: /* ! 327: * In case of rewind from close, don't wait. ! 328: * This is the only case where count can be 0. ! 329: */ ! 330: if (count == 0) ! 331: return; ! 332: iowait(bp); ! 333: if (bp->b_flags&B_WANTED) ! 334: wakeup((caddr_t)bp); ! 335: bp->b_flags &= B_ERROR; ! 336: } ! 337: ! 338: /* ! 339: * Queue a tape operation. ! 340: */ ! 341: tmstrategy(bp) ! 342: register struct buf *bp; ! 343: { ! 344: int teunit = TEUNIT(bp->b_dev); ! 345: register struct uba_ctlr *um; ! 346: register struct buf *dp; ! 347: int s; ! 348: ! 349: /* ! 350: * Put transfer at end of unit queue ! 351: */ ! 352: dp = &teutab[teunit]; ! 353: bp->av_forw = NULL; ! 354: s = spl5(); ! 355: um = tedinfo[teunit]->ui_mi; ! 356: if (dp->b_actf == NULL) { ! 357: dp->b_actf = bp; ! 358: /* ! 359: * Transport not already active... ! 360: * put at end of controller queue. ! 361: */ ! 362: dp->b_forw = NULL; ! 363: if (um->um_tab.b_actf == NULL) ! 364: um->um_tab.b_actf = dp; ! 365: else ! 366: um->um_tab.b_actl->b_forw = dp; ! 367: um->um_tab.b_actl = dp; ! 368: } else ! 369: dp->b_actl->av_forw = bp; ! 370: dp->b_actl = bp; ! 371: /* ! 372: * If the controller is not busy, get ! 373: * it going. ! 374: */ ! 375: if (um->um_tab.b_active == 0) ! 376: tmstart(um); ! 377: splx(s); ! 378: } ! 379: ! 380: /* ! 381: * Start activity on a tm controller. ! 382: */ ! 383: tmstart(um) ! 384: register struct uba_ctlr *um; ! 385: { ! 386: register struct buf *bp, *dp; ! 387: register struct tmdevice *addr = (struct tmdevice *)um->um_addr; ! 388: register struct te_softc *sc; ! 389: register struct uba_device *ui; ! 390: int teunit, cmd; ! 391: daddr_t blkno; ! 392: ! 393: /* ! 394: * Look for an idle transport on the controller. ! 395: */ ! 396: loop: ! 397: if ((dp = um->um_tab.b_actf) == NULL) ! 398: return; ! 399: if ((bp = dp->b_actf) == NULL) { ! 400: um->um_tab.b_actf = dp->b_forw; ! 401: goto loop; ! 402: } ! 403: teunit = TEUNIT(bp->b_dev); ! 404: ui = tedinfo[teunit]; ! 405: /* ! 406: * Record pre-transfer status (e.g. for TM_SENSE) ! 407: */ ! 408: sc = &te_softc[teunit]; ! 409: addr = (struct tmdevice *)um->um_addr; ! 410: addr->tmcs = (ui->ui_slave << 8); ! 411: sc->sc_dsreg = addr->tmcs; ! 412: sc->sc_erreg = addr->tmer; ! 413: sc->sc_resid = addr->tmbc; ! 414: /* ! 415: * Default is that last command was NOT a write command; ! 416: * if we do a write command we will notice this in tmintr(). ! 417: */ ! 418: sc->sc_lastiow = 0; ! 419: if (sc->sc_openf < 0 || (addr->tmcs&TM_CUR) == 0) { ! 420: /* ! 421: * Have had a hard error on a non-raw tape ! 422: * or the tape unit is now unavailable ! 423: * (e.g. taken off line). ! 424: */ ! 425: bp->b_flags |= B_ERROR; ! 426: goto next; ! 427: } ! 428: if (bp == &ctmbuf[TMUNIT(bp->b_dev)]) { ! 429: /* ! 430: * Execute control operation with the specified count. ! 431: */ ! 432: if (bp->b_command == TM_SENSE) ! 433: goto next; ! 434: /* ! 435: * Set next state; give 5 minutes to complete ! 436: * rewind, or 10 seconds per iteration (minimum 60 ! 437: * seconds and max 5 minutes) to complete other ops. ! 438: */ ! 439: if (bp->b_command == TM_REW) { ! 440: um->um_tab.b_active = SREW; ! 441: sc->sc_timo = 5 * 60; ! 442: } else { ! 443: um->um_tab.b_active = SCOM; ! 444: sc->sc_timo = ! 445: imin(imax(10*(int)-bp->b_repcnt,60),5*60); ! 446: } ! 447: if (bp->b_command == TM_SFORW || bp->b_command == TM_SREV) ! 448: addr->tmbc = bp->b_repcnt; ! 449: goto dobpcmd; ! 450: } ! 451: /* ! 452: * For raw I/O, save the current block ! 453: * number in case we have to retry. ! 454: */ ! 455: if (bp->b_flags & B_RAW) { ! 456: if (um->um_tab.b_errcnt == 0) { ! 457: sc->sc_blkno = bdbtofsb(bp->b_blkno); ! 458: sc->sc_nxrec = sc->sc_blkno + 1; ! 459: } ! 460: } ! 461: else { ! 462: /* ! 463: * Handle boundary cases for operation ! 464: * on non-raw tapes. ! 465: */ ! 466: if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { ! 467: /* ! 468: * Can't read past known end-of-file. ! 469: */ ! 470: bp->b_flags |= B_ERROR; ! 471: bp->b_error = ENXIO; ! 472: goto next; ! 473: } ! 474: if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && ! 475: bp->b_flags&B_READ) { ! 476: /* ! 477: * Reading at end of file returns 0 bytes. ! 478: */ ! 479: bp->b_resid = bp->b_bcount; ! 480: clrbuf(bp); ! 481: goto next; ! 482: } ! 483: if ((bp->b_flags&B_READ) == 0) ! 484: /* ! 485: * Writing sets EOF ! 486: */ ! 487: sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; ! 488: } ! 489: /* ! 490: * If the data transfer command is in the correct place, ! 491: * set up all the registers except the csr, and give ! 492: * control over to the UNIBUS adapter routines, to ! 493: * wait for resources to start the i/o. ! 494: */ ! 495: if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { ! 496: addr->tmbc = -bp->b_bcount; ! 497: if ((bp->b_flags&B_READ) == 0) { ! 498: if (um->um_tab.b_errcnt && ! 499: (sc->sc_ioerreg&(TMER_HARD|TMER_SOFT)) != TMER_BGL) ! 500: cmd = TM_WIRG; ! 501: else ! 502: cmd = TM_WCOM; ! 503: } else ! 504: cmd = TM_RCOM; ! 505: um->um_tab.b_active = SIO; ! 506: um->um_cmd = sc->sc_dens|cmd; ! 507: #ifdef notdef ! 508: if (tmreverseop(sc->sc_lastcmd)) ! 509: while (addr->tmer & TMER_SDWN) ! 510: DELAY(10),tmgapsdcnt++; ! 511: sc->sc_lastcmd = TM_RCOM; /* will serve */ ! 512: #endif ! 513: sc->sc_timo = 60; /* premature, but should serve */ ! 514: (void) ubago(ui); ! 515: return; ! 516: } ! 517: /* ! 518: * Tape positioned incorrectly; ! 519: * set to seek forwards or backwards to the correct spot. ! 520: * This happens for raw tapes only on error retries. ! 521: */ ! 522: um->um_tab.b_active = SSEEK; ! 523: if (blkno < bdbtofsb(bp->b_blkno)) { ! 524: bp->b_command = TM_SFORW; ! 525: addr->tmbc = blkno - bdbtofsb(bp->b_blkno); ! 526: } else { ! 527: bp->b_command = TM_SREV; ! 528: addr->tmbc = bdbtofsb(bp->b_blkno) - blkno; ! 529: } ! 530: sc->sc_timo = imin(imax(10 * -addr->tmbc, 60), 5 * 60); ! 531: dobpcmd: ! 532: #ifdef notdef ! 533: /* ! 534: * It is strictly necessary to wait for the tape ! 535: * to stop before changing directions, but the TC11 ! 536: * handles this for us. ! 537: */ ! 538: if (tmreverseop(sc->sc_lastcmd) != tmreverseop(bp->b_command)) ! 539: while (addr->tmer & TM_SDWN) ! 540: DELAY(10),tmgapsdcnt++; ! 541: sc->sc_lastcmd = bp->b_command; ! 542: #endif ! 543: /* ! 544: * Do the command in bp. ! 545: */ ! 546: addr->tmcs = (sc->sc_dens | bp->b_command); ! 547: return; ! 548: ! 549: next: ! 550: /* ! 551: * Done with this operation due to error or ! 552: * the fact that it doesn't do anything. ! 553: * Release UBA resources (if any), dequeue ! 554: * the transfer and continue processing this slave. ! 555: */ ! 556: if (um->um_ubinfo) ! 557: ubadone(um); ! 558: um->um_tab.b_errcnt = 0; ! 559: dp->b_actf = bp->av_forw; ! 560: iodone(bp); ! 561: goto loop; ! 562: } ! 563: ! 564: /* ! 565: * The UNIBUS resources we needed have been ! 566: * allocated to us; start the device. ! 567: */ ! 568: tmdgo(um) ! 569: register struct uba_ctlr *um; ! 570: { ! 571: register struct tmdevice *addr = (struct tmdevice *)um->um_addr; ! 572: ! 573: addr->tmba = um->um_ubinfo; ! 574: addr->tmcs = um->um_cmd | ((um->um_ubinfo >> 12) & 0x30); ! 575: } ! 576: ! 577: /* ! 578: * Tm interrupt routine. ! 579: */ ! 580: /*ARGSUSED*/ ! 581: tmintr(tm11) ! 582: int tm11; ! 583: { ! 584: struct buf *dp; ! 585: register struct buf *bp; ! 586: register struct uba_ctlr *um = tmminfo[tm11]; ! 587: register struct tmdevice *addr; ! 588: register struct te_softc *sc; ! 589: int teunit; ! 590: register state; ! 591: ! 592: if ((dp = um->um_tab.b_actf) == NULL) ! 593: return; ! 594: bp = dp->b_actf; ! 595: teunit = TEUNIT(bp->b_dev); ! 596: addr = (struct tmdevice *)tedinfo[teunit]->ui_addr; ! 597: sc = &te_softc[teunit]; ! 598: /* ! 599: * If last command was a rewind, and tape is still ! 600: * rewinding, wait for the rewind complete interrupt. ! 601: */ ! 602: if (um->um_tab.b_active == SREW) { ! 603: um->um_tab.b_active = SCOM; ! 604: if (addr->tmer&TMER_RWS) { ! 605: sc->sc_timo = 5*60; /* 5 minutes */ ! 606: return; ! 607: } ! 608: } ! 609: /* ! 610: * An operation completed... record status ! 611: */ ! 612: sc->sc_timo = INF; ! 613: if (um->um_tab.b_active = SIO) ! 614: sc->sc_ioerreg = addr->tmer; ! 615: sc->sc_dsreg = addr->tmcs; ! 616: sc->sc_erreg = addr->tmer; ! 617: sc->sc_resid = addr->tmbc; ! 618: if ((bp->b_flags & B_READ) == 0) ! 619: sc->sc_lastiow = 1; ! 620: state = um->um_tab.b_active; ! 621: um->um_tab.b_active = 0; ! 622: /* ! 623: * Check for errors. ! 624: */ ! 625: if (addr->tmcs&TM_ERR) { ! 626: while (addr->tmer & TMER_SDWN) ! 627: DELAY(10); /* await settle down */ ! 628: /* ! 629: * If we hit the end of the tape file, update our position. ! 630: */ ! 631: if (addr->tmer&TMER_EOF) { ! 632: tmseteof(bp); /* set blkno and nxrec */ ! 633: state = SCOM; /* force completion */ ! 634: /* ! 635: * Stuff bc so it will be unstuffed correctly ! 636: * later to get resid. ! 637: */ ! 638: addr->tmbc = -bp->b_bcount; ! 639: goto opdone; ! 640: } ! 641: /* ! 642: * If we were reading raw tape and the only error was that the ! 643: * record was too long, then we don't consider this an error. ! 644: */ ! 645: if ((bp->b_flags & (B_READ|B_RAW)) == (B_READ|B_RAW) && ! 646: (addr->tmer&(TMER_HARD|TMER_SOFT)) == TMER_RLE) ! 647: goto ignoreerr; ! 648: /* ! 649: * If error is not hard, and this was an i/o operation ! 650: * retry up to 8 times. ! 651: */ ! 652: if ((addr->tmer&TMER_HARD)==0 && state==SIO) { ! 653: if (++um->um_tab.b_errcnt < 7) { ! 654: if (tmdiag) ! 655: log(LOG_DEBUG, ! 656: "te%d: soft error bn%d er=%b\n", ! 657: minor(bp->b_dev)&03, ! 658: bp->b_blkno, sc->sc_erreg, ! 659: TMER_BITS); ! 660: sc->sc_blkno++; ! 661: ubadone(um); ! 662: goto opcont; ! 663: } ! 664: } else ! 665: /* ! 666: * Hard or non-i/o errors on non-raw tape ! 667: * cause it to close. ! 668: */ ! 669: if ((bp->b_flags&B_RAW) == 0 && sc->sc_openf > 0) ! 670: sc->sc_openf = -1; ! 671: /* ! 672: * Couldn't recover error ! 673: */ ! 674: tprintf(sc->sc_ttyp, ! 675: "te%d: hard error bn%d er=%b\n", minor(bp->b_dev)&03, ! 676: bp->b_blkno, sc->sc_erreg, TMER_BITS); ! 677: #ifdef AVIV ! 678: if (tmdiag) { ! 679: addr->tmmr = DAB; ! 680: printf("reject code 0%o", addr->tmmr & DAB_MASK); ! 681: addr->tmmr = DTS; ! 682: if (addr->tmmr & DTS_MASK) ! 683: printf(", dead track 0%o", addr->tmmr & DTS_MASK); ! 684: addr->tmmr = RWERR; ! 685: printf(", read/write errors %b\n", ! 686: addr->tmmr & RWERR_MASK, ! 687: RWERR_BITS); ! 688: addr->tmmr = DRSENSE; ! 689: printf("drive sense %b, ", addr->tmmr & DRSENSE_MASK, ! 690: DRSENSE_BITS); ! 691: printf("fsr %b\n", addr->tmfsr, FSR_BITS); ! 692: } ! 693: #endif AVIV ! 694: bp->b_flags |= B_ERROR; ! 695: goto opdone; ! 696: } ! 697: /* ! 698: * Advance tape control FSM. ! 699: */ ! 700: ignoreerr: ! 701: switch (state) { ! 702: ! 703: case SIO: ! 704: /* ! 705: * Read/write increments tape block number ! 706: */ ! 707: sc->sc_blkno++; ! 708: sc->sc_blks++; ! 709: if (um->um_tab.b_errcnt) ! 710: sc->sc_softerrs++; ! 711: goto opdone; ! 712: ! 713: case SCOM: ! 714: /* ! 715: * For forward/backward space record update current position. ! 716: */ ! 717: if (bp == &ctmbuf[TMUNIT(bp->b_dev)]) ! 718: switch ((int)bp->b_command) { ! 719: ! 720: case TM_SFORW: ! 721: sc->sc_blkno -= bp->b_repcnt; ! 722: break; ! 723: ! 724: case TM_SREV: ! 725: sc->sc_blkno += bp->b_repcnt; ! 726: break; ! 727: } ! 728: goto opdone; ! 729: ! 730: case SSEEK: ! 731: sc->sc_blkno = bdbtofsb(bp->b_blkno); ! 732: goto opcont; ! 733: ! 734: default: ! 735: panic("tmintr"); ! 736: } ! 737: opdone: ! 738: /* ! 739: * Reset error count and remove ! 740: * from device queue. ! 741: */ ! 742: um->um_tab.b_errcnt = 0; ! 743: dp->b_actf = bp->av_forw; ! 744: /* ! 745: * Check resid; watch out for resid >32767 (tmbc not negative). ! 746: */ ! 747: bp->b_resid = ((int) -addr->tmbc) & 0xffff; ! 748: ubadone(um); ! 749: iodone(bp); ! 750: /* ! 751: * Circulate slave to end of controller ! 752: * queue to give other slaves a chance. ! 753: */ ! 754: um->um_tab.b_actf = dp->b_forw; ! 755: if (dp->b_actf) { ! 756: dp->b_forw = NULL; ! 757: if (um->um_tab.b_actf == NULL) ! 758: um->um_tab.b_actf = dp; ! 759: else ! 760: um->um_tab.b_actl->b_forw = dp; ! 761: um->um_tab.b_actl = dp; ! 762: } ! 763: if (um->um_tab.b_actf == 0) ! 764: return; ! 765: opcont: ! 766: tmstart(um); ! 767: } ! 768: ! 769: tmtimer(dev) ! 770: int dev; ! 771: { ! 772: register struct te_softc *sc = &te_softc[TEUNIT(dev)]; ! 773: register short x; ! 774: ! 775: if (sc->sc_timo != INF && (sc->sc_timo -= 5) < 0) { ! 776: printf("te%d: lost interrupt\n", TEUNIT(dev)); ! 777: sc->sc_timo = INF; ! 778: x = spl5(); ! 779: tmintr(TMUNIT(dev)); ! 780: (void) splx(x); ! 781: } ! 782: timeout(tmtimer, (caddr_t)dev, 5*hz); ! 783: } ! 784: ! 785: tmseteof(bp) ! 786: register struct buf *bp; ! 787: { ! 788: register int teunit = TEUNIT(bp->b_dev); ! 789: register struct tmdevice *addr = ! 790: (struct tmdevice *)tedinfo[teunit]->ui_addr; ! 791: register struct te_softc *sc = &te_softc[teunit]; ! 792: ! 793: if (bp == &ctmbuf[TMUNIT(bp->b_dev)]) { ! 794: if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { ! 795: /* reversing */ ! 796: sc->sc_nxrec = bdbtofsb(bp->b_blkno) - addr->tmbc; ! 797: sc->sc_blkno = sc->sc_nxrec; ! 798: } else { ! 799: /* spacing forward */ ! 800: sc->sc_blkno = bdbtofsb(bp->b_blkno) + addr->tmbc; ! 801: sc->sc_nxrec = sc->sc_blkno - 1; ! 802: } ! 803: return; ! 804: } ! 805: /* eof on read */ ! 806: sc->sc_nxrec = bdbtofsb(bp->b_blkno); ! 807: } ! 808: ! 809: tmreset(uban) ! 810: int uban; ! 811: { ! 812: register struct uba_ctlr *um; ! 813: register tm11, teunit; ! 814: register struct uba_device *ui; ! 815: register struct buf *dp; ! 816: ! 817: for (tm11 = 0; tm11 < NTM; tm11++) { ! 818: if ((um = tmminfo[tm11]) == 0 || um->um_alive == 0 || ! 819: um->um_ubanum != uban) ! 820: continue; ! 821: printf(" tm%d", tm11); ! 822: um->um_tab.b_active = 0; ! 823: um->um_tab.b_actf = um->um_tab.b_actl = 0; ! 824: if (um->um_ubinfo) { ! 825: printf("<%d>", (um->um_ubinfo>>28)&0xf); ! 826: um->um_ubinfo = 0; ! 827: } ! 828: ((struct tmdevice *)(um->um_addr))->tmcs = TM_DCLR; ! 829: for (teunit = 0; teunit < NTE; teunit++) { ! 830: if ((ui = tedinfo[teunit]) == 0 || ui->ui_mi != um || ! 831: ui->ui_alive == 0) ! 832: continue; ! 833: dp = &teutab[teunit]; ! 834: dp->b_active = 0; ! 835: dp->b_forw = 0; ! 836: if (um->um_tab.b_actf == NULL) ! 837: um->um_tab.b_actf = dp; ! 838: else ! 839: um->um_tab.b_actl->b_forw = dp; ! 840: um->um_tab.b_actl = dp; ! 841: if (te_softc[teunit].sc_openf > 0) ! 842: te_softc[teunit].sc_openf = -1; ! 843: } ! 844: tmstart(um); ! 845: } ! 846: } ! 847: ! 848: /*ARGSUSED*/ ! 849: tmioctl(dev, cmd, data, flag) ! 850: caddr_t data; ! 851: dev_t dev; ! 852: { ! 853: int teunit = TEUNIT(dev); ! 854: register struct te_softc *sc = &te_softc[teunit]; ! 855: register struct buf *bp = &ctmbuf[TMUNIT(dev)]; ! 856: register callcount; ! 857: int fcount; ! 858: struct mtop *mtop; ! 859: struct mtget *mtget; ! 860: /* we depend of the values and order of the MT codes here */ ! 861: static tmops[] = ! 862: {TM_WEOF,TM_SFORW,TM_SREV,TM_SFORW,TM_SREV,TM_REW,TM_OFFL,TM_SENSE}; ! 863: ! 864: switch (cmd) { ! 865: ! 866: case MTIOCTOP: /* tape operation */ ! 867: mtop = (struct mtop *)data; ! 868: switch (mtop->mt_op) { ! 869: ! 870: case MTWEOF: ! 871: callcount = mtop->mt_count; ! 872: fcount = 1; ! 873: break; ! 874: ! 875: case MTFSF: case MTBSF: ! 876: callcount = mtop->mt_count; ! 877: fcount = INF; ! 878: break; ! 879: ! 880: case MTFSR: case MTBSR: ! 881: callcount = 1; ! 882: fcount = mtop->mt_count; ! 883: break; ! 884: ! 885: case MTREW: case MTOFFL: case MTNOP: ! 886: callcount = 1; ! 887: fcount = 1; ! 888: break; ! 889: ! 890: default: ! 891: return (ENXIO); ! 892: } ! 893: if (callcount <= 0 || fcount <= 0) ! 894: return (EINVAL); ! 895: while (--callcount >= 0) { ! 896: tmcommand(dev, tmops[mtop->mt_op], fcount); ! 897: if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) && ! 898: bp->b_resid) ! 899: return (EIO); ! 900: if ((bp->b_flags&B_ERROR) || sc->sc_erreg&TMER_BOT) ! 901: break; ! 902: } ! 903: return (geterror(bp)); ! 904: ! 905: case MTIOCGET: ! 906: mtget = (struct mtget *)data; ! 907: mtget->mt_dsreg = sc->sc_dsreg; ! 908: mtget->mt_erreg = sc->sc_erreg; ! 909: mtget->mt_resid = sc->sc_resid; ! 910: mtget->mt_type = MT_ISTM; ! 911: break; ! 912: ! 913: default: ! 914: return (ENXIO); ! 915: } ! 916: return (0); ! 917: } ! 918: ! 919: #define DBSIZE 20 ! 920: ! 921: tmdump() ! 922: { ! 923: register struct uba_device *ui; ! 924: register struct uba_regs *up; ! 925: register struct tmdevice *addr; ! 926: int blk, num; ! 927: int start; ! 928: ! 929: start = 0; ! 930: num = maxfree; ! 931: #define phys(a,b) ((b)((int)(a)&0x7fffffff)) ! 932: if (tedinfo[0] == 0) ! 933: return (ENXIO); ! 934: ui = phys(tedinfo[0], struct uba_device *); ! 935: up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; ! 936: ubainit(up); ! 937: DELAY(1000000); ! 938: addr = (struct tmdevice *)ui->ui_physaddr; ! 939: tmwait(addr); ! 940: addr->tmcs = TM_DCLR | TM_GO; ! 941: while (num > 0) { ! 942: blk = num > DBSIZE ? DBSIZE : num; ! 943: tmdwrite(start, blk, addr, up); ! 944: start += blk; ! 945: num -= blk; ! 946: } ! 947: tmeof(addr); ! 948: tmeof(addr); ! 949: tmwait(addr); ! 950: if (addr->tmcs&TM_ERR) ! 951: return (EIO); ! 952: addr->tmcs = TM_REW | TM_GO; ! 953: tmwait(addr); ! 954: return (0); ! 955: } ! 956: ! 957: tmdwrite(dbuf, num, addr, up) ! 958: register dbuf, num; ! 959: register struct tmdevice *addr; ! 960: struct uba_regs *up; ! 961: { ! 962: register struct pte *io; ! 963: register int npf; ! 964: ! 965: tmwait(addr); ! 966: io = up->uba_map; ! 967: npf = num+1; ! 968: while (--npf != 0) ! 969: *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); ! 970: *(int *)io = 0; ! 971: addr->tmbc = -(num*NBPG); ! 972: addr->tmba = 0; ! 973: addr->tmcs = TM_WCOM | TM_GO; ! 974: } ! 975: ! 976: tmwait(addr) ! 977: register struct tmdevice *addr; ! 978: { ! 979: register s; ! 980: ! 981: do ! 982: s = addr->tmcs; ! 983: while ((s & TM_CUR) == 0); ! 984: } ! 985: ! 986: tmeof(addr) ! 987: struct tmdevice *addr; ! 988: { ! 989: ! 990: tmwait(addr); ! 991: addr->tmcs = TM_WEOF | TM_GO; ! 992: } ! 993: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.