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