Mercurial > yaffs-ecoscentric
view packages/fs/yaffs/current/src/ecos-yaffs-nand.c @ 300:9c8ff034abb0
Graft in 20090826 source snapshot
| author | Ross Younger <wry@ecoscentric.com> |
|---|---|
| date | Tue, 03 Nov 2009 12:15:09 +0000 |
| parents | |
| children | 16de60f90faa |
line wrap: on
line source
//============================================================================= // // ecos-yaffs-nand.c // // Glue for YAFFS to the eCos NAND library // //============================================================================= // ####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 2009 eCosCentric Limited. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later // version. // // eCos is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License // along with eCos; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // As a special exception, if other files instantiate templates or use // macros or inline functions from this file, or you compile this file // and link it with other works to produce a work based on this file, // this file does not by itself cause the resulting work to be covered by // the GNU General Public License. However the source code for this file // must still be made available in accordance with section (3) of the GNU // General Public License v2. // // This exception does not invalidate any other reasons why a work based // on this file might be covered by the GNU General Public License. // ------------------------------------------- // ####ECOSGPLCOPYRIGHTEND#### //============================================================================= //#####DESCRIPTIONBEGIN#### // // Author(s): wry // Date: 2009-05-07 // //####DESCRIPTIONEND#### //============================================================================= #include "ecos-yaffs.h" #include "ecos-yaffs-nand.h" #include "yaffs_packedtags1.h" #include "yaffs_packedtags2.h" #include "yaffs_tagscompat.h" #include <cyg/nand/util.h> // for BLOCK2PAGEADDR int eyaffs_initialiseNAND (struct yaffs_DeviceStruct * dev) { // Nothing to do - we've already inited it in mount(). //cyg_nand_partition *part = (cyg_nand_partition*) dev->genericDevice; return YAFFS_OK; } int eyaffs_deinitialiseNAND (struct yaffs_DeviceStruct * dev) { // Nothing to do //cyg_nand_partition *part = (cyg_nand_partition*) dev->genericDevice; return YAFFS_OK; } int eyaffs_eraseBlockInNAND (struct yaffs_DeviceStruct * dev, int blockInNAND) { cyg_nand_partition *part = (cyg_nand_partition*) dev->genericDevice; int rv = cyg_nand_erase_block(part, blockInNAND); return rv==0 ? YAFFS_OK : YAFFS_FAIL; } // If writing a yaffs_PackedTags1, we store only its eight meaningful bytes #define PACKEDTAGS1_OOBSIZE 8 int eyaffs_writeChunkWithTagsToNAND (struct yaffs_DeviceStruct * dev, int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * tags) { cyg_nand_partition *part = (cyg_nand_partition*) dev->genericDevice; int rv; if (!dev->isYaffs2) { #ifdef CONFIG_YAFFS_NO_YAFFS1 rv = 1; #else yaffs_PackedTags1 pt1; if (tags->chunkDeleted) { memset(&pt1, 0xff, sizeof(pt1)); pt1.deleted = 0; //((CYG_BYTE*)&pt1)[8] = 0; // TODO: support 9BYTE_TAGS, if there is a demand to (requires corresponding fixup in the ECC check below) } else { yaffs_PackTags1(&pt1, tags); yaffs_CalcTagsECC((yaffs_Tags *)&pt1); } rv = cyg_nand_write_page(part, chunkInNAND, data, data ? dev->nDataBytesPerChunk : 0, &pt1, PACKEDTAGS1_OOBSIZE); #endif } else { #ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE return YAFFS_FAIL; #else // YAFFS2 mode. // N.B. We are not doing ECC - the NAND layer does that - so don't // need to bother with the whole tags struct, just the bit that matters. if (!data || !tags) { T(YAFFS_TRACE_ERROR, (TSTR("**>> yaffs2: both data and tags must be present" TENDSTR))); YBUG(); return YAFFS_FAIL; } if (dev->inbandTags) { yaffs_PackedTags2TagsPart *pt2tp; pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk); yaffs_PackTags2TagsPart(pt2tp, tags); rv = cyg_nand_write_page(part, chunkInNAND, data, dev->totalBytesPerChunk, 0, 0); } else { yaffs_PackedTags2TagsPart pt; yaffs_PackTags2TagsPart(&pt, tags); rv = cyg_nand_write_page(part, chunkInNAND, data, dev->nDataBytesPerChunk, &pt, sizeof(yaffs_PackedTags2TagsPart)); } #endif } // all done: return rv==0 ? YAFFS_OK : YAFFS_FAIL; } int eyaffs_readChunkWithTagsFromNAND (struct yaffs_DeviceStruct * dev, int chunkInNAND, __u8 * data, yaffs_ExtendedTags * tags) { cyg_nand_partition *part = (cyg_nand_partition*) dev->genericDevice; int localData = 0; int rv; if (!dev->isYaffs2) { #ifdef CONFIG_YAFFS_NO_YAFFS1 rv = 1; #else yaffs_PackedTags1 pt1; memset(&pt1, 0xff, sizeof(yaffs_PackedTags1)); rv = cyg_nand_read_page(part, chunkInNAND, data, data ? dev->nDataBytesPerChunk : 0, &pt1, PACKEDTAGS1_OOBSIZE); if (rv == 0) { if (yaffs_CheckFF((CYG_BYTE*)&pt1, 8)) { // block is empty if (tags) { memset(tags, 0, sizeof(*tags)); tags->eccResult = YAFFS_ECC_RESULT_NO_ERROR; } } else { // must check and correct tags' mini-ecc. int deleted = !pt1.deleted; // this would break the tags ECC. pt1.deleted = 1; // TODO: support 9BYTE_TAGS if there is a demand. int rv2 = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1); if (rv2 < 0) { T(YAFFS_TRACE_ERROR, (TSTR ("**>>yaffs ecc error unfixed on chunk %d:0" TENDSTR), chunkInNAND)); dev->eccUnfixed++; rv = EIO; } else { if (tags) { yaffs_UnpackTags1(tags, &pt1); tags->chunkDeleted = deleted; tags->eccResult = YAFFS_ECC_RESULT_NO_ERROR; } if (rv2 > 0) { T(YAFFS_TRACE_ERROR, (TSTR ("**>>yaffs ecc tags error fix performed on chunk %d:0" TENDSTR), chunkInNAND)); dev->eccFixed++; if (tags) tags->eccResult = YAFFS_ECC_RESULT_FIXED; } } } } // else reading the NAND failed; drop out #endif } else { // YAFFS2 mode #ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE return YAFFS_FAIL; #else if (dev->inbandTags) { if (!data) { localData = 1; data = yaffs_GetTempBuffer(dev, __LINE__); } rv = cyg_nand_read_page(part, chunkInNAND, data, data ? dev->totalBytesPerChunk : 0, 0, 0); if (tags) { yaffs_PackedTags2TagsPart *pt2tp; pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk]; yaffs_UnpackTags2TagsPart(tags, pt2tp); } } else { yaffs_PackedTags2TagsPart pt; rv = cyg_nand_read_page(part, chunkInNAND, data, data ? dev->nDataBytesPerChunk : 0, &pt, sizeof(yaffs_PackedTags2TagsPart)); if (tags) yaffs_UnpackTags2TagsPart(tags, &pt); } #endif } // all done: if (localData) yaffs_ReleaseTempBuffer(dev, data, __LINE__); if (rv != 0) { if (tags) { // mark the tags as clearly useless memset(tags, 0, sizeof(yaffs_ExtendedTags)); tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; tags->blockBad = 1; } return YAFFS_FAIL; } return YAFFS_OK; // TODO: go through yaffs_guts and ensure that all calls to ReadChunksWithTagsFromNAND DTRT on FAIL or if the read tags aren't valid. } int eyaffs_markNANDBlockBad (struct yaffs_DeviceStruct * dev, int blockNo) { cyg_nand_partition *part = (cyg_nand_partition*) dev->genericDevice; int rv = cyg_nand_bbt_markbad(part, blockNo); return rv==0 ? YAFFS_OK : YAFFS_FAIL; } int eyaffs_queryNANDBlock (struct yaffs_DeviceStruct * dev, int blockNo, yaffs_BlockState * state, __u32 *sequenceNumber) { yaffs_ExtendedTags tags; cyg_nand_page_addr pg; cyg_nand_partition *part = (cyg_nand_partition*) dev->genericDevice; int rv = cyg_nand_bbt_query(part, blockNo); if (rv < 0) return YAFFS_FAIL; switch(rv) { case CYG_NAND_BBT_OK: // Now we need to read the tags from the OOB area of the first page pg = CYG_NAND_BLOCK2PAGEADDR(part->dev, blockNo); // TODO: This is quite inefficient on small page devices in // YAFFS2 mode with inbandTags enabled, as the whole page has // to be read. Some day, it would be nice to implement part-page // reads in the NAND layer where this can be efficiently done. int rv2 = eyaffs_readChunkWithTagsFromNAND(dev, pg, 0, &tags); if (rv2 == YAFFS_FAIL) { (void) cyg_nand_bbt_markbad(part, blockNo); goto deadblock; } if (tags.chunkUsed) { *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; *sequenceNumber = tags.sequenceNumber; return YAFFS_OK; } *state = YAFFS_BLOCK_STATE_EMPTY; *sequenceNumber = 0; return YAFFS_OK; case CYG_NAND_BBT_WORNBAD: case CYG_NAND_BBT_RESERVED: case CYG_NAND_BBT_FACTORY_BAD: deadblock: *state = YAFFS_BLOCK_STATE_DEAD; *sequenceNumber = 0; return YAFFS_OK; default: YBUG(); // can't happen return YAFFS_FAIL; } }
