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