aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyungmin Park <kyungmin.park@samsung.com>2007-02-06 22:15:01 -0500
committerKyungmin Park <kyungmin.park@samsung.com>2007-02-06 22:15:01 -0500
commit211ac75f5e867ab7a54811a514814149caca42c3 (patch)
treef73ec68bb5969aa0f522aa05a71737aa69626513
parent81f38e11233dae671c0673bbdcea01194b75d68f (diff)
[MTD] OneNAND: Error message printing and bad block scan erros
Provide the bad block scan with its own read function so that important error messages that are not from the the bad block scan, can always be printed. Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
-rw-r--r--drivers/mtd/onenand/onenand_base.c157
-rw-r--r--drivers/mtd/onenand/onenand_bbt.c21
-rw-r--r--include/linux/mtd/bbm.h7
3 files changed, 155 insertions, 30 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 3d6f880cba9c..f690c1916d1d 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -304,16 +304,16 @@ static int onenand_wait(struct mtd_info *mtd, int state)
304 ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); 304 ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
305 305
306 if (ctrl & ONENAND_CTRL_ERROR) { 306 if (ctrl & ONENAND_CTRL_ERROR) {
307 DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: controller error = 0x%04x\n", ctrl); 307 printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", ctrl);
308 if (ctrl & ONENAND_CTRL_LOCK) 308 if (ctrl & ONENAND_CTRL_LOCK)
309 DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: it's locked error.\n"); 309 printk(KERN_ERR "onenand_wait: it's locked error.\n");
310 return ctrl; 310 return ctrl;
311 } 311 }
312 312
313 if (interrupt & ONENAND_INT_READ) { 313 if (interrupt & ONENAND_INT_READ) {
314 int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); 314 int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
315 if (ecc) { 315 if (ecc) {
316 DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error = 0x%04x\n", ecc); 316 printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc);
317 if (ecc & ONENAND_ECC_2BIT_ALL) { 317 if (ecc & ONENAND_ECC_2BIT_ALL) {
318 mtd->ecc_stats.failed++; 318 mtd->ecc_stats.failed++;
319 return ecc; 319 return ecc;
@@ -703,7 +703,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
703 703
704 /* Do not allow reads past end of device */ 704 /* Do not allow reads past end of device */
705 if ((from + len) > mtd->size) { 705 if ((from + len) > mtd->size) {
706 DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: Attempt read beyond end of device\n"); 706 printk(KERN_ERR "onenand_read: Attempt read beyond end of device\n");
707 *retlen = 0; 707 *retlen = 0;
708 return -EINVAL; 708 return -EINVAL;
709 } 709 }
@@ -834,7 +834,7 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col
834 * 834 *
835 * OneNAND read out-of-band data from the spare area 835 * OneNAND read out-of-band data from the spare area
836 */ 836 */
837int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, 837static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
838 size_t *retlen, u_char *buf, mtd_oob_mode_t mode) 838 size_t *retlen, u_char *buf, mtd_oob_mode_t mode)
839{ 839{
840 struct onenand_chip *this = mtd->priv; 840 struct onenand_chip *this = mtd->priv;
@@ -854,7 +854,7 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
854 column = from & (mtd->oobsize - 1); 854 column = from & (mtd->oobsize - 1);
855 855
856 if (unlikely(column >= oobsize)) { 856 if (unlikely(column >= oobsize)) {
857 DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempted to start read outside oob\n"); 857 printk(KERN_ERR "onenand_read_oob: Attempted to start read outside oob\n");
858 return -EINVAL; 858 return -EINVAL;
859 } 859 }
860 860
@@ -862,7 +862,7 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
862 if (unlikely(from >= mtd->size || 862 if (unlikely(from >= mtd->size ||
863 column + len > ((mtd->size >> this->page_shift) - 863 column + len > ((mtd->size >> this->page_shift) -
864 (from >> this->page_shift)) * oobsize)) { 864 (from >> this->page_shift)) * oobsize)) {
865 DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempted to read beyond end of device\n"); 865 printk(KERN_ERR "onenand_read_oob: Attempted to read beyond end of device\n");
866 return -EINVAL; 866 return -EINVAL;
867 } 867 }
868 868
@@ -888,7 +888,7 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
888 this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); 888 this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
889 889
890 if (ret) { 890 if (ret) {
891 DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = 0x%x\n", ret); 891 printk(KERN_ERR "onenand_read_oob: read failed = 0x%x\n", ret);
892 break; 892 break;
893 } 893 }
894 894
@@ -936,6 +936,121 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
936 &ops->oobretlen, ops->oobbuf, ops->mode); 936 &ops->oobretlen, ops->oobbuf, ops->mode);
937} 937}
938 938
939/**
940 * onenand_bbt_wait - [DEFAULT] wait until the command is done
941 * @param mtd MTD device structure
942 * @param state state to select the max. timeout value
943 *
944 * Wait for command done.
945 */
946static int onenand_bbt_wait(struct mtd_info *mtd, int state)
947{
948 struct onenand_chip *this = mtd->priv;
949 unsigned long timeout;
950 unsigned int interrupt;
951 unsigned int ctrl;
952
953 /* The 20 msec is enough */
954 timeout = jiffies + msecs_to_jiffies(20);
955 while (time_before(jiffies, timeout)) {
956 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
957 if (interrupt & ONENAND_INT_MASTER)
958 break;
959 }
960 /* To get correct interrupt status in timeout case */
961 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
962 ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
963
964 if (ctrl & ONENAND_CTRL_ERROR) {
965 printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl);
966 /* Initial bad block case */
967 if (ctrl & ONENAND_CTRL_LOAD)
968 return ONENAND_BBT_READ_ERROR;
969 return ONENAND_BBT_READ_FATAL_ERROR;
970 }
971
972 if (interrupt & ONENAND_INT_READ) {
973 int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
974 if (ecc & ONENAND_ECC_2BIT_ALL)
975 return ONENAND_BBT_READ_ERROR;
976 } else {
977 printk(KERN_ERR "onenand_bbt_wait: read timeout!"
978 "ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
979 return ONENAND_BBT_READ_FATAL_ERROR;
980 }
981
982 return 0;
983}
984
985/**
986 * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan
987 * @param mtd MTD device structure
988 * @param from offset to read from
989 * @param @ops oob operation description structure
990 *
991 * OneNAND read out-of-band data from the spare area for bbt scan
992 */
993int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
994 struct mtd_oob_ops *ops)
995{
996 struct onenand_chip *this = mtd->priv;
997 int read = 0, thislen, column;
998 int ret = 0;
999 size_t len = ops->ooblen;
1000 u_char *buf = ops->oobbuf;
1001
1002 DEBUG(MTD_DEBUG_LEVEL3, "onenand_bbt_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, len);
1003
1004 /* Initialize return value */
1005 ops->oobretlen = 0;
1006
1007 /* Do not allow reads past end of device */
1008 if (unlikely((from + len) > mtd->size)) {
1009 printk(KERN_ERR "onenand_bbt_read_oob: Attempt read beyond end of device\n");
1010 return ONENAND_BBT_READ_FATAL_ERROR;
1011 }
1012
1013 /* Grab the lock and see if the device is available */
1014 onenand_get_device(mtd, FL_READING);
1015
1016 column = from & (mtd->oobsize - 1);
1017
1018 while (read < len) {
1019 cond_resched();
1020
1021 thislen = mtd->oobsize - column;
1022 thislen = min_t(int, thislen, len);
1023
1024 this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
1025
1026 onenand_update_bufferram(mtd, from, 0);
1027
1028 ret = onenand_bbt_wait(mtd, FL_READING);
1029 if (ret)
1030 break;
1031
1032 this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
1033 read += thislen;
1034 if (read == len)
1035 break;
1036
1037 buf += thislen;
1038
1039 /* Read more? */
1040 if (read < len) {
1041 /* Update Page size */
1042 from += mtd->writesize;
1043 column = 0;
1044 }
1045 }
1046
1047 /* Deselect and wake up anyone waiting on the device */
1048 onenand_release_device(mtd);
1049
1050 ops->oobretlen = read;
1051 return ret;
1052}
1053
939#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE 1054#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
940/** 1055/**
941 * onenand_verify_oob - [GENERIC] verify the oob contents after a write 1056 * onenand_verify_oob - [GENERIC] verify the oob contents after a write
@@ -1040,13 +1155,13 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
1040 1155
1041 /* Do not allow writes past end of device */ 1156 /* Do not allow writes past end of device */
1042 if (unlikely((to + len) > mtd->size)) { 1157 if (unlikely((to + len) > mtd->size)) {
1043 DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt write to past end of device\n"); 1158 printk(KERN_ERR "onenand_write: Attempt write to past end of device\n");
1044 return -EINVAL; 1159 return -EINVAL;
1045 } 1160 }
1046 1161
1047 /* Reject writes, which are not page aligned */ 1162 /* Reject writes, which are not page aligned */
1048 if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { 1163 if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {
1049 DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt to write not page aligned data\n"); 1164 printk(KERN_ERR "onenand_write: Attempt to write not page aligned data\n");
1050 return -EINVAL; 1165 return -EINVAL;
1051 } 1166 }
1052 1167
@@ -1083,14 +1198,14 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
1083 onenand_update_bufferram(mtd, to, !ret && !subpage); 1198 onenand_update_bufferram(mtd, to, !ret && !subpage);
1084 1199
1085 if (ret) { 1200 if (ret) {
1086 DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed %d\n", ret); 1201 printk(KERN_ERR "onenand_write: write filaed %d\n", ret);
1087 break; 1202 break;
1088 } 1203 }
1089 1204
1090 /* Only check verify write turn on */ 1205 /* Only check verify write turn on */
1091 ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen); 1206 ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen);
1092 if (ret) { 1207 if (ret) {
1093 DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed %d\n", ret); 1208 printk(KERN_ERR "onenand_write: verify failed %d\n", ret);
1094 break; 1209 break;
1095 } 1210 }
1096 1211
@@ -1180,13 +1295,13 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
1180 column = to & (mtd->oobsize - 1); 1295 column = to & (mtd->oobsize - 1);
1181 1296
1182 if (unlikely(column >= oobsize)) { 1297 if (unlikely(column >= oobsize)) {
1183 DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempted to start write outside oob\n"); 1298 printk(KERN_ERR "onenand_write_oob: Attempted to start write outside oob\n");
1184 return -EINVAL; 1299 return -EINVAL;
1185 } 1300 }
1186 1301
1187 /* For compatibility with NAND: Do not allow write past end of page */ 1302 /* For compatibility with NAND: Do not allow write past end of page */
1188 if (column + len > oobsize) { 1303 if (column + len > oobsize) {
1189 DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: " 1304 printk(KERN_ERR "onenand_write_oob: "
1190 "Attempt to write past end of page\n"); 1305 "Attempt to write past end of page\n");
1191 return -EINVAL; 1306 return -EINVAL;
1192 } 1307 }
@@ -1195,7 +1310,7 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
1195 if (unlikely(to >= mtd->size || 1310 if (unlikely(to >= mtd->size ||
1196 column + len > ((mtd->size >> this->page_shift) - 1311 column + len > ((mtd->size >> this->page_shift) -
1197 (to >> this->page_shift)) * oobsize)) { 1312 (to >> this->page_shift)) * oobsize)) {
1198 DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempted to write past end of device\n"); 1313 printk(KERN_ERR "onenand_write_oob: Attempted to write past end of device\n");
1199 return -EINVAL; 1314 return -EINVAL;
1200 } 1315 }
1201 1316
@@ -1225,13 +1340,13 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
1225 1340
1226 ret = this->wait(mtd, FL_WRITING); 1341 ret = this->wait(mtd, FL_WRITING);
1227 if (ret) { 1342 if (ret) {
1228 DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: write failed %d\n", ret); 1343 printk(KERN_ERR "onenand_write_oob: write failed %d\n", ret);
1229 break; 1344 break;
1230 } 1345 }
1231 1346
1232 ret = onenand_verify_oob(mtd, this->page_buf, to); 1347 ret = onenand_verify_oob(mtd, this->page_buf, to);
1233 if (ret) { 1348 if (ret) {
1234 DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: verify failed %d\n", ret); 1349 printk(KERN_ERR "onenand_write_oob: verify failed %d\n", ret);
1235 break; 1350 break;
1236 } 1351 }
1237 1352
@@ -1314,19 +1429,19 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
1314 1429
1315 /* Start address must align on block boundary */ 1430 /* Start address must align on block boundary */
1316 if (unlikely(instr->addr & (block_size - 1))) { 1431 if (unlikely(instr->addr & (block_size - 1))) {
1317 DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Unaligned address\n"); 1432 printk(KERN_ERR "onenand_erase: Unaligned address\n");
1318 return -EINVAL; 1433 return -EINVAL;
1319 } 1434 }
1320 1435
1321 /* Length must align on block boundary */ 1436 /* Length must align on block boundary */
1322 if (unlikely(instr->len & (block_size - 1))) { 1437 if (unlikely(instr->len & (block_size - 1))) {
1323 DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Length not block aligned\n"); 1438 printk(KERN_ERR "onenand_erase: Length not block aligned\n");
1324 return -EINVAL; 1439 return -EINVAL;
1325 } 1440 }
1326 1441
1327 /* Do not allow erase past end of device */ 1442 /* Do not allow erase past end of device */
1328 if (unlikely((instr->len + instr->addr) > mtd->size)) { 1443 if (unlikely((instr->len + instr->addr) > mtd->size)) {
1329 DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Erase past end of device\n"); 1444 printk(KERN_ERR "onenand_erase: Erase past end of device\n");
1330 return -EINVAL; 1445 return -EINVAL;
1331 } 1446 }
1332 1447
@@ -1356,7 +1471,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
1356 ret = this->wait(mtd, FL_ERASING); 1471 ret = this->wait(mtd, FL_ERASING);
1357 /* Check, if it is write protected */ 1472 /* Check, if it is write protected */
1358 if (ret) { 1473 if (ret) {
1359 DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift)); 1474 printk(KERN_ERR "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift));
1360 instr->state = MTD_ERASE_FAILED; 1475 instr->state = MTD_ERASE_FAILED;
1361 instr->fail_addr = addr; 1476 instr->fail_addr = addr;
1362 goto erase_exit; 1477 goto erase_exit;
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c
index acea9a1a7297..aecdd50a1781 100644
--- a/drivers/mtd/onenand/onenand_bbt.c
+++ b/drivers/mtd/onenand/onenand_bbt.c
@@ -17,8 +17,8 @@
17#include <linux/mtd/onenand.h> 17#include <linux/mtd/onenand.h>
18#include <linux/mtd/compatmac.h> 18#include <linux/mtd/compatmac.h>
19 19
20extern int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, 20extern int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
21 size_t *retlen, u_char *buf, mtd_oob_mode_t mode); 21 struct mtd_oob_ops *ops);
22 22
23/** 23/**
24 * check_short_pattern - [GENERIC] check if a pattern is in the buffer 24 * check_short_pattern - [GENERIC] check if a pattern is in the buffer
@@ -65,6 +65,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
65 int startblock; 65 int startblock;
66 loff_t from; 66 loff_t from;
67 size_t readlen, ooblen; 67 size_t readlen, ooblen;
68 struct mtd_oob_ops ops;
68 69
69 printk(KERN_INFO "Scanning device for bad blocks\n"); 70 printk(KERN_INFO "Scanning device for bad blocks\n");
70 71
@@ -82,22 +83,24 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
82 startblock = 0; 83 startblock = 0;
83 from = 0; 84 from = 0;
84 85
86 ops.mode = MTD_OOB_PLACE;
87 ops.ooblen = readlen;
88 ops.oobbuf = buf;
89 ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
90
85 for (i = startblock; i < numblocks; ) { 91 for (i = startblock; i < numblocks; ) {
86 int ret; 92 int ret;
87 93
88 for (j = 0; j < len; j++) { 94 for (j = 0; j < len; j++) {
89 size_t retlen;
90
91 /* No need to read pages fully, 95 /* No need to read pages fully,
92 * just read required OOB bytes */ 96 * just read required OOB bytes */
93 ret = onenand_do_read_oob(mtd, from + j * mtd->writesize + bd->offs, 97 ret = onenand_bbt_read_oob(mtd, from + j * mtd->writesize + bd->offs, &ops);
94 readlen, &retlen, &buf[0], MTD_OOB_PLACE);
95 98
96 /* If it is a initial bad block, just ignore it */ 99 /* If it is a initial bad block, just ignore it */
97 if (ret && !(ret & ONENAND_CTRL_LOAD)) 100 if (ret == ONENAND_BBT_READ_FATAL_ERROR)
98 return ret; 101 return -EIO;
99 102
100 if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) { 103 if (ret || check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) {
101 bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); 104 bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
102 printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", 105 printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
103 i >> 1, (unsigned int) from); 106 i >> 1, (unsigned int) from);
diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h
index 1221b7c44158..fff8c53e5434 100644
--- a/include/linux/mtd/bbm.h
+++ b/include/linux/mtd/bbm.h
@@ -92,6 +92,13 @@ struct nand_bbt_descr {
92 */ 92 */
93#define ONENAND_BADBLOCK_POS 0 93#define ONENAND_BADBLOCK_POS 0
94 94
95/*
96 * Bad block scanning errors
97 */
98#define ONENAND_BBT_READ_ERROR 1
99#define ONENAND_BBT_READ_ECC_ERROR 2
100#define ONENAND_BBT_READ_FATAL_ERROR 4
101
95/** 102/**
96 * struct bbm_info - [GENERIC] Bad Block Table data structure 103 * struct bbm_info - [GENERIC] Bad Block Table data structure
97 * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry 104 * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry