1/* 2 * YAFFS: Yet another FFS. A NAND-flash specific file system. 3 * yaffs_ramdisk.c: yaffs ram disk component 4 * 5 * Copyright (C) 2002 Aleph One Ltd. 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 15// This provides a YAFFS nand emulation on a file for emulating 2kB pages. 16// THis is only intended as test code to test persistence etc. 17 18const char *yaffs_flashif_c_version = "$Id: yaffs_fileem2k.c,v 1.7 2006/10/13 08:52:49 charles Exp $"; 19 20 21#include "yportenv.h" 22 23#include "yaffs_flashif.h" 24#include "yaffs_guts.h" 25#include "devextras.h" 26 27#include <sys/types.h> 28#include <sys/stat.h> 29#include <fcntl.h> 30#include <unistd.h> 31 32#include "yaffs_fileem2k.h" 33#include "yaffs_packedtags2.h" 34 35 36 37typedef struct 38{ 39 __u8 data[PAGE_SIZE]; // Data + spare 40} yflash_Page; 41 42typedef struct 43{ 44 yflash_Page page[PAGES_PER_BLOCK]; // The pages in the block 45 46} yflash_Block; 47 48 49 50#define MAX_HANDLES 20 51#define BLOCKS_PER_HANDLE 8000 52 53typedef struct 54{ 55 int handle[MAX_HANDLES]; 56 int nBlocks; 57} yflash_Device; 58 59static yflash_Device filedisk; 60 61int yaffs_testPartialWrite = 0; 62 63 64static char *NToName(char *buf,int n) 65{ 66 sprintf(buf,"emfile%d",n); 67 return buf; 68} 69 70static char dummyBuffer[BLOCK_SIZE]; 71 72static int GetBlockFileHandle(int n) 73{ 74 int h; 75 int requiredSize; 76 77 char name[40]; 78 NToName(name,n); 79 int fSize; 80 int i; 81 82 h = open(name, O_RDWR | O_CREAT, S_IREAD | S_IWRITE); 83 if(h >= 0){ 84 fSize = lseek(h,0,SEEK_END); 85 requiredSize = BLOCKS_PER_HANDLE * BLOCK_SIZE; 86 if(fSize < requiredSize){ 87 for(i = 0; i < BLOCKS_PER_HANDLE; i++) 88 if(write(h,dummyBuffer,BLOCK_SIZE) != BLOCK_SIZE) 89 return -1; 90 91 } 92 } 93 94 return h; 95 96} 97 98static int CheckInit(void) 99{ 100 static int initialised = 0; 101 int h; 102 int i; 103 104 105 off_t fSize; 106 off_t requiredSize; 107 int written; 108 int blk; 109 110 yflash_Page p; 111 112 if(initialised) 113 { 114 return YAFFS_OK; 115 } 116 117 initialised = 1; 118 119 memset(dummyBuffer,0xff,sizeof(dummyBuffer)); 120 121 122 filedisk.nBlocks = SIZE_IN_MB * BLOCKS_PER_MB; 123 124 for(i = 0; i < MAX_HANDLES; i++) 125 filedisk.handle[i] = -1; 126 127 for(i = 0,blk = 0; blk < filedisk.nBlocks; blk+=BLOCKS_PER_HANDLE,i++) 128 filedisk.handle[i] = GetBlockFileHandle(i); 129 130 131 return 1; 132} 133 134 135int yflash_GetNumberOfBlocks(void) 136{ 137 CheckInit(); 138 139 return filedisk.nBlocks; 140} 141 142int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags) 143{ 144 int written; 145 int pos; 146 int h; 147 148 CheckInit(); 149 150 151 152 if(data) 153 { 154 pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE; 155 h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))]; 156 157 lseek(h,pos,SEEK_SET); 158 written = write(h,data,dev->nDataBytesPerChunk); 159 160 if(yaffs_testPartialWrite){ 161 close(h); 162 exit(1); 163 } 164 165 if(written != dev->nDataBytesPerChunk) return YAFFS_FAIL; 166 } 167 168 if(tags) 169 { 170 pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE ; 171 h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))]; 172 173 lseek(h,pos,SEEK_SET); 174 if( 0 && dev->isYaffs2) 175 { 176 177 written = write(h,tags,sizeof(yaffs_ExtendedTags)); 178 if(written != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL; 179 } 180 else 181 { 182 yaffs_PackedTags2 pt; 183 yaffs_PackTags2(&pt,tags); 184 185 written = write(h,&pt,sizeof(pt)); 186 if(written != sizeof(pt)) return YAFFS_FAIL; 187 } 188 } 189 190 191 return YAFFS_OK; 192 193} 194 195int yaffs_CheckAllFF(const __u8 *ptr, int n) 196{ 197 while(n) 198 { 199 n--; 200 if(*ptr!=0xFF) return 0; 201 ptr++; 202 } 203 return 1; 204} 205 206 207static int fail300 = 1; 208static int fail320 = 1; 209 210int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags) 211{ 212 int nread; 213 int pos; 214 int h; 215 216 CheckInit(); 217 218 219 220 if(data) 221 { 222 223 pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE; 224 h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))]; 225 lseek(h,pos,SEEK_SET); 226 nread = read(h,data,dev->nDataBytesPerChunk); 227 228 if(nread != dev->nDataBytesPerChunk) return YAFFS_FAIL; 229 } 230 231 if(tags) 232 { 233 pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE; 234 h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))]; 235 lseek(h,pos,SEEK_SET); 236 237 if(0 && dev->isYaffs2) 238 { 239 nread= read(h,tags,sizeof(yaffs_ExtendedTags)); 240 if(nread != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL; 241 if(yaffs_CheckAllFF((__u8 *)tags,sizeof(yaffs_ExtendedTags))) 242 { 243 yaffs_InitialiseTags(tags); 244 } 245 else 246 { 247 tags->chunkUsed = 1; 248 } 249 } 250 else 251 { 252 yaffs_PackedTags2 pt; 253 nread= read(h,&pt,sizeof(pt)); 254 yaffs_UnpackTags2(tags,&pt); 255 if((chunkInNAND >> 6) == 300) { 256 if(fail300 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){ 257 tags->eccResult = YAFFS_ECC_RESULT_FIXED; 258 fail300 = 0; 259 } 260 261 } 262 if((chunkInNAND >> 6) == 320) { 263 if(fail320 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){ 264 tags->eccResult = YAFFS_ECC_RESULT_FIXED; 265 fail320 = 0; 266 } 267 } 268 if(nread != sizeof(pt)) return YAFFS_FAIL; 269 } 270 } 271 272 273 return YAFFS_OK; 274 275} 276 277 278int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) 279{ 280 int written; 281 int h; 282 283 yaffs_PackedTags2 pt; 284 285 CheckInit(); 286 287 memset(&pt,0,sizeof(pt)); 288 h = filedisk.handle[(blockNo / ( BLOCKS_PER_HANDLE))]; 289 lseek(h,((blockNo % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE + PAGE_DATA_SIZE,SEEK_SET); 290 written = write(h,&pt,sizeof(pt)); 291 292 if(written != sizeof(pt)) return YAFFS_FAIL; 293 294 295 return YAFFS_OK; 296 297} 298 299int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) 300{ 301 302 int i; 303 int h; 304 305 CheckInit(); 306 307 if(blockNumber == 320) 308 fail320 = 1; 309 310 if(blockNumber < 0 || blockNumber >= filedisk.nBlocks) 311 { 312 T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber)); 313 return YAFFS_FAIL; 314 } 315 else 316 { 317 318 __u8 pg[PAGE_SIZE]; 319 int syz = PAGE_SIZE; 320 int pos; 321 322 memset(pg,0xff,syz); 323 324 325 h = filedisk.handle[(blockNumber / ( BLOCKS_PER_HANDLE))]; 326 lseek(h,((blockNumber % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE,SEEK_SET); 327 for(i = 0; i < dev->nChunksPerBlock; i++) 328 { 329 write(h,pg,PAGE_SIZE); 330 } 331 pos = lseek(h, 0,SEEK_CUR); 332 333 return YAFFS_OK; 334 } 335 336} 337 338int yflash_InitialiseNAND(yaffs_Device *dev) 339{ 340 CheckInit(); 341 342 return YAFFS_OK; 343} 344 345 346 347 348int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber) 349{ 350 yaffs_ExtendedTags tags; 351 int chunkNo; 352 353 *sequenceNumber = 0; 354 355 chunkNo = blockNo * dev->nChunksPerBlock; 356 357 yflash_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags); 358 if(tags.blockBad) 359 { 360 *state = YAFFS_BLOCK_STATE_DEAD; 361 } 362 else if(!tags.chunkUsed) 363 { 364 *state = YAFFS_BLOCK_STATE_EMPTY; 365 } 366 else if(tags.chunkUsed) 367 { 368 *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; 369 *sequenceNumber = tags.sequenceNumber; 370 } 371 return YAFFS_OK; 372} 373 374