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