附录参考 - 📘 附录 B 概览:主机软件如何构造 NVMe 命令 (第450页)
我们现在进入了 《NVM Express® Base Specification, Revision 2.0b》附录 B:主机端的设计考量(Annex B. Host Considerations) 的分析环节。这个附录主要是面向主机软件开发者,从构建指令、管理队列的角度,提供一些具体的指导与流程建议。
📘 附录 B 概览:主机软件如何构造 NVMe 命令
B.1 构建 NVMe 命令的基本步骤
主机软件向控制器发出命令前,需要经过以下几个步骤来构造并提交命令:
✅ 步骤一:确认 Submission Queue(提交队列)未满
- NVMe 队列是循环队列,当队列中命令数达到队列大小减一时,视为已满;
- 如果队列未满,主机可以在空槽
SQ[pFreeSlot]中构造命令。
✅ 步骤二:构建命令字段
| 字段 | 说明 |
|---|---|
CDW0.OPC |
设置为对应的操作码,例如读(02h)、写(01h)等 |
CDW0.FUSE |
是否是 Fused Command 的一部分,通常为 00b |
CDW0.CID |
命令标识符,需在该队列中唯一 |
NSID |
指定该命令要操作的命名空间 ID |
MPTR |
若使用单独的 Metadata Buffer,则需填入其地址 |
PRP1/PRP2 或 SGL Entry 1 |
若有数据传输,指定数据缓冲区物理地址 |
CDW10–CDW15 |
指令特定的参数字段,按命令类型决定其含义 |
✅ 步骤三:通过 Transport 层触发命令提交
如 PCIe 的 MMIO 操作,或者 Fabrics 上的传输层驱动。
B.2 创建 I/O Submission Queue 的流程
这一小节详细解释了如何通过 Admin 命令创建一个 使用非连续物理内存地址(PRP List) 的 I/O 提交队列(I/O Submission Queue)。
✅ 前提条件:
- 控制器需支持非连续 PRP(CAP.CQR = 1);
- 创建 I/O SQ 前必须 先创建对应的 I/O Completion Queue(CQ)。
✅ 构建 “Create I/O Submission Queue” 命令的步骤如下:
| 字段 | 设置内容 | 说明 |
|---|---|---|
CDW0.OPC |
01h | 操作码,表示创建 I/O SQ |
CDW0.FUSE |
00b | 非 Fused 操作 |
CDW0.CID |
任一可用命令 ID | 在 Admin SQ 中唯一 |
NSID |
0h | 因为 SQ 非命名空间相关 |
MPTR |
0h | 无 metadata |
PRP1 |
指向 PRP List 的物理地址 | 说明 SQ 本体的地址 |
PRP2 |
0h | 不使用第二个地址 |
CDW10.QSIZE |
191(表示 192 项) | 队列深度,不超过 CAP.MQES |
CDW10.QID |
SQ ID | 要创建的 SQ 的标识符 |
CDW11.CQID |
CQ ID | SQ 将关联的 Completion Queue |
CDW11.QPRIO |
10b | Medium Priority |
CDW11.PC |
0 | 表示使用 PRP List(非连续内存) |
构造完成后,通过传输层提交该命令。
🔒注意:PRP List 在 SQ 生命周期内不得修改或释放,否则控制器可能访问非法内存。
🔍 小结:主机软件构建 NVMe 命令的核心关注点
- 确定队列状态与命令槽位(pFreeSlot)
- 正确填写命令结构体中的关键字段(CDW0~CDW15、PRP等)
- 遵守 NVMe 中的资源生命周期管理(如 PRP List 不可更改)
- 正确配对 SQ 与 CQ,并设置优先级与队列类型
如你希望,我可以进一步配合这部分写一个完整的 C 或 Rust 伪代码示例,来模拟 NVMe Admin 命令构造与提交流程。需要我继续吗?