xref: /csrg-svn/sys/tahoe/vba/vd.c (revision 24004)
1 /*	vd.c	1.1	85/07/21	*/
2 
3 #include "fsd.h"
4 #if NVD > 0
5 /*
6 **	VDDC Driver - Versabus to SMD direct interface version.
7 **		Written for TAHOE vmunix, CCI-WDC 9/1/83.
8 */
9 
10 #include "../h/param.h"
11 #include "../h/buf.h"
12 #include "../h/cmap.h"
13 #include "../h/conf.h"
14 #include "../h/dir.h"
15 #include "../h/dk.h"
16 #include "../h/map.h"
17 #include "../machine/mtpr.h"
18 #include "../machine/pte.h"
19 #include "../h/systm.h"
20 #include "../vba/vbavar.h"
21 #include "../h/user.h"
22 #include "../h/vmmac.h"
23 #include "../h/proc.h"
24 #include "../h/uio.h"
25 #include "../vba/vddc.h"
26 
27 int	vddebug = 1;	/* if = 1, error messages are printed on the console */
28 int	vdintflg = 0;	/* if = 1, interrupts are handled by the driver,
29 			 * otherwise they are just ignored. (during setup) */
30 
31 static struct size FSD[] = {
32     9600,       0,	/* minor 0/ 8/16/24 = fsd0a - fsd3a - cyl   0 -  59*/
33    12000,    9600,	/* minor 1/ 9/17/25 = fsd0b - fsd3b - cyl  60 - 134*/
34   108480,   21600,	/* minor 2/10/18/26 = fsd0c - fsd3c - cyl 135 - 812*/
35     1600,  130080,	/* minor 3/11/19/27 = fsd0d - fsd3d - cyl 813 - 822*/
36   130080,       0,	/* minor 4/12/20/28 = fsd0e - fsd3e - cyl   0 - 812*/
37   131680,       0,	/* minor 5/13/21/29 = fsd0f - fsd3f - cyl   0 - 822*/
38        0,	0,	/* Non existent minor device */
39        0,	0,	/* Non existent minor device */
40        0,	0,	/* Non existent minor device */
41        0,	0,	/* Non existent minor device */
42        0,	0,	/* Non existent minor device */
43        0,	0,	/* Non existent minor device */
44        0,	0,	/* Non existent minor device */
45        0,	0,	/* Non existent minor device */
46        0,	0,	/* Non existent minor device */
47        0,	0,	/* Non existent minor device */
48 };
49 
50 static struct size	SMD[]= {
51     20064,	0, 	/* minor 32/40/48/56 = smd0a - smd3a cyl 0- 65 */
52     13680,  20064, 	/* minor 33/41/49/57 = smd0b - smd3b cyl 66- 110 */
53    214928,  33744, 	/* minor 34/42/50/58 = smd0c - smd3c cyl 111-817 */
54      1520, 248672, 	/* minor 35/43/51/59 = smd0d - smd3d cyl 818-822 */
55    248672,	0, 	/* minor 36/44/52/60 = smd0e - smd3e cyl 0-817 */
56    250192,	0, 	/* minor 37/45/53/61 = smd0f - smd3f cyl 0-822 */
57 	0,	0, 	/* minor 38/46/54/62 = smd0g - smd3g */
58 	0,	0, 	/* minor 39/47/55/63 = smd0h - smd3h */
59 	0,	0,	/* Non existent minor device */
60 	0,	0,	/* Non existent minor device */
61 	0,	0,	/* Non existent minor device */
62 	0,	0,	/* Non existent minor device */
63 	0,	0,	/* Non existent minor device */
64 	0,	0,	/* Non existent minor device */
65 	0,	0,	/* Non existent minor device */
66 	0,	0,	/* Non existent minor device */
67 };
68 
69 static struct size XFSD[] = {
70     20352,	0, 	/* minor 64/72/80/88 = xfsd0a - xfsd3a cyl 0- 52 */
71     20352,  20352, 	/* minor 65/73/81/89 = xfsd0b - xfsd3b cyl 53- 105 */
72    230400,  40704, 	/* minor 66/74/82/90 = xfsd0c - xfsd3c cyl 106-705 */
73      1920, 271104, 	/* minor 67/75/83/91 = xfsd0d - xfsd3d cyl 706-710 */
74    271104,	0, 	/* minor 68/76/84/92 = xfsd0e - xfsd3e cyl 0-705 */
75    273024,	0, 	/* minor 69/77/85/93 = xfsd0f - xfsd3f cyl 0-710 */
76 	0,	0, 	/* minor 70/78/86/94 = xfsd0g - xfsd3g */
77 	0,	0, 	/* minor 71/79/87/95 = xfsd0h - xfsd3h */
78 	0,	0,	/* Non existent minor device */
79 	0,	0,	/* Non existent minor device */
80 	0,	0,	/* Non existent minor device */
81 	0,	0,	/* Non existent minor device */
82 	0,	0,	/* Non existent minor device */
83 	0,	0,	/* Non existent minor device */
84 	0,	0,	/* Non existent minor device */
85 	0,	0,	/* Non existent minor device */
86 };
87 
88 /*
89 /*
90 /* Layout of minor number assignments for the VDDC devices.
91 /*
92 /* 	  1
93 /*	  5		            3 2   0
94 /*	 +---------------------------+-----+
95 /*	 |     		 Unit number | FLS |
96 /*	 +---------------------------+-----+
97 /*			      	   |    |_____ File system # ( 0-7 )
98 /*			      	   |__________ Unit # in the system
99 /*
100 /********************************************************/
101 
102 #define VDUNIT(x)	(minor(x) >> 3)
103 #define FLSYS(x)	(minor(x) & 0x07)
104 #define PHYS(x)		( vtoph( 0, (int) (x) ) )
105 
106 
107 /* Drive types should be in order of drive capacity for auto-configuration */
108 /* e.g: smallest capacity = drive type 0, highest capacity = type NXPDRV-1 */
109 
110 struct vdst {
111 	short nsect;
112 	short ntrak;
113 	short nspc;
114 	short ncyl;
115 	struct size *sizes;
116 	short dtype;		/* type as in byte 5 (drive) of iopb */
117 	char	*name;		/* drive name for autoconf */
118 } vdst[] = {
119 
120 16,	10,	16*10,	823,	FSD,	0,	"fsd",
121 16,	19,	16*19,	823,	SMD,	1, 	"smd",
122 16,	24,	16*24,  711,   XFSD,	2,	"xfd"
123 };
124 
125 
126 struct	vba_ctlr *vdminfo[NVD];
127 struct  vba_device *vddinfo[NFSD];
128 
129 /*
130 **	Internal Functions
131 */
132 int	vdopen();
133 int	vdclose();
134 int	vdprobe();		/* See if VDDC is really there */
135 int	vd_setup();		/* Called from vdprobe */
136 int	vdslave();		/* See if drive is really there */
137 int	vdattach();
138 int	vddgo();
139 int	vdstrategy();		/* VDDC strategy routine */
140 int	vdstart();		/* Top level interface to device queue */
141 int	vdintr();		/* Top Level ISR */
142 int	vdread();		/* raw i/o read routine */
143 int	vdwrite();		/* raw i/o write routine */
144 int	vddump();		/* dump routine */
145 int	vdsize();		/* sizes for swapconfig */
146 int	dskrst();		/* reset a drive after hard error */
147 
148 long	vdstd[] = {
149 		0x0f2000 };
150 
151 struct	vba_driver vddriver = {
152 	vdprobe, vdslave, vdattach, vddgo, vdstd,
153 	"smd/fsd", vddinfo, "vd", vdminfo
154 };
155 
156 struct	buf	vdutab[NFSD];
157 struct 	buf	rvdbuf[NFSD];
158 char	vdbuf[NVD][MAXBPTE * NBPG];	/* internal buffer for raw/swap i/o */
159 long	vdbufused[NVD];
160 extern char	vd0utl[],vd1utl[],vd2utl[],vd3utl[];
161 
162 /*
163 **	Disk Address
164 */
165 struct	dskadr	{
166 	char	track;		/* all 8 bits */
167 	char	sector;		/* low order 5 bits */
168 	short	cylinder;	/* low order 12 bits */
169 };
170 
171 /*
172 **	DCB Trailer Formats
173 **********************************/
174 
175 /*
176 **	Read / Write Trailer
177 */
178 struct	trrw	{
179 	char	*memadr;			/* memory address */
180 	long	wcount;				/* 16 bit word count */
181 	struct	dskadr	disk;			/* disk address */
182 };
183 
184 /*
185 **	Format Trailer
186 */
187 struct	trfmt	{
188 	char	*addr;			/* data buffer to be filled on sector*/
189 	long	nsectors;		/* # of sectors to be formatted */
190 	struct	dskadr	disk;
191 	struct	dskadr  hdr;
192 };
193 
194 /*
195 **	Reset / Configure Trailer
196 */
197 struct	treset	{
198 	long	ncyl;		/* # cylinders */
199 	long	nsurfaces;	/* # surfaces */
200 };				/* # of sectors is defined by VDDC */
201 				/* to be 32/track of 512 data bytes each */
202 
203 /*
204 **	Seek Trailer
205 */
206 struct	trseek	{
207 	struct	dskadr	disk;
208 };
209 
210 /*
211 **	DCB Format
212 */
213 struct	fmt_dcb	{
214 	struct	fmt_dcb	*nxtdcb;	/* next dcb in chain or End of Chain */
215 	short	intflg;			/* interrupt settings and flags */
216 	short	opcode;			/* DCB Command code etc... */
217 	long	operrsta;		/* Error & Status info */
218 	short	fill;			/* not used */
219 	char	devselect;		/* Drive selection */
220 	char	trailcnt;		/* Trailer Word Count */
221 	long	err_memadr;		/* Error memory address */
222 	short	fill2;
223 	short	err_wcount;		/* Error word count */
224 	short	err_track;		/* Error track/sector */
225 	short	err_cyl;		/* Error cylinder adr */
226 	union	{
227 		struct	trrw	rwtrail;	/* read/write trailer */
228 		struct	trfmt	fmtrail;	/* format trailer */
229 		struct	treset	resetrail;	/* reset/configure trailer */
230 		struct	trseek	seektrail;	/* seek trailer */
231 	} trail;
232 };
233 
234 /*
235 **	MDCB Format
236 */
237 struct	fmt_mdcb	{
238 	struct	fmt_dcb	*firstdcb;	/* first dcb in chain */
239 	struct	fmt_dcb	*procdcb;	/* dcb being processed */
240 	struct	fmt_dcb	*intdcb;	/* dcb causing interrupt */
241 	long	vddcstat;		/* VDDC status */
242 }mdcbx[NVD];
243 
244 /*
245 **	DCB
246 */
247 
248 struct	fmt_dcb		dcbx[NVD];
249 
250 int vdtimeout;
251 #define	POLLTILLDONE(x, name) { \
252 	vdtimeout = 1000*(x); \
253 	uncache((char *)&dcb->operrsta); \
254 	while (! (dcb->operrsta & DCBCMP)) { \
255 		DELAY(1000); \
256 		vdtimeout--; \
257 		uncache((char *)&dcb->operrsta); \
258 		if (vdtimeout <=0) { \
259 			printf("vd: timeout on %s\n", name);\
260 			return(0); \
261 		} \
262 	} \
263 }
264 
265 /*
266 **	See if the controller is really there.
267 **	if TRUE - initialize the controller.
268 */
269 vdprobe(cntrl_vaddr)
270 caddr_t cntrl_vaddr;
271 {
272 	if ( badaddr(cntrl_vaddr,2) ) return(0); /* no controller */
273 	else
274 		if (vd_setup(cntrl_vaddr))	/* initialize the controller */
275 			return(1);
276 		else return(0);		/* initialization error */
277 }
278 
279 vd_setup(cntrl_vaddr)
280 caddr_t cntrl_vaddr;
281 {
282 	register struct fmt_dcb *dcb = &dcbx[0];
283 	register struct fmt_mdcb *mdcb = &mdcbx[0];
284 	int j;
285 
286 	VDDC_RESET(cntrl_vaddr);		/* Reset the controller */
287 		/* Burn some time ...... needed after accessing reset port */
288 	for (j=0; j<20; j++)
289 		DELAY(1000);
290 
291 	/* setup & issue INIT to initialize VDDC */
292 
293 	dcb->opcode = INIT;
294 	dcb->nxtdcb = (struct fmt_dcb *)0;
295 	dcb->intflg = NOINT;
296 	mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb);
297 	dcb->operrsta  = 0;
298 	VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) );	/* do it */
299 	POLLTILLDONE(1,"INIT");		/* poll till done */
300 	if (dcb->operrsta & HRDERR) {
301 		if (vddebug)
302 			printf("vd: init error, err=%b\n",
303 			    dcb->operrsta, ERRBITS);
304 		return(0);
305 	}
306 	/* setup & issue DIAGNOSE */
307 
308 	dcb->opcode = DIAG;
309 	dcb->nxtdcb = (struct fmt_dcb *)0;
310 	dcb->intflg = NOINT;
311 	mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb);
312 	dcb->operrsta  = 0;
313 	VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) )	/* do it */
314 	POLLTILLDONE(1,"DIAG")		/* poll till done */
315 	if (dcb->operrsta & HRDERR) {
316 		if (vddebug)
317 			printf("vd: diagnose error, err=%b\n",
318 			    dcb->operrsta, ERRBITS);
319 		return(0);
320 	}
321 	/* Start drives command */
322 #ifdef notdef
323 	dcb->opcode = VDSTART;
324 	dcb->nxtdcb = (struct fmt_dcb *)0;
325 	dcb->intflg = NOINT;
326 	mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb);
327 	dcb->operrsta  = 0;
328 	VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) )	/* do it */
329 	POLLTILLDONE(20,"VDSTART")		/* poll till done */
330 	if (dcb->operrsta & HRDERR) {
331 		if (vddebug)
332 			printf("vd: start error, err=%b\n",
333 			    dcb->operrsta, ERRBITS);
334 		return(0);
335 	}
336 #endif
337 	return(1);
338    }
339 
340 /*
341  * See if a drive is really there
342  * Try to Reset/Configure the drive, then test its status.
343 */
344 vdslave(ui,cntrl_vaddr)
345 register struct vba_device *ui;
346 register caddr_t cntrl_vaddr;
347 {
348 	register struct fmt_dcb	*dcb = &dcbx[0];
349 	register struct fmt_mdcb *mdcb = &mdcbx[ui->ui_ctlr];
350 	register struct vdst *st;
351 	int dsktype;
352 
353 	/*
354 	**  check drive status - see if drive exists.
355 	*/
356 	dcb->opcode = VDSTATUS;
357 	dcb->intflg = NOINT;
358 	dcb->operrsta  = 0;
359 	dcb->devselect = (char)ui->ui_slave;
360 	dcb->trailcnt = (char)0;
361 	mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb);
362 	mdcb->vddcstat = 0;
363 	VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb))	/* do it */
364 	POLLTILLDONE(5,"VDSTATUS")
365 #ifdef notdef
366 	if (dcb->operrsta & HRDERR) {
367 		if (vddebug)
368 		  printf("vd%d: status error, err=%b\n", ui->ui_unit,
369 		      dcb->operrsta, ERRBITS);
370 		return(0);
371 	}
372 #endif
373 	uncache((char *)&mdcb->vddcstat);
374 	if (mdcb->vddcstat & DRVNRDY) return(0); /* not ready-> non existent */
375 
376 	/*
377 	 * drive is alive, now get its type!
378 	 * Seek on all drive types starting from the largest one.
379 	 * a sucessful seek to the last sector/cylinder/track verifies
380 	 * the drive type connected to this port.
381 	 */
382 	for (dsktype = NVDDRV-1; dsktype >= 0; dsktype--) {
383 		st = &vdst[dsktype];
384 		dcb->opcode = RSTCFG;		/* configure drive command */
385 		dcb->intflg = NOINT;
386 		dcb->operrsta  = 0;
387 		dcb->trail.resetrail.ncyl = st->ncyl;
388 		dcb->trail.resetrail.nsurfaces = st->ntrak;
389 		dcb->devselect = (char)ui->ui_slave;
390 		dcb->trailcnt = (char)2;
391 		mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb);
392 		VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) )	/* do it */
393 		POLLTILLDONE(3,"RSTCFG")
394 		if (dcb->operrsta & HRDERR) {
395 			if (vddebug)
396 				printf("vd%d: reset error, err=%b\n",
397 				    ui->ui_unit, dcb->operrsta, ERRBITS);
398 			return(0);
399 		}
400 		mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb);
401 		dcb->intflg = NOINT;
402 		dcb->opcode =  RD;
403 		dcb->operrsta = 0;
404 		dcb->devselect = (char)ui->ui_slave;
405 		dcb->trailcnt = (char)3;
406 		dcb->trail.rwtrail.memadr = (char *)PHYS(vdbuf);
407 		dcb->trail.rwtrail.wcount = 256;
408 		dcb->trail.rwtrail.disk.cylinder = st->ncyl -4;
409 		dcb->trail.rwtrail.disk.track = st->ntrak -1;
410 		dcb->trail.rwtrail.disk.sector = 0;
411 		VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) )	/* do it */
412 		POLLTILLDONE(5,"RD")
413 if (vddebug)
414 	printf("vd%d: cyl %d, trk %d, sec %d, operrsta err=%b\n",
415 	   ui->ui_unit,
416 	   dcb->trail.rwtrail.disk.cylinder,
417 	   dcb->trail.rwtrail.disk.track,
418 	   dcb->trail.rwtrail.disk.sector,
419 	   dcb->operrsta, ERRBITS);
420 		if ( (dcb->operrsta & HRDERR) == 0)
421 		/* found the drive type! */
422 			break;
423 	}
424 	if (dsktype < 0) {
425 		/* If reached here, a drive which is not defined in the
426 		 * 'vdst' tables is connected. Cannot set it's type.
427 		 */
428 		printf("vd%d: unrecognized drive type\n", ui->ui_unit);
429 		return(0);
430 	}
431 	ui->ui_type = dsktype;
432 	vddriver.ud_dname = st->name;
433 	return(1);
434 }
435 
436 vdattach(ui)
437 struct vba_device *ui;
438 {
439 	if (ui->ui_dk >= 0)
440 		dk_mspw[ui->ui_dk] = .0000020345;	/* BAD VALUE */
441 }
442 
443 vddgo(um)
444 struct vba_ctlr *um;
445 {
446 }
447 
448 vdstrategy(bp)
449 register struct buf *bp;
450 {
451 	register struct vba_device *ui;
452 	register struct vba_ctlr *um;
453 	register int unit;
454 	register struct buf *dp;
455 	register struct size *sizep;
456 	int index, blocks, s;
457 
458 	vdintflg = 1;		/* enable interrupts handling by the driver */
459 	blocks = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
460 	unit = VDUNIT(bp->b_dev);
461 	ui = vddinfo[unit];
462 	if (ui == 0 || ui->ui_alive == 0) goto bad1;
463 	index = FLSYS(bp->b_dev); /* get file system index */
464 	sizep = vdst[ui->ui_type].sizes;
465 	if (bp->b_blkno < 0 ||
466 	 (dkblock(bp)+blocks > sizep[index].nblocks))	/* disk overflow */
467 		goto bad1;
468 	s = spl8();
469 	dp = &vdutab[ui->ui_unit];
470 	bp->b_resid = bp->b_blkno + sizep[index].block0;
471 					/* block # plays same role as
472 					   cylinder # for disksort, as long
473 					   as increasing blocks correspond to
474 					   increasing cylinders on disk */
475 
476 	buf_setup (bp, SECTSIZ);
477 
478 	disksort(dp, bp);
479 	if (dp->b_active == 0) {	/* unit is on controller queue */
480 		/* put the device on the controller queue */
481 		dp->b_forw = NULL;		/* end of queue indicator */
482 		um = ui->ui_mi;		/* get controller structure !! */
483 		if (um->um_tab.b_actf == NULL)	/* controller queue is empty */
484 			um->um_tab.b_actf = dp;
485 		else
486 			um->um_tab.b_actl->b_forw = dp; /* add into queue */
487 		um->um_tab.b_actl = dp;		/* update queue tail */
488 		dp->b_active ++;
489 	}
490 	bp = &ui->ui_mi->um_tab;	/* controller structure addr */
491 	if (bp->b_actf && 		/* cntrl queue not empty */
492 		bp->b_active == 0)	/* controller not active */
493 		(void) vdstart(ui->ui_mi);/* go start I/O */
494 	splx(s);
495 	return;
496 
497 bad1:
498 	bp->b_flags |= B_ERROR;
499 	iodone(bp);
500 	return;
501 }
502 
503 
504 /*
505  * Start up a transfer on a drive.
506  */
507 vdstart(um)
508 register struct vba_ctlr *um;
509 {
510 	register struct buf *bp, *dp;
511 	register struct fmt_dcb *dcb = &dcbx[um->um_ctlr];
512 	register struct fmt_mdcb *mdcb;
513 	register struct size *sizep;	/* Pointer to one of the tables */
514 	register struct vdst *st;
515 	register int index ;		/* Index in the relevant table */
516 	register int phadr;		/* Buffer's physical address */
517 	register caddr_t cntrl_vaddr = um->um_addr;
518 	int	sblock, unit;
519 	int ct;
520 
521 loop:
522 	/*
523 	 * Pull a request off the controller queue
524 	 */
525 	if ((dp = um->um_tab.b_actf) == NULL)
526 		return ;
527 	if ((bp = dp->b_actf) == NULL) {
528 		dp->b_active = 0;	/* device removed from ctlr queue */
529 		um->um_tab.b_actf = dp->b_forw;
530 		goto loop;
531 	}
532 	/*
533 		 * Mark controller busy, and
534 		 * prepare a command packet for the controller.
535 		 */
536 	um->um_tab.b_active++;
537 	unit = VDUNIT(bp->b_dev);
538 	st = &vdst[vddinfo[unit]->ui_type];
539 	mdcb = &mdcbx[vddinfo[unit]->ui_ctlr];
540 	index = FLSYS(bp->b_dev);
541 	sizep = st->sizes;
542 	mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb);
543 	dcb->intflg = INTDUN;		/* interrupt on completion */
544 	dcb->opcode = (bp->b_flags & B_READ) ? RD : WD;
545 	dcb->operrsta = 0;
546 	dcb->devselect = (char)(vddinfo[unit])->ui_slave;
547 	dcb->trailcnt = (char)3;
548 	ct = vddinfo[unit]->ui_ctlr;
549 
550 	switch (ct) {
551 		case 0:
552 			phadr = get_ioadr(bp, vdbuf[0], VD0map, (caddr_t)vd0utl);
553 			break;
554 		case 1:
555 			phadr = get_ioadr(bp, vdbuf[1], VD1map, (caddr_t)vd1utl);
556 			break;
557 		case 2:
558 			phadr = get_ioadr(bp, vdbuf[2], VD2map, (caddr_t)vd2utl);
559 			break;
560 		case 3:
561 			phadr = get_ioadr(bp, vdbuf[3], VD3map, (caddr_t)vd3utl);
562 			break;
563 	}
564 /*
565 	phadr = get_ioadr(bp, vdbuf, IOmap, (caddr_t)ioutl);
566 */
567 
568 	if (vddinfo[unit]->ui_dk >= 0) {
569 		int dku = vddinfo[unit]->ui_dk;
570 		dk_busy |= 1<<dku;
571 		dk_xfer[dku]++;
572 		dk_wds[dku] += bp->b_bcount>>6;
573 	}
574 	dcb->trail.rwtrail.memadr = (char *)phadr;
575 	dcb->trail.rwtrail.wcount = (bp->b_bcount + 1) / 2;
576 	sblock = sizep[index].block0 + bp->b_blkno;
577 	dcb->trail.rwtrail.disk.cylinder = (short)(sblock / st->nspc);
578 	dcb->trail.rwtrail.disk.track = (char)((sblock % st->nspc) / st->nsect);
579 	dcb->trail.rwtrail.disk.sector = (char)(sblock*2 % (st->nsect*2));
580 
581 #ifdef VDDCPERF
582 	scope_out(1);
583 #endif
584 
585 	VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb))	/* do it */
586 }
587 
588 
589 /*
590  * Handle a disk interrupt.
591  */
592 vdintr(vdnum)
593 register vdnum;
594 {
595 	register struct buf *bp, *dp;
596 	register struct vba_ctlr *um = vdminfo[vdnum];
597 	register struct fmt_dcb *dcb = &dcbx[vdnum];
598 	register struct fmt_mdcb *mdcb = &mdcbx[vdnum];
599 	register struct vdst *st;
600 	int unit;
601 	struct vba_device *ui;
602 
603 #ifdef VDDCPERF
604 	scope_out(2);
605 #endif
606 	if (intenable == 0 || vdintflg == 0) 	/* ignore all interrupts */
607 		return;
608 	if (um->um_tab.b_active == NULL) return;/* unexpected interrupt */
609 	uncache((char *)&mdcb->intdcb);
610 	uncache((char *)&dcb->operrsta);
611 	if ( mdcb->intdcb != (struct fmt_dcb *)PHYS(dcb)) {	/* dcb causing interrupt */
612 		printf("vd%d: bad dcb=%x (phys=%x)\n",
613 		    vdnum, mdcb->intdcb, PHYS(dcb));
614 		return;
615 	}
616 	if (! (dcb->operrsta & DCBCMP))	{ /* unexpected interrupt */
617 		printf("vd%d: unexpected interrupt, err=%b\n", vdnum,
618 		    dcb->operrsta, ERRBITS);
619 		return;
620 	}
621 	dp = um->um_tab.b_actf;		/* device queue head in ctlr queue */
622 	bp = dp->b_actf;		/* first buffer in device queue */
623 	unit = VDUNIT(bp->b_dev);
624 	ui = vddinfo[unit];
625 	if (ui->ui_dk >= 0)
626 		dk_busy &= ~(1 << ui->ui_dk);
627 	if (dcb->operrsta & (HRDERR|SFTERR)) {
628 		st = &vdst[ui->ui_type];
629 		if (dcb->operrsta & HRDERR) {
630 			harderr(bp, &st->name[7]);
631 			printf("status=%b\n", dcb->operrsta, ERRBITS);
632 			dskrst(bp);
633 			bp->b_flags |= B_ERROR;
634 		} else
635 #define	SECTOR(x)	((x)*2)
636 			printf("%s%d: soft error sn%d status=%b\n", &st->name[7], unit,
637 			   SECTOR(bp->b_blkno + st->sizes[FLSYS(bp->b_dev)].block0),
638 			   dcb->operrsta, ERRBITS);
639 	}
640 	switch (vdnum) {
641 		case 0:
642 			end_transfer(bp, vdbuf[0], VD0map, (caddr_t)vd0utl);
643 			break;
644 		case 1:
645 			end_transfer(bp, vdbuf[1], VD1map, (caddr_t)vd1utl);
646 			break;
647 		case 2:
648 			end_transfer(bp, vdbuf[2], VD2map, (caddr_t)vd2utl);
649 			break;
650 		case 3:
651 			end_transfer(bp, vdbuf[3], VD3map, (caddr_t)vd3utl);
652 			break;
653 	}
654 
655 	um->um_tab.b_active = 0;
656 	um->um_tab.b_errcnt = 0;
657 	if (dp->b_forw != NULL) {		/* more than 1 unit on queue */
658 		um->um_tab.b_actf = dp->b_forw;	/* next device on ctlr queue */
659 		dp->b_forw = um->um_tab.b_actl->b_forw;	/* be last in queue */
660 		um->um_tab.b_actl->b_forw = dp;	/* last points now to dp */
661 		um->um_tab.b_actl = dp;		/* pointer in ctlr structure */
662 	}
663 	dp->b_errcnt = 0;
664 	dp->b_actf = bp->av_forw;		/* remove first from queue */
665 	bp->b_resid = 0;	/* All data read here */
666 
667 #ifdef VDDCPERF
668 	scope_out(3);
669 #endif
670 
671 	iodone(bp);
672 	vdstart(um);		/* start requests for next device on queue */
673 }
674 
675 
676 vdread(dev, uio)
677 dev_t dev;
678 struct uio *uio;
679 {
680 	register int unit = VDUNIT(dev);
681 	register int error;
682 	register int ct;
683 	register int s;
684 
685 	if (unit >= NFSD)
686 		error = ENXIO;
687 	else {
688 		ct = vddinfo[unit]->ui_ctlr;
689 		s = spl8();
690 		while (vdbufused[ct]) sleep (&vdbufused[ct],PRIBIO+1);
691 		vdbufused[ct] = 1;
692 		splx(s);
693 		error = physio(vdstrategy, &rvdbuf[unit], dev, B_READ, minphys, uio);
694 		vdbufused[ct] = 0;
695 		wakeup (&vdbufused[ct]);
696 	}
697 	return error;
698 }
699 
700 vdwrite(dev, uio)
701 dev_t dev;
702 struct uio *uio;
703 {
704 	register int unit = VDUNIT(dev);
705 	register int error;
706 	register int ct;
707 	register int s;
708 
709 	if (unit >= NFSD)
710 		error = ENXIO;
711 	else {
712 		ct = vddinfo[unit]->ui_ctlr;
713 		s = spl8();
714 		while (vdbufused[ct]) sleep (&vdbufused[ct],PRIBIO+1);
715 		vdbufused[ct] = 1;
716 		splx(s);
717 		error = physio(vdstrategy, &rvdbuf[unit], dev, B_WRITE, minphys, uio);
718 		vdbufused[ct] = 0;
719 		wakeup (&vdbufused[ct]);
720 	}
721 	return error;
722 }
723 
724 #define	DUMPSIZE	32	/* Up to 32k at a time - controller limit */
725 
726 vddump(dev)
727 dev_t	dev;
728 /*
729  * Dump the main memory to the given device.
730  */
731 {
732 	register struct vba_ctlr *um;
733 	register struct fmt_dcb *dcb = &dcbx[0];
734 	register struct fmt_mdcb *mdcb = &mdcbx[0];
735 	register struct vdst *st;
736 	register int unit;
737 	register caddr_t cntrl_vaddr ;
738 	register struct size *sizep;	/* Pointer to one of the tables */
739 	int index,sblock,blkcount,thiscount;
740 	int	memaddr;
741 
742 	unit = VDUNIT(dev);
743 	um = (vddinfo[unit])->ui_mi;
744 	st = &vdst[(vddinfo[unit])->ui_type];
745 	dcb = &dcbx[um->um_ctlr];
746 	cntrl_vaddr = um->um_addr;
747 	memaddr = 0x0;
748 	index = FLSYS(dev);
749 	sizep = st->sizes;
750 	blkcount = maxfree - 2;		/* In 1k byte pages */
751 	if (dumplo + blkcount > sizep[index].nblocks) return(EINVAL);
752 	sblock = sizep[index].block0 + dumplo;
753 	while (blkcount > 0) {
754 		thiscount = MIN (blkcount, DUMPSIZE);
755 		mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb);
756 		dcb->intflg = NOINT;
757 		dcb->opcode = WD;
758 		dcb->operrsta = 0;
759 		dcb->devselect = (char)(vddinfo[unit])->ui_slave;
760 		dcb->trailcnt = (char)3;
761 		dcb->trail.rwtrail.memadr = (char *)memaddr;
762 		dcb->trail.rwtrail.wcount = thiscount*512;
763 		dcb->trail.rwtrail.disk.cylinder= (short)(sblock/st->nspc);
764 		dcb->trail.rwtrail.disk.track = (char)((sblock % st->nspc)
765 			/ st->nsect);
766 		dcb->trail.rwtrail.disk.sector = (char)(sblock*2 % (st->nsect*2));
767 		VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) )	/* do it */
768 		POLLTILLDONE(5,"WD");
769 		if (dcb->operrsta & HRDERR) {
770 			if (vddebug)
771 				printf("vd%d: i/o error, err=%b\n", unit,
772 				    dcb->operrsta, ERRBITS);
773 			return(EIO);
774 		};
775 		blkcount -= thiscount;
776 		memaddr += thiscount*NBPG;
777 		sblock += thiscount;
778 	}
779 	return(0);
780 }
781 
782 vdopen(dev, flag)
783 register dev_t dev;
784 int flag;
785 {
786 	register struct vba_device *ui;
787 	register unit = VDUNIT(dev);
788 
789 	ui = vddinfo[unit];
790 	if (ui == 0 || ui->ui_alive == 0 || ui->ui_type >= NVDDRV)
791 		return ENXIO;
792 	return 0;
793 }
794 
795 vdsize(dev)
796 register dev_t dev;
797 {
798 	register struct vba_device *ui;
799 	register unit = VDUNIT(dev);
800 
801 	ui = vddinfo[unit];
802 	if (ui == 0 || ui->ui_alive == 0 || ui->ui_type >= NVDDRV)
803 		return -1;
804 	return vdst[ui->ui_type].sizes[FLSYS(dev)].nblocks;
805 }
806 
807 /* reset a drive after a hard error */
808 dskrst(bp)
809 	register struct buf *bp;
810 {
811 	register struct vdst *st;
812 	register struct fmt_dcb *dcb;
813 	register struct fmt_mdcb *mdcb;
814 	register struct vba_device *ui;
815 	register caddr_t cntrl_vaddr ;
816 	int unit;
817 
818 	unit = VDUNIT(bp->b_dev);
819 	ui = vddinfo[unit];
820 	mdcb = &mdcbx[ui->ui_ctlr];
821 	dcb = &dcbx[ui->ui_ctlr];
822 	cntrl_vaddr = (ui->ui_mi)->um_addr;
823 	st = &vdst[vddinfo[unit]->ui_type];
824 	dcb->opcode = RSTCFG;		/* configure drive command */
825 	dcb->intflg = NOINT;
826 	dcb->operrsta  = 0;
827 	dcb->trail.resetrail.ncyl = st->ncyl;
828 	dcb->trail.resetrail.nsurfaces = st->ntrak;
829 	dcb->devselect = (char)ui->ui_slave;
830 	dcb->trailcnt = (char)2;
831 	mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb);
832 	VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) )	/* do it */
833 	POLLTILLDONE(3,"reset")
834 	if (dcb->operrsta & HRDERR) {
835 		if (vddebug) {
836 			harderr(bp, &st->name[7]);
837 			printf("reset failed, err=%b\n", dcb->operrsta,ERRBITS);
838 		}
839 	}
840 }
841 #endif
842