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