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