/************************************************************************/ /** \file yaffsnewcfg_ecc.c * \brief YAFFS direct interface implementation with bad blocks+ECC * * \date 2012/05/16 * \author Stephane Lesage - ATEIS * */ /************************************************************************/ /* Includes */ #include "yaffscfg.h" #include "yaffsfs.h" #include "yaffs_packedtags2.h" #include "yaffs_trace.h" #include "nandflash.h" #include /* Externals */ /* Macros */ /* Variables */ union { unsigned char buffer[64]; struct { unsigned char state[8]; struct yaffs_packed_tags2 PT2; unsigned char ecc[8][3]; }; } spare; unsigned yaffs_trace_mask = YAFFS_TRACE_ALLOCATE | YAFFS_TRACE_SCAN | YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ERASE | YAFFS_TRACE_GC | YAFFS_TRACE_WRITE | YAFFS_TRACE_TRACING | YAFFS_TRACE_DELETION | YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_VERIFY_ALL | 0; static int yaffsfs_lastError; static struct yaffs_dev bootDev; static struct yaffs_dev flashDev; /* OS Glue Functions */ u32 yaffsfs_CurrentTime(void) { return 0; } void yaffsfs_SetError(int err) { yaffsfs_lastError = err; } int yaffsfs_GetLastError(void) { return yaffsfs_lastError; } void yaffsfs_Lock(void) { } void yaffsfs_Unlock(void) { } void *yaffsfs_malloc(size_t size) { return malloc(size); } void yaffsfs_free(void *ptr) { return free(ptr); } void yaffs_bug_fn(const char *file_name, int line_no) { printf("yaffs bug detected %s:%d\n", file_name, line_no); assert(0); } void yaffsfs_OSInitialisation(void) { } /* NAND Functions */ int yflash2_InitialiseNAND(struct yaffs_dev *dev) { return YAFFS_OK; } int yflash2_EraseBlockInNAND(struct yaffs_dev *dev, int block_no) { bool ret = NANDFlash_EraseBlock(block_no); return ret ? YAFFS_OK : YAFFS_FAIL; } int yflash2_WriteChunkWithTagsToNAND(struct yaffs_dev *dev, int nand_chunk, const u8 *data, const struct yaffs_ext_tags *tags) { int i; assert(tags); assert(data); memset(spare.state, -1, sizeof(spare.state)); yaffs_pack_tags2(&spare.PT2, tags, !dev->param.no_tags_ecc); for (i=0; i<8; i++) yaffs_ecc_calc(data+256*i, spare.ecc[i]); bool ret = NANDFlash_ProgramPage(nand_chunk, data, spare.buffer); return ret ? YAFFS_OK : YAFFS_FAIL; } int yflash2_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev, int nand_chunk, u8 *data, struct yaffs_ext_tags *tags) { assert(tags); NANDFlash_ReadPage(nand_chunk, data, spare.buffer); yaffs_unpack_tags2(tags, &spare.PT2, !dev->param.no_tags_ecc); if (tags->ecc_result == YAFFS_ECC_RESULT_UNFIXED) return YAFFS_OK; if (data) { int i; for (i=0; i<8; i++) { unsigned char ecc[3]; yaffs_ecc_calc(data+256*i, ecc); int res = yaffs_ecc_correct(data+256*i, ecc, spare.ecc[i]); if (res < 0) { tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED; } else if (res > 0) { if (tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED; } } } return YAFFS_OK; } int yflash2_MarkNANDBlockBad(struct yaffs_dev *dev, int block_no) { NANDFlash_MarkBlockBad(block_no); return YAFFS_OK; } int yflash2_QueryNANDBlock(struct yaffs_dev *dev, int block_no, enum yaffs_block_state *state, u32 *seq_number) { struct yaffs_ext_tags tags; bool bad = NANDFlash_IsBlockBad(block_no, spare.buffer); if (bad) { *seq_number = 0; *state = YAFFS_BLOCK_STATE_DEAD; return YAFFS_FAIL; } yaffs_unpack_tags2(&tags, &spare.PT2, !dev->param.no_tags_ecc); if (tags.chunk_used) { *seq_number = tags.seq_number; *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; } else { *seq_number = 0; *state = YAFFS_BLOCK_STATE_EMPTY; } return YAFFS_OK; } /* Startup */ int yaffs_start_up(void) { yaffsfs_OSInitialisation(); // Set up devices memset(&bootDev, 0, sizeof(bootDev)); bootDev.os_context = (void*) 0; // Used to identify the device in fstat. bootDev.param.name = "/boot"; bootDev.param.total_bytes_per_chunk = NANDFlashDevice.DataSize; bootDev.param.spare_bytes_per_chunk = NANDFlashDevice.SpareSize; bootDev.param.chunks_per_block = NANDFlashDevice.PagesPerBlock; bootDev.param.start_block = 0; bootDev.param.end_block = 63; // Last block in 8MB bootDev.param.n_reserved_blocks = 5; bootDev.param.n_caches = 10; bootDev.param.is_yaffs2 = 1; bootDev.param.erase_fn = yflash2_EraseBlockInNAND; bootDev.param.initialise_flash_fn = yflash2_InitialiseNAND; bootDev.param.write_chunk_tags_fn = yflash2_WriteChunkWithTagsToNAND; bootDev.param.read_chunk_tags_fn = yflash2_ReadChunkWithTagsFromNAND; bootDev.param.bad_block_fn = yflash2_MarkNANDBlockBad; bootDev.param.query_block_fn = yflash2_QueryNANDBlock; bootDev.param.wide_tnodes_disabled = 1; yaffs_add_device(&bootDev); memset(&flashDev, 0, sizeof(flashDev)); flashDev.os_context = (void*) 1; // Used to identify the device in fstat. flashDev.param.name = "/flash"; flashDev.param.total_bytes_per_chunk = NANDFlashDevice.DataSize; flashDev.param.spare_bytes_per_chunk = NANDFlashDevice.SpareSize; flashDev.param.chunks_per_block = NANDFlashDevice.PagesPerBlock; flashDev.param.start_block = 64; // First block after 8MB flashDev.param.end_block = NANDFlashDevice.NbBlocks-1; flashDev.param.n_reserved_blocks = 5; flashDev.param.n_caches = 10; flashDev.param.is_yaffs2 = 1; flashDev.param.erase_fn = yflash2_EraseBlockInNAND; flashDev.param.initialise_flash_fn = yflash2_InitialiseNAND; flashDev.param.write_chunk_tags_fn = yflash2_WriteChunkWithTagsToNAND; flashDev.param.read_chunk_tags_fn = yflash2_ReadChunkWithTagsFromNAND; flashDev.param.bad_block_fn = yflash2_MarkNANDBlockBad; flashDev.param.query_block_fn = yflash2_QueryNANDBlock; yaffs_add_device(&flashDev); return 0; }