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