1 |
1626 |
jcastillo |
/* Yo, Emacs! we're -*- Linux-C -*-
|
2 |
|
|
*
|
3 |
|
|
* Copyright (c) 1993 Ning and David Mosberger.
|
4 |
|
|
*
|
5 |
|
|
* This is based on code originally written by Bas Laarhoven (bas@vimec.nl)
|
6 |
|
|
* and David L. Brown, Jr., and incorporates improvements suggested by
|
7 |
|
|
* Kai Harrekilde-Petersen.
|
8 |
|
|
*
|
9 |
|
|
* This program is free software; you can redistribute it and/or
|
10 |
|
|
* modify it under the terms of the GNU General Public License as
|
11 |
|
|
* published by the Free Software Foundation; either version 2, or (at
|
12 |
|
|
* your option) any later version.
|
13 |
|
|
*
|
14 |
|
|
* This program is distributed in the hope that it will be useful, but
|
15 |
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
16 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
17 |
|
|
* General Public License for more details.
|
18 |
|
|
*
|
19 |
|
|
* You should have received a copy of the GNU General Public License
|
20 |
|
|
* along with this program; see the file COPYING. If not, write to
|
21 |
|
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
|
22 |
|
|
* USA.
|
23 |
|
|
*
|
24 |
|
|
* $Source: /home/marcus/revision_ctrl_test/oc_cvs/cvs/or1k/rc203soc/sw/uClinux/drivers/char/ftape/ecc.c,v $
|
25 |
|
|
* $Author: jcastillo $
|
26 |
|
|
*
|
27 |
|
|
* $Revision: 1.1 $
|
28 |
|
|
* $Date: 2005-12-20 10:16:52 $
|
29 |
|
|
* $State: Exp $
|
30 |
|
|
*
|
31 |
|
|
* This file contains the Reed-Solomon error correction code
|
32 |
|
|
* for the QIC-40/80 floppy-tape driver for Linux.
|
33 |
|
|
*/
|
34 |
|
|
|
35 |
|
|
#include <linux/ftape.h>
|
36 |
|
|
#include <asm/errno.h>
|
37 |
|
|
|
38 |
|
|
#include "tracing.h"
|
39 |
|
|
#include "ecc.h"
|
40 |
|
|
|
41 |
|
|
/*
|
42 |
|
|
* Machines that are big-endian should define macro BIG_ENDIAN.
|
43 |
|
|
* Unfortunately, there doesn't appear to be a standard include
|
44 |
|
|
* file that works for all OSs.
|
45 |
|
|
*/
|
46 |
|
|
|
47 |
|
|
#if defined(__sparc__) || defined(__hppa)
|
48 |
|
|
#define BIG_ENDIAN
|
49 |
|
|
#endif /* __sparc__ || __hppa */
|
50 |
|
|
|
51 |
|
|
#if defined(__mips__)
|
52 |
|
|
#error Find a smart way to determine the Endianness of the MIPS CPU
|
53 |
|
|
#endif
|
54 |
|
|
|
55 |
|
|
#ifdef TEST
|
56 |
|
|
|
57 |
|
|
#undef TRACE()
|
58 |
|
|
#undef TRACE_()
|
59 |
|
|
#undef TRACE()
|
60 |
|
|
#undef TRACEi()
|
61 |
|
|
#undef TRACElx()
|
62 |
|
|
#undef TRACE_FUN()
|
63 |
|
|
#undef TRACE_EXIT
|
64 |
|
|
#define printk printf
|
65 |
|
|
#define TRACE_FUN( level, name) char __fun[] = name
|
66 |
|
|
#define TRACE_EXIT
|
67 |
|
|
#define TRACE_(l,m) { if (ftape_ecc_tracing >= (l) && (l) <= TOP_LEVEL) { \
|
68 |
|
|
printk( "[%03d] " __FILE__ " (%s) - ", (int)ftape_trace_id++, __fun); \
|
69 |
|
|
m; } }
|
70 |
|
|
#define TRACE(l,m) TRACE_(l,printk(m".\n"))
|
71 |
|
|
#define TRACEi(l,m,i) TRACE_(l,printk(m" %d.\n",i))
|
72 |
|
|
#define TRACElx(l,m,i) TRACE_(l,printk(m" 0x%08lx.\n",i))
|
73 |
|
|
|
74 |
|
|
int ftape_ecc_tracing = 1;
|
75 |
|
|
unsigned char ftape_trace_id = 0;
|
76 |
|
|
|
77 |
|
|
#endif /* TEST */
|
78 |
|
|
|
79 |
|
|
/*
|
80 |
|
|
* Notice: to minimize the potential for confusion, we use r to
|
81 |
|
|
* denote the independent variable of the polynomials
|
82 |
|
|
* in the Galois Field GF(2^8). We reserve x for polynomials
|
83 |
|
|
* that have coefficients in GF(2^8).
|
84 |
|
|
*
|
85 |
|
|
* The Galois Field in which coefficient arithmetic is performed are
|
86 |
|
|
* the polynomials over Z_2 (i.e., 0 and 1) modulo the irreducible
|
87 |
|
|
* polynomial f(r), where f(r)=r^8 + r^7 + r^2 + r + 1. A polynomial
|
88 |
|
|
* is represented as a byte with the MSB as the coefficient of r^7 and
|
89 |
|
|
* the LSB as the coefficient of r^0. For example, the binary
|
90 |
|
|
* representation of f(x) is 0x187 (of course, this doesn't fit into 8
|
91 |
|
|
* bits). In this field, the polynomial r is a primitive element.
|
92 |
|
|
* That is, r^i with i in 0,...,255 enumerates all elements in the
|
93 |
|
|
* field.
|
94 |
|
|
*
|
95 |
|
|
* The generator polynomial for the QIC-80 ECC is
|
96 |
|
|
*
|
97 |
|
|
* g(x) = x^3 + r^105*x^2 + r^105*x + 1
|
98 |
|
|
*
|
99 |
|
|
* which can be factored into:
|
100 |
|
|
*
|
101 |
|
|
* g(x) = (x-r^-1)(x-r^0)(x-r^1)
|
102 |
|
|
*
|
103 |
|
|
* the byte representation of the coefficients are:
|
104 |
|
|
*
|
105 |
|
|
* r^105 = 0xc0
|
106 |
|
|
* r^-1 = 0xc3
|
107 |
|
|
* r^0 = 0x01
|
108 |
|
|
* r^1 = 0x02
|
109 |
|
|
*
|
110 |
|
|
* Notice that r^-1 = r^254 as exponent arithmetic is performed
|
111 |
|
|
* modulo 2^8-1 = 255.
|
112 |
|
|
*
|
113 |
|
|
* For more information on Galois Fields and Reed-Solomon codes,
|
114 |
|
|
* refer to any good book. I found _An Introduction to Error
|
115 |
|
|
* Correcting Codes with Applications_ by S. A. Vanstone and
|
116 |
|
|
* P. C. van Oorschot to be a good introduction into the former.
|
117 |
|
|
* _CODING THEORY: The Essentials_ I found very useful for its
|
118 |
|
|
* concise description of Reed-Solomon encoding/decoding.
|
119 |
|
|
*
|
120 |
|
|
*/
|
121 |
|
|
|
122 |
|
|
typedef unsigned char Matrix[3][3];
|
123 |
|
|
|
124 |
|
|
/*
|
125 |
|
|
* gfpow[] is defined such that gfpow[i] returns r^i if
|
126 |
|
|
* i is in the range [0..255].
|
127 |
|
|
*/
|
128 |
|
|
static const unsigned char gfpow[] =
|
129 |
|
|
{
|
130 |
|
|
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
|
131 |
|
|
0x87, 0x89, 0x95, 0xad, 0xdd, 0x3d, 0x7a, 0xf4,
|
132 |
|
|
0x6f, 0xde, 0x3b, 0x76, 0xec, 0x5f, 0xbe, 0xfb,
|
133 |
|
|
0x71, 0xe2, 0x43, 0x86, 0x8b, 0x91, 0xa5, 0xcd,
|
134 |
|
|
0x1d, 0x3a, 0x74, 0xe8, 0x57, 0xae, 0xdb, 0x31,
|
135 |
|
|
0x62, 0xc4, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, 0x67,
|
136 |
|
|
0xce, 0x1b, 0x36, 0x6c, 0xd8, 0x37, 0x6e, 0xdc,
|
137 |
|
|
0x3f, 0x7e, 0xfc, 0x7f, 0xfe, 0x7b, 0xf6, 0x6b,
|
138 |
|
|
0xd6, 0x2b, 0x56, 0xac, 0xdf, 0x39, 0x72, 0xe4,
|
139 |
|
|
0x4f, 0x9e, 0xbb, 0xf1, 0x65, 0xca, 0x13, 0x26,
|
140 |
|
|
0x4c, 0x98, 0xb7, 0xe9, 0x55, 0xaa, 0xd3, 0x21,
|
141 |
|
|
0x42, 0x84, 0x8f, 0x99, 0xb5, 0xed, 0x5d, 0xba,
|
142 |
|
|
0xf3, 0x61, 0xc2, 0x03, 0x06, 0x0c, 0x18, 0x30,
|
143 |
|
|
0x60, 0xc0, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0,
|
144 |
|
|
0x47, 0x8e, 0x9b, 0xb1, 0xe5, 0x4d, 0x9a, 0xb3,
|
145 |
|
|
0xe1, 0x45, 0x8a, 0x93, 0xa1, 0xc5, 0x0d, 0x1a,
|
146 |
|
|
0x34, 0x68, 0xd0, 0x27, 0x4e, 0x9c, 0xbf, 0xf9,
|
147 |
|
|
0x75, 0xea, 0x53, 0xa6, 0xcb, 0x11, 0x22, 0x44,
|
148 |
|
|
0x88, 0x97, 0xa9, 0xd5, 0x2d, 0x5a, 0xb4, 0xef,
|
149 |
|
|
0x59, 0xb2, 0xe3, 0x41, 0x82, 0x83, 0x81, 0x85,
|
150 |
|
|
0x8d, 0x9d, 0xbd, 0xfd, 0x7d, 0xfa, 0x73, 0xe6,
|
151 |
|
|
0x4b, 0x96, 0xab, 0xd1, 0x25, 0x4a, 0x94, 0xaf,
|
152 |
|
|
0xd9, 0x35, 0x6a, 0xd4, 0x2f, 0x5e, 0xbc, 0xff,
|
153 |
|
|
0x79, 0xf2, 0x63, 0xc6, 0x0b, 0x16, 0x2c, 0x58,
|
154 |
|
|
0xb0, 0xe7, 0x49, 0x92, 0xa3, 0xc1, 0x05, 0x0a,
|
155 |
|
|
0x14, 0x28, 0x50, 0xa0, 0xc7, 0x09, 0x12, 0x24,
|
156 |
|
|
0x48, 0x90, 0xa7, 0xc9, 0x15, 0x2a, 0x54, 0xa8,
|
157 |
|
|
0xd7, 0x29, 0x52, 0xa4, 0xcf, 0x19, 0x32, 0x64,
|
158 |
|
|
0xc8, 0x17, 0x2e, 0x5c, 0xb8, 0xf7, 0x69, 0xd2,
|
159 |
|
|
0x23, 0x46, 0x8c, 0x9f, 0xb9, 0xf5, 0x6d, 0xda,
|
160 |
|
|
0x33, 0x66, 0xcc, 0x1f, 0x3e, 0x7c, 0xf8, 0x77,
|
161 |
|
|
0xee, 0x5b, 0xb6, 0xeb, 0x51, 0xa2, 0xc3, 0x01
|
162 |
|
|
};
|
163 |
|
|
|
164 |
|
|
/*
|
165 |
|
|
* This is a log table. That is, gflog[r^i] returns i (modulo f(r)).
|
166 |
|
|
* gflog[0] is undefined and the first element is therefore not valid.
|
167 |
|
|
*/
|
168 |
|
|
static const unsigned char gflog[256] =
|
169 |
|
|
{
|
170 |
|
|
0xff, 0x00, 0x01, 0x63, 0x02, 0xc6, 0x64, 0x6a,
|
171 |
|
|
0x03, 0xcd, 0xc7, 0xbc, 0x65, 0x7e, 0x6b, 0x2a,
|
172 |
|
|
0x04, 0x8d, 0xce, 0x4e, 0xc8, 0xd4, 0xbd, 0xe1,
|
173 |
|
|
0x66, 0xdd, 0x7f, 0x31, 0x6c, 0x20, 0x2b, 0xf3,
|
174 |
|
|
0x05, 0x57, 0x8e, 0xe8, 0xcf, 0xac, 0x4f, 0x83,
|
175 |
|
|
0xc9, 0xd9, 0xd5, 0x41, 0xbe, 0x94, 0xe2, 0xb4,
|
176 |
|
|
0x67, 0x27, 0xde, 0xf0, 0x80, 0xb1, 0x32, 0x35,
|
177 |
|
|
0x6d, 0x45, 0x21, 0x12, 0x2c, 0x0d, 0xf4, 0x38,
|
178 |
|
|
0x06, 0x9b, 0x58, 0x1a, 0x8f, 0x79, 0xe9, 0x70,
|
179 |
|
|
0xd0, 0xc2, 0xad, 0xa8, 0x50, 0x75, 0x84, 0x48,
|
180 |
|
|
0xca, 0xfc, 0xda, 0x8a, 0xd6, 0x54, 0x42, 0x24,
|
181 |
|
|
0xbf, 0x98, 0x95, 0xf9, 0xe3, 0x5e, 0xb5, 0x15,
|
182 |
|
|
0x68, 0x61, 0x28, 0xba, 0xdf, 0x4c, 0xf1, 0x2f,
|
183 |
|
|
0x81, 0xe6, 0xb2, 0x3f, 0x33, 0xee, 0x36, 0x10,
|
184 |
|
|
0x6e, 0x18, 0x46, 0xa6, 0x22, 0x88, 0x13, 0xf7,
|
185 |
|
|
0x2d, 0xb8, 0x0e, 0x3d, 0xf5, 0xa4, 0x39, 0x3b,
|
186 |
|
|
0x07, 0x9e, 0x9c, 0x9d, 0x59, 0x9f, 0x1b, 0x08,
|
187 |
|
|
0x90, 0x09, 0x7a, 0x1c, 0xea, 0xa0, 0x71, 0x5a,
|
188 |
|
|
0xd1, 0x1d, 0xc3, 0x7b, 0xae, 0x0a, 0xa9, 0x91,
|
189 |
|
|
0x51, 0x5b, 0x76, 0x72, 0x85, 0xa1, 0x49, 0xeb,
|
190 |
|
|
0xcb, 0x7c, 0xfd, 0xc4, 0xdb, 0x1e, 0x8b, 0xd2,
|
191 |
|
|
0xd7, 0x92, 0x55, 0xaa, 0x43, 0x0b, 0x25, 0xaf,
|
192 |
|
|
0xc0, 0x73, 0x99, 0x77, 0x96, 0x5c, 0xfa, 0x52,
|
193 |
|
|
0xe4, 0xec, 0x5f, 0x4a, 0xb6, 0xa2, 0x16, 0x86,
|
194 |
|
|
0x69, 0xc5, 0x62, 0xfe, 0x29, 0x7d, 0xbb, 0xcc,
|
195 |
|
|
0xe0, 0xd3, 0x4d, 0x8c, 0xf2, 0x1f, 0x30, 0xdc,
|
196 |
|
|
0x82, 0xab, 0xe7, 0x56, 0xb3, 0x93, 0x40, 0xd8,
|
197 |
|
|
0x34, 0xb0, 0xef, 0x26, 0x37, 0x0c, 0x11, 0x44,
|
198 |
|
|
0x6f, 0x78, 0x19, 0x9a, 0x47, 0x74, 0xa7, 0xc1,
|
199 |
|
|
0x23, 0x53, 0x89, 0xfb, 0x14, 0x5d, 0xf8, 0x97,
|
200 |
|
|
0x2e, 0x4b, 0xb9, 0x60, 0x0f, 0xed, 0x3e, 0xe5,
|
201 |
|
|
0xf6, 0x87, 0xa5, 0x17, 0x3a, 0xa3, 0x3c, 0xb7
|
202 |
|
|
};
|
203 |
|
|
|
204 |
|
|
/*
|
205 |
|
|
* This is a multiplication table for the factor
|
206 |
|
|
* 0xc0 (i.e., r^105 (modulo f(r)).
|
207 |
|
|
* gfmul_c0[f] returns r^105 * f(r) (modulo f(r)).
|
208 |
|
|
*/
|
209 |
|
|
static const unsigned char gfmul_c0[256] =
|
210 |
|
|
{
|
211 |
|
|
0x00, 0xc0, 0x07, 0xc7, 0x0e, 0xce, 0x09, 0xc9,
|
212 |
|
|
0x1c, 0xdc, 0x1b, 0xdb, 0x12, 0xd2, 0x15, 0xd5,
|
213 |
|
|
0x38, 0xf8, 0x3f, 0xff, 0x36, 0xf6, 0x31, 0xf1,
|
214 |
|
|
0x24, 0xe4, 0x23, 0xe3, 0x2a, 0xea, 0x2d, 0xed,
|
215 |
|
|
0x70, 0xb0, 0x77, 0xb7, 0x7e, 0xbe, 0x79, 0xb9,
|
216 |
|
|
0x6c, 0xac, 0x6b, 0xab, 0x62, 0xa2, 0x65, 0xa5,
|
217 |
|
|
0x48, 0x88, 0x4f, 0x8f, 0x46, 0x86, 0x41, 0x81,
|
218 |
|
|
0x54, 0x94, 0x53, 0x93, 0x5a, 0x9a, 0x5d, 0x9d,
|
219 |
|
|
0xe0, 0x20, 0xe7, 0x27, 0xee, 0x2e, 0xe9, 0x29,
|
220 |
|
|
0xfc, 0x3c, 0xfb, 0x3b, 0xf2, 0x32, 0xf5, 0x35,
|
221 |
|
|
0xd8, 0x18, 0xdf, 0x1f, 0xd6, 0x16, 0xd1, 0x11,
|
222 |
|
|
0xc4, 0x04, 0xc3, 0x03, 0xca, 0x0a, 0xcd, 0x0d,
|
223 |
|
|
0x90, 0x50, 0x97, 0x57, 0x9e, 0x5e, 0x99, 0x59,
|
224 |
|
|
0x8c, 0x4c, 0x8b, 0x4b, 0x82, 0x42, 0x85, 0x45,
|
225 |
|
|
0xa8, 0x68, 0xaf, 0x6f, 0xa6, 0x66, 0xa1, 0x61,
|
226 |
|
|
0xb4, 0x74, 0xb3, 0x73, 0xba, 0x7a, 0xbd, 0x7d,
|
227 |
|
|
0x47, 0x87, 0x40, 0x80, 0x49, 0x89, 0x4e, 0x8e,
|
228 |
|
|
0x5b, 0x9b, 0x5c, 0x9c, 0x55, 0x95, 0x52, 0x92,
|
229 |
|
|
0x7f, 0xbf, 0x78, 0xb8, 0x71, 0xb1, 0x76, 0xb6,
|
230 |
|
|
0x63, 0xa3, 0x64, 0xa4, 0x6d, 0xad, 0x6a, 0xaa,
|
231 |
|
|
0x37, 0xf7, 0x30, 0xf0, 0x39, 0xf9, 0x3e, 0xfe,
|
232 |
|
|
0x2b, 0xeb, 0x2c, 0xec, 0x25, 0xe5, 0x22, 0xe2,
|
233 |
|
|
0x0f, 0xcf, 0x08, 0xc8, 0x01, 0xc1, 0x06, 0xc6,
|
234 |
|
|
0x13, 0xd3, 0x14, 0xd4, 0x1d, 0xdd, 0x1a, 0xda,
|
235 |
|
|
0xa7, 0x67, 0xa0, 0x60, 0xa9, 0x69, 0xae, 0x6e,
|
236 |
|
|
0xbb, 0x7b, 0xbc, 0x7c, 0xb5, 0x75, 0xb2, 0x72,
|
237 |
|
|
0x9f, 0x5f, 0x98, 0x58, 0x91, 0x51, 0x96, 0x56,
|
238 |
|
|
0x83, 0x43, 0x84, 0x44, 0x8d, 0x4d, 0x8a, 0x4a,
|
239 |
|
|
0xd7, 0x17, 0xd0, 0x10, 0xd9, 0x19, 0xde, 0x1e,
|
240 |
|
|
0xcb, 0x0b, 0xcc, 0x0c, 0xc5, 0x05, 0xc2, 0x02,
|
241 |
|
|
0xef, 0x2f, 0xe8, 0x28, 0xe1, 0x21, 0xe6, 0x26,
|
242 |
|
|
0xf3, 0x33, 0xf4, 0x34, 0xfd, 0x3d, 0xfa, 0x3a
|
243 |
|
|
};
|
244 |
|
|
|
245 |
|
|
|
246 |
|
|
/*
|
247 |
|
|
* Returns V modulo 255 provided V is in the range -255,-254,...,509.
|
248 |
|
|
*/
|
249 |
|
|
static inline unsigned char mod255(int v)
|
250 |
|
|
{
|
251 |
|
|
if (v > 0) {
|
252 |
|
|
if (v < 255) {
|
253 |
|
|
return v;
|
254 |
|
|
} else {
|
255 |
|
|
return v - 255;
|
256 |
|
|
}
|
257 |
|
|
} else {
|
258 |
|
|
return v + 255;
|
259 |
|
|
}
|
260 |
|
|
}
|
261 |
|
|
|
262 |
|
|
|
263 |
|
|
/*
|
264 |
|
|
* Add two numbers in the field. Addition in this field is
|
265 |
|
|
* equivalent to a bit-wise exclusive OR operation---subtraction
|
266 |
|
|
* is therefore identical to addition.
|
267 |
|
|
*/
|
268 |
|
|
static inline unsigned char gfadd(unsigned char a, unsigned char b)
|
269 |
|
|
{
|
270 |
|
|
return a ^ b;
|
271 |
|
|
}
|
272 |
|
|
|
273 |
|
|
|
274 |
|
|
/*
|
275 |
|
|
* Add two vectors of numbers in the field. Each byte in A and B get
|
276 |
|
|
* added individually.
|
277 |
|
|
*/
|
278 |
|
|
static inline unsigned long gfadd_long(unsigned long a, unsigned long b)
|
279 |
|
|
{
|
280 |
|
|
return a ^ b;
|
281 |
|
|
}
|
282 |
|
|
|
283 |
|
|
|
284 |
|
|
/*
|
285 |
|
|
* Multiply two numbers in the field:
|
286 |
|
|
*/
|
287 |
|
|
static inline unsigned char gfmul(unsigned char a, unsigned char b)
|
288 |
|
|
{
|
289 |
|
|
if (a && b) {
|
290 |
|
|
return gfpow[mod255(gflog[a] + gflog[b])];
|
291 |
|
|
} else {
|
292 |
|
|
return 0;
|
293 |
|
|
}
|
294 |
|
|
}
|
295 |
|
|
|
296 |
|
|
|
297 |
|
|
/*
|
298 |
|
|
* Just like gfmul, except we have already looked up the log
|
299 |
|
|
* of the second number.
|
300 |
|
|
*/
|
301 |
|
|
static inline unsigned char gfmul_exp(unsigned char a, int b)
|
302 |
|
|
{
|
303 |
|
|
if (a) {
|
304 |
|
|
return gfpow[mod255(gflog[a] + b)];
|
305 |
|
|
} else {
|
306 |
|
|
return 0;
|
307 |
|
|
}
|
308 |
|
|
}
|
309 |
|
|
|
310 |
|
|
|
311 |
|
|
/*
|
312 |
|
|
* Just like gfmul_exp, except that A is a vector of numbers. That is,
|
313 |
|
|
* each byte in A gets multiplied by gfpow[mod255(B)].
|
314 |
|
|
*/
|
315 |
|
|
static inline unsigned long gfmul_exp_long(unsigned long a, int b)
|
316 |
|
|
{
|
317 |
|
|
TRACE_FUN(8, "gfmul_exp_long");
|
318 |
|
|
unsigned char t;
|
319 |
|
|
|
320 |
|
|
if (sizeof(long) == 4) {
|
321 |
|
|
TRACE_EXIT;
|
322 |
|
|
return
|
323 |
|
|
((t = a >> 24 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 24) : 0) |
|
324 |
|
|
((t = a >> 16 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 16) : 0) |
|
325 |
|
|
((t = a >> 8 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 8) : 0) |
|
326 |
|
|
((t = a >> 0 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 0) : 0);
|
327 |
|
|
#if !defined(linux)
|
328 |
|
|
} else if (sizeof(long) == 8) {
|
329 |
|
|
TRACE_EXIT;
|
330 |
|
|
return
|
331 |
|
|
((t = a >> 56 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 56) : 0) |
|
332 |
|
|
((t = a >> 48 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 48) : 0) |
|
333 |
|
|
((t = a >> 40 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 40) : 0) |
|
334 |
|
|
((t = a >> 32 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 32) : 0) |
|
335 |
|
|
((t = a >> 24 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 24) : 0) |
|
336 |
|
|
((t = a >> 16 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 16) : 0) |
|
337 |
|
|
((t = a >> 8 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 8) : 0) |
|
338 |
|
|
((t = a >> 0 & 0xff) ? (((unsigned long) gfpow[mod255(gflog[t] + b)]) << 0) : 0);
|
339 |
|
|
#endif
|
340 |
|
|
} else {
|
341 |
|
|
TRACEx1(1, "Error: size of long is %d bytes", (int) sizeof(long));
|
342 |
|
|
}
|
343 |
|
|
TRACE_EXIT;
|
344 |
|
|
return -1;
|
345 |
|
|
}
|
346 |
|
|
|
347 |
|
|
|
348 |
|
|
/*
|
349 |
|
|
* Divide two numbers in the field. Returns a/b (modulo f(x)).
|
350 |
|
|
*/
|
351 |
|
|
static inline unsigned char gfdiv(unsigned char a, unsigned char b)
|
352 |
|
|
{
|
353 |
|
|
TRACE_FUN(8, "gfdiv");
|
354 |
|
|
if (!b) {
|
355 |
|
|
TRACE(-1, "Error: division by zero");
|
356 |
|
|
return 0xff;
|
357 |
|
|
} else if (a == 0) {
|
358 |
|
|
return 0;
|
359 |
|
|
} else {
|
360 |
|
|
return gfpow[mod255(gflog[a] - gflog[b])];
|
361 |
|
|
}
|
362 |
|
|
TRACE_EXIT;
|
363 |
|
|
}
|
364 |
|
|
|
365 |
|
|
|
366 |
|
|
/*
|
367 |
|
|
* The following functions return the inverse of the matrix of the
|
368 |
|
|
* linear system that needs to be solved to determine the error
|
369 |
|
|
* magnitudes. The first deals with matrices of rank 3, while the
|
370 |
|
|
* second deals with matrices of rank 2. The error indices are passed
|
371 |
|
|
* in arguments L0,..,L2 (0=first sector, 31=last sector). The
|
372 |
|
|
* error indices must be sorted in ascending order, i.e., L0<L1<L2.
|
373 |
|
|
*
|
374 |
|
|
* The linear system that needs to be solved for the error
|
375 |
|
|
* magnitudes is A * b = s, where s is the known vector of
|
376 |
|
|
* syndromes, b is the vector of error magnitudes and A in
|
377 |
|
|
* the ORDER=3 case:
|
378 |
|
|
*
|
379 |
|
|
* A_3 = {{1/r^L[0], 1/r^L[1], 1/r^L[2]},
|
380 |
|
|
* { 1, 1, 1},
|
381 |
|
|
* { r^L[0], r^L[1], r^L[2]}}
|
382 |
|
|
*/
|
383 |
|
|
static inline int gfinv3(unsigned char l0, unsigned char l1, unsigned char l2, Matrix Ainv)
|
384 |
|
|
{
|
385 |
|
|
TRACE_FUN(8, "gfinv3");
|
386 |
|
|
unsigned char det;
|
387 |
|
|
unsigned char t20, t10, t21, t12, t01, t02;
|
388 |
|
|
int log_det;
|
389 |
|
|
|
390 |
|
|
/* compute some intermediate results: */
|
391 |
|
|
t20 = gfpow[l2 - l0]; /* t20 = r^l2/r^l0 */
|
392 |
|
|
t10 = gfpow[l1 - l0]; /* t10 = r^l1/r^l0 */
|
393 |
|
|
t21 = gfpow[l2 - l1]; /* t21 = r^l2/r^l1 */
|
394 |
|
|
t12 = gfpow[l1 - l2 + 255]; /* t12 = r^l1/r^l2 */
|
395 |
|
|
t01 = gfpow[l0 - l1 + 255]; /* t01 = r^l0/r^l1 */
|
396 |
|
|
t02 = gfpow[l0 - l2 + 255]; /* t02 = r^l0/r^l2 */
|
397 |
|
|
/*
|
398 |
|
|
* Calculate the determinant of matrix A_3^-1 (sometimes called
|
399 |
|
|
* the Vandermonde determinant):
|
400 |
|
|
*/
|
401 |
|
|
det = gfadd(t20, gfadd(t10, gfadd(t21, gfadd(t12, gfadd(t01, t02)))));
|
402 |
|
|
if (!det) {
|
403 |
|
|
TRACE(1, "Inversion failed (3 CRC errors, >0 CRC failures)");
|
404 |
|
|
TRACE_EXIT;
|
405 |
|
|
return 0;
|
406 |
|
|
}
|
407 |
|
|
log_det = 255 - gflog[det];
|
408 |
|
|
|
409 |
|
|
/*
|
410 |
|
|
* Now, calculate all of the coefficients:
|
411 |
|
|
*/
|
412 |
|
|
Ainv[0][0] = gfmul_exp(gfadd(gfpow[l1], gfpow[l2]), log_det);
|
413 |
|
|
Ainv[0][1] = gfmul_exp(gfadd(t21, t12), log_det);
|
414 |
|
|
Ainv[0][2] = gfmul_exp(gfadd(gfpow[255 - l1], gfpow[255 - l2]), log_det);
|
415 |
|
|
|
416 |
|
|
Ainv[1][0] = gfmul_exp(gfadd(gfpow[l0], gfpow[l2]), log_det);
|
417 |
|
|
Ainv[1][1] = gfmul_exp(gfadd(t20, t02), log_det);
|
418 |
|
|
Ainv[1][2] = gfmul_exp(gfadd(gfpow[255 - l0], gfpow[255 - l2]), log_det);
|
419 |
|
|
|
420 |
|
|
Ainv[2][0] = gfmul_exp(gfadd(gfpow[l0], gfpow[l1]), log_det);
|
421 |
|
|
Ainv[2][1] = gfmul_exp(gfadd(t10, t01), log_det);
|
422 |
|
|
Ainv[2][2] = gfmul_exp(gfadd(gfpow[255 - l0], gfpow[255 - l1]), log_det);
|
423 |
|
|
|
424 |
|
|
TRACE_EXIT;
|
425 |
|
|
return 1;
|
426 |
|
|
}
|
427 |
|
|
|
428 |
|
|
|
429 |
|
|
static inline int gfinv2(unsigned char l0, unsigned char l1, Matrix Ainv)
|
430 |
|
|
{
|
431 |
|
|
TRACE_FUN(8, "gfinv2");
|
432 |
|
|
unsigned char det;
|
433 |
|
|
unsigned char t1, t2;
|
434 |
|
|
int log_det;
|
435 |
|
|
|
436 |
|
|
t1 = gfpow[255 - l0];
|
437 |
|
|
t2 = gfpow[255 - l1];
|
438 |
|
|
det = gfadd(t1, t2);
|
439 |
|
|
if (!det) {
|
440 |
|
|
TRACE(1, "Inversion failed (2 CRC errors, >0 CRC failures)");
|
441 |
|
|
TRACE_EXIT;
|
442 |
|
|
return 0;
|
443 |
|
|
}
|
444 |
|
|
log_det = 255 - gflog[det];
|
445 |
|
|
|
446 |
|
|
/*
|
447 |
|
|
* Now, calculate all of the coefficients:
|
448 |
|
|
*/
|
449 |
|
|
Ainv[0][0] = Ainv[1][0] = gfpow[log_det];
|
450 |
|
|
|
451 |
|
|
Ainv[0][1] = gfmul_exp(t2, log_det);
|
452 |
|
|
Ainv[1][1] = gfmul_exp(t1, log_det);
|
453 |
|
|
|
454 |
|
|
TRACE_EXIT;
|
455 |
|
|
return 1;
|
456 |
|
|
}
|
457 |
|
|
|
458 |
|
|
|
459 |
|
|
/*
|
460 |
|
|
* Multiply matrix A by vector S and return result in vector B.
|
461 |
|
|
* M is assumed to be of order NxN, S and B of order Nx1.
|
462 |
|
|
*/
|
463 |
|
|
static inline void gfmat_mul(int n, Matrix A, unsigned char *s, unsigned char *b)
|
464 |
|
|
{
|
465 |
|
|
int i, j;
|
466 |
|
|
unsigned char dot_prod;
|
467 |
|
|
|
468 |
|
|
for (i = 0; i < n; ++i) {
|
469 |
|
|
dot_prod = 0;
|
470 |
|
|
for (j = 0; j < n; ++j) {
|
471 |
|
|
dot_prod = gfadd(dot_prod, gfmul(A[i][j], s[j]));
|
472 |
|
|
}
|
473 |
|
|
b[i] = dot_prod;
|
474 |
|
|
}
|
475 |
|
|
}
|
476 |
|
|
|
477 |
|
|
|
478 |
|
|
|
479 |
|
|
/*
|
480 |
|
|
* The Reed Solomon ECC codes are computed over the N-th byte of each
|
481 |
|
|
* block, where N=SECTOR_SIZE. There are up to 29 blocks of data, and
|
482 |
|
|
* 3 blocks of ECC. The blocks are stored contiguously in memory.
|
483 |
|
|
* A segment, consequently, is assumed to have at least 4 blocks:
|
484 |
|
|
* one or more data blocks plus three ECC blocks.
|
485 |
|
|
*
|
486 |
|
|
* Notice: In QIC-80 speak, a CRC error is a sector with an incorrect
|
487 |
|
|
* CRC. A CRC failure is a sector with incorrect data, but
|
488 |
|
|
* a valid CRC. In the error control literature, the former
|
489 |
|
|
* is usually called "erasure", the latter "error."
|
490 |
|
|
*/
|
491 |
|
|
/*
|
492 |
|
|
* Compute the parity bytes for C columns of data, where C is the
|
493 |
|
|
* number of bytes that fit into a long integer. We use a linear
|
494 |
|
|
* feed-back register to do this. The parity bytes P[0], P[STRIDE],
|
495 |
|
|
* P[2*STRIDE] are computed such that:
|
496 |
|
|
*
|
497 |
|
|
* x^k * p(x) + m(x) = 0 (modulo g(x))
|
498 |
|
|
*
|
499 |
|
|
* where k = NBLOCKS,
|
500 |
|
|
* p(x) = P[0] + P[STRIDE]*x + P[2*STRIDE]*x^2, and
|
501 |
|
|
* m(x) = sum_{i=0}^k m_i*x^i.
|
502 |
|
|
* m_i = DATA[i*SECTOR_SIZE]
|
503 |
|
|
*/
|
504 |
|
|
static inline void set_parity(unsigned long *data, int nblocks, unsigned long *p, int stride)
|
505 |
|
|
{
|
506 |
|
|
TRACE_FUN(8, "set_parity");
|
507 |
|
|
unsigned long p0, p1, p2, t1, t2, *end;
|
508 |
|
|
|
509 |
|
|
end = data + nblocks * (SECTOR_SIZE / sizeof(long));
|
510 |
|
|
p0 = p1 = p2 = 0;
|
511 |
|
|
while (data < end) {
|
512 |
|
|
/*
|
513 |
|
|
* The new parity bytes p0_i, p1_i, p2_i are computed from the old
|
514 |
|
|
* values p0_{i-1}, p1_{i-1}, p2_{i-1} recursively as:
|
515 |
|
|
*
|
516 |
|
|
* p0_i = p1_{i-1} + r^105 * (m_{i-1} - p0_{i-1})
|
517 |
|
|
* p1_i = p2_{i-1} + r^105 * (m_{i-1} - p0_{i-1})
|
518 |
|
|
* p2_i = (m_{i-1} - p0_{i-1})
|
519 |
|
|
*
|
520 |
|
|
* With the initial condition: p0_0 = p1_0 = p2_0 = 0.
|
521 |
|
|
*/
|
522 |
|
|
t1 = gfadd_long(*data, p0);
|
523 |
|
|
/*
|
524 |
|
|
* Multiply each byte in t1 by 0xc0:
|
525 |
|
|
*/
|
526 |
|
|
if (sizeof(long) == 4) {
|
527 |
|
|
t2 = ((unsigned long) gfmul_c0[t1 >> 24 & 0xff]) << 24 |
|
528 |
|
|
((unsigned long) gfmul_c0[t1 >> 16 & 0xff]) << 16 |
|
529 |
|
|
((unsigned long) gfmul_c0[t1 >> 8 & 0xff]) << 8 |
|
530 |
|
|
((unsigned long) gfmul_c0[t1 >> 0 & 0xff]) << 0;
|
531 |
|
|
#if !defined(linux)
|
532 |
|
|
} else if (sizeof(long) == 8) {
|
533 |
|
|
t2 = ((unsigned long) gfmul_c0[t1 >> 56 & 0xff]) << 56 |
|
534 |
|
|
((unsigned long) gfmul_c0[t1 >> 48 & 0xff]) << 48 |
|
535 |
|
|
((unsigned long) gfmul_c0[t1 >> 40 & 0xff]) << 40 |
|
536 |
|
|
((unsigned long) gfmul_c0[t1 >> 32 & 0xff]) << 32 |
|
537 |
|
|
((unsigned long) gfmul_c0[t1 >> 24 & 0xff]) << 24 |
|
538 |
|
|
((unsigned long) gfmul_c0[t1 >> 16 & 0xff]) << 16 |
|
539 |
|
|
((unsigned long) gfmul_c0[t1 >> 8 & 0xff]) << 8 |
|
540 |
|
|
((unsigned long) gfmul_c0[t1 >> 0 & 0xff]) << 0;
|
541 |
|
|
#endif
|
542 |
|
|
} else {
|
543 |
|
|
TRACEx1(1, "Error: long is of size %d", (int) sizeof(long));
|
544 |
|
|
}
|
545 |
|
|
p0 = gfadd_long(t2, p1);
|
546 |
|
|
p1 = gfadd_long(t2, p2);
|
547 |
|
|
p2 = t1;
|
548 |
|
|
data += SECTOR_SIZE / sizeof(long);
|
549 |
|
|
}
|
550 |
|
|
*p = p0;
|
551 |
|
|
p += stride;
|
552 |
|
|
*p = p1;
|
553 |
|
|
p += stride;
|
554 |
|
|
*p = p2;
|
555 |
|
|
TRACE_EXIT;
|
556 |
|
|
}
|
557 |
|
|
|
558 |
|
|
|
559 |
|
|
/*
|
560 |
|
|
* Compute the 3 syndrome values. DATA should point to the first byte
|
561 |
|
|
* of the column for which the syndromes are desired. The syndromes
|
562 |
|
|
* are computed over the first NBLOCKS of rows. The three bytes will be
|
563 |
|
|
* placed in S[0], S[1], and S[2].
|
564 |
|
|
*
|
565 |
|
|
* S[i] is the value of the "message" polynomial m(x) evaluated at the
|
566 |
|
|
* i-th root of the generator polynomial g(x).
|
567 |
|
|
*
|
568 |
|
|
* As g(x)=(x-r^-1)(x-1)(x-r^1) we evaluate the message polynomial at
|
569 |
|
|
* x=r^-1 to get S[0], at x=r^0=1 to get S[1], and at x=r to get S[2].
|
570 |
|
|
* This could be done directly and efficiently via the Horner scheme.
|
571 |
|
|
* However, it would require multiplication tables for the factors
|
572 |
|
|
* r^-1 (0xc3) and r (0x02). The following scheme does not require
|
573 |
|
|
* any multiplication tables beyond what's needed for set_parity()
|
574 |
|
|
* anyway and is slightly faster if there are no errors and slightly
|
575 |
|
|
* slower if there are errors. The latter is hopefully the infrequent
|
576 |
|
|
* case.
|
577 |
|
|
*
|
578 |
|
|
* To understand the alternative algorithm, notice that
|
579 |
|
|
* set_parity(m, k, p) computes parity bytes such that:
|
580 |
|
|
*
|
581 |
|
|
* x^k * p(x) = m(x) (modulo g(x)).
|
582 |
|
|
*
|
583 |
|
|
* That is, to evaluate m(r^m), where r^m is a root of g(x), we can
|
584 |
|
|
* simply evaluate (r^m)^k*p(r^m). Also, notice that p is 0 if and
|
585 |
|
|
* only if s is zero. That is, if all parity bytes are 0, we know
|
586 |
|
|
* there is no error in the data and consequently there is no need to
|
587 |
|
|
* compute s(x) at all! In all other cases, we compute s(x) from p(x)
|
588 |
|
|
* by evaluating (r^m)^k*p(r^m) for m=-1, m=0, and m=1. The p(x)
|
589 |
|
|
* polynomial is evaluated via the Horner scheme.
|
590 |
|
|
*/
|
591 |
|
|
static int compute_syndromes(unsigned long *data, int nblocks, unsigned long *s)
|
592 |
|
|
{
|
593 |
|
|
unsigned long p[3];
|
594 |
|
|
|
595 |
|
|
set_parity(data, nblocks, p, 1);
|
596 |
|
|
if (p[0] | p[1] | p[2]) {
|
597 |
|
|
/*
|
598 |
|
|
* Some of the checked columns do not have a zero syndrome. For
|
599 |
|
|
* simplicity, we compute the syndromes for all columns that we
|
600 |
|
|
* have computed the remainders for.
|
601 |
|
|
*/
|
602 |
|
|
s[0] = gfmul_exp_long(gfadd_long(p[0], gfmul_exp_long(gfadd_long(p[1],
|
603 |
|
|
gfmul_exp_long(p[2], -1)), -1)), -nblocks);
|
604 |
|
|
s[1] = gfadd_long(gfadd_long(p[2], p[1]), p[0]);
|
605 |
|
|
s[2] = gfmul_exp_long(gfadd_long(p[0], gfmul_exp_long(gfadd_long(p[1],
|
606 |
|
|
gfmul_exp_long(p[2], 1)), 1)), nblocks);
|
607 |
|
|
return 0;
|
608 |
|
|
} else {
|
609 |
|
|
return 1;
|
610 |
|
|
}
|
611 |
|
|
}
|
612 |
|
|
|
613 |
|
|
|
614 |
|
|
/*
|
615 |
|
|
* Correct the block in the column pointed to by DATA. There are NBAD
|
616 |
|
|
* CRC errors and their indices are in BAD_LOC[0], up to
|
617 |
|
|
* BAD_LOC[NBAD-1]. If NBAD>1, Ainv holds the inverse of the matrix
|
618 |
|
|
* of the linear system that needs to be solved to determine the error
|
619 |
|
|
* magnitudes. S[0], S[1], and S[2] are the syndrome values. If row
|
620 |
|
|
* j gets corrected, then bit j will be set in CORRECTION_MAP.
|
621 |
|
|
*/
|
622 |
|
|
static inline int correct_block(unsigned char *data, int nblocks,
|
623 |
|
|
int nbad, int *bad_loc, Matrix Ainv,
|
624 |
|
|
unsigned char *s,
|
625 |
|
|
BAD_SECTOR * correction_map)
|
626 |
|
|
{
|
627 |
|
|
TRACE_FUN(8, "correct_block");
|
628 |
|
|
int ncorrected = 0;
|
629 |
|
|
int i;
|
630 |
|
|
unsigned char t1, t2;
|
631 |
|
|
unsigned char c0, c1, c2; /* check bytes */
|
632 |
|
|
unsigned char error_mag[3], log_error_mag;
|
633 |
|
|
unsigned char *dp, l, e;
|
634 |
|
|
|
635 |
|
|
switch (nbad) {
|
636 |
|
|
case 0:
|
637 |
|
|
/* might have a CRC failure: */
|
638 |
|
|
if (s[0] == 0) {
|
639 |
|
|
/* more than one error */
|
640 |
|
|
TRACE(1, "ECC failed (0 CRC errors, >1 CRC failures)");
|
641 |
|
|
TRACE_EXIT;
|
642 |
|
|
return -1;
|
643 |
|
|
} /* if */
|
644 |
|
|
t1 = gfdiv(s[1], s[0]);
|
645 |
|
|
if ((bad_loc[nbad++] = gflog[t1]) >= nblocks) {
|
646 |
|
|
TRACE(1, "ECC failed (0 CRC errors, >1 CRC failures): ");
|
647 |
|
|
TRACEi(1, "attempt to correct data at ", bad_loc[0]);
|
648 |
|
|
TRACE_EXIT;
|
649 |
|
|
return -1;
|
650 |
|
|
}
|
651 |
|
|
error_mag[0] = s[1];
|
652 |
|
|
break;
|
653 |
|
|
case 1:
|
654 |
|
|
t1 = gfadd(gfmul_exp(s[1], bad_loc[0]), s[2]);
|
655 |
|
|
t2 = gfadd(gfmul_exp(s[0], bad_loc[0]), s[1]);
|
656 |
|
|
if (t1 == 0 && t2 == 0) {
|
657 |
|
|
/* one erasure, no error: */
|
658 |
|
|
Ainv[0][0] = gfpow[bad_loc[0]];
|
659 |
|
|
} else if (t1 == 0 || t2 == 0) {
|
660 |
|
|
/* one erasure and more than one error: */
|
661 |
|
|
TRACE(1, "ECC failed (1 erasure, >1 error)");
|
662 |
|
|
TRACE_EXIT;
|
663 |
|
|
return -1;
|
664 |
|
|
} else {
|
665 |
|
|
/* one erasure, one error: */
|
666 |
|
|
if ((bad_loc[nbad++] = gflog[gfdiv(t1, t2)]) >= nblocks) {
|
667 |
|
|
TRACE(1, "ECC failed (1 CRC errors, >1 CRC failures): ");
|
668 |
|
|
TRACEi(1, "attempt to correct data at ", bad_loc[1]);
|
669 |
|
|
TRACE_EXIT;
|
670 |
|
|
return -1;
|
671 |
|
|
} /* if */
|
672 |
|
|
if (!gfinv2(bad_loc[0], bad_loc[1], Ainv)) {
|
673 |
|
|
/* inversion failed---must have more than one error */
|
674 |
|
|
TRACE_EXIT;
|
675 |
|
|
return -1;
|
676 |
|
|
}
|
677 |
|
|
}
|
678 |
|
|
/*
|
679 |
|
|
* FALL THROUGH TO ERROR MAGNITUDE COMPUTATION:
|
680 |
|
|
*/
|
681 |
|
|
case 2:
|
682 |
|
|
case 3:
|
683 |
|
|
/* compute error magnitudes: */
|
684 |
|
|
gfmat_mul(nbad, Ainv, s, error_mag);
|
685 |
|
|
break;
|
686 |
|
|
|
687 |
|
|
default:
|
688 |
|
|
TRACE(1, "Internal Error: number of CRC errors > 3");
|
689 |
|
|
TRACE_EXIT;
|
690 |
|
|
return -1;
|
691 |
|
|
}
|
692 |
|
|
|
693 |
|
|
/*
|
694 |
|
|
* Perform correction by adding ERROR_MAG[i] to the byte at offset
|
695 |
|
|
* BAD_LOC[i]. Also add the value of the computed error polynomial
|
696 |
|
|
* to the syndrome values. If the correction was successful, the
|
697 |
|
|
* resulting check bytes should be zero (i.e., the corrected data
|
698 |
|
|
* is a valid code word).
|
699 |
|
|
*/
|
700 |
|
|
c0 = s[0];
|
701 |
|
|
c1 = s[1];
|
702 |
|
|
c2 = s[2];
|
703 |
|
|
for (i = 0; i < nbad; ++i) {
|
704 |
|
|
e = error_mag[i];
|
705 |
|
|
if (e) {
|
706 |
|
|
/* correct the byte at offset L by magnitude E: */
|
707 |
|
|
l = bad_loc[i];
|
708 |
|
|
dp = &data[l * SECTOR_SIZE];
|
709 |
|
|
*dp = gfadd(*dp, e);
|
710 |
|
|
*correction_map |= 1 << l;
|
711 |
|
|
++ncorrected;
|
712 |
|
|
|
713 |
|
|
log_error_mag = gflog[e];
|
714 |
|
|
c0 = gfadd(c0, gfpow[mod255(log_error_mag - l)]);
|
715 |
|
|
c1 = gfadd(c1, e);
|
716 |
|
|
c2 = gfadd(c2, gfpow[mod255(log_error_mag + l)]);
|
717 |
|
|
}
|
718 |
|
|
}
|
719 |
|
|
if (c0 || c1 || c2) {
|
720 |
|
|
TRACE(1, "ECC self-check failed, too many errors");
|
721 |
|
|
TRACE_EXIT;
|
722 |
|
|
return -1;
|
723 |
|
|
}
|
724 |
|
|
TRACE_EXIT;
|
725 |
|
|
return ncorrected;
|
726 |
|
|
}
|
727 |
|
|
|
728 |
|
|
|
729 |
|
|
#if defined(ECC_SANITY_CHECK) || defined(ECC_PARANOID)
|
730 |
|
|
|
731 |
|
|
/*
|
732 |
|
|
* Perform a sanity check on the computed parity bytes:
|
733 |
|
|
*/
|
734 |
|
|
static int sanity_check(unsigned long *data, int nblocks)
|
735 |
|
|
{
|
736 |
|
|
TRACE_FUN(8, "sanity_check");
|
737 |
|
|
unsigned long s[3];
|
738 |
|
|
|
739 |
|
|
if (!compute_syndromes(data, nblocks, s)) {
|
740 |
|
|
TRACE(-1, "Internal Error: syndrome self-check failed");
|
741 |
|
|
TRACE_EXIT;
|
742 |
|
|
return 0;
|
743 |
|
|
}
|
744 |
|
|
TRACE_EXIT;
|
745 |
|
|
return 1;
|
746 |
|
|
}
|
747 |
|
|
|
748 |
|
|
#endif /* defined(ECC_SANITY_CHECK) || defined(ECC_PARANOID) */
|
749 |
|
|
|
750 |
|
|
|
751 |
|
|
|
752 |
|
|
/*
|
753 |
|
|
* Compute the parity for an entire segment of data.
|
754 |
|
|
*/
|
755 |
|
|
int ecc_set_segment_parity(struct memory_segment *mseg)
|
756 |
|
|
{
|
757 |
|
|
int i;
|
758 |
|
|
unsigned char *parity_bytes;
|
759 |
|
|
|
760 |
|
|
parity_bytes = &mseg->data[(mseg->blocks - 3) * SECTOR_SIZE];
|
761 |
|
|
for (i = 0; i < SECTOR_SIZE; i += sizeof(long)) {
|
762 |
|
|
set_parity((unsigned long *) &mseg->data[i], mseg->blocks - 3,
|
763 |
|
|
(unsigned long *) &parity_bytes[i],
|
764 |
|
|
SECTOR_SIZE / sizeof(long));
|
765 |
|
|
#ifdef ECC_PARANOID
|
766 |
|
|
if (!sanity_check((unsigned long *) &mseg->data[i], mseg->blocks)) {
|
767 |
|
|
return -1;
|
768 |
|
|
}
|
769 |
|
|
#endif /* ECC_PARANOID */
|
770 |
|
|
}
|
771 |
|
|
return 0;
|
772 |
|
|
}
|
773 |
|
|
|
774 |
|
|
|
775 |
|
|
/*
|
776 |
|
|
* Checks and corrects (if possible) the segment MSEG. Returns one of
|
777 |
|
|
* ECC_OK, ECC_CORRECTED, and ECC_FAILED.
|
778 |
|
|
*/
|
779 |
|
|
int ecc_correct_data(struct memory_segment *mseg)
|
780 |
|
|
{
|
781 |
|
|
TRACE_FUN(5, "ecc_correct_data");
|
782 |
|
|
int col, i, result;
|
783 |
|
|
int ncorrected = 0;
|
784 |
|
|
int nerasures = 0; /* # of erasures (CRC errors) */
|
785 |
|
|
int erasure_loc[3]; /* erasure locations */
|
786 |
|
|
unsigned long ss[3];
|
787 |
|
|
unsigned char s[3];
|
788 |
|
|
Matrix Ainv;
|
789 |
|
|
|
790 |
|
|
mseg->corrected = 0;
|
791 |
|
|
|
792 |
|
|
/* find first column that has non-zero syndromes: */
|
793 |
|
|
for (col = 0; col < SECTOR_SIZE; col += sizeof(long)) {
|
794 |
|
|
if (!compute_syndromes((unsigned long *) &mseg->data[col],
|
795 |
|
|
mseg->blocks, ss)) {
|
796 |
|
|
/* something is wrong---have to fix things */
|
797 |
|
|
break;
|
798 |
|
|
}
|
799 |
|
|
}
|
800 |
|
|
if (col >= SECTOR_SIZE) {
|
801 |
|
|
/* all syndromes are ok, therefore nothing to correct */
|
802 |
|
|
TRACE_EXIT;
|
803 |
|
|
return ECC_OK;
|
804 |
|
|
}
|
805 |
|
|
/* count the number of CRC errors if there were any: */
|
806 |
|
|
if (mseg->read_bad) {
|
807 |
|
|
for (i = 0; i < mseg->blocks; i++) {
|
808 |
|
|
if (BAD_CHECK(mseg->read_bad, i)) {
|
809 |
|
|
if (nerasures >= 3) {
|
810 |
|
|
/* this is too much for ECC */
|
811 |
|
|
TRACE(1, "ECC failed (>3 CRC errors)");
|
812 |
|
|
TRACE_EXIT;
|
813 |
|
|
return ECC_FAILED;
|
814 |
|
|
} /* if */
|
815 |
|
|
erasure_loc[nerasures++] = i;
|
816 |
|
|
}
|
817 |
|
|
}
|
818 |
|
|
}
|
819 |
|
|
/*
|
820 |
|
|
* If there are at least 2 CRC errors, determine inverse of matrix
|
821 |
|
|
* of linear system to be solved:
|
822 |
|
|
*/
|
823 |
|
|
switch (nerasures) {
|
824 |
|
|
case 2:
|
825 |
|
|
if (!gfinv2(erasure_loc[0], erasure_loc[1], Ainv)) {
|
826 |
|
|
TRACE_EXIT;
|
827 |
|
|
return ECC_FAILED;
|
828 |
|
|
}
|
829 |
|
|
break;
|
830 |
|
|
case 3:
|
831 |
|
|
if (!gfinv3(erasure_loc[0], erasure_loc[1], erasure_loc[2], Ainv)) {
|
832 |
|
|
TRACE_EXIT;
|
833 |
|
|
return ECC_FAILED;
|
834 |
|
|
}
|
835 |
|
|
break;
|
836 |
|
|
default:
|
837 |
|
|
/* this is not an error condition... */
|
838 |
|
|
break;
|
839 |
|
|
}
|
840 |
|
|
|
841 |
|
|
do {
|
842 |
|
|
for (i = 0; i < sizeof(long); ++i) {
|
843 |
|
|
s[0] = ss[0];
|
844 |
|
|
s[1] = ss[1];
|
845 |
|
|
s[2] = ss[2];
|
846 |
|
|
if (s[0] | s[1] | s[2]) {
|
847 |
|
|
#ifdef BIG_ENDIAN
|
848 |
|
|
result = correct_block(&mseg->data[col + sizeof(long) - 1 - i],
|
849 |
|
|
mseg->blocks,
|
850 |
|
|
nerasures, erasure_loc, Ainv, s,
|
851 |
|
|
&mseg->corrected);
|
852 |
|
|
#else
|
853 |
|
|
result = correct_block(&mseg->data[col + i], mseg->blocks,
|
854 |
|
|
nerasures, erasure_loc, Ainv, s,
|
855 |
|
|
&mseg->corrected);
|
856 |
|
|
#endif
|
857 |
|
|
if (result < 0) {
|
858 |
|
|
TRACE_EXIT;
|
859 |
|
|
return ECC_FAILED;
|
860 |
|
|
}
|
861 |
|
|
ncorrected += result;
|
862 |
|
|
}
|
863 |
|
|
ss[0] >>= 8;
|
864 |
|
|
ss[1] >>= 8;
|
865 |
|
|
ss[2] >>= 8;
|
866 |
|
|
}
|
867 |
|
|
|
868 |
|
|
#ifdef ECC_SANITY_CHECK
|
869 |
|
|
if (!sanity_check((unsigned long *) &mseg->data[col], mseg->blocks)) {
|
870 |
|
|
TRACE_EXIT;
|
871 |
|
|
return ECC_FAILED;
|
872 |
|
|
}
|
873 |
|
|
#endif /* ECC_SANITY_CHECK */
|
874 |
|
|
|
875 |
|
|
/* find next column with non-zero syndromes: */
|
876 |
|
|
while ((col += sizeof(long)) < SECTOR_SIZE) {
|
877 |
|
|
if (!compute_syndromes((unsigned long *) &mseg->data[col],
|
878 |
|
|
mseg->blocks, ss)) {
|
879 |
|
|
/* something is wrong---have to fix things */
|
880 |
|
|
break;
|
881 |
|
|
}
|
882 |
|
|
}
|
883 |
|
|
} while (col < SECTOR_SIZE);
|
884 |
|
|
if (ncorrected && nerasures == 0) {
|
885 |
|
|
TRACE(2, "block contained error not caught by CRC");
|
886 |
|
|
}
|
887 |
|
|
TRACEi((ncorrected > 0) ? 4 : 8, "number of corrections:", ncorrected);
|
888 |
|
|
TRACE_EXIT;
|
889 |
|
|
return ncorrected ? ECC_CORRECTED : ECC_OK;
|
890 |
|
|
}
|
891 |
|
|
|
892 |
|
|
/*** end of ecc.c ***/
|