xref: /csrg-svn/sys/vax/uba/up.c (revision 2298)
1 /*	up.c	4.11	01/28/81	*/
2 
3 #include "up.h"
4 #if NUP > 0
5 #if SC11 > 0
6 #include "../dev/up.c.SC11"
7 #else
8 /*
9  * UNIBUS disk driver with overlapped seeks and ECC recovery.
10  */
11 #define	DELAY(N)		{ register int d; d = N; while (--d > 0); }
12 
13 #include "../h/param.h"
14 #include "../h/systm.h"
15 #include "../h/dk.h"
16 #include "../h/buf.h"
17 #include "../h/conf.h"
18 #include "../h/dir.h"
19 #include "../h/user.h"
20 #include "../h/map.h"
21 #include "../h/pte.h"
22 #include "../h/mba.h"
23 #include "../h/mtpr.h"
24 #include "../h/uba.h"
25 #include "../h/vm.h"
26 
27 #define	ushort	unsigned short
28 
29 struct	device
30 {
31 	ushort	upcs1;		/* control and status register 1 */
32 	short	upwc;		/* word count register */
33 	ushort	upba;		/* UNIBUS address register */
34 	ushort	upda;		/* desired address register */
35 	ushort	upcs2;		/* control and status register 2 */
36 	ushort	upds;		/* drive Status */
37 	ushort	uper1;		/* error register 1 */
38 	ushort	upas;		/* attention summary */
39 	ushort	upla;		/* look ahead */
40 	ushort	updb;		/* data buffer */
41 	ushort	upmr;		/* maintenance */
42 	ushort	updt;		/* drive type */
43 	ushort	upsn;		/* serial number */
44 	ushort	upof;		/* offset register */
45 	ushort	updc;		/* desired cylinder address register */
46 	ushort	upcc;		/* current cylinder */
47 	ushort	uper2;		/* error register 2 */
48 	ushort	uper3;		/* error register 3 */
49 	ushort	upec1;		/* burst error bit position */
50 	ushort	upec2;		/* burst error bit pattern */
51 };
52 
53 /*
54  * Software extension to the upas register, so we can
55  * postpone starting SEARCH commands until the controller
56  * is not transferring.
57  */
58 int	upsoftas;
59 
60 /*
61  * If upseek then we don't issue SEARCH commands but rather just
62  * settle for a SEEK to the correct cylinder.
63  */
64 int	upseek;
65 
66 #define	NSECT	32
67 #define	NTRAC	19
68 
69 /*
70  * Constants controlling on-cylinder SEARCH usage.
71  *
72  * 	upSDIST/2 msec		time needed to start transfer
73  * 	upRDIST/2 msec		tolerable rotational latency when on-cylinder
74  *
75  * If we are no closer than upSDIST sectors and no further than upSDIST+upRDIST
76  * and in the driver then we take it as it is.  Otherwise we do a SEARCH
77  * requesting an interrupt upSDIST sectors in advance.
78  */
79 #define	_upSDIST	2		/* 1.0 msec */
80 #define	_upRDIST	4		/* 2.0 msec */
81 
82 int	upSDIST = _upSDIST;
83 int	upRDIST = _upRDIST;
84 
85 /*
86  * To fill a 300M drive:
87  *	A is designed to be used as a root.
88  *	B is suitable for a swap area.
89  *	H is the primary storage area.
90  * On systems with RP06'es, we normally use only 291346 blocks of the H
91  * area, and use DEF or G to cover the rest of the drive.  The C system
92  * covers the whole drive and can be used for pack-pack copying.
93  *
94  * Note: sizes here are for AMPEX drives with 815 cylinders.
95  * CDC drives can make the F,G, and H areas larger as they have 823 cylinders.
96  */
97 struct	size
98 {
99 	daddr_t	nblocks;
100 	int	cyloff;
101 } up_sizes[8] = {
102 	15884,	0,		/* A=cyl 0 thru 26 */
103 	33440,	27,		/* B=cyl 27 thru 81 */
104 	495520,	0,		/* C=cyl 0 thru 814 */
105 	15884,	562,		/* D=cyl 562 thru 588 */
106 	55936,	589,		/* E=cyl 589 thru 680 */
107 	81472,	681,		/* F=cyl 681 thru 814 */
108 	153824,	562,		/* G=cyl 562 thru 814 */
109 	291346,	82,		/* H=cyl 82 thru 561 */
110 };
111 
112 /*
113  * The following defines are used in offset positioning
114  * when trying to recover disk errors, with the constants being
115  * +/- microinches.  Note that header compare inhibit (HCI) is not
116  * tried (this makes sense only during read, in any case.)
117  *
118  * NB: Not all drives/controllers emulate all of these.
119  */
120 #define	P400	020
121 #define	M400	0220
122 #define	P800	040
123 #define	M800	0240
124 #define	P1200	060
125 #define	M1200	0260
126 #define	HCI	020000
127 
128 int	up_offset[16] =
129 {
130 	P400, M400, P400, M400,
131 	P800, M800, P800, M800,
132 	P1200, M1200, P1200, M1200,
133 	0, 0, 0, 0,
134 };
135 
136 /*
137  * Each drive has a table uputab[i].  On this table are sorted the
138  * pending requests implementing an elevator algorithm (see dsort.c.)
139  * In the upustart() routine, each drive is independently advanced
140  * until it is on the desired cylinder for the next transfer and near
141  * the desired sector.  The drive is then chained onto the uptab
142  * table, and the transfer is initiated by the upstart() routine.
143  * When the transfer is completed the driver reinvokes the upustart()
144  * routine to set up the next transfer.
145  */
146 struct	buf	uptab;
147 struct	buf	uputab[NUP];
148 
149 struct	buf	rupbuf;			/* Buffer for raw i/o */
150 
151 /* Drive commands, placed in upcs1 */
152 #define	GO	01		/* Go bit, set in all commands */
153 #define	PRESET	020		/* Preset drive at init or after errors */
154 #define	OFFSET	014		/* Offset heads to try to recover error */
155 #define	RTC	016		/* Return to center-line after OFFSET */
156 #define	SEARCH	030		/* Search for cylinder+sector */
157 #define	SEEK	04		/* Seek to cylinder */
158 #define	RECAL	06		/* Recalibrate, needed after seek error */
159 #define	DCLR	010		/* Drive clear, after error */
160 #define	WCOM	060		/* Write */
161 #define	RCOM	070		/* Read */
162 
163 /* Other bits of upcs1 */
164 #define	IE	0100		/* Controller wide interrupt enable */
165 #define	TRE	040000		/* Transfer error */
166 #define	RDY	0200		/* Transfer terminated */
167 
168 /* Drive status bits of upds */
169 #define	PIP	020000		/* Positioning in progress */
170 #define	ERR	040000		/* Error has occurred, DCLR necessary */
171 #define	VV	0100		/* Volume is valid, set by PRESET */
172 #define	DPR	0400		/* Drive has been preset */
173 #define	MOL	010000		/* Drive is online, heads loaded, etc */
174 #define	DRY	0200		/* Drive ready */
175 
176 /* Bits of upcs2 */
177 #define	CLR	040		/* Controller clear */
178 #define	MXF	01000
179 #define	NEM	04000
180 
181 /* Bits of uper1 */
182 #define	DCK	0100000		/* Ecc error occurred */
183 #define	ECH	0100		/* Ecc error was unrecoverable */
184 #define	WLE	04000		/* Attempt to write read-only drive */
185 
186 /* Bits of upof; the offset bits above are also in this register */
187 #define	FMT22	010000		/* 16 bits/word, must be always set */
188 
189 #define	b_cylin b_resid
190 
191 int	up_ubinfo;		/* Information about UBA usage saved here */
192 
193 int	up_wticks;		/* Ticks waiting for interrupt */
194 int	upwstart;		/* Have started guardian */
195 int	upwatch();
196 
197 #ifdef INTRLVE
198 daddr_t dkblock();
199 #endif
200 
201 /*
202  * Queue an i/o request for a drive, checking first that it is in range.
203  *
204  * A unit start is issued if the drive is inactive, causing
205  * a SEARCH for the correct cylinder/sector.  If the drive is
206  * already nearly on the money and the controller is not transferring
207  * we kick it to start the transfer.
208  */
209 upstrategy(bp)
210 register struct buf *bp;
211 {
212 	register struct buf *dp;
213 	register unit, xunit;
214 	long sz, bn;
215 
216 	if (upwstart == 0) {
217 		timeout(upwatch, (caddr_t)0, HZ);
218 		upwstart++;
219 	}
220 	xunit = minor(bp->b_dev) & 077;
221 	sz = bp->b_bcount;
222 	sz = (sz+511) >> 9;		/* transfer size in 512 byte sectors */
223 	unit = dkunit(bp);
224 	if (unit >= NUP ||
225 	    bp->b_blkno < 0 ||
226 	    (bn = dkblock(bp))+sz > up_sizes[xunit&07].nblocks) {
227 		bp->b_flags |= B_ERROR;
228 		iodone(bp);
229 		return;
230 	}
231 	if (UPDK_N+unit <= UPDK_NMAX)
232 		dk_mspw[UPDK_N+unit] = .0000020345;
233 	bp->b_cylin = bn/(NSECT*NTRAC) + up_sizes[xunit&07].cyloff;
234 	dp = &uputab[unit];
235 	(void) spl5();
236 	disksort(dp, bp);
237 	if (dp->b_active == 0) {
238 		(void) upustart(unit);
239 		if (uptab.b_actf && uptab.b_active == 0)
240 			(void) upstart();
241 	}
242 	(void) spl0();
243 }
244 
245 /*
246  * Start activity on specified drive; called when drive is inactive
247  * and new transfer request arrives and also when upas indicates that
248  * a SEARCH command is complete.
249  */
250 upustart(unit)
251 register unit;
252 {
253 	register struct buf *bp, *dp;
254 	register struct device *upaddr = UPADDR;
255 	daddr_t bn;
256 	int sn, cn, csn;
257 	int didie = 0;
258 
259 	/*
260 	 * Other drivers tend to say something like
261 	 *	upaddr->upcs1 = IE;
262 	 *	upaddr->upas = 1<<unit;
263 	 * here, but some controllers will cancel a command
264 	 * happens to be sitting in the cs1 if you clear the go
265 	 * bit by storing there (so the first is not safe).
266 	 *
267 	 * Thus we keep careful track of when we re-enable IE
268 	 * after an interrupt and do it only if we didn't issue
269 	 * a command which re-enabled it as a matter of course.
270 	 * We clear bits in upas in the interrupt routine, when
271 	 * no transfers are active.
272 	 */
273 	if (unit >= NUP)
274 		goto out;
275 	if (unit+UPDK_N <= UPDK_NMAX)
276 		dk_busy &= ~(1<<(unit+UPDK_N));
277 	dp = &uputab[unit];
278 	if ((bp = dp->b_actf) == NULL)
279 		goto out;
280 	/*
281 	 * Most controllers don't start SEARCH commands when transfers are
282 	 * in progress.  In fact, some tend to get confused when given
283 	 * SEARCH'es during transfers, generating interrupts with neither
284 	 * RDY nor a bit in the upas register.  Thus we defer
285 	 * until an interrupt when a transfer is pending.
286 	 */
287 	if (uptab.b_active) {
288 		upsoftas |= 1<<unit;
289 		return (0);
290 	}
291 	if (dp->b_active)
292 		goto done;
293 	dp->b_active = 1;
294 	if ((upaddr->upcs2 & 07) != unit)
295 		upaddr->upcs2 = unit;
296 	/*
297 	 * If we have changed packs or just initialized,
298 	 * then the volume will not be valid; if so, clear
299 	 * the drive, preset it and put in 16bit/word mode.
300 	 */
301 	if ((upaddr->upds & VV) == 0) {
302 		upaddr->upcs1 = IE|DCLR|GO;
303 		upaddr->upcs1 = IE|PRESET|GO;
304 		upaddr->upof = FMT22;
305 		didie = 1;
306 	}
307 	if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL))
308 		goto done;
309 
310 #if NUP > 1
311 	/*
312 	 * Do enough of the disk address decoding to determine
313 	 * which cylinder and sector the request is on.
314 	 * If we are on the correct cylinder and the desired sector
315 	 * lies between upSDIST and upSDIST+upRDIST sectors ahead of us, then
316 	 * we don't bother to SEARCH but just begin the transfer asap.
317 	 * Otherwise ask for a interrupt upSDIST sectors ahead.
318 	 */
319 	bn = dkblock(bp);
320 	cn = bp->b_cylin;
321 	sn = bn%(NSECT*NTRAC);
322 	sn = (sn+NSECT-upSDIST)%NSECT;
323 
324 	if (cn - upaddr->updc)
325 		goto search;		/* Not on-cylinder */
326 	else if (upseek)
327 		goto done;		/* Ok just to be on-cylinder */
328 	csn = (upaddr->upla>>6) - sn - 1;
329 	if (csn < 0)
330 		csn += NSECT;
331 	if (csn > NSECT-upRDIST)
332 		goto done;
333 
334 search:
335 	upaddr->updc = cn;
336 	if (upseek)
337 		upaddr->upcs1 = IE|SEEK|GO;
338 	else {
339 		upaddr->upda = sn;
340 		upaddr->upcs1 = IE|SEARCH|GO;
341 	}
342 	didie = 1;
343 	/*
344 	 * Mark this unit busy.
345 	 */
346 	unit += UPDK_N;
347 	if (unit <= UPDK_NMAX) {
348 		dk_busy |= 1<<unit;
349 		dk_seek[unit]++;
350 	}
351 	goto out;
352 #endif
353 
354 done:
355 	/*
356 	 * This unit is ready to go so
357 	 * link it onto the chain of ready disks.
358 	 */
359 	dp->b_forw = NULL;
360 	if (uptab.b_actf == NULL)
361 		uptab.b_actf = dp;
362 	else
363 		uptab.b_actl->b_forw = dp;
364 	uptab.b_actl = dp;
365 
366 out:
367 	return (didie);
368 }
369 
370 /*
371  * Start a transfer; call from top level at spl5() or on interrupt.
372  */
373 upstart()
374 {
375 	register struct buf *bp, *dp;
376 	register unit;
377 	register struct device *upaddr;
378 	daddr_t bn;
379 	int dn, sn, tn, cn, cmd;
380 
381 loop:
382 	/*
383 	 * Pick a drive off the queue of ready drives, and
384 	 * perform the first transfer on its queue.
385 	 *
386 	 * Looping here is completely for the sake of drives which
387 	 * are not present and on-line, for which we completely clear the
388 	 * request queue.
389 	 */
390 	if ((dp = uptab.b_actf) == NULL)
391 		return (0);
392 	if ((bp = dp->b_actf) == NULL) {
393 		uptab.b_actf = dp->b_forw;
394 		goto loop;
395 	}
396 	/*
397 	 * Mark the controller busy, and multi-part disk address.
398 	 * Select the unit on which the i/o is to take place.
399 	 */
400 	uptab.b_active++;
401 	unit = minor(bp->b_dev) & 077;
402 	dn = dkunit(bp);
403 	bn = dkblock(bp);
404 	cn = up_sizes[unit&07].cyloff;
405 	cn += bn/(NSECT*NTRAC);
406 	sn = bn%(NSECT*NTRAC);
407 	tn = sn/NSECT;
408 	sn %= NSECT;
409 	upaddr = UPADDR;
410 	if ((upaddr->upcs2 & 07) != dn)
411 		upaddr->upcs2 = dn;
412 	up_ubinfo = ubasetup(bp, 1);
413 	/*
414 	 * If drive is not present and on-line, then
415 	 * get rid of this with an error and loop to get
416 	 * rid of the rest of its queued requests.
417 	 * (Then on to any other ready drives.)
418 	 */
419 	if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) {
420 		printf("!DPR || !MOL, unit %d, ds %o", dn, upaddr->upds);
421 		if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) {
422 			printf("-- hard\n");
423 			uptab.b_active = 0;
424 			uptab.b_errcnt = 0;
425 			dp->b_actf = bp->av_forw;
426 			dp->b_active = 0;
427 			bp->b_flags |= B_ERROR;
428 			iodone(bp);
429 			/* A funny place to do this ... */
430 			ubarelse(&up_ubinfo);
431 			goto loop;
432 		}
433 		printf("-- came back\n");
434 	}
435 	/*
436 	 * If this is a retry, then with the 16'th retry we
437 	 * begin to try offsetting the heads to recover the data.
438 	 */
439 	if (uptab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) {
440 		upaddr->upof = up_offset[uptab.b_errcnt & 017] | FMT22;
441 		upaddr->upcs1 = IE|OFFSET|GO;
442 		while (upaddr->upds & PIP)
443 			DELAY(25);
444 	}
445 	/*
446 	 * Now set up the transfer, retrieving the high
447 	 * 2 bits of the UNIBUS address from the information
448 	 * returned by ubasetup() for the cs1 register bits 8 and 9.
449 	 */
450 	upaddr->updc = cn;
451 	upaddr->upda = (tn << 8) + sn;
452 	upaddr->upba = up_ubinfo;
453 	upaddr->upwc = -bp->b_bcount / sizeof (short);
454 	cmd = (up_ubinfo >> 8) & 0x300;
455 	if (bp->b_flags & B_READ)
456 		cmd |= IE|RCOM|GO;
457 	else
458 		cmd |= IE|WCOM|GO;
459 	upaddr->upcs1 = cmd;
460 	/*
461 	 * This is a controller busy situation.
462 	 * Record in dk slot NUP+UPDK_N (after last drive)
463 	 * unless there aren't that many slots reserved for
464 	 * us in which case we record this as a drive busy
465 	 * (if there is room for that).
466 	 */
467 	unit = dn+UPDK_N;
468 	if (unit <= UPDK_NMAX) {
469 		dk_busy |= 1<<unit;
470 		dk_xfer[unit]++;
471 		dk_wds[unit] += bp->b_bcount>>6;
472 	}
473 	return (1);
474 }
475 
476 /*
477  * Handle a device interrupt.
478  *
479  * If the transferring drive needs attention, service it
480  * retrying on error or beginning next transfer.
481  * Service all other ready drives, calling ustart to transfer
482  * their blocks to the ready queue in uptab, and then restart
483  * the controller if there is anything to do.
484  */
485 upintr()
486 {
487 	register struct buf *bp, *dp;
488 	register unit;
489 	register struct device *upaddr = UPADDR;
490 	int as = upaddr->upas & 0377;
491 	int oupsoftas;
492 	int needie = 1;
493 
494 	(void) spl6();
495 	up_wticks = 0;
496 	if (uptab.b_active) {
497 		/*
498 		 * The drive is transferring, thus the hardware
499 		 * (say the designers) will only interrupt when the transfer
500 		 * completes; check for it anyways.
501 		 */
502 		if ((upaddr->upcs1 & RDY) == 0) {
503 			printf("!RDY: cs1 %o, ds %o, wc %d\n", upaddr->upcs1,
504 			    upaddr->upds, upaddr->upwc);
505 			printf("as=%d act %d %d %d\n", as, uptab.b_active,
506 			    uputab[0].b_active, uputab[1].b_active);
507 		}
508 		/*
509 		 * Mark drive not busy, and check for an
510 		 * error condition which may have resulted from the transfer.
511 		 */
512 		dp = uptab.b_actf;
513 		bp = dp->b_actf;
514 		unit = dkunit(bp);
515 		if (UPDK_N+unit <= UPDK_NMAX)
516 			dk_busy &= ~(1<<(UPDK_N+unit));
517 		if ((upaddr->upcs2 & 07) != unit)
518 			upaddr->upcs2 = unit;
519 		if ((upaddr->upds&ERR) || (upaddr->upcs1&TRE)) {
520 			int cs2;
521 			/*
522 			 * An error occurred, indeed.  Select this unit
523 			 * to get at the drive status (a SEARCH may have
524 			 * intervened to change the selected unit), and
525 			 * wait for the command which caused the interrupt
526 			 * to complete (DRY).
527 			 */
528 			while ((upaddr->upds & DRY) == 0)
529 				DELAY(25);
530 			/*
531 			 * After 28 retries (16 w/o servo offsets, and then
532 			 * 12 with servo offsets), or if we encountered
533 			 * an error because the drive is write-protected,
534 			 * give up.  Print an error message on the last 2
535 			 * retries before a hard failure.
536 			 */
537 			if (++uptab.b_errcnt > 28 || upaddr->uper1&WLE)
538 				bp->b_flags |= B_ERROR;
539 			else
540 				uptab.b_active = 0;	/* To force retry */
541 			if (uptab.b_errcnt > 27)
542 				cs2 = (int)upaddr->upcs2;
543 				deverror(bp, (int)upaddr->upcs2,
544 				    (int)upaddr->uper1);
545 			/*
546 			 * If this was a correctible ECC error, let upecc
547 			 * do the dirty work to correct it.  If upecc
548 			 * starts another READ for the rest of the data
549 			 * then it returns 1 (having set uptab.b_active).
550 			 * Otherwise we are done and fall through to
551 			 * finish up.
552 			 */
553 			if ((upaddr->uper1&(DCK|ECH))==DCK && upecc(upaddr, bp))
554 				return;
555 			/*
556 			 * Clear the drive and, every 4 retries, recalibrate
557 			 * to hopefully help clear up seek positioning problems.
558 			 */
559 			upaddr->upcs1 = TRE|IE|DCLR|GO;
560 			needie = 0;
561 			if ((uptab.b_errcnt&07) == 4) {
562 				upaddr->upcs1 = RECAL|GO|IE;
563 				while(upaddr->upds & PIP)
564 					DELAY(25);
565 			}
566 			if (uptab.b_errcnt == 28 && cs2&(NEM|MXF)) {
567 				printf("FLAKEY UP ");
568 				ubareset();
569 				return;
570 			}
571 		}
572 		/*
573 		 * If we are still noted as active, then no
574 		 * (further) retries are necessary.
575 		 *
576 		 * Make sure the correct unit is selected,
577 		 * return it to centerline if necessary, and mark
578 		 * this i/o complete, starting the next transfer
579 		 * on this drive with the upustart routine (if any).
580 		 */
581 		if (uptab.b_active) {
582 			if (uptab.b_errcnt >= 16) {
583 				upaddr->upcs1 = RTC|GO|IE;
584 				while (upaddr->upds & PIP)
585 					DELAY(25);
586 				needie = 0;
587 			}
588 			uptab.b_active = 0;
589 			uptab.b_errcnt = 0;
590 			uptab.b_actf = dp->b_forw;
591 			dp->b_active = 0;
592 			dp->b_errcnt = 0;
593 			dp->b_actf = bp->av_forw;
594 			bp->b_resid = (-upaddr->upwc * sizeof(short));
595 			if (bp->b_resid)
596 				printf("resid %d ds %o er? %o %o %o\n",
597 				    bp->b_resid, upaddr->upds,
598 				    upaddr->uper1, upaddr->uper2, upaddr->uper3);
599 			iodone(bp);
600 			if(dp->b_actf)
601 				if (upustart(unit))
602 					needie = 0;
603 		}
604 		as &= ~(1<<unit);
605 		upsoftas &= ~(1<<unit);
606 		ubarelse(&up_ubinfo);
607 	} else {
608 		if (upaddr->upcs1 & TRE)
609 			upaddr->upcs1 = TRE;
610 	}
611 	/*
612 	 * If we have a unit with an outstanding SEARCH,
613 	 * and the hardware indicates the unit requires attention,
614 	 * the bring the drive to the ready queue.
615 	 * Finally, if the controller is not transferring
616 	 * start it if any drives are now ready to transfer.
617 	 */
618 	as |= upsoftas;
619 	oupsoftas = upsoftas;
620 	upsoftas = 0;
621 	for (unit = 0; unit < NUP; unit++)
622 		if ((as|oupsoftas) & (1<<unit)) {
623 			if (as & (1<<unit))
624 				upaddr->upas = 1<<unit;
625 			if (upustart(unit))
626 				needie = 0;
627 		}
628 	if (uptab.b_actf && uptab.b_active == 0)
629 		if (upstart())
630 			needie = 0;
631 	if (needie)
632 		upaddr->upcs1 = IE;
633 }
634 
635 upread(dev)
636 {
637 
638 	physio(upstrategy, &rupbuf, dev, B_READ, minphys);
639 }
640 
641 upwrite(dev)
642 {
643 
644 	physio(upstrategy, &rupbuf, dev, B_WRITE, minphys);
645 }
646 
647 /*
648  * Correct an ECC error, and restart the i/o to complete
649  * the transfer if necessary.  This is quite complicated because
650  * the transfer may be going to an odd memory address base and/or
651  * across a page boundary.
652  */
653 upecc(up, bp)
654 register struct device *up;
655 register struct buf *bp;
656 {
657 	struct uba_regs *ubp = (struct uba_regs *)UBA0;
658 	register int i;
659 	caddr_t addr;
660 	int reg, bit, byte, npf, mask, o, cmd, ubaddr;
661 	int bn, cn, tn, sn;
662 
663 	/*
664 	 * Npf is the number of sectors transferred before the sector
665 	 * containing the ECC error, and reg is the UBA register
666 	 * mapping (the first part of) the transfer.
667 	 * O is offset within a memory page of the first byte transferred.
668 	 */
669 	npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1;
670 	reg = btop(up_ubinfo&0x3ffff) + npf;
671 	o = (int)bp->b_un.b_addr & PGOFSET;
672 	printf("%D ", bp->b_blkno+npf);
673 	prdev("ECC", bp->b_dev);
674 	mask = up->upec2;
675 	if (mask == 0) {
676 		up->upof = FMT22;		/* == RTC ???? */
677 		return (0);
678 	}
679 	/*
680 	 * Flush the buffered data path, and compute the
681 	 * byte and bit position of the error.  The variable i
682 	 * is the byte offset in the transfer, the variable byte
683 	 * is the offset from a page boundary in main memory.
684 	 */
685 	ubp->uba_dpr[(up_ubinfo>>28)&0x0f] |= BNE;
686 	i = up->upec1 - 1;		/* -1 makes 0 origin */
687 	bit = i&07;
688 	i = (i&~07)>>3;
689 	byte = i + o;
690 	/*
691 	 * Correct while possible bits remain of mask.  Since mask
692 	 * contains 11 bits, we continue while the bit offset is > -11.
693 	 * Also watch out for end of this block and the end of the whole
694 	 * transfer.
695 	 */
696 	while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) {
697 		addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+
698 		    (byte & PGOFSET);
699 		putmemc(addr, getmemc(addr)^(mask<<bit));
700 		byte++;
701 		i++;
702 		bit -= 8;
703 	}
704 	uptab.b_active++;	/* Either complete or continuing... */
705 	if (up->upwc == 0)
706 		return (0);
707 	/*
708 	 * Have to continue the transfer... clear the drive,
709 	 * and compute the position where the transfer is to continue.
710 	 * We have completed npf+1 sectors of the transfer already;
711 	 * restart at offset o of next sector (i.e. in UBA register reg+1).
712 	 */
713 	up->upcs1 = TRE|IE|DCLR|GO;
714 	bn = dkblock(bp);
715 	cn = bp->b_cylin;
716 	sn = bn%(NSECT*NTRAC) + npf + 1;
717 	tn = sn/NSECT;
718 	sn %= NSECT;
719 	cn += tn/NTRAC;
720 	tn %= NTRAC;
721 	up->updc = cn;
722 	up->upda = (tn << 8) | sn;
723 	ubaddr = (int)ptob(reg+1) + o;
724 	up->upba = ubaddr;
725 	cmd = (ubaddr >> 8) & 0x300;
726 	cmd |= IE|GO|RCOM;
727 	up->upcs1 = cmd;
728 	return (1);
729 }
730 
731 /*
732  * Reset driver after UBA init.
733  * Cancel software state of all pending transfers
734  * and restart all units and the controller.
735  */
736 upreset()
737 {
738 	int unit;
739 
740 	printf(" up");
741 	DELAY(15000000);		/* give it time to self-test */
742 	uptab.b_active = 0;
743 	uptab.b_actf = uptab.b_actl = 0;
744 	if (up_ubinfo) {
745 		printf("<%d>", (up_ubinfo>>28)&0xf);
746 		ubarelse(&up_ubinfo);
747 	}
748 	UPADDR->upcs2 = CLR;		/* clear controller */
749 	for (unit = 0; unit < NUP; unit++) {
750 		uputab[unit].b_active = 0;
751 		(void) upustart(unit);
752 	}
753 	(void) upstart();
754 }
755 
756 /*
757  * Wake up every second and if an interrupt is pending
758  * but nothing has happened increment a counter.
759  * If nothing happens for 20 seconds, reset the controller
760  * and begin anew.
761  */
762 upwatch()
763 {
764 	int i;
765 
766 	timeout(upwatch, (caddr_t)0, HZ);
767 	if (uptab.b_active == 0) {
768 		for (i = 0; i < NUP; i++)
769 			if (uputab[i].b_active)
770 				goto active;
771 		up_wticks = 0;		/* idling */
772 		return;
773 	}
774 active:
775 	up_wticks++;
776 	if (up_wticks >= 20) {
777 		up_wticks = 0;
778 		printf("LOST INTERRUPT RESET");
779 		upreset();
780 		printf("\n");
781 	}
782 }
783 #endif
784 #endif
785