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