From 26858ce64e03790db982e90a4a0faa59b6e21f9c Mon Sep 17 00:00:00 2001 From: Junchao-Mellanox <57339448+Junchao-Mellanox@users.noreply.github.com> Date: Tue, 16 May 2023 02:34:54 +0800 Subject: [PATCH] [Mellanox] add PSU fan direction support (#14508) - Why I did it Add PSU fan direction support - How I did it Implement fan.get_direction for PSU fan - How to verify it Manual test Unit test --- .../mlnx-platform-api/sonic_platform/fan.py | 31 +++++++++++++++++-- .../sonic_platform/fan_drawer.py | 15 ++------- .../mlnx-platform-api/tests/test_fan_api.py | 11 +++++-- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/fan.py b/platform/mellanox/mlnx-platform-api/sonic_platform/fan.py index ec205fe60431..c53abf6af9c1 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/fan.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/fan.py @@ -31,6 +31,7 @@ from .led import ComponentFaultyIndicator from . import utils from .thermal import Thermal + from .fan_drawer import VirtualDrawer except ImportError as e: raise ImportError (str(e) + "- required module not found") @@ -45,7 +46,10 @@ FAN_DIR = "/var/run/hw-management/thermal/fan{}_dir" FAN_DIR_VALUE_EXHAUST = 0 FAN_DIR_VALUE_INTAKE = 1 - +FAN_DIR_MAPPING = { + FAN_DIR_VALUE_EXHAUST: FanBase.FAN_DIRECTION_EXHAUST, + FAN_DIR_VALUE_INTAKE: FanBase.FAN_DIRECTION_INTAKE, +} class MlnxFan(FanBase): def __init__(self, fan_index, position): @@ -125,6 +129,20 @@ def is_replaceable(self): """ return False + @classmethod + def get_fan_direction(cls, dir_path): + try: + fan_dir = utils.read_int_from_file(dir_path, raise_exception=True) + ret = FAN_DIR_MAPPING.get(fan_dir) + if ret is None: + logger.log_error(f"Got wrong value {fan_dir} for fan direction {dir_path}") + return FanBase.FAN_DIRECTION_NOT_APPLICABLE + else: + return ret + except (ValueError, IOError) as e: + logger.log_error(f"Failed to read fan direction from {dir_path} - {e}") + return FanBase.FAN_DIRECTION_NOT_APPLICABLE + class PsuFan(MlnxFan): # PSU fan speed vector @@ -145,6 +163,7 @@ def __init__(self, fan_index, position, psu): self.psu_i2c_bus_path = os.path.join(CONFIG_PATH, 'psu{0}_i2c_bus'.format(self.index)) self.psu_i2c_addr_path = os.path.join(CONFIG_PATH, 'psu{0}_i2c_addr'.format(self.index)) self.psu_i2c_command_path = os.path.join(CONFIG_PATH, 'fan_command') + self.psu_fan_dir_path = os.path.join(FAN_PATH, "psu{}_fan_dir".format(self.index)) def get_direction(self): """ @@ -165,7 +184,10 @@ def get_direction(self): 1 stands for forward, in other words intake 0 stands for reverse, in other words exhaust """ - return self.FAN_DIRECTION_NOT_APPLICABLE + if not os.path.exists(self.psu_fan_dir_path) or not self.get_presence(): + return self.FAN_DIRECTION_NOT_APPLICABLE + + return MlnxFan.get_fan_direction(self.psu_fan_dir_path) def get_status(self): """ @@ -263,7 +285,10 @@ def get_direction(self): 1 stands for forward, in other words intake 0 stands for reverse, in other words exhaust """ - return self.fan_drawer.get_direction() + if not isinstance(self.fan_drawer, VirtualDrawer): + return self.fan_drawer.get_direction() + else: + return MlnxFan.get_fan_direction(FAN_DIR.format(self.index)) def get_status(self): """ diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/fan_drawer.py b/platform/mellanox/mlnx-platform-api/sonic_platform/fan_drawer.py index 848abb04aca3..ee72357db198 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/fan_drawer.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/fan_drawer.py @@ -58,19 +58,8 @@ def get_direction(self): if not self.get_presence(): return FanBase.FAN_DIRECTION_NOT_APPLICABLE - try: - from .fan import FAN_DIR, FAN_DIR_VALUE_INTAKE, FAN_DIR_VALUE_EXHAUST - fan_dir = utils.read_int_from_file(FAN_DIR.format(self._index), raise_exception=True) - if fan_dir == FAN_DIR_VALUE_INTAKE: - return FanBase.FAN_DIRECTION_INTAKE - elif fan_dir == FAN_DIR_VALUE_EXHAUST: - return FanBase.FAN_DIRECTION_EXHAUST - else: - logger.log_error("Got wrong value {} for fan direction {}".format(fan_dir, self._index)) - return FanBase.FAN_DIRECTION_NOT_APPLICABLE - except (ValueError, IOError) as e: - logger.log_error("Failed to read fan direction status to {}".format(repr(e))) - return FanBase.FAN_DIRECTION_NOT_APPLICABLE + from .fan import FAN_DIR, MlnxFan + return MlnxFan.get_fan_direction(FAN_DIR.format(self._index)) def set_status_led(self, color): """ diff --git a/platform/mellanox/mlnx-platform-api/tests/test_fan_api.py b/platform/mellanox/mlnx-platform-api/tests/test_fan_api.py index 75d1cbe707fe..8f51ddb31681 100644 --- a/platform/mellanox/mlnx-platform-api/tests/test_fan_api.py +++ b/platform/mellanox/mlnx-platform-api/tests/test_fan_api.py @@ -25,7 +25,7 @@ sys.path.insert(0, modules_path) from sonic_platform import utils -from sonic_platform.fan import Fan, PsuFan +from sonic_platform.fan import Fan, PsuFan, FAN_DIR_VALUE_INTAKE, FAN_DIR_VALUE_EXHAUST from sonic_platform.fan_drawer import RealDrawer, VirtualDrawer from sonic_platform.psu import Psu @@ -107,11 +107,12 @@ def test_system_fan_set_speed(self, mock_write_file): fan.set_speed(60) mock_write_file.assert_called_with(fan.fan_speed_set_path, 153, raise_exception=True) + @patch('sonic_platform.utils.read_int_from_file') @patch('sonic_platform.thermal.Thermal.get_cooling_level') @patch('sonic_platform.psu.Psu.get_presence') @patch('sonic_platform.psu.Psu.get_powergood_status') @patch('os.path.exists') - def test_psu_fan_basic(self, mock_path_exists, mock_powergood, mock_presence, mock_cooling_level): + def test_psu_fan_basic(self, mock_path_exists, mock_powergood, mock_presence, mock_cooling_level, mock_read_int): mock_path_exists.return_value = False psu = Psu(0) fan = PsuFan(0, 1, psu) @@ -126,6 +127,12 @@ def test_psu_fan_basic(self, mock_path_exists, mock_powergood, mock_presence, mo assert fan.get_presence() is True mock_cooling_level.return_value = 7 assert fan.get_target_speed() == 70 + mock_read_int.return_value = FAN_DIR_VALUE_INTAKE + assert fan.get_direction() == Fan.FAN_DIRECTION_INTAKE + mock_read_int.return_value = FAN_DIR_VALUE_EXHAUST + assert fan.get_direction() == Fan.FAN_DIRECTION_EXHAUST + mock_read_int.return_value = -1 # invalid value + assert fan.get_direction() == Fan.FAN_DIRECTION_NOT_APPLICABLE def test_psu_fan_set_speed(self): psu = Psu(0)