Refactor nand driver layer. WIP: yaffs2 working on Linux
authorCharles Manning <cdhmanning@gmail.com>
Tue, 19 Jun 2012 02:32:23 +0000 (14:32 +1200)
committerCharles Manning <cdhmanning@gmail.com>
Tue, 19 Jun 2012 02:37:37 +0000 (14:37 +1200)
Signed-off-by: Charles Manning <cdhmanning@gmail.com>
18 files changed:
Makefile
yaffs_checkptrw.c
yaffs_guts.c
yaffs_guts.h
yaffs_mtdif.c [deleted file]
yaffs_mtdif.h
yaffs_mtdif1.h [deleted file]
yaffs_mtdif1_multi.c [deleted file]
yaffs_mtdif1_single.c [deleted file]
yaffs_mtdif2_multi.c [deleted file]
yaffs_mtdif2_single.c [deleted file]
yaffs_mtdif_multi.c [new file with mode: 0644]
yaffs_nand.c
yaffs_tagscompat.c
yaffs_tagscompat.h
yaffs_tagsmarshall.c [new file with mode: 0644]
yaffs_tagsmarshall.h [moved from yaffs_mtdif2.h with 52% similarity]
yaffs_vfs_multi.c

index 6722182858b5c8022474288cdc6d0a77334d56de..a34645895253a0555b3053923ed7bd8b80ded1ee 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -27,11 +27,12 @@ ifneq ($(KERNELRELEASE),)
 
        obj-m := $(YAFFS_O)
 
-       yaffs2-objs := yaffs_mtdif.o yaffs_mtdif2_single.o
-       yaffs2-objs += yaffs_mtdif1_single.o yaffs_packedtags1.o
+       yaffs2-objs := yaffs_mtdif_single.o
+       yaffs2-objs += yaffs_packedtags1.o
        yaffs2-objs += yaffs_ecc.o yaffs_vfs_single.o yaffs_guts.o
        yaffs2-objs += yaffs_packedtags2.o
        yaffs2-objs += yaffs_tagscompat.o
+       yaffs2-objs += yaffs_tagsmarshall.o
        yaffs2-objs += yaffs_checkptrw.o yaffs_nand.o
        yaffs2-objs += yaffs_checkptrw.o yaffs_nand.o yaffs_nameval.o
        yaffs2-objs += yaffs_allocator.o yaffs_bitmap.o yaffs_attribs.o
@@ -40,11 +41,12 @@ ifneq ($(KERNELRELEASE),)
        yaffs2-objs += yaffs_verify.o
        yaffs2-objs += yaffs_summary.o
 
-       yaffs2multi-objs := yaffs_mtdif.o yaffs_mtdif2_multi.o
-       yaffs2multi-objs += yaffs_mtdif1_multi.o yaffs_packedtags1.o
+       yaffs2multi-objs := yaffs_mtdif_multi.o
+       yaffs2multi-objs += yaffs_packedtags1.o
        yaffs2multi-objs += yaffs_ecc.o yaffs_vfs_multi.o yaffs_guts.o
        yaffs2multi-objs += yaffs_packedtags2.o
        yaffs2multi-objs += yaffs_tagscompat.o
+       yaffs2multi-objs += yaffs_tagsmarshall.o
        yaffs2multi-objs += yaffs_checkptrw.o yaffs_nand.o
        yaffs2multi-objs += yaffs_checkptrw.o yaffs_nand.o yaffs_nameval.o
        yaffs2multi-objs += yaffs_allocator.o yaffs_bitmap.o yaffs_attribs.o
index 8478eb88185fc4e1b271f161f31062e1f84bffb4..b1c4beed2b854a7a0bbff25ff3e5657875d769b0 100644 (file)
@@ -74,7 +74,7 @@ static int yaffs_checkpt_erase(struct yaffs_dev *dev)
 {
        int i;
 
-       if (!dev->param.erase_fn)
+       if (!dev->param.drv_erase_fn)
                return 0;
        yaffs_trace(YAFFS_TRACE_CHECKPOINT,
                "checking blocks %d to %d",
@@ -91,14 +91,14 @@ static int yaffs_checkpt_erase(struct yaffs_dev *dev)
 
                        dev->n_erasures++;
 
-                       result = dev->param.erase_fn(dev, offset_i);
+                       result = dev->param.drv_erase_fn(dev, offset_i);
                        if(result) {
                                bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
                                dev->n_erased_blocks++;
                                dev->n_free_chunks +=
                                    dev->param.chunks_per_block;
                        } else {
-                               dev->param.bad_block_fn(dev, offset_i);
+                               dev->param.drv_bad_block_fn(dev, offset_i);
                                bi->block_state = YAFFS_BLOCK_STATE_DEAD;
                        }
                }
@@ -202,7 +202,8 @@ int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
        /* Got the functions we need? */
        if (!dev->param.write_chunk_tags_fn ||
            !dev->param.read_chunk_tags_fn ||
-           !dev->param.erase_fn || !dev->param.bad_block_fn)
+           !dev->param.drv_erase_fn ||
+           !dev->param.drv_mark_bad_fn)
                return 0;
 
        if (writing && !yaffs2_checkpt_space_ok(dev))
index 79568eeeae39eb20d171226afc015cedbda75e5d..0c33102b46bfc2e64cba900348f2582ccefd282e 100644 (file)
@@ -17,6 +17,7 @@
 #include "yaffs_guts.h"
 #include "yaffs_getblockinfo.h"
 #include "yaffs_tagscompat.h"
+#include "yaffs_tagsmarshall.h"
 #include "yaffs_nand.h"
 #include "yaffs_yaffs1.h"
 #include "yaffs_yaffs2.h"
@@ -4531,30 +4532,30 @@ YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj)
 
 /*--------------------------- Initialisation code -------------------------- */
 
-static int yaffs_check_dev_fns(const struct yaffs_dev *dev)
+static int yaffs_check_dev_fns(struct yaffs_dev *dev)
 {
+       struct yaffs_param *param = &dev->param;
+
        /* Common functions, gotta have */
-       if (!dev->param.erase_fn || !dev->param.initialise_flash_fn)
+       if (!param->drv_initialise_fn ||
+           !param->drv_read_chunk_fn ||
+           !param->drv_write_chunk_fn ||
+           !param->drv_erase_fn ||
+           !param->drv_initialise_fn)
                return 0;
 
-       /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
-       if (dev->param.write_chunk_tags_fn &&
-           dev->param.read_chunk_tags_fn &&
-           !dev->param.write_chunk_fn &&
-           !dev->param.read_chunk_fn &&
-           dev->param.bad_block_fn && dev->param.query_block_fn)
-               return 1;
+       /* Install the default tags marshalling functions if needed. */
+       yaffs_tags_compat_install(dev);
+       yaffs_tags_marshall_install(dev);
 
-       /* Can use the "spare" style interface for yaffs1 */
-       if (!dev->param.is_yaffs2 &&
-           !dev->param.write_chunk_tags_fn &&
-           !dev->param.read_chunk_tags_fn &&
-           dev->param.write_chunk_fn &&
-           dev->param.read_chunk_fn &&
-           !dev->param.bad_block_fn && !dev->param.query_block_fn)
-               return 1;
+       /* Check we now have the marshalling functions required. */
+       if (!param->write_chunk_tags_fn ||
+           !param->read_chunk_tags_fn ||
+           !param->query_block_fn ||
+           !param->mark_bad_fn)
+               return 0;
 
-       return 0;               /* bad */
+       return 1;
 }
 
 static int yaffs_create_initial_dir(struct yaffs_dev *dev)
@@ -4924,8 +4925,8 @@ void yaffs_deinitialise(struct yaffs_dev *dev)
 
                dev->is_mounted = 0;
 
-               if (dev->param.deinitialise_flash_fn)
-                       dev->param.deinitialise_flash_fn(dev);
+               if (dev->param.drv_deinitialise_fn)
+                       dev->param.drv_deinitialise_fn(dev);
        }
 }
 
index f4fe47519677726c314e0e54d36cf2d35165b37d..643e5750954784e1cfb2cdd2a5ac6f4268eb4c76 100644 (file)
@@ -558,29 +558,43 @@ struct yaffs_param {
 
        int enable_xattr;       /* Enable xattribs */
 
-       /* NAND access functions (Must be set before calling YAFFS) */
-
-       int (*write_chunk_fn) (struct yaffs_dev *dev,
-                              int nand_chunk, const u8 *data,
-                              const struct yaffs_spare *spare);
-       int (*read_chunk_fn) (struct yaffs_dev *dev,
-                             int nand_chunk, u8 *data,
-                             struct yaffs_spare *spare);
-       int (*erase_fn) (struct yaffs_dev *dev, int flash_block);
-       int (*initialise_flash_fn) (struct yaffs_dev *dev);
-       int (*deinitialise_flash_fn) (struct yaffs_dev *dev);
-
-       /* yaffs2 mode functions */
+       /* Tags marshalling functions.
+        * If these are not set then defaults will be assigned.
+        */
        int (*write_chunk_tags_fn) (struct yaffs_dev *dev,
                                    int nand_chunk, const u8 *data,
                                    const struct yaffs_ext_tags *tags);
        int (*read_chunk_tags_fn) (struct yaffs_dev *dev,
                                   int nand_chunk, u8 *data,
                                   struct yaffs_ext_tags *tags);
-       int (*bad_block_fn) (struct yaffs_dev *dev, int block_no);
+
        int (*query_block_fn) (struct yaffs_dev *dev, int block_no,
                               enum yaffs_block_state *state,
                               u32 *seq_number);
+       int (*mark_bad_fn) (struct yaffs_dev *dev, int block_no);
+
+       /* NAND driver access functions All required except
+        * the deinitialise function which is optional.
+        */
+
+       int (*drv_write_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
+                                  const u8 *data, int data_len,
+                                  const u8 *oob, int oob_len);
+       int (*drv_read_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
+                                  u8 *data, int data_len,
+                                  u8 *oob, int oob_len,
+                                  enum yaffs_ecc_result *ecc_result);
+       int (*drv_erase_fn) (struct yaffs_dev *dev, int block_no);
+       int (*drv_mark_bad_fn) (struct yaffs_dev *dev, int block_no);
+       int (*drv_check_bad_fn) (struct yaffs_dev *dev, int block_no);
+       int (*drv_initialise_fn) (struct yaffs_dev *dev);
+       int (*drv_deinitialise_fn) (struct yaffs_dev *dev);
+
+
+       int max_objects;        /*
+                                * Set to limit the number of objects created.
+                                * 0 = no limit.
+                               */
 
        /* The remove_obj_fn function must be supplied by OS flavours that
         * need it.
@@ -612,10 +626,6 @@ struct yaffs_param {
 
        int disable_summary;
 
-       int max_objects;        /*
-                                * Set to limit the number of objects created.
-                                * 0 = no limit.
-                               */
 };
 
 struct yaffs_dev {
@@ -766,6 +776,7 @@ struct yaffs_dev {
        u32 n_page_writes;
        u32 n_page_reads;
        u32 n_erasures;
+       u32 n_bad_markings;
        u32 n_erase_failures;
        u32 n_gc_copies;
        u32 all_gcs;
diff --git a/yaffs_mtdif.c b/yaffs_mtdif.c
deleted file mode 100644 (file)
index edc1525..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
- *
- * Copyright (C) 2002-2011 Aleph One Ltd.
- *   for Toby Churchill Ltd and Brightstar Engineering
- *
- * Created by Charles Manning <charles@aleph1.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "yportenv.h"
-
-#include "yaffs_mtdif.h"
-
-#include "linux/mtd/mtd.h"
-#include "linux/types.h"
-#include "linux/time.h"
-#include "linux/mtd/nand.h"
-
-#include "yaffs_linux.h"
-
-int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
-{
-       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-       u32 addr =
-           ((loff_t) block_no) * dev->param.total_bytes_per_chunk *
-           dev->param.chunks_per_block;
-       struct erase_info ei;
-       int retval = 0;
-
-       ei.mtd = mtd;
-       ei.addr = addr;
-       ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
-       ei.time = 1000;
-       ei.retries = 2;
-       ei.callback = NULL;
-       ei.priv = (u_long) dev;
-
-       retval = mtd->erase(mtd, &ei);
-
-       if (retval == 0)
-               return YAFFS_OK;
-
-       return YAFFS_FAIL;
-}
-
-int nandmtd_initialise(struct yaffs_dev *dev)
-{
-       return YAFFS_OK;
-}
index 3ef5581fdbcfabd2f4fd41b9d521870527152285..e5172eb1336727737a2bdb87c655143b66b8fbac 100644 (file)
@@ -18,6 +18,6 @@
 
 #include "yaffs_guts.h"
 
-int nandmtd_erase_block(struct yaffs_dev *dev, int block_no);
-int nandmtd_initialise(struct yaffs_dev *dev);
+void yaffs_mtd_drv_install(struct yaffs_dev *dev);
+
 #endif
diff --git a/yaffs_mtdif1.h b/yaffs_mtdif1.h
deleted file mode 100644 (file)
index 6a5df50..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * YAFFS: Yet another Flash File System. A NAND-flash specific file system.
- *
- * Copyright (C) 2002-2011 Aleph One Ltd.
- *   for Toby Churchill Ltd and Brightstar Engineering
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License version 2.1 as
- * published by the Free Software Foundation.
- *
- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
- */
-
-#ifndef __YAFFS_MTDIF1_H__
-#define __YAFFS_MTDIF1_H__
-
-int nandmtd1_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
-                             const u8 *data,
-                             const struct yaffs_ext_tags *tags);
-
-int nandmtd1_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
-                            u8 *data, struct yaffs_ext_tags *tags);
-
-int nandmtd1_mark_block_bad(struct yaffs_dev *dev, int block_no);
-
-int nandmtd1_query_block(struct yaffs_dev *dev, int block_no,
-                        enum yaffs_block_state *state, u32 *seq_number);
-
-#endif
diff --git a/yaffs_mtdif1_multi.c b/yaffs_mtdif1_multi.c
deleted file mode 100644 (file)
index 14d5c6f..0000000
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * YAFFS: Yet another FFS. A NAND-flash specific file system.
- *
- * Copyright (C) 2002-2011 Aleph One Ltd.
- *   for Toby Churchill Ltd and Brightstar Engineering
- *
- * Created by Charles Manning <charles@aleph1.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- * This module provides the interface between yaffs_nand.c and the
- * MTD API.  This version is used when the MTD interface supports the
- * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
- * and we have small-page NAND device.
- *
- * These functions are invoked via function pointers in yaffs_nand.c.
- * This replaces functionality provided by functions in yaffs_mtdif.c
- * and the yaffs_tags compatability functions in yaffs_tagscompat.c that are
- * called in yaffs_mtdif.c when the function pointers are NULL.
- * We assume the MTD layer is performing ECC (use_nand_ecc is true).
- */
-
-#include "yportenv.h"
-#include "yaffs_trace.h"
-#include "yaffs_guts.h"
-#include "yaffs_packedtags1.h"
-#include "yaffs_tagscompat.h"  /* for yaffs_calc_tags_ecc */
-#include "yaffs_linux.h"
-
-#include "linux/kernel.h"
-#include "linux/version.h"
-#include "linux/types.h"
-#include "linux/mtd/mtd.h"
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
-#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
-#endif
-
-
-/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
-#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
-
-
-#if 0
-/* Use the following nand_ecclayout with MTD when using
- * 9 byte tags and the older on-NAND tags layout.
- * If you have existing Yaffs images and the byte order differs from this,
- * adjust 'oobfree' to match your existing Yaffs data.
- *
- * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
- * page_status byte (at NAND spare offset 4) scattered/gathered from/to
- * the 9th byte.
- *
- * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
- * We have/need packed_tags1 plus page_status: T0,T1,T2,T3,T4,T5,T6,T7,P
- * where Tn are the tag bytes, En are MTD's ECC bytes, P is the page_status
- * byte and B is the small-page bad-block indicator byte.
- */
-static struct nand_ecclayout nand_oob_16 = {
-       .eccbytes = 6,
-       .eccpos = {8, 9, 10, 13, 14, 15},
-       .oobavail = 9,
-       .oobfree = {{0, 4}, {6, 2}, {11, 2}, {4, 1} }
-};
-#endif
-
-/* Write a chunk (page) of data to NAND.
- *
- * Caller always provides ExtendedTags data which are converted to a more
- * compact (packed) form for storage in NAND.  A mini-ECC runs over the
- * contents of the tags meta-data; used to valid the tags when read.
- *
- *  - Pack ExtendedTags to packed_tags1 form
- *  - Compute mini-ECC for packed_tags1
- *  - Write data and packed tags to NAND.
- *
- * Note: Due to the use of the packed_tags1 meta-data which does not include
- * a full sequence number (as found in the larger packed_tags2 form) it is
- * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
- * discarded and dirty.  This is not ideal: newer NAND parts are supposed
- * to be written just once.  When Yaffs performs this operation, this
- * function is called with a NULL data pointer -- calling MTD write_oob
- * without data is valid usage (2.6.17).
- *
- * Any underlying MTD error results in YAFFS_FAIL.
- * Returns YAFFS_OK or YAFFS_FAIL.
- */
-int nandmtd1_write_chunk_tags(struct yaffs_dev *dev,
-                             int nand_chunk, const u8 *data,
-                             const struct yaffs_ext_tags *etags)
-{
-       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-       int chunk_bytes = dev->data_bytes_per_chunk;
-       loff_t addr = ((loff_t) nand_chunk) * chunk_bytes;
-       struct mtd_oob_ops ops;
-       struct yaffs_packed_tags1 pt1;
-       int retval;
-
-       /* we assume that packed_tags1 and struct yaffs_tags are compatible */
-       compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12);
-       compile_time_assertion(sizeof(struct yaffs_tags) == 8);
-
-       yaffs_pack_tags1(&pt1, etags);
-       yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1);
-
-       /* When deleting a chunk, the upper layer provides only skeletal
-        * etags, one with is_deleted set.  However, we need to update the
-        * tags, not erase them completely.  So we use the NAND write property
-        * that only zeroed-bits stick and set tag bytes to all-ones and
-        * zero just the (not) deleted bit.
-        */
-       if(dev->param.tags_9bytes) {
-               ((u8 *) &pt1)[8] = 0xff;
-               if (etags->is_deleted) {
-                       memset(&pt1, 0xff, 8);
-                       /* zero page_status byte to indicate deleted */
-                       ((u8 *) &pt1)[8] = 0;
-                }
-        } else {
-               if (etags->is_deleted) {
-                       memset(&pt1, 0xff, 8);
-                       /* clear delete status bit to indicate deleted */
-                       pt1.deleted = 0;
-                }
-       }
-
-       memset(&ops, 0, sizeof(ops));
-       ops.mode = MTD_OPS_AUTO_OOB;
-       ops.len = (data) ? chunk_bytes : 0;
-       ops.ooblen = dev->param.tags_9bytes ? 9 : 8;
-       ops.datbuf = (u8 *) data;
-       ops.oobbuf = (u8 *) &pt1;
-
-       retval = mtd->write_oob(mtd, addr, &ops);
-       if (retval) {
-               yaffs_trace(YAFFS_TRACE_MTD,
-                       "write_oob failed, chunk %d, mtd error %d",
-                       nand_chunk, retval);
-       }
-       return retval ? YAFFS_FAIL : YAFFS_OK;
-}
-
-/* Return with empty ExtendedTags but add ecc_result.
- */
-static int rettags(struct yaffs_ext_tags *etags, int ecc_result, int retval)
-{
-       if (etags) {
-               memset(etags, 0, sizeof(*etags));
-               etags->ecc_result = ecc_result;
-       }
-       return retval;
-}
-
-/* Read a chunk (page) from NAND.
- *
- * Caller expects ExtendedTags data to be usable even on error; that is,
- * all members except ecc_result and block_bad are zeroed.
- *
- *  - Check ECC results for data (if applicable)
- *  - Check for blank/erased block (return empty ExtendedTags if blank)
- *  - Check the packed_tags1 mini-ECC (correct if necessary/possible)
- *  - Convert packed_tags1 to ExtendedTags
- *  - Update ecc_result and block_bad members to refect state.
- *
- * Returns YAFFS_OK or YAFFS_FAIL.
- */
-int nandmtd1_read_chunk_tags(struct yaffs_dev *dev,
-                            int nand_chunk, u8 *data,
-                            struct yaffs_ext_tags *etags)
-{
-       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-       int chunk_bytes = dev->data_bytes_per_chunk;
-       loff_t addr = ((loff_t) nand_chunk) * chunk_bytes;
-       int eccres = YAFFS_ECC_RESULT_NO_ERROR;
-       struct mtd_oob_ops ops;
-       struct yaffs_packed_tags1 pt1;
-       int retval;
-       int deleted;
-
-       memset(&ops, 0, sizeof(ops));
-       ops.mode = MTD_OPS_AUTO_OOB;
-       ops.len = (data) ? chunk_bytes : 0;
-       ops.ooblen = dev->param.tags_9bytes ? 9 : 8;
-       ops.datbuf = data;
-       ops.oobbuf = (u8 *) &pt1;
-
-#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20))
-       /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
-        * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
-        */
-       ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
-#endif
-       /* Read page and oob using MTD.
-        * Check status and determine ECC result.
-        */
-       retval = mtd->read_oob(mtd, addr, &ops);
-       if (retval)
-               yaffs_trace(YAFFS_TRACE_MTD,
-                       "read_oob failed, chunk %d, mtd error %d",
-                       nand_chunk, retval);
-
-       switch (retval) {
-       case 0:
-               /* no error */
-               break;
-
-       case -EUCLEAN:
-               /* MTD's ECC fixed the data */
-               eccres = YAFFS_ECC_RESULT_FIXED;
-               dev->n_ecc_fixed++;
-               break;
-
-       case -EBADMSG:
-               /* MTD's ECC could not fix the data */
-               dev->n_ecc_unfixed++;
-               /* fall into... */
-       default:
-               rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
-               etags->block_bad = (mtd->block_isbad) (mtd, addr);
-               return YAFFS_FAIL;
-       }
-
-       /* Check for a blank/erased chunk.
-        */
-       if (yaffs_check_ff((u8 *) &pt1, 8)) {
-               /* when blank, upper layers want ecc_result to be <= NO_ERROR */
-               return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
-       }
-
-       if(dev->param.tags_9bytes) {
-               deleted = (hweight8(((u8 *) &pt1)[8]) < 7);
-        } else {
-               /* Read deleted status (bit) then return it to it's non-deleted
-                * state before performing tags mini-ECC check. pt1.deleted is
-                * inverted.
-                */
-               deleted = !pt1.deleted;
-               pt1.deleted = 1;
-        }
-
-       /* Check the packed tags mini-ECC and correct if necessary/possible.
-        */
-       retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1);
-       switch (retval) {
-       case 0:
-               /* no tags error, use MTD result */
-               break;
-       case 1:
-               /* recovered tags-ECC error */
-               dev->n_tags_ecc_fixed++;
-               if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
-                       eccres = YAFFS_ECC_RESULT_FIXED;
-               break;
-       default:
-               /* unrecovered tags-ECC error */
-               dev->n_tags_ecc_unfixed++;
-               return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
-       }
-
-       /* Unpack the tags to extended form and set ECC result.
-        * [set should_be_ff just to keep yaffs_unpack_tags1 happy]
-        */
-       pt1.should_be_ff = 0xffffffff;
-       yaffs_unpack_tags1(etags, &pt1);
-       etags->ecc_result = eccres;
-
-       /* Set deleted state */
-       etags->is_deleted = deleted;
-       return YAFFS_OK;
-}
-
-/* Mark a block bad.
- *
- * This is a persistant state.
- * Use of this function should be rare.
- *
- * Returns YAFFS_OK or YAFFS_FAIL.
- */
-int nandmtd1_mark_block_bad(struct yaffs_dev *dev, int block_no)
-{
-       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-       int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
-       int retval;
-
-       yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);
-
-       retval = mtd->block_markbad(mtd, (loff_t) blocksize * block_no);
-       return (retval) ? YAFFS_FAIL : YAFFS_OK;
-}
-
-/* Check any MTD prerequists.
- *
- * Returns YAFFS_OK or YAFFS_FAIL.
- */
-static int nandmtd1_test_prerequists(struct yaffs_dev *dev, struct mtd_info *mtd)
-{
-       /* 2.6.18 has mtd->ecclayout->oobavail */
-       /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
-       int oobavail = mtd->ecclayout->oobavail;
-
-       if (oobavail < (dev->param.tags_9bytes ? 9 : 8)) {
-               yaffs_trace(YAFFS_TRACE_ERROR,
-                       "mtd device has only %d bytes for tags, need %d",
-                       oobavail, dev->param.tags_9bytes ? 9 : 8);
-               return YAFFS_FAIL;
-       }
-       return YAFFS_OK;
-}
-
-/* Query for the current state of a specific block.
- *
- * Examine the tags of the first chunk of the block and return the state:
- *  - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
- *  - YAFFS_BLOCK_STATE_NEEDS_SCAN, the block is in use
- *  - YAFFS_BLOCK_STATE_EMPTY, the block is clean
- *
- * Always returns YAFFS_OK.
- */
-int nandmtd1_query_block(struct yaffs_dev *dev, int block_no,
-                        enum yaffs_block_state *state_ptr, u32 * seq_ptr)
-{
-       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-       int chunk_num = block_no * dev->param.chunks_per_block;
-       loff_t addr = (loff_t) chunk_num * dev->data_bytes_per_chunk;
-       struct yaffs_ext_tags etags;
-       int state = YAFFS_BLOCK_STATE_DEAD;
-       int seqnum = 0;
-       int retval;
-
-       /* We don't yet have a good place to test for MTD config prerequists.
-        * Do it here as we are called during the initial scan.
-        */
-       if (nandmtd1_test_prerequists(dev, mtd) != YAFFS_OK)
-               return YAFFS_FAIL;
-
-       retval = nandmtd1_read_chunk_tags(dev, chunk_num, NULL, &etags);
-       etags.block_bad = (mtd->block_isbad) (mtd, addr);
-       if (etags.block_bad) {
-               yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
-                       "block %d is marked bad",
-                       block_no);
-               state = YAFFS_BLOCK_STATE_DEAD;
-       } else if (etags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
-               /* bad tags, need to look more closely */
-               state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
-       } else if (etags.chunk_used) {
-               state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
-               seqnum = etags.seq_number;
-       } else {
-               state = YAFFS_BLOCK_STATE_EMPTY;
-       }
-
-       *state_ptr = state;
-       *seq_ptr = seqnum;
-
-       /* query always succeeds */
-       return YAFFS_OK;
-}
-
-#endif /*MTD_VERSION */
diff --git a/yaffs_mtdif1_single.c b/yaffs_mtdif1_single.c
deleted file mode 100644 (file)
index dbc9122..0000000
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * YAFFS: Yet another FFS. A NAND-flash specific file system.
- *
- * Copyright (C) 2002-2011 Aleph One Ltd.
- *   for Toby Churchill Ltd and Brightstar Engineering
- *
- * Created by Charles Manning <charles@aleph1.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- * This module provides the interface between yaffs_nand.c and the
- * MTD API.  This version is used when the MTD interface supports the
- * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
- * and we have small-page NAND device.
- *
- * These functions are invoked via function pointers in yaffs_nand.c.
- * This replaces functionality provided by functions in yaffs_mtdif.c
- * and the yaffs_tags compatability functions in yaffs_tagscompat.c that are
- * called in yaffs_mtdif.c when the function pointers are NULL.
- * We assume the MTD layer is performing ECC (use_nand_ecc is true).
- */
-
-#include "yportenv.h"
-#include "yaffs_trace.h"
-#include "yaffs_guts.h"
-#include "yaffs_packedtags1.h"
-#include "yaffs_tagscompat.h"  /* for yaffs_calc_tags_ecc */
-#include "yaffs_linux.h"
-#include "linux/kernel.h"
-#include "linux/version.h"
-#include "linux/types.h"
-#include "linux/mtd/mtd.h"
-
-/* Write a chunk (page) of data to NAND.
- *
- * Caller always provides ExtendedTags data which are converted to a more
- * compact (packed) form for storage in NAND.  A mini-ECC runs over the
- * contents of the tags meta-data; used to valid the tags when read.
- *
- *  - Pack ExtendedTags to packed_tags1 form
- *  - Compute mini-ECC for packed_tags1
- *  - Write data and packed tags to NAND.
- *
- * Note: Due to the use of the packed_tags1 meta-data which does not include
- * a full sequence number (as found in the larger packed_tags2 form) it is
- * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
- * discarded and dirty.  This is not ideal: newer NAND parts are supposed
- * to be written just once.  When Yaffs performs this operation, this
- * function is called with a NULL data pointer -- calling MTD write_oob
- * without data is valid usage (2.6.17).
- *
- * Any underlying MTD error results in YAFFS_FAIL.
- * Returns YAFFS_OK or YAFFS_FAIL.
- */
-int nandmtd1_write_chunk_tags(struct yaffs_dev *dev,
-                             int nand_chunk, const u8 *data,
-                             const struct yaffs_ext_tags *etags)
-{
-       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-       int chunk_bytes = dev->data_bytes_per_chunk;
-       loff_t addr = ((loff_t) nand_chunk) * chunk_bytes;
-       struct mtd_oob_ops ops;
-       struct yaffs_packed_tags1 pt1;
-       int retval;
-
-       /* we assume that packed_tags1 and struct yaffs_tags are compatible */
-       compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12);
-       compile_time_assertion(sizeof(struct yaffs_tags) == 8);
-
-       yaffs_pack_tags1(&pt1, etags);
-       yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1);
-
-       /* When deleting a chunk, the upper layer provides only skeletal
-        * etags, one with is_deleted set.  However, we need to update the
-        * tags, not erase them completely.  So we use the NAND write property
-        * that only zeroed-bits stick and set tag bytes to all-ones and
-        * zero just the (not) deleted bit.
-        */
-
-       if (dev->param.tags_9bytes) {
-               ((u8 *) &pt1)[8] = 0xff;
-               if (etags->is_deleted) {
-                       memset(&pt1, 0xff, 8);
-                       /* zero page_status byte to indicate deleted */
-                       ((u8 *) &pt1)[8] = 0;
-               }
-       } else {
-               if (etags->is_deleted) {
-                       memset(&pt1, 0xff, 8);
-                       /* clear delete status bit to indicate deleted */
-                       pt1.deleted = 0;
-               }
-       }
-
-       memset(&ops, 0, sizeof(ops));
-       ops.mode = MTD_OPS_AUTO_OOB;
-       ops.len = (data) ? chunk_bytes : 0;
-       ops.ooblen = dev->param.tags_9bytes ? 9 : 8;
-       ops.datbuf = (u8 *) data;
-       ops.oobbuf = (u8 *) &pt1;
-
-       retval = mtd->write_oob(mtd, addr, &ops);
-       if (retval) {
-               yaffs_trace(YAFFS_TRACE_MTD,
-                       "write_oob failed, chunk %d, mtd error %d",
-                       nand_chunk, retval);
-       }
-       return retval ? YAFFS_FAIL : YAFFS_OK;
-}
-
-/* Return with empty ExtendedTags but add ecc_result.
- */
-static int rettags(struct yaffs_ext_tags *etags, int ecc_result, int retval)
-{
-       if (etags) {
-               memset(etags, 0, sizeof(*etags));
-               etags->ecc_result = ecc_result;
-       }
-       return retval;
-}
-
-/* Read a chunk (page) from NAND.
- *
- * Caller expects ExtendedTags data to be usable even on error; that is,
- * all members except ecc_result and block_bad are zeroed.
- *
- *  - Check ECC results for data (if applicable)
- *  - Check for blank/erased block (return empty ExtendedTags if blank)
- *  - Check the packed_tags1 mini-ECC (correct if necessary/possible)
- *  - Convert packed_tags1 to ExtendedTags
- *  - Update ecc_result and block_bad members to refect state.
- *
- * Returns YAFFS_OK or YAFFS_FAIL.
- */
-int nandmtd1_read_chunk_tags(struct yaffs_dev *dev,
-                            int nand_chunk, u8 *data,
-                            struct yaffs_ext_tags *etags)
-{
-       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-       int chunk_bytes = dev->data_bytes_per_chunk;
-       loff_t addr = ((loff_t) nand_chunk) * chunk_bytes;
-       int eccres = YAFFS_ECC_RESULT_NO_ERROR;
-       struct mtd_oob_ops ops;
-       struct yaffs_packed_tags1 pt1;
-       int retval;
-       int deleted;
-
-       memset(&ops, 0, sizeof(ops));
-       ops.mode = MTD_OPS_AUTO_OOB;
-       ops.len = (data) ? chunk_bytes : 0;
-       ops.ooblen =  dev->param.tags_9bytes ? 9 : 8;
-       ops.datbuf = data;
-       ops.oobbuf = (u8 *) &pt1;
-
-       /* Read page and oob using MTD.
-        * Check status and determine ECC result.
-        */
-       retval = mtd->read_oob(mtd, addr, &ops);
-       if (retval) {
-               yaffs_trace(YAFFS_TRACE_MTD,
-                       "read_oob failed, chunk %d, mtd error %d",
-                       nand_chunk, retval);
-       }
-
-       switch (retval) {
-       case 0:
-               /* no error */
-               break;
-
-       case -EUCLEAN:
-               /* MTD's ECC fixed the data */
-               eccres = YAFFS_ECC_RESULT_FIXED;
-               dev->n_ecc_fixed++;
-               break;
-
-       case -EBADMSG:
-               /* MTD's ECC could not fix the data */
-               dev->n_ecc_unfixed++;
-               /* fall into... */
-       default:
-               rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
-               etags->block_bad = (mtd->block_isbad) (mtd, addr);
-               return YAFFS_FAIL;
-       }
-
-       /* Check for a blank/erased chunk.
-        */
-       if (yaffs_check_ff((u8 *) &pt1, 8)) {
-               /* when blank, upper layers want ecc_result to be <= NO_ERROR */
-               return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
-       }
-#ifndef CONFIG_YAFFS_9BYTE_TAGS
-       /* Read deleted status (bit) then return it to it's non-deleted
-        * state before performing tags mini-ECC check. pt1.deleted is
-        * inverted.
-        */
-       deleted = !pt1.deleted;
-       pt1.deleted = 1;
-#else
-       deleted = (hweight8(((u8 *) &pt1)[8]) < 7);
-#endif
-
-       /* Check the packed tags mini-ECC and correct if necessary/possible.
-        */
-       retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1);
-       switch (retval) {
-       case 0:
-               /* no tags error, use MTD result */
-               break;
-       case 1:
-               /* recovered tags-ECC error */
-               dev->n_tags_ecc_fixed++;
-               if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
-                       eccres = YAFFS_ECC_RESULT_FIXED;
-               break;
-       default:
-               /* unrecovered tags-ECC error */
-               dev->n_tags_ecc_unfixed++;
-               return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
-       }
-
-       /* Unpack the tags to extended form and set ECC result.
-        * [set should_be_ff just to keep yaffs_unpack_tags1 happy]
-        */
-       pt1.should_be_ff = 0xffffffff;
-       yaffs_unpack_tags1(etags, &pt1);
-       etags->ecc_result = eccres;
-
-       /* Set deleted state */
-       etags->is_deleted = deleted;
-       return YAFFS_OK;
-}
-
-/* Mark a block bad.
- *
- * This is a persistant state.
- * Use of this function should be rare.
- *
- * Returns YAFFS_OK or YAFFS_FAIL.
- */
-int nandmtd1_mark_block_bad(struct yaffs_dev *dev, int block_no)
-{
-       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-       int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
-       int retval;
-
-       yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
-               "marking block %d bad", block_no);
-
-       retval = mtd->block_markbad(mtd, (loff_t) blocksize * block_no);
-       return (retval) ? YAFFS_FAIL : YAFFS_OK;
-}
-
-/* Check any MTD prerequists.
- *
- * Returns YAFFS_OK or YAFFS_FAIL.
- */
-static int nandmtd1_test_prerequists(struct yaffs_dev *dev,
-                                       struct mtd_info *mtd)
-{
-       /* 2.6.18 has mtd->ecclayout->oobavail */
-       /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
-       int oobavail = mtd->ecclayout->oobavail;
-
-       if (oobavail < (dev->param.tags_9bytes ? 9 : 8)) {
-               yaffs_trace(YAFFS_TRACE_ERROR,
-                       "mtd device has only %d bytes for tags, need %d",
-                       oobavail, (dev->param.tags_9bytes ? 9 : 8));
-               return YAFFS_FAIL;
-       }
-       return YAFFS_OK;
-}
-
-/* Query for the current state of a specific block.
- *
- * Examine the tags of the first chunk of the block and return the state:
- *  - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
- *  - YAFFS_BLOCK_STATE_NEEDS_SCAN, the block is in use
- *  - YAFFS_BLOCK_STATE_EMPTY, the block is clean
- *
- * Always returns YAFFS_OK.
- */
-int nandmtd1_query_block(struct yaffs_dev *dev, int block_no,
-                        enum yaffs_block_state *state_ptr, u32 * seq_ptr)
-{
-       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-       int chunk_num = block_no * dev->param.chunks_per_block;
-       loff_t addr = (loff_t) chunk_num * dev->data_bytes_per_chunk;
-       struct yaffs_ext_tags etags;
-       int state = YAFFS_BLOCK_STATE_DEAD;
-       int seqnum = 0;
-       int retval;
-
-       /* We don't yet have a good place to test for MTD config prerequists.
-        * Do it here as we are called during the initial scan.
-        */
-       if (nandmtd1_test_prerequists(dev, mtd) != YAFFS_OK)
-               return YAFFS_FAIL;
-
-       retval = nandmtd1_read_chunk_tags(dev, chunk_num, NULL, &etags);
-       etags.block_bad = (mtd->block_isbad) (mtd, addr);
-       if (etags.block_bad) {
-               yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
-                       "block %d is marked bad", block_no);
-               state = YAFFS_BLOCK_STATE_DEAD;
-       } else if (etags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
-               /* bad tags, need to look more closely */
-               state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
-       } else if (etags.chunk_used) {
-               state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
-               seqnum = etags.seq_number;
-       } else {
-               state = YAFFS_BLOCK_STATE_EMPTY;
-       }
-
-       *state_ptr = state;
-       *seq_ptr = seqnum;
-
-       /* query always succeeds */
-       return YAFFS_OK;
-}
diff --git a/yaffs_mtdif2_multi.c b/yaffs_mtdif2_multi.c
deleted file mode 100644 (file)
index 18ac992..0000000
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
- *
- * Copyright (C) 2002-2011 Aleph One Ltd.
- *   for Toby Churchill Ltd and Brightstar Engineering
- *
- * Created by Charles Manning <charles@aleph1.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/* mtd interface for YAFFS2 */
-
-#include "yportenv.h"
-#include "yaffs_trace.h"
-
-#include "yaffs_mtdif2.h"
-
-#include "linux/mtd/mtd.h"
-#include "linux/types.h"
-#include "linux/time.h"
-
-#include "yaffs_packedtags2.h"
-
-#include "yaffs_linux.h"
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
-#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
-#endif
-
-
-
-/* NB For use with inband tags....
- * We assume that the data buffer is of size total_bytes_per_chunk so
- * that we can also use it to load the tags.
- */
-int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
-                             const u8 *data,
-                             const struct yaffs_ext_tags *tags)
-{
-       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
-       struct mtd_oob_ops ops;
-#else
-       size_t dummy;
-#endif
-       int retval = 0;
-
-       loff_t addr;
-
-       struct yaffs_packed_tags2 pt;
-
-       int packed_tags_size =
-           dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
-       void *packed_tags_ptr =
-           dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
-
-       yaffs_trace(YAFFS_TRACE_MTD,
-               "nandmtd2_write_chunk_tags chunk %d data %p tags %p",
-               nand_chunk, data, tags);
-
-       addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
-
-       /* For yaffs2 writing there must be both data and tags.
-        * If we're using inband tags, then the tags are stuffed into
-        * the end of the data buffer.
-        */
-       if (!data || !tags)
-               BUG();
-       else if (dev->param.inband_tags) {
-               struct yaffs_packed_tags2_tags_only *pt2tp;
-               pt2tp =
-                   (struct yaffs_packed_tags2_tags_only *)(data +
-                                                       dev->
-                                                       data_bytes_per_chunk);
-               yaffs_pack_tags2_tags_only(pt2tp, tags);
-       } else {
-               yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
-       }
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
-       ops.mode = MTD_OPS_AUTO_OOB;
-       ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
-       ops.len = dev->param.total_bytes_per_chunk;
-       ops.ooboffs = 0;
-       ops.datbuf = (u8 *) data;
-       ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
-       retval = mtd->write_oob(mtd, addr, &ops);
-
-#else
-       if (!dev->param.inband_tags) {
-               retval =
-                   mtd->write_ecc(mtd, addr, dev->data_bytes_per_chunk,
-                                  &dummy, data, (u8 *) packed_tags_ptr, NULL);
-       } else {
-               retval =
-                   mtd->write(mtd, addr, dev->param.total_bytes_per_chunk,
-                              &dummy, data);
-       }
-#endif
-
-       if (retval == 0)
-               return YAFFS_OK;
-       else
-               return YAFFS_FAIL;
-}
-
-int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
-                            u8 *data, struct yaffs_ext_tags *tags)
-{
-       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
-       struct mtd_oob_ops ops;
-#endif
-       size_t dummy;
-       int retval = 0;
-       int local_data = 0;
-
-       loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
-
-       struct yaffs_packed_tags2 pt;
-
-       int packed_tags_size =
-           dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
-       void *packed_tags_ptr =
-           dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
-
-       yaffs_trace(YAFFS_TRACE_MTD,
-               "nandmtd2_read_chunk_tags chunk %d data %p tags %p",
-               nand_chunk, data, tags);
-
-       if (dev->param.inband_tags) {
-
-               if (!data) {
-                       local_data = 1;
-                       data = yaffs_get_temp_buffer(dev);
-               }
-
-       }
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
-       if (dev->param.inband_tags || (data && !tags))
-               retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
-                                  &dummy, data);
-       else if (tags) {
-               ops.mode = MTD_OPS_AUTO_OOB;
-               ops.ooblen = packed_tags_size;
-               ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
-               ops.ooboffs = 0;
-               ops.datbuf = data;
-               ops.oobbuf = yaffs_dev_to_lc(dev)->spare_buffer;
-               retval = mtd->read_oob(mtd, addr, &ops);
-       }
-#else
-       if (!dev->param.inband_tags && data && tags) {
-
-               retval = mtd->read_ecc(mtd, addr, dev->data_bytes_per_chunk,
-                                      &dummy, data, dev->spare_buffer, NULL);
-       } else {
-               if (data)
-                       retval =
-                           mtd->read(mtd, addr, dev->data_bytes_per_chunk,
-                                     &dummy, data);
-               if (!dev->param.inband_tags && tags)
-                       retval =
-                           mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
-                                         dev->spare_buffer);
-       }
-#endif
-
-       if (dev->param.inband_tags) {
-               if (tags) {
-                       struct yaffs_packed_tags2_tags_only *pt2tp;
-                       pt2tp =
-                               (struct yaffs_packed_tags2_tags_only *)
-                               &data[dev->data_bytes_per_chunk];
-                       yaffs_unpack_tags2_tags_only(tags, pt2tp);
-               }
-       } else {
-               if (tags) {
-                       memcpy(packed_tags_ptr,
-                              yaffs_dev_to_lc(dev)->spare_buffer,
-                              packed_tags_size);
-                       yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
-               }
-       }
-
-       if (local_data)
-               yaffs_release_temp_buffer(dev, data);
-
-       if (tags && retval == -EBADMSG
-           && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
-               tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
-               dev->n_ecc_unfixed++;
-       }
-       if (tags && retval == -EUCLEAN
-           && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
-               tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
-               dev->n_ecc_fixed++;
-       }
-       if (retval == 0)
-               return YAFFS_OK;
-       else
-               return YAFFS_FAIL;
-}
-
-int nandmtd2_mark_block_bad(struct yaffs_dev *dev, int block_no)
-{
-       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-       int retval;
-       yaffs_trace(YAFFS_TRACE_MTD,
-               "nandmtd2_mark_block_bad %d",
-               block_no);
-
-       retval =
-           mtd->block_markbad(mtd,
-                              block_no * dev->param.chunks_per_block *
-                              dev->param.total_bytes_per_chunk);
-
-       if (retval == 0)
-               return YAFFS_OK;
-       else
-               return YAFFS_FAIL;
-
-}
-
-int nandmtd2_query_block(struct yaffs_dev *dev, int block_no,
-                        enum yaffs_block_state *state, u32 *seq_number)
-{
-       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-       int retval;
-
-       yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_query_block %d", block_no);
-       retval =
-           mtd->block_isbad(mtd,
-                            block_no * dev->param.chunks_per_block *
-                            dev->param.total_bytes_per_chunk);
-
-       if (retval) {
-               yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
-
-               *state = YAFFS_BLOCK_STATE_DEAD;
-               *seq_number = 0;
-       } else {
-               struct yaffs_ext_tags t;
-               nandmtd2_read_chunk_tags(dev, block_no *
-                                        dev->param.chunks_per_block, NULL, &t);
-
-               if (t.chunk_used) {
-                       *seq_number = t.seq_number;
-                       *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
-               } else {
-                       *seq_number = 0;
-                       *state = YAFFS_BLOCK_STATE_EMPTY;
-               }
-       }
-       yaffs_trace(YAFFS_TRACE_MTD,
-               "block is bad seq %d state %d",
-               *seq_number, *state);
-
-       if (retval == 0)
-               return YAFFS_OK;
-       else
-               return YAFFS_FAIL;
-}
-
diff --git a/yaffs_mtdif2_single.c b/yaffs_mtdif2_single.c
deleted file mode 100644 (file)
index f92c49f..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
- *
- * Copyright (C) 2002-2011 Aleph One Ltd.
- *   for Toby Churchill Ltd and Brightstar Engineering
- *
- * Created by Charles Manning <charles@aleph1.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/* mtd interface for YAFFS2 */
-
-#include "yportenv.h"
-#include "yaffs_trace.h"
-#include "yaffs_mtdif2.h"
-#include "yaffs_packedtags2.h"
-#include "yaffs_linux.h"
-#include "linux/mtd/mtd.h"
-#include "linux/types.h"
-#include "linux/time.h"
-#include "mtd/mtd-abi.h"
-
-
-/* NB For use with inband tags....
- * We assume that the data buffer is of size total_bytes_per_chunk so that
- * we can also use it to load the tags.
- */
-int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
-                             const u8 *data,
-                             const struct yaffs_ext_tags *tags)
-{
-       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-       struct mtd_oob_ops ops;
-       int retval = 0;
-       loff_t addr;
-       struct yaffs_packed_tags2 pt;
-       int packed_tags_size =
-           dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
-       void *packed_tags_ptr =
-           dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
-
-       yaffs_trace(YAFFS_TRACE_MTD,
-               "nandmtd2_write_chunk_tags chunk %d data %p tags %p",
-               nand_chunk, data, tags);
-
-       addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
-
-       /* For yaffs2 writing there must be both data and tags.
-        * If we're using inband tags, then the tags are stuffed into
-        * the end of the data buffer.
-        */
-       if (!data || !tags)
-               BUG();
-       else if (dev->param.inband_tags) {
-               struct yaffs_packed_tags2_tags_only *pt2tp;
-
-               pt2tp =
-                   (struct yaffs_packed_tags2_tags_only *)
-                       (data + dev->data_bytes_per_chunk);
-               yaffs_pack_tags2_tags_only(pt2tp, tags);
-       } else {
-               yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
-       }
-
-       ops.mode = MTD_OPS_AUTO_OOB;
-       ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
-       ops.len = dev->param.total_bytes_per_chunk;
-       ops.ooboffs = 0;
-       ops.datbuf = (u8 *) data;
-       ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
-       retval = mtd->write_oob(mtd, addr, &ops);
-
-       if (retval == 0)
-               return YAFFS_OK;
-
-       return YAFFS_FAIL;
-}
-
-int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
-                            u8 *data, struct yaffs_ext_tags *tags)
-{
-       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-       struct mtd_oob_ops ops;
-       size_t dummy;
-       int retval = 0;
-       int local_data = 0;
-       loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
-       struct yaffs_packed_tags2 pt;
-       int packed_tags_size =
-           dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
-       void *packed_tags_ptr =
-           dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
-
-       yaffs_trace(YAFFS_TRACE_MTD,
-               "nandmtd2_read_chunk_tags chunk %d data %p tags %p",
-               nand_chunk, data, tags);
-
-       if (dev->param.inband_tags && !data) {
-               local_data = 1;
-               data = yaffs_get_temp_buffer(dev);
-       }
-
-       if (dev->param.inband_tags || (data && !tags)) {
-               retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
-                                  &dummy, data);
-       } else if (tags) {
-               ops.mode = MTD_OPS_AUTO_OOB;
-               ops.ooblen = packed_tags_size;
-               ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
-               ops.ooboffs = 0;
-               ops.datbuf = data;
-               ops.oobbuf = yaffs_dev_to_lc(dev)->spare_buffer;
-               retval = mtd->read_oob(mtd, addr, &ops);
-       }
-
-       if (dev->param.inband_tags && tags) {
-               struct yaffs_packed_tags2_tags_only *pt2tp;
-
-               pt2tp =
-                       (struct yaffs_packed_tags2_tags_only *)
-                               &data[dev->data_bytes_per_chunk];
-               yaffs_unpack_tags2_tags_only(tags, pt2tp);
-       } else if (tags) {
-               memcpy(packed_tags_ptr,
-                      yaffs_dev_to_lc(dev)->spare_buffer,
-                      packed_tags_size);
-               yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
-       }
-
-       if (local_data)
-               yaffs_release_temp_buffer(dev, data);
-
-       if (tags && retval == -EBADMSG &&
-           tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
-               tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
-               dev->n_ecc_unfixed++;
-       }
-       if (tags && retval == -EUCLEAN &&
-           tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
-               tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
-               dev->n_ecc_fixed++;
-       }
-
-       if (retval == 0)
-               return YAFFS_OK;
-
-       return YAFFS_FAIL;
-}
-
-int nandmtd2_mark_block_bad(struct yaffs_dev *dev, int block_no)
-{
-       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-       int retval;
-
-       yaffs_trace(YAFFS_TRACE_MTD,
-               "nandmtd2_mark_block_bad %d", block_no);
-
-       retval =
-           mtd->block_markbad(mtd,
-                              block_no * dev->param.chunks_per_block *
-                              dev->param.total_bytes_per_chunk);
-
-       if (retval == 0)
-               return YAFFS_OK;
-
-       return YAFFS_FAIL;
-}
-
-int nandmtd2_query_block(struct yaffs_dev *dev, int block_no,
-                        enum yaffs_block_state *state, u32 * seq_number)
-{
-       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-       int retval;
-
-       yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_query_block %d", block_no);
-       retval =
-           mtd->block_isbad(mtd,
-                            block_no * dev->param.chunks_per_block *
-                            dev->param.total_bytes_per_chunk);
-
-       if (retval) {
-               yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
-
-               *state = YAFFS_BLOCK_STATE_DEAD;
-               *seq_number = 0;
-       } else {
-               struct yaffs_ext_tags t;
-
-               nandmtd2_read_chunk_tags(dev, block_no *
-                                        dev->param.chunks_per_block, NULL, &t);
-
-               if (t.chunk_used) {
-                       *seq_number = t.seq_number;
-                       *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
-               } else {
-                       *seq_number = 0;
-                       *state = YAFFS_BLOCK_STATE_EMPTY;
-               }
-       }
-       yaffs_trace(YAFFS_TRACE_MTD,
-               "block is bad seq %d state %d", *seq_number, *state);
-
-       if (retval == 0)
-               return YAFFS_OK;
-
-       return YAFFS_FAIL;
-}
diff --git a/yaffs_mtdif_multi.c b/yaffs_mtdif_multi.c
new file mode 100644 (file)
index 0000000..7968c3f
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yportenv.h"
+
+#include "yaffs_mtdif.h"
+
+#include "linux/mtd/mtd.h"
+#include "linux/types.h"
+#include "linux/time.h"
+#include "linux/mtd/nand.h"
+#include "linux/kernel.h"
+#include "linux/version.h"
+#include "linux/types.h"
+
+#include "yaffs_trace.h"
+#include "yaffs_guts.h"
+#include "yaffs_linux.h"
+
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
+#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
+#endif
+
+
+int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
+{
+       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+       u32 addr =
+           ((loff_t) block_no) * dev->param.total_bytes_per_chunk *
+           dev->param.chunks_per_block;
+       struct erase_info ei;
+       int retval = 0;
+
+       ei.mtd = mtd;
+       ei.addr = addr;
+       ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
+       ei.time = 1000;
+       ei.retries = 2;
+       ei.callback = NULL;
+       ei.priv = (u_long) dev;
+
+       retval = mtd->erase(mtd, &ei);
+
+       if (retval == 0)
+               return YAFFS_OK;
+
+       return YAFFS_FAIL;
+}
+
+
+static         int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk,
+                                  const u8 *data, int data_len,
+                                  const u8 *oob, int oob_len)
+{
+       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+       loff_t addr;
+       struct mtd_oob_ops ops;
+       int retval;
+
+       addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
+       memset(&ops, 0, sizeof(ops));
+       ops.mode = MTD_OPS_AUTO_OOB;
+       ops.len = (data) ? data_len : 0;
+       ops.ooblen = oob_len;
+       ops.datbuf = (u8 *)data;
+       ops.oobbuf = (u8 *)oob;
+
+       retval = mtd->write_oob(mtd, addr, &ops);
+       if (retval) {
+               yaffs_trace(YAFFS_TRACE_MTD,
+                       "write_oob failed, chunk %d, mtd error %d",
+                       nand_chunk, retval);
+       }
+       return retval ? YAFFS_FAIL : YAFFS_OK;
+}
+
+static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk,
+                                  u8 *data, int data_len,
+                                  u8 *oob, int oob_len,
+                                  int *ecc_result)
+{
+       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+       loff_t addr;
+       struct mtd_oob_ops ops;
+       int retval;
+
+       addr = ((loff_t) nand_chunk) * dev->data_bytes_per_chunk;
+       memset(&ops, 0, sizeof(ops));
+       ops.mode = MTD_OPS_AUTO_OOB;
+       ops.len = (data) ? data_len : 0;
+       ops.ooblen = oob_len;
+       ops.datbuf = data;
+       ops.oobbuf = oob;
+
+#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20))
+       /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
+        * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
+        */
+       ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
+#endif
+       /* Read page and oob using MTD.
+        * Check status and determine ECC result.
+        */
+       retval = mtd->read_oob(mtd, addr, &ops);
+       if (retval)
+               yaffs_trace(YAFFS_TRACE_MTD,
+                       "read_oob failed, chunk %d, mtd error %d",
+                       nand_chunk, retval);
+
+       switch (retval) {
+       case 0:
+               /* no error */
+               if(ecc_result)
+                       *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+               break;
+
+       case -EUCLEAN:
+               /* MTD's ECC fixed the data */
+               if(ecc_result)
+                       *ecc_result = YAFFS_ECC_RESULT_FIXED;
+               dev->n_ecc_fixed++;
+               break;
+
+       case -EBADMSG:
+       default:
+               /* MTD's ECC could not fix the data */
+               dev->n_ecc_unfixed++;
+               if(ecc_result)
+                       *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+               return YAFFS_FAIL;
+       }
+
+       return YAFFS_OK;
+}
+
+static         int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no)
+{
+       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+
+       loff_t addr;
+       struct erase_info ei;
+       int retval = 0;
+       u32 block_size;
+
+       block_size = dev->param.total_bytes_per_chunk *
+                    dev->param.chunks_per_block;
+       addr = ((loff_t) block_no) * block_size;
+
+       ei.mtd = mtd;
+       ei.addr = addr;
+       ei.len = block_size;
+       ei.time = 1000;
+       ei.retries = 2;
+       ei.callback = NULL;
+       ei.priv = (u_long) dev;
+
+       retval = mtd->erase(mtd, &ei);
+
+       if (retval == 0)
+               return YAFFS_OK;
+
+       return YAFFS_FAIL;
+}
+
+static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no)
+{
+       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+       int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
+       int retval;
+
+       yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);
+
+       retval = mtd->block_markbad(mtd, (loff_t) blocksize * block_no);
+       return (retval) ? YAFFS_FAIL : YAFFS_OK;
+}
+
+static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no)
+{
+       struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+       int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
+       int retval;
+
+       yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "checking block %d bad", block_no);
+
+       retval = mtd->block_isbad(mtd, (loff_t) blocksize * block_no);
+       return (retval) ? YAFFS_FAIL : YAFFS_OK;
+}
+
+static int yaffs_mtd_initialise(struct yaffs_dev *dev)
+{
+       return YAFFS_OK;
+}
+
+static int yaffs_mtd_deinitialise(struct yaffs_dev *dev)
+{
+       return YAFFS_OK;
+}
+
+
+
+void yaffs_mtd_drv_install(struct yaffs_dev *dev)
+{
+       struct yaffs_param *param = &dev->param;
+
+       param->drv_write_chunk_fn = yaffs_mtd_write;
+       param->drv_read_chunk_fn = yaffs_mtd_read;
+       param->drv_erase_fn = yaffs_mtd_erase;
+       param->drv_mark_bad_fn = yaffs_mtd_mark_bad;
+       param->drv_check_bad_fn = yaffs_mtd_check_bad;
+       param->drv_initialise_fn = yaffs_mtd_initialise;
+       param->drv_deinitialise_fn = yaffs_mtd_deinitialise;
+}
index 165d01004d6efde447d4b88a42f38c74dafa5fed..4c1993bb7d2eed23c54e38ded284c062f93dc29e 100644 (file)
 #include "yaffs_getblockinfo.h"
 #include "yaffs_summary.h"
 
+static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
+{
+       return chunk - dev->chunk_offset;
+}
+
 int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
                             u8 *buffer, struct yaffs_ext_tags *tags)
 {
        int result;
        struct yaffs_ext_tags local_tags;
-       int flash_chunk = nand_chunk - dev->chunk_offset;
+       int flash_chunk = apply_chunk_offset(dev, nand_chunk);
 
        dev->n_page_reads++;
 
@@ -30,13 +35,7 @@ int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
        if (!tags)
                tags = &local_tags;
 
-       if (dev->param.read_chunk_tags_fn)
-               result =
-                   dev->param.read_chunk_tags_fn(dev, flash_chunk, buffer,
-                                                 tags);
-       else
-               result = yaffs_tags_compat_rd(dev,
-                                             flash_chunk, buffer, tags);
+       result = dev->param.read_chunk_tags_fn(dev, flash_chunk, buffer, tags);
        if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
 
                struct yaffs_block_info *bi;
@@ -53,27 +52,24 @@ int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
                                const u8 *buffer, struct yaffs_ext_tags *tags)
 {
        int result;
-       int flash_chunk = nand_chunk - dev->chunk_offset;
+       int flash_chunk = apply_chunk_offset(dev, nand_chunk);
 
        dev->n_page_writes++;
 
-       if (tags) {
-               tags->seq_number = dev->seq_number;
-               tags->chunk_used = 1;
-               yaffs_trace(YAFFS_TRACE_WRITE,
-                       "Writing chunk %d tags %d %d",
-                       nand_chunk, tags->obj_id, tags->chunk_id);
-       } else {
+       if (!tags) {
                yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
                BUG();
                return YAFFS_FAIL;
        }
 
-       if (dev->param.write_chunk_tags_fn)
-               result = dev->param.write_chunk_tags_fn(dev, flash_chunk,
+       tags->seq_number = dev->seq_number;
+       tags->chunk_used = 1;
+       yaffs_trace(YAFFS_TRACE_WRITE,
+               "Writing chunk %d tags %d %d",
+               nand_chunk, tags->obj_id, tags->chunk_id);
+
+       result = dev->param.write_chunk_tags_fn(dev, flash_chunk,
                                                        buffer, tags);
-       else
-               result = yaffs_tags_compat_wr(dev, flash_chunk, buffer, tags);
 
        yaffs_summary_add(dev, tags, nand_chunk);
 
@@ -83,38 +79,33 @@ int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
 int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
 {
        block_no -= dev->block_offset;
-       if (dev->param.bad_block_fn)
-               return dev->param.bad_block_fn(dev, block_no);
-
-       return yaffs_tags_compat_mark_bad(dev, block_no);
+       dev->n_bad_markings++;
+       return dev->param.mark_bad_fn(dev, block_no);
 }
 
+
 int yaffs_query_init_block_state(struct yaffs_dev *dev,
                                 int block_no,
                                 enum yaffs_block_state *state,
                                 u32 *seq_number)
 {
        block_no -= dev->block_offset;
-       if (dev->param.query_block_fn)
-               return dev->param.query_block_fn(dev, block_no, state,
-                                                seq_number);
-
-       return yaffs_tags_compat_query_block(dev, block_no, state, seq_number);
+       return dev->param.query_block_fn(dev, block_no, state, seq_number);
 }
 
-int yaffs_erase_block(struct yaffs_dev *dev, int flash_block)
+int yaffs_erase_block(struct yaffs_dev *dev, int block_no)
 {
        int result;
 
-       flash_block -= dev->block_offset;
+       block_no -= dev->block_offset;
        dev->n_erasures++;
-       result = dev->param.erase_fn(dev, flash_block);
+       result = dev->param.drv_erase_fn(dev, block_no);
        return result;
 }
 
 int yaffs_init_nand(struct yaffs_dev *dev)
 {
-       if (dev->param.initialise_flash_fn)
-               return dev->param.initialise_flash_fn(dev);
+       if (dev->param.drv_initialise_fn)
+               return dev->param.drv_initialise_fn(dev);
        return YAFFS_OK;
 }
index 32ba11fa9d5ce8e2ed0aab3fc8988fef0b2908f5..78781e638346f37d7138d7b87f366e5009ed95e0 100644 (file)
@@ -127,6 +127,10 @@ static int yaffs_wr_nand(struct yaffs_dev *dev,
                         int nand_chunk, const u8 *data,
                         struct yaffs_spare *spare)
 {
+       int data_size;
+       int spare_size;
+       u8 spare_buffer[100];
+
        if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) {
                yaffs_trace(YAFFS_TRACE_ERROR,
                        "**>> yaffs chunk %d is not valid",
@@ -134,7 +138,11 @@ static int yaffs_wr_nand(struct yaffs_dev *dev,
                return YAFFS_FAIL;
        }
 
-       return dev->param.write_chunk_fn(dev, nand_chunk, data, spare);
+       /* Format up the spare */
+
+       return dev->param.drv_write_chunk_fn(dev, nand_chunk,
+                               data, data_size,
+                               spare_buffer, spare_size);
 }
 
 static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
@@ -146,6 +154,8 @@ static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
 {
        int ret_val;
        struct yaffs_spare local_spare;
+       int data_size;
+       int spare_size;
 
        if (!spare) {
                /* If we don't have a real spare, then we use a local one. */
@@ -155,7 +165,10 @@ static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
 
        if (!dev->param.use_nand_ecc) {
                ret_val =
-                   dev->param.read_chunk_fn(dev, nand_chunk, data, spare);
+                   dev->param.drv_read_chunk_fn(dev, nand_chunk,
+                                                data, data_size,
+                                                (u8 *)spare, spare_size,
+                                       ecc_result);
                if (data && correct_errors) {
                        /* Do ECC correction */
                        /* Todo handle any errors */
@@ -213,9 +226,10 @@ static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
 
                memset(&nspare, 0, sizeof(nspare));
 
-               ret_val = dev->param.read_chunk_fn(dev, nand_chunk, data,
-                                                  (struct yaffs_spare *)
-                                                  &nspare);
+               ret_val = dev->param.drv_read_chunk_fn(dev, nand_chunk,
+                                               data, data_size,
+                                               (u8 *) &nspare, sizeof(nspare),
+                                               NULL);
                memcpy(spare, &nspare, sizeof(struct yaffs_spare));
                if (data && correct_errors) {
                        if (nspare.eccres1 > 0) {
@@ -277,7 +291,7 @@ static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk)
         */
 }
 
-int yaffs_tags_compat_wr(struct yaffs_dev *dev,
+static int yaffs_tags_compat_wr(struct yaffs_dev *dev,
                         int nand_chunk,
                         const u8 *data, const struct yaffs_ext_tags *ext_tags)
 {
@@ -309,7 +323,7 @@ int yaffs_tags_compat_wr(struct yaffs_dev *dev,
        return yaffs_wr_nand(dev, nand_chunk, data, &spare);
 }
 
-int yaffs_tags_compat_rd(struct yaffs_dev *dev,
+static int yaffs_tags_compat_rd(struct yaffs_dev *dev,
                         int nand_chunk,
                         u8 *data, struct yaffs_ext_tags *ext_tags)
 {
@@ -358,7 +372,7 @@ int yaffs_tags_compat_rd(struct yaffs_dev *dev,
        return YAFFS_OK;
 }
 
-int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
+static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
 {
        struct yaffs_spare spare;
 
@@ -374,7 +388,7 @@ int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
        return YAFFS_OK;
 }
 
-int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
+static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
                                  int block_no,
                                  enum yaffs_block_state *state,
                                  u32 *seq_number)
@@ -405,3 +419,17 @@ int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
 
        return YAFFS_OK;
 }
+
+void yaffs_tags_compat_install(struct yaffs_dev *dev)
+{
+       if(dev->param.is_yaffs2)
+               return;
+       if(!dev->param.write_chunk_tags_fn)
+               dev->param.write_chunk_tags_fn = yaffs_tags_compat_wr;
+       if(!dev->param.read_chunk_tags_fn)
+               dev->param.read_chunk_tags_fn = yaffs_tags_compat_rd;
+       if(!dev->param.read_chunk_tags_fn)
+               dev->param.query_block_fn = yaffs_tags_compat_query_block;
+       if(!dev->param.mark_bad_fn)
+               dev->param.mark_bad_fn = yaffs_tags_compat_mark_bad;
+}
index b3c665577252bbbc059295aa5ee10e45f16fbeb8..92d298a6f582b8d8475840fb13e8034d9d6b1381 100644 (file)
 #ifndef __YAFFS_TAGSCOMPAT_H__
 #define __YAFFS_TAGSCOMPAT_H__
 
+
 #include "yaffs_guts.h"
+
+#if 0
+
+
 int yaffs_tags_compat_wr(struct yaffs_dev *dev,
                         int nand_chunk,
                         const u8 *data, const struct yaffs_ext_tags *tags);
@@ -29,8 +34,11 @@ int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
                                  enum yaffs_block_state *state,
                                  u32 *seq_number);
 
+#endif
+
+
+void yaffs_tags_compat_install(struct yaffs_dev *dev);
 void yaffs_calc_tags_ecc(struct yaffs_tags *tags);
 int yaffs_check_tags_ecc(struct yaffs_tags *tags);
-int yaffs_count_bits(u8 byte);
 
 #endif
diff --git a/yaffs_tagsmarshall.c b/yaffs_tagsmarshall.c
new file mode 100644 (file)
index 0000000..bbc228b
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_guts.h"
+#include "yaffs_trace.h"
+#include "yaffs_packedtags2.h"
+
+static int yaffs_tags_marshall_write(struct yaffs_dev *dev,
+                                   int nand_chunk, const u8 *data,
+                                   const struct yaffs_ext_tags *tags)
+{
+       struct yaffs_packed_tags2 pt;
+       int retval;
+
+       int packed_tags_size =
+           dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
+       void *packed_tags_ptr =
+           dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
+
+       yaffs_trace(YAFFS_TRACE_MTD,
+               "yaffs_tags_marshall_write chunk %d data %p tags %p",
+               nand_chunk, data, tags);
+
+       /* For yaffs2 writing there must be both data and tags.
+        * If we're using inband tags, then the tags are stuffed into
+        * the end of the data buffer.
+        */
+       if (!data || !tags)
+               BUG();
+       else if (dev->param.inband_tags) {
+               struct yaffs_packed_tags2_tags_only *pt2tp;
+               pt2tp =
+                   (struct yaffs_packed_tags2_tags_only *)(data +
+                                                       dev->
+                                                       data_bytes_per_chunk);
+               yaffs_pack_tags2_tags_only(pt2tp, tags);
+       } else {
+               yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
+       }
+
+       retval = dev->param.drv_write_chunk_fn(dev, nand_chunk,
+                       data, dev->param.total_bytes_per_chunk,
+                       (dev->param.inband_tags) ? NULL : packed_tags_ptr,
+                       (dev->param.inband_tags) ? 0 : packed_tags_size);
+
+       return retval;
+}
+
+static int yaffs_tags_marshall_read(struct yaffs_dev *dev,
+                                  int nand_chunk, u8 *data,
+                                  struct yaffs_ext_tags *tags)
+{
+       int retval = 0;
+       int local_data = 0;
+       u8 spare_buffer[100];
+       enum yaffs_ecc_result ecc_result;
+
+       struct yaffs_packed_tags2 pt;
+
+       int packed_tags_size =
+           dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
+       void *packed_tags_ptr =
+           dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
+
+       yaffs_trace(YAFFS_TRACE_MTD,
+               "yaffs_tags_marshall_read chunk %d data %p tags %p",
+               nand_chunk, data, tags);
+
+       if (dev->param.inband_tags) {
+               if (!data) {
+                       local_data = 1;
+                       data = yaffs_get_temp_buffer(dev);
+               }
+       }
+
+       if (dev->param.inband_tags || (data && !tags))
+               retval = dev->param.drv_read_chunk_fn(dev, nand_chunk,
+                                       data, dev->param.total_bytes_per_chunk,
+                                       NULL, 0,
+                                       &ecc_result);
+       else if (tags)
+               retval = dev->param.drv_read_chunk_fn(dev, nand_chunk,
+                                       data, dev->param.total_bytes_per_chunk,
+                                       spare_buffer, packed_tags_size,
+                                       &ecc_result);
+       else
+               BUG();
+
+
+       if (dev->param.inband_tags) {
+               if (tags) {
+                       struct yaffs_packed_tags2_tags_only *pt2tp;
+                       pt2tp =
+                               (struct yaffs_packed_tags2_tags_only *)
+                               &data[dev->data_bytes_per_chunk];
+                       yaffs_unpack_tags2_tags_only(tags, pt2tp);
+               }
+       } else if (tags) {
+               memcpy(packed_tags_ptr, spare_buffer, packed_tags_size);
+               yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
+       }
+
+       if (local_data)
+               yaffs_release_temp_buffer(dev, data);
+
+       if (tags && ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
+               tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+               dev->n_ecc_unfixed++;
+       }
+
+       if (tags && ecc_result == -YAFFS_ECC_RESULT_FIXED) {
+               if (tags->ecc_result <= YAFFS_ECC_RESULT_NO_ERROR)
+                       tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
+               dev->n_ecc_fixed++;
+       }
+
+       if (ecc_result < YAFFS_ECC_RESULT_UNFIXED)
+               return YAFFS_OK;
+       else
+               return YAFFS_FAIL;
+}
+
+static int yaffs_tags_marshall_query_block(struct yaffs_dev *dev, int block_no,
+                              enum yaffs_block_state *state,
+                              u32 *seq_number)
+{
+       int retval;
+
+       yaffs_trace(YAFFS_TRACE_MTD, "yaffs_tags_marshall_query_block %d",
+                       block_no);
+
+       retval = dev->param.drv_check_bad_fn(dev, block_no);
+
+       if (retval== YAFFS_FAIL) {
+               yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
+
+               *state = YAFFS_BLOCK_STATE_DEAD;
+               *seq_number = 0;
+       } else {
+               struct yaffs_ext_tags t;
+
+               yaffs_tags_marshall_read(dev,
+                                   block_no * dev->param.chunks_per_block,
+                                   NULL, &t);
+
+               if (t.chunk_used) {
+                       *seq_number = t.seq_number;
+                       *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
+               } else {
+                       *seq_number = 0;
+                       *state = YAFFS_BLOCK_STATE_EMPTY;
+               }
+       }
+
+       yaffs_trace(YAFFS_TRACE_MTD,
+               "block query returns  seq %d state %d",
+               *seq_number, *state);
+
+       if (retval == 0)
+               return YAFFS_OK;
+       else
+               return YAFFS_FAIL;
+}
+
+static int yaffs_tags_marshall_mark_bad(struct yaffs_dev *dev, int block_no)
+{
+       return dev->param.drv_mark_bad_fn(dev, block_no);
+
+}
+
+
+void yaffs_tags_marshall_install(struct yaffs_dev *dev)
+{
+       if (!dev->param.is_yaffs2)
+               return;
+
+       if (!dev->param.write_chunk_tags_fn)
+               dev->param.write_chunk_tags_fn = yaffs_tags_marshall_write;
+
+       if (!dev->param.read_chunk_tags_fn)
+               dev->param.read_chunk_tags_fn = yaffs_tags_marshall_read;
+
+       if (!dev->param.query_block_fn)
+               dev->param.query_block_fn = yaffs_tags_marshall_query_block;
+
+       if (!dev->param.mark_bad_fn)
+               dev->param.mark_bad_fn = yaffs_tags_marshall_mark_bad;
+
+}
similarity index 52%
rename from yaffs_mtdif2.h
rename to yaffs_tagsmarshall.h
index d4d18585b2cfa4fc737040938c6d9ae8a8bb701c..bf3e68a1a5be8a7e2321f08a7d3828851949f6b7 100644 (file)
  * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
  */
 
-#ifndef __YAFFS_MTDIF2_H__
-#define __YAFFS_MTDIF2_H__
+#ifndef __YAFFS_TAGSMARSHALL_H__
+#define __YAFFS_TAGSMARSHALL_H__
 
 #include "yaffs_guts.h"
-int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
-                             const u8 *data,
-                             const struct yaffs_ext_tags *tags);
-int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
-                            u8 *data, struct yaffs_ext_tags *tags);
-int nandmtd2_mark_block_bad(struct yaffs_dev *dev, int block_no);
-int nandmtd2_query_block(struct yaffs_dev *dev, int block_no,
-                        enum yaffs_block_state *state, u32 *seq_number);
+void yaffs_tags_marshall_install(struct yaffs_dev *dev);
 
 #endif
index ce41d6c81d8150a0ad59a70fec185c2645d167c7..322f9819c3f47fef498b25e382aa8822ecea96a3 100644 (file)
@@ -176,8 +176,6 @@ static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
 #include "yaffs_linux.h"
 
 #include "yaffs_mtdif.h"
-#include "yaffs_mtdif1.h"
-#include "yaffs_mtdif2.h"
 
 unsigned int yaffs_trace_mask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS;
 unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
@@ -2831,14 +2829,7 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version,
 
        /* Set up the memory size parameters.... */
 
-       n_blocks =
-           YCALCBLOCKS(mtd->size,
-                       (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
 
-       param->start_block = 0;
-       param->end_block = n_blocks - 1;
-       param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
-       param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
        param->n_reserved_blocks = 5;
        param->n_caches = (options.no_cache) ? 0 : 10;
        param->inband_tags = options.inband_tags;
@@ -2861,12 +2852,6 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version,
 
        /* ... and the functions. */
        if (yaffs_version == 2) {
-               param->write_chunk_tags_fn = nandmtd2_write_chunk_tags;
-               param->read_chunk_tags_fn = nandmtd2_read_chunk_tags;
-               param->bad_block_fn = nandmtd2_mark_block_bad;
-               param->query_block_fn = nandmtd2_query_block;
-               yaffs_dev_to_lc(dev)->spare_buffer =
-                               kmalloc(mtd->oobsize, GFP_NOFS);
                param->is_yaffs2 = 1;
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
                param->total_bytes_per_chunk = mtd->writesize;
@@ -2880,21 +2865,18 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version,
                param->start_block = 0;
                param->end_block = n_blocks - 1;
        } else {
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
-               /* use the MTD interface in yaffs_mtdif1.c */
-               param->write_chunk_tags_fn = nandmtd1_write_chunk_tags;
-               param->read_chunk_tags_fn = nandmtd1_read_chunk_tags;
-               param->bad_block_fn = nandmtd1_mark_block_bad;
-               param->query_block_fn = nandmtd1_query_block;
-#else
-               param->write_chunk_fn = nandmtd_write_chunk;
-               param->read_chunk_fn = nandmtd_read_chunk;
-#endif
                param->is_yaffs2 = 0;
+               n_blocks = YCALCBLOCKS(mtd->size,
+                            YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
+
+               param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
+               param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
        }
-       /* ... and common functions */
-       param->erase_fn = nandmtd_erase_block;
-       param->initialise_flash_fn = nandmtd_initialise;
+
+       param->start_block = 0;
+       param->end_block = n_blocks - 1;
+
+       yaffs_mtd_drv_install(dev);
 
        yaffs_dev_to_lc(dev)->put_super_fn = yaffs_mtd_put_super;