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