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 */