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