xref: /csrg-svn/sys/tahoe/vba/vd.c (revision 25675)
1*25675Ssam /*	vd.c	1.2	86/01/05	*/
224004Ssam 
324004Ssam #include "fsd.h"
424004Ssam #if NVD > 0
524004Ssam /*
6*25675Ssam  * VDDC - Versabus SMD/ESMD driver.
7*25675Ssam  */
8*25675Ssam #include "../tahoe/mtpr.h"
9*25675Ssam #include "../tahoe/pte.h"
1024004Ssam 
11*25675Ssam #include "param.h"
12*25675Ssam #include "buf.h"
13*25675Ssam #include "cmap.h"
14*25675Ssam #include "conf.h"
15*25675Ssam #include "dir.h"
16*25675Ssam #include "dk.h"
17*25675Ssam #include "map.h"
18*25675Ssam #include "systm.h"
19*25675Ssam #include "user.h"
20*25675Ssam #include "vmmac.h"
21*25675Ssam #include "proc.h"
22*25675Ssam #include "uio.h"
2324004Ssam 
24*25675Ssam #include "../tahoevba/vbavar.h"
25*25675Ssam #define	VDGENDATA
26*25675Ssam #include "../tahoevba/vddcreg.h"
27*25675Ssam #undef VDGENDATA
2824004Ssam 
29*25675Ssam #define	MAX_BLOCKSIZE	(MAXBPTE*NBPG)
30*25675Ssam #define	DUMPSIZE	64	/* controller limit */
3124004Ssam 
3224004Ssam #define VDUNIT(x)	(minor(x) >> 3)
33*25675Ssam #define FILSYS(x)	(minor(x) & 0x07)
34*25675Ssam #define PHYS(x)		(vtoph((struct proc *)0, (unsigned)(x)))
35*25675Ssam #define TRUE		1
36*25675Ssam #define	FALSE		0
3724004Ssam 
38*25675Ssam #define CTLR_ERROR	1
39*25675Ssam #define DRIVE_ERROR	2
40*25675Ssam #define HARD_DATA_ERROR	3
41*25675Ssam #define SOFT_DATA_ERROR	4
4224004Ssam 
43*25675Ssam #define b_cylin	b_resid
44*25675Ssam #define b_daddr	b_error
4524004Ssam 
4624004Ssam struct	vba_ctlr *vdminfo[NVD];
4724004Ssam struct  vba_device *vddinfo[NFSD];
48*25675Ssam int	vdprobe(), vdslave(), vdattach(), vddgo();
49*25675Ssam struct	vba_driver vddriver =
50*25675Ssam     { vdprobe, vdslave, vdattach, vddgo, vddcaddr, "smd/fsd",
51*25675Ssam       vddinfo, "vd", vdminfo };
5224004Ssam 
5324004Ssam /*
54*25675Ssam  * Per-drive state.
55*25675Ssam  */
56*25675Ssam typedef struct {
57*25675Ssam 	struct	buf raw_q_element;
58*25675Ssam 	short	sec_per_blk;
59*25675Ssam 	short	sec_per_cyl;
60*25675Ssam 	char	status;
61*25675Ssam 	struct	buf xfer_queue;
62*25675Ssam 	int	drive_type;
63*25675Ssam 	fs_tab	info;
64*25675Ssam } unit_tab;
6524004Ssam 
6624004Ssam /*
67*25675Ssam  * Per-controller state.
68*25675Ssam  */
69*25675Ssam typedef struct {
70*25675Ssam 	char	ctlr_type;	/* controller type */
71*25675Ssam 	char	*map;		/* i/o page map */
72*25675Ssam 	char	*utl;		/* mapped i/o space */
73*25675Ssam 	u_int	cur_slave:8;	/* last active unit number */
74*25675Ssam 	u_int	int_expected:1;	/* expect an interupt */
75*25675Ssam 	u_int	ctlr_started:1;	/* start command was issued */
76*25675Ssam 	u_int	overlap_seeks:1;/* should overlap seeks */
77*25675Ssam 	u_int	off_cylinder:16;/* off cylinder bit map */
78*25675Ssam 	u_int	unit_type[16];	/* slave types */
79*25675Ssam 	u_int	cur_cyl[16];	/* cylinder last selected */
80*25675Ssam 	long	cur_trk[16];	/* track last selected */
81*25675Ssam 	fmt_mdcb ctlr_mdcb;	/* controller mdcb */
82*25675Ssam 	fmt_dcb	ctlr_dcb;	/* r/w dcb */
83*25675Ssam 	fmt_dcb	seek_dcb[4];	/* dcbs for overlapped seeks */
84*25675Ssam 	/* buffer for raw/swap i/o */
85*25675Ssam 	char	rawbuf[MAX_BLOCKSIZE];
86*25675Ssam } ctlr_tab;
8724004Ssam 
88*25675Ssam extern char	vd0utl[];
89*25675Ssam #if NVD > 1
90*25675Ssam extern char	vd1utl[];
91*25675Ssam #endif
92*25675Ssam #if NVD > 2
93*25675Ssam extern char	vd2utl[];
94*25675Ssam #endif
95*25675Ssam #if NVD > 3
96*25675Ssam extern char	vd3utl[];
97*25675Ssam #endif
9824004Ssam 
99*25675Ssam #define	VDCINIT(map, utl) { \
100*25675Ssam     UNKNOWN, (char *)map, utl, 0, FALSE, FALSE, TRUE, 0, \
101*25675Ssam 	{ UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, \
102*25675Ssam 	  UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN } \
103*25675Ssam }
104*25675Ssam ctlr_tab vdctlr_info[NVD] = {
105*25675Ssam 	VDCINIT(VD0map, vd0utl),
106*25675Ssam #if NVD > 1
107*25675Ssam 	VDCINIT(VD1map, vd1utl),
108*25675Ssam #endif
109*25675Ssam #if NVD > 2
110*25675Ssam 	VDCINIT(VD2map, vd2utl),
111*25675Ssam #endif
112*25675Ssam #if NVD > 3
113*25675Ssam 	VDCINIT(VD3map, vd3utl),
114*25675Ssam #endif
11524004Ssam };
11624004Ssam 
117*25675Ssam unit_tab vdunit_info[NFSD];
11824004Ssam 
11924004Ssam /*
120*25675Ssam  * See if the controller is really there; if so, initialize it.
121*25675Ssam  */
122*25675Ssam vdprobe(addr)
123*25675Ssam 	cdr *addr;
124*25675Ssam {
125*25675Ssam 	if (badaddr((caddr_t)addr, 2))
126*25675Ssam 		return (0);
127*25675Ssam 	addr->cdr_reset = 0xffffffff;
128*25675Ssam 	DELAY(1000000);
129*25675Ssam 	if (addr->cdr_reset != (unsigned)0xffffffff) {
130*25675Ssam 		DELAY(1000000);
131*25675Ssam 	} else {
132*25675Ssam 		addr->cdr_reserved = 0x0;
133*25675Ssam 		DELAY(3000000);
134*25675Ssam 	}
135*25675Ssam 	return (sizeof (cdr));
136*25675Ssam }
13724004Ssam 
13824004Ssam /*
139*25675Ssam  * See if a drive is really there
140*25675Ssam  * Try to reset/configure the drive, then test its status.
141*25675Ssam  */
142*25675Ssam vdslave(vi, addr)
143*25675Ssam 	register struct vba_device *vi;
144*25675Ssam 	register cdr *addr;
145*25675Ssam {
146*25675Ssam 	register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr];
147*25675Ssam 	register unit_tab *ui = &vdunit_info[vi->ui_unit];
148*25675Ssam 	register fmt_mdcb *mdcb = &ci->ctlr_mdcb;
149*25675Ssam 	register fmt_dcb *dcb = &ci->ctlr_dcb;
150*25675Ssam 	register int type;
15124004Ssam 
152*25675Ssam 	if (ci->ctlr_type == UNKNOWN) {
153*25675Ssam 		addr->cdr_reset = 0xffffffff;
154*25675Ssam 		DELAY(1000000);
155*25675Ssam 		if (addr->cdr_reset != (unsigned)0xffffffff) {
156*25675Ssam 			ci->ctlr_type = SMDCTLR;
157*25675Ssam 			ci->overlap_seeks = 0;
158*25675Ssam 			DELAY(1000000);
159*25675Ssam 		} else {
160*25675Ssam 			ci->overlap_seeks = 1;
161*25675Ssam 			ci->ctlr_type = SMD_ECTLR;
162*25675Ssam 			addr->cdr_reserved = 0x0;
163*25675Ssam 			DELAY(3000000);
164*25675Ssam 			addr->cdr_csr = 0;
165*25675Ssam 			addr->mdcb_tcf = AM_ENPDA;
166*25675Ssam 			addr->dcb_tcf = AM_ENPDA;
167*25675Ssam 			addr->trail_tcf = AM_ENPDA;
168*25675Ssam 			addr->data_tcf = AM_ENPDA;
169*25675Ssam 			addr->cdr_ccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
170*25675Ssam 			    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
171*25675Ssam 		}
172*25675Ssam 		if (vdnotrailer(addr,
173*25675Ssam 		    vi->ui_ctlr, vi->ui_slave, INIT, 10) & HRDERR) {
174*25675Ssam 			printf("vd%d: init error\n", vi->ui_unit);
175*25675Ssam 			return (0);
176*25675Ssam 		}
177*25675Ssam 		if (vdnotrailer(addr,
178*25675Ssam 		    vi->ui_ctlr, vi->ui_slave, DIAG, 10) & HRDERR) {
179*25675Ssam 			printf("vd%d: diagnostic error\n", vi->ui_unit);
180*25675Ssam 			return (0);
181*25675Ssam 		}
182*25675Ssam 	}
183*25675Ssam 	/*
184*25675Ssam 	 * Seek on all drive types starting from the largest one.
185*25675Ssam 	 * a successful seek to the last sector/cylinder/track verifies
186*25675Ssam 	 * the drive type connected to this port.
187*25675Ssam 	 */
188*25675Ssam 	for (type = 0; type < nvddrv; type++) {
189*25675Ssam 		/* XXX */
190*25675Ssam 		if (ci->ctlr_type == SMDCTLR && vdst[type].nsec != 32)
191*25675Ssam 			continue;
192*25675Ssam 		/* XXX */
193*25675Ssam 		if (!vdconfigure_drive(addr, vi->ui_ctlr, vi->ui_slave, type,0))
194*25675Ssam 			return (0);
195*25675Ssam 		dcb->opcode = (short)RD;
196*25675Ssam 		dcb->intflg = NOINT;
197*25675Ssam 		dcb->nxtdcb = (fmt_dcb *)0;	/* end of chain */
198*25675Ssam 		dcb->operrsta = 0;
199*25675Ssam 		dcb->devselect = (char)(vi->ui_slave);
200*25675Ssam 		dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long));
201*25675Ssam 		dcb->trail.rwtrail.memadr = (char *)PHYS(ci->rawbuf);
202*25675Ssam 		dcb->trail.rwtrail.wcount = vdst[type].secsize/sizeof(short);
203*25675Ssam 		dcb->trail.rwtrail.disk.cylinder = vdst[type].ncyl - 2;
204*25675Ssam 		dcb->trail.rwtrail.disk.track = vdst[type].ntrak - 1;
205*25675Ssam 		dcb->trail.rwtrail.disk.sector = vdst[type].nsec - 1;
206*25675Ssam 		mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
207*25675Ssam 		mdcb->vddcstat = 0;
208*25675Ssam 		VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type);
209*25675Ssam 		POLLTILLDONE(addr, dcb, 60, ci->ctlr_type);
210*25675Ssam 		if (vdtimeout <= 0)
211*25675Ssam 			printf(" during probe\n");
212*25675Ssam 		if ((dcb->operrsta&HRDERR) == 0)
213*25675Ssam 			break;
214*25675Ssam 	}
215*25675Ssam 	if (type >= nvddrv) {
216*25675Ssam 		/*
217*25675Ssam 		 * If reached here, a drive which is not defined in the
218*25675Ssam 		 * 'vdst' tables is connected. Cannot set it's type.
219*25675Ssam 		 */
220*25675Ssam 		printf("vd%d: unknown drive type\n", vi->ui_unit);
221*25675Ssam 		return (0);
222*25675Ssam 	}
223*25675Ssam 	ui->drive_type = type;
224*25675Ssam 	ui->info = vdst[type];
225*25675Ssam 	ui->sec_per_blk = DEV_BSIZE / ui->info.secsize;
226*25675Ssam 	vi->ui_type = type;
227*25675Ssam  	vi->ui_dk = 1;
228*25675Ssam 	vddriver.ud_dname = ui->info.type_name;
229*25675Ssam 	return (1);
23024004Ssam }
23124004Ssam 
232*25675Ssam vdconfigure_drive(addr, ctlr, slave, type, pass)
233*25675Ssam 	register cdr *addr;
234*25675Ssam 	int ctlr, slave, type, pass;
23524004Ssam {
236*25675Ssam 	register ctlr_tab *ci = &vdctlr_info[ctlr];
237*25675Ssam 
238*25675Ssam 	ci->ctlr_dcb.opcode = RSTCFG;		/* command */
239*25675Ssam 	ci->ctlr_dcb.intflg = NOINT;
240*25675Ssam 	ci->ctlr_dcb.nxtdcb = (fmt_dcb *)0;	/* end of chain */
241*25675Ssam 	ci->ctlr_dcb.operrsta = 0;
242*25675Ssam 	ci->ctlr_dcb.devselect = (char)slave;
243*25675Ssam 	ci->ctlr_dcb.trail.rstrail.ncyl = vdst[type].ncyl;
244*25675Ssam 	ci->ctlr_dcb.trail.rstrail.nsurfaces = vdst[type].ntrak;
245*25675Ssam 	if (ci->ctlr_type == SMD_ECTLR) {
246*25675Ssam 		ci->ctlr_dcb.trailcnt = (char)4;
247*25675Ssam 		ci->ctlr_dcb.trail.rstrail.nsectors = vdst[type].nsec;
248*25675Ssam 		ci->ctlr_dcb.trail.rstrail.slip_sec = vdst[type].nslip;
249*25675Ssam 	} else
250*25675Ssam 		ci->ctlr_dcb.trailcnt = (char)2;
251*25675Ssam 	ci->ctlr_mdcb.firstdcb = (fmt_dcb *)(PHYS(&ci->ctlr_dcb));
252*25675Ssam 	ci->ctlr_mdcb.vddcstat = 0;
253*25675Ssam 	VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(&ci->ctlr_mdcb)), ci->ctlr_type);
254*25675Ssam 	POLLTILLDONE(addr, &ci->ctlr_dcb, 5, ci->ctlr_type);
255*25675Ssam 	if (vdtimeout <= 0) {
256*25675Ssam 		printf(" during config\n");
257*25675Ssam 		return (0);
258*25675Ssam 	}
259*25675Ssam 	if (ci->ctlr_dcb.operrsta & HRDERR) {
260*25675Ssam 		if ((ci->ctlr_dcb.operrsta & (NOTCYLERR|DRVNRDY)) == 0)
261*25675Ssam 			printf("vd%d: drive %d: config error\n", ctlr, slave);
262*25675Ssam 		else if (pass == 0) {
263*25675Ssam 			vdstart_drive(addr, ctlr, slave);
264*25675Ssam 			return (vdconfigure_drive(addr, ctlr, slave, type, 1));
265*25675Ssam 		} else if (pass == 2)
266*25675Ssam 			return (vdconfigure_drive(addr, ctlr, slave, type, 3));
267*25675Ssam 		return (0);
268*25675Ssam 	}
269*25675Ssam 	return (1);
27024004Ssam }
27124004Ssam 
272*25675Ssam vdstart_drive(addr, ctlr, slave)
273*25675Ssam 	cdr *addr;
274*25675Ssam 	register int ctlr, slave;
27524004Ssam {
276*25675Ssam 	int error = 0;
27724004Ssam 
278*25675Ssam 	printf("vd%d: starting drive %d, wait...", ctlr, slave);
279*25675Ssam 	if (vdctlr_info[ctlr].ctlr_started) {
280*25675Ssam printf("DELAY(5500000)...");
281*25675Ssam 		DELAY(5500000);
282*25675Ssam 		goto done;
28324004Ssam 	}
284*25675Ssam 	vdctlr_info[ctlr].ctlr_started = 1;
285*25675Ssam 	error = vdnotrailer(addr, ctlr, 0, VDSTART, (slave*6)+62) & HRDERR;
286*25675Ssam 	if (!error) {
287*25675Ssam printf("DELAY(%d)...", (slave * 5500000) + 62000000);
288*25675Ssam 		DELAY((slave * 5500000) + 62000000);
28924004Ssam 	}
290*25675Ssam done:
291*25675Ssam 	printf("\n");
292*25675Ssam 	return (error == 0);
293*25675Ssam }
29424004Ssam 
295*25675Ssam vdnotrailer(addr, ctlr, unit, function, time)
296*25675Ssam 	register cdr *addr;
297*25675Ssam 	int ctlr, unit, function, time;
29824004Ssam {
299*25675Ssam 	fmt_mdcb *mdcb = &vdctlr_info[ctlr].ctlr_mdcb;
300*25675Ssam 	fmt_dcb *dcb = &vdctlr_info[ctlr].ctlr_dcb;
301*25675Ssam 	int type = vdctlr_info[ctlr].ctlr_type;
30224004Ssam 
303*25675Ssam 	dcb->opcode = function;		/* command */
30424004Ssam 	dcb->intflg = NOINT;
305*25675Ssam 	dcb->nxtdcb = (fmt_dcb *)0;	/* end of chain */
306*25675Ssam 	dcb->operrsta = 0;
307*25675Ssam 	dcb->devselect = (char)unit;
30824004Ssam 	dcb->trailcnt = (char)0;
309*25675Ssam 	mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
31024004Ssam 	mdcb->vddcstat = 0;
311*25675Ssam 	VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(mdcb)), type);
312*25675Ssam 	POLLTILLDONE(addr, dcb, time, type);
313*25675Ssam 	if (vdtimeout <= 0) {
314*25675Ssam 		printf(" during init\n");
315*25675Ssam 		return (DCBCMP|ANYERR|HRDERR|OPABRT);
31624004Ssam 	}
317*25675Ssam 	return (dcb->operrsta);
318*25675Ssam }
31924004Ssam 
320*25675Ssam vdattach(vi)
321*25675Ssam 	register struct vba_device *vi;
322*25675Ssam {
323*25675Ssam 	register unit_tab *ui = &vdunit_info[vi->ui_unit];
324*25675Ssam 	register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr];
325*25675Ssam 	register struct buf *cq = &vi->ui_mi->um_tab;
326*25675Ssam 	register struct buf *uq = cq->b_forw;
327*25675Ssam 	register struct buf *start_queue = uq;
328*25675Ssam 	register fs_tab	*fs = &ui->info;
329*25675Ssam 
330*25675Ssam 	ui->info = vdst[vi->ui_type];
331*25675Ssam 	ui->sec_per_blk = DEV_BSIZE / ui->info.secsize;
332*25675Ssam 	ui->sec_per_cyl = ui->info.nsec * ui->info.ntrak;
333*25675Ssam 	ui->xfer_queue.b_dev = vi->ui_slave;
334*25675Ssam 	ci->unit_type[vi->ui_slave] = vi->ui_type;
335*25675Ssam 	/* load unit into controller's active unit list */
336*25675Ssam 	if (uq == NULL) {
337*25675Ssam 		cq->b_forw = &ui->xfer_queue;
338*25675Ssam 		ui->xfer_queue.b_forw = &ui->xfer_queue;
339*25675Ssam 		ui->xfer_queue.b_back = &ui->xfer_queue;
340*25675Ssam 	} else {
341*25675Ssam 		while (uq->b_forw != start_queue)
342*25675Ssam 			uq = uq->b_forw;
343*25675Ssam 		ui->xfer_queue.b_forw = start_queue;
344*25675Ssam 		ui->xfer_queue.b_back = uq;
345*25675Ssam 		uq->b_forw = &ui->xfer_queue;
346*25675Ssam 		start_queue->b_back = &ui->xfer_queue;
347*25675Ssam 	}
34824004Ssam 	/*
349*25675Ssam 	 * (60 / rpm) / (number of sectors per track * (bytes per sector / 2))
35024004Ssam 	 */
351*25675Ssam 	dk_mspw[vi->ui_unit] = 120.0 / (fs->rpm * fs->nsec * fs->secsize);
35224004Ssam }
35324004Ssam 
354*25675Ssam /*ARGSUSED*/
355*25675Ssam vddgo(um)
356*25675Ssam 	struct vba_ctlr *um;
35724004Ssam {
35824004Ssam 
35924004Ssam }
36024004Ssam 
36124004Ssam vdstrategy(bp)
362*25675Ssam 	register struct buf *bp;
36324004Ssam {
364*25675Ssam 	register int unit = VDUNIT(bp->b_dev);
365*25675Ssam 	register struct vba_device *vi = vddinfo[unit];
366*25675Ssam 	register par_tab *par;
367*25675Ssam 	register unit_tab *ui;
368*25675Ssam 	register fs_tab *fs;
369*25675Ssam 	register int blks, bn, s;
37024004Ssam 
371*25675Ssam 	if (bp->b_bcount == 0 || vi == 0 || vi->ui_alive == 0)
372*25675Ssam 		goto bad;
373*25675Ssam 	ui = &vdunit_info[unit];
374*25675Ssam 	fs = &ui->info;
375*25675Ssam 	par = &fs->partition[FILSYS(bp->b_dev)];
376*25675Ssam 	blks = (bp->b_bcount + DEV_BSIZE-1) >> DEV_BSHIFT;
377*25675Ssam 	if (bp->b_blkno + blks >= par->par_len) {
378*25675Ssam 		blks = par->par_len - bp->b_blkno;
379*25675Ssam 		if (blks <= 0)
380*25675Ssam 			goto bad;
381*25675Ssam 		bp->b_bcount = blks * DEV_BSIZE;
382*25675Ssam 	}
383*25675Ssam 	bn = bp->b_blkno + par->par_start;
384*25675Ssam 	bn *= ui->sec_per_blk;
385*25675Ssam 	bp->b_daddr = (bn / fs->nsec) % fs->ntrak;
386*25675Ssam 	bp->b_cylin = bn / ui->sec_per_cyl;
387*25675Ssam 	vbasetup(bp, ui->info.secsize);
388*25675Ssam 	s = spl7();
389*25675Ssam 	if (ui->xfer_queue.av_forw == NULL) {
390*25675Ssam 		register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr];
391*25675Ssam 		int slave = vi->ui_slave;
39224004Ssam 
393*25675Ssam 		if (bp->b_cylin != ci->cur_cyl[slave] ||
394*25675Ssam 		    bp->b_daddr != ci->cur_trk[slave])
395*25675Ssam 			ci->off_cylinder |= 1 << slave;
39624004Ssam 	}
397*25675Ssam 	bp->b_daddr |= (bn % fs->nsec) << 8;
398*25675Ssam 	disksort(&ui->xfer_queue, bp);
399*25675Ssam 	if (!vddinfo[unit]->ui_mi->um_tab.b_active++) {
400*25675Ssam 		splx(s);
401*25675Ssam 		vdstart(vddinfo[unit]->ui_mi);
402*25675Ssam 	} else
403*25675Ssam 		splx(s);
40424004Ssam 	return;
405*25675Ssam bad:
406*25675Ssam 	bp->b_flags |= B_ERROR, bp->b_error = ENXIO;
407*25675Ssam 	bp->b_resid = bp->b_bcount;
40824004Ssam 	iodone(bp);
40924004Ssam }
41024004Ssam 
41124004Ssam /*
41224004Ssam  * Start up a transfer on a drive.
41324004Ssam  */
414*25675Ssam vdstart(ci)
415*25675Ssam 	register struct vba_ctlr *ci;
41624004Ssam {
417*25675Ssam 	register struct buf *cq = &ci->um_tab;
418*25675Ssam 	register struct buf *uq = cq->b_forw;
41924004Ssam 
420*25675Ssam 	/* search for next ready unit */
421*25675Ssam 	cq->b_forw = cq->b_forw->b_forw;
422*25675Ssam 	uq = cq->b_forw;
423*25675Ssam 	do {
424*25675Ssam 		if (uq->av_forw != NULL) {
425*25675Ssam 			cq->b_forw = uq;
426*25675Ssam 			vdexecute(ci, uq);
427*25675Ssam 			return;
428*25675Ssam 		}
429*25675Ssam 		uq = uq->b_forw;
430*25675Ssam 	} while (uq != cq->b_forw);
431*25675Ssam }
432*25675Ssam 
433*25675Ssam /*
434*25675Ssam  * Initiate seeks for all drives off-cylinder.
435*25675Ssam  */
436*25675Ssam vdload_seeks(ci, uq)
437*25675Ssam 	register ctlr_tab *ci;
438*25675Ssam 	register struct buf *uq;
439*25675Ssam {
440*25675Ssam 	register int unit, slave, nseeks;
441*25675Ssam 	register fmt_dcb *dcb;
442*25675Ssam 	register struct buf *bp;
443*25675Ssam 	register struct buf *start_queue = uq;
444*25675Ssam 
445*25675Ssam 	nseeks = 0;
446*25675Ssam 	do {
447*25675Ssam 		bp = uq->av_forw;
448*25675Ssam 		if (bp != NULL) {
449*25675Ssam 			unit = VDUNIT(bp->b_dev);
450*25675Ssam 			slave = vddinfo[unit]->ui_slave;
451*25675Ssam 			if (ci->off_cylinder & (1 << slave)) {
452*25675Ssam 				ci->off_cylinder &= ~(1 << slave);
453*25675Ssam 				if (ci->cur_cyl[slave] != bp->b_cylin) {
454*25675Ssam 					ci->cur_cyl[slave] = bp->b_cylin;
455*25675Ssam 					dk_seek[unit]++;
456*25675Ssam 				}
457*25675Ssam 				ci->cur_trk[slave] = bp->b_daddr&0xff;
458*25675Ssam 				dcb = &ci->seek_dcb[nseeks++];
459*25675Ssam 				dcb->opcode = SEEK;
460*25675Ssam 				dcb->intflg = NOINT | INT_PBA;
461*25675Ssam 				dcb->operrsta = 0;
462*25675Ssam 				dcb->devselect = (char)slave;
463*25675Ssam 				dcb->trailcnt = (char)1;
464*25675Ssam 				dcb->trail.sktrail.skaddr.cylinder =
465*25675Ssam 				    bp->b_cylin;
466*25675Ssam 				dcb->trail.sktrail.skaddr.track =
467*25675Ssam 				    bp->b_daddr & 0xff;
468*25675Ssam 				dcb->trail.sktrail.skaddr.sector = 0;
469*25675Ssam 			}
470*25675Ssam 		}
471*25675Ssam 		uq = uq->b_forw;
472*25675Ssam 	} while (uq != start_queue && nseeks < 4);
473*25675Ssam 	return (nseeks);
474*25675Ssam }
475*25675Ssam 
476*25675Ssam extern	vd_int_timeout();
477*25675Ssam /*
478*25675Ssam  * Execute the next command on the unit queue uq.
479*25675Ssam  */
480*25675Ssam vdexecute(controller_info, uq)
481*25675Ssam 	register struct vba_ctlr *controller_info;
482*25675Ssam 	register struct buf *uq;
483*25675Ssam {
484*25675Ssam 	register struct	buf *bp = uq->av_forw;
485*25675Ssam 	register int ctlr = controller_info->um_ctlr;
486*25675Ssam 	register ctlr_tab *ci = &vdctlr_info[ctlr];
487*25675Ssam 	register int unit = VDUNIT(bp->b_dev);
488*25675Ssam 	register int slave = vddinfo[unit]->ui_slave;
489*25675Ssam 	register fmt_mdcb *mdcb = &ci->ctlr_mdcb;
490*25675Ssam 	register fmt_dcb *dcb = &ci->ctlr_dcb;
491*25675Ssam 
49224004Ssam 	/*
493*25675Ssam 	 * If there are overlapped seeks to perform, shuffle
494*25675Ssam 	 * them to the front of the queue and get them started
495*25675Ssam 	 * before any data transfers (to get some parallelism).
49624004Ssam 	 */
497*25675Ssam 	if ((ci->off_cylinder & ~(1<<slave)) && ci->overlap_seeks) {
498*25675Ssam 		register int i, nseeks;
499*25675Ssam 
500*25675Ssam 		/* setup seek requests in seek-q */
501*25675Ssam 		nseeks = vdload_seeks(ci, uq);
502*25675Ssam 		/* place at the front of the master q */
503*25675Ssam 		mdcb->firstdcb = (fmt_dcb *)PHYS(&ci->seek_dcb[0]);
504*25675Ssam 		/* shuffle any remaining seeks up in the seek-q */
505*25675Ssam 		for (i = 1; i < nseeks; i++)
506*25675Ssam 			ci->seek_dcb[i-1].nxtdcb =
507*25675Ssam 			    (fmt_dcb *)PHYS(&ci->seek_dcb[i]);
508*25675Ssam 		ci->seek_dcb[nseeks-1].nxtdcb = (fmt_dcb *)PHYS(dcb);
509*25675Ssam 	} else {
510*25675Ssam 		if (bp->b_cylin != ci->cur_cyl[slave]) {
511*25675Ssam 			ci->cur_cyl[slave] = bp->b_cylin;
512*25675Ssam 			dk_seek[unit]++;
513*25675Ssam 		}
514*25675Ssam 		ci->cur_trk[slave] = bp->b_daddr & 0xff;
515*25675Ssam 		ci->off_cylinder = 0;
516*25675Ssam 		mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
51724004Ssam 	}
51824004Ssam 	dcb->opcode = (bp->b_flags & B_READ) ? RD : WD;
519*25675Ssam 	dcb->intflg = INTDONE;
520*25675Ssam 	dcb->nxtdcb = (fmt_dcb *)0;	/* end of chain */
52124004Ssam 	dcb->operrsta = 0;
522*25675Ssam 	dcb->devselect = (char)slave;
523*25675Ssam 	dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long));
524*25675Ssam 	dcb->trail.rwtrail.memadr = (char *)
525*25675Ssam 	    vbastart(bp, ci->rawbuf, (long *)ci->map, ci->utl);
526*25675Ssam 	dcb->trail.rwtrail.wcount = (short)((bp->b_bcount+1) / sizeof (short));
527*25675Ssam 	dcb->trail.rwtrail.disk.cylinder = bp->b_cylin;
528*25675Ssam 	dcb->trail.rwtrail.disk.track = bp->b_daddr & 0xff;
529*25675Ssam 	dcb->trail.rwtrail.disk.sector = bp->b_daddr >> 8;
530*25675Ssam 	mdcb->vddcstat = 0;
531*25675Ssam    	dk_wds[unit] += bp->b_bcount / 32;
532*25675Ssam 	ci->int_expected = 1;
533*25675Ssam 	timeout(vd_int_timeout, (caddr_t)ctlr, 20*60);
534*25675Ssam   	dk_busy |= 1 << unit;
535*25675Ssam #ifdef VDDCPERF
536*25675Ssam 	scope_out(1);
537*25675Ssam #endif
538*25675Ssam 	VDDC_ATTENTION((cdr *)(vdminfo[ctlr]->um_addr),
539*25675Ssam 	    (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type);
540*25675Ssam }
54124004Ssam 
54224004Ssam /*
543*25675Ssam  * Watch for lost interrupts.
544*25675Ssam  */
545*25675Ssam vd_int_timeout(ctlr)
546*25675Ssam 	register int ctlr;
547*25675Ssam {
548*25675Ssam 	register ctlr_tab *ci = &vdctlr_info[ctlr];
549*25675Ssam 	register fmt_dcb *dcb = &ci->ctlr_dcb;
55024004Ssam 
551*25675Ssam 	uncache(&dcb->operrsta);
552*25675Ssam 	printf("vd%d: lost interupt, status %x", ctlr, dcb->operrsta);
553*25675Ssam 	if (ci->ctlr_type == SMD_ECTLR) {
554*25675Ssam 		uncache(&dcb->err_code);
555*25675Ssam 		printf(", error code %x", dcb->err_code);
55624004Ssam 	}
557*25675Ssam 	printf("\n");
558*25675Ssam 	if ((dcb->operrsta&DCBCMP) == 0) {
559*25675Ssam 		VDDC_ABORT((cdr *)(vdminfo[ctlr]->um_addr), ci->ctlr_type);
560*25675Ssam 		dcb->operrsta |= DCBUSC | DCBABT | ANYERR | HRDERR | CTLRERR;
561*25675Ssam 	}
562*25675Ssam 	vdintr(ctlr);
56324004Ssam }
56424004Ssam 
56524004Ssam /*
56624004Ssam  * Handle a disk interrupt.
56724004Ssam  */
568*25675Ssam vdintr(ctlr)
569*25675Ssam 	register int ctlr;
57024004Ssam {
571*25675Ssam 	register ctlr_tab *ci;
572*25675Ssam 	register struct buf *cq, *uq, *bp;
573*25675Ssam 	register int slave, unit;
574*25675Ssam 	register fmt_mdcb  *mdcb;
575*25675Ssam 	register fmt_dcb *dcb;
576*25675Ssam 	int code, s;
57724004Ssam 
578*25675Ssam 	untimeout(vd_int_timeout, (caddr_t)ctlr);
57924004Ssam #ifdef VDDCPERF
58024004Ssam 	scope_out(2);
58124004Ssam #endif
582*25675Ssam 	ci = &vdctlr_info[ctlr];
583*25675Ssam 	if (!ci->int_expected) {
584*25675Ssam 		printf("vd%d: stray interrupt\n", ctlr);
58524004Ssam 		return;
58624004Ssam 	}
587*25675Ssam 	/*
588*25675Ssam 	 * Take first request off controller's queue.
589*25675Ssam 	 */
590*25675Ssam 	cq = &vdminfo[ctlr]->um_tab;
591*25675Ssam 	uq = cq->b_forw;
592*25675Ssam 	bp = uq->av_forw;
59324004Ssam 	unit = VDUNIT(bp->b_dev);
594*25675Ssam 	dk_busy &= ~(1 << unit);
595*25675Ssam 	dk_xfer[unit]++;
596*25675Ssam 	ci->int_expected = 0;
597*25675Ssam 	/* find associated control blocks */
598*25675Ssam 	mdcb = &ci->ctlr_mdcb, uncache(&mdcb->intdcb);
599*25675Ssam 	dcb = &ci->ctlr_dcb, uncache(&dcb->operrsta);
600*25675Ssam 	if (ci->ctlr_type == SMD_ECTLR)
601*25675Ssam 		uncache(&dcb->err_code);
602*25675Ssam 	slave = uq->b_dev;
603*25675Ssam 	switch (code = vddecode_error(dcb)) {
60424004Ssam 
605*25675Ssam 	case CTLR_ERROR:
606*25675Ssam 	case DRIVE_ERROR:
607*25675Ssam 		if (cq->b_errcnt >= 2)
608*25675Ssam 			vdhard_error(ci, bp, dcb);
609*25675Ssam 		if (code == CTLR_ERROR)
610*25675Ssam 			vdreset_ctlr((cdr *)vdminfo[ctlr]->um_addr, ctlr);
611*25675Ssam 		else
612*25675Ssam 			reset_drive((cdr *)vdminfo[ctlr]->um_addr, ctlr,
613*25675Ssam 			    slave, 2);
614*25675Ssam 		if (cq->b_errcnt++ < 2) {	/* retry error */
615*25675Ssam 			cq->b_forw = uq->b_back;
616*25675Ssam 			vdstart(vdminfo[ctlr]);
617*25675Ssam 			return;
618*25675Ssam 		}
619*25675Ssam 		bp->b_resid = bp->b_bcount;
620*25675Ssam 		break;
621*25675Ssam 
622*25675Ssam 	case HARD_DATA_ERROR:
623*25675Ssam 		vdhard_error(ci, bp, dcb);
624*25675Ssam 		bp->b_resid = 0;
625*25675Ssam 		break;
626*25675Ssam 
627*25675Ssam 	case SOFT_DATA_ERROR:
628*25675Ssam 		vdsoft_error(ci, bp, dcb);
629*25675Ssam 		/* fall thru... */
630*25675Ssam 
631*25675Ssam 	default:			/* operation completed */
632*25675Ssam 		bp->b_error = 0;
633*25675Ssam 		bp->b_resid = 0;
634*25675Ssam 		break;
63524004Ssam 	}
636*25675Ssam 	vbadone(bp, ci->rawbuf, (long *)ci->map, ci->utl);
637*25675Ssam 	/*
638*25675Ssam 	 * Take next request on this unit q, or, if none,
639*25675Ssam 	 * the next request on the next active unit q.
640*25675Ssam 	 */
641*25675Ssam 	s = spl7();
642*25675Ssam 	uq->av_forw = bp->av_forw;
643*25675Ssam 	if (uq->av_back != bp) {
644*25675Ssam 		register struct buf *next;
64524004Ssam 
646*25675Ssam 		unit = VDUNIT(uq->av_forw->b_dev);
647*25675Ssam 		slave = vddinfo[unit]->ui_slave;
648*25675Ssam 		next = uq->av_forw;
649*25675Ssam 		if (next->b_cylin != ci->cur_cyl[slave] ||
650*25675Ssam 		    (next->b_daddr & 0xff) != ci->cur_trk[slave])
651*25675Ssam 			ci->off_cylinder |= 1 << slave;
652*25675Ssam 	} else
653*25675Ssam 		uq->av_back = NULL;
654*25675Ssam 	splx(s);
655*25675Ssam 	/* reset controller state */
656*25675Ssam 	cq->b_errcnt = 0;
657*25675Ssam 	cq->b_active--;
65824004Ssam #ifdef VDDCPERF
65924004Ssam 	scope_out(3);
66024004Ssam #endif
661*25675Ssam 	if (bp->b_flags & B_ERROR)
662*25675Ssam 		bp->b_error = EIO;
66324004Ssam 	iodone(bp);
664*25675Ssam 	vdstart(vdminfo[ctlr]);
66524004Ssam }
66624004Ssam 
667*25675Ssam /*
668*25675Ssam  * Convert controller status to internal operation/error code.
669*25675Ssam  */
670*25675Ssam vddecode_error(dcb)
671*25675Ssam 	register fmt_dcb *dcb;
672*25675Ssam {
67324004Ssam 
674*25675Ssam 	if (dcb->operrsta & HRDERR) {
675*25675Ssam 		if (dcb->operrsta & (HCRCERR | HCMPERR | UCDATERR | WPTERR |
676*25675Ssam 		    DSEEKERR | NOTCYLERR |DRVNRDY | INVDADR))
677*25675Ssam 			return (DRIVE_ERROR);
678*25675Ssam 		if (dcb->operrsta & (CTLRERR | OPABRT | INVCMD | DNEMEM))
679*25675Ssam 			return (CTLR_ERROR);
680*25675Ssam 		return (HARD_DATA_ERROR);
681*25675Ssam 	}
682*25675Ssam 	if (dcb->operrsta & SFTERR)
683*25675Ssam 		return (SOFT_DATA_ERROR);
684*25675Ssam 	return (0);
685*25675Ssam }
686*25675Ssam 
687*25675Ssam /*
688*25675Ssam  * Report a hard error.
689*25675Ssam  */
690*25675Ssam vdhard_error(ci, bp, dcb)
691*25675Ssam 	ctlr_tab *ci;
692*25675Ssam 	register struct buf *bp;
693*25675Ssam 	register fmt_dcb *dcb;
694*25675Ssam {
695*25675Ssam 	unit_tab *ui = &vdunit_info[VDUNIT(bp->b_dev)];
696*25675Ssam 
697*25675Ssam 	bp->b_flags |= B_ERROR;
698*25675Ssam 	harderr(bp, ui->info.type_name);
699*25675Ssam 	printf("status %x", dcb->operrsta);
700*25675Ssam 	if (ci->ctlr_type == SMD_ECTLR)
701*25675Ssam 		printf(" ecode %x", dcb->err_code);
702*25675Ssam 	printf("\n");
703*25675Ssam }
704*25675Ssam 
705*25675Ssam /*
706*25675Ssam  * Report a soft error.
707*25675Ssam  */
708*25675Ssam vdsoft_error(ci, bp, dcb)
709*25675Ssam 	ctlr_tab *ci;
710*25675Ssam 	register struct buf *bp;
711*25675Ssam 	register fmt_dcb *dcb;
712*25675Ssam {
713*25675Ssam 	unit_tab *ui = &vdunit_info[VDUNIT(bp->b_dev)];
714*25675Ssam 
715*25675Ssam 	printf("%s%d%c: soft error sn%d status %x", ui->info.type_name,
716*25675Ssam 	    dkunit(bp), 'a'+(minor(bp->b_dev)&07), bp->b_blkno,
717*25675Ssam 	    dcb->operrsta);
718*25675Ssam 	if (ci->ctlr_type == SMD_ECTLR)
719*25675Ssam 		printf(" ecode %x", dcb->err_code);
720*25675Ssam 	printf("\n");
721*25675Ssam }
722*25675Ssam 
723*25675Ssam /*ARGSUSED*/
724*25675Ssam vdopen(dev, flag)
725*25675Ssam 	dev_t dev;
726*25675Ssam 	int flag;
727*25675Ssam {
728*25675Ssam 	register unit = VDUNIT(dev);
729*25675Ssam 	register struct vba_device *vi = vddinfo[unit];
730*25675Ssam 
731*25675Ssam 	if (vi == 0 || vi->ui_alive == 0 || vi->ui_type >= nvddrv)
732*25675Ssam 		return (ENXIO);
733*25675Ssam 	if (vdunit_info[unit].info.partition[FILSYS(dev)].par_len == 0)
734*25675Ssam 		return (ENXIO);
735*25675Ssam 	return (0);
736*25675Ssam }
737*25675Ssam 
73824004Ssam vdread(dev, uio)
739*25675Ssam 	dev_t dev;
740*25675Ssam 	struct uio *uio;
74124004Ssam {
74224004Ssam 	register int unit = VDUNIT(dev);
743*25675Ssam 	register unit_tab *ui = &vdunit_info[unit];
74424004Ssam 
74524004Ssam 	if (unit >= NFSD)
746*25675Ssam 		return (ENXIO);
747*25675Ssam 	return (physio(vdstrategy, &ui->raw_q_element, dev, B_READ,
748*25675Ssam 	    minphys, uio));
74924004Ssam }
75024004Ssam 
75124004Ssam vdwrite(dev, uio)
752*25675Ssam 	dev_t dev;
753*25675Ssam 	struct uio *uio;
75424004Ssam {
75524004Ssam 	register int unit = VDUNIT(dev);
756*25675Ssam 	register unit_tab *ui = &vdunit_info[unit];
75724004Ssam 
75824004Ssam 	if (unit >= NFSD)
759*25675Ssam 		return (ENXIO);
760*25675Ssam 	return (physio(vdstrategy, &ui->raw_q_element, dev, B_WRITE,
761*25675Ssam 	    minphys, uio));
76224004Ssam }
76324004Ssam 
76424004Ssam /*
765*25675Ssam  * Crash dump.
76624004Ssam  */
767*25675Ssam vddump(dev)
768*25675Ssam 	dev_t dev;
76924004Ssam {
770*25675Ssam 	register int unit = VDUNIT(dev);
771*25675Ssam 	register unit_tab *ui = &vdunit_info[unit];
772*25675Ssam 	register fs_tab *fs = &ui->info;
773*25675Ssam 	register int ctlr = vddinfo[unit]->ui_ctlr;
774*25675Ssam 	register struct vba_ctlr *vba_vdctlr_info = vdminfo[ctlr];
775*25675Ssam 	register int filsys = FILSYS(dev);
776*25675Ssam 	register cdr *addr = (cdr *)(vba_vdctlr_info->um_addr);
777*25675Ssam 	register int cur_blk, blkcount, blocks;
778*25675Ssam 	caddr_t memaddr;
77924004Ssam 
780*25675Ssam 	vdreset_ctlr(addr, ctlr);
78124004Ssam 	blkcount = maxfree - 2;		/* In 1k byte pages */
782*25675Ssam 	if (dumplo + blkcount > fs->partition[filsys].par_len) {
783*25675Ssam 		blkcount = fs->partition[filsys].par_len - dumplo;
784*25675Ssam 		printf("vd%d: Dump truncated to %dMB\n", unit, blkcount/1024);
785*25675Ssam 	}
786*25675Ssam 	cur_blk = fs->partition[filsys].par_start + dumplo;
787*25675Ssam 	memaddr = 0;
78824004Ssam 	while (blkcount > 0) {
789*25675Ssam 		blocks = MIN(blkcount, DUMPSIZE);
790*25675Ssam 		if (!vdwrite_block(addr, ctlr, unit, memaddr, cur_blk, blocks))
791*25675Ssam 			return (EIO);
792*25675Ssam 		blkcount -= blocks;
793*25675Ssam 		memaddr += blocks * NBPG;
794*25675Ssam 		cur_blk += blocks;
79524004Ssam 	}
796*25675Ssam 	return (0);
79724004Ssam }
79824004Ssam 
799*25675Ssam /*
800*25675Ssam  * Write a block to disk during a crash dump.
801*25675Ssam  */
802*25675Ssam vdwrite_block(caddr, ctlr, unit, addr, block, blocks)
803*25675Ssam 	register cdr *caddr;
804*25675Ssam 	register int ctlr, unit;
805*25675Ssam 	register caddr_t addr;
806*25675Ssam 	register int block, blocks;
80724004Ssam {
808*25675Ssam 	register fmt_mdcb *mdcb = &vdctlr_info[ctlr].ctlr_mdcb;
809*25675Ssam 	register fmt_dcb *dcb = &vdctlr_info[ctlr].ctlr_dcb;
810*25675Ssam 	register unit_tab *ui = &vdunit_info[unit];
811*25675Ssam 	register fs_tab	 *fs = &ui->info;
81224004Ssam 
813*25675Ssam 	block *= (int)ui->sec_per_blk;
814*25675Ssam 	blocks *= (int)ui->sec_per_blk;
815*25675Ssam 	mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
816*25675Ssam 	dcb->intflg = NOINT;
817*25675Ssam 	dcb->opcode = WD;
818*25675Ssam 	dcb->operrsta = 0;
819*25675Ssam 	dcb->devselect = (char)(vddinfo[unit])->ui_slave;
820*25675Ssam 	dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long));
821*25675Ssam 	dcb->trail.rwtrail.memadr = addr;
822*25675Ssam 	dcb->trail.rwtrail.wcount = (short)
823*25675Ssam 	    ((blocks * fs->secsize)/ sizeof (short));
824*25675Ssam 	dcb->trail.rwtrail.disk.cylinder = (short)(block / ui->sec_per_cyl);
825*25675Ssam 	dcb->trail.rwtrail.disk.track = (char)((block / fs->nsec) % fs->ntrak);
826*25675Ssam 	dcb->trail.rwtrail.disk.sector = (char)(block % fs->nsec);
827*25675Ssam 	VDDC_ATTENTION(caddr, (fmt_mdcb *)(PHYS(mdcb)),
828*25675Ssam 	    vdctlr_info[ctlr].ctlr_type);
829*25675Ssam 	POLLTILLDONE(caddr, dcb, 5, vdctlr_info[ctlr].ctlr_type);
830*25675Ssam 	if (vdtimeout <= 0) {
831*25675Ssam 		printf(" during dump\n");
832*25675Ssam 		return (0);
833*25675Ssam 	}
834*25675Ssam 	if (dcb->operrsta & HRDERR) {
835*25675Ssam 		printf("vd%d: hard error, status %x\n", unit, dcb->operrsta);
836*25675Ssam 		return (0);
837*25675Ssam 	}
838*25675Ssam 	return (1);
83924004Ssam }
84024004Ssam 
84124004Ssam vdsize(dev)
842*25675Ssam 	dev_t dev;
84324004Ssam {
844*25675Ssam 	struct vba_device *vi = vddinfo[VDUNIT(dev)];
84524004Ssam 
846*25675Ssam 	if (vi == 0 || vi->ui_alive == 0 || vi->ui_type >= nvddrv)
847*25675Ssam 		return (-1);
848*25675Ssam 	return (vdunit_info[VDUNIT(dev)].info.partition[FILSYS(dev)].par_len);
84924004Ssam }
85024004Ssam 
851*25675Ssam /*
852*25675Ssam  * Perform a controller reset.
853*25675Ssam  */
854*25675Ssam vdreset_ctlr(addr, ctlr)
855*25675Ssam 	register cdr *addr;
856*25675Ssam 	register int ctlr;
85724004Ssam {
858*25675Ssam 	register struct buf *cq = &vdminfo[ctlr]->um_tab;
859*25675Ssam 	register struct buf *uq = cq->b_forw;
860*25675Ssam 	register ctlr_tab *ci = &vdctlr_info[ctlr];
861*25675Ssam 
862*25675Ssam 	VDDC_RESET(addr, ci->ctlr_type);
863*25675Ssam 	ci->ctlr_started = 0;
864*25675Ssam 	if (ci->ctlr_type == SMD_ECTLR) {
865*25675Ssam 		addr->cdr_csr = 0;
866*25675Ssam 		addr->mdcb_tcf = AM_ENPDA;
867*25675Ssam 		addr->dcb_tcf = AM_ENPDA;
868*25675Ssam 		addr->trail_tcf = AM_ENPDA;
869*25675Ssam 		addr->data_tcf = AM_ENPDA;
870*25675Ssam 		addr->cdr_ccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
871*25675Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
872*25675Ssam 	}
873*25675Ssam 	if (vdnotrailer(addr, ctlr, 0, INIT, 10) & HRDERR) {
874*25675Ssam 		printf("failed to init\n");
875*25675Ssam 		return (0);
876*25675Ssam 	}
877*25675Ssam 	if (vdnotrailer(addr, ctlr, 0, DIAG, 10) & HRDERR) {
878*25675Ssam 		printf("diagnostic error\n");
879*25675Ssam 		return (0);
880*25675Ssam 	}
881*25675Ssam 	/*  reset all units attached to controller */
882*25675Ssam 	uq = cq->b_forw;
883*25675Ssam 	do {
884*25675Ssam 		reset_drive(addr, ctlr, uq->b_dev, 0);
885*25675Ssam 		uq = uq->b_forw;
886*25675Ssam 	} while (uq != cq->b_forw);
887*25675Ssam 	return (1);
888*25675Ssam }
88924004Ssam 
890*25675Ssam /*
891*25675Ssam  * Perform a reset on a drive.
892*25675Ssam  */
893*25675Ssam reset_drive(addr, ctlr, slave, start)
894*25675Ssam 	register cdr *addr;
895*25675Ssam 	register int ctlr, slave, start;
896*25675Ssam {
897*25675Ssam 	register int type = vdctlr_info[ctlr].unit_type[slave];
898*25675Ssam 
899*25675Ssam 	if (type == UNKNOWN)
900*25675Ssam 		return;
901*25675Ssam 	if (!vdconfigure_drive(addr, ctlr, slave, type, start))
902*25675Ssam 		printf("vd%d: drive %d: couldn't reset\n", ctlr, slave);
903*25675Ssam }
904*25675Ssam 
905*25675Ssam #ifdef notdef
906*25675Ssam /*
907*25675Ssam  * Dump the mdcb and DCB for diagnostic purposes.
908*25675Ssam  */
909*25675Ssam vdprintdcb(lp)
910*25675Ssam 	register long *lp;
911*25675Ssam {
912*25675Ssam 	register int i, dcb, tc;
913*25675Ssam 
914*25675Ssam 	for (dcb = 0; lp; lp = (long *)(*lp), dcb++) {
915*25675Ssam 		lp = (long *)((long)lp | 0xc0000000);
916*25675Ssam 		printf("\nDump of dcb%d@%x:", dcb, lp);
917*25675Ssam 		for (i = 0, tc = lp[3] & 0xff; i < tc+7; i++)
918*25675Ssam 			printf(" %lx", lp[i]);
919*25675Ssam 		printf("\n");
92024004Ssam 	}
921*25675Ssam 	DELAY(1750000);
92224004Ssam }
92324004Ssam #endif
924*25675Ssam #endif
925