从主函数跳到ReqHandler,在ReqHandler内先初始化SSD--InitNandReset,然后建立映射表InitFtlMapTable

 void InitNandReset()
{
// reset SSD
int i, j;
for(i=; i<CHANNEL_NUM; ++i)
{
for(j=; j<WAY_NUM; ++j)
{
WaitWayFree(i, j);
SsdReset(i, j);
}
} // change SSD mode
for(i=; i<CHANNEL_NUM; ++i)
{
for(j=; j<WAY_NUM; ++j)
{
WaitWayFree(i, j);
SsdModeChange(i, j);
}
} print("\n[ ssd NAND device reset complete. ]\r\n");
}

InitNandReset

遍历每条channel每条way来重启,change mode

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

 void InitFtlMapTable()
{
InitPageMap();
InitBlockMap();
InitDieBlock(); InitGcMap();
}

这里有四步,我们一步一步来分析


首先是页表建立,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

 void InitPageMap()
{
pageMap = (struct pmArray*)(PAGE_MAP_ADDR); // page status initialization, allows lpn, ppn access
int i, j;
for(i= ; i<DIE_NUM ; i++)
{
for(j= ; j<PAGE_NUM_PER_DIE ; j++)
{
pageMap->pmEntry[i][j].ppn = 0xffffffff; pageMap->pmEntry[i][j].valid = ;
pageMap->pmEntry[i][j].lpn = 0x7fffffff;
}
} xil_printf("[ ssd page map initialized. ]\r\n");
}

这里将设置每个页表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 > )
{
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,其中因为第一个块厂家保证是好的,所以不需要保存是否为坏块,所以里面可以存一个标记位,表示是否有现成的坏块信息表

     if(*shifter == EMPTY_BYTE)    //check whether badblock marks exist
{
// static bad block management
for(blockNo=; blockNo < BLOCK_NUM_PER_DIE; blockNo++)
for(dieNo=; dieNo < DIE_NUM; dieNo++)
{
blockMap->bmEntry[dieNo][blockNo].bad = ; SsdRead(dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM, (blockNo*PAGE_NUM_PER_BLOCK+), RAM_DISK_BASE_ADDR);
WaitWayFree(dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM); if(CountBits(*markPointer)<)
{
xil_printf("Bad block is detected on: Ch %d Way %d Block %d \r\n",dieNo%CHANNEL_NUM, dieNo/CHANNEL_NUM, blockNo);
blockMap->bmEntry[dieNo][blockNo].bad = ;
badBlockCount++;
}
shifter= (u8*)(GC_BUFFER_ADDR + blockNo + dieNo *BLOCK_NUM_PER_DIE );//gather badblock mark at GC buffer
*shifter = blockMap->bmEntry[dieNo][blockNo].bad;
} // save bad block mark
loop = DIE_NUM *BLOCK_NUM_PER_DIE;
dieNo = METADATA_BLOCK_PPN % DIE_NUM;
diePpn = METADATA_BLOCK_PPN / DIE_NUM;
blockNo = diePpn / PAGE_NUM_PER_BLOCK; SsdErase(dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM, blockNo);
WaitWayFree(dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM); tempBuffer = GC_BUFFER_ADDR;
while(loop>)
{
WaitWayFree(dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM);
SsdProgram(dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM, diePpn, tempBuffer);
diePpn++;
tempBuffer += PAGE_SIZE;
loop -= PAGE_SIZE;
}
xil_printf("[ Bad block Marks are saved. ]\r\n");
}

第九行为什么是读取每个块第一页的内容而不是第零页的内容?

12行位数小于4位就是坏块?

    else    //read existing bad block marks
{
for(blockNo=; blockNo<BLOCK_NUM_PER_DIE; blockNo++)
for(dieNo=; 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 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= ; i<BLOCK_NUM_PER_DIE ; i++)
{
for(j= ; j<DIE_NUM ; j++)
{
blockMap->bmEntry[j][i].free = ;
blockMap->bmEntry[j][i].eraseCnt = ;
blockMap->bmEntry[j][i].invalidPageCnt = ;
blockMap->bmEntry[j][i].currentPage = 0x0;
blockMap->bmEntry[j][i].prevBlock = 0xffffffff;
blockMap->bmEntry[j][i].nextBlock = 0xffffffff;
}
}

初始化块表的一些值

    for (i = ; i < BLOCK_NUM_PER_DIE; ++i)
for (j = ; 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. ]\r\n");

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

    for(i= ; i<DIE_NUM ; i++)
{
// initially, 0th block of each die is allocated for storage start point
blockMap->bmEntry[i][].free = ;
blockMap->bmEntry[i][].currentPage = 0xffff;
// initially, the last block of each die is reserved as free block for GC migration
blockMap->bmEntry[i][BLOCK_NUM_PER_DIE-].free = ;
}
//block0 of die0 is metadata block
blockMap->bmEntry[][].free = ;
blockMap->bmEntry[][].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= ; i<DIE_NUM ; i++)
{
if(i==) // prevent to write at meta data block
dieBlock->dieEntry[i].currentBlock = ;
else
dieBlock->dieEntry[i].currentBlock = ;
dieBlock->dieEntry[i].freeBlock = BLOCK_NUM_PER_DIE - ;
} 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 initialization
int i, j;
for(i= ; i<DIE_NUM ; i++)
{
for(j= ; j<PAGE_NUM_PER_BLOCK+ ; j++)
{
gcMap->gcEntry[i][j].head = 0xffffffff;
gcMap->gcEntry[i][j].tail = 0xffffffff;
}
} xil_printf("[ ssd gc map initialized. ]\r\n");
}

  

Cosmos OpenSSD--greedy_ftl1.2.0(一)的更多相关文章

  1. Cosmos OpenSSD架构分析--FSC

    接口速度: type   bw  read 75μs 1s/75μs*8k/1s=104m/s write 1300μs   1s/1300μs*8k/1s=6m/s erase 3.8ms  1s/ ...

  2. Azure Storage 系列(五)通过Azure.Cosmos.Table 类库在.Net 上使用 Table Storage

    一,引言 上一篇文章我们在.NET 项目中添加了 “WindowsAzure.Storage” 的 NuGet 包进行操作Table 数据,但是使用的 “WindowsAzure.Storage”  ...

  3. Azure Cosmos DB (五) .Net Core 控制台应用

    一,引言 之前在讲Azure CosmosDB Core(SQL)核心的时候,使用了EF Core 的方式,引用了 "Microsoft.EntityFrameworkCore.Cosmos ...

  4. 乘风破浪,遇见最佳跨平台跨终端框架.Net Core/.Net生态 - 官方扩展集锦(Microsoft.Extensions on Nuget)

    什么是Microsoft.Extensions .NET Platform Extensions是一套.Net官方的API集合,提供了一些常用的编程模式和实用工具,例如依赖项注入.日志记录.缓存.Ho ...

  5. ZAM 3D 制作简单的3D字幕 流程(二)

    原地址:http://www.cnblogs.com/yk250/p/5663907.html 文中表述仅为本人理解,若有偏差和错误请指正! 接着 ZAM 3D 制作简单的3D字幕 流程(一) .本篇 ...

  6. ZAM 3D 制作3D动画字幕 用于Xaml导出

    原地址-> http://www.cnblogs.com/yk250/p/5662788.html 介绍:对经常使用Blend做动画的人来说,ZAM 3D 也很好上手,专业制作3D素材的XAML ...

  7. 微信小程序省市区选择器对接数据库

    前言,小程序本身是带有地区选着器的(网站:https://mp.weixin.qq.com/debug/wxadoc/dev/component/picker.html),由于自己开发的程序的数据是很 ...

  8. osg编译日志

    1>------ 已启动全部重新生成: 项目: ZERO_CHECK, 配置: Debug x64 ------1> Checking Build System1> CMake do ...

  9. Cosmos OpenSSD--greedy_ftl1.2.0(三)

    我们来假设模拟一个小型的模型来分析写和垃圾回收的过程 假设只有一个die,4个block,每个block4个page,每个page8KB 那么PageMap就是Page[0][0]到Page[0][1 ...

随机推荐

  1. 201521123052《Java程序设计》第9周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 本次PTA作业题集异常 1.常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己 ...

  2. PHP面向对象三大特性之一:封装

    面向对象的三大特性:封装.继承.多态 1.封装 封装的目的:让类更加安全,做法是不让外界直接访问类的成员 具体做法:1.成员变为私有:访问修饰符(public.private.protected)   ...

  3. sourcetree和gitlab配置图解

    一.前期准备安装 1.git客户端(1.产生gitlab服务端和本地git相互传输时所需要校验的私钥和公钥    2.直接在Idea中使用git提交和push代码,当然也可以用sourcetree提交 ...

  4. C++初学 virtual 相关

    声明: 1.为了节省篇幅,头文件和域什么的都没写.另外可能是java转C++,有些叫法可能会不对 2.因初学,都是自己摸索的,有错望指出,勿喷 假设父类声明 Parent.h中如下 class Par ...

  5. Excel开发之旅(二)----数据的读写

    1.要实现数据的读写,首先,我们需要添加引用: using Excel=Microsoft.Office.Interop.Excel; 直接在项目中添加即可. 2.给3个按钮添加响应事件,工程代码截图 ...

  6. GitHub使用(二) - 新建文件夹

    1.首先打开我们已经建好的仓库 "test.github.com" 页面,可以看到如下图页面,找到“新建文件Create new file”按钮并点击.

  7. DotNetCore跨平台~linux上还原自主nuget包需要注意的问题

    问题的产生的背景 由于我们使用了jenkins进行部署(jenkins~集群分发功能和职责处理),而对于.net core项目来说又是跨平台的,所以对它的项目拉取,包的还原,项目的编译和项目的发布都是 ...

  8. MySQL+Keepalived配置高可用

    服务器环境: 主mysql:192.168.1.163 从mysql:192.168.1.126 VIP:192.168.1.50 一.mysql配置主从同步 1.配置主mysql服务器 vim /e ...

  9. 在分布式数据库中CAP原理CAP+BASE

    本篇博文的内容均来源于网络,本人只是整理,仅供学习! 一.关系型数据库 关系型数据库遵循ACID规则 事务在英文中是transaction,和现实世界中的交易很类似,它有如下四个特性: 1.A (At ...

  10. Hive基础(1)---Hive是什么

    1. Hive是什么 Hive是基于Hadoop的数据仓库解决方案.由于Hadoop本身在数据存储和计算方面有很好的可扩展性和高容错性,因此使用Hive构建的数据仓库也秉承了这些特性. 这是来自官方的 ...