xref: /csrg-svn/sys/vax/uba/rl.c (revision 26369)
123338Smckusick /*
223338Smckusick  * Copyright (c) 1982 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*26369Skarels  *	@(#)rl.c	6.7 (Berkeley) 02/23/86
723338Smckusick  */
810770Ssam 
910770Ssam #include "rl.h"
1012452Ssam #if NRL > 0
1110770Ssam /*
1210770Ssam  * UNIBUS RL02 disk driver
1310770Ssam  */
1413091Ssam #include "../machine/pte.h"
1510770Ssam 
1617077Sbloom #include "param.h"
1717077Sbloom #include "systm.h"
1817077Sbloom #include "dk.h"
1917077Sbloom #include "dkbad.h"
2017077Sbloom #include "buf.h"
2117077Sbloom #include "conf.h"
2217077Sbloom #include "dir.h"
2317077Sbloom #include "user.h"
2417077Sbloom #include "map.h"
2517077Sbloom #include "vm.h"
2617077Sbloom #include "cmap.h"
2717077Sbloom #include "uio.h"
2817077Sbloom #include "kernel.h"
2910770Ssam 
3013091Ssam #include "../vax/cpu.h"
3113091Ssam #include "../vax/nexus.h"
3217077Sbloom #include "ubavar.h"
3317077Sbloom #include "ubareg.h"
3417077Sbloom #include "rlreg.h"
3510770Ssam 
3610770Ssam /* Pending Controller items and statistics */
3710770Ssam struct	rl_softc {
3810770Ssam 	int	rl_softas;	/* Attention sumary, (seeks pending) */
3910770Ssam 	int	rl_ndrive;	/* Number of drives on controller */
4010770Ssam 	int	rl_wticks;	/* Monitor time for function */
4110770Ssam } rl_softc[NHL];
4210770Ssam 
4310770Ssam /*
4413091Ssam  * State of controller from last transfer.
4513091Ssam  * Since only one transfer can be done at a time per
4610770Ssam  * controller, only allocate one for each controller.
4710770Ssam  */
4810770Ssam struct	rl_stat {
4910770Ssam 	short	rl_cyl[4];	/* Current cylinder for each drive */
5010770Ssam 	short	rl_dn;		/* drive number currently transferring */
5110770Ssam 	short	rl_cylnhd;	/* current cylinder and head of transfer */
5210770Ssam 	u_short	rl_bleft;	/* bytes left to transfer */
5310770Ssam 	u_short	rl_bpart;	/* bytes transferred */
5410770Ssam } rl_stat[NHL];
5510770Ssam 
5624741Sbloom #define rlunit(dev)	(minor(dev) >> 3)
5724741Sbloom 
5810770Ssam /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
5913091Ssam /* Last cylinder not used. Saved for Bad Sector File */
6010770Ssam struct	size {
6110770Ssam 	daddr_t	nblocks;
6210770Ssam 	int	cyloff;
6310770Ssam } rl02_sizes[8] = {
6413091Ssam 	15884,		0,		/* A=cyl   0 thru 397 */
6513091Ssam 	 4520,		398,		/* B=cyl 398 thru 510 */
6613091Ssam 	   -1,		0,		/* C=cyl   0 thru 511 */
6713091Ssam 	 4520,		398,		/* D=cyl 398 thru 510 */
6817431Skarels 	    0,          0,		/* E= Not Defined     */
6910770Ssam 	    0,          0,		/* F= Not Defined     */
7013091Ssam 	20440,	        0,		/* G=cyl   0 thru 510 */
7110770Ssam 	    0,          0,		/* H= Not Defined     */
7210770Ssam };
7310770Ssam /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
7410770Ssam 
7510770Ssam int	rlprobe(), rlslave(), rlattach(), rldgo(), rlintr();
7610770Ssam struct	uba_ctlr	*rlminfo[NHL];
7710770Ssam struct	uba_device	*rldinfo[NRL];
7810770Ssam struct	uba_device	*rlip[NHL][4];
7910770Ssam 
8010770Ssam /* RL02 driver structure */
8117431Skarels u_short	rlstd[] = { 0174400, 0 };
8210770Ssam struct	uba_driver hldriver =
8310770Ssam     { rlprobe, rlslave, rlattach, rldgo, rlstd, "rl", rldinfo, "hl", rlminfo };
8410770Ssam 
8510770Ssam /* User table per controller */
8610770Ssam struct	buf	rlutab[NRL];
8710770Ssam 
8810770Ssam /* RL02 drive structure */
8910770Ssam struct	RL02 {
9010770Ssam 	short	nbpt;		/* Number of 512 byte blocks/track */
9110770Ssam 	short	ntrak;
9210770Ssam 	short	nbpc;		/* Number of 512 byte blocks/cylinder */
9310770Ssam 	short	ncyl;
9410770Ssam 	short	btrak;		/* Number of bytes/track */
9510770Ssam 	struct	size *sizes;
9610770Ssam } rl02 = {
9710770Ssam 	20,	2,	40,	512,	20*512,	rl02_sizes /* rl02/DEC*/
9810770Ssam };
9910770Ssam 
10010770Ssam struct	buf	rrlbuf[NRL];
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*/
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 
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)
16810770Ssam 		dk_mspw[ui->ui_dk] = .000003906;   /* 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 
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 
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  */
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  */
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 
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  */
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 			 */
45010770Ssam 			harderr(bp, "rl");
45113091Ssam 			printf("cs=%b mp=%b\n", err, RLCS_BITS,
45213091Ssam 			    status, RLER_BITS);
45310770Ssam 			bp->b_flags |= B_ERROR;
45410770Ssam 		} else
45510770Ssam 			um->um_tab.b_active = 0;	 /* force retry */
45613091Ssam 		/* determine disk position */
45710770Ssam 		rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR;
45810770Ssam 		rlwait(rladdr);
45913091Ssam 		/* save disk drive position */
46013091Ssam 		st->rl_cyl[ui->ui_slave] =
46113091Ssam 		    (rladdr->rlmp.readhdr & 0177700) >> 6;
46210770Ssam 	}
46310770Ssam 	/*
46410770Ssam 	 * If still ``active'', then don't need any more retries.
46510770Ssam 	 */
46610770Ssam 	if (um->um_tab.b_active) {
46710770Ssam 		/* RL02 check if more data from previous request */
46813091Ssam 		if ((bp->b_flags & B_ERROR) == 0 &&
46913091Ssam 		     (int)(st->rl_bleft -= st->rl_bpart) > 0) {
47010770Ssam 			/*
47113091Ssam 			 * The following code was modeled from the rk07
47210770Ssam 			 * driver when an ECC error occured.  It has to
47310770Ssam 			 * fix the bits then restart the transfer which is
47410770Ssam 			 * what we have to do (restart transfer).
47510770Ssam 			 */
47610770Ssam 			int reg, npf, o, cmd, ubaddr, diff, head;
47710770Ssam 
47810770Ssam 			/* seek to next head/track */
47910770Ssam 			/* increment head and/or cylinder */
48010770Ssam 			st->rl_cylnhd++;
48110770Ssam 			diff = (st->rl_cyl[ui->ui_slave] >> 1) -
48210770Ssam 				(st->rl_cylnhd >> 1);
48310770Ssam 			st->rl_cyl[ui->ui_slave] = st->rl_cylnhd;
48410770Ssam 			head = st->rl_cylnhd & 1;
48513091Ssam 			rlwait(rladdr);
48613091Ssam 			if (diff < 0)
48713091Ssam 				rladdr->rlda.seek =
48813091Ssam 				    -diff << 7 | RLDA_HGH | head << 4;
48910770Ssam 			else
49013091Ssam 				rladdr->rlda.seek =
49113091Ssam 				    diff << 7 | RLDA_LOW | head << 4;
49210770Ssam 			rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK;
49310770Ssam 			npf = btop( bp->b_bcount - st->rl_bleft );
49410770Ssam 			reg = btop(um->um_ubinfo&0x3ffff) + npf;
49510770Ssam 			o = (int)bp->b_un.b_addr & PGOFSET;
49610770Ssam 			ubapurge(um);
49710770Ssam 			um->um_tab.b_active++;
49813091Ssam 			rlwait(rladdr);
49910770Ssam 			rladdr->rlda.rw = st->rl_cylnhd << 6;
50013091Ssam 			if (st->rl_bleft < (st->rl_bpart = rl02.btrak))
50110770Ssam 				st->rl_bpart = st->rl_bleft;
50210770Ssam 			rladdr->rlmp.rw = -(st->rl_bpart >> 1);
50310770Ssam 			cmd = (bp->b_flags&B_READ ? RL_READ : RL_WRITE) |
50413091Ssam 			    RL_IE | (ui->ui_slave << 8);
50510770Ssam 			ubaddr = (int)ptob(reg) + o;
50610770Ssam 			cmd |= ((ubaddr >> 12) & RL_BAE);
50710770Ssam 			rladdr->rlba = ubaddr;
50810770Ssam 			rladdr->rlcs = cmd;
50910770Ssam 			return;
51010770Ssam 		}
51110770Ssam 		um->um_tab.b_active = 0;
51210770Ssam 		um->um_tab.b_errcnt = 0;
51310770Ssam 		dp->b_active = 0;
51410770Ssam 		dp->b_errcnt = 0;
51510770Ssam 		/* "b_resid" words remaining after error */
51610770Ssam 		bp->b_resid = st->rl_bleft;
51710770Ssam 		um->um_tab.b_actf = dp->b_forw;
51810770Ssam 		dp->b_actf = bp->av_forw;
51910770Ssam 		st->rl_dn = -1;
52010770Ssam 		st->rl_bpart = st->rl_bleft = 0;
52110770Ssam 		iodone(bp);
52210770Ssam 		/*
52310770Ssam 		 * If this unit has more work to do,
52410770Ssam 		 * then start it up right away.
52510770Ssam 		 */
52610770Ssam 		if (dp->b_actf)
52713091Ssam 			rlustart(ui);
52810770Ssam 		as &= ~(1<<ui->ui_slave);
52910770Ssam 	} else
53010770Ssam 		as |= (1<<ui->ui_slave);
53110770Ssam 	ubadone(um);
53210770Ssam 	/* reset state info */
53310770Ssam 	st->rl_dn = -1;
53410770Ssam 	st->rl_cylnhd = st->rl_bpart = st->rl_bleft = 0;
53510770Ssam 	/*
53610770Ssam 	 * Process other units which need attention.
53710770Ssam 	 * For each unit which needs attention, call
53810770Ssam 	 * the unit start routine to place the slave
53910770Ssam 	 * on the controller device queue.
54010770Ssam 	 */
541*26369Skarels 	while (unit = ffs((long)as)) {
54210770Ssam 		unit--;		/* was 1 origin */
54310770Ssam 		as &= ~(1<<unit);
54413091Ssam 		rlustart(rlip[rl21][unit]);
54510770Ssam 	}
54610770Ssam 	/*
54710770Ssam 	 * If the controller is not transferring, but
54810770Ssam 	 * there are devices ready to transfer, start
54910770Ssam 	 * the controller.
55010770Ssam 	 */
55110770Ssam 	if (um->um_tab.b_actf && um->um_tab.b_active == 0)
55213091Ssam 		rlstart(um);
55310770Ssam }
55410770Ssam 
55512452Ssam rlwait(rladdr)
55612452Ssam 	register struct rldevice *rladdr;
55710770Ssam {
55812452Ssam 
55910770Ssam 	while ((rladdr->rlcs & RL_CRDY) == 0)
56013091Ssam 		;
56110770Ssam }
56210770Ssam 
56312452Ssam rlread(dev, uio)
56410770Ssam 	dev_t dev;
56512452Ssam 	struct uio *uio;
56610770Ssam {
56724741Sbloom 	register int unit = rlunit(dev);
56810770Ssam 
56910770Ssam 	if (unit >= NRL)
57012452Ssam 		return (ENXIO);
57112452Ssam 	return (physio(rlstrategy, &rrlbuf[unit], dev, B_READ, minphys, uio));
57210770Ssam }
57310770Ssam 
57412452Ssam rlwrite(dev, uio)
57510770Ssam 	dev_t dev;
57612452Ssam 	struct uio *uio;
57710770Ssam {
57824741Sbloom 	register int unit = rlunit(dev);
57910770Ssam 
58010770Ssam 	if (unit >= NRL)
58112452Ssam 		return (ENXIO);
58212452Ssam 	return (physio(rlstrategy, &rrlbuf[unit], dev, B_WRITE, minphys, uio));
58310770Ssam }
58410770Ssam 
58510770Ssam /*
58610770Ssam  * Reset driver after UBA init.
58710770Ssam  * Cancel software state of all pending transfers
58810770Ssam  * and restart all units and the controller.
58910770Ssam  */
59010770Ssam rlreset(uban)
59110770Ssam 	int uban;
59210770Ssam {
59310770Ssam 	register struct uba_ctlr *um;
59410770Ssam 	register struct uba_device *ui;
59510770Ssam 	register struct rldevice *rladdr;
59610770Ssam 	register struct rl_stat *st;
59713091Ssam 	register int rl21, unit;
59810770Ssam 
59910770Ssam 	for (rl21 = 0; rl21 < NHL; rl21++) {
60010770Ssam 		if ((um = rlminfo[rl21]) == 0 || um->um_ubanum != uban ||
60110770Ssam 		    um->um_alive == 0)
60210770Ssam 			continue;
60313091Ssam 		printf(" hl%d", rl21);
60410770Ssam 		rladdr = (struct rldevice *)um->um_addr;
60510770Ssam 		st = &rl_stat[rl21];
60610770Ssam 		um->um_tab.b_active = 0;
60710770Ssam 		um->um_tab.b_actf = um->um_tab.b_actl = 0;
60810770Ssam 		if (um->um_ubinfo) {
60910770Ssam 			printf("<%d>", (um->um_ubinfo>>28)&0xf);
61012452Ssam 			um->um_ubinfo = 0;
61110770Ssam 		}
61210770Ssam 		/* reset controller */
61310770Ssam 		st->rl_dn = -1;
61410770Ssam 		st->rl_cylnhd = 0;
61510770Ssam 		st->rl_bleft = 0;
61610770Ssam 		st->rl_bpart = 0;
61712452Ssam 		rlwait(rladdr);
61810770Ssam 		for (unit = 0; unit < NRL; unit++) {
61910770Ssam 			rladdr->rlcs = (unit << 8) | RL_GETSTAT;
62012452Ssam 			rlwait(rladdr);
62110770Ssam 			/* Determine disk posistion */
62210770Ssam 			rladdr->rlcs = (unit << 8) | RL_RHDR;
62310770Ssam 			rlwait(rladdr);
62410770Ssam 			/* save disk drive posistion */
62510770Ssam 			st->rl_cyl[unit] =
62610770Ssam 				(rladdr->rlmp.readhdr & 0177700) >> 6;
62710770Ssam 			if ((ui = rldinfo[unit]) == 0)
62810770Ssam 				continue;
62910770Ssam 			if (ui->ui_alive == 0 || ui->ui_mi != um)
63010770Ssam 				continue;
63110770Ssam 			rlutab[unit].b_active = 0;
63213091Ssam 			rlustart(ui);
63310770Ssam 		}
63413091Ssam 		rlstart(um);
63510770Ssam 	}
63610770Ssam }
63710770Ssam 
63810770Ssam /*
63910770Ssam  * Wake up every second and if an interrupt is pending
64010770Ssam  * but nothing has happened increment a counter.
64110770Ssam  * If nothing happens for 20 seconds, reset the UNIBUS
64210770Ssam  * and begin anew.
64310770Ssam  */
64410770Ssam rlwatch()
64510770Ssam {
64610770Ssam 	register struct uba_ctlr *um;
64710770Ssam 	register rl21, unit;
64810770Ssam 	register struct rl_softc *rl;
64910770Ssam 
65010770Ssam 	timeout(rlwatch, (caddr_t)0, hz);
65110770Ssam 	for (rl21 = 0; rl21 < NHL; rl21++) {
65210770Ssam 		um = rlminfo[rl21];
65310770Ssam 		if (um == 0 || um->um_alive == 0)
65410770Ssam 			continue;
65510770Ssam 		rl = &rl_softc[rl21];
65610770Ssam 		if (um->um_tab.b_active == 0) {
65710770Ssam 			for (unit = 0; unit < NRL; unit++)
65810770Ssam 				if (rlutab[unit].b_active &&
65910770Ssam 				    rldinfo[unit]->ui_mi == um)
66010770Ssam 					goto active;
66110770Ssam 			rl->rl_wticks = 0;
66210770Ssam 			continue;
66310770Ssam 		}
66410770Ssam active:
66510770Ssam 		rl->rl_wticks++;
66610770Ssam 		if (rl->rl_wticks >= 20) {
66710770Ssam 			rl->rl_wticks = 0;
66810770Ssam 			printf("hl%d: lost interrupt\n", rl21);
66910770Ssam 			ubareset(um->um_ubanum);
67010770Ssam 		}
67110770Ssam 	}
67210770Ssam }
67310770Ssam 
67413091Ssam /*ARGSUSED*/
67510770Ssam rldump(dev)
67610770Ssam 	dev_t dev;
67710770Ssam {
67813091Ssam 
67910770Ssam 	/* don't think there is room on swap for it anyway. */
68010770Ssam }
68113272Ssam 
68213272Ssam rlsize(dev)
68313272Ssam 	dev_t dev;
68413272Ssam {
68524741Sbloom 	register int unit = rlunit(dev);
68613272Ssam 	register struct uba_device *ui;
68713272Ssam 
68813272Ssam 	if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0)
68913272Ssam 		return (-1);
69013272Ssam 	return (rl02.sizes[minor(dev) & 07].nblocks);
69113272Ssam }
69212504Ssam #endif
693