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