nvme协议阅读笔记

作者

QQ群:852283276
微信:arm80x86
微信公众号:青儿创客基地
B站:主页 https://space.bilibili.com/208826118

参考

nvme官网
NVMe over Fabrics 概况

Controller Registers

CAP – Controller Capabilities

CAP的低16位,指示了主控支持的最大IO队列的深度,16位最大是65536,这就是64K最大队列深度的来源。
327

AQA – Admin Queue Attributes

Admin队列,最大深度是4K,
329

SQyTDBL – Submission Queue y Tail Doorbell

330
由驱动写入通知主控Tail位置,在发起传输的时,提交SQ使用。

CQyHDBL – Completion Queue y Head Doorbell

331
由驱动写入通知主控Head位置,在中断里,处理完CQ时使用。

Identify

Identify Controller data structure (CNS 01h)

VWC,在controller的信息中有一个Volatile Write Cache (VWC)位,
286
MDTS,max_hw_sectors = 1 << (id->mdts + page_shift - 9),单次传输的最大大小是有限制的,所以PRP的链表不支持无限长的,实际测试三星970pro的传输大小最大2MB,
292
NVMe over Fabrics使用qualified naming授权命名寻址约定。NVMe Qualified Name(NQN)用于识别远程NVMe存储目标。它类似于iSCSI限定名(IQN)。[2047:1792]是NVMEoF的协议内容,
293
参考NVMEoF协议,
294

mandatory: 强制的; 法定的; 义务的
capsule: (装药物的)胶囊;(装物或装液体的)小塑料容器;太空舱;航天舱

例如IOCCSZ指示nvme_command的长度,

//drivers\nvme\host\rdma.c
static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
		int idx, size_t queue_size)
{
...
	if (idx > 0)
		queue->cmnd_capsule_len = ctrl->ctrl.ioccsz * 16;
	else
		queue->cmnd_capsule_len = sizeof(struct nvme_command);
...
}

Identify Namespace data structure (CNS 00h)

296
295
所以,ns->ext表示set to ‘1’ indicates that the metadata is transferred at the end of the data LBA,metadata和数据一起发送还是存在一个单独的缓存里。ns->ms表示主控支持的LBA格式,

//drivers\nvme\host\core.c
#ifdef CONFIG_BLK_DEV_INTEGRITY
static void nvme_prep_integrity(struct gendisk *disk, struct nvme_id_ns *id,
		u16 bs)
{
...
	ns->ms = le16_to_cpu(id->lbaf[id->flbas & NVME_NS_FLBAS_LBA_MASK].ms);
	ns->ext = ns->ms && (id->flbas & NVME_NS_FLBAS_META_EXT);

	/* PI implementation requires metadata equal t10 pi tuple size */
	if (ns->ms == sizeof(struct t10_pi_tuple))
		pi_type = id->dps & NVME_NS_DPS_PI_MASK;
...
#endif /* CONFIG_BLK_DEV_INTEGRITY */

LBA格式,RP表示该种格式的性能,LBADS表示LBA大小,不得小于512,MS表示metadata的大小,
297
在执行格式化命令Format NVM command的时候可以选择LBA格式,通常,盘加载后有且仅有一个ns,这个格式化命令没有从内核驱动中得到实现。
298

Completion Queue

Status位于DW3的高15位,
314

Status

328
其中Phase Tag位在队列完成一次队列深度的传输之后取反,在驱动中处理完成队列会检查这个位,通过Phase Tag信息能判断中Tail的位置。
315
SCT,状态码的类型,
316
状态码被分为三组,

  • 00h to 7Fh: Applicable to Admin Command Set, or across multiple command sets;
  • 80h to BFh: I/O Command Set Specific status codes; and
  • C0h to FFh: Vendor Specific status codes.

多个队列同时传输时三星970pro返回的status是81940x2002,返回SCInvalid Command Opcode: A reserved coded value or an unsupported value in the command opcode field.More标志置1,More (M): If set to ‘1’, there is more status information for this command as part of the Error Information log that may be retrieved with the Get Log Page command. If cleared to ‘0’, there is no additional status information for this command. Refer to section 5.14.1.1.
对一个盘执行flush命令返回0x4101,对于More标志为1,SCT为0, SC为0x80,属于I/O Command Set Specific status codes;,对应LBA Out of Range: The command references an LBA that exceeds the size of the namespace.,我发一个Admin,怎么返回I/O的错误码呢?首先关注VWC位,
395

DSM-Dataset Management

NVMe SSD新功能Reservation从入门到精通
面壁UNH IOL NVMe一致性测试之9 – Dataset Management command
NVMe之命令

Dataset Management command可以通过设置Dword 11的Attribute-Deallocate(AD)字段deallocate一定范围的LBA,deallocate也就是通常所说的Trim。SSD收到AD字段为1的Dataset Management command后,会将相应范围的LBA Trim掉。如果Host针对被Trim的地址发送read命令,SSD应该返回全1,全0或者最后写入的数据。如果使能了deallocated 或 unwritten logical block error,当Host读取被deallocate区域时,SSD会返回该命令失败并且错误为unwritten或者deallocated logical block error,如果对一个被deallocate的LBA做写操作会导致deallocate状态消失,读操作则没有影响。

HMB

东芝RC100 M.2 NVMe固态硬盘HMB特性解读
4.7 Controller Memory Buffer
How to enable host memory buffer in Windows10 by registry key?
NVMe Host Memory Buffer主机内存缓冲效果
面壁UNH IOL NVMe一致性测试之17 – Host Memory Buffer
StorPortAllocateHostMemoryBuffer function (storport.h)

简言之,HMB是给DRAMLess SSD设计的用来存放FTL表的,肯定是比板载的DRAM延迟要大,毕竟经过了PCIe传输。
hmb

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中的list是一种有序的可变集合,可以包含任意类型的元素,使用方括号[]来表示。以下是list的常见用法: 1. 创建list ``` # 创建一个空的list my_list = [] # 创建一个包含元素的list my_list = [1, 2, 3, "hello", "world"] ``` 2. 访问list元素 ``` # 通过下标访问list元素 my_list = [1, 2, 3, "hello", "world"] print(my_list[0]) # 输出1 print(my_list[3]) # 输出"hello" # 通过负数下标访问list元素,负数下标表示从右向左数 my_list = [1, 2, 3, "hello", "world"] print(my_list[-1]) # 输出"world" print(my_list[-2]) # 输出"hello" ``` 3. 修改list元素 ``` # 通过下标修改list元素 my_list = [1, 2, 3, "hello", "world"] my_list[0] = 0 my_list[3] = "hi" print(my_list) # 输出[0, 2, 3, "hi", "world"] ``` 4. 添加元素到list ``` # 添加元素到list末尾 my_list = [1, 2, 3] my_list.append(4) print(my_list) # 输出[1, 2, 3, 4] # 插入元素到指定位置 my_list = [1, 2, 3] my_list.insert(1, "hello") print(my_list) # 输出[1, "hello", 2, 3] ``` 5. 删除list元素 ``` # 删除list中指定元素 my_list = [1, 2, 3, "hello", "world"] my_list.remove(3) my_list.remove("hello") print(my_list) # 输出[1, 2, "world"] # 删除list末尾元素 my_list = [1, 2, 3, "hello", "world"] my_list.pop() print(my_list) # 输出[1, 2, 3, "hello"] ``` 6. 切片操作 ``` # 切片操作,获取list的一部分 my_list = [1, 2, 3, "hello", "world"] print(my_list[1:3]) # 输出[2, 3] print(my_list[:3]) # 输出[1, 2, 3] print(my_list[3:]) # 输出["hello", "world"] print(my_list[::2]) # 输出[1, 3, "world"] ``` 7. 迭代list ``` # 迭代list my_list = [1, 2, 3, "hello", "world"] for item in my_list: print(item) # 输出: # 1 # 2 # 3 # hello # world ``` 8. 获取list长度 ``` # 获取list长度 my_list = [1, 2, 3, "hello", "world"] print(len(my_list)) # 输出5 ``` 9. 判断元素是否在list中 ``` # 判断元素是否在list中 my_list = [1, 2, 3, "hello", "world"] print(3 in my_list) # 输出True print("hi" in my_list) # 输出False ``` 10. list排序 ``` # list排序 my_list = [3, 2, 1, 5, 4] my_list.sort() print(my_list) # 输出[1, 2, 3, 4, 5] ``` 11. 复制list ``` # 复制list my_list = [1, 2, 3, "hello", "world"] new_list = my_list.copy() print(new_list) # 输出[1, 2, 3, "hello", "world"] ``` 以上是list的基本用法,list还有很多其他的用法,可以根据需要进行查阅。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值