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 "asm/errno.h"
  19
  20const char *yaffs_mtdif2_c_version =
  21    "$Id: yaffs_mtdif2.c,v 1.17 2007/02/14 01:09:06 wookey Exp $";
  22
  23#include "yportenv.h"
  24
  25
  26#include "yaffs_mtdif2.h"
  27
  28#include "linux/mtd/mtd.h"
  29#include "linux/types.h"
  30#include "linux/time.h"
  31
  32#include "yaffs_packedtags2.h"
  33
  34int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
  35                                      const __u8 * data,
  36                                      const yaffs_ExtendedTags * tags)
  37{
  38        struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
  39#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
  40        struct mtd_oob_ops ops;
  41#else
  42        size_t dummy;
  43#endif
  44        int retval = 0;
  45
  46        loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
  47
  48        yaffs_PackedTags2 pt;
  49
  50        T(YAFFS_TRACE_MTD,
  51          (TSTR
  52           ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
  53            TENDSTR), chunkInNAND, data, tags));
  54
  55#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
  56        if (tags)
  57                yaffs_PackTags2(&pt, tags);
  58        else
  59                BUG(); /* both tags and data should always be present */
  60
  61        if (data) {
  62                ops.mode = MTD_OOB_AUTO;
  63                ops.ooblen = sizeof(pt);
  64                ops.len = dev->nDataBytesPerChunk;
  65                ops.ooboffs = 0;
  66                ops.datbuf = (__u8 *)data;
  67                ops.oobbuf = (void *)&pt;
  68                retval = mtd->write_oob(mtd, addr, &ops);
  69        } else
  70                BUG(); /* both tags and data should always be present */
  71#else
  72        if (tags) {
  73                yaffs_PackTags2(&pt, tags);
  74        }
  75
  76        if (data && tags) {
  77                if (dev->useNANDECC)
  78                        retval =
  79                            mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
  80                                           &dummy, data, (__u8 *) & pt, NULL);
  81                else
  82                        retval =
  83                            mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
  84                                           &dummy, data, (__u8 *) & pt, NULL);
  85        } else {
  86                if (data)
  87                        retval =
  88                            mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
  89                                       data);
  90                if (tags)
  91                        retval =
  92                            mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
  93                                           (__u8 *) & pt);
  94
  95        }
  96#endif
  97
  98        if (retval == 0)
  99                return YAFFS_OK;
 100        else
 101                return YAFFS_FAIL;
 102}
 103
 104int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
 105                                       __u8 * data, yaffs_ExtendedTags * tags)
 106{
 107        struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
 108#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
 109        struct mtd_oob_ops ops;
 110#endif
 111        size_t dummy;
 112        int retval = 0;
 113
 114        loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
 115
 116        yaffs_PackedTags2 pt;
 117
 118        T(YAFFS_TRACE_MTD,
 119          (TSTR
 120           ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
 121            TENDSTR), chunkInNAND, data, tags));
 122
 123#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
 124        if (data && !tags)
 125                retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
 126                                &dummy, data);
 127        else if (tags) {
 128                ops.mode = MTD_OOB_AUTO;
 129                ops.ooblen = sizeof(pt);
 130                ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
 131                ops.ooboffs = 0;
 132                ops.datbuf = data;
 133                ops.oobbuf = dev->spareBuffer;
 134                retval = mtd->read_oob(mtd, addr, &ops);
 135        }
 136#else
 137        if (data && tags) {
 138                if (dev->useNANDECC) {
 139                        retval =
 140                            mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
 141                                          &dummy, data, dev->spareBuffer,
 142                                          NULL);
 143                } else {
 144                        retval =
 145                            mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
 146                                          &dummy, data, dev->spareBuffer,
 147                                          NULL);
 148                }
 149        } else {
 150                if (data)
 151                        retval =
 152                            mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
 153                                      data);
 154                if (tags)
 155                        retval =
 156                            mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
 157                                          dev->spareBuffer);
 158        }
 159#endif
 160
 161        memcpy(&pt, dev->spareBuffer, sizeof(pt));
 162
 163        if (tags)
 164                yaffs_UnpackTags2(tags, &pt);
 165
 166        if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
 167                tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
 168
 169        if (retval == 0)
 170                return YAFFS_OK;
 171        else
 172                return YAFFS_FAIL;
 173}
 174
 175int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
 176{
 177        struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
 178        int retval;
 179        T(YAFFS_TRACE_MTD,
 180          (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
 181
 182        retval =
 183            mtd->block_markbad(mtd,
 184                               blockNo * dev->nChunksPerBlock *
 185                               dev->nDataBytesPerChunk);
 186
 187        if (retval == 0)
 188                return YAFFS_OK;
 189        else
 190                return YAFFS_FAIL;
 191
 192}
 193
 194int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
 195                            yaffs_BlockState * state, int *sequenceNumber)
 196{
 197        struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
 198        int retval;
 199
 200        T(YAFFS_TRACE_MTD,
 201          (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
 202        retval =
 203            mtd->block_isbad(mtd,
 204                             blockNo * dev->nChunksPerBlock *
 205                             dev->nDataBytesPerChunk);
 206
 207        if (retval) {
 208                T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
 209
 210                *state = YAFFS_BLOCK_STATE_DEAD;
 211                *sequenceNumber = 0;
 212        } else {
 213                yaffs_ExtendedTags t;
 214                nandmtd2_ReadChunkWithTagsFromNAND(dev,
 215                                                   blockNo *
 216                                                   dev->nChunksPerBlock, NULL,
 217                                                   &t);
 218
 219                if (t.chunkUsed) {
 220                        *sequenceNumber = t.sequenceNumber;
 221                        *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
 222                } else {
 223                        *sequenceNumber = 0;
 224                        *state = YAFFS_BLOCK_STATE_EMPTY;
 225                }
 226        }
 227        T(YAFFS_TRACE_MTD,
 228          (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
 229           *state));
 230
 231        if (retval == 0)
 232                return YAFFS_OK;
 233        else
 234                return YAFFS_FAIL;
 235}
 236