|
|
1.1 root 1: /*
2: * UNIBUS SMD disk driver
3: *
4: * undone:
5: * Add bad sector forwarding code
6: * Check that offset recovery code works
7: * unibus mapping is suboptimal; if the queue gets long,
8: * buffered data paths will be underused
9: */
10:
11: #include "sys/param.h"
12: #include "sys/buf.h"
13: #include "sys/conf.h"
14: #include "sys/user.h"
15: #include "sys/up.h"
16: #include "sys/ubaddr.h"
17: #include "sys/subaddr.h"
18:
19: #define NOUPSEEK 1 /* because emulex doesn't do it right */
20:
21: /*
22: * hardware registers
23: */
24:
25: struct updevice
26: {
27: u_short upcs1; /* control and status register 1 */
28: short upwc; /* word count register */
29: u_short upba; /* UNIBUS address register */
30: u_short upda; /* desired address register */
31: u_short upcs2; /* control and status register 2 */
32: u_short upds; /* drive status */
33: u_short uper1; /* error register 1 */
34: u_short upas; /* attention summary */
35: u_short upla; /* look ahead */
36: u_short updb; /* data buffer */
37: u_short upmr; /* maintenance */
38: u_short updt; /* drive type */
39: u_short upsn; /* serial number */
40: u_short upof; /* offset register */
41: u_short updc; /* desired cylinder address register */
42: u_short uphr; /* holding register */
43: u_short upmr2; /* maintenance register 2 */
44: u_short uper2; /* error register 2 */
45: u_short upec1; /* burst error bit position */
46: u_short upec2; /* burst error bit pattern */
47: };
48:
49: /*
50: * upcs1
51: */
52:
53: #define UP_SC 0100000 /* special condition */
54: #define UP_TRE 0040000 /* transfer error */
55: #define UP_IE 0000100 /* interrupt enable */
56: #define UP_GO 0000001
57:
58: #define UP_SEEK 004 /* seek */
59: #define UP_RECAL 006 /* recalibrate */
60: #define UP_DCLR 010 /* drive clear */
61: #define UP_OFFSET 014 /* offset */
62: #define UP_RTC 016 /* return to center-line */
63: #define UP_PRESET 020 /* read-in preset */
64: #define UP_SEARCH 030 /* search */
65: #define UP_WCOM 060 /* write */
66: #define UP_RCOM 070 /* read data */
67:
68: /*
69: * upcs2
70: */
71: #define UPCS2_NED 0010000 /* nonexistent drive */
72: #define UPCS2_CLR 0000040 /* controller clear */
73: #define UPCS2_SEL 0000007 /* unit select */
74:
75: /*
76: * upds
77: */
78: #define UPDS_ERR 0040000 /* composite drive error */
79: #define UPDS_PIP 0020000 /* positioning in progress */
80: #define UPDS_MOL 0010000 /* medium on line */
81: #define UPDS_DPR 0000400 /* drive present */
82: #define UPDS_DRY 0000200 /* drive ready */
83: #define UPDS_VV 0000100 /* volume valid */
84: #define UPDS_DREADY (UPDS_DPR|UPDS_DRY|UPDS_MOL|UPDS_VV)
85:
86: /*
87: * uper1
88: */
89: #define UPER1_DCK 0100000 /* data check */
90: #define UPER1_WLE 0004000 /* write lock error */
91: #define UPER1_ECH 0000100 /* ecc hard error */
92:
93: /*
94: * uphr: emulex hack
95: */
96: #define UPHR_MAXCYL 0100027 /* max cyl address */
97: #define UPHR_MAXTRAK 0100030 /* max track address */
98: #define UPHR_MAXSECT 0100031 /* max sector address */
99:
100: /*
101: * upof
102: */
103: #define UPOF_FMT22 0010000 /* 16 bit format */
104: /* THE SC21 ACTUALLY JUST IMPLEMENTS ADVANCE/RETARD... */
105: #define UPOF_P400 0020 /* +400 uinches */
106: #define UPOF_M400 0220 /* -400 uinches */
107: #define UPOF_P800 0040 /* +800 uinches */
108: #define UPOF_M800 0240 /* -800 uinches */
109: #define UPOF_P1200 0060 /* +1200 uinches */
110: #define UPOF_M1200 0260 /* -1200 uinches */
111:
112: #define SECTOR 512 /* size of a hardware sector */
113:
114: /*
115: * monstrous size tables
116: * one per type of drive
117: */
118: struct size
119: {
120: daddr_t nblocks;
121: int cyloff;
122: } up_sizes[8] = {
123: 15884, 0, /* A=cyl 0 thru 26 */
124: 33440, 27, /* B=cyl 27 thru 81 */
125: 495520, 0, /* C=cyl 0 thru 814 */
126: 15884, 562, /* D=cyl 562 thru 588 */
127: 55936, 589, /* E=cyl 589 thru 680 */
128: #ifndef NOBADSECT
129: 81376, 681, /* F=cyl 681 thru 814 */
130: 153728, 562, /* G=cyl 562 thru 814 */
131: #else
132: 81472, 681,
133: 153824, 562,
134: #endif
135: 291346, 82, /* H=cyl 82 thru 561 */
136: }, fj_sizes[8] = {
137: 10240, 0, /* A=cyl 0 thru 31 */
138: 20480, 32, /* B=cyl 32 thru 95 */
139: 232640, 96, /* C=cyl 96 thru 822 */
140: 0, 0,
141: 0, 0,
142: 0, 0,
143: 0, 0,
144: #ifndef NOBADSECT
145: 0, 0, /* H=cyl 155 thru 822 */
146: #else
147: 0, 0,
148: #endif
149: }, fj3_sizes[8] = {
150: 10240, 0, /* A=cyl 0 thru 19 */
151: 20480, 20, /* B=cyl 20 thru 59 */
152: 246784, 60, /* C=cyl 60 thru 541 */
153: 246784, 542, /* D=cyl 542 thru 1024 */
154: 0, 0,
155: 0, 0,
156: 0, 0,
157: #ifndef NOBADSECT
158: 0, 0, /* H=cyl 155 thru 822 */
159: #else
160: 0, 0,
161: #endif
162: }, cd_sizes[8] = {
163: 10240, 0, /* A=cyl 0 thru 63 */
164: 20480, 64, /* B=cyl 64 thru 191 */
165: 100960, 192, /* C=cyl 192 thru 822 */
166: 0, 0,
167: 0, 0,
168: 0, 0,
169: 0, 0,
170: #ifndef NOBADSECT
171: 100960, 0, /* H=cyl 0 thru 630 */
172: #else
173: 100960, 0,
174: #endif
175: }, fj1_sizes[8] = {
176: 1024, 0, /* cyl 0 through 3 */
177: 0, 0,
178: 0, 0,
179: 0, 0,
180: 0, 0,
181: 0, 0,
182: 0, 0,
183: 0, 0,
184: };
185:
186: /*
187: * tables of per-drive info, mostly sizes of things
188: * indexed by magic numbers; see uputype
189: */
190: struct upst upst[] = {
191: 32, 19, 3, 4, 32*19, 823, up_sizes, /* 9300/cdc */
192: /* 9300 actually has 815 cylinders... */
193: 32, 10, 3, 4, 32*10, 823, fj_sizes, /* fujitsu 160m */
194: 32, 5, 3, 4, 32*5, 631, cd_sizes, /* CDC 76 MB */
195: 32, 8, 3, 4, 32*8, 4, fj1_sizes, /* Fixed part of FJ */
196: 32, 16, 3, 4, 32*16, 1024, fj3_sizes, /* fujitsu 330m */
197: };
198:
199: u_char up_offset[16] = {
200: UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400,
201: UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800,
202: UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200,
203: 0, 0, 0, 0
204: };
205:
206: /*
207: * things from config
208: */
209: extern int upcnt, sccnt;
210: extern struct ubaddr scaddr[];
211: extern struct subaddr upaddr[];
212: extern struct scctl scctl[];
213: extern struct updisk updisk[];
214: extern struct buf upbuf[];
215:
216: /*
217: * controller flags, scctl.flags
218: */
219:
220: #define CACTIVE 01 /* xfer in progress */
221: #define CWAITING 02 /* xfering and timer has ticked */
222:
223: /*
224: * unit flags, updisk.flags
225: */
226:
227: #define UACTIVE 01 /* working on this xfer */
228: #define URXFR 02 /* done with any seeking; ready to roll */
229: #define UWOL 04 /* waiting for offline drive */
230: #define UWAITOL 010 /* waiting and timer has ticked */
231:
232: /*
233: * device number
234: */
235:
236: #define UNIT(d) ((minor(d)>>3) & 07)
237: #define PART(d) (minor(d) & 07)
238:
239: /*
240: * abuse of spare bits of struct buf
241: */
242: #define b_cylin b_resid /* for disksort */
243: #define b_ubm av_back /* this buffer's map */
244:
245: int upwstart, upwatch(); /* Have started guardian */
246: int upwaitdry;
247:
248: int upopen(), upstrategy(), upread(), upwrite();
249:
250: struct cdevsw upcdev = cdinit(upopen, nulldev, upread, upwrite, nodev);
251:
252: struct bdevsw upbdev = bdinit(upopen, nulldev, upstrategy, 0);
253:
254: upopen(dev, flag)
255: int dev, flag;
256: {
257: if (upuinit(UNIT(dev)) == 0)
258: u.u_error = ENXIO;
259: }
260:
261: upuinit(unit)
262: register int unit;
263: {
264: register struct updevice *reg;
265: register struct updisk *up;
266: register struct subaddr *ua;
267:
268: if (unit < 0 || unit > upcnt)
269: return (0);
270: ua = &upaddr[unit];
271: if (ua->ctl < 0)
272: return (0);
273: up = &updisk[unit];
274: if (up->ctl)
275: return (1);
276: if (upcinit(ua->ctl) == 0)
277: return (0);
278: reg = scctl[ua->ctl].addr;
279: if ((up->type = uputype(reg, ua->unit)) < 0) {
280: printf("up%d absent or bad type\n", unit);
281: return (0);
282: }
283: up->unit = ua->unit;
284: up->ctl = &scctl[ua->ctl];
285: up->ctl->drives[ua->unit] = up;
286: return (1);
287: }
288:
289:
290: /*
291: * determine drive type
292: * very emulex dependent; should look at drive type register too.
293: * perhaps there should be a way to change it?
294: * this is called by updump too;
295: * be prepared to run without memory management
296: * unit is the hardware unit
297: * return is an index into upst
298: */
299: int
300: uputype(reg, unit)
301: register struct updevice *reg;
302: int unit;
303: {
304:
305: reg->upcs1 = 0; /* conservative */
306: reg->upcs2 = unit;
307: if (reg->upcs2&UPCS2_NED) {
308: reg->upcs1 = UP_DCLR|UP_GO;
309: return (-1);
310: }
311: reg->uphr = UPHR_MAXTRAK;
312: switch (reg->uphr) {
313: default:
314: reg->upcs1 = UP_DCLR|UP_GO;
315: return (-1);
316: case 9:
317: return (unit >= 4 ? 3 : 1); /* fujitsu hack */
318: case 4:
319: return (2); /* CDC 76MB hack */
320: case 7:
321: return (3); /* Fixed Fujitsu hack */
322: case 15:
323: return (4); /* fuji 330m hack */
324: case 19:
325: return (0); /* CDC 300 MB hack */
326: }
327: }
328:
329: upcinit(ctl)
330: int ctl;
331: {
332: register struct scctl *sc;
333: register struct updevice *reg;
334:
335: if (ctl < 0 || ctl >= sccnt)
336: return (0);
337: sc = &scctl[ctl];
338: if (sc->addr)
339: return (1);
340: if ((reg = (struct updevice *)ubaddr(&scaddr[ctl])) == 0
341: || ubbadaddr(scaddr[ctl].ubno, ®->upcs1, sizeof(short))) {
342: printf("sc%d absent\n", ctl);
343: return (0);
344: }
345: reg->upcs2 = UPCS2_CLR;
346: sc->addr = reg;
347: sc->ubno = scaddr[ctl].ubno;
348: if (upwstart == 0) {
349: timeout(upwatch, (caddr_t)0, HZ);
350: upwstart++;
351: }
352: return (1);
353: }
354:
355: upstrategy(bp)
356: register struct buf *bp;
357: {
358: register struct updisk *up;
359: register struct upst *st;
360: register int unit;
361: register int part;
362: long sz;
363: int s;
364:
365: sz = (bp->b_bcount+SECTOR-1)/SECTOR;
366: unit = UNIT(bp->b_dev);
367: up = &updisk[unit];
368: if (up->ctl == 0) {
369: bp->b_flags |= B_ERROR;
370: iodone(bp);
371: return;
372: }
373: st = &upst[up->type];
374: part = PART(bp->b_dev);
375: if (bp->b_blkno < 0 || bp->b_blkno+sz > st->sizes[part].nblocks) {
376: if (bp->b_blkno == st->sizes[part].nblocks)
377: bp->b_resid = bp->b_bcount;
378: else { /* partial read too hard for now */
379: bp->b_error = ENXIO;
380: bp->b_flags |= B_ERROR;
381: }
382: iodone(bp);
383: return;
384: }
385: bp->b_cylin = bp->b_blkno/st->nspc + st->sizes[part].cyloff;
386: bp->b_ubm = (struct buf *)ubmbuf(up->ctl->ubno, bp, USLP);
387: s = spl6();
388: disksort(&up->actf, &up->actl, bp);
389: if ((up->flags & UACTIVE) == 0) {
390: upustart(up);
391: if (up->ctl->actf && (up->ctl->flags & CACTIVE) == 0)
392: upstart(up->ctl);
393: }
394: splx(s);
395: }
396:
397: /*
398: * unit start:
399: * if there's a block for this drive, start seeking there
400: *
401: * up->upcs = UP_IE cancels a pending command in the SC21
402: * why not up->cs |= UP_IE?
403: */
404: upustart(up)
405: register struct updisk *up;
406: {
407: register struct buf *bp;
408: register struct updevice *reg;
409: register struct scctl *sc;
410: register struct upst *st;
411: int sn, csn;
412: int didie = 0;
413:
414: sc = up->ctl;
415: if ((bp = up->actf) == NULL)
416: return (0);
417: #ifndef NOUPSEEK
418: if (sc->flags & CACTIVE) { /* can't start seek till xfer done */
419: sc->softas |= 1<<up->unit;
420: return (0);
421: }
422: #endif
423: reg = sc->addr;
424: reg->upcs2 = up->unit;
425: if ((reg->upds & UPDS_VV) == 0) {
426: reg->upcs1 = UP_IE|UP_DCLR|UP_GO;
427: reg->upcs1 = UP_IE|UP_PRESET|UP_GO;
428: reg->upof = UPOF_FMT22;
429: didie = 1;
430: }
431: if ((reg->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) {
432: up->flags |= UWOL;
433: return (didie);
434: }
435: if ((up->flags & UACTIVE) == 0) { /* start seek if didn't already */
436: up->flags |= UACTIVE;
437: #ifndef NOUPSEEK
438: st = &upst[up->type];
439: sn = bp->b_blkno%st->nspc;
440: sn = (sn + st->nsect - st->sdist) % st->nsect; /* sector to seek to */
441: csn = sn - (reg->upla>>6);
442: if (csn < 0)
443: csn += st->nsect;
444: if (bp->b_cylin != reg->updc /* seek if off cylinder */
445: || csn > st->rdist) { /* or not close enough */
446: reg->updc = bp->b_cylin;
447: reg->upda = sn;
448: reg->upcs1 = UP_IE|UP_SEARCH|UP_GO;
449: return (1);
450: }
451: #endif
452: }
453: if ((up->flags & URXFR) == 0) { /* seek done, put on ctl queue */
454: up->next = NULL;
455: if (sc->actf == NULL)
456: sc->actf = up;
457: else
458: sc->actl->next = up;
459: sc->actl = up;
460: up->flags |= URXFR;
461: }
462: return (didie);
463: }
464:
465: /*
466: * Start up a transfer on a drive.
467: */
468: upstart(sc)
469: register struct scctl *sc;
470: {
471: register struct buf *bp;
472: register struct updisk *up;
473: register struct updevice *reg;
474: register struct upst *st;
475: register c;
476: uaddr_t uad;
477: int sn, tn;
478:
479: loop:
480: if ((up = sc->actf) == NULL)
481: return (0);
482: if ((bp = up->actf) == NULL) {
483: sc->actf = up->next;
484: goto loop;
485: }
486: sc->flags |= CACTIVE;
487: st = &upst[up->type];
488: sn = bp->b_blkno%st->nspc;
489: tn = sn/st->nsect;
490: sn %= st->nsect;
491: reg = sc->addr;
492: reg->upcs2 = up->unit;
493: c = 0;
494: while ((reg->upds&UPDS_DRY) == 0) {
495: if (++c > 512)
496: break;
497: upwaitdry++;
498: }
499: if ((reg->upds & UPDS_DREADY) != UPDS_DREADY) {
500: printf("up%d: not ready", UNIT(bp->b_dev));
501: if ((reg->upds & UPDS_DREADY) != UPDS_DREADY) {
502: printf("\n");
503: sc->flags &=~ (CACTIVE|CWAITING);
504: sc->errcnt = 0;
505: up->actf = bp->av_forw;
506: up->flags &=~ (UACTIVE|URXFR);
507: bp->b_flags |= B_ERROR;
508: iodone(bp);
509: goto loop;
510: }
511: printf(" (flakey)\n"); /* inscrutable */
512: }
513: reg->updc = bp->b_cylin;
514: reg->upda = (tn << 8) + sn;
515: reg->upwc = -bp->b_bcount / sizeof(short);
516: if (bp->b_flags & B_READ)
517: c = UP_IE|UP_RCOM|UP_GO;
518: else
519: c = UP_IE|UP_WCOM|UP_GO;
520: bp->b_ubm = (struct buf *)ubinspath(ubmapath(sc->ubno), (ubm_t)bp->b_ubm);
521: uad = ubadbuf(sc->ubno, bp, (ubm_t)bp->b_ubm);
522: reg->upba = uad;
523: reg->upcs1 = c|((uad>>8)&0x300);
524: return (1);
525: }
526:
527: /*
528: * Handle a disk interrupt.
529: */
530: sc0int(ctl)
531: int ctl;
532: {
533: register struct updevice *reg;
534: register struct scctl *sc;
535: register struct updisk *up;
536: register struct buf *bp;
537: register int unit, i, as;
538: int needie;
539:
540: if (ctl < 0 || ctl >= sccnt) {
541: printf("sc%d bad intr\n");
542: return;
543: }
544: sc = &scctl[ctl];
545: if ((reg = sc->addr) == 0) {
546: printf("sc%d: stray intr\n");
547: return;
548: }
549: needie = 1;
550: as = (reg->upas & 0377) | sc->softas;
551: sc->softas = 0;
552: if ((sc->flags & CACTIVE) == 0) { /* must be a seek */
553: if (reg->upcs1 & UP_TRE)
554: reg->upcs1 = UP_TRE;
555: goto doattn;
556: }
557: up = sc->actf;
558: bp = up->actf;
559: reg->upcs2 = up->unit;
560: if ((reg->upds&UPDS_ERR) || (reg->upcs1&UP_TRE)) {
561: i = 0;
562: while ((reg->upds & UPDS_DRY) == 0) {
563: if (++i > 512)
564: break;
565: upwaitdry++;
566: }
567: if (reg->uper1&UPER1_WLE) {
568: printf("up%d: write locked\n", UNIT(bp->b_dev));
569: bp->b_flags |= B_ERROR;
570: } else if (++sc->errcnt > 27) {
571: harderr(bp, "up");
572: printf("cs2=%o er1=%o er2=%o\n",
573: reg->upcs2&0177777, reg->uper1&0177777, reg->uper2&0177777);
574: bp->b_flags |= B_ERROR;
575: } else {
576: /*
577: * soft ecc, try to correct
578: */
579: sc->flags &=~ (CACTIVE|CWAITING); /* force retry */
580: if ((reg->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK)
581: if (upecc(up))
582: return; /* probably wrong */
583: }
584: /*
585: * `hard' error. clear and try again
586: */
587: reg->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
588: needie = 0;
589: if ((sc->errcnt&07) == 4 && (sc->flags & CACTIVE) == 0) {
590: reg->upcs1 = UP_RECAL|UP_IE|UP_GO;
591: sc->recal = 0;
592: goto nextrecal;
593: }
594: }
595: /*
596: * Advance recalibration finite state machine
597: * if recalibrate in progress, through
598: * RECAL
599: * SEEK
600: * OFFSET (optional)
601: * RETRY
602: */
603: switch (sc->recal) {
604: case 1:
605: reg->updc = bp->b_cylin;
606: reg->upcs1 = UP_SEEK|UP_IE|UP_GO;
607: goto nextrecal;
608: case 2:
609: if (sc->errcnt < 16 || (bp->b_flags&B_READ) == 0)
610: goto donerecal;
611: reg->upof = up_offset[sc->errcnt & 017] | UPOF_FMT22;
612: reg->upcs1 = UP_IE|UP_OFFSET|UP_GO;
613: nextrecal:
614: sc->recal++;
615: sc->flags |= CACTIVE;
616: return;
617:
618: donerecal:
619: case 3:
620: sc->recal = 0;
621: sc->flags &=~ CACTIVE;
622: break;
623: }
624: if (sc->flags & CACTIVE) { /* `active' means we're done */
625: if (sc->errcnt >= 16) {
626: reg->upof = UPOF_FMT22;
627: reg->upcs1 = UP_RTC|UP_GO|UP_IE;
628: while (reg->upds & UPDS_PIP)
629: DELAY(25);
630: needie = 0;
631: }
632: sc->flags &=~ (CACTIVE|CWAITING);
633: sc->errcnt = 0;
634: sc->actf = up->next;
635: up->flags &=~ (UACTIVE|URXFR);
636: up->actf = bp->av_forw;
637: bp->b_resid = (-reg->upwc * sizeof(short));
638: ubmfree(sc->ubno, (ubm_t)bp->b_ubm);
639: iodone(bp);
640: if (up->actf)
641: if (upustart(up))
642: needie = 0;
643: }
644: as |= reg->upas;
645: as &= ~(1<<up->unit);
646: doattn:
647: /*
648: * Process other units which need attention.
649: */
650: for (unit = 0, i = 1; unit < NSCUP && as; i <<= 1, unit++) {
651: if ((as & i) == 0)
652: continue;
653: as &= ~i;
654: reg->upas = i;
655: if ((up = sc->drives[unit]) != NULL && upustart(up))
656: needie = 0;
657: }
658: if (sc->actf && (sc->flags & CACTIVE) == 0)
659: if (upstart(sc))
660: needie = 0;
661: if (needie)
662: reg->upcs1 = UP_IE; /* why bother? */
663: }
664:
665: upread(dev)
666: dev_t dev;
667: {
668: physio(upstrategy, &upbuf[UNIT(dev)], dev, B_READ, minphys);
669: }
670:
671: upwrite(dev)
672: dev_t dev;
673: {
674: physio(upstrategy, &upbuf[UNIT(dev)], dev, B_WRITE, minphys);
675: }
676:
677: /*
678: * correct an ECC error and restart the transfer
679: * the error is (upec1-1) bits into the current sector;
680: * at that point, the bits set in upec2 are wrong.
681: *
682: * should be able just to set the GO bit and proceed,
683: * but emulex insists we do DCLR first, or so the book says,
684: * because DCK sets ERR in upds
685: */
686: upecc(up)
687: register struct updisk *up;
688: {
689: register struct updevice *reg;
690: register struct scctl *sc;
691: register struct buf *bp;
692: register int i;
693: int nxf;
694: unsigned int mask;
695: uaddr_t uad, lastua;
696: int xc, xa;
697:
698: if ((bp = up->actf) == NULL || (sc = up->ctl) == NULL)
699: panic("upecc");
700: reg = sc->addr;
701: ubmflush(sc->ubno, ubmpath((ubm_t)bp->b_ubm));
702: lastua = reg->upba + ((reg->upcs1&0x300)<<8);
703: nxf = bp->b_bcount + (reg->upwc * sizeof(short));
704: i = reg->upec1 - 1; /* -1 makes 0 origin */
705: uad = lastua - (nxf > SECTOR ? SECTOR : nxf) + ((i&~07)>>3);
706: mask = reg->upec2;
707: mask <<= i&07;
708: for (; uad < lastua && mask; mask >>= 8, uad++)
709: ubputc(sc->ubno, uad, ubgetc(sc->ubno, uad)^mask);
710: printf("up%d%o: soft ecc sec %ld\n", UNIT(bp->b_dev), PART(bp->b_dev),
711: bp->b_blkno + nxf/SECTOR - 1);
712: sc->flags |= CACTIVE; /* either complete or continuing */
713: if (reg->upwc == 0)
714: return (0);
715: #ifdef notdef
716: reg->uper1 = 0;
717: reg->upcs1 |= UP_GO;
718: #else /* clear wretched emulex error */
719: xc = reg->updc;
720: xa = reg->upda;
721: /* ba, wc undisturbed by DCLR */
722: reg->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
723: reg->updc = xc;
724: reg->upda = xa;
725: reg->upba = lastua;
726: i = (lastua >> 8) & 0x300;
727: i |= UP_IE|UP_GO|UP_RCOM;
728: reg->upcs1 = i;
729: #endif
730: return (1);
731: }
732:
733: /*
734: * check for offline drives and hung controllers
735: */
736:
737: upwatch()
738: {
739: register struct scctl *sc;
740: register struct updisk *up;
741: register struct updevice *reg;
742: register struct buf *bp;
743: register int ounit;
744: register int s;
745:
746: s = spl6();
747: timeout(upwatch, (caddr_t)0, 15*HZ);
748: for (up = &updisk[upcnt-1]; up >= updisk; up--) {
749: if ((up->flags & UWOL) == 0)
750: continue;
751: reg = up->ctl->addr;
752: ounit = reg->upcs2 & UPCS2_SEL;
753: reg->upcs2 = up->unit;
754: if ((reg->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) {
755: if ((up->flags & UWAITOL) == 0) {
756: up->flags |= UWAITOL;
757: reg->upcs2 = ounit;
758: continue;
759: }
760: printf("up%d offline\n", up - updisk);
761: while ((bp = up->actf) != NULL) {
762: bp->b_flags |= B_ERROR;
763: up->actf = bp->av_forw;
764: ubmfree(up->ctl->ubno, (ubm_t)bp->b_ubm);
765: iodone(bp);
766: }
767: }
768: up->flags &=~ (UWAITOL|UWOL);
769: upustart(up);
770: reg->upcs2 = ounit;
771: }
772: for (sc = &scctl[sccnt-1]; sc >= scctl; sc--) {
773: if (sc->flags & CACTIVE) {
774: if ((sc->flags & CWAITING) == 0)
775: sc->flags |= CWAITING;
776: else {
777: sc->addr->upcs2 = UPCS2_CLR;
778: printf("sc%d hung, kicked\n", sc - scctl);
779: sc->flags &=~ (CWAITING|CACTIVE);
780: }
781: }
782: if (sc->actf && (sc->flags & CACTIVE) == 0)
783: upstart(sc);
784: }
785: splx(s);
786: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.