Commit | Line | Data |
---|---|---|
d763a2b7 | 1 | /* up.c 4.15 81/02/16 */ |
008c0481 | 2 | |
66b4fb09 | 3 | #include "up.h" |
3f3a34c3 | 4 | #if NSC21 > 0 |
008c0481 | 5 | /* |
10fb932f | 6 | * UNIBUS disk driver with overlapped seeks and ECC recovery. |
008c0481 | 7 | */ |
355250d9 | 8 | #define DELAY(N) { register int d; d = N; while (--d > 0); } |
008c0481 BJ |
9 | |
10 | #include "../h/param.h" | |
11 | #include "../h/systm.h" | |
3f3a34c3 BJ |
12 | #include "../h/cpu.h" |
13 | #include "../h/nexus.h" | |
41888f16 | 14 | #include "../h/dk.h" |
008c0481 BJ |
15 | #include "../h/buf.h" |
16 | #include "../h/conf.h" | |
17 | #include "../h/dir.h" | |
18 | #include "../h/user.h" | |
19 | #include "../h/map.h" | |
80e7c811 | 20 | #include "../h/pte.h" |
008c0481 BJ |
21 | #include "../h/mba.h" |
22 | #include "../h/mtpr.h" | |
008c0481 BJ |
23 | #include "../h/uba.h" |
24 | #include "../h/vm.h" | |
0ff318b2 | 25 | #include "../h/cmap.h" |
008c0481 | 26 | |
0ff318b2 | 27 | #include "../h/upreg.h" |
008c0481 | 28 | |
3f3a34c3 BJ |
29 | struct up_softc { |
30 | int sc_softas; | |
31 | int sc_seek; | |
32 | int sc_info; | |
33 | int sc_wticks; | |
5aa9d5ea | 34 | /* struct uba_minfo sc_minfo; */ |
3f3a34c3 | 35 | } up_softc[NSC21]; |
008c0481 | 36 | |
3f3a34c3 | 37 | /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ |
008c0481 BJ |
38 | struct size |
39 | { | |
40 | daddr_t nblocks; | |
41 | int cyloff; | |
42 | } up_sizes[8] = { | |
43 | 15884, 0, /* A=cyl 0 thru 26 */ | |
44 | 33440, 27, /* B=cyl 27 thru 81 */ | |
d1778415 | 45 | 495520, 0, /* C=cyl 0 thru 814 */ |
008c0481 BJ |
46 | 15884, 562, /* D=cyl 562 thru 588 */ |
47 | 55936, 589, /* E=cyl 589 thru 680 */ | |
48 | 81472, 681, /* F=cyl 681 thru 814 */ | |
49 | 153824, 562, /* G=cyl 562 thru 814 */ | |
008c0481 | 50 | 291346, 82, /* H=cyl 82 thru 561 */ |
3f3a34c3 BJ |
51 | }, fj_sizes[8] = { |
52 | 15884, 0, /* A=cyl 0 thru 49 */ | |
53 | 33440, 50, /* B=cyl 50 thru 154 */ | |
54 | 263360, 0, /* C=cyl 0 thru 822 */ | |
55 | 0, 0, | |
56 | 0, 0, | |
57 | 0, 0, | |
58 | 0, 0, | |
59 | 213760, 155, /* H=cyl 155 thru 822 */ | |
008c0481 | 60 | }; |
3f3a34c3 | 61 | /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ |
008c0481 | 62 | |
3f3a34c3 BJ |
63 | #define _upSDIST 2 /* 1.0 msec */ |
64 | #define _upRDIST 4 /* 2.0 msec */ | |
65 | ||
66 | int upSDIST = _upSDIST; | |
67 | int upRDIST = _upRDIST; | |
68 | ||
69 | int upcntrlr(), upslave(), updgo(), upintr(); | |
70 | struct uba_minfo *upminfo[NSC21]; | |
71 | struct uba_dinfo *updinfo[NUP]; | |
d763a2b7 BJ |
72 | |
73 | u_short upstd[] = { 0776700, 0774400, 0776300 }; | |
3f3a34c3 | 74 | struct uba_driver updriver = |
d763a2b7 | 75 | { upcntrlr, upslave, updgo, 0, upstd, "up", updinfo, upminfo }; |
3f3a34c3 BJ |
76 | struct buf uputab[NUP]; |
77 | ||
78 | struct upst { | |
79 | short nsect; | |
80 | short ntrak; | |
81 | short nspc; | |
82 | short ncyl; | |
83 | struct size *sizes; | |
84 | } upst[] = { | |
85 | 32, 19, 32*19, 815, up_sizes, /* 9300 */ | |
86 | 32, 19, 32*19, 823, up_sizes, /* so cdc will boot */ | |
87 | 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ | |
88 | }; | |
008c0481 BJ |
89 | |
90 | int up_offset[16] = | |
91 | { | |
92 | P400, M400, P400, M400, | |
93 | P800, M800, P800, M800, | |
94 | P1200, M1200, P1200, M1200, | |
95 | 0, 0, 0, 0, | |
96 | }; | |
97 | ||
3f3a34c3 | 98 | struct buf rupbuf; /* GROT */ |
008c0481 | 99 | |
008c0481 BJ |
100 | #define b_cylin b_resid |
101 | ||
008c0481 BJ |
102 | #ifdef INTRLVE |
103 | daddr_t dkblock(); | |
104 | #endif | |
3f3a34c3 BJ |
105 | |
106 | int upwstart, upwatch(); /* Have started guardian */ | |
107 | ||
108 | /*ARGSUSED*/ | |
109 | upcntrlr(um, reg) | |
110 | struct uba_minfo *um; | |
111 | caddr_t reg; | |
008c0481 | 112 | { |
d763a2b7 BJ |
113 | register int br, cvec; |
114 | ||
3f3a34c3 | 115 | ((struct device *)reg)->upcs1 |= (IE|RDY); |
d763a2b7 | 116 | return (1); |
3f3a34c3 BJ |
117 | } |
118 | ||
d763a2b7 | 119 | upslave(ui, reg, slaveno) |
3f3a34c3 BJ |
120 | struct uba_dinfo *ui; |
121 | caddr_t reg; | |
122 | { | |
123 | register struct device *upaddr = (struct device *)reg; | |
3f3a34c3 BJ |
124 | |
125 | upaddr->upcs1 = 0; /* conservative */ | |
126 | upaddr->upcs2 = slaveno; | |
127 | if (upaddr->upcs2&NED) { | |
128 | upaddr->upcs1 = DCLR|GO; | |
129 | return (0); | |
130 | } | |
6a81870e | 131 | if (upwstart == 0) { |
49c84d3f | 132 | timeout(upwatch, (caddr_t)0, HZ); |
6a81870e BJ |
133 | upwstart++; |
134 | } | |
3f3a34c3 BJ |
135 | return (1); |
136 | } | |
137 | ||
138 | /* | |
139 | dk_mspw[UPDK_N+unit] = .0000020345; | |
140 | */ | |
141 | ||
142 | upstrategy(bp) | |
143 | register struct buf *bp; | |
144 | { | |
145 | register struct uba_dinfo *ui; | |
146 | register struct uba_minfo *um; | |
147 | register struct upst *st; | |
148 | register int unit; | |
149 | int xunit = minor(bp->b_dev) & 07; | |
150 | long sz, bn; | |
151 | ||
008c0481 BJ |
152 | sz = bp->b_bcount; |
153 | sz = (sz+511) >> 9; /* transfer size in 512 byte sectors */ | |
154 | unit = dkunit(bp); | |
3f3a34c3 BJ |
155 | if (unit >= NUP) |
156 | goto bad; | |
157 | ui = updinfo[unit]; | |
158 | if (ui == 0 || ui->ui_alive == 0) | |
159 | goto bad; | |
160 | st = &upst[ui->ui_type]; | |
161 | if (bp->b_blkno < 0 || | |
162 | (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) | |
163 | goto bad; | |
164 | bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; | |
008c0481 | 165 | (void) spl5(); |
3f3a34c3 BJ |
166 | disksort(&uputab[ui->ui_unit], bp); |
167 | if (uputab[ui->ui_unit].b_active == 0) { | |
168 | (void) upustart(ui); | |
169 | bp = &ui->ui_mi->um_tab; | |
170 | if (bp->b_actf && bp->b_active == 0) | |
171 | (void) upstart(ui->ui_mi); | |
008c0481 BJ |
172 | } |
173 | (void) spl0(); | |
3f3a34c3 BJ |
174 | return; |
175 | ||
176 | bad: | |
177 | bp->b_flags |= B_ERROR; | |
178 | iodone(bp); | |
179 | return; | |
008c0481 BJ |
180 | } |
181 | ||
3f3a34c3 BJ |
182 | upustart(ui) |
183 | register struct uba_dinfo *ui; | |
008c0481 BJ |
184 | { |
185 | register struct buf *bp, *dp; | |
3f3a34c3 BJ |
186 | register struct uba_minfo *um; |
187 | register struct device *upaddr; | |
188 | register struct upst *st; | |
008c0481 BJ |
189 | daddr_t bn; |
190 | int sn, cn, csn; | |
eb891eaa | 191 | int didie = 0; |
008c0481 | 192 | |
3f3a34c3 BJ |
193 | /* SC21 cancels commands if you say cs1 = IE, so dont */ |
194 | /* being ultra-cautious, we clear as bits only in upintr() */ | |
195 | dk_busy &= ~(1<<ui->ui_dk); | |
196 | dp = &uputab[ui->ui_unit]; | |
7bc8d985 | 197 | if ((bp = dp->b_actf) == NULL) |
eb891eaa | 198 | goto out; |
3f3a34c3 BJ |
199 | /* dont confuse controller by giving SEARCH while dt in progress */ |
200 | um = ui->ui_mi; | |
201 | if (um->um_tab.b_active) { | |
d763a2b7 | 202 | up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; |
2a3b9a7f BJ |
203 | return (0); |
204 | } | |
a3f430e0 BJ |
205 | if (dp->b_active) |
206 | goto done; | |
207 | dp->b_active = 1; | |
3f3a34c3 BJ |
208 | upaddr = (struct device *)um->um_addr; |
209 | upaddr->upcs2 = ui->ui_slave; | |
7bc8d985 BJ |
210 | if ((upaddr->upds & VV) == 0) { |
211 | upaddr->upcs1 = IE|DCLR|GO; | |
008c0481 | 212 | upaddr->upcs1 = IE|PRESET|GO; |
008c0481 | 213 | upaddr->upof = FMT22; |
eb891eaa | 214 | didie = 1; |
008c0481 | 215 | } |
008c0481 | 216 | if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) |
2a3b9a7f | 217 | goto done; |
3f3a34c3 | 218 | st = &upst[ui->ui_type]; |
008c0481 BJ |
219 | bn = dkblock(bp); |
220 | cn = bp->b_cylin; | |
3f3a34c3 BJ |
221 | sn = bn%st->nspc; |
222 | sn = (sn + st->nsect - upSDIST) % st->nsect; | |
7bc8d985 BJ |
223 | if (cn - upaddr->updc) |
224 | goto search; /* Not on-cylinder */ | |
3f3a34c3 | 225 | /**** WHAT SHOULD THIS BE NOW ??? |
2a3b9a7f BJ |
226 | else if (upseek) |
227 | goto done; /* Ok just to be on-cylinder */ | |
008c0481 | 228 | csn = (upaddr->upla>>6) - sn - 1; |
7bc8d985 | 229 | if (csn < 0) |
3f3a34c3 BJ |
230 | csn += st->nsect; |
231 | if (csn > st->nsect - upRDIST) | |
008c0481 | 232 | goto done; |
008c0481 BJ |
233 | search: |
234 | upaddr->updc = cn; | |
3f3a34c3 | 235 | /*** ANOTHER OCCURRENCE |
2a3b9a7f BJ |
236 | if (upseek) |
237 | upaddr->upcs1 = IE|SEEK|GO; | |
3f3a34c3 | 238 | else ****/ { |
2a3b9a7f BJ |
239 | upaddr->upda = sn; |
240 | upaddr->upcs1 = IE|SEARCH|GO; | |
241 | } | |
eb891eaa | 242 | didie = 1; |
3f3a34c3 BJ |
243 | if (ui->ui_dk >= 0) { |
244 | dk_busy |= 1<<ui->ui_dk; | |
245 | dk_seek[ui->ui_dk]++; | |
008c0481 | 246 | } |
eb891eaa | 247 | goto out; |
008c0481 BJ |
248 | done: |
249 | dp->b_forw = NULL; | |
3f3a34c3 BJ |
250 | if (um->um_tab.b_actf == NULL) |
251 | um->um_tab.b_actf = dp; | |
008c0481 | 252 | else |
3f3a34c3 BJ |
253 | um->um_tab.b_actl->b_forw = dp; |
254 | um->um_tab.b_actl = dp; | |
eb891eaa BJ |
255 | out: |
256 | return (didie); | |
008c0481 BJ |
257 | } |
258 | ||
3f3a34c3 BJ |
259 | upstart(um) |
260 | register struct uba_minfo *um; | |
008c0481 BJ |
261 | { |
262 | register struct buf *bp, *dp; | |
3f3a34c3 | 263 | register struct uba_dinfo *ui; |
008c0481 BJ |
264 | register unit; |
265 | register struct device *upaddr; | |
3f3a34c3 | 266 | register struct upst *st; |
008c0481 | 267 | daddr_t bn; |
5aa9d5ea | 268 | int dn, sn, tn, cmd; |
008c0481 | 269 | |
008c0481 | 270 | loop: |
3f3a34c3 | 271 | if ((dp = um->um_tab.b_actf) == NULL) |
eb891eaa | 272 | return (0); |
008c0481 | 273 | if ((bp = dp->b_actf) == NULL) { |
3f3a34c3 | 274 | um->um_tab.b_actf = dp->b_forw; |
008c0481 BJ |
275 | goto loop; |
276 | } | |
7bc8d985 BJ |
277 | /* |
278 | * Mark the controller busy, and multi-part disk address. | |
279 | * Select the unit on which the i/o is to take place. | |
280 | */ | |
3f3a34c3 BJ |
281 | um->um_tab.b_active++; |
282 | ui = updinfo[dkunit(bp)]; | |
008c0481 | 283 | bn = dkblock(bp); |
3f3a34c3 BJ |
284 | dn = ui->ui_slave; |
285 | st = &upst[ui->ui_type]; | |
286 | sn = bn%st->nspc; | |
287 | tn = sn/st->nsect; | |
288 | sn %= st->nsect; | |
289 | upaddr = (struct device *)ui->ui_addr; | |
355250d9 | 290 | if ((upaddr->upcs2 & 07) != dn) |
008c0481 | 291 | upaddr->upcs2 = dn; |
d763a2b7 | 292 | up_softc[um->um_ctlr].sc_info = |
3f3a34c3 | 293 | ubasetup(ui->ui_ubanum, bp, UBA_NEEDBDP|UBA_CANTWAIT); |
7bc8d985 BJ |
294 | /* |
295 | * If drive is not present and on-line, then | |
296 | * get rid of this with an error and loop to get | |
297 | * rid of the rest of its queued requests. | |
298 | * (Then on to any other ready drives.) | |
299 | */ | |
008c0481 | 300 | if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { |
88253fd2 BJ |
301 | printf("!DPR || !MOL, unit %d, ds %o", dn, upaddr->upds); |
302 | if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { | |
303 | printf("-- hard\n"); | |
3f3a34c3 BJ |
304 | um->um_tab.b_active = 0; |
305 | um->um_tab.b_errcnt = 0; | |
88253fd2 BJ |
306 | dp->b_actf = bp->av_forw; |
307 | dp->b_active = 0; | |
308 | bp->b_flags |= B_ERROR; | |
309 | iodone(bp); | |
310 | /* A funny place to do this ... */ | |
d763a2b7 | 311 | ubarelse(ui->ui_ubanum, &up_softc[um->um_ctlr].sc_info); |
88253fd2 BJ |
312 | goto loop; |
313 | } | |
314 | printf("-- came back\n"); | |
008c0481 | 315 | } |
7bc8d985 BJ |
316 | /* |
317 | * If this is a retry, then with the 16'th retry we | |
318 | * begin to try offsetting the heads to recover the data. | |
319 | */ | |
3f3a34c3 BJ |
320 | if (um->um_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) { |
321 | upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | FMT22; | |
7bc8d985 | 322 | upaddr->upcs1 = IE|OFFSET|GO; |
7bc8d985 | 323 | while (upaddr->upds & PIP) |
008c0481 BJ |
324 | DELAY(25); |
325 | } | |
7bc8d985 BJ |
326 | /* |
327 | * Now set up the transfer, retrieving the high | |
328 | * 2 bits of the UNIBUS address from the information | |
329 | * returned by ubasetup() for the cs1 register bits 8 and 9. | |
330 | */ | |
5aa9d5ea | 331 | upaddr->updc = bp->b_cylin; |
008c0481 | 332 | upaddr->upda = (tn << 8) + sn; |
d763a2b7 | 333 | upaddr->upba = up_softc[um->um_ctlr].sc_info; |
008c0481 | 334 | upaddr->upwc = -bp->b_bcount / sizeof (short); |
d763a2b7 | 335 | cmd = (up_softc[um->um_ctlr].sc_info >> 8) & 0x300; |
008c0481 | 336 | if (bp->b_flags & B_READ) |
7bc8d985 | 337 | cmd |= IE|RCOM|GO; |
008c0481 | 338 | else |
7bc8d985 | 339 | cmd |= IE|WCOM|GO; |
7bc8d985 | 340 | upaddr->upcs1 = cmd; |
7bc8d985 BJ |
341 | /* |
342 | * This is a controller busy situation. | |
c134650e | 343 | * Record in dk slot NUP+UPDK_N (after last drive) |
7bc8d985 BJ |
344 | * unless there aren't that many slots reserved for |
345 | * us in which case we record this as a drive busy | |
346 | * (if there is room for that). | |
347 | */ | |
3f3a34c3 BJ |
348 | unit = ui->ui_dk; |
349 | dk_busy |= 1<<unit; | |
350 | dk_xfer[unit]++; | |
351 | dk_wds[unit] += bp->b_bcount>>6; | |
eb891eaa | 352 | return (1); |
008c0481 BJ |
353 | } |
354 | ||
3f3a34c3 BJ |
355 | updgo() |
356 | { | |
357 | } | |
358 | ||
008c0481 BJ |
359 | /* |
360 | * Handle a device interrupt. | |
361 | * | |
362 | * If the transferring drive needs attention, service it | |
363 | * retrying on error or beginning next transfer. | |
364 | * Service all other ready drives, calling ustart to transfer | |
3f3a34c3 | 365 | * their blocks to the ready queue in um->um_tab, and then restart |
008c0481 BJ |
366 | * the controller if there is anything to do. |
367 | */ | |
3f3a34c3 BJ |
368 | upintr(sc21) |
369 | register sc21; | |
008c0481 BJ |
370 | { |
371 | register struct buf *bp, *dp; | |
3f3a34c3 BJ |
372 | register struct uba_minfo *um = upminfo[sc21]; |
373 | register struct uba_dinfo *ui; | |
374 | register struct device *upaddr = (struct device *)um->um_addr; | |
008c0481 | 375 | register unit; |
008c0481 | 376 | int as = upaddr->upas & 0377; |
eb891eaa | 377 | int needie = 1; |
008c0481 | 378 | |
a3f430e0 | 379 | (void) spl6(); |
d763a2b7 | 380 | up_softc[um->um_ctlr].sc_wticks = 0; |
3f3a34c3 | 381 | if (um->um_tab.b_active) { |
7bc8d985 | 382 | if ((upaddr->upcs1 & RDY) == 0) { |
39bd608f BJ |
383 | printf("!RDY: cs1 %o, ds %o, wc %d\n", upaddr->upcs1, |
384 | upaddr->upds, upaddr->upwc); | |
3f3a34c3 | 385 | printf("as=%d act %d %d %d\n", as, um->um_tab.b_active, |
d1778415 | 386 | uputab[0].b_active, uputab[1].b_active); |
6e179703 | 387 | } |
3f3a34c3 | 388 | dp = um->um_tab.b_actf; |
008c0481 | 389 | bp = dp->b_actf; |
3f3a34c3 BJ |
390 | ui = updinfo[dkunit(bp)]; |
391 | dk_busy &= ~(1 << ui->ui_dk); | |
392 | upaddr->upcs2 = ui->ui_slave; | |
10fb932f | 393 | if ((upaddr->upds&ERR) || (upaddr->upcs1&TRE)) { |
0ad5097e | 394 | int cs2; |
7bc8d985 | 395 | while ((upaddr->upds & DRY) == 0) |
008c0481 | 396 | DELAY(25); |
3f3a34c3 | 397 | if (++um->um_tab.b_errcnt > 28 || upaddr->uper1&WLE) |
008c0481 BJ |
398 | bp->b_flags |= B_ERROR; |
399 | else | |
3f3a34c3 BJ |
400 | um->um_tab.b_active = 0; /* force retry */ |
401 | if (um->um_tab.b_errcnt > 27) { | |
0ad5097e | 402 | cs2 = (int)upaddr->upcs2; |
3f3a34c3 BJ |
403 | deverror(bp, cs2, (int)upaddr->uper1); |
404 | } | |
405 | if ((upaddr->uper1&(DCK|ECH))==DCK && upecc(ui)) | |
7bc8d985 | 406 | return; |
008c0481 | 407 | upaddr->upcs1 = TRE|IE|DCLR|GO; |
eb891eaa | 408 | needie = 0; |
3f3a34c3 | 409 | if ((um->um_tab.b_errcnt&07) == 4) { |
008c0481 | 410 | upaddr->upcs1 = RECAL|GO|IE; |
008c0481 BJ |
411 | while(upaddr->upds & PIP) |
412 | DELAY(25); | |
413 | } | |
3f3a34c3 | 414 | if (um->um_tab.b_errcnt == 28 && cs2&(NEM|MXF)) { |
0ad5097e | 415 | printf("FLAKEY UP "); |
3f3a34c3 | 416 | ubareset(um->um_ubanum); |
0ad5097e BJ |
417 | return; |
418 | } | |
008c0481 | 419 | } |
3f3a34c3 BJ |
420 | if (um->um_tab.b_active) { |
421 | if (um->um_tab.b_errcnt >= 16) { | |
7bc8d985 | 422 | upaddr->upcs1 = RTC|GO|IE; |
7bc8d985 | 423 | while (upaddr->upds & PIP) |
008c0481 | 424 | DELAY(25); |
eb891eaa | 425 | needie = 0; |
008c0481 | 426 | } |
3f3a34c3 BJ |
427 | um->um_tab.b_active = 0; |
428 | um->um_tab.b_errcnt = 0; | |
429 | um->um_tab.b_actf = dp->b_forw; | |
008c0481 BJ |
430 | dp->b_active = 0; |
431 | dp->b_errcnt = 0; | |
432 | dp->b_actf = bp->av_forw; | |
7bc8d985 | 433 | bp->b_resid = (-upaddr->upwc * sizeof(short)); |
2a3b9a7f | 434 | if (bp->b_resid) |
d1778415 BJ |
435 | printf("resid %d ds %o er? %o %o %o\n", |
436 | bp->b_resid, upaddr->upds, | |
2a3b9a7f | 437 | upaddr->uper1, upaddr->uper2, upaddr->uper3); |
008c0481 | 438 | iodone(bp); |
3f3a34c3 BJ |
439 | if (dp->b_actf) |
440 | if (upustart(ui)) | |
eb891eaa | 441 | needie = 0; |
008c0481 | 442 | } |
d763a2b7 BJ |
443 | up_softc[um->um_ctlr].sc_softas &= ~(1<<ui->ui_slave); |
444 | ubarelse(ui->ui_ubanum, &up_softc[um->um_ctlr].sc_info); | |
1f3d30ee | 445 | } else { |
355250d9 | 446 | if (upaddr->upcs1 & TRE) |
008c0481 | 447 | upaddr->upcs1 = TRE; |
008c0481 | 448 | } |
d763a2b7 | 449 | as |= up_softc[um->um_ctlr].sc_softas; |
3f3a34c3 BJ |
450 | for (unit = 0; unit < NUP; unit++) { |
451 | if ((ui = updinfo[unit]) == 0 || ui->ui_mi != um) | |
452 | continue; | |
453 | if (as & (1<<unit)) { | |
355250d9 | 454 | if (as & (1<<unit)) |
5c65daa3 | 455 | upaddr->upas = 1<<unit; |
3f3a34c3 | 456 | if (upustart(ui)) |
1f3d30ee BJ |
457 | needie = 0; |
458 | } | |
3f3a34c3 BJ |
459 | } |
460 | if (um->um_tab.b_actf && um->um_tab.b_active == 0) | |
461 | if (upstart(um)) | |
eb891eaa | 462 | needie = 0; |
2a3b9a7f | 463 | if (needie) |
7bc8d985 | 464 | upaddr->upcs1 = IE; |
008c0481 BJ |
465 | } |
466 | ||
467 | upread(dev) | |
468 | { | |
008c0481 BJ |
469 | physio(upstrategy, &rupbuf, dev, B_READ, minphys); |
470 | } | |
471 | ||
472 | upwrite(dev) | |
473 | { | |
008c0481 BJ |
474 | physio(upstrategy, &rupbuf, dev, B_WRITE, minphys); |
475 | } | |
476 | ||
7bc8d985 BJ |
477 | /* |
478 | * Correct an ECC error, and restart the i/o to complete | |
479 | * the transfer if necessary. This is quite complicated because | |
480 | * the transfer may be going to an odd memory address base and/or | |
481 | * across a page boundary. | |
482 | */ | |
3f3a34c3 BJ |
483 | upecc(ui) |
484 | register struct uba_dinfo *ui; | |
008c0481 | 485 | { |
3f3a34c3 BJ |
486 | register struct device *up = (struct device *)ui->ui_addr; |
487 | register struct buf *bp = uputab[ui->ui_unit].b_actf; | |
488 | register struct uba_minfo *um = ui->ui_mi; | |
489 | register struct upst *st; | |
490 | struct uba_regs *ubp = ui->ui_hd->uh_uba; | |
7bc8d985 | 491 | register int i; |
008c0481 | 492 | caddr_t addr; |
7bc8d985 | 493 | int reg, bit, byte, npf, mask, o, cmd, ubaddr; |
008c0481 BJ |
494 | int bn, cn, tn, sn; |
495 | ||
008c0481 | 496 | /* |
7bc8d985 BJ |
497 | * Npf is the number of sectors transferred before the sector |
498 | * containing the ECC error, and reg is the UBA register | |
499 | * mapping (the first part of) the transfer. | |
500 | * O is offset within a memory page of the first byte transferred. | |
008c0481 | 501 | */ |
7bc8d985 | 502 | npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; |
d763a2b7 | 503 | reg = btop(up_softc[um->um_ctlr].sc_info&0x3ffff) + npf; |
008c0481 BJ |
504 | o = (int)bp->b_un.b_addr & PGOFSET; |
505 | printf("%D ", bp->b_blkno+npf); | |
506 | prdev("ECC", bp->b_dev); | |
507 | mask = up->upec2; | |
508 | if (mask == 0) { | |
7bc8d985 | 509 | up->upof = FMT22; /* == RTC ???? */ |
008c0481 BJ |
510 | return (0); |
511 | } | |
7bc8d985 BJ |
512 | /* |
513 | * Flush the buffered data path, and compute the | |
514 | * byte and bit position of the error. The variable i | |
515 | * is the byte offset in the transfer, the variable byte | |
516 | * is the offset from a page boundary in main memory. | |
517 | */ | |
d763a2b7 | 518 | ubp->uba_dpr[(up_softc[um->um_ctlr].sc_info>>28)&0x0f] |= UBA_BNE; |
7bc8d985 BJ |
519 | i = up->upec1 - 1; /* -1 makes 0 origin */ |
520 | bit = i&07; | |
521 | i = (i&~07)>>3; | |
008c0481 | 522 | byte = i + o; |
7bc8d985 BJ |
523 | /* |
524 | * Correct while possible bits remain of mask. Since mask | |
525 | * contains 11 bits, we continue while the bit offset is > -11. | |
526 | * Also watch out for end of this block and the end of the whole | |
527 | * transfer. | |
528 | */ | |
529 | while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { | |
530 | addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ | |
531 | (byte & PGOFSET); | |
532 | putmemc(addr, getmemc(addr)^(mask<<bit)); | |
533 | byte++; | |
534 | i++; | |
535 | bit -= 8; | |
008c0481 | 536 | } |
3f3a34c3 | 537 | um->um_tab.b_active++; /* Either complete or continuing... */ |
008c0481 BJ |
538 | if (up->upwc == 0) |
539 | return (0); | |
7bc8d985 BJ |
540 | /* |
541 | * Have to continue the transfer... clear the drive, | |
542 | * and compute the position where the transfer is to continue. | |
543 | * We have completed npf+1 sectors of the transfer already; | |
544 | * restart at offset o of next sector (i.e. in UBA register reg+1). | |
545 | */ | |
546 | up->upcs1 = TRE|IE|DCLR|GO; | |
008c0481 | 547 | bn = dkblock(bp); |
3f3a34c3 | 548 | st = &upst[ui->ui_type]; |
008c0481 | 549 | cn = bp->b_cylin; |
3f3a34c3 BJ |
550 | sn = bn%st->nspc + npf + 1; |
551 | tn = sn/st->nsect; | |
552 | sn %= st->nsect; | |
553 | cn += tn/st->ntrak; | |
554 | tn %= st->ntrak; | |
008c0481 | 555 | up->updc = cn; |
7bc8d985 BJ |
556 | up->upda = (tn << 8) | sn; |
557 | ubaddr = (int)ptob(reg+1) + o; | |
558 | up->upba = ubaddr; | |
559 | cmd = (ubaddr >> 8) & 0x300; | |
560 | cmd |= IE|GO|RCOM; | |
561 | up->upcs1 = cmd; | |
008c0481 BJ |
562 | return (1); |
563 | } | |
977c2848 BJ |
564 | |
565 | /* | |
566 | * Reset driver after UBA init. | |
567 | * Cancel software state of all pending transfers | |
568 | * and restart all units and the controller. | |
569 | */ | |
3f3a34c3 | 570 | upreset(uban) |
977c2848 | 571 | { |
3f3a34c3 BJ |
572 | register struct uba_minfo *um; |
573 | register struct uba_dinfo *ui; | |
574 | register sc21, unit; | |
5aa9d5ea | 575 | int any = 0; |
3f3a34c3 | 576 | |
3f3a34c3 BJ |
577 | for (sc21 = 0; sc21 < NSC21; sc21++) { |
578 | if ((um = upminfo[sc21]) == 0) | |
579 | continue; | |
580 | if (um->um_ubanum != uban) | |
581 | continue; | |
582 | if (!um->um_alive) | |
583 | continue; | |
5aa9d5ea RE |
584 | if (any == 0) { |
585 | printf(" up"); | |
586 | DELAY(15000000); /* give it time to self-test */ | |
587 | any++; | |
588 | } | |
3f3a34c3 BJ |
589 | um->um_tab.b_active = 0; |
590 | um->um_tab.b_actf = um->um_tab.b_actl = 0; | |
d763a2b7 BJ |
591 | if (up_softc[um->um_ctlr].sc_info) { |
592 | printf("<%d>", (up_softc[um->um_ctlr].sc_info>>28)&0xf); | |
593 | ubarelse(um->um_ubanum, &up_softc[um->um_ctlr].sc_info); | |
3f3a34c3 BJ |
594 | } |
595 | ((struct device *)(um->um_addr))->upcs2 = CLR; | |
596 | for (unit = 0; unit < NUP; unit++) { | |
597 | if ((ui = updinfo[unit]) == 0) | |
598 | continue; | |
599 | if (ui->ui_alive == 0) | |
600 | continue; | |
601 | uputab[unit].b_active = 0; | |
602 | (void) upustart(ui); | |
603 | } | |
604 | (void) upstart(um); | |
977c2848 | 605 | } |
977c2848 | 606 | } |
6a81870e BJ |
607 | |
608 | /* | |
609 | * Wake up every second and if an interrupt is pending | |
610 | * but nothing has happened increment a counter. | |
611 | * If nothing happens for 20 seconds, reset the controller | |
612 | * and begin anew. | |
613 | */ | |
614 | upwatch() | |
615 | { | |
3f3a34c3 BJ |
616 | register struct uba_minfo *um; |
617 | register sc21, unit; | |
6a81870e | 618 | |
49c84d3f | 619 | timeout(upwatch, (caddr_t)0, HZ); |
3f3a34c3 BJ |
620 | for (sc21 = 0; sc21 < NSC21; sc21++) { |
621 | um = upminfo[sc21]; | |
622 | if (um->um_tab.b_active == 0) { | |
623 | for (unit = 0; unit < NUP; unit++) | |
624 | if (updinfo[unit]->ui_mi == um && | |
625 | uputab[unit].b_active) | |
626 | goto active; | |
627 | up_softc[sc21].sc_wticks = 0; | |
628 | continue; | |
629 | } | |
630 | active: | |
631 | up_softc[sc21].sc_wticks++; | |
632 | if (up_softc[sc21].sc_wticks >= 20) { | |
633 | up_softc[sc21].sc_wticks = 0; | |
634 | printf("LOST INTERRUPT RESET"); | |
635 | upreset(um->um_ubanum); | |
636 | printf("\n"); | |
637 | } | |
6a81870e BJ |
638 | } |
639 | } | |
0ff318b2 BJ |
640 | |
641 | #define DBSIZE 20 | |
642 | ||
643 | updump(dev) | |
644 | dev_t dev; | |
645 | { | |
646 | struct device *upaddr; | |
647 | char *start; | |
648 | int num, blk, unit, nsect, ntrak, nspc; | |
649 | struct size *sizes; | |
3f3a34c3 BJ |
650 | register struct uba_regs *uba; |
651 | register struct uba_dinfo *ui; | |
0ff318b2 | 652 | register short *rp; |
3f3a34c3 | 653 | struct upst *st; |
0ff318b2 | 654 | |
0ff318b2 BJ |
655 | unit = minor(dev) >> 3; |
656 | if (unit >= NUP) { | |
657 | printf("bad unit\n"); | |
658 | return (-1); | |
659 | } | |
3f3a34c3 BJ |
660 | #define phys1(cast, addr) ((cast)((int)addr & 0x7fffffff)) |
661 | #define phys(cast, addr) phys1(cast, phys1(cast *, &addr)) | |
662 | ui = phys(struct uba_dinfo *, updinfo[unit]); | |
663 | if (ui->ui_alive == 0) { | |
664 | printf("dna\n"); | |
665 | return(-1); | |
666 | } | |
667 | uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; | |
668 | #if VAX780 | |
669 | if (cpu == VAX_780) { | |
670 | uba->uba_cr = UBA_ADINIT; | |
671 | uba->uba_cr = UBA_IFS|UBA_BRIE|UBA_USEFIE|UBA_SUEFIE; | |
672 | while ((uba->uba_cnfgr & UBA_UBIC) == 0) | |
673 | ; | |
674 | } | |
675 | #endif | |
676 | DELAY(1000000); | |
677 | upaddr = (struct device *)ui->ui_physaddr; | |
678 | while ((upaddr->upcs1&DVA) == 0) | |
679 | ; | |
680 | num = maxfree; | |
681 | start = 0; | |
0ff318b2 BJ |
682 | upaddr->upcs2 = unit; |
683 | if ((upaddr->upds & VV) == 0) { | |
684 | upaddr->upcs1 = DCLR|GO; | |
685 | upaddr->upcs1 = PRESET|GO; | |
686 | upaddr->upof = FMT22; | |
687 | } | |
688 | if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { | |
689 | printf("up !DPR || !MOL\n"); | |
690 | return (-1); | |
691 | } | |
3f3a34c3 BJ |
692 | st = phys1(struct upst *, &upst[ui->ui_type]); |
693 | nsect = st->nsect; | |
694 | ntrak = st->ntrak; | |
695 | sizes = phys(struct size *, st->sizes); | |
0ff318b2 | 696 | if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) { |
3f3a34c3 | 697 | printf("oor\n"); |
0ff318b2 BJ |
698 | return (-1); |
699 | } | |
3f3a34c3 | 700 | nspc = st->nspc; |
0ff318b2 BJ |
701 | while (num > 0) { |
702 | register struct pte *io; | |
703 | register int i; | |
704 | int cn, sn, tn; | |
705 | daddr_t bn; | |
706 | ||
707 | blk = num > DBSIZE ? DBSIZE : num; | |
3f3a34c3 | 708 | io = uba->uba_map; |
0ff318b2 | 709 | for (i = 0; i < blk; i++) |
3f3a34c3 | 710 | *(int *)io++ = (btop(start)+i) | (1<<21) | UBA_MRV; |
0ff318b2 BJ |
711 | *(int *)io = 0; |
712 | bn = dumplo + btop(start); | |
713 | cn = bn/nspc + sizes[minor(dev)&07].cyloff; | |
714 | sn = bn%nspc; | |
715 | tn = sn/nsect; | |
716 | sn = sn%nsect; | |
717 | upaddr->updc = cn; | |
718 | rp = (short *) &upaddr->upda; | |
719 | *rp = (tn << 8) + sn; | |
720 | *--rp = 0; | |
721 | *--rp = -blk*NBPG / sizeof (short); | |
722 | *--rp = GO|WCOM; | |
723 | do { | |
724 | DELAY(25); | |
725 | } while ((upaddr->upcs1 & RDY) == 0); | |
726 | if (upaddr->upcs1&ERR) { | |
727 | printf("up dump dsk err: (%d,%d,%d) cs1=%x, er1=%x\n", | |
728 | cn, tn, sn, upaddr->upcs1, upaddr->uper1); | |
729 | return (-1); | |
730 | } | |
731 | start += blk*NBPG; | |
732 | num -= blk; | |
733 | } | |
0ff318b2 BJ |
734 | return (0); |
735 | } | |
63c35a63 | 736 | #endif |