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