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: * @(#)xp.c 2.6 (2.11BSD GTE) 1998/4/3 7: */ 8: 9: /* 10: * RM02/03/05, RP04/05/06/07, CDC 9766, SI, Fuji 160 and Eagle. This 11: * driver will handle most variants of SMD drives on one or more controllers. 12: */ 13: 14: #include "xp.h" 15: #if NXPD > 0 16: 17: #include "param.h" 18: #include "../machine/seg.h" 19: 20: #include "systm.h" 21: #include "buf.h" 22: #include "conf.h" 23: #include "user.h" 24: #include "hpreg.h" 25: #include "dkbad.h" 26: #include "dk.h" 27: #include "disklabel.h" 28: #include "disk.h" 29: #include "file.h" 30: #include "map.h" 31: #include "uba.h" 32: #include "stat.h" 33: #include "syslog.h" 34: 35: #define XP_SDIST 2 36: #define XP_RDIST 6 37: 38: /* 39: * 'xp' is unique amoung 2.11BSD disk drivers. Drives are not organized 40: * into groups of 8 drives per controller. Instead drives are numbered 41: * across controllers: the second drive ("unit 1") could be on the 2nd 42: * controller. This has the effect of turning the high 5 bits of the minor 43: * device number into the unit number and drives are thus numbered 0 thru 31. 44: * 45: * NOTE: this is different than /boot's view of the world. Sigh. 46: */ 47: 48: #define XPUNIT(dev) (dkunit(dev) & 0x1f) 49: 50: int xp_offset[] = { 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: struct xp_controller { 58: struct buf *xp_actf; /* pointer to next active xputab */ 59: struct buf *xp_actl; /* pointer to last active xputab */ 60: struct hpdevice *xp_addr; /* csr address */ 61: char xp_rh70; /* massbus flag */ 62: char xp_active; /* nonzero if doing a transfer */ 63: }; 64: 65: struct xp_drive { 66: struct xp_controller *xp_ctlr; /* controller to which slave attached */ 67: int xp_unit; /* slave number */ 68: u_short xp_nsect; 69: u_short xp_ntrack; 70: u_short xp_nspc; /* sectors/cylinder */ 71: u_short xp_cc; /* current cylinder, for RM's */ 72: u_long xp_dd0; /* drivedata longword 0 */ 73: struct dkdevice xp_dk; /* kernel resident portion of label */ 74: u_short xp_ncyl; /* cylinders per pack */ 75: }; 76: /* 77: * Some shorthand for accessing the in-kernel label structure. 78: */ 79: #define xp_bopen xp_dk.dk_bopenmask 80: #define xp_copen xp_dk.dk_copenmask 81: #define xp_open xp_dk.dk_openmask 82: #define xp_flags xp_dk.dk_flags 83: #define xp_label xp_dk.dk_label 84: #define xp_parts xp_dk.dk_parts 85: 86: struct xp_controller xp_controller[NXPC]; 87: struct xp_drive xp_drive[NXPD]; 88: 89: struct buf xptab; 90: struct buf xputab[NXPD]; 91: 92: #ifdef BADSECT 93: struct dkbad xpbad[NXPD]; 94: struct buf bxpbuf[NXPD]; 95: #endif 96: 97: #ifdef UCB_METER 98: static int xp_dkn = -1; /* number for iostat */ 99: #endif 100: 101: int xpstrategy(); 102: void xpgetinfo(); 103: daddr_t xpsize(); 104: extern size_t physmem; 105: 106: /* 107: * Setup root SMD ('xp') device (use bootcsr passed from ROMs). In the event 108: * that the system was not booted from a SMD drive but swapdev is a SMD device 109: * we attach the first (0176700) controller. This would be a very unusual 110: * configuration and is unlikely to be encountered. 111: * 112: * This is very confusing, it is an ugly hack, but short of moving autoconfig 113: * back into the kernel there's nothing else I can think of to do. 114: * 115: * NOTE: the swap device must be on the controller used for booting since 116: * that is the only one attached here - the other controllers are attached 117: * by /etc/autoconfig when it runs later. 118: */ 119: 120: xproot(csr) 121: register struct hpdevice *csr; 122: { 123: 124: if (!csr) /* XXX */ 125: csr = (struct hpdevice *)0176700; /* XXX */ 126: xpattach(csr, 0); 127: } 128: 129: /* 130: * Attach controller at xpaddr. Mark as nonexistent if xpaddr is 0; otherwise 131: * attach slaves. This routine must be called once per controller 132: * in ascending controller numbers. 133: * 134: * NOTE: This means that the 'xp' lines in /etc/dtab _MUST_ be in order 135: * starting with 'xp 0' first. 136: */ 137: 138: xpattach(xpaddr, unit) 139: register struct hpdevice *xpaddr; 140: int unit; /* controller number */ 141: { 142: register struct xp_controller *xc = &xp_controller[unit]; 143: static int last_attached = -1; 144: 145: #ifdef UCB_METER 146: if (xp_dkn < 0) { 147: dk_alloc(&xp_dkn, NXPD, "xp", 0L); 148: } 149: #endif 150: 151: if ((unsigned)unit >= NXPC) 152: return(0); 153: if (xpaddr && (fioword(xpaddr) != -1)) { 154: xc->xp_addr = xpaddr; 155: if (fioword(&xpaddr->hpbae) != -1) 156: xc->xp_rh70 = 1; 157: /* 158: * If already attached, ignore (don't want to renumber drives) 159: */ 160: if (unit > last_attached) { 161: last_attached = unit; 162: xpslave(xpaddr, xc); 163: } 164: return(1); 165: } 166: xc->xp_addr = 0; 167: return(0); 168: } 169: 170: /* 171: * Determine what drives are attached to a controller; the type and geometry 172: * information will be retrieved at open time from the disklabel. 173: */ 174: xpslave(xpaddr, xc) 175: register struct hpdevice *xpaddr; 176: struct xp_controller *xc; 177: { 178: register struct xp_drive *xd; 179: register struct xpst *st; 180: int j, dummy; 181: static int nxp = 0; 182: 183: for (j = 0; j < 8; j++) { 184: xpaddr->hpcs1.w = HP_NOP; 185: xpaddr->hpcs2.w = j; 186: xpaddr->hpcs1.w = HP_GO; /* testing... */ 187: delay(6000L); 188: dummy = xpaddr->hpds; 189: if (xpaddr->hpcs2.w & HPCS2_NED) { 190: xpaddr->hpcs2.w = HPCS2_CLR; 191: continue; 192: } 193: if (nxp < NXPD) { 194: xd = &xp_drive[nxp++]; 195: xd->xp_ctlr = xc; 196: xd->xp_unit = j; 197: /* 198: * Allocate the disklabel now. This is very early in the system's life 199: * so fragmentation will be minimized if any labels are allocated from 200: * main memory. Then initialize the flags to indicate a drive is present. 201: */ 202: xd->xp_label = disklabelalloc(); 203: xd->xp_flags = DKF_ALIVE; 204: } 205: } 206: } 207: 208: xpopen(dev, flags, mode) 209: dev_t dev; 210: int flags, mode; 211: { 212: register struct xp_drive *xd; 213: int unit = XPUNIT(dev); 214: int i, part = dkpart(dev), rpm; 215: register int mask; 216: 217: if (unit >= NXPD) 218: return(ENXIO); 219: xd = &xp_drive[unit]; 220: if ((xd->xp_flags & DKF_ALIVE) == 0) 221: return(ENXIO); 222: /* 223: * Now we read the label. First wait for any pending opens/closes to 224: * complete. 225: */ 226: while (xd->xp_flags & (DKF_OPENING|DKF_CLOSING)) 227: sleep(xd, PRIBIO); 228: /* 229: * On first open get label (which has the geometry information as well as 230: * the partition tables). We may block reading the label so be careful to 231: * stop any other opens. 232: */ 233: if (xd->xp_open == 0) 234: { 235: xd->xp_flags |= DKF_OPENING; 236: xpgetinfo(xd, dev); 237: xd->xp_flags &= ~DKF_OPENING; 238: wakeup(xd); 239: } 240: /* 241: * Need to make sure the partition is not out of bounds. This requires 242: * mapping in the external label. Since this only happens when a partition 243: * is opened (at mount time for example) it is unlikely to be an efficiency 244: * concern. 245: */ 246: mapseg5(xd->xp_label, LABELDESC); 247: i = ((struct disklabel *)SEG5)->d_npartitions; 248: rpm = ((struct disklabel *)SEG5)->d_rpm; 249: normalseg5(); 250: if (part >= i) 251: return(ENXIO); 252: #ifdef UCB_METER 253: if (xp_dkn >= 0) { 254: dk_wps[xp_dkn+unit] = (long) xd->xp_nsect * (rpm / 60) * 256L; 255: } 256: #endif 257: mask = 1 << part; 258: dkoverlapchk(xd->xp_open, dev, xd->xp_label, "xp"); 259: if (mode == S_IFCHR) 260: xd->xp_copen |= mask; 261: else if (mode == S_IFBLK) 262: xd->xp_bopen |= mask; 263: else 264: return(EINVAL); 265: xd->xp_open |= mask; 266: return(0); 267: } 268: 269: xpclose(dev, flags, mode) 270: dev_t dev; 271: int flags, mode; 272: { 273: int s; 274: register int mask; 275: register struct xp_drive *xd; 276: int unit = XPUNIT(dev); 277: 278: xd = &xp_drive[unit]; 279: mask = 1 << dkpart(dev); 280: if (mode == S_IFCHR) 281: xd->xp_copen &= ~mask; 282: else if (mode == S_IFBLK) 283: xd->xp_bopen &= ~mask; 284: else 285: return(EINVAL); 286: xd->xp_open = xd->xp_copen | xd->xp_bopen; 287: if (xd->xp_open == 0) 288: { 289: xd->xp_flags |= DKF_CLOSING; 290: s = splbio(); 291: while (xputab[unit].b_actf) 292: sleep(&xputab[unit], PRIBIO); 293: xd->xp_flags &= ~DKF_CLOSING; 294: splx(s); 295: wakeup(xd); 296: } 297: return(0); 298: } 299: 300: void 301: xpdfltlbl(xd, lp) 302: register struct xp_drive *xd; 303: register struct disklabel *lp; 304: { 305: register struct partition *pi = &lp->d_partitions[0]; 306: 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 label containing a geometry sufficient *only* to 311: * read/write sector 1 (LABELSECTOR) is created. 1 track, 1 cylinder and 312: * 2 sectors per track. 313: */ 314: 315: bzero(lp, sizeof (*lp)); 316: lp->d_type = DTYPE_SMD; 317: lp->d_secsize = 512; /* XXX */ 318: lp->d_nsectors = LABELSECTOR + 1; /* # sectors/track */ 319: lp->d_ntracks = 1; /* # tracks/cylinder */ 320: lp->d_secpercyl = LABELSECTOR + 1; /* # sectors/cylinder */ 321: lp->d_ncylinders = 1; /* # cylinders */ 322: lp->d_npartitions = 1; /* 1 partition = 'a' */ 323: /* 324: * Need to put the information where the driver expects it. This is normally 325: * done after reading the label. Since we're creating a fake label we have to 326: * copy the invented geometry information to the right place. 327: */ 328: xd->xp_nsect = lp->d_nsectors; 329: xd->xp_ntrack = lp->d_ntracks; 330: xd->xp_nspc = lp->d_secpercyl; 331: xd->xp_ncyl = lp->d_ncylinders; 332: xd->xp_dd0 = lp->d_drivedata[0]; 333: 334: pi->p_size = LABELSECTOR + 1; 335: pi->p_fstype = FS_V71K; 336: pi->p_frag = 1; 337: pi->p_fsize = 1024; 338: bcopy(pi, xd->xp_parts, sizeof (lp->d_partitions)); 339: } 340: 341: /* 342: * Read disklabel. It is tempting to generalize this routine so that 343: * all disk drivers could share it. However by the time all of the 344: * necessary parameters are setup and passed the savings vanish. Also, 345: * each driver has a different method of calculating the number of blocks 346: * to use if one large partition must cover the disk. 347: * 348: * This routine used to always return success and callers carefully checked 349: * the return status. Silly. This routine will fake a label (a single 350: * partition spanning the drive) if necessary but will never return an error. 351: * 352: * It is the caller's responsibility to check the validity of partition 353: * numbers, etc. 354: */ 355: 356: void 357: xpgetinfo(xd, dev) 358: register struct xp_drive *xd; 359: dev_t dev; 360: { 361: struct disklabel locallabel; 362: char *msg; 363: register struct disklabel *lp = &locallabel; 364: 365: xpdfltlbl(xd, lp); 366: msg = readdisklabel((dev & ~7) | 0, xpstrategy, lp); /* 'a' */ 367: if (msg != 0) 368: { 369: log(LOG_NOTICE, "xp%da using labelonly geometry: %s\n", 370: XPUNIT(dev), msg); 371: xpdfltlbl(xd, lp); 372: } 373: mapseg5(xd->xp_label, LABELDESC); 374: bcopy(lp, (struct disklabel *)SEG5, sizeof (struct disklabel)); 375: normalseg5(); 376: bcopy(lp->d_partitions, xd->xp_parts, sizeof (lp->d_partitions)); 377: xd->xp_nsect = lp->d_nsectors; 378: xd->xp_ntrack = lp->d_ntracks; 379: xd->xp_nspc = lp->d_secpercyl; 380: xd->xp_ncyl = lp->d_ncylinders; 381: xd->xp_dd0 = lp->d_drivedata[0]; 382: return; 383: } 384: 385: xpstrategy(bp) 386: register struct buf *bp; 387: { 388: register struct xp_drive *xd; 389: struct partition *pi; 390: int unit; 391: struct buf *dp; 392: register int s; 393: 394: unit = XPUNIT(bp->b_dev); 395: xd = &xp_drive[unit]; 396: 397: if (unit >= NXPD || !xd->xp_ctlr || !(xd->xp_flags & DKF_ALIVE)) 398: { 399: bp->b_error = ENXIO; 400: goto bad; 401: } 402: s = partition_check(bp, &xd->xp_dk); 403: if (s < 0) 404: goto bad; 405: if (s == 0) 406: goto done; 407: if (xd->xp_ctlr->xp_rh70 == 0) 408: mapalloc(bp); 409: pi = &xd->xp_parts[dkpart(bp->b_dev)]; 410: bp->b_cylin = (bp->b_blkno + pi->p_offset) / xd->xp_nspc; 411: dp = &xputab[unit]; 412: s = splbio(); 413: disksort(dp, bp); 414: if (dp->b_active == 0) 415: { 416: xpustart(unit); 417: if (xd->xp_ctlr->xp_active == 0) 418: xpstart(xd->xp_ctlr); 419: } 420: splx(s); 421: return; 422: bad: 423: bp->b_flags |= B_ERROR; 424: done: 425: iodone(bp); 426: return; 427: } 428: 429: /* 430: * Unit start routine. Seek the drive to where the data are and then generate 431: * another interrupt to actually start the transfer. If there is only one 432: * drive or we are very close to the data, don't bother with the search. If 433: * called after searching once, don't bother to look where we are, just queue 434: * for transfer (to avoid positioning forever without transferring). 435: */ 436: xpustart(unit) 437: int unit; 438: { 439: register struct xp_drive *xd; 440: register struct hpdevice *xpaddr; 441: register struct buf *dp; 442: struct buf *bp, *bbp; 443: daddr_t bn; 444: int sn, cn, csn; 445: 446: xd = &xp_drive[unit]; 447: xpaddr = xd->xp_ctlr->xp_addr; 448: xpaddr->hpcs2.w = xd->xp_unit; 449: xpaddr->hpcs1.c[0] = HP_IE; 450: xpaddr->hpas = 1 << xd->xp_unit; 451: #ifdef UCB_METER 452: if (xp_dkn >= 0) { 453: dk_busy &= ~(1 << (xp_dkn + unit)); 454: } 455: #endif 456: dp = &xputab[unit]; 457: if ((bp=dp->b_actf) == NULL) 458: return; 459: /* 460: * If we have already positioned this drive, 461: * then just put it on the ready queue. 462: */ 463: if (dp->b_active) 464: goto done; 465: dp->b_active++; 466: /* 467: * If drive has just come up, set up the pack. 468: */ 469: if (((xpaddr->hpds & HPDS_VV) == 0) || !(xd->xp_flags & DKF_ONLINE)) { 470: xpaddr->hpcs1.c[0] = HP_IE | HP_PRESET | HP_GO; 471: xpaddr->hpof = HPOF_FMT22; 472: xd->xp_flags |= DKF_ONLINE; 473: #ifdef XPDEBUG 474: log(LOG_NOTICE, "xp%d preset done\n", unit); 475: #endif 476: 477: /* 478: * XXX - The 'h' partition is used below to access the bad block area. This 479: * XXX - will almost certainly be wrong if the user has defined another 480: * XXX - partition to span the entire drive including the bad block area. It 481: * XXX - is not known what to do about this. 482: */ 483: #ifdef BADSECT 484: bbp = &bxpbuf[unit]; 485: bbp->b_flags = B_READ | B_BUSY | B_PHYS; 486: bbp->b_dev = bp->b_dev | 7; /* "h" partition whole disk */ 487: bbp->b_bcount = sizeof(struct dkbad); 488: bbp->b_un.b_addr = (caddr_t)&xpbad[unit]; 489: bbp->b_blkno = (daddr_t)xd->xp_ncyl * xd->xp_nspc - xd->xp_nsect; 490: bbp->b_cylin = xd->xp_ncyl - 1; 491: if (xd->xp_ctlr->xp_rh70 == 0) 492: mapalloc(bbp); 493: dp->b_actf = bbp; 494: bbp->av_forw = bp; 495: bp = bbp; 496: #endif BADSECT 497: } 498: 499: #if NXPD > 1 500: /* 501: * If drive is offline, forget about positioning. 502: */ 503: if (xpaddr->hpds & (HPDS_DREADY) != (HPDS_DREADY)) 504: { 505: xd->xp_flags &= ~DKF_ONLINE; 506: goto done; 507: } 508: /* 509: * Figure out where this transfer is going to 510: * and see if we are close enough to justify not searching. 511: */ 512: bn = bp->b_blkno; 513: cn = bp->b_cylin; 514: sn = bn % xd->xp_nspc; 515: sn += xd->xp_nsect - XP_SDIST; 516: sn %= xd->xp_nsect; 517: 518: if ((!(xd->xp_dd0 & XP_CC) && (xd->xp_cc != cn)) 519: || xpaddr->hpcc != cn) 520: goto search; 521: if (xd->xp_dd0 & XP_NOSEARCH) 522: goto done; 523: csn = (xpaddr->hpla >> 6) - sn + XP_SDIST - 1; 524: if (csn < 0) 525: csn += xd->xp_nsect; 526: if (csn > xd->xp_nsect - XP_RDIST) 527: goto done; 528: search: 529: xpaddr->hpdc = cn; 530: xpaddr->hpda = sn; 531: xpaddr->hpcs1.c[0] = (xd->xp_dd0 & XP_NOSEARCH) ? 532: (HP_IE | HP_SEEK | HP_GO) : (HP_IE | HP_SEARCH | HP_GO); 533: xd->xp_cc = cn; 534: #ifdef UCB_METER 535: /* 536: * Mark unit busy for iostat. 537: */ 538: if (xp_dkn >= 0) { 539: int dkn = xp_dkn + unit; 540: 541: dk_busy |= 1<<dkn; 542: dk_seek[dkn]++; 543: } 544: #endif 545: return; 546: #endif NXPD > 1 547: done: 548: /* 549: * Device is ready to go. 550: * Put it on the ready queue for the controller. 551: */ 552: dp->b_forw = NULL; 553: if (xd->xp_ctlr->xp_actf == NULL) 554: xd->xp_ctlr->xp_actf = dp; 555: else 556: xd->xp_ctlr->xp_actl->b_forw = dp; 557: xd->xp_ctlr->xp_actl = dp; 558: } 559: 560: /* 561: * Start up a transfer on a controller. 562: */ 563: xpstart(xc) 564: register struct xp_controller *xc; 565: { 566: register struct hpdevice *xpaddr; 567: register struct buf *bp; 568: struct xp_drive *xd; 569: struct buf *dp; 570: daddr_t bn; 571: int unit, part, sn, tn, cn; 572: 573: xpaddr = xc->xp_addr; 574: loop: 575: /* 576: * Pull a request off the controller queue. 577: */ 578: if ((dp = xc->xp_actf) == NULL) 579: return; 580: if ((bp = dp->b_actf) == NULL) { 581: /* 582: * No more requests for this drive, remove from controller queue and 583: * look at next drive. We know we're at the head of the controller queue. 584: * The drive may not need anything, in which case it might be shutting 585: * down in xpclose() and a wakeup is done. 586: */ 587: dp->b_active = 0; 588: xc->xp_actf = dp->b_forw; 589: unit = dp - xputab; 590: xd = &xp_drive[unit]; 591: if (xd->xp_open == 0) 592: wakeup(dp); /* finish close protocol */ 593: goto loop; 594: } 595: /* 596: * Mark controller busy and determine destination of this request. 597: */ 598: xc->xp_active++; 599: part = dkpart(bp->b_dev); 600: unit = XPUNIT(bp->b_dev); 601: xd = &xp_drive[unit]; 602: bn = bp->b_blkno; 603: cn = (xd->xp_parts[part].p_offset + bn) / xd->xp_nspc; 604: sn = bn % xd->xp_nspc; 605: tn = sn / xd->xp_nsect; 606: sn = sn % xd->xp_nsect; 607: /* 608: * Select drive. 609: */ 610: xpaddr->hpcs2.w = xd->xp_unit; 611: /* 612: * Check that it is ready and online. 613: */ 614: if ((xpaddr->hpds & HPDS_DREADY) != (HPDS_DREADY)) { 615: xd->xp_flags &= ~DKF_ONLINE; 616: xc->xp_active = 0; 617: dp->b_errcnt = 0; 618: dp->b_actf = bp->av_forw; 619: bp->b_flags |= B_ERROR; 620: iodone(bp); 621: goto loop; 622: } 623: xd->xp_flags |= DKF_ONLINE; 624: 625: if (dp->b_errcnt >= 16 && (bp->b_flags & B_READ)) { 626: xpaddr->hpof = xp_offset[dp->b_errcnt & 017] | HPOF_FMT22; 627: xpaddr->hpcs1.w = HP_OFFSET | HP_GO; 628: while ((xpaddr->hpds & (HPDS_PIP | HPDS_DRY)) != HPDS_DRY); 629: } 630: xpaddr->hpdc = cn; 631: xpaddr->hpda = (tn << 8) + sn; 632: xpaddr->hpba = bp->b_un.b_addr; 633: if (xc->xp_rh70) 634: xpaddr->hpbae = bp->b_xmem; 635: xpaddr->hpwc = -(bp->b_bcount >> 1); 636: /* 637: * Warning: unit is being used as a temporary. 638: */ 639: unit = ((bp->b_xmem & 3) << 8) | HP_IE | HP_GO; 640: #ifdef XP_FORMAT 641: if (minor(bp->b_dev) & 0200) 642: unit |= bp->b_flags & B_READ ? HP_RHDR : HP_WHDR; 643: else 644: unit |= bp->b_flags & B_READ ? HP_RCOM : HP_WCOM; 645: #else 646: if (bp->b_flags & B_READ) 647: unit |= HP_RCOM; 648: else 649: unit |= HP_WCOM; 650: #endif 651: xpaddr->hpcs1.w = unit; 652: #ifdef UCB_METER 653: if (xp_dkn >= 0) { 654: int dkn = xp_dkn + XPUNIT(bp->b_dev); 655: 656: dk_busy |= 1<<dkn; 657: dk_xfer[dkn]++; 658: dk_seek[dkn]++; 659: dk_wds[dkn] += bp->b_bcount>>6; 660: } 661: #endif 662: } 663: 664: /* 665: * Handle a disk interrupt. 666: */ 667: xpintr(dev) 668: int dev; 669: { 670: register struct hpdevice *xpaddr; 671: register struct buf *dp; 672: struct xp_controller *xc; 673: struct xp_drive *xd; 674: struct buf *bp; 675: register int unit; 676: int as; 677: 678: xc = &xp_controller[dev]; 679: xpaddr = xc->xp_addr; 680: as = xpaddr->hpas & 0377; 681: if (xc->xp_active) { 682: /* 683: * Get device and block structures. Select the drive. 684: */ 685: dp = xc->xp_actf; 686: bp = dp->b_actf; 687: #ifdef BADSECT 688: if (bp->b_flags & B_BAD) 689: if (xpecc(bp, CONT)) 690: return; 691: #endif 692: unit = XPUNIT(bp->b_dev); 693: #ifdef UCB_METER 694: if (xp_dkn >= 0) { 695: dk_busy &= ~(1 << (xp_dkn + unit)); 696: } 697: #endif 698: xd = &xp_drive[unit]; 699: xpaddr->hpcs2.c[0] = xd->xp_unit; 700: /* 701: * Check for and process errors. 702: */ 703: if (xpaddr->hpcs1.w & HP_TRE) { 704: while ((xpaddr->hpds & HPDS_DRY) == 0); 705: if (xpaddr->hper1 & HPER1_WLE) { 706: /* 707: * Give up on write locked deviced immediately. 708: */ 709: log(LOG_NOTICE, "xp%d: write locked\n", unit); 710: bp->b_flags |= B_ERROR; 711: #ifdef BADSECT 712: } 713: else if ((xpaddr->rmer2 & RMER2_BSE) 714: || (xpaddr->hper1 & HPER1_FER)) { 715: #ifdef XP_FORMAT 716: /* 717: * Allow this error on format devices. 718: */ 719: if (minor(bp->b_dev) & 0200) 720: goto errdone; 721: #endif 722: if (xpecc(bp, BSE)) 723: return; 724: else 725: goto hard; 726: #endif BADSECT 727: } 728: else { 729: /* 730: * After 28 retries (16 without offset and 731: * 12 with offset positioning), give up. 732: */ 733: if (++dp->b_errcnt > 28) { 734: hard: 735: harderr(bp, "xp"); 736: log(LOG_NOTICE,"cs2=%b er1=%b er2=%b\n", 737: xpaddr->hpcs2.w, HPCS2_BITS, 738: xpaddr->hper1, HPER1_BITS, 739: xpaddr->rmer2, RMER2_BITS); 740: bp->b_flags |= B_ERROR; 741: } 742: else 743: xc->xp_active = 0; 744: } 745: /* 746: * If soft ecc, correct it (continuing by returning if 747: * necessary). Otherwise, fall through and retry the 748: * transfer. 749: */ 750: if((xpaddr->hper1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK) 751: if (xpecc(bp, ECC)) 752: return; 753: errdone: 754: xpaddr->hpcs1.w = HP_TRE | HP_IE | HP_DCLR | HP_GO; 755: if ((dp->b_errcnt & 07) == 4) { 756: xpaddr->hpcs1.w = HP_RECAL | HP_IE | HP_GO; 757: while ((xpaddr->hpds & (HPDS_PIP | HPDS_DRY)) != HPDS_DRY); 758: } 759: xd->xp_cc = -1; 760: } 761: if (xc->xp_active) { 762: if (dp->b_errcnt) { 763: xpaddr->hpcs1.w = HP_RTC | HP_GO; 764: while ((xpaddr->hpds & (HPDS_PIP | HPDS_DRY)) != HPDS_DRY); 765: } 766: xc->xp_active = 0; 767: xc->xp_actf = dp->b_forw; 768: dp->b_active = 0; 769: dp->b_errcnt = 0; 770: dp->b_actf = bp->b_actf; 771: xd->xp_cc = bp->b_cylin; 772: bp->b_resid = - (xpaddr->hpwc << 1); 773: iodone(bp); 774: xpaddr->hpcs1.w = HP_IE; 775: if (dp->b_actf) 776: xpustart(unit); 777: } 778: as &= ~(1 << xp_drive[unit].xp_unit); 779: } 780: else { 781: if (as == 0) 782: xpaddr->hpcs1.w = HP_IE; 783: xpaddr->hpcs1.c[1] = HP_TRE >> 8; 784: } 785: for (unit = 0; unit < NXPD; unit++) 786: if ((xp_drive[unit].xp_ctlr == xc) && 787: (as & (1 << xp_drive[unit].xp_unit))) 788: xpustart(unit); 789: xpstart(xc); 790: } 791: 792: #define exadr(x,y) (((long)(x) << 16) | (unsigned)(y)) 793: 794: /* 795: * Correct an ECC error and restart the i/o to complete the transfer if 796: * necessary. This is quite complicated because the correction may be going 797: * to an odd memory address base and the transfer may cross a sector boundary. 798: */ 799: xpecc(bp, flag) 800: register struct buf *bp; 801: int flag; 802: { 803: register struct xp_drive *xd; 804: register struct hpdevice *xpaddr; 805: register unsigned byte; 806: ubadr_t bb, addr; 807: long wrong; 808: int bit, wc; 809: unsigned ndone, npx; 810: int ocmd; 811: int cn, tn, sn; 812: daddr_t bn; 813: struct ubmap *ubp; 814: int unit; 815: 816: /* 817: * ndone is #bytes including the error which is assumed to be in the 818: * last disk page transferred. 819: */ 820: unit = XPUNIT(bp->b_dev); 821: xd = &xp_drive[unit]; 822: xpaddr = xd->xp_ctlr->xp_addr; 823: #ifdef BADSECT 824: if (flag == CONT) { 825: npx = bp->b_error; 826: bp->b_error = 0; 827: ndone = npx * NBPG; 828: wc = ((int)(ndone - bp->b_bcount)) / (int)NBPW; 829: } 830: else { 831: #endif 832: wc = xpaddr->hpwc; 833: ndone = ((unsigned)wc * NBPW) + bp->b_bcount; 834: npx = ndone / NBPG; 835: #ifdef BADSECT 836: } 837: #endif 838: ocmd = (xpaddr->hpcs1.w & ~HP_RDY) | HP_IE | HP_GO; 839: bb = exadr(bp->b_xmem, bp->b_un.b_addr); 840: bn = bp->b_blkno; 841: cn = bp->b_cylin - (bn / xd->xp_nspc); 842: bn += npx; 843: cn += bn / xd->xp_nspc; 844: sn = bn % xd->xp_nspc; 845: tn = sn; 846: tn /= xd->xp_nsect; 847: sn %= xd->xp_nsect; 848: switch (flag) { 849: case ECC: 850: log(LOG_NOTICE, "xp%d%c: soft ecc sn%D\n", 851: unit, 'a' + dkpart(bp->b_dev), 852: bp->b_blkno + (npx - 1)); 853: wrong = xpaddr->hpec2; 854: if (wrong == 0) { 855: xpaddr->hpof = HPOF_FMT22; 856: xpaddr->hpcs1.w |= HP_IE; 857: return (0); 858: } 859: /* 860: * Compute the byte/bit position of the err 861: * within the last disk page transferred. 862: * Hpec1 is origin-1. 863: */ 864: byte = xpaddr->hpec1 - 1; 865: bit = byte & 07; 866: byte >>= 3; 867: byte += ndone - NBPG; 868: wrong <<= bit; 869: /* 870: * Correct until mask is zero or until end of 871: * transfer, whichever comes first. 872: */ 873: while (byte < bp->b_bcount && wrong != 0) { 874: addr = bb + byte; 875: if (bp->b_flags & (B_MAP|B_UBAREMAP)) { 876: /* 877: * Simulate UNIBUS map if UNIBUS 878: * transfer. 879: */ 880: ubp = UBMAP + ((addr >> 13) & 037); 881: addr = exadr(ubp->ub_hi, ubp->ub_lo) + (addr & 017777); 882: } 883: putmemc(addr, getmemc(addr) ^ (int) wrong); 884: byte++; 885: wrong >>= 8; 886: } 887: break; 888: #ifdef BADSECT 889: case BSE: 890: if ((bn = isbad(&xpbad[unit], cn, tn, sn)) < 0) 891: return(0); 892: bp->b_flags |= B_BAD; 893: bp->b_error = npx + 1; 894: bn = (daddr_t)xd->xp_ncyl * xd->xp_nspc - xd->xp_nsect - 1 - bn; 895: cn = bn/xd->xp_nspc; 896: sn = bn%xd->xp_nspc; 897: tn = sn; 898: tn /= xd->xp_nsect; 899: sn %= xd->xp_nsect; 900: log(LOG_NOTICE, "revector to cn %d tn %d sn %d\n", 901: cn, tn, sn); 902: wc = -(512 / (int)NBPW); 903: break; 904: case CONT: 905: bp->b_flags &= ~B_BAD; 906: log(LOG_NOTICE, "xpecc CONT: bn %D cn %d tn %d sn %d\n", 907: bn, cn, tn, sn); 908: break; 909: #endif BADSECT 910: } 911: xd->xp_ctlr->xp_active++; 912: if (wc == 0) 913: return (0); 914: 915: /* 916: * Have to continue the transfer. Clear the drive and compute the 917: * position where the transfer is to continue. We have completed 918: * npx sectors of the transfer already. 919: */ 920: xpaddr->hpcs2.w = xd->xp_unit; 921: xpaddr->hpcs1.w = HP_TRE | HP_DCLR | HP_GO; 922: addr = bb + ndone; 923: xpaddr->hpdc = cn; 924: xpaddr->hpda = (tn << 8) + sn; 925: xpaddr->hpwc = wc; 926: xpaddr->hpba = (caddr_t)addr; 927: if (xd->xp_ctlr->xp_rh70) 928: xpaddr->hpbae = (int)(addr >> 16); 929: xpaddr->hpcs1.w = ocmd; 930: return (1); 931: } 932: 933: xpioctl(dev, cmd, data, flag) 934: dev_t dev; 935: int cmd; 936: caddr_t data; 937: int flag; 938: { 939: register int error; 940: struct dkdevice *disk = &xp_drive[XPUNIT(dev)].xp_dk; 941: 942: error = ioctldisklabel(dev, cmd, data, flag, disk, xpstrategy); 943: return(error); 944: } 945: 946: #ifdef XP_DUMP 947: /* 948: * Dump routine. Dumps from dumplo to end of memory/end of disk section for 949: * minor(dev). 950: */ 951: #define DBSIZE 16 /* number of blocks to write */ 952: 953: xpdump(dev) 954: dev_t dev; 955: { 956: struct xp_drive *xd; 957: register struct hpdevice *xpaddr; 958: struct partition *pi; 959: daddr_t bn, dumpsize; 960: long paddr; 961: int sn, count, memblks, unit; 962: register struct ubmap *ubp; 963: 964: unit = XPUNIT(dev); 965: xd = &xp_drive[unit]; 966: 967: if (unit > NXPD || xd->xp_ctlr == 0) 968: return(EINVAL); 969: if (!(xd->xp_flags & DKF_ALIVE)) 970: return(ENXIO); 971: 972: pi = &xd->xp_parts[dkpart(dev)]; 973: if (pi->p_fstype != FS_SWAP) 974: return(EFTYPE); 975: 976: xpaddr = xd->xp_ctlr->xp_addr; 977: 978: dumpsize = xpsize(dev) - dumplo; 979: memblks = ctod(physmem); 980: 981: if (dumplo < 0 || dumpsize <= 0) 982: return(EINVAL); 983: if (memblks > dumpsize) 984: memblks = dumpsize; 985: bn = dumplo + pi->p_offset; 986: 987: xpaddr->hpcs2.w = xd->xp_unit; 988: if ((xpaddr->hpds & HPDS_VV) == 0) 989: { 990: xpaddr->hpcs1.w = HP_DCLR | HP_GO; 991: xpaddr->hpcs1.w = HP_PRESET | HP_GO; 992: xpaddr->hpof = HPOF_FMT22; 993: } 994: if ((xpaddr->hpds & HPDS_DREADY) != (HPDS_DREADY)) 995: return(EFAULT); 996: ubp = &UBMAP[0]; 997: for (paddr = 0L; memblks > 0; ) 998: { 999: count = MIN(memblks, DBSIZE); 1000: xpaddr->hpdc = bn / xd->xp_nspc; 1001: sn = bn % xd->xp_nspc; 1002: xpaddr->hpda = ((sn / xd->xp_nsect) << 8) | (sn % xd->xp_nsect); 1003: xpaddr->hpwc = -(count << (PGSHIFT - 1)); 1004: xpaddr->hper1 = 0; 1005: xpaddr->hper3 = 0; 1006: if (ubmap && (xd->xp_ctlr->xp_rh70 == 0)) 1007: { 1008: ubp->ub_lo = loint(paddr); 1009: ubp->ub_hi = hiint(paddr); 1010: xpaddr->hpba = 0; 1011: xpaddr->hpcs1.w = HP_WCOM | HP_GO; 1012: } 1013: else 1014: { 1015: /* 1016: * Non-UNIBUS map, or 11/70 RH70 (MASSBUS) 1017: */ 1018: xpaddr->hpba = (caddr_t)loint(paddr); 1019: if (xd->xp_ctlr->xp_rh70) 1020: xpaddr->hpbae = hiint(paddr); 1021: xpaddr->hpcs1.w = HP_WCOM | HP_GO | ((paddr >> 8) & (03 << 8)); 1022: } 1023: /* Emulex controller emulating two RM03's needs a delay */ 1024: delay(50000L); 1025: while (xpaddr->hpcs1.w & HP_GO) 1026: continue; 1027: if (xpaddr->hpcs1.w & HP_TRE) 1028: return(EIO); 1029: paddr += (count << PGSHIFT); 1030: bn += count; 1031: memblks -= count; 1032: } 1033: return(0); 1034: } 1035: #endif XP_DUMP 1036: 1037: /* 1038: * Return the number of blocks in a partition. Call xpopen() to read the 1039: * label if necessary. If an open is necessary then a matching close 1040: * will be done. 1041: */ 1042: daddr_t 1043: xpsize(dev) 1044: register dev_t dev; 1045: { 1046: register struct xp_drive *xd; 1047: daddr_t psize; 1048: int didopen = 0; 1049: 1050: xd = &xp_drive[XPUNIT(dev)]; 1051: /* 1052: * This should never happen but if we get called early in the kernel's 1053: * life (before opening the swap or root devices) then we have to do 1054: * the open here. 1055: */ 1056: if (xd->xp_open == 0) 1057: { 1058: if (xpopen(dev, FREAD|FWRITE, S_IFBLK)) 1059: return(-1); 1060: didopen = 1; 1061: } 1062: psize = xd->xp_parts[dkpart(dev)].p_size; 1063: if (didopen) 1064: xpclose(dev, FREAD|FWRITE, S_IFBLK); 1065: return(psize); 1066: } 1067: #endif /* NXPD */