1: /*
   2:  *	SCCS id	@(#)dvhp.c	2.1 (Berkeley)	9/1/83
   3:  */
   4: 
   5: /*
   6:  *	Disk driver for Diva Comp V controller.
   7:  */
   8: 
   9: #include "dvhp.h"
  10: #if NDVHP > 0
  11: #include "param.h"
  12: #include <sys/systm.h>
  13: #include <sys/buf.h>
  14: #include <sys/conf.h>
  15: #include <sys/dir.h>
  16: #include <sys/user.h>
  17: #include <sys/hpreg.h>
  18: #ifndef INTRLVE
  19: #include <sys/inline.h>
  20: #endif
  21: #include <sys/uba.h>
  22: 
  23: #define DVHP_NSECT  33
  24: #define DVHP_NTRAC  19
  25: #define DVHP_SDIST  2
  26: #define DVHP_RDIST  6
  27: 
  28: extern  struct  size dvhp_sizes[];
  29: extern  struct  hpdevice *DVHPADDR;
  30: 
  31: int dvhp_offset[] =
  32: {
  33:     HPOF_P400,  HPOF_M400,  HPOF_P400,  HPOF_M400,
  34:     HPOF_P800,  HPOF_M800,  HPOF_P800,  HPOF_M800,
  35:     HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200,
  36:     0,      0,      0,      0
  37: };
  38: 
  39: struct  buf dvhptab;
  40: #ifdef  UCB_DBUFS
  41: struct  buf rdvhpbuf[NHP];
  42: #else
  43: struct  buf rdvhpbuf;
  44: #endif
  45: struct  buf dvhputab[NDVHP];
  46: 
  47: #ifdef  INTRLVE
  48: extern  daddr_t dkblock();
  49: #endif
  50: 
  51: void
  52: dvhproot()
  53: {
  54:     dvhpattach(DVHPADDR, 0);
  55: }
  56: 
  57: dvhpattach(addr, unit)
  58: register struct hpdevice *addr;
  59: {
  60:     if (unit != 0)
  61:         return(0);
  62:     if ((addr != (struct hpdevice *) NULL) && (fioword(addr) != -1)) {
  63:         DVHPADDR = addr;
  64: #if PDP11 == 70 || PDP11 == GENERIC
  65:         if (fioword(&(addr->hpbae)) != -1)
  66:             dvhptab.b_flags |= B_RH70;
  67: #endif
  68:         return(1);
  69:     }
  70:     DVHPADDR = (struct hpdevice *) NULL;
  71:     return(0);
  72: }
  73: 
  74: dvhpstrategy(bp)
  75: register struct buf *bp;
  76: {
  77:     register struct buf *dp;
  78:     register unit;
  79:     long bn;
  80: 
  81:     unit = minor(bp->b_dev) & 077;
  82:     if (unit >= (NDVHP << 3) || (DVHPADDR == (struct hpdevice *) NULL)) {
  83:         bp->b_error = ENXIO;
  84:         goto errexit;
  85:     }
  86:     if (bp->b_blkno < 0 ||
  87:         (bn = dkblock(bp)) + (long) ((bp->b_bcount + 511) >> 9)
  88:         > dvhp_sizes[unit & 07].nblocks) {
  89:         bp->b_error = EINVAL;
  90: errexit:
  91:         bp->b_flags |= B_ERROR;
  92:         iodone(bp);
  93:         return;
  94:     }
  95: #ifdef  UNIBUS_MAP
  96:     if ((dvhptab.b_flags & B_RH70) == 0)
  97:         mapalloc(bp);
  98: #endif
  99:     bp->b_cylin = bn / (DVHP_NSECT * DVHP_NTRAC) + dvhp_sizes[unit & 07].cyloff;
 100:     unit = dkunit(bp);
 101:     dp = &dvhputab[unit];
 102:     (void) _spl5();
 103:     disksort(dp, bp);
 104:     if (dp->b_active == 0) {
 105:         dvhpustart(unit);
 106:         if (dvhptab.b_active == 0)
 107:             dvhpstart();
 108:     }
 109:     (void) _spl0();
 110: }
 111: 
 112: /*
 113:  * Unit start routine.
 114:  * Seek the drive to where the data are
 115:  * and then generate another interrupt
 116:  * to actually start the transfer.
 117:  * If there is only one drive on the controller
 118:  * or we are very close to the data, don't
 119:  * bother with the search.  If called after
 120:  * searching once, don't bother to look
 121:  * where we are, just queue for transfer (to avoid
 122:  * positioning forever without transferring).
 123:  */
 124: dvhpustart(unit)
 125: register unit;
 126: {
 127:     register struct hpdevice *dvhpaddr = DVHPADDR;
 128:     register struct buf *dp;
 129:     struct  buf *bp;
 130:     daddr_t bn;
 131:     int sn, cn, csn;
 132: 
 133:     dvhpaddr->hpcs2.w = unit;
 134:     dvhpaddr->hpcs1.c[0] = HP_IE;
 135:     dvhpaddr->hpas = 1 << unit;
 136: 
 137:     if (unit >= NDVHP)
 138:         return;
 139: #ifdef  DVHP_DKN
 140:     dk_busy &= ~(1 << (unit + DVHP_DKN));
 141: #endif
 142:     dp = &dvhputab[unit];
 143:     if ((bp=dp->b_actf) == NULL)
 144:         return;
 145:     /*
 146: 	 * If we have already positioned this drive,
 147: 	 * then just put it on the ready queue.
 148: 	 */
 149:     if (dp->b_active)
 150:         goto done;
 151:     dp->b_active++;
 152:     /*
 153: 	 * If drive has just come up,
 154: 	 * set up the pack.
 155: 	 */
 156:     if ((dvhpaddr->hpds & HPDS_VV) == 0) {
 157:         /* SHOULD WARN SYSTEM THAT THIS HAPPENED */
 158:         dvhpaddr->hpcs1.c[0] = HP_IE | HP_PRESET | HP_GO;
 159:         dvhpaddr->hpof = HPOF_FMT22;
 160:     }
 161: #if NDVHP > 1
 162:     /*
 163: 	 * If drive is offline, forget about positioning.
 164: 	 */
 165:     if ((dvhpaddr->hpds & (HPDS_DPR | HPDS_MOL)) != (HPDS_DPR | HPDS_MOL))
 166:         goto done;
 167:     /*
 168: 	 * Not on cylinder at correct position:  seek
 169: 	 */
 170:     bn = dkblock(bp);
 171:     cn = bp->b_cylin;
 172:     sn = bn % (DVHP_NSECT * DVHP_NTRAC);
 173:     sn = (sn + DVHP_NSECT - DVHP_SDIST) % DVHP_NSECT;
 174: 
 175:     if (dvhpaddr->hpcc != cn) {
 176:         dvhpaddr->hpdc = cn;
 177:         dvhpaddr->hpcs1.c[0] = HP_IE | HP_SEEK | HP_GO;
 178: #ifdef  DVHP_DKN
 179:         /*
 180: 		 * Mark unit busy for iostat.
 181: 		 */
 182:         unit += DVHP_DKN;
 183:         dk_busy |= 1 << unit;
 184:         dk_numb[unit]++;
 185: #endif
 186:         return;
 187:     }
 188: #endif	NDVHP > 1
 189: 
 190: done:
 191:     /*
 192: 	 * Device is ready to go.
 193: 	 * Put it on the ready queue for the controller.
 194: 	 */
 195:     dp->b_forw = NULL;
 196:     if (dvhptab.b_actf == NULL)
 197:         dvhptab.b_actf = dp;
 198:     else
 199:         dvhptab.b_actl->b_forw = dp;
 200:     dvhptab.b_actl = dp;
 201: }
 202: 
 203: /*
 204:  * Start up a transfer on a drive.
 205:  */
 206: dvhpstart()
 207: {
 208:     register struct hpdevice *dvhpaddr = DVHPADDR;
 209:     register struct buf *bp;
 210:     struct  buf *dp;
 211:     register unit;
 212:     daddr_t bn;
 213:     int dn, sn, tn, cn;
 214: 
 215: loop:
 216:     /*
 217: 	 * Pull a request off the controller queue.
 218: 	 */
 219:     if ((dp = dvhptab.b_actf) == NULL)
 220:         return;
 221:     if ((bp = dp->b_actf) == NULL) {
 222:         dvhptab.b_actf = dp->b_forw;
 223:         goto loop;
 224:     }
 225:     /*
 226: 	 * Mark controller busy and
 227: 	 * determine destination of this request.
 228: 	 */
 229:     dvhptab.b_active++;
 230:     unit = minor(bp->b_dev) & 077;
 231:     dn = dkunit(bp);
 232:     bn = dkblock(bp);
 233:     cn = bn / (DVHP_NSECT * DVHP_NTRAC) + dvhp_sizes[unit & 07].cyloff;
 234:     sn = bn % (DVHP_NSECT * DVHP_NTRAC);
 235:     tn = sn / DVHP_NSECT;
 236:     sn = sn % DVHP_NSECT;
 237: 
 238:     /*
 239: 	 * Select drive.
 240: 	 */
 241:     dvhpaddr->hpcs2.w = dn;
 242: 
 243:     /*
 244: 	 * Check that it is ready and online.
 245: 	 */
 246:     if ((dvhpaddr->hpds & (HPDS_DPR | HPDS_MOL)) != (HPDS_DPR | HPDS_MOL)) {
 247:         dvhptab.b_active = 0;
 248:         dvhptab.b_errcnt = 0;
 249:         dp->b_actf = bp->av_forw;
 250:         bp->b_flags |= B_ERROR;
 251:         iodone(bp);
 252:         goto loop;
 253:     }
 254:     if (dvhptab.b_errcnt >= 16 && (bp->b_flags & B_READ)) {
 255:         dvhpaddr->hpof = dvhp_offset[dvhptab.b_errcnt & 017] | HPOF_FMT22;
 256:         dvhpaddr->hpcs1.w = HP_OFFSET | HP_GO;
 257:         while ((dvhpaddr->hpds & (HPDS_PIP | HPDS_DRY)) != HPDS_DRY)
 258:             ;
 259:     }
 260:     dvhpaddr->hpdc = cn;
 261:     dvhpaddr->hpda = (tn << 8) + sn;
 262:     dvhpaddr->hpba = bp->b_un.b_addr;
 263: #if PDP11 == 70 || PDP11 == GENERIC
 264:     if (dvhptab.b_flags & B_RH70)
 265:         dvhpaddr->hpbae = bp->b_xmem;
 266: #endif
 267:     dvhpaddr->hpwc = -(bp->b_bcount >> 1);
 268:     /*
 269: 	 * Warning:  unit is being used as a temporary.
 270: 	 */
 271:     unit = ((bp->b_xmem & 3) << 8) | HP_IE | HP_GO;
 272:     if (bp->b_flags & B_READ)
 273:         unit |= HP_RCOM;
 274:     else
 275:         unit |= HP_WCOM;
 276:     dvhpaddr->hpcs1.w = unit;
 277: 
 278: #ifdef  DVHP_DKN
 279:     dk_busy |= 1 << (DVHP_DKN + NDVHP);
 280:     dk_numb[DVHP_DKN + NDVHP]++;
 281:     dk_wds[DVHP_DKN + NDVHP] += bp->b_bcount >> 6;
 282: #endif	DVHP_DKN
 283: }
 284: 
 285: /*
 286:  * Handle a disk interrupt.
 287:  */
 288: dvhpintr()
 289: {
 290:     register struct hpdevice *dvhpaddr = DVHPADDR;
 291:     register struct buf *dp;
 292:     struct  buf *bp;
 293:     register unit;
 294:     int as, i, j;
 295: 
 296:     as = dvhpaddr->hpas & 0377;
 297:     if (dvhptab.b_active) {
 298: #ifdef  DVHP_DKN
 299:         dk_busy &= ~(1 << (DVHP_DKN + NDVHP));
 300: #endif	DVHP_DKN
 301:         /*
 302: 		 * Get device and block structures.  Select the drive.
 303: 		 */
 304:         dp = dvhptab.b_actf;
 305:         bp = dp->b_actf;
 306:         unit = dkunit(bp);
 307:         dvhpaddr->hpcs2.c[0] = unit;
 308:         /*
 309: 		 * Check for and process errors.
 310: 		 */
 311:         if (dvhpaddr->hpcs1.w & HP_TRE) {       /* error bit */
 312:             while ((dvhpaddr->hpds & HPDS_DRY) == 0)
 313:                 ;
 314:             if (dvhpaddr->hper1 & HPER1_WLE) {
 315:                 /*
 316: 				 *	Give up on write locked devices
 317: 				 *	immediately.
 318: 				 */
 319:                 printf("dvhp%d: write locked\n", unit);
 320:                 bp->b_flags |= B_ERROR;
 321:             } else {
 322:                 /*
 323: 				 * After 28 retries (16 without offset and
 324: 				 * 12 with offset positioning), give up.
 325: 				 */
 326:                 if (++dvhptab.b_errcnt > 28) {
 327:                     bp->b_flags |= B_ERROR;
 328: #ifdef  UCB_DEVERR
 329:                     harderr(bp, "dvhp");
 330:                     printf("cs2=%b er1=%b\n",
 331:                         dvhpaddr->hpcs2.w, HPCS2_BITS,
 332:                         dvhpaddr->hper1, HPER1_BITS);
 333: #else
 334:                     deverror(bp, dvhpaddr->hpcs2.w,
 335:                         dvhpaddr->hper1);
 336: #endif
 337:                 } else
 338:                     dvhptab.b_active = 0;
 339:             }
 340: #ifdef  UCB_ECC
 341:             /*
 342: 			 * If soft ecc, correct it (continuing
 343: 			 * by returning if necessary).
 344: 			 * Otherwise, fall through and retry the transfer.
 345: 			 */
 346:             if ((dvhpaddr->hper1 & (HPER1_DCK | HPER1_ECH)) == HPER1_DCK)
 347:                 if (dvhpecc(bp))
 348:                     return;
 349: #endif
 350:             dvhpaddr->hpcs1.w = HP_TRE | HP_IE | HP_DCLR | HP_GO;
 351:             if ((dvhptab.b_errcnt & 07) == 4) {
 352:                 dvhpaddr->hpcs1.w = HP_RECAL | HP_IE | HP_GO;
 353:                 while ((dvhpaddr->hpds & (HPDS_PIP | HPDS_DRY)) != HPDS_DRY)
 354:                     ;
 355:             }
 356:         }
 357:         if (dvhptab.b_active) {
 358:             if (dvhptab.b_errcnt) {
 359:                 dvhpaddr->hpcs1.w = HP_RTC | HP_GO;
 360:                 while ((dvhpaddr->hpds & (HPDS_PIP | HPDS_DRY)) != HPDS_DRY)
 361:                     ;
 362:             }
 363:             dvhptab.b_active = 0;
 364:             dvhptab.b_errcnt = 0;
 365:             dvhptab.b_actf = dp->b_forw;
 366:             dp->b_active = 0;
 367:             dp->b_actf = bp->av_forw;
 368:             bp->b_resid = -(dvhpaddr->hpwc << 1);
 369:             iodone(bp);
 370:             dvhpaddr->hpcs1.w = HP_IE;
 371:             if (dp->b_actf)
 372:                 dvhpustart(unit);
 373:         }
 374:         as &= ~(1 << unit);
 375:     } else
 376:         {
 377:         if (as == 0)
 378:             dvhpaddr->hpcs1.w = HP_IE;
 379:         dvhpaddr->hpcs1.c[1] = HP_TRE >> 8;
 380:     }
 381:     for (unit = 0; unit < NDVHP; unit++)
 382:         if (as & (1 << unit))
 383:             dvhpustart(unit);
 384:     dvhpstart();
 385: }
 386: 
 387: dvhpread(dev)
 388: dev_t   dev;
 389: {
 390: #ifdef  UCB_DBUFS
 391:     register int unit = (minor(dev) >> 3) & 07;
 392: 
 393:     if (unit >= NHP)
 394:         u.u_error = ENXIO;
 395:     else
 396:         physio(dvhpstrategy, &rdvhpbuf[unit], dev, B_READ);
 397: #else
 398:     physio(dvhpstrategy, &rdvhpbuf, dev, B_READ);
 399: #endif
 400: }
 401: 
 402: dvhpwrite(dev)
 403: dev_t   dev;
 404: {
 405: #ifdef  UCB_DBUFS
 406:     register int unit = (minor(dev) >> 3) & 07;
 407: 
 408:     if (unit >= NHP)
 409:         u.u_error = ENXIO;
 410:     else
 411:         physio(dvhpstrategy, &rdvhpbuf[unit], dev, B_WRITE);
 412: #else
 413:     physio(dvhpstrategy, &rdvhpbuf, dev, B_WRITE);
 414: #endif
 415: }
 416: 
 417: #ifdef  UCB_ECC
 418: #define exadr(x,y)  (((long)(x) << 16) | (unsigned)(y))
 419: 
 420: /*
 421:  * Correct an ECC error and restart the i/o to complete
 422:  * the transfer if necessary.  This is quite complicated because
 423:  * the transfer may be going to an odd memory address base
 424:  * and/or across a page boundary.
 425:  */
 426: dvhpecc(bp)
 427: register struct buf *bp;
 428: {
 429:     register struct hpdevice *dvhpaddr = DVHPADDR;
 430:     register unsigned byte;
 431:     ubadr_t bb, addr;
 432:     long    wrong;
 433:     int bit, wc;
 434:     unsigned ndone, npx;
 435:     int ocmd;
 436:     int cn, tn, sn;
 437:     daddr_t bn;
 438: #ifdef  UNIBUS_MAP
 439:     struct  ubmap *ubp;
 440: #endif
 441: 
 442:     /*
 443: 	 *	ndone is #bytes including the error
 444: 	 *	which is assumed to be in the last disk page transferred.
 445: 	 */
 446:     wc = dvhpaddr->hpwc;
 447:     ndone = (wc * NBPW) + bp->b_bcount;
 448:     npx = ndone / PGSIZE;
 449:     printf("dvhp%d%c: soft ecc bn %D\n",
 450:         dkunit(bp), 'a' + (minor(bp->b_dev) & 07),
 451:         bp->b_blkno + (npx - 1));
 452:     wrong = dvhpaddr->hpec2;
 453:     if(wrong == 0) {
 454:         dvhpaddr->hpof = HPOF_FMT22;
 455:         dvhpaddr->hpcs1.w |= HP_IE;
 456:         return (0);
 457:     }
 458: 
 459:     /*
 460: 	 *	Compute the byte/bit position of the err
 461: 	 *	within the last disk page transferred.
 462: 	 *	Hpec1 is origin-1.
 463: 	 */
 464:     byte = dvhpaddr->hpec1 - 1;
 465:     bit = byte & 07;
 466:     byte >>= 3;
 467:     byte += ndone - PGSIZE;
 468:     bb = exadr(bp->b_xmem, bp->b_un.b_addr);
 469:     wrong <<= bit;
 470: 
 471:     /*
 472: 	 *	Correct until mask is zero or until end of transfer,
 473: 	 *	whichever comes first.
 474: 	 */
 475:     while (byte < bp->b_bcount && wrong != 0) {
 476:         addr = bb + byte;
 477: #ifdef  UNIBUS_MAP
 478:         if (bp->b_flags & (B_MAP | B_UBAREMAP)) {
 479:             /*
 480: 			 * Simulate UNIBUS map if UNIBUS transfer.
 481: 			 */
 482:             ubp = UBMAP + ((addr >> 13) & 037);
 483:             addr = exadr(ubp->ub_hi, ubp->ub_lo) + (addr & 017777);
 484:         }
 485: #endif
 486:         putmemc(addr, getmemc(addr) ^ (int) wrong);
 487:         byte++;
 488:         wrong >>= 8;
 489:     }
 490: 
 491:     dvhptab.b_active++;
 492:     if (wc == 0)
 493:         return (0);
 494: 
 495:     /*
 496: 	 * Have to continue the transfer.  Clear the drive
 497: 	 * and compute the position where the transfer is to continue.
 498: 	 * We have completed npx sectors of the transfer already.
 499: 	 */
 500:     ocmd = (dvhpaddr->hpcs1.w & ~HP_RDY) | HP_IE | HP_GO;
 501:     dvhpaddr->hpcs2.w = dkunit(bp);
 502:     dvhpaddr->hpcs1.w = HP_TRE | HP_DCLR | HP_GO;
 503: 
 504:     bn = dkblock(bp);
 505:     cn = bp->b_cylin - bn / (DVHP_NSECT * DVHP_NTRAC);
 506:     bn += npx;
 507:     addr = bb + ndone;
 508: 
 509:     cn += bn / (DVHP_NSECT * DVHP_NTRAC);
 510:     sn = bn % (DVHP_NSECT * DVHP_NTRAC);
 511:     tn = sn / DVHP_NSECT;
 512:     sn %= DVHP_NSECT;
 513: 
 514:     dvhpaddr->hpdc = cn;
 515:     dvhpaddr->hpda = (tn << 8) + sn;
 516:     dvhpaddr->hpwc = ((int)(ndone - bp->b_bcount)) / NBPW;
 517:     dvhpaddr->hpba = (int) addr;
 518: #if PDP11 == 70 || PDP11 == GENERIC
 519:     if (dvhptab.b_flags & B_RH70)
 520:         dvhpaddr->hpbae = (int) (addr >> 16);
 521: #endif
 522:     dvhpaddr->hpcs1.w = ocmd;
 523:     return (1);
 524: }
 525: #endif	UCB_ECC
 526: #endif	NDVHP

Defined functions

dvhpattach defined in line 57; used 1 times
  • in line 54
dvhpecc defined in line 426; used 1 times
dvhpintr defined in line 288; never used
dvhpread defined in line 387; never used
dvhproot defined in line 51; never used
dvhpstart defined in line 206; used 2 times
dvhpstrategy defined in line 74; used 4 times
dvhpustart defined in line 124; used 3 times
dvhpwrite defined in line 402; never used

Defined variables

dvhp_offset defined in line 31; used 1 times
dvhptab defined in line 39; used 27 times
dvhputab defined in line 45; used 2 times
rdvhpbuf defined in line 43; used 4 times

Defined macros

DVHP_NSECT defined in line 23; used 13 times
DVHP_NTRAC defined in line 24; used 7 times
DVHP_RDIST defined in line 26; never used
DVHP_SDIST defined in line 25; used 1 times
exadr defined in line 418; used 2 times
Last modified: 1983-09-02
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1424
Valid CSS Valid XHTML 1.0 Strict