*openUBMC 支持整机配置硬盘背板上硬盘起始槽位号功能详细设计说明书*

<table>
    <tr>
        <td>所属SIG组:</td>
        <td>general_hardware</td>
    </tr>
    <tr>
        <td>落入版本:</td>
        <td>26.03</td>
    </tr>
    <tr>
        <td>设计人员:</td>
        <td>yelmh</td>
    </tr>
    <tr>
        <td>日期:</td>
        <td>2026/02/05</td>
    </tr>
</table>

**Copyright © 2025 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/02/05</td>
        <td>1.0</td>
        <td>支持整机配置硬盘背板上硬盘起始槽位号功能</td>
        <td>yelmh</td>
        <td>/</td>
    </tr>
</table>

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

<table>
    <tr>
        <th>Abbreviations 缩略语</th>
        <th>Full spelling 英文全名</th>
        <th>Chinese explanation 中文解释</th>
    </tr>
    <tr>
        <td>PSR</td>
        <td>Product Specific Record</td>
        <td>产品特定记录，整机配置</td>
    </tr>
    <tr>
        <td>DriveStartSlotConfig</td>
        <td>Drive Start Slot Configuration</td>
        <td>硬盘起始槽位配置，整机PSR定义的硬盘组合模型</td>
    </tr>
    <tr>
        <td>HddBackplane</td>
        <td>HDD Backplane</td>
        <td>硬盘背板</td>
    </tr>
    <tr>
        <td>M2TransferCard</td>
        <td>M.2 Transfer Card</td>
        <td>M.2 转接卡（同属背板类，与 HddBackplane 共用 StartSlot 更新逻辑）</td>
    </tr>
</table>

[TOC]

# 1.功能分析
## 1.1 功能背景

支持整机灵活定义硬盘槽位，实现全局硬盘编号统一编码，满足业务需求。

整机PSR中新增私有对象DriveStartSlotConfig及私有属性Configurations，用于灵活定义硬盘背板槽位。系统根据整机PSR下发的DriveStartSlotConfig进行动态更新，以便在**实际插装的硬盘背板与配置匹配**时，按公式（Id = HddBackplaneStartSlot + RelativeSlot）计算并对外展示一致的盘位信息。

**举例**：当整机存在四个硬盘背板槽位时，若实际插装的硬盘背板类型/槽位与DriveStartSlotConfig配置一致，则可确定每个槽位上硬盘背板对应的硬盘起始槽位号，从而**保证全局硬盘槽位编号一致且连续、无冲突**。若已配置但实际插装不符合配置（如背板类型/槽位与配置不匹配），则硬盘槽位编码的**一致性与连续性无法保证**。

**整体方案**：
1. 硬盘背板模型中硬盘起始槽位号由整机配置PSR的定义来更新；
2. 整机PSR模型仅定义1个硬盘组合的起始槽位配置，具体模型定义参考示例；
3. 通用硬件管理APP处理整机PSR定义的硬盘组合模型：
   - 为兼容历史，部分硬盘背板（例如部分M2 X场景）会将`StartSlot`配置为`0xFF`，用于**保持硬盘Name/Id/NodeId按CSR中的固定配置生效**，不走`Drive.update_drive_slot_info`逻辑，本需求**不修改该语义**；
   - 新增使用`StartSlot = 0xFE`作为“待 PSR 更新”的标志位，仅当硬盘背板起始槽位号为`0xFE`时，才参与 DriveStartSlotConfig 匹配更新；
   - 如果匹配成功且对应硬盘背板的硬盘起始槽位号为`0xFE`时，更新对应的硬盘起始槽位号为 PSR 配置的值；
   - 如果匹配失败或未收到配置且对应硬盘背板的硬盘起始槽位号为`0xFE`时，更新对应的硬盘起始槽位号为`0`（兜底）；`0xFF`保持为“仅 CSR 生效”的历史语义，**不参与** PSR 匹配更新。

**应用场景**：用于灵活定义硬盘背板槽位。**持久化类型**：不持久化。**操作权限**：ReadOnly。


## 1.2 功能描述

本需求实现硬盘背板模型中硬盘起始槽位号（StartSlot）由整机PSR配置动态更新的能力。

### 1.2.1 核心能力

1. **三时机处理机制**：在DriveStartSlotConfig对象添加、硬盘背板对象添加、PSR add_object_complete信号触发三个时机执行匹配与更新逻辑。
2. **匹配更新策略**：对`StartSlot`为`0xFE`的硬盘背板进行匹配，匹配成功按PSR配置的ChildStartSlot更新，匹配失败或未收到配置则更新为`0`；`StartSlot=0xFF`的背板不参与PSR匹配更新，继续沿用CSR中对Drive Name/Id/NodeId的固定配置
3. **兜底保障**：add_object_complete作为最终兜底时机，设置psr_add_object_complete_fired标志位；背板添加时若无配置且标志位已置位则更新为0，确保add_object_complete之后才添加的背板不会永远保持StartSlot=0xFF。

### 1.2.2 处理原则

- 仅当`StartSlot=0xFE`时参与PSR匹配更新，已为其他有效值（含0、历史配置为`0xFF`）的背板不修改
- 无论配置到达顺序如何，三时机覆盖所有场景

## 1.3 功能场景

### 1.3.1 场景触发条件及对象

- **使用角色**：系统自动处理，无需用户干预
- **处理主体**：通用硬件管理APP（general_hardware）的unit_manager
- **触发时机**：对象添加回调（on_add_object）、add_object_complete信号
- **使用对象**：DriveStartSlotConfig配置对象、HddBackplane/M2TransferCard硬盘背板对象

### 1.3.2 使用时间及频度

- **使用时间**：BMC启动后PSR加载阶段、整机配置变更后PSR重新加载时
- **使用频度**：与PSR加载/变更一致，低频触发

### 1.3.3 主要场景及子场景

#### 场景1：DriveStartSlotConfig先于背板到达

- 先收到DriveStartSlotConfig配置
- 后收到HddBackplane/M2TransferCard对象（StartSlot=0xFE）
- 背板添加时遍历已添加的DriveStartSlotConfig进行匹配更新

#### 场景2：背板先于DriveStartSlotConfig到达

- 先收到HddBackplane/M2TransferCard对象（StartSlot=0xFE）
- 后收到DriveStartSlotConfig配置
- 配置添加时遍历已添加的硬盘背板进行匹配更新

#### 场景3：PSR add_object_complete统一处理

- PSR所在position的对象添加完成
- 遍历所有StartSlot=0xFE的背板进行统一更新
- 有配置则匹配更新，无配置则全部更新为0

#### 场景4：未收到配置或匹配超时

- PSR下发完成但未收到DriveStartSlotConfig
- 或匹配硬盘组合配置模型失败
- add_object_complete时将无效背板StartSlot更新为0

#### 场景5：add_object_complete之后背板才添加且无配置

- add_object_complete已触发（PSR加载完成），此时无DriveStartSlotConfig
- 之后硬盘背板对象才添加（如来自其他position、热插拔等），StartSlot=0xFE
- 背板添加时检测到无配置，但psr_add_object_complete标志位已置位，将StartSlot更新为0，避免永远保持0xFE

## 1.4 功能列表
| 功能编号 | 功能标题 | 功能描述 |
| ------- | ------- | -------- |
| F1 | DriveStartSlotConfig添加时匹配更新 | DriveStartSlotConfig对象添加时，遍历已添加的硬盘背板，对StartSlot=0xFE的进行匹配，匹配成功且连续性校验通过按ChildStartSlot更新，否则更新为0 |
| F2 | 硬盘背板添加时匹配更新 | 硬盘背板对象添加时，若StartSlot为0xFE，有配置则匹配更新；无配置时若psr_add_object_complete已触发则更新为0，否则不处理（等待时机3） |
| F3 | PSR add_object_complete统一处理 | 监听到PSR add_object_complete时，遍历所有StartSlot为0xFE的背板，有DriveStartSlotConfig则匹配更新，无则全部更新为0 |

# 2.功能设计
## 2.1 总体方案分析
本方案在通用硬件管理APP（general_hardware）的unit_manager中扩展硬盘背板StartSlot更新逻辑，新增对整机PSR定义的DriveStartSlotConfig（硬盘组合起始槽位配置）的处理，在DriveStartSlotConfig添加、硬盘背板添加、PSR add_object_complete三个时机统一执行匹配与更新，确保StartSlot为0xFE的背板最终获得有效值。

### 2.1.1 方案详细设计
#### 2.1.1.1 系统架构

##### 2.1.1.1.1 StartSlot更新管理架构
```mermaid
classDiagram
    class unit_manager {
        -hdd_backplanes: table[]
        -drive_start_slot_configs: table[]
        -psr_position: string
        -psr_add_object_complete_fired: boolean
        +on_add_object()
        +on_add_object_complete()
        +add_hddbackplane_obj_cb()
        +on_add_object(DriveStartSlotConfig 分支)
    }

    class drive_start_slot_helper {
        <<module>>
        +find_matching_configuration_index()
        +check_configuration_continuity()
        +calculate_start_slot_from_config()
        +update_backplane_start_slot_if_pending()
    }

    class hdd_backplane {
        +position: string
        +StartSlot: U8
        +update_start_slot_from_drive_config()
    }

    class m2_transform_card {
        +position: string
        +StartSlot: U8
        +update_start_slot_from_drive_config()
    }

    class DriveStartSlotConfig {
        +Configurations: Array
    }
    class Configuration {
        +UID: String
        +Slot: U8
        +ChildSlotType: String
        +ChildSlotIndex: Array
        +ChildStartSlot: Array
    }
    DriveStartSlotConfig "1" o-- "*" Configuration : contains

    unit_manager "1" o-- "*" hdd_backplane : manages
    unit_manager "1" o-- "*" DriveStartSlotConfig : manages
    unit_manager ..> drive_start_slot_helper : use
    hdd_backplane ..> drive_start_slot_helper : use
    m2_transform_card ..> drive_start_slot_helper : use
```

##### 2.1.1.1.2 处理流程时序图
```mermaid
sequenceDiagram
    participant PSR as PSR加载
    participant UM as unit_manager
    participant Config as DriveStartSlotConfig
    participant BP as HddBackplane

    Note over PSR,BP: 时机1: DriveStartSlotConfig先添加
    PSR->>UM: 添加DriveStartSlotConfig
    UM->>UM: 遍历hdd_backplanes
    loop StartSlot=0xFE的背板
        UM->>BP: update_start_slot_from_drive_config(→helper)
        alt 匹配成功
            BP->>BP: set_prop(StartSlot, ChildStartSlot[i])
        else 匹配失败
            BP->>BP: set_prop(StartSlot, 0)
        end
    end

    Note over PSR,BP: 时机2: 背板添加
    PSR->>UM: 添加HddBackplane/M2(StartSlot=0xFE)
    UM->>BP: update_start_slot_from_drive_config(→helper)
    alt 有配置
        BP->>BP: 匹配并更新StartSlot
    else 无配置
        alt psr_add_object_complete已触发
            BP->>BP: 更新StartSlot=0
        else 未触发
            UM->>UM: 不处理(等待时机3)
        end
    end

    Note over PSR,BP: 时机3: add_object_complete
    PSR->>UM: add_object_complete(psr_position)
    UM->>UM: 设置psr_add_object_complete_fired=true
    UM->>UM: 遍历所有StartSlot=0xFE的背板
    UM->>BP: update_backplane_start_slot_if_pending(helper)
    alt 有DriveStartSlotConfig
        BP->>BP: 匹配更新
    else 无DriveStartSlotConfig
        BP->>BP: 全部更新为0
    end
```

#### 2.1.1.2 方案概述
**关键点**：
- 整机PSR模型仅定义1个硬盘组合的起始槽位配置，DriveStartSlotConfig含Configurations数组，每项通过UID、Slot、ChildSlotType、ChildSlotIndex与背板匹配，ChildStartSlot对应起始槽位值；
- 硬盘背板StartSlot为**0xFE**表示“待 PSR 更新”，需根据 PSR 配置更新；**0xFF**表示“仅 CSR 生效”，不参与 PSR 匹配更新；
- 匹配逻辑：根据背板所在父单板 UID、父单板 Slot、背板 Type、背板 Slot 与 Configuration 的 UID、Slot、ChildSlotType、ChildSlotIndex 进行匹配；
- 更新策略：仅当 StartSlot 为 0xFE 时更新，匹配成功用 ChildStartSlot，匹配失败或未收到配置用 0。

**实现策略**：
1. DriveStartSlotConfig添加时：遍历已添加的硬盘背板，对 StartSlot=0xFE 的调用背板 `update_start_slot_from_drive_config`（内部委托 drive_start_slot_helper）进行匹配并更新；
2. 硬盘背板添加时：若 StartSlot=0xFE，有配置则匹配更新；无配置时若 psr_add_object_complete 已触发则更新为 0，否则不处理；
3. PSR add_object_complete 时：设置标志位，遍历所有 StartSlot=0xFE 的背板，调用 drive_start_slot_helper.update_backplane_start_slot_if_pending，有配置则匹配更新，无配置则全部更新为 0。

#### 2.1.1.3 开发视图

```mermaid
graph TB
    subgraph "general_hardware组件"
        subgraph "unit_manager"
            A[unit_manager.lua]
            B[on_add_object]
            C[on_add_object_complete]
            D[add_drive_start_slot_config_cb]
            E[add_hddbackplane_obj_cb]
        end

        subgraph "drive_start_slot_helper"
            H0[drive_start_slot_helper.lua]
            H1[find_matching_configuration_index]
            H2[check_configuration_continuity]
            H3[calculate_start_slot_from_config]
            H4[update_backplane_start_slot_if_pending]
        end

        subgraph "背板 class/unit/seu"
            F[hdd_backplane.lua]
            F2[m2_transform_card.lua]
            G[update_start_slot_from_drive_config]
        end

        subgraph "数据模型"
            H[DriveStartSlotConfig]
            I[HddBackplane/M2TransferCard]
        end

        A --> B
        A --> C
        B --> D
        B --> E
        E --> F
        E --> F2
        F --> G
        F2 --> G
        G --> H0
        H0 --> H1
        H0 --> H2
        H0 --> H3
        H0 --> H4
        H4 --> H
        H4 --> I
    end

    subgraph "storage组件"
        S[drive_object.lua]
        T[Drive.before_add_object<br/>循环等待HddBackplaneStartSlot从0xFE变为最终值(0或有效起始槽位)并更新Id/Name/NodeId]
    end

    S --> T
    T --> I
```

- **涉及模块**：general_hardware/src/lualib/unit_manager/、storage/src/lualib/drive/
- **主要文件**：
  - **unit_manager.lua**：on_add_object 中 DriveStartSlotConfig 分支（将配置加入 drive_start_slot_configs，object 为 nil 时不添加并打 error 日志）、add_hddbackplane_obj_cb/add_m2_transform_card_obj_cb 中调用 update_start_slot_from_drive_config、on_add_object_complete 中设置 psr_add_object_complete_fired 并遍历背板调用 helper；
  - **drive_start_slot_helper.lua**（路径：unit_manager/drive_start_slot_helper.lua）：匹配与更新逻辑的通用辅助模块，供时机2/3复用。职责：根据 DriveStartSlotConfig 与背板/父单板属性做匹配、连续性校验、计算 StartSlot 及仅当 StartSlot=0xFE 时更新；不负责遍历背板或解析父单板，由 unit_manager 传入 parent_unit。 **DriveStartSlotConfigItem 按 types.json 下标访问**：config_item[1]=UID、[2]=Slot、[3]=ChildSlotType、[4]=ChildSlotIndex、[5]=ChildStartSlot。**get_prop/set_prop** 需传入接口参数（如 `IF_HDD_BACKPLANE` = `bmc.kepler.Systems.HddBackplane`）。接口：find_matching_configuration_index、check_configuration_continuity、calculate_start_slot_from_config、update_backplane_start_slot_if_pending；
  - **class/unit/seu/hdd_backplane.lua、m2_transform_card.lua**：背板对象实现 update_start_slot_from_drive_config(configs, psr_fired, parent_unit)，内部委托 drive_start_slot_helper.update_backplane_start_slot_if_pending；
  - **drive_object.lua**：Drive.before_add_object 中等待 HddBackplaneStartSlot 并更新 Id/Name/NodeId。
- **文件名与目录说明**：辅助模块命名为 drive_start_slot_helper.lua，与“硬盘起始槽位配置”语义一致；放在 unit_manager 目录下与 unit_manager.lua 同级，因属于 unit_manager 业务下的通用逻辑且被 unit_manager 与背板类共同引用，非类定义故不放入 class/ 下。
- **数据模型**：DriveStartSlotConfig（PSR 模型，含 Configurations：UID、Slot、ChildSlotType、ChildSlotIndex、ChildStartSlot）、HddBackplane/M2TransferCard（含 StartSlot，接口 bmc.kepler.Systems.HddBackplane 含 StartSlot、SlotCount）、Drive（含 HddBackplaneStartSlot、RelativeSlot、Id、Name、NodeId）、psr_add_object_complete_fired（布尔标志，初始化 false，add_object_complete 触发时置 true）。
- **构建**：随 general_hardware 组件与 storage 组件构建，无新增构建依赖。

#### 2.1.1.4 运行视图
- **启动阶段**：PSR加载→对象按序添加（DriveStartSlotConfig、HddBackplane等）→各添加回调触发匹配更新
- **PSR完成阶段**：add_object_complete信号触发→遍历StartSlot=0xFE的背板统一更新
- **运行期**：storage 组件在 Drive.before_add_object 流程中监听/轮询 Drive.HddBackplaneStartSlot（同步语法关联的 HddBackplane.StartSlot），当其不再为 0xFE/0xFF（含兜底为 0 的场景）时，按公式 `Id = HddBackplaneStartSlot + RelativeSlot` 动态更新 Drive 的 Id/Name/NodeId。**当实际插装与 DriveStartSlotConfig 配置匹配时**，可保证对外槽位展示与配置一致；若已配置但实际插装不符合配置，则槽位展示一致性不作保证。

### 2.1.2 内部依赖分析

| 依赖组件 | 依赖接口/功能 | 依赖说明 |
| ------- | ----------- | ------- |
| storage | HddBackplane.StartSlot | Drive.HddBackplaneStartSlot关联HddBackplane.StartSlot，用于硬盘Id计算，已有无需变更 |
| object_manage/mdb | on_add_object、on_add_object_complete | 对象添加回调和add_object_complete信号，需注册DriveStartSlotConfig回调 |

### 2.1.3 外部依赖分析
无新增平台SDK依赖，沿用现有PSR加载、对象管理框架。

### 2.1.4 北向接口分析
本功能通过更新HddBackplane.StartSlot间接影响Redfish等接口中硬盘相关资源的展示（如Drive的Id、NodeId等），无新增接口，属性定义沿用现有规范。
| 特性 | SNMP | CLI | WEB | KVM_VMM | IPMI(RMCP/RMCP+) | HMM | Redfish |
| ---- | ---- | ---- | --- | ------ | ---------------- | --- | ------- |
| 支持整机配置硬盘背板起始槽位号 | NA | NA | NA | NA | NA | NA | 间接影响（Drive资源Id等） |

说明：本功能不涉及新增北向接口，仅通过更新HddBackplane.StartSlot间接影响Redfish等接口中Drive资源的Id、NodeId等属性展示。无Redfish新增属性。

### 2.1.5 兼容性分析

| 影响项 | 影响说明 | 兼容性措施 |
| ----- | ------- | --------- |
| 现有硬盘背板 | StartSlot 已为有效值（非 0xFE）的背板（包括历史配置为 0xFF 的场景） | 仅更新逻辑不修改其值，跳过处理；0xFF 表示“仅 CSR 生效”，不参与 PSR 匹配 |
| 老版本 PSR/不配置场景 | 无 DriveStartSlotConfig 配置 | 行为与历史保持一致：add_object_complete 时将所有 StartSlot=0xFE 的背板更新为 0；历史为 0xFF 的背板仍保持“仅 CSR 固定配置生效”的语义 |
| 已配置但实际插装不符合配置 | 背板类型/槽位与 DriveStartSlotConfig 不匹配，或连续性校验不通过 | 仅保证 StartSlot 最终不为 0xFE（会兜底为 0 或保持 0xFF）；**硬盘槽位编码一致性/连续性不作保证** |

### 2.1.6 定制化接口分析
本功能依赖整机PSR配置，不涉及BMC侧定制化接口变更。空定制化条件下，若PSR无DriveStartSlotConfig，则StartSlot=0xFE的背板将被更新为0，历史配置为0xFF的背板保持不变，符合默认行为并兼容既有按CSR固定配置的场景。

### 2.1.7 导入导出分析
不涉及导入导出配置，DriveStartSlotConfig由PSR下发，非用户可导入导出项。

### 2.1.8 传感器分析
不涉及新增传感器。

### 2.1.9 精准告警事件分析
不涉及新增事件。

### 2.1.10 系统锁定分析
本功能为内部对象属性更新，不涉及对外接口或命令，无系统锁定相关变更。

### 2.1.11 用例场景分析

| 用例编号 | 用例名称 | 用例描述 | 前置条件 | 执行步骤 | 预期结果 |
| -------- | -------- | -------- | -------- | -------- | -------- |
| UC1 | DriveStartSlotConfig先于背板到达 | 配置先添加后背板添加，验证匹配更新 | PSR加载中 | 1.收到DriveStartSlotConfig<br/>2.收到HddBackplane(StartSlot=0xFE) | 背板添加时匹配配置，StartSlot更新为ChildStartSlot或0 |
| UC2 | 背板先于DriveStartSlotConfig到达 | 背板先添加后配置添加，验证匹配更新 | PSR加载中 | 1.收到HddBackplane(StartSlot=0xFE)<br/>2.收到DriveStartSlotConfig | 配置添加时遍历背板匹配，StartSlot更新 |
| UC3 | PSR add_object_complete有配置 | 统一处理有配置场景 | 已有DriveStartSlotConfig和背板 | add_object_complete触发 | 所有StartSlot=0xFE的背板完成匹配更新 |
| UC4 | PSR add_object_complete无配置 | 统一处理无配置场景 | 无DriveStartSlotConfig，有背板StartSlot=0xFE | add_object_complete触发 | 所有StartSlot=0xFE的背板更新为0 |
| UC5 | 匹配超时/未收到配置 | 兜底场景处理 | PSR下发完成，无DriveStartSlotConfig | add_object_complete触发 | 所有StartSlot=0xFE的背板更新为0 |
| UC6 | add_object_complete后背板才添加且无配置 | 避免StartSlot永远0xFE | add_object_complete已触发且无配置，之后背板才添加 | 1.add_object_complete触发<br/>2.背板添加(StartSlot=0xFE) | 背板添加时检测标志位，StartSlot更新为0 |

### 2.1.12 装备能力差异分析
无装备版本与Release版本能力差异，逻辑通用。

### 2.1.13 持久化分析
HddBackplane.StartSlot可能被storage等组件间接持久化（如通过关联计算）。本功能仅更新内存中的StartSlot值，不直接变更持久化schema；更新后的值符合现有取值范围（0~254），与老版本兼容。

## 2.2 非功能质量属性设计
### 2.2.1 扩展性分析
匹配与更新逻辑集中在 **drive_start_slot_helper** 与 unit_manager、背板类（hdd_backplane/m2_transform_card）协作；后续若 PSR 模型扩展（如多硬盘组合配置），可在同一回调框架下于 helper 内扩展匹配规则，无需改动整体架构。

### 2.2.2 重用性分析
匹配逻辑（背板所在父单板 UID/Slot、背板 Type/Slot 与 Configuration 的 UID/Slot/ChildSlotType/ChildSlotIndex 匹配及连续性校验）已抽象为 **drive_start_slot_helper** 模块，供 DriveStartSlotConfig 添加、背板添加、add_object_complete 三个场景复用；HddBackplane 与 M2TransferCard 共用同一套 helper 接口。

### 2.2.3 可测试性分析

#### 2.2.3.1 测试覆盖
1. **功能覆盖**
   - DriveStartSlotConfig添加时匹配更新
   - 硬盘背板添加时匹配更新
   - PSR add_object_complete统一处理
   - 配置先到/背板先到两种顺序
   - 有配置/无配置两种场景
   - StartSlot有效值不更新

2. **错误场景覆盖**
   - 匹配失败更新为0
   - 连续性校验不通过更新为0
   - 未收到配置全部更新为0

3. **接口覆盖**
   - 北向接口（Drive资源Id等）间接验证

#### 2.2.3.2 测试环境要求
1. **软件要求**
   - PSR/CSR已配置DriveStartSlotConfig和HddBackplane对象
   - 支持对象添加回调和add_object_complete信号

2. **构造要求**
   - 可构造测试用DriveStartSlotConfig与HddBackplane对象
   - 可模拟对象添加顺序和add_object_complete时机

### 2.2.4 资料分析
若CSR/PSR配置字典或开发指南涉及DriveStartSlotConfig、StartSlot更新规则，需同步更新文档。

### 2.2.5 资源使用分析
无新增线程、消息队列；仅在对象添加和add_object_complete时执行遍历与匹配，背板数量有限（通常个位数），CPU和内存占用可忽略；不涉及Flash读写。

### 2.2.6 可靠性分析
| 编号 | 场景 | 问题描述 | 可靠性影响 | 问题级别 | 建议解决方案/需求 | 讨论结果 | 跟踪人 | 备注 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 1 | DC场景 | PSR加载顺序不确定 | 低 | 低 | 三时机覆盖所有顺序 | 已覆盖 | - | - |
| 2 | AC场景 | 同上 | 低 | 低 | 同上 | 已覆盖 | - | - |
| 3 | BMC场景 | add_object_complete未触发 | 低 | 低 | 依赖框架保证PSR add_object_complete必触发 | 需确认 | - | - |
| 4 | 服务重启 | 重启后PSR重新加载 | 无 | - | 逻辑在每次加载时执行 | - | - | - |
| 5 | 数据获取异常状态 | DriveStartSlotConfig格式异常 | 低 | 低 | 匹配失败时更新为0 | 已考虑 | - | - |
| 6 | add_object_complete后背板添加 | 无配置时背板StartSlot永远0xFE | 高 | 高 | psr_add_object_complete_fired标志位，背板添加时无配置且标志位已置位则更新为0 | 已实现 | - | - |
| 7 | config.mds_obj/object 为 nil | on_add_object 回调收到 nil 对象 | 低 | 低 | unit_manager 不添加并打 error；helper 打 debug 并跳过 | 已实现 | - | 见 3.1.2.6 故障排查 |
### 2.2.7 安全性分析
| 安全合规项 | 是否涉及 | 现有的防护措施 |
| --- | --- | --- |
| 访问控制（通道、文件权限、用户权限、查询权限、配置权限、接口权限） | 否 | 无新增对外接口 |
| 敏感数据 | 否 | 无敏感数据 |
| 日志（操作日志、维护日志、安全日志、运行日志） | 可选 | 可记录StartSlot更新日志便于排查 |
| 文档 | 否 | - |
| 加密及算法 | 否 | - |
| 新增关键资源（密钥、证书、关键配置）备份、恢复 | 否 | - |
| 新增对外接口入参校验 | 否 | - |
| 新增开源及三方软件引入 | 否 | - |
# 3.功能实现
## 3.1【F1-F3】支持整机配置硬盘背板上硬盘起始槽位号实现
### 3.1.1 功能实现设计

**处理时机与流程概览**：

```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 时机1: DriveStartSlotConfig对象添加                                          │
│   仅将配置加入 drive_start_slot_configs（object 为 nil 时不添加并打 error）   │
│   不在此处遍历背板匹配，由时机2/3 统一处理                                    │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ 时机2: 硬盘背板对象添加                                                       │
│   若自身StartSlot≠0xFE → 不处理                                               │
│   若StartSlot=0xFE → 调用 update_start_slot_from_drive_config(→helper)        │
│   → 有配置: 匹配成功用ChildStartSlot，匹配失败用0                              │
│   → 无配置且psr_add_object_complete已触发: 更新为0（兜底，避免永远0xFE）       │
│   → 无配置且psr_add_object_complete未触发: 不处理（等待时机3处理）             │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ 时机3: PSR add_object_complete                                               │
│   设置psr_add_object_complete_fired=true                                     │
│   遍历所有已添加的硬盘背板，对StartSlot=0xFE的调用 helper.                    │
│   update_backplane_start_slot_if_pending 进行统一处理                         │
│   → 有DriveStartSlotConfig: 匹配成功用ChildStartSlot，失败用0                  │
│   → 无DriveStartSlotConfig: 全部更新为0                                        │
└─────────────────────────────────────────────────────────────────────────────┘
```

**核心原则**：仅当 StartSlot=0xFE 时参与更新；已为有效值（含 0xFF“仅 CSR 生效”）的背板不修改。**兜底机制**：通过 psr_add_object_complete_fired 标志位，确保在 add_object_complete 之后才添加的背板（且无配置时）也能被正确更新为 0，避免 StartSlot 永远保持 0xFE。

### 3.1.2 功能详细设计

#### 3.1.2.1 整机PSR模型定义（参考）

**对象作用**：DriveStartSlotConfig用于确定硬盘背板的起始槽位。整机PSR模型仅定义1个硬盘组合的起始槽位配置，对象包含Configurations数组，每个配置项通过UID、Slot、ChildSlotType、ChildSlotIndex与背板匹配，ChildStartSlot数组对应各槽位的起始槽位号。

**属性定义**：

| 属性名称 | 变化类型 | 签名 | 读写&权限 | 持久化 | 变化通知 | 属性说明 | 属性约束 |
| -------- | -------- | ---- | --------- | ------ | -------- | -------- | -------- |
| DriveStartSlotConfig | 新增对象 | - | - | - | - | 用于确定硬盘背板的起始槽位 | 无 |
| Configurations | 新增属性 | a | 只读 R：ReadOnly | 不持久化 | false | 硬盘背板起始槽位配置 | 无 |
| UID | 新增属性 | s | 只读 R：ReadOnly | 不持久化 | false | 天池单板的UID | 无 |
| Slot | 新增属性 | y | 只读 R：ReadOnly | 不持久化 | false | 上一级组件（如单板）的槽位号，用于精确匹配配置所属组件 | 无 |
| ChildSlotType | 新增属性 | s | 只读 R：ReadOnly | 不持久化 | false | 该组件下一级硬盘背板的类型 | 无 |
| ChildSlotIndex | 新增属性 | ay | 只读 R：ReadOnly | 不持久化 | false | 该组件下一级硬盘背板所在的槽位 | 无 |
| ChildStartSlot | 新增属性 | ay | 只读 R：ReadOnly | 不持久化 | false | 该组件下一级硬盘背板的起始槽位 | 无 |

说明：UID、Slot、ChildSlotType、ChildSlotIndex、ChildStartSlot为Configurations数组中每项配置的元素属性。

**HddBackplane/M2TransferCard 私有属性 SlotCount**（接口：`bmc.kepler.Systems.HddBackplane`）：

| 属性名称 | Usage | 类型 | 默认值 | 属性说明 |
| -------- | ----- | ---- | ------ | -------- |
| SlotCount | CSR | U8 | 0 | 硬盘背板槽位个数，用于连续性校验；相邻背板起始槽位差值需等于对应背板的 SlotCount |

**对象示例**：

```json
"DriveStartSlotConfig_1": {
    "Configurations": [
      {
        "UID": "000XXX",
        "Slot": 1,
        "ChildSlotType": "SEU",
        "ChildSlotIndex": [1, 2],
        "ChildStartSlot": [3, 11]
      },
      {
        "UID": "000XXX",
        "Slot": 1,
        "ChildSlotType": "M2",
        "ChildSlotIndex": [6],
        "ChildStartSlot": [0]
      }
    ]
}
```

示例说明：第一个配置表示UID为"000XXX"、Slot为1的天池单板（EXU）下，类型为SEU的背板槽位1、2的起始槽位分别为3、11（即槽位1背板起始3，槽位2背板起始11，若槽位1背板SlotCount=8则3+8=11，满足连续性）；第二个配置表示同一块单板（UID相同、Slot=1）下类型为M2的背板槽位6的起始槽位为0，为最后元素无需连续性校验。ChildSlotIndex与ChildStartSlot一一对应。

**匹配规则**：父单板的UID、父单板的Slot、背板类型（Type）、背板槽位（Slot）分别与Configuration的UID、Slot、ChildSlotType、ChildSlotIndex对应；匹配成功后，取ChildSlotIndex中匹配下标i对应的ChildStartSlot[i]作为StartSlot。**连续性校验**：若非最后元素，需满足 DriveStartSlotConfig 中相邻背板起始槽位的差值（ChildStartSlot[i+1]-ChildStartSlot[i]）与对应背板的槽位数量（SlotCount，或 M2TransferCard 的 M2SlotMaxCount）相等，即 `ChildStartSlot[i] + 背板槽位个数 == ChildStartSlot[i+1]`，校验不通过视为匹配失败。

#### 3.1.2.2 DriveStartSlotConfig对象添加时处理

**输入**：新添加的DriveStartSlotConfig对象（含Configurations数组，每项含UID、ChildSlotType、ChildSlotIndex、ChildStartSlot）

**处理逻辑**：
1. 遍历 `unit_manager.hdd_backplanes` 中已添加的硬盘背板对象；
2. 对每个背板，若 `StartSlot == 0xFE`：调用该背板的 `update_start_slot_from_drive_config(drive_start_slot_configs, psr_add_object_complete_fired, parent_unit)`，内部委托 `drive_start_slot_helper.update_backplane_start_slot_if_pending`。helper 使用父单板 UID/Slot、背板 Type/Slot 与 Configuration 的 UID/Slot/ChildSlotType/ChildSlotIndex 匹配，背板槽位个数从背板属性 **SlotCount**（接口 bmc.kepler.Systems.HddBackplane）获取；匹配成功且通过连续性校验则 `set_prop('StartSlot', ChildStartSlot[i])`，否则 `set_prop('StartSlot', 0)`；
3. 若 `StartSlot ~= 0xFE`，跳过，不更新（包括历史配置为 0xFF、或已被更新为 0/其他有效值的背板）。

#### 3.1.2.3 硬盘背板对象添加时处理

**输入**：新添加的 HddBackplane 或 M2TransferCard 对象；unit_manager 在 add_hddbackplane_obj_cb 中解析 parent_unit 并传入。

**处理逻辑**（在背板 `update_start_slot_from_drive_config` 内，委托 drive_start_slot_helper.update_backplane_start_slot_if_pending）：
1. 若背板 `get_prop('StartSlot', IF_HDD_BACKPLANE) ~= 0xFE`，直接返回，不处理；
2. 若 StartSlot == 0xFE：
   - **有 DriveStartSlotConfig 对象**：helper 根据 parent_unit、背板 Type/Slot/SlotCount 与 Configurations 匹配（DriveStartSlotConfigItem 按下标访问），匹配成功且通过连续性校验则 `set_prop('StartSlot', ChildStartSlot[i], IF_HDD_BACKPLANE)`，匹配失败或校验不通过则 `set_prop('StartSlot', 0, IF_HDD_BACKPLANE)`；
   - **无 DriveStartSlotConfig 对象**：若 psr_add_object_complete_fired == true，则 set_prop('StartSlot', 0)（兜底）；若为 false，则不处理（等待时机3统一处理）。

#### 3.1.2.4 PSR add_object_complete时处理

**触发条件**：`on_add_object_complete(position)`，且`position == psr_position`（即PSR所在position的对象添加完成）

**处理逻辑**：
1. 设置`psr_add_object_complete_fired = true`（供时机2中“add_object_complete之后才添加的背板”兜底使用）；
2. 遍历所有已添加的硬盘背板对象；
3. 对每个背板，若`StartSlot == 0xFE`：
   - **有DriveStartSlotConfig对象**：对每个配置进行匹配，匹配成功且通过连续性校验则`StartSlot = ChildStartSlot[i]`，匹配失败或校验不通过则`StartSlot = 0`；
   - **无DriveStartSlotConfig对象**：直接将`StartSlot`更新为`0`；
4. 若`StartSlot ~= 0xFE`，跳过。

**说明**：无论是否有 DriveStartSlotConfig，最终都要将 StartSlot 为 0xFE 的背板更新为有效值；匹配则按 ChildStartSlot 更新，否则更新为 0。标志位 psr_add_object_complete_fired 确保在 add_object_complete 之后才添加的背板（无配置时）也能被更新为 0。

#### 3.1.2.5 匹配规则说明

- **匹配依据**：背板所在容器的UID、背板类型（Type，如SEU、M2）、背板槽位（Slot）分别与Configuration的UID、ChildSlotType、ChildSlotIndex对应；
- **取值规则**：ChildSlotIndex[i]与背板Slot匹配时，取ChildStartSlot[i]作为该背板的StartSlot；
- **连续性校验**（配置合法性校验）：匹配到 ChildSlotIndex[i] 对应 ChildStartSlot[i] 时，需校验 `ChildStartSlot[i] + 背板槽位个数 == ChildStartSlot[i+1]`，即相邻背板起始槽位差值等于当前背板槽位数量。槽位个数从背板对象的 **SlotCount** 属性获取（接口 `bmc.kepler.Systems.HddBackplane`，Usage:CSR，U8，默认 0）；HddBackplane 与 M2TransferCard 均实现该接口。若 SlotCount 为 nil/0/0xff 则视为无效，不进行匹配更新。若当前为 ChildStartSlot 数组最后一个元素，则无需连续性校验。

#### 3.1.2.6 超时与未收到配置场景

- **整机 PSR 下发完还未收到 DriveStartSlotConfig**：在 add_object_complete 时，无 DriveStartSlotConfig 对象，将所有 StartSlot=0xFE 的背板更新为 0；
- **匹配硬盘组合配置模型超时**：同上，add_object_complete 作为最终兜底时机，将未匹配的 StartSlot=0xFE 更新为 0；
- **add_object_complete 之后背板才添加且无配置**：背板可能来自其他 position 或热插拔，在 add_object_complete 之后才添加。此时无 DriveStartSlotConfig，背板添加时检测到 psr_add_object_complete_fired 已置位，将 StartSlot 更新为 0，避免永远保持 0xFE。

#### 3.1.2.8 场景覆盖性分析（StartSlot=0xFE遗漏检查）

| 序号 | 场景描述 | 时机1 | 时机2 | 时机3 | 是否覆盖 | 说明 |
| ---- | -------- | ----- | ----- | ----- | -------- | ---- |
| 1 | 配置先到、背板后到 | 仅加入 configs | 背板添加时有配置，匹配更新 | - | ✓ | 时机2处理 |
| 2 | 背板先到、配置后到 | 仅加入 configs | - | add_object_complete 统一处理 | ✓ | 时机3处理 |
| 3 | 背板与配置同批、add_object_complete有配置 | 可能已处理 | 可能已处理 | 统一处理 | ✓ | 三时机至少一处处理 |
| 4 | add_object_complete无配置、背板已存在 | - | - | 全部更新为0 | ✓ | 时机3处理 |
| 5 | add_object_complete无配置、背板后添加 | - | 无配置且标志位已置位→更新为0 | - | ✓ | 时机2兜底 |
| 6 | add_object_complete有配置、背板后添加（热插拔等） | - | 有配置则匹配更新 | - | ✓ | 时机2处理 |
| 7 | 匹配失败（UID/Slot/Type/Slot不匹配） | 更新为0 | 更新为0 | 更新为0 | ✓ | 三时机均处理 |
| 8 | 连续性校验不通过（SlotCount 参与） | 更新为0 | 更新为0 | 更新为0 | ✓ | 视为匹配失败 |
| 9 | psr_add_object_complete未触发且无配置 | - | 不处理，等待时机3 | 触发后处理 | ✓ | 依赖框架保证 psr_position 的 add_object_complete 必触发 |

**前置假设**：框架保证psr_position的add_object_complete在PSR对象分发完成后必触发；若该信号因异常未触发，场景9中背板将保持0xFE，属框架级问题。

#### 3.1.2.9 StartSlot更新决策流程图

```mermaid
flowchart TD
    A[收到DriveStartSlotConfig/背板/add_object_complete] --> B{处理对象类型}
    B -->|DriveStartSlotConfig添加| C1[加入drive_start_slot_configs]
    B -->|背板添加| D{StartSlot==0xFE?}
    B -->|add_object_complete| E[遍历所有StartSlot=0xFE的背板，调用helper]

    C1 --> C1E[结束，时机2/3执行匹配]
    D -->|否| F[不处理]
    D -->|是| G{有DriveStartSlotConfig?}
    G -->|否| G2{psr_add_object_complete已触发?}
    G2 -->|是| P[StartSlot=0]
    G2 -->|否| F
    G -->|是| H[遍历配置进行匹配]
    H --> K[匹配UID/ChildSlotType/ChildSlotIndex]
    E --> L{有DriveStartSlotConfig?}
    L -->|否| M[全部更新为0]
    L -->|是| K

    K --> N{匹配成功且连续性校验通过?}
    N -->|是| O[StartSlot=ChildStartSlot]
    N -->|否| P
```

#### 3.1.2.10 Drive对象Id及相关属性更新设计

**Id计算规则**：硬盘Drive对象的`Id`由所在硬盘背板的起始槽位号和相对槽位共同决定：

- 公式：`Id = HddBackplaneStartSlot + RelativeSlot`
  - `HddBackplaneStartSlot`：来自Drive对象的属性，映射自对应HddBackplane.StartSlot
  - `RelativeSlot`：硬盘在所属背板上的相对槽位偏移，一般为0、1、2...
- 对外展示：Drive.Id对外即“硬盘槽位号”，相关接口和日志均以此为准

**before_add_object中的处理流程**：

在Drive ORM对象的`before_add_object`（或等价初始化流程）中，需要在`HddBackplaneStartSlot`稳定后统一更新与槽位相关的属性：

1. **等待HddBackplaneStartSlot生效**
   - 起始值可能为`0xFF`（无效或待更新状态），需要在合理的超时时间内轮询等待其变为最终值（PSR更新完毕后可能为0或真实起始槽位号）
   - 伪代码示例：
     - 若`HddBackplaneStartSlot == 0xFF`且未超时：`sleep`一小段时间后重新检查
     - 直到获得非`0xFF`值或超时为止

2. **统一更新与槽位相关的属性**
   - 在获得有效的`HddBackplaneStartSlot`后，统一基于公式计算并更新：
     - `Id = HddBackplaneStartSlot + RelativeSlot`
     - `Name`：按Drive类配置字典约定，例如`Disk${Id}`或`NVMeDisk${Id}`
     - `NodeId`：通常为`PhysicalLocation + Name`，用于Redfish URL和内部索引
  - 这样在以下条件成立时可以保证：
    - **实际插装的硬盘背板与DriveStartSlotConfig配置匹配**（UID/Type/Slot匹配且连续性校验通过）
    - 对外展示的盘位号与整机PSR定义的起始槽位保持一致
    - Drive相关接口和日志中的槽位信息与背板起始槽位号动态联动

3. **可选：后续变化时的重计算**
   - 若设计上HddBackplaneStartSlot在运行期可能变化（例如重新装配配置），应在对应属性变化时触发Drive.Id/Name/NodeId的重计算，保持一致性
   - 若仅在硬件发现阶段确定一次，则只需在`before_add_object`阶段处理一次即可

#### 3.1.2.11 相关CSR对象动态引用约束

硬盘背板起始槽位号动态更新后，所有“指向某个盘位”的CSR配置必须通过Drive对象的属性进行**动态引用**，禁止硬编码具体槽位号或Id。

1. **Event/ThresholdSensor/Component等对象**
   - 不允许在CSR中写死特定盘位，例如：
     - `"NodeId": "HDDPlaneDisk8"`
     - 固定的`Id: 8`这类常量
   - 推荐的做法是通过表达式引用Drive对象属性，例如：
     - `"< =/Drive_1.Id"` / `"< =/Drive_1.NodeId"` / `"< =/Drive_1.SlotNumber"` 等
   - 这样在`Id = HddBackplaneStartSlot + RelativeSlot`发生变化时，相关事件、阈值传感器、Component对象会自动跟随更新

2. **下行BusinessConnector（业务连接器）对象**
   - Connector或ProcessingFlow中的目标盘位信息，不应直接写死具体“第几号盘”
   - 应通过Drive对象属性动态拼接或匹配，例如：
     - 使用Drive.Id或SlotNumber作为计算参数，在公式/映射中构造目标路径或索引
     - 通过Drive.NodeId拼接Redfish或内部路径

3. **约束总结**
   - **禁止**在CSR中硬编码具体硬盘Id/槽位号
   - **必须**通过Drive.Id/Name/NodeId/SlotNumber等属性进行动态关联
   - 目的：当HddBackplane.StartSlot根据整机PSR调整时，所有与盘位相关的对象（事件、传感器、Component、业务连接器等）能够自动适配新的全局盘位编号，避免出现“盘位展示与真实位置不一致”的问题

### 3.1.3 开发者测试
<!--
增加模块接口：以活动图/流程图等形式明确模块内处理流程，针对模块处理流程中的分支进行覆盖
修改模块接口处理流程：覆盖修改影响流程分支
-->
#### 3.1.3.1 单元测试
DT设计参考：
| 组件名 | 用例类型 | 测试用例描述 | 用例名称 | 预置条件 | 操作步骤 | 预期结果 |
| --- | --- | --- | --- | --- | --- | --- |
| general_hardware | UT | DriveStartSlotConfig先添加后背板添加，匹配成功 | test_drive_start_slot_config_first_match_ok | 无 | 1.添加DriveStartSlotConfig(Configurations含UID/Slot/SEU/ChildSlotIndex[1]/ChildStartSlot[8])<br/>2.添加HddBackplane(Slot=1,Type=SEU,StartSlot=0xFE) | HddBackplane.StartSlot=8 |
| general_hardware | UT | 背板先添加后DriveStartSlotConfig添加，匹配成功 | test_backplane_first_then_config_match_ok | 无 | 1.添加HddBackplane(Slot=1,Type=SEU,StartSlot=0xFE)<br/>2.添加DriveStartSlotConfig(Configurations含匹配项) | HddBackplane.StartSlot=8 |
| general_hardware | UT | add_object_complete有配置，匹配失败更新为0 | test_add_object_complete_with_config_match_fail | 有背板StartSlot=0xFE，有DriveStartSlotConfig但不匹配 | 触发PSR add_object_complete | 背板.StartSlot=0 |
| general_hardware | UT | add_object_complete无配置，全部更新为0 | test_add_object_complete_no_config | 有背板StartSlot=0xFE，无DriveStartSlotConfig | 触发PSR add_object_complete | 所有背板.StartSlot=0 |
| general_hardware | UT | StartSlot已有效值不更新 | test_start_slot_valid_not_update | 背板StartSlot=4（有效值） | 添加DriveStartSlotConfig或触发add_object_complete | 背板.StartSlot仍为4 |
| general_hardware | UT | add_object_complete后背板添加且无配置 | test_backplane_add_after_complete_no_config | add_object_complete已触发且无配置 | 1.触发add_object_complete<br/>2.添加背板(StartSlot=0xFE) | 背板添加时检测标志位，StartSlot更新为0 |
| general_hardware | UT | 连续性校验不通过（SlotCount） | test_continuity_check_fail | 配置ChildStartSlot[1,2]=[3,9]，背板SlotCount=8(3+8≠9) | 匹配并校验 | 校验不通过，StartSlot更新为0 |

#### 3.1.3.2 集成测试
不涉及

# 4.总结

本设计文档详细描述了openUBMC支持整机配置硬盘背板上硬盘起始槽位号的功能实现方案，主要特性包括：

1. **三时机处理机制**：在DriveStartSlotConfig添加、硬盘背板添加、PSR add_object_complete三个时机执行匹配与更新，覆盖配置与背板任意到达顺序

2. **匹配更新策略**：仅对 StartSlot=0xFE 的背板进行更新，匹配成功按 ChildStartSlot 更新，匹配失败或未收到配置则更新为 0；0xFF 表示“仅 CSR 生效”，不参与 PSR 匹配，确保所有“待更新”背板最终得到有效值。

3. **兜底保障**：add_object_complete 作为最终兜底时机，设置 psr_add_object_complete_fired 标志位；背板添加时若无配置且标志位已置位则更新为 0，避免 add_object_complete 之后才添加的背板 StartSlot 永远保持 0xFE。

4. **兼容性**：已为有效值的背板不修改，老版本 PSR 无 DriveStartSlotConfig 时行为明确。

5. **实现结构**：匹配与更新逻辑集中在 **drive_start_slot_helper** 模块（unit_manager/drive_start_slot_helper.lua），供 DriveStartSlotConfig 添加、背板添加、add_object_complete 三时机复用；背板类（HddBackplane、M2TransferCard）通过 update_start_slot_from_drive_config 委托 helper，unit_manager 负责遍历与 parent_unit 解析。

该方案提升了硬盘背板起始槽位号配置的灵活性：当**配置存在且实际插装符合配置**时，系统可根据整机 PSR 配置动态更新槽位号，保证硬盘槽位编码一致且连续、硬盘 ID 计算正确、存储管理和 Redfish 等北向接口展示准确；当**已配置但实际插装不符合配置**时，硬盘槽位编码无法得到保证；当**不配置**时，行为与历史功能保持一致（add_object_complete 兜底将 StartSlot=0xFE 更新为 0）。