xref: /csrg-svn/sys/tahoe/vba/vd.c (revision 35413)
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*35413Skarels  *	@(#)vd.c	7.8 (Berkeley) 08/27/88
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"
3225675Ssam #include "dir.h"
3329564Ssam #include "dkstat.h"
3430519Ssam #include "disklabel.h"
3525675Ssam #include "map.h"
3630519Ssam #include "file.h"
3725675Ssam #include "systm.h"
3825675Ssam #include "user.h"
3925675Ssam #include "vmmac.h"
4025675Ssam #include "proc.h"
4125675Ssam #include "uio.h"
4230370Skarels #include "syslog.h"
4330370Skarels #include "kernel.h"
4430519Ssam #include "ioctl.h"
4530756Skarels #include "stat.h"
4624004Ssam 
4729951Skarels #include "../tahoe/cpu.h"
4829951Skarels #include "../tahoe/mtpr.h"
4929951Skarels #include "../tahoe/pte.h"
5029951Skarels 
5125675Ssam #include "../tahoevba/vbavar.h"
5225928Ssam #include "../tahoevba/vdreg.h"
5324004Ssam 
5432211Skarels #ifndef	COMPAT_42
5530519Ssam #define	COMPAT_42
5632211Skarels #endif
5734396Skarels #define	B_FORMAT	B_XXX		/* XXX */
5830519Ssam 
5930519Ssam #define vdunit(dev)	(minor(dev) >> 3)
6030519Ssam #define vdpart(dev)	(minor(dev) & 0x07)
6130519Ssam #define	vdminor(unit,part)	(((unit) << 3) | (part))
6224004Ssam 
6324004Ssam struct	vba_ctlr *vdminfo[NVD];
6429564Ssam struct  vba_device *vddinfo[NDK];
6530756Skarels int	vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy();
6634528Skarels long	vdstd[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 };
6725675Ssam struct	vba_driver vddriver =
6834528Skarels   { vdprobe, vdslave, vdattach, vddgo, vdstd, "dk", vddinfo, "vd", vdminfo };
6924004Ssam 
7024004Ssam /*
7130519Ssam  * Per-controller state.
7230519Ssam  */
7330519Ssam struct vdsoftc {
7430519Ssam 	u_short	vd_flags;
7530519Ssam #define	VD_INIT		0x1	/* controller initialized */
7630519Ssam #define	VD_STARTED	0x2	/* start command issued */
7730519Ssam #define	VD_DOSEEKS	0x4	/* should overlap seeks */
7830756Skarels #define	VD_SCATGATH	0x8	/* can do scatter-gather commands (correctly) */
7935082Skarels #define	VD_LOCKED	0x10	/* locked for direct controller access */
8035082Skarels #define	VD_WAIT		0x20	/* someone needs direct controller access */
8130519Ssam 	u_short	vd_type;	/* controller type */
8230519Ssam 	u_short	vd_wticks;	/* timeout */
8330519Ssam 	struct	mdcb vd_mdcb;	/* master command block */
8430519Ssam 	u_long	vd_mdcbphys;	/* physical address of vd_mdcb */
8530519Ssam 	struct	dcb vd_dcb;	/* i/o command block */
8630519Ssam 	u_long	vd_dcbphys;	/* physical address of vd_dcb */
8730601Skarels 	struct	vb_buf vd_rbuf;	/* vba resources */
8830519Ssam } vdsoftc[NVD];
8930519Ssam 
9034396Skarels #define	VDMAXTIME	20	/* max time for operation, sec. */
9134396Skarels 
9230519Ssam /*
9325675Ssam  * Per-drive state.
9425675Ssam  */
9530519Ssam struct	dksoftc {
9634076Skarels 	int	dk_state;	/* open fsm */
9730756Skarels #ifndef SECSIZE
9830756Skarels 	u_short	dk_bshift;	/* shift for * (DEV_BSIZE / sectorsize) XXX */
9930756Skarels #endif SECSIZE
10034076Skarels 	int	dk_wlabel;	/* label sector is currently writable */
10132576Skarels 	u_long	dk_copenpart;	/* character units open on this drive */
10232576Skarels 	u_long	dk_bopenpart;	/* block units open on this drive */
10332576Skarels 	u_long	dk_openpart;	/* all units open on this drive */
10430519Ssam 	u_int	dk_curcyl;	/* last selected cylinder */
10530756Skarels 	struct	skdcb dk_dcb;	/* seek command block */
10630519Ssam 	u_long	dk_dcbphys;	/* physical address of dk_dcb */
10734396Skarels 	int	df_reg[3];	/* for formatting, in-out parameters */
10830519Ssam } dksoftc[NDK];
10924004Ssam 
11024004Ssam /*
11130519Ssam  * Drive states.  Used during steps of open/initialization.
11230519Ssam  * States < OPEN (> 0) are transient, during an open operation.
11334076Skarels  * OPENRAW is used for unlabeled disks, to allow format operations.
11425675Ssam  */
11530519Ssam #define	CLOSED		0		/* disk is closed */
11630519Ssam #define	WANTOPEN	1		/* open requested, not started */
11730519Ssam #define	WANTOPENRAW	2		/* open requested, no label */
11830519Ssam #define	RDLABEL		3		/* reading pack label */
11930519Ssam #define	OPEN		4		/* intialized and ready */
12030519Ssam #define	OPENRAW		5		/* open, no label */
12124004Ssam 
12230519Ssam struct	buf dkutab[NDK];	/* i/o queue headers */
12330519Ssam struct	disklabel dklabel[NDK];	/* pack labels */
12424004Ssam 
12530519Ssam #define b_cylin	b_resid
12630574Skarels #define	b_track	b_error		/* used for seek commands */
12730574Skarels #define	b_seekf	b_forw		/* second queue on um_tab */
12830574Skarels #define	b_seekl	b_back		/* second queue on um_tab */
12930519Ssam 
13030519Ssam int	vdwstart, vdwatch();
13130519Ssam 
13224004Ssam /*
13325675Ssam  * See if the controller is really there; if so, initialize it.
13425675Ssam  */
13525857Ssam vdprobe(reg, vm)
13625857Ssam 	caddr_t reg;
13725857Ssam 	struct vba_ctlr *vm;
13825675Ssam {
13925857Ssam 	register br, cvec;		/* must be r12, r11 */
14030519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)reg;
14130519Ssam 	struct vdsoftc *vd;
14230573Skarels 	int s;
14325857Ssam 
14430370Skarels #ifdef lint
14530370Skarels 	br = 0; cvec = br; br = cvec;
14630370Skarels 	vdintr(0);
14730370Skarels #endif
14825857Ssam 	if (badaddr((caddr_t)reg, 2))
14925675Ssam 		return (0);
15030519Ssam 	vd = &vdsoftc[vm->um_ctlr];
15130519Ssam 	vdaddr->vdreset = 0xffffffff;
15225675Ssam 	DELAY(1000000);
15330519Ssam 	if (vdaddr->vdreset != (unsigned)0xffffffff) {
15430519Ssam 		vd->vd_type = VDTYPE_VDDC;
15530519Ssam 		vd->vd_flags &= ~VD_DOSEEKS;
15625675Ssam 		DELAY(1000000);
15725675Ssam 	} else {
15830519Ssam 		vd->vd_type = VDTYPE_SMDE;
15930519Ssam 		vd->vd_flags |= VD_DOSEEKS;
16030519Ssam 		vdaddr->vdrstclr = 0;
16125675Ssam 		DELAY(3000000);
16230519Ssam 		vdaddr->vdcsr = 0;
16330519Ssam 		vdaddr->vdtcf_mdcb = AM_ENPDA;
16430519Ssam 		vdaddr->vdtcf_dcb = AM_ENPDA;
16530519Ssam 		vdaddr->vdtcf_trail = AM_ENPDA;
16630519Ssam 		vdaddr->vdtcf_data = AM_ENPDA;
167*35413Skarels 		vdaddr->vdccf = CCF_SEN | CCF_DIU | CCF_STS |
16829921Skarels 		    XMD_32BIT | BSZ_16WRD |
16925925Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
17025675Ssam 	}
17130519Ssam 	vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb);
17230519Ssam 	vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb);
17330519Ssam 	vm->um_addr = reg;		/* XXX */
17430573Skarels 	s = spl7();
175*35413Skarels 	if (!vdcmd(vm, VDOP_INIT, 10, 0) || !vdcmd(vm, VDOP_DIAG, 10, 0)) {
17630519Ssam 		printf("vd%d: %s cmd failed\n", vm->um_ctlr,
17730519Ssam 		    vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
17830573Skarels 		splx(s);
17930519Ssam 		return (0);
18030519Ssam 	}
18130756Skarels 	if (vd->vd_type == VDTYPE_SMDE) {
18230756Skarels 		vd->vd_dcb.trail.idtrail.date = 0;
183*35413Skarels 		if (vdcmd(vm, VDOP_IDENT, 10, 0)) {
18430756Skarels 			uncache(&vd->vd_dcb.trail.idtrail.date);
18530756Skarels 			if (vd->vd_dcb.trail.idtrail.date != 0)
18630756Skarels 				vd->vd_flags |= VD_SCATGATH;
18730756Skarels 		}
18830756Skarels 	}
18930573Skarels 	splx(s);
19025925Ssam 	/*
19125950Ssam 	 * Allocate page tables and i/o buffer.
19225925Ssam 	 */
19332211Skarels 	if (vbainit(&vd->vd_rbuf, MAXPHYS,
19432211Skarels 	    vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) {
19532211Skarels 		printf("vd%d: vbainit failed\n", vm->um_ctlr);
19632211Skarels 		return (0);
19732211Skarels 	}
19825857Ssam 	br = 0x17, cvec = 0xe0 + vm->um_ctlr;	/* XXX */
19930519Ssam 	return (sizeof (struct vddevice));
20025675Ssam }
20124004Ssam 
20224004Ssam /*
20330519Ssam  * See if a drive is really there.
20430519Ssam  *
20530519Ssam  * Can't read pack label here as various data structures
20630519Ssam  * aren't setup for doing a read in a straightforward
20730519Ssam  * manner.  Instead just probe for the drive and leave
20830519Ssam  * the pack label stuff to the attach routine.
20925675Ssam  */
21034076Skarels /* ARGSUSED */
21134076Skarels vdslave(vi, vdaddr)
21225675Ssam 	register struct vba_device *vi;
21330519Ssam 	struct vddevice *vdaddr;
21425675Ssam {
21530519Ssam 	register struct disklabel *lp = &dklabel[vi->ui_unit];
21632211Skarels 	register struct dksoftc *dk = &dksoftc[vi->ui_unit];
21730519Ssam 	struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
21824004Ssam 
21930519Ssam 	if ((vd->vd_flags&VD_INIT) == 0) {
220*35413Skarels 		printf("vd%d: %s controller", vi->ui_ctlr,
221*35413Skarels 		    vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE");
222*35413Skarels 		if (vd->vd_flags & VD_SCATGATH) {
223*35413Skarels 			char rev[5];
224*35413Skarels 
225*35413Skarels 			bcopy((caddr_t)&vd->vd_dcb.trail.idtrail.rev, rev,
226*35413Skarels 			    sizeof(vd->vd_dcb.trail.idtrail.rev));
227*35413Skarels 			printf(" firmware rev %s (%d-%d-%d)", rev,
228*35413Skarels 			    (vd->vd_dcb.trail.idtrail.date >> 8) & 0xff,
229*35413Skarels 			    vd->vd_dcb.trail.idtrail.date & 0xff,
230*35413Skarels 			    (vd->vd_dcb.trail.idtrail.date >> 16) & 0xffff);
231*35413Skarels 		}
232*35413Skarels 		printf("\n");
23330519Ssam 		vd->vd_flags |= VD_INIT;
23425675Ssam 	}
23530519Ssam 
23625675Ssam 	/*
23730519Ssam 	 * Initialize label enough to do a reset on
23830519Ssam 	 * the drive.  The remainder of the default
23930519Ssam 	 * label values will be filled in in vdinit
24030519Ssam 	 * at attach time.
24125675Ssam 	 */
24232211Skarels 	if (vd->vd_type == VDTYPE_SMDE)
24332211Skarels 		lp->d_secsize = VD_MAXSECSIZE;
24432211Skarels 	else
24532211Skarels 		lp->d_secsize = VDDC_SECSIZE;
24634396Skarels 	lp->d_nsectors = 66;		/* only used on smd-e */
24734076Skarels 	lp->d_ntracks = 23;
24834396Skarels 	lp->d_ncylinders = 850;
24934396Skarels 	lp->d_secpercyl = 66*23;
250*35413Skarels 	lp->d_rpm = 3600;
25134592Skarels 	lp->d_npartitions = 1;
25234592Skarels 	lp->d_partitions[0].p_offset = 0;
25334592Skarels 	lp->d_partitions[0].p_size = LABELSECTOR + 1;
25424004Ssam 
25530519Ssam 	/*
25630519Ssam 	 * Initialize invariant portion of
25730519Ssam 	 * dcb used for overlapped seeks.
25830519Ssam 	 */
25930519Ssam 	dk->dk_dcb.opcode = VDOP_SEEK;
26030519Ssam 	dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA;
26130519Ssam 	dk->dk_dcb.devselect = vi->ui_slave;
26230756Skarels 	dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long);
26330519Ssam 	dk->dk_dcb.trail.sktrail.skaddr.sector = 0;
26430519Ssam 	dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb);
26532211Skarels #ifndef SECSIZE
26632211Skarels 	vd_setsecsize(dk, lp);
26732211Skarels #endif
26832211Skarels 	return (vdreset_drive(vi));
26932211Skarels }
27032211Skarels 
27132211Skarels vdattach(vi)
27232211Skarels 	register struct vba_device *vi;
27332211Skarels {
27432211Skarels 	register int unit = vi->ui_unit;
27532211Skarels 	register struct disklabel *lp = &dklabel[unit];
27632211Skarels 
27730601Skarels 	/*
27830601Skarels 	 * Try to initialize device and read pack label.
27930601Skarels 	 */
28030601Skarels 	if (vdinit(vdminor(unit, 0), 0) != 0) {
28130601Skarels 		printf(": unknown drive type");
28230601Skarels 		return;
28330601Skarels 	}
28432211Skarels 	if (dksoftc[unit].dk_state == OPEN)
28532211Skarels 		printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>",
28632211Skarels 		    lp->d_typename, lp->d_secsize,
28732211Skarels 		    lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors);
28830519Ssam 	/*
28930519Ssam 	 * (60 / rpm) / (sectors per track * (bytes per sector / 2))
29030519Ssam 	 */
29130519Ssam 	if (vi->ui_dk >= 0)
29230519Ssam 		dk_mspw[vi->ui_dk] = 120.0 /
29330519Ssam 		    (lp->d_rpm * lp->d_nsectors * lp->d_secsize);
29430519Ssam #ifdef notyet
29530573Skarels 	addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp);
29630519Ssam #endif
29724004Ssam }
29824004Ssam 
29930756Skarels vdopen(dev, flags, fmt)
30030519Ssam 	dev_t dev;
30130756Skarels 	int flags, fmt;
30224004Ssam {
30330519Ssam 	register unit = vdunit(dev);
30430519Ssam 	register struct disklabel *lp;
30530519Ssam 	register struct dksoftc *dk;
30630519Ssam 	register struct partition *pp;
30730519Ssam 	struct vba_device *vi;
30830756Skarels 	int s, error, part = vdpart(dev), mask = 1 << part;
30930519Ssam 	daddr_t start, end;
31024004Ssam 
31130519Ssam 	if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
31230519Ssam 		return (ENXIO);
31330519Ssam 	lp = &dklabel[unit];
31430519Ssam 	dk = &dksoftc[unit];
31530519Ssam 
31630519Ssam 	s = spl7();
31730519Ssam 	while (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
31830519Ssam 	    dk->dk_state != CLOSED)
31930519Ssam 		sleep((caddr_t)dk, PZERO+1);
32030519Ssam 	splx(s);
32130519Ssam 	if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
32230519Ssam 		if (error = vdinit(dev, flags))
32330519Ssam 			return (error);
32430573Skarels 
32530573Skarels 	if (vdwstart == 0) {
32630573Skarels 		timeout(vdwatch, (caddr_t)0, hz);
32730573Skarels 		vdwstart++;
32830573Skarels 	}
32930519Ssam 	/*
33030519Ssam 	 * Warn if a partion is opened
33130519Ssam 	 * that overlaps another partition which is open
33230519Ssam 	 * unless one is the "raw" partition (whole disk).
33330519Ssam 	 */
33432211Skarels #define	RAWPART		8		/* 'x' partition */	/* XXX */
33532576Skarels 	if ((dk->dk_openpart & mask) == 0 && part != RAWPART) {
33630519Ssam 		pp = &lp->d_partitions[part];
33730519Ssam 		start = pp->p_offset;
33830519Ssam 		end = pp->p_offset + pp->p_size;
33930519Ssam 		for (pp = lp->d_partitions;
34030519Ssam 		     pp < &lp->d_partitions[lp->d_npartitions]; pp++) {
34130519Ssam 			if (pp->p_offset + pp->p_size <= start ||
34230519Ssam 			    pp->p_offset >= end)
34330519Ssam 				continue;
34430519Ssam 			if (pp - lp->d_partitions == RAWPART)
34530519Ssam 				continue;
34630519Ssam 			if (dk->dk_openpart & (1 << (pp - lp->d_partitions)))
34730519Ssam 				log(LOG_WARNING,
34830519Ssam 				    "dk%d%c: overlaps open partition (%c)\n",
34930519Ssam 				    unit, part + 'a',
35030519Ssam 				    pp - lp->d_partitions + 'a');
35130519Ssam 		}
35224004Ssam 	}
35330519Ssam 	if (part >= lp->d_npartitions)
35430519Ssam 		return (ENXIO);
35530756Skarels 	dk->dk_openpart |= mask;
35630756Skarels 	switch (fmt) {
35730756Skarels 	case S_IFCHR:
35830756Skarels 		dk->dk_copenpart |= mask;
35930756Skarels 		break;
36030756Skarels 	case S_IFBLK:
36130756Skarels 		dk->dk_bopenpart |= mask;
36230756Skarels 		break;
36330756Skarels 	}
36430519Ssam 	return (0);
36525675Ssam }
36624004Ssam 
36734528Skarels /* ARGSUSED */
36830756Skarels vdclose(dev, flags, fmt)
36930519Ssam 	dev_t dev;
37030756Skarels 	int flags, fmt;
37124004Ssam {
37230519Ssam 	register int unit = vdunit(dev);
37330519Ssam 	register struct dksoftc *dk = &dksoftc[unit];
37430756Skarels 	int part = vdpart(dev), mask = 1 << part;
37524004Ssam 
37630756Skarels 	switch (fmt) {
37730756Skarels 	case S_IFCHR:
37830756Skarels 		dk->dk_copenpart &= ~mask;
37930756Skarels 		break;
38030756Skarels 	case S_IFBLK:
38130756Skarels 		dk->dk_bopenpart &= ~mask;
38230756Skarels 		break;
38330756Skarels 	}
38430756Skarels 	if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0)
38530756Skarels 		dk->dk_openpart &= ~mask;
38630519Ssam 	/*
38730519Ssam 	 * Should wait for i/o to complete on this partition
38830519Ssam 	 * even if others are open, but wait for work on blkflush().
38930519Ssam 	 */
39030519Ssam 	if (dk->dk_openpart == 0) {
39130573Skarels 		int s = spl7();
39230573Skarels 		while (dkutab[unit].b_actf)
39330573Skarels 			sleep((caddr_t)dk, PZERO-1);
39430519Ssam 		splx(s);
39530519Ssam 		dk->dk_state = CLOSED;
39634076Skarels 		dk->dk_wlabel = 0;
39724004Ssam 	}
39830756Skarels 	return (0);
39925675Ssam }
40024004Ssam 
40130519Ssam vdinit(dev, flags)
40230519Ssam 	dev_t dev;
40330519Ssam 	int flags;
40425675Ssam {
40530519Ssam 	register struct disklabel *lp;
40630519Ssam 	register struct dksoftc *dk;
40730519Ssam 	struct vba_device *vi;
40830519Ssam 	int unit = vdunit(dev), error = 0;
40930756Skarels 	char *msg, *readdisklabel();
41030519Ssam 	extern int cold;
41125675Ssam 
41230519Ssam 	dk = &dksoftc[unit];
41330519Ssam 	if (flags & O_NDELAY) {
41430519Ssam 		dk->dk_state = OPENRAW;
41534528Skarels 		return (0);
41630519Ssam 	}
41730519Ssam 	dk->dk_state = RDLABEL;
41830519Ssam 	lp = &dklabel[unit];
41930519Ssam 	vi = vddinfo[unit];
42030756Skarels 	if (msg = readdisklabel(dev, vdstrategy, lp)) {
42134076Skarels 		if (cold) {
42230601Skarels 			printf(": %s", msg);
42334076Skarels 			dk->dk_state = CLOSED;
42434076Skarels 		} else {
42532211Skarels 			log(LOG_ERR, "dk%d: %s\n", unit, msg);
42634076Skarels 			dk->dk_state = OPENRAW;
42734076Skarels 		}
42830519Ssam #ifdef COMPAT_42
42935082Skarels 		vdlock(vi->ui_ctlr);
43034076Skarels 		if (vdmaptype(vi, lp))
43130519Ssam 			dk->dk_state = OPEN;
43235082Skarels 		vdunlock(vi->ui_ctlr);
43330519Ssam #endif
43430756Skarels 	} else {
43530756Skarels 		/*
43630756Skarels 		 * Now that we have the label, configure
43730756Skarels 		 * the correct drive parameters.
43830756Skarels 		 */
43935082Skarels 		vdlock(vi->ui_ctlr);
44032211Skarels 		if (vdreset_drive(vi))
44132211Skarels 			dk->dk_state = OPEN;
44232211Skarels 		else {
44330756Skarels 			dk->dk_state = CLOSED;
44430756Skarels 			error = ENXIO;
44532211Skarels 		}
44635082Skarels 		vdunlock(vi->ui_ctlr);
44725675Ssam 	}
44830756Skarels #ifndef SECSIZE
44932211Skarels 	vd_setsecsize(dk, lp);
45032211Skarels #endif
45130519Ssam 	wakeup((caddr_t)dk);
45230519Ssam 	return (error);
45324004Ssam }
45424004Ssam 
45532211Skarels #ifndef SECSIZE
45632211Skarels vd_setsecsize(dk, lp)
45732211Skarels 	register struct dksoftc *dk;
45832211Skarels 	register struct disklabel *lp;
45932211Skarels {
46032211Skarels 	int mul;
46132211Skarels 
46232211Skarels 	/*
46332211Skarels 	 * Calculate scaling shift for mapping
46432211Skarels 	 * DEV_BSIZE blocks to drive sectors.
46532211Skarels 	 */
46632211Skarels 	mul = DEV_BSIZE / lp->d_secsize;
46732211Skarels 	dk->dk_bshift = 0;
46832211Skarels 	while ((mul >>= 1) > 0)
46932211Skarels 		dk->dk_bshift++;
47032211Skarels }
47132211Skarels #endif SECSIZE
47232211Skarels 
47325675Ssam /*ARGSUSED*/
47430519Ssam vddgo(vm)
47530519Ssam 	struct vba_device *vm;
47624004Ssam {
47724004Ssam 
47824004Ssam }
47924004Ssam 
48024004Ssam vdstrategy(bp)
48125675Ssam 	register struct buf *bp;
48224004Ssam {
48330519Ssam 	register struct vba_device *vi;
48430519Ssam 	register struct disklabel *lp;
48530519Ssam 	register struct dksoftc *dk;
48630519Ssam 	register int unit;
48730573Skarels 	register daddr_t sn;
48830519Ssam 	struct buf *dp;
48930573Skarels 	daddr_t sz, maxsz;
49030519Ssam 	int part, s;
49124004Ssam 
49230519Ssam 	unit = vdunit(bp->b_dev);
49332211Skarels 	if (unit >= NDK) {
49429954Skarels 		bp->b_error = ENXIO;
49525675Ssam 		goto bad;
49629954Skarels 	}
49730519Ssam 	vi = vddinfo[unit];
49830519Ssam 	lp = &dklabel[unit];
49930519Ssam 	if (vi == 0 || vi->ui_alive == 0) {
50030519Ssam 		bp->b_error = ENXIO;
50130519Ssam 		goto bad;
50230519Ssam 	}
50330519Ssam 	dk = &dksoftc[unit];
50430519Ssam 	if (dk->dk_state < OPEN)
50530519Ssam 		goto q;
50634076Skarels 	if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) {
50734076Skarels 		bp->b_error = EROFS;
50834076Skarels 		goto bad;
50934076Skarels 	}
51030519Ssam 	part = vdpart(bp->b_dev);
51130519Ssam 	if ((dk->dk_openpart & (1 << part)) == 0) {
51230519Ssam 		bp->b_error = ENODEV;
51330519Ssam 		goto bad;
51430519Ssam 	}
51532211Skarels 	sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
51630519Ssam 	maxsz = lp->d_partitions[part].p_size;
51730756Skarels #ifndef SECSIZE
51830756Skarels 	sn = bp->b_blkno << dk->dk_bshift;
51930756Skarels #else SECSIZE
52030573Skarels 	sn = bp->b_blkno;
52130756Skarels #endif SECSIZE
52234076Skarels 	if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR &&
52334076Skarels #if LABELSECTOR != 0
52434076Skarels 	    sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR &&
52534076Skarels #endif
52634076Skarels 	    (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) {
52734076Skarels 		bp->b_error = EROFS;
52834076Skarels 		goto bad;
52934076Skarels 	}
53030519Ssam 	if (sn < 0 || sn + sz > maxsz) {
53130519Ssam 		if (sn == maxsz) {
53229954Skarels 			bp->b_resid = bp->b_bcount;
53329954Skarels 			goto done;
53429954Skarels 		}
53530756Skarels 		sz = maxsz - sn;
53630573Skarels 		if (sz <= 0) {
53730573Skarels 			bp->b_error = EINVAL;
53830573Skarels 			goto bad;
53930573Skarels 		}
54030573Skarels 		bp->b_bcount = sz * lp->d_secsize;
54125675Ssam 	}
54230519Ssam 	bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl;
54330756Skarels #ifdef SECSIZE
54430756Skarels if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0)
54530756Skarels panic("vdstrat blksize");
54630756Skarels #endif SECSIZE
54730519Ssam q:
54825675Ssam 	s = spl7();
54930519Ssam 	dp = &dkutab[vi->ui_unit];
55030519Ssam 	disksort(dp, bp);
55130519Ssam 	if (!dp->b_active) {
55230519Ssam 		(void) vdustart(vi);
55330573Skarels 		if (!vi->ui_mi->um_tab.b_active)
55430519Ssam 			vdstart(vi->ui_mi);
55524004Ssam 	}
55630519Ssam 	splx(s);
55724004Ssam 	return;
55825675Ssam bad:
55929954Skarels 	bp->b_flags |= B_ERROR;
56029954Skarels done:
56130519Ssam 	biodone(bp);
56230519Ssam 	return;
56324004Ssam }
56424004Ssam 
56530519Ssam vdustart(vi)
56630519Ssam 	register struct vba_device *vi;
56724004Ssam {
56830519Ssam 	register struct buf *bp, *dp;
56930519Ssam 	register struct vba_ctlr *vm;
57030519Ssam 	register int unit = vi->ui_unit;
57130519Ssam 	register struct dksoftc *dk;
57230519Ssam 	register struct vdsoftc *vd;
57330519Ssam 	struct disklabel *lp;
57424004Ssam 
57530519Ssam 	dp = &dkutab[unit];
57630519Ssam 	/*
57730519Ssam 	 * If queue empty, nothing to do.
57830519Ssam 	 */
57930519Ssam 	if ((bp = dp->b_actf) == NULL)
58030519Ssam 		return;
58130519Ssam 	/*
58230574Skarels 	 * If drive is off-cylinder and controller supports seeks,
58330574Skarels 	 * place drive on seek queue for controller.
58430574Skarels 	 * Otherwise, place on transfer queue.
58530519Ssam 	 */
58630519Ssam 	vd = &vdsoftc[vi->ui_ctlr];
58730519Ssam 	dk = &dksoftc[unit];
58830574Skarels 	vm = vi->ui_mi;
58930519Ssam 	if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) {
59030519Ssam 		lp = &dklabel[unit];
59130574Skarels 		bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors;
59230574Skarels 		if (vm->um_tab.b_seekf == NULL)
59330574Skarels 			vm->um_tab.b_seekf = dp;
59430574Skarels 		else
59530574Skarels 			vm->um_tab.b_seekl->b_forw = dp;
59630574Skarels 		vm->um_tab.b_seekl = dp;
59730574Skarels 	} else {
59830574Skarels 		if (vm->um_tab.b_actf == NULL)
59930574Skarels 			vm->um_tab.b_actf = dp;
60030574Skarels 		else
60130574Skarels 			vm->um_tab.b_actl->b_forw = dp;
60230574Skarels 		vm->um_tab.b_actl = dp;
60330519Ssam 	}
60430573Skarels 	dp->b_forw = NULL;
60530573Skarels 	dp->b_active++;
60625675Ssam }
60725675Ssam 
60825675Ssam /*
60930519Ssam  * Start next transfer on a controller.
61030574Skarels  * There are two queues of drives, the first on-cylinder
61130574Skarels  * and the second off-cylinder from their next transfers.
61230574Skarels  * Perform the first transfer for the first drive on the on-cylinder
61330574Skarels  * queue, if any, otherwise the first transfer for the first drive
61430574Skarels  * on the second queue.  Initiate seeks on remaining drives on the
61530574Skarels  * off-cylinder queue, then move them all to the on-cylinder queue.
61625675Ssam  */
61730519Ssam vdstart(vm)
61830519Ssam 	register struct vba_ctlr *vm;
61925675Ssam {
62025675Ssam 	register struct buf *bp;
62130519Ssam 	register struct vba_device *vi;
62230519Ssam 	register struct vdsoftc *vd;
62330519Ssam 	register struct dksoftc *dk;
62430519Ssam 	register struct disklabel *lp;
62530519Ssam 	register struct dcb **dcbp;
62630519Ssam 	struct buf *dp;
62730519Ssam 	int sn, tn;
62825675Ssam 
62930519Ssam loop:
63030519Ssam 	/*
63130519Ssam 	 * Pull a request off the controller queue.
63230519Ssam 	 */
63330574Skarels 	if ((dp = vm->um_tab.b_actf) == NULL &&
63430574Skarels 	    (dp = vm->um_tab.b_seekf) == NULL)
63530519Ssam 		return;
63630519Ssam 	if ((bp = dp->b_actf) == NULL) {
63730601Skarels 		if (dp == vm->um_tab.b_actf)
63830601Skarels 			vm->um_tab.b_actf = dp->b_forw;
63930601Skarels 		else
64030601Skarels 			vm->um_tab.b_seekf = dp->b_forw;
64130519Ssam 		goto loop;
64230519Ssam 	}
64325675Ssam 
64424004Ssam 	/*
64530519Ssam 	 * Mark controller busy, and determine
64630519Ssam 	 * destination of this request.
64724004Ssam 	 */
64830519Ssam 	vm->um_tab.b_active++;
64930519Ssam 	vi = vddinfo[vdunit(bp->b_dev)];
65030519Ssam 	dk = &dksoftc[vi->ui_unit];
65130756Skarels #ifndef SECSIZE
65230756Skarels 	sn = bp->b_blkno << dk->dk_bshift;
65330756Skarels #else SECSIZE
65430573Skarels 	sn = bp->b_blkno;
65530756Skarels #endif SECSIZE
65630519Ssam 	lp = &dklabel[vi->ui_unit];
65730519Ssam 	sn %= lp->d_secpercyl;
65830519Ssam 	tn = sn / lp->d_nsectors;
65930519Ssam 	sn %= lp->d_nsectors;
66030519Ssam 
66130519Ssam 	/*
66230519Ssam 	 * Construct dcb for read/write command.
66330519Ssam 	 */
66430519Ssam 	vd = &vdsoftc[vm->um_ctlr];
66530519Ssam 	vd->vd_dcb.intflg = DCBINT_DONE;
66632211Skarels 	vd->vd_dcb.devselect = dk->dk_dcb.devselect;
66730519Ssam 	vd->vd_dcb.operrsta = 0;
66830519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
66930519Ssam 	vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin;
67030519Ssam 	vd->vd_dcb.trail.rwtrail.disk.track = tn;
67130519Ssam 	vd->vd_dcb.trail.rwtrail.disk.sector = sn;
67230574Skarels 	dk->dk_curcyl = bp->b_cylin;
67330574Skarels 	bp->b_track = 0;		/* init overloaded field */
67430756Skarels 	vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
67534396Skarels 	if (bp->b_flags & B_FORMAT)
67634396Skarels 		vd->vd_dcb.opcode = dk->dk_op;
67734396Skarels 	else if (vd->vd_flags & VD_SCATGATH &&
67834396Skarels 	    ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0)
67930756Skarels 		vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW;
68034396Skarels 	else
68130756Skarels 		vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD;
68234396Skarels 
68334396Skarels 	switch (vd->vd_dcb.opcode) {
68434396Skarels 	case VDOP_FSECT:
68534396Skarels 		vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
68634396Skarels 		vd->vd_dcb.trail.fmtrail.nsectors = bp->b_bcount /
68734396Skarels 		    lp->d_secsize;
68834396Skarels 		vd->vd_dcb.trail.fmtrail.hdr = *(dskadr *)&dk->dk_althdr;
68934396Skarels 		vd->vd_dcb.trail.rwtrail.disk.cylinder |= dk->dk_fmtflags;
69034396Skarels 		goto setupaddr;
69134396Skarels 
69234396Skarels 	case VDOP_RDRAW:
69334396Skarels 	case VDOP_RD:
69434396Skarels 	case VDOP_WD:
69534396Skarels 		vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1;
69634396Skarels setupaddr:
69730756Skarels 		vd->vd_dcb.trail.rwtrail.memadr =
69834528Skarels 			vbasetup(bp, &vd->vd_rbuf, (int)lp->d_secsize);
69934396Skarels 		break;
70034396Skarels 
70134396Skarels 	case VDOP_RAS:
70234396Skarels 	case VDOP_GAW:
70334396Skarels 		vd->vd_dcb.trailcnt += vba_sgsetup(bp, &vd->vd_rbuf,
70434396Skarels 		    &vd->vd_dcb.trail.sgtrail);
70534396Skarels 		break;
70630756Skarels 	}
70730574Skarels 	if (vi->ui_dk >= 0) {
70830574Skarels 		dk_busy |= 1<<vi->ui_dk;
70930574Skarels 		dk_xfer[vi->ui_dk]++;
71030574Skarels 		dk_wds[vi->ui_dk] += bp->b_bcount>>6;
71130574Skarels 	}
71230519Ssam 
71330519Ssam 	/*
71430519Ssam 	 * Look for any seeks to be performed on other drives on this
71530519Ssam 	 * controller.  If overlapped seeks exist, insert seek commands
71630519Ssam 	 * on the controller's command queue before the transfer.
71730519Ssam 	 */
71830519Ssam 	dcbp = &vd->vd_mdcb.mdcb_head;
71930519Ssam 
72030574Skarels 	if (dp == vm->um_tab.b_seekf)
72130574Skarels 		dp = dp->b_forw;
72230574Skarels 	else
72330574Skarels 		dp = vm->um_tab.b_seekf;
72430574Skarels 	for (; dp != NULL; dp = dp->b_forw) {
72530574Skarels 		if ((bp = dp->b_actf) == NULL)
72630574Skarels 			continue;
72730574Skarels 		vi = vddinfo[vdunit(bp->b_dev)];
72830574Skarels 		dk = &dksoftc[vi->ui_unit];
72930519Ssam 		dk->dk_curcyl = bp->b_cylin;
73030574Skarels 		if (vi->ui_dk >= 0)
73130574Skarels 			dk_seek[vi->ui_dk]++;
73230574Skarels 		dk->dk_dcb.operrsta = 0;
73330574Skarels 		dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin;
73430574Skarels 		dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track;
73530574Skarels 		*dcbp = (struct dcb *)dk->dk_dcbphys;
73630574Skarels 		dcbp = &dk->dk_dcb.nxtdcb;
73724004Ssam 	}
73830519Ssam 	*dcbp = (struct dcb *)vd->vd_dcbphys;
73930574Skarels 	if (vm->um_tab.b_actf)
74030574Skarels 		vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf;
74130574Skarels 	else
74230574Skarels 		vm->um_tab.b_actf = vm->um_tab.b_seekf;
74330601Skarels 	if (vm->um_tab.b_seekf)
74430601Skarels 		vm->um_tab.b_actl = vm->um_tab.b_seekl;
74530574Skarels 	vm->um_tab.b_seekf = 0;
74624004Ssam 
74730519Ssam 	/*
74830519Ssam 	 * Initiate operation.
74930519Ssam 	 */
75030519Ssam 	vd->vd_mdcb.mdcb_status = 0;
75130519Ssam 	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
75224004Ssam }
75324004Ssam 
75435082Skarels /*
75535082Skarels  * Wait for controller to finish current operation
75635082Skarels  * so that direct controller accesses can be done.
75735082Skarels  */
75835082Skarels vdlock(ctlr)
75935082Skarels {
76035082Skarels 	register struct vba_ctlr *vm = vdminfo[ctlr];
76135082Skarels 	register struct vdsoftc *vd = &vdsoftc[ctlr];
76235082Skarels 	int s;
76335082Skarels 
76435082Skarels 	s = spl7();
76535082Skarels 	while (vm->um_tab.b_active || vd->vd_flags & VD_LOCKED) {
76635082Skarels 		vd->vd_flags |= VD_WAIT;
76735082Skarels 		sleep((caddr_t)vd, PRIBIO);
76835082Skarels 	}
76935082Skarels 	vd->vd_flags |= VD_LOCKED;
77035082Skarels 	splx(s);
77135082Skarels }
77235082Skarels 
77335082Skarels /*
77435082Skarels  * Continue normal operations after pausing for
77535082Skarels  * munging the controller directly.
77635082Skarels  */
77735082Skarels vdunlock(ctlr)
77835082Skarels {
77935082Skarels 	register struct vba_ctlr *vm = vdminfo[ctlr];
78035082Skarels 	register struct vdsoftc *vd = &vdsoftc[ctlr];
78135082Skarels 
78235082Skarels 	vd->vd_flags &= ~VD_LOCKED;
78335082Skarels 	if (vd->vd_flags & VD_WAIT) {
78435082Skarels 		vd->vd_flags &= ~VD_WAIT;
78535082Skarels 		wakeup((caddr_t)vd);
78635082Skarels 	} else if (vm->um_tab.b_actf || vm->um_tab.b_seekf)
78735082Skarels 		vdstart(vm);
78835082Skarels }
78935082Skarels 
79030519Ssam #define	DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE)
79124004Ssam /*
79224004Ssam  * Handle a disk interrupt.
79324004Ssam  */
79425675Ssam vdintr(ctlr)
79530519Ssam 	register ctlr;
79624004Ssam {
79730519Ssam 	register struct buf *bp, *dp;
79830519Ssam 	register struct vba_ctlr *vm = vdminfo[ctlr];
79930519Ssam 	register struct vba_device *vi;
80030519Ssam 	register struct vdsoftc *vd = &vdsoftc[ctlr];
80130519Ssam 	register status;
80234528Skarels 	int timedout;
80330573Skarels 	struct dksoftc *dk;
80424004Ssam 
80530519Ssam 	if (!vm->um_tab.b_active) {
80625675Ssam 		printf("vd%d: stray interrupt\n", ctlr);
80724004Ssam 		return;
80824004Ssam 	}
80925675Ssam 	/*
81030519Ssam 	 * Get device and block structures, and a pointer
81130519Ssam 	 * to the vba_device for the drive.
81225675Ssam 	 */
81330519Ssam 	dp = vm->um_tab.b_actf;
81430519Ssam 	bp = dp->b_actf;
81530519Ssam 	vi = vddinfo[vdunit(bp->b_dev)];
81634528Skarels 	dk = &dksoftc[vi->ui_unit];
81730574Skarels 	if (vi->ui_dk >= 0)
81830574Skarels 		dk_busy &= ~(1<<vi->ui_dk);
81934396Skarels 	timedout = (vd->vd_wticks >= VDMAXTIME);
82030519Ssam 	/*
82130519Ssam 	 * Check for and process errors on
82230519Ssam 	 * either the drive or the controller.
82330519Ssam 	 */
82430519Ssam 	uncache(&vd->vd_dcb.operrsta);
82530519Ssam 	status = vd->vd_dcb.operrsta;
82634396Skarels 	if (bp->b_flags & B_FORMAT) {
82734396Skarels 		dk->dk_operrsta = status;
82834396Skarels 		uncache(&vd->vd_dcb.err_code);
82934396Skarels 		dk->dk_ecode = vd->vd_dcb.err_code;
83034396Skarels 	}
83134396Skarels 	if (status & VDERR_HARD || timedout) {
83234528Skarels 		if (vd->vd_type == VDTYPE_SMDE)
83330601Skarels 			uncache(&vd->vd_dcb.err_code);
83430519Ssam 		if (status & DCBS_WPT) {
83530519Ssam 			/*
83630519Ssam 			 * Give up on write locked devices immediately.
83730519Ssam 			 */
83830573Skarels 			printf("dk%d: write locked\n", vi->ui_unit);
83930519Ssam 			bp->b_flags |= B_ERROR;
84034396Skarels 		} else if (status & VDERR_RETRY || timedout) {
84132211Skarels 			int endline = 1;
84232211Skarels 
84334396Skarels 			if (status & VDERR_CTLR || timedout) {
84434396Skarels 				vdharderr("controller err",
84534396Skarels 				    vd, bp, &vd->vd_dcb);
84634396Skarels 				printf("; resetting controller...");
84734396Skarels 				vdreset_ctlr(vm);
84834396Skarels 			} else if (status & VDERR_DRIVE) {
84934396Skarels 				vdharderr("drive err", vd, bp, &vd->vd_dcb);
85034396Skarels 				printf("; resetting drive...");
85130519Ssam 				if (!vdreset_drive(vi))
85230519Ssam 					vi->ui_alive = 0;
85332211Skarels 			} else
85432211Skarels 				endline = 0;
85530519Ssam 			/*
85630519Ssam 			 * Retry transfer once, unless reset failed.
85730519Ssam 			 */
85834396Skarels 			if (!vi->ui_alive || dp->b_errcnt++ >= 2 ||
85934396Skarels 			    bp->b_flags & B_FORMAT) {
86032211Skarels 				if (endline)
86132211Skarels 					printf("\n");
86230519Ssam 				goto hard;
86332211Skarels 			}
86432211Skarels 
86532211Skarels 			if (endline)
86632211Skarels 				printf(" retrying\n");
86730519Ssam 			vm->um_tab.b_active = 0;	/* force retry */
86830519Ssam 		} else  {
86930519Ssam 	hard:
87030519Ssam 			bp->b_flags |= B_ERROR;
87134396Skarels 			vdharderr("hard error", vd, bp, &vd->vd_dcb);
87230519Ssam 			printf("\n");
87330519Ssam 		}
87430519Ssam 	} else if (status & DCBS_SOFT)
87534528Skarels 		vdsofterr(bp, &vd->vd_dcb);
87634396Skarels 	vd->vd_wticks = 0;
87730519Ssam 	if (vm->um_tab.b_active) {
87830519Ssam 		vm->um_tab.b_active = 0;
87930519Ssam 		vm->um_tab.b_actf = dp->b_forw;
88030519Ssam 		dp->b_active = 0;
88130519Ssam 		dp->b_errcnt = 0;
88230519Ssam 		dp->b_actf = bp->av_forw;
88330519Ssam 		bp->b_resid = 0;
88430601Skarels 		vbadone(bp, &vd->vd_rbuf);
88530519Ssam 		biodone(bp);
88630370Skarels 		/*
88730519Ssam 		 * If this unit has more work to do,
88830519Ssam 		 * then start it up right away.
88930370Skarels 		 */
89030519Ssam 		if (dp->b_actf)
89130519Ssam 			vdustart(vi);
89234528Skarels 		else if (dk->dk_openpart == 0)
89330573Skarels 			wakeup((caddr_t)dk);
89424004Ssam 	}
89525675Ssam 	/*
89630519Ssam 	 * If there are devices ready to
89730519Ssam 	 * transfer, start the controller.
89825675Ssam 	 */
89935082Skarels 	if (vd->vd_flags & VD_WAIT) {
90035082Skarels 		vd->vd_flags &= ~VD_WAIT;
90135082Skarels 		wakeup((caddr_t)vd);
90235082Skarels 	} else if (vm->um_tab.b_actf || vm->um_tab.b_seekf)
90330519Ssam 		vdstart(vm);
90424004Ssam }
90524004Ssam 
90634396Skarels vdharderr(what, vd, bp, dcb)
90734396Skarels 	char *what;
90834396Skarels 	struct vdsoftc *vd;
90934396Skarels 	register struct buf *bp;
91034396Skarels 	register struct dcb *dcb;
91134396Skarels {
91234396Skarels 	int unit = vdunit(bp->b_dev), status = dcb->operrsta;
91334396Skarels 	register struct disklabel *lp = &dklabel[unit];
91434528Skarels 	int blkdone;
91534396Skarels 
91634396Skarels 	if (vd->vd_wticks < VDMAXTIME)
91734396Skarels 		status &= ~DONTCARE;
91834710Skarels 	blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) *
91934710Skarels 	    lp->d_nsectors + dcb->err_sec -
92034710Skarels 	    lp->d_partitions[vdpart(bp->b_dev)].p_offset) >>
92134710Skarels 	    dksoftc[unit].dk_bshift) - bp->b_blkno;
92234528Skarels 	diskerr(bp, "dk", what, LOG_PRINTF, blkdone, lp);
92334528Skarels 	printf(", status %b", status, VDERRBITS);
92434396Skarels 	if (vd->vd_type == VDTYPE_SMDE)
92534396Skarels 		printf(" ecode %x", dcb->err_code);
92634396Skarels }
92734396Skarels 
92834528Skarels vdsofterr(bp, dcb)
92925675Ssam 	register struct buf *bp;
93030519Ssam 	register struct dcb *dcb;
93125675Ssam {
93234562Skarels 	int unit = vdunit(bp->b_dev);
93334562Skarels 	struct disklabel *lp = &dklabel[unit];
93434528Skarels 	int status = dcb->operrsta;
93534528Skarels 	int blkdone;
93625675Ssam 
93734710Skarels 	blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) *
93834710Skarels 	    lp->d_nsectors + dcb->err_sec -
93934710Skarels 	    lp->d_partitions[vdpart(bp->b_dev)].p_offset) >>
94034710Skarels 	    dksoftc[unit].dk_bshift) - bp->b_blkno;
94134528Skarels 
94234528Skarels 	if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) {
94334528Skarels 		diskerr(bp, "dk", "soft error", LOG_WARNING, blkdone, lp);
94434528Skarels 		addlog(", status %b ecode %x\n", status, VDERRBITS,
94534396Skarels 		    dcb->err_code);
94634528Skarels 	} else {
94734528Skarels 		diskerr(bp, "dk", "soft ecc", LOG_WARNING, blkdone, lp);
94834528Skarels 		addlog("\n");
94934528Skarels 	}
95025675Ssam }
95125675Ssam 
95230519Ssam vdioctl(dev, cmd, data, flag)
95325675Ssam 	dev_t dev;
95430519Ssam 	int cmd;
95530519Ssam 	caddr_t data;
95630519Ssam 	int flag;
95724004Ssam {
95832576Skarels 	register int unit = vdunit(dev);
95930519Ssam 	register struct disklabel *lp = &dklabel[unit];
96034076Skarels 	register struct dksoftc *dk = &dksoftc[unit];
96134640Skarels 	int error = 0, vdformat();
96224004Ssam 
96330519Ssam 	switch (cmd) {
96430519Ssam 
96530519Ssam 	case DIOCGDINFO:
96630519Ssam 		*(struct disklabel *)data = *lp;
96730519Ssam 		break;
96830519Ssam 
96930573Skarels 	case DIOCGPART:
97030573Skarels 		((struct partinfo *)data)->disklab = lp;
97130573Skarels 		((struct partinfo *)data)->part =
97230573Skarels 		    &lp->d_partitions[vdpart(dev)];
97330519Ssam 		break;
97430519Ssam 
97530519Ssam 	case DIOCSDINFO:
97630519Ssam 		if ((flag & FWRITE) == 0)
97730519Ssam 			error = EBADF;
97830519Ssam 		else
97932576Skarels 			error = setdisklabel(lp, (struct disklabel *)data,
98034076Skarels 			    (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart);
98134396Skarels 		if (error == 0 && dk->dk_state == OPENRAW &&
98234396Skarels 		    vdreset_drive(vddinfo[unit]))
98334076Skarels 			dk->dk_state = OPEN;
98430519Ssam 		break;
98530519Ssam 
98634076Skarels 	case DIOCWLABEL:
98734076Skarels 		if ((flag & FWRITE) == 0)
98834076Skarels 			error = EBADF;
98934076Skarels 		else
99034076Skarels 			dk->dk_wlabel = *(int *)data;
99134076Skarels 		break;
99234076Skarels 
99332576Skarels 	case DIOCWDINFO:
99432576Skarels 		if ((flag & FWRITE) == 0)
99530519Ssam 			error = EBADF;
99632576Skarels 		else if ((error = setdisklabel(lp, (struct disklabel *)data,
99734076Skarels 		    (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) {
99834640Skarels 			int wlab;
99934640Skarels 
1000*35413Skarels 			if (error == 0 && dk->dk_state == OPENRAW &&
1001*35413Skarels 			    vdreset_drive(vddinfo[unit]))
1002*35413Skarels 				dk->dk_state = OPEN;
100334640Skarels 			/* simulate opening partition 0 so write succeeds */
100434640Skarels 			dk->dk_openpart |= (1 << 0);		/* XXX */
100534640Skarels 			wlab = dk->dk_wlabel;
100634640Skarels 			dk->dk_wlabel = 1;
100732576Skarels 			error = writedisklabel(dev, vdstrategy, lp);
100834640Skarels 			dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;
100934640Skarels 			dk->dk_wlabel = wlab;
101034076Skarels 		}
101130519Ssam 		break;
101230519Ssam 
101334396Skarels 	case DIOCWFORMAT:
101434396Skarels 	    {
101534396Skarels 		register struct format_op *fop;
101634396Skarels 		struct uio auio;
101734396Skarels 		struct iovec aiov;
101834396Skarels 
101934396Skarels 		if ((flag & FWRITE) == 0) {
102034396Skarels 			error = EBADF;
102134396Skarels 			break;
102234396Skarels 		}
102334396Skarels 		fop = (struct format_op *)data;
102434396Skarels 		aiov.iov_base = fop->df_buf;
102534396Skarels 		aiov.iov_len = fop->df_count;
102634396Skarels 		auio.uio_iov = &aiov;
102734396Skarels 		auio.uio_iovcnt = 1;
102834396Skarels 		auio.uio_resid = fop->df_count;
102934396Skarels 		auio.uio_segflg = UIO_USERSPACE;
103034396Skarels 		auio.uio_offset = fop->df_startblk * lp->d_secsize;
103134396Skarels 		dk->dk_operrsta = fop->dk_operrsta;
103234396Skarels 		dk->dk_ecode = fop->dk_ecode;
103334396Skarels 		/*
103434396Skarels 		 * Don't return errors, as the format op won't get copied
103534396Skarels 		 * out if we return nonzero.  Callers must check the returned
103634396Skarels 		 * count.
103734396Skarels 		 */
103834396Skarels 		(void) physio(vdformat, (struct buf *)NULL, dev,
103934396Skarels 		    (cmd == DIOCWFORMAT ? B_WRITE : B_READ), minphys, &auio);
104034396Skarels 		fop->df_count -= auio.uio_resid;
104134396Skarels 		fop->dk_operrsta = dk->dk_operrsta;
104234396Skarels 		fop->dk_ecode = dk->dk_ecode;
104334396Skarels 		break;
104434396Skarels 	    }
104534396Skarels 
104630519Ssam 	default:
104730519Ssam 		error = ENOTTY;
104830519Ssam 		break;
104924004Ssam 	}
105032606Skarels 	return (error);
105124004Ssam }
105224004Ssam 
105334396Skarels vdformat(bp)
105434396Skarels 	struct buf *bp;
105534396Skarels {
105634396Skarels 	bp->b_flags |= B_FORMAT;
105734396Skarels 	vdstrategy(bp);
105834396Skarels }
105934396Skarels 
106025675Ssam /*
106130519Ssam  * Watch for lost interrupts.
106225675Ssam  */
106330519Ssam vdwatch()
106430519Ssam {
106530519Ssam 	register struct vdsoftc *vd;
106630519Ssam 	register struct vba_ctlr *vm;
106734528Skarels 	register int ctlr;
106834396Skarels 	int s;
106930519Ssam 
107030519Ssam 	timeout(vdwatch, (caddr_t)0, hz);
107130519Ssam 	for (ctlr = 0; ctlr < NVD; ctlr++) {
107230519Ssam 		vm = vdminfo[ctlr];
107330519Ssam 		if (vm == 0 || vm->um_alive == 0)
107430519Ssam 			continue;
107530519Ssam 		vd = &vdsoftc[ctlr];
107634396Skarels 		s = spl7();
107734396Skarels 		if (vm->um_tab.b_active && vd->vd_wticks++ >= VDMAXTIME) {
107830519Ssam 			printf("vd%d: lost interrupt\n", ctlr);
107934396Skarels #ifdef maybe
108034396Skarels 			VDABORT((struct vddevice *)vm->um_addr, vd->vd_type);
108134396Skarels #endif
108234396Skarels 			vdintr(ctlr);
108330519Ssam 		}
108434396Skarels 		splx(s);
108530519Ssam 	}
108630519Ssam }
108730519Ssam 
108830519Ssam #define	DBSIZE	64	/* controller limit with 1K sectors */
108930519Ssam /*
109030519Ssam  * Crash dump.
109130519Ssam  */
109230519Ssam vddump(dev)
109330519Ssam 	dev_t dev;
109424004Ssam {
109530519Ssam 	register struct vba_device *vi;
109630519Ssam 	register struct vba_ctlr *vm;
109730519Ssam 	register struct disklabel *lp;
109830519Ssam 	register struct vdsoftc *vd;
109930519Ssam 	struct dksoftc *dk;
110030519Ssam 	int part, unit, num;
110130601Skarels 	u_long start;
110224004Ssam 
110330519Ssam 	start = 0;
110430519Ssam 	unit = vdunit(dev);
110530519Ssam 	if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
110630519Ssam 		return (ENXIO);
110730519Ssam 	dk = &dksoftc[unit];
110834076Skarels 	if (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
110934076Skarels 	    vdinit(vdminor(unit, 0), 0) != 0)
111030519Ssam 		return (ENXIO);
111130519Ssam 	lp = &dklabel[unit];
111230519Ssam 	part = vdpart(dev);
111330519Ssam 	if (part >= lp->d_npartitions)
111430519Ssam 		return (ENXIO);
111532211Skarels 	vm = vi->ui_mi;
111630519Ssam 	vdreset_ctlr(vm);
111730519Ssam 	if (dumplo < 0)
111830519Ssam 		return (EINVAL);
111930519Ssam 	/*
112030756Skarels 	 * Maxfree is in pages, dumplo is in DEV_BSIZE units.
112130519Ssam 	 */
112230519Ssam 	num = maxfree * (NBPG / lp->d_secsize);
112330756Skarels 	dumplo *= DEV_BSIZE / lp->d_secsize;
112430519Ssam 	if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size)
112530519Ssam 		num = lp->d_partitions[vdpart(dev)].p_size - dumplo;
112630519Ssam 	vd = &vdsoftc[vm->um_ctlr];
112730519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
112830519Ssam 	vd->vd_dcb.opcode = VDOP_WD;
112932211Skarels 	vd->vd_dcb.devselect = dk->dk_dcb.devselect;
113030756Skarels 	vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
113130519Ssam 	while (num > 0) {
113230519Ssam 		int nsec, cn, sn, tn;
113330519Ssam 
113430519Ssam 		nsec = MIN(num, DBSIZE);
113530601Skarels 		sn = dumplo + start / lp->d_secsize;
113630519Ssam 		cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) /
113730519Ssam 		    lp->d_secpercyl;
113830519Ssam 		sn %= lp->d_secpercyl;
113930519Ssam 		tn = sn / lp->d_nsectors;
114030519Ssam 		sn %= lp->d_nsectors;
114130519Ssam 		vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
114230519Ssam 		vd->vd_dcb.trail.rwtrail.memadr = start;
114330519Ssam 		vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1;
114430519Ssam 		vd->vd_dcb.trail.rwtrail.disk.cylinder = cn;
114530519Ssam 		vd->vd_dcb.trail.rwtrail.disk.track = tn;
114630519Ssam 		vd->vd_dcb.trail.rwtrail.disk.sector = sn;
114730519Ssam 		vd->vd_dcb.operrsta = 0;
114830519Ssam 		VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
114930519Ssam 		if (!vdpoll(vm, 5)) {
115030519Ssam 			printf(" during dump\n");
115130519Ssam 			return (EIO);
115230519Ssam 		}
115330519Ssam 		if (vd->vd_dcb.operrsta & VDERR_HARD) {
115430519Ssam 			printf("dk%d: hard error, status=%b\n", unit,
115530519Ssam 			    vd->vd_dcb.operrsta, VDERRBITS);
115630519Ssam 			return (EIO);
115730519Ssam 		}
115830519Ssam 		start += nsec * lp->d_secsize;
115930519Ssam 		num -= nsec;
116025675Ssam 	}
116130519Ssam 	return (0);
116224004Ssam }
116324004Ssam 
116424004Ssam vdsize(dev)
116525675Ssam 	dev_t dev;
116624004Ssam {
116730519Ssam 	register int unit = vdunit(dev);
116830519Ssam 	register struct dksoftc *dk;
116930519Ssam 	struct vba_device *vi;
117030519Ssam 	struct disklabel *lp;
117124004Ssam 
117230519Ssam 	if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 ||
117330519Ssam 	    (dk = &dksoftc[unit])->dk_state != OPEN)
117425675Ssam 		return (-1);
117530519Ssam 	lp = &dklabel[unit];
117630756Skarels #ifdef SECSIZE
117730573Skarels 	return ((int)lp->d_partitions[vdpart(dev)].p_size);
117830756Skarels #else SECSIZE
117930756Skarels 	return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift);
118030756Skarels #endif SECSIZE
118124004Ssam }
118224004Ssam 
118325675Ssam /*
118425675Ssam  * Perform a controller reset.
118525675Ssam  */
118630519Ssam vdreset_ctlr(vm)
118730519Ssam 	register struct vba_ctlr *vm;
118824004Ssam {
118930519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
119030519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
119130519Ssam 	register int unit;
119230519Ssam 	struct vba_device *vi;
119325675Ssam 
119430519Ssam 	VDRESET(vdaddr, vd->vd_type);
119530519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
119630519Ssam 		vdaddr->vdcsr = 0;
119730519Ssam 		vdaddr->vdtcf_mdcb = AM_ENPDA;
119830519Ssam 		vdaddr->vdtcf_dcb = AM_ENPDA;
119930519Ssam 		vdaddr->vdtcf_trail = AM_ENPDA;
120030519Ssam 		vdaddr->vdtcf_data = AM_ENPDA;
120130519Ssam 		vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
120225675Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
120325675Ssam 	}
1204*35413Skarels 	if (!vdcmd(vm, VDOP_INIT, 10, 0) || !vdcmd(vm, VDOP_DIAG, 10, 0)) {
120530519Ssam 		printf("%s cmd failed\n",
120630519Ssam 		    vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
120730370Skarels 		return;
120825675Ssam 	}
120930519Ssam 	for (unit = 0; unit < NDK; unit++)
121030519Ssam 		if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive)
121130519Ssam 			(void) vdreset_drive(vi);
121230519Ssam }
121330519Ssam 
121430519Ssam vdreset_drive(vi)
121530519Ssam 	register struct vba_device *vi;
121630519Ssam {
121730519Ssam 	register struct disklabel *lp = &dklabel[vi->ui_unit];
121830519Ssam 	struct vba_ctlr *vm = vdminfo[vi->ui_ctlr];
121930519Ssam 	struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
122032211Skarels 	register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
122132211Skarels 	register struct dksoftc *dk = &dksoftc[vi->ui_unit];
122230519Ssam 
122330519Ssam top:
122430519Ssam 	vd->vd_dcb.opcode = VDOP_CONFIG;		/* command */
122530519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
122630519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
122730519Ssam 	vd->vd_dcb.operrsta = 0;
122832211Skarels 	vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags;
122930519Ssam 	vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders;
123030519Ssam 	vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks;
123130519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
123230756Skarels 		vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long);
123330519Ssam 		vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors;
123430601Skarels 		vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack;
123532211Skarels 		vd->vd_dcb.trail.rstrail.recovery = VDRF_NORMAL;
123630519Ssam 	} else
123730519Ssam 		vd->vd_dcb.trailcnt = 2;		/* XXX */
123830519Ssam 	vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
123930519Ssam 	vd->vd_mdcb.mdcb_status = 0;
124030519Ssam 	VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type);
124130519Ssam 	if (!vdpoll(vm, 5)) {
124230519Ssam 		printf(" during config\n");
124330519Ssam 		return (0);
124425675Ssam 	}
1245*35413Skarels /*
1246*35413Skarels uncache(&vd->vd_dcb.err_code);
1247*35413Skarels printf("vdreset_drive %d, error %b, ecode %x, status %x => ",
1248*35413Skarels    vi->ui_unit, vd->vd_dcb.operrsta, VDERRBITS, vd->vd_dcb.err_code,
1249*35413Skarels    vdaddr->vdstatus[vi->ui_slave]);
1250*35413Skarels uncache(&vdaddr->vdstatus[vi->ui_slave]);
1251*35413Skarels printf("%x =>", vdaddr->vdstatus[vi->ui_slave]);
1252*35413Skarels { int status = vd->vd_dcb.operrsta;
1253*35413Skarels vdcmd(vm, VDOP_STATUS, 5, vi->ui_slave);
1254*35413Skarels vd->vd_dcb.operrsta = status;
1255*35413Skarels }
1256*35413Skarels uncache(&vdaddr->vdstatus[vi->ui_slave]);
1257*35413Skarels printf("%x\n", vdaddr->vdstatus[vi->ui_slave]);
1258*35413Skarels */
125930519Ssam 	if (vd->vd_dcb.operrsta & VDERR_HARD) {
126032211Skarels 		if (vd->vd_type == VDTYPE_SMDE) {
126132211Skarels 			if (lp->d_devflags == 0) {
126232211Skarels 				lp->d_devflags = VD_ESDI;
126332211Skarels 				goto top;
126432211Skarels 			}
126532211Skarels #ifdef notdef
126632211Skarels 			/* this doesn't work, STA_US isn't set(?) */
126732211Skarels 			if ((vdaddr->vdstatus[vi->ui_slave] & STA_US) == 0)
126832211Skarels 				return (0);
126932211Skarels #endif
127032211Skarels 		}
127130519Ssam 		if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0)
127232211Skarels 			printf("dk%d: config error %b ecode %x\n", vi->ui_unit,
127334396Skarels 			   vd->vd_dcb.operrsta, VDERRBITS,
127434396Skarels 			   (u_char) vd->vd_dcb.err_code);
127532211Skarels 		else if ((vd->vd_flags & VD_STARTED) == 0) {
127630519Ssam 			int started;
127730519Ssam 
127832211Skarels 			printf(" starting drives, wait ... ");
127930519Ssam 			vd->vd_flags |= VD_STARTED;
128030519Ssam 			started = (vdcmd(vm, VDOP_START, 10) == 1);
128130519Ssam 			DELAY(62000000);
1282*35413Skarels 			printf("done\n");
128332211Skarels 			lp->d_devflags = 0;
128430519Ssam 			if (started)
128530519Ssam 				goto top;
128630519Ssam 		}
128730519Ssam 		return (0);
128830519Ssam 	}
128932211Skarels 	dk->dk_dcb.devselect |= lp->d_devflags;
129030519Ssam 	return (1);
129125675Ssam }
129224004Ssam 
129325675Ssam /*
129430519Ssam  * Perform a command w/o trailer.
129525675Ssam  */
1296*35413Skarels vdcmd(vm, cmd, t, slave)
129730519Ssam 	register struct vba_ctlr *vm;
129825675Ssam {
129930519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
130025675Ssam 
130130519Ssam 	vd->vd_dcb.opcode = cmd;		/* command */
130230519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
130330519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
130430519Ssam 	vd->vd_dcb.operrsta = 0;
1305*35413Skarels 	vd->vd_dcb.devselect = slave;
130630519Ssam 	vd->vd_dcb.trailcnt = 0;
130730519Ssam 	vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
130830519Ssam 	vd->vd_mdcb.mdcb_status = 0;
130930519Ssam 	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
131030519Ssam 	if (!vdpoll(vm, t)) {
131130519Ssam 		printf(" during init\n");
131230370Skarels 		return (0);
131330370Skarels 	}
131430519Ssam 	return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0);
131525675Ssam }
131625675Ssam 
131725925Ssam /*
131830519Ssam  * Poll controller until operation
131930519Ssam  * completes or timeout expires.
132025925Ssam  */
132130519Ssam vdpoll(vm, t)
132230519Ssam 	register struct vba_ctlr *vm;
132325925Ssam 	register int t;
132425925Ssam {
132530519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
132630519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
132725925Ssam 
132825925Ssam 	t *= 1000;
132930370Skarels 	for (;;) {
133030519Ssam 		uncache(&vd->vd_dcb.operrsta);
133130519Ssam 		if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT))
133230370Skarels 			break;
133325925Ssam 		if (--t <= 0) {
133430519Ssam 			printf("vd%d: controller timeout", vm->um_ctlr);
133530519Ssam 			VDABORT(vdaddr, vd->vd_type);
133625925Ssam 			return (0);
133725925Ssam 		}
133830370Skarels 		DELAY(1000);
133925925Ssam 	}
134030519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
134130519Ssam 		do {
134225925Ssam 			DELAY(50);
134330519Ssam 			uncache(&vdaddr->vdcsr);
134430519Ssam 		} while (vdaddr->vdcsr & CS_GO);
134532211Skarels 	 	DELAY(300);
134632211Skarels 		uncache(&vd->vd_dcb.err_code);
134725925Ssam 	}
134825925Ssam 	DELAY(200);
134930519Ssam 	uncache(&vd->vd_dcb.operrsta);
135025925Ssam 	return (1);
135125925Ssam }
135225925Ssam 
135330519Ssam #ifdef COMPAT_42
135430519Ssam struct	vdst {
135530519Ssam 	int	nsec;		/* sectors/track */
135630519Ssam 	int	ntrack;		/* tracks/cylinder */
135730519Ssam 	int	ncyl;		/* cylinders */
135832211Skarels 	int	secsize;	/* sector size */
135930519Ssam 	char	*name;		/* type name */
136030519Ssam 	struct {
136130519Ssam 		int	off;	/* partition offset in sectors */
136230519Ssam 		int	size;	/* partition size in sectors */
136330573Skarels 	} parts[8];
136430519Ssam } vdst[] = {
136532211Skarels 	{ 66, 23, 850, 512, "NEC 800",
136632211Skarels 		{0,	 1290300},	/* a cyl   0 - 849 */
136732211Skarels 	},
136834737Sbostic 	{ 64, 20, 842, 512, "2361a",
136934737Sbostic 		{0,	 61440},	/* a cyl   0 - 47 */
137034737Sbostic 		{61440,	 67840},	/* b cyl  48 - 100 */
137134737Sbostic 		{129280, 942080}, 	/* c cyl 101 - 836 */
137234737Sbostic 		{0,      1071360}, 	/* d cyl   0 - 836 */
137334737Sbostic 		{449280, 311040},	/* e cyl 351 - 593 */
137434737Sbostic 		{760320, 311040}, 	/* f cyl 594 - 836 */
137534737Sbostic 		{449280, 622080},	/* g cyl 351 - 836 */
137634737Sbostic 		{129280, 320000}	/* h cyl 101 - 350 */
137734737Sbostic 	},
137832211Skarels 	{ 48, 24, 711, 512, "xsd",
137931039Skarels 		{0,	 61056},	/* a cyl   0 - 52 */
138031039Skarels 		{61056,	 61056},	/* b cyl  53 - 105 */
138131039Skarels 		{122112, 691200}, 	/* c cyl 106 - 705 */
138231039Skarels 		{237312, 576000}, 	/* d cyl 206 - 705 */
138331039Skarels 		{352512, 460800},	/* e cyl 306 - 705 */
138431039Skarels 		{467712, 345600}, 	/* f cyl 406 - 705 */
138531039Skarels 		{582912, 230400},	/* g cyl 506 - 705 */
138631039Skarels 		{698112, 115200}	/* h cyl 606 - 705 */
138730573Skarels 	},
138832211Skarels 	{ 44, 20, 842, 512, "eagle",
138930601Skarels 		{0,	 52800},	/* egl0a cyl   0 - 59 */
139030601Skarels 		{52800,	 66000},	/* egl0b cyl  60 - 134 */
139130601Skarels 		{118800, 617760}, 	/* egl0c cyl 135 - 836 */
139230756Skarels 		{736560, 4400}, 	/* egl0d cyl 837 - 841 */
139331039Skarels 		{0, 	 736560},	/* egl0e cyl   0 - 836 */
139431039Skarels 		{0, 	 740960}, 	/* egl0f cyl   0 - 841 */
139530601Skarels 		{118800, 310640},	/* egl0g cyl 135 - 487 */
139630601Skarels 		{429440, 307120}	/* egl0h cyl 488 - 836 */
139730573Skarels 	},
139832211Skarels 	{ 64, 10, 823, 512, "fuj",
139931039Skarels 		{0,	 38400},	/* fuj0a cyl   0 - 59 */
140031039Skarels 		{38400,	 48000},	/* fuj0b cyl  60 - 134 */
140131039Skarels 		{86400,	 437120}, 	/* fuj0c cyl 135 - 817 */
140231039Skarels 		{159360, 364160}, 	/* fuj0d cyl 249 - 817 */
140331039Skarels 		{232320, 291200},	/* fuj0e cyl 363 - 817 */
140431039Skarels 		{305280, 218240}, 	/* fuj0f cyl 477 - 817 */
140531039Skarels 		{378240, 145280},	/* fuj0g cyl 591 - 817 */
140631039Skarels 		{451200, 72320}		/* fug0h cyl 705 - 817 */
140730573Skarels 	},
140832211Skarels 	{ 32, 24, 711, 512, "xfd",
140930756Skarels 		{ 0,	 40704 },	/* a cyl   0 - 52 */
141030756Skarels 		{ 40704, 40704 },	/* b cyl  53 - 105 */
141130756Skarels 		{ 81408, 460800 },	/* c cyl 106 - 705 */
141230756Skarels 		{ 0,	 81408 },	/* d cyl 709 - 710 (a & b) */
141330756Skarels 		{ 0,	 542208 },	/* e cyl   0 - 705 */
141430756Skarels 		{ 40704, 501504 },	/* f cyl  53 - 705 (b & c) */
141530756Skarels 		{ 81408, 230400 },	/* g cyl 106 - 405 (1/2 of c) */
141630756Skarels 		{ 311808,230400 }	/* h cyl 406 - 705 (1/2 of c) */
141730573Skarels 	},
141832211Skarels 	{ 32, 19, 823, 512, "smd",
141931039Skarels 		{0,	 40128},	/* a cyl   0-65 */
142031039Skarels 		{40128,  27360},	/* b cyl  66-110 */
142131039Skarels 		{67488,  429856},	/* c cyl 111-817 */
142231039Skarels 		{139232, 358112},	/* d cyl 229 - 817 */
142331039Skarels 		{210976, 286368},	/* e cyl 347 - 817 */
142431039Skarels 		{282720, 214624},	/* f cyl 465 - 817 */
142531039Skarels 		{354464, 142880},	/* g cyl 583 - 817 */
142631039Skarels 		{426208, 71136}		/* h cyl 701 - 817 */
142730573Skarels 	},
142832211Skarels 	{ 18, 15, 1224, 1024, "mxd",
142932211Skarels 		{0,	 21600},	/* a cyl   0-79 */
143032211Skarels 		{21600,  22410},	/* b cyl  80-162 */
143132211Skarels 		{44010,  285120},	/* c cyl 163-1217 */
143232211Skarels #ifdef notyet
143332211Skarels 		{x, 237600},	/* d cyl y - 1217 */
143432211Skarels 		{x, 190080},	/* e cyl y - 1217 */
143532211Skarels 		{x, 142560},	/* f cyl y - 1217 */
143632211Skarels 		{x, 95040},	/* g cyl y - 1217 */
143732211Skarels 		{x, 47520}		/* h cyl 701 - 817 */
143832211Skarels #endif
143932211Skarels 	},
144032211Skarels 	{ 32, 10, 823, 512, "fsd",
144130756Skarels 		{0,	 19200},	/* a cyl   0 -  59 */
144230756Skarels 		{19200,	 24000},	/* b cyl  60 - 134 */
144330756Skarels 		{43200,	 218560},	/* c cyl 135 - 817 */
144430573Skarels 	}
144530519Ssam };
144630519Ssam #define	NVDST	(sizeof (vdst) / sizeof (vdst[0]))
144730519Ssam 
144825675Ssam /*
144930519Ssam  * Construct a label for an unlabeled pack.  We
145030519Ssam  * deduce the drive type by reading from the last
145130519Ssam  * track on successively smaller drives until we
145230519Ssam  * don't get an error.
145325675Ssam  */
145430519Ssam vdmaptype(vi, lp)
145530519Ssam 	register struct vba_device *vi;
145630519Ssam 	register struct disklabel *lp;
145725675Ssam {
145830519Ssam 	register struct vdsoftc *vd;
145930519Ssam 	register struct vdst *p;
146032211Skarels 	struct vba_ctlr *vm = vi->ui_mi;
146130519Ssam 	int i;
146225675Ssam 
146330519Ssam 	vd = &vdsoftc[vi->ui_ctlr];
146430519Ssam 	for (p = vdst; p < &vdst[NVDST]; p++) {
146530519Ssam 		if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32)
146630519Ssam 			continue;
146730519Ssam 		lp->d_nsectors = p->nsec;
146830519Ssam 		lp->d_ntracks = p->ntrack;
146930519Ssam 		lp->d_ncylinders = p->ncyl;
147032211Skarels 		lp->d_secsize = p->secsize;
1471*35413Skarels 		DELAY(100000);
147230519Ssam 		if (!vdreset_drive(vi))
147330519Ssam 			return (0);
1474*35413Skarels 		DELAY(100000);
147530519Ssam 		vd->vd_dcb.opcode = VDOP_RD;
147630519Ssam 		vd->vd_dcb.intflg = DCBINT_NONE;
147730519Ssam 		vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
147832211Skarels 		vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect;
147930756Skarels 		vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
148030601Skarels 		vd->vd_dcb.trail.rwtrail.memadr =
148130601Skarels 		    vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf);
148232211Skarels 		vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short);
148330519Ssam 		vd->vd_dcb.operrsta = 0;
148430519Ssam 		vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2;
148530519Ssam 		vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1;
148630519Ssam 		vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1;
148730519Ssam 		vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
148830519Ssam 		vd->vd_mdcb.mdcb_status = 0;
148930519Ssam 		VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
149030519Ssam 		if (!vdpoll(vm, 60))
149130519Ssam 			printf(" during probe\n");
149230519Ssam 		if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0)
149330519Ssam 			break;
149424004Ssam 	}
149532211Skarels 	if (p >= &vdst[NVDST])
149630519Ssam 		return (0);
149732211Skarels 
149830573Skarels 	for (i = 0; i < 8; i++) {
149930519Ssam 		lp->d_partitions[i].p_offset = p->parts[i].off;
150030519Ssam 		lp->d_partitions[i].p_size = p->parts[i].size;
150130519Ssam 	}
150230573Skarels 	lp->d_npartitions = 8;
150330519Ssam 	lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
150430519Ssam 	bcopy(p->name, lp->d_typename, 4);
150530519Ssam 	return (1);
150624004Ssam }
150730519Ssam #endif COMPAT_42
150824004Ssam #endif
1509