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:  *	@(#)rl.c	1.11 (2.11BSD GTE) 1998/4/3
   7:  */
   8: 
   9: /*
  10:  *  RL01/RL02 disk driver
  11:  *
  12:  * Date: July 19, 1996
  13:  * The driver was taking the WRITE LOCK (RLMP_WL) bit to indicate
  14:  * an error, when all it really does is indicate that the disk is
  15:  * write protected.  Set up RLMP_MASK to ignore this bit.  (Tim Shoppa)
  16:  *
  17:  * Date: January 7, 1996
  18:  * Fix broken UCB_METER statistics gathering.
  19:  *
  20:  * Date: November 27, 1995
  21:  * Add support for using the software unibus/qbus map.  This allows 3rd
  22:  * party 18bit RL controllers (DSD-880) to be used in a 22bit Qbus system.
  23:  * NOTE:  I have been told that the DEC RLV11 does not properly monitor
  24:  * the I/O Page signal which means the RLV11 still can not be used.
  25:  *
  26:  * Date: August 1, 1995
  27:  * Fix bug which prevented labeling disks with no label or a corrupted label.
  28:  * Correct typographical error, the raclose() routine was being called by
  29:  * mistake in the rlsize() routine.
  30:  *
  31:  * Date: June 15, 1995.
  32:  * Modified to handle disklabels.  This provides the ability to partition
  33:  * a drive.  An RL02 can hold a root and swap partition quite easily and is
  34:  * useful for maintenance.
  35:  */
  36: 
  37: #include "rl.h"
  38: #if NRL > 0
  39: 
  40: #if NRL > 4
  41: error to have more than 4 drives - only 1 controller is supported.
  42: #endif
  43: 
  44: #include "param.h"
  45: #include "buf.h"
  46: #include "machine/seg.h"
  47: #include "user.h"
  48: #include "systm.h"
  49: #include "conf.h"
  50: #include "dk.h"
  51: #include "file.h"
  52: #include "ioctl.h"
  53: #include "stat.h"
  54: #include "map.h"
  55: #include "uba.h"
  56: #include "disklabel.h"
  57: #include "disk.h"
  58: #include "syslog.h"
  59: #include "rlreg.h"
  60: 
  61: #define RL01_NBLKS  10240   /* Number of UNIX blocks for an RL01 drive */
  62: #define RL02_NBLKS  20480   /* Number of UNIX blocks for an RL02 drive */
  63: #define RL_CYLSZ    10240   /* bytes per cylinder */
  64: #define RL_SECSZ    256 /* bytes per sector */
  65: 
  66: #define rlwait(r)   while (((r)->rlcs & RL_CRDY) == 0)
  67: #define RLUNIT(x)   (dkunit(x) & 7)
  68: #define RLMP_MASK   ( ~( RLMP_WL | RLMP_DTYP | RLMP_HSEL ) )
  69: #define RLMP_OK     ( RLMP_HO | RLMP_BH | RLMP_LCKON )
  70: 
  71: struct  rldevice *RLADDR;
  72: 
  73: static  char    q22bae;
  74: static  char    rlsoftmap = -1; /* -1 = OK to change during attach
  75: 				 *  0 = Never use soft map
  76: 				 *  1 = Always use soft map
  77: 				 */
  78:     daddr_t rlsize();
  79:     int rlstrategy();
  80:     void    rldfltlbl();
  81: 
  82: struct  buf rlutab[NRL];    /* Seek structure for each device */
  83: struct  buf rltab;
  84: 
  85: struct  rl_softc {
  86:     short   cn[4];      /* location of heads for each drive */
  87:     short   nblks[4];   /* number of blocks on drive */
  88:     short   dn;     /* drive number */
  89:     short   com;        /* read or write command word */
  90:     short   chn;        /* cylinder and head number */
  91:     u_short bleft;      /* bytes left to be transferred */
  92:     u_short bpart;      /* number of bytes transferred */
  93:     short   sn;     /* sector number */
  94:     union   {
  95:         short   w[2];
  96:         long    l;
  97:     } rl_un;        /* address of memory for transfer */
  98: 
  99: } rl = {-1,-1,-1,-1};   /* initialize cn[] */
 100: 
 101: struct  dkdevice rl_dk[NRL];
 102: 
 103: #ifdef UCB_METER
 104: static  int     rl_dkn = -1;    /* number for iostat */
 105: #endif
 106: 
 107: rlroot()
 108: {
 109:     rlattach((struct rldevice *)0174400, 0);
 110: }
 111: 
 112: rlattach(addr, unit)
 113:     register struct rldevice *addr;
 114: {
 115: #ifdef UCB_METER
 116:     if (rl_dkn < 0) {
 117:         dk_alloc(&rl_dkn, NRL, "rl", 20L * 10L * 512L);
 118:     }
 119: #endif
 120: 
 121:     if (unit != 0)
 122:         return (0);
 123:     if ((addr != (struct rldevice *)NULL) && (fioword(addr) != -1)) {
 124:         RLADDR = addr;
 125:         if (fioword(&addr->rlbae) == -1)
 126:             q22bae = -1;
 127: #ifdef  SOFUB_MAP
 128:         if (q22bae != 0 && !ubmap && rlsoftmap == -1)
 129:             rlsoftmap = 1;
 130: #endif
 131:         return (1);
 132:     }
 133:     RLADDR = (struct rldevice *)NULL;
 134:     return (0);
 135: }
 136: 
 137: rlopen(dev, flag, mode)
 138:     dev_t dev;
 139:     int flag;
 140:     int mode;
 141:     {
 142:     int i, mask;
 143:     int drive = RLUNIT(dev);
 144:     register struct dkdevice *disk;
 145: 
 146:     if  (drive >= NRL || !RLADDR)
 147:         return (ENXIO);
 148:     disk = &rl_dk[drive];
 149:     if  ((disk->dk_flags & DKF_ALIVE) == 0)
 150:         {
 151:         if  (rlgsts(drive) < 0)
 152:             return(ENXIO);
 153:         }
 154: /*
 155:  * The drive has responded to a GETSTATUS (is alive).  Now we read the
 156:  * label.  Allocate an external label structure if one has not already
 157:  * been assigned to this drive.  First wait for any pending opens/closes
 158:  * to complete.
 159: */
 160:     while   (disk->dk_flags & (DKF_OPENING | DKF_CLOSING))
 161:         sleep(disk, PRIBIO);
 162: 
 163: /*
 164:  * Next if an external label buffer has not already been allocated do so now.
 165:  * This "can not fail" because if the initial pool of label buffers has
 166:  * been exhausted the allocation takes place from main memory.  The return
 167:  * value is the 'click' address to be used when mapping in the label.
 168: */
 169: 
 170:     if  (disk->dk_label == 0)
 171:         disk->dk_label = disklabelalloc();
 172: 
 173: /*
 174:  * On first open get label and partition info.  We may block reading the
 175:  * label so be careful to stop any other opens.
 176: */
 177: 
 178:     if  (disk->dk_openmask == 0)
 179:         {
 180:         disk->dk_flags |= DKF_OPENING;
 181:         rlgetinfo(disk, dev);
 182:         disk->dk_flags &= ~DKF_OPENING;
 183:         wakeup(disk);
 184:         }
 185: /*
 186:  * Need to make sure the partition is not out of bounds.  This requires
 187:  * mapping in the external label.  This only happens when a partition
 188:  * is opened (at mount time) and isn't an efficiency problem.
 189: */
 190:     mapseg5(disk->dk_label, LABELDESC);
 191:     i = ((struct disklabel *)SEG5)->d_npartitions;
 192:     normalseg5();
 193:     if  (dkpart(dev) >= i)
 194:         return(ENXIO);
 195: 
 196:     mask = 1 << dkpart(dev);
 197:     dkoverlapchk(disk->dk_openmask, dev, disk->dk_label, "rl");
 198:     if  (mode == S_IFCHR)
 199:         disk->dk_copenmask |= mask;
 200:     else if (mode == S_IFBLK)
 201:         disk->dk_bopenmask |= mask;
 202:     else
 203:         return(EINVAL);
 204:     disk->dk_openmask |= mask;
 205:     return(0);
 206:     }
 207: 
 208: /*
 209:  * Disk drivers now have to have close entry points in order to keep
 210:  * track of what partitions are still active on a drive.
 211: */
 212: rlclose(dev, flag, mode)
 213:     register dev_t  dev;
 214:     int flag, mode;
 215:     {
 216:     int s, drive = RLUNIT(dev);
 217:     register int    mask;
 218:     register struct dkdevice *disk;
 219: 
 220:     disk = &rl_dk[drive];
 221:     mask = 1 << dkpart(dev);
 222:     if  (mode == S_IFCHR)
 223:         disk->dk_copenmask &= ~mask;
 224:     else if (mode == S_IFBLK)
 225:         disk->dk_bopenmask &= ~mask;
 226:     else
 227:         return(EINVAL);
 228:     disk->dk_openmask = disk->dk_bopenmask | disk->dk_copenmask;
 229:     if  (disk->dk_openmask == 0)
 230:         {
 231:         disk->dk_flags |= DKF_CLOSING;
 232:         s = splbio();
 233:         while   (rlutab[drive].b_actf)
 234:             {
 235:             disk->dk_flags |= DKF_WANTED;
 236:             sleep(&rlutab[drive], PRIBIO);
 237:             }
 238:         splx(s);
 239:         disk->dk_flags &= ~(DKF_CLOSING | DKF_WANTED);
 240:         wakeup(disk);
 241:         }
 242:     return(0);
 243:     }
 244: 
 245: /*
 246:  * This code was moved from rlgetinfo() because it is fairly large and used
 247:  * twice - once to initialize for reading the label and a second time if
 248:  * there is no valid label present on the drive and the default one must be
 249:  * used.
 250: */
 251: 
 252: void
 253: rldfltlbl(disk, lp, dev)
 254:     struct dkdevice *disk;
 255:     register struct disklabel *lp;
 256:     dev_t   dev;
 257:     {
 258:     register struct partition *pi = &lp->d_partitions[0];
 259: 
 260:     bzero(lp, sizeof (*lp));
 261:     lp->d_type = DTYPE_DEC;
 262:     lp->d_secsize = 512;        /* XXX */
 263:     lp->d_nsectors = 20;
 264:     lp->d_ntracks = 2;
 265:     lp->d_secpercyl = 2 * 20;
 266:     lp->d_npartitions = 1;      /* 'a' */
 267:     pi->p_size = rl.nblks[dkunit(dev)]; /* entire volume */
 268:     pi->p_fstype = FS_V71K;
 269:     pi->p_frag = 1;
 270:     pi->p_fsize = 1024;
 271: /*
 272:  * Put where rlstrategy() will look.
 273: */
 274:     bcopy(pi, disk->dk_parts, sizeof (lp->d_partitions));
 275:     }
 276: 
 277: /*
 278:  * Read disklabel.  It is tempting to generalize this routine so that
 279:  * all disk drivers could share it.  However by the time all of the
 280:  * necessary parameters are setup and passed the savings vanish.  Also,
 281:  * each driver has a different method of calculating the number of blocks
 282:  * to use if one large partition must cover the disk.
 283:  *
 284:  * This routine used to always return success and callers carefully checked
 285:  * the return status.  Silly.  This routine will fake a label (a single
 286:  * partition spanning the drive) if necessary but will never return an error.
 287:  *
 288:  * It is the caller's responsibility to check the validity of partition
 289:  * numbers, etc.
 290: */
 291: 
 292: void
 293: rlgetinfo(disk, dev)
 294:     register struct dkdevice *disk;
 295:     dev_t   dev;
 296:     {
 297:     struct  disklabel locallabel;
 298:     char    *msg;
 299:     register struct disklabel *lp = &locallabel;
 300: /*
 301:  * NOTE: partition 0 ('a') is used to read the label.  Therefore 'a' must
 302:  * start at the beginning of the disk!  If there is no label or the label
 303:  * is corrupted then 'a' will span the entire disk
 304: */
 305: 
 306:     rldfltlbl(disk, lp, dev);
 307:     msg = readdisklabel((dev & ~7) | 0, rlstrategy, lp);    /* 'a' */
 308:     if  (msg != 0)
 309:         {
 310:         log(LOG_NOTICE, "rl%da is entire disk: %s\n", dkunit(dev), msg);
 311:         rldfltlbl(disk, lp, dev);
 312:         }
 313:     mapseg5(disk->dk_label, LABELDESC)
 314:     bcopy(lp, (struct disklabel *)SEG5, sizeof (struct disklabel));
 315:     normalseg5();
 316:     bcopy(lp->d_partitions, disk->dk_parts, sizeof (lp->d_partitions));
 317:     return;
 318:     }
 319: 
 320: rlstrategy(bp)
 321:     register struct buf *bp;
 322: {
 323:     int drive;
 324:     register int    s;
 325:     register struct dkdevice *disk;
 326: 
 327:     drive = RLUNIT(bp->b_dev);
 328:     disk = &rl_dk[drive];
 329: 
 330:     if  (drive >= NRL || !RLADDR || !(disk->dk_flags & DKF_ALIVE))
 331:         {
 332:         bp->b_error = ENXIO;
 333:         goto bad;
 334:         }
 335:     s = partition_check(bp, disk);
 336:     if  (s < 0)
 337:         goto bad;
 338:     if  (s == 0)
 339:         goto done;
 340: #ifdef  SOFUB_MAP
 341:     if  (rlsoftmap == 1)
 342:         {
 343:         if  (sofub_alloc(bp) == 0)
 344:             return;
 345:         }
 346:     else
 347: #endif
 348:         mapalloc(bp);
 349: 
 350:     bp->av_forw = NULL;
 351:     bp->b_cylin = (int)(bp->b_blkno/20L);
 352:     s = splbio();
 353:     disksort(&rlutab[drive], bp);   /* Put the request on drive Q */
 354:     if  (rltab.b_active == 0)
 355:         rlstart();
 356:     splx(s);
 357:     return;
 358: bad:
 359:     bp->b_flags |= B_ERROR;
 360: done:
 361:     iodone(bp);
 362:     return;
 363: }
 364: 
 365: rlstart()
 366: {
 367:     register struct rl_softc *rlp = &rl;
 368:     register struct buf *bp, *dp;
 369:     struct  dkdevice *disk;
 370:     int unit;
 371: 
 372:     if((bp = rltab.b_actf) == NULL) {
 373:         for(unit = 0;unit < NRL;unit++) {   /* Start seeks */
 374:             dp = &rlutab[unit];
 375:             if  (dp->b_actf == NULL)
 376:                 {
 377: /*
 378:  * No more requests in the drive queue.  If a close is pending waiting
 379:  * for activity to be done on the drive then issue a wakeup and clear the
 380:  * flag.
 381: */
 382:                 disk = &rl_dk[unit];
 383:                 if  (disk->dk_flags & DKF_WANTED)
 384:                     {
 385:                     disk->dk_flags &= ~DKF_WANTED;
 386:                     wakeup(dp);
 387:                     }
 388:                 continue;
 389:                 }
 390:             rlseek((int)(dp->b_actf->b_blkno/20l),unit);
 391:         }
 392: 
 393:         rlgss();    /* Put shortest seek on Q */
 394:         if((bp = rltab.b_actf) == NULL) /* No more work */
 395:             return;
 396:     }
 397:     rltab.b_active++;
 398:     rlp->dn = RLUNIT(bp->b_dev);
 399:     rlp->chn = bp->b_blkno / 20;
 400:     rlp->sn = (bp->b_blkno % 20) << 1;
 401:     rlp->bleft = bp->b_bcount;
 402:     rlp->rl_un.w[0] = bp->b_xmem & 077;
 403:     rlp->rl_un.w[1] = (int) bp->b_un.b_addr;
 404:     rlp->com = (rlp->dn << 8) | RL_IE;
 405:     if (bp->b_flags & B_READ)
 406:         rlp->com |= RL_RCOM;
 407:     else
 408:         rlp->com |= RL_WCOM;
 409:     rlio();
 410: }
 411: 
 412: rlintr()
 413: {
 414:     register struct buf *bp;
 415:     register struct rldevice *rladdr = RLADDR;
 416:     register status;
 417: 
 418:     if (rltab.b_active == NULL)
 419:         return;
 420:     bp = rltab.b_actf;
 421: #ifdef UCB_METER
 422:     if (rl_dkn >= 0)
 423:         dk_busy &= ~(1 << (rl_dkn + rl.dn));
 424: #endif
 425:     if (rladdr->rlcs & RL_CERR) {
 426:         if (rladdr->rlcs & RL_HARDERR && rltab.b_errcnt > 2) {
 427:             harderr(bp, "rl");
 428:             log(LOG_ERR, "cs=%b da=%b\n", rladdr->rlcs, RL_BITS,
 429:                 rladdr->rlda, RLDA_BITS);
 430:         }
 431:         if (rladdr->rlcs & RL_DRE) {
 432:             rladdr->rlda = RLDA_GS;
 433:             rladdr->rlcs = (rl.dn <<  8) | RL_GETSTATUS;
 434:             rlwait(rladdr);
 435:             status = rladdr->rlmp;
 436:             if(rltab.b_errcnt > 2) {
 437:                 harderr(bp, "rl");
 438:                 log(LOG_ERR, "mp=%b da=%b\n", status, RLMP_BITS,
 439:                     rladdr->rlda, RLDA_BITS);
 440:             }
 441:             rladdr->rlda = RLDA_RESET | RLDA_GS;
 442:             rladdr->rlcs = (rl.dn << 8) | RL_GETSTATUS;
 443:             rlwait(rladdr);
 444:             if(status & RLMP_VCHK) {
 445:                 rlstart();
 446:                 return;
 447:             }
 448:         }
 449:         if (++rltab.b_errcnt <= 10) {
 450:             rl.cn[rl.dn] = -1;
 451:             rlstart();
 452:             return;
 453:         }
 454:         else {
 455:             bp->b_flags |= B_ERROR;
 456:             rl.bpart = rl.bleft;
 457:         }
 458:     }
 459: 
 460:     if ((rl.bleft -= rl.bpart) > 0) {
 461:         rl.rl_un.l += rl.bpart;
 462:         rl.sn=0;
 463:         rl.chn++;
 464:         rlseek(rl.chn,rl.dn);   /* Seek to new position */
 465:         rlio();
 466:         return;
 467:     }
 468:     bp->b_resid = 0;
 469:     rltab.b_active = NULL;
 470:     rltab.b_errcnt = 0;
 471:     rltab.b_actf = bp->av_forw;
 472: #ifdef notdef
 473:     if((bp != NULL)&&(rlutab[rl.dn].b_actf != NULL))
 474:         rlseek((int)(rlutab[rl.dn].b_actf->b_blkno/20l),rl.dn);
 475: #endif
 476: #ifdef  SOFUB_MAP
 477:     if  (rlsoftmap == 1)
 478:         sofub_relse(bp, bp->b_bcount);
 479: #endif
 480:     iodone(bp);
 481:     rlstart();
 482: }
 483: 
 484: rlio()
 485: {
 486:     register struct rldevice *rladdr = RLADDR;
 487: 
 488:     if (rl.bleft < (rl.bpart = RL_CYLSZ - (rl.sn * RL_SECSZ)))
 489:         rl.bpart = rl.bleft;
 490:     rlwait(rladdr);
 491:     rladdr->rlda = (rl.chn << 6) | rl.sn;
 492:     rladdr->rlba = (caddr_t)rl.rl_un.w[1];
 493:     rladdr->rlmp = -(rl.bpart >> 1);
 494:     if  (q22bae == 0)
 495:         rladdr->rlbae = rl.rl_un.w[0];
 496:     rladdr->rlcs = rl.com | (rl.rl_un.w[0] & 03) << 4;
 497: #ifdef UCB_METER
 498:     if (rl_dkn >= 0) {
 499:         int dkn = rl_dkn + rl.dn;
 500: 
 501:         dk_busy |= 1<<dkn;
 502:         dk_xfer[dkn]++;
 503:         dk_wds[dkn] += rl.bpart>>6;
 504:     }
 505: #endif
 506: }
 507: 
 508: /*
 509:  * Start a seek on an rl drive
 510:  * Greg Travis, April 1982 - Adapted to 2.8/2.9 BSD Oct 1982/May 1984
 511:  */
 512: static
 513: rlseek(cyl, dev)
 514:     register int cyl;
 515:     register int dev;
 516: {
 517:     struct rldevice *rp;
 518:     register int dif;
 519: 
 520:     rp = RLADDR;
 521:     if(rl.cn[dev] < 0)  /* Find the frigging heads */
 522:         rlfh(dev);
 523:     dif = (rl.cn[dev] >> 1) - (cyl >> 1);
 524:     if(dif || ((rl.cn[dev] & 01) != (cyl & 01))) {
 525:         if(dif < 0)
 526:             rp->rlda = (-dif << 7) | RLDA_SEEKHI | ((cyl & 01) << 4);
 527:         else
 528:             rp->rlda = (dif << 7) | RLDA_SEEKLO | ((cyl & 01) << 4);
 529:         rp->rlcs = (dev << 8) | RL_SEEK;
 530:         rl.cn[dev] = cyl;
 531: #ifdef UCB_METER
 532:         if (rl_dkn >= 0) {
 533:             int dkn = rl_dkn + dev;
 534: 
 535:             dk_busy |= 1<<dkn;  /* Mark unit busy */
 536:             dk_seek[dkn]++;     /* Number of seeks */
 537:         }
 538: #endif
 539:         rlwait(rp); /* Wait for command */
 540:     }
 541: }
 542: 
 543: /* Find the heads for the given drive */
 544: static
 545: rlfh(dev)
 546:     register int dev;
 547: {
 548:     register struct rldevice *rp;
 549: 
 550:     rp = RLADDR;
 551:     rp->rlcs = (dev << 8) | RL_RHDR;
 552:     rlwait(rp);
 553:     rl.cn[dev] = ((unsigned)rp->rlmp & 0177700) >> 6;
 554: }
 555: 
 556: /*
 557:  * Find the shortest seek for the current drive and put
 558:  * it on the activity queue
 559:  */
 560: static
 561: rlgss()
 562: {
 563:     register int unit, dcn;
 564:     register struct buf *dp;
 565: 
 566:     rltab.b_actf = NULL;    /* We fill this queue with up to 4 reqs */
 567:     for(unit = 0;unit < NRL;unit++) {
 568:         dp = rlutab[unit].b_actf;
 569:         if(dp == NULL)
 570:             continue;
 571:         rlutab[unit].b_actf = dp->av_forw;  /* Out */
 572:         dp->av_forw = dp->av_back = NULL;
 573:         dcn = (dp->b_blkno/20) >> 1;
 574:         if(rl.cn[unit] < 0)
 575:             rlfh(unit);
 576:         if(dcn < rl.cn[unit])
 577:             dp->b_cylin = (rl.cn[unit] >> 1) - dcn;
 578:         else
 579:             dp->b_cylin = dcn - (rl.cn[unit] >> 1);
 580:         disksort(&rltab, dp);   /* Put the request on the current q */
 581:     }
 582: }
 583: 
 584: rlioctl(dev, cmd, data, flag)
 585:     dev_t   dev;
 586:     int cmd;
 587:     caddr_t data;
 588:     int flag;
 589:     {
 590:     register int    error;
 591:     struct  dkdevice *disk = &rl_dk[RLUNIT(dev)];
 592: 
 593:     error = ioctldisklabel(dev, cmd, data, flag, disk, rlstrategy);
 594:     return(error);
 595:     }
 596: 
 597: #ifdef RL_DUMP
 598: /*
 599:  * Dump routine for RL01/02
 600:  * This routine is stupid (because the rl is stupid) and assumes that
 601:  * dumplo begins on a track boundary!
 602:  */
 603: 
 604: #define DBSIZE  10  /* Half a track of sectors.  Can't go higher
 605: 			 * because only a single UMR is set for the transfer.
 606: 			 */
 607: 
 608: rldump(dev)
 609:     dev_t dev;
 610: {
 611:     register struct rldevice *rladdr = RLADDR;
 612:     struct  dkdevice *disk;
 613:     struct  partition *pi;
 614:     daddr_t bn, dumpsize;
 615:     long paddr;
 616:     int count, memblks;
 617:     u_int com;
 618:     int ccn, cn, tn, sn, unit, dif, partition;
 619:     register struct ubmap *ubp;
 620: 
 621:     unit = RLUNIT(dev);
 622:     if  (unit >= NRL)
 623:         return(EINVAL);
 624:     partition = dkpart(dev);
 625:     disk = &rl_dk[unit];
 626:     pi = &disk->dk_parts[partition];
 627: 
 628:     if  (!(disk->dk_flags & DKF_ALIVE))
 629:         return(ENXIO);
 630:     if  (pi->p_fstype != FS_SWAP)
 631:         return(EFTYPE);
 632:     if  (rlsoftmap == 1)    /* No crash dumps via soft map */
 633:         return(EFAULT);
 634: 
 635:     dumpsize = rlsize(dev) - dumplo;
 636:     memblks = ctod(physmem);
 637: 
 638:     if  (dumplo < 0 || dumpsize <= 0)
 639:         return(EINVAL);
 640:     if  (memblks > dumpsize)
 641:         memblks = dumpsize;
 642:     bn = dumplo + pi->p_offset;
 643: 
 644:     rladdr->rlcs = (dev << 8) | RL_RHDR;    /* Find the heads */
 645:     rlwait(rladdr);
 646:     ccn = ((unsigned)rladdr->rlmp&0177700) >> 6;
 647: 
 648:     ubp = &UBMAP[0];
 649:     for (paddr = 0L; memblks > 0; ) {
 650:         count = MIN(memblks, DBSIZE);
 651:         cn = bn / 20;
 652:         sn = (unsigned)(bn % 20) << 1;
 653:         dif = (ccn >> 1) - (cn >> 1);
 654:         if(dif || ((ccn & 01) != (cn & 01))) {
 655:             if(dif < 0)
 656:                 rladdr->rlda = (-dif << 7) | RLDA_SEEKHI |
 657:                     ((cn & 01) << 4);
 658:             else
 659:                 rladdr->rlda = (dif << 7) | RLDA_SEEKLO |
 660:                     ((cn & 01) << 4);
 661:             rladdr->rlcs = (dev << 8) | RL_SEEK;
 662:             ccn = cn;
 663:             rlwait(rladdr);
 664:         }
 665:         rladdr->rlda = (cn << 6) | sn;
 666:         rladdr->rlmp = -(count << (PGSHIFT-1));
 667:         com = (dev << 8) | RL_WCOM;
 668:         /* If there is a map - use it */
 669:         if(ubmap) {
 670:             ubp->ub_lo = loint(paddr);
 671:             ubp->ub_hi = hiint(paddr);
 672:             rladdr->rlba = 0;
 673:         } else {
 674:             rladdr->rlba = loint(paddr);
 675:             if  (q22bae == 0)
 676:                 rladdr->rlbae = hiint(paddr);
 677:             com |= (hiint(paddr) & 03) << 4;
 678:         }
 679:         rladdr->rlcs = com;
 680:         rlwait(rladdr);
 681:         if(rladdr->rlcs & RL_CERR) {
 682:             if(rladdr->rlcs & RL_NXM)
 683:                 return(0);  /* End of memory */
 684:             log(LOG_ERR, "rl%d: dmp err, cs=%b da=%b mp=%b\n",
 685:                 dev,rladdr->rlcs,RL_BITS,rladdr->rlda,
 686:                 RLDA_BITS, rladdr->rlmp, RLMP_BITS);
 687:             return(EIO);
 688:         }
 689:         paddr += (count << PGSHIFT);
 690:         bn += count;
 691:         memblks -= count;
 692:     }
 693:     return(0);  /* Filled the disk */
 694: }
 695: #endif RL_DUMP
 696: 
 697: /*
 698:  * Return the number of blocks in a partition.  Call rlopen() to online
 699:  * the drive if necessary.  If an open is necessary then a matching close
 700:  * will be done.
 701: */
 702: daddr_t
 703: rlsize(dev)
 704:     register dev_t dev;
 705:     {
 706:     register struct dkdevice *disk;
 707:     daddr_t psize;
 708:     int didopen = 0;
 709: 
 710:     disk = &rl_dk[RLUNIT(dev)];
 711: /*
 712:  * This should never happen but if we get called early in the kernel's
 713:  * life (before opening the swap or root devices) then we have to do
 714:  * the open here.
 715: */
 716:     if  (disk->dk_openmask == 0)
 717:         {
 718:         if  (rlopen(dev, FREAD|FWRITE, S_IFBLK))
 719:             return(-1);
 720:         didopen = 1;
 721:         }
 722:     psize = disk->dk_parts[dkpart(dev)].p_size;
 723:     if  (didopen)
 724:         rlclose(dev, FREAD|FWRITE, S_IFBLK);
 725:     return(psize);
 726:     }
 727: 
 728: /*
 729:  * This routine is only called by rlopen() the first time a drive is
 730:  * touched.  Once the number of blocks has been determined the drive is
 731:  * marked 'alive'.
 732:  *
 733:  * For some unknown reason the RL02 (seems to be
 734:  * only drive 1) does not return a valid drive status
 735:  * the first time that a GET STATUS request is issued
 736:  * for the drive, in fact it can take up to three or more
 737:  * GET STATUS requests to obtain the correct status.
 738:  * In order to overcome this "HACK" the driver has been
 739:  * modified to issue a GET STATUS request, validate the
 740:  * drive status returned, and then use it to determine the
 741:  * drive type. If a valid status is not returned after eight
 742:  * attempts, then an error message is printed.
 743:  */
 744: rlgsts(drive)
 745:     register int    drive;
 746:     {
 747:     register int    ctr = 0;
 748:     register struct rldevice *rp = RLADDR;
 749: 
 750:     do  { /* get status and reset when first touching this drive */
 751:         rp->rlda = RLDA_RESET | RLDA_GS;
 752:         rp->rlcs = (drive << 8) | RL_GETSTATUS; /* set up csr */
 753:         rlwait(rp);
 754:         } while (((rp->rlmp & RLMP_MASK) != RLMP_OK) && (++ctr < 16));
 755:     if  (ctr >= 16)
 756:         {
 757:         log(LOG_ERR, "rl%d: !sts cs=%b da=%b\n", drive,
 758:             rp->rlcs, RL_BITS, rp->rlda, RLDA_BITS);
 759:         rl_dk[drive].dk_flags &= ~DKF_ALIVE;
 760:         return(-1);
 761:         }
 762:     if  (rp->rlmp & RLMP_DTYP)
 763:         rl.nblks[drive] = RL02_NBLKS;   /* drive is RL02 */
 764:     else
 765:         rl.nblks[drive] = RL01_NBLKS;   /* drive RL01 */
 766:     rl_dk[drive].dk_flags |= DKF_ALIVE;
 767:     return(0);
 768:     }
 769: #endif /* NRL */

Defined functions

rlattach defined in line 112; used 1 times
rlclose defined in line 212; used 1 times
rldfltlbl defined in line 252; used 3 times
rldump defined in line 608; never used
rlfh defined in line 544; used 2 times
rlgetinfo defined in line 292; used 1 times
rlgss defined in line 560; used 1 times
rlgsts defined in line 744; used 1 times
rlintr defined in line 412; used 1 times
rlio defined in line 484; used 2 times
rlioctl defined in line 584; never used
rlopen defined in line 137; used 1 times
rlroot defined in line 107; never used
rlseek defined in line 512; used 3 times
rlsize defined in line 702; used 2 times
rlstart defined in line 365; used 4 times
rlstrategy defined in line 320; used 3 times

Defined variables

RLADDR defined in line 71; used 10 times
q22bae defined in line 73; used 4 times
rl defined in line 99; used 45 times
rl_dk defined in line 101; used 9 times
rl_dkn defined in line 104; used 8 times
rlsoftmap defined in line 74; used 5 times
rltab defined in line 83; used 14 times
rlutab defined in line 82; used 8 times

Defined struct's

rl_softc defined in line 85; used 2 times
  • in line 367(2)

Defined macros

DBSIZE defined in line 604; used 1 times
RL01_NBLKS defined in line 61; used 1 times
RL02_NBLKS defined in line 62; used 1 times
RLMP_MASK defined in line 68; used 1 times
RLMP_OK defined in line 69; used 1 times
RLUNIT defined in line 67; used 7 times
RL_CYLSZ defined in line 63; used 1 times
RL_SECSZ defined in line 64; used 1 times
rlwait defined in line 66; used 9 times
Last modified: 1998-04-04
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4832
Valid CSS Valid XHTML 1.0 Strict