diff --git a/sonic_platform_base/sfp_base.py b/sonic_platform_base/sfp_base.py index 780695b1d6fe..d6e735487ab0 100644 --- a/sonic_platform_base/sfp_base.py +++ b/sonic_platform_base/sfp_base.py @@ -109,6 +109,7 @@ def get_transceiver_info(self): keys |Value Format |Information ---------------------------|---------------|---------------------------- type |1*255VCHAR |type of SFP + type_abbrv_name |1*255VCHAR |type of SFP, abbreviated hardware_rev |1*255VCHAR |hardware version of SFP serial |1*255VCHAR |serial number of the SFP manufacturer |1*255VCHAR |SFP vendor name diff --git a/sonic_platform_base/sonic_xcvr/api/public/sff8436.py b/sonic_platform_base/sonic_xcvr/api/public/sff8436.py new file mode 100644 index 000000000000..7d4314be3c12 --- /dev/null +++ b/sonic_platform_base/sonic_xcvr/api/public/sff8436.py @@ -0,0 +1,250 @@ +from ...fields import consts +from ..xcvr_api import XcvrApi + +class Sff8436Api(XcvrApi): + NUM_CHANNELS = 4 + + def __init__(self, xcvr_eeprom): + super(Sff8436Api, self).__init__(xcvr_eeprom) + + def get_model(self): + return self.xcvr_eeprom.read(consts.VENDOR_PART_NO_FIELD) + + def get_serial(self): + return self.xcvr_eeprom.read(consts.VENDOR_SERIAL_NO_FIELD) + + def get_transceiver_info(self): + serial_id = self.xcvr_eeprom.read(consts.SERIAL_ID_FIELD) + if serial_id is None: + return None + + ext_id = serial_id[consts.EXT_ID_FIELD] + power_class = ext_id[consts.POWER_CLASS_FIELD] + clei_code = ext_id[consts.CLEI_CODE_FIELD] + cdr_tx = ext_id[consts.CDR_TX_FIELD] + cdr_rx = ext_id[consts.CDR_RX_FIELD] + + smf_len = serial_id[consts.LENGTH_SMF_KM_FIELD] + om3_len = serial_id[consts.LENGTH_OM3_FIELD] + om2_len = serial_id[consts.LENGTH_OM2_FIELD] + om1_len = serial_id[consts.LENGTH_OM1_FIELD] + cable_assembly_len = serial_id[consts.LENGTH_ASSEMBLY_FIELD] + + len_types = ['Length(km)', 'Length OM3(2m)', 'Length OM2(m)', 'Length OM1(m)', 'Length Cable Assembly(m)'] + cable_len = 0 + cable_type = "Unknown" + for len, type in zip([smf_len, om3_len, om2_len, om1_len, cable_assembly_len], len_types): + if len > 0: + cable_len = len + cable_type = type + + xcvr_info = { + "type": serial_id[consts.ID_FIELD], + "type_abbrv_name": serial_id[consts.ID_ABBRV_FIELD], + "hardware_rev": serial_id[consts.VENDOR_REV_FIELD], + "serial": serial_id[consts.VENDOR_SERIAL_NO_FIELD], + "manufacturer": serial_id[consts.VENDOR_NAME_FIELD], + "model": serial_id[consts.VENDOR_PART_NO_FIELD], + "connector": serial_id[consts.CONNECTOR_FIELD], + "encoding": serial_id[consts.ENCODING_FIELD], + "ext_identifier": ", ".join([power_class, clei_code, cdr_tx, cdr_rx]), + "ext_rateselect_compliance": serial_id[consts.EXT_RATE_SELECT_COMPLIANCE_FIELD], + "cable_type": cable_type, + "cable_length": cable_len, + "nominal_bit_rate": serial_id[consts.NOMINAL_BR_FIELD], + "specification_compliance": str(serial_id[consts.SPEC_COMPLIANCE_FIELD]), + "vendor_date": serial_id[consts.VENDOR_DATE_FIELD], + "vendor_oui": serial_id[consts.VENDOR_OUI_FIELD], + "application_advertisement": "N/A", + } + + return xcvr_info + + def get_transceiver_bulk_status(self): + rx_los = self.get_rx_los() + tx_fault = self.get_tx_fault() + tx_disable = self.get_tx_disable() + tx_disabled_channel = self.get_tx_disable_channel() + temp = self.get_module_temperature() + voltage = self.get_voltage() + tx_bias = self.get_tx_bias() + rx_power = self.get_rx_power() + tx_power = self.get_tx_power() + read_failed = rx_los is None or \ + tx_fault is None or \ + tx_disable is None or \ + tx_disabled_channel is None or \ + temp is None or \ + voltage is None or \ + tx_bias is None or \ + rx_power is None or \ + tx_power is None + if read_failed: + return None + + bulk_status = { + "rx_los": all(rx_los), + "tx_fault": all(tx_fault), + "tx_disable": all(tx_disable), + "tx_disabled_channel": tx_disabled_channel, + "temperature": temp, + "voltage": voltage + } + + for i in range(1, self.NUM_CHANNELS + 1): + bulk_status["tx%dbias" % i] = tx_bias[i - 1] + bulk_status["rx%dpower" % i] = rx_power[i - 1] + bulk_status["tx%dpower" % i] = tx_power[i - 1] + + return bulk_status + + def get_transceiver_threshold_info(self): + threshold_info_keys = ['temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', + 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', + 'txbiaslowalarm', 'txbiaslowwarning' + ] + threshold_info_dict = dict.fromkeys(threshold_info_keys, 'N/A') + flat_mem = self.is_flat_memory() + if flat_mem is None: + return None + if flat_mem: + return threshold_info_dict + + temp_thresholds = self.xcvr_eeprom.read(consts.TEMP_THRESHOLDS_FIELD) + voltage_thresholds = self.xcvr_eeprom.read(consts.VOLTAGE_THRESHOLDS_FIELD) + rx_power_thresholds = self.xcvr_eeprom.read(consts.RX_POWER_THRESHOLDS_FIELD) + tx_bias_thresholds = self.xcvr_eeprom.read(consts.TX_BIAS_THRESHOLDS_FIELD) + read_failed = temp_thresholds is None or \ + voltage_thresholds is None or \ + rx_power_thresholds is None or \ + tx_bias_thresholds is None + if read_failed: + return None + + for thresh in rx_power_thresholds: + rx_power_thresholds[thresh] = self.mw_to_dbm(rx_power_thresholds[thresh]) + + return { + "temphighalarm": float("{:.3f}".format(temp_thresholds[consts.TEMP_HIGH_ALARM_FIELD])), + "templowalarm": float("{:.3f}".format(temp_thresholds[consts.TEMP_LOW_ALARM_FIELD])), + "temphighwarning": float("{:.3f}".format(temp_thresholds[consts.TEMP_HIGH_WARNING_FIELD])), + "templowwarning": float("{:.3f}".format(temp_thresholds[consts.TEMP_LOW_WARNING_FIELD])), + "vcchighalarm": float("{:.3f}".format(voltage_thresholds[consts.VOLTAGE_HIGH_ALARM_FIELD])), + "vcclowalarm": float("{:.3f}".format(voltage_thresholds[consts.VOLTAGE_LOW_ALARM_FIELD])), + "vcchighwarning": float("{:.3f}".format(voltage_thresholds[consts.VOLTAGE_HIGH_WARNING_FIELD])), + "vcclowwarning": float("{:.3f}".format(voltage_thresholds[consts.VOLTAGE_LOW_WARNING_FIELD])), + "rxpowerhighalarm": float("{:.3f}".format(rx_power_thresholds[consts.RX_POWER_HIGH_ALARM_FIELD])), + "rxpowerlowalarm": float("{:.3f}".format(rx_power_thresholds[consts.RX_POWER_LOW_ALARM_FIELD])), + "rxpowerhighwarning": float("{:.3f}".format(rx_power_thresholds[consts.RX_POWER_HIGH_WARNING_FIELD])), + "rxpowerlowwarning": float("{:.3f}".format(rx_power_thresholds[consts.RX_POWER_LOW_WARNING_FIELD])), + "txpowerhighalarm": "N/A", + "txpowerlowalarm": "N/A", + "txpowerhighwarning": "N/A", + "txpowerlowwarning": "N/A", + "txbiashighalarm": float("{:.3f}".format(tx_bias_thresholds[consts.TX_BIAS_HIGH_ALARM_FIELD])), + "txbiaslowalarm": float("{:.3f}".format(tx_bias_thresholds[consts.TX_BIAS_LOW_ALARM_FIELD])), + "txbiashighwarning": float("{:.3f}".format(tx_bias_thresholds[consts.TX_BIAS_HIGH_WARNING_FIELD])), + "txbiaslowwarning": float("{:.3f}".format(tx_bias_thresholds[consts.TX_BIAS_LOW_WARNING_FIELD])) + } + + def get_rx_los(self): + rx_los = self.xcvr_eeprom.read(consts.RX_LOS_FIELD) + if rx_los is None: + return None + return [bool(rx_los & (1 << i)) for i in range(self.NUM_CHANNELS)] + + def get_tx_fault(self): + tx_fault = self.xcvr_eeprom.read(consts.TX_FAULT_FIELD) + if tx_fault is None: + return None + return [bool(tx_fault & (1 << i)) for i in range(self.NUM_CHANNELS)] + + def get_tx_disable(self): + tx_disable = self.xcvr_eeprom.read(consts.TX_DISABLE_FIELD) + if tx_disable is None: + return None + return [bool(tx_disable & (1 << i)) for i in range(self.NUM_CHANNELS)] + + def get_tx_disable_channel(self): + return self.xcvr_eeprom.read(consts.TX_DISABLE_FIELD) + + def get_module_temperature(self): + temp = self.xcvr_eeprom.read(consts.TEMPERATURE_FIELD) + if temp is None: + return None + return float("{:.3f}".format(temp)) + + def get_voltage(self): + voltage = self.xcvr_eeprom.read(consts.VOLTAGE_FIELD) + if voltage is None: + return None + return float("{:.3f}".format(voltage)) + + def get_tx_bias(self): + tx_bias = self.xcvr_eeprom.read(consts.TX_BIAS_FIELD) + if tx_bias is None: + return None + return [channel_bias for channel_bias in tx_bias.values()] + + def get_rx_power(self): + rx_power = self.xcvr_eeprom.read(consts.RX_POWER_FIELD) + if rx_power is None: + return None + return [float("{:.3f}".format(channel_power)) for channel_power in rx_power.values()] + + def get_tx_power(self): + return ["N/A" for _ in range(self.NUM_CHANNELS)] + + def tx_disable(self, tx_disable): + val = 0xF if tx_disable else 0x0 + return self.xcvr_eeprom.write(consts.TX_DISABLE_FIELD, val) + + def tx_disable_channel(self, channel, disable): + channel_state = self.get_tx_disable_channel() + if channel_state is None: + return False + + for i in range(self.NUM_CHANNELS): + mask = (1 << i) + if not (channel & mask): + continue + if disable: + channel_state |= mask + else: + channel_state &= ~mask + + return self.xcvr_eeprom.write(consts.TX_DISABLE_FIELD, channel_state) + + def get_power_override(self): + return self.xcvr_eeprom.read(consts.POWER_OVERRIDE_FIELD) + + def set_power_override(self, power_override, power_set): + ret = self.xcvr_eeprom.write(consts.POWER_OVERRIDE_FIELD, power_override) + if power_override: + ret &= self.xcvr_eeprom.write(consts.POWER_SET_FIELD, power_set) + return ret + + def is_flat_memory(self): + return self.xcvr_eeprom.read(consts.FLAT_MEM_FIELD) + + def get_tx_power_support(self): + return False + + def is_copper(self): + eth_compliance = self.xcvr_eeprom.read(consts.ETHERNET_10_40G_COMPLIANCE_FIELD) + if eth_compliance is None: + return None + return eth_compliance == "40GBASE-CR4" + + def get_temperature_support(self): + return True + + def get_voltage_support(self): + return True diff --git a/sonic_platform_base/sonic_xcvr/api/xcvr_api.py b/sonic_platform_base/sonic_xcvr/api/xcvr_api.py index 0904e4868bd2..933bbe37ac79 100644 --- a/sonic_platform_base/sonic_xcvr/api/xcvr_api.py +++ b/sonic_platform_base/sonic_xcvr/api/xcvr_api.py @@ -4,17 +4,27 @@ Abstract base class for platform-independent APIs used to interact with xcvrs in SONiC """ - +from math import log10 class XcvrApi(object): def __init__(self, xcvr_eeprom): self.xcvr_eeprom = xcvr_eeprom + @staticmethod + def mw_to_dbm(mW): + if mW == 0: + return float("-inf") + elif mW < 0: + return float("NaN") + return 10. * log10(mW) + def get_model(self): """ Retrieves the model (part number) of the xcvr Returns: A string, the model/part number of the xcvr + + If there is an issue with reading the xcvr, None should be returned. """ raise NotImplementedError @@ -24,6 +34,8 @@ def get_serial(self): Returns: A string, the serial number of the xcvr + + If there is an issue with reading the xcvr, None should be returned. """ raise NotImplementedError @@ -53,6 +65,8 @@ def get_transceiver_info(self): vendor_oui |string |vendor OUI application_advertisement |string |supported applications advertisement ================================================================================ + + If there is an issue with reading the xcvr, None should be returned. """ raise NotImplementedError @@ -79,6 +93,8 @@ def get_transceiver_bulk_status(self): txpower |float |TX output power in mW, n is the channel number, | |for example, tx2power stands for tx power of channel 2. ======================================================================== + + If there is an issue with reading the xcvr, None should be returned. """ raise NotImplementedError @@ -112,6 +128,8 @@ def get_transceiver_threshold_info(self): txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. ======================================================================== + + If there is an issue with reading the xcvr, None should be returned. """ raise NotImplementedError @@ -126,6 +144,8 @@ def get_rx_los(self): E.g., for a tranceiver with four channels: [False, False, True, False] If Rx LOS status is unsupported on the xcvr, each list element should be "N/A" instead. + + If there is an issue with reading the xcvr, None should be returned. """ raise NotImplementedError @@ -140,6 +160,8 @@ def get_tx_fault(self): E.g., for a tranceiver with four channels: [False, False, True, False] If TX fault status is unsupported on the xcvr, each list element should be "N/A" instead. + + If there is an issue with reading the xcvr, None should be returned. """ raise NotImplementedError @@ -152,6 +174,8 @@ def get_tx_disable(self): TX channels which have been disabled in this xcvr. As an example, a returned value of 0x5 indicates that channel 0 and channel 2 have been disabled. + + If there is an issue with reading the xcvr, None should be returned. """ raise NotImplementedError @@ -164,16 +188,20 @@ def get_tx_disable_channel(self): TX channels which have been disabled in this xcvr. As an example, a returned value of 0x5 indicates that channel 0 and channel 2 have been disabled. + + If there is an issue with reading the xcvr, None should be returned. """ raise NotImplementedError - def get_temperature(self): + def get_module_temperature(self): """ Retrieves the temperature of this xcvr Returns: A float representing the current temperature in Celsius, or "N/A" if temperature measurements are unsupported on the xcvr. + + If there is an issue with reading the xcvr, None should be returned. """ raise NotImplementedError @@ -184,6 +212,8 @@ def get_voltage(self): Returns: A float representing the supply voltage in mV, or "N/A" if voltage measurements are unsupported on the xcvr. + + If there is an issue with reading the xcvr, None should be returned. """ raise NotImplementedError @@ -197,6 +227,8 @@ def get_tx_bias(self): E.g., for a tranceiver with four channels: ['110.09', '111.12', '108.21', '112.09'] If TX bias is unsupported on the xcvr, each list element should be "N/A" instead. + + If there is an issue with reading the xcvr, None should be returned. """ raise NotImplementedError @@ -210,6 +242,8 @@ def get_rx_power(self): E.g., for a tranceiver with four channels: ['1.77', '1.71', '1.68', '1.70'] If RX power is unsupported on the xcvr, each list element should be "N/A" instead. + + If there is an issue with reading the xcvr, None should be returned. """ raise NotImplementedError @@ -223,6 +257,8 @@ def get_tx_power(self): E.g., for a tranceiver with four channels: ['1.86', '1.86', '1.86', '1.86'] If TX power is unsupported on the xcvr, each list element should be "N/A" instead. + + If there is an issue with reading the xcvr, None should be returned. """ raise NotImplementedError @@ -260,6 +296,8 @@ def get_power_override(self): Returns: A boolean, True if power-override is enabled, False if disabled + + If there is an issue with reading the xcvr, None should be returned. """ raise NotImplementedError @@ -283,3 +321,56 @@ def set_power_override(self, power_override, power_set): False if not """ raise NotImplementedError + + def is_flat_memory(self): + """ + Determines whether the xcvr's memory map is flat or paged + + Returns: + A Boolean, True if flat memory, False if paging is implemented + + If there is an issue with reading the xcvr, None should be returned. + """ + raise NotImplementedError + + def get_tx_power_support(self): + """ + Retrieves the tx power measurement capability of this xcvr + + Returns: + A Boolean, True if tx power measurement is supported, False otherwise + + If there is an issue with reading the xcvr, None should be returned. + """ + raise NotImplementedError + + def is_copper(self): + """ + Returns: + A Boolean, True if xcvr is copper, False if optical + + If there is an issue with reading the xcvr, None should be returned. + """ + raise NotImplementedError + + def get_temperature_support(self): + """ + Retrieves the temperature measurement capability of this xcvr + + Returns: + A Boolean, True if module temperature is supported, False otherwise + + If there is an issue with reading the xcvr, None should be returned. + """ + raise NotImplementedError + + def get_voltage_support(self): + """ + Retrieves the temperature measurement capability of this xcvr + + Returns: + A Boolean, True if module voltage measurement is supported, False otherwise + + If there is an issue with reading the xcvr, None should be returned. + """ + raise NotImplementedError diff --git a/sonic_platform_base/sonic_xcvr/codes/public/sff8024.py b/sonic_platform_base/sonic_xcvr/codes/public/sff8024.py index 5948b1af2f0a..16be425a8f6b 100644 --- a/sonic_platform_base/sonic_xcvr/codes/public/sff8024.py +++ b/sonic_platform_base/sonic_xcvr/codes/public/sff8024.py @@ -41,4 +41,75 @@ class Sff8024(XcvrCodes): 30: 'QSFP+ or later with CMIS' } + XCVR_IDENTIFIER_ABBRV = { + 0: 'Unknown', + 1: 'GBIC', + 2: 'Soldered', + 3: 'SFP', + 4: 'XBI300', + 5: 'XENPAK', + 6: 'XFP', + 7: 'XFF', + 8: 'XFP-E', + 9: 'XPAK', + 10: 'X2', + 11: 'DWDM-SFP', + 12: 'QSFP', + 13: 'QSFP+', + 14: 'CXP', + 15: 'HD4X', + 16: 'HD8X', + 17: 'QSFP28', + 18: 'CXP2', + 19: 'CDFP-1/2', + 20: 'HD4X-Fanout', + 21: 'HD8X-Fanout', + 22: 'CDFP-3', + 23: 'MicroQSFP', + 24: 'QSFP-DD', + 25: 'OSFP-8X', + 26: 'SFP-DD', + 27: 'DSFP', + 28: 'Link-x4', + 29: 'Link-x8', + 30: 'QSFP+', + } + + CONNECTORS = { + 0: 'Unknown or unspecified', + 1: 'SC', + 2: 'FC Style 1 copper connector', + 3: 'FC Style 2 copper connector', + 4: 'BNC/TNC', + 5: 'FC coax headers', + 6: 'Fiberjack', + 7: 'LC', + 8: 'MT-RJ', + 9: 'MU', + 10: 'SG', + 11: 'Optical Pigtail', + 12: 'MPO 1x12', + 13: 'MPO 2x16', + 32: 'HSSDC II', + 33: 'Copper pigtail', + 34: 'RJ45', + 35: 'No separable connector', + 36: 'MXC 2x16', + 37: 'CS optical connector', + 38: 'SN optical connector', + 39: 'MPO 2x12', + 40: 'MPO 1x16', + } + + ENCODINGS = { + 0: "Unspecified", + 1: "8B/10B", + 2: "4B/5B", + 3: "NRZ", + # 4-6 differ between 8472 and 8436/8636 + 7: "256B/257B (transcoded FEC-enabled data)", + 8: "PAM4", + } + + # TODO: Add other codes diff --git a/sonic_platform_base/sonic_xcvr/codes/public/sff8436.py b/sonic_platform_base/sonic_xcvr/codes/public/sff8436.py new file mode 100644 index 000000000000..9cde7095eca2 --- /dev/null +++ b/sonic_platform_base/sonic_xcvr/codes/public/sff8436.py @@ -0,0 +1,106 @@ +from .sff8024 import Sff8024 + +class Sff8436Codes(Sff8024): + ENCODINGS = { + 0: "Unspecified", + 1: "8B/10B", + 2: "4B/5B", + 3: "NRZ", + 4: "SONET Scrambled", + 5: "64B/66B", + 6: "Manchester", + 7: "256B/257B (transcoded FEC-enabled data)", + 8: "PAM4", + } + + POWER_CLASSES = { + 0: "Power Class 1 Module (1.5W max. Power consumption)", + 64: "Power Class 2 Module (2.0W max. Power consumption)", + 128: "Power Class 3 Module (2.5W max. Power consumption)", + 192: "Power Class 4 Module (3.5W max. Power consumption)", + } + + CLEI_CODE = { + 0: "No CLEI code present in Page 02h", + 16: "CLEI code present in Page 02h" + } + + CDR_TX = { + 0: "No CDR in TX", + 8: "CDR present in TX" + } + + CDR_RX = { + 0: "No CDR in RX", + 4: "CDR present in RX" + } + + ETHERNET_10_40G_COMPLIANCE = { + 1: "40G Active Cable (XLPPI)", + 2: "40GBASE-LR4", + 4: "40GBASE-SR4", + 8: "40GBASE-CR4", + 16: "10GBASE-SR", + 32: "10GBASE-LR", + 64: "10GBASE-LRM" + } + + SONET_COMPLIANCE = { + 1: "OC 48 short reach", + 2: "OC 48, intermediate reach", + 4: "OC 48, long reach", + 16: "40G OTN (OTU3B/OTU3C)" + } + + SAS_SATA_COMPLIANCE = { + 8: "SAS 3.0G", + 16: "SAS 6.0G", + } + + GIGABIT_ETHERNET_COMPLIANCE = { + 1: "1000BASE-SX", + 2: "1000BASE-LX", + 4: "1000BASE-CX", + 8: "1000BASE-T" + } + + FIBRE_CHANNEL_LINK_LENGTH = { + 8: "Medium (M)", + 16: "Long distance (L)", + 32: "Intermediate distance (I)", + 64: "Short distance (S)", + 128: "Very long distance (V)" + } + + FIBRE_CHANNEL_TRANSMITTER_TECH = { + 16: "Longwave Laser (LL)", + 32: "Shortwave laser w OFC (SL)", + 64: "Shortwave laser w/o OFC (SN)", + 128: "Electrical intra-enclosure", + 256: "Electrical inter-enclosure (EN)", + 512: "Longwave laser (LC)" + } + + FIBRE_CHANNEL_TRANSMISSION_MEDIA = { + 1: "Single Mode (SM)", + 2: "Multi-mode 50 um (OM3)", + 4: "Multi-mode 50m (M5)", + 8: "Multi-mode 62.5m (M6)", + 16: "Video Coax (TV)", + 32: "Miniature Coax (MI)", + 64: "Shielded Twisted Pair (TP", + 128: "Twin Axial Pair (TW)" + } + + FIBRE_CHANNEL_SPEED = { + 1: "100 Mbytes/Sec", + 4: "200 Mbytes/Sec", + 16: "400 Mbytes/Sec", + 32: "1600 Mbytes/Sec", + 64: "800 Mbytes/Sec", + 128: "1200 Mbytes/Sec" + } + + EXT_RATESELECT_COMPLIANCE = { + 0: "QSFP+ Rate Select Version 1" + } diff --git a/sonic_platform_base/sonic_xcvr/fields/consts.py b/sonic_platform_base/sonic_xcvr/fields/consts.py index 088b8ad10514..4f80fe5c7d59 100644 --- a/sonic_platform_base/sonic_xcvr/fields/consts.py +++ b/sonic_platform_base/sonic_xcvr/fields/consts.py @@ -1,12 +1,101 @@ # COMMON ID_FIELD = "Identifier" +ID_ABBRV_FIELD = "Identifier Abbreviation" + +STATUS_FIELD = "Status Indicators" +STATUS_IND_BITS_FIELD = "Status Indicator Bits" + +FLAT_MEM_FIELD = "Flat_mem" +CONNECTOR_FIELD = "Connector" + +DIAG_MON_TYPE_FIELD = "Diagnostic Monitoring Type" +DEVICE_TECH_FIELD = "Device Technology" +EXT_SPEC_COMPLIANCE_FIELD = "Extended Specification Compliance" + +LENGTH_SMF_KM_FIELD = "Length SMF (km)" +LENGTH_SMF_M_FIELD = "Length SMF (m)" +LENGTH_OM4_FIELD = "Length OM4" +LENGTH_OM3_FIELD = "Length OM3" +LENGTH_OM2_FIELD = "Length OM2" +LENGTH_OM1_FIELD = "Length OM1" + +MODULE_MONITORS_FIELD = "Module Monitors" + +RX_LOS_FIELD = "RxLOS" +RX_POWER_FIELD = "RxPower" +RX_POWER_THRESHOLDS_FIELD = "RxPowerThresholds" +RX_POWER_HIGH_ALARM_FIELD = "RxPowerHighAlarm" +RX_POWER_LOW_ALARM_FIELD = "RxPowerLowAlarm" +RX_POWER_HIGH_WARNING_FIELD = "RxPowerHighWarning" +RX_POWER_LOW_WARNING_FIELD = "RxPowerLowWarning" + +TEMPERATURE_FIELD = "Temperature" +TEMP_SUPPORT_FIELD = "Temperature Monitoring Implemented" +TEMP_THRESHOLDS_FIELD = "TempThresholds" +TEMP_HIGH_ALARM_FIELD = "TempHighAlarm" +TEMP_LOW_ALARM_FIELD = "TempLowAlarm" +TEMP_HIGH_WARNING_FIELD = "TempHighWarning" +TEMP_LOW_WARNING_FIELD = "TempLowWarning" + +THRESHOLDS_FIELD = "Thresholds" + +TX_BIAS_FIELD = "TxBias" +TX_BIAS_THRESHOLDS_FIELD = "TxBiasThresholds" +TX_BIAS_HIGH_ALARM_FIELD = "TxHighAlarm" +TX_BIAS_LOW_ALARM_FIELD = "TxLowAlarm" +TX_BIAS_HIGH_WARNING_FIELD = "TxHighWarning" +TX_BIAS_LOW_WARNING_FIELD = "TxLowWarning" + +TX_FAULT_FIELD = "TxFault" +TX_DISABLE_FIELD = "TxDisable" + +TX_POWER_FIELD = "TxPower" +TX_POWER_SUPPORT_FIELD = "TxPowerSupported" +TX_POWER_THRESHOLDS_FIELD = "TxPowerThresholds" +TX_POWER_HIGH_ALARM_FIELD = "TxPowerHighAlarm" +TX_POWER_LOW_ALARM_FIELD = "TxPowerLowAlarm" +TX_POWER_HIGH_WARNING_FIELD = "TxPowerHighWarning" +TX_POWER_LOW_WARNING_FIELD = "TxPowerLowWarning" VENDOR_NAME_FIELD = "VendorName" +VENDOR_DATE_FIELD = "VendorDate" VENDOR_OUI_FIELD = "VendorOUI" VENDOR_PART_NO_FIELD = "VendorPN" +VENDOR_REV_FIELD = "VendorRev" +VENDOR_SERIAL_NO_FIELD = "VendorSN" +VOLTAGE_FIELD = "Voltage" +VOLTAGE_SUPPORT_FIELD = "Supply Voltage Monitoring Implemented" +VOLTAGE_THRESHOLDS_FIELD = "VoltageThresholds" +VOLTAGE_HIGH_ALARM_FIELD = "VoltageHighAlarm" +VOLTAGE_LOW_ALARM_FIELD = "VoltageLowAlarm" +VOLTAGE_HIGH_WARNING_FIELD = "VoltageHighWarning" +VOLTAGE_LOW_WARNING_FIELD = "VoltageLowWarning" + +SERIAL_ID_FIELD = "Serial ID" +EXT_ID_FIELD = "Extended Identifier" +POWER_CLASS_FIELD = "Power Class" +CLEI_CODE_FIELD = "CLEI Code" +CDR_TX_FIELD = "CDR TX" +CDR_RX_FIELD = "CDR RX" +SPEC_COMPLIANCE_FIELD = "Specification Compliance" +ENCODING_FIELD = "Encoding" +NOMINAL_BR_FIELD = "Nominal BR" +EXT_RATE_SELECT_COMPLIANCE_FIELD = "Extended RateSelect Compliance" +LENGTH_ASSEMBLY_FIELD = "Length Cable Assembly" + +ETHERNET_10_40G_COMPLIANCE_FIELD = "10/40G Ethernet Compliance Code" +SONET_COMPLIANCE_FIELD = "SONET Compliance Codes" +SAS_SATA_COMPLIANCE_FIELD = "SAS/SATA Compliance Codes" +GIGABIT_ETHERNET_COMPLIANCE_FIELD = "Gigabit Ethernet Compliant Codes" +FIBRE_CHANNEL_LINK_LENGTH_FIELD = "Fibre Channel Link Length" +FIBRE_CHANNEL_TRANSMITTER_TECH_FIELD = "Fibre Channel Transmitter Technology" +FIBRE_CHANNEL_TRANSMISSION_MEDIA_FIELD = "Fibre Channel Transmission Media" +FIBRE_CHANNEL_SPEED_FIELD = "Fibre Channel Speed" -# SFF-8436 +POWER_CTRL_FIELD = "Power Control" +POWER_OVERRIDE_FIELD = "Power Override" +POWER_SET_FIELD = "Power Set" # CMIS diff --git a/sonic_platform_base/sonic_xcvr/mem_maps/public/sff8436.py b/sonic_platform_base/sonic_xcvr/mem_maps/public/sff8436.py new file mode 100644 index 000000000000..652a0381dcd4 --- /dev/null +++ b/sonic_platform_base/sonic_xcvr/mem_maps/public/sff8436.py @@ -0,0 +1,137 @@ +from ..xcvr_mem_map import XcvrMemMap +from ...fields.xcvr_field import ( + CodeRegField, + HexRegField, + NumberRegField, + RegBitField, + RegGroupField, + StringRegField, +) +from ...fields import consts + +class Sff8436MemMap(XcvrMemMap): + def __init__(self, codes): + super(Sff8436MemMap, self).__init__(codes) + + self.STATUS = RegGroupField(consts.STATUS_FIELD, + NumberRegField(consts.STATUS_IND_BITS_FIELD, self.get_addr(0, 2), + RegBitField(consts.FLAT_MEM_FIELD, 2) + ) + ) + + self.SERIAL_ID = RegGroupField(consts.SERIAL_ID_FIELD, + CodeRegField(consts.ID_FIELD, self.get_addr(0, 128), self.codes.XCVR_IDENTIFIERS), + CodeRegField(consts.ID_ABBRV_FIELD, self.get_addr(0, 128), self.codes.XCVR_IDENTIFIER_ABBRV), + RegGroupField(consts.EXT_ID_FIELD, + CodeRegField(consts.POWER_CLASS_FIELD, 129, self.codes.POWER_CLASSES, + RegBitField("%s_6" % consts.POWER_CLASS_FIELD, 6), + RegBitField("%s_7" % consts.POWER_CLASS_FIELD, 7) + ), + CodeRegField(consts.CLEI_CODE_FIELD, 129, self.codes.CLEI_CODE, + RegBitField("%s_4" % consts.CLEI_CODE_FIELD, 4) + ), + CodeRegField(consts.CDR_TX_FIELD, 129, self.codes.CDR_TX, + RegBitField("%s_3" % consts.CDR_TX_FIELD, 3) + ), + CodeRegField(consts.CDR_RX_FIELD, 129, self.codes.CDR_RX, + RegBitField("%s_2" % consts.CDR_RX_FIELD, 2) + ), + ), + CodeRegField(consts.CONNECTOR_FIELD, 130, self.codes.CONNECTORS), + RegGroupField(consts.SPEC_COMPLIANCE_FIELD, + CodeRegField(consts.ETHERNET_10_40G_COMPLIANCE_FIELD, self.get_addr(0, 131), self.codes.ETHERNET_10_40G_COMPLIANCE), + CodeRegField(consts.SONET_COMPLIANCE_FIELD, self.get_addr(0, 132), self.codes.SONET_COMPLIANCE), + CodeRegField(consts.SAS_SATA_COMPLIANCE_FIELD, self.get_addr(0, 133), self.codes.SAS_SATA_COMPLIANCE), + CodeRegField(consts.GIGABIT_ETHERNET_COMPLIANCE_FIELD, self.get_addr(0, 134), self.codes.GIGABIT_ETHERNET_COMPLIANCE), + CodeRegField(consts.FIBRE_CHANNEL_LINK_LENGTH_FIELD, self.get_addr(0, 135), self.codes.FIBRE_CHANNEL_LINK_LENGTH, + *(RegBitField("%s_%d" % (consts.FIBRE_CHANNEL_LINK_LENGTH_FIELD, bit), bit) for bit in range(3, 8)) + ), + CodeRegField(consts.FIBRE_CHANNEL_TRANSMITTER_TECH_FIELD, self.get_addr(0, 135), self.codes.FIBRE_CHANNEL_TRANSMITTER_TECH, + *(RegBitField("%s_%d" % (consts.FIBRE_CHANNEL_TRANSMITTER_TECH_FIELD, bit), bit) for bit in list(range(0,3)) + list(range(8, 16))), + size=2, format="