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 */

Defined functions

xpattach defined in line 138; used 1 times
xpclose defined in line 269; used 1 times
xpdfltlbl defined in line 300; used 2 times
xpdump defined in line 953; never used
xpecc defined in line 799; used 3 times
xpgetinfo defined in line 356; used 2 times
xpintr defined in line 667; used 1 times
xpioctl defined in line 933; never used
xpopen defined in line 208; used 1 times
xproot defined in line 120; never used
xpsize defined in line 1042; used 2 times
xpslave defined in line 174; used 1 times
xpstart defined in line 563; used 2 times
xpstrategy defined in line 385; used 3 times
xpustart defined in line 436; used 3 times

Defined variables

bxpbuf defined in line 94; used 1 times
xp_controller defined in line 86; used 2 times
xp_dkn defined in line 98; used 12 times
xp_drive defined in line 87; used 15 times
xp_offset defined in line 50; used 1 times
xpbad defined in line 93; used 2 times
xptab defined in line 89; never used
xputab defined in line 90; used 5 times

Defined struct's

xp_controller defined in line 57; used 12 times
xp_drive defined in line 65; used 26 times

Defined macros

DBSIZE defined in line 951; used 1 times
XPUNIT defined in line 48; used 11 times
XP_RDIST defined in line 36; used 1 times
XP_SDIST defined in line 35; used 2 times
exadr defined in line 792; used 2 times
xp_bopen defined in line 79; used 3 times
xp_copen defined in line 80; used 3 times
xp_flags defined in line 82; used 14 times
xp_label defined in line 83; used 4 times
xp_open defined in line 81; used 7 times
xp_parts defined in line 84; used 6 times
Last modified: 1998-04-04
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 6277
Valid CSS Valid XHTML 1.0 Strict