日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Cosmos OpenSSD--greedy_ftl1.2.0(一)

發布時間:2024/4/17 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Cosmos OpenSSD--greedy_ftl1.2.0(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

從主函數跳到ReqHandler,在ReqHandler內先初始化SSD--InitNandReset,然后建立映射表InitFtlMapTable

1 void InitNandReset() 2 { 3 // reset SSD 4 int i, j; 5 for(i=0; i<CHANNEL_NUM; ++i) 6 { 7 for(j=0; j<WAY_NUM; ++j) 8 { 9 WaitWayFree(i, j); 10 SsdReset(i, j); 11 } 12 } 13 14 // change SSD mode 15 for(i=0; i<CHANNEL_NUM; ++i) 16 { 17 for(j=0; j<WAY_NUM; ++j) 18 { 19 WaitWayFree(i, j); 20 SsdModeChange(i, j); 21 } 22 } 23 24 print("\n[ ssd NAND device reset complete. ]\r\n"); 25 } InitNandReset

遍歷每條channel每條way來重啟,change mode

接下來來看怎么建立映射表InitFtlMapTable

1 void InitFtlMapTable() 2 { 3 InitPageMap(); 4 InitBlockMap(); 5 InitDieBlock(); 6 7 InitGcMap(); 8 }

這里有四步,我們一步一步來分析


?首先是頁表建立,InitPageMap

#define RAM_DISK_BASE_ADDR 0x10000000

#define PAGE_MAP_ADDR (RAM_DISK_BASE_ADDR + (0x1 << 27))    //PAGE_MAP_ADDR?=0x18000000

?

?#define? CHANNEL_NUM? 4                        //4個channel ?#define? WAY_NUM? 4                          //每個channel4條way ?#define? DIE_NUM? (CHANNEL_NUM * WAY_NUM) =16          //每條way上連著一個die ? ?#define ? PAGE_NUM_PER_BLOCK? 256                  //每個塊256個page ?#define? BLOCK_NUM_PER_DIE? 4096                  //每個die4096個block

#define? PAGE_NUM_PER_DIE? (PAGE_NUM_PER_BLOCK * BLOCK_NUM_PER_DIE) 

?

struct pmEntry {
  u32 ppn; // Physical Page Number (PPN) to which a logical page is mapped

  u32 valid : 1; // validity of a physical page
  u32 lpn : 31; // Logical Page Number (LPN) of a physical page
};

每個entry頁表構造如下圖

?每個入口8Byte

?

struct pmArray {
  struct pmEntry pmEntry[DIE_NUM][PAGE_NUM_PER_DIE];    //頁表entry個數為DIE_NUM *?PAGE_NUM_PER_DIE = 16*4096*256 = 224
};

這樣頁表大小就為?224?* 8Byte = 128MB

1 void InitPageMap() 2 { 3 pageMap = (struct pmArray*)(PAGE_MAP_ADDR); 4 5 // page status initialization, allows lpn, ppn access 6 int i, j; 7 for(i=0 ; i<DIE_NUM ; i++) 8 { 9 for(j=0 ; j<PAGE_NUM_PER_DIE ; j++) 10 { 11 pageMap->pmEntry[i][j].ppn = 0xffffffff; 12 13 pageMap->pmEntry[i][j].valid = 1; 14 pageMap->pmEntry[i][j].lpn = 0x7fffffff; 15 } 16 } 17 18 xil_printf("[ ssd page map initialized. ]\r\n"); 19 }

?這里將設置每個頁表entry的初始值,


?接下來分析InitBlockMap

#define BLOCK_MAP_ADDR (PAGE_MAP_ADDR + sizeof(struct pmEntry) * PAGE_NUM_PER_SSD)  //塊表是在頁表之后繼續建立

?

struct bmEntry {
  u32 bad : 1;
  u32 free : 1;
  u32 eraseCnt : 30;
  u32 invalidPageCnt : 16;
  u32 currentPage : 16;
  u32 prevBlock;
  u32 nextBlock;
};

每個塊entry構造圖如下,占據16Byte

?

struct bmArray {
  struct bmEntry bmEntry[DIE_NUM][BLOCK_NUM_PER_DIE];    //塊表入口數為 16 * 4096 = 216,所以塊表大小為216?*?16Byte = 1MB
};

分配塊表之后,首先先檢測壞塊--CheckBadBlock

   blockMap = (struct bmArray*)(BLOCK_MAP_ADDR);u32 dieNo, diePpn, blockNo, tempBuffer, badBlockCount;u8* shifter;u8* markPointer;int loop;markPointer = (u8*)(RAM_DISK_BASE_ADDR + BAD_BLOCK_MARK_POSITION);

#define BAD_BLOCK_MARK_POSITION (7972)  //代表著壞塊標記的偏移量

//read badblock marksloop = DIE_NUM *BLOCK_NUM_PER_DIE;dieNo = METADATA_BLOCK_PPN % DIE_NUM;diePpn = METADATA_BLOCK_PPN / DIE_NUM;tempBuffer = RAM_DISK_BASE_ADDR;while(loop > 0){SsdRead(dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM, diePpn, tempBuffer);WaitWayFree(dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM);diePpn++;tempBuffer += PAGE_SIZE;loop -= PAGE_SIZE;}

疑問:dieNo =0,diePpn=0,進入循環之后,讀取channel0,way0的第01234567頁存在tempbuffer里面,8頁大小為64KB,一個字節記錄一個塊的信息的話,那么大小也為1Byte*16*4096=64KB,其中因為第一個塊廠家保證是好的,所以不需要保存是否為壞塊,所以里面可以存一個標記位,表示是否有現成的壞塊信息表

1 if(*shifter == EMPTY_BYTE) //check whether badblock marks exist 2 { 3 // static bad block management 4 for(blockNo=0; blockNo < BLOCK_NUM_PER_DIE; blockNo++) 5 for(dieNo=0; dieNo < DIE_NUM; dieNo++) 6 { 7 blockMap->bmEntry[dieNo][blockNo].bad = 0; 8 9 SsdRead(dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM, (blockNo*PAGE_NUM_PER_BLOCK+1), RAM_DISK_BASE_ADDR); 10 WaitWayFree(dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM); 11 12 if(CountBits(*markPointer)<4) 13 { 14 xil_printf("Bad block is detected on: Ch %d Way %d Block %d \r\n",dieNo%CHANNEL_NUM, dieNo/CHANNEL_NUM, blockNo); 15 blockMap->bmEntry[dieNo][blockNo].bad = 1; 16 badBlockCount++; 17 } 18 shifter= (u8*)(GC_BUFFER_ADDR + blockNo + dieNo *BLOCK_NUM_PER_DIE );//gather badblock mark at GC buffer 19 *shifter = blockMap->bmEntry[dieNo][blockNo].bad; 20 } 21 22 // save bad block mark 23 loop = DIE_NUM *BLOCK_NUM_PER_DIE; 24 dieNo = METADATA_BLOCK_PPN % DIE_NUM; 25 diePpn = METADATA_BLOCK_PPN / DIE_NUM; 26 blockNo = diePpn / PAGE_NUM_PER_BLOCK; 27 28 SsdErase(dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM, blockNo); 29 WaitWayFree(dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM); 30 31 tempBuffer = GC_BUFFER_ADDR; 32 while(loop>0) 33 { 34 WaitWayFree(dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM); 35 SsdProgram(dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM, diePpn, tempBuffer); 36 diePpn++; 37 tempBuffer += PAGE_SIZE; 38 loop -= PAGE_SIZE; 39 } 40 xil_printf("[ Bad block Marks are saved. ]\r\n"); 41 }

第九行為什么是讀取每個塊第一頁的內容而不是第零頁的內容?

12行位數小于4位就是壞塊?

else //read existing bad block marks {for(blockNo=0; blockNo<BLOCK_NUM_PER_DIE; blockNo++)for(dieNo=0; dieNo<DIE_NUM; dieNo++){shifter = (u8*)(RAM_DISK_BASE_ADDR + blockNo + dieNo *BLOCK_NUM_PER_DIE );blockMap->bmEntry[dieNo][blockNo].bad = *shifter;if(blockMap->bmEntry[dieNo][blockNo].bad){xil_printf("Bad block mark is checked at: Ch %d Way %d Block %d \r\n",dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM, blockNo );badBlockCount++;}}xil_printf("[ Bad blocks are checked. ]\r\n");}// save bad block sizeBAD_BLOCK_SIZE = badBlockCount * BLOCK_SIZE_MB;

?接下來是InitBlockMap的代碼

blockMap = (struct bmArray*)(BLOCK_MAP_ADDR);CheckBadBlock();// block status initialization except bad block marks, allows only physical accessint i, j;for(i=0 ; i<BLOCK_NUM_PER_DIE ; i++){for(j=0 ; j<DIE_NUM ; j++){blockMap->bmEntry[j][i].free = 1;blockMap->bmEntry[j][i].eraseCnt = 0;blockMap->bmEntry[j][i].invalidPageCnt = 0;blockMap->bmEntry[j][i].currentPage = 0x0;blockMap->bmEntry[j][i].prevBlock = 0xffffffff;blockMap->bmEntry[j][i].nextBlock = 0xffffffff;}}

初始化塊表的一些值

for (i = 0; i < BLOCK_NUM_PER_DIE; ++i)for (j = 0; j < DIE_NUM; ++j)if (!blockMap->bmEntry[j][i].bad && ((i != METADATA_BLOCK_PPN % DIE_NUM)|| (j != (METADATA_BLOCK_PPN / DIE_NUM) / PAGE_NUM_PER_BLOCK))){// initial block eraseWaitWayFree(j % CHANNEL_NUM, j / CHANNEL_NUM);SsdErase(j % CHANNEL_NUM, j / CHANNEL_NUM, i);}
  xil_printf("[ ssd entire block erasure completed. ]\r\n");

?除了die0的block0之外,全部擦除

for(i=0 ; i<DIE_NUM ; i++){// initially, 0th block of each die is allocated for storage start pointblockMap->bmEntry[i][0].free = 0;blockMap->bmEntry[i][0].currentPage = 0xffff;// initially, the last block of each die is reserved as free block for GC migrationblockMap->bmEntry[i][BLOCK_NUM_PER_DIE-1].free = 0;}//block0 of die0 is metadata blockblockMap->bmEntry[0][1].free = 0;blockMap->bmEntry[0][1].currentPage = 0xffff;xil_printf("[ ssd block map initialized. ]\r\n");

因為die0的第一個block是用來存儲元數據,所以他開始的塊指針為第一塊

每個die的開始和最后一塊都不能用,die0的第一塊也不讓用


#define DIE_MAP_ADDR (BLOCK_MAP_ADDR + sizeof(struct bmEntry) * BLOCK_NUM_PER_SSD)

?

struct dieEntry {
u32 currentBlock;
u32 freeBlock;
};

struct dieArray {
struct dieEntry dieEntry[DIE_NUM];
};

void InitDieBlock() {dieBlock = (struct dieArray*)(DIE_MAP_ADDR);// xil_printf("DIE_MAP_ADDR : %8x\r\n", DIE_MAP_ADDR);int i;for(i=0 ; i<DIE_NUM ; i++){if(i==0) // prevent to write at meta data blockdieBlock->dieEntry[i].currentBlock = 1;elsedieBlock->dieEntry[i].currentBlock = 0;dieBlock->dieEntry[i].freeBlock = BLOCK_NUM_PER_DIE - 1;}xil_printf("[ ssd die map initialized. ]\r\n"); }

?freeblock用作垃圾回收


struct gcEntry {
u32 head;
u32 tail;
};

struct gcArray {
struct gcEntry gcEntry[DIE_NUM][PAGE_NUM_PER_BLOCK+1];
};

void InitGcMap() {gcMap = (struct gcArray*)(GC_MAP_ADDR);// xil_printf("GC_MAP_ADDR : %8x\r\n", GC_MAP_ADDR);// gc table status initializationint i, j;for(i=0 ; i<DIE_NUM ; i++){for(j=0 ; j<PAGE_NUM_PER_BLOCK+1 ; j++){gcMap->gcEntry[i][j].head = 0xffffffff;gcMap->gcEntry[i][j].tail = 0xffffffff;}}xil_printf("[ ssd gc map initialized. ]\r\n"); }

?

  

?

轉載于:https://www.cnblogs.com/losing-1216/p/4919765.html

與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的Cosmos OpenSSD--greedy_ftl1.2.0(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。