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