1: /* 2: * SCCS id @(#)xp.c 2.1 (Berkeley) 8/23/83 3: * This driver has been modified to perform bad-sector forwarding. 4: * It has not been tested after that modification. 5: * If you want to use it, install it instead of the normal xp driver, 6: * AND TEST BOTH BAD-SECTOR FORWARDING AND ECC CORRECTION. 7: * Also, if you are using XP_PROBE (xpslave determines drive type), 8: * you will have to force the selection of the number of cylinders for RP's 9: * to RP06_CYL or RP04_CYL, assuming that you have only one or the other, 10: * or else punt. 11: */ 12: #define HP_CYL RP06_CYL 13: 14: /* 15: * RM02/03/05, RP04/05/06, DIVA disk driver. 16: * SI Eagle added 9/20/83. 17: * This driver will handle most variants of SMD drives 18: * on one or more controllers. 19: * If XP_PROBE is defined, it includes a probe routine 20: * that will determine the number and type of drives attached 21: * to each controller; otherwise, the data structures must be 22: * initialized. 23: * 24: * For simplicity we use hpreg.h instead of an xpreg.h. The bits 25: * are the same. 26: */ 27: 28: #include "xp.h" 29: #if NXP > 0 30: #include "param.h" 31: #include <sys/systm.h> 32: #include <sys/buf.h> 33: #include <sys/conf.h> 34: #include <sys/dir.h> 35: #include <sys/user.h> 36: #include <sys/seg.h> 37: #include <sys/hpreg.h> 38: #ifndef INTRLVE 39: #include <sys/inline.h> 40: #endif 41: #ifdef UNIBUS_MAP 42: #include <sys/uba.h> 43: #endif 44: #include <sys/dkbad.h> 45: 46: #define XP_SDIST 2 47: #define XP_RDIST 6 48: 49: int xp_offset[] = 50: { 51: HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400, 52: HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800, 53: HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200, 54: 0, 0, 0, 0 55: }; 56: 57: /* 58: * Xp_drive and xp_controller may be initialized in ioconf.c, 59: * or they may be filled in at boot time if XP_PROBE is enabled. 60: * Xp_controller address fields must be initialized for any boot devices, 61: * however. 62: */ 63: struct xp_drive xp_drive[NXP]; 64: struct xp_controller xp_controller[NXP_CONTROLLER]; 65: 66: struct buf xptab; 67: struct buf rxpbuf[NXP]; 68: struct buf xputab[NXP]; 69: #ifdef BADSECT 70: struct dkbad xpbad[NXP]; 71: struct buf bxpbuf[NXP]; 72: bool_t xp_init[NXP]; 73: #endif 74: 75: #ifdef INTRLVE 76: extern daddr_t dkblock(); 77: #endif 78: 79: /* 80: * Attach controllers whose addresses are known at boot time. 81: * Stop at the first not found, so that the drive numbering 82: * won't get confused. 83: */ 84: xproot() 85: { 86: register i; 87: register struct hpdevice *xpaddr; 88: 89: for (i = 0; i < NXP_CONTROLLER; i++) 90: if (((xpaddr = xp_controller[i].xp_addr) == 0) 91: || (xpattach(xpaddr, i) == 0)) 92: break; 93: } 94: 95: /* 96: * Attach controller at xpaddr. 97: * Mark as nonexistent if xpaddr is 0; 98: * otherwise attach slaves if probing. 99: * NOTE: if probing for drives, this routine must be called 100: * once per controller, in ascending controller numbers. 101: */ 102: xpattach(xpaddr, unit) 103: register struct hpdevice *xpaddr; 104: { 105: register struct xp_controller *xc = &xp_controller[unit]; 106: #ifdef XP_PROBE 107: static int last_attached = -1; 108: #endif 109: 110: if ((unsigned) unit >= NXP_CONTROLLER) 111: return(0); 112: if ((xpaddr != 0) && (fioword(xpaddr) != -1)) { 113: xc->xp_addr = xpaddr; 114: #if PDP11 == 70 || PDP11 == GENERIC 115: if (fioword(&(xpaddr->hpbae)) != -1) 116: xc->xp_flags |= XP_RH70; 117: #endif 118: #ifdef XP_PROBE 119: /* 120: * If already attached, ignore (don't want to renumber drives) 121: */ 122: if (unit > last_attached) { 123: last_attached = unit; 124: xpslave(xpaddr, xc); 125: } 126: #endif 127: return(1); 128: } 129: xc->xp_addr = 0; 130: return(0); 131: } 132: 133: #ifdef XP_PROBE 134: /* 135: * Determine what drives are attached to a controller; 136: * guess their types and fill in the drive structures. 137: */ 138: xpslave(xpaddr, xc) 139: register struct hpdevice *xpaddr; 140: struct xp_controller *xc; 141: { 142: register struct xp_drive *xd; 143: int j, dummy; 144: static int nxp = 0; 145: extern struct size dv_sizes[], hp_sizes[], rm_sizes[], rm5_sizes[], si_sizes[]; 146: 147: for (j = 0; j < 8; j++) { 148: xpaddr->hpcs1.w = 0; 149: xpaddr->hpcs2.w = j; 150: dummy = xpaddr->hpds; 151: if (xpaddr->hpcs2.w & HPCS2_NED) { 152: xpaddr->hpcs2.w = HPCS2_CLR; 153: continue; 154: } 155: if (nxp < NXP) { 156: xd = &xp_drive[nxp++]; 157: xd->xp_ctlr = xc; 158: xd->xp_unit = j; 159: /* 160: * If drive type is initialized, 161: * believe it. 162: */ 163: if (xd->xp_type == 0) 164: xd->xp_type = xpaddr->hpdt & 077; 165: switch (xd->xp_type) { 166: 167: case RM02: 168: case RM03: 169: xd->xp_nsect = RM_SECT; 170: xd->xp_ntrack = RM_TRAC; 171: xd->xp_nspc = RM_SECT * RM_TRAC; 172: xd->xp_ncyl = RM_CYL; 173: xd->xp_sizes = &rm_sizes; 174: xd->xp_ctlr->xp_flags |= XP_NOCC; 175: break; 176: 177: case RM5X: 178: xd->xp_ncyl = RM5X_CYL; 179: goto rm5; 180: case RM05: 181: xd->xp_ncyl = RM5_CYL; 182: rm5: 183: if ((xpaddr->hpsn & SI_SN_MSK) == SI_SN_DT) { 184: xd->xp_nsect = SI_SECT; 185: xd->xp_ntrack = SI_TRAC; 186: xd->xp_ncyl = SI_CYL; 187: xd->xp_nspc = SI_SECT * SI_TRAC; 188: xd->xp_sizes = &si_sizes; 189: xd->xp_ctlr->xp_flags |= XP_NOCC; 190: } else { 191: xd->xp_nsect = RM5_SECT; 192: xd->xp_ntrack = RM5_TRAC; 193: xd->xp_nspc = RM5_SECT * RM5_TRAC; 194: xd->xp_sizes = &rm5_sizes; 195: xd->xp_ctlr->xp_flags |= XP_NOCC; 196: } 197: break; 198: 199: case RP: 200: xd->xp_nsect = HP_SECT; 201: xd->xp_ntrack = HP_TRAC; 202: xd->xp_nspc = HP_SECT * HP_TRAC; 203: xd->xp_ncyl = HP_CYL; 204: xd->xp_sizes = &hp_sizes; 205: break; 206: 207: case DV: 208: xd->xp_nsect = DV_SECT; 209: xd->xp_ntrack = DV_TRAC; 210: xd->xp_nspc = DV_SECT * DV_TRAC; 211: xd->xp_ncyl = DV_CYL; 212: xd->xp_sizes = &dv_sizes; 213: xd->xp_ctlr->xp_flags |= XP_NOSEARCH; 214: break; 215: 216: default: 217: printf("xp%d: drive type %o unrecognized\n", 218: nxp - 1, xd->xp_type); 219: xd->xp_ctlr = NULL; 220: break; 221: } 222: } 223: } 224: } 225: #endif XP_PROBE 226: 227: xpstrategy(bp) 228: register struct buf *bp; 229: { 230: register struct xp_drive *xd; 231: register unit; 232: struct buf *dp; 233: short pseudo_unit; 234: int s; 235: long bn; 236: 237: unit = dkunit(bp); 238: pseudo_unit = minor(bp->b_dev) & 07; 239: 240: if ((unit >= NXP) || ((xd = &xp_drive[unit])->xp_ctlr == 0) || 241: (xd->xp_ctlr->xp_addr == 0)) { 242: bp->b_error = ENXIO; 243: goto errexit; 244: } 245: if ((bp->b_blkno < 0) || 246: ((bn = dkblock(bp)) + ((bp->b_bcount + 511) >> 9) 247: > xd->xp_sizes[pseudo_unit].nblocks)) { 248: bp->b_error = EINVAL; 249: errexit: 250: bp->b_flags |= B_ERROR; 251: iodone(bp); 252: return; 253: } 254: #ifdef UNIBUS_MAP 255: if ((xd->xp_ctlr->xp_flags & XP_RH70) == 0) 256: mapalloc(bp); 257: #endif UNIBUS_MAP 258: bp->b_cylin = bn / xd->xp_nspc 259: + xd->xp_sizes[pseudo_unit].cyloff; 260: dp = &xputab[unit]; 261: s = spl5(); 262: disksort(dp, bp); 263: if (dp->b_active == 0) { 264: xpustart(unit); 265: if (xd->xp_ctlr->xp_active == 0) 266: xpstart(xd->xp_ctlr); 267: } 268: splx(s); 269: } 270: 271: /* 272: * Unit start routine. 273: * Seek the drive to where the data are 274: * and then generate another interrupt 275: * to actually start the transfer. 276: * If there is only one drive 277: * or we are very close to the data, don't 278: * bother with the search. If called after 279: * searching once, don't bother to look 280: * where we are, just queue for transfer (to avoid 281: * positioning forever without transferring). 282: */ 283: xpustart(unit) 284: int unit; 285: { 286: register struct xp_drive *xd; 287: register struct hpdevice *xpaddr; 288: register struct buf *dp; 289: struct buf *bp; 290: daddr_t bn; 291: int sn, cn, csn; 292: 293: xd = &xp_drive[unit]; 294: xpaddr = xd->xp_ctlr->xp_addr; 295: xpaddr->hpcs2.w = xd->xp_unit; 296: xpaddr->hpcs1.c[0] = HP_IE; 297: xpaddr->hpas = 1 << xd->xp_unit; 298: 299: if (unit >= NXP) 300: return; 301: #ifdef XP_DKN 302: dk_busy &= ~(1 << (unit + XP_DKN)); 303: #endif 304: dp = &xputab[unit]; 305: if ((bp=dp->b_actf) == NULL) 306: return; 307: /* 308: * If we have already positioned this drive, 309: * then just put it on the ready queue. 310: */ 311: if (dp->b_active) 312: goto done; 313: dp->b_active++; 314: /* 315: * If drive has just come up, 316: * set up the pack. 317: */ 318: #ifdef BADSECT 319: if (((xpaddr->hpds & HPDS_VV) == 0) || (xp_init[unit] == 0)) 320: #else 321: if ((xpaddr->hpds & HPDS_VV) == 0) 322: #endif 323: { 324: #ifdef BADSECT 325: struct buf *bbp = &bxpbuf[unit]; 326: #endif 327: /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 328: xpaddr->hpcs1.c[0] = HP_IE | HP_PRESET | HP_GO; 329: xpaddr->hpof = HPOF_FMT22; 330: #ifdef BADSECT 331: xp_init[unit] = 1; 332: bbp->b_flags = B_READ | B_BUSY | B_PHYS; 333: bbp->b_dev = bp->b_dev; 334: bbp->b_bcount = sizeof(struct dkbad); 335: bbp->b_un.b_addr = (caddr_t)&xpbad[unit]; 336: bbp->b_blkno = (daddr_t)xd->xp_ncyl*xd->xp_nspc - xd->xp_nsect; 337: bbp->b_cylin = xd->xp_ncyl - 1; 338: #ifdef UNIBUS_MAP 339: if ((xd->xp_ctlr->xp_flags & XP_RH70) == 0) 340: mapalloc(bbp); 341: #endif UNIBUS_MAP 342: dp->b_actf = bbp; 343: bbp->av_forw = bp; 344: bp = bbp; 345: #endif BADSECT 346: } 347: #if NXP > 1 348: /* 349: * If drive is offline, forget about positioning. 350: */ 351: if ((xpaddr->hpds & (HPDS_DPR | HPDS_MOL)) != (HPDS_DPR | HPDS_MOL)) 352: goto done; 353: 354: /* 355: * Figure out where this transfer is going to 356: * and see if we are close enough to justify not searching. 357: */ 358: bn = dkblock(bp); 359: cn = bp->b_cylin; 360: sn = bn % xd->xp_nspc; 361: sn += xd->xp_nsect - XP_SDIST; 362: sn %= xd->xp_nsect; 363: 364: if (((xd->xp_ctlr->xp_flags & XP_NOCC) && (xd->xp_cc != cn)) 365: || xpaddr->hpcc != cn) 366: goto search; 367: if (xd->xp_ctlr->xp_flags & XP_NOSEARCH) 368: goto done; 369: csn = (xpaddr->hpla >> 6) - sn + XP_SDIST - 1; 370: if (csn < 0) 371: csn += xd->xp_nsect; 372: if (csn > xd->xp_nsect - XP_RDIST) 373: goto done; 374: 375: search: 376: xpaddr->hpdc = cn; 377: xpaddr->hpda = sn; 378: xpaddr->hpcs1.c[0] = (xd->xp_ctlr->xp_flags & XP_NOSEARCH)? 379: (HP_IE | HP_SEEK | HP_GO) : (HP_IE | HP_SEARCH | HP_GO); 380: xd->xp_cc = cn; 381: #ifdef XP_DKN 382: /* 383: * Mark unit busy for iostat. 384: */ 385: unit += XP_DKN; 386: dk_busy |= 1 << unit; 387: dk_numb[unit]++; 388: #endif XP_DKN 389: return; 390: #endif NXP > 1 391: 392: done: 393: /* 394: * Device is ready to go. 395: * Put it on the ready queue for the controller. 396: */ 397: dp->b_forw = NULL; 398: if (xd->xp_ctlr->xp_actf == NULL) 399: xd->xp_ctlr->xp_actf = dp; 400: else 401: xd->xp_ctlr->xp_actl->b_forw = dp; 402: xd->xp_ctlr->xp_actl = dp; 403: } 404: 405: /* 406: * Start up a transfer on a controller. 407: */ 408: xpstart(xc) 409: register struct xp_controller *xc; 410: { 411: register struct hpdevice *xpaddr; 412: register struct buf *bp; 413: struct xp_drive *xd; 414: struct buf *dp; 415: int unit; 416: short pseudo_unit; 417: daddr_t bn; 418: int sn, tn, cn; 419: 420: xpaddr = xc->xp_addr; 421: loop: 422: /* 423: * Pull a request off the controller queue. 424: */ 425: if ((dp = xc->xp_actf) == NULL) 426: return; 427: if ((bp = dp->b_actf) == NULL) { 428: xc->xp_actf = dp->b_forw; 429: goto loop; 430: } 431: /* 432: * Mark controller busy and 433: * determine destination of this request. 434: */ 435: xc->xp_active++; 436: pseudo_unit = minor(bp->b_dev) & 07; 437: unit = dkunit(bp); 438: xd = &xp_drive[unit]; 439: bn = dkblock(bp); 440: cn = bp->b_cylin; 441: sn = bn % xd->xp_nspc; 442: tn = sn / xd->xp_nsect; 443: sn = sn % xd->xp_nsect; 444: 445: /* 446: * Select drive. 447: */ 448: xpaddr->hpcs2.w = xd->xp_unit; 449: /* 450: * Check that it is ready and online. 451: */ 452: if ((xpaddr->hpds & (HPDS_DPR | HPDS_MOL)) != (HPDS_DPR | HPDS_MOL)) { 453: xc->xp_active = 0; 454: dp->b_errcnt = 0; 455: dp->b_actf = bp->av_forw; 456: bp->b_flags |= B_ERROR; 457: iodone(bp); 458: goto loop; 459: } 460: if (dp->b_errcnt >= 16 && (bp->b_flags & B_READ)) { 461: xpaddr->hpof = xp_offset[dp->b_errcnt & 017] | HPOF_FMT22; 462: xpaddr->hpcs1.w = HP_OFFSET | HP_GO; 463: while ((xpaddr->hpds & (HPDS_PIP | HPDS_DRY)) != HPDS_DRY) 464: ; 465: } 466: xpaddr->hpdc = cn; 467: xpaddr->hpda = (tn << 8) + sn; 468: xpaddr->hpba = bp->b_un.b_addr; 469: #if PDP11 == 70 || PDP11 == GENERIC 470: if (xc->xp_flags & XP_RH70) 471: xpaddr->hpbae = bp->b_xmem; 472: #endif 473: xpaddr->hpwc = -(bp->b_bcount >> 1); 474: 475: /* 476: * Warning: unit is being used as a temporary. 477: */ 478: unit = ((bp->b_xmem & 3) << 8) | HP_IE | HP_GO; 479: #ifdef XP_FORMAT 480: if (minor(bp->b_dev) & 0200) 481: unit |= bp->b_flags & B_READ? HP_RHDR : HP_WHDR; 482: else 483: unit |= bp->b_flags & B_READ? HP_RCOM : HP_WCOM; 484: #else 485: if (bp->b_flags & B_READ) 486: unit |= HP_RCOM; 487: else 488: unit |= HP_WCOM; 489: #endif 490: xpaddr->hpcs1.w = unit; 491: 492: #ifdef XP_DKN 493: unit = xc - &xp_controller[0] + XP_DKN + NXP; 494: dk_busy |= 1 << unit; 495: dk_numb[unit]++; 496: dk_wds[unit] += bp->b_bcount >> 6; 497: #endif 498: } 499: 500: /* 501: * Handle a disk interrupt. 502: */ 503: xpintr(dev) 504: int dev; 505: { 506: register struct hpdevice *xpaddr; 507: register struct buf *dp; 508: struct xp_controller *xc; 509: struct xp_drive *xd; 510: struct buf *bp; 511: register unit; 512: int as, i, j; 513: 514: xc = &xp_controller[dev]; 515: xpaddr = xc->xp_addr; 516: as = xpaddr->hpas & 0377; 517: if (xc->xp_active) { 518: #ifdef XP_DKN 519: dk_busy &= ~(1 << (dev + XP_DKN + NXP)); 520: #endif 521: /* 522: * Get device and block structures. Select the drive. 523: */ 524: dp = xc->xp_actf; 525: bp = dp->b_actf; 526: #ifdef BADSECT 527: if (bp->b_flags&B_BAD) 528: if (xpecc(bp, CONT)) 529: return; 530: #endif 531: unit = dkunit(bp); 532: xd = &xp_drive[unit]; 533: xpaddr->hpcs2.c[0] = xd->xp_unit; 534: /* 535: * Check for and process errors. 536: */ 537: if (xpaddr->hpcs1.w & HP_TRE) { 538: while ((xpaddr->hpds & HPDS_DRY) == 0) 539: ; 540: if (xpaddr->hper1 & HPER1_WLE) { 541: /* 542: * Give up on write locked deviced 543: * immediately. 544: */ 545: printf("xp%d: write locked\n", unit); 546: bp->b_flags |= B_ERROR; 547: #ifdef BADSECT 548: } else if ((xpaddr->rmer2 & RMER2_BSE) 549: || (xpaddr->hper1 & HPER1_FER)) { 550: #ifdef XP_FORMAT 551: /* 552: * Allow this error on format devices. 553: */ 554: if (minor(bp->b_dev) & 0200) 555: goto errdone; 556: #endif 557: if (xpecc(bp, BSE)) 558: return; 559: else 560: goto hard; 561: #endif BADSECT 562: } else { 563: /* 564: * After 28 retries (16 without offset and 565: * 12 with offset positioning), give up. 566: */ 567: if (++dp->b_errcnt > 28) { 568: hard: 569: #ifdef UCB_DEVERR 570: harderr(bp, "xp"); 571: printf("cs2=%b er1=%b\n", xpaddr->hpcs2.w, 572: HPCS2_BITS, xpaddr->hper1, HPER1_BITS); 573: #else 574: deverror(bp, xpaddr->hpcs2.w, xpaddr->hper1); 575: #endif 576: bp->b_flags |= B_ERROR; 577: } else 578: xc->xp_active = 0; 579: } 580: #ifdef UCB_ECC 581: /* 582: * If soft ecc, correct it (continuing 583: * by returning if necessary). 584: * Otherwise, fall through and retry the transfer. 585: */ 586: if((xpaddr->hper1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK) 587: if (xpecc(bp, ECC)) 588: return; 589: #endif 590: errdone: 591: xpaddr->hpcs1.w = HP_TRE | HP_IE | HP_DCLR | HP_GO; 592: if ((dp->b_errcnt & 07) == 4) { 593: xpaddr->hpcs1.w = HP_RECAL | HP_IE | HP_GO; 594: while ((xpaddr->hpds & (HPDS_PIP | HPDS_DRY)) != HPDS_DRY) 595: ; 596: } 597: xd->xp_cc = -1; 598: } 599: if (xc->xp_active) { 600: if (dp->b_errcnt) { 601: xpaddr->hpcs1.w = HP_RTC | HP_GO; 602: while ((xpaddr->hpds & (HPDS_PIP | HPDS_DRY)) != HPDS_DRY) 603: ; 604: } 605: xc->xp_active = 0; 606: xc->xp_actf = dp->b_forw; 607: dp->b_active = 0; 608: dp->b_errcnt = 0; 609: dp->b_actf = bp->b_actf; 610: xd->xp_cc = bp->b_cylin; 611: bp->b_resid = - (xpaddr->hpwc << 1); 612: iodone(bp); 613: xpaddr->hpcs1.w = HP_IE; 614: if (dp->b_actf) 615: xpustart(unit); 616: } 617: as &= ~(1 << xp_drive[unit].xp_unit); 618: } else 619: { 620: if (as == 0) 621: xpaddr->hpcs1.w = HP_IE; 622: xpaddr->hpcs1.c[1] = HP_TRE >> 8; 623: } 624: for (unit = 0; unit < NXP; unit++) 625: if ((xp_drive[unit].xp_ctlr == xc) && 626: (as & (1 << xp_drive[unit].xp_unit))) 627: xpustart(unit); 628: xpstart(xc); 629: } 630: 631: xpread(dev) 632: dev_t dev; 633: { 634: physio(xpstrategy, &rxpbuf[(minor(dev) >> 3) & 07], dev, B_READ); 635: } 636: 637: xpwrite(dev) 638: dev_t dev; 639: { 640: physio(xpstrategy, &rxpbuf[(minor(dev) >> 3) & 07], dev, B_WRITE); 641: } 642: 643: 644: #ifdef UCB_ECC 645: #define exadr(x,y) (((long)(x) << 16) | (unsigned)(y)) 646: 647: /* 648: * Correct an ECC error and restart the i/o to complete 649: * the transfer if necessary. This is quite complicated because 650: * the correction may be going to an odd memory address base 651: * and the transfer may cross a sector boundary. 652: */ 653: xpecc(bp, flag) 654: register struct buf *bp; 655: { 656: register struct xp_drive *xd; 657: register struct hpdevice *xpaddr; 658: register unsigned byte; 659: ubadr_t bb, addr; 660: long wrong; 661: int bit, wc; 662: unsigned ndone, npx; 663: int ocmd; 664: int cn, tn, sn; 665: daddr_t bn; 666: #ifdef UNIBUS_MAP 667: struct ubmap *ubp; 668: #endif 669: int unit; 670: 671: /* 672: * ndone is #bytes including the error 673: * which is assumed to be in the last disk page transferred. 674: */ 675: unit = dkunit(bp); 676: xd = &xp_drive[unit]; 677: xpaddr = xd->xp_ctlr->xp_addr; 678: #ifdef BADSECT 679: if (flag == CONT) { 680: npx = bp->b_error; 681: bp->b_error = 0; 682: ndone = npx * PGSIZE; 683: wc = ((int)(ndone - bp->b_bcount)) / NBPW; 684: } else 685: #endif 686: { 687: wc = xpaddr->hpwc; 688: ndone = (wc * NBPW) + bp->b_bcount; 689: npx = ndone / PGSIZE; 690: } 691: ocmd = (xpaddr->hpcs1.w & ~HP_DRY) | HP_IE | HP_GO; 692: bb = exadr(bp->b_xmem, bp->b_un.b_addr); 693: bn = dkblock(bp); 694: cn = bp->b_cylin - (bn / xd->xp_nspc); 695: bn += npx; 696: cn += bn / xd->xp_nspc; 697: sn = bn % xd->xp_nspc; 698: /* tn = sn / xd->xp_nsect; /* CC complains about this ??? */ 699: tn = sn; 700: tn /= xd->xp_nsect; 701: sn %= xd->xp_nsect; 702: 703: switch (flag) { 704: case ECC: 705: printf("xp%d%c: soft ecc bn %D\n", 706: unit, 'a' + (minor(bp->b_dev) & 07), 707: bp->b_blkno + (npx - 1)); 708: wrong = xpaddr->hpec2; 709: if (wrong == 0) { 710: xpaddr->hpof = HPOF_FMT22; 711: xpaddr->hpcs1.w |= HP_IE; 712: return (0); 713: } 714: 715: /* 716: * Compute the byte/bit position of the err 717: * within the last disk page transferred. 718: * Hpec1 is origin-1. 719: */ 720: byte = xpaddr->hpec1 - 1; 721: bit = byte & 07; 722: byte >>= 3; 723: byte += ndone - PGSIZE; 724: wrong <<= bit; 725: 726: /* 727: * Correct until mask is zero or until end of transfer, 728: * whichever comes first. 729: */ 730: while (byte < bp->b_bcount && wrong != 0) { 731: addr = bb + byte; 732: #ifdef UNIBUS_MAP 733: if (bp->b_flags & (B_MAP|B_UBAREMAP)) { 734: /* 735: * Simulate UNIBUS map if UNIBUS transfer. 736: */ 737: ubp = UBMAP + ((addr >> 13) & 037); 738: addr = exadr(ubp->ub_hi, ubp->ub_lo) 739: + (addr & 017777); 740: } 741: #endif 742: putmemc(addr, getmemc(addr) ^ (int) wrong); 743: byte++; 744: wrong >>= 8; 745: } 746: break; 747: #ifdef BADSECT 748: case BSE: 749: if ((bn = isbad(&xpbad[unit], cn, tn, sn)) < 0) 750: return(0); 751: bp->b_flags |= B_BAD; 752: bp->b_error = npx + 1; 753: bn = (daddr_t)xd->xp_ncyl * xd->xp_nspc - xd->xp_nsect - 1 - bn; 754: cn = bn/xd->xp_nspc; 755: sn = bn%xd->xp_nspc; 756: /* tn = sn/xd->xp_nsect; /* CC can't hack this */ 757: tn = sn; 758: tn /= xd->xp_nsect; 759: sn %= xd->xp_nsect; 760: #ifdef DEBUG 761: printf("revector to cn %d tn %d sn %d\n", cn, tn, sn); 762: #endif 763: wc = -(512 / NBPW); 764: break; 765: 766: case CONT: 767: bp->b_flags &= ~B_BAD; 768: #ifdef DEBUG 769: printf("xpecc CONT: bn %D cn %d tn %d sn %d\n", bn, cn, tn, sn); 770: #endif 771: break; 772: #endif BADSECT 773: } 774: 775: xd->xp_ctlr->xp_active++; 776: if (wc == 0) 777: return (0); 778: 779: /* 780: * Have to continue the transfer. Clear the drive 781: * and compute the position where the transfer is to continue. 782: * We have completed npx sectors of the transfer already. 783: */ 784: xpaddr->hpcs2.w = xd->xp_unit; 785: xpaddr->hpcs1.w = HP_TRE | HP_DCLR | HP_GO; 786: 787: addr = bb + ndone; 788: xpaddr->hpdc = cn; 789: xpaddr->hpda = (tn << 8) + sn; 790: xpaddr->hpwc = wc; 791: xpaddr->hpba = (int) addr; 792: #if PDP11 == 70 || PDP11 == GENERIC 793: if (xd->xp_ctlr->xp_flags & XP_RH70) 794: xpaddr->hpbae = (int) (addr >> 16); 795: #endif 796: xpaddr->hpcs1.w = ocmd; 797: return (1); 798: } 799: #endif UCB_ECC 800: 801: #if defined(XP_DUMP) && defined(UCB_AUTOBOOT) 802: /* 803: * Dump routine. 804: * Dumps from dumplo to end of memory/end of disk section for minor(dev). 805: * It uses the UNIBUS map to dump all of memory if there is a UNIBUS map 806: * and this isn't an RH70. This depends on UNIBUS_MAP being defined. 807: */ 808: 809: #ifdef UNIBUS_MAP 810: #define DBSIZE (UBPAGE/PGSIZE) /* unit of transfer, one UBPAGE */ 811: #else 812: #define DBSIZE 16 /* unit of transfer, same number */ 813: #endif 814: 815: xpdump(dev) 816: dev_t dev; 817: { 818: /* ONLY USE 2 REGISTER VARIABLES, OR C COMPILER CHOKES */ 819: register struct xp_drive *xd; 820: register struct hpdevice *xpaddr; 821: daddr_t bn, dumpsize; 822: long paddr; 823: int sn, count; 824: #ifdef UNIBUS_MAP 825: extern bool_t ubmap; 826: struct ubmap *ubp; 827: #endif 828: 829: if ((bdevsw[major(dev)].d_strategy != xpstrategy) /* paranoia */ 830: || ((dev=minor(dev)) > (NXP << 3))) 831: return(EINVAL); 832: xd = &xp_drive[dev >> 3]; 833: dev &= 07; 834: if (xd->xp_ctlr == 0) 835: return(EINVAL); 836: xpaddr = xd->xp_ctlr->xp_addr; 837: dumpsize = xd->xp_sizes[dev].nblocks; 838: if ((dumplo < 0) || (dumplo >= dumpsize)) 839: return(EINVAL); 840: dumpsize -= dumplo; 841: 842: xpaddr->hpcs2.w = xd->xp_unit; 843: if ((xpaddr->hpds & HPDS_VV) == 0) { 844: xpaddr->hpcs1.w = HP_DCLR | HP_GO; 845: xpaddr->hpcs1.w = HP_PRESET | HP_GO; 846: xpaddr->hpof = HPOF_FMT22; 847: } 848: if ((xpaddr->hpds & (HPDS_DPR | HPDS_MOL)) != (HPDS_DPR | HPDS_MOL)) 849: return(EFAULT); 850: #ifdef UNIBUS_MAP 851: ubp = &UBMAP[0]; 852: #endif 853: for (paddr = 0L; dumpsize > 0; dumpsize -= count) { 854: count = dumpsize>DBSIZE? DBSIZE: dumpsize; 855: bn = dumplo + (paddr >> PGSHIFT); 856: xpaddr->hpdc = bn / xd->xp_nspc 857: + xd->xp_sizes[dev].cyloff; 858: sn = bn % xd->xp_nspc; 859: xpaddr->hpda = ((sn / xd->xp_nsect) << 8) | (sn % xd->xp_nsect); 860: xpaddr->hpwc = -(count << (PGSHIFT - 1)); 861: #ifdef UNIBUS_MAP 862: /* 863: * If UNIBUS_MAP exists, use 864: * the map, unless on an 11/70 with RH70. 865: */ 866: if (ubmap && ((xd->xp_ctlr->xp_flags & XP_RH70) == 0)) { 867: ubp->ub_lo = loint(paddr); 868: ubp->ub_hi = hiint(paddr); 869: xpaddr->hpba = 0; 870: xpaddr->hpcs1.w = HP_WCOM | HP_GO; 871: } 872: else 873: #endif 874: { 875: /* 876: * Non-UNIBUS map, or 11/70 RH70 (MASSBUS) 877: */ 878: xpaddr->hpba = loint(paddr); 879: #if PDP11 == 70 || PDP11 == GENERIC 880: if (xd->xp_ctlr->xp_flags & XP_RH70) 881: xpaddr->hpbae = hiint(paddr); 882: #endif 883: xpaddr->hpcs1.w = HP_WCOM | HP_GO | ((paddr >> 8) & (03 << 8)); 884: } 885: while (xpaddr->hpcs1.w & HP_GO) 886: ; 887: if (xpaddr->hpcs1.w & HP_TRE) { 888: if (xpaddr->hpcs2.w & HPCS2_NEM) 889: return(0); /* made it to end of memory */ 890: return(EIO); 891: } 892: paddr += (DBSIZE << PGSHIFT); 893: } 894: return(0); /* filled disk minor dev */ 895: } 896: #endif XP_DUMP 897: #endif NXP