# 2.11BSD#431 - /usr/src/sys/pdpuba/xp.c

##### Functions

    xpattach          X
    xpclose           X
    xpdfltlbl         X
    xpdump            X
    xpecc             X
    xpgetinfo         X
    xpintr            X
    xpioctl           X
    xpopen            X
    xproot            X
    xpsize            X
    xpslave           X
    xpstart           X
    xpstrategy        X
    xpustart          X

##### Variables

    bxpbuf            X
    xp_controller     X
    xp_drive          X
    xp_offset         X
    xpbad             X
    xptab             X
    xputab            X

##### Macros

    DBSIZE            X
    XPUNIT            X
    XP_RDIST          X
    XP_SDIST          X
    exadr             X
    xp_bopen          X
    xp_copen          X
    xp_flags          X
    xp_label          X
    xp_open           X
    xp_parts          X

##### struct's

    xp_controller     X
    xp_drive          X

       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

- in line 126

xpclose defined in line 269; used 1 times

- in line 1064

xpdfltlbl defined in line 300; used 2 times

- in line 365, 371

xpdump defined in line 953; never used
xpecc defined in line 799; used 3 times

- in line 689, 722, 751

xpgetinfo defined in line 356; used 2 times

- in line 102, 236

xpintr defined in line 667; used 1 times

- in /usr/src/sys/pdp/scb.s line 360

xpioctl defined in line 933; never used
xpopen defined in line 208; used 1 times

- in line 1058

xproot defined in line 120; never used
xpsize defined in line 1042; used 2 times

- in line 103, 978

xpslave defined in line 174; used 1 times

- in line 162

xpstart defined in line 563; used 2 times

- in line 418, 789

xpstrategy defined in line 385; used 3 times

- in line 101, 366, 942

xpustart defined in line 436; used 3 times

- in line 416, 776, 788

#### Defined variables

bxpbuf defined in line 94; used 1 times

- in line 484

xp_controller defined in line 86; used 2 times

- in line 142, 678

xp_dkn defined in line 98; used 12 times

- in line 146-147(2), 253-254(2), 452-453(2), 538-539(2), 653-654(2), 694-695(2)

xp_drive defined in line 87; used 15 times

- in line 194, 219, 278, 395, 446, 590, 601, 698, 778, 786-787(2), 821, 940, 965, 1050

xp_offset defined in line 50; used 1 times

- in line 626

xpbad defined in line 93; used 2 times

- in line 488, 890

xptab defined in line 89; never used
xputab defined in line 90; used 5 times

- in line 291-292(2), 411, 456, 589

#### Defined struct's

xp_controller defined in line 57; used 12 times

- in line 66(2), 86(2), 142(2), 176(2), 564(2), 672(2)

xp_drive defined in line 65; used 26 times

- in line 87(2), 178(2), 212(2), 275(2), 302(2), 358(2), 388(2), 439(2), 568(2), 673(2), 803(2), 956(2), 1046(2)

#### Defined macros

DBSIZE defined in line 951; used 1 times

- in line 999

XPUNIT defined in line 48; used 11 times

- in line 213, 276, 370, 394, 600, 654, 692, 820, 940, 964, 1050

XP_RDIST defined in line 36; used 1 times

- in line 526

XP_SDIST defined in line 35; used 2 times

- in line 515, 523

exadr defined in line 792; used 2 times

- in line 839, 881

xp_bopen defined in line 79; used 3 times

- in line 262, 283-286(2)

xp_copen defined in line 80; used 3 times

- in line 260, 281-286(2)

xp_flags defined in line 82; used 14 times

- in line 203, 220, 226, 235-237(2), 289-293(2), 397, 469-472(2), 505, 615, 623, 969

xp_label defined in line 83; used 4 times

- in line 202, 246, 258, 373

xp_open defined in line 81; used 7 times

- in line 233, 258, 265, 286-287(2), 591, 1056

xp_parts defined in line 84; used 6 times

- in line 338, 376, 409, 603, 972, 1062

Last modified: 1998-04-04 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 2435 |