xref: /csrg-svn/sys/tahoe/vba/vd.c (revision 32211)
1*32211Skarels /*	vd.c	1.20	87/09/17	*/
224004Ssam 
329564Ssam #include "dk.h"
424004Ssam #if NVD > 0
524004Ssam /*
630519Ssam  * 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"
1430519Ssam #include "disklabel.h"
1525675Ssam #include "map.h"
1630519Ssam #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"
2430519Ssam #include "ioctl.h"
2530756Skarels #include "stat.h"
2624004Ssam 
2729951Skarels #include "../tahoe/cpu.h"
2829951Skarels #include "../tahoe/mtpr.h"
2929951Skarels #include "../tahoe/pte.h"
3029951Skarels 
3125675Ssam #include "../tahoevba/vbavar.h"
3225928Ssam #include "../tahoevba/vdreg.h"
3324004Ssam 
34*32211Skarels #ifndef	COMPAT_42
3530519Ssam #define	COMPAT_42
36*32211Skarels #endif
3730519Ssam 
3830519Ssam #define vdunit(dev)	(minor(dev) >> 3)
3930519Ssam #define vdpart(dev)	(minor(dev) & 0x07)
4030519Ssam #define	vdminor(unit,part)	(((unit) << 3) | (part))
4124004Ssam 
4224004Ssam struct	vba_ctlr *vdminfo[NVD];
4329564Ssam struct  vba_device *vddinfo[NDK];
4430756Skarels int	vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy();
4530519Ssam long	vdaddr[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 };
4625675Ssam struct	vba_driver vddriver =
4730519Ssam   { vdprobe, vdslave, vdattach, vddgo, vdaddr, "dk", vddinfo, "vd", vdminfo };
4824004Ssam 
4924004Ssam /*
5030519Ssam  * Per-controller state.
5130519Ssam  */
5230519Ssam struct vdsoftc {
5330519Ssam 	u_short	vd_flags;
5430519Ssam #define	VD_INIT		0x1	/* controller initialized */
5530519Ssam #define	VD_STARTED	0x2	/* start command issued */
5630519Ssam #define	VD_DOSEEKS	0x4	/* should overlap seeks */
5730756Skarels #define	VD_SCATGATH	0x8	/* can do scatter-gather commands (correctly) */
5830519Ssam 	u_short	vd_type;	/* controller type */
5930519Ssam 	u_short	vd_wticks;	/* timeout */
6030519Ssam 	struct	mdcb vd_mdcb;	/* master command block */
6130519Ssam 	u_long	vd_mdcbphys;	/* physical address of vd_mdcb */
6230519Ssam 	struct	dcb vd_dcb;	/* i/o command block */
6330519Ssam 	u_long	vd_dcbphys;	/* physical address of vd_dcb */
6430601Skarels 	struct	vb_buf vd_rbuf;	/* vba resources */
6530519Ssam } vdsoftc[NVD];
6630519Ssam 
6730519Ssam /*
6825675Ssam  * Per-drive state.
6925675Ssam  */
7030519Ssam struct	dksoftc {
7130519Ssam 	u_short	dk_state;	/* open fsm */
7230756Skarels 	u_short	dk_copenpart;	/* character units open on this drive */
7330756Skarels 	u_short	dk_bopenpart;	/* block units open on this drive */
7430756Skarels 	u_short	dk_openpart;	/* all units open on this drive */
7530756Skarels #ifndef SECSIZE
7630756Skarels 	u_short	dk_bshift;	/* shift for * (DEV_BSIZE / sectorsize) XXX */
7730756Skarels #endif SECSIZE
7830519Ssam 	u_int	dk_curcyl;	/* last selected cylinder */
7930756Skarels 	struct	skdcb dk_dcb;	/* seek command block */
8030519Ssam 	u_long	dk_dcbphys;	/* physical address of dk_dcb */
8130519Ssam } dksoftc[NDK];
8224004Ssam 
8324004Ssam /*
8430519Ssam  * Drive states.  Used during steps of open/initialization.
8530519Ssam  * States < OPEN (> 0) are transient, during an open operation.
8630519Ssam  * OPENRAW is used for unabeled disks, to allow format operations.
8725675Ssam  */
8830519Ssam #define	CLOSED		0		/* disk is closed */
8930519Ssam #define	WANTOPEN	1		/* open requested, not started */
9030519Ssam #define	WANTOPENRAW	2		/* open requested, no label */
9130519Ssam #define	RDLABEL		3		/* reading pack label */
9230519Ssam #define	OPEN		4		/* intialized and ready */
9330519Ssam #define	OPENRAW		5		/* open, no label */
9424004Ssam 
9530519Ssam struct	buf rdkbuf[NDK];	/* raw i/o buffer headers */
9630519Ssam struct	buf dkutab[NDK];	/* i/o queue headers */
9730519Ssam struct	disklabel dklabel[NDK];	/* pack labels */
9824004Ssam 
9930519Ssam #define b_cylin	b_resid
10030574Skarels #define	b_track	b_error		/* used for seek commands */
10130574Skarels #define	b_seekf	b_forw		/* second queue on um_tab */
10230574Skarels #define	b_seekl	b_back		/* second queue on um_tab */
10330519Ssam 
10430519Ssam int	vdwstart, vdwatch();
10530519Ssam 
10624004Ssam /*
10725675Ssam  * See if the controller is really there; if so, initialize it.
10825675Ssam  */
10925857Ssam vdprobe(reg, vm)
11025857Ssam 	caddr_t reg;
11125857Ssam 	struct vba_ctlr *vm;
11225675Ssam {
11325857Ssam 	register br, cvec;		/* must be r12, r11 */
11430519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)reg;
11530519Ssam 	struct vdsoftc *vd;
11630573Skarels 	int s;
11725857Ssam 
11830370Skarels #ifdef lint
11930370Skarels 	br = 0; cvec = br; br = cvec;
12030370Skarels 	vdintr(0);
12130370Skarels #endif
12225857Ssam 	if (badaddr((caddr_t)reg, 2))
12325675Ssam 		return (0);
12430519Ssam 	vd = &vdsoftc[vm->um_ctlr];
12530519Ssam 	vdaddr->vdreset = 0xffffffff;
12625675Ssam 	DELAY(1000000);
12730519Ssam 	if (vdaddr->vdreset != (unsigned)0xffffffff) {
12830519Ssam 		vd->vd_type = VDTYPE_VDDC;
12930519Ssam 		vd->vd_flags &= ~VD_DOSEEKS;
13025675Ssam 		DELAY(1000000);
13125675Ssam 	} else {
13230519Ssam 		vd->vd_type = VDTYPE_SMDE;
13330519Ssam 		vd->vd_flags |= VD_DOSEEKS;
13430519Ssam 		vdaddr->vdrstclr = 0;
13525675Ssam 		DELAY(3000000);
13630519Ssam 		vdaddr->vdcsr = 0;
13730519Ssam 		vdaddr->vdtcf_mdcb = AM_ENPDA;
13830519Ssam 		vdaddr->vdtcf_dcb = AM_ENPDA;
13930519Ssam 		vdaddr->vdtcf_trail = AM_ENPDA;
14030519Ssam 		vdaddr->vdtcf_data = AM_ENPDA;
14130519Ssam 		vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS |
14229921Skarels 		    XMD_32BIT | BSZ_16WRD |
14325925Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
14425675Ssam 	}
14530519Ssam 	vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb);
14630519Ssam 	vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb);
14730519Ssam 	vm->um_addr = reg;		/* XXX */
14830573Skarels 	s = spl7();
14930519Ssam 	if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) {
15030519Ssam 		printf("vd%d: %s cmd failed\n", vm->um_ctlr,
15130519Ssam 		    vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
15230573Skarels 		splx(s);
15330519Ssam 		return (0);
15430519Ssam 	}
15530756Skarels 	if (vd->vd_type == VDTYPE_SMDE) {
15630756Skarels 		vd->vd_dcb.trail.idtrail.date = 0;
15730756Skarels 		if (vdcmd(vm, VDOP_IDENT, 10)) {
15830756Skarels 			uncache(&vd->vd_dcb.trail.idtrail.date);
15930756Skarels 			if (vd->vd_dcb.trail.idtrail.date != 0)
16030756Skarels 				vd->vd_flags |= VD_SCATGATH;
16130756Skarels 		}
16230756Skarels 	}
16330573Skarels 	splx(s);
16425925Ssam 	/*
16525950Ssam 	 * Allocate page tables and i/o buffer.
16625925Ssam 	 */
167*32211Skarels 	if (vbainit(&vd->vd_rbuf, MAXPHYS,
168*32211Skarels 	    vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) {
169*32211Skarels 		printf("vd%d: vbainit failed\n", vm->um_ctlr);
170*32211Skarels 		return (0);
171*32211Skarels 	}
17225857Ssam 	br = 0x17, cvec = 0xe0 + vm->um_ctlr;	/* XXX */
17330519Ssam 	return (sizeof (struct vddevice));
17425675Ssam }
17524004Ssam 
17624004Ssam /*
17730519Ssam  * See if a drive is really there.
17830519Ssam  *
17930519Ssam  * Can't read pack label here as various data structures
18030519Ssam  * aren't setup for doing a read in a straightforward
18130519Ssam  * manner.  Instead just probe for the drive and leave
18230519Ssam  * the pack label stuff to the attach routine.
18325675Ssam  */
18425675Ssam vdslave(vi, addr)
18525675Ssam 	register struct vba_device *vi;
18630519Ssam 	struct vddevice *vdaddr;
18725675Ssam {
18830519Ssam 	register struct disklabel *lp = &dklabel[vi->ui_unit];
189*32211Skarels 	register struct dksoftc *dk = &dksoftc[vi->ui_unit];
19030519Ssam 	struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
19124004Ssam 
19230519Ssam 	if ((vd->vd_flags&VD_INIT) == 0) {
19330756Skarels 		printf("vd%d: %s controller%s\n", vi->ui_ctlr,
19430756Skarels 		    vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE",
19530756Skarels 		    (vd->vd_flags & VD_SCATGATH) ? " with scatter-gather" : "");
19630519Ssam 		vd->vd_flags |= VD_INIT;
19725675Ssam 	}
19830519Ssam 
19925675Ssam 	/*
20030519Ssam 	 * Initialize label enough to do a reset on
20130519Ssam 	 * the drive.  The remainder of the default
20230519Ssam 	 * label values will be filled in in vdinit
20330519Ssam 	 * at attach time.
20425675Ssam 	 */
205*32211Skarels 	if (vd->vd_type == VDTYPE_SMDE)
206*32211Skarels 		lp->d_secsize = VD_MAXSECSIZE;
207*32211Skarels 	else
208*32211Skarels 		lp->d_secsize = VDDC_SECSIZE;
209*32211Skarels 	lp->d_nsectors = 72;		/* only used on smd-e */
21030519Ssam 	lp->d_ntracks = 24;
211*32211Skarels 	lp->d_ncylinders = 842;
212*32211Skarels 	lp->d_secpercyl = 72*24;
21324004Ssam 
21430519Ssam 	/*
21530519Ssam 	 * Initialize invariant portion of
21630519Ssam 	 * dcb used for overlapped seeks.
21730519Ssam 	 */
21830519Ssam 	dk->dk_dcb.opcode = VDOP_SEEK;
21930519Ssam 	dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA;
22030519Ssam 	dk->dk_dcb.devselect = vi->ui_slave;
22130756Skarels 	dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long);
22230519Ssam 	dk->dk_dcb.trail.sktrail.skaddr.sector = 0;
22330519Ssam 	dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb);
224*32211Skarels #ifndef SECSIZE
225*32211Skarels 	vd_setsecsize(dk, lp);
226*32211Skarels #endif
227*32211Skarels 	return (vdreset_drive(vi));
228*32211Skarels }
229*32211Skarels 
230*32211Skarels vdattach(vi)
231*32211Skarels 	register struct vba_device *vi;
232*32211Skarels {
233*32211Skarels 	register int unit = vi->ui_unit;
234*32211Skarels 	register struct disklabel *lp = &dklabel[unit];
235*32211Skarels 
23630601Skarels 	/*
23730601Skarels 	 * Try to initialize device and read pack label.
23830601Skarels 	 */
23930601Skarels 	if (vdinit(vdminor(unit, 0), 0) != 0) {
24030601Skarels 		printf(": unknown drive type");
24130601Skarels 		return;
24230601Skarels 	}
243*32211Skarels 	if (dksoftc[unit].dk_state == OPEN)
244*32211Skarels 		printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>",
245*32211Skarels 		    lp->d_typename, lp->d_secsize,
246*32211Skarels 		    lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors);
24730519Ssam 	/*
24830519Ssam 	 * (60 / rpm) / (sectors per track * (bytes per sector / 2))
24930519Ssam 	 */
25030519Ssam 	if (vi->ui_dk >= 0)
25130519Ssam 		dk_mspw[vi->ui_dk] = 120.0 /
25230519Ssam 		    (lp->d_rpm * lp->d_nsectors * lp->d_secsize);
25330519Ssam #ifdef notyet
25430573Skarels 	addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp);
25530519Ssam #endif
25624004Ssam }
25724004Ssam 
25830756Skarels vdopen(dev, flags, fmt)
25930519Ssam 	dev_t dev;
26030756Skarels 	int flags, fmt;
26124004Ssam {
26230519Ssam 	register unit = vdunit(dev);
26330519Ssam 	register struct disklabel *lp;
26430519Ssam 	register struct dksoftc *dk;
26530519Ssam 	register struct partition *pp;
26630519Ssam 	struct vba_device *vi;
26730756Skarels 	int s, error, part = vdpart(dev), mask = 1 << part;
26830519Ssam 	daddr_t start, end;
26924004Ssam 
27030519Ssam 	if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
27130519Ssam 		return (ENXIO);
27230519Ssam 	lp = &dklabel[unit];
27330519Ssam 	dk = &dksoftc[unit];
27430519Ssam 
27530519Ssam 	s = spl7();
27630519Ssam 	while (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
27730519Ssam 	    dk->dk_state != CLOSED)
27830519Ssam 		sleep((caddr_t)dk, PZERO+1);
27930519Ssam 	splx(s);
28030519Ssam 	if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
28130519Ssam 		if (error = vdinit(dev, flags))
28230519Ssam 			return (error);
28330573Skarels 
28430573Skarels 	if (vdwstart == 0) {
28530573Skarels 		timeout(vdwatch, (caddr_t)0, hz);
28630573Skarels 		vdwstart++;
28730573Skarels 	}
28830519Ssam 	/*
28930519Ssam 	 * Warn if a partion is opened
29030519Ssam 	 * that overlaps another partition which is open
29130519Ssam 	 * unless one is the "raw" partition (whole disk).
29230519Ssam 	 */
293*32211Skarels #define	RAWPART		8		/* 'x' partition */	/* XXX */
29430519Ssam 	if ((dk->dk_openpart & (1 << part)) == 0 &&
29530519Ssam 	    part != RAWPART) {
29630519Ssam 		pp = &lp->d_partitions[part];
29730519Ssam 		start = pp->p_offset;
29830519Ssam 		end = pp->p_offset + pp->p_size;
29930519Ssam 		for (pp = lp->d_partitions;
30030519Ssam 		     pp < &lp->d_partitions[lp->d_npartitions]; pp++) {
30130519Ssam 			if (pp->p_offset + pp->p_size <= start ||
30230519Ssam 			    pp->p_offset >= end)
30330519Ssam 				continue;
30430519Ssam 			if (pp - lp->d_partitions == RAWPART)
30530519Ssam 				continue;
30630519Ssam 			if (dk->dk_openpart & (1 << (pp - lp->d_partitions)))
30730519Ssam 				log(LOG_WARNING,
30830519Ssam 				    "dk%d%c: overlaps open partition (%c)\n",
30930519Ssam 				    unit, part + 'a',
31030519Ssam 				    pp - lp->d_partitions + 'a');
31130519Ssam 		}
31224004Ssam 	}
31330519Ssam 	if (part >= lp->d_npartitions)
31430519Ssam 		return (ENXIO);
31530756Skarels 	dk->dk_openpart |= mask;
31630756Skarels 	switch (fmt) {
31730756Skarels 	case S_IFCHR:
31830756Skarels 		dk->dk_copenpart |= mask;
31930756Skarels 		break;
32030756Skarels 	case S_IFBLK:
32130756Skarels 		dk->dk_bopenpart |= mask;
32230756Skarels 		break;
32330756Skarels 	}
32430519Ssam 	return (0);
32525675Ssam }
32624004Ssam 
32730756Skarels vdclose(dev, flags, fmt)
32830519Ssam 	dev_t dev;
32930756Skarels 	int flags, fmt;
33024004Ssam {
33130519Ssam 	register int unit = vdunit(dev);
33230519Ssam 	register struct dksoftc *dk = &dksoftc[unit];
33330756Skarels 	int part = vdpart(dev), mask = 1 << part;
33424004Ssam 
33530756Skarels 	switch (fmt) {
33630756Skarels 	case S_IFCHR:
33730756Skarels 		dk->dk_copenpart &= ~mask;
33830756Skarels 		break;
33930756Skarels 	case S_IFBLK:
34030756Skarels 		dk->dk_bopenpart &= ~mask;
34130756Skarels 		break;
34230756Skarels 	}
34330756Skarels 	if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0)
34430756Skarels 		dk->dk_openpart &= ~mask;
34530519Ssam 	/*
34630519Ssam 	 * Should wait for i/o to complete on this partition
34730519Ssam 	 * even if others are open, but wait for work on blkflush().
34830519Ssam 	 */
34930519Ssam 	if (dk->dk_openpart == 0) {
35030573Skarels 		int s = spl7();
35130573Skarels 		while (dkutab[unit].b_actf)
35230573Skarels 			sleep((caddr_t)dk, PZERO-1);
35330519Ssam 		splx(s);
35430519Ssam 		dk->dk_state = CLOSED;
35524004Ssam 	}
35630756Skarels 	return (0);
35725675Ssam }
35824004Ssam 
35930519Ssam vdinit(dev, flags)
36030519Ssam 	dev_t dev;
36130519Ssam 	int flags;
36225675Ssam {
36330519Ssam 	register struct disklabel *lp;
36430519Ssam 	register struct dksoftc *dk;
36530519Ssam 	struct vba_device *vi;
36630519Ssam 	int unit = vdunit(dev), error = 0;
36730756Skarels 	char *msg, *readdisklabel();
36830519Ssam 	extern int cold;
36925675Ssam 
37030519Ssam 	dk = &dksoftc[unit];
37130519Ssam 	if (flags & O_NDELAY) {
37230519Ssam 		dk->dk_state = OPENRAW;
37330756Skarels 		return;
37430519Ssam 	}
37530519Ssam 	dk->dk_state = RDLABEL;
37630519Ssam 	lp = &dklabel[unit];
37730519Ssam 	vi = vddinfo[unit];
37830756Skarels 	if (msg = readdisklabel(dev, vdstrategy, lp)) {
37930519Ssam 		if (cold)
38030601Skarels 			printf(": %s", msg);
38130519Ssam 		else
382*32211Skarels 			log(LOG_ERR, "dk%d: %s\n", unit, msg);
38330519Ssam #ifdef COMPAT_42
38430756Skarels 		if (!vdmaptype(vi, lp))
38530756Skarels 			dk->dk_state = OPENRAW;
38630756Skarels 		else
38730519Ssam 			dk->dk_state = OPEN;
38830519Ssam #else
38930519Ssam 		dk->dk_state = OPENRAW;
39030519Ssam #endif
39130756Skarels 	} else {
39230756Skarels 		/*
39330756Skarels 		 * Now that we have the label, configure
39430756Skarels 		 * the correct drive parameters.
39530756Skarels 		 */
396*32211Skarels 		if (vdreset_drive(vi))
397*32211Skarels 			dk->dk_state = OPEN;
398*32211Skarels 		else {
39930756Skarels 			dk->dk_state = CLOSED;
40030756Skarels 			error = ENXIO;
401*32211Skarels 		}
40225675Ssam 	}
40330756Skarels #ifndef SECSIZE
404*32211Skarels 	vd_setsecsize(dk, lp);
405*32211Skarels #endif
40630519Ssam 	wakeup((caddr_t)dk);
40730519Ssam 	return (error);
40824004Ssam }
40924004Ssam 
410*32211Skarels #ifndef SECSIZE
411*32211Skarels vd_setsecsize(dk, lp)
412*32211Skarels 	register struct dksoftc *dk;
413*32211Skarels 	register struct disklabel *lp;
414*32211Skarels {
415*32211Skarels 	int mul;
416*32211Skarels 
417*32211Skarels 	/*
418*32211Skarels 	 * Calculate scaling shift for mapping
419*32211Skarels 	 * DEV_BSIZE blocks to drive sectors.
420*32211Skarels 	 */
421*32211Skarels 	mul = DEV_BSIZE / lp->d_secsize;
422*32211Skarels 	dk->dk_bshift = 0;
423*32211Skarels 	while ((mul >>= 1) > 0)
424*32211Skarels 		dk->dk_bshift++;
425*32211Skarels }
426*32211Skarels #endif SECSIZE
427*32211Skarels 
42825675Ssam /*ARGSUSED*/
42930519Ssam vddgo(vm)
43030519Ssam 	struct vba_device *vm;
43124004Ssam {
43224004Ssam 
43324004Ssam }
43424004Ssam 
43524004Ssam vdstrategy(bp)
43625675Ssam 	register struct buf *bp;
43724004Ssam {
43830519Ssam 	register struct vba_device *vi;
43930519Ssam 	register struct disklabel *lp;
44030519Ssam 	register struct dksoftc *dk;
44130519Ssam 	register int unit;
44230573Skarels 	register daddr_t sn;
44330519Ssam 	struct buf *dp;
44430573Skarels 	daddr_t sz, maxsz;
44530519Ssam 	int part, s;
44624004Ssam 
44730519Ssam 	unit = vdunit(bp->b_dev);
448*32211Skarels 	if (unit >= NDK) {
44929954Skarels 		bp->b_error = ENXIO;
45025675Ssam 		goto bad;
45129954Skarels 	}
45230519Ssam 	vi = vddinfo[unit];
45330519Ssam 	lp = &dklabel[unit];
45430519Ssam 	if (vi == 0 || vi->ui_alive == 0) {
45530519Ssam 		bp->b_error = ENXIO;
45630519Ssam 		goto bad;
45730519Ssam 	}
45830519Ssam 	dk = &dksoftc[unit];
45930519Ssam 	if (dk->dk_state < OPEN)
46030519Ssam 		goto q;
46130519Ssam 	part = vdpart(bp->b_dev);
46230519Ssam 	if ((dk->dk_openpart & (1 << part)) == 0) {
46330519Ssam 		bp->b_error = ENODEV;
46430519Ssam 		goto bad;
46530519Ssam 	}
466*32211Skarels 	sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
46730519Ssam 	maxsz = lp->d_partitions[part].p_size;
46830756Skarels #ifndef SECSIZE
46930756Skarels 	sn = bp->b_blkno << dk->dk_bshift;
47030756Skarels #else SECSIZE
47130573Skarels 	sn = bp->b_blkno;
47230756Skarels #endif SECSIZE
47330519Ssam 	if (sn < 0 || sn + sz > maxsz) {
47430519Ssam 		if (sn == maxsz) {
47529954Skarels 			bp->b_resid = bp->b_bcount;
47629954Skarels 			goto done;
47729954Skarels 		}
47830756Skarels 		sz = maxsz - sn;
47930573Skarels 		if (sz <= 0) {
48030573Skarels 			bp->b_error = EINVAL;
48130573Skarels 			goto bad;
48230573Skarels 		}
48330573Skarels 		bp->b_bcount = sz * lp->d_secsize;
48425675Ssam 	}
48530519Ssam 	bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl;
48630756Skarels #ifdef SECSIZE
48730756Skarels if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0)
48830756Skarels panic("vdstrat blksize");
48930756Skarels #endif SECSIZE
49030519Ssam q:
49125675Ssam 	s = spl7();
49230519Ssam 	dp = &dkutab[vi->ui_unit];
49330519Ssam 	disksort(dp, bp);
49430519Ssam 	if (!dp->b_active) {
49530519Ssam 		(void) vdustart(vi);
49630573Skarels 		if (!vi->ui_mi->um_tab.b_active)
49730519Ssam 			vdstart(vi->ui_mi);
49824004Ssam 	}
49930519Ssam 	splx(s);
50024004Ssam 	return;
50125675Ssam bad:
50229954Skarels 	bp->b_flags |= B_ERROR;
50329954Skarels done:
50430519Ssam 	biodone(bp);
50530519Ssam 	return;
50624004Ssam }
50724004Ssam 
50830519Ssam vdustart(vi)
50930519Ssam 	register struct vba_device *vi;
51024004Ssam {
51130519Ssam 	register struct buf *bp, *dp;
51230519Ssam 	register struct vba_ctlr *vm;
51330519Ssam 	register int unit = vi->ui_unit;
51430519Ssam 	register struct dksoftc *dk;
51530519Ssam 	register struct vdsoftc *vd;
51630519Ssam 	struct disklabel *lp;
51724004Ssam 
51830519Ssam 	dp = &dkutab[unit];
51930519Ssam 	/*
52030519Ssam 	 * If queue empty, nothing to do.
52130519Ssam 	 */
52230519Ssam 	if ((bp = dp->b_actf) == NULL)
52330519Ssam 		return;
52430519Ssam 	/*
52530574Skarels 	 * If drive is off-cylinder and controller supports seeks,
52630574Skarels 	 * place drive on seek queue for controller.
52730574Skarels 	 * Otherwise, place on transfer queue.
52830519Ssam 	 */
52930519Ssam 	vd = &vdsoftc[vi->ui_ctlr];
53030519Ssam 	dk = &dksoftc[unit];
53130574Skarels 	vm = vi->ui_mi;
53230519Ssam 	if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) {
53330519Ssam 		lp = &dklabel[unit];
53430574Skarels 		bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors;
53530574Skarels 		if (vm->um_tab.b_seekf == NULL)
53630574Skarels 			vm->um_tab.b_seekf = dp;
53730574Skarels 		else
53830574Skarels 			vm->um_tab.b_seekl->b_forw = dp;
53930574Skarels 		vm->um_tab.b_seekl = dp;
54030574Skarels 	} else {
54130574Skarels 		if (vm->um_tab.b_actf == NULL)
54230574Skarels 			vm->um_tab.b_actf = dp;
54330574Skarels 		else
54430574Skarels 			vm->um_tab.b_actl->b_forw = dp;
54530574Skarels 		vm->um_tab.b_actl = dp;
54630519Ssam 	}
54730573Skarels 	dp->b_forw = NULL;
54830573Skarels 	dp->b_active++;
54925675Ssam }
55025675Ssam 
55125675Ssam /*
55230519Ssam  * Start next transfer on a controller.
55330574Skarels  * There are two queues of drives, the first on-cylinder
55430574Skarels  * and the second off-cylinder from their next transfers.
55530574Skarels  * Perform the first transfer for the first drive on the on-cylinder
55630574Skarels  * queue, if any, otherwise the first transfer for the first drive
55730574Skarels  * on the second queue.  Initiate seeks on remaining drives on the
55830574Skarels  * off-cylinder queue, then move them all to the on-cylinder queue.
55925675Ssam  */
56030519Ssam vdstart(vm)
56130519Ssam 	register struct vba_ctlr *vm;
56225675Ssam {
56325675Ssam 	register struct buf *bp;
56430519Ssam 	register struct vba_device *vi;
56530519Ssam 	register struct vdsoftc *vd;
56630519Ssam 	register struct dksoftc *dk;
56730519Ssam 	register struct disklabel *lp;
56830519Ssam 	register struct dcb **dcbp;
56930519Ssam 	struct mdcb *mdcb;
57030519Ssam 	struct buf *dp;
57130519Ssam 	int sn, tn;
57225675Ssam 
57330519Ssam loop:
57430519Ssam 	/*
57530519Ssam 	 * Pull a request off the controller queue.
57630519Ssam 	 */
57730574Skarels 	if ((dp = vm->um_tab.b_actf) == NULL &&
57830574Skarels 	    (dp = vm->um_tab.b_seekf) == NULL)
57930519Ssam 		return;
58030519Ssam 	if ((bp = dp->b_actf) == NULL) {
58130601Skarels 		if (dp == vm->um_tab.b_actf)
58230601Skarels 			vm->um_tab.b_actf = dp->b_forw;
58330601Skarels 		else
58430601Skarels 			vm->um_tab.b_seekf = dp->b_forw;
58530519Ssam 		goto loop;
58630519Ssam 	}
58725675Ssam 
58824004Ssam 	/*
58930519Ssam 	 * Mark controller busy, and determine
59030519Ssam 	 * destination of this request.
59124004Ssam 	 */
59230519Ssam 	vm->um_tab.b_active++;
59330519Ssam 	vi = vddinfo[vdunit(bp->b_dev)];
59430519Ssam 	dk = &dksoftc[vi->ui_unit];
59530756Skarels #ifndef SECSIZE
59630756Skarels 	sn = bp->b_blkno << dk->dk_bshift;
59730756Skarels #else SECSIZE
59830573Skarels 	sn = bp->b_blkno;
59930756Skarels #endif SECSIZE
60030519Ssam 	lp = &dklabel[vi->ui_unit];
60130519Ssam 	sn %= lp->d_secpercyl;
60230519Ssam 	tn = sn / lp->d_nsectors;
60330519Ssam 	sn %= lp->d_nsectors;
60430519Ssam 
60530519Ssam 	/*
60630519Ssam 	 * Construct dcb for read/write command.
60730519Ssam 	 */
60830519Ssam 	vd = &vdsoftc[vm->um_ctlr];
60930519Ssam 	vd->vd_dcb.intflg = DCBINT_DONE;
610*32211Skarels 	vd->vd_dcb.devselect = dk->dk_dcb.devselect;
61130519Ssam 	vd->vd_dcb.operrsta = 0;
61230519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
61330519Ssam 	vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin;
61430519Ssam 	vd->vd_dcb.trail.rwtrail.disk.track = tn;
61530519Ssam 	vd->vd_dcb.trail.rwtrail.disk.sector = sn;
61630574Skarels 	dk->dk_curcyl = bp->b_cylin;
61730574Skarels 	bp->b_track = 0;		/* init overloaded field */
61830756Skarels 	vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
61930756Skarels 	if (vd->vd_flags & VD_SCATGATH &&
62030756Skarels 	    ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0) {
62130756Skarels 		vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW;
62230756Skarels 		vd->vd_dcb.trailcnt += vba_sgsetup(bp, &vd->vd_rbuf,
62330756Skarels 		    &vd->vd_dcb.trail.sgtrail);
62430756Skarels 	} else {
62530756Skarels 		vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD;
62630756Skarels 		vd->vd_dcb.trail.rwtrail.memadr =
62730756Skarels 			vbasetup(bp, &vd->vd_rbuf, lp->d_secsize);
62830756Skarels 		vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1;
62930756Skarels 	}
63030574Skarels 	if (vi->ui_dk >= 0) {
63130574Skarels 		dk_busy |= 1<<vi->ui_dk;
63230574Skarels 		dk_xfer[vi->ui_dk]++;
63330574Skarels 		dk_wds[vi->ui_dk] += bp->b_bcount>>6;
63430574Skarels 	}
63530519Ssam 
63630519Ssam 	/*
63730519Ssam 	 * Look for any seeks to be performed on other drives on this
63830519Ssam 	 * controller.  If overlapped seeks exist, insert seek commands
63930519Ssam 	 * on the controller's command queue before the transfer.
64030519Ssam 	 */
64130519Ssam 	dcbp = &vd->vd_mdcb.mdcb_head;
64230519Ssam 
64330574Skarels 	if (dp == vm->um_tab.b_seekf)
64430574Skarels 		dp = dp->b_forw;
64530574Skarels 	else
64630574Skarels 		dp = vm->um_tab.b_seekf;
64730574Skarels 	for (; dp != NULL; dp = dp->b_forw) {
64830574Skarels 		if ((bp = dp->b_actf) == NULL)
64930574Skarels 			continue;
65030574Skarels 		vi = vddinfo[vdunit(bp->b_dev)];
65130574Skarels 		dk = &dksoftc[vi->ui_unit];
65230519Ssam 		dk->dk_curcyl = bp->b_cylin;
65330574Skarels 		if (vi->ui_dk >= 0)
65430574Skarels 			dk_seek[vi->ui_dk]++;
65530574Skarels 		dk->dk_dcb.operrsta = 0;
65630574Skarels 		dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin;
65730574Skarels 		dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track;
65830574Skarels 		*dcbp = (struct dcb *)dk->dk_dcbphys;
65930574Skarels 		dcbp = &dk->dk_dcb.nxtdcb;
66024004Ssam 	}
66130519Ssam 	*dcbp = (struct dcb *)vd->vd_dcbphys;
66230574Skarels 	if (vm->um_tab.b_actf)
66330574Skarels 		vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf;
66430574Skarels 	else
66530574Skarels 		vm->um_tab.b_actf = vm->um_tab.b_seekf;
66630601Skarels 	if (vm->um_tab.b_seekf)
66730601Skarels 		vm->um_tab.b_actl = vm->um_tab.b_seekl;
66830574Skarels 	vm->um_tab.b_seekf = 0;
66924004Ssam 
67030519Ssam 	/*
67130519Ssam 	 * Initiate operation.
67230519Ssam 	 */
67330519Ssam 	vd->vd_mdcb.mdcb_status = 0;
67430519Ssam 	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
67524004Ssam }
67624004Ssam 
67730519Ssam #define	DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE)
67824004Ssam /*
67924004Ssam  * Handle a disk interrupt.
68024004Ssam  */
68125675Ssam vdintr(ctlr)
68230519Ssam 	register ctlr;
68324004Ssam {
68430519Ssam 	register struct buf *bp, *dp;
68530519Ssam 	register struct vba_ctlr *vm = vdminfo[ctlr];
68630519Ssam 	register struct vba_device *vi;
68730519Ssam 	register struct vdsoftc *vd = &vdsoftc[ctlr];
68830519Ssam 	register status;
68930601Skarels 	int ecode;
69030573Skarels 	struct dksoftc *dk;
69124004Ssam 
69230519Ssam 	vd->vd_wticks = 0;
69330519Ssam 	if (!vm->um_tab.b_active) {
69425675Ssam 		printf("vd%d: stray interrupt\n", ctlr);
69524004Ssam 		return;
69624004Ssam 	}
69725675Ssam 	/*
69830519Ssam 	 * Get device and block structures, and a pointer
69930519Ssam 	 * to the vba_device for the drive.
70025675Ssam 	 */
70130519Ssam 	dp = vm->um_tab.b_actf;
70230519Ssam 	bp = dp->b_actf;
70330519Ssam 	vi = vddinfo[vdunit(bp->b_dev)];
70430574Skarels 	if (vi->ui_dk >= 0)
70530574Skarels 		dk_busy &= ~(1<<vi->ui_dk);
70630519Ssam 	/*
70730519Ssam 	 * Check for and process errors on
70830519Ssam 	 * either the drive or the controller.
70930519Ssam 	 */
71030519Ssam 	uncache(&vd->vd_dcb.operrsta);
71130519Ssam 	status = vd->vd_dcb.operrsta;
71230519Ssam 	if (status & VDERR_HARD) {
71330601Skarels 		if (vd->vd_type == VDTYPE_SMDE) {
71430601Skarels 			uncache(&vd->vd_dcb.err_code);
71530601Skarels 			ecode = vd->vd_dcb.err_code;
71630601Skarels 		}
71730519Ssam 		if (status & DCBS_WPT) {
71830519Ssam 			/*
71930519Ssam 			 * Give up on write locked devices immediately.
72030519Ssam 			 */
72130573Skarels 			printf("dk%d: write locked\n", vi->ui_unit);
72230519Ssam 			bp->b_flags |= B_ERROR;
72330573Skarels 		} else if (status & VDERR_RETRY) {
724*32211Skarels 			int endline = 1;
725*32211Skarels 
72630519Ssam 			if (status & VDERR_DRIVE) {
727*32211Skarels 				printf("dk%d%c: drive err %b, bn %d,",
728*32211Skarels 				    vi->ui_unit, 'a' + vdpart(bp->b_dev),
729*32211Skarels 				    status &~ DONTCARE, VDERRBITS, bp->b_blkno);
730*32211Skarels 				if (vd->vd_type == VDTYPE_SMDE)
731*32211Skarels 					printf(" ecode %x,", ecode);
732*32211Skarels 				printf(" resetting drive...");
73330519Ssam 				if (!vdreset_drive(vi))
73430519Ssam 					vi->ui_alive = 0;
735*32211Skarels 			} else if (status & VDERR_CTLR) {
736*32211Skarels 				printf("dk%d%c: controller err %b, bn %d,",
737*32211Skarels 				    vi->ui_unit, 'a' + vdpart(bp->b_dev),
738*32211Skarels 				    status &~ DONTCARE, VDERRBITS, bp->b_blkno);
739*32211Skarels 				if (vd->vd_type == VDTYPE_SMDE)
740*32211Skarels 					printf(" ecode %x,", ecode);
741*32211Skarels 				printf("resetting controller...");
74230519Ssam 				vdreset_ctlr(vm);
743*32211Skarels 			} else
744*32211Skarels 				endline = 0;
74530519Ssam 			/*
74630519Ssam 			 * Retry transfer once, unless reset failed.
74730519Ssam 			 */
748*32211Skarels 			if (!vi->ui_alive || dp->b_errcnt++ >= 2) {
749*32211Skarels 				if (endline)
750*32211Skarels 					printf("\n");
75130519Ssam 				goto hard;
752*32211Skarels 			}
753*32211Skarels 
754*32211Skarels 			if (endline)
755*32211Skarels 				printf(" retrying\n");
75630519Ssam 			vm->um_tab.b_active = 0;	/* force retry */
75730519Ssam 		} else  {
75830519Ssam 	hard:
75930519Ssam 			bp->b_flags |= B_ERROR;
76030519Ssam 			/* NEED TO ADJUST b_blkno to failed sector */
76130519Ssam 			harderr(bp, "dk");
76230519Ssam 			printf("status %x (%b)", status,
76330519Ssam 			   status &~ DONTCARE, VDERRBITS);
76430601Skarels 			if (vd->vd_type == VDTYPE_SMDE)
76530601Skarels 				printf(" ecode %x", ecode);
76630519Ssam 			printf("\n");
76730519Ssam 		}
76830519Ssam 	} else if (status & DCBS_SOFT)
76930519Ssam 		vdsofterr(vd, bp, &vd->vd_dcb);
77030519Ssam 	if (vm->um_tab.b_active) {
77130519Ssam 		vm->um_tab.b_active = 0;
77230519Ssam 		vm->um_tab.b_actf = dp->b_forw;
77330519Ssam 		dp->b_active = 0;
77430519Ssam 		dp->b_errcnt = 0;
77530519Ssam 		dp->b_actf = bp->av_forw;
77630519Ssam 		bp->b_resid = 0;
77730601Skarels 		vbadone(bp, &vd->vd_rbuf);
77830519Ssam 		biodone(bp);
77930370Skarels 		/*
78030519Ssam 		 * If this unit has more work to do,
78130519Ssam 		 * then start it up right away.
78230370Skarels 		 */
78330519Ssam 		if (dp->b_actf)
78430519Ssam 			vdustart(vi);
78530573Skarels 		else if ((dk = &dksoftc[vi->ui_unit])->dk_openpart == 0)
78630573Skarels 			wakeup((caddr_t)dk);
78724004Ssam 	}
78825675Ssam 	/*
78930519Ssam 	 * If there are devices ready to
79030519Ssam 	 * transfer, start the controller.
79125675Ssam 	 */
79230601Skarels 	if (vm->um_tab.b_actf || vm->um_tab.b_seekf)
79330519Ssam 		vdstart(vm);
79424004Ssam }
79524004Ssam 
79630519Ssam vdsofterr(vd, bp, dcb)
79730519Ssam 	struct vdsoftc *vd;
79825675Ssam 	register struct buf *bp;
79930519Ssam 	register struct dcb *dcb;
80025675Ssam {
80130519Ssam 	int unit = vdunit(bp->b_dev), status = dcb->operrsta;
80230519Ssam 	char part = 'a' + vdpart(bp->b_dev);
80325675Ssam 
804*32211Skarels 	if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE))
80530519Ssam 		log(LOG_WARNING, "dk%d%c: soft error sn%d status %b ecode %x\n",
80630519Ssam 		    unit, part, bp->b_blkno, status, VDERRBITS, dcb->err_code);
807*32211Skarels 	else
80830370Skarels 		log(LOG_WARNING, "dk%d%c: soft ecc sn%d\n",
80930370Skarels 		    unit, part, bp->b_blkno);
81025675Ssam }
81125675Ssam 
81224004Ssam vdread(dev, uio)
81325675Ssam 	dev_t dev;
81425675Ssam 	struct uio *uio;
81524004Ssam {
81630519Ssam 	register int unit = vdunit(dev);
81724004Ssam 
81829564Ssam 	if (unit >= NDK)
81925675Ssam 		return (ENXIO);
82030519Ssam 	return (physio(vdstrategy, &rdkbuf[unit], dev, B_READ, minphys, uio));
82124004Ssam }
82224004Ssam 
82324004Ssam vdwrite(dev, uio)
82425675Ssam 	dev_t dev;
82525675Ssam 	struct uio *uio;
82624004Ssam {
82730519Ssam 	register int unit = vdunit(dev);
82824004Ssam 
82929564Ssam 	if (unit >= NDK)
83025675Ssam 		return (ENXIO);
83130519Ssam 	return (physio(vdstrategy, &rdkbuf[unit], dev, B_WRITE, minphys, uio));
83224004Ssam }
83324004Ssam 
83430519Ssam vdioctl(dev, cmd, data, flag)
83525675Ssam 	dev_t dev;
83630519Ssam 	int cmd;
83730519Ssam 	caddr_t data;
83830519Ssam 	int flag;
83924004Ssam {
84030519Ssam 	int unit = vdunit(dev);
84130519Ssam 	register struct disklabel *lp = &dklabel[unit];
84230519Ssam 	int error = 0;
84324004Ssam 
84430519Ssam 	switch (cmd) {
84530519Ssam 
84630519Ssam 	case DIOCGDINFO:
84730519Ssam 		*(struct disklabel *)data = *lp;
84830519Ssam 		break;
84930519Ssam 
85030573Skarels 	case DIOCGPART:
85130573Skarels 		((struct partinfo *)data)->disklab = lp;
85230573Skarels 		((struct partinfo *)data)->part =
85330573Skarels 		    &lp->d_partitions[vdpart(dev)];
85430519Ssam 		break;
85530519Ssam 
85630519Ssam 	case DIOCSDINFO:
85730519Ssam 		if ((flag & FWRITE) == 0)
85830519Ssam 			error = EBADF;
85930519Ssam 		else
86030519Ssam 			*lp = *(struct disklabel *)data;
86130519Ssam 		break;
86230519Ssam 
86330519Ssam 	case DIOCWDINFO: {
86430519Ssam 		struct buf *bp;
86530519Ssam 		struct disklabel *dlp;
86630519Ssam 
86730519Ssam 		if ((flag & FWRITE) == 0) {
86830519Ssam 			error = EBADF;
86930519Ssam 			break;
87030519Ssam 		}
87130519Ssam 		*lp = *(struct disklabel *)data;
87230519Ssam 		bp = geteblk(lp->d_secsize);
87330756Skarels 		bp->b_dev = makedev(major(dev), vdminor(vdunit(dev), 0));
87430519Ssam 		bp->b_blkno = LABELSECTOR;
87530519Ssam 		bp->b_bcount = lp->d_secsize;
87630519Ssam 		bp->b_flags = B_READ;
87730519Ssam 		dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET);
87830519Ssam 		vdstrategy(bp);
87930519Ssam 		biowait(bp);
88030519Ssam 		if (bp->b_flags & B_ERROR) {
88130519Ssam 			error = u.u_error;		/* XXX */
88230519Ssam 			u.u_error = 0;
88330519Ssam 			goto bad;
88430519Ssam 		}
88530519Ssam 		*dlp = *lp;
88630519Ssam 		bp->b_flags = B_WRITE;
88730519Ssam 		vdstrategy(bp);
88830519Ssam 		biowait(bp);
88930519Ssam 		if (bp->b_flags & B_ERROR) {
89030519Ssam 			error = u.u_error;		/* XXX */
89130519Ssam 			u.u_error = 0;
89230519Ssam 		}
89330519Ssam bad:
89430519Ssam 		brelse(bp);
89530519Ssam 		break;
89625675Ssam 	}
89730519Ssam 
89830519Ssam 	default:
89930519Ssam 		error = ENOTTY;
90030519Ssam 		break;
90124004Ssam 	}
90225675Ssam 	return (0);
90324004Ssam }
90424004Ssam 
90525675Ssam /*
90630519Ssam  * Watch for lost interrupts.
90725675Ssam  */
90830519Ssam vdwatch()
90930519Ssam {
91030519Ssam 	register struct vdsoftc *vd;
91130519Ssam 	register struct vba_ctlr *vm;
91225675Ssam 	register int ctlr, unit;
91330519Ssam 
91430519Ssam 	timeout(vdwatch, (caddr_t)0, hz);
91530519Ssam 	for (ctlr = 0; ctlr < NVD; ctlr++) {
91630519Ssam 		vm = vdminfo[ctlr];
91730519Ssam 		if (vm == 0 || vm->um_alive == 0)
91830519Ssam 			continue;
91930519Ssam 		vd = &vdsoftc[ctlr];
92030601Skarels 		if (vm->um_tab.b_active && vd->vd_wticks++ >= 20) {
92130519Ssam 			vd->vd_wticks = 0;
92230519Ssam 			printf("vd%d: lost interrupt\n", ctlr);
92330519Ssam 			/* abort pending dcb's and restart controller */
92430519Ssam 		}
92530519Ssam 	}
92630519Ssam }
92730519Ssam 
92830519Ssam #define	DBSIZE	64	/* controller limit with 1K sectors */
92930519Ssam /*
93030519Ssam  * Crash dump.
93130519Ssam  */
93230519Ssam vddump(dev)
93330519Ssam 	dev_t dev;
93424004Ssam {
93530519Ssam 	register struct vba_device *vi;
93630519Ssam 	register struct vba_ctlr *vm;
93730519Ssam 	register struct disklabel *lp;
93830519Ssam 	register struct vdsoftc *vd;
93930519Ssam 	struct dksoftc *dk;
94030519Ssam 	int part, unit, num;
94130601Skarels 	u_long start;
94224004Ssam 
94330519Ssam 	start = 0;
94430519Ssam 	unit = vdunit(dev);
94530519Ssam 	if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
94630519Ssam 		return (ENXIO);
94730519Ssam 	dk = &dksoftc[unit];
94830519Ssam 	if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
94930519Ssam 		return (ENXIO);
95030519Ssam 	lp = &dklabel[unit];
95130519Ssam 	part = vdpart(dev);
95230519Ssam 	if (part >= lp->d_npartitions)
95330519Ssam 		return (ENXIO);
954*32211Skarels 	vm = vi->ui_mi;
95530519Ssam 	vdreset_ctlr(vm);
95630519Ssam 	if (dumplo < 0)
95730519Ssam 		return (EINVAL);
95830519Ssam 	/*
95930756Skarels 	 * Maxfree is in pages, dumplo is in DEV_BSIZE units.
96030519Ssam 	 */
96130519Ssam 	num = maxfree * (NBPG / lp->d_secsize);
96230756Skarels 	dumplo *= DEV_BSIZE / lp->d_secsize;
96330519Ssam 	if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size)
96430519Ssam 		num = lp->d_partitions[vdpart(dev)].p_size - dumplo;
96530519Ssam 	vd = &vdsoftc[vm->um_ctlr];
96630519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
96730519Ssam 	vd->vd_dcb.opcode = VDOP_WD;
968*32211Skarels 	vd->vd_dcb.devselect = dk->dk_dcb.devselect;
96930756Skarels 	vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
97030519Ssam 	while (num > 0) {
97130519Ssam 		int nsec, cn, sn, tn;
97230519Ssam 
97330519Ssam 		nsec = MIN(num, DBSIZE);
97430601Skarels 		sn = dumplo + start / lp->d_secsize;
97530519Ssam 		cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) /
97630519Ssam 		    lp->d_secpercyl;
97730519Ssam 		sn %= lp->d_secpercyl;
97830519Ssam 		tn = sn / lp->d_nsectors;
97930519Ssam 		sn %= lp->d_nsectors;
98030519Ssam 		vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
98130519Ssam 		vd->vd_dcb.trail.rwtrail.memadr = start;
98230519Ssam 		vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1;
98330519Ssam 		vd->vd_dcb.trail.rwtrail.disk.cylinder = cn;
98430519Ssam 		vd->vd_dcb.trail.rwtrail.disk.track = tn;
98530519Ssam 		vd->vd_dcb.trail.rwtrail.disk.sector = sn;
98630519Ssam 		vd->vd_dcb.operrsta = 0;
98730519Ssam 		VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
98830519Ssam 		if (!vdpoll(vm, 5)) {
98930519Ssam 			printf(" during dump\n");
99030519Ssam 			return (EIO);
99130519Ssam 		}
99230519Ssam 		if (vd->vd_dcb.operrsta & VDERR_HARD) {
99330519Ssam 			printf("dk%d: hard error, status=%b\n", unit,
99430519Ssam 			    vd->vd_dcb.operrsta, VDERRBITS);
99530519Ssam 			return (EIO);
99630519Ssam 		}
99730519Ssam 		start += nsec * lp->d_secsize;
99830519Ssam 		num -= nsec;
99925675Ssam 	}
100030519Ssam 	return (0);
100124004Ssam }
100224004Ssam 
100324004Ssam vdsize(dev)
100425675Ssam 	dev_t dev;
100524004Ssam {
100630519Ssam 	register int unit = vdunit(dev);
100730519Ssam 	register struct dksoftc *dk;
100830519Ssam 	struct vba_device *vi;
100930519Ssam 	struct disklabel *lp;
101024004Ssam 
101130519Ssam 	if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 ||
101230519Ssam 	    (dk = &dksoftc[unit])->dk_state != OPEN)
101325675Ssam 		return (-1);
101430519Ssam 	lp = &dklabel[unit];
101530756Skarels #ifdef SECSIZE
101630573Skarels 	return ((int)lp->d_partitions[vdpart(dev)].p_size);
101730756Skarels #else SECSIZE
101830756Skarels 	return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift);
101930756Skarels #endif SECSIZE
102024004Ssam }
102124004Ssam 
102225675Ssam /*
102325675Ssam  * Perform a controller reset.
102425675Ssam  */
102530519Ssam vdreset_ctlr(vm)
102630519Ssam 	register struct vba_ctlr *vm;
102724004Ssam {
102830519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
102930519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
103030519Ssam 	register int unit;
103130519Ssam 	struct vba_device *vi;
103225675Ssam 
103330519Ssam 	VDRESET(vdaddr, vd->vd_type);
103430519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
103530519Ssam 		vdaddr->vdcsr = 0;
103630519Ssam 		vdaddr->vdtcf_mdcb = AM_ENPDA;
103730519Ssam 		vdaddr->vdtcf_dcb = AM_ENPDA;
103830519Ssam 		vdaddr->vdtcf_trail = AM_ENPDA;
103930519Ssam 		vdaddr->vdtcf_data = AM_ENPDA;
104030519Ssam 		vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
104125675Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
104225675Ssam 	}
104330519Ssam 	if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) {
104430519Ssam 		printf("%s cmd failed\n",
104530519Ssam 		    vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
104630370Skarels 		return;
104725675Ssam 	}
104830519Ssam 	for (unit = 0; unit < NDK; unit++)
104930519Ssam 		if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive)
105030519Ssam 			(void) vdreset_drive(vi);
105130519Ssam }
105230519Ssam 
105330519Ssam vdreset_drive(vi)
105430519Ssam 	register struct vba_device *vi;
105530519Ssam {
105630519Ssam 	register struct disklabel *lp = &dklabel[vi->ui_unit];
105730519Ssam 	struct vba_ctlr *vm = vdminfo[vi->ui_ctlr];
105830519Ssam 	struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
1059*32211Skarels 	register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
1060*32211Skarels 	register struct dksoftc *dk = &dksoftc[vi->ui_unit];
106130519Ssam 
106230519Ssam top:
106330519Ssam 	vd->vd_dcb.opcode = VDOP_CONFIG;		/* command */
106430519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
106530519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
106630519Ssam 	vd->vd_dcb.operrsta = 0;
1067*32211Skarels 	vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags;
106830519Ssam 	vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders;
106930519Ssam 	vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks;
107030519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
107130756Skarels 		vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long);
107230519Ssam 		vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors;
107330601Skarels 		vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack;
1074*32211Skarels 		vd->vd_dcb.trail.rstrail.recovery = VDRF_NORMAL;
107530519Ssam 	} else
107630519Ssam 		vd->vd_dcb.trailcnt = 2;		/* XXX */
107730519Ssam 	vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
107830519Ssam 	vd->vd_mdcb.mdcb_status = 0;
107930519Ssam 	VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type);
108030519Ssam 	if (!vdpoll(vm, 5)) {
108130519Ssam 		printf(" during config\n");
108230519Ssam 		return (0);
108325675Ssam 	}
108430519Ssam 	if (vd->vd_dcb.operrsta & VDERR_HARD) {
1085*32211Skarels 		if (vd->vd_type == VDTYPE_SMDE) {
1086*32211Skarels 			if (lp->d_devflags == 0) {
1087*32211Skarels 				lp->d_devflags = VD_ESDI;
1088*32211Skarels 				goto top;
1089*32211Skarels 			}
1090*32211Skarels #ifdef notdef
1091*32211Skarels 			/* this doesn't work, STA_US isn't set(?) */
1092*32211Skarels 			if ((vdaddr->vdstatus[vi->ui_slave] & STA_US) == 0)
1093*32211Skarels 				return (0);
1094*32211Skarels #endif
1095*32211Skarels 		}
109630519Ssam 		if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0)
1097*32211Skarels 			printf("dk%d: config error %b ecode %x\n", vi->ui_unit,
1098*32211Skarels 			   vd->vd_dcb.operrsta, VDERRBITS, vd->vd_dcb.err_code);
1099*32211Skarels 		else if ((vd->vd_flags & VD_STARTED) == 0) {
110030519Ssam 			int started;
110130519Ssam 
1102*32211Skarels 			printf(" starting drives, wait ... ");
110330519Ssam 			vd->vd_flags |= VD_STARTED;
110430519Ssam 			started = (vdcmd(vm, VDOP_START, 10) == 1);
110530519Ssam 			DELAY(62000000);
1106*32211Skarels 			printf("done");
1107*32211Skarels 			lp->d_devflags = 0;
110830519Ssam 			if (started)
110930519Ssam 				goto top;
111030519Ssam 		}
111130519Ssam 		return (0);
111230519Ssam 	}
1113*32211Skarels 	dk->dk_dcb.devselect |= lp->d_devflags;
111430519Ssam 	return (1);
111525675Ssam }
111624004Ssam 
111725675Ssam /*
111830519Ssam  * Perform a command w/o trailer.
111925675Ssam  */
112030519Ssam vdcmd(vm, cmd, t)
112130519Ssam 	register struct vba_ctlr *vm;
112225675Ssam {
112330519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
112425675Ssam 
112530519Ssam 	vd->vd_dcb.opcode = cmd;		/* command */
112630519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
112730519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
112830519Ssam 	vd->vd_dcb.operrsta = 0;
112930519Ssam 	vd->vd_dcb.devselect = 0;
113030519Ssam 	vd->vd_dcb.trailcnt = 0;
113130519Ssam 	vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
113230519Ssam 	vd->vd_mdcb.mdcb_status = 0;
113330519Ssam 	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
113430519Ssam 	if (!vdpoll(vm, t)) {
113530519Ssam 		printf(" during init\n");
113630370Skarels 		return (0);
113730370Skarels 	}
113830519Ssam 	return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0);
113925675Ssam }
114025675Ssam 
114125925Ssam /*
114230519Ssam  * Poll controller until operation
114330519Ssam  * completes or timeout expires.
114425925Ssam  */
114530519Ssam vdpoll(vm, t)
114630519Ssam 	register struct vba_ctlr *vm;
114725925Ssam 	register int t;
114825925Ssam {
114930519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
115030519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
115125925Ssam 
115225925Ssam 	t *= 1000;
115330370Skarels 	for (;;) {
115430519Ssam 		uncache(&vd->vd_dcb.operrsta);
115530519Ssam 		if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT))
115630370Skarels 			break;
115725925Ssam 		if (--t <= 0) {
115830519Ssam 			printf("vd%d: controller timeout", vm->um_ctlr);
115930519Ssam 			VDABORT(vdaddr, vd->vd_type);
116025925Ssam 			DELAY(30000);
116125925Ssam 			return (0);
116225925Ssam 		}
116330370Skarels 		DELAY(1000);
116425925Ssam 	}
116530519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
116630519Ssam 		do {
116725925Ssam 			DELAY(50);
116830519Ssam 			uncache(&vdaddr->vdcsr);
116930519Ssam 		} while (vdaddr->vdcsr & CS_GO);
1170*32211Skarels 	 	DELAY(300);
1171*32211Skarels 		uncache(&vd->vd_dcb.err_code);
117225925Ssam 	}
117325925Ssam 	DELAY(200);
117430519Ssam 	uncache(&vd->vd_dcb.operrsta);
117525925Ssam 	return (1);
117625925Ssam }
117725925Ssam 
117830519Ssam #ifdef COMPAT_42
117930519Ssam struct	vdst {
118030519Ssam 	int	nsec;		/* sectors/track */
118130519Ssam 	int	ntrack;		/* tracks/cylinder */
118230519Ssam 	int	ncyl;		/* cylinders */
1183*32211Skarels 	int	secsize;	/* sector size */
118430519Ssam 	char	*name;		/* type name */
118530519Ssam 	struct {
118630519Ssam 		int	off;	/* partition offset in sectors */
118730519Ssam 		int	size;	/* partition size in sectors */
118830573Skarels 	} parts[8];
118930519Ssam } vdst[] = {
1190*32211Skarels 	{ 66, 23, 850, 512, "NEC 800",
1191*32211Skarels 		{0,	 1290300},	/* a cyl   0 - 849 */
1192*32211Skarels 	},
1193*32211Skarels 	{ 48, 24, 711, 512, "xsd",
119431039Skarels 		{0,	 61056},	/* a cyl   0 - 52 */
119531039Skarels 		{61056,	 61056},	/* b cyl  53 - 105 */
119631039Skarels 		{122112, 691200}, 	/* c cyl 106 - 705 */
119731039Skarels 		{237312, 576000}, 	/* d cyl 206 - 705 */
119831039Skarels 		{352512, 460800},	/* e cyl 306 - 705 */
119931039Skarels 		{467712, 345600}, 	/* f cyl 406 - 705 */
120031039Skarels 		{582912, 230400},	/* g cyl 506 - 705 */
120131039Skarels 		{698112, 115200}	/* h cyl 606 - 705 */
120230573Skarels 	},
1203*32211Skarels 	{ 44, 20, 842, 512, "eagle",
120430601Skarels 		{0,	 52800},	/* egl0a cyl   0 - 59 */
120530601Skarels 		{52800,	 66000},	/* egl0b cyl  60 - 134 */
120630601Skarels 		{118800, 617760}, 	/* egl0c cyl 135 - 836 */
120730756Skarels 		{736560, 4400}, 	/* egl0d cyl 837 - 841 */
120831039Skarels 		{0, 	 736560},	/* egl0e cyl   0 - 836 */
120931039Skarels 		{0, 	 740960}, 	/* egl0f cyl   0 - 841 */
121030601Skarels 		{118800, 310640},	/* egl0g cyl 135 - 487 */
121130601Skarels 		{429440, 307120}	/* egl0h cyl 488 - 836 */
121230573Skarels 	},
1213*32211Skarels 	{ 64, 10, 823, 512, "fuj",
121431039Skarels 		{0,	 38400},	/* fuj0a cyl   0 - 59 */
121531039Skarels 		{38400,	 48000},	/* fuj0b cyl  60 - 134 */
121631039Skarels 		{86400,	 437120}, 	/* fuj0c cyl 135 - 817 */
121731039Skarels 		{159360, 364160}, 	/* fuj0d cyl 249 - 817 */
121831039Skarels 		{232320, 291200},	/* fuj0e cyl 363 - 817 */
121931039Skarels 		{305280, 218240}, 	/* fuj0f cyl 477 - 817 */
122031039Skarels 		{378240, 145280},	/* fuj0g cyl 591 - 817 */
122131039Skarels 		{451200, 72320}		/* fug0h cyl 705 - 817 */
122230573Skarels 	},
1223*32211Skarels 	{ 32, 23, 850, 1024, "NEC 800-1024",
1224*32211Skarels 		{0,	 703800},	/* a cyl   0 - 849 */
1225*32211Skarels 	},
1226*32211Skarels 	{ 32, 24, 711, 512, "xfd",
122730756Skarels 		{ 0,	 40704 },	/* a cyl   0 - 52 */
122830756Skarels 		{ 40704, 40704 },	/* b cyl  53 - 105 */
122930756Skarels 		{ 81408, 460800 },	/* c cyl 106 - 705 */
123030756Skarels 		{ 0,	 81408 },	/* d cyl 709 - 710 (a & b) */
123130756Skarels 		{ 0,	 542208 },	/* e cyl   0 - 705 */
123230756Skarels 		{ 40704, 501504 },	/* f cyl  53 - 705 (b & c) */
123330756Skarels 		{ 81408, 230400 },	/* g cyl 106 - 405 (1/2 of c) */
123430756Skarels 		{ 311808,230400 }	/* h cyl 406 - 705 (1/2 of c) */
123530573Skarels 	},
1236*32211Skarels 	{ 32, 19, 823, 512, "smd",
123731039Skarels 		{0,	 40128},	/* a cyl   0-65 */
123831039Skarels 		{40128,  27360},	/* b cyl  66-110 */
123931039Skarels 		{67488,  429856},	/* c cyl 111-817 */
124031039Skarels 		{139232, 358112},	/* d cyl 229 - 817 */
124131039Skarels 		{210976, 286368},	/* e cyl 347 - 817 */
124231039Skarels 		{282720, 214624},	/* f cyl 465 - 817 */
124331039Skarels 		{354464, 142880},	/* g cyl 583 - 817 */
124431039Skarels 		{426208, 71136}		/* h cyl 701 - 817 */
124530573Skarels 	},
1246*32211Skarels 	{ 18, 15, 1224, 1024, "mxd",
1247*32211Skarels 		{0,	 21600},	/* a cyl   0-79 */
1248*32211Skarels 		{21600,  22410},	/* b cyl  80-162 */
1249*32211Skarels 		{44010,  285120},	/* c cyl 163-1217 */
1250*32211Skarels #ifdef notyet
1251*32211Skarels 		{x, 237600},	/* d cyl y - 1217 */
1252*32211Skarels 		{x, 190080},	/* e cyl y - 1217 */
1253*32211Skarels 		{x, 142560},	/* f cyl y - 1217 */
1254*32211Skarels 		{x, 95040},	/* g cyl y - 1217 */
1255*32211Skarels 		{x, 47520}		/* h cyl 701 - 817 */
1256*32211Skarels #endif
1257*32211Skarels 	},
1258*32211Skarels 	{ 32, 10, 823, 512, "fsd",
125930756Skarels 		{0,	 19200},	/* a cyl   0 -  59 */
126030756Skarels 		{19200,	 24000},	/* b cyl  60 - 134 */
126130756Skarels 		{43200,	 218560},	/* c cyl 135 - 817 */
126230573Skarels 	}
126330519Ssam };
126430519Ssam #define	NVDST	(sizeof (vdst) / sizeof (vdst[0]))
126530519Ssam 
126625675Ssam /*
126730519Ssam  * Construct a label for an unlabeled pack.  We
126830519Ssam  * deduce the drive type by reading from the last
126930519Ssam  * track on successively smaller drives until we
127030519Ssam  * don't get an error.
127125675Ssam  */
127230519Ssam vdmaptype(vi, lp)
127330519Ssam 	register struct vba_device *vi;
127430519Ssam 	register struct disklabel *lp;
127525675Ssam {
127630519Ssam 	register struct vdsoftc *vd;
127730519Ssam 	register struct vdst *p;
1278*32211Skarels 	struct vba_ctlr *vm = vi->ui_mi;
127930519Ssam 	int i;
128025675Ssam 
128130519Ssam 	vd = &vdsoftc[vi->ui_ctlr];
128230519Ssam 	for (p = vdst; p < &vdst[NVDST]; p++) {
128330519Ssam 		if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32)
128430519Ssam 			continue;
128530519Ssam 		lp->d_nsectors = p->nsec;
128630519Ssam 		lp->d_ntracks = p->ntrack;
128730519Ssam 		lp->d_ncylinders = p->ncyl;
1288*32211Skarels 		lp->d_secsize = p->secsize;
128930519Ssam 		if (!vdreset_drive(vi))
129030519Ssam 			return (0);
129130519Ssam 		vd->vd_dcb.opcode = VDOP_RD;
129230519Ssam 		vd->vd_dcb.intflg = DCBINT_NONE;
129330519Ssam 		vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
1294*32211Skarels 		vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect;
129530756Skarels 		vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
129630601Skarels 		vd->vd_dcb.trail.rwtrail.memadr =
129730601Skarels 		    vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf);
1298*32211Skarels 		vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short);
129930519Ssam 		vd->vd_dcb.operrsta = 0;
130030519Ssam 		vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2;
130130519Ssam 		vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1;
130230519Ssam 		vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1;
130330519Ssam 		vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
130430519Ssam 		vd->vd_mdcb.mdcb_status = 0;
130530519Ssam 		VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
130630519Ssam 		if (!vdpoll(vm, 60))
130730519Ssam 			printf(" during probe\n");
130830519Ssam 		if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0)
130930519Ssam 			break;
131024004Ssam 	}
1311*32211Skarels 	if (p >= &vdst[NVDST])
131230519Ssam 		return (0);
1313*32211Skarels 
131430573Skarels 	for (i = 0; i < 8; i++) {
131530519Ssam 		lp->d_partitions[i].p_offset = p->parts[i].off;
131630519Ssam 		lp->d_partitions[i].p_size = p->parts[i].size;
131730519Ssam 	}
131830573Skarels 	lp->d_npartitions = 8;
131930519Ssam 	lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
132030519Ssam 	lp->d_rpm = 3600;
132130519Ssam 	bcopy(p->name, lp->d_typename, 4);
132230519Ssam 	return (1);
132324004Ssam }
132430519Ssam #endif COMPAT_42
132524004Ssam #endif
1326