|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1988 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: * @(#)up.c 7.7 (Berkeley) 7/9/88
7: */
8:
9: /*
10: * UNIBUS peripheral standalone driver with ECC correction and bad
11: * block forwarding. Also supports header operation and write check
12: * for data and/or header.
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 "../vaxuba/upreg.h"
23: #include "../vaxuba/ubareg.h"
24:
25: #include "saio.h"
26: #include "savax.h"
27:
28: #define RETRIES 27
29:
30: #define MAXBADDESC 126 /* max number of bad sectors recorded */
31: #define SECTSIZ 512 /* sector size in bytes */
32: #define HDRSIZ 4 /* number of bytes in sector header */
33:
34: #define MAXUNIT 8
35: #define MAXCTLR 1 /* all addresses must be specified */
36: u_short ubastd[MAXCTLR] = { 0776700 };
37: struct disklabel uplabel[MAXNUBA][MAXCTLR][MAXUNIT];
38: char lbuf[SECTSIZ];
39:
40: extern struct st upst[];
41:
42: #ifndef SMALL
43: struct dkbad upbad[MAXNUBA][MAXCTLR][MAXUNIT]; /* bad sector table */
44: #endif
45: int sectsiz; /* real sector size */
46:
47: struct up_softc {
48: char gottype;
49: char type;
50: char debug;
51: # define UPF_BSEDEBUG 01 /* debugging bad sector forwarding */
52: # define UPF_ECCDEBUG 02 /* debugging ecc correction */
53: int retries;
54: int ecclim;
55: } up_softc[MAXNUBA][MAXCTLR][MAXUNIT];
56:
57: u_char up_offset[16] = {
58: UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400,
59: UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800,
60: UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200,
61: 0, 0, 0, 0
62: };
63:
64: upopen(io)
65: register struct iob *io;
66: {
67: register struct updevice *upaddr;
68: register struct up_softc *sc;
69: register struct st *st;
70: register struct disklabel *lp;
71: struct disklabel *dlp;
72: register int unit;
73: int error = 0, uba, ctlr;
74:
75: if ((u_int)(uba = io->i_adapt) >= nuba)
76: return (EADAPT);
77: if ((u_int)(ctlr = io->i_ctlr) >= MAXCTLR)
78: return (ECTLR);
79: unit = io->i_unit;
80: if ((u_int)unit >= MAXUNIT)
81: return (EUNIT);
82: upaddr = (struct updevice *)ubamem(uba, ubastd[ctlr]);
83: upaddr->upcs2 = unit;
84: while ((upaddr->upcs1 & UP_DVA) == 0);
85: sc = &up_softc[uba][ctlr][unit];
86: lp = &uplabel[uba][ctlr][unit];
87: if (sc->gottype == 0) {
88: register int i;
89: struct iob tio;
90:
91: #ifndef SMALL
92: sc->retries = RETRIES;
93: sc->ecclim = 11;
94: sc->debug = 0;
95: #endif
96: /* Read in the pack label. */
97: lp->d_nsectors = 32;
98: lp->d_secpercyl = 19*32;
99: tio = *io;
100: tio.i_bn = LABELSECTOR;
101: tio.i_ma = lbuf;
102: tio.i_cc = SECTSIZ;
103: tio.i_flgs |= F_RDDATA;
104: if (upstrategy(&tio, READ) != SECTSIZ)
105: error = ERDLAB;
106: dlp = (struct disklabel *)(lbuf + LABELOFFSET);
107: if (error == 0 && (dlp->d_magic != DISKMAGIC ||
108: dlp->d_magic2 != DISKMAGIC))
109: error = EUNLAB;
110: if (error == 0)
111: *lp = *dlp;
112: else
113: #ifdef COMPAT_42
114: if (upmaptype(unit, upaddr, lp) == 0)
115: #endif
116: return (error);
117:
118: #ifndef SMALL
119: /* Read in the bad sector table. */
120: tio.i_bn = lp->d_secpercyl * lp->d_ncylinders - lp->d_nsectors;
121: tio.i_ma = (char *)&upbad[uba][ctlr][unit];
122: tio.i_cc = sizeof(struct dkbad);
123: tio.i_flgs |= F_RDDATA;
124: for (i = 0; i < 5; i++) {
125: if (upstrategy(&tio, READ) == sizeof(struct dkbad))
126: break;
127: tio.i_bn += 2;
128: }
129: if (i == 5) {
130: printf("up: can't read bad sector table\n");
131: for (i = 0; i < MAXBADDESC; i++) {
132: upbad[uba][ctlr][unit].bt_bad[i].bt_cyl = -1;
133: upbad[uba][ctlr][unit].bt_bad[i].bt_trksec = -1;
134: }
135: }
136: #endif
137: sc->gottype = 1;
138: }
139: if (io->i_part >= lp->d_npartitions ||
140: lp->d_partitions[io->i_part].p_size == 0)
141: return (EPART);
142: io->i_boff = lp->d_partitions[io->i_part].p_offset;
143: io->i_flgs &= ~F_TYPEMASK;
144: return (0);
145: }
146:
147: upstrategy(io, func)
148: register struct iob *io;
149: int func;
150: {
151: int cn, tn, sn, o;
152: register unit = io->i_unit;
153: register daddr_t bn;
154: int recal, info, waitdry;
155: register struct updevice *upaddr;
156: register struct disklabel *lp;
157: struct up_softc *sc;
158: int error, rv = io->i_cc;
159: #ifndef SMALL
160: int doprintf = 0;
161: #endif
162:
163: upaddr = (struct updevice *)ubamem(io->i_adapt, ubastd[io->i_ctlr]);
164: sc = &up_softc[io->i_adapt][io->i_ctlr][unit];
165: lp = &uplabel[io->i_adapt][io->i_ctlr][unit];
166: sectsiz = SECTSIZ;
167: #ifndef SMALL
168: if (io->i_flgs & (F_HDR|F_HCHECK))
169: sectsiz += HDRSIZ;
170: #endif
171: upaddr->upcs2 = unit;
172: if ((upaddr->upds & UPDS_VV) == 0) {
173: upaddr->upcs1 = UP_DCLR|UP_GO;
174: upaddr->upcs1 = UP_PRESET|UP_GO;
175: upaddr->upof = UPOF_FMT22;
176: }
177: if ((upaddr->upds & UPDS_DREADY) == 0) {
178: printf("up%d not ready\n", unit);
179: return (-1);
180: }
181: info = ubasetup(io, 1);
182: upaddr->upwc = -io->i_cc / sizeof (short);
183: recal = 0;
184: io->i_errcnt = 0;
185:
186: restart:
187: o = io->i_cc + (upaddr->upwc * sizeof (short));
188: upaddr->upba = info + o;
189: bn = io->i_bn + o / sectsiz;
190: #ifndef SMALL
191: error = 0;
192: if (doprintf && sc->debug & (UPF_ECCDEBUG|UPF_BSEDEBUG))
193: printf("wc=%d o=%d i_bn=%d bn=%d\n",
194: upaddr->upwc, o, io->i_bn, bn);
195: #endif
196: upwaitdry(upaddr);
197: if (upstart(io, bn, lp) != 0) {
198: rv = -1;
199: goto done;
200: }
201: upwaitrdy(upaddr);
202: /*
203: * If transfer has completed, free UNIBUS
204: * resources and return transfer size.
205: */
206: if ((upaddr->upds&UPDS_ERR) == 0 && (upaddr->upcs1&UP_TRE) == 0)
207: goto done;
208: bn = io->i_bn +
209: (io->i_cc + upaddr->upwc * sizeof (short)) / sectsiz;
210: if (upaddr->uper1 & (UPER1_DCK|UPER1_ECH))
211: bn--;
212: cn = bn / lp->d_secpercyl;
213: sn = bn % lp->d_secpercyl;
214: tn = sn / lp->d_nsectors;
215: sn = sn % lp->d_nsectors;
216: #ifndef SMALL
217: if (sc->debug & (UPF_ECCDEBUG|UPF_BSEDEBUG)) {
218: printf("up error: sn%d (cyl,trk,sec)=(%d,%d,%d) ",
219: bn, cn, tn, sn);
220: printf("cs2=%b er1=%b er2=%b wc=%d\n",
221: upaddr->upcs2, UPCS2_BITS, upaddr->uper1,
222: UPER1_BITS, upaddr->uper2, UPER2_BITS, upaddr->upwc);
223: }
224: #endif
225: waitdry = 0;
226: while ((upaddr->upds&UPDS_DRY) == 0 && ++waitdry < sectsiz)
227: DELAY(5);
228: #ifndef SMALL
229: if (upaddr->uper1&UPER1_WLE) {
230: /*
231: * Give up on write locked devices immediately.
232: */
233: printf("up%d: write locked\n", unit);
234: rv = -1;
235: goto done;
236: }
237: if (upaddr->uper2 & UPER2_BSE) {
238: if ((io->i_flgs&F_NBSF) == 0 && upecc(io, BSE) == 0)
239: goto success;
240: error = EBSE;
241: goto hard;
242: }
243: /*
244: * ECC error. If a soft error, correct it;
245: * if correction is too large, no more retries.
246: */
247: if ((upaddr->uper1 & (UPER1_DCK|UPER1_ECH|UPER1_HCRC)) == UPER1_DCK) {
248: if (upecc(io, ECC) == 0)
249: goto success;
250: error = EECC;
251: goto hard;
252: }
253: /*
254: * If the error is a header CRC, check if a replacement sector
255: * exists in the bad sector table.
256: */
257: if ((upaddr->uper1&UPER1_HCRC) && (io->i_flgs&F_NBSF) == 0 &&
258: upecc(io, BSE) == 0)
259: goto success;
260: #endif
261: if (++io->i_errcnt > sc->retries) {
262: /*
263: * After 28 retries (16 without offset, and
264: * 12 with offset positioning) give up.
265: */
266: hard:
267: #ifndef SMALL
268: if (error == 0) {
269: error = EHER;
270: if (upaddr->upcs2 & UPCS2_WCE)
271: error = EWCK;
272: }
273: io->i_error = error;
274: #endif
275: printf("up error: sn%d (cyl,trk,sec)=(%d,%d,%d) ",
276: bn, cn, tn, sn);
277: printf("cs2=%b er1=%b er2=%b\n",
278: upaddr->upcs2, UPCS2_BITS, upaddr->uper1,
279: UPER1_BITS, upaddr->uper2, UPER2_BITS);
280: upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO;
281: io->i_errblk = bn;
282: if (io->i_errcnt >= 16) {
283: upaddr->upof = UPOF_FMT22;
284: upaddr->upcs1 = UP_RTC|UP_GO;
285: upwaitdry(upaddr);
286: }
287: rv = -1;
288: goto done;
289: }
290: /*
291: * Clear drive error and, every eight attempts, (starting with the
292: * fourth) recalibrate to clear the slate.
293: */
294: upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO;
295: if ((io->i_errcnt&07) == 4 ) {
296: upaddr->upcs1 = UP_RECAL|UP_GO;
297: upwaitdry(upaddr);
298: upaddr->updc = cn;
299: upaddr->upcs1 = UP_SEEK|UP_GO;
300: upwaitdry(upaddr);
301: }
302: if (io->i_errcnt >= 16 && (func & READ)) {
303: upaddr->upof = up_offset[io->i_errcnt & 017] | UPOF_FMT22;
304: upaddr->upcs1 = UP_OFFSET|UP_GO;
305: upwaitdry(upaddr);
306: }
307: goto restart;
308:
309: success:
310: #define rounddown(x, y) (((x) / (y)) * (y))
311: upaddr->upwc = rounddown(upaddr->upwc, sectsiz / sizeof (short));
312: if (upaddr->upwc) {
313: #ifndef SMALL
314: doprintf++;
315: #endif
316: goto restart;
317: }
318: done:
319: ubafree(io, info);
320: /*
321: * If we were offset positioning,
322: * return to centerline.
323: */
324: if (io->i_errcnt >= 16) {
325: upaddr->upof = UPOF_FMT22;
326: upaddr->upcs1 = UP_RTC|UP_GO;
327: upwaitdry(upaddr);
328: }
329: return (rv);
330: }
331:
332: upwaitrdy(upaddr)
333: register struct updevice *upaddr;
334: {
335: do {
336: DELAY(25);
337: } while ((upaddr->upcs1 & UP_RDY) == 0);
338: }
339:
340: upwaitdry(upaddr)
341: register struct updevice *upaddr;
342: {
343: while ((upaddr->upds&UPDS_DRY) == 0)
344: DELAY(25);
345: }
346:
347: #ifndef SMALL
348: /*
349: * Correct an ECC error, and restart the i/o to complete the transfer (if
350: * necessary). This is quite complicated because the transfer may be going
351: * to an odd memory address base and/or across a page boundary.
352: */
353: upecc(io, flag)
354: register struct iob *io;
355: int flag;
356: {
357: register i, unit;
358: register struct up_softc *sc;
359: register struct updevice *up;
360: register struct disklabel *lp;
361: caddr_t addr;
362: int bn, twc, npf, mask, cn, tn, sn;
363: daddr_t bbn;
364:
365: /*
366: * Npf is the number of sectors transferred
367: * before the sector containing the ECC error;
368: * bn is the current block number.
369: */
370: unit = io->i_unit;
371: sc = &up_softc[io->i_adapt][io->i_ctlr][unit];
372: lp = &uplabel[io->i_adapt][io->i_ctlr][unit];
373: up = (struct updevice *)ubamem(io->i_adapt, ubastd[io->i_ctlr]);
374: twc = up->upwc;
375: npf = ((twc * sizeof(short)) + io->i_cc) / sectsiz;
376: if (flag == ECC)
377: npf--;
378: if (sc->debug & UPF_ECCDEBUG)
379: printf("npf=%d mask=0x%x ec1=%d wc=%d\n",
380: npf, up->upec2, up->upec1, twc);
381: bn = io->i_bn + npf;
382: cn = bn / lp->d_secpercyl;
383: sn = bn % lp->d_secpercyl;
384: tn = sn / lp->d_nsectors;
385: sn = sn % lp->d_nsectors;
386:
387: /*
388: * ECC correction.
389: */
390: if (flag == ECC) {
391: int bit, o;
392:
393: mask = up->upec2;
394: printf("up%d: soft ecc sn%d\n", unit, bn);
395: for (i = mask, bit = 0; i; i >>= 1)
396: if (i & 1)
397: bit++;
398: if (bit > sc->ecclim) {
399: printf("%d-bit error\n", bit);
400: return (1);
401: }
402: /*
403: * Compute the byte and bit position of
404: * the error. o is the byte offset in
405: * the transfer at which the correction
406: * applied.
407: */
408: i = up->upec1 - 1; /* -1 makes 0 origin */
409: bit = i & 07;
410: o = (i & ~07) >> 3;
411: up->upcs1 = UP_TRE|UP_DCLR|UP_GO;
412: /*
413: * Correct while possible bits remain of mask.
414: * Since mask contains 11 bits, we continue while
415: * the bit offset is > -11. Also watch out for
416: * end of this block and the end of the transfer.
417: */
418: while (o < sectsiz && (npf*sectsiz)+o < io->i_cc && bit > -11) {
419: /*
420: * addr =
421: * (base address of transfer) +
422: * (# sectors transferred before the error) *
423: * (sector size) +
424: * (byte offset to incorrect data)
425: */
426: addr = io->i_ma + (npf * sectsiz) + o;
427: /*
428: * No data transfer occurs with a write check,
429: * so don't correct the resident copy of data.
430: */
431: if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) {
432: if (sc->debug & UPF_ECCDEBUG)
433: printf("addr=0x%x old=0x%x ", addr,
434: (*addr&0xff));
435: *addr ^= (mask << bit);
436: if (sc->debug & UPF_ECCDEBUG)
437: printf("new=0x%x\n", (*addr&0xff));
438: }
439: o++, bit -= 8;
440: }
441: return (0);
442: }
443:
444: /*
445: * Bad sector forwarding.
446: */
447: if (flag == BSE) {
448: /*
449: * If not in bad sector table,
450: * indicate a hard error to caller.
451: */
452: up->upcs1 = UP_TRE|UP_DCLR|UP_GO;
453: if ((bbn = isbad(&upbad[io->i_adapt][io->i_ctlr][unit], cn, tn, sn)) < 0)
454: return (1);
455: bbn = (lp->d_ncylinders * lp->d_secpercyl) -
456: lp->d_nsectors - 1 - bbn;
457: twc = up->upwc + sectsiz;
458: up->upwc = - (sectsiz / sizeof (short));
459: if (sc->debug & UPF_BSEDEBUG)
460: printf("revector sn %d to %d\n", sn, bbn);
461: /*
462: * Clear the drive & read the replacement
463: * sector. If this is in the middle of a
464: * transfer, then set up the controller
465: * registers in a normal fashion.
466: * The UNIBUS address need not be changed.
467: */
468: upwaitrdy(up);
469: if (upstart(io, bbn, lp))
470: return (1); /* error */
471: io->i_errcnt = 0; /* success */
472: upwaitrdy(up);
473: if ((up->upds & UPDS_ERR) || (up->upcs1 & UP_TRE)) {
474: up->upwc = twc - sectsiz;
475: return (1);
476: }
477: }
478: if (twc)
479: up->upwc = twc;
480: return (0);
481: }
482: #endif /* !SMALL */
483:
484: upstart(io, bn, lp)
485: register struct iob *io;
486: daddr_t bn;
487: register struct disklabel *lp;
488: {
489: register struct updevice *upaddr;
490: register struct up_softc *sc;
491: int sn, tn;
492:
493: upaddr = (struct updevice *)ubamem(io->i_adapt, ubastd[io->i_ctlr]);
494: sc = &up_softc[io->i_adapt][io->i_ctlr][io->i_unit];
495: sn = bn % lp->d_secpercyl;
496: tn = sn / lp->d_nsectors;
497: sn = sn % lp->d_nsectors;
498: upaddr->updc = bn / lp->d_secpercyl;
499: upaddr->upda = (tn << 8) + sn;
500: switch (io->i_flgs & F_TYPEMASK) {
501:
502: case F_RDDATA:
503: upaddr->upcs1 = UP_RCOM|UP_GO;
504: break;
505:
506: case F_WRDATA:
507: upaddr->upcs1 = UP_WCOM|UP_GO;
508: break;
509:
510: #ifndef SMALL
511: case F_HDR|F_RDDATA:
512: upaddr->upcs1 = UP_RHDR|UP_GO;
513: break;
514:
515: case F_HDR|F_WRDATA:
516: upaddr->upcs1 = UP_WHDR|UP_GO;
517: break;
518:
519: case F_CHECK|F_WRDATA:
520: case F_CHECK|F_RDDATA:
521: upaddr->upcs1 = UP_WCDATA|UP_GO;
522: break;
523:
524: case F_HCHECK|F_WRDATA:
525: case F_HCHECK|F_RDDATA:
526: upaddr->upcs1 = UP_WCHDR|UP_GO;
527: break;
528: #endif
529:
530: default:
531: io->i_error = ECMD;
532: io->i_flgs &= ~F_TYPEMASK;
533: return (1);
534: }
535: return (0);
536: }
537:
538: #ifndef SMALL
539: /*ARGSUSED*/
540: upioctl(io, cmd, arg)
541: struct iob *io;
542: int cmd;
543: caddr_t arg;
544: {
545: register struct up_softc *sc;
546:
547: sc = &up_softc[io->i_adapt][io->i_ctlr][io->i_unit];
548: switch(cmd) {
549: case SAIODEBUG:
550: sc->debug = (int)arg;
551: break;
552: case SAIODEVDATA:
553: *(struct disklabel *)arg =
554: uplabel[io->i_adapt][io->i_ctlr][io->i_unit];
555: break;
556: case SAIOGBADINFO:
557: *(struct dkbad *)arg =
558: upbad[io->i_adapt][io->i_ctlr][io->i_unit];
559: break;
560: case SAIOECCLIM:
561: sc->ecclim = (int)arg;
562: break;
563: case SAIORETRIES:
564: sc->retries = (int)arg;
565: break;
566: default:
567: return (ECMD);
568: }
569: return (0);
570: }
571: #endif /* !SMALL */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.