xref: /csrg-svn/sys/tahoe/vba/vd.c (revision 30574)
1 /*	vd.c	1.16	87/03/01	*/
2 
3 #include "dk.h"
4 #if NVD > 0
5 /*
6  * Versabus VDDC/SMDE driver.
7  */
8 #include "param.h"
9 #include "buf.h"
10 #include "cmap.h"
11 #include "conf.h"
12 #include "dir.h"
13 #include "dkstat.h"
14 #include "disklabel.h"
15 #include "map.h"
16 #include "file.h"
17 #include "systm.h"
18 #include "user.h"
19 #include "vmmac.h"
20 #include "proc.h"
21 #include "uio.h"
22 #include "syslog.h"
23 #include "kernel.h"
24 #include "ioctl.h"
25 
26 #include "../tahoe/cpu.h"
27 #include "../tahoe/mtpr.h"
28 #include "../tahoe/pte.h"
29 
30 #include "../tahoevba/vbavar.h"
31 #include "../tahoevba/vdreg.h"
32 
33 #define	COMPAT_42
34 
35 #define	VDMAXIO		(MAXBPTE*NBPG)
36 
37 #define vdunit(dev)	(minor(dev) >> 3)
38 #define vdpart(dev)	(minor(dev) & 0x07)
39 #define	vdminor(unit,part)	(((unit) << 3) | (part))
40 
41 struct	vba_ctlr *vdminfo[NVD];
42 struct  vba_device *vddinfo[NDK];
43 int	vdprobe(), vdslave(), vdattach(), vddgo();
44 long	vdaddr[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 };
45 struct	vba_driver vddriver =
46   { vdprobe, vdslave, vdattach, vddgo, vdaddr, "dk", vddinfo, "vd", vdminfo };
47 
48 /*
49  * Per-controller state.
50  */
51 struct vdsoftc {
52 	u_short	vd_flags;
53 #define	VD_INIT		0x1	/* controller initialized */
54 #define	VD_STARTED	0x2	/* start command issued */
55 #define	VD_DOSEEKS	0x4	/* should overlap seeks */
56 	u_short	vd_type;	/* controller type */
57 	u_short	vd_wticks;	/* timeout */
58 	struct	mdcb vd_mdcb;	/* master command block */
59 	u_long	vd_mdcbphys;	/* physical address of vd_mdcb */
60 	struct	dcb vd_dcb;	/* i/o command block */
61 	u_long	vd_dcbphys;	/* physical address of vd_dcb */
62 	struct	pte *vd_map;	/* i/o page map */
63 	caddr_t	vd_utl;		/* mapped i/o space */
64 	caddr_t	vd_rawbuf;	/* buffer for raw+swap i/o */
65 } vdsoftc[NVD];
66 
67 /*
68  * Per-drive state.
69  */
70 struct	dksoftc {
71 	u_short	dk_state;	/* open fsm */
72 	u_short	dk_openpart;	/* units open on this drive */
73 	u_int	dk_curcyl;	/* last selected cylinder */
74 	struct	dcb dk_dcb;	/* seek command block */
75 	u_long	dk_dcbphys;	/* physical address of dk_dcb */
76 } dksoftc[NDK];
77 
78 /*
79  * Drive states.  Used during steps of open/initialization.
80  * States < OPEN (> 0) are transient, during an open operation.
81  * OPENRAW is used for unabeled disks, to allow format operations.
82  */
83 #define	CLOSED		0		/* disk is closed */
84 #define	WANTOPEN	1		/* open requested, not started */
85 #define	WANTOPENRAW	2		/* open requested, no label */
86 #define	RDLABEL		3		/* reading pack label */
87 #define	OPEN		4		/* intialized and ready */
88 #define	OPENRAW		5		/* open, no label */
89 
90 struct	buf rdkbuf[NDK];	/* raw i/o buffer headers */
91 struct	buf dkutab[NDK];	/* i/o queue headers */
92 struct	disklabel dklabel[NDK];	/* pack labels */
93 
94 #define b_cylin	b_resid
95 #define	b_track	b_error		/* used for seek commands */
96 #define	b_seekf	b_forw		/* second queue on um_tab */
97 #define	b_seekl	b_back		/* second queue on um_tab */
98 
99 int	vdwstart, vdwatch();
100 
101 /*
102  * See if the controller is really there; if so, initialize it.
103  */
104 vdprobe(reg, vm)
105 	caddr_t reg;
106 	struct vba_ctlr *vm;
107 {
108 	register br, cvec;		/* must be r12, r11 */
109 	register struct vddevice *vdaddr = (struct vddevice *)reg;
110 	struct vdsoftc *vd;
111 	int s;
112 
113 #ifdef lint
114 	br = 0; cvec = br; br = cvec;
115 	vdintr(0);
116 #endif
117 	if (badaddr((caddr_t)reg, 2))
118 		return (0);
119 	vd = &vdsoftc[vm->um_ctlr];
120 	vdaddr->vdreset = 0xffffffff;
121 	DELAY(1000000);
122 	if (vdaddr->vdreset != (unsigned)0xffffffff) {
123 		vd->vd_type = VDTYPE_VDDC;
124 		vd->vd_flags &= ~VD_DOSEEKS;
125 		DELAY(1000000);
126 	} else {
127 		vd->vd_type = VDTYPE_SMDE;
128 		vd->vd_flags |= VD_DOSEEKS;
129 		vdaddr->vdrstclr = 0;
130 		DELAY(3000000);
131 		vdaddr->vdcsr = 0;
132 		vdaddr->vdtcf_mdcb = AM_ENPDA;
133 		vdaddr->vdtcf_dcb = AM_ENPDA;
134 		vdaddr->vdtcf_trail = AM_ENPDA;
135 		vdaddr->vdtcf_data = AM_ENPDA;
136 		vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS |
137 		    XMD_32BIT | BSZ_16WRD |
138 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
139 	}
140 	vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb);
141 	vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb);
142 	vm->um_addr = reg;		/* XXX */
143 	s = spl7();
144 	if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) {
145 		printf("vd%d: %s cmd failed\n", vm->um_ctlr,
146 		    vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
147 		splx(s);
148 		return (0);
149 	}
150 	splx(s);
151 	/*
152 	 * Allocate page tables and i/o buffer.
153 	 */
154 	vbmapalloc(btoc(VDMAXIO)+1, &vd->vd_map, &vd->vd_utl);
155 	vd->vd_rawbuf = calloc(VDMAXIO);
156 	br = 0x17, cvec = 0xe0 + vm->um_ctlr;	/* XXX */
157 	return (sizeof (struct vddevice));
158 }
159 
160 /*
161  * See if a drive is really there.
162  *
163  * Can't read pack label here as various data structures
164  * aren't setup for doing a read in a straightforward
165  * manner.  Instead just probe for the drive and leave
166  * the pack label stuff to the attach routine.
167  */
168 vdslave(vi, addr)
169 	register struct vba_device *vi;
170 	struct vddevice *vdaddr;
171 {
172 	register struct disklabel *lp = &dklabel[vi->ui_unit];
173 	struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
174 
175 	if ((vd->vd_flags&VD_INIT) == 0) {
176 		printf("vd%d: %s controller\n", vi->ui_ctlr,
177 		    vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE");
178 		vd->vd_flags |= VD_INIT;
179 	}
180 
181 	/*
182 	 * Initialize label enough to do a reset on
183 	 * the drive.  The remainder of the default
184 	 * label values will be filled in in vdinit
185 	 * at attach time.
186 	 */
187 	lp->d_secsize = DEV_BSIZE / 2;		/* XXX */
188 	lp->d_nsectors = 32;
189 	lp->d_ntracks = 24;
190 	lp->d_ncylinders = 711;
191 	lp->d_secpercyl = 32*24;
192 	return (vdreset_drive(vi));
193 }
194 
195 /*
196  * Read pack label.
197  */
198 vdattach(vi)
199 	register struct vba_device *vi;
200 {
201 	register int unit = vi->ui_unit;
202 	register struct dksoftc *dk = &dksoftc[unit];
203 	register struct disklabel *lp;
204 
205 	/*
206 	 * Try to initialize device and read pack label.
207 	 */
208 	if (vdinit(vdminor(unit, 0), 0) != 0) {
209 		printf(": unknown drive type");
210 		return;
211 	}
212 	/*
213 	 * Initialize invariant portion of
214 	 * dcb used for overlapped seeks.
215 	 */
216 	dk->dk_dcb.opcode = VDOP_SEEK;
217 	dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA;
218 	dk->dk_dcb.devselect = vi->ui_slave;
219 	dk->dk_dcb.trailcnt = sizeof (trseek) / sizeof (long);
220 	dk->dk_dcb.trail.sktrail.skaddr.sector = 0;
221 	dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb);
222 	lp = &dklabel[unit];
223 	printf(": %s <ntrak %d, ncyl %d, nsec %d>",
224 	    lp->d_typename, lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors);
225 	/*
226 	 * (60 / rpm) / (sectors per track * (bytes per sector / 2))
227 	 */
228 	if (vi->ui_dk >= 0)
229 		dk_mspw[vi->ui_dk] = 120.0 /
230 		    (lp->d_rpm * lp->d_nsectors * lp->d_secsize);
231 #ifdef notyet
232 	addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp);
233 #endif
234 }
235 
236 /*ARGSUSED*/
237 vdopen(dev, flags)
238 	dev_t dev;
239 	int flags;
240 {
241 	register unit = vdunit(dev);
242 	register struct disklabel *lp;
243 	register struct dksoftc *dk;
244 	register struct partition *pp;
245 	struct vba_device *vi;
246 	int s, error, part = vdpart(dev);
247 	daddr_t start, end;
248 
249 	if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
250 		return (ENXIO);
251 	lp = &dklabel[unit];
252 	dk = &dksoftc[unit];
253 
254 	s = spl7();
255 	while (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
256 	    dk->dk_state != CLOSED)
257 		sleep((caddr_t)dk, PZERO+1);
258 	splx(s);
259 	if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
260 		if (error = vdinit(dev, flags))
261 			return (error);
262 
263 	if (vdwstart == 0) {
264 		timeout(vdwatch, (caddr_t)0, hz);
265 		vdwstart++;
266 	}
267 	/*
268 	 * Warn if a partion is opened
269 	 * that overlaps another partition which is open
270 	 * unless one is the "raw" partition (whole disk).
271 	 */
272 #define	RAWPART		2		/* 'c' partition */	/* XXX */
273 	if ((dk->dk_openpart & (1 << part)) == 0 &&
274 	    part != RAWPART) {
275 		pp = &lp->d_partitions[part];
276 		start = pp->p_offset;
277 		end = pp->p_offset + pp->p_size;
278 		for (pp = lp->d_partitions;
279 		     pp < &lp->d_partitions[lp->d_npartitions]; pp++) {
280 			if (pp->p_offset + pp->p_size <= start ||
281 			    pp->p_offset >= end)
282 				continue;
283 			if (pp - lp->d_partitions == RAWPART)
284 				continue;
285 			if (dk->dk_openpart & (1 << (pp - lp->d_partitions)))
286 				log(LOG_WARNING,
287 				    "dk%d%c: overlaps open partition (%c)\n",
288 				    unit, part + 'a',
289 				    pp - lp->d_partitions + 'a');
290 		}
291 	}
292 	if (part >= lp->d_npartitions)
293 		return (ENXIO);
294 	dk->dk_openpart |= 1 << part;
295 	return (0);
296 }
297 
298 vdclose(dev, flags)
299 	dev_t dev;
300 	int flags;
301 {
302 	register int unit = vdunit(dev);
303 	register struct dksoftc *dk = &dksoftc[unit];
304 
305 	dk->dk_openpart &= ~(1 << vdpart(dev));
306 	/*
307 	 * Should wait for i/o to complete on this partition
308 	 * even if others are open, but wait for work on blkflush().
309 	 */
310 	if (dk->dk_openpart == 0) {
311 		int s = spl7();
312 		while (dkutab[unit].b_actf)
313 			sleep((caddr_t)dk, PZERO-1);
314 		splx(s);
315 		dk->dk_state = CLOSED;
316 	}
317 }
318 
319 vdinit(dev, flags)
320 	dev_t dev;
321 	int flags;
322 {
323 	register struct buf *bp = NULL;
324 	register struct disklabel *lp;
325 	register struct dksoftc *dk;
326 	struct vba_device *vi;
327 	struct disklabel *dlp;
328 	int unit = vdunit(dev), error = 0;
329 	extern int cold;
330 
331 	dk = &dksoftc[unit];
332 	if (flags & O_NDELAY) {
333 		dk->dk_state = OPENRAW;
334 		goto done;
335 	}
336 
337 	/*
338 	 * Initialize portion of the label
339 	 * not set up in the slave routine.
340 	 */
341 	dk->dk_state = RDLABEL;
342 	lp = &dklabel[unit];
343 	lp->d_secperunit = 0x1fffffff;
344 	lp->d_npartitions = 1;
345 	lp->d_partitions[0].p_size = 0x1fffffff;
346 	lp->d_partitions[0].p_offset = 0;
347 
348 	bp = geteblk(DEV_BSIZE);		/* max sector size */
349 	bp->b_dev = dev;
350 	bp->b_blkno = LABELSECTOR;
351 	bp->b_bcount = DEV_BSIZE;
352 	bp->b_flags = B_BUSY | B_READ;
353 	bp->b_cylin = LABELSECTOR / lp->d_secpercyl;
354 	vdstrategy(bp);
355 	biowait(bp);
356 	if (bp->b_flags & B_ERROR) {
357 		error = u.u_error;		/* XXX */
358 		u.u_error = 0;
359 		dk->dk_state = CLOSED;
360 		goto done;
361 	}
362 	vi = vddinfo[unit];
363 	dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET);
364 	if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
365 	    dkcksum(dlp) == 0) {
366 		*lp = *dlp;
367 		/*
368 		 * Now that we have the label, configure
369 		 * the correct drive parameters.
370 		 */
371 		if (!vdreset_drive(vi))
372 			dk->dk_state = CLOSED;
373 		else
374 			dk->dk_state = OPEN;
375 	} else {
376 		if (cold)
377 			printf(": no disk label");
378 		else
379 			log(LOG_ERR, "dk%d: no disk label\n", vi->ui_unit);
380 #ifdef COMPAT_42
381 		if (!vdmaptype(vi, lp)) {
382 			error = ENXIO;
383 			dk->dk_state = CLOSED;
384 		} else
385 			dk->dk_state = OPEN;
386 #else
387 		dk->dk_state = OPENRAW;
388 #endif
389 	}
390 done:
391 	if (bp) {
392 		bp->b_flags = B_INVAL | B_AGE;
393 		brelse(bp);
394 	}
395 	wakeup((caddr_t)dk);
396 	return (error);
397 }
398 
399 /*ARGSUSED*/
400 vddgo(vm)
401 	struct vba_device *vm;
402 {
403 
404 }
405 
406 vdstrategy(bp)
407 	register struct buf *bp;
408 {
409 	register struct vba_device *vi;
410 	register struct disklabel *lp;
411 	register struct dksoftc *dk;
412 	register int unit;
413 	register daddr_t sn;
414 	struct buf *dp;
415 	daddr_t sz, maxsz;
416 	int part, s;
417 
418 	sz = bp->b_bcount;
419 	sz = (sz + DEV_BSIZE - 1) >> DEV_BSHIFT;
420 	unit = vdunit(bp->b_dev);
421 	if (unit > NDK) {
422 		bp->b_error = ENXIO;
423 		goto bad;
424 	}
425 	vi = vddinfo[unit];
426 	lp = &dklabel[unit];
427 	if (vi == 0 || vi->ui_alive == 0) {
428 		bp->b_error = ENXIO;
429 		goto bad;
430 	}
431 	dk = &dksoftc[unit];
432 	if (dk->dk_state < OPEN)
433 		goto q;
434 	part = vdpart(bp->b_dev);
435 	if ((dk->dk_openpart & (1 << part)) == 0) {
436 		bp->b_error = ENODEV;
437 		goto bad;
438 	}
439 	maxsz = lp->d_partitions[part].p_size;
440 	sn = bp->b_blkno;
441 	if (sn < 0 || sn + sz > maxsz) {
442 		if (sn == maxsz) {
443 			bp->b_resid = bp->b_bcount;
444 			goto done;
445 		}
446 		sz = maxsz - bp->b_blkno;
447 		if (sz <= 0) {
448 			bp->b_error = EINVAL;
449 			goto bad;
450 		}
451 		bp->b_bcount = sz * lp->d_secsize;
452 	}
453 	bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl;
454 q:
455 	vbasetup(bp, lp->d_secsize);
456 	s = spl7();
457 	dp = &dkutab[vi->ui_unit];
458 	disksort(dp, bp);
459 	if (!dp->b_active) {
460 		(void) vdustart(vi);
461 		if (!vi->ui_mi->um_tab.b_active)
462 			vdstart(vi->ui_mi);
463 	}
464 	splx(s);
465 	return;
466 bad:
467 	bp->b_flags |= B_ERROR;
468 done:
469 	biodone(bp);
470 	return;
471 }
472 
473 vdustart(vi)
474 	register struct vba_device *vi;
475 {
476 	register struct buf *bp, *dp;
477 	register struct vba_ctlr *vm;
478 	register int unit = vi->ui_unit;
479 	register struct dksoftc *dk;
480 	register struct vdsoftc *vd;
481 	struct disklabel *lp;
482 
483 	dp = &dkutab[unit];
484 	/*
485 	 * If queue empty, nothing to do.
486 	 */
487 	if ((bp = dp->b_actf) == NULL)
488 		return;
489 	/*
490 	 * If drive is off-cylinder and controller supports seeks,
491 	 * place drive on seek queue for controller.
492 	 * Otherwise, place on transfer queue.
493 	 */
494 	vd = &vdsoftc[vi->ui_ctlr];
495 	dk = &dksoftc[unit];
496 	vm = vi->ui_mi;
497 	if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) {
498 		lp = &dklabel[unit];
499 		bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors;
500 		if (vm->um_tab.b_seekf == NULL)
501 			vm->um_tab.b_seekf = dp;
502 		else
503 			vm->um_tab.b_seekl->b_forw = dp;
504 		vm->um_tab.b_seekl = dp;
505 	} else {
506 		if (vm->um_tab.b_actf == NULL)
507 			vm->um_tab.b_actf = dp;
508 		else
509 			vm->um_tab.b_actl->b_forw = dp;
510 		vm->um_tab.b_actl = dp;
511 	}
512 	dp->b_forw = NULL;
513 	dp->b_active++;
514 }
515 
516 /*
517  * Start next transfer on a controller.
518  * There are two queues of drives, the first on-cylinder
519  * and the second off-cylinder from their next transfers.
520  * Perform the first transfer for the first drive on the on-cylinder
521  * queue, if any, otherwise the first transfer for the first drive
522  * on the second queue.  Initiate seeks on remaining drives on the
523  * off-cylinder queue, then move them all to the on-cylinder queue.
524  */
525 vdstart(vm)
526 	register struct vba_ctlr *vm;
527 {
528 	register struct buf *bp;
529 	register struct vba_device *vi;
530 	register struct vdsoftc *vd;
531 	register struct dksoftc *dk;
532 	register struct disklabel *lp;
533 	register int slave;
534 	register struct dcb **dcbp;
535 	struct mdcb *mdcb;
536 	struct buf *dp;
537 	int sn, tn;
538 
539 loop:
540 	/*
541 	 * Pull a request off the controller queue.
542 	 */
543 	if ((dp = vm->um_tab.b_actf) == NULL &&
544 	    (dp = vm->um_tab.b_seekf) == NULL)
545 		return;
546 	if ((bp = dp->b_actf) == NULL) {
547 		vm->um_tab.b_actf = dp->b_forw;
548 		goto loop;
549 	}
550 
551 	/*
552 	 * Mark controller busy, and determine
553 	 * destination of this request.
554 	 */
555 	vm->um_tab.b_active++;
556 	vi = vddinfo[vdunit(bp->b_dev)];
557 	dk = &dksoftc[vi->ui_unit];
558 	sn = bp->b_blkno;
559 	lp = &dklabel[vi->ui_unit];
560 	sn %= lp->d_secpercyl;
561 	tn = sn / lp->d_nsectors;
562 	sn %= lp->d_nsectors;
563 
564 	/*
565 	 * Construct dcb for read/write command.
566 	 */
567 	vd = &vdsoftc[vm->um_ctlr];
568 	slave = vi->ui_slave;
569 	vd->vd_dcb.opcode = (bp->b_flags & B_READ) ? VDOP_RD : VDOP_WD;
570 	vd->vd_dcb.intflg = DCBINT_DONE;
571 	vd->vd_dcb.devselect = slave;
572 	vd->vd_dcb.operrsta = 0;
573 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
574 	vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long);
575 	vd->vd_dcb.trail.rwtrail.memadr = (char *)
576 	    vbastart(bp, vd->vd_rawbuf, (long *)vd->vd_map, vd->vd_utl);
577 	vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1;
578 	vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin;
579 	vd->vd_dcb.trail.rwtrail.disk.track = tn;
580 	vd->vd_dcb.trail.rwtrail.disk.sector = sn;
581 	dk->dk_curcyl = bp->b_cylin;
582 	bp->b_track = 0;		/* init overloaded field */
583 	if (vi->ui_dk >= 0) {
584 		dk_busy |= 1<<vi->ui_dk;
585 		dk_xfer[vi->ui_dk]++;
586 		dk_wds[vi->ui_dk] += bp->b_bcount>>6;
587 	}
588 
589 	/*
590 	 * Look for any seeks to be performed on other drives on this
591 	 * controller.  If overlapped seeks exist, insert seek commands
592 	 * on the controller's command queue before the transfer.
593 	 */
594 	dcbp = &vd->vd_mdcb.mdcb_head;
595 
596 	if (dp == vm->um_tab.b_seekf)
597 		dp = dp->b_forw;
598 	else
599 		dp = vm->um_tab.b_seekf;
600 	for (; dp != NULL; dp = dp->b_forw) {
601 		if ((bp = dp->b_actf) == NULL)
602 			continue;
603 		vi = vddinfo[vdunit(bp->b_dev)];
604 		dk = &dksoftc[vi->ui_unit];
605 		dk->dk_curcyl = bp->b_cylin;
606 		if (vi->ui_dk >= 0)
607 			dk_seek[vi->ui_dk]++;
608 		dk->dk_dcb.operrsta = 0;
609 		dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin;
610 #ifdef notdef
611 		dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_daddr>>8;
612 		dk->dk_dcb.trail.sktrail.skaddr.sector =
613 		    bp->b_daddr & 0xff;
614 #else
615 		dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track;
616 #endif
617 		*dcbp = (struct dcb *)dk->dk_dcbphys;
618 		dcbp = &dk->dk_dcb.nxtdcb;
619 	}
620 	*dcbp = (struct dcb *)vd->vd_dcbphys;
621 	if (vm->um_tab.b_actf)
622 		vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf;
623 	else
624 		vm->um_tab.b_actf = vm->um_tab.b_seekf;
625 	vm->um_tab.b_actl = vm->um_tab.b_seekl;
626 	vm->um_tab.b_seekf = 0;
627 	vm->um_tab.b_seekl = 0;
628 
629 	/*
630 	 * Initiate operation.
631 	 */
632 	vd->vd_mdcb.mdcb_status = 0;
633 	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
634 }
635 
636 #define	DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE)
637 /*
638  * Handle a disk interrupt.
639  */
640 vdintr(ctlr)
641 	register ctlr;
642 {
643 	register struct buf *bp, *dp;
644 	register struct vba_ctlr *vm = vdminfo[ctlr];
645 	register struct vba_device *vi;
646 	register struct vdsoftc *vd = &vdsoftc[ctlr];
647 	register status;
648 	struct dksoftc *dk;
649 
650 	vd->vd_wticks = 0;
651 	if (!vm->um_tab.b_active) {
652 		printf("vd%d: stray interrupt\n", ctlr);
653 		return;
654 	}
655 	/*
656 	 * Get device and block structures, and a pointer
657 	 * to the vba_device for the drive.
658 	 */
659 	dp = vm->um_tab.b_actf;
660 	bp = dp->b_actf;
661 	vi = vddinfo[vdunit(bp->b_dev)];
662 	if (vi->ui_dk >= 0)
663 		dk_busy &= ~(1<<vi->ui_dk);
664 	/*
665 	 * Check for and process errors on
666 	 * either the drive or the controller.
667 	 */
668 	uncache(&vd->vd_dcb.operrsta);
669 	status = vd->vd_dcb.operrsta;
670 	if (status & VDERR_HARD) {
671 		if (status & DCBS_WPT) {
672 			/*
673 			 * Give up on write locked devices immediately.
674 			 */
675 			printf("dk%d: write locked\n", vi->ui_unit);
676 			bp->b_flags |= B_ERROR;
677 		} else if (status & VDERR_RETRY) {
678 			if (status & VDERR_DRIVE) {
679 				if (!vdreset_drive(vi))
680 					vi->ui_alive = 0;
681 			} else if (status & VDERR_CTLR)
682 				vdreset_ctlr(vm);
683 			/*
684 			 * Retry transfer once, unless reset failed.
685 			 */
686 			if (!vi->ui_alive || bp->b_errcnt++ >= 2)
687 				goto hard;
688 			vm->um_tab.b_active = 0;	/* force retry */
689 		} else  {
690 	hard:
691 			bp->b_flags |= B_ERROR;
692 			/* NEED TO ADJUST b_blkno to failed sector */
693 			harderr(bp, "dk");
694 			printf("status %x (%b)", status,
695 			   status &~ DONTCARE, VDERRBITS);
696 			if (vd->vd_type == VDTYPE_SMDE) {
697 				uncache(&vd->vd_dcb.err_code);
698 				printf(" ecode %x", vd->vd_dcb.err_code);
699 			}
700 			printf("\n");
701 		}
702 	} else if (status & DCBS_SOFT)
703 		vdsofterr(vd, bp, &vd->vd_dcb);
704 	if (vm->um_tab.b_active) {
705 		vm->um_tab.b_active = 0;
706 		vm->um_tab.b_errcnt = 0;
707 		vm->um_tab.b_actf = dp->b_forw;
708 		dp->b_active = 0;
709 		dp->b_errcnt = 0;
710 		dp->b_actf = bp->av_forw;
711 		bp->b_resid = 0;
712 		vbadone(bp, vd->vd_rawbuf, (long *)vd->vd_map, vd->vd_utl);
713 		biodone(bp);
714 		/*
715 		 * If this unit has more work to do,
716 		 * then start it up right away.
717 		 */
718 		if (dp->b_actf)
719 			vdustart(vi);
720 		else if ((dk = &dksoftc[vi->ui_unit])->dk_openpart == 0)
721 			wakeup((caddr_t)dk);
722 	}
723 	/*
724 	 * If there are devices ready to
725 	 * transfer, start the controller.
726 	 */
727 	if (vm->um_tab.b_actf)
728 		vdstart(vm);
729 }
730 
731 vdsofterr(vd, bp, dcb)
732 	struct vdsoftc *vd;
733 	register struct buf *bp;
734 	register struct dcb *dcb;
735 {
736 	int unit = vdunit(bp->b_dev), status = dcb->operrsta;
737 	char part = 'a' + vdpart(bp->b_dev);
738 
739 	if (status != (DCBS_DCE|DCBS_CCD|DCBS_SOFT|DCBS_ERR)) {
740 		if (vd->vd_type == VDTYPE_SMDE)
741 			uncache(&dcb->err_code);
742 		log(LOG_WARNING, "dk%d%c: soft error sn%d status %b ecode %x\n",
743 		    unit, part, bp->b_blkno, status, VDERRBITS, dcb->err_code);
744 	} else
745 		log(LOG_WARNING, "dk%d%c: soft ecc sn%d\n",
746 		    unit, part, bp->b_blkno);
747 }
748 
749 vdread(dev, uio)
750 	dev_t dev;
751 	struct uio *uio;
752 {
753 	register int unit = vdunit(dev);
754 
755 	if (unit >= NDK)
756 		return (ENXIO);
757 	return (physio(vdstrategy, &rdkbuf[unit], dev, B_READ, minphys, uio));
758 }
759 
760 vdwrite(dev, uio)
761 	dev_t dev;
762 	struct uio *uio;
763 {
764 	register int unit = vdunit(dev);
765 
766 	if (unit >= NDK)
767 		return (ENXIO);
768 	return (physio(vdstrategy, &rdkbuf[unit], dev, B_WRITE, minphys, uio));
769 }
770 
771 vdioctl(dev, cmd, data, flag)
772 	dev_t dev;
773 	int cmd;
774 	caddr_t data;
775 	int flag;
776 {
777 	int unit = vdunit(dev);
778 	register struct disklabel *lp = &dklabel[unit];
779 	int error = 0;
780 
781 	switch (cmd) {
782 
783 	case DIOCGDINFO:
784 		*(struct disklabel *)data = *lp;
785 		break;
786 
787 	case DIOCGPART:
788 		((struct partinfo *)data)->disklab = lp;
789 		((struct partinfo *)data)->part =
790 		    &lp->d_partitions[vdpart(dev)];
791 		break;
792 
793 	case DIOCSDINFO:
794 		if ((flag & FWRITE) == 0)
795 			error = EBADF;
796 		else
797 			*lp = *(struct disklabel *)data;
798 		break;
799 
800 	case DIOCWDINFO: {
801 		struct buf *bp;
802 		struct disklabel *dlp;
803 
804 		if ((flag & FWRITE) == 0) {
805 			error = EBADF;
806 			break;
807 		}
808 		*lp = *(struct disklabel *)data;
809 		bp = geteblk(lp->d_secsize);
810 		bp->b_dev = dev;
811 		bp->b_blkno = LABELSECTOR;
812 		bp->b_bcount = lp->d_secsize;
813 		bp->b_flags = B_READ;
814 		dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET);
815 		vdstrategy(bp);
816 		biowait(bp);
817 		if (bp->b_flags & B_ERROR) {
818 			error = u.u_error;		/* XXX */
819 			u.u_error = 0;
820 			goto bad;
821 		}
822 		*dlp = *lp;
823 		bp->b_flags = B_WRITE;
824 		vdstrategy(bp);
825 		biowait(bp);
826 		if (bp->b_flags & B_ERROR) {
827 			error = u.u_error;		/* XXX */
828 			u.u_error = 0;
829 		}
830 bad:
831 		brelse(bp);
832 		break;
833 	}
834 
835 	default:
836 		error = ENOTTY;
837 		break;
838 	}
839 	return (0);
840 }
841 
842 /*
843  * Watch for lost interrupts.
844  */
845 vdwatch()
846 {
847 	register struct vdsoftc *vd;
848 	register struct vba_ctlr *vm;
849 	register int ctlr, unit;
850 
851 	timeout(vdwatch, (caddr_t)0, hz);
852 	for (ctlr = 0; ctlr < NVD; ctlr++) {
853 		vm = vdminfo[ctlr];
854 		if (vm == 0 || vm->um_alive == 0)
855 			continue;
856 		vd = &vdsoftc[ctlr];
857 		if (!vm->um_tab.b_active) {
858 			for (unit = 0; unit < NDK; unit++)
859 				if (dkutab[unit].b_active &&
860 				    vddinfo[unit]->ui_mi == vm)
861 					goto active;
862 			vd->vd_wticks = 0;
863 			continue;
864 		}
865 active:
866 		vd->vd_wticks++;
867 		if (vd->vd_wticks >= 20) {
868 			vd->vd_wticks = 0;
869 			printf("vd%d: lost interrupt\n", ctlr);
870 			/* abort pending dcb's and restart controller */
871 		}
872 	}
873 }
874 
875 #define	DBSIZE	64	/* controller limit with 1K sectors */
876 /*
877  * Crash dump.
878  */
879 vddump(dev)
880 	dev_t dev;
881 {
882 	register struct vba_device *vi;
883 	register struct vba_ctlr *vm;
884 	register struct disklabel *lp;
885 	register struct vdsoftc *vd;
886 	struct dksoftc *dk;
887 	int part, unit, num;
888 	caddr_t start;
889 
890 	start = 0;
891 	unit = vdunit(dev);
892 	if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
893 		return (ENXIO);
894 	dk = &dksoftc[unit];
895 	if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
896 		return (ENXIO);
897 	lp = &dklabel[unit];
898 	part = vdpart(dev);
899 	if (part >= lp->d_npartitions)
900 		return (ENXIO);
901 	vm = vdminfo[vi->ui_ctlr];
902 	vdreset_ctlr(vm);
903 	if (dumplo < 0)
904 		return (EINVAL);
905 	/*
906 	 * Dumplo and maxfree are in pages.
907 	 */
908 	num = maxfree * (NBPG / lp->d_secsize);
909 	dumplo *= NBPG / lp->d_secsize;
910 	if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size)
911 		num = lp->d_partitions[vdpart(dev)].p_size - dumplo;
912 	vd = &vdsoftc[vm->um_ctlr];
913 	vd->vd_dcb.intflg = DCBINT_NONE;
914 	vd->vd_dcb.opcode = VDOP_WD;
915 	vd->vd_dcb.devselect = vi->ui_slave;
916 	vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long);
917 	while (num > 0) {
918 		int nsec, cn, sn, tn;
919 
920 		nsec = MIN(num, DBSIZE);
921 		sn = dumplo + (unsigned)start / lp->d_secsize;
922 		cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) /
923 		    lp->d_secpercyl;
924 		sn %= lp->d_secpercyl;
925 		tn = sn / lp->d_nsectors;
926 		sn %= lp->d_nsectors;
927 		vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
928 		vd->vd_dcb.trail.rwtrail.memadr = start;
929 		vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1;
930 		vd->vd_dcb.trail.rwtrail.disk.cylinder = cn;
931 		vd->vd_dcb.trail.rwtrail.disk.track = tn;
932 		vd->vd_dcb.trail.rwtrail.disk.sector = sn;
933 		vd->vd_dcb.operrsta = 0;
934 		VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
935 		if (!vdpoll(vm, 5)) {
936 			printf(" during dump\n");
937 			return (EIO);
938 		}
939 		if (vd->vd_dcb.operrsta & VDERR_HARD) {
940 			printf("dk%d: hard error, status=%b\n", unit,
941 			    vd->vd_dcb.operrsta, VDERRBITS);
942 			return (EIO);
943 		}
944 		start += nsec * lp->d_secsize;
945 		num -= nsec;
946 	}
947 	return (0);
948 }
949 
950 vdsize(dev)
951 	dev_t dev;
952 {
953 	register int unit = vdunit(dev);
954 	register struct dksoftc *dk;
955 	struct vba_device *vi;
956 	struct disklabel *lp;
957 
958 	if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 ||
959 	    (dk = &dksoftc[unit])->dk_state != OPEN)
960 		return (-1);
961 	lp = &dklabel[unit];
962 	return ((int)lp->d_partitions[vdpart(dev)].p_size);
963 }
964 
965 /*
966  * Perform a controller reset.
967  */
968 vdreset_ctlr(vm)
969 	register struct vba_ctlr *vm;
970 {
971 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
972 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
973 	register int unit;
974 	struct vba_device *vi;
975 
976 	VDRESET(vdaddr, vd->vd_type);
977 	if (vd->vd_type == VDTYPE_SMDE) {
978 		vdaddr->vdcsr = 0;
979 		vdaddr->vdtcf_mdcb = AM_ENPDA;
980 		vdaddr->vdtcf_dcb = AM_ENPDA;
981 		vdaddr->vdtcf_trail = AM_ENPDA;
982 		vdaddr->vdtcf_data = AM_ENPDA;
983 		vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
984 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
985 	}
986 	if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) {
987 		printf("%s cmd failed\n",
988 		    vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
989 		return;
990 	}
991 	for (unit = 0; unit < NDK; unit++)
992 		if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive)
993 			(void) vdreset_drive(vi);
994 }
995 
996 vdreset_drive(vi)
997 	register struct vba_device *vi;
998 {
999 	register struct disklabel *lp = &dklabel[vi->ui_unit];
1000 	struct vba_ctlr *vm = vdminfo[vi->ui_ctlr];
1001 	struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
1002 	struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
1003 
1004 top:
1005 	vd->vd_dcb.opcode = VDOP_CONFIG;		/* command */
1006 	vd->vd_dcb.intflg = DCBINT_NONE;
1007 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
1008 	vd->vd_dcb.operrsta = 0;
1009 	vd->vd_dcb.devselect = vi->ui_slave;
1010 	vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders;
1011 	vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks;
1012 	if (vd->vd_type == VDTYPE_SMDE) {
1013 		vd->vd_dcb.trailcnt = sizeof (treset) / sizeof (long);
1014 		vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors;
1015 		vd->vd_dcb.trail.rstrail.slip_sec = lp->d_trackskew;
1016 		vd->vd_dcb.trail.rstrail.recovery = 0x18f;
1017 	} else
1018 		vd->vd_dcb.trailcnt = 2;		/* XXX */
1019 	vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
1020 	vd->vd_mdcb.mdcb_status = 0;
1021 	VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type);
1022 	if (!vdpoll(vm, 5)) {
1023 		printf(" during config\n");
1024 		return (0);
1025 	}
1026 	if (vd->vd_dcb.operrsta & VDERR_HARD) {
1027 		if (vd->vd_type == VDTYPE_SMDE &&
1028 		    (vdaddr->vdstatus[vi->ui_slave]&STA_US) == 0)
1029 			return (0);
1030 		if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0)
1031 			printf("dk%d: config error\n", vi->ui_unit);
1032 		else if ((vd->vd_flags&VD_STARTED) == 0) {
1033 			int started;
1034 
1035 			printf("vd%d: starting drives, wait ... ", vm->um_ctlr);
1036 			vd->vd_flags |= VD_STARTED;
1037 			started = (vdcmd(vm, VDOP_START, 10) == 1);
1038 			DELAY(62000000);
1039 			printf("\n");
1040 			if (started)
1041 				goto top;
1042 		}
1043 		return (0);
1044 	}
1045 	return (1);
1046 }
1047 
1048 /*
1049  * Perform a command w/o trailer.
1050  */
1051 vdcmd(vm, cmd, t)
1052 	register struct vba_ctlr *vm;
1053 {
1054 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
1055 
1056 	vd->vd_dcb.opcode = cmd;		/* command */
1057 	vd->vd_dcb.intflg = DCBINT_NONE;
1058 	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
1059 	vd->vd_dcb.operrsta = 0;
1060 	vd->vd_dcb.devselect = 0;
1061 	vd->vd_dcb.trailcnt = 0;
1062 	vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
1063 	vd->vd_mdcb.mdcb_status = 0;
1064 	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
1065 	if (!vdpoll(vm, t)) {
1066 		printf(" during init\n");
1067 		return (0);
1068 	}
1069 	return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0);
1070 }
1071 
1072 /*
1073  * Poll controller until operation
1074  * completes or timeout expires.
1075  */
1076 vdpoll(vm, t)
1077 	register struct vba_ctlr *vm;
1078 	register int t;
1079 {
1080 	register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
1081 	register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
1082 
1083 	t *= 1000;
1084 	for (;;) {
1085 		uncache(&vd->vd_dcb.operrsta);
1086 		if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT))
1087 			break;
1088 		if (--t <= 0) {
1089 			printf("vd%d: controller timeout", vm->um_ctlr);
1090 			VDABORT(vdaddr, vd->vd_type);
1091 			DELAY(30000);
1092 			return (0);
1093 		}
1094 		DELAY(1000);
1095 	}
1096 	if (vd->vd_type == VDTYPE_SMDE) {
1097 		do {
1098 			DELAY(50);
1099 			uncache(&vdaddr->vdcsr);
1100 		} while (vdaddr->vdcsr & CS_GO);
1101 		DELAY(300);
1102 	}
1103 	DELAY(200);
1104 	uncache(&vd->vd_dcb.operrsta);
1105 	return (1);
1106 }
1107 
1108 #ifdef COMPAT_42
1109 struct	vdst {
1110 	int	nsec;		/* sectors/track */
1111 	int	ntrack;		/* tracks/cylinder */
1112 	int	ncyl;		/* cylinders */
1113 	char	*name;		/* type name */
1114 	struct {
1115 		int	off;	/* partition offset in sectors */
1116 		int	size;	/* partition size in sectors */
1117 	} parts[8];
1118 } vdst[] = {
1119 	{ 48, 24, 711, "xsd",
1120 		{0,	 30528},	/* a cyl   0 - 52 */
1121 		{30528,	 30528},	/* b cyl  53 - 105 */
1122 		{61056,	 345600}, 	/* c cyl 106 - 705 */
1123 		{118656, 288000}, 	/* d cyl 206 - 705 */
1124 		{176256, 230400},	/* e cyl 306 - 705 */
1125 		{233856, 172800}, 	/* f cyl 406 - 705 */
1126 		{291456, 115200},	/* g cyl 506 - 705 */
1127 		{349056, 57600}		/* h cyl 606 - 705 */
1128 	},
1129 	{ 44, 20, 842, "egl",
1130 		{0,	 26400},	/* egl0a cyl   0 - 59 */
1131 		{26400,	 33000},	/* egl0b cyl  60 - 134 */
1132 		{59400,	 308880}, 	/* egl0c cyl 135 - 836 */
1133 		{368280, 2640}, 	/* egl0d cyl 837 - 842 */
1134 		{0, 368280},		/* egl0e cyl 0 - 836 */
1135 		{0, 370920}, 		/* egl0f cyl 0 - 842 */
1136 		{59400, 155320},	/* egl0g cyl 135 - 487 */
1137 		{214720, 153560}	/* egl0h cyl 488 - 836 */
1138 	},
1139 	{ 64, 10, 823, "fuj",
1140 		{0,	 19200},	/* fuj0a cyl   0 - 59 */
1141 		{19200,	 24000},	/* fuj0b cyl  60 - 134 */
1142 		{43200,	 218560}, 	/* fuj0c cyl 135 - 817 */
1143 		{79680,	 182080}, 	/* fuj0d cyl 249 - 817 */
1144 		{116160, 145600},	/* fuj0e cyl 363 - 817 */
1145 		{152640, 109120}, 	/* fuj0f cyl 477 - 817 */
1146 		{189120, 72640},	/* fuj0g cyl 591 - 817 */
1147 		{225600, 36160}		/* fug0h cyl 705 - 817 */
1148 	},
1149 	{ 32, 24, 711, "xfd",
1150 		{ 0,	 20352 },	/* a cyl   0 - 52 */
1151 		{ 20352, 20352 },	/* b cyl  53 - 105 */
1152 		{ 40704, 230400 },	/* c cyl 106 - 705 */
1153 		{ 0,	 40704 },	/* d cyl 709 - 710 (a & b) */
1154 		{ 0,	 271104 },	/* e cyl   0 - 705 */
1155 		{ 20352, 250752 },	/* f cyl  53 - 705 (b & c) */
1156 		{ 40704, 115200 },	/* g cyl 106 - 405 (1/2 of c) */
1157 		{ 155904,115200 }	/* h cyl 406 - 705 (1/2 of c) */
1158 	},
1159 	{ 32, 19, 823, "smd",
1160 		{0,	 20064},	/* a cyl   0-65 */
1161 		{20064, 13680},		/* b cyl  66-110 */
1162 		{33744, 214928},	/* c cyl 111-817 */
1163 		{69616,	 179056},	/* d cyl 229 - 817 */
1164 		{105488, 143184},	/* e cyl 347 - 817 */
1165 		{141360, 107312},	/* f cyl 465 - 817 */
1166 		{177232, 71440},	/* g cyl 583 - 817 */
1167 		{213104, 35568}		/* h cyl 701 - 817 */
1168 	},
1169 	{ 32, 10, 823, "fsd",
1170 		{0,	 9600},		/* a cyl   0 -  59 */
1171 		{9600,	 12000},	/* b cyl  60 - 134 */
1172 		{21600,	 109280},	/* c cyl 135 - 817 */
1173 		{39840,	 91040},	/* d cyl 249 - 817 */
1174 		{58080,	 72800},	/* e cyl 363 - 817 */
1175 		{76320,	 54560},	/* f cyl 477 - 817 */
1176 		{94560,  36320},	/* g cyl 591 - 817 */
1177 		{112800, 18080}		/* h cyl 705 - 817 */
1178 	}
1179 };
1180 #define	NVDST	(sizeof (vdst) / sizeof (vdst[0]))
1181 
1182 /*
1183  * Construct a label for an unlabeled pack.  We
1184  * deduce the drive type by reading from the last
1185  * track on successively smaller drives until we
1186  * don't get an error.
1187  */
1188 vdmaptype(vi, lp)
1189 	register struct vba_device *vi;
1190 	register struct disklabel *lp;
1191 {
1192 	register struct vdsoftc *vd;
1193 	register struct vdst *p;
1194 	struct vba_ctlr *vm = vdminfo[vi->ui_ctlr];
1195 	int i;
1196 
1197 	vd = &vdsoftc[vi->ui_ctlr];
1198 	for (p = vdst; p < &vdst[NVDST]; p++) {
1199 		if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32)
1200 			continue;
1201 		lp->d_nsectors = p->nsec;
1202 		lp->d_ntracks = p->ntrack;
1203 		lp->d_ncylinders = p->ncyl;
1204 		if (!vdreset_drive(vi))
1205 			return (0);
1206 		vd->vd_dcb.opcode = VDOP_RD;
1207 		vd->vd_dcb.intflg = DCBINT_NONE;
1208 		vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
1209 		vd->vd_dcb.devselect = vi->ui_slave;
1210 		vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long);
1211 		vd->vd_dcb.trail.rwtrail.memadr = (char *)
1212 		    vtoph((struct proc *)0, (unsigned)vd->vd_rawbuf);
1213 		vd->vd_dcb.trail.rwtrail.wcount = 512 / sizeof(short);
1214 		vd->vd_dcb.operrsta = 0;
1215 		vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2;
1216 		vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1;
1217 		vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1;
1218 		vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
1219 		vd->vd_mdcb.mdcb_status = 0;
1220 		VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
1221 		if (!vdpoll(vm, 60))
1222 			printf(" during probe\n");
1223 		if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0)
1224 			break;
1225 	}
1226 	if (p >= &vdst[NVDST]) {
1227 		printf("dk%d: unknown drive type\n", vi->ui_unit);
1228 		return (0);
1229 	}
1230 	for (i = 0; i < 8; i++) {
1231 		lp->d_partitions[i].p_offset = p->parts[i].off;
1232 		lp->d_partitions[i].p_size = p->parts[i].size;
1233 	}
1234 	lp->d_npartitions = 8;
1235 	lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1236 	lp->d_rpm = 3600;
1237 	lp->d_secsize = 512;
1238 	bcopy(p->name, lp->d_typename, 4);
1239 	return (1);
1240 }
1241 #endif COMPAT_42
1242 #endif
1243