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