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