Commit | Line | Data |
---|---|---|
da7c5cc6 KM |
1 | /* |
2 | * Copyright (c) 1982 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | * | |
580dd3c9 | 6 | * @(#)idc.c 6.12 (Berkeley) %G% |
da7c5cc6 | 7 | */ |
6c163e27 SL |
8 | |
9 | #include "rb.h" | |
10 | #if NIDC > 0 | |
7da157da BJ |
11 | int idcdebug = 0; |
12 | #define printd if(idcdebug)printf | |
13 | int idctrb[1000]; | |
14 | int *trp = idctrb; | |
bc3a8383 | 15 | #define trace(a,b) {*trp++ = *(int*)a; *trp++ = (int)b; if(trp>&idctrb[998])trp=idctrb;} |
6c163e27 SL |
16 | /* |
17 | * IDC (RB730) disk driver | |
18 | * | |
19 | * There can only ever be one IDC on a machine, | |
20 | * and only on a VAX-11/730. We take advantage | |
21 | * of that to simplify the driver. | |
22 | * | |
23 | * TODO: | |
6c163e27 | 24 | * ecc |
6c163e27 | 25 | */ |
961945a8 SL |
26 | #include "../machine/pte.h" |
27 | ||
ff360633 JB |
28 | #include "param.h" |
29 | #include "systm.h" | |
30 | #include "buf.h" | |
31 | #include "conf.h" | |
32 | #include "dir.h" | |
33 | #include "user.h" | |
34 | #include "map.h" | |
35 | #include "vm.h" | |
36 | #include "dk.h" | |
37 | #include "cmap.h" | |
38 | #include "dkbad.h" | |
39 | #include "uio.h" | |
40 | #include "kernel.h" | |
57fd7c67 | 41 | #include "syslog.h" |
6c163e27 | 42 | |
896962b1 | 43 | #include "../vax/cpu.h" |
ff360633 JB |
44 | #include "ubareg.h" |
45 | #include "ubavar.h" | |
46 | #include "idcreg.h" | |
6c163e27 SL |
47 | |
48 | struct idc_softc { | |
49 | int sc_bcnt; /* number of bytes to transfer */ | |
50 | int sc_resid; /* total number of bytes to transfer */ | |
51 | int sc_ubaddr; /* Unibus address of data */ | |
52 | short sc_unit; /* unit doing transfer */ | |
53 | short sc_softas; /* software attention summary bits */ | |
54 | union idc_dar { | |
55 | long dar_l; | |
56 | u_short dar_w[2]; | |
57 | u_char dar_b[4]; | |
58 | } sc_un; /* prototype disk address register */ | |
59 | } idc_softc; | |
60 | ||
61 | #define dar_dar dar_l /* the whole disk address */ | |
62 | #define dar_cyl dar_w[1] /* cylinder address */ | |
63 | #define dar_trk dar_b[1] /* track */ | |
64 | #define dar_sect dar_b[0] /* sector */ | |
65 | #define sc_dar sc_un.dar_dar | |
66 | #define sc_cyl sc_un.dar_cyl | |
67 | #define sc_trk sc_un.dar_trk | |
68 | #define sc_sect sc_un.dar_sect | |
69 | ||
dac559fa JB |
70 | #define idcunit(dev) (minor(dev) >> 3) |
71 | ||
6c163e27 SL |
72 | /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ |
73 | struct size { | |
74 | daddr_t nblocks; | |
75 | int cyloff; | |
76 | } rb02_sizes[8] ={ | |
77 | 15884, 0, /* A=cyl 0 thru 399 */ | |
78 | 4480, 400, /* B=cyl 400 thru 510 */ | |
79 | 20480, 0, /* C=cyl 0 thru 511 */ | |
80 | 0, 0, | |
81 | 0, 0, | |
82 | 0, 0, | |
83 | 0, 0, | |
84 | 0, 0, | |
85 | }, rb80_sizes[8] ={ | |
86 | 15884, 0, /* A=cyl 0 thru 36 */ | |
87 | 33440, 37, /* B=cyl 37 thru 114 */ | |
88 | 242606, 0, /* C=cyl 0 thru 558 */ | |
89 | 0, 0, | |
90 | 0, 0, | |
91 | 0, 0, | |
92 | 82080, 115, /* G=cyl 115 thru 304 */ | |
93 | 110143, 305, /* H=cyl 305 thru 558 */ | |
94 | }; | |
95 | /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ | |
96 | ||
97 | int idcprobe(), idcslave(), idcattach(), idcdgo(), idcintr(); | |
98 | struct uba_ctlr *idcminfo[NIDC]; | |
99 | struct uba_device *idcdinfo[NRB]; | |
100 | ||
101 | u_short idcstd[] = { 0174400, 0}; | |
102 | struct uba_driver idcdriver = | |
103 | { idcprobe, idcslave, idcattach, idcdgo, idcstd, "rb", idcdinfo, "idc", idcminfo, 0 }; | |
104 | struct buf idcutab[NRB]; | |
105 | union idc_dar idccyl[NRB]; | |
106 | ||
107 | struct idcst { | |
108 | short nbps; | |
109 | short nsect; | |
110 | short ntrak; | |
111 | short nspc; | |
112 | short ncyl; | |
113 | struct size *sizes; | |
114 | } idcst[] = { | |
115 | 256, NRB02SECT, NRB02TRK, NRB02SECT*NRB02TRK, NRB02CYL, rb02_sizes, | |
116 | 512, NRB80SECT, NRB80TRK, NRB80SECT*NRB80TRK, NRB80CYL, rb80_sizes, | |
117 | }; | |
118 | ||
119 | struct buf ridcbuf[NRB]; | |
120 | ||
121 | #define b_cylin b_resid | |
122 | ||
6c163e27 SL |
123 | int idcwstart, idcwticks, idcwatch(); |
124 | ||
bc3a8383 | 125 | /*ARGSUSED*/ |
6c163e27 SL |
126 | idcprobe(reg) |
127 | caddr_t reg; | |
128 | { | |
129 | register int br, cvec; | |
130 | register struct idcdevice *idcaddr; | |
131 | ||
132 | #ifdef lint | |
133 | br = 0; cvec = br; br = cvec; | |
134 | #endif | |
135 | idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200); | |
136 | idcaddr->idccsr = IDC_ATTN|IDC_IE; | |
137 | while ((idcaddr->idccsr & IDC_CRDY) == 0) | |
138 | ; | |
139 | idcaddr->idccsr = IDC_ATTN|IDC_CRDY; | |
9c0adba0 | 140 | return (sizeof (struct idcdevice)); |
6c163e27 SL |
141 | } |
142 | ||
bc3a8383 | 143 | /*ARGSUSED*/ |
6c163e27 SL |
144 | idcslave(ui, reg) |
145 | struct uba_device *ui; | |
146 | caddr_t reg; | |
147 | { | |
148 | register struct idcdevice *idcaddr; | |
149 | register int i; | |
150 | ||
151 | idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200); | |
152 | ui->ui_type = 0; | |
153 | idcaddr->idcmpr = IDCGS_GETSTAT; | |
154 | idcaddr->idccsr = IDC_GETSTAT|(ui->ui_slave<<8); | |
ac76a23d | 155 | (void) idcwait(idcaddr, 0); |
6c163e27 SL |
156 | i = idcaddr->idcmpr; |
157 | idcaddr->idccsr = IDC_CRDY|(1<<(ui->ui_slave+16)); | |
ac76a23d | 158 | (void) idcwait(idcaddr, 0); |
2ee461b6 EW |
159 | /* read header to synchronize microcode */ |
160 | idcaddr->idccsr = (ui->ui_slave<<8)|IDC_RHDR; | |
161 | (void) idcwait(idcaddr, 0); | |
162 | i = idcaddr->idcmpr; /* read header word 1 */ | |
163 | i = idcaddr->idcmpr; /* read header word 2 */ | |
bc3a8383 | 164 | #ifdef lint |
2ee461b6 | 165 | i = i; |
bc3a8383 | 166 | #endif |
2ee461b6 | 167 | if ((idcaddr->idccsr & (IDC_ERR|IDC_R80)) == IDC_R80) |
6c163e27 | 168 | ui->ui_type = 1; |
2ee461b6 | 169 | else if ((idcaddr->idccsr & (IDC_DE|IDC_R80)) == 0) |
04069650 MK |
170 | /* |
171 | * RB02 may not have pack spun up, just look for drive error. | |
172 | */ | |
2ee461b6 EW |
173 | ui->ui_type = 0; |
174 | else | |
175 | return (0); | |
6c163e27 SL |
176 | return (1); |
177 | } | |
178 | ||
179 | idcattach(ui) | |
180 | register struct uba_device *ui; | |
181 | { | |
182 | ||
183 | /* | |
184 | * Fix all addresses to correspond | |
185 | * to the "real" IDC address. | |
186 | */ | |
187 | ui->ui_mi->um_addr = ui->ui_addr = (caddr_t)uba_hd[0].uh_uba + 0x200; | |
188 | ui->ui_physaddr = (caddr_t)uba_hd[0].uh_physuba + 0x200; | |
189 | if (idcwstart == 0) { | |
190 | timeout(idcwatch, (caddr_t)0, hz); | |
191 | idcwstart++; | |
192 | } | |
193 | if (ui->ui_dk >= 0) | |
194 | if (ui->ui_type) | |
195 | dk_mspw[ui->ui_dk] = 1.0 / (60 * NRB80SECT * 256); | |
196 | else | |
197 | dk_mspw[ui->ui_dk] = 1.0 / (60 * NRB02SECT * 128); | |
198 | idccyl[ui->ui_unit].dar_dar = -1; | |
199 | ui->ui_flags = 0; | |
200 | } | |
7da157da BJ |
201 | |
202 | idcopen(dev) | |
203 | dev_t dev; | |
204 | { | |
dac559fa | 205 | register int unit = idcunit(dev); |
7da157da BJ |
206 | register struct uba_device *ui; |
207 | ||
208 | if (unit >= NRB || (ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0) | |
209 | return (ENXIO); | |
210 | return (0); | |
211 | } | |
6c163e27 SL |
212 | |
213 | idcstrategy(bp) | |
214 | register struct buf *bp; | |
215 | { | |
216 | register struct uba_device *ui; | |
217 | register struct idcst *st; | |
218 | register int unit; | |
219 | register struct buf *dp; | |
220 | int xunit = minor(bp->b_dev) & 07; | |
221 | long bn, sz; | |
222 | ||
223 | sz = (bp->b_bcount+511) >> 9; | |
dac559fa JB |
224 | unit = idcunit(bp->b_dev); |
225 | if (unit >= NRB) { | |
226 | bp->b_error = ENXIO; | |
6c163e27 | 227 | goto bad; |
dac559fa | 228 | } |
6c163e27 | 229 | ui = idcdinfo[unit]; |
dac559fa JB |
230 | if (ui == 0 || ui->ui_alive == 0) { |
231 | bp->b_error = ENXIO; | |
6c163e27 | 232 | goto bad; |
dac559fa | 233 | } |
6c163e27 SL |
234 | st = &idcst[ui->ui_type]; |
235 | if (bp->b_blkno < 0 || | |
dac559fa | 236 | (bn = bp->b_blkno)+sz > st->sizes[xunit].nblocks) { |
9d0e0faa MK |
237 | if (bp->b_blkno == st->sizes[xunit].nblocks) { |
238 | bp->b_resid = bp->b_bcount; | |
dac559fa | 239 | goto done; |
9d0e0faa | 240 | } |
dac559fa | 241 | bp->b_error = EINVAL; |
6c163e27 | 242 | goto bad; |
dac559fa | 243 | } |
6c163e27 SL |
244 | if (ui->ui_type == 0) |
245 | bn *= 2; | |
246 | bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; | |
247 | (void) spl5(); | |
bc3a8383 | 248 | trace("strt",bp); |
6c163e27 SL |
249 | dp = &idcutab[ui->ui_unit]; |
250 | disksort(dp, bp); | |
251 | if (dp->b_active == 0) { | |
bc3a8383 | 252 | trace("!act",dp); |
6c163e27 SL |
253 | (void) idcustart(ui); |
254 | bp = &ui->ui_mi->um_tab; | |
255 | if (bp->b_actf && bp->b_active == 0) | |
256 | (void) idcstart(ui->ui_mi); | |
257 | } | |
258 | (void) spl0(); | |
259 | return; | |
260 | ||
261 | bad: | |
262 | bp->b_flags |= B_ERROR; | |
dac559fa | 263 | done: |
6c163e27 SL |
264 | iodone(bp); |
265 | return; | |
266 | } | |
267 | ||
268 | idcustart(ui) | |
269 | register struct uba_device *ui; | |
270 | { | |
271 | register struct buf *bp, *dp; | |
272 | register struct uba_ctlr *um; | |
273 | register struct idcdevice *idcaddr; | |
274 | register struct idcst *st; | |
275 | union idc_dar cyltrk; | |
276 | daddr_t bn; | |
277 | int unit; | |
278 | ||
279 | if (ui == 0) | |
280 | return (0); | |
281 | dk_busy &= ~(1<<ui->ui_dk); | |
282 | dp = &idcutab[ui->ui_unit]; | |
283 | um = ui->ui_mi; | |
284 | unit = ui->ui_slave; | |
bc3a8383 | 285 | trace("ust", dp); |
6c163e27 SL |
286 | idcaddr = (struct idcdevice *)um->um_addr; |
287 | if (um->um_tab.b_active) { | |
288 | idc_softc.sc_softas |= 1<<unit; | |
bc3a8383 | 289 | trace("umac",idc_softc.sc_softas); |
6c163e27 SL |
290 | return (0); |
291 | } | |
292 | if ((bp = dp->b_actf) == NULL) { | |
bc3a8383 | 293 | trace("!bp",0); |
6c163e27 SL |
294 | return (0); |
295 | } | |
296 | if (dp->b_active) { | |
bc3a8383 | 297 | trace("dpac",dp->b_active); |
6c163e27 SL |
298 | goto done; |
299 | } | |
300 | dp->b_active = 1; | |
301 | /* CHECK DRIVE READY? */ | |
dac559fa | 302 | bn = bp->b_blkno; |
bc3a8383 | 303 | trace("seek", bn); |
6c163e27 SL |
304 | if (ui->ui_type == 0) |
305 | bn *= 2; | |
306 | st = &idcst[ui->ui_type]; | |
307 | cyltrk.dar_cyl = bp->b_cylin; | |
308 | cyltrk.dar_trk = (bn / st->nsect) % st->ntrak; | |
309 | cyltrk.dar_sect = 0; | |
310 | printd("idcustart, unit %d, cyltrk 0x%x\n", unit, cyltrk.dar_dar); | |
311 | /* | |
312 | * If on cylinder, no need to seek. | |
313 | */ | |
314 | if (cyltrk.dar_dar == idccyl[ui->ui_unit].dar_dar) | |
315 | goto done; | |
316 | /* | |
317 | * RB80 can change heads (tracks) just by loading | |
318 | * the disk address register, perform optimization | |
319 | * here instead of doing a full seek. | |
320 | */ | |
321 | if (ui->ui_type && cyltrk.dar_cyl == idccyl[ui->ui_unit].dar_cyl) { | |
322 | idcaddr->idccsr = IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8); | |
323 | idcaddr->idcdar = cyltrk.dar_dar; | |
324 | idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar; | |
325 | goto done; | |
326 | } | |
327 | /* | |
328 | * Need to do a full seek. Select the unit, clear | |
329 | * its attention bit, set the command, load the | |
330 | * disk address register, and then go. | |
331 | */ | |
332 | idcaddr->idccsr = | |
333 | IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16)); | |
334 | idcaddr->idcdar = cyltrk.dar_dar; | |
335 | idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar; | |
336 | printd(" seek"); | |
337 | idcaddr->idccsr = IDC_IE|IDC_SEEK|(unit<<8); | |
338 | if (ui->ui_dk >= 0) { | |
339 | dk_busy |= 1<<ui->ui_dk; | |
340 | dk_seek[ui->ui_dk]++; | |
341 | } | |
342 | /* | |
343 | * RB80's initiate seeks very quickly. Wait for it | |
344 | * to come ready rather than taking the interrupt. | |
345 | */ | |
346 | if (ui->ui_type) { | |
347 | if (idcwait(idcaddr, 10) == 0) | |
348 | return (1); | |
349 | idcaddr->idccsr &= ~IDC_ATTN; | |
350 | /* has the seek completed? */ | |
351 | if (idcaddr->idccsr & IDC_DRDY) { | |
352 | printd(", drdy"); | |
353 | idcaddr->idccsr = | |
354 | IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16)); | |
355 | goto done; | |
356 | } | |
357 | } | |
358 | printd(", idccsr = 0x%x\n", idcaddr->idccsr); | |
359 | return (1); | |
360 | done: | |
361 | if (dp->b_active != 2) { | |
bc3a8383 | 362 | trace("!=2",dp->b_active); |
6c163e27 SL |
363 | dp->b_forw = NULL; |
364 | if (um->um_tab.b_actf == NULL) | |
365 | um->um_tab.b_actf = dp; | |
366 | else { | |
bc3a8383 | 367 | trace("!NUL",um->um_tab.b_actl); |
6c163e27 SL |
368 | um->um_tab.b_actl->b_forw = dp; |
369 | } | |
370 | um->um_tab.b_actl = dp; | |
371 | dp->b_active = 2; | |
372 | } | |
373 | return (0); | |
374 | } | |
375 | ||
376 | idcstart(um) | |
377 | register struct uba_ctlr *um; | |
378 | { | |
379 | register struct buf *bp, *dp; | |
380 | register struct uba_device *ui; | |
381 | register struct idcdevice *idcaddr; | |
382 | register struct idc_softc *sc; | |
383 | struct idcst *st; | |
384 | daddr_t bn; | |
385 | int sn, tn, cmd; | |
386 | ||
387 | loop: | |
388 | if ((dp = um->um_tab.b_actf) == NULL) { | |
bc3a8383 | 389 | trace("nodp",um); |
6c163e27 SL |
390 | return (0); |
391 | } | |
392 | if ((bp = dp->b_actf) == NULL) { | |
bc3a8383 | 393 | trace("nobp", dp); |
6c163e27 SL |
394 | um->um_tab.b_actf = dp->b_forw; |
395 | goto loop; | |
396 | } | |
397 | um->um_tab.b_active = 1; | |
dac559fa JB |
398 | ui = idcdinfo[idcunit(bp->b_dev)]; |
399 | bn = bp->b_blkno; | |
bc3a8383 | 400 | trace("star",bp); |
6c163e27 SL |
401 | if (ui->ui_type == 0) |
402 | bn *= 2; | |
403 | sc = &idc_softc; | |
404 | st = &idcst[ui->ui_type]; | |
405 | sn = bn%st->nspc; | |
406 | tn = sn/st->nsect; | |
407 | sn %= st->nsect; | |
408 | sc->sc_sect = sn; | |
409 | sc->sc_trk = tn; | |
410 | sc->sc_cyl = bp->b_cylin; | |
411 | idcaddr = (struct idcdevice *)ui->ui_addr; | |
412 | printd("idcstart, unit %d, dar 0x%x", ui->ui_slave, sc->sc_dar); | |
413 | if (bp->b_flags & B_READ) | |
414 | cmd = IDC_IE|IDC_READ|(ui->ui_slave<<8); | |
415 | else | |
416 | cmd = IDC_IE|IDC_WRITE|(ui->ui_slave<<8); | |
417 | idcaddr->idccsr = IDC_CRDY|cmd; | |
418 | if ((idcaddr->idccsr&IDC_DRDY) == 0) { | |
dac559fa | 419 | printf("rb%d: not ready\n", idcunit(bp->b_dev)); |
6c163e27 SL |
420 | um->um_tab.b_active = 0; |
421 | um->um_tab.b_errcnt = 0; | |
422 | dp->b_actf = bp->av_forw; | |
423 | dp->b_active = 0; | |
424 | bp->b_flags |= B_ERROR; | |
425 | iodone(bp); | |
426 | goto loop; | |
427 | } | |
428 | idccyl[ui->ui_unit].dar_dar = sc->sc_dar; | |
429 | idccyl[ui->ui_unit].dar_sect = 0; | |
430 | sn = (st->nsect - sn) * st->nbps; | |
431 | if (sn > bp->b_bcount) | |
432 | sn = bp->b_bcount; | |
433 | sc->sc_bcnt = sn; | |
434 | sc->sc_resid = bp->b_bcount; | |
435 | sc->sc_unit = ui->ui_slave; | |
436 | printd(", bcr 0x%x, cmd 0x%x\n", sn, cmd); | |
437 | um->um_cmd = cmd; | |
438 | (void) ubago(ui); | |
439 | return (1); | |
440 | } | |
441 | ||
442 | idcdgo(um) | |
443 | register struct uba_ctlr *um; | |
444 | { | |
445 | register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr; | |
446 | register struct idc_softc *sc = &idc_softc; | |
447 | ||
448 | /* | |
449 | * VERY IMPORTANT: must load registers in this order. | |
450 | */ | |
451 | idcaddr->idcbar = sc->sc_ubaddr = um->um_ubinfo&0x3ffff; | |
452 | idcaddr->idcbcr = -sc->sc_bcnt; | |
453 | idcaddr->idcdar = sc->sc_dar; | |
454 | printd("idcdgo, ubinfo 0x%x, cmd 0x%x\n", um->um_ubinfo, um->um_cmd); | |
455 | idcaddr->idccsr = um->um_cmd; | |
bc3a8383 | 456 | trace("go", um); |
6c163e27 SL |
457 | um->um_tab.b_active = 2; |
458 | /*** CLEAR SPURIOUS ATTN ON R80? ***/ | |
459 | } | |
460 | ||
461 | idcintr(idc) | |
462 | int idc; | |
463 | { | |
464 | register struct uba_ctlr *um = idcminfo[idc]; | |
465 | register struct uba_device *ui; | |
466 | register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr; | |
467 | register struct idc_softc *sc = &idc_softc; | |
468 | register struct buf *bp, *dp; | |
469 | struct idcst *st; | |
470 | int unit, as, er, cmd, ds = 0; | |
471 | ||
472 | printd("idcintr, idccsr 0x%x", idcaddr->idccsr); | |
473 | top: | |
474 | idcwticks = 0; | |
bc3a8383 | 475 | trace("intr", um->um_tab.b_active); |
6c163e27 SL |
476 | if (um->um_tab.b_active == 2) { |
477 | /* | |
478 | * Process a data transfer complete interrupt. | |
479 | */ | |
480 | um->um_tab.b_active = 1; | |
481 | dp = um->um_tab.b_actf; | |
482 | bp = dp->b_actf; | |
dac559fa | 483 | ui = idcdinfo[idcunit(bp->b_dev)]; |
6c163e27 SL |
484 | unit = ui->ui_slave; |
485 | st = &idcst[ui->ui_type]; | |
486 | idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8); | |
487 | if ((er = idcaddr->idccsr) & IDC_ERR) { | |
488 | if (er & IDC_DE) { | |
489 | idcaddr->idcmpr = IDCGS_GETSTAT; | |
490 | idcaddr->idccsr = IDC_GETSTAT|(unit<<8); | |
ac76a23d | 491 | (void) idcwait(idcaddr, 0); |
6c163e27 SL |
492 | ds = idcaddr->idcmpr; |
493 | idcaddr->idccsr = | |
494 | IDC_IE|IDC_CRDY|(1<<(unit+16)); | |
495 | } | |
496 | printd(", er 0x%x, ds 0x%x", er, ds); | |
497 | if (ds & IDCDS_WL) { | |
dac559fa JB |
498 | printf("rb%d: write locked\n", |
499 | idcunit(bp->b_dev)); | |
6c163e27 SL |
500 | bp->b_flags |= B_ERROR; |
501 | } else if (++um->um_tab.b_errcnt > 28 || er&IDC_HARD) { | |
502 | hard: | |
503 | harderr(bp, "rb"); | |
504 | printf("csr=%b ds=%b\n", er, IDCCSR_BITS, ds, | |
505 | ui->ui_type?IDCRB80DS_BITS:IDCRB02DS_BITS); | |
506 | bp->b_flags |= B_ERROR; | |
507 | } else if (er & IDC_DCK) { | |
580dd3c9 | 508 | switch ((int)(er & IDC_ECS)) { |
6c163e27 SL |
509 | case IDC_ECS_NONE: |
510 | break; | |
511 | case IDC_ECS_SOFT: | |
512 | idcecc(ui); | |
513 | break; | |
514 | case IDC_ECS_HARD: | |
515 | default: | |
516 | goto hard; | |
517 | } | |
518 | } else | |
519 | /* recoverable error, set up for retry */ | |
520 | goto seek; | |
521 | } | |
522 | if ((sc->sc_resid -= sc->sc_bcnt) != 0) { | |
523 | sc->sc_ubaddr += sc->sc_bcnt; | |
524 | /* | |
525 | * Current transfer is complete, have | |
526 | * we overflowed to the next track? | |
527 | */ | |
528 | if ((sc->sc_sect += sc->sc_bcnt/st->nbps) == st->nsect) { | |
529 | sc->sc_sect = 0; | |
530 | if (++sc->sc_trk == st->ntrak) { | |
531 | sc->sc_trk = 0; | |
532 | sc->sc_cyl++; | |
533 | } else if (ui->ui_type) { | |
534 | /* | |
535 | * RB80 can change heads just by | |
536 | * loading the disk address register. | |
537 | */ | |
538 | idcaddr->idccsr = IDC_SEEK|IDC_CRDY| | |
539 | IDC_IE|(unit<<8); | |
540 | printd(", change to track 0x%x", sc->sc_dar); | |
541 | idcaddr->idcdar = sc->sc_dar; | |
542 | idccyl[ui->ui_unit].dar_dar = sc->sc_dar; | |
543 | idccyl[ui->ui_unit].dar_sect = 0; | |
544 | goto cont; | |
545 | } | |
546 | /* | |
547 | * Changing tracks on RB02 or cylinders | |
548 | * on RB80, start a seek. | |
549 | */ | |
550 | seek: | |
551 | cmd = IDC_IE|IDC_SEEK|(unit<<8); | |
552 | idcaddr->idccsr = cmd|IDC_CRDY; | |
553 | idcaddr->idcdar = sc->sc_dar; | |
554 | printd(", seek to 0x%x\n", sc->sc_dar); | |
555 | idccyl[ui->ui_unit].dar_dar = sc->sc_dar; | |
556 | idccyl[ui->ui_unit].dar_sect = 0; | |
557 | sc->sc_bcnt = 0; | |
558 | idcaddr->idccsr = cmd; | |
559 | if (ui->ui_type) { | |
560 | if (idcwait(idcaddr, 10) == 0) | |
561 | return; | |
562 | idcaddr->idccsr &= ~IDC_ATTN; | |
563 | if (idcaddr->idccsr & IDC_DRDY) | |
564 | goto top; | |
565 | } | |
566 | } else { | |
567 | /* | |
568 | * Continue transfer on current track. | |
569 | */ | |
570 | cont: | |
571 | sc->sc_bcnt = (st->nsect-sc->sc_sect)*st->nbps; | |
572 | if (sc->sc_bcnt > sc->sc_resid) | |
573 | sc->sc_bcnt = sc->sc_resid; | |
574 | if (bp->b_flags & B_READ) | |
575 | cmd = IDC_IE|IDC_READ|(unit<<8); | |
576 | else | |
577 | cmd = IDC_IE|IDC_WRITE|(unit<<8); | |
578 | idcaddr->idccsr = cmd|IDC_CRDY; | |
579 | idcaddr->idcbar = sc->sc_ubaddr; | |
580 | idcaddr->idcbcr = -sc->sc_bcnt; | |
581 | idcaddr->idcdar = sc->sc_dar; | |
582 | printd(", continue I/O 0x%x, 0x%x\n", sc->sc_dar, sc->sc_bcnt); | |
583 | idcaddr->idccsr = cmd; | |
584 | um->um_tab.b_active = 2; | |
585 | } | |
586 | return; | |
587 | } | |
588 | /* | |
589 | * Entire transfer is done, clean up. | |
590 | */ | |
591 | ubadone(um); | |
592 | dk_busy &= ~(1 << ui->ui_dk); | |
593 | um->um_tab.b_active = 0; | |
594 | um->um_tab.b_errcnt = 0; | |
595 | um->um_tab.b_actf = dp->b_forw; | |
596 | dp->b_active = 0; | |
597 | dp->b_errcnt = 0; | |
598 | dp->b_actf = bp->av_forw; | |
bc3a8383 | 599 | trace("done", dp); trace(&um->um_tab.b_actf, dp->b_actf); |
6c163e27 SL |
600 | bp->b_resid = sc->sc_resid; |
601 | printd(", iodone, resid 0x%x\n", bp->b_resid); | |
602 | iodone(bp); | |
603 | if (dp->b_actf) | |
604 | if (idcustart(ui)) | |
605 | return; | |
606 | } else if (um->um_tab.b_active == 1) { | |
607 | /* | |
608 | * Got an interrupt while setting up for a command | |
609 | * or doing a mid-transfer seek. Save any attentions | |
610 | * for later and process a mid-transfer seek complete. | |
611 | */ | |
612 | as = idcaddr->idccsr; | |
613 | idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN); | |
614 | as = (as >> 16) & 0xf; | |
615 | unit = sc->sc_unit; | |
616 | sc->sc_softas |= as & ~(1<<unit); | |
617 | if (as & (1<<unit)) { | |
618 | printd(", seek1 complete"); | |
619 | um->um_tab.b_active = 2; | |
620 | goto top; | |
621 | } | |
622 | printd(", as1 %o\n", as); | |
623 | return; | |
624 | } | |
625 | /* | |
626 | * Process any seek initiated or complete interrupts. | |
627 | */ | |
628 | as = idcaddr->idccsr; | |
629 | idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN); | |
630 | as = ((as >> 16) & 0xf) | sc->sc_softas; | |
631 | sc->sc_softas = 0; | |
bc3a8383 | 632 | trace("as", as); |
6c163e27 SL |
633 | printd(", as %o", as); |
634 | for (unit = 0; unit < NRB; unit++) | |
635 | if (as & (1<<unit)) { | |
636 | as &= ~(1<<unit); | |
637 | idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8); | |
638 | ui = idcdinfo[unit]; | |
639 | if (ui) { | |
640 | printd(", attn unit %d", unit); | |
641 | if (idcaddr->idccsr & IDC_DRDY) | |
642 | if (idcustart(ui)) { | |
643 | sc->sc_softas = as; | |
644 | return; | |
645 | } | |
646 | } else { | |
647 | printd(", unsol. intr. unit %d", unit); | |
648 | } | |
649 | } | |
650 | printd("\n"); | |
651 | if (um->um_tab.b_actf && um->um_tab.b_active == 0) { | |
bc3a8383 | 652 | trace("stum",um->um_tab.b_actf); |
ac76a23d | 653 | (void) idcstart(um); |
6c163e27 SL |
654 | } |
655 | } | |
656 | ||
bc3a8383 | 657 | idcwait(addr, n) |
6c163e27 | 658 | register struct idcdevice *addr; |
bc3a8383 | 659 | register int n; |
6c163e27 SL |
660 | { |
661 | register int i; | |
662 | ||
bc3a8383 | 663 | while (--n && (addr->idccsr & IDC_CRDY) == 0) |
6c163e27 SL |
664 | for (i = 10; i; i--) |
665 | ; | |
bc3a8383 | 666 | return (n); |
6c163e27 SL |
667 | } |
668 | ||
740e4029 | 669 | idcread(dev, uio) |
6c163e27 | 670 | dev_t dev; |
740e4029 | 671 | struct uio *uio; |
6c163e27 | 672 | { |
dac559fa | 673 | register int unit = idcunit(dev); |
6c163e27 SL |
674 | |
675 | if (unit >= NRB) | |
aa890753 BJ |
676 | return (ENXIO); |
677 | return (physio(idcstrategy, &ridcbuf[unit], dev, B_READ, minphys, uio)); | |
6c163e27 SL |
678 | } |
679 | ||
406ddcbe | 680 | idcwrite(dev, uio) |
6c163e27 | 681 | dev_t dev; |
406ddcbe | 682 | struct uio *uio; |
6c163e27 | 683 | { |
dac559fa | 684 | register int unit = idcunit(dev); |
6c163e27 SL |
685 | |
686 | if (unit >= NRB) | |
aa890753 BJ |
687 | return (ENXIO); |
688 | return (physio(idcstrategy, &ridcbuf[unit], dev, B_WRITE, minphys, uio)); | |
6c163e27 SL |
689 | } |
690 | ||
691 | idcecc(ui) | |
692 | register struct uba_device *ui; | |
693 | { | |
694 | register struct idcdevice *idc = (struct idcdevice *)ui->ui_addr; | |
695 | register struct buf *bp = idcutab[ui->ui_unit].b_actf; | |
696 | register struct uba_ctlr *um = ui->ui_mi; | |
697 | register struct idcst *st; | |
698 | register int i; | |
699 | struct uba_regs *ubp = ui->ui_hd->uh_uba; | |
700 | int bit, byte, mask; | |
701 | caddr_t addr; | |
702 | int reg, npf, o; | |
703 | int cn, tn, sn; | |
704 | ||
6c163e27 SL |
705 | npf = btop(idc->idcbcr + idc_softc.sc_bcnt) - 1;; |
706 | reg = btop(idc_softc.sc_ubaddr) + npf; | |
707 | o = (int)bp->b_un.b_addr & PGOFSET; | |
708 | st = &idcst[ui->ui_type]; | |
709 | cn = idc_softc.sc_cyl; | |
710 | tn = idc_softc.sc_trk; | |
711 | sn = idc_softc.sc_sect; | |
712 | um->um_tab.b_active = 1; /* Either complete or continuing... */ | |
283ffc90 | 713 | log(LOG_WARNING, "rb%d%c: soft ecc sn%d\n", idcunit(bp->b_dev), |
6c163e27 SL |
714 | 'a'+(minor(bp->b_dev)&07), |
715 | (cn*st->ntrak + tn) * st->nsect + sn + npf); | |
716 | mask = idc->idceccpat; | |
717 | i = idc->idceccpos - 1; /* -1 makes 0 origin */ | |
718 | bit = i&07; | |
719 | i = (i&~07)>>3; | |
720 | byte = i + o; | |
721 | while (i < 512 && (int)ptob(npf)+i < idc_softc.sc_bcnt && bit > -11) { | |
049855d8 KM |
722 | /* |
723 | * should be: | |
724 | * addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ | |
725 | * (byte & PGOFSET); | |
726 | * but this generates an extzv which hangs the UNIBUS. | |
727 | */ | |
728 | addr = ptob(*(int *)&ubp->uba_map[reg+btop(byte)]&0x1fffff)+ | |
6c163e27 SL |
729 | (byte & PGOFSET); |
730 | putmemc(addr, getmemc(addr)^(mask<<bit)); | |
731 | byte++; | |
732 | i++; | |
733 | bit -= 8; | |
734 | } | |
735 | idc_softc.sc_bcnt += idc->idcbcr; | |
736 | um->um_tab.b_errcnt = 0; /* error has been corrected */ | |
737 | return; | |
738 | } | |
739 | ||
740 | idcreset(uban) | |
741 | int uban; | |
742 | { | |
743 | register struct uba_ctlr *um; | |
744 | register struct uba_device *ui; | |
745 | register unit; | |
746 | ||
747 | if ((um = idcminfo[0]) == 0 || um->um_ubanum != uban || | |
748 | um->um_alive == 0) | |
749 | return; | |
750 | printf(" idc0"); | |
751 | um->um_tab.b_active = 0; | |
752 | um->um_tab.b_actf = um->um_tab.b_actl = 0; | |
753 | if (um->um_ubinfo) { | |
754 | printf("<%d>", (um->um_ubinfo>>28)&0xf); | |
96b997eb | 755 | um->um_ubinfo = 0; |
6c163e27 SL |
756 | } |
757 | for (unit = 0; unit < NRB; unit++) { | |
758 | if ((ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0) | |
759 | continue; | |
760 | idcutab[unit].b_active = 0; | |
761 | (void) idcustart(ui); | |
762 | } | |
763 | (void) idcstart(um); | |
764 | } | |
765 | ||
766 | idcwatch() | |
767 | { | |
768 | register struct uba_ctlr *um; | |
769 | register unit; | |
770 | ||
771 | timeout(idcwatch, (caddr_t)0, hz); | |
772 | um = idcminfo[0]; | |
773 | if (um == 0 || um->um_alive == 0) | |
774 | return; | |
775 | if (um->um_tab.b_active == 0) { | |
776 | for (unit = 0; unit < NRB; unit++) | |
777 | if (idcutab[unit].b_active) | |
778 | goto active; | |
779 | idcwticks = 0; | |
780 | return; | |
781 | } | |
782 | active: | |
783 | idcwticks++; | |
784 | if (idcwticks >= 20) { | |
785 | idcwticks = 0; | |
786 | printf("idc0: lost interrupt\n"); | |
787 | idcintr(0); | |
788 | } | |
789 | } | |
790 | ||
bc3a8383 | 791 | /*ARGSUSED*/ |
6c163e27 SL |
792 | idcdump(dev) |
793 | dev_t dev; | |
794 | { | |
6c163e27 SL |
795 | struct idcdevice *idcaddr; |
796 | char *start; | |
2b5d41cf | 797 | int num, blk, unit; |
6c163e27 SL |
798 | struct size *sizes; |
799 | register struct uba_regs *uba; | |
800 | register struct uba_device *ui; | |
801 | struct idcst *st; | |
66923854 | 802 | union idc_dar dar; |
2b5d41cf | 803 | int nspg; |
6c163e27 | 804 | |
dac559fa | 805 | unit = idcunit(dev); |
6c163e27 SL |
806 | if (unit >= NRB) |
807 | return (ENXIO); | |
808 | #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) | |
809 | ui = phys(struct uba_device *, idcdinfo[unit]); | |
810 | if (ui->ui_alive == 0) | |
811 | return (ENXIO); | |
812 | uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; | |
813 | ubainit(uba); | |
814 | idcaddr = (struct idcdevice *)ui->ui_physaddr; | |
2b5d41cf BJ |
815 | if (idcwait(idcaddr, 100) == 0) |
816 | return (EFAULT); | |
817 | /* | |
818 | * Since we can only transfer one track at a time, and | |
819 | * the rl02 has 256 byte sectors, all the calculations | |
820 | * are done in terms of physical sectors (i.e. num and blk | |
821 | * are in sectors not NBPG blocks. | |
822 | */ | |
823 | st = phys(struct idcst *, &idcst[ui->ui_type]); | |
6c163e27 | 824 | sizes = phys(struct size *, st->sizes); |
46f6960a | 825 | if (dumplo < 0) |
6c163e27 | 826 | return (EINVAL); |
46f6960a JB |
827 | if (dumplo + maxfree >= sizes[minor(dev)&07].nblocks) |
828 | num = sizes[minor(dev)&07].nblocks - dumplo; | |
2b5d41cf | 829 | nspg = NBPG / st->nbps; |
46f6960a | 830 | num = num * nspg; |
2b5d41cf BJ |
831 | start = 0; |
832 | ||
6c163e27 SL |
833 | while (num > 0) { |
834 | register struct pte *io; | |
835 | register int i; | |
6c163e27 SL |
836 | daddr_t bn; |
837 | ||
2b5d41cf BJ |
838 | bn = (dumplo + btop(start)) * nspg; |
839 | dar.dar_cyl = bn / st->nspc + sizes[minor(dev)&07].cyloff; | |
840 | bn %= st->nspc; | |
841 | dar.dar_trk = bn / st->nsect; | |
842 | dar.dar_sect = bn % st->nsect; | |
843 | blk = st->nsect - dar.dar_sect; | |
844 | if (num < blk) | |
845 | blk = num; | |
846 | ||
6c163e27 | 847 | io = uba->uba_map; |
2b5d41cf | 848 | for (i = 0; i < (blk + nspg - 1) / nspg; i++) |
6c163e27 SL |
849 | *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; |
850 | *(int *)io = 0; | |
2b5d41cf BJ |
851 | |
852 | idcaddr->idccsr = IDC_CRDY | IDC_SEEK | unit<<8; | |
853 | if ((idcaddr->idccsr&IDC_DRDY) == 0) | |
854 | return (EFAULT); | |
855 | idcaddr->idcdar = dar.dar_dar; | |
856 | idcaddr->idccsr = IDC_SEEK | unit << 8; | |
857 | while ((idcaddr->idccsr & (IDC_CRDY|IDC_DRDY)) | |
858 | != (IDC_CRDY|IDC_DRDY)) | |
859 | ; | |
860 | if (idcaddr->idccsr & IDC_ERR) { | |
861 | printf("rb%d: seek, csr=%b\n", | |
862 | unit, idcaddr->idccsr, IDCCSR_BITS); | |
863 | return (EIO); | |
864 | } | |
865 | ||
866 | idcaddr->idccsr = IDC_CRDY | IDC_WRITE | unit<<8; | |
867 | if ((idcaddr->idccsr&IDC_DRDY) == 0) | |
868 | return (EFAULT); | |
869 | idcaddr->idcbar = 0; /* start addr 0 */ | |
870 | idcaddr->idcbcr = - (blk * st->nbps); | |
871 | idcaddr->idcdar = dar.dar_dar; | |
872 | idcaddr->idccsr = IDC_WRITE | unit << 8; | |
873 | while ((idcaddr->idccsr & (IDC_CRDY|IDC_DRDY)) | |
874 | != (IDC_CRDY|IDC_DRDY)) | |
875 | ; | |
876 | if (idcaddr->idccsr & IDC_ERR) { | |
877 | printf("rb%d: write, csr=%b\n", | |
878 | unit, idcaddr->idccsr, IDCCSR_BITS); | |
6c163e27 | 879 | return (EIO); |
2b5d41cf BJ |
880 | } |
881 | ||
882 | start += blk * st->nbps; | |
6c163e27 SL |
883 | num -= blk; |
884 | } | |
885 | return (0); | |
6c163e27 | 886 | } |
cf83ab8e SL |
887 | |
888 | idcsize(dev) | |
889 | dev_t dev; | |
890 | { | |
dac559fa | 891 | int unit = idcunit(dev); |
cf83ab8e SL |
892 | struct uba_device *ui; |
893 | struct idcst *st; | |
894 | ||
895 | if (unit >= NRB || (ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0) | |
896 | return (-1); | |
897 | st = &idcst[ui->ui_type]; | |
898 | return (st->sizes[minor(dev) & 07].nblocks); | |
899 | } | |
6c163e27 | 900 | #endif |