Commit | Line | Data |
---|---|---|
210a9f40 SL |
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 |