xref: /csrg-svn/sys/tahoe/vba/vd.c (revision 30519)
1*30519Ssam /*	vd.c	1.14	87/02/18	*/
224004Ssam 
329564Ssam #include "dk.h"
424004Ssam #if NVD > 0
524004Ssam /*
6*30519Ssam  * Versabus VDDC/SMDE driver.
725675Ssam  */
825675Ssam #include "param.h"
925675Ssam #include "buf.h"
1025675Ssam #include "cmap.h"
1125675Ssam #include "conf.h"
1225675Ssam #include "dir.h"
1329564Ssam #include "dkstat.h"
14*30519Ssam #include "disklabel.h"
1525675Ssam #include "map.h"
16*30519Ssam #include "file.h"
1725675Ssam #include "systm.h"
1825675Ssam #include "user.h"
1925675Ssam #include "vmmac.h"
2025675Ssam #include "proc.h"
2125675Ssam #include "uio.h"
2230370Skarels #include "syslog.h"
2330370Skarels #include "kernel.h"
24*30519Ssam #include "ioctl.h"
2524004Ssam 
2629951Skarels #include "../tahoe/cpu.h"
2729951Skarels #include "../tahoe/mtpr.h"
2829951Skarels #include "../tahoe/pte.h"
2929951Skarels 
3025675Ssam #include "../tahoevba/vbavar.h"
3125928Ssam #include "../tahoevba/vdreg.h"
3224004Ssam 
33*30519Ssam #define	COMPAT_42
34*30519Ssam 
3525925Ssam #define	VDMAXIO		(MAXBPTE*NBPG)
3624004Ssam 
37*30519Ssam #define vdunit(dev)	(minor(dev) >> 3)
38*30519Ssam #define vdpart(dev)	(minor(dev) & 0x07)
39*30519Ssam #define	vdminor(unit,part)	(((unit) << 3) | (part))
4024004Ssam 
4124004Ssam struct	vba_ctlr *vdminfo[NVD];
4229564Ssam struct  vba_device *vddinfo[NDK];
4325675Ssam int	vdprobe(), vdslave(), vdattach(), vddgo();
44*30519Ssam long	vdaddr[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 };
4525675Ssam struct	vba_driver vddriver =
46*30519Ssam   { vdprobe, vdslave, vdattach, vddgo, vdaddr, "dk", vddinfo, "vd", vdminfo };
4724004Ssam 
4824004Ssam /*
49*30519Ssam  * Per-controller state.
50*30519Ssam  */
51*30519Ssam struct vdsoftc {
52*30519Ssam 	u_short	vd_flags;
53*30519Ssam #define	VD_INIT		0x1	/* controller initialized */
54*30519Ssam #define	VD_STARTED	0x2	/* start command issued */
55*30519Ssam #define	VD_DOSEEKS	0x4	/* should overlap seeks */
56*30519Ssam 	u_short	vd_type;	/* controller type */
57*30519Ssam 	u_short	vd_wticks;	/* timeout */
58*30519Ssam 	u_short	vd_offcyl;	/* off cylinder bitmask */
59*30519Ssam 	struct	mdcb vd_mdcb;	/* master command block */
60*30519Ssam 	u_long	vd_mdcbphys;	/* physical address of vd_mdcb */
61*30519Ssam 	struct	dcb vd_dcb;	/* i/o command block */
62*30519Ssam 	u_long	vd_dcbphys;	/* physical address of vd_dcb */
63*30519Ssam 	struct	pte *vd_map;	/* i/o page map */
64*30519Ssam 	caddr_t	vd_utl;		/* mapped i/o space */
65*30519Ssam 	caddr_t	vd_rawbuf;	/* buffer for raw+swap i/o */
66*30519Ssam } vdsoftc[NVD];
67*30519Ssam 
68*30519Ssam /*
6925675Ssam  * Per-drive state.
7025675Ssam  */
71*30519Ssam struct	dksoftc {
72*30519Ssam 	u_short	dk_state;	/* open fsm */
73*30519Ssam 	u_short	dk_openpart;	/* units open on this drive */
74*30519Ssam 	u_short	dk_bshift;	/* shift for * (DEV_BSIZE / sectorsize) XXX */
75*30519Ssam 	u_short	dk_curdaddr;	/* last selected track & sector */
76*30519Ssam 	u_int	dk_curcyl;	/* last selected cylinder */
77*30519Ssam 	struct	dcb dk_dcb;	/* seek command block */
78*30519Ssam 	u_long	dk_dcbphys;	/* physical address of dk_dcb */
79*30519Ssam } dksoftc[NDK];
8024004Ssam 
8124004Ssam /*
82*30519Ssam  * Drive states.  Used during steps of open/initialization.
83*30519Ssam  * States < OPEN (> 0) are transient, during an open operation.
84*30519Ssam  * OPENRAW is used for unabeled disks, to allow format operations.
8525675Ssam  */
86*30519Ssam #define	CLOSED		0		/* disk is closed */
87*30519Ssam #define	WANTOPEN	1		/* open requested, not started */
88*30519Ssam #define	WANTOPENRAW	2		/* open requested, no label */
89*30519Ssam #define	RDLABEL		3		/* reading pack label */
90*30519Ssam #define	OPEN		4		/* intialized and ready */
91*30519Ssam #define	OPENRAW		5		/* open, no label */
9224004Ssam 
93*30519Ssam struct	buf rdkbuf[NDK];	/* raw i/o buffer headers */
94*30519Ssam struct	buf dkutab[NDK];	/* i/o queue headers */
95*30519Ssam struct	disklabel dklabel[NDK];	/* pack labels */
9624004Ssam 
97*30519Ssam #define b_cylin	b_resid
98*30519Ssam #define	b_daddr	b_error
99*30519Ssam 
100*30519Ssam int	vdwstart, vdwatch();
101*30519Ssam 
10224004Ssam /*
10325675Ssam  * See if the controller is really there; if so, initialize it.
10425675Ssam  */
10525857Ssam vdprobe(reg, vm)
10625857Ssam 	caddr_t reg;
10725857Ssam 	struct vba_ctlr *vm;
10825675Ssam {
10925857Ssam 	register br, cvec;		/* must be r12, r11 */
110*30519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)reg;
111*30519Ssam 	struct vdsoftc *vd;
11225857Ssam 
11330370Skarels #ifdef lint
11430370Skarels 	br = 0; cvec = br; br = cvec;
11530370Skarels 	vdintr(0);
11630370Skarels #endif
11725857Ssam 	if (badaddr((caddr_t)reg, 2))
11825675Ssam 		return (0);
119*30519Ssam 	vd = &vdsoftc[vm->um_ctlr];
120*30519Ssam 	vdaddr->vdreset = 0xffffffff;
12125675Ssam 	DELAY(1000000);
122*30519Ssam 	if (vdaddr->vdreset != (unsigned)0xffffffff) {
123*30519Ssam 		vd->vd_type = VDTYPE_VDDC;
124*30519Ssam 		vd->vd_flags &= ~VD_DOSEEKS;
12525675Ssam 		DELAY(1000000);
12625675Ssam 	} else {
127*30519Ssam 		vd->vd_type = VDTYPE_SMDE;
128*30519Ssam 		vd->vd_flags |= VD_DOSEEKS;
129*30519Ssam 		vdaddr->vdrstclr = 0;
13025675Ssam 		DELAY(3000000);
131*30519Ssam 		vdaddr->vdcsr = 0;
132*30519Ssam 		vdaddr->vdtcf_mdcb = AM_ENPDA;
133*30519Ssam 		vdaddr->vdtcf_dcb = AM_ENPDA;
134*30519Ssam 		vdaddr->vdtcf_trail = AM_ENPDA;
135*30519Ssam 		vdaddr->vdtcf_data = AM_ENPDA;
136*30519Ssam 		vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS |
13729921Skarels 		    XMD_32BIT | BSZ_16WRD |
13825925Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
13925675Ssam 	}
140*30519Ssam 	vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb);
141*30519Ssam 	vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb);
142*30519Ssam 	vm->um_addr = reg;		/* XXX */
143*30519Ssam 	if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) {
144*30519Ssam 		printf("vd%d: %s cmd failed\n", vm->um_ctlr,
145*30519Ssam 		    vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
146*30519Ssam 		return (0);
147*30519Ssam 	}
14825925Ssam 	/*
14925950Ssam 	 * Allocate page tables and i/o buffer.
15025925Ssam 	 */
151*30519Ssam 	vbmapalloc(btoc(VDMAXIO)+1, &vd->vd_map, &vd->vd_utl);
152*30519Ssam 	vd->vd_rawbuf = calloc(VDMAXIO);
15325857Ssam 	br = 0x17, cvec = 0xe0 + vm->um_ctlr;	/* XXX */
154*30519Ssam 	return (sizeof (struct vddevice));
15525675Ssam }
15624004Ssam 
15724004Ssam /*
158*30519Ssam  * See if a drive is really there.
159*30519Ssam  *
160*30519Ssam  * Can't read pack label here as various data structures
161*30519Ssam  * aren't setup for doing a read in a straightforward
162*30519Ssam  * manner.  Instead just probe for the drive and leave
163*30519Ssam  * the pack label stuff to the attach routine.
16425675Ssam  */
16525675Ssam vdslave(vi, addr)
16625675Ssam 	register struct vba_device *vi;
167*30519Ssam 	struct vddevice *vdaddr;
16825675Ssam {
169*30519Ssam 	register struct disklabel *lp = &dklabel[vi->ui_unit];
170*30519Ssam 	struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
17124004Ssam 
172*30519Ssam 	if ((vd->vd_flags&VD_INIT) == 0) {
17325925Ssam 		printf("vd%d: %s controller\n", vi->ui_ctlr,
174*30519Ssam 		    vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE");
175*30519Ssam 		vd->vd_flags |= VD_INIT;
17625675Ssam 	}
177*30519Ssam 
17825675Ssam 	/*
179*30519Ssam 	 * Initialize label enough to do a reset on
180*30519Ssam 	 * the drive.  The remainder of the default
181*30519Ssam 	 * label values will be filled in in vdinit
182*30519Ssam 	 * at attach time.
18325675Ssam 	 */
184*30519Ssam 	lp->d_secsize = DEV_BSIZE / 2;		/* XXX */
185*30519Ssam 	lp->d_nsectors = 32;
186*30519Ssam 	lp->d_ntracks = 24;
187*30519Ssam 	lp->d_ncylinders = 711;
188*30519Ssam 	lp->d_secpercyl = 32*24;
189*30519Ssam 	return (vdreset_drive(vi));
19024004Ssam }
19124004Ssam 
192*30519Ssam /*
193*30519Ssam  * Read pack label.
194*30519Ssam  */
195*30519Ssam vdattach(vi)
196*30519Ssam 	register struct vba_device *vi;
19724004Ssam {
198*30519Ssam 	register int unit = vi->ui_unit;
199*30519Ssam 	register struct dksoftc *dk = &dksoftc[unit];
200*30519Ssam 	register struct disklabel *lp;
20125675Ssam 
202*30519Ssam 	if (vdwstart == 0) {
203*30519Ssam 		timeout(vdwatch, (caddr_t)0, hz);
204*30519Ssam 		vdwstart++;
20525675Ssam 	}
206*30519Ssam 	/*
207*30519Ssam 	 * Try to initialize device and read pack label.
208*30519Ssam 	 */
209*30519Ssam 	if (vdinit(vdminor(unit, 0), 0) != 0) {
210*30519Ssam 		printf(": unknown drive type");
211*30519Ssam 		return;
21225675Ssam 	}
213*30519Ssam 	/*
214*30519Ssam 	 * Initialize invariant portion of
215*30519Ssam 	 * dcb used for overlapped seeks.
216*30519Ssam 	 */
217*30519Ssam 	dk->dk_dcb.opcode = VDOP_SEEK;
218*30519Ssam 	dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA;
219*30519Ssam 	dk->dk_dcb.devselect = vi->ui_slave;
220*30519Ssam 	dk->dk_dcb.trailcnt = sizeof (trseek) / sizeof (long);
221*30519Ssam 	dk->dk_dcb.trail.sktrail.skaddr.sector = 0;
222*30519Ssam 	dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb);
223*30519Ssam 	lp = &dklabel[unit];
224*30519Ssam 	printf(": %s <ntrak %d, ncyl %d, nsec %d>",
225*30519Ssam 	    lp->d_typename, lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors);
226*30519Ssam 	/*
227*30519Ssam 	 * (60 / rpm) / (sectors per track * (bytes per sector / 2))
228*30519Ssam 	 */
229*30519Ssam 	if (vi->ui_dk >= 0)
230*30519Ssam 		dk_mspw[vi->ui_dk] = 120.0 /
231*30519Ssam 		    (lp->d_rpm * lp->d_nsectors * lp->d_secsize);
232*30519Ssam #ifdef notyet
233*30519Ssam 	addwap(makedev(VDMAJOR, vdminor(unit, 0)), &dklabel[unit]);
234*30519Ssam #endif
23524004Ssam }
23624004Ssam 
237*30519Ssam /*ARGSUSED*/
238*30519Ssam vdopen(dev, flags)
239*30519Ssam 	dev_t dev;
240*30519Ssam 	int flags;
24124004Ssam {
242*30519Ssam 	register unit = vdunit(dev);
243*30519Ssam 	register struct disklabel *lp;
244*30519Ssam 	register struct dksoftc *dk;
245*30519Ssam 	register struct partition *pp;
246*30519Ssam 	struct vba_device *vi;
247*30519Ssam 	int s, error, part = vdpart(dev);
248*30519Ssam 	daddr_t start, end;
24924004Ssam 
250*30519Ssam 	if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
251*30519Ssam 		return (ENXIO);
252*30519Ssam 	lp = &dklabel[unit];
253*30519Ssam 	dk = &dksoftc[unit];
254*30519Ssam 
255*30519Ssam 	s = spl7();
256*30519Ssam 	while (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
257*30519Ssam 	    dk->dk_state != CLOSED)
258*30519Ssam 		sleep((caddr_t)dk, PZERO+1);
259*30519Ssam 	splx(s);
260*30519Ssam 	if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
261*30519Ssam 		if (error = vdinit(dev, flags))
262*30519Ssam 			return (error);
263*30519Ssam 	/*
264*30519Ssam 	 * Warn if a partion is opened
265*30519Ssam 	 * that overlaps another partition which is open
266*30519Ssam 	 * unless one is the "raw" partition (whole disk).
267*30519Ssam 	 */
268*30519Ssam #define	RAWPART		2		/* 'c' partition */	/* XXX */
269*30519Ssam 	if ((dk->dk_openpart & (1 << part)) == 0 &&
270*30519Ssam 	    part != RAWPART) {
271*30519Ssam 		pp = &lp->d_partitions[part];
272*30519Ssam 		start = pp->p_offset;
273*30519Ssam 		end = pp->p_offset + pp->p_size;
274*30519Ssam 		for (pp = lp->d_partitions;
275*30519Ssam 		     pp < &lp->d_partitions[lp->d_npartitions]; pp++) {
276*30519Ssam 			if (pp->p_offset + pp->p_size <= start ||
277*30519Ssam 			    pp->p_offset >= end)
278*30519Ssam 				continue;
279*30519Ssam 			if (pp - lp->d_partitions == RAWPART)
280*30519Ssam 				continue;
281*30519Ssam 			if (dk->dk_openpart & (1 << (pp - lp->d_partitions)))
282*30519Ssam 				log(LOG_WARNING,
283*30519Ssam 				    "dk%d%c: overlaps open partition (%c)\n",
284*30519Ssam 				    unit, part + 'a',
285*30519Ssam 				    pp - lp->d_partitions + 'a');
286*30519Ssam 		}
28724004Ssam 	}
288*30519Ssam 	if (part >= lp->d_npartitions)
289*30519Ssam 		return (ENXIO);
290*30519Ssam 	dk->dk_openpart |= 1 << part;
291*30519Ssam 	return (0);
29225675Ssam }
29324004Ssam 
294*30519Ssam vdclose(dev, flags)
295*30519Ssam 	dev_t dev;
296*30519Ssam 	int flags;
29724004Ssam {
298*30519Ssam 	register int unit = vdunit(dev);
299*30519Ssam 	register struct dksoftc *dk = &dksoftc[unit];
30024004Ssam 
301*30519Ssam 	dk->dk_openpart &= ~(1 << vdpart(dev));
302*30519Ssam #ifdef notdef
303*30519Ssam 	/*
304*30519Ssam 	 * Should wait for i/o to complete on this partition
305*30519Ssam 	 * even if others are open, but wait for work on blkflush().
306*30519Ssam 	 */
307*30519Ssam 	if (dk->dk_openpart == 0) {
308*30519Ssam 		struct vba_device *vi = vddinfo[unit];
309*30519Ssam 		int s;
310*30519Ssam 
311*30519Ssam 		s = spl7();
312*30519Ssam 		/* can't sleep on b_actf, it might be async. */
313*30519Ssam 		while (vi->ui_tab.b_actf)
314*30519Ssam 			sleep((caddr_t)&vi->ui_tab.b_actf, PZERO-1);
315*30519Ssam 		splx(s);
316*30519Ssam 		dk->dk_state = CLOSED;
31724004Ssam 	}
318*30519Ssam #endif
31925675Ssam }
32024004Ssam 
321*30519Ssam vdinit(dev, flags)
322*30519Ssam 	dev_t dev;
323*30519Ssam 	int flags;
32425675Ssam {
325*30519Ssam 	register struct buf *bp = NULL;
326*30519Ssam 	register struct disklabel *lp;
327*30519Ssam 	register struct dksoftc *dk;
328*30519Ssam 	struct vba_device *vi;
329*30519Ssam 	struct disklabel *dlp;
330*30519Ssam 	int unit = vdunit(dev), error = 0;
331*30519Ssam 	extern int cold;
33225675Ssam 
333*30519Ssam 	dk = &dksoftc[unit];
334*30519Ssam 	if (flags & O_NDELAY) {
335*30519Ssam 		dk->dk_state = OPENRAW;
336*30519Ssam 		goto done;
337*30519Ssam 	}
338*30519Ssam 
339*30519Ssam 	/*
340*30519Ssam 	 * Initialize portion of the label
341*30519Ssam 	 * not set up in the slave routine.
342*30519Ssam 	 */
343*30519Ssam 	dk->dk_bshift = 1;		/* DEV_BSIZE / 512 */
344*30519Ssam 	dk->dk_state = RDLABEL;
345*30519Ssam 	lp = &dklabel[unit];
346*30519Ssam 	lp->d_secperunit = 0x1fffffff;
347*30519Ssam 	lp->d_npartitions = 1;
348*30519Ssam 	lp->d_partitions[0].p_size = 0x1fffffff;
349*30519Ssam 	lp->d_partitions[0].p_offset = 0;
350*30519Ssam 
351*30519Ssam 	bp = geteblk(DEV_BSIZE);		/* max sector size */
352*30519Ssam 	bp->b_dev = dev;
353*30519Ssam 	bp->b_blkno = LABELSECTOR;
354*30519Ssam 	bp->b_bcount = DEV_BSIZE;
355*30519Ssam 	bp->b_flags = B_BUSY | B_READ;
356*30519Ssam 	bp->b_cylin = LABELSECTOR / lp->d_secpercyl;
357*30519Ssam 	vdstrategy(bp);
358*30519Ssam 	biowait(bp);
359*30519Ssam 	if (bp->b_flags & B_ERROR) {
360*30519Ssam 		error = u.u_error;		/* XXX */
361*30519Ssam 		u.u_error = 0;
362*30519Ssam 		dk->dk_state = CLOSED;
363*30519Ssam 		goto done;
364*30519Ssam 	}
365*30519Ssam 	vi = vddinfo[unit];
366*30519Ssam 	dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET);
367*30519Ssam 	if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
368*30519Ssam 	    dkcksum(dlp) == 0) {
369*30519Ssam 		*lp = *dlp;
370*30519Ssam 		/*
371*30519Ssam 		 * Now that we have the label, configure
372*30519Ssam 		 * the correct drive parameters.
373*30519Ssam 		 */
374*30519Ssam 		if (!vdreset_drive(vi))
375*30519Ssam 			dk->dk_state = CLOSED;
376*30519Ssam 		else
377*30519Ssam 			dk->dk_state = OPEN;
37825675Ssam 	} else {
379*30519Ssam 		if (cold)
380*30519Ssam 			printf(": no disk label");
381*30519Ssam 		else
382*30519Ssam 			log(LOG_ERR, "dk%d: no disk label\n", vi->ui_unit);
383*30519Ssam #ifdef COMPAT_42
384*30519Ssam 		if (!vdmaptype(vi, lp)) {
385*30519Ssam 			error = ENXIO;
386*30519Ssam 			dk->dk_state = CLOSED;
387*30519Ssam 		} else
388*30519Ssam 			dk->dk_state = OPEN;
389*30519Ssam #else
390*30519Ssam 		dk->dk_state = OPENRAW;
391*30519Ssam #endif
39225675Ssam 	}
393*30519Ssam done:
39424004Ssam 	/*
395*30519Ssam 	 * If open, calculate scaling shift for
396*30519Ssam 	 * mapping DEV_BSIZE blocks to drive sectors.
39724004Ssam 	 */
398*30519Ssam 	if (dk->dk_state == OPEN || dk->dk_state == OPENRAW) {
399*30519Ssam 		int mul = DEV_BSIZE / lp->d_secsize;
400*30519Ssam 		dk->dk_bshift = 0;
401*30519Ssam 		while ((mul >>= 1) > 0)
402*30519Ssam 			dk->dk_bshift++;
403*30519Ssam 	}
404*30519Ssam 	if (bp) {
405*30519Ssam 		bp->b_flags = B_INVAL | B_AGE;
406*30519Ssam 		brelse(bp);
407*30519Ssam 	}
408*30519Ssam 	wakeup((caddr_t)dk);
409*30519Ssam 	return (error);
41024004Ssam }
41124004Ssam 
41225675Ssam /*ARGSUSED*/
413*30519Ssam vddgo(vm)
414*30519Ssam 	struct vba_device *vm;
41524004Ssam {
41624004Ssam 
41724004Ssam }
41824004Ssam 
41924004Ssam vdstrategy(bp)
42025675Ssam 	register struct buf *bp;
42124004Ssam {
422*30519Ssam 	register struct vba_device *vi;
423*30519Ssam 	register struct disklabel *lp;
424*30519Ssam 	register struct dksoftc *dk;
425*30519Ssam 	register int unit;
426*30519Ssam 	struct buf *dp;
427*30519Ssam 	daddr_t sz, sn, maxsz;
428*30519Ssam 	int part, s;
42924004Ssam 
430*30519Ssam 	sz = bp->b_bcount;
431*30519Ssam 	sz = (sz + DEV_BSIZE - 1) >> DEV_BSHIFT;
432*30519Ssam 	unit = vdunit(bp->b_dev);
433*30519Ssam 	if (unit > NDK) {
43429954Skarels 		bp->b_error = ENXIO;
43525675Ssam 		goto bad;
43629954Skarels 	}
437*30519Ssam 	vi = vddinfo[unit];
438*30519Ssam 	lp = &dklabel[unit];
439*30519Ssam 	if (vi == 0 || vi->ui_alive == 0) {
440*30519Ssam 		bp->b_error = ENXIO;
441*30519Ssam 		goto bad;
442*30519Ssam 	}
443*30519Ssam 	dk = &dksoftc[unit];
444*30519Ssam 	if (dk->dk_state < OPEN)
445*30519Ssam 		goto q;
446*30519Ssam 	part = vdpart(bp->b_dev);
447*30519Ssam 	if ((dk->dk_openpart & (1 << part)) == 0) {
448*30519Ssam 		bp->b_error = ENODEV;
449*30519Ssam 		goto bad;
450*30519Ssam 	}
451*30519Ssam 	maxsz = lp->d_partitions[part].p_size;
452*30519Ssam 	sn = bp->b_blkno << dk->dk_bshift;
453*30519Ssam 	if (sn < 0 || sn + sz > maxsz) {
454*30519Ssam 		if (sn == maxsz) {
45529954Skarels 			bp->b_resid = bp->b_bcount;
45629954Skarels 			goto done;
45729954Skarels 		}
458*30519Ssam 		bp->b_error = EINVAL;
459*30519Ssam 		goto bad;
46025675Ssam 	}
461*30519Ssam 	bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl;
462*30519Ssam q:
463*30519Ssam 	vbasetup(bp, lp->d_secsize);
46425675Ssam 	s = spl7();
465*30519Ssam 	dp = &dkutab[vi->ui_unit];
466*30519Ssam 	disksort(dp, bp);
467*30519Ssam 	if (!dp->b_active) {
468*30519Ssam 		(void) vdustart(vi);
469*30519Ssam 		bp = &vi->ui_mi->um_tab;
470*30519Ssam 		if (bp->b_actf && !bp->b_active)
471*30519Ssam 			vdstart(vi->ui_mi);
47224004Ssam 	}
473*30519Ssam 	splx(s);
47424004Ssam 	return;
47525675Ssam bad:
47629954Skarels 	bp->b_flags |= B_ERROR;
47729954Skarels done:
478*30519Ssam 	biodone(bp);
479*30519Ssam 	return;
48024004Ssam }
48124004Ssam 
482*30519Ssam vdustart(vi)
483*30519Ssam 	register struct vba_device *vi;
48424004Ssam {
485*30519Ssam 	register struct buf *bp, *dp;
486*30519Ssam 	register struct vba_ctlr *vm;
487*30519Ssam 	register int unit = vi->ui_unit;
488*30519Ssam 	register struct dksoftc *dk;
489*30519Ssam 	register struct vdsoftc *vd;
490*30519Ssam 	struct disklabel *lp;
49124004Ssam 
492*30519Ssam 	dk_busy &= ~(1<<vi->ui_dk);
493*30519Ssam 	dp = &dkutab[unit];
494*30519Ssam 	/*
495*30519Ssam 	 * If queue empty, nothing to do.
496*30519Ssam 	 */
497*30519Ssam 	if ((bp = dp->b_actf) == NULL)
498*30519Ssam 		return;
499*30519Ssam 	/*
500*30519Ssam 	 * If drive is off-cylinder, mark unit to force
501*30519Ssam 	 * overlap seek with next transfer on this controller.
502*30519Ssam 	 */
503*30519Ssam 	vd = &vdsoftc[vi->ui_ctlr];
504*30519Ssam 	dk = &dksoftc[unit];
505*30519Ssam 	if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) {
506*30519Ssam 		int sn = bp->b_blkno << dk->dk_bshift;
507*30519Ssam 		lp = &dklabel[unit];
508*30519Ssam 		bp->b_daddr = (sn % lp->d_secpercyl) / lp->d_nsectors;
509*30519Ssam 		if (bp->b_daddr != dk->dk_curdaddr)
510*30519Ssam 			vd->vd_offcyl |= 1 << vi->ui_slave;
511*30519Ssam 	}
512*30519Ssam 	/*
513*30519Ssam 	 * If controller is not busy, place request on the
514*30519Ssam 	 * controller's ready queue (unless its already there).
515*30519Ssam 	 */
516*30519Ssam 	if (!dp->b_active) {
517*30519Ssam 		dp->b_forw = NULL;
518*30519Ssam 		vm = vi->ui_mi;
519*30519Ssam 		if (vm->um_tab.b_actf == NULL)
520*30519Ssam 			vm->um_tab.b_actf = dp;
521*30519Ssam 		else
522*30519Ssam 			vm->um_tab.b_actl->b_forw = dp;
523*30519Ssam 		vm->um_tab.b_actl = dp;
524*30519Ssam 		dp->b_active++;
525*30519Ssam 	}
52625675Ssam }
52725675Ssam 
52825675Ssam /*
529*30519Ssam  * Start next transfer on a controller.
53025675Ssam  */
531*30519Ssam vdstart(vm)
532*30519Ssam 	register struct vba_ctlr *vm;
53325675Ssam {
53425675Ssam 	register struct buf *bp;
535*30519Ssam 	register struct vba_device *vi;
536*30519Ssam 	register struct vdsoftc *vd;
537*30519Ssam 	register struct dksoftc *dk;
538*30519Ssam 	register struct disklabel *lp;
539*30519Ssam 	register int slave;
540*30519Ssam 	register struct dcb **dcbp;
541*30519Ssam 	struct mdcb *mdcb;
542*30519Ssam 	struct buf *dp;
543*30519Ssam 	int sn, tn;
54425675Ssam 
545*30519Ssam loop:
546*30519Ssam 	/*
547*30519Ssam 	 * Pull a request off the controller queue.
548*30519Ssam 	 */
549*30519Ssam 	if ((dp = vm->um_tab.b_actf) == NULL)
550*30519Ssam 		return;
551*30519Ssam 	if ((bp = dp->b_actf) == NULL) {
552*30519Ssam 		vm->um_tab.b_actf = dp->b_forw;
553*30519Ssam 		goto loop;
554*30519Ssam 	}
55525675Ssam 
55624004Ssam 	/*
557*30519Ssam 	 * Mark controller busy, and determine
558*30519Ssam 	 * destination of this request.
55924004Ssam 	 */
560*30519Ssam 	vm->um_tab.b_active++;
561*30519Ssam 	vi = vddinfo[vdunit(bp->b_dev)];
562*30519Ssam 	dk = &dksoftc[vi->ui_unit];
563*30519Ssam 	sn = bp->b_blkno << dk->dk_bshift;
564*30519Ssam 	lp = &dklabel[vi->ui_unit];
565*30519Ssam 	sn %= lp->d_secpercyl;
566*30519Ssam 	tn = sn / lp->d_nsectors;
567*30519Ssam 	sn %= lp->d_nsectors;
568*30519Ssam 
569*30519Ssam 	/*
570*30519Ssam 	 * Construct dcb for read/write command.
571*30519Ssam 	 */
572*30519Ssam 	vd = &vdsoftc[vm->um_ctlr];
573*30519Ssam 	slave = vi->ui_slave;
574*30519Ssam 	vd->vd_dcb.opcode = (bp->b_flags & B_READ) ? VDOP_RD : VDOP_WD;
575*30519Ssam 	vd->vd_dcb.intflg = DCBINT_DONE;
576*30519Ssam 	vd->vd_dcb.devselect = slave;
577*30519Ssam 	vd->vd_dcb.operrsta = 0;
578*30519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
579*30519Ssam 	vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long);
580*30519Ssam 	vd->vd_dcb.trail.rwtrail.memadr = (char *)
581*30519Ssam 	    vbastart(bp, vd->vd_rawbuf, (long *)vd->vd_map, vd->vd_utl);
582*30519Ssam 	vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1;
583*30519Ssam 	vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin;
584*30519Ssam 	vd->vd_dcb.trail.rwtrail.disk.track = tn;
585*30519Ssam 	vd->vd_dcb.trail.rwtrail.disk.sector = sn;
586*30519Ssam 
587*30519Ssam 	/*
588*30519Ssam 	 * Look for any seeks to be performed on other drives on this
589*30519Ssam 	 * controller.  If overlapped seeks exist, insert seek commands
590*30519Ssam 	 * on the controller's command queue before the transfer.
591*30519Ssam 	 */
592*30519Ssam 	dcbp = &vd->vd_mdcb.mdcb_head;
593*30519Ssam 	if (vd->vd_offcyl &~ (1<<slave)) {
594*30519Ssam 		register struct dksoftc *tdk;
595*30519Ssam 		register struct buf *tp;
596*30519Ssam 
597*30519Ssam 		for (dp = dp->b_forw; dp != NULL; dp = dp->b_forw) {
598*30519Ssam 			if ((tp = dp->b_actf) == NULL)
599*30519Ssam 				continue;
600*30519Ssam 			slave = (vi = vddinfo[vdunit(tp->b_dev)])->ui_slave;
601*30519Ssam 			if ((vd->vd_offcyl & (1<<slave)) == 0)
602*30519Ssam 				continue;
603*30519Ssam 			vd->vd_offcyl &= ~(1 << slave);
604*30519Ssam 			tdk = &dksoftc[vi->ui_unit];
605*30519Ssam 			if (tdk->dk_curcyl != tp->b_cylin) {
606*30519Ssam 				tdk->dk_curcyl = tp->b_cylin;
607*30519Ssam 				dk_seek[vi->ui_dk]++;
608*30519Ssam 			}
609*30519Ssam 			tdk->dk_curdaddr = tp->b_daddr;
610*30519Ssam 			tdk->dk_dcb.operrsta = 0;
611*30519Ssam 			tdk->dk_dcb.trail.sktrail.skaddr.cylinder = tp->b_cylin;
612*30519Ssam 			tdk->dk_dcb.trail.sktrail.skaddr.track = tp->b_daddr>>8;
613*30519Ssam 			tdk->dk_dcb.trail.sktrail.skaddr.sector =
614*30519Ssam 			    tp->b_daddr & 0xff;
615*30519Ssam 			*dcbp = (struct dcb *)tdk->dk_dcbphys;
616*30519Ssam 			dcbp = &tdk->dk_dcb.nxtdcb;
617*30519Ssam 		}
61825675Ssam 	} else {
619*30519Ssam 		dk->dk_curcyl = bp->b_cylin;
620*30519Ssam 		dk->dk_curdaddr = (tn << 8) | sn;
621*30519Ssam 		vd->vd_offcyl = 0;
62224004Ssam 	}
623*30519Ssam 	*dcbp = (struct dcb *)vd->vd_dcbphys;
62424004Ssam 
625*30519Ssam 	/*
626*30519Ssam 	 * Initiate operation.
627*30519Ssam 	 */
628*30519Ssam 	bp->b_daddr = 0;		/* init overloaded field */
629*30519Ssam 	if (vi->ui_dk >= 0) {
630*30519Ssam 		dk_busy |= 1<<vi->ui_dk;
631*30519Ssam 		dk_xfer[vi->ui_dk]++;
632*30519Ssam 		dk_wds[vi->ui_dk] += bp->b_bcount>>6;
63324004Ssam 	}
634*30519Ssam 	vd->vd_mdcb.mdcb_status = 0;
635*30519Ssam 	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
63624004Ssam }
63724004Ssam 
638*30519Ssam #define	DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE)
63924004Ssam /*
64024004Ssam  * Handle a disk interrupt.
64124004Ssam  */
64225675Ssam vdintr(ctlr)
643*30519Ssam 	register ctlr;
64424004Ssam {
645*30519Ssam 	register struct buf *bp, *dp;
646*30519Ssam 	register struct vba_ctlr *vm = vdminfo[ctlr];
647*30519Ssam 	register struct vba_device *vi;
648*30519Ssam 	register struct vdsoftc *vd = &vdsoftc[ctlr];
649*30519Ssam 	register status;
65024004Ssam 
651*30519Ssam 	vd->vd_wticks = 0;
652*30519Ssam 	if (!vm->um_tab.b_active) {
65325675Ssam 		printf("vd%d: stray interrupt\n", ctlr);
65424004Ssam 		return;
65524004Ssam 	}
65625675Ssam 	/*
657*30519Ssam 	 * Get device and block structures, and a pointer
658*30519Ssam 	 * to the vba_device for the drive.
65925675Ssam 	 */
660*30519Ssam 	dp = vm->um_tab.b_actf;
661*30519Ssam 	bp = dp->b_actf;
662*30519Ssam 	vi = vddinfo[vdunit(bp->b_dev)];
663*30519Ssam 	dk_busy &= ~(1<<vi->ui_dk);
664*30519Ssam 	/*
665*30519Ssam 	 * Check for and process errors on
666*30519Ssam 	 * either the drive or the controller.
667*30519Ssam 	 */
668*30519Ssam 	uncache(&vd->vd_dcb.operrsta);
669*30519Ssam 	status = vd->vd_dcb.operrsta;
670*30519Ssam 	if (status & VDERR_HARD) {
671*30519Ssam 		if (status & DCBS_WPT) {
672*30519Ssam 			/*
673*30519Ssam 			 * Give up on write locked devices immediately.
674*30519Ssam 			 */
675*30519Ssam 			printf("dk%d: write locked\n", vdunit(bp->b_dev));
676*30519Ssam 			bp->b_flags |= B_ERROR;
677*30519Ssam 		} else if (status & VDERR_SOFT) {
678*30519Ssam 			if (status & VDERR_DRIVE) {
679*30519Ssam 				if (!vdreset_drive(vi))
680*30519Ssam 					vi->ui_alive = 0;
681*30519Ssam 			} else if (status & VDERR_CTLR)
682*30519Ssam 				vdreset_ctlr(vm);
683*30519Ssam 			/*
684*30519Ssam 			 * Retry transfer once, unless reset failed.
685*30519Ssam 			 */
686*30519Ssam 			if (!vi->ui_alive || bp->b_errcnt++ >= 2)
687*30519Ssam 				goto hard;
688*30519Ssam 			vm->um_tab.b_active = 0;	/* force retry */
689*30519Ssam 		} else  {
690*30519Ssam 	hard:
691*30519Ssam 			bp->b_flags |= B_ERROR;
692*30519Ssam 			/* NEED TO ADJUST b_blkno to failed sector */
693*30519Ssam 			harderr(bp, "dk");
694*30519Ssam 			printf("status %x (%b)", status,
695*30519Ssam 			   status &~ DONTCARE, VDERRBITS);
696*30519Ssam 			if (vd->vd_type == VDTYPE_SMDE) {
697*30519Ssam 				uncache(&vd->vd_dcb.err_code);
698*30519Ssam 				printf(" ecode %x", vd->vd_dcb.err_code);
699*30519Ssam 			}
700*30519Ssam 			printf("\n");
701*30519Ssam 		}
702*30519Ssam 	} else if (status & DCBS_SOFT)
703*30519Ssam 		vdsofterr(vd, bp, &vd->vd_dcb);
704*30519Ssam 	if (vm->um_tab.b_active) {
705*30519Ssam 		vm->um_tab.b_active = 0;
706*30519Ssam 		vm->um_tab.b_errcnt = 0;
707*30519Ssam 		vm->um_tab.b_actf = dp->b_forw;
708*30519Ssam 		dp->b_active = 0;
709*30519Ssam 		dp->b_errcnt = 0;
710*30519Ssam 		dp->b_actf = bp->av_forw;
711*30519Ssam 		bp->b_resid = 0;
712*30519Ssam 		vbadone(bp, vd->vd_rawbuf, (long *)vd->vd_map, vd->vd_utl);
713*30519Ssam 		biodone(bp);
71430370Skarels 		/*
715*30519Ssam 		 * If this unit has more work to do,
716*30519Ssam 		 * then start it up right away.
71730370Skarels 		 */
718*30519Ssam 		if (dp->b_actf)
719*30519Ssam 			vdustart(vi);
72024004Ssam 	}
72125675Ssam 	/*
722*30519Ssam 	 * If there are devices ready to
723*30519Ssam 	 * transfer, start the controller.
72425675Ssam 	 */
725*30519Ssam 	if (vm->um_tab.b_actf)
726*30519Ssam 		vdstart(vm);
72724004Ssam }
72824004Ssam 
729*30519Ssam vdsofterr(vd, bp, dcb)
730*30519Ssam 	struct vdsoftc *vd;
73125675Ssam 	register struct buf *bp;
732*30519Ssam 	register struct dcb *dcb;
73325675Ssam {
734*30519Ssam 	int unit = vdunit(bp->b_dev), status = dcb->operrsta;
735*30519Ssam 	char part = 'a' + vdpart(bp->b_dev);
73625675Ssam 
737*30519Ssam 	if (status != (DCBS_DCE|DCBS_CCD|DCBS_SOFT|DCBS_ERR)) {
738*30519Ssam 		if (vd->vd_type == VDTYPE_SMDE)
739*30519Ssam 			uncache(&dcb->err_code);
740*30519Ssam 		log(LOG_WARNING, "dk%d%c: soft error sn%d status %b ecode %x\n",
741*30519Ssam 		    unit, part, bp->b_blkno, status, VDERRBITS, dcb->err_code);
742*30519Ssam 	} else
74330370Skarels 		log(LOG_WARNING, "dk%d%c: soft ecc sn%d\n",
74430370Skarels 		    unit, part, bp->b_blkno);
74525675Ssam }
74625675Ssam 
74724004Ssam vdread(dev, uio)
74825675Ssam 	dev_t dev;
74925675Ssam 	struct uio *uio;
75024004Ssam {
751*30519Ssam 	register int unit = vdunit(dev);
75224004Ssam 
75329564Ssam 	if (unit >= NDK)
75425675Ssam 		return (ENXIO);
755*30519Ssam 	return (physio(vdstrategy, &rdkbuf[unit], dev, B_READ, minphys, uio));
75624004Ssam }
75724004Ssam 
75824004Ssam vdwrite(dev, uio)
75925675Ssam 	dev_t dev;
76025675Ssam 	struct uio *uio;
76124004Ssam {
762*30519Ssam 	register int unit = vdunit(dev);
76324004Ssam 
76429564Ssam 	if (unit >= NDK)
76525675Ssam 		return (ENXIO);
766*30519Ssam 	return (physio(vdstrategy, &rdkbuf[unit], dev, B_WRITE, minphys, uio));
76724004Ssam }
76824004Ssam 
769*30519Ssam vdioctl(dev, cmd, data, flag)
77025675Ssam 	dev_t dev;
771*30519Ssam 	int cmd;
772*30519Ssam 	caddr_t data;
773*30519Ssam 	int flag;
77424004Ssam {
775*30519Ssam 	int unit = vdunit(dev);
776*30519Ssam 	register struct disklabel *lp = &dklabel[unit];
777*30519Ssam 	int error = 0;
77824004Ssam 
779*30519Ssam 	switch (cmd) {
780*30519Ssam 
781*30519Ssam 	case DIOCGDINFO:
782*30519Ssam 		*(struct disklabel *)data = *lp;
783*30519Ssam 		break;
784*30519Ssam 
785*30519Ssam 	case DIOCGDINFOP:
786*30519Ssam 		*(struct disklabel **)data = lp;
787*30519Ssam 		break;
788*30519Ssam 
789*30519Ssam 	case DIOCSDINFO:
790*30519Ssam 		if ((flag & FWRITE) == 0)
791*30519Ssam 			error = EBADF;
792*30519Ssam 		else
793*30519Ssam 			*lp = *(struct disklabel *)data;
794*30519Ssam 		break;
795*30519Ssam 
796*30519Ssam 	case DIOCWDINFO: {
797*30519Ssam 		struct buf *bp;
798*30519Ssam 		struct disklabel *dlp;
799*30519Ssam 
800*30519Ssam 		if ((flag & FWRITE) == 0) {
801*30519Ssam 			error = EBADF;
802*30519Ssam 			break;
803*30519Ssam 		}
804*30519Ssam 		*lp = *(struct disklabel *)data;
805*30519Ssam 		bp = geteblk(lp->d_secsize);
806*30519Ssam 		bp->b_dev = dev;
807*30519Ssam 		bp->b_blkno = LABELSECTOR;
808*30519Ssam 		bp->b_bcount = lp->d_secsize;
809*30519Ssam 		bp->b_flags = B_READ;
810*30519Ssam 		dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET);
811*30519Ssam 		vdstrategy(bp);
812*30519Ssam 		biowait(bp);
813*30519Ssam 		if (bp->b_flags & B_ERROR) {
814*30519Ssam 			error = u.u_error;		/* XXX */
815*30519Ssam 			u.u_error = 0;
816*30519Ssam 			goto bad;
817*30519Ssam 		}
818*30519Ssam 		*dlp = *lp;
819*30519Ssam 		bp->b_flags = B_WRITE;
820*30519Ssam 		vdstrategy(bp);
821*30519Ssam 		biowait(bp);
822*30519Ssam 		if (bp->b_flags & B_ERROR) {
823*30519Ssam 			error = u.u_error;		/* XXX */
824*30519Ssam 			u.u_error = 0;
825*30519Ssam 		}
826*30519Ssam bad:
827*30519Ssam 		brelse(bp);
828*30519Ssam 		break;
82925675Ssam 	}
830*30519Ssam 
831*30519Ssam 	default:
832*30519Ssam 		error = ENOTTY;
833*30519Ssam 		break;
83424004Ssam 	}
83525675Ssam 	return (0);
83624004Ssam }
83724004Ssam 
83825675Ssam /*
839*30519Ssam  * Watch for lost interrupts.
84025675Ssam  */
841*30519Ssam vdwatch()
842*30519Ssam {
843*30519Ssam 	register struct vdsoftc *vd;
844*30519Ssam 	register struct vba_ctlr *vm;
84525675Ssam 	register int ctlr, unit;
846*30519Ssam 
847*30519Ssam 	timeout(vdwatch, (caddr_t)0, hz);
848*30519Ssam 	for (ctlr = 0; ctlr < NVD; ctlr++) {
849*30519Ssam 		vm = vdminfo[ctlr];
850*30519Ssam 		if (vm == 0 || vm->um_alive == 0)
851*30519Ssam 			continue;
852*30519Ssam 		vd = &vdsoftc[ctlr];
853*30519Ssam 		if (!vm->um_tab.b_active) {
854*30519Ssam 			for (unit = 0; unit < NDK; unit++)
855*30519Ssam 				if (dkutab[unit].b_active &&
856*30519Ssam 				    vddinfo[unit]->ui_mi == vm)
857*30519Ssam 					goto active;
858*30519Ssam 			vd->vd_wticks = 0;
859*30519Ssam 			continue;
860*30519Ssam 		}
861*30519Ssam active:
862*30519Ssam 		vd->vd_wticks++;
863*30519Ssam 		if (vd->vd_wticks >= 20) {
864*30519Ssam 			vd->vd_wticks = 0;
865*30519Ssam 			printf("vd%d: lost interrupt\n", ctlr);
866*30519Ssam 			/* abort pending dcb's and restart controller */
867*30519Ssam 		}
868*30519Ssam 	}
869*30519Ssam }
870*30519Ssam 
871*30519Ssam #define	DBSIZE	64	/* controller limit with 1K sectors */
872*30519Ssam /*
873*30519Ssam  * Crash dump.
874*30519Ssam  */
875*30519Ssam vddump(dev)
876*30519Ssam 	dev_t dev;
87724004Ssam {
878*30519Ssam 	register struct vba_device *vi;
879*30519Ssam 	register struct vba_ctlr *vm;
880*30519Ssam 	register struct disklabel *lp;
881*30519Ssam 	register struct vdsoftc *vd;
882*30519Ssam 	struct dksoftc *dk;
883*30519Ssam 	int part, unit, num;
884*30519Ssam 	caddr_t start;
88524004Ssam 
886*30519Ssam 	start = 0;
887*30519Ssam 	unit = vdunit(dev);
888*30519Ssam 	if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
889*30519Ssam 		return (ENXIO);
890*30519Ssam 	dk = &dksoftc[unit];
891*30519Ssam 	if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
892*30519Ssam 		return (ENXIO);
893*30519Ssam 	lp = &dklabel[unit];
894*30519Ssam 	part = vdpart(dev);
895*30519Ssam 	if (part >= lp->d_npartitions)
896*30519Ssam 		return (ENXIO);
897*30519Ssam 	vm = vdminfo[vi->ui_ctlr];
898*30519Ssam 	vdreset_ctlr(vm);
899*30519Ssam 	if (dumplo < 0)
900*30519Ssam 		return (EINVAL);
901*30519Ssam 	/*
902*30519Ssam 	 * Dumplo and maxfree are in pages;
903*30519Ssam 	 * dumplo will change soon (XXX).
904*30519Ssam 	 */
905*30519Ssam 	num = maxfree * (NBPG / lp->d_secsize);
906*30519Ssam 	dumplo *= NBPG / lp->d_secsize;		/* XXX */
907*30519Ssam 	if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size)
908*30519Ssam 		num = lp->d_partitions[vdpart(dev)].p_size - dumplo;
909*30519Ssam 	vd = &vdsoftc[vm->um_ctlr];
910*30519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
911*30519Ssam 	vd->vd_dcb.opcode = VDOP_WD;
912*30519Ssam 	vd->vd_dcb.devselect = vi->ui_slave;
913*30519Ssam 	vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long);
914*30519Ssam 	while (num > 0) {
915*30519Ssam 		int nsec, cn, sn, tn;
916*30519Ssam 
917*30519Ssam 		nsec = MIN(num, DBSIZE);
918*30519Ssam 		sn = dumplo + (unsigned)start / lp->d_secsize;
919*30519Ssam 		cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) /
920*30519Ssam 		    lp->d_secpercyl;
921*30519Ssam 		sn %= lp->d_secpercyl;
922*30519Ssam 		tn = sn / lp->d_nsectors;
923*30519Ssam 		sn %= lp->d_nsectors;
924*30519Ssam 		vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
925*30519Ssam 		vd->vd_dcb.trail.rwtrail.memadr = start;
926*30519Ssam 		vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1;
927*30519Ssam 		vd->vd_dcb.trail.rwtrail.disk.cylinder = cn;
928*30519Ssam 		vd->vd_dcb.trail.rwtrail.disk.track = tn;
929*30519Ssam 		vd->vd_dcb.trail.rwtrail.disk.sector = sn;
930*30519Ssam 		vd->vd_dcb.operrsta = 0;
931*30519Ssam 		VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
932*30519Ssam 		if (!vdpoll(vm, 5)) {
933*30519Ssam 			printf(" during dump\n");
934*30519Ssam 			return (EIO);
935*30519Ssam 		}
936*30519Ssam 		if (vd->vd_dcb.operrsta & VDERR_HARD) {
937*30519Ssam 			printf("dk%d: hard error, status=%b\n", unit,
938*30519Ssam 			    vd->vd_dcb.operrsta, VDERRBITS);
939*30519Ssam 			return (EIO);
940*30519Ssam 		}
941*30519Ssam 		start += nsec * lp->d_secsize;
942*30519Ssam 		num -= nsec;
94325675Ssam 	}
944*30519Ssam 	return (0);
94524004Ssam }
94624004Ssam 
94724004Ssam vdsize(dev)
94825675Ssam 	dev_t dev;
94924004Ssam {
950*30519Ssam 	register int unit = vdunit(dev);
951*30519Ssam 	register struct dksoftc *dk;
952*30519Ssam 	struct vba_device *vi;
953*30519Ssam 	struct disklabel *lp;
95424004Ssam 
955*30519Ssam 	if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 ||
956*30519Ssam 	    (dk = &dksoftc[unit])->dk_state != OPEN)
95725675Ssam 		return (-1);
958*30519Ssam 	lp = &dklabel[unit];
959*30519Ssam 	return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift);
96024004Ssam }
96124004Ssam 
96225675Ssam /*
96325675Ssam  * Perform a controller reset.
96425675Ssam  */
965*30519Ssam vdreset_ctlr(vm)
966*30519Ssam 	register struct vba_ctlr *vm;
96724004Ssam {
968*30519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
969*30519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
970*30519Ssam 	register int unit;
971*30519Ssam 	struct vba_device *vi;
97225675Ssam 
973*30519Ssam 	VDRESET(vdaddr, vd->vd_type);
974*30519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
975*30519Ssam 		vdaddr->vdcsr = 0;
976*30519Ssam 		vdaddr->vdtcf_mdcb = AM_ENPDA;
977*30519Ssam 		vdaddr->vdtcf_dcb = AM_ENPDA;
978*30519Ssam 		vdaddr->vdtcf_trail = AM_ENPDA;
979*30519Ssam 		vdaddr->vdtcf_data = AM_ENPDA;
980*30519Ssam 		vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
98125675Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
98225675Ssam 	}
983*30519Ssam 	if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) {
984*30519Ssam 		printf("%s cmd failed\n",
985*30519Ssam 		    vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
98630370Skarels 		return;
98725675Ssam 	}
988*30519Ssam 	for (unit = 0; unit < NDK; unit++)
989*30519Ssam 		if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive)
990*30519Ssam 			(void) vdreset_drive(vi);
991*30519Ssam }
992*30519Ssam 
993*30519Ssam vdreset_drive(vi)
994*30519Ssam 	register struct vba_device *vi;
995*30519Ssam {
996*30519Ssam 	register struct disklabel *lp = &dklabel[vi->ui_unit];
997*30519Ssam 	struct vba_ctlr *vm = vdminfo[vi->ui_ctlr];
998*30519Ssam 	struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
999*30519Ssam 	struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
1000*30519Ssam 
1001*30519Ssam top:
1002*30519Ssam 	vd->vd_dcb.opcode = VDOP_CONFIG;		/* command */
1003*30519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
1004*30519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
1005*30519Ssam 	vd->vd_dcb.operrsta = 0;
1006*30519Ssam 	vd->vd_dcb.devselect = vi->ui_slave;
1007*30519Ssam 	vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders;
1008*30519Ssam 	vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks;
1009*30519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
1010*30519Ssam 		vd->vd_dcb.trailcnt = sizeof (treset) / sizeof (long);
1011*30519Ssam 		vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors;
1012*30519Ssam 		vd->vd_dcb.trail.rstrail.slip_sec = lp->d_trackskew;
1013*30519Ssam 		vd->vd_dcb.trail.rstrail.recovery = 0x18f;
1014*30519Ssam 	} else
1015*30519Ssam 		vd->vd_dcb.trailcnt = 2;		/* XXX */
1016*30519Ssam 	vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
1017*30519Ssam 	vd->vd_mdcb.mdcb_status = 0;
1018*30519Ssam 	VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type);
1019*30519Ssam 	if (!vdpoll(vm, 5)) {
1020*30519Ssam 		printf(" during config\n");
1021*30519Ssam 		return (0);
102225675Ssam 	}
1023*30519Ssam 	if (vd->vd_dcb.operrsta & VDERR_HARD) {
1024*30519Ssam 		if (vd->vd_type == VDTYPE_SMDE &&
1025*30519Ssam 		    (vdaddr->vdstatus[vi->ui_slave]&STA_US) == 0)
1026*30519Ssam 			return (0);
1027*30519Ssam 		if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0)
1028*30519Ssam 			printf("dk%d: config error\n", vi->ui_unit);
1029*30519Ssam 		else if ((vd->vd_flags&VD_STARTED) == 0) {
1030*30519Ssam 			int started;
1031*30519Ssam 
1032*30519Ssam 			printf("vd%d: starting drives, wait ... ", vm->um_ctlr);
1033*30519Ssam 			vd->vd_flags |= VD_STARTED;
1034*30519Ssam 			started = (vdcmd(vm, VDOP_START, 10) == 1);
1035*30519Ssam 			DELAY(62000000);
1036*30519Ssam 			printf("\n");
1037*30519Ssam 			if (started)
1038*30519Ssam 				goto top;
1039*30519Ssam 		}
1040*30519Ssam 		return (0);
1041*30519Ssam 	}
1042*30519Ssam 	return (1);
104325675Ssam }
104424004Ssam 
104525675Ssam /*
1046*30519Ssam  * Perform a command w/o trailer.
104725675Ssam  */
1048*30519Ssam vdcmd(vm, cmd, t)
1049*30519Ssam 	register struct vba_ctlr *vm;
105025675Ssam {
1051*30519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
105225675Ssam 
1053*30519Ssam 	vd->vd_dcb.opcode = cmd;		/* command */
1054*30519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
1055*30519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
1056*30519Ssam 	vd->vd_dcb.operrsta = 0;
1057*30519Ssam 	vd->vd_dcb.devselect = 0;
1058*30519Ssam 	vd->vd_dcb.trailcnt = 0;
1059*30519Ssam 	vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
1060*30519Ssam 	vd->vd_mdcb.mdcb_status = 0;
1061*30519Ssam 	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
1062*30519Ssam 	if (!vdpoll(vm, t)) {
1063*30519Ssam 		printf(" during init\n");
106430370Skarels 		return (0);
106530370Skarels 	}
1066*30519Ssam 	return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0);
106725675Ssam }
106825675Ssam 
106925925Ssam /*
1070*30519Ssam  * Poll controller until operation
1071*30519Ssam  * completes or timeout expires.
107225925Ssam  */
1073*30519Ssam vdpoll(vm, t)
1074*30519Ssam 	register struct vba_ctlr *vm;
107525925Ssam 	register int t;
107625925Ssam {
1077*30519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
1078*30519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
107925925Ssam 
108025925Ssam 	t *= 1000;
108130370Skarels 	for (;;) {
1082*30519Ssam 		uncache(&vd->vd_dcb.operrsta);
1083*30519Ssam 		if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT))
108430370Skarels 			break;
108525925Ssam 		if (--t <= 0) {
1086*30519Ssam 			printf("vd%d: controller timeout", vm->um_ctlr);
1087*30519Ssam 			VDABORT(vdaddr, vd->vd_type);
108825925Ssam 			DELAY(30000);
108925925Ssam 			return (0);
109025925Ssam 		}
109130370Skarels 		DELAY(1000);
109225925Ssam 	}
1093*30519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
1094*30519Ssam 		do {
109525925Ssam 			DELAY(50);
1096*30519Ssam 			uncache(&vdaddr->vdcsr);
1097*30519Ssam 		} while (vdaddr->vdcsr & CS_GO);
109825925Ssam 		DELAY(300);
109925925Ssam 	}
110025925Ssam 	DELAY(200);
1101*30519Ssam 	uncache(&vd->vd_dcb.operrsta);
110225925Ssam 	return (1);
110325925Ssam }
110425925Ssam 
1105*30519Ssam #ifdef COMPAT_42
1106*30519Ssam struct	vdst {
1107*30519Ssam 	int	nsec;		/* sectors/track */
1108*30519Ssam 	int	ntrack;		/* tracks/cylinder */
1109*30519Ssam 	int	ncyl;		/* cylinders */
1110*30519Ssam 	char	*name;		/* type name */
1111*30519Ssam 	struct {
1112*30519Ssam 		int	off;	/* partition offset in sectors */
1113*30519Ssam 		int	size;	/* partition size in sectors */
1114*30519Ssam 	} parts[3];
1115*30519Ssam } vdst[] = {
1116*30519Ssam 	{ 48, 24, 711, "xsd", {0,61056}, {61056,61056}, {122112,691200} },
1117*30519Ssam 	{ 44, 20, 842, "egl", {0,52800}, {52800,66000}, {118800,617760} },
1118*30519Ssam 	{ 64, 10, 823, "fuj", {0,38400}, {38400,48000}, { 86400,437120} },
1119*30519Ssam 	{ 32, 24, 711, "xfd", {0,40704}, {40704,40704}, { 81408,460800} },
1120*30519Ssam 	{ 32, 19, 823, "smd", {0,40128}, {40128,27360}, { 67488,429856} },
1121*30519Ssam 	{ 32, 10, 823, "fsd", {0,19200}, {19200,24000}, { 43200,218560} }
1122*30519Ssam };
1123*30519Ssam #define	NVDST	(sizeof (vdst) / sizeof (vdst[0]))
1124*30519Ssam 
112525675Ssam /*
1126*30519Ssam  * Construct a label for an unlabeled pack.  We
1127*30519Ssam  * deduce the drive type by reading from the last
1128*30519Ssam  * track on successively smaller drives until we
1129*30519Ssam  * don't get an error.
113025675Ssam  */
1131*30519Ssam vdmaptype(vi, lp)
1132*30519Ssam 	register struct vba_device *vi;
1133*30519Ssam 	register struct disklabel *lp;
113425675Ssam {
1135*30519Ssam 	register struct vdsoftc *vd;
1136*30519Ssam 	register struct vdst *p;
1137*30519Ssam 	struct vba_ctlr *vm = vdminfo[vi->ui_ctlr];
1138*30519Ssam 	int i;
113925675Ssam 
1140*30519Ssam 	vd = &vdsoftc[vi->ui_ctlr];
1141*30519Ssam 	for (p = vdst; p < &vdst[NVDST]; p++) {
1142*30519Ssam 		if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32)
1143*30519Ssam 			continue;
1144*30519Ssam 		lp->d_nsectors = p->nsec;
1145*30519Ssam 		lp->d_ntracks = p->ntrack;
1146*30519Ssam 		lp->d_ncylinders = p->ncyl;
1147*30519Ssam 		if (!vdreset_drive(vi))
1148*30519Ssam 			return (0);
1149*30519Ssam 		vd->vd_dcb.opcode = VDOP_RD;
1150*30519Ssam 		vd->vd_dcb.intflg = DCBINT_NONE;
1151*30519Ssam 		vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
1152*30519Ssam 		vd->vd_dcb.devselect = vi->ui_slave;
1153*30519Ssam 		vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long);
1154*30519Ssam 		vd->vd_dcb.trail.rwtrail.memadr = (char *)
1155*30519Ssam 		    vtoph((struct proc *)0, (unsigned)vd->vd_rawbuf);
1156*30519Ssam 		vd->vd_dcb.trail.rwtrail.wcount = 512 / sizeof(short);
1157*30519Ssam 		vd->vd_dcb.operrsta = 0;
1158*30519Ssam 		vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2;
1159*30519Ssam 		vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1;
1160*30519Ssam 		vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1;
1161*30519Ssam 		vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
1162*30519Ssam 		vd->vd_mdcb.mdcb_status = 0;
1163*30519Ssam 		VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
1164*30519Ssam 		if (!vdpoll(vm, 60))
1165*30519Ssam 			printf(" during probe\n");
1166*30519Ssam 		if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0)
1167*30519Ssam 			break;
116824004Ssam 	}
1169*30519Ssam 	if (p >= &vdst[NVDST]) {
1170*30519Ssam 		printf("dk%d: unknown drive type\n", vi->ui_unit);
1171*30519Ssam 		return (0);
1172*30519Ssam 	}
1173*30519Ssam 	for (i = 0; i < 3; i++) {
1174*30519Ssam 		lp->d_partitions[i].p_offset = p->parts[i].off;
1175*30519Ssam 		lp->d_partitions[i].p_size = p->parts[i].size;
1176*30519Ssam 	}
1177*30519Ssam 	lp->d_npartitions = 3;
1178*30519Ssam 	lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1179*30519Ssam 	lp->d_rpm = 3600;
1180*30519Ssam 	lp->d_secsize = 512;
1181*30519Ssam 	bcopy(p->name, lp->d_typename, 4);
1182*30519Ssam 	return (1);
118324004Ssam }
1184*30519Ssam #endif COMPAT_42
118524004Ssam #endif
1186