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