aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAdrian Hunter <ext-adrian.hunter@nokia.com>2007-03-19 06:47:45 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2007-04-17 13:55:08 -0400
commit514087e74fb401a6621e8c836f4eaab87c269f24 (patch)
treea963d3669d42d0b8d3872a53ce511049c4a7363c /drivers
parent2b77a0ed54eeea61937e7f71b0487b815edfbcdf (diff)
[MTD] nandsim: enhance nandsim to simulate flash errors
New module parameters have been added to nandsim to simulate: bitflips random bit flips badblocks blocks that are initially marked bad weakblocks blocks that fail to erase after a small number of erase cycles weakpages pages that fail to write after a small number of successful writes gravepages pages that fail to read after a small number of successful reads Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com> Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/nand/nandsim.c301
1 files changed, 300 insertions, 1 deletions
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 638e6c256d3e..05b42077d22f 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -38,6 +38,7 @@
38#include <linux/mtd/partitions.h> 38#include <linux/mtd/partitions.h>
39#include <linux/delay.h> 39#include <linux/delay.h>
40#include <linux/list.h> 40#include <linux/list.h>
41#include <linux/random.h>
41 42
42/* Default simulator parameters values */ 43/* Default simulator parameters values */
43#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ 44#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \
@@ -93,6 +94,11 @@ static uint log = CONFIG_NANDSIM_LOG;
93static uint dbg = CONFIG_NANDSIM_DBG; 94static uint dbg = CONFIG_NANDSIM_DBG;
94static unsigned long parts[MAX_MTD_DEVICES]; 95static unsigned long parts[MAX_MTD_DEVICES];
95static unsigned int parts_num; 96static unsigned int parts_num;
97static char *badblocks = NULL;
98static char *weakblocks = NULL;
99static char *weakpages = NULL;
100static unsigned int bitflips = 0;
101static char *gravepages = NULL;
96 102
97module_param(first_id_byte, uint, 0400); 103module_param(first_id_byte, uint, 0400);
98module_param(second_id_byte, uint, 0400); 104module_param(second_id_byte, uint, 0400);
@@ -108,6 +114,11 @@ module_param(do_delays, uint, 0400);
108module_param(log, uint, 0400); 114module_param(log, uint, 0400);
109module_param(dbg, uint, 0400); 115module_param(dbg, uint, 0400);
110module_param_array(parts, ulong, &parts_num, 0400); 116module_param_array(parts, ulong, &parts_num, 0400);
117module_param(badblocks, charp, 0400);
118module_param(weakblocks, charp, 0400);
119module_param(weakpages, charp, 0400);
120module_param(bitflips, uint, 0400);
121module_param(gravepages, charp, 0400);
111 122
112MODULE_PARM_DESC(first_id_byte, "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)"); 123MODULE_PARM_DESC(first_id_byte, "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)");
113MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); 124MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)");
@@ -123,6 +134,18 @@ MODULE_PARM_DESC(do_delays, "Simulate NAND delays using busy-waits if not z
123MODULE_PARM_DESC(log, "Perform logging if not zero"); 134MODULE_PARM_DESC(log, "Perform logging if not zero");
124MODULE_PARM_DESC(dbg, "Output debug information if not zero"); 135MODULE_PARM_DESC(dbg, "Output debug information if not zero");
125MODULE_PARM_DESC(parts, "Partition sizes (in erase blocks) separated by commas"); 136MODULE_PARM_DESC(parts, "Partition sizes (in erase blocks) separated by commas");
137/* Page and erase block positions for the following parameters are independent of any partitions */
138MODULE_PARM_DESC(badblocks, "Erase blocks that are initially marked bad, separated by commas");
139MODULE_PARM_DESC(weakblocks, "Weak erase blocks [: remaining erase cycles (defaults to 3)]"
140 " separated by commas e.g. 113:2 means eb 113"
141 " can be erased only twice before failing");
142MODULE_PARM_DESC(weakpages, "Weak pages [: maximum writes (defaults to 3)]"
143 " separated by commas e.g. 1401:2 means page 1401"
144 " can be written only twice before failing");
145MODULE_PARM_DESC(bitflips, "Maximum number of random bit flips per page (zero by default)");
146MODULE_PARM_DESC(gravepages, "Pages that lose data [: maximum reads (defaults to 3)]"
147 " separated by commas e.g. 1401:2 means page 1401"
148 " can be read only twice before failing");
126 149
127/* The largest possible page size */ 150/* The largest possible page size */
128#define NS_LARGEST_PAGE_SIZE 2048 151#define NS_LARGEST_PAGE_SIZE 2048
@@ -344,6 +367,33 @@ static struct nandsim_operations {
344 STATE_DATAOUT, STATE_READY}} 367 STATE_DATAOUT, STATE_READY}}
345}; 368};
346 369
370struct weak_block {
371 struct list_head list;
372 unsigned int erase_block_no;
373 unsigned int max_erases;
374 unsigned int erases_done;
375};
376
377static LIST_HEAD(weak_blocks);
378
379struct weak_page {
380 struct list_head list;
381 unsigned int page_no;
382 unsigned int max_writes;
383 unsigned int writes_done;
384};
385
386static LIST_HEAD(weak_pages);
387
388struct grave_page {
389 struct list_head list;
390 unsigned int page_no;
391 unsigned int max_reads;
392 unsigned int reads_done;
393};
394
395static LIST_HEAD(grave_pages);
396
347/* MTD structure for NAND controller */ 397/* MTD structure for NAND controller */
348static struct mtd_info *nsmtd; 398static struct mtd_info *nsmtd;
349 399
@@ -555,6 +605,204 @@ static void free_nandsim(struct nandsim *ns)
555 return; 605 return;
556} 606}
557 607
608static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd)
609{
610 char *w;
611 int zero_ok;
612 unsigned int erase_block_no;
613 loff_t offset;
614
615 if (!badblocks)
616 return 0;
617 w = badblocks;
618 do {
619 zero_ok = (*w == '0' ? 1 : 0);
620 erase_block_no = simple_strtoul(w, &w, 0);
621 if (!zero_ok && !erase_block_no) {
622 NS_ERR("invalid badblocks.\n");
623 return -EINVAL;
624 }
625 offset = erase_block_no * ns->geom.secsz;
626 if (mtd->block_markbad(mtd, offset)) {
627 NS_ERR("invalid badblocks.\n");
628 return -EINVAL;
629 }
630 if (*w == ',')
631 w += 1;
632 } while (*w);
633 return 0;
634}
635
636static int parse_weakblocks(void)
637{
638 char *w;
639 int zero_ok;
640 unsigned int erase_block_no;
641 unsigned int max_erases;
642 struct weak_block *wb;
643
644 if (!weakblocks)
645 return 0;
646 w = weakblocks;
647 do {
648 zero_ok = (*w == '0' ? 1 : 0);
649 erase_block_no = simple_strtoul(w, &w, 0);
650 if (!zero_ok && !erase_block_no) {
651 NS_ERR("invalid weakblocks.\n");
652 return -EINVAL;
653 }
654 max_erases = 3;
655 if (*w == ':') {
656 w += 1;
657 max_erases = simple_strtoul(w, &w, 0);
658 }
659 if (*w == ',')
660 w += 1;
661 wb = kzalloc(sizeof(*wb), GFP_KERNEL);
662 if (!wb) {
663 NS_ERR("unable to allocate memory.\n");
664 return -ENOMEM;
665 }
666 wb->erase_block_no = erase_block_no;
667 wb->max_erases = max_erases;
668 list_add(&wb->list, &weak_blocks);
669 } while (*w);
670 return 0;
671}
672
673static int erase_error(unsigned int erase_block_no)
674{
675 struct weak_block *wb;
676
677 list_for_each_entry(wb, &weak_blocks, list)
678 if (wb->erase_block_no == erase_block_no) {
679 if (wb->erases_done >= wb->max_erases)
680 return 1;
681 wb->erases_done += 1;
682 return 0;
683 }
684 return 0;
685}
686
687static int parse_weakpages(void)
688{
689 char *w;
690 int zero_ok;
691 unsigned int page_no;
692 unsigned int max_writes;
693 struct weak_page *wp;
694
695 if (!weakpages)
696 return 0;
697 w = weakpages;
698 do {
699 zero_ok = (*w == '0' ? 1 : 0);
700 page_no = simple_strtoul(w, &w, 0);
701 if (!zero_ok && !page_no) {
702 NS_ERR("invalid weakpagess.\n");
703 return -EINVAL;
704 }
705 max_writes = 3;
706 if (*w == ':') {
707 w += 1;
708 max_writes = simple_strtoul(w, &w, 0);
709 }
710 if (*w == ',')
711 w += 1;
712 wp = kzalloc(sizeof(*wp), GFP_KERNEL);
713 if (!wp) {
714 NS_ERR("unable to allocate memory.\n");
715 return -ENOMEM;
716 }
717 wp->page_no = page_no;
718 wp->max_writes = max_writes;
719 list_add(&wp->list, &weak_pages);
720 } while (*w);
721 return 0;
722}
723
724static int write_error(unsigned int page_no)
725{
726 struct weak_page *wp;
727
728 list_for_each_entry(wp, &weak_pages, list)
729 if (wp->page_no == page_no) {
730 if (wp->writes_done >= wp->max_writes)
731 return 1;
732 wp->writes_done += 1;
733 return 0;
734 }
735 return 0;
736}
737
738static int parse_gravepages(void)
739{
740 char *g;
741 int zero_ok;
742 unsigned int page_no;
743 unsigned int max_reads;
744 struct grave_page *gp;
745
746 if (!gravepages)
747 return 0;
748 g = gravepages;
749 do {
750 zero_ok = (*g == '0' ? 1 : 0);
751 page_no = simple_strtoul(g, &g, 0);
752 if (!zero_ok && !page_no) {
753 NS_ERR("invalid gravepagess.\n");
754 return -EINVAL;
755 }
756 max_reads = 3;
757 if (*g == ':') {
758 g += 1;
759 max_reads = simple_strtoul(g, &g, 0);
760 }
761 if (*g == ',')
762 g += 1;
763 gp = kzalloc(sizeof(*gp), GFP_KERNEL);
764 if (!gp) {
765 NS_ERR("unable to allocate memory.\n");
766 return -ENOMEM;
767 }
768 gp->page_no = page_no;
769 gp->max_reads = max_reads;
770 list_add(&gp->list, &grave_pages);
771 } while (*g);
772 return 0;
773}
774
775static int read_error(unsigned int page_no)
776{
777 struct grave_page *gp;
778
779 list_for_each_entry(gp, &grave_pages, list)
780 if (gp->page_no == page_no) {
781 if (gp->reads_done >= gp->max_reads)
782 return 1;
783 gp->reads_done += 1;
784 return 0;
785 }
786 return 0;
787}
788
789static void free_lists(void)
790{
791 struct list_head *pos, *n;
792 list_for_each_safe(pos, n, &weak_blocks) {
793 list_del(pos);
794 kfree(list_entry(pos, struct weak_block, list));
795 }
796 list_for_each_safe(pos, n, &weak_pages) {
797 list_del(pos);
798 kfree(list_entry(pos, struct weak_page, list));
799 }
800 list_for_each_safe(pos, n, &grave_pages) {
801 list_del(pos);
802 kfree(list_entry(pos, struct grave_page, list));
803 }
804}
805
558/* 806/*
559 * Returns the string representation of 'state' state. 807 * Returns the string representation of 'state' state.
560 */ 808 */
@@ -867,9 +1115,31 @@ static void read_page(struct nandsim *ns, int num)
867 NS_DBG("read_page: page %d not allocated\n", ns->regs.row); 1115 NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
868 memset(ns->buf.byte, 0xFF, num); 1116 memset(ns->buf.byte, 0xFF, num);
869 } else { 1117 } else {
1118 unsigned int page_no = ns->regs.row;
870 NS_DBG("read_page: page %d allocated, reading from %d\n", 1119 NS_DBG("read_page: page %d allocated, reading from %d\n",
871 ns->regs.row, ns->regs.column + ns->regs.off); 1120 ns->regs.row, ns->regs.column + ns->regs.off);
1121 if (read_error(page_no)) {
1122 int i;
1123 memset(ns->buf.byte, 0xFF, num);
1124 for (i = 0; i < num; ++i)
1125 ns->buf.byte[i] = random32();
1126 NS_WARN("simulating read error in page %u\n", page_no);
1127 return;
1128 }
872 memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); 1129 memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
1130 if (bitflips && random32() < (1 << 22)) {
1131 int flips = 1;
1132 if (bitflips > 1)
1133 flips = (random32() % (int) bitflips) + 1;
1134 while (flips--) {
1135 int pos = random32() % (num * 8);
1136 ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
1137 NS_WARN("read_page: flipping bit %d in page %d "
1138 "reading from %d ecc: corrected=%u failed=%u\n",
1139 pos, ns->regs.row, ns->regs.column + ns->regs.off,
1140 nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
1141 }
1142 }
873 } 1143 }
874} 1144}
875 1145
@@ -928,6 +1198,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
928{ 1198{
929 int num; 1199 int num;
930 int busdiv = ns->busw == 8 ? 1 : 2; 1200 int busdiv = ns->busw == 8 ? 1 : 2;
1201 unsigned int erase_block_no, page_no;
931 1202
932 action &= ACTION_MASK; 1203 action &= ACTION_MASK;
933 1204
@@ -987,14 +1258,21 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
987 8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column; 1258 8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column;
988 ns->regs.column = 0; 1259 ns->regs.column = 0;
989 1260
1261 erase_block_no = ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift);
1262
990 NS_DBG("do_state_action: erase sector at address %#x, off = %d\n", 1263 NS_DBG("do_state_action: erase sector at address %#x, off = %d\n",
991 ns->regs.row, NS_RAW_OFFSET(ns)); 1264 ns->regs.row, NS_RAW_OFFSET(ns));
992 NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift)); 1265 NS_LOG("erase sector %u\n", erase_block_no);
993 1266
994 erase_sector(ns); 1267 erase_sector(ns);
995 1268
996 NS_MDELAY(erase_delay); 1269 NS_MDELAY(erase_delay);
997 1270
1271 if (erase_error(erase_block_no)) {
1272 NS_WARN("simulating erase failure in erase block %u\n", erase_block_no);
1273 return -1;
1274 }
1275
998 break; 1276 break;
999 1277
1000 case ACTION_PRGPAGE: 1278 case ACTION_PRGPAGE:
@@ -1017,6 +1295,8 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
1017 if (prog_page(ns, num) == -1) 1295 if (prog_page(ns, num) == -1)
1018 return -1; 1296 return -1;
1019 1297
1298 page_no = ns->regs.row;
1299
1020 NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n", 1300 NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
1021 num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off); 1301 num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);
1022 NS_LOG("programm page %d\n", ns->regs.row); 1302 NS_LOG("programm page %d\n", ns->regs.row);
@@ -1024,6 +1304,11 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
1024 NS_UDELAY(programm_delay); 1304 NS_UDELAY(programm_delay);
1025 NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv); 1305 NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv);
1026 1306
1307 if (write_error(page_no)) {
1308 NS_WARN("simulating write failure in page %u\n", page_no);
1309 return -1;
1310 }
1311
1027 break; 1312 break;
1028 1313
1029 case ACTION_ZEROOFF: 1314 case ACTION_ZEROOFF:
@@ -1602,6 +1887,15 @@ static int __init ns_init_module(void)
1602 1887
1603 nsmtd->owner = THIS_MODULE; 1888 nsmtd->owner = THIS_MODULE;
1604 1889
1890 if ((retval = parse_weakblocks()) != 0)
1891 goto error;
1892
1893 if ((retval = parse_weakpages()) != 0)
1894 goto error;
1895
1896 if ((retval = parse_gravepages()) != 0)
1897 goto error;
1898
1605 if ((retval = nand_scan(nsmtd, 1)) != 0) { 1899 if ((retval = nand_scan(nsmtd, 1)) != 0) {
1606 NS_ERR("can't register NAND Simulator\n"); 1900 NS_ERR("can't register NAND Simulator\n");
1607 if (retval > 0) 1901 if (retval > 0)
@@ -1612,6 +1906,9 @@ static int __init ns_init_module(void)
1612 if ((retval = init_nandsim(nsmtd)) != 0) 1906 if ((retval = init_nandsim(nsmtd)) != 0)
1613 goto err_exit; 1907 goto err_exit;
1614 1908
1909 if ((retval = parse_badblocks(nand, nsmtd)) != 0)
1910 goto err_exit;
1911
1615 if ((retval = nand_default_bbt(nsmtd)) != 0) 1912 if ((retval = nand_default_bbt(nsmtd)) != 0)
1616 goto err_exit; 1913 goto err_exit;
1617 1914
@@ -1628,6 +1925,7 @@ err_exit:
1628 kfree(nand->partitions[i].name); 1925 kfree(nand->partitions[i].name);
1629error: 1926error:
1630 kfree(nsmtd); 1927 kfree(nsmtd);
1928 free_lists();
1631 1929
1632 return retval; 1930 return retval;
1633} 1931}
@@ -1647,6 +1945,7 @@ static void __exit ns_cleanup_module(void)
1647 for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i) 1945 for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
1648 kfree(ns->partitions[i].name); 1946 kfree(ns->partitions[i].name);
1649 kfree(nsmtd); /* Free other structures */ 1947 kfree(nsmtd); /* Free other structures */
1948 free_lists();
1650} 1949}
1651 1950
1652module_exit(ns_cleanup_module); 1951module_exit(ns_cleanup_module);