| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 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: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-ecc.c,v $ | 
|  | 26 | * $Revision: 1.3 $ | 
|  | 27 | * $Date: 1997/10/05 19:18:10 $ | 
|  | 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 | } |