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