|
|
1.1 ! root 1: /* ! 2: * MASSBUS SMD disk driver ! 3: */ ! 4: ! 5: #include "sys/param.h" ! 6: #include "sys/buf.h" ! 7: #include "sys/conf.h" ! 8: #include "sys/dir.h" ! 9: #include "sys/user.h" ! 10: #include "sys/hp.h" ! 11: #include "sys/mbaddr.h" ! 12: #include "sys/mbsts.h" ! 13: #include "sys/bad144.h" ! 14: ! 15: /* ! 16: * hardware registers ! 17: */ ! 18: ! 19: struct hpdevice { ! 20: int hpcs1; /* control and status register 1 */ ! 21: int hpds; /* drive status */ ! 22: int hper1; /* error register 1 */ ! 23: int hpmr; /* maintenance */ ! 24: int hpas; /* attention summary */ ! 25: int hpda; /* desired address register */ ! 26: int hpdt; /* drive type */ ! 27: int hpla; /* look ahead */ ! 28: int hpsn; /* serial number */ ! 29: int hpof; /* offset register */ ! 30: int hpdc; /* desired cylinder address register */ ! 31: int hpcc; /* current cylinder */ ! 32: /* on an rp drive, mr2 is called er2 and er2 is called er3 */ ! 33: /* we use rm terminology here */ ! 34: int hpmr2; /* maintenance register 2 */ ! 35: int hper2; /* error register 2 */ ! 36: int hpec1; /* burst error bit position */ ! 37: int hpec2; /* burst error bit pattern */ ! 38: }; ! 39: ! 40: /* ! 41: * hpcs1 ! 42: */ ! 43: ! 44: #define HP_GO 0000001 ! 45: ! 46: #define HP_SEEK 004 /* seek */ ! 47: #define HP_RECAL 006 /* recalibrate */ ! 48: #define HP_DCLR 010 /* drive clear */ ! 49: #define HP_OFFSET 014 /* offset */ ! 50: #define HP_RTC 016 /* return to center-line */ ! 51: #define HP_PRESET 020 /* read-in preset */ ! 52: #define HP_SEARCH 030 /* search */ ! 53: #define HP_WCOM 060 /* write */ ! 54: #define HP_RCOM 070 /* read data */ ! 55: ! 56: /* ! 57: * hpds ! 58: */ ! 59: #define HPDS_ERR 0040000 /* composite drive error */ ! 60: #define HPDS_PIP 0020000 /* positioning in progress */ ! 61: #define HPDS_MOL 0010000 /* medium on line */ ! 62: #define HPDS_DPR 0000400 /* drive present */ ! 63: #define HPDS_DRY 0000200 /* drive ready */ ! 64: #define HPDS_VV 0000100 /* volume valid */ ! 65: #define HPDS_DREADY (HPDS_DPR|HPDS_DRY|HPDS_MOL|HPDS_VV) ! 66: ! 67: /* ! 68: * hper1 ! 69: */ ! 70: #define HPER1_DCK 0100000 /* data check */ ! 71: #define HPER1_WLE 0004000 /* write lock error */ ! 72: #define HPER1_ECH 0000100 /* ecc hard error */ ! 73: #define HPER1_FER 0000020 /* format error */ ! 74: ! 75: /* ! 76: * hpdt ! 77: */ ! 78: #define HPDT_TYPE 0x1ff ! 79: #define HPDT_RP05 021 ! 80: #define HPDT_RP06 022 ! 81: #define HPDT_RP07 042 ! 82: #define HPDT_RM03 024 ! 83: #define HPDT_RM05 027 ! 84: #define HPDT_FUJI 025 ! 85: ! 86: /* ! 87: * hpcc: emulex hack ! 88: */ ! 89: #define HPHR_MAXCYL 0100027 /* max cyl address */ ! 90: #define HPHR_MAXTRAK 0100030 /* max track address */ ! 91: #define HPHR_MAXSECT 0100031 /* max sector address */ ! 92: ! 93: /* ! 94: * hpof ! 95: */ ! 96: #define HPOF_FMT22 0010000 /* 16 bit format */ ! 97: #define HPOF_P400 0020 /* +400 uinches */ ! 98: #define HPOF_M400 0220 /* -400 uinches */ ! 99: #define HPOF_P800 0040 /* +800 uinches */ ! 100: #define HPOF_M800 0240 /* -800 uinches */ ! 101: #define HPOF_P1200 0060 /* +1200 uinches */ ! 102: #define HPOF_M1200 0260 /* -1200 uinches */ ! 103: ! 104: /* ! 105: * hper2 ! 106: */ ! 107: #define HPER2_BSE 0100000 /* bad sector */ ! 108: ! 109: #define SECTOR 512 /* size of a hardware sector */ ! 110: ! 111: /* ! 112: * monstrous size tables ! 113: * one per type of drive ! 114: */ ! 115: struct size ! 116: { ! 117: daddr_t nblocks; ! 118: int cyloff; ! 119: }; ! 120: struct size hp6_sizes[8] = { ! 121: 15884, 0, /* A=cyl 0 thru 37 */ ! 122: 33440, 38, /* B=cyl 38 thru 117 */ ! 123: 340670, 0, /* C=cyl 0 thru 814 */ ! 124: 0, 0, ! 125: 0, 0, ! 126: 0, 0, ! 127: #ifndef NOBADSECT ! 128: 291280, 118, /* G=cyl 118 thru 814 */ ! 129: #else ! 130: 291346, 118, ! 131: #endif ! 132: 0, 0, ! 133: }; ! 134: struct size rm3_sizes[8] = { ! 135: 15884, 0, /* A=cyl 0 thru 99 */ ! 136: 33440, 100, /* B=cyl 100 thru 309 */ ! 137: 131680, 0, /* C=cyl 0 thru 822 */ ! 138: 0, 0, ! 139: 0, 0, ! 140: 0, 0, ! 141: #ifndef NOBADSECT ! 142: 81984, 310, /* G=cyl 310 thru 822 */ ! 143: #else ! 144: 82080, 310, ! 145: #endif ! 146: 113280, 115, /* H=cyl 115 thru 708 -- ex 32v */ ! 147: }; ! 148: struct size rm5_sizes[8] = { ! 149: 15884, 0, /* A=cyl 0 thru 26 */ ! 150: 33440, 27, /* B=cyl 27 thru 81 */ ! 151: 500384, 0, /* C=cyl 0 thru 822 */ ! 152: 15884, 562, /* D=cyl 562 thru 588 */ ! 153: 55936, 589, /* E=cyl 589 thru 680 */ ! 154: #ifndef NOBADSECT ! 155: 86240, 681, /* F=cyl 681 thru 822 */ ! 156: 158592, 562, /* G=cyl 562 thru 822 */ ! 157: #else ! 158: 86636, 681, ! 159: 158688, 562, ! 160: #endif ! 161: 291346, 82, /* H=cyl 82 thru 561 */ ! 162: }; ! 163: struct size mfj_sizes[8] = { ! 164: 10240, 0, /* A=cyl 0 thru 31 */ ! 165: 20480, 32, /* B=cyl 32 thru 95 */ ! 166: 232640, 96, /* C=cyl 96 thru 822 */ ! 167: 0, 0, ! 168: 0, 0, ! 169: 0, 0, ! 170: 0, 0, ! 171: 0, 0, ! 172: }; ! 173: struct size eagle_sizes[8] ={ ! 174: 27520, 0, /* A=cyl 0 thru 31 */ ! 175: 27520, 32, /* B=cyl 32 thru 63 */ ! 176: 667360, 64, /* C=cyl 64 thru 839 */ ! 177: 232640, 64, /* D=cyl 64 thru 340 (partial) */ ! 178: 232640, 341, /* E=cyl 341 thru 617 (partial) */ ! 179: 0, 0, ! 180: 0, 0, ! 181: 0, 0, ! 182: }; ! 183: /* 48 sector Emulex Eagle */ ! 184: struct size eag48_sizes[8] = { /* cyl 841 used for bad sectors + info */ ! 185: #ifndef OLDPART ! 186: 11*960, 0, /* A = cyl 0 thru 10 for / */ ! 187: 22*960, 11, /* B = cyl 11 thru 32 for swap */ ! 188: 842*960, 0, /* C = all cyl 0 thru 841 for testing */ ! 189: 16*960, 33, /* D = cyl 33 thru 48 for /usr/guest */ ! 190: 66*960, 49, /* E = cyl 49 thru 114 for /usr/src */ ! 191: 242*960,115, /* F = cyl 115 thru 356 nearly 1/3 */ ! 192: 242*960,357, /* G = cyl 357 thru 598 nearly 1/3 */ ! 193: 242*960,599, /* H = cyl 599 thru 840 nearly 1/3 */ ! 194: #else /* old jones partitions */ ! 195: 45*960, 0, /* A = cyl 0 thru 44 for /tmp */ ! 196: 64*960, 45, /* B = cyl 45 thru 108 for swap */ ! 197: 842*960, 0, /* C = all cyl 0 thru 841 for testing */ ! 198: 244*960,109, /* D = cyl 109 thru 352 nearly 1/3 */ ! 199: 244*960,353, /* E = cyl 353 thru 596 nearly 1/3 */ ! 200: 244*960,597, /* F = cyl 597 thru 840 nearly 1/3 */ ! 201: 0, 0, /* G = cyl 0 thru 402 nearly 1/2 */ ! 202: 0, 0, /* H = cyl 438 thru 840 nearly 1/2 */ ! 203: #endif ! 204: }; ! 205: struct size hp7_sizes[8] = { ! 206: 15884, 0, /* A=cyl 0 thru 9 */ ! 207: 64000, 10, /* B=cyl 10 thru 49 */ ! 208: 1008000,0, /* C=cyl 0 thru 629 */ ! 209: 504000, 0, /* D=cyl 0 thru 314 */ ! 210: 504000, 315, /* E=cyl 315 thru 629 */ ! 211: 928000, 50, /* F=cyl 50 thru 629 */ ! 212: 0, 0, ! 213: 0, 0, ! 214: }; ! 215: ! 216: /* ! 217: * tables of per-drive info, mostly sizes of things ! 218: * indexed by numbers in hptypes ! 219: */ ! 220: ! 221: struct hptype hptype[] = { ! 222: HPDT_RM03, 32, 5, 3, 4, 32*5, 823, rm3_sizes, /* RM03 */ ! 223: HPDT_RM05, 32, 19, 2, 3, 32*19, 823, rm5_sizes, /* RM05 */ ! 224: HPDT_RP06, 22, 19, 2, 3, 22*19, 815, hp6_sizes, /* RP06 */ ! 225: HPDT_RP05, 22, 19, 2, 3, 22*19, 411, hp6_sizes, /* RP05 */ ! 226: HPDT_RP07, 50, 32, 2, 3, 50*32, 630, hp7_sizes, /* RP07 */ ! 227: /* HPDT_FUJI (emulex) entries must be contiguous and last */ ! 228: HPDT_FUJI, 32, 10, 2, 3, 32*10, 823, mfj_sizes, /* little fujitsu */ ! 229: HPDT_FUJI, 43, 20, 8, 9, 43*20, 842, eagle_sizes, /* eagle */ ! 230: HPDT_FUJI, 48, 20, 8, 9, 48*20, 842, eag48_sizes, /* eagle 48 sectors */ ! 231: 0 ! 232: }; ! 233: ! 234: #define NOFFS 16 ! 235: unsigned char hp_offset[NOFFS] = { ! 236: HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400, ! 237: HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800, ! 238: HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200, ! 239: 0, 0, 0, 0 ! 240: }; ! 241: ! 242: /* ! 243: * things from config ! 244: */ ! 245: extern int hpcnt; ! 246: extern struct mbaddr hpaddr[]; ! 247: extern struct hpdisk hpdisk[]; ! 248: extern struct buf hpbuf[]; ! 249: extern struct buf hpbadbuf[]; ! 250: extern struct bad144 hpbad[]; ! 251: ! 252: /* ! 253: * unit flags, hpdisk.flags ! 254: */ ! 255: ! 256: #define UACTIVE 01 /* started seek */ ! 257: #define UXFER 02 /* done with any seeking; ready to transfer */ ! 258: #define UWOL 04 /* waiting for offline drive */ ! 259: #define UWAITOL 010 /* waiting and timer has ticked */ ! 260: #define UHAVBAD 020 /* have read bad block table */ ! 261: #define UREVEC 040 /* halfway through reading revectored sector */ ! 262: ! 263: /* ! 264: * device number ! 265: */ ! 266: ! 267: #define UNIT(d) ((minor(d)>>3) & 07) ! 268: #define PART(d) (minor(d) & 07) ! 269: ! 270: /* ! 271: * abuse of spare bits of struct buf ! 272: */ ! 273: #define b_cylin b_resid /* for disksort */ ! 274: ! 275: int hpwstart; ! 276: int hpwatch(); ! 277: int hpwaitdry; ! 278: ! 279: int hpopen(), hpstrategy(), hpread(), hpwrite(); ! 280: struct cdevsw hpcdev = cdinit(hpopen, nulldev, hpread, hpwrite, nodev); ! 281: struct bdevsw hpbdev = bdinit(hpopen, nulldev, hpstrategy, 0); ! 282: ! 283: hpopen(dev, flag) ! 284: int dev, flag; ! 285: { ! 286: if (hpuinit(UNIT(dev)) == 0) ! 287: u.u_error = ENXIO; ! 288: } ! 289: ! 290: static char hponce; ! 291: ! 292: hpuinit(unit) ! 293: register int unit; ! 294: { ! 295: register struct hpdevice *reg; ! 296: register struct hpdisk *hp; ! 297: ! 298: if (unit < 0 || unit > hpcnt) ! 299: return (0); ! 300: hp = &hpdisk[unit]; ! 301: if (hp->addr) ! 302: return (1); ! 303: if ((reg = (struct hpdevice *)mbaddr(&hpaddr[unit])) == NULL ! 304: || badaddr(®->hpcs1, sizeof(long)) ! 305: || (reg->hpds & HPDS_DPR) == 0) { ! 306: printf("hp%d absent\n", unit); ! 307: return (0); ! 308: } ! 309: if ((hp->type = hputype(reg)) < 0) { ! 310: printf("hp%d absent or bad type\n", unit); ! 311: return (0); ! 312: } ! 313: hp->addr = reg; ! 314: if (hponce == 0) { ! 315: hponce++; ! 316: hpwatch(); ! 317: } ! 318: return (1); ! 319: } ! 320: ! 321: /* ! 322: * determine drive type ! 323: * this is called by hpdump too; ! 324: * be prepared to run without memory management ! 325: * return is an index into hpst ! 326: */ ! 327: int ! 328: hputype(reg) ! 329: register struct hpdevice *reg; ! 330: { ! 331: register int t, i; ! 332: register int nsect, ntrak; ! 333: ! 334: t = reg->hpdt & HPDT_TYPE; ! 335: for (i = 0; hptype[i].type; i++) ! 336: if (hptype[i].type == t) ! 337: break; ! 338: if (hptype[i].type == 0) { ! 339: printf("hp type 0%o unknown\n", t); ! 340: return (-1); ! 341: } ! 342: if (hptype[i].type != HPDT_FUJI) ! 343: return (i); ! 344: /* ! 345: * special hackery for emulex ! 346: */ ! 347: reg->hpcc = HPHR_MAXTRAK; ! 348: DELAY(2); /* hack */ ! 349: ntrak = reg->hpcc + 1; ! 350: ntrak &= 0xffff; ! 351: reg->hpcc = HPHR_MAXSECT; ! 352: DELAY(2); /* hack */ ! 353: nsect = reg->hpcc + 1; ! 354: nsect &= 0xffff; ! 355: for (; hptype[i].type; i++) ! 356: if (ntrak == hptype[i].ntrak && nsect == hptype[i].nsect) ! 357: return (i); ! 358: /* ! 359: * 48-sector eagle known to be last, ! 360: * so the following broken-hardware test might work ! 361: */ ! 362: if (nsect == 46) { ! 363: printf("hp said ntrak %d nsect %d, eag48 assumed\n", ntrak, nsect); ! 364: return (i - 1); ! 365: } ! 366: printf("hp fuji ntrak %d nsect %d unknown\n", ntrak, nsect); ! 367: return (-1); ! 368: } ! 369: ! 370: /* ! 371: * a subtlety: ! 372: * b_cylin = cylinder number; ! 373: * later, when computing disk address, ! 374: * we use b_cylin, and take b_blkno % cylindersize ! 375: * i.e. there's an embedded assumption that every disk partition ! 376: * begins on a cylinder boundary ! 377: */ ! 378: hpstrategy(bp) ! 379: register struct buf *bp; ! 380: { ! 381: register struct hpdisk *hp; ! 382: register struct hptype *st; ! 383: register int unit; ! 384: register int part; ! 385: long sz; ! 386: int s; ! 387: ! 388: sz = (bp->b_bcount+SECTOR-1)/SECTOR; ! 389: unit = UNIT(bp->b_dev); ! 390: hp = &hpdisk[unit]; ! 391: if (hp->addr == NULL) { /* safety check */ ! 392: bp->b_flags |= B_ERROR; ! 393: iodone(bp); ! 394: return; ! 395: } ! 396: st = &hptype[hp->type]; ! 397: part = PART(bp->b_dev); ! 398: if (bp->b_blkno < 0 || bp->b_blkno+sz > st->sizes[part].nblocks) { ! 399: if (bp->b_blkno == st->sizes[part].nblocks) ! 400: bp->b_resid = bp->b_bcount; ! 401: else { /* partial read too hard for now */ ! 402: bp->b_error = ENXIO; ! 403: bp->b_flags |= B_ERROR; ! 404: } ! 405: iodone(bp); ! 406: return; ! 407: } ! 408: bp->b_cylin = bp->b_blkno/st->nspc + st->sizes[part].cyloff; ! 409: s = spl6(); ! 410: disksort(&hp->actf, &hp->actl, bp); ! 411: if ((hp->flags & UACTIVE) == 0) ! 412: hpustart(hp); ! 413: splx(s); ! 414: } ! 415: ! 416: /* ! 417: * unit start: ! 418: * if there's a block for this drive, start seeking there ! 419: */ ! 420: int hpxfer(); ! 421: ! 422: hpustart(hp) ! 423: register struct hpdisk *hp; ! 424: { ! 425: register struct buf *bp; ! 426: register struct hpdevice *reg; ! 427: register struct hptype *st; ! 428: int sn, csn; ! 429: ! 430: if ((bp = hp->actf) == NULL) ! 431: return; ! 432: reg = hp->addr; ! 433: if ((reg->hpds & HPDS_VV) == 0) { ! 434: reg->hpcs1 = HP_DCLR|HP_GO; ! 435: reg->hpcs1 = HP_PRESET|HP_GO; ! 436: reg->hpof = HPOF_FMT22; ! 437: hp->flags &=~ UHAVBAD; ! 438: } ! 439: if ((hp->flags & UHAVBAD) == 0) { ! 440: hprbad(hp); ! 441: bp = hp->actf; ! 442: hp->flags |= UHAVBAD; ! 443: } ! 444: if ((reg->hpds & (HPDS_DPR|HPDS_MOL)) != (HPDS_DPR|HPDS_MOL)) { ! 445: hp->flags |= UWOL; ! 446: return; ! 447: } ! 448: if ((hp->flags & UACTIVE) == 0) { /* start seek if didn't already */ ! 449: hp->flags |= UACTIVE; ! 450: st = &hptype[hp->type]; ! 451: sn = bp->b_blkno%st->nsect - st->sdist; /* seek here before io */ ! 452: if (sn < 0) ! 453: sn += st->nsect; ! 454: csn = sn - (reg->hpla>>6); ! 455: if (csn < 0) ! 456: csn += st->nsect; ! 457: if (bp->b_cylin != reg->hpdc /* seek if off cylinder */ ! 458: || csn > st->rdist) { /* or not close enough */ ! 459: reg->hpdc = bp->b_cylin; ! 460: reg->hpda = sn; ! 461: reg->hpcs1 = HP_SEARCH|HP_GO; ! 462: return; ! 463: } ! 464: } ! 465: if ((hp->flags & UXFER) == 0) { /* seek done, time for transfer */ ! 466: hp->flags |= UXFER; ! 467: mbstart(&hpaddr[UNIT(bp->b_dev)], bp, hpxfer); ! 468: } ! 469: } ! 470: ! 471: /* ! 472: * start transfer ! 473: */ ! 474: hpxfer(bp) ! 475: register struct buf *bp; ! 476: { ! 477: register struct hpdisk *hp; ! 478: register struct hpdevice *reg; ! 479: register struct hptype *st; ! 480: int sn, tn; ! 481: ! 482: hp = &hpdisk[UNIT(bp->b_dev)]; ! 483: st = &hptype[hp->type]; ! 484: sn = bp->b_blkno%st->nspc; ! 485: tn = sn/st->nsect; ! 486: sn %= st->nsect; ! 487: reg = hp->addr; ! 488: if ((reg->hpds & HPDS_DREADY) != HPDS_DREADY) { ! 489: printf("hp%d: not ready\n", UNIT(bp->b_dev)); ! 490: hp->errcnt = 0; ! 491: hp->actf = bp->av_forw; ! 492: hp->flags &=~ (UACTIVE|UXFER); ! 493: bp->b_flags |= B_ERROR; ! 494: iodone(bp); ! 495: return; ! 496: } ! 497: reg->hpdc = bp->b_cylin; ! 498: reg->hpda = (tn << 8) + sn; ! 499: if (bp->b_flags & B_READ) ! 500: reg->hpcs1 = HP_RCOM|HP_GO; ! 501: else ! 502: reg->hpcs1 = HP_WCOM|HP_GO; ! 503: } ! 504: ! 505: /* ! 506: * interrupt, passed from MBA code ! 507: */ ! 508: hp0int(unit, mbsr, mbbc, attn) ! 509: int unit, mbsr, mbbc, attn; ! 510: { ! 511: register struct hpdisk *hp; ! 512: ! 513: hp = &hpdisk[unit]; ! 514: if (hp->addr == 0) { ! 515: if (hpuinit(unit) == 0) { ! 516: printf("hp%d: hopeless interrupt\n", unit); ! 517: return; /* but ATTN wasn't cleared; will recur */ ! 518: } ! 519: /* init ok, so addr nonzero, so can clear it */ ! 520: } ! 521: hp->addr->hpas = attn; ! 522: if (hp->flags & UXFER) ! 523: hpxdone(hp, mbsr, mbbc); ! 524: if ((hp->flags & UXFER) == 0) ! 525: hpustart(hp); ! 526: } ! 527: ! 528: /* ! 529: * transfer stopped: ! 530: * because it's done, or because of an error ! 531: * common convention in error-sniffing routines: ! 532: * return 1 if the error was recovered ! 533: * and the device has been restarted ! 534: * return 0 if this transfer has been abandoned ! 535: * leave flags & UXFER set if we're all done; ! 536: * clear UXFER if the transfer should be retried ! 537: */ ! 538: ! 539: #define ERRCMIN 16 /* after this many errors, try offsets */ ! 540: #define ERRCAL(e) (((e)%8)==4) /* try recal this often */ ! 541: #define ERRMAX 28 /* after this many errors, give up on transfer */ ! 542: ! 543: hpxdone(hp, mbsr, mbbc) ! 544: register struct hpdisk *hp; ! 545: int mbsr, mbbc; ! 546: { ! 547: register struct hpdevice *reg; ! 548: register struct buf *bp; ! 549: ! 550: reg = hp->addr; ! 551: bp = hp->actf; ! 552: if ((reg->hpds&HPDS_ERR) || (mbsr&MBSR_EBITS)) { ! 553: if (hpwhaterr(hp, mbsr, mbbc)) ! 554: return; ! 555: reg->hpcs1 = HP_DCLR|HP_GO; ! 556: } ! 557: if (hp->recal && hpmorecal(hp)) ! 558: return; ! 559: if (hp->flags & UREVEC && hpbadcont(hp)) ! 560: return; ! 561: if (hp->flags & UXFER) { /* `active' means we're done */ ! 562: if (hp->errcnt >= ERRCMIN) { ! 563: reg->hpof = HPOF_FMT22; ! 564: reg->hpcs1 = HP_RTC|HP_GO; ! 565: while (reg->hpds & HPDS_PIP) ! 566: DELAY(25); ! 567: } ! 568: hp->errcnt = 0; ! 569: hp->flags &=~ (UACTIVE|UXFER); ! 570: hp->actf = bp->av_forw; ! 571: bp->b_resid = mbbc; ! 572: iodone(bp); ! 573: } ! 574: } ! 575: ! 576: /* ! 577: * sort out errors ! 578: */ ! 579: ! 580: hpwhaterr(hp, mbsr, mbbc) ! 581: register struct hpdisk *hp; ! 582: int mbsr, mbbc; ! 583: { ! 584: register struct hpdevice *reg; ! 585: register struct buf *bp; ! 586: register int i; ! 587: ! 588: reg = hp->addr; ! 589: bp = hp->actf; ! 590: /* ! 591: * let registers settle ! 592: */ ! 593: i = 0; ! 594: while ((reg->hpds & HPDS_DRY) == 0) { ! 595: if (++i > 512) ! 596: break; ! 597: hpwaitdry++; ! 598: } ! 599: if (reg->hper1 & HPER1_WLE) { ! 600: printf("hp%d: write locked\n", UNIT(bp->b_dev)); ! 601: bp->b_flags |= B_ERROR; ! 602: return (0); /* finished */ ! 603: } ! 604: if ((reg->hper2 & HPER2_BSE || reg->hper1 & HPER1_FER) ! 605: && hpbadrep(hp, mbbc)) ! 606: return (1); /* restarted, reading replacement */ ! 607: if (++hp->errcnt > ERRMAX) { ! 608: harderr(bp, "hp"); ! 609: printf("mbsr %o er1 %o er2 %o\n", ! 610: mbsr, reg->hper1&0177777, reg->hper2&0177777); ! 611: bp->b_flags |= B_ERROR; ! 612: return (0); /* finished */ ! 613: } ! 614: if (bp->b_flags & B_READ ! 615: && (reg->hper1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK) ! 616: return (hpecc(hp, mbbc)); /* restart or finish */ ! 617: /* ! 618: * hard error: clear and try again, ! 619: * perhaps with recal ! 620: */ ! 621: if (ERRCAL(hp->errcnt)) { ! 622: hpstrecal(hp); ! 623: return (1); /* restarted */ ! 624: } ! 625: hp->flags &=~ UXFER; ! 626: return (0); /* please restart me */ ! 627: } ! 628: ! 629: /* ! 630: * recalibration state machine ! 631: * walks through the sequence ! 632: * RECAL ! 633: * SEEK back to the cylinder we wanted ! 634: * perhaps offset the heads slightly ! 635: * and try the operation again ! 636: */ ! 637: ! 638: hpstrecal(hp) ! 639: register struct hpdisk *hp; ! 640: { ! 641: ! 642: hp->addr->hpcs1 = HP_DCLR|HP_GO; ! 643: hp->addr->hpcs1 = HP_RECAL|HP_GO; ! 644: hp->recal = 1; ! 645: } ! 646: ! 647: hpmorecal(hp) ! 648: register struct hpdisk *hp; ! 649: { ! 650: register struct hpdevice *reg; ! 651: ! 652: reg = hp->addr; ! 653: switch (hp->recal) { ! 654: case 1: /* did RECAL, time to seek */ ! 655: reg->hpdc = hp->actf->b_cylin; ! 656: reg->hpcs1 = HP_SEEK|HP_GO; ! 657: hp->recal++; ! 658: return (1); ! 659: ! 660: case 2: /* did seek, time for offset */ ! 661: if (hp->errcnt > ERRCMIN && hp->actf->b_flags & B_READ) { ! 662: reg->hpof = hp_offset[hp->errcnt%NOFFS]|HPOF_FMT22; ! 663: reg->hpcs1 = HP_OFFSET|HP_GO; ! 664: hp->recal++; ! 665: return (1); ! 666: } ! 667: /* too soon or a write, fall through */ ! 668: default: /* time to restart the transfer */ ! 669: hp->recal = 0; ! 670: hp->flags &=~ UXFER; ! 671: return (0); ! 672: } ! 673: } ! 674: ! 675: /* ! 676: * read the bad144 bad block table: ! 677: * call on first access to drive, ! 678: * or when VV was down ! 679: */ ! 680: ! 681: hprbad(hp) ! 682: register struct hpdisk *hp; ! 683: { ! 684: register struct buf *xbp, *bp; ! 685: register struct hptype *st; ! 686: ! 687: st = &hptype[hp->type]; ! 688: xbp = hp->actf; ! 689: bp = &hpbadbuf[UNIT(xbp->b_dev)]; ! 690: if (xbp == bp) ! 691: return; /* cheap reentry protection */ ! 692: bp->b_flags = B_BUSY|B_READ; ! 693: bp->b_dev = xbp->b_dev; ! 694: bp->b_un.b_addr = (caddr_t)&hpbad[UNIT(xbp->b_dev)]; ! 695: bp->b_bcount = sizeof(struct bad144); ! 696: bp->b_resid = 0; ! 697: bp->b_blkno = st->ncyl * st->nspc - st->nsect; /* fake-ish */ ! 698: bp->b_cylin = st->ncyl - 1; ! 699: bp->av_forw = xbp; ! 700: hp->actf = bp; ! 701: bzero(bp->b_un.b_addr, sizeof(struct bad144)); ! 702: } ! 703: ! 704: /* ! 705: * here when a bad block is detected: ! 706: * find the replacement block, and restart transfer for it ! 707: */ ! 708: hpbadrep(hp, mbbc) ! 709: register struct hpdisk *hp; ! 710: int mbbc; ! 711: { ! 712: register daddr_t bno; ! 713: register struct hptype *st; ! 714: struct buf *bp; ! 715: register int i; ! 716: ! 717: if (hp->flags & UREVEC) ! 718: return (0); ! 719: st = &hptype[hp->type]; ! 720: bp = hp->actf; ! 721: hp->badsec = (bp->b_bcount - mbbc) / SECTOR; ! 722: bno = bp->b_cylin * st->nspc + bp->b_blkno % st->nspc; /* true lbn */ ! 723: bno += hp->badsec; ! 724: i = bno / st->nspc; ! 725: bno %= st->nspc; ! 726: i = bad144rep(&hpbad[UNIT(bp->b_dev)], i, (int)bno/st->nsect, (int)bno%st->nsect); ! 727: if (i < 0) ! 728: return (0); ! 729: bno = st->ncyl*st->nspc - st->nsect - 1 - i; ! 730: hp->addr->hpcs1 = HP_DCLR|HP_GO; ! 731: if (mbbc > SECTOR) ! 732: mbbc = SECTOR; ! 733: hpcontin(hp, bno, hp->badsec*SECTOR, mbbc); ! 734: hp->flags |= UREVEC; ! 735: return (1); ! 736: } ! 737: ! 738: /* ! 739: * here after replacing the bad block: ! 740: * now do the rest of the original transfer ! 741: */ ! 742: hpbadcont(hp) ! 743: register struct hpdisk *hp; ! 744: { ! 745: register struct buf *bp; ! 746: int next, resid; ! 747: daddr_t bno; ! 748: int nspc; ! 749: ! 750: hp->flags &=~ UREVEC; ! 751: bp = hp->actf; ! 752: next = (hp->badsec + 1) * SECTOR; ! 753: resid = bp->b_bcount - next; ! 754: if (resid <= 0) ! 755: return (0); ! 756: nspc = hptype[hp->type].nspc; ! 757: bno = bp->b_cylin*nspc + bp->b_blkno%nspc; ! 758: bno += hp->badsec + 1; ! 759: hpcontin(hp, bno, next, resid); ! 760: return (1); ! 761: } ! 762: ! 763: /* ! 764: * correct an ECC error and restart the transfer ! 765: * the error is (hpec1-1) bits into the current sector; ! 766: * at that point, the bits set in hpec2 are wrong. ! 767: */ ! 768: hpecc(hp, bc) ! 769: register struct hpdisk *hp; ! 770: int bc; ! 771: { ! 772: register struct hpdevice *reg; ! 773: register struct buf *bp; ! 774: register int i; ! 775: int nxf; ! 776: unsigned int mask; ! 777: long a, lasta; ! 778: struct mbaddr *ap; ! 779: register daddr_t bno; ! 780: register struct hptype *st; ! 781: ! 782: if ((bp = hp->actf) == NULL) ! 783: panic("hpecc"); ! 784: reg = hp->addr; ! 785: ap = &hpaddr[UNIT(bp->b_dev)]; ! 786: lasta = mbcuraddr(ap); ! 787: nxf = bp->b_bcount - bc; ! 788: i = reg->hpec1 - 1; /* -1 makes 0 origin */ ! 789: a = lasta - (nxf > SECTOR ? SECTOR : nxf) + ((i&~07)>>3); ! 790: mask = reg->hpec2; ! 791: mask <<= i&07; ! 792: for (; a < lasta && mask; mask >>= 8, a++) ! 793: mbputc(ap, a, mbgetc(ap, a)^mask); ! 794: st = &hptype[hp->type]; ! 795: bno = bp->b_cylin*st->nspc + bp->b_blkno%st->nspc + nxf/SECTOR; ! 796: printf("hp%d: soft ecc sec %ld\n", UNIT(bp->b_dev), bno - 1); ! 797: if (bc == 0) ! 798: return (0); ! 799: reg->hpcs1 = HP_DCLR|HP_GO; ! 800: hpcontin(hp, bno, bp->b_bcount - bc, bc); ! 801: return (1); ! 802: } ! 803: ! 804: /* ! 805: * continue the current transfer, ! 806: * which was interrupted: ! 807: * move size bytes to or from the current buffer at offset off, ! 808: * starting with disk sector bno ! 809: * used for bad sector replacement, ! 810: * and to continue after bad sectors or ECC correction ! 811: */ ! 812: hpcontin(hp, bno, off, size) ! 813: register struct hpdisk *hp; ! 814: daddr_t bno; ! 815: int off, size; ! 816: { ! 817: register struct hpdevice *reg; ! 818: struct mbaddr *ap; ! 819: register struct buf *bp; ! 820: register struct hptype *st; ! 821: ! 822: reg = hp->addr; ! 823: bp = hp->actf; ! 824: ap = &hpaddr[UNIT(bp->b_dev)]; ! 825: st = &hptype[hp->type]; ! 826: mbadj(ap, off, size); ! 827: reg->hpdc = bno / st->nspc; ! 828: bno %= st->nspc; ! 829: reg->hpda = ((bno/st->nsect)<<8) | (bno%st->nsect); ! 830: mbcontin(ap); ! 831: if (bp->b_flags & B_READ) ! 832: reg->hpcs1 = HP_RCOM|HP_GO; ! 833: else ! 834: reg->hpcs1 = HP_WCOM|HP_GO; ! 835: } ! 836: ! 837: hpread(dev) ! 838: dev_t dev; ! 839: { ! 840: physio(hpstrategy, &hpbuf[UNIT(dev)], dev, B_READ, minphys); ! 841: } ! 842: ! 843: hpwrite(dev) ! 844: dev_t dev; ! 845: { ! 846: physio(hpstrategy, &hpbuf[UNIT(dev)], dev, B_WRITE, minphys); ! 847: } ! 848: ! 849: /* ! 850: * check for offline drives and hung controllers ! 851: */ ! 852: ! 853: hpwatch() ! 854: { ! 855: register struct hpdisk *hp; ! 856: register struct hpdevice *reg; ! 857: register struct buf *bp; ! 858: register int s; ! 859: ! 860: s = spl6(); ! 861: timeout(hpwatch, (caddr_t)0, 15*HZ); ! 862: for (hp = &hpdisk[hpcnt-1]; hp >= hpdisk; hp--) { ! 863: if ((hp->flags & UWOL) == 0 || (reg = hp->addr) == 0) ! 864: continue; ! 865: if ((reg->hpds & (HPDS_DPR|HPDS_MOL)) != (HPDS_DPR|HPDS_MOL)) { ! 866: if ((hp->flags & UWAITOL) == 0) { ! 867: hp->flags |= UWAITOL; ! 868: continue; ! 869: } ! 870: printf("hp%d offline\n", hp - hpdisk); ! 871: while ((bp = hp->actf) != NULL) { ! 872: bp->b_flags |= B_ERROR; ! 873: hp->actf = bp->av_forw; ! 874: iodone(bp); ! 875: } ! 876: } ! 877: hp->flags &=~ (UWAITOL|UWOL); ! 878: hpustart(hp); ! 879: } ! 880: splx(s); ! 881: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.