本文总结 NVMe
热插拔情况下系统和 NVMe
设备会发生什么。
Update: 2022 / 11 / 7
NVMe | 热插拔
- 总览
- 起因
- 实现
- 硬件
- pin 脚及信号
- 寄存器
- 准备工作
- BIOS
- 软件
- 插入
- 软件
- 拔出
- 软件
- 参考链接
总览
参考这里 1’ 2’ 3’ 4’ 5
起因
为什么要有热插拔 ?——
从历史上到目前,IT
系统设备( PC
、服务器、存储等等)中,对于 RAS
( Reliability
,Availability
,Serviceability
,即可靠性、可用性和可维护性)的要求变得越来越高。
那么系统怎么样才更可靠,可用性才更高?这是有专门的可靠性设计的,涉及太多的领域,我们不展开。常规的看,对于系统可能出现的问题和故障,需要做 故障检测
、故障隔离
、故障告警
、故障恢复
等等。
- 故障的检测可能会使用检测链路状况、器件状态等等。在
PCIe
领域,常见的是检测链路协商宽度、速率,检测AER
寄存器等等。 - 故障的隔离主要的目的是让故障或即将故障失效的器件、部件从系统中隔离出去。比如把失效的
PCIe
卡从系统中移除,不再接管业务,避免故障扩散。 - 故障恢复的手段就更多样化了,有复位修复、上下电修复、备份冗余、故障时切换备机等等。比如把失效的
PCIe
设备重新上下电做修复,或者把业务切换到备用的卡上,或者更换故障PCIe
卡,也就是我们常说的更换FRU
(Field Replace Unit
现场可更换单元)
网上很多的文章和书籍讲热插拔,都是讲的标准的热插拔,主要目的是为了现场快速更换 PCIe
设备。
热插拔的基本目的是要让 PCIe
设备按照规定的顺序、原则,从系统中移除或插入到系统中来,并能正常的工作,且不影响系统的正常运行。事实上,PCIe
热插拔
的关键目的就是为前面面所提到的系统 RAS
服务的,是提升系统 RAS
能力的非常重要的手段。
热插拔有三个重要的功能:
- 在线替换发生故障的
PCIe
设备。不需要关闭、重启系统; - 热插拔器件,系统及其他功能服务继续运行,不受影响;
- 热插拔
PCIe
设备的相关驱动/软件自动加载 / 卸载;
Spec
中对于热插拔是这样定义的:
功能 | 定义 |
|
|
|
|
注意,这里有两个相关概念,前面我们讲的热插拔,其实是广义的“热插拔”。这里的 Hot-Plug
,为了方便,我们叫做 PCIe
热插拔,也就是我们现在及后面将要讨论的内容。
热插拔分为两种,一是 通知式热插拔
,一个是 暴力热插拔
,所谓 通知式热插拔
就是先通知 driver
卸载驱动,停止 I / O
,然后再拔出。所谓 暴力热插拔
就是带着 I / O
拔出
Hot Swap
,即热交换,也叫热切换,主要指的是 CPCI
( Compact PCI
,紧凑型 PCI
)领域所使用的。关于 Hot Swap
,CPCI
有专门定义的一套规范,叫 《CompactPCI® Hot Swap Specification》
,也有中文版本,有兴趣的可以自行研究。
实现
Spec
定义的热插拔是把一个 PCIe
卡(设备)从一个正在运行的背板或者系统中插入/或者移除。这个过程需要不影响系统的其他功能。插入的新的设备可以正确工作。
显然,这里面需要考虑的问题有硬件和软件两方面的事情。
硬件
pin 脚及信号
SFF-8639
也叫 U.2
,物理结构可以兼容 SAS
,SATA
,SATA Express
和 NVMe
。SFF-8639
详细的引脚定义可以参考 PCI Express SFF-8639 Module specification
。
其中比较重要的 PCI sideband
信号有 PWRDIS
、IfDet#
、PERST#
、DualPortEn
。
信号 | 作用 |
| 该信号 |
| 长针信号,是 |
|
|
| 双端口盘(一般存储上会用双端口盘)该信号需要 |
对于热插拔,Spec
对于所谓插槽(插卡)的 ON
、OFF
状态都做了比较清晰的定义,如下:
状态 | 定义 |
| • Power is applied to the slot. • REFCLK is on. • The link is active or in the standby (LOs or Ll ) low power state due to Active State Power Management. • The PERST# signal is deasserted. 简而言之:电源打开、时钟开启、链路 |
| • Power to the slot is turned off. • REFCLK is off. • The link is inactive. (Driver at the root of switch port is in Hi Z state) • The PERST# signal is asserted. 简而言之:电源关闭、时钟关闭、链路断开、复位信号拉低生效。 |
寄存器
Spec
为标准热插拔控制器定义了一套标准的寄存器组,即 PCI Express Capbilities
结构里面包含的内容。
PCI Express Capbilities
结构的 Cap ID
为 0x10
,可以容易的根据 ID
找到这个结构。这个结构里面包含 Device Capability
、Device Control / Status
、Link Control / Status
、Slot Capbility / Control/Status
等多个寄存器。
不是每个 PCIe
设备都完全具备这个图里的所有寄存器的。我们关注的热插拔,其实主要是Root Complex
和 PCIe Switch
的下行端口是有热插拔能力的。
在这些寄存器中,对于热插拔而言,我们重点关注 Slot
相关的几个寄存器:Slot Capabilities
、Slot Status
、Slot Control
。在讲这几个寄存器之前,我们首先要了解一下 Spec
定义的关于热插拔可能产生的事件(中断,可以通过设置 Slot Control
寄存器的 bit5
Hot-Plug Interrupt Enable
来使能):
事件 | 说明 |
插槽事件 | 插槽检测到的一些动作或状态变化 • 按钮按下事件 • 检测到电源失效( • • 在位检测变化事件 |
命令完成事件 | 设置 |
数据链路层状态变化事件 |
|
下面,我们简单看看几个相关的寄存器:
-
Slot Capabilities
:表征了这个槽位的能力,是否支持热插拔。
比如,Bit0
Attention Button Present
表示了这个槽位的按钮是否存在。其他bit
位根据命名基本上都能清楚的看出来是做什么用的,不再赘述。
注意一下Physical Slot Number
这个字段,这个字段表征当前槽位的槽位号,往往是PCIe Switch
/RC
的内部定义端口号。
-
Slot Control Register
:主要控制热插拔功能的寄存器。
-
Slot Status Register
:主要表示热插拔状态的寄存器。
硬件上看,很显然,一个新的设备插入系统,肯定是需要硬件上支持识别到这个插入动作的。因此,Spec
定义了一个 在位
( Present
)的 pin
脚,硬件上用作判断 PCIe
卡是否插入。卡插入时,这个 pin
被拉低。当然,因为 PCIe
金手指的长度较长,插入卡时有可能前后高低差异。因此,需要有前后多个 Present Pin
来确保金手指完全插入。
需要注意的是,检测卡是否在位,除了使用 Present Pin
之外,也可以通过链路的负载检测等来完成。也就是所谓带内检测在位。或者一些特殊的场景比如 NT-NT
背靠背,就没有 Present
信号。NT-NT
的插入时,链路自动重新 Link
。
除了在位( Present
),硬件上还需要实现的是:电源控制,复位逻辑(可控的给出 PERST
信号复位新插入的设备)。另外,Spec
定义的热插拔是可控的、优雅的,不是突然地、暴力的。因此,热插拔的控制逻辑,需要一个按钮,来告诉系统我需要插入/拔出了。另外,人机界面上,一个 LED
指示灯来提示用户热插拔的工作状态也是友好的。
综上,热插拔所需要的的硬件基本元素如下:
|
|
| 绿色的 |
| 黄色 |
|
|
| 检测锁止开关是否打开的光传感器。协议定义的 |
| 机电联锁。一种确保不能随意移除卡的机制。 |
| 按钮。用于告诉系统 |
| 热插拔槽位标号,这个取决于每个公司的自定义。 |
| 上下电控制部分。包括电源故障检测。 |
上面是 Spec
定义的一些元素,实际应用中,可以根据自己的实际项目需求来取舍。下图是一个支持热插拔的 PCIe Switch
的典型信号示意图:
准备工作
BIOS
- 为每个端口预留资源
由于 PCIe
设备的枚举是遵从深度优先的原则,如果系统启动时没有带盘启动,BIOS
枚举时不会为 RP
或者 switch
下行口预留资源( bus
资源、memory
资源、prefetchable memory
资源)。后面再插入 Nvme
盘,由于端口资源不足,盘无法枚举进系统,除非软件重新调整资源后再枚举(这样会影响其他盘的 IO
)。
如果是要做整机系统卖给客户,BIOS
必须要为支持热插拔的端口预留资源(按照系统支持的EndPoint
需要的最大资源预留)。如果仅仅是验证芯片功能,可以让系统带着 Nvme
盘或接口卡启动,确保在枚举时为支持热插拔的端口分配了资源。
-
PCI Express
配置空间设置
由于 PCIe
配置空间有些 reg
是 HwInit
的,驱动是无法访问的,如果要支持 Nvme
盘的暴力热插拔,需要 BIOS
或者 Firmware
初始化一些 HwInit
的 reg
。
Slot Implemented
如果 PCIe Capabilities
中的 Slot Implemented
没有实现,将会导致 Slot Capability
无法实现。因此,Slot Implemented
必须为置 1
。
Surprise Down Error Report Capable
Link Capabilities Reg
中的 Surprise Down Error Report Capable
必须要为 1
,否则无法把 Surprise Down Error
转换成 DPC
(如果要接 NVMe
盘的端口不支持 Surprise Down
,则不需要修改该 bit
)
Data Link Layer Link Active Reporting Capable
Data Link Layer Link Active Reporting Capable
最好实现,这样可以通过带内 Link Up
和 Link Down
方式辅助定位 NVMe
是否被拔出。
Power Controller Present
Slot Capabilities Reg
中的 power controller present
最好能实现,这样软件可以控制槽位电源。Hot-plug surprise
必须为 0
(如果接 Nvme
盘的端口不支持 surprise down
的错误可以不关注该bit
),hot-plug surprise
是 DPC
实现之前传统的 surprise down handling
机制,其实有点掩耳盗铃的意思。由于在某些平台上,RC
收到 uncorrectable error
的 message
会导致系统 crash
,因此在支持热插拔时就增加了 hot-plug surprise bit
,当出现 surprise down error
时,不向 host
报告错误,从而阻止系统 crash
。这个 bit
只能阻止 surprise down error
的上报,不能处理暴力拔出时未完成的 I / O
的导致的 CPU
等待超时问题,并且会影响 DPC
功能,属于历史遗留问题。
针对这一点 PCIe
Spec
也有详细的描述:
Hot-Plug Capable
Hot-Plug Capable
需要为 1
,否则无法支持热插拔的各种中断。
软件
当 Slot
有对应的能力时,软件需要打开 Slot Ctrl capabilities
对应的 bit
,并且根据系统要求设置 DPC Ctrl
。
插入
软件
NVMe
暴力插入的流程中软件层面流程图如下图所示:
其中 CPLD
模拟的 PCA9555
可以由真正的 PCA9555
芯片代替,使用 CPLD
模拟 PCA9555
完全是基于成本考虑。
- 当
SSD
被插入,IfDet#
信号就被拉低,SFF8639
后的I / O
端口改变,GPIO
中断到FW
,FW
通过IIC
接口读取SFF8639
后的I / O
端口,然后和已经保存的I / O
端口状态对比,发现某个slot
的IfDet#
信号改变。 -
FW
更改芯片配置空间的presence status
和presence change status
寄存器。presence change
change
中断(MSI
中断)到CPU
,CPU
调用hotplug service
注册的中断服务函数。 - 中断服务函数起线程或者工作队列读取配置控制的
presence change status
,presence status
、power status
,FW
把配置空间的转换成IIC
读取SFF8639
对应的IO
端口。 - 线程或者工作队列根据
presence change status
,presence status
、power status
来判断是否要热插拔,如果满足热插拔条件,则写配置空间的power ctrl
把slot
上电,然后等待PCIe
链路linkup
。 -
FW
通过IIC
写把配置空间的power ctrl
写到SFF8639
对应的IIO
端口,NVMe SSD
被上电,#PERST
释放,PCIe
链路link up
。 - 线程或者工作队列等待
PCIe
链路link up
后,扫描NVMe
,调用NVMe
注册的probe
。 -
NVMe driver
配置芯片返回probe
流程,热插入完毕。
SFF-8639
spec
定义的在位信号和 PCIe
的定义是有冲突的。SFF-8639
规定 PRSNT#
和IfDet#
这两个带外信号都是 frist-to-mate
and last-to-break
的,也就是说 SFF-8639
规定的PRSNT#
和 IfDet#
比 PCIe
带内信号要长,而 PCIe
spec
规定的恰好相反。
下面是 PCIe
SFF8639
Module Specification
的原话:
The SFF-8639 interface includes the PRSNT# and IfDet# signals, as an out of band presence detect mechanism, to detect the presence of the SFF-8639 module. Since PRSNT# and IfDet# are not in the last-to-mate and first-to-break group, another vendor-specific mechanism is required to provide warning of module removal。
由于历史原因( SAS
盘上是没有 button
按钮)导致的客户操作习惯(客户换盘都是暴力拔出的),Nvme
盘需要支持 暴力热插拔
而不是 通知式热插拔
。暴力热插拔
是指不提前通知驱动停I / O
的情况下,就把 PCIe
设备从系统中拔出,这样会导致存在未完成的 I / O
。
支持 暴力热插拔
要求 switch
或者 RP
( 如果 SSD
接在 switch
下或 RP
下)可以协助处理这些未完成的请求,或者 host
有类似的机制,针对未完成的 Non posted
请求,返回 completion
包( PCIe
协议要求 Non posted
请求需要 completion
包),从而阻止 host
等待未完成的请求导致的超时(超时可以能导致系统 crash
)。这就要用到 PCIe 3.1
协议新增的一个重要的 capability
:DPC
。
DPC
是什么? DPC
全称 Downstream Port Containment
,这个 capability
是 PCIe 3.1
协议针对root port
和 switch downstream port
新增的。其作用是当检查到下行口本身出现错误(什么等级的错误会触发 DPC
是可以配置的)或者下行口下面的设备上报错误 message
(什么等级的error message
会触发 DPC
也是可以配的)可以关闭对应端口(让该端口的 LSTTM
进入disable
状态),把 PCIe traffic
拦截在该端口之下,从而阻止错误扩散。
针对未完成的 Non posted
的请求,root port
或者 switch downstream port
根据 DPC
的设置返回completion
包,completion
包的状态是 UR
或者 CA
。对应 Non posted
的请求,在 completion
没有返回前,CPU
认为该指令是未完成的。DPC
这种机制就为系统恢复错误提供了机会,因此,可以用来实现 Nvme
盘的暴力热插拔的需求。
拔出
先看卡的拔出过程。(注意,我们这里的插拔不是暴力的拔出,所谓暴力,是指不通知系统和软件,直接暴力的、突然的把 PCIe
卡从系统槽位中拔出。Spec
定义的热插拔是有严格的顺序要求和处理过程的。)
软件
NVMe
暴力拔出的流程中软件层面流程图如下图所示:
- 按
Attention Button
按钮或者通过软件的命令,通知热插拔控制器开始进行热拔出操作。 - 闪烁
LED
灯,表示这张卡准备从系统中移除。五秒内没有其他异常,流程继续。五秒内可以取消此次操作。 - 系统把这个
PCIe
设备在系统中拥有的资源删除,如总线资源、Memory
资源等。确保再没有流程访问这种卡。 - 关闭这个卡所在槽位的电源。关闭
LED
灯,表示该卡可以从系统中拔出了。完成Surprise Remove
流程。 - (可选操作)打开
MRL
。 - 用户移除这张卡。如果过程中有错误,则跳出移除过程,可以点
LED
红灯表示错误。需要人工干预处理。
软件方面的元素,其实简单来说就两个:
- 热插拔驱动:系统的驱动程序,支持
PCIe
的热插拔过程、移除拔出卡的资源、重新分配插入卡的资源、控制上下电等等。 - 支持热插拔的设备驱动:主要是需要支持插入时的初始化和移除时的资源释放。典型的是
linux
设备驱动的probe
/remove
。
参考链接
- HOT-PLUG(一) ↩︎
- HOT-PLUG(二) ↩︎
- HOT-PLUG(三) ↩︎
- HOT-PLUG(四) ↩︎