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