|
|
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.1 (Berkeley) 6/5/86 ! 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 "dk.h" ! 25: #include "dkbad.h" ! 26: #include "buf.h" ! 27: #include "conf.h" ! 28: #include "dir.h" ! 29: #include "user.h" ! 30: #include "map.h" ! 31: #include "vm.h" ! 32: #include "cmap.h" ! 33: #include "uio.h" ! 34: #include "kernel.h" ! 35: #include "syslog.h" ! 36: ! 37: #include "../vax/cpu.h" ! 38: #include "../vax/nexus.h" ! 39: #include "ubavar.h" ! 40: #include "ubareg.h" ! 41: #include "upreg.h" ! 42: ! 43: struct up_softc { ! 44: int sc_softas; ! 45: int sc_ndrive; ! 46: int sc_wticks; ! 47: int sc_recal; ! 48: } up_softc[NSC]; ! 49: ! 50: #define upunit(dev) (minor(dev) >> 3) ! 51: ! 52: /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ ! 53: struct size { ! 54: daddr_t nblocks; ! 55: int cyloff; ! 56: } up9300_sizes[8] = { ! 57: 15884, 0, /* A=cyl 0 thru 26 */ ! 58: 33440, 27, /* B=cyl 27 thru 81 */ ! 59: 495520, 0, /* C=cyl 0 thru 814 */ ! 60: 15884, 562, /* D=cyl 562 thru 588 */ ! 61: 55936, 589, /* E=cyl 589 thru 680 */ ! 62: 81376, 681, /* F=cyl 681 thru 814 */ ! 63: 153728, 562, /* G=cyl 562 thru 814 */ ! 64: 291346, 82, /* H=cyl 82 thru 561 */ ! 65: }, up9766_sizes[8] = { ! 66: 15884, 0, /* A=cyl 0 thru 26 */ ! 67: 33440, 27, /* B=cyl 27 thru 81 */ ! 68: 500384, 0, /* C=cyl 0 thru 822 */ ! 69: 15884, 562, /* D=cyl 562 thru 588 */ ! 70: 55936, 589, /* E=cyl 589 thru 680 */ ! 71: 86240, 681, /* F=cyl 681 thru 822 */ ! 72: 158592, 562, /* G=cyl 562 thru 822 */ ! 73: 291346, 82, /* H=cyl 82 thru 561 */ ! 74: }, up160_sizes[8] = { ! 75: 15884, 0, /* A=cyl 0 thru 49 */ ! 76: 33440, 50, /* B=cyl 50 thru 154 */ ! 77: 263360, 0, /* C=cyl 0 thru 822 */ ! 78: 15884, 155, /* D=cyl 155 thru 204 */ ! 79: 55936, 205, /* E=cyl 205 thru 379 */ ! 80: 141664, 380, /* F=cyl 380 thru 822 */ ! 81: 213664, 155, /* G=cyl 155 thru 822 */ ! 82: 0, 0, ! 83: }, upam_sizes[8] = { ! 84: 15884, 0, /* A=cyl 0 thru 31 */ ! 85: 33440, 32, /* B=cyl 32 thru 97 */ ! 86: 524288, 0, /* C=cyl 0 thru 1023 */ ! 87: 15884, 668, /* D=cyl 668 thru 699 */ ! 88: 55936, 700, /* E=cyl 700 thru 809 */ ! 89: 109472, 810, /* F=cyl 810 thru 1023 */ ! 90: 182176, 668, /* G=cyl 668 thru 1023 */ ! 91: 291346, 98, /* H=cyl 98 thru 667 */ ! 92: }, up980_sizes[8] = { ! 93: 15884, 0, /* A=cyl 0 thru 99 */ ! 94: 33440, 100, /* B=cyl 100 thru 308 */ ! 95: 131680, 0, /* C=cyl 0 thru 822 */ ! 96: 15884, 309, /* D=cyl 309 thru 408 */ ! 97: 55936, 409, /* E=cyl 409 thru 758 */ ! 98: 10080, 759, /* F=cyl 759 thru 822 */ ! 99: 82080, 309, /* G=cyl 309 thru 822 */ ! 100: 0, 0, ! 101: }, upeagle_sizes[8] = { ! 102: 15884, 0, /* A=cyl 0 thru 16 */ ! 103: 66880, 17, /* B=cyl 17 thru 86 */ ! 104: 808320, 0, /* C=cyl 0 thru 841 */ ! 105: 15884, 391, /* D=cyl 391 thru 407 */ ! 106: 307200, 408, /* E=cyl 408 thru 727 */ ! 107: 109296, 728, /* F=cyl 728 thru 841 */ ! 108: 432816, 391, /* G=cyl 391 thru 841 */ ! 109: 291346, 87, /* H=cyl 87 thru 390 */ ! 110: }; ! 111: /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ ! 112: ! 113: int upprobe(), upslave(), upattach(), updgo(), upintr(); ! 114: struct uba_ctlr *upminfo[NSC]; ! 115: struct uba_device *updinfo[NUP]; ! 116: #define UPIPUNITS 8 ! 117: struct uba_device *upip[NSC][UPIPUNITS]; /* fuji w/fixed head gives n,n+4 */ ! 118: ! 119: u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; ! 120: struct uba_driver scdriver = ! 121: { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; ! 122: struct buf uputab[NUP]; ! 123: char upinit[NUP]; ! 124: ! 125: struct upst { ! 126: short nsect; /* # sectors/track */ ! 127: short ntrak; /* # tracks/cylinder */ ! 128: short nspc; /* # sectors/cylinder */ ! 129: short ncyl; /* # cylinders */ ! 130: struct size *sizes; /* partition tables */ ! 131: short sdist; /* seek distance metric */ ! 132: short rdist; /* rotational distance metric */ ! 133: } upst[] = { ! 134: { 32, 19, 32*19, 815, up9300_sizes, 3, 4 }, /* 9300 */ ! 135: { 32, 19, 32*19, 823, up9766_sizes, 3, 4 }, /* 9766 */ ! 136: { 32, 10, 32*10, 823, up160_sizes, 3, 4 }, /* fuji 160m */ ! 137: { 32, 16, 32*16, 1024, upam_sizes, 7, 8 }, /* Capricorn */ ! 138: { 32, 5, 32*5, 823, up980_sizes, 3, 4 }, /* DM980 */ ! 139: { 48, 20, 48*20, 842, upeagle_sizes, 15, 8 }, /* EAGLE */ ! 140: { 0, 0, 0, 0, 0, 0, 0 } ! 141: }; ! 142: ! 143: u_char up_offset[16] = { ! 144: UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, ! 145: UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, ! 146: UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, ! 147: 0, 0, 0, 0 ! 148: }; ! 149: ! 150: struct buf rupbuf[NUP]; ! 151: 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_mspw[ui->ui_dk] = .0000020345; ! 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("up%d: uphr=%x\n", ui->ui_slave, 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: harderr(bp, "up"); ! 613: printf("cn=%d tn=%d sn=%d cs2=%b er1=%b er2=%b\n", ! 614: upaddr->updc, ((upaddr->upda)>>8)&077, ! 615: (upaddr->upda)&037, ! 616: upaddr->upcs2, UPCS2_BITS, ! 617: upaddr->uper1, UPER1_BITS, ! 618: upaddr->uper2, UPER2_BITS); ! 619: bp->b_flags |= B_ERROR; ! 620: } else if (upaddr->uper2 & UPER2_BSE) { ! 621: if (upecc(ui, BSE)) ! 622: return; ! 623: else ! 624: goto hard; ! 625: } else { ! 626: /* ! 627: * Retriable error. ! 628: * If a soft ecc, correct it (continuing ! 629: * by returning if necessary. ! 630: * Otherwise fall through and retry the transfer ! 631: */ ! 632: if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) { ! 633: if (upecc(ui, ECC)) ! 634: return; ! 635: } else ! 636: um->um_tab.b_active = 0; /* force retry */ ! 637: } ! 638: /* ! 639: * Clear drive error and, every eight attempts, ! 640: * (starting with the fourth) ! 641: * recalibrate to clear the slate. ! 642: */ ! 643: upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; ! 644: needie = 0; ! 645: if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { ! 646: upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; ! 647: sc->sc_recal = 0; ! 648: goto nextrecal; ! 649: } ! 650: } ! 651: /* ! 652: * Advance recalibration finite state machine ! 653: * if recalibrate in progress, through ! 654: * RECAL ! 655: * SEEK ! 656: * OFFSET (optional) ! 657: * RETRY ! 658: */ ! 659: switch (sc->sc_recal) { ! 660: ! 661: case 1: ! 662: upaddr->updc = bp->b_cylin; ! 663: upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; ! 664: goto nextrecal; ! 665: case 2: ! 666: if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) ! 667: goto donerecal; ! 668: upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; ! 669: upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; ! 670: goto nextrecal; ! 671: nextrecal: ! 672: sc->sc_recal++; ! 673: um->um_tab.b_active = 1; ! 674: return; ! 675: donerecal: ! 676: case 3: ! 677: sc->sc_recal = 0; ! 678: um->um_tab.b_active = 0; ! 679: break; ! 680: } ! 681: /* ! 682: * If still ``active'', then don't need any more retries. ! 683: */ ! 684: if (um->um_tab.b_active) { ! 685: /* ! 686: * If we were offset positioning, ! 687: * return to centerline. ! 688: */ ! 689: if (um->um_tab.b_errcnt >= 16) { ! 690: upaddr->upof = UPOF_FMT22; ! 691: upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; ! 692: while (upaddr->upds & UPDS_PIP) ! 693: DELAY(25); ! 694: needie = 0; ! 695: } ! 696: um->um_tab.b_active = 0; ! 697: um->um_tab.b_errcnt = 0; ! 698: um->um_tab.b_actf = dp->b_forw; ! 699: dp->b_active = 0; ! 700: dp->b_errcnt = 0; ! 701: dp->b_actf = bp->av_forw; ! 702: bp->b_resid = (-upaddr->upwc * sizeof(short)); ! 703: iodone(bp); ! 704: /* ! 705: * If this unit has more work to do, ! 706: * then start it up right away. ! 707: */ ! 708: if (dp->b_actf) ! 709: if (upustart(ui)) ! 710: needie = 0; ! 711: } ! 712: as &= ~(1<<ui->ui_slave); ! 713: /* ! 714: * Release unibus resources and flush data paths. ! 715: */ ! 716: ubadone(um); ! 717: doattn: ! 718: /* ! 719: * Process other units which need attention. ! 720: * For each unit which needs attention, call ! 721: * the unit start routine to place the slave ! 722: * on the controller device queue. ! 723: */ ! 724: while (unit = ffs((long)as)) { ! 725: unit--; /* was 1 origin */ ! 726: as &= ~(1<<unit); ! 727: upaddr->upas = 1<<unit; ! 728: if (unit < UPIPUNITS && upustart(upip[sc21][unit])) ! 729: needie = 0; ! 730: } ! 731: /* ! 732: * If the controller is not transferring, but ! 733: * there are devices ready to transfer, start ! 734: * the controller. ! 735: */ ! 736: if (um->um_tab.b_actf && um->um_tab.b_active == 0) ! 737: if (upstart(um)) ! 738: needie = 0; ! 739: if (needie) ! 740: upaddr->upcs1 = UP_IE; ! 741: } ! 742: ! 743: upread(dev, uio) ! 744: dev_t dev; ! 745: struct uio *uio; ! 746: { ! 747: register int unit = upunit(dev); ! 748: ! 749: if (unit >= NUP) ! 750: return (ENXIO); ! 751: return (physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys, uio)); ! 752: } ! 753: ! 754: upwrite(dev, uio) ! 755: dev_t dev; ! 756: struct uio *uio; ! 757: { ! 758: register int unit = upunit(dev); ! 759: ! 760: if (unit >= NUP) ! 761: return (ENXIO); ! 762: return (physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys, uio)); ! 763: } ! 764: ! 765: /* ! 766: * Correct an ECC error, and restart the i/o to complete ! 767: * the transfer if necessary. This is quite complicated because ! 768: * the transfer may be going to an odd memory address base and/or ! 769: * across a page boundary. ! 770: */ ! 771: upecc(ui, flag) ! 772: register struct uba_device *ui; ! 773: int flag; ! 774: { ! 775: register struct updevice *up = (struct updevice *)ui->ui_addr; ! 776: register struct buf *bp = uputab[ui->ui_unit].b_actf; ! 777: register struct uba_ctlr *um = ui->ui_mi; ! 778: register struct upst *st; ! 779: struct uba_regs *ubp = ui->ui_hd->uh_uba; ! 780: register int i; ! 781: caddr_t addr; ! 782: int reg, bit, byte, npf, mask, o, cmd, ubaddr; ! 783: int bn, cn, tn, sn; ! 784: ! 785: /* ! 786: * Npf is the number of sectors transferred before the sector ! 787: * containing the ECC error, and reg is the UBA register ! 788: * mapping (the first part of) the transfer. ! 789: * O is offset within a memory page of the first byte transferred. ! 790: */ ! 791: if (flag == CONT) ! 792: npf = bp->b_error; ! 793: else ! 794: npf = btodb(bp->b_bcount + (up->upwc * sizeof(short)) + 511); ! 795: reg = btop(um->um_ubinfo&0x3ffff) + npf; ! 796: o = (int)bp->b_un.b_addr & PGOFSET; ! 797: mask = up->upec2; ! 798: #ifdef UPECCDEBUG ! 799: printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, ! 800: up->upec1); ! 801: #endif ! 802: bn = bp->b_blkno; ! 803: st = &upst[ui->ui_type]; ! 804: cn = bp->b_cylin; ! 805: sn = bn%st->nspc + npf; ! 806: tn = sn/st->nsect; ! 807: sn %= st->nsect; ! 808: cn += tn/st->ntrak; ! 809: tn %= st->ntrak; ! 810: ubapurge(um); ! 811: um->um_tab.b_active=2; ! 812: /* ! 813: * action taken depends on the flag ! 814: */ ! 815: switch(flag){ ! 816: case ECC: ! 817: npf--; ! 818: reg--; ! 819: mask = up->upec2; ! 820: log(LOG_WARNING, "up%d%c: soft ecc sn%d\n", upunit(bp->b_dev), ! 821: 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); ! 822: /* ! 823: * Flush the buffered data path, and compute the ! 824: * byte and bit position of the error. The variable i ! 825: * is the byte offset in the transfer, the variable byte ! 826: * is the offset from a page boundary in main memory. ! 827: */ ! 828: i = up->upec1 - 1; /* -1 makes 0 origin */ ! 829: bit = i&07; ! 830: i = (i&~07)>>3; ! 831: byte = i + o; ! 832: /* ! 833: * Correct while possible bits remain of mask. Since mask ! 834: * contains 11 bits, we continue while the bit offset is > -11. ! 835: * Also watch out for end of this block and the end of the whole ! 836: * transfer. ! 837: */ ! 838: while (i < 512 && (int)dbtob(npf)+i < bp->b_bcount && bit > -11) { ! 839: struct pte pte; ! 840: ! 841: pte = ubp->uba_map[reg + btop(byte)]; ! 842: addr = ptob(pte.pg_pfnum) + (byte & PGOFSET); ! 843: #ifdef UPECCDEBUG ! 844: printf("addr %x map reg %x\n", ! 845: addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); ! 846: printf("old: %x, ", getmemc(addr)); ! 847: #endif ! 848: putmemc(addr, getmemc(addr)^(mask<<bit)); ! 849: #ifdef UPECCDEBUG ! 850: printf("new: %x\n", getmemc(addr)); ! 851: #endif ! 852: byte++; ! 853: i++; ! 854: bit -= 8; ! 855: } ! 856: if (up->upwc == 0) ! 857: return (0); ! 858: npf++; ! 859: reg++; ! 860: break; ! 861: case BSE: ! 862: /* ! 863: * if not in bad sector table, return 0 ! 864: */ ! 865: if ((bn = isbad(&upbad[ui->ui_unit], cn, tn, sn)) < 0) ! 866: return(0); ! 867: /* ! 868: * flag this one as bad ! 869: */ ! 870: bp->b_flags |= B_BAD; ! 871: bp->b_error = npf + 1; ! 872: #ifdef UPECCDEBUG ! 873: printf("BSE: restart at %d\n",npf+1); ! 874: #endif ! 875: bn = st->ncyl * st->nspc -st->nsect - 1 - bn; ! 876: cn = bn / st->nspc; ! 877: sn = bn % st->nspc; ! 878: tn = sn / st->nsect; ! 879: sn %= st->nsect; ! 880: up->upwc = -(512 / sizeof (short)); ! 881: #ifdef UPECCDEBUG ! 882: printf("revector to cn %d tn %d sn %d\n", cn, tn, sn); ! 883: #endif ! 884: break; ! 885: case CONT: ! 886: #ifdef UPECCDEBUG ! 887: printf("upecc, CONT: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn); ! 888: #endif ! 889: bp->b_flags &= ~B_BAD; ! 890: if ((int)dbtob(npf) >= bp->b_bcount) ! 891: return (0); ! 892: up->upwc = -((bp->b_bcount - (int)dbtob(npf)) / sizeof(short)); ! 893: break; ! 894: } ! 895: if (up->upwc == 0) { ! 896: um->um_tab.b_active = 0; ! 897: return (0); ! 898: } ! 899: /* ! 900: * Have to continue the transfer... clear the drive, ! 901: * and compute the position where the transfer is to continue. ! 902: * We have completed npf+1 sectors of the transfer already; ! 903: * restart at offset o of next sector (i.e. in UBA register reg+1). ! 904: */ ! 905: #ifdef notdef ! 906: up->uper1 = 0; ! 907: up->upcs1 |= UP_GO; ! 908: #else ! 909: up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; ! 910: up->updc = cn; ! 911: up->upda = (tn << 8) | sn; ! 912: ubaddr = (int)ptob(reg) + o; ! 913: up->upba = ubaddr; ! 914: cmd = (ubaddr >> 8) & 0x300; ! 915: cmd |= ((bp->b_flags&B_READ)?UP_RCOM:UP_WCOM)|UP_IE|UP_GO; ! 916: um->um_tab.b_errcnt = 0; ! 917: up->upcs1 = cmd; ! 918: #endif ! 919: return (1); ! 920: } ! 921: ! 922: /* ! 923: * Reset driver after UBA init. ! 924: * Cancel software state of all pending transfers ! 925: * and restart all units and the controller. ! 926: */ ! 927: upreset(uban) ! 928: int uban; ! 929: { ! 930: register struct uba_ctlr *um; ! 931: register struct uba_device *ui; ! 932: register sc21, unit; ! 933: ! 934: for (sc21 = 0; sc21 < NSC; sc21++) { ! 935: if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || ! 936: um->um_alive == 0) ! 937: continue; ! 938: printf(" sc%d", sc21); ! 939: um->um_tab.b_active = 0; ! 940: um->um_tab.b_actf = um->um_tab.b_actl = 0; ! 941: up_softc[sc21].sc_recal = 0; ! 942: up_softc[sc21].sc_wticks = 0; ! 943: if (um->um_ubinfo) { ! 944: printf("<%d>", (um->um_ubinfo>>28)&0xf); ! 945: um->um_ubinfo = 0; ! 946: } ! 947: ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; ! 948: for (unit = 0; unit < NUP; unit++) { ! 949: if ((ui = updinfo[unit]) == 0) ! 950: continue; ! 951: if (ui->ui_alive == 0 || ui->ui_mi != um) ! 952: continue; ! 953: uputab[unit].b_active = 0; ! 954: (void) upustart(ui); ! 955: } ! 956: (void) upstart(um); ! 957: } ! 958: } ! 959: ! 960: /* ! 961: * Wake up every second and if an interrupt is pending ! 962: * but nothing has happened increment a counter. ! 963: * If nothing happens for 20 seconds, reset the UNIBUS ! 964: * and begin anew. ! 965: */ ! 966: upwatch() ! 967: { ! 968: register struct uba_ctlr *um; ! 969: register sc21, unit; ! 970: register struct up_softc *sc; ! 971: ! 972: timeout(upwatch, (caddr_t)0, hz); ! 973: for (sc21 = 0; sc21 < NSC; sc21++) { ! 974: um = upminfo[sc21]; ! 975: if (um == 0 || um->um_alive == 0) ! 976: continue; ! 977: sc = &up_softc[sc21]; ! 978: if (um->um_tab.b_active == 0) { ! 979: for (unit = 0; unit < NUP; unit++) ! 980: if (uputab[unit].b_active && ! 981: updinfo[unit]->ui_mi == um) ! 982: goto active; ! 983: sc->sc_wticks = 0; ! 984: continue; ! 985: } ! 986: active: ! 987: sc->sc_wticks++; ! 988: if (sc->sc_wticks >= 20) { ! 989: sc->sc_wticks = 0; ! 990: printf("sc%d: lost interrupt\n", sc21); ! 991: ubareset(um->um_ubanum); ! 992: } ! 993: } ! 994: } ! 995: ! 996: #define DBSIZE 20 ! 997: ! 998: updump(dev) ! 999: dev_t dev; ! 1000: { ! 1001: struct updevice *upaddr; ! 1002: char *start; ! 1003: int num, blk, unit; ! 1004: struct size *sizes; ! 1005: register struct uba_regs *uba; ! 1006: register struct uba_device *ui; ! 1007: register short *rp; ! 1008: struct upst *st; ! 1009: register int retry; ! 1010: ! 1011: unit = upunit(dev); ! 1012: if (unit >= NUP) ! 1013: return (ENXIO); ! 1014: #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) ! 1015: ui = phys(struct uba_device *, updinfo[unit]); ! 1016: if (ui->ui_alive == 0) ! 1017: return (ENXIO); ! 1018: uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; ! 1019: ubainit(uba); ! 1020: upaddr = (struct updevice *)ui->ui_physaddr; ! 1021: DELAY(5000000); ! 1022: num = maxfree; ! 1023: upaddr->upcs2 = unit; ! 1024: DELAY(100); ! 1025: upaddr->upcs1 = UP_DCLR|UP_GO; ! 1026: upaddr->upcs1 = UP_PRESET|UP_GO; ! 1027: upaddr->upof = UPOF_FMT22; ! 1028: retry = 0; ! 1029: do { ! 1030: DELAY(25); ! 1031: if (++retry > 527) ! 1032: break; ! 1033: } while ((upaddr->upds & UP_RDY) == 0); ! 1034: if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) ! 1035: return (EFAULT); ! 1036: start = 0; ! 1037: st = &upst[ui->ui_type]; ! 1038: sizes = phys(struct size *, st->sizes); ! 1039: if (dumplo < 0) ! 1040: return (EINVAL); ! 1041: if (dumplo + num >= sizes[minor(dev)&07].nblocks) ! 1042: num = sizes[minor(dev)&07].nblocks - dumplo; ! 1043: while (num > 0) { ! 1044: register struct pte *io; ! 1045: register int i; ! 1046: int cn, sn, tn; ! 1047: daddr_t bn; ! 1048: ! 1049: blk = num > DBSIZE ? DBSIZE : num; ! 1050: io = uba->uba_map; ! 1051: for (i = 0; i < blk; i++) ! 1052: *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; ! 1053: *(int *)io = 0; ! 1054: bn = dumplo + btop(start); ! 1055: cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; ! 1056: sn = bn%st->nspc; ! 1057: tn = sn/st->nsect; ! 1058: sn = sn%st->nsect; ! 1059: upaddr->updc = cn; ! 1060: rp = (short *) &upaddr->upda; ! 1061: *rp = (tn << 8) + sn; ! 1062: *--rp = 0; ! 1063: *--rp = -blk*NBPG / sizeof (short); ! 1064: *--rp = UP_GO|UP_WCOM; ! 1065: retry = 0; ! 1066: do { ! 1067: DELAY(25); ! 1068: if (++retry > 527) ! 1069: break; ! 1070: } while ((upaddr->upcs1 & UP_RDY) == 0); ! 1071: if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { ! 1072: printf("up%d: not ready", unit); ! 1073: if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { ! 1074: printf("\n"); ! 1075: return (EIO); ! 1076: } ! 1077: printf(" (flakey)\n"); ! 1078: } ! 1079: if (upaddr->upds&UPDS_ERR) ! 1080: return (EIO); ! 1081: start += blk*NBPG; ! 1082: num -= blk; ! 1083: } ! 1084: return (0); ! 1085: } ! 1086: ! 1087: upsize(dev) ! 1088: dev_t dev; ! 1089: { ! 1090: int unit = upunit(dev); ! 1091: struct uba_device *ui; ! 1092: struct upst *st; ! 1093: ! 1094: if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0) ! 1095: return (-1); ! 1096: st = &upst[ui->ui_type]; ! 1097: return (st->sizes[minor(dev) & 07].nblocks); ! 1098: } ! 1099: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.