add rd53
[unix-history] / usr / src / sys / vax / uba / idc.c
CommitLineData
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
11int idcdebug = 0;
12#define printd if(idcdebug)printf
13int idctrb[1000];
14int *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
48struct 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 */
73struct 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
97int idcprobe(), idcslave(), idcattach(), idcdgo(), idcintr();
98struct uba_ctlr *idcminfo[NIDC];
99struct uba_device *idcdinfo[NRB];
100
101u_short idcstd[] = { 0174400, 0};
102struct uba_driver idcdriver =
103 { idcprobe, idcslave, idcattach, idcdgo, idcstd, "rb", idcdinfo, "idc", idcminfo, 0 };
104struct buf idcutab[NRB];
105union idc_dar idccyl[NRB];
106
107struct 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
119struct buf ridcbuf[NRB];
120
121#define b_cylin b_resid
122
6c163e27
SL
123int idcwstart, idcwticks, idcwatch();
124
bc3a8383 125/*ARGSUSED*/
6c163e27
SL
126idcprobe(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
144idcslave(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
179idcattach(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
202idcopen(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
213idcstrategy(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
261bad:
262 bp->b_flags |= B_ERROR;
dac559fa 263done:
6c163e27
SL
264 iodone(bp);
265 return;
266}
267
268idcustart(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);
360done:
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
376idcstart(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
387loop:
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
442idcdgo(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
461idcintr(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);
473top:
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) {
502hard:
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 */
550seek:
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 */
570cont:
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 657idcwait(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 669idcread(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 680idcwrite(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
691idcecc(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
740idcreset(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
766idcwatch()
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 }
782active:
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
792idcdump(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
888idcsize(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