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