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