DellEMC: S6100, S6000 - Enable thermalctld, Platform API implementation and fixes (#6438)

**- Why I did it**

To incorporate the below changes in DellEMC S6100, S6000 platforms.

- S6100, S6000:
    - Enable 'thermalctld'
    - Implement DeviceBase methods (presence, status, model, serial) for Fantray and Component
    - Implement ‘get_position_in_parent’, ‘is_replaceable’ methods for all device types
    - Implement ‘get_status’ method for Fantray
    - Implement ‘get_temperature’, ‘get_temperature_high_threshold’, ‘get_voltage_high_threshold’, ‘get_voltage_low_threshold’ methods for PSU
    - Implement ‘get_status_led’, ‘set_status_led’ methods for Chassis
    - SFP:
        - Make EEPROM read both Python2 and Python3 compatible
        - Fix ‘get_tx_disable_channel’ method’s return type
        - Implement ‘tx_disable’, ‘tx_disable_channel’ and ‘set_power_override’ methods
- S6000:
    - Move PSU thermal sensors from Chassis to respective PSU
    - Make available the data of both Fans present in each Fantray


**- How I did it**

- Remove 'skip_thermalctld:true' in pmon_daemon_control.json
- Implement the platform API methods in the respective device files
- Use `bytearray` for data read from transceiver EEPROM 
- Change return type of 'get_tx_disable_channel' to match specification in sonic_platform_common/sfp_base.py
This commit is contained in:
Arun Saravanan Balachandran 2021-02-05 20:30:08 +00:00 committed by GitHub
parent 85a6314424
commit fa89c6dd8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 1084 additions and 280 deletions

View File

@ -1,4 +1,3 @@
{
"skip_ledd": true,
"skip_thermalctld": true
"skip_ledd": true
}

View File

@ -1,4 +1,3 @@
{
"skip_ledd": true,
"skip_thermalctld": true
"skip_ledd": true
}

View File

@ -174,6 +174,9 @@
/* Mailbox PowerOn Reason */
#define TRACK_POWERON_REASON 0x05FF
/* System Status LED */
#define SYSTEM_STATUS_LED 0x04DF
/* CPU Set IO Modules */
#define CPU_IOM1_CTRL_FLAG 0x04D9
#define CPU_IOM2_CTRL_FLAG 0x04DA
@ -607,6 +610,44 @@ static ssize_t show_mb_poweron_reason(struct device *dev,
return sprintf(buf, "0x%x\n", ret);
}
/* System Status LED */
static ssize_t set_sys_status_led(struct device *dev,
struct device_attribute *devattr, const char *buf, size_t count)
{
int err = 0;
unsigned int dev_data = 0;
struct smf_data *data = dev_get_drvdata(dev);
if (data->kind == z9100smf)
return -1;
err = kstrtouint(buf, 16, &dev_data);
if (err)
return err;
err = smf_write_reg(data, SYSTEM_STATUS_LED, dev_data);
if(err < 0)
return err;
return count;
}
static ssize_t show_sys_status_led(struct device *dev,
struct device_attribute *devattr, char *buf)
{
unsigned int ret = 0;
struct smf_data *data = dev_get_drvdata(dev);
if (data->kind == z9100smf)
return 0;
ret = smf_read_reg(data, SYSTEM_STATUS_LED);
if(ret < 0)
return ret;
return sprintf(buf, "0x%x\n", ret);
}
/* FANIN ATTR */
static ssize_t
show_fan_label(struct device *dev, struct device_attribute *attr, char *buf)
@ -2081,12 +2122,17 @@ static SENSOR_DEVICE_ATTR(smf_poweron_reason, S_IRUGO,
static SENSOR_DEVICE_ATTR(mb_poweron_reason, S_IRUGO|S_IWUSR,
show_mb_poweron_reason, set_mb_poweron_reason, 0);
/* System Status LED */
static SENSOR_DEVICE_ATTR(sys_status_led, S_IRUGO|S_IWUSR,
show_sys_status_led, set_sys_status_led, 0);
static struct attribute *smf_dell_attrs[] = {
&sensor_dev_attr_smf_version.dev_attr.attr,
&sensor_dev_attr_smf_firmware_ver.dev_attr.attr,
&sensor_dev_attr_smf_reset_reason.dev_attr.attr,
&sensor_dev_attr_smf_poweron_reason.dev_attr.attr,
&sensor_dev_attr_mb_poweron_reason.dev_attr.attr,
&sensor_dev_attr_sys_status_led.dev_attr.attr,
&sensor_dev_attr_fan_tray_presence.dev_attr.attr,
&sensor_dev_attr_fan1_airflow.dev_attr.attr,
&sensor_dev_attr_fan3_airflow.dev_attr.attr,

View File

@ -24,7 +24,7 @@ except ImportError as e:
MAX_S6000_FANTRAY = 3
MAX_S6000_PSU = 2
MAX_S6000_THERMAL = 10
MAX_S6000_THERMAL = 6
MAX_S6000_COMPONENT = 4
@ -44,6 +44,8 @@ class Chassis(ChassisBase):
def __init__(self):
ChassisBase.__init__(self)
self.status_led_reg = "system_led"
self.supported_led_color = ['green', 'blinking green', 'amber', 'blinking amber']
# Initialize SFP list
self.PORT_START = 0
self.PORT_END = 31
@ -101,13 +103,30 @@ class Chassis(ChassisBase):
try:
with open(mb_reg_file, 'r') as fd:
rv = fd.read()
except Exception as error:
except IOError:
rv = 'ERR'
rv = rv.rstrip('\r\n')
rv = rv.lstrip(" ")
return rv
def _set_cpld_register(self, reg_name, value):
# On successful write, returns the value will be written on
# 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, 'w') as fd:
rv = fd.write(str(value))
except IOError:
rv = 'ERR'
return rv
def _nvram_write(self, offset, val):
resource = "/dev/nvram"
fd = os.open(resource, os.O_RDWR)
@ -179,6 +198,23 @@ class Chassis(ChassisBase):
"""
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
def get_base_mac(self):
"""
Retrieves the base MAC address for the chassis
@ -305,4 +341,41 @@ class Chassis(ChassisBase):
return True, ret_dict
return False, ret_dict
def set_status_led(self, color):
"""
Sets the state of the system LED
Args:
color: A string representing the color with which to set the
system LED
Returns:
bool: True if system LED state is set successfully, False if not
"""
if color not in self.supported_led_color:
return False
# Change color string format to the one used by driver
color = color.replace('amber', 'yellow')
color = color.replace('blinking ', 'blink_')
rv = self._set_cpld_register(self.status_led_reg, color)
if (rv != 'ERR'):
return True
else:
return False
def get_status_led(self):
"""
Gets the state of the system LED
Returns:
A string, one of the valid LED color strings which could be vendor
specified.
"""
status_led = self._get_cpld_register(self.status_led_reg)
if (status_led != 'ERR'):
status_led = status_led.replace('yellow', 'amber')
status_led = status_led.replace('blink_', 'blinking ')
return status_led
else:
return None

View File

@ -29,8 +29,8 @@ class Component(ComponentBase):
"booting")],
["System-CPLD", "Used for managing CPU board devices and power"],
["Master-CPLD", ("Used for managing Fan, PSU, system LEDs, QSFP "
"modules (1-16)")],
["Slave-CPLD", "Used for managing QSFP modules (17-32)"]
"modules (17-32)")],
["Slave-CPLD", "Used for managing QSFP modules (1-16)"]
]
def __init__(self, component_index):
@ -90,6 +90,55 @@ class Component(ComponentBase):
"""
return self.name
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_presence(self):
"""
Retrieves the presence of the component
Returns:
bool: True if present, False if not
"""
return True
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
def get_description(self):
"""
Retrieves the description of the component

View File

@ -36,8 +36,8 @@ psu_eeprom_format = [
('Fab Rev', 's', 2)
]
# Fan eeprom fields in format required by EepromDecoder
fan_eeprom_format = [
# FanTray eeprom fields in format required by EepromDecoder
fantray_eeprom_format = [
('PPID', 's', 20), ('DPN Rev', 's', 3), ('Service Tag', 's', 7),
('Part Number', 's', 10), ('Part Num Revision', 's', 3),
('Mfg Test', 's', 2), ('Redundant copy', 's', 83),
@ -51,10 +51,10 @@ class Eeprom(TlvInfoDecoder):
I2C_DIR = "/sys/class/i2c-adapter/"
def __init__(self, is_psu=False, psu_index=0, is_fan=False, fan_index=0):
def __init__(self, is_psu=False, psu_index=0, is_fantray=False, fantray_index=0):
self.is_psu_eeprom = is_psu
self.is_fan_eeprom = is_fan
self.is_sys_eeprom = not (is_psu | is_fan)
self.is_fantray_eeprom = is_fantray
self.is_sys_eeprom = not (is_psu | is_fantray)
if self.is_sys_eeprom:
self.start_offset = 0
@ -71,10 +71,10 @@ class Eeprom(TlvInfoDecoder):
+ "i2c-1/1-005{}/eeprom".format(2 - self.index)
self.format = psu_eeprom_format
else:
self.index = fan_index
self.index = fantray_index
self.eeprom_path = self.I2C_DIR \
+ "i2c-11/11-005{}/eeprom".format(4 - self.index)
self.format = fan_eeprom_format
self.format = fantray_eeprom_format
EepromDecoder.__init__(self, self.eeprom_path, self.format,
self.start_offset, '', True)
self._load_device_eeprom()

View File

@ -13,7 +13,6 @@ try:
import os
import glob
from sonic_platform_base.fan_base import FanBase
from sonic_platform.eeprom import Eeprom
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
@ -25,33 +24,37 @@ MAX_S6000_FAN_SPEED = 19000
class Fan(FanBase):
"""DellEMC Platform-specific Fan class"""
CPLD_DIR = "/sys/devices/platform/dell-s6000-cpld.0/"
I2C_DIR = "/sys/class/i2c-adapter/"
FAN_DEV_MAPPING = {
1: {1: ("i2c-11/11-002a", 1), 2: ("i2c-11/11-002a", 2)},
2: {1: ("i2c-11/11-0029", 3), 2: ("i2c-11/11-0029", 4)},
3: {1: ("i2c-11/11-0029", 1), 2: ("i2c-11/11-0029", 2)}
}
def __init__(self, fan_index, psu_fan=False, dependency=None):
def __init__(self, fantray_index=1, fan_index=1,
psu_index=1, psu_fan=False, dependency=None):
self.is_psu_fan = psu_fan
self.is_driver_initialized = True
if not self.is_psu_fan:
# Fan is 1-based in DellEMC platforms
self.index = fan_index + 1
self.fan_presence_reg = "fan_prs"
self.fan_led_reg = "fan{}_led".format(fan_index)
self.get_fan_speed_reg = self.I2C_DIR + "i2c-11/11-0029/" +\
"fan{}_input".format(self.index)
self.set_fan_speed_reg = self.I2C_DIR + "i2c-11/11-0029/" +\
"fan{}_target".format(self.index)
self.eeprom = Eeprom(is_fan=True, fan_index=self.index)
self.max_fan_speed = MAX_S6000_FAN_SPEED
self.supported_led_color = ['off', 'green', 'amber']
else:
self.fantray_index = fantray_index
self.index = fan_index
self.dependency = dependency
self.get_fan_speed_reg = self.I2C_DIR +\
"{}/fan{}_input".format(*self.FAN_DEV_MAPPING[fantray_index][fan_index])
self.set_fan_speed_reg = self.I2C_DIR +\
"i2c-1/1-005{}/fan1_target".format(10 - self.index)
"{}/fan{}_target".format(*self.FAN_DEV_MAPPING[fantray_index][fan_index])
self.max_fan_speed = MAX_S6000_FAN_SPEED
else:
self.psu_index = psu_index
self.index = 1
self.dependency = dependency
self.set_fan_speed_reg = self.I2C_DIR +\
"i2c-1/1-005{}/fan1_target".format(10 - self.psu_index)
hwmon_dir = self.I2C_DIR +\
"i2c-1/1-005{}/hwmon/".format(10 - self.index)
"i2c-1/1-005{}/hwmon/".format(10 - self.psu_index)
try:
hwmon_node = os.listdir(hwmon_dir)[0]
except OSError:
@ -61,43 +64,6 @@ class Fan(FanBase):
self.get_fan_speed_reg = hwmon_dir + hwmon_node + '/fan1_input'
self.max_fan_speed = MAX_S6000_PSU_FAN_SPEED
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 _set_cpld_register(self, reg_name, value):
# On successful write, returns the value will be written on
# 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)):
print("open error")
return rv
try:
with open(cpld_reg_file, 'w') as fd:
rv = fd.write(str(value))
except:
rv = 'ERR'
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'
@ -155,9 +121,9 @@ class Fan(FanBase):
string: The name of the Fan
"""
if not self.is_psu_fan:
return "FanTray{}-Fan1".format(self.index)
return "FanTray{}-Fan{}".format(self.fantray_index, self.index)
else:
return "PSU{} Fan".format(self.index)
return "PSU{} Fan".format(self.psu_index)
def get_presence(self):
"""
@ -166,41 +132,22 @@ class Fan(FanBase):
Returns:
bool: True if Fan is present, False if not
"""
status = False
if self.is_psu_fan:
return self.dependency.get_presence()
fan_presence = self._get_cpld_register(self.fan_presence_reg)
if (fan_presence != 'ERR'):
fan_presence = int(fan_presence,16) & self.index
if fan_presence:
status = True
return status
def get_model(self):
"""
Retrieves the part number of the Fan
Returns:
string: Part number of Fan
"""
if not self.is_psu_fan:
return self.eeprom.get_part_number()
else:
return 'NA'
def get_serial(self):
"""
Retrieves the serial number of the Fan
Returns:
string: Serial number of Fan
"""
# Sample Serial number format "US-01234D-54321-25A-0123-A00"
if not self.is_psu_fan:
return self.eeprom.get_serial_number()
else:
return 'NA'
def get_status(self):
@ -218,6 +165,23 @@ class Fan(FanBase):
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.index
def is_replaceable(self):
"""
Indicate whether Fan is replaceable.
Returns:
bool: True if it is replaceable.
"""
return False
def get_direction(self):
"""
Retrieves the fan airflow direction
@ -234,11 +198,10 @@ class Fan(FanBase):
if self.is_psu_fan:
direction = {1: self.FAN_DIRECTION_EXHAUST, 2: self.FAN_DIRECTION_INTAKE,
3: self.FAN_DIRECTION_EXHAUST, 4: self.FAN_DIRECTION_INTAKE}
fan_direction = self.dependency.eeprom.airflow_fan_type()
else:
direction = {1: self.FAN_DIRECTION_EXHAUST, 2: self.FAN_DIRECTION_INTAKE}
fan_direction = self.eeprom.airflow_fan_type()
fan_direction = self.dependency.eeprom.airflow_fan_type()
return direction.get(fan_direction, self.FAN_DIRECTION_NOT_APPLICABLE)
def get_speed(self):
@ -282,8 +245,8 @@ class Fan(FanBase):
Returns:
bool: True if set success, False if fail.
"""
fan_set = (speed * self.max_fan_speed)/ 100
rv = self._set_i2c_register(self.set_fan_speed_reg , fan_set)
fan_set = (speed * self.max_fan_speed) // 100
rv = self._set_i2c_register(self.set_fan_speed_reg, fan_set)
if (rv != 'ERR'):
return True
else:
@ -298,16 +261,9 @@ class Fan(FanBase):
Returns:
bool: True if set success, False if fail.
"""
if self.is_psu_fan or (color not in self.supported_led_color):
return False
if(color == self.STATUS_LED_COLOR_AMBER):
color = 'yellow'
rv = self._set_cpld_register(self.fan_led_reg ,color)
if (rv != 'ERR'):
# No LED available for FanTray and PSU Fan
# Return True to avoid thermalctld alarm.
return True
else:
return False
def get_status_led(self):
"""
@ -316,19 +272,9 @@ class Fan(FanBase):
Returns:
A string, one of the predefined STATUS_LED_COLOR_* strings.
"""
if self.is_psu_fan:
# No LED available for PSU Fan
# No LED available for FanTray and PSU Fan
return None
fan_led = self._get_cpld_register(self.fan_led_reg)
if (fan_led != 'ERR'):
if (fan_led == 'yellow'):
return self.STATUS_LED_COLOR_AMBER
else:
return fan_led
else:
return self.STATUS_LED_COLOR_OFF
def get_target_speed(self):
"""
Retrieves the target (expected) speed of the fan

View File

@ -9,26 +9,176 @@
########################################################################
try:
import os
from sonic_platform_base.fan_drawer_base import FanDrawerBase
from sonic_platform.eeprom import Eeprom
from sonic_platform.fan import Fan
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
MAX_S6000_FANS_PER_FANTRAY = 2
class FanDrawer(FanDrawerBase):
"""DellEMC Platform-specific Fan class"""
"""DellEMC Platform-specific Fan Drawer class"""
CPLD_DIR = "/sys/devices/platform/dell-s6000-cpld.0/"
def __init__(self, fantray_index):
FanDrawerBase.__init__(self)
# FanTray is 1-based in DellEMC platforms
self.fantrayindex = fantray_index + 1
self._fan_list.append(Fan(fantray_index))
self.index = fantray_index + 1
self.eeprom = Eeprom(is_fantray=True, fantray_index=self.index)
self.fantray_presence_reg = "fan_prs"
self.fantray_led_reg = "fan{}_led".format(self.index - 1)
self.supported_led_color = ['off', 'green', 'amber']
for i in range(1, MAX_S6000_FANS_PER_FANTRAY+1):
self._fan_list.append(Fan(fantray_index=self.index, fan_index=i, dependency=self))
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 IOError:
rv = 'ERR'
rv = rv.rstrip('\r\n')
rv = rv.lstrip(" ")
return rv
def _set_cpld_register(self, reg_name, value):
# On successful write, returns the value will be written on
# 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, 'w') as fd:
rv = fd.write(str(value))
except IOError:
rv = 'ERR'
return rv
def get_name(self):
"""
Retrieves the fan drawer name
Retrieves the Fandrawer name
Returns:
string: The name of the device
"""
return "FanTray{}".format(self.fantrayindex)
return "FanTray{}".format(self.index)
def get_presence(self):
"""
Retrieves the presence of the Fandrawer
Returns:
bool: True if Fandrawer is present, False if not
"""
presence = False
fantray_presence = self._get_cpld_register(self.fantray_presence_reg)
if (fantray_presence != 'ERR'):
fantray_presence = int(fantray_presence, 16) & (1 << (self.index - 1))
if fantray_presence:
presence = True
return presence
def get_model(self):
"""
Retrieves the part number of the Fandrawer
Returns:
string: Part number of Fandrawer
"""
return self.eeprom.get_part_number()
def get_serial(self):
"""
Retrieves the serial number of the Fandrawer
Returns:
string: Serial number of Fandrawer
"""
# Sample Serial number format "US-01234D-54321-25A-0123-A00"
return self.eeprom.get_serial_number()
def get_status(self):
"""
Retrieves the operational status of the Fandrawer
Returns:
bool: True if Fandrawer 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.index
def is_replaceable(self):
"""
Indicate whether this fan drawer is replaceable.
Returns:
bool: True if it is replaceable.
"""
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
fandrawer status LED
Returns:
bool: True if set success, False if fail.
"""
if color not in self.supported_led_color:
return False
if color == self.STATUS_LED_COLOR_AMBER:
color = 'yellow'
rv = self._set_cpld_register(self.fantray_led_reg, color)
if (rv != 'ERR'):
return True
else:
return False
def get_status_led(self):
"""
Gets the state of the fandrawer status LED
Returns:
A string, one of the predefined STATUS_LED_COLOR_* strings.
"""
fantray_led = self._get_cpld_register(self.fantray_led_reg)
if (fantray_led != 'ERR'):
if (fantray_led == 'yellow'):
return self.STATUS_LED_COLOR_AMBER
else:
return fantray_led
else:
return self.STATUS_LED_COLOR_OFF

View File

@ -15,9 +15,12 @@ try:
from sonic_platform_base.psu_base import PsuBase
from sonic_platform.eeprom import Eeprom
from sonic_platform.fan import Fan
from sonic_platform.thermal import Thermal
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
MAX_S6000_THERMALS_PER_PSU = 2
class Psu(PsuBase):
"""DellEMC Platform-specific PSU class"""
@ -53,7 +56,10 @@ class Psu(PsuBase):
self.eeprom = Eeprom(is_psu=True, psu_index=self.index)
self._fan_list.append(Fan(self.index, psu_fan=True, dependency=self))
self._fan_list.append(Fan(psu_index=self.index, psu_fan=True, dependency=self))
for i in range(1, MAX_S6000_THERMALS_PER_PSU+1):
self._thermal_list.append(Thermal(psu_index=self.index, thermal_index=i,
psu_thermal=True, dependency=self))
def _get_cpld_register(self, reg_name):
# On successful read, returns the value read from given
@ -171,6 +177,23 @@ class Psu(PsuBase):
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.index
def is_replaceable(self):
"""
Indicate whether PSU is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True
def get_voltage(self):
"""
Retrieves current PSU voltage output
@ -266,3 +289,50 @@ class Psu(PsuBase):
# In S6000, the firmware running in the PSU controls the LED
# and the PSU LED state cannot be changed from CPU.
return False
def get_temperature(self):
"""
Retrieves current temperature reading from PSU
Returns:
A float number of current temperature in Celsius up to
nearest thousandth of one degree Celsius, e.g. 30.125
"""
if self.get_presence():
return self.get_thermal(0).get_temperature()
else:
return 0.0
def get_temperature_high_threshold(self):
"""
Retrieves the high threshold temperature of PSU
Returns:
A float number, the high threshold temperature of PSU in
Celsius up to nearest thousandth of one degree Celsius,
e.g. 30.125
"""
if self.get_presence():
return self.get_thermal(0).get_high_threshold()
else:
return 0.0
def get_voltage_high_threshold(self):
"""
Retrieves the high threshold PSU voltage output
Returns:
A float number, the high threshold output voltage in volts,
e.g. 12.1
"""
return 12.6
def get_voltage_low_threshold(self):
"""
Retrieves the low threshold PSU voltage output
Returns:
A float number, the low threshold output voltage in volts,
e.g. 12.1
"""
return 11.4

View File

@ -10,6 +10,7 @@
try:
import re
import struct
import time
from sonic_platform_base.sfp_base import SfpBase
from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId
@ -27,6 +28,9 @@ INFO_OFFSET = 128
DOM_OFFSET = 0
DOM_OFFSET1 = 384
QSFP_CONTROL_OFFSET = 86
QSFP_POWEROVERRIDE_OFFSET = 93
cable_length_tup = ('Length(km)', 'Length OM3(2m)', 'Length OM2(m)',
'Length OM1(m)', 'Length Cable Assembly(m)')
@ -108,7 +112,7 @@ class Sfp(SfpBase):
sfp_control, sfp_ctrl_idx):
SfpBase.__init__(self)
self.sfp_type = sfp_type
self.index = index
self.index = index + 1
self.eeprom_path = eeprom_path
self.sfp_control = sfp_control
self.sfp_ctrl_idx = sfp_ctrl_idx
@ -132,9 +136,10 @@ class Sfp(SfpBase):
eeprom.close()
return None
raw = bytearray(raw)
try:
for n in range(0, num_bytes):
eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2)
eeprom_raw[n] = hex(raw[n])[2:].zfill(2)
except BaseException:
eeprom.close()
return None
@ -588,38 +593,12 @@ class Sfp(SfpBase):
"""
Retrieves the TX disabled channels in this SFP
"""
tx_disable = None
tx_disable_list = []
tx_disable_channel = 0
tx_disable_data = self._get_eeprom_data('tx_disable')
if (tx_disable_data is not None):
tx_disable = tx_disable_data['data']['Tx1Disable']['value']
if (tx_disable == 'On'):
tx_disable_list.append(1)
else:
tx_disable_list.append(0)
tx_disable = tx_disable_data['data']['Tx2Disable']['value']
if (tx_disable == 'On'):
tx_disable_list.append(1)
else:
tx_disable_list.append(0)
tx_disable = tx_disable_data['data']['Tx3Disable']['value']
if (tx_disable == 'On'):
tx_disable_list.append(1)
else:
tx_disable_list.append(0)
tx_disable = tx_disable_data['data']['Tx4Disable']['value']
if (tx_disable == 'On'):
tx_disable_list.append(1)
else:
tx_disable_list.append(0)
bit4 = int(tx_disable_list[3]) * 8
bit3 = int(tx_disable_list[2]) * 4
bit2 = int(tx_disable_list[1]) * 2
bit1 = int(tx_disable_list[0]) * 1
tx_disable_channel = hex(bit4 + bit3 + bit2 + bit1)
tx_disable = self.get_tx_disable()
for channel, disable in enumerate(tx_disable):
if disable:
tx_disable_channel |= 1 << channel
return tx_disable_channel
@ -722,7 +701,6 @@ class Sfp(SfpBase):
return rx_power_list
def get_tx_power(self):
"""
Retrieves the TX power of this SFP
@ -822,19 +800,68 @@ class Sfp(SfpBase):
"""
Disable SFP TX for all channels
"""
eeprom = None
tx_disable_value = 0xf if tx_disable else 0x0
try:
eeprom = open(self.eeprom_path, "r+b")
eeprom.seek(QSFP_CONTROL_OFFSET)
eeprom.write(struct.pack('B', tx_disable_value))
except IOError:
return False
finally:
if eeprom is not None:
eeprom.close()
time.sleep(0.01)
return True
def tx_disable_channel(self, channel, disable):
"""
Sets the tx_disable for specified SFP channels
"""
eeprom = None
current_state = self.get_tx_disable_channel()
if disable:
tx_disable_value = current_state | channel
else:
tx_disable_value = current_state & (~channel)
try:
eeprom = open(self.eeprom_path, "r+b")
eeprom.seek(QSFP_CONTROL_OFFSET)
eeprom.write(struct.pack('B', tx_disable_value))
except IOError:
return False
finally:
if eeprom is not None:
eeprom.close()
time.sleep(0.01)
return True
def set_power_override(self, power_override, power_set):
"""
Sets SFP power level using power_override and power_set
"""
eeprom = None
power_override_bit = 0x1 if power_override else 0
power_set_bit = 0x2 if power_set else 0
value = power_override_bit | power_set_bit
try:
eeprom = open(self.eeprom_path, "r+b")
eeprom.seek(QSFP_POWEROVERRIDE_OFFSET)
eeprom.write(struct.pack('B', value))
except IOError:
return False
finally:
if eeprom is not None:
eeprom.close()
time.sleep(0.01)
return True
def get_status(self):
"""
@ -848,3 +875,20 @@ class Sfp(SfpBase):
status = True
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.index
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True

View File

@ -13,7 +13,6 @@ try:
import os
import glob
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")
@ -34,11 +33,20 @@ class Thermal(ThermalBase):
'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
def __init__(self, thermal_index,
psu_index=1, psu_thermal=False, dependency=None):
self.is_psu_thermal = psu_thermal
self.dependency = dependency
self.is_driver_initialized = True
self.dependency = None
if self.is_psu_thermal:
self.index = (2 * psu_index) + thermal_index + 2
else:
# CPU thermal
if thermal_index > 3:
self.index = thermal_index + 5
else:
self.index = thermal_index + 1
if self.index < 9:
i2c_path = self.I2C_DIR + self.I2C_DEV_MAPPING[self.index - 1][0]
@ -54,10 +62,6 @@ class Thermal(ThermalBase):
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
@ -168,6 +172,23 @@ class Thermal(ThermalBase):
else:
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 Thermal is replaceable.
Returns:
bool: True if it is replaceable.
"""
return False
def get_temperature(self):
"""
Retrieves current temperature reading from thermal

View File

@ -54,9 +54,21 @@ class Chassis(ChassisBase):
power_reason_dict[33] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC
power_reason_dict[44] = ChassisBase.REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED
status_led_reg_to_color = {
0x00: 'green', 0x01: 'blinking green', 0x02: 'amber',
0x04: 'amber', 0x08: 'blinking amber', 0x10: 'blinking amber'
}
color_to_status_led_reg = {
'green': 0x00, 'blinking green': 0x01,
'amber': 0x02, 'blinking amber': 0x08
}
def __init__(self):
ChassisBase.__init__(self)
self.status_led_reg = "sys_status_led"
self.supported_led_color = ['green', 'blinking green', 'amber', 'blinking amber']
# Initialize EEPROM
self._eeprom = Eeprom()
for i in range(MAX_S6100_MODULE):
@ -113,6 +125,23 @@ class Chassis(ChassisBase):
rv = rv.lstrip(" ")
return rv
def _set_pmc_register(self, reg_name, value):
# On successful write, returns the length of value written on
# reg_name and on failure returns 'ERR'
rv = 'ERR'
mb_reg_file = self.MAILBOX_DIR + '/' + reg_name
if (not os.path.isfile(mb_reg_file)):
return rv
try:
with open(mb_reg_file, 'w') as fd:
rv = fd.write(str(value))
except IOError:
rv = 'ERR'
return rv
def _get_register(self, reg_file):
# On successful read, returns the value read from given
# reg_name and on failure returns 'ERR'
@ -172,6 +201,23 @@ class Chassis(ChassisBase):
"""
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
def get_base_mac(self):
"""
Retrieves the base MAC address for the chassis
@ -325,3 +371,38 @@ class Chassis(ChassisBase):
break
return True, ret_dict
def set_status_led(self, color):
"""
Sets the state of the system LED
Args:
color: A string representing the color with which to set the
system LED
Returns:
bool: True if system LED state is set successfully, False if not
"""
if color not in self.supported_led_color:
return False
value = self.color_to_status_led_reg[color]
rv = self._set_pmc_register(self.status_led_reg, value)
if (rv != 'ERR'):
return True
else:
return False
def get_status_led(self):
"""
Gets the state of the system LED
Returns:
A string, one of the valid LED color strings which could be
vendor specified.
"""
reg_val = self._get_pmc_register(self.status_led_reg)
if (reg_val != 'ERR'):
return self.status_led_reg_to_color.get(int(reg_val, 16), None)
else:
return None

View File

@ -39,9 +39,10 @@ class Component(ComponentBase):
]
def __init__(self, component_index=0,
is_module=False, iom_index=0, i2c_line=0):
is_module=False, iom_index=0, i2c_line=0, dependency=None):
self.is_module_component = is_module
self.dependency = dependency
if self.is_module_component:
self.index = iom_index
@ -132,6 +133,61 @@ class Component(ComponentBase):
"""
return self.name
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_presence(self):
"""
Retrieves the presence of the component
Returns:
bool: True if present, False if not
"""
if self.is_module_component:
return self.dependency.get_presence()
else:
return True
def get_status(self):
"""
Retrieves the operational status of the component
Returns:
bool: True if component is operating properly, False if not
"""
if self.is_module_component:
return self.dependency.get_status()
else:
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
def get_description(self):
"""
Retrieves the description of the component

View File

@ -26,30 +26,23 @@ class Fan(FanBase):
HWMON_NODE = os.listdir(HWMON_DIR)[0]
MAILBOX_DIR = HWMON_DIR + HWMON_NODE
def __init__(self, fantray_index=1, fan_index=1, psu_fan=False):
def __init__(self, fantray_index=1, psu_index=1, psu_fan=False, dependency=None):
self.is_psu_fan = psu_fan
if not self.is_psu_fan:
# API index is starting from 0, DellEMC platform index is starting
# from 1
self.fantrayindex = fantray_index + 1
self.fanindex = fan_index + 1
self.fan_presence_reg = "fan{}_fault".format(
2 * self.fantrayindex - 1)
self.fantrayindex = fantray_index
self.dependency = dependency
self.fan_status_reg = "fan{}_alarm".format(
2 * self.fantrayindex - 1)
self.get_fan_speed_reg = "fan{}_input".format(
2 * self.fantrayindex - 1)
self.get_fan_dir_reg = "fan{}_airflow".format(
2 * self.fantrayindex - 1)
self.fan_serialno_reg = "fan{}_serialno".format(
2 * self.fantrayindex - 1)
self.max_fan_speed = MAX_S6100_FAN_SPEED
else:
# PSU Fan index starts from 11
self.fanindex = fan_index + 10
self.fan_presence_reg = "fan{}_fault".format(self.fanindex)
self.get_fan_speed_reg = "fan{}_input".format(self.fanindex)
self.get_fan_dir_reg = "fan{}_airflow".format(self.fanindex)
self.psuindex = psu_index
self.fan_presence_reg = "fan{}_fault".format(self.psuindex + 10)
self.get_fan_speed_reg = "fan{}_input".format(self.psuindex + 10)
self.get_fan_dir_reg = "fan{}_airflow".format(self.psuindex + 10)
self.max_fan_speed = MAX_S6100_PSU_FAN_SPEED
def _get_pmc_register(self, reg_name):
@ -77,10 +70,9 @@ class Fan(FanBase):
string: The name of the device
"""
if not self.is_psu_fan:
return "FanTray{}-Fan{}".format(
self.fantrayindex, self.fanindex - 1)
return "FanTray{}-Fan1".format(self.fantrayindex)
else:
return "PSU{} Fan".format(self.fanindex - 10)
return "PSU{} Fan".format(self.psuindex)
def get_model(self):
"""
@ -88,52 +80,33 @@ class Fan(FanBase):
Returns:
string: Part number of FAN
"""
# For Serial number "US-01234D-54321-25A-0123-A00", the part
# number is "01234D"
if self.is_psu_fan:
return 'NA'
fan_serialno = self._get_pmc_register(self.fan_serialno_reg)
if (fan_serialno != 'ERR') and self.get_presence():
if (len(fan_serialno.split('-')) > 1):
fan_partno = fan_serialno.split('-')[1]
else:
fan_partno = 'NA'
else:
fan_partno = 'NA'
return fan_partno
def get_serial(self):
"""
Retrieves the serial number of the FAN
Returns:
string: Serial number of FAN
"""
# Sample Serial number format "US-01234D-54321-25A-0123-A00"
if self.is_psu_fan:
return 'NA'
fan_serialno = self._get_pmc_register(self.fan_serialno_reg)
if (fan_serialno == 'ERR') or not self.get_presence():
fan_serialno = 'NA'
return fan_serialno
def get_presence(self):
"""
Retrieves the presence of the FAN
Returns:
bool: True if fan is present, False if not
"""
status = False
fantray_presence = self._get_pmc_register(self.fan_presence_reg)
if (fantray_presence != 'ERR'):
fantray_presence = int(fantray_presence, 10)
if (~fantray_presence & 0b1):
status = True
if not self.is_psu_fan:
return self.dependency.get_presence()
return status
presence = False
fan_presence = self._get_pmc_register(self.fan_presence_reg)
if (fan_presence != 'ERR'):
fan_presence = int(fan_presence, 10)
if (~fan_presence & 0b1):
presence = True
return presence
def get_status(self):
"""
@ -157,6 +130,23 @@ class Fan(FanBase):
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 1
def is_replaceable(self):
"""
Indicate whether Fan is replaceable.
Returns:
bool: True if it is replaceable.
"""
return False
def get_direction(self):
"""
Retrieves the fan airflow direction
@ -216,7 +206,6 @@ class Fan(FanBase):
Returns:
bool: True if set success, False if fail.
"""
# Fan speeds are controlled by Smart-fussion FPGA.
return False
@ -229,7 +218,7 @@ class Fan(FanBase):
Returns:
bool: True if set success, False if fail.
"""
# Leds are controlled by Smart-fussion FPGA.
# No LED available for FanTray and PSU Fan
# Return True to avoid thermalctld alarm.
return True
@ -240,17 +229,8 @@ class Fan(FanBase):
Returns:
A string, one of the predefined STATUS_LED_COLOR_* strings.
"""
if self.is_psu_fan:
# No LED available for PSU Fan
# No LED available for FanTray and PSU Fan
return None
else:
if self.get_presence():
if self.get_status():
return self.STATUS_LED_COLOR_GREEN
else:
return self.STATUS_LED_COLOR_AMBER
else:
return self.STATUS_LED_COLOR_OFF
def get_target_speed(self):
"""
@ -262,5 +242,3 @@ class Fan(FanBase):
# Fan speeds are controlled by Smart-fussion FPGA.
# Return current speed to avoid false thermalctld alarm.
return self.get_speed()

View File

@ -9,6 +9,8 @@
########################################################################
try:
import os
from sonic_platform_base.fan_drawer_base import FanDrawerBase
from sonic_platform.fan import Fan
except ImportError as e:
@ -16,14 +18,38 @@ except ImportError as e:
class FanDrawer(FanDrawerBase):
"""DellEMC Platform-specific Fan class"""
"""DellEMC Platform-specific Fan Drawer class"""
HWMON_DIR = "/sys/devices/platform/SMF.512/hwmon/"
HWMON_NODE = os.listdir(HWMON_DIR)[0]
MAILBOX_DIR = HWMON_DIR + HWMON_NODE
def __init__(self, fantray_index):
FanDrawerBase.__init__(self)
# FanTray is 1-based in DellEMC platforms
self.fantrayindex = fantray_index + 1
self._fan_list.append(Fan(fantray_index))
self.index = fantray_index + 1
self.presence_reg = "fan{}_fault".format(2 * self.index - 1)
self.serialno_reg = "fan{}_serialno".format(2 * self.index - 1)
self._fan_list.append(Fan(self.index, dependency=self))
def _get_pmc_register(self, reg_name):
# On successful read, returns the value read from given
# reg_name and on failure returns 'ERR'
rv = 'ERR'
mb_reg_file = self.MAILBOX_DIR+'/'+reg_name
if (not os.path.isfile(mb_reg_file)):
return rv
try:
with open(mb_reg_file, 'r') as fd:
rv = fd.read()
except Exception as error:
rv = 'ERR'
rv = rv.rstrip('\r\n')
rv = rv.lstrip(" ")
return rv
def get_name(self):
"""
@ -31,4 +57,105 @@ class FanDrawer(FanDrawerBase):
Returns:
string: The name of the device
"""
return "FanTray{}".format(self.fantrayindex)
return "FanTray{}".format(self.index)
def get_model(self):
"""
Retrieves the part number of Fandrawer
Returns:
string: Part number of Fandrawer
"""
# For Serial number "US-01234D-54321-25A-0123-A00", the part
# number is "01234D"
fantray_serialno = self._get_pmc_register(self.serialno_reg)
if (fantray_serialno != 'ERR') and self.get_presence():
if (len(fantray_serialno.split('-')) > 1):
fantray_partno = fantray_serialno.split('-')[1]
else:
fantray_partno = 'NA'
else:
fantray_partno = 'NA'
return fantray_partno
def get_serial(self):
"""
Retrieves the serial number of Fandrawer
Returns:
string: Serial number of Fandrawer
"""
# Sample Serial number format "US-01234D-54321-25A-0123-A00"
fantray_serialno = self._get_pmc_register(self.serialno_reg)
if (fantray_serialno == 'ERR') or not self.get_presence():
fantray_serialno = 'NA'
return fantray_serialno
def get_presence(self):
"""
Retrieves the presence of the Fandrawer
Returns:
bool: True if fan is present, False if not
"""
presence = False
fantray_presence = self._get_pmc_register(self.presence_reg)
if (fantray_presence != 'ERR'):
fantray_presence = int(fantray_presence, 10)
if (~fantray_presence & 0b1):
presence = True
return presence
def get_status(self):
"""
Retrieves the operational status of the Fandrawer
Returns:
bool: True if Fandrawer is operating properly, False if not
"""
return self.get_fan(0).get_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.index
def is_replaceable(self):
"""
Indicate whether this Fandrawer is replaceable.
Returns:
bool: True if it is replaceable.
"""
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.
"""
# Leds are controlled by Smart-fussion FPGA.
# Return True to avoid thermalctld alarm.
return True
def get_status_led(self):
"""
Gets the state of the Fan status LED
Returns:
A string, one of the predefined STATUS_LED_COLOR_* strings.
"""
if self.get_presence():
if self.get_fan(0).get_status():
return self.STATUS_LED_COLOR_GREEN
else:
return self.STATUS_LED_COLOR_AMBER
else:
return self.STATUS_LED_COLOR_OFF

View File

@ -63,7 +63,7 @@ class Module(ModuleBase):
self.iom_presence_reg = "iom_presence"
component = Component(is_module=True, iom_index=self.index,
i2c_line=self.port_i2c_line)
i2c_line=self.port_i2c_line, dependency=self)
self._component_list.append(component)
eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/i2c-{1}/{1}-0050/eeprom"
@ -157,6 +157,23 @@ class Module(ModuleBase):
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.index
def is_replaceable(self):
"""
Indicate whether Module is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True
def get_base_mac(self):
"""
Retrieves the base MAC address for the module

View File

@ -34,13 +34,15 @@ class Psu(PsuBase):
self.psu_voltage_reg = "in30_input"
self.psu_current_reg = "curr602_input"
self.psu_power_reg = "power2_input"
self.psu_temperature_reg = "temp14_input"
elif self.index == 2:
self.psu_voltage_reg = "in32_input"
self.psu_current_reg = "curr702_input"
self.psu_power_reg = "power4_input"
self.psu_temperature_reg = "temp15_input"
# Passing True to specify it is a PSU fan
psu_fan = Fan(fan_index=self.index, psu_fan=True)
psu_fan = Fan(psu_index=self.index, psu_fan=True)
self._fan_list.append(psu_fan)
def _get_pmc_register(self, reg_name):
@ -232,3 +234,87 @@ class Psu(PsuBase):
# In S6100, SmartFusion FPGA controls the PSU LED and the PSU
# LED state cannot be changed from CPU.
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 PSU is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True
def get_temperature(self):
"""
Retrieves current temperature reading from PSU
Returns:
A float number of current temperature in Celsius up to
nearest thousandth of one degree Celsius, e.g. 30.125
"""
temperature = 0.0
if self.get_presence():
psu_temperature = self._get_pmc_register(self.psu_temperature_reg)
if (psu_temperature != 'ERR'):
temperature = float(psu_temperature) / 1000
return temperature
def get_temperature_high_threshold(self):
"""
Retrieves the high threshold temperature of PSU
Returns:
A float number, the high threshold temperature of PSU in
Celsius up to nearest thousandth of one degree Celsius,
e.g. 30.125
"""
return 90.0
def get_voltage_high_threshold(self):
"""
Retrieves the high threshold PSU voltage output
Returns:
A float number, the high threshold output voltage in volts,
e.g. 12.1
"""
voltage_high_threshold = 0.0
if self.get_presence():
psu_type = self._get_pmc_register(self.psu_presence_reg)
if (psu_type != 'ERR'):
psu_type = int(psu_type, 16)
if (psu_type & 0b10):
voltage_high_threshold = 12.6
else:
voltage_high_threshold = 12.8
return voltage_high_threshold
def get_voltage_low_threshold(self):
"""
Retrieves the low threshold PSU voltage output
Returns:
A float number, the low threshold output voltage in volts,
e.g. 12.1
"""
voltage_low_threshold = 0.0
if self.get_presence():
psu_type = self._get_pmc_register(self.psu_presence_reg)
if (psu_type != 'ERR'):
psu_type = int(psu_type, 16)
if (psu_type & 0b10):
voltage_low_threshold = 11.4
else:
voltage_low_threshold = 11.6
return voltage_low_threshold

View File

@ -10,6 +10,7 @@
try:
import re
import struct
import time
from sonic_platform_base.sfp_base import SfpBase
from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId
@ -27,6 +28,9 @@ INFO_OFFSET = 128
DOM_OFFSET = 0
DOM_OFFSET1 = 384
QSFP_CONTROL_OFFSET = 86
QSFP_POWEROVERRIDE_OFFSET = 93
cable_length_tup = ('Length(km)', 'Length OM3(2m)', 'Length OM2(m)',
'Length OM1(m)', 'Length Cable Assembly(m)')
@ -107,7 +111,7 @@ class Sfp(SfpBase):
sfp_control, sfp_ctrl_idx):
SfpBase.__init__(self)
self.sfp_type = sfp_type
self.index = index
self.index = index + 1
self.eeprom_path = eeprom_path
self.sfp_control = sfp_control
self.sfp_ctrl_idx = sfp_ctrl_idx
@ -131,9 +135,10 @@ class Sfp(SfpBase):
eeprom.close()
return None
raw = bytearray(raw)
try:
for n in range(0, num_bytes):
eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2)
eeprom_raw[n] = hex(raw[n])[2:].zfill(2)
except BaseException:
eeprom.close()
return None
@ -594,38 +599,12 @@ class Sfp(SfpBase):
"""
Retrieves the TX disabled channels in this SFP
"""
tx_disable = None
tx_disable_list = []
tx_disable_channel = 0
tx_disable_data = self._get_eeprom_data('tx_disable')
if (tx_disable_data is not None):
tx_disable = tx_disable_data['data']['Tx1Disable']['value']
if (tx_disable == 'On'):
tx_disable_list.append(1)
else:
tx_disable_list.append(0)
tx_disable = tx_disable_data['data']['Tx2Disable']['value']
if (tx_disable == 'On'):
tx_disable_list.append(1)
else:
tx_disable_list.append(0)
tx_disable = tx_disable_data['data']['Tx3Disable']['value']
if (tx_disable == 'On'):
tx_disable_list.append(1)
else:
tx_disable_list.append(0)
tx_disable = tx_disable_data['data']['Tx4Disable']['value']
if (tx_disable == 'On'):
tx_disable_list.append(1)
else:
tx_disable_list.append(0)
bit4 = int(tx_disable_list[3]) * 8
bit3 = int(tx_disable_list[2]) * 4
bit2 = int(tx_disable_list[1]) * 2
bit1 = int(tx_disable_list[0]) * 1
tx_disable_channel = hex(bit4 + bit3 + bit2 + bit1)
tx_disable = self.get_tx_disable()
for channel, disable in enumerate(tx_disable):
if disable:
tx_disable_channel |= 1 << channel
return tx_disable_channel
@ -836,19 +815,68 @@ class Sfp(SfpBase):
"""
Disable SFP TX for all channels
"""
eeprom = None
tx_disable_value = 0xf if tx_disable else 0x0
try:
eeprom = open(self.eeprom_path, "r+b")
eeprom.seek(QSFP_CONTROL_OFFSET)
eeprom.write(struct.pack('B', tx_disable_value))
except IOError:
return False
finally:
if eeprom is not None:
eeprom.close()
time.sleep(0.01)
return True
def tx_disable_channel(self, channel, disable):
"""
Sets the tx_disable for specified SFP channels
"""
eeprom = None
current_state = self.get_tx_disable_channel()
if disable:
tx_disable_value = current_state | channel
else:
tx_disable_value = current_state & (~channel)
try:
eeprom = open(self.eeprom_path, "r+b")
eeprom.seek(QSFP_CONTROL_OFFSET)
eeprom.write(struct.pack('B', tx_disable_value))
except IOError:
return False
finally:
if eeprom is not None:
eeprom.close()
time.sleep(0.01)
return True
def set_power_override(self, power_override, power_set):
"""
Sets SFP power level using power_override and power_set
"""
eeprom = None
power_override_bit = 0x1 if power_override else 0
power_set_bit = 0x2 if power_set else 0
value = power_override_bit | power_set_bit
try:
eeprom = open(self.eeprom_path, "r+b")
eeprom.seek(QSFP_POWEROVERRIDE_OFFSET)
eeprom.write(struct.pack('B', value))
except IOError:
return False
finally:
if eeprom is not None:
eeprom.close()
time.sleep(0.01)
return True
def get_status(self):
"""
@ -862,3 +890,20 @@ class Sfp(SfpBase):
status = True
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.index
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True

View File

@ -131,6 +131,23 @@ class Thermal(ThermalBase):
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.index
def is_replaceable(self):
"""
Indicate whether this Thermal is replaceable.
Returns:
bool: True if it is replaceable.
"""
return False
def get_temperature(self):
"""
Retrieves current temperature reading from thermal