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