1: /* 2: * Copyright (c) 1986 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: * 6: * @(#)hk.c 2.3 (2.11BSD GTE) 1998/4/3 7: */ 8: 9: /* 10: * RK611/RK0[67] disk driver 11: * 12: * Heavily modified for disklabel support. Still only supports 1 controller 13: * (but who'd have more than one of these on a system anyhow?) - 1997/11/11 sms 14: * 15: * This driver mimics the 4.1bsd rk driver. 16: * It does overlapped seeks, ECC, and bad block handling. 17: * salkind@nyu 18: * 19: * dkunit() takes a 'dev_t' now instead of 'buf *'. 1995/04/13 - sms 20: * 21: * Removed ifdefs on both Q22 and UNIBUS_MAP, substituting a runtime 22: * test for presence of a Unibus Map. Reworked the partition logic, 23: * the 'e' partiton no longer overlaps the 'a'+'b' partitions - a separate 24: * 'b' partition is now present. Old root filesystems can still be used 25: * because the size is the same, but user data will have to be saved and 26: * then reloaded. 12/28/92 -- sms@wlv.iipo.gtegsc.com 27: * 28: * Modified to correctly handle 22 bit addressing available on DILOG 29: * DQ615 controller. 05/31/90 -- tymann@oswego.edu 30: * 31: */ 32: 33: #include "hk.h" 34: #if NHK > 0 35: #include "param.h" 36: #include "systm.h" 37: #include "buf.h" 38: #include "machine/seg.h" 39: #include "conf.h" 40: #include "user.h" 41: #include "map.h" 42: #include "uba.h" 43: #include "hkreg.h" 44: #include "dkbad.h" 45: #include "dk.h" 46: #include "stat.h" 47: #include "file.h" 48: #include "disklabel.h" 49: #include "disk.h" 50: #include "syslog.h" 51: 52: #define NHK7CYL 815 53: #define NHK6CYL 411 54: #define HK_NSECT 22 55: #define HK_NTRAC 3 56: #define HK_NSPC (HK_NTRAC*HK_NSECT) 57: 58: struct hkdevice *HKADDR; 59: 60: daddr_t hksize(); 61: void hkdfltlbl(); 62: int hkstrategy(); 63: 64: /* Can be u_char because all are less than 0377 */ 65: u_char hk_offset[] = 66: { 67: HKAS_P400, HKAS_M400, HKAS_P400, HKAS_M400, 68: HKAS_P800, HKAS_M800, HKAS_P800, HKAS_M800, 69: HKAS_P1200, HKAS_M1200, HKAS_P1200, HKAS_M1200, 70: 0, 0, 0, 0, 71: }; 72: 73: int hk_type[NHK]; 74: int hk_cyl[NHK]; 75: 76: struct hk_softc 77: { 78: int sc_softas; 79: int sc_recal; 80: } hk; 81: 82: struct buf hktab; 83: struct buf hkutab[NHK]; 84: struct dkdevice hk_dk[NHK]; 85: 86: #ifdef BADSECT 87: struct dkbad hkbad[NHK]; 88: struct buf bhkbuf[NHK]; 89: #endif 90: 91: #ifdef UCB_METER 92: static int hk_dkn = -1; /* number for iostat */ 93: #endif 94: 95: #define hkwait(hkaddr) while ((hkaddr->hkcs1 & HK_CRDY) == 0) 96: #define hkncyl(unit) (hk_type[unit] ? NHK7CYL : NHK6CYL) 97: 98: void 99: hkroot() 100: { 101: hkattach((struct hkdevice *)0177440, 0); 102: } 103: 104: hkattach(addr, unit) 105: struct hkdevice *addr; 106: { 107: #ifdef UCB_METER 108: if (hk_dkn < 0) 109: { 110: dk_alloc(&hk_dkn, NHK+1, "hk", 60L * (long)HK_NSECT * 256L); 111: if (hk_dkn >= 0) 112: dk_wps[hk_dkn+NHK] = 0L; 113: } 114: #endif 115: if (unit != 0) 116: return(0); 117: HKADDR = addr; 118: return(1); 119: } 120: 121: hkopen(dev, flag, mode) 122: dev_t dev; 123: int flag; 124: int mode; 125: { 126: register int unit = dkunit(dev); 127: register struct hkdevice *hkaddr = HKADDR; 128: register struct dkdevice *disk; 129: int i, mask; 130: 131: if (unit >= NHK || !HKADDR) 132: return(ENXIO); 133: disk = &hk_dk[unit]; 134: 135: if ((disk->dk_flags & DKF_ALIVE) == 0) 136: { 137: hk_type[unit] = 0; 138: hkaddr->hkcs1 = HK_CCLR; 139: hkaddr->hkcs2 = unit; 140: hkaddr->hkcs1 = HK_DCLR | HK_GO; 141: hkwait(hkaddr); 142: if (hkaddr->hkcs2&HKCS2_NED || !(hkaddr->hkds&HKDS_SVAL)) 143: { 144: hkaddr->hkcs1 = HK_CCLR; 145: hkwait(hkaddr); 146: return(ENXIO); 147: } 148: disk->dk_flags |= DKF_ALIVE; 149: if ((hkaddr->hkcs1&HK_CERR) && (hkaddr->hker&HKER_DTYE)) 150: { 151: hk_type[unit] = HK_CDT; 152: hkaddr->hkcs1 = HK_CCLR; 153: hkwait(hkaddr); 154: } 155: } 156: /* 157: * The drive has responded to a probe (is alive). Now we read the 158: * label. Allocate an external label structure if one has not already 159: * been assigned to this drive. First wait for any pending opens/closes 160: * to complete. 161: */ 162: while (disk->dk_flags & (DKF_OPENING | DKF_CLOSING)) 163: sleep(disk, PRIBIO); 164: 165: /* 166: * Next if an external label buffer has not already been allocated do so now. 167: * This "can not fail" because if the initial pool of label buffers has 168: * been exhausted the allocation takes place from main memory. The return 169: * value is the 'click' address to be used when mapping in the label. 170: */ 171: 172: if (disk->dk_label == 0) 173: disk->dk_label = disklabelalloc(); 174: 175: /* 176: * On first open get label and partition info. We may block reading the 177: * label so be careful to stop any other opens. 178: */ 179: if (disk->dk_openmask == 0) 180: { 181: disk->dk_flags |= DKF_OPENING; 182: hkgetinfo(disk, dev); 183: disk->dk_flags &= ~DKF_OPENING; 184: wakeup(disk); 185: hk_cyl[unit] = -1; 186: } 187: /* 188: * Need to make sure the partition is not out of bounds. This requires 189: * mapping in the external label. This only happens when a partition 190: * is opened (at mount time) and isn't an efficiency problem. 191: */ 192: mapseg5(disk->dk_label, LABELDESC); 193: i = ((struct disklabel *)SEG5)->d_npartitions; 194: normalseg5(); 195: if (dkpart(dev) >= i) 196: return(ENXIO); 197: mask = 1 << dkpart(dev); 198: dkoverlapchk(disk->dk_openmask, dev, disk->dk_label, "hk"); 199: if (mode == S_IFCHR) 200: disk->dk_copenmask |= mask; 201: else if (mode == S_IFBLK) 202: disk->dk_bopenmask |= mask; 203: else 204: return(EINVAL); 205: disk->dk_openmask |= mask; 206: return(0); 207: } 208: 209: /* 210: * Disk drivers now have to have close entry points in order to keep 211: * track of what partitions are still active on a drive. 212: */ 213: hkclose(dev, flag, mode) 214: register dev_t dev; 215: int flag, mode; 216: { 217: int s, drive = dkunit(dev); 218: register int mask; 219: register struct dkdevice *disk; 220: 221: disk = &hk_dk[drive]; 222: mask = 1 << dkpart(dev); 223: if (mode == S_IFCHR) 224: disk->dk_copenmask &= ~mask; 225: else if (mode == S_IFBLK) 226: disk->dk_bopenmask &= ~mask; 227: else 228: return(EINVAL); 229: disk->dk_openmask = disk->dk_bopenmask | disk->dk_copenmask; 230: if (disk->dk_openmask == 0) 231: { 232: disk->dk_flags |= DKF_CLOSING; 233: s = splbio(); 234: while (hkutab[drive].b_actf) 235: { 236: disk->dk_flags |= DKF_WANTED; 237: sleep(&hkutab[drive], PRIBIO); 238: } 239: splx(s); 240: /* 241: * On last close of a drive we declare it not alive and offline to force a 242: * probe on the next open in order to handle diskpack changes. 243: */ 244: disk->dk_flags &= 245: ~(DKF_CLOSING | DKF_WANTED | DKF_ALIVE | DKF_ONLINE); 246: wakeup(disk); 247: } 248: return(0); 249: } 250: 251: /* 252: * This code moved here from hkgetinfo() because it is fairly large and used 253: * twice - once to initialize for reading the label and a second time if 254: * there is no valid label present on the drive and the default one must be 255: * used to span the drive. 256: */ 257: 258: void 259: hkdfltlbl(disk, lp, dev) 260: struct dkdevice *disk; 261: register struct disklabel *lp; 262: dev_t dev; 263: { 264: register struct partition *pi = &lp->d_partitions[0]; 265: 266: bzero(lp, sizeof (*lp)); 267: lp->d_type = DTYPE_DEC; 268: lp->d_secsize = 512; /* XXX */ 269: lp->d_nsectors = HK_NSECT; 270: lp->d_ntracks = HK_NTRAC; 271: lp->d_secpercyl = HK_NSPC; 272: lp->d_npartitions = 1; /* 'a' */ 273: lp->d_ncylinders = hkncyl(dkunit(dev)); 274: pi->p_size = lp->d_ncylinders * lp->d_secpercyl; /* entire volume */ 275: pi->p_fstype = FS_V71K; 276: pi->p_frag = 1; 277: pi->p_fsize = 1024; 278: /* 279: * Put where hkstrategy() will look. 280: */ 281: bcopy(pi, disk->dk_parts, sizeof (lp->d_partitions)); 282: } 283: 284: /* 285: * Read disklabel. It is tempting to generalize this routine so that 286: * all disk drivers could share it. However by the time all of the 287: * necessary parameters are setup and passed the savings vanish. Also, 288: * each driver has a different method of calculating the number of blocks 289: * to use if one large partition must cover the disk. 290: * 291: * This routine used to always return success and callers carefully checked 292: * the return status. Silly. This routine will fake a label (a single 293: * partition spanning the drive) if necessary but will never return an error. 294: * 295: * It is the caller's responsibility to check the validity of partition 296: * numbers, etc. 297: */ 298: 299: void 300: hkgetinfo(disk, dev) 301: register struct dkdevice *disk; 302: dev_t dev; 303: { 304: struct disklabel locallabel; 305: char *msg; 306: register struct disklabel *lp = &locallabel; 307: /* 308: * NOTE: partition 0 ('a') is used to read the label. Therefore 'a' must 309: * start at the beginning of the disk! If there is no label or the label 310: * is corrupted then 'a' will span the entire disk 311: */ 312: hkdfltlbl(disk, lp, dev); 313: msg = readdisklabel((dev & ~7) | 0, hkstrategy, lp); /* 'a' */ 314: if (msg != 0) 315: { 316: log(LOG_NOTICE, "hk%da is entire disk: %s\n", dkunit(dev), msg); 317: hkdfltlbl(disk, lp, dev); 318: } 319: mapseg5(disk->dk_label, LABELDESC) 320: bcopy(lp, (struct disklabel *)SEG5, sizeof (struct disklabel)); 321: normalseg5(); 322: bcopy(lp->d_partitions, disk->dk_parts, sizeof (lp->d_partitions)); 323: return; 324: } 325: 326: hkstrategy(bp) 327: register struct buf *bp; 328: { 329: register struct buf *dp; 330: int s, drive; 331: register struct dkdevice *disk; 332: 333: drive = dkunit(bp->b_dev); 334: disk = &hk_dk[drive]; 335: 336: if (drive >= NHK || !HKADDR || !(disk->dk_flags & DKF_ALIVE)) 337: { 338: bp->b_error = ENXIO; 339: goto bad; 340: } 341: s = partition_check(bp, disk); 342: if (s < 0) 343: goto bad; 344: if (s == 0) 345: goto done; 346: 347: bp->b_cylin = bp->b_blkno / HK_NSPC; 348: mapalloc(bp); 349: dp = &hkutab[drive]; 350: s = splbio(); 351: disksort(dp, bp); 352: if (dp->b_active == 0) 353: { 354: hkustart(drive); 355: if (hktab.b_active == 0) 356: hkstart(); 357: } 358: splx(s); 359: return; 360: bad: 361: bp->b_flags |= B_ERROR; 362: done: 363: iodone(bp); 364: } 365: 366: hkustart(unit) 367: int unit; 368: { 369: register struct hkdevice *hkaddr = HKADDR; 370: register struct buf *bp, *dp; 371: struct dkdevice *disk; 372: int didie = 0; 373: 374: #ifdef UCB_METER 375: if (hk_dkn >= 0) 376: dk_busy &= ~(1 << (hk_dkn + unit)); 377: #endif 378: if (hktab.b_active) { 379: hk.sc_softas |= (1 << unit); 380: return(0); 381: } 382: 383: hkaddr->hkcs1 = HK_CCLR; 384: hkaddr->hkcs2 = unit; 385: hkaddr->hkcs1 = hk_type[unit] | HK_DCLR | HK_GO; 386: hkwait(hkaddr); 387: 388: dp = &hkutab[unit]; 389: disk = &hk_dk[unit]; 390: if ((bp = dp->b_actf) == NULL) 391: return(0); 392: if (dp->b_active) 393: goto done; 394: dp->b_active = 1; 395: if (!(hkaddr->hkds & HKDS_VV) || !(disk->dk_flags & DKF_ONLINE)) 396: { 397: /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 398: #ifdef BADSECT 399: struct buf *bbp = &bhkbuf[unit]; 400: #endif 401: 402: hkaddr->hkcs1 = hk_type[unit]|HK_PACK|HK_GO; 403: disk->dk_flags |= DKF_ONLINE; 404: /* 405: * XXX - The 'c' partition is used below to access the bad block area. This 406: * XXX - is DIFFERENT than the XP driver (which should have used 'c' but could 407: * XXX - not due to historical reasons). The 'c' partition MUST span the entire 408: * XXX - disk including the bad sector track. The 'h' partition should be 409: * XXX - used for user data. 410: */ 411: #ifdef BADSECT 412: bbp->b_flags = B_READ|B_BUSY|B_PHYS; 413: bbp->b_dev = (bp->b_dev & ~7) | ('c' - 'a'); 414: bbp->b_bcount = sizeof(struct dkbad); 415: bbp->b_un.b_addr = (caddr_t)&hkbad[unit]; 416: bbp->b_blkno = (long)hkncyl(unit)*HK_NSPC - HK_NSECT; 417: bbp->b_cylin = hkncyl(unit) - 1; 418: mapalloc(bbp); 419: dp->b_actf = bbp; 420: bbp->av_forw = bp; 421: bp = bbp; 422: #endif 423: hkwait(hkaddr); 424: } 425: if ((hkaddr->hkds & HKDS_DREADY) != HKDS_DREADY) 426: { 427: disk->dk_flags &= ~DKF_ONLINE; 428: goto done; 429: } 430: #ifdef NHK > 1 431: if (bp->b_cylin == hk_cyl[unit]) 432: goto done; 433: hkaddr->hkcyl = bp->b_cylin; 434: hk_cyl[unit] = bp->b_cylin; 435: hkaddr->hkcs1 = hk_type[unit] | HK_IE | HK_SEEK | HK_GO; 436: didie = 1; 437: #ifdef UCB_METER 438: if (hk_dkn >= 0) { 439: int dkn = hk_dkn + unit; 440: 441: dk_busy |= 1<<dkn; 442: dk_seek[dkn]++; 443: } 444: #endif 445: return (didie); 446: #endif NHK > 1 447: 448: done: 449: if (dp->b_active != 2) { 450: dp->b_forw = NULL; 451: if (hktab.b_actf == NULL) 452: hktab.b_actf = dp; 453: else 454: hktab.b_actl->b_forw = dp; 455: hktab.b_actl = dp; 456: dp->b_active = 2; 457: } 458: return (didie); 459: } 460: 461: hkstart() 462: { 463: register struct buf *bp, *dp; 464: register struct hkdevice *hkaddr = HKADDR; 465: register struct dkdevice *disk; 466: daddr_t bn; 467: int sn, tn, cmd, unit; 468: 469: loop: 470: if ((dp = hktab.b_actf) == NULL) 471: return(0); 472: if ((bp = dp->b_actf) == NULL) { 473: /* 474: * No more requests for this drive, remove from controller queue and 475: * look at next drive. We know we're at the head of the controller queue. 476: * The drive may not need anything, in which case it might be shutting 477: * down in hkclose() and a wakeup is done. 478: */ 479: hktab.b_actf = dp->b_forw; 480: unit = dp - hkutab; 481: disk = &hk_dk[unit]; 482: if (disk->dk_flags & DKF_WANTED) 483: { 484: disk->dk_flags &= ~DKF_WANTED; 485: wakeup(dp); /* finish the close protocol */ 486: } 487: goto loop; 488: } 489: hktab.b_active++; 490: unit = dkunit(bp->b_dev); 491: disk = &hk_dk[unit]; 492: bn = bp->b_blkno; 493: 494: sn = bn % HK_NSPC; 495: tn = sn / HK_NSECT; 496: sn %= HK_NSECT; 497: retry: 498: hkaddr->hkcs1 = HK_CCLR; 499: hkaddr->hkcs2 = unit; 500: hkaddr->hkcs1 = hk_type[unit] | HK_DCLR | HK_GO; 501: hkwait(hkaddr); 502: 503: if ((hkaddr->hkds & HKDS_SVAL) == 0) 504: goto nosval; 505: if (hkaddr->hkds & HKDS_PIP) 506: goto retry; 507: if ((hkaddr->hkds&HKDS_DREADY) != HKDS_DREADY) { 508: disk->dk_flags &= ~DKF_ONLINE; 509: log(LOG_WARNING, "hk%d: !ready\n", unit); 510: if ((hkaddr->hkds&HKDS_DREADY) != HKDS_DREADY) { 511: hkaddr->hkcs1 = hk_type[unit] | HK_DCLR | HK_GO; 512: hkwait(hkaddr); 513: hkaddr->hkcs1 = HK_CCLR; 514: hkwait(hkaddr); 515: hktab.b_active = 0; 516: hktab.b_errcnt = 0; 517: dp->b_actf = bp->av_forw; 518: dp->b_active = 0; 519: bp->b_flags |= B_ERROR; 520: iodone(bp); 521: goto loop; 522: } 523: } 524: disk->dk_flags |= DKF_ONLINE; 525: nosval: 526: hkaddr->hkcyl = bp->b_cylin; 527: hk_cyl[unit] = bp->b_cylin; 528: hkaddr->hkda = (tn << 8) + sn; 529: hkaddr->hkwc = -(bp->b_bcount >> 1); 530: hkaddr->hkba = bp->b_un.b_addr; 531: if (!ubmap) 532: hkaddr->hkxmem=bp->b_xmem; 533: 534: cmd = hk_type[unit] | ((bp->b_xmem & 3) << 8) | HK_IE | HK_GO; 535: if (bp->b_flags & B_READ) 536: cmd |= HK_READ; 537: else 538: cmd |= HK_WRITE; 539: hkaddr->hkcs1 = cmd; 540: #ifdef UCB_METER 541: if (hk_dkn >= 0) { 542: int dkn = hk_dkn + NHK; 543: 544: dk_busy |= 1<<dkn; 545: dk_xfer[dkn]++; 546: dk_wds[dkn] += bp->b_bcount>>6; 547: } 548: #endif 549: return(1); 550: } 551: 552: hkintr() 553: { 554: register struct hkdevice *hkaddr = HKADDR; 555: register struct buf *bp, *dp; 556: int unit; 557: int as = (hkaddr->hkatt >> 8) | hk.sc_softas; 558: int needie = 1; 559: 560: hk.sc_softas = 0; 561: if (hktab.b_active) { 562: dp = hktab.b_actf; 563: bp = dp->b_actf; 564: unit = dkunit(bp->b_dev); 565: #ifdef UCB_METER 566: if (hk_dkn >= 0) 567: dk_busy &= ~(1 << (hk_dkn + NHK)); 568: #endif 569: #ifdef BADSECT 570: if (bp->b_flags&B_BAD) 571: if (hkecc(bp, CONT)) 572: return; 573: #endif 574: if (hkaddr->hkcs1 & HK_CERR) { 575: int recal; 576: u_short ds = hkaddr->hkds; 577: u_short cs2 = hkaddr->hkcs2; 578: u_short er = hkaddr->hker; 579: 580: if (er & HKER_WLE) { 581: log(LOG_WARNING, "hk%d: wrtlck\n", unit); 582: bp->b_flags |= B_ERROR; 583: } else if (++hktab.b_errcnt > 28 || 584: ds&HKDS_HARD || er&HKER_HARD || cs2&HKCS2_HARD) { 585: hard: 586: harderr(bp, "hk"); 587: log(LOG_WARNING, "cs2=%b ds=%b er=%b\n", 588: cs2, HKCS2_BITS, ds, 589: HKDS_BITS, er, HKER_BITS); 590: bp->b_flags |= B_ERROR; 591: hk.sc_recal = 0; 592: } else if (er & HKER_BSE) { 593: #ifdef BADSECT 594: if (hkecc(bp, BSE)) 595: return; 596: else 597: #endif 598: goto hard; 599: } else 600: hktab.b_active = 0; 601: if (cs2&HKCS2_MDS) { 602: hkaddr->hkcs2 = HKCS2_SCLR; 603: goto retry; 604: } 605: recal = 0; 606: if (ds&HKDS_DROT || er&(HKER_OPI|HKER_SKI|HKER_UNS) || 607: (hktab.b_errcnt&07) == 4) 608: recal = 1; 609: if ((er & (HKER_DCK|HKER_ECH)) == HKER_DCK) 610: if (hkecc(bp, ECC)) 611: return; 612: hkaddr->hkcs1 = HK_CCLR; 613: hkaddr->hkcs2 = unit; 614: hkaddr->hkcs1 = hk_type[unit]|HK_DCLR|HK_GO; 615: hkwait(hkaddr); 616: if (recal && hktab.b_active == 0) { 617: hkaddr->hkcs1 = hk_type[unit]|HK_IE|HK_RECAL|HK_GO; 618: hk_cyl[unit] = -1; 619: hk.sc_recal = 0; 620: goto nextrecal; 621: } 622: } 623: retry: 624: switch (hk.sc_recal) { 625: 626: case 1: 627: hkaddr->hkcyl = bp->b_cylin; 628: hk_cyl[unit] = bp->b_cylin; 629: hkaddr->hkcs1 = hk_type[unit]|HK_IE|HK_SEEK|HK_GO; 630: goto nextrecal; 631: case 2: 632: if (hktab.b_errcnt < 16 || 633: (bp->b_flags&B_READ) == 0) 634: goto donerecal; 635: hkaddr->hkatt = hk_offset[hktab.b_errcnt & 017]; 636: hkaddr->hkcs1 = hk_type[unit]|HK_IE|HK_OFFSET|HK_GO; 637: /* fall into ... */ 638: nextrecal: 639: hk.sc_recal++; 640: hkwait(hkaddr); 641: hktab.b_active = 1; 642: return; 643: donerecal: 644: case 3: 645: hk.sc_recal = 0; 646: hktab.b_active = 0; 647: break; 648: } 649: if (hktab.b_active) { 650: hktab.b_active = 0; 651: hktab.b_errcnt = 0; 652: hktab.b_actf = dp->b_forw; 653: dp->b_active = 0; 654: dp->b_errcnt = 0; 655: dp->b_actf = bp->av_forw; 656: bp->b_resid = -(hkaddr->hkwc << 1); 657: iodone(bp); 658: if (dp->b_actf) 659: if (hkustart(unit)) 660: needie = 0; 661: } 662: as &= ~(1<<unit); 663: } 664: for (unit = 0; as; as >>= 1, unit++) 665: if (as & 1) { 666: if (unit < NHK && (hk_dk[unit].dk_flags & DKF_ALIVE)) { 667: if (hkustart(unit)) 668: needie = 0; 669: } else { 670: hkaddr->hkcs1 = HK_CCLR; 671: hkaddr->hkcs2 = unit; 672: hkaddr->hkcs1 = HK_DCLR | HK_GO; 673: hkwait(hkaddr); 674: hkaddr->hkcs1 = HK_CCLR; 675: } 676: } 677: if (hktab.b_actf && hktab.b_active == 0) 678: if (hkstart()) 679: needie = 0; 680: if (needie) 681: hkaddr->hkcs1 = HK_IE; 682: } 683: 684: #ifdef HK_DUMP 685: /* 686: * Dump routine for RK06/07 687: * Dumps from dumplo to end of memory/end of disk section for minor(dev). 688: * It uses the UNIBUS map to dump all of memory if there is a UNIBUS map. 689: */ 690: #define DBSIZE (UBPAGE/NBPG) /* unit of transfer, one UBPAGE */ 691: 692: hkdump(dev) 693: dev_t dev; 694: { 695: register struct hkdevice *hkaddr = HKADDR; 696: daddr_t bn, dumpsize; 697: long paddr; 698: register struct ubmap *ubp; 699: int count, memblks; 700: register struct partition *pi; 701: struct dkdevice *disk; 702: int com, cn, tn, sn, unit; 703: 704: unit = dkunit(dev); 705: if (unit >= NHK) 706: return(EINVAL); 707: 708: disk = &hk_dk[unit]; 709: if ((disk->dk_flags & DKF_ALIVE) == 0) 710: return(ENXIO); 711: pi = &disk->dk_parts[dkpart(dev)]; 712: if (pi->p_fstype != FS_SWAP) 713: return(EFTYPE); 714: 715: dumpsize = hksize(dev) - dumplo; 716: memblks = ctod(physmem); 717: if (dumplo < 0 || dumpsize <= 0) 718: return(EINVAL); 719: bn = dumplo + pi->p_offset; 720: 721: hkaddr->hkcs1 = HK_CCLR; 722: hkwait(hkaddr); 723: hkaddr->hkcs2 = unit; 724: hkaddr->hkcs1 = hk_type[unit] | HK_DCLR | HK_GO; 725: hkwait(hkaddr); 726: if ((hkaddr->hkds & HKDS_VV) == 0) 727: { 728: hkaddr->hkcs1 = hk_type[unit]|HK_IE|HK_PACK|HK_GO; 729: hkwait(hkaddr); 730: } 731: ubp = &UBMAP[0]; 732: for (paddr = 0L; memblks > 0; ) 733: { 734: count = MIN(memblks, DBSIZE); 735: cn = bn/HK_NSPC; 736: sn = bn%HK_NSPC; 737: tn = sn/HK_NSECT; 738: sn = sn%HK_NSECT; 739: hkaddr->hkcyl = cn; 740: hkaddr->hkda = (tn << 8) | sn; 741: hkaddr->hkwc = -(count << (PGSHIFT-1)); 742: com = hk_type[unit]|HK_GO|HK_WRITE; 743: if (ubmap) 744: { 745: ubp->ub_lo = loint(paddr); 746: ubp->ub_hi = hiint(paddr); 747: hkaddr->hkba = 0; 748: } 749: else 750: { 751: /* non UNIBUS map */ 752: hkaddr->hkba = loint(paddr); 753: hkaddr->hkxmem = hiint(paddr); 754: com |= ((paddr >> 8) & (03 << 8)); 755: } 756: hkaddr->hkcs2 = unit; 757: hkaddr->hkcs1 = com; 758: hkwait(hkaddr); 759: if (hkaddr->hkcs1 & HK_CERR) 760: { 761: if (hkaddr->hkcs2 & HKCS2_NEM) 762: return(0); /* made it to end of memory */ 763: return(EIO); 764: } 765: paddr += (count << PGSHIFT); 766: bn += count; 767: memblks -= count; 768: } 769: return(0); /* filled disk minor dev */ 770: } 771: #endif HK_DUMP 772: 773: #define exadr(x,y) (((long)(x) << 16) | (unsigned)(y)) 774: 775: /* 776: * Correct an ECC error and restart the i/o to complete 777: * the transfer if necessary. This is quite complicated because 778: * the transfer may be going to an odd memory address base 779: * and/or across a page boundary. 780: */ 781: hkecc(bp, flag) 782: register struct buf *bp; 783: { 784: register struct hkdevice *hkaddr = HKADDR; 785: ubadr_t addr; 786: int npx, wc; 787: int cn, tn, sn; 788: daddr_t bn; 789: unsigned ndone; 790: int cmd; 791: int unit; 792: 793: #ifdef BADSECT 794: if (flag == CONT) { 795: npx = bp->b_error; 796: ndone = npx * NBPG; 797: wc = ((int)(ndone - bp->b_bcount)) / NBPW; 798: } else 799: #endif 800: { 801: wc = hkaddr->hkwc; 802: ndone = (wc * NBPW) + bp->b_bcount; 803: npx = ndone / NBPG; 804: } 805: unit = dkunit(bp->b_dev); 806: bn = bp->b_blkno; 807: cn = bp->b_cylin - bn / HK_NSPC; 808: bn += npx; 809: cn += bn / HK_NSPC; 810: sn = bn % HK_NSPC; 811: tn = sn / HK_NSECT; 812: sn %= HK_NSECT; 813: hktab.b_active++; 814: 815: switch (flag) { 816: case ECC: 817: { 818: register byte; 819: int bit; 820: long mask; 821: ubadr_t bb; 822: unsigned o; 823: struct ubmap *ubp; 824: 825: log(LOG_WARNING, "hk%d%c: soft ecc sn %D\n", 826: unit, 'a' + (bp->b_dev & 07), bp->b_blkno + npx - 1); 827: mask = hkaddr->hkecpt; 828: byte = hkaddr->hkecps - 1; 829: bit = byte & 07; 830: byte >>= 3; 831: mask <<= bit; 832: o = (ndone - NBPG) + byte; 833: bb = exadr(bp->b_xmem, bp->b_un.b_addr); 834: bb += o; 835: if (ubmap && (bp->b_flags & (B_MAP|B_UBAREMAP))) { 836: ubp = UBMAP + ((bb >> 13) & 037); 837: bb = exadr(ubp->ub_hi, ubp->ub_lo) + (bb & 017777); 838: } 839: /* 840: * Correct until mask is zero or until end of 841: * sector or transfer, whichever comes first. 842: */ 843: while (byte < NBPG && o < bp->b_bcount && mask != 0) { 844: putmemc(bb, getmemc(bb) ^ (int)mask); 845: byte++; 846: o++; 847: bb++; 848: mask >>= 8; 849: } 850: if (wc == 0) 851: return(0); 852: break; 853: } 854: 855: #ifdef BADSECT 856: case BSE: 857: if ((bn = isbad(&hkbad[unit], cn, tn, sn)) < 0) 858: return(0); 859: bp->b_flags |= B_BAD; 860: bp->b_error = npx + 1; 861: bn = (long)hkncyl(unit)*HK_NSPC - HK_NSECT - 1 - bn; 862: cn = bn/HK_NSPC; 863: sn = bn%HK_NSPC; 864: tn = sn/HK_NSECT; 865: sn %= HK_NSECT; 866: wc = -(NBPG / NBPW); 867: break; 868: 869: case CONT: 870: bp->b_flags &= ~B_BAD; 871: if (wc == 0) 872: return(0); 873: break; 874: #endif BADSECT 875: } 876: /* 877: * Have to continue the transfer. Clear the drive 878: * and compute the position where the transfer is to continue. 879: * We have completed npx sectors of the transfer already. 880: */ 881: hkaddr->hkcs1 = HK_CCLR; 882: hkwait(hkaddr); 883: hkaddr->hkcs2 = unit; 884: hkaddr->hkcs1 = hk_type[unit] | HK_DCLR | HK_GO; 885: hkwait(hkaddr); 886: 887: addr = exadr(bp->b_xmem, bp->b_un.b_addr); 888: addr += ndone; 889: hkaddr->hkcyl = cn; 890: hkaddr->hkda = (tn << 8) + sn; 891: hkaddr->hkwc = wc; 892: hkaddr->hkba = (caddr_t)addr; 893: 894: if (!ubmap) 895: hkaddr->hkxmem=hiint(addr); 896: cmd = hk_type[unit] | ((hiint(addr) & 3) << 8) | HK_IE | HK_GO; 897: if (bp->b_flags & B_READ) 898: cmd |= HK_READ; 899: else 900: cmd |= HK_WRITE; 901: hkaddr->hkcs1 = cmd; 902: hktab.b_errcnt = 0; /* error has been corrected */ 903: return (1); 904: } 905: 906: /* 907: * Return the number of blocks in a partition. Call hkopen() to read the 908: * label if necessary. If an open is necessary then a matching close 909: * will be done. 910: */ 911: 912: daddr_t 913: hksize(dev) 914: register dev_t dev; 915: { 916: register struct dkdevice *disk; 917: daddr_t psize; 918: int didopen = 0; 919: 920: disk = &hk_dk[dkunit(dev)]; 921: /* 922: * This should never happen but if we get called early in the kernel's 923: * life (before opening the swap or root devices) then we have to do 924: * the open here. 925: */ 926: 927: if (disk->dk_openmask == 0) 928: { 929: if (hkopen(dev, FREAD|FWRITE, S_IFBLK)) 930: return(-1); 931: didopen = 1; 932: } 933: psize = disk->dk_parts[dkpart(dev)].p_size; 934: if (didopen) 935: hkclose(dev, FREAD|FWRITE, S_IFBLK); 936: return(psize); 937: } 938: #endif NHK > 0