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:  *	@(#)hk.c	2.3 (2.11BSD GTE) 1998/4/3
   7:  */
   8: 
   9: /*
  10:  * RK611/RK0[67] disk driver
  11:  *
  12:  * Heavily modified for disklabel support.  Still only supports 1 controller
  13:  * (but who'd have more than one of these on a system anyhow?) - 1997/11/11 sms
  14:  *
  15:  * This driver mimics the 4.1bsd rk driver.
  16:  * It does overlapped seeks, ECC, and bad block handling.
  17:  * 	salkind@nyu
  18:  *
  19:  * dkunit() takes a 'dev_t' now instead of 'buf *'.  1995/04/13 - sms
  20:  *
  21:  * Removed ifdefs on both Q22 and UNIBUS_MAP, substituting a runtime
  22:  * test for presence of a Unibus Map.  Reworked the partition logic,
  23:  * the 'e' partiton no longer overlaps the 'a'+'b' partitions - a separate
  24:  * 'b' partition is now present.  Old root filesystems can still be used
  25:  * because the size is the same, but user data will have to be saved and
  26:  * then reloaded.  12/28/92 -- sms@wlv.iipo.gtegsc.com
  27:  *
  28:  * Modified to correctly handle 22 bit addressing available on DILOG
  29:  * DQ615 controller. 05/31/90 -- tymann@oswego.edu
  30:  *
  31:  */
  32: 
  33: #include "hk.h"
  34: #if NHK > 0
  35: #include "param.h"
  36: #include "systm.h"
  37: #include "buf.h"
  38: #include "machine/seg.h"
  39: #include "conf.h"
  40: #include "user.h"
  41: #include "map.h"
  42: #include "uba.h"
  43: #include "hkreg.h"
  44: #include "dkbad.h"
  45: #include "dk.h"
  46: #include "stat.h"
  47: #include "file.h"
  48: #include "disklabel.h"
  49: #include "disk.h"
  50: #include "syslog.h"
  51: 
  52: #define NHK7CYL 815
  53: #define NHK6CYL 411
  54: #define HK_NSECT    22
  55: #define HK_NTRAC    3
  56: #define HK_NSPC     (HK_NTRAC*HK_NSECT)
  57: 
  58: struct  hkdevice *HKADDR;
  59: 
  60:     daddr_t hksize();
  61:     void    hkdfltlbl();
  62:     int hkstrategy();
  63: 
  64: /* Can be u_char because all are less than 0377 */
  65: u_char  hk_offset[] =
  66:     {
  67:     HKAS_P400,  HKAS_M400,  HKAS_P400,  HKAS_M400,
  68:     HKAS_P800,  HKAS_M800,  HKAS_P800,  HKAS_M800,
  69:     HKAS_P1200, HKAS_M1200, HKAS_P1200, HKAS_M1200,
  70:     0,      0,      0,      0,
  71:     };
  72: 
  73:     int hk_type[NHK];
  74:     int hk_cyl[NHK];
  75: 
  76: struct hk_softc
  77:     {
  78:     int sc_softas;
  79:     int sc_recal;
  80:     } hk;
  81: 
  82:     struct  buf hktab;
  83:     struct  buf hkutab[NHK];
  84:     struct  dkdevice hk_dk[NHK];
  85: 
  86: #ifdef BADSECT
  87:     struct  dkbad   hkbad[NHK];
  88:     struct  buf bhkbuf[NHK];
  89: #endif
  90: 
  91: #ifdef UCB_METER
  92:     static  int     hk_dkn = -1;    /* number for iostat */
  93: #endif
  94: 
  95: #define hkwait(hkaddr)      while ((hkaddr->hkcs1 & HK_CRDY) == 0)
  96: #define hkncyl(unit)        (hk_type[unit] ? NHK7CYL : NHK6CYL)
  97: 
  98: void
  99: hkroot()
 100:     {
 101:     hkattach((struct hkdevice *)0177440, 0);
 102:     }
 103: 
 104: hkattach(addr, unit)
 105: struct hkdevice *addr;
 106:     {
 107: #ifdef UCB_METER
 108:     if  (hk_dkn < 0)
 109:         {
 110:         dk_alloc(&hk_dkn, NHK+1, "hk", 60L * (long)HK_NSECT * 256L);
 111:         if  (hk_dkn >= 0)
 112:             dk_wps[hk_dkn+NHK] = 0L;
 113:         }
 114: #endif
 115:     if (unit != 0)
 116:         return(0);
 117:     HKADDR = addr;
 118:     return(1);
 119:     }
 120: 
 121: hkopen(dev, flag, mode)
 122:     dev_t   dev;
 123:     int flag;
 124:     int mode;
 125:     {
 126:     register int unit = dkunit(dev);
 127:     register struct hkdevice *hkaddr = HKADDR;
 128:     register struct dkdevice *disk;
 129:     int i, mask;
 130: 
 131:     if  (unit >= NHK || !HKADDR)
 132:         return(ENXIO);
 133:     disk = &hk_dk[unit];
 134: 
 135:     if  ((disk->dk_flags & DKF_ALIVE) == 0)
 136:         {
 137:         hk_type[unit] = 0;
 138:         hkaddr->hkcs1 = HK_CCLR;
 139:         hkaddr->hkcs2 = unit;
 140:         hkaddr->hkcs1 = HK_DCLR | HK_GO;
 141:         hkwait(hkaddr);
 142:         if  (hkaddr->hkcs2&HKCS2_NED || !(hkaddr->hkds&HKDS_SVAL))
 143:             {
 144:             hkaddr->hkcs1 = HK_CCLR;
 145:             hkwait(hkaddr);
 146:             return(ENXIO);
 147:             }
 148:         disk->dk_flags |= DKF_ALIVE;
 149:         if  ((hkaddr->hkcs1&HK_CERR) && (hkaddr->hker&HKER_DTYE))
 150:             {
 151:             hk_type[unit] = HK_CDT;
 152:             hkaddr->hkcs1 = HK_CCLR;
 153:             hkwait(hkaddr);
 154:             }
 155:         }
 156: /*
 157:  * The drive has responded to a probe (is alive).  Now we read the
 158:  * label.  Allocate an external label structure if one has not already
 159:  * been assigned to this drive.  First wait for any pending opens/closes
 160:  * to complete.
 161: */
 162:     while   (disk->dk_flags & (DKF_OPENING | DKF_CLOSING))
 163:         sleep(disk, PRIBIO);
 164: 
 165: /*
 166:  * Next if an external label buffer has not already been allocated do so now.
 167:  * This "can not fail" because if the initial pool of label buffers has
 168:  * been exhausted the allocation takes place from main memory.  The return
 169:  * value is the 'click' address to be used when mapping in the label.
 170: */
 171: 
 172:     if  (disk->dk_label == 0)
 173:         disk->dk_label = disklabelalloc();
 174: 
 175: /*
 176:  * On first open get label and partition info.  We may block reading the
 177:  * label so be careful to stop any other opens.
 178: */
 179:     if  (disk->dk_openmask == 0)
 180:         {
 181:         disk->dk_flags |= DKF_OPENING;
 182:         hkgetinfo(disk, dev);
 183:         disk->dk_flags &= ~DKF_OPENING;
 184:         wakeup(disk);
 185:         hk_cyl[unit] = -1;
 186:         }
 187: /*
 188:  * Need to make sure the partition is not out of bounds.  This requires
 189:  * mapping in the external label.  This only happens when a partition
 190:  * is opened (at mount time) and isn't an efficiency problem.
 191: */
 192:     mapseg5(disk->dk_label, LABELDESC);
 193:     i = ((struct disklabel *)SEG5)->d_npartitions;
 194:     normalseg5();
 195:     if  (dkpart(dev) >= i)
 196:         return(ENXIO);
 197:     mask = 1 << dkpart(dev);
 198:     dkoverlapchk(disk->dk_openmask, dev, disk->dk_label, "hk");
 199:     if  (mode == S_IFCHR)
 200:         disk->dk_copenmask |= mask;
 201:     else if (mode == S_IFBLK)
 202:         disk->dk_bopenmask |= mask;
 203:     else
 204:         return(EINVAL);
 205:     disk->dk_openmask |= mask;
 206:     return(0);
 207:     }
 208: 
 209: /*
 210:  * Disk drivers now have to have close entry points in order to keep
 211:  * track of what partitions are still active on a drive.
 212: */
 213: hkclose(dev, flag, mode)
 214: register dev_t  dev;
 215:     int     flag, mode;
 216:     {
 217:     int     s, drive = dkunit(dev);
 218:     register int    mask;
 219:     register struct dkdevice *disk;
 220: 
 221:     disk = &hk_dk[drive];
 222:     mask = 1 << dkpart(dev);
 223:     if  (mode == S_IFCHR)
 224:         disk->dk_copenmask &= ~mask;
 225:     else if (mode == S_IFBLK)
 226:         disk->dk_bopenmask &= ~mask;
 227:     else
 228:         return(EINVAL);
 229:     disk->dk_openmask = disk->dk_bopenmask | disk->dk_copenmask;
 230:     if  (disk->dk_openmask == 0)
 231:         {
 232:         disk->dk_flags |= DKF_CLOSING;
 233:         s = splbio();
 234:         while   (hkutab[drive].b_actf)
 235:             {
 236:             disk->dk_flags |= DKF_WANTED;
 237:             sleep(&hkutab[drive], PRIBIO);
 238:             }
 239:         splx(s);
 240: /*
 241:  * On last close of a drive we declare it not alive and offline to force a
 242:  * probe on the next open in order to handle diskpack changes.
 243: */
 244:         disk->dk_flags &=
 245:             ~(DKF_CLOSING | DKF_WANTED | DKF_ALIVE | DKF_ONLINE);
 246:         wakeup(disk);
 247:         }
 248:     return(0);
 249:     }
 250: 
 251: /*
 252:  * This code moved here from hkgetinfo() because it is fairly large and used
 253:  * twice - once to initialize for reading the label and a second time if
 254:  * there is no valid label present on the drive and the default one must be
 255:  * used to span the drive.
 256: */
 257: 
 258: void
 259: hkdfltlbl(disk, lp, dev)
 260:     struct dkdevice *disk;
 261:     register struct disklabel *lp;
 262:     dev_t   dev;
 263:     {
 264:     register struct partition *pi = &lp->d_partitions[0];
 265: 
 266:     bzero(lp, sizeof (*lp));
 267:         lp->d_type = DTYPE_DEC;
 268:     lp->d_secsize = 512;            /* XXX */
 269:     lp->d_nsectors = HK_NSECT;
 270:     lp->d_ntracks = HK_NTRAC;
 271:     lp->d_secpercyl = HK_NSPC;
 272:     lp->d_npartitions = 1;          /* 'a' */
 273:     lp->d_ncylinders = hkncyl(dkunit(dev));
 274:     pi->p_size = lp->d_ncylinders * lp->d_secpercyl;     /* entire volume */
 275:     pi->p_fstype = FS_V71K;
 276:     pi->p_frag = 1;
 277:     pi->p_fsize = 1024;
 278: /*
 279:  * Put where hkstrategy() will look.
 280: */
 281:     bcopy(pi, disk->dk_parts, sizeof (lp->d_partitions));
 282:     }
 283: 
 284: /*
 285:  * Read disklabel.  It is tempting to generalize this routine so that
 286:  * all disk drivers could share it.  However by the time all of the
 287:  * necessary parameters are setup and passed the savings vanish.  Also,
 288:  * each driver has a different method of calculating the number of blocks
 289:  * to use if one large partition must cover the disk.
 290:  *
 291:  * This routine used to always return success and callers carefully checked
 292:  * the return status.  Silly.  This routine will fake a label (a single
 293:  * partition spanning the drive) if necessary but will never return an error.
 294:  *
 295:  * It is the caller's responsibility to check the validity of partition
 296:  * numbers, etc.
 297: */
 298: 
 299: void
 300: hkgetinfo(disk, dev)
 301: register struct dkdevice *disk;
 302:     dev_t   dev;
 303:     {
 304:     struct  disklabel locallabel;
 305:     char    *msg;
 306:     register struct disklabel *lp = &locallabel;
 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' will span the entire disk
 311: */
 312:     hkdfltlbl(disk, lp, dev);
 313:     msg = readdisklabel((dev & ~7) | 0, hkstrategy, lp);    /* 'a' */
 314:     if      (msg != 0)
 315:         {
 316:         log(LOG_NOTICE, "hk%da is entire disk: %s\n", dkunit(dev), msg);
 317:         hkdfltlbl(disk, lp, dev);
 318:         }
 319:     mapseg5(disk->dk_label, LABELDESC)
 320:     bcopy(lp, (struct disklabel *)SEG5, sizeof (struct disklabel));
 321:     normalseg5();
 322:     bcopy(lp->d_partitions, disk->dk_parts, sizeof (lp->d_partitions));
 323:     return;
 324:     }
 325: 
 326: hkstrategy(bp)
 327: register struct buf *bp;
 328: {
 329:     register struct buf *dp;
 330:     int s, drive;
 331:     register struct dkdevice *disk;
 332: 
 333:     drive = dkunit(bp->b_dev);
 334:     disk = &hk_dk[drive];
 335: 
 336:     if  (drive >= NHK || !HKADDR  || !(disk->dk_flags & DKF_ALIVE))
 337:         {
 338:         bp->b_error = ENXIO;
 339:         goto bad;
 340:         }
 341:     s = partition_check(bp, disk);
 342:     if  (s < 0)
 343:         goto bad;
 344:     if  (s == 0)
 345:         goto done;
 346: 
 347:     bp->b_cylin = bp->b_blkno / HK_NSPC;
 348:     mapalloc(bp);
 349:     dp = &hkutab[drive];
 350:     s = splbio();
 351:     disksort(dp, bp);
 352:     if  (dp->b_active == 0)
 353:         {
 354:         hkustart(drive);
 355:         if  (hktab.b_active == 0)
 356:             hkstart();
 357:         }
 358:     splx(s);
 359:     return;
 360: bad:
 361:     bp->b_flags |= B_ERROR;
 362: done:
 363:     iodone(bp);
 364:     }
 365: 
 366: hkustart(unit)
 367:     int unit;
 368: {
 369:     register struct hkdevice *hkaddr = HKADDR;
 370:     register struct buf *bp, *dp;
 371:     struct dkdevice *disk;
 372:     int didie = 0;
 373: 
 374: #ifdef UCB_METER
 375:     if (hk_dkn >= 0)
 376:         dk_busy &= ~(1 << (hk_dkn + unit));
 377: #endif
 378:     if (hktab.b_active) {
 379:         hk.sc_softas |= (1 << unit);
 380:         return(0);
 381:     }
 382: 
 383:     hkaddr->hkcs1 = HK_CCLR;
 384:     hkaddr->hkcs2 = unit;
 385:     hkaddr->hkcs1 = hk_type[unit] | HK_DCLR | HK_GO;
 386:     hkwait(hkaddr);
 387: 
 388:     dp = &hkutab[unit];
 389:     disk = &hk_dk[unit];
 390:     if ((bp = dp->b_actf) == NULL)
 391:         return(0);
 392:     if (dp->b_active)
 393:         goto done;
 394:     dp->b_active = 1;
 395:     if  (!(hkaddr->hkds & HKDS_VV) || !(disk->dk_flags & DKF_ONLINE))
 396:         {
 397:         /* SHOULD WARN SYSTEM THAT THIS HAPPENED */
 398: #ifdef BADSECT
 399:         struct buf *bbp = &bhkbuf[unit];
 400: #endif
 401: 
 402:         hkaddr->hkcs1 = hk_type[unit]|HK_PACK|HK_GO;
 403:         disk->dk_flags |= DKF_ONLINE;
 404: /*
 405:  * XXX - The 'c' partition is used below to access the bad block area.  This
 406:  * XXX - is DIFFERENT than the XP driver (which should have used 'c' but could
 407:  * XXX - not due to historical reasons).  The 'c' partition MUST span the entire
 408:  * XXX - disk including the bad sector track.  The 'h' partition should be
 409:  * XXX - used for user data.
 410: */
 411: #ifdef BADSECT
 412:         bbp->b_flags = B_READ|B_BUSY|B_PHYS;
 413:         bbp->b_dev = (bp->b_dev & ~7) | ('c' - 'a');
 414:         bbp->b_bcount = sizeof(struct dkbad);
 415:         bbp->b_un.b_addr = (caddr_t)&hkbad[unit];
 416:         bbp->b_blkno = (long)hkncyl(unit)*HK_NSPC - HK_NSECT;
 417:         bbp->b_cylin = hkncyl(unit) - 1;
 418:         mapalloc(bbp);
 419:         dp->b_actf = bbp;
 420:         bbp->av_forw = bp;
 421:         bp = bbp;
 422: #endif
 423:         hkwait(hkaddr);
 424:         }
 425:     if  ((hkaddr->hkds & HKDS_DREADY) != HKDS_DREADY)
 426:         {
 427:         disk->dk_flags &= ~DKF_ONLINE;
 428:         goto done;
 429:         }
 430: #ifdef NHK > 1
 431:     if (bp->b_cylin == hk_cyl[unit])
 432:         goto done;
 433:     hkaddr->hkcyl = bp->b_cylin;
 434:     hk_cyl[unit] = bp->b_cylin;
 435:     hkaddr->hkcs1 = hk_type[unit] | HK_IE | HK_SEEK | HK_GO;
 436:     didie = 1;
 437: #ifdef UCB_METER
 438:     if (hk_dkn >= 0) {
 439:         int dkn = hk_dkn + unit;
 440: 
 441:         dk_busy |= 1<<dkn;
 442:         dk_seek[dkn]++;
 443:     }
 444: #endif
 445:     return (didie);
 446: #endif NHK > 1
 447: 
 448: done:
 449:     if (dp->b_active != 2) {
 450:         dp->b_forw = NULL;
 451:         if (hktab.b_actf == NULL)
 452:             hktab.b_actf = dp;
 453:         else
 454:             hktab.b_actl->b_forw = dp;
 455:         hktab.b_actl = dp;
 456:         dp->b_active = 2;
 457:     }
 458:     return (didie);
 459: }
 460: 
 461: hkstart()
 462: {
 463:     register struct buf *bp, *dp;
 464:     register struct hkdevice *hkaddr = HKADDR;
 465:     register struct dkdevice *disk;
 466:     daddr_t bn;
 467:     int sn, tn, cmd, unit;
 468: 
 469: loop:
 470:     if ((dp = hktab.b_actf) == NULL)
 471:         return(0);
 472:     if ((bp = dp->b_actf) == NULL) {
 473: /*
 474:  * No more requests for this drive, remove from controller queue and
 475:  * look at next drive.  We know we're at the head of the controller queue.
 476:  * The drive may not need anything, in which case it might be shutting
 477:  * down in hkclose() and a wakeup is done.
 478: */
 479:         hktab.b_actf = dp->b_forw;
 480:         unit = dp - hkutab;
 481:         disk = &hk_dk[unit];
 482:         if  (disk->dk_flags & DKF_WANTED)
 483:             {
 484:             disk->dk_flags &= ~DKF_WANTED;
 485:             wakeup(dp); /* finish the close protocol */
 486:             }
 487:         goto loop;
 488:     }
 489:     hktab.b_active++;
 490:     unit = dkunit(bp->b_dev);
 491:     disk = &hk_dk[unit];
 492:     bn = bp->b_blkno;
 493: 
 494:     sn = bn % HK_NSPC;
 495:     tn = sn / HK_NSECT;
 496:     sn %= HK_NSECT;
 497: retry:
 498:     hkaddr->hkcs1 = HK_CCLR;
 499:     hkaddr->hkcs2 = unit;
 500:     hkaddr->hkcs1 = hk_type[unit] | HK_DCLR | HK_GO;
 501:     hkwait(hkaddr);
 502: 
 503:     if ((hkaddr->hkds & HKDS_SVAL) == 0)
 504:         goto nosval;
 505:     if (hkaddr->hkds & HKDS_PIP)
 506:         goto retry;
 507:     if ((hkaddr->hkds&HKDS_DREADY) != HKDS_DREADY) {
 508:         disk->dk_flags &= ~DKF_ONLINE;
 509:         log(LOG_WARNING, "hk%d: !ready\n", unit);
 510:         if ((hkaddr->hkds&HKDS_DREADY) != HKDS_DREADY) {
 511:             hkaddr->hkcs1 = hk_type[unit] | HK_DCLR | HK_GO;
 512:             hkwait(hkaddr);
 513:             hkaddr->hkcs1 = HK_CCLR;
 514:             hkwait(hkaddr);
 515:             hktab.b_active = 0;
 516:             hktab.b_errcnt = 0;
 517:             dp->b_actf = bp->av_forw;
 518:             dp->b_active = 0;
 519:             bp->b_flags |= B_ERROR;
 520:             iodone(bp);
 521:             goto loop;
 522:         }
 523:     }
 524:     disk->dk_flags |= DKF_ONLINE;
 525: nosval:
 526:     hkaddr->hkcyl = bp->b_cylin;
 527:     hk_cyl[unit] = bp->b_cylin;
 528:     hkaddr->hkda = (tn << 8) + sn;
 529:     hkaddr->hkwc = -(bp->b_bcount >> 1);
 530:     hkaddr->hkba = bp->b_un.b_addr;
 531:     if  (!ubmap)
 532:         hkaddr->hkxmem=bp->b_xmem;
 533: 
 534:     cmd = hk_type[unit] | ((bp->b_xmem & 3) << 8) | HK_IE | HK_GO;
 535:     if (bp->b_flags & B_READ)
 536:         cmd |= HK_READ;
 537:     else
 538:         cmd |= HK_WRITE;
 539:     hkaddr->hkcs1 = cmd;
 540: #ifdef UCB_METER
 541:     if (hk_dkn >= 0) {
 542:         int dkn = hk_dkn + NHK;
 543: 
 544:         dk_busy |= 1<<dkn;
 545:         dk_xfer[dkn]++;
 546:         dk_wds[dkn] += bp->b_bcount>>6;
 547:     }
 548: #endif
 549:     return(1);
 550: }
 551: 
 552: hkintr()
 553: {
 554:     register struct hkdevice *hkaddr = HKADDR;
 555:     register struct buf *bp, *dp;
 556:     int unit;
 557:     int as = (hkaddr->hkatt >> 8) | hk.sc_softas;
 558:     int needie = 1;
 559: 
 560:     hk.sc_softas = 0;
 561:     if (hktab.b_active) {
 562:         dp = hktab.b_actf;
 563:         bp = dp->b_actf;
 564:         unit = dkunit(bp->b_dev);
 565: #ifdef UCB_METER
 566:         if (hk_dkn >= 0)
 567:             dk_busy &= ~(1 << (hk_dkn + NHK));
 568: #endif
 569: #ifdef BADSECT
 570:         if (bp->b_flags&B_BAD)
 571:             if (hkecc(bp, CONT))
 572:                 return;
 573: #endif
 574:         if (hkaddr->hkcs1 & HK_CERR) {
 575:             int recal;
 576:             u_short ds = hkaddr->hkds;
 577:             u_short cs2 = hkaddr->hkcs2;
 578:             u_short er = hkaddr->hker;
 579: 
 580:             if (er & HKER_WLE) {
 581:                 log(LOG_WARNING, "hk%d: wrtlck\n", unit);
 582:                 bp->b_flags |= B_ERROR;
 583:             } else if (++hktab.b_errcnt > 28 ||
 584:                 ds&HKDS_HARD || er&HKER_HARD || cs2&HKCS2_HARD) {
 585: hard:
 586:                 harderr(bp, "hk");
 587:                 log(LOG_WARNING, "cs2=%b ds=%b er=%b\n",
 588:                     cs2, HKCS2_BITS, ds,
 589:                     HKDS_BITS, er, HKER_BITS);
 590:                 bp->b_flags |= B_ERROR;
 591:                 hk.sc_recal = 0;
 592:             } else if (er & HKER_BSE) {
 593: #ifdef BADSECT
 594:                 if (hkecc(bp, BSE))
 595:                     return;
 596:                 else
 597: #endif
 598:                     goto hard;
 599:             } else
 600:                 hktab.b_active = 0;
 601:             if (cs2&HKCS2_MDS) {
 602:                 hkaddr->hkcs2 = HKCS2_SCLR;
 603:                 goto retry;
 604:             }
 605:             recal = 0;
 606:             if (ds&HKDS_DROT || er&(HKER_OPI|HKER_SKI|HKER_UNS) ||
 607:                 (hktab.b_errcnt&07) == 4)
 608:                 recal = 1;
 609:             if ((er & (HKER_DCK|HKER_ECH)) == HKER_DCK)
 610:                 if (hkecc(bp, ECC))
 611:                     return;
 612:             hkaddr->hkcs1 = HK_CCLR;
 613:             hkaddr->hkcs2 = unit;
 614:             hkaddr->hkcs1 = hk_type[unit]|HK_DCLR|HK_GO;
 615:             hkwait(hkaddr);
 616:             if (recal && hktab.b_active == 0) {
 617:                 hkaddr->hkcs1 = hk_type[unit]|HK_IE|HK_RECAL|HK_GO;
 618:                 hk_cyl[unit] = -1;
 619:                 hk.sc_recal = 0;
 620:                 goto nextrecal;
 621:             }
 622:         }
 623: retry:
 624:         switch (hk.sc_recal) {
 625: 
 626:         case 1:
 627:             hkaddr->hkcyl = bp->b_cylin;
 628:             hk_cyl[unit] = bp->b_cylin;
 629:             hkaddr->hkcs1 = hk_type[unit]|HK_IE|HK_SEEK|HK_GO;
 630:             goto nextrecal;
 631:         case 2:
 632:             if (hktab.b_errcnt < 16 ||
 633:                 (bp->b_flags&B_READ) == 0)
 634:                 goto donerecal;
 635:             hkaddr->hkatt = hk_offset[hktab.b_errcnt & 017];
 636:             hkaddr->hkcs1 = hk_type[unit]|HK_IE|HK_OFFSET|HK_GO;
 637:             /* fall into ... */
 638:         nextrecal:
 639:             hk.sc_recal++;
 640:             hkwait(hkaddr);
 641:             hktab.b_active = 1;
 642:             return;
 643:         donerecal:
 644:         case 3:
 645:             hk.sc_recal = 0;
 646:             hktab.b_active = 0;
 647:             break;
 648:         }
 649:         if (hktab.b_active) {
 650:             hktab.b_active = 0;
 651:             hktab.b_errcnt = 0;
 652:             hktab.b_actf = dp->b_forw;
 653:             dp->b_active = 0;
 654:             dp->b_errcnt = 0;
 655:             dp->b_actf = bp->av_forw;
 656:             bp->b_resid = -(hkaddr->hkwc << 1);
 657:             iodone(bp);
 658:             if (dp->b_actf)
 659:                 if (hkustart(unit))
 660:                     needie = 0;
 661:         }
 662:         as &= ~(1<<unit);
 663:     }
 664:     for (unit = 0; as; as >>= 1, unit++)
 665:         if (as & 1) {
 666:             if (unit < NHK && (hk_dk[unit].dk_flags & DKF_ALIVE)) {
 667:                 if (hkustart(unit))
 668:                     needie = 0;
 669:             } else {
 670:                 hkaddr->hkcs1 = HK_CCLR;
 671:                 hkaddr->hkcs2 = unit;
 672:                 hkaddr->hkcs1 = HK_DCLR | HK_GO;
 673:                 hkwait(hkaddr);
 674:                 hkaddr->hkcs1 = HK_CCLR;
 675:             }
 676:         }
 677:     if (hktab.b_actf && hktab.b_active == 0)
 678:         if (hkstart())
 679:             needie = 0;
 680:     if (needie)
 681:         hkaddr->hkcs1 = HK_IE;
 682: }
 683: 
 684: #ifdef HK_DUMP
 685: /*
 686:  *  Dump routine for RK06/07
 687:  *  Dumps from dumplo to end of memory/end of disk section for minor(dev).
 688:  *  It uses the UNIBUS map to dump all of memory if there is a UNIBUS map.
 689:  */
 690: #define DBSIZE  (UBPAGE/NBPG)       /* unit of transfer, one UBPAGE */
 691: 
 692: hkdump(dev)
 693:     dev_t dev;
 694:     {
 695:     register struct hkdevice *hkaddr = HKADDR;
 696:     daddr_t bn, dumpsize;
 697:     long paddr;
 698:     register struct ubmap *ubp;
 699:     int count, memblks;
 700:     register struct partition *pi;
 701:     struct dkdevice *disk;
 702:     int com, cn, tn, sn, unit;
 703: 
 704:     unit = dkunit(dev);
 705:     if  (unit >= NHK)
 706:         return(EINVAL);
 707: 
 708:     disk = &hk_dk[unit];
 709:     if  ((disk->dk_flags & DKF_ALIVE) == 0)
 710:         return(ENXIO);
 711:     pi = &disk->dk_parts[dkpart(dev)];
 712:     if  (pi->p_fstype != FS_SWAP)
 713:         return(EFTYPE);
 714: 
 715:     dumpsize = hksize(dev) - dumplo;
 716:     memblks = ctod(physmem);
 717:     if  (dumplo < 0 || dumpsize <= 0)
 718:         return(EINVAL);
 719:     bn = dumplo + pi->p_offset;
 720: 
 721:     hkaddr->hkcs1 = HK_CCLR;
 722:     hkwait(hkaddr);
 723:     hkaddr->hkcs2 = unit;
 724:     hkaddr->hkcs1 = hk_type[unit] | HK_DCLR | HK_GO;
 725:     hkwait(hkaddr);
 726:     if  ((hkaddr->hkds & HKDS_VV) == 0)
 727:         {
 728:         hkaddr->hkcs1 = hk_type[unit]|HK_IE|HK_PACK|HK_GO;
 729:         hkwait(hkaddr);
 730:         }
 731:     ubp = &UBMAP[0];
 732:     for (paddr = 0L; memblks > 0; )
 733:         {
 734:         count = MIN(memblks, DBSIZE);
 735:         cn = bn/HK_NSPC;
 736:         sn = bn%HK_NSPC;
 737:         tn = sn/HK_NSECT;
 738:         sn = sn%HK_NSECT;
 739:         hkaddr->hkcyl = cn;
 740:         hkaddr->hkda = (tn << 8) | sn;
 741:         hkaddr->hkwc = -(count << (PGSHIFT-1));
 742:         com = hk_type[unit]|HK_GO|HK_WRITE;
 743:         if  (ubmap)
 744:             {
 745:             ubp->ub_lo = loint(paddr);
 746:             ubp->ub_hi = hiint(paddr);
 747:             hkaddr->hkba = 0;
 748:             }
 749:         else
 750:             {
 751:             /* non UNIBUS map */
 752:             hkaddr->hkba = loint(paddr);
 753:             hkaddr->hkxmem = hiint(paddr);
 754:             com |= ((paddr >> 8) & (03 << 8));
 755:             }
 756:         hkaddr->hkcs2 = unit;
 757:         hkaddr->hkcs1 = com;
 758:         hkwait(hkaddr);
 759:         if  (hkaddr->hkcs1 & HK_CERR)
 760:             {
 761:             if (hkaddr->hkcs2 & HKCS2_NEM)
 762:                 return(0);  /* made it to end of memory */
 763:             return(EIO);
 764:             }
 765:         paddr += (count << PGSHIFT);
 766:         bn += count;
 767:         memblks -= count;
 768:         }
 769:     return(0);      /* filled disk minor dev */
 770: }
 771: #endif HK_DUMP
 772: 
 773: #define exadr(x,y)  (((long)(x) << 16) | (unsigned)(y))
 774: 
 775: /*
 776:  * Correct an ECC error and restart the i/o to complete
 777:  * the transfer if necessary.  This is quite complicated because
 778:  * the transfer may be going to an odd memory address base
 779:  * and/or across a page boundary.
 780:  */
 781: hkecc(bp, flag)
 782: register struct buf *bp;
 783: {
 784:     register struct hkdevice *hkaddr = HKADDR;
 785:     ubadr_t addr;
 786:     int npx, wc;
 787:     int cn, tn, sn;
 788:     daddr_t bn;
 789:     unsigned ndone;
 790:     int cmd;
 791:     int unit;
 792: 
 793: #ifdef BADSECT
 794:     if (flag == CONT) {
 795:         npx = bp->b_error;
 796:         ndone = npx * NBPG;
 797:         wc = ((int)(ndone - bp->b_bcount)) / NBPW;
 798:     } else
 799: #endif
 800:         {
 801:         wc = hkaddr->hkwc;
 802:         ndone = (wc * NBPW) + bp->b_bcount;
 803:         npx = ndone / NBPG;
 804:         }
 805:     unit = dkunit(bp->b_dev);
 806:     bn = bp->b_blkno;
 807:     cn = bp->b_cylin - bn / HK_NSPC;
 808:     bn += npx;
 809:     cn += bn / HK_NSPC;
 810:     sn = bn % HK_NSPC;
 811:     tn = sn / HK_NSECT;
 812:     sn %= HK_NSECT;
 813:     hktab.b_active++;
 814: 
 815:     switch (flag) {
 816:     case ECC:
 817:         {
 818:         register byte;
 819:         int bit;
 820:         long mask;
 821:         ubadr_t bb;
 822:         unsigned o;
 823:         struct ubmap *ubp;
 824: 
 825:         log(LOG_WARNING, "hk%d%c:  soft ecc sn %D\n",
 826:             unit, 'a' + (bp->b_dev & 07), bp->b_blkno + npx - 1);
 827:         mask = hkaddr->hkecpt;
 828:         byte = hkaddr->hkecps - 1;
 829:         bit = byte & 07;
 830:         byte >>= 3;
 831:         mask <<= bit;
 832:         o = (ndone - NBPG) + byte;
 833:         bb = exadr(bp->b_xmem, bp->b_un.b_addr);
 834:         bb += o;
 835:         if (ubmap && (bp->b_flags & (B_MAP|B_UBAREMAP))) {
 836:             ubp = UBMAP + ((bb >> 13) & 037);
 837:             bb = exadr(ubp->ub_hi, ubp->ub_lo) + (bb & 017777);
 838:         }
 839:         /*
 840: 		 * Correct until mask is zero or until end of
 841: 		 * sector or transfer, whichever comes first.
 842: 		 */
 843:         while (byte < NBPG && o < bp->b_bcount && mask != 0) {
 844:             putmemc(bb, getmemc(bb) ^ (int)mask);
 845:             byte++;
 846:             o++;
 847:             bb++;
 848:             mask >>= 8;
 849:         }
 850:         if (wc == 0)
 851:             return(0);
 852:         break;
 853:     }
 854: 
 855: #ifdef BADSECT
 856:     case BSE:
 857:         if ((bn = isbad(&hkbad[unit], cn, tn, sn)) < 0)
 858:             return(0);
 859:         bp->b_flags |= B_BAD;
 860:         bp->b_error = npx + 1;
 861:         bn = (long)hkncyl(unit)*HK_NSPC - HK_NSECT - 1 - bn;
 862:         cn = bn/HK_NSPC;
 863:         sn = bn%HK_NSPC;
 864:         tn = sn/HK_NSECT;
 865:         sn %= HK_NSECT;
 866:         wc = -(NBPG / NBPW);
 867:         break;
 868: 
 869:     case CONT:
 870:         bp->b_flags &= ~B_BAD;
 871:         if (wc == 0)
 872:             return(0);
 873:         break;
 874: #endif BADSECT
 875:     }
 876:     /*
 877: 	 * Have to continue the transfer.  Clear the drive
 878: 	 * and compute the position where the transfer is to continue.
 879: 	 * We have completed npx sectors of the transfer already.
 880: 	 */
 881:     hkaddr->hkcs1 = HK_CCLR;
 882:     hkwait(hkaddr);
 883:     hkaddr->hkcs2 = unit;
 884:     hkaddr->hkcs1 = hk_type[unit] | HK_DCLR | HK_GO;
 885:     hkwait(hkaddr);
 886: 
 887:     addr = exadr(bp->b_xmem, bp->b_un.b_addr);
 888:     addr += ndone;
 889:     hkaddr->hkcyl = cn;
 890:     hkaddr->hkda = (tn << 8) + sn;
 891:     hkaddr->hkwc = wc;
 892:     hkaddr->hkba = (caddr_t)addr;
 893: 
 894:     if  (!ubmap)
 895:         hkaddr->hkxmem=hiint(addr);
 896:     cmd = hk_type[unit] | ((hiint(addr) & 3) << 8) | HK_IE | HK_GO;
 897:     if (bp->b_flags & B_READ)
 898:         cmd |= HK_READ;
 899:     else
 900:         cmd |= HK_WRITE;
 901:     hkaddr->hkcs1 = cmd;
 902:     hktab.b_errcnt = 0; /* error has been corrected */
 903:     return (1);
 904: }
 905: 
 906: /*
 907:  * Return the number of blocks in a partition.  Call hkopen() to read the
 908:  * label if necessary.  If an open is necessary then a matching close
 909:  * will be done.
 910: */
 911: 
 912: daddr_t
 913: hksize(dev)
 914: register dev_t dev;
 915:     {
 916:     register struct dkdevice *disk;
 917:     daddr_t psize;
 918:     int     didopen = 0;
 919: 
 920:     disk = &hk_dk[dkunit(dev)];
 921: /*
 922:  * This should never happen but if we get called early in the kernel's
 923:  * life (before opening the swap or root devices) then we have to do
 924:  * the open here.
 925: */
 926: 
 927:     if      (disk->dk_openmask == 0)
 928:         {
 929:         if      (hkopen(dev, FREAD|FWRITE, S_IFBLK))
 930:             return(-1);
 931:         didopen = 1;
 932:         }
 933:     psize = disk->dk_parts[dkpart(dev)].p_size;
 934:     if      (didopen)
 935:         hkclose(dev, FREAD|FWRITE, S_IFBLK);
 936:     return(psize);
 937:     }
 938: #endif NHK > 0

Defined functions

hkattach defined in line 104; used 1 times
hkclose defined in line 213; used 1 times
hkdfltlbl defined in line 258; used 3 times
hkdump defined in line 692; never used
hkecc defined in line 781; used 3 times
hkgetinfo defined in line 299; used 1 times
hkintr defined in line 552; used 1 times
hkopen defined in line 121; used 1 times
hkroot defined in line 98; never used
hksize defined in line 912; used 2 times
hkstart defined in line 461; used 2 times
hkstrategy defined in line 326; used 2 times
hkustart defined in line 366; used 3 times

Defined variables

HKADDR defined in line 58; used 9 times
bhkbuf defined in line 88; used 1 times
hk defined in line 80; used 8 times
hk_cyl defined in line 74; used 6 times
hk_dk defined in line 84; used 9 times
hk_dkn defined in line 92; used 12 times
hk_offset defined in line 65; used 1 times
hk_type defined in line 73; used 18 times
hkbad defined in line 87; used 2 times
hktab defined in line 82; used 29 times
hkutab defined in line 83; used 5 times

Defined struct's

hk_softc defined in line 76; never used

Defined macros

DBSIZE defined in line 690; used 1 times
HK_NSECT defined in line 54; used 13 times
HK_NSPC defined in line 56; used 12 times
HK_NTRAC defined in line 55; used 2 times
NHK6CYL defined in line 53; used 1 times
  • in line 96
NHK7CYL defined in line 52; used 1 times
  • in line 96
exadr defined in line 773; used 3 times
hkncyl defined in line 96; used 4 times
hkwait defined in line 95; used 17 times
Last modified: 1998-04-04
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 6409
Valid CSS Valid XHTML 1.0 Strict