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