NVM Command是NVMe协议里面的IO命令,主要包含Write、Read、Compare、Verify、Write Zeroes、Write Uncorrectable、Reservation这些命令。命令下发需满足以下两点:控制器状态寄存器(CSTS.RDY);创建了适当的I/O SQ和CQ。
检查当前磁盘支持哪些NVM Command
我们知道并不是所有NVM Command盘片都支持,在协议里只规定Flush、Write、Read命令是强制要求的,其他的都是可选项。所有我们在使用时,需要查看一下命令是否支持。可以通过查看Identify Controller Data Structure的ONCS[521:520]查看命令是否支持。
Bit 7:如果置1,则主控支持Verify命令;否则不支持;
Bit 5:如果置1,则主控支持Reservations;否则不支持;
Bit 3:如果置1,则主控支持Write Zeroes;否则不支持;
Bit 2:如果置1,则主控支持Dataset Management;否则不支持;
Bit 1:如果置1,则主控支持Write Uncorrectable;否则不支持;
Bit 0:如果置1,则主控支持Compare命令;否则不支持;
NVM Command详解
注:命令下发使用nvme-cli做演示。
一、Flush命令
用于请求使易失性写缓存的内容的内容具有非易失性,即Flush命令应将与指定命名空间相关联的数据和元数据提交给非易失性介质。Flush命令适用于控制器在提交flush命令之前完成的指定名称空间的所有命令。控制器还可以从任何名称空间中刷新其他数据和元数据。
我们还可通过Idnetify controller Data Structure的VWC[525]查看盘片是否存在易失性写缓存。
Bit 0:如果置1,表示存在易失性写缓存;否则不存在;
Bit 2:1:表示NSID设置FFFF FFFFh时,指示Flush命令行为。
00b:表示不支持将NSID设为FFFF FFFFh,只有在1.3之前版本才支持返回此值
01b:保留字段
10b:表示Flush不支持将NSID设为FFFF FFFFh,返回状态码为Invalid Namespace or Format
11b:表示Flush支持将NSID设为FFFF FFFFh
注:若不存在易失性写缓存或者未启用,则flush命令也可以成功完成,只是没有效果。
#不指定namespace
> nvme flush /dev/nvme0n1
#指定namespace下发flush命令
> nvme flush -n 1/2... /dev/nvme0n1
二、Reservation命令
该命令用于namespace上的权限管理操作。消费级盘该指令不常见,故不作过多介绍。
Reservation Acquire命令:用于获取名称空间上的预订,抢占名称空间上的预订,以及中止名称空间上保持的预订
Reservation Register命令:用于注册、注销或替换保留密钥
Reservation Release命令:用于释放或清除保留在命名空间上的预订
Reservation Report命令:将Reservation Status数据结构返回到内存,该数据结构描述命名空间的注册和预订状态
三、Write命令
会将数据和元数据写入所指示的逻辑块的I/O控制器,主机还可以指定保护信息作为操作的一部分。
协议 | Nvme-cli | 释义 |
---|---|---|
CDW10&11[63:00] | --start-block,-s | 开始的逻辑块地址 |
CDW12[31] | --limited-retry,-l | 进行有限次retry用于错误恢复 |
CDW12[30] | --force-unit-access,-f | 强制设备在命令完成之前将数据写到闪存,数据还是会经过缓存进行写入,只是会等待写入闪存后才返回命令 |
CDW12[29:26] | --prinfo,-p | 指定保护信息操作和检查字段 |
CDW12[23:20] | --dir-type,-T | 指令类型,可在identify[257:256]Bit 5查看支持情况 |
CDW12[15:00] | --block-count,-c | 表示要写入的逻辑块数,基于0‘s based |
CDW13[31:16] | --dir-spec,-S | 指定与‘DTYPE’字段相关的指令特定值 |
CDW13[07:00] | --dsm,-D | 表示正在写的LBA的属性 |
CDW14[31:00] | --ref-tag,-r | 指定初始逻辑块参考标记值,把逻辑块数据与一个地址关联起来,防止被误用或者乱序逻辑块传输,用来检测数据是否写入错误的LBA。prinfo使用才用此值 |
CDW15[31:16] | --app-tag,-a | 指定应用程序标记值,prinfo使用才用此值 |
CDW15[15:00] | --app-tag-mask,-m | 指定应用程序标记掩码值,prinfo使用才用此值 |
DATA Pointer[63:00] | --data-size,-z | 指定传输的数据 |
Metadata Pointer[127:00] | --metadata-size,-y | 指定元数据指针 |
write命令下发,下面命令执行效果相同。
> echo "7788" | nvme write -s 0 -c 1 -z 512 /dev/nvme0n1
Rounding data size to fit block count(1024 bytes)
write:Success
> cat data.bin
7788
> nvme write -s 0 -c 1 -z 512 -d data.bin /dev/nvme0n1
Rounding data size to fit block count(1024 bytes)
write:Success
四、Read命令
会从所指示的lba的I/O控制器中读取数据和元数据,该命令可以指定作为读取操作的一部分所要检查的保护信息。
协议 | Nvme-cli | 释义 |
---|---|---|
CDW10&11[63:00] | --start-block,-s | 开始的逻辑块地址 |
CDW12[31] | --limited-retry,-l | 进行有限次retry用于错误恢复 |
CDW12[30] | --force-unit-access,-f | 强制设备在命令完成之前将数据写到闪存,数据还是会经过缓存进行写入,只是会等待写入闪存后才返回命令 |
CDW12[29:26] | --prinfo,-p | 指定保护信息操作和检查字段 |
CDW12[15:00] | --block-count,-c | 表示要写入的逻辑块数,基于0‘s based |
CDW13[07:00] | --dsm,-D | 表示正在写的LBA的属性 |
CDW14[31:00] | --ref-tag,-r | 指定初始逻辑块参考标记的期望值,prinfo使用才用此值 |
CDW15[31:16] | --app-tag,-a | 指定应用程序标记的期望值,prinfo使用才用此值 |
CDW15[15:00] | --app-tag-mask,-m | 指定应用程序标记掩码的期望值,prinfo使用才用此值 |
DATA Pointer[63:00] | --data-size,-z | 指定读取的数据大小 |
Metadata Pointer[127:00] | --metadata-size,-y | 指定元数据指针 |
read命令下发,下面命令执行效果相同。
> nvme read -s 0 -c 1 -z 512 /dev/nvme0n1
Rounding data size to fit block count(1024 bytes)
7788
read:Success
> nvme read -s 0 -c 1 -z 512 -d data.bin /dev/nvme0n1
Rounding data size to fit block count(1024 bytes)
read:Success
> cat data.bin
7788
五、Write Uncorrectable命令
用于将一系列逻辑块标记为无效。在此操作之后读取指定的逻辑块时,返回未恢复读取错误状态[02,81]。要清除无效的逻辑块状态,需要对这些逻辑块执行写入操作。
协议 | Nvme-cli | 释义 |
---|---|---|
CDW10&11[63:00] | --start-block,-s | 开始的逻辑块地址 |
CDW12[15:00] | --block-count,-c | 表示要写入的逻辑块数,基于0‘s based |
write uncorrectable命令下发。
> nvme write-uncor -n 1 -s 0 -c 2 /dev/nvme0n1
NVMe Write Uncorrectable Success
> nvme read -s 0 -c 1 -z 512 /dev/nvme0n1
NVMe status:READ_ERROR:The read data could not be recovered from the media(0x281)
六、Compare命令
从介质中读取由该命令指定的逻辑块,并将读取的数据与作为该命令的一部分传输的比较数据缓冲区进行比较。若从控制器和比较数据缓冲区相等,没有错误,则命令成功完成;否则失败。
协议 | Nvme-cli | 释义 |
---|---|---|
CDW10&11[63:00] | --start-block,-s | 开始的逻辑块地址 |
CDW12[31] | --limited-retry,-l | 进行有限次retry用于错误恢复 |
CDW12[30] | --force-unit-access,-f | 强制设备在命令完成之前将数据写到闪存,数据还是会经过缓存进行写入,只是会等待写入闪存后才返回命令 |
CDW12[29:26] | --prinfo,-p | 指定保护信息操作和检查字段 |
CDW12[15:00] | --block-count,-c | 表示要写入的逻辑块数,基于0‘s based |
CDW14[31:00] | --ref-tag,-r | 指定初始逻辑块参考标记的期望值,prinfo使用才用此值 |
CDW15[31:16] | --app-tag,-a | 指定应用程序标记的期望值,prinfo使用才用此值 |
CDW15[15:00] | --app-tag-mask,-m | 指定应用程序标记掩码的期望值,prinfo使用才用此值 |
compare命令下发。
> nvme compare -s 0 -c 1 -z 512 -d data.bin /dev/nvme0n1
Rounding data size to fit block count(1024 bytes)
compare:Success
七、Write Zeroes命令
用于将逻辑块的范围设置为零,成功完成此命令后,后续读取此范围内的逻辑块返回的值应清除到0h,直到写入此LBA范围。
协议 | Nvme-cli | 释义 |
---|---|---|
CDW10&11[63:00] | --start-block,-s | 开始的逻辑块地址 |
CDW12[31] | --limited-retry,-l | 进行有限次retry用于错误恢复 |
CDW12[30] | --force-unit-access,-f | 强制设备在命令完成之前将数据写到闪存,数据还是会经过缓存进行写入,只是会等待写入闪存后才返回命令 |
CDW12[29:26] | --prinfo,-p | 指定保护信息操作和检查字段 |
CDW12[25] | --deac,-d | 主机是否解除分配的指定逻辑块,即同trim返回值相同 |
CDW12[15:00] | --block-count,-c | 表示要写入的逻辑块数,基于0‘s based |
CDW14[31:00] | --ref-tag,-r | 指定初始逻辑块参考标记值,把逻辑块数据与一个地址关联起来,防止被误用或者乱序逻辑块传输,用来检测数据是否写入错误的LBA。prinfo使用才用此值 |
CDW15[31:16] | --app-tag,-a | 指定应用程序标记值,prinfo使用才用此值 |
CDW15[15:00] | --app-tag-mask,-m | 指定应用程序标记掩码值,prinfo使用才用此值 |
write zeroes命令下发。
> nvme write-zeroes -n 1 -s 0 -c 2 /dev/nvme0n1
NVMe Write Zeroes Success
八、Verify命令
通过读取指示的LBA的数据和元数据(如果适用)来验证存储信息的完整性,而不向主机传输任何数据或元数据,Verify操作包括在执行Verify命令期间验证存储信息完整性的控制器操作(例如读取)。即verify本身不传输数据,就是内部读一下看看能不能读,能读就通过。出unc时会报错,即unrecovered read error[02.81]。
协议 | Nvme-cli | 释义 |
---|---|---|
CDW10&11[63:00] | --start-block,-s | 开始的逻辑块地址 |
CDW12[31] | --limited-retry,-l | 进行有限次retry用于错误恢复 |
CDW12[30] | --force-unit-access,-f | 强制设备在命令完成之前将数据写到闪存,数据还是会经过缓存进行写入,只是会等待写入闪存后才返回命令 |
CDW12[29:26] | --prinfo,-p | 指定保护信息操作和检查字段 |
CDW12[15:00] | --block-count,-c | 表示要写入的逻辑块数,基于0‘s based |
CDW14[31:00] | --ref-tag,-r | 指定初始逻辑块参考标记的期望值,把逻辑块数据与一个地址关联起来,防止被误用或者乱序逻辑块传输,用来检测数据是否写入错误的LBA。prinfo使用才用此值 |
CDW15[31:16] | --app-tag,-a | 指定应用程序标记的期望值,prinfo使用才用此值 |
CDW15[15:00] | --app-tag-mask,-m | 指定应用程序标记掩码的期望值,prinfo使用才用此值 |
write zeroes命令下发。
> nvme verify /dev/nvme0n1
NVMe Verify Success
> nvme verify -n 1 -s 0 -c 1 /dev/nvme0n1
NVMe Verify Success
九、Dataset Management命令
主机使用“数据集管理”命令来指示逻辑块的范围属性,包括如读或写数据的频率、访问大小及其他优化性能和可靠性的信息属性。此命令为建议性命令,控制器可以根据所提供的信息选择不采取任何操作。
协议 | Nvme-cli | 释义 |
---|---|---|
CDW10[07:00] | Range[--ctx-attrs,-a;--blocks,-b;--slbs,-s] | 指定16字节范围集的数量,基于0's based |
CDW11[02] | --ad,-d | NVM子系统可以解除分配所有提供的范围,trim |
CDW11[01] | --idw,-w | 数据集被优化为一个集成单元的写访问,即写入数据集一部分,那么预计数据集中所有范围都将被写入 |
CDW11[00] | --idr,-r | 数据集被优化为一个集成单元的写访问,即写入数据集一部分,那么预计数据集中所有范围都将被写入 |
Context Attributes
为每个Range指定上下文属性提供了主机如何实现该范围的信息,此信息的使用是可选的,控制器不需要执行任何特定的操作。
注:无论主机提供属性是否准确,控制器都需要保持NVM介质上数据的完整性。
Command Access Size[31:24]:此数据集的单个读或写命令中预期传输的逻辑块数;置0,表示未提供访问大小
WP,Write Prepare[10]:置1,则所提供的范围预计将在不久将来被写
SW,Sequential Write Range[09]:置1,则数据集应针对顺序写访问进行优化;主机希望将数据集做为单个对象进行写入操作
SR,Sequential Read Range[08]:置1,则数据集应针对顺序读访问进行优化;主机希望将数据集做为单个对象进行读取操作
AL,Access Latency[05:04]:
00b:None
01b:Idle,可接受更长时间延迟
10b:Normal,典型的延迟
11b:Low,最小可能的延迟
AF,Access Frequency[03:00]:
0h:不提供任何频率信息
1h:此LBA范围典型的读写数
2h:对指示的LBA很少写入和很少读取
3h:对LBA范围不频繁写和频繁读
4h:对LBA范围频繁写和不频繁读
5h:对LBA范围频繁读取和写入
Deallocate
使用DSM命令释放的逻辑块在写入逻辑块时不在释放,read和verify不会影响逻辑块的释放状态;从释放的快读取的值应是确定的。
Dataset management命令下发。
> nvme dsm -a 0 -b 8 -s 0 -d /dev/nvme0n1
NVMe DSM:Success