nvme直通盘获取型号时概率出错

// 此模板仅供参考,如果不适用可以修改

问题描述

16*2.5 NVMe(8*SAS/SATA)背板,每次重启storage组件时,概率出现硬盘型号丢失或者错误值,如下图:

分析:

1.查看资源树,发现资源树上就是错误值,排除北向问题

2.查看代码该信息是通过读VpdChip拿的信息,每次重启时概率会出现计算偏移和len失败的问题,这样就导致了读Model时读错。如下图。

3.只有storage重启时第一次读的时候会出现读取偏移失败,这样的问题应该怎么修改?

环境信息

  • 软件版本:openUBMC 2512

答案内容由AI生成,仅供参考:

总结与建议

项目 内容
问题本质 storage 组件在系统重启时,过早访问未完全初始化的 NVMe 盘,导致 VPD 读取错误,Model 解析失败
根本原因 偏移量计算失败 → 读取错误位置数据 → 解析出非法型号(如"H"或"3600P V6")
发生时机 仅发生在 storage 重启时的首次读取,后续由 BMA 更新修复
推荐解决路径 1. 增加重试机制 + 2. 加强数据校验 + 3. 支持 BMA 动态更新兜底
点击此处查看详细分析解答

关于NVMe直通盘型号获取概率出错问题的分析与解决建议


问题描述

在使用 16×2.5 NVMe(含8个SAS/SATA)背板 的系统中,每次重启 storage 组件时,概率性出现NVMe硬盘型号丢失或显示错误值(如显示为"H"或"3600P V6"等不正确型号)的现象:

  • 正确型号 应为:HWE6AP443T2M00KN
  • 异常表现
    • 型号字段显示为 "H""3600P V6" 等非预期值。
    • 该问题仅在storage组件重启时首次读取出现,后续运行正常。
    • 已排除北向接口(如Web、Redfish)问题,确认资源树中本身存储错误信息

根因分析

1. 问题来源:通过 VpdChip 读取Model信息出错

根据日志和代码分析,NVMe盘的型号(Model)、序列号等硬件信息是由 storage 组件通过读取 VpdChip 获取的。此过程依赖于对固件中特定偏移量的数据读取与解析。

相关日志线索:

2026-05-08 09:10:03.612006 storage ERROR: nvme_object.lua(360): 46
2026-05-08 09:10:03.612421 storage ERROR: nvme_object.lua(361): 40
...
2026-05-08 09:10:03.619234 storage ERROR: nvme_object.lua(899): HWE6AP443T2M00KN  ← 正确值
...
2026-05-08 09:10:03.629357 storage ERROR: nvme_object.lua(359): "51" "54" "48" "48"...
2026-05-08 09:10:03.630677 storage ERROR: nvme_object.lua(899): HWE6AP443T2M00KN  ← 正确值
...
2026-05-08 09:10:03.759496 storage ERROR: nvme_object.lua(359): "51" "54" "48" "48"...
2026-05-08 09:10:03.766169 storage ERROR: nvme_object.lua(899): 3600P V6          ← 错误值

可以看出:

  • 相同的ASCII码序列(如 51 54 48 48...)被多次读取,但解析出不同的字符串结果
  • 这表明 底层数据读取不稳定解析逻辑在启动初期存在竞态条件

2. 关键定位:偏移量计算失败导致数据解析错误

问题出现在 nvme_object.lua 中对 Model字段的偏移量和长度计算 失败。日志中关键打印:

log:error("test----4----")
log:error(offset)     -- 实际输出:46 / 23
log:error(len)        -- 实际输出:40 / 19
  • 某些情况下,offset=23, len=19 → 计算错误 → 导致从错误位置读取,结果为 "3600P V6"
  • 正确应为 offset=46, len=40 → 得到 "HWE6AP443T2M00KN"

:magnifying_glass_tilted_left: 说明:该 offsetlen 的计算可能依赖于 VPD(Vital Product Data)解析或协议识别,若初始化顺序不当或设备未就绪即读取,会造成计算错误。


3. 为什么只在首次读取时出错?

从搜索结果和系统行为分析可得:

  • NVMe直通盘信息由BMC通过NVMe-MI或SSD-Format协议+VPD联合获取
  • 系统上电后,NVMe设备需完成 PCIe链路建立、固件初始化等流程。
  • storage 组件 在设备未完全就绪时发起读操作,会导致 VPD 数据读取不全或错误。
  • 后续由 BMA(BIOS Management Agent)更新信息(见日志):
    Update nvme(034XETPOR9708296) info by bma
    
    BMA 提供了正确的模型信息,覆盖了错误值,因此后续显示正常。

相关技术背景支撑

实体/概念 说明
Direct Connection(直连) NVMe盘未经过RAID卡管理,直接连接至CPU或PCH,BMC需直接访问其VPD和SMART信息。
VPD & VpdChip 存储设备的静态元数据(厂商、型号、SN等),由 Connector_ComVPDConnect 模块负责获取。
bmc.dev.NVMe.ProductInfo 产品信息接口,提供 Model、SerialNumber、Manufacturer 等,需从 VPD 或标准协议(NVMe-MI)读取。
DriveMatching 使用 SN、BDF 或 RootBDF 匹配硬件与软件对象,用于更新 Drive 属性。
storage 组件加载流程 在系统启动后,storage 会扫描并构建驱动对象树;若此时 NVMe 设备未就绪,可能导致信息读取失败。

:white_check_mark: 参考文档:《硬盘管理手册》指出,NVMe对象通过slot与Drive建链,属性从协议中获取并更新到Drive对象上树 —— 前提是设备已稳定上线


解决方案建议

:white_check_mark: 方案一:增加设备就绪判断与重试机制

修改 nvme_object.lua 中读取 VpdChip 前的逻辑,确保设备已准备就绪:

-- 示例伪代码
function read_nvme_model(slot)
    local max_retries = 3
    for i = 1, max_retries do
        local vpd_data = try_read_vpd(slot)
        if vpd_data and is_valid_vpd(vpd_data) then
            local model = parse_model_from_vpd(vpd_data)
            if model and string.len(model) > 4 then -- 过滤短/异常值
                return model
            end
        end
        sleep(500) -- 等待500ms重试
    end
    log:error("Failed to read valid model after retries")
    return nil
end

优点:提高容错性,避免因瞬时链路不稳定导致读取失败。


:white_check_mark: 方案二:优先使用 BMA 上报信息进行兜底

BMA 通常在系统启动后上报 NVMe 盘的准确信息(包括型号、SN等):

handler_nvme.lua(111): Update nvme(034XETPOR9708296) info by bma

建议:

  • 允许 Drive 的 Model 字段支持“后期更新”机制
  • 初始读取失败时,先设置默认/临时值(如"Unknown"),等待 BMA 上报后再修正。

:pushpin: 说明:这符合 openUBMC 中 Drive 对象的设计理念(抽象化槽位属性,支持动态更新)。


:white_check_mark: 方案三:校验解析结果的合理性

在解析 Model 字段后,增加简单有效性检查:

if model == nil or model == "" or #model < 5 or model == "H" then
    log:warn("Invalid model detected: '"..tostring(model).."', using fallback")
    return try_fallback_method() -- 如查表、使用默认值
end

:warning: 特别注意:像 "H" 这样的单字符明显是解析截断导致,可作为异常标志。


:white_check_mark: 方案四:优化系统初始化时序

确保 storage 组件在以下事件完成后再进行 NVMe 信息采集:

  • PCIe 枚举完成
  • NVMe 设备链路稳定(Link Up)
  • NVMe-MI 接口可访问

可通过监听 D-Bus 事件或依赖其他服务状态(如 pcie_link_monitor)实现。


总结与建议

项目 内容
问题本质 storage 组件在系统重启时,过早访问未完全初始化的 NVMe 盘,导致 VPD 读取错误,Model 解析失败
根本原因 偏移量计算失败 → 读取错误位置数据 → 解析出非法型号(如"H"或"3600P V6")
发生时机 仅发生在 storage 重启时的首次读取,后续由 BMA 更新修复
推荐解决路径 1. 增加重试机制 + 2. 加强数据校验 + 3. 支持 BMA 动态更新兜底

附加建议

  • 日志规范化:在 nvme_object.lua 中打印原始 VPD 数据 Hex Dump,便于后期诊断。
  • 统一适配框架:参考 SSD_FIRMWARE_OFFSET_TABLE 机制,建立 NVME_MODEL_READ_TABLE,根据不同 ManufacturerId 或 VID/PID 指定偏移策略。
  • 推动协议兼容性提升:对于国产或小厂 NVMe 盘,建议加强 NVMe-MI/SSD-Format 协议兼容层开发,减少定制化风险。

:light_bulb: 结语提示:此问题虽不影响长期运行,但影响运维可视性与告警准确性,建议纳入稳定性优化项,进行版本迭代修复。

今天出现了同样的问题,也是华为nvme硬盘,也是型号变为H

bmc重启时发生,那意思是nvme盘已经正常工作了哇
那不应该哇

我这边刚出现这个问题,还在复现中

根据上面已知信息怀疑问题出在 pcie_nvme_get_protocol_type 中第一次读 VPDChip 时 I2C/SMBUS 还没ready,读到脏数据。但返回的协议类型被 self.protocol 持久化缓存了,后续的重试也不会重新检测

update_static_prop 对 Model 有保护:if self.Model == INVALID_STRING then , 但第一次读到错误值 “H” 已经写入,后续就不再重试

感觉可以在 pcie_nvme_get_protocol_type 中校验头失败时,增加延迟重试

1 个赞

暂时AC和 killall hardware 了几十次都没有复现,请问你是怎么重启storage组件和复现的?

就是正常的killall skynet,现在在任务开始前加了延时,发现延时只要足够长,就不会出现问题

既然同样的代码,你的复现概率异常的高,建议先从硬件链路和硬盘上着手去看