上篇文章咱们介绍了NVMe热插拔背景知识和常见的流程,下来介绍下最常见的NVMe热插入过程遇到的问题以及简单的识别方法。
一、UEFI设置问题
系统在启动过程中,UEFI初始化过程主要包含:
-
正确的Root Port Bifurcation配置
-
在对应Root Port分配下行Bus Number以及预留足够的内存资源
-
插槽的Root Port的PCIe Capability里面:
-
设置Slot Capability里面的Hotplug Capable
-
根据主板情况,设置Slot Capability里面的SLOT_PWR_LIMIT_SCALE 和SLOT_PWR_LIMIT_VALUE
-
如果支持Surprise remove,设定Slot Capability里面的HOTPLUG_SURPRISE
-
根据主板情况,正确设置Slot Capability里面的PWR_CONTROLLER_PRESENT及其它几个PRESENT位
-
设定PHYSICAL_SLOT_NUM
-
-
Hotplug Descriptor初始化:VPP I2C地址,热插拔类型等
-
对应的SMBIOS和ACPI等
这里比如叫常见的问题主要为:UEFI没有设定正确的Hotplug Capable、没有正确设置PWR_CONTROLLER_PRESENT被设置、没有设置正确的VPP I2C地址、或者Hotplug的处理模式等。是否这方面的问题,可以通过检查以下几个点进行初步排查:不使用热插拔,正常开机是否能检查到;问题是否为100%发生。如果以上两个问题答案均为是,那么就有可能是这个方面的原因。
二、资源问题
从上篇文章的热插入过程,我们知道资源分配问题发生在第14步。这个问题比较简单,通常是UEFI没有在Root port下面预留足够的内存资源,导致操作系统分配资源失败。一般建议保留1MB,但是个别NVMe硬盘可能使用到2MB甚至4MB。确认这个问题的方法也比较简单,OS如Linux的dmesg log就能看到,通常会看到如下log:
WARNING: PCI: 185: 0000:cb:00.0:Failed to assign BAR[4] (MEM64 f=0x4 0x0-0x100000): Out of resources
PCI: 1263: 0000:cb:00.0 8086:41408086:af08 disabled due to insufficient resources or because the device is not supported: Out of resources
三、电源问题
UEFI在PCIe Capability寄存器中的Slot Capability里面SLOT_PWR_LIMIT_SCALE 和SLOT_PWR_LIMIT_VALUE设定错误,导致供电不足。单颗NVMe最高功耗可能高达25W,具体是否为该问题可以查看具体NVMe盘的规范。
四、NVMe盘固件问题
这类问题也常发生,要分析的话通常要用厂商工具读取NVMe的log,交给厂商分析,在这里不做详述。简单判断的方法为,看问题是否发生在特定某个或某系列或某厂商的NVMe盘。
五、时序问题
当我们排除掉上述问题后,我们就可能会怀疑时序问题了。
PCIe规范里面并没有特别定义NVMe的上电时序,但其实总体跟CEM是一样的:
比较容易出问题的是:
-
从3.3V稳定到PERST#拉起的时间不到100ms,导致PERST#拉起的时候,可能电源还没稳定。
-
从PERST#拉起到整个Training完成后DL Active不能超过1秒钟,但是PERST#拉起到RefClock准备好的时间太差,导致后面Training时间不足。
-
各种原因导致PRESENCE信息丢失,其中最常见的就是I2C异常或者背板异常
-
PERST#没有传递到NVMe盘
先解释一下,上面第2条说的1秒钟要求,是从热插入流程步骤7到13这一些列过程。这过程有多次的I2C数据传递和处理,有些I2C数据可能并非实时处理而是使用轮询机制处理,轮询周期的长短将严重影响,甚至可能会发生I2C的不稳定导致重试甚至挂起,所以这个过程其实很容易出问题。要分析这个问题会比较复杂:
首先,看Linux的dmesg log是否有类似如下log:
WARNING: PCIEHP: 1389: 0000:c9:03.0: hotplug slot:0x46 DataLinkLayerStateChanged event does not occur within 1 second, linkStatusDLLLA0
其次,测量NVMe的PERST#最终是否被拉起,如果没拉起,就得一步一步往前排查;如果有拉起,那就检查时间是否超时。
检查超时的两种情况:
-
PWR_CONTROLLER_PRESENT被设置,或者电源由FPGA控制,则测量3.3V拉起到NVMe PERST#拉起的时间差
-
PWR_CONTROLLER_PRESENT没被设置,并且电源一直存在,则测量Clock到NVMe PERST#拉起的时间差
因为考虑到NVMe 后续training的时间可能用到400ms,所以保险起见是上诉两种情况的时间差均不宜超过400ms,留下200ms的余量,从而保证总时间不超过1秒。
如果是第3条PRESENCE丢失问题,那么Linux dmesg log中,类似如下两条log看不到:
PCIEHP: 1552: 0000:c9:03.0: hotplug slot:0x46:num reads=1 slot status=0x48.
PCIEHP: 1465: 0000:c9:03.0: hotplug slot:0x46(0000:cb:00.0) Adapter inserted.
如果是第4条PERST#问题,那么可能会看到第2条类似的log,最终超时1秒,可以通过测量NVMe盘的PERST#信号来确认。
六、其它问题
除了上面说的问题,还有一些其它原因也可能导致热插拔失败。比如,上一次拔出之后,发生了严重的错误,导致CPU Root port进入异常状态无法退出,从而无法完成新的插入和training动作。确认方法为检测AER寄存器,看看是否有错误发生;或者用协议分析仪看CPU Root port是否进入了Compliance mode。
如果中间连接了Retimer,也可能是Retimer异常。如果通过PCIe Switch连接,情况可能又不一样。但不管哪种问题,只要你充分理解了整个插入的流程,一步一步排查,问题总能找到。