xref: /csrg-svn/sys/vax/uba/rl.c (revision 12504)
1*12504Ssam /*	rl.c	4.3	83/05/18	*/
210770Ssam 
310770Ssam #include "rl.h"
412452Ssam #if NRL > 0
510770Ssam /*
610770Ssam  * UNIBUS RL02 disk driver
710770Ssam  * (not yet converted to 4.1c)
810770Ssam  */
910770Ssam 
1010770Ssam #include "../h/param.h"
1110770Ssam #include "../h/systm.h"
1210770Ssam #include "../h/cpu.h"
1310770Ssam #include "../h/nexus.h"
1410770Ssam #include "../h/dk.h"
1510770Ssam #include "../h/buf.h"
1610770Ssam #include "../h/conf.h"
1710770Ssam #include "../h/dir.h"
1810770Ssam #include "../h/user.h"
1910770Ssam #include "../h/map.h"
2010770Ssam #include "../h/pte.h"
2110770Ssam #include "../h/mtpr.h"
2210770Ssam #include "../h/vm.h"
2310770Ssam #include "../h/ubavar.h"
2410770Ssam #include "../h/ubareg.h"
2510770Ssam #include "../h/cmap.h"
2610770Ssam 
2710770Ssam #include "../h/rlreg.h"
2810770Ssam 
2910770Ssam /* Pending Controller items and statistics */
3010770Ssam struct	rl_softc {
3110770Ssam 	int	rl_softas;	/* Attention sumary, (seeks pending) */
3210770Ssam 	int	rl_ndrive;	/* Number of drives on controller */
3310770Ssam 	int	rl_wticks;	/* Monitor time for function */
3410770Ssam } rl_softc[NHL];
3510770Ssam 
3610770Ssam /*
3710770Ssam  * this struct is used to keep the state of the controller for the last
3810770Ssam  * transfer done.  Since only one transfer can be done at a time per
3910770Ssam  * controller, only allocate one for each controller.
4010770Ssam  */
4110770Ssam struct	rl_stat {
4210770Ssam 	short	rl_cyl[4];	/* Current cylinder for each drive */
4310770Ssam 	short	rl_dn;		/* drive number currently transferring */
4410770Ssam 	short	rl_cylnhd;	/* current cylinder and head of transfer */
4510770Ssam 	u_short	rl_bleft;	/* bytes left to transfer */
4610770Ssam 	u_short	rl_bpart;	/* bytes transferred */
4710770Ssam } rl_stat[NHL];
4810770Ssam 
4910770Ssam /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
5010770Ssam struct	size {
5110770Ssam 	daddr_t	nblocks;
5210770Ssam 	int	cyloff;
5310770Ssam } rl02_sizes[8] = {
5410770Ssam 	14440,  	0,		/* A=cyl   0 thru 360 */
5510770Ssam 	 6040,        361,		/* B=cyl 361 thru 511 */
5610770Ssam 	20480,	        0,		/* C=cyl   0 thru 511 */
5710770Ssam 	    0,          0,		/* D= Not Defined     */
5810770Ssam 	    0,          0,		/* E= Not Defined     */
5910770Ssam 	    0,          0,		/* F= Not Defined     */
6010770Ssam 	    0,          0,		/* G= Not Defined     */
6110770Ssam 	    0,          0,		/* H= Not Defined     */
6210770Ssam };
6310770Ssam /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
6410770Ssam 
6510770Ssam int	rlprobe(), rlslave(), rlattach(), rldgo(), rlintr();
6610770Ssam struct	uba_ctlr	*rlminfo[NHL];
6710770Ssam struct	uba_device	*rldinfo[NRL];
6810770Ssam struct	uba_device	*rlip[NHL][4];
6910770Ssam 
7010770Ssam /* RL02 driver structure */
7110770Ssam u_short	rlstd[] = { 0174400 };
7210770Ssam struct	uba_driver hldriver =
7310770Ssam     { rlprobe, rlslave, rlattach, rldgo, rlstd, "rl", rldinfo, "hl", rlminfo };
7410770Ssam 
7510770Ssam /* User table per controller */
7610770Ssam struct	buf	rlutab[NRL];
7710770Ssam 
7810770Ssam /* RL02 drive structure */
7910770Ssam struct	RL02 {
8010770Ssam 	short	nbpt;		/* Number of 512 byte blocks/track */
8110770Ssam 	short	ntrak;
8210770Ssam 	short	nbpc;		/* Number of 512 byte blocks/cylinder */
8310770Ssam 	short	ncyl;
8410770Ssam 	short	btrak;		/* Number of bytes/track */
8510770Ssam 	struct	size *sizes;
8610770Ssam } rl02 = {
8710770Ssam 	20,	2,	40,	512,	20*512,	rl02_sizes /* rl02/DEC*/
8810770Ssam };
8910770Ssam 
9010770Ssam struct	buf	rrlbuf[NRL];
9110770Ssam 
9210770Ssam #define	b_cylin b_resid		/* Last seek as CYL<<1 | HD */
9310770Ssam 
9410770Ssam #ifdef INTRLVE
9510770Ssam daddr_t dkblock();
9610770Ssam #endif
9710770Ssam 
9810770Ssam int	rlwstart, rlwatch();		/* Have started guardian */
9910770Ssam 
10010770Ssam /* Check that controller exists */
10110770Ssam /*ARGSUSED*/
10210770Ssam rlprobe(reg)
10310770Ssam 	caddr_t reg;
10410770Ssam {
10510770Ssam 	register int br, cvec;
10610770Ssam 
10710770Ssam #ifdef lint
10810770Ssam 	br = 0; cvec = br; br = cvec;
10910770Ssam #endif
11010770Ssam 	((struct rldevice *)reg)->rlcs = RL_IE | RL_NOOP;  /* Enable intrpt */
11110770Ssam 	DELAY(10);	/* Ensure interrupt takes place (10 microsec ) */
11210770Ssam 	((struct rldevice *)reg)->rlcs &= ~RL_IE;  /* Disable intrpt */
11312452Ssam 	return (sizeof (struct rldevice));
11410770Ssam }
11510770Ssam 
11610770Ssam /* Check that drive exists and is functional*/
11710770Ssam rlslave(ui, reg)
11810770Ssam 	struct uba_device *ui;
11910770Ssam 	caddr_t reg;
12010770Ssam {
12110770Ssam 	register struct rldevice *rladdr = (struct rldevice *)reg;
12210770Ssam 	short ctr = 0;
12310770Ssam 
12410770Ssam 	/*
12510770Ssam 	 * DEC reports that:
12610770Ssam 	 * For some unknown reason the RL02 (seems to be only drive 1)
12710770Ssam 	 * does not return a valid drive status the first time that a
12810770Ssam 	 * GET STATUS request is issued for the drive, in fact it can
12910770Ssam 	 * take up to three or more GET STATUS requests to obtain the
13010770Ssam 	 * correct status.
13110770Ssam 	 * In order to overcome this, the driver has been modified to
13210770Ssam 	 * issue a GET STATUS request and validate the drive status
13310770Ssam 	 * returned.  If a valid status is not returned after eight
13410770Ssam 	 * attempts, then an error message is printed.
13510770Ssam 	 */
13610770Ssam 	do {
13710770Ssam 		rladdr->rlda.getstat = RL_RESET;
13810770Ssam 		rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/
13910770Ssam 		rlwait(rladdr);
14010770Ssam 	} while( (rladdr->rlmp.getstat&RLMP_STATUS) != RLMP_STATOK && ++ctr<8 );
14110770Ssam 
14210770Ssam 
14310770Ssam 	if ((rladdr->rlcs & RL_DE) || (ctr >= 8))
14410770Ssam 		return (0);			 /* Error return */
14510770Ssam 	if ((rladdr->rlmp.getstat & RLMP_DT) == 0 ) {	/* NO RL01'S */
14610770Ssam 		printf("rl01 drives not supported (drive %d)\n", ui->ui_slave );
14710770Ssam 		return(0);
14810770Ssam 	}
14910770Ssam 	return (1);
15010770Ssam }
15110770Ssam 
15210770Ssam /* Initialize controller */
15310770Ssam rlattach(ui)
15410770Ssam 	register struct uba_device *ui;
15510770Ssam {
15610770Ssam 	register struct rldevice *rladdr;
15710770Ssam 
15810770Ssam 	if (rlwstart == 0) {
15910770Ssam 		timeout(rlwatch, (caddr_t)0, hz);   /* Watch for lost intr */
16010770Ssam 		rlwstart++;
16110770Ssam 	}
16210770Ssam 	/* Initialize iostat values */
16310770Ssam 	if (ui->ui_dk >= 0)
16410770Ssam 		dk_mspw[ui->ui_dk] = .000003906;   /* 16bit transfer time? */
16510770Ssam 	rlip[ui->ui_ctlr][ui->ui_slave] = ui;
16610770Ssam 	rl_softc[ui->ui_ctlr].rl_ndrive++;	   /* increment device/ctrl */
16710770Ssam 	rladdr = (struct rldevice *)ui->ui_addr;
16810770Ssam 
16910770Ssam 	/* reset controller */
17010770Ssam 	rladdr->rlda.getstat = RL_RESET;	/* SHOULD BE REPEATED? */
17110770Ssam 	rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT; /* Reset DE bit */
17210770Ssam 	rlwait(rladdr);
17310770Ssam 
17410770Ssam 	/* Determine disk posistion */
17510770Ssam 	rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR;
17610770Ssam 	rlwait(rladdr);
17710770Ssam 
17810770Ssam 	/* save disk drive posistion */
17910770Ssam 	rl_stat[ui->ui_ctlr].rl_cyl[ui->ui_slave] =
18010770Ssam 		(rladdr->rlmp.readhdr & 0177700) >> 6;
18110770Ssam 	rl_stat[ui->ui_ctlr].rl_dn = -1;
18210770Ssam }
18310770Ssam 
18412452Ssam rlopen(dev)
18512452Ssam 	dev_t dev;
18612452Ssam {
18712452Ssam 	register int unit = minor(dev) >> 3;
18812452Ssam 	register struct uba_device *mi;
18912452Ssam 
19012452Ssam 	if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0)
19112452Ssam 		return (ENXIO);
19212452Ssam 	return (0);
19312452Ssam }
19412452Ssam 
19510770Ssam rlstrategy(bp)
19610770Ssam 	register struct buf *bp;
19710770Ssam {
19810770Ssam 	register struct uba_device *ui;
19910770Ssam 	register int drive;
20010770Ssam 	register struct buf *dp;
20110770Ssam 	int partition = minor(bp->b_dev) & 07;
20210770Ssam 	long bn, sz;
20310770Ssam 
20410770Ssam 	sz = (bp->b_bcount+511) >> 9;	/* Blocks to transfer */
20510770Ssam 
20610770Ssam 	drive = dkunit(bp);		/* Drive number */
20710770Ssam 	if (drive >= NRL)
20810770Ssam 		goto bad;
20910770Ssam 	ui = rldinfo[drive];		/* Controller uba_device */
21010770Ssam 	if (ui == 0 || ui->ui_alive == 0)
21110770Ssam 		goto bad;
21210770Ssam 	if (bp->b_blkno < 0 ||
21310770Ssam 	    (bn = dkblock(bp))+sz > rl02.sizes[partition].nblocks)
21410770Ssam 		goto bad;
21510770Ssam 
21610770Ssam 	/* bn is in 512 byte block size */
21710770Ssam 	bp->b_cylin = bn/rl02.nbpc + rl02.sizes[partition].cyloff;
21810770Ssam 	(void) spl5();
21910770Ssam 	dp = &rlutab[ui->ui_unit];
22010770Ssam 	disksort(dp, bp);
22110770Ssam 	if (dp->b_active == 0) {
22210770Ssam 		(void) rlustart(ui);
22310770Ssam 		bp = &ui->ui_mi->um_tab;
22410770Ssam 		if (bp->b_actf && bp->b_active == 0)
22510770Ssam 			(void) rlstart(ui->ui_mi);
22610770Ssam 	}
22710770Ssam 	(void) spl0();
22810770Ssam 	return;
22910770Ssam 
23010770Ssam bad:
23110770Ssam 	bp->b_flags |= B_ERROR;
23210770Ssam 	iodone(bp);
23310770Ssam 	return;
23410770Ssam }
23510770Ssam 
23610770Ssam /*
23710770Ssam  * Unit start routine.
23810770Ssam  * Seek the drive to be where the data is
23910770Ssam  * and then generate another interrupt
24010770Ssam  * to actually start the transfer.
24110770Ssam  */
24210770Ssam rlustart(ui)
24310770Ssam 	register struct uba_device *ui;
24410770Ssam {
24510770Ssam 	register struct buf *bp, *dp;
24610770Ssam 	register struct uba_ctlr *um;
24710770Ssam 	register struct rldevice *rladdr;
24810770Ssam 	daddr_t bn;
24910770Ssam 	short cyl, sn, hd, diff;
25010770Ssam 
25110770Ssam 	if (ui == 0)
25210770Ssam 		return (0);
25310770Ssam 	um = ui->ui_mi;
25410770Ssam 	dk_busy &= ~(1<<ui->ui_dk);	/* Kernel define, drives busy */
25510770Ssam 	dp = &rlutab[ui->ui_unit];
25610770Ssam 	if ((bp = dp->b_actf) == NULL)
25710770Ssam 		goto out;
25810770Ssam 	/*
25910770Ssam 	 * If the controller is active, just remember
26010770Ssam 	 * that this device has to be positioned...
26110770Ssam 	 */
26210770Ssam 	if (um->um_tab.b_active) {
26310770Ssam 		rl_softc[um->um_ctlr].rl_softas |=  1<<ui->ui_slave;
26410770Ssam 		return (0);
26510770Ssam 	}
26610770Ssam 	/*
26710770Ssam 	 * If we have already positioned this drive,
26810770Ssam 	 * then just put it on the ready queue.
26910770Ssam 	 */
27010770Ssam 	if (dp->b_active)
27110770Ssam 		goto done;
27210770Ssam 	dp->b_active = 1;	/* Posistioning drive */
27310770Ssam 	rladdr = (struct rldevice *)um->um_addr;
27410770Ssam 
27510770Ssam 	/*
27610770Ssam 	 * Figure out where this transfer is going to
27710770Ssam 	 * and see if we are seeked correctly.
27810770Ssam 	 */
27910770Ssam 	bn = dkblock(bp);		/* Block # desired */
28010770Ssam 	/*
28110770Ssam 	 * these next two look funky... but we need to map
28210770Ssam 	 * 512 byte logical disk blocks to 256 byte sectors.
28310770Ssam 	 * (rl02's are stupid).
28410770Ssam 	 */
28510770Ssam 	sn = (bn % rl02.nbpt) << 1;	/* Sector # desired */
28610770Ssam 	hd = (bn / rl02.nbpt) & 1;	/* Get head required */
28710770Ssam 
28810770Ssam 	diff = (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] >> 1) - bp->b_cylin;
28910770Ssam 	if ( diff == 0 && (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] & 1) == hd)
29010770Ssam 		goto done;		/* on cylinder and head */
29110770Ssam 
29210770Ssam search:
29310770Ssam 	/*
29410770Ssam 	 * Not at correct position.
29510770Ssam 	 */
29610770Ssam 
29710770Ssam 	rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] = (bp->b_cylin << 1) | hd;
29810770Ssam 
29910770Ssam 	if (diff < 0)
30010770Ssam 		rladdr->rlda.seek = -diff << 7 | RLDA_HGH | hd << 4;
30110770Ssam 	else
30210770Ssam 		rladdr->rlda.seek = diff << 7 | RLDA_LOW | hd << 4;
30310770Ssam 	rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK;
30410770Ssam 
30510770Ssam 	/*
30610770Ssam 	 * Mark unit busy for iostat.
30710770Ssam 	 */
30810770Ssam 	if (ui->ui_dk >= 0) {
30910770Ssam 		dk_busy |= 1<<ui->ui_dk;
31010770Ssam 		dk_seek[ui->ui_dk]++;
31110770Ssam 	}
31212452Ssam 	rlwait(rladdr);
31310770Ssam 
31410770Ssam 	/*
31510770Ssam 	 * fall through since we are now at the correct cylinder
31610770Ssam 	 */
31710770Ssam done:
31810770Ssam 	/*
31910770Ssam 	 * Device is ready to go.
32010770Ssam 	 * Put it on the ready queue for the controller
32110770Ssam 	 * (unless its already there.)
32210770Ssam 	 */
32310770Ssam 	if (dp->b_active != 2) {
32410770Ssam 		dp->b_forw = NULL;
32510770Ssam 		if (um->um_tab.b_actf == NULL)
32610770Ssam 			um->um_tab.b_actf = dp;
32710770Ssam 		else
32810770Ssam 			um->um_tab.b_actl->b_forw = dp;
32910770Ssam 		um->um_tab.b_actl = dp;
33010770Ssam 		dp->b_active = 2;	/* Request on ready queue */
33110770Ssam 	}
33210770Ssam out:
33310770Ssam 	return (0);
33410770Ssam }
33510770Ssam 
33610770Ssam /*
33710770Ssam  * Start up a transfer on a drive.
33810770Ssam  */
33910770Ssam rlstart(um)
34010770Ssam 	register struct uba_ctlr *um;
34110770Ssam {
34210770Ssam 	register struct buf *bp, *dp;
34310770Ssam 	register struct uba_device *ui;
34410770Ssam 	register struct rldevice *rladdr;
34510770Ssam 	register struct rl_stat *st = &rl_stat[um->um_ctlr];
34610770Ssam 	daddr_t bn;
34710770Ssam 	short sn, cyl, cmd;
34810770Ssam 
34910770Ssam loop:
35010770Ssam 	/*
35110770Ssam 	 * Pull a request off the controller queue
35210770Ssam 	 */
35310770Ssam 	if ((dp = um->um_tab.b_actf) == NULL) {
35410770Ssam 		st->rl_dn = -1;
35510770Ssam 		st->rl_cylnhd = 0;
35610770Ssam 		st->rl_bleft = 0;
35710770Ssam 		st->rl_bpart = 0;
35810770Ssam 		return (0);
35910770Ssam 	}
36010770Ssam 	if ((bp = dp->b_actf) == NULL) {
36110770Ssam 		um->um_tab.b_actf = dp->b_forw;
36210770Ssam 		goto loop;
36310770Ssam 	}
36410770Ssam 	/*
36510770Ssam 	 * Mark controller busy, and
36610770Ssam 	 * determine destinationst.
36710770Ssam 	 */
36810770Ssam 	um->um_tab.b_active++;
36910770Ssam 	ui = rldinfo[dkunit(bp)];		/* Controller */
37010770Ssam 	bn = dkblock(bp);			/* 512 byte Block number */
37110770Ssam 	cyl = bp->b_cylin << 1;			/* Cylinder */
37210770Ssam 	cyl |= (bn / rl02.nbpt) & 1;		/* Get head required */
37310770Ssam 	sn = (bn % rl02.nbpt) << 1;		/* Sector number */
37410770Ssam 	rladdr = (struct rldevice *)ui->ui_addr;
37510770Ssam 
37610770Ssam 	/*
37710770Ssam 	 * Check that controller is ready
37810770Ssam 	 */
37912452Ssam 	rlwait(rladdr);
38010770Ssam 
38110770Ssam 	/*
38210770Ssam 	 * Setup for the transfer, and get in the
38310770Ssam 	 * UNIBUS adaptor queue.
38410770Ssam 	 */
38510770Ssam 	rladdr->rlda.rw = cyl<<6 | sn;
38610770Ssam 
38710770Ssam 	/* save away current transfers drive status */
38810770Ssam 	st->rl_dn = ui->ui_slave;
38910770Ssam 	st->rl_cylnhd = cyl;
39010770Ssam 	st->rl_bleft = bp->b_bcount;
39110770Ssam 	st->rl_bpart = rl02.btrak - (sn * NRLBPSC);
39210770Ssam 
39310770Ssam 	/* RL02 must seek between cylinders and between tracks */
39410770Ssam 	/* Determine maximum data transfer at this time */
39510770Ssam 	if( st->rl_bleft < st->rl_bpart)
39610770Ssam 		st->rl_bpart = st->rl_bleft;
39710770Ssam 
39810770Ssam 	rladdr->rlmp.rw = -(st->rl_bpart >> 1);
39910770Ssam 	if (bp->b_flags & B_READ)
40010770Ssam 		cmd = RL_IE | RL_READ | (ui->ui_slave << 8);
40110770Ssam 	else
40210770Ssam 		cmd = RL_IE | RL_WRITE | (ui->ui_slave << 8);
40310770Ssam 	um->um_cmd = cmd;
40410770Ssam 	(void) ubago(ui);
40510770Ssam 	return (1);
40610770Ssam }
40710770Ssam 
40810770Ssam /*
40910770Ssam  * Now all ready to go, stuff the registers.
41010770Ssam  */
41110770Ssam rldgo(um)
41210770Ssam 	register struct uba_ctlr *um;
41310770Ssam {
41410770Ssam 	register struct rldevice *rladdr = (struct rldevice *)um->um_addr;
41510770Ssam 
41610770Ssam 
41710770Ssam 	/* Place in unibus address for transfer (lower 18 bits of um_ubinfo) */
41810770Ssam 	/* Then execute instruction */
41910770Ssam 	rladdr->rlba = um->um_ubinfo;
42010770Ssam 	rladdr->rlcs = um->um_cmd|((um->um_ubinfo>>12)&RL_BAE);
42110770Ssam }
42210770Ssam 
42310770Ssam /*
42410770Ssam  * Handle a disk interrupt.
42510770Ssam  */
42610770Ssam rlintr(rl21)
42710770Ssam 	register rl21;
42810770Ssam {
42910770Ssam 	register struct buf *bp, *dp;
43010770Ssam 	register struct uba_ctlr *um = rlminfo[rl21];
43110770Ssam 	register struct uba_device *ui;
43210770Ssam 	register struct rldevice *rladdr = (struct rldevice *)um->um_addr;
43310770Ssam 	register unit;
43410770Ssam 	struct rl_softc *rl = &rl_softc[um->um_ctlr];
43510770Ssam 	struct rl_stat *st = &rl_stat[um->um_ctlr];
43610770Ssam 	int as = rl->rl_softas;
43710770Ssam 	int needie = 1, waitdry, status;
43810770Ssam 
43910770Ssam 	rl->rl_wticks = 0;
44010770Ssam 	rl->rl_softas = 0;
44110770Ssam 
44210770Ssam 	/*
44310770Ssam 	 * Get device and block structures, and a pointer
44410770Ssam 	 * to the uba_device for the drive.
44510770Ssam 	 */
44610770Ssam 	dp = um->um_tab.b_actf;
44710770Ssam 	bp = dp->b_actf;
44810770Ssam 	ui = rldinfo[dkunit(bp)];
44910770Ssam 	dk_busy &= ~(1 << ui->ui_dk);	/* Clear busy bit */
45010770Ssam 
45110770Ssam 	/*
45210770Ssam 	 * Check for and process errors on
45310770Ssam 	 * either the drive or the controller.
45410770Ssam 	 */
45510770Ssam 	if (rladdr->rlcs & RL_ERR) {
45610770Ssam 		u_short err;
45710770Ssam 		rlwait( rladdr );
45810770Ssam 
45910770Ssam 		err = rladdr->rlcs;
46010770Ssam 
46110770Ssam 		/* get staus and reset controller */
46210770Ssam 		rladdr->rlda.getstat = RL_GSTAT;
46310770Ssam 		rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT;
46410770Ssam 		rlwait(rladdr);
46510770Ssam 		status = rladdr->rlmp.getstat;
46610770Ssam 
46710770Ssam 		/* reset drive */
46810770Ssam 		rladdr->rlda.getstat = RL_RESET;
46910770Ssam 		rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/
47010770Ssam 		rlwait(rladdr);
47110770Ssam 
47210770Ssam 		if ( (status & RLMP_WL) == RLMP_WL ) {
47310770Ssam 			/*
47410770Ssam 			 * Give up on write protected devices
47510770Ssam 			 * immediately.
47610770Ssam 			 */
47710770Ssam 			printf("rl%d: write protected\n", dkunit(bp));
47810770Ssam 			bp->b_flags |= B_ERROR;
47910770Ssam 		} else if (++um->um_tab.b_errcnt > 10) {
48010770Ssam 			/*
48110770Ssam 			 * After 10 retries give up.
48210770Ssam 			 */
48310770Ssam 			harderr(bp, "rl");
48410770Ssam 			printf("cs=%b mp=%b\n",
48510770Ssam 				err, RLCS_BITS, status, RLER_BITS);
48610770Ssam 
48710770Ssam 			bp->b_flags |= B_ERROR;
48810770Ssam 		} else
48910770Ssam 			um->um_tab.b_active = 0;	 /* force retry */
49010770Ssam 
49110770Ssam 		/* Determine disk posistion */
49210770Ssam 		rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR;
49310770Ssam 		rlwait(rladdr);
49410770Ssam 
49510770Ssam 		/* save disk drive posistion */
49610770Ssam 		st->rl_cyl[ui->ui_slave] = (rladdr->rlmp.readhdr & 0177700) >> 6;
49710770Ssam 	}
49810770Ssam 
49910770Ssam 	/*
50010770Ssam 	 * If still ``active'', then don't need any more retries.
50110770Ssam 	 */
50210770Ssam 	if (um->um_tab.b_active) {
50310770Ssam 		/* RL02 check if more data from previous request */
50410770Ssam 		if ( (bp->b_flags & B_ERROR) == 0 &&
50510770Ssam 		     (st->rl_bleft -= st->rl_bpart) > 0 ) {
50610770Ssam 			/*
50710770Ssam 			 * the following code was modeled from the rk07
50810770Ssam 			 * driver when an ECC error occured.  It has to
50910770Ssam 			 * fix the bits then restart the transfer which is
51010770Ssam 			 * what we have to do (restart transfer).
51110770Ssam 			 */
51210770Ssam 			int reg, npf, o, cmd, ubaddr, diff, head;
51310770Ssam 
51410770Ssam 
51510770Ssam 			/* seek to next head/track */
51610770Ssam 
51710770Ssam 			/* increment head and/or cylinder */
51810770Ssam 			st->rl_cylnhd++;
51910770Ssam 			diff = (st->rl_cyl[ui->ui_slave] >> 1) -
52010770Ssam 				(st->rl_cylnhd >> 1);
52110770Ssam 			st->rl_cyl[ui->ui_slave] = st->rl_cylnhd;
52210770Ssam 			head = st->rl_cylnhd & 1;
52310770Ssam 			rlwait( rladdr );
52410770Ssam 
52510770Ssam 			if ( diff < 0 )
52610770Ssam 				rladdr->rlda.seek = -diff << 7 | RLDA_HGH | head << 4;
52710770Ssam 			else
52810770Ssam 				rladdr->rlda.seek = diff << 7 | RLDA_LOW | head << 4;
52910770Ssam 			rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK;
53010770Ssam 
53110770Ssam 			npf = btop( bp->b_bcount - st->rl_bleft );
53210770Ssam 			reg = btop(um->um_ubinfo&0x3ffff) + npf;
53310770Ssam 			o = (int)bp->b_un.b_addr & PGOFSET;
53410770Ssam 			ubapurge(um);
53510770Ssam 			um->um_tab.b_active++;
53610770Ssam 
53710770Ssam 			rlwait( rladdr );
53810770Ssam 			rladdr->rlda.rw = st->rl_cylnhd << 6;
53910770Ssam 			if ( st->rl_bleft < (st->rl_bpart = rl02.btrak) )
54010770Ssam 				st->rl_bpart = st->rl_bleft;
54110770Ssam 			rladdr->rlmp.rw = -(st->rl_bpart >> 1);
54210770Ssam 			cmd = (bp->b_flags&B_READ ? RL_READ : RL_WRITE) |
54310770Ssam 				RL_IE | (ui->ui_slave << 8);
54410770Ssam 			ubaddr = (int)ptob(reg) + o;
54510770Ssam 			cmd |= ((ubaddr >> 12) & RL_BAE);
54610770Ssam 
54710770Ssam 			rladdr->rlba = ubaddr;
54810770Ssam 			rladdr->rlcs = cmd;
54910770Ssam 			return;
55010770Ssam 		}
55110770Ssam 
55210770Ssam 		um->um_tab.b_active = 0;
55310770Ssam 		um->um_tab.b_errcnt = 0;
55410770Ssam 		dp->b_active = 0;
55510770Ssam 		dp->b_errcnt = 0;
55610770Ssam 
55710770Ssam 		/* "b_resid" words remaining after error */
55810770Ssam 		bp->b_resid = st->rl_bleft;
55910770Ssam 		um->um_tab.b_actf = dp->b_forw;
56010770Ssam 		dp->b_actf = bp->av_forw;
56110770Ssam 
56210770Ssam retry:
56310770Ssam 		st->rl_dn = -1;
56410770Ssam 		st->rl_bpart = st->rl_bleft = 0;
56510770Ssam 		iodone(bp);
56610770Ssam 		/*
56710770Ssam 		 * If this unit has more work to do,
56810770Ssam 		 * then start it up right away.
56910770Ssam 		 */
57010770Ssam 		if (dp->b_actf)
57110770Ssam 			if (rlustart(ui))
57210770Ssam 				needie = 0;
57310770Ssam 		as &= ~(1<<ui->ui_slave);
57410770Ssam 	} else
57510770Ssam 		as |= (1<<ui->ui_slave);
57610770Ssam 	/*
57710770Ssam 	 * Release unibus resources and flush data paths.
57810770Ssam 	 */
57910770Ssam 	ubadone(um);
58010770Ssam 
58110770Ssam 	/* reset state info */
58210770Ssam 	st->rl_dn = -1;
58310770Ssam 	st->rl_cylnhd = st->rl_bpart = st->rl_bleft = 0;
58410770Ssam 
58510770Ssam doattn:
58610770Ssam 	/*
58710770Ssam 	 * Process other units which need attention.
58810770Ssam 	 * For each unit which needs attention, call
58910770Ssam 	 * the unit start routine to place the slave
59010770Ssam 	 * on the controller device queue.
59110770Ssam 	 */
59210770Ssam 	while (unit = ffs(as)) {
59310770Ssam 		unit--;		/* was 1 origin */
59410770Ssam 		as &= ~(1<<unit);
59510770Ssam 		(void) rlustart(rlip[rl21][unit]);
59610770Ssam 	}
59710770Ssam 	/*
59810770Ssam 	 * If the controller is not transferring, but
59910770Ssam 	 * there are devices ready to transfer, start
60010770Ssam 	 * the controller.
60110770Ssam 	 */
60210770Ssam 	if (um->um_tab.b_actf && um->um_tab.b_active == 0)
60310770Ssam 		(void) rlstart(um);
60410770Ssam }
60510770Ssam 
60612452Ssam rlwait(rladdr)
60712452Ssam 	register struct rldevice *rladdr;
60810770Ssam {
60912452Ssam 
61010770Ssam 	while ((rladdr->rlcs & RL_CRDY) == 0)
61110770Ssam 		continue;         /* Wait */
61210770Ssam }
61310770Ssam 
61412452Ssam rlread(dev, uio)
61510770Ssam 	dev_t dev;
61612452Ssam 	struct uio *uio;
61710770Ssam {
61810770Ssam 	register int unit = minor(dev) >> 3;
61910770Ssam 
62010770Ssam 	if (unit >= NRL)
62112452Ssam 		return (ENXIO);
62212452Ssam 	return (physio(rlstrategy, &rrlbuf[unit], dev, B_READ, minphys, uio));
62310770Ssam }
62410770Ssam 
62512452Ssam rlwrite(dev, uio)
62610770Ssam 	dev_t dev;
62712452Ssam 	struct uio *uio;
62810770Ssam {
62910770Ssam 	register int unit = minor(dev) >> 3;
63010770Ssam 
63110770Ssam 	if (unit >= NRL)
63212452Ssam 		return (ENXIO);
63312452Ssam 	return (physio(rlstrategy, &rrlbuf[unit], dev, B_WRITE, minphys, uio));
63410770Ssam }
63510770Ssam 
63610770Ssam /*
63710770Ssam  * Reset driver after UBA init.
63810770Ssam  * Cancel software state of all pending transfers
63910770Ssam  * and restart all units and the controller.
64010770Ssam  */
64110770Ssam rlreset(uban)
64210770Ssam 	int uban;
64310770Ssam {
64410770Ssam 	register struct uba_ctlr *um;
64510770Ssam 	register struct uba_device *ui;
64610770Ssam 	register struct rldevice *rladdr;
64710770Ssam 	register struct rl_stat *st;
64810770Ssam 	register int	rl21, unit;
64910770Ssam 
65010770Ssam 	for (rl21 = 0; rl21 < NHL; rl21++) {
65110770Ssam 		if ((um = rlminfo[rl21]) == 0 || um->um_ubanum != uban ||
65210770Ssam 		    um->um_alive == 0)
65310770Ssam 			continue;
65410770Ssam 		printf(" Reset hl%d", rl21);
65510770Ssam 		rladdr = (struct rldevice *)um->um_addr;
65610770Ssam 		st = &rl_stat[rl21];
65710770Ssam 		um->um_tab.b_active = 0;
65810770Ssam 		um->um_tab.b_actf = um->um_tab.b_actl = 0;
65910770Ssam 		if (um->um_ubinfo) {
66010770Ssam 			printf("<%d>", (um->um_ubinfo>>28)&0xf);
66112452Ssam 			um->um_ubinfo = 0;
66210770Ssam 		}
66310770Ssam 
66410770Ssam 		/* reset controller */
66510770Ssam 		st->rl_dn = -1;
66610770Ssam 		st->rl_cylnhd = 0;
66710770Ssam 		st->rl_bleft = 0;
66810770Ssam 		st->rl_bpart = 0;
66912452Ssam 		rlwait(rladdr);
67010770Ssam 
67110770Ssam 		for (unit = 0; unit < NRL; unit++) {
67210770Ssam 			rladdr->rlcs = (unit << 8) | RL_GETSTAT;
67312452Ssam 			rlwait(rladdr);
67410770Ssam 
67510770Ssam 			/* Determine disk posistion */
67610770Ssam 			rladdr->rlcs = (unit << 8) | RL_RHDR;
67710770Ssam 			rlwait(rladdr);
67810770Ssam 
67910770Ssam 			/* save disk drive posistion */
68010770Ssam 			st->rl_cyl[unit] =
68110770Ssam 				(rladdr->rlmp.readhdr & 0177700) >> 6;
68210770Ssam 
68310770Ssam 			if ((ui = rldinfo[unit]) == 0)
68410770Ssam 				continue;
68510770Ssam 			if (ui->ui_alive == 0 || ui->ui_mi != um)
68610770Ssam 				continue;
68710770Ssam 			rlutab[unit].b_active = 0;
68810770Ssam 			(void) rlustart(ui);
68910770Ssam 		}
69010770Ssam 		(void) rlstart(um);
69110770Ssam 	}
69210770Ssam }
69310770Ssam 
69410770Ssam /*
69510770Ssam  * Wake up every second and if an interrupt is pending
69610770Ssam  * but nothing has happened increment a counter.
69710770Ssam  * If nothing happens for 20 seconds, reset the UNIBUS
69810770Ssam  * and begin anew.
69910770Ssam  */
70010770Ssam rlwatch()
70110770Ssam {
70210770Ssam 	register struct uba_ctlr *um;
70310770Ssam 	register rl21, unit;
70410770Ssam 	register struct rl_softc *rl;
70510770Ssam 
70610770Ssam 	timeout(rlwatch, (caddr_t)0, hz);
70710770Ssam 	for (rl21 = 0; rl21 < NHL; rl21++) {
70810770Ssam 		um = rlminfo[rl21];
70910770Ssam 		if (um == 0 || um->um_alive == 0)
71010770Ssam 			continue;
71110770Ssam 		rl = &rl_softc[rl21];
71210770Ssam 		if (um->um_tab.b_active == 0) {
71310770Ssam 			for (unit = 0; unit < NRL; unit++)
71410770Ssam 				if (rlutab[unit].b_active &&
71510770Ssam 				    rldinfo[unit]->ui_mi == um)
71610770Ssam 					goto active;
71710770Ssam 			rl->rl_wticks = 0;
71810770Ssam 			continue;
71910770Ssam 		}
72010770Ssam active:
72110770Ssam 		rl->rl_wticks++;
72210770Ssam 		if (rl->rl_wticks >= 20) {
72310770Ssam 			rl->rl_wticks = 0;
72410770Ssam 			printf("hl%d: lost interrupt\n", rl21);
72510770Ssam 			ubareset(um->um_ubanum);
72610770Ssam 		}
72710770Ssam 	}
72810770Ssam }
72910770Ssam 
73010770Ssam rldump(dev)
73110770Ssam 	dev_t dev;
73210770Ssam {
73310770Ssam 	/* don't think there is room on swap for it anyway. */
73410770Ssam }
735*12504Ssam 
736*12504Ssam rlsize(dev)
737*12504Ssam 	dev_t dev;
738*12504Ssam {
739*12504Ssam 	int unit = minor(dev) >> 3;
740*12504Ssam 	struct uba_device *ui;
741*12504Ssam 	struct rlst *st;
742*12504Ssam 
743*12504Ssam 	if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0)
744*12504Ssam 		return (-1);
745*12504Ssam 	st = &rl02;
746*12504Ssam 	return (st->sizes[minor(dev) & 07].nblocks);
747*12504Ssam }
748*12504Ssam #endif
749