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