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