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