材料说明:
文档《NVM-Express-1_4-2019.06.10-Ratified.pdf》来自于NVMe网站:https://nvmexpress.org/
笔记目的是学习NVMe基本概念,为学习NVMe over Fabric打基础,所以当前记录中与PCIe相关的内容,以及其他无关紧要的内容,都先跳过。
1 引言(入门简介)
1.2 内容范围
NVMe基础规格说明书为NVM subsystem中由controller负责的通信 定义寄存器接口。【注:对于NVMe over Fabric来说,使用软件仿真controller,不一定是物理寄存器】。它还定义了可能需要通过controller支持的标准命令集。
controller有三类型,分别具有不同的功能能力:
a) I/O controllers;
b) discovery controllers; 【注:NVMe over Fabric重点关注】
c) administrative controllers.【注:NVMe基础规格说明书 v1.4新增内容,administrative controllers目的是仅提供NVM subsystem管理功能,不支持访非易失存储的逻辑块数据和元数据。实际上administrative controllers提供的NVM subsystem管理功能在I/O controllers上都具有】
在后边的描述中,通常使用术语controller而不是列举出相关controller类型,可能需要结合上下文来判断对应的类型。
1.4 操作原理
NVMe精心设计了有限的接口来解决企业和客户使用基于PCIe固态盘或网络连接设备的系统需求。这些接口提供最佳命令提交和完成路径。包括为便于并行操作而支持到65535个I/O队列,每个I/O队列最大可以支持64k个待处理的命令。另外,还添加了许多企业功能,例如端到端数据保护(兼容知名的T10 DIF和SNIA DIX标准),增强的错误报告,虚拟化。
接口具有如下关键属性特征:
- 在命令提交或完成路径中无需读取不可缓存/MMIO寄存器;
- 在命令提交路径中一个MMIO寄存器最大极限的写是非常有必要的;
- 最大支持到65535个I/O队列,每个I/O队列支持存放65535个待处理的命令【即:每个I/O队列深度是64k】;
- 每个I/O队列对应一个优先级,具有明确定义的仲裁机制;
- 确保高效的小I/O操作,完成一个4KB读请求的所有信息都包含在64字节命令自身中;【?-待详细解释】
- 高效和合理的命令集;
- 支持MSI/MSI-X和中断聚合;
- 支持多namespace;
- 有效的支持像SR-IOV这样的I/O虚拟化架构;
- 健壮的错误报告和管理能力;
- 支持多路径I/O和共享namespace。
本NVMe基础规格说明书定义一个寄存器的改进的集,包括以下功能:
- controller功能能力特征;
- controller失败状态(命令状态是通过CQ被直接处理的);
- Admin队列配置(I/O队列配置是用Admin命令处理的);
- 为有限数量的提交和完成队列使用的门铃寄存器
一个NVMe controller关联单一的一个PCI Function。应用于整个controller的功能能力和设置在Controller Capabilities(CAP)寄存器和Identify Controller数据结构中被表示指出。
一个namespace是大量可以被格式化成多个逻辑块的非易失存储。一个NVMe controller可以支持多个namespace,使用namespace ID来引用。namespace可以使用Namespace Management和Namespace Attachment命令来创建和删除。Identify Namespace数据结构显示具体特定namespace的功能能力和设置。用于namespace ID FFFFFFFFh的所有namespace公共的功能能力和设置通过Identify Namespace数据结构来公告。
NVMe接口基于一个提交和完成队列对机制。命令Command被主机软件放入到一个提交队列Submission Queue(SQ)中,完成Completion被controller放入相应的完成队列Completion Queue(CQ)。多个提交队列可以使用同一个完成队列【注:多个SQ公用一个CQ仅限于NVMe over PCIe,在NVMe over Fabric中SQ和CQ是一对一的关系】。SQ和CQ从内存中申请。
Admin SQ和对应的CQ存在的目的是为了controller管理和控制(例如I/O SQ和CQ的创建和删除,异常终止命令等)。只有Admin Command Set管理命令集中的命令才可以提交到Admin SQ。
I/O命令集在I/O队列对中使用。这个NVMe基础规格说明书定义了一个I/O命令集,称之为NVM Command Set(NVM命令集)。主机选择I/O命令集的一个能用于所有I/O队列对。
主机软件能在controller所支持的最大队列数量范围内创建队列。典型的被创建的命令队列数量是基于系统配置和预期的工作负荷。例如在四核的处理系统上,为避免使用锁和确保在相应的处理器核cache上创建数据结构,或许每个核上创建一个队列对。下边图Figure 1 展示了一个队列对机制的图,展示的是SQ和CQ之间1:1映射。
下边图Figure 2展示了一个在Core B上多个I/O SQ共用同一个I/O CQ的例子。
从Figure 1 和Figure 2看到Admin SQ和Admin CQ都是1:1映射。
SQ是一个主机软件用于提交命令的固定数量槽位的环形缓冲区,主机软件提交的命令是为了被controller执行。当有1到n个需要被执行的新命令时,主机软件更新响应的SQ 尾部门铃寄存器。当有新门铃寄存器写入时,在controller中前一个SQ尾部值被覆盖。controller按顺序从SQ中取SQ项,但是执行这些命令时可能是乱序的。
每个SQ项是一个命令。命令大小为64字节。在存储器中用于数据传输的物理存储位置,使用Physical Region Page(PRP)条目或Scatter Gather Lists(SGL)聚散列表来指定。每个命令可以包含两个PRP条目或一个SGL聚散列表段。如果需要多于两个PRP条目来描述数据缓冲区,那么可以提供一个指向PRP条目描述列表的指针来表示。如果需要多于一个的SGL聚散列表段来描述数据缓冲区,那么SGL段提供一个指向下一个SGL段的指针。
CQ是一个固定数量槽位的环形缓冲区,用于公布完成的命令状态。一个完成的命令通过对应的SQ ID和主机分配的命令ID的组合来唯一标识。多个SQ共用一个CQ的特性,用于单个工作线程通过一个CQ处理所有命令完成的场景。主机处理完CQ项之后,CQ头指针被主机软件更新,置成最后空闲CQ槽位。在CQ项中定义了一个Phase Tag(P)位标明是否一个项被新推送出来,而无需查询寄存器。这能够让主机软件判断新项是前一个的一部分还是当前完成通知的返回。
1.4.1 多路径I/O和namespace共享
这一章节描述的是多路径I/O和namespace共享的一个概貌。多路径I/O指的是在单个主机和一个namespace之间存在两个或更多的完全独立的路径,而namespace共享指的是为两个或更多的主机使用不同的NVMe controller来访问一个公共共享的namespace的能力。多路径I/O和namespace共享二者都要求NVM subsystem含有两个或更多的controller。支持多路径I/O和namespace共享的NVM subsystem也可以支持非对称controller行为(见1.4.2章节)。被两个或更多主机并发访问的一个共享的namespace对主机间协调的形式有一定要求。用于协调这些主机的步骤不在本NVMe基础规格说明书中。
下边图Figure 3展示了一个包含单个NVMe controller和单个PCIe端口的NVM subsystem。应为这是一个单Function的PCIe设备,NVMe controller必须被关联到PCI Function 0。一个controller可以支持多namespace。在图Figure 3中的这个controller支持了两个namespace,分别称为NS A和NS B。与每个controller namespace相关的是namespace ID,标记为NSID 1和NSID 2,它被用于controller引用特定的namespace。这个namespace ID与namespace本身是有明显的区别的,它应对一个主机和controller在命令中使用指定一个特定的namespace。controller的namespace ID的选择超出了本NVMe基础规格说明书的范围。在这个例子中,namespace ID 1与namespace A相关联,namespace ID 2与namespace B相关联。两个namespace都是这个controller私有的,并且这种配置既不支持多路径I/O也不支持namespace共享。
图Figure 4展示了一个多Function的NVM subsystem,具有单个PCIe端口,内含两个controller,一个controller关联PCI Function 0,另一个关联PCI Function 1。
每个controller支持一个私有的namespace和访问共享的namespace B。被访问的这个共享的namespace的namespace ID必须在所有controller中都是相同的。在这个例子中,两个controller都使用namespace ID 2去访问共享的namespace B。
【注:协议规定,共享的namespace对应的namespace ID在所有controller中都必须是相同的值,但是并没有要求其他的namespace ID必须在整个NVM subsystem中唯一性】
对于每一个controller,具有一个唯一的Identify Controller数据结构;对于每一个namespace,具有一个唯一的Identify Namespace数据结构。
访问共享namespace的controller们都返回共享namespace对应的那个Identify Namespace数据结构。有一个全局唯一的标识符对应namespace本身,当有多路径到达同一个共享namespace时可以用它来确定。请参照7.10章节。
关联到一个共享namespace的controller们可以同时并发地操作这个namespace。单个的命令提交操作共享namespace在controller的级别是原子性的,如果是多个具有顺序的命令提交到不同的controller来访问共享namespace,就得要求主机软件或相关应用来保证它们的顺序要求。【注:此段有待再深入理解,然后更新一下】
图Figure 5 举例说明了一个具有两个PCIe端口的 NVM subsystem,每个PCIe端口对应一个controller。两个controller都是映射到相应端口的PCI Function 0上。在这个例子中每个PCIe端口都是完全独立的,并且有它自己的PCIe基本的复位和参考时钟输入。一个端口的复位只影响到此端口对应的controller,而不影响另一个controller,共享namespace,以及通过另一个controller在共享namespace上的操作执行。本例子功能的行为在其他方面与Figure 4是相同的。
在图Figure 5中展示的两个端口可能被挂载到同一个Root Complex也可能被挂载到不同的Root Complex上,可能被用于执行多路径I/O和I/O共享架构。系统级架构方面和PCIe网络中使用多端口超出了本NVMe基础规格说明书的范围。
图Figure 6示例一个具有一个物理Function和4个虚拟Function的支持SR-IOV的NVM subsystem。每个Function对应一个NVMe controller,每个controller有一个私有namespace和一个被所有controller共享访问的namespace,这个共享namespace标记为NS F。在这个例子中controller们的行为与本章节的其他例子相一致。关于SR-IOV更多的信息请参照第8.5.4章节。
本章节中提供的例子目的都是打算阐述概念,而不是刻意的枚举所有可能的配置。一个NVM subsystem可以包含多PCIe端口,且每个端口支持SR-IOV。
1.4.2 非对称controller行为
非对称controller行为在NVM subsystem中可能因为namespace访问特征(例如性能)而导致,或许因为:
NVM subsystem中的内部配置;
用于访问namespace的controller是哪一个
提供非对称controller行为的NVM subsystem可以支持8.20章节中描述的Asymmetric Namespace Access Report。
1.5 惯例约定
【注:此章节暂且忽略】
1.6 定义
1.6.1 Admin队列
Admin队列是用ID 0标识的SQ和CQ。Admin SQ和相应的Admin CQ分别的用于提交管理命令和接收这些管理命令的completion。
Admin SQ和Admin CQ是一对一的相互唯一关联的。
1.6.2 管理controller
能够对外呈现允许主机来管理NVM subsystem能力的controller。管理controller不能执行I/O队列,不能向主机提供访问非易失存储媒介上逻辑块的数据和元数据,也不能向管理controller上挂载namespace(从来没有任何有效的NSID)。
1.6.3 仲裁迸发
一次可以从一个SQ所发送命令的最大数量使用轮询或按紧急优先级加权轮询进行仲裁。【注:这里的描述语句待斟酌】
1.6.4 仲裁机制
用于决策选择哪一个SQ的命令紧接着将要被controller执行的方法。NVMe基础规格说明书中定义了三种仲裁机制:轮询、带紧急优先级加权轮询、厂家指定。请参考4.13章节。
1.6.5 缓存
缓存是一个被NVM subsystem使用的数据存储区,主机不可访问此缓存,也可能包含【容纳/存储】的是存储在非易失媒介中用户数据的一个子集,或者也可能包含的是未提交到非易失媒介的用户数据。
1.6.6 候选命令
候选命令是已经传输到controller被提交了的命令,controller认为已经准备好可以被处理的命令。
1.6.7 命令完成
当controller完成了对命令的处理,向对应的CQ发出了CQ项,并且在CQ项中更新了状态信息,这样才算一个命令被完成。
1.6.8 命令提交
对NVMe over PCI的实现来说,当SQ门铃写入,即修改SQ尾部指针值为命令被放置的这个SQ槽位,就算是这个命令被提交了。
对于NVMe over Fabric的实现来说,请参考1.0版本的NVMe over Fabric 规格说明书1.4.14章节。
1.6.9 controller
controller是主机和NVM subsystem之间的接口。有三种类型:
a) I/O controllers;
b) discovery controllers;
c) administrative controllers.
controller执行主机用SQ提交的命令,以及在CQ上发布completion。所有的controller都实现一个Admin SQ和一个Admin CQ。根据controller的类型不同,一个controller可能实现一个或者多个I/O SQ和I/O CQ。当传输层是PCIe时,一个controller是一个PCIe function。
1.6.10 directive
directive是一种主机和NVM subsystem或controller信息交流的方法。信息可以使用Directive Send和Directive Receive命令传输。一个I/O命令的子部分可以包含一个Directive Type域和一个Directive Specific域来传达更多的特定于此I/O命令的信息。请参考第9章节。
1.6.11 discovery controller
一种具有允许主机检索Discovery Log Page能力的controller。discovery controller不能执行I/O队列,也不能访问非易失存储媒介。更多信息请参考NVMe over Fabric规格说明书。
1.6.12 仿真controller
仿真controller是指使用软件定义的NVMe controller。一个仿真controller可以基于一个物理NVMe controller,也可以不基于物理NVMe controller。
1.6.13 持久组
NVM subsystem中NVM的一部分,它作为一个组被持久的管理【注:持久是指不动态的消失或掉电重启后消失?】。请参考第8.17章节。
1.6.14 扩展LBA
扩展LBA是一个更大的LBA,它是在与LBA关联的元数据与LBA数据连续转换时创建的。
1.6.15 固件槽位
位于NVM subsystem中的固件槽位用于存储固件镜像。NVM subsystem存储着1到7个固件镜像。
1.6.16 主机
主机是接口实体,通过一个或多个controller连接NVM subsystem,向SQ提交命令,从CQ取回命令completion。
1.6.17 主机内存
可以被主机和controller读写的内存,这个内存不是controller呈现的,主机内存可以实现在主机内也可以实现在主机外。【注:Host memory概念貌似与望文生义出现偏差?】
1.6.18 I/O命令
I/O命令就是指提交到I/O SQ的命令。
1.6.19 I/O CQ
用于标明命令完成,与一个或多个I/O SQ相关联的CQ。 I/O CQ的ID从1至65535。
1.6.20 I/O controller
执行I/O队列和打算被用于访问非易失存储NVM存储媒介的controller。
1.6.21 I/O SQ
用于提交I/O命令让controller去执行的SQ。I/O SQ的ID从1至65535。
1.6.22 LBA范围
用起始LBA和逻辑块数量指定的一个连续的逻辑块集合。
1.6.23 逻辑块
用于命令读写的最小可寻址的数据单元。
1.6.24 逻辑块地址LBA
逻辑块的地址。请参考通用的LBA概念。
1.6.25 元数据
元数据是关于特定LBA数据的上下文信息。如果存储空间由controller提供,主机可以包含NVM subsystem要存储的元数据。元数据可能包括保护信息(请参考第8.3章节)。
1.6.26 namespace
可格式化为逻辑块的大量非易失性存储。当格式化时,一个大小为n个逻辑块的namespace,逻辑块地址是从0至(n-1)。
1.6.27 Namespace ID(NSID)
被controller提供访问一个namespace的标识,或者在SQE【注:SQE,前边描述中用过“SQ项”,他是SQ Entry】中包含namespace标识符(请参考插图Figure 105)的域字段名。请参考第6.1章节,在第6.1章节定义了合法NSID、非法NSID、活动NSID、闲置NSID、已分配的NSID、未分配的NSID。
1.6.28 NVM
NVM是non-volatile memory的首字母缩写。
1.6.29 NVM Set
持久组中NVM的一部分。请参考第4.9章节。
1.6.30 NVM subsystem
一个NVM subsystem包括一个或多个controller,0个或多个namespace,一个或多个端口。一个NVM subsystem可以包含一个非易失存储媒介和一个非易失存储媒介与NVM subsystem中controller之间的接口。
1.6.31 主controller
主controller是一个支持虚拟化管理的NVMe controller。一个NVM subsystem中可以包含多个主controller。NVM subsystem中辅助controller【注:原文是Secondary controller】动态资源的管理依赖于主controller。(请参考第8.5章节)
一个主controller的例子是:PCIe SR-IOV物理Function支持NVMe接口和虚拟化增强能力(请参考第8.5.4章节)。
1.6.32 私有namespace
私有namespace是指只能同时被挂载到一个controller上的namespace。主机可以通过Identify Namespace数据结构中的Namespace Multi-path I/O 和 Namespace Sharing Capabilities(NMIC)域来判断一个namespace是私有namespace还是共享namespace。
1.6.33 运行时D3(电源移除)
在运行时D3(RTD3)主电源从controller上移除。或许有辅助电源也或许没有辅助电源。对于PCIe,RTD3是D3cold电源状态(请参考第8.4.4章节)。
1.6.34 清洁操作【sanitize operation 或称为无害化处理】
在NVM subsystem中用户数据被切换处理后,不论是缓存中的还是非易失媒介中的前一个用户的数据都不能再被恢复出来。
1.6.35 辅助controller
依赖一个主controller管理一些controller资源的NVMe controller(请参考第8.5章节)。
辅助controller的例子是PCIe SR-IOV虚拟化功能(请参考第8.5.4章节)。
1.6.36 共享namespace
在NVM subsystem中可以被同时的挂载到两个或多个controller上的namespace。主机可以通过Identify Namespace数据结构中的Namespace Multi-path I/O 和 Namespace Sharing Capabilities(NMIC)域来判断一个namespace是私有namespace还是共享namespace。
1.6.37 用户数据
由逻辑块数据和可选的元数据组成的数据。