Add large NAND support and improve retirement handling
[yaffs2.git] / yaffs_nand.c
1 /*
2  * YAFFS: Yet another FFS. A NAND-flash specific file system. 
3  *
4  * Copyright (C) 2002 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  
15 const char *yaffs_nand_c_version =
16     "$Id: yaffs_nand.c,v 1.3 2006-10-03 10:13:03 charles Exp $";
17
18 #include "yaffs_nand.h"
19 #include "yaffs_tagscompat.h"
20 #include "yaffs_tagsvalidity.h"
21
22
23 int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
24                                            __u8 * buffer,
25                                            yaffs_ExtendedTags * tags)
26 {
27         int result;
28         yaffs_ExtendedTags localTags;
29         
30         int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
31         
32         /* If there are no tags provided, use local tags to get prioritised gc working */
33         if(!tags)
34                 tags = &localTags;
35
36         if (dev->readChunkWithTagsFromNAND)
37                 result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
38                                                       tags);
39         else
40                 result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
41                                                                         realignedChunkInNAND,
42                                                                         buffer,
43                                                                         tags);  
44         if(tags && 
45            tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR){
46         
47                 yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
48                 bi->gcPrioritise = 1;
49                 dev->hasPendingPrioritisedGCs = 1;
50         }
51                                                                 
52         return result;
53 }
54
55 int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
56                                                    int chunkInNAND,
57                                                    const __u8 * buffer,
58                                                    yaffs_ExtendedTags * tags)
59 {
60         chunkInNAND -= dev->chunkOffset;
61
62         
63         if (tags) {
64                 tags->sequenceNumber = dev->sequenceNumber;
65                 tags->chunkUsed = 1;
66                 if (!yaffs_ValidateTags(tags)) {
67                         T(YAFFS_TRACE_ERROR,
68                           (TSTR("Writing uninitialised tags" TENDSTR)));
69                         YBUG();
70                 }
71                 T(YAFFS_TRACE_WRITE,
72                   (TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND,
73                    tags->objectId, tags->chunkId));
74         } else {
75                 T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
76                 YBUG();
77         }
78
79         if (dev->writeChunkWithTagsToNAND)
80                 return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
81                                                      tags);
82         else
83                 return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
84                                                                        chunkInNAND,
85                                                                        buffer,
86                                                                        tags);
87 }
88
89 int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo)
90 {
91         blockNo -= dev->blockOffset;
92
93 ;
94         if (dev->markNANDBlockBad)
95                 return dev->markNANDBlockBad(dev, blockNo);
96         else
97                 return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
98 }
99
100 int yaffs_QueryInitialBlockState(yaffs_Device * dev,
101                                                  int blockNo,
102                                                  yaffs_BlockState * state,
103                                                  unsigned *sequenceNumber)
104 {
105         blockNo -= dev->blockOffset;
106
107         if (dev->queryNANDBlock)
108                 return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
109         else
110                 return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
111                                                              state,
112                                                              sequenceNumber);
113 }
114
115
116 int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
117                                   int blockInNAND)
118 {
119         int result;
120
121         blockInNAND -= dev->blockOffset;
122
123
124         dev->nBlockErasures++;
125         result = dev->eraseBlockInNAND(dev, blockInNAND);
126
127         /* If at first we don't succeed, try again *once*.*/
128         if (!result)
129                 result = dev->eraseBlockInNAND(dev, blockInNAND);       
130         return result;
131 }
132
133 int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
134 {
135         return dev->initialiseNAND(dev);
136 }
137
138
139