从主函数跳到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

Cosmos OpenSSD--greedy_ftl1.2.0(一)相关推荐

  1. Cosmos 白皮书

    Table of Contents 介绍 Tendermint 验证人 共识 轻客户端 防止攻击 ABCI Cosmos 概述 Tendermint-拜占庭容错 治理 枢纽与分区 枢纽 分区 跨链通信 ...

  2. 估算带卷积核二分类0,3的网络的收敛时间和迭代次数

    制作一个网络分类minst的0和3求出这网络的迭代次数曲线表达式n(δ),和准确率表达式p-max(δ),用预期准确率去估算n,并推算需要的时间. 将minst的28*28的图片缩小到9*9,网络用一 ...

  3. java 汉明距离_Java实现 LeetCode 461 汉明距离

    461. 汉明距离 两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目. 给出两个整数 x 和 y,计算它们之间的汉明距离. 注意: 0 ≤ x, y < 231. 示例: 输入 ...

  4. python自制linux桌面,自己动手写Python实现Ubuntu自动切换壁纸

    使用Windows 7一段时间,觉得它的自动换壁纸也挺好用的,换到Ubuntu 11.04上,本想装个软件让它自动换,后来发现Drapes运行不了,又懒得装其他软件了. 于是想按照别人说的写个shel ...

  5. 利用archetype创建maven脚手架和新项目

    一.基于maven脚手架创建新的项目(如何生成maven脚手架本文后面会有详细说明): 1.在maven的本地环境(比如C:\Users\dell\.m2)下新建文件archetype-catalog ...

  6. 主流链分片技术和共识算法

    前言 设计到的链:Harmony.Elrond.Cosmos.ETH 2.0.Polkadot.Near Protocol 一. 主流链所用的分片技术对比 1.0 Harmony Harmony 是一 ...

  7. 全面回顾2022年加密行业大事件:破后而立方能绝处逢生

    2022年,加密领域以Luna/UST的崩溃为起点开启了漫长的加密寒冬,在严峻的宏观环境下以及一系列戏剧性事件中遭受了沉重打击.2022年初,加密货币生态系统的市值达到近3万亿美元,而截至年底已蒸发2 ...

  8. linux系统下的动态壁纸,Ubuntu 10.04下实现动态桌面壁纸

    不知大家在使用Ubuntu时有没有注意到,Ubuntu下是可以实现多张壁纸动态切换的,好像Win7下也有类似的功能(曾经使用 win7一段时间).我也是最近才注意到这点,下面是在Ubuntu 10.0 ...

  9. 神经网络收敛标准与准确率之间的数学关系

    制作一个带一个3*3卷积核的神经网络,测试集是minst的0和2图片集,将28*28的图片缩小成9*9,隐藏层30个节点所以网络的结构是 S(minst0)-(con3*3)49-30-2-(1,0) ...

  10. 用共振频率去进行图片分类的尝试

    假设有一种物质,这种物质的原子核的质子数和电子数可以不同,允许质子的带电量不同,并且质子带负电,同时这个原子的电子不满足鲍利不相容原理,环境温度是 (1/1.3806505)*10^23k,电子波的频 ...

最新文章

  1. PHP 毫秒级定时器,实现php毫秒定时器方法详解
  2. PowerDesigner设计的数据库 ORA-0092
  3. 空行替换_Word怎么批量删除空行和空格?有技巧很简单!
  4. 11.4 iftop:动态显示网络接口流量信息
  5. 人工机器:机器人模块化和双足机器人被动行走
  6. 扩大VMware虚拟机中linux硬盘空间
  7. GenXus学习笔记——Transaction的建立
  8. AWD-LSTM为什么这么棒?
  9. 2017.5.6 子矩阵 思考记录
  10. ORACLE 一些时间查询方式
  11. 50 - 算法- LeetCode 104 -二叉树
  12. 案例:Oracle dul数据挖掘 没有数据库备份非常规恢复truncate删除的数据表
  13. css3制作俩面翻转盒子效果
  14. HTML — 快速开发总结篇
  15. Bus Hound 使用指南
  16. Java线程之线程的五种状态
  17. Java进阶——Java中的字符串常量池
  18. OpenG利用glreadPixel实现截屏功能
  19. 金山 V8 终端安全系统 默认弱口令漏洞
  20. vue : 无法将“vue”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确, 然后再试一次 必解决技巧

热门文章

  1. 三个最简单公式讲完卡尔曼滤波算法
  2. pixhawk自学笔记之uorb学习总结
  3. 2019牛客暑期多校训练营(第四场)I - String (后缀自动机+回文树)
  4. HDU - Dogs' Candies
  5. java scala 混合打包_scala和java混合开发打包
  6. C++:Static修饰变量 vs Static修饰函数
  7. [Jarvis OJ - PWN]——[XMAN]level3
  8. kdj超卖_一个判断股票超买超卖现象的指标——KDJ,简单明了,准确且省心
  9. spring的bean定义真的和顺序无关?
  10. Eclipse-cvs指南