1
2
3
4
5
6
7
8
9
10#include <linux/kernel.h>
11#include <asm/errno.h>
12#include <linux/delay.h>
13#include <linux/slab.h>
14#include <linux/mtd/mtd.h>
15#include <linux/mtd/rawnand.h>
16#include <linux/mtd/nftl.h>
17
18#define SECTORSIZE 512
19
20
21
22
23
24
25static int find_boot_record(struct NFTLrecord *nftl)
26{
27 struct nftl_uci1 h1;
28 unsigned int block, boot_record_count = 0;
29 size_t retlen;
30 u8 buf[SECTORSIZE];
31 struct NFTLMediaHeader *mh = &nftl->MediaHdr;
32 struct mtd_info *mtd = nftl->mbd.mtd;
33 unsigned int i;
34
35
36
37
38
39
40
41 nftl->EraseSize = nftl->mbd.mtd->erasesize;
42 nftl->nb_blocks = (u32)nftl->mbd.mtd->size / nftl->EraseSize;
43
44 nftl->MediaUnit = BLOCK_NIL;
45 nftl->SpareMediaUnit = BLOCK_NIL;
46
47
48 for (block = 0; block < nftl->nb_blocks; block++) {
49 int ret;
50
51
52
53 ret = mtd_read(mtd, block * nftl->EraseSize, SECTORSIZE,
54 &retlen, buf);
55
56
57 if (retlen != SECTORSIZE) {
58 static int warncount = 5;
59
60 if (warncount) {
61 printk(KERN_WARNING "Block read at 0x%x of mtd%d failed: %d\n",
62 block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
63 if (!--warncount)
64 printk(KERN_WARNING "Further failures for this block will not be printed\n");
65 }
66 continue;
67 }
68
69 if (retlen < 6 || memcmp(buf, "ANAND", 6)) {
70
71#if 0
72 printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n",
73 block * nftl->EraseSize, nftl->mbd.mtd->index);
74#endif
75 continue;
76 }
77
78
79 ret = nftl_read_oob(mtd, block * nftl->EraseSize +
80 SECTORSIZE + 8, 8, &retlen,
81 (char *)&h1);
82 if (ret < 0) {
83 printk(KERN_WARNING "ANAND header found at 0x%x in mtd%d, but OOB data read failed (err %d)\n",
84 block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
85 continue;
86 }
87
88#if 0
89
90
91
92 if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) {
93 printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n",
94 block * nftl->EraseSize, nftl->mbd.mtd->index,
95 le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1));
96 continue;
97 }
98
99
100 ret = mtd->read(mtd, block * nftl->EraseSize, SECTORSIZE,
101 &retlen, buf);
102 if (ret < 0) {
103 printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n",
104 block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
105 continue;
106 }
107
108
109 if (memcmp(buf, "ANAND", 6)) {
110 printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but went away on reread!\n",
111 block * nftl->EraseSize, nftl->mbd.mtd->index);
112 printk(KERN_NOTICE "New data are: %6ph\n", buf);
113 continue;
114 }
115#endif
116
117
118 if (boot_record_count) {
119
120
121 if (memcmp(mh, buf, sizeof(struct NFTLMediaHeader))) {
122 printk(KERN_NOTICE "NFTL Media Headers at 0x%x and 0x%x disagree.\n",
123 nftl->MediaUnit * nftl->EraseSize, block * nftl->EraseSize);
124
125 if (boot_record_count < 2) {
126
127 return -1;
128 }
129 continue;
130 }
131 if (boot_record_count == 1)
132 nftl->SpareMediaUnit = block;
133
134
135 nftl->ReplUnitTable[block] = BLOCK_RESERVED;
136
137
138 boot_record_count++;
139 continue;
140 }
141
142
143 memcpy(mh, buf, sizeof(struct NFTLMediaHeader));
144
145
146#if 0
147The new DiskOnChip driver scans the MediaHeader itself, and presents a virtual
148erasesize based on UnitSizeFactor. So the erasesize we read from the mtd
149device is already correct.
150 if (mh->UnitSizeFactor == 0) {
151 printk(KERN_NOTICE "NFTL: UnitSizeFactor 0x00 detected. This violates the spec but we think we know what it means...\n");
152 } else if (mh->UnitSizeFactor < 0xfc) {
153 printk(KERN_NOTICE "Sorry, we don't support UnitSizeFactor 0x%02x\n",
154 mh->UnitSizeFactor);
155 return -1;
156 } else if (mh->UnitSizeFactor != 0xff) {
157 printk(KERN_NOTICE "WARNING: Support for NFTL with UnitSizeFactor 0x%02x is experimental\n",
158 mh->UnitSizeFactor);
159 nftl->EraseSize = nftl->mbd.mtd->erasesize << (0xff - mh->UnitSizeFactor);
160 nftl->nb_blocks = (u32)nftl->mbd.mtd->size / nftl->EraseSize;
161 }
162#endif
163 nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
164 if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
165 printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n");
166 printk(KERN_NOTICE "nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n",
167 nftl->nb_boot_blocks, nftl->nb_blocks);
168 return -1;
169 }
170
171 nftl->numvunits = le32_to_cpu(mh->FormattedSize) / nftl->EraseSize;
172 if (nftl->numvunits > (nftl->nb_blocks - nftl->nb_boot_blocks - 2)) {
173 printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n");
174 printk(KERN_NOTICE "numvunits (%d) > nb_blocks (%d) - nb_boot_blocks(%d) - 2\n",
175 nftl->numvunits, nftl->nb_blocks, nftl->nb_boot_blocks);
176 return -1;
177 }
178
179 nftl->mbd.size = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
180
181
182
183 nftl->nb_blocks = le16_to_cpu(mh->NumEraseUnits) + le16_to_cpu(mh->FirstPhysicalEUN);
184
185
186 nftl->lastEUN = nftl->nb_blocks - 1;
187
188
189 nftl->EUNtable = kmalloc_array(nftl->nb_blocks, sizeof(u16),
190 GFP_KERNEL);
191 if (!nftl->EUNtable)
192 return -ENOMEM;
193
194 nftl->ReplUnitTable = kmalloc_array(nftl->nb_blocks,
195 sizeof(u16),
196 GFP_KERNEL);
197 if (!nftl->ReplUnitTable) {
198 kfree(nftl->EUNtable);
199 return -ENOMEM;
200 }
201
202
203 for (i = 0; i < nftl->nb_boot_blocks; i++)
204 nftl->ReplUnitTable[i] = BLOCK_RESERVED;
205
206 for (; i < nftl->nb_blocks; i++) {
207 nftl->ReplUnitTable[i] = BLOCK_NOTEXPLORED;
208 }
209
210
211 nftl->ReplUnitTable[block] = BLOCK_RESERVED;
212
213
214 for (i = 0; i < nftl->nb_blocks; i++) {
215#if 0
216The new DiskOnChip driver already scanned the bad block table. Just query it.
217 if ((i & (SECTORSIZE - 1)) == 0) {
218
219 ret = mtd->read(nftl->mbd.mtd,
220 block * nftl->EraseSize + i +
221 SECTORSIZE, SECTORSIZE,
222 &retlen, buf);
223 if (ret < 0) {
224 printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n",
225 ret);
226 kfree(nftl->ReplUnitTable);
227 kfree(nftl->EUNtable);
228 return -1;
229 }
230 }
231
232 if (buf[i & (SECTORSIZE - 1)] != 0xff)
233 nftl->ReplUnitTable[i] = BLOCK_RESERVED;
234#endif
235 if (mtd_block_isbad(nftl->mbd.mtd,
236 i * nftl->EraseSize))
237 nftl->ReplUnitTable[i] = BLOCK_RESERVED;
238 }
239
240 nftl->MediaUnit = block;
241 boot_record_count++;
242
243 }
244
245 return boot_record_count?0:-1;
246}
247
248static int memcmpb(void *a, int c, int n)
249{
250 int i;
251 for (i = 0; i < n; i++) {
252 if (c != ((unsigned char *)a)[i])
253 return 1;
254 }
255 return 0;
256}
257
258
259static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len,
260 int check_oob)
261{
262 struct mtd_info *mtd = nftl->mbd.mtd;
263 size_t retlen;
264 int i, ret;
265 u8 *buf;
266
267 buf = kmalloc(SECTORSIZE + mtd->oobsize, GFP_KERNEL);
268 if (!buf)
269 return -ENOMEM;
270
271 ret = -1;
272 for (i = 0; i < len; i += SECTORSIZE) {
273 if (mtd_read(mtd, address, SECTORSIZE, &retlen, buf))
274 goto out;
275 if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
276 goto out;
277
278 if (check_oob) {
279 if(nftl_read_oob(mtd, address, mtd->oobsize,
280 &retlen, &buf[SECTORSIZE]) < 0)
281 goto out;
282 if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0)
283 goto out;
284 }
285 address += SECTORSIZE;
286 }
287
288 ret = 0;
289
290out:
291 kfree(buf);
292 return ret;
293}
294
295
296
297
298
299
300
301
302int NFTL_formatblock(struct NFTLrecord *nftl, int block)
303{
304 size_t retlen;
305 unsigned int nb_erases, erase_mark;
306 struct nftl_uci1 uci;
307 struct erase_info *instr = &nftl->instr;
308 struct mtd_info *mtd = nftl->mbd.mtd;
309
310
311 if (nftl_read_oob(mtd, block * nftl->EraseSize + SECTORSIZE + 8,
312 8, &retlen, (char *)&uci) < 0)
313 goto default_uci1;
314
315 erase_mark = le16_to_cpu ((uci.EraseMark | uci.EraseMark1));
316 if (erase_mark != ERASE_MARK) {
317 default_uci1:
318 uci.EraseMark = cpu_to_le16(ERASE_MARK);
319 uci.EraseMark1 = cpu_to_le16(ERASE_MARK);
320 uci.WearInfo = cpu_to_le32(0);
321 }
322
323 memset(instr, 0, sizeof(struct erase_info));
324
325
326 instr->addr = block * nftl->EraseSize;
327 instr->len = nftl->EraseSize;
328 if (mtd_erase(mtd, instr)) {
329 printk("Error while formatting block %d\n", block);
330 goto fail;
331 }
332
333
334 nb_erases = le32_to_cpu(uci.WearInfo);
335 nb_erases++;
336
337
338 if (nb_erases == 0)
339 nb_erases = 1;
340
341
342
343
344
345 if (check_free_sectors(nftl, instr->addr, nftl->EraseSize, 1) != 0)
346 goto fail;
347
348 uci.WearInfo = le32_to_cpu(nb_erases);
349 if (nftl_write_oob(mtd, block * nftl->EraseSize + SECTORSIZE +
350 8, 8, &retlen, (char *)&uci) < 0)
351 goto fail;
352 return 0;
353fail:
354
355
356 mtd_block_markbad(nftl->mbd.mtd, instr->addr);
357 return -1;
358}
359
360
361
362
363
364
365
366
367
368
369static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_block)
370{
371 struct mtd_info *mtd = nftl->mbd.mtd;
372 unsigned int block, i, status;
373 struct nftl_bci bci;
374 int sectors_per_block;
375 size_t retlen;
376
377 sectors_per_block = nftl->EraseSize / SECTORSIZE;
378 block = first_block;
379 for (;;) {
380 for (i = 0; i < sectors_per_block; i++) {
381 if (nftl_read_oob(mtd,
382 block * nftl->EraseSize + i * SECTORSIZE,
383 8, &retlen, (char *)&bci) < 0)
384 status = SECTOR_IGNORE;
385 else
386 status = bci.Status | bci.Status1;
387
388 switch(status) {
389 case SECTOR_FREE:
390
391
392 if (memcmpb(&bci, 0xff, 8) != 0 ||
393 check_free_sectors(nftl, block * nftl->EraseSize + i * SECTORSIZE,
394 SECTORSIZE, 0) != 0) {
395 printk("Incorrect free sector %d in block %d: "
396 "marking it as ignored\n",
397 i, block);
398
399
400 bci.Status = SECTOR_IGNORE;
401 bci.Status1 = SECTOR_IGNORE;
402 nftl_write_oob(mtd, block *
403 nftl->EraseSize +
404 i * SECTORSIZE, 8,
405 &retlen, (char *)&bci);
406 }
407 break;
408 default:
409 break;
410 }
411 }
412
413
414 block = nftl->ReplUnitTable[block];
415 if (!(block == BLOCK_NIL || block < nftl->nb_blocks))
416 printk("incorrect ReplUnitTable[] : %d\n", block);
417 if (block == BLOCK_NIL || block >= nftl->nb_blocks)
418 break;
419 }
420}
421
422
423static int calc_chain_length(struct NFTLrecord *nftl, unsigned int first_block)
424{
425 unsigned int length = 0, block = first_block;
426
427 for (;;) {
428 length++;
429
430
431 if (length >= nftl->nb_blocks) {
432 printk("nftl: length too long %d !\n", length);
433 break;
434 }
435
436 block = nftl->ReplUnitTable[block];
437 if (!(block == BLOCK_NIL || block < nftl->nb_blocks))
438 printk("incorrect ReplUnitTable[] : %d\n", block);
439 if (block == BLOCK_NIL || block >= nftl->nb_blocks)
440 break;
441 }
442 return length;
443}
444
445
446
447
448
449
450
451
452
453
454
455static void format_chain(struct NFTLrecord *nftl, unsigned int first_block)
456{
457 unsigned int block = first_block, block1;
458
459 printk("Formatting chain at block %d\n", first_block);
460
461 for (;;) {
462 block1 = nftl->ReplUnitTable[block];
463
464 printk("Formatting block %d\n", block);
465 if (NFTL_formatblock(nftl, block) < 0) {
466
467 nftl->ReplUnitTable[block] = BLOCK_RESERVED;
468 } else {
469 nftl->ReplUnitTable[block] = BLOCK_FREE;
470 }
471
472
473 block = block1;
474
475 if (!(block == BLOCK_NIL || block < nftl->nb_blocks))
476 printk("incorrect ReplUnitTable[] : %d\n", block);
477 if (block == BLOCK_NIL || block >= nftl->nb_blocks)
478 break;
479 }
480}
481
482
483
484
485
486
487
488static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)
489{
490 struct mtd_info *mtd = nftl->mbd.mtd;
491 struct nftl_uci1 h1;
492 unsigned int erase_mark;
493 size_t retlen;
494
495
496 if (nftl_read_oob(mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
497 &retlen, (char *)&h1) < 0)
498 return -1;
499
500 erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1));
501 if (erase_mark != ERASE_MARK) {
502
503
504 if (check_free_sectors (nftl, block * nftl->EraseSize, nftl->EraseSize, 1) != 0)
505 return -1;
506
507
508 h1.EraseMark = cpu_to_le16(ERASE_MARK);
509 h1.EraseMark1 = cpu_to_le16(ERASE_MARK);
510 h1.WearInfo = cpu_to_le32(0);
511 if (nftl_write_oob(mtd,
512 block * nftl->EraseSize + SECTORSIZE + 8, 8,
513 &retlen, (char *)&h1) < 0)
514 return -1;
515 } else {
516#if 0
517
518 for (i = 0; i < nftl->EraseSize; i += SECTORSIZE) {
519
520 if (check_free_sectors (nftl, block * nftl->EraseSize + i,
521 SECTORSIZE, 0) != 0)
522 return -1;
523
524 if (nftl_read_oob(mtd, block * nftl->EraseSize + i,
525 16, &retlen, buf) < 0)
526 return -1;
527 if (i == SECTORSIZE) {
528
529 if (memcmpb(buf, 0xff, 8))
530 return -1;
531 } else {
532 if (memcmpb(buf, 0xff, 16))
533 return -1;
534 }
535 }
536#endif
537 }
538
539 return 0;
540}
541
542
543
544
545
546
547
548
549static int get_fold_mark(struct NFTLrecord *nftl, unsigned int block)
550{
551 struct mtd_info *mtd = nftl->mbd.mtd;
552 struct nftl_uci2 uci;
553 size_t retlen;
554
555 if (nftl_read_oob(mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8,
556 8, &retlen, (char *)&uci) < 0)
557 return 0;
558
559 return le16_to_cpu((uci.FoldMark | uci.FoldMark1));
560}
561
562int NFTL_mount(struct NFTLrecord *s)
563{
564 int i;
565 unsigned int first_logical_block, logical_block, rep_block, erase_mark;
566 unsigned int block, first_block, is_first_block;
567 int chain_length, do_format_chain;
568 struct nftl_uci0 h0;
569 struct nftl_uci1 h1;
570 struct mtd_info *mtd = s->mbd.mtd;
571 size_t retlen;
572
573
574 if (find_boot_record(s) < 0) {
575 printk("Could not find valid boot record\n");
576 return -1;
577 }
578
579
580 for (i = 0; i < s->nb_blocks; i++) {
581 s->EUNtable[i] = BLOCK_NIL;
582 }
583
584
585 first_logical_block = 0;
586 for (first_block = 0; first_block < s->nb_blocks; first_block++) {
587
588 if (s->ReplUnitTable[first_block] == BLOCK_NOTEXPLORED) {
589 block = first_block;
590 chain_length = 0;
591 do_format_chain = 0;
592
593 for (;;) {
594
595 if (nftl_read_oob(mtd,
596 block * s->EraseSize + 8, 8,
597 &retlen, (char *)&h0) < 0 ||
598 nftl_read_oob(mtd,
599 block * s->EraseSize +
600 SECTORSIZE + 8, 8,
601 &retlen, (char *)&h1) < 0) {
602 s->ReplUnitTable[block] = BLOCK_NIL;
603 do_format_chain = 1;
604 break;
605 }
606
607 logical_block = le16_to_cpu ((h0.VirtUnitNum | h0.SpareVirtUnitNum));
608 rep_block = le16_to_cpu ((h0.ReplUnitNum | h0.SpareReplUnitNum));
609 erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1));
610
611 is_first_block = !(logical_block >> 15);
612 logical_block = logical_block & 0x7fff;
613
614
615 if (erase_mark != ERASE_MARK || logical_block >= s->nb_blocks) {
616 if (chain_length == 0) {
617
618 if (check_and_mark_free_block(s, block) < 0) {
619
620 printk("Formatting block %d\n", block);
621 if (NFTL_formatblock(s, block) < 0) {
622
623 s->ReplUnitTable[block] = BLOCK_RESERVED;
624 } else {
625 s->ReplUnitTable[block] = BLOCK_FREE;
626 }
627 } else {
628
629 s->ReplUnitTable[block] = BLOCK_FREE;
630 }
631
632 goto examine_ReplUnitTable;
633 } else {
634
635
636 printk("Block %d: free but referenced in chain %d\n",
637 block, first_block);
638 s->ReplUnitTable[block] = BLOCK_NIL;
639 do_format_chain = 1;
640 break;
641 }
642 }
643
644
645 if (chain_length == 0) {
646
647
648
649 if (!is_first_block)
650 goto examine_ReplUnitTable;
651 first_logical_block = logical_block;
652 } else {
653 if (logical_block != first_logical_block) {
654 printk("Block %d: incorrect logical block: %d expected: %d\n",
655 block, logical_block, first_logical_block);
656
657
658 do_format_chain = 1;
659 }
660 if (is_first_block) {
661
662
663
664 if (get_fold_mark(s, block) != FOLD_MARK_IN_PROGRESS ||
665 rep_block != 0xffff) {
666 printk("Block %d: incorrectly marked as first block in chain\n",
667 block);
668
669
670 do_format_chain = 1;
671 } else {
672 printk("Block %d: folding in progress - ignoring first block flag\n",
673 block);
674 }
675 }
676 }
677 chain_length++;
678 if (rep_block == 0xffff) {
679
680 s->ReplUnitTable[block] = BLOCK_NIL;
681 break;
682 } else if (rep_block >= s->nb_blocks) {
683 printk("Block %d: referencing invalid block %d\n",
684 block, rep_block);
685 do_format_chain = 1;
686 s->ReplUnitTable[block] = BLOCK_NIL;
687 break;
688 } else if (s->ReplUnitTable[rep_block] != BLOCK_NOTEXPLORED) {
689
690
691
692
693
694 if (s->ReplUnitTable[rep_block] == BLOCK_NIL &&
695 s->EUNtable[first_logical_block] == rep_block &&
696 get_fold_mark(s, first_block) == FOLD_MARK_IN_PROGRESS) {
697
698 printk("Block %d: folding in progress - ignoring first block flag\n",
699 rep_block);
700 s->ReplUnitTable[block] = rep_block;
701 s->EUNtable[first_logical_block] = BLOCK_NIL;
702 } else {
703 printk("Block %d: referencing block %d already in another chain\n",
704 block, rep_block);
705
706 do_format_chain = 1;
707 s->ReplUnitTable[block] = BLOCK_NIL;
708 }
709 break;
710 } else {
711
712 s->ReplUnitTable[block] = rep_block;
713 block = rep_block;
714 }
715 }
716
717
718
719 if (do_format_chain) {
720
721 format_chain(s, first_block);
722 } else {
723 unsigned int first_block1, chain_to_format, chain_length1;
724 int fold_mark;
725
726
727 fold_mark = get_fold_mark(s, first_block);
728 if (fold_mark == 0) {
729
730 printk("Could read foldmark at block %d\n", first_block);
731 format_chain(s, first_block);
732 } else {
733 if (fold_mark == FOLD_MARK_IN_PROGRESS)
734 check_sectors_in_chain(s, first_block);
735
736
737
738
739
740 first_block1 = s->EUNtable[first_logical_block];
741 if (first_block1 != BLOCK_NIL) {
742
743 chain_length1 = calc_chain_length(s, first_block1);
744 printk("Two chains at blocks %d (len=%d) and %d (len=%d)\n",
745 first_block1, chain_length1, first_block, chain_length);
746
747 if (chain_length >= chain_length1) {
748 chain_to_format = first_block1;
749 s->EUNtable[first_logical_block] = first_block;
750 } else {
751 chain_to_format = first_block;
752 }
753 format_chain(s, chain_to_format);
754 } else {
755 s->EUNtable[first_logical_block] = first_block;
756 }
757 }
758 }
759 }
760 examine_ReplUnitTable:;
761 }
762
763
764 s->numfreeEUNs = 0;
765 s->LastFreeEUN = le16_to_cpu(s->MediaHdr.FirstPhysicalEUN);
766
767 for (block = 0; block < s->nb_blocks; block++) {
768 if (s->ReplUnitTable[block] == BLOCK_NOTEXPLORED) {
769 printk("Unreferenced block %d, formatting it\n", block);
770 if (NFTL_formatblock(s, block) < 0)
771 s->ReplUnitTable[block] = BLOCK_RESERVED;
772 else
773 s->ReplUnitTable[block] = BLOCK_FREE;
774 }
775 if (s->ReplUnitTable[block] == BLOCK_FREE) {
776 s->numfreeEUNs++;
777 s->LastFreeEUN = block;
778 }
779 }
780
781 return 0;
782}
783