Home | History | Annotate | Download | only in direct
      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