hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/mtd/nand/bbt_store.c
....@@ -8,18 +8,78 @@
88 #include <linux/slab.h>
99
1010 #ifdef BBT_DEBUG
11
-#define BBT_DBG pr_err
11
+#define bbt_dbg pr_err
1212 #else
13
-#define BBT_DBG(args...)
13
+#define bbt_dbg(args...)
1414 #endif
15
+
16
+#define BBT_VERSION_INVALID (0xFFFFFFFFU)
17
+#define BBT_VERSION_BLOCK_ABNORMAL (BBT_VERSION_INVALID - 1)
18
+#define BBT_VERSION_MAX (BBT_VERSION_INVALID - 8)
1519
1620 struct nanddev_bbt_info {
1721 u8 pattern[4];
1822 unsigned int version;
23
+ u32 hash;
1924 };
2025
2126 static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
2227
28
+#if defined(BBT_DEBUG) && defined(BBT_DEBUG_DUMP)
29
+static void bbt_dbg_hex(char *s, void *buf, u32 len)
30
+{
31
+ print_hex_dump(KERN_WARNING, s, DUMP_PREFIX_OFFSET, 4, 4, buf, len, 0);
32
+}
33
+#endif
34
+
35
+static u32 js_hash(u8 *buf, u32 len)
36
+{
37
+ u32 hash = 0x47C6A7E6;
38
+ u32 i;
39
+
40
+ for (i = 0; i < len; i++)
41
+ hash ^= ((hash << 5) + buf[i] + (hash >> 2));
42
+
43
+ return hash;
44
+}
45
+
46
+static bool bbt_check_hash(u8 *buf, u32 len, u32 hash_cmp)
47
+{
48
+ u32 hash;
49
+
50
+ /* compatible with no-hash version */
51
+ if (hash_cmp == 0 || hash_cmp == 0xFFFFFFFF)
52
+ return 1;
53
+
54
+ hash = js_hash(buf, len);
55
+ if (hash != hash_cmp)
56
+ return 0;
57
+
58
+ return 1;
59
+}
60
+
61
+static u32 bbt_nand_isbad_bypass(struct nand_device *nand, u32 block)
62
+{
63
+ struct mtd_info *mtd = nanddev_to_mtd(nand);
64
+ struct nand_pos pos;
65
+
66
+ nanddev_bbt_set_block_status(nand, block, NAND_BBT_BLOCK_STATUS_UNKNOWN);
67
+ nanddev_offs_to_pos(nand, block * mtd->erasesize, &pos);
68
+
69
+ return nanddev_isbad(nand, &pos);
70
+}
71
+
72
+/**
73
+ * nanddev_read_bbt() - Read the BBT (Bad Block Table)
74
+ * @nand: NAND device
75
+ * @block: bbt block address
76
+ * @update: true - get version and overwrite bbt.cache with new version;
77
+ * false - get bbt version only;
78
+ *
79
+ * Initialize the in-memory BBT.
80
+ *
81
+ * Return: 0 in case of success, a negative error code otherwise.
82
+ */
2383 static int nanddev_read_bbt(struct nand_device *nand, u32 block, bool update)
2484 {
2585 unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
....@@ -30,7 +90,7 @@
3090 u8 *data_buf, *oob_buf;
3191 struct nanddev_bbt_info *bbt_info;
3292 struct mtd_oob_ops ops;
33
- int bbt_page_num;
93
+ u32 bbt_page_num;
3494 int ret = 0;
3595 unsigned int version = 0;
3696
....@@ -40,7 +100,7 @@
40100 if (block >= nblocks)
41101 return -EINVAL;
42102
43
- /* Aligned to page size, and even pages is better */
103
+ /* aligned to page size, and even pages is better */
44104 bbt_page_num = (sizeof(struct nanddev_bbt_info) + nbytes +
45105 mtd->writesize - 1) >> (ffs(mtd->writesize) - 1);
46106 bbt_page_num = (bbt_page_num + 1) / 2 * 2;
....@@ -64,29 +124,72 @@
64124 ops.ooblen = bbt_page_num * mtd->oobsize;
65125 ops.ooboffs = 0;
66126
127
+ /* store one entry for each block */
67128 ret = mtd_read_oob(mtd, block * mtd->erasesize, &ops);
68129 if (ret && ret != -EUCLEAN) {
69
- pr_err("%s fail %d\n", __func__, ret);
70
- ret = -EIO;
130
+ pr_err("read_bbt blk=%d fail=%d update=%d\n", block, ret, update);
131
+ ret = 0;
132
+ version = BBT_VERSION_BLOCK_ABNORMAL;
71133 goto out;
72134 } else {
73135 ret = 0;
74136 }
75137
76
- if (oob_buf[0] != 0xff && !memcmp(bbt_pattern, bbt_info->pattern, 4))
77
- version = bbt_info->version;
138
+ /* bad block or good block without bbt */
139
+ if (memcmp(bbt_pattern, bbt_info->pattern, 4)) {
140
+ ret = 0;
141
+ goto out;
142
+ }
78143
79
- BBT_DBG("read_bbt from blk=%d tag=%d ver=%d\n", block, update, version);
144
+ /* good block with abnornal bbt */
145
+ if (oob_buf[0] == 0xff ||
146
+ !bbt_check_hash(data_buf, nbytes + sizeof(struct nanddev_bbt_info) - 4, bbt_info->hash)) {
147
+ pr_err("read_bbt check fail blk=%d ret=%d update=%d\n", block, ret, update);
148
+ ret = 0;
149
+ version = BBT_VERSION_BLOCK_ABNORMAL;
150
+ goto out;
151
+ }
152
+
153
+ /* good block with good bbt */
154
+ version = bbt_info->version;
155
+ bbt_dbg("read_bbt from blk=%d ver=%d update=%d\n", block, version, update);
80156 if (update && version > nand->bbt.version) {
81157 memcpy(nand->bbt.cache, data_buf, nbytes);
82158 nand->bbt.version = version;
83159 }
84160
85
-out:
86
- kfree(oob_buf);
87
- kfree(data_buf);
161
+#if defined(BBT_DEBUG) && defined(BBT_DEBUG_DUMP)
162
+ bbt_dbg_hex("bbt", data_buf, nbytes + sizeof(struct nanddev_bbt_info));
163
+ if (version) {
164
+ u8 *temp_buf = kzalloc(bbt_page_num * mtd->writesize, GFP_KERNEL);
165
+ bool in_scan = nand->bbt.option & NANDDEV_BBT_SCANNED;
88166
89
- return ret < 0 ? -EIO : version;
167
+ if (!temp_buf)
168
+ goto out;
169
+
170
+ memcpy(temp_buf, nand->bbt.cache, nbytes);
171
+ memcpy(nand->bbt.cache, data_buf, nbytes);
172
+
173
+ if (!in_scan)
174
+ nand->bbt.option |= NANDDEV_BBT_SCANNED;
175
+ for (block = 0; block < nblocks; block++) {
176
+ ret = nanddev_bbt_get_block_status(nand, block);
177
+ if (ret != NAND_BBT_BLOCK_GOOD)
178
+ bbt_dbg("bad block[0x%x], ret=%d\n", block, ret);
179
+ }
180
+ if (!in_scan)
181
+ nand->bbt.option &= ~NANDDEV_BBT_SCANNED;
182
+ memcpy(nand->bbt.cache, temp_buf, nbytes);
183
+ kfree(temp_buf);
184
+ ret = 0;
185
+ }
186
+#endif
187
+
188
+out:
189
+ kfree(data_buf);
190
+ kfree(oob_buf);
191
+
192
+ return ret < 0 ? -EIO : (int)version;
90193 }
91194
92195 static int nanddev_write_bbt(struct nand_device *nand, u32 block)
....@@ -99,18 +202,18 @@
99202 u8 *data_buf, *oob_buf;
100203 struct nanddev_bbt_info *bbt_info;
101204 struct mtd_oob_ops ops;
102
- int bbt_page_num;
103
- int ret = 0;
205
+ u32 bbt_page_num;
206
+ int ret = 0, version;
104207 struct nand_pos pos;
105208
106
- BBT_DBG("write_bbt to blk=%d ver=%d\n", block, nand->bbt.version);
209
+ bbt_dbg("write_bbt to blk=%d ver=%d\n", block, nand->bbt.version);
107210 if (!nand->bbt.cache)
108211 return -ENOMEM;
109212
110213 if (block >= nblocks)
111214 return -EINVAL;
112215
113
- /* Aligned to page size, and even pages is better */
216
+ /* aligned to page size, and even pages is better */
114217 bbt_page_num = (sizeof(struct nanddev_bbt_info) + nbytes +
115218 mtd->writesize - 1) >> (ffs(mtd->writesize) - 1);
116219 bbt_page_num = (bbt_page_num + 1) / 2 * 2;
....@@ -130,7 +233,9 @@
130233 memcpy(data_buf, nand->bbt.cache, nbytes);
131234 memcpy(bbt_info, bbt_pattern, 4);
132235 bbt_info->version = nand->bbt.version;
236
+ bbt_info->hash = js_hash(data_buf, nbytes + sizeof(struct nanddev_bbt_info) - 4);
133237
238
+ /* store one entry for each block */
134239 nanddev_offs_to_pos(nand, block * mtd->erasesize, &pos);
135240 ret = nand->ops->erase(nand, &pos);
136241 if (ret)
....@@ -144,10 +249,23 @@
144249 ops.ooblen = bbt_page_num * mtd->oobsize;
145250 ops.ooboffs = 0;
146251 ret = mtd_write_oob(mtd, block * mtd->erasesize, &ops);
252
+ if (ret) {
253
+ nand->ops->erase(nand, &pos);
254
+ goto out;
255
+ }
147256
257
+ version = nanddev_read_bbt(nand, block, false);
258
+ if (version != bbt_info->version) {
259
+ pr_err("bbt_write fail, blk=%d recheck fail %d-%d\n",
260
+ block, version, bbt_info->version);
261
+ nand->ops->erase(nand, &pos);
262
+ ret = -EIO;
263
+ } else {
264
+ ret = 0;
265
+ }
148266 out:
149
- kfree(oob_buf);
150267 kfree(data_buf);
268
+ kfree(oob_buf);
151269
152270 return ret;
153271 }
....@@ -158,14 +276,30 @@
158276 struct mtd_info *mtd = nanddev_to_mtd(nand);
159277 struct nand_pos pos;
160278 u32 start_block, block;
279
+ unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
280
+ unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block,
281
+ BITS_PER_LONG);
161282
162283 start_block = nblocks - NANDDEV_BBT_SCAN_MAXBLOCKS;
163284
164285 for (block = 0; block < nblocks; block++) {
165286 nanddev_offs_to_pos(nand, block * mtd->erasesize, &pos);
166
- if (nanddev_isbad(nand, &pos))
287
+ if (nanddev_isbad(nand, &pos)) {
288
+ if (bbt_nand_isbad_bypass(nand, 0)) {
289
+ memset(nand->bbt.cache, 0, nwords * sizeof(*nand->bbt.cache));
290
+ pr_err("bbt_format fail, test good block %d fail\n", 0);
291
+ return -EIO;
292
+ }
293
+
294
+ if (!bbt_nand_isbad_bypass(nand, block)) {
295
+ memset(nand->bbt.cache, 0, nwords * sizeof(*nand->bbt.cache));
296
+ pr_err("bbt_format fail, test bad block %d fail\n", block);
297
+ return -EIO;
298
+ }
299
+
167300 nanddev_bbt_set_block_status(nand, block,
168301 NAND_BBT_BLOCK_FACTORY_BAD);
302
+ }
169303 }
170304
171305 for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) {
....@@ -197,16 +331,34 @@
197331 for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++)
198332 nanddev_read_bbt(nand, start_block + block, true);
199333
334
+ nand->bbt.option |= NANDDEV_BBT_SCANNED;
200335 if (nand->bbt.version == 0) {
201
- nanddev_bbt_format(nand);
336
+ ret = nanddev_bbt_format(nand);
337
+ if (ret) {
338
+ nand->bbt.option = 0;
339
+ pr_err("%s format fail\n", __func__);
340
+
341
+ return ret;
342
+ }
202343 ret = nanddev_bbt_in_flash_update(nand);
203344 if (ret) {
204345 nand->bbt.option = 0;
205
- pr_err("%s fail\n", __func__);
346
+ pr_err("%s update fail\n", __func__);
347
+
348
+ return ret;
206349 }
207350 }
208351
209
- nand->bbt.option |= NANDDEV_BBT_SCANNED;
352
+#if defined(BBT_DEBUG)
353
+ pr_err("scan_bbt success\n");
354
+ if (nand->bbt.version) {
355
+ for (block = 0; block < nblocks; block++) {
356
+ ret = nanddev_bbt_get_block_status(nand, block);
357
+ if (ret != NAND_BBT_BLOCK_GOOD)
358
+ bbt_dbg("bad block[0x%x], ret=%d\n", block, ret);
359
+ }
360
+ }
361
+#endif
210362
211363 return ret;
212364 }
....@@ -222,31 +374,31 @@
222374 */
223375 int nanddev_bbt_in_flash_update(struct nand_device *nand)
224376 {
377
+ struct nand_pos pos;
378
+ struct mtd_info *mtd = nanddev_to_mtd(nand);
379
+
225380 if (nand->bbt.option & NANDDEV_BBT_SCANNED) {
226381 unsigned int nblocks = nanddev_neraseblocks(nand);
227382 u32 bbt_version[NANDDEV_BBT_SCAN_MAXBLOCKS];
228383 int start_block, block;
229384 u32 min_version, block_des;
230
- int ret, count = 0;
385
+ int ret, count = 0, status;
231386
232387 start_block = nblocks - NANDDEV_BBT_SCAN_MAXBLOCKS;
233388 for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) {
234
- ret = nanddev_bbt_get_block_status(nand, start_block + block);
235
- if (ret == NAND_BBT_BLOCK_FACTORY_BAD) {
236
- bbt_version[block] = 0xFFFFFFFF;
237
- continue;
238
- }
239
- ret = nanddev_read_bbt(nand, start_block + block,
240
- false);
241
- if (ret < 0)
242
- bbt_version[block] = 0xFFFFFFFF;
243
- else if (ret == 0)
244
- bbt_version[block] = 0;
389
+ status = nanddev_bbt_get_block_status(nand, start_block + block);
390
+ ret = nanddev_read_bbt(nand, start_block + block, false);
391
+ if (ret == 0 && status == NAND_BBT_BLOCK_FACTORY_BAD)
392
+ bbt_version[block] = BBT_VERSION_INVALID;
393
+ else if (ret == -EIO)
394
+ bbt_version[block] = BBT_VERSION_INVALID;
395
+ else if (ret == BBT_VERSION_BLOCK_ABNORMAL)
396
+ bbt_version[block] = ret;
245397 else
246398 bbt_version[block] = ret;
247399 }
248400 get_min_ver:
249
- min_version = 0xFFFFFFFF;
401
+ min_version = BBT_VERSION_MAX;
250402 block_des = 0;
251403 for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) {
252404 if (bbt_version[block] < min_version) {
....@@ -255,25 +407,38 @@
255407 }
256408 }
257409
410
+ /* Overwrite the BBT_VERSION_BLOCK_ABNORMAL block */
411
+ if (nand->bbt.version < min_version)
412
+ nand->bbt.version = min_version + 4;
413
+
258414 if (block_des > 0) {
259415 nand->bbt.version++;
260416 ret = nanddev_write_bbt(nand, block_des);
261
- bbt_version[block_des - start_block] = 0xFFFFFFFF;
262417 if (ret) {
263
- pr_err("%s blk= %d ret= %d\n", __func__,
264
- block_des, ret);
265
- goto get_min_ver;
266
- } else {
267
- count++;
268
- if (count < 2)
269
- goto get_min_ver;
270
- BBT_DBG("%s success\n", __func__);
271
- }
272
- } else {
273
- pr_err("%s failed\n", __func__);
418
+ pr_err("bbt_update fail, blk=%d ret= %d\n", block_des, ret);
274419
275
- return -EINVAL;
420
+ return -1;
421
+ }
422
+
423
+ bbt_version[block_des - start_block] = BBT_VERSION_INVALID;
424
+ count++;
425
+ if (count < 2)
426
+ goto get_min_ver;
427
+ bbt_dbg("bbt_update success\n");
428
+ } else {
429
+ pr_err("bbt_update failed\n");
430
+ ret = -1;
276431 }
432
+
433
+ for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) {
434
+ if (bbt_version[block] == BBT_VERSION_BLOCK_ABNORMAL) {
435
+ block_des = start_block + block;
436
+ nanddev_offs_to_pos(nand, block_des * mtd->erasesize, &pos);
437
+ nand->ops->erase(nand, &pos);
438
+ }
439
+ }
440
+
441
+ return ret;
277442 }
278443
279444 return 0;