xref: /csrg-svn/sys/tahoe/vba/vd.c (revision 34396)
1*34396Skarels /*	vd.c	1.25	88/05/21	*/
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 
3432211Skarels #ifndef	COMPAT_42
3530519Ssam #define	COMPAT_42
3632211Skarels #endif
37*34396Skarels #define	B_FORMAT	B_XXX		/* XXX */
3830519Ssam 
3930519Ssam #define vdunit(dev)	(minor(dev) >> 3)
4030519Ssam #define vdpart(dev)	(minor(dev) & 0x07)
4130519Ssam #define	vdminor(unit,part)	(((unit) << 3) | (part))
4224004Ssam 
4324004Ssam struct	vba_ctlr *vdminfo[NVD];
4429564Ssam struct  vba_device *vddinfo[NDK];
4530756Skarels int	vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy();
4630519Ssam long	vdaddr[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 };
4725675Ssam struct	vba_driver vddriver =
4830519Ssam   { vdprobe, vdslave, vdattach, vddgo, vdaddr, "dk", vddinfo, "vd", vdminfo };
4924004Ssam 
5024004Ssam /*
5130519Ssam  * Per-controller state.
5230519Ssam  */
5330519Ssam struct vdsoftc {
5430519Ssam 	u_short	vd_flags;
5530519Ssam #define	VD_INIT		0x1	/* controller initialized */
5630519Ssam #define	VD_STARTED	0x2	/* start command issued */
5730519Ssam #define	VD_DOSEEKS	0x4	/* should overlap seeks */
5830756Skarels #define	VD_SCATGATH	0x8	/* can do scatter-gather commands (correctly) */
5930519Ssam 	u_short	vd_type;	/* controller type */
6030519Ssam 	u_short	vd_wticks;	/* timeout */
6130519Ssam 	struct	mdcb vd_mdcb;	/* master command block */
6230519Ssam 	u_long	vd_mdcbphys;	/* physical address of vd_mdcb */
6330519Ssam 	struct	dcb vd_dcb;	/* i/o command block */
6430519Ssam 	u_long	vd_dcbphys;	/* physical address of vd_dcb */
6530601Skarels 	struct	vb_buf vd_rbuf;	/* vba resources */
6630519Ssam } vdsoftc[NVD];
6730519Ssam 
68*34396Skarels #define	VDMAXTIME	20	/* max time for operation, sec. */
69*34396Skarels 
7030519Ssam /*
7125675Ssam  * Per-drive state.
7225675Ssam  */
7330519Ssam struct	dksoftc {
7434076Skarels 	int	dk_state;	/* open fsm */
7530756Skarels #ifndef SECSIZE
7630756Skarels 	u_short	dk_bshift;	/* shift for * (DEV_BSIZE / sectorsize) XXX */
7730756Skarels #endif SECSIZE
7834076Skarels 	int	dk_wlabel;	/* label sector is currently writable */
7932576Skarels 	u_long	dk_copenpart;	/* character units open on this drive */
8032576Skarels 	u_long	dk_bopenpart;	/* block units open on this drive */
8132576Skarels 	u_long	dk_openpart;	/* all units open on this drive */
8230519Ssam 	u_int	dk_curcyl;	/* last selected cylinder */
8330756Skarels 	struct	skdcb dk_dcb;	/* seek command block */
8430519Ssam 	u_long	dk_dcbphys;	/* physical address of dk_dcb */
85*34396Skarels 	int	df_reg[3];	/* for formatting, in-out parameters */
8630519Ssam } dksoftc[NDK];
8724004Ssam 
8824004Ssam /*
8930519Ssam  * Drive states.  Used during steps of open/initialization.
9030519Ssam  * States < OPEN (> 0) are transient, during an open operation.
9134076Skarels  * OPENRAW is used for unlabeled disks, to allow format operations.
9225675Ssam  */
9330519Ssam #define	CLOSED		0		/* disk is closed */
9430519Ssam #define	WANTOPEN	1		/* open requested, not started */
9530519Ssam #define	WANTOPENRAW	2		/* open requested, no label */
9630519Ssam #define	RDLABEL		3		/* reading pack label */
9730519Ssam #define	OPEN		4		/* intialized and ready */
9830519Ssam #define	OPENRAW		5		/* open, no label */
9924004Ssam 
10030519Ssam struct	buf dkutab[NDK];	/* i/o queue headers */
10130519Ssam struct	disklabel dklabel[NDK];	/* pack labels */
10224004Ssam 
10330519Ssam #define b_cylin	b_resid
10430574Skarels #define	b_track	b_error		/* used for seek commands */
10530574Skarels #define	b_seekf	b_forw		/* second queue on um_tab */
10630574Skarels #define	b_seekl	b_back		/* second queue on um_tab */
10730519Ssam 
10830519Ssam int	vdwstart, vdwatch();
10930519Ssam 
11024004Ssam /*
11125675Ssam  * See if the controller is really there; if so, initialize it.
11225675Ssam  */
11325857Ssam vdprobe(reg, vm)
11425857Ssam 	caddr_t reg;
11525857Ssam 	struct vba_ctlr *vm;
11625675Ssam {
11725857Ssam 	register br, cvec;		/* must be r12, r11 */
11830519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)reg;
11930519Ssam 	struct vdsoftc *vd;
12030573Skarels 	int s;
12125857Ssam 
12230370Skarels #ifdef lint
12330370Skarels 	br = 0; cvec = br; br = cvec;
12430370Skarels 	vdintr(0);
12530370Skarels #endif
12625857Ssam 	if (badaddr((caddr_t)reg, 2))
12725675Ssam 		return (0);
12830519Ssam 	vd = &vdsoftc[vm->um_ctlr];
12930519Ssam 	vdaddr->vdreset = 0xffffffff;
13025675Ssam 	DELAY(1000000);
13130519Ssam 	if (vdaddr->vdreset != (unsigned)0xffffffff) {
13230519Ssam 		vd->vd_type = VDTYPE_VDDC;
13330519Ssam 		vd->vd_flags &= ~VD_DOSEEKS;
13425675Ssam 		DELAY(1000000);
13525675Ssam 	} else {
13630519Ssam 		vd->vd_type = VDTYPE_SMDE;
13730519Ssam 		vd->vd_flags |= VD_DOSEEKS;
13830519Ssam 		vdaddr->vdrstclr = 0;
13925675Ssam 		DELAY(3000000);
14030519Ssam 		vdaddr->vdcsr = 0;
14130519Ssam 		vdaddr->vdtcf_mdcb = AM_ENPDA;
14230519Ssam 		vdaddr->vdtcf_dcb = AM_ENPDA;
14330519Ssam 		vdaddr->vdtcf_trail = AM_ENPDA;
14430519Ssam 		vdaddr->vdtcf_data = AM_ENPDA;
14530519Ssam 		vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS |
14629921Skarels 		    XMD_32BIT | BSZ_16WRD |
14725925Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
14825675Ssam 	}
14930519Ssam 	vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb);
15030519Ssam 	vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb);
15130519Ssam 	vm->um_addr = reg;		/* XXX */
15230573Skarels 	s = spl7();
15330519Ssam 	if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) {
15430519Ssam 		printf("vd%d: %s cmd failed\n", vm->um_ctlr,
15530519Ssam 		    vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
15630573Skarels 		splx(s);
15730519Ssam 		return (0);
15830519Ssam 	}
15930756Skarels 	if (vd->vd_type == VDTYPE_SMDE) {
16030756Skarels 		vd->vd_dcb.trail.idtrail.date = 0;
16130756Skarels 		if (vdcmd(vm, VDOP_IDENT, 10)) {
16230756Skarels 			uncache(&vd->vd_dcb.trail.idtrail.date);
16330756Skarels 			if (vd->vd_dcb.trail.idtrail.date != 0)
16430756Skarels 				vd->vd_flags |= VD_SCATGATH;
16530756Skarels 		}
16630756Skarels 	}
16730573Skarels 	splx(s);
16825925Ssam 	/*
16925950Ssam 	 * Allocate page tables and i/o buffer.
17025925Ssam 	 */
17132211Skarels 	if (vbainit(&vd->vd_rbuf, MAXPHYS,
17232211Skarels 	    vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) {
17332211Skarels 		printf("vd%d: vbainit failed\n", vm->um_ctlr);
17432211Skarels 		return (0);
17532211Skarels 	}
17625857Ssam 	br = 0x17, cvec = 0xe0 + vm->um_ctlr;	/* XXX */
17730519Ssam 	return (sizeof (struct vddevice));
17825675Ssam }
17924004Ssam 
18024004Ssam /*
18130519Ssam  * See if a drive is really there.
18230519Ssam  *
18330519Ssam  * Can't read pack label here as various data structures
18430519Ssam  * aren't setup for doing a read in a straightforward
18530519Ssam  * manner.  Instead just probe for the drive and leave
18630519Ssam  * the pack label stuff to the attach routine.
18725675Ssam  */
18834076Skarels /* ARGSUSED */
18934076Skarels vdslave(vi, vdaddr)
19025675Ssam 	register struct vba_device *vi;
19130519Ssam 	struct vddevice *vdaddr;
19225675Ssam {
19330519Ssam 	register struct disklabel *lp = &dklabel[vi->ui_unit];
19432211Skarels 	register struct dksoftc *dk = &dksoftc[vi->ui_unit];
19530519Ssam 	struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
19624004Ssam 
19730519Ssam 	if ((vd->vd_flags&VD_INIT) == 0) {
19830756Skarels 		printf("vd%d: %s controller%s\n", vi->ui_ctlr,
19930756Skarels 		    vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE",
20030756Skarels 		    (vd->vd_flags & VD_SCATGATH) ? " with scatter-gather" : "");
20130519Ssam 		vd->vd_flags |= VD_INIT;
20225675Ssam 	}
20330519Ssam 
20425675Ssam 	/*
20530519Ssam 	 * Initialize label enough to do a reset on
20630519Ssam 	 * the drive.  The remainder of the default
20730519Ssam 	 * label values will be filled in in vdinit
20830519Ssam 	 * at attach time.
20925675Ssam 	 */
21032211Skarels 	if (vd->vd_type == VDTYPE_SMDE)
21132211Skarels 		lp->d_secsize = VD_MAXSECSIZE;
21232211Skarels 	else
21332211Skarels 		lp->d_secsize = VDDC_SECSIZE;
214*34396Skarels 	lp->d_nsectors = 66;		/* only used on smd-e */
21534076Skarels 	lp->d_ntracks = 23;
216*34396Skarels 	lp->d_ncylinders = 850;
217*34396Skarels 	lp->d_secpercyl = 66*23;
21824004Ssam 
21930519Ssam 	/*
22030519Ssam 	 * Initialize invariant portion of
22130519Ssam 	 * dcb used for overlapped seeks.
22230519Ssam 	 */
22330519Ssam 	dk->dk_dcb.opcode = VDOP_SEEK;
22430519Ssam 	dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA;
22530519Ssam 	dk->dk_dcb.devselect = vi->ui_slave;
22630756Skarels 	dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long);
22730519Ssam 	dk->dk_dcb.trail.sktrail.skaddr.sector = 0;
22830519Ssam 	dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb);
22932211Skarels #ifndef SECSIZE
23032211Skarels 	vd_setsecsize(dk, lp);
23132211Skarels #endif
23232211Skarels 	return (vdreset_drive(vi));
23332211Skarels }
23432211Skarels 
23532211Skarels vdattach(vi)
23632211Skarels 	register struct vba_device *vi;
23732211Skarels {
23832211Skarels 	register int unit = vi->ui_unit;
23932211Skarels 	register struct disklabel *lp = &dklabel[unit];
24032211Skarels 
24130601Skarels 	/*
24230601Skarels 	 * Try to initialize device and read pack label.
24330601Skarels 	 */
24430601Skarels 	if (vdinit(vdminor(unit, 0), 0) != 0) {
24530601Skarels 		printf(": unknown drive type");
24630601Skarels 		return;
24730601Skarels 	}
24832211Skarels 	if (dksoftc[unit].dk_state == OPEN)
24932211Skarels 		printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>",
25032211Skarels 		    lp->d_typename, lp->d_secsize,
25132211Skarels 		    lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors);
25230519Ssam 	/*
25330519Ssam 	 * (60 / rpm) / (sectors per track * (bytes per sector / 2))
25430519Ssam 	 */
25530519Ssam 	if (vi->ui_dk >= 0)
25630519Ssam 		dk_mspw[vi->ui_dk] = 120.0 /
25730519Ssam 		    (lp->d_rpm * lp->d_nsectors * lp->d_secsize);
25830519Ssam #ifdef notyet
25930573Skarels 	addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp);
26030519Ssam #endif
26124004Ssam }
26224004Ssam 
26330756Skarels vdopen(dev, flags, fmt)
26430519Ssam 	dev_t dev;
26530756Skarels 	int flags, fmt;
26624004Ssam {
26730519Ssam 	register unit = vdunit(dev);
26830519Ssam 	register struct disklabel *lp;
26930519Ssam 	register struct dksoftc *dk;
27030519Ssam 	register struct partition *pp;
27130519Ssam 	struct vba_device *vi;
27230756Skarels 	int s, error, part = vdpart(dev), mask = 1 << part;
27330519Ssam 	daddr_t start, end;
27424004Ssam 
27530519Ssam 	if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
27630519Ssam 		return (ENXIO);
27730519Ssam 	lp = &dklabel[unit];
27830519Ssam 	dk = &dksoftc[unit];
27930519Ssam 
28030519Ssam 	s = spl7();
28130519Ssam 	while (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
28230519Ssam 	    dk->dk_state != CLOSED)
28330519Ssam 		sleep((caddr_t)dk, PZERO+1);
28430519Ssam 	splx(s);
28530519Ssam 	if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
28630519Ssam 		if (error = vdinit(dev, flags))
28730519Ssam 			return (error);
28830573Skarels 
28930573Skarels 	if (vdwstart == 0) {
29030573Skarels 		timeout(vdwatch, (caddr_t)0, hz);
29130573Skarels 		vdwstart++;
29230573Skarels 	}
29330519Ssam 	/*
29430519Ssam 	 * Warn if a partion is opened
29530519Ssam 	 * that overlaps another partition which is open
29630519Ssam 	 * unless one is the "raw" partition (whole disk).
29730519Ssam 	 */
29832211Skarels #define	RAWPART		8		/* 'x' partition */	/* XXX */
29932576Skarels 	if ((dk->dk_openpart & mask) == 0 && part != RAWPART) {
30030519Ssam 		pp = &lp->d_partitions[part];
30130519Ssam 		start = pp->p_offset;
30230519Ssam 		end = pp->p_offset + pp->p_size;
30330519Ssam 		for (pp = lp->d_partitions;
30430519Ssam 		     pp < &lp->d_partitions[lp->d_npartitions]; pp++) {
30530519Ssam 			if (pp->p_offset + pp->p_size <= start ||
30630519Ssam 			    pp->p_offset >= end)
30730519Ssam 				continue;
30830519Ssam 			if (pp - lp->d_partitions == RAWPART)
30930519Ssam 				continue;
31030519Ssam 			if (dk->dk_openpart & (1 << (pp - lp->d_partitions)))
31130519Ssam 				log(LOG_WARNING,
31230519Ssam 				    "dk%d%c: overlaps open partition (%c)\n",
31330519Ssam 				    unit, part + 'a',
31430519Ssam 				    pp - lp->d_partitions + 'a');
31530519Ssam 		}
31624004Ssam 	}
31730519Ssam 	if (part >= lp->d_npartitions)
31830519Ssam 		return (ENXIO);
31930756Skarels 	dk->dk_openpart |= mask;
32030756Skarels 	switch (fmt) {
32130756Skarels 	case S_IFCHR:
32230756Skarels 		dk->dk_copenpart |= mask;
32330756Skarels 		break;
32430756Skarels 	case S_IFBLK:
32530756Skarels 		dk->dk_bopenpart |= mask;
32630756Skarels 		break;
32730756Skarels 	}
32830519Ssam 	return (0);
32925675Ssam }
33024004Ssam 
33130756Skarels vdclose(dev, flags, fmt)
33230519Ssam 	dev_t dev;
33330756Skarels 	int flags, fmt;
33424004Ssam {
33530519Ssam 	register int unit = vdunit(dev);
33630519Ssam 	register struct dksoftc *dk = &dksoftc[unit];
33730756Skarels 	int part = vdpart(dev), mask = 1 << part;
33824004Ssam 
33930756Skarels 	switch (fmt) {
34030756Skarels 	case S_IFCHR:
34130756Skarels 		dk->dk_copenpart &= ~mask;
34230756Skarels 		break;
34330756Skarels 	case S_IFBLK:
34430756Skarels 		dk->dk_bopenpart &= ~mask;
34530756Skarels 		break;
34630756Skarels 	}
34730756Skarels 	if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0)
34830756Skarels 		dk->dk_openpart &= ~mask;
34930519Ssam 	/*
35030519Ssam 	 * Should wait for i/o to complete on this partition
35130519Ssam 	 * even if others are open, but wait for work on blkflush().
35230519Ssam 	 */
35330519Ssam 	if (dk->dk_openpart == 0) {
35430573Skarels 		int s = spl7();
35530573Skarels 		while (dkutab[unit].b_actf)
35630573Skarels 			sleep((caddr_t)dk, PZERO-1);
35730519Ssam 		splx(s);
35830519Ssam 		dk->dk_state = CLOSED;
35934076Skarels 		dk->dk_wlabel = 0;
36024004Ssam 	}
36130756Skarels 	return (0);
36225675Ssam }
36324004Ssam 
36430519Ssam vdinit(dev, flags)
36530519Ssam 	dev_t dev;
36630519Ssam 	int flags;
36725675Ssam {
36830519Ssam 	register struct disklabel *lp;
36930519Ssam 	register struct dksoftc *dk;
37030519Ssam 	struct vba_device *vi;
37130519Ssam 	int unit = vdunit(dev), error = 0;
37230756Skarels 	char *msg, *readdisklabel();
37330519Ssam 	extern int cold;
37425675Ssam 
37530519Ssam 	dk = &dksoftc[unit];
37630519Ssam 	if (flags & O_NDELAY) {
37730519Ssam 		dk->dk_state = OPENRAW;
37830756Skarels 		return;
37930519Ssam 	}
38030519Ssam 	dk->dk_state = RDLABEL;
38130519Ssam 	lp = &dklabel[unit];
38230519Ssam 	vi = vddinfo[unit];
38330756Skarels 	if (msg = readdisklabel(dev, vdstrategy, lp)) {
38434076Skarels 		if (cold) {
38530601Skarels 			printf(": %s", msg);
38634076Skarels 			dk->dk_state = CLOSED;
38734076Skarels 		} else {
38832211Skarels 			log(LOG_ERR, "dk%d: %s\n", unit, msg);
38934076Skarels 			dk->dk_state = OPENRAW;
39034076Skarels 		}
39130519Ssam #ifdef COMPAT_42
39234076Skarels 		if (vdmaptype(vi, lp))
39330519Ssam 			dk->dk_state = OPEN;
39430519Ssam #endif
39530756Skarels 	} else {
39630756Skarels 		/*
39730756Skarels 		 * Now that we have the label, configure
39830756Skarels 		 * the correct drive parameters.
39930756Skarels 		 */
40032211Skarels 		if (vdreset_drive(vi))
40132211Skarels 			dk->dk_state = OPEN;
40232211Skarels 		else {
40330756Skarels 			dk->dk_state = CLOSED;
40430756Skarels 			error = ENXIO;
40532211Skarels 		}
40625675Ssam 	}
40730756Skarels #ifndef SECSIZE
40832211Skarels 	vd_setsecsize(dk, lp);
40932211Skarels #endif
41030519Ssam 	wakeup((caddr_t)dk);
41130519Ssam 	return (error);
41224004Ssam }
41324004Ssam 
41432211Skarels #ifndef SECSIZE
41532211Skarels vd_setsecsize(dk, lp)
41632211Skarels 	register struct dksoftc *dk;
41732211Skarels 	register struct disklabel *lp;
41832211Skarels {
41932211Skarels 	int mul;
42032211Skarels 
42132211Skarels 	/*
42232211Skarels 	 * Calculate scaling shift for mapping
42332211Skarels 	 * DEV_BSIZE blocks to drive sectors.
42432211Skarels 	 */
42532211Skarels 	mul = DEV_BSIZE / lp->d_secsize;
42632211Skarels 	dk->dk_bshift = 0;
42732211Skarels 	while ((mul >>= 1) > 0)
42832211Skarels 		dk->dk_bshift++;
42932211Skarels }
43032211Skarels #endif SECSIZE
43132211Skarels 
43225675Ssam /*ARGSUSED*/
43330519Ssam vddgo(vm)
43430519Ssam 	struct vba_device *vm;
43524004Ssam {
43624004Ssam 
43724004Ssam }
43824004Ssam 
43924004Ssam vdstrategy(bp)
44025675Ssam 	register struct buf *bp;
44124004Ssam {
44230519Ssam 	register struct vba_device *vi;
44330519Ssam 	register struct disklabel *lp;
44430519Ssam 	register struct dksoftc *dk;
44530519Ssam 	register int unit;
44630573Skarels 	register daddr_t sn;
44730519Ssam 	struct buf *dp;
44830573Skarels 	daddr_t sz, maxsz;
44930519Ssam 	int part, s;
45024004Ssam 
45130519Ssam 	unit = vdunit(bp->b_dev);
45232211Skarels 	if (unit >= NDK) {
45329954Skarels 		bp->b_error = ENXIO;
45425675Ssam 		goto bad;
45529954Skarels 	}
45630519Ssam 	vi = vddinfo[unit];
45730519Ssam 	lp = &dklabel[unit];
45830519Ssam 	if (vi == 0 || vi->ui_alive == 0) {
45930519Ssam 		bp->b_error = ENXIO;
46030519Ssam 		goto bad;
46130519Ssam 	}
46230519Ssam 	dk = &dksoftc[unit];
46330519Ssam 	if (dk->dk_state < OPEN)
46430519Ssam 		goto q;
46534076Skarels 	if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) {
46634076Skarels 		bp->b_error = EROFS;
46734076Skarels 		goto bad;
46834076Skarels 	}
46930519Ssam 	part = vdpart(bp->b_dev);
47030519Ssam 	if ((dk->dk_openpart & (1 << part)) == 0) {
47130519Ssam 		bp->b_error = ENODEV;
47230519Ssam 		goto bad;
47330519Ssam 	}
47432211Skarels 	sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
47530519Ssam 	maxsz = lp->d_partitions[part].p_size;
47630756Skarels #ifndef SECSIZE
47730756Skarels 	sn = bp->b_blkno << dk->dk_bshift;
47830756Skarels #else SECSIZE
47930573Skarels 	sn = bp->b_blkno;
48030756Skarels #endif SECSIZE
48134076Skarels 	if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR &&
48234076Skarels #if LABELSECTOR != 0
48334076Skarels 	    sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR &&
48434076Skarels #endif
48534076Skarels 	    (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) {
48634076Skarels 		bp->b_error = EROFS;
48734076Skarels 		goto bad;
48834076Skarels 	}
48930519Ssam 	if (sn < 0 || sn + sz > maxsz) {
49030519Ssam 		if (sn == maxsz) {
49129954Skarels 			bp->b_resid = bp->b_bcount;
49229954Skarels 			goto done;
49329954Skarels 		}
49430756Skarels 		sz = maxsz - sn;
49530573Skarels 		if (sz <= 0) {
49630573Skarels 			bp->b_error = EINVAL;
49730573Skarels 			goto bad;
49830573Skarels 		}
49930573Skarels 		bp->b_bcount = sz * lp->d_secsize;
50025675Ssam 	}
50130519Ssam 	bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl;
50230756Skarels #ifdef SECSIZE
50330756Skarels if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0)
50430756Skarels panic("vdstrat blksize");
50530756Skarels #endif SECSIZE
50630519Ssam q:
50725675Ssam 	s = spl7();
50830519Ssam 	dp = &dkutab[vi->ui_unit];
50930519Ssam 	disksort(dp, bp);
51030519Ssam 	if (!dp->b_active) {
51130519Ssam 		(void) vdustart(vi);
51230573Skarels 		if (!vi->ui_mi->um_tab.b_active)
51330519Ssam 			vdstart(vi->ui_mi);
51424004Ssam 	}
51530519Ssam 	splx(s);
51624004Ssam 	return;
51725675Ssam bad:
51829954Skarels 	bp->b_flags |= B_ERROR;
51929954Skarels done:
52030519Ssam 	biodone(bp);
52130519Ssam 	return;
52224004Ssam }
52324004Ssam 
52430519Ssam vdustart(vi)
52530519Ssam 	register struct vba_device *vi;
52624004Ssam {
52730519Ssam 	register struct buf *bp, *dp;
52830519Ssam 	register struct vba_ctlr *vm;
52930519Ssam 	register int unit = vi->ui_unit;
53030519Ssam 	register struct dksoftc *dk;
53130519Ssam 	register struct vdsoftc *vd;
53230519Ssam 	struct disklabel *lp;
53324004Ssam 
53430519Ssam 	dp = &dkutab[unit];
53530519Ssam 	/*
53630519Ssam 	 * If queue empty, nothing to do.
53730519Ssam 	 */
53830519Ssam 	if ((bp = dp->b_actf) == NULL)
53930519Ssam 		return;
54030519Ssam 	/*
54130574Skarels 	 * If drive is off-cylinder and controller supports seeks,
54230574Skarels 	 * place drive on seek queue for controller.
54330574Skarels 	 * Otherwise, place on transfer queue.
54430519Ssam 	 */
54530519Ssam 	vd = &vdsoftc[vi->ui_ctlr];
54630519Ssam 	dk = &dksoftc[unit];
54730574Skarels 	vm = vi->ui_mi;
54830519Ssam 	if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) {
54930519Ssam 		lp = &dklabel[unit];
55030574Skarels 		bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors;
55130574Skarels 		if (vm->um_tab.b_seekf == NULL)
55230574Skarels 			vm->um_tab.b_seekf = dp;
55330574Skarels 		else
55430574Skarels 			vm->um_tab.b_seekl->b_forw = dp;
55530574Skarels 		vm->um_tab.b_seekl = dp;
55630574Skarels 	} else {
55730574Skarels 		if (vm->um_tab.b_actf == NULL)
55830574Skarels 			vm->um_tab.b_actf = dp;
55930574Skarels 		else
56030574Skarels 			vm->um_tab.b_actl->b_forw = dp;
56130574Skarels 		vm->um_tab.b_actl = dp;
56230519Ssam 	}
56330573Skarels 	dp->b_forw = NULL;
56430573Skarels 	dp->b_active++;
56525675Ssam }
56625675Ssam 
56725675Ssam /*
56830519Ssam  * Start next transfer on a controller.
56930574Skarels  * There are two queues of drives, the first on-cylinder
57030574Skarels  * and the second off-cylinder from their next transfers.
57130574Skarels  * Perform the first transfer for the first drive on the on-cylinder
57230574Skarels  * queue, if any, otherwise the first transfer for the first drive
57330574Skarels  * on the second queue.  Initiate seeks on remaining drives on the
57430574Skarels  * off-cylinder queue, then move them all to the on-cylinder queue.
57525675Ssam  */
57630519Ssam vdstart(vm)
57730519Ssam 	register struct vba_ctlr *vm;
57825675Ssam {
57925675Ssam 	register struct buf *bp;
58030519Ssam 	register struct vba_device *vi;
58130519Ssam 	register struct vdsoftc *vd;
58230519Ssam 	register struct dksoftc *dk;
58330519Ssam 	register struct disklabel *lp;
58430519Ssam 	register struct dcb **dcbp;
58530519Ssam 	struct mdcb *mdcb;
58630519Ssam 	struct buf *dp;
58730519Ssam 	int sn, tn;
58825675Ssam 
58930519Ssam loop:
59030519Ssam 	/*
59130519Ssam 	 * Pull a request off the controller queue.
59230519Ssam 	 */
59330574Skarels 	if ((dp = vm->um_tab.b_actf) == NULL &&
59430574Skarels 	    (dp = vm->um_tab.b_seekf) == NULL)
59530519Ssam 		return;
59630519Ssam 	if ((bp = dp->b_actf) == NULL) {
59730601Skarels 		if (dp == vm->um_tab.b_actf)
59830601Skarels 			vm->um_tab.b_actf = dp->b_forw;
59930601Skarels 		else
60030601Skarels 			vm->um_tab.b_seekf = dp->b_forw;
60130519Ssam 		goto loop;
60230519Ssam 	}
60325675Ssam 
60424004Ssam 	/*
60530519Ssam 	 * Mark controller busy, and determine
60630519Ssam 	 * destination of this request.
60724004Ssam 	 */
60830519Ssam 	vm->um_tab.b_active++;
60930519Ssam 	vi = vddinfo[vdunit(bp->b_dev)];
61030519Ssam 	dk = &dksoftc[vi->ui_unit];
61130756Skarels #ifndef SECSIZE
61230756Skarels 	sn = bp->b_blkno << dk->dk_bshift;
61330756Skarels #else SECSIZE
61430573Skarels 	sn = bp->b_blkno;
61530756Skarels #endif SECSIZE
61630519Ssam 	lp = &dklabel[vi->ui_unit];
61730519Ssam 	sn %= lp->d_secpercyl;
61830519Ssam 	tn = sn / lp->d_nsectors;
61930519Ssam 	sn %= lp->d_nsectors;
62030519Ssam 
62130519Ssam 	/*
62230519Ssam 	 * Construct dcb for read/write command.
62330519Ssam 	 */
62430519Ssam 	vd = &vdsoftc[vm->um_ctlr];
62530519Ssam 	vd->vd_dcb.intflg = DCBINT_DONE;
62632211Skarels 	vd->vd_dcb.devselect = dk->dk_dcb.devselect;
62730519Ssam 	vd->vd_dcb.operrsta = 0;
62830519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
62930519Ssam 	vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin;
63030519Ssam 	vd->vd_dcb.trail.rwtrail.disk.track = tn;
63130519Ssam 	vd->vd_dcb.trail.rwtrail.disk.sector = sn;
63230574Skarels 	dk->dk_curcyl = bp->b_cylin;
63330574Skarels 	bp->b_track = 0;		/* init overloaded field */
63430756Skarels 	vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
635*34396Skarels 	if (bp->b_flags & B_FORMAT)
636*34396Skarels 		vd->vd_dcb.opcode = dk->dk_op;
637*34396Skarels 	else if (vd->vd_flags & VD_SCATGATH &&
638*34396Skarels 	    ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0)
63930756Skarels 		vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW;
640*34396Skarels 	else
64130756Skarels 		vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD;
642*34396Skarels 
643*34396Skarels 	switch (vd->vd_dcb.opcode) {
644*34396Skarels 	case VDOP_FSECT:
645*34396Skarels 		vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
646*34396Skarels 		vd->vd_dcb.trail.fmtrail.nsectors = bp->b_bcount /
647*34396Skarels 		    lp->d_secsize;
648*34396Skarels 		vd->vd_dcb.trail.fmtrail.hdr = *(dskadr *)&dk->dk_althdr;
649*34396Skarels 		vd->vd_dcb.trail.rwtrail.disk.cylinder |= dk->dk_fmtflags;
650*34396Skarels 		goto setupaddr;
651*34396Skarels 
652*34396Skarels 	case VDOP_RDRAW:
653*34396Skarels 	case VDOP_RD:
654*34396Skarels 	case VDOP_WD:
655*34396Skarels 		vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1;
656*34396Skarels setupaddr:
65730756Skarels 		vd->vd_dcb.trail.rwtrail.memadr =
65830756Skarels 			vbasetup(bp, &vd->vd_rbuf, lp->d_secsize);
659*34396Skarels 		break;
660*34396Skarels 
661*34396Skarels 	case VDOP_RAS:
662*34396Skarels 	case VDOP_GAW:
663*34396Skarels 		vd->vd_dcb.trailcnt += vba_sgsetup(bp, &vd->vd_rbuf,
664*34396Skarels 		    &vd->vd_dcb.trail.sgtrail);
665*34396Skarels 		break;
66630756Skarels 	}
66730574Skarels 	if (vi->ui_dk >= 0) {
66830574Skarels 		dk_busy |= 1<<vi->ui_dk;
66930574Skarels 		dk_xfer[vi->ui_dk]++;
67030574Skarels 		dk_wds[vi->ui_dk] += bp->b_bcount>>6;
67130574Skarels 	}
67230519Ssam 
67330519Ssam 	/*
67430519Ssam 	 * Look for any seeks to be performed on other drives on this
67530519Ssam 	 * controller.  If overlapped seeks exist, insert seek commands
67630519Ssam 	 * on the controller's command queue before the transfer.
67730519Ssam 	 */
67830519Ssam 	dcbp = &vd->vd_mdcb.mdcb_head;
67930519Ssam 
68030574Skarels 	if (dp == vm->um_tab.b_seekf)
68130574Skarels 		dp = dp->b_forw;
68230574Skarels 	else
68330574Skarels 		dp = vm->um_tab.b_seekf;
68430574Skarels 	for (; dp != NULL; dp = dp->b_forw) {
68530574Skarels 		if ((bp = dp->b_actf) == NULL)
68630574Skarels 			continue;
68730574Skarels 		vi = vddinfo[vdunit(bp->b_dev)];
68830574Skarels 		dk = &dksoftc[vi->ui_unit];
68930519Ssam 		dk->dk_curcyl = bp->b_cylin;
69030574Skarels 		if (vi->ui_dk >= 0)
69130574Skarels 			dk_seek[vi->ui_dk]++;
69230574Skarels 		dk->dk_dcb.operrsta = 0;
69330574Skarels 		dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin;
69430574Skarels 		dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track;
69530574Skarels 		*dcbp = (struct dcb *)dk->dk_dcbphys;
69630574Skarels 		dcbp = &dk->dk_dcb.nxtdcb;
69724004Ssam 	}
69830519Ssam 	*dcbp = (struct dcb *)vd->vd_dcbphys;
69930574Skarels 	if (vm->um_tab.b_actf)
70030574Skarels 		vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf;
70130574Skarels 	else
70230574Skarels 		vm->um_tab.b_actf = vm->um_tab.b_seekf;
70330601Skarels 	if (vm->um_tab.b_seekf)
70430601Skarels 		vm->um_tab.b_actl = vm->um_tab.b_seekl;
70530574Skarels 	vm->um_tab.b_seekf = 0;
70624004Ssam 
70730519Ssam 	/*
70830519Ssam 	 * Initiate operation.
70930519Ssam 	 */
71030519Ssam 	vd->vd_mdcb.mdcb_status = 0;
71130519Ssam 	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
71224004Ssam }
71324004Ssam 
71430519Ssam #define	DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE)
71524004Ssam /*
71624004Ssam  * Handle a disk interrupt.
71724004Ssam  */
71825675Ssam vdintr(ctlr)
71930519Ssam 	register ctlr;
72024004Ssam {
72130519Ssam 	register struct buf *bp, *dp;
72230519Ssam 	register struct vba_ctlr *vm = vdminfo[ctlr];
72330519Ssam 	register struct vba_device *vi;
72430519Ssam 	register struct vdsoftc *vd = &vdsoftc[ctlr];
72530519Ssam 	register status;
726*34396Skarels 	int ecode, timedout;
72730573Skarels 	struct dksoftc *dk;
72824004Ssam 
72930519Ssam 	if (!vm->um_tab.b_active) {
73025675Ssam 		printf("vd%d: stray interrupt\n", ctlr);
73124004Ssam 		return;
73224004Ssam 	}
73325675Ssam 	/*
73430519Ssam 	 * Get device and block structures, and a pointer
73530519Ssam 	 * to the vba_device for the drive.
73625675Ssam 	 */
73730519Ssam 	dp = vm->um_tab.b_actf;
73830519Ssam 	bp = dp->b_actf;
73930519Ssam 	vi = vddinfo[vdunit(bp->b_dev)];
74030574Skarels 	if (vi->ui_dk >= 0)
74130574Skarels 		dk_busy &= ~(1<<vi->ui_dk);
742*34396Skarels 	timedout = (vd->vd_wticks >= VDMAXTIME);
74330519Ssam 	/*
74430519Ssam 	 * Check for and process errors on
74530519Ssam 	 * either the drive or the controller.
74630519Ssam 	 */
74730519Ssam 	uncache(&vd->vd_dcb.operrsta);
74830519Ssam 	status = vd->vd_dcb.operrsta;
749*34396Skarels 	if (bp->b_flags & B_FORMAT) {
750*34396Skarels 		dk->dk_operrsta = status;
751*34396Skarels 		uncache(&vd->vd_dcb.err_code);
752*34396Skarels 		dk->dk_ecode = vd->vd_dcb.err_code;
753*34396Skarels 	}
754*34396Skarels 	if (status & VDERR_HARD || timedout) {
75530601Skarels 		if (vd->vd_type == VDTYPE_SMDE) {
75630601Skarels 			uncache(&vd->vd_dcb.err_code);
75730601Skarels 			ecode = vd->vd_dcb.err_code;
75830601Skarels 		}
75930519Ssam 		if (status & DCBS_WPT) {
76030519Ssam 			/*
76130519Ssam 			 * Give up on write locked devices immediately.
76230519Ssam 			 */
76330573Skarels 			printf("dk%d: write locked\n", vi->ui_unit);
76430519Ssam 			bp->b_flags |= B_ERROR;
765*34396Skarels 		} else if (status & VDERR_RETRY || timedout) {
76632211Skarels 			int endline = 1;
76732211Skarels 
768*34396Skarels 			if (status & VDERR_CTLR || timedout) {
769*34396Skarels 				vdharderr("controller err",
770*34396Skarels 				    vd, bp, &vd->vd_dcb);
771*34396Skarels 				printf("; resetting controller...");
772*34396Skarels 				vdreset_ctlr(vm);
773*34396Skarels 			} else if (status & VDERR_DRIVE) {
774*34396Skarels 				vdharderr("drive err", vd, bp, &vd->vd_dcb);
775*34396Skarels 				printf("; resetting drive...");
77630519Ssam 				if (!vdreset_drive(vi))
77730519Ssam 					vi->ui_alive = 0;
77832211Skarels 			} else
77932211Skarels 				endline = 0;
78030519Ssam 			/*
78130519Ssam 			 * Retry transfer once, unless reset failed.
78230519Ssam 			 */
783*34396Skarels 			if (!vi->ui_alive || dp->b_errcnt++ >= 2 ||
784*34396Skarels 			    bp->b_flags & B_FORMAT) {
78532211Skarels 				if (endline)
78632211Skarels 					printf("\n");
78730519Ssam 				goto hard;
78832211Skarels 			}
78932211Skarels 
79032211Skarels 			if (endline)
79132211Skarels 				printf(" retrying\n");
79230519Ssam 			vm->um_tab.b_active = 0;	/* force retry */
79330519Ssam 		} else  {
79430519Ssam 	hard:
79530519Ssam 			bp->b_flags |= B_ERROR;
796*34396Skarels 			vdharderr("hard error", vd, bp, &vd->vd_dcb);
79730519Ssam 			printf("\n");
79830519Ssam 		}
79930519Ssam 	} else if (status & DCBS_SOFT)
80030519Ssam 		vdsofterr(vd, bp, &vd->vd_dcb);
801*34396Skarels 	vd->vd_wticks = 0;
80230519Ssam 	if (vm->um_tab.b_active) {
80330519Ssam 		vm->um_tab.b_active = 0;
80430519Ssam 		vm->um_tab.b_actf = dp->b_forw;
80530519Ssam 		dp->b_active = 0;
80630519Ssam 		dp->b_errcnt = 0;
80730519Ssam 		dp->b_actf = bp->av_forw;
80830519Ssam 		bp->b_resid = 0;
80930601Skarels 		vbadone(bp, &vd->vd_rbuf);
81030519Ssam 		biodone(bp);
81130370Skarels 		/*
81230519Ssam 		 * If this unit has more work to do,
81330519Ssam 		 * then start it up right away.
81430370Skarels 		 */
81530519Ssam 		if (dp->b_actf)
81630519Ssam 			vdustart(vi);
81730573Skarels 		else if ((dk = &dksoftc[vi->ui_unit])->dk_openpart == 0)
81830573Skarels 			wakeup((caddr_t)dk);
81924004Ssam 	}
82025675Ssam 	/*
82130519Ssam 	 * If there are devices ready to
82230519Ssam 	 * transfer, start the controller.
82325675Ssam 	 */
82430601Skarels 	if (vm->um_tab.b_actf || vm->um_tab.b_seekf)
82530519Ssam 		vdstart(vm);
82624004Ssam }
82724004Ssam 
828*34396Skarels vdharderr(what, vd, bp, dcb)
829*34396Skarels 	char *what;
830*34396Skarels 	struct vdsoftc *vd;
831*34396Skarels 	register struct buf *bp;
832*34396Skarels 	register struct dcb *dcb;
833*34396Skarels {
834*34396Skarels 	int unit = vdunit(bp->b_dev), status = dcb->operrsta;
835*34396Skarels 	int part = vdpart(bp->b_dev);
836*34396Skarels 	register struct disklabel *lp = &dklabel[unit];
837*34396Skarels 	char partname = 'a' + part;
838*34396Skarels 	int sn;
839*34396Skarels 
840*34396Skarels 	if (vd->vd_wticks < VDMAXTIME)
841*34396Skarels 		status &= ~DONTCARE;
842*34396Skarels /* generic
843*34396Skarels 	sn = bp->b_blkno + lp->d_partitions[part].p_offset;
844*34396Skarels */
845*34396Skarels 	sn = ((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk)
846*34396Skarels 	    * lp->d_nsectors + dcb->err_sec;
847*34396Skarels 	printf("dk%d%c: %s bn [%d-%d) (sn %d), status %b",
848*34396Skarels 	    unit, partname, what, bp->b_blkno,
849*34396Skarels 	    bp->b_blkno + (bp->b_bcount - 1)/DEV_BSIZE, sn, status, VDERRBITS);
850*34396Skarels 	if (vd->vd_type == VDTYPE_SMDE)
851*34396Skarels 		printf(" ecode %x", dcb->err_code);
852*34396Skarels 	printf("\n(error sec %d trk %d cyl %d wcount %d)", dcb->err_sec,
853*34396Skarels 	    dcb->err_trk, dcb->err_cyl, dcb->err_wcount);
854*34396Skarels }
855*34396Skarels 
85630519Ssam vdsofterr(vd, bp, dcb)
85730519Ssam 	struct vdsoftc *vd;
85825675Ssam 	register struct buf *bp;
85930519Ssam 	register struct dcb *dcb;
86025675Ssam {
86130519Ssam 	int unit = vdunit(bp->b_dev), status = dcb->operrsta;
862*34396Skarels 	int part = vdpart(bp->b_dev);
863*34396Skarels 	char partname = 'a' + part;
864*34396Skarels 	int sn = (bp->b_blkno << dksoftc[unit].dk_bshift) +
865*34396Skarels 	    dklabel[unit].d_partitions[part].p_offset;
86625675Ssam 
86732211Skarels 	if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE))
868*34396Skarels 		log(LOG_WARNING,
869*34396Skarels 		    "dk%d%c: soft error sn %d bn %d, status %b ecode %x\n",
870*34396Skarels 		    unit, partname, sn, bp->b_blkno, status, VDERRBITS,
871*34396Skarels 		    dcb->err_code);
87232211Skarels 	else
873*34396Skarels 		log(LOG_WARNING, "dk%d%c: soft ecc sn %d bn %d\n",
874*34396Skarels 		    unit, part, sn, bp->b_blkno);
87525675Ssam }
87625675Ssam 
87730519Ssam vdioctl(dev, cmd, data, flag)
87825675Ssam 	dev_t dev;
87930519Ssam 	int cmd;
88030519Ssam 	caddr_t data;
88130519Ssam 	int flag;
88224004Ssam {
88332576Skarels 	register int unit = vdunit(dev);
88430519Ssam 	register struct disklabel *lp = &dklabel[unit];
88534076Skarels 	register struct dksoftc *dk = &dksoftc[unit];
886*34396Skarels 	int error = 0, wlab, vdformat();
88724004Ssam 
88830519Ssam 	switch (cmd) {
88930519Ssam 
89030519Ssam 	case DIOCGDINFO:
89130519Ssam 		*(struct disklabel *)data = *lp;
89230519Ssam 		break;
89330519Ssam 
89430573Skarels 	case DIOCGPART:
89530573Skarels 		((struct partinfo *)data)->disklab = lp;
89630573Skarels 		((struct partinfo *)data)->part =
89730573Skarels 		    &lp->d_partitions[vdpart(dev)];
89830519Ssam 		break;
89930519Ssam 
90030519Ssam 	case DIOCSDINFO:
90130519Ssam 		if ((flag & FWRITE) == 0)
90230519Ssam 			error = EBADF;
90330519Ssam 		else
90432576Skarels 			error = setdisklabel(lp, (struct disklabel *)data,
90534076Skarels 			    (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart);
906*34396Skarels 		if (error == 0 && dk->dk_state == OPENRAW &&
907*34396Skarels 		    vdreset_drive(vddinfo[unit]))
90834076Skarels 			dk->dk_state = OPEN;
90930519Ssam 		break;
91030519Ssam 
91134076Skarels 	case DIOCWLABEL:
91234076Skarels 		if ((flag & FWRITE) == 0)
91334076Skarels 			error = EBADF;
91434076Skarels 		else
91534076Skarels 			dk->dk_wlabel = *(int *)data;
91634076Skarels 		break;
91734076Skarels 
91832576Skarels 	case DIOCWDINFO:
91934076Skarels 		/* simulate opening partition 0 so write succeeds */
92034076Skarels 		dk->dk_openpart |= (1 << 0);		/* XXX */
92134076Skarels 		wlab = dk->dk_wlabel;
92234076Skarels 		dk->dk_wlabel = 1;
92332576Skarels 		if ((flag & FWRITE) == 0)
92430519Ssam 			error = EBADF;
92532576Skarels 		else if ((error = setdisklabel(lp, (struct disklabel *)data,
92634076Skarels 		    (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) {
92734076Skarels 			dk->dk_state = OPEN;
92832576Skarels 			error = writedisklabel(dev, vdstrategy, lp);
92934076Skarels 		}
93034076Skarels 		dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;
93134076Skarels 		dk->dk_wlabel = wlab;
93230519Ssam 		break;
93330519Ssam 
934*34396Skarels 	case DIOCWFORMAT:
935*34396Skarels 	    {
936*34396Skarels 		register struct format_op *fop;
937*34396Skarels 		struct uio auio;
938*34396Skarels 		struct iovec aiov;
939*34396Skarels 
940*34396Skarels 		if ((flag & FWRITE) == 0) {
941*34396Skarels 			error = EBADF;
942*34396Skarels 			break;
943*34396Skarels 		}
944*34396Skarels 		fop = (struct format_op *)data;
945*34396Skarels 		aiov.iov_base = fop->df_buf;
946*34396Skarels 		aiov.iov_len = fop->df_count;
947*34396Skarels 		auio.uio_iov = &aiov;
948*34396Skarels 		auio.uio_iovcnt = 1;
949*34396Skarels 		auio.uio_resid = fop->df_count;
950*34396Skarels 		auio.uio_segflg = UIO_USERSPACE;
951*34396Skarels 		auio.uio_offset = fop->df_startblk * lp->d_secsize;
952*34396Skarels 		dk->dk_operrsta = fop->dk_operrsta;
953*34396Skarels 		dk->dk_ecode = fop->dk_ecode;
954*34396Skarels 		/*
955*34396Skarels 		 * Don't return errors, as the format op won't get copied
956*34396Skarels 		 * out if we return nonzero.  Callers must check the returned
957*34396Skarels 		 * count.
958*34396Skarels 		 */
959*34396Skarels 		(void) physio(vdformat, (struct buf *)NULL, dev,
960*34396Skarels 		    (cmd == DIOCWFORMAT ? B_WRITE : B_READ), minphys, &auio);
961*34396Skarels 		fop->df_count -= auio.uio_resid;
962*34396Skarels 		fop->dk_operrsta = dk->dk_operrsta;
963*34396Skarels 		fop->dk_ecode = dk->dk_ecode;
964*34396Skarels 		break;
965*34396Skarels 	    }
966*34396Skarels 
96730519Ssam 	default:
96830519Ssam 		error = ENOTTY;
96930519Ssam 		break;
97024004Ssam 	}
97132606Skarels 	return (error);
97224004Ssam }
97324004Ssam 
974*34396Skarels vdformat(bp)
975*34396Skarels 	struct buf *bp;
976*34396Skarels {
977*34396Skarels 	bp->b_flags |= B_FORMAT;
978*34396Skarels 	vdstrategy(bp);
979*34396Skarels }
980*34396Skarels 
98125675Ssam /*
98230519Ssam  * Watch for lost interrupts.
98325675Ssam  */
98430519Ssam vdwatch()
98530519Ssam {
98630519Ssam 	register struct vdsoftc *vd;
98730519Ssam 	register struct vba_ctlr *vm;
98825675Ssam 	register int ctlr, unit;
989*34396Skarels 	int s;
99030519Ssam 
99130519Ssam 	timeout(vdwatch, (caddr_t)0, hz);
99230519Ssam 	for (ctlr = 0; ctlr < NVD; ctlr++) {
99330519Ssam 		vm = vdminfo[ctlr];
99430519Ssam 		if (vm == 0 || vm->um_alive == 0)
99530519Ssam 			continue;
99630519Ssam 		vd = &vdsoftc[ctlr];
997*34396Skarels 		s = spl7();
998*34396Skarels 		if (vm->um_tab.b_active && vd->vd_wticks++ >= VDMAXTIME) {
99930519Ssam 			printf("vd%d: lost interrupt\n", ctlr);
1000*34396Skarels #ifdef maybe
1001*34396Skarels 			VDABORT((struct vddevice *)vm->um_addr, vd->vd_type);
1002*34396Skarels #endif
1003*34396Skarels 			vdintr(ctlr);
100430519Ssam 		}
1005*34396Skarels 		splx(s);
100630519Ssam 	}
100730519Ssam }
100830519Ssam 
100930519Ssam #define	DBSIZE	64	/* controller limit with 1K sectors */
101030519Ssam /*
101130519Ssam  * Crash dump.
101230519Ssam  */
101330519Ssam vddump(dev)
101430519Ssam 	dev_t dev;
101524004Ssam {
101630519Ssam 	register struct vba_device *vi;
101730519Ssam 	register struct vba_ctlr *vm;
101830519Ssam 	register struct disklabel *lp;
101930519Ssam 	register struct vdsoftc *vd;
102030519Ssam 	struct dksoftc *dk;
102130519Ssam 	int part, unit, num;
102230601Skarels 	u_long start;
102324004Ssam 
102430519Ssam 	start = 0;
102530519Ssam 	unit = vdunit(dev);
102630519Ssam 	if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
102730519Ssam 		return (ENXIO);
102830519Ssam 	dk = &dksoftc[unit];
102934076Skarels 	if (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
103034076Skarels 	    vdinit(vdminor(unit, 0), 0) != 0)
103130519Ssam 		return (ENXIO);
103230519Ssam 	lp = &dklabel[unit];
103330519Ssam 	part = vdpart(dev);
103430519Ssam 	if (part >= lp->d_npartitions)
103530519Ssam 		return (ENXIO);
103632211Skarels 	vm = vi->ui_mi;
103730519Ssam 	vdreset_ctlr(vm);
103830519Ssam 	if (dumplo < 0)
103930519Ssam 		return (EINVAL);
104030519Ssam 	/*
104130756Skarels 	 * Maxfree is in pages, dumplo is in DEV_BSIZE units.
104230519Ssam 	 */
104330519Ssam 	num = maxfree * (NBPG / lp->d_secsize);
104430756Skarels 	dumplo *= DEV_BSIZE / lp->d_secsize;
104530519Ssam 	if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size)
104630519Ssam 		num = lp->d_partitions[vdpart(dev)].p_size - dumplo;
104730519Ssam 	vd = &vdsoftc[vm->um_ctlr];
104830519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
104930519Ssam 	vd->vd_dcb.opcode = VDOP_WD;
105032211Skarels 	vd->vd_dcb.devselect = dk->dk_dcb.devselect;
105130756Skarels 	vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
105230519Ssam 	while (num > 0) {
105330519Ssam 		int nsec, cn, sn, tn;
105430519Ssam 
105530519Ssam 		nsec = MIN(num, DBSIZE);
105630601Skarels 		sn = dumplo + start / lp->d_secsize;
105730519Ssam 		cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) /
105830519Ssam 		    lp->d_secpercyl;
105930519Ssam 		sn %= lp->d_secpercyl;
106030519Ssam 		tn = sn / lp->d_nsectors;
106130519Ssam 		sn %= lp->d_nsectors;
106230519Ssam 		vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
106330519Ssam 		vd->vd_dcb.trail.rwtrail.memadr = start;
106430519Ssam 		vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1;
106530519Ssam 		vd->vd_dcb.trail.rwtrail.disk.cylinder = cn;
106630519Ssam 		vd->vd_dcb.trail.rwtrail.disk.track = tn;
106730519Ssam 		vd->vd_dcb.trail.rwtrail.disk.sector = sn;
106830519Ssam 		vd->vd_dcb.operrsta = 0;
106930519Ssam 		VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
107030519Ssam 		if (!vdpoll(vm, 5)) {
107130519Ssam 			printf(" during dump\n");
107230519Ssam 			return (EIO);
107330519Ssam 		}
107430519Ssam 		if (vd->vd_dcb.operrsta & VDERR_HARD) {
107530519Ssam 			printf("dk%d: hard error, status=%b\n", unit,
107630519Ssam 			    vd->vd_dcb.operrsta, VDERRBITS);
107730519Ssam 			return (EIO);
107830519Ssam 		}
107930519Ssam 		start += nsec * lp->d_secsize;
108030519Ssam 		num -= nsec;
108125675Ssam 	}
108230519Ssam 	return (0);
108324004Ssam }
108424004Ssam 
108524004Ssam vdsize(dev)
108625675Ssam 	dev_t dev;
108724004Ssam {
108830519Ssam 	register int unit = vdunit(dev);
108930519Ssam 	register struct dksoftc *dk;
109030519Ssam 	struct vba_device *vi;
109130519Ssam 	struct disklabel *lp;
109224004Ssam 
109330519Ssam 	if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 ||
109430519Ssam 	    (dk = &dksoftc[unit])->dk_state != OPEN)
109525675Ssam 		return (-1);
109630519Ssam 	lp = &dklabel[unit];
109730756Skarels #ifdef SECSIZE
109830573Skarels 	return ((int)lp->d_partitions[vdpart(dev)].p_size);
109930756Skarels #else SECSIZE
110030756Skarels 	return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift);
110130756Skarels #endif SECSIZE
110224004Ssam }
110324004Ssam 
110425675Ssam /*
110525675Ssam  * Perform a controller reset.
110625675Ssam  */
110730519Ssam vdreset_ctlr(vm)
110830519Ssam 	register struct vba_ctlr *vm;
110924004Ssam {
111030519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
111130519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
111230519Ssam 	register int unit;
111330519Ssam 	struct vba_device *vi;
111425675Ssam 
111530519Ssam 	VDRESET(vdaddr, vd->vd_type);
111630519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
111730519Ssam 		vdaddr->vdcsr = 0;
111830519Ssam 		vdaddr->vdtcf_mdcb = AM_ENPDA;
111930519Ssam 		vdaddr->vdtcf_dcb = AM_ENPDA;
112030519Ssam 		vdaddr->vdtcf_trail = AM_ENPDA;
112130519Ssam 		vdaddr->vdtcf_data = AM_ENPDA;
112230519Ssam 		vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
112325675Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
112425675Ssam 	}
112530519Ssam 	if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) {
112630519Ssam 		printf("%s cmd failed\n",
112730519Ssam 		    vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
112830370Skarels 		return;
112925675Ssam 	}
113030519Ssam 	for (unit = 0; unit < NDK; unit++)
113130519Ssam 		if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive)
113230519Ssam 			(void) vdreset_drive(vi);
113330519Ssam }
113430519Ssam 
113530519Ssam vdreset_drive(vi)
113630519Ssam 	register struct vba_device *vi;
113730519Ssam {
113830519Ssam 	register struct disklabel *lp = &dklabel[vi->ui_unit];
113930519Ssam 	struct vba_ctlr *vm = vdminfo[vi->ui_ctlr];
114030519Ssam 	struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
114132211Skarels 	register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
114232211Skarels 	register struct dksoftc *dk = &dksoftc[vi->ui_unit];
114330519Ssam 
114430519Ssam top:
114530519Ssam 	vd->vd_dcb.opcode = VDOP_CONFIG;		/* command */
114630519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
114730519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
114830519Ssam 	vd->vd_dcb.operrsta = 0;
114932211Skarels 	vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags;
115030519Ssam 	vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders;
115130519Ssam 	vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks;
115230519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
115330756Skarels 		vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long);
115430519Ssam 		vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors;
115530601Skarels 		vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack;
115632211Skarels 		vd->vd_dcb.trail.rstrail.recovery = VDRF_NORMAL;
115730519Ssam 	} else
115830519Ssam 		vd->vd_dcb.trailcnt = 2;		/* XXX */
115930519Ssam 	vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
116030519Ssam 	vd->vd_mdcb.mdcb_status = 0;
116130519Ssam 	VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type);
116230519Ssam 	if (!vdpoll(vm, 5)) {
116330519Ssam 		printf(" during config\n");
116430519Ssam 		return (0);
116525675Ssam 	}
116630519Ssam 	if (vd->vd_dcb.operrsta & VDERR_HARD) {
116732211Skarels 		if (vd->vd_type == VDTYPE_SMDE) {
116832211Skarels 			if (lp->d_devflags == 0) {
116932211Skarels 				lp->d_devflags = VD_ESDI;
117032211Skarels 				goto top;
117132211Skarels 			}
117232211Skarels #ifdef notdef
117332211Skarels 			/* this doesn't work, STA_US isn't set(?) */
117432211Skarels 			if ((vdaddr->vdstatus[vi->ui_slave] & STA_US) == 0)
117532211Skarels 				return (0);
117632211Skarels #endif
117732211Skarels 		}
117830519Ssam 		if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0)
117932211Skarels 			printf("dk%d: config error %b ecode %x\n", vi->ui_unit,
1180*34396Skarels 			   vd->vd_dcb.operrsta, VDERRBITS,
1181*34396Skarels 			   (u_char) vd->vd_dcb.err_code);
118232211Skarels 		else if ((vd->vd_flags & VD_STARTED) == 0) {
118330519Ssam 			int started;
118430519Ssam 
118532211Skarels 			printf(" starting drives, wait ... ");
118630519Ssam 			vd->vd_flags |= VD_STARTED;
118730519Ssam 			started = (vdcmd(vm, VDOP_START, 10) == 1);
118830519Ssam 			DELAY(62000000);
118932211Skarels 			printf("done");
119032211Skarels 			lp->d_devflags = 0;
119130519Ssam 			if (started)
119230519Ssam 				goto top;
119330519Ssam 		}
119430519Ssam 		return (0);
119530519Ssam 	}
119632211Skarels 	dk->dk_dcb.devselect |= lp->d_devflags;
119730519Ssam 	return (1);
119825675Ssam }
119924004Ssam 
120025675Ssam /*
120130519Ssam  * Perform a command w/o trailer.
120225675Ssam  */
120330519Ssam vdcmd(vm, cmd, t)
120430519Ssam 	register struct vba_ctlr *vm;
120525675Ssam {
120630519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
120725675Ssam 
120830519Ssam 	vd->vd_dcb.opcode = cmd;		/* command */
120930519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
121030519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
121130519Ssam 	vd->vd_dcb.operrsta = 0;
121230519Ssam 	vd->vd_dcb.devselect = 0;
121330519Ssam 	vd->vd_dcb.trailcnt = 0;
121430519Ssam 	vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
121530519Ssam 	vd->vd_mdcb.mdcb_status = 0;
121630519Ssam 	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
121730519Ssam 	if (!vdpoll(vm, t)) {
121830519Ssam 		printf(" during init\n");
121930370Skarels 		return (0);
122030370Skarels 	}
122130519Ssam 	return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0);
122225675Ssam }
122325675Ssam 
122425925Ssam /*
122530519Ssam  * Poll controller until operation
122630519Ssam  * completes or timeout expires.
122725925Ssam  */
122830519Ssam vdpoll(vm, t)
122930519Ssam 	register struct vba_ctlr *vm;
123025925Ssam 	register int t;
123125925Ssam {
123230519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
123330519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
123425925Ssam 
123525925Ssam 	t *= 1000;
123630370Skarels 	for (;;) {
123730519Ssam 		uncache(&vd->vd_dcb.operrsta);
123830519Ssam 		if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT))
123930370Skarels 			break;
124025925Ssam 		if (--t <= 0) {
124130519Ssam 			printf("vd%d: controller timeout", vm->um_ctlr);
124230519Ssam 			VDABORT(vdaddr, vd->vd_type);
124325925Ssam 			return (0);
124425925Ssam 		}
124530370Skarels 		DELAY(1000);
124625925Ssam 	}
124730519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
124830519Ssam 		do {
124925925Ssam 			DELAY(50);
125030519Ssam 			uncache(&vdaddr->vdcsr);
125130519Ssam 		} while (vdaddr->vdcsr & CS_GO);
125232211Skarels 	 	DELAY(300);
125332211Skarels 		uncache(&vd->vd_dcb.err_code);
125425925Ssam 	}
125525925Ssam 	DELAY(200);
125630519Ssam 	uncache(&vd->vd_dcb.operrsta);
125725925Ssam 	return (1);
125825925Ssam }
125925925Ssam 
126030519Ssam #ifdef COMPAT_42
126130519Ssam struct	vdst {
126230519Ssam 	int	nsec;		/* sectors/track */
126330519Ssam 	int	ntrack;		/* tracks/cylinder */
126430519Ssam 	int	ncyl;		/* cylinders */
126532211Skarels 	int	secsize;	/* sector size */
126630519Ssam 	char	*name;		/* type name */
126730519Ssam 	struct {
126830519Ssam 		int	off;	/* partition offset in sectors */
126930519Ssam 		int	size;	/* partition size in sectors */
127030573Skarels 	} parts[8];
127130519Ssam } vdst[] = {
127232211Skarels 	{ 66, 23, 850, 512, "NEC 800",
127332211Skarels 		{0,	 1290300},	/* a cyl   0 - 849 */
127432211Skarels 	},
127532211Skarels 	{ 48, 24, 711, 512, "xsd",
127631039Skarels 		{0,	 61056},	/* a cyl   0 - 52 */
127731039Skarels 		{61056,	 61056},	/* b cyl  53 - 105 */
127831039Skarels 		{122112, 691200}, 	/* c cyl 106 - 705 */
127931039Skarels 		{237312, 576000}, 	/* d cyl 206 - 705 */
128031039Skarels 		{352512, 460800},	/* e cyl 306 - 705 */
128131039Skarels 		{467712, 345600}, 	/* f cyl 406 - 705 */
128231039Skarels 		{582912, 230400},	/* g cyl 506 - 705 */
128331039Skarels 		{698112, 115200}	/* h cyl 606 - 705 */
128430573Skarels 	},
128532211Skarels 	{ 44, 20, 842, 512, "eagle",
128630601Skarels 		{0,	 52800},	/* egl0a cyl   0 - 59 */
128730601Skarels 		{52800,	 66000},	/* egl0b cyl  60 - 134 */
128830601Skarels 		{118800, 617760}, 	/* egl0c cyl 135 - 836 */
128930756Skarels 		{736560, 4400}, 	/* egl0d cyl 837 - 841 */
129031039Skarels 		{0, 	 736560},	/* egl0e cyl   0 - 836 */
129131039Skarels 		{0, 	 740960}, 	/* egl0f cyl   0 - 841 */
129230601Skarels 		{118800, 310640},	/* egl0g cyl 135 - 487 */
129330601Skarels 		{429440, 307120}	/* egl0h cyl 488 - 836 */
129430573Skarels 	},
129532211Skarels 	{ 64, 10, 823, 512, "fuj",
129631039Skarels 		{0,	 38400},	/* fuj0a cyl   0 - 59 */
129731039Skarels 		{38400,	 48000},	/* fuj0b cyl  60 - 134 */
129831039Skarels 		{86400,	 437120}, 	/* fuj0c cyl 135 - 817 */
129931039Skarels 		{159360, 364160}, 	/* fuj0d cyl 249 - 817 */
130031039Skarels 		{232320, 291200},	/* fuj0e cyl 363 - 817 */
130131039Skarels 		{305280, 218240}, 	/* fuj0f cyl 477 - 817 */
130231039Skarels 		{378240, 145280},	/* fuj0g cyl 591 - 817 */
130331039Skarels 		{451200, 72320}		/* fug0h cyl 705 - 817 */
130430573Skarels 	},
130532211Skarels 	{ 32, 24, 711, 512, "xfd",
130630756Skarels 		{ 0,	 40704 },	/* a cyl   0 - 52 */
130730756Skarels 		{ 40704, 40704 },	/* b cyl  53 - 105 */
130830756Skarels 		{ 81408, 460800 },	/* c cyl 106 - 705 */
130930756Skarels 		{ 0,	 81408 },	/* d cyl 709 - 710 (a & b) */
131030756Skarels 		{ 0,	 542208 },	/* e cyl   0 - 705 */
131130756Skarels 		{ 40704, 501504 },	/* f cyl  53 - 705 (b & c) */
131230756Skarels 		{ 81408, 230400 },	/* g cyl 106 - 405 (1/2 of c) */
131330756Skarels 		{ 311808,230400 }	/* h cyl 406 - 705 (1/2 of c) */
131430573Skarels 	},
131532211Skarels 	{ 32, 19, 823, 512, "smd",
131631039Skarels 		{0,	 40128},	/* a cyl   0-65 */
131731039Skarels 		{40128,  27360},	/* b cyl  66-110 */
131831039Skarels 		{67488,  429856},	/* c cyl 111-817 */
131931039Skarels 		{139232, 358112},	/* d cyl 229 - 817 */
132031039Skarels 		{210976, 286368},	/* e cyl 347 - 817 */
132131039Skarels 		{282720, 214624},	/* f cyl 465 - 817 */
132231039Skarels 		{354464, 142880},	/* g cyl 583 - 817 */
132331039Skarels 		{426208, 71136}		/* h cyl 701 - 817 */
132430573Skarels 	},
132532211Skarels 	{ 18, 15, 1224, 1024, "mxd",
132632211Skarels 		{0,	 21600},	/* a cyl   0-79 */
132732211Skarels 		{21600,  22410},	/* b cyl  80-162 */
132832211Skarels 		{44010,  285120},	/* c cyl 163-1217 */
132932211Skarels #ifdef notyet
133032211Skarels 		{x, 237600},	/* d cyl y - 1217 */
133132211Skarels 		{x, 190080},	/* e cyl y - 1217 */
133232211Skarels 		{x, 142560},	/* f cyl y - 1217 */
133332211Skarels 		{x, 95040},	/* g cyl y - 1217 */
133432211Skarels 		{x, 47520}		/* h cyl 701 - 817 */
133532211Skarels #endif
133632211Skarels 	},
133732211Skarels 	{ 32, 10, 823, 512, "fsd",
133830756Skarels 		{0,	 19200},	/* a cyl   0 -  59 */
133930756Skarels 		{19200,	 24000},	/* b cyl  60 - 134 */
134030756Skarels 		{43200,	 218560},	/* c cyl 135 - 817 */
134130573Skarels 	}
134230519Ssam };
134330519Ssam #define	NVDST	(sizeof (vdst) / sizeof (vdst[0]))
134430519Ssam 
134525675Ssam /*
134630519Ssam  * Construct a label for an unlabeled pack.  We
134730519Ssam  * deduce the drive type by reading from the last
134830519Ssam  * track on successively smaller drives until we
134930519Ssam  * don't get an error.
135025675Ssam  */
135130519Ssam vdmaptype(vi, lp)
135230519Ssam 	register struct vba_device *vi;
135330519Ssam 	register struct disklabel *lp;
135425675Ssam {
135530519Ssam 	register struct vdsoftc *vd;
135630519Ssam 	register struct vdst *p;
135732211Skarels 	struct vba_ctlr *vm = vi->ui_mi;
135830519Ssam 	int i;
135925675Ssam 
136030519Ssam 	vd = &vdsoftc[vi->ui_ctlr];
136130519Ssam 	for (p = vdst; p < &vdst[NVDST]; p++) {
136230519Ssam 		if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32)
136330519Ssam 			continue;
136430519Ssam 		lp->d_nsectors = p->nsec;
136530519Ssam 		lp->d_ntracks = p->ntrack;
136630519Ssam 		lp->d_ncylinders = p->ncyl;
136732211Skarels 		lp->d_secsize = p->secsize;
136830519Ssam 		if (!vdreset_drive(vi))
136930519Ssam 			return (0);
137030519Ssam 		vd->vd_dcb.opcode = VDOP_RD;
137130519Ssam 		vd->vd_dcb.intflg = DCBINT_NONE;
137230519Ssam 		vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
137332211Skarels 		vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect;
137430756Skarels 		vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
137530601Skarels 		vd->vd_dcb.trail.rwtrail.memadr =
137630601Skarels 		    vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf);
137732211Skarels 		vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short);
137830519Ssam 		vd->vd_dcb.operrsta = 0;
137930519Ssam 		vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2;
138030519Ssam 		vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1;
138130519Ssam 		vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1;
138230519Ssam 		vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
138330519Ssam 		vd->vd_mdcb.mdcb_status = 0;
138430519Ssam 		VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
138530519Ssam 		if (!vdpoll(vm, 60))
138630519Ssam 			printf(" during probe\n");
138730519Ssam 		if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0)
138830519Ssam 			break;
138924004Ssam 	}
139032211Skarels 	if (p >= &vdst[NVDST])
139130519Ssam 		return (0);
139232211Skarels 
139330573Skarels 	for (i = 0; i < 8; i++) {
139430519Ssam 		lp->d_partitions[i].p_offset = p->parts[i].off;
139530519Ssam 		lp->d_partitions[i].p_size = p->parts[i].size;
139630519Ssam 	}
139730573Skarels 	lp->d_npartitions = 8;
139830519Ssam 	lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
139930519Ssam 	lp->d_rpm = 3600;
140030519Ssam 	bcopy(p->name, lp->d_typename, 4);
140130519Ssam 	return (1);
140224004Ssam }
140330519Ssam #endif COMPAT_42
140424004Ssam #endif
1405