xref: /csrg-svn/sys/tahoe/vba/vd.c (revision 40737)
134528Skarels /*
234528Skarels  * Copyright (c) 1988 Regents of the University of California.
334528Skarels  * All rights reserved.
434528Skarels  *
535056Skarels  * This code is derived from software contributed to Berkeley by
635056Skarels  * Computer Consoles Inc.
735056Skarels  *
834528Skarels  * Redistribution and use in source and binary forms are permitted
934866Sbostic  * provided that the above copyright notice and this paragraph are
1034866Sbostic  * duplicated in all such forms and that any documentation,
1134866Sbostic  * advertising materials, and other materials related to such
1234866Sbostic  * distribution and use acknowledge that the software was developed
1334866Sbostic  * by the University of California, Berkeley.  The name of the
1434866Sbostic  * University may not be used to endorse or promote products derived
1534866Sbostic  * from this software without specific prior written permission.
1634866Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1734866Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1834866Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1934528Skarels  *
20*40737Skarels  *	@(#)vd.c	7.11 (Berkeley) 04/03/90
2134528Skarels  */
2224004Ssam 
2329564Ssam #include "dk.h"
2424004Ssam #if NVD > 0
2524004Ssam /*
2630519Ssam  * Versabus VDDC/SMDE driver.
2725675Ssam  */
2825675Ssam #include "param.h"
2925675Ssam #include "buf.h"
3025675Ssam #include "cmap.h"
3125675Ssam #include "conf.h"
3229564Ssam #include "dkstat.h"
3330519Ssam #include "disklabel.h"
3425675Ssam #include "map.h"
3530519Ssam #include "file.h"
3625675Ssam #include "systm.h"
3725675Ssam #include "user.h"
3825675Ssam #include "vmmac.h"
3925675Ssam #include "proc.h"
4030370Skarels #include "syslog.h"
4130370Skarels #include "kernel.h"
4230519Ssam #include "ioctl.h"
4330756Skarels #include "stat.h"
4424004Ssam 
4529951Skarels #include "../tahoe/cpu.h"
4629951Skarels #include "../tahoe/mtpr.h"
4729951Skarels #include "../tahoe/pte.h"
4829951Skarels 
4925675Ssam #include "../tahoevba/vbavar.h"
5025928Ssam #include "../tahoevba/vdreg.h"
5124004Ssam 
5232211Skarels #ifndef	COMPAT_42
5330519Ssam #define	COMPAT_42
5432211Skarels #endif
5534396Skarels #define	B_FORMAT	B_XXX		/* XXX */
5630519Ssam 
5730519Ssam #define vdunit(dev)	(minor(dev) >> 3)
5830519Ssam #define vdpart(dev)	(minor(dev) & 0x07)
5930519Ssam #define	vdminor(unit,part)	(((unit) << 3) | (part))
6024004Ssam 
6124004Ssam struct	vba_ctlr *vdminfo[NVD];
6229564Ssam struct  vba_device *vddinfo[NDK];
6330756Skarels int	vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy();
6434528Skarels long	vdstd[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 };
6525675Ssam struct	vba_driver vddriver =
6634528Skarels   { vdprobe, vdslave, vdattach, vddgo, vdstd, "dk", vddinfo, "vd", vdminfo };
6724004Ssam 
6824004Ssam /*
6930519Ssam  * Per-controller state.
7030519Ssam  */
7130519Ssam struct vdsoftc {
7230519Ssam 	u_short	vd_flags;
73*40737Skarels #define	VD_PRINT	0x1	/* controller info printed */
7430519Ssam #define	VD_STARTED	0x2	/* start command issued */
7530519Ssam #define	VD_DOSEEKS	0x4	/* should overlap seeks */
7630756Skarels #define	VD_SCATGATH	0x8	/* can do scatter-gather commands (correctly) */
7735082Skarels #define	VD_LOCKED	0x10	/* locked for direct controller access */
7835082Skarels #define	VD_WAIT		0x20	/* someone needs direct controller access */
7930519Ssam 	u_short	vd_type;	/* controller type */
8030519Ssam 	u_short	vd_wticks;	/* timeout */
81*40737Skarels 	u_short	vd_secsize;	/* sector size for controller */
8230519Ssam 	struct	mdcb vd_mdcb;	/* master command block */
8330519Ssam 	u_long	vd_mdcbphys;	/* physical address of vd_mdcb */
8430519Ssam 	struct	dcb vd_dcb;	/* i/o command block */
8530519Ssam 	u_long	vd_dcbphys;	/* physical address of vd_dcb */
8630601Skarels 	struct	vb_buf vd_rbuf;	/* vba resources */
8730519Ssam } vdsoftc[NVD];
8830519Ssam 
8934396Skarels #define	VDMAXTIME	20	/* max time for operation, sec. */
9034396Skarels 
9130519Ssam /*
9225675Ssam  * Per-drive state.
9325675Ssam  */
9430519Ssam struct	dksoftc {
9534076Skarels 	int	dk_state;	/* open fsm */
9630756Skarels #ifndef SECSIZE
9730756Skarels 	u_short	dk_bshift;	/* shift for * (DEV_BSIZE / sectorsize) XXX */
9830756Skarels #endif SECSIZE
9934076Skarels 	int	dk_wlabel;	/* label sector is currently writable */
10032576Skarels 	u_long	dk_copenpart;	/* character units open on this drive */
10132576Skarels 	u_long	dk_bopenpart;	/* block units open on this drive */
10232576Skarels 	u_long	dk_openpart;	/* all units open on this drive */
10330519Ssam 	u_int	dk_curcyl;	/* last selected cylinder */
10430756Skarels 	struct	skdcb dk_dcb;	/* seek command block */
10530519Ssam 	u_long	dk_dcbphys;	/* physical address of dk_dcb */
10634396Skarels 	int	df_reg[3];	/* for formatting, in-out parameters */
10730519Ssam } dksoftc[NDK];
10824004Ssam 
10924004Ssam /*
11030519Ssam  * Drive states.  Used during steps of open/initialization.
11130519Ssam  * States < OPEN (> 0) are transient, during an open operation.
11234076Skarels  * OPENRAW is used for unlabeled disks, to allow format operations.
11325675Ssam  */
11430519Ssam #define	CLOSED		0		/* disk is closed */
11530519Ssam #define	WANTOPEN	1		/* open requested, not started */
11630519Ssam #define	WANTOPENRAW	2		/* open requested, no label */
11730519Ssam #define	RDLABEL		3		/* reading pack label */
11830519Ssam #define	OPEN		4		/* intialized and ready */
11930519Ssam #define	OPENRAW		5		/* open, no label */
12024004Ssam 
12130519Ssam struct	buf dkutab[NDK];	/* i/o queue headers */
12230519Ssam struct	disklabel dklabel[NDK];	/* pack labels */
12324004Ssam 
12430519Ssam #define b_cylin	b_resid
12530574Skarels #define	b_track	b_error		/* used for seek commands */
12630574Skarels #define	b_seekf	b_forw		/* second queue on um_tab */
12730574Skarels #define	b_seekl	b_back		/* second queue on um_tab */
12830519Ssam 
12930519Ssam int	vdwstart, vdwatch();
13030519Ssam 
13124004Ssam /*
13225675Ssam  * See if the controller is really there; if so, initialize it.
13325675Ssam  */
13425857Ssam vdprobe(reg, vm)
13525857Ssam 	caddr_t reg;
13625857Ssam 	struct vba_ctlr *vm;
13725675Ssam {
13825857Ssam 	register br, cvec;		/* must be r12, r11 */
13930519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)reg;
14030519Ssam 	struct vdsoftc *vd;
14130573Skarels 	int s;
14225857Ssam 
14330370Skarels #ifdef lint
14430370Skarels 	br = 0; cvec = br; br = cvec;
14530370Skarels 	vdintr(0);
14630370Skarels #endif
14725857Ssam 	if (badaddr((caddr_t)reg, 2))
14825675Ssam 		return (0);
14930519Ssam 	vd = &vdsoftc[vm->um_ctlr];
15030519Ssam 	vdaddr->vdreset = 0xffffffff;
15125675Ssam 	DELAY(1000000);
15230519Ssam 	if (vdaddr->vdreset != (unsigned)0xffffffff) {
15330519Ssam 		vd->vd_type = VDTYPE_VDDC;
15430519Ssam 		vd->vd_flags &= ~VD_DOSEEKS;
15525675Ssam 		DELAY(1000000);
15625675Ssam 	} else {
15730519Ssam 		vd->vd_type = VDTYPE_SMDE;
15830519Ssam 		vd->vd_flags |= VD_DOSEEKS;
15930519Ssam 		vdaddr->vdrstclr = 0;
16025675Ssam 		DELAY(3000000);
16125675Ssam 	}
16230519Ssam 	vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb);
16330519Ssam 	vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb);
16430519Ssam 	vm->um_addr = reg;		/* XXX */
16530573Skarels 	s = spl7();
166*40737Skarels 	if (vdinit_ctlr(vm, vd) == 0) {
16730573Skarels 		splx(s);
16830519Ssam 		return (0);
16930519Ssam 	}
17030756Skarels 	if (vd->vd_type == VDTYPE_SMDE) {
171*40737Skarels #ifdef notdef
172*40737Skarels 		/*
173*40737Skarels 		 * Attempt PROBE to get all drive status;
174*40737Skarels 		 * we take advantage of this in vdreset_drive
175*40737Skarels 		 * to try to avoid guessing games.
176*40737Skarels 		 */
177*40737Skarels 		(void) vdcmd(vm, VDOP_PROBE, 5, 0);
178*40737Skarels #endif
179*40737Skarels 		/*
180*40737Skarels 		 * Check for scatter-gather by checking firmware date
181*40737Skarels 		 * with IDENT command.  The date is printed when
182*40737Skarels 		 * vdslave is first called, thus this must be
183*40737Skarels 		 * the last controller operation in vdprobe.
184*40737Skarels 		 */
18530756Skarels 		vd->vd_dcb.trail.idtrail.date = 0;
18635413Skarels 		if (vdcmd(vm, VDOP_IDENT, 10, 0)) {
18730756Skarels 			uncache(&vd->vd_dcb.trail.idtrail.date);
18830756Skarels 			if (vd->vd_dcb.trail.idtrail.date != 0)
18930756Skarels 				vd->vd_flags |= VD_SCATGATH;
19030756Skarels 		}
19130756Skarels 	}
19230573Skarels 	splx(s);
19325925Ssam 	/*
19425950Ssam 	 * Allocate page tables and i/o buffer.
19525925Ssam 	 */
19632211Skarels 	if (vbainit(&vd->vd_rbuf, MAXPHYS,
19732211Skarels 	    vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) {
19832211Skarels 		printf("vd%d: vbainit failed\n", vm->um_ctlr);
19932211Skarels 		return (0);
20032211Skarels 	}
20125857Ssam 	br = 0x17, cvec = 0xe0 + vm->um_ctlr;	/* XXX */
20230519Ssam 	return (sizeof (struct vddevice));
20325675Ssam }
20424004Ssam 
20524004Ssam /*
20630519Ssam  * See if a drive is really there.
20730519Ssam  *
20830519Ssam  * Can't read pack label here as various data structures
20930519Ssam  * aren't setup for doing a read in a straightforward
21030519Ssam  * manner.  Instead just probe for the drive and leave
21130519Ssam  * the pack label stuff to the attach routine.
21225675Ssam  */
21334076Skarels /* ARGSUSED */
21434076Skarels vdslave(vi, vdaddr)
21525675Ssam 	register struct vba_device *vi;
21630519Ssam 	struct vddevice *vdaddr;
21725675Ssam {
21830519Ssam 	register struct disklabel *lp = &dklabel[vi->ui_unit];
21932211Skarels 	register struct dksoftc *dk = &dksoftc[vi->ui_unit];
22030519Ssam 	struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
221*40737Skarels 	int bcd();
22224004Ssam 
223*40737Skarels 	if ((vd->vd_flags&VD_PRINT) == 0) {
22435413Skarels 		printf("vd%d: %s controller", vi->ui_ctlr,
22535413Skarels 		    vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE");
22635413Skarels 		if (vd->vd_flags & VD_SCATGATH) {
22735413Skarels 			char rev[5];
22835413Skarels 
22935413Skarels 			bcopy((caddr_t)&vd->vd_dcb.trail.idtrail.rev, rev,
23035413Skarels 			    sizeof(vd->vd_dcb.trail.idtrail.rev));
23135413Skarels 			printf(" firmware rev %s (%d-%d-%d)", rev,
232*40737Skarels 			    bcd((vd->vd_dcb.trail.idtrail.date >> 8) & 0xff),
233*40737Skarels 			    bcd(vd->vd_dcb.trail.idtrail.date & 0xff),
234*40737Skarels 			    bcd((vd->vd_dcb.trail.idtrail.date >> 16)&0xffff));
23535413Skarels 		}
23635413Skarels 		printf("\n");
237*40737Skarels 		vd->vd_flags |= VD_PRINT;
23825675Ssam 	}
23930519Ssam 
24025675Ssam 	/*
24130519Ssam 	 * Initialize label enough to do a reset on
24230519Ssam 	 * the drive.  The remainder of the default
24330519Ssam 	 * label values will be filled in in vdinit
24430519Ssam 	 * at attach time.
24525675Ssam 	 */
24632211Skarels 	if (vd->vd_type == VDTYPE_SMDE)
24732211Skarels 		lp->d_secsize = VD_MAXSECSIZE;
24832211Skarels 	else
24932211Skarels 		lp->d_secsize = VDDC_SECSIZE;
25034396Skarels 	lp->d_nsectors = 66;		/* only used on smd-e */
25134076Skarels 	lp->d_ntracks = 23;
25234396Skarels 	lp->d_ncylinders = 850;
25334396Skarels 	lp->d_secpercyl = 66*23;
25435413Skarels 	lp->d_rpm = 3600;
25534592Skarels 	lp->d_npartitions = 1;
25634592Skarels 	lp->d_partitions[0].p_offset = 0;
25734592Skarels 	lp->d_partitions[0].p_size = LABELSECTOR + 1;
25824004Ssam 
25930519Ssam 	/*
26030519Ssam 	 * Initialize invariant portion of
26130519Ssam 	 * dcb used for overlapped seeks.
26230519Ssam 	 */
26330519Ssam 	dk->dk_dcb.opcode = VDOP_SEEK;
26430519Ssam 	dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA;
26530519Ssam 	dk->dk_dcb.devselect = vi->ui_slave;
26630756Skarels 	dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long);
26730519Ssam 	dk->dk_dcb.trail.sktrail.skaddr.sector = 0;
26830519Ssam 	dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb);
26932211Skarels #ifndef SECSIZE
27032211Skarels 	vd_setsecsize(dk, lp);
27132211Skarels #endif
27232211Skarels 	return (vdreset_drive(vi));
27332211Skarels }
27432211Skarels 
275*40737Skarels static int
276*40737Skarels bcd(n)
277*40737Skarels 	register u_int n;
278*40737Skarels {
279*40737Skarels 	register int bin = 0;
280*40737Skarels 	register int mul = 1;
281*40737Skarels 
282*40737Skarels 	while (n) {
283*40737Skarels 		bin += (n & 0xf) * mul;
284*40737Skarels 		n >>= 4;
285*40737Skarels 		mul *= 10;
286*40737Skarels 	}
287*40737Skarels 	return (bin);
288*40737Skarels }
289*40737Skarels 
29032211Skarels vdattach(vi)
29132211Skarels 	register struct vba_device *vi;
29232211Skarels {
29332211Skarels 	register int unit = vi->ui_unit;
29432211Skarels 	register struct disklabel *lp = &dklabel[unit];
29532211Skarels 
29630601Skarels 	/*
29730601Skarels 	 * Try to initialize device and read pack label.
29830601Skarels 	 */
29930601Skarels 	if (vdinit(vdminor(unit, 0), 0) != 0) {
30030601Skarels 		printf(": unknown drive type");
30130601Skarels 		return;
30230601Skarels 	}
30332211Skarels 	if (dksoftc[unit].dk_state == OPEN)
30432211Skarels 		printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>",
30532211Skarels 		    lp->d_typename, lp->d_secsize,
30632211Skarels 		    lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors);
30730519Ssam 	/*
30830519Ssam 	 * (60 / rpm) / (sectors per track * (bytes per sector / 2))
30930519Ssam 	 */
31030519Ssam 	if (vi->ui_dk >= 0)
31138170Smckusick 		dk_wpms[vi->ui_dk] =
31238170Smckusick 		    (lp->d_rpm * lp->d_nsectors * lp->d_secsize) / 120;
31330519Ssam #ifdef notyet
31430573Skarels 	addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp);
31530519Ssam #endif
31624004Ssam }
31724004Ssam 
31830756Skarels vdopen(dev, flags, fmt)
31930519Ssam 	dev_t dev;
32030756Skarels 	int flags, fmt;
32124004Ssam {
32230519Ssam 	register unit = vdunit(dev);
32330519Ssam 	register struct disklabel *lp;
32430519Ssam 	register struct dksoftc *dk;
32530519Ssam 	register struct partition *pp;
32630519Ssam 	struct vba_device *vi;
327*40737Skarels 	int s, error = 0, part = vdpart(dev), mask = 1 << part;
32830519Ssam 	daddr_t start, end;
32924004Ssam 
33030519Ssam 	if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
33130519Ssam 		return (ENXIO);
33230519Ssam 	lp = &dklabel[unit];
33330519Ssam 	dk = &dksoftc[unit];
33430519Ssam 
33530519Ssam 	s = spl7();
33630519Ssam 	while (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
33730519Ssam 	    dk->dk_state != CLOSED)
338*40737Skarels 		if (error = tsleep((caddr_t)dk, (PZERO+1) | PCATCH, devopn, 0))
339*40737Skarels 			break;
34030519Ssam 	splx(s);
341*40737Skarels 	if (error)
342*40737Skarels 		return (error);
34330519Ssam 	if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
34430519Ssam 		if (error = vdinit(dev, flags))
34530519Ssam 			return (error);
34630573Skarels 
34730573Skarels 	if (vdwstart == 0) {
34830573Skarels 		timeout(vdwatch, (caddr_t)0, hz);
34930573Skarels 		vdwstart++;
35030573Skarels 	}
35130519Ssam 	/*
35230519Ssam 	 * Warn if a partion is opened
35330519Ssam 	 * that overlaps another partition which is open
35430519Ssam 	 * unless one is the "raw" partition (whole disk).
35530519Ssam 	 */
35632211Skarels #define	RAWPART		8		/* 'x' partition */	/* XXX */
35732576Skarels 	if ((dk->dk_openpart & mask) == 0 && part != RAWPART) {
35830519Ssam 		pp = &lp->d_partitions[part];
35930519Ssam 		start = pp->p_offset;
36030519Ssam 		end = pp->p_offset + pp->p_size;
36130519Ssam 		for (pp = lp->d_partitions;
36230519Ssam 		     pp < &lp->d_partitions[lp->d_npartitions]; pp++) {
36330519Ssam 			if (pp->p_offset + pp->p_size <= start ||
36430519Ssam 			    pp->p_offset >= end)
36530519Ssam 				continue;
36630519Ssam 			if (pp - lp->d_partitions == RAWPART)
36730519Ssam 				continue;
36830519Ssam 			if (dk->dk_openpart & (1 << (pp - lp->d_partitions)))
36930519Ssam 				log(LOG_WARNING,
37030519Ssam 				    "dk%d%c: overlaps open partition (%c)\n",
37130519Ssam 				    unit, part + 'a',
37230519Ssam 				    pp - lp->d_partitions + 'a');
37330519Ssam 		}
37424004Ssam 	}
37530519Ssam 	if (part >= lp->d_npartitions)
37630519Ssam 		return (ENXIO);
37730756Skarels 	dk->dk_openpart |= mask;
37830756Skarels 	switch (fmt) {
37930756Skarels 	case S_IFCHR:
38030756Skarels 		dk->dk_copenpart |= mask;
38130756Skarels 		break;
38230756Skarels 	case S_IFBLK:
38330756Skarels 		dk->dk_bopenpart |= mask;
38430756Skarels 		break;
38530756Skarels 	}
38630519Ssam 	return (0);
38725675Ssam }
38824004Ssam 
38934528Skarels /* ARGSUSED */
39030756Skarels vdclose(dev, flags, fmt)
39130519Ssam 	dev_t dev;
39230756Skarels 	int flags, fmt;
39324004Ssam {
39430519Ssam 	register int unit = vdunit(dev);
39530519Ssam 	register struct dksoftc *dk = &dksoftc[unit];
39630756Skarels 	int part = vdpart(dev), mask = 1 << part;
39724004Ssam 
39830756Skarels 	switch (fmt) {
39930756Skarels 	case S_IFCHR:
40030756Skarels 		dk->dk_copenpart &= ~mask;
40130756Skarels 		break;
40230756Skarels 	case S_IFBLK:
40330756Skarels 		dk->dk_bopenpart &= ~mask;
40430756Skarels 		break;
40530756Skarels 	}
40630756Skarels 	if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0)
40730756Skarels 		dk->dk_openpart &= ~mask;
40830519Ssam 	/*
40930519Ssam 	 * Should wait for i/o to complete on this partition
41030519Ssam 	 * even if others are open, but wait for work on blkflush().
41130519Ssam 	 */
41230519Ssam 	if (dk->dk_openpart == 0) {
41330573Skarels 		int s = spl7();
41430573Skarels 		while (dkutab[unit].b_actf)
41530573Skarels 			sleep((caddr_t)dk, PZERO-1);
41630519Ssam 		splx(s);
41730519Ssam 		dk->dk_state = CLOSED;
41834076Skarels 		dk->dk_wlabel = 0;
41924004Ssam 	}
42030756Skarels 	return (0);
42125675Ssam }
42224004Ssam 
42330519Ssam vdinit(dev, flags)
42430519Ssam 	dev_t dev;
42530519Ssam 	int flags;
42625675Ssam {
42730519Ssam 	register struct disklabel *lp;
42830519Ssam 	register struct dksoftc *dk;
42930519Ssam 	struct vba_device *vi;
43030519Ssam 	int unit = vdunit(dev), error = 0;
43130756Skarels 	char *msg, *readdisklabel();
43230519Ssam 	extern int cold;
43325675Ssam 
43430519Ssam 	dk = &dksoftc[unit];
43530519Ssam 	if (flags & O_NDELAY) {
43630519Ssam 		dk->dk_state = OPENRAW;
43734528Skarels 		return (0);
43830519Ssam 	}
43930519Ssam 	dk->dk_state = RDLABEL;
44030519Ssam 	lp = &dklabel[unit];
44130519Ssam 	vi = vddinfo[unit];
44230756Skarels 	if (msg = readdisklabel(dev, vdstrategy, lp)) {
44334076Skarels 		if (cold) {
44430601Skarels 			printf(": %s", msg);
44534076Skarels 			dk->dk_state = CLOSED;
44634076Skarels 		} else {
44732211Skarels 			log(LOG_ERR, "dk%d: %s\n", unit, msg);
44834076Skarels 			dk->dk_state = OPENRAW;
44934076Skarels 		}
45030519Ssam #ifdef COMPAT_42
45135082Skarels 		vdlock(vi->ui_ctlr);
45234076Skarels 		if (vdmaptype(vi, lp))
45330519Ssam 			dk->dk_state = OPEN;
45435082Skarels 		vdunlock(vi->ui_ctlr);
45530519Ssam #endif
45630756Skarels 	} else {
45730756Skarels 		/*
45830756Skarels 		 * Now that we have the label, configure
45930756Skarels 		 * the correct drive parameters.
46030756Skarels 		 */
46135082Skarels 		vdlock(vi->ui_ctlr);
46232211Skarels 		if (vdreset_drive(vi))
46332211Skarels 			dk->dk_state = OPEN;
46432211Skarels 		else {
46530756Skarels 			dk->dk_state = CLOSED;
46630756Skarels 			error = ENXIO;
46732211Skarels 		}
46835082Skarels 		vdunlock(vi->ui_ctlr);
46925675Ssam 	}
47030756Skarels #ifndef SECSIZE
47132211Skarels 	vd_setsecsize(dk, lp);
47232211Skarels #endif
47330519Ssam 	wakeup((caddr_t)dk);
47430519Ssam 	return (error);
47524004Ssam }
47624004Ssam 
47732211Skarels #ifndef SECSIZE
47832211Skarels vd_setsecsize(dk, lp)
47932211Skarels 	register struct dksoftc *dk;
48032211Skarels 	register struct disklabel *lp;
48132211Skarels {
48232211Skarels 	int mul;
48332211Skarels 
48432211Skarels 	/*
48532211Skarels 	 * Calculate scaling shift for mapping
48632211Skarels 	 * DEV_BSIZE blocks to drive sectors.
48732211Skarels 	 */
48832211Skarels 	mul = DEV_BSIZE / lp->d_secsize;
48932211Skarels 	dk->dk_bshift = 0;
49032211Skarels 	while ((mul >>= 1) > 0)
49132211Skarels 		dk->dk_bshift++;
49232211Skarels }
49332211Skarels #endif SECSIZE
49432211Skarels 
49525675Ssam /*ARGSUSED*/
49630519Ssam vddgo(vm)
49730519Ssam 	struct vba_device *vm;
49824004Ssam {
49924004Ssam 
50024004Ssam }
50124004Ssam 
50224004Ssam vdstrategy(bp)
50325675Ssam 	register struct buf *bp;
50424004Ssam {
50530519Ssam 	register struct vba_device *vi;
50630519Ssam 	register struct disklabel *lp;
50730519Ssam 	register struct dksoftc *dk;
50830519Ssam 	register int unit;
50930573Skarels 	register daddr_t sn;
51030519Ssam 	struct buf *dp;
51130573Skarels 	daddr_t sz, maxsz;
51230519Ssam 	int part, s;
51324004Ssam 
51430519Ssam 	unit = vdunit(bp->b_dev);
51532211Skarels 	if (unit >= NDK) {
51629954Skarels 		bp->b_error = ENXIO;
51725675Ssam 		goto bad;
51829954Skarels 	}
51930519Ssam 	vi = vddinfo[unit];
52030519Ssam 	lp = &dklabel[unit];
52130519Ssam 	if (vi == 0 || vi->ui_alive == 0) {
52230519Ssam 		bp->b_error = ENXIO;
52330519Ssam 		goto bad;
52430519Ssam 	}
52530519Ssam 	dk = &dksoftc[unit];
526*40737Skarels 	if (dk->dk_state < OPEN) {
527*40737Skarels 		if (dk->dk_state == CLOSED) {
528*40737Skarels 			bp->b_error = EIO;
529*40737Skarels 			goto bad;
530*40737Skarels 		}
53130519Ssam 		goto q;
532*40737Skarels 	}
53334076Skarels 	if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) {
53434076Skarels 		bp->b_error = EROFS;
53534076Skarels 		goto bad;
53634076Skarels 	}
53730519Ssam 	part = vdpart(bp->b_dev);
53830519Ssam 	if ((dk->dk_openpart & (1 << part)) == 0) {
53930519Ssam 		bp->b_error = ENODEV;
54030519Ssam 		goto bad;
54130519Ssam 	}
54232211Skarels 	sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
54330519Ssam 	maxsz = lp->d_partitions[part].p_size;
54430756Skarels #ifndef SECSIZE
54530756Skarels 	sn = bp->b_blkno << dk->dk_bshift;
54630756Skarels #else SECSIZE
54730573Skarels 	sn = bp->b_blkno;
54830756Skarels #endif SECSIZE
54934076Skarels 	if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR &&
55034076Skarels #if LABELSECTOR != 0
55134076Skarels 	    sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR &&
55234076Skarels #endif
55334076Skarels 	    (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) {
55434076Skarels 		bp->b_error = EROFS;
55534076Skarels 		goto bad;
55634076Skarels 	}
55730519Ssam 	if (sn < 0 || sn + sz > maxsz) {
55830519Ssam 		if (sn == maxsz) {
55929954Skarels 			bp->b_resid = bp->b_bcount;
56029954Skarels 			goto done;
56129954Skarels 		}
56230756Skarels 		sz = maxsz - sn;
56330573Skarels 		if (sz <= 0) {
56430573Skarels 			bp->b_error = EINVAL;
56530573Skarels 			goto bad;
56630573Skarels 		}
56730573Skarels 		bp->b_bcount = sz * lp->d_secsize;
56825675Ssam 	}
56930519Ssam 	bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl;
57030756Skarels #ifdef SECSIZE
57130756Skarels if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0)
57230756Skarels panic("vdstrat blksize");
57330756Skarels #endif SECSIZE
57430519Ssam q:
57525675Ssam 	s = spl7();
57630519Ssam 	dp = &dkutab[vi->ui_unit];
57730519Ssam 	disksort(dp, bp);
57830519Ssam 	if (!dp->b_active) {
57930519Ssam 		(void) vdustart(vi);
58030573Skarels 		if (!vi->ui_mi->um_tab.b_active)
58130519Ssam 			vdstart(vi->ui_mi);
58224004Ssam 	}
58330519Ssam 	splx(s);
58424004Ssam 	return;
58525675Ssam bad:
58629954Skarels 	bp->b_flags |= B_ERROR;
58729954Skarels done:
58830519Ssam 	biodone(bp);
58930519Ssam 	return;
59024004Ssam }
59124004Ssam 
59230519Ssam vdustart(vi)
59330519Ssam 	register struct vba_device *vi;
59424004Ssam {
59530519Ssam 	register struct buf *bp, *dp;
59630519Ssam 	register struct vba_ctlr *vm;
59730519Ssam 	register int unit = vi->ui_unit;
59830519Ssam 	register struct dksoftc *dk;
59930519Ssam 	register struct vdsoftc *vd;
60030519Ssam 	struct disklabel *lp;
60124004Ssam 
60230519Ssam 	dp = &dkutab[unit];
60330519Ssam 	/*
60430519Ssam 	 * If queue empty, nothing to do.
60530519Ssam 	 */
60630519Ssam 	if ((bp = dp->b_actf) == NULL)
60730519Ssam 		return;
60830519Ssam 	/*
60930574Skarels 	 * If drive is off-cylinder and controller supports seeks,
61030574Skarels 	 * place drive on seek queue for controller.
61130574Skarels 	 * Otherwise, place on transfer queue.
61230519Ssam 	 */
61330519Ssam 	vd = &vdsoftc[vi->ui_ctlr];
61430519Ssam 	dk = &dksoftc[unit];
61530574Skarels 	vm = vi->ui_mi;
61630519Ssam 	if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) {
61730519Ssam 		lp = &dklabel[unit];
61830574Skarels 		bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors;
61930574Skarels 		if (vm->um_tab.b_seekf == NULL)
62030574Skarels 			vm->um_tab.b_seekf = dp;
62130574Skarels 		else
62230574Skarels 			vm->um_tab.b_seekl->b_forw = dp;
62330574Skarels 		vm->um_tab.b_seekl = dp;
62430574Skarels 	} else {
62530574Skarels 		if (vm->um_tab.b_actf == NULL)
62630574Skarels 			vm->um_tab.b_actf = dp;
62730574Skarels 		else
62830574Skarels 			vm->um_tab.b_actl->b_forw = dp;
62930574Skarels 		vm->um_tab.b_actl = dp;
63030519Ssam 	}
63130573Skarels 	dp->b_forw = NULL;
63230573Skarels 	dp->b_active++;
63325675Ssam }
63425675Ssam 
63525675Ssam /*
63630519Ssam  * Start next transfer on a controller.
63730574Skarels  * There are two queues of drives, the first on-cylinder
63830574Skarels  * and the second off-cylinder from their next transfers.
63930574Skarels  * Perform the first transfer for the first drive on the on-cylinder
64030574Skarels  * queue, if any, otherwise the first transfer for the first drive
64130574Skarels  * on the second queue.  Initiate seeks on remaining drives on the
64230574Skarels  * off-cylinder queue, then move them all to the on-cylinder queue.
64325675Ssam  */
64430519Ssam vdstart(vm)
64530519Ssam 	register struct vba_ctlr *vm;
64625675Ssam {
64725675Ssam 	register struct buf *bp;
64830519Ssam 	register struct vba_device *vi;
64930519Ssam 	register struct vdsoftc *vd;
65030519Ssam 	register struct dksoftc *dk;
65130519Ssam 	register struct disklabel *lp;
65230519Ssam 	register struct dcb **dcbp;
65330519Ssam 	struct buf *dp;
65430519Ssam 	int sn, tn;
65525675Ssam 
65630519Ssam loop:
65730519Ssam 	/*
65830519Ssam 	 * Pull a request off the controller queue.
65930519Ssam 	 */
66030574Skarels 	if ((dp = vm->um_tab.b_actf) == NULL &&
66130574Skarels 	    (dp = vm->um_tab.b_seekf) == NULL)
66230519Ssam 		return;
66330519Ssam 	if ((bp = dp->b_actf) == NULL) {
66430601Skarels 		if (dp == vm->um_tab.b_actf)
66530601Skarels 			vm->um_tab.b_actf = dp->b_forw;
66630601Skarels 		else
66730601Skarels 			vm->um_tab.b_seekf = dp->b_forw;
66830519Ssam 		goto loop;
66930519Ssam 	}
67025675Ssam 
67124004Ssam 	/*
67230519Ssam 	 * Mark controller busy, and determine
67330519Ssam 	 * destination of this request.
67424004Ssam 	 */
67530519Ssam 	vm->um_tab.b_active++;
67630519Ssam 	vi = vddinfo[vdunit(bp->b_dev)];
67730519Ssam 	dk = &dksoftc[vi->ui_unit];
67830756Skarels #ifndef SECSIZE
67930756Skarels 	sn = bp->b_blkno << dk->dk_bshift;
68030756Skarels #else SECSIZE
68130573Skarels 	sn = bp->b_blkno;
68230756Skarels #endif SECSIZE
68330519Ssam 	lp = &dklabel[vi->ui_unit];
68430519Ssam 	sn %= lp->d_secpercyl;
68530519Ssam 	tn = sn / lp->d_nsectors;
68630519Ssam 	sn %= lp->d_nsectors;
68730519Ssam 
68830519Ssam 	/*
68930519Ssam 	 * Construct dcb for read/write command.
69030519Ssam 	 */
69130519Ssam 	vd = &vdsoftc[vm->um_ctlr];
69230519Ssam 	vd->vd_dcb.intflg = DCBINT_DONE;
69332211Skarels 	vd->vd_dcb.devselect = dk->dk_dcb.devselect;
69430519Ssam 	vd->vd_dcb.operrsta = 0;
69530519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
69630519Ssam 	vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin;
69730519Ssam 	vd->vd_dcb.trail.rwtrail.disk.track = tn;
69830519Ssam 	vd->vd_dcb.trail.rwtrail.disk.sector = sn;
69930574Skarels 	dk->dk_curcyl = bp->b_cylin;
70030574Skarels 	bp->b_track = 0;		/* init overloaded field */
70130756Skarels 	vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
70234396Skarels 	if (bp->b_flags & B_FORMAT)
70334396Skarels 		vd->vd_dcb.opcode = dk->dk_op;
70434396Skarels 	else if (vd->vd_flags & VD_SCATGATH &&
70534396Skarels 	    ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0)
70630756Skarels 		vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW;
70734396Skarels 	else
70830756Skarels 		vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD;
70934396Skarels 
71034396Skarels 	switch (vd->vd_dcb.opcode) {
71134396Skarels 	case VDOP_FSECT:
712*40737Skarels 		vd->vd_dcb.trailcnt = sizeof (struct trfmt) / sizeof (long);
71334396Skarels 		vd->vd_dcb.trail.fmtrail.nsectors = bp->b_bcount /
71434396Skarels 		    lp->d_secsize;
71534396Skarels 		vd->vd_dcb.trail.fmtrail.hdr = *(dskadr *)&dk->dk_althdr;
71634396Skarels 		vd->vd_dcb.trail.rwtrail.disk.cylinder |= dk->dk_fmtflags;
71734396Skarels 		goto setupaddr;
71834396Skarels 
71934396Skarels 	case VDOP_RDRAW:
72034396Skarels 	case VDOP_RD:
721*40737Skarels 	case VDOP_RHDE:
72234396Skarels 	case VDOP_WD:
72334396Skarels 		vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1;
72434396Skarels setupaddr:
72530756Skarels 		vd->vd_dcb.trail.rwtrail.memadr =
72634528Skarels 			vbasetup(bp, &vd->vd_rbuf, (int)lp->d_secsize);
72734396Skarels 		break;
72834396Skarels 
72934396Skarels 	case VDOP_RAS:
73034396Skarels 	case VDOP_GAW:
73135712Sbostic 		vd->vd_dcb.trailcnt += vd_sgsetup(bp, &vd->vd_rbuf,
73234396Skarels 		    &vd->vd_dcb.trail.sgtrail);
73334396Skarels 		break;
73430756Skarels 	}
73530574Skarels 	if (vi->ui_dk >= 0) {
73630574Skarels 		dk_busy |= 1<<vi->ui_dk;
73730574Skarels 		dk_xfer[vi->ui_dk]++;
73830574Skarels 		dk_wds[vi->ui_dk] += bp->b_bcount>>6;
73930574Skarels 	}
74030519Ssam 
74130519Ssam 	/*
74230519Ssam 	 * Look for any seeks to be performed on other drives on this
74330519Ssam 	 * controller.  If overlapped seeks exist, insert seek commands
74430519Ssam 	 * on the controller's command queue before the transfer.
74530519Ssam 	 */
74630519Ssam 	dcbp = &vd->vd_mdcb.mdcb_head;
74730519Ssam 
74830574Skarels 	if (dp == vm->um_tab.b_seekf)
74930574Skarels 		dp = dp->b_forw;
75030574Skarels 	else
75130574Skarels 		dp = vm->um_tab.b_seekf;
75230574Skarels 	for (; dp != NULL; dp = dp->b_forw) {
75330574Skarels 		if ((bp = dp->b_actf) == NULL)
75430574Skarels 			continue;
75530574Skarels 		vi = vddinfo[vdunit(bp->b_dev)];
75630574Skarels 		dk = &dksoftc[vi->ui_unit];
75730519Ssam 		dk->dk_curcyl = bp->b_cylin;
75830574Skarels 		if (vi->ui_dk >= 0)
75930574Skarels 			dk_seek[vi->ui_dk]++;
76030574Skarels 		dk->dk_dcb.operrsta = 0;
76130574Skarels 		dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin;
76230574Skarels 		dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track;
76330574Skarels 		*dcbp = (struct dcb *)dk->dk_dcbphys;
76430574Skarels 		dcbp = &dk->dk_dcb.nxtdcb;
76524004Ssam 	}
76630519Ssam 	*dcbp = (struct dcb *)vd->vd_dcbphys;
76730574Skarels 	if (vm->um_tab.b_actf)
76830574Skarels 		vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf;
76930574Skarels 	else
77030574Skarels 		vm->um_tab.b_actf = vm->um_tab.b_seekf;
77130601Skarels 	if (vm->um_tab.b_seekf)
77230601Skarels 		vm->um_tab.b_actl = vm->um_tab.b_seekl;
77330574Skarels 	vm->um_tab.b_seekf = 0;
77424004Ssam 
77530519Ssam 	/*
77630519Ssam 	 * Initiate operation.
77730519Ssam 	 */
77830519Ssam 	vd->vd_mdcb.mdcb_status = 0;
77930519Ssam 	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
78024004Ssam }
78124004Ssam 
78235082Skarels /*
78335082Skarels  * Wait for controller to finish current operation
78435082Skarels  * so that direct controller accesses can be done.
78535082Skarels  */
78635082Skarels vdlock(ctlr)
78735082Skarels {
78835082Skarels 	register struct vba_ctlr *vm = vdminfo[ctlr];
78935082Skarels 	register struct vdsoftc *vd = &vdsoftc[ctlr];
79035082Skarels 	int s;
79135082Skarels 
79235082Skarels 	s = spl7();
79335082Skarels 	while (vm->um_tab.b_active || vd->vd_flags & VD_LOCKED) {
79435082Skarels 		vd->vd_flags |= VD_WAIT;
79535082Skarels 		sleep((caddr_t)vd, PRIBIO);
79635082Skarels 	}
79735082Skarels 	vd->vd_flags |= VD_LOCKED;
79835082Skarels 	splx(s);
79935082Skarels }
80035082Skarels 
80135082Skarels /*
80235082Skarels  * Continue normal operations after pausing for
80335082Skarels  * munging the controller directly.
80435082Skarels  */
80535082Skarels vdunlock(ctlr)
80635082Skarels {
80735082Skarels 	register struct vba_ctlr *vm = vdminfo[ctlr];
80835082Skarels 	register struct vdsoftc *vd = &vdsoftc[ctlr];
80935082Skarels 
81035082Skarels 	vd->vd_flags &= ~VD_LOCKED;
81135082Skarels 	if (vd->vd_flags & VD_WAIT) {
81235082Skarels 		vd->vd_flags &= ~VD_WAIT;
81335082Skarels 		wakeup((caddr_t)vd);
81435082Skarels 	} else if (vm->um_tab.b_actf || vm->um_tab.b_seekf)
81535082Skarels 		vdstart(vm);
81635082Skarels }
81735082Skarels 
81830519Ssam #define	DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE)
81924004Ssam /*
82024004Ssam  * Handle a disk interrupt.
82124004Ssam  */
82225675Ssam vdintr(ctlr)
82330519Ssam 	register ctlr;
82424004Ssam {
82530519Ssam 	register struct buf *bp, *dp;
82630519Ssam 	register struct vba_ctlr *vm = vdminfo[ctlr];
82730519Ssam 	register struct vba_device *vi;
82830519Ssam 	register struct vdsoftc *vd = &vdsoftc[ctlr];
82930519Ssam 	register status;
83034528Skarels 	int timedout;
83130573Skarels 	struct dksoftc *dk;
83224004Ssam 
83330519Ssam 	if (!vm->um_tab.b_active) {
83425675Ssam 		printf("vd%d: stray interrupt\n", ctlr);
83524004Ssam 		return;
83624004Ssam 	}
83725675Ssam 	/*
83830519Ssam 	 * Get device and block structures, and a pointer
83930519Ssam 	 * to the vba_device for the drive.
84025675Ssam 	 */
84130519Ssam 	dp = vm->um_tab.b_actf;
84230519Ssam 	bp = dp->b_actf;
84330519Ssam 	vi = vddinfo[vdunit(bp->b_dev)];
84434528Skarels 	dk = &dksoftc[vi->ui_unit];
84530574Skarels 	if (vi->ui_dk >= 0)
84630574Skarels 		dk_busy &= ~(1<<vi->ui_dk);
84734396Skarels 	timedout = (vd->vd_wticks >= VDMAXTIME);
84830519Ssam 	/*
84930519Ssam 	 * Check for and process errors on
85030519Ssam 	 * either the drive or the controller.
85130519Ssam 	 */
85230519Ssam 	uncache(&vd->vd_dcb.operrsta);
85330519Ssam 	status = vd->vd_dcb.operrsta;
85434396Skarels 	if (bp->b_flags & B_FORMAT) {
85534396Skarels 		dk->dk_operrsta = status;
85634396Skarels 		uncache(&vd->vd_dcb.err_code);
857*40737Skarels 		/* ecodecnt gets err_code + err_wcnt from the same longword */
858*40737Skarels 		dk->dk_ecodecnt = *(long *)&vd->vd_dcb.err_code;
859*40737Skarels 		uncache(&vd->vd_dcb.err_trk);
860*40737Skarels 		/* erraddr gets error trk/sec/cyl from the same longword */
861*40737Skarels 		dk->dk_erraddr = *(long *)&vd->vd_dcb.err_trk;
862*40737Skarels 	} else if (status & VDERR_HARD || timedout) {
86334528Skarels 		if (vd->vd_type == VDTYPE_SMDE)
86430601Skarels 			uncache(&vd->vd_dcb.err_code);
86530519Ssam 		if (status & DCBS_WPT) {
86630519Ssam 			/*
86730519Ssam 			 * Give up on write locked devices immediately.
86830519Ssam 			 */
86930573Skarels 			printf("dk%d: write locked\n", vi->ui_unit);
87030519Ssam 			bp->b_flags |= B_ERROR;
87134396Skarels 		} else if (status & VDERR_RETRY || timedout) {
87234396Skarels 			if (status & VDERR_CTLR || timedout) {
873*40737Skarels 				vdharderr(timedout ?
874*40737Skarels 				    "controller timeout" : "controller err",
87534396Skarels 				    vd, bp, &vd->vd_dcb);
87634396Skarels 				printf("; resetting controller...");
87734396Skarels 				vdreset_ctlr(vm);
87834396Skarels 			} else if (status & VDERR_DRIVE) {
87934396Skarels 				vdharderr("drive err", vd, bp, &vd->vd_dcb);
88034396Skarels 				printf("; resetting drive...");
88130519Ssam 				if (!vdreset_drive(vi))
882*40737Skarels 					dk->dk_state = CLOSED;
88332211Skarels 			} else
884*40737Skarels 				vdharderr("data err", vd, bp, &vd->vd_dcb);
88530519Ssam 			/*
88630519Ssam 			 * Retry transfer once, unless reset failed.
88730519Ssam 			 */
888*40737Skarels 			if (!vi->ui_alive || dp->b_errcnt++ >= 1) {
889*40737Skarels 				printf("\n");
89030519Ssam 				goto hard;
89132211Skarels 			}
89232211Skarels 
893*40737Skarels 			printf(" retrying\n");
89430519Ssam 			vm->um_tab.b_active = 0;	/* force retry */
89530519Ssam 		} else  {
896*40737Skarels 			vdharderr("hard error", vd, bp, &vd->vd_dcb);
897*40737Skarels 			printf("\n");
89830519Ssam 	hard:
89930519Ssam 			bp->b_flags |= B_ERROR;
90030519Ssam 		}
90130519Ssam 	} else if (status & DCBS_SOFT)
90234528Skarels 		vdsofterr(bp, &vd->vd_dcb);
903*40737Skarels if (vd->vd_wticks > 3) {
904*40737Skarels vd->vd_dcb.err_code = vd->vd_wticks;
905*40737Skarels vdharderr("slow transfer (ecode is sec.)", vd, bp, &vd->vd_dcb);
906*40737Skarels printf("\n");
907*40737Skarels }
90834396Skarels 	vd->vd_wticks = 0;
90930519Ssam 	if (vm->um_tab.b_active) {
91030519Ssam 		vm->um_tab.b_active = 0;
91130519Ssam 		vm->um_tab.b_actf = dp->b_forw;
91230519Ssam 		dp->b_active = 0;
91330519Ssam 		dp->b_errcnt = 0;
91430519Ssam 		dp->b_actf = bp->av_forw;
91530519Ssam 		bp->b_resid = 0;
91630601Skarels 		vbadone(bp, &vd->vd_rbuf);
91730519Ssam 		biodone(bp);
91830370Skarels 		/*
91930519Ssam 		 * If this unit has more work to do,
92030519Ssam 		 * then start it up right away.
92130370Skarels 		 */
92230519Ssam 		if (dp->b_actf)
92330519Ssam 			vdustart(vi);
92434528Skarels 		else if (dk->dk_openpart == 0)
92530573Skarels 			wakeup((caddr_t)dk);
92624004Ssam 	}
92725675Ssam 	/*
92830519Ssam 	 * If there are devices ready to
92930519Ssam 	 * transfer, start the controller.
93025675Ssam 	 */
93135082Skarels 	if (vd->vd_flags & VD_WAIT) {
93235082Skarels 		vd->vd_flags &= ~VD_WAIT;
93335082Skarels 		wakeup((caddr_t)vd);
93435082Skarels 	} else if (vm->um_tab.b_actf || vm->um_tab.b_seekf)
93530519Ssam 		vdstart(vm);
93624004Ssam }
93724004Ssam 
93834396Skarels vdharderr(what, vd, bp, dcb)
93934396Skarels 	char *what;
94034396Skarels 	struct vdsoftc *vd;
94134396Skarels 	register struct buf *bp;
94234396Skarels 	register struct dcb *dcb;
94334396Skarels {
94434396Skarels 	int unit = vdunit(bp->b_dev), status = dcb->operrsta;
94534396Skarels 	register struct disklabel *lp = &dklabel[unit];
94634528Skarels 	int blkdone;
94734396Skarels 
94834396Skarels 	if (vd->vd_wticks < VDMAXTIME)
94934396Skarels 		status &= ~DONTCARE;
95034710Skarels 	blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) *
95134710Skarels 	    lp->d_nsectors + dcb->err_sec -
95234710Skarels 	    lp->d_partitions[vdpart(bp->b_dev)].p_offset) >>
95334710Skarels 	    dksoftc[unit].dk_bshift) - bp->b_blkno;
95434528Skarels 	diskerr(bp, "dk", what, LOG_PRINTF, blkdone, lp);
95534528Skarels 	printf(", status %b", status, VDERRBITS);
95634396Skarels 	if (vd->vd_type == VDTYPE_SMDE)
95734396Skarels 		printf(" ecode %x", dcb->err_code);
95834396Skarels }
95934396Skarels 
96034528Skarels vdsofterr(bp, dcb)
96125675Ssam 	register struct buf *bp;
96230519Ssam 	register struct dcb *dcb;
96325675Ssam {
96434562Skarels 	int unit = vdunit(bp->b_dev);
96534562Skarels 	struct disklabel *lp = &dklabel[unit];
96634528Skarels 	int status = dcb->operrsta;
96734528Skarels 	int blkdone;
96825675Ssam 
96934710Skarels 	blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) *
97034710Skarels 	    lp->d_nsectors + dcb->err_sec -
97134710Skarels 	    lp->d_partitions[vdpart(bp->b_dev)].p_offset) >>
97234710Skarels 	    dksoftc[unit].dk_bshift) - bp->b_blkno;
97334528Skarels 
97434528Skarels 	if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) {
97534528Skarels 		diskerr(bp, "dk", "soft error", LOG_WARNING, blkdone, lp);
97634528Skarels 		addlog(", status %b ecode %x\n", status, VDERRBITS,
97734396Skarels 		    dcb->err_code);
97834528Skarels 	} else {
97934528Skarels 		diskerr(bp, "dk", "soft ecc", LOG_WARNING, blkdone, lp);
98034528Skarels 		addlog("\n");
98134528Skarels 	}
98225675Ssam }
98325675Ssam 
98430519Ssam vdioctl(dev, cmd, data, flag)
98525675Ssam 	dev_t dev;
98630519Ssam 	int cmd;
98730519Ssam 	caddr_t data;
98830519Ssam 	int flag;
98924004Ssam {
99032576Skarels 	register int unit = vdunit(dev);
99130519Ssam 	register struct disklabel *lp = &dklabel[unit];
99234076Skarels 	register struct dksoftc *dk = &dksoftc[unit];
99334640Skarels 	int error = 0, vdformat();
99424004Ssam 
99530519Ssam 	switch (cmd) {
99630519Ssam 
99730519Ssam 	case DIOCGDINFO:
99830519Ssam 		*(struct disklabel *)data = *lp;
99930519Ssam 		break;
100030519Ssam 
100130573Skarels 	case DIOCGPART:
100230573Skarels 		((struct partinfo *)data)->disklab = lp;
100330573Skarels 		((struct partinfo *)data)->part =
100430573Skarels 		    &lp->d_partitions[vdpart(dev)];
100530519Ssam 		break;
100630519Ssam 
100730519Ssam 	case DIOCSDINFO:
100830519Ssam 		if ((flag & FWRITE) == 0)
100930519Ssam 			error = EBADF;
101030519Ssam 		else
101132576Skarels 			error = setdisklabel(lp, (struct disklabel *)data,
101234076Skarels 			    (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart);
101334396Skarels 		if (error == 0 && dk->dk_state == OPENRAW &&
101434396Skarels 		    vdreset_drive(vddinfo[unit]))
101534076Skarels 			dk->dk_state = OPEN;
101630519Ssam 		break;
101730519Ssam 
101834076Skarels 	case DIOCWLABEL:
101934076Skarels 		if ((flag & FWRITE) == 0)
102034076Skarels 			error = EBADF;
102134076Skarels 		else
102234076Skarels 			dk->dk_wlabel = *(int *)data;
102334076Skarels 		break;
102434076Skarels 
102532576Skarels 	case DIOCWDINFO:
102632576Skarels 		if ((flag & FWRITE) == 0)
102730519Ssam 			error = EBADF;
102832576Skarels 		else if ((error = setdisklabel(lp, (struct disklabel *)data,
102934076Skarels 		    (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) {
103034640Skarels 			int wlab;
103134640Skarels 
103235413Skarels 			if (error == 0 && dk->dk_state == OPENRAW &&
103335413Skarels 			    vdreset_drive(vddinfo[unit]))
103435413Skarels 				dk->dk_state = OPEN;
103534640Skarels 			/* simulate opening partition 0 so write succeeds */
103634640Skarels 			dk->dk_openpart |= (1 << 0);		/* XXX */
103734640Skarels 			wlab = dk->dk_wlabel;
103834640Skarels 			dk->dk_wlabel = 1;
103932576Skarels 			error = writedisklabel(dev, vdstrategy, lp);
104034640Skarels 			dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;
104134640Skarels 			dk->dk_wlabel = wlab;
104234076Skarels 		}
104330519Ssam 		break;
104430519Ssam 
104534396Skarels 	case DIOCWFORMAT:
104634396Skarels 	    {
104734396Skarels 		register struct format_op *fop;
104834396Skarels 		struct uio auio;
104934396Skarels 		struct iovec aiov;
105034396Skarels 
105134396Skarels 		if ((flag & FWRITE) == 0) {
105234396Skarels 			error = EBADF;
105334396Skarels 			break;
105434396Skarels 		}
105534396Skarels 		fop = (struct format_op *)data;
105634396Skarels 		aiov.iov_base = fop->df_buf;
105734396Skarels 		aiov.iov_len = fop->df_count;
105834396Skarels 		auio.uio_iov = &aiov;
105934396Skarels 		auio.uio_iovcnt = 1;
106034396Skarels 		auio.uio_resid = fop->df_count;
106134396Skarels 		auio.uio_segflg = UIO_USERSPACE;
106234396Skarels 		auio.uio_offset = fop->df_startblk * lp->d_secsize;
1063*40737Skarels 		/* This assumes one active format operation per disk... */
1064*40737Skarels 		dk->dk_op = fop->dk_op;
1065*40737Skarels 		dk->dk_althdr = fop->dk_althdr;
1066*40737Skarels 		dk->dk_fmtflags = fop->dk_fmtflags;
106734396Skarels 		/*
106834396Skarels 		 * Don't return errors, as the format op won't get copied
106934396Skarels 		 * out if we return nonzero.  Callers must check the returned
1070*40737Skarels 		 * registers and count.
107134396Skarels 		 */
1072*40737Skarels 		error = physio(vdformat, (struct buf *)NULL, dev,
1073*40737Skarels 		     B_WRITE, minphys, &auio);
1074*40737Skarels 		if (error == EIO)
1075*40737Skarels 			error = 0;
107634396Skarels 		fop->df_count -= auio.uio_resid;
1077*40737Skarels 		/* This assumes one active format operation per disk... */
107834396Skarels 		fop->dk_operrsta = dk->dk_operrsta;
1079*40737Skarels 		fop->dk_ecodecnt = dk->dk_ecodecnt;
1080*40737Skarels 		fop->dk_erraddr = dk->dk_erraddr;
108134396Skarels 		break;
108234396Skarels 	    }
108334396Skarels 
108430519Ssam 	default:
108530519Ssam 		error = ENOTTY;
108630519Ssam 		break;
108724004Ssam 	}
108832606Skarels 	return (error);
108924004Ssam }
109024004Ssam 
109134396Skarels vdformat(bp)
109234396Skarels 	struct buf *bp;
109334396Skarels {
109434396Skarels 	bp->b_flags |= B_FORMAT;
109534396Skarels 	vdstrategy(bp);
109634396Skarels }
109734396Skarels 
109825675Ssam /*
109930519Ssam  * Watch for lost interrupts.
110025675Ssam  */
110130519Ssam vdwatch()
110230519Ssam {
110330519Ssam 	register struct vdsoftc *vd;
110430519Ssam 	register struct vba_ctlr *vm;
110534528Skarels 	register int ctlr;
110634396Skarels 	int s;
110730519Ssam 
110830519Ssam 	timeout(vdwatch, (caddr_t)0, hz);
110930519Ssam 	for (ctlr = 0; ctlr < NVD; ctlr++) {
111030519Ssam 		vm = vdminfo[ctlr];
111130519Ssam 		if (vm == 0 || vm->um_alive == 0)
111230519Ssam 			continue;
111330519Ssam 		vd = &vdsoftc[ctlr];
111434396Skarels 		s = spl7();
111534396Skarels 		if (vm->um_tab.b_active && vd->vd_wticks++ >= VDMAXTIME) {
111630519Ssam 			printf("vd%d: lost interrupt\n", ctlr);
111734396Skarels #ifdef maybe
111834396Skarels 			VDABORT((struct vddevice *)vm->um_addr, vd->vd_type);
111934396Skarels #endif
112034396Skarels 			vdintr(ctlr);
112130519Ssam 		}
112234396Skarels 		splx(s);
112330519Ssam 	}
112430519Ssam }
112530519Ssam 
112630519Ssam #define	DBSIZE	64	/* controller limit with 1K sectors */
112730519Ssam /*
112830519Ssam  * Crash dump.
112930519Ssam  */
113030519Ssam vddump(dev)
113130519Ssam 	dev_t dev;
113224004Ssam {
113330519Ssam 	register struct vba_device *vi;
113430519Ssam 	register struct vba_ctlr *vm;
113530519Ssam 	register struct disklabel *lp;
113630519Ssam 	register struct vdsoftc *vd;
113730519Ssam 	struct dksoftc *dk;
113830519Ssam 	int part, unit, num;
113930601Skarels 	u_long start;
114024004Ssam 
114130519Ssam 	start = 0;
114230519Ssam 	unit = vdunit(dev);
114330519Ssam 	if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
114430519Ssam 		return (ENXIO);
114530519Ssam 	dk = &dksoftc[unit];
114634076Skarels 	if (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
114734076Skarels 	    vdinit(vdminor(unit, 0), 0) != 0)
114830519Ssam 		return (ENXIO);
114930519Ssam 	lp = &dklabel[unit];
115030519Ssam 	part = vdpart(dev);
115130519Ssam 	if (part >= lp->d_npartitions)
115230519Ssam 		return (ENXIO);
115332211Skarels 	vm = vi->ui_mi;
115430519Ssam 	vdreset_ctlr(vm);
115530519Ssam 	if (dumplo < 0)
115630519Ssam 		return (EINVAL);
115730519Ssam 	/*
115830756Skarels 	 * Maxfree is in pages, dumplo is in DEV_BSIZE units.
115930519Ssam 	 */
116030519Ssam 	num = maxfree * (NBPG / lp->d_secsize);
116130756Skarels 	dumplo *= DEV_BSIZE / lp->d_secsize;
116230519Ssam 	if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size)
116330519Ssam 		num = lp->d_partitions[vdpart(dev)].p_size - dumplo;
116430519Ssam 	vd = &vdsoftc[vm->um_ctlr];
116530519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
116630519Ssam 	vd->vd_dcb.opcode = VDOP_WD;
116732211Skarels 	vd->vd_dcb.devselect = dk->dk_dcb.devselect;
116830756Skarels 	vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
116930519Ssam 	while (num > 0) {
117030519Ssam 		int nsec, cn, sn, tn;
117130519Ssam 
117230519Ssam 		nsec = MIN(num, DBSIZE);
117330601Skarels 		sn = dumplo + start / lp->d_secsize;
117430519Ssam 		cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) /
117530519Ssam 		    lp->d_secpercyl;
117630519Ssam 		sn %= lp->d_secpercyl;
117730519Ssam 		tn = sn / lp->d_nsectors;
117830519Ssam 		sn %= lp->d_nsectors;
117930519Ssam 		vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
118030519Ssam 		vd->vd_dcb.trail.rwtrail.memadr = start;
118130519Ssam 		vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1;
118230519Ssam 		vd->vd_dcb.trail.rwtrail.disk.cylinder = cn;
118330519Ssam 		vd->vd_dcb.trail.rwtrail.disk.track = tn;
118430519Ssam 		vd->vd_dcb.trail.rwtrail.disk.sector = sn;
118530519Ssam 		vd->vd_dcb.operrsta = 0;
118630519Ssam 		VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
118730519Ssam 		if (!vdpoll(vm, 5)) {
118830519Ssam 			printf(" during dump\n");
118930519Ssam 			return (EIO);
119030519Ssam 		}
119130519Ssam 		if (vd->vd_dcb.operrsta & VDERR_HARD) {
119230519Ssam 			printf("dk%d: hard error, status=%b\n", unit,
119330519Ssam 			    vd->vd_dcb.operrsta, VDERRBITS);
119430519Ssam 			return (EIO);
119530519Ssam 		}
119630519Ssam 		start += nsec * lp->d_secsize;
119730519Ssam 		num -= nsec;
119825675Ssam 	}
119930519Ssam 	return (0);
120024004Ssam }
120124004Ssam 
120224004Ssam vdsize(dev)
120325675Ssam 	dev_t dev;
120424004Ssam {
120530519Ssam 	register int unit = vdunit(dev);
120630519Ssam 	register struct dksoftc *dk;
120730519Ssam 	struct vba_device *vi;
120830519Ssam 	struct disklabel *lp;
120924004Ssam 
121030519Ssam 	if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 ||
121130519Ssam 	    (dk = &dksoftc[unit])->dk_state != OPEN)
121225675Ssam 		return (-1);
121330519Ssam 	lp = &dklabel[unit];
121430756Skarels #ifdef SECSIZE
121530573Skarels 	return ((int)lp->d_partitions[vdpart(dev)].p_size);
121630756Skarels #else SECSIZE
121730756Skarels 	return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift);
121830756Skarels #endif SECSIZE
121924004Ssam }
122024004Ssam 
122125675Ssam /*
1222*40737Skarels  * Initialize controller.
122325675Ssam  */
1224*40737Skarels vdinit_ctlr(vm, vd)
1225*40737Skarels 	struct vba_ctlr *vm;
1226*40737Skarels 	struct vdsoftc *vd;
122724004Ssam {
122830519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
1229*40737Skarels 
123030519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
123130519Ssam 		vdaddr->vdcsr = 0;
123230519Ssam 		vdaddr->vdtcf_mdcb = AM_ENPDA;
123330519Ssam 		vdaddr->vdtcf_dcb = AM_ENPDA;
123430519Ssam 		vdaddr->vdtcf_trail = AM_ENPDA;
123530519Ssam 		vdaddr->vdtcf_data = AM_ENPDA;
1236*40737Skarels 		vdaddr->vdccf = CCF_SEN | CCF_DIU | CCF_STS | CCF_RFE |
1237*40737Skarels 		    XMD_32BIT | BSZ_16WRD |
123825675Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
123925675Ssam 	}
124035413Skarels 	if (!vdcmd(vm, VDOP_INIT, 10, 0) || !vdcmd(vm, VDOP_DIAG, 10, 0)) {
1241*40737Skarels 		printf("vd%d: %s cmd failed\n", vm->um_ctlr,
124230519Ssam 		    vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
1243*40737Skarels 		return (0);
1244*40737Skarels 	}
1245*40737Skarels 	vd->vd_secsize = vdaddr->vdsecsize << 1;
1246*40737Skarels 	return (1);
1247*40737Skarels }
1248*40737Skarels 
1249*40737Skarels /*
1250*40737Skarels  * Perform a controller reset.
1251*40737Skarels  */
1252*40737Skarels vdreset_ctlr(vm)
1253*40737Skarels 	register struct vba_ctlr *vm;
1254*40737Skarels {
1255*40737Skarels 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
1256*40737Skarels 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
1257*40737Skarels 	register int unit;
1258*40737Skarels 	struct vba_device *vi;
1259*40737Skarels 
1260*40737Skarels 	VDRESET(vdaddr, vd->vd_type);
1261*40737Skarels 	if (vdinit_ctlr(vm, vd) == 0)
126230370Skarels 		return;
126330519Ssam 	for (unit = 0; unit < NDK; unit++)
126430519Ssam 		if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive)
126530519Ssam 			(void) vdreset_drive(vi);
126630519Ssam }
126730519Ssam 
126830519Ssam vdreset_drive(vi)
126930519Ssam 	register struct vba_device *vi;
127030519Ssam {
127130519Ssam 	register struct disklabel *lp = &dklabel[vi->ui_unit];
127230519Ssam 	struct vba_ctlr *vm = vdminfo[vi->ui_ctlr];
127330519Ssam 	struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
127432211Skarels 	register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
127532211Skarels 	register struct dksoftc *dk = &dksoftc[vi->ui_unit];
1276*40737Skarels 	int config_status, config_ecode, saw_drive = 0;
127730519Ssam 
1278*40737Skarels #ifdef notdef
1279*40737Skarels 	/*
1280*40737Skarels 	 * check for ESDI distribution panel already configured,
1281*40737Skarels 	 * e.g. on boot drive, or if PROBE on controller actually
1282*40737Skarels 	 * worked.  Status will be zero if drive hasn't
1283*40737Skarels 	 * been probed yet.
1284*40737Skarels 	 */
1285*40737Skarels #if STA_ESDI != 0
1286*40737Skarels 	if ((vdaddr->vdstatus[vi->ui_slave] & STA_TYPE) == STA_ESDI)
1287*40737Skarels 		lp->d_devflags |= VD_ESDI;
1288*40737Skarels #endif
1289*40737Skarels #endif
129030519Ssam top:
129130519Ssam 	vd->vd_dcb.opcode = VDOP_CONFIG;		/* command */
129230519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
129330519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
129430519Ssam 	vd->vd_dcb.operrsta = 0;
129532211Skarels 	vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags;
129630519Ssam 	vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders;
129730519Ssam 	vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks;
129830519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
129930756Skarels 		vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long);
130030519Ssam 		vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors;
130130601Skarels 		vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack;
1302*40737Skarels 		vd->vd_dcb.trail.rstrail.recovery =
1303*40737Skarels 		    (lp->d_flags & D_REMOVABLE) ? VDRF_NORMAL :
1304*40737Skarels 		    (VDRF_NORMAL &~ (VDRF_OSP|VDRF_OSM));
130530519Ssam 	} else
130630519Ssam 		vd->vd_dcb.trailcnt = 2;		/* XXX */
130730519Ssam 	vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
130830519Ssam 	vd->vd_mdcb.mdcb_status = 0;
130930519Ssam 	VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type);
131030519Ssam 	if (!vdpoll(vm, 5)) {
131130519Ssam 		printf(" during config\n");
131230519Ssam 		return (0);
131325675Ssam 	}
1314*40737Skarels 	config_status = vd->vd_dcb.operrsta;
1315*40737Skarels 	config_ecode = (u_char)vd->vd_dcb.err_code;
1316*40737Skarels 	if (config_status & VDERR_HARD) {
131732211Skarels 		if (vd->vd_type == VDTYPE_SMDE) {
1318*40737Skarels 			/*
1319*40737Skarels 			 * If drive status was updated successfully,
1320*40737Skarels 			 * STA_US (unit selected) should be set
1321*40737Skarels 			 * if the drive is attached and powered up.
1322*40737Skarels 			 * (But only if we've guessed right on SMD
1323*40737Skarels 			 * vs. ESDI; if that flag is wrong, we won't
1324*40737Skarels 			 * see the drive.)  If we don't see STA_US
1325*40737Skarels 			 * with either SMD or ESDI set for the unit,
1326*40737Skarels 			 * we assume that the drive doesn't exist,
1327*40737Skarels 			 * and don't wait for it to spin up.
1328*40737Skarels 			 */
1329*40737Skarels 			(void) vdcmd(vm, VDOP_STATUS, 5, vi->ui_slave);
1330*40737Skarels 			uncache(&vdaddr->vdstatus[vi->ui_slave]);
1331*40737Skarels 			if (vdaddr->vdstatus[vi->ui_slave] & STA_US)
1332*40737Skarels 				saw_drive = 1;
1333*40737Skarels 			else if (lp->d_devflags == 0) {
133432211Skarels 				lp->d_devflags = VD_ESDI;
133532211Skarels 				goto top;
133632211Skarels 			}
1337*40737Skarels 		} else
1338*40737Skarels 			saw_drive = 1;
1339*40737Skarels 		if ((config_status & (DCBS_OCYL|DCBS_NRDY)) == 0)
134032211Skarels 			printf("dk%d: config error %b ecode %x\n", vi->ui_unit,
1341*40737Skarels 			   config_status, VDERRBITS, config_ecode);
1342*40737Skarels 		else if ((vd->vd_flags & VD_STARTED) == 0 && saw_drive) {
134330519Ssam 			int started;
134430519Ssam 
134532211Skarels 			printf(" starting drives, wait ... ");
134630519Ssam 			vd->vd_flags |= VD_STARTED;
134730519Ssam 			started = (vdcmd(vm, VDOP_START, 10) == 1);
134830519Ssam 			DELAY(62000000);
134935413Skarels 			printf("done\n");
135032211Skarels 			lp->d_devflags = 0;
135130519Ssam 			if (started)
135230519Ssam 				goto top;
135330519Ssam 		}
135430519Ssam 		return (0);
135530519Ssam 	}
135632211Skarels 	dk->dk_dcb.devselect |= lp->d_devflags;
135730519Ssam 	return (1);
135825675Ssam }
135924004Ssam 
136025675Ssam /*
136130519Ssam  * Perform a command w/o trailer.
136225675Ssam  */
136335413Skarels vdcmd(vm, cmd, t, slave)
136430519Ssam 	register struct vba_ctlr *vm;
136525675Ssam {
136630519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
136725675Ssam 
136830519Ssam 	vd->vd_dcb.opcode = cmd;		/* command */
136930519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
137030519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
137130519Ssam 	vd->vd_dcb.operrsta = 0;
137235413Skarels 	vd->vd_dcb.devselect = slave;
137330519Ssam 	vd->vd_dcb.trailcnt = 0;
137430519Ssam 	vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
137530519Ssam 	vd->vd_mdcb.mdcb_status = 0;
137630519Ssam 	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
137730519Ssam 	if (!vdpoll(vm, t)) {
137830519Ssam 		printf(" during init\n");
137930370Skarels 		return (0);
138030370Skarels 	}
138130519Ssam 	return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0);
138225675Ssam }
138325675Ssam 
138425925Ssam /*
138530519Ssam  * Poll controller until operation
138630519Ssam  * completes or timeout expires.
138725925Ssam  */
138830519Ssam vdpoll(vm, t)
138930519Ssam 	register struct vba_ctlr *vm;
139025925Ssam 	register int t;
139125925Ssam {
139230519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
139330519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
139425925Ssam 
139525925Ssam 	t *= 1000;
139630370Skarels 	for (;;) {
139730519Ssam 		uncache(&vd->vd_dcb.operrsta);
139830519Ssam 		if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT))
139930370Skarels 			break;
140025925Ssam 		if (--t <= 0) {
140130519Ssam 			printf("vd%d: controller timeout", vm->um_ctlr);
140230519Ssam 			VDABORT(vdaddr, vd->vd_type);
140325925Ssam 			return (0);
140425925Ssam 		}
140530370Skarels 		DELAY(1000);
140625925Ssam 	}
140730519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
140830519Ssam 		do {
140925925Ssam 			DELAY(50);
141030519Ssam 			uncache(&vdaddr->vdcsr);
141130519Ssam 		} while (vdaddr->vdcsr & CS_GO);
141232211Skarels 	 	DELAY(300);
141332211Skarels 		uncache(&vd->vd_dcb.err_code);
141425925Ssam 	}
141525925Ssam 	DELAY(200);
141630519Ssam 	uncache(&vd->vd_dcb.operrsta);
141725925Ssam 	return (1);
141825925Ssam }
141925925Ssam 
142030519Ssam #ifdef COMPAT_42
142130519Ssam struct	vdst {
142230519Ssam 	int	nsec;		/* sectors/track */
142330519Ssam 	int	ntrack;		/* tracks/cylinder */
142430519Ssam 	int	ncyl;		/* cylinders */
142532211Skarels 	int	secsize;	/* sector size */
142630519Ssam 	char	*name;		/* type name */
142730519Ssam 	struct {
142830519Ssam 		int	off;	/* partition offset in sectors */
142930519Ssam 		int	size;	/* partition size in sectors */
143030573Skarels 	} parts[8];
143130519Ssam } vdst[] = {
143232211Skarels 	{ 66, 23, 850, 512, "NEC 800",
143332211Skarels 		{0,	 1290300},	/* a cyl   0 - 849 */
143432211Skarels 	},
143534737Sbostic 	{ 64, 20, 842, 512, "2361a",
143634737Sbostic 		{0,	 61440},	/* a cyl   0 - 47 */
143734737Sbostic 		{61440,	 67840},	/* b cyl  48 - 100 */
143834737Sbostic 		{129280, 942080}, 	/* c cyl 101 - 836 */
143934737Sbostic 		{0,      1071360}, 	/* d cyl   0 - 836 */
144034737Sbostic 		{449280, 311040},	/* e cyl 351 - 593 */
144134737Sbostic 		{760320, 311040}, 	/* f cyl 594 - 836 */
144234737Sbostic 		{449280, 622080},	/* g cyl 351 - 836 */
144334737Sbostic 		{129280, 320000}	/* h cyl 101 - 350 */
144434737Sbostic 	},
144532211Skarels 	{ 48, 24, 711, 512, "xsd",
144631039Skarels 		{0,	 61056},	/* a cyl   0 - 52 */
144731039Skarels 		{61056,	 61056},	/* b cyl  53 - 105 */
144831039Skarels 		{122112, 691200}, 	/* c cyl 106 - 705 */
144931039Skarels 		{237312, 576000}, 	/* d cyl 206 - 705 */
145031039Skarels 		{352512, 460800},	/* e cyl 306 - 705 */
145131039Skarels 		{467712, 345600}, 	/* f cyl 406 - 705 */
145231039Skarels 		{582912, 230400},	/* g cyl 506 - 705 */
145331039Skarels 		{698112, 115200}	/* h cyl 606 - 705 */
145430573Skarels 	},
145532211Skarels 	{ 44, 20, 842, 512, "eagle",
145630601Skarels 		{0,	 52800},	/* egl0a cyl   0 - 59 */
145730601Skarels 		{52800,	 66000},	/* egl0b cyl  60 - 134 */
145830601Skarels 		{118800, 617760}, 	/* egl0c cyl 135 - 836 */
145930756Skarels 		{736560, 4400}, 	/* egl0d cyl 837 - 841 */
146031039Skarels 		{0, 	 736560},	/* egl0e cyl   0 - 836 */
146131039Skarels 		{0, 	 740960}, 	/* egl0f cyl   0 - 841 */
146230601Skarels 		{118800, 310640},	/* egl0g cyl 135 - 487 */
146330601Skarels 		{429440, 307120}	/* egl0h cyl 488 - 836 */
146430573Skarels 	},
146532211Skarels 	{ 64, 10, 823, 512, "fuj",
146631039Skarels 		{0,	 38400},	/* fuj0a cyl   0 - 59 */
146731039Skarels 		{38400,	 48000},	/* fuj0b cyl  60 - 134 */
146831039Skarels 		{86400,	 437120}, 	/* fuj0c cyl 135 - 817 */
146931039Skarels 		{159360, 364160}, 	/* fuj0d cyl 249 - 817 */
147031039Skarels 		{232320, 291200},	/* fuj0e cyl 363 - 817 */
147131039Skarels 		{305280, 218240}, 	/* fuj0f cyl 477 - 817 */
147231039Skarels 		{378240, 145280},	/* fuj0g cyl 591 - 817 */
147331039Skarels 		{451200, 72320}		/* fug0h cyl 705 - 817 */
147430573Skarels 	},
147532211Skarels 	{ 32, 24, 711, 512, "xfd",
147630756Skarels 		{ 0,	 40704 },	/* a cyl   0 - 52 */
147730756Skarels 		{ 40704, 40704 },	/* b cyl  53 - 105 */
147830756Skarels 		{ 81408, 460800 },	/* c cyl 106 - 705 */
147930756Skarels 		{ 0,	 81408 },	/* d cyl 709 - 710 (a & b) */
148030756Skarels 		{ 0,	 542208 },	/* e cyl   0 - 705 */
148130756Skarels 		{ 40704, 501504 },	/* f cyl  53 - 705 (b & c) */
148230756Skarels 		{ 81408, 230400 },	/* g cyl 106 - 405 (1/2 of c) */
148330756Skarels 		{ 311808,230400 }	/* h cyl 406 - 705 (1/2 of c) */
148430573Skarels 	},
148532211Skarels 	{ 32, 19, 823, 512, "smd",
148631039Skarels 		{0,	 40128},	/* a cyl   0-65 */
148731039Skarels 		{40128,  27360},	/* b cyl  66-110 */
148831039Skarels 		{67488,  429856},	/* c cyl 111-817 */
148931039Skarels 		{139232, 358112},	/* d cyl 229 - 817 */
149031039Skarels 		{210976, 286368},	/* e cyl 347 - 817 */
149131039Skarels 		{282720, 214624},	/* f cyl 465 - 817 */
149231039Skarels 		{354464, 142880},	/* g cyl 583 - 817 */
149331039Skarels 		{426208, 71136}		/* h cyl 701 - 817 */
149430573Skarels 	},
149532211Skarels 	{ 18, 15, 1224, 1024, "mxd",
149632211Skarels 		{0,	 21600},	/* a cyl   0-79 */
149732211Skarels 		{21600,  22410},	/* b cyl  80-162 */
149832211Skarels 		{44010,  285120},	/* c cyl 163-1217 */
149932211Skarels #ifdef notyet
150032211Skarels 		{x, 237600},	/* d cyl y - 1217 */
150132211Skarels 		{x, 190080},	/* e cyl y - 1217 */
150232211Skarels 		{x, 142560},	/* f cyl y - 1217 */
150332211Skarels 		{x, 95040},	/* g cyl y - 1217 */
150432211Skarels 		{x, 47520}		/* h cyl 701 - 817 */
150532211Skarels #endif
150632211Skarels 	},
150732211Skarels 	{ 32, 10, 823, 512, "fsd",
150830756Skarels 		{0,	 19200},	/* a cyl   0 -  59 */
150930756Skarels 		{19200,	 24000},	/* b cyl  60 - 134 */
151030756Skarels 		{43200,	 218560},	/* c cyl 135 - 817 */
151130573Skarels 	}
151230519Ssam };
151330519Ssam #define	NVDST	(sizeof (vdst) / sizeof (vdst[0]))
151430519Ssam 
151525675Ssam /*
151630519Ssam  * Construct a label for an unlabeled pack.  We
151730519Ssam  * deduce the drive type by reading from the last
151830519Ssam  * track on successively smaller drives until we
151930519Ssam  * don't get an error.
152025675Ssam  */
152130519Ssam vdmaptype(vi, lp)
152230519Ssam 	register struct vba_device *vi;
152330519Ssam 	register struct disklabel *lp;
152425675Ssam {
152530519Ssam 	register struct vdsoftc *vd;
152630519Ssam 	register struct vdst *p;
152732211Skarels 	struct vba_ctlr *vm = vi->ui_mi;
152830519Ssam 	int i;
152925675Ssam 
153030519Ssam 	vd = &vdsoftc[vi->ui_ctlr];
153130519Ssam 	for (p = vdst; p < &vdst[NVDST]; p++) {
153230519Ssam 		if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32)
153330519Ssam 			continue;
153430519Ssam 		lp->d_nsectors = p->nsec;
153530519Ssam 		lp->d_ntracks = p->ntrack;
153630519Ssam 		lp->d_ncylinders = p->ncyl;
153732211Skarels 		lp->d_secsize = p->secsize;
153835413Skarels 		DELAY(100000);
153930519Ssam 		if (!vdreset_drive(vi))
154030519Ssam 			return (0);
154135413Skarels 		DELAY(100000);
154230519Ssam 		vd->vd_dcb.opcode = VDOP_RD;
154330519Ssam 		vd->vd_dcb.intflg = DCBINT_NONE;
154430519Ssam 		vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
154532211Skarels 		vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect;
154630756Skarels 		vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
154730601Skarels 		vd->vd_dcb.trail.rwtrail.memadr =
154830601Skarels 		    vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf);
154932211Skarels 		vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short);
155030519Ssam 		vd->vd_dcb.operrsta = 0;
155130519Ssam 		vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2;
155230519Ssam 		vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1;
155330519Ssam 		vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1;
155430519Ssam 		vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
155530519Ssam 		vd->vd_mdcb.mdcb_status = 0;
155630519Ssam 		VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
155730519Ssam 		if (!vdpoll(vm, 60))
155830519Ssam 			printf(" during probe\n");
155930519Ssam 		if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0)
156030519Ssam 			break;
156124004Ssam 	}
156232211Skarels 	if (p >= &vdst[NVDST])
156330519Ssam 		return (0);
156432211Skarels 
156530573Skarels 	for (i = 0; i < 8; i++) {
156630519Ssam 		lp->d_partitions[i].p_offset = p->parts[i].off;
156730519Ssam 		lp->d_partitions[i].p_size = p->parts[i].size;
156830519Ssam 	}
156930573Skarels 	lp->d_npartitions = 8;
157030519Ssam 	lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
157130519Ssam 	bcopy(p->name, lp->d_typename, 4);
157230519Ssam 	return (1);
157324004Ssam }
157430519Ssam #endif COMPAT_42
157524004Ssam #endif
1576