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