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