This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / drivers / mtd / chips / cfi_cmdset_0001.c
index 9028cac..c1e3536 100644 (file)
@@ -4,9 +4,8 @@
  *
  * (C) 2000 Red Hat. GPL'd
  *
- * $Id: cfi_cmdset_0001.c,v 1.160 2004/11/01 06:02:24 nico Exp $
- * (+ suspend fix from v1.162)
- * (+ partition detection fix from v1.163)
+ * $Id: cfi_cmdset_0001.c,v 1.154 2004/08/09 13:19:43 dwmw2 Exp $
+ *
  * 
  * 10/10/2000  Nicolas Pitre <nico@cam.org>
  *     - completely revamped method functions so they are aware and
 // debugging, turns off buffer write mode if set to 1
 #define FORCE_WORD_WRITE 0
 
-#define MANUFACTURER_INTEL     0x0089
-#define I82802AB       0x00ad
-#define I82802AC       0x00ac
-#define MANUFACTURER_ST         0x0020
-#define M50LPW080       0x002F
-
 static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 //static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 //static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
@@ -62,19 +55,14 @@ static void cfi_intelext_destroy(struct mtd_info *);
 
 struct mtd_info *cfi_cmdset_0001(struct map_info *, int);
 
-static struct mtd_info *cfi_intelext_setup (struct mtd_info *);
-static int cfi_intelext_partition_fixup(struct mtd_info *, struct cfi_private **);
+static struct mtd_info *cfi_intelext_setup (struct map_info *);
+static int cfi_intelext_partition_fixup(struct map_info *, struct cfi_private **);
 
 static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
                     size_t *retlen, u_char **mtdbuf);
 static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
                        size_t len);
 
-static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
-static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr);
-#include "fwh_lock.h"
-
-
 
 /*
  *  *********** SETUP AND PROBE BITS  ***********
@@ -135,9 +123,8 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp)
 
 #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
 /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ 
-static void fixup_intel_strataflash(struct mtd_info *mtd, void* param)
+static void fixup_intel_strataflash(struct map_info *map, void* param)
 {
-       struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
        struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
 
@@ -147,18 +134,16 @@ static void fixup_intel_strataflash(struct mtd_info *mtd, void* param)
 }
 #endif
 
-static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param)
+static void fixup_st_m28w320ct(struct map_info *map, void* param)
 {
-       struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
        
        cfi->cfiq->BufWriteTimeoutTyp = 0;      /* Not supported */
        cfi->cfiq->BufWriteTimeoutMax = 0;      /* Not supported */
 }
 
-static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param)
+static void fixup_st_m28w320cb(struct map_info *map, void* param)
 {
-       struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
        
        /* Note this is done after the region info is endian swapped */
@@ -166,112 +151,25 @@ static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param)
                (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e;
 };
 
-static void fixup_use_point(struct mtd_info *mtd, void *param)
-{
-       struct map_info *map = mtd->priv;
-       if (!mtd->point && map_is_linear(map)) {
-               mtd->point   = cfi_intelext_point;
-               mtd->unpoint = cfi_intelext_unpoint;
-       }
-}
-
-static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
-{
-       struct map_info *map = mtd->priv;
-       struct cfi_private *cfi = map->fldrv_priv;
-       if (cfi->cfiq->BufWriteTimeoutTyp) {
-               printk(KERN_INFO "Using buffer write method\n" );
-               mtd->write = cfi_intelext_write_buffers;
-       }
-}
-
-static struct cfi_fixup cfi_fixup_table[] = {
+static struct cfi_fixup fixup_table[] = {
 #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
-       { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, 
+       {
+               CFI_MFR_ANY, CFI_ID_ANY,
+               fixup_intel_strataflash, NULL
+       }, 
 #endif
-#if !FORCE_WORD_WRITE
-       { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL },
-#endif
-       { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
-       { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
-       { 0, 0, NULL, NULL }
-};
-
-static struct cfi_fixup jedec_fixup_table[] = {
-       { MANUFACTURER_INTEL, I82802AB,   fixup_use_fwh_lock, NULL, },
-       { MANUFACTURER_INTEL, I82802AC,   fixup_use_fwh_lock, NULL, },
-       { MANUFACTURER_ST,    M50LPW080,  fixup_use_fwh_lock, NULL, },
-       { 0, 0, NULL, NULL }
-};
-static struct cfi_fixup fixup_table[] = {
-       /* The CFI vendor ids and the JEDEC vendor IDs appear
-        * to be common.  It is like the devices id's are as
-        * well.  This table is to pick all cases where
-        * we know that is the case.
-        */
-       { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_point, NULL },
-       { 0, 0, NULL, NULL }
-};
-
-static inline struct cfi_pri_intelext *
-read_pri_intelext(struct map_info *map, __u16 adr)
-{
-       struct cfi_pri_intelext *extp;
-       unsigned int extp_size = sizeof(*extp);
-
- again:
-       extp = (struct cfi_pri_intelext *)cfi_read_pri(map, adr, extp_size, "Intel/Sharp");
-       if (!extp)
-               return NULL;
-
-       /* Do some byteswapping if necessary */
-       extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
-       extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
-       extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
-
-       if (extp->MajorVersion == '1' && extp->MinorVersion == '3') {
-               unsigned int extra_size = 0;
-               int nb_parts, i;
-
-               /* Protection Register info */
-               extra_size += (extp->NumProtectionFields - 1) * (4 + 6);
-
-               /* Burst Read info */
-               extra_size += 6;
-
-               /* Number of hardware-partitions */
-               extra_size += 1;
-               if (extp_size < sizeof(*extp) + extra_size)
-                       goto need_more;
-               nb_parts = extp->extra[extra_size - 1];
-
-               for (i = 0; i < nb_parts; i++) {
-                       struct cfi_intelext_regioninfo *rinfo;
-                       rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[extra_size];
-                       extra_size += sizeof(*rinfo);
-                       if (extp_size < sizeof(*extp) + extra_size)
-                               goto need_more;
-                       rinfo->NumIdentPartitions=le16_to_cpu(rinfo->NumIdentPartitions);
-                       extra_size += (rinfo->NumBlockTypes - 1)
-                                     * sizeof(struct cfi_intelext_blockinfo);
-               }
-
-               if (extp_size < sizeof(*extp) + extra_size) {
-                       need_more:
-                       extp_size = sizeof(*extp) + extra_size;
-                       kfree(extp);
-                       if (extp_size > 4096) {
-                               printk(KERN_ERR
-                                       "%s: cfi_pri_intelext is too fat\n",
-                                       __FUNCTION__);
-                               return NULL;
-                       }
-                       goto again;
-               }
+       {
+               0x0020, /* STMicroelectronics */
+               0x00ba, /* M28W320CT */
+               fixup_st_m28w320ct, NULL
+       }, {
+               0x0020, /* STMicroelectronics */
+               0x00bb, /* M28W320CB */
+               fixup_st_m28w320cb, NULL
+       }, {
+               0, 0, NULL, NULL
        }
-               
-       return extp;
-}
+};
 
 /* This routine is made available to other mtd code via
  * inter_module_register.  It must only be accessed through
@@ -283,30 +181,8 @@ read_pri_intelext(struct map_info *map, __u16 adr)
 struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
 {
        struct cfi_private *cfi = map->fldrv_priv;
-       struct mtd_info *mtd;
        int i;
 
-       mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
-       if (!mtd) {
-               printk(KERN_ERR "Failed to allocate memory for MTD device\n");
-               return NULL;
-       }
-       memset(mtd, 0, sizeof(*mtd));
-       mtd->priv = map;
-       mtd->type = MTD_NORFLASH;
-
-       /* Fill in the default mtd operations */
-       mtd->erase   = cfi_intelext_erase_varsize;
-       mtd->read    = cfi_intelext_read;
-       mtd->write   = cfi_intelext_write_words;
-       mtd->sync    = cfi_intelext_sync;
-       mtd->lock    = cfi_intelext_lock;
-       mtd->unlock  = cfi_intelext_unlock;
-       mtd->suspend = cfi_intelext_suspend;
-       mtd->resume  = cfi_intelext_resume;
-       mtd->flags   = MTD_CAP_NORFLASH;
-       mtd->name    = map->name;
-       
        if (cfi->cfi_mode == CFI_MODE_CFI) {
                /* 
                 * It's a real CFI chip, not one for which the probe
@@ -316,17 +192,20 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
                __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
                struct cfi_pri_intelext *extp;
 
-               extp = read_pri_intelext(map, adr);
-               if (!extp) {
-                       kfree(mtd);
+               extp = (struct cfi_pri_intelext*)cfi_read_pri(map, adr, sizeof(*extp), "Intel/Sharp");
+               if (!extp)
                        return NULL;
-               }
+               
+               /* Do some byteswapping if necessary */
+               extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
+               extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
+               extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
 
                /* Install our own private info structure */
                cfi->cmdset_priv = extp;        
 
-               cfi_fixup(mtd, cfi_fixup_table);
-
+               cfi_fixup(map, fixup_table);
+                       
 #ifdef DEBUG_CFI_FEATURES
                /* Tell the user about it in lots of lovely detail */
                cfi_tell_features(extp);
@@ -336,12 +215,6 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
                        printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n");
                }
        }
-       else if (cfi->cfi_mode == CFI_MODE_JEDEC) {
-               /* Apply jedec specific fixups */
-               cfi_fixup(mtd, jedec_fixup_table);
-       }
-       /* Apply generic fixups */
-       cfi_fixup(mtd, fixup_table);
 
        for (i=0; i< cfi->numchips; i++) {
                cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
@@ -352,19 +225,28 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
 
        map->fldrv = &cfi_intelext_chipdrv;
        
-       return cfi_intelext_setup(mtd);
+       return cfi_intelext_setup(map);
 }
 
-static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
+static struct mtd_info *cfi_intelext_setup(struct map_info *map)
 {
-       struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
+       struct mtd_info *mtd;
        unsigned long offset = 0;
        int i,j;
        unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
 
+       mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
        //printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips);
 
+       if (!mtd) {
+               printk(KERN_ERR "Failed to allocate memory for MTD device\n");
+               goto setup_err;
+       }
+
+       memset(mtd, 0, sizeof(*mtd));
+       mtd->priv = map;
+       mtd->type = MTD_NORFLASH;
        mtd->size = devsize * cfi->numchips;
 
        mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
@@ -404,14 +286,38 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
                       mtd->eraseregions[i].numblocks);
        }
 
+       /* Also select the correct geometry setup too */ 
+       mtd->erase = cfi_intelext_erase_varsize;
+       mtd->read = cfi_intelext_read;
+
+       if (map_is_linear(map)) {
+               mtd->point = cfi_intelext_point;
+               mtd->unpoint = cfi_intelext_unpoint;
+       }
+
+       if ( cfi->cfiq->BufWriteTimeoutTyp && !FORCE_WORD_WRITE) {
+               printk(KERN_INFO "Using buffer write method\n" );
+               mtd->write = cfi_intelext_write_buffers;
+       } else {
+               printk(KERN_INFO "Using word write method\n" );
+               mtd->write = cfi_intelext_write_words;
+       }
 #if 0
        mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
        mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
 #endif
+       mtd->sync = cfi_intelext_sync;
+       mtd->lock = cfi_intelext_lock;
+       mtd->unlock = cfi_intelext_unlock;
+       mtd->suspend = cfi_intelext_suspend;
+       mtd->resume = cfi_intelext_resume;
+       mtd->flags = MTD_CAP_NORFLASH;
+       map->fldrv = &cfi_intelext_chipdrv;
+       mtd->name = map->name;
 
        /* This function has the potential to distort the reality
           a bit and therefore should be called last. */
-       if (cfi_intelext_partition_fixup(mtd, &cfi) != 0)
+       if (cfi_intelext_partition_fixup(map, &cfi) != 0)
                goto setup_err;
 
        __module_get(THIS_MODULE);
@@ -427,16 +333,20 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
        return NULL;
 }
 
-static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
+static int cfi_intelext_partition_fixup(struct map_info *map,
                                        struct cfi_private **pcfi)
 {
-       struct map_info *map = mtd->priv;
        struct cfi_private *cfi = *pcfi;
        struct cfi_pri_intelext *extp = cfi->cmdset_priv;
 
        /*
         * Probing of multi-partition flash ships.
         *
+        * This is extremely crude at the moment and should probably be
+        * extracted entirely from the Intel extended query data instead.
+        * Right now a L18 flash is assumed if multiple operations is
+        * detected.
+        *
         * To support multiple partitions when available, we simply arrange
         * for each of them to have their own flchip structure even if they
         * are on the same physical chip.  This means completely recreating
@@ -445,49 +355,20 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
         * arrangement at this point. This can be rearranged in the future
         * if someone feels motivated enough.  --nico
         */
-       if (extp && extp->MajorVersion == '1' && extp->MinorVersion == '3'
-           && extp->FeatureSupport & (1 << 9)) {
+       if (extp && extp->FeatureSupport & (1 << 9)) {
                struct cfi_private *newcfi;
                struct flchip *chip;
                struct flchip_shared *shared;
-               int offs, numregions, numparts, partshift, numvirtchips, i, j;
-
-               /* Protection Register info */
-               offs = (extp->NumProtectionFields - 1) * (4 + 6);
-
-               /* Burst Read info */
-               offs += 6;
-
-               /* Number of partition regions */
-               numregions = extp->extra[offs];
-               offs += 1;
-
-               /* Number of hardware partitions */
-               numparts = 0;
-               for (i = 0; i < numregions; i++) {
-                       struct cfi_intelext_regioninfo *rinfo;
-                       rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[offs];
-                       numparts += rinfo->NumIdentPartitions;
-                       offs += sizeof(*rinfo)
-                               + (rinfo->NumBlockTypes - 1) *
-                                 sizeof(struct cfi_intelext_blockinfo);
-               }
+               int numparts, partshift, numvirtchips, i, j;
 
                /*
-                * All functions below currently rely on all chips having
-                * the same geometry so we'll just assume that all hardware
-                * partitions are of the same size too.
+                * The L18 flash memory array is divided
+                * into multiple 8-Mbit partitions.
                 */
-               partshift = cfi->chipshift - __ffs(numparts);
-
-               if ((1 << partshift) < mtd->erasesize) {
-                       printk( KERN_ERR
-                               "%s: bad number of hw partitions (%d)\n",
-                               __FUNCTION__, numparts);
-                       return -EINVAL;
-               }
-
+               numparts = 1 << (cfi->cfiq->DevSize - 20);
+               partshift = 20 + __ffs(cfi->interleave);
                numvirtchips = cfi->numchips * numparts;
+
                newcfi = kmalloc(sizeof(struct cfi_private) + numvirtchips * sizeof(struct flchip), GFP_KERNEL);
                if (!newcfi)
                        return -ENOMEM;
@@ -517,10 +398,10 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
                        }
                }
 
-               printk(KERN_DEBUG "%s: %d set(s) of %d interleaved chips "
-                                 "--> %d partitions of %d KiB\n",
+               printk(KERN_DEBUG "%s: %d sets of %d interleaved chips "
+                                 "--> %d partitions of %#x bytes\n",
                                  map->name, cfi->numchips, cfi->interleave,
-                                 newcfi->numchips, 1<<(newcfi->chipshift-10));
+                                 newcfi->numchips, 1<<newcfi->chipshift);
 
                map->fldrv_priv = newcfi;
                *pcfi = newcfi;
@@ -634,8 +515,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                return 0;
 
        case FL_ERASING:
-               if (!cfip ||
-                   !(cfip->FeatureSupport & 2) ||
+               if (!(cfip->FeatureSupport & 2) ||
                    !(mode == FL_READY || mode == FL_POINT ||
                     (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1))))
                        goto sleep;
@@ -942,7 +822,6 @@ static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, siz
        }
        return ret;
 }
-
 #if 0
 static int cfi_intelext_read_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, int base_offst, int reg_sz)
 {
@@ -1005,7 +884,7 @@ static int cfi_intelext_read_user_prot_reg (struct mtd_info *mtd, loff_t from, s
        int base_offst,reg_sz;
        
        /* Check that we actually have some protection registers */
-       if(!extp || !(extp->FeatureSupport&64)){
+       if(!(extp->FeatureSupport&64)){
                printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
                return 0;
        }
@@ -1024,7 +903,7 @@ static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, s
        int base_offst,reg_sz;
        
        /* Check that we actually have some protection registers */
-       if(!extp || !(extp->FeatureSupport&64)){
+       if(!(extp->FeatureSupport&64)){
                printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
                return 0;
        }
@@ -1110,7 +989,6 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
 
        /* Done and happy. */
        chip->state = FL_STATUS;
-
        /* check for lock bit */
        if (map_word_bitsset(map, status, CMD(0x02))) {
                /* clear status */
@@ -1262,15 +1140,13 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
 
                if (++z > 20) {
                        /* Argh. Not ready for write to buffer */
-                       map_word Xstatus;
                        map_write(map, CMD(0x70), cmd_adr);
                        chip->state = FL_STATUS;
-                       Xstatus = map_read(map, cmd_adr);
+                       printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %lx, status = %lx\n",
+                              status.x[0], map_read(map, cmd_adr).x[0]);
                        /* Odd. Clear status bits */
                        map_write(map, CMD(0x50), cmd_adr);
                        map_write(map, CMD(0x70), cmd_adr);
-                       printk(KERN_ERR "Chip not ready for buffer write. status = %lx, Xstatus = %lx\n",
-                              status.x[0], Xstatus.x[0]);
                        ret = -EIO;
                        goto out;
                }
@@ -1432,6 +1308,102 @@ static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to,
        return 0;
 }
 
+typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip,
+                             unsigned long adr, int len, void *thunk);
+
+static int cfi_intelext_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
+                                    loff_t ofs, size_t len, void *thunk)
+{
+       struct map_info *map = mtd->priv;
+       struct cfi_private *cfi = map->fldrv_priv;
+       unsigned long adr;
+       int chipnum, ret = 0;
+       int i, first;
+       struct mtd_erase_region_info *regions = mtd->eraseregions;
+
+       if (ofs > mtd->size)
+               return -EINVAL;
+
+       if ((len + ofs) > mtd->size)
+               return -EINVAL;
+
+       /* Check that both start and end of the requested erase are
+        * aligned with the erasesize at the appropriate addresses.
+        */
+
+       i = 0;
+
+       /* Skip all erase regions which are ended before the start of 
+          the requested erase. Actually, to save on the calculations,
+          we skip to the first erase region which starts after the
+          start of the requested erase, and then go back one.
+       */
+       
+       while (i < mtd->numeraseregions && ofs >= regions[i].offset)
+              i++;
+       i--;
+
+       /* OK, now i is pointing at the erase region in which this 
+          erase request starts. Check the start of the requested
+          erase range is aligned with the erase size which is in
+          effect here.
+       */
+
+       if (ofs & (regions[i].erasesize-1))
+               return -EINVAL;
+
+       /* Remember the erase region we start on */
+       first = i;
+
+       /* Next, check that the end of the requested erase is aligned
+        * with the erase region at that address.
+        */
+
+       while (i<mtd->numeraseregions && (ofs + len) >= regions[i].offset)
+               i++;
+
+       /* As before, drop back one to point at the region in which
+          the address actually falls
+       */
+       i--;
+       
+       if ((ofs + len) & (regions[i].erasesize-1))
+               return -EINVAL;
+
+       chipnum = ofs >> cfi->chipshift;
+       adr = ofs - (chipnum << cfi->chipshift);
+
+       i=first;
+
+       while(len) {
+               unsigned long chipmask;
+               int size = regions[i].erasesize;
+
+               ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk);
+               
+               if (ret)
+                       return ret;
+
+               adr += size;
+               len -= size;
+
+               chipmask = (1 << cfi->chipshift) - 1;
+               if ((adr & chipmask) == ((regions[i].offset + size * regions[i].numblocks) & chipmask))
+                       i++;
+
+               if (adr >> cfi->chipshift) {
+                       adr = 0;
+                       chipnum++;
+                       
+                       if (chipnum >= cfi->numchips)
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+
 static int do_erase_oneblock(struct map_info *map, struct flchip *chip,
                             unsigned long adr, int len, void *thunk)
 {
@@ -1498,17 +1470,16 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip,
                
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
-                       map_word Xstatus;
                        map_write(map, CMD(0x70), adr);
                        chip->state = FL_STATUS;
-                       Xstatus = map_read(map, adr);
+                       printk(KERN_ERR "waiting for erase at %08lx to complete timed out. Xstatus = %lx, status = %lx.\n",
+                              adr, status.x[0], map_read(map, adr).x[0]);
                        /* Clear status bits */
                        map_write(map, CMD(0x50), adr);
                        map_write(map, CMD(0x70), adr);
-                       printk(KERN_ERR "waiting for erase at %08lx to complete timed out. status = %lx, Xstatus = %lx.\n",
-                              adr, status.x[0], Xstatus.x[0]);
-                       ret = -EIO;
-                       goto out;
+                       DISABLE_VPP(map);
+                       spin_unlock(chip->mutex);
+                       return -EIO;
                }
                
                /* Latency issues. Drop the lock, wait a while and retry */
@@ -1517,6 +1488,9 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip,
                schedule_timeout(1);
                spin_lock(chip->mutex);
        }
+       
+       DISABLE_VPP(map);
+       ret = 0;
 
        /* We've broken this before. It doesn't hurt to be safe */
        map_write(map, CMD(0x70), adr);
@@ -1525,13 +1499,7 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip,
 
        /* check for lock bit */
        if (map_word_bitsset(map, status, CMD(0x3a))) {
-               unsigned char chipstatus;
-
-               /* Reset the error bits */
-               map_write(map, CMD(0x50), adr);
-               map_write(map, CMD(0x70), adr);
-
-               chipstatus = status.x[0];
+               unsigned char chipstatus = status.x[0];
                if (!map_word_equal(map, status, CMD(chipstatus))) {
                        int i, w;
                        for (w=0; w<map_words(map); w++) {
@@ -1542,7 +1510,10 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip,
                        printk(KERN_WARNING "Status is not identical for all chips: 0x%lx. Merging to give 0x%02x\n",
                               status.x[0], chipstatus);
                }
-
+               /* Reset the error bits */
+               map_write(map, CMD(0x50), adr);
+               map_write(map, CMD(0x70), adr);
+               
                if ((chipstatus & 0x30) == 0x30) {
                        printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus);
                        ret = -EIO;
@@ -1557,18 +1528,16 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip,
                        if (retries--) {
                                printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, chipstatus);
                                timeo = jiffies + HZ;
-                               put_chip(map, chip, adr);
+                               chip->state = FL_STATUS;
                                spin_unlock(chip->mutex);
                                goto retry;
                        }
                        printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, chipstatus);
                        ret = -EIO;
                }
-       } else {
-               ret = 0;
        }
 
out:  put_chip(map, chip, adr);
      wake_up(&chip->wq);
        spin_unlock(chip->mutex);
        return ret;
 }
@@ -1581,7 +1550,7 @@ int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
        ofs = instr->addr;
        len = instr->len;
 
-       ret = cfi_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL);
+       ret = cfi_intelext_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL);
        if (ret)
                return ret;
 
@@ -1636,13 +1605,12 @@ static int do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip
                                       unsigned long adr, int len, void *thunk)
 {
        struct cfi_private *cfi = map->fldrv_priv;
-       int status, ofs_factor = cfi->interleave * cfi->device_type;
+       int ofs_factor = cfi->interleave * cfi->device_type;
 
        cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
-       chip->state = FL_JEDEC_QUERY;
-       status = cfi_read_query(map, adr+(2*ofs_factor));
        printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
-              adr, status);
+              adr, cfi_read_query(map, adr+(2*ofs_factor)));
+       chip->state = FL_JEDEC_QUERY;
        return 0;
 }
 #endif
@@ -1698,13 +1666,11 @@ static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip,
                
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
-                       map_word Xstatus;
                        map_write(map, CMD(0x70), adr);
                        chip->state = FL_STATUS;
-                       Xstatus = map_read(map, adr);
-                       printk(KERN_ERR "waiting for unlock to complete timed out. status = %lx, Xstatus = %lx.\n",
-                              status.x[0], Xstatus.x[0]);
-                       put_chip(map, chip, adr);
+                       printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %lx, status = %lx.\n",
+                              status.x[0], map_read(map, adr).x[0]);
+                       DISABLE_VPP(map);
                        spin_unlock(chip->mutex);
                        return -EIO;
                }
@@ -1729,18 +1695,18 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
 #ifdef DEBUG_LOCK_BITS
        printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
               __FUNCTION__, ofs, len);
-       cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
-               ofs, len, 0);
+       cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
+                                 ofs, len, 0);
 #endif
 
-       ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, 
-               ofs, len, DO_XXLOCK_ONEBLOCK_LOCK);
+       ret = cfi_intelext_varsize_frob(mtd, do_xxlock_oneblock, 
+                                       ofs, len, DO_XXLOCK_ONEBLOCK_LOCK);
        
 #ifdef DEBUG_LOCK_BITS
        printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
               __FUNCTION__, ret);
-       cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
-               ofs, len, 0);
+       cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
+                                 ofs, len, 0);
 #endif
 
        return ret;
@@ -1753,18 +1719,18 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
 #ifdef DEBUG_LOCK_BITS
        printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
               __FUNCTION__, ofs, len);
-       cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
-               ofs, len, 0);
+       cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
+                                 ofs, len, 0);
 #endif
 
-       ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,
+       ret = cfi_intelext_varsize_frob(mtd, do_xxlock_oneblock,
                                        ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK);
        
 #ifdef DEBUG_LOCK_BITS
        printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
               __FUNCTION__, ret);
-       cfi_varsize_frob(mtd, do_printlockstatus_oneblock, 
-               ofs, len, 0);
+       cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock, 
+                                 ofs, len, 0);
 #endif
        
        return ret;
@@ -1795,18 +1761,9 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)
                                 * as the whole point is that nobody can do anything
                                 * with the chip now anyway.
                                 */
-                       } else {
-                               /* There seems to be an operation pending. We must wait for it. */
-                               printk(KERN_NOTICE "Flash device refused suspend due to pending operation (oldstate %d)\n", chip->oldstate);
-                               ret = -EAGAIN;
                        }
                        break;
                default:
-                       /* Should we actually wait? Once upon a time these routines weren't
-                          allowed to. Or should we return -EAGAIN, because the upper layers
-                          ought to have already shut down anything which was using the device
-                          anyway? The latter for now. */
-                       printk(KERN_NOTICE "Flash device refused suspend due to active operation (state %d)\n", chip->oldstate);
                        ret = -EAGAIN;
                case FL_PM_SUSPENDED:
                        break;
@@ -1827,7 +1784,6 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)
                                   because we're returning failure, and it didn't
                                   get power cycled */
                                chip->state = chip->oldstate;
-                               chip->oldstate = FL_READY;
                                wake_up(&chip->wq);
                        }
                        spin_unlock(chip->mutex);
@@ -1853,7 +1809,7 @@ static void cfi_intelext_resume(struct mtd_info *mtd)
                /* Go to known state. Chip may have been power cycled */
                if (chip->state == FL_PM_SUSPENDED) {
                        map_write(map, CMD(0xFF), cfi->chips[i].start);
-                       chip->oldstate = chip->state = FL_READY;
+                       chip->state = FL_READY;
                        wake_up(&chip->wq);
                }