在上面SGL例子中,共有3个SGL段,用到了4种SGL描述符。Host需要往SSD中读取13KB的数据,其中真正只需要11KB数据,这11KB的数据需要放到3个大小不同的内存中,分别是:3KB,4KB和4KB。
4.3.3 比较PRP与SGL无论是PRP还是SGL,本质都是描述内存中的一段数据空间,这段数据空间在物理上可能连续的,也可能是不连续的。Host在命令中设置好PRP或者SGL,告诉Controller数据源在内存的什么位置,或者从闪存上读取的数据应该放到内存的什么位置。
SGL和PRP本质的区别在于,一段数据空间,对PRP来说,它只能映射到一个个物理页,而对SGL来说,它可以映射到任意大小的连续物理空间,具有更大的灵活性,也能够描述更大的数据空间。如下图:
5. NVMe协议定义的命令5.0 命令执行过程命令由host提交到内存中的SQ队列中,更新TDBxSQ后,NVMe控制器通过DMA的方式将SQ中的命令(怎么取,如何取,取多少,因设计而异)取到控制器缓冲区,执行命令;执行完成后,根据执行状态,组装完成命令,仍然通过DMA的方式将完成命令写入内存CQ的队列中;NVMe控制器通过MSI-X中断方式通知host已完成命令;最后,host处理CQ命令,更新控制器中HDBxCQ,标识着命令真正完成。
5.1 命令分类命令分为Admin指令与NVM指令(I/O指令)。
Admin指令只能提交到Admin Controller中,主要负责管理NVMe控制器,也包含对NVM的一些控制指令。
NVM 指令只能提交到I/O Controller中,主要负责完成数据的传输。
在1.0e版本中,Admin指令有15条(3条与NVM相关),NVM指令有6条;在1.3d版本中,Admin指令有15条(3条与NVM相关),NVM指令有11条。
5.2 命令通用格式命令均为64字节,具有相同的格式,某些字段根据命令的不同有不同的定义。
Dword0 | CID、传输方式、聚合操作、操作码 |
1 | NID(命名空间ID) |
2 | 保留 |
3 | 保留 |
4、5 | 元数据指针(MPTR) |
6-9 | 数据指针(DPTR) |
10-15 | 根据命令指定 |
完成命令同样具有相同的格式,某些字段根据命令的不同有不同的定义。
Dword0 | 根据命令指定 |
1 | 保留 |
2 | SQID、SQ头指针 |
3 | 状态域、P位、CID |
Admin指令与NVM指令根据放置的的队列组(Queue Pair)来区分,Admin指令在Admin CQ与SQ里,NVM指令在I/O CQ与SQ里。
通过Dword0中的8位操作码定义不同指令,注意并不是绝对的顺序增加(eg,没有03h)。每一种指令都对应有其完成命令,通过SQID(提交队列ID) CID(命令ID)唯一标识完成的命令。
操作码 | 指令 | 作用 |
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 | 固件镜像下载, | 下载固件镜像 |
Note:
- Admin队列是通过配置ASQ等寄存器创建的
- 先创建CQ再创建SQ
NVMe控制器读写的最小单元是LB,层次图如下:
NVM指令与Admin指令结构完全相同,也是通过Dword0中的8位操作码来定义不同指令。
操作码 | 指令 | 作用 |
00h | Flush | 将数据(和元数据)提交到NVM中,所有命令都要执行 |
01h | Write | 将数据(和元数据)写入NVM中 |
02h | Read | 读NVM中的数据(和元数据) |
04h | Wirte Uncorrectable | 标记无效数据块 |
05h | Compare | 比较从NVM端读出的数据和比较数据缓冲区的数据 |
09h | Dataset Management | 标识一定范围数据的特点,eg,频繁读、频繁写(提升性能) |
控制器从功能上可以分为三类,I/O、Admin和Discovery。
在实现过程中,Admin 控制器只有一个,负责管理控制器及其他控制功能。控制器只是抽象的概念,应用于具体的实现中,可能是一个具体的模块,也可能多个模块。
控制器主要的作用是实现对NVMe定义命令的翻译,从而实现数据传输、状态控制等功能。
6.1 命令执行过程1. host将命令(1条或者多条)写入提前分配好的SQ中;
2. 更新对应SQ的DB寄存器;
3. NVMe控制器取SQ中命令(通过HDB和TDB可以判断是否有未完成命令);
4. NVMe控制器执行命令;
5. NVMe 控制器在命令完成后,将完成命令(可能执行成功,也可能失败,但都会返回完成命令)写入host内存SQ对应的CQ中;
6. NVMe 控制器根据实现的中断方式,提醒host命令已完成;
7. host响应中断,处理完成命令;
8. host 更新对应CQ的DB寄存器。