kernel: add missing config symbol
[15.05/openwrt.git] / target / linux / generic / patches-3.18 / 502-yaffs-fix-compat-tags-handling.patch
1 Subject: yaffs: fix compat tags handling
2
3 Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
4 ---
5 --- a/fs/yaffs2/yaffs_tagscompat.c
6 +++ b/fs/yaffs2/yaffs_tagscompat.c
7 @@ -17,7 +17,9 @@
8  #include "yaffs_getblockinfo.h"
9  #include "yaffs_trace.h"
10  
11 +#if 0
12  static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
13 +#endif
14  
15  
16  /********** Tags ECC calculations  *********/
17 @@ -71,6 +73,7 @@ int yaffs_check_tags_ecc(struct yaffs_ta
18         return 0;
19  }
20  
21 +#if 0
22  /********** Tags **********/
23  
24  static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
25 @@ -379,3 +382,214 @@ void yaffs_tags_compat_install(struct ya
26         if(!dev->tagger.mark_bad_fn)
27                 dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
28  }
29 +#else
30 +
31 +#include "yaffs_packedtags1.h"
32 +
33 +static int yaffs_tags_compat_write(struct yaffs_dev *dev,
34 +                                  int nand_chunk,
35 +                                  const u8 *data,
36 +                                  const struct yaffs_ext_tags *tags)
37 +{
38 +       struct yaffs_packed_tags1 pt1;
39 +       u8 tag_buf[9];
40 +       int retval;
41 +
42 +       /* we assume that yaffs_packed_tags1 and yaffs_tags are compatible */
43 +       compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12);
44 +       compile_time_assertion(sizeof(struct yaffs_tags) == 8);
45 +
46 +       yaffs_pack_tags1(&pt1, tags);
47 +       yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1);
48 +
49 +       /* When deleting a chunk, the upper layer provides only skeletal
50 +        * tags, one with is_deleted set.  However, we need to update the
51 +        * tags, not erase them completely.  So we use the NAND write property
52 +        * that only zeroed-bits stick and set tag bytes to all-ones and
53 +        * zero just the (not) deleted bit.
54 +        */
55 +       if (!dev->param.tags_9bytes) {
56 +               if (tags->is_deleted) {
57 +                       memset(&pt1, 0xff, 8);
58 +                       /* clear delete status bit to indicate deleted */
59 +                       pt1.deleted = 0;
60 +               }
61 +               memcpy(tag_buf, &pt1, 8);
62 +       } else {
63 +               if (tags->is_deleted) {
64 +                       memset(tag_buf, 0xff, 8);
65 +                       tag_buf[8] = 0;
66 +               } else {
67 +                       memcpy(tag_buf, &pt1, 8);
68 +                       tag_buf[8] = 0xff;
69 +               }
70 +       }
71 +
72 +       retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,
73 +                       data,
74 +                       (data) ? dev->data_bytes_per_chunk : 0,
75 +                       tag_buf,
76 +                       (dev->param.tags_9bytes) ? 9 : 8);
77 +
78 +       return retval;
79 +}
80 +
81 +/* Return with empty extended tags but add ecc_result.
82 + */
83 +static int return_empty_tags(struct yaffs_ext_tags *tags,
84 +                            enum yaffs_ecc_result ecc_result,
85 +                            int retval)
86 +{
87 +       if (tags) {
88 +               memset(tags, 0, sizeof(*tags));
89 +               tags->ecc_result = ecc_result;
90 +       }
91 +
92 +       return retval;
93 +}
94 +
95 +static int yaffs_tags_compat_read(struct yaffs_dev *dev,
96 +                                 int nand_chunk,
97 +                                 u8 *data,
98 +                                 struct yaffs_ext_tags *tags)
99 +{
100 +       struct yaffs_packed_tags1 pt1;
101 +       enum yaffs_ecc_result ecc_result;
102 +       int retval;
103 +       int deleted;
104 +       u8 tag_buf[9];
105 +
106 +       retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
107 +                       data, dev->param.total_bytes_per_chunk,
108 +                       tag_buf,
109 +                       (dev->param.tags_9bytes) ? 9 : 8,
110 +                       &ecc_result);
111 +
112 +       switch (ecc_result) {
113 +       case YAFFS_ECC_RESULT_NO_ERROR:
114 +       case YAFFS_ECC_RESULT_FIXED:
115 +               break;
116 +
117 +       case YAFFS_ECC_RESULT_UNFIXED:
118 +       default:
119 +               return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, 0);
120 +               tags->block_bad = dev->drv.drv_check_bad_fn(dev, nand_chunk);
121 +               return YAFFS_FAIL;
122 +       }
123 +
124 +       /* Check for a blank/erased chunk. */
125 +       if (yaffs_check_ff(tag_buf, 8)) {
126 +               /* when blank, upper layers want ecc_result to be <= NO_ERROR */
127 +               return return_empty_tags(tags, YAFFS_ECC_RESULT_NO_ERROR,
128 +                                        YAFFS_OK);
129 +       }
130 +
131 +       memcpy(&pt1, tag_buf, 8);
132 +
133 +       if (!dev->param.tags_9bytes) {
134 +               /* Read deleted status (bit) then return it to it's non-deleted
135 +                * state before performing tags mini-ECC check. pt1.deleted is
136 +                * inverted.
137 +                */
138 +               deleted = !pt1.deleted;
139 +               pt1.deleted = 1;
140 +       } else {
141 +               deleted = (hweight8(tag_buf[8]) < 7) ? 1 : 0;
142 +       }
143 +
144 +       /* Check the packed tags mini-ECC and correct if necessary/possible. */
145 +       retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1);
146 +       switch (retval) {
147 +       case 0:
148 +               /* no tags error, use MTD result */
149 +               break;
150 +       case 1:
151 +               /* recovered tags-ECC error */
152 +               dev->n_tags_ecc_fixed++;
153 +               if (ecc_result == YAFFS_ECC_RESULT_NO_ERROR)
154 +                       ecc_result = YAFFS_ECC_RESULT_FIXED;
155 +               break;
156 +       default:
157 +               /* unrecovered tags-ECC error */
158 +               dev->n_tags_ecc_unfixed++;
159 +               return return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED,
160 +                                        YAFFS_FAIL);
161 +       }
162 +
163 +       /* Unpack the tags to extended form and set ECC result.
164 +        * [set should_be_ff just to keep yaffs_unpack_tags1 happy]
165 +        */
166 +       pt1.should_be_ff = 0xffffffff;
167 +       yaffs_unpack_tags1(tags, &pt1);
168 +       tags->ecc_result = ecc_result;
169 +
170 +       /* Set deleted state */
171 +       tags->is_deleted = deleted;
172 +       return YAFFS_OK;
173 +}
174 +
175 +static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no)
176 +{
177 +       return dev->drv.drv_mark_bad_fn(dev, block_no);
178 +}
179 +
180 +static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
181 +                                        int block_no,
182 +                                        enum yaffs_block_state *state,
183 +                                        u32 *seq_number)
184 +{
185 +       struct yaffs_ext_tags tags;
186 +       int retval;
187 +
188 +       yaffs_trace(YAFFS_TRACE_MTD, "%s %d", __func__, block_no);
189 +
190 +       *seq_number = 0;
191 +
192 +       retval = dev->drv.drv_check_bad_fn(dev, block_no);
193 +       if (retval == YAFFS_FAIL) {
194 +               *state = YAFFS_BLOCK_STATE_DEAD;
195 +               goto out;
196 +       }
197 +
198 +       yaffs_tags_compat_read(dev, block_no * dev->param.chunks_per_block,
199 +                              NULL, &tags);
200 +
201 +       if (tags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
202 +               yaffs_trace(YAFFS_TRACE_MTD, "block %d is marked bad",
203 +                           block_no);
204 +               *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
205 +       } else if (tags.chunk_used) {
206 +               *seq_number = tags.seq_number;
207 +               *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
208 +       } else {
209 +               *state = YAFFS_BLOCK_STATE_EMPTY;
210 +       }
211 +
212 +       retval = YAFFS_OK;
213 +
214 +out:
215 +       yaffs_trace(YAFFS_TRACE_MTD,
216 +                   "block query returns seq %u state %d",
217 +                   *seq_number, *state);
218 +
219 +       return retval;
220 +}
221 +
222 +void yaffs_tags_compat_install(struct yaffs_dev *dev)
223 +{
224 +       if (dev->param.is_yaffs2)
225 +               return;
226 +
227 +       if (!dev->tagger.write_chunk_tags_fn)
228 +               dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_write;
229 +
230 +       if (!dev->tagger.read_chunk_tags_fn)
231 +               dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_read;
232 +
233 +       if (!dev->tagger.query_block_fn)
234 +               dev->tagger.query_block_fn = yaffs_tags_compat_query_block;
235 +
236 +       if (!dev->tagger.mark_bad_fn)
237 +               dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
238 +}
239 +#endif