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