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