[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.sfp_module_initialized = False
self.__initialize_eeprom()
self.is_host = self._api_common.is_host()
if not self.is_host: self._api_common = Common()
self._is_host = self._api_common.is_host()
self.__initialize_eeprom()
self.__initialize_fan() self.__initialize_fan()
self.__initialize_psu() self.__initialize_psu()
self.__initialize_thermals() self.__initialize_thermals()
else:
self.__initialize_components() self.__initialize_components()
self._reboot_cause_path = HOST_REBOOT_CAUSE_PATH if self.__is_host( self.sfp_module_initialized = False
) else PMON_REBOOT_CAUSE_PATH 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,7 +244,7 @@ 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):
try:
with open(path, 'r') as f: with open(path, 'r') as f:
output = f.readline() output = f.readline()
return output.strip('\n') 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,24 +273,16 @@ 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):
""" """
Retrieves the serial number of the device Retrieves the serial number of the device
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):
""" """
Retrieves the operational status of the device Retrieves the operational status of the device
@ -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

View File

@ -6,23 +6,44 @@
# #
############################################################################# #############################################################################
import os
import time
from ctypes import create_string_buffer
try: try:
import time
from ctypes import create_string_buffer
from sonic_platform_base.sfp_base import SfpBase from sonic_platform_base.sfp_base import SfpBase
from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom
from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId
from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom
from sonic_platform_base.sonic_sfp.sff8472 import sffbase from sonic_platform_base.sonic_sfp.sff8472 import sffbase
from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId
from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom
from sonic_platform_base.sonic_sfp.inf8628 import inf8628InterfaceId
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")
INFO_OFFSET = 0 INFO_OFFSET = 128
DOM_OFFSET = 256 DOM_OFFSET = 0
# definitions of the offset and width for values in XCVR info eeprom
XCVR_INTFACE_BULK_OFFSET = 0 XCVR_INTFACE_BULK_OFFSET = 0
XCVR_INTFACE_BULK_WIDTH_QSFP = 20
XCVR_INTFACE_BULK_WIDTH_SFP = 21 XCVR_INTFACE_BULK_WIDTH_SFP = 21
XCVR_TYPE_OFFSET = 0
XCVR_TYPE_WIDTH = 1
XCVR_EXT_TYPE_OFFSET = 1
XCVR_EXT_TYPE_WIDTH = 1
XCVR_CONNECTOR_OFFSET = 2
XCVR_CONNECTOR_WIDTH = 1
XCVR_COMPLIANCE_CODE_OFFSET = 3
XCVR_COMPLIANCE_CODE_WIDTH = 8
XCVR_ENCODING_OFFSET = 11
XCVR_ENCODING_WIDTH = 1
XCVR_NBR_OFFSET = 12
XCVR_NBR_WIDTH = 1
XCVR_EXT_RATE_SEL_OFFSET = 13
XCVR_EXT_RATE_SEL_WIDTH = 1
XCVR_CABLE_LENGTH_OFFSET = 14
XCVR_CABLE_LENGTH_WIDTH_QSFP = 5
XCVR_CABLE_LENGTH_WIDTH_SFP = 6
XCVR_VENDOR_NAME_OFFSET = 20 XCVR_VENDOR_NAME_OFFSET = 20
XCVR_VENDOR_NAME_WIDTH = 16 XCVR_VENDOR_NAME_WIDTH = 16
XCVR_VENDOR_OUI_OFFSET = 37 XCVR_VENDOR_OUI_OFFSET = 37
@ -30,30 +51,86 @@ XCVR_VENDOR_OUI_WIDTH = 3
XCVR_VENDOR_PN_OFFSET = 40 XCVR_VENDOR_PN_OFFSET = 40
XCVR_VENDOR_PN_WIDTH = 16 XCVR_VENDOR_PN_WIDTH = 16
XCVR_HW_REV_OFFSET = 56 XCVR_HW_REV_OFFSET = 56
XCVR_HW_REV_WIDTH_OSFP = 2
XCVR_HW_REV_WIDTH_QSFP = 2
XCVR_HW_REV_WIDTH_SFP = 4 XCVR_HW_REV_WIDTH_SFP = 4
XCVR_VENDOR_SN_OFFSET = 68 XCVR_VENDOR_SN_OFFSET = 68
XCVR_VENDOR_SN_WIDTH = 16 XCVR_VENDOR_SN_WIDTH = 16
XCVR_VENDOR_DATE_OFFSET = 84 XCVR_VENDOR_DATE_OFFSET = 84
XCVR_VENDOR_DATE_WIDTH = 8 XCVR_VENDOR_DATE_WIDTH = 8
XCVR_DOM_CAPABILITY_OFFSET = 92 XCVR_DOM_CAPABILITY_OFFSET = 92
XCVR_DOM_CAPABILITY_WIDTH = 1 XCVR_DOM_CAPABILITY_WIDTH = 2
XCVR_INTERFACE_DATA_START = 0
XCVR_INTERFACE_DATA_SIZE = 92
QSFP_DOM_BULK_DATA_START = 22
QSFP_DOM_BULK_DATA_SIZE = 36
SFP_DOM_BULK_DATA_START = 96
SFP_DOM_BULK_DATA_SIZE = 10
# definitions of the offset for values in OSFP info eeprom
OSFP_TYPE_OFFSET = 0
OSFP_VENDOR_NAME_OFFSET = 129
OSFP_VENDOR_PN_OFFSET = 148
OSFP_HW_REV_OFFSET = 164
OSFP_VENDOR_SN_OFFSET = 166
# Offset for values in QSFP eeprom
QSFP_DOM_REV_OFFSET = 1
QSFP_DOM_REV_WIDTH = 1
QSFP_TEMPE_OFFSET = 22
QSFP_TEMPE_WIDTH = 2
QSFP_VOLT_OFFSET = 26
QSFP_VOLT_WIDTH = 2
QSFP_VERSION_COMPLIANCE_OFFSET = 1
QSFP_VERSION_COMPLIANCE_WIDTH = 2
QSFP_CHANNL_MON_OFFSET = 34
QSFP_CHANNL_MON_WIDTH = 16
QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24
QSFP_CHANNL_DISABLE_STATUS_OFFSET = 86
QSFP_CHANNL_DISABLE_STATUS_WIDTH = 1
QSFP_CHANNL_RX_LOS_STATUS_OFFSET = 3
QSFP_CHANNL_RX_LOS_STATUS_WIDTH = 1
QSFP_CHANNL_TX_FAULT_STATUS_OFFSET = 4
QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1
QSFP_CONTROL_OFFSET = 86
QSFP_CONTROL_WIDTH = 8
QSFP_MODULE_MONITOR_OFFSET = 0
QSFP_MODULE_MONITOR_WIDTH = 9
QSFP_POWEROVERRIDE_OFFSET = 93
QSFP_POWEROVERRIDE_WIDTH = 1
QSFP_POWEROVERRIDE_BIT = 0
QSFP_POWERSET_BIT = 1
QSFP_OPTION_VALUE_OFFSET = 192
QSFP_OPTION_VALUE_WIDTH = 4
QSFP_MODULE_UPPER_PAGE3_START = 384
QSFP_MODULE_THRESHOLD_OFFSET = 128
QSFP_MODULE_THRESHOLD_WIDTH = 24
QSFP_CHANNL_THRESHOLD_OFFSET = 176
QSFP_CHANNL_THRESHOLD_WIDTH = 24
SFP_MODULE_ADDRA2_OFFSET = 256
SFP_MODULE_THRESHOLD_OFFSET = 0
SFP_MODULE_THRESHOLD_WIDTH = 56
SFP_CHANNL_THRESHOLD_OFFSET = 112
SFP_CHANNL_THRESHOLD_WIDTH = 2
# Offset for values in SFP eeprom
SFP_TEMPE_OFFSET = 96 SFP_TEMPE_OFFSET = 96
SFP_TEMPE_WIDTH = 2 SFP_TEMPE_WIDTH = 2
SFP_VOLT_OFFSET = 98 SFP_VOLT_OFFSET = 98
SFP_VOLT_WIDTH = 2 SFP_VOLT_WIDTH = 2
SFP_CHANNL_MON_OFFSET = 100 SFP_CHANNL_MON_OFFSET = 100
SFP_CHANNL_MON_WIDTH = 6 SFP_CHANNL_MON_WIDTH = 6
SFP_MODULE_THRESHOLD_OFFSET = 0 SFP_CHANNL_STATUS_OFFSET = 110
SFP_MODULE_THRESHOLD_WIDTH = 40 SFP_CHANNL_STATUS_WIDTH = 1
SFP_CHANNL_THRESHOLD_OFFSET = 112
SFP_CHANNL_THRESHOLD_WIDTH = 2
SFP_STATUS_CONTROL_OFFSET = 110
SFP_STATUS_CONTROL_WIDTH = 1
SFP_TX_DISABLE_HARD_BIT = 7 SFP_TX_DISABLE_HARD_BIT = 7
SFP_TX_DISABLE_SOFT_BIT = 6 SFP_TX_DISABLE_SOFT_BIT = 6
qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)',
'Length OM2(m)', 'Length OM1(m)',
'Length Cable Assembly(m)')
sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)', sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)',
'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)', 'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)',
'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)') 'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)')
@ -64,44 +141,63 @@ sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCod
'FibreChannelTechnology', 'SFP+CableTechnology', 'FibreChannelTechnology', 'SFP+CableTechnology',
'FibreChannelTransmissionMedia', 'FibreChannelSpeed') 'FibreChannelTransmissionMedia', 'FibreChannelSpeed')
qsfp_compliance_code_tup = ('10/40G Ethernet Compliance Code', 'SONET Compliance codes',
'SAS/SATA compliance codes', 'Gigabit Ethernet Compliant codes',
'Fibre Channel link length/Transmitter Technology',
'Fibre Channel transmission media', 'Fibre Channel Speed')
SFP_TYPE = "SFP"
QSFP_TYPE = "QSFP"
OSFP_TYPE = "OSFP"
ETP_TYPE = "ETP"
SFP_PORT_START = 49
SFP_PORT_END = 52
PORT_START = 1
PORT_END = 55
class Sfp(SfpBase): class Sfp(SfpBase):
"""Platform-specific Sfp class""" """Platform-specific Sfp class"""
# Port number # Port I2C number
PORT_START = 1
PORT_END = 52
port_to_i2c_mapping = { port_to_i2c_mapping = {
49: 15, 49: 15,
50: 14, 50: 14,
51: 17, 51: 17,
52: 16 52: 16
} }
_sfp_port = list(range(49, PORT_END + 1)) _sfp_port = list(range(SFP_PORT_START, SFP_PORT_END + 1))
PRS_PATH = "/sys/devices/platform/e1031.smc/SFP/sfp_modabs"
PLATFORM_ROOT_PATH = '/usr/share/sonic/device'
PMON_HWSKU_PATH = '/usr/share/sonic/hwsku'
HOST_CHK_CMD = "docker > /dev/null 2>&1"
PLATFORM = "x86_64-cel_e1031-r0" PRS_PATH = "/sys/devices/platform/e1031.smc/SFP/sfp_modabs"
HWSKU = "Celestica-E1031-T48S4"
def __init__(self, sfp_index, sfp_name): def __init__(self, sfp_index, sfp_name):
SfpBase.__init__(self)
# Init common function
self._api_common = Common()
# Init index # Init index
self.index = sfp_index self.index = sfp_index
self.port_num = self.index + 1 self.port_num = self.index + 1
# Init sfp data
self.sfp_type = self.__get_sfp_type()
self.name = sfp_name
# Init eeprom path # Init eeprom path
eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom'
self.port_to_eeprom_mapping = {} self.port_to_eeprom_mapping = {}
for x in range(self.PORT_START, self.PORT_END + 1): for x in range(PORT_START, PORT_END + 1):
if x not in self._sfp_port: if x not in self._sfp_port:
self.port_to_i2c_mapping[x] = None self.port_to_i2c_mapping[x] = None
self.port_to_eeprom_mapping[x] = eeprom_path.format( self.port_to_eeprom_mapping[x] = eeprom_path.format(
self.port_to_i2c_mapping[x]) self.port_to_i2c_mapping[x])
self.info_dict_keys = ['type', 'hardware_rev', 'serial', 'manufacturer', 'model', 'connector', 'encoding', 'ext_identifier', self.info_dict_keys = ['type', 'hardware_rev', 'serial', 'manufacturer', 'model', 'connector', 'encoding', 'ext_identifier',
'ext_rateselect_compliance', 'cable_type', 'cable_length', 'nominal_bit_rate', 'specification_compliance', 'vendor_date', 'vendor_oui'] 'ext_rateselect_compliance', 'cable_type', 'cable_length', 'nominal_bit_rate', 'specification_compliance',
'vendor_date', 'vendor_oui', "application_advertisement", "type_abbrv_name"]
self.dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', self.dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage',
'rx1power', 'rx2power', 'rx3power', 'rx4power', 'tx1bias', 'tx2bias', 'tx3bias', 'tx4bias', 'tx1power', 'tx2power', 'tx3power', 'tx4power'] 'rx1power', 'rx2power', 'rx3power', 'rx4power', 'tx1bias', 'tx2bias', 'tx3bias', 'tx4bias', 'tx1power', 'tx2power', 'tx3power', 'tx4power']
@ -109,10 +205,12 @@ class Sfp(SfpBase):
self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', 'rxpowerhighwarning', self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', 'rxpowerhighwarning',
'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] 'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning']
self.name = sfp_name self._dom_capability_detect()
SfpBase.__init__(self)
def _convert_string_to_num(self, value_str): def __get_sfp_type(self):
return SFP_TYPE if self.port_num in self._sfp_port else ETP_TYPE
def __convert_string_to_num(self, value_str):
if "-inf" in value_str: if "-inf" in value_str:
return 'N/A' return 'N/A'
elif "Unknown" in value_str: elif "Unknown" in value_str:
@ -132,18 +230,6 @@ class Sfp(SfpBase):
else: else:
return 'N/A' return 'N/A'
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 __is_host(self):
return os.system(self.HOST_CHK_CMD) == 0
def __read_eeprom_specific_bytes(self, offset, num_bytes): def __read_eeprom_specific_bytes(self, offset, num_bytes):
sysfsfile_eeprom = None sysfsfile_eeprom = None
eeprom_raw = [] eeprom_raw = []
@ -156,9 +242,13 @@ class Sfp(SfpBase):
sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0)
sysfsfile_eeprom.seek(offset) sysfsfile_eeprom.seek(offset)
raw = sysfsfile_eeprom.read(num_bytes) raw = sysfsfile_eeprom.read(num_bytes)
if isinstance(raw, str):
for n in range(0, num_bytes): for n in range(0, num_bytes):
eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2)
except Exception: else:
for n in range(0, num_bytes):
eeprom_raw[n] = hex(raw[n])[2:].zfill(2)
except BaseException:
pass pass
finally: finally:
if sysfsfile_eeprom: if sysfsfile_eeprom:
@ -166,6 +256,106 @@ class Sfp(SfpBase):
return eeprom_raw return eeprom_raw
def _dom_capability_detect(self):
if not self.get_presence():
self.dom_supported = False
self.dom_temp_supported = False
self.dom_volt_supported = False
self.dom_rx_power_supported = False
self.dom_tx_power_supported = False
self.calibration = 0
return
if self.sfp_type == "QSFP":
self.calibration = 1
sfpi_obj = sff8436InterfaceId()
if sfpi_obj is None:
self.dom_supported = False
offset = 128
# QSFP capability byte parse, through this byte can know whether it support tx_power or not.
# TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436,
# need to add more code for determining the capability and version compliance
# in SFF-8636 dom capability definitions evolving with the versions.
qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes(
(offset + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH)
if qsfp_dom_capability_raw is not None:
qsfp_version_compliance_raw = self.__read_eeprom_specific_bytes(
QSFP_VERSION_COMPLIANCE_OFFSET, QSFP_VERSION_COMPLIANCE_WIDTH)
qsfp_version_compliance = int(
qsfp_version_compliance_raw[0], 16)
dom_capability = sfpi_obj.parse_dom_capability(
qsfp_dom_capability_raw, 0)
if qsfp_version_compliance >= 0x08:
self.dom_temp_supported = dom_capability['data']['Temp_support']['value'] == 'On'
self.dom_volt_supported = dom_capability['data']['Voltage_support']['value'] == 'On'
self.dom_rx_power_supported = dom_capability['data']['Rx_power_support']['value'] == 'On'
self.dom_tx_power_supported = dom_capability['data']['Tx_power_support']['value'] == 'On'
else:
self.dom_temp_supported = True
self.dom_volt_supported = True
self.dom_rx_power_supported = dom_capability['data']['Rx_power_support']['value'] == 'On'
self.dom_tx_power_supported = True
self.dom_supported = True
self.calibration = 1
sfpd_obj = sff8436Dom()
if sfpd_obj is None:
return None
qsfp_option_value_raw = self.__read_eeprom_specific_bytes(
QSFP_OPTION_VALUE_OFFSET, QSFP_OPTION_VALUE_WIDTH)
if qsfp_option_value_raw is not None:
optional_capability = sfpd_obj.parse_option_params(
qsfp_option_value_raw, 0)
self.dom_tx_disable_supported = optional_capability[
'data']['TxDisable']['value'] == 'On'
dom_status_indicator = sfpd_obj.parse_dom_status_indicator(
qsfp_version_compliance_raw, 1)
self.qsfp_page3_available = dom_status_indicator['data']['FlatMem']['value'] == 'Off'
else:
self.dom_supported = False
self.dom_temp_supported = False
self.dom_volt_supported = False
self.dom_rx_power_supported = False
self.dom_tx_power_supported = False
self.calibration = 0
self.qsfp_page3_available = False
elif self.sfp_type == "SFP":
sfpi_obj = sff8472InterfaceId()
if sfpi_obj is None:
return None
sfp_dom_capability_raw = self.__read_eeprom_specific_bytes(
XCVR_DOM_CAPABILITY_OFFSET, XCVR_DOM_CAPABILITY_WIDTH)
if sfp_dom_capability_raw is not None:
sfp_dom_capability = int(sfp_dom_capability_raw[0], 16)
self.dom_supported = (sfp_dom_capability & 0x40 != 0)
if self.dom_supported:
self.dom_temp_supported = True
self.dom_volt_supported = True
self.dom_rx_power_supported = True
self.dom_tx_power_supported = True
if sfp_dom_capability & 0x20 != 0:
self.calibration = 1
elif sfp_dom_capability & 0x10 != 0:
self.calibration = 2
else:
self.calibration = 0
else:
self.dom_temp_supported = False
self.dom_volt_supported = False
self.dom_rx_power_supported = False
self.dom_tx_power_supported = False
self.calibration = 0
self.dom_tx_disable_supported = (
int(sfp_dom_capability_raw[1], 16) & 0x40 != 0)
else:
self.dom_supported = False
self.dom_temp_supported = False
self.dom_volt_supported = False
self.dom_rx_power_supported = False
self.dom_tx_power_supported = False
def get_transceiver_info(self): def get_transceiver_info(self):
""" """
Retrieves transceiver info of this SFP Retrieves transceiver info of this SFP
@ -190,71 +380,168 @@ class Sfp(SfpBase):
vendor_oui |1*255VCHAR |vendor OUI vendor_oui |1*255VCHAR |vendor OUI
======================================================================== ========================================================================
""" """
# check present status compliance_code_dict = {}
sfpi_obj = sff8472InterfaceId() transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A')
if not self.get_presence() or not sfpi_obj: if not self.get_presence():
return {} return transceiver_info_dict
offset = INFO_OFFSET # ToDo: OSFP tranceiver info parsing not fully supported.
# in inf8628.py lack of some memory map definition
# will be implemented when the inf8628 memory map ready
if self.sfp_type == OSFP_TYPE:
offset = 0
vendor_rev_width = XCVR_HW_REV_WIDTH_OSFP
sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes( sfpi_obj = inf8628InterfaceId()
(offset + XCVR_INTFACE_BULK_OFFSET), XCVR_INTFACE_BULK_WIDTH_SFP) if sfpi_obj is None:
sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk( return None
sfp_interface_bulk_raw, 0)
sfp_type_raw = self.__read_eeprom_specific_bytes(
(offset + OSFP_TYPE_OFFSET), XCVR_TYPE_WIDTH)
if sfp_type_raw is not None:
sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0)
else:
return None
sfp_vendor_name_raw = self.__read_eeprom_specific_bytes( sfp_vendor_name_raw = self.__read_eeprom_specific_bytes(
(offset + XCVR_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) (offset + OSFP_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH)
if sfp_vendor_name_raw is not None:
sfp_vendor_name_data = sfpi_obj.parse_vendor_name( sfp_vendor_name_data = sfpi_obj.parse_vendor_name(
sfp_vendor_name_raw, 0) sfp_vendor_name_raw, 0)
else:
return None
sfp_vendor_pn_raw = self.__read_eeprom_specific_bytes( sfp_vendor_pn_raw = self.__read_eeprom_specific_bytes(
(offset + XCVR_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) (offset + OSFP_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH)
if sfp_vendor_pn_raw is not None:
sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(
sfp_vendor_pn_raw, 0) sfp_vendor_pn_raw, 0)
else:
return None
sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes( sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes(
(offset + XCVR_HW_REV_OFFSET), XCVR_HW_REV_WIDTH_SFP) (offset + OSFP_HW_REV_OFFSET), vendor_rev_width)
if sfp_vendor_rev_raw is not None:
sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(
sfp_vendor_rev_raw, 0) sfp_vendor_rev_raw, 0)
else:
return None
sfp_vendor_sn_raw = self.__read_eeprom_specific_bytes( sfp_vendor_sn_raw = self.__read_eeprom_specific_bytes(
(offset + XCVR_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) (offset + OSFP_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH)
if sfp_vendor_sn_raw is not None:
sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(
sfp_vendor_sn_raw, 0) sfp_vendor_sn_raw, 0)
else:
return None
sfp_vendor_oui_raw = self.__read_eeprom_specific_bytes( transceiver_info_dict['type'] = sfp_type_data['data']['type']['value']
(offset + XCVR_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH) transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value']
if sfp_vendor_oui_raw is not None: transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value']
transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value']
transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value']
transceiver_info_dict['vendor_oui'] = 'N/A'
transceiver_info_dict['vendor_date'] = 'N/A'
transceiver_info_dict['connector'] = 'N/A'
transceiver_info_dict['encoding'] = 'N/A'
transceiver_info_dict['ext_identifier'] = 'N/A'
transceiver_info_dict['ext_rateselect_compliance'] = 'N/A'
transceiver_info_dict['cable_type'] = 'N/A'
transceiver_info_dict['cable_length'] = 'N/A'
transceiver_info_dict['specification_compliance'] = '{}'
transceiver_info_dict['nominal_bit_rate'] = 'N/A'
else:
if self.sfp_type == QSFP_TYPE:
offset = 128
vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP
# cable_length_width = XCVR_CABLE_LENGTH_WIDTH_QSFP
interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP
sfpi_obj = sff8436InterfaceId()
if sfpi_obj is None:
print("Error: sfp_object open failed")
return None
else:
offset = 0
vendor_rev_width = XCVR_HW_REV_WIDTH_SFP
# cable_length_width = XCVR_CABLE_LENGTH_WIDTH_SFP
interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP
sfpi_obj = sff8472InterfaceId()
if sfpi_obj is None:
print("Error: sfp_object open failed")
return None
sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes(
offset + XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE)
if sfp_interface_bulk_raw is None:
return None
start = XCVR_INTFACE_BULK_OFFSET - XCVR_INTERFACE_DATA_START
end = start + interface_info_bulk_width
sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(
sfp_interface_bulk_raw[start: end], 0)
start = XCVR_VENDOR_NAME_OFFSET - XCVR_INTERFACE_DATA_START
end = start + XCVR_VENDOR_NAME_WIDTH
sfp_vendor_name_data = sfpi_obj.parse_vendor_name(
sfp_interface_bulk_raw[start: end], 0)
start = XCVR_VENDOR_PN_OFFSET - XCVR_INTERFACE_DATA_START
end = start + XCVR_VENDOR_PN_WIDTH
sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(
sfp_interface_bulk_raw[start: end], 0)
start = XCVR_HW_REV_OFFSET - XCVR_INTERFACE_DATA_START
end = start + vendor_rev_width
sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(
sfp_interface_bulk_raw[start: end], 0)
start = XCVR_VENDOR_SN_OFFSET - XCVR_INTERFACE_DATA_START
end = start + XCVR_VENDOR_SN_WIDTH
sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(
sfp_interface_bulk_raw[start: end], 0)
start = XCVR_VENDOR_OUI_OFFSET - XCVR_INTERFACE_DATA_START
end = start + XCVR_VENDOR_OUI_WIDTH
sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui( sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(
sfp_vendor_oui_raw, 0) sfp_interface_bulk_raw[start: end], 0)
sfp_vendor_date_raw = self.__read_eeprom_specific_bytes( start = XCVR_VENDOR_DATE_OFFSET - XCVR_INTERFACE_DATA_START
(offset + XCVR_VENDOR_DATE_OFFSET), XCVR_VENDOR_DATE_WIDTH) end = start + XCVR_VENDOR_DATE_WIDTH
sfp_vendor_date_data = sfpi_obj.parse_vendor_date( sfp_vendor_date_data = sfpi_obj.parse_vendor_date(
sfp_vendor_date_raw, 0) sfp_interface_bulk_raw[start: end], 0)
transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A')
compliance_code_dict = dict()
if sfp_interface_bulk_data:
transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value']
transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value']
transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value']
transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value']
transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value']
transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value']
transceiver_info_dict['vendor_date'] = sfp_vendor_date_data[
'data']['VendorDataCode(YYYY-MM-DD Lot)']['value']
transceiver_info_dict['connector'] = sfp_interface_bulk_data['data']['Connector']['value'] transceiver_info_dict['connector'] = sfp_interface_bulk_data['data']['Connector']['value']
transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value'] transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value']
transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value'] transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value']
transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value'] transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value']
transceiver_info_dict['type_abbrv_name'] = sfp_interface_bulk_data['data']['type_abbrv_name']['value'] transceiver_info_dict['type_abbrv_name'] = sfp_interface_bulk_data['data']['type_abbrv_name']['value']
transceiver_info_dict['manufacturer'] = sfp_vendor_name_data[ if self.sfp_type == QSFP_TYPE:
'data']['Vendor Name']['value'] if sfp_vendor_name_data else 'N/A' for key in qsfp_cable_length_tup:
transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] if sfp_vendor_pn_data else 'N/A' if key in sfp_interface_bulk_data['data']:
transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] if sfp_vendor_rev_data else 'N/A' transceiver_info_dict['cable_type'] = key
transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] if sfp_vendor_sn_data else 'N/A' transceiver_info_dict['cable_length'] = str(
transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] if sfp_vendor_oui_data else 'N/A' sfp_interface_bulk_data['data'][key]['value'])
transceiver_info_dict['vendor_date'] = sfp_vendor_date_data[
'data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] if sfp_vendor_date_data else 'N/A'
transceiver_info_dict['cable_type'] = "Unknown"
transceiver_info_dict['cable_length'] = "Unknown"
for key in qsfp_compliance_code_tup:
if key in sfp_interface_bulk_data['data']['Specification compliance']['value']:
compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value']
transceiver_info_dict['specification_compliance'] = str(
compliance_code_dict)
transceiver_info_dict['nominal_bit_rate'] = str(
sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value'])
else:
for key in sfp_cable_length_tup: for key in sfp_cable_length_tup:
if key in sfp_interface_bulk_data['data']: if key in sfp_interface_bulk_data['data']:
transceiver_info_dict['cable_type'] = key transceiver_info_dict['cable_type'] = key
@ -266,6 +553,7 @@ class Sfp(SfpBase):
compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value']
transceiver_info_dict['specification_compliance'] = str( transceiver_info_dict['specification_compliance'] = str(
compliance_code_dict) compliance_code_dict)
transceiver_info_dict['nominal_bit_rate'] = str( transceiver_info_dict['nominal_bit_rate'] = str(
sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value'])
@ -296,44 +584,117 @@ class Sfp(SfpBase):
| |for example, tx2power stands for tx power of channel 2. | |for example, tx2power stands for tx power of channel 2.
======================================================================== ========================================================================
""" """
# check present status
sfpd_obj = sff8472Dom()
if not self.get_presence() or not sfpd_obj:
return {}
eeprom_ifraw = self.__read_eeprom_specific_bytes(0, DOM_OFFSET)
sfpi_obj = sff8472InterfaceId(eeprom_ifraw)
cal_type = sfpi_obj.get_calibration_type()
sfpd_obj._calibration_type = cal_type
offset = DOM_OFFSET
transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A')
dom_temperature_raw = self.__read_eeprom_specific_bytes(
(offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH)
if dom_temperature_raw is not None: if self.sfp_type == OSFP_TYPE:
pass
elif self.sfp_type == QSFP_TYPE:
if not self.dom_supported:
return transceiver_dom_info_dict
offset = 0
sfpd_obj = sff8436Dom()
if sfpd_obj is None:
return transceiver_dom_info_dict
dom_data_raw = self.__read_eeprom_specific_bytes(
(offset + QSFP_DOM_BULK_DATA_START), QSFP_DOM_BULK_DATA_SIZE)
if dom_data_raw is None:
return transceiver_dom_info_dict
if self.dom_temp_supported:
start = QSFP_TEMPE_OFFSET - QSFP_DOM_BULK_DATA_START
end = start + QSFP_TEMPE_WIDTH
dom_temperature_data = sfpd_obj.parse_temperature( dom_temperature_data = sfpd_obj.parse_temperature(
dom_temperature_raw, 0) dom_data_raw[start: end], 0)
transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] temp = self.__convert_string_to_num(
dom_temperature_data['data']['Temperature']['value'])
if temp is not None:
transceiver_dom_info_dict['temperature'] = temp
dom_voltage_raw = self.__read_eeprom_specific_bytes( if self.dom_volt_supported:
(offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) start = QSFP_VOLT_OFFSET - QSFP_DOM_BULK_DATA_START
if dom_voltage_raw is not None: end = start + QSFP_VOLT_WIDTH
dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) dom_voltage_data = sfpd_obj.parse_voltage(
transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] dom_data_raw[start: end], 0)
volt = self.__convert_string_to_num(
dom_voltage_data['data']['Vcc']['value'])
if volt is not None:
transceiver_dom_info_dict['voltage'] = volt
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( start = QSFP_CHANNL_MON_OFFSET - QSFP_DOM_BULK_DATA_START
(offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) end = start + QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH
if dom_channel_monitor_raw is not None: dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(
dom_voltage_data = sfpd_obj.parse_channel_monitor_params( dom_data_raw[start: end], 0)
dom_channel_monitor_raw, 0)
transceiver_dom_info_dict['tx1power'] = dom_voltage_data['data']['TXPower']['value']
transceiver_dom_info_dict['rx1power'] = dom_voltage_data['data']['RXPower']['value']
transceiver_dom_info_dict['tx1bias'] = dom_voltage_data['data']['TXBias']['value']
for key in transceiver_dom_info_dict: if self.dom_tx_power_supported:
transceiver_dom_info_dict[key] = self._convert_string_to_num( transceiver_dom_info_dict['tx1power'] = self.__convert_string_to_num(
transceiver_dom_info_dict[key]) dom_channel_monitor_data['data']['TX1Power']['value'])
transceiver_dom_info_dict['tx2power'] = self.__convert_string_to_num(
dom_channel_monitor_data['data']['TX2Power']['value'])
transceiver_dom_info_dict['tx3power'] = self.__convert_string_to_num(
dom_channel_monitor_data['data']['TX3Power']['value'])
transceiver_dom_info_dict['tx4power'] = self.__convert_string_to_num(
dom_channel_monitor_data['data']['TX4Power']['value'])
if self.dom_rx_power_supported:
transceiver_dom_info_dict['rx1power'] = self.__convert_string_to_num(
dom_channel_monitor_data['data']['RX1Power']['value'])
transceiver_dom_info_dict['rx2power'] = self.__convert_string_to_num(
dom_channel_monitor_data['data']['RX2Power']['value'])
transceiver_dom_info_dict['rx3power'] = self.__convert_string_to_num(
dom_channel_monitor_data['data']['RX3Power']['value'])
transceiver_dom_info_dict['rx4power'] = self.__convert_string_to_num(
dom_channel_monitor_data['data']['RX4Power']['value'])
transceiver_dom_info_dict['tx1bias'] = self.__convert_string_to_num(
dom_channel_monitor_data['data']['TX1Bias']['value'])
transceiver_dom_info_dict['tx2bias'] = self.__convert_string_to_num(
dom_channel_monitor_data['data']['TX2Bias']['value'])
transceiver_dom_info_dict['tx3bias'] = self.__convert_string_to_num(
dom_channel_monitor_data['data']['TX3Bias']['value'])
transceiver_dom_info_dict['tx4bias'] = self.__convert_string_to_num(
dom_channel_monitor_data['data']['TX4Bias']['value'])
else:
if not self.dom_supported:
return transceiver_dom_info_dict
offset = 256
sfpd_obj = sff8472Dom()
if sfpd_obj is None:
return transceiver_dom_info_dict
sfpd_obj._calibration_type = self.calibration
dom_data_raw = self.__read_eeprom_specific_bytes(
(offset + SFP_DOM_BULK_DATA_START), SFP_DOM_BULK_DATA_SIZE)
start = SFP_TEMPE_OFFSET - SFP_DOM_BULK_DATA_START
end = start + SFP_TEMPE_WIDTH
dom_temperature_data = sfpd_obj.parse_temperature(
dom_data_raw[start: end], 0)
start = SFP_VOLT_OFFSET - SFP_DOM_BULK_DATA_START
end = start + SFP_VOLT_WIDTH
dom_voltage_data = sfpd_obj.parse_voltage(
dom_data_raw[start: end], 0)
start = SFP_CHANNL_MON_OFFSET - SFP_DOM_BULK_DATA_START
end = start + SFP_CHANNL_MON_WIDTH
dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(
dom_data_raw[start: end], 0)
transceiver_dom_info_dict['temperature'] = self.__convert_string_to_num(
dom_temperature_data['data']['Temperature']['value'])
transceiver_dom_info_dict['voltage'] = self.__convert_string_to_num(
dom_voltage_data['data']['Vcc']['value'])
transceiver_dom_info_dict['rx1power'] = self.__convert_string_to_num(
dom_channel_monitor_data['data']['RXPower']['value'])
transceiver_dom_info_dict['tx1bias'] = self.__convert_string_to_num(
dom_channel_monitor_data['data']['TXBias']['value'])
transceiver_dom_info_dict['tx1power'] = self.__convert_string_to_num(
dom_channel_monitor_data['data']['TXPower']['value'])
transceiver_dom_info_dict['rx_los'] = self.get_rx_los() transceiver_dom_info_dict['rx_los'] = self.get_rx_los()
transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault() transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault()
@ -372,26 +733,79 @@ class Sfp(SfpBase):
txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA.
======================================================================== ========================================================================
""" """
# check present status
sfpd_obj = sff8472Dom()
if not self.get_presence() and not sfpd_obj:
return {}
eeprom_ifraw = self.__read_eeprom_specific_bytes(0, DOM_OFFSET)
sfpi_obj = sff8472InterfaceId(eeprom_ifraw)
cal_type = sfpi_obj.get_calibration_type()
sfpd_obj._calibration_type = cal_type
offset = DOM_OFFSET
transceiver_dom_threshold_info_dict = dict.fromkeys( transceiver_dom_threshold_info_dict = dict.fromkeys(
self.threshold_dict_keys, 'N/A') self.threshold_dict_keys, 'N/A')
if self.sfp_type == OSFP_TYPE:
pass
elif self.sfp_type == QSFP_TYPE:
if not self.dom_supported or not self.qsfp_page3_available:
return transceiver_dom_threshold_info_dict
# Dom Threshold data starts from offset 384
# Revert offset back to 0 once data is retrieved
offset = QSFP_MODULE_UPPER_PAGE3_START
sfpd_obj = sff8436Dom()
if sfpd_obj is None:
return transceiver_dom_threshold_info_dict
dom_module_threshold_raw = self.__read_eeprom_specific_bytes( dom_module_threshold_raw = self.__read_eeprom_specific_bytes(
(offset + SFP_MODULE_THRESHOLD_OFFSET), SFP_MODULE_THRESHOLD_WIDTH) (offset + QSFP_MODULE_THRESHOLD_OFFSET), QSFP_MODULE_THRESHOLD_WIDTH)
if dom_module_threshold_raw is None:
return transceiver_dom_threshold_info_dict
dom_module_threshold_data = sfpd_obj.parse_module_threshold_values(
dom_module_threshold_raw, 0)
dom_channel_threshold_raw = self.__read_eeprom_specific_bytes((offset + QSFP_CHANNL_THRESHOLD_OFFSET),
QSFP_CHANNL_THRESHOLD_WIDTH)
if dom_channel_threshold_raw is None:
return transceiver_dom_threshold_info_dict
dom_channel_threshold_data = sfpd_obj.parse_channel_threshold_values(
dom_channel_threshold_raw, 0)
# Threshold Data
transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value']
transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value']
transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value']
transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value']
transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value']
transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value']
transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value']
transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value']
transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value']
transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value']
transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value']
transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value']
transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['TxBiasHighAlarm']['value']
transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['TxBiasHighWarning']['value']
transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['TxBiasLowAlarm']['value']
transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value']
transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_channel_threshold_data['data']['TxPowerHighAlarm']['value']
transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_channel_threshold_data['data']['TxPowerHighWarning']['value']
transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_channel_threshold_data['data']['TxPowerLowAlarm']['value']
transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_channel_threshold_data['data']['TxPowerLowWarning']['value']
else:
offset = SFP_MODULE_ADDRA2_OFFSET
if not self.dom_supported:
return transceiver_dom_threshold_info_dict
sfpd_obj = sff8472Dom(None, self.calibration)
if sfpd_obj is None:
return transceiver_dom_threshold_info_dict
dom_module_threshold_raw = self.__read_eeprom_specific_bytes((offset + SFP_MODULE_THRESHOLD_OFFSET),
SFP_MODULE_THRESHOLD_WIDTH)
if dom_module_threshold_raw is not None: if dom_module_threshold_raw is not None:
dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold( dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold(
dom_module_threshold_raw, 0) dom_module_threshold_raw, 0)
else:
return transceiver_dom_threshold_info_dict
# Threshold Data
transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value']
transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value']
transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value']
@ -415,7 +829,7 @@ class Sfp(SfpBase):
transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value']
for key in transceiver_dom_threshold_info_dict: for key in transceiver_dom_threshold_info_dict:
transceiver_dom_threshold_info_dict[key] = self._convert_string_to_num( transceiver_dom_threshold_info_dict[key] = self.__convert_string_to_num(
transceiver_dom_threshold_info_dict[key]) transceiver_dom_threshold_info_dict[key])
return transceiver_dom_threshold_info_dict return transceiver_dom_threshold_info_dict
@ -437,11 +851,27 @@ class Sfp(SfpBase):
Note : RX LOS status is latched until a call to get_rx_los or a reset. Note : RX LOS status is latched until a call to get_rx_los or a reset.
""" """
rx_los = False rx_los = False
status_control_raw = self.__read_eeprom_specific_bytes( if self.sfp_type == OSFP_TYPE:
SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) return False
if status_control_raw:
data = int(status_control_raw[0], 16) elif self.sfp_type == QSFP_TYPE:
rx_los = (sffbase().test_bit(data, 1) != 0) offset = 0
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
(offset + QSFP_CHANNL_RX_LOS_STATUS_OFFSET), QSFP_CHANNL_RX_LOS_STATUS_WIDTH)
if dom_channel_monitor_raw is not None:
rx_los_data = int(dom_channel_monitor_raw[0], 16)
rx1_los = (rx_los_data & 0x01 != 0)
rx2_los = (rx_los_data & 0x02 != 0)
rx3_los = (rx_los_data & 0x04 != 0)
rx4_los = (rx_los_data & 0x08 != 0)
rx_los = (rx1_los and rx2_los and rx3_los and rx4_los)
else:
offset = 256
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
(offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH)
if dom_channel_monitor_raw is not None:
rx_los_data = int(dom_channel_monitor_raw[0], 16)
rx_los = (rx_los_data & 0x02 != 0)
return rx_los return rx_los
@ -452,14 +882,32 @@ class Sfp(SfpBase):
A Boolean, True if SFP has TX fault, False if not A Boolean, True if SFP has TX fault, False if not
Note : TX fault status is lached until a call to get_tx_fault or a reset. Note : TX fault status is lached until a call to get_tx_fault or a reset.
""" """
tx_fault = False tx4_fault = False
status_control_raw = self.__read_eeprom_specific_bytes(
SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH)
if status_control_raw:
data = int(status_control_raw[0], 16)
tx_fault = (sffbase().test_bit(data, 2) != 0)
return tx_fault if self.sfp_type == OSFP_TYPE or not self.dom_supported:
return False
elif self.sfp_type == QSFP_TYPE:
offset = 0
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
(offset + QSFP_CHANNL_TX_FAULT_STATUS_OFFSET), QSFP_CHANNL_TX_FAULT_STATUS_WIDTH)
if dom_channel_monitor_raw is not None:
tx_fault_data = int(dom_channel_monitor_raw[0], 16)
tx1_fault = (tx_fault_data & 0x01 != 0)
tx2_fault = (tx_fault_data & 0x02 != 0)
tx3_fault = (tx_fault_data & 0x04 != 0)
tx4_fault = (tx_fault_data & 0x08 != 0)
tx4_fault = (
tx1_fault and tx2_fault and tx3_fault and tx4_fault)
else:
offset = 256
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
(offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH)
if dom_channel_monitor_raw is not None:
tx_fault_data = int(dom_channel_monitor_raw[0], 16)
tx4_fault = (tx_fault_data & 0x04 != 0)
return tx4_fault
def get_tx_disable(self): def get_tx_disable(self):
""" """
@ -469,7 +917,7 @@ class Sfp(SfpBase):
""" """
tx_disable = False tx_disable = False
status_control_raw = self.__read_eeprom_specific_bytes( status_control_raw = self.__read_eeprom_specific_bytes(
SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) SFP_CHANNL_STATUS_OFFSET, SFP_CHANNL_STATUS_WIDTH)
if status_control_raw: if status_control_raw:
data = int(status_control_raw[0], 16) data = int(status_control_raw[0], 16)
tx_disable_hard = (sffbase().test_bit( tx_disable_hard = (sffbase().test_bit(
@ -516,8 +964,8 @@ class Sfp(SfpBase):
Returns: Returns:
An integer number of current temperature in Celsius An integer number of current temperature in Celsius
""" """
transceiver_dom_info_dict = self.get_transceiver_bulk_status() transceiver_bulk_status = self.get_transceiver_bulk_status()
return transceiver_dom_info_dict.get("temperature", "N/A") return transceiver_bulk_status.get("temperature", "N/A")
def get_voltage(self): def get_voltage(self):
""" """
@ -525,8 +973,8 @@ class Sfp(SfpBase):
Returns: Returns:
An integer number of supply voltage in mV An integer number of supply voltage in mV
""" """
transceiver_dom_info_dict = self.get_transceiver_bulk_status() transceiver_bulk_status = self.get_transceiver_bulk_status()
return transceiver_dom_info_dict.get("voltage", "N/A") return transceiver_bulk_status.get("voltage", "N/A")
def get_tx_bias(self): def get_tx_bias(self):
""" """
@ -584,7 +1032,7 @@ class Sfp(SfpBase):
""" """
sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num]
status_control_raw = self.__read_eeprom_specific_bytes( status_control_raw = self.__read_eeprom_specific_bytes(
SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) SFP_CHANNL_STATUS_OFFSET, SFP_CHANNL_STATUS_WIDTH)
if status_control_raw is not None: if status_control_raw is not None:
# Set bit 6 for Soft TX Disable Select # Set bit 6 for Soft TX Disable Select
# 01000000 = 64 and 10111111 = 191 # 01000000 = 64 and 10111111 = 191
@ -598,10 +1046,9 @@ class Sfp(SfpBase):
buffer = create_string_buffer(1) buffer = create_string_buffer(1)
buffer[0] = chr(tx_disable_ctl) buffer[0] = chr(tx_disable_ctl)
# Write to eeprom # Write to eeprom
sysfsfile_eeprom.seek(SFP_STATUS_CONTROL_OFFSET) sysfsfile_eeprom.seek(SFP_CHANNL_STATUS_OFFSET)
sysfsfile_eeprom.write(buffer[0]) sysfsfile_eeprom.write(buffer[0])
except Exception: except Exception:
#print("Error: unable to open file: %s" % str(e))
return False return False
finally: finally:
if sysfsfile_eeprom: if sysfsfile_eeprom:
@ -656,6 +1103,10 @@ class Sfp(SfpBase):
# SFP doesn't support this feature # SFP doesn't support this feature
return False return False
##############################################################
###################### Device methods ########################
##############################################################
def get_name(self): def get_name(self):
""" """
Retrieves the name of the device Retrieves the name of the device
@ -700,3 +1151,26 @@ class Sfp(SfpBase):
""" """
transceiver_dom_info_dict = self.get_transceiver_info() transceiver_dom_info_dict = self.get_transceiver_info()
return transceiver_dom_info_dict.get("serial", "N/A") return transceiver_dom_info_dict.get("serial", "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 self.get_presence() and not self.get_reset_status()
def get_position_in_parent(self):
"""
Returns:
Temp return 0
"""
return 0
def is_replaceable(self):
"""
Retrieves if replaceable
Returns:
A boolean value, True if replaceable
"""
return True

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: except IOError as e:
pass print("Error: unable to disable wdt due to : {}".format(e))
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