00001
00007 #include "uffs/uffs_blockInfo.h"
00008 #include "uffs/uffs_public.h"
00009 #include "uffs/uffs_os.h"
00010
00011 #include <string.h>
00012
00013 #define PFX "bc:"
00014
00015 #define UFFS_CLONE_BLOCK_INFO_NEXT ((uffs_blockInfo *)(-2))
00016
00024 URET uffs_InitBlockInfoCache(uffs_Device *dev, int maxCachedBlocks)
00025 {
00026 u8 * eccs = NULL;
00027 uffs_blockInfo * blockInfos = NULL;
00028 uffs_pageSpare * pageSpares = NULL;
00029 void * buf = NULL;
00030 uffs_blockInfo *work = NULL;
00031 int size, i, j;
00032
00033 if(dev->bc.head != NULL) {
00034 uffs_Perror(UFFS_ERR_NOISY, PFX"block info cache has been inited already, now release it first.\n");
00035 uffs_ReleaseBlockInfoCache(dev);
00036 }
00037
00038 size = (
00039 sizeof(uffs_blockInfo) +
00040 sizeof(uffs_pageSpare) * dev->attr.pages_per_block
00041 ) * maxCachedBlocks;
00042
00043 buf = uffs_MemAlloc(dev, size);
00044 memset(buf, 0, size);
00045
00046 if(!buf) {
00047 uffs_Perror(UFFS_ERR_DEAD, "Alloc block cache buffer fail. size:%d bytes.", size);
00048 return U_FAIL;
00049 }
00050 dev->bc.internalBufHead = buf;
00051 dev->bc.maxBlockCached = maxCachedBlocks;
00052
00053 size = 0;
00054 blockInfos = (uffs_blockInfo *)buf;
00055 size += sizeof(uffs_blockInfo) * maxCachedBlocks;
00056
00057 pageSpares = (uffs_pageSpare *)((int)buf + size);
00058
00059
00060 work = &(blockInfos[0]);
00061 dev->bc.head = work;
00062 work->refCount = 0;
00063 work->prev = NULL;
00064 work->next = &(blockInfos[1]);
00065 work->blockNum = UFFS_INVALID_BLOCK;
00066
00067 for( i = 0; i < maxCachedBlocks - 2; i++) {
00068 work = &(blockInfos[i+1]);
00069 work->prev = &(blockInfos[i]);
00070 work->next = &(blockInfos[i+2]);
00071 work->refCount = 0;
00072 work->blockNum = UFFS_INVALID_BLOCK;
00073 }
00074
00075 work = &(blockInfos[i+1]);
00076 work->prev = &(blockInfos[i]);
00077 work->next = NULL;
00078 work->blockNum = UFFS_INVALID_BLOCK;
00079 work->refCount = 0;
00080 dev->bc.tail = work;
00081
00082
00083 work = dev->bc.head;
00084 for( i = 0; i < maxCachedBlocks; i++) {
00085 work->spares = &(pageSpares[i*dev->attr.pages_per_block]);
00086 for(j = 0; j < dev->attr.pages_per_block; j++) {
00087 work->spares[j].expired = 1;
00088 }
00089 work->expiredCount = dev->attr.pages_per_block;
00090 work = work->next;
00091 }
00092 return U_SUCC;
00093 }
00094
00100 URET uffs_ReleaseBlockInfoCache(uffs_Device *dev)
00101 {
00102 uffs_blockInfo *work;
00103
00104 if(dev->bc.head) {
00105 for(work = dev->bc.head; work != NULL; work = work->next) {
00106 if(work->refCount != 0) {
00107 uffs_Perror(UFFS_ERR_SERIOUS, PFX "There have refed block info cache, release cache fail.\n");
00108 return U_FAIL;
00109 }
00110 }
00111 uffs_MemFree(dev, dev->bc.internalBufHead);
00112 }
00113
00114 dev->bc.head = dev->bc.tail = NULL;
00115 dev->bc.internalBufHead = NULL;
00116 return U_SUCC;
00117 }
00118
00119 static void _BreakBcFromList(uffs_Device *dev, uffs_blockInfo *bc)
00120 {
00121 if(bc->prev) {
00122 bc->prev->next = bc->next;
00123 }
00124 if(bc->next) {
00125 bc->next->prev = bc->prev;
00126 }
00127 if(dev->bc.head == bc) dev->bc.head = bc->next;
00128 if(dev->bc.tail == bc) dev->bc.tail = bc->prev;
00129 }
00130
00131 static void _InsertToBcListTail(uffs_Device *dev, uffs_blockInfo *bc)
00132 {
00133 bc->next = NULL;
00134 bc->prev = dev->bc.tail;
00135 bc->prev->next = bc;
00136 dev->bc.tail = bc;
00137 }
00138
00139 static void _MoveBcToTail(uffs_Device *dev, uffs_blockInfo *bc)
00140 {
00141 _BreakBcFromList(dev, bc);
00142 _InsertToBcListTail(dev, bc);
00143 }
00144
00150 void uffs_CheckPageSpare(uffs_Device *dev, uffs_pageSpare *spare)
00151 {
00152 if(uffs_CalTagCheckSum(&(spare->tag)) == spare->tag.checkSum) {
00153 spare->checkOk = 1;
00154 }
00155 else {
00156 spare->checkOk = 0;
00157 }
00158 }
00159
00171 URET uffs_LoadBlockInfo(uffs_Device *dev, uffs_blockInfo *work, int page)
00172 {
00173 int i;
00174 uffs_pageSpare *spare;
00175
00176 if(page == UFFS_ALL_PAGES) {
00177 for(i = 0; i < dev->attr.pages_per_block; i++) {
00178 spare = &(work->spares[i]);
00179 if(spare->expired == 0) continue;
00180
00181 if( dev->flash->LoadPageSpare(dev, work->blockNum, i, &(spare->tag)) == U_FAIL ) {
00182 uffs_Perror(UFFS_ERR_SERIOUS, PFX "load block %d page %d spare fail.", work->blockNum, i);
00183 return U_FAIL;
00184 }
00185 uffs_CheckPageSpare(dev, spare);
00186 spare->expired = 0;
00187 work->expiredCount--;
00188 }
00189 }
00190 else {
00191 if(page < 0 || page >= dev->attr.pages_per_block) {
00192 uffs_Perror(UFFS_ERR_SERIOUS, PFX "page out of range !\n");
00193 return U_FAIL;
00194 }
00195 spare = &(work->spares[page]);
00196 if(spare->expired != 0) {
00197 if( dev->flash->LoadPageSpare(dev, work->blockNum, page, &(spare->tag)) == U_FAIL ) {
00198 uffs_Perror(UFFS_ERR_SERIOUS, PFX "load block %d page %d spare fail.", work->blockNum, page);
00199 return U_FAIL;
00200 }
00201 uffs_CheckPageSpare(dev, spare);
00202 spare->expired = 0;
00203 work->expiredCount--;
00204 }
00205 }
00206 return U_SUCC;
00207 }
00208
00209
00218 uffs_blockInfo * uffs_FindBlockInfoInCache(uffs_Device *dev, int block)
00219 {
00220 uffs_blockInfo *work;
00221
00222
00223 for(work = dev->bc.head; work != NULL; work = work->next) {
00224 if(work->blockNum == block) {
00225 work->refCount++;
00226 return work;
00227 }
00228 }
00229 return NULL;
00230 }
00231
00232
00243 uffs_blockInfo * uffs_GetBlockInfo(uffs_Device *dev, int block)
00244 {
00245 uffs_blockInfo *work;
00246 int i;
00247
00248
00249 if((work = uffs_FindBlockInfoInCache(dev, block)) != NULL) {
00250 _MoveBcToTail(dev, work);
00251 return work;
00252 }
00253
00254
00255 for(work = dev->bc.head; work != NULL; work = work->next) {
00256 if(work->refCount == 0) break;
00257 }
00258 if(work == NULL) {
00259
00260 uffs_Perror(UFFS_ERR_SERIOUS, PFX "insufficient block info cache\n");
00261 return NULL;
00262 }
00263
00264 work->blockNum = block;
00265 work->expiredCount = dev->attr.pages_per_block;
00266 for(i = 0; i < dev->attr.pages_per_block; i++) {
00267 work->spares[i].expired = 1;
00268 }
00269
00270 work->refCount = 1;
00271
00272 _MoveBcToTail(dev, work);
00273
00274 return work;
00275 }
00276
00282 void uffs_PutBlockInfo(uffs_Device *dev, uffs_blockInfo *p)
00283 {
00284 if(p->refCount == 0) {
00285 uffs_Perror(UFFS_ERR_SERIOUS, PFX "Put an unused block info cache back ?\n");
00286 }
00287 else {
00288 p->refCount--;
00289 }
00290 }
00291
00292
00299 void uffs_ExpireBlockInfo(uffs_Device *dev, uffs_blockInfo *p, int page)
00300 {
00301 int i;
00302 uffs_pageSpare *spare;
00303
00304 if(page == UFFS_ALL_PAGES) {
00305 for(i = 0; i < dev->attr.pages_per_block; i++) {
00306 spare = &(p->spares[i]);
00307 if(spare->expired == 0) {
00308 spare->expired = 1;
00309 p->expiredCount++;
00310 }
00311 }
00312 }
00313 else {
00314 if(page >= 0 && page < dev->attr.pages_per_block) {
00315 spare = &(p->spares[page]);
00316 if(spare->expired == 0) {
00317 spare->expired = 1;
00318 p->expiredCount++;
00319 }
00320 }
00321 }
00322 }
00323
00327 UBOOL uffs_IsAllBlockInfoFree(uffs_Device *dev)
00328 {
00329 uffs_blockInfo *work;
00330
00331 work = dev->bc.head;
00332 while(work) {
00333 if(work->refCount != 0) return U_FALSE;
00334 work = work->next;
00335 }
00336
00337 return U_TRUE;
00338 }
00339
00340 void uffs_ExpireAllBlockInfo(uffs_Device *dev)
00341 {
00342 uffs_blockInfo *bc;
00343
00344 bc = dev->bc.head;
00345 while(bc) {
00346 uffs_ExpireBlockInfo(dev, bc, UFFS_ALL_PAGES);
00347 bc = bc->next;
00348 }
00349 return;
00350 }