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