zoukankan      html  css  js  c++  java
  • 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("
    [ ssd NAND device reset complete. ]
    ");
    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. ]
    ");
    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 marks
        loop = 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 
    ",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. ]
    ");
    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  
    ",dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM, blockNo );
                        badBlockCount++;
                    }
                }
    
            xil_printf("[ Bad blocks are checked. ]
    ");
        }
    
        // save bad block size
        BAD_BLOCK_SIZE = badBlockCount * BLOCK_SIZE_MB;

     接下来是InitBlockMap的代码

        blockMap = (struct bmArray*)(BLOCK_MAP_ADDR);
    
        CheckBadBlock();
    
        // block status initialization except bad block marks, allows only physical access
        int 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 erase
                    WaitWayFree(j % CHANNEL_NUM, j / CHANNEL_NUM);
                    SsdErase(j % CHANNEL_NUM, j / CHANNEL_NUM, i);
                }
      xil_printf("[ ssd entire block erasure completed. ] ");

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

        for(i=0 ; i<DIE_NUM ; i++)
        {
            // initially, 0th block of each die is allocated for storage start point
            blockMap->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 migration
            blockMap->bmEntry[i][BLOCK_NUM_PER_DIE-1].free = 0;
        }
        //block0 of die0 is metadata block
        blockMap->bmEntry[0][1].free = 0;
        blockMap->bmEntry[0][1].currentPage = 0xffff;
    
        xil_printf("[ ssd block map initialized. ]
    ");

    因为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
    ", DIE_MAP_ADDR);
    
        int i;
        for(i=0 ; i<DIE_NUM ; i++)
        {
            if(i==0) // prevent to write at meta data block
                dieBlock->dieEntry[i].currentBlock = 1;
            else
                dieBlock->dieEntry[i].currentBlock = 0;
            dieBlock->dieEntry[i].freeBlock = BLOCK_NUM_PER_DIE - 1;
        }
    
        xil_printf("[ ssd die map initialized. ]
    ");
    }

     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
    ", GC_MAP_ADDR);
    
        // gc table status initialization
        int 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. ]
    ");
    }

     

      

  • 相关阅读:
    Asp.net实现URL重写
    IHttpModule不起作用的两个原因
    从客户端中检测到有潜在危险的 request.form值[解决方法]
    PHP $_SERVER详解
    string.Format 格式化日期格式
    图解正向代理、反向代理、透明代理
    Javacard 解释器怎样在API类库中找到源文件调用的类、方法或者静态域?
    API
    指令集
    机器码与字节码
  • 原文地址:https://www.cnblogs.com/losing-1216/p/4919765.html
Copyright © 2011-2022 走看看