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:
parent
276fade8c2
commit
0bae3b44ec
@ -1,4 +1,3 @@
|
||||
{
|
||||
"skip_ledd": true,
|
||||
"skip_thermalctld": true
|
||||
"skip_ledd": true
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
{
|
||||
"skip_ledd": true,
|
||||
"skip_thermalctld": true
|
||||
"skip_ledd": true
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user