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"
18 static void yaffs_HandleReadDataError(yaffs_Device
* dev
, int chunkInNAND
);
20 static void yaffs_CheckWrittenBlock(yaffs_Device
* dev
, int chunkInNAND
);
21 static void yaffs_HandleWriteChunkOk(yaffs_Device
* dev
, int chunkInNAND
,
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
);
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
48 int yaffs_CountBits(__u8 x
)
51 retVal
= yaffs_countBitsTable
[x
];
55 /********** Tags ECC calculations *********/
57 void yaffs_CalcECC(const __u8
* data
, yaffs_Spare
* spare
)
59 yaffs_ECCCalculate(data
, spare
->ecc1
);
60 yaffs_ECCCalculate(&data
[256], spare
->ecc2
);
63 void yaffs_CalcTagsECC(yaffs_Tags
* tags
)
65 /* Calculate an ecc */
67 unsigned char *b
= ((yaffs_TagsUnion
*) tags
)->asBytes
;
74 for (i
= 0; i
< 8; i
++) {
75 for (j
= 1; j
& 0xff; j
<<= 1) {
87 int yaffs_CheckECCOnTags(yaffs_Tags
* tags
)
89 unsigned ecc
= tags
->ecc
;
91 yaffs_CalcTagsECC(tags
);
95 if (ecc
&& ecc
<= 64) {
96 /* TODO: Handle the failure better. Retire? */
97 unsigned char *b
= ((yaffs_TagsUnion
*) tags
)->asBytes
;
101 b
[ecc
/ 8] ^= (1 << (ecc
& 7));
103 /* Now recvalc the ecc */
104 yaffs_CalcTagsECC(tags
);
106 return 1; /* recovered error */
108 /* Wierd ecc failure value */
109 /* TODO Need to do somethiong here */
110 return -1; /* unrecovered error */
116 /********** Tags **********/
118 static void yaffs_LoadTagsIntoSpare(yaffs_Spare
* sparePtr
,
119 yaffs_Tags
* tagsPtr
)
121 yaffs_TagsUnion
*tu
= (yaffs_TagsUnion
*) tagsPtr
;
123 yaffs_CalcTagsECC(tagsPtr
);
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];
135 static void yaffs_GetTagsFromSpare(yaffs_Device
* dev
, yaffs_Spare
* sparePtr
,
136 yaffs_Tags
* tagsPtr
)
138 yaffs_TagsUnion
*tu
= (yaffs_TagsUnion
*) tagsPtr
;
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
;
150 result
= yaffs_CheckECCOnTags(tagsPtr
);
153 } else if (result
< 0) {
154 dev
->tagsEccUnfixed
++;
158 static void yaffs_SpareInitialise(yaffs_Spare
* spare
)
160 memset(spare
, 0xFF, sizeof(yaffs_Spare
));
163 static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct
*dev
,
164 int chunkInNAND
, const __u8
* data
,
167 if (chunkInNAND
< dev
->startBlock
* dev
->nChunksPerBlock
) {
169 (TSTR("**>> yaffs chunk %d is not valid" TENDSTR
),
175 return dev
->writeChunkToNAND(dev
, chunkInNAND
, data
, spare
);
178 static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct
*dev
,
182 yaffs_ECCResult
* eccResult
,
183 int doErrorCorrection
)
186 yaffs_Spare localSpare
;
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 */
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
;
204 yaffs_ECCCalculate(data
, calcEcc
);
206 yaffs_ECCCorrect(data
, spare
->ecc1
, calcEcc
);
207 yaffs_ECCCalculate(&data
[256], calcEcc
);
209 yaffs_ECCCorrect(&data
[256], spare
->ecc2
, calcEcc
);
211 if (eccResult1
> 0) {
214 ("**>>yaffs ecc error fix performed on chunk %d:0"
215 TENDSTR
), chunkInNAND
));
217 } else if (eccResult1
< 0) {
220 ("**>>yaffs ecc error unfixed on chunk %d:0"
221 TENDSTR
), chunkInNAND
));
225 if (eccResult2
> 0) {
228 ("**>>yaffs ecc error fix performed on chunk %d:1"
229 TENDSTR
), chunkInNAND
));
231 } else if (eccResult2
< 0) {
234 ("**>>yaffs ecc error unfixed on chunk %d:1"
235 TENDSTR
), chunkInNAND
));
239 if (eccResult1
|| eccResult2
) {
240 /* We had a data problem on this page */
241 yaffs_HandleReadDataError(dev
, chunkInNAND
);
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
;
249 *eccResult
= YAFFS_ECC_RESULT_NO_ERROR
;
252 /* Must allocate enough memory for spare+2*sizeof(int) */
253 /* for ecc results from device. */
254 struct yaffs_NANDSpare nspare
;
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) {
263 ("**>>mtd ecc error fix performed on chunk %d:0"
264 TENDSTR
), chunkInNAND
));
265 } else if (nspare
.eccres1
< 0) {
268 ("**>>mtd ecc error unfixed on chunk %d:0"
269 TENDSTR
), chunkInNAND
));
272 if (nspare
.eccres2
> 0) {
275 ("**>>mtd ecc error fix performed on chunk %d:1"
276 TENDSTR
), chunkInNAND
));
277 } else if (nspare
.eccres2
< 0) {
280 ("**>>mtd ecc error unfixed on chunk %d:1"
281 TENDSTR
), chunkInNAND
));
284 if (nspare
.eccres1
|| nspare
.eccres2
) {
285 /* We had a data problem on this page */
286 yaffs_HandleReadDataError(dev
, chunkInNAND
);
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
;
294 *eccResult
= YAFFS_ECC_RESULT_NO_ERROR
;
302 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct
*dev
,
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
)];
313 dev
->readChunkFromNAND(dev
, chunkInNAND
, data
, (yaffs_Spare
*) spare
);
316 memset(cmpbuf
, 0xff, YAFFS_BYTES_PER_CHUNK
);
320 if (memcmp(cmpbuf
, data
, YAFFS_BYTES_PER_CHUNK
))
322 if (memcmp(cmpbuf
, spare
, 16))
331 * Functions for robustisizing
334 static void yaffs_HandleReadDataError(yaffs_Device
* dev
, int chunkInNAND
)
336 int blockInNAND
= chunkInNAND
/ dev
->nChunksPerBlock
;
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
));
344 * Just do a garbage collection on the affected block
345 * then retire the block
351 static void yaffs_CheckWrittenBlock(yaffs_Device
* dev
, int chunkInNAND
)
355 static void yaffs_HandleWriteChunkOk(yaffs_Device
* dev
, int chunkInNAND
,
357 const yaffs_Spare
* spare
)
361 static void yaffs_HandleUpdateChunk(yaffs_Device
* dev
, int chunkInNAND
,
362 const yaffs_Spare
* spare
)
366 static void yaffs_HandleWriteChunkError(yaffs_Device
* dev
, int chunkInNAND
)
368 int blockInNAND
= chunkInNAND
/ dev
->nChunksPerBlock
;
370 /* Mark the block for retirement */
371 yaffs_GetBlockInfo(dev
, blockInNAND
)->needsRetiring
= 1;
372 /* Delete the chunk */
373 yaffs_DeleteChunk(dev
, chunkInNAND
, 1, __LINE__
);
376 static int yaffs_VerifyCompare(const __u8
* d0
, const __u8
* d1
,
377 const yaffs_Spare
* s0
, const yaffs_Spare
* s1
)
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]) {
401 int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device
* dev
,
404 const yaffs_ExtendedTags
*
410 yaffs_SpareInitialise(&spare
);
412 if (eTags
->chunkDeleted
) {
413 spare
.pageStatus
= 0;
415 tags
.objectId
= eTags
->objectId
;
416 tags
.chunkId
= eTags
->chunkId
;
417 tags
.byteCount
= eTags
->byteCount
;
418 tags
.serialNumber
= eTags
->serialNumber
;
420 if (!dev
->useNANDECC
&& data
) {
421 yaffs_CalcECC(data
, &spare
);
423 yaffs_LoadTagsIntoSpare(&spare
, &tags
);
427 return yaffs_WriteChunkToNAND(dev
, chunkInNAND
, data
, &spare
);
430 int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device
* dev
,
433 yaffs_ExtendedTags
* eTags
)
438 yaffs_ECCResult eccResult
;
440 static yaffs_Spare spareFF
;
444 memset(&spareFF
, 0xFF, sizeof(spareFF
));
448 if (yaffs_ReadChunkFromNAND
449 (dev
, chunkInNAND
, data
, &spare
, &eccResult
, 1)) {
450 /* eTags may be NULL */
454 (yaffs_CountBits(spare
.pageStatus
) < 7) ? 1 : 0;
456 eTags
->chunkDeleted
= deleted
;
457 eTags
->eccResult
= eccResult
;
458 eTags
->blockBad
= 0; /* We're reading it */
459 /* therefore it is not a bad block */
461 (memcmp(&spareFF
, &spare
, sizeof(spareFF
)) !=
464 if (eTags
->chunkUsed
) {
465 yaffs_GetTagsFromSpare(dev
, &spare
, &tags
);
467 eTags
->objectId
= tags
.objectId
;
468 eTags
->chunkId
= tags
.chunkId
;
469 eTags
->byteCount
= tags
.byteCount
;
470 eTags
->serialNumber
= tags
.serialNumber
;
480 int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct
*dev
,
486 memset(&spare
, 0xff, sizeof(yaffs_Spare
));
488 spare
.blockStatus
= 'Y';
490 yaffs_WriteChunkToNAND(dev
, blockInNAND
* dev
->nChunksPerBlock
, NULL
,
492 yaffs_WriteChunkToNAND(dev
, blockInNAND
* dev
->nChunksPerBlock
+ 1,
499 int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct
*dev
,
500 int blockNo
, yaffs_BlockState
*
505 yaffs_Spare spare0
, spare1
;
506 static yaffs_Spare spareFF
;
508 yaffs_ECCResult dummy
;
511 memset(&spareFF
, 0xFF, sizeof(spareFF
));
517 yaffs_ReadChunkFromNAND(dev
, blockNo
* dev
->nChunksPerBlock
, NULL
,
519 yaffs_ReadChunkFromNAND(dev
, blockNo
* dev
->nChunksPerBlock
+ 1, NULL
,
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
;
527 *state
= YAFFS_BLOCK_STATE_NEEDS_SCANNING
;