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
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
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
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;
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
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
00159
00160 region = SEARCH_REGION_DIR|SEARCH_REGION_FILE|SEARCH_REGION_DATA;
00161 bad = uffs_FindNodeByBlock(dev, dev->bad.block, ®ion);
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
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
00184 good->u.list.block = dev->bad.block;
00185 uffs_InsertToBadBlockList(dev, good);
00186
00187
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);
00199 }
00200
00201 uffs_PutBlockInfo(dev, bc);
00202
00203 }