xref: /csrg-svn/sys/tahoe/vba/vd.c (revision 25928)
1 /*	vd.c	1.7	86/01/21	*/
2 
3 #include "fsd.h"
4 #if NVD > 0
5 /*
6  * VDDC - Versabus SMD/ESMD driver.
7  */
8 #ifdef VDDCPERF
9 #define	DOSCOPE
10 #endif
11 
12 #include "../tahoe/mtpr.h"
13 #include "../tahoe/pte.h"
14 
15 #include "param.h"
16 #include "buf.h"
17 #include "cmap.h"
18 #include "conf.h"
19 #include "dir.h"
20 #include "dk.h"
21 #include "map.h"
22 #include "systm.h"
23 #include "user.h"
24 #include "vmmac.h"
25 #include "proc.h"
26 #include "uio.h"
27 
28 #include "../tahoevba/vbavar.h"
29 #define	VDGENDATA
30 #include "../tahoevba/vdreg.h"
31 #undef VDGENDATA
32 #include "../tahoevba/scope.h"
33 
34 #define	VDMAXIO		(MAXBPTE*NBPG)
35 #define	DUMPSIZE	64	/* controller limit */
36 
37 #define VDUNIT(x)	(minor(x) >> 3)
38 #define FILSYS(x)	(minor(x) & 0x07)
39 #define PHYS(x)		(vtoph((struct proc *)0, (unsigned)(x)))
40 #define TRUE		1
41 #define	FALSE		0
42 
43 #define CTLR_ERROR	1
44 #define DRIVE_ERROR	2
45 #define HARD_DATA_ERROR	3
46 #define SOFT_DATA_ERROR	4
47 
48 #define b_cylin	b_resid
49 #define b_daddr	b_error
50 
51 struct	vba_ctlr *vdminfo[NVD];
52 struct  vba_device *vddinfo[NFSD];
53 int	vdprobe(), vdslave(), vdattach(), vddgo();
54 struct	vba_driver vddriver =
55     { vdprobe, vdslave, vdattach, vddgo, vddcaddr, "smd/fsd",
56       vddinfo, "vd", vdminfo };
57 
58 /*
59  * Per-drive state.
60  */
61 typedef struct {
62 	struct	buf raw_q_element;
63 	short	sec_per_blk;
64 	short	sec_per_cyl;
65 	char	status;
66 	struct	buf xfer_queue;
67 	int	drive_type;
68 	fs_tab	info;
69 } unit_tab;
70 
71 /*
72  * Per-controller state.
73  */
74 typedef struct {
75 	char	ctlr_type;	/* controller type */
76 	struct	pte *map;	/* i/o page map */
77 	caddr_t	utl;		/* mapped i/o space */
78 	u_int	cur_slave:8;	/* last active unit number */
79 	u_int	int_expected:1;	/* expect an interupt */
80 	u_int	ctlr_started:1;	/* start command was issued */
81 	u_int	overlap_seeks:1;/* should overlap seeks */
82 	u_int	initdone:1;	/* controller initialization completed */
83 	u_int	off_cylinder:16;/* off cylinder bit map */
84 	u_int	unit_type[16];	/* slave types */
85 	u_int	cur_cyl[16];	/* cylinder last selected */
86 	long	cur_trk[16];	/* track last selected */
87 	fmt_mdcb ctlr_mdcb;	/* controller mdcb */
88 	fmt_dcb	ctlr_dcb;	/* r/w dcb */
89 	fmt_dcb	seek_dcb[4];	/* dcbs for overlapped seeks */
90 	/* buffer for raw/swap i/o */
91 	char	rawbuf[VDMAXIO];
92 } ctlr_tab;
93 
94 ctlr_tab vdctlr_info[NVD];
95 unit_tab vdunit_info[NFSD];
96 
97 /*
98  * See if the controller is really there; if so, initialize it.
99  */
100 vdprobe(reg, vm)
101 	caddr_t reg;
102 	struct vba_ctlr *vm;
103 {
104 	register br, cvec;		/* must be r12, r11 */
105 	register cdr *addr = (cdr *)reg;
106 	register ctlr_tab *ci;
107 	int i;
108 
109 	if (badaddr((caddr_t)reg, 2))
110 		return (0);
111 	ci = &vdctlr_info[vm->um_ctlr];
112 	addr->cdr_reset = 0xffffffff;
113 	DELAY(1000000);
114 	if (addr->cdr_reset != (unsigned)0xffffffff) {
115 		ci->ctlr_type = SMDCTLR;
116 		ci->overlap_seeks = 0;
117 		DELAY(1000000);
118 	} else {
119 		ci->overlap_seeks = 1;
120 		ci->ctlr_type = SMD_ECTLR;
121 		addr->cdr_reserved = 0x0;
122 		DELAY(3000000);
123 		addr->cdr_csr = 0;
124 		addr->mdcb_tcf = AM_ENPDA;
125 		addr->dcb_tcf = AM_ENPDA;
126 		addr->trail_tcf = AM_ENPDA;
127 		addr->data_tcf = AM_ENPDA;
128 		addr->cdr_ccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
129 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
130 	}
131 	/*
132 	 * Allocate page tables.
133 	 */
134 	vbmapalloc(btoc(VDMAXIO)+1, &ci->map, &ci->utl);
135 	/*
136 	 * Initialize all the drives to be of an unknown type.
137 	 */
138 	for (i = 0; i < 15; i++)
139 		ci->unit_type[i] = UNKNOWN;
140 	br = 0x17, cvec = 0xe0 + vm->um_ctlr;	/* XXX */
141 	return (sizeof (*addr));
142 }
143 
144 /*
145  * See if a drive is really there
146  * Try to reset/configure the drive, then test its status.
147  */
148 vdslave(vi, addr)
149 	register struct vba_device *vi;
150 	register cdr *addr;
151 {
152 	register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr];
153 	register unit_tab *ui = &vdunit_info[vi->ui_unit];
154 	register fmt_mdcb *mdcb = &ci->ctlr_mdcb;
155 	register fmt_dcb *dcb = &ci->ctlr_dcb;
156 	register int type;
157 
158 	if (!ci->initdone) {
159 		printf("vd%d: %s controller\n", vi->ui_ctlr,
160 		    ci->ctlr_type == SMDCTLR ? "smd" : "xsmd");
161 		if (vdnotrailer(addr, vi->ui_ctlr, vi->ui_slave, INIT, 10) &
162 		    HRDERR) {
163 			printf("vd%d: init error\n", vi->ui_ctlr);
164 			return (0);
165 		}
166 		if (vdnotrailer(addr, vi->ui_ctlr, vi->ui_slave, DIAG, 10) &
167 		    HRDERR) {
168 			printf("vd%d: diagnostic error\n", vi->ui_ctlr);
169 			return (0);
170 		}
171 		ci->initdone = 1;
172 	}
173 	/*
174 	 * Seek on all drive types starting from the largest one.
175 	 * a successful seek to the last sector/cylinder/track verifies
176 	 * the drive type connected to this port.
177 	 */
178 	for (type = 0; type < nvddrv; type++) {
179 		/* XXX */
180 		if (ci->ctlr_type == SMDCTLR && vdst[type].nsec != 32)
181 			continue;
182 		/* XXX */
183 		if (!vdconfigure_drive(addr, vi->ui_ctlr, vi->ui_slave, type,0))
184 			return (0);
185 		dcb->opcode = (short)RD;
186 		dcb->intflg = NOINT;
187 		dcb->nxtdcb = (fmt_dcb *)0;	/* end of chain */
188 		dcb->operrsta = 0;
189 		dcb->devselect = (char)(vi->ui_slave);
190 		dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long));
191 		dcb->trail.rwtrail.memadr = (char *)PHYS(ci->rawbuf);
192 		dcb->trail.rwtrail.wcount = vdst[type].secsize/sizeof(short);
193 		dcb->trail.rwtrail.disk.cylinder = vdst[type].ncyl - 2;
194 		dcb->trail.rwtrail.disk.track = vdst[type].ntrak - 1;
195 		dcb->trail.rwtrail.disk.sector = vdst[type].nsec - 1;
196 		mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
197 		mdcb->vddcstat = 0;
198 		VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type);
199 		if (!vdpoll(ci, addr, 60))
200 			printf(" during probe\n");
201 		if ((dcb->operrsta&HRDERR) == 0)
202 			break;
203 	}
204 	if (type >= nvddrv) {
205 		/*
206 		 * If reached here, a drive which is not defined in the
207 		 * 'vdst' tables is connected. Cannot set it's type.
208 		 */
209 		printf("vd%d: unknown drive type\n", vi->ui_unit);
210 		return (0);
211 	}
212 	ui->drive_type = type;
213 	ui->info = vdst[type];
214 	ui->sec_per_blk = DEV_BSIZE / ui->info.secsize;
215 	vi->ui_type = type;
216  	vi->ui_dk = 1;
217 	vddriver.ud_dname = ui->info.type_name;
218 	return (1);
219 }
220 
221 vdconfigure_drive(addr, ctlr, slave, type, pass)
222 	register cdr *addr;
223 	int ctlr, slave, type, pass;
224 {
225 	register ctlr_tab *ci = &vdctlr_info[ctlr];
226 
227 	ci->ctlr_dcb.opcode = RSTCFG;		/* command */
228 	ci->ctlr_dcb.intflg = NOINT;
229 	ci->ctlr_dcb.nxtdcb = (fmt_dcb *)0;	/* end of chain */
230 	ci->ctlr_dcb.operrsta = 0;
231 	ci->ctlr_dcb.devselect = (char)slave;
232 	ci->ctlr_dcb.trail.rstrail.ncyl = vdst[type].ncyl;
233 	ci->ctlr_dcb.trail.rstrail.nsurfaces = vdst[type].ntrak;
234 	if (ci->ctlr_type == SMD_ECTLR) {
235 		ci->ctlr_dcb.trailcnt = (char)4;
236 		ci->ctlr_dcb.trail.rstrail.nsectors = vdst[type].nsec;
237 		ci->ctlr_dcb.trail.rstrail.slip_sec = vdst[type].nslip;
238 	} else
239 		ci->ctlr_dcb.trailcnt = (char)2;
240 	ci->ctlr_mdcb.firstdcb = (fmt_dcb *)(PHYS(&ci->ctlr_dcb));
241 	ci->ctlr_mdcb.vddcstat = 0;
242 	VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(&ci->ctlr_mdcb)), ci->ctlr_type);
243 	if (!vdpoll(ci, addr, 5)) {
244 		printf(" during config\n");
245 		return (0);
246 	}
247 	if (ci->ctlr_dcb.operrsta & HRDERR) {
248 		if ((ci->ctlr_dcb.operrsta & (NOTCYLERR|DRVNRDY)) == 0)
249 			printf("vd%d: drive %d: config error\n", ctlr, slave);
250 		else if (pass == 0) {
251 			vdstart_drive(addr, ctlr, slave);
252 			return (vdconfigure_drive(addr, ctlr, slave, type, 1));
253 		} else if (pass == 2)
254 			return (vdconfigure_drive(addr, ctlr, slave, type, 3));
255 		return (0);
256 	}
257 	return (1);
258 }
259 
260 vdstart_drive(addr, ctlr, slave)
261 	cdr *addr;
262 	register int ctlr, slave;
263 {
264 	int error = 0;
265 
266 	printf("vd%d: starting drive %d, wait...", ctlr, slave);
267 	if (vdctlr_info[ctlr].ctlr_started) {
268 printf("DELAY(5500000)...");
269 		DELAY(5500000);
270 		goto done;
271 	}
272 	vdctlr_info[ctlr].ctlr_started = 1;
273 	error = vdnotrailer(addr, ctlr, 0, VDSTART, (slave*6)+62) & HRDERR;
274 	if (!error) {
275 printf("DELAY(%d)...", (slave * 5500000) + 62000000);
276 		DELAY((slave * 5500000) + 62000000);
277 	}
278 done:
279 	printf("\n");
280 	return (error == 0);
281 }
282 
283 vdnotrailer(addr, ctlr, unit, function, time)
284 	register cdr *addr;
285 	int ctlr, unit, function, time;
286 {
287 	register ctlr_tab *ci = &vdctlr_info[ctlr];
288 	fmt_mdcb *mdcb = &ci->ctlr_mdcb;
289 	fmt_dcb *dcb = &ci->ctlr_dcb;
290 
291 	dcb->opcode = function;		/* command */
292 	dcb->intflg = NOINT;
293 	dcb->nxtdcb = (fmt_dcb *)0;	/* end of chain */
294 	dcb->operrsta = 0;
295 	dcb->devselect = (char)unit;
296 	dcb->trailcnt = (char)0;
297 	mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
298 	mdcb->vddcstat = 0;
299 	VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type);
300 	if (!vdpoll(ci, addr, time)) {
301 		printf(" during init\n");
302 		return (DCBCMP|ANYERR|HRDERR|OPABRT);
303 	}
304 	return (dcb->operrsta);
305 }
306 
307 vdattach(vi)
308 	register struct vba_device *vi;
309 {
310 	register unit_tab *ui = &vdunit_info[vi->ui_unit];
311 	register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr];
312 	register struct buf *cq = &vi->ui_mi->um_tab;
313 	register struct buf *uq = cq->b_forw;
314 	register struct buf *start_queue = uq;
315 	register fs_tab	*fs = &ui->info;
316 
317 	ui->info = vdst[vi->ui_type];
318 	ui->sec_per_blk = DEV_BSIZE / ui->info.secsize;
319 	ui->sec_per_cyl = ui->info.nsec * ui->info.ntrak;
320 	ui->xfer_queue.b_dev = vi->ui_slave;
321 	ci->unit_type[vi->ui_slave] = vi->ui_type;
322 	/* load unit into controller's active unit list */
323 	if (uq == NULL) {
324 		cq->b_forw = &ui->xfer_queue;
325 		ui->xfer_queue.b_forw = &ui->xfer_queue;
326 		ui->xfer_queue.b_back = &ui->xfer_queue;
327 	} else {
328 		while (uq->b_forw != start_queue)
329 			uq = uq->b_forw;
330 		ui->xfer_queue.b_forw = start_queue;
331 		ui->xfer_queue.b_back = uq;
332 		uq->b_forw = &ui->xfer_queue;
333 		start_queue->b_back = &ui->xfer_queue;
334 	}
335 	/*
336 	 * (60 / rpm) / (number of sectors per track * (bytes per sector / 2))
337 	 */
338 	dk_mspw[vi->ui_unit] = 120.0 / (fs->rpm * fs->nsec * fs->secsize);
339 }
340 
341 /*ARGSUSED*/
342 vddgo(um)
343 	struct vba_ctlr *um;
344 {
345 
346 }
347 
348 vdstrategy(bp)
349 	register struct buf *bp;
350 {
351 	register int unit = VDUNIT(bp->b_dev);
352 	register struct vba_device *vi = vddinfo[unit];
353 	register par_tab *par;
354 	register unit_tab *ui;
355 	register fs_tab *fs;
356 	register int blks, bn, s;
357 
358 	if (bp->b_bcount == 0 || vi == 0 || vi->ui_alive == 0)
359 		goto bad;
360 	ui = &vdunit_info[unit];
361 	fs = &ui->info;
362 	par = &fs->partition[FILSYS(bp->b_dev)];
363 	blks = (bp->b_bcount + DEV_BSIZE-1) >> DEV_BSHIFT;
364 	if (bp->b_blkno + blks >= par->par_len) {
365 		blks = par->par_len - bp->b_blkno;
366 		if (blks <= 0)
367 			goto bad;
368 		bp->b_bcount = blks * DEV_BSIZE;
369 	}
370 	bn = bp->b_blkno + par->par_start;
371 	bn *= ui->sec_per_blk;
372 	bp->b_daddr = (bn / fs->nsec) % fs->ntrak;
373 	bp->b_cylin = bn / ui->sec_per_cyl;
374 	vbasetup(bp, ui->info.secsize);
375 	s = spl7();
376 	if (ui->xfer_queue.av_forw == NULL) {
377 		register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr];
378 		int slave = vi->ui_slave;
379 
380 		if (bp->b_cylin != ci->cur_cyl[slave] ||
381 		    bp->b_daddr != ci->cur_trk[slave])
382 			ci->off_cylinder |= 1 << slave;
383 	}
384 	bp->b_daddr |= (bn % fs->nsec) << 8;
385 	disksort(&ui->xfer_queue, bp);
386 	if (!vddinfo[unit]->ui_mi->um_tab.b_active++) {
387 		splx(s);
388 		vdstart(vddinfo[unit]->ui_mi);
389 	} else
390 		splx(s);
391 	return;
392 bad:
393 	bp->b_flags |= B_ERROR, bp->b_error = ENXIO;
394 	bp->b_resid = bp->b_bcount;
395 	iodone(bp);
396 }
397 
398 /*
399  * Start up a transfer on a drive.
400  */
401 vdstart(ci)
402 	register struct vba_ctlr *ci;
403 {
404 	register struct buf *cq = &ci->um_tab;
405 	register struct buf *uq = cq->b_forw;
406 
407 	/* search for next ready unit */
408 	cq->b_forw = cq->b_forw->b_forw;
409 	uq = cq->b_forw;
410 	do {
411 		if (uq->av_forw != NULL) {
412 			cq->b_forw = uq;
413 			vdexecute(ci, uq);
414 			return;
415 		}
416 		uq = uq->b_forw;
417 	} while (uq != cq->b_forw);
418 }
419 
420 /*
421  * Initiate seeks for all drives off-cylinder.
422  */
423 vdload_seeks(ci, uq)
424 	register ctlr_tab *ci;
425 	register struct buf *uq;
426 {
427 	register int unit, slave, nseeks;
428 	register fmt_dcb *dcb;
429 	register struct buf *bp;
430 	register struct buf *start_queue = uq;
431 
432 	nseeks = 0;
433 	do {
434 		bp = uq->av_forw;
435 		if (bp != NULL) {
436 			unit = VDUNIT(bp->b_dev);
437 			slave = vddinfo[unit]->ui_slave;
438 			if (ci->off_cylinder & (1 << slave)) {
439 				ci->off_cylinder &= ~(1 << slave);
440 				if (ci->cur_cyl[slave] != bp->b_cylin) {
441 					ci->cur_cyl[slave] = bp->b_cylin;
442 					dk_seek[unit]++;
443 				}
444 				ci->cur_trk[slave] = bp->b_daddr&0xff;
445 				dcb = &ci->seek_dcb[nseeks++];
446 				dcb->opcode = SEEK;
447 				dcb->intflg = NOINT | INT_PBA;
448 				dcb->operrsta = 0;
449 				dcb->devselect = (char)slave;
450 				dcb->trailcnt = (char)1;
451 				dcb->trail.sktrail.skaddr.cylinder =
452 				    bp->b_cylin;
453 				dcb->trail.sktrail.skaddr.track =
454 				    bp->b_daddr & 0xff;
455 				dcb->trail.sktrail.skaddr.sector = 0;
456 			}
457 		}
458 		uq = uq->b_forw;
459 	} while (uq != start_queue && nseeks < 4);
460 	return (nseeks);
461 }
462 
463 extern	vd_int_timeout();
464 /*
465  * Execute the next command on the unit queue uq.
466  */
467 vdexecute(controller_info, uq)
468 	register struct vba_ctlr *controller_info;
469 	register struct buf *uq;
470 {
471 	register struct	buf *bp = uq->av_forw;
472 	register int ctlr = controller_info->um_ctlr;
473 	register ctlr_tab *ci = &vdctlr_info[ctlr];
474 	register int unit = VDUNIT(bp->b_dev);
475 	register int slave = vddinfo[unit]->ui_slave;
476 	register fmt_mdcb *mdcb = &ci->ctlr_mdcb;
477 	register fmt_dcb *dcb = &ci->ctlr_dcb;
478 
479 	/*
480 	 * If there are overlapped seeks to perform, shuffle
481 	 * them to the front of the queue and get them started
482 	 * before any data transfers (to get some parallelism).
483 	 */
484 	if ((ci->off_cylinder & ~(1<<slave)) && ci->overlap_seeks) {
485 		register int i, nseeks;
486 
487 		/* setup seek requests in seek-q */
488 		nseeks = vdload_seeks(ci, uq);
489 		/* place at the front of the master q */
490 		mdcb->firstdcb = (fmt_dcb *)PHYS(&ci->seek_dcb[0]);
491 		/* shuffle any remaining seeks up in the seek-q */
492 		for (i = 1; i < nseeks; i++)
493 			ci->seek_dcb[i-1].nxtdcb =
494 			    (fmt_dcb *)PHYS(&ci->seek_dcb[i]);
495 		ci->seek_dcb[nseeks-1].nxtdcb = (fmt_dcb *)PHYS(dcb);
496 	} else {
497 		if (bp->b_cylin != ci->cur_cyl[slave]) {
498 			ci->cur_cyl[slave] = bp->b_cylin;
499 			dk_seek[unit]++;
500 		}
501 		ci->cur_trk[slave] = bp->b_daddr & 0xff;
502 		ci->off_cylinder = 0;
503 		mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
504 	}
505 	dcb->opcode = (bp->b_flags & B_READ) ? RD : WD;
506 	dcb->intflg = INTDONE;
507 	dcb->nxtdcb = (fmt_dcb *)0;	/* end of chain */
508 	dcb->operrsta = 0;
509 	dcb->devselect = (char)slave;
510 	dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long));
511 	dcb->trail.rwtrail.memadr = (char *)
512 	    vbastart(bp, ci->rawbuf, (long *)ci->map, ci->utl);
513 	dcb->trail.rwtrail.wcount = (short)((bp->b_bcount+1) / sizeof (short));
514 	dcb->trail.rwtrail.disk.cylinder = bp->b_cylin;
515 	dcb->trail.rwtrail.disk.track = bp->b_daddr & 0xff;
516 	dcb->trail.rwtrail.disk.sector = bp->b_daddr >> 8;
517 	mdcb->vddcstat = 0;
518    	dk_wds[unit] += bp->b_bcount / 32;
519 	ci->int_expected = 1;
520 	timeout(vd_int_timeout, (caddr_t)ctlr, 20*60);
521   	dk_busy |= 1 << unit;
522 	scope_out(1);
523 	VDDC_ATTENTION((cdr *)(vdminfo[ctlr]->um_addr),
524 	    (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type);
525 }
526 
527 /*
528  * Watch for lost interrupts.
529  */
530 vd_int_timeout(ctlr)
531 	register int ctlr;
532 {
533 	register ctlr_tab *ci = &vdctlr_info[ctlr];
534 	register fmt_dcb *dcb = &ci->ctlr_dcb;
535 
536 	uncache(&dcb->operrsta);
537 	printf("vd%d: lost interupt, status %x", ctlr, dcb->operrsta);
538 	if (ci->ctlr_type == SMD_ECTLR) {
539 		uncache(&dcb->err_code);
540 		printf(", error code %x", dcb->err_code);
541 	}
542 	printf("\n");
543 	if ((dcb->operrsta&DCBCMP) == 0) {
544 		VDDC_ABORT((cdr *)(vdminfo[ctlr]->um_addr), ci->ctlr_type);
545 		dcb->operrsta |= DCBUSC | DCBABT | ANYERR | HRDERR | CTLRERR;
546 	}
547 	vdintr(ctlr);
548 }
549 
550 /*
551  * Handle a disk interrupt.
552  */
553 vdintr(ctlr)
554 	register int ctlr;
555 {
556 	register ctlr_tab *ci;
557 	register struct buf *cq, *uq, *bp;
558 	register int slave, unit;
559 	register fmt_mdcb  *mdcb;
560 	register fmt_dcb *dcb;
561 	int code, s;
562 
563 	untimeout(vd_int_timeout, (caddr_t)ctlr);
564 	scope_out(2);
565 	ci = &vdctlr_info[ctlr];
566 	if (!ci->int_expected) {
567 		printf("vd%d: stray interrupt\n", ctlr);
568 		return;
569 	}
570 	/*
571 	 * Take first request off controller's queue.
572 	 */
573 	cq = &vdminfo[ctlr]->um_tab;
574 	uq = cq->b_forw;
575 	bp = uq->av_forw;
576 	unit = VDUNIT(bp->b_dev);
577 	dk_busy &= ~(1 << unit);
578 	dk_xfer[unit]++;
579 	ci->int_expected = 0;
580 	/* find associated control blocks */
581 	mdcb = &ci->ctlr_mdcb, uncache(&mdcb->intdcb);
582 	dcb = &ci->ctlr_dcb, uncache(&dcb->operrsta);
583 	if (ci->ctlr_type == SMD_ECTLR)
584 		uncache(&dcb->err_code);
585 	slave = uq->b_dev;
586 	switch (code = vddecode_error(dcb)) {
587 
588 	case CTLR_ERROR:
589 	case DRIVE_ERROR:
590 		if (cq->b_errcnt >= 2)
591 			vdhard_error(ci, bp, dcb);
592 		if (code == CTLR_ERROR)
593 			vdreset_ctlr((cdr *)vdminfo[ctlr]->um_addr, ctlr);
594 		else
595 			reset_drive((cdr *)vdminfo[ctlr]->um_addr, ctlr,
596 			    slave, 2);
597 		if (cq->b_errcnt++ < 2) {	/* retry error */
598 			cq->b_forw = uq->b_back;
599 			vdstart(vdminfo[ctlr]);
600 			return;
601 		}
602 		bp->b_resid = bp->b_bcount;
603 		break;
604 
605 	case HARD_DATA_ERROR:
606 		vdhard_error(ci, bp, dcb);
607 		bp->b_resid = 0;
608 		break;
609 
610 	case SOFT_DATA_ERROR:
611 		vdsoft_error(ci, bp, dcb);
612 		/* fall thru... */
613 
614 	default:			/* operation completed */
615 		bp->b_error = 0;
616 		bp->b_resid = 0;
617 		break;
618 	}
619 	vbadone(bp, ci->rawbuf, (long *)ci->map, ci->utl);
620 	/*
621 	 * Take next request on this unit q, or, if none,
622 	 * the next request on the next active unit q.
623 	 */
624 	s = spl7();
625 	uq->av_forw = bp->av_forw;
626 	if (uq->av_back != bp) {
627 		register struct buf *next;
628 
629 		unit = VDUNIT(uq->av_forw->b_dev);
630 		slave = vddinfo[unit]->ui_slave;
631 		next = uq->av_forw;
632 		if (next->b_cylin != ci->cur_cyl[slave] ||
633 		    (next->b_daddr & 0xff) != ci->cur_trk[slave])
634 			ci->off_cylinder |= 1 << slave;
635 	} else
636 		uq->av_back = NULL;
637 	splx(s);
638 	/* reset controller state */
639 	cq->b_errcnt = 0;
640 	cq->b_active--;
641 	scope_out(3);
642 	if (bp->b_flags & B_ERROR)
643 		bp->b_error = EIO;
644 	iodone(bp);
645 	vdstart(vdminfo[ctlr]);
646 }
647 
648 /*
649  * Convert controller status to internal operation/error code.
650  */
651 vddecode_error(dcb)
652 	register fmt_dcb *dcb;
653 {
654 
655 	if (dcb->operrsta & HRDERR) {
656 		if (dcb->operrsta & (HCRCERR | HCMPERR | UCDATERR | WPTERR |
657 		    DSEEKERR | NOTCYLERR |DRVNRDY | INVDADR))
658 			return (DRIVE_ERROR);
659 		if (dcb->operrsta & (CTLRERR | OPABRT | INVCMD | DNEMEM))
660 			return (CTLR_ERROR);
661 		return (HARD_DATA_ERROR);
662 	}
663 	if (dcb->operrsta & SFTERR)
664 		return (SOFT_DATA_ERROR);
665 	return (0);
666 }
667 
668 /*
669  * Report a hard error.
670  */
671 vdhard_error(ci, bp, dcb)
672 	ctlr_tab *ci;
673 	register struct buf *bp;
674 	register fmt_dcb *dcb;
675 {
676 	unit_tab *ui = &vdunit_info[VDUNIT(bp->b_dev)];
677 
678 	bp->b_flags |= B_ERROR;
679 	harderr(bp, ui->info.type_name);
680 	printf("status %x", dcb->operrsta);
681 	if (ci->ctlr_type == SMD_ECTLR)
682 		printf(" ecode %x", dcb->err_code);
683 	printf("\n");
684 }
685 
686 /*
687  * Report a soft error.
688  */
689 vdsoft_error(ci, bp, dcb)
690 	ctlr_tab *ci;
691 	register struct buf *bp;
692 	register fmt_dcb *dcb;
693 {
694 	unit_tab *ui = &vdunit_info[VDUNIT(bp->b_dev)];
695 
696 	printf("%s%d%c: soft error sn%d status %x", ui->info.type_name,
697 	    minor(bp->b_dev) >> 3, 'a'+(minor(bp->b_dev)&07), bp->b_blkno,
698 	    dcb->operrsta);
699 	if (ci->ctlr_type == SMD_ECTLR)
700 		printf(" ecode %x", dcb->err_code);
701 	printf("\n");
702 }
703 
704 /*ARGSUSED*/
705 vdopen(dev, flag)
706 	dev_t dev;
707 	int flag;
708 {
709 	register unit = VDUNIT(dev);
710 	register struct vba_device *vi = vddinfo[unit];
711 
712 	if (vi == 0 || vi->ui_alive == 0 || vi->ui_type >= nvddrv)
713 		return (ENXIO);
714 	if (vdunit_info[unit].info.partition[FILSYS(dev)].par_len == 0)
715 		return (ENXIO);
716 	return (0);
717 }
718 
719 vdread(dev, uio)
720 	dev_t dev;
721 	struct uio *uio;
722 {
723 	register int unit = VDUNIT(dev);
724 	register unit_tab *ui = &vdunit_info[unit];
725 
726 	if (unit >= NFSD)
727 		return (ENXIO);
728 	return (physio(vdstrategy, &ui->raw_q_element, dev, B_READ,
729 	    minphys, uio));
730 }
731 
732 vdwrite(dev, uio)
733 	dev_t dev;
734 	struct uio *uio;
735 {
736 	register int unit = VDUNIT(dev);
737 	register unit_tab *ui = &vdunit_info[unit];
738 
739 	if (unit >= NFSD)
740 		return (ENXIO);
741 	return (physio(vdstrategy, &ui->raw_q_element, dev, B_WRITE,
742 	    minphys, uio));
743 }
744 
745 /*
746  * Crash dump.
747  */
748 vddump(dev)
749 	dev_t dev;
750 {
751 	register int unit = VDUNIT(dev);
752 	register unit_tab *ui = &vdunit_info[unit];
753 	register fs_tab *fs = &ui->info;
754 	register int ctlr = vddinfo[unit]->ui_ctlr;
755 	register struct vba_ctlr *vba_vdctlr_info = vdminfo[ctlr];
756 	register int filsys = FILSYS(dev);
757 	register cdr *addr = (cdr *)(vba_vdctlr_info->um_addr);
758 	register int cur_blk, blkcount, blocks;
759 	caddr_t memaddr;
760 
761 	vdreset_ctlr(addr, ctlr);
762 	blkcount = maxfree - 2;		/* In 1k byte pages */
763 	if (dumplo + blkcount > fs->partition[filsys].par_len) {
764 		blkcount = fs->partition[filsys].par_len - dumplo;
765 		printf("vd%d: Dump truncated to %dMB\n", unit, blkcount/1024);
766 	}
767 	cur_blk = fs->partition[filsys].par_start + dumplo;
768 	memaddr = 0;
769 	while (blkcount > 0) {
770 		blocks = MIN(blkcount, DUMPSIZE);
771 		if (!vdwrite_block(addr, ctlr, unit, memaddr, cur_blk, blocks))
772 			return (EIO);
773 		blkcount -= blocks;
774 		memaddr += blocks * NBPG;
775 		cur_blk += blocks;
776 	}
777 	return (0);
778 }
779 
780 /*
781  * Write a block to disk during a crash dump.
782  */
783 vdwrite_block(caddr, ctlr, unit, addr, block, blocks)
784 	register cdr *caddr;
785 	register int ctlr, unit;
786 	register caddr_t addr;
787 	register int block, blocks;
788 {
789 	register ctlr_tab *ci = &vdctlr_info[ctlr];
790 	register fmt_mdcb *mdcb = &ci->ctlr_mdcb;
791 	register fmt_dcb *dcb = &ci->ctlr_dcb;
792 	register unit_tab *ui = &vdunit_info[unit];
793 	register fs_tab	 *fs = &ui->info;
794 
795 	block *= (int)ui->sec_per_blk;
796 	blocks *= (int)ui->sec_per_blk;
797 	mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
798 	dcb->intflg = NOINT;
799 	dcb->opcode = WD;
800 	dcb->operrsta = 0;
801 	dcb->devselect = (char)(vddinfo[unit])->ui_slave;
802 	dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long));
803 	dcb->trail.rwtrail.memadr = addr;
804 	dcb->trail.rwtrail.wcount = (short)
805 	    ((blocks * fs->secsize)/ sizeof (short));
806 	dcb->trail.rwtrail.disk.cylinder = (short)(block / ui->sec_per_cyl);
807 	dcb->trail.rwtrail.disk.track = (char)((block / fs->nsec) % fs->ntrak);
808 	dcb->trail.rwtrail.disk.sector = (char)(block % fs->nsec);
809 	VDDC_ATTENTION(caddr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type);
810 	if (!vdpoll(ci, caddr, 5)) {
811 		printf(" during dump\n");
812 		return (0);
813 	}
814 	if (dcb->operrsta & HRDERR) {
815 		printf("vd%d: hard error, status %x\n", unit, dcb->operrsta);
816 		return (0);
817 	}
818 	return (1);
819 }
820 
821 vdsize(dev)
822 	dev_t dev;
823 {
824 	struct vba_device *vi = vddinfo[VDUNIT(dev)];
825 
826 	if (vi == 0 || vi->ui_alive == 0 || vi->ui_type >= nvddrv)
827 		return (-1);
828 	return (vdunit_info[VDUNIT(dev)].info.partition[FILSYS(dev)].par_len);
829 }
830 
831 /*
832  * Perform a controller reset.
833  */
834 vdreset_ctlr(addr, ctlr)
835 	register cdr *addr;
836 	register int ctlr;
837 {
838 	register struct buf *cq = &vdminfo[ctlr]->um_tab;
839 	register struct buf *uq = cq->b_forw;
840 	register ctlr_tab *ci = &vdctlr_info[ctlr];
841 
842 	VDDC_RESET(addr, ci->ctlr_type);
843 	ci->ctlr_started = 0;
844 	if (ci->ctlr_type == SMD_ECTLR) {
845 		addr->cdr_csr = 0;
846 		addr->mdcb_tcf = AM_ENPDA;
847 		addr->dcb_tcf = AM_ENPDA;
848 		addr->trail_tcf = AM_ENPDA;
849 		addr->data_tcf = AM_ENPDA;
850 		addr->cdr_ccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
851 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
852 	}
853 	if (vdnotrailer(addr, ctlr, 0, INIT, 10) & HRDERR) {
854 		printf("failed to init\n");
855 		return (0);
856 	}
857 	if (vdnotrailer(addr, ctlr, 0, DIAG, 10) & HRDERR) {
858 		printf("diagnostic error\n");
859 		return (0);
860 	}
861 	/*  reset all units attached to controller */
862 	uq = cq->b_forw;
863 	do {
864 		reset_drive(addr, ctlr, uq->b_dev, 0);
865 		uq = uq->b_forw;
866 	} while (uq != cq->b_forw);
867 	return (1);
868 }
869 
870 /*
871  * Perform a reset on a drive.
872  */
873 reset_drive(addr, ctlr, slave, start)
874 	register cdr *addr;
875 	register int ctlr, slave, start;
876 {
877 	register int type = vdctlr_info[ctlr].unit_type[slave];
878 
879 	if (type == UNKNOWN)
880 		return;
881 	if (!vdconfigure_drive(addr, ctlr, slave, type, start))
882 		printf("vd%d: drive %d: couldn't reset\n", ctlr, slave);
883 }
884 
885 /*
886  * Poll controller until operation completes
887  * or timeout expires.
888  */
889 vdpoll(ci, addr, t)
890 	register ctlr_tab *ci;
891 	register cdr *addr;
892 	register int t;
893 {
894 	register fmt_dcb *dcb = &ci->ctlr_dcb;
895 
896 	t *= 1000;
897 	uncache(&dcb->operrsta);
898 	while ((dcb->operrsta&(DCBCMP|DCBABT)) == 0) {
899 		DELAY(1000);
900 		uncache(&dcb->operrsta);
901 		if (--t <= 0) {
902 			printf("vd%d: controller timeout", ci-vdctlr_info);
903 			VDDC_ABORT(addr, ci->ctlr_type);
904 			DELAY(30000);
905 			uncache(&dcb->operrsta);
906 			return (0);
907 		}
908 	}
909 	if (ci->ctlr_type == SMD_ECTLR) {
910 		uncache(&addr->cdr_csr);
911 		while (addr->cdr_csr&CS_GO) {
912 			DELAY(50);
913 			uncache(&addr->cdr_csr);
914 		}
915 		DELAY(300);
916 	}
917 	DELAY(200);
918 	uncache(&dcb->operrsta);
919 	return (1);
920 }
921 
922 #ifdef notdef
923 /*
924  * Dump the mdcb and DCB for diagnostic purposes.
925  */
926 vdprintdcb(lp)
927 	register long *lp;
928 {
929 	register int i, dcb, tc;
930 
931 	for (dcb = 0; lp; lp = (long *)(*lp), dcb++) {
932 		lp = (long *)((long)lp | 0xc0000000);
933 		printf("\nDump of dcb%d@%x:", dcb, lp);
934 		for (i = 0, tc = lp[3] & 0xff; i < tc+7; i++)
935 			printf(" %lx", lp[i]);
936 		printf("\n");
937 	}
938 	DELAY(1750000);
939 }
940 #endif
941 #endif
942