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