From 9c99932eb16ba64c6d3ba69145fe8c5d5b04274d Mon Sep 17 00:00:00 2001 From: Charles Manning Date: Tue, 19 Jun 2012 14:32:23 +1200 Subject: [PATCH] Refactor nand driver layer. WIP: yaffs2 working on Linux Signed-off-by: Charles Manning --- Makefile | 10 +- yaffs_checkptrw.c | 9 +- yaffs_guts.c | 41 +-- yaffs_guts.h | 47 ++-- yaffs_mtdif.c | 53 ---- yaffs_mtdif.h | 4 +- yaffs_mtdif1.h | 29 -- yaffs_mtdif1_multi.c | 364 ------------------------- yaffs_mtdif1_single.c | 325 ---------------------- yaffs_mtdif2_multi.c | 268 ------------------ yaffs_mtdif2_single.c | 210 -------------- yaffs_mtdif_multi.c | 223 +++++++++++++++ yaffs_nand.c | 59 ++-- yaffs_tagscompat.c | 46 +++- yaffs_tagscompat.h | 10 +- yaffs_tagsmarshall.c | 199 ++++++++++++++ yaffs_mtdif2.h => yaffs_tagsmarshall.h | 13 +- yaffs_vfs_multi.c | 38 +-- 18 files changed, 569 insertions(+), 1379 deletions(-) delete mode 100644 yaffs_mtdif.c delete mode 100644 yaffs_mtdif1.h delete mode 100644 yaffs_mtdif1_multi.c delete mode 100644 yaffs_mtdif1_single.c delete mode 100644 yaffs_mtdif2_multi.c delete mode 100644 yaffs_mtdif2_single.c create mode 100644 yaffs_mtdif_multi.c create mode 100644 yaffs_tagsmarshall.c rename yaffs_mtdif2.h => yaffs_tagsmarshall.h (52%) diff --git a/Makefile b/Makefile index 6722182..a346458 100644 --- 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 diff --git a/yaffs_checkptrw.c b/yaffs_checkptrw.c index 8478eb8..b1c4bee 100644 --- a/yaffs_checkptrw.c +++ b/yaffs_checkptrw.c @@ -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)) diff --git a/yaffs_guts.c b/yaffs_guts.c index 79568ee..0c33102 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -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); } } diff --git a/yaffs_guts.h b/yaffs_guts.h index f4fe475..643e575 100644 --- a/yaffs_guts.h +++ b/yaffs_guts.h @@ -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 index edc1525..0000000 --- a/yaffs_mtdif.c +++ /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 - * - * 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; -} diff --git a/yaffs_mtdif.h b/yaffs_mtdif.h index 3ef5581..e5172eb 100644 --- a/yaffs_mtdif.h +++ b/yaffs_mtdif.h @@ -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 index 6a5df50..0000000 --- a/yaffs_mtdif1.h +++ /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 index 14d5c6f..0000000 --- a/yaffs_mtdif1_multi.c +++ /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 - * - * 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 index dbc9122..0000000 --- a/yaffs_mtdif1_single.c +++ /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 - * - * 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 index 18ac992..0000000 --- a/yaffs_mtdif2_multi.c +++ /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 - * - * 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 index f92c49f..0000000 --- a/yaffs_mtdif2_single.c +++ /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 - * - * 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 index 0000000..7968c3f --- /dev/null +++ b/yaffs_mtdif_multi.c @@ -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 + * + * 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; +} diff --git a/yaffs_nand.c b/yaffs_nand.c index 165d010..4c1993b 100644 --- a/yaffs_nand.c +++ b/yaffs_nand.c @@ -17,12 +17,17 @@ #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; } diff --git a/yaffs_tagscompat.c b/yaffs_tagscompat.c index 32ba11f..78781e6 100644 --- a/yaffs_tagscompat.c +++ b/yaffs_tagscompat.c @@ -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; +} diff --git a/yaffs_tagscompat.h b/yaffs_tagscompat.h index b3c6655..92d298a 100644 --- a/yaffs_tagscompat.h +++ b/yaffs_tagscompat.h @@ -16,7 +16,12 @@ #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 index 0000000..bbc228b --- /dev/null +++ b/yaffs_tagsmarshall.c @@ -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 + * + * 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; + +} diff --git a/yaffs_mtdif2.h b/yaffs_tagsmarshall.h similarity index 52% rename from yaffs_mtdif2.h rename to yaffs_tagsmarshall.h index d4d1858..bf3e68a 100644 --- a/yaffs_mtdif2.h +++ b/yaffs_tagsmarshall.h @@ -13,17 +13,10 @@ * 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 diff --git a/yaffs_vfs_multi.c b/yaffs_vfs_multi.c index ce41d6c..322f981 100644 --- a/yaffs_vfs_multi.c +++ b/yaffs_vfs_multi.c @@ -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; -- 2.30.2