123338Smckusick /*
229238Smckusick * Copyright (c) 1982, 1986 Regents of the University of California.
323338Smckusick * All rights reserved. The Berkeley software License Agreement
423338Smckusick * specifies the terms and conditions for redistribution.
523338Smckusick *
6*45805Sbostic * @(#)rl.c 7.10 (Berkeley) 12/16/90
723338Smckusick */
810770Ssam
910770Ssam #include "rl.h"
1012452Ssam #if NRL > 0
1110770Ssam /*
1210770Ssam * UNIBUS RL02 disk driver
1310770Ssam */
14*45805Sbostic #include "../include/pte.h"
1510770Ssam
16*45805Sbostic #include "sys/param.h"
17*45805Sbostic #include "sys/systm.h"
18*45805Sbostic #include "sys/dkstat.h"
19*45805Sbostic #include "sys/dkbad.h"
20*45805Sbostic #include "sys/ioctl.h"
21*45805Sbostic #include "sys/disklabel.h"
22*45805Sbostic #include "sys/buf.h"
23*45805Sbostic #include "sys/conf.h"
24*45805Sbostic #include "sys/user.h"
25*45805Sbostic #include "sys/map.h"
26*45805Sbostic #include "sys/vm.h"
27*45805Sbostic #include "sys/cmap.h"
28*45805Sbostic #include "sys/uio.h"
29*45805Sbostic #include "sys/kernel.h"
30*45805Sbostic #include "sys/syslog.h"
3110770Ssam
32*45805Sbostic #include "../include/cpu.h"
3313091Ssam #include "../vax/nexus.h"
3417077Sbloom #include "ubavar.h"
3517077Sbloom #include "ubareg.h"
3617077Sbloom #include "rlreg.h"
3710770Ssam
3810770Ssam /* Pending Controller items and statistics */
3910770Ssam struct rl_softc {
4010770Ssam int rl_softas; /* Attention sumary, (seeks pending) */
4110770Ssam int rl_ndrive; /* Number of drives on controller */
4210770Ssam int rl_wticks; /* Monitor time for function */
4310770Ssam } rl_softc[NHL];
4410770Ssam
4510770Ssam /*
4613091Ssam * State of controller from last transfer.
4713091Ssam * Since only one transfer can be done at a time per
4810770Ssam * controller, only allocate one for each controller.
4910770Ssam */
5010770Ssam struct rl_stat {
5110770Ssam short rl_cyl[4]; /* Current cylinder for each drive */
5210770Ssam short rl_dn; /* drive number currently transferring */
5310770Ssam short rl_cylnhd; /* current cylinder and head of transfer */
5410770Ssam u_short rl_bleft; /* bytes left to transfer */
5510770Ssam u_short rl_bpart; /* bytes transferred */
5610770Ssam } rl_stat[NHL];
5710770Ssam
5824741Sbloom #define rlunit(dev) (minor(dev) >> 3)
5924741Sbloom
6010770Ssam /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
6113091Ssam /* Last cylinder not used. Saved for Bad Sector File */
6210770Ssam struct size {
6310770Ssam daddr_t nblocks;
6410770Ssam int cyloff;
6510770Ssam } rl02_sizes[8] = {
6613091Ssam 15884, 0, /* A=cyl 0 thru 397 */
6713091Ssam 4520, 398, /* B=cyl 398 thru 510 */
6813091Ssam -1, 0, /* C=cyl 0 thru 511 */
6913091Ssam 4520, 398, /* D=cyl 398 thru 510 */
7017431Skarels 0, 0, /* E= Not Defined */
7110770Ssam 0, 0, /* F= Not Defined */
7213091Ssam 20440, 0, /* G=cyl 0 thru 510 */
7310770Ssam 0, 0, /* H= Not Defined */
7410770Ssam };
7510770Ssam /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
7610770Ssam
7710770Ssam int rlprobe(), rlslave(), rlattach(), rldgo(), rlintr();
7810770Ssam struct uba_ctlr *rlminfo[NHL];
7910770Ssam struct uba_device *rldinfo[NRL];
8010770Ssam struct uba_device *rlip[NHL][4];
8110770Ssam
8210770Ssam /* RL02 driver structure */
8317431Skarels u_short rlstd[] = { 0174400, 0 };
8410770Ssam struct uba_driver hldriver =
8510770Ssam { rlprobe, rlslave, rlattach, rldgo, rlstd, "rl", rldinfo, "hl", rlminfo };
8610770Ssam
8710770Ssam /* User table per controller */
8810770Ssam struct buf rlutab[NRL];
8910770Ssam
9010770Ssam /* RL02 drive structure */
9110770Ssam struct RL02 {
9210770Ssam short nbpt; /* Number of 512 byte blocks/track */
9310770Ssam short ntrak;
9410770Ssam short nbpc; /* Number of 512 byte blocks/cylinder */
9510770Ssam short ncyl;
9610770Ssam short btrak; /* Number of bytes/track */
9710770Ssam struct size *sizes;
9810770Ssam } rl02 = {
9910770Ssam 20, 2, 40, 512, 20*512, rl02_sizes /* rl02/DEC*/
10010770Ssam };
10110770Ssam
10210770Ssam #define b_cylin b_resid /* Last seek as CYL<<1 | HD */
10310770Ssam
10410770Ssam int rlwstart, rlwatch(); /* Have started guardian */
10510770Ssam
10610770Ssam /* Check that controller exists */
10710770Ssam /*ARGSUSED*/
rlprobe(reg)10810770Ssam rlprobe(reg)
10910770Ssam caddr_t reg;
11010770Ssam {
11110770Ssam register int br, cvec;
11210770Ssam
11310770Ssam #ifdef lint
11410770Ssam br = 0; cvec = br; br = cvec;
11513091Ssam rlintr(0);
11610770Ssam #endif
11713091Ssam ((struct rldevice *)reg)->rlcs = RL_IE | RL_NOOP;
11813091Ssam DELAY(10);
11913091Ssam ((struct rldevice *)reg)->rlcs &= ~RL_IE;
12012452Ssam return (sizeof (struct rldevice));
12110770Ssam }
12210770Ssam
12310770Ssam rlslave(ui, reg)
12410770Ssam struct uba_device *ui;
12510770Ssam caddr_t reg;
12610770Ssam {
12710770Ssam register struct rldevice *rladdr = (struct rldevice *)reg;
12810770Ssam short ctr = 0;
12910770Ssam
13010770Ssam /*
13110770Ssam * DEC reports that:
13210770Ssam * For some unknown reason the RL02 (seems to be only drive 1)
13310770Ssam * does not return a valid drive status the first time that a
13410770Ssam * GET STATUS request is issued for the drive, in fact it can
13510770Ssam * take up to three or more GET STATUS requests to obtain the
13610770Ssam * correct status.
13710770Ssam * In order to overcome this, the driver has been modified to
13810770Ssam * issue a GET STATUS request and validate the drive status
13910770Ssam * returned. If a valid status is not returned after eight
14010770Ssam * attempts, then an error message is printed.
14110770Ssam */
14210770Ssam do {
14310770Ssam rladdr->rlda.getstat = RL_RESET;
14410770Ssam rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/
14510770Ssam rlwait(rladdr);
14617431Skarels } while ((rladdr->rlcs & (RL_CRDY|RL_ERR)) != RL_CRDY && ++ctr < 8);
14717431Skarels
14810770Ssam if ((rladdr->rlcs & RL_DE) || (ctr >= 8))
14917431Skarels return (0);
15013091Ssam if ((rladdr->rlmp.getstat & RLMP_DT) == 0 ) {
15113091Ssam printf("rl%d: rl01's not supported\n", ui->ui_slave);
15210770Ssam return(0);
15310770Ssam }
15410770Ssam return (1);
15510770Ssam }
15610770Ssam
rlattach(ui)15710770Ssam rlattach(ui)
15810770Ssam register struct uba_device *ui;
15910770Ssam {
16010770Ssam register struct rldevice *rladdr;
16110770Ssam
16210770Ssam if (rlwstart == 0) {
16313091Ssam timeout(rlwatch, (caddr_t)0, hz);
16410770Ssam rlwstart++;
16510770Ssam }
16610770Ssam /* Initialize iostat values */
16710770Ssam if (ui->ui_dk >= 0)
16838175Smckusick dk_wpms[ui->ui_dk] = 256016; /* 16bit transfer time? */
16910770Ssam rlip[ui->ui_ctlr][ui->ui_slave] = ui;
17013091Ssam rl_softc[ui->ui_ctlr].rl_ndrive++;
17110770Ssam rladdr = (struct rldevice *)ui->ui_addr;
17210770Ssam /* reset controller */
17310770Ssam rladdr->rlda.getstat = RL_RESET; /* SHOULD BE REPEATED? */
17410770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT; /* Reset DE bit */
17510770Ssam rlwait(rladdr);
17613091Ssam /* determine disk posistion */
17710770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR;
17810770Ssam rlwait(rladdr);
17910770Ssam /* save disk drive posistion */
18010770Ssam rl_stat[ui->ui_ctlr].rl_cyl[ui->ui_slave] =
18113091Ssam (rladdr->rlmp.readhdr & 0177700) >> 6;
18210770Ssam rl_stat[ui->ui_ctlr].rl_dn = -1;
18310770Ssam }
18410770Ssam
rlopen(dev)18512452Ssam rlopen(dev)
18612452Ssam dev_t dev;
18712452Ssam {
18824741Sbloom register int unit = rlunit(dev);
18913091Ssam register struct uba_device *ui;
19012452Ssam
19112452Ssam if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0)
19212452Ssam return (ENXIO);
19312452Ssam return (0);
19412452Ssam }
19512452Ssam
rlstrategy(bp)19610770Ssam rlstrategy(bp)
19710770Ssam register struct buf *bp;
19810770Ssam {
19910770Ssam register struct uba_device *ui;
20010770Ssam register int drive;
20110770Ssam register struct buf *dp;
20213091Ssam int partition = minor(bp->b_dev) & 07, s;
20310770Ssam long bn, sz;
20410770Ssam
20513091Ssam sz = (bp->b_bcount+511) >> 9;
20624741Sbloom drive = rlunit(bp->b_dev);
20724741Sbloom if (drive >= NRL) {
20824741Sbloom bp->b_error = ENXIO;
20910770Ssam goto bad;
21024741Sbloom }
21113091Ssam ui = rldinfo[drive];
21224741Sbloom if (ui == 0 || ui->ui_alive == 0) {
21324741Sbloom bp->b_error = ENXIO;
21410770Ssam goto bad;
21524741Sbloom }
21610770Ssam if (bp->b_blkno < 0 ||
21724741Sbloom (bn = bp->b_blkno)+sz > rl02.sizes[partition].nblocks) {
21824786Skarels if (bp->b_blkno == rl02.sizes[partition].nblocks) {
21924786Skarels bp->b_resid = bp->b_bcount;
22024741Sbloom goto done;
22124786Skarels }
22224741Sbloom bp->b_error = EINVAL;
22310770Ssam goto bad;
22424741Sbloom }
22510770Ssam /* bn is in 512 byte block size */
22610770Ssam bp->b_cylin = bn/rl02.nbpc + rl02.sizes[partition].cyloff;
22713091Ssam s = spl5();
22810770Ssam dp = &rlutab[ui->ui_unit];
22910770Ssam disksort(dp, bp);
23010770Ssam if (dp->b_active == 0) {
23113091Ssam rlustart(ui);
23210770Ssam bp = &ui->ui_mi->um_tab;
23310770Ssam if (bp->b_actf && bp->b_active == 0)
23413091Ssam rlstart(ui->ui_mi);
23510770Ssam }
23613091Ssam splx(s);
23710770Ssam return;
23810770Ssam
23910770Ssam bad:
24010770Ssam bp->b_flags |= B_ERROR;
24124741Sbloom done:
24210770Ssam iodone(bp);
24310770Ssam return;
24410770Ssam }
24510770Ssam
24610770Ssam /*
24710770Ssam * Unit start routine.
24810770Ssam * Seek the drive to be where the data is
24910770Ssam * and then generate another interrupt
25010770Ssam * to actually start the transfer.
25110770Ssam */
rlustart(ui)25210770Ssam rlustart(ui)
25310770Ssam register struct uba_device *ui;
25410770Ssam {
25510770Ssam register struct buf *bp, *dp;
25610770Ssam register struct uba_ctlr *um;
25710770Ssam register struct rldevice *rladdr;
25810770Ssam daddr_t bn;
25913091Ssam short hd, diff;
26010770Ssam
26110770Ssam if (ui == 0)
26213091Ssam return;
26310770Ssam um = ui->ui_mi;
26413091Ssam dk_busy &= ~(1 << ui->ui_dk);
26510770Ssam dp = &rlutab[ui->ui_unit];
26610770Ssam if ((bp = dp->b_actf) == NULL)
26713091Ssam return;
26810770Ssam /*
26910770Ssam * If the controller is active, just remember
27010770Ssam * that this device has to be positioned...
27110770Ssam */
27210770Ssam if (um->um_tab.b_active) {
27310770Ssam rl_softc[um->um_ctlr].rl_softas |= 1<<ui->ui_slave;
27413091Ssam return;
27510770Ssam }
27610770Ssam /*
27710770Ssam * If we have already positioned this drive,
27810770Ssam * then just put it on the ready queue.
27910770Ssam */
28010770Ssam if (dp->b_active)
28110770Ssam goto done;
28213091Ssam dp->b_active = 1; /* positioning drive */
28310770Ssam rladdr = (struct rldevice *)um->um_addr;
28410770Ssam
28510770Ssam /*
28610770Ssam * Figure out where this transfer is going to
28710770Ssam * and see if we are seeked correctly.
28810770Ssam */
28924741Sbloom bn = bp->b_blkno; /* Block # desired */
29010770Ssam /*
29113091Ssam * Map 512 byte logical disk blocks
29213091Ssam * to 256 byte sectors (rl02's are stupid).
29310770Ssam */
29410770Ssam hd = (bn / rl02.nbpt) & 1; /* Get head required */
29510770Ssam diff = (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] >> 1) - bp->b_cylin;
29610770Ssam if ( diff == 0 && (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] & 1) == hd)
29710770Ssam goto done; /* on cylinder and head */
29810770Ssam /*
29910770Ssam * Not at correct position.
30010770Ssam */
30110770Ssam rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] = (bp->b_cylin << 1) | hd;
30210770Ssam if (diff < 0)
30310770Ssam rladdr->rlda.seek = -diff << 7 | RLDA_HGH | hd << 4;
30410770Ssam else
30510770Ssam rladdr->rlda.seek = diff << 7 | RLDA_LOW | hd << 4;
30610770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK;
30710770Ssam
30810770Ssam /*
30910770Ssam * Mark unit busy for iostat.
31010770Ssam */
31110770Ssam if (ui->ui_dk >= 0) {
31210770Ssam dk_busy |= 1<<ui->ui_dk;
31310770Ssam dk_seek[ui->ui_dk]++;
31410770Ssam }
31512452Ssam rlwait(rladdr);
31610770Ssam done:
31710770Ssam /*
31810770Ssam * Device is ready to go.
31910770Ssam * Put it on the ready queue for the controller
32010770Ssam * (unless its already there.)
32110770Ssam */
32210770Ssam if (dp->b_active != 2) {
32310770Ssam dp->b_forw = NULL;
32410770Ssam if (um->um_tab.b_actf == NULL)
32510770Ssam um->um_tab.b_actf = dp;
32610770Ssam else
32710770Ssam um->um_tab.b_actl->b_forw = dp;
32810770Ssam um->um_tab.b_actl = dp;
32910770Ssam dp->b_active = 2; /* Request on ready queue */
33010770Ssam }
33110770Ssam }
33210770Ssam
33310770Ssam /*
33410770Ssam * Start up a transfer on a drive.
33510770Ssam */
rlstart(um)33610770Ssam rlstart(um)
33710770Ssam register struct uba_ctlr *um;
33810770Ssam {
33910770Ssam register struct buf *bp, *dp;
34010770Ssam register struct uba_device *ui;
34110770Ssam register struct rldevice *rladdr;
34210770Ssam register struct rl_stat *st = &rl_stat[um->um_ctlr];
34310770Ssam daddr_t bn;
34410770Ssam short sn, cyl, cmd;
34510770Ssam
34610770Ssam loop:
34710770Ssam if ((dp = um->um_tab.b_actf) == NULL) {
34810770Ssam st->rl_dn = -1;
34910770Ssam st->rl_cylnhd = 0;
35010770Ssam st->rl_bleft = 0;
35110770Ssam st->rl_bpart = 0;
35213091Ssam return;
35310770Ssam }
35410770Ssam if ((bp = dp->b_actf) == NULL) {
35510770Ssam um->um_tab.b_actf = dp->b_forw;
35610770Ssam goto loop;
35710770Ssam }
35810770Ssam /*
35910770Ssam * Mark controller busy, and
36013091Ssam * determine destination.
36110770Ssam */
36210770Ssam um->um_tab.b_active++;
36324741Sbloom ui = rldinfo[rlunit(bp->b_dev)]; /* Controller */
36424741Sbloom bn = bp->b_blkno; /* 512 byte Block number */
36510770Ssam cyl = bp->b_cylin << 1; /* Cylinder */
36610770Ssam cyl |= (bn / rl02.nbpt) & 1; /* Get head required */
36710770Ssam sn = (bn % rl02.nbpt) << 1; /* Sector number */
36810770Ssam rladdr = (struct rldevice *)ui->ui_addr;
36912452Ssam rlwait(rladdr);
37010770Ssam rladdr->rlda.rw = cyl<<6 | sn;
37110770Ssam /* save away current transfers drive status */
37210770Ssam st->rl_dn = ui->ui_slave;
37310770Ssam st->rl_cylnhd = cyl;
37410770Ssam st->rl_bleft = bp->b_bcount;
37510770Ssam st->rl_bpart = rl02.btrak - (sn * NRLBPSC);
37613091Ssam /*
37713091Ssam * RL02 must seek between cylinders and between tracks,
37813091Ssam * determine maximum data transfer at this time.
37913091Ssam */
38013091Ssam if (st->rl_bleft < st->rl_bpart)
38110770Ssam st->rl_bpart = st->rl_bleft;
38210770Ssam rladdr->rlmp.rw = -(st->rl_bpart >> 1);
38310770Ssam if (bp->b_flags & B_READ)
38410770Ssam cmd = RL_IE | RL_READ | (ui->ui_slave << 8);
38510770Ssam else
38610770Ssam cmd = RL_IE | RL_WRITE | (ui->ui_slave << 8);
38710770Ssam um->um_cmd = cmd;
38810770Ssam (void) ubago(ui);
38910770Ssam }
39010770Ssam
rldgo(um)39110770Ssam rldgo(um)
39210770Ssam register struct uba_ctlr *um;
39310770Ssam {
39410770Ssam register struct rldevice *rladdr = (struct rldevice *)um->um_addr;
39510770Ssam
39610770Ssam rladdr->rlba = um->um_ubinfo;
39710770Ssam rladdr->rlcs = um->um_cmd|((um->um_ubinfo>>12)&RL_BAE);
39810770Ssam }
39910770Ssam
40010770Ssam /*
40110770Ssam * Handle a disk interrupt.
40210770Ssam */
rlintr(rl21)40310770Ssam rlintr(rl21)
40410770Ssam register rl21;
40510770Ssam {
40610770Ssam register struct buf *bp, *dp;
40710770Ssam register struct uba_ctlr *um = rlminfo[rl21];
40810770Ssam register struct uba_device *ui;
40910770Ssam register struct rldevice *rladdr = (struct rldevice *)um->um_addr;
41010770Ssam register unit;
41110770Ssam struct rl_softc *rl = &rl_softc[um->um_ctlr];
41210770Ssam struct rl_stat *st = &rl_stat[um->um_ctlr];
41313091Ssam int as = rl->rl_softas, status;
41410770Ssam
41510770Ssam rl->rl_wticks = 0;
41610770Ssam rl->rl_softas = 0;
41710770Ssam dp = um->um_tab.b_actf;
41810770Ssam bp = dp->b_actf;
41924741Sbloom ui = rldinfo[rlunit(bp->b_dev)];
42013091Ssam dk_busy &= ~(1 << ui->ui_dk);
42110770Ssam
42210770Ssam /*
42310770Ssam * Check for and process errors on
42410770Ssam * either the drive or the controller.
42510770Ssam */
42610770Ssam if (rladdr->rlcs & RL_ERR) {
42710770Ssam u_short err;
42813091Ssam rlwait(rladdr);
42910770Ssam err = rladdr->rlcs;
43010770Ssam /* get staus and reset controller */
43110770Ssam rladdr->rlda.getstat = RL_GSTAT;
43210770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT;
43310770Ssam rlwait(rladdr);
43410770Ssam status = rladdr->rlmp.getstat;
43510770Ssam /* reset drive */
43610770Ssam rladdr->rlda.getstat = RL_RESET;
43710770Ssam rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/
43810770Ssam rlwait(rladdr);
43913091Ssam if ((status & RLMP_WL) == RLMP_WL) {
44010770Ssam /*
44110770Ssam * Give up on write protected devices
44210770Ssam * immediately.
44310770Ssam */
44424741Sbloom printf("rl%d: write protected\n", rlunit(bp->b_dev));
44510770Ssam bp->b_flags |= B_ERROR;
44610770Ssam } else if (++um->um_tab.b_errcnt > 10) {
44710770Ssam /*
44810770Ssam * After 10 retries give up.
44910770Ssam */
45034524Skarels diskerr(bp, "rl", "hard error", LOG_PRINTF, -1,
45134524Skarels (struct disklabel *)0);
45234524Skarels printf(" cs=%b mp=%b\n", err, RLCS_BITS,
45313091Ssam status, RLER_BITS);
45410770Ssam bp->b_flags |= B_ERROR;
45510770Ssam } else
45610770Ssam um->um_tab.b_active = 0; /* force retry */
45713091Ssam /* determine disk position */
45810770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR;
45910770Ssam rlwait(rladdr);
46013091Ssam /* save disk drive position */
46113091Ssam st->rl_cyl[ui->ui_slave] =
46213091Ssam (rladdr->rlmp.readhdr & 0177700) >> 6;
46310770Ssam }
46410770Ssam /*
46510770Ssam * If still ``active'', then don't need any more retries.
46610770Ssam */
46710770Ssam if (um->um_tab.b_active) {
46810770Ssam /* RL02 check if more data from previous request */
46913091Ssam if ((bp->b_flags & B_ERROR) == 0 &&
47013091Ssam (int)(st->rl_bleft -= st->rl_bpart) > 0) {
47110770Ssam /*
47213091Ssam * The following code was modeled from the rk07
47310770Ssam * driver when an ECC error occured. It has to
47410770Ssam * fix the bits then restart the transfer which is
47510770Ssam * what we have to do (restart transfer).
47610770Ssam */
47710770Ssam int reg, npf, o, cmd, ubaddr, diff, head;
47810770Ssam
47910770Ssam /* seek to next head/track */
48010770Ssam /* increment head and/or cylinder */
48110770Ssam st->rl_cylnhd++;
48210770Ssam diff = (st->rl_cyl[ui->ui_slave] >> 1) -
48310770Ssam (st->rl_cylnhd >> 1);
48410770Ssam st->rl_cyl[ui->ui_slave] = st->rl_cylnhd;
48510770Ssam head = st->rl_cylnhd & 1;
48613091Ssam rlwait(rladdr);
48713091Ssam if (diff < 0)
48813091Ssam rladdr->rlda.seek =
48913091Ssam -diff << 7 | RLDA_HGH | head << 4;
49010770Ssam else
49113091Ssam rladdr->rlda.seek =
49213091Ssam diff << 7 | RLDA_LOW | head << 4;
49310770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK;
49410770Ssam npf = btop( bp->b_bcount - st->rl_bleft );
49536035Skarels reg = btop(UBAI_ADDR(um->um_ubinfo)) + npf;
49610770Ssam o = (int)bp->b_un.b_addr & PGOFSET;
49710770Ssam ubapurge(um);
49810770Ssam um->um_tab.b_active++;
49913091Ssam rlwait(rladdr);
50010770Ssam rladdr->rlda.rw = st->rl_cylnhd << 6;
50113091Ssam if (st->rl_bleft < (st->rl_bpart = rl02.btrak))
50210770Ssam st->rl_bpart = st->rl_bleft;
50310770Ssam rladdr->rlmp.rw = -(st->rl_bpart >> 1);
50410770Ssam cmd = (bp->b_flags&B_READ ? RL_READ : RL_WRITE) |
50513091Ssam RL_IE | (ui->ui_slave << 8);
50610770Ssam ubaddr = (int)ptob(reg) + o;
50710770Ssam cmd |= ((ubaddr >> 12) & RL_BAE);
50810770Ssam rladdr->rlba = ubaddr;
50910770Ssam rladdr->rlcs = cmd;
51010770Ssam return;
51110770Ssam }
51210770Ssam um->um_tab.b_active = 0;
51310770Ssam um->um_tab.b_errcnt = 0;
51410770Ssam dp->b_active = 0;
51510770Ssam dp->b_errcnt = 0;
51610770Ssam /* "b_resid" words remaining after error */
51710770Ssam bp->b_resid = st->rl_bleft;
51810770Ssam um->um_tab.b_actf = dp->b_forw;
51910770Ssam dp->b_actf = bp->av_forw;
52010770Ssam st->rl_dn = -1;
52110770Ssam st->rl_bpart = st->rl_bleft = 0;
52210770Ssam iodone(bp);
52310770Ssam /*
52410770Ssam * If this unit has more work to do,
52510770Ssam * then start it up right away.
52610770Ssam */
52710770Ssam if (dp->b_actf)
52813091Ssam rlustart(ui);
52910770Ssam as &= ~(1<<ui->ui_slave);
53010770Ssam } else
53110770Ssam as |= (1<<ui->ui_slave);
53210770Ssam ubadone(um);
53310770Ssam /* reset state info */
53410770Ssam st->rl_dn = -1;
53510770Ssam st->rl_cylnhd = st->rl_bpart = st->rl_bleft = 0;
53610770Ssam /*
53710770Ssam * Process other units which need attention.
53810770Ssam * For each unit which needs attention, call
53910770Ssam * the unit start routine to place the slave
54010770Ssam * on the controller device queue.
54110770Ssam */
54226369Skarels while (unit = ffs((long)as)) {
54310770Ssam unit--; /* was 1 origin */
54410770Ssam as &= ~(1<<unit);
54513091Ssam rlustart(rlip[rl21][unit]);
54610770Ssam }
54710770Ssam /*
54810770Ssam * If the controller is not transferring, but
54910770Ssam * there are devices ready to transfer, start
55010770Ssam * the controller.
55110770Ssam */
55210770Ssam if (um->um_tab.b_actf && um->um_tab.b_active == 0)
55313091Ssam rlstart(um);
55410770Ssam }
55510770Ssam
rlwait(rladdr)55612452Ssam rlwait(rladdr)
55712452Ssam register struct rldevice *rladdr;
55810770Ssam {
55912452Ssam
56010770Ssam while ((rladdr->rlcs & RL_CRDY) == 0)
56113091Ssam ;
56210770Ssam }
56310770Ssam
56410770Ssam /*
56510770Ssam * Reset driver after UBA init.
56610770Ssam * Cancel software state of all pending transfers
56710770Ssam * and restart all units and the controller.
56810770Ssam */
rlreset(uban)56910770Ssam rlreset(uban)
57010770Ssam int uban;
57110770Ssam {
57210770Ssam register struct uba_ctlr *um;
57310770Ssam register struct uba_device *ui;
57410770Ssam register struct rldevice *rladdr;
57510770Ssam register struct rl_stat *st;
57613091Ssam register int rl21, unit;
57710770Ssam
57810770Ssam for (rl21 = 0; rl21 < NHL; rl21++) {
57910770Ssam if ((um = rlminfo[rl21]) == 0 || um->um_ubanum != uban ||
58010770Ssam um->um_alive == 0)
58110770Ssam continue;
58213091Ssam printf(" hl%d", rl21);
58310770Ssam rladdr = (struct rldevice *)um->um_addr;
58410770Ssam st = &rl_stat[rl21];
58510770Ssam um->um_tab.b_active = 0;
58610770Ssam um->um_tab.b_actf = um->um_tab.b_actl = 0;
58710770Ssam if (um->um_ubinfo) {
58810770Ssam printf("<%d>", (um->um_ubinfo>>28)&0xf);
58912452Ssam um->um_ubinfo = 0;
59010770Ssam }
59110770Ssam /* reset controller */
59210770Ssam st->rl_dn = -1;
59310770Ssam st->rl_cylnhd = 0;
59410770Ssam st->rl_bleft = 0;
59510770Ssam st->rl_bpart = 0;
59612452Ssam rlwait(rladdr);
59710770Ssam for (unit = 0; unit < NRL; unit++) {
59810770Ssam rladdr->rlcs = (unit << 8) | RL_GETSTAT;
59912452Ssam rlwait(rladdr);
60010770Ssam /* Determine disk posistion */
60110770Ssam rladdr->rlcs = (unit << 8) | RL_RHDR;
60210770Ssam rlwait(rladdr);
60310770Ssam /* save disk drive posistion */
60410770Ssam st->rl_cyl[unit] =
60510770Ssam (rladdr->rlmp.readhdr & 0177700) >> 6;
60610770Ssam if ((ui = rldinfo[unit]) == 0)
60710770Ssam continue;
60810770Ssam if (ui->ui_alive == 0 || ui->ui_mi != um)
60910770Ssam continue;
61010770Ssam rlutab[unit].b_active = 0;
61113091Ssam rlustart(ui);
61210770Ssam }
61313091Ssam rlstart(um);
61410770Ssam }
61510770Ssam }
61610770Ssam
61710770Ssam /*
61810770Ssam * Wake up every second and if an interrupt is pending
61910770Ssam * but nothing has happened increment a counter.
62010770Ssam * If nothing happens for 20 seconds, reset the UNIBUS
62110770Ssam * and begin anew.
62210770Ssam */
rlwatch()62310770Ssam rlwatch()
62410770Ssam {
62510770Ssam register struct uba_ctlr *um;
62610770Ssam register rl21, unit;
62710770Ssam register struct rl_softc *rl;
62810770Ssam
62910770Ssam timeout(rlwatch, (caddr_t)0, hz);
63010770Ssam for (rl21 = 0; rl21 < NHL; rl21++) {
63110770Ssam um = rlminfo[rl21];
63210770Ssam if (um == 0 || um->um_alive == 0)
63310770Ssam continue;
63410770Ssam rl = &rl_softc[rl21];
63510770Ssam if (um->um_tab.b_active == 0) {
63610770Ssam for (unit = 0; unit < NRL; unit++)
63710770Ssam if (rlutab[unit].b_active &&
63810770Ssam rldinfo[unit]->ui_mi == um)
63910770Ssam goto active;
64010770Ssam rl->rl_wticks = 0;
64110770Ssam continue;
64210770Ssam }
64310770Ssam active:
64410770Ssam rl->rl_wticks++;
64510770Ssam if (rl->rl_wticks >= 20) {
64610770Ssam rl->rl_wticks = 0;
64710770Ssam printf("hl%d: lost interrupt\n", rl21);
64810770Ssam ubareset(um->um_ubanum);
64910770Ssam }
65010770Ssam }
65110770Ssam }
65210770Ssam
65313091Ssam /*ARGSUSED*/
rldump(dev)65410770Ssam rldump(dev)
65510770Ssam dev_t dev;
65610770Ssam {
65713091Ssam
65810770Ssam /* don't think there is room on swap for it anyway. */
65910770Ssam }
66013272Ssam
rlsize(dev)66113272Ssam rlsize(dev)
66213272Ssam dev_t dev;
66313272Ssam {
66424741Sbloom register int unit = rlunit(dev);
66513272Ssam register struct uba_device *ui;
66613272Ssam
66713272Ssam if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0)
66813272Ssam return (-1);
66913272Ssam return (rl02.sizes[minor(dev) & 07].nblocks);
67013272Ssam }
67112504Ssam #endif
672