• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 
nandemul_yield(int n)80 static void nandemul_yield(int n)
81 {
82 #ifdef __KERNEL__
83 	if(n > 0) schedule_timeout(n);
84 #endif
85 
86 }
87 
88 
nandemul_ReallyEraseBlock(int blockNumber)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 
nandemul2k_CalcNBlocks(void)111 static int nandemul2k_CalcNBlocks(void)
112 {
113 	return EM_SIZE_IN_MEG * BLOCKS_PER_MEG;
114 }
115 
116 
117 
CheckInit(void)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 
nandemul2k_WriteChunkWithTagsToNAND(yaffs_Device * dev,int chunkInNAND,const __u8 * data,yaffs_ExtendedTags * tags)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 
nandemul2k_ReadChunkWithTagsFromNAND(yaffs_Device * dev,int chunkInNAND,__u8 * data,yaffs_ExtendedTags * tags)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 
nandemul2k_CheckChunkErased(yaffs_Device * dev,int chunkInNAND)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 
nandemul2k_EraseBlockInNAND(yaffs_Device * dev,int blockNumber)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 
nandemul2k_InitialiseNAND(yaffs_Device * dev)309 int nandemul2k_InitialiseNAND(yaffs_Device *dev)
310 {
311 	CheckInit();
312 	return YAFFS_OK;
313 }
314 
nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct * dev,int blockNo)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 
nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct * dev,int blockNo,yaffs_BlockState * state,int * sequenceNumber)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 
nandemul2k_GetBytesPerChunk(void)355 int nandemul2k_GetBytesPerChunk(void) { return PAGE_DATA_SIZE;}
356 
nandemul2k_GetChunksPerBlock(void)357 int nandemul2k_GetChunksPerBlock(void) { return PAGES_PER_BLOCK; }
nandemul2k_GetNumberOfBlocks(void)358 int nandemul2k_GetNumberOfBlocks(void) {return nandemul2k_CalcNBlocks();}
359 
360 
361 #endif //YAFFS_RAM_ENABLED
362 
363