|
|
1.1 ! root 1: /* up.c 4.41 81/11/12 */ ! 2: ! 3: #include "up.h" ! 4: #if NSC > 0 ! 5: /* ! 6: * UNIBUS disk driver with overlapped seeks and ECC recovery. ! 7: * ! 8: * TODO: ! 9: * Add bad sector forwarding code ! 10: * Check that offset recovery code works ! 11: */ ! 12: ! 13: #include "../h/param.h" ! 14: #include "../h/systm.h" ! 15: #include "../h/cpu.h" ! 16: #include "../h/nexus.h" ! 17: #include "../h/dk.h" ! 18: #include "../h/buf.h" ! 19: #include "../h/conf.h" ! 20: #include "../h/dir.h" ! 21: #include "../h/user.h" ! 22: #include "../h/map.h" ! 23: #include "../h/pte.h" ! 24: #include "../h/mtpr.h" ! 25: #include "../h/vm.h" ! 26: #include "../h/ubavar.h" ! 27: #include "../h/ubareg.h" ! 28: #include "../h/cmap.h" ! 29: ! 30: #include "../h/upreg.h" ! 31: ! 32: struct up_softc { ! 33: int sc_softas; ! 34: int sc_ndrive; ! 35: int sc_wticks; ! 36: int sc_recal; ! 37: } up_softc[NSC]; ! 38: ! 39: /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ ! 40: struct size ! 41: { ! 42: daddr_t nblocks; ! 43: int cyloff; ! 44: } up_sizes[8] = { ! 45: 15884, 0, /* A=cyl 0 thru 26 */ ! 46: 33440, 27, /* B=cyl 27 thru 81 */ ! 47: 495520, 0, /* C=cyl 0 thru 814 */ ! 48: 15884, 562, /* D=cyl 562 thru 588 */ ! 49: 55936, 589, /* E=cyl 589 thru 680 */ ! 50: #ifndef NOBADSECT ! 51: 81376, 681, /* F=cyl 681 thru 814 */ ! 52: 153728, 562, /* G=cyl 562 thru 814 */ ! 53: #else ! 54: 81472, 681, ! 55: 153824, 562, ! 56: #endif ! 57: 291346, 82, /* H=cyl 82 thru 561 */ ! 58: }, fj_sizes[8] = { ! 59: 15884, 0, /* A=cyl 0 thru 49 */ ! 60: 33440, 50, /* B=cyl 50 thru 154 */ ! 61: 263360, 0, /* C=cyl 0 thru 822 */ ! 62: 0, 0, ! 63: 0, 0, ! 64: 0, 0, ! 65: 0, 0, ! 66: #ifndef NOBADSECT ! 67: 213664, 155, /* H=cyl 155 thru 822 */ ! 68: #else ! 69: 213760, 155, ! 70: #endif ! 71: }; ! 72: /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ ! 73: ! 74: /* ! 75: * On a 780 upSDIST could be 2, but ! 76: * in the interest of 750's... ! 77: */ ! 78: #define _upSDIST 3 /* 1.5 msec */ ! 79: #define _upRDIST 4 /* 2.0 msec */ ! 80: ! 81: int upSDIST = _upSDIST; ! 82: int upRDIST = _upRDIST; ! 83: ! 84: int upprobe(), upslave(), upattach(), updgo(), upintr(); ! 85: struct uba_ctlr *upminfo[NSC]; ! 86: struct uba_device *updinfo[NUP]; ! 87: struct uba_device *upip[NSC][4]; ! 88: ! 89: u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; ! 90: struct uba_driver scdriver = ! 91: { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; ! 92: struct buf uputab[NUP]; ! 93: ! 94: struct upst { ! 95: short nsect; ! 96: short ntrak; ! 97: short nspc; ! 98: short ncyl; ! 99: struct size *sizes; ! 100: } upst[] = { ! 101: 32, 19, 32*19, 823, up_sizes, /* 9300/cdc */ ! 102: /* 9300 actually has 815 cylinders... */ ! 103: 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ ! 104: }; ! 105: ! 106: u_char up_offset[16] = { ! 107: UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, ! 108: UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, ! 109: UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, ! 110: 0, 0, 0, 0 ! 111: }; ! 112: ! 113: struct buf rupbuf[NUP]; ! 114: ! 115: #define b_cylin b_resid ! 116: ! 117: #ifdef INTRLVE ! 118: daddr_t dkblock(); ! 119: #endif ! 120: ! 121: int upwstart, upwatch(); /* Have started guardian */ ! 122: int upseek; ! 123: int upwaitdry; ! 124: ! 125: /*ARGSUSED*/ ! 126: upprobe(reg) ! 127: caddr_t reg; ! 128: { ! 129: register int br, cvec; ! 130: ! 131: #ifdef lint ! 132: br = 0; cvec = br; br = cvec; ! 133: #endif ! 134: ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; ! 135: DELAY(10); ! 136: ((struct updevice *)reg)->upcs1 = 0; ! 137: return (1); ! 138: } ! 139: ! 140: upslave(ui, reg) ! 141: struct uba_device *ui; ! 142: caddr_t reg; ! 143: { ! 144: register struct updevice *upaddr = (struct updevice *)reg; ! 145: ! 146: upaddr->upcs1 = 0; /* conservative */ ! 147: upaddr->upcs2 = ui->ui_slave; ! 148: if (upaddr->upcs2&UPCS2_NED) { ! 149: upaddr->upcs1 = UP_DCLR|UP_GO; ! 150: return (0); ! 151: } ! 152: return (1); ! 153: } ! 154: ! 155: upattach(ui) ! 156: register struct uba_device *ui; ! 157: { ! 158: register struct updevice *upaddr; ! 159: ! 160: if (upwstart == 0) { ! 161: timeout(upwatch, (caddr_t)0, hz); ! 162: upwstart++; ! 163: } ! 164: if (ui->ui_dk >= 0) ! 165: dk_mspw[ui->ui_dk] = .0000020345; ! 166: upip[ui->ui_ctlr][ui->ui_slave] = ui; ! 167: up_softc[ui->ui_ctlr].sc_ndrive++; ! 168: upaddr = (struct updevice *)ui->ui_addr; ! 169: upaddr->upcs1 = 0; ! 170: upaddr->upcs2 = ui->ui_slave; ! 171: upaddr->uphr = UPHR_MAXTRAK; ! 172: if (upaddr->uphr == 9) ! 173: ui->ui_type = 1; /* fujitsu hack */ ! 174: upaddr->upcs2 = UPCS2_CLR; ! 175: /* ! 176: upaddr->uphr = UPHR_MAXCYL; ! 177: printf("maxcyl %d\n", upaddr->uphr); ! 178: upaddr->uphr = UPHR_MAXTRAK; ! 179: printf("maxtrak %d\n", upaddr->uphr); ! 180: upaddr->uphr = UPHR_MAXSECT; ! 181: printf("maxsect %d\n", upaddr->uphr); ! 182: */ ! 183: } ! 184: ! 185: upstrategy(bp) ! 186: register struct buf *bp; ! 187: { ! 188: register struct uba_device *ui; ! 189: register struct upst *st; ! 190: register int unit; ! 191: register struct buf *dp; ! 192: int xunit = minor(bp->b_dev) & 07; ! 193: long bn, sz; ! 194: ! 195: sz = (bp->b_bcount+511) >> 9; ! 196: unit = dkunit(bp); ! 197: if (unit >= NUP) ! 198: goto bad; ! 199: ui = updinfo[unit]; ! 200: if (ui == 0 || ui->ui_alive == 0) ! 201: goto bad; ! 202: st = &upst[ui->ui_type]; ! 203: if (bp->b_blkno < 0 || ! 204: (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) ! 205: goto bad; ! 206: bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; ! 207: (void) spl5(); ! 208: dp = &uputab[ui->ui_unit]; ! 209: disksort(dp, bp); ! 210: if (dp->b_active == 0) { ! 211: (void) upustart(ui); ! 212: bp = &ui->ui_mi->um_tab; ! 213: if (bp->b_actf && bp->b_active == 0) ! 214: (void) upstart(ui->ui_mi); ! 215: } ! 216: (void) spl0(); ! 217: return; ! 218: ! 219: bad: ! 220: bp->b_flags |= B_ERROR; ! 221: iodone(bp); ! 222: return; ! 223: } ! 224: ! 225: /* ! 226: * Unit start routine. ! 227: * Seek the drive to be where the data is ! 228: * and then generate another interrupt ! 229: * to actually start the transfer. ! 230: * If there is only one drive on the controller, ! 231: * or we are very close to the data, don't ! 232: * bother with the search. If called after ! 233: * searching once, don't bother to look where ! 234: * we are, just queue for transfer (to avoid ! 235: * positioning forever without transferrring.) ! 236: */ ! 237: upustart(ui) ! 238: register struct uba_device *ui; ! 239: { ! 240: register struct buf *bp, *dp; ! 241: register struct uba_ctlr *um; ! 242: register struct updevice *upaddr; ! 243: register struct upst *st; ! 244: daddr_t bn; ! 245: int sn, csn; ! 246: /* ! 247: * The SC21 cancels commands if you just say ! 248: * cs1 = UP_IE ! 249: * so we are cautious about handling of cs1. ! 250: * Also don't bother to clear as bits other than in upintr(). ! 251: */ ! 252: int didie = 0; ! 253: ! 254: if (ui == 0) ! 255: return (0); ! 256: um = ui->ui_mi; ! 257: dk_busy &= ~(1<<ui->ui_dk); ! 258: dp = &uputab[ui->ui_unit]; ! 259: if ((bp = dp->b_actf) == NULL) ! 260: goto out; ! 261: /* ! 262: * If the controller is active, just remember ! 263: * that this device would like to be positioned... ! 264: * if we tried to position now we would confuse the SC21. ! 265: */ ! 266: if (um->um_tab.b_active) { ! 267: up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; ! 268: return (0); ! 269: } ! 270: /* ! 271: * If we have already positioned this drive, ! 272: * then just put it on the ready queue. ! 273: */ ! 274: if (dp->b_active) ! 275: goto done; ! 276: dp->b_active = 1; ! 277: upaddr = (struct updevice *)um->um_addr; ! 278: upaddr->upcs2 = ui->ui_slave; ! 279: /* ! 280: * If drive has just come up, ! 281: * setup the pack. ! 282: */ ! 283: if ((upaddr->upds & UPDS_VV) == 0) { ! 284: /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ ! 285: upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; ! 286: upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; ! 287: upaddr->upof = UPOF_FMT22; ! 288: didie = 1; ! 289: } ! 290: /* ! 291: * If drive is offline, forget about positioning. ! 292: */ ! 293: if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) ! 294: goto done; ! 295: /* ! 296: * If there is only one drive, ! 297: * dont bother searching. ! 298: */ ! 299: if (up_softc[um->um_ctlr].sc_ndrive == 1) ! 300: goto done; ! 301: /* ! 302: * Figure out where this transfer is going to ! 303: * and see if we are close enough to justify not searching. ! 304: */ ! 305: st = &upst[ui->ui_type]; ! 306: bn = dkblock(bp); ! 307: sn = bn%st->nspc; ! 308: sn = (sn + st->nsect - upSDIST) % st->nsect; ! 309: if (bp->b_cylin - upaddr->updc) ! 310: goto search; /* Not on-cylinder */ ! 311: else if (upseek) ! 312: goto done; /* Ok just to be on-cylinder */ ! 313: csn = (upaddr->upla>>6) - sn - 1; ! 314: if (csn < 0) ! 315: csn += st->nsect; ! 316: if (csn > st->nsect - upRDIST) ! 317: goto done; ! 318: search: ! 319: upaddr->updc = bp->b_cylin; ! 320: /* ! 321: * Not on cylinder at correct position, ! 322: * seek/search. ! 323: */ ! 324: if (upseek) ! 325: upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; ! 326: else { ! 327: upaddr->upda = sn; ! 328: upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; ! 329: } ! 330: didie = 1; ! 331: /* ! 332: * Mark unit busy for iostat. ! 333: */ ! 334: if (ui->ui_dk >= 0) { ! 335: dk_busy |= 1<<ui->ui_dk; ! 336: dk_seek[ui->ui_dk]++; ! 337: } ! 338: goto out; ! 339: done: ! 340: /* ! 341: * Device is ready to go. ! 342: * Put it on the ready queue for the controller ! 343: * (unless its already there.) ! 344: */ ! 345: if (dp->b_active != 2) { ! 346: dp->b_forw = NULL; ! 347: if (um->um_tab.b_actf == NULL) ! 348: um->um_tab.b_actf = dp; ! 349: else ! 350: um->um_tab.b_actl->b_forw = dp; ! 351: um->um_tab.b_actl = dp; ! 352: dp->b_active = 2; ! 353: } ! 354: out: ! 355: return (didie); ! 356: } ! 357: ! 358: /* ! 359: * Start up a transfer on a drive. ! 360: */ ! 361: upstart(um) ! 362: register struct uba_ctlr *um; ! 363: { ! 364: register struct buf *bp, *dp; ! 365: register struct uba_device *ui; ! 366: register struct updevice *upaddr; ! 367: struct upst *st; ! 368: daddr_t bn; ! 369: int dn, sn, tn, cmd, waitdry; ! 370: ! 371: loop: ! 372: /* ! 373: * Pull a request off the controller queue ! 374: */ ! 375: if ((dp = um->um_tab.b_actf) == NULL) ! 376: return (0); ! 377: if ((bp = dp->b_actf) == NULL) { ! 378: um->um_tab.b_actf = dp->b_forw; ! 379: goto loop; ! 380: } ! 381: /* ! 382: * Mark controller busy, and ! 383: * determine destination of this request. ! 384: */ ! 385: um->um_tab.b_active++; ! 386: ui = updinfo[dkunit(bp)]; ! 387: bn = dkblock(bp); ! 388: dn = ui->ui_slave; ! 389: st = &upst[ui->ui_type]; ! 390: sn = bn%st->nspc; ! 391: tn = sn/st->nsect; ! 392: sn %= st->nsect; ! 393: upaddr = (struct updevice *)ui->ui_addr; ! 394: /* ! 395: * Select drive if not selected already. ! 396: */ ! 397: if ((upaddr->upcs2&07) != dn) ! 398: upaddr->upcs2 = dn; ! 399: /* ! 400: * Check that it is ready and online ! 401: */ ! 402: waitdry = 0; ! 403: while ((upaddr->upds&UPDS_DRY) == 0) { ! 404: if (++waitdry > 512) ! 405: break; ! 406: upwaitdry++; ! 407: } ! 408: if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { ! 409: printf("up%d: not ready", dkunit(bp)); ! 410: if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { ! 411: printf("\n"); ! 412: um->um_tab.b_active = 0; ! 413: um->um_tab.b_errcnt = 0; ! 414: dp->b_actf = bp->av_forw; ! 415: dp->b_active = 0; ! 416: bp->b_flags |= B_ERROR; ! 417: iodone(bp); ! 418: goto loop; ! 419: } ! 420: /* ! 421: * Oh, well, sometimes this ! 422: * happens, for reasons unknown. ! 423: */ ! 424: printf(" (flakey)\n"); ! 425: } ! 426: /* ! 427: * Setup for the transfer, and get in the ! 428: * UNIBUS adaptor queue. ! 429: */ ! 430: upaddr->updc = bp->b_cylin; ! 431: upaddr->upda = (tn << 8) + sn; ! 432: upaddr->upwc = -bp->b_bcount / sizeof (short); ! 433: if (bp->b_flags & B_READ) ! 434: cmd = UP_IE|UP_RCOM|UP_GO; ! 435: else ! 436: cmd = UP_IE|UP_WCOM|UP_GO; ! 437: um->um_cmd = cmd; ! 438: (void) ubago(ui); ! 439: return (1); ! 440: } ! 441: ! 442: /* ! 443: * Now all ready to go, stuff the registers. ! 444: */ ! 445: updgo(um) ! 446: struct uba_ctlr *um; ! 447: { ! 448: register struct updevice *upaddr = (struct updevice *)um->um_addr; ! 449: ! 450: upaddr->upba = um->um_ubinfo; ! 451: upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); ! 452: } ! 453: ! 454: /* ! 455: * Handle a disk interrupt. ! 456: */ ! 457: upintr(sc21) ! 458: register sc21; ! 459: { ! 460: register struct buf *bp, *dp; ! 461: register struct uba_ctlr *um = upminfo[sc21]; ! 462: register struct uba_device *ui; ! 463: register struct updevice *upaddr = (struct updevice *)um->um_addr; ! 464: register unit; ! 465: struct up_softc *sc = &up_softc[um->um_ctlr]; ! 466: int as = (upaddr->upas & 0377) | sc->sc_softas; ! 467: int needie = 1, waitdry, err; ! 468: ! 469: sc->sc_wticks = 0; ! 470: sc->sc_softas = 0; ! 471: /* ! 472: * If controller wasn't transferring, then this is an ! 473: * interrupt for attention status on seeking drives. ! 474: * Just service them. ! 475: */ ! 476: if (um->um_tab.b_active == 0) { ! 477: if (upaddr->upcs1 & UP_TRE) ! 478: upaddr->upcs1 = UP_TRE; ! 479: goto doattn; ! 480: } ! 481: /* ! 482: * Get device and block structures, and a pointer ! 483: * to the uba_device for the drive. Select the drive. ! 484: */ ! 485: dp = um->um_tab.b_actf; ! 486: bp = dp->b_actf; ! 487: ui = updinfo[dkunit(bp)]; ! 488: dk_busy &= ~(1 << ui->ui_dk); ! 489: if ((upaddr->upcs2&07) != ui->ui_slave) ! 490: upaddr->upcs2 = ui->ui_slave; ! 491: /* ! 492: * Check for and process errors on ! 493: * either the drive or the controller. ! 494: */ ! 495: if ((err = (upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) || ! 496: upaddr->upwc != 0) { ! 497: if (!err) ! 498: printf("up%d: word count != 0\n", dkunit(bp)); ! 499: waitdry = 0; ! 500: while ((upaddr->upds & UPDS_DRY) == 0) { ! 501: if (++waitdry > 512) ! 502: break; ! 503: upwaitdry++; ! 504: } ! 505: if (upaddr->uper1&UPER1_WLE) { ! 506: /* ! 507: * Give up on write locked devices ! 508: * immediately. ! 509: */ ! 510: printf("up%d: write locked\n", dkunit(bp)); ! 511: bp->b_flags |= B_ERROR; ! 512: } else if (++um->um_tab.b_errcnt > 27) { ! 513: /* ! 514: * After 28 retries (16 without offset, and ! 515: * 12 with offset positioning) give up. ! 516: */ ! 517: harderr(bp, "up"); ! 518: printf("cs2=%b er1=%b er2=%b\n", ! 519: upaddr->upcs2, UPCS2_BITS, ! 520: upaddr->uper1, UPER1_BITS, ! 521: upaddr->uper2, UPER2_BITS); ! 522: bp->b_flags |= B_ERROR; ! 523: } else { ! 524: /* ! 525: * Retriable error. ! 526: * If a soft ecc, correct it (continuing ! 527: * by returning if necessary. ! 528: * Otherwise fall through and retry the transfer ! 529: */ ! 530: um->um_tab.b_active = 0; /* force retry */ ! 531: if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) ! 532: if (upecc(ui)) ! 533: return; ! 534: } ! 535: /* ! 536: * Clear drive error and, every eight attempts, ! 537: * (starting with the fourth) ! 538: * recalibrate to clear the slate. ! 539: */ ! 540: upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; ! 541: needie = 0; ! 542: if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { ! 543: upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; ! 544: sc->sc_recal = 0; ! 545: goto nextrecal; ! 546: } ! 547: } ! 548: /* ! 549: * Advance recalibration finite state machine ! 550: * if recalibrate in progress, through ! 551: * RECAL ! 552: * SEEK ! 553: * OFFSET (optional) ! 554: * RETRY ! 555: */ ! 556: switch (sc->sc_recal) { ! 557: ! 558: case 1: ! 559: upaddr->updc = bp->b_cylin; ! 560: upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; ! 561: goto nextrecal; ! 562: case 2: ! 563: if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) ! 564: goto donerecal; ! 565: upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; ! 566: upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; ! 567: goto nextrecal; ! 568: nextrecal: ! 569: sc->sc_recal++; ! 570: um->um_tab.b_active = 1; ! 571: return; ! 572: donerecal: ! 573: case 3: ! 574: sc->sc_recal = 0; ! 575: um->um_tab.b_active = 0; ! 576: break; ! 577: } ! 578: /* ! 579: * If still ``active'', then don't need any more retries. ! 580: */ ! 581: if (um->um_tab.b_active) { ! 582: /* ! 583: * If we were offset positioning, ! 584: * return to centerline. ! 585: */ ! 586: if (um->um_tab.b_errcnt >= 16) { ! 587: upaddr->upof = UPOF_FMT22; ! 588: upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; ! 589: while (upaddr->upds & UPDS_PIP) ! 590: DELAY(25); ! 591: needie = 0; ! 592: } ! 593: um->um_tab.b_active = 0; ! 594: um->um_tab.b_errcnt = 0; ! 595: um->um_tab.b_actf = dp->b_forw; ! 596: dp->b_active = 0; ! 597: dp->b_errcnt = 0; ! 598: dp->b_actf = bp->av_forw; ! 599: bp->b_resid = (-upaddr->upwc * sizeof(short)); ! 600: iodone(bp); ! 601: /* ! 602: * If this unit has more work to do, ! 603: * then start it up right away. ! 604: */ ! 605: if (dp->b_actf) ! 606: if (upustart(ui)) ! 607: needie = 0; ! 608: } ! 609: as &= ~(1<<ui->ui_slave); ! 610: /* ! 611: * Release unibus resources and flush data paths. ! 612: */ ! 613: ubadone(um); ! 614: doattn: ! 615: /* ! 616: * Process other units which need attention. ! 617: * For each unit which needs attention, call ! 618: * the unit start routine to place the slave ! 619: * on the controller device queue. ! 620: */ ! 621: while (unit = ffs(as)) { ! 622: unit--; /* was 1 origin */ ! 623: as &= ~(1<<unit); ! 624: upaddr->upas = 1<<unit; ! 625: if (upustart(upip[sc21][unit])) ! 626: needie = 0; ! 627: } ! 628: /* ! 629: * If the controller is not transferring, but ! 630: * there are devices ready to transfer, start ! 631: * the controller. ! 632: */ ! 633: if (um->um_tab.b_actf && um->um_tab.b_active == 0) ! 634: if (upstart(um)) ! 635: needie = 0; ! 636: if (needie) ! 637: upaddr->upcs1 = UP_IE; ! 638: } ! 639: ! 640: upread(dev) ! 641: dev_t dev; ! 642: { ! 643: register int unit = minor(dev) >> 3; ! 644: ! 645: if (unit >= NUP) ! 646: u.u_error = ENXIO; ! 647: else ! 648: physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys); ! 649: } ! 650: ! 651: upwrite(dev) ! 652: dev_t dev; ! 653: { ! 654: register int unit = minor(dev) >> 3; ! 655: ! 656: if (unit >= NUP) ! 657: u.u_error = ENXIO; ! 658: else ! 659: physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys); ! 660: } ! 661: ! 662: /* ! 663: * Correct an ECC error, and restart the i/o to complete ! 664: * the transfer if necessary. This is quite complicated because ! 665: * the transfer may be going to an odd memory address base and/or ! 666: * across a page boundary. ! 667: */ ! 668: upecc(ui) ! 669: register struct uba_device *ui; ! 670: { ! 671: register struct updevice *up = (struct updevice *)ui->ui_addr; ! 672: register struct buf *bp = uputab[ui->ui_unit].b_actf; ! 673: register struct uba_ctlr *um = ui->ui_mi; ! 674: register struct upst *st; ! 675: struct uba_regs *ubp = ui->ui_hd->uh_uba; ! 676: register int i; ! 677: caddr_t addr; ! 678: int reg, bit, byte, npf, mask, o, cmd, ubaddr; ! 679: int bn, cn, tn, sn; ! 680: ! 681: /* ! 682: * Npf is the number of sectors transferred before the sector ! 683: * containing the ECC error, and reg is the UBA register ! 684: * mapping (the first part of) the transfer. ! 685: * O is offset within a memory page of the first byte transferred. ! 686: */ ! 687: npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; ! 688: reg = btop(um->um_ubinfo&0x3ffff) + npf; ! 689: o = (int)bp->b_un.b_addr & PGOFSET; ! 690: printf("up%d%c: soft ecc sn%d\n", dkunit(bp), ! 691: 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); ! 692: mask = up->upec2; ! 693: #ifdef UPECCDEBUG ! 694: printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, ! 695: up->upec1); ! 696: #endif ! 697: /* ! 698: * Flush the buffered data path, and compute the ! 699: * byte and bit position of the error. The variable i ! 700: * is the byte offset in the transfer, the variable byte ! 701: * is the offset from a page boundary in main memory. ! 702: */ ! 703: ubapurge(um); ! 704: i = up->upec1 - 1; /* -1 makes 0 origin */ ! 705: bit = i&07; ! 706: i = (i&~07)>>3; ! 707: byte = i + o; ! 708: /* ! 709: * Correct while possible bits remain of mask. Since mask ! 710: * contains 11 bits, we continue while the bit offset is > -11. ! 711: * Also watch out for end of this block and the end of the whole ! 712: * transfer. ! 713: */ ! 714: while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { ! 715: addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ ! 716: (byte & PGOFSET); ! 717: #ifdef UPECCDEBUG ! 718: printf("addr %x map reg %x\n", ! 719: addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); ! 720: printf("old: %x, ", getmemc(addr)); ! 721: #endif ! 722: putmemc(addr, getmemc(addr)^(mask<<bit)); ! 723: #ifdef UPECCDEBUG ! 724: printf("new: %x\n", getmemc(addr)); ! 725: #endif ! 726: byte++; ! 727: i++; ! 728: bit -= 8; ! 729: } ! 730: um->um_tab.b_active++; /* Either complete or continuing... */ ! 731: if (up->upwc == 0) ! 732: return (0); ! 733: /* ! 734: * Have to continue the transfer... clear the drive, ! 735: * and compute the position where the transfer is to continue. ! 736: * We have completed npf+1 sectors of the transfer already; ! 737: * restart at offset o of next sector (i.e. in UBA register reg+1). ! 738: */ ! 739: #ifdef notdef ! 740: up->uper1 = 0; ! 741: up->upcs1 |= UP_GO; ! 742: #else ! 743: up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; ! 744: bn = dkblock(bp); ! 745: st = &upst[ui->ui_type]; ! 746: cn = bp->b_cylin; ! 747: sn = bn%st->nspc + npf + 1; ! 748: tn = sn/st->nsect; ! 749: sn %= st->nsect; ! 750: cn += tn/st->ntrak; ! 751: tn %= st->ntrak; ! 752: up->updc = cn; ! 753: up->upda = (tn << 8) | sn; ! 754: ubaddr = (int)ptob(reg+1) + o; ! 755: up->upba = ubaddr; ! 756: cmd = (ubaddr >> 8) & 0x300; ! 757: cmd |= UP_IE|UP_GO|UP_RCOM; ! 758: up->upcs1 = cmd; ! 759: #endif ! 760: return (1); ! 761: } ! 762: ! 763: /* ! 764: * Reset driver after UBA init. ! 765: * Cancel software state of all pending transfers ! 766: * and restart all units and the controller. ! 767: */ ! 768: upreset(uban) ! 769: int uban; ! 770: { ! 771: register struct uba_ctlr *um; ! 772: register struct uba_device *ui; ! 773: register sc21, unit; ! 774: ! 775: for (sc21 = 0; sc21 < NSC; sc21++) { ! 776: if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || ! 777: um->um_alive == 0) ! 778: continue; ! 779: printf(" sc%d", sc21); ! 780: um->um_tab.b_active = 0; ! 781: um->um_tab.b_actf = um->um_tab.b_actl = 0; ! 782: up_softc[sc21].sc_recal = 0; ! 783: if (um->um_ubinfo) { ! 784: printf("<%d>", (um->um_ubinfo>>28)&0xf); ! 785: ubadone(um); ! 786: } ! 787: ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; ! 788: for (unit = 0; unit < NUP; unit++) { ! 789: if ((ui = updinfo[unit]) == 0) ! 790: continue; ! 791: if (ui->ui_alive == 0 || ui->ui_mi != um) ! 792: continue; ! 793: uputab[unit].b_active = 0; ! 794: (void) upustart(ui); ! 795: } ! 796: (void) upstart(um); ! 797: } ! 798: } ! 799: ! 800: /* ! 801: * Wake up every second and if an interrupt is pending ! 802: * but nothing has happened increment a counter. ! 803: * If nothing happens for 20 seconds, reset the UNIBUS ! 804: * and begin anew. ! 805: */ ! 806: upwatch() ! 807: { ! 808: register struct uba_ctlr *um; ! 809: register sc21, unit; ! 810: register struct up_softc *sc; ! 811: ! 812: timeout(upwatch, (caddr_t)0, hz); ! 813: for (sc21 = 0; sc21 < NSC; sc21++) { ! 814: um = upminfo[sc21]; ! 815: if (um == 0 || um->um_alive == 0) ! 816: continue; ! 817: sc = &up_softc[sc21]; ! 818: if (um->um_tab.b_active == 0) { ! 819: for (unit = 0; unit < NUP; unit++) ! 820: if (uputab[unit].b_active && ! 821: updinfo[unit]->ui_mi == um) ! 822: goto active; ! 823: sc->sc_wticks = 0; ! 824: continue; ! 825: } ! 826: active: ! 827: sc->sc_wticks++; ! 828: if (sc->sc_wticks >= 20) { ! 829: sc->sc_wticks = 0; ! 830: printf("sc%d: lost interrupt\n", sc21); ! 831: ubareset(um->um_ubanum); ! 832: } ! 833: } ! 834: } ! 835: ! 836: #define DBSIZE 20 ! 837: ! 838: updump(dev) ! 839: dev_t dev; ! 840: { ! 841: struct updevice *upaddr; ! 842: char *start; ! 843: int num, blk, unit; ! 844: struct size *sizes; ! 845: register struct uba_regs *uba; ! 846: register struct uba_device *ui; ! 847: register short *rp; ! 848: struct upst *st; ! 849: ! 850: unit = minor(dev) >> 3; ! 851: if (unit >= NUP) ! 852: return (ENXIO); ! 853: #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) ! 854: ui = phys(struct uba_device *, updinfo[unit]); ! 855: if (ui->ui_alive == 0) ! 856: return (ENXIO); ! 857: uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; ! 858: ubainit(uba); ! 859: upaddr = (struct updevice *)ui->ui_physaddr; ! 860: DELAY(2000000); ! 861: num = maxfree; ! 862: start = 0; ! 863: upaddr->upcs2 = unit; ! 864: DELAY(100); ! 865: if ((upaddr->upcs1&UP_DVA) == 0) ! 866: return (EFAULT); ! 867: if ((upaddr->upds & UPDS_VV) == 0) { ! 868: upaddr->upcs1 = UP_DCLR|UP_GO; ! 869: upaddr->upcs1 = UP_PRESET|UP_GO; ! 870: upaddr->upof = UPOF_FMT22; ! 871: } ! 872: if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) ! 873: return (EFAULT); ! 874: st = &upst[ui->ui_type]; ! 875: sizes = phys(struct size *, st->sizes); ! 876: if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) ! 877: return (EINVAL); ! 878: while (num > 0) { ! 879: register struct pte *io; ! 880: register int i; ! 881: int cn, sn, tn; ! 882: daddr_t bn; ! 883: ! 884: blk = num > DBSIZE ? DBSIZE : num; ! 885: io = uba->uba_map; ! 886: for (i = 0; i < blk; i++) ! 887: *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; ! 888: *(int *)io = 0; ! 889: bn = dumplo + btop(start); ! 890: cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; ! 891: sn = bn%st->nspc; ! 892: tn = sn/st->nsect; ! 893: sn = sn%st->nsect; ! 894: upaddr->updc = cn; ! 895: rp = (short *) &upaddr->upda; ! 896: *rp = (tn << 8) + sn; ! 897: *--rp = 0; ! 898: *--rp = -blk*NBPG / sizeof (short); ! 899: *--rp = UP_GO|UP_WCOM; ! 900: do { ! 901: DELAY(25); ! 902: } while ((upaddr->upcs1 & UP_RDY) == 0); ! 903: if (upaddr->upds&UPDS_ERR) ! 904: return (EIO); ! 905: start += blk*NBPG; ! 906: num -= blk; ! 907: } ! 908: return (0); ! 909: } ! 910: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.