Further extensions for VxWorks wrapper
[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
19 #include "yramsim.h"
20
21 #include "yaffs_guts.h"
22 #include <string.h>
23
24
25
26 #define DATA_SIZE       2048
27 #define SPARE_SIZE      64
28 #define PAGE_SIZE       (DATA_SIZE + SPARE_SIZE)
29 #define PAGES_PER_BLOCK 64
30
31
32 typedef struct {
33         unsigned char page[PAGES_PER_BLOCK][PAGE_SIZE];
34         unsigned blockOk;
35 } Block;
36
37 typedef struct {
38         Block **blockList;
39         int nBlocks;
40 } SimData;
41
42
43 SimData *simDevs[N_RAM_SIM_DEVS];
44
45 static SimData *DevToSim(struct yaffs_dev *dev)
46 {
47         return (SimData*)(dev->driver_context);
48 }
49
50
51 static void CheckInitialised(void)
52 {
53
54 }
55
56 static int yramsim_erase_internal(SimData *sim, unsigned blockId,int force)
57 {
58         if(blockId < 0 || blockId >= sim->nBlocks){
59                 return 0;
60         }
61
62         if(!sim->blockList[blockId]){
63                 return 0;
64         }
65
66         if(!force && !sim->blockList[blockId]->blockOk){
67                 return 0;
68         }
69
70         memset(sim->blockList[blockId],0xff,sizeof(Block));
71         sim->blockList[blockId]->blockOk = 1;
72
73         return 1;
74 }
75
76
77
78
79 static int yramsim_initialise(struct yaffs_dev *dev)
80 {
81         SimData *sim = DevToSim(dev);
82         Block **blockList = sim->blockList;
83         return blockList != NULL;
84 }
85
86
87 static int yramsim_deinitialise(struct yaffs_dev *dev)
88 {
89         return 1;
90 }
91
92 static int yramsim_rd_chunk (struct yaffs_dev *dev, int pageId,
93                                           u8 *data, int dataLength,
94                                           u8 *spare, int spareLength,
95                                           enum yaffs_ecc_result *ecc_result)
96 {
97         SimData *sim = DevToSim(dev);
98         Block **blockList = sim->blockList;
99
100         unsigned blockId = pageId / PAGES_PER_BLOCK;
101         unsigned pageOffset = pageId % PAGES_PER_BLOCK;
102         unsigned char * d;
103         unsigned char *s;
104         if(blockId >= sim->nBlocks ||
105            pageOffset >= PAGES_PER_BLOCK ||
106            dataLength >DATA_SIZE ||
107            spareLength > SPARE_SIZE ||
108            !blockList[blockId]->blockOk){
109                    return YAFFS_FAIL;
110         }
111
112         d = blockList[blockId]->page[pageOffset];
113         s = d + DATA_SIZE;
114
115         if(data)
116                 memcpy(data,d,dataLength);
117
118         if(spare)
119                 memcpy(spare,s,spareLength);
120
121         if (ecc_result) 
122                 *ecc_result  = YAFFS_ECC_RESULT_NO_ERROR;
123
124         return YAFFS_OK;
125 }
126
127 static int yramsim_wr_chunk (struct yaffs_dev *dev, int pageId,
128                                            const u8 *data, int dataLength,
129                                            const u8 *spare, int spareLength)
130 {
131         SimData *sim = DevToSim(dev);
132         Block **blockList = sim->blockList;
133
134         unsigned blockId = pageId / PAGES_PER_BLOCK;
135         unsigned pageOffset = pageId % PAGES_PER_BLOCK;
136         unsigned char * d;
137         unsigned char *s;
138         if(blockId >= sim->nBlocks ||
139            pageOffset >= PAGES_PER_BLOCK ||
140            dataLength >DATA_SIZE ||
141            spareLength > SPARE_SIZE ||
142            !blockList[blockId]->blockOk){
143                    return YAFFS_FAIL;
144         }
145
146         d = blockList[blockId]->page[pageOffset];
147         s = d + DATA_SIZE;
148
149         if(data)
150                 memcpy(d,data,dataLength);
151
152         if(spare)
153                 memcpy(s,spare,spareLength);
154
155         return YAFFS_OK;
156 }
157
158
159 static int yramsim_erase(struct yaffs_dev *dev, int blockId)
160 {
161         SimData *sim = DevToSim(dev);
162
163         CheckInitialised();
164         return yramsim_erase_internal(sim,blockId,0);
165 }
166
167 static int yramsim_check_block_bad(struct yaffs_dev *dev, int blockId)
168 {
169         SimData *sim = DevToSim(dev);
170         Block **blockList = sim->blockList;
171         if(blockId >= sim->nBlocks){
172                 return YAFFS_FAIL;
173         }
174
175         return blockList[blockId]->blockOk ? YAFFS_OK : YAFFS_FAIL;
176 }
177
178 static int yramsim_mark_block_bad(struct yaffs_dev *dev, int blockId)
179 {
180         SimData *sim = DevToSim(dev);
181         Block **blockList = sim->blockList;
182         if(blockId >= sim->nBlocks){
183                 return YAFFS_FAIL;
184         }
185
186         blockList[blockId]->blockOk = 0;
187
188         return YAFFS_OK;
189 }
190
191
192 static SimData *yramsim_alloc_sim_data(u32 devId, u32 nBlocks)
193 {
194         int ok = 1;
195
196         Block **blockList;
197         SimData *sim;
198         Block *b;
199         u32 i;
200
201         if(devId >= N_RAM_SIM_DEVS)
202                 return NULL;
203
204         sim = simDevs[devId];
205
206         if(sim)
207                 return sim;
208
209         sim = malloc(sizeof (SimData));
210         if(!sim)
211                 return NULL;
212
213         simDevs[devId] = sim;
214
215         blockList = malloc(nBlocks * sizeof(Block *));
216
217         sim->blockList = blockList;
218         sim->nBlocks = nBlocks;
219         if(!blockList){
220                 free(sim);
221                 return NULL;
222         }
223
224         for(i = 0; i < nBlocks; i++)
225                 blockList[i] = NULL;
226
227         for(i = 0; i < nBlocks && ok; i++){
228                 b=  malloc(sizeof(Block));
229                 if(b){
230                         blockList[i] = b;
231                         yramsim_erase_internal(sim,i,1);
232                 }
233                 else
234                         ok = 0;
235         }
236
237         if(!ok){
238                 for(i = 0; i < nBlocks; i++)
239                         if(blockList[i]){
240                                 free(blockList[i]);
241                                 blockList[i] = NULL;
242                         }
243                 free(blockList);
244                 blockList = NULL;
245                 free(sim);
246                 sim = NULL;
247         }
248
249         return sim;
250 }
251
252
253 struct yaffs_dev *yramsim_CreateRamSim(const YCHAR *name,
254                                 u32 devId, u32 nBlocks,
255                                 u32 start_block, u32 end_block)
256 {
257         SimData *sim;
258         struct yaffs_dev *dev;
259         struct yaffs_param *p;
260         struct yaffs_driver *d;
261
262         sim = yramsim_alloc_sim_data(devId, nBlocks);
263
264         dev = malloc(sizeof(*dev));
265
266         if(!sim || !dev){
267                 free(sim);
268                 free(dev);
269                 return NULL;
270         }
271         
272         memset(dev, 0, sizeof(*dev));
273
274         if(start_block >= sim->nBlocks)
275                 start_block = 0;
276         if(end_block == 0 || end_block >= sim->nBlocks)
277                 end_block = sim->nBlocks - 1;
278
279         p = &dev->param;
280         p->name = strdup(name);
281         p->start_block = start_block;
282         p->end_block = end_block;
283         p->total_bytes_per_chunk = DATA_SIZE;
284         p->spare_bytes_per_chunk= SPARE_SIZE;
285         p->chunks_per_block = PAGES_PER_BLOCK;
286         p->n_reserved_blocks = 2;
287         p->use_nand_ecc = 1;
288         p->inband_tags = 0;
289         p->is_yaffs2 = 1;
290         
291         d= &dev->drv;
292         d->drv_initialise_fn = yramsim_initialise;
293         d->drv_deinitialise_fn = yramsim_deinitialise;
294         d->drv_read_chunk_fn = yramsim_rd_chunk;
295         d->drv_write_chunk_fn = yramsim_wr_chunk;
296         d->drv_erase_fn = yramsim_erase;
297         d->drv_check_bad_fn = yramsim_check_block_bad;
298         d->drv_mark_bad_fn = yramsim_mark_block_bad;
299         
300         dev->driver_context= (void *)sim;
301
302         return dev;
303 }