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