Commit | Line | Data |
---|---|---|
9d915fad | 1 | /* scat_vddc.c 1.2 86/01/05 */ |
1a286dc6 SL |
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" | |
9d915fad SL |
18 | #include "../tahoe/mtpr.h" |
19 | #include "../tahoe/pte.h" | |
1a286dc6 | 20 | #include "../h/systm.h" |
9d915fad | 21 | #include "../tahoevba/vbavar.h" |
1a286dc6 SL |
22 | #include "../h/user.h" |
23 | #include "../h/vmmac.h" | |
24 | #include "../h/proc.h" | |
25 | #include "../h/uio.h" | |
9d915fad | 26 | #include "../tahoevba/vddc.h" |
1a286dc6 SL |
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 |