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