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