OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [ftape/] [lowlevel/] [ftape-ecc.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.