Cleanup patch - Remove all trailing whitespace and fix a few typos.
[yaffs2.git] / yaffs_tagscompat.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2007 Aleph One Ltd.
5  *   for Toby Churchill Ltd and Brightstar Engineering
6  *
7  * Created by Charles Manning <charles@aleph1.co.uk>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13
14 #include "yaffs_guts.h"
15 #include "yaffs_tagscompat.h"
16 #include "yaffs_ecc.h"
17
18 static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND);
19 #ifdef NOTYET
20 static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND);
21 static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
22                                      const __u8 * data,
23                                      const yaffs_Spare * spare);
24 static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
25                                     const yaffs_Spare * spare);
26 static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND);
27 #endif
28
29 static const char yaffs_countBitsTable[256] = {
30         0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
31         1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
32         1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
33         2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
34         1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
35         2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
36         2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
37         3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
38         1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
39         2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
40         2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
41         3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
42         2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
43         3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
44         3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
45         4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
46 };
47
48 int yaffs_CountBits(__u8 x)
49 {
50         int retVal;
51         retVal = yaffs_countBitsTable[x];
52         return retVal;
53 }
54
55 /********** Tags ECC calculations  *********/
56
57 void yaffs_CalcECC(const __u8 * data, yaffs_Spare * spare)
58 {
59         yaffs_ECCCalculate(data, spare->ecc1);
60         yaffs_ECCCalculate(&data[256], spare->ecc2);
61 }
62
63 void yaffs_CalcTagsECC(yaffs_Tags * tags)
64 {
65         /* Calculate an ecc */
66
67         unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
68         unsigned i, j;
69         unsigned ecc = 0;
70         unsigned bit = 0;
71
72         tags->ecc = 0;
73
74         for (i = 0; i < 8; i++) {
75                 for (j = 1; j & 0xff; j <<= 1) {
76                         bit++;
77                         if (b[i] & j) {
78                                 ecc ^= bit;
79                         }
80                 }
81         }
82
83         tags->ecc = ecc;
84
85 }
86
87 int yaffs_CheckECCOnTags(yaffs_Tags * tags)
88 {
89         unsigned ecc = tags->ecc;
90
91         yaffs_CalcTagsECC(tags);
92
93         ecc ^= tags->ecc;
94
95         if (ecc && ecc <= 64) {
96                 /* TODO: Handle the failure better. Retire? */
97                 unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
98
99                 ecc--;
100
101                 b[ecc / 8] ^= (1 << (ecc & 7));
102
103                 /* Now recvalc the ecc */
104                 yaffs_CalcTagsECC(tags);
105
106                 return 1;       /* recovered error */
107         } else if (ecc) {
108                 /* Wierd ecc failure value */
109                 /* TODO Need to do somethiong here */
110                 return -1;      /* unrecovered error */
111         }
112
113         return 0;
114 }
115
116 /********** Tags **********/
117
118 static void yaffs_LoadTagsIntoSpare(yaffs_Spare * sparePtr,
119                                     yaffs_Tags * tagsPtr)
120 {
121         yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
122
123         yaffs_CalcTagsECC(tagsPtr);
124
125         sparePtr->tagByte0 = tu->asBytes[0];
126         sparePtr->tagByte1 = tu->asBytes[1];
127         sparePtr->tagByte2 = tu->asBytes[2];
128         sparePtr->tagByte3 = tu->asBytes[3];
129         sparePtr->tagByte4 = tu->asBytes[4];
130         sparePtr->tagByte5 = tu->asBytes[5];
131         sparePtr->tagByte6 = tu->asBytes[6];
132         sparePtr->tagByte7 = tu->asBytes[7];
133 }
134
135 static void yaffs_GetTagsFromSpare(yaffs_Device * dev, yaffs_Spare * sparePtr,
136                                    yaffs_Tags * tagsPtr)
137 {
138         yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
139         int result;
140
141         tu->asBytes[0] = sparePtr->tagByte0;
142         tu->asBytes[1] = sparePtr->tagByte1;
143         tu->asBytes[2] = sparePtr->tagByte2;
144         tu->asBytes[3] = sparePtr->tagByte3;
145         tu->asBytes[4] = sparePtr->tagByte4;
146         tu->asBytes[5] = sparePtr->tagByte5;
147         tu->asBytes[6] = sparePtr->tagByte6;
148         tu->asBytes[7] = sparePtr->tagByte7;
149
150         result = yaffs_CheckECCOnTags(tagsPtr);
151         if (result > 0) {
152                 dev->tagsEccFixed++;
153         } else if (result < 0) {
154                 dev->tagsEccUnfixed++;
155         }
156 }
157
158 static void yaffs_SpareInitialise(yaffs_Spare * spare)
159 {
160         memset(spare, 0xFF, sizeof(yaffs_Spare));
161 }
162
163 static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
164                                   int chunkInNAND, const __u8 * data,
165                                   yaffs_Spare * spare)
166 {
167         if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
168                 T(YAFFS_TRACE_ERROR,
169                   (TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
170                    chunkInNAND));
171                 return YAFFS_FAIL;
172         }
173
174         dev->nPageWrites++;
175         return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
176 }
177
178 static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
179                                    int chunkInNAND,
180                                    __u8 * data,
181                                    yaffs_Spare * spare,
182                                    yaffs_ECCResult * eccResult,
183                                    int doErrorCorrection)
184 {
185         int retVal;
186         yaffs_Spare localSpare;
187
188         dev->nPageReads++;
189
190         if (!spare && data) {
191                 /* If we don't have a real spare, then we use a local one. */
192                 /* Need this for the calculation of the ecc */
193                 spare = &localSpare;
194         }
195
196         if (!dev->useNANDECC) {
197                 retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
198                 if (data && doErrorCorrection) {
199                         /* Do ECC correction */
200                         /* Todo handle any errors */
201                         int eccResult1, eccResult2;
202                         __u8 calcEcc[3];
203
204                         yaffs_ECCCalculate(data, calcEcc);
205                         eccResult1 =
206                             yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
207                         yaffs_ECCCalculate(&data[256], calcEcc);
208                         eccResult2 =
209                             yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
210
211                         if (eccResult1 > 0) {
212                                 T(YAFFS_TRACE_ERROR,
213                                   (TSTR
214                                    ("**>>yaffs ecc error fix performed on chunk %d:0"
215                                     TENDSTR), chunkInNAND));
216                                 dev->eccFixed++;
217                         } else if (eccResult1 < 0) {
218                                 T(YAFFS_TRACE_ERROR,
219                                   (TSTR
220                                    ("**>>yaffs ecc error unfixed on chunk %d:0"
221                                     TENDSTR), chunkInNAND));
222                                 dev->eccUnfixed++;
223                         }
224
225                         if (eccResult2 > 0) {
226                                 T(YAFFS_TRACE_ERROR,
227                                   (TSTR
228                                    ("**>>yaffs ecc error fix performed on chunk %d:1"
229                                     TENDSTR), chunkInNAND));
230                                 dev->eccFixed++;
231                         } else if (eccResult2 < 0) {
232                                 T(YAFFS_TRACE_ERROR,
233                                   (TSTR
234                                    ("**>>yaffs ecc error unfixed on chunk %d:1"
235                                     TENDSTR), chunkInNAND));
236                                 dev->eccUnfixed++;
237                         }
238
239                         if (eccResult1 || eccResult2) {
240                                 /* We had a data problem on this page */
241                                 yaffs_HandleReadDataError(dev, chunkInNAND);
242                         }
243
244                         if (eccResult1 < 0 || eccResult2 < 0)
245                                 *eccResult = YAFFS_ECC_RESULT_UNFIXED;
246                         else if (eccResult1 > 0 || eccResult2 > 0)
247                                 *eccResult = YAFFS_ECC_RESULT_FIXED;
248                         else
249                                 *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
250                 }
251         } else {
252                 /* Must allocate enough memory for spare+2*sizeof(int) */
253                 /* for ecc results from device. */
254                 struct yaffs_NANDSpare nspare;
255                 retVal =
256                     dev->readChunkFromNAND(dev, chunkInNAND, data,
257                                            (yaffs_Spare *) & nspare);
258                 memcpy(spare, &nspare, sizeof(yaffs_Spare));
259                 if (data && doErrorCorrection) {
260                         if (nspare.eccres1 > 0) {
261                                 T(YAFFS_TRACE_ERROR,
262                                   (TSTR
263                                    ("**>>mtd ecc error fix performed on chunk %d:0"
264                                     TENDSTR), chunkInNAND));
265                         } else if (nspare.eccres1 < 0) {
266                                 T(YAFFS_TRACE_ERROR,
267                                   (TSTR
268                                    ("**>>mtd ecc error unfixed on chunk %d:0"
269                                     TENDSTR), chunkInNAND));
270                         }
271
272                         if (nspare.eccres2 > 0) {
273                                 T(YAFFS_TRACE_ERROR,
274                                   (TSTR
275                                    ("**>>mtd ecc error fix performed on chunk %d:1"
276                                     TENDSTR), chunkInNAND));
277                         } else if (nspare.eccres2 < 0) {
278                                 T(YAFFS_TRACE_ERROR,
279                                   (TSTR
280                                    ("**>>mtd ecc error unfixed on chunk %d:1"
281                                     TENDSTR), chunkInNAND));
282                         }
283
284                         if (nspare.eccres1 || nspare.eccres2) {
285                                 /* We had a data problem on this page */
286                                 yaffs_HandleReadDataError(dev, chunkInNAND);
287                         }
288
289                         if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
290                                 *eccResult = YAFFS_ECC_RESULT_UNFIXED;
291                         else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
292                                 *eccResult = YAFFS_ECC_RESULT_FIXED;
293                         else
294                                 *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
295
296                 }
297         }
298         return retVal;
299 }
300
301 #ifdef NOTYET
302 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
303                                   int chunkInNAND)
304 {
305
306         static int init = 0;
307         static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
308         static __u8 data[YAFFS_BYTES_PER_CHUNK];
309         /* Might as well always allocate the larger size for */
310         /* dev->useNANDECC == true; */
311         static __u8 spare[sizeof(struct yaffs_NANDSpare)];
312
313         dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
314
315         if (!init) {
316                 memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
317                 init = 1;
318         }
319
320         if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK))
321                 return YAFFS_FAIL;
322         if (memcmp(cmpbuf, spare, 16))
323                 return YAFFS_FAIL;
324
325         return YAFFS_OK;
326
327 }
328 #endif
329
330 /*
331  * Functions for robustisizing
332  */
333
334 static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND)
335 {
336         int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
337
338         /* Mark the block for retirement */
339         yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
340         T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
341           (TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));
342
343         /* TODO:
344          * Just do a garbage collection on the affected block
345          * then retire the block
346          * NB recursion
347          */
348 }
349
350 #ifdef NOTYET
351 static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND)
352 {
353 }
354
355 static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
356                                      const __u8 * data,
357                                      const yaffs_Spare * spare)
358 {
359 }
360
361 static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
362                                     const yaffs_Spare * spare)
363 {
364 }
365
366 static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND)
367 {
368         int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
369
370         /* Mark the block for retirement */
371         yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
372         /* Delete the chunk */
373         yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
374 }
375
376 static int yaffs_VerifyCompare(const __u8 * d0, const __u8 * d1,
377                                const yaffs_Spare * s0, const yaffs_Spare * s1)
378 {
379
380         if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
381             s0->tagByte0 != s1->tagByte0 ||
382             s0->tagByte1 != s1->tagByte1 ||
383             s0->tagByte2 != s1->tagByte2 ||
384             s0->tagByte3 != s1->tagByte3 ||
385             s0->tagByte4 != s1->tagByte4 ||
386             s0->tagByte5 != s1->tagByte5 ||
387             s0->tagByte6 != s1->tagByte6 ||
388             s0->tagByte7 != s1->tagByte7 ||
389             s0->ecc1[0] != s1->ecc1[0] ||
390             s0->ecc1[1] != s1->ecc1[1] ||
391             s0->ecc1[2] != s1->ecc1[2] ||
392             s0->ecc2[0] != s1->ecc2[0] ||
393             s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) {
394                 return 0;
395         }
396
397         return 1;
398 }
399 #endif                          /* NOTYET */
400
401 int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev,
402                                                     int chunkInNAND,
403                                                     const __u8 * data,
404                                                     const yaffs_ExtendedTags *
405                                                     eTags)
406 {
407         yaffs_Spare spare;
408         yaffs_Tags tags;
409
410         yaffs_SpareInitialise(&spare);
411
412         if (eTags->chunkDeleted) {
413                 spare.pageStatus = 0;
414         } else {
415                 tags.objectId = eTags->objectId;
416                 tags.chunkId = eTags->chunkId;
417                 tags.byteCount = eTags->byteCount;
418                 tags.serialNumber = eTags->serialNumber;
419
420                 if (!dev->useNANDECC && data) {
421                         yaffs_CalcECC(data, &spare);
422                 }
423                 yaffs_LoadTagsIntoSpare(&spare, &tags);
424
425         }
426
427         return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);
428 }
429
430 int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
431                                                      int chunkInNAND,
432                                                      __u8 * data,
433                                                      yaffs_ExtendedTags * eTags)
434 {
435
436         yaffs_Spare spare;
437         yaffs_Tags tags;
438         yaffs_ECCResult eccResult;
439
440         static yaffs_Spare spareFF;
441         static int init;
442
443         if (!init) {
444                 memset(&spareFF, 0xFF, sizeof(spareFF));
445                 init = 1;
446         }
447
448         if (yaffs_ReadChunkFromNAND
449             (dev, chunkInNAND, data, &spare, &eccResult, 1)) {
450                 /* eTags may be NULL */
451                 if (eTags) {
452
453                         int deleted =
454                             (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
455
456                         eTags->chunkDeleted = deleted;
457                         eTags->eccResult = eccResult;
458                         eTags->blockBad = 0;    /* We're reading it */
459                         /* therefore it is not a bad block */
460                         eTags->chunkUsed =
461                             (memcmp(&spareFF, &spare, sizeof(spareFF)) !=
462                              0) ? 1 : 0;
463
464                         if (eTags->chunkUsed) {
465                                 yaffs_GetTagsFromSpare(dev, &spare, &tags);
466
467                                 eTags->objectId = tags.objectId;
468                                 eTags->chunkId = tags.chunkId;
469                                 eTags->byteCount = tags.byteCount;
470                                 eTags->serialNumber = tags.serialNumber;
471                         }
472                 }
473
474                 return YAFFS_OK;
475         } else {
476                 return YAFFS_FAIL;
477         }
478 }
479
480 int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
481                                             int blockInNAND)
482 {
483
484         yaffs_Spare spare;
485
486         memset(&spare, 0xff, sizeof(yaffs_Spare));
487
488         spare.blockStatus = 'Y';
489
490         yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
491                                &spare);
492         yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
493                                NULL, &spare);
494
495         return YAFFS_OK;
496
497 }
498
499 int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
500                                           int blockNo, yaffs_BlockState *
501                                           state,
502                                           int *sequenceNumber)
503 {
504
505         yaffs_Spare spare0, spare1;
506         static yaffs_Spare spareFF;
507         static int init;
508         yaffs_ECCResult dummy;
509
510         if (!init) {
511                 memset(&spareFF, 0xFF, sizeof(spareFF));
512                 init = 1;
513         }
514
515         *sequenceNumber = 0;
516
517         yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
518                                 &spare0, &dummy, 1);
519         yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
520                                 &spare1, &dummy, 1);
521
522         if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
523                 *state = YAFFS_BLOCK_STATE_DEAD;
524         else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
525                 *state = YAFFS_BLOCK_STATE_EMPTY;
526         else
527                 *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
528
529         return YAFFS_OK;
530 }