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