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