xref: /csrg-svn/sys/tahoe/vba/vd.c (revision 34737)
134528Skarels /*
234528Skarels  * Copyright (c) 1988 Regents of the University of California.
334528Skarels  * All rights reserved.
434528Skarels  *
534528Skarels  * Redistribution and use in source and binary forms are permitted
634528Skarels  * provided that this notice is preserved and that due credit is given
734528Skarels  * to the University of California at Berkeley. The name of the University
834528Skarels  * may not be used to endorse or promote products derived from this
934528Skarels  * software without specific prior written permission. This software
1034528Skarels  * is provided ``as is'' without express or implied warranty.
1134528Skarels  *
12*34737Sbostic  *	@(#)vd.c	7.4 (Berkeley) 06/14/88
1334528Skarels  */
1424004Ssam 
1529564Ssam #include "dk.h"
1624004Ssam #if NVD > 0
1724004Ssam /*
1830519Ssam  * Versabus VDDC/SMDE driver.
1925675Ssam  */
2025675Ssam #include "param.h"
2125675Ssam #include "buf.h"
2225675Ssam #include "cmap.h"
2325675Ssam #include "conf.h"
2425675Ssam #include "dir.h"
2529564Ssam #include "dkstat.h"
2630519Ssam #include "disklabel.h"
2725675Ssam #include "map.h"
2830519Ssam #include "file.h"
2925675Ssam #include "systm.h"
3025675Ssam #include "user.h"
3125675Ssam #include "vmmac.h"
3225675Ssam #include "proc.h"
3325675Ssam #include "uio.h"
3430370Skarels #include "syslog.h"
3530370Skarels #include "kernel.h"
3630519Ssam #include "ioctl.h"
3730756Skarels #include "stat.h"
3824004Ssam 
3929951Skarels #include "../tahoe/cpu.h"
4029951Skarels #include "../tahoe/mtpr.h"
4129951Skarels #include "../tahoe/pte.h"
4229951Skarels 
4325675Ssam #include "../tahoevba/vbavar.h"
4425928Ssam #include "../tahoevba/vdreg.h"
4524004Ssam 
4632211Skarels #ifndef	COMPAT_42
4730519Ssam #define	COMPAT_42
4832211Skarels #endif
4934396Skarels #define	B_FORMAT	B_XXX		/* XXX */
5030519Ssam 
5130519Ssam #define vdunit(dev)	(minor(dev) >> 3)
5230519Ssam #define vdpart(dev)	(minor(dev) & 0x07)
5330519Ssam #define	vdminor(unit,part)	(((unit) << 3) | (part))
5424004Ssam 
5524004Ssam struct	vba_ctlr *vdminfo[NVD];
5629564Ssam struct  vba_device *vddinfo[NDK];
5730756Skarels int	vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy();
5834528Skarels long	vdstd[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 };
5925675Ssam struct	vba_driver vddriver =
6034528Skarels   { vdprobe, vdslave, vdattach, vddgo, vdstd, "dk", vddinfo, "vd", vdminfo };
6124004Ssam 
6224004Ssam /*
6330519Ssam  * Per-controller state.
6430519Ssam  */
6530519Ssam struct vdsoftc {
6630519Ssam 	u_short	vd_flags;
6730519Ssam #define	VD_INIT		0x1	/* controller initialized */
6830519Ssam #define	VD_STARTED	0x2	/* start command issued */
6930519Ssam #define	VD_DOSEEKS	0x4	/* should overlap seeks */
7030756Skarels #define	VD_SCATGATH	0x8	/* can do scatter-gather commands (correctly) */
7130519Ssam 	u_short	vd_type;	/* controller type */
7230519Ssam 	u_short	vd_wticks;	/* timeout */
7330519Ssam 	struct	mdcb vd_mdcb;	/* master command block */
7430519Ssam 	u_long	vd_mdcbphys;	/* physical address of vd_mdcb */
7530519Ssam 	struct	dcb vd_dcb;	/* i/o command block */
7630519Ssam 	u_long	vd_dcbphys;	/* physical address of vd_dcb */
7730601Skarels 	struct	vb_buf vd_rbuf;	/* vba resources */
7830519Ssam } vdsoftc[NVD];
7930519Ssam 
8034396Skarels #define	VDMAXTIME	20	/* max time for operation, sec. */
8134396Skarels 
8230519Ssam /*
8325675Ssam  * Per-drive state.
8425675Ssam  */
8530519Ssam struct	dksoftc {
8634076Skarels 	int	dk_state;	/* open fsm */
8730756Skarels #ifndef SECSIZE
8830756Skarels 	u_short	dk_bshift;	/* shift for * (DEV_BSIZE / sectorsize) XXX */
8930756Skarels #endif SECSIZE
9034076Skarels 	int	dk_wlabel;	/* label sector is currently writable */
9132576Skarels 	u_long	dk_copenpart;	/* character units open on this drive */
9232576Skarels 	u_long	dk_bopenpart;	/* block units open on this drive */
9332576Skarels 	u_long	dk_openpart;	/* all units open on this drive */
9430519Ssam 	u_int	dk_curcyl;	/* last selected cylinder */
9530756Skarels 	struct	skdcb dk_dcb;	/* seek command block */
9630519Ssam 	u_long	dk_dcbphys;	/* physical address of dk_dcb */
9734396Skarels 	int	df_reg[3];	/* for formatting, in-out parameters */
9830519Ssam } dksoftc[NDK];
9924004Ssam 
10024004Ssam /*
10130519Ssam  * Drive states.  Used during steps of open/initialization.
10230519Ssam  * States < OPEN (> 0) are transient, during an open operation.
10334076Skarels  * OPENRAW is used for unlabeled disks, to allow format operations.
10425675Ssam  */
10530519Ssam #define	CLOSED		0		/* disk is closed */
10630519Ssam #define	WANTOPEN	1		/* open requested, not started */
10730519Ssam #define	WANTOPENRAW	2		/* open requested, no label */
10830519Ssam #define	RDLABEL		3		/* reading pack label */
10930519Ssam #define	OPEN		4		/* intialized and ready */
11030519Ssam #define	OPENRAW		5		/* open, no label */
11124004Ssam 
11230519Ssam struct	buf dkutab[NDK];	/* i/o queue headers */
11330519Ssam struct	disklabel dklabel[NDK];	/* pack labels */
11424004Ssam 
11530519Ssam #define b_cylin	b_resid
11630574Skarels #define	b_track	b_error		/* used for seek commands */
11730574Skarels #define	b_seekf	b_forw		/* second queue on um_tab */
11830574Skarels #define	b_seekl	b_back		/* second queue on um_tab */
11930519Ssam 
12030519Ssam int	vdwstart, vdwatch();
12130519Ssam 
12224004Ssam /*
12325675Ssam  * See if the controller is really there; if so, initialize it.
12425675Ssam  */
12525857Ssam vdprobe(reg, vm)
12625857Ssam 	caddr_t reg;
12725857Ssam 	struct vba_ctlr *vm;
12825675Ssam {
12925857Ssam 	register br, cvec;		/* must be r12, r11 */
13030519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)reg;
13130519Ssam 	struct vdsoftc *vd;
13230573Skarels 	int s;
13325857Ssam 
13430370Skarels #ifdef lint
13530370Skarels 	br = 0; cvec = br; br = cvec;
13630370Skarels 	vdintr(0);
13730370Skarels #endif
13825857Ssam 	if (badaddr((caddr_t)reg, 2))
13925675Ssam 		return (0);
14030519Ssam 	vd = &vdsoftc[vm->um_ctlr];
14130519Ssam 	vdaddr->vdreset = 0xffffffff;
14225675Ssam 	DELAY(1000000);
14330519Ssam 	if (vdaddr->vdreset != (unsigned)0xffffffff) {
14430519Ssam 		vd->vd_type = VDTYPE_VDDC;
14530519Ssam 		vd->vd_flags &= ~VD_DOSEEKS;
14625675Ssam 		DELAY(1000000);
14725675Ssam 	} else {
14830519Ssam 		vd->vd_type = VDTYPE_SMDE;
14930519Ssam 		vd->vd_flags |= VD_DOSEEKS;
15030519Ssam 		vdaddr->vdrstclr = 0;
15125675Ssam 		DELAY(3000000);
15230519Ssam 		vdaddr->vdcsr = 0;
15330519Ssam 		vdaddr->vdtcf_mdcb = AM_ENPDA;
15430519Ssam 		vdaddr->vdtcf_dcb = AM_ENPDA;
15530519Ssam 		vdaddr->vdtcf_trail = AM_ENPDA;
15630519Ssam 		vdaddr->vdtcf_data = AM_ENPDA;
15730519Ssam 		vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS |
15829921Skarels 		    XMD_32BIT | BSZ_16WRD |
15925925Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
16025675Ssam 	}
16130519Ssam 	vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb);
16230519Ssam 	vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb);
16330519Ssam 	vm->um_addr = reg;		/* XXX */
16430573Skarels 	s = spl7();
16530519Ssam 	if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) {
16630519Ssam 		printf("vd%d: %s cmd failed\n", vm->um_ctlr,
16730519Ssam 		    vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
16830573Skarels 		splx(s);
16930519Ssam 		return (0);
17030519Ssam 	}
17130756Skarels 	if (vd->vd_type == VDTYPE_SMDE) {
17230756Skarels 		vd->vd_dcb.trail.idtrail.date = 0;
17330756Skarels 		if (vdcmd(vm, VDOP_IDENT, 10)) {
17430756Skarels 			uncache(&vd->vd_dcb.trail.idtrail.date);
17530756Skarels 			if (vd->vd_dcb.trail.idtrail.date != 0)
17630756Skarels 				vd->vd_flags |= VD_SCATGATH;
17730756Skarels 		}
17830756Skarels 	}
17930573Skarels 	splx(s);
18025925Ssam 	/*
18125950Ssam 	 * Allocate page tables and i/o buffer.
18225925Ssam 	 */
18332211Skarels 	if (vbainit(&vd->vd_rbuf, MAXPHYS,
18432211Skarels 	    vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) {
18532211Skarels 		printf("vd%d: vbainit failed\n", vm->um_ctlr);
18632211Skarels 		return (0);
18732211Skarels 	}
18825857Ssam 	br = 0x17, cvec = 0xe0 + vm->um_ctlr;	/* XXX */
18930519Ssam 	return (sizeof (struct vddevice));
19025675Ssam }
19124004Ssam 
19224004Ssam /*
19330519Ssam  * See if a drive is really there.
19430519Ssam  *
19530519Ssam  * Can't read pack label here as various data structures
19630519Ssam  * aren't setup for doing a read in a straightforward
19730519Ssam  * manner.  Instead just probe for the drive and leave
19830519Ssam  * the pack label stuff to the attach routine.
19925675Ssam  */
20034076Skarels /* ARGSUSED */
20134076Skarels vdslave(vi, vdaddr)
20225675Ssam 	register struct vba_device *vi;
20330519Ssam 	struct vddevice *vdaddr;
20425675Ssam {
20530519Ssam 	register struct disklabel *lp = &dklabel[vi->ui_unit];
20632211Skarels 	register struct dksoftc *dk = &dksoftc[vi->ui_unit];
20730519Ssam 	struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
20824004Ssam 
20930519Ssam 	if ((vd->vd_flags&VD_INIT) == 0) {
21030756Skarels 		printf("vd%d: %s controller%s\n", vi->ui_ctlr,
21130756Skarels 		    vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE",
21230756Skarels 		    (vd->vd_flags & VD_SCATGATH) ? " with scatter-gather" : "");
21330519Ssam 		vd->vd_flags |= VD_INIT;
21425675Ssam 	}
21530519Ssam 
21625675Ssam 	/*
21730519Ssam 	 * Initialize label enough to do a reset on
21830519Ssam 	 * the drive.  The remainder of the default
21930519Ssam 	 * label values will be filled in in vdinit
22030519Ssam 	 * at attach time.
22125675Ssam 	 */
22232211Skarels 	if (vd->vd_type == VDTYPE_SMDE)
22332211Skarels 		lp->d_secsize = VD_MAXSECSIZE;
22432211Skarels 	else
22532211Skarels 		lp->d_secsize = VDDC_SECSIZE;
22634396Skarels 	lp->d_nsectors = 66;		/* only used on smd-e */
22734076Skarels 	lp->d_ntracks = 23;
22834396Skarels 	lp->d_ncylinders = 850;
22934396Skarels 	lp->d_secpercyl = 66*23;
23034592Skarels 	lp->d_npartitions = 1;
23134592Skarels 	lp->d_partitions[0].p_offset = 0;
23234592Skarels 	lp->d_partitions[0].p_size = LABELSECTOR + 1;
23324004Ssam 
23430519Ssam 	/*
23530519Ssam 	 * Initialize invariant portion of
23630519Ssam 	 * dcb used for overlapped seeks.
23730519Ssam 	 */
23830519Ssam 	dk->dk_dcb.opcode = VDOP_SEEK;
23930519Ssam 	dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA;
24030519Ssam 	dk->dk_dcb.devselect = vi->ui_slave;
24130756Skarels 	dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long);
24230519Ssam 	dk->dk_dcb.trail.sktrail.skaddr.sector = 0;
24330519Ssam 	dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb);
24432211Skarels #ifndef SECSIZE
24532211Skarels 	vd_setsecsize(dk, lp);
24632211Skarels #endif
24732211Skarels 	return (vdreset_drive(vi));
24832211Skarels }
24932211Skarels 
25032211Skarels vdattach(vi)
25132211Skarels 	register struct vba_device *vi;
25232211Skarels {
25332211Skarels 	register int unit = vi->ui_unit;
25432211Skarels 	register struct disklabel *lp = &dklabel[unit];
25532211Skarels 
25630601Skarels 	/*
25730601Skarels 	 * Try to initialize device and read pack label.
25830601Skarels 	 */
25930601Skarels 	if (vdinit(vdminor(unit, 0), 0) != 0) {
26030601Skarels 		printf(": unknown drive type");
26130601Skarels 		return;
26230601Skarels 	}
26332211Skarels 	if (dksoftc[unit].dk_state == OPEN)
26432211Skarels 		printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>",
26532211Skarels 		    lp->d_typename, lp->d_secsize,
26632211Skarels 		    lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors);
26730519Ssam 	/*
26830519Ssam 	 * (60 / rpm) / (sectors per track * (bytes per sector / 2))
26930519Ssam 	 */
27030519Ssam 	if (vi->ui_dk >= 0)
27130519Ssam 		dk_mspw[vi->ui_dk] = 120.0 /
27230519Ssam 		    (lp->d_rpm * lp->d_nsectors * lp->d_secsize);
27330519Ssam #ifdef notyet
27430573Skarels 	addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp);
27530519Ssam #endif
27624004Ssam }
27724004Ssam 
27830756Skarels vdopen(dev, flags, fmt)
27930519Ssam 	dev_t dev;
28030756Skarels 	int flags, fmt;
28124004Ssam {
28230519Ssam 	register unit = vdunit(dev);
28330519Ssam 	register struct disklabel *lp;
28430519Ssam 	register struct dksoftc *dk;
28530519Ssam 	register struct partition *pp;
28630519Ssam 	struct vba_device *vi;
28730756Skarels 	int s, error, part = vdpart(dev), mask = 1 << part;
28830519Ssam 	daddr_t start, end;
28924004Ssam 
29030519Ssam 	if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
29130519Ssam 		return (ENXIO);
29230519Ssam 	lp = &dklabel[unit];
29330519Ssam 	dk = &dksoftc[unit];
29430519Ssam 
29530519Ssam 	s = spl7();
29630519Ssam 	while (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
29730519Ssam 	    dk->dk_state != CLOSED)
29830519Ssam 		sleep((caddr_t)dk, PZERO+1);
29930519Ssam 	splx(s);
30030519Ssam 	if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
30130519Ssam 		if (error = vdinit(dev, flags))
30230519Ssam 			return (error);
30330573Skarels 
30430573Skarels 	if (vdwstart == 0) {
30530573Skarels 		timeout(vdwatch, (caddr_t)0, hz);
30630573Skarels 		vdwstart++;
30730573Skarels 	}
30830519Ssam 	/*
30930519Ssam 	 * Warn if a partion is opened
31030519Ssam 	 * that overlaps another partition which is open
31130519Ssam 	 * unless one is the "raw" partition (whole disk).
31230519Ssam 	 */
31332211Skarels #define	RAWPART		8		/* 'x' partition */	/* XXX */
31432576Skarels 	if ((dk->dk_openpart & mask) == 0 && part != RAWPART) {
31530519Ssam 		pp = &lp->d_partitions[part];
31630519Ssam 		start = pp->p_offset;
31730519Ssam 		end = pp->p_offset + pp->p_size;
31830519Ssam 		for (pp = lp->d_partitions;
31930519Ssam 		     pp < &lp->d_partitions[lp->d_npartitions]; pp++) {
32030519Ssam 			if (pp->p_offset + pp->p_size <= start ||
32130519Ssam 			    pp->p_offset >= end)
32230519Ssam 				continue;
32330519Ssam 			if (pp - lp->d_partitions == RAWPART)
32430519Ssam 				continue;
32530519Ssam 			if (dk->dk_openpart & (1 << (pp - lp->d_partitions)))
32630519Ssam 				log(LOG_WARNING,
32730519Ssam 				    "dk%d%c: overlaps open partition (%c)\n",
32830519Ssam 				    unit, part + 'a',
32930519Ssam 				    pp - lp->d_partitions + 'a');
33030519Ssam 		}
33124004Ssam 	}
33230519Ssam 	if (part >= lp->d_npartitions)
33330519Ssam 		return (ENXIO);
33430756Skarels 	dk->dk_openpart |= mask;
33530756Skarels 	switch (fmt) {
33630756Skarels 	case S_IFCHR:
33730756Skarels 		dk->dk_copenpart |= mask;
33830756Skarels 		break;
33930756Skarels 	case S_IFBLK:
34030756Skarels 		dk->dk_bopenpart |= mask;
34130756Skarels 		break;
34230756Skarels 	}
34330519Ssam 	return (0);
34425675Ssam }
34524004Ssam 
34634528Skarels /* ARGSUSED */
34730756Skarels vdclose(dev, flags, fmt)
34830519Ssam 	dev_t dev;
34930756Skarels 	int flags, fmt;
35024004Ssam {
35130519Ssam 	register int unit = vdunit(dev);
35230519Ssam 	register struct dksoftc *dk = &dksoftc[unit];
35330756Skarels 	int part = vdpart(dev), mask = 1 << part;
35424004Ssam 
35530756Skarels 	switch (fmt) {
35630756Skarels 	case S_IFCHR:
35730756Skarels 		dk->dk_copenpart &= ~mask;
35830756Skarels 		break;
35930756Skarels 	case S_IFBLK:
36030756Skarels 		dk->dk_bopenpart &= ~mask;
36130756Skarels 		break;
36230756Skarels 	}
36330756Skarels 	if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0)
36430756Skarels 		dk->dk_openpart &= ~mask;
36530519Ssam 	/*
36630519Ssam 	 * Should wait for i/o to complete on this partition
36730519Ssam 	 * even if others are open, but wait for work on blkflush().
36830519Ssam 	 */
36930519Ssam 	if (dk->dk_openpart == 0) {
37030573Skarels 		int s = spl7();
37130573Skarels 		while (dkutab[unit].b_actf)
37230573Skarels 			sleep((caddr_t)dk, PZERO-1);
37330519Ssam 		splx(s);
37430519Ssam 		dk->dk_state = CLOSED;
37534076Skarels 		dk->dk_wlabel = 0;
37624004Ssam 	}
37730756Skarels 	return (0);
37825675Ssam }
37924004Ssam 
38030519Ssam vdinit(dev, flags)
38130519Ssam 	dev_t dev;
38230519Ssam 	int flags;
38325675Ssam {
38430519Ssam 	register struct disklabel *lp;
38530519Ssam 	register struct dksoftc *dk;
38630519Ssam 	struct vba_device *vi;
38730519Ssam 	int unit = vdunit(dev), error = 0;
38830756Skarels 	char *msg, *readdisklabel();
38930519Ssam 	extern int cold;
39025675Ssam 
39130519Ssam 	dk = &dksoftc[unit];
39230519Ssam 	if (flags & O_NDELAY) {
39330519Ssam 		dk->dk_state = OPENRAW;
39434528Skarels 		return (0);
39530519Ssam 	}
39630519Ssam 	dk->dk_state = RDLABEL;
39730519Ssam 	lp = &dklabel[unit];
39830519Ssam 	vi = vddinfo[unit];
39930756Skarels 	if (msg = readdisklabel(dev, vdstrategy, lp)) {
40034076Skarels 		if (cold) {
40130601Skarels 			printf(": %s", msg);
40234076Skarels 			dk->dk_state = CLOSED;
40334076Skarels 		} else {
40432211Skarels 			log(LOG_ERR, "dk%d: %s\n", unit, msg);
40534076Skarels 			dk->dk_state = OPENRAW;
40634076Skarels 		}
40730519Ssam #ifdef COMPAT_42
40834076Skarels 		if (vdmaptype(vi, lp))
40930519Ssam 			dk->dk_state = OPEN;
41030519Ssam #endif
41130756Skarels 	} else {
41230756Skarels 		/*
41330756Skarels 		 * Now that we have the label, configure
41430756Skarels 		 * the correct drive parameters.
41530756Skarels 		 */
41632211Skarels 		if (vdreset_drive(vi))
41732211Skarels 			dk->dk_state = OPEN;
41832211Skarels 		else {
41930756Skarels 			dk->dk_state = CLOSED;
42030756Skarels 			error = ENXIO;
42132211Skarels 		}
42225675Ssam 	}
42330756Skarels #ifndef SECSIZE
42432211Skarels 	vd_setsecsize(dk, lp);
42532211Skarels #endif
42630519Ssam 	wakeup((caddr_t)dk);
42730519Ssam 	return (error);
42824004Ssam }
42924004Ssam 
43032211Skarels #ifndef SECSIZE
43132211Skarels vd_setsecsize(dk, lp)
43232211Skarels 	register struct dksoftc *dk;
43332211Skarels 	register struct disklabel *lp;
43432211Skarels {
43532211Skarels 	int mul;
43632211Skarels 
43732211Skarels 	/*
43832211Skarels 	 * Calculate scaling shift for mapping
43932211Skarels 	 * DEV_BSIZE blocks to drive sectors.
44032211Skarels 	 */
44132211Skarels 	mul = DEV_BSIZE / lp->d_secsize;
44232211Skarels 	dk->dk_bshift = 0;
44332211Skarels 	while ((mul >>= 1) > 0)
44432211Skarels 		dk->dk_bshift++;
44532211Skarels }
44632211Skarels #endif SECSIZE
44732211Skarels 
44825675Ssam /*ARGSUSED*/
44930519Ssam vddgo(vm)
45030519Ssam 	struct vba_device *vm;
45124004Ssam {
45224004Ssam 
45324004Ssam }
45424004Ssam 
45524004Ssam vdstrategy(bp)
45625675Ssam 	register struct buf *bp;
45724004Ssam {
45830519Ssam 	register struct vba_device *vi;
45930519Ssam 	register struct disklabel *lp;
46030519Ssam 	register struct dksoftc *dk;
46130519Ssam 	register int unit;
46230573Skarels 	register daddr_t sn;
46330519Ssam 	struct buf *dp;
46430573Skarels 	daddr_t sz, maxsz;
46530519Ssam 	int part, s;
46624004Ssam 
46730519Ssam 	unit = vdunit(bp->b_dev);
46832211Skarels 	if (unit >= NDK) {
46929954Skarels 		bp->b_error = ENXIO;
47025675Ssam 		goto bad;
47129954Skarels 	}
47230519Ssam 	vi = vddinfo[unit];
47330519Ssam 	lp = &dklabel[unit];
47430519Ssam 	if (vi == 0 || vi->ui_alive == 0) {
47530519Ssam 		bp->b_error = ENXIO;
47630519Ssam 		goto bad;
47730519Ssam 	}
47830519Ssam 	dk = &dksoftc[unit];
47930519Ssam 	if (dk->dk_state < OPEN)
48030519Ssam 		goto q;
48134076Skarels 	if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) {
48234076Skarels 		bp->b_error = EROFS;
48334076Skarels 		goto bad;
48434076Skarels 	}
48530519Ssam 	part = vdpart(bp->b_dev);
48630519Ssam 	if ((dk->dk_openpart & (1 << part)) == 0) {
48730519Ssam 		bp->b_error = ENODEV;
48830519Ssam 		goto bad;
48930519Ssam 	}
49032211Skarels 	sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
49130519Ssam 	maxsz = lp->d_partitions[part].p_size;
49230756Skarels #ifndef SECSIZE
49330756Skarels 	sn = bp->b_blkno << dk->dk_bshift;
49430756Skarels #else SECSIZE
49530573Skarels 	sn = bp->b_blkno;
49630756Skarels #endif SECSIZE
49734076Skarels 	if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR &&
49834076Skarels #if LABELSECTOR != 0
49934076Skarels 	    sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR &&
50034076Skarels #endif
50134076Skarels 	    (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) {
50234076Skarels 		bp->b_error = EROFS;
50334076Skarels 		goto bad;
50434076Skarels 	}
50530519Ssam 	if (sn < 0 || sn + sz > maxsz) {
50630519Ssam 		if (sn == maxsz) {
50729954Skarels 			bp->b_resid = bp->b_bcount;
50829954Skarels 			goto done;
50929954Skarels 		}
51030756Skarels 		sz = maxsz - sn;
51130573Skarels 		if (sz <= 0) {
51230573Skarels 			bp->b_error = EINVAL;
51330573Skarels 			goto bad;
51430573Skarels 		}
51530573Skarels 		bp->b_bcount = sz * lp->d_secsize;
51625675Ssam 	}
51730519Ssam 	bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl;
51830756Skarels #ifdef SECSIZE
51930756Skarels if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0)
52030756Skarels panic("vdstrat blksize");
52130756Skarels #endif SECSIZE
52230519Ssam q:
52325675Ssam 	s = spl7();
52430519Ssam 	dp = &dkutab[vi->ui_unit];
52530519Ssam 	disksort(dp, bp);
52630519Ssam 	if (!dp->b_active) {
52730519Ssam 		(void) vdustart(vi);
52830573Skarels 		if (!vi->ui_mi->um_tab.b_active)
52930519Ssam 			vdstart(vi->ui_mi);
53024004Ssam 	}
53130519Ssam 	splx(s);
53224004Ssam 	return;
53325675Ssam bad:
53429954Skarels 	bp->b_flags |= B_ERROR;
53529954Skarels done:
53630519Ssam 	biodone(bp);
53730519Ssam 	return;
53824004Ssam }
53924004Ssam 
54030519Ssam vdustart(vi)
54130519Ssam 	register struct vba_device *vi;
54224004Ssam {
54330519Ssam 	register struct buf *bp, *dp;
54430519Ssam 	register struct vba_ctlr *vm;
54530519Ssam 	register int unit = vi->ui_unit;
54630519Ssam 	register struct dksoftc *dk;
54730519Ssam 	register struct vdsoftc *vd;
54830519Ssam 	struct disklabel *lp;
54924004Ssam 
55030519Ssam 	dp = &dkutab[unit];
55130519Ssam 	/*
55230519Ssam 	 * If queue empty, nothing to do.
55330519Ssam 	 */
55430519Ssam 	if ((bp = dp->b_actf) == NULL)
55530519Ssam 		return;
55630519Ssam 	/*
55730574Skarels 	 * If drive is off-cylinder and controller supports seeks,
55830574Skarels 	 * place drive on seek queue for controller.
55930574Skarels 	 * Otherwise, place on transfer queue.
56030519Ssam 	 */
56130519Ssam 	vd = &vdsoftc[vi->ui_ctlr];
56230519Ssam 	dk = &dksoftc[unit];
56330574Skarels 	vm = vi->ui_mi;
56430519Ssam 	if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) {
56530519Ssam 		lp = &dklabel[unit];
56630574Skarels 		bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors;
56730574Skarels 		if (vm->um_tab.b_seekf == NULL)
56830574Skarels 			vm->um_tab.b_seekf = dp;
56930574Skarels 		else
57030574Skarels 			vm->um_tab.b_seekl->b_forw = dp;
57130574Skarels 		vm->um_tab.b_seekl = dp;
57230574Skarels 	} else {
57330574Skarels 		if (vm->um_tab.b_actf == NULL)
57430574Skarels 			vm->um_tab.b_actf = dp;
57530574Skarels 		else
57630574Skarels 			vm->um_tab.b_actl->b_forw = dp;
57730574Skarels 		vm->um_tab.b_actl = dp;
57830519Ssam 	}
57930573Skarels 	dp->b_forw = NULL;
58030573Skarels 	dp->b_active++;
58125675Ssam }
58225675Ssam 
58325675Ssam /*
58430519Ssam  * Start next transfer on a controller.
58530574Skarels  * There are two queues of drives, the first on-cylinder
58630574Skarels  * and the second off-cylinder from their next transfers.
58730574Skarels  * Perform the first transfer for the first drive on the on-cylinder
58830574Skarels  * queue, if any, otherwise the first transfer for the first drive
58930574Skarels  * on the second queue.  Initiate seeks on remaining drives on the
59030574Skarels  * off-cylinder queue, then move them all to the on-cylinder queue.
59125675Ssam  */
59230519Ssam vdstart(vm)
59330519Ssam 	register struct vba_ctlr *vm;
59425675Ssam {
59525675Ssam 	register struct buf *bp;
59630519Ssam 	register struct vba_device *vi;
59730519Ssam 	register struct vdsoftc *vd;
59830519Ssam 	register struct dksoftc *dk;
59930519Ssam 	register struct disklabel *lp;
60030519Ssam 	register struct dcb **dcbp;
60130519Ssam 	struct buf *dp;
60230519Ssam 	int sn, tn;
60325675Ssam 
60430519Ssam loop:
60530519Ssam 	/*
60630519Ssam 	 * Pull a request off the controller queue.
60730519Ssam 	 */
60830574Skarels 	if ((dp = vm->um_tab.b_actf) == NULL &&
60930574Skarels 	    (dp = vm->um_tab.b_seekf) == NULL)
61030519Ssam 		return;
61130519Ssam 	if ((bp = dp->b_actf) == NULL) {
61230601Skarels 		if (dp == vm->um_tab.b_actf)
61330601Skarels 			vm->um_tab.b_actf = dp->b_forw;
61430601Skarels 		else
61530601Skarels 			vm->um_tab.b_seekf = dp->b_forw;
61630519Ssam 		goto loop;
61730519Ssam 	}
61825675Ssam 
61924004Ssam 	/*
62030519Ssam 	 * Mark controller busy, and determine
62130519Ssam 	 * destination of this request.
62224004Ssam 	 */
62330519Ssam 	vm->um_tab.b_active++;
62430519Ssam 	vi = vddinfo[vdunit(bp->b_dev)];
62530519Ssam 	dk = &dksoftc[vi->ui_unit];
62630756Skarels #ifndef SECSIZE
62730756Skarels 	sn = bp->b_blkno << dk->dk_bshift;
62830756Skarels #else SECSIZE
62930573Skarels 	sn = bp->b_blkno;
63030756Skarels #endif SECSIZE
63130519Ssam 	lp = &dklabel[vi->ui_unit];
63230519Ssam 	sn %= lp->d_secpercyl;
63330519Ssam 	tn = sn / lp->d_nsectors;
63430519Ssam 	sn %= lp->d_nsectors;
63530519Ssam 
63630519Ssam 	/*
63730519Ssam 	 * Construct dcb for read/write command.
63830519Ssam 	 */
63930519Ssam 	vd = &vdsoftc[vm->um_ctlr];
64030519Ssam 	vd->vd_dcb.intflg = DCBINT_DONE;
64132211Skarels 	vd->vd_dcb.devselect = dk->dk_dcb.devselect;
64230519Ssam 	vd->vd_dcb.operrsta = 0;
64330519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
64430519Ssam 	vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin;
64530519Ssam 	vd->vd_dcb.trail.rwtrail.disk.track = tn;
64630519Ssam 	vd->vd_dcb.trail.rwtrail.disk.sector = sn;
64730574Skarels 	dk->dk_curcyl = bp->b_cylin;
64830574Skarels 	bp->b_track = 0;		/* init overloaded field */
64930756Skarels 	vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
65034396Skarels 	if (bp->b_flags & B_FORMAT)
65134396Skarels 		vd->vd_dcb.opcode = dk->dk_op;
65234396Skarels 	else if (vd->vd_flags & VD_SCATGATH &&
65334396Skarels 	    ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0)
65430756Skarels 		vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW;
65534396Skarels 	else
65630756Skarels 		vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD;
65734396Skarels 
65834396Skarels 	switch (vd->vd_dcb.opcode) {
65934396Skarels 	case VDOP_FSECT:
66034396Skarels 		vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
66134396Skarels 		vd->vd_dcb.trail.fmtrail.nsectors = bp->b_bcount /
66234396Skarels 		    lp->d_secsize;
66334396Skarels 		vd->vd_dcb.trail.fmtrail.hdr = *(dskadr *)&dk->dk_althdr;
66434396Skarels 		vd->vd_dcb.trail.rwtrail.disk.cylinder |= dk->dk_fmtflags;
66534396Skarels 		goto setupaddr;
66634396Skarels 
66734396Skarels 	case VDOP_RDRAW:
66834396Skarels 	case VDOP_RD:
66934396Skarels 	case VDOP_WD:
67034396Skarels 		vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1;
67134396Skarels setupaddr:
67230756Skarels 		vd->vd_dcb.trail.rwtrail.memadr =
67334528Skarels 			vbasetup(bp, &vd->vd_rbuf, (int)lp->d_secsize);
67434396Skarels 		break;
67534396Skarels 
67634396Skarels 	case VDOP_RAS:
67734396Skarels 	case VDOP_GAW:
67834396Skarels 		vd->vd_dcb.trailcnt += vba_sgsetup(bp, &vd->vd_rbuf,
67934396Skarels 		    &vd->vd_dcb.trail.sgtrail);
68034396Skarels 		break;
68130756Skarels 	}
68230574Skarels 	if (vi->ui_dk >= 0) {
68330574Skarels 		dk_busy |= 1<<vi->ui_dk;
68430574Skarels 		dk_xfer[vi->ui_dk]++;
68530574Skarels 		dk_wds[vi->ui_dk] += bp->b_bcount>>6;
68630574Skarels 	}
68730519Ssam 
68830519Ssam 	/*
68930519Ssam 	 * Look for any seeks to be performed on other drives on this
69030519Ssam 	 * controller.  If overlapped seeks exist, insert seek commands
69130519Ssam 	 * on the controller's command queue before the transfer.
69230519Ssam 	 */
69330519Ssam 	dcbp = &vd->vd_mdcb.mdcb_head;
69430519Ssam 
69530574Skarels 	if (dp == vm->um_tab.b_seekf)
69630574Skarels 		dp = dp->b_forw;
69730574Skarels 	else
69830574Skarels 		dp = vm->um_tab.b_seekf;
69930574Skarels 	for (; dp != NULL; dp = dp->b_forw) {
70030574Skarels 		if ((bp = dp->b_actf) == NULL)
70130574Skarels 			continue;
70230574Skarels 		vi = vddinfo[vdunit(bp->b_dev)];
70330574Skarels 		dk = &dksoftc[vi->ui_unit];
70430519Ssam 		dk->dk_curcyl = bp->b_cylin;
70530574Skarels 		if (vi->ui_dk >= 0)
70630574Skarels 			dk_seek[vi->ui_dk]++;
70730574Skarels 		dk->dk_dcb.operrsta = 0;
70830574Skarels 		dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin;
70930574Skarels 		dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track;
71030574Skarels 		*dcbp = (struct dcb *)dk->dk_dcbphys;
71130574Skarels 		dcbp = &dk->dk_dcb.nxtdcb;
71224004Ssam 	}
71330519Ssam 	*dcbp = (struct dcb *)vd->vd_dcbphys;
71430574Skarels 	if (vm->um_tab.b_actf)
71530574Skarels 		vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf;
71630574Skarels 	else
71730574Skarels 		vm->um_tab.b_actf = vm->um_tab.b_seekf;
71830601Skarels 	if (vm->um_tab.b_seekf)
71930601Skarels 		vm->um_tab.b_actl = vm->um_tab.b_seekl;
72030574Skarels 	vm->um_tab.b_seekf = 0;
72124004Ssam 
72230519Ssam 	/*
72330519Ssam 	 * Initiate operation.
72430519Ssam 	 */
72530519Ssam 	vd->vd_mdcb.mdcb_status = 0;
72630519Ssam 	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
72724004Ssam }
72824004Ssam 
72930519Ssam #define	DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE)
73024004Ssam /*
73124004Ssam  * Handle a disk interrupt.
73224004Ssam  */
73325675Ssam vdintr(ctlr)
73430519Ssam 	register ctlr;
73524004Ssam {
73630519Ssam 	register struct buf *bp, *dp;
73730519Ssam 	register struct vba_ctlr *vm = vdminfo[ctlr];
73830519Ssam 	register struct vba_device *vi;
73930519Ssam 	register struct vdsoftc *vd = &vdsoftc[ctlr];
74030519Ssam 	register status;
74134528Skarels 	int timedout;
74230573Skarels 	struct dksoftc *dk;
74324004Ssam 
74430519Ssam 	if (!vm->um_tab.b_active) {
74525675Ssam 		printf("vd%d: stray interrupt\n", ctlr);
74624004Ssam 		return;
74724004Ssam 	}
74825675Ssam 	/*
74930519Ssam 	 * Get device and block structures, and a pointer
75030519Ssam 	 * to the vba_device for the drive.
75125675Ssam 	 */
75230519Ssam 	dp = vm->um_tab.b_actf;
75330519Ssam 	bp = dp->b_actf;
75430519Ssam 	vi = vddinfo[vdunit(bp->b_dev)];
75534528Skarels 	dk = &dksoftc[vi->ui_unit];
75630574Skarels 	if (vi->ui_dk >= 0)
75730574Skarels 		dk_busy &= ~(1<<vi->ui_dk);
75834396Skarels 	timedout = (vd->vd_wticks >= VDMAXTIME);
75930519Ssam 	/*
76030519Ssam 	 * Check for and process errors on
76130519Ssam 	 * either the drive or the controller.
76230519Ssam 	 */
76330519Ssam 	uncache(&vd->vd_dcb.operrsta);
76430519Ssam 	status = vd->vd_dcb.operrsta;
76534396Skarels 	if (bp->b_flags & B_FORMAT) {
76634396Skarels 		dk->dk_operrsta = status;
76734396Skarels 		uncache(&vd->vd_dcb.err_code);
76834396Skarels 		dk->dk_ecode = vd->vd_dcb.err_code;
76934396Skarels 	}
77034396Skarels 	if (status & VDERR_HARD || timedout) {
77134528Skarels 		if (vd->vd_type == VDTYPE_SMDE)
77230601Skarels 			uncache(&vd->vd_dcb.err_code);
77330519Ssam 		if (status & DCBS_WPT) {
77430519Ssam 			/*
77530519Ssam 			 * Give up on write locked devices immediately.
77630519Ssam 			 */
77730573Skarels 			printf("dk%d: write locked\n", vi->ui_unit);
77830519Ssam 			bp->b_flags |= B_ERROR;
77934396Skarels 		} else if (status & VDERR_RETRY || timedout) {
78032211Skarels 			int endline = 1;
78132211Skarels 
78234396Skarels 			if (status & VDERR_CTLR || timedout) {
78334396Skarels 				vdharderr("controller err",
78434396Skarels 				    vd, bp, &vd->vd_dcb);
78534396Skarels 				printf("; resetting controller...");
78634396Skarels 				vdreset_ctlr(vm);
78734396Skarels 			} else if (status & VDERR_DRIVE) {
78834396Skarels 				vdharderr("drive err", vd, bp, &vd->vd_dcb);
78934396Skarels 				printf("; resetting drive...");
79030519Ssam 				if (!vdreset_drive(vi))
79130519Ssam 					vi->ui_alive = 0;
79232211Skarels 			} else
79332211Skarels 				endline = 0;
79430519Ssam 			/*
79530519Ssam 			 * Retry transfer once, unless reset failed.
79630519Ssam 			 */
79734396Skarels 			if (!vi->ui_alive || dp->b_errcnt++ >= 2 ||
79834396Skarels 			    bp->b_flags & B_FORMAT) {
79932211Skarels 				if (endline)
80032211Skarels 					printf("\n");
80130519Ssam 				goto hard;
80232211Skarels 			}
80332211Skarels 
80432211Skarels 			if (endline)
80532211Skarels 				printf(" retrying\n");
80630519Ssam 			vm->um_tab.b_active = 0;	/* force retry */
80730519Ssam 		} else  {
80830519Ssam 	hard:
80930519Ssam 			bp->b_flags |= B_ERROR;
81034396Skarels 			vdharderr("hard error", vd, bp, &vd->vd_dcb);
81130519Ssam 			printf("\n");
81230519Ssam 		}
81330519Ssam 	} else if (status & DCBS_SOFT)
81434528Skarels 		vdsofterr(bp, &vd->vd_dcb);
81534396Skarels 	vd->vd_wticks = 0;
81630519Ssam 	if (vm->um_tab.b_active) {
81730519Ssam 		vm->um_tab.b_active = 0;
81830519Ssam 		vm->um_tab.b_actf = dp->b_forw;
81930519Ssam 		dp->b_active = 0;
82030519Ssam 		dp->b_errcnt = 0;
82130519Ssam 		dp->b_actf = bp->av_forw;
82230519Ssam 		bp->b_resid = 0;
82330601Skarels 		vbadone(bp, &vd->vd_rbuf);
82430519Ssam 		biodone(bp);
82530370Skarels 		/*
82630519Ssam 		 * If this unit has more work to do,
82730519Ssam 		 * then start it up right away.
82830370Skarels 		 */
82930519Ssam 		if (dp->b_actf)
83030519Ssam 			vdustart(vi);
83134528Skarels 		else if (dk->dk_openpart == 0)
83230573Skarels 			wakeup((caddr_t)dk);
83324004Ssam 	}
83425675Ssam 	/*
83530519Ssam 	 * If there are devices ready to
83630519Ssam 	 * transfer, start the controller.
83725675Ssam 	 */
83830601Skarels 	if (vm->um_tab.b_actf || vm->um_tab.b_seekf)
83930519Ssam 		vdstart(vm);
84024004Ssam }
84124004Ssam 
84234396Skarels vdharderr(what, vd, bp, dcb)
84334396Skarels 	char *what;
84434396Skarels 	struct vdsoftc *vd;
84534396Skarels 	register struct buf *bp;
84634396Skarels 	register struct dcb *dcb;
84734396Skarels {
84834396Skarels 	int unit = vdunit(bp->b_dev), status = dcb->operrsta;
84934396Skarels 	register struct disklabel *lp = &dklabel[unit];
85034528Skarels 	int blkdone;
85134396Skarels 
85234396Skarels 	if (vd->vd_wticks < VDMAXTIME)
85334396Skarels 		status &= ~DONTCARE;
85434710Skarels 	blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) *
85534710Skarels 	    lp->d_nsectors + dcb->err_sec -
85634710Skarels 	    lp->d_partitions[vdpart(bp->b_dev)].p_offset) >>
85734710Skarels 	    dksoftc[unit].dk_bshift) - bp->b_blkno;
85834528Skarels 	diskerr(bp, "dk", what, LOG_PRINTF, blkdone, lp);
85934528Skarels 	printf(", status %b", status, VDERRBITS);
86034396Skarels 	if (vd->vd_type == VDTYPE_SMDE)
86134396Skarels 		printf(" ecode %x", dcb->err_code);
86234396Skarels }
86334396Skarels 
86434528Skarels vdsofterr(bp, dcb)
86525675Ssam 	register struct buf *bp;
86630519Ssam 	register struct dcb *dcb;
86725675Ssam {
86834562Skarels 	int unit = vdunit(bp->b_dev);
86934562Skarels 	struct disklabel *lp = &dklabel[unit];
87034528Skarels 	int status = dcb->operrsta;
87134528Skarels 	int blkdone;
87225675Ssam 
87334710Skarels 	blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) *
87434710Skarels 	    lp->d_nsectors + dcb->err_sec -
87534710Skarels 	    lp->d_partitions[vdpart(bp->b_dev)].p_offset) >>
87634710Skarels 	    dksoftc[unit].dk_bshift) - bp->b_blkno;
87734528Skarels 
87834528Skarels 	if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) {
87934528Skarels 		diskerr(bp, "dk", "soft error", LOG_WARNING, blkdone, lp);
88034528Skarels 		addlog(", status %b ecode %x\n", status, VDERRBITS,
88134396Skarels 		    dcb->err_code);
88234528Skarels 	} else {
88334528Skarels 		diskerr(bp, "dk", "soft ecc", LOG_WARNING, blkdone, lp);
88434528Skarels 		addlog("\n");
88534528Skarels 	}
88625675Ssam }
88725675Ssam 
88830519Ssam vdioctl(dev, cmd, data, flag)
88925675Ssam 	dev_t dev;
89030519Ssam 	int cmd;
89130519Ssam 	caddr_t data;
89230519Ssam 	int flag;
89324004Ssam {
89432576Skarels 	register int unit = vdunit(dev);
89530519Ssam 	register struct disklabel *lp = &dklabel[unit];
89634076Skarels 	register struct dksoftc *dk = &dksoftc[unit];
89734640Skarels 	int error = 0, vdformat();
89824004Ssam 
89930519Ssam 	switch (cmd) {
90030519Ssam 
90130519Ssam 	case DIOCGDINFO:
90230519Ssam 		*(struct disklabel *)data = *lp;
90330519Ssam 		break;
90430519Ssam 
90530573Skarels 	case DIOCGPART:
90630573Skarels 		((struct partinfo *)data)->disklab = lp;
90730573Skarels 		((struct partinfo *)data)->part =
90830573Skarels 		    &lp->d_partitions[vdpart(dev)];
90930519Ssam 		break;
91030519Ssam 
91130519Ssam 	case DIOCSDINFO:
91230519Ssam 		if ((flag & FWRITE) == 0)
91330519Ssam 			error = EBADF;
91430519Ssam 		else
91532576Skarels 			error = setdisklabel(lp, (struct disklabel *)data,
91634076Skarels 			    (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart);
91734396Skarels 		if (error == 0 && dk->dk_state == OPENRAW &&
91834396Skarels 		    vdreset_drive(vddinfo[unit]))
91934076Skarels 			dk->dk_state = OPEN;
92030519Ssam 		break;
92130519Ssam 
92234076Skarels 	case DIOCWLABEL:
92334076Skarels 		if ((flag & FWRITE) == 0)
92434076Skarels 			error = EBADF;
92534076Skarels 		else
92634076Skarels 			dk->dk_wlabel = *(int *)data;
92734076Skarels 		break;
92834076Skarels 
92932576Skarels 	case DIOCWDINFO:
93032576Skarels 		if ((flag & FWRITE) == 0)
93130519Ssam 			error = EBADF;
93232576Skarels 		else if ((error = setdisklabel(lp, (struct disklabel *)data,
93334076Skarels 		    (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) {
93434640Skarels 			int wlab;
93534640Skarels 
93634076Skarels 			dk->dk_state = OPEN;
93734640Skarels 			/* simulate opening partition 0 so write succeeds */
93834640Skarels 			dk->dk_openpart |= (1 << 0);		/* XXX */
93934640Skarels 			wlab = dk->dk_wlabel;
94034640Skarels 			dk->dk_wlabel = 1;
94132576Skarels 			error = writedisklabel(dev, vdstrategy, lp);
94234640Skarels 			dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;
94334640Skarels 			dk->dk_wlabel = wlab;
94434076Skarels 		}
94530519Ssam 		break;
94630519Ssam 
94734396Skarels 	case DIOCWFORMAT:
94834396Skarels 	    {
94934396Skarels 		register struct format_op *fop;
95034396Skarels 		struct uio auio;
95134396Skarels 		struct iovec aiov;
95234396Skarels 
95334396Skarels 		if ((flag & FWRITE) == 0) {
95434396Skarels 			error = EBADF;
95534396Skarels 			break;
95634396Skarels 		}
95734396Skarels 		fop = (struct format_op *)data;
95834396Skarels 		aiov.iov_base = fop->df_buf;
95934396Skarels 		aiov.iov_len = fop->df_count;
96034396Skarels 		auio.uio_iov = &aiov;
96134396Skarels 		auio.uio_iovcnt = 1;
96234396Skarels 		auio.uio_resid = fop->df_count;
96334396Skarels 		auio.uio_segflg = UIO_USERSPACE;
96434396Skarels 		auio.uio_offset = fop->df_startblk * lp->d_secsize;
96534396Skarels 		dk->dk_operrsta = fop->dk_operrsta;
96634396Skarels 		dk->dk_ecode = fop->dk_ecode;
96734396Skarels 		/*
96834396Skarels 		 * Don't return errors, as the format op won't get copied
96934396Skarels 		 * out if we return nonzero.  Callers must check the returned
97034396Skarels 		 * count.
97134396Skarels 		 */
97234396Skarels 		(void) physio(vdformat, (struct buf *)NULL, dev,
97334396Skarels 		    (cmd == DIOCWFORMAT ? B_WRITE : B_READ), minphys, &auio);
97434396Skarels 		fop->df_count -= auio.uio_resid;
97534396Skarels 		fop->dk_operrsta = dk->dk_operrsta;
97634396Skarels 		fop->dk_ecode = dk->dk_ecode;
97734396Skarels 		break;
97834396Skarels 	    }
97934396Skarels 
98030519Ssam 	default:
98130519Ssam 		error = ENOTTY;
98230519Ssam 		break;
98324004Ssam 	}
98432606Skarels 	return (error);
98524004Ssam }
98624004Ssam 
98734396Skarels vdformat(bp)
98834396Skarels 	struct buf *bp;
98934396Skarels {
99034396Skarels 	bp->b_flags |= B_FORMAT;
99134396Skarels 	vdstrategy(bp);
99234396Skarels }
99334396Skarels 
99425675Ssam /*
99530519Ssam  * Watch for lost interrupts.
99625675Ssam  */
99730519Ssam vdwatch()
99830519Ssam {
99930519Ssam 	register struct vdsoftc *vd;
100030519Ssam 	register struct vba_ctlr *vm;
100134528Skarels 	register int ctlr;
100234396Skarels 	int s;
100330519Ssam 
100430519Ssam 	timeout(vdwatch, (caddr_t)0, hz);
100530519Ssam 	for (ctlr = 0; ctlr < NVD; ctlr++) {
100630519Ssam 		vm = vdminfo[ctlr];
100730519Ssam 		if (vm == 0 || vm->um_alive == 0)
100830519Ssam 			continue;
100930519Ssam 		vd = &vdsoftc[ctlr];
101034396Skarels 		s = spl7();
101134396Skarels 		if (vm->um_tab.b_active && vd->vd_wticks++ >= VDMAXTIME) {
101230519Ssam 			printf("vd%d: lost interrupt\n", ctlr);
101334396Skarels #ifdef maybe
101434396Skarels 			VDABORT((struct vddevice *)vm->um_addr, vd->vd_type);
101534396Skarels #endif
101634396Skarels 			vdintr(ctlr);
101730519Ssam 		}
101834396Skarels 		splx(s);
101930519Ssam 	}
102030519Ssam }
102130519Ssam 
102230519Ssam #define	DBSIZE	64	/* controller limit with 1K sectors */
102330519Ssam /*
102430519Ssam  * Crash dump.
102530519Ssam  */
102630519Ssam vddump(dev)
102730519Ssam 	dev_t dev;
102824004Ssam {
102930519Ssam 	register struct vba_device *vi;
103030519Ssam 	register struct vba_ctlr *vm;
103130519Ssam 	register struct disklabel *lp;
103230519Ssam 	register struct vdsoftc *vd;
103330519Ssam 	struct dksoftc *dk;
103430519Ssam 	int part, unit, num;
103530601Skarels 	u_long start;
103624004Ssam 
103730519Ssam 	start = 0;
103830519Ssam 	unit = vdunit(dev);
103930519Ssam 	if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
104030519Ssam 		return (ENXIO);
104130519Ssam 	dk = &dksoftc[unit];
104234076Skarels 	if (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
104334076Skarels 	    vdinit(vdminor(unit, 0), 0) != 0)
104430519Ssam 		return (ENXIO);
104530519Ssam 	lp = &dklabel[unit];
104630519Ssam 	part = vdpart(dev);
104730519Ssam 	if (part >= lp->d_npartitions)
104830519Ssam 		return (ENXIO);
104932211Skarels 	vm = vi->ui_mi;
105030519Ssam 	vdreset_ctlr(vm);
105130519Ssam 	if (dumplo < 0)
105230519Ssam 		return (EINVAL);
105330519Ssam 	/*
105430756Skarels 	 * Maxfree is in pages, dumplo is in DEV_BSIZE units.
105530519Ssam 	 */
105630519Ssam 	num = maxfree * (NBPG / lp->d_secsize);
105730756Skarels 	dumplo *= DEV_BSIZE / lp->d_secsize;
105830519Ssam 	if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size)
105930519Ssam 		num = lp->d_partitions[vdpart(dev)].p_size - dumplo;
106030519Ssam 	vd = &vdsoftc[vm->um_ctlr];
106130519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
106230519Ssam 	vd->vd_dcb.opcode = VDOP_WD;
106332211Skarels 	vd->vd_dcb.devselect = dk->dk_dcb.devselect;
106430756Skarels 	vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
106530519Ssam 	while (num > 0) {
106630519Ssam 		int nsec, cn, sn, tn;
106730519Ssam 
106830519Ssam 		nsec = MIN(num, DBSIZE);
106930601Skarels 		sn = dumplo + start / lp->d_secsize;
107030519Ssam 		cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) /
107130519Ssam 		    lp->d_secpercyl;
107230519Ssam 		sn %= lp->d_secpercyl;
107330519Ssam 		tn = sn / lp->d_nsectors;
107430519Ssam 		sn %= lp->d_nsectors;
107530519Ssam 		vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
107630519Ssam 		vd->vd_dcb.trail.rwtrail.memadr = start;
107730519Ssam 		vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1;
107830519Ssam 		vd->vd_dcb.trail.rwtrail.disk.cylinder = cn;
107930519Ssam 		vd->vd_dcb.trail.rwtrail.disk.track = tn;
108030519Ssam 		vd->vd_dcb.trail.rwtrail.disk.sector = sn;
108130519Ssam 		vd->vd_dcb.operrsta = 0;
108230519Ssam 		VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
108330519Ssam 		if (!vdpoll(vm, 5)) {
108430519Ssam 			printf(" during dump\n");
108530519Ssam 			return (EIO);
108630519Ssam 		}
108730519Ssam 		if (vd->vd_dcb.operrsta & VDERR_HARD) {
108830519Ssam 			printf("dk%d: hard error, status=%b\n", unit,
108930519Ssam 			    vd->vd_dcb.operrsta, VDERRBITS);
109030519Ssam 			return (EIO);
109130519Ssam 		}
109230519Ssam 		start += nsec * lp->d_secsize;
109330519Ssam 		num -= nsec;
109425675Ssam 	}
109530519Ssam 	return (0);
109624004Ssam }
109724004Ssam 
109824004Ssam vdsize(dev)
109925675Ssam 	dev_t dev;
110024004Ssam {
110130519Ssam 	register int unit = vdunit(dev);
110230519Ssam 	register struct dksoftc *dk;
110330519Ssam 	struct vba_device *vi;
110430519Ssam 	struct disklabel *lp;
110524004Ssam 
110630519Ssam 	if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 ||
110730519Ssam 	    (dk = &dksoftc[unit])->dk_state != OPEN)
110825675Ssam 		return (-1);
110930519Ssam 	lp = &dklabel[unit];
111030756Skarels #ifdef SECSIZE
111130573Skarels 	return ((int)lp->d_partitions[vdpart(dev)].p_size);
111230756Skarels #else SECSIZE
111330756Skarels 	return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift);
111430756Skarels #endif SECSIZE
111524004Ssam }
111624004Ssam 
111725675Ssam /*
111825675Ssam  * Perform a controller reset.
111925675Ssam  */
112030519Ssam vdreset_ctlr(vm)
112130519Ssam 	register struct vba_ctlr *vm;
112224004Ssam {
112330519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
112430519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
112530519Ssam 	register int unit;
112630519Ssam 	struct vba_device *vi;
112725675Ssam 
112830519Ssam 	VDRESET(vdaddr, vd->vd_type);
112930519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
113030519Ssam 		vdaddr->vdcsr = 0;
113130519Ssam 		vdaddr->vdtcf_mdcb = AM_ENPDA;
113230519Ssam 		vdaddr->vdtcf_dcb = AM_ENPDA;
113330519Ssam 		vdaddr->vdtcf_trail = AM_ENPDA;
113430519Ssam 		vdaddr->vdtcf_data = AM_ENPDA;
113530519Ssam 		vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
113625675Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
113725675Ssam 	}
113830519Ssam 	if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) {
113930519Ssam 		printf("%s cmd failed\n",
114030519Ssam 		    vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
114130370Skarels 		return;
114225675Ssam 	}
114330519Ssam 	for (unit = 0; unit < NDK; unit++)
114430519Ssam 		if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive)
114530519Ssam 			(void) vdreset_drive(vi);
114630519Ssam }
114730519Ssam 
114830519Ssam vdreset_drive(vi)
114930519Ssam 	register struct vba_device *vi;
115030519Ssam {
115130519Ssam 	register struct disklabel *lp = &dklabel[vi->ui_unit];
115230519Ssam 	struct vba_ctlr *vm = vdminfo[vi->ui_ctlr];
115330519Ssam 	struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
115432211Skarels 	register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
115532211Skarels 	register struct dksoftc *dk = &dksoftc[vi->ui_unit];
115630519Ssam 
115730519Ssam top:
115830519Ssam 	vd->vd_dcb.opcode = VDOP_CONFIG;		/* command */
115930519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
116030519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
116130519Ssam 	vd->vd_dcb.operrsta = 0;
116232211Skarels 	vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags;
116330519Ssam 	vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders;
116430519Ssam 	vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks;
116530519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
116630756Skarels 		vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long);
116730519Ssam 		vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors;
116830601Skarels 		vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack;
116932211Skarels 		vd->vd_dcb.trail.rstrail.recovery = VDRF_NORMAL;
117030519Ssam 	} else
117130519Ssam 		vd->vd_dcb.trailcnt = 2;		/* XXX */
117230519Ssam 	vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
117330519Ssam 	vd->vd_mdcb.mdcb_status = 0;
117430519Ssam 	VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type);
117530519Ssam 	if (!vdpoll(vm, 5)) {
117630519Ssam 		printf(" during config\n");
117730519Ssam 		return (0);
117825675Ssam 	}
117930519Ssam 	if (vd->vd_dcb.operrsta & VDERR_HARD) {
118032211Skarels 		if (vd->vd_type == VDTYPE_SMDE) {
118132211Skarels 			if (lp->d_devflags == 0) {
118232211Skarels 				lp->d_devflags = VD_ESDI;
118332211Skarels 				goto top;
118432211Skarels 			}
118532211Skarels #ifdef notdef
118632211Skarels 			/* this doesn't work, STA_US isn't set(?) */
118732211Skarels 			if ((vdaddr->vdstatus[vi->ui_slave] & STA_US) == 0)
118832211Skarels 				return (0);
118932211Skarels #endif
119032211Skarels 		}
119130519Ssam 		if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0)
119232211Skarels 			printf("dk%d: config error %b ecode %x\n", vi->ui_unit,
119334396Skarels 			   vd->vd_dcb.operrsta, VDERRBITS,
119434396Skarels 			   (u_char) vd->vd_dcb.err_code);
119532211Skarels 		else if ((vd->vd_flags & VD_STARTED) == 0) {
119630519Ssam 			int started;
119730519Ssam 
119832211Skarels 			printf(" starting drives, wait ... ");
119930519Ssam 			vd->vd_flags |= VD_STARTED;
120030519Ssam 			started = (vdcmd(vm, VDOP_START, 10) == 1);
120130519Ssam 			DELAY(62000000);
120232211Skarels 			printf("done");
120332211Skarels 			lp->d_devflags = 0;
120430519Ssam 			if (started)
120530519Ssam 				goto top;
120630519Ssam 		}
120730519Ssam 		return (0);
120830519Ssam 	}
120932211Skarels 	dk->dk_dcb.devselect |= lp->d_devflags;
121030519Ssam 	return (1);
121125675Ssam }
121224004Ssam 
121325675Ssam /*
121430519Ssam  * Perform a command w/o trailer.
121525675Ssam  */
121630519Ssam vdcmd(vm, cmd, t)
121730519Ssam 	register struct vba_ctlr *vm;
121825675Ssam {
121930519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
122025675Ssam 
122130519Ssam 	vd->vd_dcb.opcode = cmd;		/* command */
122230519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
122330519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
122430519Ssam 	vd->vd_dcb.operrsta = 0;
122530519Ssam 	vd->vd_dcb.devselect = 0;
122630519Ssam 	vd->vd_dcb.trailcnt = 0;
122730519Ssam 	vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
122830519Ssam 	vd->vd_mdcb.mdcb_status = 0;
122930519Ssam 	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
123030519Ssam 	if (!vdpoll(vm, t)) {
123130519Ssam 		printf(" during init\n");
123230370Skarels 		return (0);
123330370Skarels 	}
123430519Ssam 	return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0);
123525675Ssam }
123625675Ssam 
123725925Ssam /*
123830519Ssam  * Poll controller until operation
123930519Ssam  * completes or timeout expires.
124025925Ssam  */
124130519Ssam vdpoll(vm, t)
124230519Ssam 	register struct vba_ctlr *vm;
124325925Ssam 	register int t;
124425925Ssam {
124530519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
124630519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
124725925Ssam 
124825925Ssam 	t *= 1000;
124930370Skarels 	for (;;) {
125030519Ssam 		uncache(&vd->vd_dcb.operrsta);
125130519Ssam 		if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT))
125230370Skarels 			break;
125325925Ssam 		if (--t <= 0) {
125430519Ssam 			printf("vd%d: controller timeout", vm->um_ctlr);
125530519Ssam 			VDABORT(vdaddr, vd->vd_type);
125625925Ssam 			return (0);
125725925Ssam 		}
125830370Skarels 		DELAY(1000);
125925925Ssam 	}
126030519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
126130519Ssam 		do {
126225925Ssam 			DELAY(50);
126330519Ssam 			uncache(&vdaddr->vdcsr);
126430519Ssam 		} while (vdaddr->vdcsr & CS_GO);
126532211Skarels 	 	DELAY(300);
126632211Skarels 		uncache(&vd->vd_dcb.err_code);
126725925Ssam 	}
126825925Ssam 	DELAY(200);
126930519Ssam 	uncache(&vd->vd_dcb.operrsta);
127025925Ssam 	return (1);
127125925Ssam }
127225925Ssam 
127330519Ssam #ifdef COMPAT_42
127430519Ssam struct	vdst {
127530519Ssam 	int	nsec;		/* sectors/track */
127630519Ssam 	int	ntrack;		/* tracks/cylinder */
127730519Ssam 	int	ncyl;		/* cylinders */
127832211Skarels 	int	secsize;	/* sector size */
127930519Ssam 	char	*name;		/* type name */
128030519Ssam 	struct {
128130519Ssam 		int	off;	/* partition offset in sectors */
128230519Ssam 		int	size;	/* partition size in sectors */
128330573Skarels 	} parts[8];
128430519Ssam } vdst[] = {
128532211Skarels 	{ 66, 23, 850, 512, "NEC 800",
128632211Skarels 		{0,	 1290300},	/* a cyl   0 - 849 */
128732211Skarels 	},
1288*34737Sbostic 	{ 64, 20, 842, 512, "2361a",
1289*34737Sbostic 		{0,	 61440},	/* a cyl   0 - 47 */
1290*34737Sbostic 		{61440,	 67840},	/* b cyl  48 - 100 */
1291*34737Sbostic 		{129280, 942080}, 	/* c cyl 101 - 836 */
1292*34737Sbostic 		{0,      1071360}, 	/* d cyl   0 - 836 */
1293*34737Sbostic 		{449280, 311040},	/* e cyl 351 - 593 */
1294*34737Sbostic 		{760320, 311040}, 	/* f cyl 594 - 836 */
1295*34737Sbostic 		{449280, 622080},	/* g cyl 351 - 836 */
1296*34737Sbostic 		{129280, 320000}	/* h cyl 101 - 350 */
1297*34737Sbostic 	},
129832211Skarels 	{ 48, 24, 711, 512, "xsd",
129931039Skarels 		{0,	 61056},	/* a cyl   0 - 52 */
130031039Skarels 		{61056,	 61056},	/* b cyl  53 - 105 */
130131039Skarels 		{122112, 691200}, 	/* c cyl 106 - 705 */
130231039Skarels 		{237312, 576000}, 	/* d cyl 206 - 705 */
130331039Skarels 		{352512, 460800},	/* e cyl 306 - 705 */
130431039Skarels 		{467712, 345600}, 	/* f cyl 406 - 705 */
130531039Skarels 		{582912, 230400},	/* g cyl 506 - 705 */
130631039Skarels 		{698112, 115200}	/* h cyl 606 - 705 */
130730573Skarels 	},
130832211Skarels 	{ 44, 20, 842, 512, "eagle",
130930601Skarels 		{0,	 52800},	/* egl0a cyl   0 - 59 */
131030601Skarels 		{52800,	 66000},	/* egl0b cyl  60 - 134 */
131130601Skarels 		{118800, 617760}, 	/* egl0c cyl 135 - 836 */
131230756Skarels 		{736560, 4400}, 	/* egl0d cyl 837 - 841 */
131331039Skarels 		{0, 	 736560},	/* egl0e cyl   0 - 836 */
131431039Skarels 		{0, 	 740960}, 	/* egl0f cyl   0 - 841 */
131530601Skarels 		{118800, 310640},	/* egl0g cyl 135 - 487 */
131630601Skarels 		{429440, 307120}	/* egl0h cyl 488 - 836 */
131730573Skarels 	},
131832211Skarels 	{ 64, 10, 823, 512, "fuj",
131931039Skarels 		{0,	 38400},	/* fuj0a cyl   0 - 59 */
132031039Skarels 		{38400,	 48000},	/* fuj0b cyl  60 - 134 */
132131039Skarels 		{86400,	 437120}, 	/* fuj0c cyl 135 - 817 */
132231039Skarels 		{159360, 364160}, 	/* fuj0d cyl 249 - 817 */
132331039Skarels 		{232320, 291200},	/* fuj0e cyl 363 - 817 */
132431039Skarels 		{305280, 218240}, 	/* fuj0f cyl 477 - 817 */
132531039Skarels 		{378240, 145280},	/* fuj0g cyl 591 - 817 */
132631039Skarels 		{451200, 72320}		/* fug0h cyl 705 - 817 */
132730573Skarels 	},
132832211Skarels 	{ 32, 24, 711, 512, "xfd",
132930756Skarels 		{ 0,	 40704 },	/* a cyl   0 - 52 */
133030756Skarels 		{ 40704, 40704 },	/* b cyl  53 - 105 */
133130756Skarels 		{ 81408, 460800 },	/* c cyl 106 - 705 */
133230756Skarels 		{ 0,	 81408 },	/* d cyl 709 - 710 (a & b) */
133330756Skarels 		{ 0,	 542208 },	/* e cyl   0 - 705 */
133430756Skarels 		{ 40704, 501504 },	/* f cyl  53 - 705 (b & c) */
133530756Skarels 		{ 81408, 230400 },	/* g cyl 106 - 405 (1/2 of c) */
133630756Skarels 		{ 311808,230400 }	/* h cyl 406 - 705 (1/2 of c) */
133730573Skarels 	},
133832211Skarels 	{ 32, 19, 823, 512, "smd",
133931039Skarels 		{0,	 40128},	/* a cyl   0-65 */
134031039Skarels 		{40128,  27360},	/* b cyl  66-110 */
134131039Skarels 		{67488,  429856},	/* c cyl 111-817 */
134231039Skarels 		{139232, 358112},	/* d cyl 229 - 817 */
134331039Skarels 		{210976, 286368},	/* e cyl 347 - 817 */
134431039Skarels 		{282720, 214624},	/* f cyl 465 - 817 */
134531039Skarels 		{354464, 142880},	/* g cyl 583 - 817 */
134631039Skarels 		{426208, 71136}		/* h cyl 701 - 817 */
134730573Skarels 	},
134832211Skarels 	{ 18, 15, 1224, 1024, "mxd",
134932211Skarels 		{0,	 21600},	/* a cyl   0-79 */
135032211Skarels 		{21600,  22410},	/* b cyl  80-162 */
135132211Skarels 		{44010,  285120},	/* c cyl 163-1217 */
135232211Skarels #ifdef notyet
135332211Skarels 		{x, 237600},	/* d cyl y - 1217 */
135432211Skarels 		{x, 190080},	/* e cyl y - 1217 */
135532211Skarels 		{x, 142560},	/* f cyl y - 1217 */
135632211Skarels 		{x, 95040},	/* g cyl y - 1217 */
135732211Skarels 		{x, 47520}		/* h cyl 701 - 817 */
135832211Skarels #endif
135932211Skarels 	},
136032211Skarels 	{ 32, 10, 823, 512, "fsd",
136130756Skarels 		{0,	 19200},	/* a cyl   0 -  59 */
136230756Skarels 		{19200,	 24000},	/* b cyl  60 - 134 */
136330756Skarels 		{43200,	 218560},	/* c cyl 135 - 817 */
136430573Skarels 	}
136530519Ssam };
136630519Ssam #define	NVDST	(sizeof (vdst) / sizeof (vdst[0]))
136730519Ssam 
136825675Ssam /*
136930519Ssam  * Construct a label for an unlabeled pack.  We
137030519Ssam  * deduce the drive type by reading from the last
137130519Ssam  * track on successively smaller drives until we
137230519Ssam  * don't get an error.
137325675Ssam  */
137430519Ssam vdmaptype(vi, lp)
137530519Ssam 	register struct vba_device *vi;
137630519Ssam 	register struct disklabel *lp;
137725675Ssam {
137830519Ssam 	register struct vdsoftc *vd;
137930519Ssam 	register struct vdst *p;
138032211Skarels 	struct vba_ctlr *vm = vi->ui_mi;
138130519Ssam 	int i;
138225675Ssam 
138330519Ssam 	vd = &vdsoftc[vi->ui_ctlr];
138430519Ssam 	for (p = vdst; p < &vdst[NVDST]; p++) {
138530519Ssam 		if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32)
138630519Ssam 			continue;
138730519Ssam 		lp->d_nsectors = p->nsec;
138830519Ssam 		lp->d_ntracks = p->ntrack;
138930519Ssam 		lp->d_ncylinders = p->ncyl;
139032211Skarels 		lp->d_secsize = p->secsize;
139130519Ssam 		if (!vdreset_drive(vi))
139230519Ssam 			return (0);
139330519Ssam 		vd->vd_dcb.opcode = VDOP_RD;
139430519Ssam 		vd->vd_dcb.intflg = DCBINT_NONE;
139530519Ssam 		vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
139632211Skarels 		vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect;
139730756Skarels 		vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
139830601Skarels 		vd->vd_dcb.trail.rwtrail.memadr =
139930601Skarels 		    vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf);
140032211Skarels 		vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short);
140130519Ssam 		vd->vd_dcb.operrsta = 0;
140230519Ssam 		vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2;
140330519Ssam 		vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1;
140430519Ssam 		vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1;
140530519Ssam 		vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
140630519Ssam 		vd->vd_mdcb.mdcb_status = 0;
140730519Ssam 		VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
140830519Ssam 		if (!vdpoll(vm, 60))
140930519Ssam 			printf(" during probe\n");
141030519Ssam 		if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0)
141130519Ssam 			break;
141224004Ssam 	}
141332211Skarels 	if (p >= &vdst[NVDST])
141430519Ssam 		return (0);
141532211Skarels 
141630573Skarels 	for (i = 0; i < 8; i++) {
141730519Ssam 		lp->d_partitions[i].p_offset = p->parts[i].off;
141830519Ssam 		lp->d_partitions[i].p_size = p->parts[i].size;
141930519Ssam 	}
142030573Skarels 	lp->d_npartitions = 8;
142130519Ssam 	lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
142230519Ssam 	lp->d_rpm = 3600;
142330519Ssam 	bcopy(p->name, lp->d_typename, 4);
142430519Ssam 	return (1);
142524004Ssam }
142630519Ssam #endif COMPAT_42
142724004Ssam #endif
1428