diff --git a/device/dell/x86_64-dellemc_z9332f_d1508-r0/platform.json b/device/dell/x86_64-dellemc_z9332f_d1508-r0/platform.json new file mode 100644 index 00000000000..e8add067ca0 --- /dev/null +++ b/device/dell/x86_64-dellemc_z9332f_d1508-r0/platform.json @@ -0,0 +1,317 @@ +{ + "chassis": { + "name": "Z9332F-ON", + "components": [ + { + "name": "BIOS" + }, + { + "name": "FPGA" + }, + { + "name": "BMC" + }, + { + "name": "Baseboard CPLD" + }, + { + "name": "Switch CPLD 1" + }, + { + "name": "Switch CPLD 2" + } + ], + "fans": [ + { + "name": "FanTray1-Fan1" + }, + { + "name": "FanTray1-Fan2" + }, + { + "name": "FanTray2-Fan1" + }, + { + "name": "FanTray2-Fan2" + }, + { + "name": "FanTray3-Fan1" + }, + { + "name": "FanTray3-Fan2" + }, + { + "name": "FanTray4-Fan1" + }, + { + "name": "FanTray4-Fan2" + }, + { + "name": "FanTray5-Fan1" + }, + { + "name": "FanTray5-Fan2" + }, + { + "name": "FanTray6-Fan1" + }, + { + "name": "FanTray6-Fan2" + }, + { + "name": "FanTray7-Fan1" + }, + { + "name": "FanTray7-Fan2" + } + ], + "fan_drawers":[ + { + "name": "FanTray1", + "fans": [ + { + "name": "FanTray1-Fan1" + }, + { + "name": "FanTray1-Fan2" + } + ] + }, + { + "name": "FanTray2", + "fans": [ + { + "name": "FanTray2-Fan1" + }, + { + "name": "FanTray2-Fan2" + } + ] + }, + { + "name": "FanTray3", + "fans": [ + { + "name": "FanTray3-Fan1" + }, + { + "name": "FanTray3-Fan2" + } + ] + }, + { + "name": "FanTray4", + "fans": [ + { + "name": "FanTray4-Fan1" + }, + { + "name": "FanTray4-Fan2" + } + ] + }, + { + "name": "FanTray5", + "fans": [ + { + "name": "FanTray5-Fan1" + }, + { + "name": "FanTray5-Fan2" + } + ] + }, + { + "name": "FanTray6", + "fans": [ + { + "name": "FanTray6-Fan1" + }, + { + "name": "FanTray6-Fan2" + } + ] + }, + { + "name": "FanTray7", + "fans": [ + { + "name": "FanTray7-Fan1" + }, + { + "name": "FanTray7-Fan2" + } + ] + } + ], + "psus": [ + { + "name": "PSU1", + "fans": [ + { + "name": "PSU1 Fan" + } + ] + }, + { + "name": "PSU2", + "fans": [ + { + "name": "PSU2 Fan" + } + ] + } + ], + "thermals": [ + { + "name": "CPU On-board" + }, + { + "name": "Baseboard U3" + }, + { + "name": "SW Internal" + }, + { + "name": "Fan U52" + }, + { + "name": "Fan U17" + }, + { + "name": "SW U52" + }, + { + "name": "SW U16" + }, + { + "name": "PSU1 Inlet" + }, + { + "name": "PSU1 Hotspot" + }, + { + "name": "PSU2 Inlet" + }, + { + "name": "PSU2 Hotspot" + }, + { + "name": "SW U04" + }, + { + "name": "SW U14" + }, + { + "name": "SW U4403" + } + ], + "modules": [], + "sfps": [ + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "QSFP-DD Double Density 8X Pluggable Transceiver" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + } + + ] + }, + "interfaces": {} +} diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/chassis.py index 8ac97943cc0..e337922a342 100755 --- a/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/chassis.py +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/chassis.py @@ -366,3 +366,19 @@ def set_status_led(self, color): self.sys_ledcolor = color return True + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether Chassis is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/component.py index b564c166453..c60cc06b8f5 100644 --- a/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/component.py +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/component.py @@ -19,7 +19,8 @@ def get_bios_version(): - return subprocess.check_output(['dmidecode', '-s', 'bios-version']).strip() + return subprocess.check_output( + ['dmidecode', '-s', 'bios-version']).decode('utf-8').strip() def get_fpga_version(): val = hwaccess.pci_get_value('/sys/bus/pci/devices/0000:09:00.0/resource0', 0) @@ -28,7 +29,7 @@ def get_fpga_version(): def get_bmc_version(): return subprocess.check_output( ['cat', '/sys/class/ipmi/ipmi0/device/bmc/firmware_revision'] - ).strip() + ).decode('utf-8').strip() def get_cpld_version(bus, i2caddr): return '{}'.format(hwaccess.i2c_get(bus, i2caddr, 0)) @@ -120,3 +121,52 @@ def install_firmware(self, image_path): A boolean, True if install was successful, False if not """ return False + + def get_presence(self): + """ + Retrieves the presence of the component + Returns: + bool: True if present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the part number of the component + Returns: + string: Part number of component + """ + return 'NA' + + def get_serial(self): + """ + Retrieves the serial number of the component + Returns: + string: Serial number of component + """ + return 'NA' + + def get_status(self): + """ + Retrieves the operational status of the component + Returns: + bool: True if component is operating properly, False if not + """ + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether component is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/fan.py index d7bc0fdd392..6ffadb2a1e5 100755 --- a/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/fan.py +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/fan.py @@ -9,7 +9,7 @@ ######################################################################## try: from sonic_platform_base.fan_base import FanBase - from sonic_platform.ipmihelper import IpmiSensor, IpmiFru, get_ipmitool_raw_output + from sonic_platform.ipmihelper import IpmiSensor, get_ipmitool_raw_output except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -33,10 +33,6 @@ class Fan(FanBase): PSU_FAN_SENSOR_MAPPING = { 1: {"State": 0x2f, "Speed": 0x33}, 2: {"State": 0x39, "Speed": 0x3d} } - # { FANTRAY-ID: FRU-ID } - FAN_FRU_MAPPING = { 1: 6, 2: 7, 3: 8, 4: 9, 5: 10, 6: 11, 7: 12 } - PSU_FRU_MAPPING = { 1: 3, 2: 4 } - def __init__(self, fantray_index=1, fan_index=1, psu_fan=False, dependency=None): FanBase.__init__(self) self.is_psu_fan = psu_fan @@ -51,7 +47,6 @@ def __init__(self, fantray_index=1, fan_index=1, psu_fan=False, dependency=None) self.state_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["State"], is_discrete=True) self.speed_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Speed"]) - self.fru = IpmiFru(self.FAN_FRU_MAPPING[self.fantrayindex]) self.fan_dir_raw_cmd = "0x3a 0x0a {}".format(fantray_index) else: self.dependency = dependency @@ -59,7 +54,6 @@ def __init__(self, fantray_index=1, fan_index=1, psu_fan=False, dependency=None) self.state_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["State"], is_discrete=True) self.speed_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["Speed"]) - self.fru = IpmiFru(self.PSU_FRU_MAPPING[self.fanindex]) self.fan_dir_raw_cmd = "0x3a 0x0a {}".format(7+(fan_index-1)) self.max_speed = 23500 @@ -80,10 +74,7 @@ def get_model(self): Returns: String: Part number of FAN """ - if self.is_psu_fan: - return None - else: - return self.fru.get_board_part_number() + return 'NA' def get_serial(self): """ @@ -91,10 +82,7 @@ def get_serial(self): Returns: String: Serial number of FAN """ - if self.is_psu_fan: - return None - else: - return self.fru.get_board_serial() + return 'NA' def get_presence(self): """ @@ -159,7 +147,7 @@ def get_speed(self): if not is_valid or self.max_speed == 0: return None else: - speed = (100 * fan_speed)/self.max_speed + speed = (100 * fan_speed)//self.max_speed return speed def get_speed_rpm(self): @@ -170,3 +158,48 @@ def get_speed_rpm(self): """ is_valid, fan_speed = self.speed_sensor.get_reading() return fan_speed if is_valid else None + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return self.fanindex + + def is_replaceable(self): + """ + Indicate whether Fan is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def get_speed_tolerance(self): + """ + Retrieves the speed tolerance of the fan + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + if self.get_presence(): + # The tolerance value is fixed as 20% for all the DellEMC platforms + tolerance = 20 + else: + tolerance = 0 + + return tolerance + + def set_status_led(self, color): + """ + Set led to expected color + Args: + color: A string representing the color with which to set the + fan status LED + Returns: + bool: True if set success, False if fail. + """ + # Fan tray status LED controlled by HW + # Return True to avoid thermalctld alarm + return True diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/fan_drawer.py index 0fdc80e651e..f7ea8a4cbf6 100644 --- a/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/fan_drawer.py +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/fan_drawer.py @@ -11,6 +11,7 @@ try: from sonic_platform_base.fan_drawer_base import FanDrawerBase from sonic_platform.fan import Fan + from sonic_platform.ipmihelper import IpmiFru except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -20,6 +21,7 @@ class FanDrawer(FanDrawerBase): """DellEMC Platform-specific Fan class""" + FAN_FRU_MAPPING = { 1: 6, 2: 7, 3: 8, 4: 9, 5: 10, 6: 11, 7: 12 } def __init__(self, fantray_index): FanDrawerBase.__init__(self) @@ -27,6 +29,7 @@ def __init__(self, fantray_index): self.fantrayindex = fantray_index + 1 for i in range(Z9332F_FANS_PER_FANTRAY): self._fan_list.append(Fan(fantray_index, i)) + self.fru = IpmiFru(self.FAN_FRU_MAPPING[self.fantrayindex]) def get_name(self): """ @@ -35,3 +38,68 @@ def get_name(self): string: The name of the device """ return "FanTray{}".format(self.fantrayindex) + + def get_presence(self): + """ + Retrieves the presence of the fan drawer + Returns: + bool: True if fan_tray is present, False if not + """ + return self.get_fan(0).get_presence() + + def get_model(self): + """ + Retrieves the part number of the fan drawer + Returns: + string: Part number of fan drawer + """ + return self.fru.get_board_part_number() + + def get_serial(self): + """ + Retrieves the serial number of the fan drawer + Returns: + string: Serial number of the fan drawer + """ + return self.fru.get_board_serial() + + def get_status(self): + """ + Retrieves the operational status of the fan drawer + Returns: + bool: True if fan drawer is operating properly, False if not + """ + status = True + for fan in self.get_all_fans(): + status &= fan.get_status() + return status + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return self.fantrayindex + + def is_replaceable(self): + """ + Indicate whether this fan drawer is replaceable. + Returns: + bool: True if it is replaceable, False if not + """ + return True + + def set_status_led(self, color): + """ + Set led to expected color + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if set success, False if fail. + """ + # Fan tray status LED controlled by BMC + # Return True to avoid thermalctld alarm + return True diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/psu.py index afd9c5a26a6..a12ecbc65d8 100644 --- a/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/psu.py +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/psu.py @@ -212,3 +212,20 @@ def get_type(self): if type_res is not None and len(type_res) == 1 : return psu_type[type_res[0]] return None + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return self.index + + def is_replaceable(self): + """ + Indicate whether this PSU is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/sfp.py index efda0d13c63..a6aa228ac33 100644 --- a/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/sfp.py +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/sfp.py @@ -10,6 +10,7 @@ try: import os + import re import time import subprocess import struct @@ -75,7 +76,8 @@ 'manufacturer', 'model', 'connector', 'encoding', 'ext_identifier', 'ext_rateselect_compliance', 'cable_type', 'cable_length', 'nominal_bit_rate', - 'specification_compliance', 'type_abbrv_name','vendor_date', 'vendor_oui'] + 'specification_compliance', 'type_abbrv_name', 'vendor_date', + 'vendor_oui', 'application_advertisement'] dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', 'tx_disable', 'tx_disable_channel', @@ -236,6 +238,15 @@ def __init__(self, index, sfp_type, eeprom_path): def get_eeprom_sysfs_path(self): return self.eeprom_path + def _strip_unit_from_str(self, value_str): + match = re.match(r'(.*)C$|(.*)Volts$|(.*)mA$|(.*)dBm$', value_str) + if match: + for value in match.groups(): + if value is not None: + return float(value) + + return None + def pci_mem_read(self, mm, offset): mm.seek(offset) read_data_stream = mm.read(4) @@ -356,8 +367,8 @@ def get_transceiver_info(self): compliance_code_dict = {} transceiver_info_dict = dict.fromkeys(info_dict_keys, 'N/A') self.media_type = self.set_media_type() - if self.reinit_sfp_driver() == False: - return transceiver_info_dict + if not self.reinit_sfp_driver(): + return transceiver_info_dict # BaseInformation try: @@ -663,59 +674,59 @@ def get_rx_los(self): """ Retrieves the RX LOS (lost-of-signal) status of SFP """ - rx_los = False + rx_los_list = [] try: if self.media_type.startswith('QSFP'): rx_los_data = self._get_eeprom_data('rx_los') # As the function expects a single boolean, if any one channel experience LOS, # is considered LOS for QSFP for rx_los_id in ('Rx1LOS', 'Rx2LOS', 'Rx3LOS', 'Rx4LOS') : - rx_los |= (rx_los_data['data'][rx_los_id]['value'] is 'On') + rx_los_list.append(rx_los_data['data'][rx_los_id]['value'] == 'On') else: rx_los_data = self._read_eeprom_bytes(self.eeprom_path, SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) data = int(rx_los_data[0], 16) - rx_los = sffbase().test_bit(data, 1) != 0 + rx_los_list.append(sffbase().test_bit(data, 1) != 0) except (TypeError, ValueError): return 'N/A' - return rx_los + return rx_los_list def get_tx_fault(self): """ Retrieves the TX fault status of SFP """ - tx_fault = False + tx_fault_list = [] try: if self.media_type.startswith('QSFP'): tx_fault_data = self._get_eeprom_data('tx_fault') for tx_fault_id in ('Tx1Fault', 'Tx2Fault', 'Tx3Fault', 'Tx4Fault') : - tx_fault |= (tx_fault_data['data'][tx_fault_id]['value'] is 'On') + tx_fault_list.append(tx_fault_data['data'][tx_fault_id]['value'] == 'On') else: tx_fault_data = self._read_eeprom_bytes(self.eeprom_path, SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) data = int(tx_fault_data[0], 16) - tx_fault = (sffbase().test_bit(data, 2) != 0) + tx_fault_list.append(sffbase().test_bit(data, 2) != 0) except (TypeError, ValueError): return 'N/A' - return tx_fault + return tx_fault_list def get_tx_disable(self): """ Retrieves the tx_disable status of this SFP """ - tx_disable = False + tx_disable_list = [] try: if self.media_type.startswith('QSFP'): tx_disable_data = self._get_eeprom_data('tx_disable') for tx_disable_id in ('Tx1Disable', 'Tx2Disable', 'Tx3Disable', 'Tx4Disable'): - tx_disable |= (tx_disable_data['data'][tx_disable_id]['value'] is 'On') + tx_disable_list.append(tx_disable_data['data'][tx_disable_id]['value'] == 'On') else: tx_disable_data = self._read_eeprom_bytes(self.eeprom_path, SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) data = int(tx_disable_data[0], 16) tx_disable_hard = (sffbase().test_bit(data, SFP_TX_DISABLE_HARD_BIT) != 0) tx_disable_soft = (sffbase().test_bit(data, SFP_TX_DISABLE_SOFT_BIT) != 0) - tx_disable = tx_disable_hard | tx_disable_soft + tx_disable_list.append(tx_disable_hard | tx_disable_soft) except (TypeError, ValueError): return 'N/A' - return tx_disable + return tx_disable_list def get_tx_disable_channel(self): """ @@ -727,7 +738,7 @@ def get_tx_disable_channel(self): tx_disable_data = self._get_eeprom_data('tx_disable') for tx_disable_id in ('Tx1Disable', 'Tx2Disable', 'Tx3Disable', 'Tx4Disable'): tx_disable_channel <<= 1 - tx_disable_channel |= (tx_disable_data['data']['Tx1Disable']['value'] is 'On') + tx_disable_channel |= (tx_disable_data['data']['Tx1Disable']['value'] == 'On') except (TypeError, ValueError): return 'N/A' return tx_disable_channel @@ -762,7 +773,7 @@ def get_power_override(self): if self.media_type.startswith('QSFP'): power_override_data = self._get_eeprom_data('power_override') power_override = power_override_data['data']['PowerOverRide']['value'] - power_override_state = (power_override is 'On') + power_override_state = (power_override == 'On') except (TypeError, ValueError): pass return power_override_state @@ -773,7 +784,7 @@ def get_temperature(self): temperature = None try : temperature_data = self._get_eeprom_data('Temperature') - temperature = temperature_data['data']['Temperature']['value'] + temperature = self._strip_unit_from_str(temperature_data['data']['Temperature']['value']) except (TypeError, ValueError): return None return temperature @@ -785,7 +796,7 @@ def get_voltage(self): voltage = None try: voltage_data = self._get_eeprom_data('Voltage') - voltage = voltage_data['data']['Vcc']['value'] + voltage = self._strip_unit_from_str(voltage_data['data']['Vcc']['value']) except (TypeError, ValueError): return None return voltage @@ -799,11 +810,11 @@ def get_tx_bias(self): tx_bias_data = self._get_eeprom_data('ChannelMonitor') if self.media_type.startswith('QSFP'): for tx_bias_id in ('TX1Bias', 'TX2Bias', 'TX3Bias', 'TX4Bias') : - tx_bias = tx_bias_data['data'][tx_bias_id]['value'] + tx_bias = self._strip_unit_from_str(tx_bias_data['data'][tx_bias_id]['value']) tx_bias_list.append(tx_bias) else: tx1_bias = tx_bias_data['data']['TXBias']['value'] - tx_bias_list = [tx1_bias, "N/A", "N/A", "N/A"] + tx_bias_list.append(self._strip_unit_from_str(tx1_bias)) except (TypeError, ValueError): return None return tx_bias_list @@ -817,11 +828,11 @@ def get_rx_power(self): rx_power_data = self._get_eeprom_data('ChannelMonitor') if self.media_type.startswith('QSFP'): for rx_power_id in ('RX1Power', 'RX2Power', 'RX3Power', 'RX4Power'): - rx_power = rx_power_data['data'][rx_power_id]['value'] - rx_power_list.append(rx_power) + rx_power = self._strip_unit_from_str(rx_power_data['data'][rx_power_id]['value']) + rx_power_list.append(self._strip_unit_from_str(rx_power)) else: rx1_pw = rx_power_data['data']['RXPower']['value'] - rx_power_list = [rx1_pw, "N/A", "N/A", "N/A"] + rx_power_list.append(self._strip_unit_from_str(rx1_pw)) except (TypeError, ValueError): return None return rx_power_list @@ -849,11 +860,11 @@ def get_tx_power(self): channel_monitor_data = self._get_eeprom_data('ChannelMonitor_TxPower') for tx_power_id in ('TX1Power', 'TX2Power', 'TX3Power', 'TX4Power'): tx_pw = channel_monitor_data['data'][tx_power_id]['value'] - tx_power_list.append(tx_pw) + tx_power_list.append(self._strip_unit_from_str(tx_pw)) else: channel_monitor_data = self._get_eeprom_data('ChannelMonitor') tx1_pw = channel_monitor_data['data']['TXPower']['value'] - tx_power_list = [tx1_pw, 'N/A', 'N/A', 'N/A'] + tx_power_list.append(self._strip_unit_from_str(tx1_pw)) except (TypeError, ValueError): return None return tx_power_list @@ -1012,7 +1023,7 @@ def reinit_sfp_driver(self): if not os.path.isfile(driver_path): print(driver_path, "does not exist") return False - + try: with os.fdopen(os.open(driver_path, os.O_RDONLY)) as fd: driver_name = fd.read() @@ -1038,3 +1049,23 @@ def reinit_sfp_driver(self): except IOError as e: print("Error: Unable to open file: %s" % str(e)) + return False + + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return self.index + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/thermal.py index 1c7fe59857a..578be59735a 100644 --- a/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/thermal.py +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/thermal.py @@ -19,28 +19,30 @@ class Thermal(ThermalBase): """DellEMC Platform-specific Thermal class""" - # [ Sensor-Name, Sensor-ID ] + # [ Sensor-Name, Sensor-ID, high threshold, high critical_threshold ] SENSOR_MAPPING = [ - ['CPU On-board', 0x5], - ['Baseboard U3', 0x4], - ['SW Internal', 0x61], - ['Fan U52', 0x0], - ['Fan U17', 0x1], - ['SW U52', 0x2], - ['SW U16', 0x3], - ['PSU1 Inlet', 0x34], - ['PSU1 Hotspot', 0x35], - ['PSU2 Inlet', 0x3E], - ['PSU2 Hotspot', 0x3F], - ['SW U04', 0x4F], - ['SW U14', 0x56], - ['SW U4403', 0x5D] + ['CPU On-board', 0x5, False, True], + ['Baseboard U3', 0x4, False, False], + ['SW Internal', 0x61, True, True], + ['Fan U52', 0x0, True, True], + ['Fan U17', 0x1, False, False], + ['SW U52', 0x2, False, False], + ['SW U16', 0x3, True, True], + ['PSU1 Inlet', 0x34, False, False], + ['PSU1 Hotspot', 0x35, False, False], + ['PSU2 Inlet', 0x3E, False, False], + ['PSU2 Hotspot', 0x3F, False, False], + ['SW U04', 0x4F, False, False], + ['SW U14', 0x56, False, False], + ['SW U4403', 0x5D, False, False] ] def __init__(self, thermal_index=0): ThermalBase.__init__(self) self.index = thermal_index + 1 self.sensor = IpmiSensor(self.SENSOR_MAPPING[self.index - 1][1]) + self.has_high_threshold = self.SENSOR_MAPPING[self.index - 1][2] + self.has_high_crit_threshold = self.SENSOR_MAPPING[self.index - 1][3] def get_name(self): """ @@ -111,11 +113,12 @@ def get_high_threshold(self): Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ - is_valid, high_threshold = self.sensor.get_threshold("UpperNonCritical") - if not is_valid: - return super(Thermal, self).get_high_threshold() + if self.has_high_threshold: + is_valid, high_threshold = self.sensor.get_threshold("UpperNonCritical") + if is_valid: + return float(high_threshold) - return float(high_threshold) + return super(Thermal, self).get_high_threshold() def get_low_threshold(self): """ @@ -126,11 +129,7 @@ def get_low_threshold(self): Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ - is_valid, low_threshold = self.sensor.get_threshold("LowerNonRecoverable") - if not is_valid: - low_threshold = 0 - - return float(low_threshold) + return 0.0 def get_high_critical_threshold(self): """ @@ -140,12 +139,12 @@ def get_high_critical_threshold(self): thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ - is_valid, high_crit_threshold = self.sensor.get_threshold("UpperCritical") - if not is_valid: - return super(Thermal, self).get_high_critical_threshold() + if self.has_high_crit_threshold: + is_valid, high_crit_threshold = self.sensor.get_threshold("UpperCritical") + if is_valid: + return float(high_crit_threshold) - return float(high_crit_threshold) - + return super(Thermal, self).get_high_critical_threshold() def set_high_threshold(self, temperature): """ @@ -174,3 +173,20 @@ def set_low_threshold(self, temperature): """ # Thermal threshold values are pre-defined based on HW. return False + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return self.index + + def is_replaceable(self): + """ + Indicate whether this Thermal is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/watchdog.py index 76a7584e91a..55460bdf06e 100644 --- a/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/watchdog.py +++ b/platform/broadcom/sonic-platform-modules-dell/z9332f/sonic_platform/watchdog.py @@ -11,8 +11,8 @@ try: import ctypes - import subprocess from sonic_platform_base.watchdog_base import WatchdogBase + from sonic_platform.hwaccess import io_reg_read, io_reg_write except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -29,7 +29,14 @@ class Watchdog(WatchdogBase): Abstract base class for interfacing with a hardware watchdog module """ - TIMERS = [15,20,30,40,50,60,65,70] + TIMERS = [0.2, 30, 60, 180, 240, 300, 420, 600] + io_resource = "/dev/port" + wd_timer_offset = 0xA181 + wd_status_offset = 0xA182 + wd_timer_punch_offset = 0xA184 + wd_enable = 1 + wd_disable = 0 + wd_punch_enable = 0 armed_time = 0 timeout = 0 @@ -41,34 +48,6 @@ def __init__(self): self._clock_gettime = self._librt.clock_gettime self._clock_gettime.argtypes=[ctypes.c_int, ctypes.POINTER(_timespec)] - def _get_command_result(self, cmdline): - try: - proc = subprocess.Popen(cmdline.split(), stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - stdout = proc.communicate()[0] - proc.wait() - result = stdout.rstrip('\n') - except OSError: - result = None - - return result - - def _get_reg_val(self): - # 0x31 = CPLD I2C Base Address - # 0x07 = Watchdog Function Register - value = self._get_command_result("/usr/sbin/i2cget -y 601 0x31 0x07") - if not value: - return None - else: - return int(value, 16) - - def _set_reg_val(self,val): - # 0x31 = CPLD I2C Base Address - # 0x07 = Watchdog Function Register - value = self._get_command_result("/usr/sbin/i2cset -y 601 0x31 0x07 %s" - % (val)) - return value - def _get_time(self): """ To get clock monotonic time @@ -94,7 +73,7 @@ def arm(self, seconds): """ timer_offset = -1 for key,timer_seconds in enumerate(self.TIMERS): - if seconds <= timer_seconds: + if seconds > 0 and seconds <= timer_seconds: timer_offset = key seconds = timer_seconds break @@ -102,43 +81,25 @@ def arm(self, seconds): if timer_offset == -1: return -1 - # Extracting 5th to 7th bits for WD timer values - # 000 - 15 sec - # 001 - 20 sec - # 010 - 30 sec - # 011 - 40 sec - # 100 - 50 sec - # 101 - 60 sec - # 110 - 65 sec - # 111 - 70 sec - reg_val = self._get_reg_val() - wd_timer_offset = (reg_val >> 4) & 0x7 - - if wd_timer_offset != timer_offset: - # Setting 5th to 7th bits - # value from timer_offset + wd_timer_val = io_reg_read(self.io_resource, self.wd_timer_offset) + + if wd_timer_val != timer_offset: self.disarm() - self._set_reg_val(reg_val | (timer_offset << 4)) + io_reg_write(self.io_resource, self.wd_timer_offset, timer_offset) if self.is_armed(): - # Setting last bit to WD Timer punch - # Last bit = WD Timer punch - self._set_reg_val(reg_val & 0xFE) - + # Setting the WD timer punch + io_reg_write(self.io_resource, self.wd_timer_punch_offset, self.wd_punch_enable) self.armed_time = self._get_time() self.timeout = seconds return seconds else: - # Setting 4th bit to enable WD - # 4th bit = Enable WD - reg_val = self._get_reg_val() - self._set_reg_val(reg_val | 0x8) - + # Enable WD + io_reg_write(self.io_resource, self.wd_status_offset, self.wd_enable) self.armed_time = self._get_time() self.timeout = seconds return seconds - def disarm(self): """ Disarm the hardware watchdog @@ -148,11 +109,8 @@ def disarm(self): if not """ if self.is_armed(): - # Setting 4th bit to disable WD - # 4th bit = Disable WD - reg_val = self._get_reg_val() - self._set_reg_val(reg_val & 0xF7) - + # Disable WD + io_reg_write(self.io_resource, self.wd_status_offset, self.wd_disable) self.armed_time = 0 self.timeout = 0 return True @@ -166,14 +124,11 @@ def is_armed(self): Returns: A boolean, True if watchdog is armed, False if not """ - - # Extracting 4th bit to get WD Enable/Disable status + # Getting the WD Enable/Disable status # 0 - Disabled WD # 1 - Enabled WD - reg_val = self._get_reg_val() - wd_offset = (reg_val >> 3) & 1 - - return bool(wd_offset) + wd_status = io_reg_read(self.io_resource, self.wd_status_offset) + return bool(wd_status) def get_remaining_time(self): """ @@ -185,7 +140,7 @@ def get_remaining_time(self): their watchdog timer. If the watchdog is not armed, returns -1. - S5232 doesnot have hardware support to show remaining time. + Z9332 does not have hardware support to show remaining time. Due to this limitation, this API is implemented in software. This API would return correct software time difference if it is called from the process which armed the watchdog timer.