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