[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""" """Platform-specific SfpUtil class"""
PORT_START = 1 PORT_START = 1
PORT_END = 52 PORT_END = 55
SFP_PORT_START = 49
SFP_PORT_END = 52
port_to_i2c_mapping = { 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, 49: 15,
50: 14, 50: 14,
51: 17, 51: 17,
52: 16 52: 16
} }
_port_to_eeprom_mapping = {} _port_to_eeprom_mapping = {}
_sfp_port = list(range(49, PORT_END + 1)) _sfp_port = list(range(SFP_PORT_START, SFP_PORT_END + 1))
@property @property
def port_start(self): def port_start(self):
@ -89,7 +43,7 @@ class SfpUtil(SfpUtilBase):
# Override port_to_eeprom_mapping for class initialization # Override port_to_eeprom_mapping for class initialization
eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom'
for x in range(self.PORT_START, self.PORT_END + 1): 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 self.port_to_eeprom_mapping[x] = port_eeprom_path
SfpUtilBase.__init__(self) SfpUtilBase.__init__(self)
@ -103,7 +57,7 @@ class SfpUtil(SfpUtilBase):
try: try:
with open(sfp_modabs_path, 'r') as port_status: with open(sfp_modabs_path, 'r') as port_status:
status = int(port_status.read(), 16) status = int(port_status.read(), 16)
status = (status >> (port_num - 49)) & 1 status = (status >> (port_num - self.SFP_PORT_START)) & 1
except IOError: except IOError:
return False return False
@ -138,7 +92,8 @@ class SfpUtil(SfpUtilBase):
for port_num in self._sfp_port: for port_num in self._sfp_port:
change = (changes >> (port_num - 49)) & 1 change = (changes >> (port_num - 49)) & 1
if change == 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 found_flag = 1
if not found_flag: if not found_flag:

View File

@ -6,25 +6,26 @@
# #
############################################################################# #############################################################################
try: try:
import sys
from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper
from sonic_platform_base.chassis_base import ChassisBase from sonic_platform_base.chassis_base import ChassisBase
from sonic_py_common import device_info
from .common import Common from .common import Common
from .event import SfpEvent from .event import SfpEvent
except ImportError as e: except ImportError as e:
raise ImportError(str(e) + "- required module not found") raise ImportError(str(e) + "- required module not found")
NUM_FAN_TRAY = 3 NUM_FAN_TRAY = 3
NUM_FAN = 1
NUM_PSU = 2 NUM_PSU = 2
NUM_THERMAL = 7 NUM_THERMAL = 7
NUM_SFP = 52 NUM_SFP = 55
NUM_COMPONENT = 3 NUM_COMPONENT = 3
RESET_REGISTER = "0x112" RESET_REGISTER = "0x112"
HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/previous-reboot-cause.txt" 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" PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/previous-reboot-cause.txt"
HOST_CHK_CMD = "docker > /dev/null 2>&1" HOST_CHK_CMD = "docker > /dev/null 2>&1"
STATUS_LED_PATH = "/sys/devices/platform/e1031.smc/master_led"
class Chassis(ChassisBase): class Chassis(ChassisBase):
@ -32,66 +33,63 @@ class Chassis(ChassisBase):
def __init__(self): def __init__(self):
ChassisBase.__init__(self) ChassisBase.__init__(self)
self._api_common = Common() self._api_common = Common()
self.sfp_module_initialized = False self._is_host = self._api_common.is_host()
self.__initialize_eeprom() 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.sfp_module_initialized = False
self.__initialize_fan() self._reboot_cause_path = HOST_REBOOT_CAUSE_PATH if self._is_host else PMON_REBOOT_CAUSE_PATH
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
def __initialize_sfp(self): def __initialize_sfp(self):
sfputil_helper = SfpUtilHelper() sfputil_helper = SfpUtilHelper()
port_config_file_path = device_info.get_path_to_port_config_file() port_config_file_path = device_info.get_path_to_port_config_file()
sfputil_helper.read_porttab_mappings(port_config_file_path, 0) 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): for index in range(0, NUM_SFP):
name_idx = 0 if index+1 == NUM_SFP else index+1 sfp = Sfp(index, sfputil_helper.logical[index])
sfp = Sfp(index, sfputil_helper.logical[name_idx])
self._sfp_list.append(sfp) self._sfp_list.append(sfp)
self.sfp_module_initialized = True self.sfp_module_initialized = True
def __initialize_psu(self): def __initialize_psu(self):
from sonic_platform.psu import Psu from .psu import Psu
for index in range(0, NUM_PSU): for index in range(0, NUM_PSU):
psu = Psu(index) psu = Psu(index)
self._psu_list.append(psu) self._psu_list.append(psu)
def __initialize_fan(self): def __initialize_fan(self):
from sonic_platform.fan import Fan from .fan_drawer import FanDrawer
for fant_index in range(0, NUM_FAN_TRAY): for i in range(NUM_FAN_TRAY):
for fan_index in range(0, NUM_FAN): fandrawer = FanDrawer(i)
fan = Fan(fant_index, fan_index) self._fan_drawer_list.append(fandrawer)
self._fan_list.append(fan) self._fan_list += fandrawer.get_all_fans()
def __initialize_thermals(self): def __initialize_thermals(self):
from sonic_platform.thermal import Thermal from .thermal import Thermal
airflow = self.__get_air_flow() airflow = self.__get_air_flow()
for index in range(0, NUM_THERMAL): for index in range(0, NUM_THERMAL):
thermal = Thermal(index, airflow) thermal = Thermal(index, airflow)
self._thermal_list.append(thermal) self._thermal_list.append(thermal)
def __initialize_eeprom(self): def __initialize_eeprom(self):
from sonic_platform.eeprom import Tlv from .eeprom import Tlv
self._eeprom = Tlv() self._eeprom = Tlv()
def __initialize_components(self): def __initialize_components(self):
from sonic_platform.component import Component from .component import Component
for index in range(0, NUM_COMPONENT): for index in range(0, NUM_COMPONENT):
component = Component(index) component = Component(index)
self._component_list.append(component) self._component_list.append(component)
def __get_air_flow(self): def __get_air_flow(self):
air_flow_path = '/usr/share/sonic/device/{}/fan_airflow'.format( 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) air_flow = self._api_common.read_txt_file(air_flow_path)
return air_flow or 'B2F' return air_flow or 'B2F'
@ -154,7 +152,6 @@ class Chassis(ChassisBase):
else: else:
reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE
description = 'Unknown reason' description = 'Unknown reason'
return (reboot_cause, description) return (reboot_cause, description)
def get_watchdog(self): def get_watchdog(self):
@ -247,8 +244,8 @@ class Chassis(ChassisBase):
# The index will start from 1 # The index will start from 1
sfp = self._sfp_list[index-1] sfp = self._sfp_list[index-1]
except IndexError: except IndexError:
sys.stderr.write("SFP index {} out of range (1-{})\n".format( print("SFP index {} out of range (1-{})\n".format(
index, len(self._sfp_list))) index, len(self._sfp_list)))
return sfp return sfp
############################################################## ##############################################################
@ -269,13 +266,13 @@ class Chassis(ChassisBase):
Returns: Returns:
string: The name of the device string: The name of the device
""" """
return self._api_common.hwsku return self._api_common.get_hwsku()
def get_presence(self): def get_presence(self):
""" """
Retrieves the presence of the PSU Retrieves the presence of the Chassis
Returns: Returns:
bool: True if PSU is present, False if not bool: True if Chassis is present, False if not
""" """
return True return True
@ -303,3 +300,52 @@ class Chassis(ChassisBase):
""" """
return True 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): def __init__(self, conf=None):
self._main_conf = conf 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): def run_command(self, command):
status = False status = False
@ -38,7 +49,7 @@ class Common:
p = subprocess.Popen( p = subprocess.Popen(
command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
raw_data, err = p.communicate() raw_data, err = p.communicate()
if err == '': if p.returncode == 0:
status, output = True, raw_data.strip() status, output = True, raw_data.strip()
except Exception: except Exception:
pass pass
@ -152,10 +163,28 @@ class Common:
status, output = self.run_command(cmd) status, output = self.run_command(cmd)
return output if status else None 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): def read_txt_file(self, path):
with open(path, 'r') as f: try:
output = f.readline() with open(path, 'r') as f:
return output.strip('\n') 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): def write_txt_file(self, file_path, value):
try: try:

View File

@ -6,12 +6,12 @@
# #
############################################################################# #############################################################################
import os.path
import shutil
import shlex
import subprocess
try: try:
import os.path
import shutil
import shlex
import subprocess
from sonic_platform_base.component_base import ComponentBase from sonic_platform_base.component_base import ComponentBase
except ImportError as e: except ImportError as e:
raise ImportError(str(e) + "- required module not found") raise ImportError(str(e) + "- required module not found")
@ -119,6 +119,29 @@ class Component(ComponentBase):
return fw_version 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): def install_firmware(self, image_path):
""" """
Install firmware to module Install firmware to module
@ -139,5 +162,73 @@ class Component(ComponentBase):
install_command = "ispvm %s" % new_image_path install_command = "ispvm %s" % new_image_path
# elif self.name == "BIOS": # elif self.name == "BIOS":
# install_command = "afulnx_64 %s /p /b /n /x /r" % image_path # install_command = "afulnx_64 %s /p /b /n /x /r" % image_path
return self.__run_command(install_command) 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: else:
from cStringIO import StringIO 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 import eeprom_tlvinfo
from sonic_platform_base.sonic_eeprom.eeprom_base import EepromDecoder
except ImportError as e: except ImportError as e:
raise ImportError(str(e) + "- required module not found") raise ImportError(str(e) + "- required module not found")
CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' CACHE_ROOT = '/var/cache/sonic/decode-syseeprom'
CACHE_FILE = 'syseeprom_cache' CACHE_FILE = 'syseeprom_cache'
NULL = 'N/A'
class Tlv(eeprom_tlvinfo.TlvInfoDecoder): class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
@ -32,8 +33,8 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
def __init__(self): def __init__(self):
self._eeprom_path = "/sys/class/i2c-adapter/i2c-2/2-0050/eeprom" self._eeprom_path = "/sys/class/i2c-adapter/i2c-2/2-0050/eeprom"
self._eeprom = None
super(Tlv, self).__init__(self._eeprom_path, 0, '', True) super(Tlv, self).__init__(self._eeprom_path, 0, '', True)
self._eeprom = self._load_eeprom()
def __parse_output(self, decode_output): def __parse_output(self, decode_output):
decode_output.replace('\0', '') decode_output.replace('\0', '')
@ -50,7 +51,7 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
value = match.group(3).rstrip('\0') value = match.group(3).rstrip('\0')
_eeprom_info_dict[idx] = value _eeprom_info_dict[idx] = value
except Exception: except BaseException:
pass pass
return _eeprom_info_dict return _eeprom_info_dict
@ -59,7 +60,7 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
sys.stdout = StringIO() sys.stdout = StringIO()
try: try:
self.read_eeprom_db() self.read_eeprom_db()
except Exception: except BaseException:
decode_output = sys.stdout.getvalue() decode_output = sys.stdout.getvalue()
sys.stdout = original_stdout sys.stdout = original_stdout
return self.__parse_output(decode_output) return self.__parse_output(decode_output)
@ -71,7 +72,7 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
if not os.path.exists(CACHE_ROOT): if not os.path.exists(CACHE_ROOT):
try: try:
os.makedirs(CACHE_ROOT) os.makedirs(CACHE_ROOT)
except Exception: except BaseException:
pass pass
# #
@ -80,7 +81,7 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
# #
try: try:
self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE)) self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE))
except Exception: except BaseException:
pass pass
e = self.read_eeprom() e = self.read_eeprom()
@ -89,7 +90,7 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
try: try:
self.update_cache(e) self.update_cache(e)
except Exception: except BaseException:
pass pass
self.decode_eeprom(e) self.decode_eeprom(e)
@ -102,14 +103,98 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
return self.__parse_output(decode_output) 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): def get_eeprom(self):
return self._eeprom self._eeprom = self._load_eeprom() if not self._eeprom else self._eeprom
return self._valid_tlv(self._eeprom)
def get_serial(self):
return self._eeprom.get('0x23', "Undefined.")
def get_mac(self):
return self._eeprom.get('0x24', "Undefined.")
def get_pn(self): 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: try:
import time import time
import select import select
from .helper import APIHelper from .common import Common
from sonic_py_common.logger import Logger from sonic_py_common.logger import Logger
except ImportError as e: except ImportError as e:
raise ImportError(repr(e) + " - required module not found") 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' GPIO_SUS7 = '/sys/devices/platform/hlx-ich.0/sci_int_gpio_sus7'
def __init__(self, sfp_list): def __init__(self, sfp_list):
self._api_helper = APIHelper() self._api_common = Common()
self._sfp_list = sfp_list self._sfp_list = sfp_list
self._logger = Logger() self._logger = Logger()
# clear interrupt # 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): def get_sfp_event(self, timeout):
epoll = select.epoll() epoll = select.epoll()
@ -37,7 +37,7 @@ class SfpEvent:
events = epoll.poll(timeout=timeout_sec if timeout != 0 else -1) events = epoll.poll(timeout=timeout_sec if timeout != 0 else -1)
if events: if events:
# Read the QSFP ABS interrupt & status registers # 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) self.INT_PATH)
changes = int(port_changes, 16) changes = int(port_changes, 16)
for sfp in self._sfp_list: for sfp in self._sfp_list:
@ -48,7 +48,8 @@ class SfpEvent:
if change == 1: if change == 1:
time.sleep(self.DELAY) time.sleep(self.DELAY)
port_status = sfp.get_presence() 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 return port_dict
except Exception as e: except Exception as e:

View File

@ -6,6 +6,7 @@
# #
############################################################################# #############################################################################
from __future__ import division
import math import math
import os.path import os.path
@ -20,8 +21,10 @@ FAN_PATH = "/sys/devices/platform/e1031.smc/"
EMC2305_MAX_PWM = 255 EMC2305_MAX_PWM = 255
EMC2305_FAN_PWM = "pwm{}" EMC2305_FAN_PWM = "pwm{}"
EMC2305_FAN_TARGET = "fan{}_target" EMC2305_FAN_TARGET = "fan{}_target"
EMC2305_FAN_PWM_MODE = "pwm{}_enable"
EMC2305_FAN_INPUT = "pwm{}" EMC2305_FAN_INPUT = "pwm{}"
FAN_NAME_LIST = ["FAN-1", "FAN-2", "FAN-3"] FAN_NAME_LIST = ["FAN-1", "FAN-2", "FAN-3"]
FAN_SPEED_TOLERANCE = 10
PSU_FAN_MAX_RPM = 11000 PSU_FAN_MAX_RPM = 11000
PSU_HWMON_PATH = "/sys/bus/i2c/devices/i2c-{0}/{0}-00{1}/hwmon" PSU_HWMON_PATH = "/sys/bus/i2c/devices/i2c-{0}/{0}-00{1}/hwmon"
PSU_I2C_MAPPING = { PSU_I2C_MAPPING = {
@ -34,12 +37,16 @@ PSU_I2C_MAPPING = {
"addr": "5a" "addr": "5a"
}, },
} }
NULL_VAL = 'N/A'
class Fan(FanBase): class Fan(FanBase):
"""Platform-specific Fan class""" """Platform-specific Fan class"""
def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): 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_index = fan_index
self.fan_tray_index = fan_tray_index self.fan_tray_index = fan_tray_index
self.is_psu_fan = is_psu_fan self.is_psu_fan = is_psu_fan
@ -64,13 +71,10 @@ class Fan(FanBase):
self.fan_e1031_led = "fan{}_led" self.fan_e1031_led = "fan{}_led"
self.fan_e1031_led_col_map = { self.fan_e1031_led_col_map = {
self.STATUS_LED_COLOR_GREEN: "green", 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.STATUS_LED_COLOR_OFF: "off"
} }
self._api_common = Common()
FanBase.__init__(self)
def __search_file_by_name(self, directory, file_name): def __search_file_by_name(self, directory, file_name):
for dirpath, dirnames, files in os.walk(directory): for dirpath, dirnames, files in os.walk(directory):
for name in files: for name in files:
@ -141,19 +145,26 @@ class Fan(FanBase):
0 : when PWM mode is use 0 : when PWM mode is use
pwm : when pwm mode is not use pwm : when pwm mode is not use
""" """
target = 0 target = NULL_VAL
if not self.is_psu_fan: if not self.is_psu_fan:
chip = self.emc2305_chip_mapping[self.fan_index] chip = self.emc2305_chip_mapping[self.fan_index]
device = chip['device'] device = chip['device']
fan_index = chip['index_map'] fan_index = chip['index_map']
sysfs_path = "%s%s/%s" % (
EMC2305_PATH, device, EMC2305_FAN_TARGET) enable_path = "%s%s/%s" % (
sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index]) EMC2305_PATH, device, EMC2305_FAN_PWM_MODE)
raw = self._api_common.read_txt_file(sysfs_path).strip('\r\n') 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 pwm = int(raw, 10) if raw else 0
target = math.ceil(float(pwm) * 100 / EMC2305_MAX_PWM) target = math.ceil(float(pwm) * 100 / EMC2305_MAX_PWM)
return target return int(target)
def get_speed_tolerance(self): def get_speed_tolerance(self):
""" """
@ -162,7 +173,7 @@ class Fan(FanBase):
An integer, the percentage of variance from target speed which is An integer, the percentage of variance from target speed which is
considered tolerable considered tolerable
""" """
return 10 return FAN_SPEED_TOLERANCE
def set_speed(self, speed): def set_speed(self, speed):
""" """
@ -211,6 +222,28 @@ class Fan(FanBase):
return set_status_led 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): def get_name(self):
""" """
Retrieves the name of the device Retrieves the name of the device
@ -240,11 +273,7 @@ class Fan(FanBase):
Returns: Returns:
string: Model/part number of device string: Model/part number of device
""" """
if self.is_psu_fan: return NULL_VAL
return NULL_VAL
model = NULL_VAL
return model
def get_serial(self): def get_serial(self):
""" """
@ -252,11 +281,7 @@ class Fan(FanBase):
Returns: Returns:
string: Serial number of device string: Serial number of device
""" """
if self.is_psu_fan: return NULL_VAL
return NULL_VAL
serial = NULL_VAL
return serial
def get_status(self): def get_status(self):
""" """
@ -269,7 +294,7 @@ class Fan(FanBase):
fan_fault_sysfs_name = "fan1_fault" fan_fault_sysfs_name = "fan1_fault"
fan_fault_sysfs_path = self.__search_file_by_name( fan_fault_sysfs_path = self.__search_file_by_name(
self.psu_hwmon_path, fan_fault_sysfs_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(): elif self.get_presence():
chip = self.emc2305_chip_mapping[self.fan_index] chip = self.emc2305_chip_mapping[self.fan_index]
@ -278,7 +303,27 @@ class Fan(FanBase):
sysfs_path = "%s%s/%s" % ( sysfs_path = "%s%s/%s" % (
EMC2305_PATH, device, 'fan{}_fault') EMC2305_PATH, device, 'fan{}_fault')
sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index]) 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 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: try:
from sonic_platform_base.psu_base import PsuBase from sonic_platform_base.psu_base import PsuBase
from sonic_platform.fan import Fan from sonic_platform.fan import Fan
from .common import Common
from .eeprom import DeviceEEPROM
except ImportError as e: except ImportError as e:
raise ImportError(str(e) + "- required module not found") raise ImportError(str(e) + "- required module not found")
FAN_E1031_SPEED_PATH = "/sys/class/hwmon/hwmon{}/fan1_input" 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" HWMON_PATH = "/sys/bus/i2c/devices/i2c-{0}/{0}-00{1}/hwmon"
FAN_MAX_RPM = 11000 FAN_MAX_RPM = 11000
PSU_NAME_LIST = ["PSU-R", "PSU-L"] PSU_NAME_LIST = ["PSU-R", "PSU-L"]
@ -22,13 +25,22 @@ PSU_NUM_FAN = [1, 1]
PSU_I2C_MAPPING = { PSU_I2C_MAPPING = {
0: { 0: {
"num": 13, "num": 13,
"addr": "5b" "addr": "5b",
"eeprom_addr": "53"
}, },
1: { 1: {
"num": 12, "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): class Psu(PsuBase):
@ -36,32 +48,26 @@ class Psu(PsuBase):
def __init__(self, psu_index): def __init__(self, psu_index):
PsuBase.__init__(self) PsuBase.__init__(self)
self._api_common = Common()
self.index = psu_index self.index = psu_index
self.psu_path = "/sys/devices/platform/e1031.smc/"
self.psu_presence = "psu{}_prs" self.psu_presence = "psu{}_prs"
self.psu_oper_status = "psu{}_status" self.psu_oper_status = "psu{}_status"
self.i2c_num = PSU_I2C_MAPPING[self.index]["num"] self.i2c_num = PSU_I2C_MAPPING[self.index]["num"]
self.i2c_addr = PSU_I2C_MAPPING[self.index]["addr"] self.i2c_addr = PSU_I2C_MAPPING[self.index]["addr"]
self.hwmon_path = HWMON_PATH.format(self.i2c_num, self.i2c_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]): for fan_index in range(0, PSU_NUM_FAN[self.index]):
fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index)
self._fan_list.append(fan) self._fan_list.append(fan)
PsuBase.__init__(self)
def __read_txt_file(self, file_path): def _search_file_by_contain(self, directory, search_str, file_start):
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):
for dirpath, dirnames, files in os.walk(directory): for dirpath, dirnames, files in os.walk(directory):
for name in files: for name in files:
file_path = os.path.join(dirpath, name) 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 file_path
return None return None
@ -76,7 +82,7 @@ class Psu(PsuBase):
voltage_name = "in{}_input" voltage_name = "in{}_input"
voltage_label = "vout1" 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") self.hwmon_path, voltage_label, "in")
if vout_label_path: if vout_label_path:
dir_name = os.path.dirname(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))) in_num = ''.join(list(filter(str.isdigit, basename)))
vout_path = os.path.join( vout_path = os.path.join(
dir_name, voltage_name.format(in_num)) 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 psu_voltage = float(vout_val) / 1000
return psu_voltage return psu_voltage
@ -99,7 +105,7 @@ class Psu(PsuBase):
current_name = "curr{}_input" current_name = "curr{}_input"
current_label = "iout1" 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") self.hwmon_path, current_label, "cur")
if curr_label_path: if curr_label_path:
dir_name = os.path.dirname(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_num = ''.join(list(filter(str.isdigit, basename)))
cur_path = os.path.join( cur_path = os.path.join(
dir_name, current_name.format(cur_num)) 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 psu_current = float(cur_val) / 1000
return psu_current return psu_current
@ -122,7 +128,7 @@ class Psu(PsuBase):
current_name = "power{}_input" current_name = "power{}_input"
current_label = "pout1" 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") self.hwmon_path, current_label, "power")
if pw_label_path: if pw_label_path:
dir_name = os.path.dirname(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_num = ''.join(list(filter(str.isdigit, basename)))
pw_path = os.path.join( pw_path = os.path.join(
dir_name, current_name.format(pw_num)) 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 psu_power = float(pw_val) / 1000000
return psu_power return psu_power
@ -165,6 +171,10 @@ class Psu(PsuBase):
# Hardware not supported # Hardware not supported
return self.STATUS_LED_COLOR_OFF return self.STATUS_LED_COLOR_OFF
##############################################################
###################### Device methods ########################
##############################################################
def get_name(self): def get_name(self):
""" """
Retrieves the name of the device Retrieves the name of the device
@ -180,8 +190,8 @@ class Psu(PsuBase):
bool: True if PSU is present, False if not bool: True if PSU is present, False if not
""" """
psu_location = ["R", "L"] psu_location = ["R", "L"]
presences_status = self.__read_txt_file( presences_status = self._api_common.read_txt_file(
self.psu_path + self.psu_presence.format(psu_location[self.index])) or 0 PSU_E1031_STAT_PATH + self.psu_presence.format(psu_location[self.index])) or 0
return int(presences_status) == 1 return int(presences_status) == 1
@ -192,7 +202,153 @@ class Psu(PsuBase):
A boolean value, True if device is operating properly, False if not A boolean value, True if device is operating properly, False if not
""" """
psu_location = ["R", "L"] psu_location = ["R", "L"]
power_status = self.__read_txt_file( power_status = self._api_common.read_txt_file(
self.psu_path + self.psu_oper_status.format(psu_location[self.index])) or 0 PSU_E1031_STAT_PATH + self.psu_oper_status.format(psu_location[self.index])) or 0
return int(power_status) == 1 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): class Thermal(ThermalBase):
"""Platform-specific Thermal class""" """Platform-specific Thermal class"""
THERMAL_NAME_LIST = []
MAINBOARD_SS_PATH = "/sys/class/i2c-adapter/i2c-11/11-001a/hwmon/hwmon2" 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" 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" 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.name = self.get_name()
self.postion = self._thermal_info["postion"] self.postion = self._thermal_info["postion"]
self.minimum_thermal = self.get_temperature()
self.maximum_thermal = self.get_temperature()
def _get_hwmon_path(self): 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] hwmon_dir = os.listdir(hwmon_path)[0]
return os.path.join(hwmon_path, hwmon_dir) 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) temp_file_path = os.path.join(self._hwmon_path, file_name)
return self._api_common.write_txt_file(temp_file_path, str(temperature)) 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): def get_temperature(self):
""" """
Retrieves current temperature reading from thermal 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 up to nearest thousandth of one degree Celsius, e.g. 30.125
""" """
max_crit_key = '{}_max'.format(self._airflow) 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): def get_low_threshold(self):
""" """
@ -153,7 +167,7 @@ class Thermal(ThermalBase):
A float number, the low threshold temperature of thermal in Celsius A float number, the low threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125 up to nearest thousandth of one degree Celsius, e.g. 30.125
""" """
return 0.0 return 0.001
def set_high_threshold(self, temperature): def set_high_threshold(self, temperature):
""" """
@ -166,8 +180,8 @@ class Thermal(ThermalBase):
""" """
temp_file = "temp{}_max".format(self._ss_index) temp_file = "temp{}_max".format(self._ss_index)
is_set = self._set_threshold(temp_file, int(temperature*1000)) is_set = self._set_threshold(temp_file, int(temperature*1000))
file_set = False file_set = True
if is_set: if is_set and self._api_common.is_host():
try: try:
with open(self.SS_CONFIG_PATH, 'r+') as f: with open(self.SS_CONFIG_PATH, 'r+') as f:
content = f.readlines() content = f.readlines()
@ -215,7 +229,35 @@ class Thermal(ThermalBase):
A float number, the low critical threshold temperature of thermal in Celsius A float number, the low critical threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125 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): def get_name(self):
""" """
@ -267,3 +309,21 @@ class Thermal(ThermalBase):
raw_txt = self._api_common.read_txt_file(fault_file_path) raw_txt = self._api_common.read_txt_file(fault_file_path)
return int(raw_txt) == 0 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 # Watchdog contains an implementation of SONiC Platform Base API
# #
############################################################################# #############################################################################
import fcntl
import os
import array
try: try:
import os
import time
from sonic_platform_base.watchdog_base import WatchdogBase from sonic_platform_base.watchdog_base import WatchdogBase
from .common import Common
except ImportError as e: except ImportError as e:
raise ImportError(str(e) + "- required module not found") 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 WDT_COMMON_ERROR = -1
WD_MAIN_IDENTITY = "iTCO_wdt" MMC_VERSION_REG = "0x100"
WDT_SYSFS_PATH = "/sys/class/watchdog/"
# 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): class Watchdog(WatchdogBase):
def __init__(self): 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 # Set default value
self._disable() self._disable()
self.armed = False self.armed = False
self.timeout = self._gettimeout(self.timeout_path) self.timeout = 0
def _is_wd_main(self, dev): def _get_mmc_version(self):
""" hex_str_v = self._api_common.get_reg(self.getreg_path, MMC_VERSION_REG)
Checks watchdog identity return int(hex_str_v, 16)
"""
identity = self._read_file(
"{}/{}/identity".format(WDT_SYSFS_PATH, dev))
return identity == WD_MAIN_IDENTITY
def _get_wdt(self): def _get_level_hex(self, sub_hex):
""" sub_hex_str = sub_hex.replace("x", "0")
Retrieves watchdog device return hex(int(sub_hex_str, 16))
"""
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 _read_file(self, file_path): def _seconds_to_lmh_hex(self, seconds):
""" ms = seconds*1000 # calculate timeout in ms format
Read text file hex_str = hex(ms)
""" l = self._get_level_hex(hex_str[-2:])
try: m = self._get_level_hex(hex_str[-4:-2])
with open(file_path, "r") as fd: h = self._get_level_hex(hex_str[-6:-4])
txt = fd.read() return (l, m, h)
except IOError:
return WDT_COMMON_ERROR
return txt.strip()
def _enable(self): def _enable(self):
""" """
Turn on the watchdog timer Turn on the watchdog timer
""" """
req = array.array('h', [WDIOS_ENABLECARD]) return self._api_common.set_reg(self.setreg_path, self.cpld_info['wdt_en_reg'], self.cpld_info['wdt_en_cmd'])
fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False)
def _disable(self): def _disable(self):
""" """
Turn off the watchdog timer Turn off the watchdog timer
""" """
req = array.array('h', [WDIOS_DISABLECARD]) return self._api_common.set_reg(self.setreg_path, self.cpld_info['wdt_en_reg'], self.cpld_info['wdt_dis_cmd'])
fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False)
def _keepalive(self): def _keepalive(self):
""" """
Keep alive watchdog timer 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): def _settimeout(self, seconds):
""" """
@ -119,29 +112,23 @@ class Watchdog(WatchdogBase):
@param seconds - timeout in seconds @param seconds - timeout in seconds
@return is the actual set timeout @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): if self.mmc_v <= V06_MMC_VERSION:
""" timeout_hex = V06_WDT_WIDTH_SELECTOR.get(seconds, '0x2')
Get watchdog timeout seconds = 60 if timeout_hex == '0x2' else seconds
@return watchdog timeout self._api_common.set_reg(
""" self.setreg_path, V06_WDT_WIDTH, timeout_hex)
req = array.array('I', [0])
fcntl.ioctl(self.watchdog, WDIOC_GETTIMEOUT, req, True)
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): return seconds
"""
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])
################################################################# #################################################################
@ -157,22 +144,25 @@ class Watchdog(WatchdogBase):
An integer specifying the *actual* number of seconds the watchdog An integer specifying the *actual* number of seconds the watchdog
was armed with. On failure returns -1. was armed with. On failure returns -1.
""" """
ret = WDT_COMMON_ERROR ret = WDT_COMMON_ERROR
if seconds < 0:
if seconds < 0 or seconds > 180:
return ret return ret
try: try:
if self.timeout != seconds: if self.timeout != seconds:
self.timeout = self._settimeout(seconds) self.timeout = self._settimeout(seconds)
if self.armed: if self.armed:
self._keepalive() self._keepalive()
else: else:
self._enable() self._enable()
self.armed = True self.armed = True
ret = self.timeout ret = self.timeout
self.arm_timestamp = time.time()
except IOError as e: except IOError as e:
pass print("Error: unable to enable wdt due to : {}".format(e))
return ret return ret
@ -183,14 +173,12 @@ class Watchdog(WatchdogBase):
A boolean, True if watchdog is disarmed successfully, False if not A boolean, True if watchdog is disarmed successfully, False if not
""" """
disarmed = False disarmed = False
if self.is_armed(): try:
try: self._disable()
self._disable() self.armed = False
self.armed = False disarmed = True
disarmed = True except IOError as e:
except IOError: print("Error: unable to disable wdt due to : {}".format(e))
pass
return disarmed return disarmed
def is_armed(self): def is_armed(self):
@ -199,7 +187,6 @@ class Watchdog(WatchdogBase):
Returns: Returns:
A boolean, True if watchdog is armed, False if not A boolean, True if watchdog is armed, False if not
""" """
return self.armed return self.armed
def get_remaining_time(self): def get_remaining_time(self):
@ -214,16 +201,6 @@ class Watchdog(WatchdogBase):
timeleft = WDT_COMMON_ERROR timeleft = WDT_COMMON_ERROR
if self.armed: if self.armed:
try: timeleft = int(self.timeout - (time.time() - self.arm_timestamp))
timeleft = self._gettimeleft()
except IOError:
pass
return timeleft 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-3/new_device
echo max6699 0x1a > /sys/bus/i2c/devices/i2c-11/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 # Attach PSUs
# echo dps200 0x5a > /sys/bus/i2c/devices/i2c-12/new_device echo dps200 0x5a > /sys/bus/i2c/devices/i2c-12/new_device
# echo dps200 0x5b > /sys/bus/i2c/devices/i2c-13/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 # Attach fans
echo emc2305 0x4d > /sys/bus/i2c/devices/i2c-23/new_device echo emc2305 0x4d > /sys/bus/i2c/devices/i2c-23/new_device