# 2.11BSD#431 - /usr/src/sys/pdpuba/rl.c

##### Functions

    rlattach          X
    rlclose           X
    rldfltlbl         X
    rldump            X
    rlgetinfo         X
    rlgsts            X
    rlintr            X
    rlio              X
    rlioctl           X
    rlopen            X
    rlroot            X
    rlsize            X
    rlstart           X
    rlstrategy        X

##### Variables

    RLADDR            X
    rl                X
    rl_dk             X
    rltab             X
    rlutab            X

##### Macros

    DBSIZE            X
    RL01_NBLKS        X
    RL02_NBLKS        X
    RLMP_MASK         X
    RLMP_OK           X
    RLUNIT            X
    RL_CYLSZ          X
    RL_SECSZ          X
    rlwait            X

##### struct's

    rl_softc          X

       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

- in line 109

rlclose defined in line 212; used 1 times

- in line 724

rldfltlbl defined in line 252; used 3 times

- in line 80, 306-311(2)

rldump defined in line 608; never used
rlfh defined in line 544; used 2 times

- in line 522, 575

rlgetinfo defined in line 292; used 1 times

- in line 181

rlgss defined in line 560; used 1 times

- in line 393

rlgsts defined in line 744; used 1 times

- in line 151

rlintr defined in line 412; used 1 times

- in /usr/src/sys/pdp/scb.s line 336

rlio defined in line 484; used 2 times

- in line 409, 465

rlioctl defined in line 584; never used
rlopen defined in line 137; used 1 times

- in line 718

rlroot defined in line 107; never used
rlseek defined in line 512; used 3 times

- in line 390, 464, 474

rlsize defined in line 702; used 2 times

- in line 78, 635

rlstart defined in line 365; used 4 times

- in line 355, 445, 451, 481

rlstrategy defined in line 320; used 3 times

- in line 79, 307, 593

#### Defined variables

RLADDR defined in line 71; used 10 times

- in line 124, 133, 146, 330, 415, 486, 520, 550, 611, 748

q22bae defined in line 73; used 4 times

- in line 126-128(2), 494, 675

rl defined in line 99; used 45 times

- in line 267, 367, 423, 433, 442, 450(2), 456-464(10), 473-474(3), 488-503(14), 521-524(3), 530, 553, 574-579(4), 763-765(2)

rl_dk defined in line 101; used 9 times

- in line 148, 220, 328, 382, 591, 625, 710, 759, 766

rl_dkn defined in line 104; used 8 times

- in line 116-117(2), 422-423(2), 498-499(2), 532-533(2)

rlsoftmap defined in line 74; used 5 times

- in line 128-129(2), 341, 477, 632

rltab defined in line 83; used 14 times

- in line 354, 372, 394-397(2), 418-420(2), 426, 436, 449, 469-471(3), 566, 580

rlutab defined in line 82; used 8 times

- in line 233-236(2), 353, 374, 473-474(2), 568-571(2)

#### 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

- in line 650

RL01_NBLKS defined in line 61; used 1 times

- in line 765

RL02_NBLKS defined in line 62; used 1 times

- in line 763

RLMP_MASK defined in line 68; used 1 times

- in line 754

RLMP_OK defined in line 69; used 1 times

- in line 754

RLUNIT defined in line 67; used 7 times

- in line 143, 216, 327, 398, 591, 621, 710

RL_CYLSZ defined in line 63; used 1 times

- in line 488

RL_SECSZ defined in line 64; used 1 times

- in line 488

rlwait defined in line 66; used 9 times

- in line 434, 443, 490, 539, 552, 645, 663, 680, 753

Last modified: 1998-04-04 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1826 |