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