|
|
1.1 ! root 1: /* up.c 3.28 10/21/80 */ ! 2: ! 3: #include "../conf/up.h" ! 4: /* ! 5: * UNIBUS disk driver with overlapped seeks and ECC recovery. ! 6: * ! 7: * This driver works marginally on an Emulex SC-11B controller with rev ! 8: * level J microcode, defining: ! 9: * int olducode = 1; ! 10: * to force CPU stalling delays. ! 11: * ! 12: * It has worked with no delays and no problems on a prototype ! 13: * SC-21 controller. Emulex intends to upgrade all SC-11s on VAXes to SC-21s. ! 14: * You should get a SC-21 to replace any SC-11 on a VAX. ! 15: * ! 16: * SC-11B Controller switch settings: ! 17: * SW1-1 5/19 surfaces (off, 19 surfaces on Ampex 9300) ! 18: * SW1-2 chksum enable (off, checksum disabled) ! 19: * SW1-3 volume select (off, 815 cylinders) ! 20: * SW1-4 sector select (on, 32 sectors) ! 21: * SW1-5 unused (off) ! 22: * SW1-6 port select (on, single port) ! 23: * SW1-7 npr delay (off, disable) ! 24: * SW1-8 ecc test mode (off, disable) ! 25: * and top mounted switches: ! 26: * SW2-1 extend opcodes (off=open, disable) ! 27: * SW2-2 extend diag (off=open, disable) ! 28: * SW2-3 4 wd dma burst (on=closed, enable) ! 29: * SW2-4 unused (off=open) ! 30: */ ! 31: ! 32: #include "../h/param.h" ! 33: #include "../h/systm.h" ! 34: #include "../h/dk.h" ! 35: #include "../h/buf.h" ! 36: #include "../h/conf.h" ! 37: #include "../h/dir.h" ! 38: #include "../h/user.h" ! 39: #include "../h/map.h" ! 40: #include "../h/pte.h" ! 41: #include "../h/mba.h" ! 42: #include "../h/mtpr.h" ! 43: #include "../h/uba.h" ! 44: #include "../h/vm.h" ! 45: ! 46: #define ushort unsigned short ! 47: ! 48: struct device ! 49: { ! 50: ushort upcs1; /* control and status register 1 */ ! 51: short upwc; /* word count register */ ! 52: ushort upba; /* UNIBUS address register */ ! 53: ushort upda; /* desired address register */ ! 54: ushort upcs2; /* control and status register 2 */ ! 55: ushort upds; /* drive Status */ ! 56: ushort uper1; /* error register 1 */ ! 57: ushort upas; /* attention summary */ ! 58: ushort upla; /* look ahead */ ! 59: ushort updb; /* data buffer */ ! 60: ushort upmr; /* maintenance */ ! 61: ushort updt; /* drive type */ ! 62: ushort upsn; /* serial number */ ! 63: ushort upof; /* offset register */ ! 64: ushort updc; /* desired cylinder address register */ ! 65: ushort upcc; /* current cylinder */ ! 66: ushort uper2; /* error register 2 */ ! 67: ushort uper3; /* error register 3 */ ! 68: ushort upec1; /* burst error bit position */ ! 69: ushort upec2; /* burst error bit pattern */ ! 70: }; ! 71: ! 72: /* ! 73: * Software extension to the upas register, so we can ! 74: * postpone starting SEARCH commands until the controller ! 75: * is not transferring. ! 76: */ ! 77: int upsoftas; ! 78: ! 79: /* ! 80: * If upseek then we don't issue SEARCH commands but rather just ! 81: * settle for a SEEK to the correct cylinder. ! 82: */ ! 83: int upseek; ! 84: ! 85: #define NSECT 32 ! 86: #define NTRAC 19 ! 87: ! 88: /* ! 89: * Constants controlling on-cylinder SEARCH usage. ! 90: * ! 91: * upSDIST/2 msec time needed to start transfer ! 92: * upRDIST/2 msec tolerable rotational latency when on-cylinder ! 93: * ! 94: * If we are no closer than upSDIST sectors and no further than upSDIST+upRDIST ! 95: * and in the driver then we take it as it is. Otherwise we do a SEARCH ! 96: * requesting an interrupt upSDIST sectors in advance. ! 97: */ ! 98: #define _upSDIST 2 /* 1.0 msec */ ! 99: #define _upRDIST 4 /* 2.0 msec */ ! 100: ! 101: int upSDIST = _upSDIST; ! 102: int upRDIST = _upRDIST; ! 103: ! 104: /* ! 105: * To fill a 300M drive: ! 106: * A is designed to be used as a root. ! 107: * B is suitable for a swap area. ! 108: * H is the primary storage area. ! 109: * On systems with RP06'es, we normally use only 291346 blocks of the H ! 110: * area, and use DEF or G to cover the rest of the drive. The C system ! 111: * covers the whole drive and can be used for pack-pack copying. ! 112: */ ! 113: struct size ! 114: { ! 115: daddr_t nblocks; ! 116: int cyloff; ! 117: } up_sizes[8] = { ! 118: 15884, 0, /* A=cyl 0 thru 26 */ ! 119: 33440, 27, /* B=cyl 27 thru 81 */ ! 120: 495520, 0, /* C=cyl 0 thru 814 */ ! 121: 15884, 562, /* D=cyl 562 thru 588 */ ! 122: 55936, 589, /* E=cyl 589 thru 680 */ ! 123: 81472, 681, /* F=cyl 681 thru 814 */ ! 124: 153824, 562, /* G=cyl 562 thru 814 */ ! 125: 445664, 82, /* H=cyl 82 thru 814 */ ! 126: /* Later, and more safely for H area... ! 127: 291346, 82, /* H=cyl 82 thru 561 */ ! 128: }; ! 129: ! 130: /* ! 131: * The following defines are used in offset positioning ! 132: * when trying to recover disk errors, with the constants being ! 133: * +/- microinches. Note that header compare inhibit (HCI) is not ! 134: * tried (this makes sense only during read, in any case.) ! 135: * ! 136: * NOT ALL OF THESE ARE IMPLEMENTED ON 9300!?! ! 137: */ ! 138: #define P400 020 ! 139: #define M400 0220 ! 140: #define P800 040 ! 141: #define M800 0240 ! 142: #define P1200 060 ! 143: #define M1200 0260 ! 144: #define HCI 020000 ! 145: ! 146: int up_offset[16] = ! 147: { ! 148: P400, M400, P400, M400, ! 149: P800, M800, P800, M800, ! 150: P1200, M1200, P1200, M1200, ! 151: 0, 0, 0, 0, ! 152: }; ! 153: ! 154: /* ! 155: * Each drive has a table uputab[i]. On this table are sorted the ! 156: * pending requests implementing an elevator algorithm (see dsort.c.) ! 157: * In the upustart() routine, each drive is independently advanced ! 158: * until it is on the desired cylinder for the next transfer and near ! 159: * the desired sector. The drive is then chained onto the uptab ! 160: * table, and the transfer is initiated by the upstart() routine. ! 161: * When the transfer is completed the driver reinvokes the upustart() ! 162: * routine to set up the next transfer. ! 163: */ ! 164: struct buf uptab; ! 165: struct buf uputab[NUP]; ! 166: ! 167: struct buf rupbuf; /* Buffer for raw i/o */ ! 168: ! 169: /* Drive commands, placed in upcs1 */ ! 170: #define GO 01 /* Go bit, set in all commands */ ! 171: #define PRESET 020 /* Preset drive at init or after errors */ ! 172: #define OFFSET 014 /* Offset heads to try to recover error */ ! 173: #define RTC 016 /* Return to center-line after OFFSET */ ! 174: #define SEARCH 030 /* Search for cylinder+sector */ ! 175: #define SEEK 04 /* Seek to cylinder */ ! 176: #define RECAL 06 /* Recalibrate, needed after seek error */ ! 177: #define DCLR 010 /* Drive clear, after error */ ! 178: #define WCOM 060 /* Write */ ! 179: #define RCOM 070 /* Read */ ! 180: ! 181: /* Other bits of upcs1 */ ! 182: #define IE 0100 /* Controller wide interrupt enable */ ! 183: #define TRE 040000 /* Transfer error */ ! 184: #define RDY 0200 /* Transfer terminated */ ! 185: ! 186: /* Drive status bits of upds */ ! 187: #define PIP 020000 /* Positioning in progress */ ! 188: #define ERR 040000 /* Error has occurred, DCLR necessary */ ! 189: #define VV 0100 /* Volume is valid, set by PRESET */ ! 190: #define DPR 0400 /* Drive has been preset */ ! 191: #define MOL 010000 /* Drive is online, heads loaded, etc */ ! 192: #define DRY 0200 /* Drive ready */ ! 193: ! 194: /* Bits of upcs2 */ ! 195: #define CLR 040 /* Controller clear */ ! 196: /* Bits of uper1 */ ! 197: #define DCK 0100000 /* Ecc error occurred */ ! 198: #define ECH 0100 /* Ecc error was unrecoverable */ ! 199: #define WLE 04000 /* Attempt to write read-only drive */ ! 200: ! 201: /* Bits of upof; the offset bits above are also in this register */ ! 202: #define FMT22 010000 /* 16 bits/word, must be always set */ ! 203: ! 204: #define b_cylin b_resid ! 205: ! 206: int up_ubinfo; /* Information about UBA usage saved here */ ! 207: /* ! 208: * The EMULEX controller balks if accessed quickly after ! 209: * certain operations. With rev J delays seem to be needed only ! 210: * when selecting a new unit, and in drive initialization type ! 211: * like PRESET and DCLR. The following variables control the delay ! 212: * DELAY(n) is approximately n usec. ! 213: */ ! 214: int olducode = 1; ! 215: int idelay = 500; /* Delay after PRESET or DCLR */ ! 216: int osdelay = 150; /* Old delay after selecting drive in upcs2 */ ! 217: int ordelay = 100; /* Old delay after SEARCH */ ! 218: int oasdel = 100; /* Old delay after clearing bit in upas */ ! 219: int nsdelay = 25; ! 220: ! 221: #define DELAY(N) { register int d; d = N; while (--d > 0); } ! 222: ! 223: int nwaitcs2; /* How many sdelay loops ? */ ! 224: int neasycs2; /* How many sdelay loops not needed ? */ ! 225: ! 226: int up_wticks; /* Ticks waiting for interrupt */ ! 227: int upwstart; /* Have started guardian */ ! 228: int upwatch(); ! 229: ! 230: #ifdef INTRLVE ! 231: daddr_t dkblock(); ! 232: #endif ! 233: ! 234: /* ! 235: * Queue an i/o request for a drive, checking first that it is in range. ! 236: * ! 237: * A unit start is issued if the drive is inactive, causing ! 238: * a SEARCH for the correct cylinder/sector. If the drive is ! 239: * already nearly on the money and the controller is not transferring ! 240: * we kick it to start the transfer. ! 241: */ ! 242: upstrategy(bp) ! 243: register struct buf *bp; ! 244: { ! 245: register struct buf *dp; ! 246: register unit, xunit; ! 247: long sz, bn; ! 248: ! 249: if (upwstart == 0) { ! 250: timeout((caddr_t)upwatch, 0, HZ); ! 251: upwstart++; ! 252: } ! 253: xunit = minor(bp->b_dev) & 077; ! 254: sz = bp->b_bcount; ! 255: sz = (sz+511) >> 9; /* transfer size in 512 byte sectors */ ! 256: unit = dkunit(bp); ! 257: if (unit >= NUP || ! 258: bp->b_blkno < 0 || ! 259: (bn = dkblock(bp))+sz > up_sizes[xunit&07].nblocks) { ! 260: bp->b_flags |= B_ERROR; ! 261: iodone(bp); ! 262: return; ! 263: } ! 264: if (DK_N+unit <= DK_NMAX) ! 265: dk_mspw[DK_N+unit] = .0000020345; ! 266: bp->b_cylin = bn/(NSECT*NTRAC) + up_sizes[xunit&07].cyloff; ! 267: dp = &uputab[unit]; ! 268: (void) spl5(); ! 269: disksort(dp, bp); ! 270: if (dp->b_active == 0) { ! 271: (void) upustart(unit); ! 272: if (uptab.b_actf && uptab.b_active == 0) ! 273: (void) upstart(); ! 274: } ! 275: (void) spl0(); ! 276: } ! 277: ! 278: /* ! 279: * Start activity on specified drive; called when drive is inactive ! 280: * and new transfer request arrives and also when upas indicates that ! 281: * a SEARCH command is complete. ! 282: */ ! 283: upustart(unit) ! 284: register unit; ! 285: { ! 286: register struct buf *bp, *dp; ! 287: register struct device *upaddr = UPADDR; ! 288: daddr_t bn; ! 289: int sn, cn, csn; ! 290: int didie = 0; ! 291: ! 292: /* ! 293: * Other drivers tend to say something like ! 294: * upaddr->upcs1 = IE; ! 295: * upaddr->upas = 1<<unit; ! 296: * here, but the SC-11B will cancel a command which ! 297: * happens to be sitting in the cs1 if you clear the go ! 298: * bit by storing there (so the first is not safe), ! 299: * and it also does not like being bothered with operations ! 300: * such as clearing upas when a transfer is active (as ! 301: * it may well be.) ! 302: * ! 303: * Thus we keep careful track of when we re-enable IE ! 304: * after an interrupt and do it only if we didn't issue ! 305: * a command which re-enabled it as a matter of course. ! 306: * We clear bits in upas in the interrupt routine, when ! 307: * no transfers are active. ! 308: */ ! 309: if (unit >= NUP) ! 310: goto out; ! 311: if (unit+DK_N <= DK_NMAX) ! 312: dk_busy &= ~(1<<(unit+DK_N)); ! 313: dp = &uputab[unit]; ! 314: if ((bp = dp->b_actf) == NULL) ! 315: goto out; ! 316: /* ! 317: * The SC-11B doesn't start SEARCH commands when transfers are ! 318: * in progress. In fact, it tends to get confused when given ! 319: * SEARCH'es during transfers, generating interrupts with neither ! 320: * RDY nor a bit in the upas register. Thus we defer ! 321: * until an interrupt when a transfer is pending. ! 322: */ ! 323: if (uptab.b_active) { ! 324: upsoftas |= 1<<unit; ! 325: return (0); ! 326: } ! 327: if (dp->b_active) ! 328: goto done; ! 329: dp->b_active = 1; ! 330: if ((upaddr->upcs2 & 07) != unit) { ! 331: upaddr->upcs2 = unit; ! 332: DELAY(olducode ? osdelay : nsdelay); ! 333: nwaitcs2++; ! 334: } else ! 335: neasycs2++; ! 336: /* ! 337: * If we have changed packs or just initialized, ! 338: * then the volume will not be valid; if so, clear ! 339: * the drive, preset it and put in 16bit/word mode. ! 340: */ ! 341: if ((upaddr->upds & VV) == 0) { ! 342: upaddr->upcs1 = IE|DCLR|GO; ! 343: DELAY(idelay); ! 344: upaddr->upcs1 = IE|PRESET|GO; ! 345: DELAY(idelay); ! 346: upaddr->upof = FMT22; ! 347: didie = 1; ! 348: } ! 349: if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) ! 350: goto done; ! 351: /* ! 352: * Do enough of the disk address decoding to determine ! 353: * which cylinder and sector the request is on. ! 354: * If we are on the correct cylinder and the desired sector ! 355: * lies between upSDIST and upSDIST+upRDIST sectors ahead of us, then ! 356: * we don't bother to SEARCH but just begin the transfer asap. ! 357: * Otherwise ask for a interrupt upSDIST sectors ahead. ! 358: */ ! 359: bn = dkblock(bp); ! 360: cn = bp->b_cylin; ! 361: sn = bn%(NSECT*NTRAC); ! 362: sn = (sn+NSECT-upSDIST)%NSECT; ! 363: ! 364: if (cn - upaddr->updc) ! 365: goto search; /* Not on-cylinder */ ! 366: else if (upseek) ! 367: goto done; /* Ok just to be on-cylinder */ ! 368: csn = (upaddr->upla>>6) - sn - 1; ! 369: if (csn < 0) ! 370: csn += NSECT; ! 371: if (csn > NSECT-upRDIST) ! 372: goto done; ! 373: ! 374: search: ! 375: upaddr->updc = cn; ! 376: if (upseek) ! 377: upaddr->upcs1 = IE|SEEK|GO; ! 378: else { ! 379: upaddr->upda = sn; ! 380: upaddr->upcs1 = IE|SEARCH|GO; ! 381: } ! 382: didie = 1; ! 383: /* ! 384: * Mark this unit busy. ! 385: */ ! 386: unit += DK_N; ! 387: if (unit <= DK_NMAX) { ! 388: dk_busy |= 1<<unit; ! 389: dk_seek[unit]++; ! 390: } ! 391: if (olducode) ! 392: DELAY(ordelay); ! 393: goto out; ! 394: ! 395: done: ! 396: /* ! 397: * This unit is ready to go so ! 398: * link it onto the chain of ready disks. ! 399: */ ! 400: dp->b_forw = NULL; ! 401: if (uptab.b_actf == NULL) ! 402: uptab.b_actf = dp; ! 403: else ! 404: uptab.b_actl->b_forw = dp; ! 405: uptab.b_actl = dp; ! 406: ! 407: out: ! 408: return (didie); ! 409: } ! 410: ! 411: /* ! 412: * Start a transfer; call from top level at spl5() or on interrupt. ! 413: */ ! 414: upstart() ! 415: { ! 416: register struct buf *bp, *dp; ! 417: register unit; ! 418: register struct device *upaddr; ! 419: daddr_t bn; ! 420: int dn, sn, tn, cn, cmd; ! 421: ! 422: loop: ! 423: /* ! 424: * Pick a drive off the queue of ready drives, and ! 425: * perform the first transfer on its queue. ! 426: * ! 427: * Looping here is completely for the sake of drives which ! 428: * are not present and on-line, for which we completely clear the ! 429: * request queue. ! 430: */ ! 431: if ((dp = uptab.b_actf) == NULL) ! 432: return (0); ! 433: if ((bp = dp->b_actf) == NULL) { ! 434: uptab.b_actf = dp->b_forw; ! 435: goto loop; ! 436: } ! 437: /* ! 438: * Mark the controller busy, and multi-part disk address. ! 439: * Select the unit on which the i/o is to take place. ! 440: */ ! 441: uptab.b_active++; ! 442: unit = minor(bp->b_dev) & 077; ! 443: dn = dkunit(bp); ! 444: bn = dkblock(bp); ! 445: cn = up_sizes[unit&07].cyloff; ! 446: cn += bn/(NSECT*NTRAC); ! 447: sn = bn%(NSECT*NTRAC); ! 448: tn = sn/NSECT; ! 449: sn %= NSECT; ! 450: upaddr = UPADDR; ! 451: if ((upaddr->upcs2 & 07) != dn) { ! 452: upaddr->upcs2 = dn; ! 453: /* DELAY(sdelay); Provided by ubasetup() */ ! 454: nwaitcs2++; ! 455: } else ! 456: neasycs2++; ! 457: up_ubinfo = ubasetup(bp, 1); /* Providing delay */ ! 458: /* ! 459: * If drive is not present and on-line, then ! 460: * get rid of this with an error and loop to get ! 461: * rid of the rest of its queued requests. ! 462: * (Then on to any other ready drives.) ! 463: */ ! 464: if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { ! 465: printf("!DPR || !MOL, unit %d, ds %o", dn, upaddr->upds); ! 466: if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { ! 467: printf("-- hard\n"); ! 468: uptab.b_active = 0; ! 469: uptab.b_errcnt = 0; ! 470: dp->b_actf = bp->av_forw; ! 471: dp->b_active = 0; ! 472: bp->b_flags |= B_ERROR; ! 473: iodone(bp); ! 474: /* A funny place to do this ... */ ! 475: ubafree(up_ubinfo), up_ubinfo = 0; ! 476: goto loop; ! 477: } ! 478: printf("-- came back\n"); ! 479: } ! 480: /* ! 481: * If this is a retry, then with the 16'th retry we ! 482: * begin to try offsetting the heads to recover the data. ! 483: */ ! 484: if (uptab.b_errcnt >= 16 && (bp->b_flags&B_WRITE) == 0) { ! 485: upaddr->upof = up_offset[uptab.b_errcnt & 017] | FMT22; ! 486: upaddr->upcs1 = IE|OFFSET|GO; ! 487: DELAY(idelay); ! 488: while (upaddr->upds & PIP) ! 489: DELAY(25); ! 490: } ! 491: /* ! 492: * Now set up the transfer, retrieving the high ! 493: * 2 bits of the UNIBUS address from the information ! 494: * returned by ubasetup() for the cs1 register bits 8 and 9. ! 495: */ ! 496: upaddr->updc = cn; ! 497: upaddr->upda = (tn << 8) + sn; ! 498: upaddr->upba = up_ubinfo; ! 499: upaddr->upwc = -bp->b_bcount / sizeof (short); ! 500: cmd = (up_ubinfo >> 8) & 0x300; ! 501: if (bp->b_flags & B_READ) ! 502: cmd |= IE|RCOM|GO; ! 503: else ! 504: cmd |= IE|WCOM|GO; ! 505: upaddr->upcs1 = cmd; ! 506: /* ! 507: * This is a controller busy situation. ! 508: * Record in dk slot NUP+DK_N (after last drive) ! 509: * unless there aren't that many slots reserved for ! 510: * us in which case we record this as a drive busy ! 511: * (if there is room for that). ! 512: */ ! 513: unit = dn+DK_N; ! 514: if (unit <= DK_NMAX) { ! 515: dk_busy |= 1<<unit; ! 516: dk_xfer[unit]++; ! 517: dk_wds[unit] += bp->b_bcount>>6; ! 518: } ! 519: return (1); ! 520: } ! 521: ! 522: /* ! 523: * Handle a device interrupt. ! 524: * ! 525: * If the transferring drive needs attention, service it ! 526: * retrying on error or beginning next transfer. ! 527: * Service all other ready drives, calling ustart to transfer ! 528: * their blocks to the ready queue in uptab, and then restart ! 529: * the controller if there is anything to do. ! 530: */ ! 531: upintr() ! 532: { ! 533: register struct buf *bp, *dp; ! 534: register unit; ! 535: register struct device *upaddr = UPADDR; ! 536: int as = upaddr->upas & 0377; ! 537: int oupsoftas; ! 538: int needie = 1; ! 539: ! 540: (void) spl6(); ! 541: up_wticks = 0; ! 542: if (uptab.b_active) { ! 543: /* ! 544: * The drive is transferring, thus the hardware ! 545: * (say the designers) will only interrupt when the transfer ! 546: * completes; check for it anyways. ! 547: */ ! 548: if ((upaddr->upcs1 & RDY) == 0) { ! 549: printf("!RDY: cs1 %o, ds %o, wc %d\n", upaddr->upcs1, ! 550: upaddr->upds, upaddr->upwc); ! 551: printf("as=%d act %d %d %d\n", as, uptab.b_active, ! 552: uputab[0].b_active, uputab[1].b_active); ! 553: } ! 554: /* ! 555: * Mark drive not busy, and check for an ! 556: * error condition which may have resulted from the transfer. ! 557: */ ! 558: dp = uptab.b_actf; ! 559: bp = dp->b_actf; ! 560: unit = dkunit(bp); ! 561: if (DK_N+unit <= DK_NMAX) ! 562: dk_busy &= ~(1<<(DK_N+unit)); ! 563: if ((upaddr->upcs2 & 07) != unit) { ! 564: upaddr->upcs2 = unit; ! 565: DELAY(olducode ? osdelay : nsdelay); ! 566: nwaitcs2++; ! 567: } else ! 568: neasycs2++; ! 569: if ((upaddr->upds&ERR) || (upaddr->upcs1&TRE)) { ! 570: /* ! 571: * An error occurred, indeed. Select this unit ! 572: * to get at the drive status (a SEARCH may have ! 573: * intervened to change the selected unit), and ! 574: * wait for the command which caused the interrupt ! 575: * to complete (DRY). ! 576: */ ! 577: while ((upaddr->upds & DRY) == 0) ! 578: DELAY(25); ! 579: /* ! 580: * After 28 retries (16 w/o servo offsets, and then ! 581: * 12 with servo offsets), or if we encountered ! 582: * an error because the drive is write-protected, ! 583: * give up. Print an error message on the last 2 ! 584: * retries before a hard failure. ! 585: */ ! 586: if (++uptab.b_errcnt > 28 || upaddr->uper1&WLE) ! 587: bp->b_flags |= B_ERROR; ! 588: else ! 589: uptab.b_active = 0; /* To force retry */ ! 590: if (uptab.b_errcnt > 27) ! 591: deverror(bp, upaddr->upcs2, upaddr->uper1); ! 592: /* ! 593: * If this was a correctible ECC error, let upecc ! 594: * do the dirty work to correct it. If upecc ! 595: * starts another READ for the rest of the data ! 596: * then it returns 1 (having set uptab.b_active). ! 597: * Otherwise we are done and fall through to ! 598: * finish up. ! 599: */ ! 600: if ((upaddr->uper1&(DCK|ECH))==DCK && upecc(upaddr, bp)) ! 601: return; ! 602: /* ! 603: * Clear the drive and, every 4 retries, recalibrate ! 604: * to hopefully help clear up seek positioning problems. ! 605: */ ! 606: upaddr->upcs1 = TRE|IE|DCLR|GO; ! 607: DELAY(idelay); ! 608: needie = 0; ! 609: if ((uptab.b_errcnt&07) == 4) { ! 610: upaddr->upcs1 = RECAL|GO|IE; ! 611: DELAY(idelay); ! 612: while(upaddr->upds & PIP) ! 613: DELAY(25); ! 614: } ! 615: } ! 616: /* ! 617: * If we are still noted as active, then no ! 618: * (further) retries are necessary. ! 619: * ! 620: * Make sure the correct unit is selected, ! 621: * return it to centerline if necessary, and mark ! 622: * this i/o complete, starting the next transfer ! 623: * on this drive with the upustart routine (if any). ! 624: */ ! 625: if (uptab.b_active) { ! 626: if (uptab.b_errcnt >= 16) { ! 627: upaddr->upcs1 = RTC|GO|IE; ! 628: DELAY(idelay); ! 629: while (upaddr->upds & PIP) ! 630: DELAY(25); ! 631: needie = 0; ! 632: } ! 633: uptab.b_active = 0; ! 634: uptab.b_errcnt = 0; ! 635: uptab.b_actf = dp->b_forw; ! 636: dp->b_active = 0; ! 637: dp->b_errcnt = 0; ! 638: dp->b_actf = bp->av_forw; ! 639: bp->b_resid = (-upaddr->upwc * sizeof(short)); ! 640: if (bp->b_resid) ! 641: printf("resid %d ds %o er? %o %o %o\n", ! 642: bp->b_resid, upaddr->upds, ! 643: upaddr->uper1, upaddr->uper2, upaddr->uper3); ! 644: iodone(bp); ! 645: if(dp->b_actf) ! 646: if (upustart(unit)) ! 647: needie = 0; ! 648: } ! 649: as &= ~(1<<unit); ! 650: upsoftas &= ~(1<<unit); ! 651: ubafree(up_ubinfo), up_ubinfo = 0; ! 652: } else { ! 653: if (upaddr->upcs1 & TRE) { ! 654: upaddr->upcs1 = TRE; ! 655: DELAY(idelay); ! 656: } ! 657: } ! 658: /* ! 659: * If we have a unit with an outstanding SEARCH, ! 660: * and the hardware indicates the unit requires attention, ! 661: * the bring the drive to the ready queue. ! 662: * Finally, if the controller is not transferring ! 663: * start it if any drives are now ready to transfer. ! 664: */ ! 665: as |= upsoftas; ! 666: oupsoftas = upsoftas; ! 667: upsoftas = 0; ! 668: for (unit = 0; unit < NUP; unit++) ! 669: if ((as|oupsoftas) & (1<<unit)) { ! 670: if (as & (1<<unit)) { ! 671: upaddr->upas = 1<<unit; ! 672: if (olducode) ! 673: DELAY(oasdel); ! 674: } ! 675: if (upustart(unit)) ! 676: needie = 0; ! 677: } ! 678: if (uptab.b_actf && uptab.b_active == 0) ! 679: if (upstart()) ! 680: needie = 0; ! 681: out: ! 682: if (needie) ! 683: upaddr->upcs1 = IE; ! 684: } ! 685: ! 686: upread(dev) ! 687: { ! 688: ! 689: physio(upstrategy, &rupbuf, dev, B_READ, minphys); ! 690: } ! 691: ! 692: upwrite(dev) ! 693: { ! 694: ! 695: physio(upstrategy, &rupbuf, dev, B_WRITE, minphys); ! 696: } ! 697: ! 698: /* ! 699: * Correct an ECC error, and restart the i/o to complete ! 700: * the transfer if necessary. This is quite complicated because ! 701: * the transfer may be going to an odd memory address base and/or ! 702: * across a page boundary. ! 703: */ ! 704: upecc(up, bp) ! 705: register struct device *up; ! 706: register struct buf *bp; ! 707: { ! 708: struct uba_regs *ubp = (struct uba_regs *)UBA0; ! 709: register int i; ! 710: caddr_t addr; ! 711: int reg, bit, byte, npf, mask, o, cmd, ubaddr; ! 712: int bn, cn, tn, sn; ! 713: ! 714: /* ! 715: * Npf is the number of sectors transferred before the sector ! 716: * containing the ECC error, and reg is the UBA register ! 717: * mapping (the first part of) the transfer. ! 718: * O is offset within a memory page of the first byte transferred. ! 719: */ ! 720: npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; ! 721: reg = btop(up_ubinfo&0x3ffff) + npf; ! 722: o = (int)bp->b_un.b_addr & PGOFSET; ! 723: printf("%D ", bp->b_blkno+npf); ! 724: prdev("ECC", bp->b_dev); ! 725: mask = up->upec2; ! 726: if (mask == 0) { ! 727: up->upof = FMT22; /* == RTC ???? */ ! 728: DELAY(idelay); ! 729: return (0); ! 730: } ! 731: /* ! 732: * Flush the buffered data path, and compute the ! 733: * byte and bit position of the error. The variable i ! 734: * is the byte offset in the transfer, the variable byte ! 735: * is the offset from a page boundary in main memory. ! 736: */ ! 737: ubp->uba_dpr[(up_ubinfo>>28)&0x0f] |= BNE; ! 738: i = up->upec1 - 1; /* -1 makes 0 origin */ ! 739: bit = i&07; ! 740: i = (i&~07)>>3; ! 741: byte = i + o; ! 742: /* ! 743: * Correct while possible bits remain of mask. Since mask ! 744: * contains 11 bits, we continue while the bit offset is > -11. ! 745: * Also watch out for end of this block and the end of the whole ! 746: * transfer. ! 747: */ ! 748: while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { ! 749: addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ ! 750: (byte & PGOFSET); ! 751: putmemc(addr, getmemc(addr)^(mask<<bit)); ! 752: byte++; ! 753: i++; ! 754: bit -= 8; ! 755: } ! 756: uptab.b_active++; /* Either complete or continuing... */ ! 757: if (up->upwc == 0) ! 758: return (0); ! 759: /* ! 760: * Have to continue the transfer... clear the drive, ! 761: * and compute the position where the transfer is to continue. ! 762: * We have completed npf+1 sectors of the transfer already; ! 763: * restart at offset o of next sector (i.e. in UBA register reg+1). ! 764: */ ! 765: up->upcs1 = TRE|IE|DCLR|GO; ! 766: DELAY(idelay); ! 767: bn = dkblock(bp); ! 768: cn = bp->b_cylin; ! 769: sn = bn%(NSECT*NTRAC) + npf + 1; ! 770: tn = sn/NSECT; ! 771: sn %= NSECT; ! 772: cn += tn/NTRAC; ! 773: tn %= NTRAC; ! 774: up->updc = cn; ! 775: up->upda = (tn << 8) | sn; ! 776: ubaddr = (int)ptob(reg+1) + o; ! 777: up->upba = ubaddr; ! 778: cmd = (ubaddr >> 8) & 0x300; ! 779: cmd |= IE|GO|RCOM; ! 780: up->upcs1 = cmd; ! 781: return (1); ! 782: } ! 783: ! 784: /* ! 785: * Reset driver after UBA init. ! 786: * Cancel software state of all pending transfers ! 787: * and restart all units and the controller. ! 788: */ ! 789: upreset() ! 790: { ! 791: int unit; ! 792: ! 793: printf(" up"); ! 794: uptab.b_active = 0; ! 795: uptab.b_actf = uptab.b_actl = 0; ! 796: if (up_ubinfo) { ! 797: printf("<%d>", (up_ubinfo>>28)&0xf); ! 798: ubafree(up_ubinfo), up_ubinfo = 0; ! 799: } ! 800: UPADDR->upcs2 = CLR; /* clear controller */ ! 801: DELAY(idelay); ! 802: for (unit = 0; unit < NUP; unit++) { ! 803: uputab[unit].b_active = 0; ! 804: (void) upustart(unit); ! 805: } ! 806: (void) upstart(); ! 807: } ! 808: ! 809: /* ! 810: * Wake up every second and if an interrupt is pending ! 811: * but nothing has happened increment a counter. ! 812: * If nothing happens for 20 seconds, reset the controller ! 813: * and begin anew. ! 814: */ ! 815: upwatch() ! 816: { ! 817: int i; ! 818: ! 819: timeout((caddr_t)upwatch, 0, HZ); ! 820: if (uptab.b_active == 0) { ! 821: for (i = 0; i < NUP; i++) ! 822: if (uputab[i].b_active) ! 823: goto active; ! 824: up_wticks = 0; /* idling */ ! 825: return; ! 826: } ! 827: active: ! 828: up_wticks++; ! 829: if (up_wticks >= 20) { ! 830: up_wticks = 0; ! 831: printf("LOST INTERRUPT RESET"); ! 832: upreset(); ! 833: printf("\n"); ! 834: } ! 835: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.