Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[202012] [Mellanox] Fix issue: SFP eeprom corrupted after replacing cable with different sfp type #13543

Merged
merged 2 commits into from
Feb 19, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 65 additions & 36 deletions platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#############################################################################

try:
import functools
import time
from sonic_platform_base.sfp_base import SfpBase
from sonic_platform_base.sonic_eeprom import eeprom_dts
Expand Down Expand Up @@ -323,6 +324,24 @@ def deinitialize_sdk_handle(sdk_handle):
logger.log_warning("Sdk handle is none")
return False


def refresh_sfp_type(refresh_dom_capability=True):
"""Decorator to force refreshing sfp type

Args:
refresh_dom_capability (bool, optional): refresh DOM capability. Defaults to True.
"""
def decorator(method):
@functools.wraps(method)
def _impl(self, *args, **kwargs):
self._refresh_sfp_type()
if refresh_dom_capability:
self._dom_capability_detect()
return method(self, *args, **kwargs)
return _impl
return decorator


class SFP(SfpBase):
"""Platform-specific SFP class"""

Expand All @@ -332,9 +351,9 @@ def __init__(self, sfp_index, sfp_type, sdk_handle_getter, platform):
self.sdk_sysfs_page_path_header = SFP_SYSFS_PATH.format(sfp_index)
self.sfp_eeprom_path = "qsfp{}".format(self.index)
self.sfp_status_path = "qsfp{}_status".format(self.index)
self._detect_sfp_type(sfp_type)
self._sfp_type = None
self._default_sfp_type = sfp_type
self.dom_tx_disable_supported = False
self._dom_capability_detect()
self.sdk_handle_getter = sdk_handle_getter
self.sdk_index = sfp_index

Expand All @@ -352,7 +371,7 @@ def reinit(self):
Re-initialize this SFP object when a new SFP inserted
:return:
"""
self._detect_sfp_type(self.sfp_type)
self._refresh_sfp_type()
self._dom_capability_detect()

def get_presence(self):
Expand Down Expand Up @@ -382,7 +401,8 @@ def _read_eeprom_specific_bytes(self, offset, num_bytes):
if page_num == 0:
page = self.sdk_sysfs_page_path_header + PATH_PAGE00
else:
if self.sfp_type == SFP_TYPE and page_num == 1:
self._refresh_sfp_type()
if page_num == 1 and self.sfp_type == SFP_TYPE:
page = self.sdk_sysfs_page_path_header + PATH_PAGE00_A2
else:
page = self.sdk_sysfs_page_path_header + PATH_PAGE.format(page_num)
Expand All @@ -394,26 +414,33 @@ def _read_eeprom_specific_bytes(self, offset, num_bytes):
except (OSError, IOError):
return None

def _detect_sfp_type(self, sfp_type):
eeprom_raw = []
eeprom_raw = self._read_eeprom_specific_bytes(XCVR_TYPE_OFFSET, XCVR_TYPE_WIDTH)
if eeprom_raw:
if eeprom_raw[0] in SFP_TYPE_CODE_LIST:
self.sfp_type = SFP_TYPE
elif eeprom_raw[0] in QSFP_TYPE_CODE_LIST:
self.sfp_type = QSFP_TYPE
elif eeprom_raw[0] in QSFP_DD_TYPE_CODE_LIST:
self.sfp_type = QSFP_DD_TYPE
@property
def sfp_type(self):
if self._sfp_type is None:
eeprom_raw = []
eeprom_raw = self._read_eeprom_specific_bytes(XCVR_TYPE_OFFSET, XCVR_TYPE_WIDTH)
if eeprom_raw:
if eeprom_raw[0] in SFP_TYPE_CODE_LIST:
self._sfp_type = SFP_TYPE
elif eeprom_raw[0] in QSFP_TYPE_CODE_LIST:
self._sfp_type = QSFP_TYPE
elif eeprom_raw[0] in QSFP_DD_TYPE_CODE_LIST:
self._sfp_type = QSFP_DD_TYPE
else:
# we don't recognize this identifier value, treat the xSFP module as the default type
self._sfp_type = self._default_sfp_type
logger.log_info("Identifier value of {} module {} is {} which isn't recognized and will be treated as default type ({})".format(
self._default_sfp_type, self.index, eeprom_raw[0], self._default_sfp_type
))
else:
# we don't regonize this identifier value, treat the xSFP module as the default type
self.sfp_type = sfp_type
logger.log_info("Identifier value of {} module {} is {} which isn't regonized and will be treated as default type ({})".format(
sfp_type, self.index, eeprom_raw[0], sfp_type
))
else:
# eeprom_raw being None indicates the module is not present.
# in this case we treat it as the default type according to the SKU
self.sfp_type = sfp_type
# eeprom_raw being None indicates the module is not present.
# in this case we treat it as the default type according to the SKU
self._sfp_type = self._default_sfp_type
self._default_sfp_type = self._sfp_type
return self._sfp_type

def _refresh_sfp_type(self):
self._sfp_type = None

def _is_qsfp_copper(self):
# This function read the specification compliance byte and
Expand Down Expand Up @@ -537,6 +564,7 @@ def _dom_capability_detect(self):
self.dom_supported = False
self.dom_temp_supported = False
self.dom_volt_supported = False
self.second_application_list = False
self.dom_rx_power_supported = False
self.dom_tx_power_supported = False
self.dom_tx_bias_power_supported = False
Expand Down Expand Up @@ -595,7 +623,7 @@ def _convert_string_to_num(self, value_str):
else:
return 'N/A'


@refresh_sfp_type()
def get_transceiver_info(self):
"""
Retrieves transceiver info of this SFP
Expand Down Expand Up @@ -900,7 +928,7 @@ def get_transceiver_info(self):

return transceiver_info_dict


@refresh_sfp_type()
def get_transceiver_bulk_status(self):
"""
Retrieves transceiver bulk status of this SFP
Expand Down Expand Up @@ -1100,7 +1128,7 @@ def get_transceiver_bulk_status(self):

return transceiver_dom_info_dict


@refresh_sfp_type()
def get_transceiver_threshold_info(self):
"""
Retrieves transceiver threshold info of this SFP
Expand Down Expand Up @@ -1279,7 +1307,7 @@ def get_transceiver_threshold_info(self):

return transceiver_dom_threshold_info_dict


@refresh_sfp_type()
def get_reset_status(self):
"""
Retrieves the reset status of SFP
Expand Down Expand Up @@ -1332,6 +1360,7 @@ def get_reset_status(self):
dom_channel_status_data = sfpd_obj.parse_dom_channel_status(dom_channel_status_raw, 0)
return dom_channel_status_data['data']['Status']['value'] == 'On'

@refresh_sfp_type()
def get_rx_los(self):
"""
Retrieves the RX LOS (lost-of-signal) status of SFP
Expand Down Expand Up @@ -1364,7 +1393,7 @@ def get_rx_los(self):
rx_los_list.append(False)
return rx_los_list


@refresh_sfp_type()
def get_tx_fault(self):
"""
Retrieves the TX fault status of SFP
Expand Down Expand Up @@ -1397,7 +1426,7 @@ def get_tx_fault(self):
tx_fault_list.append(False)
return tx_fault_list


@refresh_sfp_type()
def get_tx_disable(self):
"""
Retrieves the tx_disable status of this SFP
Expand Down Expand Up @@ -1500,7 +1529,7 @@ def get_lpmode(self):

return oper_pwr_mode == SX_MGMT_PHY_MOD_PWR_MODE_LOW_E


@refresh_sfp_type(refresh_dom_capability=True)
def get_power_override(self):
"""
Retrieves the power-override status of this SFP
Expand All @@ -1521,7 +1550,7 @@ def get_power_override(self):
else:
return NotImplementedError


@refresh_sfp_type()
def get_temperature(self):
"""
Retrieves the temperature of this SFP
Expand Down Expand Up @@ -1579,7 +1608,7 @@ def get_temperature(self):
else:
return None


@refresh_sfp_type()
def get_voltage(self):
"""
Retrieves the supply voltage of this SFP
Expand Down Expand Up @@ -1638,7 +1667,7 @@ def get_voltage(self):
else:
return None


@refresh_sfp_type()
def get_tx_bias(self):
"""
Retrieves the TX bias current of this SFP
Expand Down Expand Up @@ -1672,7 +1701,7 @@ def get_tx_bias(self):
if sfpd_obj is None:
return None

if dom_tx_bias_power_supported:
if self.dom_tx_bias_power_supported:
dom_tx_bias_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_TX_BIAS_OFFSET), QSFP_DD_TX_BIAS_WIDTH)
if dom_tx_bias_raw is not None:
dom_tx_bias_data = sfpd_obj.parse_dom_tx_bias(dom_tx_bias_raw, 0)
Expand Down Expand Up @@ -1705,7 +1734,7 @@ def get_tx_bias(self):

return tx_bias_list


@refresh_sfp_type()
def get_rx_power(self):
"""
Retrieves the received optical power for this SFP
Expand Down Expand Up @@ -1781,7 +1810,7 @@ def get_rx_power(self):
return None
return rx_power_list


@refresh_sfp_type()
def get_tx_power(self):
"""
Retrieves the TX power of this SFP
Expand Down