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