X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_mtdif_multi.c;h=2d34b017d08e696939347ade4341868351aa8a21;hp=e61699d6e85f4475a2ddf87630c7161d0daec1a7;hb=e1cc6e41366587ff0bdb7e246b5f17d230c13226;hpb=54721f22512e7c859c4c4a4ae7e5374ecf7fb570 diff --git a/yaffs_mtdif_multi.c b/yaffs_mtdif_multi.c index e61699d..2d34b01 100644 --- a/yaffs_mtdif_multi.c +++ b/yaffs_mtdif_multi.c @@ -1,8 +1,7 @@ /* * 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 + * Copyright (C) 2002-2018 Aleph One Ltd. * * Created by Charles Manning * @@ -18,39 +17,55 @@ #include "linux/mtd/mtd.h" #include "linux/types.h" #include "linux/time.h" +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)) #include "linux/mtd/nand.h" +#else +#include "linux/mtd/rawnand.h" +#endif #include "linux/kernel.h" #include "linux/version.h" #include "linux/types.h" +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +#include "uapi/linux/major.h" +#endif #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 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) +#define mtd_erase(m, ei) (m)->erase(m, ei) +#define mtd_write_oob(m, addr, pops) (m)->write_oob(m, addr, pops) +#define mtd_read_oob(m, addr, pops) (m)->read_oob(m, addr, pops) +#define mtd_block_isbad(m, offs) (m)->block_isbad(m, offs) +#define mtd_block_markbad(m, offs) (m)->block_markbad(m, offs) +#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; + u32 addr = ((loff_t) block_no) * dev->param.total_bytes_per_chunk * + dev->param.chunks_per_block; struct erase_info ei; int retval = 0; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)) ei.mtd = mtd; +#endif ei.addr = addr; ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)) ei.time = 1000; ei.retries = 2; ei.callback = NULL; ei.priv = (u_long) dev; +#endif - retval = mtd->erase(mtd, &ei); + retval = mtd_erase(mtd, &ei); if (retval == 0) return YAFFS_OK; @@ -58,16 +73,29 @@ int nandmtd_erase_block(struct yaffs_dev *dev, int block_no) 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) +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; + yaffs_trace(YAFFS_TRACE_MTD, + "yaffs_mtd_write(%p, %d, %p, %d, %p, %d)\n", + dev, nand_chunk, data, data_len, oob, oob_len); + + if (!data || !data_len) { + data = NULL; + data_len = 0; + } + + if (!oob || !oob_len) { + oob = NULL; + oob_len = 0; + } + addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk; memset(&ops, 0, sizeof(ops)); ops.mode = MTD_OPS_AUTO_OOB; @@ -76,7 +104,7 @@ static int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk, ops.datbuf = (u8 *)data; ops.oobbuf = (u8 *)oob; - retval = mtd->write_oob(mtd, addr, &ops); + retval = mtd_write_oob(mtd, addr, &ops); if (retval) { yaffs_trace(YAFFS_TRACE_MTD, "write_oob failed, chunk %d, mtd error %d", @@ -95,7 +123,7 @@ static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk, struct mtd_oob_ops ops; int retval; - addr = ((loff_t) nand_chunk) * dev->data_bytes_per_chunk; + 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; @@ -112,7 +140,7 @@ static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk, /* Read page and oob using MTD. * Check status and determine ECC result. */ - retval = mtd->read_oob(mtd, addr, &ops); + retval = mtd_read_oob(mtd, addr, &ops); if (retval) yaffs_trace(YAFFS_TRACE_MTD, "read_oob failed, chunk %d, mtd error %d", @@ -144,7 +172,7 @@ static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk, return YAFFS_OK; } -static int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no) +static int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no) { struct mtd_info *mtd = yaffs_dev_to_mtd(dev); @@ -157,15 +185,19 @@ static int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no) dev->param.chunks_per_block; addr = ((loff_t) block_no) * block_size; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)) ei.mtd = mtd; +#endif ei.addr = addr; ei.len = block_size; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)) ei.time = 1000; ei.retries = 2; ei.callback = NULL; ei.priv = (u_long) dev; +#endif - retval = mtd->erase(mtd, &ei); + retval = mtd_erase(mtd, &ei); if (retval == 0) return YAFFS_OK; @@ -176,24 +208,24 @@ static int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no) 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 blocksize = dev->param.chunks_per_block * dev->param.total_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); + 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 blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk; int retval; - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "checking block %d bad", block_no); + yaffs_trace(YAFFS_TRACE_MTD, "checking block %d bad", block_no); - retval = mtd->block_isbad(mtd, (loff_t) blocksize * block_no); + retval = mtd_block_isbad(mtd, (loff_t) blocksize * block_no); return (retval) ? YAFFS_FAIL : YAFFS_OK; } @@ -207,8 +239,6 @@ static int yaffs_mtd_deinitialise(struct yaffs_dev *dev) return YAFFS_OK; } - - void yaffs_mtd_drv_install(struct yaffs_dev *dev) { struct yaffs_driver *drv = &dev->drv; @@ -221,3 +251,63 @@ void yaffs_mtd_drv_install(struct yaffs_dev *dev) drv->drv_initialise_fn = yaffs_mtd_initialise; drv->drv_deinitialise_fn = yaffs_mtd_deinitialise; } + +struct mtd_info * yaffs_get_mtd_device(dev_t sdev) +{ + struct mtd_info *mtd; + + mtd = yaffs_get_mtd_device(sdev); + + /* Check it's an mtd device..... */ + if (MAJOR(sdev) != MTD_BLOCK_MAJOR) + return NULL; /* This isn't an mtd device */ + + /* Check it's NAND */ + if (mtd->type != MTD_NANDFLASH) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs: MTD device is not NAND it's type %d", + mtd->type); + return NULL; + } + + yaffs_trace(YAFFS_TRACE_OS, " %s %d", WRITE_SIZE_STR, WRITE_SIZE(mtd)); + yaffs_trace(YAFFS_TRACE_OS, " oobsize %d", mtd->oobsize); + yaffs_trace(YAFFS_TRACE_OS, " erasesize %d", mtd->erasesize); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) + yaffs_trace(YAFFS_TRACE_OS, " size %u", mtd->size); +#else + yaffs_trace(YAFFS_TRACE_OS, " size %lld", mtd->size); +#endif + + return mtd; +} + +int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags) +{ + if (yaffs_version == 2) { + if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE || + mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) && + !inband_tags) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "MTD device does not have the right page sizes" + ); + return -1; + } + } else { + if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK || + mtd->oobsize != YAFFS_BYTES_PER_SPARE) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "MTD device does not support have the right page sizes" + ); + return -1; + } + } + + return 0; +} + +void yaffs_put_mtd_device(struct mtd_info *mtd) +{ + if (mtd) + put_mtd_device(mtd); +}