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