xref: /nrf52832-nimble/rt-thread/components/dfs/filesystems/uffs/src/emu/uffs_fileem_ecc_hw.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2   This file is part of UFFS, the Ultra-low-cost Flash File System.
3 
4   Copyright (C) 2005-2010 Ricky Zheng <[email protected]>
5 
6   UFFS is free software; you can redistribute it and/or modify it under
7   the GNU Library General Public License as published by the Free Software
8   Foundation; either version 2 of the License, or (at your option) any
9   later version.
10 
11   UFFS is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   or GNU Library General Public License, as applicable, for more details.
15 
16   You should have received a copy of the GNU General Public License
17   and GNU Library General Public License along with UFFS; if not, write
18   to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19   Boston, MA  02110-1301, USA.
20 
21   As a special exception, if other files instantiate templates or use
22   macros or inline functions from this file, or you compile this file
23   and link it with other works to produce a work based on this file,
24   this file does not by itself cause the resulting work to be covered
25   by the GNU General Public License. However the source code for this
26   file must still be made available in accordance with section (3) of
27   the GNU General Public License v2.
28 
29   This exception does not invalidate any other reasons why a work based
30   on this file might be covered by the GNU General Public License.
31 */
32 
33 /**
34  * \file uffs_fileem_ecc_hw.c
35  * \brief emulate uffs file system for hardware ECC.
36  *
37  *	 In this emulator, we call 'uffs_FlashMakeSpare()' to do the layout job
38  *	 and call 'uffs_EccMake()' to calculate ECC.
39  *
40  * \author Ricky Zheng @ Oct, 2010
41  */
42 
43 #include <sys/types.h>
44 #include <string.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include "uffs_config.h"
48 #include "uffs/uffs_device.h"
49 #include "uffs_fileem.h"
50 #include "uffs/uffs_ecc.h"
51 
52 #define PFX "femu: "
53 #define MSG(msg,...) uffs_PerrorRaw(UFFS_MSG_NORMAL, msg, ## __VA_ARGS__)
54 #define MSGLN(msg,...) uffs_Perror(UFFS_MSG_NORMAL, msg, ## __VA_ARGS__)
55 
femu_hw_WritePageWithLayout(uffs_Device * dev,u32 block,u32 page,const u8 * data,int data_len,const u8 * ecc,const uffs_TagStore * ts)56 static int femu_hw_WritePageWithLayout(uffs_Device *dev, u32 block, u32 page,
57 							const u8 *data, int data_len, const u8 *ecc, const uffs_TagStore *ts)
58 {
59 	int written;
60 	int abs_page;
61 	int full_page_size;
62 	uffs_FileEmu *emu;
63 	struct uffs_StorageAttrSt *attr = dev->attr;
64 	u8 spare[UFFS_MAX_SPARE_SIZE];
65 	u8 ecc_buf[UFFS_MAX_ECC_SIZE];
66 	int spare_len;
67 
68 
69 	emu = (uffs_FileEmu *)(dev->attr->_private);
70 
71 	if (!emu || !(emu->fp)) {
72 		goto err;
73 	}
74 
75 	abs_page = attr->pages_per_block * block + page;
76 	full_page_size = attr->page_data_size + attr->spare_size;
77 
78 	if (data && data_len > 0) {
79 		if (data_len > attr->page_data_size)
80 			goto err;
81 
82 		emu->em_monitor_page[abs_page]++;
83 		if (emu->em_monitor_page[abs_page] > PAGE_DATA_WRITE_COUNT_LIMIT) {
84 			MSG("Warrning: block %d page %d exceed it's maximum write time!", block, page);
85 			goto err;
86 		}
87 
88 		fseek(emu->fp, abs_page * full_page_size, SEEK_SET);
89 
90 		written = fwrite(data, 1, data_len, emu->fp);
91 
92 		if (written != data_len) {
93 			MSG("write page I/O error ?");
94 			goto err;
95 		}
96 
97 		dev->st.page_write_count++;
98 		dev->st.io_write += written;
99 
100 	}
101 
102 	if (ts) {
103 
104 		emu->em_monitor_spare[abs_page]++;
105 		if (emu->em_monitor_spare[abs_page] > PAGE_SPARE_WRITE_COUNT_LIMIT) {
106 			MSG("Warrning: block %d page %d (spare) exceed it's maximum write time!", block, page);
107 			goto err;
108 		}
109 
110 		if (!uffs_Assert(data != NULL, "BUG: Write spare without data ?"))
111 			goto err;
112 
113 		uffs_EccMake(data, data_len, ecc_buf);
114 		uffs_FlashMakeSpare(dev, ts, ecc_buf, spare);
115 		spare_len = dev->mem.spare_data_size;
116 
117 		fseek(emu->fp, abs_page * full_page_size + attr->page_data_size, SEEK_SET);
118 		written = fwrite(spare, 1, spare_len, emu->fp);
119 		if (written != spare_len) {
120 			MSG("write spare I/O error ?");
121 			goto err;
122 		}
123 
124 		dev->st.spare_write_count++;
125 		dev->st.io_write += written;
126 	}
127 
128 	if (data == NULL && ts == NULL) {
129 		// mark bad block
130 		fseek(emu->fp, abs_page * full_page_size + attr->page_data_size + attr->block_status_offs, SEEK_SET);
131 		written = fwrite("\0", 1, 1, emu->fp);
132 		if (written != 1) {
133 			MSG("write bad block mark I/O error ?");
134 			goto err;
135 		}
136 		dev->st.io_write++;
137 	}
138 
139 	fflush(emu->fp);
140 	return UFFS_FLASH_NO_ERR;
141 err:
142 	fflush(emu->fp);
143 	return UFFS_FLASH_IO_ERR;
144 }
145 
146 
femu_hw_ReadPageWithLayout(uffs_Device * dev,u32 block,u32 page,u8 * data,int data_len,u8 * ecc,uffs_TagStore * ts,u8 * ecc_store)147 static URET femu_hw_ReadPageWithLayout(uffs_Device *dev, u32 block, u32 page, u8* data, int data_len, u8 *ecc,
148 									uffs_TagStore *ts, u8 *ecc_store)
149 {
150 	int nread;
151 	uffs_FileEmu *emu;
152 	int abs_page;
153 	int full_page_size;
154 	struct uffs_StorageAttrSt *attr = dev->attr;
155 	unsigned char status;
156 	u8 spare[UFFS_MAX_SPARE_SIZE];
157 	int spare_len;
158 
159 	emu = (uffs_FileEmu *)(dev->attr->_private);
160 
161 	if (!emu || !(emu->fp)) {
162 		goto err;
163 	}
164 
165 	abs_page = attr->pages_per_block * block + page;
166 	full_page_size = attr->page_data_size + attr->spare_size;
167 
168 	if (data && data_len > 0) {
169 		if (data_len > attr->page_data_size)
170 			goto err;
171 
172 		fseek(emu->fp, abs_page * full_page_size, SEEK_SET);
173 		nread = fread(data, 1, data_len, emu->fp);
174 
175 		if (nread != data_len) {
176 			MSG("read page I/O error ?");
177 			goto err;
178 		}
179 		dev->st.io_read += nread;
180 		dev->st.page_read_count++;
181 
182 		if (ecc) {
183 			// calculate ECC for data
184 			uffs_EccMake(data, data_len, ecc);
185 		}
186 	}
187 
188 	if (ts) {
189 
190 		spare_len = dev->mem.spare_data_size;
191 		fseek(emu->fp, abs_page * full_page_size + attr->page_data_size, SEEK_SET);
192 		nread = fread(spare, 1, spare_len, emu->fp);
193 
194 		if (nread != spare_len) {
195 			MSG("read page spare I/O error ?");
196 			goto err;
197 		}
198 
199 		// unload ts and ecc from spare
200 		uffs_FlashUnloadSpare(dev, spare, ts, ecc_store);
201 
202 		dev->st.io_read += nread;
203 		dev->st.spare_read_count++;
204 	}
205 
206 	if (data == NULL && ts == NULL) {
207 		// read bad block mark
208 		fseek(emu->fp, abs_page * full_page_size + attr->page_data_size + attr->block_status_offs, SEEK_SET);
209 		nread = fread(&status, 1, 1, emu->fp);
210 
211 		if (nread != 1) {
212 			MSG("read badblock mark I/O error ?");
213 			goto err;
214 		}
215 		dev->st.io_read++;
216 
217 		return status == 0xFF ? UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK;
218 	}
219 
220 	return UFFS_FLASH_NO_ERR;
221 err:
222 	return UFFS_FLASH_IO_ERR;
223 }
224 
225 
226 uffs_FlashOps g_femu_ops_ecc_hw = {
227 	femu_InitFlash,				// InitFlash()
228 	femu_ReleaseFlash,			// ReleaseFlash()
229 	NULL,						// ReadPage()
230 	femu_hw_ReadPageWithLayout,	// ReadPageWithLayout()
231 	NULL,						// WritePage()
232 	femu_hw_WritePageWithLayout,// WritePageWithLayout()
233 	NULL,						// IsBadBlock(), let UFFS take care of it.
234 	NULL,						// MarkBadBlock(), let UFFS take care of it.
235 	femu_EraseBlock,			// EraseBlock()
236 };
237