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