Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / mtd / mtdconcat.c
index 5a4f02c..9af8403 100644 (file)
@@ -7,13 +7,14 @@
  *
  * This code is GPL
  *
- * $Id: mtdconcat.c,v 1.8 2003/06/30 11:01:26 dwmw2 Exp $
+ * $Id: mtdconcat.c,v 1.11 2005/11/07 11:14:20 gleixner Exp $
  */
 
-#include <linux/module.h>
-#include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/types.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/concat.h>
@@ -43,7 +44,7 @@ struct mtd_concat {
  */
 #define CONCAT(x)  ((struct mtd_concat *)(x))
 
-/* 
+/*
  * MTD methods which look up the relevant subdevice, translate the
  * effective address and pass through to the subdevice.
  */
@@ -391,7 +392,7 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
        struct mtd_concat *concat = CONCAT(mtd);
        struct mtd_info *subdev;
        int i, err;
-       u_int32_t length;
+       u_int32_t length, offset = 0;
        struct erase_info *erase;
 
        if (!(mtd->flags & MTD_WRITEABLE))
@@ -450,6 +451,8 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
                        return -EINVAL;
        }
 
+       instr->fail_addr = 0xffffffff;
+
        /* make a local copy of instr to avoid modifying the caller's struct */
        erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);
 
@@ -465,15 +468,16 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
         */
        for (i = 0; i < concat->num_subdev; i++) {
                subdev = concat->subdev[i];
-               if (subdev->size <= erase->addr)
+               if (subdev->size <= erase->addr) {
                        erase->addr -= subdev->size;
-               else
+                       offset += subdev->size;
+               } else {
                        break;
+               }
        }
 
        /* must never happen since size limit has been verified above */
-       if (i >= concat->num_subdev)
-               BUG();
+       BUG_ON(i >= concat->num_subdev);
 
        /* now do the erase: */
        err = 0;
@@ -495,8 +499,9 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
                if ((err = concat_dev_erase(subdev, erase))) {
                        /* sanity check: should never happen since
                         * block alignment has been checked above */
-                       if (err == -EINVAL)
-                               BUG();
+                       BUG_ON(err == -EINVAL);
+                       if (erase->fail_addr != 0xffffffff)
+                               instr->fail_addr = erase->fail_addr + offset;
                        break;
                }
                /*
@@ -508,12 +513,13 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
                 * current subdevice, i.e. at offset zero.
                 */
                erase->addr = 0;
+               offset += subdev->size;
        }
+       instr->state = erase->state;
        kfree(erase);
        if (err)
                return err;
 
-       instr->state = MTD_ERASE_DONE;
        if (instr->callback)
                instr->callback(instr);
        return 0;
@@ -870,7 +876,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],       /* subdevices to c
        return &concat->mtd;
 }
 
-/* 
+/*
  * This function destroys an MTD object obtained from concat_mtd_devs()
  */