lint
[unix-history] / usr / src / sys / vax / uba / up.c
CommitLineData
a0eab615 1/* up.c 4.31 81/03/09 */
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
BJ
9 * Add reading of bad sector information and disk layout from sector 1
10 * Add bad sector forwarding code
11 * Check multiple drive handling
0c48c799 12 * Check unibus reset code
89bd2f01 13 * Check that offset recovery code, etc works
008c0481
BJ
14 */
15
16#include "../h/param.h"
17#include "../h/systm.h"
3f3a34c3
BJ
18#include "../h/cpu.h"
19#include "../h/nexus.h"
41888f16 20#include "../h/dk.h"
008c0481
BJ
21#include "../h/buf.h"
22#include "../h/conf.h"
23#include "../h/dir.h"
24#include "../h/user.h"
25#include "../h/map.h"
80e7c811 26#include "../h/pte.h"
008c0481 27#include "../h/mtpr.h"
008c0481 28#include "../h/vm.h"
89bd2f01
BJ
29#include "../h/ubavar.h"
30#include "../h/ubareg.h"
0ff318b2 31#include "../h/cmap.h"
008c0481 32
0ff318b2 33#include "../h/upreg.h"
008c0481 34
3f3a34c3
BJ
35struct up_softc {
36 int sc_softas;
71236e46 37 int sc_ndrive;
3f3a34c3 38 int sc_wticks;
736772ef 39 int sc_recal;
a3cb8f60 40} up_softc[NSC];
008c0481 41
3f3a34c3 42/* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
008c0481
BJ
43struct size
44{
45 daddr_t nblocks;
46 int cyloff;
47} up_sizes[8] = {
48 15884, 0, /* A=cyl 0 thru 26 */
49 33440, 27, /* B=cyl 27 thru 81 */
d1778415 50 495520, 0, /* C=cyl 0 thru 814 */
008c0481
BJ
51 15884, 562, /* D=cyl 562 thru 588 */
52 55936, 589, /* E=cyl 589 thru 680 */
53 81472, 681, /* F=cyl 681 thru 814 */
54 153824, 562, /* G=cyl 562 thru 814 */
008c0481 55 291346, 82, /* H=cyl 82 thru 561 */
3f3a34c3
BJ
56}, fj_sizes[8] = {
57 15884, 0, /* A=cyl 0 thru 49 */
58 33440, 50, /* B=cyl 50 thru 154 */
59 263360, 0, /* C=cyl 0 thru 822 */
60 0, 0,
61 0, 0,
62 0, 0,
63 0, 0,
64 213760, 155, /* H=cyl 155 thru 822 */
008c0481 65};
3f3a34c3 66/* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
008c0481 67
3f3a34c3
BJ
68#define _upSDIST 2 /* 1.0 msec */
69#define _upRDIST 4 /* 2.0 msec */
70
71int upSDIST = _upSDIST;
72int upRDIST = _upRDIST;
73
71236e46 74int upprobe(), upslave(), upattach(), updgo(), upintr();
89bd2f01
BJ
75struct uba_ctlr *upminfo[NSC];
76struct uba_device *updinfo[NUP];
77struct uba_device *upip[NSC][4];
d763a2b7 78
71236e46 79u_short upstd[] = { 0776700, 0774400, 0776300, 0 };
0801d37f 80struct uba_driver scdriver =
71236e46 81 { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo };
3f3a34c3
BJ
82struct buf uputab[NUP];
83
84struct upst {
85 short nsect;
86 short ntrak;
87 short nspc;
88 short ncyl;
89 struct size *sizes;
90} upst[] = {
71236e46
BJ
91 32, 19, 32*19, 823, up_sizes, /* 9300/cdc */
92/* 9300 actually has 815 cylinders... */
3f3a34c3
BJ
93 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */
94};
008c0481 95
2601dfbd
BJ
96u_char up_offset[16] = {
97 UP_P400, UP_M400, UP_P400, UP_M400, UP_P800, UP_M800, UP_P800, UP_M800,
98 UP_P1200, UP_M1200, UP_P1200, UP_M1200, 0, 0, 0, 0
99};
008c0481 100
0801d37f 101struct buf rupbuf[NUP];
008c0481 102
008c0481
BJ
103#define b_cylin b_resid
104
008c0481
BJ
105#ifdef INTRLVE
106daddr_t dkblock();
107#endif
3f3a34c3
BJ
108
109int upwstart, upwatch(); /* Have started guardian */
7e00c42b 110int upseek;
f88f8fdb 111int upwaitdry;
3f3a34c3
BJ
112
113/*ARGSUSED*/
71236e46 114upprobe(reg)
3f3a34c3 115 caddr_t reg;
008c0481 116{
d763a2b7
BJ
117 register int br, cvec;
118
71236e46
BJ
119#ifdef lint
120 br = 0; cvec = br; br = cvec;
121#endif
2601dfbd 122 ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY;
71236e46 123 DELAY(10);
2601dfbd 124 ((struct updevice *)reg)->upcs1 = 0;
d763a2b7 125 return (1);
3f3a34c3
BJ
126}
127
71236e46 128upslave(ui, reg)
89bd2f01 129 struct uba_device *ui;
3f3a34c3
BJ
130 caddr_t reg;
131{
2601dfbd 132 register struct updevice *upaddr = (struct updevice *)reg;
3f3a34c3
BJ
133
134 upaddr->upcs1 = 0; /* conservative */
71236e46 135 upaddr->upcs2 = ui->ui_slave;
2601dfbd
BJ
136 if (upaddr->upcs2&UP_NED) {
137 upaddr->upcs1 = UP_DCLR|UP_GO;
3f3a34c3
BJ
138 return (0);
139 }
71236e46
BJ
140 return (1);
141}
142
143upattach(ui)
89bd2f01 144 register struct uba_device *ui;
71236e46 145{
2601dfbd
BJ
146#ifdef notdef
147 register struct updevice *upaddr;
148#endif
71236e46 149
6a81870e 150 if (upwstart == 0) {
7780575a 151 timeout(upwatch, (caddr_t)0, hz);
6a81870e
BJ
152 upwstart++;
153 }
b7333467
BJ
154 if (ui->ui_dk >= 0)
155 dk_mspw[ui->ui_dk] = .0000020345;
71236e46
BJ
156 upip[ui->ui_ctlr][ui->ui_slave] = ui;
157 up_softc[ui->ui_ctlr].sc_ndrive++;
2601dfbd
BJ
158#ifdef notdef
159 upaddr = (struct updevice *)ui->ui_addr;
160 upaddr->upcs1 = 0;
161 upaddr->upcs2 = ui->ui_slave;
162 upaddr->uphr = -1;
163 /* ... */
164 if (upaddr-> ... == 10)
165 ui->ui_type = 1;
166#endif
3f3a34c3
BJ
167}
168
3f3a34c3
BJ
169upstrategy(bp)
170 register struct buf *bp;
171{
89bd2f01 172 register struct uba_device *ui;
3f3a34c3
BJ
173 register struct upst *st;
174 register int unit;
7e00c42b 175 register struct buf *dp;
3f3a34c3 176 int xunit = minor(bp->b_dev) & 07;
7e00c42b 177 long bn, sz;
3f3a34c3 178
7e00c42b 179 sz = (bp->b_bcount+511) >> 9;
008c0481 180 unit = dkunit(bp);
3f3a34c3
BJ
181 if (unit >= NUP)
182 goto bad;
183 ui = updinfo[unit];
184 if (ui == 0 || ui->ui_alive == 0)
185 goto bad;
186 st = &upst[ui->ui_type];
187 if (bp->b_blkno < 0 ||
188 (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks)
189 goto bad;
190 bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff;
008c0481 191 (void) spl5();
7e00c42b
BJ
192 dp = &uputab[ui->ui_unit];
193 disksort(dp, bp);
194 if (dp->b_active == 0) {
3f3a34c3
BJ
195 (void) upustart(ui);
196 bp = &ui->ui_mi->um_tab;
197 if (bp->b_actf && bp->b_active == 0)
198 (void) upstart(ui->ui_mi);
008c0481
BJ
199 }
200 (void) spl0();
3f3a34c3
BJ
201 return;
202
203bad:
204 bp->b_flags |= B_ERROR;
205 iodone(bp);
206 return;
008c0481
BJ
207}
208
736772ef
BJ
209/*
210 * Unit start routine.
211 * Seek the drive to be where the data is
212 * and then generate another interrupt
213 * to actually start the transfer.
214 * If there is only one drive on the controller,
215 * or we are very close to the data, don't
216 * bother with the search. If called after
217 * searching once, don't bother to look where
218 * we are, just queue for transfer (to avoid
219 * positioning forever without transferrring.)
220 */
3f3a34c3 221upustart(ui)
89bd2f01 222 register struct uba_device *ui;
008c0481
BJ
223{
224 register struct buf *bp, *dp;
89bd2f01 225 register struct uba_ctlr *um;
2601dfbd 226 register struct updevice *upaddr;
3f3a34c3 227 register struct upst *st;
008c0481 228 daddr_t bn;
736772ef 229 int sn, csn;
71236e46
BJ
230 /*
231 * The SC21 cancels commands if you just say
2601dfbd 232 * cs1 = UP_IE
71236e46
BJ
233 * so we are cautious about handling of cs1.
234 * Also don't bother to clear as bits other than in upintr().
235 */
736772ef
BJ
236 int didie = 0;
237
238 if (ui == 0)
239 return (0);
89bd2f01 240 um = ui->ui_mi;
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 345upstart(um)
89bd2f01 346 register struct uba_ctlr *um;
008c0481
BJ
347{
348 register struct buf *bp, *dp;
89bd2f01 349 register struct uba_device *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) {
f6d201ff 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 430 um->um_cmd = cmd;
a0eab615 431 (void) ubago(ui);
eb891eaa 432 return (1);
008c0481
BJ
433}
434
736772ef
BJ
435/*
436 * Now all ready to go, stuff the registers.
437 */
b7333467 438updgo(um)
89bd2f01 439 struct uba_ctlr *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;
89bd2f01
BJ
454 register struct uba_ctlr *um = upminfo[sc21];
455 register struct uba_device *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 }
736772ef
BJ
474 /*
475 * Get device and block structures, and a pointer
89bd2f01 476 * to the uba_device for the drive. Select the drive.
736772ef
BJ
477 */
478 dp = um->um_tab.b_actf;
479 bp = dp->b_actf;
480 ui = updinfo[dkunit(bp)];
481 dk_busy &= ~(1 << ui->ui_dk);
482 if ((upaddr->upcs2&07) != ui->ui_slave)
3f3a34c3 483 upaddr->upcs2 = ui->ui_slave;
736772ef
BJ
484 /*
485 * Check for and process errors on
486 * either the drive or the controller.
487 */
488 if ((upaddr->upds&UP_ERR) || (upaddr->upcs1&UP_TRE)) {
f88f8fdb
BJ
489 waitdry = 0;
490 while ((upaddr->upds & UP_DRY) == 0) {
491 if (++waitdry > 512)
492 break;
493 upwaitdry++;
494 }
f6d201ff 495 if (upaddr->uper1&UP_WLE) {
736772ef
BJ
496 /*
497 * Give up on write locked devices
498 * immediately.
499 */
f6d201ff 500 printf("up%d: write locked\n", dkunit(bp));
736772ef
BJ
501 bp->b_flags |= B_ERROR;
502 } else if (++um->um_tab.b_errcnt > 27) {
503 /*
504 * After 28 retries (16 without offset, and
505 * 12 with offset positioning) give up.
506 */
f6d201ff
BJ
507 harderr(bp, "up");
508 printf("cs2=%b er1=%b er2=%b\n",
c84ff1f9
BJ
509 upaddr->upcs2, UPCS2_BITS,
510 upaddr->uper1, UPER1_BITS,
511 upaddr->uper2, UPER2_BITS);
736772ef
BJ
512 bp->b_flags |= B_ERROR;
513 } else {
514 /*
515 * Retriable error.
516 * If a soft ecc, correct it (continuing
517 * by returning if necessary.
518 * Otherwise fall through and retry the transfer
519 */
520 um->um_tab.b_active = 0; /* force retry */
2601dfbd
BJ
521 if ((upaddr->uper1&(UP_DCK|UP_ECH))==UP_DCK)
522 if (upecc(ui))
523 return;
736772ef
BJ
524 }
525 /*
526 * Clear drive error and, every eight attempts,
527 * (starting with the fourth)
528 * recalibrate to clear the slate.
529 */
530 upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
531 needie = 0;
532 if ((um->um_tab.b_errcnt&07) == 4) {
533 upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO;
534 um->um_tab.b_active = 1;
535 sc->sc_recal = 1;
536 return;
537 }
538 }
539 /*
540 * Done retrying transfer... release
541 * resources... if we were recalibrating,
542 * then retry the transfer.
543 * Mathematical note: 28%8 != 4.
544 */
545 ubadone(um);
546 if (sc->sc_recal) {
547 sc->sc_recal = 0;
548 um->um_tab.b_active = 0; /* force retry */
549 }
550 /*
551 * If still ``active'', then don't need any more retries.
552 */
553 if (um->um_tab.b_active) {
554 /*
555 * If we were offset positioning,
556 * return to centerline.
557 */
558 if (um->um_tab.b_errcnt >= 16) {
559 upaddr->upof = UP_FMT22;
560 upaddr->upcs1 = UP_RTC|UP_GO|UP_IE;
561 while (upaddr->upds & UP_PIP)
562 DELAY(25);
eb891eaa 563 needie = 0;
008c0481 564 }
736772ef
BJ
565 um->um_tab.b_active = 0;
566 um->um_tab.b_errcnt = 0;
567 um->um_tab.b_actf = dp->b_forw;
568 dp->b_active = 0;
569 dp->b_errcnt = 0;
570 dp->b_actf = bp->av_forw;
571 bp->b_resid = (-upaddr->upwc * sizeof(short));
572 iodone(bp);
573 /*
574 * If this unit has more work to do,
575 * then start it up right away.
576 */
577 if (dp->b_actf)
578 if (upustart(ui))
eb891eaa 579 needie = 0;
008c0481 580 }
736772ef
BJ
581 as &= ~(1<<ui->ui_slave);
582doattn:
583 /*
584 * Process other units which need attention.
585 * For each unit which needs attention, call
586 * the unit start routine to place the slave
587 * on the controller device queue.
588 */
71236e46
BJ
589 for (unit = 0; as; as >>= 1, unit++)
590 if (as & 1) {
7e00c42b 591 upaddr->upas = 1<<unit;
71236e46 592 if (upustart(upip[sc21][unit]))
1f3d30ee
BJ
593 needie = 0;
594 }
736772ef
BJ
595 /*
596 * If the controller is not transferring, but
597 * there are devices ready to transfer, start
598 * the controller.
599 */
3f3a34c3
BJ
600 if (um->um_tab.b_actf && um->um_tab.b_active == 0)
601 if (upstart(um))
eb891eaa 602 needie = 0;
2a3b9a7f 603 if (needie)
2601dfbd 604 upaddr->upcs1 = UP_IE;
008c0481
BJ
605}
606
607upread(dev)
0801d37f 608 dev_t dev;
008c0481 609{
0801d37f 610 register int unit = minor(dev) >> 3;
7e00c42b 611
0801d37f
BJ
612 if (unit >= NUP)
613 u.u_error = ENXIO;
614 else
615 physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys);
008c0481
BJ
616}
617
618upwrite(dev)
0801d37f 619 dev_t dev;
008c0481 620{
0801d37f 621 register int unit = minor(dev) >> 3;
7e00c42b 622
0801d37f
BJ
623 if (unit >= NUP)
624 u.u_error = ENXIO;
625 else
626 physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys);
008c0481
BJ
627}
628
7bc8d985
BJ
629/*
630 * Correct an ECC error, and restart the i/o to complete
631 * the transfer if necessary. This is quite complicated because
632 * the transfer may be going to an odd memory address base and/or
633 * across a page boundary.
634 */
3f3a34c3 635upecc(ui)
89bd2f01 636 register struct uba_device *ui;
008c0481 637{
2601dfbd 638 register struct updevice *up = (struct updevice *)ui->ui_addr;
3f3a34c3 639 register struct buf *bp = uputab[ui->ui_unit].b_actf;
89bd2f01 640 register struct uba_ctlr *um = ui->ui_mi;
3f3a34c3
BJ
641 register struct upst *st;
642 struct uba_regs *ubp = ui->ui_hd->uh_uba;
7bc8d985 643 register int i;
008c0481 644 caddr_t addr;
7bc8d985 645 int reg, bit, byte, npf, mask, o, cmd, ubaddr;
008c0481
BJ
646 int bn, cn, tn, sn;
647
008c0481 648 /*
7bc8d985
BJ
649 * Npf is the number of sectors transferred before the sector
650 * containing the ECC error, and reg is the UBA register
651 * mapping (the first part of) the transfer.
652 * O is offset within a memory page of the first byte transferred.
008c0481 653 */
7bc8d985 654 npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1;
b7333467 655 reg = btop(um->um_ubinfo&0x3ffff) + npf;
008c0481 656 o = (int)bp->b_un.b_addr & PGOFSET;
89bd2f01 657 printf("up%d%c: soft ecc sn%d\n", dkunit(bp),
0c48c799 658 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf);
008c0481 659 mask = up->upec2;
7bc8d985
BJ
660 /*
661 * Flush the buffered data path, and compute the
662 * byte and bit position of the error. The variable i
663 * is the byte offset in the transfer, the variable byte
664 * is the offset from a page boundary in main memory.
665 */
060afaf6 666 ubapurge(um);
7bc8d985
BJ
667 i = up->upec1 - 1; /* -1 makes 0 origin */
668 bit = i&07;
669 i = (i&~07)>>3;
008c0481 670 byte = i + o;
7bc8d985
BJ
671 /*
672 * Correct while possible bits remain of mask. Since mask
673 * contains 11 bits, we continue while the bit offset is > -11.
674 * Also watch out for end of this block and the end of the whole
675 * transfer.
676 */
677 while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) {
678 addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+
679 (byte & PGOFSET);
680 putmemc(addr, getmemc(addr)^(mask<<bit));
681 byte++;
682 i++;
683 bit -= 8;
008c0481 684 }
3f3a34c3 685 um->um_tab.b_active++; /* Either complete or continuing... */
008c0481
BJ
686 if (up->upwc == 0)
687 return (0);
7bc8d985
BJ
688 /*
689 * Have to continue the transfer... clear the drive,
690 * and compute the position where the transfer is to continue.
691 * We have completed npf+1 sectors of the transfer already;
692 * restart at offset o of next sector (i.e. in UBA register reg+1).
693 */
2601dfbd
BJ
694#ifdef notdef
695 up->uper1 = 0;
696 up->upcs1 |= UP_GO;
697#else
698 up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
008c0481 699 bn = dkblock(bp);
3f3a34c3 700 st = &upst[ui->ui_type];
008c0481 701 cn = bp->b_cylin;
3f3a34c3
BJ
702 sn = bn%st->nspc + npf + 1;
703 tn = sn/st->nsect;
704 sn %= st->nsect;
705 cn += tn/st->ntrak;
706 tn %= st->ntrak;
008c0481 707 up->updc = cn;
7bc8d985
BJ
708 up->upda = (tn << 8) | sn;
709 ubaddr = (int)ptob(reg+1) + o;
710 up->upba = ubaddr;
711 cmd = (ubaddr >> 8) & 0x300;
2601dfbd 712 cmd |= UP_IE|UP_GO|UP_RCOM;
7bc8d985 713 up->upcs1 = cmd;
2601dfbd 714#endif
008c0481
BJ
715 return (1);
716}
977c2848
BJ
717
718/*
719 * Reset driver after UBA init.
720 * Cancel software state of all pending transfers
721 * and restart all units and the controller.
722 */
3f3a34c3 723upreset(uban)
f6d201ff 724 int uban;
977c2848 725{
89bd2f01
BJ
726 register struct uba_ctlr *um;
727 register struct uba_device *ui;
3f3a34c3
BJ
728 register sc21, unit;
729
a3cb8f60 730 for (sc21 = 0; sc21 < NSC; sc21++) {
7e00c42b
BJ
731 if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban ||
732 um->um_alive == 0)
3f3a34c3 733 continue;
f6d201ff 734 printf(" sc%d", sc21);
3f3a34c3
BJ
735 um->um_tab.b_active = 0;
736 um->um_tab.b_actf = um->um_tab.b_actl = 0;
f6d201ff 737 up_softc[sc21].sc_recal = 0;
b7333467
BJ
738 if (um->um_ubinfo) {
739 printf("<%d>", (um->um_ubinfo>>28)&0xf);
0801d37f 740 ubadone(um);
3f3a34c3 741 }
2601dfbd 742 ((struct updevice *)(um->um_addr))->upcs2 = UP_CLR;
3f3a34c3
BJ
743 for (unit = 0; unit < NUP; unit++) {
744 if ((ui = updinfo[unit]) == 0)
745 continue;
f6d201ff 746 if (ui->ui_alive == 0 || ui->ui_mi != um)
3f3a34c3
BJ
747 continue;
748 uputab[unit].b_active = 0;
749 (void) upustart(ui);
750 }
751 (void) upstart(um);
977c2848 752 }
977c2848 753}
6a81870e
BJ
754
755/*
756 * Wake up every second and if an interrupt is pending
757 * but nothing has happened increment a counter.
f6d201ff 758 * If nothing happens for 20 seconds, reset the UNIBUS
6a81870e
BJ
759 * and begin anew.
760 */
761upwatch()
762{
89bd2f01 763 register struct uba_ctlr *um;
3f3a34c3 764 register sc21, unit;
7e00c42b 765 register struct up_softc *sc;
6a81870e 766
7780575a 767 timeout(upwatch, (caddr_t)0, hz);
a3cb8f60 768 for (sc21 = 0; sc21 < NSC; sc21++) {
3f3a34c3 769 um = upminfo[sc21];
7e00c42b
BJ
770 if (um == 0 || um->um_alive == 0)
771 continue;
772 sc = &up_softc[sc21];
3f3a34c3
BJ
773 if (um->um_tab.b_active == 0) {
774 for (unit = 0; unit < NUP; unit++)
2601dfbd
BJ
775 if (uputab[unit].b_active &&
776 updinfo[unit]->ui_mi == um)
3f3a34c3 777 goto active;
7e00c42b 778 sc->sc_wticks = 0;
3f3a34c3
BJ
779 continue;
780 }
f6d201ff 781active:
7e00c42b
BJ
782 sc->sc_wticks++;
783 if (sc->sc_wticks >= 20) {
784 sc->sc_wticks = 0;
f6d201ff 785 printf("sc%d: lost interrupt\n", sc21);
a3cb8f60 786 ubareset(um->um_ubanum);
3f3a34c3 787 }
6a81870e
BJ
788 }
789}
0ff318b2
BJ
790
791#define DBSIZE 20
792
793updump(dev)
794 dev_t dev;
795{
2601dfbd 796 struct updevice *upaddr;
0ff318b2 797 char *start;
a0eab615 798 int num, blk, unit;
0ff318b2 799 struct size *sizes;
3f3a34c3 800 register struct uba_regs *uba;
89bd2f01 801 register struct uba_device *ui;
0ff318b2 802 register short *rp;
3f3a34c3 803 struct upst *st;
0ff318b2 804
0ff318b2 805 unit = minor(dev) >> 3;
0c48c799
BJ
806 if (unit >= NUP)
807 return (ENXIO);
7e00c42b 808#define phys(cast, addr) ((cast)((int)addr & 0x7fffffff))
89bd2f01 809 ui = phys(struct uba_device *, updinfo[unit]);
0c48c799
BJ
810 if (ui->ui_alive == 0)
811 return (ENXIO);
3f3a34c3 812 uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
89bd2f01 813 ubainit(uba);
2601dfbd 814 upaddr = (struct updevice *)ui->ui_physaddr;
89bd2f01 815 DELAY(2000000);
3f3a34c3
BJ
816 num = maxfree;
817 start = 0;
0ff318b2 818 upaddr->upcs2 = unit;
89bd2f01
BJ
819 DELAY(100);
820 if ((upaddr->upcs1&UP_DVA) == 0)
821 return (EFAULT);
2601dfbd
BJ
822 if ((upaddr->upds & UP_VV) == 0) {
823 upaddr->upcs1 = UP_DCLR|UP_GO;
824 upaddr->upcs1 = UP_PRESET|UP_GO;
825 upaddr->upof = UP_FMT22;
0ff318b2 826 }
0c48c799
BJ
827 if ((upaddr->upds & UP_DREADY) != UP_DREADY)
828 return (EFAULT);
7e00c42b 829 st = &upst[ui->ui_type];
3f3a34c3 830 sizes = phys(struct size *, st->sizes);
0c48c799
BJ
831 if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks)
832 return (EINVAL);
0ff318b2
BJ
833 while (num > 0) {
834 register struct pte *io;
835 register int i;
836 int cn, sn, tn;
837 daddr_t bn;
838
839 blk = num > DBSIZE ? DBSIZE : num;
3f3a34c3 840 io = uba->uba_map;
0ff318b2 841 for (i = 0; i < blk; i++)
89bd2f01 842 *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV;
0ff318b2
BJ
843 *(int *)io = 0;
844 bn = dumplo + btop(start);
71236e46
BJ
845 cn = bn/st->nspc + sizes[minor(dev)&07].cyloff;
846 sn = bn%st->nspc;
847 tn = sn/st->nsect;
848 sn = sn%st->nsect;
0ff318b2
BJ
849 upaddr->updc = cn;
850 rp = (short *) &upaddr->upda;
851 *rp = (tn << 8) + sn;
852 *--rp = 0;
853 *--rp = -blk*NBPG / sizeof (short);
2601dfbd 854 *--rp = UP_GO|UP_WCOM;
0ff318b2
BJ
855 do {
856 DELAY(25);
2601dfbd 857 } while ((upaddr->upcs1 & UP_RDY) == 0);
0c48c799
BJ
858 if (upaddr->upcs1&UP_ERR)
859 return (EIO);
0ff318b2
BJ
860 start += blk*NBPG;
861 num -= blk;
862 }
0ff318b2
BJ
863 return (0);
864}
63c35a63 865#endif