uffs_badblock.c

Go to the documentation of this file.
00001 
00007 #include "uffs/uffs_fs.h"
00008 #include "uffs/uffs_config.h"
00009 #include "uffs/uffs_ecc.h"
00010 #include <string.h>
00011 
00012 #define PFX "badblock:"
00013 
00014 void uffs_InitBadBlock(uffs_Device *dev)
00015 {
00016     dev->bad.block = UFFS_INVALID_BLOCK;
00017 }
00018 
00029 URET uffs_CheckBadBlock(uffs_Device *dev, uffs_Buf *buf, int block)
00030 {
00031     u8 ecc[MAX_ECC_LENGTH];
00032     int ret;
00033 
00034     dev->flash->MakeEcc(dev, buf->data, ecc);
00035     ret = dev->flash->EccCollect(dev, buf->data, buf->ecc, ecc);
00036     if(ret > 0) {
00037         uffs_Perror(UFFS_ERR_NOISY, PFX"bad block(%d) found but corrected by ecc!\n", block);
00038 
00039         if (dev->bad.block == block) {
00040             uffs_Perror(UFFS_ERR_NORMAL, PFX"The bad block %d has been reported before.\n", block);
00041             return U_SUCC;
00042         }
00043 
00044         if (dev->bad.block != UFFS_INVALID_BLOCK) {
00045             uffs_Perror(UFFS_ERR_SERIOUS, PFX"uffs can't handle more than one bad block!\n");
00046             return U_FAIL;
00047         }
00052         dev->bad.block = block;
00053         return U_SUCC;
00054     }
00055     else if(ret < 0) {
00056         uffs_Perror(UFFS_ERR_SERIOUS, PFX"bad block(%d) found and can't be corrected by ecc!\n", block);
00057         if (dev->bad.block == block) {
00058             uffs_Perror(UFFS_ERR_NORMAL, PFX"The bad block %d has been reported before.\n", block);
00059             return U_FAIL;
00060         }
00061 
00062         if(dev->bad.block != UFFS_INVALID_BLOCK) {
00063             uffs_Perror(UFFS_ERR_SERIOUS, PFX"uffs can't handle more than one bad block!\n");
00064             return U_FAIL;
00065         }
00069         dev->bad.block = block;
00070         return U_FAIL;
00071     }
00072     
00073     //no error found
00074     return U_SUCC;
00075 }
00076 
00081 void uffs_RecoverBadBlock(uffs_Device *dev)
00082 {
00083     TreeNode *good, *bad;
00084     uffs_Buf *buf;
00085     u16 i;
00086     u16 page;
00087     uffs_blockInfo *bc = NULL;
00088     uffs_Tags *tag;
00089     uffs_Tags newTag;
00090     UBOOL succRecov;
00091     URET ret;
00092     int region;
00093     u8 type;
00094     
00095     if(dev->bad.block == UFFS_INVALID_BLOCK) return;
00096 
00097     //FIX ME!! TODO: recover the bad block to a good block
00098     good = uffs_GetErased(dev);
00099     if(good == NULL) {
00100         uffs_Perror(UFFS_ERR_SERIOUS, PFX"no free block to replace bad block!\n");
00101         return;
00102     }
00103 
00104     //recover block
00105     bc = uffs_GetBlockInfo(dev, dev->bad.block);
00106     
00107     if(bc == NULL) {
00108         uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't get bad block info\n");
00109         return;
00110     }
00111 
00112     succRecov = U_TRUE;
00113     for(i = 0; i < dev->attr.pages_per_block; i++) {
00114         page = uffs_FindPageInBlockWithPageId(dev, bc, i);
00115         if(page == UFFS_INVALID_PAGE) {
00116             break;  //end of last valid page, normal break
00117         }
00118         page = uffs_FindBestPageInBlock(dev, bc, page);
00119         tag = &(bc->spares[page].tag);
00120         buf = uffs_BufClone(dev, NULL);
00121         if(buf == NULL) {   
00122             uffs_Perror(UFFS_ERR_SERIOUS, PFX"Can't clone a new buf!\n");
00123             succRecov = U_FALSE;
00124             break;
00125         }
00126         //NOTE: since this is a bad block, we can't guarantee the data is ECC ok, so just load data even ECC is not OK.
00127         ret = uffs_LoadPhiDataToBufEccUnCare(dev, buf, bc->blockNum, page);
00128         if(ret == U_FAIL) {
00129             uffs_Perror(UFFS_ERR_SERIOUS, PFX"I/O error ?\n");
00130             uffs_BufFreeClone(dev, buf);
00131             succRecov = U_FALSE;
00132             break;
00133         }
00134         buf->dataLen = tag->dataLength;
00135         if(buf->dataLen > dev->com.pgDataSize) {
00136             uffs_Perror(UFFS_ERR_NOISY, PFX"data length over flow!!!\n");
00137             buf->dataLen = dev->com.pgDataSize;
00138         }
00139 
00140         buf->father = tag->father;
00141         buf->serial = tag->serial;
00142         buf->type = tag->type;
00143         buf->pageID = tag->pageID;
00144         
00145         newTag = *tag;
00146         newTag.blockTimeStamp = uffs_GetNextBlockTimeStamp(tag->blockTimeStamp);
00147         ret = uffs_WriteDataToNewPage(dev, good->u.list.block, i, &newTag, buf);
00148         uffs_BufFreeClone(dev, buf);
00149         if(ret != U_SUCC) {
00150             uffs_Perror(UFFS_ERR_NORMAL, PFX"I/O error ?\n");
00151             succRecov = U_FALSE;
00152             break;
00153         }
00154     }
00155 
00156 
00157     if(succRecov == U_TRUE) {
00158         //successful recover bad block, so need to mark bad block, and replace with good one
00159 
00160         region = SEARCH_REGION_DIR|SEARCH_REGION_FILE|SEARCH_REGION_DATA;
00161         bad = uffs_FindNodeByBlock(dev, dev->bad.block, &region);
00162         if(bad != NULL) {
00163             switch(region){
00164             case SEARCH_REGION_DIR:
00165                 bad->u.dir.block = good->u.list.block;
00166                 type = UFFS_TYPE_DIR;
00167                 break;
00168             case SEARCH_REGION_FILE:
00169                 bad->u.file.block = good->u.list.block;
00170                 type = UFFS_TYPE_FILE;
00171                 break;
00172             case SEARCH_REGION_DATA:
00173                 bad->u.data.block = good->u.list.block;
00174                 type = UFFS_TYPE_DATA;
00175             }
00176             
00177             //from now, the 'bad' is actually good block :)))
00178             uffs_Perror(UFFS_ERR_NOISY, PFX"new bad block %d found, and replaced by %d!\n", dev->bad.block, good->u.list.block);
00179             dev->ops->EraseBlock(dev, dev->bad.block);
00180             dev->flash->MakeBadBlockMark(dev, dev->bad.block);
00181             uffs_ExpireBlockInfo(dev, bc, UFFS_ALL_PAGES);
00182 
00183             //Now, we need to turn the good into 'bad', and put it into bad block list
00184             good->u.list.block = dev->bad.block;
00185             uffs_InsertToBadBlockList(dev, good);
00186 
00187             //clear bad block mark.
00188             dev->bad.block = UFFS_INVALID_BLOCK;
00189         }
00190         else {
00191             uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't find the reported bad block in the tree???\n");
00192             dev->ops->EraseBlock(dev, good->u.list.block);
00193             uffs_InsertToErasedListTail(dev, good);
00194         }
00195     }
00196     else {
00197         dev->ops->EraseBlock(dev, good->u.list.block);
00198         uffs_InsertToErasedListTail(dev, good); //put back to erased list
00199     }
00200 
00201     uffs_PutBlockInfo(dev, bc);
00202 
00203 }

Generated on Sat Mar 17 15:45:44 2007 for uffs-doc by  doxygen 1.5.0