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