| 
									
										
										
										
											2013-08-03 18:52:07 +09:00
										 |  |  | #define pr_fmt(fmt) "mtd_test: " fmt
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/init.h>
 | 
					
						
							|  |  |  | #include <linux/module.h>
 | 
					
						
							|  |  |  | #include <linux/sched.h>
 | 
					
						
							|  |  |  | #include <linux/printk.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "mtd_test.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int err; | 
					
						
							|  |  |  | 	struct erase_info ei; | 
					
						
							|  |  |  | 	loff_t addr = ebnum * mtd->erasesize; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memset(&ei, 0, sizeof(struct erase_info)); | 
					
						
							|  |  |  | 	ei.mtd  = mtd; | 
					
						
							|  |  |  | 	ei.addr = addr; | 
					
						
							|  |  |  | 	ei.len  = mtd->erasesize; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = mtd_erase(mtd, &ei); | 
					
						
							|  |  |  | 	if (err) { | 
					
						
							|  |  |  | 		pr_info("error %d while erasing EB %d\n", err, ebnum); | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ei.state == MTD_ERASE_FAILED) { | 
					
						
							|  |  |  | 		pr_info("some erase error occurred at EB %d\n", ebnum); | 
					
						
							|  |  |  | 		return -EIO; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int is_block_bad(struct mtd_info *mtd, unsigned int ebnum) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 	loff_t addr = ebnum * mtd->erasesize; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = mtd_block_isbad(mtd, addr); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		pr_info("block %d is bad\n", ebnum); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int mtdtest_scan_for_bad_eraseblocks(struct mtd_info *mtd, unsigned char *bbt, | 
					
						
							|  |  |  | 					unsigned int eb, int ebcnt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i, bad = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!mtd_can_have_bb(mtd)) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pr_info("scanning for bad eraseblocks\n"); | 
					
						
							|  |  |  | 	for (i = 0; i < ebcnt; ++i) { | 
					
						
							|  |  |  | 		bbt[i] = is_block_bad(mtd, eb + i) ? 1 : 0; | 
					
						
							|  |  |  | 		if (bbt[i]) | 
					
						
							|  |  |  | 			bad += 1; | 
					
						
							|  |  |  | 		cond_resched(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	pr_info("scanned %d eraseblocks, %d are bad\n", i, bad); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int mtdtest_erase_good_eraseblocks(struct mtd_info *mtd, unsigned char *bbt, | 
					
						
							|  |  |  | 				unsigned int eb, int ebcnt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int err; | 
					
						
							|  |  |  | 	unsigned int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < ebcnt; ++i) { | 
					
						
							|  |  |  | 		if (bbt[i]) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		err = mtdtest_erase_eraseblock(mtd, eb + i); | 
					
						
							|  |  |  | 		if (err) | 
					
						
							|  |  |  | 			return err; | 
					
						
							|  |  |  | 		cond_resched(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int mtdtest_read(struct mtd_info *mtd, loff_t addr, size_t size, void *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	size_t read; | 
					
						
							|  |  |  | 	int err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = mtd_read(mtd, addr, size, &read, buf); | 
					
						
							|  |  |  | 	/* Ignore corrected ECC errors */ | 
					
						
							|  |  |  | 	if (mtd_is_bitflip(err)) | 
					
						
							|  |  |  | 		err = 0; | 
					
						
							|  |  |  | 	if (!err && read != size) | 
					
						
							|  |  |  | 		err = -EIO; | 
					
						
							| 
									
										
										
										
											2013-08-15 22:55:08 +09:00
										 |  |  | 	if (err) | 
					
						
							|  |  |  | 		pr_err("error: read failed at %#llx\n", addr); | 
					
						
							| 
									
										
										
										
											2013-08-03 18:52:07 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int mtdtest_write(struct mtd_info *mtd, loff_t addr, size_t size, | 
					
						
							|  |  |  | 		const void *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	size_t written; | 
					
						
							|  |  |  | 	int err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = mtd_write(mtd, addr, size, &written, buf); | 
					
						
							|  |  |  | 	if (!err && written != size) | 
					
						
							|  |  |  | 		err = -EIO; | 
					
						
							| 
									
										
										
										
											2013-08-15 22:55:09 +09:00
										 |  |  | 	if (err) | 
					
						
							|  |  |  | 		pr_err("error: write failed at %#llx\n", addr); | 
					
						
							| 
									
										
										
										
											2013-08-03 18:52:07 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return err; | 
					
						
							|  |  |  | } |