From 37eb088b74ab37abdd06956cb5c5d63089d143df Mon Sep 17 00:00:00 2001 From: Junchao-Mellanox <57339448+Junchao-Mellanox@users.noreply.github.com> Date: Thu, 26 Nov 2020 16:09:48 +0800 Subject: [PATCH] [Mellanox] [201911] Fix issue: set fan led in certain order causes incorrect physical fan led color (#6019) * Fix issue: fan led colo status * Fix LGTM warning * Support fan led management for non-swapable fan --- .../mlnx-platform-api/sonic_platform/fan.py | 51 ++++++++++++++++--- .../mlnx-platform-api/sonic_platform/led.py | 51 +++++++++++++++++++ 2 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 platform/mellanox/mlnx-platform-api/sonic_platform/led.py diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/fan.py b/platform/mellanox/mlnx-platform-api/sonic_platform/fan.py index bd0487eb0e87..a6043da38e32 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/fan.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/fan.py @@ -13,6 +13,8 @@ try: from sonic_platform_base.fan_base import FanBase + + from .led import SharedLed, ComponentFaultyIndicator from .utils import read_int_from_file, read_str_from_file, write_file except ImportError as e: raise ImportError (str(e) + "- required module not found") @@ -33,6 +35,8 @@ # 1. don't have fanX_status and should be treated as always present platform_with_unplugable_fan = ['x86_64-mlnx_msn2010-r0', 'x86_64-mlnx_msn2100-r0'] +VIRTUAL_DRAWER_INDEX = 0 + class Fan(FanBase): """Platform-specific Fan class""" @@ -41,6 +45,10 @@ class Fan(FanBase): min_cooling_level = 2 MIN_VALID_COOLING_LEVEL = 1 MAX_VALID_COOLING_LEVEL = 10 + + # Fan drawer leds + fan_drawer_leds = {} + # PSU fan speed vector PSU_FAN_SPEED = ['0x3c', '0x3c', '0x3c', '0x3c', '0x3c', '0x3c', '0x3c', '0x46', '0x50', '0x5a', '0x64'] @@ -71,11 +79,31 @@ def __init__(self, has_fan_dir, fan_index, drawer_index = 1, psu_fan = False, pl self.psu_i2c_command_path = os.path.join(CONFIG_PATH, 'fan_command') self.fan_status_path = "fan{}_fault".format(self.index) - self.fan_green_led_path = "led_fan{}_green".format(self.drawer_index) - self.fan_red_led_path = "led_fan{}_red".format(self.drawer_index) - self.fan_orange_led_path = "led_fan{}_orange".format(self.drawer_index) - self.fan_pwm_path = "pwm1" - self.fan_led_cap_path = "led_fan{}_capability".format(self.drawer_index) + + if not self.is_psu_fan: # We don't support PSU led management in 201911 + if not self.always_presence: + if self.drawer_index not in Fan.fan_drawer_leds: + shared_led = SharedLed() + Fan.fan_drawer_leds[self.drawer_index] = shared_led + else: + shared_led = Fan.fan_drawer_leds[self.drawer_index] + self.fan_green_led_path = "led_fan{}_green".format(self.drawer_index) + self.fan_red_led_path = "led_fan{}_red".format(self.drawer_index) + self.fan_orange_led_path = "led_fan{}_orange".format(self.drawer_index) + self.fan_led_cap_path = "led_fan{}_capability".format(self.drawer_index) + else: # For 2010/2100, all fans share one LED + if VIRTUAL_DRAWER_INDEX not in Fan.fan_drawer_leds: + shared_led = SharedLed() + Fan.fan_drawer_leds[VIRTUAL_DRAWER_INDEX] = shared_led + else: + shared_led = Fan.fan_drawer_leds[VIRTUAL_DRAWER_INDEX] + self.fan_green_led_path = "led_fan_green" + self.fan_red_led_path = "led_fan_red" + self.fan_orange_led_path = "led_fan_orange" + self.fan_led_cap_path = "led_fan_capability" + + self.fault_indicator = ComponentFaultyIndicator(shared_led) + if has_fan_dir: self.fan_dir = FAN_DIR else: @@ -250,6 +278,16 @@ def _get_led_capability(self): return cap_list def set_status_led(self, color): + if self.is_psu_fan: + return False + self.fault_indicator.set_status(color) + if not self.always_presence: + target_color = Fan.fan_drawer_leds[self.drawer_index].get_status() + else: + target_color = Fan.fan_drawer_leds[VIRTUAL_DRAWER_INDEX].get_status() + return self._set_status_led(target_color) + + def _set_status_led(self, color): """ Set led to expected color @@ -264,9 +302,6 @@ def set_status_led(self, color): if led_cap_list is None: return False - if self.is_psu_fan: - # PSU fan led status is not able to set - return False status = False try: if color == 'green': diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/led.py b/platform/mellanox/mlnx-platform-api/sonic_platform/led.py new file mode 100644 index 000000000000..ef39dfcfb415 --- /dev/null +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/led.py @@ -0,0 +1,51 @@ +class Led(object): + STATUS_LED_COLOR_GREEN = 'green' + STATUS_LED_COLOR_GREEN_BLINK = 'green_blink' + STATUS_LED_COLOR_RED = 'red' + STATUS_LED_COLOR_RED_BLINK = 'red_blink' + STATUS_LED_COLOR_ORANGE = 'orange' + STATUS_LED_COLOR_ORANGE_BLINK = 'orange_blink' + STATUS_LED_COLOR_OFF = 'off' + + +class SharedLed(object): + LED_PRIORITY = { + Led.STATUS_LED_COLOR_RED: 0, + Led.STATUS_LED_COLOR_GREEN: 1 + } + + def __init__(self): + self._virtual_leds = [] + self._target_color = Led.STATUS_LED_COLOR_GREEN + + def add_virtual_leds(self, led): + self._virtual_leds.append(led) + + def update_status_led(self): + target_color = Led.STATUS_LED_COLOR_GREEN + for virtual_led in self._virtual_leds: + if SharedLed.LED_PRIORITY[virtual_led.get_led_color()] < SharedLed.LED_PRIORITY[target_color]: + target_color = virtual_led.get_led_color() + + self._target_color = target_color + return True + + def get_status(self): + return self._target_color + + +class ComponentFaultyIndicator(object): + def __init__(self, shared_led): + self._color = Led.STATUS_LED_COLOR_GREEN + self._shared_led = shared_led + self._shared_led.add_virtual_leds(self) + + def set_status(self, color): + self._color = color + return self._shared_led.update_status_led() + + def get_led_color(self): + return self._color + + def get_status(self): + return self._shared_led.get_status()