misc pre-mba changes (non-recursive printf, futz, resuba, %uXX...)
[unix-history] / usr / src / sys / vax / uba / up.c
CommitLineData
7c0e42e4 1/* up.c 4.11 %G% */
008c0481 2
66b4fb09 3#include "up.h"
a801d8f2 4#if NUP > 0
a0c1902e
BJ
5#if SC11 > 0
6#include "../dev/up.c.SC11"
63c35a63 7#else
008c0481 8/*
10fb932f 9 * UNIBUS disk driver with overlapped seeks and ECC recovery.
008c0481 10 */
355250d9 11#define DELAY(N) { register int d; d = N; while (--d > 0); }
008c0481
BJ
12
13#include "../h/param.h"
14#include "../h/systm.h"
41888f16 15#include "../h/dk.h"
008c0481
BJ
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"
80e7c811 21#include "../h/pte.h"
008c0481
BJ
22#include "../h/mba.h"
23#include "../h/mtpr.h"
008c0481
BJ
24#include "../h/uba.h"
25#include "../h/vm.h"
26
008c0481
BJ
27#define ushort unsigned short
28
29struct 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
2a3b9a7f
BJ
53/*
54 * Software extension to the upas register, so we can
55 * postpone starting SEARCH commands until the controller
56 * is not transferring.
57 */
d1778415 58int upsoftas;
2a3b9a7f
BJ
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 */
64int upseek;
65
008c0481
BJ
66#define NSECT 32
67#define NTRAC 19
68
69/*
70 * Constants controlling on-cylinder SEARCH usage.
71 *
41888f16
BJ
72 * upSDIST/2 msec time needed to start transfer
73 * upRDIST/2 msec tolerable rotational latency when on-cylinder
2a3b9a7f 74 *
41888f16 75 * If we are no closer than upSDIST sectors and no further than upSDIST+upRDIST
2a3b9a7f 76 * and in the driver then we take it as it is. Otherwise we do a SEARCH
41888f16 77 * requesting an interrupt upSDIST sectors in advance.
008c0481 78 */
3cab1981
BJ
79#define _upSDIST 2 /* 1.0 msec */
80#define _upRDIST 4 /* 2.0 msec */
2a3b9a7f 81
41888f16
BJ
82int upSDIST = _upSDIST;
83int upRDIST = _upRDIST;
008c0481
BJ
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.
355250d9
BJ
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.
008c0481
BJ
96 */
97struct 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 */
d1778415 104 495520, 0, /* C=cyl 0 thru 814 */
008c0481
BJ
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 */
008c0481
BJ
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 *
355250d9 118 * NB: Not all drives/controllers emulate all of these.
008c0481
BJ
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
128int 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 */
146struct buf uptab;
147struct buf uputab[NUP];
148
149struct 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 */
2a3b9a7f 157#define SEEK 04 /* Seek to cylinder */
008c0481
BJ
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 */
ec1b1145 166#define RDY 0200 /* Transfer terminated */
008c0481
BJ
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
6a81870e
BJ
176/* Bits of upcs2 */
177#define CLR 040 /* Controller clear */
0ad5097e
BJ
178#define MXF 01000
179#define NEM 04000
180
008c0481
BJ
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
191int up_ubinfo; /* Information about UBA usage saved here */
008c0481 192
6a81870e
BJ
193int up_wticks; /* Ticks waiting for interrupt */
194int upwstart; /* Have started guardian */
195int upwatch();
196
008c0481
BJ
197#ifdef INTRLVE
198daddr_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 */
209upstrategy(bp)
210register struct buf *bp;
211{
212 register struct buf *dp;
213 register unit, xunit;
214 long sz, bn;
215
6a81870e 216 if (upwstart == 0) {
49c84d3f 217 timeout(upwatch, (caddr_t)0, HZ);
6a81870e
BJ
218 upwstart++;
219 }
008c0481
BJ
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 }
c134650e
BJ
231 if (UPDK_N+unit <= UPDK_NMAX)
232 dk_mspw[UPDK_N+unit] = .0000020345;
008c0481
BJ
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) {
eb891eaa 238 (void) upustart(unit);
008c0481 239 if (uptab.b_actf && uptab.b_active == 0)
eb891eaa 240 (void) upstart();
008c0481
BJ
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 */
250upustart(unit)
251register unit;
252{
253 register struct buf *bp, *dp;
254 register struct device *upaddr = UPADDR;
255 daddr_t bn;
256 int sn, cn, csn;
eb891eaa 257 int didie = 0;
008c0481 258
7bc8d985 259 /*
2a3b9a7f
BJ
260 * Other drivers tend to say something like
261 * upaddr->upcs1 = IE;
262 * upaddr->upas = 1<<unit;
355250d9 263 * here, but some controllers will cancel a command
2a3b9a7f 264 * happens to be sitting in the cs1 if you clear the go
355250d9 265 * bit by storing there (so the first is not safe).
2a3b9a7f
BJ
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.
7bc8d985 272 */
2a3b9a7f
BJ
273 if (unit >= NUP)
274 goto out;
c134650e
BJ
275 if (unit+UPDK_N <= UPDK_NMAX)
276 dk_busy &= ~(1<<(unit+UPDK_N));
008c0481 277 dp = &uputab[unit];
7bc8d985 278 if ((bp = dp->b_actf) == NULL)
eb891eaa 279 goto out;
2a3b9a7f 280 /*
355250d9
BJ
281 * Most controllers don't start SEARCH commands when transfers are
282 * in progress. In fact, some tend to get confused when given
2a3b9a7f
BJ
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) {
d1778415 288 upsoftas |= 1<<unit;
2a3b9a7f
BJ
289 return (0);
290 }
a3f430e0
BJ
291 if (dp->b_active)
292 goto done;
293 dp->b_active = 1;
355250d9 294 if ((upaddr->upcs2 & 07) != unit)
008c0481 295 upaddr->upcs2 = unit;
7bc8d985
BJ
296 /*
297 * If we have changed packs or just initialized,
2a3b9a7f 298 * then the volume will not be valid; if so, clear
7bc8d985
BJ
299 * the drive, preset it and put in 16bit/word mode.
300 */
301 if ((upaddr->upds & VV) == 0) {
302 upaddr->upcs1 = IE|DCLR|GO;
008c0481 303 upaddr->upcs1 = IE|PRESET|GO;
008c0481 304 upaddr->upof = FMT22;
eb891eaa 305 didie = 1;
008c0481 306 }
008c0481 307 if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL))
2a3b9a7f 308 goto done;
7c0e42e4
RE
309
310#if NUP > 1
7bc8d985
BJ
311 /*
312 * Do enough of the disk address decoding to determine
313 * which cylinder and sector the request is on.
7bc8d985 314 * If we are on the correct cylinder and the desired sector
41888f16 315 * lies between upSDIST and upSDIST+upRDIST sectors ahead of us, then
7bc8d985 316 * we don't bother to SEARCH but just begin the transfer asap.
41888f16 317 * Otherwise ask for a interrupt upSDIST sectors ahead.
7bc8d985 318 */
008c0481
BJ
319 bn = dkblock(bp);
320 cn = bp->b_cylin;
321 sn = bn%(NSECT*NTRAC);
41888f16 322 sn = (sn+NSECT-upSDIST)%NSECT;
008c0481 323
7bc8d985
BJ
324 if (cn - upaddr->updc)
325 goto search; /* Not on-cylinder */
2a3b9a7f
BJ
326 else if (upseek)
327 goto done; /* Ok just to be on-cylinder */
008c0481 328 csn = (upaddr->upla>>6) - sn - 1;
7bc8d985 329 if (csn < 0)
008c0481 330 csn += NSECT;
41888f16 331 if (csn > NSECT-upRDIST)
008c0481
BJ
332 goto done;
333
334search:
335 upaddr->updc = cn;
2a3b9a7f
BJ
336 if (upseek)
337 upaddr->upcs1 = IE|SEEK|GO;
338 else {
339 upaddr->upda = sn;
340 upaddr->upcs1 = IE|SEARCH|GO;
341 }
eb891eaa 342 didie = 1;
7bc8d985
BJ
343 /*
344 * Mark this unit busy.
345 */
c134650e
BJ
346 unit += UPDK_N;
347 if (unit <= UPDK_NMAX) {
008c0481 348 dk_busy |= 1<<unit;
f9b6e695 349 dk_seek[unit]++;
008c0481 350 }
eb891eaa 351 goto out;
7c0e42e4 352#endif
008c0481
BJ
353
354done:
7bc8d985 355 /*
2a3b9a7f
BJ
356 * This unit is ready to go so
357 * link it onto the chain of ready disks.
7bc8d985 358 */
008c0481 359 dp->b_forw = NULL;
7bc8d985 360 if (uptab.b_actf == NULL)
008c0481
BJ
361 uptab.b_actf = dp;
362 else
363 uptab.b_actl->b_forw = dp;
364 uptab.b_actl = dp;
eb891eaa
BJ
365
366out:
367 return (didie);
008c0481
BJ
368}
369
370/*
371 * Start a transfer; call from top level at spl5() or on interrupt.
008c0481
BJ
372 */
373upstart()
374{
375 register struct buf *bp, *dp;
376 register unit;
377 register struct device *upaddr;
378 daddr_t bn;
7bc8d985 379 int dn, sn, tn, cn, cmd;
008c0481 380
008c0481 381loop:
7bc8d985
BJ
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 */
1f3d30ee 390 if ((dp = uptab.b_actf) == NULL)
eb891eaa 391 return (0);
008c0481
BJ
392 if ((bp = dp->b_actf) == NULL) {
393 uptab.b_actf = dp->b_forw;
394 goto loop;
395 }
7bc8d985
BJ
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 */
008c0481
BJ
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;
7bc8d985 408 sn %= NSECT;
008c0481 409 upaddr = UPADDR;
355250d9 410 if ((upaddr->upcs2 & 07) != dn)
008c0481 411 upaddr->upcs2 = dn;
355250d9 412 up_ubinfo = ubasetup(bp, 1);
7bc8d985
BJ
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 */
008c0481 419 if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) {
88253fd2
BJ
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 ... */
b28deaf8 430 ubarelse(&up_ubinfo);
88253fd2
BJ
431 goto loop;
432 }
433 printf("-- came back\n");
008c0481 434 }
7bc8d985
BJ
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 */
7c0e42e4 439 if (uptab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) {
008c0481 440 upaddr->upof = up_offset[uptab.b_errcnt & 017] | FMT22;
7bc8d985 441 upaddr->upcs1 = IE|OFFSET|GO;
7bc8d985 442 while (upaddr->upds & PIP)
008c0481
BJ
443 DELAY(25);
444 }
7bc8d985
BJ
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 */
008c0481
BJ
450 upaddr->updc = cn;
451 upaddr->upda = (tn << 8) + sn;
452 upaddr->upba = up_ubinfo;
453 upaddr->upwc = -bp->b_bcount / sizeof (short);
7bc8d985 454 cmd = (up_ubinfo >> 8) & 0x300;
008c0481 455 if (bp->b_flags & B_READ)
7bc8d985 456 cmd |= IE|RCOM|GO;
008c0481 457 else
7bc8d985 458 cmd |= IE|WCOM|GO;
7bc8d985 459 upaddr->upcs1 = cmd;
7bc8d985
BJ
460 /*
461 * This is a controller busy situation.
c134650e 462 * Record in dk slot NUP+UPDK_N (after last drive)
7bc8d985
BJ
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 */
c134650e
BJ
467 unit = dn+UPDK_N;
468 if (unit <= UPDK_NMAX) {
008c0481 469 dk_busy |= 1<<unit;
f9b6e695 470 dk_xfer[unit]++;
008c0481
BJ
471 dk_wds[unit] += bp->b_bcount>>6;
472 }
eb891eaa 473 return (1);
008c0481
BJ
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 */
485upintr()
486{
487 register struct buf *bp, *dp;
488 register unit;
489 register struct device *upaddr = UPADDR;
490 int as = upaddr->upas & 0377;
d1778415 491 int oupsoftas;
eb891eaa 492 int needie = 1;
008c0481 493
a3f430e0 494 (void) spl6();
6a81870e 495 up_wticks = 0;
7bc8d985
BJ
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) {
39bd608f
BJ
503 printf("!RDY: cs1 %o, ds %o, wc %d\n", upaddr->upcs1,
504 upaddr->upds, upaddr->upwc);
d1778415
BJ
505 printf("as=%d act %d %d %d\n", as, uptab.b_active,
506 uputab[0].b_active, uputab[1].b_active);
6e179703 507 }
7bc8d985 508 /*
f9b6e695 509 * Mark drive not busy, and check for an
7bc8d985
BJ
510 * error condition which may have resulted from the transfer.
511 */
008c0481
BJ
512 dp = uptab.b_actf;
513 bp = dp->b_actf;
514 unit = dkunit(bp);
c134650e
BJ
515 if (UPDK_N+unit <= UPDK_NMAX)
516 dk_busy &= ~(1<<(UPDK_N+unit));
355250d9 517 if ((upaddr->upcs2 & 07) != unit)
2a3b9a7f 518 upaddr->upcs2 = unit;
10fb932f 519 if ((upaddr->upds&ERR) || (upaddr->upcs1&TRE)) {
0ad5097e 520 int cs2;
7bc8d985
BJ
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).
7bc8d985 527 */
7bc8d985 528 while ((upaddr->upds & DRY) == 0)
008c0481 529 DELAY(25);
7bc8d985
BJ
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)
008c0481
BJ
538 bp->b_flags |= B_ERROR;
539 else
7bc8d985
BJ
540 uptab.b_active = 0; /* To force retry */
541 if (uptab.b_errcnt > 27)
0ad5097e 542 cs2 = (int)upaddr->upcs2;
49c84d3f
BJ
543 deverror(bp, (int)upaddr->upcs2,
544 (int)upaddr->uper1);
7bc8d985
BJ
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 */
008c0481 559 upaddr->upcs1 = TRE|IE|DCLR|GO;
eb891eaa 560 needie = 0;
7bc8d985 561 if ((uptab.b_errcnt&07) == 4) {
008c0481 562 upaddr->upcs1 = RECAL|GO|IE;
008c0481
BJ
563 while(upaddr->upds & PIP)
564 DELAY(25);
565 }
0ad5097e
BJ
566 if (uptab.b_errcnt == 28 && cs2&(NEM|MXF)) {
567 printf("FLAKEY UP ");
568 ubareset();
569 return;
570 }
008c0481 571 }
7bc8d985
BJ
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) {
7bc8d985
BJ
582 if (uptab.b_errcnt >= 16) {
583 upaddr->upcs1 = RTC|GO|IE;
7bc8d985 584 while (upaddr->upds & PIP)
008c0481 585 DELAY(25);
eb891eaa 586 needie = 0;
008c0481
BJ
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;
7bc8d985 594 bp->b_resid = (-upaddr->upwc * sizeof(short));
2a3b9a7f 595 if (bp->b_resid)
d1778415
BJ
596 printf("resid %d ds %o er? %o %o %o\n",
597 bp->b_resid, upaddr->upds,
2a3b9a7f 598 upaddr->uper1, upaddr->uper2, upaddr->uper3);
008c0481
BJ
599 iodone(bp);
600 if(dp->b_actf)
eb891eaa
BJ
601 if (upustart(unit))
602 needie = 0;
008c0481
BJ
603 }
604 as &= ~(1<<unit);
d1778415 605 upsoftas &= ~(1<<unit);
b28deaf8 606 ubarelse(&up_ubinfo);
1f3d30ee 607 } else {
355250d9 608 if (upaddr->upcs1 & TRE)
008c0481 609 upaddr->upcs1 = TRE;
008c0481 610 }
7bc8d985
BJ
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 */
d1778415
BJ
618 as |= upsoftas;
619 oupsoftas = upsoftas;
620 upsoftas = 0;
7bc8d985 621 for (unit = 0; unit < NUP; unit++)
d1778415 622 if ((as|oupsoftas) & (1<<unit)) {
355250d9 623 if (as & (1<<unit))
5c65daa3 624 upaddr->upas = 1<<unit;
1f3d30ee
BJ
625 if (upustart(unit))
626 needie = 0;
627 }
7bc8d985 628 if (uptab.b_actf && uptab.b_active == 0)
eb891eaa
BJ
629 if (upstart())
630 needie = 0;
2a3b9a7f 631 if (needie)
7bc8d985 632 upaddr->upcs1 = IE;
008c0481
BJ
633}
634
635upread(dev)
636{
637
638 physio(upstrategy, &rupbuf, dev, B_READ, minphys);
639}
640
641upwrite(dev)
642{
643
644 physio(upstrategy, &rupbuf, dev, B_WRITE, minphys);
645}
646
7bc8d985
BJ
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 */
008c0481
BJ
653upecc(up, bp)
654register struct device *up;
655register struct buf *bp;
656{
657 struct uba_regs *ubp = (struct uba_regs *)UBA0;
7bc8d985 658 register int i;
008c0481 659 caddr_t addr;
7bc8d985 660 int reg, bit, byte, npf, mask, o, cmd, ubaddr;
008c0481
BJ
661 int bn, cn, tn, sn;
662
008c0481 663 /*
7bc8d985
BJ
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.
008c0481 668 */
7bc8d985
BJ
669 npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1;
670 reg = btop(up_ubinfo&0x3ffff) + npf;
008c0481
BJ
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) {
7bc8d985 676 up->upof = FMT22; /* == RTC ???? */
008c0481
BJ
677 return (0);
678 }
7bc8d985
BJ
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;
008c0481 689 byte = i + o;
7bc8d985
BJ
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;
008c0481 703 }
7bc8d985 704 uptab.b_active++; /* Either complete or continuing... */
008c0481
BJ
705 if (up->upwc == 0)
706 return (0);
7bc8d985
BJ
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;
008c0481
BJ
714 bn = dkblock(bp);
715 cn = bp->b_cylin;
7bc8d985 716 sn = bn%(NSECT*NTRAC) + npf + 1;
008c0481
BJ
717 tn = sn/NSECT;
718 sn %= NSECT;
7bc8d985
BJ
719 cn += tn/NTRAC;
720 tn %= NTRAC;
008c0481 721 up->updc = cn;
7bc8d985
BJ
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;
008c0481
BJ
728 return (1);
729}
977c2848
BJ
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 */
736upreset()
737{
738 int unit;
739
740 printf(" up");
0ad5097e 741 DELAY(15000000); /* give it time to self-test */
977c2848
BJ
742 uptab.b_active = 0;
743 uptab.b_actf = uptab.b_actl = 0;
977c2848
BJ
744 if (up_ubinfo) {
745 printf("<%d>", (up_ubinfo>>28)&0xf);
b28deaf8 746 ubarelse(&up_ubinfo);
977c2848 747 }
6a81870e 748 UPADDR->upcs2 = CLR; /* clear controller */
977c2848
BJ
749 for (unit = 0; unit < NUP; unit++) {
750 uputab[unit].b_active = 0;
751 (void) upustart(unit);
752 }
753 (void) upstart();
754}
6a81870e
BJ
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 */
762upwatch()
763{
764 int i;
765
49c84d3f 766 timeout(upwatch, (caddr_t)0, HZ);
6a81870e
BJ
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 }
774active:
775 up_wticks++;
776 if (up_wticks >= 20) {
777 up_wticks = 0;
778 printf("LOST INTERRUPT RESET");
779 upreset();
780 printf("\n");
781 }
782}
a801d8f2 783#endif
63c35a63 784#endif