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