1: /*
   2:  *	SCCS id	@(#)xp.c	2.1 (Berkeley)	8/23/83
   3:  *	This driver has been modified to perform bad-sector forwarding.
   4:  *	It has not been tested after that modification.
   5:  *	If you want to use it, install it instead of the normal xp driver,
   6:  *	AND TEST BOTH BAD-SECTOR FORWARDING AND ECC CORRECTION.
   7:  *	Also, if you are using XP_PROBE (xpslave determines drive type),
   8:  *	you will have to force the selection of the number of cylinders for RP's
   9:  *	to RP06_CYL or RP04_CYL, assuming that you have only one or the other,
  10:  *	or else punt.
  11:  */
  12: #define HP_CYL  RP06_CYL
  13: 
  14: /*
  15:  *	RM02/03/05, RP04/05/06, DIVA disk driver.
  16:  *	SI Eagle added 9/20/83.
  17:  *	This driver will handle most variants of SMD drives
  18:  *	on one or more controllers.
  19:  *	If XP_PROBE is defined, it includes a probe routine
  20:  *	that will determine the number and type of drives attached
  21:  *	to each controller; otherwise, the data structures must be
  22:  *	initialized.
  23:  *
  24:  *	For simplicity we use hpreg.h instead of an xpreg.h.  The bits
  25:  *	are the same.
  26:  */
  27: 
  28: #include "xp.h"
  29: #if NXP > 0
  30: #include "param.h"
  31: #include <sys/systm.h>
  32: #include <sys/buf.h>
  33: #include <sys/conf.h>
  34: #include <sys/dir.h>
  35: #include <sys/user.h>
  36: #include <sys/seg.h>
  37: #include <sys/hpreg.h>
  38: #ifndef INTRLVE
  39: #include <sys/inline.h>
  40: #endif
  41: #ifdef  UNIBUS_MAP
  42: #include <sys/uba.h>
  43: #endif
  44: #include <sys/dkbad.h>
  45: 
  46: #define XP_SDIST    2
  47: #define XP_RDIST    6
  48: 
  49: int xp_offset[] =
  50: {
  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: /*
  58:  *  Xp_drive and xp_controller may be initialized in ioconf.c,
  59:  *  or they may be filled in at boot time if XP_PROBE is enabled.
  60:  *  Xp_controller address fields must be initialized for any boot devices,
  61:  *  however.
  62:  */
  63: struct  xp_drive xp_drive[NXP];
  64: struct  xp_controller xp_controller[NXP_CONTROLLER];
  65: 
  66: struct  buf xptab;
  67: struct  buf rxpbuf[NXP];
  68: struct  buf xputab[NXP];
  69: #ifdef BADSECT
  70: struct  dkbad   xpbad[NXP];
  71: struct  buf bxpbuf[NXP];
  72: bool_t  xp_init[NXP];
  73: #endif
  74: 
  75: #ifdef  INTRLVE
  76: extern  daddr_t dkblock();
  77: #endif
  78: 
  79: /*
  80:  *  Attach controllers whose addresses are known at boot time.
  81:  *  Stop at the first not found, so that the drive numbering
  82:  *  won't get confused.
  83:  */
  84: xproot()
  85: {
  86:     register i;
  87:     register struct hpdevice *xpaddr;
  88: 
  89:     for (i = 0; i < NXP_CONTROLLER; i++)
  90:         if (((xpaddr = xp_controller[i].xp_addr) == 0)
  91:             || (xpattach(xpaddr, i) == 0))
  92:             break;
  93: }
  94: 
  95: /*
  96:  *  Attach controller at xpaddr.
  97:  *  Mark as nonexistent if xpaddr is 0;
  98:  *  otherwise attach slaves if probing.
  99:  *  NOTE: if probing for drives, this routine must be called
 100:  *  once per controller, in ascending controller numbers.
 101:  */
 102: xpattach(xpaddr, unit)
 103: register struct hpdevice *xpaddr;
 104: {
 105:     register struct xp_controller *xc = &xp_controller[unit];
 106: #ifdef  XP_PROBE
 107:     static int last_attached = -1;
 108: #endif
 109: 
 110:     if ((unsigned) unit >= NXP_CONTROLLER)
 111:         return(0);
 112:     if ((xpaddr != 0) && (fioword(xpaddr) != -1)) {
 113:         xc->xp_addr = xpaddr;
 114: #if PDP11 == 70 || PDP11 == GENERIC
 115:         if (fioword(&(xpaddr->hpbae)) != -1)
 116:             xc->xp_flags |= XP_RH70;
 117: #endif
 118: #ifdef  XP_PROBE
 119:         /*
 120: 		 *  If already attached, ignore (don't want to renumber drives)
 121: 		 */
 122:         if (unit > last_attached) {
 123:             last_attached = unit;
 124:             xpslave(xpaddr, xc);
 125:         }
 126: #endif
 127:         return(1);
 128:     }
 129:     xc->xp_addr = 0;
 130:     return(0);
 131: }
 132: 
 133: #ifdef  XP_PROBE
 134: /*
 135:  *  Determine what drives are attached to a controller;
 136:  *  guess their types and fill in the drive structures.
 137:  */
 138: xpslave(xpaddr, xc)
 139: register struct hpdevice *xpaddr;
 140: struct xp_controller *xc;
 141: {
 142:     register struct xp_drive *xd;
 143:     int j,  dummy;
 144:     static int nxp = 0;
 145:     extern  struct size dv_sizes[], hp_sizes[], rm_sizes[], rm5_sizes[], si_sizes[];
 146: 
 147:     for (j = 0; j < 8; j++) {
 148:         xpaddr->hpcs1.w = 0;
 149:         xpaddr->hpcs2.w = j;
 150:         dummy = xpaddr->hpds;
 151:         if (xpaddr->hpcs2.w & HPCS2_NED) {
 152:             xpaddr->hpcs2.w = HPCS2_CLR;
 153:             continue;
 154:         }
 155:         if (nxp < NXP) {
 156:             xd = &xp_drive[nxp++];
 157:             xd->xp_ctlr = xc;
 158:             xd->xp_unit = j;
 159:             /*
 160: 			 * If drive type is initialized,
 161: 			 * believe it.
 162: 			 */
 163:             if (xd->xp_type == 0)
 164:                 xd->xp_type = xpaddr->hpdt & 077;
 165:             switch (xd->xp_type) {
 166: 
 167:             case RM02:
 168:             case RM03:
 169:                 xd->xp_nsect = RM_SECT;
 170:                 xd->xp_ntrack = RM_TRAC;
 171:                 xd->xp_nspc = RM_SECT * RM_TRAC;
 172:                 xd->xp_ncyl = RM_CYL;
 173:                 xd->xp_sizes = &rm_sizes;
 174:                 xd->xp_ctlr->xp_flags |= XP_NOCC;
 175:                 break;
 176: 
 177:             case RM5X:
 178:                 xd->xp_ncyl = RM5X_CYL;
 179:                 goto rm5;
 180:             case RM05:
 181:                 xd->xp_ncyl = RM5_CYL;
 182:             rm5:
 183:                 if ((xpaddr->hpsn & SI_SN_MSK) == SI_SN_DT) {
 184:                     xd->xp_nsect = SI_SECT;
 185:                     xd->xp_ntrack = SI_TRAC;
 186:                     xd->xp_ncyl = SI_CYL;
 187:                     xd->xp_nspc = SI_SECT * SI_TRAC;
 188:                     xd->xp_sizes = &si_sizes;
 189:                     xd->xp_ctlr->xp_flags |= XP_NOCC;
 190:                 } else {
 191:                     xd->xp_nsect = RM5_SECT;
 192:                     xd->xp_ntrack = RM5_TRAC;
 193:                     xd->xp_nspc = RM5_SECT * RM5_TRAC;
 194:                     xd->xp_sizes = &rm5_sizes;
 195:                     xd->xp_ctlr->xp_flags |= XP_NOCC;
 196:                 }
 197:                 break;
 198: 
 199:             case RP:
 200:                 xd->xp_nsect = HP_SECT;
 201:                 xd->xp_ntrack = HP_TRAC;
 202:                 xd->xp_nspc = HP_SECT * HP_TRAC;
 203:                 xd->xp_ncyl = HP_CYL;
 204:                 xd->xp_sizes = &hp_sizes;
 205:                 break;
 206: 
 207:             case DV:
 208:                 xd->xp_nsect = DV_SECT;
 209:                 xd->xp_ntrack = DV_TRAC;
 210:                 xd->xp_nspc = DV_SECT * DV_TRAC;
 211:                 xd->xp_ncyl = DV_CYL;
 212:                 xd->xp_sizes = &dv_sizes;
 213:                 xd->xp_ctlr->xp_flags |= XP_NOSEARCH;
 214:                 break;
 215: 
 216:             default:
 217:                 printf("xp%d: drive type %o unrecognized\n",
 218:                 nxp - 1, xd->xp_type);
 219:                 xd->xp_ctlr = NULL;
 220:                 break;
 221:             }
 222:         }
 223:     }
 224: }
 225: #endif	XP_PROBE
 226: 
 227: xpstrategy(bp)
 228: register struct buf *bp;
 229: {
 230:     register struct xp_drive *xd;
 231:     register unit;
 232:     struct buf *dp;
 233:     short   pseudo_unit;
 234:     int s;
 235:     long    bn;
 236: 
 237:     unit = dkunit(bp);
 238:     pseudo_unit = minor(bp->b_dev) & 07;
 239: 
 240:     if ((unit >= NXP) || ((xd = &xp_drive[unit])->xp_ctlr == 0) ||
 241:        (xd->xp_ctlr->xp_addr == 0)) {
 242:         bp->b_error = ENXIO;
 243:         goto errexit;
 244:     }
 245:     if ((bp->b_blkno < 0) ||
 246:        ((bn = dkblock(bp)) + ((bp->b_bcount + 511) >> 9)
 247:          > xd->xp_sizes[pseudo_unit].nblocks)) {
 248:         bp->b_error = EINVAL;
 249: errexit:
 250:         bp->b_flags |= B_ERROR;
 251:         iodone(bp);
 252:         return;
 253:     }
 254: #ifdef  UNIBUS_MAP
 255:     if ((xd->xp_ctlr->xp_flags & XP_RH70) == 0)
 256:         mapalloc(bp);
 257: #endif	UNIBUS_MAP
 258:     bp->b_cylin = bn / xd->xp_nspc
 259:         + xd->xp_sizes[pseudo_unit].cyloff;
 260:     dp = &xputab[unit];
 261:     s = spl5();
 262:     disksort(dp, bp);
 263:     if (dp->b_active == 0) {
 264:         xpustart(unit);
 265:         if (xd->xp_ctlr->xp_active == 0)
 266:             xpstart(xd->xp_ctlr);
 267:     }
 268:     splx(s);
 269: }
 270: 
 271: /*
 272:  * Unit start routine.
 273:  * Seek the drive to where the data are
 274:  * and then generate another interrupt
 275:  * to actually start the transfer.
 276:  * If there is only one drive
 277:  * or we are very close to the data, don't
 278:  * bother with the search.  If called after
 279:  * searching once, don't bother to look
 280:  * where we are, just queue for transfer (to avoid
 281:  * positioning forever without transferring).
 282:  */
 283: xpustart(unit)
 284: int unit;
 285: {
 286:     register struct xp_drive *xd;
 287:     register struct hpdevice *xpaddr;
 288:     register struct buf *dp;
 289:     struct  buf *bp;
 290:     daddr_t bn;
 291:     int sn, cn, csn;
 292: 
 293:     xd = &xp_drive[unit];
 294:     xpaddr = xd->xp_ctlr->xp_addr;
 295:     xpaddr->hpcs2.w = xd->xp_unit;
 296:     xpaddr->hpcs1.c[0] = HP_IE;
 297:     xpaddr->hpas = 1 << xd->xp_unit;
 298: 
 299:     if (unit >= NXP)
 300:         return;
 301: #ifdef  XP_DKN
 302:     dk_busy &= ~(1 << (unit + XP_DKN));
 303: #endif
 304:     dp = &xputab[unit];
 305:     if ((bp=dp->b_actf) == NULL)
 306:         return;
 307:     /*
 308: 	 * If we have already positioned this drive,
 309: 	 * then just put it on the ready queue.
 310: 	 */
 311:     if (dp->b_active)
 312:         goto done;
 313:     dp->b_active++;
 314:     /*
 315: 	 * If drive has just come up,
 316: 	 * set up the pack.
 317: 	 */
 318: #ifdef BADSECT
 319:     if (((xpaddr->hpds & HPDS_VV) == 0) || (xp_init[unit] == 0))
 320: #else
 321:     if ((xpaddr->hpds & HPDS_VV) == 0)
 322: #endif
 323:     {
 324: #ifdef BADSECT
 325:         struct buf *bbp = &bxpbuf[unit];
 326: #endif
 327:         /* SHOULD WARN SYSTEM THAT THIS HAPPENED */
 328:         xpaddr->hpcs1.c[0] = HP_IE | HP_PRESET | HP_GO;
 329:         xpaddr->hpof = HPOF_FMT22;
 330: #ifdef BADSECT
 331:         xp_init[unit] = 1;
 332:         bbp->b_flags = B_READ | B_BUSY | B_PHYS;
 333:         bbp->b_dev = bp->b_dev;
 334:         bbp->b_bcount = sizeof(struct dkbad);
 335:         bbp->b_un.b_addr = (caddr_t)&xpbad[unit];
 336:         bbp->b_blkno = (daddr_t)xd->xp_ncyl*xd->xp_nspc - xd->xp_nsect;
 337:         bbp->b_cylin = xd->xp_ncyl - 1;
 338: #ifdef  UNIBUS_MAP
 339:         if ((xd->xp_ctlr->xp_flags & XP_RH70) == 0)
 340:             mapalloc(bbp);
 341: #endif	UNIBUS_MAP
 342:         dp->b_actf = bbp;
 343:         bbp->av_forw = bp;
 344:         bp = bbp;
 345: #endif	BADSECT
 346:     }
 347: #if NXP > 1
 348:     /*
 349: 	 * If drive is offline, forget about positioning.
 350: 	 */
 351:     if ((xpaddr->hpds & (HPDS_DPR | HPDS_MOL)) != (HPDS_DPR | HPDS_MOL))
 352:         goto done;
 353: 
 354:     /*
 355: 	 * Figure out where this transfer is going to
 356: 	 * and see if we are close enough to justify not searching.
 357: 	 */
 358:     bn = dkblock(bp);
 359:     cn = bp->b_cylin;
 360:     sn = bn % xd->xp_nspc;
 361:     sn += xd->xp_nsect - XP_SDIST;
 362:     sn %= xd->xp_nsect;
 363: 
 364:     if (((xd->xp_ctlr->xp_flags & XP_NOCC) && (xd->xp_cc != cn))
 365:         || xpaddr->hpcc != cn)
 366:         goto search;
 367:     if (xd->xp_ctlr->xp_flags & XP_NOSEARCH)
 368:         goto done;
 369:     csn = (xpaddr->hpla >> 6) - sn + XP_SDIST - 1;
 370:     if (csn < 0)
 371:         csn += xd->xp_nsect;
 372:     if (csn > xd->xp_nsect - XP_RDIST)
 373:         goto done;
 374: 
 375: search:
 376:     xpaddr->hpdc = cn;
 377:     xpaddr->hpda = sn;
 378:     xpaddr->hpcs1.c[0] = (xd->xp_ctlr->xp_flags & XP_NOSEARCH)?
 379:         (HP_IE | HP_SEEK | HP_GO) : (HP_IE | HP_SEARCH | HP_GO);
 380:     xd->xp_cc = cn;
 381: #ifdef  XP_DKN
 382:     /*
 383: 	 * Mark unit busy for iostat.
 384: 	 */
 385:     unit += XP_DKN;
 386:     dk_busy |= 1 << unit;
 387:     dk_numb[unit]++;
 388: #endif	XP_DKN
 389:     return;
 390: #endif	NXP > 1
 391: 
 392: done:
 393:     /*
 394: 	 * Device is ready to go.
 395: 	 * Put it on the ready queue for the controller.
 396: 	 */
 397:     dp->b_forw = NULL;
 398:     if (xd->xp_ctlr->xp_actf == NULL)
 399:         xd->xp_ctlr->xp_actf = dp;
 400:     else
 401:         xd->xp_ctlr->xp_actl->b_forw = dp;
 402:     xd->xp_ctlr->xp_actl = dp;
 403: }
 404: 
 405: /*
 406:  * Start up a transfer on a controller.
 407:  */
 408: xpstart(xc)
 409: register struct xp_controller *xc;
 410: {
 411:     register struct hpdevice *xpaddr;
 412:     register struct buf *bp;
 413:     struct xp_drive *xd;
 414:     struct  buf *dp;
 415:     int unit;
 416:     short   pseudo_unit;
 417:     daddr_t bn;
 418:     int sn, tn, cn;
 419: 
 420:     xpaddr = xc->xp_addr;
 421: loop:
 422:     /*
 423: 	 * Pull a request off the controller queue.
 424: 	 */
 425:     if ((dp = xc->xp_actf) == NULL)
 426:         return;
 427:     if ((bp = dp->b_actf) == NULL) {
 428:         xc->xp_actf = dp->b_forw;
 429:         goto loop;
 430:     }
 431:     /*
 432: 	 * Mark controller busy and
 433: 	 * determine destination of this request.
 434: 	 */
 435:     xc->xp_active++;
 436:     pseudo_unit = minor(bp->b_dev) & 07;
 437:     unit = dkunit(bp);
 438:     xd = &xp_drive[unit];
 439:     bn = dkblock(bp);
 440:     cn = bp->b_cylin;
 441:     sn = bn % xd->xp_nspc;
 442:     tn = sn / xd->xp_nsect;
 443:     sn = sn % xd->xp_nsect;
 444: 
 445:     /*
 446: 	 * Select drive.
 447: 	 */
 448:     xpaddr->hpcs2.w = xd->xp_unit;
 449:     /*
 450: 	 * Check that it is ready and online.
 451: 	 */
 452:     if ((xpaddr->hpds & (HPDS_DPR | HPDS_MOL)) != (HPDS_DPR | HPDS_MOL)) {
 453:         xc->xp_active = 0;
 454:         dp->b_errcnt = 0;
 455:         dp->b_actf = bp->av_forw;
 456:         bp->b_flags |= B_ERROR;
 457:         iodone(bp);
 458:         goto loop;
 459:     }
 460:     if (dp->b_errcnt >= 16 && (bp->b_flags & B_READ)) {
 461:         xpaddr->hpof = xp_offset[dp->b_errcnt & 017] | HPOF_FMT22;
 462:         xpaddr->hpcs1.w = HP_OFFSET | HP_GO;
 463:         while ((xpaddr->hpds & (HPDS_PIP | HPDS_DRY)) != HPDS_DRY)
 464:             ;
 465:     }
 466:     xpaddr->hpdc = cn;
 467:     xpaddr->hpda = (tn << 8) + sn;
 468:     xpaddr->hpba = bp->b_un.b_addr;
 469: #if PDP11 == 70 || PDP11 == GENERIC
 470:     if (xc->xp_flags & XP_RH70)
 471:         xpaddr->hpbae = bp->b_xmem;
 472: #endif
 473:     xpaddr->hpwc = -(bp->b_bcount >> 1);
 474: 
 475:     /*
 476: 	 * Warning:  unit is being used as a temporary.
 477: 	 */
 478:     unit = ((bp->b_xmem & 3) << 8) | HP_IE | HP_GO;
 479: #ifdef  XP_FORMAT
 480:     if (minor(bp->b_dev) & 0200)
 481:         unit |= bp->b_flags & B_READ? HP_RHDR : HP_WHDR;
 482:     else
 483:         unit |= bp->b_flags & B_READ? HP_RCOM : HP_WCOM;
 484: #else
 485:     if (bp->b_flags & B_READ)
 486:         unit |= HP_RCOM;
 487:     else
 488:         unit |= HP_WCOM;
 489: #endif
 490:     xpaddr->hpcs1.w = unit;
 491: 
 492: #ifdef  XP_DKN
 493:     unit = xc - &xp_controller[0] + XP_DKN + NXP;
 494:     dk_busy |= 1 << unit;
 495:     dk_numb[unit]++;
 496:     dk_wds[unit] += bp->b_bcount >> 6;
 497: #endif
 498: }
 499: 
 500: /*
 501:  * Handle a disk interrupt.
 502:  */
 503: xpintr(dev)
 504: int dev;
 505: {
 506:     register struct hpdevice *xpaddr;
 507:     register struct buf *dp;
 508:     struct xp_controller *xc;
 509:     struct xp_drive *xd;
 510:     struct  buf *bp;
 511:     register unit;
 512:     int as, i, j;
 513: 
 514:     xc = &xp_controller[dev];
 515:     xpaddr = xc->xp_addr;
 516:     as = xpaddr->hpas & 0377;
 517:     if (xc->xp_active) {
 518: #ifdef  XP_DKN
 519:         dk_busy &= ~(1 << (dev + XP_DKN + NXP));
 520: #endif
 521:         /*
 522: 		 * Get device and block structures.  Select the drive.
 523: 		 */
 524:         dp = xc->xp_actf;
 525:         bp = dp->b_actf;
 526: #ifdef BADSECT
 527:         if (bp->b_flags&B_BAD)
 528:             if (xpecc(bp, CONT))
 529:                 return;
 530: #endif
 531:         unit = dkunit(bp);
 532:         xd = &xp_drive[unit];
 533:         xpaddr->hpcs2.c[0] = xd->xp_unit;
 534:         /*
 535: 		 * Check for and process errors.
 536: 		 */
 537:         if (xpaddr->hpcs1.w & HP_TRE) {
 538:             while ((xpaddr->hpds & HPDS_DRY) == 0)
 539:                 ;
 540:             if (xpaddr->hper1 & HPER1_WLE) {
 541:                 /*
 542: 				 *	Give up on write locked deviced
 543: 				 *	immediately.
 544: 				 */
 545:                 printf("xp%d: write locked\n", unit);
 546:                 bp->b_flags |= B_ERROR;
 547: #ifdef  BADSECT
 548:             } else if ((xpaddr->rmer2 & RMER2_BSE)
 549:                 || (xpaddr->hper1 & HPER1_FER)) {
 550: #ifdef  XP_FORMAT
 551:                 /*
 552: 				 * Allow this error on format devices.
 553: 				 */
 554:                 if (minor(bp->b_dev) & 0200)
 555:                     goto errdone;
 556: #endif
 557:                 if (xpecc(bp, BSE))
 558:                     return;
 559:                 else
 560:                     goto hard;
 561: #endif	BADSECT
 562:             } else {
 563:                 /*
 564: 				 * After 28 retries (16 without offset and
 565: 				 * 12 with offset positioning), give up.
 566: 				 */
 567:                 if (++dp->b_errcnt > 28) {
 568: hard:
 569: #ifdef  UCB_DEVERR
 570:                     harderr(bp, "xp");
 571:                     printf("cs2=%b er1=%b\n", xpaddr->hpcs2.w,
 572:                     HPCS2_BITS, xpaddr->hper1, HPER1_BITS);
 573: #else
 574:                     deverror(bp, xpaddr->hpcs2.w, xpaddr->hper1);
 575: #endif
 576:                     bp->b_flags |= B_ERROR;
 577:                 } else
 578:                     xc->xp_active = 0;
 579:             }
 580: #ifdef UCB_ECC
 581:             /*
 582: 			 * If soft ecc, correct it (continuing
 583: 			 * by returning if necessary).
 584: 			 * Otherwise, fall through and retry the transfer.
 585: 			 */
 586:             if((xpaddr->hper1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK)
 587:                 if (xpecc(bp, ECC))
 588:                     return;
 589: #endif
 590: errdone:
 591:             xpaddr->hpcs1.w = HP_TRE | HP_IE | HP_DCLR | HP_GO;
 592:             if ((dp->b_errcnt & 07) == 4) {
 593:                 xpaddr->hpcs1.w = HP_RECAL | HP_IE | HP_GO;
 594:                 while ((xpaddr->hpds & (HPDS_PIP | HPDS_DRY)) != HPDS_DRY)
 595:                     ;
 596:             }
 597:             xd->xp_cc = -1;
 598:         }
 599:         if (xc->xp_active) {
 600:             if (dp->b_errcnt) {
 601:                 xpaddr->hpcs1.w = HP_RTC | HP_GO;
 602:                 while ((xpaddr->hpds & (HPDS_PIP | HPDS_DRY)) != HPDS_DRY)
 603:                     ;
 604:             }
 605:             xc->xp_active = 0;
 606:             xc->xp_actf = dp->b_forw;
 607:             dp->b_active = 0;
 608:             dp->b_errcnt = 0;
 609:             dp->b_actf = bp->b_actf;
 610:             xd->xp_cc = bp->b_cylin;
 611:             bp->b_resid = - (xpaddr->hpwc << 1);
 612:             iodone(bp);
 613:             xpaddr->hpcs1.w = HP_IE;
 614:             if (dp->b_actf)
 615:                 xpustart(unit);
 616:         }
 617:         as &= ~(1 << xp_drive[unit].xp_unit);
 618:     } else
 619:         {
 620:         if (as == 0)
 621:             xpaddr->hpcs1.w = HP_IE;
 622:         xpaddr->hpcs1.c[1] = HP_TRE >> 8;
 623:     }
 624:     for (unit = 0; unit < NXP; unit++)
 625:         if ((xp_drive[unit].xp_ctlr == xc) &&
 626:             (as & (1 << xp_drive[unit].xp_unit)))
 627:                 xpustart(unit);
 628:     xpstart(xc);
 629: }
 630: 
 631: xpread(dev)
 632: dev_t   dev;
 633: {
 634:     physio(xpstrategy, &rxpbuf[(minor(dev) >> 3) & 07], dev, B_READ);
 635: }
 636: 
 637: xpwrite(dev)
 638: dev_t   dev;
 639: {
 640:     physio(xpstrategy, &rxpbuf[(minor(dev) >> 3) & 07], dev, B_WRITE);
 641: }
 642: 
 643: 
 644: #ifdef  UCB_ECC
 645: #define exadr(x,y)  (((long)(x) << 16) | (unsigned)(y))
 646: 
 647: /*
 648:  * Correct an ECC error and restart the i/o to complete
 649:  * the transfer if necessary.  This is quite complicated because
 650:  * the correction may be going to an odd memory address base
 651:  * and the transfer may cross a sector boundary.
 652:  */
 653: xpecc(bp, flag)
 654: register struct buf *bp;
 655: {
 656:     register struct xp_drive *xd;
 657:     register struct hpdevice *xpaddr;
 658:     register unsigned byte;
 659:     ubadr_t bb, addr;
 660:     long    wrong;
 661:     int bit, wc;
 662:     unsigned ndone, npx;
 663:     int ocmd;
 664:     int cn, tn, sn;
 665:     daddr_t bn;
 666: #ifdef  UNIBUS_MAP
 667:     struct  ubmap *ubp;
 668: #endif
 669:     int unit;
 670: 
 671:     /*
 672: 	 *	ndone is #bytes including the error
 673: 	 *	which is assumed to be in the last disk page transferred.
 674: 	 */
 675:     unit = dkunit(bp);
 676:     xd = &xp_drive[unit];
 677:     xpaddr = xd->xp_ctlr->xp_addr;
 678: #ifdef  BADSECT
 679:     if (flag == CONT) {
 680:         npx = bp->b_error;
 681:         bp->b_error = 0;
 682:         ndone = npx * PGSIZE;
 683:         wc = ((int)(ndone - bp->b_bcount)) / NBPW;
 684:     } else
 685: #endif
 686:     {
 687:         wc = xpaddr->hpwc;
 688:         ndone = (wc * NBPW) + bp->b_bcount;
 689:         npx = ndone / PGSIZE;
 690:     }
 691:     ocmd = (xpaddr->hpcs1.w & ~HP_DRY) | HP_IE | HP_GO;
 692:     bb = exadr(bp->b_xmem, bp->b_un.b_addr);
 693:     bn = dkblock(bp);
 694:     cn = bp->b_cylin - (bn / xd->xp_nspc);
 695:     bn += npx;
 696:     cn += bn / xd->xp_nspc;
 697:     sn = bn % xd->xp_nspc;
 698: /*	tn = sn / xd->xp_nsect;  /* CC complains about this ??? */
 699:     tn = sn;
 700:     tn /= xd->xp_nsect;
 701:     sn %= xd->xp_nsect;
 702: 
 703:     switch (flag) {
 704:     case ECC:
 705:         printf("xp%d%c: soft ecc bn %D\n",
 706:             unit, 'a' + (minor(bp->b_dev) & 07),
 707:             bp->b_blkno + (npx - 1));
 708:         wrong = xpaddr->hpec2;
 709:         if (wrong == 0) {
 710:             xpaddr->hpof = HPOF_FMT22;
 711:             xpaddr->hpcs1.w |= HP_IE;
 712:             return (0);
 713:         }
 714: 
 715:         /*
 716: 		 *	Compute the byte/bit position of the err
 717: 		 *	within the last disk page transferred.
 718: 		 *	Hpec1 is origin-1.
 719: 		 */
 720:         byte = xpaddr->hpec1 - 1;
 721:         bit = byte & 07;
 722:         byte >>= 3;
 723:         byte += ndone - PGSIZE;
 724:         wrong <<= bit;
 725: 
 726:         /*
 727: 		 *	Correct until mask is zero or until end of transfer,
 728: 		 *	whichever comes first.
 729: 		 */
 730:         while (byte < bp->b_bcount && wrong != 0) {
 731:             addr = bb + byte;
 732: #ifdef  UNIBUS_MAP
 733:             if (bp->b_flags & (B_MAP|B_UBAREMAP)) {
 734:                 /*
 735: 				 * Simulate UNIBUS map if UNIBUS transfer.
 736: 				 */
 737:                 ubp = UBMAP + ((addr >> 13) & 037);
 738:                 addr = exadr(ubp->ub_hi, ubp->ub_lo)
 739:                     + (addr & 017777);
 740:             }
 741: #endif
 742:             putmemc(addr, getmemc(addr) ^ (int) wrong);
 743:             byte++;
 744:             wrong >>= 8;
 745:         }
 746:         break;
 747: #ifdef BADSECT
 748:     case BSE:
 749:         if ((bn = isbad(&xpbad[unit], cn, tn, sn)) < 0)
 750:             return(0);
 751:         bp->b_flags |= B_BAD;
 752:         bp->b_error = npx + 1;
 753:         bn = (daddr_t)xd->xp_ncyl * xd->xp_nspc - xd->xp_nsect - 1 - bn;
 754:         cn = bn/xd->xp_nspc;
 755:         sn = bn%xd->xp_nspc;
 756:     /*	tn = sn/xd->xp_nsect; /* CC can't hack this */
 757:         tn = sn;
 758:         tn /= xd->xp_nsect;
 759:         sn %= xd->xp_nsect;
 760: #ifdef DEBUG
 761:         printf("revector to cn %d tn %d sn %d\n", cn, tn, sn);
 762: #endif
 763:         wc = -(512 / NBPW);
 764:         break;
 765: 
 766:     case CONT:
 767:         bp->b_flags &= ~B_BAD;
 768: #ifdef DEBUG
 769:         printf("xpecc CONT: bn %D cn %d tn %d sn %d\n", bn, cn, tn, sn);
 770: #endif
 771:         break;
 772: #endif	BADSECT
 773:     }
 774: 
 775:     xd->xp_ctlr->xp_active++;
 776:     if (wc == 0)
 777:         return (0);
 778: 
 779:     /*
 780: 	 * Have to continue the transfer.  Clear the drive
 781: 	 * and compute the position where the transfer is to continue.
 782: 	 * We have completed npx sectors of the transfer already.
 783: 	 */
 784:     xpaddr->hpcs2.w = xd->xp_unit;
 785:     xpaddr->hpcs1.w = HP_TRE | HP_DCLR | HP_GO;
 786: 
 787:     addr = bb + ndone;
 788:     xpaddr->hpdc = cn;
 789:     xpaddr->hpda = (tn << 8) + sn;
 790:     xpaddr->hpwc = wc;
 791:     xpaddr->hpba = (int) addr;
 792: #if PDP11 == 70 || PDP11 == GENERIC
 793:     if (xd->xp_ctlr->xp_flags & XP_RH70)
 794:         xpaddr->hpbae = (int) (addr >> 16);
 795: #endif
 796:     xpaddr->hpcs1.w = ocmd;
 797:     return (1);
 798: }
 799: #endif	UCB_ECC
 800: 
 801: #if defined(XP_DUMP) && defined(UCB_AUTOBOOT)
 802: /*
 803:  *  Dump routine.
 804:  *  Dumps from dumplo to end of memory/end of disk section for minor(dev).
 805:  *  It uses the UNIBUS map to dump all of memory if there is a UNIBUS map
 806:  *  and this isn't an RH70.  This depends on UNIBUS_MAP being defined.
 807:  */
 808: 
 809: #ifdef  UNIBUS_MAP
 810: #define DBSIZE  (UBPAGE/PGSIZE)     /* unit of transfer, one UBPAGE */
 811: #else
 812: #define DBSIZE  16          /* unit of transfer, same number */
 813: #endif
 814: 
 815: xpdump(dev)
 816: dev_t dev;
 817: {
 818:     /* ONLY USE 2 REGISTER VARIABLES, OR C COMPILER CHOKES */
 819:     register struct xp_drive *xd;
 820:     register struct hpdevice *xpaddr;
 821:     daddr_t bn, dumpsize;
 822:     long    paddr;
 823:     int sn, count;
 824: #ifdef  UNIBUS_MAP
 825:     extern  bool_t ubmap;
 826:     struct ubmap *ubp;
 827: #endif
 828: 
 829:     if ((bdevsw[major(dev)].d_strategy != xpstrategy)   /* paranoia */
 830:         || ((dev=minor(dev)) > (NXP << 3)))
 831:         return(EINVAL);
 832:     xd = &xp_drive[dev >> 3];
 833:     dev &= 07;
 834:     if (xd->xp_ctlr == 0)
 835:         return(EINVAL);
 836:     xpaddr = xd->xp_ctlr->xp_addr;
 837:     dumpsize = xd->xp_sizes[dev].nblocks;
 838:     if ((dumplo < 0) || (dumplo >= dumpsize))
 839:         return(EINVAL);
 840:     dumpsize -= dumplo;
 841: 
 842:     xpaddr->hpcs2.w = xd->xp_unit;
 843:     if ((xpaddr->hpds & HPDS_VV) == 0) {
 844:         xpaddr->hpcs1.w = HP_DCLR | HP_GO;
 845:         xpaddr->hpcs1.w = HP_PRESET | HP_GO;
 846:         xpaddr->hpof = HPOF_FMT22;
 847:     }
 848:     if ((xpaddr->hpds & (HPDS_DPR | HPDS_MOL)) != (HPDS_DPR | HPDS_MOL))
 849:         return(EFAULT);
 850: #ifdef  UNIBUS_MAP
 851:     ubp = &UBMAP[0];
 852: #endif
 853:     for (paddr = 0L; dumpsize > 0; dumpsize -= count) {
 854:         count = dumpsize>DBSIZE? DBSIZE: dumpsize;
 855:         bn = dumplo + (paddr >> PGSHIFT);
 856:         xpaddr->hpdc = bn / xd->xp_nspc
 857:             + xd->xp_sizes[dev].cyloff;
 858:         sn = bn % xd->xp_nspc;
 859:         xpaddr->hpda = ((sn / xd->xp_nsect) << 8) | (sn % xd->xp_nsect);
 860:         xpaddr->hpwc = -(count << (PGSHIFT - 1));
 861: #ifdef  UNIBUS_MAP
 862:         /*
 863: 		 *  If UNIBUS_MAP exists, use
 864: 		 *  the map, unless on an 11/70 with RH70.
 865: 		 */
 866:         if (ubmap && ((xd->xp_ctlr->xp_flags & XP_RH70) == 0)) {
 867:             ubp->ub_lo = loint(paddr);
 868:             ubp->ub_hi = hiint(paddr);
 869:             xpaddr->hpba = 0;
 870:             xpaddr->hpcs1.w = HP_WCOM | HP_GO;
 871:         }
 872:         else
 873: #endif
 874:             {
 875:             /*
 876: 			 *  Non-UNIBUS map, or 11/70 RH70 (MASSBUS)
 877: 			 */
 878:             xpaddr->hpba = loint(paddr);
 879: #if PDP11 == 70 || PDP11 == GENERIC
 880:             if (xd->xp_ctlr->xp_flags & XP_RH70)
 881:                 xpaddr->hpbae = hiint(paddr);
 882: #endif
 883:             xpaddr->hpcs1.w = HP_WCOM | HP_GO | ((paddr >> 8) & (03 << 8));
 884:         }
 885:         while (xpaddr->hpcs1.w & HP_GO)
 886:             ;
 887:         if (xpaddr->hpcs1.w & HP_TRE) {
 888:             if (xpaddr->hpcs2.w & HPCS2_NEM)
 889:                 return(0);  /* made it to end of memory */
 890:             return(EIO);
 891:         }
 892:         paddr += (DBSIZE << PGSHIFT);
 893:     }
 894:     return(0);      /* filled disk minor dev */
 895: }
 896: #endif	XP_DUMP
 897: #endif	NXP

Defined functions

xpattach defined in line 102; used 1 times
  • in line 91
xpdump defined in line 815; never used
xpecc defined in line 653; used 3 times
xpintr defined in line 503; used 4 times
xpread defined in line 631; never used
xproot defined in line 84; never used
xpslave defined in line 138; used 1 times
xpstart defined in line 408; used 2 times
xpstrategy defined in line 227; used 3 times
xpustart defined in line 283; used 3 times
xpwrite defined in line 637; never used

Defined variables

bxpbuf defined in line 71; used 1 times
rxpbuf defined in line 67; used 2 times
xp_controller defined in line 64; used 4 times
xp_drive defined in line 63; used 10 times
xp_init defined in line 72; used 2 times
xp_offset defined in line 49; used 1 times
xpbad defined in line 70; used 2 times
xptab defined in line 66; used 2 times
xputab defined in line 68; used 2 times

Defined macros

DBSIZE defined in line 812; used 3 times
HP_CYL defined in line 12; used 1 times
XP_RDIST defined in line 47; used 1 times
XP_SDIST defined in line 46; used 2 times
exadr defined in line 645; used 2 times
Last modified: 1984-02-19
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2238
Valid CSS Valid XHTML 1.0 Strict