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