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