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