*openUBMC 支持北向接口显示硬盘固件版本信息详细设计说明书*

<table>
    <tr>
        <td>所属SIG组:</td>
        <td>hardware</td>
    </tr>
    <tr>
        <td>落入版本:</td>
        <td>26.03</td>
    </tr>
    <tr>
        <td>设计人员:</td>
        <td>hmh</td>
    </tr>
    <tr>
        <td>日期:</td>
        <td>2026/01/16</td>
    </tr>
</table>


**Copyright © 2026 openUBMC Community**

您对&quot;本文档&quot;的复制，使用，修改及分发受木兰宽松许可证, 第2版协议(以下简称&quot;MulanPSL2&quot;)的约束。
为了方便用户理解，您可以通过访问<https://license.coscl.org.cn/MulanPSL2>了解MulanPSL2的概要 (但不是替代)。
MulanPSL2的完整协议内容您可以访问如下网址获取：<https://license.coscl.org.cn/MulanPSL2>。

**改版记录**

<table>
    <tr>
        <th>日期</th>
        <th>修订版本</th>
        <th>修订描述</th>
        <th>作者</th>
        <th>审核</th>
    </tr>
    <tr>
        <td>2026/01/16</td>
        <td>1.0</td>
        <td>新增硬盘固件版本信息显示</td>
        <td>hmh</td>
        <td>xxx</td>
    </tr>
    <tr>
        <td>xxx</td>
        <td>xxx</td>
        <td>xxx</td>
        <td>xxx</td>
        <td>xxx</td>
    </tr>
</table>

**List of abbreviations**  **缩略语清单** ：

<table>
    <tr>
        <th>Abbreviations 缩略语</th>
        <th>Full spelling 英文全名</th>
        <th>Chinese explanation 中文解释</th>
    </tr>
    <tr>
        <td>RAID</td>
        <td>Redundant Array of Independent Disks</td>
        <td>独立磁盘冗余阵列</td>
    </tr>
    <tr>
        <td>FirmwareInfo</td>
        <td>Firmware Information</td>
        <td>固件信息对象</td>
    </tr>
    <tr>
        <td>SNMP</td>
        <td>Simple Network Management Protocol</td>
        <td>简单网络管理协议</td>
    </tr>
    <tr>
        <td>Redfish</td>
        <td>Redfish</td>
        <td>一种用于管理和监控服务器硬件的RESTful API标准</td>
    </tr>
    <tr>
        <td>WEBREST</td>
        <td>Web RESTful API</td>
        <td>基于Web的RESTful接口</td>
    </tr>
</table>

[TOC]

# 1.功能分析
## 1.1 功能背景
<!-- 描述该需求的来源或背景，比如：支撑XXX功能、XXX优化等；以及该需求对用户（含组件）带来什么具体价值，如果没有该需求，对用户（含组件）带来什么损失； -->
该需求用于支持北向接口显示硬盘固件版本信息，使得用户可以通过SNMP、Redfish、WEBREST等北向接口查询到自研RAID卡管理的硬盘的固件版本信息，提升硬盘固件管理的可视化和可维护性。通过将硬盘固件信息注册到固件管理组件，用户可以统一通过固件管理接口查询和管理所有可升级固件的版本信息。

## 1.2 功能描述
<!-- 描述该需求交付的整体功能，主要实现XXX功能，解决XXX问题，明确方案如何实现 -->
实现自研RAID卡管理的硬盘固件版本信息注册到固件管理组件，并通过北向接口对外提供查询能力。

方案:
1.对于支持升级的硬盘（自研RAID卡管理的硬盘），在硬盘满足条件时注册FirmwareInfo对象到固件管理组件（FirmwareInventory）
2.当硬盘固件版本变更时，更新对应的FirmwareInfo对象信息
3.当硬盘拔出时，取消注册对应的FirmwareInfo对象
4.用户通过SNMP、Redfish、WEBREST等北向接口可以查询到对应硬盘的固件版本信息

## 1.3 功能场景
1) 场景触发条件及对象：网管、运维人员、开发人员可以通过SNMP、Redfish、WEBREST等接口查看获取硬盘的固件版本信息
2) 使用时间及频度：不频繁，主要用于查询和监控

## 1.4 功能列表
<!-- 描述该需求交付的功能列表，内容包括：列出功能详细描述，标题、描述。 -->
| 功能编号 | 功能标题 | 功能描述 |
| ------- | ------- | -------- |
| 1 | 硬盘固件信息注册 | 对于支持升级的硬盘（自研RAID卡管理的硬盘）注册FirmwareInfo到固件管理组件 |
| 2 | 硬盘固件版本更新 | 当硬盘固件版本变更时，更新对应的FirmwareInfo对象信息 |
| 3 | 硬盘固件信息注销 | 当硬盘拔出时，取消注册对应的FirmwareInfo对象 |
| 4 | 北向接口查询支持 | 用户通过SNMP、Redfish、WEBREST等北向接口可以查询到对应硬盘的固件版本信息 |

# 2.功能设计
## 2.1 总体方案分析
<!-- 描述该方案的总体设计（注：相关输出方案可同步刷新到各组件仓） -->

1.在Drive对象更新流程中，判断是否为自研RAID卡管理的硬盘，如果是则注册FirmwareInfo对象到FirmwareInventory

2.在Drive对象的固件版本（Revision属性）更新时，通过资源树获取对应的FirmwareInfo对象并更新Version属性

3.在Revision属性变化回调中，判断是否已注册FirmwareInfo（通过register_firmware_info_flag标志位）：
  - 如果未注册，调用method_misc的retry_register_firmware_info方法注册FirmwareInfo对象到FirmwareInventory，带重试机制（重试3次，间隔5秒）
  - 如果已注册，调用update_firmware_info方法通过mdb.get_cached_object获取FirmwareInfo对象并更新Version属性，带重试机制（重试3次，间隔5秒）

4.FirmwareInfo的持久化类型为TemporaryPer，BMC复位时数据会清除，Drive对象重新走自发现流程判断是否需要注册FirmwareInfo对象

5.通过北向映射器配置，使得FirmwareInventory中的FirmwareInfo对象可以通过SNMP、Redfish、WEBREST等北向接口查询

### 2.1.1 方案详细设计
#### 2.1.1.1 方案概述
<!-- 描述该方案的整体实现，内容包括：涉及的关键点，实现策略等 -->

1.在Drive对象identify流程中，判断硬盘是否为自研RAID卡管理，如果是则注册Revision属性变化的回调监听

2.在Revision属性变化回调中，判断是否已注册FirmwareInfo：
  - 如果未注册，则调用method_misc的retry_register_firmware_info方法注册FirmwareInfo对象到FirmwareInventory，带重试机制（重试3次，每次间隔5秒）
  - 如果已注册，则通过mdb.get_cached_object获取对应的FirmwareInfo对象并更新Version属性，带重试机制（重试3次，每次间隔5秒）

3.在update_static_drive_info流程中，如果未注册FirmwareInfo且为自研RAID卡管理，则主动调用register_firmware_info_by_revision注册（避免仅靠属性变化回调的场景遗漏）

4.在Drive对象的Presence属性变为0时（拔盘场景），调用unregister_firmware_info方法，该方法会：
  - 取消Revision属性变化的信号回调
  - 调用method_misc的retry_unregister_firmware_info方法删除FirmwareInfo对象，带重试机制（重试3次，每次间隔5秒）
  - 清除Revision属性为INVALID_STRING

5.FirmwareInfo的持久化类型为TemporaryPer，BMC复位时数据会清除，Drive对象重新走identify流程时会重新注册FirmwareInfo对象

6.通过北向映射器配置，FirmwareInventory对象及其子对象FirmwareInfo可以通过北向接口查询

各个北向接口：
web接口：UI/Rest/BMCSettings/UpdateService，方法：Get，新增硬盘固件版本信息展示
snmp接口：/snmp/1.3.6.1.4.1.{{SnmpOemIdentifier}}.11.50/firmwareDescriptionTable/Readonly
方法Get，显示硬盘FirmwareType需新增枚举值（23）代表硬盘固件类型，需要更新资料和MIB文件。
redfish接口：/redfish/v1/UpdateService/FirmwareInventory，方法：Get，需要Members中新增硬盘固件信息的@odata.id和对应uri。

#### 2.1.1.2 开发视图
<!-- 开发视图面向系统开发及软件管理，描述系统代码结构，构建结构的视图，主要解决系统技术实现和开发的问题，它依托逻辑视图，描述代码、构建结构 -->
```mermaid
classDiagram
    class object {
        + on_add_object()
        + on_delete_object()
        + on_property_changed()
    }

    class Drive {
        + identified()
        + update_static_drive_info()
        + Revision
        + RefControllerTypeId
        + Manufacturer
        + register_firmware_info_flag
        + signal_slots
        + register_firmware_info()
        + register_firmware_info_by_revision()
        + update_firmware_info()
        + unregister_firmware_info()
    }

    class FirmwareInventory {
        + Add()
        + Delete()
    }
    
    class dbus资源树 {
        + get_cached_object()
    }

    class method_misc {
        + test_controller_vendor()
        + retry_register_firmware_info()
        + retry_unregister_firmware_info()
    }
    
    class pd_identify_service {
        + on_add_drive_call_back()
    }

    object <|-- Drive
    Drive --> method_misc : depends on
    Drive --> dbus资源树 : depends on
    method_misc --> FirmwareInventory : depends on
    pd_identify_service --> Drive : depends on
```

#### 2.1.1.3 运行视图
<!-- 运行视图面向系统运行，描述系统启动过程、运行期交互的视图，主要解决系统运行期交互，描述各可执行交付件在运行期的交互关系 -->
```mermaid
sequenceDiagram
    participant hwdiscovery
    participant dbus资源树
    participant storage
    participant Drive对象
    participant method_misc
    participant FirmwareInventory
    participant pd_identify_service
    participant 北向接口
    participant User

    hwdiscovery->>dbus资源树:解析CSR并自发现Drive对象
    storage->>dbus资源树:获取Drive对象数据，Drive对象初始化
    storage->>Drive对象:调用identified方法，设置RefControllerTypeId
    Drive对象->>Drive对象:调用register_firmware_info，判断是否为自研RAID卡
    alt 自研RAID卡
        Drive对象->>Drive对象:注册Revision属性变化回调监听
    end
    storage->>Drive对象:调用update_static_drive_info更新Revision等属性
    Drive对象->>Drive对象:Revision属性变化触发回调
    Drive对象->>method_misc:调用retry_register_firmware_info注册FirmwareInfo
    method_misc->>FirmwareInventory:调用Add接口(带重试机制，3次，间隔5秒)
    FirmwareInventory->>dbus资源树:创建FirmwareInfo对象
    method_misc->>Drive对象:注册成功回调，设置register_firmware_info_flag=true
    loop 固件版本更新
        storage->>Drive对象:更新Revision属性
        Drive对象->>Drive对象:Revision属性变化触发回调
        Drive对象->>dbus资源树:调用get_cached_object获取FirmwareInfo对象(带重试机制，3次，间隔5秒)
        Drive对象->>dbus资源树:直接赋值更新FirmwareInfo对象Version属性
    end
    alt 拔盘场景
        hwdiscovery->>dbus资源树:Presence属性设为0
        pd_identify_service->>Drive对象:触发on_property_changed回调，调用unregister_firmware_info
        Drive对象->>Drive对象:取消Revision属性变化回调
        Drive对象->>method_misc:调用retry_unregister_firmware_info删除FirmwareInfo
        method_misc->>FirmwareInventory:调用Delete接口(带重试机制，3次，间隔5秒)
        FirmwareInventory->>dbus资源树:删除FirmwareInfo对象
        method_misc->>Drive对象:删除成功回调，设置register_firmware_info_flag=false
        Drive对象->>Drive对象:清除Revision为INVALID_STRING
    end
    User->>北向接口:查询硬盘固件版本信息
    北向接口->>dbus资源树:通过映射配置器获取FirmwareInfo信息
    dbus资源树->>北向接口:返回FirmwareInfo对象信息
    北向接口->>User:返回硬盘固件版本信息
```

### 2.1.2 内部依赖分析
<!-- 是否涉及与其他组件接口依赖，如果涉及需要确认当前是否已完成，是否匹配当前需求开发诉求 -->
依赖固件管理组件（firmware_mgmt）的FirmwareInventory对象接口：
- Add接口：用于注册FirmwareInfo对象，通过method_misc的retry_register_firmware_info方法调用，带重试机制（重试3次，间隔5秒）
- 无更新接口，需要通过mdb.get_cached_object获取FirmwareInfo对象后直接赋值更新Version属性
- Delete接口：用于删除FirmwareInfo对象，通过method_misc的retry_unregister_firmware_info方法调用，带重试机制（重试3次，间隔5秒）

依赖storage组件内部的client模块提供的接口：
- PFirmwareInventoryFirmwareInventoryAdd：调用FirmwareInventory的Add接口
- PFirmwareInventoryFirmwareInventoryDelete：调用FirmwareInventory的Delete接口

### 2.1.3 外部依赖分析
<!-- 是否涉及与平台SDK的依赖关系 -->
不涉及外部依赖

### 2.1.4 北向接口分析
<!-- 需要分析当前功能是否有以下接口影响，如果有影响，则需要具体的补充影响点。其中注意点如下：
（1）如果有新增IPMI接口，请排查代码中IPMI命令注册的过滤字段，是否完全和IPMI命令的定义一致？
（2）新增一个接口时，需要咨询SIG组是否还有其他的接口受影响 -->
| 特性 | SNMP | CLI | WEB | KVM_VMM | IPMI(RMCP/RMCP+) | HMM | Redfish |
| ---- | ---- | ---- | --- | ------ | ---------------- | --- | ------- |
| 支持北向接口显示硬盘固件版本信息 | 支持 | 不涉及 | 支持 | 不涉及 | 不涉及 | 不涉及 | 支持 |

**各北向接口详细说明：**

1. **WEB接口**：
   - 接口路径：`UI/Rest/BMCSettings/UpdateService`
   - 方法：Get
   - 说明：新增硬盘固件版本信息展示

2. **SNMP接口**：
   - 接口路径：`/snmp/1.3.6.1.4.1.{{SnmpOemIdentifier}}.11.50/firmwareDescriptionTable/Readonly`
   - 方法：Get
   - 说明：显示硬盘FirmwareType需新增枚举值（23）代表硬盘固件类型，需要更新资料和MIB文件

3. **Redfish接口**：
   - 接口路径：`/redfish/v1/UpdateService/FirmwareInventory`
   - 方法：Get
   - 说明：需要Members中新增硬盘固件信息的@odata.id和对应uri

### 2.1.5 兼容性分析
<!-- 当前的功能对现有在网的功能是否有影响，具体的影响点进行分析之后输出影响分析表格 -->
对于不支持固件升级的硬盘或非自研RAID卡管理的硬盘，不进行FirmwareInfo注册，不影响现有功能。
对于已支持固件升级的硬盘，新增FirmwareInfo注册功能，不影响现有Drive对象的功能。
FirmwareInfo的持久化类型为TemporaryPer，BMC复位时数据会清除，不会影响持久化存储，Drive对象重新走自发现流程时会重新判断是否需要注册FirmwareInfo对象。

### 2.1.6 定制化接口分析
不涉及
### 2.1.7 导入导出分析
<!-- 如果支持导入导出的配置，则需要分析导入导出的schema。 -->
不涉及
### 2.1.8 传感器分析
<!-- 如果需要新增传感器，则需要提前登记和评审新增的传感器要素。新增传感器评审需要上SIG-Interface进行评审 -->
不涉及
### 2.1.9 精准告警事件分析
<!-- 如果需要新增事件，则需要提前登记和评审新增的时间要素 -->
不涉及
### 2.1.10 系统锁定分析
<!-- 对外的接口或者命令是否支持系统锁定 -->
不涉及
### 2.1.11 用例场景分析
<!-- 以表格的形式输出该需求涉及的用例场景 -->

| 用例编号 | 用例描述 | 前置条件 |执行步骤 | 预期结果 |
| --- | --- | --- | --- | --- |
| 1 | 自研RAID卡管理的硬盘插入后注册FirmwareInfo | BMC正常运行，自研RAID卡在位 | 1.插入自研RAID卡管理的硬盘到硬盘槽位；2.等待硬盘识别完成；3.通过SNMP/Redfish/Web接口查询FirmwareInventory；4.检查对应硬盘的FirmwareInfo是否存在；5.对比FirmwareInfo的Version与硬盘Revision是否一致 | FirmwareInventory中存在对应硬盘的FirmwareInfo对象，Version字段与硬盘实际固件版本一致 |
| 2 | 非自研RAID卡管理的硬盘不注册FirmwareInfo | BMC正常运行，非自研RAID卡在位 | 1.插入非自研RAID卡管理的硬盘到硬盘槽位；2.等待硬盘识别完成；3.通过SNMP/Redfish/Web接口查询FirmwareInventory；4.检查FirmwareInventory中是否存在该硬盘的FirmwareInfo | FirmwareInventory中不存在该硬盘的FirmwareInfo对象 |
| 3 | 硬盘固件版本更新时同步更新FirmwareInfo | 已插入自研RAID卡管理的硬盘，FirmwareInfo已注册 | 1.记录当前硬盘固件版本；2.对硬盘进行固件升级操作；3.等待升级完成；4.通过SNMP/Redfish/Web接口查询FirmwareInventory；5.检查对应硬盘的FirmwareInfo的Version字段 | FirmwareInfo的Version字段更新为升级后的新版本号 |
| 4 | 硬盘拔出时删除FirmwareInfo | 已插入自研RAID卡管理的硬盘，FirmwareInfo已注册 | 1.记录当前FirmwareInventory中存在的硬盘FirmwareInfo；2.拔出对应硬盘；3.等待系统识别硬盘拔出；4.通过SNMP/Redfish/Web接口查询FirmwareInventory；5.检查该硬盘的FirmwareInfo是否还存在 | FirmwareInventory中不再存在已拔出硬盘的FirmwareInfo对象 |
| 5 | 通过SNMP查询硬盘固件版本信息 | 已插入自研RAID卡管理的硬盘，FirmwareInfo已注册 | 1.通过SNMP客户端工具访问OID：1.3.6.1.4.1.{{SnmpOemIdentifier}}.11.50/firmwareDescriptionTable；2.查看返回的固件列表；3.查找硬盘对应的固件信息项；4.检查FirmwareType字段和Version字段 | 返回的固件列表中包含硬盘固件信息，FirmwareType为23，Version为硬盘实际固件版本 |
| 6 | 通过Redfish查询硬盘固件版本信息 | 已插入自研RAID卡管理的硬盘，FirmwareInfo已注册 | 1.通过Redfish客户端访问/redfish/v1/UpdateService/FirmwareInventory；2.查看Members列表；3.查找硬盘对应的FirmwareInfo URI；4.访问该URI获取详细信息；5.检查Version字段 | Members列表中包含硬盘的@odata.id，访问对应URI返回硬盘固件详细信息，Version为硬盘实际固件版本 |
| 7 | 通过WEBREST查询硬盘固件版本信息 | 已插入自研RAID卡管理的硬盘，FirmwareInfo已注册 | 1.通过Web浏览器或REST客户端访问UI/Rest/BMCSettings/UpdateService；2.查看返回的固件列表；3.查找硬盘对应的固件信息；4.检查Version字段 | 返回的固件列表中包含硬盘固件信息，Version为硬盘实际固件版本 |
| 8 | BMC复位后FirmwareInfo重新注册 | 已插入自研RAID卡管理的硬盘，FirmwareInfo已注册 | 1.通过命令触发BMC复位；2.等待BMC重启完成；3.等待硬盘重新识别完成；4.通过SNMP/Redfish/Web接口查询FirmwareInventory；5.检查硬盘的FirmwareInfo是否存在及Version是否正确 | BMC复位后，FirmwareInventory中重新生成硬盘的FirmwareInfo对象，Version为硬盘实际固件版本 |
| 9 | FirmwareInfo的Id唯一性验证 | BMC正常运行，自研RAID卡在位，有多个硬盘槽位 | 1.同时插入多个自研RAID卡管理的硬盘；2.等待所有硬盘识别完成；3.通过SNMP/Redfish/Web接口查询FirmwareInventory；4.记录所有硬盘FirmwareInfo的Id字段；5.检查Id是否有重复 | FirmwareInventory中每个硬盘的FirmwareInfo对象的Id唯一，无重复 |
| 10 | OS复位后FirmwareInfo保持 | 已插入自研RAID卡管理的硬盘，FirmwareInfo已注册，OS正常运行 | 1.记录复位前FirmwareInventory中硬盘的FirmwareInfo信息；2.触发OS复位（warm reset）；3.等待OS重启完成；4.通过SNMP/Redfish/Web接口查询FirmwareInventory；5.对比复位前后FirmwareInfo信息 | OS复位后，FirmwareInfo对象保持不变，Version与复位前一致 |
| 11 | 整机AC后FirmwareInfo重新注册 | 已插入自研RAID卡管理的硬盘，FirmwareInfo已注册 | 1.记录AC前FirmwareInventory中硬盘的FirmwareInfo信息；2.对整机进行AC下电；3.对整机进行AC上电；4.等待BMC和系统启动完成；5.等待硬盘重新识别完成；6.通过SNMP/Redfish/Web接口查询FirmwareInventory；7.检查硬盘的FirmwareInfo是否存在及Version是否正确 | 整机AC后，FirmwareInventory中重新生成硬盘的FirmwareInfo对象，Version为硬盘实际固件版本 |

## 2.2 非功能质量属性设计
### 2.2.1 扩展性分析
<!-- 考虑后续新增类似功能可以很好地扩展 -->
如果后续需要支持其他类型设备的固件信息注册，可以参考本方案的实现方式，通过判断设备类型和是否支持升级来决定是否注册FirmwareInfo。

### 2.2.2 重用性分析
<!-- 是否为通用处理方式、接口，如果是得考虑重用性 -->
FirmwareInventory的Add、Delete接口为通用接口，可被其他组件重用。

### 2.2.3 可测试性分析
<!-- 此需求如何验证，是否可直接验证，or通过XXX功能覆盖验证，or需要单独怎加测试接口验证 -->
1.在自研RAID卡管理的支持升级的硬盘插入后，通过资源树查询FirmwareInventory对象，验证是否存在对应硬盘的FirmwareInfo对象，Id为Drive对象的NodeId
2.验证注册FirmwareInfo后，Drive对象的Revision属性的on_property_changed信号已注册监听
3.在硬盘固件版本更新后，验证通过资源树get_mdb_object获取FirmwareInfo对象，并通过set_property更新Version属性，与Drive对象的Revision属性一致
4.在硬盘拔出（Presence属性变为0）后，验证触发on_property_changed回调，FirmwareInventory中对应的FirmwareInfo对象被删除
5.通过SNMP、Redfish、WEBREST等北向接口查询FirmwareInfo信息，验证返回的固件版本信息与Drive对象的Revision属性一致

### 2.2.4 资料分析

<!-- 是否涉及资料修改 -->
修改对应北向接口资料，体现硬盘固件版本信息的查询。

### 2.2.5 资源使用分析
<!-- 新增线程、内存分配、模型属性名长度是否合理，CPU占用率是否会激增，Flash中新增文件是否合理（频繁读写Flash会大幅缩短emmc寿命）；是否涉及消息队列，如果涉及请检查是否存在某些场景下消息队列会满导致消息丢失，例如大量消息发送到队列且处理消息需要耗费较长时间的场景。 -->
1.新增FirmwareInfo对象占用内存很小，每个硬盘对应一个FirmwareInfo对象
2.Drive对象新增属性：
   - register_firmware_info_flag：boolean类型，标识是否已注册FirmwareInfo
   - signal_slots：table类型，存储信号槽位，用于取消信号回调
   - RefControllerTypeId：u8类型，存储控制器类型ID（原有属性，从pd.controller_type获取）
3.使用skynet.fork异步执行注册、注销、更新操作，不会阻塞主流程
4.重试机制使用skynet.sleep实现延时，每次间隔5秒，最多重试3次
5.不涉及Flash读写，FirmwareInfo的持久化类型为TemporaryPer，仅存储在内存中

### 2.2.6 可靠性分析
| 编号 | 场景 | 问题描述 | 可靠性影响 | 建议解决方案/需求 | 备注 |
| --- | --- | --- | --- | --- | --- |
| 1 | FirmwareInventory对象未加载 | Drive对象创建时FirmwareInventory对象可能尚未加载 | 注册失败，需要重试机制 | 已实现重试机制：retry_register_firmware_info方法重试3次，每次间隔5秒 | 已实现 |
| 2 | 固件版本更新失败 | 通过mdb.get_cached_object获取FirmwareInfo对象失败 | FirmwareInfo对象的Version与Drive对象的Revision不一致 | 已实现重试机制：update_firmware_info方法重试3次，每次间隔5秒，记录错误日志，下次Revision属性变化时重试 | 已实现 |
| 3 | 拔盘时删除失败 | 调用FirmwareInventory的Delete接口失败 | FirmwareInventory中存在无效的FirmwareInfo对象 | 已实现重试机制：retry_unregister_firmware_info方法重试3次，每次间隔5秒，记录错误日志 | 已实现 |
| 4 | 并发场景 | 多个硬盘同时插入或拔出 | 可能存在并发注册或删除的问题 | 通过register_firmware_info_flag标志位避免重复注册，通过FirmwareInventory对象的接口保证线程安全 | 已实现 |
| 5 | BMC重启场景 | BMC重启后FirmwareInfo对象需要重新注册 | FirmwareInfo对象丢失（TemporaryPer类型，BMC复位时清除） | Drive对象重新走identify流程，调用register_firmware_info重新注册FirmwareInfo对象 | 已实现 |
| 6 | 重复注册回调场景 | 插拔盘场景可能重复注册Revision属性变化回调 | 可能存在多个回调监听同一属性 | 在register_firmware_info方法中，注册新回调前先调用disconnect取消旧回调 | 已实现 |

### 2.2.7 安全性分析
| 安全合规项 | 是否涉及 | 现有的防护措施 |
| --- | --- | --- |
| 访问控制（通道、文件权限、用户权限、查询权限、配置权限、接口权限） | 不涉及 |  |
| 敏感数据 | 不涉及 |  |
| 日志（操作日志、维护日志、安全日志、运行日志） | 涉及 | 记录FirmwareInfo注册、更新、删除的操作日志 |
| 文档 | 不涉及 |  |
| 加密及算法 | 不涉及 |                      |
| 新增关键资源（密钥、证书、关键配置）备份、恢复 | 不涉及 |  |
| 新增对外接口入参校验 | 不涉及 |  |
| 新增开源及三方软件引入 | 不涉及 |  |

# 3.功能实现
<!-- 通过表格、流程图、简明文字描述提供，力求容易看懂、容易实现，详细描述细节。 -->
## 3.1 支持北向接口显示硬盘固件版本信息
### 3.1.1 功能实现设计
实现自研RAID卡管理的硬盘固件版本信息注册到固件管理组件，并通过北向接口对外提供查询能力。主要包括：
1. 硬盘固件信息注册：在Drive对象identify流程中，判断硬盘是否为自研RAID卡管理，如果是则注册Revision属性变化回调，当Revision属性变化时调用method_misc的retry_register_firmware_info方法注册FirmwareInfo对象
2. 硬盘固件版本更新：在Revision属性变化回调中，如果已注册FirmwareInfo，则通过mdb.get_cached_object获取对应的FirmwareInfo对象并直接赋值更新Version属性
3. 硬盘固件信息注销：在Drive对象的Presence属性变为0时（拔盘场景），pd_identify_service调用Drive对象的unregister_firmware_info方法，取消Revision属性变化回调并调用method_misc的retry_unregister_firmware_info方法删除FirmwareInfo对象
4. 北向接口查询支持：通过北向映射器配置，FirmwareInventory对象及其子对象FirmwareInfo可以通过SNMP、Redfish、WEBREST等北向接口查询

### 3.1.2 功能详细设计

#### 3.1.2.1 硬盘固件信息注册
1.在Drive对象的identified方法中，设置RefControllerTypeId为pd.controller_type，调用register_firmware_info方法
2.在register_firmware_info方法中，调用method_misc.test_controller_vendor()判断RefControllerTypeId是否为自研RAID卡类型（VENDER_HUAWEI）
3.如果是自研RAID卡，注册Revision属性的on_property_changed信号回调，回调中会：
   - 判断是否已注册FirmwareInfo（通过register_firmware_info_flag标志位）
   - 如果未注册，调用register_firmware_info_by_revision方法注册FirmwareInfo
   - 如果已注册，调用update_firmware_info方法更新FirmwareInfo的Version属性
4.在register_firmware_info_by_revision方法中，构造FirmwareInfo对象的参数：
   - Id: 使用Drive对象的NodeId（例如HDDPlaneDiskX），Id为FirmwareInfo对象的主键，需要保证唯一
   - Name: 使用Drive对象的NodeId
   - Version: 使用Drive对象的Revision属性
   - Manufacturer: 使用Drive对象的Manufacturer属性
   - SoftwareId: 使用Drive对象的NodeId
   - State: 'Enabled'
   - Severity: 'Informational'
   - EstimatedDuration: '30'
5.调用method_misc的retry_register_firmware_info方法注册FirmwareInfo对象，该方法会：
   - 调用client的PFirmwareInventoryFirmwareInventoryAdd接口
   - 带重试机制：重试3次，每次间隔5秒（5000ms）
   - 注册成功后调用回调函数，设置register_firmware_info_flag=true
6.在update_static_drive_info方法中，更新Manufacturer和Revision属性后，如果未注册FirmwareInfo且为自研RAID卡，则主动调用register_firmware_info_by_revision注册（避免仅靠属性变化回调的场景遗漏）
7.FirmwareInfo的持久化类型为TemporaryPer，BMC复位时数据会清除，Drive对象重新走identify流程时会重新注册FirmwareInfo对象

#### 3.1.2.2 硬盘固件版本更新
1.在register_firmware_info方法中已注册Revision属性的on_property_changed信号回调
2.当Revision属性变化触发回调时，判断该Drive对象是否已注册FirmwareInfo（通过register_firmware_info_flag标志位）
3.如果已注册，调用update_firmware_info方法更新FirmwareInfo的Version属性，该方法会：
   - 在skynet.fork中异步执行（避免阻塞主流程）
   - 通过mdb.get_cached_object获取FirmwareInfo对象，路径为common_def.FWINVENTORY_PATH + self.NodeId，接口为common_def.FIRMWARE_INFO_INTERFACE
   - 带重试机制：重试3次，每次间隔5秒（5000ms）
   - 获取成功后直接赋值obj.Version = revision更新Version属性
   - 记录notice级别日志：'[Drive] %s update firmware info version to %s'
4.如果获取FirmwareInfo对象失败，记录error级别日志：'[Drive] %s get firmware info failed after %s retries'

#### 3.1.2.3 硬盘固件信息注销
1.在pd_identify_service的on_add_drive_call_back方法中，监听Drive对象的Presence属性的on_property_changed信号
2.当Presence属性变为0时（拔盘场景），触发回调，调用Drive对象的unregister_firmware_info方法
3.在unregister_firmware_info方法中：
   - 判断是否已注册FirmwareInfo（通过register_firmware_info_flag标志位），如果未注册则直接返回
   - 取消Revision属性变化的信号回调（通过signal_slots[SIGNAL_SLOT_REVISION_CHANGED].disconnect()）
   - 调用method_misc的retry_unregister_firmware_info方法删除FirmwareInfo对象，传入Drive对象的NodeId作为Id参数
4.在retry_unregister_firmware_info方法中：
   - 在skynet.fork中异步执行
   - 调用client的PFirmwareInventoryFirmwareInventoryDelete接口
   - 带重试机制：重试3次，每次间隔5秒（5000ms）
   - 删除成功后调用回调函数，设置register_firmware_info_flag=false
   - 记录notice级别日志：'[MethodMisc] unregister firmware info success, Id=%s'
5.在pd_identify_service的回调中，调用unregister_firmware_info后，清除Drive对象的Revision属性为common_def.INVALID_STRING
6.如果删除失败，记录error级别日志：'[MethodMisc] unregister firmware info failed after %s retries'

#### 3.1.2.4 北向接口查询支持
1. **WEB接口**：
   - 接口路径：`UI/Rest/BMCSettings/UpdateService`
   - 方法：Get
   - 实现：通过北向映射器配置，在UpdateService接口中新增硬盘固件版本信息展示

2. **SNMP接口**：
   - 接口路径：`/snmp/1.3.6.1.4.1.{{SnmpOemIdentifier}}.11.50/firmwareDescriptionTable/Readonly`
   - 方法：Get
   - 实现：在firmwareDescriptionTable中新增FirmwareType枚举值（23）代表硬盘固件类型，需要更新资料和MIB文件

3. **Redfish接口**：
   - 接口路径：`/redfish/v1/UpdateService/FirmwareInventory`
   - 方法：Get
   - 实现：在FirmwareInventory的Members数组中新增硬盘固件信息的@odata.id和对应uri，通过北向映射器配置实现

### 3.1.3 开发者测试
#### 3.1.3.1 单元测试
<!-- UT，主要是功能单元测试，测试对象是功能单元接口。UT测试设计要从黑盒（功能）角度设计，从输入(I)、处理（B）、预期输出（O）的角度进行用例分析设计，测试覆盖率仅作为反馈，用于分析哪些功能场景没有覆盖到，从而指导测试设计优化并补充测试用例 -->

| 组件名  | 用例类型 | 测试用例描述                                 | 用例名称                                  | 预置条件   | 操作步骤                                                     | 预期结果  |
| ------- | -------- | -------------------------------------------- | ----------------------------------------- | ---------- | ------------------------------------------------------------ | --------- |
| Storage | UT       | 测试自研RAID卡管理的硬盘注册Revision属性变化回调 | test_drive_register_revision_callback | 打桩Drive对象、pd对象、method_misc | 1.创建Drive对象<br> 2.设置pd.controller_type为自研RAID卡类型<br> 3.打桩method_misc.test_controller_vendor返回true<br> 4.调用identified方法<br> 5.调用register_firmware_info<br>  | Revision属性的on_property_changed信号回调已注册，signal_slots[SIGNAL_SLOT_REVISION_CHANGED]不为nil  |
| Storage | UT       | 测试非自研RAID卡管理的硬盘不注册回调 | test_drive_not_register_callback | 打桩Drive对象、pd对象、method_misc | 1.创建Drive对象<br>2.设置pd.controller_type为非自研RAID卡类型<br>3.打桩method_misc.test_controller_vendor返回false<br>4.调用identified方法<br>5.调用register_firmware_info | Revision属性的on_property_changed信号回调未注册，signal_slots[SIGNAL_SLOT_REVISION_CHANGED]为nil |
| Storage | UT       | 测试Revision属性变化时注册FirmwareInfo | test_revision_changed_register_firmware_info | 打桩Drive对象、method_misc、client，已注册回调但未注册FirmwareInfo | 1.设置register_firmware_info_flag=false<br>2.修改Drive对象的Revision属性<br>3.触发on_property_changed回调<br>4.验证调用method_misc.retry_register_firmware_info | method_misc.retry_register_firmware_info被调用，参数包含Id、Name、Version、Manufacturer等 |
| Storage | UT       | 测试Revision属性变化时更新FirmwareInfo | test_revision_changed_update_firmware_info | 打桩Drive对象、mdb，已注册FirmwareInfo | 1.设置register_firmware_info_flag=true<br>2.修改Drive对象的Revision属性<br>3.触发on_property_changed回调<br>4.验证调用mdb.get_cached_object获取FirmwareInfo对象<br>5.验证FirmwareInfo对象的Version属性被更新 | mdb.get_cached_object被调用，FirmwareInfo对象的Version属性被更新为新的Revision值  |
| Storage | UT       | 测试硬盘拔出时注销FirmwareInfo | test_drive_unregister_firmware_info | 打桩Drive对象、method_misc、client，已注册FirmwareInfo | 1.设置register_firmware_info_flag=true<br>2.设置signal_slots[SIGNAL_SLOT_REVISION_CHANGED]不为nil<br>3.调用unregister_firmware_info<br>4.验证调用method_misc.retry_unregister_firmware_info<br>5.验证signal_slots[SIGNAL_SLOT_REVISION_CHANGED]被disconnect | method_misc.retry_unregister_firmware_info被调用，Id参数为Drive对象的NodeId，signal_slots[SIGNAL_SLOT_REVISION_CHANGED]为nil  |
| Storage | UT       | 测试method_misc的retry_register_firmware_info重试机制 | test_retry_register_firmware_info | 打桩client、skynet | 1.打桩client.PFirmwareInventoryFirmwareInventoryAdd前2次返回失败，第3次返回成功<br>2.调用method_misc.retry_register_firmware_info<br>3.验证重试次数和间隔 | client.PFirmwareInventoryFirmwareInventoryAdd被调用3次，间隔5秒，最终注册成功，success_callback被调用 |
| Storage | UT       | 测试method_misc的retry_unregister_firmware_info重试机制 | test_retry_unregister_firmware_info | 打桩client、skynet | 1.打桩client.PFirmwareInventoryFirmwareInventoryDelete前2次返回失败，第3次返回成功<br>2.调用method_misc.retry_unregister_firmware_info<br>3.验证重试次数和间隔 | client.PFirmwareInventoryFirmwareInventoryDelete被调用3次，间隔5秒，最终删除成功，success_callback被调用 |
| Storage | UT       | 测试update_static_drive_info主动注册FirmwareInfo | test_update_static_drive_info_register | 打桩Drive对象、method_misc，未注册FirmwareInfo且为自研RAID卡 | 1.设置register_firmware_info_flag=false<br>2.设置RefControllerTypeId为自研RAID卡类型<br>3.打桩method_misc.test_controller_vendor返回true<br>4.调用update_static_drive_info更新Revision<br>5.验证调用register_firmware_info_by_revision | register_firmware_info_by_revision被调用，参数为Revision值 |

#### 3.1.3.2 集成测试
<!-- IT，主要是组件/模块内的集成测试，测试对象是模块/组件接口。IT测试设计将模块/组件当作黑盒测试，IT测试用例中禁止对组件/模块内部代码打桩，如果确实有少量场景难以构造，可以考虑在测试框架中统一打桩并提供接口供测试用例调用构造场景。
说明：API测试属于IT，其测试对象是微服务接口。
PCST，是指PC上的服务集成测试，测试对象是功能需求。PCST测试设计，要覆盖正常功能、异常功能和交叉功能，采用灰盒 -->
不涉及
