2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
4 * Copyright (C) 2002-2007 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
7 * Created by Charles Manning <charles@aleph1.co.uk>
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.
14 #include "yaffs_guts.h"
15 #include "yaffs_tagscompat.h"
16 #include "yaffs_ecc.h"
17 #include "yaffs_getblockinfo.h"
19 static void yaffs_HandleReadDataError(yaffs_Device
* dev
, int chunkInNAND
);
21 static void yaffs_CheckWrittenBlock(yaffs_Device
* dev
, int chunkInNAND
);
22 static void yaffs_HandleWriteChunkOk(yaffs_Device
* dev
, int chunkInNAND
,
24 const yaffs_Spare
* spare
);
25 static void yaffs_HandleUpdateChunk(yaffs_Device
* dev
, int chunkInNAND
,
26 const yaffs_Spare
* spare
);
27 static void yaffs_HandleWriteChunkError(yaffs_Device
* dev
, int chunkInNAND
);
30 static const char yaffs_countBitsTable
[256] = {
31 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
32 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
33 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
34 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
35 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
36 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
37 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
38 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
39 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
40 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
41 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
42 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
43 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
44 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
45 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
46 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
49 int yaffs_CountBits(__u8 x
)
52 retVal
= yaffs_countBitsTable
[x
];
56 /********** Tags ECC calculations *********/
58 void yaffs_CalcECC(const __u8
* data
, yaffs_Spare
* spare
)
60 yaffs_ECCCalculate(data
, spare
->ecc1
);
61 yaffs_ECCCalculate(&data
[256], spare
->ecc2
);
64 void yaffs_CalcTagsECC(yaffs_Tags
* tags
)
66 /* Calculate an ecc */
68 unsigned char *b
= ((yaffs_TagsUnion
*) tags
)->asBytes
;
75 for (i
= 0; i
< 8; i
++) {
76 for (j
= 1; j
& 0xff; j
<<= 1) {
88 int yaffs_CheckECCOnTags(yaffs_Tags
* tags
)
90 unsigned ecc
= tags
->ecc
;
92 yaffs_CalcTagsECC(tags
);
96 if (ecc
&& ecc
<= 64) {
97 /* TODO: Handle the failure better. Retire? */
98 unsigned char *b
= ((yaffs_TagsUnion
*) tags
)->asBytes
;
102 b
[ecc
/ 8] ^= (1 << (ecc
& 7));
104 /* Now recvalc the ecc */
105 yaffs_CalcTagsECC(tags
);
107 return 1; /* recovered error */
109 /* Wierd ecc failure value */
110 /* TODO Need to do somethiong here */
111 return -1; /* unrecovered error */
117 /********** Tags **********/
119 static void yaffs_LoadTagsIntoSpare(yaffs_Spare
* sparePtr
,
120 yaffs_Tags
* tagsPtr
)
122 yaffs_TagsUnion
*tu
= (yaffs_TagsUnion
*) tagsPtr
;
124 yaffs_CalcTagsECC(tagsPtr
);
126 sparePtr
->tagByte0
= tu
->asBytes
[0];
127 sparePtr
->tagByte1
= tu
->asBytes
[1];
128 sparePtr
->tagByte2
= tu
->asBytes
[2];
129 sparePtr
->tagByte3
= tu
->asBytes
[3];
130 sparePtr
->tagByte4
= tu
->asBytes
[4];
131 sparePtr
->tagByte5
= tu
->asBytes
[5];
132 sparePtr
->tagByte6
= tu
->asBytes
[6];
133 sparePtr
->tagByte7
= tu
->asBytes
[7];
136 static void yaffs_GetTagsFromSpare(yaffs_Device
* dev
, yaffs_Spare
* sparePtr
,
137 yaffs_Tags
* tagsPtr
)
139 yaffs_TagsUnion
*tu
= (yaffs_TagsUnion
*) tagsPtr
;
142 tu
->asBytes
[0] = sparePtr
->tagByte0
;
143 tu
->asBytes
[1] = sparePtr
->tagByte1
;
144 tu
->asBytes
[2] = sparePtr
->tagByte2
;
145 tu
->asBytes
[3] = sparePtr
->tagByte3
;
146 tu
->asBytes
[4] = sparePtr
->tagByte4
;
147 tu
->asBytes
[5] = sparePtr
->tagByte5
;
148 tu
->asBytes
[6] = sparePtr
->tagByte6
;
149 tu
->asBytes
[7] = sparePtr
->tagByte7
;
151 result
= yaffs_CheckECCOnTags(tagsPtr
);
154 } else if (result
< 0) {
155 dev
->tagsEccUnfixed
++;
159 static void yaffs_SpareInitialise(yaffs_Spare
* spare
)
161 memset(spare
, 0xFF, sizeof(yaffs_Spare
));
164 static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct
*dev
,
165 int chunkInNAND
, const __u8
* data
,
168 if (chunkInNAND
< dev
->startBlock
* dev
->nChunksPerBlock
) {
170 (TSTR("**>> yaffs chunk %d is not valid" TENDSTR
),
176 return dev
->writeChunkToNAND(dev
, chunkInNAND
, data
, spare
);
179 static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct
*dev
,
183 yaffs_ECCResult
* eccResult
,
184 int doErrorCorrection
)
187 yaffs_Spare localSpare
;
191 if (!spare
&& data
) {
192 /* If we don't have a real spare, then we use a local one. */
193 /* Need this for the calculation of the ecc */
197 if (!dev
->useNANDECC
) {
198 retVal
= dev
->readChunkFromNAND(dev
, chunkInNAND
, data
, spare
);
199 if (data
&& doErrorCorrection
) {
200 /* Do ECC correction */
201 /* Todo handle any errors */
202 int eccResult1
, eccResult2
;
205 yaffs_ECCCalculate(data
, calcEcc
);
207 yaffs_ECCCorrect(data
, spare
->ecc1
, calcEcc
);
208 yaffs_ECCCalculate(&data
[256], calcEcc
);
210 yaffs_ECCCorrect(&data
[256], spare
->ecc2
, calcEcc
);
212 if (eccResult1
> 0) {
215 ("**>>yaffs ecc error fix performed on chunk %d:0"
216 TENDSTR
), chunkInNAND
));
218 } else if (eccResult1
< 0) {
221 ("**>>yaffs ecc error unfixed on chunk %d:0"
222 TENDSTR
), chunkInNAND
));
226 if (eccResult2
> 0) {
229 ("**>>yaffs ecc error fix performed on chunk %d:1"
230 TENDSTR
), chunkInNAND
));
232 } else if (eccResult2
< 0) {
235 ("**>>yaffs ecc error unfixed on chunk %d:1"
236 TENDSTR
), chunkInNAND
));
240 if (eccResult1
|| eccResult2
) {
241 /* We had a data problem on this page */
242 yaffs_HandleReadDataError(dev
, chunkInNAND
);
245 if (eccResult1
< 0 || eccResult2
< 0)
246 *eccResult
= YAFFS_ECC_RESULT_UNFIXED
;
247 else if (eccResult1
> 0 || eccResult2
> 0)
248 *eccResult
= YAFFS_ECC_RESULT_FIXED
;
250 *eccResult
= YAFFS_ECC_RESULT_NO_ERROR
;
253 /* Must allocate enough memory for spare+2*sizeof(int) */
254 /* for ecc results from device. */
255 struct yaffs_NANDSpare nspare
;
257 dev
->readChunkFromNAND(dev
, chunkInNAND
, data
,
258 (yaffs_Spare
*) & nspare
);
259 memcpy(spare
, &nspare
, sizeof(yaffs_Spare
));
260 if (data
&& doErrorCorrection
) {
261 if (nspare
.eccres1
> 0) {
264 ("**>>mtd ecc error fix performed on chunk %d:0"
265 TENDSTR
), chunkInNAND
));
266 } else if (nspare
.eccres1
< 0) {
269 ("**>>mtd ecc error unfixed on chunk %d:0"
270 TENDSTR
), chunkInNAND
));
273 if (nspare
.eccres2
> 0) {
276 ("**>>mtd ecc error fix performed on chunk %d:1"
277 TENDSTR
), chunkInNAND
));
278 } else if (nspare
.eccres2
< 0) {
281 ("**>>mtd ecc error unfixed on chunk %d:1"
282 TENDSTR
), chunkInNAND
));
285 if (nspare
.eccres1
|| nspare
.eccres2
) {
286 /* We had a data problem on this page */
287 yaffs_HandleReadDataError(dev
, chunkInNAND
);
290 if (nspare
.eccres1
< 0 || nspare
.eccres2
< 0)
291 *eccResult
= YAFFS_ECC_RESULT_UNFIXED
;
292 else if (nspare
.eccres1
> 0 || nspare
.eccres2
> 0)
293 *eccResult
= YAFFS_ECC_RESULT_FIXED
;
295 *eccResult
= YAFFS_ECC_RESULT_NO_ERROR
;
303 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct
*dev
,
308 static __u8 cmpbuf
[YAFFS_BYTES_PER_CHUNK
];
309 static __u8 data
[YAFFS_BYTES_PER_CHUNK
];
310 /* Might as well always allocate the larger size for */
311 /* dev->useNANDECC == true; */
312 static __u8 spare
[sizeof(struct yaffs_NANDSpare
)];
314 dev
->readChunkFromNAND(dev
, chunkInNAND
, data
, (yaffs_Spare
*) spare
);
317 memset(cmpbuf
, 0xff, YAFFS_BYTES_PER_CHUNK
);
321 if (memcmp(cmpbuf
, data
, YAFFS_BYTES_PER_CHUNK
))
323 if (memcmp(cmpbuf
, spare
, 16))
332 * Functions for robustisizing
335 static void yaffs_HandleReadDataError(yaffs_Device
* dev
, int chunkInNAND
)
337 int blockInNAND
= chunkInNAND
/ dev
->nChunksPerBlock
;
339 /* Mark the block for retirement */
340 yaffs_GetBlockInfo(dev
, blockInNAND
)->needsRetiring
= 1;
341 T(YAFFS_TRACE_ERROR
| YAFFS_TRACE_BAD_BLOCKS
,
342 (TSTR("**>>Block %d marked for retirement" TENDSTR
), blockInNAND
));
345 * Just do a garbage collection on the affected block
346 * then retire the block
352 static void yaffs_CheckWrittenBlock(yaffs_Device
* dev
, int chunkInNAND
)
356 static void yaffs_HandleWriteChunkOk(yaffs_Device
* dev
, int chunkInNAND
,
358 const yaffs_Spare
* spare
)
362 static void yaffs_HandleUpdateChunk(yaffs_Device
* dev
, int chunkInNAND
,
363 const yaffs_Spare
* spare
)
367 static void yaffs_HandleWriteChunkError(yaffs_Device
* dev
, int chunkInNAND
)
369 int blockInNAND
= chunkInNAND
/ dev
->nChunksPerBlock
;
371 /* Mark the block for retirement */
372 yaffs_GetBlockInfo(dev
, blockInNAND
)->needsRetiring
= 1;
373 /* Delete the chunk */
374 yaffs_DeleteChunk(dev
, chunkInNAND
, 1, __LINE__
);
377 static int yaffs_VerifyCompare(const __u8
* d0
, const __u8
* d1
,
378 const yaffs_Spare
* s0
, const yaffs_Spare
* s1
)
381 if (memcmp(d0
, d1
, YAFFS_BYTES_PER_CHUNK
) != 0 ||
382 s0
->tagByte0
!= s1
->tagByte0
||
383 s0
->tagByte1
!= s1
->tagByte1
||
384 s0
->tagByte2
!= s1
->tagByte2
||
385 s0
->tagByte3
!= s1
->tagByte3
||
386 s0
->tagByte4
!= s1
->tagByte4
||
387 s0
->tagByte5
!= s1
->tagByte5
||
388 s0
->tagByte6
!= s1
->tagByte6
||
389 s0
->tagByte7
!= s1
->tagByte7
||
390 s0
->ecc1
[0] != s1
->ecc1
[0] ||
391 s0
->ecc1
[1] != s1
->ecc1
[1] ||
392 s0
->ecc1
[2] != s1
->ecc1
[2] ||
393 s0
->ecc2
[0] != s1
->ecc2
[0] ||
394 s0
->ecc2
[1] != s1
->ecc2
[1] || s0
->ecc2
[2] != s1
->ecc2
[2]) {
402 int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device
* dev
,
405 const yaffs_ExtendedTags
*
411 yaffs_SpareInitialise(&spare
);
413 if (eTags
->chunkDeleted
) {
414 spare
.pageStatus
= 0;
416 tags
.objectId
= eTags
->objectId
;
417 tags
.chunkId
= eTags
->chunkId
;
418 tags
.byteCount
= eTags
->byteCount
;
419 tags
.serialNumber
= eTags
->serialNumber
;
421 if (!dev
->useNANDECC
&& data
) {
422 yaffs_CalcECC(data
, &spare
);
424 yaffs_LoadTagsIntoSpare(&spare
, &tags
);
428 return yaffs_WriteChunkToNAND(dev
, chunkInNAND
, data
, &spare
);
431 int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device
* dev
,
434 yaffs_ExtendedTags
* eTags
)
439 yaffs_ECCResult eccResult
;
441 static yaffs_Spare spareFF
;
445 memset(&spareFF
, 0xFF, sizeof(spareFF
));
449 if (yaffs_ReadChunkFromNAND
450 (dev
, chunkInNAND
, data
, &spare
, &eccResult
, 1)) {
451 /* eTags may be NULL */
455 (yaffs_CountBits(spare
.pageStatus
) < 7) ? 1 : 0;
457 eTags
->chunkDeleted
= deleted
;
458 eTags
->eccResult
= eccResult
;
459 eTags
->blockBad
= 0; /* We're reading it */
460 /* therefore it is not a bad block */
462 (memcmp(&spareFF
, &spare
, sizeof(spareFF
)) !=
465 if (eTags
->chunkUsed
) {
466 yaffs_GetTagsFromSpare(dev
, &spare
, &tags
);
468 eTags
->objectId
= tags
.objectId
;
469 eTags
->chunkId
= tags
.chunkId
;
470 eTags
->byteCount
= tags
.byteCount
;
471 eTags
->serialNumber
= tags
.serialNumber
;
481 int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct
*dev
,
487 memset(&spare
, 0xff, sizeof(yaffs_Spare
));
489 spare
.blockStatus
= 'Y';
491 yaffs_WriteChunkToNAND(dev
, blockInNAND
* dev
->nChunksPerBlock
, NULL
,
493 yaffs_WriteChunkToNAND(dev
, blockInNAND
* dev
->nChunksPerBlock
+ 1,
500 int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct
*dev
,
502 yaffs_BlockState
*state
,
503 __u32
*sequenceNumber
)
506 yaffs_Spare spare0
, spare1
;
507 static yaffs_Spare spareFF
;
509 yaffs_ECCResult dummy
;
512 memset(&spareFF
, 0xFF, sizeof(spareFF
));
518 yaffs_ReadChunkFromNAND(dev
, blockNo
* dev
->nChunksPerBlock
, NULL
,
520 yaffs_ReadChunkFromNAND(dev
, blockNo
* dev
->nChunksPerBlock
+ 1, NULL
,
523 if (yaffs_CountBits(spare0
.blockStatus
& spare1
.blockStatus
) < 7)
524 *state
= YAFFS_BLOCK_STATE_DEAD
;
525 else if (memcmp(&spareFF
, &spare0
, sizeof(spareFF
)) == 0)
526 *state
= YAFFS_BLOCK_STATE_EMPTY
;
528 *state
= YAFFS_BLOCK_STATE_NEEDS_SCANNING
;