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 20 const 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 34 int 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 104 int 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 175 int 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 194 int 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