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