[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 Judy Joseph
parent a10f1f22de
commit b0782fb17e
16 changed files with 2270 additions and 608 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,23 +6,44 @@
#
#############################################################################
import os
try:
import time
from ctypes import create_string_buffer
try:
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 sff8472Dom
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:
raise ImportError(str(e) + "- required module not found")
INFO_OFFSET = 0
DOM_OFFSET = 256
INFO_OFFSET = 128
DOM_OFFSET = 0
# definitions of the offset and width for values in XCVR info eeprom
XCVR_INTFACE_BULK_OFFSET = 0
XCVR_INTFACE_BULK_WIDTH_QSFP = 20
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_WIDTH = 16
XCVR_VENDOR_OUI_OFFSET = 37
@ -30,30 +51,86 @@ XCVR_VENDOR_OUI_WIDTH = 3
XCVR_VENDOR_PN_OFFSET = 40
XCVR_VENDOR_PN_WIDTH = 16
XCVR_HW_REV_OFFSET = 56
XCVR_HW_REV_WIDTH_OSFP = 2
XCVR_HW_REV_WIDTH_QSFP = 2
XCVR_HW_REV_WIDTH_SFP = 4
XCVR_VENDOR_SN_OFFSET = 68
XCVR_VENDOR_SN_WIDTH = 16
XCVR_VENDOR_DATE_OFFSET = 84
XCVR_VENDOR_DATE_WIDTH = 8
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_WIDTH = 2
SFP_VOLT_OFFSET = 98
SFP_VOLT_WIDTH = 2
SFP_CHANNL_MON_OFFSET = 100
SFP_CHANNL_MON_WIDTH = 6
SFP_MODULE_THRESHOLD_OFFSET = 0
SFP_MODULE_THRESHOLD_WIDTH = 40
SFP_CHANNL_THRESHOLD_OFFSET = 112
SFP_CHANNL_THRESHOLD_WIDTH = 2
SFP_STATUS_CONTROL_OFFSET = 110
SFP_STATUS_CONTROL_WIDTH = 1
SFP_CHANNL_STATUS_OFFSET = 110
SFP_CHANNL_STATUS_WIDTH = 1
SFP_TX_DISABLE_HARD_BIT = 7
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)',
'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)',
'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)')
@ -64,44 +141,63 @@ sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCod
'FibreChannelTechnology', 'SFP+CableTechnology',
'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):
"""Platform-specific Sfp class"""
# Port number
PORT_START = 1
PORT_END = 52
# Port I2C number
port_to_i2c_mapping = {
49: 15,
50: 14,
51: 17,
52: 16
}
_sfp_port = list(range(49, 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"
_sfp_port = list(range(SFP_PORT_START, SFP_PORT_END + 1))
PLATFORM = "x86_64-cel_e1031-r0"
HWSKU = "Celestica-E1031-T48S4"
PRS_PATH = "/sys/devices/platform/e1031.smc/SFP/sfp_modabs"
def __init__(self, sfp_index, sfp_name):
SfpBase.__init__(self)
# Init common function
self._api_common = Common()
# Init index
self.index = sfp_index
self.port_num = self.index + 1
# Init sfp data
self.sfp_type = self.__get_sfp_type()
self.name = sfp_name
# Init eeprom path
eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom'
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:
self.port_to_i2c_mapping[x] = None
self.port_to_eeprom_mapping[x] = eeprom_path.format(
self.port_to_i2c_mapping[x])
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',
'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',
'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning']
self.name = sfp_name
SfpBase.__init__(self)
self._dom_capability_detect()
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:
return 'N/A'
elif "Unknown" in value_str:
@ -132,18 +230,6 @@ class Sfp(SfpBase):
else:
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):
sysfsfile_eeprom = None
eeprom_raw = []
@ -156,9 +242,13 @@ class Sfp(SfpBase):
sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0)
sysfsfile_eeprom.seek(offset)
raw = sysfsfile_eeprom.read(num_bytes)
if isinstance(raw, str):
for n in range(0, num_bytes):
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
finally:
if sysfsfile_eeprom:
@ -166,6 +256,106 @@ class Sfp(SfpBase):
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):
"""
Retrieves transceiver info of this SFP
@ -190,71 +380,168 @@ class Sfp(SfpBase):
vendor_oui |1*255VCHAR |vendor OUI
========================================================================
"""
# check present status
sfpi_obj = sff8472InterfaceId()
if not self.get_presence() or not sfpi_obj:
return {}
compliance_code_dict = {}
transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A')
if not self.get_presence():
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(
(offset + XCVR_INTFACE_BULK_OFFSET), XCVR_INTFACE_BULK_WIDTH_SFP)
sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(
sfp_interface_bulk_raw, 0)
sfpi_obj = inf8628InterfaceId()
if sfpi_obj is None:
return None
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(
(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_raw, 0)
else:
return None
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_raw, 0)
else:
return None
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_raw, 0)
else:
return None
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_raw, 0)
else:
return None
sfp_vendor_oui_raw = self.__read_eeprom_specific_bytes(
(offset + XCVR_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH)
if sfp_vendor_oui_raw is not None:
transceiver_info_dict['type'] = sfp_type_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'] = '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_raw, 0)
sfp_interface_bulk_raw[start: end], 0)
sfp_vendor_date_raw = self.__read_eeprom_specific_bytes(
(offset + XCVR_VENDOR_DATE_OFFSET), XCVR_VENDOR_DATE_WIDTH)
start = XCVR_VENDOR_DATE_OFFSET - XCVR_INTERFACE_DATA_START
end = start + XCVR_VENDOR_DATE_WIDTH
sfp_vendor_date_data = sfpi_obj.parse_vendor_date(
sfp_vendor_date_raw, 0)
transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A')
compliance_code_dict = dict()
if sfp_interface_bulk_data:
sfp_interface_bulk_raw[start: end], 0)
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['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_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['manufacturer'] = sfp_vendor_name_data[
'data']['Vendor Name']['value'] if sfp_vendor_name_data else 'N/A'
transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] if sfp_vendor_pn_data else 'N/A'
transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] if sfp_vendor_rev_data else 'N/A'
transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] if sfp_vendor_sn_data else 'N/A'
transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] if sfp_vendor_oui_data else 'N/A'
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"
if self.sfp_type == QSFP_TYPE:
for key in qsfp_cable_length_tup:
if key in sfp_interface_bulk_data['data']:
transceiver_info_dict['cable_type'] = key
transceiver_info_dict['cable_length'] = str(
sfp_interface_bulk_data['data'][key]['value'])
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:
if key in sfp_interface_bulk_data['data']:
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']
transceiver_info_dict['specification_compliance'] = str(
compliance_code_dict)
transceiver_info_dict['nominal_bit_rate'] = str(
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.
========================================================================
"""
# 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')
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_raw, 0)
transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value']
dom_data_raw[start: end], 0)
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(
(offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH)
if dom_voltage_raw is not None:
dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0)
transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value']
if self.dom_volt_supported:
start = QSFP_VOLT_OFFSET - QSFP_DOM_BULK_DATA_START
end = start + QSFP_VOLT_WIDTH
dom_voltage_data = sfpd_obj.parse_voltage(
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(
(offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH)
if dom_channel_monitor_raw is not None:
dom_voltage_data = sfpd_obj.parse_channel_monitor_params(
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']
start = QSFP_CHANNL_MON_OFFSET - QSFP_DOM_BULK_DATA_START
end = start + QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH
dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(
dom_data_raw[start: end], 0)
for key in transceiver_dom_info_dict:
transceiver_dom_info_dict[key] = self._convert_string_to_num(
transceiver_dom_info_dict[key])
if self.dom_tx_power_supported:
transceiver_dom_info_dict['tx1power'] = self.__convert_string_to_num(
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['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.
========================================================================
"""
# 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(
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(
(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:
dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold(
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['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['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']
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])
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.
"""
rx_los = 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)
rx_los = (sffbase().test_bit(data, 1) != 0)
if self.sfp_type == OSFP_TYPE:
return False
elif self.sfp_type == QSFP_TYPE:
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
@ -452,14 +882,32 @@ class Sfp(SfpBase):
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.
"""
tx_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)
tx4_fault = False
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):
"""
@ -469,7 +917,7 @@ class Sfp(SfpBase):
"""
tx_disable = False
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:
data = int(status_control_raw[0], 16)
tx_disable_hard = (sffbase().test_bit(
@ -516,8 +964,8 @@ class Sfp(SfpBase):
Returns:
An integer number of current temperature in Celsius
"""
transceiver_dom_info_dict = self.get_transceiver_bulk_status()
return transceiver_dom_info_dict.get("temperature", "N/A")
transceiver_bulk_status = self.get_transceiver_bulk_status()
return transceiver_bulk_status.get("temperature", "N/A")
def get_voltage(self):
"""
@ -525,8 +973,8 @@ class Sfp(SfpBase):
Returns:
An integer number of supply voltage in mV
"""
transceiver_dom_info_dict = self.get_transceiver_bulk_status()
return transceiver_dom_info_dict.get("voltage", "N/A")
transceiver_bulk_status = self.get_transceiver_bulk_status()
return transceiver_bulk_status.get("voltage", "N/A")
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]
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:
# Set bit 6 for Soft TX Disable Select
# 01000000 = 64 and 10111111 = 191
@ -598,10 +1046,9 @@ class Sfp(SfpBase):
buffer = create_string_buffer(1)
buffer[0] = chr(tx_disable_ctl)
# Write to eeprom
sysfsfile_eeprom.seek(SFP_STATUS_CONTROL_OFFSET)
sysfsfile_eeprom.seek(SFP_CHANNL_STATUS_OFFSET)
sysfsfile_eeprom.write(buffer[0])
except Exception:
#print("Error: unable to open file: %s" % str(e))
return False
finally:
if sysfsfile_eeprom:
@ -656,6 +1103,10 @@ class Sfp(SfpBase):
# SFP doesn't support this feature
return False
##############################################################
###################### Device methods ########################
##############################################################
def get_name(self):
"""
Retrieves the name of the device
@ -700,3 +1151,26 @@ class Sfp(SfpBase):
"""
transceiver_dom_info_dict = self.get_transceiver_info()
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):
"""Platform-specific Thermal class"""
THERMAL_NAME_LIST = []
MAINBOARD_SS_PATH = "/sys/class/i2c-adapter/i2c-11/11-001a/hwmon/hwmon2"
CPUBOARD_SS_PATH = "/sys/class/i2c-adapter/i2c-3/3-001a/hwmon/hwmon1"
SS_CONFIG_PATH = "/usr/share/sonic/device/x86_64-cel_e1031-r0/sensors.conf"
@ -110,9 +109,12 @@ class Thermal(ThermalBase):
self.name = self.get_name()
self.postion = self._thermal_info["postion"]
self.minimum_thermal = self.get_temperature()
self.maximum_thermal = self.get_temperature()
def _get_hwmon_path(self):
hwmon_path = os.path.join(I2C_ADAPTER_PATH, self._thermal_info["i2c_path"])
hwmon_path = os.path.join(
I2C_ADAPTER_PATH, self._thermal_info["i2c_path"])
hwmon_dir = os.listdir(hwmon_path)[0]
return os.path.join(hwmon_path, hwmon_dir)
@ -126,6 +128,17 @@ class Thermal(ThermalBase):
temp_file_path = os.path.join(self._hwmon_path, file_name)
return self._api_common.write_txt_file(temp_file_path, str(temperature))
def _get_threshold(self, file_name):
temp_file_path = os.path.join(self._hwmon_path, file_name)
data = self._api_common.read_txt_file(temp_file_path)
if data:
try:
threshold = float(data)
return round(threshold/1000, 3)
except Exception:
pass
return None
def get_temperature(self):
"""
Retrieves current temperature reading from thermal
@ -144,7 +157,8 @@ class Thermal(ThermalBase):
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
max_crit_key = '{}_max'.format(self._airflow)
return self._thermal_info.get(max_crit_key, None)
high_threshold_file = "temp{}_max".format(self._ss_index)
return self._get_threshold(high_threshold_file) or self._thermal_info.get(max_crit_key, None)
def get_low_threshold(self):
"""
@ -153,7 +167,7 @@ class Thermal(ThermalBase):
A float number, the low threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
return 0.0
return 0.001
def set_high_threshold(self, temperature):
"""
@ -166,8 +180,8 @@ class Thermal(ThermalBase):
"""
temp_file = "temp{}_max".format(self._ss_index)
is_set = self._set_threshold(temp_file, int(temperature*1000))
file_set = False
if is_set:
file_set = True
if is_set and self._api_common.is_host():
try:
with open(self.SS_CONFIG_PATH, 'r+') as f:
content = f.readlines()
@ -215,7 +229,35 @@ class Thermal(ThermalBase):
A float number, the low critical threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
return 0.0
return 0.001
def get_minimum_recorded(self):
"""
Retrieves the minimum recorded temperature of thermal
Returns:
A float number, the minimum recorded temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
tmp = self.get_temperature()
if tmp < self.minimum_thermal:
self.minimum_thermal = tmp
return self.minimum_thermal
def get_maximum_recorded(self):
"""
Retrieves the maximum recorded temperature of thermal
Returns:
A float number, the maximum recorded temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
tmp = self.get_temperature()
if tmp > self.maximum_thermal:
self.maximum_thermal = tmp
return self.maximum_thermal
##############################################################
###################### Device methods ########################
##############################################################
def get_name(self):
"""
@ -267,3 +309,21 @@ class Thermal(ThermalBase):
raw_txt = self._api_common.read_txt_file(fault_file_path)
return int(raw_txt) == 0
def is_replaceable(self):
"""
Retrieves whether thermal module is replaceable
Returns:
A boolean value, True if replaceable, False if not
"""
return False
def get_position_in_parent(self):
"""
Retrieves the thermal position information
Returns:
A int value, 0 represent ASIC thermal, 1 represent CPU thermal info
"""
if self.postion == "cpu":
return 1
return 0

View File

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

View File

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