Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=211ac75f5e867ab7a54811a514814149caca42c3
Commit:     211ac75f5e867ab7a54811a514814149caca42c3
Parent:     81f38e11233dae671c0673bbdcea01194b75d68f
Author:     Kyungmin Park <[EMAIL PROTECTED]>
AuthorDate: Wed Feb 7 12:15:01 2007 +0900
Committer:  Kyungmin Park <[EMAIL PROTECTED]>
CommitDate: Wed Feb 7 12:15:01 2007 +0900

    [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 <[EMAIL PROTECTED]>
    Signed-off-by: Kyungmin Park <[EMAIL PROTECTED]>
---
 drivers/mtd/onenand/onenand_base.c |  157 +++++++++++++++++++++++++++++++-----
 drivers/mtd/onenand/onenand_bbt.c  |   21 +++--
 include/linux/mtd/bbm.h            |    7 ++
 3 files changed, 155 insertions(+), 30 deletions(-)

diff --git a/drivers/mtd/onenand/onenand_base.c 
b/drivers/mtd/onenand/onenand_base.c
index 3d6f880..f690c19 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)
        ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
 
        if (ctrl & ONENAND_CTRL_ERROR) {
-               DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: controller error = 
0x%04x\n", ctrl);
+               printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", 
ctrl);
                if (ctrl & ONENAND_CTRL_LOCK)
-                       DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: it's locked 
error.\n");
+                       printk(KERN_ERR "onenand_wait: it's locked error.\n");
                return ctrl;
        }
 
        if (interrupt & ONENAND_INT_READ) {
                int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
                if (ecc) {
-                       DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error = 
0x%04x\n", ecc);
+                       printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", 
ecc);
                        if (ecc & ONENAND_ECC_2BIT_ALL) {
                                mtd->ecc_stats.failed++;
                                return ecc;
@@ -703,7 +703,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, 
size_t len,
 
        /* Do not allow reads past end of device */
        if ((from + len) > mtd->size) {
-               DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: Attempt read beyond end 
of device\n");
+               printk(KERN_ERR "onenand_read: Attempt read beyond end of 
device\n");
                *retlen = 0;
                return -EINVAL;
        }
@@ -834,7 +834,7 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, 
uint8_t *buf, int col
  *
  * OneNAND read out-of-band data from the spare area
  */
-int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
+static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
                        size_t *retlen, u_char *buf, mtd_oob_mode_t mode)
 {
        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,
        column = from & (mtd->oobsize - 1);
 
        if (unlikely(column >= oobsize)) {
-               DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempted to start 
read outside oob\n");
+               printk(KERN_ERR "onenand_read_oob: Attempted to start read 
outside oob\n");
                return -EINVAL;
        }
 
@@ -862,7 +862,7 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, 
size_t len,
        if (unlikely(from >= mtd->size ||
                     column + len > ((mtd->size >> this->page_shift) -
                                     (from >> this->page_shift)) * oobsize)) {
-               DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempted to read 
beyond end of device\n");
+               printk(KERN_ERR "onenand_read_oob: Attempted to read beyond end 
of device\n");
                return -EINVAL;
        }
 
@@ -888,7 +888,7 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, 
size_t len,
                        this->read_bufferram(mtd, ONENAND_SPARERAM, buf, 
column, thislen);
 
                if (ret) {
-                       DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed 
= 0x%x\n", ret);
+                       printk(KERN_ERR "onenand_read_oob: read failed = 
0x%x\n", ret);
                        break;
                }
 
@@ -936,6 +936,121 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t 
from,
                                   &ops->oobretlen, ops->oobbuf, ops->mode);
 }
 
+/**
+ * onenand_bbt_wait - [DEFAULT] wait until the command is done
+ * @param mtd          MTD device structure
+ * @param state                state to select the max. timeout value
+ *
+ * Wait for command done.
+ */
+static int onenand_bbt_wait(struct mtd_info *mtd, int state)
+{
+       struct onenand_chip *this = mtd->priv;
+       unsigned long timeout;
+       unsigned int interrupt;
+       unsigned int ctrl;
+
+       /* The 20 msec is enough */
+       timeout = jiffies + msecs_to_jiffies(20);
+       while (time_before(jiffies, timeout)) {
+               interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
+               if (interrupt & ONENAND_INT_MASTER)
+                       break;
+       }
+       /* To get correct interrupt status in timeout case */
+       interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
+       ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
+
+       if (ctrl & ONENAND_CTRL_ERROR) {
+               printk(KERN_DEBUG "onenand_bbt_wait: controller error = 
0x%04x\n", ctrl);
+               /* Initial bad block case */
+               if (ctrl & ONENAND_CTRL_LOAD)
+                       return ONENAND_BBT_READ_ERROR;
+               return ONENAND_BBT_READ_FATAL_ERROR;
+       }
+
+       if (interrupt & ONENAND_INT_READ) {
+               int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
+               if (ecc & ONENAND_ECC_2BIT_ALL)
+                       return ONENAND_BBT_READ_ERROR;
+       } else {
+               printk(KERN_ERR "onenand_bbt_wait: read timeout!"
+                       "ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
+               return ONENAND_BBT_READ_FATAL_ERROR;
+       }
+
+       return 0;
+}
+
+/**
+ * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan
+ * @param mtd          MTD device structure
+ * @param from         offset to read from
+ * @param @ops         oob operation description structure
+ *
+ * OneNAND read out-of-band data from the spare area for bbt scan
+ */
+int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, 
+                           struct mtd_oob_ops *ops)
+{
+       struct onenand_chip *this = mtd->priv;
+       int read = 0, thislen, column;
+       int ret = 0;
+       size_t len = ops->ooblen;
+       u_char *buf = ops->oobbuf;
+
+       DEBUG(MTD_DEBUG_LEVEL3, "onenand_bbt_read_oob: from = 0x%08x, len = 
%i\n", (unsigned int) from, len);
+
+       /* Initialize return value */
+       ops->oobretlen = 0;
+
+       /* Do not allow reads past end of device */
+       if (unlikely((from + len) > mtd->size)) {
+               printk(KERN_ERR "onenand_bbt_read_oob: Attempt read beyond end 
of device\n");
+               return ONENAND_BBT_READ_FATAL_ERROR;
+       }
+
+       /* Grab the lock and see if the device is available */
+       onenand_get_device(mtd, FL_READING);
+
+       column = from & (mtd->oobsize - 1);
+
+       while (read < len) {
+               cond_resched();
+
+               thislen = mtd->oobsize - column;
+               thislen = min_t(int, thislen, len);
+
+               this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
+
+               onenand_update_bufferram(mtd, from, 0);
+
+               ret = onenand_bbt_wait(mtd, FL_READING);
+               if (ret)
+                       break;
+
+               this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, 
thislen);
+               read += thislen;
+               if (read == len)
+                       break;
+
+               buf += thislen;
+
+               /* Read more? */
+               if (read < len) {
+                       /* Update Page size */
+                       from += mtd->writesize;
+                       column = 0;
+               }
+       }
+
+       /* Deselect and wake up anyone waiting on the device */
+       onenand_release_device(mtd);
+
+       ops->oobretlen = read;
+       return ret;
+}
+
 #ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
 /**
  * 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,
 
        /* Do not allow writes past end of device */
        if (unlikely((to + len) > mtd->size)) {
-               DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt write to past 
end of device\n");
+               printk(KERN_ERR "onenand_write: Attempt write to past end of 
device\n");
                return -EINVAL;
        }
 
        /* Reject writes, which are not page aligned */
         if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {
-                DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt to write not 
page aligned data\n");
+                printk(KERN_ERR "onenand_write: Attempt to write not page 
aligned data\n");
                 return -EINVAL;
         }
 
@@ -1083,14 +1198,14 @@ static int onenand_write(struct mtd_info *mtd, loff_t 
to, size_t len,
                onenand_update_bufferram(mtd, to, !ret && !subpage);
 
                if (ret) {
-                       DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed 
%d\n", ret);
+                       printk(KERN_ERR "onenand_write: write filaed %d\n", 
ret);
                        break;
                }
 
                /* Only check verify write turn on */
                ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen);
                if (ret) {
-                       DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed 
%d\n", ret);
+                       printk(KERN_ERR "onenand_write: verify failed %d\n", 
ret);
                        break;
                }
 
@@ -1180,13 +1295,13 @@ static int onenand_do_write_oob(struct mtd_info *mtd, 
loff_t to, size_t len,
        column = to & (mtd->oobsize - 1);
 
        if (unlikely(column >= oobsize)) {
-               DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempted to start 
write outside oob\n");
+               printk(KERN_ERR "onenand_write_oob: Attempted to start write 
outside oob\n");
                return -EINVAL;
        }
 
        /* For compatibility with NAND: Do not allow write past end of page */
        if (column + len > oobsize) {
-               DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: "
+               printk(KERN_ERR "onenand_write_oob: "
                      "Attempt to write past end of page\n");
                return -EINVAL;
        }
@@ -1195,7 +1310,7 @@ static int onenand_do_write_oob(struct mtd_info *mtd, 
loff_t to, size_t len,
        if (unlikely(to >= mtd->size ||
                     column + len > ((mtd->size >> this->page_shift) -
                                     (to >> this->page_shift)) * oobsize)) {
-               DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempted to write 
past end of device\n");
+               printk(KERN_ERR "onenand_write_oob: Attempted to write past end 
of device\n");
                return -EINVAL;
        }
 
@@ -1225,13 +1340,13 @@ static int onenand_do_write_oob(struct mtd_info *mtd, 
loff_t to, size_t len,
 
                ret = this->wait(mtd, FL_WRITING);
                if (ret) {
-                       DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: write 
failed %d\n", ret);
+                       printk(KERN_ERR "onenand_write_oob: write failed %d\n", 
ret);
                        break;
                }
 
                ret = onenand_verify_oob(mtd, this->page_buf, to);
                if (ret) {
-                       DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: verify 
failed %d\n", ret);
+                       printk(KERN_ERR "onenand_write_oob: verify failed 
%d\n", ret);
                        break;
                }
 
@@ -1314,19 +1429,19 @@ static int onenand_erase(struct mtd_info *mtd, struct 
erase_info *instr)
 
        /* Start address must align on block boundary */
        if (unlikely(instr->addr & (block_size - 1))) {
-               DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Unaligned address\n");
+               printk(KERN_ERR "onenand_erase: Unaligned address\n");
                return -EINVAL;
        }
 
        /* Length must align on block boundary */
        if (unlikely(instr->len & (block_size - 1))) {
-               DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Length not block 
aligned\n");
+               printk(KERN_ERR "onenand_erase: Length not block aligned\n");
                return -EINVAL;
        }
 
        /* Do not allow erase past end of device */
        if (unlikely((instr->len + instr->addr) > mtd->size)) {
-               DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Erase past end of 
device\n");
+               printk(KERN_ERR "onenand_erase: Erase past end of device\n");
                return -EINVAL;
        }
 
@@ -1356,7 +1471,7 @@ static int onenand_erase(struct mtd_info *mtd, struct 
erase_info *instr)
                ret = this->wait(mtd, FL_ERASING);
                /* Check, if it is write protected */
                if (ret) {
-                       DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Failed erase, 
block %d\n", (unsigned) (addr >> this->erase_shift));
+                       printk(KERN_ERR "onenand_erase: Failed erase, block 
%d\n", (unsigned) (addr >> this->erase_shift));
                        instr->state = MTD_ERASE_FAILED;
                        instr->fail_addr = addr;
                        goto erase_exit;
diff --git a/drivers/mtd/onenand/onenand_bbt.c 
b/drivers/mtd/onenand/onenand_bbt.c
index acea9a1..aecdd50 100644
--- a/drivers/mtd/onenand/onenand_bbt.c
+++ b/drivers/mtd/onenand/onenand_bbt.c
@@ -17,8 +17,8 @@
 #include <linux/mtd/onenand.h>
 #include <linux/mtd/compatmac.h>
 
-extern int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
-                              size_t *retlen, u_char *buf, mtd_oob_mode_t 
mode);
+extern int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
+                               struct mtd_oob_ops *ops);
 
 /**
  * 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
        int startblock;
        loff_t from;
        size_t readlen, ooblen;
+       struct mtd_oob_ops ops;
 
        printk(KERN_INFO "Scanning device for bad blocks\n");
 
@@ -82,22 +83,24 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, 
struct nand_bbt_descr
        startblock = 0;
        from = 0;
 
+       ops.mode = MTD_OOB_PLACE;
+       ops.ooblen = readlen;
+       ops.oobbuf = buf;
+       ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
+
        for (i = startblock; i < numblocks; ) {
                int ret;
 
                for (j = 0; j < len; j++) {
-                       size_t retlen;
-
                        /* No need to read pages fully,
                         * just read required OOB bytes */
-                       ret = onenand_do_read_oob(mtd, from + j * 
mtd->writesize + bd->offs,
-                                                 readlen, &retlen, &buf[0], 
MTD_OOB_PLACE);
+                       ret = onenand_bbt_read_oob(mtd, from + j * 
mtd->writesize + bd->offs, &ops);
 
                        /* If it is a initial bad block, just ignore it */
-                       if (ret && !(ret & ONENAND_CTRL_LOAD))
-                               return ret;
+                       if (ret == ONENAND_BBT_READ_FATAL_ERROR)
+                               return -EIO;
 
-                       if (check_short_pattern(&buf[j * scanlen], scanlen, 
mtd->writesize, bd)) {
+                       if (ret || check_short_pattern(&buf[j * scanlen], 
scanlen, mtd->writesize, bd)) {
                                bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
                                printk(KERN_WARNING "Bad eraseblock %d at 
0x%08x\n",
                                        i >> 1, (unsigned int) from);
diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h
index 1221b7c..fff8c53 100644
--- a/include/linux/mtd/bbm.h
+++ b/include/linux/mtd/bbm.h
@@ -92,6 +92,13 @@ struct nand_bbt_descr {
  */
 #define ONENAND_BADBLOCK_POS   0
 
+/*
+ * Bad block scanning errors
+ */
+#define ONENAND_BBT_READ_ERROR         1
+#define ONENAND_BBT_READ_ECC_ERROR     2
+#define ONENAND_BBT_READ_FATAL_ERROR   4
+
 /**
  * struct bbm_info - [GENERIC] Bad Block Table data structure
  * @bbt_erase_shift:   [INTERN] number of address bits in a bbt entry
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to