xref: /original-bsd/sys/tahoe/vba/vd.c (revision b7cc7b86)
1 /*
2  * Copyright (c) 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Computer Consoles Inc.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)vd.c	7.13 (Berkeley) 12/16/90
11  */
12 
13 #include "dk.h"
14 #if NVD > 0
15 /*
16  * Versabus VDDC/SMDE driver.
17  */
18 #include "sys/param.h"
19 #include "sys/buf.h"
20 #include "sys/cmap.h"
21 #include "sys/conf.h"
22 #include "sys/dkstat.h"
23 #include "sys/disklabel.h"
24 #include "sys/map.h"
25 #include "sys/file.h"
26 #include "sys/systm.h"
27 #include "sys/user.h"
28 #include "sys/vmmac.h"
29 #include "sys/proc.h"
30 #include "sys/syslog.h"
31 #include "sys/kernel.h"
32 #include "sys/ioctl.h"
33 #include "sys/stat.h"
34 
35 #include "../include/cpu.h"
36 #include "../include/mtpr.h"
37 #include "../include/pte.h"
38 
39 #include "../vba/vbavar.h"
40 #include "../vba/vdreg.h"
41 
42 #ifndef	COMPAT_42
43 #define	COMPAT_42
44 #endif
45 #define	B_FORMAT	B_XXX		/* XXX */
46 
47 #define vdunit(dev)	(minor(dev) >> 3)
48 #define vdpart(dev)	(minor(dev) & 0x07)
49 #define	vdminor(unit,part)	(((unit) << 3) | (part))
50 
51 struct	vba_ctlr *vdminfo[NVD];
52 struct  vba_device *vddinfo[NDK];
53 int	vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy();
54 long	vdstd[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 };
55 struct	vba_driver vddriver =
56   { vdprobe, vdslave, vdattach, vddgo, vdstd, "dk", vddinfo, "vd", vdminfo };
57 
58 /*
59  * Per-controller state.
60  */
61 struct vdsoftc {
62 	u_short	vd_flags;
63 #define	VD_PRINT	0x1	/* controller info printed */
64 #define	VD_STARTED	0x2	/* start command issued */
65 #define	VD_DOSEEKS	0x4	/* should overlap seeks */
66 #define	VD_SCATGATH	0x8	/* can do scatter-gather commands (correctly) */
67 #define	VD_LOCKED	0x10	/* locked for direct controller access */
68 #define	VD_WAIT		0x20	/* someone needs direct controller access */
69 	u_short	vd_type;	/* controller type */
70 	u_short	vd_wticks;	/* timeout */
71 	u_short	vd_secsize;	/* sector size for controller */
72 	struct	mdcb vd_mdcb;	/* master command block */
73 	u_long	vd_mdcbphys;	/* physical address of vd_mdcb */
74 	struct	dcb vd_dcb;	/* i/o command block */
75 	u_long	vd_dcbphys;	/* physical address of vd_dcb */
76 	struct	vb_buf vd_rbuf;	/* vba resources */
77 } vdsoftc[NVD];
78 
79 #define	VDMAXTIME	20	/* max time for operation, sec. */
80 
81 /*
82  * Per-drive state.
83  */
84 struct	dksoftc {
85 	int	dk_state;	/* open fsm */
86 #ifndef SECSIZE
87 	u_short	dk_bshift;	/* shift for * (DEV_BSIZE / sectorsize) XXX */
88 #endif SECSIZE
89 	int	dk_wlabel;	/* label sector is currently writable */
90 	u_long	dk_copenpart;	/* character units open on this drive */
91 	u_long	dk_bopenpart;	/* block units open on this drive */
92 	u_long	dk_openpart;	/* all units open on this drive */
93 	u_int	dk_curcyl;	/* last selected cylinder */
94 	struct	skdcb dk_dcb;	/* seek command block */
95 	u_long	dk_dcbphys;	/* physical address of dk_dcb */
96 	int	df_reg[3];	/* for formatting, in-out parameters */
97 } dksoftc[NDK];
98 
99 /*
100  * Drive states.  Used during steps of open/initialization.
101  * States < OPEN (> 0) are transient, during an open operation.
102  * OPENRAW is used for unlabeled disks, to allow format operations.
103  */
104 #define	CLOSED		0		/* disk is closed */
105 #define	WANTOPEN	1		/* open requested, not started */
106 #define	WANTOPENRAW	2		/* open requested, no label */
107 #define	RDLABEL		3		/* reading pack label */
108 #define	OPEN		4		/* intialized and ready */
109 #define	OPENRAW		5		/* open, no label */
110 
111 struct	buf dkutab[NDK];	/* i/o queue headers */
112 struct	disklabel dklabel[NDK];	/* pack labels */
113 
114 #define b_cylin	b_resid
115 #define	b_track	b_error		/* used for seek commands */
116 #define	b_seekf	b_forw		/* second queue on um_tab */
117 #define	b_seekl	b_back		/* second queue on um_tab */
118 
119 int	vdwstart, vdwatch();
120 
121 /*
122  * See if the controller is really there; if so, initialize it.
123  */
124 vdprobe(reg, vm)
125 	caddr_t reg;
126 	struct vba_ctlr *vm;
127 {
128 	register br, cvec;		/* must be r12, r11 */
129 	register struct vddevice *vdaddr = (struct vddevice *)reg;
130 	struct vdsoftc *vd;
131 	int s;
132 
133 #ifdef lint
134 	br = 0; cvec = br; br = cvec;
135 	vdintr(0);
136 #endif
137 	if (badaddr((caddr_t)reg, 2))
138 		return (0);
139 	vd = &vdsoftc[vm->um_ctlr];
140 	vdaddr->vdreset = 0xffffffff;
141 	DELAY(1000000);
142 	if (vdaddr->vdreset != (unsigned)0xffffffff) {
143 		vd->vd_type = VDTYPE_VDDC;
144 		vd->vd_flags &= ~VD_DOSEEKS;
145 		DELAY(1000000);
146 	} else {
147 		vd->vd_type = VDTYPE_SMDE;
148 		vd->vd_flags |= VD_DOSEEKS;
149 		vdaddr->vdrstclr = 0;
150 		DELAY(3000000);
151 	}
152 	vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb);
153 	vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb);
154 	vm->um_addr = reg;		/* XXX */
155 	s = spl7();
156 	if (vdinit_ctlr(vm, vd) == 0) {
157 		splx(s);
158 		return (0);
159 	}
160 	if (vd->vd_type == VDTYPE_SMDE) {
161 #ifdef notdef
162 		/*
163 		 * Attempt PROBE to get all drive status;
164 		 * we take advantage of this in vdreset_drive
165 		 * to try to avoid guessing games.
166 		 */
167 		(void) vdcmd(vm, VDOP_PROBE, 5, 0);
168 #endif
169 		/*
170 		 * Check for scatter-gather by checking firmware date
171 		 * with IDENT command.  The date is printed when
172 		 * vdslave is first called, thus this must be
173 		 * the last controller operation in vdprobe.
174 		 */
175 		vd->vd_dcb.trail.idtrail.date = 0;
176 		if (vdcmd(vm, VDOP_IDENT, 10, 0)) {
177 			uncache(&vd->vd_dcb.trail.idtrail.date);
178 			if (vd->vd_dcb.trail.idtrail.date != 0)
179 				vd->vd_flags |= VD_SCATGATH;
180 		}
181 	}
182 	splx(s);
183 	/*
184 	 * Allocate page tables and i/o buffer.
185 	 */
186 	if (vbainit(&vd->vd_rbuf, MAXPHYS,
187 	    vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) {
188 		printf("vd%d: vbainit failed\n", vm->um_ctlr);
189 		return (0);
190 	}
191 	br = 0x17, cvec = 0xe0 + vm->um_ctlr;	/* XXX */
192 	return (sizeof (struct vddevice));
193 }
194 
195 /*
196  * See if a drive is really there.
197  *
198  * Can't read pack label here as various data structures
199  * aren't setup for doing a read in a straightforward
200  * manner.  Instead just probe for the drive and leave
201  * the pack label stuff to the attach routine.
202  */
203 /* ARGSUSED */
204 vdslave(vi, vdaddr)
205 	register struct vba_device *vi;
206 	struct vddevice *vdaddr;
207 {
208 	register struct disklabel *lp = &dklabel[vi->ui_unit];
209 	register struct dksoftc *dk = &dksoftc[vi->ui_unit];
210 	struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
211 	int bcd();
212 
213 	if ((vd->vd_flags&VD_PRINT) == 0) {
214 		printf("vd%d: %s controller", vi->ui_ctlr,
215 		    vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE");
216 		if (vd->vd_flags & VD_SCATGATH) {
217 			char rev[5];
218 
219 			bcopy((caddr_t)&vd->vd_dcb.trail.idtrail.rev, rev,
220 			    sizeof(vd->vd_dcb.trail.idtrail.rev));
221 			printf(" firmware rev %s (%d-%d-%d)", rev,
222 			    bcd((vd->vd_dcb.trail.idtrail.date >> 8) & 0xff),
223 			    bcd(vd->vd_dcb.trail.idtrail.date & 0xff),
224 			    bcd((vd->vd_dcb.trail.idtrail.date >> 16)&0xffff));
225 		}
226 		printf("\n");
227 		vd->vd_flags |= VD_PRINT;
228 	}
229 
230 	/*
231 	 * Initialize label enough to do a reset on
232 	 * the drive.  The remainder of the default
233 	 * label values will be filled in in vdinit
234 	 * at attach time.
235 	 */
236 	if (vd->vd_type == VDTYPE_SMDE)
237 		lp->d_secsize = VD_MAXSECSIZE;
238 	else
239 		lp->d_secsize = VDDC_SECSIZE;
240 	lp->d_nsectors = 66;		/* only used on smd-e */
241 	lp->d_ntracks = 23;
242 	lp->d_ncylinders = 850;
243 	lp->d_secpercyl = 66*23;
244 	lp->d_rpm = 3600;
245 	lp->d_npartitions = 1;
246 	lp->d_partitions[0].p_offset = 0;
247 	lp->d_partitions[0].p_size = LABELSECTOR + 1;
248 
249 	/*
250 	 * Initialize invariant portion of
251 	 * dcb used for overlapped seeks.
252 	 */
253 	dk->dk_dcb.opcode = VDOP_SEEK;
254 	dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA;
255 	dk->dk_dcb.devselect = vi->ui_slave;
256 	dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long);
257 	dk->dk_dcb.trail.sktrail.skaddr.sector = 0;
258 	dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb);
259 #ifndef SECSIZE
260 	vd_setsecsize(dk, lp);
261 #endif
262 	return (vdreset_drive(vi));
263 }
264 
265 static int
266 bcd(n)
267 	register u_int n;
268 {
269 	register int bin = 0;
270 	register int mul = 1;
271 
272 	while (n) {
273 		bin += (n & 0xf) * mul;
274 		n >>= 4;
275 		mul *= 10;
276 	}
277 	return (bin);
278 }
279 
280 vdattach(vi)
281 	register struct vba_device *vi;
282 {
283 	register int unit = vi->ui_unit;
284 	register struct disklabel *lp = &dklabel[unit];
285 
286 	/*
287 	 * Try to initialize device and read pack label.
288 	 */
289 	if (vdinit(vdminor(unit, 0), 0) != 0) {
290 		printf(": unknown drive type");
291 		return;
292 	}
293 	if (dksoftc[unit].dk_state == OPEN)
294 		printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>",
295 		    lp->d_typename, lp->d_secsize,
296 		    lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors);
297 	/*
298 	 * (60 / rpm) / (sectors per track * (bytes per sector / 2))
299 	 */
300 	if (vi->ui_dk >= 0)
301 		dk_wpms[vi->ui_dk] =
302 		    (lp->d_rpm * lp->d_nsectors * lp->d_secsize) / 120;
303 #ifdef notyet
304 	addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp);
305 #endif
306 }
307 
308 vdopen(dev, flags, fmt)
309 	dev_t dev;
310 	int flags, fmt;
311 {
312 	register unit = vdunit(dev);
313 	register struct disklabel *lp;
314 	register struct dksoftc *dk;
315 	register struct partition *pp;
316 	struct vba_device *vi;
317 	int s, error = 0, part = vdpart(dev), mask = 1 << part;
318 	daddr_t start, end;
319 
320 	if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
321 		return (ENXIO);
322 	lp = &dklabel[unit];
323 	dk = &dksoftc[unit];
324 
325 	s = spl7();
326 	while (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
327 	    dk->dk_state != CLOSED)
328 		if (error = tsleep((caddr_t)dk, (PZERO+1) | PCATCH, devopn, 0))
329 			break;
330 	splx(s);
331 	if (error)
332 		return (error);
333 	if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
334 		if (error = vdinit(dev, flags))
335 			return (error);
336 
337 	if (vdwstart == 0) {
338 		timeout(vdwatch, (caddr_t)0, hz);
339 		vdwstart++;
340 	}
341 	/*
342 	 * Warn if a partion is opened
343 	 * that overlaps another partition which is open
344 	 * unless one is the "raw" partition (whole disk).
345 	 */
346 #define	RAWPART		8		/* 'x' partition */	/* XXX */
347 	if ((dk->dk_openpart & mask) == 0 && part != RAWPART) {
348 		pp = &lp->d_partitions[part];
349 		start = pp->p_offset;
350 		end = pp->p_offset + pp->p_size;
351 		for (pp = lp->d_partitions;
352 		     pp < &lp->d_partitions[lp->d_npartitions]; pp++) {
353 			if (pp->p_offset + pp->p_size <= start ||
354 			    pp->p_offset >= end)
355 				continue;
356 			if (pp - lp->d_partitions == RAWPART)
357 				continue;
358 			if (dk->dk_openpart & (1 << (pp - lp->d_partitions)))
359 				log(LOG_WARNING,
360 				    "dk%d%c: overlaps open partition (%c)\n",
361 				    unit, part + 'a',
362 				    pp - lp->d_partitions + 'a');
363 		}
364 	}
365 	if (part >= lp->d_npartitions)
366 		return (ENXIO);
367 	dk->dk_openpart |= mask;
368 	switch (fmt) {
369 	case S_IFCHR:
370 		dk->dk_copenpart |= mask;
371 		break;
372 	case S_IFBLK:
373 		dk->dk_bopenpart |= mask;
374 		break;
375 	}
376 	return (0);
377 }
378 
379 /* ARGSUSED */
380 vdclose(dev, flags, fmt)
381 	dev_t dev;
382 	int flags, fmt;
383 {
384 	register int unit = vdunit(dev);
385 	register struct dksoftc *dk = &dksoftc[unit];
386 	int part = vdpart(dev), mask = 1 << part;
387 
388 	switch (fmt) {
389 	case S_IFCHR:
390 		dk->dk_copenpart &= ~mask;
391 		break;
392 	case S_IFBLK:
393 		dk->dk_bopenpart &= ~mask;
394 		break;
395 	}
396 	if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0)
397 		dk->dk_openpart &= ~mask;
398 	/*
399 	 * Should wait for i/o to complete on this partition
400 	 * even if others are open, but wait for work on blkflush().
401 	 */
402 	if (dk->dk_openpart == 0) {
403 		int s = spl7();
404 		while (dkutab[unit].b_actf)
405 			sleep((caddr_t)dk, PZERO-1);
406 		splx(s);
407 		dk->dk_state = CLOSED;
408 		dk->dk_wlabel = 0;
409 	}
410 	return (0);
411 }
412 
413 vdinit(dev, flags)
414 	dev_t dev;
415 	int flags;
416 {
417 	register struct disklabel *lp;
418 	register struct dksoftc *dk;
419 	struct vba_device *vi;
420 	int unit = vdunit(dev), error = 0;
421 	char *msg, *readdisklabel();
422 	extern int cold;
423 
424 	dk = &dksoftc[unit];
425 	if (flags & O_NDELAY) {
426 		dk->dk_state = OPENRAW;
427 		return (0);
428 	}
429 	dk->dk_state = RDLABEL;
430 	lp = &dklabel[unit];
431 	vi = vddinfo[unit];
432 	if (msg = readdisklabel(dev, vdstrategy, lp)) {
433 		if (cold) {
434 			printf(": %s", msg);
435 			dk->dk_state = CLOSED;
436 		} else {
437 			log(LOG_ERR, "dk%d: %s\n", unit, msg);
438 			dk->dk_state = OPENRAW;
439 		}
440 #ifdef COMPAT_42
441 		vdlock(vi->ui_ctlr);
442 		if (vdmaptype(vi, lp))
443 			dk->dk_state = OPEN;
444 		vdunlock(vi->ui_ctlr);
445 #endif
446 	} else {
447 		/*
448 		 * Now that we have the label, configure
449 		 * the correct drive parameters.
450 		 */
451 		vdlock(vi->ui_ctlr);
452 		if (vdreset_drive(vi))
453 			dk->dk_state = OPEN;
454 		else {
455 			dk->dk_state = CLOSED;
456 			error = ENXIO;
457 		}
458 		vdunlock(vi->ui_ctlr);
459 	}
460 #ifndef SECSIZE
461 	vd_setsecsize(dk, lp);
462 #endif
463 	wakeup((caddr_t)dk);
464 	return (error);
465 }
466 
467 #ifndef SECSIZE
468 vd_setsecsize(dk, lp)
469 	register struct dksoftc *dk;
470 	register struct disklabel *lp;
471 {
472 	int mul;
473 
474 	/*
475 	 * Calculate scaling shift for mapping
476 	 * DEV_BSIZE blocks to drive sectors.
477 	 */
478 	mul = DEV_BSIZE / lp->d_secsize;
479 	dk->dk_bshift = 0;
480 	while ((mul >>= 1) > 0)
481 		dk->dk_bshift++;
482 }
483 #endif SECSIZE
484 
485 /*ARGSUSED*/
486 vddgo(vm)
487 	struct vba_device *vm;
488 {
489 
490 }
491 
492 vdstrategy(bp)
493 	register struct buf *bp;
494 {
495 	register struct vba_device *vi;
496 	register struct disklabel *lp;
497 	register struct dksoftc *dk;
498 	register int unit;
499 	register daddr_t sn;
500 	struct buf *dp;
501 	daddr_t sz, maxsz;
502 	int part, s;
503 
504 	unit = vdunit(bp->b_dev);
505 	if (unit >= NDK) {
506 		bp->b_error = ENXIO;
507 		goto bad;
508 	}
509 	vi = vddinfo[unit];
510 	lp = &dklabel[unit];
511 	if (vi == 0 || vi->ui_alive == 0) {
512 		bp->b_error = ENXIO;
513 		goto bad;
514 	}
515 	dk = &dksoftc[unit];
516 	if (dk->dk_state < OPEN) {
517 		if (dk->dk_state == CLOSED) {
518 			bp->b_error = EIO;
519 			goto bad;
520 		}
521 		goto q;
522 	}
523 	if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) {
524 		bp->b_error = EROFS;
525 		goto bad;
526 	}
527 	part = vdpart(bp->b_dev);
528 	if ((dk->dk_openpart & (1 << part)) == 0) {
529 		bp->b_error = ENODEV;
530 		goto bad;
531 	}
532 	sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
533 	maxsz = lp->d_partitions[part].p_size;
534 #ifndef SECSIZE
535 	sn = bp->b_blkno << dk->dk_bshift;
536 #else SECSIZE
537 	sn = bp->b_blkno;
538 #endif SECSIZE
539 	if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR &&
540 #if LABELSECTOR != 0
541 	    sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR &&
542 #endif
543 	    (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) {
544 		bp->b_error = EROFS;
545 		goto bad;
546 	}
547 	if (sn < 0 || sn + sz > maxsz) {
548 		if (sn == maxsz) {
549 			bp->b_resid = bp->b_bcount;
550 			goto done;
551 		}
552 		sz = maxsz - sn;
553 		if (sz <= 0) {
554 			bp->b_error = EINVAL;
555 			goto bad;
556 		}
557 		bp->b_bcount = sz * lp->d_secsize;
558 	}
559 	bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl;
560 #ifdef SECSIZE
561 if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0)
562 panic("vdstrat blksize");
563 #endif SECSIZE
564 q:
565 	s = spl7();
566 	dp = &dkutab[vi->ui_unit];
567 	disksort(dp, bp);
568 	if (!dp->b_active) {
569 		(void) vdustart(vi);
570 		if (!vi->ui_mi->um_tab.b_active)
571 			vdstart(vi->ui_mi);
572 	}
573 	splx(s);
574 	return;
575 bad:
576 	bp->b_flags |= B_ERROR;
577 done:
578 	biodone(bp);
579 	return;
580 }
581 
582 vdustart(vi)
583 	register struct vba_device *vi;
584 {
585 	register struct buf *bp, *dp;
586 	register struct vba_ctlr *vm;
587 	register int unit = vi->ui_unit;
588 	register struct dksoftc *dk;
589 	register struct vdsoftc *vd;
590 	struct disklabel *lp;
591 
592 	dp = &dkutab[unit];
593 	/*
594 	 * If queue empty, nothing to do.
595 	 */
596 	if ((bp = dp->b_actf) == NULL)
597 		return;
598 	/*
599 	 * If drive is off-cylinder and controller supports seeks,
600 	 * place drive on seek queue for controller.
601 	 * Otherwise, place on transfer queue.
602 	 */
603 	vd = &vdsoftc[vi->ui_ctlr];
604 	dk = &dksoftc[unit];
605 	vm = vi->ui_mi;
606 	if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) {
607 		lp = &dklabel[unit];
608 		bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors;
609 		if (vm->um_tab.b_seekf == NULL)
610 			vm->um_tab.b_seekf = dp;
611 		else
612 			vm->um_tab.b_seekl->b_forw = dp;
613 		vm->um_tab.b_seekl = dp;
614 	} else {
615 		if (vm->um_tab.b_actf == NULL)
616 			vm->um_tab.b_actf = dp;
617 		else
618 			vm->um_tab.b_actl->b_forw = dp;
619 		vm->um_tab.b_actl = dp;
620 	}
621 	dp->b_forw = NULL;
622 	dp->b_active++;
623 }
624 
625 /*
626  * Start next transfer on a controller.
627  * There are two queues of drives, the first on-cylinder
628  * and the second off-cylinder from their next transfers.
629  * Perform the first transfer for the first drive on the on-cylinder
630  * queue, if any, otherwise the first transfer for the first drive
631  * on the second queue.  Initiate seeks on remaining drives on the
632  * off-cylinder queue, then move them all to the on-cylinder queue.
633  */
634 vdstart(vm)
635 	register struct vba_ctlr *vm;
636 {
637 	register struct buf *bp;
638 	register struct vba_device *vi;
639 	register struct vdsoftc *vd;
640 	register struct dksoftc *dk;
641 	register struct disklabel *lp;
642 	register struct dcb **dcbp;
643 	struct buf *dp;
644 	int sn, tn;
645 
646 loop:
647 	/*
648 	 * Pull a request off the controller queue.
649 	 */
650 	if ((dp = vm->um_tab.b_actf) == NULL &&
651 	    (dp = vm->um_tab.b_seekf) == NULL)
652 		return;
653 	if ((bp = dp->b_actf) == NULL) {
654 		if (dp == vm->um_tab.b_actf)
655 			vm->um_tab.b_actf = dp->b_forw;
656 		else
657 			vm->um_tab.b_seekf = dp->b_forw;
658 		goto loop;
659 	}
660 
661 	/*
662 	 * Mark controller busy, and determine
663 	 * destination of this request.
664 	 */
665 	vm->um_tab.b_active++;
666 	vi = vddinfo[vdunit(bp->b_dev)];
667 	dk = &dksoftc[vi->ui_unit];
668 #ifndef SECSIZE
669 	sn = bp->b_blkno << dk->dk_bshift;
670 #else SECSIZE
671 	sn = bp->b_blkno;
672 #endif SECSIZE
673 	lp = &dklabel[vi->ui_unit];
674 	sn %= lp->d_secpercyl;
675 	tn = sn / lp->d_nsectors;
676 	sn %= lp->d_nsectors;
677 
678 	/*
679 	 * Construct dcb for read/write command.
680 	 */
681 	vd = &vdsoftc[vm->um_ctlr];
682 	vd->vd_dcb.intflg = DCBINT_DONE;
683 	vd->vd_dcb.devselect = dk->dk_dcb.devselect;
684 	vd->vd_dcb.operrsta = 0;
685 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
686 	vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin;
687 	vd->vd_dcb.trail.rwtrail.disk.track = tn;
688 	vd->vd_dcb.trail.rwtrail.disk.sector = sn;
689 	dk->dk_curcyl = bp->b_cylin;
690 	bp->b_track = 0;		/* init overloaded field */
691 	vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
692 	if (bp->b_flags & B_FORMAT)
693 		vd->vd_dcb.opcode = dk->dk_op;
694 	else if (vd->vd_flags & VD_SCATGATH &&
695 	    ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0)
696 		vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW;
697 	else
698 		vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD;
699 
700 	switch (vd->vd_dcb.opcode) {
701 	case VDOP_FSECT:
702 		vd->vd_dcb.trailcnt = sizeof (struct trfmt) / sizeof (long);
703 		vd->vd_dcb.trail.fmtrail.nsectors = bp->b_bcount /
704 		    lp->d_secsize;
705 		vd->vd_dcb.trail.fmtrail.hdr = *(dskadr *)&dk->dk_althdr;
706 		vd->vd_dcb.trail.rwtrail.disk.cylinder |= dk->dk_fmtflags;
707 		goto setupaddr;
708 
709 	case VDOP_RDRAW:
710 	case VDOP_RD:
711 	case VDOP_RHDE:
712 	case VDOP_WD:
713 		vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1;
714 setupaddr:
715 		vd->vd_dcb.trail.rwtrail.memadr =
716 			vbasetup(bp, &vd->vd_rbuf, (int)lp->d_secsize);
717 		break;
718 
719 	case VDOP_RAS:
720 	case VDOP_GAW:
721 		vd->vd_dcb.trailcnt += vd_sgsetup(bp, &vd->vd_rbuf,
722 		    &vd->vd_dcb.trail.sgtrail);
723 		break;
724 	}
725 	if (vi->ui_dk >= 0) {
726 		dk_busy |= 1<<vi->ui_dk;
727 		dk_xfer[vi->ui_dk]++;
728 		dk_wds[vi->ui_dk] += bp->b_bcount>>6;
729 	}
730 
731 	/*
732 	 * Look for any seeks to be performed on other drives on this
733 	 * controller.  If overlapped seeks exist, insert seek commands
734 	 * on the controller's command queue before the transfer.
735 	 */
736 	dcbp = &vd->vd_mdcb.mdcb_head;
737 
738 	if (dp == vm->um_tab.b_seekf)
739 		dp = dp->b_forw;
740 	else
741 		dp = vm->um_tab.b_seekf;
742 	for (; dp != NULL; dp = dp->b_forw) {
743 		if ((bp = dp->b_actf) == NULL)
744 			continue;
745 		vi = vddinfo[vdunit(bp->b_dev)];
746 		dk = &dksoftc[vi->ui_unit];
747 		dk->dk_curcyl = bp->b_cylin;
748 		if (vi->ui_dk >= 0)
749 			dk_seek[vi->ui_dk]++;
750 		dk->dk_dcb.operrsta = 0;
751 		dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin;
752 		dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track;
753 		*dcbp = (struct dcb *)dk->dk_dcbphys;
754 		dcbp = &dk->dk_dcb.nxtdcb;
755 	}
756 	*dcbp = (struct dcb *)vd->vd_dcbphys;
757 	if (vm->um_tab.b_actf)
758 		vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf;
759 	else
760 		vm->um_tab.b_actf = vm->um_tab.b_seekf;
761 	if (vm->um_tab.b_seekf)
762 		vm->um_tab.b_actl = vm->um_tab.b_seekl;
763 	vm->um_tab.b_seekf = 0;
764 
765 	/*
766 	 * Initiate operation.
767 	 */
768 	vd->vd_mdcb.mdcb_status = 0;
769 	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
770 }
771 
772 /*
773  * Wait for controller to finish current operation
774  * so that direct controller accesses can be done.
775  */
776 vdlock(ctlr)
777 {
778 	register struct vba_ctlr *vm = vdminfo[ctlr];
779 	register struct vdsoftc *vd = &vdsoftc[ctlr];
780 	int s;
781 
782 	s = spl7();
783 	while (vm->um_tab.b_active || vd->vd_flags & VD_LOCKED) {
784 		vd->vd_flags |= VD_WAIT;
785 		sleep((caddr_t)vd, PRIBIO);
786 	}
787 	vd->vd_flags |= VD_LOCKED;
788 	splx(s);
789 }
790 
791 /*
792  * Continue normal operations after pausing for
793  * munging the controller directly.
794  */
795 vdunlock(ctlr)
796 {
797 	register struct vba_ctlr *vm = vdminfo[ctlr];
798 	register struct vdsoftc *vd = &vdsoftc[ctlr];
799 
800 	vd->vd_flags &= ~VD_LOCKED;
801 	if (vd->vd_flags & VD_WAIT) {
802 		vd->vd_flags &= ~VD_WAIT;
803 		wakeup((caddr_t)vd);
804 	} else if (vm->um_tab.b_actf || vm->um_tab.b_seekf)
805 		vdstart(vm);
806 }
807 
808 #define	DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE)
809 /*
810  * Handle a disk interrupt.
811  */
812 vdintr(ctlr)
813 	register ctlr;
814 {
815 	register struct buf *bp, *dp;
816 	register struct vba_ctlr *vm = vdminfo[ctlr];
817 	register struct vba_device *vi;
818 	register struct vdsoftc *vd = &vdsoftc[ctlr];
819 	register status;
820 	int timedout;
821 	struct dksoftc *dk;
822 
823 	if (!vm->um_tab.b_active) {
824 		printf("vd%d: stray interrupt\n", ctlr);
825 		return;
826 	}
827 	/*
828 	 * Get device and block structures, and a pointer
829 	 * to the vba_device for the drive.
830 	 */
831 	dp = vm->um_tab.b_actf;
832 	bp = dp->b_actf;
833 	vi = vddinfo[vdunit(bp->b_dev)];
834 	dk = &dksoftc[vi->ui_unit];
835 	if (vi->ui_dk >= 0)
836 		dk_busy &= ~(1<<vi->ui_dk);
837 	timedout = (vd->vd_wticks >= VDMAXTIME);
838 	/*
839 	 * Check for and process errors on
840 	 * either the drive or the controller.
841 	 */
842 	uncache(&vd->vd_dcb.operrsta);
843 	status = vd->vd_dcb.operrsta;
844 	if (bp->b_flags & B_FORMAT) {
845 		dk->dk_operrsta = status;
846 		uncache(&vd->vd_dcb.err_code);
847 		/* ecodecnt gets err_code + err_wcnt from the same longword */
848 		dk->dk_ecodecnt = *(long *)&vd->vd_dcb.err_code;
849 		uncache(&vd->vd_dcb.err_trk);
850 		/* erraddr gets error trk/sec/cyl from the same longword */
851 		dk->dk_erraddr = *(long *)&vd->vd_dcb.err_trk;
852 	} else if (status & VDERR_HARD || timedout) {
853 		if (vd->vd_type == VDTYPE_SMDE)
854 			uncache(&vd->vd_dcb.err_code);
855 		if (status & DCBS_WPT) {
856 			/*
857 			 * Give up on write locked devices immediately.
858 			 */
859 			printf("dk%d: write locked\n", vi->ui_unit);
860 			bp->b_flags |= B_ERROR;
861 		} else if (status & VDERR_RETRY || timedout) {
862 			if (status & VDERR_CTLR || timedout) {
863 				vdharderr(timedout ?
864 				    "controller timeout" : "controller err",
865 				    vd, bp, &vd->vd_dcb);
866 				printf("; resetting controller...");
867 				vdreset_ctlr(vm);
868 			} else if (status & VDERR_DRIVE) {
869 				vdharderr("drive err", vd, bp, &vd->vd_dcb);
870 				printf("; resetting drive...");
871 				if (!vdreset_drive(vi))
872 					dk->dk_state = CLOSED;
873 			} else
874 				vdharderr("data err", vd, bp, &vd->vd_dcb);
875 			/*
876 			 * Retry transfer once, unless reset failed.
877 			 */
878 			if (!vi->ui_alive || dp->b_errcnt++ >= 1) {
879 				printf("\n");
880 				goto hard;
881 			}
882 
883 			printf(" retrying\n");
884 			vm->um_tab.b_active = 0;	/* force retry */
885 		} else  {
886 			vdharderr("hard error", vd, bp, &vd->vd_dcb);
887 			printf("\n");
888 	hard:
889 			bp->b_flags |= B_ERROR;
890 		}
891 	} else if (status & DCBS_SOFT)
892 		vdsofterr(bp, &vd->vd_dcb);
893 if (vd->vd_wticks > 3) {
894 vd->vd_dcb.err_code = vd->vd_wticks;
895 vdharderr("slow transfer (ecode is sec.)", vd, bp, &vd->vd_dcb);
896 printf("\n");
897 }
898 	vd->vd_wticks = 0;
899 	if (vm->um_tab.b_active) {
900 		vm->um_tab.b_active = 0;
901 		vm->um_tab.b_actf = dp->b_forw;
902 		dp->b_active = 0;
903 		dp->b_errcnt = 0;
904 		dp->b_actf = bp->av_forw;
905 		bp->b_resid = 0;
906 		vbadone(bp, &vd->vd_rbuf);
907 		biodone(bp);
908 		/*
909 		 * If this unit has more work to do,
910 		 * then start it up right away.
911 		 */
912 		if (dp->b_actf)
913 			vdustart(vi);
914 		else if (dk->dk_openpart == 0)
915 			wakeup((caddr_t)dk);
916 	}
917 	/*
918 	 * If there are devices ready to
919 	 * transfer, start the controller.
920 	 */
921 	if (vd->vd_flags & VD_WAIT) {
922 		vd->vd_flags &= ~VD_WAIT;
923 		wakeup((caddr_t)vd);
924 	} else if (vm->um_tab.b_actf || vm->um_tab.b_seekf)
925 		vdstart(vm);
926 }
927 
928 vdharderr(what, vd, bp, dcb)
929 	char *what;
930 	struct vdsoftc *vd;
931 	register struct buf *bp;
932 	register struct dcb *dcb;
933 {
934 	int unit = vdunit(bp->b_dev), status = dcb->operrsta;
935 	register struct disklabel *lp = &dklabel[unit];
936 	int blkdone;
937 
938 	if (vd->vd_wticks < VDMAXTIME)
939 		status &= ~DONTCARE;
940 	blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) *
941 	    lp->d_nsectors + dcb->err_sec -
942 	    lp->d_partitions[vdpart(bp->b_dev)].p_offset) >>
943 	    dksoftc[unit].dk_bshift) - bp->b_blkno;
944 	diskerr(bp, "dk", what, LOG_PRINTF, blkdone, lp);
945 	printf(", status %b", status, VDERRBITS);
946 	if (vd->vd_type == VDTYPE_SMDE)
947 		printf(" ecode %x", dcb->err_code);
948 }
949 
950 vdsofterr(bp, dcb)
951 	register struct buf *bp;
952 	register struct dcb *dcb;
953 {
954 	int unit = vdunit(bp->b_dev);
955 	struct disklabel *lp = &dklabel[unit];
956 	int status = dcb->operrsta;
957 	int blkdone;
958 
959 	blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) *
960 	    lp->d_nsectors + dcb->err_sec -
961 	    lp->d_partitions[vdpart(bp->b_dev)].p_offset) >>
962 	    dksoftc[unit].dk_bshift) - bp->b_blkno;
963 
964 	if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) {
965 		diskerr(bp, "dk", "soft error", LOG_WARNING, blkdone, lp);
966 		addlog(", status %b ecode %x\n", status, VDERRBITS,
967 		    dcb->err_code);
968 	} else {
969 		diskerr(bp, "dk", "soft ecc", LOG_WARNING, blkdone, lp);
970 		addlog("\n");
971 	}
972 }
973 
974 vdioctl(dev, cmd, data, flag)
975 	dev_t dev;
976 	int cmd;
977 	caddr_t data;
978 	int flag;
979 {
980 	register int unit = vdunit(dev);
981 	register struct disklabel *lp = &dklabel[unit];
982 	register struct dksoftc *dk = &dksoftc[unit];
983 	int error = 0, vdformat();
984 
985 	switch (cmd) {
986 
987 	case DIOCGDINFO:
988 		*(struct disklabel *)data = *lp;
989 		break;
990 
991 	case DIOCGPART:
992 		((struct partinfo *)data)->disklab = lp;
993 		((struct partinfo *)data)->part =
994 		    &lp->d_partitions[vdpart(dev)];
995 		break;
996 
997 	case DIOCSDINFO:
998 		if ((flag & FWRITE) == 0)
999 			error = EBADF;
1000 		else
1001 			error = setdisklabel(lp, (struct disklabel *)data,
1002 			    (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart);
1003 		if (error == 0 && dk->dk_state == OPENRAW &&
1004 		    vdreset_drive(vddinfo[unit]))
1005 			dk->dk_state = OPEN;
1006 		break;
1007 
1008 	case DIOCWLABEL:
1009 		if ((flag & FWRITE) == 0)
1010 			error = EBADF;
1011 		else
1012 			dk->dk_wlabel = *(int *)data;
1013 		break;
1014 
1015 	case DIOCWDINFO:
1016 		if ((flag & FWRITE) == 0)
1017 			error = EBADF;
1018 		else if ((error = setdisklabel(lp, (struct disklabel *)data,
1019 		    (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) {
1020 			int wlab;
1021 
1022 			if (error == 0 && dk->dk_state == OPENRAW &&
1023 			    vdreset_drive(vddinfo[unit]))
1024 				dk->dk_state = OPEN;
1025 			/* simulate opening partition 0 so write succeeds */
1026 			dk->dk_openpart |= (1 << 0);		/* XXX */
1027 			wlab = dk->dk_wlabel;
1028 			dk->dk_wlabel = 1;
1029 			error = writedisklabel(dev, vdstrategy, lp);
1030 			dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;
1031 			dk->dk_wlabel = wlab;
1032 		}
1033 		break;
1034 
1035 	case DIOCWFORMAT:
1036 	    {
1037 		register struct format_op *fop;
1038 		struct uio auio;
1039 		struct iovec aiov;
1040 
1041 		if ((flag & FWRITE) == 0) {
1042 			error = EBADF;
1043 			break;
1044 		}
1045 		fop = (struct format_op *)data;
1046 		aiov.iov_base = fop->df_buf;
1047 		aiov.iov_len = fop->df_count;
1048 		auio.uio_iov = &aiov;
1049 		auio.uio_iovcnt = 1;
1050 		auio.uio_resid = fop->df_count;
1051 		auio.uio_segflg = UIO_USERSPACE;
1052 		auio.uio_offset = fop->df_startblk * lp->d_secsize;
1053 		/* This assumes one active format operation per disk... */
1054 		dk->dk_op = fop->dk_op;
1055 		dk->dk_althdr = fop->dk_althdr;
1056 		dk->dk_fmtflags = fop->dk_fmtflags;
1057 		/*
1058 		 * Don't return errors, as the format op won't get copied
1059 		 * out if we return nonzero.  Callers must check the returned
1060 		 * registers and count.
1061 		 */
1062 		error = physio(vdformat, (struct buf *)NULL, dev,
1063 		     B_WRITE, minphys, &auio);
1064 		if (error == EIO)
1065 			error = 0;
1066 		fop->df_count -= auio.uio_resid;
1067 		/* This assumes one active format operation per disk... */
1068 		fop->dk_operrsta = dk->dk_operrsta;
1069 		fop->dk_ecodecnt = dk->dk_ecodecnt;
1070 		fop->dk_erraddr = dk->dk_erraddr;
1071 		break;
1072 	    }
1073 
1074 	default:
1075 		error = ENOTTY;
1076 		break;
1077 	}
1078 	return (error);
1079 }
1080 
1081 vdformat(bp)
1082 	struct buf *bp;
1083 {
1084 	bp->b_flags |= B_FORMAT;
1085 	vdstrategy(bp);
1086 }
1087 
1088 /*
1089  * Watch for lost interrupts.
1090  */
1091 vdwatch()
1092 {
1093 	register struct vdsoftc *vd;
1094 	register struct vba_ctlr *vm;
1095 	register int ctlr;
1096 	int s;
1097 
1098 	timeout(vdwatch, (caddr_t)0, hz);
1099 	for (ctlr = 0; ctlr < NVD; ctlr++) {
1100 		vm = vdminfo[ctlr];
1101 		if (vm == 0 || vm->um_alive == 0)
1102 			continue;
1103 		vd = &vdsoftc[ctlr];
1104 		s = spl7();
1105 		if (vm->um_tab.b_active && vd->vd_wticks++ >= VDMAXTIME) {
1106 			printf("vd%d: lost interrupt\n", ctlr);
1107 #ifdef maybe
1108 			VDABORT((struct vddevice *)vm->um_addr, vd->vd_type);
1109 #endif
1110 			vdintr(ctlr);
1111 		}
1112 		splx(s);
1113 	}
1114 }
1115 
1116 #define	DBSIZE	64	/* controller limit with 1K sectors */
1117 /*
1118  * Crash dump.
1119  */
1120 vddump(dev)
1121 	dev_t dev;
1122 {
1123 	register struct vba_device *vi;
1124 	register struct vba_ctlr *vm;
1125 	register struct disklabel *lp;
1126 	register struct vdsoftc *vd;
1127 	struct dksoftc *dk;
1128 	int part, unit, num;
1129 	u_long start;
1130 
1131 	start = 0;
1132 	unit = vdunit(dev);
1133 	if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
1134 		return (ENXIO);
1135 	dk = &dksoftc[unit];
1136 	if (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
1137 	    vdinit(vdminor(unit, 0), 0) != 0)
1138 		return (ENXIO);
1139 	lp = &dklabel[unit];
1140 	part = vdpart(dev);
1141 	if (part >= lp->d_npartitions)
1142 		return (ENXIO);
1143 	vm = vi->ui_mi;
1144 	vdreset_ctlr(vm);
1145 	if (dumplo < 0)
1146 		return (EINVAL);
1147 	/*
1148 	 * Maxfree is in pages, dumplo is in DEV_BSIZE units.
1149 	 */
1150 	num = maxfree * (NBPG / lp->d_secsize);
1151 	dumplo *= DEV_BSIZE / lp->d_secsize;
1152 	if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size)
1153 		num = lp->d_partitions[vdpart(dev)].p_size - dumplo;
1154 	vd = &vdsoftc[vm->um_ctlr];
1155 	vd->vd_dcb.intflg = DCBINT_NONE;
1156 	vd->vd_dcb.opcode = VDOP_WD;
1157 	vd->vd_dcb.devselect = dk->dk_dcb.devselect;
1158 	vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
1159 	while (num > 0) {
1160 		int nsec, cn, sn, tn;
1161 
1162 		nsec = MIN(num, DBSIZE);
1163 		sn = dumplo + start / lp->d_secsize;
1164 		cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) /
1165 		    lp->d_secpercyl;
1166 		sn %= lp->d_secpercyl;
1167 		tn = sn / lp->d_nsectors;
1168 		sn %= lp->d_nsectors;
1169 		vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
1170 		vd->vd_dcb.trail.rwtrail.memadr = start;
1171 		vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1;
1172 		vd->vd_dcb.trail.rwtrail.disk.cylinder = cn;
1173 		vd->vd_dcb.trail.rwtrail.disk.track = tn;
1174 		vd->vd_dcb.trail.rwtrail.disk.sector = sn;
1175 		vd->vd_dcb.operrsta = 0;
1176 		VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
1177 		if (!vdpoll(vm, 5)) {
1178 			printf(" during dump\n");
1179 			return (EIO);
1180 		}
1181 		if (vd->vd_dcb.operrsta & VDERR_HARD) {
1182 			printf("dk%d: hard error, status=%b\n", unit,
1183 			    vd->vd_dcb.operrsta, VDERRBITS);
1184 			return (EIO);
1185 		}
1186 		start += nsec * lp->d_secsize;
1187 		num -= nsec;
1188 	}
1189 	return (0);
1190 }
1191 
1192 vdsize(dev)
1193 	dev_t dev;
1194 {
1195 	register int unit = vdunit(dev);
1196 	register struct dksoftc *dk;
1197 	struct vba_device *vi;
1198 	struct disklabel *lp;
1199 
1200 	if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 ||
1201 	    (dk = &dksoftc[unit])->dk_state != OPEN)
1202 		return (-1);
1203 	lp = &dklabel[unit];
1204 #ifdef SECSIZE
1205 	return ((int)lp->d_partitions[vdpart(dev)].p_size);
1206 #else SECSIZE
1207 	return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift);
1208 #endif SECSIZE
1209 }
1210 
1211 /*
1212  * Initialize controller.
1213  */
1214 vdinit_ctlr(vm, vd)
1215 	struct vba_ctlr *vm;
1216 	struct vdsoftc *vd;
1217 {
1218 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
1219 
1220 	if (vd->vd_type == VDTYPE_SMDE) {
1221 		vdaddr->vdcsr = 0;
1222 		vdaddr->vdtcf_mdcb = AM_ENPDA;
1223 		vdaddr->vdtcf_dcb = AM_ENPDA;
1224 		vdaddr->vdtcf_trail = AM_ENPDA;
1225 		vdaddr->vdtcf_data = AM_ENPDA;
1226 		vdaddr->vdccf = CCF_SEN | CCF_DIU | CCF_STS | CCF_RFE |
1227 		    XMD_32BIT | BSZ_16WRD |
1228 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
1229 	}
1230 	if (!vdcmd(vm, VDOP_INIT, 10, 0) || !vdcmd(vm, VDOP_DIAG, 10, 0)) {
1231 		printf("vd%d: %s cmd failed\n", vm->um_ctlr,
1232 		    vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
1233 		return (0);
1234 	}
1235 	vd->vd_secsize = vdaddr->vdsecsize << 1;
1236 	return (1);
1237 }
1238 
1239 /*
1240  * Perform a controller reset.
1241  */
1242 vdreset_ctlr(vm)
1243 	register struct vba_ctlr *vm;
1244 {
1245 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
1246 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
1247 	register int unit;
1248 	struct vba_device *vi;
1249 
1250 	VDRESET(vdaddr, vd->vd_type);
1251 	if (vdinit_ctlr(vm, vd) == 0)
1252 		return;
1253 	for (unit = 0; unit < NDK; unit++)
1254 		if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive)
1255 			(void) vdreset_drive(vi);
1256 }
1257 
1258 vdreset_drive(vi)
1259 	register struct vba_device *vi;
1260 {
1261 	register struct disklabel *lp = &dklabel[vi->ui_unit];
1262 	struct vba_ctlr *vm = vdminfo[vi->ui_ctlr];
1263 	struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
1264 	register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
1265 	register struct dksoftc *dk = &dksoftc[vi->ui_unit];
1266 	int config_status, config_ecode, saw_drive = 0;
1267 
1268 #ifdef notdef
1269 	/*
1270 	 * check for ESDI distribution panel already configured,
1271 	 * e.g. on boot drive, or if PROBE on controller actually
1272 	 * worked.  Status will be zero if drive hasn't
1273 	 * been probed yet.
1274 	 */
1275 #if STA_ESDI != 0
1276 	if ((vdaddr->vdstatus[vi->ui_slave] & STA_TYPE) == STA_ESDI)
1277 		lp->d_devflags |= VD_ESDI;
1278 #endif
1279 #endif
1280 top:
1281 	vd->vd_dcb.opcode = VDOP_CONFIG;		/* command */
1282 	vd->vd_dcb.intflg = DCBINT_NONE;
1283 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
1284 	vd->vd_dcb.operrsta = 0;
1285 	vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags;
1286 	vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders;
1287 	vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks;
1288 	if (vd->vd_type == VDTYPE_SMDE) {
1289 		vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long);
1290 		vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors;
1291 		vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack;
1292 		vd->vd_dcb.trail.rstrail.recovery =
1293 		    (lp->d_flags & D_REMOVABLE) ? VDRF_NORMAL :
1294 		    (VDRF_NORMAL &~ (VDRF_OSP|VDRF_OSM));
1295 	} else
1296 		vd->vd_dcb.trailcnt = 2;		/* XXX */
1297 	vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
1298 	vd->vd_mdcb.mdcb_status = 0;
1299 	VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type);
1300 	if (!vdpoll(vm, 5)) {
1301 		printf(" during config\n");
1302 		return (0);
1303 	}
1304 	config_status = vd->vd_dcb.operrsta;
1305 	config_ecode = (u_char)vd->vd_dcb.err_code;
1306 	if (config_status & VDERR_HARD) {
1307 		if (vd->vd_type == VDTYPE_SMDE) {
1308 			/*
1309 			 * If drive status was updated successfully,
1310 			 * STA_US (unit selected) should be set
1311 			 * if the drive is attached and powered up.
1312 			 * (But only if we've guessed right on SMD
1313 			 * vs. ESDI; if that flag is wrong, we won't
1314 			 * see the drive.)  If we don't see STA_US
1315 			 * with either SMD or ESDI set for the unit,
1316 			 * we assume that the drive doesn't exist,
1317 			 * and don't wait for it to spin up.
1318 			 */
1319 			(void) vdcmd(vm, VDOP_STATUS, 5, vi->ui_slave);
1320 			uncache(&vdaddr->vdstatus[vi->ui_slave]);
1321 			if (vdaddr->vdstatus[vi->ui_slave] & STA_US)
1322 				saw_drive = 1;
1323 			else if (lp->d_devflags == 0) {
1324 				lp->d_devflags = VD_ESDI;
1325 				goto top;
1326 			}
1327 		} else
1328 			saw_drive = 1;
1329 		if ((config_status & (DCBS_OCYL|DCBS_NRDY)) == 0)
1330 			printf("dk%d: config error %b ecode %x\n", vi->ui_unit,
1331 			   config_status, VDERRBITS, config_ecode);
1332 		else if ((vd->vd_flags & VD_STARTED) == 0 && saw_drive) {
1333 			int started;
1334 
1335 			printf(" starting drives, wait ... ");
1336 			vd->vd_flags |= VD_STARTED;
1337 			started = (vdcmd(vm, VDOP_START, 10) == 1);
1338 			DELAY(62000000);
1339 			printf("done\n");
1340 			lp->d_devflags = 0;
1341 			if (started)
1342 				goto top;
1343 		}
1344 		return (0);
1345 	}
1346 	dk->dk_dcb.devselect |= lp->d_devflags;
1347 	return (1);
1348 }
1349 
1350 /*
1351  * Perform a command w/o trailer.
1352  */
1353 vdcmd(vm, cmd, t, slave)
1354 	register struct vba_ctlr *vm;
1355 {
1356 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
1357 
1358 	vd->vd_dcb.opcode = cmd;		/* command */
1359 	vd->vd_dcb.intflg = DCBINT_NONE;
1360 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
1361 	vd->vd_dcb.operrsta = 0;
1362 	vd->vd_dcb.devselect = slave;
1363 	vd->vd_dcb.trailcnt = 0;
1364 	vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
1365 	vd->vd_mdcb.mdcb_status = 0;
1366 	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
1367 	if (!vdpoll(vm, t)) {
1368 		printf(" during init\n");
1369 		return (0);
1370 	}
1371 	return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0);
1372 }
1373 
1374 /*
1375  * Poll controller until operation
1376  * completes or timeout expires.
1377  */
1378 vdpoll(vm, t)
1379 	register struct vba_ctlr *vm;
1380 	register int t;
1381 {
1382 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
1383 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
1384 
1385 	t *= 1000;
1386 	for (;;) {
1387 		uncache(&vd->vd_dcb.operrsta);
1388 		if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT))
1389 			break;
1390 		if (--t <= 0) {
1391 			printf("vd%d: controller timeout", vm->um_ctlr);
1392 			VDABORT(vdaddr, vd->vd_type);
1393 			return (0);
1394 		}
1395 		DELAY(1000);
1396 	}
1397 	if (vd->vd_type == VDTYPE_SMDE) {
1398 		do {
1399 			DELAY(50);
1400 			uncache(&vdaddr->vdcsr);
1401 		} while (vdaddr->vdcsr & CS_GO);
1402 	 	DELAY(300);
1403 		uncache(&vd->vd_dcb.err_code);
1404 	}
1405 	DELAY(200);
1406 	uncache(&vd->vd_dcb.operrsta);
1407 	return (1);
1408 }
1409 
1410 #ifdef COMPAT_42
1411 struct	vdst {
1412 	int	nsec;		/* sectors/track */
1413 	int	ntrack;		/* tracks/cylinder */
1414 	int	ncyl;		/* cylinders */
1415 	int	secsize;	/* sector size */
1416 	char	*name;		/* type name */
1417 	struct {
1418 		int	off;	/* partition offset in sectors */
1419 		int	size;	/* partition size in sectors */
1420 	} parts[8];
1421 } vdst[] = {
1422 	{ 66, 23, 850, 512, "NEC 800",
1423 		{0,	 1290300},	/* a cyl   0 - 849 */
1424 	},
1425 	{ 64, 20, 842, 512, "2361a",
1426 		{0,	 61440},	/* a cyl   0 - 47 */
1427 		{61440,	 67840},	/* b cyl  48 - 100 */
1428 		{129280, 942080}, 	/* c cyl 101 - 836 */
1429 		{0,      1071360}, 	/* d cyl   0 - 836 */
1430 		{449280, 311040},	/* e cyl 351 - 593 */
1431 		{760320, 311040}, 	/* f cyl 594 - 836 */
1432 		{449280, 622080},	/* g cyl 351 - 836 */
1433 		{129280, 320000}	/* h cyl 101 - 350 */
1434 	},
1435 	{ 48, 24, 711, 512, "xsd",
1436 		{0,	 61056},	/* a cyl   0 - 52 */
1437 		{61056,	 61056},	/* b cyl  53 - 105 */
1438 		{122112, 691200}, 	/* c cyl 106 - 705 */
1439 		{237312, 576000}, 	/* d cyl 206 - 705 */
1440 		{352512, 460800},	/* e cyl 306 - 705 */
1441 		{467712, 345600}, 	/* f cyl 406 - 705 */
1442 		{582912, 230400},	/* g cyl 506 - 705 */
1443 		{698112, 115200}	/* h cyl 606 - 705 */
1444 	},
1445 	{ 44, 20, 842, 512, "eagle",
1446 		{0,	 52800},	/* egl0a cyl   0 - 59 */
1447 		{52800,	 66000},	/* egl0b cyl  60 - 134 */
1448 		{118800, 617760}, 	/* egl0c cyl 135 - 836 */
1449 		{736560, 4400}, 	/* egl0d cyl 837 - 841 */
1450 		{0, 	 736560},	/* egl0e cyl   0 - 836 */
1451 		{0, 	 740960}, 	/* egl0f cyl   0 - 841 */
1452 		{118800, 310640},	/* egl0g cyl 135 - 487 */
1453 		{429440, 307120}	/* egl0h cyl 488 - 836 */
1454 	},
1455 	{ 64, 10, 823, 512, "fuj",
1456 		{0,	 38400},	/* fuj0a cyl   0 - 59 */
1457 		{38400,	 48000},	/* fuj0b cyl  60 - 134 */
1458 		{86400,	 437120}, 	/* fuj0c cyl 135 - 817 */
1459 		{159360, 364160}, 	/* fuj0d cyl 249 - 817 */
1460 		{232320, 291200},	/* fuj0e cyl 363 - 817 */
1461 		{305280, 218240}, 	/* fuj0f cyl 477 - 817 */
1462 		{378240, 145280},	/* fuj0g cyl 591 - 817 */
1463 		{451200, 72320}		/* fug0h cyl 705 - 817 */
1464 	},
1465 	{ 32, 24, 711, 512, "xfd",
1466 		{ 0,	 40704 },	/* a cyl   0 - 52 */
1467 		{ 40704, 40704 },	/* b cyl  53 - 105 */
1468 		{ 81408, 460800 },	/* c cyl 106 - 705 */
1469 		{ 0,	 81408 },	/* d cyl 709 - 710 (a & b) */
1470 		{ 0,	 542208 },	/* e cyl   0 - 705 */
1471 		{ 40704, 501504 },	/* f cyl  53 - 705 (b & c) */
1472 		{ 81408, 230400 },	/* g cyl 106 - 405 (1/2 of c) */
1473 		{ 311808,230400 }	/* h cyl 406 - 705 (1/2 of c) */
1474 	},
1475 	{ 32, 19, 823, 512, "smd",
1476 		{0,	 40128},	/* a cyl   0-65 */
1477 		{40128,  27360},	/* b cyl  66-110 */
1478 		{67488,  429856},	/* c cyl 111-817 */
1479 		{139232, 358112},	/* d cyl 229 - 817 */
1480 		{210976, 286368},	/* e cyl 347 - 817 */
1481 		{282720, 214624},	/* f cyl 465 - 817 */
1482 		{354464, 142880},	/* g cyl 583 - 817 */
1483 		{426208, 71136}		/* h cyl 701 - 817 */
1484 	},
1485 	{ 18, 15, 1224, 1024, "mxd",
1486 		{0,	 21600},	/* a cyl   0-79 */
1487 		{21600,  22410},	/* b cyl  80-162 */
1488 		{44010,  285120},	/* c cyl 163-1217 */
1489 #ifdef notyet
1490 		{x, 237600},	/* d cyl y - 1217 */
1491 		{x, 190080},	/* e cyl y - 1217 */
1492 		{x, 142560},	/* f cyl y - 1217 */
1493 		{x, 95040},	/* g cyl y - 1217 */
1494 		{x, 47520}		/* h cyl 701 - 817 */
1495 #endif
1496 	},
1497 	{ 32, 10, 823, 512, "fsd",
1498 		{0,	 19200},	/* a cyl   0 -  59 */
1499 		{19200,	 24000},	/* b cyl  60 - 134 */
1500 		{43200,	 218560},	/* c cyl 135 - 817 */
1501 	}
1502 };
1503 #define	NVDST	(sizeof (vdst) / sizeof (vdst[0]))
1504 
1505 /*
1506  * Construct a label for an unlabeled pack.  We
1507  * deduce the drive type by reading from the last
1508  * track on successively smaller drives until we
1509  * don't get an error.
1510  */
1511 vdmaptype(vi, lp)
1512 	register struct vba_device *vi;
1513 	register struct disklabel *lp;
1514 {
1515 	register struct vdsoftc *vd;
1516 	register struct vdst *p;
1517 	struct vba_ctlr *vm = vi->ui_mi;
1518 	int i;
1519 
1520 	vd = &vdsoftc[vi->ui_ctlr];
1521 	for (p = vdst; p < &vdst[NVDST]; p++) {
1522 		if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32)
1523 			continue;
1524 		lp->d_nsectors = p->nsec;
1525 		lp->d_ntracks = p->ntrack;
1526 		lp->d_ncylinders = p->ncyl;
1527 		lp->d_secsize = p->secsize;
1528 		DELAY(100000);
1529 		if (!vdreset_drive(vi))
1530 			return (0);
1531 		DELAY(100000);
1532 		vd->vd_dcb.opcode = VDOP_RD;
1533 		vd->vd_dcb.intflg = DCBINT_NONE;
1534 		vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
1535 		vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect;
1536 		vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
1537 		vd->vd_dcb.trail.rwtrail.memadr =
1538 		    vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf);
1539 		vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short);
1540 		vd->vd_dcb.operrsta = 0;
1541 		vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2;
1542 		vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1;
1543 		vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1;
1544 		vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
1545 		vd->vd_mdcb.mdcb_status = 0;
1546 		VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
1547 		if (!vdpoll(vm, 60))
1548 			printf(" during probe\n");
1549 		if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0)
1550 			break;
1551 	}
1552 	if (p >= &vdst[NVDST])
1553 		return (0);
1554 
1555 	for (i = 0; i < 8; i++) {
1556 		lp->d_partitions[i].p_offset = p->parts[i].off;
1557 		lp->d_partitions[i].p_size = p->parts[i].size;
1558 	}
1559 	lp->d_npartitions = 8;
1560 	lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1561 	bcopy(p->name, lp->d_typename, 4);
1562 	return (1);
1563 }
1564 #endif COMPAT_42
1565 #endif
1566