fixes from lucasfilm
[unix-history] / usr / src / sys / vax / uba / up.c
CommitLineData
cc7ff771 1/* up.c 4.44 82/03/29 */
008c0481 2
66b4fb09 3#include "up.h"
a3cb8f60 4#if NSC > 0
008c0481 5/*
10fb932f 6 * UNIBUS disk driver with overlapped seeks and ECC recovery.
0c48c799
BJ
7 *
8 * TODO:
0c48c799 9 * Add bad sector forwarding code
299d67ed 10 * Check that offset recovery code works
008c0481
BJ
11 */
12
13#include "../h/param.h"
14#include "../h/systm.h"
3f3a34c3
BJ
15#include "../h/cpu.h"
16#include "../h/nexus.h"
41888f16 17#include "../h/dk.h"
008c0481
BJ
18#include "../h/buf.h"
19#include "../h/conf.h"
20#include "../h/dir.h"
21#include "../h/user.h"
22#include "../h/map.h"
80e7c811 23#include "../h/pte.h"
008c0481 24#include "../h/mtpr.h"
008c0481 25#include "../h/vm.h"
89bd2f01
BJ
26#include "../h/ubavar.h"
27#include "../h/ubareg.h"
0ff318b2 28#include "../h/cmap.h"
008c0481 29
0ff318b2 30#include "../h/upreg.h"
008c0481 31
3f3a34c3
BJ
32struct up_softc {
33 int sc_softas;
71236e46 34 int sc_ndrive;
3f3a34c3 35 int sc_wticks;
736772ef 36 int sc_recal;
a3cb8f60 37} up_softc[NSC];
008c0481 38
3f3a34c3 39/* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
008c0481
BJ
40struct size
41{
42 daddr_t nblocks;
43 int cyloff;
44} up_sizes[8] = {
45 15884, 0, /* A=cyl 0 thru 26 */
46 33440, 27, /* B=cyl 27 thru 81 */
d1778415 47 495520, 0, /* C=cyl 0 thru 814 */
008c0481
BJ
48 15884, 562, /* D=cyl 562 thru 588 */
49 55936, 589, /* E=cyl 589 thru 680 */
0d728200
BJ
50#ifndef NOBADSECT
51 81376, 681, /* F=cyl 681 thru 814 */
52 153728, 562, /* G=cyl 562 thru 814 */
53#else
54 81472, 681,
55 153824, 562,
56#endif
008c0481 57 291346, 82, /* H=cyl 82 thru 561 */
3f3a34c3
BJ
58}, fj_sizes[8] = {
59 15884, 0, /* A=cyl 0 thru 49 */
60 33440, 50, /* B=cyl 50 thru 154 */
61 263360, 0, /* C=cyl 0 thru 822 */
62 0, 0,
63 0, 0,
64 0, 0,
65 0, 0,
0d728200
BJ
66#ifndef NOBADSECT
67 213664, 155, /* H=cyl 155 thru 822 */
68#else
69 213760, 155,
70#endif
0cc9b5a9
BJ
71}, am_sizes[8] = {
72 15884, 0, /* A=cyl 0 thru 31 */
73 33440, 32, /* B=cyl 32 thru 97 */
74 524288, 0, /* C=cyl 0 thru 1023 */
75 0, 0,
76 0, 0,
77 0, 0,
78 181760, 668, /* G=cyl 668 thru 1022 */
79 291346, 98, /* H=cyl 98 thru 667 */
008c0481 80};
3f3a34c3 81/* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
008c0481 82
cc7ff771
BJ
83/*
84 * On a 780 upSDIST could be 2, but
85 * in the interest of 750's...
86 */
87#define _upSDIST 3 /* 1.5 msec */
3f3a34c3
BJ
88#define _upRDIST 4 /* 2.0 msec */
89
90int upSDIST = _upSDIST;
91int upRDIST = _upRDIST;
92
71236e46 93int upprobe(), upslave(), upattach(), updgo(), upintr();
89bd2f01
BJ
94struct uba_ctlr *upminfo[NSC];
95struct uba_device *updinfo[NUP];
96struct uba_device *upip[NSC][4];
d763a2b7 97
71236e46 98u_short upstd[] = { 0776700, 0774400, 0776300, 0 };
0801d37f 99struct uba_driver scdriver =
71236e46 100 { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo };
3f3a34c3
BJ
101struct buf uputab[NUP];
102
103struct upst {
104 short nsect;
105 short ntrak;
106 short nspc;
107 short ncyl;
108 struct size *sizes;
109} upst[] = {
71236e46
BJ
110 32, 19, 32*19, 823, up_sizes, /* 9300/cdc */
111/* 9300 actually has 815 cylinders... */
3f3a34c3 112 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */
cc7ff771 113 32, 16, 32*16, 1024, am_sizes, /* ampex capricorn */
3f3a34c3 114};
008c0481 115
2601dfbd 116u_char up_offset[16] = {
299d67ed
BJ
117 UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400,
118 UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800,
119 UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200,
120 0, 0, 0, 0
2601dfbd 121};
008c0481 122
0801d37f 123struct buf rupbuf[NUP];
008c0481 124
008c0481
BJ
125#define b_cylin b_resid
126
008c0481
BJ
127#ifdef INTRLVE
128daddr_t dkblock();
129#endif
3f3a34c3
BJ
130
131int upwstart, upwatch(); /* Have started guardian */
7e00c42b 132int upseek;
f88f8fdb 133int upwaitdry;
3f3a34c3
BJ
134
135/*ARGSUSED*/
71236e46 136upprobe(reg)
3f3a34c3 137 caddr_t reg;
008c0481 138{
d763a2b7
BJ
139 register int br, cvec;
140
71236e46
BJ
141#ifdef lint
142 br = 0; cvec = br; br = cvec;
143#endif
2601dfbd 144 ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY;
71236e46 145 DELAY(10);
2601dfbd 146 ((struct updevice *)reg)->upcs1 = 0;
d763a2b7 147 return (1);
3f3a34c3
BJ
148}
149
71236e46 150upslave(ui, reg)
89bd2f01 151 struct uba_device *ui;
3f3a34c3
BJ
152 caddr_t reg;
153{
2601dfbd 154 register struct updevice *upaddr = (struct updevice *)reg;
3f3a34c3
BJ
155
156 upaddr->upcs1 = 0; /* conservative */
71236e46 157 upaddr->upcs2 = ui->ui_slave;
299d67ed 158 if (upaddr->upcs2&UPCS2_NED) {
2601dfbd 159 upaddr->upcs1 = UP_DCLR|UP_GO;
3f3a34c3
BJ
160 return (0);
161 }
71236e46
BJ
162 return (1);
163}
164
165upattach(ui)
89bd2f01 166 register struct uba_device *ui;
71236e46 167{
2601dfbd 168 register struct updevice *upaddr;
71236e46 169
6a81870e 170 if (upwstart == 0) {
7780575a 171 timeout(upwatch, (caddr_t)0, hz);
6a81870e
BJ
172 upwstart++;
173 }
b7333467
BJ
174 if (ui->ui_dk >= 0)
175 dk_mspw[ui->ui_dk] = .0000020345;
71236e46
BJ
176 upip[ui->ui_ctlr][ui->ui_slave] = ui;
177 up_softc[ui->ui_ctlr].sc_ndrive++;
2601dfbd
BJ
178 upaddr = (struct updevice *)ui->ui_addr;
179 upaddr->upcs1 = 0;
180 upaddr->upcs2 = ui->ui_slave;
26e15512 181 upaddr->uphr = UPHR_MAXTRAK;
c6a51a7b 182 if (upaddr->uphr == 9)
26e15512 183 ui->ui_type = 1; /* fujitsu hack */
0cc9b5a9
BJ
184 else if (upaddr->uphr == 15)
185 ui->ui_type = 2; /* ampex hack */
26e15512
BJ
186 upaddr->upcs2 = UPCS2_CLR;
187/*
188 upaddr->uphr = UPHR_MAXCYL;
189 printf("maxcyl %d\n", upaddr->uphr);
190 upaddr->uphr = UPHR_MAXTRAK;
191 printf("maxtrak %d\n", upaddr->uphr);
192 upaddr->uphr = UPHR_MAXSECT;
193 printf("maxsect %d\n", upaddr->uphr);
194*/
3f3a34c3
BJ
195}
196
3f3a34c3
BJ
197upstrategy(bp)
198 register struct buf *bp;
199{
89bd2f01 200 register struct uba_device *ui;
3f3a34c3
BJ
201 register struct upst *st;
202 register int unit;
7e00c42b 203 register struct buf *dp;
3f3a34c3 204 int xunit = minor(bp->b_dev) & 07;
7e00c42b 205 long bn, sz;
3f3a34c3 206
7e00c42b 207 sz = (bp->b_bcount+511) >> 9;
008c0481 208 unit = dkunit(bp);
3f3a34c3
BJ
209 if (unit >= NUP)
210 goto bad;
211 ui = updinfo[unit];
212 if (ui == 0 || ui->ui_alive == 0)
213 goto bad;
214 st = &upst[ui->ui_type];
215 if (bp->b_blkno < 0 ||
216 (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks)
217 goto bad;
218 bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff;
0cc9b5a9 219 (void) spl5();
7e00c42b
BJ
220 dp = &uputab[ui->ui_unit];
221 disksort(dp, bp);
222 if (dp->b_active == 0) {
3f3a34c3
BJ
223 (void) upustart(ui);
224 bp = &ui->ui_mi->um_tab;
225 if (bp->b_actf && bp->b_active == 0)
226 (void) upstart(ui->ui_mi);
008c0481 227 }
0cc9b5a9 228 (void) spl0();
3f3a34c3
BJ
229 return;
230
231bad:
232 bp->b_flags |= B_ERROR;
233 iodone(bp);
234 return;
008c0481
BJ
235}
236
736772ef
BJ
237/*
238 * Unit start routine.
239 * Seek the drive to be where the data is
240 * and then generate another interrupt
241 * to actually start the transfer.
242 * If there is only one drive on the controller,
243 * or we are very close to the data, don't
244 * bother with the search. If called after
245 * searching once, don't bother to look where
246 * we are, just queue for transfer (to avoid
247 * positioning forever without transferrring.)
248 */
3f3a34c3 249upustart(ui)
89bd2f01 250 register struct uba_device *ui;
008c0481
BJ
251{
252 register struct buf *bp, *dp;
89bd2f01 253 register struct uba_ctlr *um;
2601dfbd 254 register struct updevice *upaddr;
3f3a34c3 255 register struct upst *st;
008c0481 256 daddr_t bn;
736772ef 257 int sn, csn;
71236e46
BJ
258 /*
259 * The SC21 cancels commands if you just say
2601dfbd 260 * cs1 = UP_IE
71236e46
BJ
261 * so we are cautious about handling of cs1.
262 * Also don't bother to clear as bits other than in upintr().
263 */
736772ef
BJ
264 int didie = 0;
265
266 if (ui == 0)
267 return (0);
89bd2f01 268 um = ui->ui_mi;
3f3a34c3
BJ
269 dk_busy &= ~(1<<ui->ui_dk);
270 dp = &uputab[ui->ui_unit];
7bc8d985 271 if ((bp = dp->b_actf) == NULL)
eb891eaa 272 goto out;
736772ef
BJ
273 /*
274 * If the controller is active, just remember
275 * that this device would like to be positioned...
276 * if we tried to position now we would confuse the SC21.
277 */
3f3a34c3 278 if (um->um_tab.b_active) {
d763a2b7 279 up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave;
2a3b9a7f
BJ
280 return (0);
281 }
736772ef
BJ
282 /*
283 * If we have already positioned this drive,
284 * then just put it on the ready queue.
285 */
a3f430e0
BJ
286 if (dp->b_active)
287 goto done;
288 dp->b_active = 1;
2601dfbd 289 upaddr = (struct updevice *)um->um_addr;
3f3a34c3 290 upaddr->upcs2 = ui->ui_slave;
736772ef
BJ
291 /*
292 * If drive has just come up,
293 * setup the pack.
294 */
299d67ed 295 if ((upaddr->upds & UPDS_VV) == 0) {
71236e46 296 /* SHOULD WARN SYSTEM THAT THIS HAPPENED */
2601dfbd
BJ
297 upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO;
298 upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO;
299d67ed 299 upaddr->upof = UPOF_FMT22;
eb891eaa 300 didie = 1;
008c0481 301 }
736772ef
BJ
302 /*
303 * If drive is offline, forget about positioning.
304 */
299d67ed 305 if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL))
2a3b9a7f 306 goto done;
736772ef
BJ
307 /*
308 * If there is only one drive,
309 * dont bother searching.
310 */
71236e46
BJ
311 if (up_softc[um->um_ctlr].sc_ndrive == 1)
312 goto done;
736772ef
BJ
313 /*
314 * Figure out where this transfer is going to
315 * and see if we are close enough to justify not searching.
316 */
3f3a34c3 317 st = &upst[ui->ui_type];
008c0481 318 bn = dkblock(bp);
3f3a34c3
BJ
319 sn = bn%st->nspc;
320 sn = (sn + st->nsect - upSDIST) % st->nsect;
736772ef 321 if (bp->b_cylin - upaddr->updc)
7bc8d985 322 goto search; /* Not on-cylinder */
2a3b9a7f
BJ
323 else if (upseek)
324 goto done; /* Ok just to be on-cylinder */
008c0481 325 csn = (upaddr->upla>>6) - sn - 1;
7bc8d985 326 if (csn < 0)
3f3a34c3
BJ
327 csn += st->nsect;
328 if (csn > st->nsect - upRDIST)
008c0481 329 goto done;
008c0481 330search:
736772ef
BJ
331 upaddr->updc = bp->b_cylin;
332 /*
333 * Not on cylinder at correct position,
334 * seek/search.
335 */
2a3b9a7f 336 if (upseek)
2601dfbd 337 upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO;
7e00c42b 338 else {
2a3b9a7f 339 upaddr->upda = sn;
2601dfbd 340 upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO;
2a3b9a7f 341 }
eb891eaa 342 didie = 1;
736772ef
BJ
343 /*
344 * Mark unit busy for iostat.
345 */
3f3a34c3
BJ
346 if (ui->ui_dk >= 0) {
347 dk_busy |= 1<<ui->ui_dk;
348 dk_seek[ui->ui_dk]++;
008c0481 349 }
eb891eaa 350 goto out;
008c0481 351done:
736772ef
BJ
352 /*
353 * Device is ready to go.
354 * Put it on the ready queue for the controller
355 * (unless its already there.)
356 */
2601dfbd
BJ
357 if (dp->b_active != 2) {
358 dp->b_forw = NULL;
359 if (um->um_tab.b_actf == NULL)
360 um->um_tab.b_actf = dp;
361 else
362 um->um_tab.b_actl->b_forw = dp;
363 um->um_tab.b_actl = dp;
364 dp->b_active = 2;
365 }
eb891eaa
BJ
366out:
367 return (didie);
008c0481
BJ
368}
369
736772ef
BJ
370/*
371 * Start up a transfer on a drive.
372 */
3f3a34c3 373upstart(um)
89bd2f01 374 register struct uba_ctlr *um;
008c0481
BJ
375{
376 register struct buf *bp, *dp;
89bd2f01 377 register struct uba_device *ui;
2601dfbd 378 register struct updevice *upaddr;
7e00c42b 379 struct upst *st;
008c0481 380 daddr_t bn;
f88f8fdb 381 int dn, sn, tn, cmd, waitdry;
008c0481 382
008c0481 383loop:
736772ef
BJ
384 /*
385 * Pull a request off the controller queue
386 */
3f3a34c3 387 if ((dp = um->um_tab.b_actf) == NULL)
eb891eaa 388 return (0);
008c0481 389 if ((bp = dp->b_actf) == NULL) {
3f3a34c3 390 um->um_tab.b_actf = dp->b_forw;
008c0481
BJ
391 goto loop;
392 }
736772ef
BJ
393 /*
394 * Mark controller busy, and
395 * determine destination of this request.
396 */
3f3a34c3
BJ
397 um->um_tab.b_active++;
398 ui = updinfo[dkunit(bp)];
008c0481 399 bn = dkblock(bp);
3f3a34c3
BJ
400 dn = ui->ui_slave;
401 st = &upst[ui->ui_type];
402 sn = bn%st->nspc;
403 tn = sn/st->nsect;
404 sn %= st->nsect;
2601dfbd 405 upaddr = (struct updevice *)ui->ui_addr;
736772ef
BJ
406 /*
407 * Select drive if not selected already.
408 */
409 if ((upaddr->upcs2&07) != dn)
410 upaddr->upcs2 = dn;
411 /*
412 * Check that it is ready and online
413 */
f88f8fdb 414 waitdry = 0;
299d67ed 415 while ((upaddr->upds&UPDS_DRY) == 0) {
f88f8fdb
BJ
416 if (++waitdry > 512)
417 break;
418 upwaitdry++;
419 }
299d67ed 420 if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) {
f6d201ff 421 printf("up%d: not ready", dkunit(bp));
299d67ed 422 if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) {
71236e46 423 printf("\n");
3f3a34c3
BJ
424 um->um_tab.b_active = 0;
425 um->um_tab.b_errcnt = 0;
88253fd2
BJ
426 dp->b_actf = bp->av_forw;
427 dp->b_active = 0;
428 bp->b_flags |= B_ERROR;
429 iodone(bp);
88253fd2
BJ
430 goto loop;
431 }
736772ef
BJ
432 /*
433 * Oh, well, sometimes this
434 * happens, for reasons unknown.
435 */
2601dfbd 436 printf(" (flakey)\n");
008c0481 437 }
736772ef
BJ
438 /*
439 * Setup for the transfer, and get in the
440 * UNIBUS adaptor queue.
441 */
5aa9d5ea 442 upaddr->updc = bp->b_cylin;
008c0481 443 upaddr->upda = (tn << 8) + sn;
008c0481
BJ
444 upaddr->upwc = -bp->b_bcount / sizeof (short);
445 if (bp->b_flags & B_READ)
2601dfbd 446 cmd = UP_IE|UP_RCOM|UP_GO;
008c0481 447 else
2601dfbd 448 cmd = UP_IE|UP_WCOM|UP_GO;
b7333467 449 um->um_cmd = cmd;
a0eab615 450 (void) ubago(ui);
eb891eaa 451 return (1);
008c0481
BJ
452}
453
736772ef
BJ
454/*
455 * Now all ready to go, stuff the registers.
456 */
b7333467 457updgo(um)
89bd2f01 458 struct uba_ctlr *um;
3f3a34c3 459{
2601dfbd 460 register struct updevice *upaddr = (struct updevice *)um->um_addr;
7e00c42b 461
cc7ff771 462 um->um_tab.b_active++; /* should now be 2 */
b7333467
BJ
463 upaddr->upba = um->um_ubinfo;
464 upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300);
3f3a34c3
BJ
465}
466
736772ef
BJ
467/*
468 * Handle a disk interrupt.
469 */
443c8066 470upintr(sc21)
3f3a34c3 471 register sc21;
008c0481
BJ
472{
473 register struct buf *bp, *dp;
89bd2f01
BJ
474 register struct uba_ctlr *um = upminfo[sc21];
475 register struct uba_device *ui;
2601dfbd 476 register struct updevice *upaddr = (struct updevice *)um->um_addr;
008c0481 477 register unit;
7e00c42b 478 struct up_softc *sc = &up_softc[um->um_ctlr];
71236e46 479 int as = (upaddr->upas & 0377) | sc->sc_softas;
f88f8fdb 480 int needie = 1, waitdry;
008c0481 481
7e00c42b 482 sc->sc_wticks = 0;
71236e46 483 sc->sc_softas = 0;
736772ef
BJ
484 /*
485 * If controller wasn't transferring, then this is an
486 * interrupt for attention status on seeking drives.
487 * Just service them.
488 */
cc7ff771 489 if (um->um_tab.b_active != 2 && !sc->sc_recal) {
736772ef
BJ
490 if (upaddr->upcs1 & UP_TRE)
491 upaddr->upcs1 = UP_TRE;
492 goto doattn;
493 }
736772ef
BJ
494 /*
495 * Get device and block structures, and a pointer
89bd2f01 496 * to the uba_device for the drive. Select the drive.
736772ef
BJ
497 */
498 dp = um->um_tab.b_actf;
499 bp = dp->b_actf;
500 ui = updinfo[dkunit(bp)];
501 dk_busy &= ~(1 << ui->ui_dk);
502 if ((upaddr->upcs2&07) != ui->ui_slave)
3f3a34c3 503 upaddr->upcs2 = ui->ui_slave;
736772ef
BJ
504 /*
505 * Check for and process errors on
506 * either the drive or the controller.
507 */
299d67ed 508 if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) {
f88f8fdb 509 waitdry = 0;
299d67ed 510 while ((upaddr->upds & UPDS_DRY) == 0) {
f88f8fdb
BJ
511 if (++waitdry > 512)
512 break;
513 upwaitdry++;
514 }
299d67ed 515 if (upaddr->uper1&UPER1_WLE) {
736772ef
BJ
516 /*
517 * Give up on write locked devices
518 * immediately.
519 */
f6d201ff 520 printf("up%d: write locked\n", dkunit(bp));
736772ef
BJ
521 bp->b_flags |= B_ERROR;
522 } else if (++um->um_tab.b_errcnt > 27) {
523 /*
524 * After 28 retries (16 without offset, and
525 * 12 with offset positioning) give up.
526 */
f6d201ff
BJ
527 harderr(bp, "up");
528 printf("cs2=%b er1=%b er2=%b\n",
c84ff1f9
BJ
529 upaddr->upcs2, UPCS2_BITS,
530 upaddr->uper1, UPER1_BITS,
531 upaddr->uper2, UPER2_BITS);
736772ef
BJ
532 bp->b_flags |= B_ERROR;
533 } else {
534 /*
535 * Retriable error.
536 * If a soft ecc, correct it (continuing
537 * by returning if necessary.
538 * Otherwise fall through and retry the transfer
539 */
540 um->um_tab.b_active = 0; /* force retry */
299d67ed 541 if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK)
2601dfbd
BJ
542 if (upecc(ui))
543 return;
736772ef
BJ
544 }
545 /*
546 * Clear drive error and, every eight attempts,
547 * (starting with the fourth)
548 * recalibrate to clear the slate.
549 */
550 upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
551 needie = 0;
fc4d0a69 552 if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) {
736772ef 553 upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO;
a6442a2f
BJ
554 sc->sc_recal = 0;
555 goto nextrecal;
736772ef
BJ
556 }
557 }
558 /*
a6442a2f
BJ
559 * Advance recalibration finite state machine
560 * if recalibrate in progress, through
561 * RECAL
562 * SEEK
563 * OFFSET (optional)
564 * RETRY
736772ef 565 */
a6442a2f
BJ
566 switch (sc->sc_recal) {
567
568 case 1:
569 upaddr->updc = bp->b_cylin;
570 upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO;
571 goto nextrecal;
572 case 2:
573 if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0)
574 goto donerecal;
299d67ed 575 upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22;
a6442a2f
BJ
576 upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO;
577 goto nextrecal;
578 nextrecal:
579 sc->sc_recal++;
580 um->um_tab.b_active = 1;
581 return;
582 donerecal:
583 case 3:
736772ef 584 sc->sc_recal = 0;
a6442a2f
BJ
585 um->um_tab.b_active = 0;
586 break;
736772ef
BJ
587 }
588 /*
589 * If still ``active'', then don't need any more retries.
590 */
591 if (um->um_tab.b_active) {
592 /*
593 * If we were offset positioning,
594 * return to centerline.
595 */
596 if (um->um_tab.b_errcnt >= 16) {
299d67ed 597 upaddr->upof = UPOF_FMT22;
736772ef 598 upaddr->upcs1 = UP_RTC|UP_GO|UP_IE;
299d67ed 599 while (upaddr->upds & UPDS_PIP)
736772ef 600 DELAY(25);
eb891eaa 601 needie = 0;
008c0481 602 }
736772ef
BJ
603 um->um_tab.b_active = 0;
604 um->um_tab.b_errcnt = 0;
605 um->um_tab.b_actf = dp->b_forw;
606 dp->b_active = 0;
607 dp->b_errcnt = 0;
608 dp->b_actf = bp->av_forw;
609 bp->b_resid = (-upaddr->upwc * sizeof(short));
610 iodone(bp);
611 /*
612 * If this unit has more work to do,
613 * then start it up right away.
614 */
615 if (dp->b_actf)
616 if (upustart(ui))
eb891eaa 617 needie = 0;
008c0481 618 }
736772ef 619 as &= ~(1<<ui->ui_slave);
8c58f40c
BJ
620 /*
621 * Release unibus resources and flush data paths.
622 */
623 ubadone(um);
736772ef
BJ
624doattn:
625 /*
626 * Process other units which need attention.
627 * For each unit which needs attention, call
628 * the unit start routine to place the slave
629 * on the controller device queue.
630 */
a6442a2f
BJ
631 while (unit = ffs(as)) {
632 unit--; /* was 1 origin */
633 as &= ~(1<<unit);
634 upaddr->upas = 1<<unit;
635 if (upustart(upip[sc21][unit]))
636 needie = 0;
637 }
736772ef
BJ
638 /*
639 * If the controller is not transferring, but
640 * there are devices ready to transfer, start
641 * the controller.
642 */
3f3a34c3
BJ
643 if (um->um_tab.b_actf && um->um_tab.b_active == 0)
644 if (upstart(um))
eb891eaa 645 needie = 0;
2a3b9a7f 646 if (needie)
2601dfbd 647 upaddr->upcs1 = UP_IE;
008c0481
BJ
648}
649
650upread(dev)
0801d37f 651 dev_t dev;
008c0481 652{
0801d37f 653 register int unit = minor(dev) >> 3;
7e00c42b 654
0801d37f
BJ
655 if (unit >= NUP)
656 u.u_error = ENXIO;
657 else
658 physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys);
008c0481
BJ
659}
660
661upwrite(dev)
0801d37f 662 dev_t dev;
008c0481 663{
0801d37f 664 register int unit = minor(dev) >> 3;
7e00c42b 665
0801d37f
BJ
666 if (unit >= NUP)
667 u.u_error = ENXIO;
668 else
669 physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys);
008c0481
BJ
670}
671
7bc8d985
BJ
672/*
673 * Correct an ECC error, and restart the i/o to complete
674 * the transfer if necessary. This is quite complicated because
675 * the transfer may be going to an odd memory address base and/or
676 * across a page boundary.
677 */
3f3a34c3 678upecc(ui)
89bd2f01 679 register struct uba_device *ui;
008c0481 680{
2601dfbd 681 register struct updevice *up = (struct updevice *)ui->ui_addr;
3f3a34c3 682 register struct buf *bp = uputab[ui->ui_unit].b_actf;
89bd2f01 683 register struct uba_ctlr *um = ui->ui_mi;
3f3a34c3
BJ
684 register struct upst *st;
685 struct uba_regs *ubp = ui->ui_hd->uh_uba;
7bc8d985 686 register int i;
008c0481 687 caddr_t addr;
7bc8d985 688 int reg, bit, byte, npf, mask, o, cmd, ubaddr;
008c0481
BJ
689 int bn, cn, tn, sn;
690
008c0481 691 /*
7bc8d985
BJ
692 * Npf is the number of sectors transferred before the sector
693 * containing the ECC error, and reg is the UBA register
694 * mapping (the first part of) the transfer.
695 * O is offset within a memory page of the first byte transferred.
008c0481 696 */
7bc8d985 697 npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1;
b7333467 698 reg = btop(um->um_ubinfo&0x3ffff) + npf;
008c0481 699 o = (int)bp->b_un.b_addr & PGOFSET;
89bd2f01 700 printf("up%d%c: soft ecc sn%d\n", dkunit(bp),
0c48c799 701 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf);
008c0481 702 mask = up->upec2;
299d67ed 703#ifdef UPECCDEBUG
8c58f40c
BJ
704 printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask,
705 up->upec1);
299d67ed 706#endif
7bc8d985
BJ
707 /*
708 * Flush the buffered data path, and compute the
709 * byte and bit position of the error. The variable i
710 * is the byte offset in the transfer, the variable byte
711 * is the offset from a page boundary in main memory.
712 */
060afaf6 713 ubapurge(um);
7bc8d985
BJ
714 i = up->upec1 - 1; /* -1 makes 0 origin */
715 bit = i&07;
716 i = (i&~07)>>3;
008c0481 717 byte = i + o;
7bc8d985
BJ
718 /*
719 * Correct while possible bits remain of mask. Since mask
720 * contains 11 bits, we continue while the bit offset is > -11.
721 * Also watch out for end of this block and the end of the whole
722 * transfer.
723 */
724 while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) {
725 addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+
726 (byte & PGOFSET);
299d67ed 727#ifdef UPECCDEBUG
8c58f40c
BJ
728 printf("addr %x map reg %x\n",
729 addr, *(int *)(&ubp->uba_map[reg+btop(byte)]));
730 printf("old: %x, ", getmemc(addr));
299d67ed 731#endif
7bc8d985 732 putmemc(addr, getmemc(addr)^(mask<<bit));
299d67ed 733#ifdef UPECCDEBUG
8c58f40c 734 printf("new: %x\n", getmemc(addr));
299d67ed 735#endif
7bc8d985
BJ
736 byte++;
737 i++;
738 bit -= 8;
008c0481 739 }
cc7ff771 740 um->um_tab.b_active = 2; /* Either complete or continuing... */
008c0481
BJ
741 if (up->upwc == 0)
742 return (0);
7bc8d985
BJ
743 /*
744 * Have to continue the transfer... clear the drive,
745 * and compute the position where the transfer is to continue.
746 * We have completed npf+1 sectors of the transfer already;
747 * restart at offset o of next sector (i.e. in UBA register reg+1).
748 */
2601dfbd
BJ
749#ifdef notdef
750 up->uper1 = 0;
751 up->upcs1 |= UP_GO;
752#else
753 up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
008c0481 754 bn = dkblock(bp);
3f3a34c3 755 st = &upst[ui->ui_type];
008c0481 756 cn = bp->b_cylin;
3f3a34c3
BJ
757 sn = bn%st->nspc + npf + 1;
758 tn = sn/st->nsect;
759 sn %= st->nsect;
760 cn += tn/st->ntrak;
761 tn %= st->ntrak;
008c0481 762 up->updc = cn;
7bc8d985
BJ
763 up->upda = (tn << 8) | sn;
764 ubaddr = (int)ptob(reg+1) + o;
765 up->upba = ubaddr;
766 cmd = (ubaddr >> 8) & 0x300;
2601dfbd 767 cmd |= UP_IE|UP_GO|UP_RCOM;
7bc8d985 768 up->upcs1 = cmd;
2601dfbd 769#endif
008c0481
BJ
770 return (1);
771}
977c2848
BJ
772
773/*
774 * Reset driver after UBA init.
775 * Cancel software state of all pending transfers
776 * and restart all units and the controller.
777 */
3f3a34c3 778upreset(uban)
f6d201ff 779 int uban;
977c2848 780{
89bd2f01
BJ
781 register struct uba_ctlr *um;
782 register struct uba_device *ui;
3f3a34c3
BJ
783 register sc21, unit;
784
a3cb8f60 785 for (sc21 = 0; sc21 < NSC; sc21++) {
7e00c42b
BJ
786 if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban ||
787 um->um_alive == 0)
3f3a34c3 788 continue;
f6d201ff 789 printf(" sc%d", sc21);
3f3a34c3
BJ
790 um->um_tab.b_active = 0;
791 um->um_tab.b_actf = um->um_tab.b_actl = 0;
f6d201ff 792 up_softc[sc21].sc_recal = 0;
cc7ff771 793 up_softc[sc21].sc_wticks = 0;
b7333467
BJ
794 if (um->um_ubinfo) {
795 printf("<%d>", (um->um_ubinfo>>28)&0xf);
0801d37f 796 ubadone(um);
3f3a34c3 797 }
299d67ed 798 ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR;
3f3a34c3
BJ
799 for (unit = 0; unit < NUP; unit++) {
800 if ((ui = updinfo[unit]) == 0)
801 continue;
f6d201ff 802 if (ui->ui_alive == 0 || ui->ui_mi != um)
3f3a34c3
BJ
803 continue;
804 uputab[unit].b_active = 0;
805 (void) upustart(ui);
806 }
807 (void) upstart(um);
977c2848 808 }
977c2848 809}
6a81870e
BJ
810
811/*
812 * Wake up every second and if an interrupt is pending
813 * but nothing has happened increment a counter.
f6d201ff 814 * If nothing happens for 20 seconds, reset the UNIBUS
6a81870e
BJ
815 * and begin anew.
816 */
817upwatch()
818{
89bd2f01 819 register struct uba_ctlr *um;
3f3a34c3 820 register sc21, unit;
7e00c42b 821 register struct up_softc *sc;
6a81870e 822
7780575a 823 timeout(upwatch, (caddr_t)0, hz);
a3cb8f60 824 for (sc21 = 0; sc21 < NSC; sc21++) {
3f3a34c3 825 um = upminfo[sc21];
7e00c42b
BJ
826 if (um == 0 || um->um_alive == 0)
827 continue;
828 sc = &up_softc[sc21];
3f3a34c3
BJ
829 if (um->um_tab.b_active == 0) {
830 for (unit = 0; unit < NUP; unit++)
2601dfbd
BJ
831 if (uputab[unit].b_active &&
832 updinfo[unit]->ui_mi == um)
3f3a34c3 833 goto active;
7e00c42b 834 sc->sc_wticks = 0;
3f3a34c3
BJ
835 continue;
836 }
f6d201ff 837active:
7e00c42b
BJ
838 sc->sc_wticks++;
839 if (sc->sc_wticks >= 20) {
840 sc->sc_wticks = 0;
f6d201ff 841 printf("sc%d: lost interrupt\n", sc21);
a3cb8f60 842 ubareset(um->um_ubanum);
3f3a34c3 843 }
6a81870e
BJ
844 }
845}
0ff318b2
BJ
846
847#define DBSIZE 20
848
849updump(dev)
850 dev_t dev;
851{
2601dfbd 852 struct updevice *upaddr;
0ff318b2 853 char *start;
a0eab615 854 int num, blk, unit;
0ff318b2 855 struct size *sizes;
3f3a34c3 856 register struct uba_regs *uba;
89bd2f01 857 register struct uba_device *ui;
0ff318b2 858 register short *rp;
3f3a34c3 859 struct upst *st;
0ff318b2 860
0ff318b2 861 unit = minor(dev) >> 3;
0c48c799
BJ
862 if (unit >= NUP)
863 return (ENXIO);
7e00c42b 864#define phys(cast, addr) ((cast)((int)addr & 0x7fffffff))
89bd2f01 865 ui = phys(struct uba_device *, updinfo[unit]);
0c48c799
BJ
866 if (ui->ui_alive == 0)
867 return (ENXIO);
3f3a34c3 868 uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
89bd2f01 869 ubainit(uba);
2601dfbd 870 upaddr = (struct updevice *)ui->ui_physaddr;
89bd2f01 871 DELAY(2000000);
3f3a34c3
BJ
872 num = maxfree;
873 start = 0;
0ff318b2 874 upaddr->upcs2 = unit;
89bd2f01
BJ
875 DELAY(100);
876 if ((upaddr->upcs1&UP_DVA) == 0)
877 return (EFAULT);
299d67ed 878 if ((upaddr->upds & UPDS_VV) == 0) {
2601dfbd
BJ
879 upaddr->upcs1 = UP_DCLR|UP_GO;
880 upaddr->upcs1 = UP_PRESET|UP_GO;
299d67ed 881 upaddr->upof = UPOF_FMT22;
0ff318b2 882 }
299d67ed 883 if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY)
0c48c799 884 return (EFAULT);
7e00c42b 885 st = &upst[ui->ui_type];
3f3a34c3 886 sizes = phys(struct size *, st->sizes);
0c48c799
BJ
887 if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks)
888 return (EINVAL);
0ff318b2
BJ
889 while (num > 0) {
890 register struct pte *io;
891 register int i;
892 int cn, sn, tn;
893 daddr_t bn;
894
895 blk = num > DBSIZE ? DBSIZE : num;
3f3a34c3 896 io = uba->uba_map;
0ff318b2 897 for (i = 0; i < blk; i++)
89bd2f01 898 *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV;
0ff318b2
BJ
899 *(int *)io = 0;
900 bn = dumplo + btop(start);
71236e46
BJ
901 cn = bn/st->nspc + sizes[minor(dev)&07].cyloff;
902 sn = bn%st->nspc;
903 tn = sn/st->nsect;
904 sn = sn%st->nsect;
0ff318b2
BJ
905 upaddr->updc = cn;
906 rp = (short *) &upaddr->upda;
907 *rp = (tn << 8) + sn;
908 *--rp = 0;
909 *--rp = -blk*NBPG / sizeof (short);
2601dfbd 910 *--rp = UP_GO|UP_WCOM;
0ff318b2
BJ
911 do {
912 DELAY(25);
2601dfbd 913 } while ((upaddr->upcs1 & UP_RDY) == 0);
299d67ed 914 if (upaddr->upds&UPDS_ERR)
0c48c799 915 return (EIO);
0ff318b2
BJ
916 start += blk*NBPG;
917 num -= blk;
918 }
0ff318b2
BJ
919 return (0);
920}
63c35a63 921#endif