|
|
1.1 root 1: /*
2: * MASSBUS SMD disk driver
3: */
4:
5: #include "sys/param.h"
6: #include "sys/buf.h"
7: #include "sys/conf.h"
8: #include "sys/dir.h"
9: #include "sys/user.h"
10: #include "sys/hp.h"
11: #include "sys/mbaddr.h"
12: #include "sys/mbsts.h"
13: #include "sys/bad144.h"
14:
15: /*
16: * hardware registers
17: */
18:
19: struct hpdevice {
20: int hpcs1; /* control and status register 1 */
21: int hpds; /* drive status */
22: int hper1; /* error register 1 */
23: int hpmr; /* maintenance */
24: int hpas; /* attention summary */
25: int hpda; /* desired address register */
26: int hpdt; /* drive type */
27: int hpla; /* look ahead */
28: int hpsn; /* serial number */
29: int hpof; /* offset register */
30: int hpdc; /* desired cylinder address register */
31: int hpcc; /* current cylinder */
32: /* on an rp drive, mr2 is called er2 and er2 is called er3 */
33: /* we use rm terminology here */
34: int hpmr2; /* maintenance register 2 */
35: int hper2; /* error register 2 */
36: int hpec1; /* burst error bit position */
37: int hpec2; /* burst error bit pattern */
38: };
39:
40: /*
41: * hpcs1
42: */
43:
44: #define HP_GO 0000001
45:
46: #define HP_SEEK 004 /* seek */
47: #define HP_RECAL 006 /* recalibrate */
48: #define HP_DCLR 010 /* drive clear */
49: #define HP_OFFSET 014 /* offset */
50: #define HP_RTC 016 /* return to center-line */
51: #define HP_PRESET 020 /* read-in preset */
52: #define HP_SEARCH 030 /* search */
53: #define HP_WCOM 060 /* write */
54: #define HP_RCOM 070 /* read data */
55:
56: /*
57: * hpds
58: */
59: #define HPDS_ERR 0040000 /* composite drive error */
60: #define HPDS_PIP 0020000 /* positioning in progress */
61: #define HPDS_MOL 0010000 /* medium on line */
62: #define HPDS_DPR 0000400 /* drive present */
63: #define HPDS_DRY 0000200 /* drive ready */
64: #define HPDS_VV 0000100 /* volume valid */
65: #define HPDS_DREADY (HPDS_DPR|HPDS_DRY|HPDS_MOL|HPDS_VV)
66:
67: /*
68: * hper1
69: */
70: #define HPER1_DCK 0100000 /* data check */
71: #define HPER1_WLE 0004000 /* write lock error */
72: #define HPER1_ECH 0000100 /* ecc hard error */
73: #define HPER1_FER 0000020 /* format error */
74:
75: /*
76: * hpdt
77: */
78: #define HPDT_TYPE 0x1ff
79: #define HPDT_RP05 021
80: #define HPDT_RP06 022
81: #define HPDT_RP07 042
82: #define HPDT_RM03 024
83: #define HPDT_RM05 027
84: #define HPDT_FUJI 025
85:
86: /*
87: * hpcc: emulex hack
88: */
89: #define HPHR_MAXCYL 0100027 /* max cyl address */
90: #define HPHR_MAXTRAK 0100030 /* max track address */
91: #define HPHR_MAXSECT 0100031 /* max sector address */
92:
93: /*
94: * hpof
95: */
96: #define HPOF_FMT22 0010000 /* 16 bit format */
97: #define HPOF_P400 0020 /* +400 uinches */
98: #define HPOF_M400 0220 /* -400 uinches */
99: #define HPOF_P800 0040 /* +800 uinches */
100: #define HPOF_M800 0240 /* -800 uinches */
101: #define HPOF_P1200 0060 /* +1200 uinches */
102: #define HPOF_M1200 0260 /* -1200 uinches */
103:
104: /*
105: * hper2
106: */
107: #define HPER2_BSE 0100000 /* bad sector */
108:
109: #define SECTOR 512 /* size of a hardware sector */
110:
111: /*
112: * monstrous size tables
113: * one per type of drive
114: */
115: struct size
116: {
117: daddr_t nblocks;
118: int cyloff;
119: };
120: struct size hp6_sizes[8] = {
121: 15884, 0, /* A=cyl 0 thru 37 */
122: 33440, 38, /* B=cyl 38 thru 117 */
123: 340670, 0, /* C=cyl 0 thru 814 */
124: 0, 0,
125: 0, 0,
126: 0, 0,
127: #ifndef NOBADSECT
128: 291280, 118, /* G=cyl 118 thru 814 */
129: #else
130: 291346, 118,
131: #endif
132: 0, 0,
133: };
134: struct size rm3_sizes[8] = {
135: 15884, 0, /* A=cyl 0 thru 99 */
136: 33440, 100, /* B=cyl 100 thru 309 */
137: 131680, 0, /* C=cyl 0 thru 822 */
138: 0, 0,
139: 0, 0,
140: 0, 0,
141: #ifndef NOBADSECT
142: 81984, 310, /* G=cyl 310 thru 822 */
143: #else
144: 82080, 310,
145: #endif
146: 113280, 115, /* H=cyl 115 thru 708 -- ex 32v */
147: };
148: struct size rm5_sizes[8] = {
149: 15884, 0, /* A=cyl 0 thru 26 */
150: 33440, 27, /* B=cyl 27 thru 81 */
151: 500384, 0, /* C=cyl 0 thru 822 */
152: 15884, 562, /* D=cyl 562 thru 588 */
153: 55936, 589, /* E=cyl 589 thru 680 */
154: #ifndef NOBADSECT
155: 86240, 681, /* F=cyl 681 thru 822 */
156: 158592, 562, /* G=cyl 562 thru 822 */
157: #else
158: 86636, 681,
159: 158688, 562,
160: #endif
161: 291346, 82, /* H=cyl 82 thru 561 */
162: };
163: struct size mfj_sizes[8] = {
164: 10240, 0, /* A=cyl 0 thru 31 */
165: 20480, 32, /* B=cyl 32 thru 95 */
166: 232640, 96, /* C=cyl 96 thru 822 */
167: 0, 0,
168: 0, 0,
169: 0, 0,
170: 0, 0,
171: 0, 0,
172: };
173: struct size eagle_sizes[8] ={
174: 27520, 0, /* A=cyl 0 thru 31 */
175: 27520, 32, /* B=cyl 32 thru 63 */
176: 667360, 64, /* C=cyl 64 thru 839 */
177: 232640, 64, /* D=cyl 64 thru 340 (partial) */
178: 232640, 341, /* E=cyl 341 thru 617 (partial) */
179: 0, 0,
180: 0, 0,
181: 0, 0,
182: };
183: /* 48 sector Emulex Eagle */
184: struct size eag48_sizes[8] = { /* cyl 841 used for bad sectors + info */
185: #ifndef OLDPART
186: 11*960, 0, /* A = cyl 0 thru 10 for / */
187: 22*960, 11, /* B = cyl 11 thru 32 for swap */
188: 842*960, 0, /* C = all cyl 0 thru 841 for testing */
189: 16*960, 33, /* D = cyl 33 thru 48 for /usr/guest */
190: 66*960, 49, /* E = cyl 49 thru 114 for /usr/src */
191: 242*960,115, /* F = cyl 115 thru 356 nearly 1/3 */
192: 242*960,357, /* G = cyl 357 thru 598 nearly 1/3 */
193: 242*960,599, /* H = cyl 599 thru 840 nearly 1/3 */
194: #else /* old jones partitions */
195: 45*960, 0, /* A = cyl 0 thru 44 for /tmp */
196: 64*960, 45, /* B = cyl 45 thru 108 for swap */
197: 842*960, 0, /* C = all cyl 0 thru 841 for testing */
198: 244*960,109, /* D = cyl 109 thru 352 nearly 1/3 */
199: 244*960,353, /* E = cyl 353 thru 596 nearly 1/3 */
200: 244*960,597, /* F = cyl 597 thru 840 nearly 1/3 */
201: 0, 0, /* G = cyl 0 thru 402 nearly 1/2 */
202: 0, 0, /* H = cyl 438 thru 840 nearly 1/2 */
203: #endif
204: };
205: struct size hp7_sizes[8] = {
206: 15884, 0, /* A=cyl 0 thru 9 */
207: 64000, 10, /* B=cyl 10 thru 49 */
208: 1008000,0, /* C=cyl 0 thru 629 */
209: 504000, 0, /* D=cyl 0 thru 314 */
210: 504000, 315, /* E=cyl 315 thru 629 */
211: 928000, 50, /* F=cyl 50 thru 629 */
212: 0, 0,
213: 0, 0,
214: };
215:
216: /*
217: * tables of per-drive info, mostly sizes of things
218: * indexed by numbers in hptypes
219: */
220:
221: struct hptype hptype[] = {
222: HPDT_RM03, 32, 5, 3, 4, 32*5, 823, rm3_sizes, /* RM03 */
223: HPDT_RM05, 32, 19, 2, 3, 32*19, 823, rm5_sizes, /* RM05 */
224: HPDT_RP06, 22, 19, 2, 3, 22*19, 815, hp6_sizes, /* RP06 */
225: HPDT_RP05, 22, 19, 2, 3, 22*19, 411, hp6_sizes, /* RP05 */
226: HPDT_RP07, 50, 32, 2, 3, 50*32, 630, hp7_sizes, /* RP07 */
227: /* HPDT_FUJI (emulex) entries must be contiguous and last */
228: HPDT_FUJI, 32, 10, 2, 3, 32*10, 823, mfj_sizes, /* little fujitsu */
229: HPDT_FUJI, 43, 20, 8, 9, 43*20, 842, eagle_sizes, /* eagle */
230: HPDT_FUJI, 48, 20, 8, 9, 48*20, 842, eag48_sizes, /* eagle 48 sectors */
231: 0
232: };
233:
234: #define NOFFS 16
235: unsigned char hp_offset[NOFFS] = {
236: HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400,
237: HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800,
238: HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200,
239: 0, 0, 0, 0
240: };
241:
242: /*
243: * things from config
244: */
245: extern int hpcnt;
246: extern struct mbaddr hpaddr[];
247: extern struct hpdisk hpdisk[];
248: extern struct buf hpbuf[];
249: extern struct buf hpbadbuf[];
250: extern struct bad144 hpbad[];
251:
252: /*
253: * unit flags, hpdisk.flags
254: */
255:
256: #define UACTIVE 01 /* started seek */
257: #define UXFER 02 /* done with any seeking; ready to transfer */
258: #define UWOL 04 /* waiting for offline drive */
259: #define UWAITOL 010 /* waiting and timer has ticked */
260: #define UHAVBAD 020 /* have read bad block table */
261: #define UREVEC 040 /* halfway through reading revectored sector */
262:
263: /*
264: * device number
265: */
266:
267: #define UNIT(d) ((minor(d)>>3) & 07)
268: #define PART(d) (minor(d) & 07)
269:
270: /*
271: * abuse of spare bits of struct buf
272: */
273: #define b_cylin b_resid /* for disksort */
274:
275: int hpwstart;
276: int hpwatch();
277: int hpwaitdry;
278:
279: int hpopen(), hpstrategy(), hpread(), hpwrite();
280: struct cdevsw hpcdev = cdinit(hpopen, nulldev, hpread, hpwrite, nodev);
281: struct bdevsw hpbdev = bdinit(hpopen, nulldev, hpstrategy, 0);
282:
283: hpopen(dev, flag)
284: int dev, flag;
285: {
286: if (hpuinit(UNIT(dev)) == 0)
287: u.u_error = ENXIO;
288: }
289:
290: static char hponce;
291:
292: hpuinit(unit)
293: register int unit;
294: {
295: register struct hpdevice *reg;
296: register struct hpdisk *hp;
297:
298: if (unit < 0 || unit > hpcnt)
299: return (0);
300: hp = &hpdisk[unit];
301: if (hp->addr)
302: return (1);
303: if ((reg = (struct hpdevice *)mbaddr(&hpaddr[unit])) == NULL
304: || badaddr(®->hpcs1, sizeof(long))
305: || (reg->hpds & HPDS_DPR) == 0) {
306: printf("hp%d absent\n", unit);
307: return (0);
308: }
309: if ((hp->type = hputype(reg)) < 0) {
310: printf("hp%d absent or bad type\n", unit);
311: return (0);
312: }
313: hp->addr = reg;
314: if (hponce == 0) {
315: hponce++;
316: hpwatch();
317: }
318: return (1);
319: }
320:
321: /*
322: * determine drive type
323: * this is called by hpdump too;
324: * be prepared to run without memory management
325: * return is an index into hpst
326: */
327: int
328: hputype(reg)
329: register struct hpdevice *reg;
330: {
331: register int t, i;
332: register int nsect, ntrak;
333:
334: t = reg->hpdt & HPDT_TYPE;
335: for (i = 0; hptype[i].type; i++)
336: if (hptype[i].type == t)
337: break;
338: if (hptype[i].type == 0) {
339: printf("hp type 0%o unknown\n", t);
340: return (-1);
341: }
342: if (hptype[i].type != HPDT_FUJI)
343: return (i);
344: /*
345: * special hackery for emulex
346: */
347: reg->hpcc = HPHR_MAXTRAK;
348: DELAY(2); /* hack */
349: ntrak = reg->hpcc + 1;
350: ntrak &= 0xffff;
351: reg->hpcc = HPHR_MAXSECT;
352: DELAY(2); /* hack */
353: nsect = reg->hpcc + 1;
354: nsect &= 0xffff;
355: for (; hptype[i].type; i++)
356: if (ntrak == hptype[i].ntrak && nsect == hptype[i].nsect)
357: return (i);
358: /*
359: * 48-sector eagle known to be last,
360: * so the following broken-hardware test might work
361: */
362: if (nsect == 46) {
363: printf("hp said ntrak %d nsect %d, eag48 assumed\n", ntrak, nsect);
364: return (i - 1);
365: }
366: printf("hp fuji ntrak %d nsect %d unknown\n", ntrak, nsect);
367: return (-1);
368: }
369:
370: /*
371: * a subtlety:
372: * b_cylin = cylinder number;
373: * later, when computing disk address,
374: * we use b_cylin, and take b_blkno % cylindersize
375: * i.e. there's an embedded assumption that every disk partition
376: * begins on a cylinder boundary
377: */
378: hpstrategy(bp)
379: register struct buf *bp;
380: {
381: register struct hpdisk *hp;
382: register struct hptype *st;
383: register int unit;
384: register int part;
385: long sz;
386: int s;
387:
388: sz = (bp->b_bcount+SECTOR-1)/SECTOR;
389: unit = UNIT(bp->b_dev);
390: hp = &hpdisk[unit];
391: if (hp->addr == NULL) { /* safety check */
392: bp->b_flags |= B_ERROR;
393: iodone(bp);
394: return;
395: }
396: st = &hptype[hp->type];
397: part = PART(bp->b_dev);
398: if (bp->b_blkno < 0 || bp->b_blkno+sz > st->sizes[part].nblocks) {
399: if (bp->b_blkno == st->sizes[part].nblocks)
400: bp->b_resid = bp->b_bcount;
401: else { /* partial read too hard for now */
402: bp->b_error = ENXIO;
403: bp->b_flags |= B_ERROR;
404: }
405: iodone(bp);
406: return;
407: }
408: bp->b_cylin = bp->b_blkno/st->nspc + st->sizes[part].cyloff;
409: s = spl6();
410: disksort(&hp->actf, &hp->actl, bp);
411: if ((hp->flags & UACTIVE) == 0)
412: hpustart(hp);
413: splx(s);
414: }
415:
416: /*
417: * unit start:
418: * if there's a block for this drive, start seeking there
419: */
420: int hpxfer();
421:
422: hpustart(hp)
423: register struct hpdisk *hp;
424: {
425: register struct buf *bp;
426: register struct hpdevice *reg;
427: register struct hptype *st;
428: int sn, csn;
429:
430: if ((bp = hp->actf) == NULL)
431: return;
432: reg = hp->addr;
433: if ((reg->hpds & HPDS_VV) == 0) {
434: reg->hpcs1 = HP_DCLR|HP_GO;
435: reg->hpcs1 = HP_PRESET|HP_GO;
436: reg->hpof = HPOF_FMT22;
437: hp->flags &=~ UHAVBAD;
438: }
439: if ((hp->flags & UHAVBAD) == 0) {
440: hprbad(hp);
441: bp = hp->actf;
442: hp->flags |= UHAVBAD;
443: }
444: if ((reg->hpds & (HPDS_DPR|HPDS_MOL)) != (HPDS_DPR|HPDS_MOL)) {
445: hp->flags |= UWOL;
446: return;
447: }
448: if ((hp->flags & UACTIVE) == 0) { /* start seek if didn't already */
449: hp->flags |= UACTIVE;
450: st = &hptype[hp->type];
451: sn = bp->b_blkno%st->nsect - st->sdist; /* seek here before io */
452: if (sn < 0)
453: sn += st->nsect;
454: csn = sn - (reg->hpla>>6);
455: if (csn < 0)
456: csn += st->nsect;
457: if (bp->b_cylin != reg->hpdc /* seek if off cylinder */
458: || csn > st->rdist) { /* or not close enough */
459: reg->hpdc = bp->b_cylin;
460: reg->hpda = sn;
461: reg->hpcs1 = HP_SEARCH|HP_GO;
462: return;
463: }
464: }
465: if ((hp->flags & UXFER) == 0) { /* seek done, time for transfer */
466: hp->flags |= UXFER;
467: mbstart(&hpaddr[UNIT(bp->b_dev)], bp, hpxfer);
468: }
469: }
470:
471: /*
472: * start transfer
473: */
474: hpxfer(bp)
475: register struct buf *bp;
476: {
477: register struct hpdisk *hp;
478: register struct hpdevice *reg;
479: register struct hptype *st;
480: int sn, tn;
481:
482: hp = &hpdisk[UNIT(bp->b_dev)];
483: st = &hptype[hp->type];
484: sn = bp->b_blkno%st->nspc;
485: tn = sn/st->nsect;
486: sn %= st->nsect;
487: reg = hp->addr;
488: if ((reg->hpds & HPDS_DREADY) != HPDS_DREADY) {
489: printf("hp%d: not ready\n", UNIT(bp->b_dev));
490: hp->errcnt = 0;
491: hp->actf = bp->av_forw;
492: hp->flags &=~ (UACTIVE|UXFER);
493: bp->b_flags |= B_ERROR;
494: iodone(bp);
495: return;
496: }
497: reg->hpdc = bp->b_cylin;
498: reg->hpda = (tn << 8) + sn;
499: if (bp->b_flags & B_READ)
500: reg->hpcs1 = HP_RCOM|HP_GO;
501: else
502: reg->hpcs1 = HP_WCOM|HP_GO;
503: }
504:
505: /*
506: * interrupt, passed from MBA code
507: */
508: hp0int(unit, mbsr, mbbc, attn)
509: int unit, mbsr, mbbc, attn;
510: {
511: register struct hpdisk *hp;
512:
513: hp = &hpdisk[unit];
514: if (hp->addr == 0) {
515: if (hpuinit(unit) == 0) {
516: printf("hp%d: hopeless interrupt\n", unit);
517: return; /* but ATTN wasn't cleared; will recur */
518: }
519: /* init ok, so addr nonzero, so can clear it */
520: }
521: hp->addr->hpas = attn;
522: if (hp->flags & UXFER)
523: hpxdone(hp, mbsr, mbbc);
524: if ((hp->flags & UXFER) == 0)
525: hpustart(hp);
526: }
527:
528: /*
529: * transfer stopped:
530: * because it's done, or because of an error
531: * common convention in error-sniffing routines:
532: * return 1 if the error was recovered
533: * and the device has been restarted
534: * return 0 if this transfer has been abandoned
535: * leave flags & UXFER set if we're all done;
536: * clear UXFER if the transfer should be retried
537: */
538:
539: #define ERRCMIN 16 /* after this many errors, try offsets */
540: #define ERRCAL(e) (((e)%8)==4) /* try recal this often */
541: #define ERRMAX 28 /* after this many errors, give up on transfer */
542:
543: hpxdone(hp, mbsr, mbbc)
544: register struct hpdisk *hp;
545: int mbsr, mbbc;
546: {
547: register struct hpdevice *reg;
548: register struct buf *bp;
549:
550: reg = hp->addr;
551: bp = hp->actf;
552: if ((reg->hpds&HPDS_ERR) || (mbsr&MBSR_EBITS)) {
553: if (hpwhaterr(hp, mbsr, mbbc))
554: return;
555: reg->hpcs1 = HP_DCLR|HP_GO;
556: }
557: if (hp->recal && hpmorecal(hp))
558: return;
559: if (hp->flags & UREVEC && hpbadcont(hp))
560: return;
561: if (hp->flags & UXFER) { /* `active' means we're done */
562: if (hp->errcnt >= ERRCMIN) {
563: reg->hpof = HPOF_FMT22;
564: reg->hpcs1 = HP_RTC|HP_GO;
565: while (reg->hpds & HPDS_PIP)
566: DELAY(25);
567: }
568: hp->errcnt = 0;
569: hp->flags &=~ (UACTIVE|UXFER);
570: hp->actf = bp->av_forw;
571: bp->b_resid = mbbc;
572: iodone(bp);
573: }
574: }
575:
576: /*
577: * sort out errors
578: */
579:
580: hpwhaterr(hp, mbsr, mbbc)
581: register struct hpdisk *hp;
582: int mbsr, mbbc;
583: {
584: register struct hpdevice *reg;
585: register struct buf *bp;
586: register int i;
587:
588: reg = hp->addr;
589: bp = hp->actf;
590: /*
591: * let registers settle
592: */
593: i = 0;
594: while ((reg->hpds & HPDS_DRY) == 0) {
595: if (++i > 512)
596: break;
597: hpwaitdry++;
598: }
599: if (reg->hper1 & HPER1_WLE) {
600: printf("hp%d: write locked\n", UNIT(bp->b_dev));
601: bp->b_flags |= B_ERROR;
602: return (0); /* finished */
603: }
604: if ((reg->hper2 & HPER2_BSE || reg->hper1 & HPER1_FER)
605: && hpbadrep(hp, mbbc))
606: return (1); /* restarted, reading replacement */
607: if (++hp->errcnt > ERRMAX) {
608: harderr(bp, "hp");
609: printf("mbsr %o er1 %o er2 %o\n",
610: mbsr, reg->hper1&0177777, reg->hper2&0177777);
611: bp->b_flags |= B_ERROR;
612: return (0); /* finished */
613: }
614: if (bp->b_flags & B_READ
615: && (reg->hper1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK)
616: return (hpecc(hp, mbbc)); /* restart or finish */
617: /*
618: * hard error: clear and try again,
619: * perhaps with recal
620: */
621: if (ERRCAL(hp->errcnt)) {
622: hpstrecal(hp);
623: return (1); /* restarted */
624: }
625: hp->flags &=~ UXFER;
626: return (0); /* please restart me */
627: }
628:
629: /*
630: * recalibration state machine
631: * walks through the sequence
632: * RECAL
633: * SEEK back to the cylinder we wanted
634: * perhaps offset the heads slightly
635: * and try the operation again
636: */
637:
638: hpstrecal(hp)
639: register struct hpdisk *hp;
640: {
641:
642: hp->addr->hpcs1 = HP_DCLR|HP_GO;
643: hp->addr->hpcs1 = HP_RECAL|HP_GO;
644: hp->recal = 1;
645: }
646:
647: hpmorecal(hp)
648: register struct hpdisk *hp;
649: {
650: register struct hpdevice *reg;
651:
652: reg = hp->addr;
653: switch (hp->recal) {
654: case 1: /* did RECAL, time to seek */
655: reg->hpdc = hp->actf->b_cylin;
656: reg->hpcs1 = HP_SEEK|HP_GO;
657: hp->recal++;
658: return (1);
659:
660: case 2: /* did seek, time for offset */
661: if (hp->errcnt > ERRCMIN && hp->actf->b_flags & B_READ) {
662: reg->hpof = hp_offset[hp->errcnt%NOFFS]|HPOF_FMT22;
663: reg->hpcs1 = HP_OFFSET|HP_GO;
664: hp->recal++;
665: return (1);
666: }
667: /* too soon or a write, fall through */
668: default: /* time to restart the transfer */
669: hp->recal = 0;
670: hp->flags &=~ UXFER;
671: return (0);
672: }
673: }
674:
675: /*
676: * read the bad144 bad block table:
677: * call on first access to drive,
678: * or when VV was down
679: */
680:
681: hprbad(hp)
682: register struct hpdisk *hp;
683: {
684: register struct buf *xbp, *bp;
685: register struct hptype *st;
686:
687: st = &hptype[hp->type];
688: xbp = hp->actf;
689: bp = &hpbadbuf[UNIT(xbp->b_dev)];
690: if (xbp == bp)
691: return; /* cheap reentry protection */
692: bp->b_flags = B_BUSY|B_READ;
693: bp->b_dev = xbp->b_dev;
694: bp->b_un.b_addr = (caddr_t)&hpbad[UNIT(xbp->b_dev)];
695: bp->b_bcount = sizeof(struct bad144);
696: bp->b_resid = 0;
697: bp->b_blkno = st->ncyl * st->nspc - st->nsect; /* fake-ish */
698: bp->b_cylin = st->ncyl - 1;
699: bp->av_forw = xbp;
700: hp->actf = bp;
701: bzero(bp->b_un.b_addr, sizeof(struct bad144));
702: }
703:
704: /*
705: * here when a bad block is detected:
706: * find the replacement block, and restart transfer for it
707: */
708: hpbadrep(hp, mbbc)
709: register struct hpdisk *hp;
710: int mbbc;
711: {
712: register daddr_t bno;
713: register struct hptype *st;
714: struct buf *bp;
715: register int i;
716:
717: if (hp->flags & UREVEC)
718: return (0);
719: st = &hptype[hp->type];
720: bp = hp->actf;
721: hp->badsec = (bp->b_bcount - mbbc) / SECTOR;
722: bno = bp->b_cylin * st->nspc + bp->b_blkno % st->nspc; /* true lbn */
723: bno += hp->badsec;
724: i = bno / st->nspc;
725: bno %= st->nspc;
726: i = bad144rep(&hpbad[UNIT(bp->b_dev)], i, (int)bno/st->nsect, (int)bno%st->nsect);
727: if (i < 0)
728: return (0);
729: bno = st->ncyl*st->nspc - st->nsect - 1 - i;
730: hp->addr->hpcs1 = HP_DCLR|HP_GO;
731: if (mbbc > SECTOR)
732: mbbc = SECTOR;
733: hpcontin(hp, bno, hp->badsec*SECTOR, mbbc);
734: hp->flags |= UREVEC;
735: return (1);
736: }
737:
738: /*
739: * here after replacing the bad block:
740: * now do the rest of the original transfer
741: */
742: hpbadcont(hp)
743: register struct hpdisk *hp;
744: {
745: register struct buf *bp;
746: int next, resid;
747: daddr_t bno;
748: int nspc;
749:
750: hp->flags &=~ UREVEC;
751: bp = hp->actf;
752: next = (hp->badsec + 1) * SECTOR;
753: resid = bp->b_bcount - next;
754: if (resid <= 0)
755: return (0);
756: nspc = hptype[hp->type].nspc;
757: bno = bp->b_cylin*nspc + bp->b_blkno%nspc;
758: bno += hp->badsec + 1;
759: hpcontin(hp, bno, next, resid);
760: return (1);
761: }
762:
763: /*
764: * correct an ECC error and restart the transfer
765: * the error is (hpec1-1) bits into the current sector;
766: * at that point, the bits set in hpec2 are wrong.
767: */
768: hpecc(hp, bc)
769: register struct hpdisk *hp;
770: int bc;
771: {
772: register struct hpdevice *reg;
773: register struct buf *bp;
774: register int i;
775: int nxf;
776: unsigned int mask;
777: long a, lasta;
778: struct mbaddr *ap;
779: register daddr_t bno;
780: register struct hptype *st;
781:
782: if ((bp = hp->actf) == NULL)
783: panic("hpecc");
784: reg = hp->addr;
785: ap = &hpaddr[UNIT(bp->b_dev)];
786: lasta = mbcuraddr(ap);
787: nxf = bp->b_bcount - bc;
788: i = reg->hpec1 - 1; /* -1 makes 0 origin */
789: a = lasta - (nxf > SECTOR ? SECTOR : nxf) + ((i&~07)>>3);
790: mask = reg->hpec2;
791: mask <<= i&07;
792: for (; a < lasta && mask; mask >>= 8, a++)
793: mbputc(ap, a, mbgetc(ap, a)^mask);
794: st = &hptype[hp->type];
795: bno = bp->b_cylin*st->nspc + bp->b_blkno%st->nspc + nxf/SECTOR;
796: printf("hp%d: soft ecc sec %ld\n", UNIT(bp->b_dev), bno - 1);
797: if (bc == 0)
798: return (0);
799: reg->hpcs1 = HP_DCLR|HP_GO;
800: hpcontin(hp, bno, bp->b_bcount - bc, bc);
801: return (1);
802: }
803:
804: /*
805: * continue the current transfer,
806: * which was interrupted:
807: * move size bytes to or from the current buffer at offset off,
808: * starting with disk sector bno
809: * used for bad sector replacement,
810: * and to continue after bad sectors or ECC correction
811: */
812: hpcontin(hp, bno, off, size)
813: register struct hpdisk *hp;
814: daddr_t bno;
815: int off, size;
816: {
817: register struct hpdevice *reg;
818: struct mbaddr *ap;
819: register struct buf *bp;
820: register struct hptype *st;
821:
822: reg = hp->addr;
823: bp = hp->actf;
824: ap = &hpaddr[UNIT(bp->b_dev)];
825: st = &hptype[hp->type];
826: mbadj(ap, off, size);
827: reg->hpdc = bno / st->nspc;
828: bno %= st->nspc;
829: reg->hpda = ((bno/st->nsect)<<8) | (bno%st->nsect);
830: mbcontin(ap);
831: if (bp->b_flags & B_READ)
832: reg->hpcs1 = HP_RCOM|HP_GO;
833: else
834: reg->hpcs1 = HP_WCOM|HP_GO;
835: }
836:
837: hpread(dev)
838: dev_t dev;
839: {
840: physio(hpstrategy, &hpbuf[UNIT(dev)], dev, B_READ, minphys);
841: }
842:
843: hpwrite(dev)
844: dev_t dev;
845: {
846: physio(hpstrategy, &hpbuf[UNIT(dev)], dev, B_WRITE, minphys);
847: }
848:
849: /*
850: * check for offline drives and hung controllers
851: */
852:
853: hpwatch()
854: {
855: register struct hpdisk *hp;
856: register struct hpdevice *reg;
857: register struct buf *bp;
858: register int s;
859:
860: s = spl6();
861: timeout(hpwatch, (caddr_t)0, 15*HZ);
862: for (hp = &hpdisk[hpcnt-1]; hp >= hpdisk; hp--) {
863: if ((hp->flags & UWOL) == 0 || (reg = hp->addr) == 0)
864: continue;
865: if ((reg->hpds & (HPDS_DPR|HPDS_MOL)) != (HPDS_DPR|HPDS_MOL)) {
866: if ((hp->flags & UWAITOL) == 0) {
867: hp->flags |= UWAITOL;
868: continue;
869: }
870: printf("hp%d offline\n", hp - hpdisk);
871: while ((bp = hp->actf) != NULL) {
872: bp->b_flags |= B_ERROR;
873: hp->actf = bp->av_forw;
874: iodone(bp);
875: }
876: }
877: hp->flags &=~ (UWAITOL|UWOL);
878: hpustart(hp);
879: }
880: splx(s);
881: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.