xref: /csrg-svn/sys/vax/uba/rk.c (revision 34524)
123336Smckusick /*
229236Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323336Smckusick  * All rights reserved.  The Berkeley software License Agreement
423336Smckusick  * specifies the terms and conditions for redistribution.
523336Smckusick  *
6*34524Skarels  *	@(#)rk.c	7.4 (Berkeley) 05/27/88
723336Smckusick  */
81899Swnj 
91942Swnj #include "rk.h"
102648Swnj #if NHK > 0
113104Swnj int	rkpip;		/* DEBUG */
123104Swnj int	rknosval;	/* DEBUG */
133709Sroot #ifdef RKDEBUG
143293Swnj int	rkdebug;
153709Sroot #endif
163709Sroot #ifdef RKBDEBUG
173709Sroot int	rkbdebug;
183709Sroot #endif
191899Swnj /*
203293Swnj  * RK611/RK0[67] disk driver
212622Swnj  *
222622Swnj  * This driver mimics up.c; see it for an explanation of common code.
232685Swnj  *
242885Swnj  * TODO:
253208Swnj  *	Learn why we lose an interrupt sometime when spinning drives down
261899Swnj  */
279777Ssam #include "../machine/pte.h"
289777Ssam 
2917076Sbloom #include "param.h"
3017076Sbloom #include "systm.h"
3117076Sbloom #include "buf.h"
3217076Sbloom #include "conf.h"
3317076Sbloom #include "dir.h"
3417076Sbloom #include "user.h"
3517076Sbloom #include "map.h"
3617076Sbloom #include "vm.h"
3730390Skarels #include "dkstat.h"
3817076Sbloom #include "cmap.h"
3917076Sbloom #include "dkbad.h"
40*34524Skarels #include "ioctl.h"
41*34524Skarels #include "disklabel.h"
4217076Sbloom #include "uio.h"
4317076Sbloom #include "kernel.h"
4418315Sralph #include "syslog.h"
451899Swnj 
468478Sroot #include "../vax/cpu.h"
4717076Sbloom #include "ubareg.h"
4817076Sbloom #include "ubavar.h"
4917076Sbloom #include "rkreg.h"
501899Swnj 
512618Swnj struct	rk_softc {
522618Swnj 	int	sc_softas;
532618Swnj 	int	sc_ndrive;
542618Swnj 	int	sc_wticks;
552618Swnj 	int	sc_recal;
562648Swnj } rk_softc[NHK];
571899Swnj 
5824740Sbloom #define rkunit(dev)	(minor(dev) >> 3)
5924740Sbloom 
602618Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
612787Swnj struct size {
622618Swnj 	daddr_t	nblocks;
632618Swnj 	int	cyloff;
6425322Smckusick } rk7_sizes[8] = {
652618Swnj 	15884,	0,		/* A=cyl 0 thru 240 */
662665Swnj 	10032,	241,		/* B=cyl 241 thru 392 */
672665Swnj 	53790,	0,		/* C=cyl 0 thru 814 */
6825322Smckusick 	15884,	393,		/* D=cyl 393 thru 633 */
692618Swnj 	0,	0,
7025322Smckusick 	11792,	634,		/* F=cyl 634 thru 814 */
7125322Smckusick 	27786,	393,		/* G=cyl 393 thru 814, should be 27698 */
722618Swnj 	0,	0,
733709Sroot }, rk6_sizes[8] ={
743709Sroot 	15884,	0,		/* A=cyl 0 thru 240 */
753709Sroot 	11154,	241,		/* B=cyl 241 thru 409 */
763709Sroot 	27126,	0,		/* C=cyl 0 thru 410 */
773709Sroot 	0,	0,
783709Sroot 	0,	0,
793709Sroot 	0,	0,
803709Sroot 	0,	0,
813709Sroot 	0,	0,
822618Swnj };
832618Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
841899Swnj 
853709Sroot short	rktypes[] = { RK_CDT, 0 };
863709Sroot 
872618Swnj int	rkprobe(), rkslave(), rkattach(), rkdgo(), rkintr();
882981Swnj struct	uba_ctlr *rkminfo[NHK];
892981Swnj struct	uba_device *rkdinfo[NRK];
902981Swnj struct	uba_device *rkip[NHK][4];
911899Swnj 
922618Swnj u_short	rkstd[] = { 0777440, 0 };
932618Swnj struct	uba_driver hkdriver =
942622Swnj  { rkprobe, rkslave, rkattach, rkdgo, rkstd, "rk", rkdinfo, "hk", rkminfo, 1 };
952648Swnj struct	buf rkutab[NRK];
962648Swnj short	rkcyl[NRK];
973709Sroot struct	dkbad rkbad[NRK];
983709Sroot struct	buf brkbuf[NRK];
991899Swnj 
1002618Swnj struct	rkst {
1012618Swnj 	short	nsect;
1022618Swnj 	short	ntrak;
1032618Swnj 	short	nspc;
1042618Swnj 	short	ncyl;
1052618Swnj 	struct	size *sizes;
1062618Swnj } rkst[] = {
1072618Swnj 	NRKSECT, NRKTRK, NRKSECT*NRKTRK,	NRK7CYL,	rk7_sizes,
1083709Sroot 	NRKSECT, NRKTRK, NRKSECT*NRKTRK,	NRK6CYL,	rk6_sizes,
1092618Swnj };
1101899Swnj 
1112618Swnj u_char 	rk_offset[16] =
1123293Swnj   { RKAS_P400,RKAS_M400,RKAS_P400,RKAS_M400,RKAS_P800,RKAS_M800,RKAS_P800,
1133293Swnj     RKAS_M800,RKAS_P1200,RKAS_M1200,RKAS_P1200,RKAS_M1200,0,0,0,0
1143293Swnj   };
1151899Swnj 
1162618Swnj #define	b_cylin	b_resid
1172618Swnj 
1182618Swnj int	rkwstart, rkwatch();
1192618Swnj 
1202618Swnj rkprobe(reg)
1212618Swnj 	caddr_t reg;
1221899Swnj {
1232618Swnj 	register int br, cvec;
1241899Swnj 
1252618Swnj #ifdef lint
1262618Swnj 	br = 0; cvec = br; br = cvec;
1274935Swnj 	rkintr(0);
1282618Swnj #endif
1292618Swnj 	((struct rkdevice *)reg)->rkcs1 = RK_CDT|RK_IE|RK_CRDY;
1302618Swnj 	DELAY(10);
1312618Swnj 	((struct rkdevice *)reg)->rkcs1 = RK_CDT;
1327416Skre 	return (sizeof (struct rkdevice));
1332618Swnj }
1341899Swnj 
1352618Swnj rkslave(ui, reg)
1362981Swnj 	struct uba_device *ui;
1372618Swnj 	caddr_t reg;
1382618Swnj {
1392618Swnj 	register struct rkdevice *rkaddr = (struct rkdevice *)reg;
1401899Swnj 
1413709Sroot 	ui->ui_type = 0;
1423709Sroot 	rkaddr->rkcs1 = RK_CCLR;
1432618Swnj 	rkaddr->rkcs2 = ui->ui_slave;
1442957Swnj 	rkaddr->rkcs1 = RK_CDT|RK_DCLR|RK_GO;
1452622Swnj 	rkwait(rkaddr);
1462894Swnj 	DELAY(50);
1473293Swnj 	if (rkaddr->rkcs2&RKCS2_NED || (rkaddr->rkds&RKDS_SVAL) == 0) {
1483709Sroot 		rkaddr->rkcs1 = RK_CCLR;
1492618Swnj 		return (0);
1502618Swnj 	}
1513709Sroot 	if (rkaddr->rkcs1&RK_CERR && rkaddr->rker&RKER_DTYE) {
1523709Sroot 		ui->ui_type = 1;
1533709Sroot 		rkaddr->rkcs1 = RK_CCLR;
1543709Sroot 	}
1552618Swnj 	return (1);
1562618Swnj }
1572618Swnj 
1582618Swnj rkattach(ui)
1592981Swnj 	register struct uba_device *ui;
1602618Swnj {
1612618Swnj 
1622618Swnj 	if (rkwstart == 0) {
1632758Swnj 		timeout(rkwatch, (caddr_t)0, hz);
1642618Swnj 		rkwstart++;
1652618Swnj 	}
1662618Swnj 	if (ui->ui_dk >= 0)
1672758Swnj 		dk_mspw[ui->ui_dk] = 1.0 / (60 * NRKSECT * 256);
1682618Swnj 	rkip[ui->ui_ctlr][ui->ui_slave] = ui;
1692618Swnj 	rk_softc[ui->ui_ctlr].sc_ndrive++;
1702618Swnj 	rkcyl[ui->ui_unit] = -1;
1713709Sroot 	ui->ui_flags = 0;
1722618Swnj }
1732618Swnj 
1748573Sroot rkopen(dev)
1758573Sroot 	dev_t dev;
1768573Sroot {
17724785Skarels 	register int unit = rkunit(dev);
1788573Sroot 	register struct uba_device *ui;
1798573Sroot 
1808573Sroot 	if (unit >= NRK || (ui = rkdinfo[unit]) == 0 || ui->ui_alive == 0)
1818573Sroot 		return (ENXIO);
1828573Sroot 	return (0);
1838573Sroot }
1848573Sroot 
1851899Swnj rkstrategy(bp)
1862618Swnj 	register struct buf *bp;
1871899Swnj {
1882981Swnj 	register struct uba_device *ui;
1892618Swnj 	register struct rkst *st;
1902618Swnj 	register int unit;
1912618Swnj 	register struct buf *dp;
1922618Swnj 	int xunit = minor(bp->b_dev) & 07;
1932618Swnj 	long bn, sz;
1945433Sroot 	int s;
1951899Swnj 
1962618Swnj 	sz = (bp->b_bcount+511) >> 9;
19724740Sbloom 	unit = rkunit(bp->b_dev);
19824740Sbloom 	if (unit >= NRK) {
19924740Sbloom 		bp->b_error = ENXIO;
2002618Swnj 		goto bad;
20124740Sbloom 	}
2022618Swnj 	ui = rkdinfo[unit];
20324740Sbloom 	if (ui == 0 || ui->ui_alive == 0) {
20424740Sbloom 		bp->b_error = ENXIO;
2052618Swnj 		goto bad;
20624740Sbloom 	}
2072618Swnj 	st = &rkst[ui->ui_type];
2082618Swnj 	if (bp->b_blkno < 0 ||
20924740Sbloom 	    (bn = bp->b_blkno)+sz > st->sizes[xunit].nblocks) {
21024785Skarels 		if (bp->b_blkno == st->sizes[xunit].nblocks) {
21124785Skarels 		    bp->b_resid = bp->b_bcount;
21224740Sbloom 		    goto done;
21324785Skarels 		}
21424740Sbloom 		bp->b_error = EINVAL;
2152618Swnj 		goto bad;
21624740Sbloom 	}
2172618Swnj 	bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff;
2185433Sroot 	s = spl5();
2192618Swnj 	dp = &rkutab[ui->ui_unit];
2202618Swnj 	disksort(dp, bp);
2212618Swnj 	if (dp->b_active == 0) {
2222618Swnj 		(void) rkustart(ui);
2232618Swnj 		bp = &ui->ui_mi->um_tab;
2242618Swnj 		if (bp->b_actf && bp->b_active == 0)
2252618Swnj 			(void) rkstart(ui->ui_mi);
2261899Swnj 	}
2275433Sroot 	splx(s);
2282618Swnj 	return;
2292618Swnj 
2302618Swnj bad:
2312618Swnj 	bp->b_flags |= B_ERROR;
23224740Sbloom done:
2332618Swnj 	iodone(bp);
2342618Swnj 	return;
2351899Swnj }
2361899Swnj 
2372618Swnj rkustart(ui)
2382981Swnj 	register struct uba_device *ui;
2392618Swnj {
2402618Swnj 	register struct buf *bp, *dp;
2412981Swnj 	register struct uba_ctlr *um;
2422618Swnj 	register struct rkdevice *rkaddr;
2431899Swnj 
2442618Swnj 	if (ui == 0)
2456347Swnj 		return;
2462618Swnj 	dk_busy &= ~(1<<ui->ui_dk);
2472618Swnj 	dp = &rkutab[ui->ui_unit];
2482618Swnj 	um = ui->ui_mi;
2492894Swnj 	rkaddr = (struct rkdevice *)um->um_addr;
2502618Swnj 	if (um->um_tab.b_active) {
2512618Swnj 		rk_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave;
2526347Swnj 		return;
2532618Swnj 	}
2546347Swnj 	if ((bp = dp->b_actf) == NULL)
2556347Swnj 		return;
2563709Sroot 	rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_CERR;
2572618Swnj 	rkaddr->rkcs2 = ui->ui_slave;
2583709Sroot 	rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_DCLR|RK_GO;
2592618Swnj 	rkwait(rkaddr);
2603709Sroot 	if ((rkaddr->rkds & RKDS_VV) == 0 || ui->ui_flags == 0) {
2612618Swnj 		/* SHOULD WARN SYSTEM THAT THIS HAPPENED */
2623709Sroot 		struct rkst *st = &rkst[ui->ui_type];
2633709Sroot 		struct buf *bbp = &brkbuf[ui->ui_unit];
2643709Sroot 
2653709Sroot 		rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_PACK|RK_GO;
2663709Sroot 		ui->ui_flags = 1;
2673709Sroot 		bbp->b_flags = B_READ|B_BUSY;
2683709Sroot 		bbp->b_dev = bp->b_dev;
2693709Sroot 		bbp->b_bcount = 512;
2703709Sroot 		bbp->b_un.b_addr = (caddr_t)&rkbad[ui->ui_unit];
2713709Sroot 		bbp->b_blkno = st->ncyl*st->nspc - st->nsect;
2723709Sroot 		bbp->b_cylin = st->ncyl - 1;
2733709Sroot 		dp->b_actf = bbp;
2743709Sroot 		bbp->av_forw = bp;
2753709Sroot 		bp = bbp;
2762618Swnj 		rkwait(rkaddr);
2772618Swnj 	}
2782903Swnj 	if (dp->b_active)
2792903Swnj 		goto done;
2802903Swnj 	dp->b_active = 1;
2813293Swnj 	if ((rkaddr->rkds & RKDS_DREADY) != RKDS_DREADY)
2822894Swnj 		goto done;
2832618Swnj 	if (rk_softc[um->um_ctlr].sc_ndrive == 1)
2842618Swnj 		goto done;
2852618Swnj 	if (bp->b_cylin == rkcyl[ui->ui_unit])
2862618Swnj 		goto done;
2872618Swnj 	rkaddr->rkcyl = bp->b_cylin;
2882618Swnj 	rkcyl[ui->ui_unit] = bp->b_cylin;
2893709Sroot 	rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_IE|RK_SEEK|RK_GO;
2902618Swnj 	if (ui->ui_dk >= 0) {
2912618Swnj 		dk_busy |= 1<<ui->ui_dk;
2922618Swnj 		dk_seek[ui->ui_dk]++;
2932618Swnj 	}
2942618Swnj 	goto out;
2952618Swnj done:
2962618Swnj 	if (dp->b_active != 2) {
2972618Swnj 		dp->b_forw = NULL;
2982618Swnj 		if (um->um_tab.b_actf == NULL)
2992618Swnj 			um->um_tab.b_actf = dp;
3002618Swnj 		else
3012618Swnj 			um->um_tab.b_actl->b_forw = dp;
3022618Swnj 		um->um_tab.b_actl = dp;
3032618Swnj 		dp->b_active = 2;
3042618Swnj 	}
3052618Swnj out:
3066347Swnj 	return;
3072618Swnj }
3082618Swnj 
3092618Swnj rkstart(um)
3102981Swnj 	register struct uba_ctlr *um;
3111899Swnj {
3122618Swnj 	register struct buf *bp, *dp;
3132981Swnj 	register struct uba_device *ui;
3142618Swnj 	register struct rkdevice *rkaddr;
3152618Swnj 	struct rkst *st;
3161899Swnj 	daddr_t bn;
3172618Swnj 	int sn, tn, cmd;
3181899Swnj 
3192618Swnj loop:
3202618Swnj 	if ((dp = um->um_tab.b_actf) == NULL)
3216347Swnj 		return;
3222618Swnj 	if ((bp = dp->b_actf) == NULL) {
3232618Swnj 		um->um_tab.b_actf = dp->b_forw;
3242618Swnj 		goto loop;
3251899Swnj 	}
3262618Swnj 	um->um_tab.b_active++;
32724740Sbloom 	ui = rkdinfo[rkunit(bp->b_dev)];
32824740Sbloom 	bn = bp->b_blkno;
3292618Swnj 	st = &rkst[ui->ui_type];
3302618Swnj 	sn = bn%st->nspc;
3312618Swnj 	tn = sn/st->nsect;
3322618Swnj 	sn %= st->nsect;
3332618Swnj 	rkaddr = (struct rkdevice *)ui->ui_addr;
3342957Swnj retry:
3353709Sroot 	rkaddr->rkcs1 = RK_CCLR;
3362618Swnj 	rkaddr->rkcs2 = ui->ui_slave;
3373709Sroot 	rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_DCLR|RK_GO;
3382618Swnj 	rkwait(rkaddr);
3393293Swnj 	if ((rkaddr->rkds&RKDS_SVAL) == 0) {
3402957Swnj 		rknosval++;
3412957Swnj 		goto nosval;
3422894Swnj 	}
3433293Swnj 	if (rkaddr->rkds&RKDS_PIP) {
3442957Swnj 		rkpip++;
3452957Swnj 		goto retry;
3462957Swnj 	}
3473293Swnj 	if ((rkaddr->rkds&RKDS_DREADY) != RKDS_DREADY) {
34824740Sbloom 		printf("rk%d: not ready", rkunit(bp->b_dev));
3493293Swnj 		if ((rkaddr->rkds&RKDS_DREADY) != RKDS_DREADY) {
3502894Swnj 			printf("\n");
3513709Sroot 			rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_DCLR|RK_GO;
3522894Swnj 			rkwait(rkaddr);
3533709Sroot 			rkaddr->rkcs1 = RK_CCLR;
3542894Swnj 			rkwait(rkaddr);
3552894Swnj 			um->um_tab.b_active = 0;
3562894Swnj 			um->um_tab.b_errcnt = 0;
3572894Swnj 			dp->b_actf = bp->av_forw;
3582894Swnj 			dp->b_active = 0;
3592894Swnj 			bp->b_flags |= B_ERROR;
3602894Swnj 			iodone(bp);
3612894Swnj 			goto loop;
3622894Swnj 		}
3632894Swnj 		printf(" (came back!)\n");
3642894Swnj 	}
3652957Swnj nosval:
3662618Swnj 	rkaddr->rkcyl = bp->b_cylin;
3672618Swnj 	rkcyl[ui->ui_unit] = bp->b_cylin;
3682618Swnj 	rkaddr->rkda = (tn << 8) + sn;
3692618Swnj 	rkaddr->rkwc = -bp->b_bcount / sizeof (short);
3702618Swnj 	if (bp->b_flags & B_READ)
3713709Sroot 		cmd = rktypes[ui->ui_type]|RK_IE|RK_READ|RK_GO;
3722618Swnj 	else
3733709Sroot 		cmd = rktypes[ui->ui_type]|RK_IE|RK_WRITE|RK_GO;
3742618Swnj 	um->um_cmd = cmd;
3753104Swnj 	(void) ubago(ui);
3761899Swnj }
3771899Swnj 
3782618Swnj rkdgo(um)
3792981Swnj 	register struct uba_ctlr *um;
3801899Swnj {
3812618Swnj 	register struct rkdevice *rkaddr = (struct rkdevice *)um->um_addr;
3821899Swnj 
3837031Swnj 	um->um_tab.b_active = 2;	/* should now be 2 */
3842618Swnj 	rkaddr->rkba = um->um_ubinfo;
3852618Swnj 	rkaddr->rkcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300);
3862618Swnj }
3872618Swnj 
3882710Swnj rkintr(rk11)
3892618Swnj 	int rk11;
3902618Swnj {
3912981Swnj 	register struct uba_ctlr *um = rkminfo[rk11];
3922981Swnj 	register struct uba_device *ui;
3932618Swnj 	register struct rkdevice *rkaddr = (struct rkdevice *)um->um_addr;
3942618Swnj 	register struct buf *bp, *dp;
3952618Swnj 	int unit;
3962618Swnj 	struct rk_softc *sc = &rk_softc[um->um_ctlr];
3972618Swnj 	int as = (rkaddr->rkatt >> 8) | sc->sc_softas;
3982618Swnj 
3992618Swnj 	sc->sc_wticks = 0;
4002618Swnj 	sc->sc_softas = 0;
4016347Swnj 	if (um->um_tab.b_active == 2 || sc->sc_recal) {
4027031Swnj 		um->um_tab.b_active = 1;
4032618Swnj 		dp = um->um_tab.b_actf;
4042618Swnj 		bp = dp->b_actf;
40524740Sbloom 		ui = rkdinfo[rkunit(bp->b_dev)];
4062618Swnj 		dk_busy &= ~(1 << ui->ui_dk);
4073709Sroot 		if (bp->b_flags&B_BAD)
4083709Sroot 			if (rkecc(ui, CONT))
4093709Sroot 				return;
4102618Swnj 		if (rkaddr->rkcs1 & RK_CERR) {
4112618Swnj 			int recal;
4122618Swnj 			u_short ds = rkaddr->rkds;
4132618Swnj 			u_short cs2 = rkaddr->rkcs2;
4142618Swnj 			u_short er = rkaddr->rker;
4153709Sroot #ifdef RKDEBUG
4163293Swnj 			if (rkdebug) {
4173293Swnj 				printf("cs2=%b ds=%b er=%b\n",
4183293Swnj 				    cs2, RKCS2_BITS, ds,
4193293Swnj 				    RKDS_BITS, er, RKER_BITS);
4203293Swnj 			}
4213709Sroot #endif
4223293Swnj 			if (er & RKER_WLE) {
42324740Sbloom 				printf("rk%d: write locked\n",
42424740Sbloom 					rkunit(bp->b_dev));
4252685Swnj 				bp->b_flags |= B_ERROR;
4262685Swnj 			} else if (++um->um_tab.b_errcnt > 28 ||
4272676Swnj 			    ds&RKDS_HARD || er&RKER_HARD || cs2&RKCS2_HARD) {
4283709Sroot hard:
429*34524Skarels 				diskerr(bp, "rk", "hard error", LOG_PRINTF, -1,
430*34524Skarels 				    (struct disklabel *)0);
431*34524Skarels 				printf(" cs2=%b ds=%b er=%b\n",
4322894Swnj 				    cs2, RKCS2_BITS, ds,
4332676Swnj 				    RKDS_BITS, er, RKER_BITS);
4343145Swnj 				bp->b_flags |= B_ERROR;
4353145Swnj 				sc->sc_recal = 0;
4363709Sroot 			} else if (er & RKER_BSE) {
4373709Sroot 				if (rkecc(ui, BSE))
4383709Sroot 					return;
4393709Sroot 				else
4403709Sroot 					goto hard;
4417182Sroot 			} else {
4427182Sroot 				if ((er & (RKER_DCK|RKER_ECH)) == RKER_DCK) {
4437182Sroot 					if (rkecc(ui, ECC))
4447182Sroot 						return;
4457182Sroot 				} else
4467182Sroot 					um->um_tab.b_active = 0;
4477182Sroot 			}
4483293Swnj 			if (cs2&RKCS2_MDS) {
4493293Swnj 				rkaddr->rkcs2 = RKCS2_SCLR;
4502618Swnj 				goto retry;
4511899Swnj 			}
4522618Swnj 			recal = 0;
4533293Swnj 			if (ds&RKDS_DROT || er&(RKER_OPI|RKER_SKI|RKER_UNS) ||
4542618Swnj 			    (um->um_tab.b_errcnt&07) == 4)
4552618Swnj 				recal = 1;
4563709Sroot 			rkaddr->rkcs1 = RK_CCLR;
4572618Swnj 			rkaddr->rkcs2 = ui->ui_slave;
4583709Sroot 			rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_DCLR|RK_GO;
4592618Swnj 			rkwait(rkaddr);
4602618Swnj 			if (recal && um->um_tab.b_active == 0) {
4613709Sroot 				rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_IE|RK_RECAL|RK_GO;
4622618Swnj 				rkcyl[ui->ui_unit] = -1;
4632957Swnj 				sc->sc_recal = 0;
4642957Swnj 				goto nextrecal;
4652618Swnj 			}
4661899Swnj 		}
4672618Swnj retry:
4682957Swnj 		switch (sc->sc_recal) {
4692957Swnj 
4702957Swnj 		case 1:
4712957Swnj 			rkaddr->rkcyl = bp->b_cylin;
4722957Swnj 			rkcyl[ui->ui_unit] = bp->b_cylin;
4733709Sroot 			rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_IE|RK_SEEK|RK_GO;
4742957Swnj 			goto nextrecal;
4752957Swnj 		case 2:
4762957Swnj 			if (um->um_tab.b_errcnt < 16 ||
4773290Swnj 			    (bp->b_flags&B_READ) == 0)
4783159Swnj 				goto donerecal;
4792957Swnj 			rkaddr->rkatt = rk_offset[um->um_tab.b_errcnt & 017];
4803709Sroot 			rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_IE|RK_OFFSET|RK_GO;
4812957Swnj 			/* fall into ... */
4822957Swnj 		nextrecal:
4832957Swnj 			sc->sc_recal++;
4842957Swnj 			rkwait(rkaddr);
4852957Swnj 			um->um_tab.b_active = 1;
4862957Swnj 			return;
4873159Swnj 		donerecal:
4882957Swnj 		case 3:
4892618Swnj 			sc->sc_recal = 0;
4902618Swnj 			um->um_tab.b_active = 0;
4912957Swnj 			break;
4921899Swnj 		}
4933709Sroot 		ubadone(um);
4942618Swnj 		if (um->um_tab.b_active) {
4952618Swnj 			um->um_tab.b_active = 0;
4962618Swnj 			um->um_tab.b_errcnt = 0;
4972618Swnj 			um->um_tab.b_actf = dp->b_forw;
4982618Swnj 			dp->b_active = 0;
4992618Swnj 			dp->b_errcnt = 0;
5002618Swnj 			dp->b_actf = bp->av_forw;
5012618Swnj 			bp->b_resid = -rkaddr->rkwc * sizeof(short);
5022618Swnj 			iodone(bp);
5032618Swnj 			if (dp->b_actf)
5046347Swnj 				rkustart(ui);
5051899Swnj 		}
5062618Swnj 		as &= ~(1<<ui->ui_slave);
5071899Swnj 	}
5082618Swnj 	for (unit = 0; as; as >>= 1, unit++)
5092981Swnj 		if (as & 1) {
5102981Swnj 			ui = rkip[rk11][unit];
5112981Swnj 			if (ui) {
5126347Swnj 				rkustart(rkip[rk11][unit]);
5132981Swnj 			} else {
5143709Sroot 				rkaddr->rkcs1 = RK_CCLR;
5152981Swnj 				rkaddr->rkcs2 = unit;
5163709Sroot 				rkaddr->rkcs1 = RK_DCLR|RK_GO;
5172981Swnj 				rkwait(rkaddr);
5183709Sroot 				rkaddr->rkcs1 = RK_CCLR;
5192981Swnj 			}
5202981Swnj 		}
5212618Swnj 	if (um->um_tab.b_actf && um->um_tab.b_active == 0)
5226347Swnj 		rkstart(um);
5238609Sroot 	if (((rkaddr->rkcs1) & RK_IE) == 0)
5243709Sroot 		rkaddr->rkcs1 = RK_IE;
5251899Swnj }
5261899Swnj 
5272618Swnj rkwait(addr)
5282618Swnj 	register struct rkdevice *addr;
5292618Swnj {
5301899Swnj 
5312618Swnj 	while ((addr->rkcs1 & RK_CRDY) == 0)
5322618Swnj 		;
5332618Swnj }
5342618Swnj 
5353709Sroot rkecc(ui, flag)
5362981Swnj 	register struct uba_device *ui;
5371899Swnj {
5382618Swnj 	register struct rkdevice *rk = (struct rkdevice *)ui->ui_addr;
5392618Swnj 	register struct buf *bp = rkutab[ui->ui_unit].b_actf;
5402981Swnj 	register struct uba_ctlr *um = ui->ui_mi;
5412618Swnj 	register struct rkst *st;
5422618Swnj 	struct uba_regs *ubp = ui->ui_hd->uh_uba;
5432618Swnj 	caddr_t addr;
5443709Sroot 	int reg, npf, o, cmd, ubaddr;
5452618Swnj 	int bn, cn, tn, sn;
5461899Swnj 
5473709Sroot 	if (flag == CONT)
5483709Sroot 		npf = bp->b_error;
5493709Sroot 	else
55027675Skarels 		npf = btodb(bp->b_bcount + (rk->rkwc * sizeof(short)) + 511);
5512618Swnj 	reg = btop(um->um_ubinfo&0x3ffff) + npf;
5522618Swnj 	o = (int)bp->b_un.b_addr & PGOFSET;
55324740Sbloom 	bn = bp->b_blkno;
5542618Swnj 	st = &rkst[ui->ui_type];
5552618Swnj 	cn = bp->b_cylin;
5563709Sroot 	sn = bn%st->nspc + npf;
5572618Swnj 	tn = sn/st->nsect;
5582618Swnj 	sn %= st->nsect;
5592618Swnj 	cn += tn/st->ntrak;
5602618Swnj 	tn %= st->ntrak;
5613709Sroot 	ubapurge(um);
5623709Sroot 	switch (flag) {
5633709Sroot 	case ECC:
5643709Sroot 		{
5653709Sroot 		register int i;
5663709Sroot 		int bit, byte, mask;
5673709Sroot 
5683709Sroot 		npf--;
5693709Sroot 		reg--;
570*34524Skarels 		diskerr(bp, "rk", "soft ecc", LOG_WARNING, npf,
571*34524Skarels 		    (struct disklabel *)0);
572*34524Skarels 		addlog("\n");
5733709Sroot 		mask = rk->rkec2;
5743709Sroot 		i = rk->rkec1 - 1;		/* -1 makes 0 origin */
5753709Sroot 		bit = i&07;
5763709Sroot 		i = (i&~07)>>3;
5773709Sroot 		byte = i + o;
57827675Skarels 		while (i < 512 && (int)dbtob(npf)+i < bp->b_bcount && bit > -11) {
5793709Sroot 			addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+
5803709Sroot 			    (byte & PGOFSET);
5813709Sroot 			putmemc(addr, getmemc(addr)^(mask<<bit));
5823709Sroot 			byte++;
5833709Sroot 			i++;
5843709Sroot 			bit -= 8;
5853709Sroot 		}
5867182Sroot 		if (rk->rkwc == 0) {
5877182Sroot 			um->um_tab.b_active = 0;
5883709Sroot 			return (0);
5897182Sroot 		}
5903709Sroot 		npf++;
5913709Sroot 		reg++;
5923709Sroot 		break;
5933709Sroot 		}
5943709Sroot 
5953709Sroot 	case BSE:
5963709Sroot #ifdef RKBDEBUG
5973709Sroot 		if (rkbdebug)
5983709Sroot 	printf("rkecc, BSE: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn);
5993709Sroot #endif
6003709Sroot 		if ((bn = isbad(&rkbad[ui->ui_unit], cn, tn, sn)) < 0)
6013709Sroot 			return(0);
6023709Sroot 		bp->b_flags |= B_BAD;
6033709Sroot 		bp->b_error = npf + 1;
6043709Sroot 		bn = st->ncyl*st->nspc - st->nsect - 1 - bn;
6053709Sroot 		cn = bn/st->nspc;
6063709Sroot 		sn = bn%st->nspc;
6073709Sroot 		tn = sn/st->nsect;
6083709Sroot 		sn %= st->nsect;
6093709Sroot #ifdef RKBDEBUG
6103709Sroot 		if (rkbdebug)
6113709Sroot 	printf("revector to cn %d tn %d sn %d\n", cn, tn, sn);
6123709Sroot #endif
6133709Sroot 		rk->rkwc = -(512 / sizeof (short));
6143709Sroot 		break;
6153709Sroot 
6163709Sroot 	case CONT:
6173709Sroot #ifdef RKBDEBUG
6183709Sroot 		if (rkbdebug)
6193709Sroot 	printf("rkecc, CONT: bn %d cn %d tn %d sn %d\n", bn,cn,tn,sn);
6203709Sroot #endif
6213709Sroot 		bp->b_flags &= ~B_BAD;
62227675Skarels 		if ((int)dbtob(npf) >= bp->b_bcount)
6237182Sroot 			return (0);
62427675Skarels 		rk->rkwc = -((bp->b_bcount - (int)dbtob(npf)) / sizeof (short));
6253709Sroot 		break;
6263709Sroot 	}
6273709Sroot 	rk->rkcs1 = RK_CCLR;
6283709Sroot 	rk->rkcs2 = ui->ui_slave;
6293709Sroot 	rk->rkcs1 = rktypes[ui->ui_type]|RK_DCLR|RK_GO;
6303709Sroot 	rkwait(rk);
6312618Swnj 	rk->rkcyl = cn;
6322618Swnj 	rk->rkda = (tn << 8) | sn;
6333709Sroot 	ubaddr = (int)ptob(reg) + o;
6342618Swnj 	rk->rkba = ubaddr;
6353709Sroot 	cmd = (bp->b_flags&B_READ ? RK_READ : RK_WRITE)|RK_IE|RK_GO;
6363709Sroot 	cmd |= (ubaddr >> 8) & 0x300;
6373709Sroot 	cmd |= rktypes[ui->ui_type];
6382618Swnj 	rk->rkcs1 = cmd;
6397031Swnj 	um->um_tab.b_active = 2;	/* continuing */
6403709Sroot 	um->um_tab.b_errcnt = 0;	/* error has been corrected */
6412618Swnj 	return (1);
6421899Swnj }
6431899Swnj 
6442618Swnj rkreset(uban)
6452927Swnj 	int uban;
6461899Swnj {
6472981Swnj 	register struct uba_ctlr *um;
6482981Swnj 	register struct uba_device *ui;
6492618Swnj 	register rk11, unit;
6501899Swnj 
6512648Swnj 	for (rk11 = 0; rk11 < NHK; rk11++) {
6522618Swnj 		if ((um = rkminfo[rk11]) == 0 || um->um_ubanum != uban ||
6532618Swnj 		    um->um_alive == 0)
6542618Swnj 			continue;
6552927Swnj 		printf(" hk%d", rk11);
6562618Swnj 		um->um_tab.b_active = 0;
6572618Swnj 		um->um_tab.b_actf = um->um_tab.b_actl = 0;
6582618Swnj 		rk_softc[um->um_ctlr].sc_recal = 0;
6596347Swnj 		rk_softc[um->um_ctlr].sc_wticks = 0;
6602618Swnj 		if (um->um_ubinfo) {
6612618Swnj 			printf("<%d>", (um->um_ubinfo>>28)&0xf);
6629354Ssam 			um->um_ubinfo = 0;
6632618Swnj 		}
6644039Swnj 		for (unit = 0; unit < NRK; unit++) {
6652618Swnj 			if ((ui = rkdinfo[unit]) == 0)
6662618Swnj 				continue;
6674039Swnj 			if (ui->ui_alive == 0 || ui->ui_mi != um)
6682618Swnj 				continue;
6692618Swnj 			rkutab[unit].b_active = 0;
6702618Swnj 			(void) rkustart(ui);
6712618Swnj 		}
6722618Swnj 		(void) rkstart(um);
6732618Swnj 	}
6741899Swnj }
6752380Swnj 
6762618Swnj rkwatch()
6772380Swnj {
6782981Swnj 	register struct uba_ctlr *um;
6792618Swnj 	register rk11, unit;
6802618Swnj 	register struct rk_softc *sc;
6812380Swnj 
6822758Swnj 	timeout(rkwatch, (caddr_t)0, hz);
6832648Swnj 	for (rk11 = 0; rk11 < NHK; rk11++) {
6842618Swnj 		um = rkminfo[rk11];
6852618Swnj 		if (um == 0 || um->um_alive == 0)
6862618Swnj 			continue;
6872618Swnj 		sc = &rk_softc[rk11];
6882618Swnj 		if (um->um_tab.b_active == 0) {
6892648Swnj 			for (unit = 0; unit < NRK; unit++)
6902622Swnj 				if (rkutab[unit].b_active &&
6912622Swnj 				    rkdinfo[unit]->ui_mi == um)
6922618Swnj 					goto active;
6932618Swnj 			sc->sc_wticks = 0;
6942618Swnj 			continue;
6952618Swnj 		}
6962618Swnj active:
6972618Swnj 		sc->sc_wticks++;
6982618Swnj 		if (sc->sc_wticks >= 20) {
6992618Swnj 			sc->sc_wticks = 0;
7002927Swnj 			printf("hk%d: lost interrupt\n", rk11);
7012648Swnj 			ubareset(um->um_ubanum);
7022618Swnj 		}
7032618Swnj 	}
7042380Swnj }
7052618Swnj 
7062618Swnj #define	DBSIZE	20
7072618Swnj 
7082618Swnj rkdump(dev)
7092618Swnj 	dev_t dev;
7102618Swnj {
7112618Swnj 	struct rkdevice *rkaddr;
7122618Swnj 	char *start;
7132618Swnj 	int num, blk, unit;
7142618Swnj 	struct size *sizes;
7152618Swnj 	register struct uba_regs *uba;
7162981Swnj 	register struct uba_device *ui;
7172618Swnj 	register short *rp;
7182618Swnj 	struct rkst *st;
7192618Swnj 
72024785Skarels 	unit = rkunit(dev);
7212885Swnj 	if (unit >= NRK)
7222885Swnj 		return (ENXIO);
7232618Swnj #define	phys(cast, addr) ((cast)((int)addr & 0x7fffffff))
7242981Swnj 	ui = phys(struct uba_device *, rkdinfo[unit]);
7252885Swnj 	if (ui->ui_alive == 0)
7262885Swnj 		return (ENXIO);
7272618Swnj 	uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
7283329Swnj 	ubainit(uba);
7292618Swnj 	rkaddr = (struct rkdevice *)ui->ui_physaddr;
7302618Swnj 	num = maxfree;
7312618Swnj 	start = 0;
7323709Sroot 	rkaddr->rkcs1 = RK_CCLR;
7332618Swnj 	rkaddr->rkcs2 = unit;
7343709Sroot 	rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_DCLR|RK_GO;
7352618Swnj 	rkwait(rkaddr);
7363293Swnj 	if ((rkaddr->rkds & RKDS_VV) == 0) {
7373709Sroot 		rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_IE|RK_PACK|RK_GO;
7382618Swnj 		rkwait(rkaddr);
7392618Swnj 	}
7402618Swnj 	st = &rkst[ui->ui_type];
7412618Swnj 	sizes = phys(struct size *, st->sizes);
74224210Sbloom 	if (dumplo < 0)
7432885Swnj 		return (EINVAL);
74424210Sbloom 	if (dumplo + num >= sizes[minor(dev)&07].nblocks)
74524210Sbloom 		num = sizes[minor(dev)&07].nblocks - dumplo;
7462618Swnj 	while (num > 0) {
7472618Swnj 		register struct pte *io;
7482618Swnj 		register int i;
7492618Swnj 		int cn, sn, tn;
7502618Swnj 		daddr_t bn;
7512618Swnj 
7522618Swnj 		blk = num > DBSIZE ? DBSIZE : num;
7532618Swnj 		io = uba->uba_map;
7542618Swnj 		for (i = 0; i < blk; i++)
7552981Swnj 			*(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV;
7562618Swnj 		*(int *)io = 0;
7572618Swnj 		bn = dumplo + btop(start);
7582618Swnj 		cn = bn/st->nspc + sizes[minor(dev)&07].cyloff;
7592618Swnj 		sn = bn%st->nspc;
7602618Swnj 		tn = sn/st->nsect;
7612618Swnj 		sn = sn%st->nsect;
7622618Swnj 		rkaddr->rkcyl = cn;
7632618Swnj 		rp = (short *) &rkaddr->rkda;
7642618Swnj 		*rp = (tn << 8) + sn;
7652618Swnj 		*--rp = 0;
7662618Swnj 		*--rp = -blk*NBPG / sizeof (short);
7673709Sroot 		*--rp = rktypes[ui->ui_type]|RK_GO|RK_WRITE;
7682618Swnj 		rkwait(rkaddr);
7692885Swnj 		if (rkaddr->rkcs1 & RK_CERR)
7702885Swnj 			return (EIO);
7712618Swnj 		start += blk*NBPG;
7722618Swnj 		num -= blk;
7732618Swnj 	}
7742618Swnj 	return (0);
7752618Swnj }
77612503Ssam 
77712503Ssam rksize(dev)
77812503Ssam 	dev_t dev;
77912503Ssam {
78024785Skarels 	int unit = rkunit(dev);
78112503Ssam 	struct uba_device *ui;
78212503Ssam 	struct rkst *st;
78312503Ssam 
78412503Ssam 	if (unit >= NRK || (ui = rkdinfo[unit]) == 0 || ui->ui_alive == 0)
78512503Ssam 		return (-1);
78612503Ssam 	st = &rkst[ui->ui_type];
78712503Ssam 	return (st->sizes[minor(dev) & 07].nblocks);
78812503Ssam }
7892618Swnj #endif
790