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
18const char *yaffs_flashif_c_version = "$Id: yaffs_fileem2k.c,v 1.7 2006/10/13 08:52:49 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
37typedef struct
38{
39	__u8 data[PAGE_SIZE]; // Data + spare
40} yflash_Page;
41
42typedef struct
43{
44	yflash_Page page[PAGES_PER_BLOCK]; // The pages in the block
45
46} yflash_Block;
47
48
49
50#define MAX_HANDLES 20
51#define BLOCKS_PER_HANDLE 8000
52
53typedef struct
54{
55	int handle[MAX_HANDLES];
56	int nBlocks;
57} yflash_Device;
58
59static yflash_Device filedisk;
60
61int yaffs_testPartialWrite = 0;
62
63
64static char *NToName(char *buf,int n)
65{
66	sprintf(buf,"emfile%d",n);
67	return buf;
68}
69
70static char dummyBuffer[BLOCK_SIZE];
71
72static int GetBlockFileHandle(int n)
73{
74	int h;
75	int requiredSize;
76
77	char name[40];
78	NToName(name,n);
79	int fSize;
80	int i;
81
82	h =  open(name, O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
83	if(h >= 0){
84		fSize = lseek(h,0,SEEK_END);
85		requiredSize = BLOCKS_PER_HANDLE * BLOCK_SIZE;
86		if(fSize < requiredSize){
87		   for(i = 0; i < BLOCKS_PER_HANDLE; i++)
88		   	if(write(h,dummyBuffer,BLOCK_SIZE) != BLOCK_SIZE)
89				return -1;
90
91		}
92	}
93
94	return h;
95
96}
97
98static int  CheckInit(void)
99{
100	static int initialised = 0;
101	int h;
102	int i;
103
104
105	off_t fSize;
106	off_t requiredSize;
107	int written;
108	int blk;
109
110	yflash_Page p;
111
112	if(initialised)
113	{
114		return YAFFS_OK;
115	}
116
117	initialised = 1;
118
119	memset(dummyBuffer,0xff,sizeof(dummyBuffer));
120
121
122	filedisk.nBlocks = SIZE_IN_MB * BLOCKS_PER_MB;
123
124	for(i = 0; i <  MAX_HANDLES; i++)
125		filedisk.handle[i] = -1;
126
127	for(i = 0,blk = 0; blk < filedisk.nBlocks; blk+=BLOCKS_PER_HANDLE,i++)
128		filedisk.handle[i] = GetBlockFileHandle(i);
129
130
131	return 1;
132}
133
134
135int yflash_GetNumberOfBlocks(void)
136{
137	CheckInit();
138
139	return filedisk.nBlocks;
140}
141
142int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags)
143{
144	int written;
145	int pos;
146	int h;
147
148	CheckInit();
149
150
151
152	if(data)
153	{
154		pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
155		h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
156
157		lseek(h,pos,SEEK_SET);
158		written = write(h,data,dev->nDataBytesPerChunk);
159
160		if(yaffs_testPartialWrite){
161			close(h);
162			exit(1);
163		}
164
165		if(written != dev->nDataBytesPerChunk) return YAFFS_FAIL;
166	}
167
168	if(tags)
169	{
170		pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE ;
171		h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
172
173		lseek(h,pos,SEEK_SET);
174		if( 0 && dev->isYaffs2)
175		{
176
177			written = write(h,tags,sizeof(yaffs_ExtendedTags));
178			if(written != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL;
179		}
180		else
181		{
182			yaffs_PackedTags2 pt;
183			yaffs_PackTags2(&pt,tags);
184
185			written = write(h,&pt,sizeof(pt));
186			if(written != sizeof(pt)) return YAFFS_FAIL;
187		}
188	}
189
190
191	return YAFFS_OK;
192
193}
194
195int 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
207static int fail300 = 1;
208static int fail320 = 1;
209
210int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
211{
212	int nread;
213	int pos;
214	int h;
215
216	CheckInit();
217
218
219
220	if(data)
221	{
222
223		pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
224		h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
225		lseek(h,pos,SEEK_SET);
226		nread = read(h,data,dev->nDataBytesPerChunk);
227
228		if(nread != dev->nDataBytesPerChunk) return YAFFS_FAIL;
229	}
230
231	if(tags)
232	{
233		pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE;
234		h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
235		lseek(h,pos,SEEK_SET);
236
237		if(0 && dev->isYaffs2)
238		{
239			nread= read(h,tags,sizeof(yaffs_ExtendedTags));
240			if(nread != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL;
241			if(yaffs_CheckAllFF((__u8 *)tags,sizeof(yaffs_ExtendedTags)))
242			{
243				yaffs_InitialiseTags(tags);
244			}
245			else
246			{
247				tags->chunkUsed = 1;
248			}
249		}
250		else
251		{
252			yaffs_PackedTags2 pt;
253			nread= read(h,&pt,sizeof(pt));
254			yaffs_UnpackTags2(tags,&pt);
255			if((chunkInNAND >> 6) == 300) {
256			    if(fail300 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){
257			       tags->eccResult = YAFFS_ECC_RESULT_FIXED;
258			       fail300 = 0;
259			    }
260
261			}
262			if((chunkInNAND >> 6) == 320) {
263			    if(fail320 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){
264			       tags->eccResult = YAFFS_ECC_RESULT_FIXED;
265			       fail320 = 0;
266			    }
267			}
268			if(nread != sizeof(pt)) return YAFFS_FAIL;
269		}
270	}
271
272
273	return YAFFS_OK;
274
275}
276
277
278int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
279{
280	int written;
281	int h;
282
283	yaffs_PackedTags2 pt;
284
285	CheckInit();
286
287	memset(&pt,0,sizeof(pt));
288	h = filedisk.handle[(blockNo / ( BLOCKS_PER_HANDLE))];
289	lseek(h,((blockNo % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE + PAGE_DATA_SIZE,SEEK_SET);
290	written = write(h,&pt,sizeof(pt));
291
292	if(written != sizeof(pt)) return YAFFS_FAIL;
293
294
295	return YAFFS_OK;
296
297}
298
299int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
300{
301
302	int i;
303	int h;
304
305	CheckInit();
306
307	if(blockNumber == 320)
308		fail320 = 1;
309
310	if(blockNumber < 0 || blockNumber >= filedisk.nBlocks)
311	{
312		T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
313		return YAFFS_FAIL;
314	}
315	else
316	{
317
318		__u8 pg[PAGE_SIZE];
319		int syz = PAGE_SIZE;
320		int pos;
321
322		memset(pg,0xff,syz);
323
324
325		h = filedisk.handle[(blockNumber / ( BLOCKS_PER_HANDLE))];
326		lseek(h,((blockNumber % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE,SEEK_SET);
327		for(i = 0; i < dev->nChunksPerBlock; i++)
328		{
329			write(h,pg,PAGE_SIZE);
330		}
331		pos = lseek(h, 0,SEEK_CUR);
332
333		return YAFFS_OK;
334	}
335
336}
337
338int yflash_InitialiseNAND(yaffs_Device *dev)
339{
340	CheckInit();
341
342	return YAFFS_OK;
343}
344
345
346
347
348int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber)
349{
350	yaffs_ExtendedTags tags;
351	int chunkNo;
352
353	*sequenceNumber = 0;
354
355	chunkNo = blockNo * dev->nChunksPerBlock;
356
357	yflash_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags);
358	if(tags.blockBad)
359	{
360		*state = YAFFS_BLOCK_STATE_DEAD;
361	}
362	else if(!tags.chunkUsed)
363	{
364		*state = YAFFS_BLOCK_STATE_EMPTY;
365	}
366	else if(tags.chunkUsed)
367	{
368		*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
369		*sequenceNumber = tags.sequenceNumber;
370	}
371	return YAFFS_OK;
372}
373
374