2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
4 * Copyright (C) 2002-2011 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
7 * Created by Charles Manning <charles@aleph1.co.uk>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
16 #include "yaffs_mtdif.h"
18 #include "linux/mtd/mtd.h"
19 #include "linux/types.h"
20 #include "linux/time.h"
21 #include "linux/mtd/nand.h"
22 #include "linux/kernel.h"
23 #include "linux/version.h"
24 #include "linux/types.h"
26 #include "yaffs_trace.h"
27 #include "yaffs_guts.h"
28 #include "yaffs_linux.h"
31 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
32 #define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
36 int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
38 struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
40 ((loff_t) block_no) * dev->param.total_bytes_per_chunk *
41 dev->param.chunks_per_block;
47 ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
51 ei.priv = (u_long) dev;
53 retval = mtd->erase(mtd, &ei);
62 static int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk,
63 const u8 *data, int data_len,
64 const u8 *oob, int oob_len)
66 struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
68 struct mtd_oob_ops ops;
71 addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
72 memset(&ops, 0, sizeof(ops));
73 ops.mode = MTD_OPS_AUTO_OOB;
74 ops.len = (data) ? data_len : 0;
76 ops.datbuf = (u8 *)data;
77 ops.oobbuf = (u8 *)oob;
79 retval = mtd->write_oob(mtd, addr, &ops);
81 yaffs_trace(YAFFS_TRACE_MTD,
82 "write_oob failed, chunk %d, mtd error %d",
85 return retval ? YAFFS_FAIL : YAFFS_OK;
88 static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk,
89 u8 *data, int data_len,
91 enum yaffs_ecc_result *ecc_result)
93 struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
95 struct mtd_oob_ops ops;
98 addr = ((loff_t) nand_chunk) * dev->data_bytes_per_chunk;
99 memset(&ops, 0, sizeof(ops));
100 ops.mode = MTD_OPS_AUTO_OOB;
101 ops.len = (data) ? data_len : 0;
102 ops.ooblen = oob_len;
106 #if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20))
107 /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
108 * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
110 ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
112 /* Read page and oob using MTD.
113 * Check status and determine ECC result.
115 retval = mtd->read_oob(mtd, addr, &ops);
117 yaffs_trace(YAFFS_TRACE_MTD,
118 "read_oob failed, chunk %d, mtd error %d",
125 *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
129 /* MTD's ECC fixed the data */
131 *ecc_result = YAFFS_ECC_RESULT_FIXED;
137 /* MTD's ECC could not fix the data */
138 dev->n_ecc_unfixed++;
140 *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
147 static int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no)
149 struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
152 struct erase_info ei;
156 block_size = dev->param.total_bytes_per_chunk *
157 dev->param.chunks_per_block;
158 addr = ((loff_t) block_no) * block_size;
166 ei.priv = (u_long) dev;
168 retval = mtd->erase(mtd, &ei);
176 static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no)
178 struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
179 int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
182 yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);
184 retval = mtd->block_markbad(mtd, (loff_t) blocksize * block_no);
185 return (retval) ? YAFFS_FAIL : YAFFS_OK;
188 static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no)
190 struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
191 int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
194 yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "checking block %d bad", block_no);
196 retval = mtd->block_isbad(mtd, (loff_t) blocksize * block_no);
197 return (retval) ? YAFFS_FAIL : YAFFS_OK;
200 static int yaffs_mtd_initialise(struct yaffs_dev *dev)
205 static int yaffs_mtd_deinitialise(struct yaffs_dev *dev)
212 void yaffs_mtd_drv_install(struct yaffs_dev *dev)
214 struct yaffs_driver *drv = &dev->drv;
216 drv->drv_write_chunk_fn = yaffs_mtd_write;
217 drv->drv_read_chunk_fn = yaffs_mtd_read;
218 drv->drv_erase_fn = yaffs_mtd_erase;
219 drv->drv_mark_bad_fn = yaffs_mtd_mark_bad;
220 drv->drv_check_bad_fn = yaffs_mtd_check_bad;
221 drv->drv_initialise_fn = yaffs_mtd_initialise;
222 drv->drv_deinitialise_fn = yaffs_mtd_deinitialise;