|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 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 7.1 (Berkeley) 6/5/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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.