2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
4 * Copyright (C) 2002-2007 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.
14 /* mtd interface for YAFFS2 */
18 #include "asm/errno.h"
21 #include "yaffs_trace.h"
23 #include "yaffs_mtdif2.h"
25 #include "linux/mtd/mtd.h"
26 #include "linux/types.h"
27 #include "linux/time.h"
29 #include "yaffs_trace.h"
31 #include "yaffs_packedtags2.h"
35 int nandmtd2_WriteChunkWithTagsToNAND(struct yaffs_dev* dev, int chunkInNAND,
37 const struct yaffs_ext_tags * tags)
39 struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
40 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
41 struct mtd_oob_ops ops;
47 loff_t addr = ((loff_t) chunkInNAND) * dev->data_bytes_per_chunk;
49 struct yaffs_packed_tags2 pt;
51 yaffs_trace(YAFFS_TRACE_MTD,
52 "nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p",
53 chunkInNAND, data, tags);
55 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
57 yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
59 BUG(); /* both tags and data should always be present */
62 ops.mode = MTD_OOB_AUTO;
63 ops.ooblen = sizeof(pt);
64 ops.len = dev->data_bytes_per_chunk;
66 ops.datbuf = (u8 *)data;
67 ops.oobbuf = (void *)&pt;
68 retval = mtd->write_oob(mtd, addr, &ops);
70 BUG(); /* both tags and data should always be present */
73 yaffs_pack_tags2(&pt, tags);
77 if (dev->param.use_nand_ecc)
79 mtd->write_ecc(mtd, addr, dev->data_bytes_per_chunk,
80 &dummy, data, (u8 *) & pt, NULL);
83 mtd->write_ecc(mtd, addr, dev->data_bytes_per_chunk,
84 &dummy, data, (u8 *) & pt, NULL);
88 mtd->write(mtd, addr, dev->data_bytes_per_chunk, &dummy,
92 mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
104 int nandmtd2_ReadChunkWithTagsFromNAND(struct yaffs_dev * dev, int chunkInNAND,
105 u8 * data, struct yaffs_ext_tags * tags)
107 static u8 *spare_buffer = NULL;
109 struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
110 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
111 struct mtd_oob_ops ops;
116 loff_t addr = ((loff_t) chunkInNAND) * dev->data_bytes_per_chunk;
118 struct yaffs_packed_tags2 pt;
121 spare_buffer = kmalloc(mtd->oobsize, GFP_NOFS);
123 yaffs_trace(YAFFS_TRACE_MTD,
124 "nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p",
125 chunkInNAND, data, tags);
127 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
129 retval = mtd->read(mtd, addr, dev->data_bytes_per_chunk,
132 ops.mode = MTD_OOB_AUTO;
133 ops.ooblen = sizeof(pt);
134 ops.len = data ? dev->data_bytes_per_chunk : sizeof(pt);
137 ops.oobbuf = spare_buffer;
138 retval = mtd->read_oob(mtd, addr, &ops);
142 if (dev->useNANDECC) {
144 mtd->read_ecc(mtd, addr, dev->data_bytes_per_chunk,
145 &dummy, data, dev->spare_buffer,
149 mtd->read_ecc(mtd, addr, dev->data_bytes_per_chunk,
150 &dummy, data, dev->spare_buffer,
156 mtd->read(mtd, addr, dev->data_bytes_per_chunk, &dummy,
160 mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
165 memcpy(&pt, spare_buffer, sizeof(pt));
168 yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
170 if(tags && retval == -EBADMSG && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR)
171 tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
179 int nandmtd2_MarkNANDBlockBad(struct yaffs_dev *dev, int blockNo)
181 struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
184 yaffs_trace(YAFFS_TRACE_MTD,
185 "nandmtd2_MarkNANDBlockBad %d", blockNo);
188 mtd->block_markbad(mtd,
189 blockNo * dev->param.chunks_per_block *
190 dev->data_bytes_per_chunk);
199 int nandmtd2_QueryNANDBlock(struct yaffs_dev *dev, int blockNo,
200 enum yaffs_block_state * state, int *sequenceNumber)
202 struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
205 yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_QueryNANDBlock %d", blockNo);
207 mtd->block_isbad(mtd,
208 blockNo * dev->param.chunks_per_block *
209 dev->data_bytes_per_chunk);
212 yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
214 *state = YAFFS_BLOCK_STATE_DEAD;
217 struct yaffs_ext_tags t;
218 nandmtd2_ReadChunkWithTagsFromNAND(dev,
220 dev->param.chunks_per_block, NULL,
224 *sequenceNumber = t.seq_number;
225 *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
228 *state = YAFFS_BLOCK_STATE_EMPTY;
231 yaffs_trace(YAFFS_TRACE_MTD, "block is bad seq %d state %d", *sequenceNumber, *state);