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