xref: /csrg-svn/sys/vax/uba/idc.c (revision 9354)
1 /*	idc.c	4.10	82/11/26	*/
2 
3 #include "rb.h"
4 #if NIDC > 0
5 int	idcdebug = 0;
6 #define	printd if(idcdebug)printf
7 int	idctrb[1000];
8 int	*trp = idctrb;
9 #define	trace(a,b) {*trp++ = *(int*)a; *trp++ = (int)b; if(trp>&idctrb[998])trp=idctrb;}
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"
31 #include "../h/dk.h"
32 #include "../h/cmap.h"
33 #include "../h/dkbad.h"
34 #include "../h/uio.h"
35 
36 #include "../vax/cpu.h"
37 #include "../vaxuba/ubareg.h"
38 #include "../vaxuba/ubavar.h"
39 #include "../vaxuba/idcreg.h"
40 
41 struct 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 */
64 struct 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 
88 int	idcprobe(), idcslave(), idcattach(), idcdgo(), idcintr();
89 struct	uba_ctlr *idcminfo[NIDC];
90 struct	uba_device *idcdinfo[NRB];
91 
92 u_short	idcstd[] = { 0174400, 0};
93 struct	uba_driver idcdriver =
94  { idcprobe, idcslave, idcattach, idcdgo, idcstd, "rb", idcdinfo, "idc", idcminfo, 0 };
95 struct	buf idcutab[NRB];
96 union	idc_dar idccyl[NRB];
97 
98 struct	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 
110 struct	buf ridcbuf[NRB];
111 
112 #define	b_cylin	b_resid
113 
114 #ifdef INTRLVE
115 daddr_t	dkblock();
116 #endif
117 
118 int	idcwstart, idcwticks, idcwatch();
119 
120 /*ARGSUSED*/
121 idcprobe(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;
135 	return (sizeof (struct idcdevice));
136 }
137 
138 /*ARGSUSED*/
139 idcslave(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);
150 	(void) idcwait(idcaddr, 0);
151 	i = idcaddr->idcmpr;
152 	idcaddr->idccsr = IDC_CRDY|(1<<(ui->ui_slave+16));
153 	/* read header to synchronize microcode */
154 	(void) idcwait(idcaddr, 0);
155 	idcaddr->idccsr = (ui->ui_slave<<8)|IDC_RHDR;
156 	(void) idcwait(idcaddr, 0);
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 */
161 #ifdef lint
162 	i = i;
163 #endif
164 	if (idcaddr->idccsr&IDC_R80)
165 		ui->ui_type = 1;
166 	return (1);
167 }
168 
169 idcattach(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 }
191 
192 idcopen(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 }
202 
203 idcstrategy(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();
228 	trace("strt",bp);
229 	dp = &idcutab[ui->ui_unit];
230 	disksort(dp, bp);
231 	if (dp->b_active == 0) {
232 		trace("!act",dp);
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 
241 bad:
242 	bp->b_flags |= B_ERROR;
243 	iodone(bp);
244 	return;
245 }
246 
247 idcustart(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;
264 	trace("ust", dp);
265 	idcaddr = (struct idcdevice *)um->um_addr;
266 	if (um->um_tab.b_active) {
267 		idc_softc.sc_softas |= 1<<unit;
268 		trace("umac",idc_softc.sc_softas);
269 		return (0);
270 	}
271 	if ((bp = dp->b_actf) == NULL) {
272 		trace("!bp",0);
273 		return (0);
274 	}
275 	if (dp->b_active) {
276 		trace("dpac",dp->b_active);
277 		goto done;
278 	}
279 	dp->b_active = 1;
280 	/* CHECK DRIVE READY? */
281 	bn = dkblock(bp);
282 	trace("seek", bn);
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);
339 done:
340 	if (dp->b_active != 2) {
341 		trace("!=2",dp->b_active);
342 		dp->b_forw = NULL;
343 		if (um->um_tab.b_actf == NULL)
344 			um->um_tab.b_actf = dp;
345 		else {
346 			trace("!NUL",um->um_tab.b_actl);
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 
355 idcstart(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 
366 loop:
367 	if ((dp = um->um_tab.b_actf) == NULL) {
368 		trace("nodp",um);
369 		return (0);
370 	}
371 	if ((bp = dp->b_actf) == NULL) {
372 		trace("nobp", dp);
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);
379 	trace("star",bp);
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 
421 idcdgo(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;
435 	trace("go", um);
436 	um->um_tab.b_active = 2;
437 	/*** CLEAR SPURIOUS ATTN ON R80? ***/
438 }
439 
440 idcintr(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);
452 top:
453 	idcwticks = 0;
454 	trace("intr", um->um_tab.b_active);
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);
470 				(void) idcwait(idcaddr, 0);
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) {
480 hard:
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 				 */
528 seek:
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 				 */
548 cont:
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;
577 		trace("done", dp); trace(&um->um_tab.b_actf, dp->b_actf);
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;
610 	trace("as", as);
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) {
630 		trace("stum",um->um_tab.b_actf);
631 		(void) idcstart(um);
632 	}
633 }
634 
635 idcwait(addr, n)
636 	register struct idcdevice *addr;
637 	register int n;
638 {
639 	register int i;
640 
641 	while (--n && (addr->idccsr & IDC_CRDY) == 0)
642 		for (i = 10; i; i--)
643 			;
644 	return (n);
645 }
646 
647 idcread(dev, uio)
648 	dev_t dev;
649 	struct uio *uio;
650 {
651 	register int unit = minor(dev) >> 3;
652 
653 	if (unit >= NRB)
654 		return (ENXIO);
655 	return (physio(idcstrategy, &ridcbuf[unit], dev, B_READ, minphys, uio));
656 }
657 
658 idcwrite(dev, uio)
659 	dev_t dev;
660 	struct uio *uio;
661 {
662 	register int unit = minor(dev) >> 3;
663 
664 	if (unit >= NRB)
665 		return (ENXIO);
666 	return (physio(idcstrategy, &ridcbuf[unit], dev, B_WRITE, minphys, uio));
667 }
668 
669 idcecc(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 
713 idcreset(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);
728 		um->um_ubinfo = 0;
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 
739 idcwatch()
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 	}
755 active:
756 	idcwticks++;
757 	if (idcwticks >= 20) {
758 		idcwticks = 0;
759 		printf("idc0: lost interrupt\n");
760 		idcintr(0);
761 	}
762 }
763 
764 /*ARGSUSED*/
765 idcdump(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;
793 	(void) idcwait(idcaddr);
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;
823 		(void) idcwait(idcaddr);
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
836