|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: *
6: * @(#)hp.c 7.10 (Berkeley) 7/8/88
7: */
8:
9: /*
10: * RP??/RM?? disk driver with ECC handling and bad block forwarding.
11: * Also supports header io operations and commands to write check
12: * header and data.
13: */
14: #include "param.h"
15: #include "inode.h"
16: #include "fs.h"
17: #include "dkbad.h"
18: #include "disklabel.h"
19:
20: #include "../vax/pte.h"
21:
22: #include "../vaxmba/hpreg.h"
23: #include "../vaxmba/mbareg.h"
24:
25: #include "saio.h"
26: #include "savax.h"
27:
28: #define RETRIES 27
29:
30: #define MASKREG(reg) ((reg)&0xffff)
31:
32: #define MAXBADDESC 126
33: #define SECTSIZ 512 /* sector size in bytes */
34: #define HDRSIZ 4 /* number of bytes in sector header */
35:
36: char lbuf[SECTSIZ];
37:
38: #define RP06(type) ((type) == MBDT_RP06 || (type) == MBDT_RP05 \
39: || (type) == MBDT_RP04)
40: #define ML11(type) ((type) == MBDT_ML11A)
41: #define RM80(type) ((type) == MBDT_RM80)
42:
43: u_char hp_offset[16] = {
44: HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400,
45: HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800,
46: HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200,
47: 0, 0, 0, 0,
48: };
49:
50: #define MAXUNIT 8
51: struct disklabel hplabel[MAXNMBA][MAXUNIT];
52: #ifndef SMALL
53: struct dkbad hpbad[MAXNMBA][MAXUNIT];
54: int sectsiz;
55: #endif
56:
57: struct hp_softc {
58: char type;
59: char gottype;
60: char ssect; /* 1 when on track w/skip sector */
61: char debug;
62: # define HPF_BSEDEBUG 01 /* debugging bad sector forwarding */
63: # define HPF_ECCDEBUG 02 /* debugging ecc correction */
64: int ecclim;
65: int retries;
66: } hp_softc[MAXNMBA][MAXUNIT];
67:
68: /*
69: * When awaiting command completion, don't hang on to the status register
70: * since this ties up some controllers.
71: */
72: #define HPWAIT(addr) \
73: while ((((addr)->hpds)&HPDS_DRY) == 0) \
74: DELAY(500);
75:
76: hpopen(io)
77: register struct iob *io;
78: {
79: register unit = io->i_unit;
80: register struct hp_softc *sc;
81: register struct disklabel *lp;
82: struct hpdevice *hpaddr;
83: struct disklabel *dlp;
84: int error = 0;
85:
86: /*
87: * Accept adaptor number as either controller or adaptor,
88: * but not both.
89: */
90: if (io->i_ctlr) {
91: if (io->i_adapt == 0)
92: io->i_adapt = io->i_ctlr;
93: else
94: return (ECTLR);
95: }
96: if ((u_int)io->i_adapt >= MAXNMBA || !mbainit(io->i_adapt))
97: return (EADAPT);
98: if ((u_int)unit >= MAXUNIT)
99: return (EUNIT);
100: hpaddr = (struct hpdevice *)mbadrv(io->i_adapt, unit);
101: sc = &hp_softc[io->i_adapt][unit];
102: lp = &hplabel[io->i_adapt][unit];
103: if (sc->gottype == 0) {
104: register int i;
105: struct iob tio;
106:
107: #ifndef SMALL
108: sc->retries = RETRIES;
109: sc->ecclim = 11;
110: sc->debug = 0;
111: #endif
112: hpaddr->hpcs1 = HP_DCLR|HP_GO; /* init drive */
113: hpaddr->hpcs1 = HP_PRESET|HP_GO;
114: #ifndef SMALL
115: if ((hpaddr->hpds & HPDS_DPR) == 0)
116: return (ENXIO);
117: sc->type = hpaddr->hpdt & MBDT_TYPE;
118: if (sc->type == MBDT_ML11B)
119: sc->type = MBDT_ML11A;
120: if (!ML11(sc->type))
121: #endif
122: hpaddr->hpof = HPOF_FMT22;
123: /*
124: * Read in the pack label.
125: */
126: lp->d_nsectors = 32;
127: lp->d_secpercyl = 20*32;
128: tio = *io;
129: tio.i_bn = LABELSECTOR;
130: tio.i_ma = lbuf;
131: tio.i_cc = SECTSIZ;
132: tio.i_flgs |= F_RDDATA;
133: if (hpstrategy(&tio, READ) != SECTSIZ)
134: error = ERDLAB;
135: dlp = (struct disklabel *)(lbuf + LABELOFFSET);
136: if (error == 0 && (dlp->d_magic != DISKMAGIC ||
137: dlp->d_magic2 != DISKMAGIC))
138: error = EUNLAB;
139: if (error == 0)
140: *lp = *dlp;
141: else
142: #ifdef COMPAT_42
143: if (hpmaptype(hpaddr, hpaddr->hpdt & MBDT_TYPE, unit, lp) == 0)
144: #endif
145: return (error);
146:
147: #ifndef SMALL
148: /*
149: * Read in the bad sector table.
150: */
151: tio.i_bn = lp->d_secpercyl * lp->d_ncylinders - lp->d_nsectors;
152: tio.i_ma = (char *)&hpbad[io->i_adapt][unit];
153: tio.i_cc = sizeof(struct dkbad);
154: for (i = 0; i < 5; i++) {
155: if (hpstrategy(&tio, READ) == sizeof(struct dkbad))
156: break;
157: tio.i_bn += 2;
158: }
159: if (i == 5) {
160: printf("hp: can't read bad sector table\n");
161: for (i = 0; i < MAXBADDESC; i++) {
162: hpbad[io->i_adapt][unit].bt_bad[i].bt_cyl = -1;
163: hpbad[io->i_adapt][unit].bt_bad[i].bt_trksec = -1;
164: }
165: }
166: #endif
167: sc->gottype = 1;
168: }
169: if (io->i_part >= lp->d_npartitions ||
170: lp->d_partitions[io->i_part].p_size == 0)
171: return (EPART);
172: io->i_boff = lp->d_partitions[io->i_part].p_offset;
173: return (0);
174: }
175:
176: hpstrategy(io, func)
177: register struct iob *io;
178: {
179: register int unit = io->i_unit;
180: register struct hp_softc *sc;
181: register struct disklabel *lp;
182: struct mba_regs *mba;
183: struct hpdevice *hpaddr;
184: daddr_t bn, startblock;
185: int cn, tn, sn, bytecnt, bytesleft, rv;
186: int er1, er2, hprecal;
187: char *membase;
188:
189: mba = mbamba(io->i_adapt);
190: hpaddr = (struct hpdevice *)mbadrv(io->i_adapt, unit);
191: sc = &hp_softc[io->i_adapt][unit];
192: lp = &hplabel[io->i_adapt][unit];
193: #ifndef SMALL
194: sectsiz = SECTSIZ;
195: if ((io->i_flgs & (F_HDR|F_HCHECK)) != 0)
196: sectsiz += HDRSIZ;
197: if ((hpaddr->hpds & HPDS_VV) == 0) {
198: hpaddr->hpcs1 = HP_DCLR|HP_GO;
199: hpaddr->hpcs1 = HP_PRESET|HP_GO;
200: if (!ML11(sc->type))
201: hpaddr->hpof = HPOF_FMT22;
202: }
203: io->i_errcnt = 0;
204: sc->ssect = 0;
205: rv = bytecnt = io->i_cc;
206: membase = io->i_ma;
207: startblock = io->i_bn;
208: hprecal = 0;
209: #endif
210:
211: restart:
212: bn = io->i_bn;
213: cn = bn / lp->d_secpercyl;
214: sn = bn % lp->d_secpercyl;
215: tn = sn / lp->d_nsectors;
216: sn = sn % lp->d_nsectors + sc->ssect;
217:
218: HPWAIT(hpaddr);
219: mba->mba_sr = -1;
220: if (ML11(sc->type))
221: hpaddr->hpda = bn;
222: else {
223: hpaddr->hpdc = cn;
224: hpaddr->hpda = (tn << 8) + sn;
225: }
226: #ifdef SMALL
227: mbastart(io, io->i_unit, func); /* start transfer */
228: HPWAIT(hpaddr);
229: if (hpaddr->hpds & HPDS_ERR) {
230: printf("hp error: sn [%d-%d) ds=%b er1=%b\n",
231: bn, bn + io->i_cc/SECTSIZ, MASKREG(hpaddr->hpds), HPDS_BITS,
232: MASKREG(hpaddr->hper1), HPER1_BITS);
233: return (-1);
234: }
235: return (io->i_cc);
236: #else
237: if (mbastart(io, io->i_unit, func) != 0) { /* start transfer */
238: rv = -1;
239: goto done;
240: }
241: HPWAIT(hpaddr);
242: /*
243: * Successful data transfer, return.
244: */
245: if ((hpaddr->hpds&HPDS_ERR) == 0 && (mba->mba_sr&MBSR_EBITS) == 0)
246: goto done;
247:
248: /*
249: * Error handling. Calculate location of error.
250: */
251: bytesleft = MASKREG(mba->mba_bcr);
252: if (bytesleft)
253: bytesleft |= 0xffff0000; /* sxt */
254: bn = io->i_bn + (io->i_cc + bytesleft) / sectsiz;
255: er1 = MASKREG(hpaddr->hper1);
256: er2 = MASKREG(hpaddr->hper2);
257: if (er1 & (HPER1_DCK|HPER1_ECH))
258: bn--; /* Error is in Prev block */
259: cn = bn/lp->d_secpercyl;
260: sn = bn%lp->d_secpercyl;
261: tn = sn/lp->d_nsectors;
262: sn = sn%lp->d_nsectors;
263: if (sc->debug & (HPF_ECCDEBUG|HPF_BSEDEBUG)) {
264: printf("hp error: sn%d (cyl,trk,sec)=(%d,%d,%d) ds=%b\n",
265: bn, cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS);
266: printf("er1=%b er2=%b\n", er1, HPER1_BITS, er2, HPER2_BITS);
267: printf("bytes left: %d, of 0x%x, da 0x%x\n",-bytesleft,
268: hpaddr->hpof, hpaddr->hpda);
269: }
270: if (er1 & HPER1_HCRC) {
271: er1 &= ~(HPER1_HCE|HPER1_FER);
272: er2 &= ~HPER2_BSE;
273: if ((io->i_flgs&F_NBSF) == 0 && hpecc(io, BSE) == 0)
274: goto success;
275: }
276: /*
277: * Give up early if drive write locked.
278: */
279: if (er1&HPER1_WLE) {
280: printf("hp%d: write locked\n", unit);
281: rv = -1;
282: goto done;
283: }
284: /*
285: * Skip sector handling.
286: */
287: if (RM80(sc->type) && (er2 & HPER2_SSE)) {
288: (void) hpecc(io, SSE);
289: sc->ssect = 1;
290: goto restart;
291: }
292: /*
293: * Attempt to forward bad sectors on anything but an ML11.
294: * Interpret format error bit as a bad block on RP06's.
295: */
296: if (((er2 & HPER2_BSE) && !ML11(sc->type)) ||
297: (MASKREG(er1) == HPER1_FER && RP06(sc->type))) {
298: if (io->i_flgs & F_NBSF) {
299: io->i_error = EBSE;
300: goto hard;
301: }
302: if (hpecc(io, BSE) == 0)
303: goto success;
304: io->i_error = EBSE;
305: goto hard;
306: }
307: /*
308: * ECC correction?
309: */
310: if ((er1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK) {
311: if (hpecc(io, ECC) == 0)
312: goto success;
313: io->i_error = EECC;
314: goto hard;
315: }
316:
317: /*
318: * If a hard error, or maximum retry count
319: * exceeded, clear controller state and
320: * pass back error to caller.
321: */
322: if (++io->i_errcnt > sc->retries || (er1 & HPER1_HARD) ||
323: (!ML11(sc->type) && (er2 & HPER2_HARD)) ||
324: (ML11(sc->type) && (io->i_errcnt >= 16))) {
325: io->i_error = EHER;
326: if (mba->mba_sr & (MBSR_WCKUP|MBSR_WCKLWR))
327: io->i_error = EWCK;
328: hard:
329: io->i_errblk = bn + sc->ssect;
330: if (sc->debug & (HPF_BSEDEBUG|HPF_ECCDEBUG))
331: printf(" dc=%d, da=0x%x",MASKREG(hpaddr->hpdc),
332: MASKREG(hpaddr->hpda));
333: else {
334: printf("hp error: sn%d (cyl,trk,sec)=(%d,%d,%d) ds=%b \n",
335: bn, cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS);
336: printf("er1=%b er2=%b", er1, HPER1_BITS, er2, HPER2_BITS);
337: }
338: hpaddr->hpcs1 = HP_DCLR|HP_GO;
339: printf("\n");
340: rv = -1;
341: goto done;
342:
343: }
344: /* fall thru to retry */
345: hpaddr->hpcs1 = HP_DCLR|HP_GO;
346: HPWAIT(hpaddr);
347:
348: /*
349: * Every fourth retry recalibrate.
350: */
351: if (((io->i_errcnt & 07) == 4) ) {
352: hpaddr->hpcs1 = HP_RECAL|HP_GO;
353: HPWAIT(hpaddr);
354: hpaddr->hpdc = cn;
355: hpaddr->hpcs1 = HP_SEEK|HP_GO;
356: HPWAIT(hpaddr);
357: }
358:
359: if (io->i_errcnt >= 16 && (io->i_flgs & F_READ)) {
360: hpaddr->hpof = hp_offset[io->i_errcnt & 017]|HPOF_FMT22;
361: hpaddr->hpcs1 = HP_OFFSET|HP_GO;
362: HPWAIT(hpaddr);
363: }
364: if (sc->debug & (HPF_ECCDEBUG|HPF_BSEDEBUG))
365: printf("restart: bn=%d, cc=%d, ma=0x%x hprecal=%d\n",
366: io->i_bn, io->i_cc, io->i_ma, hprecal);
367: goto restart;
368:
369: success:
370: /*
371: * On successful error recovery, bump
372: * block number to advance to next portion
373: * of i/o transfer.
374: */
375: bn++;
376: if ((bn-startblock) * sectsiz < bytecnt) {
377: io->i_bn = bn;
378: io->i_ma = membase + (io->i_bn - startblock)*sectsiz;
379: io->i_cc = bytecnt - (io->i_bn - startblock)*sectsiz;
380: if (sc->debug & (HPF_ECCDEBUG|HPF_BSEDEBUG))
381: printf("restart: bn=%d, cc=%d, ma=0x%x hprecal=%d\n",
382: io->i_bn, io->i_cc, io->i_ma, hprecal);
383: goto restart;
384: }
385: done:
386: if (io->i_errcnt >= 16) {
387: hpaddr->hpcs1 = HP_RTC|HP_GO;
388: while (hpaddr->hpds & HPDS_PIP)
389: ;
390: }
391: io->i_bn = startblock; /*reset i_bn to original */
392: io->i_cc = bytecnt; /*reset i_cc to total count xfered*/
393: io->i_ma = membase; /*reset i_ma to original */
394: return (rv);
395: #endif
396: }
397:
398: #ifndef SMALL
399: hpecc(io, flag)
400: register struct iob *io;
401: int flag;
402: {
403: register int unit = io->i_unit;
404: register struct mba_regs *mbp;
405: register struct hpdevice *rp;
406: register struct hp_softc *sc;
407: register struct disklabel *lp;
408: int npf, bn, cn, tn, sn, bcr;
409:
410: mbp = mbamba(io->i_adapt);
411: rp = (struct hpdevice *)mbadrv(io->i_adapt, unit);
412: sc = &hp_softc[io->i_adapt][unit];
413: lp = &hplabel[io->i_adapt][unit];
414: bcr = MASKREG(mbp->mba_bcr);
415: if (bcr)
416: bcr |= 0xffff0000; /* sxt */
417: npf = (bcr + io->i_cc) / sectsiz; /* # sectors read */
418: if (flag == ECC)
419: npf--; /* Error is in prev block --ghg */
420: bn = io->i_bn + npf + sc->ssect; /* physical block #*/
421: if (sc->debug & HPF_ECCDEBUG)
422: printf("bcr=%d npf=%d ssect=%d sectsiz=%d i_cc=%d\n",
423: bcr, npf, sc->ssect, sectsiz, io->i_cc);
424: /*
425: * ECC correction logic.
426: */
427: if (flag == ECC) {
428: register int i;
429: caddr_t addr;
430: int bit, o, mask;
431:
432: printf("hp%d: soft ecc sn%d\n", unit, bn);
433: mask = MASKREG(rp->hpec2);
434: for (i = mask, bit = 0; i; i >>= 1)
435: if (i & 1)
436: bit++;
437: if (bit > sc->ecclim) {
438: printf("%d-bit error\n", bit);
439: return (1);
440: }
441: i = MASKREG(rp->hpec1) - 1; /* -1 makes 0 origin */
442: bit = i&07;
443: o = (i & ~07) >> 3;
444: rp->hpcs1 = HP_DCLR | HP_GO;
445: while (o <sectsiz && npf*sectsiz + o < io->i_cc && bit > -11) {
446: addr = io->i_ma + (npf*sectsiz) + o;
447: /*
448: * No data transfer occurs with a write check,
449: * so don't correct the resident copy of data.
450: */
451: if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) {
452: if (sc->debug & HPF_ECCDEBUG)
453: printf("addr=%x old=%x ", addr,
454: (*addr & 0xff));
455: *addr ^= (mask << bit);
456: if (sc->debug & HPF_ECCDEBUG)
457: printf("new=%x\n",(*addr & 0xff));
458: }
459: o++, bit -= 8;
460: }
461: return (0);
462: }
463:
464: /*
465: * Skip sector error.
466: * Set skip-sector-inhibit and
467: * read next sector
468: */
469: if (flag == SSE) {
470: rp->hpcs1 = HP_DCLR | HP_GO;
471: HPWAIT(rp);
472: rp->hpof |= HPOF_SSEI;
473: return (0);
474: }
475:
476: /*
477: * Bad block forwarding.
478: */
479: if (flag == BSE) {
480: int bbn;
481:
482: rp->hpcs1 = HP_DCLR | HP_GO;
483: if (sc->debug & HPF_BSEDEBUG)
484: printf("hpecc: BSE @ bn %d\n", bn);
485: cn = bn / lp->d_secpercyl;
486: sn = bn % lp->d_secpercyl;
487: tn = sn / lp->d_nsectors;
488: sn = sn % lp->d_nsectors;
489: bcr += sectsiz;
490: if ((bbn = isbad(&hpbad[io->i_adapt][unit], cn, tn, sn)) < 0)
491: return (1);
492: bbn = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors - 1
493: - bbn;
494: cn = bbn / lp->d_secpercyl;
495: sn = bbn % lp->d_secpercyl;
496: tn = sn / lp->d_nsectors;
497: sn = sn % lp->d_nsectors;
498: io->i_cc = sectsiz;
499: io->i_ma += npf * sectsiz;
500: if (sc->debug & HPF_BSEDEBUG)
501: printf("revector to cn %d tn %d sn %d\n", cn, tn, sn);
502: rp->hpof &= ~HPOF_SSEI;
503: mbp->mba_sr = -1;
504: rp->hpdc = cn;
505: rp->hpda = (tn<<8) + sn;
506: mbastart(io, io->i_unit, io->i_flgs);
507: io->i_errcnt = 0;
508: HPWAIT(rp);
509: return (rp->hpds&HPDS_ERR);
510: }
511: printf("hpecc: flag=%d\n", flag);
512: return (1);
513: }
514:
515: /*ARGSUSED*/
516: hpioctl(io, cmd, arg)
517: struct iob *io;
518: int cmd;
519: caddr_t arg;
520: {
521: register unit = io->i_unit;
522: register struct hp_softc *sc = &hp_softc[io->i_adapt][unit];
523: register struct disklabel *lp = &hplabel[io->i_adapt][unit];
524: struct mba_drv *drv = mbadrv(io->i_adapt, unit);
525:
526: switch(cmd) {
527:
528: case SAIODEBUG:
529: sc->debug = (int)arg;
530: break;
531:
532: case SAIODEVDATA:
533: if (drv->mbd_dt&MBDT_TAP)
534: return (ECMD);
535: *(struct disklabel *)arg = *lp;
536: break;
537:
538: case SAIOGBADINFO:
539: if (drv->mbd_dt&MBDT_TAP)
540: return (ECMD);
541: *(struct dkbad *)arg = hpbad[io->i_adapt][unit];
542: break;
543:
544: case SAIOECCLIM:
545: sc->ecclim = (int)arg;
546: break;
547:
548: case SAIORETRIES:
549: sc->retries = (int)arg;
550: break;
551:
552: case SAIOSSI: /* skip-sector-inhibit */
553: if (drv->mbd_dt&MBDT_TAP)
554: return (ECMD);
555: if ((io->i_flgs&F_SSI) == 0) {
556: /* make sure this is done once only */
557: io->i_flgs |= F_SSI;
558: lp->d_nsectors++;
559: lp->d_secpercyl += lp->d_ntracks;
560: }
561: break;
562:
563: case SAIONOSSI: /* remove skip-sector-inhibit */
564: if (io->i_flgs & F_SSI) {
565: io->i_flgs &= ~F_SSI;
566: drv->mbd_of &= ~HPOF_SSEI;
567: lp->d_nsectors--;
568: lp->d_secpercyl -= lp->d_ntracks;
569: }
570: break;
571:
572: case SAIOSSDEV: /* drive have skip sector? */
573: return (RM80(sc->type) ? 0 : ECMD);
574:
575: default:
576: return (ECMD);
577: }
578: return (0);
579: }
580: #endif /* !SMALL */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.