[device/celestica]: Fix failed test cases of Haliburton platform API (#7579)

- Why I did it
To fix failed test cases of Haliburton platform APIs that found on platform_tests script
- How I did it
Add device/celestica/x86_64-cel_e1031-r0/platform.json
Update functions to support python3.7
Add more functions follow latest sonic_platform_base
Fix the bug
- How to verify it
Run platform_tests script

Signed-off-by: Wirut Getbamrung [wgetbumr@celestica.com]
This commit is contained in:
Wirut Getbamrung 2021-07-23 20:18:39 +07:00 committed by GitHub
parent 7698747028
commit 4bf873bf42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 2270 additions and 608 deletions

View File

@ -0,0 +1,758 @@
{
"chassis": {
"name": "Celestica-E1031-T48S4",
"components": [
{
"name": "SMC_CPLD"
},
{
"name": "MMC_CPLD"
},
{
"name": "BIOS"
}
],
"fans": [
{
"name": "FAN-1"
},
{
"name": "FAN-2"
},
{
"name": "FAN-3"
}
],
"fan_drawers": [
{
"name": "Drawer1",
"fans": [
{
"name": "FAN-1"
}
]
},
{
"name": "Drawer2",
"fans": [
{
"name": "FAN-2"
}
]
},
{
"name": "Drawer3",
"fans": [
{
"name": "FAN-3"
}
]
}
],
"psus": [
{
"name": "PSU-R",
"fans": [
{
"name": "PSU-1 FAN-1"
}
]
},
{
"name": "PSU-L",
"fans": [
{
"name": "PSU-2 FAN-1"
}
]
}
],
"thermals": [
{
"name": "Inlet ambient sensor (Rear to Front)"
},
{
"name": "Helix shutdown sensor (Rear to Front)"
},
{
"name": "Inlet ambient sensor (Front to Rear, right)"
},
{
"name": "Helix shutdown sensor (Front to Rear)"
},
{
"name": "Inlet ambient sensor (Front to Rear, left)"
},
{
"name": "CPU errata sensor (Front to Rear)"
},
{
"name": "CPU errata sensor (Rear to Front)"
}
],
"sfps": [
{
"name": "Ethernet54"
},
{
"name": "Ethernet0"
},
{
"name": "Ethernet1"
},
{
"name": "Ethernet2"
},
{
"name": "Ethernet3"
},
{
"name": "Ethernet4"
},
{
"name": "Ethernet5"
},
{
"name": "Ethernet6"
},
{
"name": "Ethernet7"
},
{
"name": "Ethernet8"
},
{
"name": "Ethernet9"
},
{
"name": "Ethernet10"
},
{
"name": "Ethernet11"
},
{
"name": "Ethernet12"
},
{
"name": "Ethernet13"
},
{
"name": "Ethernet14"
},
{
"name": "Ethernet15"
},
{
"name": "Ethernet16"
},
{
"name": "Ethernet17"
},
{
"name": "Ethernet18"
},
{
"name": "Ethernet19"
},
{
"name": "Ethernet20"
},
{
"name": "Ethernet21"
},
{
"name": "Ethernet22"
},
{
"name": "Ethernet23"
},
{
"name": "Ethernet24"
},
{
"name": "Ethernet25"
},
{
"name": "Ethernet26"
},
{
"name": "Ethernet27"
},
{
"name": "Ethernet28"
},
{
"name": "Ethernet29"
},
{
"name": "Ethernet30"
},
{
"name": "Ethernet31"
},
{
"name": "Ethernet32"
},
{
"name": "Ethernet33"
},
{
"name": "Ethernet34"
},
{
"name": "Ethernet35"
},
{
"name": "Ethernet36"
},
{
"name": "Ethernet37"
},
{
"name": "Ethernet38"
},
{
"name": "Ethernet39"
},
{
"name": "Ethernet40"
},
{
"name": "Ethernet41"
},
{
"name": "Ethernet42"
},
{
"name": "Ethernet43"
},
{
"name": "Ethernet44"
},
{
"name": "Ethernet45"
},
{
"name": "Ethernet46"
},
{
"name": "Ethernet47"
},
{
"name": "Ethernet48"
},
{
"name": "Ethernet49"
},
{
"name": "Ethernet50"
},
{
"name": "Ethernet51"
},
{
"name": "Ethernet52"
},
{
"name": "Ethernet53"
}
]
},
"interfaces": {
"Ethernet0": {
"index": "1",
"lanes": "2",
"breakout_modes": {
"1x1G": [
"etp1"
]
}
},
"Ethernet1": {
"index": "2",
"lanes": "1",
"breakout_modes": {
"1x1G": [
"etp2"
]
}
},
"Ethernet2": {
"index": "3",
"lanes": "4",
"breakout_modes": {
"1x1G": [
"etp3"
]
}
},
"Ethernet3": {
"index": "4",
"lanes": "3",
"breakout_modes": {
"1x1G": [
"etp4"
]
}
},
"Ethernet4": {
"index": "5",
"lanes": "6",
"breakout_modes": {
"1x1G": [
"etp5"
]
}
},
"Ethernet5": {
"index": "6",
"lanes": "5",
"breakout_modes": {
"1x1G": [
"etp6"
]
}
},
"Ethernet6": {
"index": "7",
"lanes": "8",
"breakout_modes": {
"1x1G": [
"etp7"
]
}
},
"Ethernet7": {
"index": "8",
"lanes": "7",
"breakout_modes": {
"1x1G": [
"etp8"
]
}
},
"Ethernet8": {
"index": "9",
"lanes": "10",
"breakout_modes": {
"1x1G": [
"etp9"
]
}
},
"Ethernet9": {
"index": "10",
"lanes": "9",
"breakout_modes": {
"1x1G": [
"etp10"
]
}
},
"Ethernet10": {
"index": "11",
"lanes": "12",
"breakout_modes": {
"1x1G": [
"etp11"
]
}
},
"Ethernet11": {
"index": "12",
"lanes": "11",
"breakout_modes": {
"1x1G": [
"etp12"
]
}
},
"Ethernet12": {
"index": "13",
"lanes": "14",
"breakout_modes": {
"1x1G": [
"etp13"
]
}
},
"Ethernet13": {
"index": "14",
"lanes": "13",
"breakout_modes": {
"1x1G": [
"etp14"
]
}
},
"Ethernet14": {
"index": "15",
"lanes": "16",
"breakout_modes": {
"1x1G": [
"etp15"
]
}
},
"Ethernet15": {
"index": "16",
"lanes": "15",
"breakout_modes": {
"1x1G": [
"etp16"
]
}
},
"Ethernet16": {
"index": "17",
"lanes": "18",
"breakout_modes": {
"1x1G": [
"etp17"
]
}
},
"Ethernet17": {
"index": "18",
"lanes": "17",
"breakout_modes": {
"1x1G": [
"etp18"
]
}
},
"Ethernet18": {
"index": "19",
"lanes": "20",
"breakout_modes": {
"1x1G": [
"etp19"
]
}
},
"Ethernet19": {
"index": "20",
"lanes": "19",
"breakout_modes": {
"1x1G": [
"etp20"
]
}
},
"Ethernet20": {
"index": "21",
"lanes": "22",
"breakout_modes": {
"1x1G": [
"etp21"
]
}
},
"Ethernet21": {
"index": "22",
"lanes": "21",
"breakout_modes": {
"1x1G": [
"etp22"
]
}
},
"Ethernet22": {
"index": "23",
"lanes": "24",
"breakout_modes": {
"1x1G": [
"etp23"
]
}
},
"Ethernet23": {
"index": "24",
"lanes": "23",
"breakout_modes": {
"1x1G": [
"etp24"
]
}
},
"Ethernet24": {
"index": "25",
"lanes": "26",
"breakout_modes": {
"1x1G": [
"etp25"
]
}
},
"Ethernet25": {
"index": "26",
"lanes": "25",
"breakout_modes": {
"1x1G": [
"etp26"
]
}
},
"Ethernet26": {
"index": "27",
"lanes": "28",
"breakout_modes": {
"1x1G": [
"etp27"
]
}
},
"Ethernet27": {
"index": "28",
"lanes": "27",
"breakout_modes": {
"1x1G": [
"etp28"
]
}
},
"Ethernet28": {
"index": "29",
"lanes": "30",
"breakout_modes": {
"1x1G": [
"etp29"
]
}
},
"Ethernet29": {
"index": "30",
"lanes": "29",
"breakout_modes": {
"1x1G": [
"etp30"
]
}
},
"Ethernet30": {
"index": "31",
"lanes": "32",
"breakout_modes": {
"1x1G": [
"etp31"
]
}
},
"Ethernet31": {
"index": "32",
"lanes": "31",
"breakout_modes": {
"1x1G": [
"etp32"
]
}
},
"Ethernet32": {
"index": "33",
"lanes": "34",
"breakout_modes": {
"1x1G": [
"etp33"
]
}
},
"Ethernet33": {
"index": "34",
"lanes": "33",
"breakout_modes": {
"1x1G": [
"etp34"
]
}
},
"Ethernet34": {
"index": "35",
"lanes": "36",
"breakout_modes": {
"1x1G": [
"etp35"
]
}
},
"Ethernet35": {
"index": "36",
"lanes": "35",
"breakout_modes": {
"1x1G": [
"etp36"
]
}
},
"Ethernet36": {
"index": "37",
"lanes": "38",
"breakout_modes": {
"1x1G": [
"etp37"
]
}
},
"Ethernet37": {
"index": "38",
"lanes": "37",
"breakout_modes": {
"1x1G": [
"etp38"
]
}
},
"Ethernet38": {
"index": "39",
"lanes": "40",
"breakout_modes": {
"1x1G": [
"etp39"
]
}
},
"Ethernet39": {
"index": "40",
"lanes": "39",
"breakout_modes": {
"1x1G": [
"etp40"
]
}
},
"Ethernet40": {
"index": "41",
"lanes": "42",
"breakout_modes": {
"1x1G": [
"etp41"
]
}
},
"Ethernet41": {
"index": "42",
"lanes": "41",
"breakout_modes": {
"1x1G": [
"etp42"
]
}
},
"Ethernet42": {
"index": "43",
"lanes": "44",
"breakout_modes": {
"1x1G": [
"etp43"
]
}
},
"Ethernet43": {
"index": "44",
"lanes": "43",
"breakout_modes": {
"1x1G": [
"etp44"
]
}
},
"Ethernet44": {
"index": "45",
"lanes": "46",
"breakout_modes": {
"1x1G": [
"etp45"
]
}
},
"Ethernet45": {
"index": "46",
"lanes": "45",
"breakout_modes": {
"1x1G": [
"etp46"
]
}
},
"Ethernet46": {
"index": "47",
"lanes": "48",
"breakout_modes": {
"1x1G": [
"etp47"
]
}
},
"Ethernet47": {
"index": "48",
"lanes": "47",
"breakout_modes": {
"1x1G": [
"etp48"
]
}
},
"Ethernet48": {
"index": "49",
"lanes": "48",
"breakout_modes": {
"1x10G": [
"etp49"
]
}
},
"Ethernet49": {
"index": "50",
"lanes": "53",
"breakout_modes": {
"1x10G": [
"etp50"
]
}
},
"Ethernet50": {
"index": "51",
"lanes": "56",
"breakout_modes": {
"1x10G": [
"etp51"
]
}
},
"Ethernet51": {
"index": "52",
"lanes": "55",
"breakout_modes": {
"1x10G": [
"etp52"
]
}
},
"Ethernet52": {
"index": "53",
"lanes": "49",
"breakout_modes": {
"1x10G": [
"etp53"
]
}
},
"Ethernet53": {
"index": "54,54,54,54",
"lanes": "57,58,59,60 ",
"breakout_modes": {
"1x10G": [
"etp54"
]
}
},
"Ethernet54": {
"index": "55,55,55,55",
"lanes": "61,62,63,64",
"breakout_modes": {
"1x10G": [
"etp55"
]
}
}
}
}

View File

@ -0,0 +1,11 @@
{
"chassis": {
"Celestica-E1031-T48S4": {
"component": {
"BIOS": {},
"SMC_CPLD": {},
"MMC_CPLD": {}
}
}
}
}

View File

@ -11,63 +11,17 @@ class SfpUtil(SfpUtilBase):
"""Platform-specific SfpUtil class"""
PORT_START = 1
PORT_END = 52
PORT_END = 55
SFP_PORT_START = 49
SFP_PORT_END = 52
port_to_i2c_mapping = {
1: None,
2: None,
3: None,
4: None,
5: None,
6: None,
7: None,
8: None,
9: None,
10: None,
11: None,
12: None,
13: None,
14: None,
15: None,
16: None,
17: None,
18: None,
19: None,
20: None,
21: None,
22: None,
23: None,
24: None,
25: None,
26: None,
27: None,
28: None,
29: None,
30: None,
31: None,
32: None,
33: None,
34: None,
35: None,
36: None,
37: None,
38: None,
39: None,
40: None,
41: None,
42: None,
43: None,
44: None,
45: None,
46: None,
47: None,
48: None,
49: 15,
50: 14,
51: 17,
52: 16
}
_port_to_eeprom_mapping = {}
_sfp_port = list(range(49, PORT_END + 1))
_sfp_port = list(range(SFP_PORT_START, SFP_PORT_END + 1))
@property
def port_start(self):
@ -89,7 +43,7 @@ class SfpUtil(SfpUtilBase):
# Override port_to_eeprom_mapping for class initialization
eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom'
for x in range(self.PORT_START, self.PORT_END + 1):
port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x])
port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x]) if x in self._sfp_port else None
self.port_to_eeprom_mapping[x] = port_eeprom_path
SfpUtilBase.__init__(self)
@ -103,7 +57,7 @@ class SfpUtil(SfpUtilBase):
try:
with open(sfp_modabs_path, 'r') as port_status:
status = int(port_status.read(), 16)
status = (status >> (port_num - 49)) & 1
status = (status >> (port_num - self.SFP_PORT_START)) & 1
except IOError:
return False
@ -138,7 +92,8 @@ class SfpUtil(SfpUtilBase):
for port_num in self._sfp_port:
change = (changes >> (port_num - 49)) & 1
if change == 1:
port_dict[str(port_num)] = str(int(self.get_presence(port_num)))
port_dict[str(port_num)] = str(
int(self.get_presence(port_num)))
found_flag = 1
if not found_flag:

View File

@ -6,25 +6,26 @@
#
#############################################################################
try:
import sys
from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper
from sonic_platform_base.chassis_base import ChassisBase
from sonic_py_common import device_info
from .common import Common
from .event import SfpEvent
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
NUM_FAN_TRAY = 3
NUM_FAN = 1
NUM_PSU = 2
NUM_THERMAL = 7
NUM_SFP = 52
NUM_SFP = 55
NUM_COMPONENT = 3
RESET_REGISTER = "0x112"
HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/previous-reboot-cause.txt"
PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/previous-reboot-cause.txt"
HOST_CHK_CMD = "docker > /dev/null 2>&1"
STATUS_LED_PATH = "/sys/devices/platform/e1031.smc/master_led"
class Chassis(ChassisBase):
@ -32,66 +33,63 @@ class Chassis(ChassisBase):
def __init__(self):
ChassisBase.__init__(self)
self._api_common = Common()
self.sfp_module_initialized = False
self._is_host = self._api_common.is_host()
self.__initialize_eeprom()
self.is_host = self._api_common.is_host()
self.__initialize_fan()
self.__initialize_psu()
self.__initialize_thermals()
self.__initialize_components()
if not self.is_host:
self.__initialize_fan()
self.__initialize_psu()
self.__initialize_thermals()
else:
self.__initialize_components()
self._reboot_cause_path = HOST_REBOOT_CAUSE_PATH if self.__is_host(
) else PMON_REBOOT_CAUSE_PATH
self.sfp_module_initialized = False
self._reboot_cause_path = HOST_REBOOT_CAUSE_PATH if self._is_host else PMON_REBOOT_CAUSE_PATH
def __initialize_sfp(self):
sfputil_helper = SfpUtilHelper()
port_config_file_path = device_info.get_path_to_port_config_file()
sfputil_helper.read_porttab_mappings(port_config_file_path, 0)
from sonic_platform.sfp import Sfp
from .sfp import Sfp
for index in range(0, NUM_SFP):
name_idx = 0 if index+1 == NUM_SFP else index+1
sfp = Sfp(index, sfputil_helper.logical[name_idx])
sfp = Sfp(index, sfputil_helper.logical[index])
self._sfp_list.append(sfp)
self.sfp_module_initialized = True
def __initialize_psu(self):
from sonic_platform.psu import Psu
from .psu import Psu
for index in range(0, NUM_PSU):
psu = Psu(index)
self._psu_list.append(psu)
def __initialize_fan(self):
from sonic_platform.fan import Fan
for fant_index in range(0, NUM_FAN_TRAY):
for fan_index in range(0, NUM_FAN):
fan = Fan(fant_index, fan_index)
self._fan_list.append(fan)
from .fan_drawer import FanDrawer
for i in range(NUM_FAN_TRAY):
fandrawer = FanDrawer(i)
self._fan_drawer_list.append(fandrawer)
self._fan_list += fandrawer.get_all_fans()
def __initialize_thermals(self):
from sonic_platform.thermal import Thermal
from .thermal import Thermal
airflow = self.__get_air_flow()
for index in range(0, NUM_THERMAL):
thermal = Thermal(index, airflow)
self._thermal_list.append(thermal)
def __initialize_eeprom(self):
from sonic_platform.eeprom import Tlv
from .eeprom import Tlv
self._eeprom = Tlv()
def __initialize_components(self):
from sonic_platform.component import Component
from .component import Component
for index in range(0, NUM_COMPONENT):
component = Component(index)
self._component_list.append(component)
def __get_air_flow(self):
air_flow_path = '/usr/share/sonic/device/{}/fan_airflow'.format(
self._api_common.platform) if self.is_host else '/usr/share/sonic/platform/fan_airflow'
self._api_common.get_platform()) if self._is_host else '/usr/share/sonic/platform/fan_airflow'
air_flow = self._api_common.read_txt_file(air_flow_path)
return air_flow or 'B2F'
@ -154,7 +152,6 @@ class Chassis(ChassisBase):
else:
reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE
description = 'Unknown reason'
return (reboot_cause, description)
def get_watchdog(self):
@ -247,8 +244,8 @@ class Chassis(ChassisBase):
# The index will start from 1
sfp = self._sfp_list[index-1]
except IndexError:
sys.stderr.write("SFP index {} out of range (1-{})\n".format(
index, len(self._sfp_list)))
print("SFP index {} out of range (1-{})\n".format(
index, len(self._sfp_list)))
return sfp
##############################################################
@ -269,13 +266,13 @@ class Chassis(ChassisBase):
Returns:
string: The name of the device
"""
return self._api_common.hwsku
return self._api_common.get_hwsku()
def get_presence(self):
"""
Retrieves the presence of the PSU
Retrieves the presence of the Chassis
Returns:
bool: True if PSU is present, False if not
bool: True if Chassis is present, False if not
"""
return True
@ -303,3 +300,52 @@ class Chassis(ChassisBase):
"""
return True
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
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 this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return False
def set_status_led(self, color):
"""
Sets the state of the PSU status LED
Args:
color: A string representing the color with which to set the PSU status LED
Note: Only support green and off
Returns:
bool: True if status LED state is set successfully, False if not
"""
status_str = {
self.STATUS_LED_COLOR_GREEN: 'green',
self.STATUS_LED_COLOR_AMBER: 'amber',
self.STATUS_LED_COLOR_OFF: 'off'
}.get(color, 'off')
return self._api_common.write_txt_file(STATUS_LED_PATH, status_str)
def get_status_led(self):
"""
Gets the state of the PSU status LED
Returns:
A string, one of the predefined STATUS_LED_COLOR_* strings above
"""
status = self._api_common.read_txt_file(STATUS_LED_PATH)
status_str = {
'on': self.STATUS_LED_COLOR_GREEN,
'amber': self.STATUS_LED_COLOR_AMBER,
'off': self.STATUS_LED_COLOR_OFF
}.get(status, None)
return status_str

View File

@ -29,7 +29,18 @@ class Common:
def __init__(self, conf=None):
self._main_conf = conf
(self.platform, self.hwsku) = device_info.get_platform_and_hwsku()
self.platform = None
self.hwsku = None
def get_platform(self):
(self.platform, self.hwsku) = device_info.get_platform_and_hwsku(
) if not self.platform else (self.platform, self.hwsku)
return self.platform
def get_hwsku(self):
(self.platform, self.hwsku) = device_info.get_platform_and_hwsku(
) if not self.hwsku else (self.platform, self.hwsku)
return self.hwsku
def run_command(self, command):
status = False
@ -38,7 +49,7 @@ class Common:
p = subprocess.Popen(
command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
raw_data, err = p.communicate()
if err == '':
if p.returncode == 0:
status, output = True, raw_data.strip()
except Exception:
pass
@ -152,10 +163,28 @@ class Common:
status, output = self.run_command(cmd)
return output if status else None
def set_reg(self, path, reg_addr, value):
cmd = "echo {0} {1} > {2}".format(reg_addr, value, path)
status, output = self.run_command(cmd)
return output if status else None
def read_txt_file(self, path):
with open(path, 'r') as f:
output = f.readline()
return output.strip('\n')
try:
with open(path, 'r') as f:
output = f.readline()
return output.strip('\n')
except Exception:
pass
return ''
def read_one_line_file(self, file_path):
try:
with open(file_path, 'r') as fd:
data = fd.readline()
return data.strip()
except IOError:
pass
return ''
def write_txt_file(self, file_path, value):
try:

View File

@ -6,12 +6,12 @@
#
#############################################################################
import os.path
import shutil
import shlex
import subprocess
try:
import os.path
import shutil
import shlex
import subprocess
from sonic_platform_base.component_base import ComponentBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
@ -119,6 +119,29 @@ class Component(ComponentBase):
return fw_version
def get_available_firmware_version(self, image_path):
"""
Retrieves the available firmware version of the component
Note: the firmware version will be read from image
Args:
image_path: A string, path to firmware image
Returns:
A string containing the available firmware version of the component
"""
return "N/A"
def get_firmware_update_notification(self, image_path):
"""
Retrieves a notification on what should be done in order to complete
the component firmware update
Args:
image_path: A string, path to firmware image
Returns:
A string containing the component firmware update notification if required.
By default 'None' value will be used, which indicates that no actions are required
"""
return "None"
def install_firmware(self, image_path):
"""
Install firmware to module
@ -139,5 +162,73 @@ class Component(ComponentBase):
install_command = "ispvm %s" % new_image_path
# elif self.name == "BIOS":
# install_command = "afulnx_64 %s /p /b /n /x /r" % image_path
return self.__run_command(install_command)
def update_firmware(self, image_path):
"""
Updates firmware of the component
This API performs firmware update: it assumes firmware installation and loading in a single call.
In case platform component requires some extra steps (apart from calling Low Level Utility)
to load the installed firmware (e.g, reboot, power cycle, etc.) - this will be done automatically by API
Args:
image_path: A string, path to firmware image
Raises:
RuntimeError: update failed
"""
return False
##############################################################
###################### Device methods ########################
##############################################################
def get_presence(self):
"""
Retrieves the presence of the FAN
Returns:
bool: True if FAN is present, False if not
"""
return True
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return 'N/A'
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return 'N/A'
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return True
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device.
If the agent cannot determine the parent-relative position
for some reason, or if the associated value of
entPhysicalContainedIn is'0', then the value '-1' is returned
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 this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return False

View File

@ -17,13 +17,14 @@ try:
else:
from cStringIO import StringIO
from sonic_platform_base.sonic_eeprom import eeprom_dts
from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo
from sonic_platform_base.sonic_eeprom.eeprom_base import EepromDecoder
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
CACHE_ROOT = '/var/cache/sonic/decode-syseeprom'
CACHE_FILE = 'syseeprom_cache'
NULL = 'N/A'
class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
@ -32,8 +33,8 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
def __init__(self):
self._eeprom_path = "/sys/class/i2c-adapter/i2c-2/2-0050/eeprom"
self._eeprom = None
super(Tlv, self).__init__(self._eeprom_path, 0, '', True)
self._eeprom = self._load_eeprom()
def __parse_output(self, decode_output):
decode_output.replace('\0', '')
@ -50,7 +51,7 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
value = match.group(3).rstrip('\0')
_eeprom_info_dict[idx] = value
except Exception:
except BaseException:
pass
return _eeprom_info_dict
@ -59,7 +60,7 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
sys.stdout = StringIO()
try:
self.read_eeprom_db()
except Exception:
except BaseException:
decode_output = sys.stdout.getvalue()
sys.stdout = original_stdout
return self.__parse_output(decode_output)
@ -71,7 +72,7 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
if not os.path.exists(CACHE_ROOT):
try:
os.makedirs(CACHE_ROOT)
except Exception:
except BaseException:
pass
#
@ -80,7 +81,7 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
#
try:
self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE))
except Exception:
except BaseException:
pass
e = self.read_eeprom()
@ -89,7 +90,7 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
try:
self.update_cache(e)
except Exception:
except BaseException:
pass
self.decode_eeprom(e)
@ -102,14 +103,98 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
return self.__parse_output(decode_output)
def _valid_tlv(self, eeprom_data):
tlvinfo_type_codes_list = [
self._TLV_CODE_PRODUCT_NAME,
self._TLV_CODE_PART_NUMBER,
self._TLV_CODE_SERIAL_NUMBER,
self._TLV_CODE_MAC_BASE,
self._TLV_CODE_MANUF_DATE,
self._TLV_CODE_DEVICE_VERSION,
self._TLV_CODE_LABEL_REVISION,
self._TLV_CODE_PLATFORM_NAME,
self._TLV_CODE_ONIE_VERSION,
self._TLV_CODE_MAC_SIZE,
self._TLV_CODE_MANUF_NAME,
self._TLV_CODE_MANUF_COUNTRY,
self._TLV_CODE_VENDOR_NAME,
self._TLV_CODE_DIAG_VERSION,
self._TLV_CODE_SERVICE_TAG,
self._TLV_CODE_VENDOR_EXT,
self._TLV_CODE_CRC_32
]
for code in tlvinfo_type_codes_list:
code_str = "0x{:X}".format(code)
eeprom_data[code_str] = eeprom_data.get(code_str, NULL)
return eeprom_data
def get_eeprom(self):
return self._eeprom
def get_serial(self):
return self._eeprom.get('0x23', "Undefined.")
def get_mac(self):
return self._eeprom.get('0x24', "Undefined.")
self._eeprom = self._load_eeprom() if not self._eeprom else self._eeprom
return self._valid_tlv(self._eeprom)
def get_pn(self):
return self._eeprom.get('0x21', "Undefined.")
return self.get_eeprom()['0x22']
def get_serial(self):
return self.get_eeprom()['0x23']
def get_mac(self):
return self.get_eeprom()['0x24']
class DeviceEEPROM(eeprom_tlvinfo.TlvInfoDecoder):
def __init__(self, eeprom_path, device_format, start_offset):
# Decode device eeprom as per specified format
self.format = device_format
self.start_offset = start_offset
EepromDecoder.__init__(self, eeprom_path, self.format,
self.start_offset, '', True)
self._load_device_eeprom()
def _load_device_eeprom(self):
"""
Reads the Fan/PSU EEPROM and interprets as per the specified format
"""
self.serial_number = 'NA'
self.model_str = 'NA'
# device eeproms use proprietary format
try:
# Read Fan/PSU EEPROM as per the specified format.
self.eeprom_data = EepromDecoder.read_eeprom(self)
except Exception as e:
return
if self.eeprom_data[0] == 255:
return
(valid, data) = self._get_eeprom_field("Model")
if valid:
self.model_str = data.decode()
try:
(valid, data) = self._get_eeprom_field("Serial Number")
if valid:
self.serial_number = data.decode()
except Exception as e:
return
def _get_eeprom_field(self, field_name, decode=False):
"""
For a field name specified in the EEPROM format, returns the
presence of the field and the value for the same.
"""
field_start = 0
for field in self.format:
field_end = field_start + field[2]
if field[0] == field_name:
if decode:
return (True, self.eeprom_data[field_start:field_end].decode('ascii'))
else:
return (True, self.eeprom_data[field_start:field_end])
field_start = field_end
return (False, None)

View File

@ -1,7 +1,7 @@
try:
import time
import select
from .helper import APIHelper
from .common import Common
from sonic_py_common.logger import Logger
except ImportError as e:
raise ImportError(repr(e) + " - required module not found")
@ -16,12 +16,12 @@ class SfpEvent:
GPIO_SUS7 = '/sys/devices/platform/hlx-ich.0/sci_int_gpio_sus7'
def __init__(self, sfp_list):
self._api_helper = APIHelper()
self._api_common = Common()
self._sfp_list = sfp_list
self._logger = Logger()
# clear interrupt
self._api_helper.read_one_line_file(self.INT_PATH)
self._api_common.read_one_line_file(self.INT_PATH)
def get_sfp_event(self, timeout):
epoll = select.epoll()
@ -37,7 +37,7 @@ class SfpEvent:
events = epoll.poll(timeout=timeout_sec if timeout != 0 else -1)
if events:
# Read the QSFP ABS interrupt & status registers
port_changes = self._api_helper.read_one_line_file(
port_changes = self._api_common.read_one_line_file(
self.INT_PATH)
changes = int(port_changes, 16)
for sfp in self._sfp_list:
@ -48,7 +48,8 @@ class SfpEvent:
if change == 1:
time.sleep(self.DELAY)
port_status = sfp.get_presence()
port_dict[str(sfp.port_num)] = '1' if port_status else '0'
port_dict[str(sfp.port_num)
] = '1' if port_status else '0'
return port_dict
except Exception as e:

View File

@ -6,6 +6,7 @@
#
#############################################################################
from __future__ import division
import math
import os.path
@ -20,8 +21,10 @@ FAN_PATH = "/sys/devices/platform/e1031.smc/"
EMC2305_MAX_PWM = 255
EMC2305_FAN_PWM = "pwm{}"
EMC2305_FAN_TARGET = "fan{}_target"
EMC2305_FAN_PWM_MODE = "pwm{}_enable"
EMC2305_FAN_INPUT = "pwm{}"
FAN_NAME_LIST = ["FAN-1", "FAN-2", "FAN-3"]
FAN_SPEED_TOLERANCE = 10
PSU_FAN_MAX_RPM = 11000
PSU_HWMON_PATH = "/sys/bus/i2c/devices/i2c-{0}/{0}-00{1}/hwmon"
PSU_I2C_MAPPING = {
@ -34,12 +37,16 @@ PSU_I2C_MAPPING = {
"addr": "5a"
},
}
NULL_VAL = 'N/A'
class Fan(FanBase):
"""Platform-specific Fan class"""
def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0):
FanBase.__init__(self)
self._api_common = Common()
self.fan_index = fan_index
self.fan_tray_index = fan_tray_index
self.is_psu_fan = is_psu_fan
@ -64,13 +71,10 @@ class Fan(FanBase):
self.fan_e1031_led = "fan{}_led"
self.fan_e1031_led_col_map = {
self.STATUS_LED_COLOR_GREEN: "green",
self.STATUS_LED_COLOR_RED: "amber",
self.STATUS_LED_COLOR_AMBER: "amber",
self.STATUS_LED_COLOR_OFF: "off"
}
self._api_common = Common()
FanBase.__init__(self)
def __search_file_by_name(self, directory, file_name):
for dirpath, dirnames, files in os.walk(directory):
for name in files:
@ -141,19 +145,26 @@ class Fan(FanBase):
0 : when PWM mode is use
pwm : when pwm mode is not use
"""
target = 0
target = NULL_VAL
if not self.is_psu_fan:
chip = self.emc2305_chip_mapping[self.fan_index]
device = chip['device']
fan_index = chip['index_map']
sysfs_path = "%s%s/%s" % (
EMC2305_PATH, device, EMC2305_FAN_TARGET)
sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index])
raw = self._api_common.read_txt_file(sysfs_path).strip('\r\n')
enable_path = "%s%s/%s" % (
EMC2305_PATH, device, EMC2305_FAN_PWM_MODE)
enable = self._api_common.read_txt_file(
enable_path.format(fan_index[self.fan_tray_index]))
target_mode = EMC2305_FAN_TARGET if enable != "0" else EMC2305_FAN_PWM
target_path = "%s%s/%s" % (EMC2305_PATH, device,
target_mode.format(fan_index[self.fan_tray_index]))
raw = self._api_common.read_txt_file(target_path)
pwm = int(raw, 10) if raw else 0
target = math.ceil(float(pwm) * 100 / EMC2305_MAX_PWM)
return target
return int(target)
def get_speed_tolerance(self):
"""
@ -162,7 +173,7 @@ class Fan(FanBase):
An integer, the percentage of variance from target speed which is
considered tolerable
"""
return 10
return FAN_SPEED_TOLERANCE
def set_speed(self, speed):
"""
@ -211,6 +222,28 @@ class Fan(FanBase):
return set_status_led
def get_status_led(self):
"""
Gets the state of the fan status LED
Returns:
A string, one of the predefined STATUS_LED_COLOR_* strings above
"""
led = self.STATUS_LED_COLOR_GREEN
if not self.is_psu_fan:
fan_led_file = (FAN_PATH +
self.fan_e1031_led.format(self.fan_tray_index+1))
led = self._api_common.read_txt_file(fan_led_file)
return {
'green': self.STATUS_LED_COLOR_GREEN,
'off': self.STATUS_LED_COLOR_OFF,
'amber': self.STATUS_LED_COLOR_AMBER
}.get(led, self.STATUS_LED_COLOR_OFF)
##############################################################
###################### Device methods ########################
##############################################################
def get_name(self):
"""
Retrieves the name of the device
@ -240,11 +273,7 @@ class Fan(FanBase):
Returns:
string: Model/part number of device
"""
if self.is_psu_fan:
return NULL_VAL
model = NULL_VAL
return model
return NULL_VAL
def get_serial(self):
"""
@ -252,11 +281,7 @@ class Fan(FanBase):
Returns:
string: Serial number of device
"""
if self.is_psu_fan:
return NULL_VAL
serial = NULL_VAL
return serial
return NULL_VAL
def get_status(self):
"""
@ -269,7 +294,7 @@ class Fan(FanBase):
fan_fault_sysfs_name = "fan1_fault"
fan_fault_sysfs_path = self.__search_file_by_name(
self.psu_hwmon_path, fan_fault_sysfs_name)
status = self._api_common.read_txt_file(fan_fault_sysfs_path)
status = self._api_common.read_one_line_file(fan_fault_sysfs_path)
elif self.get_presence():
chip = self.emc2305_chip_mapping[self.fan_index]
@ -278,7 +303,27 @@ class Fan(FanBase):
sysfs_path = "%s%s/%s" % (
EMC2305_PATH, device, 'fan{}_fault')
sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index])
status = self._api_common.read_txt_file(sysfs_path)
status = self._api_common.read_one_line_file(sysfs_path)
return False if int(status) != 0 else True
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device.
If the agent cannot determine the parent-relative position
for some reason, or if the associated value of
entPhysicalContainedIn is'0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device
or -1 if cannot determine the position
"""
return (self.fan_tray_index*2 + self.fan_index + 1) \
if not self.is_psu_fan else (self.fan_index+1)
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True if not self.is_psu_fan else False

View File

@ -0,0 +1,108 @@
#!/usr/bin/env python
#############################################################################
# Celestica
#
# Module contains an implementation of SONiC Platform Base API and
# provides the the Fan-Drawers' information available in the platform
#
#############################################################################
try:
from sonic_platform_base.fan_drawer_base import FanDrawerBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
NUM_FAN = 1
class FanDrawer(FanDrawerBase):
def __init__(self, fantray_index):
FanDrawerBase.__init__(self)
self._index = fantray_index + 1
self._init_fan(fantray_index)
def _init_fan(self, fantray_index):
from sonic_platform.fan import Fan
for index in range(NUM_FAN):
fan = Fan(fantray_index, index)
self._fan_list.append(fan)
def set_status_led(self, color):
"""
Sets the state of the fan drawer status LED
Args:
color: A string representing the color with which to set the
fan drawer status LED
Returns:
bool: True if status LED state is set successfully, False if not
"""
return self._fan_list[0].set_status_led(color)
def get_status_led(self, color=None):
"""
Gets the state of the fan drawer LED
Returns:
A string, one of the predefined STATUS_LED_COLOR_* strings above
"""
return self._fan_list[0].get_status_led()
##############################################################
###################### Device methods ########################
##############################################################
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
return "Drawer{}".format(self._index)
def get_presence(self):
"""
Retrieves the presence of the device
Returns:
bool: True if device is present, False if not
"""
return self._fan_list[0].get_presence()
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return self._fan_list[0].get_model()
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return self._fan_list[0].get_serial()
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return self._fan_list[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
"""
return self._index
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True

View File

@ -1,133 +0,0 @@
import os
import struct
import subprocess
from mmap import *
from sonic_py_common import device_info
HOST_CHK_CMD = "docker > /dev/null 2>&1"
EMPTY_STRING = ""
class APIHelper():
def __init__(self):
(self.platform, self.hwsku) = device_info.get_platform_and_hwsku()
def is_host(self):
return os.system(HOST_CHK_CMD) == 0
def pci_get_value(self, resource, offset):
status = True
result = ""
try:
fd = os.open(resource, os.O_RDWR)
mm = mmap(fd, 0)
mm.seek(int(offset))
read_data_stream = mm.read(4)
result = struct.unpack('I', read_data_stream)
except Exception:
status = False
return status, result
def run_command(self, cmd):
status = True
result = ""
try:
p = subprocess.Popen(
cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
raw_data, err = p.communicate()
if err == '':
result = raw_data.strip()
except Exception:
status = False
return status, result
def run_interactive_command(self, cmd):
try:
os.system(cmd)
except Exception:
return False
return True
def read_txt_file(self, file_path):
try:
with open(file_path, 'r') as fd:
data = fd.read()
return data.strip()
except IOError:
pass
return None
def read_one_line_file(self, file_path):
try:
with open(file_path, 'r') as fd:
data = fd.readline()
return data.strip()
except IOError:
pass
return None
def write_txt_file(self, file_path, value):
try:
with open(file_path, 'w') as fd:
fd.write(str(value))
except Exception:
return False
return True
def get_cpld_reg_value(self, getreg_path, register):
cmd = "echo {1} > {0}; cat {0}".format(getreg_path, register)
status, result = self.run_command(cmd)
return result if status else None
def ipmi_raw(self, netfn, cmd):
status = True
result = ""
try:
cmd = "ipmitool raw {} {}".format(str(netfn), str(cmd))
p = subprocess.Popen(
cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
raw_data, err = p.communicate()
if err == '':
result = raw_data.strip()
else:
status = False
except Exception:
status = False
return status, result
def ipmi_fru_id(self, id, key=None):
status = True
result = ""
try:
cmd = "ipmitool fru print {}".format(str(
id)) if not key else "ipmitool fru print {0} | grep '{1}' ".format(str(id), str(key))
p = subprocess.Popen(
cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
raw_data, err = p.communicate()
if err == '':
result = raw_data.strip()
else:
status = False
except Exception:
status = False
return status, result
def ipmi_set_ss_thres(self, id, threshold_key, value):
status = True
result = ""
try:
cmd = "ipmitool sensor thresh '{}' {} {}".format(
str(id), str(threshold_key), str(value))
p = subprocess.Popen(
cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
raw_data, err = p.communicate()
if err == '':
result = raw_data.strip()
else:
status = False
except Exception:
status = False
return status, result

View File

@ -11,10 +11,13 @@ import os.path
try:
from sonic_platform_base.psu_base import PsuBase
from sonic_platform.fan import Fan
from .common import Common
from .eeprom import DeviceEEPROM
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
FAN_E1031_SPEED_PATH = "/sys/class/hwmon/hwmon{}/fan1_input"
PSU_E1031_STAT_PATH = "/sys/devices/platform/e1031.smc/"
HWMON_PATH = "/sys/bus/i2c/devices/i2c-{0}/{0}-00{1}/hwmon"
FAN_MAX_RPM = 11000
PSU_NAME_LIST = ["PSU-R", "PSU-L"]
@ -22,13 +25,22 @@ PSU_NUM_FAN = [1, 1]
PSU_I2C_MAPPING = {
0: {
"num": 13,
"addr": "5b"
"addr": "5b",
"eeprom_addr": "53"
},
1: {
"num": 12,
"addr": "5a"
"addr": "5a",
"eeprom_addr": "52"
},
}
PSU_EEPROM_PATH = "/sys/bus/i2c/devices/{}-00{}/eeprom"
PSU_EEPROM_FORMAT = [
('Serial Number', 's', 16), ('burn', 'x', 16),
('Model', 's', 16),
('Part Number', 's', 16),
]
PSU_EEPROM_START_OFFSET = 48
class Psu(PsuBase):
@ -36,32 +48,26 @@ class Psu(PsuBase):
def __init__(self, psu_index):
PsuBase.__init__(self)
self._api_common = Common()
self.index = psu_index
self.psu_path = "/sys/devices/platform/e1031.smc/"
self.psu_presence = "psu{}_prs"
self.psu_oper_status = "psu{}_status"
self.i2c_num = PSU_I2C_MAPPING[self.index]["num"]
self.i2c_addr = PSU_I2C_MAPPING[self.index]["addr"]
self.hwmon_path = HWMON_PATH.format(self.i2c_num, self.i2c_addr)
self.eeprom_addr = PSU_EEPROM_PATH.format(
self.i2c_num, PSU_I2C_MAPPING[self.index]["eeprom_addr"])
for fan_index in range(0, PSU_NUM_FAN[self.index]):
fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index)
self._fan_list.append(fan)
PsuBase.__init__(self)
def __read_txt_file(self, file_path):
try:
with open(file_path, 'r') as fd:
data = fd.read()
return data.strip()
except IOError:
pass
return ""
def __search_file_by_contain(self, directory, search_str, file_start):
def _search_file_by_contain(self, directory, search_str, file_start):
for dirpath, dirnames, files in os.walk(directory):
for name in files:
file_path = os.path.join(dirpath, name)
if name.startswith(file_start) and search_str in self.__read_txt_file(file_path):
if name.startswith(file_start) and search_str in self._api_common.read_txt_file(file_path):
return file_path
return None
@ -76,7 +82,7 @@ class Psu(PsuBase):
voltage_name = "in{}_input"
voltage_label = "vout1"
vout_label_path = self.__search_file_by_contain(
vout_label_path = self._search_file_by_contain(
self.hwmon_path, voltage_label, "in")
if vout_label_path:
dir_name = os.path.dirname(vout_label_path)
@ -84,7 +90,7 @@ class Psu(PsuBase):
in_num = ''.join(list(filter(str.isdigit, basename)))
vout_path = os.path.join(
dir_name, voltage_name.format(in_num))
vout_val = self.__read_txt_file(vout_path)
vout_val = self._api_common.read_txt_file(vout_path)
psu_voltage = float(vout_val) / 1000
return psu_voltage
@ -99,7 +105,7 @@ class Psu(PsuBase):
current_name = "curr{}_input"
current_label = "iout1"
curr_label_path = self.__search_file_by_contain(
curr_label_path = self._search_file_by_contain(
self.hwmon_path, current_label, "cur")
if curr_label_path:
dir_name = os.path.dirname(curr_label_path)
@ -107,7 +113,7 @@ class Psu(PsuBase):
cur_num = ''.join(list(filter(str.isdigit, basename)))
cur_path = os.path.join(
dir_name, current_name.format(cur_num))
cur_val = self.__read_txt_file(cur_path)
cur_val = self._api_common.read_txt_file(cur_path)
psu_current = float(cur_val) / 1000
return psu_current
@ -122,7 +128,7 @@ class Psu(PsuBase):
current_name = "power{}_input"
current_label = "pout1"
pw_label_path = self.__search_file_by_contain(
pw_label_path = self._search_file_by_contain(
self.hwmon_path, current_label, "power")
if pw_label_path:
dir_name = os.path.dirname(pw_label_path)
@ -130,7 +136,7 @@ class Psu(PsuBase):
pw_num = ''.join(list(filter(str.isdigit, basename)))
pw_path = os.path.join(
dir_name, current_name.format(pw_num))
pw_val = self.__read_txt_file(pw_path)
pw_val = self._api_common.read_txt_file(pw_path)
psu_power = float(pw_val) / 1000000
return psu_power
@ -165,6 +171,10 @@ class Psu(PsuBase):
# Hardware not supported
return self.STATUS_LED_COLOR_OFF
##############################################################
###################### Device methods ########################
##############################################################
def get_name(self):
"""
Retrieves the name of the device
@ -180,8 +190,8 @@ class Psu(PsuBase):
bool: True if PSU is present, False if not
"""
psu_location = ["R", "L"]
presences_status = self.__read_txt_file(
self.psu_path + self.psu_presence.format(psu_location[self.index])) or 0
presences_status = self._api_common.read_txt_file(
PSU_E1031_STAT_PATH + self.psu_presence.format(psu_location[self.index])) or 0
return int(presences_status) == 1
@ -192,7 +202,153 @@ class Psu(PsuBase):
A boolean value, True if device is operating properly, False if not
"""
psu_location = ["R", "L"]
power_status = self.__read_txt_file(
self.psu_path + self.psu_oper_status.format(psu_location[self.index])) or 0
power_status = self._api_common.read_txt_file(
PSU_E1031_STAT_PATH + self.psu_oper_status.format(psu_location[self.index])) or 0
return int(power_status) == 1
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
self._eeprom = DeviceEEPROM(
self.eeprom_addr, PSU_EEPROM_FORMAT, PSU_EEPROM_START_OFFSET)
return self._eeprom.model_str
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
self._eeprom = DeviceEEPROM(
self.eeprom_addr, PSU_EEPROM_FORMAT, PSU_EEPROM_START_OFFSET)
return self._eeprom.serial_number
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
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 this device 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
there are three temp sensors , we choose one of them
"""
psu_temperature = None
temperature_name = "temp{}_input"
temperature_label = "vout1"
vout_label_path = self._search_file_by_contain(
self.hwmon_path, temperature_label, "in")
if vout_label_path:
dir_name = os.path.dirname(vout_label_path)
basename = os.path.basename(vout_label_path)
in_num = ''.join(list(filter(str.isdigit, basename)))
temp_path = os.path.join(
dir_name, temperature_name.format(in_num))
vout_val = self._api_common.read_txt_file(temp_path)
psu_temperature = float(vout_val) / 1000
return psu_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
there are three temp sensors , we choose one of them
"""
psu_temperature = None
temperature_name = "temp{}_max"
temperature_label = "vout1"
vout_label_path = self._search_file_by_contain(
self.hwmon_path, temperature_label, "in")
if vout_label_path:
dir_name = os.path.dirname(vout_label_path)
basename = os.path.basename(vout_label_path)
in_num = ''.join(list(filter(str.isdigit, basename)))
temp_path = os.path.join(
dir_name, temperature_name.format(in_num))
vout_val = self._api_common.read_txt_file(temp_path)
psu_temperature = float(vout_val) / 1000
return psu_temperature
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
"""
psu_voltage = 12.6
voltage_name = "in{}_crit"
voltage_label = "vout1"
vout_label_path = self._search_file_by_contain(
self.hwmon_path, voltage_label, "in")
if vout_label_path:
dir_name = os.path.dirname(vout_label_path)
basename = os.path.basename(vout_label_path)
in_num = ''.join(list(filter(str.isdigit, basename)))
vout_path = os.path.join(
dir_name, voltage_name.format(in_num))
if os.path.exists(vout_path):
vout_val = self._api_common.read_txt_file(vout_path)
psu_voltage = float(vout_val) / 1000
return psu_voltage
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
"""
psu_voltage = 11.4
voltage_name = "in{}_lcrit"
voltage_label = "vout1"
vout_label_path = self._search_file_by_contain(
self.hwmon_path, voltage_label, "in")
if vout_label_path:
dir_name = os.path.dirname(vout_label_path)
basename = os.path.basename(vout_label_path)
in_num = ''.join(list(filter(str.isdigit, basename)))
vout_path = os.path.join(
dir_name, voltage_name.format(in_num))
if os.path.exists(vout_path):
vout_val = self._api_common.read_txt_file(vout_path)
psu_voltage = float(vout_val) / 1000
return psu_voltage
def get_maximum_supplied_power(self):
"""
Retrieves the maximum supplied power by PSU
Returns:
A float number, the maximum power output in Watts.
e.g. 1200.1
"""
return 200.0

File diff suppressed because it is too large Load Diff

View File

@ -93,7 +93,6 @@ I2C_ADAPTER_PATH = "/sys/class/i2c-adapter"
class Thermal(ThermalBase):
"""Platform-specific Thermal class"""
THERMAL_NAME_LIST = []
MAINBOARD_SS_PATH = "/sys/class/i2c-adapter/i2c-11/11-001a/hwmon/hwmon2"
CPUBOARD_SS_PATH = "/sys/class/i2c-adapter/i2c-3/3-001a/hwmon/hwmon1"
SS_CONFIG_PATH = "/usr/share/sonic/device/x86_64-cel_e1031-r0/sensors.conf"
@ -110,9 +109,12 @@ class Thermal(ThermalBase):
self.name = self.get_name()
self.postion = self._thermal_info["postion"]
self.minimum_thermal = self.get_temperature()
self.maximum_thermal = self.get_temperature()
def _get_hwmon_path(self):
hwmon_path = os.path.join(I2C_ADAPTER_PATH, self._thermal_info["i2c_path"])
hwmon_path = os.path.join(
I2C_ADAPTER_PATH, self._thermal_info["i2c_path"])
hwmon_dir = os.listdir(hwmon_path)[0]
return os.path.join(hwmon_path, hwmon_dir)
@ -126,6 +128,17 @@ class Thermal(ThermalBase):
temp_file_path = os.path.join(self._hwmon_path, file_name)
return self._api_common.write_txt_file(temp_file_path, str(temperature))
def _get_threshold(self, file_name):
temp_file_path = os.path.join(self._hwmon_path, file_name)
data = self._api_common.read_txt_file(temp_file_path)
if data:
try:
threshold = float(data)
return round(threshold/1000, 3)
except Exception:
pass
return None
def get_temperature(self):
"""
Retrieves current temperature reading from thermal
@ -144,7 +157,8 @@ class Thermal(ThermalBase):
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
max_crit_key = '{}_max'.format(self._airflow)
return self._thermal_info.get(max_crit_key, None)
high_threshold_file = "temp{}_max".format(self._ss_index)
return self._get_threshold(high_threshold_file) or self._thermal_info.get(max_crit_key, None)
def get_low_threshold(self):
"""
@ -153,7 +167,7 @@ class Thermal(ThermalBase):
A float number, the low threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
return 0.0
return 0.001
def set_high_threshold(self, temperature):
"""
@ -166,8 +180,8 @@ class Thermal(ThermalBase):
"""
temp_file = "temp{}_max".format(self._ss_index)
is_set = self._set_threshold(temp_file, int(temperature*1000))
file_set = False
if is_set:
file_set = True
if is_set and self._api_common.is_host():
try:
with open(self.SS_CONFIG_PATH, 'r+') as f:
content = f.readlines()
@ -215,7 +229,35 @@ class Thermal(ThermalBase):
A float number, the low critical threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
return 0.0
return 0.001
def get_minimum_recorded(self):
"""
Retrieves the minimum recorded temperature of thermal
Returns:
A float number, the minimum recorded temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
tmp = self.get_temperature()
if tmp < self.minimum_thermal:
self.minimum_thermal = tmp
return self.minimum_thermal
def get_maximum_recorded(self):
"""
Retrieves the maximum recorded temperature of thermal
Returns:
A float number, the maximum recorded temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
tmp = self.get_temperature()
if tmp > self.maximum_thermal:
self.maximum_thermal = tmp
return self.maximum_thermal
##############################################################
###################### Device methods ########################
##############################################################
def get_name(self):
"""
@ -267,3 +309,21 @@ class Thermal(ThermalBase):
raw_txt = self._api_common.read_txt_file(fault_file_path)
return int(raw_txt) == 0
def is_replaceable(self):
"""
Retrieves whether thermal module is replaceable
Returns:
A boolean value, True if replaceable, False if not
"""
return False
def get_position_in_parent(self):
"""
Retrieves the thermal position information
Returns:
A int value, 0 represent ASIC thermal, 1 represent CPU thermal info
"""
if self.postion == "cpu":
return 1
return 0

View File

@ -4,114 +4,107 @@
# Watchdog contains an implementation of SONiC Platform Base API
#
#############################################################################
import fcntl
import os
import array
try:
import os
import time
from sonic_platform_base.watchdog_base import WatchdogBase
from .common import Common
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
""" ioctl constants """
IO_WRITE = 0x40000000
IO_READ = 0x80000000
IO_READ_WRITE = 0xC0000000
IO_SIZE_INT = 0x00040000
IO_SIZE_40 = 0x00280000
IO_TYPE_WATCHDOG = ord('W') << 8
WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG
WDR_40 = IO_READ | IO_SIZE_40 | IO_TYPE_WATCHDOG
WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG
""" Watchdog ioctl commands """
WDIOC_GETSUPPORT = 0 | WDR_40
WDIOC_GETSTATUS = 1 | WDR_INT
WDIOC_GETBOOTSTATUS = 2 | WDR_INT
WDIOC_GETTEMP = 3 | WDR_INT
WDIOC_SETOPTIONS = 4 | WDR_INT
WDIOC_KEEPALIVE = 5 | WDR_INT
WDIOC_SETTIMEOUT = 6 | WDWR_INT
WDIOC_GETTIMEOUT = 7 | WDR_INT
WDIOC_SETPRETIMEOUT = 8 | WDWR_INT
WDIOC_GETPRETIMEOUT = 9 | WDR_INT
WDIOC_GETTIMELEFT = 10 | WDR_INT
""" Watchdog status constants """
WDIOS_DISABLECARD = 0x0001
WDIOS_ENABLECARD = 0x0002
PLATFORM_CPLD_PATH = '/sys/devices/platform/e1031.smc/'
SETREG_FILE = 'setreg'
GETREG_FILE = 'getreg'
WDT_COMMON_ERROR = -1
WD_MAIN_IDENTITY = "iTCO_wdt"
WDT_SYSFS_PATH = "/sys/class/watchdog/"
MMC_VERSION_REG = "0x100"
# watchdog infomation for cpld v06
V06_MMC_VERSION = 0x05
V06_WDT_WIDTH = '0x110'
V06_WDT_WIDTH_SELECTOR = {
30: '0x1',
60: '0x2',
180: '0x3'
}
V06_CPLD_WDT_INFO = {
'wdt_en_reg': '0x111',
'wdt_en_cmd': '0x0',
'wdt_dis_cmd': '0x1'
}
# watchdog infomation
WDT_TIMER_L_BIT_REG = '0x117'
WDT_TIMER_M_BIT_REG = '0x118'
WDT_TIMER_H_BIT_REG = '0x119'
WDT_KEEP_ALVIVE_REG = '0x11a'
CPLD_WDT_INFO = {
'wdt_en_reg': '0x116',
'wdt_en_cmd': '0x1',
'wdt_dis_cmd': '0x0'
}
class Watchdog(WatchdogBase):
def __init__(self):
WatchdogBase.__init__(self)
# Init api_common
self._api_common = Common()
# Init cpld reg path
self.setreg_path = os.path.join(PLATFORM_CPLD_PATH, SETREG_FILE)
self.getreg_path = os.path.join(PLATFORM_CPLD_PATH, GETREG_FILE)
self.mmc_v = self._get_mmc_version()
self.cpld_info = V06_CPLD_WDT_INFO if self.mmc_v <= V06_MMC_VERSION else CPLD_WDT_INFO
self.watchdog, self.wdt_main_dev_name = self._get_wdt()
self.status_path = "/sys/class/watchdog/%s/status" % self.wdt_main_dev_name
self.state_path = "/sys/class/watchdog/%s/state" % self.wdt_main_dev_name
self.timeout_path = "/sys/class/watchdog/%s/timeout" % self.wdt_main_dev_name
# Set default value
self._disable()
self.armed = False
self.timeout = self._gettimeout(self.timeout_path)
self.timeout = 0
def _is_wd_main(self, dev):
"""
Checks watchdog identity
"""
identity = self._read_file(
"{}/{}/identity".format(WDT_SYSFS_PATH, dev))
return identity == WD_MAIN_IDENTITY
def _get_mmc_version(self):
hex_str_v = self._api_common.get_reg(self.getreg_path, MMC_VERSION_REG)
return int(hex_str_v, 16)
def _get_wdt(self):
"""
Retrieves watchdog device
"""
wdt_main_dev_list = [dev for dev in os.listdir(
"/dev/") if dev.startswith("watchdog") and self._is_wd_main(dev)]
if not wdt_main_dev_list:
return None
wdt_main_dev_name = wdt_main_dev_list[0]
watchdog_device_path = "/dev/{}".format(wdt_main_dev_name)
watchdog = os.open(watchdog_device_path, os.O_RDWR)
return watchdog, wdt_main_dev_name
def _get_level_hex(self, sub_hex):
sub_hex_str = sub_hex.replace("x", "0")
return hex(int(sub_hex_str, 16))
def _read_file(self, file_path):
"""
Read text file
"""
try:
with open(file_path, "r") as fd:
txt = fd.read()
except IOError:
return WDT_COMMON_ERROR
return txt.strip()
def _seconds_to_lmh_hex(self, seconds):
ms = seconds*1000 # calculate timeout in ms format
hex_str = hex(ms)
l = self._get_level_hex(hex_str[-2:])
m = self._get_level_hex(hex_str[-4:-2])
h = self._get_level_hex(hex_str[-6:-4])
return (l, m, h)
def _enable(self):
"""
Turn on the watchdog timer
"""
req = array.array('h', [WDIOS_ENABLECARD])
fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False)
return self._api_common.set_reg(self.setreg_path, self.cpld_info['wdt_en_reg'], self.cpld_info['wdt_en_cmd'])
def _disable(self):
"""
Turn off the watchdog timer
"""
req = array.array('h', [WDIOS_DISABLECARD])
fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False)
return self._api_common.set_reg(self.setreg_path, self.cpld_info['wdt_en_reg'], self.cpld_info['wdt_dis_cmd'])
def _keepalive(self):
"""
Keep alive watchdog timer
"""
fcntl.ioctl(self.watchdog, WDIOC_KEEPALIVE)
if self.mmc_v <= V06_MMC_VERSION:
self._disable()
self._enable()
else:
self._api_common.set_reg(
self.setreg_path, WDT_KEEP_ALVIVE_REG, self.cpld_info['wdt_en_cmd'])
def _settimeout(self, seconds):
"""
@ -119,29 +112,23 @@ class Watchdog(WatchdogBase):
@param seconds - timeout in seconds
@return is the actual set timeout
"""
req = array.array('I', [seconds])
fcntl.ioctl(self.watchdog, WDIOC_SETTIMEOUT, req, True)
return int(req[0])
def _gettimeout(self, timeout_path):
"""
Get watchdog timeout
@return watchdog timeout
"""
req = array.array('I', [0])
fcntl.ioctl(self.watchdog, WDIOC_GETTIMEOUT, req, True)
if self.mmc_v <= V06_MMC_VERSION:
timeout_hex = V06_WDT_WIDTH_SELECTOR.get(seconds, '0x2')
seconds = 60 if timeout_hex == '0x2' else seconds
self._api_common.set_reg(
self.setreg_path, V06_WDT_WIDTH, timeout_hex)
return int(req[0])
else:
(l, m, h) = self._seconds_to_lmh_hex(seconds)
self._api_common.set_reg(
self.setreg_path, WDT_TIMER_H_BIT_REG, h) # set high bit
self._api_common.set_reg(
self.setreg_path, WDT_TIMER_M_BIT_REG, m) # set med bit
self._api_common.set_reg(
self.setreg_path, WDT_TIMER_L_BIT_REG, l) # set low bit
def _gettimeleft(self):
"""
Get time left before watchdog timer expires
@return time left in seconds
"""
req = array.array('I', [0])
fcntl.ioctl(self.watchdog, WDIOC_GETTIMELEFT, req, True)
return int(req[0])
return seconds
#################################################################
@ -157,22 +144,25 @@ class Watchdog(WatchdogBase):
An integer specifying the *actual* number of seconds the watchdog
was armed with. On failure returns -1.
"""
ret = WDT_COMMON_ERROR
if seconds < 0:
if seconds < 0 or seconds > 180:
return ret
try:
if self.timeout != seconds:
self.timeout = self._settimeout(seconds)
if self.armed:
self._keepalive()
else:
self._enable()
self.armed = True
ret = self.timeout
self.arm_timestamp = time.time()
except IOError as e:
pass
print("Error: unable to enable wdt due to : {}".format(e))
return ret
@ -183,14 +173,12 @@ class Watchdog(WatchdogBase):
A boolean, True if watchdog is disarmed successfully, False if not
"""
disarmed = False
if self.is_armed():
try:
self._disable()
self.armed = False
disarmed = True
except IOError:
pass
try:
self._disable()
self.armed = False
disarmed = True
except IOError as e:
print("Error: unable to disable wdt due to : {}".format(e))
return disarmed
def is_armed(self):
@ -199,7 +187,6 @@ class Watchdog(WatchdogBase):
Returns:
A boolean, True if watchdog is armed, False if not
"""
return self.armed
def get_remaining_time(self):
@ -214,16 +201,6 @@ class Watchdog(WatchdogBase):
timeleft = WDT_COMMON_ERROR
if self.armed:
try:
timeleft = self._gettimeleft()
except IOError:
pass
timeleft = int(self.timeout - (time.time() - self.arm_timestamp))
return timeleft
def __del__(self):
"""
Close watchdog
"""
os.close(self.watchdog)

View File

@ -53,12 +53,11 @@ start)
echo max6699 0x1a > /sys/bus/i2c/devices/i2c-3/new_device
echo max6699 0x1a > /sys/bus/i2c/devices/i2c-11/new_device
## TODO: fix dps200 driver cause kernel panic issue
# https://github.com/Azure/sonic-buildimage/issues/6602
# Attach PSUs
# echo dps200 0x5a > /sys/bus/i2c/devices/i2c-12/new_device
# echo dps200 0x5b > /sys/bus/i2c/devices/i2c-13/new_device
echo dps200 0x5a > /sys/bus/i2c/devices/i2c-12/new_device
echo 24c02 0x52 > /sys/bus/i2c/devices/i2c-12/new_device
echo dps200 0x5b > /sys/bus/i2c/devices/i2c-13/new_device
echo 24c02 0x53 > /sys/bus/i2c/devices/i2c-13/new_device
# Attach fans
echo emc2305 0x4d > /sys/bus/i2c/devices/i2c-23/new_device