DellEMC S6000 : Platform2.0 API implementation [PSU, Thermal] (#3357)
* DellEMC S6000 : Platform2.0 API implementation [PSU, Thermal] * Fix invalid number of arguments error * DellEMC S6000 : Platform2.0 [ Thermal ] * DellEMC S6000 : Platform2.0 API [PSU, Thermal] * Updated merge changes
This commit is contained in:
parent
19ffb027d2
commit
6ca0d7b197
platform/broadcom/sonic-platform-modules-dell/s6000
@ -549,6 +549,18 @@ static ssize_t get_psu1_status(struct device *dev, struct device_attribute *deva
|
||||
return sprintf(buf, "%d\n", data);
|
||||
}
|
||||
|
||||
static ssize_t get_powersupply_status(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int data;
|
||||
struct cpld_platform_data *pdata = dev->platform_data;
|
||||
|
||||
data = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x3);
|
||||
if (data < 0)
|
||||
return sprintf(buf, "read error");
|
||||
|
||||
return sprintf(buf, "%x\n", data);
|
||||
}
|
||||
|
||||
static ssize_t get_system_led(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int ret;
|
||||
@ -1126,6 +1138,7 @@ static DEVICE_ATTR(psu0_prs, S_IRUGO, get_psu0_prs, NULL);
|
||||
static DEVICE_ATTR(psu1_prs, S_IRUGO, get_psu1_prs, NULL);
|
||||
static DEVICE_ATTR(psu0_status, S_IRUGO, get_psu0_status, NULL);
|
||||
static DEVICE_ATTR(psu1_status, S_IRUGO, get_psu1_status, NULL);
|
||||
static DEVICE_ATTR(powersupply_status, S_IRUGO, get_powersupply_status, NULL);
|
||||
static DEVICE_ATTR(system_led, S_IRUGO | S_IWUSR, get_system_led, set_system_led);
|
||||
static DEVICE_ATTR(locator_led, S_IRUGO | S_IWUSR, get_locator_led, set_locator_led);
|
||||
static DEVICE_ATTR(power_led, S_IRUGO | S_IWUSR, get_power_led, set_power_led);
|
||||
@ -1150,6 +1163,7 @@ static struct attribute *s6000_cpld_attrs[] = {
|
||||
&dev_attr_psu1_prs.attr,
|
||||
&dev_attr_psu0_status.attr,
|
||||
&dev_attr_psu1_status.attr,
|
||||
&dev_attr_powersupply_status.attr,
|
||||
&dev_attr_system_led.attr,
|
||||
&dev_attr_locator_led.attr,
|
||||
&dev_attr_power_led.attr,
|
||||
|
@ -1,2 +1,2 @@
|
||||
__all__ = ["platform", "chassis", "sfp"]
|
||||
__all__ = ["platform", "chassis", "sfp", "psu", "thermal"]
|
||||
from sonic_platform import *
|
||||
|
@ -16,11 +16,15 @@ try:
|
||||
from sonic_platform.sfp import Sfp
|
||||
from sonic_platform.eeprom import Eeprom
|
||||
from sonic_platform.fan import Fan
|
||||
from sonic_platform.psu import Psu
|
||||
from sonic_platform.thermal import Thermal
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
MAX_S6000_FAN = 3
|
||||
MAX_S6000_PSU = 2
|
||||
MAX_S6000_THERMAL = 10
|
||||
|
||||
BIOS_QUERY_VERSION_COMMAND = "dmidecode -s system-version"
|
||||
#components definitions
|
||||
@ -75,6 +79,14 @@ class Chassis(ChassisBase):
|
||||
fan = Fan(i)
|
||||
self._fan_list.append(fan)
|
||||
|
||||
for i in range(MAX_S6000_PSU):
|
||||
psu = Psu(i)
|
||||
self._psu_list.append(psu)
|
||||
|
||||
for i in range(MAX_S6000_THERMAL):
|
||||
thermal = Thermal(i)
|
||||
self._thermal_list.append(thermal)
|
||||
|
||||
# Initialize component list
|
||||
self._component_name_list.append(COMPONENT_BIOS)
|
||||
self._component_name_list.append(COMPONENT_CPLD1)
|
||||
|
@ -0,0 +1,240 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
########################################################################
|
||||
# DellEMC S6000
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the PSUs' information which are available in the platform
|
||||
#
|
||||
########################################################################
|
||||
|
||||
|
||||
try:
|
||||
import os
|
||||
from sonic_platform_base.psu_base import PsuBase
|
||||
from sonic_platform.eeprom import Eeprom
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Psu(PsuBase):
|
||||
"""DellEMC Platform-specific PSU class"""
|
||||
|
||||
CPLD_DIR = "/sys/devices/platform/dell-s6000-cpld.0/"
|
||||
I2C_DIR = "/sys/class/i2c-adapter/"
|
||||
|
||||
def __init__(self, psu_index):
|
||||
# PSU is 1-based in DellEMC platforms
|
||||
self.index = psu_index + 1
|
||||
self.psu_presence_reg = "psu{}_prs".format(psu_index)
|
||||
self.psu_status_reg = "powersupply_status"
|
||||
|
||||
if self.index == 1:
|
||||
ltc_dir = self.I2C_DIR + "i2c-11/11-0042/hwmon/"
|
||||
else:
|
||||
ltc_dir = self.I2C_DIR + "i2c-11/11-0040/hwmon/"
|
||||
hwmon_node = os.listdir(ltc_dir)[0]
|
||||
self.HWMON_DIR = ltc_dir + hwmon_node + '/'
|
||||
|
||||
self.psu_voltage_reg = self.HWMON_DIR + "in1_input"
|
||||
self.psu_current_reg = self.HWMON_DIR + "curr1_input"
|
||||
self.psu_power_reg = self.HWMON_DIR + "power1_input"
|
||||
|
||||
self.eeprom = Eeprom(is_psu=True, psu_index=self.index)
|
||||
|
||||
# Overriding _fan_list class variable defined in PsuBase, to
|
||||
# make it unique per Psu object
|
||||
self._fan_list = []
|
||||
|
||||
def _get_cpld_register(self, reg_name):
|
||||
# On successful read, returns the value read from given
|
||||
# reg_name and on failure returns 'ERR'
|
||||
rv = 'ERR'
|
||||
cpld_reg_file = self.CPLD_DIR + reg_name
|
||||
|
||||
if (not os.path.isfile(cpld_reg_file)):
|
||||
return rv
|
||||
|
||||
try:
|
||||
with open(cpld_reg_file, 'r') as fd:
|
||||
rv = fd.read()
|
||||
except:
|
||||
rv = 'ERR'
|
||||
|
||||
rv = rv.rstrip('\r\n')
|
||||
rv = rv.lstrip(" ")
|
||||
return rv
|
||||
|
||||
def _get_i2c_register(self, reg_file):
|
||||
# On successful read, returns the value read from given
|
||||
# reg_name and on failure returns 'ERR'
|
||||
rv = 'ERR'
|
||||
|
||||
if (not os.path.isfile(reg_file)):
|
||||
return rv
|
||||
|
||||
try:
|
||||
with open(reg_file, 'r') as fd:
|
||||
rv = fd.read()
|
||||
except:
|
||||
rv = 'ERR'
|
||||
|
||||
rv = rv.rstrip('\r\n')
|
||||
rv = rv.lstrip(" ")
|
||||
return rv
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
return "PSU{}".format(self.index)
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the Power Supply Unit (PSU)
|
||||
|
||||
Returns:
|
||||
bool: True if PSU is present, False if not
|
||||
"""
|
||||
status = False
|
||||
psu_presence = self._get_cpld_register(self.psu_presence_reg)
|
||||
if (psu_presence != 'ERR'):
|
||||
psu_presence = int(psu_presence)
|
||||
if psu_presence:
|
||||
status = True
|
||||
|
||||
return status
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the part number of the PSU
|
||||
|
||||
Returns:
|
||||
string: Part number of PSU
|
||||
"""
|
||||
return self.eeprom.part_number_str()
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the PSU
|
||||
|
||||
Returns:
|
||||
string: Serial number of PSU
|
||||
"""
|
||||
# Sample Serial number format "US-01234D-54321-25A-0123-A00"
|
||||
return self.eeprom.serial_number_str()
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the PSU
|
||||
|
||||
Returns:
|
||||
bool: True if PSU is operating properly, False if not
|
||||
"""
|
||||
status = False
|
||||
psu_status = self._get_cpld_register(self.psu_status_reg)
|
||||
if (psu_status != 'ERR'):
|
||||
psu_status = (int(psu_status, 16) >> ((2 - self.index) * 4)) & 0xF
|
||||
if (~psu_status & 0b1000) and (~psu_status & 0b0100):
|
||||
status = True
|
||||
|
||||
return status
|
||||
|
||||
def get_voltage(self):
|
||||
"""
|
||||
Retrieves current PSU voltage output
|
||||
|
||||
Returns:
|
||||
A float number, the output voltage in volts,
|
||||
e.g. 12.1
|
||||
"""
|
||||
psu_voltage = self._get_i2c_register(self.psu_voltage_reg)
|
||||
if (psu_voltage != 'ERR') and self.get_status():
|
||||
# Converting the value returned by driver which is in
|
||||
# millivolts to volts
|
||||
psu_voltage = float(psu_voltage) / 1000
|
||||
else:
|
||||
psu_voltage = 0.0
|
||||
|
||||
return psu_voltage
|
||||
|
||||
def get_current(self):
|
||||
"""
|
||||
Retrieves present electric current supplied by PSU
|
||||
|
||||
Returns:
|
||||
A float number, electric current in amperes,
|
||||
e.g. 15.4
|
||||
"""
|
||||
psu_current = self._get_i2c_register(self.psu_current_reg)
|
||||
if (psu_current != 'ERR') and self.get_status():
|
||||
# Converting the value returned by driver which is in
|
||||
# milliamperes to amperes
|
||||
psu_current = float(psu_current) / 1000
|
||||
else:
|
||||
psu_current = 0.0
|
||||
|
||||
return psu_current
|
||||
|
||||
def get_power(self):
|
||||
"""
|
||||
Retrieves current energy supplied by PSU
|
||||
|
||||
Returns:
|
||||
A float number, the power in watts,
|
||||
e.g. 302.6
|
||||
"""
|
||||
psu_power = self._get_i2c_register(self.psu_power_reg)
|
||||
if (psu_power != 'ERR') and self.get_status():
|
||||
# Converting the value returned by driver which is in
|
||||
# microwatts to watts
|
||||
psu_power = float(psu_power) / 1000000
|
||||
else:
|
||||
psu_power = 0.0
|
||||
|
||||
return psu_power
|
||||
|
||||
def get_powergood_status(self):
|
||||
"""
|
||||
Retrieves the powergood status of PSU
|
||||
Returns:
|
||||
A boolean, True if PSU has stablized its output voltages and
|
||||
passed all its internal self-tests, False if not.
|
||||
"""
|
||||
status = False
|
||||
psu_status = self._get_cpld_register(self.psu_status_reg)
|
||||
if (psu_status != 'ERR'):
|
||||
psu_status = (int(psu_status, 16) >> ((2 - self.index) * 4)) & 0xF
|
||||
if (psu_status == 0x2):
|
||||
status = True
|
||||
|
||||
return status
|
||||
|
||||
def get_status_led(self):
|
||||
"""
|
||||
Gets the state of the PSU status LED
|
||||
|
||||
Returns:
|
||||
A string, one of the predefined STATUS_LED_COLOR_* strings.
|
||||
"""
|
||||
if self.get_powergood_status():
|
||||
return self.STATUS_LED_COLOR_GREEN
|
||||
else:
|
||||
return self.STATUS_LED_COLOR_OFF
|
||||
|
||||
def set_status_led(self, color):
|
||||
"""
|
||||
Sets the state of the PSU status LED
|
||||
Args:
|
||||
color: A string representing the color with which to set the
|
||||
PSU status LED
|
||||
Returns:
|
||||
bool: True if status LED state is set successfully, False if
|
||||
not
|
||||
"""
|
||||
# In S6000, the firmware running in the PSU controls the LED
|
||||
# and the PSU LED state cannot be changed from CPU.
|
||||
return False
|
@ -0,0 +1,217 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
########################################################################
|
||||
# DellEMC S6000
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the Thermals' information which are available in the platform
|
||||
#
|
||||
########################################################################
|
||||
|
||||
|
||||
try:
|
||||
import os
|
||||
from sonic_platform_base.thermal_base import ThermalBase
|
||||
from sonic_platform.psu import Psu
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Thermal(ThermalBase):
|
||||
"""DellEMC Platform-specific Thermal class"""
|
||||
|
||||
I2C_DIR = "/sys/class/i2c-adapter/"
|
||||
I2C_DEV_MAPPING = (['i2c-11/11-004c/hwmon/', 1],
|
||||
['i2c-11/11-004d/hwmon/', 1],
|
||||
['i2c-11/11-004e/hwmon/', 1],
|
||||
['i2c-10/10-0018/hwmon/', 1],
|
||||
['i2c-1/1-0059/hwmon/', 1],
|
||||
['i2c-1/1-0059/hwmon/', 2],
|
||||
['i2c-1/1-0058/hwmon/', 1],
|
||||
['i2c-1/1-0058/hwmon/', 2])
|
||||
THERMAL_NAME = ('ASIC On-board', 'NIC', 'System Front', 'DIMM',
|
||||
'PSU1-Sensor 1', 'PSU1-Sensor 2', 'PSU2-Sensor 1',
|
||||
'PSU2-Sensor 2', 'CPU Core 0', 'CPU Core 1')
|
||||
|
||||
def __init__(self, thermal_index):
|
||||
self.index = thermal_index + 1
|
||||
self.is_psu_thermal = False
|
||||
self.dependency = None
|
||||
|
||||
if self.index < 9:
|
||||
i2c_path = self.I2C_DIR + self.I2C_DEV_MAPPING[self.index - 1][0]
|
||||
hwmon_temp_index = self.I2C_DEV_MAPPING[self.index - 1][1]
|
||||
hwmon_temp_suffix = "max"
|
||||
hwmon_node = os.listdir(i2c_path)[0]
|
||||
self.HWMON_DIR = i2c_path + hwmon_node + '/'
|
||||
|
||||
if self.index == 4:
|
||||
hwmon_temp_suffix = "crit"
|
||||
|
||||
if self.index > 4:
|
||||
self.is_psu_thermal = True
|
||||
self.dependency = Psu(self.index / 7)
|
||||
else:
|
||||
dev_path = "/sys/devices/platform/coretemp.0/hwmon/"
|
||||
hwmon_temp_index = self.index - 7
|
||||
hwmon_temp_suffix = "crit"
|
||||
hwmon_node = os.listdir(dev_path)[0]
|
||||
self.HWMON_DIR = dev_path + hwmon_node + '/'
|
||||
|
||||
self.thermal_temperature_file = self.HWMON_DIR \
|
||||
+ "temp{}_input".format(hwmon_temp_index)
|
||||
self.thermal_high_threshold_file = self.HWMON_DIR \
|
||||
+ "temp{}_{}".format(hwmon_temp_index, hwmon_temp_suffix)
|
||||
self.thermal_low_threshold_file = self.HWMON_DIR \
|
||||
+ "temp{}_min".format(hwmon_temp_index)
|
||||
|
||||
def _read_sysfs_file(self, sysfs_file):
|
||||
# On successful read, returns the value read from given
|
||||
# sysfs_file and on failure returns 'ERR'
|
||||
rv = 'ERR'
|
||||
|
||||
if (not os.path.isfile(sysfs_file)):
|
||||
return rv
|
||||
|
||||
try:
|
||||
with open(sysfs_file, 'r') as fd:
|
||||
rv = fd.read()
|
||||
except:
|
||||
rv = 'ERR'
|
||||
|
||||
rv = rv.rstrip('\r\n')
|
||||
rv = rv.lstrip(" ")
|
||||
return rv
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the thermal
|
||||
|
||||
Returns:
|
||||
string: The name of the thermal
|
||||
"""
|
||||
return self.THERMAL_NAME[self.index - 1]
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the thermal
|
||||
|
||||
Returns:
|
||||
bool: True if thermal is present, False if not
|
||||
"""
|
||||
if self.dependency:
|
||||
return self.dependency.get_presence()
|
||||
else:
|
||||
return True
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the Thermal
|
||||
|
||||
Returns:
|
||||
string: Model/part number of Thermal
|
||||
"""
|
||||
return 'NA'
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the Thermal
|
||||
|
||||
Returns:
|
||||
string: Serial number of Thermal
|
||||
"""
|
||||
return 'NA'
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the thermal
|
||||
|
||||
Returns:
|
||||
A boolean value, True if thermal is operating properly,
|
||||
False if not
|
||||
"""
|
||||
if self.dependency:
|
||||
return self.dependency.get_status()
|
||||
else:
|
||||
return True
|
||||
|
||||
def get_temperature(self):
|
||||
"""
|
||||
Retrieves current temperature reading from thermal
|
||||
|
||||
Returns:
|
||||
A float number of current temperature in Celsius up to
|
||||
nearest thousandth of one degree Celsius, e.g. 30.125
|
||||
"""
|
||||
thermal_temperature = self._read_sysfs_file(
|
||||
self.thermal_temperature_file)
|
||||
if (thermal_temperature != 'ERR'):
|
||||
thermal_temperature = float(thermal_temperature) / 1000
|
||||
else:
|
||||
thermal_temperature = 0
|
||||
|
||||
return "{:.3f}".format(thermal_temperature)
|
||||
|
||||
def get_high_threshold(self):
|
||||
"""
|
||||
Retrieves the high threshold temperature of thermal
|
||||
|
||||
Returns:
|
||||
A float number, the high threshold temperature of thermal in
|
||||
Celsius up to nearest thousandth of one degree Celsius,
|
||||
e.g. 30.125
|
||||
"""
|
||||
thermal_high_threshold = self._read_sysfs_file(
|
||||
self.thermal_high_threshold_file)
|
||||
if (thermal_high_threshold != 'ERR'):
|
||||
thermal_high_threshold = float(thermal_high_threshold) / 1000
|
||||
else:
|
||||
thermal_high_threshold = 0
|
||||
|
||||
return "{:.3f}".format(thermal_high_threshold)
|
||||
|
||||
def get_low_threshold(self):
|
||||
"""
|
||||
Retrieves the low threshold temperature of thermal
|
||||
|
||||
Returns:
|
||||
A float number, the low threshold temperature of thermal in
|
||||
Celsius up to nearest thousandth of one degree Celsius,
|
||||
e.g. 30.125
|
||||
"""
|
||||
thermal_low_threshold = self._read_sysfs_file(
|
||||
self.thermal_low_threshold_file)
|
||||
if (thermal_low_threshold != 'ERR'):
|
||||
thermal_low_threshold = float(thermal_low_threshold) / 1000
|
||||
else:
|
||||
thermal_low_threshold = 0
|
||||
|
||||
return "{:.3f}".format(thermal_low_threshold)
|
||||
|
||||
def set_high_threshold(self, temperature):
|
||||
"""
|
||||
Sets the high threshold temperature of thermal
|
||||
|
||||
Args :
|
||||
temperature: A float number up to nearest thousandth of one
|
||||
degree Celsius, e.g. 30.125
|
||||
Returns:
|
||||
A boolean, True if threshold is set successfully, False if
|
||||
not
|
||||
"""
|
||||
# Thermal threshold values are pre-defined based on HW.
|
||||
return False
|
||||
|
||||
def set_low_threshold(self, temperature):
|
||||
"""
|
||||
Sets the low threshold temperature of thermal
|
||||
|
||||
Args :
|
||||
temperature: A float number up to nearest thousandth of one
|
||||
degree Celsius, e.g. 30.125
|
||||
Returns:
|
||||
A boolean, True if threshold is set successfully, False if
|
||||
not
|
||||
"""
|
||||
# Thermal threshold values are pre-defined based on HW.
|
||||
return False
|
Reference in New Issue
Block a user