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