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