|
|
1.1 ! root 1: /* ! 2: * UNIBUS SMD disk driver ! 3: * ! 4: * undone: ! 5: * Add bad sector forwarding code ! 6: * Check that offset recovery code works ! 7: * unibus mapping is suboptimal; if the queue gets long, ! 8: * buffered data paths will be underused ! 9: */ ! 10: ! 11: #include "sys/param.h" ! 12: #include "sys/buf.h" ! 13: #include "sys/conf.h" ! 14: #include "sys/user.h" ! 15: #include "sys/up.h" ! 16: #include "sys/ubaddr.h" ! 17: #include "sys/subaddr.h" ! 18: ! 19: #define NOUPSEEK 1 /* because emulex doesn't do it right */ ! 20: ! 21: /* ! 22: * hardware registers ! 23: */ ! 24: ! 25: struct updevice ! 26: { ! 27: u_short upcs1; /* control and status register 1 */ ! 28: short upwc; /* word count register */ ! 29: u_short upba; /* UNIBUS address register */ ! 30: u_short upda; /* desired address register */ ! 31: u_short upcs2; /* control and status register 2 */ ! 32: u_short upds; /* drive status */ ! 33: u_short uper1; /* error register 1 */ ! 34: u_short upas; /* attention summary */ ! 35: u_short upla; /* look ahead */ ! 36: u_short updb; /* data buffer */ ! 37: u_short upmr; /* maintenance */ ! 38: u_short updt; /* drive type */ ! 39: u_short upsn; /* serial number */ ! 40: u_short upof; /* offset register */ ! 41: u_short updc; /* desired cylinder address register */ ! 42: u_short uphr; /* holding register */ ! 43: u_short upmr2; /* maintenance register 2 */ ! 44: u_short uper2; /* error register 2 */ ! 45: u_short upec1; /* burst error bit position */ ! 46: u_short upec2; /* burst error bit pattern */ ! 47: }; ! 48: ! 49: /* ! 50: * upcs1 ! 51: */ ! 52: ! 53: #define UP_SC 0100000 /* special condition */ ! 54: #define UP_TRE 0040000 /* transfer error */ ! 55: #define UP_IE 0000100 /* interrupt enable */ ! 56: #define UP_GO 0000001 ! 57: ! 58: #define UP_SEEK 004 /* seek */ ! 59: #define UP_RECAL 006 /* recalibrate */ ! 60: #define UP_DCLR 010 /* drive clear */ ! 61: #define UP_OFFSET 014 /* offset */ ! 62: #define UP_RTC 016 /* return to center-line */ ! 63: #define UP_PRESET 020 /* read-in preset */ ! 64: #define UP_SEARCH 030 /* search */ ! 65: #define UP_WCOM 060 /* write */ ! 66: #define UP_RCOM 070 /* read data */ ! 67: ! 68: /* ! 69: * upcs2 ! 70: */ ! 71: #define UPCS2_NED 0010000 /* nonexistent drive */ ! 72: #define UPCS2_CLR 0000040 /* controller clear */ ! 73: #define UPCS2_SEL 0000007 /* unit select */ ! 74: ! 75: /* ! 76: * upds ! 77: */ ! 78: #define UPDS_ERR 0040000 /* composite drive error */ ! 79: #define UPDS_PIP 0020000 /* positioning in progress */ ! 80: #define UPDS_MOL 0010000 /* medium on line */ ! 81: #define UPDS_DPR 0000400 /* drive present */ ! 82: #define UPDS_DRY 0000200 /* drive ready */ ! 83: #define UPDS_VV 0000100 /* volume valid */ ! 84: #define UPDS_DREADY (UPDS_DPR|UPDS_DRY|UPDS_MOL|UPDS_VV) ! 85: ! 86: /* ! 87: * uper1 ! 88: */ ! 89: #define UPER1_DCK 0100000 /* data check */ ! 90: #define UPER1_WLE 0004000 /* write lock error */ ! 91: #define UPER1_ECH 0000100 /* ecc hard error */ ! 92: ! 93: /* ! 94: * uphr: emulex hack ! 95: */ ! 96: #define UPHR_MAXCYL 0100027 /* max cyl address */ ! 97: #define UPHR_MAXTRAK 0100030 /* max track address */ ! 98: #define UPHR_MAXSECT 0100031 /* max sector address */ ! 99: ! 100: /* ! 101: * upof ! 102: */ ! 103: #define UPOF_FMT22 0010000 /* 16 bit format */ ! 104: /* THE SC21 ACTUALLY JUST IMPLEMENTS ADVANCE/RETARD... */ ! 105: #define UPOF_P400 0020 /* +400 uinches */ ! 106: #define UPOF_M400 0220 /* -400 uinches */ ! 107: #define UPOF_P800 0040 /* +800 uinches */ ! 108: #define UPOF_M800 0240 /* -800 uinches */ ! 109: #define UPOF_P1200 0060 /* +1200 uinches */ ! 110: #define UPOF_M1200 0260 /* -1200 uinches */ ! 111: ! 112: #define SECTOR 512 /* size of a hardware sector */ ! 113: ! 114: /* ! 115: * monstrous size tables ! 116: * one per type of drive ! 117: */ ! 118: struct size ! 119: { ! 120: daddr_t nblocks; ! 121: int cyloff; ! 122: } up_sizes[8] = { ! 123: 15884, 0, /* A=cyl 0 thru 26 */ ! 124: 33440, 27, /* B=cyl 27 thru 81 */ ! 125: 495520, 0, /* C=cyl 0 thru 814 */ ! 126: 15884, 562, /* D=cyl 562 thru 588 */ ! 127: 55936, 589, /* E=cyl 589 thru 680 */ ! 128: #ifndef NOBADSECT ! 129: 81376, 681, /* F=cyl 681 thru 814 */ ! 130: 153728, 562, /* G=cyl 562 thru 814 */ ! 131: #else ! 132: 81472, 681, ! 133: 153824, 562, ! 134: #endif ! 135: 291346, 82, /* H=cyl 82 thru 561 */ ! 136: }, fj_sizes[8] = { ! 137: 10240, 0, /* A=cyl 0 thru 31 */ ! 138: 20480, 32, /* B=cyl 32 thru 95 */ ! 139: 232640, 96, /* C=cyl 96 thru 822 */ ! 140: 0, 0, ! 141: 0, 0, ! 142: 0, 0, ! 143: 0, 0, ! 144: #ifndef NOBADSECT ! 145: 0, 0, /* H=cyl 155 thru 822 */ ! 146: #else ! 147: 0, 0, ! 148: #endif ! 149: }, fj3_sizes[8] = { ! 150: 10240, 0, /* A=cyl 0 thru 19 */ ! 151: 20480, 20, /* B=cyl 20 thru 59 */ ! 152: 246784, 60, /* C=cyl 60 thru 541 */ ! 153: 246784, 542, /* D=cyl 542 thru 1024 */ ! 154: 0, 0, ! 155: 0, 0, ! 156: 0, 0, ! 157: #ifndef NOBADSECT ! 158: 0, 0, /* H=cyl 155 thru 822 */ ! 159: #else ! 160: 0, 0, ! 161: #endif ! 162: }, cd_sizes[8] = { ! 163: 10240, 0, /* A=cyl 0 thru 63 */ ! 164: 20480, 64, /* B=cyl 64 thru 191 */ ! 165: 100960, 192, /* C=cyl 192 thru 822 */ ! 166: 0, 0, ! 167: 0, 0, ! 168: 0, 0, ! 169: 0, 0, ! 170: #ifndef NOBADSECT ! 171: 100960, 0, /* H=cyl 0 thru 630 */ ! 172: #else ! 173: 100960, 0, ! 174: #endif ! 175: }, fj1_sizes[8] = { ! 176: 1024, 0, /* cyl 0 through 3 */ ! 177: 0, 0, ! 178: 0, 0, ! 179: 0, 0, ! 180: 0, 0, ! 181: 0, 0, ! 182: 0, 0, ! 183: 0, 0, ! 184: }; ! 185: ! 186: /* ! 187: * tables of per-drive info, mostly sizes of things ! 188: * indexed by magic numbers; see uputype ! 189: */ ! 190: struct upst upst[] = { ! 191: 32, 19, 3, 4, 32*19, 823, up_sizes, /* 9300/cdc */ ! 192: /* 9300 actually has 815 cylinders... */ ! 193: 32, 10, 3, 4, 32*10, 823, fj_sizes, /* fujitsu 160m */ ! 194: 32, 5, 3, 4, 32*5, 631, cd_sizes, /* CDC 76 MB */ ! 195: 32, 8, 3, 4, 32*8, 4, fj1_sizes, /* Fixed part of FJ */ ! 196: 32, 16, 3, 4, 32*16, 1024, fj3_sizes, /* fujitsu 330m */ ! 197: }; ! 198: ! 199: u_char up_offset[16] = { ! 200: UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, ! 201: UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, ! 202: UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, ! 203: 0, 0, 0, 0 ! 204: }; ! 205: ! 206: /* ! 207: * things from config ! 208: */ ! 209: extern int upcnt, sccnt; ! 210: extern struct ubaddr scaddr[]; ! 211: extern struct subaddr upaddr[]; ! 212: extern struct scctl scctl[]; ! 213: extern struct updisk updisk[]; ! 214: extern struct buf upbuf[]; ! 215: ! 216: /* ! 217: * controller flags, scctl.flags ! 218: */ ! 219: ! 220: #define CACTIVE 01 /* xfer in progress */ ! 221: #define CWAITING 02 /* xfering and timer has ticked */ ! 222: ! 223: /* ! 224: * unit flags, updisk.flags ! 225: */ ! 226: ! 227: #define UACTIVE 01 /* working on this xfer */ ! 228: #define URXFR 02 /* done with any seeking; ready to roll */ ! 229: #define UWOL 04 /* waiting for offline drive */ ! 230: #define UWAITOL 010 /* waiting and timer has ticked */ ! 231: ! 232: /* ! 233: * device number ! 234: */ ! 235: ! 236: #define UNIT(d) ((minor(d)>>3) & 07) ! 237: #define PART(d) (minor(d) & 07) ! 238: ! 239: /* ! 240: * abuse of spare bits of struct buf ! 241: */ ! 242: #define b_cylin b_resid /* for disksort */ ! 243: #define b_ubm av_back /* this buffer's map */ ! 244: ! 245: int upwstart, upwatch(); /* Have started guardian */ ! 246: int upwaitdry; ! 247: ! 248: int upopen(), upstrategy(), upread(), upwrite(); ! 249: ! 250: struct cdevsw upcdev = cdinit(upopen, nulldev, upread, upwrite, nodev); ! 251: ! 252: struct bdevsw upbdev = bdinit(upopen, nulldev, upstrategy, 0); ! 253: ! 254: upopen(dev, flag) ! 255: int dev, flag; ! 256: { ! 257: if (upuinit(UNIT(dev)) == 0) ! 258: u.u_error = ENXIO; ! 259: } ! 260: ! 261: upuinit(unit) ! 262: register int unit; ! 263: { ! 264: register struct updevice *reg; ! 265: register struct updisk *up; ! 266: register struct subaddr *ua; ! 267: ! 268: if (unit < 0 || unit > upcnt) ! 269: return (0); ! 270: ua = &upaddr[unit]; ! 271: if (ua->ctl < 0) ! 272: return (0); ! 273: up = &updisk[unit]; ! 274: if (up->ctl) ! 275: return (1); ! 276: if (upcinit(ua->ctl) == 0) ! 277: return (0); ! 278: reg = scctl[ua->ctl].addr; ! 279: if ((up->type = uputype(reg, ua->unit)) < 0) { ! 280: printf("up%d absent or bad type\n", unit); ! 281: return (0); ! 282: } ! 283: up->unit = ua->unit; ! 284: up->ctl = &scctl[ua->ctl]; ! 285: up->ctl->drives[ua->unit] = up; ! 286: return (1); ! 287: } ! 288: ! 289: ! 290: /* ! 291: * determine drive type ! 292: * very emulex dependent; should look at drive type register too. ! 293: * perhaps there should be a way to change it? ! 294: * this is called by updump too; ! 295: * be prepared to run without memory management ! 296: * unit is the hardware unit ! 297: * return is an index into upst ! 298: */ ! 299: int ! 300: uputype(reg, unit) ! 301: register struct updevice *reg; ! 302: int unit; ! 303: { ! 304: ! 305: reg->upcs1 = 0; /* conservative */ ! 306: reg->upcs2 = unit; ! 307: if (reg->upcs2&UPCS2_NED) { ! 308: reg->upcs1 = UP_DCLR|UP_GO; ! 309: return (-1); ! 310: } ! 311: reg->uphr = UPHR_MAXTRAK; ! 312: switch (reg->uphr) { ! 313: default: ! 314: reg->upcs1 = UP_DCLR|UP_GO; ! 315: return (-1); ! 316: case 9: ! 317: return (unit >= 4 ? 3 : 1); /* fujitsu hack */ ! 318: case 4: ! 319: return (2); /* CDC 76MB hack */ ! 320: case 7: ! 321: return (3); /* Fixed Fujitsu hack */ ! 322: case 15: ! 323: return (4); /* fuji 330m hack */ ! 324: case 19: ! 325: return (0); /* CDC 300 MB hack */ ! 326: } ! 327: } ! 328: ! 329: upcinit(ctl) ! 330: int ctl; ! 331: { ! 332: register struct scctl *sc; ! 333: register struct updevice *reg; ! 334: ! 335: if (ctl < 0 || ctl >= sccnt) ! 336: return (0); ! 337: sc = &scctl[ctl]; ! 338: if (sc->addr) ! 339: return (1); ! 340: if ((reg = (struct updevice *)ubaddr(&scaddr[ctl])) == 0 ! 341: || ubbadaddr(scaddr[ctl].ubno, ®->upcs1, sizeof(short))) { ! 342: printf("sc%d absent\n", ctl); ! 343: return (0); ! 344: } ! 345: reg->upcs2 = UPCS2_CLR; ! 346: sc->addr = reg; ! 347: sc->ubno = scaddr[ctl].ubno; ! 348: if (upwstart == 0) { ! 349: timeout(upwatch, (caddr_t)0, HZ); ! 350: upwstart++; ! 351: } ! 352: return (1); ! 353: } ! 354: ! 355: upstrategy(bp) ! 356: register struct buf *bp; ! 357: { ! 358: register struct updisk *up; ! 359: register struct upst *st; ! 360: register int unit; ! 361: register int part; ! 362: long sz; ! 363: int s; ! 364: ! 365: sz = (bp->b_bcount+SECTOR-1)/SECTOR; ! 366: unit = UNIT(bp->b_dev); ! 367: up = &updisk[unit]; ! 368: if (up->ctl == 0) { ! 369: bp->b_flags |= B_ERROR; ! 370: iodone(bp); ! 371: return; ! 372: } ! 373: st = &upst[up->type]; ! 374: part = PART(bp->b_dev); ! 375: if (bp->b_blkno < 0 || bp->b_blkno+sz > st->sizes[part].nblocks) { ! 376: if (bp->b_blkno == st->sizes[part].nblocks) ! 377: bp->b_resid = bp->b_bcount; ! 378: else { /* partial read too hard for now */ ! 379: bp->b_error = ENXIO; ! 380: bp->b_flags |= B_ERROR; ! 381: } ! 382: iodone(bp); ! 383: return; ! 384: } ! 385: bp->b_cylin = bp->b_blkno/st->nspc + st->sizes[part].cyloff; ! 386: bp->b_ubm = (struct buf *)ubmbuf(up->ctl->ubno, bp, USLP); ! 387: s = spl6(); ! 388: disksort(&up->actf, &up->actl, bp); ! 389: if ((up->flags & UACTIVE) == 0) { ! 390: upustart(up); ! 391: if (up->ctl->actf && (up->ctl->flags & CACTIVE) == 0) ! 392: upstart(up->ctl); ! 393: } ! 394: splx(s); ! 395: } ! 396: ! 397: /* ! 398: * unit start: ! 399: * if there's a block for this drive, start seeking there ! 400: * ! 401: * up->upcs = UP_IE cancels a pending command in the SC21 ! 402: * why not up->cs |= UP_IE? ! 403: */ ! 404: upustart(up) ! 405: register struct updisk *up; ! 406: { ! 407: register struct buf *bp; ! 408: register struct updevice *reg; ! 409: register struct scctl *sc; ! 410: register struct upst *st; ! 411: int sn, csn; ! 412: int didie = 0; ! 413: ! 414: sc = up->ctl; ! 415: if ((bp = up->actf) == NULL) ! 416: return (0); ! 417: #ifndef NOUPSEEK ! 418: if (sc->flags & CACTIVE) { /* can't start seek till xfer done */ ! 419: sc->softas |= 1<<up->unit; ! 420: return (0); ! 421: } ! 422: #endif ! 423: reg = sc->addr; ! 424: reg->upcs2 = up->unit; ! 425: if ((reg->upds & UPDS_VV) == 0) { ! 426: reg->upcs1 = UP_IE|UP_DCLR|UP_GO; ! 427: reg->upcs1 = UP_IE|UP_PRESET|UP_GO; ! 428: reg->upof = UPOF_FMT22; ! 429: didie = 1; ! 430: } ! 431: if ((reg->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) { ! 432: up->flags |= UWOL; ! 433: return (didie); ! 434: } ! 435: if ((up->flags & UACTIVE) == 0) { /* start seek if didn't already */ ! 436: up->flags |= UACTIVE; ! 437: #ifndef NOUPSEEK ! 438: st = &upst[up->type]; ! 439: sn = bp->b_blkno%st->nspc; ! 440: sn = (sn + st->nsect - st->sdist) % st->nsect; /* sector to seek to */ ! 441: csn = sn - (reg->upla>>6); ! 442: if (csn < 0) ! 443: csn += st->nsect; ! 444: if (bp->b_cylin != reg->updc /* seek if off cylinder */ ! 445: || csn > st->rdist) { /* or not close enough */ ! 446: reg->updc = bp->b_cylin; ! 447: reg->upda = sn; ! 448: reg->upcs1 = UP_IE|UP_SEARCH|UP_GO; ! 449: return (1); ! 450: } ! 451: #endif ! 452: } ! 453: if ((up->flags & URXFR) == 0) { /* seek done, put on ctl queue */ ! 454: up->next = NULL; ! 455: if (sc->actf == NULL) ! 456: sc->actf = up; ! 457: else ! 458: sc->actl->next = up; ! 459: sc->actl = up; ! 460: up->flags |= URXFR; ! 461: } ! 462: return (didie); ! 463: } ! 464: ! 465: /* ! 466: * Start up a transfer on a drive. ! 467: */ ! 468: upstart(sc) ! 469: register struct scctl *sc; ! 470: { ! 471: register struct buf *bp; ! 472: register struct updisk *up; ! 473: register struct updevice *reg; ! 474: register struct upst *st; ! 475: register c; ! 476: uaddr_t uad; ! 477: int sn, tn; ! 478: ! 479: loop: ! 480: if ((up = sc->actf) == NULL) ! 481: return (0); ! 482: if ((bp = up->actf) == NULL) { ! 483: sc->actf = up->next; ! 484: goto loop; ! 485: } ! 486: sc->flags |= CACTIVE; ! 487: st = &upst[up->type]; ! 488: sn = bp->b_blkno%st->nspc; ! 489: tn = sn/st->nsect; ! 490: sn %= st->nsect; ! 491: reg = sc->addr; ! 492: reg->upcs2 = up->unit; ! 493: c = 0; ! 494: while ((reg->upds&UPDS_DRY) == 0) { ! 495: if (++c > 512) ! 496: break; ! 497: upwaitdry++; ! 498: } ! 499: if ((reg->upds & UPDS_DREADY) != UPDS_DREADY) { ! 500: printf("up%d: not ready", UNIT(bp->b_dev)); ! 501: if ((reg->upds & UPDS_DREADY) != UPDS_DREADY) { ! 502: printf("\n"); ! 503: sc->flags &=~ (CACTIVE|CWAITING); ! 504: sc->errcnt = 0; ! 505: up->actf = bp->av_forw; ! 506: up->flags &=~ (UACTIVE|URXFR); ! 507: bp->b_flags |= B_ERROR; ! 508: iodone(bp); ! 509: goto loop; ! 510: } ! 511: printf(" (flakey)\n"); /* inscrutable */ ! 512: } ! 513: reg->updc = bp->b_cylin; ! 514: reg->upda = (tn << 8) + sn; ! 515: reg->upwc = -bp->b_bcount / sizeof(short); ! 516: if (bp->b_flags & B_READ) ! 517: c = UP_IE|UP_RCOM|UP_GO; ! 518: else ! 519: c = UP_IE|UP_WCOM|UP_GO; ! 520: bp->b_ubm = (struct buf *)ubinspath(ubmapath(sc->ubno), (ubm_t)bp->b_ubm); ! 521: uad = ubadbuf(sc->ubno, bp, (ubm_t)bp->b_ubm); ! 522: reg->upba = uad; ! 523: reg->upcs1 = c|((uad>>8)&0x300); ! 524: return (1); ! 525: } ! 526: ! 527: /* ! 528: * Handle a disk interrupt. ! 529: */ ! 530: sc0int(ctl) ! 531: int ctl; ! 532: { ! 533: register struct updevice *reg; ! 534: register struct scctl *sc; ! 535: register struct updisk *up; ! 536: register struct buf *bp; ! 537: register int unit, i, as; ! 538: int needie; ! 539: ! 540: if (ctl < 0 || ctl >= sccnt) { ! 541: printf("sc%d bad intr\n"); ! 542: return; ! 543: } ! 544: sc = &scctl[ctl]; ! 545: if ((reg = sc->addr) == 0) { ! 546: printf("sc%d: stray intr\n"); ! 547: return; ! 548: } ! 549: needie = 1; ! 550: as = (reg->upas & 0377) | sc->softas; ! 551: sc->softas = 0; ! 552: if ((sc->flags & CACTIVE) == 0) { /* must be a seek */ ! 553: if (reg->upcs1 & UP_TRE) ! 554: reg->upcs1 = UP_TRE; ! 555: goto doattn; ! 556: } ! 557: up = sc->actf; ! 558: bp = up->actf; ! 559: reg->upcs2 = up->unit; ! 560: if ((reg->upds&UPDS_ERR) || (reg->upcs1&UP_TRE)) { ! 561: i = 0; ! 562: while ((reg->upds & UPDS_DRY) == 0) { ! 563: if (++i > 512) ! 564: break; ! 565: upwaitdry++; ! 566: } ! 567: if (reg->uper1&UPER1_WLE) { ! 568: printf("up%d: write locked\n", UNIT(bp->b_dev)); ! 569: bp->b_flags |= B_ERROR; ! 570: } else if (++sc->errcnt > 27) { ! 571: harderr(bp, "up"); ! 572: printf("cs2=%o er1=%o er2=%o\n", ! 573: reg->upcs2&0177777, reg->uper1&0177777, reg->uper2&0177777); ! 574: bp->b_flags |= B_ERROR; ! 575: } else { ! 576: /* ! 577: * soft ecc, try to correct ! 578: */ ! 579: sc->flags &=~ (CACTIVE|CWAITING); /* force retry */ ! 580: if ((reg->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) ! 581: if (upecc(up)) ! 582: return; /* probably wrong */ ! 583: } ! 584: /* ! 585: * `hard' error. clear and try again ! 586: */ ! 587: reg->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; ! 588: needie = 0; ! 589: if ((sc->errcnt&07) == 4 && (sc->flags & CACTIVE) == 0) { ! 590: reg->upcs1 = UP_RECAL|UP_IE|UP_GO; ! 591: sc->recal = 0; ! 592: goto nextrecal; ! 593: } ! 594: } ! 595: /* ! 596: * Advance recalibration finite state machine ! 597: * if recalibrate in progress, through ! 598: * RECAL ! 599: * SEEK ! 600: * OFFSET (optional) ! 601: * RETRY ! 602: */ ! 603: switch (sc->recal) { ! 604: case 1: ! 605: reg->updc = bp->b_cylin; ! 606: reg->upcs1 = UP_SEEK|UP_IE|UP_GO; ! 607: goto nextrecal; ! 608: case 2: ! 609: if (sc->errcnt < 16 || (bp->b_flags&B_READ) == 0) ! 610: goto donerecal; ! 611: reg->upof = up_offset[sc->errcnt & 017] | UPOF_FMT22; ! 612: reg->upcs1 = UP_IE|UP_OFFSET|UP_GO; ! 613: nextrecal: ! 614: sc->recal++; ! 615: sc->flags |= CACTIVE; ! 616: return; ! 617: ! 618: donerecal: ! 619: case 3: ! 620: sc->recal = 0; ! 621: sc->flags &=~ CACTIVE; ! 622: break; ! 623: } ! 624: if (sc->flags & CACTIVE) { /* `active' means we're done */ ! 625: if (sc->errcnt >= 16) { ! 626: reg->upof = UPOF_FMT22; ! 627: reg->upcs1 = UP_RTC|UP_GO|UP_IE; ! 628: while (reg->upds & UPDS_PIP) ! 629: DELAY(25); ! 630: needie = 0; ! 631: } ! 632: sc->flags &=~ (CACTIVE|CWAITING); ! 633: sc->errcnt = 0; ! 634: sc->actf = up->next; ! 635: up->flags &=~ (UACTIVE|URXFR); ! 636: up->actf = bp->av_forw; ! 637: bp->b_resid = (-reg->upwc * sizeof(short)); ! 638: ubmfree(sc->ubno, (ubm_t)bp->b_ubm); ! 639: iodone(bp); ! 640: if (up->actf) ! 641: if (upustart(up)) ! 642: needie = 0; ! 643: } ! 644: as |= reg->upas; ! 645: as &= ~(1<<up->unit); ! 646: doattn: ! 647: /* ! 648: * Process other units which need attention. ! 649: */ ! 650: for (unit = 0, i = 1; unit < NSCUP && as; i <<= 1, unit++) { ! 651: if ((as & i) == 0) ! 652: continue; ! 653: as &= ~i; ! 654: reg->upas = i; ! 655: if ((up = sc->drives[unit]) != NULL && upustart(up)) ! 656: needie = 0; ! 657: } ! 658: if (sc->actf && (sc->flags & CACTIVE) == 0) ! 659: if (upstart(sc)) ! 660: needie = 0; ! 661: if (needie) ! 662: reg->upcs1 = UP_IE; /* why bother? */ ! 663: } ! 664: ! 665: upread(dev) ! 666: dev_t dev; ! 667: { ! 668: physio(upstrategy, &upbuf[UNIT(dev)], dev, B_READ, minphys); ! 669: } ! 670: ! 671: upwrite(dev) ! 672: dev_t dev; ! 673: { ! 674: physio(upstrategy, &upbuf[UNIT(dev)], dev, B_WRITE, minphys); ! 675: } ! 676: ! 677: /* ! 678: * correct an ECC error and restart the transfer ! 679: * the error is (upec1-1) bits into the current sector; ! 680: * at that point, the bits set in upec2 are wrong. ! 681: * ! 682: * should be able just to set the GO bit and proceed, ! 683: * but emulex insists we do DCLR first, or so the book says, ! 684: * because DCK sets ERR in upds ! 685: */ ! 686: upecc(up) ! 687: register struct updisk *up; ! 688: { ! 689: register struct updevice *reg; ! 690: register struct scctl *sc; ! 691: register struct buf *bp; ! 692: register int i; ! 693: int nxf; ! 694: unsigned int mask; ! 695: uaddr_t uad, lastua; ! 696: int xc, xa; ! 697: ! 698: if ((bp = up->actf) == NULL || (sc = up->ctl) == NULL) ! 699: panic("upecc"); ! 700: reg = sc->addr; ! 701: ubmflush(sc->ubno, ubmpath((ubm_t)bp->b_ubm)); ! 702: lastua = reg->upba + ((reg->upcs1&0x300)<<8); ! 703: nxf = bp->b_bcount + (reg->upwc * sizeof(short)); ! 704: i = reg->upec1 - 1; /* -1 makes 0 origin */ ! 705: uad = lastua - (nxf > SECTOR ? SECTOR : nxf) + ((i&~07)>>3); ! 706: mask = reg->upec2; ! 707: mask <<= i&07; ! 708: for (; uad < lastua && mask; mask >>= 8, uad++) ! 709: ubputc(sc->ubno, uad, ubgetc(sc->ubno, uad)^mask); ! 710: printf("up%d%o: soft ecc sec %ld\n", UNIT(bp->b_dev), PART(bp->b_dev), ! 711: bp->b_blkno + nxf/SECTOR - 1); ! 712: sc->flags |= CACTIVE; /* either complete or continuing */ ! 713: if (reg->upwc == 0) ! 714: return (0); ! 715: #ifdef notdef ! 716: reg->uper1 = 0; ! 717: reg->upcs1 |= UP_GO; ! 718: #else /* clear wretched emulex error */ ! 719: xc = reg->updc; ! 720: xa = reg->upda; ! 721: /* ba, wc undisturbed by DCLR */ ! 722: reg->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; ! 723: reg->updc = xc; ! 724: reg->upda = xa; ! 725: reg->upba = lastua; ! 726: i = (lastua >> 8) & 0x300; ! 727: i |= UP_IE|UP_GO|UP_RCOM; ! 728: reg->upcs1 = i; ! 729: #endif ! 730: return (1); ! 731: } ! 732: ! 733: /* ! 734: * check for offline drives and hung controllers ! 735: */ ! 736: ! 737: upwatch() ! 738: { ! 739: register struct scctl *sc; ! 740: register struct updisk *up; ! 741: register struct updevice *reg; ! 742: register struct buf *bp; ! 743: register int ounit; ! 744: register int s; ! 745: ! 746: s = spl6(); ! 747: timeout(upwatch, (caddr_t)0, 15*HZ); ! 748: for (up = &updisk[upcnt-1]; up >= updisk; up--) { ! 749: if ((up->flags & UWOL) == 0) ! 750: continue; ! 751: reg = up->ctl->addr; ! 752: ounit = reg->upcs2 & UPCS2_SEL; ! 753: reg->upcs2 = up->unit; ! 754: if ((reg->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) { ! 755: if ((up->flags & UWAITOL) == 0) { ! 756: up->flags |= UWAITOL; ! 757: reg->upcs2 = ounit; ! 758: continue; ! 759: } ! 760: printf("up%d offline\n", up - updisk); ! 761: while ((bp = up->actf) != NULL) { ! 762: bp->b_flags |= B_ERROR; ! 763: up->actf = bp->av_forw; ! 764: ubmfree(up->ctl->ubno, (ubm_t)bp->b_ubm); ! 765: iodone(bp); ! 766: } ! 767: } ! 768: up->flags &=~ (UWAITOL|UWOL); ! 769: upustart(up); ! 770: reg->upcs2 = ounit; ! 771: } ! 772: for (sc = &scctl[sccnt-1]; sc >= scctl; sc--) { ! 773: if (sc->flags & CACTIVE) { ! 774: if ((sc->flags & CWAITING) == 0) ! 775: sc->flags |= CWAITING; ! 776: else { ! 777: sc->addr->upcs2 = UPCS2_CLR; ! 778: printf("sc%d hung, kicked\n", sc - scctl); ! 779: sc->flags &=~ (CWAITING|CACTIVE); ! 780: } ! 781: } ! 782: if (sc->actf && (sc->flags & CACTIVE) == 0) ! 783: upstart(sc); ! 784: } ! 785: splx(s); ! 786: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.