文章目录
- 1 Controller Properties
- 1.1 如何访问
- 1.2 Controller 初始化流程
- 1.3 CAP - Controller Capabilities (Offset 00h, 64-bit)
- X 面试场景问题
- 1 为什么Properties Host必须通过BAR访问,不能通过DMA?
- 2 如果Host按dword访问qword的CAP会怎样?
- 3 CC.EN从1→0关闭Controller时,CSTS.RDY多久变0?
- 4 IO SQ/CQ的创建细节?
1 Controller Properties
NVMe 协议章节 3.1.4 Controller Properties
Controller Properties(如CAP、CC、CSTS) 这些关键的寄存器,和SSD Controller初始化流程相关。
画出初始化状态机流程图?
FTL关注点:
Controller Properties(如CAP、CC、CSTS)通常通过PCIe BAR空间访问
必须按指定宽度(dword/qword)访问,跨Property访问不支持
这意味着:如果你要读取64-bit的CAP(Controller Capabilities),必须一次性读qword,不能分两次读dword
1.1 如何访问
| 层级 | 存储位置 | 说明 |
|---|---|---|
| PCIe BAR空间 | SSD控制器内部的寄存器(Registers) | 物理上在SSD主控芯片内 |
| Host视角 | 映射到Host内存地址空间的MMIO区域 | Host通过内存读写访问 |
Host CPU → PCIe TLP (Memory Read/Write) → SSD Controller BAR → 内部寄存器
关键:Host看到的"内存地址" = PCIe配置空间分配的BAR基地址 + Property Offset
1.2 Controller 初始化流程
Host要把SSD(Controller) 初始化,好让Controller能够开始接收命令
完整的Host初始化Controller的流程状态机如下:
┌─────────────────┐ │1.读取CAP │ ← 确认Controller能力 │(Offset00h)│ └────────┬────────┘ ▼ ┌─────────────────┐ │2.配置CC │ ← 设置Command Set,Page Size │(Offset14h)│ 但不Enable(EN=0)└────────┬────────┘ ▼ ┌─────────────────┐ │3.配置AQA │ ← Admin Queue深度 │(Offset24h)│ └────────┬────────┘ ▼ ┌─────────────────┐ │4.配置ASQ │ ← Admin SQ基址(64-bit)│(Offset28h)│ └────────┬────────┘ ▼ ┌─────────────────┐ │5.配置ACQ │ ← Admin CQ基址(64-bit)│(Offset30h)│ └────────┬────────┘ ▼ ┌─────────────────┐ │6.写CC.EN=1│ ← Enable Controller │(Offset14h)│ └────────┬────────┘ ▼ ┌─────────────────┐ │7.轮询CSTS │ ← Host轮询寄存器,等待RDY=1│(Offset1Ch)│ 检查CFS=0└────────┬────────┘ ▼ ┌─────────────────┐ │8.Identify │ ← 发送Admin命令 │ Controller │ 获取设备信息 └────────┬────────┘ ▼ ┌─────────────────┐ │9.Create I/O │ ← Host发送 创建I/O Queue 请求 │ Queues │ └────────┬────────┘ ▼ ┌─────────────────┐ │10.开始I/O │ ← 发送Read/Write命令 └─────────────────┘FTL需关注的Properties如下
| 关注点 | 为什么重要 |
|---|---|
| CAP.MPS | 决定PRP List结构,影响数据传输效率 |
| CAP.MQES | 决定Queue深度,影响并发I/O性能 |
| CC.MPS配置 | 必须与Host内存页大小匹配 |
| CSTS.RDY轮询 | 超时处理,防止初始化死锁 |
| Doorbell机制 | Tail Doorbell通知有新命令,Head Doorbell通知已取走完成 |
1.3 CAP - Controller Capabilities (Offset 00h, 64-bit)
CAP是只读寄存器
| 字段 | 位 | 作用 | FTL关注点 |
|---|---|---|---|
| MQES | 15:00 | Max Queue Entries Supported | 决定SQ/CQ最大深度(0-based) |
| CQR | 16 | Contiguous Queues Required | 1=必须用物理连续队列 |
| AMS | 18:17 | Arbitration Mechanism Supported | 0=Round Robin, 1=Weighted RR |
| TO | 23:20 | Timeout | 500ms × (TO+1),初始化超时计算 |
| DSTRD | 31:24 | Doorbell Stride | 每个Doorbell寄存器间距 = 4 << DSTRD |
| NSSRS | 33 | NVM Subsystem Reset Supported | 是否支持NSSR |
| CSS | 44:37 | Command Sets Supported | 支持哪些I/O Command Set |
| MPSMAX/MPSMIN | 52:32 | Memory Page Size Max/Min | 决定PRP/SGL页大小 |
X 面试场景问题
1 为什么Properties Host必须通过BAR访问,不能通过DMA?
Properties是控制器状态/配置寄存器,需要CPU直接访问(低延迟)。DMA用于数据传输(高吞吐)。BAR映射到MMIO空间,CPU可用普通load/store指令访问。
2 如果Host按dword访问qword的CAP会怎样?
未定义行为。Spec要求必须按定义宽度访问。实际可能导致读取错误值或触发错误。
3 CC.EN从1→0关闭Controller时,CSTS.RDY多久变0?
取决于CAP.TO定义的Timeout。Host必须轮询等待,或超时后强制Reset。
[疑问,CC.EN从1→0 该行为意味着什么?Controller内部做什么后会把RDY置为0?]
4 IO SQ/CQ的创建细节?
在Controller 准备就绪后,Host会给Controller发消息,来创建 IO SQ/CQ。
创建SQ/CQ的 队列数量 和 深度,如何确定的?
Host会通过Identify命令,来获取Controller 支持的 队列数量上限。
Host会通过Set Features的Number Of Queues 属性,来向Controller传递想要的 IO SQ/CQ 数量。
Number Of Queues 是 SSD的一个Feature
NSQ (Number of Submission Queues):主机希望创建的I/O提交队列数量(0值表示1个队列)。
NCQ (Number of Completion Queues):主机希望创建的I/O完成队列数量(0值表示1个队列)。
控制器收到请求后,会评估自己的能力。它不一定能满足Host的所有请求,可能会返回一个它实际能支持的、接近请求值的数量。这个协商结果会通过Set Features命令的完成队列条目返回给Host。之后,Host会读出该结果作为实际分配数量的参考。
获得最终数量后,Host便开始按这个参考结果进行实际的队列创建操作,主要有两种Admin命令:
Create I/O Completion Queue命令:用于逐个创建I/O CQ。命令参数包括指定CQ ID (qid) 和大小 (qsize) 等。
Create I/O Submission Queue命令:用于逐个创建I/O SQ。创建时需指定归属的CQ ID,实现多SQ对一CQ的关联。
典型协商流程
初始匹配阶段:主机首次写入 Set Features (FID=07h),假设要申请 NCQ=63 和
NSQ=63。若控制器最大支持32个I/O队列(0-based返回31),协商后主机会读取 Result 值: Result = (31
<< 16) | 31 (即0x001F001F)。逐个创建阶段:最终按 31 的返回值,通过 Create I/O Completion Queue 和 Create I/O
Submission Queue 命令逐个创建这些队列。