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