文章目录

  • NVMe
  • 一、概述
  • 1.1 什么是NVMe
  • 1.2 高性能&低延迟
  • 1.3 名词&术语
  • 二、NVMe命令
  • 2.1 命令通用格式
  • 2.2 两类命令
  • 2.2.1 Admin Command
  • 2.2.2 IO Command(NVM Command)
  • 2.3 SQ、CQ、DB
  • 2.4 命令的执行过程
  • 三、多命令队列与仲裁机制
  • 3.1 NVMe多命令队列
  • 3.2 多命令队列的仲裁机制
  • 3.2.1 RR
  • 3.2.2 带有优先权的RR
  • 四、内存寻址
  • 4.1 PRP方法
  • 4.2 SGL方法
  • 4.3 PRP 与 SGL 的比较
  • 五、NVMe SSD Controller 物理架构(了解)
  • 5.1 概念模型
  • 5.2 子模块
  • 5.3 NVMe主机接口控制器


一、概述

1.1 什么是NVMe

  • Non-Volatile Memory Express(非易失性存储器标准)
  • NVMe是面向PCIe SSD制定的标准接口协议,用于访问通过PCIe总线附加的SSD(可适用于各种支持PCIe总线的物理插槽上)
  • 定义了NVMe协议的使用范围、指令集、寄存器配置规范等
  • 具有良好的可拓展性、低延迟,低能耗,高性能等优点

PCle:Peripheral Component Interconnect Express,周边设备高速连接标准。是一种端对端的互连协议,提供了高速传输带宽的解决方案。其协议内容主要是物理层和数据链路层的。

另一个常用的相关协议是AHCI,AHCI主要是针对高延时的SATA接口的机械硬盘而设计的

1.2 高性能&低延迟

面向PCIe SSD产品的NVMe标准能有效降低控制器和软件接口部分的延迟,是因为:

  • 能让SSD走PCI-E通道直连CPU,有效降低了数据延迟
  • NVMe执行命令时则不需要读取寄存器

NVMe还能大大提高SSD的IOPS性能。理论上,IOPS=队列深度/ IO延迟,所以增加队列深度,就可以有效提升SSD的IOPS。

  • 传统的ACHI标准下队列深度最多能达到32
  • 在NVMe标准下,这一数值可以达到64000

此外NVMe还加入了自动功耗状态切换、动态能耗管理、免驱等功能,驱动适应性广,低功耗

1.3 名词&术语

1、Namespace

  • Namespace是一定数量逻辑块(LB)的集合
  • 其属性在Identify Controller中的数据结构中定义

逻辑块:NVMe定义的最小的读写单元,2KB、4KB……,用LBA来标识块地址
LBA range:表示物理上连续的逻辑块集合

2、Fused Operations

  • 聚合操作。只能聚合两条命令,并且这两条命令在队列中应保持相邻顺序,还需要保证聚合操作的两条命令读写的原子性
  • 只有NVM指令才有聚合操作

3、指令执行顺序

  • 除了聚合操作,每一条SQ中的命令都是独立的

4、写单元的原子性

  • 控制器需要支持写单元的原子性
  • 但有时也能通过host配置Write Atomicity feature,减小原子性单元的大小,提高性能

5、元数据

  • 数据的额外信息。可选的方式

6、仲裁机制

  • 用来选择执行的命令的SQ的机制,三种仲裁方式:
  • RR(每个队列优先级相同,轮转调度)
  • 带权重的RR(队列有4种优先级,根据优先级调度)
  • 自定义实现

7、Queue Pair

  • 由SQ(提交队列)与CQ(完成队列)组成
  • host通过SQ提交命令,NVMe Controller通过CQ提交完成命令

8、NVM 子系统

  • 控制器
  • NVM存储介质
  • 控制器与NVM之间的接口

二、NVMe命令

2.1 命令通用格式

Host提交的命令均为16字节,具有相同的格式,某些字段根据命令的不同有不同的定义

字段

定义

Dword0

CID、传输方式、聚合操作、操作码

1

NID(Namespace ID)

2

保留

3

保留

4、5

元数据指针(MPTR)

6-9

数据指针(DPTR)

10-15

根据命令指定

CQ命令均为4字节,也具有相同的格式,某些字段根据命令的不同有不同的定义

字段

定义

Dword0

根据命令指定

1

保留

2

SQID、SQ头指针

3

状态域、P位、CID

2.2 两类命令

主机提交的命令分为两类

2.2.1 Admin Command
  • Admin指令只能提交到Admin Controller中(Admin CQ/SQ)
  • 主要负责管理NVMe控制器,也包含对NVM的一些控制指令
  • Admin Command通过Dword0中的8位操作码定义不同指令,每一种指令都对应有其完成命令
  • 通过SQID(提交队列ID)+CID(命令ID)唯一标识完成的命令

字段

appmask

apptag

reftag

dsmgmt

slba

addr

metadata

rsvd

nblocks

control

Flags

Opcode

操作码

操作码

指令

作用

00h

删除I/O SQ

释放SQ空间

01h

创建 I/O SQ

保存host分配给SQ的地址、队列优先权、队列大小

02h

获取日志

返回所选日志页于缓冲区

04h

删除 I/O CQ

释放CQ空间

05h

创建 I/O CQ

保存host分配给CQ的地址、中断向量、队列大小等

06h

Identify

返回关于controller与namespace能力和状态的数据结构(2k字节)

08h

撤销

用来撤销之前完成的指令,best-effort

09h

设置features

根据FID设置相应的features

0Ah

获取 features

根据FID返回队列数量、仲裁信息等

0Ch

异步事件请求

Controller向host报告运行信息(error or health)

10h

固件激活

验证下载的镜像,提交到Firmware Slot(1-7)中

11h

固件镜像下载

下载固件镜像

2.2.2 IO Command(NVM Command)
  • NVM 指令只能提交到I/O Controller中(IO CQ/SQ)
  • 主要负责完成数据的传输
  • IO Command通过Dword0中的8位操作码定义不同指令,每一种指令都对应有其完成命令
  • 通过SQID(提交队列ID)+CID(命令ID)唯一标识完成的命令

字段

rsvd11

numd

offset

lid

prp2

prp1

rsvd1

command_id

flags

Opcode

操作码

指令

作用

00h

Flush

将数据(和元数据)提交到NVM中,所有命令都要执行

01h

Write

将数据(和元数据)写入NVM中

02h

Read

读NVM中的数据(和元数据)

04h

Wirte Uncorrectable

标记无效数据块

05h

Compare

比较从NVM端读出的数据和比较数据缓冲区的数据

09h

Dataset Management

标识一定范围数据的特点,eg,频繁读、频繁写(提升性能)

2.3 SQ、CQ、DB

NVMe的三种队列命令

  • Submission Queue(SQ)提交队列(在内存中)
  • Host要发送命令时,先把准备好的命令放在SQ中(Host并不直接往SSD中发送命令,而是把命令准备好放在自己的内存中,写DB通知SSD来取)
  • Completion Queue(CQ)完成队列(在内存中)
  • 一个命令执行完成,成功或失败,SSD总会往CQ中写入命令完成状态、
  • SSD写完后,Host会处理CQ,查看指令完成状态
  • Doorbell Register (DB)门铃注册(在SSD控制器内部)
  • Host通过写DB告诉SSD去SQ读指令
  • Host通过写DB回复SSD命令已经处理完毕,可以前来检阅

查看是否支持ashmem内核 如何查看是否支持nvme协议_查看是否支持ashmem内核

2.4 命令的执行过程

命令由host提交到内存中的SQ队列中,更新TDBxSQ后,NVMe控制器通过DMA的方式将SQ中的命令(怎么取,如何取,取多少,因设计而异)取到控制器缓冲区,执行命令;执行完成后,根据执行状态,组装完成命令,仍然通过DMA的方式将完成命令写入内存CQ的队列中;NVMe控制器通过MSI-X中断方式通知host已完成命令;最后,host处理CQ命令,更新控制器中HDBxCQ,标识着命令真正完成

通过三种队列命令配合,完成处理流程

  • ① Host写命令到SQ;
  • ② Host写DB(通知SSD取指令);
  • ③ SSD收到通知,于是从SQ中取指令;
  • ④ SSD执行指令;
  • ⑤ 指令执行完成,SSD往CQ中写指令执行结果;
  • ⑥ SSD通过MSI-X中断方式通知host已完成命令;
  • ⑦ Host处理CQ,查看指令完成状态;
  • ⑧ Host通过DB回复SSD,命令真正完成

查看是否支持ashmem内核 如何查看是否支持nvme协议_驱动开发_02

MSI-X中断:NVMe协议中支持的中断方式有4种,pin-based、Single MSI、Multi-message MSI和MSI-X,协议推荐采用MSI-X中断方式,能够支持更多的中断向量(2K)。

MSI-X允许每一个CQ发送自己的中断信息(相比于发一条中断信息提醒全部CQ队列有很大的优势)。在产生MSI-X中断信息前,需要检查该中断在相应寄存器种不被屏蔽

三、多命令队列与仲裁机制

3.1 NVMe多命令队列

  • NVMe采用了多命令队列,每个命令可变数据长度
  • NVMe协议支持命令间的乱序执行,也支持命令内数据块的乱序传输,同时支持命令队列间的可变权重处理
  • QID来标识唯一ID,16bit,由host分配
  • host可以修改队列优先级(如果支持的话),共四级:U、H、M、L

NVMe与SATA协议对比

查看是否支持ashmem内核 如何查看是否支持nvme协议_查看是否支持ashmem内核_03

3.2 多命令队列的仲裁机制

3.2.1 RR

Admin SQ与I/O SQ优先级相同,控制器每次可以选择一个队列中的多个命令,轮转调度

查看是否支持ashmem内核 如何查看是否支持nvme协议_数据_04

3.2.2 带有优先权的RR

有3个严格的优先权,Priority1 > Priority2 > Priority3,在这三个优先级队列中,高优先级的队列中如果有命令,则优先执行(非抢占式)

  • Priority1:Admin
  • Priority2:Urgent
  • Priority3:IO SQ

查看是否支持ashmem内核 如何查看是否支持nvme协议_驱动开发_05

四、内存寻址

Host告诉Controller数据源在内存的什么位置,或者从闪存上读取的数据应该放到内存的什么位置,需要内存寻址

  • NVMe把Host的内存分为页的集合,页的大小在CC寄存器中配置
  • NVMe采取PRP和SGL两种寻址方式
  • Admin命令的数据地址只能采取PRP的方式
  • I/O命令的数据地址既可以采取PRP的方式,又可以采取SGL的方式
  • Host在命令中会告诉Controller采用何种方式。具体来说,如果命令当中DW0[15:14]是0,就是PRP的方式,否则就是SGL的方式

 

4.1 PRP方法

PRP Entry是一个64位(63 ~ 0编号)的内存物理地址指针,结构如下:

查看是否支持ashmem内核 如何查看是否支持nvme协议_闪存_06

  • 最后两位为0,指四字节对齐
  • Offset(n:2)位表示页内内偏移

PRP寻址有两种方式

  • 直接用PRP指针寻址:直接由PRP指向内存页
  • 通过PRP List寻址:PRP指向PRP List的地址,PRP List存有真正的数据地址

查看是否支持ashmem内核 如何查看是否支持nvme协议_闪存_07

4.2 SGL方法

SGL是另外一种索引内存的数据结构。SSGL字段由若干个SGL描述符组成,所以SGL描述符是SGL数据结构的基本单位

目前定义的SGL描述符有6种,在一个SGL字段中并不需要同时使用

  • SGL 数据描述符,用来索引数据块地址,host内存;
  • SGL 垃圾数据描述符,用来索引无用数据;
  • SGL 段描述符,用来索引下一个SGL段;
  • SGL 最后一个段描述符,用来索引最后一个SGL段;
  • keyed SGL 数据描述符;
  • Transport SGL 数据描述符;

查看是否支持ashmem内核 如何查看是否支持nvme协议_数据_08

  • 在上面SGL例子中,共有3个SGL段,用到了4种SGL描述符
  • Host需要往SSD中读取13KB(Data Block + Bit Bucket)的数据,其中真正只需要11KB数据(Data Block),这11KB的数据需要放到3个大小不同的内存中,分别是:A(3KB),B(4KB)和 C(4KB)

4.3 PRP 与 SGL 的比较

无论是PRP还是SGL,本质都是描述内存中的一段数据空间。

Host在命令中设置好PRP或者SGL,告诉Controller数据源在内存的什么位置,或者从闪存上读取的数据应该放到内存的什么位置。

SGL和PRP本质的区别在于:

  • 一段数据空间,对PRP来说,它只能映射到一个个物理页
  • 对SGL来说,它可以映射到任意大小的连续物理空间,具有更大的灵活性,也能够描述更大的数据空间

五、NVMe SSD Controller 物理架构(了解)

5.1 概念模型

整体来看,NVMe SSD可以分为三部分

  • host端的驱动
  • PCIe+NVMe实现的控制器
  • FTL+NAND Flash的存储介质

查看是否支持ashmem内核 如何查看是否支持nvme协议_驱动开发_09

5.2 子模块

查看是否支持ashmem内核 如何查看是否支持nvme协议_驱动开发_10

1、主机接口控制器

  • 主机接口负责进行主机与固态盘之间的通信和数据传输,接受和解析I/O请求,并维护一条或者多条请求队列
  • 主机接口控制器是对外连接的模块,它的两大工作 —— 接受和解析IO、维护请求队列是NVMe的实现难点,也是最最主要的设计点,我围绕NVMe的设计实现也基本是针对主机接口控制器而言的

2、多核处理器

  • 固态盘的管理需要处理诸多复杂的任务,比如主机接口协议、调度算法、FTL算法和缓存算法等,因此需要强有力的多核处理器来提高这些任务的处理效率,从而降低软件延时

3、缓存芯片

  • 固态盘内置有缓存芯片,一般是DRAM,用于缓存用户数据和软件算法的元数据
  • 缓存既能加快数据访问的速度,提高固态盘的性能,也能够减少对闪存的写入,延长固态盘的寿命
  • 缓存用户数据的部分称之为数据缓存,缓存地址映射表的部分称之为映射缓存
  • 为了防止突然掉电导致RAM中的数据丢失,固态盘一般会内置备用电容,并采用适当的数据保护技术,用于保证在突然掉电的情况下,将RAM中关键的脏数据刷回闪存

4、中央控制器

  • 中央控制器是整个固态盘控制器的核心,负责配置固态盘的工作模式,管理各个模块之间的通信和数据流。
  • 中央控制器内置有小容量的高速SRAM缓存,用于临时缓存数据

5、纠错码引擎

  • 纠错码引擎对要写入闪存的数据进行编码,所增加的纠错码冗余会被写到闪存页的额外存储区中
  • 当需要从闪存中读取数据时,纠错码引擎会对数据和它的纠错码冗余进行解码,如果发生的比特错误数在纠错能力范围内,数据中的错误就会被纠正,从而得到正确的数据;否则,如果没有其它的数据恢复手段,存储的数据就会丢失

6、通道控制器

  • 为了提高性能,固态盘将数量众多的闪存芯片安置在多个通道上,每个通道上的多个芯片共享一条I/O总线。
  • 每个通道包含一个独立的通道控制器,主要负责与中央控制器和本通道上的闪存芯片进行通信,并维护多条操作闪存的命令队列(比如为每个芯片维护一条单独的队列,外加一条总的高优先级队列),将命令发往目标芯片进行执行

7、闪存芯片

  • 闪存芯片上既存储用户数据,也存储需要持久化的元数据,比如地址映射表
  • 固态盘提供的物理存储容量会比用户可见的容量要多(一般多7% ~ 28%),多余部分称之为过量供应(Over-provisioning, OP)空间,主要用于提高软件算法(比如垃圾回收操作)的效率和补偿因闪存坏块产生的容量损失
  • 有的固态盘还会在闪存芯片之间组建RAID5,以加强存储的可靠性

RAID5:将校验数据条带化存储在多个盘中

8、DMA引擎

  • DMA引擎负责控制在两个RAM之间进行快速的数据传输,比如在中央控制器的SRAM和缓存芯片之间

5.3 NVMe主机接口控制器

NMVe主机接口控制器的逻辑将是我主要的设计内容,一般来说NMVe主机接口控制器包括以下几个部分:

  • Admin队列处理模块
  • IO命令队列处理模块
  • IO Completion队列处理模块
  • IO写数据处理模块
  • IO读数据处理模块
  • 中断处理模块

查看是否支持ashmem内核 如何查看是否支持nvme协议_固态盘_11