xref: /nrf52832-nimble/rt-thread/components/dfs/filesystems/uffs/src/uffs/uffs_flash.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2   This file is part of UFFS, the Ultra-low-cost Flash File System.
3 
4   Copyright (C) 2005-2009 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_flash.c
35  * \brief UFFS flash interface
36  * \author Ricky Zheng, created 17th July, 2009
37  */
38 #include "uffs_config.h"
39 #include "uffs/uffs_public.h"
40 #include "uffs/uffs_ecc.h"
41 #include "uffs/uffs_flash.h"
42 #include "uffs/uffs_device.h"
43 #include "uffs/uffs_badblock.h"
44 #include "uffs/uffs_crc.h"
45 #include <string.h>
46 
47 #define PFX "flsh: "
48 
49 #define SPOOL(dev) &((dev)->mem.spare_pool)
50 #define HEADER(buf) ((struct uffs_MiniHeaderSt *)(buf)->header)
51 
52 #define ECC_SIZE(dev)	((dev)->attr->ecc_size)
53 #define NOMINAL_ECC_SIZE(dev) (3 * ((((dev)->attr->page_data_size - 1) / 256) + 1))
54 
55 #define TAG_STORE_SIZE	(sizeof(struct uffs_TagStoreSt))
56 
57 #define SEAL_BYTE(dev, spare)  spare[(dev)->mem.spare_data_size - 1]	// seal byte is the last byte of spare data
58 
59 #if defined(CONFIG_UFFS_AUTO_LAYOUT_USE_MTD_SCHEME)
60 /** Linux MTD spare layout for 512 and 2K page size */
61 static const u8 MTD512_LAYOUT_ECC[] =	{0, 4, 6, 2, 0xFF, 0};
62 static const u8 MTD512_LAYOUT_DATA[] = {8, 8, 0xFF, 0};
63 static const u8 MTD2K_LAYOUT_ECC[] = {40, 24, 0xFF, 0};
64 static const u8 MTD2K_LAYOUT_DATA[] = {2, 38, 0xFF, 0};
65 #endif
66 
TagMakeEcc(struct uffs_TagStoreSt * ts)67 static void TagMakeEcc(struct uffs_TagStoreSt *ts)
68 {
69 	ts->tag_ecc = 0xFFF;
70 	ts->tag_ecc = uffs_EccMake8(ts, sizeof(struct uffs_TagStoreSt));
71 }
72 
TagEccCorrect(struct uffs_TagStoreSt * ts)73 static int TagEccCorrect(struct uffs_TagStoreSt *ts)
74 {
75 	u16 ecc_store, ecc_read;
76 	int ret;
77 
78 	ecc_store = ts->tag_ecc;
79 	ts->tag_ecc = 0xFFF;
80 	ecc_read = uffs_EccMake8(ts, sizeof(struct uffs_TagStoreSt));
81 	ret = uffs_EccCorrect8(ts, ecc_read, ecc_store, sizeof(struct uffs_TagStoreSt));
82 	ts->tag_ecc = ecc_store;	// restore tag ecc
83 
84 	return ret;
85 
86 }
87 
88 /** setup UFFS spare data & ecc layout */
InitSpareLayout(uffs_Device * dev)89 static void InitSpareLayout(uffs_Device *dev)
90 {
91 	u8 s; // status byte offset
92 	u8 *p;
93 
94 	s = dev->attr->block_status_offs;
95 
96 	if (s < TAG_STORE_SIZE) {	/* status byte is within 0 ~ TAG_STORE_SIZE-1 */
97 
98 		/* spare data layout */
99 		p = dev->attr->_uffs_data_layout;
100 		if (s > 0) {
101 			*p++ = 0;
102 			*p++ = s;
103 		}
104 		*p++ = s + 1;
105 		*p++ = TAG_STORE_SIZE - s;
106 		*p++ = 0xFF;
107 		*p++ = 0;
108 
109 		/* spare ecc layout */
110 		p = dev->attr->_uffs_ecc_layout;
111 		if (dev->attr->ecc_opt != UFFS_ECC_NONE) {
112 			*p++ = TAG_STORE_SIZE + 1;
113 			*p++ = ECC_SIZE(dev);
114 		}
115 		*p++ = 0xFF;
116 		*p++ = 0;
117 	}
118 	else {	/* status byte > TAG_STORE_SIZE-1 */
119 
120 		/* spare data layout */
121 		p = dev->attr->_uffs_data_layout;
122 		*p++ = 0;
123 		*p++ = TAG_STORE_SIZE;
124 		*p++ = 0xFF;
125 		*p++ = 0;
126 
127 		/* spare ecc layout */
128 		p = dev->attr->_uffs_ecc_layout;
129 		if (dev->attr->ecc_opt != UFFS_ECC_NONE) {
130 			if (s < TAG_STORE_SIZE + ECC_SIZE(dev)) {
131 				if (s > TAG_STORE_SIZE) {
132 					*p++ = TAG_STORE_SIZE;
133 					*p++ = s - TAG_STORE_SIZE;
134 				}
135 				*p++ = s + 1;
136 				*p++ = TAG_STORE_SIZE + ECC_SIZE(dev) - s;
137 			}
138 			else {
139 				*p++ = TAG_STORE_SIZE;
140 				*p++ = ECC_SIZE(dev);
141 			}
142 		}
143 		*p++ = 0xFF;
144 		*p++ = 0;
145 	}
146 
147 	dev->attr->data_layout = dev->attr->_uffs_data_layout;
148 	dev->attr->ecc_layout = dev->attr->_uffs_ecc_layout;
149 }
150 
CalculateSpareDataSize(uffs_Device * dev)151 static int CalculateSpareDataSize(uffs_Device *dev)
152 {
153 	const u8 *p;
154 	int ecc_last = 0, tag_last = 0;
155 	int ecc_size, tag_size;
156 	int n;
157 
158 	ecc_size = (dev->attr->ecc_opt == UFFS_ECC_NONE ? 0 : ECC_SIZE(dev));
159 
160 	p = dev->attr->ecc_layout;
161 	if (p) {
162 		while (*p != 0xFF && ecc_size > 0) {
163 			n = (p[1] > ecc_size ? ecc_size : p[1]);
164 			ecc_last = p[0] + n;
165 			ecc_size -= n;
166 			p += 2;
167 		}
168 	}
169 
170 	tag_size = TAG_STORE_SIZE;
171 	p = dev->attr->data_layout;
172 	if (p) {
173 		while (*p != 0xFF && tag_size > 0) {
174 			n = (p[1] > tag_size ? tag_size : p[1]);
175 			tag_last = p[0] + n;
176 			tag_size -= n;
177 			p += 2;
178 		}
179 	}
180 
181 	n = (ecc_last > tag_last ? ecc_last : tag_last);
182 	n = (n > dev->attr->block_status_offs + 1 ?
183 			n : dev->attr->block_status_offs + 1);
184 
185 	return n + 1;		// plus one seal byte.
186 }
187 
188 
189 /**
190  * Initialize UFFS flash interface
191  */
uffs_FlashInterfaceInit(uffs_Device * dev)192 URET uffs_FlashInterfaceInit(uffs_Device *dev)
193 {
194 	URET ret = U_FAIL;
195 	struct uffs_StorageAttrSt *attr = dev->attr;
196 	uffs_Pool *pool = SPOOL(dev);
197 
198 	if (dev->mem.spare_pool_size == 0) {
199 		if (dev->mem.malloc) {
200 			dev->mem.spare_pool_buf = dev->mem.malloc(dev, UFFS_SPARE_BUFFER_SIZE);
201 			if (dev->mem.spare_pool_buf)
202 				dev->mem.spare_pool_size = UFFS_SPARE_BUFFER_SIZE;
203 		}
204 	}
205 
206 	if (UFFS_SPARE_BUFFER_SIZE > dev->mem.spare_pool_size) {
207 		uffs_Perror(UFFS_MSG_DEAD,
208 					"Spare buffer require %d but only %d available.",
209 					UFFS_SPARE_BUFFER_SIZE, dev->mem.spare_pool_size);
210 		memset(pool, 0, sizeof(uffs_Pool));
211 		goto ext;
212 	}
213 
214 	uffs_Perror(UFFS_MSG_NOISY,
215 					"alloc spare buffers %d bytes.",
216 					UFFS_SPARE_BUFFER_SIZE);
217 	uffs_PoolInit(pool, dev->mem.spare_pool_buf,
218 					dev->mem.spare_pool_size,
219 					UFFS_MAX_SPARE_SIZE, MAX_SPARE_BUFFERS);
220 
221 	// init flash driver
222 	if (dev->ops->InitFlash) {
223 		if (dev->ops->InitFlash(dev) < 0)
224 			goto ext;
225 	}
226 
227 	if (dev->ops->WritePage == NULL && dev->ops->WritePageWithLayout == NULL) {
228 		uffs_Perror(UFFS_MSG_SERIOUS, "Flash driver must provide 'WritePage' or 'WritePageWithLayout' function!");
229 		goto ext;
230 	}
231 
232 	if (dev->ops->ReadPage == NULL && dev->ops->ReadPageWithLayout == NULL) {
233 		uffs_Perror(UFFS_MSG_SERIOUS, "Flash driver must provide 'ReadPage' or 'ReadPageWithLayout' function!");
234 		goto ext;
235 	}
236 
237 	if (dev->attr->layout_opt == UFFS_LAYOUT_UFFS) {
238 		/* sanity check */
239 
240 		if (dev->attr->ecc_size == 0 && dev->attr->ecc_opt != UFFS_ECC_NONE) {
241 			dev->attr->ecc_size = NOMINAL_ECC_SIZE(dev);
242 		}
243 
244 		uffs_Perror(UFFS_MSG_NORMAL, "ECC size %d", dev->attr->ecc_size);
245 
246 		if ((dev->attr->data_layout && !dev->attr->ecc_layout) ||
247 			(!dev->attr->data_layout && dev->attr->ecc_layout)) {
248 			uffs_Perror(UFFS_MSG_SERIOUS,
249 						"Please setup data_layout and ecc_layout, "
250 						"or leave them all NULL !");
251 			goto ext;
252 		}
253 
254 		if (!attr->data_layout && !attr->ecc_layout) {
255 #if defined(CONFIG_UFFS_AUTO_LAYOUT_USE_MTD_SCHEME)
256 			switch(attr->page_data_size) {
257 			case 512:
258 				attr->ecc_layout = MTD512_LAYOUT_ECC;
259 				attr->data_layout = MTD512_LAYOUT_DATA;
260 				break;
261 			case 2048:
262 				attr->ecc_layout = MTD2K_LAYOUT_ECC;
263 				attr->data_layout = MTD2K_LAYOUT_DATA;
264 				break;
265 			default:
266 				InitSpareLayout(dev);
267 				break;
268 			}
269 #else
270 			InitSpareLayout(dev);
271 #endif
272 		}
273 	}
274 	else if (dev->attr->layout_opt == UFFS_LAYOUT_FLASH) {
275 		if (dev->ops->WritePageWithLayout == NULL || dev->ops->ReadPageWithLayout == NULL) {
276 			uffs_Perror(UFFS_MSG_SERIOUS, "When using UFFS_LAYOUT_FLASH option, "
277 				"flash driver must provide 'WritePageWithLayout' and 'ReadPageWithLayout' function!");
278 			goto ext;
279 		}
280 	}
281 	else {
282 		uffs_Perror(UFFS_MSG_SERIOUS, "Invalid layout_opt: %d", dev->attr->layout_opt);
283 		goto ext;
284 	}
285 
286 	if (dev->ops->EraseBlock == NULL) {
287 		uffs_Perror(UFFS_MSG_SERIOUS, "Flash driver MUST implement 'EraseBlock()' function !");
288 		goto ext;
289 	}
290 
291 	dev->mem.spare_data_size = CalculateSpareDataSize(dev);
292 	uffs_Perror(UFFS_MSG_NORMAL, "UFFS consume spare data size %d", dev->mem.spare_data_size);
293 
294 	if (dev->mem.spare_data_size > dev->attr->spare_size) {
295 		uffs_Perror(UFFS_MSG_SERIOUS, "NAND spare(%dB) can't hold UFFS spare data(%dB) !",
296 						dev->attr->spare_size, dev->mem.spare_data_size);
297 		goto ext;
298 	}
299 
300 	ret = U_SUCC;
301 ext:
302 	return ret;
303 }
304 
305 /**
306  * Release UFFS flash interface
307  */
uffs_FlashInterfaceRelease(uffs_Device * dev)308 URET uffs_FlashInterfaceRelease(uffs_Device *dev)
309 {
310 	uffs_Pool *pool;
311 
312 	pool = SPOOL(dev);
313 	if (pool->mem && dev->mem.free) {
314 		dev->mem.free(dev, pool->mem);
315 		pool->mem = NULL;
316 		dev->mem.spare_pool_size = 0;
317 	}
318 	uffs_PoolRelease(pool);
319 	memset(pool, 0, sizeof(uffs_Pool));
320 
321 	// release flash driver
322 	if (dev->ops->ReleaseFlash) {
323 		if (dev->ops->ReleaseFlash(dev) < 0)
324 			return U_FAIL;
325 	}
326 
327 	return U_SUCC;
328 }
329 
330 /**
331  * unload spare to tag and ecc.
332  */
uffs_FlashUnloadSpare(uffs_Device * dev,const u8 * spare,struct uffs_TagStoreSt * ts,u8 * ecc)333 void uffs_FlashUnloadSpare(uffs_Device *dev,
334 						const u8 *spare, struct uffs_TagStoreSt *ts, u8 *ecc)
335 {
336 	u8 *p_tag = (u8 *)ts;
337 	int tag_size = TAG_STORE_SIZE;
338 	int ecc_size = dev->attr->ecc_size;
339 	int n;
340 	const u8 *p;
341 
342 	// unload ecc
343 	p = dev->attr->ecc_layout;
344 	if (p && ecc) {
345 		while (*p != 0xFF && ecc_size > 0) {
346 			n = (p[1] > ecc_size ? ecc_size : p[1]);
347 			memcpy(ecc, spare + p[0], n);
348 			ecc_size -= n;
349 			ecc += n;
350 			p += 2;
351 		}
352 	}
353 
354 	// unload tag
355 	if (ts) {
356 		p = dev->attr->data_layout;
357 		while (*p != 0xFF && tag_size > 0) {
358 			n = (p[1] > tag_size ? tag_size : p[1]);
359 			memcpy(p_tag, spare + p[0], n);
360 			tag_size -= n;
361 			p_tag += n;
362 			p += 2;
363 		}
364 	}
365 }
366 
367 /**
368  * Read tag from page spare
369  *
370  * \param[in] dev uffs device
371  * \param[in] block flash block num
372  * \param[in] page flash page num
373  * \param[out] tag tag to be filled
374  *
375  * \return	#UFFS_FLASH_NO_ERR: success and/or has no flip bits.
376  *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
377  *			#UFFS_FLASH_ECC_FAIL: spare data has flip bits and ecc correct failed.
378  *			#UFFS_FLASH_ECC_OK: spare data has flip bits and corrected by ecc.
379 */
uffs_FlashReadPageTag(uffs_Device * dev,int block,int page,uffs_Tags * tag)380 int uffs_FlashReadPageTag(uffs_Device *dev,
381 							int block, int page, uffs_Tags *tag)
382 {
383 	uffs_FlashOps *ops = dev->ops;
384 	u8 * spare_buf;
385 	int ret = UFFS_FLASH_UNKNOWN_ERR;
386 	int tmp_ret;
387 	UBOOL is_bad = U_FALSE;
388 
389 	spare_buf = (u8 *) uffs_PoolGet(SPOOL(dev));
390 	if (spare_buf == NULL)
391 		goto ext;
392 
393 	if (ops->ReadPageWithLayout) {
394 		ret = ops->ReadPageWithLayout(dev, block, page, NULL, 0, NULL, tag ? &tag->s : NULL, NULL);
395 		if (tag)
396 			tag->seal_byte = (ret == UFFS_FLASH_NOT_SEALED ? 0xFF : 0);
397 	}
398 	else {
399 		ret = ops->ReadPage(dev, block, page, NULL, 0, NULL,
400 									spare_buf, dev->mem.spare_data_size);
401 
402 		if (tag) {
403 			tag->seal_byte = SEAL_BYTE(dev, spare_buf);
404 
405 			if (!UFFS_FLASH_HAVE_ERR(ret))
406 				uffs_FlashUnloadSpare(dev, spare_buf, &tag->s, NULL);
407 		}
408 	}
409 
410 	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
411 		is_bad = U_TRUE;
412 
413 	if (UFFS_FLASH_HAVE_ERR(ret))
414 		goto ext;
415 
416 	if (tag) {
417 		if (!TAG_IS_SEALED(tag))	// not sealed ? don't try tag ECC correction
418 			goto ext;
419 
420 		if (!TAG_IS_VALID(tag)) {
421 			if (dev->attr->ecc_opt != UFFS_ECC_NONE) {
422 				/*
423 				 * There could be a special case if:
424 				 *  a) tag is sealed (so we are here), and
425 				 *  b) s.valid == 1 and this bit is a 'bad' bit, and
426 				 *  c) after tag ECC (corrected by tag ECC) s.valid == 0.
427 				 *
428 				 * So we need to try tag ECC (don't treat it as bad block if ECC failed)
429 				 */
430 
431 				struct uffs_TagStoreSt s;
432 
433 				memcpy(&s, &tag->s, sizeof(s));
434 				tmp_ret = TagEccCorrect(&s);
435 
436 				if (tmp_ret <= 0 || !TAG_IS_VALID(tag))	// can not corrected by ECC.
437 					goto ext;
438 			}
439 			else {
440 				goto ext;
441 			}
442 		}
443 
444 		// do tag ecc correction
445 		if (dev->attr->ecc_opt != UFFS_ECC_NONE) {
446 			ret = TagEccCorrect(&tag->s);
447 			ret = (ret < 0 ? UFFS_FLASH_ECC_FAIL :
448 					(ret > 0 ? UFFS_FLASH_ECC_OK : UFFS_FLASH_NO_ERR));
449 
450 			if (UFFS_FLASH_IS_BAD_BLOCK(ret))
451 				is_bad = U_TRUE;
452 
453 			if (UFFS_FLASH_HAVE_ERR(ret))
454 				goto ext;
455 		}
456 	}
457 
458 ext:
459 	if (is_bad) {
460 		uffs_BadBlockAdd(dev, block);
461 		uffs_Perror(UFFS_MSG_NORMAL,
462 					"A new bad block (%d) is detected.", block);
463 	}
464 
465 	if (spare_buf)
466 		uffs_PoolPut(SPOOL(dev), spare_buf);
467 
468 	return ret;
469 }
470 
471 /**
472  * Read page data to buf (do ECC error correction if needed)
473  * \param[in] dev uffs device
474  * \param[in] block flash block num
475  * \param[in] page flash page num of the block
476  * \param[out] buf holding the read out data
477  * \param[in] skip_ecc skip ecc when reading data from flash
478  *
479  * \return	#UFFS_FLASH_NO_ERR: success and/or has no flip bits.
480  *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
481  *			#UFFS_FLASH_ECC_FAIL: spare data has flip bits and ecc correct failed.
482  *			#UFFS_FLASH_ECC_OK: spare data has flip bits and corrected by ecc.
483  *			#UFFS_FLASH_CRC_ERR: CRC verification failed.
484  *			#UFFS_FLASH_UNKNOWN_ERR:
485  *
486  * \note if skip_ecc is U_TRUE, skip CRC as well.
487  */
uffs_FlashReadPage(uffs_Device * dev,int block,int page,uffs_Buf * buf,UBOOL skip_ecc)488 int uffs_FlashReadPage(uffs_Device *dev, int block, int page, uffs_Buf *buf, UBOOL skip_ecc)
489 {
490 	uffs_FlashOps *ops = dev->ops;
491 	struct uffs_StorageAttrSt *attr = dev->attr;
492 	int size = dev->com.pg_size;
493 	u8 ecc_buf[UFFS_MAX_ECC_SIZE];
494 	u8 ecc_store[UFFS_MAX_ECC_SIZE];
495 	UBOOL is_bad = U_FALSE;
496 #ifdef CONFIG_ENABLE_PAGE_DATA_CRC
497 	UBOOL crc_ok = U_TRUE;
498 #endif
499 	u8 * spare;
500 
501 	int ret = UFFS_FLASH_UNKNOWN_ERR;
502 
503 	spare = (u8 *) uffs_PoolGet(SPOOL(dev));
504 	if (spare == NULL)
505 		goto ext;
506 
507 	if (ops->ReadPageWithLayout) {
508 		if (skip_ecc)
509 			ret = ops->ReadPageWithLayout(dev, block, page, buf->header, size, NULL, NULL, NULL);
510 		else
511 			ret = ops->ReadPageWithLayout(dev, block, page, buf->header, size, ecc_buf, NULL, ecc_store);
512 	}
513 	else {
514 		if (skip_ecc)
515 			ret = ops->ReadPage(dev, block, page, buf->header, size, NULL, NULL, 0);
516 		else
517 			ret = ops->ReadPage(dev, block, page, buf->header, size, ecc_buf, spare, dev->mem.spare_data_size);
518 	}
519 
520 	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
521 		is_bad = U_TRUE;
522 
523 	if (UFFS_FLASH_HAVE_ERR(ret))
524 		goto ext;
525 
526 #ifdef CONFIG_ENABLE_PAGE_DATA_CRC
527 	if (!skip_ecc) {
528 		crc_ok = (HEADER(buf)->crc == uffs_crc16sum(buf->data, size - sizeof(struct uffs_MiniHeaderSt)) ? U_TRUE : U_FALSE);
529 
530 		if (crc_ok)
531 			goto ext;	// CRC is matched, no need to do ECC correction.
532 		else {
533 			if (dev->attr->ecc_opt == UFFS_ECC_NONE || dev->attr->ecc_opt == UFFS_ECC_HW_AUTO) {
534 				// ECC is not enabled or ecc correction already done, error return immediately,
535 				// otherwise, we try CRC check again after ecc correction.
536 				ret = UFFS_FLASH_CRC_ERR;
537 				goto ext;
538 			}
539 		}
540 	}
541 #endif
542 
543 	// make ECC for UFFS_ECC_SOFT
544 	if (attr->ecc_opt == UFFS_ECC_SOFT && !skip_ecc)
545 		uffs_EccMake(buf->header, size, ecc_buf);
546 
547 	// unload ecc_store if driver doesn't do the layout
548 	if (ops->ReadPageWithLayout == NULL) {
549 		if (!skip_ecc && (attr->ecc_opt == UFFS_ECC_SOFT || attr->ecc_opt == UFFS_ECC_HW))
550 			uffs_FlashUnloadSpare(dev, spare, NULL, ecc_store);
551 	}
552 
553 	// check page data ecc
554 	if (!skip_ecc && (dev->attr->ecc_opt == UFFS_ECC_SOFT || dev->attr->ecc_opt == UFFS_ECC_HW)) {
555 
556 		ret = uffs_EccCorrect(buf->header, size, ecc_store, ecc_buf);
557 		ret = (ret < 0 ? UFFS_FLASH_ECC_FAIL :
558 				(ret > 0 ? UFFS_FLASH_ECC_OK : UFFS_FLASH_NO_ERR));
559 
560 		if (UFFS_FLASH_IS_BAD_BLOCK(ret))
561 			is_bad = U_TRUE;
562 
563 		if (UFFS_FLASH_HAVE_ERR(ret))
564 			goto ext;
565 	}
566 
567 #ifdef CONFIG_ENABLE_PAGE_DATA_CRC
568 	if (!skip_ecc && !UFFS_FLASH_HAVE_ERR(ret)) {
569 		// Everything seems ok, do CRC check again.
570 		if (HEADER(buf)->crc == uffs_crc16sum(buf->data, size - sizeof(struct uffs_MiniHeaderSt))) {
571 			ret = UFFS_FLASH_CRC_ERR;
572 			goto ext;
573 		}
574 	}
575 #endif
576 
577 ext:
578 	switch(ret) {
579 		case UFFS_FLASH_IO_ERR:
580 			uffs_Perror(UFFS_MSG_NORMAL, "Read block %d page %d I/O error", block, page);
581 			break;
582 		case UFFS_FLASH_ECC_FAIL:
583 			uffs_Perror(UFFS_MSG_NORMAL, "Read block %d page %d ECC failed", block, page);
584 			ret = UFFS_FLASH_BAD_BLK;	// treat ECC FAIL as BAD BLOCK
585 			is_bad = U_TRUE;
586 			break;
587 		case UFFS_FLASH_ECC_OK:
588 			uffs_Perror(UFFS_MSG_NORMAL, "Read block %d page %d bit flip corrected by ECC", block, page);
589 			break;
590 		case UFFS_FLASH_BAD_BLK:
591 			uffs_Perror(UFFS_MSG_NORMAL, "Read block %d page %d BAD BLOCK found", block, page);
592 			break;
593 		case UFFS_FLASH_UNKNOWN_ERR:
594 			uffs_Perror(UFFS_MSG_NORMAL, "Read block %d page %d UNKNOWN error!", block, page);
595 			break;
596 		case UFFS_FLASH_CRC_ERR:
597 			uffs_Perror(UFFS_MSG_NORMAL, "Read block %d page %d CRC failed", block, page);
598 			break;
599 		default:
600 			break;
601 	}
602 
603 	if (is_bad)
604 		uffs_BadBlockAdd(dev, block);
605 
606 	if (spare)
607 		uffs_PoolPut(SPOOL(dev), spare);
608 
609 
610 	return ret;
611 }
612 
613 /**
614  * make spare from tag and ecc
615  *
616  * \param[in] dev uffs dev
617  * \param[in] ts uffs tag store, NULL if don't pack tag store
618  * \param[in] ecc ecc of data, NULL if don't pack ecc
619  * \param[out] spare output buffer
620  * \note spare buffer size: dev->mem.spare_data_size,
621  *		 all unpacked bytes will be inited 0xFF
622  */
uffs_FlashMakeSpare(uffs_Device * dev,const uffs_TagStore * ts,const u8 * ecc,u8 * spare)623 void uffs_FlashMakeSpare(uffs_Device *dev,
624 						 const uffs_TagStore *ts, const u8 *ecc, u8* spare)
625 {
626 	u8 *p_ts = (u8 *)ts;
627 	int ts_size = TAG_STORE_SIZE;
628 	int ecc_size = ECC_SIZE(dev);
629 	int n;
630 	const u8 *p;
631 
632 	if (!uffs_Assert(spare != NULL, "invalid param"))
633 		return;
634 
635 	memset(spare, 0xFF, dev->mem.spare_data_size);	// initialize as 0xFF.
636 	SEAL_BYTE(dev, spare) = 0;						// set seal byte = 0.
637 
638 	// load ecc
639 	p = dev->attr->ecc_layout;
640 	if (p && ecc) {
641 		while (*p != 0xFF && ecc_size > 0) {
642 			n = (p[1] > ecc_size ? ecc_size : p[1]);
643 			memcpy(spare + p[0], ecc, n);
644 			ecc_size -= n;
645 			ecc += n;
646 			p += 2;
647 		}
648 	}
649 
650 	p = dev->attr->data_layout;
651 	while (*p != 0xFF && ts_size > 0) {
652 		n = (p[1] > ts_size ? ts_size : p[1]);
653 		memcpy(spare + p[0], p_ts, n);
654 		ts_size -= n;
655 		p_ts += n;
656 		p += 2;
657 	}
658 
659 	uffs_Assert(SEAL_BYTE(dev, spare) == 0, "Make spare fail!");
660 }
661 
662 /**
663  * write the whole page, include data and tag
664  *
665  * \param[in] dev uffs device
666  * \param[in] block
667  * \param[in] page
668  * \param[in] buf contains data to be wrote
669  * \param[in] tag tag to be wrote
670  *
671  * \return	#UFFS_FLASH_NO_ERR: success.
672  *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
673  *			#UFFS_FLASH_BAD_BLK: a new bad block detected.
674  */
uffs_FlashWritePageCombine(uffs_Device * dev,int block,int page,uffs_Buf * buf,uffs_Tags * tag)675 int uffs_FlashWritePageCombine(uffs_Device *dev,
676 							   int block, int page,
677 							   uffs_Buf *buf, uffs_Tags *tag)
678 {
679 	uffs_FlashOps *ops = dev->ops;
680 	int size = dev->com.pg_size;
681 	u8 ecc_buf[UFFS_MAX_ECC_SIZE];
682 	u8 *ecc = NULL;
683 	u8 *spare;
684 	struct uffs_MiniHeaderSt *header;
685 	int ret = UFFS_FLASH_UNKNOWN_ERR;
686 	UBOOL is_bad = U_FALSE;
687 	uffs_Buf *verify_buf;
688 #ifdef CONFIG_PAGE_WRITE_VERIFY
689 	uffs_Tags chk_tag;
690 #endif
691 
692 	spare = (u8 *) uffs_PoolGet(SPOOL(dev));
693 	if (spare == NULL)
694 		goto ext;
695 
696 	// setup header
697 	header = HEADER(buf);
698 	memset(header, 0xFF, sizeof(struct uffs_MiniHeaderSt));
699 	header->status = 0;
700 #ifdef CONFIG_ENABLE_PAGE_DATA_CRC
701 	header->crc = uffs_crc16sum(buf->data, size - sizeof(struct uffs_MiniHeaderSt));
702 #endif
703 
704 	// setup tag
705 	TAG_DIRTY_BIT(tag) = TAG_DIRTY;		//!< set dirty bit
706 	TAG_VALID_BIT(tag) = TAG_VALID;		//!< set valid bit
707 	SEAL_TAG(tag);						//!< seal tag (the real seal byte will be set in uffs_FlashMakeSpare())
708 
709 	if (dev->attr->ecc_opt != UFFS_ECC_NONE)
710 		TagMakeEcc(&tag->s);
711 	else
712 		tag->s.tag_ecc = TAG_ECC_DEFAULT;
713 
714 	if (dev->attr->ecc_opt == UFFS_ECC_SOFT) {
715 		uffs_EccMake(buf->header, size, ecc_buf);
716 		ecc = ecc_buf;
717 	}
718 	else if (dev->attr->ecc_opt == UFFS_ECC_HW) {
719 		ecc = ecc_buf;
720 	}
721 
722 	if (ops->WritePageWithLayout) {
723 		ret = ops->WritePageWithLayout(dev, block, page,
724 							buf->header, size, ecc, &tag->s);
725 	}
726 	else {
727 
728 		if (!uffs_Assert(!(dev->attr->layout_opt == UFFS_LAYOUT_FLASH ||
729 					dev->attr->ecc_opt == UFFS_ECC_HW ||
730 					dev->attr->ecc_opt == UFFS_ECC_HW_AUTO), "WritePageWithLayout() not implemented ?")) {
731 			ret = UFFS_FLASH_IO_ERR;
732 			goto ext;
733 		}
734 
735 		uffs_FlashMakeSpare(dev, &tag->s, ecc, spare);
736 
737 		ret = ops->WritePage(dev, block, page, buf->header, size, spare, dev->mem.spare_data_size);
738 
739 	}
740 
741 	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
742 		is_bad = U_TRUE;
743 
744 	if (UFFS_FLASH_HAVE_ERR(ret))
745 		goto ext;
746 
747 #ifdef CONFIG_PAGE_WRITE_VERIFY
748 	verify_buf = uffs_BufClone(dev, NULL);
749 	if (verify_buf) {
750 		ret = uffs_FlashReadPage(dev, block, page, verify_buf, U_FALSE);
751 		if (!UFFS_FLASH_HAVE_ERR(ret)) {
752 			if (memcmp(buf->header, verify_buf->header, size) != 0) {
753 				uffs_Perror(UFFS_MSG_NORMAL,
754 							"Page write verify failed (block %d page %d)",
755 							block, page);
756 				ret = UFFS_FLASH_BAD_BLK;
757 			}
758 		}
759 
760 		uffs_BufFreeClone(dev, verify_buf);
761 	}
762 	else {
763 		uffs_Perror(UFFS_MSG_SERIOUS, "Insufficient buf, clone buf failed.");
764 	}
765 
766 	ret = uffs_FlashReadPageTag(dev, block, page, &chk_tag);
767 	if (UFFS_FLASH_HAVE_ERR(ret))
768 		goto ext;
769 
770 	if (memcmp(&tag->s, &chk_tag.s, sizeof(uffs_TagStore)) != 0) {
771 		uffs_Perror(UFFS_MSG_NORMAL, "Page tag write verify failed (block %d page %d)",
772 					block, page);
773 		ret = UFFS_FLASH_BAD_BLK;
774 	}
775 
776 	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
777 		is_bad = U_TRUE;
778 
779 #endif
780 ext:
781 	if (is_bad)
782 		uffs_BadBlockAdd(dev, block);
783 
784 	if (spare)
785 		uffs_PoolPut(SPOOL(dev), spare);
786 
787 	return ret;
788 }
789 
790 /**
791  * mark a clean page tag as 'dirty' and 'invalid'.
792  *
793  * \param[in] dev uffs device
794  * \param[in] bc block info
795  * \param[in] page
796  *
797  * \return	#UFFS_FLASH_NO_ERR: success.
798  *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
799  *			#UFFS_FLASH_BAD_BLK: a new bad block detected.
800  */
uffs_FlashMarkDirtyPage(uffs_Device * dev,uffs_BlockInfo * bc,int page)801 int uffs_FlashMarkDirtyPage(uffs_Device *dev, uffs_BlockInfo *bc, int page)
802 {
803 	u8 *spare;
804 	uffs_FlashOps *ops = dev->ops;
805 	UBOOL is_bad = U_FALSE;
806 	int ret = UFFS_FLASH_UNKNOWN_ERR;
807 	int block = bc->block;
808 	uffs_Tags *tag = GET_TAG(bc, page);
809 	struct uffs_TagStoreSt *ts = &tag->s;
810 
811 	spare = (u8 *) uffs_PoolGet(SPOOL(dev));
812 	if (spare == NULL)
813 		goto ext;
814 
815 	memset(ts, 0xFF, sizeof(struct uffs_TagStoreSt));
816 	ts->dirty = TAG_DIRTY;  // set only 'dirty' bit, leave 'valid' bit to 1 (invalid).
817 
818 	if (dev->attr->ecc_opt != UFFS_ECC_NONE)
819 		TagMakeEcc(ts);
820 
821 	if (ops->WritePageWithLayout) {
822 		ret = ops->WritePageWithLayout(dev, block, page, NULL, 0, NULL, ts);
823 	}
824 	else {
825 		uffs_FlashMakeSpare(dev, ts, NULL, spare);
826 		ret = ops->WritePage(dev, block, page, NULL, 0, spare, dev->mem.spare_data_size);
827 	}
828 
829 	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
830 		is_bad = U_TRUE;
831 
832 ext:
833 	if (is_bad)
834 		uffs_BadBlockAdd(dev, block);
835 
836 	if (spare)
837 		uffs_PoolPut(SPOOL(dev), spare);
838 
839 	return ret;
840 }
841 
842 /** Mark this block as bad block */
uffs_FlashMarkBadBlock(uffs_Device * dev,int block)843 URET uffs_FlashMarkBadBlock(uffs_Device *dev, int block)
844 {
845 	int ret;
846 	uffs_BlockInfo *bc;
847 
848 	uffs_Perror(UFFS_MSG_NORMAL, "Mark bad block: %d", block);
849 
850 	bc = uffs_BlockInfoGet(dev, block);
851 	if (bc) {
852 		uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);	// expire this block, just in case it's been cached before
853 		uffs_BlockInfoPut(dev, bc);
854 	}
855 
856 	if (dev->ops->MarkBadBlock)
857 		return dev->ops->MarkBadBlock(dev, block) == 0 ? U_SUCC : U_FAIL;
858 
859 #ifdef CONFIG_ERASE_BLOCK_BEFORE_MARK_BAD
860 	ret = dev->ops->EraseBlock(dev, block);
861 	if (ret != UFFS_FLASH_IO_ERR) {
862 		// note: even EraseBlock return UFFS_FLASH_BAD_BLK,
863 		//			we still process it ... not recommended for most NAND flash.
864 #endif
865 	if (dev->ops->WritePageWithLayout)
866 		ret = dev->ops->WritePageWithLayout(dev, block, 0, NULL, 0, NULL, NULL);
867 	else
868 		ret = dev->ops->WritePage(dev, block, 0, NULL, 0, NULL, 0);
869 
870 #ifdef CONFIG_ERASE_BLOCK_BEFORE_MARK_BAD
871 	}
872 #endif
873 
874 	return ret == UFFS_FLASH_NO_ERR ? U_SUCC : U_FAIL;
875 }
876 
877 /** Is this block a bad block ? */
uffs_FlashIsBadBlock(uffs_Device * dev,int block)878 UBOOL uffs_FlashIsBadBlock(uffs_Device *dev, int block)
879 {
880 	struct uffs_FlashOpsSt *ops = dev->ops;
881 	UBOOL ret = U_FALSE;
882 
883 	if (ops->IsBadBlock) {
884 		/* if flash driver provide 'IsBadBlock' function, call it */
885 		ret = (ops->IsBadBlock(dev, block) == 0 ? U_FALSE : U_TRUE);
886 	}
887 	else {
888 		/* otherwise we call ReadPage[WithLayout]() to get bad block status byte */
889 		/* check the first page */
890 		if (ops->ReadPageWithLayout) {
891 			ret = (ops->ReadPageWithLayout(dev, block, 0, NULL, 0, NULL, NULL, NULL)
892 												== UFFS_FLASH_BAD_BLK ? U_TRUE : U_FALSE);
893 		}
894 		else {
895 			ret = (ops->ReadPage(dev, block, 0, NULL, 0, NULL, NULL, 0)
896 												== UFFS_FLASH_BAD_BLK ? U_TRUE : U_FALSE);
897 		}
898 
899 		if (ret == U_FALSE) {
900 			/* check the second page */
901 			if (ops->ReadPageWithLayout) {
902 				ret = (ops->ReadPageWithLayout(dev, block, 0, NULL, 0, NULL, NULL, NULL)
903 													== UFFS_FLASH_BAD_BLK ? U_TRUE : U_FALSE);
904 			}
905 			else {
906 				ret = (ops->ReadPage(dev, block, 0, NULL, 0, NULL, NULL, 0)
907 													== UFFS_FLASH_BAD_BLK ? U_TRUE : U_FALSE);
908 			}
909 		}
910 	}
911 
912 	//uffs_Perror(UFFS_MSG_NOISY, "Block %d is %s", block, ret ? "BAD" : "GOOD");
913 
914 	return ret;
915 }
916 
917 /** Erase flash block */
uffs_FlashEraseBlock(uffs_Device * dev,int block)918 URET uffs_FlashEraseBlock(uffs_Device *dev, int block)
919 {
920 	int ret;
921 	uffs_BlockInfo *bc;
922 
923 	ret = dev->ops->EraseBlock(dev, block);
924 
925 	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
926 		uffs_BadBlockAdd(dev, block);
927 
928 	bc = uffs_BlockInfoGet(dev, block);
929 	if (bc) {
930 		uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);
931 		uffs_BlockInfoPut(dev, bc);
932 	}
933 	return UFFS_FLASH_HAVE_ERR(ret) ? U_FAIL : U_SUCC;
934 }
935 
936 /**
937  * Check the block by reading all pages.
938  *
939  * \return U_SUCC - all pages are clean,
940  *         U_FAIL - block is not clean
941  */
uffs_FlashCheckErasedBlock(uffs_Device * dev,int block)942 URET uffs_FlashCheckErasedBlock(uffs_Device *dev, int block)
943 {
944 	u8 *spare = NULL;
945 	uffs_FlashOps *ops = dev->ops;
946 	int ret = U_SUCC;
947 	int page;
948 	int flash_ret;
949 	u8 ecc_store[UFFS_MAX_ECC_SIZE];
950 	uffs_TagStore ts;
951 	uffs_Buf *buf = NULL;
952 	int size = dev->com.pg_size;
953 	int i;
954 	u8 *p;
955 
956 	spare = (u8 *) uffs_PoolGet(SPOOL(dev));
957 
958 	if (spare == NULL) {
959 		uffs_Perror(UFFS_MSG_SERIOUS, "Can't allocate spare buf.");
960 		goto ext;
961 	}
962 
963 	buf = uffs_BufClone(dev, NULL);
964 
965 	if (buf == NULL) {
966 		uffs_Perror(UFFS_MSG_SERIOUS, "Can't clone buf.");
967 		goto ext;
968 	}
969 
970 	for (page = 0; page < dev->attr->pages_per_block; page++) {
971 		if (ops->ReadPageWithLayout) {
972 
973 			flash_ret = ops->ReadPageWithLayout(dev, block, page, buf->header, size, NULL, &ts, ecc_store);
974 
975 			if (flash_ret != UFFS_FLASH_IO_ERR) {
976 				// check page tag, should be all 0xFF
977 				for (i = 0, p = (u8 *)(&ts); i < sizeof(ts); i++, p++) {
978 					if (*p != 0xFF) {
979 						ret = U_FAIL;
980 						goto ext;
981 					}
982 				}
983 
984 				// for hw or soft ecc, check stored ecc, should be all 0xFF
985 				if (dev->attr->ecc_opt == UFFS_ECC_HW ||
986 					dev->attr->ecc_opt == UFFS_ECC_SOFT)
987 				{
988 					for (i = 0, p = ecc_store; i < ECC_SIZE(dev); i++, p++) {
989 						if (*p != 0xFF) {
990 							ret = U_FAIL;
991 							goto ext;
992 						}
993 					}
994 				}
995 			}
996 		}
997 		else {
998 
999 			flash_ret = ops->ReadPage(dev, block, page, buf->header, size, NULL, spare, dev->attr->spare_size);
1000 			if (flash_ret != UFFS_FLASH_IO_ERR) {
1001 				// check spare data, should be all 0xFF
1002 				for (i = 0, p = spare; i < dev->attr->spare_size; i++, p++) {
1003 					if (*p != 0xFF) {
1004 						ret = U_FAIL;
1005 						goto ext;
1006 					}
1007 				}
1008 			}
1009 		}
1010 
1011 		if (flash_ret != UFFS_FLASH_IO_ERR) {
1012 			// check page data, should be all 0xFF
1013 			for (i = 0, p = buf->header; i < size; i++, p++) {
1014 				if (*p != 0xFF) {
1015 					ret = U_FAIL;
1016 					goto ext;
1017 				}
1018 			}
1019 		}
1020 
1021 	}
1022 
1023 
1024 ext:
1025 	if (spare)
1026 		uffs_PoolPut(SPOOL(dev), spare);
1027 
1028 	if (buf)
1029 		uffs_BufFreeClone(dev, buf);
1030 
1031 
1032 	return ret;
1033 }
1034 
1035