X-Git-Url: http://aleph1.co.uk/gitweb/?a=blobdiff_plain;f=yaffs_tagsmarshall.c;fp=yaffs_tagsmarshall.c;h=bbc228bb87f8d097ce53aa702d82fdbca2b91541;hb=9c99932eb16ba64c6d3ba69145fe8c5d5b04274d;hp=0000000000000000000000000000000000000000;hpb=4b745e6080b0e0283e1e2f1de044760a8245e227;p=yaffs2.git 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; + +}