Skip to content

Commit

Permalink
DellEMC S6000 : Platform2.0 API implementation [PSU, Thermal] (#3357)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
ArunSaravananBalachandran authored and sujinmkang committed Sep 18, 2019
1 parent 19ffb02 commit 6ca0d7b
Show file tree
Hide file tree
Showing 5 changed files with 484 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__all__ = ["platform", "chassis", "sfp"]
__all__ = ["platform", "chassis", "sfp", "psu", "thermal"]
from sonic_platform import *
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@
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
Expand Down Expand Up @@ -75,6 +79,14 @@ def __init__(self):
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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 6ca0d7b

Please sign in to comment.