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