Better retirement and erasure checking.
[yaffs2.git] / direct / yaffs_fileem2k.c
1 /*
2  * YAFFS: Yet another FFS. A NAND-flash specific file system. 
3  * yaffs_ramdisk.c: yaffs ram disk component
4  *
5  * Copyright (C) 2002 Aleph One Ltd.
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 // This provides a YAFFS nand emulation on a file for emulating 2kB pages.
16 // THis is only intended as test code to test persistence etc.
17
18 const char *yaffs_flashif_c_version = "$Id: yaffs_fileem2k.c,v 1.5 2006-09-21 08:13:59 charles Exp $";
19
20
21 #include "yportenv.h"
22
23 #include "yaffs_flashif.h"
24 #include "yaffs_guts.h"
25 #include "devextras.h"
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <unistd.h> 
31
32 #include "yaffs_fileem2k.h"
33 #include "yaffs_packedtags2.h"
34
35
36
37 typedef struct 
38 {
39         __u8 data[PAGE_SIZE]; // Data + spare
40 } yflash_Page;
41
42 typedef struct
43 {
44         yflash_Page page[PAGES_PER_BLOCK]; // The pages in the block
45         
46 } yflash_Block;
47
48
49
50 typedef struct
51 {
52         int handle;
53         int nBlocks;
54 } yflash_Device;
55
56 static yflash_Device filedisk;
57
58 int yaffs_testPartialWrite = 0;
59
60 static int  CheckInit(void)
61 {
62         static int initialised = 0;
63         
64         int i;
65
66         
67         int fSize;
68         int written;
69         
70         yflash_Page p;
71         
72         if(initialised) 
73         {
74                 return YAFFS_OK;
75         }
76
77         initialised = 1;
78         
79         
80         filedisk.nBlocks = SIZE_IN_MB * BLOCKS_PER_MB;
81         
82         filedisk.handle = open("yaffsemfile2k", O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
83         
84         if(filedisk.handle < 0)
85         {
86                 perror("Failed to open yaffs emulation file");
87                 return YAFFS_FAIL;
88         }
89         
90         
91         fSize = lseek(filedisk.handle,0,SEEK_END);
92         
93         if(fSize < filedisk.nBlocks * BLOCK_SIZE)
94         {
95                 printf("Creating yaffs emulation file\n");
96                 
97                 lseek(filedisk.handle,0,SEEK_SET);
98                 
99                 memset(&p,0xff,sizeof(yflash_Page));
100                 
101                 for(i = 0; i <  filedisk.nBlocks * BLOCK_SIZE; i+= PAGE_SIZE)
102                 {
103                         written = write(filedisk.handle,&p,sizeof(yflash_Page));
104                         
105                         if(written != sizeof(yflash_Page))
106                         {
107                                 printf("Write failed\n");
108                                 return YAFFS_FAIL;
109                         }
110                 }               
111         }
112         else
113         {
114                 filedisk.nBlocks = fSize/(BLOCK_SIZE);
115         }
116         
117         return 1;
118 }
119
120
121 int yflash_GetNumberOfBlocks(void)
122 {
123         CheckInit();
124         
125         return filedisk.nBlocks;
126 }
127
128 int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags)
129 {
130         int written;
131         int pos;
132
133         CheckInit();
134         
135         
136         
137         if(data)
138         {
139                 pos = chunkInNAND * PAGE_SIZE;
140                 lseek(filedisk.handle,pos,SEEK_SET);
141                 written = write(filedisk.handle,data,dev->nBytesPerChunk);
142                 
143                 if(yaffs_testPartialWrite){
144                         close(filedisk.handle);
145                         exit(1);
146                 }
147                 
148                 if(written != dev->nBytesPerChunk) return YAFFS_FAIL;
149         }
150         
151         if(tags)
152         {
153                 pos = chunkInNAND * PAGE_SIZE + PAGE_DATA_SIZE;
154                 lseek(filedisk.handle,pos,SEEK_SET);
155                 if( 0 && dev->isYaffs2)
156                 {
157                         
158                         written = write(filedisk.handle,tags,sizeof(yaffs_ExtendedTags));
159                         if(written != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL;
160                 }
161                 else
162                 {
163                         yaffs_PackedTags2 pt;
164                         yaffs_PackTags2(&pt,tags);
165
166                         written = write(filedisk.handle,&pt,sizeof(pt));
167                         if(written != sizeof(pt)) return YAFFS_FAIL;
168                 }
169         }
170         
171
172         return YAFFS_OK;        
173
174 }
175
176 int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
177 {
178         int written;
179         
180         yaffs_PackedTags2 pt;
181
182         CheckInit();
183         
184         memset(&pt,0,sizeof(pt));
185         lseek(filedisk.handle,(blockNo * dev->nChunksPerBlock) * PAGE_SIZE + PAGE_DATA_SIZE,SEEK_SET);
186         written = write(filedisk.handle,&pt,sizeof(pt));
187                 
188         if(written != sizeof(pt)) return YAFFS_FAIL;
189         
190         
191         return YAFFS_OK;
192         
193 }
194
195 int yaffs_CheckAllFF(const __u8 *ptr, int n)
196 {
197         while(n)
198         {
199                 n--;
200                 if(*ptr!=0xFF) return 0;
201                 ptr++;
202         }
203         return 1;
204 }
205
206
207 int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
208 {
209         int nread;
210         int pos;
211
212         CheckInit();
213         
214         
215         
216         if(data)
217         {
218                 pos = chunkInNAND * PAGE_SIZE;
219                 lseek(filedisk.handle,pos,SEEK_SET);
220                 nread = read(filedisk.handle,data,dev->nBytesPerChunk);
221                 
222                 if(nread != dev->nBytesPerChunk) return YAFFS_FAIL;
223         }
224         
225         if(tags)
226         {
227                 pos = chunkInNAND * PAGE_SIZE + PAGE_DATA_SIZE;
228                 lseek(filedisk.handle,pos,SEEK_SET);
229                 if(0 && dev->isYaffs2)
230                 {
231                         nread= read(filedisk.handle,tags,sizeof(yaffs_ExtendedTags));
232                         if(nread != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL;
233                         if(yaffs_CheckAllFF((__u8 *)tags,sizeof(yaffs_ExtendedTags)))
234                         {
235                                 yaffs_InitialiseTags(tags);
236                         }
237                         else
238                         {
239                                 tags->chunkUsed = 1;
240                         }
241                 }
242                 else
243                 {
244                         yaffs_PackedTags2 pt;
245                         nread= read(filedisk.handle,&pt,sizeof(pt));
246                         yaffs_UnpackTags2(tags,&pt);
247                         if(nread != sizeof(pt)) return YAFFS_FAIL;
248                 }
249         }
250         
251
252         return YAFFS_OK;        
253
254 }
255
256
257 int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
258 {
259
260         int i;
261                 
262         CheckInit();
263         
264         if(blockNumber < 0 || blockNumber >= filedisk.nBlocks)
265         {
266                 T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
267                 return YAFFS_FAIL;
268         }
269         else
270         {
271         
272                 __u8 pg[PAGE_SIZE];
273                 int syz = PAGE_SIZE;
274                 int pos;
275                 
276                 memset(pg,0xff,syz);
277                 
278                 pos = lseek(filedisk.handle, blockNumber * dev->nChunksPerBlock * PAGE_SIZE, SEEK_SET);
279                 
280                 for(i = 0; i < dev->nChunksPerBlock; i++)
281                 {
282                         write(filedisk.handle,pg,PAGE_SIZE);
283                 }
284                 pos = lseek(filedisk.handle, 0,SEEK_CUR);
285                 
286                 return YAFFS_OK;
287         }
288         
289 }
290
291 int yflash_InitialiseNAND(yaffs_Device *dev)
292 {
293         CheckInit();
294         
295         return YAFFS_OK;
296 }
297
298
299
300
301 int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber)
302 {
303         yaffs_ExtendedTags tags;
304         int chunkNo;
305
306         *sequenceNumber = 0;
307         
308         chunkNo = blockNo * dev->nChunksPerBlock;
309         
310         yflash_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags);
311         if(tags.blockBad)
312         {
313                 *state = YAFFS_BLOCK_STATE_DEAD;
314         }
315         else if(!tags.chunkUsed)
316         {
317                 *state = YAFFS_BLOCK_STATE_EMPTY;
318         }
319         else if(tags.chunkUsed)
320         {
321                 *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
322                 *sequenceNumber = tags.sequenceNumber;
323         }
324         return YAFFS_OK;
325 }
326