new minfo strategy
[unix-history] / usr / src / sys / vax / uba / up.c
CommitLineData
d763a2b7 1/* up.c 4.15 81/02/16 */
008c0481 2
66b4fb09 3#include "up.h"
3f3a34c3 4#if NSC21 > 0
008c0481 5/*
10fb932f 6 * UNIBUS disk driver with overlapped seeks and ECC recovery.
008c0481 7 */
355250d9 8#define DELAY(N) { register int d; d = N; while (--d > 0); }
008c0481
BJ
9
10#include "../h/param.h"
11#include "../h/systm.h"
3f3a34c3
BJ
12#include "../h/cpu.h"
13#include "../h/nexus.h"
41888f16 14#include "../h/dk.h"
008c0481
BJ
15#include "../h/buf.h"
16#include "../h/conf.h"
17#include "../h/dir.h"
18#include "../h/user.h"
19#include "../h/map.h"
80e7c811 20#include "../h/pte.h"
008c0481
BJ
21#include "../h/mba.h"
22#include "../h/mtpr.h"
008c0481
BJ
23#include "../h/uba.h"
24#include "../h/vm.h"
0ff318b2 25#include "../h/cmap.h"
008c0481 26
0ff318b2 27#include "../h/upreg.h"
008c0481 28
3f3a34c3
BJ
29struct up_softc {
30 int sc_softas;
31 int sc_seek;
32 int sc_info;
33 int sc_wticks;
5aa9d5ea 34 /* struct uba_minfo sc_minfo; */
3f3a34c3 35} up_softc[NSC21];
008c0481 36
3f3a34c3 37/* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
008c0481
BJ
38struct size
39{
40 daddr_t nblocks;
41 int cyloff;
42} up_sizes[8] = {
43 15884, 0, /* A=cyl 0 thru 26 */
44 33440, 27, /* B=cyl 27 thru 81 */
d1778415 45 495520, 0, /* C=cyl 0 thru 814 */
008c0481
BJ
46 15884, 562, /* D=cyl 562 thru 588 */
47 55936, 589, /* E=cyl 589 thru 680 */
48 81472, 681, /* F=cyl 681 thru 814 */
49 153824, 562, /* G=cyl 562 thru 814 */
008c0481 50 291346, 82, /* H=cyl 82 thru 561 */
3f3a34c3
BJ
51}, fj_sizes[8] = {
52 15884, 0, /* A=cyl 0 thru 49 */
53 33440, 50, /* B=cyl 50 thru 154 */
54 263360, 0, /* C=cyl 0 thru 822 */
55 0, 0,
56 0, 0,
57 0, 0,
58 0, 0,
59 213760, 155, /* H=cyl 155 thru 822 */
008c0481 60};
3f3a34c3 61/* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
008c0481 62
3f3a34c3
BJ
63#define _upSDIST 2 /* 1.0 msec */
64#define _upRDIST 4 /* 2.0 msec */
65
66int upSDIST = _upSDIST;
67int upRDIST = _upRDIST;
68
69int upcntrlr(), upslave(), updgo(), upintr();
70struct uba_minfo *upminfo[NSC21];
71struct uba_dinfo *updinfo[NUP];
d763a2b7
BJ
72
73u_short upstd[] = { 0776700, 0774400, 0776300 };
3f3a34c3 74struct uba_driver updriver =
d763a2b7 75 { upcntrlr, upslave, updgo, 0, upstd, "up", updinfo, upminfo };
3f3a34c3
BJ
76struct buf uputab[NUP];
77
78struct upst {
79 short nsect;
80 short ntrak;
81 short nspc;
82 short ncyl;
83 struct size *sizes;
84} upst[] = {
85 32, 19, 32*19, 815, up_sizes, /* 9300 */
86 32, 19, 32*19, 823, up_sizes, /* so cdc will boot */
87 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */
88};
008c0481
BJ
89
90int up_offset[16] =
91{
92 P400, M400, P400, M400,
93 P800, M800, P800, M800,
94 P1200, M1200, P1200, M1200,
95 0, 0, 0, 0,
96};
97
3f3a34c3 98struct buf rupbuf; /* GROT */
008c0481 99
008c0481
BJ
100#define b_cylin b_resid
101
008c0481
BJ
102#ifdef INTRLVE
103daddr_t dkblock();
104#endif
3f3a34c3
BJ
105
106int upwstart, upwatch(); /* Have started guardian */
107
108/*ARGSUSED*/
109upcntrlr(um, reg)
110 struct uba_minfo *um;
111 caddr_t reg;
008c0481 112{
d763a2b7
BJ
113 register int br, cvec;
114
3f3a34c3 115 ((struct device *)reg)->upcs1 |= (IE|RDY);
d763a2b7 116 return (1);
3f3a34c3
BJ
117}
118
d763a2b7 119upslave(ui, reg, slaveno)
3f3a34c3
BJ
120 struct uba_dinfo *ui;
121 caddr_t reg;
122{
123 register struct device *upaddr = (struct device *)reg;
3f3a34c3
BJ
124
125 upaddr->upcs1 = 0; /* conservative */
126 upaddr->upcs2 = slaveno;
127 if (upaddr->upcs2&NED) {
128 upaddr->upcs1 = DCLR|GO;
129 return (0);
130 }
6a81870e 131 if (upwstart == 0) {
49c84d3f 132 timeout(upwatch, (caddr_t)0, HZ);
6a81870e
BJ
133 upwstart++;
134 }
3f3a34c3
BJ
135 return (1);
136}
137
138/*
139 dk_mspw[UPDK_N+unit] = .0000020345;
140*/
141
142upstrategy(bp)
143 register struct buf *bp;
144{
145 register struct uba_dinfo *ui;
146 register struct uba_minfo *um;
147 register struct upst *st;
148 register int unit;
149 int xunit = minor(bp->b_dev) & 07;
150 long sz, bn;
151
008c0481
BJ
152 sz = bp->b_bcount;
153 sz = (sz+511) >> 9; /* transfer size in 512 byte sectors */
154 unit = dkunit(bp);
3f3a34c3
BJ
155 if (unit >= NUP)
156 goto bad;
157 ui = updinfo[unit];
158 if (ui == 0 || ui->ui_alive == 0)
159 goto bad;
160 st = &upst[ui->ui_type];
161 if (bp->b_blkno < 0 ||
162 (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks)
163 goto bad;
164 bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff;
008c0481 165 (void) spl5();
3f3a34c3
BJ
166 disksort(&uputab[ui->ui_unit], bp);
167 if (uputab[ui->ui_unit].b_active == 0) {
168 (void) upustart(ui);
169 bp = &ui->ui_mi->um_tab;
170 if (bp->b_actf && bp->b_active == 0)
171 (void) upstart(ui->ui_mi);
008c0481
BJ
172 }
173 (void) spl0();
3f3a34c3
BJ
174 return;
175
176bad:
177 bp->b_flags |= B_ERROR;
178 iodone(bp);
179 return;
008c0481
BJ
180}
181
3f3a34c3
BJ
182upustart(ui)
183 register struct uba_dinfo *ui;
008c0481
BJ
184{
185 register struct buf *bp, *dp;
3f3a34c3
BJ
186 register struct uba_minfo *um;
187 register struct device *upaddr;
188 register struct upst *st;
008c0481
BJ
189 daddr_t bn;
190 int sn, cn, csn;
eb891eaa 191 int didie = 0;
008c0481 192
3f3a34c3
BJ
193 /* SC21 cancels commands if you say cs1 = IE, so dont */
194 /* being ultra-cautious, we clear as bits only in upintr() */
195 dk_busy &= ~(1<<ui->ui_dk);
196 dp = &uputab[ui->ui_unit];
7bc8d985 197 if ((bp = dp->b_actf) == NULL)
eb891eaa 198 goto out;
3f3a34c3
BJ
199 /* dont confuse controller by giving SEARCH while dt in progress */
200 um = ui->ui_mi;
201 if (um->um_tab.b_active) {
d763a2b7 202 up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave;
2a3b9a7f
BJ
203 return (0);
204 }
a3f430e0
BJ
205 if (dp->b_active)
206 goto done;
207 dp->b_active = 1;
3f3a34c3
BJ
208 upaddr = (struct device *)um->um_addr;
209 upaddr->upcs2 = ui->ui_slave;
7bc8d985
BJ
210 if ((upaddr->upds & VV) == 0) {
211 upaddr->upcs1 = IE|DCLR|GO;
008c0481 212 upaddr->upcs1 = IE|PRESET|GO;
008c0481 213 upaddr->upof = FMT22;
eb891eaa 214 didie = 1;
008c0481 215 }
008c0481 216 if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL))
2a3b9a7f 217 goto done;
3f3a34c3 218 st = &upst[ui->ui_type];
008c0481
BJ
219 bn = dkblock(bp);
220 cn = bp->b_cylin;
3f3a34c3
BJ
221 sn = bn%st->nspc;
222 sn = (sn + st->nsect - upSDIST) % st->nsect;
7bc8d985
BJ
223 if (cn - upaddr->updc)
224 goto search; /* Not on-cylinder */
3f3a34c3 225/**** WHAT SHOULD THIS BE NOW ???
2a3b9a7f
BJ
226 else if (upseek)
227 goto done; /* Ok just to be on-cylinder */
008c0481 228 csn = (upaddr->upla>>6) - sn - 1;
7bc8d985 229 if (csn < 0)
3f3a34c3
BJ
230 csn += st->nsect;
231 if (csn > st->nsect - upRDIST)
008c0481 232 goto done;
008c0481
BJ
233search:
234 upaddr->updc = cn;
3f3a34c3 235/*** ANOTHER OCCURRENCE
2a3b9a7f
BJ
236 if (upseek)
237 upaddr->upcs1 = IE|SEEK|GO;
3f3a34c3 238 else ****/ {
2a3b9a7f
BJ
239 upaddr->upda = sn;
240 upaddr->upcs1 = IE|SEARCH|GO;
241 }
eb891eaa 242 didie = 1;
3f3a34c3
BJ
243 if (ui->ui_dk >= 0) {
244 dk_busy |= 1<<ui->ui_dk;
245 dk_seek[ui->ui_dk]++;
008c0481 246 }
eb891eaa 247 goto out;
008c0481
BJ
248done:
249 dp->b_forw = NULL;
3f3a34c3
BJ
250 if (um->um_tab.b_actf == NULL)
251 um->um_tab.b_actf = dp;
008c0481 252 else
3f3a34c3
BJ
253 um->um_tab.b_actl->b_forw = dp;
254 um->um_tab.b_actl = dp;
eb891eaa
BJ
255out:
256 return (didie);
008c0481
BJ
257}
258
3f3a34c3
BJ
259upstart(um)
260 register struct uba_minfo *um;
008c0481
BJ
261{
262 register struct buf *bp, *dp;
3f3a34c3 263 register struct uba_dinfo *ui;
008c0481
BJ
264 register unit;
265 register struct device *upaddr;
3f3a34c3 266 register struct upst *st;
008c0481 267 daddr_t bn;
5aa9d5ea 268 int dn, sn, tn, cmd;
008c0481 269
008c0481 270loop:
3f3a34c3 271 if ((dp = um->um_tab.b_actf) == NULL)
eb891eaa 272 return (0);
008c0481 273 if ((bp = dp->b_actf) == NULL) {
3f3a34c3 274 um->um_tab.b_actf = dp->b_forw;
008c0481
BJ
275 goto loop;
276 }
7bc8d985
BJ
277 /*
278 * Mark the controller busy, and multi-part disk address.
279 * Select the unit on which the i/o is to take place.
280 */
3f3a34c3
BJ
281 um->um_tab.b_active++;
282 ui = updinfo[dkunit(bp)];
008c0481 283 bn = dkblock(bp);
3f3a34c3
BJ
284 dn = ui->ui_slave;
285 st = &upst[ui->ui_type];
286 sn = bn%st->nspc;
287 tn = sn/st->nsect;
288 sn %= st->nsect;
289 upaddr = (struct device *)ui->ui_addr;
355250d9 290 if ((upaddr->upcs2 & 07) != dn)
008c0481 291 upaddr->upcs2 = dn;
d763a2b7 292 up_softc[um->um_ctlr].sc_info =
3f3a34c3 293 ubasetup(ui->ui_ubanum, bp, UBA_NEEDBDP|UBA_CANTWAIT);
7bc8d985
BJ
294 /*
295 * If drive is not present and on-line, then
296 * get rid of this with an error and loop to get
297 * rid of the rest of its queued requests.
298 * (Then on to any other ready drives.)
299 */
008c0481 300 if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) {
88253fd2
BJ
301 printf("!DPR || !MOL, unit %d, ds %o", dn, upaddr->upds);
302 if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) {
303 printf("-- hard\n");
3f3a34c3
BJ
304 um->um_tab.b_active = 0;
305 um->um_tab.b_errcnt = 0;
88253fd2
BJ
306 dp->b_actf = bp->av_forw;
307 dp->b_active = 0;
308 bp->b_flags |= B_ERROR;
309 iodone(bp);
310 /* A funny place to do this ... */
d763a2b7 311 ubarelse(ui->ui_ubanum, &up_softc[um->um_ctlr].sc_info);
88253fd2
BJ
312 goto loop;
313 }
314 printf("-- came back\n");
008c0481 315 }
7bc8d985
BJ
316 /*
317 * If this is a retry, then with the 16'th retry we
318 * begin to try offsetting the heads to recover the data.
319 */
3f3a34c3
BJ
320 if (um->um_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) {
321 upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | FMT22;
7bc8d985 322 upaddr->upcs1 = IE|OFFSET|GO;
7bc8d985 323 while (upaddr->upds & PIP)
008c0481
BJ
324 DELAY(25);
325 }
7bc8d985
BJ
326 /*
327 * Now set up the transfer, retrieving the high
328 * 2 bits of the UNIBUS address from the information
329 * returned by ubasetup() for the cs1 register bits 8 and 9.
330 */
5aa9d5ea 331 upaddr->updc = bp->b_cylin;
008c0481 332 upaddr->upda = (tn << 8) + sn;
d763a2b7 333 upaddr->upba = up_softc[um->um_ctlr].sc_info;
008c0481 334 upaddr->upwc = -bp->b_bcount / sizeof (short);
d763a2b7 335 cmd = (up_softc[um->um_ctlr].sc_info >> 8) & 0x300;
008c0481 336 if (bp->b_flags & B_READ)
7bc8d985 337 cmd |= IE|RCOM|GO;
008c0481 338 else
7bc8d985 339 cmd |= IE|WCOM|GO;
7bc8d985 340 upaddr->upcs1 = cmd;
7bc8d985
BJ
341 /*
342 * This is a controller busy situation.
c134650e 343 * Record in dk slot NUP+UPDK_N (after last drive)
7bc8d985
BJ
344 * unless there aren't that many slots reserved for
345 * us in which case we record this as a drive busy
346 * (if there is room for that).
347 */
3f3a34c3
BJ
348 unit = ui->ui_dk;
349 dk_busy |= 1<<unit;
350 dk_xfer[unit]++;
351 dk_wds[unit] += bp->b_bcount>>6;
eb891eaa 352 return (1);
008c0481
BJ
353}
354
3f3a34c3
BJ
355updgo()
356{
357}
358
008c0481
BJ
359/*
360 * Handle a device interrupt.
361 *
362 * If the transferring drive needs attention, service it
363 * retrying on error or beginning next transfer.
364 * Service all other ready drives, calling ustart to transfer
3f3a34c3 365 * their blocks to the ready queue in um->um_tab, and then restart
008c0481
BJ
366 * the controller if there is anything to do.
367 */
3f3a34c3
BJ
368upintr(sc21)
369 register sc21;
008c0481
BJ
370{
371 register struct buf *bp, *dp;
3f3a34c3
BJ
372 register struct uba_minfo *um = upminfo[sc21];
373 register struct uba_dinfo *ui;
374 register struct device *upaddr = (struct device *)um->um_addr;
008c0481 375 register unit;
008c0481 376 int as = upaddr->upas & 0377;
eb891eaa 377 int needie = 1;
008c0481 378
a3f430e0 379 (void) spl6();
d763a2b7 380 up_softc[um->um_ctlr].sc_wticks = 0;
3f3a34c3 381 if (um->um_tab.b_active) {
7bc8d985 382 if ((upaddr->upcs1 & RDY) == 0) {
39bd608f
BJ
383 printf("!RDY: cs1 %o, ds %o, wc %d\n", upaddr->upcs1,
384 upaddr->upds, upaddr->upwc);
3f3a34c3 385 printf("as=%d act %d %d %d\n", as, um->um_tab.b_active,
d1778415 386 uputab[0].b_active, uputab[1].b_active);
6e179703 387 }
3f3a34c3 388 dp = um->um_tab.b_actf;
008c0481 389 bp = dp->b_actf;
3f3a34c3
BJ
390 ui = updinfo[dkunit(bp)];
391 dk_busy &= ~(1 << ui->ui_dk);
392 upaddr->upcs2 = ui->ui_slave;
10fb932f 393 if ((upaddr->upds&ERR) || (upaddr->upcs1&TRE)) {
0ad5097e 394 int cs2;
7bc8d985 395 while ((upaddr->upds & DRY) == 0)
008c0481 396 DELAY(25);
3f3a34c3 397 if (++um->um_tab.b_errcnt > 28 || upaddr->uper1&WLE)
008c0481
BJ
398 bp->b_flags |= B_ERROR;
399 else
3f3a34c3
BJ
400 um->um_tab.b_active = 0; /* force retry */
401 if (um->um_tab.b_errcnt > 27) {
0ad5097e 402 cs2 = (int)upaddr->upcs2;
3f3a34c3
BJ
403 deverror(bp, cs2, (int)upaddr->uper1);
404 }
405 if ((upaddr->uper1&(DCK|ECH))==DCK && upecc(ui))
7bc8d985 406 return;
008c0481 407 upaddr->upcs1 = TRE|IE|DCLR|GO;
eb891eaa 408 needie = 0;
3f3a34c3 409 if ((um->um_tab.b_errcnt&07) == 4) {
008c0481 410 upaddr->upcs1 = RECAL|GO|IE;
008c0481
BJ
411 while(upaddr->upds & PIP)
412 DELAY(25);
413 }
3f3a34c3 414 if (um->um_tab.b_errcnt == 28 && cs2&(NEM|MXF)) {
0ad5097e 415 printf("FLAKEY UP ");
3f3a34c3 416 ubareset(um->um_ubanum);
0ad5097e
BJ
417 return;
418 }
008c0481 419 }
3f3a34c3
BJ
420 if (um->um_tab.b_active) {
421 if (um->um_tab.b_errcnt >= 16) {
7bc8d985 422 upaddr->upcs1 = RTC|GO|IE;
7bc8d985 423 while (upaddr->upds & PIP)
008c0481 424 DELAY(25);
eb891eaa 425 needie = 0;
008c0481 426 }
3f3a34c3
BJ
427 um->um_tab.b_active = 0;
428 um->um_tab.b_errcnt = 0;
429 um->um_tab.b_actf = dp->b_forw;
008c0481
BJ
430 dp->b_active = 0;
431 dp->b_errcnt = 0;
432 dp->b_actf = bp->av_forw;
7bc8d985 433 bp->b_resid = (-upaddr->upwc * sizeof(short));
2a3b9a7f 434 if (bp->b_resid)
d1778415
BJ
435 printf("resid %d ds %o er? %o %o %o\n",
436 bp->b_resid, upaddr->upds,
2a3b9a7f 437 upaddr->uper1, upaddr->uper2, upaddr->uper3);
008c0481 438 iodone(bp);
3f3a34c3
BJ
439 if (dp->b_actf)
440 if (upustart(ui))
eb891eaa 441 needie = 0;
008c0481 442 }
d763a2b7
BJ
443 up_softc[um->um_ctlr].sc_softas &= ~(1<<ui->ui_slave);
444 ubarelse(ui->ui_ubanum, &up_softc[um->um_ctlr].sc_info);
1f3d30ee 445 } else {
355250d9 446 if (upaddr->upcs1 & TRE)
008c0481 447 upaddr->upcs1 = TRE;
008c0481 448 }
d763a2b7 449 as |= up_softc[um->um_ctlr].sc_softas;
3f3a34c3
BJ
450 for (unit = 0; unit < NUP; unit++) {
451 if ((ui = updinfo[unit]) == 0 || ui->ui_mi != um)
452 continue;
453 if (as & (1<<unit)) {
355250d9 454 if (as & (1<<unit))
5c65daa3 455 upaddr->upas = 1<<unit;
3f3a34c3 456 if (upustart(ui))
1f3d30ee
BJ
457 needie = 0;
458 }
3f3a34c3
BJ
459 }
460 if (um->um_tab.b_actf && um->um_tab.b_active == 0)
461 if (upstart(um))
eb891eaa 462 needie = 0;
2a3b9a7f 463 if (needie)
7bc8d985 464 upaddr->upcs1 = IE;
008c0481
BJ
465}
466
467upread(dev)
468{
008c0481
BJ
469 physio(upstrategy, &rupbuf, dev, B_READ, minphys);
470}
471
472upwrite(dev)
473{
008c0481
BJ
474 physio(upstrategy, &rupbuf, dev, B_WRITE, minphys);
475}
476
7bc8d985
BJ
477/*
478 * Correct an ECC error, and restart the i/o to complete
479 * the transfer if necessary. This is quite complicated because
480 * the transfer may be going to an odd memory address base and/or
481 * across a page boundary.
482 */
3f3a34c3
BJ
483upecc(ui)
484 register struct uba_dinfo *ui;
008c0481 485{
3f3a34c3
BJ
486 register struct device *up = (struct device *)ui->ui_addr;
487 register struct buf *bp = uputab[ui->ui_unit].b_actf;
488 register struct uba_minfo *um = ui->ui_mi;
489 register struct upst *st;
490 struct uba_regs *ubp = ui->ui_hd->uh_uba;
7bc8d985 491 register int i;
008c0481 492 caddr_t addr;
7bc8d985 493 int reg, bit, byte, npf, mask, o, cmd, ubaddr;
008c0481
BJ
494 int bn, cn, tn, sn;
495
008c0481 496 /*
7bc8d985
BJ
497 * Npf is the number of sectors transferred before the sector
498 * containing the ECC error, and reg is the UBA register
499 * mapping (the first part of) the transfer.
500 * O is offset within a memory page of the first byte transferred.
008c0481 501 */
7bc8d985 502 npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1;
d763a2b7 503 reg = btop(up_softc[um->um_ctlr].sc_info&0x3ffff) + npf;
008c0481
BJ
504 o = (int)bp->b_un.b_addr & PGOFSET;
505 printf("%D ", bp->b_blkno+npf);
506 prdev("ECC", bp->b_dev);
507 mask = up->upec2;
508 if (mask == 0) {
7bc8d985 509 up->upof = FMT22; /* == RTC ???? */
008c0481
BJ
510 return (0);
511 }
7bc8d985
BJ
512 /*
513 * Flush the buffered data path, and compute the
514 * byte and bit position of the error. The variable i
515 * is the byte offset in the transfer, the variable byte
516 * is the offset from a page boundary in main memory.
517 */
d763a2b7 518 ubp->uba_dpr[(up_softc[um->um_ctlr].sc_info>>28)&0x0f] |= UBA_BNE;
7bc8d985
BJ
519 i = up->upec1 - 1; /* -1 makes 0 origin */
520 bit = i&07;
521 i = (i&~07)>>3;
008c0481 522 byte = i + o;
7bc8d985
BJ
523 /*
524 * Correct while possible bits remain of mask. Since mask
525 * contains 11 bits, we continue while the bit offset is > -11.
526 * Also watch out for end of this block and the end of the whole
527 * transfer.
528 */
529 while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) {
530 addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+
531 (byte & PGOFSET);
532 putmemc(addr, getmemc(addr)^(mask<<bit));
533 byte++;
534 i++;
535 bit -= 8;
008c0481 536 }
3f3a34c3 537 um->um_tab.b_active++; /* Either complete or continuing... */
008c0481
BJ
538 if (up->upwc == 0)
539 return (0);
7bc8d985
BJ
540 /*
541 * Have to continue the transfer... clear the drive,
542 * and compute the position where the transfer is to continue.
543 * We have completed npf+1 sectors of the transfer already;
544 * restart at offset o of next sector (i.e. in UBA register reg+1).
545 */
546 up->upcs1 = TRE|IE|DCLR|GO;
008c0481 547 bn = dkblock(bp);
3f3a34c3 548 st = &upst[ui->ui_type];
008c0481 549 cn = bp->b_cylin;
3f3a34c3
BJ
550 sn = bn%st->nspc + npf + 1;
551 tn = sn/st->nsect;
552 sn %= st->nsect;
553 cn += tn/st->ntrak;
554 tn %= st->ntrak;
008c0481 555 up->updc = cn;
7bc8d985
BJ
556 up->upda = (tn << 8) | sn;
557 ubaddr = (int)ptob(reg+1) + o;
558 up->upba = ubaddr;
559 cmd = (ubaddr >> 8) & 0x300;
560 cmd |= IE|GO|RCOM;
561 up->upcs1 = cmd;
008c0481
BJ
562 return (1);
563}
977c2848
BJ
564
565/*
566 * Reset driver after UBA init.
567 * Cancel software state of all pending transfers
568 * and restart all units and the controller.
569 */
3f3a34c3 570upreset(uban)
977c2848 571{
3f3a34c3
BJ
572 register struct uba_minfo *um;
573 register struct uba_dinfo *ui;
574 register sc21, unit;
5aa9d5ea 575 int any = 0;
3f3a34c3 576
3f3a34c3
BJ
577 for (sc21 = 0; sc21 < NSC21; sc21++) {
578 if ((um = upminfo[sc21]) == 0)
579 continue;
580 if (um->um_ubanum != uban)
581 continue;
582 if (!um->um_alive)
583 continue;
5aa9d5ea
RE
584 if (any == 0) {
585 printf(" up");
586 DELAY(15000000); /* give it time to self-test */
587 any++;
588 }
3f3a34c3
BJ
589 um->um_tab.b_active = 0;
590 um->um_tab.b_actf = um->um_tab.b_actl = 0;
d763a2b7
BJ
591 if (up_softc[um->um_ctlr].sc_info) {
592 printf("<%d>", (up_softc[um->um_ctlr].sc_info>>28)&0xf);
593 ubarelse(um->um_ubanum, &up_softc[um->um_ctlr].sc_info);
3f3a34c3
BJ
594 }
595 ((struct device *)(um->um_addr))->upcs2 = CLR;
596 for (unit = 0; unit < NUP; unit++) {
597 if ((ui = updinfo[unit]) == 0)
598 continue;
599 if (ui->ui_alive == 0)
600 continue;
601 uputab[unit].b_active = 0;
602 (void) upustart(ui);
603 }
604 (void) upstart(um);
977c2848 605 }
977c2848 606}
6a81870e
BJ
607
608/*
609 * Wake up every second and if an interrupt is pending
610 * but nothing has happened increment a counter.
611 * If nothing happens for 20 seconds, reset the controller
612 * and begin anew.
613 */
614upwatch()
615{
3f3a34c3
BJ
616 register struct uba_minfo *um;
617 register sc21, unit;
6a81870e 618
49c84d3f 619 timeout(upwatch, (caddr_t)0, HZ);
3f3a34c3
BJ
620 for (sc21 = 0; sc21 < NSC21; sc21++) {
621 um = upminfo[sc21];
622 if (um->um_tab.b_active == 0) {
623 for (unit = 0; unit < NUP; unit++)
624 if (updinfo[unit]->ui_mi == um &&
625 uputab[unit].b_active)
626 goto active;
627 up_softc[sc21].sc_wticks = 0;
628 continue;
629 }
630 active:
631 up_softc[sc21].sc_wticks++;
632 if (up_softc[sc21].sc_wticks >= 20) {
633 up_softc[sc21].sc_wticks = 0;
634 printf("LOST INTERRUPT RESET");
635 upreset(um->um_ubanum);
636 printf("\n");
637 }
6a81870e
BJ
638 }
639}
0ff318b2
BJ
640
641#define DBSIZE 20
642
643updump(dev)
644 dev_t dev;
645{
646 struct device *upaddr;
647 char *start;
648 int num, blk, unit, nsect, ntrak, nspc;
649 struct size *sizes;
3f3a34c3
BJ
650 register struct uba_regs *uba;
651 register struct uba_dinfo *ui;
0ff318b2 652 register short *rp;
3f3a34c3 653 struct upst *st;
0ff318b2 654
0ff318b2
BJ
655 unit = minor(dev) >> 3;
656 if (unit >= NUP) {
657 printf("bad unit\n");
658 return (-1);
659 }
3f3a34c3
BJ
660#define phys1(cast, addr) ((cast)((int)addr & 0x7fffffff))
661#define phys(cast, addr) phys1(cast, phys1(cast *, &addr))
662 ui = phys(struct uba_dinfo *, updinfo[unit]);
663 if (ui->ui_alive == 0) {
664 printf("dna\n");
665 return(-1);
666 }
667 uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
668#if VAX780
669 if (cpu == VAX_780) {
670 uba->uba_cr = UBA_ADINIT;
671 uba->uba_cr = UBA_IFS|UBA_BRIE|UBA_USEFIE|UBA_SUEFIE;
672 while ((uba->uba_cnfgr & UBA_UBIC) == 0)
673 ;
674 }
675#endif
676 DELAY(1000000);
677 upaddr = (struct device *)ui->ui_physaddr;
678 while ((upaddr->upcs1&DVA) == 0)
679 ;
680 num = maxfree;
681 start = 0;
0ff318b2
BJ
682 upaddr->upcs2 = unit;
683 if ((upaddr->upds & VV) == 0) {
684 upaddr->upcs1 = DCLR|GO;
685 upaddr->upcs1 = PRESET|GO;
686 upaddr->upof = FMT22;
687 }
688 if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) {
689 printf("up !DPR || !MOL\n");
690 return (-1);
691 }
3f3a34c3
BJ
692 st = phys1(struct upst *, &upst[ui->ui_type]);
693 nsect = st->nsect;
694 ntrak = st->ntrak;
695 sizes = phys(struct size *, st->sizes);
0ff318b2 696 if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) {
3f3a34c3 697 printf("oor\n");
0ff318b2
BJ
698 return (-1);
699 }
3f3a34c3 700 nspc = st->nspc;
0ff318b2
BJ
701 while (num > 0) {
702 register struct pte *io;
703 register int i;
704 int cn, sn, tn;
705 daddr_t bn;
706
707 blk = num > DBSIZE ? DBSIZE : num;
3f3a34c3 708 io = uba->uba_map;
0ff318b2 709 for (i = 0; i < blk; i++)
3f3a34c3 710 *(int *)io++ = (btop(start)+i) | (1<<21) | UBA_MRV;
0ff318b2
BJ
711 *(int *)io = 0;
712 bn = dumplo + btop(start);
713 cn = bn/nspc + sizes[minor(dev)&07].cyloff;
714 sn = bn%nspc;
715 tn = sn/nsect;
716 sn = sn%nsect;
717 upaddr->updc = cn;
718 rp = (short *) &upaddr->upda;
719 *rp = (tn << 8) + sn;
720 *--rp = 0;
721 *--rp = -blk*NBPG / sizeof (short);
722 *--rp = GO|WCOM;
723 do {
724 DELAY(25);
725 } while ((upaddr->upcs1 & RDY) == 0);
726 if (upaddr->upcs1&ERR) {
727 printf("up dump dsk err: (%d,%d,%d) cs1=%x, er1=%x\n",
728 cn, tn, sn, upaddr->upcs1, upaddr->uper1);
729 return (-1);
730 }
731 start += blk*NBPG;
732 num -= blk;
733 }
0ff318b2
BJ
734 return (0);
735}
63c35a63 736#endif