xref: /csrg-svn/sys/tahoe/vba/vd.c (revision 30601)
1*30601Skarels /*	vd.c	1.17	87/03/10	*/
224004Ssam 
329564Ssam #include "dk.h"
424004Ssam #if NVD > 0
524004Ssam /*
630519Ssam  * Versabus VDDC/SMDE driver.
725675Ssam  */
825675Ssam #include "param.h"
925675Ssam #include "buf.h"
1025675Ssam #include "cmap.h"
1125675Ssam #include "conf.h"
1225675Ssam #include "dir.h"
1329564Ssam #include "dkstat.h"
1430519Ssam #include "disklabel.h"
1525675Ssam #include "map.h"
1630519Ssam #include "file.h"
1725675Ssam #include "systm.h"
1825675Ssam #include "user.h"
1925675Ssam #include "vmmac.h"
2025675Ssam #include "proc.h"
2125675Ssam #include "uio.h"
2230370Skarels #include "syslog.h"
2330370Skarels #include "kernel.h"
2430519Ssam #include "ioctl.h"
2524004Ssam 
2629951Skarels #include "../tahoe/cpu.h"
2729951Skarels #include "../tahoe/mtpr.h"
2829951Skarels #include "../tahoe/pte.h"
2929951Skarels 
3025675Ssam #include "../tahoevba/vbavar.h"
3125928Ssam #include "../tahoevba/vdreg.h"
3224004Ssam 
3330519Ssam #define	COMPAT_42
3430519Ssam 
35*30601Skarels #define	VDMAXIO		(VDMAXPAGES * NBPG)
3624004Ssam 
3730519Ssam #define vdunit(dev)	(minor(dev) >> 3)
3830519Ssam #define vdpart(dev)	(minor(dev) & 0x07)
3930519Ssam #define	vdminor(unit,part)	(((unit) << 3) | (part))
4024004Ssam 
4124004Ssam struct	vba_ctlr *vdminfo[NVD];
4229564Ssam struct  vba_device *vddinfo[NDK];
4325675Ssam int	vdprobe(), vdslave(), vdattach(), vddgo();
4430519Ssam long	vdaddr[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 };
4525675Ssam struct	vba_driver vddriver =
4630519Ssam   { vdprobe, vdslave, vdattach, vddgo, vdaddr, "dk", vddinfo, "vd", vdminfo };
4724004Ssam 
4824004Ssam /*
4930519Ssam  * Per-controller state.
5030519Ssam  */
5130519Ssam struct vdsoftc {
5230519Ssam 	u_short	vd_flags;
5330519Ssam #define	VD_INIT		0x1	/* controller initialized */
5430519Ssam #define	VD_STARTED	0x2	/* start command issued */
5530519Ssam #define	VD_DOSEEKS	0x4	/* should overlap seeks */
5630519Ssam 	u_short	vd_type;	/* controller type */
5730519Ssam 	u_short	vd_wticks;	/* timeout */
5830519Ssam 	struct	mdcb vd_mdcb;	/* master command block */
5930519Ssam 	u_long	vd_mdcbphys;	/* physical address of vd_mdcb */
6030519Ssam 	struct	dcb vd_dcb;	/* i/o command block */
6130519Ssam 	u_long	vd_dcbphys;	/* physical address of vd_dcb */
62*30601Skarels 	struct	vb_buf vd_rbuf;	/* vba resources */
6330519Ssam } vdsoftc[NVD];
6430519Ssam 
6530519Ssam /*
6625675Ssam  * Per-drive state.
6725675Ssam  */
6830519Ssam struct	dksoftc {
6930519Ssam 	u_short	dk_state;	/* open fsm */
7030519Ssam 	u_short	dk_openpart;	/* units open on this drive */
7130519Ssam 	u_int	dk_curcyl;	/* last selected cylinder */
7230519Ssam 	struct	dcb dk_dcb;	/* seek command block */
7330519Ssam 	u_long	dk_dcbphys;	/* physical address of dk_dcb */
7430519Ssam } dksoftc[NDK];
7524004Ssam 
7624004Ssam /*
7730519Ssam  * Drive states.  Used during steps of open/initialization.
7830519Ssam  * States < OPEN (> 0) are transient, during an open operation.
7930519Ssam  * OPENRAW is used for unabeled disks, to allow format operations.
8025675Ssam  */
8130519Ssam #define	CLOSED		0		/* disk is closed */
8230519Ssam #define	WANTOPEN	1		/* open requested, not started */
8330519Ssam #define	WANTOPENRAW	2		/* open requested, no label */
8430519Ssam #define	RDLABEL		3		/* reading pack label */
8530519Ssam #define	OPEN		4		/* intialized and ready */
8630519Ssam #define	OPENRAW		5		/* open, no label */
8724004Ssam 
8830519Ssam struct	buf rdkbuf[NDK];	/* raw i/o buffer headers */
8930519Ssam struct	buf dkutab[NDK];	/* i/o queue headers */
9030519Ssam struct	disklabel dklabel[NDK];	/* pack labels */
9124004Ssam 
9230519Ssam #define b_cylin	b_resid
9330574Skarels #define	b_track	b_error		/* used for seek commands */
9430574Skarels #define	b_seekf	b_forw		/* second queue on um_tab */
9530574Skarels #define	b_seekl	b_back		/* second queue on um_tab */
9630519Ssam 
9730519Ssam int	vdwstart, vdwatch();
9830519Ssam 
9924004Ssam /*
10025675Ssam  * See if the controller is really there; if so, initialize it.
10125675Ssam  */
10225857Ssam vdprobe(reg, vm)
10325857Ssam 	caddr_t reg;
10425857Ssam 	struct vba_ctlr *vm;
10525675Ssam {
10625857Ssam 	register br, cvec;		/* must be r12, r11 */
10730519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)reg;
10830519Ssam 	struct vdsoftc *vd;
10930573Skarels 	int s;
11025857Ssam 
11130370Skarels #ifdef lint
11230370Skarels 	br = 0; cvec = br; br = cvec;
11330370Skarels 	vdintr(0);
11430370Skarels #endif
11525857Ssam 	if (badaddr((caddr_t)reg, 2))
11625675Ssam 		return (0);
11730519Ssam 	vd = &vdsoftc[vm->um_ctlr];
11830519Ssam 	vdaddr->vdreset = 0xffffffff;
11925675Ssam 	DELAY(1000000);
12030519Ssam 	if (vdaddr->vdreset != (unsigned)0xffffffff) {
12130519Ssam 		vd->vd_type = VDTYPE_VDDC;
12230519Ssam 		vd->vd_flags &= ~VD_DOSEEKS;
12325675Ssam 		DELAY(1000000);
12425675Ssam 	} else {
12530519Ssam 		vd->vd_type = VDTYPE_SMDE;
12630519Ssam 		vd->vd_flags |= VD_DOSEEKS;
12730519Ssam 		vdaddr->vdrstclr = 0;
12825675Ssam 		DELAY(3000000);
12930519Ssam 		vdaddr->vdcsr = 0;
13030519Ssam 		vdaddr->vdtcf_mdcb = AM_ENPDA;
13130519Ssam 		vdaddr->vdtcf_dcb = AM_ENPDA;
13230519Ssam 		vdaddr->vdtcf_trail = AM_ENPDA;
13330519Ssam 		vdaddr->vdtcf_data = AM_ENPDA;
13430519Ssam 		vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS |
13529921Skarels 		    XMD_32BIT | BSZ_16WRD |
13625925Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
13725675Ssam 	}
13830519Ssam 	vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb);
13930519Ssam 	vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb);
14030519Ssam 	vm->um_addr = reg;		/* XXX */
14130573Skarels 	s = spl7();
14230519Ssam 	if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) {
14330519Ssam 		printf("vd%d: %s cmd failed\n", vm->um_ctlr,
14430519Ssam 		    vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
14530573Skarels 		splx(s);
14630519Ssam 		return (0);
14730519Ssam 	}
14830573Skarels 	splx(s);
14925925Ssam 	/*
15025950Ssam 	 * Allocate page tables and i/o buffer.
15125925Ssam 	 */
152*30601Skarels 	vbainit(&vd->vd_rbuf, VDMAXIO,
153*30601Skarels 	    vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT);
15425857Ssam 	br = 0x17, cvec = 0xe0 + vm->um_ctlr;	/* XXX */
15530519Ssam 	return (sizeof (struct vddevice));
15625675Ssam }
15724004Ssam 
15824004Ssam /*
15930519Ssam  * See if a drive is really there.
16030519Ssam  *
16130519Ssam  * Can't read pack label here as various data structures
16230519Ssam  * aren't setup for doing a read in a straightforward
16330519Ssam  * manner.  Instead just probe for the drive and leave
16430519Ssam  * the pack label stuff to the attach routine.
16525675Ssam  */
16625675Ssam vdslave(vi, addr)
16725675Ssam 	register struct vba_device *vi;
16830519Ssam 	struct vddevice *vdaddr;
16925675Ssam {
17030519Ssam 	register struct disklabel *lp = &dklabel[vi->ui_unit];
17130519Ssam 	struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
17224004Ssam 
17330519Ssam 	if ((vd->vd_flags&VD_INIT) == 0) {
17425925Ssam 		printf("vd%d: %s controller\n", vi->ui_ctlr,
17530519Ssam 		    vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE");
17630519Ssam 		vd->vd_flags |= VD_INIT;
17725675Ssam 	}
17830519Ssam 
17925675Ssam 	/*
18030519Ssam 	 * Initialize label enough to do a reset on
18130519Ssam 	 * the drive.  The remainder of the default
18230519Ssam 	 * label values will be filled in in vdinit
18330519Ssam 	 * at attach time.
18425675Ssam 	 */
18530519Ssam 	lp->d_secsize = DEV_BSIZE / 2;		/* XXX */
186*30601Skarels if (vi->ui_ctlr)
187*30601Skarels lp->d_nsectors = 48;
188*30601Skarels else
18930519Ssam 	lp->d_nsectors = 32;
19030519Ssam 	lp->d_ntracks = 24;
19130519Ssam 	lp->d_ncylinders = 711;
19230519Ssam 	lp->d_secpercyl = 32*24;
19330519Ssam 	return (vdreset_drive(vi));
19424004Ssam }
19524004Ssam 
19630519Ssam vdattach(vi)
19730519Ssam 	register struct vba_device *vi;
19824004Ssam {
19930519Ssam 	register int unit = vi->ui_unit;
20030519Ssam 	register struct dksoftc *dk = &dksoftc[unit];
20130519Ssam 	register struct disklabel *lp;
20225675Ssam 
20330519Ssam 	/*
20430519Ssam 	 * Initialize invariant portion of
20530519Ssam 	 * dcb used for overlapped seeks.
20630519Ssam 	 */
20730519Ssam 	dk->dk_dcb.opcode = VDOP_SEEK;
20830519Ssam 	dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA;
20930519Ssam 	dk->dk_dcb.devselect = vi->ui_slave;
21030519Ssam 	dk->dk_dcb.trailcnt = sizeof (trseek) / sizeof (long);
21130519Ssam 	dk->dk_dcb.trail.sktrail.skaddr.sector = 0;
21230519Ssam 	dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb);
213*30601Skarels 	/*
214*30601Skarels 	 * Try to initialize device and read pack label.
215*30601Skarels 	 */
216*30601Skarels 	if (vdinit(vdminor(unit, 0), 0) != 0) {
217*30601Skarels 		printf(": unknown drive type");
218*30601Skarels 		return;
219*30601Skarels 	}
22030519Ssam 	lp = &dklabel[unit];
22130519Ssam 	printf(": %s <ntrak %d, ncyl %d, nsec %d>",
22230519Ssam 	    lp->d_typename, lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors);
22330519Ssam 	/*
22430519Ssam 	 * (60 / rpm) / (sectors per track * (bytes per sector / 2))
22530519Ssam 	 */
22630519Ssam 	if (vi->ui_dk >= 0)
22730519Ssam 		dk_mspw[vi->ui_dk] = 120.0 /
22830519Ssam 		    (lp->d_rpm * lp->d_nsectors * lp->d_secsize);
22930519Ssam #ifdef notyet
23030573Skarels 	addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp);
23130519Ssam #endif
23224004Ssam }
23324004Ssam 
23430519Ssam /*ARGSUSED*/
23530519Ssam vdopen(dev, flags)
23630519Ssam 	dev_t dev;
23730519Ssam 	int flags;
23824004Ssam {
23930519Ssam 	register unit = vdunit(dev);
24030519Ssam 	register struct disklabel *lp;
24130519Ssam 	register struct dksoftc *dk;
24230519Ssam 	register struct partition *pp;
24330519Ssam 	struct vba_device *vi;
24430519Ssam 	int s, error, part = vdpart(dev);
24530519Ssam 	daddr_t start, end;
24624004Ssam 
24730519Ssam 	if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
24830519Ssam 		return (ENXIO);
24930519Ssam 	lp = &dklabel[unit];
25030519Ssam 	dk = &dksoftc[unit];
25130519Ssam 
25230519Ssam 	s = spl7();
25330519Ssam 	while (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
25430519Ssam 	    dk->dk_state != CLOSED)
25530519Ssam 		sleep((caddr_t)dk, PZERO+1);
25630519Ssam 	splx(s);
25730519Ssam 	if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
25830519Ssam 		if (error = vdinit(dev, flags))
25930519Ssam 			return (error);
26030573Skarels 
26130573Skarels 	if (vdwstart == 0) {
26230573Skarels 		timeout(vdwatch, (caddr_t)0, hz);
26330573Skarels 		vdwstart++;
26430573Skarels 	}
26530519Ssam 	/*
26630519Ssam 	 * Warn if a partion is opened
26730519Ssam 	 * that overlaps another partition which is open
26830519Ssam 	 * unless one is the "raw" partition (whole disk).
26930519Ssam 	 */
27030519Ssam #define	RAWPART		2		/* 'c' partition */	/* XXX */
27130519Ssam 	if ((dk->dk_openpart & (1 << part)) == 0 &&
27230519Ssam 	    part != RAWPART) {
27330519Ssam 		pp = &lp->d_partitions[part];
27430519Ssam 		start = pp->p_offset;
27530519Ssam 		end = pp->p_offset + pp->p_size;
27630519Ssam 		for (pp = lp->d_partitions;
27730519Ssam 		     pp < &lp->d_partitions[lp->d_npartitions]; pp++) {
27830519Ssam 			if (pp->p_offset + pp->p_size <= start ||
27930519Ssam 			    pp->p_offset >= end)
28030519Ssam 				continue;
28130519Ssam 			if (pp - lp->d_partitions == RAWPART)
28230519Ssam 				continue;
28330519Ssam 			if (dk->dk_openpart & (1 << (pp - lp->d_partitions)))
28430519Ssam 				log(LOG_WARNING,
28530519Ssam 				    "dk%d%c: overlaps open partition (%c)\n",
28630519Ssam 				    unit, part + 'a',
28730519Ssam 				    pp - lp->d_partitions + 'a');
28830519Ssam 		}
28924004Ssam 	}
29030519Ssam 	if (part >= lp->d_npartitions)
29130519Ssam 		return (ENXIO);
29230519Ssam 	dk->dk_openpart |= 1 << part;
29330519Ssam 	return (0);
29425675Ssam }
29524004Ssam 
29630519Ssam vdclose(dev, flags)
29730519Ssam 	dev_t dev;
29830519Ssam 	int flags;
29924004Ssam {
30030519Ssam 	register int unit = vdunit(dev);
30130519Ssam 	register struct dksoftc *dk = &dksoftc[unit];
302*30601Skarels 	int part = vdpart(dev);
30324004Ssam 
30430519Ssam 	/*
30530519Ssam 	 * Should wait for i/o to complete on this partition
30630519Ssam 	 * even if others are open, but wait for work on blkflush().
30730519Ssam 	 */
30830519Ssam 	if (dk->dk_openpart == 0) {
30930573Skarels 		int s = spl7();
31030573Skarels 		while (dkutab[unit].b_actf)
31130573Skarels 			sleep((caddr_t)dk, PZERO-1);
31230519Ssam 		splx(s);
31330519Ssam 		dk->dk_state = CLOSED;
31424004Ssam 	}
31525675Ssam }
31624004Ssam 
317*30601Skarels /*
318*30601Skarels  * Read pack label.
319*30601Skarels  */
32030519Ssam vdinit(dev, flags)
32130519Ssam 	dev_t dev;
32230519Ssam 	int flags;
32325675Ssam {
32430519Ssam 	register struct buf *bp = NULL;
32530519Ssam 	register struct disklabel *lp;
32630519Ssam 	register struct dksoftc *dk;
32730519Ssam 	struct vba_device *vi;
32830519Ssam 	struct disklabel *dlp;
32930519Ssam 	int unit = vdunit(dev), error = 0;
330*30601Skarels 	char *msg = "no disk label";
33130519Ssam 	extern int cold;
33225675Ssam 
33330519Ssam 	dk = &dksoftc[unit];
33430519Ssam 	if (flags & O_NDELAY) {
33530519Ssam 		dk->dk_state = OPENRAW;
33630519Ssam 		goto done;
33730519Ssam 	}
33830519Ssam 
33930519Ssam 	/*
34030519Ssam 	 * Initialize portion of the label
34130519Ssam 	 * not set up in the slave routine.
34230519Ssam 	 */
34330519Ssam 	dk->dk_state = RDLABEL;
34430519Ssam 	lp = &dklabel[unit];
34530519Ssam 	lp->d_secperunit = 0x1fffffff;
34630519Ssam 	lp->d_npartitions = 1;
34730519Ssam 	lp->d_partitions[0].p_size = 0x1fffffff;
34830519Ssam 	lp->d_partitions[0].p_offset = 0;
34930519Ssam 
35030519Ssam 	bp = geteblk(DEV_BSIZE);		/* max sector size */
35130519Ssam 	bp->b_dev = dev;
35230519Ssam 	bp->b_blkno = LABELSECTOR;
35330519Ssam 	bp->b_bcount = DEV_BSIZE;
35430519Ssam 	bp->b_flags = B_BUSY | B_READ;
35530519Ssam 	bp->b_cylin = LABELSECTOR / lp->d_secpercyl;
35630519Ssam 	vdstrategy(bp);
35730519Ssam 	biowait(bp);
35830519Ssam 	if (bp->b_flags & B_ERROR) {
35930519Ssam 		error = u.u_error;		/* XXX */
36030519Ssam 		u.u_error = 0;
36130519Ssam 		dk->dk_state = CLOSED;
36230519Ssam 		goto done;
36330519Ssam 	}
36430519Ssam 	vi = vddinfo[unit];
36530519Ssam 	dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET);
36630519Ssam 	if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
36730519Ssam 	    dkcksum(dlp) == 0) {
36830519Ssam 		*lp = *dlp;
36930519Ssam 		/*
37030519Ssam 		 * Now that we have the label, configure
37130519Ssam 		 * the correct drive parameters.
37230519Ssam 		 */
37330519Ssam 		if (!vdreset_drive(vi))
37430519Ssam 			dk->dk_state = CLOSED;
37530519Ssam 		else
37630519Ssam 			dk->dk_state = OPEN;
37725675Ssam 	} else {
378*30601Skarels 		if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC)
379*30601Skarels 			msg = "disk label corrupted";
38030519Ssam 		if (cold)
381*30601Skarels 			printf(": %s", msg);
38230519Ssam 		else
383*30601Skarels 			log(LOG_ERR, "dk%d: %s\n", vi->ui_unit, msg);
384*30601Skarels printf("data %x %x %x, magic %x\n", bp->b_un.b_words[0], bp->b_un.b_words[1], bp->b_un.b_words[2], dlp->d_magic);
38530519Ssam #ifdef COMPAT_42
38630519Ssam 		if (!vdmaptype(vi, lp)) {
38730519Ssam 			error = ENXIO;
38830519Ssam 			dk->dk_state = CLOSED;
38930519Ssam 		} else
39030519Ssam 			dk->dk_state = OPEN;
39130519Ssam #else
39230519Ssam 		dk->dk_state = OPENRAW;
39330519Ssam #endif
39425675Ssam 	}
39530519Ssam done:
39630519Ssam 	if (bp) {
39730519Ssam 		bp->b_flags = B_INVAL | B_AGE;
39830519Ssam 		brelse(bp);
39930519Ssam 	}
40030519Ssam 	wakeup((caddr_t)dk);
40130519Ssam 	return (error);
40224004Ssam }
40324004Ssam 
40425675Ssam /*ARGSUSED*/
40530519Ssam vddgo(vm)
40630519Ssam 	struct vba_device *vm;
40724004Ssam {
40824004Ssam 
40924004Ssam }
41024004Ssam 
41124004Ssam vdstrategy(bp)
41225675Ssam 	register struct buf *bp;
41324004Ssam {
41430519Ssam 	register struct vba_device *vi;
41530519Ssam 	register struct disklabel *lp;
41630519Ssam 	register struct dksoftc *dk;
41730519Ssam 	register int unit;
41830573Skarels 	register daddr_t sn;
41930519Ssam 	struct buf *dp;
42030573Skarels 	daddr_t sz, maxsz;
42130519Ssam 	int part, s;
42224004Ssam 
42330519Ssam 	unit = vdunit(bp->b_dev);
42430519Ssam 	if (unit > NDK) {
42529954Skarels 		bp->b_error = ENXIO;
42625675Ssam 		goto bad;
42729954Skarels 	}
42830519Ssam 	vi = vddinfo[unit];
42930519Ssam 	lp = &dklabel[unit];
43030519Ssam 	if (vi == 0 || vi->ui_alive == 0) {
43130519Ssam 		bp->b_error = ENXIO;
43230519Ssam 		goto bad;
43330519Ssam 	}
434*30601Skarels 	sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
43530519Ssam 	dk = &dksoftc[unit];
43630519Ssam 	if (dk->dk_state < OPEN)
43730519Ssam 		goto q;
43830519Ssam 	part = vdpart(bp->b_dev);
43930519Ssam 	if ((dk->dk_openpart & (1 << part)) == 0) {
44030519Ssam 		bp->b_error = ENODEV;
44130519Ssam 		goto bad;
44230519Ssam 	}
44330519Ssam 	maxsz = lp->d_partitions[part].p_size;
44430573Skarels 	sn = bp->b_blkno;
44530519Ssam 	if (sn < 0 || sn + sz > maxsz) {
44630519Ssam 		if (sn == maxsz) {
44729954Skarels 			bp->b_resid = bp->b_bcount;
44829954Skarels 			goto done;
44929954Skarels 		}
45030573Skarels 		sz = maxsz - bp->b_blkno;
45130573Skarels 		if (sz <= 0) {
45230573Skarels 			bp->b_error = EINVAL;
45330573Skarels 			goto bad;
45430573Skarels 		}
45530573Skarels 		bp->b_bcount = sz * lp->d_secsize;
45625675Ssam 	}
45730519Ssam 	bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl;
45830519Ssam q:
45925675Ssam 	s = spl7();
46030519Ssam 	dp = &dkutab[vi->ui_unit];
46130519Ssam 	disksort(dp, bp);
46230519Ssam 	if (!dp->b_active) {
46330519Ssam 		(void) vdustart(vi);
46430573Skarels 		if (!vi->ui_mi->um_tab.b_active)
46530519Ssam 			vdstart(vi->ui_mi);
46624004Ssam 	}
46730519Ssam 	splx(s);
46824004Ssam 	return;
46925675Ssam bad:
47029954Skarels 	bp->b_flags |= B_ERROR;
47129954Skarels done:
47230519Ssam 	biodone(bp);
47330519Ssam 	return;
47424004Ssam }
47524004Ssam 
47630519Ssam vdustart(vi)
47730519Ssam 	register struct vba_device *vi;
47824004Ssam {
47930519Ssam 	register struct buf *bp, *dp;
48030519Ssam 	register struct vba_ctlr *vm;
48130519Ssam 	register int unit = vi->ui_unit;
48230519Ssam 	register struct dksoftc *dk;
48330519Ssam 	register struct vdsoftc *vd;
48430519Ssam 	struct disklabel *lp;
48524004Ssam 
48630519Ssam 	dp = &dkutab[unit];
48730519Ssam 	/*
48830519Ssam 	 * If queue empty, nothing to do.
48930519Ssam 	 */
49030519Ssam 	if ((bp = dp->b_actf) == NULL)
49130519Ssam 		return;
49230519Ssam 	/*
49330574Skarels 	 * If drive is off-cylinder and controller supports seeks,
49430574Skarels 	 * place drive on seek queue for controller.
49530574Skarels 	 * Otherwise, place on transfer queue.
49630519Ssam 	 */
49730519Ssam 	vd = &vdsoftc[vi->ui_ctlr];
49830519Ssam 	dk = &dksoftc[unit];
49930574Skarels 	vm = vi->ui_mi;
50030519Ssam 	if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) {
50130519Ssam 		lp = &dklabel[unit];
50230574Skarels 		bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors;
50330574Skarels 		if (vm->um_tab.b_seekf == NULL)
50430574Skarels 			vm->um_tab.b_seekf = dp;
50530574Skarels 		else
50630574Skarels 			vm->um_tab.b_seekl->b_forw = dp;
50730574Skarels 		vm->um_tab.b_seekl = dp;
50830574Skarels 	} else {
50930574Skarels 		if (vm->um_tab.b_actf == NULL)
51030574Skarels 			vm->um_tab.b_actf = dp;
51130574Skarels 		else
51230574Skarels 			vm->um_tab.b_actl->b_forw = dp;
51330574Skarels 		vm->um_tab.b_actl = dp;
51430519Ssam 	}
51530573Skarels 	dp->b_forw = NULL;
51630573Skarels 	dp->b_active++;
51725675Ssam }
51825675Ssam 
51925675Ssam /*
52030519Ssam  * Start next transfer on a controller.
52130574Skarels  * There are two queues of drives, the first on-cylinder
52230574Skarels  * and the second off-cylinder from their next transfers.
52330574Skarels  * Perform the first transfer for the first drive on the on-cylinder
52430574Skarels  * queue, if any, otherwise the first transfer for the first drive
52530574Skarels  * on the second queue.  Initiate seeks on remaining drives on the
52630574Skarels  * off-cylinder queue, then move them all to the on-cylinder queue.
52725675Ssam  */
52830519Ssam vdstart(vm)
52930519Ssam 	register struct vba_ctlr *vm;
53025675Ssam {
53125675Ssam 	register struct buf *bp;
53230519Ssam 	register struct vba_device *vi;
53330519Ssam 	register struct vdsoftc *vd;
53430519Ssam 	register struct dksoftc *dk;
53530519Ssam 	register struct disklabel *lp;
53630519Ssam 	register int slave;
53730519Ssam 	register struct dcb **dcbp;
53830519Ssam 	struct mdcb *mdcb;
53930519Ssam 	struct buf *dp;
54030519Ssam 	int sn, tn;
54125675Ssam 
54230519Ssam loop:
54330519Ssam 	/*
54430519Ssam 	 * Pull a request off the controller queue.
54530519Ssam 	 */
54630574Skarels 	if ((dp = vm->um_tab.b_actf) == NULL &&
54730574Skarels 	    (dp = vm->um_tab.b_seekf) == NULL)
54830519Ssam 		return;
54930519Ssam 	if ((bp = dp->b_actf) == NULL) {
550*30601Skarels 		if (dp == vm->um_tab.b_actf)
551*30601Skarels 			vm->um_tab.b_actf = dp->b_forw;
552*30601Skarels 		else
553*30601Skarels 			vm->um_tab.b_seekf = dp->b_forw;
55430519Ssam 		goto loop;
55530519Ssam 	}
55625675Ssam 
55724004Ssam 	/*
55830519Ssam 	 * Mark controller busy, and determine
55930519Ssam 	 * destination of this request.
56024004Ssam 	 */
56130519Ssam 	vm->um_tab.b_active++;
56230519Ssam 	vi = vddinfo[vdunit(bp->b_dev)];
56330519Ssam 	dk = &dksoftc[vi->ui_unit];
56430573Skarels 	sn = bp->b_blkno;
56530519Ssam 	lp = &dklabel[vi->ui_unit];
56630519Ssam 	sn %= lp->d_secpercyl;
56730519Ssam 	tn = sn / lp->d_nsectors;
56830519Ssam 	sn %= lp->d_nsectors;
56930519Ssam 
57030519Ssam 	/*
57130519Ssam 	 * Construct dcb for read/write command.
57230519Ssam 	 */
57330519Ssam 	vd = &vdsoftc[vm->um_ctlr];
57430519Ssam 	slave = vi->ui_slave;
57530519Ssam 	vd->vd_dcb.opcode = (bp->b_flags & B_READ) ? VDOP_RD : VDOP_WD;
57630519Ssam 	vd->vd_dcb.intflg = DCBINT_DONE;
57730519Ssam 	vd->vd_dcb.devselect = slave;
57830519Ssam 	vd->vd_dcb.operrsta = 0;
57930519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
58030519Ssam 	vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long);
581*30601Skarels 	vd->vd_dcb.trail.rwtrail.memadr =
582*30601Skarels 		vbasetup(bp, &vd->vd_rbuf, lp->d_secsize);
58330519Ssam 	vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1;
58430519Ssam 	vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin;
58530519Ssam 	vd->vd_dcb.trail.rwtrail.disk.track = tn;
58630519Ssam 	vd->vd_dcb.trail.rwtrail.disk.sector = sn;
58730574Skarels 	dk->dk_curcyl = bp->b_cylin;
58830574Skarels 	bp->b_track = 0;		/* init overloaded field */
58930574Skarels 	if (vi->ui_dk >= 0) {
59030574Skarels 		dk_busy |= 1<<vi->ui_dk;
59130574Skarels 		dk_xfer[vi->ui_dk]++;
59230574Skarels 		dk_wds[vi->ui_dk] += bp->b_bcount>>6;
59330574Skarels 	}
59430519Ssam 
59530519Ssam 	/*
59630519Ssam 	 * Look for any seeks to be performed on other drives on this
59730519Ssam 	 * controller.  If overlapped seeks exist, insert seek commands
59830519Ssam 	 * on the controller's command queue before the transfer.
59930519Ssam 	 */
60030519Ssam 	dcbp = &vd->vd_mdcb.mdcb_head;
60130519Ssam 
60230574Skarels 	if (dp == vm->um_tab.b_seekf)
60330574Skarels 		dp = dp->b_forw;
60430574Skarels 	else
60530574Skarels 		dp = vm->um_tab.b_seekf;
60630574Skarels 	for (; dp != NULL; dp = dp->b_forw) {
60730574Skarels 		if ((bp = dp->b_actf) == NULL)
60830574Skarels 			continue;
60930574Skarels 		vi = vddinfo[vdunit(bp->b_dev)];
61030574Skarels 		dk = &dksoftc[vi->ui_unit];
61130519Ssam 		dk->dk_curcyl = bp->b_cylin;
61230574Skarels 		if (vi->ui_dk >= 0)
61330574Skarels 			dk_seek[vi->ui_dk]++;
61430574Skarels 		dk->dk_dcb.operrsta = 0;
61530574Skarels 		dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin;
61630574Skarels #ifdef notdef
61730574Skarels 		dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_daddr>>8;
61830574Skarels 		dk->dk_dcb.trail.sktrail.skaddr.sector =
61930574Skarels 		    bp->b_daddr & 0xff;
62030574Skarels #else
62130574Skarels 		dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track;
62230574Skarels #endif
62330574Skarels 		*dcbp = (struct dcb *)dk->dk_dcbphys;
62430574Skarels 		dcbp = &dk->dk_dcb.nxtdcb;
62524004Ssam 	}
62630519Ssam 	*dcbp = (struct dcb *)vd->vd_dcbphys;
62730574Skarels 	if (vm->um_tab.b_actf)
62830574Skarels 		vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf;
62930574Skarels 	else
63030574Skarels 		vm->um_tab.b_actf = vm->um_tab.b_seekf;
631*30601Skarels 	if (vm->um_tab.b_seekf)
632*30601Skarels 		vm->um_tab.b_actl = vm->um_tab.b_seekl;
63330574Skarels 	vm->um_tab.b_seekf = 0;
63424004Ssam 
63530519Ssam 	/*
63630519Ssam 	 * Initiate operation.
63730519Ssam 	 */
63830519Ssam 	vd->vd_mdcb.mdcb_status = 0;
63930519Ssam 	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
64024004Ssam }
64124004Ssam 
64230519Ssam #define	DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE)
64324004Ssam /*
64424004Ssam  * Handle a disk interrupt.
64524004Ssam  */
64625675Ssam vdintr(ctlr)
64730519Ssam 	register ctlr;
64824004Ssam {
64930519Ssam 	register struct buf *bp, *dp;
65030519Ssam 	register struct vba_ctlr *vm = vdminfo[ctlr];
65130519Ssam 	register struct vba_device *vi;
65230519Ssam 	register struct vdsoftc *vd = &vdsoftc[ctlr];
65330519Ssam 	register status;
654*30601Skarels 	int ecode;
65530573Skarels 	struct dksoftc *dk;
65624004Ssam 
65730519Ssam 	vd->vd_wticks = 0;
65830519Ssam 	if (!vm->um_tab.b_active) {
65925675Ssam 		printf("vd%d: stray interrupt\n", ctlr);
66024004Ssam 		return;
66124004Ssam 	}
66225675Ssam 	/*
66330519Ssam 	 * Get device and block structures, and a pointer
66430519Ssam 	 * to the vba_device for the drive.
66525675Ssam 	 */
66630519Ssam 	dp = vm->um_tab.b_actf;
66730519Ssam 	bp = dp->b_actf;
66830519Ssam 	vi = vddinfo[vdunit(bp->b_dev)];
66930574Skarels 	if (vi->ui_dk >= 0)
67030574Skarels 		dk_busy &= ~(1<<vi->ui_dk);
67130519Ssam 	/*
67230519Ssam 	 * Check for and process errors on
67330519Ssam 	 * either the drive or the controller.
67430519Ssam 	 */
67530519Ssam 	uncache(&vd->vd_dcb.operrsta);
67630519Ssam 	status = vd->vd_dcb.operrsta;
67730519Ssam 	if (status & VDERR_HARD) {
678*30601Skarels 		if (vd->vd_type == VDTYPE_SMDE) {
679*30601Skarels 			uncache(&vd->vd_dcb.err_code);
680*30601Skarels 			ecode = vd->vd_dcb.err_code;
681*30601Skarels 		}
68230519Ssam 		if (status & DCBS_WPT) {
68330519Ssam 			/*
68430519Ssam 			 * Give up on write locked devices immediately.
68530519Ssam 			 */
68630573Skarels 			printf("dk%d: write locked\n", vi->ui_unit);
68730519Ssam 			bp->b_flags |= B_ERROR;
68830573Skarels 		} else if (status & VDERR_RETRY) {
68930519Ssam 			if (status & VDERR_DRIVE) {
69030519Ssam 				if (!vdreset_drive(vi))
69130519Ssam 					vi->ui_alive = 0;
69230519Ssam 			} else if (status & VDERR_CTLR)
69330519Ssam 				vdreset_ctlr(vm);
69430519Ssam 			/*
69530519Ssam 			 * Retry transfer once, unless reset failed.
69630519Ssam 			 */
69730519Ssam 			if (!vi->ui_alive || bp->b_errcnt++ >= 2)
69830519Ssam 				goto hard;
69930519Ssam 			vm->um_tab.b_active = 0;	/* force retry */
70030519Ssam 		} else  {
70130519Ssam 	hard:
70230519Ssam 			bp->b_flags |= B_ERROR;
70330519Ssam 			/* NEED TO ADJUST b_blkno to failed sector */
70430519Ssam 			harderr(bp, "dk");
70530519Ssam 			printf("status %x (%b)", status,
70630519Ssam 			   status &~ DONTCARE, VDERRBITS);
707*30601Skarels 			if (vd->vd_type == VDTYPE_SMDE)
708*30601Skarels 				printf(" ecode %x", ecode);
70930519Ssam 			printf("\n");
71030519Ssam 		}
71130519Ssam 	} else if (status & DCBS_SOFT)
71230519Ssam 		vdsofterr(vd, bp, &vd->vd_dcb);
71330519Ssam 	if (vm->um_tab.b_active) {
71430519Ssam 		vm->um_tab.b_active = 0;
71530519Ssam 		vm->um_tab.b_errcnt = 0;
71630519Ssam 		vm->um_tab.b_actf = dp->b_forw;
71730519Ssam 		dp->b_active = 0;
71830519Ssam 		dp->b_errcnt = 0;
71930519Ssam 		dp->b_actf = bp->av_forw;
72030519Ssam 		bp->b_resid = 0;
721*30601Skarels 		vbadone(bp, &vd->vd_rbuf);
72230519Ssam 		biodone(bp);
72330370Skarels 		/*
72430519Ssam 		 * If this unit has more work to do,
72530519Ssam 		 * then start it up right away.
72630370Skarels 		 */
72730519Ssam 		if (dp->b_actf)
72830519Ssam 			vdustart(vi);
72930573Skarels 		else if ((dk = &dksoftc[vi->ui_unit])->dk_openpart == 0)
73030573Skarels 			wakeup((caddr_t)dk);
73124004Ssam 	}
73225675Ssam 	/*
73330519Ssam 	 * If there are devices ready to
73430519Ssam 	 * transfer, start the controller.
73525675Ssam 	 */
736*30601Skarels 	if (vm->um_tab.b_actf || vm->um_tab.b_seekf)
73730519Ssam 		vdstart(vm);
73824004Ssam }
73924004Ssam 
74030519Ssam vdsofterr(vd, bp, dcb)
74130519Ssam 	struct vdsoftc *vd;
74225675Ssam 	register struct buf *bp;
74330519Ssam 	register struct dcb *dcb;
74425675Ssam {
74530519Ssam 	int unit = vdunit(bp->b_dev), status = dcb->operrsta;
74630519Ssam 	char part = 'a' + vdpart(bp->b_dev);
74725675Ssam 
748*30601Skarels 	if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) {
74930519Ssam 		if (vd->vd_type == VDTYPE_SMDE)
75030519Ssam 			uncache(&dcb->err_code);
75130519Ssam 		log(LOG_WARNING, "dk%d%c: soft error sn%d status %b ecode %x\n",
75230519Ssam 		    unit, part, bp->b_blkno, status, VDERRBITS, dcb->err_code);
75330519Ssam 	} else
75430370Skarels 		log(LOG_WARNING, "dk%d%c: soft ecc sn%d\n",
75530370Skarels 		    unit, part, bp->b_blkno);
75625675Ssam }
75725675Ssam 
75824004Ssam vdread(dev, uio)
75925675Ssam 	dev_t dev;
76025675Ssam 	struct uio *uio;
76124004Ssam {
76230519Ssam 	register int unit = vdunit(dev);
76324004Ssam 
76429564Ssam 	if (unit >= NDK)
76525675Ssam 		return (ENXIO);
76630519Ssam 	return (physio(vdstrategy, &rdkbuf[unit], dev, B_READ, minphys, uio));
76724004Ssam }
76824004Ssam 
76924004Ssam vdwrite(dev, uio)
77025675Ssam 	dev_t dev;
77125675Ssam 	struct uio *uio;
77224004Ssam {
77330519Ssam 	register int unit = vdunit(dev);
77424004Ssam 
77529564Ssam 	if (unit >= NDK)
77625675Ssam 		return (ENXIO);
77730519Ssam 	return (physio(vdstrategy, &rdkbuf[unit], dev, B_WRITE, minphys, uio));
77824004Ssam }
77924004Ssam 
78030519Ssam vdioctl(dev, cmd, data, flag)
78125675Ssam 	dev_t dev;
78230519Ssam 	int cmd;
78330519Ssam 	caddr_t data;
78430519Ssam 	int flag;
78524004Ssam {
78630519Ssam 	int unit = vdunit(dev);
78730519Ssam 	register struct disklabel *lp = &dklabel[unit];
78830519Ssam 	int error = 0;
78924004Ssam 
79030519Ssam 	switch (cmd) {
79130519Ssam 
79230519Ssam 	case DIOCGDINFO:
79330519Ssam 		*(struct disklabel *)data = *lp;
79430519Ssam 		break;
79530519Ssam 
79630573Skarels 	case DIOCGPART:
79730573Skarels 		((struct partinfo *)data)->disklab = lp;
79830573Skarels 		((struct partinfo *)data)->part =
79930573Skarels 		    &lp->d_partitions[vdpart(dev)];
80030519Ssam 		break;
80130519Ssam 
80230519Ssam 	case DIOCSDINFO:
80330519Ssam 		if ((flag & FWRITE) == 0)
80430519Ssam 			error = EBADF;
80530519Ssam 		else
80630519Ssam 			*lp = *(struct disklabel *)data;
80730519Ssam 		break;
80830519Ssam 
80930519Ssam 	case DIOCWDINFO: {
81030519Ssam 		struct buf *bp;
81130519Ssam 		struct disklabel *dlp;
81230519Ssam 
81330519Ssam 		if ((flag & FWRITE) == 0) {
81430519Ssam 			error = EBADF;
81530519Ssam 			break;
81630519Ssam 		}
81730519Ssam 		*lp = *(struct disklabel *)data;
81830519Ssam 		bp = geteblk(lp->d_secsize);
81930519Ssam 		bp->b_dev = dev;
82030519Ssam 		bp->b_blkno = LABELSECTOR;
82130519Ssam 		bp->b_bcount = lp->d_secsize;
82230519Ssam 		bp->b_flags = B_READ;
82330519Ssam 		dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET);
82430519Ssam 		vdstrategy(bp);
82530519Ssam 		biowait(bp);
82630519Ssam 		if (bp->b_flags & B_ERROR) {
82730519Ssam 			error = u.u_error;		/* XXX */
82830519Ssam 			u.u_error = 0;
82930519Ssam 			goto bad;
83030519Ssam 		}
83130519Ssam 		*dlp = *lp;
83230519Ssam 		bp->b_flags = B_WRITE;
83330519Ssam 		vdstrategy(bp);
83430519Ssam 		biowait(bp);
83530519Ssam 		if (bp->b_flags & B_ERROR) {
83630519Ssam 			error = u.u_error;		/* XXX */
83730519Ssam 			u.u_error = 0;
83830519Ssam 		}
83930519Ssam bad:
84030519Ssam 		brelse(bp);
84130519Ssam 		break;
84225675Ssam 	}
84330519Ssam 
84430519Ssam 	default:
84530519Ssam 		error = ENOTTY;
84630519Ssam 		break;
84724004Ssam 	}
84825675Ssam 	return (0);
84924004Ssam }
85024004Ssam 
85125675Ssam /*
85230519Ssam  * Watch for lost interrupts.
85325675Ssam  */
85430519Ssam vdwatch()
85530519Ssam {
85630519Ssam 	register struct vdsoftc *vd;
85730519Ssam 	register struct vba_ctlr *vm;
85825675Ssam 	register int ctlr, unit;
85930519Ssam 
86030519Ssam 	timeout(vdwatch, (caddr_t)0, hz);
86130519Ssam 	for (ctlr = 0; ctlr < NVD; ctlr++) {
86230519Ssam 		vm = vdminfo[ctlr];
86330519Ssam 		if (vm == 0 || vm->um_alive == 0)
86430519Ssam 			continue;
86530519Ssam 		vd = &vdsoftc[ctlr];
866*30601Skarels 		if (vm->um_tab.b_active && vd->vd_wticks++ >= 20) {
86730519Ssam 			vd->vd_wticks = 0;
86830519Ssam 			printf("vd%d: lost interrupt\n", ctlr);
86930519Ssam 			/* abort pending dcb's and restart controller */
87030519Ssam 		}
87130519Ssam 	}
87230519Ssam }
87330519Ssam 
87430519Ssam #define	DBSIZE	64	/* controller limit with 1K sectors */
87530519Ssam /*
87630519Ssam  * Crash dump.
87730519Ssam  */
87830519Ssam vddump(dev)
87930519Ssam 	dev_t dev;
88024004Ssam {
88130519Ssam 	register struct vba_device *vi;
88230519Ssam 	register struct vba_ctlr *vm;
88330519Ssam 	register struct disklabel *lp;
88430519Ssam 	register struct vdsoftc *vd;
88530519Ssam 	struct dksoftc *dk;
88630519Ssam 	int part, unit, num;
887*30601Skarels 	u_long start;
88824004Ssam 
88930519Ssam 	start = 0;
89030519Ssam 	unit = vdunit(dev);
89130519Ssam 	if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
89230519Ssam 		return (ENXIO);
89330519Ssam 	dk = &dksoftc[unit];
89430519Ssam 	if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
89530519Ssam 		return (ENXIO);
89630519Ssam 	lp = &dklabel[unit];
89730519Ssam 	part = vdpart(dev);
89830519Ssam 	if (part >= lp->d_npartitions)
89930519Ssam 		return (ENXIO);
90030519Ssam 	vm = vdminfo[vi->ui_ctlr];
90130519Ssam 	vdreset_ctlr(vm);
90230519Ssam 	if (dumplo < 0)
90330519Ssam 		return (EINVAL);
90430519Ssam 	/*
90530573Skarels 	 * Dumplo and maxfree are in pages.
90630519Ssam 	 */
90730519Ssam 	num = maxfree * (NBPG / lp->d_secsize);
90830573Skarels 	dumplo *= NBPG / lp->d_secsize;
90930519Ssam 	if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size)
91030519Ssam 		num = lp->d_partitions[vdpart(dev)].p_size - dumplo;
91130519Ssam 	vd = &vdsoftc[vm->um_ctlr];
91230519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
91330519Ssam 	vd->vd_dcb.opcode = VDOP_WD;
91430519Ssam 	vd->vd_dcb.devselect = vi->ui_slave;
91530519Ssam 	vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long);
91630519Ssam 	while (num > 0) {
91730519Ssam 		int nsec, cn, sn, tn;
91830519Ssam 
91930519Ssam 		nsec = MIN(num, DBSIZE);
920*30601Skarels 		sn = dumplo + start / lp->d_secsize;
92130519Ssam 		cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) /
92230519Ssam 		    lp->d_secpercyl;
92330519Ssam 		sn %= lp->d_secpercyl;
92430519Ssam 		tn = sn / lp->d_nsectors;
92530519Ssam 		sn %= lp->d_nsectors;
92630519Ssam 		vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
92730519Ssam 		vd->vd_dcb.trail.rwtrail.memadr = start;
92830519Ssam 		vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1;
92930519Ssam 		vd->vd_dcb.trail.rwtrail.disk.cylinder = cn;
93030519Ssam 		vd->vd_dcb.trail.rwtrail.disk.track = tn;
93130519Ssam 		vd->vd_dcb.trail.rwtrail.disk.sector = sn;
93230519Ssam 		vd->vd_dcb.operrsta = 0;
93330519Ssam 		VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
93430519Ssam 		if (!vdpoll(vm, 5)) {
93530519Ssam 			printf(" during dump\n");
93630519Ssam 			return (EIO);
93730519Ssam 		}
93830519Ssam 		if (vd->vd_dcb.operrsta & VDERR_HARD) {
93930519Ssam 			printf("dk%d: hard error, status=%b\n", unit,
94030519Ssam 			    vd->vd_dcb.operrsta, VDERRBITS);
94130519Ssam 			return (EIO);
94230519Ssam 		}
94330519Ssam 		start += nsec * lp->d_secsize;
94430519Ssam 		num -= nsec;
94525675Ssam 	}
94630519Ssam 	return (0);
94724004Ssam }
94824004Ssam 
94924004Ssam vdsize(dev)
95025675Ssam 	dev_t dev;
95124004Ssam {
95230519Ssam 	register int unit = vdunit(dev);
95330519Ssam 	register struct dksoftc *dk;
95430519Ssam 	struct vba_device *vi;
95530519Ssam 	struct disklabel *lp;
95624004Ssam 
95730519Ssam 	if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 ||
95830519Ssam 	    (dk = &dksoftc[unit])->dk_state != OPEN)
95925675Ssam 		return (-1);
96030519Ssam 	lp = &dklabel[unit];
96130573Skarels 	return ((int)lp->d_partitions[vdpart(dev)].p_size);
96224004Ssam }
96324004Ssam 
96425675Ssam /*
96525675Ssam  * Perform a controller reset.
96625675Ssam  */
96730519Ssam vdreset_ctlr(vm)
96830519Ssam 	register struct vba_ctlr *vm;
96924004Ssam {
97030519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
97130519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
97230519Ssam 	register int unit;
97330519Ssam 	struct vba_device *vi;
97425675Ssam 
97530519Ssam 	VDRESET(vdaddr, vd->vd_type);
97630519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
97730519Ssam 		vdaddr->vdcsr = 0;
97830519Ssam 		vdaddr->vdtcf_mdcb = AM_ENPDA;
97930519Ssam 		vdaddr->vdtcf_dcb = AM_ENPDA;
98030519Ssam 		vdaddr->vdtcf_trail = AM_ENPDA;
98130519Ssam 		vdaddr->vdtcf_data = AM_ENPDA;
98230519Ssam 		vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
98325675Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
98425675Ssam 	}
98530519Ssam 	if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) {
98630519Ssam 		printf("%s cmd failed\n",
98730519Ssam 		    vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
98830370Skarels 		return;
98925675Ssam 	}
99030519Ssam 	for (unit = 0; unit < NDK; unit++)
99130519Ssam 		if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive)
99230519Ssam 			(void) vdreset_drive(vi);
99330519Ssam }
99430519Ssam 
99530519Ssam vdreset_drive(vi)
99630519Ssam 	register struct vba_device *vi;
99730519Ssam {
99830519Ssam 	register struct disklabel *lp = &dklabel[vi->ui_unit];
99930519Ssam 	struct vba_ctlr *vm = vdminfo[vi->ui_ctlr];
100030519Ssam 	struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
100130519Ssam 	struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
100230519Ssam 
100330519Ssam top:
100430519Ssam 	vd->vd_dcb.opcode = VDOP_CONFIG;		/* command */
100530519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
100630519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
100730519Ssam 	vd->vd_dcb.operrsta = 0;
100830519Ssam 	vd->vd_dcb.devselect = vi->ui_slave;
100930519Ssam 	vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders;
101030519Ssam 	vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks;
101130519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
101230519Ssam 		vd->vd_dcb.trailcnt = sizeof (treset) / sizeof (long);
101330519Ssam 		vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors;
1014*30601Skarels 		vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack;
101530519Ssam 		vd->vd_dcb.trail.rstrail.recovery = 0x18f;
101630519Ssam 	} else
101730519Ssam 		vd->vd_dcb.trailcnt = 2;		/* XXX */
101830519Ssam 	vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
101930519Ssam 	vd->vd_mdcb.mdcb_status = 0;
102030519Ssam 	VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type);
102130519Ssam 	if (!vdpoll(vm, 5)) {
102230519Ssam 		printf(" during config\n");
102330519Ssam 		return (0);
102425675Ssam 	}
102530519Ssam 	if (vd->vd_dcb.operrsta & VDERR_HARD) {
102630519Ssam 		if (vd->vd_type == VDTYPE_SMDE &&
102730519Ssam 		    (vdaddr->vdstatus[vi->ui_slave]&STA_US) == 0)
102830519Ssam 			return (0);
102930519Ssam 		if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0)
103030519Ssam 			printf("dk%d: config error\n", vi->ui_unit);
103130519Ssam 		else if ((vd->vd_flags&VD_STARTED) == 0) {
103230519Ssam 			int started;
103330519Ssam 
103430519Ssam 			printf("vd%d: starting drives, wait ... ", vm->um_ctlr);
103530519Ssam 			vd->vd_flags |= VD_STARTED;
103630519Ssam 			started = (vdcmd(vm, VDOP_START, 10) == 1);
103730519Ssam 			DELAY(62000000);
103830519Ssam 			printf("\n");
103930519Ssam 			if (started)
104030519Ssam 				goto top;
104130519Ssam 		}
104230519Ssam 		return (0);
104330519Ssam 	}
104430519Ssam 	return (1);
104525675Ssam }
104624004Ssam 
104725675Ssam /*
104830519Ssam  * Perform a command w/o trailer.
104925675Ssam  */
105030519Ssam vdcmd(vm, cmd, t)
105130519Ssam 	register struct vba_ctlr *vm;
105225675Ssam {
105330519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
105425675Ssam 
105530519Ssam 	vd->vd_dcb.opcode = cmd;		/* command */
105630519Ssam 	vd->vd_dcb.intflg = DCBINT_NONE;
105730519Ssam 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
105830519Ssam 	vd->vd_dcb.operrsta = 0;
105930519Ssam 	vd->vd_dcb.devselect = 0;
106030519Ssam 	vd->vd_dcb.trailcnt = 0;
106130519Ssam 	vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
106230519Ssam 	vd->vd_mdcb.mdcb_status = 0;
106330519Ssam 	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
106430519Ssam 	if (!vdpoll(vm, t)) {
106530519Ssam 		printf(" during init\n");
106630370Skarels 		return (0);
106730370Skarels 	}
106830519Ssam 	return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0);
106925675Ssam }
107025675Ssam 
107125925Ssam /*
107230519Ssam  * Poll controller until operation
107330519Ssam  * completes or timeout expires.
107425925Ssam  */
107530519Ssam vdpoll(vm, t)
107630519Ssam 	register struct vba_ctlr *vm;
107725925Ssam 	register int t;
107825925Ssam {
107930519Ssam 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
108030519Ssam 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
108125925Ssam 
108225925Ssam 	t *= 1000;
108330370Skarels 	for (;;) {
108430519Ssam 		uncache(&vd->vd_dcb.operrsta);
108530519Ssam 		if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT))
108630370Skarels 			break;
108725925Ssam 		if (--t <= 0) {
108830519Ssam 			printf("vd%d: controller timeout", vm->um_ctlr);
108930519Ssam 			VDABORT(vdaddr, vd->vd_type);
109025925Ssam 			DELAY(30000);
109125925Ssam 			return (0);
109225925Ssam 		}
109330370Skarels 		DELAY(1000);
109425925Ssam 	}
109530519Ssam 	if (vd->vd_type == VDTYPE_SMDE) {
109630519Ssam 		do {
109725925Ssam 			DELAY(50);
109830519Ssam 			uncache(&vdaddr->vdcsr);
109930519Ssam 		} while (vdaddr->vdcsr & CS_GO);
110025925Ssam 		DELAY(300);
110125925Ssam 	}
110225925Ssam 	DELAY(200);
110330519Ssam 	uncache(&vd->vd_dcb.operrsta);
110425925Ssam 	return (1);
110525925Ssam }
110625925Ssam 
110730519Ssam #ifdef COMPAT_42
110830519Ssam struct	vdst {
110930519Ssam 	int	nsec;		/* sectors/track */
111030519Ssam 	int	ntrack;		/* tracks/cylinder */
111130519Ssam 	int	ncyl;		/* cylinders */
111230519Ssam 	char	*name;		/* type name */
111330519Ssam 	struct {
111430519Ssam 		int	off;	/* partition offset in sectors */
111530519Ssam 		int	size;	/* partition size in sectors */
111630573Skarels 	} parts[8];
111730519Ssam } vdst[] = {
111830573Skarels 	{ 48, 24, 711, "xsd",
111930573Skarels 		{0,	 30528},	/* a cyl   0 - 52 */
112030573Skarels 		{30528,	 30528},	/* b cyl  53 - 105 */
112130573Skarels 		{61056,	 345600}, 	/* c cyl 106 - 705 */
112230573Skarels 		{118656, 288000}, 	/* d cyl 206 - 705 */
112330573Skarels 		{176256, 230400},	/* e cyl 306 - 705 */
112430573Skarels 		{233856, 172800}, 	/* f cyl 406 - 705 */
112530573Skarels 		{291456, 115200},	/* g cyl 506 - 705 */
112630573Skarels 		{349056, 57600}		/* h cyl 606 - 705 */
112730573Skarels 	},
112830573Skarels 	{ 44, 20, 842, "egl",
1129*30601Skarels 		{0,	 52800},	/* egl0a cyl   0 - 59 */
1130*30601Skarels 		{52800,	 66000},	/* egl0b cyl  60 - 134 */
1131*30601Skarels 		{118800, 617760}, 	/* egl0c cyl 135 - 836 */
1132*30601Skarels 		{736560, 5280}, 	/* egl0d cyl 837 - 842 */
1133*30601Skarels 		{0, 	 736560},	/* egl0e cyl 0 - 836 */
1134*30601Skarels 		{0, 	 741840}, 	/* egl0f cyl 0 - 842 */
1135*30601Skarels 		{118800, 310640},	/* egl0g cyl 135 - 487 */
1136*30601Skarels 		{429440, 307120}	/* egl0h cyl 488 - 836 */
113730573Skarels 	},
113830573Skarels 	{ 64, 10, 823, "fuj",
113930573Skarels 		{0,	 19200},	/* fuj0a cyl   0 - 59 */
114030573Skarels 		{19200,	 24000},	/* fuj0b cyl  60 - 134 */
114130573Skarels 		{43200,	 218560}, 	/* fuj0c cyl 135 - 817 */
114230573Skarels 		{79680,	 182080}, 	/* fuj0d cyl 249 - 817 */
114330573Skarels 		{116160, 145600},	/* fuj0e cyl 363 - 817 */
114430573Skarels 		{152640, 109120}, 	/* fuj0f cyl 477 - 817 */
114530573Skarels 		{189120, 72640},	/* fuj0g cyl 591 - 817 */
114630573Skarels 		{225600, 36160}		/* fug0h cyl 705 - 817 */
114730573Skarels 	},
114830573Skarels 	{ 32, 24, 711, "xfd",
114930573Skarels 		{ 0,	 20352 },	/* a cyl   0 - 52 */
115030573Skarels 		{ 20352, 20352 },	/* b cyl  53 - 105 */
115130573Skarels 		{ 40704, 230400 },	/* c cyl 106 - 705 */
115230573Skarels 		{ 0,	 40704 },	/* d cyl 709 - 710 (a & b) */
115330573Skarels 		{ 0,	 271104 },	/* e cyl   0 - 705 */
115430573Skarels 		{ 20352, 250752 },	/* f cyl  53 - 705 (b & c) */
115530573Skarels 		{ 40704, 115200 },	/* g cyl 106 - 405 (1/2 of c) */
115630573Skarels 		{ 155904,115200 }	/* h cyl 406 - 705 (1/2 of c) */
115730573Skarels 	},
115830573Skarels 	{ 32, 19, 823, "smd",
115930573Skarels 		{0,	 20064},	/* a cyl   0-65 */
116030573Skarels 		{20064, 13680},		/* b cyl  66-110 */
116130573Skarels 		{33744, 214928},	/* c cyl 111-817 */
116230573Skarels 		{69616,	 179056},	/* d cyl 229 - 817 */
116330573Skarels 		{105488, 143184},	/* e cyl 347 - 817 */
116430573Skarels 		{141360, 107312},	/* f cyl 465 - 817 */
116530573Skarels 		{177232, 71440},	/* g cyl 583 - 817 */
116630573Skarels 		{213104, 35568}		/* h cyl 701 - 817 */
116730573Skarels 	},
116830573Skarels 	{ 32, 10, 823, "fsd",
116930573Skarels 		{0,	 9600},		/* a cyl   0 -  59 */
117030573Skarels 		{9600,	 12000},	/* b cyl  60 - 134 */
117130573Skarels 		{21600,	 109280},	/* c cyl 135 - 817 */
117230573Skarels 		{39840,	 91040},	/* d cyl 249 - 817 */
117330573Skarels 		{58080,	 72800},	/* e cyl 363 - 817 */
117430573Skarels 		{76320,	 54560},	/* f cyl 477 - 817 */
117530573Skarels 		{94560,  36320},	/* g cyl 591 - 817 */
117630573Skarels 		{112800, 18080}		/* h cyl 705 - 817 */
117730573Skarels 	}
117830519Ssam };
117930519Ssam #define	NVDST	(sizeof (vdst) / sizeof (vdst[0]))
118030519Ssam 
118125675Ssam /*
118230519Ssam  * Construct a label for an unlabeled pack.  We
118330519Ssam  * deduce the drive type by reading from the last
118430519Ssam  * track on successively smaller drives until we
118530519Ssam  * don't get an error.
118625675Ssam  */
118730519Ssam vdmaptype(vi, lp)
118830519Ssam 	register struct vba_device *vi;
118930519Ssam 	register struct disklabel *lp;
119025675Ssam {
119130519Ssam 	register struct vdsoftc *vd;
119230519Ssam 	register struct vdst *p;
119330519Ssam 	struct vba_ctlr *vm = vdminfo[vi->ui_ctlr];
119430519Ssam 	int i;
119525675Ssam 
119630519Ssam 	vd = &vdsoftc[vi->ui_ctlr];
119730519Ssam 	for (p = vdst; p < &vdst[NVDST]; p++) {
119830519Ssam 		if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32)
119930519Ssam 			continue;
120030519Ssam 		lp->d_nsectors = p->nsec;
120130519Ssam 		lp->d_ntracks = p->ntrack;
120230519Ssam 		lp->d_ncylinders = p->ncyl;
120330519Ssam 		if (!vdreset_drive(vi))
120430519Ssam 			return (0);
120530519Ssam 		vd->vd_dcb.opcode = VDOP_RD;
120630519Ssam 		vd->vd_dcb.intflg = DCBINT_NONE;
120730519Ssam 		vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
120830519Ssam 		vd->vd_dcb.devselect = vi->ui_slave;
120930519Ssam 		vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long);
1210*30601Skarels 		vd->vd_dcb.trail.rwtrail.memadr =
1211*30601Skarels 		    vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf);
121230519Ssam 		vd->vd_dcb.trail.rwtrail.wcount = 512 / sizeof(short);
121330519Ssam 		vd->vd_dcb.operrsta = 0;
121430519Ssam 		vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2;
121530519Ssam 		vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1;
121630519Ssam 		vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1;
121730519Ssam 		vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
121830519Ssam 		vd->vd_mdcb.mdcb_status = 0;
121930519Ssam 		VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
122030519Ssam 		if (!vdpoll(vm, 60))
122130519Ssam 			printf(" during probe\n");
122230519Ssam 		if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0)
122330519Ssam 			break;
122424004Ssam 	}
122530519Ssam 	if (p >= &vdst[NVDST]) {
122630519Ssam 		printf("dk%d: unknown drive type\n", vi->ui_unit);
122730519Ssam 		return (0);
122830519Ssam 	}
122930573Skarels 	for (i = 0; i < 8; i++) {
123030519Ssam 		lp->d_partitions[i].p_offset = p->parts[i].off;
123130519Ssam 		lp->d_partitions[i].p_size = p->parts[i].size;
123230519Ssam 	}
123330573Skarels 	lp->d_npartitions = 8;
123430519Ssam 	lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
123530519Ssam 	lp->d_rpm = 3600;
123630519Ssam 	lp->d_secsize = 512;
123730519Ssam 	bcopy(p->name, lp->d_typename, 4);
123830519Ssam 	return (1);
123924004Ssam }
124030519Ssam #endif COMPAT_42
124124004Ssam #endif
1242