yaffs Added more tests to direct/timothy_tests/quick_tests
[yaffs2.git] / direct / basic-test / yramsim.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2010 Aleph One Ltd.
5  *   for Toby Churchill Ltd and Brightstar Engineering
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  * NAND Simulator for testing YAFFS
16  */
17
18 #include <string.h>
19
20 #include "yramsim.h"
21
22 #include "yaffs_nandif.h"
23
24
25 #define DATA_SIZE       2048
26 #define SPARE_SIZE      64
27 #define PAGE_SIZE       (DATA_SIZE + SPARE_SIZE)
28 #define PAGES_PER_BLOCK 64
29
30
31 typedef struct {
32         unsigned char page[PAGES_PER_BLOCK][PAGE_SIZE];
33         unsigned blockOk;
34 } Block;
35
36 typedef struct {
37         Block **blockList;
38         int nBlocks;
39 } SimData;
40
41
42 SimData *simDevs[N_RAM_SIM_DEVS];
43
44 static SimData *DevToSim(struct yaffs_dev *dev)
45 {
46         ynandif_Geometry *geom = (ynandif_Geometry *)(dev->driver_context);
47         SimData * sim = (SimData*)(geom->privateData);
48         return sim;
49 }
50
51
52 static void CheckInitialised(void)
53 {
54
55 }
56
57 static int yramsim_erase_internal(SimData *sim, unsigned blockId,int force)
58 {
59         if(blockId < 0 || blockId >= sim->nBlocks){
60                 return 0;
61         }
62
63         if(!sim->blockList[blockId]){
64                 return 0;
65         }
66
67         if(!force && !sim->blockList[blockId]->blockOk){
68                 return 0;
69         }
70
71         memset(sim->blockList[blockId],0xff,sizeof(Block));
72         sim->blockList[blockId]->blockOk = 1;
73
74         return 1;
75 }
76
77
78
79
80 static int yramsim_initialise(struct yaffs_dev *dev)
81 {
82         SimData *sim = DevToSim(dev);
83         Block **blockList = sim->blockList;
84         return blockList != NULL;
85 }
86
87
88 static int yramsim_deinitialise(struct yaffs_dev *dev)
89 {
90         return 1;
91 }
92
93 static int yramsim_rd_chunk (struct yaffs_dev *dev, unsigned pageId,
94                                           unsigned char *data, unsigned dataLength,
95                                           unsigned char *spare, unsigned spareLength,
96                                           int *eccStatus)
97 {
98         SimData *sim = DevToSim(dev);
99         Block **blockList = sim->blockList;
100
101         unsigned blockId = pageId / PAGES_PER_BLOCK;
102         unsigned pageOffset = pageId % PAGES_PER_BLOCK;
103         unsigned char * d;
104         unsigned char *s;
105         if(blockId >= sim->nBlocks ||
106            pageOffset >= PAGES_PER_BLOCK ||
107            dataLength >DATA_SIZE ||
108            spareLength > SPARE_SIZE ||
109            !eccStatus ||
110            !blockList[blockId]->blockOk){
111                    return 0;
112         }
113
114         d = blockList[blockId]->page[pageOffset];
115         s = d + DATA_SIZE;
116
117         if(data)
118                 memcpy(data,d,dataLength);
119
120         if(spare)
121                 memcpy(spare,s,spareLength);
122
123         *eccStatus = 0; // 0 = no error, -1 = unfixable error, 1 = fixable
124
125         return 1;
126 }
127
128 static int yramsim_wr_chunk (struct yaffs_dev *dev,unsigned pageId,
129                                            const unsigned char *data, unsigned dataLength,
130                                            const unsigned char *spare, unsigned spareLength)
131 {
132         SimData *sim = DevToSim(dev);
133         Block **blockList = sim->blockList;
134
135         unsigned blockId = pageId / PAGES_PER_BLOCK;
136         unsigned pageOffset = pageId % PAGES_PER_BLOCK;
137         unsigned char * d;
138         unsigned char *s;
139         if(blockId >= sim->nBlocks ||
140            pageOffset >= PAGES_PER_BLOCK ||
141            dataLength >DATA_SIZE ||
142            spareLength > SPARE_SIZE ||
143            !blockList[blockId]->blockOk){
144                    return 0;
145         }
146
147         d = blockList[blockId]->page[pageOffset];
148         s = d + DATA_SIZE;
149
150         if(data)
151                 memcpy(d,data,dataLength);
152
153         if(spare)
154                 memcpy(s,spare,spareLength);
155
156         return 1;
157 }
158
159
160 static int yramsim_erase(struct yaffs_dev *dev,unsigned blockId)
161 {
162         SimData *sim = DevToSim(dev);
163
164         CheckInitialised();
165         return yramsim_erase_internal(sim,blockId,0);
166 }
167
168 static int yramsim_check_block_ok(struct yaffs_dev *dev,unsigned blockId)
169 {
170         SimData *sim = DevToSim(dev);
171         Block **blockList = sim->blockList;
172         if(blockId >= sim->nBlocks){
173                 return 0;
174         }
175
176         return blockList[blockId]->blockOk ? 1 : 0;
177 }
178
179 static int yramsim_mark_block_bad(struct yaffs_dev *dev,unsigned blockId)
180 {
181         SimData *sim = DevToSim(dev);
182         Block **blockList = sim->blockList;
183         if(blockId >= sim->nBlocks){
184                 return 0;
185         }
186
187         blockList[blockId]->blockOk = 0;
188
189         return 1;
190 }
191
192
193 static SimData *yramsim_alloc_sim_data(u32 devId, u32 nBlocks)
194 {
195         int ok = 1;
196
197         Block **blockList;
198         SimData *sim;
199         Block *b;
200         u32 i;
201
202         if(devId >= N_RAM_SIM_DEVS)
203                 return NULL;
204
205         sim = simDevs[devId];
206
207         if(sim)
208                 return sim;
209
210         sim = malloc(sizeof (SimData));
211         if(!sim)
212                 return NULL;
213
214         simDevs[devId] = sim;
215
216         blockList = malloc(nBlocks * sizeof(Block *));
217
218         sim->blockList = blockList;
219         sim->nBlocks = nBlocks;
220         if(!blockList){
221                 free(sim);
222                 return NULL;
223         }
224
225         for(i = 0; i < nBlocks; i++)
226                 blockList[i] = NULL;
227
228         for(i = 0; i < nBlocks && ok; i++){
229                 b=  malloc(sizeof(Block));
230                 if(b){
231                         blockList[i] = b;
232                         yramsim_erase_internal(sim,i,1);
233                 }
234                 else
235                         ok = 0;
236         }
237
238         if(!ok){
239                 for(i = 0; i < nBlocks; i++)
240                         if(blockList[i]){
241                                 free(blockList[i]);
242                                 blockList[i] = NULL;
243                         }
244                 free(blockList);
245                 blockList = NULL;
246                 free(sim);
247                 sim = NULL;
248         }
249
250         return sim;
251 }
252
253
254 struct yaffs_dev *yramsim_CreateRamSim(const YCHAR *name,
255                                 u32 devId, u32 nBlocks,
256                                 u32 start_block, u32 end_block)
257 {
258         SimData *sim;
259         ynandif_Geometry *g;
260
261         sim = yramsim_alloc_sim_data(devId, nBlocks);
262
263         g = YMALLOC(sizeof(ynandif_Geometry));
264
265         if(!sim || !g){
266                 if(g)
267                         YFREE(g);
268                 return NULL;
269         }
270
271         if(start_block >= sim->nBlocks)
272                 start_block = 0;
273         if(end_block == 0 || end_block >= sim->nBlocks)
274                 end_block = sim->nBlocks - 1;
275
276         memset(g,0,sizeof(ynandif_Geometry));
277         g->start_block = start_block;
278         g->end_block = end_block;
279         g->dataSize = DATA_SIZE;
280         g->spareSize= SPARE_SIZE;
281         g->pagesPerBlock = PAGES_PER_BLOCK;
282         g->hasECC = 1;
283         g->inband_tags = 0;
284         g->useYaffs2 = 1;
285         g->initialise = yramsim_initialise;
286         g->deinitialise = yramsim_deinitialise;
287         g->readChunk = yramsim_rd_chunk,
288         g->writeChunk = yramsim_wr_chunk,
289         g->eraseBlock = yramsim_erase,
290         g->checkBlockOk = yramsim_check_block_ok,
291         g->markBlockBad = yramsim_mark_block_bad,
292         g->privateData = (void *)sim;
293
294         return yaffs_add_dev_from_geometry(name,g);
295 }