uboot/fs/yaffs2/yaffs_mtdif2.c
<<
>>
Prefs
   1/*
   2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
   3 *
   4 * Copyright (C) 2002-2007 Aleph One Ltd.
   5 *   for Toby Churchill Ltd and Brightstar Engineering
   6 *
   7 * Created by Charles Manning <charles@aleph1.co.uk>
   8 *
   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.
  12 */
  13
  14/* mtd interface for YAFFS2 */
  15
  16/* XXX U-BOOT XXX */
  17#include <common.h>
  18#include <linux/bug.h>
  19#include <linux/errno.h>
  20
  21#include "yportenv.h"
  22#include "yaffs_trace.h"
  23
  24#include "yaffs_mtdif2.h"
  25
  26#include <linux/mtd/mtd.h>
  27#include <linux/types.h>
  28#include <linux/time.h>
  29
  30#include "yaffs_trace.h"
  31#include "yaffs_packedtags2.h"
  32
  33#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
  34#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context))
  35
  36
  37/* NB For use with inband tags....
  38 * We assume that the data buffer is of size total_bytes_per_chunk so
  39 * that we can also use it to load the tags.
  40 */
  41int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
  42                              const u8 *data,
  43                              const struct yaffs_ext_tags *tags)
  44{
  45        struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
  46        struct mtd_oob_ops ops;
  47
  48        int retval = 0;
  49        loff_t addr;
  50
  51        struct yaffs_packed_tags2 pt;
  52
  53        int packed_tags_size =
  54            dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
  55        void *packed_tags_ptr =
  56            dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
  57
  58        yaffs_trace(YAFFS_TRACE_MTD,
  59                "nandmtd2_write_chunk_tags chunk %d data %p tags %p",
  60                nand_chunk, data, tags);
  61
  62        addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
  63
  64        /* For yaffs2 writing there must be both data and tags.
  65         * If we're using inband tags, then the tags are stuffed into
  66         * the end of the data buffer.
  67         */
  68        if (!data || !tags)
  69                BUG();
  70        else if (dev->param.inband_tags) {
  71                struct yaffs_packed_tags2_tags_only *pt2tp;
  72                pt2tp =
  73                    (struct yaffs_packed_tags2_tags_only *)(data +
  74                                                        dev->
  75                                                        data_bytes_per_chunk);
  76                yaffs_pack_tags2_tags_only(pt2tp, tags);
  77        } else {
  78                yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
  79        }
  80
  81        ops.mode = MTD_OPS_AUTO_OOB;
  82        ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
  83        ops.len = dev->param.total_bytes_per_chunk;
  84        ops.ooboffs = 0;
  85        ops.datbuf = (u8 *) data;
  86        ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
  87        retval = mtd_write_oob(mtd, addr, &ops);
  88
  89        if (retval == 0)
  90                return YAFFS_OK;
  91        else
  92                return YAFFS_FAIL;
  93}
  94
  95int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
  96                             u8 *data, struct yaffs_ext_tags *tags)
  97{
  98        struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
  99        u8 local_spare[128];
 100        struct mtd_oob_ops ops;
 101        size_t dummy;
 102        int retval = 0;
 103        int local_data = 0;
 104        struct yaffs_packed_tags2 pt;
 105        loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
 106        int packed_tags_size =
 107            dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
 108        void *packed_tags_ptr =
 109            dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
 110
 111        yaffs_trace(YAFFS_TRACE_MTD,
 112                "nandmtd2_read_chunk_tags chunk %d data %p tags %p",
 113                nand_chunk, data, tags);
 114
 115        if (dev->param.inband_tags) {
 116
 117                if (!data) {
 118                        local_data = 1;
 119                        data = yaffs_get_temp_buffer(dev);
 120                }
 121
 122        }
 123
 124        if (dev->param.inband_tags || (data && !tags))
 125                retval = mtd_read(mtd, addr, dev->param.total_bytes_per_chunk,
 126                                   &dummy, data);
 127        else if (tags) {
 128                ops.mode = MTD_OPS_AUTO_OOB;
 129                ops.ooblen = packed_tags_size;
 130                ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
 131                ops.ooboffs = 0;
 132                ops.datbuf = data;
 133                ops.oobbuf = local_spare;
 134                retval = mtd_read_oob(mtd, addr, &ops);
 135        }
 136
 137        if (dev->param.inband_tags) {
 138                if (tags) {
 139                        struct yaffs_packed_tags2_tags_only *pt2tp;
 140                        pt2tp =
 141                                (struct yaffs_packed_tags2_tags_only *)
 142                                &data[dev->data_bytes_per_chunk];
 143                        yaffs_unpack_tags2_tags_only(tags, pt2tp);
 144                }
 145        } else {
 146                if (tags) {
 147                        memcpy(packed_tags_ptr,
 148                               local_spare,
 149                               packed_tags_size);
 150                        yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
 151                }
 152        }
 153
 154        if (local_data)
 155                yaffs_release_temp_buffer(dev, data);
 156
 157        if (tags && retval == -EBADMSG
 158            && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
 159                tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
 160                dev->n_ecc_unfixed++;
 161        }
 162        if (tags && retval == -EUCLEAN
 163            && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
 164                tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
 165                dev->n_ecc_fixed++;
 166        }
 167        if (retval == 0)
 168                return YAFFS_OK;
 169        else
 170                return YAFFS_FAIL;
 171}
 172
 173
 174int nandmtd2_MarkNANDBlockBad(struct yaffs_dev *dev, int blockNo)
 175{
 176        struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
 177        int retval;
 178
 179        yaffs_trace(YAFFS_TRACE_MTD,
 180                "nandmtd2_MarkNANDBlockBad %d", blockNo);
 181
 182        retval =
 183            mtd_block_markbad(mtd,
 184                               blockNo * dev->param.chunks_per_block *
 185                               dev->data_bytes_per_chunk);
 186
 187        if (retval == 0)
 188                return YAFFS_OK;
 189        else
 190                return YAFFS_FAIL;
 191
 192}
 193
 194int nandmtd2_QueryNANDBlock(struct yaffs_dev *dev, int blockNo,
 195                            enum yaffs_block_state *state, u32 *sequenceNumber)
 196{
 197        struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
 198        int retval;
 199
 200        yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_QueryNANDBlock %d", blockNo);
 201        retval =
 202            mtd_block_isbad(mtd,
 203                             blockNo * dev->param.chunks_per_block *
 204                             dev->data_bytes_per_chunk);
 205
 206        if (retval) {
 207                yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
 208
 209                *state = YAFFS_BLOCK_STATE_DEAD;
 210                *sequenceNumber = 0;
 211        } else {
 212                struct yaffs_ext_tags t;
 213                nandmtd2_read_chunk_tags(dev,
 214                                           blockNo *
 215                                           dev->param.chunks_per_block, NULL,
 216                                           &t);
 217
 218                if (t.chunk_used) {
 219                        *sequenceNumber = t.seq_number;
 220                        *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
 221                } else {
 222                        *sequenceNumber = 0;
 223                        *state = YAFFS_BLOCK_STATE_EMPTY;
 224                }
 225        }
 226        yaffs_trace(YAFFS_TRACE_MTD, "block is bad seq %d state %d",
 227                        *sequenceNumber, *state);
 228
 229        if (retval == 0)
 230                return YAFFS_OK;
 231        else
 232                return YAFFS_FAIL;
 233}
 234