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