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