From 56eda0d5289e74d7a55661898b5fc65c191dc25f Mon Sep 17 00:00:00 2001 From: Charles Tsai Date: Mon, 22 Jun 2026 20:13:07 +0000 Subject: [PATCH 1/2] implement get_midplane_down_reason add tests Signed-off-by: Charles Tsai --- .../sonic_platform/module.py | 37 ++++++++++++++++--- .../mlnx-platform-api/tests/test_module.py | 14 +++++++ 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/module.py b/platform/mellanox/mlnx-platform-api/sonic_platform/module.py index c8757efdb11..d8dc3b7d537 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/module.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/module.py @@ -278,19 +278,34 @@ def __init__(self, dpu_id): self.CONFIG_DB_NAME = "CONFIG_DB" self.midplane_interface = None self.bus_info = None - self.reboot_base_path = f"/var/run/hw-management/{self.dpuctl_obj._name}/system/" + self.reset_base_path = f"/var/run/hw-management/{self.dpuctl_obj._name}/system/" + # Two dedicated maps keyed by the hw-management reset-cause file. Each value is + # a (reason_code, description) tuple, so within each map index 0 is always the + # reason code and index 1 the description (no cross-purpose index reuse). self.reboot_cause_map = { - f'{self.reboot_base_path}reset_aux_pwr_or_reload': + f'{self.reset_base_path}reset_aux_pwr_or_reload': (ChassisBase.REBOOT_CAUSE_POWER_LOSS, 'power auxiliary outage or reload'), - f'{self.reboot_base_path}reset_comex_pwr_fail': + f'{self.reset_base_path}reset_comex_pwr_fail': (ChassisBase.REBOOT_CAUSE_POWER_LOSS, 'Power failed to comex module'), - f'{self.reboot_base_path}reset_from_main_board': + f'{self.reset_base_path}reset_from_main_board': (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, 'Reset from Main board'), - f'{self.reboot_base_path}reset_dpu_thermal': + f'{self.reset_base_path}reset_dpu_thermal': (ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER, 'Thermal shutdown of the DPU'), - f'{self.reboot_base_path}reset_pwr_off': + f'{self.reset_base_path}reset_pwr_off': (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, 'Reset due to Power off'), } + self.midplane_down_reason_map = { + f'{self.reset_base_path}reset_aux_pwr_or_reload': + (ModuleBase.MIDPLANE_DOWN_REASON_POWER_LOSS, 'power auxiliary outage or reload'), + f'{self.reset_base_path}reset_comex_pwr_fail': + (ModuleBase.MIDPLANE_DOWN_REASON_POWER_LOSS, 'Power failed to comex module'), + f'{self.reset_base_path}reset_from_main_board': + (ModuleBase.MIDPLANE_DOWN_REASON_NON_HARDWARE, 'Reset from Main board'), + f'{self.reset_base_path}reset_dpu_thermal': + (ModuleBase.MIDPLANE_DOWN_REASON_THERMAL_OVERLOAD_OTHER, 'Thermal shutdown of the DPU'), + f'{self.reset_base_path}reset_pwr_off': + (ModuleBase.MIDPLANE_DOWN_REASON_NON_HARDWARE, 'Reset due to Power off'), + } self.MLX_DPU_REBOOT_CAUSE_WARM = 0 self.MLX_DPU_REBOOT_CAUSE_COLD = 1 self.MLX_DPU_REBOOT_CAUSE_WATCHDOG = 2 @@ -483,6 +498,16 @@ def get_reboot_cause(self): return rd return ChassisBase.REBOOT_CAUSE_NON_HARDWARE, '' + def get_midplane_down_reason(self): + """ + Retrieves the reason for the midplane down + """ + for f, rd in self.midplane_down_reason_map.items(): + if utils.read_int_from_file(f) == 1: + logger.log_notice(f"Midplane down reason for {self._name} is {rd[0]}") + return rd + return ModuleBase.MIDPLANE_DOWN_REASON_HARDWARE_OTHER, '' + def get_midplane_ip(self): """ Retrieves the midplane IP-address of the module in a modular chassis diff --git a/platform/mellanox/mlnx-platform-api/tests/test_module.py b/platform/mellanox/mlnx-platform-api/tests/test_module.py index dfc6c6c9f6e..c9126ccf28c 100644 --- a/platform/mellanox/mlnx-platform-api/tests/test_module.py +++ b/platform/mellanox/mlnx-platform-api/tests/test_module.py @@ -344,6 +344,20 @@ def mock_read_int_from_file(file_path, default=0, raise_exception=False, log_fun for index, file_name in enumerate(file_name_list): test_file_path = file_name assert m.get_reboot_cause() == reboot_cause_list[index] + + # get_midplane_down_reason() uses midplane_down_reason_map and must return MIDPLANE_DOWN_REASON_* codes. + midplane_down_reason_list = [ + (ModuleBase.MIDPLANE_DOWN_REASON_POWER_LOSS, 'power auxiliary outage or reload'), + (ModuleBase.MIDPLANE_DOWN_REASON_POWER_LOSS, 'Power failed to comex module'), + (ModuleBase.MIDPLANE_DOWN_REASON_NON_HARDWARE, 'Reset from Main board'), + (ModuleBase.MIDPLANE_DOWN_REASON_THERMAL_OVERLOAD_OTHER, 'Thermal shutdown of the DPU'), + (ModuleBase.MIDPLANE_DOWN_REASON_NON_HARDWARE, 'Reset due to Power off'), + (ModuleBase.MIDPLANE_DOWN_REASON_HARDWARE_OTHER, ''), + ] + with patch("sonic_platform.utils.read_int_from_file", wraps=mock_read_int_from_file): + for index, file_name in enumerate(file_name_list): + test_file_path = file_name + assert m.get_midplane_down_reason() == midplane_down_reason_list[index] # Test subprocess exception case mock_check_output.side_effect = subprocess.CalledProcessError(1, 'mlxreg') From 421be441733ab8e78ea053b0ca2c125dc110e8bb Mon Sep 17 00:00:00 2001 From: Charles Tsai Date: Sat, 25 Jul 2026 00:16:21 +0300 Subject: [PATCH 2/2] fix tests as we are not using new constant for midplane_down_reason Signed-off-by: Charles Tsai --- .../sonic_platform/module.py | 36 +++++++------------ .../mlnx-platform-api/tests/test_module.py | 13 ++----- 2 files changed, 16 insertions(+), 33 deletions(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/module.py b/platform/mellanox/mlnx-platform-api/sonic_platform/module.py index d8dc3b7d537..67ac6dded29 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/module.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/module.py @@ -278,34 +278,19 @@ def __init__(self, dpu_id): self.CONFIG_DB_NAME = "CONFIG_DB" self.midplane_interface = None self.bus_info = None - self.reset_base_path = f"/var/run/hw-management/{self.dpuctl_obj._name}/system/" - # Two dedicated maps keyed by the hw-management reset-cause file. Each value is - # a (reason_code, description) tuple, so within each map index 0 is always the - # reason code and index 1 the description (no cross-purpose index reuse). + self.reboot_base_path = f"/var/run/hw-management/{self.dpuctl_obj._name}/system/" self.reboot_cause_map = { - f'{self.reset_base_path}reset_aux_pwr_or_reload': + f'{self.reboot_base_path}reset_aux_pwr_or_reload': (ChassisBase.REBOOT_CAUSE_POWER_LOSS, 'power auxiliary outage or reload'), - f'{self.reset_base_path}reset_comex_pwr_fail': + f'{self.reboot_base_path}reset_comex_pwr_fail': (ChassisBase.REBOOT_CAUSE_POWER_LOSS, 'Power failed to comex module'), - f'{self.reset_base_path}reset_from_main_board': + f'{self.reboot_base_path}reset_from_main_board': (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, 'Reset from Main board'), - f'{self.reset_base_path}reset_dpu_thermal': + f'{self.reboot_base_path}reset_dpu_thermal': (ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER, 'Thermal shutdown of the DPU'), - f'{self.reset_base_path}reset_pwr_off': + f'{self.reboot_base_path}reset_pwr_off': (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, 'Reset due to Power off'), } - self.midplane_down_reason_map = { - f'{self.reset_base_path}reset_aux_pwr_or_reload': - (ModuleBase.MIDPLANE_DOWN_REASON_POWER_LOSS, 'power auxiliary outage or reload'), - f'{self.reset_base_path}reset_comex_pwr_fail': - (ModuleBase.MIDPLANE_DOWN_REASON_POWER_LOSS, 'Power failed to comex module'), - f'{self.reset_base_path}reset_from_main_board': - (ModuleBase.MIDPLANE_DOWN_REASON_NON_HARDWARE, 'Reset from Main board'), - f'{self.reset_base_path}reset_dpu_thermal': - (ModuleBase.MIDPLANE_DOWN_REASON_THERMAL_OVERLOAD_OTHER, 'Thermal shutdown of the DPU'), - f'{self.reset_base_path}reset_pwr_off': - (ModuleBase.MIDPLANE_DOWN_REASON_NON_HARDWARE, 'Reset due to Power off'), - } self.MLX_DPU_REBOOT_CAUSE_WARM = 0 self.MLX_DPU_REBOOT_CAUSE_COLD = 1 self.MLX_DPU_REBOOT_CAUSE_WATCHDOG = 2 @@ -501,12 +486,17 @@ def get_reboot_cause(self): def get_midplane_down_reason(self): """ Retrieves the reason for the midplane down + + Returns: + A tuple (string, string) where the first element is one of the + ChassisBase.REBOOT_CAUSE_* strings and the second element is a + description of the midplane down reason. """ - for f, rd in self.midplane_down_reason_map.items(): + for f, rd in self.reboot_cause_map.items(): if utils.read_int_from_file(f) == 1: logger.log_notice(f"Midplane down reason for {self._name} is {rd[0]}") return rd - return ModuleBase.MIDPLANE_DOWN_REASON_HARDWARE_OTHER, '' + return ChassisBase.REBOOT_CAUSE_NON_HARDWARE, '' def get_midplane_ip(self): """ diff --git a/platform/mellanox/mlnx-platform-api/tests/test_module.py b/platform/mellanox/mlnx-platform-api/tests/test_module.py index c9126ccf28c..911dfb43aa3 100644 --- a/platform/mellanox/mlnx-platform-api/tests/test_module.py +++ b/platform/mellanox/mlnx-platform-api/tests/test_module.py @@ -345,19 +345,12 @@ def mock_read_int_from_file(file_path, default=0, raise_exception=False, log_fun test_file_path = file_name assert m.get_reboot_cause() == reboot_cause_list[index] - # get_midplane_down_reason() uses midplane_down_reason_map and must return MIDPLANE_DOWN_REASON_* codes. - midplane_down_reason_list = [ - (ModuleBase.MIDPLANE_DOWN_REASON_POWER_LOSS, 'power auxiliary outage or reload'), - (ModuleBase.MIDPLANE_DOWN_REASON_POWER_LOSS, 'Power failed to comex module'), - (ModuleBase.MIDPLANE_DOWN_REASON_NON_HARDWARE, 'Reset from Main board'), - (ModuleBase.MIDPLANE_DOWN_REASON_THERMAL_OVERLOAD_OTHER, 'Thermal shutdown of the DPU'), - (ModuleBase.MIDPLANE_DOWN_REASON_NON_HARDWARE, 'Reset due to Power off'), - (ModuleBase.MIDPLANE_DOWN_REASON_HARDWARE_OTHER, ''), - ] + # get_midplane_down_reason() shares reboot_cause_map, so it reports the same + # (cause, description) pairs as get_reboot_cause() for every reset-cause file. with patch("sonic_platform.utils.read_int_from_file", wraps=mock_read_int_from_file): for index, file_name in enumerate(file_name_list): test_file_path = file_name - assert m.get_midplane_down_reason() == midplane_down_reason_list[index] + assert m.get_midplane_down_reason() == reboot_cause_list[index] # Test subprocess exception case mock_check_output.side_effect = subprocess.CalledProcessError(1, 'mlxreg')