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