xref: /csrg-svn/sys/tahoe/vba/vd.c (revision 25860)
1*25860Ssam /*	vd.c	1.4	86/01/12	*/
224004Ssam 
324004Ssam #include "fsd.h"
424004Ssam #if NVD > 0
524004Ssam /*
625675Ssam  * VDDC - Versabus SMD/ESMD driver.
725675Ssam  */
825675Ssam #include "../tahoe/mtpr.h"
925675Ssam #include "../tahoe/pte.h"
1024004Ssam 
1125675Ssam #include "param.h"
1225675Ssam #include "buf.h"
1325675Ssam #include "cmap.h"
1425675Ssam #include "conf.h"
1525675Ssam #include "dir.h"
1625675Ssam #include "dk.h"
1725675Ssam #include "map.h"
1825675Ssam #include "systm.h"
1925675Ssam #include "user.h"
2025675Ssam #include "vmmac.h"
2125675Ssam #include "proc.h"
2225675Ssam #include "uio.h"
2324004Ssam 
2425675Ssam #include "../tahoevba/vbavar.h"
2525675Ssam #define	VDGENDATA
2625675Ssam #include "../tahoevba/vddcreg.h"
2725675Ssam #undef VDGENDATA
2824004Ssam 
2925675Ssam #define	MAX_BLOCKSIZE	(MAXBPTE*NBPG)
3025675Ssam #define	DUMPSIZE	64	/* controller limit */
3124004Ssam 
3224004Ssam #define VDUNIT(x)	(minor(x) >> 3)
3325675Ssam #define FILSYS(x)	(minor(x) & 0x07)
3425675Ssam #define PHYS(x)		(vtoph((struct proc *)0, (unsigned)(x)))
3525675Ssam #define TRUE		1
3625675Ssam #define	FALSE		0
3724004Ssam 
3825675Ssam #define CTLR_ERROR	1
3925675Ssam #define DRIVE_ERROR	2
4025675Ssam #define HARD_DATA_ERROR	3
4125675Ssam #define SOFT_DATA_ERROR	4
4224004Ssam 
4325675Ssam #define b_cylin	b_resid
4425675Ssam #define b_daddr	b_error
4524004Ssam 
4624004Ssam struct	vba_ctlr *vdminfo[NVD];
4724004Ssam struct  vba_device *vddinfo[NFSD];
4825675Ssam int	vdprobe(), vdslave(), vdattach(), vddgo();
4925675Ssam struct	vba_driver vddriver =
5025675Ssam     { vdprobe, vdslave, vdattach, vddgo, vddcaddr, "smd/fsd",
5125675Ssam       vddinfo, "vd", vdminfo };
5224004Ssam 
5324004Ssam /*
5425675Ssam  * Per-drive state.
5525675Ssam  */
5625675Ssam typedef struct {
5725675Ssam 	struct	buf raw_q_element;
5825675Ssam 	short	sec_per_blk;
5925675Ssam 	short	sec_per_cyl;
6025675Ssam 	char	status;
6125675Ssam 	struct	buf xfer_queue;
6225675Ssam 	int	drive_type;
6325675Ssam 	fs_tab	info;
6425675Ssam } unit_tab;
6524004Ssam 
6624004Ssam /*
6725675Ssam  * Per-controller state.
6825675Ssam  */
6925675Ssam typedef struct {
7025675Ssam 	char	ctlr_type;	/* controller type */
7125675Ssam 	char	*map;		/* i/o page map */
7225675Ssam 	char	*utl;		/* mapped i/o space */
7325675Ssam 	u_int	cur_slave:8;	/* last active unit number */
7425675Ssam 	u_int	int_expected:1;	/* expect an interupt */
7525675Ssam 	u_int	ctlr_started:1;	/* start command was issued */
7625675Ssam 	u_int	overlap_seeks:1;/* should overlap seeks */
7725675Ssam 	u_int	off_cylinder:16;/* off cylinder bit map */
7825675Ssam 	u_int	unit_type[16];	/* slave types */
7925675Ssam 	u_int	cur_cyl[16];	/* cylinder last selected */
8025675Ssam 	long	cur_trk[16];	/* track last selected */
8125675Ssam 	fmt_mdcb ctlr_mdcb;	/* controller mdcb */
8225675Ssam 	fmt_dcb	ctlr_dcb;	/* r/w dcb */
8325675Ssam 	fmt_dcb	seek_dcb[4];	/* dcbs for overlapped seeks */
8425675Ssam 	/* buffer for raw/swap i/o */
8525675Ssam 	char	rawbuf[MAX_BLOCKSIZE];
8625675Ssam } ctlr_tab;
8724004Ssam 
8825675Ssam extern char	vd0utl[];
8925675Ssam #if NVD > 1
9025675Ssam extern char	vd1utl[];
9125675Ssam #endif
9225675Ssam #if NVD > 2
9325675Ssam extern char	vd2utl[];
9425675Ssam #endif
9525675Ssam #if NVD > 3
9625675Ssam extern char	vd3utl[];
9725675Ssam #endif
9824004Ssam 
9925675Ssam #define	VDCINIT(map, utl) { \
10025675Ssam     UNKNOWN, (char *)map, utl, 0, FALSE, FALSE, TRUE, 0, \
10125675Ssam 	{ UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, \
10225675Ssam 	  UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN } \
10325675Ssam }
10425675Ssam ctlr_tab vdctlr_info[NVD] = {
10525675Ssam 	VDCINIT(VD0map, vd0utl),
10625675Ssam #if NVD > 1
10725675Ssam 	VDCINIT(VD1map, vd1utl),
10825675Ssam #endif
10925675Ssam #if NVD > 2
11025675Ssam 	VDCINIT(VD2map, vd2utl),
11125675Ssam #endif
11225675Ssam #if NVD > 3
11325675Ssam 	VDCINIT(VD3map, vd3utl),
11425675Ssam #endif
11524004Ssam };
11624004Ssam 
11725675Ssam unit_tab vdunit_info[NFSD];
11824004Ssam 
11924004Ssam /*
12025675Ssam  * See if the controller is really there; if so, initialize it.
12125675Ssam  */
12225857Ssam vdprobe(reg, vm)
12325857Ssam 	caddr_t reg;
12425857Ssam 	struct vba_ctlr *vm;
12525675Ssam {
12625857Ssam 	register br, cvec;		/* must be r12, r11 */
12725857Ssam 	register cdr *cp = (cdr *)reg;
12825857Ssam 
12925857Ssam 	if (badaddr((caddr_t)reg, 2))
13025675Ssam 		return (0);
13125857Ssam 	cp->cdr_reset = 0xffffffff;
13225675Ssam 	DELAY(1000000);
13325857Ssam 	if (cp->cdr_reset != (unsigned)0xffffffff) {
13425675Ssam 		DELAY(1000000);
13525675Ssam 	} else {
13625857Ssam 		cp->cdr_reserved = 0x0;
13725675Ssam 		DELAY(3000000);
13825675Ssam 	}
13925857Ssam 	br = 0x17, cvec = 0xe0 + vm->um_ctlr;	/* XXX */
14025857Ssam 	return (sizeof (*cp));
14125675Ssam }
14224004Ssam 
14324004Ssam /*
14425675Ssam  * See if a drive is really there
14525675Ssam  * Try to reset/configure the drive, then test its status.
14625675Ssam  */
14725675Ssam vdslave(vi, addr)
14825675Ssam 	register struct vba_device *vi;
14925675Ssam 	register cdr *addr;
15025675Ssam {
15125675Ssam 	register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr];
15225675Ssam 	register unit_tab *ui = &vdunit_info[vi->ui_unit];
15325675Ssam 	register fmt_mdcb *mdcb = &ci->ctlr_mdcb;
15425675Ssam 	register fmt_dcb *dcb = &ci->ctlr_dcb;
15525675Ssam 	register int type;
15624004Ssam 
15725675Ssam 	if (ci->ctlr_type == UNKNOWN) {
15825675Ssam 		addr->cdr_reset = 0xffffffff;
15925675Ssam 		DELAY(1000000);
16025675Ssam 		if (addr->cdr_reset != (unsigned)0xffffffff) {
16125675Ssam 			ci->ctlr_type = SMDCTLR;
16225675Ssam 			ci->overlap_seeks = 0;
16325675Ssam 			DELAY(1000000);
16425675Ssam 		} else {
16525675Ssam 			ci->overlap_seeks = 1;
16625675Ssam 			ci->ctlr_type = SMD_ECTLR;
16725675Ssam 			addr->cdr_reserved = 0x0;
16825675Ssam 			DELAY(3000000);
16925675Ssam 			addr->cdr_csr = 0;
17025675Ssam 			addr->mdcb_tcf = AM_ENPDA;
17125675Ssam 			addr->dcb_tcf = AM_ENPDA;
17225675Ssam 			addr->trail_tcf = AM_ENPDA;
17325675Ssam 			addr->data_tcf = AM_ENPDA;
17425675Ssam 			addr->cdr_ccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
17525675Ssam 			    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
17625675Ssam 		}
177*25860Ssam 		printf("vd%d: %s controller\n", vi->ui_unit,
178*25860Ssam 		    ci->ctlr_type == SMDCTLR ? "smd" : "xsmd");
17925675Ssam 		if (vdnotrailer(addr,
18025675Ssam 		    vi->ui_ctlr, vi->ui_slave, INIT, 10) & HRDERR) {
18125675Ssam 			printf("vd%d: init error\n", vi->ui_unit);
18225675Ssam 			return (0);
18325675Ssam 		}
18425675Ssam 		if (vdnotrailer(addr,
18525675Ssam 		    vi->ui_ctlr, vi->ui_slave, DIAG, 10) & HRDERR) {
18625675Ssam 			printf("vd%d: diagnostic error\n", vi->ui_unit);
18725675Ssam 			return (0);
18825675Ssam 		}
18925675Ssam 	}
19025675Ssam 	/*
19125675Ssam 	 * Seek on all drive types starting from the largest one.
19225675Ssam 	 * a successful seek to the last sector/cylinder/track verifies
19325675Ssam 	 * the drive type connected to this port.
19425675Ssam 	 */
19525675Ssam 	for (type = 0; type < nvddrv; type++) {
19625675Ssam 		/* XXX */
19725675Ssam 		if (ci->ctlr_type == SMDCTLR && vdst[type].nsec != 32)
19825675Ssam 			continue;
19925675Ssam 		/* XXX */
20025675Ssam 		if (!vdconfigure_drive(addr, vi->ui_ctlr, vi->ui_slave, type,0))
20125675Ssam 			return (0);
20225675Ssam 		dcb->opcode = (short)RD;
20325675Ssam 		dcb->intflg = NOINT;
20425675Ssam 		dcb->nxtdcb = (fmt_dcb *)0;	/* end of chain */
20525675Ssam 		dcb->operrsta = 0;
20625675Ssam 		dcb->devselect = (char)(vi->ui_slave);
20725675Ssam 		dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long));
20825675Ssam 		dcb->trail.rwtrail.memadr = (char *)PHYS(ci->rawbuf);
20925675Ssam 		dcb->trail.rwtrail.wcount = vdst[type].secsize/sizeof(short);
21025675Ssam 		dcb->trail.rwtrail.disk.cylinder = vdst[type].ncyl - 2;
21125675Ssam 		dcb->trail.rwtrail.disk.track = vdst[type].ntrak - 1;
21225675Ssam 		dcb->trail.rwtrail.disk.sector = vdst[type].nsec - 1;
21325675Ssam 		mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
21425675Ssam 		mdcb->vddcstat = 0;
21525675Ssam 		VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type);
21625675Ssam 		POLLTILLDONE(addr, dcb, 60, ci->ctlr_type);
21725675Ssam 		if (vdtimeout <= 0)
21825675Ssam 			printf(" during probe\n");
21925675Ssam 		if ((dcb->operrsta&HRDERR) == 0)
22025675Ssam 			break;
22125675Ssam 	}
22225675Ssam 	if (type >= nvddrv) {
22325675Ssam 		/*
22425675Ssam 		 * If reached here, a drive which is not defined in the
22525675Ssam 		 * 'vdst' tables is connected. Cannot set it's type.
22625675Ssam 		 */
22725675Ssam 		printf("vd%d: unknown drive type\n", vi->ui_unit);
22825675Ssam 		return (0);
22925675Ssam 	}
23025675Ssam 	ui->drive_type = type;
23125675Ssam 	ui->info = vdst[type];
23225675Ssam 	ui->sec_per_blk = DEV_BSIZE / ui->info.secsize;
23325675Ssam 	vi->ui_type = type;
23425675Ssam  	vi->ui_dk = 1;
23525675Ssam 	vddriver.ud_dname = ui->info.type_name;
23625675Ssam 	return (1);
23724004Ssam }
23824004Ssam 
23925675Ssam vdconfigure_drive(addr, ctlr, slave, type, pass)
24025675Ssam 	register cdr *addr;
24125675Ssam 	int ctlr, slave, type, pass;
24224004Ssam {
24325675Ssam 	register ctlr_tab *ci = &vdctlr_info[ctlr];
24425675Ssam 
24525675Ssam 	ci->ctlr_dcb.opcode = RSTCFG;		/* command */
24625675Ssam 	ci->ctlr_dcb.intflg = NOINT;
24725675Ssam 	ci->ctlr_dcb.nxtdcb = (fmt_dcb *)0;	/* end of chain */
24825675Ssam 	ci->ctlr_dcb.operrsta = 0;
24925675Ssam 	ci->ctlr_dcb.devselect = (char)slave;
25025675Ssam 	ci->ctlr_dcb.trail.rstrail.ncyl = vdst[type].ncyl;
25125675Ssam 	ci->ctlr_dcb.trail.rstrail.nsurfaces = vdst[type].ntrak;
25225675Ssam 	if (ci->ctlr_type == SMD_ECTLR) {
25325675Ssam 		ci->ctlr_dcb.trailcnt = (char)4;
25425675Ssam 		ci->ctlr_dcb.trail.rstrail.nsectors = vdst[type].nsec;
25525675Ssam 		ci->ctlr_dcb.trail.rstrail.slip_sec = vdst[type].nslip;
25625675Ssam 	} else
25725675Ssam 		ci->ctlr_dcb.trailcnt = (char)2;
25825675Ssam 	ci->ctlr_mdcb.firstdcb = (fmt_dcb *)(PHYS(&ci->ctlr_dcb));
25925675Ssam 	ci->ctlr_mdcb.vddcstat = 0;
26025675Ssam 	VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(&ci->ctlr_mdcb)), ci->ctlr_type);
26125675Ssam 	POLLTILLDONE(addr, &ci->ctlr_dcb, 5, ci->ctlr_type);
26225675Ssam 	if (vdtimeout <= 0) {
26325675Ssam 		printf(" during config\n");
26425675Ssam 		return (0);
26525675Ssam 	}
26625675Ssam 	if (ci->ctlr_dcb.operrsta & HRDERR) {
26725675Ssam 		if ((ci->ctlr_dcb.operrsta & (NOTCYLERR|DRVNRDY)) == 0)
26825675Ssam 			printf("vd%d: drive %d: config error\n", ctlr, slave);
26925675Ssam 		else if (pass == 0) {
27025675Ssam 			vdstart_drive(addr, ctlr, slave);
27125675Ssam 			return (vdconfigure_drive(addr, ctlr, slave, type, 1));
27225675Ssam 		} else if (pass == 2)
27325675Ssam 			return (vdconfigure_drive(addr, ctlr, slave, type, 3));
27425675Ssam 		return (0);
27525675Ssam 	}
27625675Ssam 	return (1);
27724004Ssam }
27824004Ssam 
27925675Ssam vdstart_drive(addr, ctlr, slave)
28025675Ssam 	cdr *addr;
28125675Ssam 	register int ctlr, slave;
28224004Ssam {
28325675Ssam 	int error = 0;
28424004Ssam 
28525675Ssam 	printf("vd%d: starting drive %d, wait...", ctlr, slave);
28625675Ssam 	if (vdctlr_info[ctlr].ctlr_started) {
28725675Ssam printf("DELAY(5500000)...");
28825675Ssam 		DELAY(5500000);
28925675Ssam 		goto done;
29024004Ssam 	}
29125675Ssam 	vdctlr_info[ctlr].ctlr_started = 1;
29225675Ssam 	error = vdnotrailer(addr, ctlr, 0, VDSTART, (slave*6)+62) & HRDERR;
29325675Ssam 	if (!error) {
29425675Ssam printf("DELAY(%d)...", (slave * 5500000) + 62000000);
29525675Ssam 		DELAY((slave * 5500000) + 62000000);
29624004Ssam 	}
29725675Ssam done:
29825675Ssam 	printf("\n");
29925675Ssam 	return (error == 0);
30025675Ssam }
30124004Ssam 
30225675Ssam vdnotrailer(addr, ctlr, unit, function, time)
30325675Ssam 	register cdr *addr;
30425675Ssam 	int ctlr, unit, function, time;
30524004Ssam {
30625675Ssam 	fmt_mdcb *mdcb = &vdctlr_info[ctlr].ctlr_mdcb;
30725675Ssam 	fmt_dcb *dcb = &vdctlr_info[ctlr].ctlr_dcb;
30825675Ssam 	int type = vdctlr_info[ctlr].ctlr_type;
30924004Ssam 
31025675Ssam 	dcb->opcode = function;		/* command */
31124004Ssam 	dcb->intflg = NOINT;
31225675Ssam 	dcb->nxtdcb = (fmt_dcb *)0;	/* end of chain */
31325675Ssam 	dcb->operrsta = 0;
31425675Ssam 	dcb->devselect = (char)unit;
31524004Ssam 	dcb->trailcnt = (char)0;
31625675Ssam 	mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
31724004Ssam 	mdcb->vddcstat = 0;
31825675Ssam 	VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(mdcb)), type);
31925675Ssam 	POLLTILLDONE(addr, dcb, time, type);
32025675Ssam 	if (vdtimeout <= 0) {
32125675Ssam 		printf(" during init\n");
32225675Ssam 		return (DCBCMP|ANYERR|HRDERR|OPABRT);
32324004Ssam 	}
32425675Ssam 	return (dcb->operrsta);
32525675Ssam }
32624004Ssam 
32725675Ssam vdattach(vi)
32825675Ssam 	register struct vba_device *vi;
32925675Ssam {
33025675Ssam 	register unit_tab *ui = &vdunit_info[vi->ui_unit];
33125675Ssam 	register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr];
33225675Ssam 	register struct buf *cq = &vi->ui_mi->um_tab;
33325675Ssam 	register struct buf *uq = cq->b_forw;
33425675Ssam 	register struct buf *start_queue = uq;
33525675Ssam 	register fs_tab	*fs = &ui->info;
33625675Ssam 
33725675Ssam 	ui->info = vdst[vi->ui_type];
33825675Ssam 	ui->sec_per_blk = DEV_BSIZE / ui->info.secsize;
33925675Ssam 	ui->sec_per_cyl = ui->info.nsec * ui->info.ntrak;
34025675Ssam 	ui->xfer_queue.b_dev = vi->ui_slave;
34125675Ssam 	ci->unit_type[vi->ui_slave] = vi->ui_type;
34225675Ssam 	/* load unit into controller's active unit list */
34325675Ssam 	if (uq == NULL) {
34425675Ssam 		cq->b_forw = &ui->xfer_queue;
34525675Ssam 		ui->xfer_queue.b_forw = &ui->xfer_queue;
34625675Ssam 		ui->xfer_queue.b_back = &ui->xfer_queue;
34725675Ssam 	} else {
34825675Ssam 		while (uq->b_forw != start_queue)
34925675Ssam 			uq = uq->b_forw;
35025675Ssam 		ui->xfer_queue.b_forw = start_queue;
35125675Ssam 		ui->xfer_queue.b_back = uq;
35225675Ssam 		uq->b_forw = &ui->xfer_queue;
35325675Ssam 		start_queue->b_back = &ui->xfer_queue;
35425675Ssam 	}
35524004Ssam 	/*
35625675Ssam 	 * (60 / rpm) / (number of sectors per track * (bytes per sector / 2))
35724004Ssam 	 */
35825675Ssam 	dk_mspw[vi->ui_unit] = 120.0 / (fs->rpm * fs->nsec * fs->secsize);
35924004Ssam }
36024004Ssam 
36125675Ssam /*ARGSUSED*/
36225675Ssam vddgo(um)
36325675Ssam 	struct vba_ctlr *um;
36424004Ssam {
36524004Ssam 
36624004Ssam }
36724004Ssam 
36824004Ssam vdstrategy(bp)
36925675Ssam 	register struct buf *bp;
37024004Ssam {
37125675Ssam 	register int unit = VDUNIT(bp->b_dev);
37225675Ssam 	register struct vba_device *vi = vddinfo[unit];
37325675Ssam 	register par_tab *par;
37425675Ssam 	register unit_tab *ui;
37525675Ssam 	register fs_tab *fs;
37625675Ssam 	register int blks, bn, s;
37724004Ssam 
37825675Ssam 	if (bp->b_bcount == 0 || vi == 0 || vi->ui_alive == 0)
37925675Ssam 		goto bad;
38025675Ssam 	ui = &vdunit_info[unit];
38125675Ssam 	fs = &ui->info;
38225675Ssam 	par = &fs->partition[FILSYS(bp->b_dev)];
38325675Ssam 	blks = (bp->b_bcount + DEV_BSIZE-1) >> DEV_BSHIFT;
38425675Ssam 	if (bp->b_blkno + blks >= par->par_len) {
38525675Ssam 		blks = par->par_len - bp->b_blkno;
38625675Ssam 		if (blks <= 0)
38725675Ssam 			goto bad;
38825675Ssam 		bp->b_bcount = blks * DEV_BSIZE;
38925675Ssam 	}
39025675Ssam 	bn = bp->b_blkno + par->par_start;
39125675Ssam 	bn *= ui->sec_per_blk;
39225675Ssam 	bp->b_daddr = (bn / fs->nsec) % fs->ntrak;
39325675Ssam 	bp->b_cylin = bn / ui->sec_per_cyl;
39425675Ssam 	vbasetup(bp, ui->info.secsize);
39525675Ssam 	s = spl7();
39625675Ssam 	if (ui->xfer_queue.av_forw == NULL) {
39725675Ssam 		register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr];
39825675Ssam 		int slave = vi->ui_slave;
39924004Ssam 
40025675Ssam 		if (bp->b_cylin != ci->cur_cyl[slave] ||
40125675Ssam 		    bp->b_daddr != ci->cur_trk[slave])
40225675Ssam 			ci->off_cylinder |= 1 << slave;
40324004Ssam 	}
40425675Ssam 	bp->b_daddr |= (bn % fs->nsec) << 8;
40525675Ssam 	disksort(&ui->xfer_queue, bp);
40625675Ssam 	if (!vddinfo[unit]->ui_mi->um_tab.b_active++) {
40725675Ssam 		splx(s);
40825675Ssam 		vdstart(vddinfo[unit]->ui_mi);
40925675Ssam 	} else
41025675Ssam 		splx(s);
41124004Ssam 	return;
41225675Ssam bad:
41325675Ssam 	bp->b_flags |= B_ERROR, bp->b_error = ENXIO;
41425675Ssam 	bp->b_resid = bp->b_bcount;
41524004Ssam 	iodone(bp);
41624004Ssam }
41724004Ssam 
41824004Ssam /*
41924004Ssam  * Start up a transfer on a drive.
42024004Ssam  */
42125675Ssam vdstart(ci)
42225675Ssam 	register struct vba_ctlr *ci;
42324004Ssam {
42425675Ssam 	register struct buf *cq = &ci->um_tab;
42525675Ssam 	register struct buf *uq = cq->b_forw;
42624004Ssam 
42725675Ssam 	/* search for next ready unit */
42825675Ssam 	cq->b_forw = cq->b_forw->b_forw;
42925675Ssam 	uq = cq->b_forw;
43025675Ssam 	do {
43125675Ssam 		if (uq->av_forw != NULL) {
43225675Ssam 			cq->b_forw = uq;
43325675Ssam 			vdexecute(ci, uq);
43425675Ssam 			return;
43525675Ssam 		}
43625675Ssam 		uq = uq->b_forw;
43725675Ssam 	} while (uq != cq->b_forw);
43825675Ssam }
43925675Ssam 
44025675Ssam /*
44125675Ssam  * Initiate seeks for all drives off-cylinder.
44225675Ssam  */
44325675Ssam vdload_seeks(ci, uq)
44425675Ssam 	register ctlr_tab *ci;
44525675Ssam 	register struct buf *uq;
44625675Ssam {
44725675Ssam 	register int unit, slave, nseeks;
44825675Ssam 	register fmt_dcb *dcb;
44925675Ssam 	register struct buf *bp;
45025675Ssam 	register struct buf *start_queue = uq;
45125675Ssam 
45225675Ssam 	nseeks = 0;
45325675Ssam 	do {
45425675Ssam 		bp = uq->av_forw;
45525675Ssam 		if (bp != NULL) {
45625675Ssam 			unit = VDUNIT(bp->b_dev);
45725675Ssam 			slave = vddinfo[unit]->ui_slave;
45825675Ssam 			if (ci->off_cylinder & (1 << slave)) {
45925675Ssam 				ci->off_cylinder &= ~(1 << slave);
46025675Ssam 				if (ci->cur_cyl[slave] != bp->b_cylin) {
46125675Ssam 					ci->cur_cyl[slave] = bp->b_cylin;
46225675Ssam 					dk_seek[unit]++;
46325675Ssam 				}
46425675Ssam 				ci->cur_trk[slave] = bp->b_daddr&0xff;
46525675Ssam 				dcb = &ci->seek_dcb[nseeks++];
46625675Ssam 				dcb->opcode = SEEK;
46725675Ssam 				dcb->intflg = NOINT | INT_PBA;
46825675Ssam 				dcb->operrsta = 0;
46925675Ssam 				dcb->devselect = (char)slave;
47025675Ssam 				dcb->trailcnt = (char)1;
47125675Ssam 				dcb->trail.sktrail.skaddr.cylinder =
47225675Ssam 				    bp->b_cylin;
47325675Ssam 				dcb->trail.sktrail.skaddr.track =
47425675Ssam 				    bp->b_daddr & 0xff;
47525675Ssam 				dcb->trail.sktrail.skaddr.sector = 0;
47625675Ssam 			}
47725675Ssam 		}
47825675Ssam 		uq = uq->b_forw;
47925675Ssam 	} while (uq != start_queue && nseeks < 4);
48025675Ssam 	return (nseeks);
48125675Ssam }
48225675Ssam 
48325675Ssam extern	vd_int_timeout();
48425675Ssam /*
48525675Ssam  * Execute the next command on the unit queue uq.
48625675Ssam  */
48725675Ssam vdexecute(controller_info, uq)
48825675Ssam 	register struct vba_ctlr *controller_info;
48925675Ssam 	register struct buf *uq;
49025675Ssam {
49125675Ssam 	register struct	buf *bp = uq->av_forw;
49225675Ssam 	register int ctlr = controller_info->um_ctlr;
49325675Ssam 	register ctlr_tab *ci = &vdctlr_info[ctlr];
49425675Ssam 	register int unit = VDUNIT(bp->b_dev);
49525675Ssam 	register int slave = vddinfo[unit]->ui_slave;
49625675Ssam 	register fmt_mdcb *mdcb = &ci->ctlr_mdcb;
49725675Ssam 	register fmt_dcb *dcb = &ci->ctlr_dcb;
49825675Ssam 
49924004Ssam 	/*
50025675Ssam 	 * If there are overlapped seeks to perform, shuffle
50125675Ssam 	 * them to the front of the queue and get them started
50225675Ssam 	 * before any data transfers (to get some parallelism).
50324004Ssam 	 */
50425675Ssam 	if ((ci->off_cylinder & ~(1<<slave)) && ci->overlap_seeks) {
50525675Ssam 		register int i, nseeks;
50625675Ssam 
50725675Ssam 		/* setup seek requests in seek-q */
50825675Ssam 		nseeks = vdload_seeks(ci, uq);
50925675Ssam 		/* place at the front of the master q */
51025675Ssam 		mdcb->firstdcb = (fmt_dcb *)PHYS(&ci->seek_dcb[0]);
51125675Ssam 		/* shuffle any remaining seeks up in the seek-q */
51225675Ssam 		for (i = 1; i < nseeks; i++)
51325675Ssam 			ci->seek_dcb[i-1].nxtdcb =
51425675Ssam 			    (fmt_dcb *)PHYS(&ci->seek_dcb[i]);
51525675Ssam 		ci->seek_dcb[nseeks-1].nxtdcb = (fmt_dcb *)PHYS(dcb);
51625675Ssam 	} else {
51725675Ssam 		if (bp->b_cylin != ci->cur_cyl[slave]) {
51825675Ssam 			ci->cur_cyl[slave] = bp->b_cylin;
51925675Ssam 			dk_seek[unit]++;
52025675Ssam 		}
52125675Ssam 		ci->cur_trk[slave] = bp->b_daddr & 0xff;
52225675Ssam 		ci->off_cylinder = 0;
52325675Ssam 		mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
52424004Ssam 	}
52524004Ssam 	dcb->opcode = (bp->b_flags & B_READ) ? RD : WD;
52625675Ssam 	dcb->intflg = INTDONE;
52725675Ssam 	dcb->nxtdcb = (fmt_dcb *)0;	/* end of chain */
52824004Ssam 	dcb->operrsta = 0;
52925675Ssam 	dcb->devselect = (char)slave;
53025675Ssam 	dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long));
53125675Ssam 	dcb->trail.rwtrail.memadr = (char *)
53225675Ssam 	    vbastart(bp, ci->rawbuf, (long *)ci->map, ci->utl);
53325675Ssam 	dcb->trail.rwtrail.wcount = (short)((bp->b_bcount+1) / sizeof (short));
53425675Ssam 	dcb->trail.rwtrail.disk.cylinder = bp->b_cylin;
53525675Ssam 	dcb->trail.rwtrail.disk.track = bp->b_daddr & 0xff;
53625675Ssam 	dcb->trail.rwtrail.disk.sector = bp->b_daddr >> 8;
53725675Ssam 	mdcb->vddcstat = 0;
53825675Ssam    	dk_wds[unit] += bp->b_bcount / 32;
53925675Ssam 	ci->int_expected = 1;
54025675Ssam 	timeout(vd_int_timeout, (caddr_t)ctlr, 20*60);
54125675Ssam   	dk_busy |= 1 << unit;
54225675Ssam #ifdef VDDCPERF
54325675Ssam 	scope_out(1);
54425675Ssam #endif
54525675Ssam 	VDDC_ATTENTION((cdr *)(vdminfo[ctlr]->um_addr),
54625675Ssam 	    (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type);
54725675Ssam }
54824004Ssam 
54924004Ssam /*
55025675Ssam  * Watch for lost interrupts.
55125675Ssam  */
55225675Ssam vd_int_timeout(ctlr)
55325675Ssam 	register int ctlr;
55425675Ssam {
55525675Ssam 	register ctlr_tab *ci = &vdctlr_info[ctlr];
55625675Ssam 	register fmt_dcb *dcb = &ci->ctlr_dcb;
55724004Ssam 
55825675Ssam 	uncache(&dcb->operrsta);
55925675Ssam 	printf("vd%d: lost interupt, status %x", ctlr, dcb->operrsta);
56025675Ssam 	if (ci->ctlr_type == SMD_ECTLR) {
56125675Ssam 		uncache(&dcb->err_code);
56225675Ssam 		printf(", error code %x", dcb->err_code);
56324004Ssam 	}
56425675Ssam 	printf("\n");
56525675Ssam 	if ((dcb->operrsta&DCBCMP) == 0) {
56625675Ssam 		VDDC_ABORT((cdr *)(vdminfo[ctlr]->um_addr), ci->ctlr_type);
56725675Ssam 		dcb->operrsta |= DCBUSC | DCBABT | ANYERR | HRDERR | CTLRERR;
56825675Ssam 	}
56925675Ssam 	vdintr(ctlr);
57024004Ssam }
57124004Ssam 
57224004Ssam /*
57324004Ssam  * Handle a disk interrupt.
57424004Ssam  */
57525675Ssam vdintr(ctlr)
57625675Ssam 	register int ctlr;
57724004Ssam {
57825675Ssam 	register ctlr_tab *ci;
57925675Ssam 	register struct buf *cq, *uq, *bp;
58025675Ssam 	register int slave, unit;
58125675Ssam 	register fmt_mdcb  *mdcb;
58225675Ssam 	register fmt_dcb *dcb;
58325675Ssam 	int code, s;
58424004Ssam 
58525675Ssam 	untimeout(vd_int_timeout, (caddr_t)ctlr);
58624004Ssam #ifdef VDDCPERF
58724004Ssam 	scope_out(2);
58824004Ssam #endif
58925675Ssam 	ci = &vdctlr_info[ctlr];
59025675Ssam 	if (!ci->int_expected) {
59125675Ssam 		printf("vd%d: stray interrupt\n", ctlr);
59224004Ssam 		return;
59324004Ssam 	}
59425675Ssam 	/*
59525675Ssam 	 * Take first request off controller's queue.
59625675Ssam 	 */
59725675Ssam 	cq = &vdminfo[ctlr]->um_tab;
59825675Ssam 	uq = cq->b_forw;
59925675Ssam 	bp = uq->av_forw;
60024004Ssam 	unit = VDUNIT(bp->b_dev);
60125675Ssam 	dk_busy &= ~(1 << unit);
60225675Ssam 	dk_xfer[unit]++;
60325675Ssam 	ci->int_expected = 0;
60425675Ssam 	/* find associated control blocks */
60525675Ssam 	mdcb = &ci->ctlr_mdcb, uncache(&mdcb->intdcb);
60625675Ssam 	dcb = &ci->ctlr_dcb, uncache(&dcb->operrsta);
60725675Ssam 	if (ci->ctlr_type == SMD_ECTLR)
60825675Ssam 		uncache(&dcb->err_code);
60925675Ssam 	slave = uq->b_dev;
61025675Ssam 	switch (code = vddecode_error(dcb)) {
61124004Ssam 
61225675Ssam 	case CTLR_ERROR:
61325675Ssam 	case DRIVE_ERROR:
61425675Ssam 		if (cq->b_errcnt >= 2)
61525675Ssam 			vdhard_error(ci, bp, dcb);
61625675Ssam 		if (code == CTLR_ERROR)
61725675Ssam 			vdreset_ctlr((cdr *)vdminfo[ctlr]->um_addr, ctlr);
61825675Ssam 		else
61925675Ssam 			reset_drive((cdr *)vdminfo[ctlr]->um_addr, ctlr,
62025675Ssam 			    slave, 2);
62125675Ssam 		if (cq->b_errcnt++ < 2) {	/* retry error */
62225675Ssam 			cq->b_forw = uq->b_back;
62325675Ssam 			vdstart(vdminfo[ctlr]);
62425675Ssam 			return;
62525675Ssam 		}
62625675Ssam 		bp->b_resid = bp->b_bcount;
62725675Ssam 		break;
62825675Ssam 
62925675Ssam 	case HARD_DATA_ERROR:
63025675Ssam 		vdhard_error(ci, bp, dcb);
63125675Ssam 		bp->b_resid = 0;
63225675Ssam 		break;
63325675Ssam 
63425675Ssam 	case SOFT_DATA_ERROR:
63525675Ssam 		vdsoft_error(ci, bp, dcb);
63625675Ssam 		/* fall thru... */
63725675Ssam 
63825675Ssam 	default:			/* operation completed */
63925675Ssam 		bp->b_error = 0;
64025675Ssam 		bp->b_resid = 0;
64125675Ssam 		break;
64224004Ssam 	}
64325675Ssam 	vbadone(bp, ci->rawbuf, (long *)ci->map, ci->utl);
64425675Ssam 	/*
64525675Ssam 	 * Take next request on this unit q, or, if none,
64625675Ssam 	 * the next request on the next active unit q.
64725675Ssam 	 */
64825675Ssam 	s = spl7();
64925675Ssam 	uq->av_forw = bp->av_forw;
65025675Ssam 	if (uq->av_back != bp) {
65125675Ssam 		register struct buf *next;
65224004Ssam 
65325675Ssam 		unit = VDUNIT(uq->av_forw->b_dev);
65425675Ssam 		slave = vddinfo[unit]->ui_slave;
65525675Ssam 		next = uq->av_forw;
65625675Ssam 		if (next->b_cylin != ci->cur_cyl[slave] ||
65725675Ssam 		    (next->b_daddr & 0xff) != ci->cur_trk[slave])
65825675Ssam 			ci->off_cylinder |= 1 << slave;
65925675Ssam 	} else
66025675Ssam 		uq->av_back = NULL;
66125675Ssam 	splx(s);
66225675Ssam 	/* reset controller state */
66325675Ssam 	cq->b_errcnt = 0;
66425675Ssam 	cq->b_active--;
66524004Ssam #ifdef VDDCPERF
66624004Ssam 	scope_out(3);
66724004Ssam #endif
66825675Ssam 	if (bp->b_flags & B_ERROR)
66925675Ssam 		bp->b_error = EIO;
67024004Ssam 	iodone(bp);
67125675Ssam 	vdstart(vdminfo[ctlr]);
67224004Ssam }
67324004Ssam 
67425675Ssam /*
67525675Ssam  * Convert controller status to internal operation/error code.
67625675Ssam  */
67725675Ssam vddecode_error(dcb)
67825675Ssam 	register fmt_dcb *dcb;
67925675Ssam {
68024004Ssam 
68125675Ssam 	if (dcb->operrsta & HRDERR) {
68225675Ssam 		if (dcb->operrsta & (HCRCERR | HCMPERR | UCDATERR | WPTERR |
68325675Ssam 		    DSEEKERR | NOTCYLERR |DRVNRDY | INVDADR))
68425675Ssam 			return (DRIVE_ERROR);
68525675Ssam 		if (dcb->operrsta & (CTLRERR | OPABRT | INVCMD | DNEMEM))
68625675Ssam 			return (CTLR_ERROR);
68725675Ssam 		return (HARD_DATA_ERROR);
68825675Ssam 	}
68925675Ssam 	if (dcb->operrsta & SFTERR)
69025675Ssam 		return (SOFT_DATA_ERROR);
69125675Ssam 	return (0);
69225675Ssam }
69325675Ssam 
69425675Ssam /*
69525675Ssam  * Report a hard error.
69625675Ssam  */
69725675Ssam vdhard_error(ci, bp, dcb)
69825675Ssam 	ctlr_tab *ci;
69925675Ssam 	register struct buf *bp;
70025675Ssam 	register fmt_dcb *dcb;
70125675Ssam {
70225675Ssam 	unit_tab *ui = &vdunit_info[VDUNIT(bp->b_dev)];
70325675Ssam 
70425675Ssam 	bp->b_flags |= B_ERROR;
70525675Ssam 	harderr(bp, ui->info.type_name);
70625675Ssam 	printf("status %x", dcb->operrsta);
70725675Ssam 	if (ci->ctlr_type == SMD_ECTLR)
70825675Ssam 		printf(" ecode %x", dcb->err_code);
70925675Ssam 	printf("\n");
71025675Ssam }
71125675Ssam 
71225675Ssam /*
71325675Ssam  * Report a soft error.
71425675Ssam  */
71525675Ssam vdsoft_error(ci, bp, dcb)
71625675Ssam 	ctlr_tab *ci;
71725675Ssam 	register struct buf *bp;
71825675Ssam 	register fmt_dcb *dcb;
71925675Ssam {
72025675Ssam 	unit_tab *ui = &vdunit_info[VDUNIT(bp->b_dev)];
72125675Ssam 
72225675Ssam 	printf("%s%d%c: soft error sn%d status %x", ui->info.type_name,
72325857Ssam 	    minor(bp->b_dev) >> 3, 'a'+(minor(bp->b_dev)&07), bp->b_blkno,
72425675Ssam 	    dcb->operrsta);
72525675Ssam 	if (ci->ctlr_type == SMD_ECTLR)
72625675Ssam 		printf(" ecode %x", dcb->err_code);
72725675Ssam 	printf("\n");
72825675Ssam }
72925675Ssam 
73025675Ssam /*ARGSUSED*/
73125675Ssam vdopen(dev, flag)
73225675Ssam 	dev_t dev;
73325675Ssam 	int flag;
73425675Ssam {
73525675Ssam 	register unit = VDUNIT(dev);
73625675Ssam 	register struct vba_device *vi = vddinfo[unit];
73725675Ssam 
73825675Ssam 	if (vi == 0 || vi->ui_alive == 0 || vi->ui_type >= nvddrv)
73925675Ssam 		return (ENXIO);
74025675Ssam 	if (vdunit_info[unit].info.partition[FILSYS(dev)].par_len == 0)
74125675Ssam 		return (ENXIO);
74225675Ssam 	return (0);
74325675Ssam }
74425675Ssam 
74524004Ssam vdread(dev, uio)
74625675Ssam 	dev_t dev;
74725675Ssam 	struct uio *uio;
74824004Ssam {
74924004Ssam 	register int unit = VDUNIT(dev);
75025675Ssam 	register unit_tab *ui = &vdunit_info[unit];
75124004Ssam 
75224004Ssam 	if (unit >= NFSD)
75325675Ssam 		return (ENXIO);
75425675Ssam 	return (physio(vdstrategy, &ui->raw_q_element, dev, B_READ,
75525675Ssam 	    minphys, uio));
75624004Ssam }
75724004Ssam 
75824004Ssam vdwrite(dev, uio)
75925675Ssam 	dev_t dev;
76025675Ssam 	struct uio *uio;
76124004Ssam {
76224004Ssam 	register int unit = VDUNIT(dev);
76325675Ssam 	register unit_tab *ui = &vdunit_info[unit];
76424004Ssam 
76524004Ssam 	if (unit >= NFSD)
76625675Ssam 		return (ENXIO);
76725675Ssam 	return (physio(vdstrategy, &ui->raw_q_element, dev, B_WRITE,
76825675Ssam 	    minphys, uio));
76924004Ssam }
77024004Ssam 
77124004Ssam /*
77225675Ssam  * Crash dump.
77324004Ssam  */
77425675Ssam vddump(dev)
77525675Ssam 	dev_t dev;
77624004Ssam {
77725675Ssam 	register int unit = VDUNIT(dev);
77825675Ssam 	register unit_tab *ui = &vdunit_info[unit];
77925675Ssam 	register fs_tab *fs = &ui->info;
78025675Ssam 	register int ctlr = vddinfo[unit]->ui_ctlr;
78125675Ssam 	register struct vba_ctlr *vba_vdctlr_info = vdminfo[ctlr];
78225675Ssam 	register int filsys = FILSYS(dev);
78325675Ssam 	register cdr *addr = (cdr *)(vba_vdctlr_info->um_addr);
78425675Ssam 	register int cur_blk, blkcount, blocks;
78525675Ssam 	caddr_t memaddr;
78624004Ssam 
78725675Ssam 	vdreset_ctlr(addr, ctlr);
78824004Ssam 	blkcount = maxfree - 2;		/* In 1k byte pages */
78925675Ssam 	if (dumplo + blkcount > fs->partition[filsys].par_len) {
79025675Ssam 		blkcount = fs->partition[filsys].par_len - dumplo;
79125675Ssam 		printf("vd%d: Dump truncated to %dMB\n", unit, blkcount/1024);
79225675Ssam 	}
79325675Ssam 	cur_blk = fs->partition[filsys].par_start + dumplo;
79425675Ssam 	memaddr = 0;
79524004Ssam 	while (blkcount > 0) {
79625675Ssam 		blocks = MIN(blkcount, DUMPSIZE);
79725675Ssam 		if (!vdwrite_block(addr, ctlr, unit, memaddr, cur_blk, blocks))
79825675Ssam 			return (EIO);
79925675Ssam 		blkcount -= blocks;
80025675Ssam 		memaddr += blocks * NBPG;
80125675Ssam 		cur_blk += blocks;
80224004Ssam 	}
80325675Ssam 	return (0);
80424004Ssam }
80524004Ssam 
80625675Ssam /*
80725675Ssam  * Write a block to disk during a crash dump.
80825675Ssam  */
80925675Ssam vdwrite_block(caddr, ctlr, unit, addr, block, blocks)
81025675Ssam 	register cdr *caddr;
81125675Ssam 	register int ctlr, unit;
81225675Ssam 	register caddr_t addr;
81325675Ssam 	register int block, blocks;
81424004Ssam {
81525675Ssam 	register fmt_mdcb *mdcb = &vdctlr_info[ctlr].ctlr_mdcb;
81625675Ssam 	register fmt_dcb *dcb = &vdctlr_info[ctlr].ctlr_dcb;
81725675Ssam 	register unit_tab *ui = &vdunit_info[unit];
81825675Ssam 	register fs_tab	 *fs = &ui->info;
81924004Ssam 
82025675Ssam 	block *= (int)ui->sec_per_blk;
82125675Ssam 	blocks *= (int)ui->sec_per_blk;
82225675Ssam 	mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
82325675Ssam 	dcb->intflg = NOINT;
82425675Ssam 	dcb->opcode = WD;
82525675Ssam 	dcb->operrsta = 0;
82625675Ssam 	dcb->devselect = (char)(vddinfo[unit])->ui_slave;
82725675Ssam 	dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long));
82825675Ssam 	dcb->trail.rwtrail.memadr = addr;
82925675Ssam 	dcb->trail.rwtrail.wcount = (short)
83025675Ssam 	    ((blocks * fs->secsize)/ sizeof (short));
83125675Ssam 	dcb->trail.rwtrail.disk.cylinder = (short)(block / ui->sec_per_cyl);
83225675Ssam 	dcb->trail.rwtrail.disk.track = (char)((block / fs->nsec) % fs->ntrak);
83325675Ssam 	dcb->trail.rwtrail.disk.sector = (char)(block % fs->nsec);
83425675Ssam 	VDDC_ATTENTION(caddr, (fmt_mdcb *)(PHYS(mdcb)),
83525675Ssam 	    vdctlr_info[ctlr].ctlr_type);
83625675Ssam 	POLLTILLDONE(caddr, dcb, 5, vdctlr_info[ctlr].ctlr_type);
83725675Ssam 	if (vdtimeout <= 0) {
83825675Ssam 		printf(" during dump\n");
83925675Ssam 		return (0);
84025675Ssam 	}
84125675Ssam 	if (dcb->operrsta & HRDERR) {
84225675Ssam 		printf("vd%d: hard error, status %x\n", unit, dcb->operrsta);
84325675Ssam 		return (0);
84425675Ssam 	}
84525675Ssam 	return (1);
84624004Ssam }
84724004Ssam 
84824004Ssam vdsize(dev)
84925675Ssam 	dev_t dev;
85024004Ssam {
85125675Ssam 	struct vba_device *vi = vddinfo[VDUNIT(dev)];
85224004Ssam 
85325675Ssam 	if (vi == 0 || vi->ui_alive == 0 || vi->ui_type >= nvddrv)
85425675Ssam 		return (-1);
85525675Ssam 	return (vdunit_info[VDUNIT(dev)].info.partition[FILSYS(dev)].par_len);
85624004Ssam }
85724004Ssam 
85825675Ssam /*
85925675Ssam  * Perform a controller reset.
86025675Ssam  */
86125675Ssam vdreset_ctlr(addr, ctlr)
86225675Ssam 	register cdr *addr;
86325675Ssam 	register int ctlr;
86424004Ssam {
86525675Ssam 	register struct buf *cq = &vdminfo[ctlr]->um_tab;
86625675Ssam 	register struct buf *uq = cq->b_forw;
86725675Ssam 	register ctlr_tab *ci = &vdctlr_info[ctlr];
86825675Ssam 
86925675Ssam 	VDDC_RESET(addr, ci->ctlr_type);
87025675Ssam 	ci->ctlr_started = 0;
87125675Ssam 	if (ci->ctlr_type == SMD_ECTLR) {
87225675Ssam 		addr->cdr_csr = 0;
87325675Ssam 		addr->mdcb_tcf = AM_ENPDA;
87425675Ssam 		addr->dcb_tcf = AM_ENPDA;
87525675Ssam 		addr->trail_tcf = AM_ENPDA;
87625675Ssam 		addr->data_tcf = AM_ENPDA;
87725675Ssam 		addr->cdr_ccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
87825675Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
87925675Ssam 	}
88025675Ssam 	if (vdnotrailer(addr, ctlr, 0, INIT, 10) & HRDERR) {
88125675Ssam 		printf("failed to init\n");
88225675Ssam 		return (0);
88325675Ssam 	}
88425675Ssam 	if (vdnotrailer(addr, ctlr, 0, DIAG, 10) & HRDERR) {
88525675Ssam 		printf("diagnostic error\n");
88625675Ssam 		return (0);
88725675Ssam 	}
88825675Ssam 	/*  reset all units attached to controller */
88925675Ssam 	uq = cq->b_forw;
89025675Ssam 	do {
89125675Ssam 		reset_drive(addr, ctlr, uq->b_dev, 0);
89225675Ssam 		uq = uq->b_forw;
89325675Ssam 	} while (uq != cq->b_forw);
89425675Ssam 	return (1);
89525675Ssam }
89624004Ssam 
89725675Ssam /*
89825675Ssam  * Perform a reset on a drive.
89925675Ssam  */
90025675Ssam reset_drive(addr, ctlr, slave, start)
90125675Ssam 	register cdr *addr;
90225675Ssam 	register int ctlr, slave, start;
90325675Ssam {
90425675Ssam 	register int type = vdctlr_info[ctlr].unit_type[slave];
90525675Ssam 
90625675Ssam 	if (type == UNKNOWN)
90725675Ssam 		return;
90825675Ssam 	if (!vdconfigure_drive(addr, ctlr, slave, type, start))
90925675Ssam 		printf("vd%d: drive %d: couldn't reset\n", ctlr, slave);
91025675Ssam }
91125675Ssam 
91225675Ssam #ifdef notdef
91325675Ssam /*
91425675Ssam  * Dump the mdcb and DCB for diagnostic purposes.
91525675Ssam  */
91625675Ssam vdprintdcb(lp)
91725675Ssam 	register long *lp;
91825675Ssam {
91925675Ssam 	register int i, dcb, tc;
92025675Ssam 
92125675Ssam 	for (dcb = 0; lp; lp = (long *)(*lp), dcb++) {
92225675Ssam 		lp = (long *)((long)lp | 0xc0000000);
92325675Ssam 		printf("\nDump of dcb%d@%x:", dcb, lp);
92425675Ssam 		for (i = 0, tc = lp[3] & 0xff; i < tc+7; i++)
92525675Ssam 			printf(" %lx", lp[i]);
92625675Ssam 		printf("\n");
92724004Ssam 	}
92825675Ssam 	DELAY(1750000);
92924004Ssam }
93024004Ssam #endif
93125675Ssam #endif
932