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