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