1 /* 2 * YAFFS: Yet another FFS. A NAND-flash specific file system. 3 * yaffs_ramem.c NAND emulation on top of a chunk of RAM 4 * 5 * Copyright (C) 2002 Aleph One Ltd. 6 * for Toby Churchill Ltd and Brightstar Engineering 7 * 8 * Created by Charles Manning <charles (at) aleph1.co.uk> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 * 14 */ 15 //yaffs_ramem2k.c: RAM emulation in-kernel for 2K pages (YAFFS2) 16 17 18 const char *yaffs_ramem2k_c_version = "$Id: yaffs_ramem2k.c,v 1.1 2005/08/09 01:00:37 charles Exp $"; 19 20 #ifndef __KERNEL__ 21 #define CONFIG_YAFFS_RAM_ENABLED 22 #else 23 #include <linux/config.h> 24 #endif 25 26 #ifdef CONFIG_YAFFS_RAM_ENABLED 27 28 #include "yportenv.h" 29 30 #include "yaffs_nandemul2k.h" 31 #include "yaffs_guts.h" 32 #include "yaffsinterface.h" 33 #include "devextras.h" 34 #include "yaffs_packedtags2.h" 35 36 37 38 #define EM_SIZE_IN_MEG (32) 39 #define PAGE_DATA_SIZE (2048) 40 #define PAGE_SPARE_SIZE (64) 41 #define PAGES_PER_BLOCK (64) 42 43 44 45 #define EM_SIZE_IN_BYTES (EM_SIZE_IN_MEG * (1<<20)) 46 47 #define PAGE_TOTAL_SIZE (PAGE_DATA_SIZE+PAGE_SPARE_SIZE) 48 49 #define BLOCK_TOTAL_SIZE (PAGES_PER_BLOCK * PAGE_TOTAL_SIZE) 50 51 #define BLOCKS_PER_MEG ((1<<20)/(PAGES_PER_BLOCK * PAGE_DATA_SIZE)) 52 53 54 typedef struct 55 { 56 __u8 data[PAGE_TOTAL_SIZE]; // Data + spare 57 int empty; // is this empty? 58 } nandemul_Page; 59 60 61 typedef struct 62 { 63 nandemul_Page *page[PAGES_PER_BLOCK]; 64 int damaged; 65 } nandemul_Block; 66 67 68 69 typedef struct 70 { 71 nandemul_Block**block; 72 int nBlocks; 73 } nandemul_Device; 74 75 static nandemul_Device ned; 76 77 static int sizeInMB = EM_SIZE_IN_MEG; 78 79 80 static void nandemul_yield(int n) 81 { 82 #ifdef __KERNEL__ 83 if(n > 0) schedule_timeout(n); 84 #endif 85 86 } 87 88 89 static void nandemul_ReallyEraseBlock(int blockNumber) 90 { 91 int i; 92 93 nandemul_Block *blk; 94 95 if(blockNumber < 0 || blockNumber >= ned.nBlocks) 96 { 97 return; 98 } 99 100 blk = ned.block[blockNumber]; 101 102 for(i = 0; i < PAGES_PER_BLOCK; i++) 103 { 104 memset(blk->page[i],0xff,sizeof(nandemul_Page)); 105 blk->page[i]->empty = 1; 106 } 107 nandemul_yield(2); 108 } 109 110 111 static int nandemul2k_CalcNBlocks(void) 112 { 113 return EM_SIZE_IN_MEG * BLOCKS_PER_MEG; 114 } 115 116 117 118 static int CheckInit(void) 119 { 120 static int initialised = 0; 121 122 int i,j; 123 124 int fail = 0; 125 int nBlocks; 126 127 int nAllocated = 0; 128 129 if(initialised) 130 { 131 return YAFFS_OK; 132 } 133 134 135 ned.nBlocks = nBlocks = nandemul2k_CalcNBlocks(); 136 137 138 ned.block = YMALLOC(sizeof(nandemul_Block*) * nBlocks ); 139 140 if(!ned.block) return YAFFS_FAIL; 141 142 143 144 145 146 for(i=fail=0; i <nBlocks; i++) 147 { 148 149 nandemul_Block *blk; 150 151 if(!(blk = ned.block[i] = YMALLOC(sizeof(nandemul_Block)))) 152 { 153 fail = 1; 154 } 155 else 156 { 157 for(j = 0; j < PAGES_PER_BLOCK; j++) 158 { 159 if((blk->page[j] = YMALLOC(sizeof(nandemul_Page))) == 0) 160 { 161 fail = 1; 162 } 163 } 164 nandemul_ReallyEraseBlock(i); 165 ned.block[i]->damaged = 0; 166 nAllocated++; 167 } 168 } 169 170 if(fail) 171 { 172 //Todo thump pages 173 174 for(i = 0; i < nAllocated; i++) 175 { 176 YFREE(ned.block[i]); 177 } 178 YFREE(ned.block); 179 180 T(YAFFS_TRACE_ALWAYS,("Allocation failed, could only allocate %dMB of %dMB requested.\n", 181 nAllocated/64,sizeInMB)); 182 return 0; 183 } 184 185 ned.nBlocks = nBlocks; 186 187 initialised = 1; 188 189 return 1; 190 } 191 192 int nandemul2k_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags) 193 { 194 int blk; 195 int pg; 196 int i; 197 198 __u8 *x; 199 200 201 blk = chunkInNAND/PAGES_PER_BLOCK; 202 pg = chunkInNAND%PAGES_PER_BLOCK; 203 204 205 if(data) 206 { 207 x = ned.block[blk]->page[pg]->data; 208 209 for(i = 0; i < PAGE_DATA_SIZE; i++) 210 { 211 x[i] &=data[i]; 212 } 213 214 ned.block[blk]->page[pg]->empty = 0; 215 } 216 217 218 if(tags) 219 { 220 x = &ned.block[blk]->page[pg]->data[PAGE_DATA_SIZE]; 221 222 yaffs_PackTags2((yaffs_PackedTags2 *)x,tags); 223 224 } 225 226 if(tags || data) 227 { 228 nandemul_yield(1); 229 } 230 231 return YAFFS_OK; 232 } 233 234 235 int nandemul2k_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags) 236 { 237 int blk; 238 int pg; 239 240 __u8 *x; 241 242 243 244 blk = chunkInNAND/PAGES_PER_BLOCK; 245 pg = chunkInNAND%PAGES_PER_BLOCK; 246 247 248 if(data) 249 { 250 memcpy(data,ned.block[blk]->page[pg]->data,PAGE_DATA_SIZE); 251 } 252 253 254 if(tags) 255 { 256 x = &ned.block[blk]->page[pg]->data[PAGE_DATA_SIZE]; 257 258 yaffs_UnpackTags2(tags,(yaffs_PackedTags2 *)x); 259 } 260 261 return YAFFS_OK; 262 } 263 264 265 static int nandemul2k_CheckChunkErased(yaffs_Device *dev,int chunkInNAND) 266 { 267 int blk; 268 int pg; 269 int i; 270 271 272 273 blk = chunkInNAND/PAGES_PER_BLOCK; 274 pg = chunkInNAND%PAGES_PER_BLOCK; 275 276 277 for(i = 0; i < PAGE_TOTAL_SIZE; i++) 278 { 279 if(ned.block[blk]->page[pg]->data[i] != 0xFF) 280 { 281 return YAFFS_FAIL; 282 } 283 } 284 285 return YAFFS_OK; 286 287 } 288 289 int nandemul2k_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) 290 { 291 292 293 if(blockNumber < 0 || blockNumber >= ned.nBlocks) 294 { 295 T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber)); 296 } 297 else if(ned.block[blockNumber]->damaged) 298 { 299 T(YAFFS_TRACE_ALWAYS,("Attempt to erase damaged block %d\n",blockNumber)); 300 } 301 else 302 { 303 nandemul_ReallyEraseBlock(blockNumber); 304 } 305 306 return YAFFS_OK; 307 } 308 309 int nandemul2k_InitialiseNAND(yaffs_Device *dev) 310 { 311 CheckInit(); 312 return YAFFS_OK; 313 } 314 315 int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) 316 { 317 318 __u8 *x; 319 320 x = &ned.block[blockNo]->page[0]->data[PAGE_DATA_SIZE]; 321 322 memset(x,0,sizeof(yaffs_PackedTags2)); 323 324 325 return YAFFS_OK; 326 327 } 328 329 int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber) 330 { 331 yaffs_ExtendedTags tags; 332 int chunkNo; 333 334 *sequenceNumber = 0; 335 336 chunkNo = blockNo * dev->nChunksPerBlock; 337 338 nandemul2k_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags); 339 if(tags.blockBad) 340 { 341 *state = YAFFS_BLOCK_STATE_DEAD; 342 } 343 else if(!tags.chunkUsed) 344 { 345 *state = YAFFS_BLOCK_STATE_EMPTY; 346 } 347 else if(tags.chunkUsed) 348 { 349 *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; 350 *sequenceNumber = tags.sequenceNumber; 351 } 352 return YAFFS_OK; 353 } 354 355 int nandemul2k_GetBytesPerChunk(void) { return PAGE_DATA_SIZE;} 356 357 int nandemul2k_GetChunksPerBlock(void) { return PAGES_PER_BLOCK; } 358 int nandemul2k_GetNumberOfBlocks(void) {return nandemul2k_CalcNBlocks();} 359 360 361 #endif //YAFFS_RAM_ENABLED 362 363