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