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

Defined functions

xpattach defined in line 87; used 1 times
  • in line 76
xpdump defined in line 700; never used
xpecc defined in line 578; used 1 times
xpintr defined in line 450; never used
xpread defined in line 556; never used
xproot defined in line 69; never used
xpslave defined in line 123; used 1 times
xpstart defined in line 361; used 2 times
xpstrategy defined in line 204; used 3 times
xpustart defined in line 260; used 3 times
xpwrite defined in line 562; never used

Defined variables

rxpbuf defined in line 57; used 2 times
xp_controller defined in line 54; used 4 times
xp_drive defined in line 53; used 10 times
xp_offset defined in line 39; used 1 times
xptab defined in line 56; never used
xputab defined in line 58; used 2 times

Defined macros

DBSIZE defined in line 697; used 3 times
XP_RDIST defined in line 37; used 1 times
XP_SDIST defined in line 36; used 2 times
exadr defined in line 570; used 2 times
Last modified: 1984-02-19
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1875
Valid CSS Valid XHTML 1.0 Strict