From 2e5e6b2e514fb99a2b75b43bb8cef8999abc11b5 Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Wed, 31 Jul 2019 12:21:40 +0300 Subject: [PATCH 01/13] [sonic_platform.sfp] 1. don't get all output of ethtool -m sfpx when testing whether sfp is present. only fetch the first 4 bytes is enough since the purpose here is to test whether the reading operation success rather than to get the data. this is a time-saving optimize. 2. test whether sfp module present ahead of getting its capabilities, which avoid the error msg "Cannot get module EEPROM information: Input/output error" from logging. 3. fix the get_transceiver_bulk_status's issue which returns None when failed to fetch dom data. this issue will fail snmp test. 4. pass caibration to sff8472Dom. --- .../mlnx-platform-api/sonic_platform/sfp.py | 87 ++++++++----------- 1 file changed, 34 insertions(+), 53 deletions(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py index 9ea9c21899f5..cf9fbf7b5a9e 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py @@ -229,7 +229,7 @@ def get_presence(self): bool: True if device is present, False if not """ presence = False - ethtool_cmd = "ethtool -m sfp{} 2>/dev/null".format(self.index) + ethtool_cmd = "ethtool -m sfp{} hex on offset 0 length 4 2>/dev/null".format(self.index) try: proc = subprocess.Popen(ethtool_cmd, stdout=subprocess.PIPE, shell=True, stderr=subprocess.STDOUT) stdout = proc.communicate()[0] @@ -261,6 +261,15 @@ def _read_eeprom_specific_bytes(self, offset, num_bytes): return eeprom_raw def _dom_capability_detect(self): + if not self.get_presence(): + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + if self.sfp_type == "QSFP": self.calibration = 1 sfpi_obj = sff8436InterfaceId() @@ -578,30 +587,27 @@ def get_transceiver_bulk_status(self): """ transceiver_dom_info_dict = {} + dom_info_dict_keys = ['temperature', 'voltage', + 'rx1power', 'rx2power', + 'rx3power', 'rx4power', + 'tx1bias', 'tx2bias', + 'tx3bias', 'tx4bias', + 'tx1power', 'tx2power', + 'tx3power', 'tx4power' + ] + transceiver_dom_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A') + if self.sfp_type == OSFP_TYPE: - transceiver_dom_info_dict['temperature'] = 'N/A' - transceiver_dom_info_dict['voltage'] = 'N/A' - transceiver_dom_info_dict['rx1power'] = 'N/A' - transceiver_dom_info_dict['rx2power'] = 'N/A' - transceiver_dom_info_dict['rx3power'] = 'N/A' - transceiver_dom_info_dict['rx4power'] = 'N/A' - transceiver_dom_info_dict['tx1bias'] = 'N/A' - transceiver_dom_info_dict['tx2bias'] = 'N/A' - transceiver_dom_info_dict['tx3bias'] = 'N/A' - transceiver_dom_info_dict['tx4bias'] = 'N/A' - transceiver_dom_info_dict['tx1power'] = 'N/A' - transceiver_dom_info_dict['tx2power'] = 'N/A' - transceiver_dom_info_dict['tx3power'] = 'N/A' - transceiver_dom_info_dict['tx4power'] = 'N/A' + pass elif self.sfp_type == QSFP_TYPE: if not self.dom_supported: - return None + return transceiver_dom_info_dict offset = 0 sfpd_obj = sff8436Dom() if sfpd_obj is None: - return None + return transceiver_dom_info_dict if self.dom_temp_supported: dom_temperature_raw = self._read_eeprom_specific_bytes((offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) @@ -610,12 +616,8 @@ def get_transceiver_bulk_status(self): temp = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) if temp is not None: transceiver_dom_info_dict['temperature'] = temp - else: - transceiver_dom_info_dict['temperature'] = 'N/A' else: - return None - else: - transceiver_dom_info_dict['temperature'] = 'N/A' + return transceiver_dom_info_dict if self.dom_volt_supported: dom_voltage_raw = self._read_eeprom_specific_bytes((offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) @@ -624,38 +626,26 @@ def get_transceiver_bulk_status(self): volt = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) if volt is not None: transceiver_dom_info_dict['voltage'] = volt - else: - transceiver_dom_info_dict['voltage'] = 'N/A' else: - return None - else: - transceiver_dom_info_dict['voltage'] = 'N/A' + return transceiver_dom_info_dict dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) if dom_channel_monitor_raw is not None: dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + else: + return transceiver_dom_info_dict if self.dom_tx_power_supported: transceiver_dom_info_dict['tx1power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TX1Power']['value']) transceiver_dom_info_dict['tx2power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TX2Power']['value']) transceiver_dom_info_dict['tx3power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TX3Power']['value']) transceiver_dom_info_dict['tx4power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TX4Power']['value']) - else: - transceiver_dom_info_dict['tx1power'] = 'N/A' - transceiver_dom_info_dict['tx2power'] = 'N/A' - transceiver_dom_info_dict['tx3power'] = 'N/A' - transceiver_dom_info_dict['tx4power'] = 'N/A' if self.dom_rx_power_supported: transceiver_dom_info_dict['rx1power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RX1Power']['value']) transceiver_dom_info_dict['rx2power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RX2Power']['value']) transceiver_dom_info_dict['rx3power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RX3Power']['value']) transceiver_dom_info_dict['rx4power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RX4Power']['value']) - else: - transceiver_dom_info_dict['rx1power'] = 'N/A' - transceiver_dom_info_dict['rx2power'] = 'N/A' - transceiver_dom_info_dict['rx3power'] = 'N/A' - transceiver_dom_info_dict['rx4power'] = 'N/A' transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] @@ -664,46 +654,37 @@ def get_transceiver_bulk_status(self): else: if not self.dom_supported: - return None + return transceiver_dom_info_dict offset = 256 sfpd_obj = sff8472Dom() if sfpd_obj is None: - return None + return transceiver_dom_info_dict sfpd_obj._calibration_type = self.calibration dom_temperature_raw = self._read_eeprom_specific_bytes((offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) if dom_temperature_raw is not None: dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) else: - return None + return transceiver_dom_info_dict dom_voltage_raw = self._read_eeprom_specific_bytes((offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) if dom_voltage_raw is not None: dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) else: - return None + return transceiver_dom_info_dict dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) if dom_channel_monitor_raw is not None: dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) else: - return None + return transceiver_dom_info_dict transceiver_dom_info_dict['temperature'] = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) transceiver_dom_info_dict['voltage'] = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) transceiver_dom_info_dict['rx1power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RXPower']['value']) - transceiver_dom_info_dict['rx2power'] = 'N/A' - transceiver_dom_info_dict['rx3power'] = 'N/A' - transceiver_dom_info_dict['rx4power'] = 'N/A' transceiver_dom_info_dict['tx1bias'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TXBias']['value']) - transceiver_dom_info_dict['tx2bias'] = 'N/A' - transceiver_dom_info_dict['tx3bias'] = 'N/A' - transceiver_dom_info_dict['tx4bias'] = 'N/A' transceiver_dom_info_dict['tx1power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TXPower']['value']) - transceiver_dom_info_dict['tx2power'] = 'N/A' - transceiver_dom_info_dict['tx3power'] = 'N/A' - transceiver_dom_info_dict['tx4power'] = 'N/A' return transceiver_dom_info_dict @@ -1036,7 +1017,7 @@ def get_tx_bias(self): sfpd_obj = sff8472Dom() if sfpd_obj is None: return None - sfpd_obj._calibration_type = 1 + sfpd_obj._calibration_type = self.calibration if self.dom_supported: dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) @@ -1145,7 +1126,7 @@ def get_tx_power(self): return None if self.dom_supported: - sfpd_obj._calibration_type = 1 + sfpd_obj._calibration_type = self.calibration dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) if dom_channel_monitor_raw is not None: From c63b46e6bf582503b7f5f765f76ddd2c623092f6 Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Wed, 31 Jul 2019 12:58:20 +0300 Subject: [PATCH 02/13] [sonic_platform.chassis] initialize watchdog only when referenced. At any time only one daemon have priviledge of accessing watchdog device. To try accessing it from multiple daemons causes the latter ones fail and exit. --- .../sonic_platform/chassis.py | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index 41d237143d58..7915f504bd34 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -90,7 +90,7 @@ def __init__(self): self._psu_list.append(psu) # Initialize watchdog - self._watchdog = get_watchdog() + self._watchdog = None # Initialize FAN list multi_rotor_in_drawer = False @@ -163,6 +163,29 @@ def _get_port_position_tuple_by_sku_name(self): position_tuple = port_position_tuple_list[hwsku_dict_port[self.sku_name]] return position_tuple + def get_watchdog(self): + """ + Retreives hardware watchdog device on this chassis + + Returns: + An object derived from WatchdogBase representing the hardware + watchdog device + + Note: + We overload this method to ensure that watchdog is only initialized + when it is referenced. Currently, only one daemon can open the watchdog. + To initialize watchdog in the constructor causes multiple daemon + try opening watchdog when loading and constructing a chassis object + and fail. By doing so we can eliminate that risk. + """ + try: + if self._watchdog is None: + self._watchdog = get_watchdog() + except Exception as e: + logger.log_info("Fail to load watchdog due to {}".format(repr(e))) + + return self._watchdog + def get_base_mac(self): """ Retrieves the base MAC address for the chassis From f826ac7625ed436b652368cef849d2ee00f6c0bc Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Sun, 4 Aug 2019 16:34:32 +0300 Subject: [PATCH 03/13] [sonic_platform.chassis] optimize chassis's initialization by 1. removing iniaializations of varient components out from constructor and providing one initializer for each. 2. only import other modules when initializing it. by doing so, initializing time is reduced and unnecessary dependencies of chassis is removed for daemons who don't need them. --- .../sonic_platform/chassis.py | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index 7915f504bd34..9c5aaa8dfa9e 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -10,15 +10,7 @@ try: from sonic_platform_base.chassis_base import ChassisBase - from sonic_platform.psu import Psu - from sonic_platform.fan import Fan - from sonic_platform.fan import FAN_PATH - from sonic_platform.sfp import SFP - from sonic_platform.thermal import Thermal, initialize_thermals - from sonic_platform.watchdog import get_watchdog from sonic_daemon_base.daemon_base import Logger - from eeprom import Eeprom - from sfp_event import sfp_event from os import listdir from os.path import isfile, join import sys @@ -84,14 +76,22 @@ def __init__(self): # Initialize SKU name self.sku_name = self._get_sku_name() + # move the initialization of each components to their dedicated initializer + # which will be called from platform + + def initialize_psu(self): + from sonic_platform.psu import Psu # Initialize PSU list + self.psu_module = Psu for index in range(MLNX_NUM_PSU): psu = Psu(index, self.sku_name) self._psu_list.append(psu) - # Initialize watchdog - self._watchdog = None - + def initialize_fan(self): + from sonic_platform.fan import Fan + from sonic_platform.fan import FAN_PATH + self.fan_module = Fan + self.fan_path = FAN_PATH # Initialize FAN list multi_rotor_in_drawer = False num_of_fan, num_of_drawer = self._extract_num_of_fans_and_fan_drawers() @@ -104,6 +104,9 @@ def __init__(self): fan = Fan(index, index) self._fan_list.append(fan) + def initialize_sfp(self): + from sonic_platform.sfp import SFP + self.sfp_module = SFP # Initialize SFP list port_position_tuple = self._get_port_position_tuple_by_sku_name() self.PORT_START = port_position_tuple[0] @@ -118,12 +121,17 @@ def __init__(self): sfp_module = SFP(index, 'SFP') self._sfp_list.append(sfp_module) + def initialize_thermals(self): + from sonic_platform.thermal import initialize_thermals # Initialize thermals initialize_thermals(self.sku_name, self._thermal_list, self._psu_list) + def initialize_eeprom(self): + from eeprom import Eeprom # Initialize EEPROM self.eeprom = Eeprom() + def initialize_components_list(self): # Initialize component list self._component_name_list.append(COMPONENT_BIOS) self._component_name_list.append(COMPONENT_FIRMWARE) @@ -141,8 +149,8 @@ def _init_sfp_change_event(self): def _extract_num_of_fans_and_fan_drawers(self): num_of_fan = 0 num_of_drawer = 0 - for f in listdir(FAN_PATH): - if isfile(join(FAN_PATH, f)): + for f in listdir(self.fan_path): + if isfile(join(self.fan_path, f)): match_obj = re.match('fan(\d+)_speed_get', f) if match_obj != None: if int(match_obj.group(1)) > num_of_fan: @@ -180,6 +188,7 @@ def get_watchdog(self): """ try: if self._watchdog is None: + from sonic_platform.watchdog import get_watchdog self._watchdog = get_watchdog() except Exception as e: logger.log_info("Fail to load watchdog due to {}".format(repr(e))) From d8c2105b0bdf6504bb80ed69879ec899044c728f Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Sun, 4 Aug 2019 17:10:50 +0300 Subject: [PATCH 04/13] [sonic_platform.chassis] update self.eeprom to self._eeprom in order to be better aligned with base class --- .../mellanox/mlnx-platform-api/sonic_platform/chassis.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index 9c5aaa8dfa9e..5043dc11fb5b 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -129,7 +129,7 @@ def initialize_thermals(self): def initialize_eeprom(self): from eeprom import Eeprom # Initialize EEPROM - self.eeprom = Eeprom() + self._eeprom = Eeprom() def initialize_components_list(self): # Initialize component list @@ -203,7 +203,7 @@ def get_base_mac(self): A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ - return self.eeprom.get_base_mac() + return self._eeprom.get_base_mac() def get_serial_number(self): """ @@ -212,7 +212,7 @@ def get_serial_number(self): Returns: A string containing the hardware serial number for this chassis. """ - return self.eeprom.get_serial_number() + return self._eeprom.get_serial_number() def get_system_eeprom_info(self): """ @@ -223,7 +223,7 @@ def get_system_eeprom_info(self): OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ - return self.eeprom.get_system_eeprom_info() + return self._eeprom.get_system_eeprom_info() def _read_generic_file(self, filename, len): """ From 71e675163688a3b5d3afca83162d0fe848662b8c Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Mon, 5 Aug 2019 01:42:12 +0300 Subject: [PATCH 05/13] [sonic_platform.chassis] add initialization for sfp_event --- .../mlnx-platform-api/sonic_platform/chassis.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index 5043dc11fb5b..c60e03f1e4a1 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -106,7 +106,9 @@ def initialize_fan(self): def initialize_sfp(self): from sonic_platform.sfp import SFP + from sonic_platform.sfp_event import sfp_event self.sfp_module = SFP + # Initialize SFP list port_position_tuple = self._get_port_position_tuple_by_sku_name() self.PORT_START = port_position_tuple[0] @@ -121,6 +123,11 @@ def initialize_sfp(self): sfp_module = SFP(index, 'SFP') self._sfp_list.append(sfp_module) + # Initialize SFP event + self.sfp_event = sfp_event() + self.sfp_event.initialize() + self.MAX_SELECT_EVENT_RETURNED = self.PORT_END + def initialize_thermals(self): from sonic_platform.thermal import initialize_thermals # Initialize thermals @@ -138,14 +145,6 @@ def initialize_components_list(self): self._component_name_list.append(COMPONENT_CPLD1) self._component_name_list.append(COMPONENT_CPLD2) - # Initialize sfp-change-listening stuff - self._init_sfp_change_event() - - def _init_sfp_change_event(self): - self.sfp_event = sfp_event() - self.sfp_event.initialize() - self.MAX_SELECT_EVENT_RETURNED = self.PORT_END - def _extract_num_of_fans_and_fan_drawers(self): num_of_fan = 0 num_of_drawer = 0 From 9f081c5721ed9fe1fa00f3f5f1ad9bff7fe75b9e Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Mon, 5 Aug 2019 02:11:56 +0300 Subject: [PATCH 06/13] [sonic_platform] optimize initialization. 1. add platform.py 2. update __init__.py so that sonic_platform can be loaded as a whole --- .../sonic_platform/__init__.py | 2 + .../sonic_platform/platform.py | 39 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 platform/mellanox/mlnx-platform-api/sonic_platform/platform.py diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/__init__.py b/platform/mellanox/mlnx-platform-api/sonic_platform/__init__.py index e69de29bb2d1..d94d4c9ec820 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/__init__.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = ["platform", "chassis"] +from sonic_platform import * \ No newline at end of file diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/platform.py b/platform/mellanox/mlnx-platform-api/sonic_platform/platform.py new file mode 100644 index 000000000000..3c0de6b91f4b --- /dev/null +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/platform.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +############################################################################# +# Mellanox +# +# implementation of new platform api +############################################################################# + +try: + import subprocess + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Platform(PlatformBase): + def __init__(self): + PlatformBase.__init__(self) + if self._is_host(): + self._chassis = Chassis() + else: + self._chassis = Chassis() + self._chassis.initialize_psu() + self._chassis.initialize_fan() + self._chassis.initialize_sfp() + self._chassis.initialize_eeprom() + self._chassis.initialize_components_list() + + def _is_host(self): + """ + Test whether current process is running on the host or an docker + return True for host and False for docker + """ + try: + subprocess.Popen("docker") + except OSError, e: + return False + + return True From 5f7cbecbe418f1420dc5769ce63958f082ae80ef Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Thu, 8 Aug 2019 14:02:59 +0300 Subject: [PATCH 07/13] [sonic_platform.chassis]improve reboot-cause support --- .../mellanox/mlnx-platform-api/sonic_platform/chassis.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index c60e03f1e4a1..1db7f1343e69 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -36,9 +36,12 @@ REBOOT_CAUSE_ROOT = HWMGMT_SYSTEM_ROOT REBOOT_CAUSE_POWER_LOSS_FILE = 'reset_main_pwr_fail' +REBOOT_CAUSE_AUX_POWER_LOSS_FILE = 'reset_aux_pwr_or_ref' REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC_FILE = 'reset_asic_thermal' REBOOT_CAUSE_WATCHDOG_FILE = 'reset_hotswap_or_wd' REBOOT_CAUSE_MLNX_FIRMWARE_RESET = 'reset_fw_reset' +REBOOT_CAUSE_LONG_PB = 'reset_long_pb' +REBOOT_CAUSE_SHORT_PB = 'reset_short_pb' REBOOT_CAUSE_FILE_LENGTH = 1 @@ -261,6 +264,8 @@ def get_reboot_cause(self): minor_cause = '' if self._verify_reboot_cause(REBOOT_CAUSE_POWER_LOSS_FILE): major_cause = self.REBOOT_CAUSE_POWER_LOSS + elif self._verify_reboot_cause(REBOOT_CAUSE_AUX_POWER_LOSS_FILE): + major_cause = self.REBOOT_CAUSE_POWER_LOSS elif self._verify_reboot_cause(REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC_FILE): major_cause = self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC elif self._verify_reboot_cause(REBOOT_CAUSE_WATCHDOG_FILE): @@ -269,6 +274,10 @@ def get_reboot_cause(self): major_cause = self.REBOOT_CAUSE_HARDWARE_OTHER if self._verify_reboot_cause(REBOOT_CAUSE_MLNX_FIRMWARE_RESET): minor_cause = "Reset by ASIC firmware" + elif self._verify_reboot_cause(REBOOT_CAUSE_LONG_PB): + minor_cause = "Reset by long press on power button" + elif self._verify_reboot_cause(REBOOT_CAUSE_SHORT_PB): + minor_cause = "Reset by short press on power button" else: major_cause = self.REBOOT_CAUSE_NON_HARDWARE From 3f48f0544c21cc1d916b2f372887a9072668ad4b Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Sat, 10 Aug 2019 05:59:38 +0300 Subject: [PATCH 08/13] [sonic_platform.platform] improve the logic of determining whether it is running on host or docker --- .../mlnx-platform-api/sonic_platform/platform.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/platform.py b/platform/mellanox/mlnx-platform-api/sonic_platform/platform.py index 3c0de6b91f4b..1be4848bdb53 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/platform.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/platform.py @@ -31,9 +31,16 @@ def _is_host(self): Test whether current process is running on the host or an docker return True for host and False for docker """ + is_host = False try: - subprocess.Popen("docker") + proc = subprocess.Popen("docker --version 2>/dev/null", stdout=subprocess.PIPE, shell=True, stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + result = stdout.rstrip('\n') + if result != '': + is_host = True + except OSError, e: - return False + pass - return True + return is_host From 3fdff1f91029d2217cb17bc1192c50d850a8cffb Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Thu, 22 Aug 2019 09:07:13 +0300 Subject: [PATCH 09/13] [sonic_platform]only initialize sfp modules when related apis are called --- .../sonic_platform/chassis.py | 54 +++++++++++++++++++ .../sonic_platform/platform.py | 1 - 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index 1db7f1343e69..c9ab66bb6425 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -81,6 +81,8 @@ def __init__(self): # move the initialization of each components to their dedicated initializer # which will be called from platform + self.sfp_module = None + logger.log_info("Chassis loaded successfully") def initialize_psu(self): from sonic_platform.psu import Psu @@ -148,6 +150,58 @@ def initialize_components_list(self): self._component_name_list.append(COMPONENT_CPLD1) self._component_name_list.append(COMPONENT_CPLD2) + ############################################## + # SFP methods + ############################################## + def get_num_sfps(self): + """ + Retrieves the number of sfps available on this chassis + + Returns: + An integer, the number of sfps available on this chassis + """ + if self.sfp_module is None: + self.initialize_sfp() + return len(self._sfp_list) + + def get_all_sfps(self): + """ + Retrieves all sfps available on this chassis + + Returns: + A list of objects derived from SfpBase representing all sfps + available on this chassis + """ + if self.sfp_module is None: + self.initialize_sfp() + return self._sfp_list + + def get_sfp(self, index): + """ + Retrieves sfp represented by (0-based) index + + Args: + index: An integer, the index (0-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 0. + For example, 0 for Ethernet0, 1 for Ethernet4 and so on. + + Returns: + An object dervied from SfpBase representing the specified sfp + """ + if self.sfp_module is None: + self.initialize_sfp() + + sfp = None + + try: + sfp = self._sfp_list[index] + except IndexError: + sys.stderr.write("SFP index {} out of range (0-{})\n".format( + index, len(self._sfp_list)-1)) + + return sfp + def _extract_num_of_fans_and_fan_drawers(self): num_of_fan = 0 num_of_drawer = 0 diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/platform.py b/platform/mellanox/mlnx-platform-api/sonic_platform/platform.py index 1be4848bdb53..fc555bc479a3 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/platform.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/platform.py @@ -22,7 +22,6 @@ def __init__(self): self._chassis = Chassis() self._chassis.initialize_psu() self._chassis.initialize_fan() - self._chassis.initialize_sfp() self._chassis.initialize_eeprom() self._chassis.initialize_components_list() From e8177b5493fd7e8b7dc67164d1e6d31e0a090089 Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Thu, 22 Aug 2019 13:50:34 +0300 Subject: [PATCH 10/13] [sonic_platform]chassis: refractor reboot cause handling. using a dictionary to handle reboot cause --- .../sonic_platform/chassis.py | 67 +++++++++++-------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index c9ab66bb6425..70cf725b894c 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -35,14 +35,6 @@ #reboot cause related definitions REBOOT_CAUSE_ROOT = HWMGMT_SYSTEM_ROOT -REBOOT_CAUSE_POWER_LOSS_FILE = 'reset_main_pwr_fail' -REBOOT_CAUSE_AUX_POWER_LOSS_FILE = 'reset_aux_pwr_or_ref' -REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC_FILE = 'reset_asic_thermal' -REBOOT_CAUSE_WATCHDOG_FILE = 'reset_hotswap_or_wd' -REBOOT_CAUSE_MLNX_FIRMWARE_RESET = 'reset_fw_reset' -REBOOT_CAUSE_LONG_PB = 'reset_long_pb' -REBOOT_CAUSE_SHORT_PB = 'reset_short_pb' - REBOOT_CAUSE_FILE_LENGTH = 1 #version retrieving related definitions @@ -82,6 +74,7 @@ def __init__(self): # move the initialization of each components to their dedicated initializer # which will be called from platform self.sfp_module = None + self.reboot_cause_initialized = False logger.log_info("Chassis loaded successfully") def initialize_psu(self): @@ -293,7 +286,7 @@ def _read_generic_file(self, filename, len): return result except Exception as e: logger.log_info("Fail to read file {} due to {}".format(filename, repr(e))) - return '' + return '0' def _verify_reboot_cause(self, filename): ''' @@ -303,6 +296,31 @@ def _verify_reboot_cause(self, filename): ''' return bool(int(self._read_generic_file(join(REBOOT_CAUSE_ROOT, filename), REBOOT_CAUSE_FILE_LENGTH).rstrip('\n'))) + def initialize_reboot_cause(self): + self.reboot_major_cause_dict = { + 'reset_main_pwr_fail' : self.REBOOT_CAUSE_POWER_LOSS, + 'reset_aux_pwr_or_ref' : self.REBOOT_CAUSE_POWER_LOSS, + 'reset_asic_thermal' : self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC, + 'reset_hotswap_or_wd' : self.REBOOT_CAUSE_WATCHDOG, + 'reset_swb_wd' : self.REBOOT_CAUSE_WATCHDOG, + 'reset_sff_wd' : self.REBOOT_CAUSE_WATCHDOG + } + self.reboot_minor_cause_dict = { + 'reset_fw_reset' : "Reset by ASIC firmware", + 'reset_long_pb' : "Reset by long press on power button", + 'reset_short_pb' : "Reset by short press on power button", + 'reset_comex_thermal' : "ComEx thermal shutdown", + 'reset_comex_pwr_fail' : "ComEx power fail", + 'reset_comex_wd' : "Reset requested from ComEx", + 'reset_from_asic' : "Reset requested from ASIC", + 'reset_reload_bios' : "Reset caused by BIOS reload", + 'reset_sw_reset' : "Software reset", + 'reset_hotswap_or_halt' : "Reset caused by hotswap or halt", + 'reset_from_comex' : "Reset from ComEx", + 'reset_voltmon_upgrade_fail': "Reset due to voltage monitor devices upgrade failure" + } + self.reboot_cause_initialized = True + def get_reboot_cause(self): """ Retrieves the cause of the previous reboot @@ -315,27 +333,18 @@ def get_reboot_cause(self): to pass a description of the reboot cause. """ #read reboot causes files in the following order - minor_cause = '' - if self._verify_reboot_cause(REBOOT_CAUSE_POWER_LOSS_FILE): - major_cause = self.REBOOT_CAUSE_POWER_LOSS - elif self._verify_reboot_cause(REBOOT_CAUSE_AUX_POWER_LOSS_FILE): - major_cause = self.REBOOT_CAUSE_POWER_LOSS - elif self._verify_reboot_cause(REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC_FILE): - major_cause = self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC - elif self._verify_reboot_cause(REBOOT_CAUSE_WATCHDOG_FILE): - major_cause = self.REBOOT_CAUSE_WATCHDOG - else: - major_cause = self.REBOOT_CAUSE_HARDWARE_OTHER - if self._verify_reboot_cause(REBOOT_CAUSE_MLNX_FIRMWARE_RESET): - minor_cause = "Reset by ASIC firmware" - elif self._verify_reboot_cause(REBOOT_CAUSE_LONG_PB): - minor_cause = "Reset by long press on power button" - elif self._verify_reboot_cause(REBOOT_CAUSE_SHORT_PB): - minor_cause = "Reset by short press on power button" - else: - major_cause = self.REBOOT_CAUSE_NON_HARDWARE + if not self.reboot_cause_initialized: + self.initialize_reboot_cause() + + for reset_file, reset_cause in self.reboot_major_cause_dict.iteritems(): + if self._verify_reboot_cause(reset_file): + return reset_cause, '' + + for reset_file, reset_cause in self.reboot_minor_cause_dict.iteritems(): + if self._verify_reboot_cause(reset_file): + return self.REBOOT_CAUSE_HARDWARE_OTHER, reset_cause - return major_cause, minor_cause + return self.REBOOT_CAUSE_NON_HARDWARE, '' def _get_cpld_version(self, version_file): cpld_version = self._read_generic_file(join(CPLD_VERSION_ROOT, version_file), CPLD_VERSION_MAX_LENGTH) From 39b79c283aa0f70a360991f15cc66f8bc63148cf Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Fri, 23 Aug 2019 04:53:27 +0300 Subject: [PATCH 11/13] [sonic_platform] sfp: optimizing eeprom data read by combining multiple call to ethtool into one --- .../mlnx-platform-api/sonic_platform/sfp.py | 144 +++++++++--------- 1 file changed, 73 insertions(+), 71 deletions(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py index cf9fbf7b5a9e..2d5c7887df64 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py @@ -63,6 +63,24 @@ XCVR_VENDOR_DATE_WIDTH = 8 XCVR_DOM_CAPABILITY_OFFSET = 92 XCVR_DOM_CAPABILITY_WIDTH = 2 +# to improve performance we retrieve all eeprom data via a single ethtool command +# in function get_transceiver_info and get_transceiver_bulk_status +# XCVR_INTERFACE_DATA_SIZE stands for the max size to be read +# this variable is only used by get_transceiver_info. +# be attention that each time some new value added to the function +# we should make sure that it falls into the area +# [XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE] or +# adjust XCVR_INTERFACE_MAX_SIZE to contain the new data +# It's same for [QSFP_DOM_BULK_DATA_START, QSFP_DOM_BULK_DATA_SIZE] and +# [SFP_DOM_BULK_DATA_START, SFP_DOM_BULK_DATA_SIZE] which are used by +# get_transceiver_bulk_status +XCVR_INTERFACE_DATA_START = 0 +XCVR_INTERFACE_DATA_SIZE = 92 + +QSFP_DOM_BULK_DATA_START = 22 +QSFP_DOM_BULK_DATA_SIZE = 36 +SFP_DOM_BULK_DATA_START = 96 +SFP_DOM_BULK_DATA_SIZE = 10 # definitions of the offset for values in OSFP info eeprom OSFP_TYPE_OFFSET = 0 @@ -475,47 +493,37 @@ def get_transceiver_info(self): print("Error: sfp_object open failed") return None - sfp_interface_bulk_raw = self._read_eeprom_specific_bytes((offset + XCVR_INTFACE_BULK_OFFSET), interface_info_bulk_width) - if sfp_interface_bulk_raw is not None: - sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(sfp_interface_bulk_raw, 0) - else: + sfp_interface_bulk_raw = self._read_eeprom_specific_bytes(offset + XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE) + if sfp_interface_bulk_raw is None: return None - sfp_vendor_name_raw = self._read_eeprom_specific_bytes((offset + XCVR_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) - if sfp_vendor_name_raw is not None: - sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_vendor_name_raw, 0) - else: - return None + start = XCVR_INTFACE_BULK_OFFSET - XCVR_INTERFACE_DATA_START + end = start + interface_info_bulk_width + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(sfp_interface_bulk_raw[start : end], 0) - sfp_vendor_pn_raw = self._read_eeprom_specific_bytes((offset + XCVR_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) - if sfp_vendor_pn_raw is not None: - sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_vendor_pn_raw, 0) - else: - return None + start = XCVR_VENDOR_NAME_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_NAME_WIDTH + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_interface_bulk_raw[start : end], 0) - sfp_vendor_rev_raw = self._read_eeprom_specific_bytes((offset + XCVR_HW_REV_OFFSET), vendor_rev_width) - if sfp_vendor_rev_raw is not None: - sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_vendor_rev_raw, 0) - else: - return None + start = XCVR_VENDOR_PN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_PN_WIDTH + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_interface_bulk_raw[start : end], 0) - sfp_vendor_sn_raw = self._read_eeprom_specific_bytes((offset + XCVR_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) - if sfp_vendor_sn_raw is not None: - sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_vendor_sn_raw, 0) - else: - return None + start = XCVR_HW_REV_OFFSET - XCVR_INTERFACE_DATA_START + end = start + vendor_rev_width + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_interface_bulk_raw[start : end], 0) - sfp_vendor_oui_raw = self._read_eeprom_specific_bytes((offset + XCVR_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH) - if sfp_vendor_oui_raw is not None: - sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(sfp_vendor_oui_raw, 0) - else: - return None + start = XCVR_VENDOR_SN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_SN_WIDTH + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_interface_bulk_raw[start : end], 0) - sfp_vendor_date_raw = self._read_eeprom_specific_bytes((offset + XCVR_VENDOR_DATE_OFFSET), XCVR_VENDOR_DATE_WIDTH) - if sfp_vendor_date_raw is not None: - sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_vendor_date_raw, 0) - else: - return None + start = XCVR_VENDOR_OUI_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_OUI_WIDTH + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_DATE_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_DATE_WIDTH + sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_interface_bulk_raw[start : end], 0) transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] transceiver_info_dict['manufacturename'] = sfp_vendor_name_data['data']['Vendor Name']['value'] @@ -609,31 +617,29 @@ def get_transceiver_bulk_status(self): if sfpd_obj is None: return transceiver_dom_info_dict + dom_data_raw = self._read_eeprom_specific_bytes((offset + QSFP_DOM_BULK_DATA_START), QSFP_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + if self.dom_temp_supported: - dom_temperature_raw = self._read_eeprom_specific_bytes((offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) - if dom_temperature_raw is not None: - dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) - temp = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) - if temp is not None: - transceiver_dom_info_dict['temperature'] = temp - else: - return transceiver_dom_info_dict + start = QSFP_TEMPE_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature(dom_data_raw[start : end], 0) + temp = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) + if temp is not None: + transceiver_dom_info_dict['temperature'] = temp if self.dom_volt_supported: - dom_voltage_raw = self._read_eeprom_specific_bytes((offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) - if dom_voltage_raw is not None: - dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) - volt = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) - if volt is not None: - transceiver_dom_info_dict['voltage'] = volt - else: - return transceiver_dom_info_dict + start = QSFP_VOLT_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage(dom_data_raw[start : end], 0) + volt = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) + if volt is not None: + transceiver_dom_info_dict['voltage'] = volt - dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) - if dom_channel_monitor_raw is not None: - dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) - else: - return transceiver_dom_info_dict + start = QSFP_CHANNL_MON_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_data_raw[start : end], 0) if self.dom_tx_power_supported: transceiver_dom_info_dict['tx1power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TX1Power']['value']) @@ -661,24 +667,20 @@ def get_transceiver_bulk_status(self): if sfpd_obj is None: return transceiver_dom_info_dict sfpd_obj._calibration_type = self.calibration - - dom_temperature_raw = self._read_eeprom_specific_bytes((offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) - if dom_temperature_raw is not None: - dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) - else: - return transceiver_dom_info_dict - dom_voltage_raw = self._read_eeprom_specific_bytes((offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) - if dom_voltage_raw is not None: - dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) - else: - return transceiver_dom_info_dict + dom_data_raw = self._read_eeprom_specific_bytes((offset + SFP_DOM_BULK_DATA_START), SFP_DOM_BULK_DATA_SIZE) - dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) - if dom_channel_monitor_raw is not None: - dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) - else: - return transceiver_dom_info_dict + start = SFP_TEMPE_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature(dom_data_raw[start: end], 0) + + start = SFP_VOLT_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage(dom_data_raw[start: end], 0) + + start = SFP_CHANNL_MON_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_CHANNL_MON_WIDTH + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_data_raw[start: end], 0) transceiver_dom_info_dict['temperature'] = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) transceiver_dom_info_dict['voltage'] = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) From 2d48e54e656e5fbabf4ab439efe6d585d8125015 Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Sat, 24 Aug 2019 07:06:53 +0300 Subject: [PATCH 12/13] [sonic_platform]introduce an explicit flag indicating whether sfp has been initialized --- .../mlnx-platform-api/sonic_platform/chassis.py | 12 +++++++----- .../mellanox/mlnx-platform-api/sonic_platform/sfp.py | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index 70cf725b894c..2eaf5a757420 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -73,7 +73,7 @@ def __init__(self): # move the initialization of each components to their dedicated initializer # which will be called from platform - self.sfp_module = None + self.sfp_module_initialized = False self.reboot_cause_initialized = False logger.log_info("Chassis loaded successfully") @@ -126,6 +126,8 @@ def initialize_sfp(self): self.sfp_event.initialize() self.MAX_SELECT_EVENT_RETURNED = self.PORT_END + self.sfp_module_initialized = True + def initialize_thermals(self): from sonic_platform.thermal import initialize_thermals # Initialize thermals @@ -153,7 +155,7 @@ def get_num_sfps(self): Returns: An integer, the number of sfps available on this chassis """ - if self.sfp_module is None: + if not self.sfp_module_initialized: self.initialize_sfp() return len(self._sfp_list) @@ -165,7 +167,7 @@ def get_all_sfps(self): A list of objects derived from SfpBase representing all sfps available on this chassis """ - if self.sfp_module is None: + if not self.sfp_module_initialized: self.initialize_sfp() return self._sfp_list @@ -182,7 +184,7 @@ def get_sfp(self, index): Returns: An object dervied from SfpBase representing the specified sfp """ - if self.sfp_module is None: + if not self.sfp_module_initialized: self.initialize_sfp() sfp = None @@ -222,7 +224,7 @@ def _get_port_position_tuple_by_sku_name(self): def get_watchdog(self): """ - Retreives hardware watchdog device on this chassis + Retrieves hardware watchdog device on this chassis Returns: An object derived from WatchdogBase representing the hardware diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py index 2d5c7887df64..be59451a8cb7 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py @@ -67,7 +67,7 @@ # in function get_transceiver_info and get_transceiver_bulk_status # XCVR_INTERFACE_DATA_SIZE stands for the max size to be read # this variable is only used by get_transceiver_info. -# be attention that each time some new value added to the function +# please be noted that each time some new value added to the function # we should make sure that it falls into the area # [XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE] or # adjust XCVR_INTERFACE_MAX_SIZE to contain the new data From 38aa635d0b59c8037e0d4113774aeebe63612bfa Mon Sep 17 00:00:00 2001 From: Stephen Sun Date: Mon, 26 Aug 2019 06:30:37 +0300 Subject: [PATCH 13/13] [chassis] don't initialize sfp_event until it is called deinitialize sfp_event when chassis destructed so that sdk resources can be correctly released. --- .../sonic_platform/chassis.py | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index 2eaf5a757420..814c7aca8178 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -74,9 +74,14 @@ def __init__(self): # move the initialization of each components to their dedicated initializer # which will be called from platform self.sfp_module_initialized = False + self.sfp_event_initialized = False self.reboot_cause_initialized = False logger.log_info("Chassis loaded successfully") + def __del__(self): + if self.sfp_event_initialized: + self.sfp_event.deinitialize() + def initialize_psu(self): from sonic_platform.psu import Psu # Initialize PSU list @@ -104,7 +109,7 @@ def initialize_fan(self): def initialize_sfp(self): from sonic_platform.sfp import SFP - from sonic_platform.sfp_event import sfp_event + self.sfp_module = SFP # Initialize SFP list @@ -121,11 +126,6 @@ def initialize_sfp(self): sfp_module = SFP(index, 'SFP') self._sfp_list.append(sfp_module) - # Initialize SFP event - self.sfp_event = sfp_event() - self.sfp_event.initialize() - self.MAX_SELECT_EVENT_RETURNED = self.PORT_END - self.sfp_module_initialized = True def initialize_thermals(self): @@ -488,6 +488,14 @@ def get_change_event(self, timeout=0): indicates that fan 0 has been removed, fan 2 has been inserted and sfp 11 has been removed. """ + # Initialize SFP event first + if not self.sfp_event_initialized: + from sonic_platform.sfp_event import sfp_event + self.sfp_event = sfp_event() + self.sfp_event.initialize() + self.MAX_SELECT_EVENT_RETURNED = self.PORT_END + self.sfp_event_initialized = True + wait_for_ever = (timeout == 0) port_dict = {} if wait_for_ever: