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