[mellanox ]improve the method the type of sfp module is detected (#3846)
Fix the issue when an SFP module is plugged into a QSFP port via an adapter. - How I did it Originally the type of an SFP module is determined according to the SKU dictionary. However, it's possible that as SFP module is plugged into a QSFP port via an adapter. In this case, the EEPROM content will be parsed in the wrong format. To address that we fetch the identifier value of an xSFP module and then get the type by parsing it.
This commit is contained in:
parent
d21561d8be
commit
0156a3311a
@ -136,6 +136,26 @@ SFP_CHANNL_MON_WIDTH = 6
|
|||||||
SFP_CHANNL_STATUS_OFFSET = 110
|
SFP_CHANNL_STATUS_OFFSET = 110
|
||||||
SFP_CHANNL_STATUS_WIDTH = 1
|
SFP_CHANNL_STATUS_WIDTH = 1
|
||||||
|
|
||||||
|
# identifier value of xSFP module which is in the first byte of the EEPROM
|
||||||
|
# if the identifier value falls into SFP_TYPE_CODE_LIST the module is treated as a SFP module and parsed according to 8472
|
||||||
|
# for QSFP_TYPE_CODE_LIST the module is treated as a QSFP module and parsed according to 8436/8636
|
||||||
|
# Originally the type (SFP/QSFP) of each module is determined according to the SKU dictionary
|
||||||
|
# where the type of each FP port is defined. The content of EEPROM is parsed according to its type.
|
||||||
|
# However, sometimes the SFP module can be fit in an adapter and then pluged into a QSFP port.
|
||||||
|
# In this case the EEPROM content is in format of SFP but parsed as QSFP, causing failure.
|
||||||
|
# To resolve that issue the type field of the xSFP module is also fetched so that we can know exectly what type the
|
||||||
|
# module is. Currently only the following types are recognized as SFP/QSFP module.
|
||||||
|
# Meanwhile, if the a module's identifier value can't be recognized, it will be parsed according to the SKU dictionary.
|
||||||
|
# This is because in the future it's possible that some new identifier value which is not regonized but backward compatible
|
||||||
|
# with the current format and by doing so it can be parsed as much as possible.
|
||||||
|
SFP_TYPE_CODE_LIST = [
|
||||||
|
'03' # SFP/SFP+/SFP28
|
||||||
|
]
|
||||||
|
QSFP_TYPE_CODE_LIST = [
|
||||||
|
'0d', # QSFP+ or later
|
||||||
|
'11' # QSFP28 or later
|
||||||
|
]
|
||||||
|
|
||||||
qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)',
|
qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)',
|
||||||
'Length OM2(m)', 'Length OM1(m)',
|
'Length OM2(m)', 'Length OM1(m)',
|
||||||
'Length Cable Assembly(m)')
|
'Length Cable Assembly(m)')
|
||||||
@ -206,7 +226,7 @@ class SFP(SfpBase):
|
|||||||
self.index = sfp_index + 1
|
self.index = sfp_index + 1
|
||||||
self.sfp_eeprom_path = "qsfp{}".format(self.index)
|
self.sfp_eeprom_path = "qsfp{}".format(self.index)
|
||||||
self.sfp_status_path = "qsfp{}_status".format(self.index)
|
self.sfp_status_path = "qsfp{}_status".format(self.index)
|
||||||
self.sfp_type = sfp_type
|
self._detect_sfp_type(sfp_type)
|
||||||
self.dom_tx_disable_supported = False
|
self.dom_tx_disable_supported = False
|
||||||
self._dom_capability_detect()
|
self._dom_capability_detect()
|
||||||
self.sdk_handle = None
|
self.sdk_handle = None
|
||||||
@ -293,6 +313,26 @@ class SFP(SfpBase):
|
|||||||
return eeprom_raw
|
return eeprom_raw
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
def _dom_capability_detect(self):
|
def _dom_capability_detect(self):
|
||||||
if not self.get_presence():
|
if not self.get_presence():
|
||||||
self.dom_supported = False
|
self.dom_supported = False
|
||||||
@ -303,7 +343,7 @@ class SFP(SfpBase):
|
|||||||
self.calibration = 0
|
self.calibration = 0
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.sfp_type == "QSFP":
|
if self.sfp_type == QSFP_TYPE:
|
||||||
self.calibration = 1
|
self.calibration = 1
|
||||||
sfpi_obj = sff8436InterfaceId()
|
sfpi_obj = sff8436InterfaceId()
|
||||||
if sfpi_obj is None:
|
if sfpi_obj is None:
|
||||||
@ -348,7 +388,7 @@ class SFP(SfpBase):
|
|||||||
self.dom_tx_power_supported = False
|
self.dom_tx_power_supported = False
|
||||||
self.calibration = 0
|
self.calibration = 0
|
||||||
self.qsfp_page3_available = False
|
self.qsfp_page3_available = False
|
||||||
elif self.sfp_type == "SFP":
|
elif self.sfp_type == SFP_TYPE:
|
||||||
sfpi_obj = sff8472InterfaceId()
|
sfpi_obj = sff8472InterfaceId()
|
||||||
if sfpi_obj is None:
|
if sfpi_obj is None:
|
||||||
return None
|
return None
|
||||||
|
Loading…
Reference in New Issue
Block a user