1 /* 2 * Copyright (c) 1982 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 6.7 (Berkeley) 02/23/86 7 */ 8 9 #include "rl.h" 10 #if NRL > 0 11 /* 12 * UNIBUS RL02 disk driver 13 */ 14 #include "../machine/pte.h" 15 16 #include "param.h" 17 #include "systm.h" 18 #include "dk.h" 19 #include "dkbad.h" 20 #include "buf.h" 21 #include "conf.h" 22 #include "dir.h" 23 #include "user.h" 24 #include "map.h" 25 #include "vm.h" 26 #include "cmap.h" 27 #include "uio.h" 28 #include "kernel.h" 29 30 #include "../vax/cpu.h" 31 #include "../vax/nexus.h" 32 #include "ubavar.h" 33 #include "ubareg.h" 34 #include "rlreg.h" 35 36 /* Pending Controller items and statistics */ 37 struct rl_softc { 38 int rl_softas; /* Attention sumary, (seeks pending) */ 39 int rl_ndrive; /* Number of drives on controller */ 40 int rl_wticks; /* Monitor time for function */ 41 } rl_softc[NHL]; 42 43 /* 44 * State of controller from last transfer. 45 * Since only one transfer can be done at a time per 46 * controller, only allocate one for each controller. 47 */ 48 struct rl_stat { 49 short rl_cyl[4]; /* Current cylinder for each drive */ 50 short rl_dn; /* drive number currently transferring */ 51 short rl_cylnhd; /* current cylinder and head of transfer */ 52 u_short rl_bleft; /* bytes left to transfer */ 53 u_short rl_bpart; /* bytes transferred */ 54 } rl_stat[NHL]; 55 56 #define rlunit(dev) (minor(dev) >> 3) 57 58 /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 59 /* Last cylinder not used. Saved for Bad Sector File */ 60 struct size { 61 daddr_t nblocks; 62 int cyloff; 63 } rl02_sizes[8] = { 64 15884, 0, /* A=cyl 0 thru 397 */ 65 4520, 398, /* B=cyl 398 thru 510 */ 66 -1, 0, /* C=cyl 0 thru 511 */ 67 4520, 398, /* D=cyl 398 thru 510 */ 68 0, 0, /* E= Not Defined */ 69 0, 0, /* F= Not Defined */ 70 20440, 0, /* G=cyl 0 thru 510 */ 71 0, 0, /* H= Not Defined */ 72 }; 73 /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 74 75 int rlprobe(), rlslave(), rlattach(), rldgo(), rlintr(); 76 struct uba_ctlr *rlminfo[NHL]; 77 struct uba_device *rldinfo[NRL]; 78 struct uba_device *rlip[NHL][4]; 79 80 /* RL02 driver structure */ 81 u_short rlstd[] = { 0174400, 0 }; 82 struct uba_driver hldriver = 83 { rlprobe, rlslave, rlattach, rldgo, rlstd, "rl", rldinfo, "hl", rlminfo }; 84 85 /* User table per controller */ 86 struct buf rlutab[NRL]; 87 88 /* RL02 drive structure */ 89 struct RL02 { 90 short nbpt; /* Number of 512 byte blocks/track */ 91 short ntrak; 92 short nbpc; /* Number of 512 byte blocks/cylinder */ 93 short ncyl; 94 short btrak; /* Number of bytes/track */ 95 struct size *sizes; 96 } rl02 = { 97 20, 2, 40, 512, 20*512, rl02_sizes /* rl02/DEC*/ 98 }; 99 100 struct buf rrlbuf[NRL]; 101 102 #define b_cylin b_resid /* Last seek as CYL<<1 | HD */ 103 104 int rlwstart, rlwatch(); /* Have started guardian */ 105 106 /* Check that controller exists */ 107 /*ARGSUSED*/ 108 rlprobe(reg) 109 caddr_t reg; 110 { 111 register int br, cvec; 112 113 #ifdef lint 114 br = 0; cvec = br; br = cvec; 115 rlintr(0); 116 #endif 117 ((struct rldevice *)reg)->rlcs = RL_IE | RL_NOOP; 118 DELAY(10); 119 ((struct rldevice *)reg)->rlcs &= ~RL_IE; 120 return (sizeof (struct rldevice)); 121 } 122 123 rlslave(ui, reg) 124 struct uba_device *ui; 125 caddr_t reg; 126 { 127 register struct rldevice *rladdr = (struct rldevice *)reg; 128 short ctr = 0; 129 130 /* 131 * DEC reports that: 132 * For some unknown reason the RL02 (seems to be only drive 1) 133 * does not return a valid drive status the first time that a 134 * GET STATUS request is issued for the drive, in fact it can 135 * take up to three or more GET STATUS requests to obtain the 136 * correct status. 137 * In order to overcome this, the driver has been modified to 138 * issue a GET STATUS request and validate the drive status 139 * returned. If a valid status is not returned after eight 140 * attempts, then an error message is printed. 141 */ 142 do { 143 rladdr->rlda.getstat = RL_RESET; 144 rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/ 145 rlwait(rladdr); 146 } while ((rladdr->rlcs & (RL_CRDY|RL_ERR)) != RL_CRDY && ++ctr < 8); 147 148 if ((rladdr->rlcs & RL_DE) || (ctr >= 8)) 149 return (0); 150 if ((rladdr->rlmp.getstat & RLMP_DT) == 0 ) { 151 printf("rl%d: rl01's not supported\n", ui->ui_slave); 152 return(0); 153 } 154 return (1); 155 } 156 157 rlattach(ui) 158 register struct uba_device *ui; 159 { 160 register struct rldevice *rladdr; 161 162 if (rlwstart == 0) { 163 timeout(rlwatch, (caddr_t)0, hz); 164 rlwstart++; 165 } 166 /* Initialize iostat values */ 167 if (ui->ui_dk >= 0) 168 dk_mspw[ui->ui_dk] = .000003906; /* 16bit transfer time? */ 169 rlip[ui->ui_ctlr][ui->ui_slave] = ui; 170 rl_softc[ui->ui_ctlr].rl_ndrive++; 171 rladdr = (struct rldevice *)ui->ui_addr; 172 /* reset controller */ 173 rladdr->rlda.getstat = RL_RESET; /* SHOULD BE REPEATED? */ 174 rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT; /* Reset DE bit */ 175 rlwait(rladdr); 176 /* determine disk posistion */ 177 rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR; 178 rlwait(rladdr); 179 /* save disk drive posistion */ 180 rl_stat[ui->ui_ctlr].rl_cyl[ui->ui_slave] = 181 (rladdr->rlmp.readhdr & 0177700) >> 6; 182 rl_stat[ui->ui_ctlr].rl_dn = -1; 183 } 184 185 rlopen(dev) 186 dev_t dev; 187 { 188 register int unit = rlunit(dev); 189 register struct uba_device *ui; 190 191 if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0) 192 return (ENXIO); 193 return (0); 194 } 195 196 rlstrategy(bp) 197 register struct buf *bp; 198 { 199 register struct uba_device *ui; 200 register int drive; 201 register struct buf *dp; 202 int partition = minor(bp->b_dev) & 07, s; 203 long bn, sz; 204 205 sz = (bp->b_bcount+511) >> 9; 206 drive = rlunit(bp->b_dev); 207 if (drive >= NRL) { 208 bp->b_error = ENXIO; 209 goto bad; 210 } 211 ui = rldinfo[drive]; 212 if (ui == 0 || ui->ui_alive == 0) { 213 bp->b_error = ENXIO; 214 goto bad; 215 } 216 if (bp->b_blkno < 0 || 217 (bn = bp->b_blkno)+sz > rl02.sizes[partition].nblocks) { 218 if (bp->b_blkno == rl02.sizes[partition].nblocks) { 219 bp->b_resid = bp->b_bcount; 220 goto done; 221 } 222 bp->b_error = EINVAL; 223 goto bad; 224 } 225 /* bn is in 512 byte block size */ 226 bp->b_cylin = bn/rl02.nbpc + rl02.sizes[partition].cyloff; 227 s = spl5(); 228 dp = &rlutab[ui->ui_unit]; 229 disksort(dp, bp); 230 if (dp->b_active == 0) { 231 rlustart(ui); 232 bp = &ui->ui_mi->um_tab; 233 if (bp->b_actf && bp->b_active == 0) 234 rlstart(ui->ui_mi); 235 } 236 splx(s); 237 return; 238 239 bad: 240 bp->b_flags |= B_ERROR; 241 done: 242 iodone(bp); 243 return; 244 } 245 246 /* 247 * Unit start routine. 248 * Seek the drive to be where the data is 249 * and then generate another interrupt 250 * to actually start the transfer. 251 */ 252 rlustart(ui) 253 register struct uba_device *ui; 254 { 255 register struct buf *bp, *dp; 256 register struct uba_ctlr *um; 257 register struct rldevice *rladdr; 258 daddr_t bn; 259 short hd, diff; 260 261 if (ui == 0) 262 return; 263 um = ui->ui_mi; 264 dk_busy &= ~(1 << ui->ui_dk); 265 dp = &rlutab[ui->ui_unit]; 266 if ((bp = dp->b_actf) == NULL) 267 return; 268 /* 269 * If the controller is active, just remember 270 * that this device has to be positioned... 271 */ 272 if (um->um_tab.b_active) { 273 rl_softc[um->um_ctlr].rl_softas |= 1<<ui->ui_slave; 274 return; 275 } 276 /* 277 * If we have already positioned this drive, 278 * then just put it on the ready queue. 279 */ 280 if (dp->b_active) 281 goto done; 282 dp->b_active = 1; /* positioning drive */ 283 rladdr = (struct rldevice *)um->um_addr; 284 285 /* 286 * Figure out where this transfer is going to 287 * and see if we are seeked correctly. 288 */ 289 bn = bp->b_blkno; /* Block # desired */ 290 /* 291 * Map 512 byte logical disk blocks 292 * to 256 byte sectors (rl02's are stupid). 293 */ 294 hd = (bn / rl02.nbpt) & 1; /* Get head required */ 295 diff = (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] >> 1) - bp->b_cylin; 296 if ( diff == 0 && (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] & 1) == hd) 297 goto done; /* on cylinder and head */ 298 /* 299 * Not at correct position. 300 */ 301 rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] = (bp->b_cylin << 1) | hd; 302 if (diff < 0) 303 rladdr->rlda.seek = -diff << 7 | RLDA_HGH | hd << 4; 304 else 305 rladdr->rlda.seek = diff << 7 | RLDA_LOW | hd << 4; 306 rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK; 307 308 /* 309 * Mark unit busy for iostat. 310 */ 311 if (ui->ui_dk >= 0) { 312 dk_busy |= 1<<ui->ui_dk; 313 dk_seek[ui->ui_dk]++; 314 } 315 rlwait(rladdr); 316 done: 317 /* 318 * Device is ready to go. 319 * Put it on the ready queue for the controller 320 * (unless its already there.) 321 */ 322 if (dp->b_active != 2) { 323 dp->b_forw = NULL; 324 if (um->um_tab.b_actf == NULL) 325 um->um_tab.b_actf = dp; 326 else 327 um->um_tab.b_actl->b_forw = dp; 328 um->um_tab.b_actl = dp; 329 dp->b_active = 2; /* Request on ready queue */ 330 } 331 } 332 333 /* 334 * Start up a transfer on a drive. 335 */ 336 rlstart(um) 337 register struct uba_ctlr *um; 338 { 339 register struct buf *bp, *dp; 340 register struct uba_device *ui; 341 register struct rldevice *rladdr; 342 register struct rl_stat *st = &rl_stat[um->um_ctlr]; 343 daddr_t bn; 344 short sn, cyl, cmd; 345 346 loop: 347 if ((dp = um->um_tab.b_actf) == NULL) { 348 st->rl_dn = -1; 349 st->rl_cylnhd = 0; 350 st->rl_bleft = 0; 351 st->rl_bpart = 0; 352 return; 353 } 354 if ((bp = dp->b_actf) == NULL) { 355 um->um_tab.b_actf = dp->b_forw; 356 goto loop; 357 } 358 /* 359 * Mark controller busy, and 360 * determine destination. 361 */ 362 um->um_tab.b_active++; 363 ui = rldinfo[rlunit(bp->b_dev)]; /* Controller */ 364 bn = bp->b_blkno; /* 512 byte Block number */ 365 cyl = bp->b_cylin << 1; /* Cylinder */ 366 cyl |= (bn / rl02.nbpt) & 1; /* Get head required */ 367 sn = (bn % rl02.nbpt) << 1; /* Sector number */ 368 rladdr = (struct rldevice *)ui->ui_addr; 369 rlwait(rladdr); 370 rladdr->rlda.rw = cyl<<6 | sn; 371 /* save away current transfers drive status */ 372 st->rl_dn = ui->ui_slave; 373 st->rl_cylnhd = cyl; 374 st->rl_bleft = bp->b_bcount; 375 st->rl_bpart = rl02.btrak - (sn * NRLBPSC); 376 /* 377 * RL02 must seek between cylinders and between tracks, 378 * determine maximum data transfer at this time. 379 */ 380 if (st->rl_bleft < st->rl_bpart) 381 st->rl_bpart = st->rl_bleft; 382 rladdr->rlmp.rw = -(st->rl_bpart >> 1); 383 if (bp->b_flags & B_READ) 384 cmd = RL_IE | RL_READ | (ui->ui_slave << 8); 385 else 386 cmd = RL_IE | RL_WRITE | (ui->ui_slave << 8); 387 um->um_cmd = cmd; 388 (void) ubago(ui); 389 } 390 391 rldgo(um) 392 register struct uba_ctlr *um; 393 { 394 register struct rldevice *rladdr = (struct rldevice *)um->um_addr; 395 396 rladdr->rlba = um->um_ubinfo; 397 rladdr->rlcs = um->um_cmd|((um->um_ubinfo>>12)&RL_BAE); 398 } 399 400 /* 401 * Handle a disk interrupt. 402 */ 403 rlintr(rl21) 404 register rl21; 405 { 406 register struct buf *bp, *dp; 407 register struct uba_ctlr *um = rlminfo[rl21]; 408 register struct uba_device *ui; 409 register struct rldevice *rladdr = (struct rldevice *)um->um_addr; 410 register unit; 411 struct rl_softc *rl = &rl_softc[um->um_ctlr]; 412 struct rl_stat *st = &rl_stat[um->um_ctlr]; 413 int as = rl->rl_softas, status; 414 415 rl->rl_wticks = 0; 416 rl->rl_softas = 0; 417 dp = um->um_tab.b_actf; 418 bp = dp->b_actf; 419 ui = rldinfo[rlunit(bp->b_dev)]; 420 dk_busy &= ~(1 << ui->ui_dk); 421 422 /* 423 * Check for and process errors on 424 * either the drive or the controller. 425 */ 426 if (rladdr->rlcs & RL_ERR) { 427 u_short err; 428 rlwait(rladdr); 429 err = rladdr->rlcs; 430 /* get staus and reset controller */ 431 rladdr->rlda.getstat = RL_GSTAT; 432 rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT; 433 rlwait(rladdr); 434 status = rladdr->rlmp.getstat; 435 /* reset drive */ 436 rladdr->rlda.getstat = RL_RESET; 437 rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/ 438 rlwait(rladdr); 439 if ((status & RLMP_WL) == RLMP_WL) { 440 /* 441 * Give up on write protected devices 442 * immediately. 443 */ 444 printf("rl%d: write protected\n", rlunit(bp->b_dev)); 445 bp->b_flags |= B_ERROR; 446 } else if (++um->um_tab.b_errcnt > 10) { 447 /* 448 * After 10 retries give up. 449 */ 450 harderr(bp, "rl"); 451 printf("cs=%b mp=%b\n", err, RLCS_BITS, 452 status, RLER_BITS); 453 bp->b_flags |= B_ERROR; 454 } else 455 um->um_tab.b_active = 0; /* force retry */ 456 /* determine disk position */ 457 rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR; 458 rlwait(rladdr); 459 /* save disk drive position */ 460 st->rl_cyl[ui->ui_slave] = 461 (rladdr->rlmp.readhdr & 0177700) >> 6; 462 } 463 /* 464 * If still ``active'', then don't need any more retries. 465 */ 466 if (um->um_tab.b_active) { 467 /* RL02 check if more data from previous request */ 468 if ((bp->b_flags & B_ERROR) == 0 && 469 (int)(st->rl_bleft -= st->rl_bpart) > 0) { 470 /* 471 * The following code was modeled from the rk07 472 * driver when an ECC error occured. It has to 473 * fix the bits then restart the transfer which is 474 * what we have to do (restart transfer). 475 */ 476 int reg, npf, o, cmd, ubaddr, diff, head; 477 478 /* seek to next head/track */ 479 /* increment head and/or cylinder */ 480 st->rl_cylnhd++; 481 diff = (st->rl_cyl[ui->ui_slave] >> 1) - 482 (st->rl_cylnhd >> 1); 483 st->rl_cyl[ui->ui_slave] = st->rl_cylnhd; 484 head = st->rl_cylnhd & 1; 485 rlwait(rladdr); 486 if (diff < 0) 487 rladdr->rlda.seek = 488 -diff << 7 | RLDA_HGH | head << 4; 489 else 490 rladdr->rlda.seek = 491 diff << 7 | RLDA_LOW | head << 4; 492 rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK; 493 npf = btop( bp->b_bcount - st->rl_bleft ); 494 reg = btop(um->um_ubinfo&0x3ffff) + npf; 495 o = (int)bp->b_un.b_addr & PGOFSET; 496 ubapurge(um); 497 um->um_tab.b_active++; 498 rlwait(rladdr); 499 rladdr->rlda.rw = st->rl_cylnhd << 6; 500 if (st->rl_bleft < (st->rl_bpart = rl02.btrak)) 501 st->rl_bpart = st->rl_bleft; 502 rladdr->rlmp.rw = -(st->rl_bpart >> 1); 503 cmd = (bp->b_flags&B_READ ? RL_READ : RL_WRITE) | 504 RL_IE | (ui->ui_slave << 8); 505 ubaddr = (int)ptob(reg) + o; 506 cmd |= ((ubaddr >> 12) & RL_BAE); 507 rladdr->rlba = ubaddr; 508 rladdr->rlcs = cmd; 509 return; 510 } 511 um->um_tab.b_active = 0; 512 um->um_tab.b_errcnt = 0; 513 dp->b_active = 0; 514 dp->b_errcnt = 0; 515 /* "b_resid" words remaining after error */ 516 bp->b_resid = st->rl_bleft; 517 um->um_tab.b_actf = dp->b_forw; 518 dp->b_actf = bp->av_forw; 519 st->rl_dn = -1; 520 st->rl_bpart = st->rl_bleft = 0; 521 iodone(bp); 522 /* 523 * If this unit has more work to do, 524 * then start it up right away. 525 */ 526 if (dp->b_actf) 527 rlustart(ui); 528 as &= ~(1<<ui->ui_slave); 529 } else 530 as |= (1<<ui->ui_slave); 531 ubadone(um); 532 /* reset state info */ 533 st->rl_dn = -1; 534 st->rl_cylnhd = st->rl_bpart = st->rl_bleft = 0; 535 /* 536 * Process other units which need attention. 537 * For each unit which needs attention, call 538 * the unit start routine to place the slave 539 * on the controller device queue. 540 */ 541 while (unit = ffs((long)as)) { 542 unit--; /* was 1 origin */ 543 as &= ~(1<<unit); 544 rlustart(rlip[rl21][unit]); 545 } 546 /* 547 * If the controller is not transferring, but 548 * there are devices ready to transfer, start 549 * the controller. 550 */ 551 if (um->um_tab.b_actf && um->um_tab.b_active == 0) 552 rlstart(um); 553 } 554 555 rlwait(rladdr) 556 register struct rldevice *rladdr; 557 { 558 559 while ((rladdr->rlcs & RL_CRDY) == 0) 560 ; 561 } 562 563 rlread(dev, uio) 564 dev_t dev; 565 struct uio *uio; 566 { 567 register int unit = rlunit(dev); 568 569 if (unit >= NRL) 570 return (ENXIO); 571 return (physio(rlstrategy, &rrlbuf[unit], dev, B_READ, minphys, uio)); 572 } 573 574 rlwrite(dev, uio) 575 dev_t dev; 576 struct uio *uio; 577 { 578 register int unit = rlunit(dev); 579 580 if (unit >= NRL) 581 return (ENXIO); 582 return (physio(rlstrategy, &rrlbuf[unit], dev, B_WRITE, minphys, uio)); 583 } 584 585 /* 586 * Reset driver after UBA init. 587 * Cancel software state of all pending transfers 588 * and restart all units and the controller. 589 */ 590 rlreset(uban) 591 int uban; 592 { 593 register struct uba_ctlr *um; 594 register struct uba_device *ui; 595 register struct rldevice *rladdr; 596 register struct rl_stat *st; 597 register int rl21, unit; 598 599 for (rl21 = 0; rl21 < NHL; rl21++) { 600 if ((um = rlminfo[rl21]) == 0 || um->um_ubanum != uban || 601 um->um_alive == 0) 602 continue; 603 printf(" hl%d", rl21); 604 rladdr = (struct rldevice *)um->um_addr; 605 st = &rl_stat[rl21]; 606 um->um_tab.b_active = 0; 607 um->um_tab.b_actf = um->um_tab.b_actl = 0; 608 if (um->um_ubinfo) { 609 printf("<%d>", (um->um_ubinfo>>28)&0xf); 610 um->um_ubinfo = 0; 611 } 612 /* reset controller */ 613 st->rl_dn = -1; 614 st->rl_cylnhd = 0; 615 st->rl_bleft = 0; 616 st->rl_bpart = 0; 617 rlwait(rladdr); 618 for (unit = 0; unit < NRL; unit++) { 619 rladdr->rlcs = (unit << 8) | RL_GETSTAT; 620 rlwait(rladdr); 621 /* Determine disk posistion */ 622 rladdr->rlcs = (unit << 8) | RL_RHDR; 623 rlwait(rladdr); 624 /* save disk drive posistion */ 625 st->rl_cyl[unit] = 626 (rladdr->rlmp.readhdr & 0177700) >> 6; 627 if ((ui = rldinfo[unit]) == 0) 628 continue; 629 if (ui->ui_alive == 0 || ui->ui_mi != um) 630 continue; 631 rlutab[unit].b_active = 0; 632 rlustart(ui); 633 } 634 rlstart(um); 635 } 636 } 637 638 /* 639 * Wake up every second and if an interrupt is pending 640 * but nothing has happened increment a counter. 641 * If nothing happens for 20 seconds, reset the UNIBUS 642 * and begin anew. 643 */ 644 rlwatch() 645 { 646 register struct uba_ctlr *um; 647 register rl21, unit; 648 register struct rl_softc *rl; 649 650 timeout(rlwatch, (caddr_t)0, hz); 651 for (rl21 = 0; rl21 < NHL; rl21++) { 652 um = rlminfo[rl21]; 653 if (um == 0 || um->um_alive == 0) 654 continue; 655 rl = &rl_softc[rl21]; 656 if (um->um_tab.b_active == 0) { 657 for (unit = 0; unit < NRL; unit++) 658 if (rlutab[unit].b_active && 659 rldinfo[unit]->ui_mi == um) 660 goto active; 661 rl->rl_wticks = 0; 662 continue; 663 } 664 active: 665 rl->rl_wticks++; 666 if (rl->rl_wticks >= 20) { 667 rl->rl_wticks = 0; 668 printf("hl%d: lost interrupt\n", rl21); 669 ubareset(um->um_ubanum); 670 } 671 } 672 } 673 674 /*ARGSUSED*/ 675 rldump(dev) 676 dev_t dev; 677 { 678 679 /* don't think there is room on swap for it anyway. */ 680 } 681 682 rlsize(dev) 683 dev_t dev; 684 { 685 register int unit = rlunit(dev); 686 register struct uba_device *ui; 687 688 if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0) 689 return (-1); 690 return (rl02.sizes[minor(dev) & 07].nblocks); 691 } 692 #endif 693