DellEMC: Z9332F - Watchdog support, add platform.json, new platform API implementation and fixes (#6988)
Incorporate the below changes in DellEMC Z9332F platform: - Implemented watchdog platform API support - Implement ‘get_position_in_parent’, ‘is_replaceable’ methods for all device types - Change return type of SFP methods to match specification in sonic_platform_common/sfp_base.py - Added platform.json file in device directory. Co-authored-by: V P Subramaniam <Subramaniam_Vellalap@dell.com>
This commit is contained in:
parent
5221e68b99
commit
377ea1a229
317
device/dell/x86_64-dellemc_z9332f_d1508-r0/platform.json
Normal file
317
device/dell/x86_64-dellemc_z9332f_d1508-r0/platform.json
Normal file
@ -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": {}
|
||||
}
|
@ -366,3 +366,19 @@ class Chassis(ChassisBase):
|
||||
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
|
||||
|
@ -19,7 +19,8 @@ except ImportError as e:
|
||||
|
||||
|
||||
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 @@ class Component(ComponentBase):
|
||||
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
|
||||
|
@ -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 @@ class Fan(FanBase):
|
||||
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 @@ class Fan(FanBase):
|
||||
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 @@ class Fan(FanBase):
|
||||
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 @@ class Fan(FanBase):
|
||||
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 @@ class Fan(FanBase):
|
||||
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 @@ class Fan(FanBase):
|
||||
"""
|
||||
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
|
||||
|
@ -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 @@ Z9332F_FANS_PER_FANTRAY = 2
|
||||
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 @@ class FanDrawer(FanDrawerBase):
|
||||
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 @@ class FanDrawer(FanDrawerBase):
|
||||
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
|
||||
|
@ -212,3 +212,20 @@ class Psu(PsuBase):
|
||||
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
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
try:
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import subprocess
|
||||
import struct
|
||||
@ -75,7 +76,8 @@ info_dict_keys = ['type', 'hardware_rev', 'serial',
|
||||
'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 @@ class Sfp(SfpBase):
|
||||
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 @@ class Sfp(SfpBase):
|
||||
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 @@ class Sfp(SfpBase):
|
||||
"""
|
||||
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 @@ class Sfp(SfpBase):
|
||||
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 @@ class Sfp(SfpBase):
|
||||
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 @@ class Sfp(SfpBase):
|
||||
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 @@ class Sfp(SfpBase):
|
||||
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 @@ class Sfp(SfpBase):
|
||||
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 @@ class Sfp(SfpBase):
|
||||
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 @@ class Sfp(SfpBase):
|
||||
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 @@ class Sfp(SfpBase):
|
||||
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 @@ class Sfp(SfpBase):
|
||||
|
||||
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
|
||||
|
@ -19,28 +19,30 @@ except ImportError as e:
|
||||
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 @@ class Thermal(ThermalBase):
|
||||
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 @@ class Thermal(ThermalBase):
|
||||
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 @@ class Thermal(ThermalBase):
|
||||
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 @@ class Thermal(ThermalBase):
|
||||
"""
|
||||
# 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
|
||||
|
@ -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 @@ class Watchdog(WatchdogBase):
|
||||
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 @@ class Watchdog(WatchdogBase):
|
||||
"""
|
||||
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 @@ class Watchdog(WatchdogBase):
|
||||
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
|
||||
wd_timer_val = io_reg_read(self.io_resource, self.wd_timer_offset)
|
||||
|
||||
if wd_timer_offset != timer_offset:
|
||||
# Setting 5th to 7th bits
|
||||
# value from 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 @@ class Watchdog(WatchdogBase):
|
||||
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 @@ class Watchdog(WatchdogBase):
|
||||
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 @@ class Watchdog(WatchdogBase):
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user