Edgecore 4630/5835/7326/7816 API2.0 platform support (#10053)
* Initial pass of EdgeCore platform changes. * Remove libevent dependency from lldpd. * Remove python2 dependencies python3.7 force from platform install script. * Include usbmount support changes. * Add missing 4630 install file. * Update a few file permissions. Add umask line to Makefile. Specify python3.9 in install script. * Misc platform updates: - Add missing fan drawer component to sonic_platform - Remove kernel version specification from Makefile - Update to 4630 utility * - Fix file permissions on source files - Fix compile issue with 4630 driver modules (set_fs, get_fs, no longer supported in kernel 5.10) * Fix missing/extra parens in 4630 util script. * Fix indentation in fanutil.py. * Integrate deltas from Edgecore to ec_platform branch. * Installer update from Edgecore to resolve smbus serial console errors. * Update stable_size for warm boot. * Fix SFP dictionary key to match xcvrd. * - Add missing define in event.py files needed for xcvrd - Fix SFP info dict key for 7xxx switches * 5835 platform file updates including installer and 5835 utility. * 5835 fix for DMAR errors on serial console. * Don't skip starting thermalctld in the pmon container. * Revert several changes that were not related to platform. * Run thermalctld in pmon container. * Don't disable thermalctld in the pmon container. * Fix prints/parens in 7816 install utility. * - Incorporate 7816 changes from Edgecore - Fix 7326 driver file using old kernel function * Update kernel modules to use kernel_read(). * Fix compile errors with 7816 and 7326 driver modules. * Fix some indents preventing platform files from loading. * Update 7816 platform sfp dictionary to match field names in xcvrd. * Add missing service and util files for 7816. * Update file names, etc. based on full SKU for 7816. * Delete pddf files not needed. These were causing conflicts with API2.0 implementation. * Remove pddf files suggested by Edgecore that were preventing API2.0 support from starting. * Install API2.0 file instead of pddf. * Update 7326 mac service file to not use pddf. Fix syntax errors in 7326 utility script. * Fix sonic_platform setup file for 7326. * Fix syntax errors in python scripts. * Updates to 7326 platform files. * Fix some tab errors pulled down from master merge. * Remove pddf files that were added from previous merge. * Updates for 5835. * Fix missing command byte for 5835 psu status. * Fix permission bits on 4630 service files. * Update platforms to use new SFP refactoring. * Fix unused var warnings.
This commit is contained in:
parent
52c2a3ad23
commit
ad6200029f
@ -1,4 +1,4 @@
|
||||
stable_size=71303168
|
||||
stable_size=76303168
|
||||
|
||||
#polarity/lanemap is using TH2 style.
|
||||
core_clock_frequency=893
|
||||
|
@ -1,66 +0,0 @@
|
||||
{
|
||||
"XCVR":
|
||||
{
|
||||
"xcvr_present":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap-SFP28": {"1":true, "0":false },
|
||||
"valmap-QSFP28": {"1":true, "0":false}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"PSU":
|
||||
{
|
||||
"psu_present":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": { "1":true, "0":false }
|
||||
}
|
||||
},
|
||||
|
||||
"psu_power_good":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": { "1": true, "0":false }
|
||||
}
|
||||
},
|
||||
|
||||
"psu_fan_dir":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": { "F2B":"EXHAUST", "B2F":"INTAKE" }
|
||||
}
|
||||
},
|
||||
|
||||
"PSU_FAN_MAX_SPEED":"18000"
|
||||
},
|
||||
|
||||
"FAN":
|
||||
{
|
||||
"direction":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": {"1":"EXHAUST", "0":"INTAKE"}
|
||||
}
|
||||
},
|
||||
|
||||
"present":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": {"1":true, "0":false}
|
||||
}
|
||||
},
|
||||
|
||||
"duty_cycle_to_pwm": "lambda dc: ((dc*100.0)/625)",
|
||||
|
||||
"pwm_to_duty_cycle": "lambda pwm: ((pwm*625.0)/100)"
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
__all__ = [ "platform", "chassis", "sfp", "eeprom", "component", "psu", "thermal", "fan", "fan_drawer" ]
|
||||
from . import platform
|
@ -0,0 +1,255 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the Chassis information which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
try:
|
||||
from sonic_platform_base.chassis_base import ChassisBase
|
||||
from .helper import APIHelper
|
||||
from .event import SfpEvent
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
NUM_FAN_TRAY = 3
|
||||
NUM_FAN = 2
|
||||
NUM_PSU = 2
|
||||
NUM_THERMAL = 3
|
||||
PORT_START = 49
|
||||
PORT_END = 54
|
||||
NUM_COMPONENT = 2
|
||||
HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/"
|
||||
PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/"
|
||||
REBOOT_CAUSE_FILE = "reboot-cause.txt"
|
||||
PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt"
|
||||
HOST_CHK_CMD = "which systemctl > /dev/null 2>&1"
|
||||
SYSLED_FNODE = "/sys/class/leds/diag/brightness"
|
||||
SYSLED_MODES = {
|
||||
"0" : "STATUS_LED_COLOR_OFF",
|
||||
"1" : "STATUS_LED_COLOR_GREEN",
|
||||
"2" : "STATUS_LED_COLOR_AMBER",
|
||||
"5" : "STATUS_LED_COLOR_GREEN_BLINK"
|
||||
}
|
||||
|
||||
|
||||
class Chassis(ChassisBase):
|
||||
"""Platform-specific Chassis class"""
|
||||
|
||||
def __init__(self):
|
||||
ChassisBase.__init__(self)
|
||||
self._api_helper = APIHelper()
|
||||
self.is_host = self._api_helper.is_host()
|
||||
|
||||
self.config_data = {}
|
||||
|
||||
self.__initialize_fan()
|
||||
self.__initialize_psu()
|
||||
self.__initialize_thermals()
|
||||
self.__initialize_components()
|
||||
self.__initialize_sfp()
|
||||
self.__initialize_eeprom()
|
||||
|
||||
def __initialize_sfp(self):
|
||||
from sonic_platform.sfp import Sfp
|
||||
for index in range(0, PORT_END):
|
||||
sfp = Sfp(index)
|
||||
self._sfp_list.append(sfp)
|
||||
self._sfpevent = SfpEvent(self._sfp_list)
|
||||
self.sfp_module_initialized = True
|
||||
|
||||
def __initialize_fan(self):
|
||||
from sonic_platform.fan_drawer import FanDrawer
|
||||
for fant_index in range(NUM_FAN_TRAY):
|
||||
fandrawer = FanDrawer(fant_index)
|
||||
self._fan_drawer_list.append(fandrawer)
|
||||
self._fan_list.extend(fandrawer._fan_list)
|
||||
|
||||
def __initialize_psu(self):
|
||||
from sonic_platform.psu import Psu
|
||||
for index in range(0, NUM_PSU):
|
||||
psu = Psu(index)
|
||||
self._psu_list.append(psu)
|
||||
|
||||
def __initialize_thermals(self):
|
||||
from sonic_platform.thermal import Thermal
|
||||
for index in range(0, NUM_THERMAL):
|
||||
thermal = Thermal(index)
|
||||
self._thermal_list.append(thermal)
|
||||
|
||||
def __initialize_eeprom(self):
|
||||
from sonic_platform.eeprom import Tlv
|
||||
self._eeprom = Tlv()
|
||||
|
||||
def __initialize_components(self):
|
||||
from sonic_platform.component import Component
|
||||
for index in range(0, NUM_COMPONENT):
|
||||
component = Component(index)
|
||||
self._component_list.append(component)
|
||||
|
||||
def __initialize_watchdog(self):
|
||||
from sonic_platform.watchdog import Watchdog
|
||||
self._watchdog = Watchdog()
|
||||
|
||||
|
||||
def __is_host(self):
|
||||
return os.system(HOST_CHK_CMD) == 0
|
||||
|
||||
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 get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
|
||||
return self._eeprom.get_product_name()
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the Chassis
|
||||
Returns:
|
||||
bool: True if Chassis is present, False if not
|
||||
"""
|
||||
return True
|
||||
|
||||
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_base_mac(self):
|
||||
"""
|
||||
Retrieves the base MAC address for the chassis
|
||||
Returns:
|
||||
A string containing the MAC address in the format
|
||||
'XX:XX:XX:XX:XX:XX'
|
||||
"""
|
||||
return self._eeprom.get_mac()
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the device
|
||||
Returns:
|
||||
string: Model/part number of device
|
||||
"""
|
||||
return self._eeprom.get_pn()
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the hardware serial number for the chassis
|
||||
Returns:
|
||||
A string containing the hardware serial number for this chassis.
|
||||
"""
|
||||
return self._eeprom.get_serial()
|
||||
|
||||
def get_system_eeprom_info(self):
|
||||
"""
|
||||
Retrieves the full content of system EEPROM information for the chassis
|
||||
Returns:
|
||||
A dictionary where keys are the type code defined in
|
||||
OCP ONIE TlvInfo EEPROM format and values are their corresponding
|
||||
values.
|
||||
"""
|
||||
return self._eeprom.get_eeprom()
|
||||
|
||||
def get_reboot_cause(self):
|
||||
"""
|
||||
Retrieves the cause of the previous reboot
|
||||
|
||||
Returns:
|
||||
A tuple (string, string) where the first element is a string
|
||||
containing the cause of the previous reboot. This string must be
|
||||
one of the predefined strings in this class. If the first string
|
||||
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
|
||||
to pass a description of the reboot cause.
|
||||
"""
|
||||
|
||||
reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE)
|
||||
sw_reboot_cause = self._api_helper.read_txt_file(
|
||||
reboot_cause_path) or "Unknown"
|
||||
|
||||
|
||||
return ('REBOOT_CAUSE_NON_HARDWARE', sw_reboot_cause)
|
||||
|
||||
def get_change_event(self, timeout=0):
|
||||
# SFP event
|
||||
if not self.sfp_module_initialized:
|
||||
self.__initialize_sfp()
|
||||
|
||||
return self._sfpevent.get_sfp_event(timeout)
|
||||
|
||||
def get_sfp(self, index):
|
||||
"""
|
||||
Retrieves sfp represented by (1-based) index <index>
|
||||
Args:
|
||||
index: An integer, the index (1-based) of the sfp to retrieve.
|
||||
The index should be the sequence of a physical port in a chassis,
|
||||
starting from 1.
|
||||
For example, 1 for Ethernet0, 2 for Ethernet4 and so on.
|
||||
Returns:
|
||||
An object dervied from SfpBase representing the specified sfp
|
||||
"""
|
||||
sfp = None
|
||||
if not self.sfp_module_initialized:
|
||||
self.__initialize_sfp()
|
||||
|
||||
try:
|
||||
# The index will start from 1
|
||||
sfp = self._sfp_list[index-1]
|
||||
except IndexError:
|
||||
sys.stderr.write("SFP index {} out of range (1-{})\n".format(
|
||||
index, len(self._sfp_list)))
|
||||
return sfp
|
||||
|
||||
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 initizalize_system_led(self):
|
||||
return True
|
||||
|
||||
def get_status_led(self):
|
||||
val = self._api_helper.read_txt_file(SYSLED_FNODE)
|
||||
return SYSLED_MODES[val] if val in SYSLED_MODES else "UNKNOWN"
|
||||
|
||||
def set_status_led(self, color):
|
||||
mode = None
|
||||
for key, val in SYSLED_MODES.items():
|
||||
if val == color:
|
||||
mode = key
|
||||
break
|
||||
if mode is None:
|
||||
return False
|
||||
else:
|
||||
return self._api_helper.write_txt_file(SYSLED_FNODE, mode)
|
||||
|
@ -0,0 +1,172 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Component contains an implementation of SONiC Platform Base API and
|
||||
# provides the components firmware management function
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
import shlex
|
||||
import subprocess
|
||||
|
||||
|
||||
try:
|
||||
from sonic_platform_base.component_base import ComponentBase
|
||||
from .helper import APIHelper
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
CPLD_ADDR_MAPPING = {
|
||||
"CPLD1": "3-0060"
|
||||
}
|
||||
SYSFS_PATH = "/sys/bus/i2c/devices/"
|
||||
BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version"
|
||||
COMPONENT_LIST= [
|
||||
("CPLD1", "CPLD 1"),
|
||||
("BIOS", "Basic Input/Output System")
|
||||
|
||||
]
|
||||
|
||||
class Component(ComponentBase):
|
||||
"""Platform-specific Component class"""
|
||||
|
||||
DEVICE_TYPE = "component"
|
||||
|
||||
def __init__(self, component_index=0):
|
||||
self._api_helper=APIHelper()
|
||||
ComponentBase.__init__(self)
|
||||
self.index = component_index
|
||||
self.name = self.get_name()
|
||||
|
||||
def __run_command(self, command):
|
||||
# Run bash command and print output to stdout
|
||||
try:
|
||||
process = subprocess.Popen(
|
||||
shlex.split(command), stdout=subprocess.PIPE)
|
||||
while True:
|
||||
output = process.stdout.readline()
|
||||
if output == '' and process.poll() is not None:
|
||||
break
|
||||
rc = process.poll()
|
||||
if rc != 0:
|
||||
return False
|
||||
except Exception:
|
||||
return False
|
||||
return True
|
||||
|
||||
def __get_bios_version(self):
|
||||
# Retrieves the BIOS firmware version
|
||||
try:
|
||||
with open(BIOS_VERSION_PATH, 'r') as fd:
|
||||
bios_version = fd.read()
|
||||
return bios_version.strip()
|
||||
except Exception as e:
|
||||
return None
|
||||
|
||||
def __get_cpld_version(self):
|
||||
# Retrieves the CPLD firmware version
|
||||
cpld_version = dict()
|
||||
for cpld_name in CPLD_ADDR_MAPPING:
|
||||
try:
|
||||
cpld_path = "{}{}{}".format(SYSFS_PATH, CPLD_ADDR_MAPPING[cpld_name], '/version')
|
||||
cpld_version_raw= self._api_helper.read_txt_file(cpld_path)
|
||||
cpld_version[cpld_name] = "{}".format(int(cpld_version_raw,16))
|
||||
except Exception as e:
|
||||
print('Get exception when read cpld')
|
||||
cpld_version[cpld_name] = 'None'
|
||||
|
||||
return cpld_version
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the component
|
||||
Returns:
|
||||
A string containing the name of the component
|
||||
"""
|
||||
return COMPONENT_LIST[self.index][0]
|
||||
|
||||
def get_description(self):
|
||||
"""
|
||||
Retrieves the description of the component
|
||||
Returns:
|
||||
A string containing the description of the component
|
||||
"""
|
||||
return COMPONENT_LIST[self.index][1]
|
||||
|
||||
|
||||
def get_firmware_version(self):
|
||||
"""
|
||||
Retrieves the firmware version of module
|
||||
Returns:
|
||||
string: The firmware versions of the module
|
||||
"""
|
||||
fw_version = None
|
||||
if self.name == "BIOS":
|
||||
fw_version = self.__get_bios_version()
|
||||
elif "CPLD" in self.name:
|
||||
cpld_version = self.__get_cpld_version()
|
||||
fw_version = cpld_version.get(self.name)
|
||||
|
||||
return fw_version
|
||||
|
||||
def install_firmware(self, image_path):
|
||||
"""
|
||||
Install firmware to module
|
||||
Args:
|
||||
image_path: A string, path to firmware image
|
||||
Returns:
|
||||
A boolean, True if install successfully, False if not
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the device
|
||||
Returns:
|
||||
bool: True if device 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
|
@ -0,0 +1,134 @@
|
||||
try:
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
if sys.version_info[0] >= 3:
|
||||
from io import StringIO
|
||||
else:
|
||||
from cStringIO import StringIO
|
||||
|
||||
from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo
|
||||
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):
|
||||
|
||||
EEPROM_DECODE_HEADLINES = 6
|
||||
|
||||
def __init__(self):
|
||||
self._eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom"
|
||||
super(Tlv, self).__init__(self._eeprom_path, 0, '', True)
|
||||
self._eeprom = self._load_eeprom()
|
||||
|
||||
def __parse_output(self, decode_output):
|
||||
decode_output.replace('\0', '')
|
||||
lines = decode_output.split('\n')
|
||||
lines = lines[self.EEPROM_DECODE_HEADLINES:]
|
||||
_eeprom_info_dict = dict()
|
||||
|
||||
for line in lines:
|
||||
try:
|
||||
match = re.search(
|
||||
'(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line)
|
||||
if match is not None:
|
||||
idx = match.group(1)
|
||||
value = match.group(3).rstrip('\0')
|
||||
|
||||
_eeprom_info_dict[idx] = value
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return _eeprom_info_dict
|
||||
|
||||
def _load_eeprom(self):
|
||||
original_stdout = sys.stdout
|
||||
sys.stdout = StringIO()
|
||||
try:
|
||||
self.read_eeprom_db()
|
||||
except Exception:
|
||||
decode_output = sys.stdout.getvalue()
|
||||
sys.stdout = original_stdout
|
||||
return self.__parse_output(decode_output)
|
||||
|
||||
status = self.check_status()
|
||||
if 'ok' not in status:
|
||||
return False
|
||||
|
||||
if not os.path.exists(CACHE_ROOT):
|
||||
try:
|
||||
os.makedirs(CACHE_ROOT)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
#
|
||||
# only the eeprom classes that inherit from eeprom_base
|
||||
# support caching. Others will work normally
|
||||
#
|
||||
try:
|
||||
self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
e = self.read_eeprom()
|
||||
if e is None:
|
||||
return 0
|
||||
|
||||
try:
|
||||
self.update_cache(e)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self.decode_eeprom(e)
|
||||
decode_output = sys.stdout.getvalue()
|
||||
sys.stdout = original_stdout
|
||||
|
||||
(is_valid, valid_crc) = self.is_checksum_valid(e)
|
||||
if not is_valid:
|
||||
return False
|
||||
|
||||
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._valid_tlv(self._eeprom)
|
||||
|
||||
def get_pn(self):
|
||||
return self._eeprom.get('0x22', NULL)
|
||||
|
||||
def get_serial(self):
|
||||
return self._eeprom.get('0x23', NULL)
|
||||
|
||||
def get_mac(self):
|
||||
return self._eeprom.get('0x24', NULL)
|
||||
|
||||
def get_product_name(self):
|
||||
return self._eeprom.get('0x21', NULL)
|
@ -0,0 +1,63 @@
|
||||
try:
|
||||
import time
|
||||
from .helper import APIHelper
|
||||
from sonic_py_common.logger import Logger
|
||||
except ImportError as e:
|
||||
raise ImportError(repr(e) + " - required module not found")
|
||||
|
||||
POLL_INTERVAL_IN_SEC = 1
|
||||
|
||||
class SfpEvent:
|
||||
''' Listen to insert/remove sfp events '''
|
||||
|
||||
def __init__(self, sfp_list):
|
||||
self._api_helper = APIHelper()
|
||||
self._sfp_list = sfp_list
|
||||
self._logger = Logger()
|
||||
self._sfp_change_event_data = {'present': 0}
|
||||
|
||||
def get_presence_bitmap(self):
|
||||
bitmap = 0
|
||||
for sfp in self._sfp_list:
|
||||
modpres = sfp.get_presence()
|
||||
i=sfp.port_num-1
|
||||
if modpres:
|
||||
bitmap = bitmap | (1 << i)
|
||||
return bitmap
|
||||
|
||||
def get_sfp_event(self, timeout=2000):
|
||||
#now = time.time()
|
||||
port_dict = {}
|
||||
change_dict = {}
|
||||
change_dict['sfp'] = port_dict
|
||||
|
||||
if timeout < 1000:
|
||||
cd_ms = 1000
|
||||
else:
|
||||
cd_ms = timeout
|
||||
|
||||
while cd_ms > 0:
|
||||
bitmap = self.get_presence_bitmap()
|
||||
changed_ports = self._sfp_change_event_data['present'] ^ bitmap
|
||||
if changed_ports != 0:
|
||||
break
|
||||
time.sleep(POLL_INTERVAL_IN_SEC)
|
||||
# timeout=0 means wait for event forever
|
||||
if timeout != 0:
|
||||
cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000
|
||||
|
||||
if changed_ports != 0:
|
||||
for sfp in self._sfp_list:
|
||||
i=sfp.port_num-1
|
||||
if (changed_ports & (1 << i)):
|
||||
if (bitmap & (1 << i)) == 0:
|
||||
port_dict[i+1] = '0'
|
||||
else:
|
||||
port_dict[i+1] = '1'
|
||||
|
||||
|
||||
# Update the cache dict
|
||||
self._sfp_change_event_data['present'] = bitmap
|
||||
return True, change_dict
|
||||
else:
|
||||
return True, change_dict
|
284
device/accton/x86_64-accton_as4630_54pe-r0/sonic_platform/fan.py
Normal file
284
device/accton/x86_64-accton_as4630_54pe-r0/sonic_platform/fan.py
Normal file
@ -0,0 +1,284 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the fan status which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
|
||||
|
||||
try:
|
||||
from sonic_platform_base.fan_base import FanBase
|
||||
from .helper import APIHelper
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
PSU_FAN_MAX_RPM = 26688
|
||||
SPEED_TOLERANCE = 15
|
||||
CPLD_FAN_I2C_PATH = "/sys/bus/i2c/devices/3-0060/fan_"
|
||||
I2C_PATH ="/sys/bus/i2c/devices/{}-00{}/"
|
||||
PSU_HWMON_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 10,
|
||||
"addr": "58"
|
||||
},
|
||||
1: {
|
||||
"num": 11,
|
||||
"addr": "59"
|
||||
},
|
||||
}
|
||||
|
||||
PSU_CPLD_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 10,
|
||||
"addr": "50"
|
||||
},
|
||||
1: {
|
||||
"num": 11,
|
||||
"addr": "51"
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R",
|
||||
"FAN-3F", "FAN-3R"]
|
||||
|
||||
class Fan(FanBase):
|
||||
"""Platform-specific Fan class"""
|
||||
|
||||
def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0):
|
||||
self._api_helper=APIHelper()
|
||||
self.fan_index = fan_index
|
||||
self.fan_tray_index = fan_tray_index
|
||||
self.is_psu_fan = is_psu_fan
|
||||
|
||||
if self.is_psu_fan:
|
||||
self.psu_index = psu_index
|
||||
self.psu_i2c_num = PSU_HWMON_I2C_MAPPING[self.psu_index]['num']
|
||||
self.psu_i2c_addr = PSU_HWMON_I2C_MAPPING[self.psu_index]['addr']
|
||||
self.psu_hwmon_path = I2C_PATH.format(
|
||||
self.psu_i2c_num, self.psu_i2c_addr)
|
||||
|
||||
self.psu_i2c_num = PSU_CPLD_I2C_MAPPING[self.psu_index]['num']
|
||||
self.psu_i2c_addr = PSU_CPLD_I2C_MAPPING[self.psu_index]['addr']
|
||||
self.psu_cpld_path = I2C_PATH.format(
|
||||
self.psu_i2c_num, self.psu_i2c_addr)
|
||||
|
||||
FanBase.__init__(self)
|
||||
|
||||
|
||||
def get_direction(self):
|
||||
"""
|
||||
Retrieves the direction of fan
|
||||
Returns:
|
||||
A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST
|
||||
depending on fan direction
|
||||
"""
|
||||
if not self.is_psu_fan:
|
||||
dir_str = "{}{}{}".format(CPLD_FAN_I2C_PATH, 'direction_', self.fan_tray_index+1)
|
||||
val=self._api_helper.read_txt_file(dir_str)
|
||||
if val is not None:
|
||||
if int(val, 10)==0:#F2B
|
||||
direction=self.FAN_DIRECTION_EXHAUST
|
||||
else:
|
||||
direction=self.FAN_DIRECTION_INTAKE
|
||||
else:
|
||||
direction=self.FAN_DIRECTION_EXHAUST
|
||||
|
||||
else: #For PSU
|
||||
dir_str = "{}{}".format(self.psu_hwmon_path,'psu_fan_dir')
|
||||
val=self._api_helper.read_txt_file(dir_str)
|
||||
if val is not None:
|
||||
if val=='F2B':
|
||||
direction=self.FAN_DIRECTION_EXHAUST
|
||||
else:
|
||||
direction=self.FAN_DIRECTION_INTAKE
|
||||
else:
|
||||
direction=self.FAN_DIRECTION_EXHAUST
|
||||
|
||||
return direction
|
||||
|
||||
def get_speed(self):
|
||||
"""
|
||||
Retrieves the speed of fan as a percentage of full speed
|
||||
Returns:
|
||||
An integer, the percentage of full fan speed, in the range 0 (off)
|
||||
to 100 (full speed)
|
||||
|
||||
"""
|
||||
speed = 0
|
||||
if self.is_psu_fan:
|
||||
psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_speed_rpm')
|
||||
fan_speed_rpm = self._api_helper.read_txt_file(psu_fan_path)
|
||||
if fan_speed_rpm is not None:
|
||||
speed = (int(fan_speed_rpm,10))*100/26688
|
||||
if speed > 100:
|
||||
speed=100
|
||||
else:
|
||||
return 0
|
||||
elif self.get_presence():
|
||||
speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, 'duty_cycle_percentage')
|
||||
speed=self._api_helper.read_txt_file(speed_path)
|
||||
if speed is None:
|
||||
return 0
|
||||
return int(speed)
|
||||
|
||||
def get_target_speed(self):
|
||||
"""
|
||||
Retrieves the target (expected) speed of the fan
|
||||
Returns:
|
||||
An integer, the percentage of full fan speed, in the range 0 (off)
|
||||
to 100 (full speed)
|
||||
|
||||
Note:
|
||||
speed_pc = pwm_target/255*100
|
||||
|
||||
0 : when PWM mode is use
|
||||
pwm : when pwm mode is not use
|
||||
"""
|
||||
return self.get_speed()
|
||||
|
||||
def get_speed_tolerance(self):
|
||||
"""
|
||||
Retrieves the speed tolerance of the fan
|
||||
Returns:
|
||||
An integer, the percentage of variance from target speed which is
|
||||
considered tolerable
|
||||
"""
|
||||
return SPEED_TOLERANCE
|
||||
|
||||
def set_speed(self, speed):
|
||||
"""
|
||||
Sets the fan speed
|
||||
Args:
|
||||
speed: An integer, the percentage of full fan speed to set fan to,
|
||||
in the range 0 (off) to 100 (full speed)
|
||||
Returns:
|
||||
A boolean, True if speed is set successfully, False if not
|
||||
|
||||
"""
|
||||
|
||||
if not self.is_psu_fan and self.get_presence():
|
||||
speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, 'duty_cycle_percentage')
|
||||
return self._api_helper.write_txt_file(speed_path, int(speed))
|
||||
|
||||
return False
|
||||
|
||||
def set_status_led(self, color):
|
||||
"""
|
||||
Sets the state of the fan module status LED
|
||||
Args:
|
||||
color: A string representing the color with which to set the
|
||||
fan module status LED
|
||||
Returns:
|
||||
bool: True if status LED state is set successfully, False if not
|
||||
"""
|
||||
return False #Not supported
|
||||
|
||||
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
|
||||
"""
|
||||
status=self.get_presence()
|
||||
if status is None:
|
||||
return self.STATUS_LED_COLOR_OFF
|
||||
|
||||
return {
|
||||
1: self.STATUS_LED_COLOR_GREEN,
|
||||
0: self.STATUS_LED_COLOR_RED
|
||||
}.get(status, self.STATUS_LED_COLOR_OFF)
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
fan_name = FAN_NAME_LIST[self.fan_tray_index*2 + self.fan_index] \
|
||||
if not self.is_psu_fan \
|
||||
else "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1)
|
||||
|
||||
return fan_name
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the FAN
|
||||
Returns:
|
||||
bool: True if FAN is present, False if not
|
||||
"""
|
||||
|
||||
|
||||
if self.is_psu_fan:
|
||||
present_path="{}{}".format(self.psu_cpld_path, 'psu_present')
|
||||
else:
|
||||
present_path = "{}{}{}".format(CPLD_FAN_I2C_PATH, 'present_', self.fan_tray_index+1)
|
||||
|
||||
val=self._api_helper.read_txt_file(present_path)
|
||||
if val is not None:
|
||||
return int(val, 10)==1
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the device
|
||||
Returns:
|
||||
A boolean value, True if device is operating properly, False if not
|
||||
"""
|
||||
if self.is_psu_fan:
|
||||
psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_fault')
|
||||
val=self._api_helper.read_txt_file(psu_fan_path)
|
||||
if val is not None:
|
||||
return int(val, 10)==0
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
path = "{}{}{}".format(CPLD_FAN_I2C_PATH, 'fault_', self.fan_tray_index+1)
|
||||
val=self._api_helper.read_txt_file(path)
|
||||
if val is not None:
|
||||
return int(val, 10)==0
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
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_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_index+1) \
|
||||
if not self.is_psu_fan else (self.psu_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
|
||||
|
@ -0,0 +1,90 @@
|
||||
########################################################################
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides 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")
|
||||
|
||||
FANS_PER_FANTRAY = 2
|
||||
|
||||
|
||||
class FanDrawer(FanDrawerBase):
|
||||
"""Platform-specific Fan class"""
|
||||
|
||||
def __init__(self, fantray_index):
|
||||
|
||||
FanDrawerBase.__init__(self)
|
||||
# FanTray is 0-based in platforms
|
||||
self.fantrayindex = fantray_index
|
||||
self.__initialize_fan_drawer()
|
||||
|
||||
|
||||
def __initialize_fan_drawer(self):
|
||||
from sonic_platform.fan import Fan
|
||||
for i in range(FANS_PER_FANTRAY):
|
||||
self._fan_list.append(Fan(self.fantrayindex, i))
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the fan drawer name
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
return "FanTray{}".format(self.fantrayindex+1)
|
||||
|
||||
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.
|
||||
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.fantrayindex+1)
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return True
|
@ -0,0 +1,117 @@
|
||||
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, 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', errors='replace') as fd:
|
||||
data = fd.read()
|
||||
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 IOError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def ipmi_raw(self, netfn, cmd):
|
||||
status = True
|
||||
result = ""
|
||||
try:
|
||||
cmd = "ipmitool raw {} {}".format(str(netfn), str(cmd))
|
||||
p = subprocess.Popen(
|
||||
cmd, shell=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, 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, 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
|
@ -0,0 +1,21 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the platform information
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
from sonic_platform_base.platform_base import PlatformBase
|
||||
from sonic_platform.chassis import Chassis
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Platform(PlatformBase):
|
||||
"""Platform-specific Platform class"""
|
||||
|
||||
def __init__(self):
|
||||
PlatformBase.__init__(self)
|
||||
self._chassis = Chassis()
|
269
device/accton/x86_64-accton_as4630_54pe-r0/sonic_platform/psu.py
Normal file
269
device/accton/x86_64-accton_as4630_54pe-r0/sonic_platform/psu.py
Normal file
@ -0,0 +1,269 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the PSUs status which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
#import sonic_platform
|
||||
|
||||
try:
|
||||
from sonic_platform_base.psu_base import PsuBase
|
||||
from .helper import APIHelper
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
I2C_PATH ="/sys/bus/i2c/devices/{0}-00{1}/"
|
||||
|
||||
PSU_NAME_LIST = ["PSU-1", "PSU-2"]
|
||||
PSU_NUM_FAN = [1, 1]
|
||||
PSU_HWMON_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 10,
|
||||
"addr": "58"
|
||||
},
|
||||
1: {
|
||||
"num": 11,
|
||||
"addr": "59"
|
||||
},
|
||||
}
|
||||
|
||||
PSU_CPLD_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 10,
|
||||
"addr": "50"
|
||||
},
|
||||
1: {
|
||||
"num": 11,
|
||||
"addr": "51"
|
||||
},
|
||||
}
|
||||
|
||||
class Psu(PsuBase):
|
||||
"""Platform-specific Psu class"""
|
||||
|
||||
def __init__(self, psu_index=0):
|
||||
PsuBase.__init__(self)
|
||||
self.index = psu_index
|
||||
self._api_helper = APIHelper()
|
||||
|
||||
self.i2c_num = PSU_HWMON_I2C_MAPPING[self.index]["num"]
|
||||
self.i2c_addr = PSU_HWMON_I2C_MAPPING[self.index]["addr"]
|
||||
self.hwmon_path = I2C_PATH.format(self.i2c_num, self.i2c_addr)
|
||||
|
||||
self.i2c_num = PSU_CPLD_I2C_MAPPING[self.index]["num"]
|
||||
self.i2c_addr = PSU_CPLD_I2C_MAPPING[self.index]["addr"]
|
||||
self.cpld_path = I2C_PATH.format(self.i2c_num, self.i2c_addr)
|
||||
self.__initialize_fan()
|
||||
|
||||
def __initialize_fan(self):
|
||||
from sonic_platform.fan import Fan
|
||||
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)
|
||||
|
||||
def get_voltage(self):
|
||||
"""
|
||||
Retrieves current PSU voltage output
|
||||
Returns:
|
||||
A float number, the output voltage in volts,
|
||||
e.g. 12.1
|
||||
"""
|
||||
vout_path = "{}{}".format(self.hwmon_path, 'psu_v_out')
|
||||
vout_val=self._api_helper.read_txt_file(vout_path)
|
||||
if vout_val is not None:
|
||||
return float(vout_val)/ 1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_current(self):
|
||||
"""
|
||||
Retrieves present electric current supplied by PSU
|
||||
Returns:
|
||||
A float number, the electric current in amperes, e.g 15.4
|
||||
"""
|
||||
iout_path = "{}{}".format(self.hwmon_path, 'psu_i_out')
|
||||
val=self._api_helper.read_txt_file(iout_path)
|
||||
if val is not None:
|
||||
return float(val)/1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_power(self):
|
||||
"""
|
||||
Retrieves current energy supplied by PSU
|
||||
Returns:
|
||||
A float number, the power in watts, e.g. 302.6
|
||||
"""
|
||||
pout_path = "{}{}".format(self.hwmon_path, 'psu_p_out')
|
||||
val=self._api_helper.read_txt_file(pout_path)
|
||||
if val is not None:
|
||||
return float(val)/1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_powergood_status(self):
|
||||
"""
|
||||
Retrieves the powergood status of PSU
|
||||
Returns:
|
||||
A boolean, True if PSU has stablized its output voltages and passed all
|
||||
its internal self-tests, False if not.
|
||||
"""
|
||||
return self.get_status()
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
return False #Controlled by HW
|
||||
|
||||
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.get_status()
|
||||
if status is None:
|
||||
return self.STATUS_LED_COLOR_OFF
|
||||
|
||||
return {
|
||||
1: self.STATUS_LED_COLOR_GREEN,
|
||||
0: self.STATUS_LED_COLOR_RED
|
||||
}.get(status, self.STATUS_LED_COLOR_OFF)
|
||||
|
||||
|
||||
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
|
||||
"""
|
||||
temp_path = "{}{}".format(self.hwmon_path, 'psu_temp1_input')
|
||||
val=self._api_helper.read_txt_file(temp_path)
|
||||
if val is not None:
|
||||
return float(val)/1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_temperature_high_threshold(self):
|
||||
"""
|
||||
Retrieves the high threshold temperature of PSU
|
||||
Returns:
|
||||
A float number, the high threshold temperature of PSU in Celsius
|
||||
up to nearest thousandth of one degree Celsius, e.g. 30.125
|
||||
"""
|
||||
return False #Not supported
|
||||
|
||||
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
|
||||
"""
|
||||
vout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_vout_max')
|
||||
vout_val=self._api_helper.read_txt_file(vout_path)
|
||||
if vout_val is not None:
|
||||
return float(vout_val)/ 1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
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
|
||||
"""
|
||||
vout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_vout_min')
|
||||
vout_val=self._api_helper.read_txt_file(vout_path)
|
||||
if vout_val is not None:
|
||||
return float(vout_val)/ 1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
return PSU_NAME_LIST[self.index]
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the PSU
|
||||
Returns:
|
||||
bool: True if PSU is present, False if not
|
||||
"""
|
||||
presence_path="{}{}".format(self.cpld_path, 'psu_present')
|
||||
val=self._api_helper.read_txt_file(presence_path)
|
||||
if val is not None:
|
||||
return int(val, 10) == 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the device
|
||||
Returns:
|
||||
A boolean value, True if device is operating properly, False if not
|
||||
"""
|
||||
power_path="{}{}".format(self.cpld_path, 'psu_power_good')
|
||||
val=self._api_helper.read_txt_file(power_path)
|
||||
if val is not None:
|
||||
return int(val, 10) == 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the device
|
||||
Returns:
|
||||
string: Model/part number of device
|
||||
"""
|
||||
model_path="{}{}".format(self.cpld_path, 'psu_model_name')
|
||||
model=self._api_helper.read_txt_file(model_path)
|
||||
if model is None:
|
||||
return "N/A"
|
||||
|
||||
return model
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the device
|
||||
Returns:
|
||||
string: Serial number of device
|
||||
"""
|
||||
serial_path="{}{}".format(self.cpld_path, 'psu_serial_number')
|
||||
serial=self._api_helper.read_txt_file(serial_path)
|
||||
if serial is None:
|
||||
return "N/A"
|
||||
return serial
|
||||
|
||||
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.index+1
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return True
|
484
device/accton/x86_64-accton_as4630_54pe-r0/sonic_platform/sfp.py
Normal file
484
device/accton/x86_64-accton_as4630_54pe-r0/sonic_platform/sfp.py
Normal file
@ -0,0 +1,484 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Sfp contains an implementation of SONiC Platform Base API and
|
||||
# provides the sfp device status which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
import os
|
||||
import time
|
||||
import sys
|
||||
|
||||
from ctypes import create_string_buffer
|
||||
|
||||
try:
|
||||
from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase
|
||||
from .helper import APIHelper
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
CPLD_I2C_PATH = "/sys/bus/i2c/devices/3-0060/"
|
||||
|
||||
class Sfp(SfpOptoeBase):
|
||||
"""Platform-specific Sfp class"""
|
||||
|
||||
# Port number
|
||||
PORT_START = 49
|
||||
PORT_END = 54
|
||||
|
||||
# Path to sysfs
|
||||
PLATFORM_ROOT_PATH = "/usr/share/sonic/device"
|
||||
PMON_HWSKU_PATH = "/usr/share/sonic/hwsku"
|
||||
HOST_CHK_CMD = "which systemctl > /dev/null 2>&1"
|
||||
|
||||
PLATFORM = "x86_64-accton_as4630_54pe-r0"
|
||||
HWSKU = "Accton-AS4630-54PE"
|
||||
|
||||
_port_to_i2c_mapping = {
|
||||
49: 18,
|
||||
50: 19,
|
||||
51: 20,
|
||||
52: 21,
|
||||
53: 22,
|
||||
54: 23,
|
||||
}
|
||||
|
||||
def __init__(self, sfp_index=0):
|
||||
SfpOptoeBase.__init__(self)
|
||||
self._api_helper=APIHelper()
|
||||
# Init index
|
||||
self.index = sfp_index
|
||||
self.port_num = self.index + 1
|
||||
# Init eeprom path
|
||||
eeprom_path = '/sys/bus/i2c/devices/{0}-0050/eeprom'
|
||||
self.port_to_eeprom_mapping = {}
|
||||
for x in range(self.PORT_START, self.PORT_END + 1):
|
||||
self.port_to_eeprom_mapping[x] = eeprom_path.format(self._port_to_i2c_mapping[x])
|
||||
|
||||
def get_eeprom_path(self):
|
||||
return self.port_to_eeprom_mapping[self.port_num]
|
||||
|
||||
def __is_host(self):
|
||||
return os.system(self.HOST_CHK_CMD) == 0
|
||||
|
||||
def __get_path_to_port_config_file(self):
|
||||
platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM])
|
||||
hwsku_path = "/".join([platform_path, self.HWSKU]
|
||||
) if self.__is_host() else self.PMON_HWSKU_PATH
|
||||
return "/".join([hwsku_path, "port_config.ini"])
|
||||
|
||||
def __read_eeprom_specific_bytes(self, offset, num_bytes):
|
||||
sysfsfile_eeprom = None
|
||||
eeprom_raw = []
|
||||
for i in range(0, num_bytes):
|
||||
eeprom_raw.append("0x00")
|
||||
|
||||
sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num]
|
||||
try:
|
||||
sysfsfile_eeprom = open(
|
||||
sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0)
|
||||
sysfsfile_eeprom.seek(offset)
|
||||
raw = sysfsfile_eeprom.read(num_bytes)
|
||||
if sys.version_info[0] >= 3:
|
||||
for n in range(0, num_bytes):
|
||||
eeprom_raw[n] = hex(raw[n])[2:].zfill(2)
|
||||
else:
|
||||
for n in range(0, num_bytes):
|
||||
eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2)
|
||||
except Exception:
|
||||
pass
|
||||
finally:
|
||||
if sysfsfile_eeprom:
|
||||
sysfsfile_eeprom.close()
|
||||
|
||||
return eeprom_raw
|
||||
|
||||
def get_reset_status(self):
|
||||
"""
|
||||
Retrieves the reset status of SFP
|
||||
Returns:
|
||||
A Boolean, True if reset enabled, False if disabled
|
||||
"""
|
||||
if self.port_num < 53: #Copper port and sfp ports are suported.
|
||||
return False
|
||||
|
||||
reset_path="{}{}{}".format(CPLD_I2C_PATH , "module_reset_" , str(self.port_num))
|
||||
val = self._api_helper.read_txt_file(reset_path)
|
||||
|
||||
if val is not None:
|
||||
return int(val, 10) == 1
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_rx_los(self):
|
||||
"""
|
||||
Retrieves the RX LOS (lost-of-signal) status of SFP
|
||||
Returns:
|
||||
A Boolean, True if SFP has RX LOS, False if not.
|
||||
Note : RX LOS status is latched until a call to get_rx_los or a reset.
|
||||
"""
|
||||
rx_los = False
|
||||
|
||||
if self.port_num < 49: #Copper port, no sysfs
|
||||
return False
|
||||
|
||||
if self.port_num < 53:
|
||||
rx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_rx_los_', self.port_num)
|
||||
rx_los=self._api_helper.read_txt_file(rx_path)
|
||||
if rx_los is None:
|
||||
return False
|
||||
else:
|
||||
rx_los_list = []
|
||||
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
|
||||
QSFP_CHANNL_RX_LOS_STATUS_OFFSET, QSFP_CHANNL_RX_LOS_STATUS_WIDTH) if self.get_presence() else None
|
||||
if dom_channel_monitor_raw is not None:
|
||||
rx_los_data = int(dom_channel_monitor_raw[0], 16)
|
||||
rx_los_list.append(rx_los_data & 0x01 != 0)
|
||||
rx_los_list.append(rx_los_data & 0x02 != 0)
|
||||
rx_los_list.append(rx_los_data & 0x04 != 0)
|
||||
rx_los_list.append(rx_los_data & 0x08 != 0)
|
||||
rx_los = rx_los_list[0] and rx_los_list[1] and rx_los_list[2] and rx_los_list[3]
|
||||
return rx_los
|
||||
|
||||
def get_tx_fault(self):
|
||||
"""
|
||||
Retrieves the TX fault status of SFP
|
||||
Returns:
|
||||
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
|
||||
if self.port_num < 49: #Copper port, no sysfs
|
||||
return False
|
||||
|
||||
if self.port_num < 53:
|
||||
tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_fault_', self.port_num)
|
||||
tx_fault=self._api_helper.read_txt_file(tx_path)
|
||||
if tx_fault is None:
|
||||
return False
|
||||
else:
|
||||
tx_fault_list = []
|
||||
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
|
||||
QSFP_CHANNL_TX_FAULT_STATUS_OFFSET, QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) if self.get_presence() else None
|
||||
if dom_channel_monitor_raw is not None:
|
||||
tx_fault_data = int(dom_channel_monitor_raw[0], 16)
|
||||
tx_fault_list.append(tx_fault_data & 0x01 != 0)
|
||||
tx_fault_list.append(tx_fault_data & 0x02 != 0)
|
||||
tx_fault_list.append(tx_fault_data & 0x04 != 0)
|
||||
tx_fault_list.append(tx_fault_data & 0x08 != 0)
|
||||
tx_fault = tx_fault_list[0] and tx_fault_list[1] and tx_fault_list[2] and tx_fault_list[3]
|
||||
|
||||
return tx_fault
|
||||
|
||||
def get_tx_disable(self):
|
||||
"""
|
||||
Retrieves the tx_disable status of this SFP
|
||||
Returns:
|
||||
A Boolean, True if tx_disable is enabled, False if disabled
|
||||
"""
|
||||
if self.port_num < 49: #Copper port, no sysfs
|
||||
return False
|
||||
|
||||
if self.port_num < 53:
|
||||
tx_disable = False
|
||||
|
||||
tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_disable_', self.port_num)
|
||||
tx_disable=self._api_helper.read_txt_file(tx_path)
|
||||
|
||||
if tx_disable is not None:
|
||||
return tx_disable
|
||||
else:
|
||||
return False
|
||||
|
||||
else:
|
||||
tx_disable_list = []
|
||||
|
||||
sfpd_obj = sff8436Dom()
|
||||
if sfpd_obj is None:
|
||||
return False
|
||||
|
||||
dom_control_raw = self.__read_eeprom_specific_bytes(
|
||||
QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None
|
||||
if dom_control_raw is not None:
|
||||
dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0)
|
||||
tx_disable_list.append(
|
||||
'On' == dom_control_data['data']['TX1Disable']['value'])
|
||||
tx_disable_list.append(
|
||||
'On' == dom_control_data['data']['TX2Disable']['value'])
|
||||
tx_disable_list.append(
|
||||
'On' == dom_control_data['data']['TX3Disable']['value'])
|
||||
tx_disable_list.append(
|
||||
'On' == dom_control_data['data']['TX4Disable']['value'])
|
||||
|
||||
return tx_disable_list
|
||||
|
||||
def get_tx_disable_channel(self):
|
||||
"""
|
||||
Retrieves the TX disabled channels in this SFP
|
||||
Returns:
|
||||
A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent
|
||||
TX channels which have been disabled in this SFP.
|
||||
As an example, a returned value of 0x5 indicates that channel 0
|
||||
and channel 2 have been disabled.
|
||||
"""
|
||||
if self.port_num < 53:
|
||||
# SFP doesn't support this feature
|
||||
return False
|
||||
else:
|
||||
tx_disable_list = self.get_tx_disable()
|
||||
if tx_disable_list is None:
|
||||
return 0
|
||||
tx_disabled = 0
|
||||
for i in range(len(tx_disable_list)):
|
||||
if tx_disable_list[i]:
|
||||
tx_disabled |= 1 << i
|
||||
return tx_disabled
|
||||
|
||||
def get_lpmode(self):
|
||||
"""
|
||||
Retrieves the lpmode (low power mode) status of this SFP
|
||||
Returns:
|
||||
A Boolean, True if lpmode is enabled, False if disabled
|
||||
"""
|
||||
if self.port_num < 53:
|
||||
# SFP doesn't support this feature
|
||||
return False
|
||||
else:
|
||||
power_set=self.get_power_set()
|
||||
power_override = self.get_power_override()
|
||||
return power_set and power_override
|
||||
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset SFP and return all user module settings to their default srate.
|
||||
Returns:
|
||||
A boolean, True if successful, False if not
|
||||
"""
|
||||
# Check for invalid port_num
|
||||
if self.port_num < 53: #Copper port and sfp ports are not supported.
|
||||
return False
|
||||
|
||||
reset_path = "{}{}{}".format(CPLD_I2C_PATH, 'module_reset_', self.port_num)
|
||||
ret = self._api_helper.write_txt_file(reset_path, 1)
|
||||
if ret is not True:
|
||||
return ret
|
||||
|
||||
time.sleep(0.01)
|
||||
ret = self._api_helper.write_txt_file(reset_path, 0)
|
||||
time.sleep(0.2)
|
||||
|
||||
return ret
|
||||
|
||||
def tx_disable(self, tx_disable):
|
||||
"""
|
||||
Disable SFP TX for all channels
|
||||
Args:
|
||||
tx_disable : A Boolean, True to enable tx_disable mode, False to disable
|
||||
tx_disable mode.
|
||||
Returns:
|
||||
A boolean, True if tx_disable is set successfully, False if not
|
||||
"""
|
||||
if self.port_num < 49: #Copper port, no sysfs
|
||||
return False
|
||||
|
||||
if self.port_num < 53:
|
||||
tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_disable_', self.port_num)
|
||||
ret = self._api_helper.write_txt_file(tx_path, 1 if tx_disable else 0)
|
||||
if ret is not None:
|
||||
time.sleep(0.01)
|
||||
return ret
|
||||
else:
|
||||
return False
|
||||
|
||||
else:
|
||||
if not self.get_presence():
|
||||
return False
|
||||
sysfsfile_eeprom = None
|
||||
try:
|
||||
tx_disable_ctl = 0xf if tx_disable else 0x0
|
||||
buffer = create_string_buffer(1)
|
||||
if sys.version_info[0] >= 3:
|
||||
buffer[0] = tx_disable_ctl
|
||||
else:
|
||||
buffer[0] = chr(tx_disable_ctl)
|
||||
# Write to eeprom
|
||||
sysfsfile_eeprom = open(
|
||||
self.port_to_eeprom_mapping[self.port_num], "r+b")
|
||||
sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET)
|
||||
|
||||
sysfsfile_eeprom.write(buffer[0])
|
||||
except IOError as e:
|
||||
print ('Error: unable to open file: ',str(e))
|
||||
return False
|
||||
finally:
|
||||
if sysfsfile_eeprom is not None:
|
||||
sysfsfile_eeprom.close()
|
||||
time.sleep(0.01)
|
||||
return True
|
||||
|
||||
def tx_disable_channel(self, channel, disable):
|
||||
"""
|
||||
Sets the tx_disable for specified SFP channels
|
||||
Args:
|
||||
channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3,
|
||||
e.g. 0x5 for channel 0 and channel 2.
|
||||
disable : A boolean, True to disable TX channels specified in channel,
|
||||
False to enable
|
||||
Returns:
|
||||
A boolean, True if successful, False if not
|
||||
"""
|
||||
|
||||
if self.port_num < 53:
|
||||
return False # SFP doesn't support this feature
|
||||
else:
|
||||
if not self.get_presence():
|
||||
return False
|
||||
|
||||
sysfsfile_eeprom = None
|
||||
try:
|
||||
channel_state = self.get_tx_disable_channel()
|
||||
|
||||
for i in range(4):
|
||||
channel_mask = (1 << i)
|
||||
if not (channel & channel_mask):
|
||||
continue
|
||||
|
||||
if disable:
|
||||
channel_state |= channel_mask
|
||||
else:
|
||||
channel_state &= ~channel_mask
|
||||
|
||||
buffer = create_string_buffer(1)
|
||||
if sys.version_info[0] >= 3:
|
||||
buffer[0] = channel_state
|
||||
else:
|
||||
buffer[0] = chr(channel_state)
|
||||
# Write to eeprom
|
||||
sysfsfile_eeprom = open(
|
||||
self.port_to_eeprom_mapping[self.port_num], "r+b")
|
||||
sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET)
|
||||
sysfsfile_eeprom.write(buffer[0])
|
||||
except IOError as e:
|
||||
print ('Error: unable to open file: ', str(e))
|
||||
return False
|
||||
finally:
|
||||
if sysfsfile_eeprom is not None:
|
||||
sysfsfile_eeprom.close()
|
||||
time.sleep(0.01)
|
||||
return True
|
||||
|
||||
def set_lpmode(self, lpmode):
|
||||
"""
|
||||
Sets the lpmode (low power mode) of SFP
|
||||
Args:
|
||||
lpmode: A Boolean, True to enable lpmode, False to disable it
|
||||
Note : lpmode can be overridden by set_power_override
|
||||
Returns:
|
||||
A boolean, True if lpmode is set successfully, False if not
|
||||
"""
|
||||
if self.port_num < 53:
|
||||
return False # SFP doesn't support this feature
|
||||
else:
|
||||
if lpmode is True:
|
||||
self.set_power_override(True, True)
|
||||
else:
|
||||
self.set_power_override(False, False)
|
||||
|
||||
return True
|
||||
|
||||
def set_power_override(self, power_override, power_set):
|
||||
"""
|
||||
Sets SFP power level using power_override and power_set
|
||||
Args:
|
||||
power_override :
|
||||
A Boolean, True to override set_lpmode and use power_set
|
||||
to control SFP power, False to disable SFP power control
|
||||
through power_override/power_set and use set_lpmode
|
||||
to control SFP power.
|
||||
power_set :
|
||||
Only valid when power_override is True.
|
||||
A Boolean, True to set SFP to low power mode, False to set
|
||||
SFP to high power mode.
|
||||
Returns:
|
||||
A boolean, True if power-override and power_set are set successfully,
|
||||
False if not
|
||||
"""
|
||||
if self.port_num < 53:
|
||||
return False # SFP doesn't support this feature
|
||||
else:
|
||||
if not self.get_presence():
|
||||
return False
|
||||
try:
|
||||
power_override_bit = (1 << 0) if power_override else 0
|
||||
power_set_bit = (1 << 1) if power_set else (1 << 3)
|
||||
|
||||
buffer = create_string_buffer(1)
|
||||
if sys.version_info[0] >= 3:
|
||||
buffer[0] = (power_override_bit | power_set_bit)
|
||||
else:
|
||||
buffer[0] = chr(power_override_bit | power_set_bit)
|
||||
# Write to eeprom
|
||||
with open(self.port_to_eeprom_mapping[self.port_num], "r+b") as fd:
|
||||
fd.seek(QSFP_POWEROVERRIDE_OFFSET)
|
||||
fd.write(buffer[0])
|
||||
time.sleep(0.01)
|
||||
except IOError as e:
|
||||
print ('Error: unable to open file: ', str(e))
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
name = None
|
||||
sfputil_helper = SfpUtilHelper()
|
||||
sfputil_helper.read_porttab_mappings(
|
||||
self.__get_path_to_port_config_file())
|
||||
name = sfputil_helper.logical[self.index] or "Unknown"
|
||||
return name
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the device
|
||||
Returns:
|
||||
bool: True if device is present, False if not
|
||||
"""
|
||||
if self.port_num < 49: #Copper port, no sysfs
|
||||
return False
|
||||
|
||||
present_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_present_', self.port_num)
|
||||
val=self._api_helper.read_txt_file(present_path)
|
||||
if val is not None:
|
||||
return int(val, 10)==1
|
||||
else:
|
||||
return False
|
||||
|
||||
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()
|
||||
|
||||
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.port_num
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return True
|
@ -0,0 +1,236 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Thermal contains an implementation of SONiC Platform Base API and
|
||||
# provides the thermal device status which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import glob
|
||||
|
||||
try:
|
||||
from sonic_platform_base.thermal_base import ThermalBase
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
PSU_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/"
|
||||
PSU_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 10,
|
||||
"addr": "58"
|
||||
},
|
||||
1: {
|
||||
"num": 11,
|
||||
"addr": "59"
|
||||
},
|
||||
}
|
||||
|
||||
PSU_CPLD_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 10,
|
||||
"addr": "50"
|
||||
},
|
||||
1: {
|
||||
"num": 11,
|
||||
"addr": "51"
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class Thermal(ThermalBase):
|
||||
"""Platform-specific Thermal class"""
|
||||
|
||||
THERMAL_NAME_LIST = []
|
||||
PSU_THERMAL_NAME_LIST = []
|
||||
SYSFS_PATH = "/sys/bus/i2c/devices"
|
||||
|
||||
def __init__(self, thermal_index=0, is_psu=False, psu_index=0):
|
||||
self.index = thermal_index
|
||||
self.is_psu = is_psu
|
||||
self.psu_index = psu_index
|
||||
|
||||
if self.is_psu:
|
||||
psu_i2c_bus = PSU_I2C_MAPPING[psu_index]["num"]
|
||||
psu_i2c_addr = PSU_I2C_MAPPING[psu_index]["addr"]
|
||||
self.psu_hwmon_path = PSU_I2C_PATH.format(psu_i2c_bus,
|
||||
psu_i2c_addr)
|
||||
psu_i2c_bus = PSU_CPLD_I2C_MAPPING[psu_index]["num"]
|
||||
psu_i2c_addr = PSU_CPLD_I2C_MAPPING[psu_index]["addr"]
|
||||
self.cpld_path = PSU_I2C_PATH.format(psu_i2c_bus, psu_i2c_addr)
|
||||
# Add thermal name
|
||||
self.THERMAL_NAME_LIST.append("Temp sensor 1")
|
||||
self.THERMAL_NAME_LIST.append("Temp sensor 2")
|
||||
self.THERMAL_NAME_LIST.append("Temp sensor 3")
|
||||
self.PSU_THERMAL_NAME_LIST.append("PSU-1 temp sensor 1")
|
||||
self.PSU_THERMAL_NAME_LIST.append("PSU-2 temp sensor 1")
|
||||
|
||||
# Set hwmon path
|
||||
i2c_path = {
|
||||
0: "14-0048/hwmon/hwmon*/",
|
||||
1: "24-004b/hwmon/hwmon*/",
|
||||
2: "25-004a/hwmon/hwmon*/"
|
||||
}.get(self.index, None)
|
||||
|
||||
self.hwmon_path = "{}/{}".format(self.SYSFS_PATH, i2c_path)
|
||||
self.ss_key = self.THERMAL_NAME_LIST[self.index]
|
||||
self.ss_index = 1
|
||||
|
||||
def __read_txt_file(self, file_path):
|
||||
for filename in glob.glob(file_path):
|
||||
try:
|
||||
with open(filename, 'r') as fd:
|
||||
data =fd.readline().rstrip()
|
||||
return data
|
||||
except IOError as e:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def __get_temp(self, temp_file):
|
||||
if not self.is_psu:
|
||||
temp_file_path = os.path.join(self.hwmon_path, temp_file)
|
||||
else:
|
||||
temp_file_path = temp_file
|
||||
raw_temp = self.__read_txt_file(temp_file_path)
|
||||
if raw_temp is not None:
|
||||
return float(raw_temp)/1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def __set_threshold(self, file_name, temperature):
|
||||
if self.is_psu:
|
||||
return True
|
||||
temp_file_path = os.path.join(self.hwmon_path, file_name)
|
||||
for filename in glob.glob(temp_file_path):
|
||||
try:
|
||||
with open(filename, 'w') as fd:
|
||||
fd.write(str(temperature))
|
||||
return True
|
||||
except IOError as e:
|
||||
print("IOError")
|
||||
|
||||
|
||||
def get_temperature(self):
|
||||
"""
|
||||
Retrieves current temperature reading from thermal
|
||||
Returns:
|
||||
A float number of current temperature in Celsius up to nearest thousandth
|
||||
of one degree Celsius, e.g. 30.125
|
||||
"""
|
||||
if not self.is_psu:
|
||||
temp_file = "temp{}_input".format(self.ss_index)
|
||||
else:
|
||||
temp_file = self.psu_hwmon_path + "psu_temp1_input"
|
||||
|
||||
return self.__get_temp(temp_file)
|
||||
|
||||
def get_high_threshold(self):
|
||||
"""
|
||||
Retrieves the high threshold temperature of thermal
|
||||
Returns:
|
||||
A float number, the high threshold temperature of thermal in Celsius
|
||||
up to nearest thousandth of one degree Celsius, e.g. 30.125
|
||||
"""
|
||||
if self.is_psu:
|
||||
return 0
|
||||
|
||||
temp_file = "temp{}_max".format(self.ss_index)
|
||||
return self.__get_temp(temp_file)
|
||||
|
||||
def set_high_threshold(self, temperature):
|
||||
"""
|
||||
Sets the high threshold temperature of thermal
|
||||
Args :
|
||||
temperature: A float number up to nearest thousandth of one degree Celsius,
|
||||
e.g. 30.125
|
||||
Returns:
|
||||
A boolean, True if threshold is set successfully, False if not
|
||||
"""
|
||||
temp_file = "temp{}_max".format(self.ss_index)
|
||||
temperature = temperature *1000
|
||||
self.__set_threshold(temp_file, temperature)
|
||||
|
||||
return True
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the thermal device
|
||||
Returns:
|
||||
string: The name of the thermal device
|
||||
"""
|
||||
if self.is_psu:
|
||||
return self.PSU_THERMAL_NAME_LIST[self.psu_index]
|
||||
else:
|
||||
return self.THERMAL_NAME_LIST[self.index]
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the Thermal
|
||||
Returns:
|
||||
bool: True if Thermal is present, False if not
|
||||
"""
|
||||
if self.is_psu:
|
||||
val = self.__read_txt_file(self.cpld_path + "psu_present")
|
||||
return int(val, 10) == 1
|
||||
temp_file = "temp{}_input".format(self.ss_index)
|
||||
temp_file_path = os.path.join(self.hwmon_path, temp_file)
|
||||
raw_txt = self.__read_txt_file(temp_file_path)
|
||||
if raw_txt is not None:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the device
|
||||
Returns:
|
||||
A boolean value, True if device is operating properly, False if not
|
||||
"""
|
||||
if self.is_psu:
|
||||
temp_file = self.psu_hwmon_path + "psu_temp_fault"
|
||||
return self.get_presence() and (not int(
|
||||
self.__read_txt_file(temp_file)))
|
||||
|
||||
file_str = "temp{}_input".format(self.ss_index)
|
||||
file_path = os.path.join(self.hwmon_path, file_str)
|
||||
raw_txt = self.__read_txt_file(file_path)
|
||||
if raw_txt is None:
|
||||
return False
|
||||
else:
|
||||
return int(raw_txt) != 0
|
||||
|
||||
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_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.index+1
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Retrieves whether thermal module is replaceable
|
||||
Returns:
|
||||
A boolean value, True if replaceable, False if not
|
||||
"""
|
||||
return False
|
@ -2,4 +2,3 @@ CONSOLE_PORT=0x3f8
|
||||
CONSOLE_DEV=0
|
||||
CONSOLE_SPEED=115200
|
||||
ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="intel_iommu=off modprobe.blacklist=i2c-ismt,i2c_ismt,i2c-i801,i2c_i801"
|
||||
|
||||
|
@ -148,7 +148,7 @@ class SfpUtil(SfpUtilBase):
|
||||
cage_num = port_num
|
||||
if (port_num >= self.QSFP_PORT_START):
|
||||
cage_num = (port_num - self.QSFP_PORT_START)/4
|
||||
cage_num = cage_num + self.QSFP_PORT_START
|
||||
cage_num = int(cage_num + self.QSFP_PORT_START)
|
||||
|
||||
return cage_num
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"skip_ledd": true,
|
||||
"skip_thermalctld": true
|
||||
"skip_pcied": true
|
||||
}
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
__all__ = ['chassis', 'eeprom', 'platform', 'psu', 'sfp', 'thermal', 'fan']
|
||||
__all__ = [ "platform", "chassis", "sfp", "eeprom", "component", "psu", "thermal", "fan", "fan_drawer" ]
|
||||
from . import platform
|
||||
|
@ -28,7 +28,14 @@ HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/"
|
||||
PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/"
|
||||
REBOOT_CAUSE_FILE = "reboot-cause.txt"
|
||||
PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt"
|
||||
HOST_CHK_CMD = "docker > /dev/null 2>&1"
|
||||
HOST_CHK_CMD = "which systemctl > /dev/null 2>&1"
|
||||
SYSLED_FNODE= "/sys/class/leds/as5835_54x_led::diag/brightness"
|
||||
|
||||
SYSLED_MODES = {
|
||||
"0" : "STATUS_LED_COLOR_OFF",
|
||||
"1" : "STATUS_LED_COLOR_GREEN",
|
||||
"3" : "STATUS_LED_COLOR_AMBER"
|
||||
}
|
||||
|
||||
|
||||
class Chassis(ChassisBase):
|
||||
@ -37,7 +44,6 @@ class Chassis(ChassisBase):
|
||||
def __init__(self):
|
||||
ChassisBase.__init__(self)
|
||||
self._api_helper = APIHelper()
|
||||
self._api_helper = APIHelper()
|
||||
self.is_host = self._api_helper.is_host()
|
||||
|
||||
self.config_data = {}
|
||||
@ -54,15 +60,16 @@ class Chassis(ChassisBase):
|
||||
for index in range(0, PORT_END):
|
||||
sfp = Sfp(index)
|
||||
self._sfp_list.append(sfp)
|
||||
self._sfpevent = SfpEvent(self._sfp_list)
|
||||
self.sfp_module_initialized = True
|
||||
|
||||
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 sonic_platform.fan_drawer import FanDrawer
|
||||
for fant_index in range(NUM_FAN_TRAY):
|
||||
fandrawer = FanDrawer(fant_index)
|
||||
self._fan_drawer_list.append(fandrawer)
|
||||
self._fan_list.extend(fandrawer._fan_list)
|
||||
|
||||
def __initialize_psu(self):
|
||||
from sonic_platform.psu import Psu
|
||||
for index in range(0, NUM_PSU):
|
||||
@ -84,12 +91,12 @@ class Chassis(ChassisBase):
|
||||
for index in range(0, NUM_COMPONENT):
|
||||
component = Component(index)
|
||||
self._component_list.append(component)
|
||||
|
||||
|
||||
def __initialize_watchdog(self):
|
||||
from sonic_platform.watchdog import Watchdog
|
||||
self._watchdog = Watchdog()
|
||||
|
||||
|
||||
|
||||
def __is_host(self):
|
||||
return os.system(HOST_CHK_CMD) == 0
|
||||
|
||||
@ -101,23 +108,14 @@ class Chassis(ChassisBase):
|
||||
except IOError:
|
||||
pass
|
||||
return None
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the device
|
||||
Returns:
|
||||
string: Model/part number of device
|
||||
"""
|
||||
return self._eeprom.get_pn()
|
||||
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
|
||||
return self._api_helper.hwsku
|
||||
return self._eeprom.get_product_name()
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
@ -144,7 +142,15 @@ class Chassis(ChassisBase):
|
||||
"""
|
||||
return self._eeprom.get_mac()
|
||||
|
||||
def get_serial_number(self):
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the device
|
||||
Returns:
|
||||
string: Model/part number of device
|
||||
"""
|
||||
return self._eeprom.get_pn()
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the hardware serial number for the chassis
|
||||
Returns:
|
||||
@ -173,7 +179,7 @@ class Chassis(ChassisBase):
|
||||
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
|
||||
to pass a description of the reboot cause.
|
||||
"""
|
||||
|
||||
|
||||
reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE)
|
||||
sw_reboot_cause = self._api_helper.read_txt_file(
|
||||
reboot_cause_path) or "Unknown"
|
||||
@ -185,10 +191,7 @@ class Chassis(ChassisBase):
|
||||
# SFP event
|
||||
if not self.sfp_module_initialized:
|
||||
self.__initialize_sfp()
|
||||
|
||||
status, sfp_event = SfpEvent(self._sfp_list).get_sfp_event(timeout)
|
||||
|
||||
return status, sfp_event
|
||||
return self._sfpevent.get_sfp_event(timeout)
|
||||
|
||||
def get_sfp(self, index):
|
||||
"""
|
||||
@ -212,3 +215,40 @@ class Chassis(ChassisBase):
|
||||
sys.stderr.write("SFP index {} out of range (1-{})\n".format(
|
||||
index, len(self._sfp_list)))
|
||||
return sfp
|
||||
|
||||
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 initizalize_system_led(self):
|
||||
return True
|
||||
|
||||
def get_status_led(self):
|
||||
val = self._api_helper.read_txt_file(SYSLED_FNODE)
|
||||
return SYSLED_MODES[val] if val in SYSLED_MODES else "UNKNOWN"
|
||||
|
||||
def set_status_led(self, color):
|
||||
mode = None
|
||||
for key, val in SYSLED_MODES.items():
|
||||
if val == color:
|
||||
mode = key
|
||||
break
|
||||
if mode is None:
|
||||
return False
|
||||
else:
|
||||
return self._api_helper.write_txt_file(SYSLED_FNODE, mode)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#############################################################################
|
||||
# Celestica
|
||||
# Edgecore
|
||||
#
|
||||
# Component contains an implementation of SONiC Platform Base API and
|
||||
# provides the components firmware management function
|
||||
@ -67,14 +67,14 @@ class Component(ComponentBase):
|
||||
with open(BIOS_VERSION_PATH, 'r') as fd:
|
||||
bios_version = fd.read()
|
||||
return bios_version.strip()
|
||||
except Exception as e:
|
||||
except Exception as e:
|
||||
print('Get exception when read bios')
|
||||
return None
|
||||
|
||||
def __get_cpld_version(self):
|
||||
# Retrieves the CPLD firmware version
|
||||
cpld_version = dict()
|
||||
for cpld_name in CPLD_ADDR_MAPPING:
|
||||
for cpld_name in CPLD_ADDR_MAPPING:
|
||||
try:
|
||||
cpld_path = "{}{}{}".format(SYSFS_PATH, CPLD_ADDR_MAPPING[cpld_name], '/version')
|
||||
cpld_version_raw= self._api_helper.read_txt_file(cpld_path)
|
||||
@ -126,3 +126,55 @@ class Component(ComponentBase):
|
||||
A boolean, True if install successfully, False if not
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the device
|
||||
Returns:
|
||||
bool: True if device 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
|
||||
|
@ -20,7 +20,7 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
|
||||
EEPROM_DECODE_HEADLINES = 6
|
||||
|
||||
def __init__(self):
|
||||
self._eeprom_path = "/sys/bus/i2c/devices/0-0057/eeprom"
|
||||
self._eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom"
|
||||
super(Tlv, self).__init__(self._eeprom_path, 0, '', True)
|
||||
self._eeprom = self._load_eeprom()
|
||||
|
||||
@ -123,9 +123,12 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
|
||||
|
||||
def get_pn(self):
|
||||
return self._eeprom.get('0x22', NULL)
|
||||
|
||||
|
||||
def get_serial(self):
|
||||
return self._eeprom.get('0x23', NULL)
|
||||
|
||||
def get_mac(self):
|
||||
return self._eeprom.get('0x24', NULL)
|
||||
|
||||
def get_product_name(self):
|
||||
return self._eeprom.get('0x21', NULL)
|
||||
|
@ -1,42 +1,49 @@
|
||||
try:
|
||||
import time
|
||||
from .helper import APIHelper
|
||||
from sonic_py_common.logger import Logger
|
||||
except ImportError as e:
|
||||
raise ImportError(repr(e) + " - required module not found")
|
||||
|
||||
POLL_INTERVAL_IN_SEC = 1
|
||||
|
||||
class SfpEvent:
|
||||
''' Listen to insert/remove sfp events '''
|
||||
|
||||
def __init__(self, sfp_list):
|
||||
self._api_helper = APIHelper()
|
||||
self._sfp_list = sfp_list
|
||||
self._logger = Logger()
|
||||
self._sfp_change_event_data = {'present': 0}
|
||||
|
||||
sfp_change_event_data = {'valid': 0, 'last': 0, 'present': 0}
|
||||
def get_sfp_event(self, timeout=2000):
|
||||
now = time.time()
|
||||
port_dict = {}
|
||||
change_dict = {}
|
||||
change_dict['sfp'] = port_dict
|
||||
|
||||
if timeout < 1000:
|
||||
timeout = 1000
|
||||
timeout = timeout / float(1000) # Convert to secs
|
||||
|
||||
if now < (self.sfp_change_event_data['last'] + timeout) and self.sfp_change_event_data['valid']:
|
||||
return True, change_dict
|
||||
|
||||
def get_presence_bitmap(self):
|
||||
bitmap = 0
|
||||
for sfp in self._sfp_list:
|
||||
modpres = sfp.get_presence()
|
||||
i=sfp.port_num-1
|
||||
if modpres:
|
||||
bitmap = bitmap | (1 << i)
|
||||
return bitmap
|
||||
|
||||
changed_ports = self.sfp_change_event_data['present'] ^ bitmap
|
||||
if changed_ports:
|
||||
def get_sfp_event(self, timeout=2000):
|
||||
port_dict = {}
|
||||
change_dict = {}
|
||||
change_dict['sfp'] = port_dict
|
||||
|
||||
if timeout < 1000:
|
||||
cd_ms = 1000
|
||||
else:
|
||||
cd_ms = timeout
|
||||
|
||||
while cd_ms > 0:
|
||||
bitmap = self.get_presence_bitmap()
|
||||
changed_ports = self._sfp_change_event_data['present'] ^ bitmap
|
||||
if changed_ports != 0:
|
||||
break
|
||||
time.sleep(POLL_INTERVAL_IN_SEC)
|
||||
# timeout=0 means wait for event forever
|
||||
if timeout != 0:
|
||||
cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000
|
||||
|
||||
if changed_ports != 0:
|
||||
for sfp in self._sfp_list:
|
||||
i=sfp.port_num-1
|
||||
if (changed_ports & (1 << i)):
|
||||
@ -47,9 +54,7 @@ class SfpEvent:
|
||||
|
||||
|
||||
# Update the cache dict
|
||||
self.sfp_change_event_data['present'] = bitmap
|
||||
self.sfp_change_event_data['last'] = now
|
||||
self.sfp_change_event_data['valid'] = 1
|
||||
self._sfp_change_event_data['present'] = bitmap
|
||||
return True, change_dict
|
||||
else:
|
||||
return True, change_dict
|
||||
|
@ -15,9 +15,10 @@ except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
PSU_FAN_MAX_RPM = 26688
|
||||
CPLD_I2C_PATH = "/sys/bus/i2c/devices/3-0063/fan"
|
||||
PSU_HWMON_I2C_PATH ="/sys/bus/i2c/devices/{}-00{}/"
|
||||
PSU_I2C_MAPPING = {
|
||||
SPEED_TOLERANCE = 15
|
||||
CPLD_FAN_I2C_PATH = "/sys/bus/i2c/devices/3-0063/fan"
|
||||
I2C_PATH ="/sys/bus/i2c/devices/{}-00{}/"
|
||||
PSU_HWMON_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 11,
|
||||
"addr": "58"
|
||||
@ -28,6 +29,20 @@ PSU_I2C_MAPPING = {
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
PSU_CPLD_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 11,
|
||||
"addr": "50"
|
||||
},
|
||||
1: {
|
||||
"num": 12,
|
||||
"addr": "53"
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R",
|
||||
"FAN-3F", "FAN-3R", "FAN-4F", "FAN-4R",
|
||||
"FAN-5F", "FAN-5R"]
|
||||
@ -42,13 +57,18 @@ class Fan(FanBase):
|
||||
self.is_psu_fan = is_psu_fan
|
||||
if self.is_psu_fan:
|
||||
self.psu_index = psu_index
|
||||
self.psu_i2c_num = PSU_I2C_MAPPING[self.psu_index]['num']
|
||||
self.psu_i2c_addr = PSU_I2C_MAPPING[self.psu_index]['addr']
|
||||
self.psu_hwmon_path = PSU_HWMON_I2C_PATH.format(
|
||||
self.psu_i2c_num = PSU_HWMON_I2C_MAPPING[self.psu_index]['num']
|
||||
self.psu_i2c_addr = PSU_HWMON_I2C_MAPPING[self.psu_index]['addr']
|
||||
self.psu_hwmon_path = I2C_PATH.format(
|
||||
self.psu_i2c_num, self.psu_i2c_addr)
|
||||
|
||||
self.psu_i2c_num = PSU_CPLD_I2C_MAPPING[self.psu_index]['num']
|
||||
self.psu_i2c_addr = PSU_CPLD_I2C_MAPPING[self.psu_index]['addr']
|
||||
self.psu_cpld_path = I2C_PATH.format(
|
||||
self.psu_i2c_num, self.psu_i2c_addr)
|
||||
|
||||
FanBase.__init__(self)
|
||||
|
||||
|
||||
|
||||
def get_direction(self):
|
||||
"""
|
||||
@ -60,9 +80,9 @@ class Fan(FanBase):
|
||||
|
||||
|
||||
if not self.is_psu_fan:
|
||||
dir_str = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_direction')
|
||||
dir_str = "{}{}{}".format(CPLD_FAN_I2C_PATH, self.fan_tray_index+1, '_direction')
|
||||
val=self._api_helper.read_txt_file(dir_str)
|
||||
if val is not None:
|
||||
if val is not None:
|
||||
if int(val, 10)==0:
|
||||
direction=self.FAN_DIRECTION_EXHAUST
|
||||
else:
|
||||
@ -90,26 +110,26 @@ class Fan(FanBase):
|
||||
Returns:
|
||||
An integer, the percentage of full fan speed, in the range 0 (off)
|
||||
to 100 (full speed)
|
||||
|
||||
|
||||
"""
|
||||
speed = 0
|
||||
if self.is_psu_fan:
|
||||
psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_speed_rpm')
|
||||
fan_speed_rpm = self._api_helper.read_txt_file(psu_fan_path)
|
||||
if fan_speed_rpm is not None:
|
||||
speed = (int(fan_speed_rpm,10))*100/26688
|
||||
speed = (int(fan_speed_rpm,10))*100/26688
|
||||
if speed > 100:
|
||||
speed=100
|
||||
else:
|
||||
return 0
|
||||
elif self.get_presence():
|
||||
speed_path = "{}{}".format(CPLD_I2C_PATH, '_duty_cycle_percentage')
|
||||
speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, '_duty_cycle_percentage')
|
||||
speed=self._api_helper.read_txt_file(speed_path)
|
||||
if speed is None:
|
||||
return 0
|
||||
|
||||
return int(speed)
|
||||
|
||||
|
||||
def get_target_speed(self):
|
||||
"""
|
||||
Retrieves the target (expected) speed of the fan
|
||||
@ -123,7 +143,7 @@ class Fan(FanBase):
|
||||
0 : when PWM mode is use
|
||||
pwm : when pwm mode is not use
|
||||
"""
|
||||
return False #Not supported
|
||||
return self.get_speed()
|
||||
|
||||
def get_speed_tolerance(self):
|
||||
"""
|
||||
@ -132,7 +152,7 @@ class Fan(FanBase):
|
||||
An integer, the percentage of variance from target speed which is
|
||||
considered tolerable
|
||||
"""
|
||||
return False #Not supported
|
||||
return SPEED_TOLERANCE
|
||||
|
||||
def set_speed(self, speed):
|
||||
"""
|
||||
@ -146,7 +166,7 @@ class Fan(FanBase):
|
||||
"""
|
||||
|
||||
if not self.is_psu_fan and self.get_presence():
|
||||
speed_path = "{}{}".format(CPLD_I2C_PATH, '_duty_cycle_percentage')
|
||||
speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, '_duty_cycle_percentage')
|
||||
return self._api_helper.write_txt_file(speed_path, int(speed))
|
||||
|
||||
return False
|
||||
@ -195,17 +215,18 @@ class Fan(FanBase):
|
||||
Returns:
|
||||
bool: True if FAN is present, False if not
|
||||
"""
|
||||
present_path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_present')
|
||||
val=self._api_helper.read_txt_file(present_path)
|
||||
|
||||
if not self.is_psu_fan:
|
||||
if val is not None:
|
||||
return int(val, 10)==1
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
|
||||
if self.is_psu_fan:
|
||||
present_path="{}{}".format(self.psu_cpld_path, 'psu_present')
|
||||
else:
|
||||
return True
|
||||
present_path = "{}{}{}".format(CPLD_FAN_I2C_PATH, self.fan_tray_index+1, '_present')
|
||||
|
||||
val=self._api_helper.read_txt_file(present_path)
|
||||
if val is not None:
|
||||
return int(val, 10)==1
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
@ -221,7 +242,7 @@ class Fan(FanBase):
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_index+1, '_fault')
|
||||
path = "{}{}{}".format(CPLD_FAN_I2C_PATH, self.fan_tray_index+1, '_fault')
|
||||
val=self._api_helper.read_txt_file(path)
|
||||
if val is not None:
|
||||
return int(val, 10)==0
|
||||
@ -245,3 +266,25 @@ class Fan(FanBase):
|
||||
string: Serial number of device
|
||||
"""
|
||||
return "N/A"
|
||||
|
||||
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_index+1) \
|
||||
if not self.is_psu_fan else (self.psu_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
|
||||
|
||||
|
@ -0,0 +1,90 @@
|
||||
########################################################################
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides 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")
|
||||
|
||||
FANS_PER_FANTRAY = 2
|
||||
|
||||
|
||||
class FanDrawer(FanDrawerBase):
|
||||
"""Platform-specific Fan class"""
|
||||
|
||||
def __init__(self, fantray_index):
|
||||
|
||||
FanDrawerBase.__init__(self)
|
||||
# FanTray is 0-based in platforms
|
||||
self.fantrayindex = fantray_index
|
||||
self.__initialize_fan_drawer()
|
||||
|
||||
|
||||
def __initialize_fan_drawer(self):
|
||||
from sonic_platform.fan import Fan
|
||||
for i in range(FANS_PER_FANTRAY):
|
||||
self._fan_list.append(Fan(self.fantrayindex, i))
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the fan drawer name
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
return "FanTray{}".format(self.fantrayindex+1)
|
||||
|
||||
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.
|
||||
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.fantrayindex+1)
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return True
|
@ -51,7 +51,7 @@ class APIHelper():
|
||||
|
||||
def read_txt_file(self, file_path):
|
||||
try:
|
||||
with open(file_path, 'r') as fd:
|
||||
with open(file_path, 'r', errors='replace') as fd:
|
||||
data = fd.read()
|
||||
return data.strip()
|
||||
except IOError:
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
try:
|
||||
from sonic_platform_base.psu_base import PsuBase
|
||||
#from sonic_platform.fan import Fan
|
||||
from sonic_platform.thermal import Thermal
|
||||
from .helper import APIHelper
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
@ -64,6 +64,8 @@ class Psu(PsuBase):
|
||||
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)
|
||||
|
||||
self._thermal_list.append(Thermal(is_psu=True, psu_index=self.index))
|
||||
|
||||
def get_voltage(self):
|
||||
"""
|
||||
@ -154,7 +156,7 @@ class Psu(PsuBase):
|
||||
return float(val)/1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
def get_temperature_high_threshold(self):
|
||||
"""
|
||||
Retrieves the high threshold temperature of PSU
|
||||
@ -251,3 +253,20 @@ class Psu(PsuBase):
|
||||
if serial is None:
|
||||
return "N/A"
|
||||
return serial
|
||||
|
||||
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.index+1
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return True
|
||||
|
@ -13,108 +13,14 @@ import sys
|
||||
from ctypes import create_string_buffer
|
||||
|
||||
try:
|
||||
from sonic_platform_base.sfp_base import SfpBase
|
||||
from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom
|
||||
from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId
|
||||
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 sffbase
|
||||
from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper
|
||||
from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase
|
||||
from .helper import APIHelper
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
CPLD_I2C_PATH = "/sys/bus/i2c/devices/"
|
||||
|
||||
QSFP_INFO_OFFSET = 128
|
||||
QSFP_DOM_OFFSET = 0
|
||||
|
||||
SFP_INFO_OFFSET = 0
|
||||
SFP_DOM_OFFSET = 256
|
||||
|
||||
XCVR_INTFACE_BULK_OFFSET = 0
|
||||
XCVR_INTFACE_BULK_WIDTH_QSFP = 20
|
||||
XCVR_INTFACE_BULK_WIDTH_SFP = 21
|
||||
XCVR_HW_REV_WIDTH_QSFP = 2
|
||||
XCVR_HW_REV_WIDTH_SFP = 4
|
||||
XCVR_CABLE_LENGTH_WIDTH_QSFP = 5
|
||||
XCVR_VENDOR_NAME_OFFSET = 20
|
||||
XCVR_VENDOR_NAME_WIDTH = 16
|
||||
XCVR_VENDOR_OUI_OFFSET = 37
|
||||
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_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
|
||||
|
||||
# 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_CHANNL_MON_OFFSET = 34
|
||||
QSFP_CHANNL_MON_WIDTH = 16
|
||||
QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24
|
||||
QSFP_CONTROL_OFFSET = 86
|
||||
QSFP_CONTROL_WIDTH = 8
|
||||
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_POWEROVERRIDE_OFFSET = 93
|
||||
QSFP_POWEROVERRIDE_WIDTH = 1
|
||||
QSFP_MODULE_THRESHOLD_OFFSET = 128
|
||||
QSFP_MODULE_THRESHOLD_WIDTH = 24
|
||||
QSFP_CHANNEL_THRESHOLD_OFFSET = 176
|
||||
QSFP_CHANNEL_THRESHOLD_WIDTH = 16
|
||||
|
||||
qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)',
|
||||
'Length OM2(m)', 'Length OM1(m)',
|
||||
'Length Cable Assembly(m)')
|
||||
|
||||
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')
|
||||
|
||||
|
||||
# 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_TX_DISABLE_HARD_BIT = 7
|
||||
SFP_TX_DISABLE_SOFT_BIT = 6
|
||||
|
||||
sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)',
|
||||
'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)',
|
||||
'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)')
|
||||
|
||||
sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode',
|
||||
'ESCONComplianceCodes', 'SONETComplianceCodes',
|
||||
'EthernetComplianceCodes', 'FibreChannelLinkLength',
|
||||
'FibreChannelTechnology', 'SFP+CableTechnology',
|
||||
'FibreChannelTransmissionMedia', 'FibreChannelSpeed')
|
||||
|
||||
|
||||
class Sfp(SfpBase):
|
||||
class Sfp(SfpOptoeBase):
|
||||
"""Platform-specific Sfp class"""
|
||||
|
||||
# Port number
|
||||
@ -125,7 +31,7 @@ class Sfp(SfpBase):
|
||||
# Path to sysfs
|
||||
PLATFORM_ROOT_PATH = "/usr/share/sonic/device"
|
||||
PMON_HWSKU_PATH = "/usr/share/sonic/hwsku"
|
||||
HOST_CHK_CMD = "docker > /dev/null 2>&1"
|
||||
HOST_CHK_CMD = "which systemctl > /dev/null 2>&1"
|
||||
|
||||
PLATFORM = "x86_64-accton_as5835_54x-r0"
|
||||
HWSKU = "Accton-AS5835-54X"
|
||||
@ -194,6 +100,7 @@ class Sfp(SfpBase):
|
||||
}
|
||||
|
||||
def __init__(self, sfp_index=0):
|
||||
SfpOptoeBase.__init__(self)
|
||||
self._api_helper=APIHelper()
|
||||
# Init index
|
||||
self.index = sfp_index
|
||||
@ -204,44 +111,15 @@ class Sfp(SfpBase):
|
||||
self.port_to_eeprom_mapping = {}
|
||||
for x in range(self.PORT_START, self.PORT_END + 1):
|
||||
self.port_to_eeprom_mapping[x] = eeprom_path.format(self._port_to_i2c_mapping[x])
|
||||
|
||||
def get_eeprom_path(self):
|
||||
return self.port_to_eeprom_mapping[self.port_num]
|
||||
|
||||
self.info_dict_keys = ['type', 'vendor_rev', 'serial', 'manufacturer', 'model', 'connector', 'encoding', 'ext_identifier',
|
||||
'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']
|
||||
|
||||
self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', 'rxpowerhighwarning',
|
||||
'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning']
|
||||
|
||||
SfpBase.__init__(self)
|
||||
|
||||
# For cage 1~38 are at cpld2, others are at cpld3.
|
||||
def __get_cpld_num(self, port_num):
|
||||
return 1 if (port_num < 39) else 2
|
||||
|
||||
|
||||
def _convert_string_to_num(self, value_str):
|
||||
if "-inf" in value_str:
|
||||
return 'N/A'
|
||||
elif "Unknown" in value_str:
|
||||
return 'N/A'
|
||||
elif 'dBm' in value_str:
|
||||
t_str = value_str.rstrip('dBm')
|
||||
return float(t_str)
|
||||
elif 'mA' in value_str:
|
||||
t_str = value_str.rstrip('mA')
|
||||
return float(t_str)
|
||||
elif 'C' in value_str:
|
||||
t_str = value_str.rstrip('C')
|
||||
return float(t_str)
|
||||
elif 'Volts' in value_str:
|
||||
t_str = value_str.rstrip('Volts')
|
||||
return float(t_str)
|
||||
else:
|
||||
return 'N/A'
|
||||
|
||||
def __is_host(self):
|
||||
return os.system(self.HOST_CHK_CMD) == 0
|
||||
|
||||
@ -277,422 +155,6 @@ class Sfp(SfpBase):
|
||||
|
||||
return eeprom_raw
|
||||
|
||||
def get_transceiver_info(self):
|
||||
"""
|
||||
Retrieves transceiver info of this SFP
|
||||
Returns:
|
||||
A dict which contains following keys/values :
|
||||
========================================================================
|
||||
keys |Value Format |Information
|
||||
---------------------------|---------------|----------------------------
|
||||
type |1*255VCHAR |type of SFP
|
||||
vendor_rev |1*255VCHAR |vendor revision of SFP
|
||||
serial |1*255VCHAR |serial number of the SFP
|
||||
manufacturer |1*255VCHAR |SFP vendor name
|
||||
model |1*255VCHAR |SFP model name
|
||||
connector |1*255VCHAR |connector information
|
||||
encoding |1*255VCHAR |encoding information
|
||||
ext_identifier |1*255VCHAR |extend identifier
|
||||
ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance
|
||||
cable_length |INT |cable length in m
|
||||
nominal_bit_rate |INT |nominal bit rate by 100Mbs
|
||||
specification_compliance |1*255VCHAR |specification compliance
|
||||
vendor_date |1*255VCHAR |vendor date
|
||||
vendor_oui |1*255VCHAR |vendor OUI
|
||||
application_advertisement |1*255VCHAR |supported applications advertisement
|
||||
========================================================================
|
||||
"""
|
||||
# check present status
|
||||
if self.port_num < 49:
|
||||
sfpi_obj = sff8472InterfaceId() #SFP
|
||||
else:
|
||||
sfpi_obj = sff8436InterfaceId() #QSFP
|
||||
if not self.get_presence() or not sfpi_obj:
|
||||
return {}
|
||||
|
||||
if self.port_num < 49:
|
||||
offset = SFP_INFO_OFFSET
|
||||
sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes(
|
||||
(offset + XCVR_INTFACE_BULK_OFFSET), XCVR_INTFACE_BULK_WIDTH_SFP)
|
||||
else:
|
||||
offset = QSFP_INFO_OFFSET
|
||||
sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes(
|
||||
(offset + XCVR_INTFACE_BULK_OFFSET), XCVR_INTFACE_BULK_WIDTH_QSFP)
|
||||
|
||||
sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(
|
||||
sfp_interface_bulk_raw, 0)
|
||||
|
||||
sfp_vendor_name_raw = self.__read_eeprom_specific_bytes(
|
||||
(offset + XCVR_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH)
|
||||
sfp_vendor_name_data = sfpi_obj.parse_vendor_name(
|
||||
sfp_vendor_name_raw, 0)
|
||||
|
||||
sfp_vendor_pn_raw = self.__read_eeprom_specific_bytes(
|
||||
(offset + XCVR_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH)
|
||||
sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(
|
||||
sfp_vendor_pn_raw, 0)
|
||||
|
||||
if self.port_num < 49:
|
||||
sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes(
|
||||
(offset + XCVR_HW_REV_OFFSET), XCVR_HW_REV_WIDTH_SFP)
|
||||
else:
|
||||
sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes(
|
||||
(offset + XCVR_HW_REV_OFFSET), XCVR_HW_REV_WIDTH_QSFP)
|
||||
|
||||
sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(
|
||||
sfp_vendor_rev_raw, 0)
|
||||
|
||||
sfp_vendor_sn_raw = self.__read_eeprom_specific_bytes(
|
||||
(offset + XCVR_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH)
|
||||
sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(
|
||||
sfp_vendor_sn_raw, 0)
|
||||
|
||||
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:
|
||||
sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(
|
||||
sfp_vendor_oui_raw, 0)
|
||||
|
||||
sfp_vendor_date_raw = self.__read_eeprom_specific_bytes(
|
||||
(offset + XCVR_VENDOR_DATE_OFFSET), 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:
|
||||
transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['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['vendor_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.port_num < 49:
|
||||
for key in sfp_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 sfp_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']['NominalSignallingRate(UnitsOf100Mbd)']['value'])
|
||||
else:
|
||||
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'])
|
||||
|
||||
|
||||
return transceiver_info_dict
|
||||
|
||||
def get_transceiver_bulk_status(self):
|
||||
"""
|
||||
Retrieves transceiver bulk status of this SFP
|
||||
Returns:
|
||||
A dict which contains following keys/values :
|
||||
========================================================================
|
||||
keys |Value Format |Information
|
||||
---------------------------|---------------|----------------------------
|
||||
rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not.
|
||||
tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not.
|
||||
reset_status |BOOLEAN |reset status, True if SFP in reset, False if not.
|
||||
lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not.
|
||||
tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not.
|
||||
tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0
|
||||
| |to channel 3.
|
||||
temperature |INT |module temperature in Celsius
|
||||
voltage |INT |supply voltage in mV
|
||||
tx<n>bias |INT |TX Bias Current in mA, n is the channel number,
|
||||
| |for example, tx2bias stands for tx bias of channel 2.
|
||||
rx<n>power |INT |received optical power in mW, n is the channel number,
|
||||
| |for example, rx2power stands for rx power of channel 2.
|
||||
tx<n>power |INT |TX output power in mW, n is the channel number,
|
||||
| |for example, tx2power stands for tx power of channel 2.
|
||||
========================================================================
|
||||
"""
|
||||
# check present status
|
||||
if self.port_num < 49: #SFP case
|
||||
sfpd_obj = sff8472Dom()
|
||||
if not self.get_presence() or not sfpd_obj:
|
||||
return {}
|
||||
|
||||
eeprom_ifraw = self.__read_eeprom_specific_bytes(0, SFP_DOM_OFFSET)
|
||||
sfpi_obj = sff8472InterfaceId(eeprom_ifraw)
|
||||
cal_type = sfpi_obj.get_calibration_type()
|
||||
sfpd_obj._calibration_type = cal_type
|
||||
|
||||
offset = SFP_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:
|
||||
dom_temperature_data = sfpd_obj.parse_temperature(
|
||||
dom_temperature_raw, 0)
|
||||
transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value']
|
||||
|
||||
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']
|
||||
|
||||
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']
|
||||
|
||||
else: #QSFP case
|
||||
sfpd_obj = sff8436Dom()
|
||||
sfpi_obj = sff8436InterfaceId()
|
||||
|
||||
if not self.get_presence() or not sfpi_obj or not sfpd_obj:
|
||||
return {}
|
||||
|
||||
transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A')
|
||||
offset = QSFP_DOM_OFFSET
|
||||
offset_xcvr = QSFP_INFO_OFFSET
|
||||
|
||||
# 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 + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH)
|
||||
if qsfp_dom_capability_raw is not None:
|
||||
qspf_dom_capability_data = sfpi_obj.parse_dom_capability(
|
||||
qsfp_dom_capability_raw, 0)
|
||||
else:
|
||||
return None
|
||||
|
||||
dom_temperature_raw = self.__read_eeprom_specific_bytes(
|
||||
(offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH)
|
||||
if dom_temperature_raw is not None:
|
||||
dom_temperature_data = sfpd_obj.parse_temperature(
|
||||
dom_temperature_raw, 0)
|
||||
transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value']
|
||||
|
||||
dom_voltage_raw = self.__read_eeprom_specific_bytes(
|
||||
(offset + QSFP_VOLT_OFFSET), QSFP_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']
|
||||
|
||||
qsfp_dom_rev_raw = self.__read_eeprom_specific_bytes(
|
||||
(offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH)
|
||||
if qsfp_dom_rev_raw is not None:
|
||||
qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0)
|
||||
qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value']
|
||||
|
||||
# The tx_power monitoring is only available on QSFP which compliant with SFF-8636
|
||||
# and claimed that it support tx_power with one indicator bit.
|
||||
dom_channel_monitor_data = {}
|
||||
dom_channel_monitor_raw = None
|
||||
qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['value']
|
||||
if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')):
|
||||
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
|
||||
(offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WIDTH)
|
||||
if dom_channel_monitor_raw is not None:
|
||||
dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(
|
||||
dom_channel_monitor_raw, 0)
|
||||
|
||||
else:
|
||||
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
|
||||
(offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH)
|
||||
if dom_channel_monitor_raw is not None:
|
||||
dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(
|
||||
dom_channel_monitor_raw, 0)
|
||||
transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TX1Power']['value']
|
||||
transceiver_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value']
|
||||
transceiver_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value']
|
||||
transceiver_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value']
|
||||
|
||||
if dom_channel_monitor_raw:
|
||||
transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value']
|
||||
transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value']
|
||||
transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value']
|
||||
transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value']
|
||||
transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value']
|
||||
transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value']
|
||||
transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value']
|
||||
transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value']
|
||||
#End of else
|
||||
|
||||
|
||||
for key in transceiver_dom_info_dict:
|
||||
transceiver_dom_info_dict[key] = self._convert_string_to_num(
|
||||
transceiver_dom_info_dict[key])
|
||||
|
||||
transceiver_dom_info_dict['rx_los'] = self.get_rx_los()
|
||||
transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault()
|
||||
transceiver_dom_info_dict['reset_status'] = self.get_reset_status()
|
||||
transceiver_dom_info_dict['lp_mode'] = self.get_lpmode()
|
||||
|
||||
return transceiver_dom_info_dict
|
||||
|
||||
def get_transceiver_threshold_info(self):
|
||||
"""
|
||||
Retrieves transceiver threshold info of this SFP
|
||||
Returns:
|
||||
A dict which contains following keys/values :
|
||||
========================================================================
|
||||
keys |Value Format |Information
|
||||
---------------------------|---------------|----------------------------
|
||||
temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius.
|
||||
templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius.
|
||||
temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius.
|
||||
templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius.
|
||||
vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV.
|
||||
vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV.
|
||||
vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV.
|
||||
vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV.
|
||||
rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm.
|
||||
rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm.
|
||||
rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm.
|
||||
rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm.
|
||||
txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm.
|
||||
txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm.
|
||||
txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm.
|
||||
txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm.
|
||||
txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA.
|
||||
txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA.
|
||||
txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA.
|
||||
txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA.
|
||||
========================================================================
|
||||
"""
|
||||
# check present status
|
||||
if self.port_num < 49:
|
||||
sfpd_obj = sff8472Dom()
|
||||
|
||||
if not self.get_presence() and not sfpd_obj:
|
||||
return {}
|
||||
|
||||
eeprom_ifraw = self.__read_eeprom_specific_bytes(0, SFP_DOM_OFFSET)
|
||||
sfpi_obj = sff8472InterfaceId(eeprom_ifraw)
|
||||
cal_type = sfpi_obj.get_calibration_type()
|
||||
sfpd_obj._calibration_type = cal_type
|
||||
|
||||
offset = SFP_DOM_OFFSET
|
||||
transceiver_dom_threshold_info_dict = dict.fromkeys(
|
||||
self.threshold_dict_keys, 'N/A')
|
||||
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)
|
||||
|
||||
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']
|
||||
transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value']
|
||||
transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value']
|
||||
transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value']
|
||||
transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data[
|
||||
'data']['VoltageHighWarning']['value']
|
||||
transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value']
|
||||
transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value']
|
||||
transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value']
|
||||
transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value']
|
||||
transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value']
|
||||
transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value']
|
||||
transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value']
|
||||
transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value']
|
||||
transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value']
|
||||
transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value']
|
||||
transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value']
|
||||
transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value']
|
||||
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])
|
||||
|
||||
return transceiver_dom_threshold_info_dict
|
||||
|
||||
|
||||
else:
|
||||
sfpd_obj = sff8436Dom()
|
||||
|
||||
if not self.get_presence() or not sfpd_obj:
|
||||
return {}
|
||||
|
||||
transceiver_dom_threshold_dict = dict.fromkeys(
|
||||
self.threshold_dict_keys, 'N/A')
|
||||
dom_thres_raw = self.__read_eeprom_specific_bytes(
|
||||
QSFP_MODULE_THRESHOLD_OFFSET, QSFP_MODULE_THRESHOLD_WIDTH) if self.get_presence() and sfpd_obj else None
|
||||
|
||||
if dom_thres_raw:
|
||||
module_threshold_values = sfpd_obj.parse_module_threshold_values(
|
||||
dom_thres_raw, 0)
|
||||
module_threshold_data = module_threshold_values.get('data')
|
||||
if module_threshold_data:
|
||||
transceiver_dom_threshold_dict['temphighalarm'] = module_threshold_data['TempHighAlarm']['value']
|
||||
transceiver_dom_threshold_dict['templowalarm'] = module_threshold_data['TempLowAlarm']['value']
|
||||
transceiver_dom_threshold_dict['temphighwarning'] = module_threshold_data['TempHighWarning']['value']
|
||||
transceiver_dom_threshold_dict['templowwarning'] = module_threshold_data['TempLowWarning']['value']
|
||||
transceiver_dom_threshold_dict['vcchighalarm'] = module_threshold_data['VccHighAlarm']['value']
|
||||
transceiver_dom_threshold_dict['vcclowalarm'] = module_threshold_data['VccLowAlarm']['value']
|
||||
transceiver_dom_threshold_dict['vcchighwarning'] = module_threshold_data['VccHighWarning']['value']
|
||||
transceiver_dom_threshold_dict['vcclowwarning'] = module_threshold_data['VccLowWarning']['value']
|
||||
|
||||
dom_thres_raw = self.__read_eeprom_specific_bytes(
|
||||
QSFP_CHANNEL_THRESHOLD_OFFSET, QSFP_CHANNEL_THRESHOLD_WIDTH) if self.get_presence() and sfpd_obj else None
|
||||
channel_threshold_values = sfpd_obj.parse_channel_threshold_values(
|
||||
dom_thres_raw, 0)
|
||||
channel_threshold_data = channel_threshold_values.get('data')
|
||||
if channel_threshold_data:
|
||||
transceiver_dom_threshold_dict['rxpowerhighalarm'] = channel_threshold_data['RxPowerHighAlarm']['value']
|
||||
transceiver_dom_threshold_dict['rxpowerlowalarm'] = channel_threshold_data['RxPowerLowAlarm']['value']
|
||||
transceiver_dom_threshold_dict['rxpowerhighwarning'] = channel_threshold_data['RxPowerHighWarning']['value']
|
||||
transceiver_dom_threshold_dict['rxpowerlowwarning'] = channel_threshold_data['RxPowerLowWarning']['value']
|
||||
transceiver_dom_threshold_dict['txpowerhighalarm'] = "0.0dBm"
|
||||
transceiver_dom_threshold_dict['txpowerlowalarm'] = "0.0dBm"
|
||||
transceiver_dom_threshold_dict['txpowerhighwarning'] = "0.0dBm"
|
||||
transceiver_dom_threshold_dict['txpowerlowwarning'] = "0.0dBm"
|
||||
transceiver_dom_threshold_dict['txbiashighalarm'] = channel_threshold_data['TxBiasHighAlarm']['value']
|
||||
transceiver_dom_threshold_dict['txbiaslowalarm'] = channel_threshold_data['TxBiasLowAlarm']['value']
|
||||
transceiver_dom_threshold_dict['txbiashighwarning'] = channel_threshold_data['TxBiasHighWarning']['value']
|
||||
transceiver_dom_threshold_dict['txbiaslowwarning'] = channel_threshold_data['TxBiasLowWarning']['value']
|
||||
|
||||
for key in transceiver_dom_threshold_dict:
|
||||
transceiver_dom_threshold_dict[key] = self._convert_string_to_num(
|
||||
transceiver_dom_threshold_dict[key])
|
||||
|
||||
return transceiver_dom_threshold_dict
|
||||
|
||||
def get_reset_status(self):
|
||||
"""
|
||||
Retrieves the reset status of SFP
|
||||
@ -725,8 +187,10 @@ class Sfp(SfpBase):
|
||||
rx_path = "{}{}{}{}".format(CPLD_I2C_PATH, cpld_path, '/module_rx_los_', self.port_num)
|
||||
|
||||
rx_los=self._api_helper.read_txt_file(rx_path)
|
||||
if rx_los is None:
|
||||
return False
|
||||
if int(rx_los, 10) == 1:
|
||||
return [True]
|
||||
else:
|
||||
return [False]
|
||||
#status_control_raw = self.__read_eeprom_specific_bytes(
|
||||
# SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH)
|
||||
#if status_control_raw:
|
||||
@ -743,15 +207,18 @@ class Sfp(SfpBase):
|
||||
rx_los_list.append(rx_los_data & 0x02 != 0)
|
||||
rx_los_list.append(rx_los_data & 0x04 != 0)
|
||||
rx_los_list.append(rx_los_data & 0x08 != 0)
|
||||
rx_los = rx_los_list[0] and rx_los_list[1] and rx_los_list[2] and rx_los_list[3]
|
||||
|
||||
return rx_los
|
||||
return rx_los_list
|
||||
else:
|
||||
return [False]*4
|
||||
|
||||
def get_tx_fault(self):
|
||||
"""
|
||||
Retrieves the TX fault status of SFP
|
||||
Returns:
|
||||
A Boolean, True if SFP has TX fault, False if not
|
||||
A list of boolean values, representing the TX fault status
|
||||
of each available channel, value is True if SFP channel
|
||||
has TX fault, False if not.
|
||||
E.g., for a tranceiver with four channels: [False, False, True, False]
|
||||
Note : TX fault status is lached until a call to get_tx_fault or a reset.
|
||||
"""
|
||||
tx_fault = False
|
||||
@ -761,8 +228,10 @@ class Sfp(SfpBase):
|
||||
tx_path = "{}{}{}{}".format(CPLD_I2C_PATH, cpld_path, '/module_tx_fault_', self.port_num)
|
||||
|
||||
tx_fault=self._api_helper.read_txt_file(tx_path)
|
||||
if tx_fault is None:
|
||||
return False
|
||||
if int(tx_fault, 10) == 1:
|
||||
return [True]
|
||||
else:
|
||||
return [False]
|
||||
#status_control_raw = self.__read_eeprom_specific_bytes(
|
||||
# SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH)
|
||||
#if status_control_raw:
|
||||
@ -778,15 +247,19 @@ class Sfp(SfpBase):
|
||||
tx_fault_list.append(tx_fault_data & 0x02 != 0)
|
||||
tx_fault_list.append(tx_fault_data & 0x04 != 0)
|
||||
tx_fault_list.append(tx_fault_data & 0x08 != 0)
|
||||
tx_fault = tx_fault_list[0] and tx_fault_list[1] and tx_fault_list[2] and tx_fault_list[3]
|
||||
return tx_fault_list
|
||||
else:
|
||||
return [False]*4
|
||||
|
||||
return tx_fault
|
||||
|
||||
def get_tx_disable(self):
|
||||
"""
|
||||
Retrieves the tx_disable status of this SFP
|
||||
Returns:
|
||||
A Boolean, True if tx_disable is enabled, False if disabled
|
||||
A list of boolean values, representing the TX disable status
|
||||
of each available channel, value is True if SFP channel
|
||||
is TX disabled, False if not.
|
||||
E.g., for a tranceiver with four channels: [False, False, True, False]
|
||||
"""
|
||||
if self.port_num < 49:
|
||||
tx_disable = False
|
||||
@ -806,10 +279,11 @@ class Sfp(SfpBase):
|
||||
# tx_disable_soft = (sffbase().test_bit(
|
||||
# data, SFP_TX_DISABLE_SOFT_BIT) != 0)
|
||||
# tx_disable = tx_disable_hard | tx_disable_soft
|
||||
if tx_disable is not None:
|
||||
return tx_disable
|
||||
if int(tx_disable, 10)==0:
|
||||
return [False]
|
||||
else:
|
||||
return False
|
||||
return [True]
|
||||
|
||||
else:
|
||||
tx_disable_list = []
|
||||
|
||||
@ -829,8 +303,9 @@ class Sfp(SfpBase):
|
||||
'On' == dom_control_data['data']['TX3Disable']['value'])
|
||||
tx_disable_list.append(
|
||||
'On' == dom_control_data['data']['TX4Disable']['value'])
|
||||
|
||||
return tx_disable_list
|
||||
return tx_disable_list
|
||||
else:
|
||||
return [False]*4
|
||||
|
||||
def get_tx_disable_channel(self):
|
||||
"""
|
||||
@ -841,18 +316,14 @@ class Sfp(SfpBase):
|
||||
As an example, a returned value of 0x5 indicates that channel 0
|
||||
and channel 2 have been disabled.
|
||||
"""
|
||||
if self.port_num < 49:
|
||||
# SFP doesn't support this feature
|
||||
return False
|
||||
else:
|
||||
tx_disable_list = self.get_tx_disable()
|
||||
if tx_disable_list is None:
|
||||
return 0
|
||||
tx_disabled = 0
|
||||
for i in range(len(tx_disable_list)):
|
||||
if tx_disable_list[i]:
|
||||
tx_disabled |= 1 << i
|
||||
return tx_disabled
|
||||
tx_disable_list = self.get_tx_disable()
|
||||
if tx_disable_list is None:
|
||||
return 0
|
||||
tx_disabled = 0
|
||||
for i in range(len(tx_disable_list)):
|
||||
if tx_disable_list[i]:
|
||||
tx_disabled |= 1 << i
|
||||
return tx_disabled
|
||||
|
||||
def get_lpmode(self):
|
||||
"""
|
||||
@ -915,78 +386,6 @@ class Sfp(SfpBase):
|
||||
|
||||
return power_override
|
||||
|
||||
def get_temperature(self):
|
||||
"""
|
||||
Retrieves the temperature of this SFP
|
||||
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")
|
||||
|
||||
def get_voltage(self):
|
||||
"""
|
||||
Retrieves the supply voltage of this SFP
|
||||
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")
|
||||
|
||||
def get_tx_bias(self):
|
||||
"""
|
||||
Retrieves the TX bias current of this SFP
|
||||
Returns:
|
||||
A list of four integer numbers, representing TX bias in mA
|
||||
for channel 0 to channel 4.
|
||||
Ex. ['110.09', '111.12', '108.21', '112.09']
|
||||
"""
|
||||
transceiver_dom_info_dict = self.get_transceiver_bulk_status()
|
||||
|
||||
tx1_bs = transceiver_dom_info_dict.get("tx1bias", "N/A")
|
||||
if self.port_num < 49:
|
||||
return [tx1_bs, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else []
|
||||
|
||||
tx2_bs = transceiver_dom_info_dict.get("tx2bias", "N/A")
|
||||
tx3_bs = transceiver_dom_info_dict.get("tx3bias", "N/A")
|
||||
tx4_bs = transceiver_dom_info_dict.get("tx4bias", "N/A")
|
||||
return [tx1_bs, tx2_bs, tx3_bs, tx4_bs] if transceiver_dom_info_dict else []
|
||||
|
||||
def get_rx_power(self):
|
||||
"""
|
||||
Retrieves the received optical power for this SFP
|
||||
Returns:
|
||||
A list of four integer numbers, representing received optical
|
||||
power in mW for channel 0 to channel 4.
|
||||
Ex. ['1.77', '1.71', '1.68', '1.70']
|
||||
"""
|
||||
transceiver_dom_info_dict = self.get_transceiver_bulk_status()
|
||||
|
||||
rx1_pw = transceiver_dom_info_dict.get("rx1power", "N/A")
|
||||
if self.port_num < 49:
|
||||
return [rx1_pw, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else []
|
||||
rx2_pw = transceiver_dom_info_dict.get("rx2power", "N/A")
|
||||
rx3_pw = transceiver_dom_info_dict.get("rx3power", "N/A")
|
||||
rx4_pw = transceiver_dom_info_dict.get("rx4power", "N/A")
|
||||
return [rx1_pw, rx2_pw, rx3_pw, rx4_pw] if transceiver_dom_info_dict else []
|
||||
|
||||
def get_tx_power(self):
|
||||
"""
|
||||
Retrieves the TX power of this SFP
|
||||
Returns:
|
||||
A list of four integer numbers, representing TX power in mW
|
||||
for channel 0 to channel 4.
|
||||
Ex. ['1.86', '1.86', '1.86', '1.86']
|
||||
"""
|
||||
transceiver_dom_info_dict = self.get_transceiver_bulk_status()
|
||||
tx1_pw = transceiver_dom_info_dict.get("tx1power", "N/A")
|
||||
if self.port_num < 49:
|
||||
return [tx1_pw, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else []
|
||||
tx2_pw = transceiver_dom_info_dict.get("tx2power", "N/A")
|
||||
tx3_pw = transceiver_dom_info_dict.get("tx3power", "N/A")
|
||||
tx4_pw = transceiver_dom_info_dict.get("tx4power", "N/A")
|
||||
return [tx1_pw, tx2_pw, tx3_pw, tx4_pw]
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset SFP and return all user module settings to their default srate.
|
||||
@ -1000,15 +399,15 @@ class Sfp(SfpBase):
|
||||
cpld_path = self._cpld_mapping[cpld_i]
|
||||
reset_path = "{}{}{}{}".format(CPLD_I2C_PATH, cpld_path, '/module_reset_', self.port_num)
|
||||
ret = self._api_helper.write_txt_file(reset_path, 1)
|
||||
|
||||
if ret is not True:
|
||||
time.sleep(0.01)
|
||||
ret = self.self._api_helper.write_txt_file(reset_path, 0)
|
||||
time.sleep(0.2)
|
||||
return ret
|
||||
else:
|
||||
return False
|
||||
|
||||
if ret is not True:
|
||||
return ret
|
||||
|
||||
time.sleep(0.01)
|
||||
ret = self._api_helper.write_txt_file(reset_path, 0)
|
||||
time.sleep(0.2)
|
||||
|
||||
return ret
|
||||
|
||||
def tx_disable(self, tx_disable):
|
||||
"""
|
||||
@ -1120,7 +519,7 @@ class Sfp(SfpBase):
|
||||
if self.port_num < 49:
|
||||
return False # SFP doesn't support this feature
|
||||
else:
|
||||
if lpmode is True:
|
||||
if lpmode:
|
||||
self.set_power_override(True, True)
|
||||
else:
|
||||
self.set_power_override(False, False)
|
||||
@ -1195,28 +594,27 @@ class Sfp(SfpBase):
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the device
|
||||
Returns:
|
||||
string: Model/part number of device
|
||||
"""
|
||||
transceiver_dom_info_dict = self.get_transceiver_info()
|
||||
return transceiver_dom_info_dict.get("model", "N/A")
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the device
|
||||
Returns:
|
||||
string: Serial number of device
|
||||
"""
|
||||
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 self.get_transceiver_bulk_status()
|
||||
return self.get_presence()
|
||||
|
||||
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.port_num
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return True
|
||||
|
@ -15,22 +15,53 @@ try:
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
PSU_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/"
|
||||
PSU_HWMON_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 11,
|
||||
"addr": "58"
|
||||
},
|
||||
1: {
|
||||
"num": 12,
|
||||
"addr": "5b"
|
||||
},
|
||||
}
|
||||
|
||||
PSU_CPLD_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 11,
|
||||
"addr": "50"
|
||||
},
|
||||
1: {
|
||||
"num": 12,
|
||||
"addr": "53"
|
||||
},
|
||||
}
|
||||
|
||||
THERMAL_NAME_LIST = ["Temp sensor 1", "Temp sensor 2",
|
||||
"Temp sensor 3", "Temp sensor 4"]
|
||||
|
||||
PSU_THERMAL_NAME_LIST = ["PSU-1 temp sensor 1", "PSU-2 temp sensor 2"]
|
||||
|
||||
SYSFS_PATH = "/sys/bus/i2c/devices"
|
||||
|
||||
class Thermal(ThermalBase):
|
||||
"""Platform-specific Thermal class"""
|
||||
|
||||
THERMAL_NAME_LIST = []
|
||||
SYSFS_PATH = "/sys/bus/i2c/devices"
|
||||
|
||||
def __init__(self, thermal_index=0):
|
||||
def __init__(self, thermal_index=0, is_psu=False, psu_index=0):
|
||||
self.index = thermal_index
|
||||
self.is_psu = is_psu
|
||||
self.psu_index = psu_index
|
||||
|
||||
# Add thermal name
|
||||
self.THERMAL_NAME_LIST.append("Temp sensor 1")
|
||||
self.THERMAL_NAME_LIST.append("Temp sensor 2")
|
||||
self.THERMAL_NAME_LIST.append("Temp sensor 3")
|
||||
self.THERMAL_NAME_LIST.append("Temp sensor 4")
|
||||
|
||||
if self.is_psu:
|
||||
psu_i2c_bus = PSU_HWMON_I2C_MAPPING[psu_index]["num"]
|
||||
psu_i2c_addr = PSU_HWMON_I2C_MAPPING[psu_index]["addr"]
|
||||
self.psu_hwmon_path = PSU_I2C_PATH.format(psu_i2c_bus,
|
||||
psu_i2c_addr)
|
||||
psu_i2c_bus = PSU_CPLD_I2C_MAPPING[psu_index]["num"]
|
||||
psu_i2c_addr = PSU_CPLD_I2C_MAPPING[psu_index]["addr"]
|
||||
self.cpld_path = PSU_I2C_PATH.format(psu_i2c_bus, psu_i2c_addr)
|
||||
|
||||
# Set hwmon path
|
||||
i2c_path = {
|
||||
0: "18-004b/hwmon/hwmon*/",
|
||||
@ -38,9 +69,9 @@ class Thermal(ThermalBase):
|
||||
2: "20-0049/hwmon/hwmon*/",
|
||||
3: "21-004a/hwmon/hwmon*/"
|
||||
}.get(self.index, None)
|
||||
|
||||
self.hwmon_path = "{}/{}".format(self.SYSFS_PATH, i2c_path)
|
||||
self.ss_key = self.THERMAL_NAME_LIST[self.index]
|
||||
|
||||
self.hwmon_path = "{}/{}".format(SYSFS_PATH, i2c_path)
|
||||
self.ss_key = THERMAL_NAME_LIST[self.index]
|
||||
self.ss_index = 1
|
||||
|
||||
def __read_txt_file(self, file_path):
|
||||
@ -51,20 +82,23 @@ class Thermal(ThermalBase):
|
||||
return data
|
||||
except IOError as e:
|
||||
pass
|
||||
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def __get_temp(self, temp_file):
|
||||
temp_file_path = os.path.join(self.hwmon_path, temp_file)
|
||||
if not self.is_psu:
|
||||
temp_file_path = os.path.join(self.hwmon_path, temp_file)
|
||||
else:
|
||||
temp_file_path = temp_file
|
||||
raw_temp = self.__read_txt_file(temp_file_path)
|
||||
if raw_temp is not None:
|
||||
return float(raw_temp)/1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
return 0
|
||||
|
||||
def __set_threshold(self, file_name, temperature):
|
||||
if self.is_psu:
|
||||
return True
|
||||
temp_file_path = os.path.join(self.hwmon_path, file_name)
|
||||
for filename in glob.glob(temp_file_path):
|
||||
try:
|
||||
@ -73,6 +107,8 @@ class Thermal(ThermalBase):
|
||||
return True
|
||||
except IOError as e:
|
||||
print("IOError")
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def get_temperature(self):
|
||||
@ -82,7 +118,11 @@ class Thermal(ThermalBase):
|
||||
A float number of current temperature in Celsius up to nearest thousandth
|
||||
of one degree Celsius, e.g. 30.125
|
||||
"""
|
||||
temp_file = "temp{}_input".format(self.ss_index)
|
||||
if not self.is_psu:
|
||||
temp_file = "temp{}_input".format(self.ss_index)
|
||||
else:
|
||||
temp_file = self.psu_hwmon_path + "psu_temp1_input"
|
||||
|
||||
return self.__get_temp(temp_file)
|
||||
|
||||
def get_high_threshold(self):
|
||||
@ -92,6 +132,9 @@ class Thermal(ThermalBase):
|
||||
A float number, the high threshold temperature of thermal in Celsius
|
||||
up to nearest thousandth of one degree Celsius, e.g. 30.125
|
||||
"""
|
||||
if self.is_psu:
|
||||
return 80
|
||||
|
||||
temp_file = "temp{}_max".format(self.ss_index)
|
||||
return self.__get_temp(temp_file)
|
||||
|
||||
@ -116,7 +159,10 @@ class Thermal(ThermalBase):
|
||||
Returns:
|
||||
string: The name of the thermal device
|
||||
"""
|
||||
return self.THERMAL_NAME_LIST[self.index]
|
||||
if self.is_psu:
|
||||
return PSU_THERMAL_NAME_LIST[self.psu_index]
|
||||
else:
|
||||
return THERMAL_NAME_LIST[self.index]
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
@ -124,6 +170,9 @@ class Thermal(ThermalBase):
|
||||
Returns:
|
||||
bool: True if Thermal is present, False if not
|
||||
"""
|
||||
if self.is_psu:
|
||||
val = self.__read_txt_file(self.cpld_path + "psu_present")
|
||||
return int(val, 10) == 1
|
||||
temp_file = "temp{}_input".format(self.ss_index)
|
||||
temp_file_path = os.path.join(self.hwmon_path, temp_file)
|
||||
raw_txt = self.__read_txt_file(temp_file_path)
|
||||
@ -138,11 +187,49 @@ class Thermal(ThermalBase):
|
||||
Returns:
|
||||
A boolean value, True if device is operating properly, False if not
|
||||
"""
|
||||
if self.is_psu:
|
||||
temp_file = self.psu_hwmon_path + "psu_temp_fault"
|
||||
return self.get_presence() and (not int(
|
||||
self.__read_txt_file(temp_file)))
|
||||
|
||||
file_str = "temp{}_input".format(self.ss_index)
|
||||
file_path = os.path.join(self.hwmon_path, file_str)
|
||||
raw_txt = self.__read_txt_file(file_path)
|
||||
if raw_txt is None:
|
||||
return False
|
||||
else:
|
||||
else:
|
||||
return int(raw_txt) != 0
|
||||
|
||||
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_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.index+1
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Retrieves whether thermal module is replaceable
|
||||
Returns:
|
||||
A boolean value, True if replaceable, False if not
|
||||
"""
|
||||
return False
|
||||
|
@ -0,0 +1,15 @@
|
||||
{
|
||||
"services_to_ignore": [],
|
||||
"devices_to_ignore": [
|
||||
"asic",
|
||||
"psu.temperature"
|
||||
|
||||
],
|
||||
"user_defined_checkers": [],
|
||||
"polling_interval": 60,
|
||||
"led_color": {
|
||||
"fault": "STATUS_LED_COLOR_AMBER",
|
||||
"normal": "STATUS_LED_COLOR_GREEN",
|
||||
"booting": "STATUS_LED_COLOR_GREEN"
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
{
|
||||
|
||||
"XCVR":
|
||||
{
|
||||
"xcvr_present":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap-SFP": {"1":true, "0":false },
|
||||
"valmap-SFP28": {"1":true, "0":false },
|
||||
"valmap-QSFP28": {"1":true, "0":false}
|
||||
}
|
||||
}
|
||||
},
|
||||
"PSU":
|
||||
{
|
||||
"psu_present":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": { "1":true, "0":false }
|
||||
}
|
||||
},
|
||||
|
||||
"psu_power_good":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": { "1": true, "0":false }
|
||||
}
|
||||
},
|
||||
|
||||
"psu_fan_dir":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": { "F2B":"EXHAUST", "B2F":"INTAKE" }
|
||||
}
|
||||
},
|
||||
|
||||
"PSU_FAN_MAX_SPEED":"18000"
|
||||
},
|
||||
|
||||
"FAN":
|
||||
{
|
||||
"direction":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": {"1":"INTAKE", "0":"EXHAUST"}
|
||||
}
|
||||
},
|
||||
|
||||
"present":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": {"1":true, "0":false}
|
||||
}
|
||||
},
|
||||
|
||||
"duty_cycle_to_pwm": "lambda dc: ((dc*100)/625 -1)",
|
||||
|
||||
"pwm_to_duty_cycle": "lambda pwm: (((pwm+1)*625+75)/100)"
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -16,5 +16,10 @@ class board(eeprom_tlvinfo.TlvInfoDecoder):
|
||||
_TLV_INFO_MAX_LEN = 256
|
||||
|
||||
def __init__(self, name, path, cpld_root, ro):
|
||||
self.eeprom_path = "/sys/bus/i2c/devices/0-0056/eeprom"
|
||||
exists = os.path.isfile('/sys/bus/i2c/devices/0-0056/eeprom')
|
||||
if (exists is True):
|
||||
self.eeprom_path = "/sys/bus/i2c/devices/0-0056/eeprom"
|
||||
else:
|
||||
self.eeprom_path = "/sys/bus/i2c/devices/0-0057/eeprom"
|
||||
|
||||
super(board, self).__init__(self.eeprom_path, 0, '', True)
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"skip_ledd": true,
|
||||
"skip_thermalctld": true
|
||||
"skip_pcied": true
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,2 @@
|
||||
__all__ = [ "platform", "chassis", "sfp", "eeprom", "component", "psu", "thermal", "fan", "fan_drawer" ]
|
||||
from . import platform
|
@ -0,0 +1,264 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the Chassis information which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
try:
|
||||
from sonic_platform_base.chassis_base import ChassisBase
|
||||
from .event import SfpEvent
|
||||
from sonic_py_common import device_info
|
||||
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
NUM_FAN_TRAY = 6
|
||||
NUM_PSU = 2
|
||||
NUM_THERMAL = 4
|
||||
NUM_PORT = 58
|
||||
NUM_COMPONENT = 4
|
||||
|
||||
HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/"
|
||||
PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/"
|
||||
REBOOT_CAUSE_FILE = "reboot-cause.txt"
|
||||
PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt"
|
||||
HOST_CHK_CMD = "which systemctl > /dev/null 2>&1"
|
||||
SYSLED_FNODE= "/sys/class/leds/accton_as7326_56x_led::diag/brightness"
|
||||
SYSLED_MODES = {
|
||||
"0" : "STATUS_LED_COLOR_OFF",
|
||||
"1" : "STATUS_LED_COLOR_GREEN",
|
||||
"3" : "STATUS_LED_COLOR_RED",
|
||||
"5" : "STATUS_LED_COLOR_GREEN_BLINK"
|
||||
}
|
||||
|
||||
|
||||
class Chassis(ChassisBase):
|
||||
"""Platform-specific Chassis class"""
|
||||
|
||||
def __init__(self):
|
||||
ChassisBase.__init__(self)
|
||||
self.config_data = {}
|
||||
(self.platform, self.hwsku) = device_info.get_platform_and_hwsku()
|
||||
|
||||
self.__initialize_fan()
|
||||
self.__initialize_psu()
|
||||
self.__initialize_thermals()
|
||||
self.__initialize_components()
|
||||
self.__initialize_sfp()
|
||||
self.__initialize_eeprom()
|
||||
|
||||
def __initialize_sfp(self):
|
||||
from sonic_platform.sfp import Sfp
|
||||
for index in range(NUM_PORT):
|
||||
sfp = Sfp(index)
|
||||
self._sfp_list.append(sfp)
|
||||
self._sfpevent = SfpEvent(self._sfp_list)
|
||||
self.sfp_module_initialized = True
|
||||
|
||||
def __initialize_fan(self):
|
||||
from sonic_platform.fan_drawer import FanDrawer
|
||||
for fant_index in range(NUM_FAN_TRAY):
|
||||
fandrawer = FanDrawer(fant_index)
|
||||
self._fan_drawer_list.append(fandrawer)
|
||||
self._fan_list.extend(fandrawer._fan_list)
|
||||
|
||||
def __initialize_psu(self):
|
||||
from sonic_platform.psu import Psu
|
||||
for index in range(NUM_PSU):
|
||||
psu = Psu(index)
|
||||
self._psu_list.append(psu)
|
||||
|
||||
def __initialize_thermals(self):
|
||||
from sonic_platform.thermal import Thermal
|
||||
for index in range(NUM_THERMAL):
|
||||
thermal = Thermal(index)
|
||||
self._thermal_list.append(thermal)
|
||||
|
||||
def __initialize_eeprom(self):
|
||||
from sonic_platform.eeprom import Tlv
|
||||
self._eeprom = Tlv()
|
||||
|
||||
def __initialize_components(self):
|
||||
from sonic_platform.component import Component
|
||||
for index in range(NUM_COMPONENT):
|
||||
component = Component(index)
|
||||
self._component_list.append(component)
|
||||
|
||||
def __initialize_watchdog(self):
|
||||
self._watchdog = Watchdog()
|
||||
|
||||
def __is_host(self):
|
||||
return os.system(HOST_CHK_CMD) == 0
|
||||
|
||||
def __read_txt_file(self, file_path):
|
||||
try:
|
||||
with open(file_path, 'r') as fd:
|
||||
return fd.read().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_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
return self._eeprom.get_product_name()
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the Chassis
|
||||
Returns:
|
||||
bool: True if Chassis is present, False if not
|
||||
"""
|
||||
return True
|
||||
|
||||
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_base_mac(self):
|
||||
"""
|
||||
Retrieves the base MAC address for the chassis
|
||||
Returns:
|
||||
A string containing the MAC address in the format
|
||||
'XX:XX:XX:XX:XX:XX'
|
||||
"""
|
||||
return self._eeprom.get_mac()
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the device
|
||||
Returns:
|
||||
string: Model/part number of device
|
||||
"""
|
||||
return self._eeprom.get_pn()
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the hardware serial number for the chassis
|
||||
Returns:
|
||||
A string containing the hardware serial number for this chassis.
|
||||
"""
|
||||
return self._eeprom.get_serial()
|
||||
|
||||
def get_system_eeprom_info(self):
|
||||
"""
|
||||
Retrieves the full content of system EEPROM information for the chassis
|
||||
Returns:
|
||||
A dictionary where keys are the type code defined in
|
||||
OCP ONIE TlvInfo EEPROM format and values are their corresponding
|
||||
values.
|
||||
"""
|
||||
return self._eeprom.get_eeprom()
|
||||
|
||||
def get_reboot_cause(self):
|
||||
"""
|
||||
Retrieves the cause of the previous reboot
|
||||
Returns:
|
||||
A tuple (string, string) where the first element is a string
|
||||
containing the cause of the previous reboot. This string must be
|
||||
one of the predefined strings in this class. If the first string
|
||||
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
|
||||
to pass a description of the reboot cause.
|
||||
"""
|
||||
description = 'None'
|
||||
|
||||
reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) if self.__is_host(
|
||||
) else (PMON_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE)
|
||||
prev_reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + PREV_REBOOT_CAUSE_FILE) if self.__is_host(
|
||||
) else (PMON_REBOOT_CAUSE_PATH + PREV_REBOOT_CAUSE_FILE)
|
||||
|
||||
sw_reboot_cause = self.__read_txt_file(reboot_cause_path) or "Unknown"
|
||||
prev_sw_reboot_cause = self.__read_txt_file(prev_reboot_cause_path) or "Unknown"
|
||||
|
||||
if sw_reboot_cause != "Unknown":
|
||||
reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE
|
||||
description = sw_reboot_cause
|
||||
elif prev_reboot_cause_path != "Unknown":
|
||||
reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE
|
||||
description = prev_sw_reboot_cause
|
||||
|
||||
return (reboot_cause, description)
|
||||
|
||||
def get_change_event(self, timeout=0):
|
||||
# SFP event
|
||||
if not self.sfp_module_initialized:
|
||||
self.__initialize_sfp()
|
||||
return self._sfpevent.get_sfp_event(timeout)
|
||||
|
||||
def get_sfp(self, index):
|
||||
"""
|
||||
Retrieves sfp represented by (1-based) index <index>
|
||||
Args:
|
||||
index: An integer, the index (1-based) of the sfp to retrieve.
|
||||
The index should be the sequence of a physical port in a chassis,
|
||||
starting from 1.
|
||||
For example, 1 for Ethernet0, 2 for Ethernet4 and so on.
|
||||
Returns:
|
||||
An object dervied from SfpBase representing the specified sfp
|
||||
"""
|
||||
sfp = None
|
||||
if not self.sfp_module_initialized:
|
||||
self.__initialize_sfp()
|
||||
|
||||
try:
|
||||
# The index will start from 1
|
||||
sfp = self._sfp_list[index-1]
|
||||
except IndexError:
|
||||
sys.stderr.write("SFP index {} out of range (1-{})\n".format(
|
||||
index, len(self._sfp_list)))
|
||||
return sfp
|
||||
|
||||
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 initizalize_system_led(self):
|
||||
return True
|
||||
|
||||
def get_status_led(self):
|
||||
val = self.__read_txt_file(SYSLED_FNODE)
|
||||
return SYSLED_MODES[val] if val in SYSLED_MODES else "UNKNOWN"
|
||||
|
||||
def set_status_led(self, color):
|
||||
mode = None
|
||||
for key, val in SYSLED_MODES.items():
|
||||
if val == color:
|
||||
mode = key
|
||||
break
|
||||
if mode is None:
|
||||
return False
|
||||
else:
|
||||
return self.__write_txt_file(SYSLED_FNODE, mode)
|
@ -0,0 +1,161 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Component contains an implementation of SONiC Platform Base API and
|
||||
# provides the components firmware management function
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
from sonic_platform_base.component_base import ComponentBase
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
CPLD_ADDR_MAPPING = {
|
||||
"CPLD-1": "18-0060",
|
||||
"CPLD-2": "12-0062",
|
||||
"CPLD-3": "19-0064",
|
||||
}
|
||||
SYSFS_PATH = "/sys/bus/i2c/devices/"
|
||||
BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version"
|
||||
COMPONENT_NAME_LIST = ["CPLD-1", "CPLD-2", "CPLD-3", "BIOS"]
|
||||
COMPONENT_DES_LIST = [
|
||||
"CPLD-1", "CPLD-2", "CPLD-3", "Basic Input/Output System"
|
||||
]
|
||||
|
||||
|
||||
class Component(ComponentBase):
|
||||
"""Platform-specific Component class"""
|
||||
|
||||
DEVICE_TYPE = "component"
|
||||
|
||||
def __init__(self, component_index=0):
|
||||
ComponentBase.__init__(self)
|
||||
self.index = component_index
|
||||
self.name = self.get_name()
|
||||
|
||||
def __get_bios_version(self):
|
||||
# Retrieves the BIOS firmware version
|
||||
try:
|
||||
with open(BIOS_VERSION_PATH, 'r') as fd:
|
||||
bios_version = fd.read()
|
||||
return bios_version.strip()
|
||||
except Exception as e:
|
||||
return None
|
||||
|
||||
def __get_sysfs_value(self, addr, name):
|
||||
# Retrieves the cpld register value
|
||||
try:
|
||||
with open(SYSFS_PATH + addr + '/' + name, 'r') as fd:
|
||||
return fd.read().strip()
|
||||
except Exception as e:
|
||||
return None
|
||||
|
||||
def __get_cpld_version(self):
|
||||
# Retrieves the CPLD firmware version
|
||||
cpld_version = dict()
|
||||
for cpld_name in CPLD_ADDR_MAPPING:
|
||||
try:
|
||||
cpld_addr = CPLD_ADDR_MAPPING[cpld_name]
|
||||
cpld_version_raw = self.__get_sysfs_value(cpld_addr, "version")
|
||||
cpld_version[cpld_name] = "{}".format(
|
||||
int(cpld_version_raw, 16))
|
||||
except Exception as e:
|
||||
cpld_version[cpld_name] = 'None'
|
||||
|
||||
return cpld_version
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the component
|
||||
Returns:
|
||||
A string containing the name of the component
|
||||
"""
|
||||
return COMPONENT_NAME_LIST[self.index]
|
||||
|
||||
def get_description(self):
|
||||
"""
|
||||
Retrieves the description of the component
|
||||
Returns:
|
||||
A string containing the description of the component
|
||||
"""
|
||||
return COMPONENT_DES_LIST[self.index]
|
||||
|
||||
def get_firmware_version(self):
|
||||
"""
|
||||
Retrieves the firmware version of module
|
||||
Returns:
|
||||
string: The firmware versions of the module
|
||||
"""
|
||||
fw_version = None
|
||||
|
||||
if self.name == "BIOS":
|
||||
fw_version = self.__get_bios_version()
|
||||
elif "CPLD" in self.name:
|
||||
cpld_version = self.__get_cpld_version()
|
||||
fw_version = cpld_version.get(self.name)
|
||||
|
||||
return fw_version
|
||||
|
||||
def install_firmware(self, image_path):
|
||||
"""
|
||||
Install firmware to module
|
||||
Args:
|
||||
image_path: A string, path to firmware image
|
||||
Returns:
|
||||
A boolean, True if install successfully, False if not
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the device
|
||||
Returns:
|
||||
bool: True if device 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
|
||||
|
@ -0,0 +1,139 @@
|
||||
try:
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo
|
||||
if sys.version_info[0] >= 3:
|
||||
from io import StringIO
|
||||
else:
|
||||
from cStringIO import StringIO
|
||||
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):
|
||||
|
||||
EEPROM_DECODE_HEADLINES = 6
|
||||
|
||||
def __init__(self):
|
||||
#self._eeprom_path = "/sys/bus/i2c/devices/0-0056/eeprom"
|
||||
exists = os.path.isfile('/sys/bus/i2c/devices/0-0056/eeprom')
|
||||
if (exists is True):
|
||||
self._eeprom_path = "/sys/bus/i2c/devices/0-0056/eeprom"
|
||||
else:
|
||||
self._eeprom_path = "/sys/bus/i2c/devices/0-0057/eeprom"
|
||||
|
||||
super(Tlv, self).__init__(self._eeprom_path, 0, '', True)
|
||||
self._eeprom = self._load_eeprom()
|
||||
|
||||
def __parse_output(self, decode_output):
|
||||
decode_output.replace('\0', '')
|
||||
lines = decode_output.split('\n')
|
||||
lines = lines[self.EEPROM_DECODE_HEADLINES:]
|
||||
_eeprom_info_dict = dict()
|
||||
|
||||
for line in lines:
|
||||
try:
|
||||
match = re.search('(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)',
|
||||
line)
|
||||
if match is not None:
|
||||
idx = match.group(1)
|
||||
value = match.group(3).rstrip('\0')
|
||||
|
||||
_eeprom_info_dict[idx] = value
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return _eeprom_info_dict
|
||||
|
||||
def _load_eeprom(self):
|
||||
original_stdout = sys.stdout
|
||||
sys.stdout = StringIO()
|
||||
try:
|
||||
self.read_eeprom_db()
|
||||
except Exception:
|
||||
decode_output = sys.stdout.getvalue()
|
||||
sys.stdout = original_stdout
|
||||
return self.__parse_output(decode_output)
|
||||
|
||||
status = self.check_status()
|
||||
if 'ok' not in status:
|
||||
return False
|
||||
|
||||
if not os.path.exists(CACHE_ROOT):
|
||||
try:
|
||||
os.makedirs(CACHE_ROOT)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
#
|
||||
# only the eeprom classes that inherit from eeprom_base
|
||||
# support caching. Others will work normally
|
||||
#
|
||||
try:
|
||||
self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
e = self.read_eeprom()
|
||||
if e is None:
|
||||
return 0
|
||||
|
||||
try:
|
||||
self.update_cache(e)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self.decode_eeprom(e)
|
||||
decode_output = sys.stdout.getvalue()
|
||||
sys.stdout = original_stdout
|
||||
|
||||
(is_valid, valid_crc) = self.is_checksum_valid(e)
|
||||
if not is_valid:
|
||||
return False
|
||||
|
||||
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._valid_tlv(self._eeprom)
|
||||
|
||||
def get_pn(self):
|
||||
return self._eeprom.get('0x22', NULL)
|
||||
|
||||
def get_serial(self):
|
||||
return self._eeprom.get('0x23', NULL)
|
||||
|
||||
def get_mac(self):
|
||||
return self._eeprom.get('0x24', NULL)
|
||||
|
||||
def get_product_name(self):
|
||||
return self._eeprom.get('0x21', NULL)
|
@ -0,0 +1,60 @@
|
||||
try:
|
||||
import time
|
||||
from sonic_py_common.logger import Logger
|
||||
except ImportError as e:
|
||||
raise ImportError(repr(e) + " - required module not found")
|
||||
|
||||
POLL_INTERVAL_IN_SEC = 1
|
||||
|
||||
class SfpEvent:
|
||||
''' Listen to insert/remove sfp events '''
|
||||
|
||||
def __init__(self, sfp_list):
|
||||
self._sfp_list = sfp_list
|
||||
self._logger = Logger()
|
||||
self._sfp_change_event_data = {'present': 0}
|
||||
|
||||
def get_presence_bitmap(self):
|
||||
bitmap = 0
|
||||
for sfp in self._sfp_list:
|
||||
modpres = sfp.get_presence()
|
||||
i=sfp.port_num-1
|
||||
if modpres:
|
||||
bitmap = bitmap | (1 << i)
|
||||
return bitmap
|
||||
|
||||
def get_sfp_event(self, timeout=2000):
|
||||
port_dict = {}
|
||||
change_dict = {}
|
||||
change_dict['sfp'] = port_dict
|
||||
|
||||
if timeout < 1000:
|
||||
cd_ms = 1000
|
||||
else:
|
||||
cd_ms = timeout
|
||||
|
||||
while cd_ms > 0:
|
||||
bitmap = self.get_presence_bitmap()
|
||||
changed_ports = self._sfp_change_event_data['present'] ^ bitmap
|
||||
if changed_ports != 0:
|
||||
break
|
||||
time.sleep(POLL_INTERVAL_IN_SEC)
|
||||
# timeout=0 means wait for event forever
|
||||
if timeout != 0:
|
||||
cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000
|
||||
|
||||
if changed_ports != 0:
|
||||
for sfp in self._sfp_list:
|
||||
i=sfp.port_num-1
|
||||
if (changed_ports & (1 << i)):
|
||||
if (bitmap & (1 << i)) == 0:
|
||||
port_dict[i+1] = '0'
|
||||
else:
|
||||
port_dict[i+1] = '1'
|
||||
|
||||
|
||||
# Update the cache dict
|
||||
self._sfp_change_event_data['present'] = bitmap
|
||||
return True, change_dict
|
||||
else:
|
||||
return True, change_dict
|
270
device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py
Normal file
270
device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py
Normal file
@ -0,0 +1,270 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the fan status which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
from sonic_platform_base.fan_base import FanBase
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
FAN_MAX_RPM = 25500
|
||||
PSU_FAN_MAX_RPM = 25500
|
||||
SPEED_TOLERANCE = 15
|
||||
CPLD_I2C_PATH = "/sys/bus/i2c/devices/11-0066/fan"
|
||||
PSU_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/"
|
||||
PSU_HWMON_I2C_MAPPING = {
|
||||
0: {
|
||||
"bus": 17,
|
||||
"addr": "59"
|
||||
},
|
||||
1: {
|
||||
"bus": 13,
|
||||
"addr": "5b"
|
||||
},
|
||||
}
|
||||
|
||||
PSU_CPLD_I2C_MAPPING = {
|
||||
0: {
|
||||
"bus": 17,
|
||||
"addr": "51"
|
||||
},
|
||||
1: {
|
||||
"bus": 13,
|
||||
"addr": "53"
|
||||
},
|
||||
}
|
||||
|
||||
FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R",
|
||||
"FAN-3F", "FAN-3R", "FAN-4F", "FAN-4R",
|
||||
"FAN-5F", "FAN-5R", "FAN-6F", "FAN-6R"]
|
||||
|
||||
class Fan(FanBase):
|
||||
"""Platform-specific Fan class"""
|
||||
|
||||
def __init__(self,
|
||||
fan_tray_index,
|
||||
fan_index=0,
|
||||
is_psu_fan=False,
|
||||
psu_index=0):
|
||||
self.fan_index = fan_index
|
||||
self.fan_tray_index = fan_tray_index
|
||||
self.is_psu_fan = is_psu_fan
|
||||
self.psu_index = psu_index
|
||||
|
||||
if self.is_psu_fan:
|
||||
psu_i2c_bus = PSU_HWMON_I2C_MAPPING[psu_index]["bus"]
|
||||
psu_i2c_addr = PSU_HWMON_I2C_MAPPING[psu_index]["addr"]
|
||||
self.psu_hwmon_path = PSU_I2C_PATH.format(psu_i2c_bus,
|
||||
psu_i2c_addr)
|
||||
psu_i2c_bus = PSU_CPLD_I2C_MAPPING[psu_index]["bus"]
|
||||
psu_i2c_addr = PSU_CPLD_I2C_MAPPING[psu_index]["addr"]
|
||||
self.cpld_path = PSU_I2C_PATH.format(psu_i2c_bus, psu_i2c_addr)
|
||||
|
||||
FanBase.__init__(self)
|
||||
|
||||
def __read_txt_file(self, file_path):
|
||||
try:
|
||||
with open(file_path, 'r') as fd:
|
||||
return fd.read().strip()
|
||||
except IOError:
|
||||
pass
|
||||
return ""
|
||||
|
||||
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_direction(self):
|
||||
"""
|
||||
Retrieves the direction of fan
|
||||
Returns:
|
||||
A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST
|
||||
depending on fan direction
|
||||
"""
|
||||
if not self.is_psu_fan:
|
||||
val = self.__read_txt_file(
|
||||
CPLD_I2C_PATH + str(self.fan_tray_index+1) + "_direction")
|
||||
direction = self.FAN_DIRECTION_EXHAUST if (
|
||||
val == "0") else self.FAN_DIRECTION_INTAKE
|
||||
else:
|
||||
val = self.__read_txt_file(self.psu_hwmon_path + "psu_fan_dir")
|
||||
direction = self.FAN_DIRECTION_EXHAUST if (
|
||||
val == "F2B") else self.FAN_DIRECTION_INTAKE
|
||||
return direction
|
||||
|
||||
def get_speed(self):
|
||||
"""
|
||||
Retrieves the speed of fan as a percentage of full speed
|
||||
Returns:
|
||||
An integer, the percentage of full fan speed, in the range 0 (off)
|
||||
to 100 (full speed)
|
||||
"""
|
||||
speed = 0
|
||||
if self.is_psu_fan:
|
||||
speed = self.__read_txt_file(
|
||||
self.psu_hwmon_path + "psu_fan1_speed_rpm")
|
||||
speed = (int(speed, 10)) * 100 / PSU_FAN_MAX_RPM
|
||||
speed = 100 if (speed > 100) else speed
|
||||
elif self.get_presence():
|
||||
speed = self.__read_txt_file(CPLD_I2C_PATH + str(
|
||||
self.fan_index * 10 + self.fan_tray_index + 1) + "_input")
|
||||
speed = (int(speed, 10)) * 100 / FAN_MAX_RPM
|
||||
speed = 100 if (speed > 100) else speed
|
||||
return int(speed)
|
||||
|
||||
def get_target_speed(self):
|
||||
"""
|
||||
Retrieves the target (expected) speed of the fan
|
||||
Returns:
|
||||
An integer, the percentage of full fan speed, in the range 0 (off)
|
||||
to 100 (full speed)
|
||||
Note:
|
||||
speed_pc = pwm_target/255*100
|
||||
0 : when PWM mode is use
|
||||
pwm : when pwm mode is not use
|
||||
"""
|
||||
return self.get_speed()
|
||||
|
||||
def get_speed_tolerance(self):
|
||||
"""
|
||||
Retrieves the speed tolerance of the fan
|
||||
Returns:
|
||||
An integer, the percentage of variance from target speed which is
|
||||
considered tolerable
|
||||
"""
|
||||
return SPEED_TOLERANCE
|
||||
|
||||
def set_speed(self, speed):
|
||||
"""
|
||||
Sets the fan speed
|
||||
Args:
|
||||
speed: An integer, the percentage of full fan speed to set fan to,
|
||||
in the range 0 (off) to 100 (full speed)
|
||||
Returns:
|
||||
A boolean, True if speed is set successfully, False if not
|
||||
"""
|
||||
|
||||
if not self.is_psu_fan and self.get_presence():
|
||||
return self.__write_txt_file(
|
||||
CPLD_I2C_PATH + "_duty_cycle_percentage", int(speed))
|
||||
|
||||
return False
|
||||
|
||||
def set_status_led(self, color):
|
||||
"""
|
||||
Sets the state of the fan module status LED
|
||||
Args:
|
||||
color: A string representing the color with which to set the
|
||||
fan module status LED
|
||||
Returns:
|
||||
bool: True if status LED state is set successfully, False if not
|
||||
"""
|
||||
return False #Not supported
|
||||
|
||||
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
|
||||
"""
|
||||
status=self.get_presence()
|
||||
if status is None:
|
||||
return self.STATUS_LED_COLOR_OFF
|
||||
|
||||
return {
|
||||
1: self.STATUS_LED_COLOR_GREEN,
|
||||
0: self.STATUS_LED_COLOR_RED
|
||||
}.get(status, self.STATUS_LED_COLOR_OFF)
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
fan_name = FAN_NAME_LIST[self.fan_tray_index*2 + self.fan_index] \
|
||||
if not self.is_psu_fan \
|
||||
else "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1)
|
||||
|
||||
return fan_name
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the PSU
|
||||
Returns:
|
||||
bool: True if PSU is present, False if not
|
||||
"""
|
||||
if self.is_psu_fan:
|
||||
val = self.__read_txt_file(self.cpld_path + "psu_present")
|
||||
return int(val, 10) == 1
|
||||
|
||||
val = self.__read_txt_file(
|
||||
CPLD_I2C_PATH + str(self.fan_tray_index + 1) + "_present")
|
||||
return int(val, 10)==1
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the device
|
||||
Returns:
|
||||
A boolean value, True if device is operating properly, False if not
|
||||
"""
|
||||
if self.is_psu_fan:
|
||||
psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_fault')
|
||||
val=self.__read_txt_file(psu_fan_path)
|
||||
if val is not None:
|
||||
return int(val, 10)==0
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_fault')
|
||||
val=self.__read_txt_file(path)
|
||||
if val is not None:
|
||||
return int(val, 10)==0
|
||||
else:
|
||||
return False
|
||||
|
||||
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_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_index+1) \
|
||||
if not self.is_psu_fan else (self.psu_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
|
@ -0,0 +1,90 @@
|
||||
########################################################################
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides 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")
|
||||
|
||||
FANS_PER_FANTRAY = 2
|
||||
|
||||
|
||||
class FanDrawer(FanDrawerBase):
|
||||
"""Platform-specific Fan class"""
|
||||
|
||||
def __init__(self, fantray_index):
|
||||
|
||||
FanDrawerBase.__init__(self)
|
||||
# FanTray is 0-based in platforms
|
||||
self.fantrayindex = fantray_index
|
||||
self.__initialize_fan_drawer()
|
||||
|
||||
|
||||
def __initialize_fan_drawer(self):
|
||||
from sonic_platform.fan import Fan
|
||||
for i in range(FANS_PER_FANTRAY):
|
||||
self._fan_list.append(Fan(self.fantrayindex, i))
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the fan drawer name
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
return "FanTray{}".format(self.fantrayindex+1)
|
||||
|
||||
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.
|
||||
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.fantrayindex+1)
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return True
|
@ -0,0 +1,21 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the platform information
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
from sonic_platform_base.platform_base import PlatformBase
|
||||
from sonic_platform.chassis import Chassis
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Platform(PlatformBase):
|
||||
"""Platform-specific Platform class"""
|
||||
|
||||
def __init__(self):
|
||||
PlatformBase.__init__(self)
|
||||
self._chassis = Chassis()
|
264
device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py
Normal file
264
device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py
Normal file
@ -0,0 +1,264 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the PSUs status which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
#import sonic_platform
|
||||
|
||||
try:
|
||||
from sonic_platform_base.psu_base import PsuBase
|
||||
from sonic_platform.thermal import Thermal
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/"
|
||||
|
||||
PSU_NAME_LIST = ["PSU-1", "PSU-2"]
|
||||
PSU_NUM_FAN = [1, 1]
|
||||
PSU_HWMON_I2C_MAPPING = {
|
||||
0: {
|
||||
"bus": 17,
|
||||
"addr": "59"
|
||||
},
|
||||
1: {
|
||||
"bus": 13,
|
||||
"addr": "5b"
|
||||
},
|
||||
}
|
||||
|
||||
PSU_CPLD_I2C_MAPPING = {
|
||||
0: {
|
||||
"bus": 17,
|
||||
"addr": "51"
|
||||
},
|
||||
1: {
|
||||
"bus": 13,
|
||||
"addr": "53"
|
||||
},
|
||||
}
|
||||
|
||||
NUM_FAN_TRAY = 6
|
||||
|
||||
|
||||
class Psu(PsuBase):
|
||||
"""Platform-specific Psu class"""
|
||||
|
||||
def __init__(self, psu_index=0):
|
||||
PsuBase.__init__(self)
|
||||
self.index = psu_index
|
||||
|
||||
bus = PSU_HWMON_I2C_MAPPING[self.index]["bus"]
|
||||
addr = PSU_HWMON_I2C_MAPPING[self.index]["addr"]
|
||||
self.hwmon_path = I2C_PATH.format(bus, addr)
|
||||
|
||||
bus = PSU_CPLD_I2C_MAPPING[self.index]["bus"]
|
||||
addr = PSU_CPLD_I2C_MAPPING[self.index]["addr"]
|
||||
self.cpld_path = I2C_PATH.format(bus, addr)
|
||||
self.__initialize_fan()
|
||||
|
||||
def __initialize_fan(self):
|
||||
from sonic_platform.fan import Fan
|
||||
self._fan_list.append(
|
||||
Fan(NUM_FAN_TRAY + self.index,
|
||||
is_psu_fan=True,
|
||||
psu_index=self.index))
|
||||
self._thermal_list.append(Thermal(is_psu=True, psu_index=self.index))
|
||||
|
||||
def __read_txt_file(self, file_path):
|
||||
try:
|
||||
with open(file_path, 'r') as fd:
|
||||
return fd.read().strip()
|
||||
except IOError:
|
||||
pass
|
||||
return None
|
||||
|
||||
def get_voltage(self):
|
||||
"""
|
||||
Retrieves current PSU voltage output
|
||||
Returns:
|
||||
A float number, the output voltage in volts,
|
||||
e.g. 12.1
|
||||
"""
|
||||
val = self.__read_txt_file(self.hwmon_path + "psu_v_out")
|
||||
if val is not None:
|
||||
return float(val)/ 1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_current(self):
|
||||
"""
|
||||
Retrieves present electric current supplied by PSU
|
||||
Returns:
|
||||
A float number, the electric current in amperes, e.g 15.4
|
||||
"""
|
||||
val = self.__read_txt_file(self.hwmon_path + "psu_i_out")
|
||||
if val is not None:
|
||||
return float(val)/1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_power(self):
|
||||
"""
|
||||
Retrieves current energy supplied by PSU
|
||||
Returns:
|
||||
A float number, the power in watts, e.g. 302.6
|
||||
"""
|
||||
val = self.__read_txt_file(self.hwmon_path + "psu_p_out")
|
||||
if val is not None:
|
||||
return float(val)/1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_powergood_status(self):
|
||||
"""
|
||||
Retrieves the powergood status of PSU
|
||||
Returns:
|
||||
A boolean, True if PSU has stablized its output voltages and passed all
|
||||
its internal self-tests, False if not.
|
||||
"""
|
||||
return self.get_status()
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
return False #Controlled by HW
|
||||
|
||||
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.get_status()
|
||||
if status is None:
|
||||
return self.STATUS_LED_COLOR_OFF
|
||||
|
||||
return {
|
||||
1: self.STATUS_LED_COLOR_GREEN,
|
||||
0: self.STATUS_LED_COLOR_RED
|
||||
}.get(status, self.STATUS_LED_COLOR_OFF)
|
||||
|
||||
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
|
||||
"""
|
||||
return self._thermal_list[0].get_temperature()
|
||||
|
||||
def get_temperature_high_threshold(self):
|
||||
"""
|
||||
Retrieves the high threshold temperature of PSU
|
||||
Returns:
|
||||
A float number, the high threshold temperature of PSU in Celsius
|
||||
up to nearest thousandth of one degree Celsius, e.g. 30.125
|
||||
"""
|
||||
return False #Not supported
|
||||
|
||||
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
|
||||
"""
|
||||
val = self.__read_txt_file(self.hwmon_path + "psu_mfr_vout_max")
|
||||
if val is not None:
|
||||
return float(val)/ 1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
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
|
||||
"""
|
||||
val = self.__read_txt_file(self.hwmon_path + "psu_mfr_vout_min")
|
||||
if val is not None:
|
||||
return float(val)/ 1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
return PSU_NAME_LIST[self.index]
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the PSU
|
||||
Returns:
|
||||
bool: True if PSU is present, False if not
|
||||
"""
|
||||
val = self.__read_txt_file(self.cpld_path + "psu_present")
|
||||
if val is not None:
|
||||
return int(val, 10) == 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the device
|
||||
Returns:
|
||||
A boolean value, True if device is operating properly, False if not
|
||||
"""
|
||||
val = self.__read_txt_file(self.cpld_path + "psu_power_good")
|
||||
if val is not None:
|
||||
return int(val, 10) == 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the device
|
||||
Returns:
|
||||
string: Model/part number of device
|
||||
"""
|
||||
model = self.__read_txt_file(self.cpld_path + "psu_model_name")
|
||||
if model is None:
|
||||
return "N/A"
|
||||
return model
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the device
|
||||
Returns:
|
||||
string: Serial number of device
|
||||
"""
|
||||
serial = self.__read_txt_file(self.cpld_path + "psu_serial_number")
|
||||
if serial is None:
|
||||
return "N/A"
|
||||
return serial
|
||||
|
||||
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.index+1
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return True
|
626
device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py
Normal file
626
device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py
Normal file
@ -0,0 +1,626 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Sfp contains an implementation of SONiC Platform Base API and
|
||||
# provides the sfp device status which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
import os
|
||||
import time
|
||||
import sys
|
||||
|
||||
from ctypes import create_string_buffer
|
||||
|
||||
try:
|
||||
from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase
|
||||
from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
CPLD_ADDR_MAPPING = {
|
||||
0: {
|
||||
"bus": 18,
|
||||
"addr": "60"
|
||||
}, # port 31-56
|
||||
1: {
|
||||
"bus": 12,
|
||||
"addr": "62"
|
||||
}, # port 1-30
|
||||
}
|
||||
CPLD_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/"
|
||||
|
||||
class Sfp(SfpOptoeBase):
|
||||
"""Platform-specific Sfp class"""
|
||||
|
||||
# Port number
|
||||
PORT_START = 1
|
||||
PORT_END = 58
|
||||
|
||||
# Path to sysfs
|
||||
PLATFORM_ROOT_PATH = "/usr/share/sonic/device"
|
||||
PMON_HWSKU_PATH = "/usr/share/sonic/hwsku"
|
||||
HOST_CHK_CMD = "which systemctl > /dev/null 2>&1"
|
||||
|
||||
PLATFORM = "x86_64-accton_as7326_56x-r0"
|
||||
HWSKU = "Accton-AS7326-56X"
|
||||
|
||||
_port_to_i2c_mapping = {
|
||||
1: [42],
|
||||
2: [41],
|
||||
3: [44],
|
||||
4: [43],
|
||||
5: [47],
|
||||
6: [45],
|
||||
7: [46],
|
||||
8: [50],
|
||||
9: [48],
|
||||
10: [49],
|
||||
11: [52],
|
||||
12: [51],
|
||||
13: [53],
|
||||
14: [56],
|
||||
15: [55],
|
||||
16: [54],
|
||||
17: [58],
|
||||
18: [57],
|
||||
19: [60],
|
||||
20: [59],
|
||||
21: [61],
|
||||
22: [63],
|
||||
23: [62],
|
||||
24: [64],
|
||||
25: [66],
|
||||
26: [68],
|
||||
27: [65],
|
||||
28: [67],
|
||||
29: [69],
|
||||
30: [71],
|
||||
31: [72],
|
||||
32: [70],
|
||||
33: [74],
|
||||
34: [73],
|
||||
35: [76],
|
||||
36: [75],
|
||||
37: [77],
|
||||
38: [79],
|
||||
39: [78],
|
||||
40: [80],
|
||||
41: [81],
|
||||
42: [82],
|
||||
43: [84],
|
||||
44: [85],
|
||||
45: [83],
|
||||
46: [87],
|
||||
47: [88],
|
||||
48: [86],
|
||||
49: [25],
|
||||
50: [26],
|
||||
51: [27],
|
||||
52: [28],
|
||||
53: [29],
|
||||
54: [30],
|
||||
55: [31],
|
||||
56: [32],
|
||||
57: [22],
|
||||
58: [23]
|
||||
}
|
||||
|
||||
def __init__(self, sfp_index=0):
|
||||
SfpOptoeBase.__init__(self)
|
||||
# Init index
|
||||
self.index = sfp_index
|
||||
self.port_num = self.index + 1
|
||||
|
||||
cpld_idx = 0 if self.port_num > 30 else 1
|
||||
bus = CPLD_ADDR_MAPPING[cpld_idx]["bus"]
|
||||
addr = CPLD_ADDR_MAPPING[cpld_idx]["addr"]
|
||||
self.cpld_path = CPLD_I2C_PATH.format(bus, addr)
|
||||
|
||||
# Init eeprom path
|
||||
eeprom_path = '/sys/bus/i2c/devices/{0}-0050/eeprom'
|
||||
self.port_to_eeprom_mapping = {}
|
||||
for x in range(self.PORT_START, self.PORT_END + 1):
|
||||
self.port_to_eeprom_mapping[x] = eeprom_path.format(
|
||||
self._port_to_i2c_mapping[x][0])
|
||||
|
||||
def get_eeprom_path(self):
|
||||
return self.port_to_eeprom_mapping[self.port_num]
|
||||
|
||||
def __read_txt_file(self, file_path):
|
||||
try:
|
||||
with open(file_path, 'r') as fd:
|
||||
return fd.read().strip()
|
||||
except IOError:
|
||||
pass
|
||||
return ""
|
||||
|
||||
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 __is_host(self):
|
||||
return os.system(self.HOST_CHK_CMD) == 0
|
||||
|
||||
def __get_path_to_port_config_file(self):
|
||||
platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM])
|
||||
hwsku_path = "/".join(
|
||||
[platform_path,
|
||||
self.HWSKU]) if self.__is_host() else self.PMON_HWSKU_PATH
|
||||
return "/".join([hwsku_path, "port_config.ini"])
|
||||
|
||||
def __read_eeprom_specific_bytes(self, offset, num_bytes):
|
||||
sysfsfile_eeprom = None
|
||||
eeprom_raw = []
|
||||
for i in range(0, num_bytes):
|
||||
eeprom_raw.append("0x00")
|
||||
|
||||
sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[
|
||||
self.port_num]
|
||||
try:
|
||||
sysfsfile_eeprom = open(
|
||||
sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0)
|
||||
sysfsfile_eeprom.seek(offset)
|
||||
raw = sysfsfile_eeprom.read(num_bytes)
|
||||
for n in range(0, num_bytes):
|
||||
if sys.version_info[0] >= 3:
|
||||
eeprom_raw[n] = hex(raw[n])[2:].zfill(2)
|
||||
else:
|
||||
eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2)
|
||||
except Exception:
|
||||
pass
|
||||
finally:
|
||||
if sysfsfile_eeprom:
|
||||
sysfsfile_eeprom.close()
|
||||
|
||||
return eeprom_raw
|
||||
|
||||
def get_reset_status(self):
|
||||
"""
|
||||
Retrieves the reset status of SFP
|
||||
Returns:
|
||||
A Boolean, True if reset enabled, False if disabled
|
||||
"""
|
||||
if self.port_num <= 48 or self.port_num >=57:
|
||||
return False # SPF port doesn't support this feature
|
||||
|
||||
val = self.__read_txt_file(
|
||||
self.cpld_path + "module_reset_" + str(self.port_num))
|
||||
return int(val, 10) == 1
|
||||
|
||||
def get_rx_los(self):
|
||||
"""
|
||||
Retrieves the RX LOS (lost-of-signal) status of SFP
|
||||
Returns:
|
||||
A Boolean, True if SFP has RX LOS, False if not.
|
||||
Note : RX LOS status is latched until a call to get_rx_los or a reset.
|
||||
"""
|
||||
if self.port_num <= 48 or self.port_num >=57:
|
||||
rx_los = self.__read_txt_file(
|
||||
self.cpld_path + "module_rx_los_" + str(self.port_num))
|
||||
if int(rx_los, 10) == 1:
|
||||
return [True]
|
||||
else:
|
||||
return [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)
|
||||
else:
|
||||
rx_los_list = []
|
||||
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
|
||||
QSFP_CHANNL_RX_LOS_STATUS_OFFSET,
|
||||
QSFP_CHANNL_RX_LOS_STATUS_WIDTH) if self.get_presence(
|
||||
) else None
|
||||
if dom_channel_monitor_raw is not None:
|
||||
rx_los_data = int(dom_channel_monitor_raw[0], 16)
|
||||
rx_los_list.append(rx_los_data & 0x01 != 0)
|
||||
rx_los_list.append(rx_los_data & 0x02 != 0)
|
||||
rx_los_list.append(rx_los_data & 0x04 != 0)
|
||||
rx_los_list.append(rx_los_data & 0x08 != 0)
|
||||
return rx_los_list
|
||||
else:
|
||||
return [False]*4
|
||||
|
||||
def get_tx_fault(self):
|
||||
"""
|
||||
Retrieves the TX fault status of SFP
|
||||
|
||||
Returns:
|
||||
A list of boolean values, representing the TX fault status
|
||||
of each available channel, value is True if SFP channel
|
||||
has TX fault, False if not.
|
||||
E.g., for a tranceiver with four channels: [False, False, True, False]
|
||||
Note : TX fault status is lached until a call to get_tx_fault or a reset.
|
||||
"""
|
||||
tx_fault = False
|
||||
if self.port_num <= 48 or self.port_num >=57:
|
||||
tx_fault = self.__read_txt_file(
|
||||
self.cpld_path + "module_tx_fault_" + str(self.port_num))
|
||||
if int(tx_fault, 10) == 1:
|
||||
return [True]
|
||||
else:
|
||||
return [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)
|
||||
else:
|
||||
tx_fault_list = []
|
||||
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
|
||||
QSFP_CHANNL_TX_FAULT_STATUS_OFFSET,
|
||||
QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) if self.get_presence(
|
||||
) else None
|
||||
if dom_channel_monitor_raw is not None:
|
||||
tx_fault_data = int(dom_channel_monitor_raw[0], 16)
|
||||
tx_fault_list.append(tx_fault_data & 0x01 != 0)
|
||||
tx_fault_list.append(tx_fault_data & 0x02 != 0)
|
||||
tx_fault_list.append(tx_fault_data & 0x04 != 0)
|
||||
tx_fault_list.append(tx_fault_data & 0x08 != 0)
|
||||
return tx_fault_list
|
||||
else:
|
||||
return [False]*4
|
||||
|
||||
|
||||
def get_tx_disable(self):
|
||||
"""
|
||||
Retrieves the tx_disable status of this SFP
|
||||
Returns:
|
||||
A list of boolean values, representing the TX disable status
|
||||
of each available channel, value is True if SFP channel
|
||||
is TX disabled, False if not.
|
||||
E.g., for a tranceiver with four channels: [False, False, True, False]
|
||||
"""
|
||||
if self.port_num <= 48 or self.port_num >=57:
|
||||
tx_disable = False
|
||||
|
||||
status_control_raw = self.__read_eeprom_specific_bytes(
|
||||
SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH)
|
||||
if status_control_raw:
|
||||
cpld_val = self.__read_txt_file(
|
||||
self.cpld_path + "module_tx_disable_" + str(self.port_num))
|
||||
tx_disable_hard = (int(cpld_val, 10) == 1)
|
||||
data = int(status_control_raw[0], 16)
|
||||
#tx_disable_hard = (sffbase().test_bit(
|
||||
# data, SFP_TX_DISABLE_HARD_BIT) != 0)
|
||||
tx_disable_soft = (sffbase().test_bit(
|
||||
data, SFP_TX_DISABLE_SOFT_BIT) != 0)
|
||||
tx_disable = tx_disable_hard | tx_disable_soft
|
||||
if tx_disable==0:
|
||||
return [False]
|
||||
else:
|
||||
return [True]
|
||||
|
||||
else:
|
||||
return [False]
|
||||
|
||||
else:
|
||||
tx_disable_list = []
|
||||
|
||||
sfpd_obj = sff8436Dom()
|
||||
if sfpd_obj is None:
|
||||
return [False]
|
||||
|
||||
dom_control_raw = self.__read_eeprom_specific_bytes(
|
||||
QSFP_CONTROL_OFFSET,
|
||||
QSFP_CONTROL_WIDTH) if self.get_presence() else None
|
||||
if dom_control_raw is not None:
|
||||
dom_control_data = sfpd_obj.parse_control_bytes(
|
||||
dom_control_raw, 0)
|
||||
tx_disable_list.append(
|
||||
'On' == dom_control_data['data']['TX1Disable']['value'])
|
||||
tx_disable_list.append(
|
||||
'On' == dom_control_data['data']['TX2Disable']['value'])
|
||||
tx_disable_list.append(
|
||||
'On' == dom_control_data['data']['TX3Disable']['value'])
|
||||
tx_disable_list.append(
|
||||
'On' == dom_control_data['data']['TX4Disable']['value'])
|
||||
return tx_disable_list
|
||||
else:
|
||||
return [False]*4
|
||||
|
||||
def get_tx_disable_channel(self):
|
||||
"""
|
||||
Retrieves the TX disabled channels in this SFP
|
||||
Returns:
|
||||
A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent
|
||||
TX channels which have been disabled in this SFP.
|
||||
As an example, a returned value of 0x5 indicates that channel 0
|
||||
and channel 2 have been disabled.
|
||||
"""
|
||||
tx_disable_list = self.get_tx_disable()
|
||||
if tx_disable_list is None:
|
||||
return 0
|
||||
tx_disabled = 0
|
||||
for i in range(len(tx_disable_list)):
|
||||
if tx_disable_list[i]:
|
||||
tx_disabled |= 1 << i
|
||||
return tx_disabled
|
||||
|
||||
def get_lpmode(self):
|
||||
"""
|
||||
Retrieves the lpmode (low power mode) status of this SFP
|
||||
Returns:
|
||||
A Boolean, True if lpmode is enabled, False if disabled
|
||||
"""
|
||||
if self.port_num <= 48 or self.port_num >= 57:
|
||||
# SFP doesn't support this feature
|
||||
return False
|
||||
|
||||
power_set = self.get_power_set()
|
||||
power_override = self.get_power_override()
|
||||
return power_set and power_override
|
||||
|
||||
def get_power_set(self):
|
||||
|
||||
if self.port_num <= 48 or self.port_num >= 57:
|
||||
# SFP doesn't support this feature
|
||||
return False
|
||||
else:
|
||||
power_set = False
|
||||
|
||||
sfpd_obj = sff8436Dom()
|
||||
if sfpd_obj is None:
|
||||
return False
|
||||
|
||||
dom_control_raw = self.__read_eeprom_specific_bytes(
|
||||
QSFP_CONTROL_OFFSET,
|
||||
QSFP_CONTROL_WIDTH) if self.get_presence() else None
|
||||
if dom_control_raw is not None:
|
||||
dom_control_data = sfpd_obj.parse_control_bytes(
|
||||
dom_control_raw, 0)
|
||||
power_set = (
|
||||
'On' == dom_control_data['data']['PowerSet']['value'])
|
||||
|
||||
return power_set
|
||||
|
||||
def get_power_override(self):
|
||||
"""
|
||||
Retrieves the power-override status of this SFP
|
||||
Returns:
|
||||
A Boolean, True if power-override is enabled, False if disabled
|
||||
"""
|
||||
if self.port_num <= 48 or self.port_num >= 57:
|
||||
return False # SFP doesn't support this feature
|
||||
else:
|
||||
power_override = False
|
||||
|
||||
sfpd_obj = sff8436Dom()
|
||||
if sfpd_obj is None:
|
||||
return False
|
||||
|
||||
dom_control_raw = self.__read_eeprom_specific_bytes(
|
||||
QSFP_CONTROL_OFFSET,
|
||||
QSFP_CONTROL_WIDTH) if self.get_presence() else None
|
||||
if dom_control_raw is not None:
|
||||
dom_control_data = sfpd_obj.parse_control_bytes(
|
||||
dom_control_raw, 0)
|
||||
power_override = (
|
||||
'On' == dom_control_data['data']['PowerOverride']['value'])
|
||||
|
||||
return power_override
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset SFP and return all user module settings to their default srate.
|
||||
Returns:
|
||||
A boolean, True if successful, False if not
|
||||
"""
|
||||
# Check for invalid port_num
|
||||
if self.port_num <= 48 or self.port_num >=57:
|
||||
return False # SFP doesn't support this feature
|
||||
|
||||
ret = self.__write_txt_file(
|
||||
self.cpld_path + "module_reset_" + str(self.port_num), 1)
|
||||
if ret is not True:
|
||||
return ret
|
||||
|
||||
time.sleep(0.01)
|
||||
ret = self.__write_txt_file(
|
||||
self.cpld_path + "module_reset_" + str(self.port_num), 0)
|
||||
time.sleep(0.2)
|
||||
return ret
|
||||
|
||||
def tx_disable(self, tx_disable):
|
||||
"""
|
||||
Disable SFP TX for all channels
|
||||
Args:
|
||||
tx_disable : A Boolean, True to enable tx_disable mode, False to disable
|
||||
tx_disable mode.
|
||||
Returns:
|
||||
A boolean, True if tx_disable is set successfully, False if not
|
||||
"""
|
||||
if self.port_num <= 48 or self.port_num >=57:
|
||||
ret = self.__write_txt_file(
|
||||
self.cpld_path + "module_tx_disable_" + str(self.port_num), 1
|
||||
if tx_disable else 0)
|
||||
time.sleep(0.01)
|
||||
return ret
|
||||
else:
|
||||
if not self.get_presence():
|
||||
return False
|
||||
|
||||
sysfsfile_eeprom = None
|
||||
try:
|
||||
tx_disable_ctl = 0xf if tx_disable else 0x0
|
||||
buffer = create_string_buffer(1)
|
||||
if sys.version_info[0] >= 3:
|
||||
buffer[0] = tx_disable_ctl
|
||||
else:
|
||||
buffer[0] = chr(tx_disable_ctl)
|
||||
# Write to eeprom
|
||||
sysfsfile_eeprom = open(
|
||||
self.port_to_eeprom_mapping[self.port_num], "r+b")
|
||||
sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET)
|
||||
sysfsfile_eeprom.write(buffer[0])
|
||||
except IOError as e:
|
||||
print("Error: unable to open file: %s" % str(e))
|
||||
return False
|
||||
finally:
|
||||
if sysfsfile_eeprom is not None:
|
||||
sysfsfile_eeprom.close()
|
||||
time.sleep(0.01)
|
||||
return True
|
||||
|
||||
def tx_disable_channel(self, channel, disable):
|
||||
"""
|
||||
Sets the tx_disable for specified SFP channels
|
||||
Args:
|
||||
channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3,
|
||||
e.g. 0x5 for channel 0 and channel 2.
|
||||
disable : A boolean, True to disable TX channels specified in channel,
|
||||
False to enable
|
||||
Returns:
|
||||
A boolean, True if successful, False if not
|
||||
"""
|
||||
|
||||
if self.port_num <= 48 or self.port_num >=57:
|
||||
return False # SFP doesn't support this feature
|
||||
else:
|
||||
if not self.get_presence():
|
||||
return False
|
||||
|
||||
sysfsfile_eeprom = None
|
||||
try:
|
||||
channel_state = self.get_tx_disable_channel()
|
||||
|
||||
for i in range(4):
|
||||
channel_mask = (1 << i)
|
||||
if not (channel & channel_mask):
|
||||
continue
|
||||
|
||||
if disable:
|
||||
channel_state |= channel_mask
|
||||
else:
|
||||
channel_state &= ~channel_mask
|
||||
|
||||
buffer = create_string_buffer(1)
|
||||
if sys.version_info[0] >= 3:
|
||||
buffer[0] = channel_state
|
||||
else:
|
||||
buffer[0] = chr(channel_state)
|
||||
# Write to eeprom
|
||||
sysfsfile_eeprom = open(
|
||||
self.port_to_eeprom_mapping[self.port_num], "r+b")
|
||||
sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET)
|
||||
sysfsfile_eeprom.write(buffer[0])
|
||||
except IOError as e:
|
||||
print("Error: unable to open file: %s" % str(e))
|
||||
return False
|
||||
finally:
|
||||
if sysfsfile_eeprom is not None:
|
||||
sysfsfile_eeprom.close()
|
||||
time.sleep(0.01)
|
||||
return True
|
||||
|
||||
def set_lpmode(self, lpmode):
|
||||
"""
|
||||
Sets the lpmode (low power mode) of SFP
|
||||
Args:
|
||||
lpmode: A Boolean, True to enable lpmode, False to disable it
|
||||
Note : lpmode can be overridden by set_power_override
|
||||
Returns:
|
||||
A boolean, True if lpmode is set successfully, False if not
|
||||
"""
|
||||
if self.port_num <= 48 or self.port_num >=57:
|
||||
return False # SFP doesn't support this feature
|
||||
|
||||
if lpmode:
|
||||
return self.set_power_override(True, True)
|
||||
else:
|
||||
return self.set_power_override(True, False)
|
||||
|
||||
def set_power_override(self, power_override, power_set):
|
||||
"""
|
||||
Sets SFP power level using power_override and power_set
|
||||
Args:
|
||||
power_override :
|
||||
A Boolean, True to override set_lpmode and use power_set
|
||||
to control SFP power, False to disable SFP power control
|
||||
through power_override/power_set and use set_lpmode
|
||||
to control SFP power.
|
||||
power_set :
|
||||
Only valid when power_override is True.
|
||||
A Boolean, True to set SFP to low power mode, False to set
|
||||
SFP to high power mode.
|
||||
Returns:
|
||||
A boolean, True if power-override and power_set are set successfully,
|
||||
False if not
|
||||
"""
|
||||
if self.port_num <= 48 or self.port_num >=57:
|
||||
return False # SFP doesn't support this feature
|
||||
else:
|
||||
if not self.get_presence():
|
||||
return False
|
||||
try:
|
||||
power_override_bit = (1 << 0) if power_override else 0
|
||||
power_set_bit = (1 << 1) if power_set else (1 << 3)
|
||||
|
||||
buffer = create_string_buffer(1)
|
||||
if sys.version_info[0] >= 3:
|
||||
buffer[0] = (power_override_bit | power_set_bit)
|
||||
else:
|
||||
buffer[0] = chr(power_override_bit | power_set_bit)
|
||||
# Write to eeprom
|
||||
with open(self.port_to_eeprom_mapping[self.port_num],
|
||||
"r+b") as fd:
|
||||
fd.seek(QSFP_POWEROVERRIDE_OFFSET)
|
||||
fd.write(buffer[0])
|
||||
time.sleep(0.01)
|
||||
except Exception:
|
||||
print("Error: unable to open file: %s" % str(e))
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
sfputil_helper = SfpUtilHelper()
|
||||
sfputil_helper.read_porttab_mappings(
|
||||
self.__get_path_to_port_config_file())
|
||||
name = sfputil_helper.logical[self.index] or "Unknown"
|
||||
return name
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the device
|
||||
Returns:
|
||||
bool: True if device is present, False if not
|
||||
"""
|
||||
val = self.__read_txt_file(
|
||||
self.cpld_path + "module_present_" + str(self.port_num))
|
||||
return val == '1'
|
||||
|
||||
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()
|
||||
|
||||
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.port_num
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return True
|
@ -0,0 +1,232 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Thermal contains an implementation of SONiC Platform Base API and
|
||||
# provides the thermal device status which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import glob
|
||||
|
||||
try:
|
||||
from sonic_platform_base.thermal_base import ThermalBase
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
PSU_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/"
|
||||
PSU_HWMON_I2C_MAPPING = {
|
||||
0: {
|
||||
"bus": 17,
|
||||
"addr": "59"
|
||||
},
|
||||
1: {
|
||||
"bus": 13,
|
||||
"addr": "5b"
|
||||
},
|
||||
}
|
||||
|
||||
PSU_CPLD_I2C_MAPPING = {
|
||||
0: {
|
||||
"bus": 17,
|
||||
"addr": "51"
|
||||
},
|
||||
1: {
|
||||
"bus": 13,
|
||||
"addr": "53"
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class Thermal(ThermalBase):
|
||||
"""Platform-specific Thermal class"""
|
||||
|
||||
THERMAL_NAME_LIST = []
|
||||
PSU_THERMAL_NAME_LIST = []
|
||||
SYSFS_PATH = "/sys/bus/i2c/devices"
|
||||
|
||||
def __init__(self, thermal_index=0, is_psu=False, psu_index=0):
|
||||
self.index = thermal_index
|
||||
self.is_psu = is_psu
|
||||
self.psu_index = psu_index
|
||||
|
||||
if self.is_psu:
|
||||
psu_i2c_bus = PSU_HWMON_I2C_MAPPING[psu_index]["bus"]
|
||||
psu_i2c_addr = PSU_HWMON_I2C_MAPPING[psu_index]["addr"]
|
||||
self.psu_hwmon_path = PSU_I2C_PATH.format(psu_i2c_bus,
|
||||
psu_i2c_addr)
|
||||
psu_i2c_bus = PSU_CPLD_I2C_MAPPING[psu_index]["bus"]
|
||||
psu_i2c_addr = PSU_CPLD_I2C_MAPPING[psu_index]["addr"]
|
||||
self.cpld_path = PSU_I2C_PATH.format(psu_i2c_bus, psu_i2c_addr)
|
||||
|
||||
# Add thermal name
|
||||
self.THERMAL_NAME_LIST.append("Temp sensor 1")
|
||||
self.THERMAL_NAME_LIST.append("Temp sensor 2")
|
||||
self.THERMAL_NAME_LIST.append("Temp sensor 3")
|
||||
self.THERMAL_NAME_LIST.append("Temp sensor 4")
|
||||
self.PSU_THERMAL_NAME_LIST.append("PSU-1 temp sensor 1")
|
||||
self.PSU_THERMAL_NAME_LIST.append("PSU-2 temp sensor 1")
|
||||
|
||||
# Set hwmon path
|
||||
i2c_path = {
|
||||
0: "15-0048/hwmon/hwmon*/",
|
||||
1: "15-0049/hwmon/hwmon*/",
|
||||
2: "15-004a/hwmon/hwmon*/",
|
||||
3: "15-004b/hwmon/hwmon*/"
|
||||
}.get(self.index, None)
|
||||
|
||||
self.hwmon_path = "{}/{}".format(self.SYSFS_PATH, i2c_path)
|
||||
self.ss_key = self.THERMAL_NAME_LIST[self.index]
|
||||
self.ss_index = 1
|
||||
|
||||
def __read_txt_file(self, file_path):
|
||||
for filename in glob.glob(file_path):
|
||||
try:
|
||||
with open(filename, 'r') as fd:
|
||||
return fd.readline().rstrip()
|
||||
except IOError as e:
|
||||
pass
|
||||
|
||||
def __get_temp(self, temp_file):
|
||||
if not self.is_psu:
|
||||
temp_file_path = os.path.join(self.hwmon_path, temp_file)
|
||||
else:
|
||||
temp_file_path = temp_file
|
||||
|
||||
raw_temp = self.__read_txt_file(temp_file_path)
|
||||
return float(raw_temp) / 1000
|
||||
|
||||
def __set_threshold(self, file_name, temperature):
|
||||
if self.is_psu:
|
||||
return True
|
||||
|
||||
temp_file_path = os.path.join(self.hwmon_path, file_name)
|
||||
try:
|
||||
with open(temp_file_path, 'w') as fd:
|
||||
fd.write(str(temperature))
|
||||
return True
|
||||
except IOError:
|
||||
return False
|
||||
|
||||
def get_temperature(self):
|
||||
"""
|
||||
Retrieves current temperature reading from thermal
|
||||
Returns:
|
||||
A float number of current temperature in Celsius up to nearest thousandth
|
||||
of one degree Celsius, e.g. 30.125
|
||||
"""
|
||||
if not self.is_psu:
|
||||
temp_file = "temp{}_input".format(self.ss_index)
|
||||
else:
|
||||
temp_file = self.psu_hwmon_path + "psu_temp1_input"
|
||||
|
||||
return self.__get_temp(temp_file)
|
||||
|
||||
def get_high_threshold(self):
|
||||
"""
|
||||
Retrieves the high threshold temperature of thermal
|
||||
Returns:
|
||||
A float number, the high threshold temperature of thermal in Celsius
|
||||
up to nearest thousandth of one degree Celsius, e.g. 30.125
|
||||
"""
|
||||
if self.is_psu:
|
||||
return 0
|
||||
|
||||
temp_file = "temp{}_max".format(self.ss_index)
|
||||
return self.__get_temp(temp_file)
|
||||
|
||||
def set_high_threshold(self, temperature):
|
||||
"""
|
||||
Sets the high threshold temperature of thermal
|
||||
Args :
|
||||
temperature: A float number up to nearest thousandth of one degree Celsius,
|
||||
e.g. 30.125
|
||||
Returns:
|
||||
A boolean, True if threshold is set successfully, False if not
|
||||
"""
|
||||
temp_file = "temp{}_max".format(self.ss_index)
|
||||
temperature = temperature *1000
|
||||
self.__set_threshold(temp_file, temperature)
|
||||
|
||||
return True
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the thermal device
|
||||
Returns:
|
||||
string: The name of the thermal device
|
||||
"""
|
||||
if self.is_psu:
|
||||
return self.PSU_THERMAL_NAME_LIST[self.psu_index]
|
||||
else:
|
||||
return self.THERMAL_NAME_LIST[self.index]
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the PSU
|
||||
Returns:
|
||||
bool: True if PSU is present, False if not
|
||||
"""
|
||||
if self.is_psu:
|
||||
val = self.__read_txt_file(self.cpld_path + "psu_present")
|
||||
return int(val, 10) == 1
|
||||
|
||||
temp_file = "temp{}_input".format(self.ss_index)
|
||||
temp_file_path = os.path.join(self.hwmon_path, temp_file)
|
||||
raw_txt = self.__read_txt_file(temp_file_path)
|
||||
return raw_txt != None
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the device
|
||||
Returns:
|
||||
A boolean value, True if device is operating properly, False if not
|
||||
"""
|
||||
if self.is_psu:
|
||||
temp_file = self.psu_hwmon_path + "psu_temp_fault"
|
||||
return self.get_presence() and (not int(
|
||||
self.__read_txt_file(temp_file)))
|
||||
|
||||
file_str = "temp{}_input".format(self.ss_index)
|
||||
file_path = os.path.join(self.hwmon_path, file_str)
|
||||
|
||||
raw_txt = self.__read_txt_file(file_path)
|
||||
if raw_txt is None:
|
||||
return False
|
||||
else:
|
||||
return int(raw_txt) != 0
|
||||
|
||||
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_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.index+1
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Retrieves whether thermal module is replaceable
|
||||
Returns:
|
||||
A boolean value, True if replaceable, False if not
|
||||
"""
|
||||
return False
|
@ -0,0 +1,15 @@
|
||||
{
|
||||
"services_to_ignore": [],
|
||||
"devices_to_ignore": [
|
||||
"asic",
|
||||
"psu.temperature"
|
||||
|
||||
],
|
||||
"user_defined_checkers": [],
|
||||
"polling_interval": 60,
|
||||
"led_color": {
|
||||
"fault": "STATUS_LED_COLOR_RED",
|
||||
"normal": "STATUS_LED_COLOR_GREEN",
|
||||
"booting": "STATUS_LED_COLOR_GREEN_BLINK"
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
{
|
||||
|
||||
"XCVR":
|
||||
{
|
||||
"xcvr_present":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap-QSFP28": {"1":true, "0":false}
|
||||
}
|
||||
}
|
||||
},
|
||||
"PSU":
|
||||
{
|
||||
"psu_present":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": { "1":true, "0":false }
|
||||
}
|
||||
},
|
||||
|
||||
"psu_power_good":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": { "1": true, "0":false }
|
||||
}
|
||||
},
|
||||
|
||||
"psu_fan_dir":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": { "F2B":"EXHAUST", "B2F":"INTAKE" }
|
||||
}
|
||||
},
|
||||
|
||||
"PSU_FAN_MAX_SPEED":"18000"
|
||||
},
|
||||
|
||||
"FAN":
|
||||
{
|
||||
"direction":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": {"1":"INTAKE", "0":"EXHAUST"}
|
||||
}
|
||||
},
|
||||
|
||||
"present":
|
||||
{
|
||||
"i2c":
|
||||
{
|
||||
"valmap": {"1":true, "0":false}
|
||||
}
|
||||
},
|
||||
|
||||
"duty_cycle_to_pwm": "lambda dc: ((dc - 10) / 6)",
|
||||
"pwm_to_duty_cycle": "lambda pwm: ( (pwm * 6) + 10)"
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
{
|
||||
"skip_ledd": true,
|
||||
"skip_pcied": true,
|
||||
"skip_thermalctld": true
|
||||
"skip_pcied": true
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,2 @@
|
||||
__all__ = [ "platform", "chassis", "sfp", "eeprom", "component", "psu", "thermal", "fan", "fan_drawer" ]
|
||||
from . import platform
|
@ -0,0 +1,250 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the Chassis information which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
try:
|
||||
from sonic_platform_base.chassis_base import ChassisBase
|
||||
from .helper import APIHelper
|
||||
from .event import SfpEvent
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
NUM_FAN_TRAY = 4
|
||||
NUM_FAN = 2
|
||||
NUM_PSU = 2
|
||||
NUM_THERMAL = 6
|
||||
NUM_PORT = 64
|
||||
NUM_COMPONENT = 5
|
||||
HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/"
|
||||
PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/"
|
||||
REBOOT_CAUSE_FILE = "reboot-cause.txt"
|
||||
PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt"
|
||||
HOST_CHK_CMD = "which systemctl > /dev/null 2>&1"
|
||||
SYSLED_FNODE = "/sys/class/leds/as7816_64x_led::diag/brightness"
|
||||
SYSLED_MODES = {
|
||||
"0" : "STATUS_LED_COLOR_OFF",
|
||||
"16" : "STATUS_LED_COLOR_GREEN",
|
||||
"10" : "STATUS_LED_COLOR_RED"
|
||||
|
||||
}
|
||||
|
||||
|
||||
class Chassis(ChassisBase):
|
||||
"""Platform-specific Chassis class"""
|
||||
|
||||
def __init__(self):
|
||||
ChassisBase.__init__(self)
|
||||
self._api_helper = APIHelper()
|
||||
self.is_host = self._api_helper.is_host()
|
||||
|
||||
self.config_data = {}
|
||||
|
||||
self.__initialize_fan()
|
||||
self.__initialize_psu()
|
||||
self.__initialize_thermals()
|
||||
self.__initialize_components()
|
||||
self.__initialize_sfp()
|
||||
self.__initialize_eeprom()
|
||||
|
||||
def __initialize_sfp(self):
|
||||
from sonic_platform.sfp import Sfp
|
||||
for index in range(0, NUM_PORT):
|
||||
sfp = Sfp(index)
|
||||
self._sfp_list.append(sfp)
|
||||
self._sfpevent = SfpEvent(self._sfp_list)
|
||||
self.sfp_module_initialized = True
|
||||
|
||||
def __initialize_fan(self):
|
||||
from sonic_platform.fan_drawer import FanDrawer
|
||||
for fant_index in range(NUM_FAN_TRAY):
|
||||
fandrawer = FanDrawer(fant_index)
|
||||
self._fan_drawer_list.append(fandrawer)
|
||||
self._fan_list.extend(fandrawer._fan_list)
|
||||
|
||||
def __initialize_psu(self):
|
||||
from sonic_platform.psu import Psu
|
||||
for index in range(0, NUM_PSU):
|
||||
psu = Psu(index)
|
||||
self._psu_list.append(psu)
|
||||
|
||||
def __initialize_thermals(self):
|
||||
from sonic_platform.thermal import Thermal
|
||||
for index in range(0, NUM_THERMAL):
|
||||
thermal = Thermal(index)
|
||||
self._thermal_list.append(thermal)
|
||||
|
||||
def __initialize_eeprom(self):
|
||||
from sonic_platform.eeprom import Tlv
|
||||
self._eeprom = Tlv()
|
||||
|
||||
def __initialize_components(self):
|
||||
from sonic_platform.component import Component
|
||||
for index in range(0, NUM_COMPONENT):
|
||||
component = Component(index)
|
||||
self._component_list.append(component)
|
||||
|
||||
def __initialize_watchdog(self):
|
||||
from sonic_platform.watchdog import Watchdog
|
||||
self._watchdog = Watchdog()
|
||||
|
||||
|
||||
def __is_host(self):
|
||||
return os.system(HOST_CHK_CMD) == 0
|
||||
|
||||
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 get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
return self._eeprom.get_product_name()
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the Chassis
|
||||
Returns:
|
||||
bool: True if Chassis is present, False if not
|
||||
"""
|
||||
return True
|
||||
|
||||
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_base_mac(self):
|
||||
"""
|
||||
Retrieves the base MAC address for the chassis
|
||||
Returns:
|
||||
A string containing the MAC address in the format
|
||||
'XX:XX:XX:XX:XX:XX'
|
||||
"""
|
||||
return self._eeprom.get_mac()
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the device
|
||||
Returns:
|
||||
string: Model/part number of device
|
||||
"""
|
||||
return self._eeprom.get_pn()
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the hardware serial number for the chassis
|
||||
Returns:
|
||||
A string containing the hardware serial number for this chassis.
|
||||
"""
|
||||
return self._eeprom.get_serial()
|
||||
|
||||
def get_system_eeprom_info(self):
|
||||
"""
|
||||
Retrieves the full content of system EEPROM information for the chassis
|
||||
Returns:
|
||||
A dictionary where keys are the type code defined in
|
||||
OCP ONIE TlvInfo EEPROM format and values are their corresponding
|
||||
values.
|
||||
"""
|
||||
return self._eeprom.get_eeprom()
|
||||
|
||||
def get_reboot_cause(self):
|
||||
"""
|
||||
Retrieves the cause of the previous reboot
|
||||
Returns:
|
||||
A tuple (string, string) where the first element is a string
|
||||
containing the cause of the previous reboot. This string must be
|
||||
one of the predefined strings in this class. If the first string
|
||||
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
|
||||
to pass a description of the reboot cause.
|
||||
"""
|
||||
|
||||
reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE)
|
||||
sw_reboot_cause = self._api_helper.read_txt_file(
|
||||
reboot_cause_path) or "Unknown"
|
||||
|
||||
|
||||
return ('REBOOT_CAUSE_NON_HARDWARE', sw_reboot_cause)
|
||||
|
||||
def get_change_event(self, timeout=0):
|
||||
# SFP event
|
||||
if not self.sfp_module_initialized:
|
||||
self.__initialize_sfp()
|
||||
return self._sfpevent.get_sfp_event(timeout)
|
||||
|
||||
def get_sfp(self, index):
|
||||
"""
|
||||
Retrieves sfp represented by (1-based) index <index>
|
||||
Args:
|
||||
index: An integer, the index (1-based) of the sfp to retrieve.
|
||||
The index should be the sequence of a physical port in a chassis,
|
||||
starting from 1.
|
||||
For example, 1 for Ethernet0, 2 for Ethernet4 and so on.
|
||||
Returns:
|
||||
An object dervied from SfpBase representing the specified sfp
|
||||
"""
|
||||
sfp = None
|
||||
if not self.sfp_module_initialized:
|
||||
self.__initialize_sfp()
|
||||
|
||||
try:
|
||||
# The index will start from 1
|
||||
sfp = self._sfp_list[index-1]
|
||||
except IndexError:
|
||||
sys.stderr.write("SFP index {} out of range (1-{})\n".format(
|
||||
index, len(self._sfp_list)))
|
||||
return sfp
|
||||
|
||||
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 initizalize_system_led(self):
|
||||
return True
|
||||
|
||||
def get_status_led(self):
|
||||
val = self._api_helper.read_txt_file(SYSLED_FNODE)
|
||||
return SYSLED_MODES[val] if val in SYSLED_MODES else "UNKNOWN"
|
||||
|
||||
def set_status_led(self, color):
|
||||
mode = None
|
||||
for key, val in SYSLED_MODES.items():
|
||||
if val == color:
|
||||
mode = key
|
||||
break
|
||||
if mode is None:
|
||||
return False
|
||||
else:
|
||||
return self._api_helper.write_txt_file(SYSLED_FNODE, mode)
|
@ -0,0 +1,177 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Component contains an implementation of SONiC Platform Base API and
|
||||
# provides the components firmware management function
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
import shlex
|
||||
import subprocess
|
||||
|
||||
try:
|
||||
from sonic_platform_base.component_base import ComponentBase
|
||||
from .helper import APIHelper
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
CPLD_ADDR_MAPPING = {
|
||||
"CPLD1": "19-0060",
|
||||
"CPLD2": "20-0062",
|
||||
"CPLD3": "21-0064",
|
||||
"CPLD4": "22-0066",
|
||||
}
|
||||
SYSFS_PATH = "/sys/bus/i2c/devices/"
|
||||
BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version"
|
||||
COMPONENT_LIST= [
|
||||
("CPLD1", "CPLD 1"),
|
||||
("CPLD2", "CPLD 2"),
|
||||
("CPLD3", "CPLD 3"),
|
||||
("CPLD4", "CPLD 4"),
|
||||
("BIOS", "Basic Input/Output System")
|
||||
|
||||
]
|
||||
|
||||
class Component(ComponentBase):
|
||||
"""Platform-specific Component class"""
|
||||
|
||||
DEVICE_TYPE = "component"
|
||||
|
||||
def __init__(self, component_index=0):
|
||||
self._api_helper=APIHelper()
|
||||
ComponentBase.__init__(self)
|
||||
self.index = component_index
|
||||
self.name = self.get_name()
|
||||
|
||||
def __run_command(self, command):
|
||||
# Run bash command and print output to stdout
|
||||
try:
|
||||
process = subprocess.Popen(
|
||||
shlex.split(command), stdout=subprocess.PIPE)
|
||||
while True:
|
||||
output = process.stdout.readline()
|
||||
if output == '' and process.poll() is not None:
|
||||
break
|
||||
rc = process.poll()
|
||||
if rc != 0:
|
||||
return False
|
||||
except Exception:
|
||||
return False
|
||||
return True
|
||||
|
||||
def __get_bios_version(self):
|
||||
# Retrieves the BIOS firmware version
|
||||
try:
|
||||
with open(BIOS_VERSION_PATH, 'r') as fd:
|
||||
bios_version = fd.read()
|
||||
return bios_version.strip()
|
||||
except Exception as e:
|
||||
return None
|
||||
|
||||
def __get_cpld_version(self):
|
||||
# Retrieves the CPLD firmware version
|
||||
cpld_version = dict()
|
||||
for cpld_name in CPLD_ADDR_MAPPING:
|
||||
try:
|
||||
cpld_path = "{}{}{}".format(SYSFS_PATH, CPLD_ADDR_MAPPING[cpld_name], '/version')
|
||||
cpld_version_raw= self._api_helper.read_txt_file(cpld_path)
|
||||
cpld_version[cpld_name] = "{}".format(int(cpld_version_raw,16))
|
||||
except Exception as e:
|
||||
print('Get exception when read cpld')
|
||||
cpld_version[cpld_name] = 'None'
|
||||
|
||||
return cpld_version
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the component
|
||||
Returns:
|
||||
A string containing the name of the component
|
||||
"""
|
||||
return COMPONENT_LIST[self.index][0]
|
||||
|
||||
def get_description(self):
|
||||
"""
|
||||
Retrieves the description of the component
|
||||
Returns:
|
||||
A string containing the description of the component
|
||||
"""
|
||||
return COMPONENT_LIST[self.index][1]
|
||||
|
||||
def get_firmware_version(self):
|
||||
"""
|
||||
Retrieves the firmware version of module
|
||||
Returns:
|
||||
string: The firmware versions of the module
|
||||
"""
|
||||
fw_version = None
|
||||
|
||||
if self.name == "BIOS":
|
||||
fw_version = self.__get_bios_version()
|
||||
elif "CPLD" in self.name:
|
||||
cpld_version = self.__get_cpld_version()
|
||||
fw_version = cpld_version.get(self.name)
|
||||
|
||||
return fw_version
|
||||
|
||||
def install_firmware(self, image_path):
|
||||
"""
|
||||
Install firmware to module
|
||||
Args:
|
||||
image_path: A string, path to firmware image
|
||||
Returns:
|
||||
A boolean, True if install successfully, False if not
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the device
|
||||
Returns:
|
||||
bool: True if device 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
|
@ -0,0 +1,134 @@
|
||||
try:
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
if sys.version_info[0] >= 3:
|
||||
from io import StringIO
|
||||
else:
|
||||
from cStringIO import StringIO
|
||||
|
||||
from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo
|
||||
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):
|
||||
|
||||
EEPROM_DECODE_HEADLINES = 6
|
||||
|
||||
def __init__(self):
|
||||
self._eeprom_path = "/sys/bus/i2c/devices/0-0056/eeprom"
|
||||
super(Tlv, self).__init__(self._eeprom_path, 0, '', True)
|
||||
self._eeprom = self._load_eeprom()
|
||||
|
||||
def __parse_output(self, decode_output):
|
||||
decode_output.replace('\0', '')
|
||||
lines = decode_output.split('\n')
|
||||
lines = lines[self.EEPROM_DECODE_HEADLINES:]
|
||||
_eeprom_info_dict = dict()
|
||||
|
||||
for line in lines:
|
||||
try:
|
||||
match = re.search(
|
||||
'(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line)
|
||||
if match is not None:
|
||||
idx = match.group(1)
|
||||
value = match.group(3).rstrip('\0')
|
||||
|
||||
_eeprom_info_dict[idx] = value
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return _eeprom_info_dict
|
||||
|
||||
def _load_eeprom(self):
|
||||
original_stdout = sys.stdout
|
||||
sys.stdout = StringIO()
|
||||
try:
|
||||
self.read_eeprom_db()
|
||||
except Exception:
|
||||
decode_output = sys.stdout.getvalue()
|
||||
sys.stdout = original_stdout
|
||||
return self.__parse_output(decode_output)
|
||||
|
||||
status = self.check_status()
|
||||
if 'ok' not in status:
|
||||
return False
|
||||
|
||||
if not os.path.exists(CACHE_ROOT):
|
||||
try:
|
||||
os.makedirs(CACHE_ROOT)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
#
|
||||
# only the eeprom classes that inherit from eeprom_base
|
||||
# support caching. Others will work normally
|
||||
#
|
||||
try:
|
||||
self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
e = self.read_eeprom()
|
||||
if e is None:
|
||||
return 0
|
||||
|
||||
try:
|
||||
self.update_cache(e)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self.decode_eeprom(e)
|
||||
decode_output = sys.stdout.getvalue()
|
||||
sys.stdout = original_stdout
|
||||
|
||||
(is_valid, valid_crc) = self.is_checksum_valid(e)
|
||||
if not is_valid:
|
||||
return False
|
||||
|
||||
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._valid_tlv(self._eeprom)
|
||||
|
||||
def get_pn(self):
|
||||
return self._eeprom.get('0x22', NULL)
|
||||
|
||||
def get_serial(self):
|
||||
return self._eeprom.get('0x23', NULL)
|
||||
|
||||
def get_mac(self):
|
||||
return self._eeprom.get('0x24', NULL)
|
||||
|
||||
def get_product_name(self):
|
||||
return self._eeprom.get('0x21', NULL)
|
@ -0,0 +1,62 @@
|
||||
try:
|
||||
import time
|
||||
from .helper import APIHelper
|
||||
from sonic_py_common.logger import Logger
|
||||
except ImportError as e:
|
||||
raise ImportError(repr(e) + " - required module not found")
|
||||
|
||||
POLL_INTERVAL_IN_SEC = 1
|
||||
|
||||
class SfpEvent:
|
||||
''' Listen to insert/remove sfp events '''
|
||||
|
||||
def __init__(self, sfp_list):
|
||||
self._api_helper = APIHelper()
|
||||
self._sfp_list = sfp_list
|
||||
self._logger = Logger()
|
||||
self._sfp_change_event_data = {'present': 0}
|
||||
|
||||
def get_presence_bitmap(self):
|
||||
bitmap = 0
|
||||
for sfp in self._sfp_list:
|
||||
modpres = sfp.get_presence()
|
||||
i=sfp.port_num-1
|
||||
if modpres:
|
||||
bitmap = bitmap | (1 << i)
|
||||
return bitmap
|
||||
|
||||
def get_sfp_event(self, timeout=2000):
|
||||
port_dict = {}
|
||||
change_dict = {}
|
||||
change_dict['sfp'] = port_dict
|
||||
|
||||
if timeout < 1000:
|
||||
cd_ms = 1000
|
||||
else:
|
||||
cd_ms = timeout
|
||||
|
||||
while cd_ms > 0:
|
||||
bitmap = self.get_presence_bitmap()
|
||||
changed_ports = self._sfp_change_event_data['present'] ^ bitmap
|
||||
if changed_ports != 0:
|
||||
break
|
||||
time.sleep(POLL_INTERVAL_IN_SEC)
|
||||
# timeout=0 means wait for event forever
|
||||
if timeout != 0:
|
||||
cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000
|
||||
|
||||
if changed_ports != 0:
|
||||
for sfp in self._sfp_list:
|
||||
i=sfp.port_num-1
|
||||
if (changed_ports & (1 << i)):
|
||||
if (bitmap & (1 << i)) == 0:
|
||||
port_dict[i+1] = '0'
|
||||
else:
|
||||
port_dict[i+1] = '1'
|
||||
|
||||
|
||||
# Update the cache dict
|
||||
self._sfp_change_event_data['present'] = bitmap
|
||||
return True, change_dict
|
||||
else:
|
||||
return True, change_dict
|
263
device/accton/x86_64-accton_as7816_64x-r0/sonic_platform/fan.py
Normal file
263
device/accton/x86_64-accton_as7816_64x-r0/sonic_platform/fan.py
Normal file
@ -0,0 +1,263 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the fan status which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
from sonic_platform_base.fan_base import FanBase
|
||||
from .helper import APIHelper
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
SPEED_TOLERANCE = 15
|
||||
CPLD_FAN_I2C_PATH = "/sys/bus/i2c/devices/17-0068/fan"
|
||||
I2C_PATH ="/sys/bus/i2c/devices/{}-00{}/"
|
||||
PSU_HWMON_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 10,
|
||||
"addr": "5b"
|
||||
},
|
||||
1: {
|
||||
"num": 9,
|
||||
"addr": "58"
|
||||
},
|
||||
}
|
||||
|
||||
PSU_CPLD_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 10,
|
||||
"addr": "53"
|
||||
},
|
||||
1: {
|
||||
"num": 9,
|
||||
"addr": "50"
|
||||
},
|
||||
}
|
||||
|
||||
FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R",
|
||||
"FAN-3F", "FAN-3R", "FAN-4F", "FAN-4R"]
|
||||
|
||||
class Fan(FanBase):
|
||||
"""Platform-specific Fan class"""
|
||||
|
||||
def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0):
|
||||
self._api_helper=APIHelper()
|
||||
self.fan_index = fan_index
|
||||
self.fan_tray_index = fan_tray_index
|
||||
self.is_psu_fan = is_psu_fan
|
||||
|
||||
|
||||
if self.is_psu_fan:
|
||||
self.psu_index = psu_index
|
||||
self.psu_i2c_num = PSU_HWMON_I2C_MAPPING[self.psu_index]['num']
|
||||
self.psu_i2c_addr = PSU_HWMON_I2C_MAPPING[self.psu_index]['addr']
|
||||
self.psu_hwmon_path = I2C_PATH.format(
|
||||
self.psu_i2c_num, self.psu_i2c_addr)
|
||||
|
||||
self.psu_i2c_num = PSU_CPLD_I2C_MAPPING[self.psu_index]['num']
|
||||
self.psu_i2c_addr = PSU_CPLD_I2C_MAPPING[self.psu_index]['addr']
|
||||
self.psu_cpld_path = I2C_PATH.format(
|
||||
self.psu_i2c_num, self.psu_i2c_addr)
|
||||
|
||||
FanBase.__init__(self)
|
||||
|
||||
|
||||
def get_direction(self):
|
||||
"""
|
||||
Retrieves the direction of fan
|
||||
Returns:
|
||||
A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST
|
||||
depending on fan direction
|
||||
"""
|
||||
if not self.is_psu_fan:
|
||||
dir_str = "{}{}{}".format(CPLD_FAN_I2C_PATH, self.fan_tray_index+1, '_direction')
|
||||
val=self._api_helper.read_txt_file(dir_str)
|
||||
if val is not None: #F2B is FAN_DIRECTION_EXHAUST
|
||||
direction = self.FAN_DIRECTION_EXHAUST if (
|
||||
val == "0") else self.FAN_DIRECTION_INTAKE
|
||||
else:
|
||||
direction=self.FAN_DIRECTION_EXHAUST
|
||||
|
||||
else: #For PSU
|
||||
direction=self.FAN_DIRECTION_EXHAUST
|
||||
|
||||
return direction
|
||||
|
||||
def get_speed(self):
|
||||
"""
|
||||
Retrieves the speed of fan as a percentage of full speed
|
||||
Returns:
|
||||
An integer, the percentage of full fan speed, in the range 0 (off)
|
||||
to 100 (full speed)
|
||||
"""
|
||||
speed = 0
|
||||
if self.is_psu_fan:
|
||||
psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_speed_rpm')
|
||||
fan_speed_rpm = self._api_helper.read_txt_file(psu_fan_path)
|
||||
if fan_speed_rpm is not None:
|
||||
speed = (int(fan_speed_rpm,10))*100/26688
|
||||
if speed > 100:
|
||||
speed=100
|
||||
else:
|
||||
return 0
|
||||
elif self.get_presence():
|
||||
speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, '_duty_cycle_percentage')
|
||||
speed=self._api_helper.read_txt_file(speed_path)
|
||||
if speed is None:
|
||||
return 0
|
||||
return int(speed)
|
||||
|
||||
def get_target_speed(self):
|
||||
"""
|
||||
Retrieves the target (expected) speed of the fan
|
||||
Returns:
|
||||
An integer, the percentage of full fan speed, in the range 0 (off)
|
||||
to 100 (full speed)
|
||||
Note:
|
||||
speed_pc = pwm_target/255*100
|
||||
0 : when PWM mode is use
|
||||
pwm : when pwm mode is not use
|
||||
"""
|
||||
return self.get_speed()
|
||||
|
||||
def get_speed_tolerance(self):
|
||||
"""
|
||||
Retrieves the speed tolerance of the fan
|
||||
Returns:
|
||||
An integer, the percentage of variance from target speed which is
|
||||
considered tolerable
|
||||
"""
|
||||
return SPEED_TOLERANCE
|
||||
|
||||
def set_speed(self, speed):
|
||||
"""
|
||||
Sets the fan speed
|
||||
Args:
|
||||
speed: An integer, the percentage of full fan speed to set fan to,
|
||||
in the range 0 (off) to 100 (full speed)
|
||||
Returns:
|
||||
A boolean, True if speed is set successfully, False if not
|
||||
"""
|
||||
|
||||
if not self.is_psu_fan and self.get_presence():
|
||||
speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, '_duty_cycle_percentage')
|
||||
return self._api_helper.write_txt_file(speed_path, int(speed))
|
||||
|
||||
return False
|
||||
|
||||
def set_status_led(self, color):
|
||||
"""
|
||||
Sets the state of the fan module status LED
|
||||
Args:
|
||||
color: A string representing the color with which to set the
|
||||
fan module status LED
|
||||
Returns:
|
||||
bool: True if status LED state is set successfully, False if not
|
||||
"""
|
||||
return False #Not supported
|
||||
|
||||
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
|
||||
"""
|
||||
status=self.get_presence()
|
||||
if status is None:
|
||||
return self.STATUS_LED_COLOR_OFF
|
||||
|
||||
return {
|
||||
1: self.STATUS_LED_COLOR_GREEN,
|
||||
0: self.STATUS_LED_COLOR_RED
|
||||
}.get(status, self.STATUS_LED_COLOR_OFF)
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
fan_name = FAN_NAME_LIST[self.fan_tray_index*2 + self.fan_index] \
|
||||
if not self.is_psu_fan \
|
||||
else "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1)
|
||||
|
||||
return fan_name
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the FAN
|
||||
Returns:
|
||||
bool: True if FAN is present, False if not
|
||||
"""
|
||||
present_path = "{}{}{}".format(CPLD_FAN_I2C_PATH, self.fan_tray_index+1, '_present')
|
||||
val=self._api_helper.read_txt_file(present_path)
|
||||
if not self.is_psu_fan:
|
||||
if val is not None:
|
||||
return int(val, 10)==1
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the device
|
||||
Returns:
|
||||
A boolean value, True if device is operating properly, False if not
|
||||
"""
|
||||
if self.is_psu_fan:
|
||||
psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_fault')
|
||||
val=self._api_helper.read_txt_file(psu_fan_path)
|
||||
if val is not None:
|
||||
return int(val, 10)==0
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
path = "{}{}{}".format(CPLD_FAN_I2C_PATH, self.fan_tray_index+1, '_fault')
|
||||
val=self._api_helper.read_txt_file(path)
|
||||
if val is not None:
|
||||
return int(val, 10)==0
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
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_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_index+1) \
|
||||
if not self.is_psu_fan else (self.psu_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
|
@ -0,0 +1,90 @@
|
||||
########################################################################
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides 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")
|
||||
|
||||
FANS_PER_FANTRAY = 2
|
||||
|
||||
|
||||
class FanDrawer(FanDrawerBase):
|
||||
"""Platform-specific Fan class"""
|
||||
|
||||
def __init__(self, fantray_index):
|
||||
|
||||
FanDrawerBase.__init__(self)
|
||||
# FanTray is 0-based in platforms
|
||||
self.fantrayindex = fantray_index
|
||||
self.__initialize_fan_drawer()
|
||||
|
||||
|
||||
def __initialize_fan_drawer(self):
|
||||
from sonic_platform.fan import Fan
|
||||
for i in range(FANS_PER_FANTRAY):
|
||||
self._fan_list.append(Fan(self.fantrayindex, i))
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the fan drawer name
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
return "FanTray{}".format(self.fantrayindex+1)
|
||||
|
||||
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.
|
||||
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.fantrayindex+1)
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return True
|
@ -0,0 +1,117 @@
|
||||
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, 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', errors='replace') as fd:
|
||||
data = fd.read()
|
||||
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 IOError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def ipmi_raw(self, netfn, cmd):
|
||||
status = True
|
||||
result = ""
|
||||
try:
|
||||
cmd = "ipmitool raw {} {}".format(str(netfn), str(cmd))
|
||||
p = subprocess.Popen(
|
||||
cmd, shell=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, 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, 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
|
@ -0,0 +1,21 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the platform information
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
from sonic_platform_base.platform_base import PlatformBase
|
||||
from sonic_platform.chassis import Chassis
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Platform(PlatformBase):
|
||||
"""Platform-specific Platform class"""
|
||||
|
||||
def __init__(self):
|
||||
PlatformBase.__init__(self)
|
||||
self._chassis = Chassis()
|
283
device/accton/x86_64-accton_as7816_64x-r0/sonic_platform/psu.py
Normal file
283
device/accton/x86_64-accton_as7816_64x-r0/sonic_platform/psu.py
Normal file
@ -0,0 +1,283 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the PSUs status which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
from sonic_platform_base.psu_base import PsuBase
|
||||
from sonic_platform.thermal import Thermal
|
||||
from .helper import APIHelper
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
I2C_PATH ="/sys/bus/i2c/devices/{0}-00{1}/"
|
||||
|
||||
PSU_NAME_LIST = ["PSU-1", "PSU-2"]
|
||||
PSU_NUM_FAN = [1, 1]
|
||||
PSU_CPLD_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 10,
|
||||
"addr": "53"
|
||||
},
|
||||
1: {
|
||||
"num": 9,
|
||||
"addr": "50"
|
||||
},
|
||||
}
|
||||
|
||||
PSU_HWMON_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 10,
|
||||
"addr": "5b"
|
||||
},
|
||||
1: {
|
||||
"num": 9,
|
||||
"addr": "58"
|
||||
},
|
||||
}
|
||||
|
||||
NUM_FAN_TRAY = 4
|
||||
|
||||
class Psu(PsuBase):
|
||||
"""Platform-specific Psu class"""
|
||||
def __init__(self, psu_index=0):
|
||||
PsuBase.__init__(self)
|
||||
self.index = psu_index
|
||||
self._api_helper = APIHelper()
|
||||
|
||||
self.i2c_num = PSU_HWMON_I2C_MAPPING[self.index]["num"]
|
||||
self.i2c_addr = PSU_HWMON_I2C_MAPPING[self.index]["addr"]
|
||||
self.hwmon_path = I2C_PATH.format(self.i2c_num, self.i2c_addr)
|
||||
|
||||
self.i2c_num = PSU_CPLD_I2C_MAPPING[self.index]["num"]
|
||||
self.i2c_addr = PSU_CPLD_I2C_MAPPING[self.index]["addr"]
|
||||
self.cpld_path = I2C_PATH.format(self.i2c_num, self.i2c_addr)
|
||||
|
||||
self.__initialize_fan()
|
||||
|
||||
def __initialize_fan(self):
|
||||
from sonic_platform.fan import Fan
|
||||
self._fan_list.append(
|
||||
Fan(NUM_FAN_TRAY + self.index,
|
||||
is_psu_fan=True,
|
||||
psu_index=self.index))
|
||||
self._thermal_list.append(Thermal(is_psu=True, psu_index=self.index))
|
||||
|
||||
def __read_txt_file(self, file_path):
|
||||
try:
|
||||
with open(file_path, 'r') as fd:
|
||||
return fd.read().strip()
|
||||
except IOError:
|
||||
pass
|
||||
return None
|
||||
|
||||
def get_voltage(self):
|
||||
"""
|
||||
Retrieves current PSU voltage output
|
||||
Returns:
|
||||
A float number, the output voltage in volts,
|
||||
e.g. 12.1
|
||||
"""
|
||||
vout_path = "{}{}".format(self.hwmon_path, 'psu_v_out')
|
||||
vout_val=self._api_helper.read_txt_file(vout_path)
|
||||
|
||||
if vout_val is not None:
|
||||
return float(vout_val)/ 1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_current(self):
|
||||
"""
|
||||
Retrieves present electric current supplied by PSU
|
||||
Returns:
|
||||
A float number, the electric current in amperes, e.g 15.4
|
||||
"""
|
||||
iout_path = "{}{}".format(self.hwmon_path, 'psu_i_out')
|
||||
val=self._api_helper.read_txt_file(iout_path)
|
||||
if val is not None:
|
||||
return float(val)/1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_power(self):
|
||||
"""
|
||||
Retrieves current energy supplied by PSU
|
||||
Returns:
|
||||
A float number, the power in watts, e.g. 302.6
|
||||
"""
|
||||
pout_path = "{}{}".format(self.hwmon_path, 'psu_p_out')
|
||||
val=self._api_helper.read_txt_file(pout_path)
|
||||
if val is not None:
|
||||
return float(val)/1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_powergood_status(self):
|
||||
"""
|
||||
Retrieves the powergood status of PSU
|
||||
Returns:
|
||||
A boolean, True if PSU has stablized its output voltages and passed all
|
||||
its internal self-tests, False if not.
|
||||
"""
|
||||
return self.get_status()
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
return False #Controlled by HW
|
||||
|
||||
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.get_status()
|
||||
if status is None:
|
||||
return self.STATUS_LED_COLOR_OFF
|
||||
|
||||
return {
|
||||
1: self.STATUS_LED_COLOR_GREEN,
|
||||
0: self.STATUS_LED_COLOR_RED
|
||||
}.get(status, self.STATUS_LED_COLOR_OFF)
|
||||
|
||||
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
|
||||
"""
|
||||
temp_path = "{}{}".format(self.hwmon_path, 'psu_temp1_input')
|
||||
val=self._api_helper.read_txt_file(temp_path)
|
||||
if val is not None:
|
||||
return float(val)/1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_temperature_high_threshold(self):
|
||||
"""
|
||||
Retrieves the high threshold temperature of PSU
|
||||
Returns:
|
||||
A float number, the high threshold temperature of PSU in Celsius
|
||||
up to nearest thousandth of one degree Celsius, e.g. 30.125
|
||||
"""
|
||||
return False #Not supported
|
||||
|
||||
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
|
||||
"""
|
||||
vout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_vout_max')
|
||||
vout_val=self._api_helper.read_txt_file(vout_path)
|
||||
if vout_val is not None:
|
||||
return float(vout_val)/ 1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
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
|
||||
"""
|
||||
vout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_vout_min')
|
||||
vout_val=self._api_helper.read_txt_file(vout_path)
|
||||
if vout_val is not None:
|
||||
return float(vout_val)/ 1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
return PSU_NAME_LIST[self.index]
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the PSU
|
||||
Returns:
|
||||
bool: True if PSU is present, False if not
|
||||
"""
|
||||
presence_path="{}{}".format(self.cpld_path, 'psu_present')
|
||||
val=self._api_helper.read_txt_file(presence_path)
|
||||
if val is not None:
|
||||
return int(val, 10) == 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the device
|
||||
Returns:
|
||||
A boolean value, True if device is operating properly, False if not
|
||||
"""
|
||||
power_path="{}{}".format(self.cpld_path, 'psu_power_good')
|
||||
val=self._api_helper.read_txt_file(power_path)
|
||||
if val is not None:
|
||||
return int(val, 10) == 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the device
|
||||
Returns:
|
||||
string: Model/part number of device
|
||||
"""
|
||||
model_path="{}{}".format(self.hwmon_path, 'psu_mfr_model')
|
||||
val=self._api_helper.read_txt_file(model_path)
|
||||
if val is None:
|
||||
return "N/A"
|
||||
model=val[1:]
|
||||
|
||||
return model
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the device
|
||||
Returns:
|
||||
string: Serial number of device
|
||||
"""
|
||||
serial_path="{}{}".format(self.hwmon_path, 'psu_mfr_serial')
|
||||
val=self._api_helper.read_txt_file(serial_path)
|
||||
if val is None:
|
||||
return "N/A"
|
||||
serial=val[1:]
|
||||
|
||||
return serial
|
||||
|
||||
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.index+1
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return True
|
506
device/accton/x86_64-accton_as7816_64x-r0/sonic_platform/sfp.py
Normal file
506
device/accton/x86_64-accton_as7816_64x-r0/sonic_platform/sfp.py
Normal file
@ -0,0 +1,506 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Sfp contains an implementation of SONiC Platform Base API and
|
||||
# provides the sfp device status which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
import os
|
||||
import time
|
||||
import sys
|
||||
|
||||
from ctypes import create_string_buffer
|
||||
|
||||
try:
|
||||
from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase
|
||||
from .helper import APIHelper
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
CPLD_I2C_PATH = "/sys/bus/i2c/devices/19-0060/"
|
||||
|
||||
|
||||
class Sfp(SfpOptoeBase):
|
||||
"""Platform-specific Sfp class"""
|
||||
|
||||
# Port number
|
||||
PORT_START = 1
|
||||
PORT_END = 64
|
||||
|
||||
# Path to sysfs
|
||||
PLATFORM_ROOT_PATH = "/usr/share/sonic/device"
|
||||
PMON_HWSKU_PATH = "/usr/share/sonic/hwsku"
|
||||
HOST_CHK_CMD = "which systemctl > /dev/null 2>&1"
|
||||
|
||||
PLATFORM = "x86_64-accton_as7816_64x-r0"
|
||||
HWSKU = "Accton-AS7816-64X"
|
||||
|
||||
_port_to_i2c_mapping = {
|
||||
61: 25,
|
||||
62: 26,
|
||||
63: 27,
|
||||
64: 28,
|
||||
55: 29,
|
||||
56: 30,
|
||||
53: 31,
|
||||
54: 32,
|
||||
9: 33,
|
||||
10: 34,
|
||||
11: 35,
|
||||
12: 36,
|
||||
1: 37,
|
||||
2: 38,
|
||||
3: 39,
|
||||
4: 40,
|
||||
6: 41,
|
||||
5: 42,
|
||||
8: 43,
|
||||
7: 44,
|
||||
13: 45,
|
||||
14: 46,
|
||||
15: 47,
|
||||
16: 48,
|
||||
17: 49,
|
||||
18: 50,
|
||||
19: 51,
|
||||
20: 52,
|
||||
25: 53,
|
||||
26: 54,
|
||||
27: 55,
|
||||
28: 56,
|
||||
29: 57,
|
||||
30: 58,
|
||||
31: 59,
|
||||
32: 60,
|
||||
21: 61,
|
||||
22: 62,
|
||||
23: 63,
|
||||
24: 64,
|
||||
41: 65,
|
||||
42: 66,
|
||||
43: 67,
|
||||
44: 68,
|
||||
33: 69,
|
||||
34: 70,
|
||||
35: 71,
|
||||
36: 72,
|
||||
45: 73,
|
||||
46: 74,
|
||||
47: 75,
|
||||
48: 76,
|
||||
37: 77,
|
||||
38: 78,
|
||||
39: 79,
|
||||
40: 80,
|
||||
57: 81,
|
||||
58: 82,
|
||||
59: 83,
|
||||
60: 84,
|
||||
49: 85,
|
||||
50: 86,
|
||||
51: 87,
|
||||
52: 88
|
||||
}
|
||||
|
||||
def __init__(self, sfp_index=0):
|
||||
SfpOptoeBase.__init__(self)
|
||||
self._api_helper=APIHelper()
|
||||
# Init index
|
||||
self.index = sfp_index
|
||||
self.port_num = self.index + 1
|
||||
# Init eeprom path
|
||||
eeprom_path = '/sys/bus/i2c/devices/{0}-0050/eeprom'
|
||||
self.port_to_eeprom_mapping = {}
|
||||
for x in range(self.PORT_START, self.PORT_END + 1):
|
||||
self.port_to_eeprom_mapping[x] = eeprom_path.format(self._port_to_i2c_mapping[x])
|
||||
|
||||
def get_eeprom_path(self):
|
||||
return self.port_to_eeprom_mapping[self.port_num]
|
||||
|
||||
def __is_host(self):
|
||||
return os.system(self.HOST_CHK_CMD) == 0
|
||||
|
||||
def __get_path_to_port_config_file(self):
|
||||
platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM])
|
||||
hwsku_path = "/".join([platform_path, self.HWSKU]
|
||||
) if self.__is_host() else self.PMON_HWSKU_PATH
|
||||
return "/".join([hwsku_path, "port_config.ini"])
|
||||
|
||||
def __read_eeprom_specific_bytes(self, offset, num_bytes):
|
||||
sysfsfile_eeprom = None
|
||||
eeprom_raw = []
|
||||
for i in range(0, num_bytes):
|
||||
eeprom_raw.append("0x00")
|
||||
|
||||
sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num]
|
||||
try:
|
||||
sysfsfile_eeprom = open(
|
||||
sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0)
|
||||
sysfsfile_eeprom.seek(offset)
|
||||
raw = sysfsfile_eeprom.read(num_bytes)
|
||||
if sys.version_info[0] >= 3:
|
||||
for n in range(0, num_bytes):
|
||||
eeprom_raw[n] = hex(raw[n])[2:].zfill(2)
|
||||
else:
|
||||
for n in range(0, num_bytes):
|
||||
eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2)
|
||||
except Exception:
|
||||
pass
|
||||
finally:
|
||||
if sysfsfile_eeprom:
|
||||
sysfsfile_eeprom.close()
|
||||
|
||||
return eeprom_raw
|
||||
|
||||
def get_reset_status(self):
|
||||
"""
|
||||
Retrieves the reset status of SFP
|
||||
Returns:
|
||||
A Boolean, True if reset enabled, False if disabled
|
||||
"""
|
||||
reset_path="{}{}{}".format(CPLD_I2C_PATH , "module_reset_" , str(self.port_num))
|
||||
val = self._api_helper.read_txt_file(reset_path)
|
||||
|
||||
if val is not None:
|
||||
return int(val, 10) == 1
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_rx_los(self):
|
||||
"""
|
||||
Retrieves the RX LOS (lost-of-signal) status of SFP
|
||||
Returns:
|
||||
A Boolean, True if SFP has RX LOS, False if not.
|
||||
Note : RX LOS status is latched until a call to get_rx_los or a reset.
|
||||
"""
|
||||
|
||||
rx_los_list = []
|
||||
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
|
||||
QSFP_CHANNL_RX_LOS_STATUS_OFFSET, QSFP_CHANNL_RX_LOS_STATUS_WIDTH) if self.get_presence() else None
|
||||
if dom_channel_monitor_raw is not None:
|
||||
rx_los_data = int(dom_channel_monitor_raw[0], 16)
|
||||
rx_los_list.append(rx_los_data & 0x01 != 0)
|
||||
rx_los_list.append(rx_los_data & 0x02 != 0)
|
||||
rx_los_list.append(rx_los_data & 0x04 != 0)
|
||||
rx_los_list.append(rx_los_data & 0x08 != 0)
|
||||
return rx_los_list
|
||||
else:
|
||||
return [False]*4
|
||||
|
||||
|
||||
def get_tx_fault(self):
|
||||
"""
|
||||
Retrieves the TX fault status of SFP
|
||||
Returns:
|
||||
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_list = []
|
||||
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
|
||||
QSFP_CHANNL_TX_FAULT_STATUS_OFFSET, QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) if self.get_presence() else None
|
||||
if dom_channel_monitor_raw is not None:
|
||||
tx_fault_data = int(dom_channel_monitor_raw[0], 16)
|
||||
tx_fault_list.append(tx_fault_data & 0x01 != 0)
|
||||
tx_fault_list.append(tx_fault_data & 0x02 != 0)
|
||||
tx_fault_list.append(tx_fault_data & 0x04 != 0)
|
||||
tx_fault_list.append(tx_fault_data & 0x08 != 0)
|
||||
return tx_fault_list
|
||||
else:
|
||||
return [False]*4
|
||||
|
||||
def get_tx_disable(self):
|
||||
"""
|
||||
Retrieves the tx_disable status of this SFP
|
||||
Returns:
|
||||
A Boolean, True if tx_disable is enabled, False if disabled
|
||||
"""
|
||||
|
||||
tx_disable_list = []
|
||||
|
||||
sfpd_obj = sff8436Dom()
|
||||
if sfpd_obj is None:
|
||||
return False
|
||||
|
||||
dom_control_raw = self.__read_eeprom_specific_bytes(
|
||||
QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None
|
||||
if dom_control_raw is not None:
|
||||
dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0)
|
||||
tx_disable_list.append(
|
||||
'On' == dom_control_data['data']['TX1Disable']['value'])
|
||||
tx_disable_list.append(
|
||||
'On' == dom_control_data['data']['TX2Disable']['value'])
|
||||
tx_disable_list.append(
|
||||
'On' == dom_control_data['data']['TX3Disable']['value'])
|
||||
tx_disable_list.append(
|
||||
'On' == dom_control_data['data']['TX4Disable']['value'])
|
||||
return tx_disable_list
|
||||
else:
|
||||
return [False]*4
|
||||
|
||||
def get_tx_disable_channel(self):
|
||||
"""
|
||||
Retrieves the TX disabled channels in this SFP
|
||||
Returns:
|
||||
A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent
|
||||
TX channels which have been disabled in this SFP.
|
||||
As an example, a returned value of 0x5 indicates that channel 0
|
||||
and channel 2 have been disabled.
|
||||
"""
|
||||
tx_disable_list = self.get_tx_disable()
|
||||
if tx_disable_list is None:
|
||||
return 0
|
||||
tx_disabled = 0
|
||||
for i in range(len(tx_disable_list)):
|
||||
if tx_disable_list[i]:
|
||||
tx_disabled |= 1 << i
|
||||
return tx_disabled
|
||||
|
||||
def get_lpmode(self):
|
||||
"""
|
||||
Retrieves the lpmode (low power mode) status of this SFP
|
||||
Returns:
|
||||
A Boolean, True if lpmode is enabled, False if disabled
|
||||
"""
|
||||
|
||||
power_set=self.get_power_set()
|
||||
power_override = self.get_power_override()
|
||||
return power_set and power_override
|
||||
|
||||
def get_power_set(self):
|
||||
power_set = False
|
||||
sfpd_obj = sff8436Dom()
|
||||
if sfpd_obj is None:
|
||||
return False
|
||||
dom_control_raw = self.__read_eeprom_specific_bytes(
|
||||
QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None
|
||||
if dom_control_raw is not None:
|
||||
dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0)
|
||||
power_set = (
|
||||
'On' == dom_control_data['data']['PowerSet']['value'])
|
||||
|
||||
return power_set
|
||||
|
||||
def get_power_override(self):
|
||||
"""
|
||||
Retrieves the power-override status of this SFP
|
||||
Returns:
|
||||
A Boolean, True if power-override is enabled, False if disabled
|
||||
"""
|
||||
power_override = False
|
||||
sfpd_obj = sff8436Dom()
|
||||
if sfpd_obj is None:
|
||||
return False
|
||||
|
||||
dom_control_raw = self.__read_eeprom_specific_bytes(
|
||||
QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None
|
||||
if dom_control_raw is not None:
|
||||
dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0)
|
||||
power_override = (
|
||||
'On' == dom_control_data['data']['PowerOverride']['value'])
|
||||
|
||||
return power_override
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset SFP and return all user module settings to their default srate.
|
||||
Returns:
|
||||
A boolean, True if successful, False if not
|
||||
"""
|
||||
reset_path = "{}{}{}".format(CPLD_I2C_PATH , 'module_reset_' , self.port_num)
|
||||
ret = self._api_helper.write_txt_file(reset_path, 1)
|
||||
if ret is not True:
|
||||
return ret
|
||||
|
||||
time.sleep(0.01)
|
||||
ret = self._api_helper.write_txt_file(reset_path, 0)
|
||||
time.sleep(0.2)
|
||||
|
||||
return ret
|
||||
|
||||
def tx_disable(self, tx_disable):
|
||||
"""
|
||||
Disable SFP TX for all channels
|
||||
Args:
|
||||
tx_disable : A Boolean, True to enable tx_disable mode, False to disable
|
||||
tx_disable mode.
|
||||
Returns:
|
||||
A boolean, True if tx_disable is set successfully, False if not
|
||||
"""
|
||||
if not self.get_presence():
|
||||
return False
|
||||
sysfsfile_eeprom = None
|
||||
try:
|
||||
tx_disable_ctl = 0xf if tx_disable else 0x0
|
||||
buffer = create_string_buffer(1)
|
||||
if sys.version_info[0] >= 3:
|
||||
buffer[0] = tx_disable_ctl
|
||||
else:
|
||||
buffer[0] = chr(tx_disable_ctl)
|
||||
# Write to eeprom
|
||||
sysfsfile_eeprom = open(
|
||||
self.port_to_eeprom_mapping[self.port_num], "r+b")
|
||||
sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET)
|
||||
sysfsfile_eeprom.write(buffer[0])
|
||||
except IOError as e:
|
||||
print ('Error: unable to open file: ',str(e))
|
||||
return False
|
||||
finally:
|
||||
if sysfsfile_eeprom is not None:
|
||||
sysfsfile_eeprom.close()
|
||||
time.sleep(0.01)
|
||||
|
||||
return True
|
||||
|
||||
def tx_disable_channel(self, channel, disable):
|
||||
"""
|
||||
Sets the tx_disable for specified SFP channels
|
||||
Args:
|
||||
channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3,
|
||||
e.g. 0x5 for channel 0 and channel 2.
|
||||
disable : A boolean, True to disable TX channels specified in channel,
|
||||
False to enable
|
||||
Returns:
|
||||
A boolean, True if successful, False if not
|
||||
"""
|
||||
if not self.get_presence():
|
||||
return False
|
||||
|
||||
sysfsfile_eeprom = None
|
||||
try:
|
||||
channel_state = self.get_tx_disable_channel()
|
||||
for i in range(4):
|
||||
channel_mask = (1 << i)
|
||||
if not (channel & channel_mask):
|
||||
continue
|
||||
|
||||
if disable:
|
||||
channel_state |= channel_mask
|
||||
else:
|
||||
channel_state &= ~channel_mask
|
||||
|
||||
buffer = create_string_buffer(1)
|
||||
if sys.version_info[0] >= 3:
|
||||
buffer[0] = channel_state
|
||||
else:
|
||||
buffer[0] = chr(channel_state)
|
||||
# Write to eeprom
|
||||
sysfsfile_eeprom = open(
|
||||
self.port_to_eeprom_mapping[self.port_num], "r+b")
|
||||
sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET)
|
||||
sysfsfile_eeprom.write(buffer[0])
|
||||
except IOError as e:
|
||||
print ('Error: unable to open file: ', str(e))
|
||||
return False
|
||||
finally:
|
||||
if sysfsfile_eeprom is not None:
|
||||
sysfsfile_eeprom.close()
|
||||
time.sleep(0.01)
|
||||
|
||||
return True
|
||||
|
||||
def set_lpmode(self, lpmode):
|
||||
"""
|
||||
Sets the lpmode (low power mode) of SFP
|
||||
Args:
|
||||
lpmode: A Boolean, True to enable lpmode, False to disable it
|
||||
Note : lpmode can be overridden by set_power_override
|
||||
Returns:
|
||||
A boolean, True if lpmode is set successfully, False if not
|
||||
"""
|
||||
if lpmode:
|
||||
self.set_power_override(True, True)
|
||||
else:
|
||||
self.set_power_override(False, False)
|
||||
|
||||
return True
|
||||
|
||||
def set_power_override(self, power_override, power_set):
|
||||
"""
|
||||
Sets SFP power level using power_override and power_set
|
||||
Args:
|
||||
power_override :
|
||||
A Boolean, True to override set_lpmode and use power_set
|
||||
to control SFP power, False to disable SFP power control
|
||||
through power_override/power_set and use set_lpmode
|
||||
to control SFP power.
|
||||
power_set :
|
||||
Only valid when power_override is True.
|
||||
A Boolean, True to set SFP to low power mode, False to set
|
||||
SFP to high power mode.
|
||||
Returns:
|
||||
A boolean, True if power-override and power_set are set successfully,
|
||||
False if not
|
||||
"""
|
||||
|
||||
if not self.get_presence():
|
||||
return False
|
||||
try:
|
||||
power_override_bit = (1 << 0) if power_override else 0
|
||||
power_set_bit = (1 << 1) if power_set else (1 << 3)
|
||||
|
||||
buffer = create_string_buffer(1)
|
||||
if sys.version_info[0] >= 3:
|
||||
buffer[0] = (power_override_bit | power_set_bit)
|
||||
else:
|
||||
buffer[0] = chr(power_override_bit | power_set_bit)
|
||||
# Write to eeprom
|
||||
with open(self.port_to_eeprom_mapping[self.port_num], "r+b") as fd:
|
||||
fd.seek(QSFP_POWEROVERRIDE_OFFSET)
|
||||
fd.write(buffer[0])
|
||||
time.sleep(0.01)
|
||||
except Exception:
|
||||
print ('Error: unable to open file: ', str(e))
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
sfputil_helper = SfpUtilHelper()
|
||||
sfputil_helper.read_porttab_mappings(
|
||||
self.__get_path_to_port_config_file())
|
||||
name = sfputil_helper.logical[self.index] or "Unknown"
|
||||
return name
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the device
|
||||
Returns:
|
||||
bool: True if device is present, False if not
|
||||
"""
|
||||
present_path = "{}{}{}".format(CPLD_I2C_PATH , '/module_present_' , self.port_num)
|
||||
val=self._api_helper.read_txt_file(present_path)
|
||||
if val is not None:
|
||||
return int(val, 10)==1
|
||||
else:
|
||||
return False
|
||||
|
||||
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()
|
||||
|
||||
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.port_num
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return True
|
@ -0,0 +1,236 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Thermal contains an implementation of SONiC Platform Base API and
|
||||
# provides the thermal device status which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import glob
|
||||
|
||||
try:
|
||||
from sonic_platform_base.thermal_base import ThermalBase
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
PSU_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/"
|
||||
|
||||
PSU_HWMON_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 10,
|
||||
"addr": "5b"
|
||||
},
|
||||
1: {
|
||||
"num": 9,
|
||||
"addr": "58"
|
||||
},
|
||||
}
|
||||
|
||||
PSU_CPLD_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 10,
|
||||
"addr": "53"
|
||||
},
|
||||
1: {
|
||||
"num": 9,
|
||||
"addr": "50"
|
||||
},
|
||||
}
|
||||
|
||||
THERMAL_NAME_LIST = ["Temp sensor 1", "Temp sensor 2", "Temp sensor 3",
|
||||
"Temp sensor 4", "Temp sensor 5", "Temp sensor 6"]
|
||||
|
||||
PSU_THERMAL_NAME_LIST = ["PSU-1 temp sensor 1", "PSU-2 temp sensor 2"]
|
||||
|
||||
SYSFS_PATH = "/sys/bus/i2c/devices"
|
||||
|
||||
class Thermal(ThermalBase):
|
||||
"""Platform-specific Thermal class"""
|
||||
|
||||
def __init__(self, thermal_index=0, is_psu=False, psu_index=0):
|
||||
self.index = thermal_index
|
||||
self.is_psu = is_psu
|
||||
self.psu_index = psu_index
|
||||
|
||||
if self.is_psu:
|
||||
psu_i2c_bus = PSU_HWMON_I2C_MAPPING[psu_index]["num"]
|
||||
psu_i2c_addr = PSU_HWMON_I2C_MAPPING[psu_index]["addr"]
|
||||
self.psu_hwmon_path = PSU_I2C_PATH.format(psu_i2c_bus,
|
||||
psu_i2c_addr)
|
||||
psu_i2c_bus = PSU_CPLD_I2C_MAPPING[psu_index]["num"]
|
||||
psu_i2c_addr = PSU_CPLD_I2C_MAPPING[psu_index]["addr"]
|
||||
self.cpld_path = PSU_I2C_PATH.format(psu_i2c_bus, psu_i2c_addr)
|
||||
|
||||
# Set hwmon path
|
||||
i2c_path = {
|
||||
0: "18-0048/hwmon/hwmon*/",
|
||||
1: "18-0049/hwmon/hwmon*/",
|
||||
2: "18-004a/hwmon/hwmon*/",
|
||||
3: "18-004b/hwmon/hwmon*/",
|
||||
4: "17-004d/hwmon/hwmon*/",
|
||||
5: "17-004d/hwmon/hwmon*/"
|
||||
}.get(self.index, None)
|
||||
|
||||
self.hwmon_path = "{}/{}".format(SYSFS_PATH, i2c_path)
|
||||
self.ss_key = THERMAL_NAME_LIST[self.index]
|
||||
self.ss_index = 1
|
||||
|
||||
def __read_txt_file(self, file_path):
|
||||
for filename in glob.glob(file_path):
|
||||
try:
|
||||
with open(filename, 'r') as fd:
|
||||
data =fd.readline().rstrip()
|
||||
return data
|
||||
except IOError as e:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def __get_temp(self, temp_file):
|
||||
if not self.is_psu:
|
||||
temp_file_path = os.path.join(self.hwmon_path, temp_file)
|
||||
else:
|
||||
temp_file_path = temp_file
|
||||
raw_temp = self.__read_txt_file(temp_file_path)
|
||||
if raw_temp is not None:
|
||||
return float(raw_temp)/1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def __set_threshold(self, file_name, temperature):
|
||||
if self.is_psu:
|
||||
return True
|
||||
temp_file_path = os.path.join(self.hwmon_path, file_name)
|
||||
for filename in glob.glob(temp_file_path):
|
||||
try:
|
||||
with open(filename, 'w') as fd:
|
||||
fd.write(str(temperature))
|
||||
return True
|
||||
except IOError as e:
|
||||
print("IOError")
|
||||
return False
|
||||
|
||||
|
||||
def get_temperature(self):
|
||||
"""
|
||||
Retrieves current temperature reading from thermal
|
||||
Returns:
|
||||
A float number of current temperature in Celsius up to nearest thousandth
|
||||
of one degree Celsius, e.g. 30.125
|
||||
"""
|
||||
if not self.is_psu:
|
||||
temp_file = "temp{}_input".format(self.ss_index)
|
||||
else:
|
||||
temp_file = self.psu_hwmon_path + "psu_temp1_input"
|
||||
return self.__get_temp(temp_file)
|
||||
|
||||
def get_high_threshold(self):
|
||||
"""
|
||||
Retrieves the high threshold temperature of thermal
|
||||
Returns:
|
||||
A float number, the high threshold temperature of thermal in Celsius
|
||||
up to nearest thousandth of one degree Celsius, e.g. 30.125
|
||||
"""
|
||||
if self.is_psu:
|
||||
return 80
|
||||
|
||||
temp_file = "temp{}_max".format(self.ss_index)
|
||||
return self.__get_temp(temp_file)
|
||||
|
||||
def set_high_threshold(self, temperature):
|
||||
"""
|
||||
Sets the high threshold temperature of thermal
|
||||
Args :
|
||||
temperature: A float number up to nearest thousandth of one degree Celsius,
|
||||
e.g. 30.125
|
||||
Returns:
|
||||
A boolean, True if threshold is set successfully, False if not
|
||||
"""
|
||||
temp_file = "temp{}_max".format(self.ss_index)
|
||||
temperature = temperature *1000
|
||||
self.__set_threshold(temp_file, temperature)
|
||||
|
||||
return True
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the thermal device
|
||||
Returns:
|
||||
string: The name of the thermal device
|
||||
"""
|
||||
if self.is_psu:
|
||||
return PSU_THERMAL_NAME_LIST[self.psu_index]
|
||||
else:
|
||||
return THERMAL_NAME_LIST[self.index]
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the Thermal
|
||||
Returns:
|
||||
bool: True if Thermal is present, False if not
|
||||
"""
|
||||
if self.is_psu:
|
||||
val = self.__read_txt_file(self.cpld_path + "psu_present")
|
||||
return int(val, 10) == 1
|
||||
temp_file = "temp{}_input".format(self.ss_index)
|
||||
temp_file_path = os.path.join(self.hwmon_path, temp_file)
|
||||
raw_txt = self.__read_txt_file(temp_file_path)
|
||||
if raw_txt is not None:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the device
|
||||
Returns:
|
||||
A boolean value, True if device is operating properly, False if not
|
||||
"""
|
||||
if self.is_psu:
|
||||
temp_file = self.psu_hwmon_path + "psu_temp_fault"
|
||||
return self.get_presence() and (not int(
|
||||
self.__read_txt_file(temp_file)))
|
||||
|
||||
file_str = "temp{}_input".format(self.ss_index)
|
||||
file_path = os.path.join(self.hwmon_path, file_str)
|
||||
raw_txt = self.__read_txt_file(file_path)
|
||||
if raw_txt is None:
|
||||
return False
|
||||
else:
|
||||
return int(raw_txt) != 0
|
||||
|
||||
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_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.index+1
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Retrieves whether thermal module is replaceable
|
||||
Returns:
|
||||
A boolean value, True if replaceable, False if not
|
||||
"""
|
||||
return False
|
@ -0,0 +1,15 @@
|
||||
{
|
||||
"services_to_ignore": [],
|
||||
"devices_to_ignore": [
|
||||
"asic",
|
||||
"psu.temperature"
|
||||
|
||||
],
|
||||
"user_defined_checkers": [],
|
||||
"polling_interval": 60,
|
||||
"led_color": {
|
||||
"fault": "STATUS_LED_COLOR_RED",
|
||||
"normal": "STATUS_LED_COLOR_GREEN",
|
||||
"booting": "STATUS_LED_COLOR_GREEN"
|
||||
}
|
||||
}
|
5
platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/Makefile
Executable file → Normal file
5
platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/Makefile
Executable file → Normal file
@ -4,10 +4,7 @@ obj-m:= x86-64-accton-as4630-54pe-cpld.o x86-64-accton-as4630-54pe-psu.o \
|
||||
|
||||
else
|
||||
ifeq (,$(KERNEL_SRC))
|
||||
#$(error KERNEL_SRC is not defined)
|
||||
KVERSION=3.16.0-8-amd64
|
||||
KERNEL_DIR = /usr/src/linux-headers-$(KVERSION)/
|
||||
KERNELDIR:=$(KERNEL_DIR)
|
||||
$(error KERNEL_SRC is not defined)
|
||||
else
|
||||
KERNELDIR:=$(KERNEL_SRC)
|
||||
endif
|
||||
|
1
platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-cpld.c
Executable file → Normal file
1
platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-cpld.c
Executable file → Normal file
@ -598,7 +598,6 @@ static u8 is_fan_fault(struct as4630_54pe_cpld_data *data, enum fan_id id)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t fan_show_value(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
|
@ -64,7 +64,7 @@ static struct accton_as4630_54pe_led_data *ledctl = NULL;
|
||||
#define LED_TYPE_POE_REG_MASK (0x2|0x1)
|
||||
#define LED_MODE_POE_GREEN_VALUE 0x1
|
||||
#define LED_MODE_POE_AMBER_VALUE 0x2
|
||||
#define LED_MODE_POE_OFF_VALUE 0x0
|
||||
#define LED_MODE_POE_OFF_VALUE 0x3
|
||||
|
||||
#define LED_TYPE_STK1_REG_MASK 0x20
|
||||
#define LED_MODE_STK1_GREEN_VALUE 0x0
|
||||
@ -74,20 +74,20 @@ static struct accton_as4630_54pe_led_data *ledctl = NULL;
|
||||
#define LED_MODE_STK2_GREEN_VALUE 0x0
|
||||
#define LED_MODE_STK2_OFF_VALUE 0x10
|
||||
|
||||
#define LED_TYPE_FAN_REG_MASK (0x20|0x10)
|
||||
#define LED_MODE_FAN_AMBER_VALUE 0x20
|
||||
#define LED_MODE_FAN_GREEN_VALUE 0x10
|
||||
#define LED_MODE_FAN_OFF_VALUE (0x0)
|
||||
#define LED_TYPE_FAN_REG_MASK (0x8|0x4)
|
||||
#define LED_MODE_FAN_AMBER_VALUE 0x8
|
||||
#define LED_MODE_FAN_GREEN_VALUE 0x4
|
||||
#define LED_MODE_FAN_OFF_VALUE (0xC)
|
||||
|
||||
#define LED_TYPE_PSU2_REG_MASK (0x8|0x4)
|
||||
#define LED_MODE_PSU2_AMBER_VALUE 0x8
|
||||
#define LED_MODE_PSU2_GREEN_VALUE 0x4
|
||||
#define LED_MODE_PSU2_OFF_VALUE (0x0)
|
||||
#define LED_TYPE_PSU2_REG_MASK (0x80|0x40)
|
||||
#define LED_MODE_PSU2_AMBER_VALUE 0x80
|
||||
#define LED_MODE_PSU2_GREEN_VALUE 0x40
|
||||
#define LED_MODE_PSU2_OFF_VALUE (0xC0)
|
||||
|
||||
#define LED_TYPE_PSU1_REG_MASK (0x2|0x1)
|
||||
#define LED_MODE_PSU1_AMBER_VALUE 0x2
|
||||
#define LED_MODE_PSU1_GREEN_VALUE 0x1
|
||||
#define LED_MODE_PSU1_OFF_VALUE (0x0)
|
||||
#define LED_MODE_PSU1_OFF_VALUE (0x3)
|
||||
|
||||
enum led_type {
|
||||
LED_TYPE_DIAG,
|
||||
@ -106,8 +106,8 @@ struct led_reg {
|
||||
};
|
||||
|
||||
static const struct led_reg led_reg_map[] = {
|
||||
{(1<<LED_TYPE_DIAG)| (1<<LED_TYPE_PRI) | (1<<LED_TYPE_PSU2) , 0x30},
|
||||
{(1<<LED_TYPE_PSU1) | (1<<LED_TYPE_FAN) | (1<<LED_TYPE_POE) |(1<<LED_TYPE_STK1) | (1<<LED_TYPE_STK2) , 0x31},
|
||||
{(1<<LED_TYPE_DIAG)| (1<<LED_TYPE_PRI) | (1<<LED_TYPE_PSU1) , 0x30},
|
||||
{(1<<LED_TYPE_PSU2) | (1<<LED_TYPE_FAN) | (1<<LED_TYPE_POE) |(1<<LED_TYPE_STK1) | (1<<LED_TYPE_STK2) , 0x31},
|
||||
};
|
||||
|
||||
|
||||
@ -371,7 +371,7 @@ static void accton_as4630_54pe_led_fan_set(struct led_classdev *led_cdev,
|
||||
static enum led_brightness accton_as4630_54pe_led_fan_get(struct led_classdev *cdev)
|
||||
{
|
||||
accton_as4630_54pe_led_update();
|
||||
return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[0]);
|
||||
return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[1]);
|
||||
}
|
||||
|
||||
static void accton_as4630_54pe_led_psu1_set(struct led_classdev *led_cdev,
|
||||
@ -395,7 +395,7 @@ static void accton_as4630_54pe_led_psu2_set(struct led_classdev *led_cdev,
|
||||
static enum led_brightness accton_as4630_54pe_led_psu2_get(struct led_classdev *cdev)
|
||||
{
|
||||
accton_as4630_54pe_led_update();
|
||||
return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[0]);
|
||||
return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[1]);
|
||||
}
|
||||
|
||||
static struct led_classdev accton_as4630_54pe_leds[] = {
|
||||
@ -405,7 +405,7 @@ static struct led_classdev accton_as4630_54pe_leds[] = {
|
||||
.brightness_set = accton_as4630_54pe_led_diag_set,
|
||||
.brightness_get = accton_as4630_54pe_led_diag_get,
|
||||
.flags = LED_CORE_SUSPENDRESUME,
|
||||
.max_brightness = LED_MODE_GREEN,
|
||||
.max_brightness = LED_MODE_GREEN_BLINK,
|
||||
},
|
||||
[LED_TYPE_PRI] = {
|
||||
.name = "pri",
|
||||
|
0
platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-psu.c
Executable file → Normal file
0
platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-psu.c
Executable file → Normal file
@ -1,16 +0,0 @@
|
||||
[Unit]
|
||||
Description=Accton AS4630-54PE Platform Monitoring service
|
||||
Before=pmon.service
|
||||
After=pddf-platform-init.service
|
||||
DefaultDependencies=no
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/accton_as4630_54pe_pddf_monitor.py
|
||||
KillSignal=SIGKILL
|
||||
SuccessExitStatus=SIGKILL
|
||||
|
||||
# Resource Limitations
|
||||
LimitCORE=infinity
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Accton AS4630-54PE Platform handle management interface service
|
||||
After=sysinit.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/usr/local/bin/handle_mgmt_interface.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -1 +0,0 @@
|
||||
../../../../pddf/i2c/service/pddf-platform-init.service
|
@ -1,14 +1,23 @@
|
||||
from setuptools import setup
|
||||
|
||||
DEVICE_NAME = 'accton'
|
||||
HW_SKU = 'x86_64-accton_as4630_54pe-r0'
|
||||
|
||||
setup(
|
||||
name='sonic-platform',
|
||||
version='1.0',
|
||||
description='SONiC platform API implementation on Accton Platforms using PDDF',
|
||||
description='SONiC platform API implementation on Accton Platforms',
|
||||
license='Apache 2.0',
|
||||
author='SONiC Team',
|
||||
author_email='linuxnetdev@microsoft.com',
|
||||
url='https://github.com/Azure/sonic-buildimage',
|
||||
packages=['sonic_platform'],
|
||||
maintainer='Jostar Yang',
|
||||
maintainer_email='jostar_yang@edge-core.com',
|
||||
packages=[
|
||||
'sonic_platform',
|
||||
],
|
||||
package_dir={
|
||||
'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)},
|
||||
classifiers=[
|
||||
'Development Status :: 3 - Alpha',
|
||||
'Environment :: Plugins',
|
||||
|
@ -30,6 +30,7 @@ import getopt
|
||||
import sys
|
||||
import logging
|
||||
import time
|
||||
import os
|
||||
|
||||
PROJECT_NAME = 'as4630_54pe'
|
||||
version = '0.0.1'
|
||||
@ -88,8 +89,8 @@ logging.basicConfig(level=logging.INFO)
|
||||
|
||||
|
||||
if DEBUG == True:
|
||||
print((sys.argv[0]))
|
||||
print(('ARGV :', sys.argv[1:]))
|
||||
print(sys.argv[0])
|
||||
print('ARGV :', sys.argv[1:])
|
||||
|
||||
|
||||
def main():
|
||||
@ -107,7 +108,7 @@ def main():
|
||||
if DEBUG == True:
|
||||
print(options)
|
||||
print(args)
|
||||
print((len(sys.argv)))
|
||||
print(len(sys.argv))
|
||||
|
||||
for opt, arg in options:
|
||||
if opt in ('-h', '--help'):
|
||||
@ -124,6 +125,10 @@ def main():
|
||||
do_install()
|
||||
elif arg == 'clean':
|
||||
do_uninstall()
|
||||
elif arg == 'api':
|
||||
do_sonic_platform_install()
|
||||
elif arg == 'api_clean':
|
||||
do_sonic_platform_clean()
|
||||
else:
|
||||
show_help()
|
||||
|
||||
@ -131,12 +136,12 @@ def main():
|
||||
return 0
|
||||
|
||||
def show_help():
|
||||
print(( __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]}))
|
||||
print( __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]})
|
||||
sys.exit(0)
|
||||
|
||||
def my_log(txt):
|
||||
if DEBUG == True:
|
||||
print(("[ACCTON DBG]: ",txt))
|
||||
print("[ACCTON DBG]: ",txt)
|
||||
return
|
||||
|
||||
def log_os_system(cmd, show):
|
||||
@ -150,7 +155,7 @@ def log_os_system(cmd, show):
|
||||
if status:
|
||||
logging.info('Failed :'+cmd)
|
||||
if show:
|
||||
print(('Failed :'+cmd))
|
||||
print('Failed :'+cmd)
|
||||
return status, output
|
||||
|
||||
def driver_inserted():
|
||||
@ -168,7 +173,7 @@ kos = [
|
||||
'modprobe i2c_dev',
|
||||
'modprobe i2c_i801',
|
||||
'modprobe i2c_ismt',
|
||||
'modprobe i2c_mux_pca954x',
|
||||
'modprobe i2c_mux_pca954x force_deselect_on_exit=1',
|
||||
'modprobe ym2651y',
|
||||
'modprobe x86_64_accton_as4630_54pe_cpld',
|
||||
'modprobe x86_64_accton_as4630_54pe_leds',
|
||||
@ -285,6 +290,44 @@ def system_ready():
|
||||
return False
|
||||
return True
|
||||
|
||||
PLATFORM_ROOT_PATH = '/usr/share/sonic/device'
|
||||
PLATFORM_API2_WHL_FILE_PY3 ='sonic_platform-1.0-py3-none-any.whl'
|
||||
def do_sonic_platform_install():
|
||||
device_path = "{}{}{}{}".format(PLATFORM_ROOT_PATH, '/x86_64-accton_', PROJECT_NAME, '-r0')
|
||||
SONIC_PLATFORM_BSP_WHL_PKG_PY3 = "/".join([device_path, PLATFORM_API2_WHL_FILE_PY3])
|
||||
|
||||
#Check API2.0 on py whl file
|
||||
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0)
|
||||
if status:
|
||||
if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3):
|
||||
status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG_PY3, 1)
|
||||
if status:
|
||||
print ("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
return status
|
||||
else:
|
||||
print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
else:
|
||||
print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
else:
|
||||
print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
|
||||
return
|
||||
|
||||
def do_sonic_platform_clean():
|
||||
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0)
|
||||
if status:
|
||||
print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY2))
|
||||
|
||||
else:
|
||||
status, output = log_os_system("pip3 uninstall sonic-platform -y", 0)
|
||||
if status:
|
||||
print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
return status
|
||||
else:
|
||||
print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
|
||||
return
|
||||
|
||||
def do_install():
|
||||
if driver_inserted() == False:
|
||||
status = driver_install()
|
||||
@ -292,25 +335,28 @@ def do_install():
|
||||
if FORCE == 0:
|
||||
return status
|
||||
else:
|
||||
print((PROJECT_NAME.upper()+" drivers detected...."))
|
||||
print(PROJECT_NAME.upper()+" drivers detected....")
|
||||
if not device_exist():
|
||||
status = device_install()
|
||||
if status:
|
||||
if FORCE == 0:
|
||||
return status
|
||||
else:
|
||||
print((PROJECT_NAME.upper()+" devices detected...."))
|
||||
print(PROJECT_NAME.upper()+" devices detected....")
|
||||
|
||||
for i in range(len(cpld_set)):
|
||||
status, output = log_os_system(cpld_set[i], 1)
|
||||
if status:
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
do_sonic_platform_install()
|
||||
|
||||
return
|
||||
|
||||
def do_uninstall():
|
||||
if not device_exist():
|
||||
print((PROJECT_NAME.upper()+" has no device installed...."))
|
||||
print(PROJECT_NAME.upper()+" has no device installed....")
|
||||
else:
|
||||
print("Removing device....")
|
||||
status = device_uninstall()
|
||||
@ -319,7 +365,7 @@ def do_uninstall():
|
||||
return status
|
||||
|
||||
if driver_inserted()== False :
|
||||
print((PROJECT_NAME.upper()+" has no driver installed...."))
|
||||
print(PROJECT_NAME.upper()+" has no driver installed....")
|
||||
else:
|
||||
print("Removing installed driver....")
|
||||
status = driver_uninstall()
|
||||
@ -327,6 +373,8 @@ def do_uninstall():
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
do_sonic_platform_clean()
|
||||
|
||||
return
|
||||
|
||||
def device_exist():
|
||||
|
@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
#Due to the hardware design, as4630-54pe use "eth2" instead of "eth0" as management interface.
|
||||
#Rename netdev "eth0" and "eth2" to swap original "eth2" to "eth0".
|
||||
|
||||
ifconfig eth0 down
|
||||
ip link set eth0 name eth3
|
||||
ip link set eth2 name eth0
|
||||
ifconfig eth0 up
|
@ -104,7 +104,7 @@ class FanUtil(object):
|
||||
return None
|
||||
|
||||
try:
|
||||
val_file.close()
|
||||
val_file.close()
|
||||
except:
|
||||
logging.debug('GET. unable to close file. device_path:%s', device_path)
|
||||
return None
|
||||
@ -135,7 +135,7 @@ class FanUtil(object):
|
||||
val_file.write(content)
|
||||
|
||||
try:
|
||||
val_file.close()
|
||||
val_file.close()
|
||||
except:
|
||||
logging.debug('GET. unable to close file. device_path:%s', device_path)
|
||||
return None
|
||||
@ -224,14 +224,3 @@ class FanUtil(object):
|
||||
|
||||
return True
|
||||
|
||||
#def main():
|
||||
# fan = FanUtil()
|
||||
#
|
||||
# print 'get_size_node_map : %d' % fan.get_size_node_map()
|
||||
# print 'get_size_path_map : %d' % fan.get_size_path_map()
|
||||
# for x in range(fan.get_idx_fan_start(), fan.get_num_fans()+1):
|
||||
# for y in range(fan.get_idx_node_start(), fan.get_num_nodes()+1):
|
||||
# print fan.get_fan_to_device_path(x, y)
|
||||
#
|
||||
#if __name__ == '__main__':
|
||||
# main()
|
||||
|
@ -22,7 +22,6 @@
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
try:
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import glob
|
||||
@ -34,7 +33,7 @@ except ImportError as e:
|
||||
class ThermalUtil(object):
|
||||
"""Platform-specific ThermalUtil class"""
|
||||
THERMAL_NUM_MAX = 4
|
||||
THERMAL_NUM_1_IDX = 1 # 1_ON_CPU_BROAD. LM75
|
||||
THERMAL_NUM_1_IDX = 1 # 1_ON_CPU_BROAD. LM75
|
||||
THERMAL_NUM_2_IDX = 2 # 2_ON_MAIN_BROAD. LM75
|
||||
THERMAL_NUM_3_IDX = 3 # 3_ON_MAIN_BROAD. LM75
|
||||
THERMAL_NUM_4_IDX = 4 # 4_ON_MAIN_BROAD. LM75
|
||||
@ -42,88 +41,52 @@ class ThermalUtil(object):
|
||||
""" Dictionary where
|
||||
key1 = thermal id index (integer) starting from 1
|
||||
value = path to fan device file (string) """
|
||||
#_thermal_to_device_path_mapping = {}
|
||||
|
||||
_thermal_to_device_node_mapping = {
|
||||
THERMAL_NUM_1_IDX: ['18', '4b'],
|
||||
THERMAL_NUM_2_IDX: ['19', '4c'],
|
||||
THERMAL_NUM_3_IDX: ['20', '49'],
|
||||
THERMAL_NUM_4_IDX: ['21', '4a'],
|
||||
}
|
||||
|
||||
thermal_sysfspath ={
|
||||
THERMAL_NUM_1_IDX: ["/sys/bus/i2c/devices/18-004b/hwmon/hwmon3/temp1_input"],
|
||||
THERMAL_NUM_2_IDX: ["/sys/bus/i2c/devices/19-004c/hwmon/hwmon4/temp1_input"],
|
||||
THERMAL_NUM_3_IDX: ["/sys/bus/i2c/devices/20-0049/hwmon/hwmon5/temp1_input"],
|
||||
THERMAL_NUM_4_IDX: ["/sys/bus/i2c/devices/21-004a/hwmon/hwmon6/temp1_input"],
|
||||
THERMAL_NUM_1_IDX: ["/sys/bus/i2c/devices/18-004b/hwmon/hwmon*/temp1_input"],
|
||||
THERMAL_NUM_2_IDX: ["/sys/bus/i2c/devices/19-004c/hwmon/hwmon*/temp1_input"],
|
||||
THERMAL_NUM_3_IDX: ["/sys/bus/i2c/devices/20-0049/hwmon/hwmon*/temp1_input"],
|
||||
THERMAL_NUM_4_IDX: ["/sys/bus/i2c/devices/21-004a/hwmon/hwmon*/temp1_input"],
|
||||
}
|
||||
|
||||
#def __init__(self):
|
||||
def _get_thermal_val(self, thermal_num):
|
||||
def get_thermal_val(self, thermal_num):
|
||||
if thermal_num < self.THERMAL_NUM_1_IDX or thermal_num > self.THERMAL_NUM_MAX:
|
||||
logging.debug('GET. Parameter error. thermal_num, %d', thermal_num)
|
||||
return None
|
||||
|
||||
device_path = self.get_thermal_to_device_path(thermal_num)
|
||||
if(os.path.isfile(device_path)):
|
||||
for filename in glob.glob(device_path):
|
||||
try:
|
||||
val_file = open(filename, 'r')
|
||||
except IOError as e:
|
||||
logging.error('GET. unable to open file: %s', str(e))
|
||||
return None
|
||||
device_path = self.get_thermal_path(thermal_num)
|
||||
for filename in glob.glob(device_path):
|
||||
try:
|
||||
val_file = open(filename, 'r')
|
||||
except IOError as e:
|
||||
logging.error('GET. unable to open file: %s', str(e))
|
||||
return None
|
||||
content = val_file.readline().rstrip()
|
||||
if content == '':
|
||||
logging.debug('GET. content is NULL. device_path:%s', device_path)
|
||||
return None
|
||||
try:
|
||||
val_file.close()
|
||||
val_file.close()
|
||||
except:
|
||||
logging.debug('GET. unable to close file. device_path:%s', device_path)
|
||||
return None
|
||||
return int(content)
|
||||
|
||||
else:
|
||||
print("No such device_path=%s"%device_path)
|
||||
return 0
|
||||
|
||||
return 0
|
||||
|
||||
def get_num_thermals(self):
|
||||
return self.THERMAL_NUM_MAX
|
||||
|
||||
def get_idx_thermal_start(self):
|
||||
return self.THERMAL_NUM_1_IDX
|
||||
|
||||
def get_size_node_map(self):
|
||||
return len(self._thermal_to_device_node_mapping)
|
||||
|
||||
def get_size_path_map(self):
|
||||
return len(self.thermal_sysfspath)
|
||||
|
||||
def get_thermal_to_device_path(self, thermal_num):
|
||||
|
||||
def get_thermal_path(self, thermal_num):
|
||||
return self.thermal_sysfspath[thermal_num][0]
|
||||
|
||||
def get_thermal_1_val(self):
|
||||
return self._get_thermal_val(self.THERMAL_NUM_1_IDX)
|
||||
|
||||
def get_thermal_2_val(self):
|
||||
return self._get_thermal_val(self.THERMAL_NUM_2_IDX)
|
||||
|
||||
def get_thermal_3_val(self):
|
||||
return self._get_thermal_val(self.THERMAL_NUM_3_IDX)
|
||||
|
||||
def get_thermal_temp(self):
|
||||
return (self._get_thermal_val(self.THERMAL_NUM_1_IDX) + self._get_thermal_val(self.THERMAL_NUM_2_IDX) +self._get_thermal_val(self.THERMAL_NUM_3_IDX))
|
||||
|
||||
def main():
|
||||
thermal = ThermalUtil()
|
||||
print("termal1=%d" %thermal._get_thermal_val(1))
|
||||
print("termal2=%d" %thermal._get_thermal_val(2))
|
||||
print("termal3=%d" %thermal._get_thermal_val(3))
|
||||
print("termal4=%d" %thermal._get_thermal_val(4))
|
||||
#
|
||||
# print 'get_size_node_map : %d' % thermal.get_size_node_map()
|
||||
# print 'get_size_path_map : %d' % thermal.get_size_path_map()
|
||||
# for x in range(thermal.get_idx_thermal_start(), thermal.get_num_thermals()+1):
|
||||
# print thermal.get_thermal_to_device_path(x)
|
||||
#
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logging.debug('thermal1=%d', thermal.get_thermal_val(1))
|
||||
logging.debug('thermal2=%d', thermal.get_thermal_val(2))
|
||||
logging.debug('thermal3=%d', thermal.get_thermal_val(3))
|
||||
logging.debug('thermal4=%d', thermal.get_thermal_val(4))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
main()
|
||||
|
@ -91,11 +91,11 @@ class accton_as5835_54x_monitor(object):
|
||||
thermal = ThermalUtil()
|
||||
fan = FanUtil()
|
||||
|
||||
temp2 = thermal.get_thermal_2_val()
|
||||
temp2 = thermal.get_thermal_val(2)
|
||||
if temp2 is None:
|
||||
return False
|
||||
|
||||
temp3 = thermal.get_thermal_3_val()
|
||||
temp3 = thermal.get_thermal_val(3)
|
||||
if temp3 is None:
|
||||
return False
|
||||
|
||||
|
@ -48,8 +48,8 @@ FORCE = 0
|
||||
|
||||
|
||||
if DEBUG == True:
|
||||
print((sys.argv[0]))
|
||||
print(("ARGV :", sys.argv[1:]))
|
||||
print(sys.argv[0])
|
||||
print("ARGV :", sys.argv[1:])
|
||||
|
||||
|
||||
def main():
|
||||
@ -67,7 +67,7 @@ def main():
|
||||
if DEBUG == True:
|
||||
print(options)
|
||||
print(args)
|
||||
print((len(sys.argv)))
|
||||
print(len(sys.argv))
|
||||
|
||||
for opt, arg in options:
|
||||
if opt in ('-h', '--help'):
|
||||
@ -96,13 +96,13 @@ def main():
|
||||
return 0
|
||||
|
||||
def show_help():
|
||||
print((__doc__ % {'scriptName' : sys.argv[0].split("/")[-1]}))
|
||||
print(__doc__ % {'scriptName' : sys.argv[0].split("/")[-1]})
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def my_log(txt):
|
||||
if DEBUG == True:
|
||||
print(("[Debug]"+txt))
|
||||
print("[Debug]"+txt)
|
||||
return
|
||||
|
||||
def log_os_system(cmd, show):
|
||||
@ -113,7 +113,7 @@ def log_os_system(cmd, show):
|
||||
if status:
|
||||
logging.info('Failed :'+cmd)
|
||||
if show:
|
||||
print(('Failed :'+cmd))
|
||||
print('Failed :'+cmd)
|
||||
return status, output
|
||||
|
||||
def driver_check():
|
||||
@ -295,6 +295,10 @@ def device_install():
|
||||
|
||||
for i in range(49, 55): #Set qsfp port to normal state
|
||||
log_os_system("echo 0 > /sys/bus/i2c/devices/3-0062/module_reset_" + str(i), 1)
|
||||
for i in range(1, 39): #Set disable tx_disable to sfp port
|
||||
log_os_system("echo 0 > /sys/bus/i2c/devices/3-0061/module_tx_disable_" + str(i), 1)
|
||||
for i in range(39, 49): #Set disable tx_disable to sfp port
|
||||
log_os_system("echo 0 > /sys/bus/i2c/devices/3-0062/module_tx_disable_" + str(i), 1)
|
||||
|
||||
for i in range(0,len(sfp_map)):
|
||||
if i < qsfp_start:
|
||||
@ -358,31 +362,29 @@ def do_sonic_platform_install():
|
||||
if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3):
|
||||
status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG_PY3, 1)
|
||||
if status:
|
||||
print(("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3) ))
|
||||
print("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3) )
|
||||
return status
|
||||
else:
|
||||
print(("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3) ))
|
||||
print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3) )
|
||||
else:
|
||||
print(('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3)))
|
||||
print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
else:
|
||||
print(('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3)))
|
||||
print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
|
||||
return
|
||||
|
||||
def do_sonic_platform_clean():
|
||||
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0)
|
||||
if status:
|
||||
print(('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3)))
|
||||
print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
|
||||
else:
|
||||
status, output = log_os_system("pip3 uninstall sonic-platform -y", 0)
|
||||
if status:
|
||||
print(('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3)))
|
||||
print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
return status
|
||||
else:
|
||||
print(('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3)))
|
||||
|
||||
return
|
||||
print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
|
||||
def do_install():
|
||||
print("Checking system....")
|
||||
@ -393,7 +395,7 @@ def do_install():
|
||||
if FORCE == 0:
|
||||
return status
|
||||
else:
|
||||
print((PROJECT_NAME.upper()+" drivers detected...."))
|
||||
print(PROJECT_NAME.upper()+" drivers detected....")
|
||||
if not device_exist():
|
||||
print("No device, installing....")
|
||||
status = device_install()
|
||||
@ -401,7 +403,7 @@ def do_install():
|
||||
if FORCE == 0:
|
||||
return status
|
||||
else:
|
||||
print((PROJECT_NAME.upper()+" devices detected...."))
|
||||
print(PROJECT_NAME.upper()+" devices detected....")
|
||||
|
||||
do_sonic_platform_install()
|
||||
|
||||
@ -410,7 +412,7 @@ def do_install():
|
||||
def do_uninstall():
|
||||
print("Checking system....")
|
||||
if not device_exist():
|
||||
print((PROJECT_NAME.upper() +" has no device installed...."))
|
||||
print(PROJECT_NAME.upper() +" has no device installed....")
|
||||
else:
|
||||
print("Removing device....")
|
||||
status = device_uninstall()
|
||||
@ -419,7 +421,7 @@ def do_uninstall():
|
||||
return status
|
||||
|
||||
if driver_check()== False :
|
||||
print((PROJECT_NAME.upper() +" has no driver installed...."))
|
||||
print(PROJECT_NAME.upper() +" has no driver installed....")
|
||||
else:
|
||||
print("Removing installed driver....")
|
||||
status = driver_uninstall()
|
||||
|
@ -112,7 +112,7 @@ class FanUtil(object):
|
||||
return None
|
||||
|
||||
try:
|
||||
val_file.close()
|
||||
val_file.close()
|
||||
except:
|
||||
logging.debug('GET. unable to close file. device_path:%s', device_path)
|
||||
return None
|
||||
@ -143,7 +143,7 @@ class FanUtil(object):
|
||||
val_file.write(content)
|
||||
|
||||
try:
|
||||
val_file.close()
|
||||
val_file.close()
|
||||
except:
|
||||
logging.debug('GET. unable to close file. device_path:%s', device_path)
|
||||
return None
|
||||
|
@ -146,7 +146,7 @@ static int accton_getLedReg(enum led_type type, u8 *reg)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(led_reg_map); i++) {
|
||||
if(led_reg_map[i].types ==type) {
|
||||
if (led_reg_map[i].types ==type) {
|
||||
*reg = led_reg_map[i].reg_addr;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,16 +0,0 @@
|
||||
[Unit]
|
||||
Description=Accton AS7326-56X Platform Monitoring service
|
||||
Before=pmon.service
|
||||
After=pddf-platform-init.service
|
||||
DefaultDependencies=no
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/accton_as7326_pddf_monitor.py
|
||||
KillSignal=SIGKILL
|
||||
SuccessExitStatus=SIGKILL
|
||||
|
||||
# Resource Limitations
|
||||
LimitCORE=infinity
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -1,6 +1,6 @@
|
||||
[Unit]
|
||||
Description=Accton AS7326-56X Platform MAC handle service
|
||||
Before=opennsl-modules.service pddf-platform-init.service
|
||||
Before=opennsl-modules.service
|
||||
After=local-fs.target
|
||||
|
||||
[Service]
|
||||
|
@ -1 +0,0 @@
|
||||
../../../../pddf/i2c/service/pddf-platform-init.service
|
@ -1,5 +1,8 @@
|
||||
from setuptools import setup
|
||||
|
||||
DEVICE_NAME = 'accton'
|
||||
HW_SKU = 'x86_64-accton_as7326_56x-r0'
|
||||
|
||||
setup(
|
||||
name='sonic-platform',
|
||||
version='1.0',
|
||||
@ -8,7 +11,11 @@ setup(
|
||||
author='SONiC Team',
|
||||
author_email='linuxnetdev@microsoft.com',
|
||||
url='https://github.com/Azure/sonic-buildimage',
|
||||
packages=['sonic_platform'],
|
||||
packages=[
|
||||
'sonic_platform'
|
||||
],
|
||||
package_dir={
|
||||
'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)},
|
||||
classifiers=[
|
||||
'Development Status :: 3 - Alpha',
|
||||
'Environment :: Plugins',
|
||||
|
@ -166,14 +166,14 @@ class device_monitor(object):
|
||||
|
||||
thermal = ThermalUtil()
|
||||
fan = FanUtil()
|
||||
fan_dir=fan.get_fan_dir(1)
|
||||
if fan_dir > 1:
|
||||
fan_dri=1 #something wrong, set fan_dir to default val
|
||||
if fan_dir < 0:
|
||||
fan_dri=1 #something wrong, set fan_dir to default val
|
||||
#fan_dir=fan.get_fan_dir(1)
|
||||
#if fan_dir > 1:
|
||||
# fan_dri=1 #something wrong, set fan_dir to default val
|
||||
#if fan_dir < 0:
|
||||
# fan_dri=1 #something wrong, set fan_dir to default val
|
||||
ori_pwm=fan.get_fan_duty_cycle()
|
||||
new_pwm=0
|
||||
logging.debug('fan_dir=%d, ori_pwm=%d', fan_dir, ori_pwm)
|
||||
#logging.debug('fan_dir=%d, ori_pwm=%d', fan_dir, ori_pwm)
|
||||
logging.debug('test_temp=%d', test_temp)
|
||||
if test_temp==0:
|
||||
temp1 = thermal._get_thermal_val(1)
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (C) 2016 Accton Networks, Inc.
|
||||
#
|
||||
@ -14,15 +14,6 @@
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
#
|
||||
# Description:
|
||||
# Due to adoption of optoe drivers, sideband signals of SFPs are moved
|
||||
# into cpld drivers. Add a new dict, cpld_of_module, for mapping this
|
||||
# attributes to corresponding cpld nodes.
|
||||
#
|
||||
|
||||
|
||||
|
||||
"""
|
||||
Usage: %(scriptName)s [options] command object
|
||||
@ -34,18 +25,14 @@ options:
|
||||
command:
|
||||
install : install drivers and generate related sysfs nodes
|
||||
clean : uninstall drivers and remove related sysfs nodes
|
||||
show : show all systen status
|
||||
sff : dump SFP eeprom
|
||||
set : change board setting with fan|led|sfp
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import getopt
|
||||
import sys
|
||||
import logging
|
||||
import re
|
||||
import time
|
||||
|
||||
import os
|
||||
|
||||
|
||||
|
||||
@ -96,41 +83,21 @@ def main():
|
||||
for arg in args:
|
||||
if arg == 'install':
|
||||
do_install()
|
||||
elif arg == 'api':
|
||||
do_sonic_platform_install()
|
||||
elif arg == 'api_clean':
|
||||
do_sonic_platform_clean()
|
||||
elif arg == 'clean':
|
||||
do_uninstall()
|
||||
elif arg == 'show':
|
||||
device_traversal()
|
||||
elif arg == 'sff':
|
||||
if len(args)!=2:
|
||||
show_eeprom_help()
|
||||
elif int(args[1]) ==0 or int(args[1]) > DEVICE_NO['sfp']:
|
||||
show_eeprom_help()
|
||||
else:
|
||||
show_eeprom(args[1])
|
||||
return
|
||||
elif arg == 'set':
|
||||
if len(args)<3:
|
||||
show_set_help()
|
||||
else:
|
||||
set_device(args[1:])
|
||||
return
|
||||
else:
|
||||
show_help()
|
||||
|
||||
|
||||
return 0
|
||||
|
||||
def show_help():
|
||||
print(__doc__ % {'scriptName' : sys.argv[0].split("/")[-1]})
|
||||
sys.exit(0)
|
||||
|
||||
def show_set_help():
|
||||
cmd = sys.argv[0].split("/")[-1]+ " " + args[0]
|
||||
print(cmd +" [led|sfp|fan]")
|
||||
print(" use \""+ cmd + " led 0-4 \" to set led color")
|
||||
print(" use \""+ cmd + " fan 0-100\" to set fan duty percetage")
|
||||
print(" use \""+ cmd + " sfp 1-56 {0|1}\" to set sfp# tx_disable")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def dis_i2c_ir3570a(addr):
|
||||
cmd = "i2cset -y 0 0x%x 0xE5 0x01" % addr
|
||||
@ -156,11 +123,6 @@ def ir3570_check():
|
||||
return ret
|
||||
|
||||
|
||||
def show_eeprom_help():
|
||||
cmd = sys.argv[0].split("/")[-1]+ " " + args[0]
|
||||
print(" use \""+ cmd + " 1-56 \" to dump sfp# eeprom")
|
||||
sys.exit(0)
|
||||
|
||||
def my_log(txt):
|
||||
if DEBUG == True:
|
||||
print("[ROY]"+txt)
|
||||
@ -174,7 +136,7 @@ def log_os_system(cmd, show):
|
||||
if status:
|
||||
logging.info('Failed :'+cmd)
|
||||
if show:
|
||||
print(('Failed :'+cmd))
|
||||
print('Failed :'+cmd)
|
||||
return status, output
|
||||
|
||||
def driver_check():
|
||||
@ -189,7 +151,7 @@ def driver_check():
|
||||
|
||||
kos = [
|
||||
'modprobe i2c_dev',
|
||||
'modprobe i2c_mux_pca954x force_deselect_on_exit=1',
|
||||
'modprobe i2c_mux_pca954x',
|
||||
'modprobe accton_i2c_cpld' ,
|
||||
'modprobe ym2651y' ,
|
||||
'modprobe accton_as7326_56x_fan' ,
|
||||
@ -207,6 +169,8 @@ def driver_install():
|
||||
if status:
|
||||
if FORCE == 0:
|
||||
return status
|
||||
print("Done driver_install")
|
||||
|
||||
return 0
|
||||
|
||||
def driver_uninstall():
|
||||
@ -224,12 +188,8 @@ def driver_uninstall():
|
||||
return status
|
||||
return 0
|
||||
|
||||
led_prefix ='/sys/class/leds/accton_'+PROJECT_NAME+'_led::'
|
||||
hwmon_types = {'led': ['diag','fan','loc','psu1','psu2']}
|
||||
hwmon_nodes = {'led': ['brightness'] }
|
||||
hwmon_prefix ={'led': led_prefix}
|
||||
|
||||
i2c_prefix = '/sys/bus/i2c/devices/'
|
||||
'''
|
||||
i2c_bus = {'fan': ['11-0066'] ,
|
||||
'thermal': ['15-0048','15-0049', '15-004a', '15-004b'] ,
|
||||
'psu': ['17-0051','13-0053'],
|
||||
@ -238,7 +198,7 @@ i2c_nodes = {'fan': ['present', 'front_speed_rpm', 'rear_speed_rpm'] ,
|
||||
'thermal': ['hwmon/hwmon*/temp1_input'] ,
|
||||
'psu': ['psu_present ', 'psu_power_good'] ,
|
||||
'sfp': ['module_present_', 'module_tx_disable_']}
|
||||
|
||||
'''
|
||||
sfp_map = [
|
||||
42,41,44,43,47,45,46,50,
|
||||
48,49,52,51,53,56,55,54,
|
||||
@ -268,7 +228,6 @@ mknod =[
|
||||
'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-36/new_device',
|
||||
'echo pca9548 0x75 > /sys/bus/i2c/devices/i2c-37/new_device',
|
||||
'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-38/new_device',
|
||||
'echo 24c04 0x56 > /sys/bus/i2c/devices/i2c-0/new_device',
|
||||
|
||||
'echo as7326_56x_fan 0x66 > /sys/bus/i2c/devices/i2c-11/new_device ',
|
||||
'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-15/new_device',
|
||||
@ -286,12 +245,22 @@ mknod =[
|
||||
mknod2 =[
|
||||
]
|
||||
|
||||
#EERPOM
|
||||
eeprom_mknod =[
|
||||
'echo 24c04 0x56 > /sys/bus/i2c/devices/i2c-0/new_device',
|
||||
'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-0/new_device'
|
||||
]
|
||||
|
||||
|
||||
def i2c_order_check():
|
||||
# This project has only 1 i2c bus.
|
||||
return 0
|
||||
|
||||
def eeprom_check():
|
||||
cmd = "i2cget -y -f 0 0x56"
|
||||
status, output = subprocess.getstatusoutput(cmd)
|
||||
return status
|
||||
|
||||
def device_install():
|
||||
global FORCE
|
||||
|
||||
@ -320,6 +289,30 @@ def device_install():
|
||||
print(output)
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
# set all pca954x idle_disconnect
|
||||
cmd = 'echo -2 | tee /sys/bus/i2c/drivers/pca954x/*-00*/idle_state'
|
||||
status, output = log_os_system(cmd, 1)
|
||||
if status:
|
||||
print(output)
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
# initiate IDPROM
|
||||
# Close 0x77 mux to make sure if the I2C address of IDPROM is 0x56 or 0x57
|
||||
log_os_system("i2cset -f -y 0 0x77 0 ", 1)
|
||||
ret=eeprom_check()
|
||||
if ret==0:
|
||||
log_os_system(eeprom_mknod[0], 1) #old board, 0x56 eeprom
|
||||
time.sleep(0.2)
|
||||
exists = os.path.isfile('/sys/bus/i2c/devices/0-0056/eeprom')
|
||||
if (exists is False):
|
||||
subprocess.call('echo 0x56 > /sys/bus/i2c/devices/i2c-0/delete_device', shell=True)
|
||||
log_os_system(eeprom_mknod[1], 1)
|
||||
else:
|
||||
log_os_system(eeprom_mknod[1], 1) #new board, 0x57 eeprom
|
||||
|
||||
|
||||
for i in range(0,len(sfp_map)):
|
||||
if i < qsfp_start or i >= qsfp_end:
|
||||
status, output =log_os_system("echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1)
|
||||
@ -329,6 +322,7 @@ def device_install():
|
||||
print(output)
|
||||
if FORCE == 0:
|
||||
return status
|
||||
print("Done device_install")
|
||||
return
|
||||
|
||||
def device_uninstall():
|
||||
@ -364,6 +358,23 @@ def device_uninstall():
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
#Deal with for del 0x56 or 0x57 sysfs device
|
||||
exists = os.path.isfile('/sys/bus/i2c/devices/0-0056/eeprom')
|
||||
|
||||
if (exists is True):
|
||||
target = eeprom_mknod[0] #0x56
|
||||
else:
|
||||
target = eeprom_mknod[1] #0x57
|
||||
|
||||
temp = target.split()
|
||||
del temp[1]
|
||||
temp[-1] = temp[-1].replace('new_device', 'delete_device')
|
||||
status, output = log_os_system(" ".join(temp), 1)
|
||||
if status:
|
||||
print(output)
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
return
|
||||
|
||||
def system_ready():
|
||||
@ -372,6 +383,44 @@ def system_ready():
|
||||
if not device_exist():
|
||||
return False
|
||||
return True
|
||||
PLATFORM_ROOT_PATH = '/usr/share/sonic/device'
|
||||
PLATFORM_API2_WHL_FILE_PY3 ='sonic_platform-1.0-py3-none-any.whl'
|
||||
def do_sonic_platform_install():
|
||||
device_path = "{}{}{}{}".format(PLATFORM_ROOT_PATH, '/x86_64-accton_', PROJECT_NAME, '-r0')
|
||||
SONIC_PLATFORM_BSP_WHL_PKG_PY3 = "/".join([device_path, PLATFORM_API2_WHL_FILE_PY3])
|
||||
|
||||
#Check API2.0 on py whl file
|
||||
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0)
|
||||
if status:
|
||||
if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3):
|
||||
status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG_PY3, 1)
|
||||
if status:
|
||||
print("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
return status
|
||||
else:
|
||||
print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
else:
|
||||
print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
else:
|
||||
print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
|
||||
return
|
||||
|
||||
def do_sonic_platform_clean():
|
||||
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0)
|
||||
if status:
|
||||
print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
|
||||
else:
|
||||
status, output = log_os_system("pip3 uninstall sonic-platform -y", 0)
|
||||
if status:
|
||||
print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
return status
|
||||
else:
|
||||
print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
|
||||
|
||||
return
|
||||
|
||||
def do_install():
|
||||
print("Checking system....")
|
||||
@ -394,6 +443,9 @@ def do_install():
|
||||
return status
|
||||
else:
|
||||
print(PROJECT_NAME.upper()+" devices detected....")
|
||||
|
||||
do_sonic_platform_install()
|
||||
|
||||
return
|
||||
|
||||
def do_uninstall():
|
||||
@ -416,185 +468,8 @@ def do_uninstall():
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
return
|
||||
do_sonic_platform_clean()
|
||||
|
||||
def devices_info():
|
||||
global DEVICE_NO
|
||||
global ALL_DEVICE
|
||||
global i2c_bus, hwmon_types
|
||||
for key in DEVICE_NO:
|
||||
ALL_DEVICE[key]= {}
|
||||
for i in range(0,DEVICE_NO[key]):
|
||||
ALL_DEVICE[key][key+str(i+1)] = []
|
||||
|
||||
for key in i2c_bus:
|
||||
buses = i2c_bus[key]
|
||||
nodes = i2c_nodes[key]
|
||||
for i in range(0,len(buses)):
|
||||
for j in range(0,len(nodes)):
|
||||
if 'fan' == key:
|
||||
for k in range(0,DEVICE_NO[key]):
|
||||
node = key+str(k+1)
|
||||
path = i2c_prefix+ buses[i]+"/fan"+str(k+1)+"_"+ nodes[j]
|
||||
my_log(node+": "+ path)
|
||||
ALL_DEVICE[key][node].append(path)
|
||||
elif 'sfp' == key:
|
||||
for k in range(0,DEVICE_NO[key]):
|
||||
for lk in cpld_of_module:
|
||||
if k in cpld_of_module[lk]:
|
||||
cpld_str = lk
|
||||
node = key+str(k+1)
|
||||
path = i2c_prefix+ lk + "/"+ nodes[j] + str(k+1)
|
||||
my_log(node+": "+ path)
|
||||
ALL_DEVICE[key][node].append(path)
|
||||
else:
|
||||
node = key+str(i+1)
|
||||
path = i2c_prefix+ buses[i]+"/"+ nodes[j]
|
||||
my_log(node+": "+ path)
|
||||
ALL_DEVICE[key][node].append(path)
|
||||
|
||||
for key in hwmon_types:
|
||||
itypes = hwmon_types[key]
|
||||
nodes = hwmon_nodes[key]
|
||||
for i in range(0,len(itypes)):
|
||||
for j in range(0,len(nodes)):
|
||||
node = key+"_"+itypes[i]
|
||||
path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j]
|
||||
my_log(node+": "+ path)
|
||||
ALL_DEVICE[key][ key+str(i+1)].append(path)
|
||||
|
||||
#show dict all in the order
|
||||
if DEBUG == True:
|
||||
for i in sorted(ALL_DEVICE.keys()):
|
||||
print((i+": "))
|
||||
for j in sorted(ALL_DEVICE[i].keys()):
|
||||
print((" "+j))
|
||||
for k in (ALL_DEVICE[i][j]):
|
||||
print((" "+" "+k))
|
||||
return
|
||||
|
||||
def show_eeprom(index):
|
||||
if system_ready()==False:
|
||||
print("System's not ready.")
|
||||
print("Please install first!")
|
||||
return
|
||||
|
||||
if len(ALL_DEVICE)==0:
|
||||
devices_info()
|
||||
node = ALL_DEVICE['sfp'] ['sfp'+str(index)][0]
|
||||
node = node.replace(node.split("/")[-1], 'eeprom')
|
||||
# check if got hexdump command in current environment
|
||||
ret, log = log_os_system("which hexdump", 0)
|
||||
ret, log2 = log_os_system("which busybox hexdump", 0)
|
||||
if len(log):
|
||||
hex_cmd = 'hexdump'
|
||||
elif len(log2):
|
||||
hex_cmd = ' busybox hexdump'
|
||||
else:
|
||||
log = 'Failed : no hexdump cmd!!'
|
||||
logging.info(log)
|
||||
print(log)
|
||||
return 1
|
||||
|
||||
print(node + ":")
|
||||
ret, log = log_os_system("cat "+node+"| "+hex_cmd+" -C", 1)
|
||||
if ret==0:
|
||||
print(log)
|
||||
else:
|
||||
print("**********device no found**********")
|
||||
return
|
||||
|
||||
def set_device(args):
|
||||
global DEVICE_NO
|
||||
global ALL_DEVICE
|
||||
if system_ready()==False:
|
||||
print("System's not ready.")
|
||||
print("Please install first!")
|
||||
return
|
||||
|
||||
if len(ALL_DEVICE)==0:
|
||||
devices_info()
|
||||
|
||||
if args[0]=='led':
|
||||
if int(args[1])>4:
|
||||
show_set_help()
|
||||
return
|
||||
#print ALL_DEVICE['led']
|
||||
for i in range(0,len(ALL_DEVICE['led'])):
|
||||
for k in (ALL_DEVICE['led']['led'+str(i+1)]):
|
||||
ret, log = log_os_system("echo "+args[1]+" >"+k, 1)
|
||||
if ret:
|
||||
return ret
|
||||
elif args[0]=='fan':
|
||||
if int(args[1])>100:
|
||||
show_set_help()
|
||||
return
|
||||
#print ALL_DEVICE['fan']
|
||||
#fan1~6 is all fine, all fan share same setting
|
||||
node = ALL_DEVICE['fan'] ['fan1'][0]
|
||||
node = node.replace(node.split("/")[-1], 'fan_duty_cycle_percentage')
|
||||
ret, log = log_os_system("cat "+ node, 1)
|
||||
if ret==0:
|
||||
print(("Previous fan duty: " + log.strip() +"%"))
|
||||
ret, log = log_os_system("echo "+args[1]+" >"+node, 1)
|
||||
if ret==0:
|
||||
print(("Current fan duty: " + args[1] +"%"))
|
||||
return ret
|
||||
elif args[0]=='sfp':
|
||||
if int(args[1])> DEVICE_NO[args[0]] or int(args[1])==0:
|
||||
show_set_help()
|
||||
return
|
||||
if len(args)<2:
|
||||
show_set_help()
|
||||
return
|
||||
|
||||
if int(args[2])>1:
|
||||
show_set_help()
|
||||
return
|
||||
|
||||
#print ALL_DEVICE[args[0]]
|
||||
for i in range(0,len(ALL_DEVICE[args[0]])):
|
||||
for j in ALL_DEVICE[args[0]][args[0]+str(args[1])]:
|
||||
if j.find('tx_disable')!= -1:
|
||||
ret, log = log_os_system("echo "+args[2]+" >"+ j, 1)
|
||||
if ret:
|
||||
return ret
|
||||
return
|
||||
|
||||
#get digits inside a string.
|
||||
#Ex: 31 for "sfp31"
|
||||
def get_value(input):
|
||||
digit = re.findall('\d+', input)
|
||||
return int(digit[0])
|
||||
|
||||
def device_traversal():
|
||||
if system_ready()==False:
|
||||
print("System's not ready.")
|
||||
print("Please install first!")
|
||||
return
|
||||
|
||||
if len(ALL_DEVICE)==0:
|
||||
devices_info()
|
||||
for i in sorted(ALL_DEVICE.keys()):
|
||||
print("============================================")
|
||||
print((i.upper()+": "))
|
||||
print("============================================")
|
||||
|
||||
for j in sorted(list(ALL_DEVICE[i].keys()), key=get_value):
|
||||
print(" "+j+":", end=' ')
|
||||
for k in (ALL_DEVICE[i][j]):
|
||||
ret, log = log_os_system("cat "+k, 0)
|
||||
func = k.split("/")[-1].strip()
|
||||
func = re.sub(j+'_','',func,1)
|
||||
func = re.sub(i.lower()+'_','',func,1)
|
||||
if ret==0:
|
||||
print(func+"="+log+" ", end=' ')
|
||||
else:
|
||||
print(func+"="+"X"+" ", end=' ')
|
||||
print()
|
||||
print("----------------------------------------------------------------")
|
||||
|
||||
print()
|
||||
return
|
||||
|
||||
def device_exist():
|
||||
|
@ -104,7 +104,7 @@ class FanUtil(object):
|
||||
return None
|
||||
|
||||
try:
|
||||
val_file.close()
|
||||
val_file.close()
|
||||
except:
|
||||
logging.debug('GET. unable to close file. device_path:%s', device_path)
|
||||
return None
|
||||
@ -135,7 +135,7 @@ class FanUtil(object):
|
||||
val_file.write(content)
|
||||
|
||||
try:
|
||||
val_file.close()
|
||||
val_file.close()
|
||||
except:
|
||||
logging.debug('GET. unable to close file. device_path:%s', device_path)
|
||||
return None
|
||||
|
@ -81,11 +81,11 @@ class ThermalUtil(object):
|
||||
return None
|
||||
|
||||
try:
|
||||
val_file.close()
|
||||
val_file.close()
|
||||
except:
|
||||
logging.debug('GET. unable to close file. device_path:%s', device_path)
|
||||
return None
|
||||
|
||||
|
||||
return int(content)
|
||||
|
||||
|
||||
|
@ -0,0 +1,17 @@
|
||||
[Unit]
|
||||
Description=Accton AS7816-64X Platform initialization service
|
||||
Before=pmon.service determine-reboot-cause.service
|
||||
After=sysinit.target
|
||||
DefaultDependencies=no
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/usr/local/bin/accton_as7816_64x_util.py install
|
||||
ExecStop=/usr/local/bin/accton_as7816_64x_util.py clean
|
||||
|
||||
# Resource Limitations
|
||||
LimitCORE=infinity
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -1,11 +1,12 @@
|
||||
[Unit]
|
||||
Description=Accton AS7816-64X Platform Monitoring service
|
||||
Before=pmon.service
|
||||
After=pddf-platform-init.service
|
||||
After=as7816-64x-platform-init.service
|
||||
Requires=as7816-64x-platform-init.service
|
||||
DefaultDependencies=no
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/accton_as7816_pddf_monitor.py
|
||||
ExecStart=/usr/local/bin/accton_as7816_64x_monitor.py
|
||||
KillSignal=SIGKILL
|
||||
SuccessExitStatus=SIGKILL
|
||||
|
@ -1,13 +0,0 @@
|
||||
[Unit]
|
||||
Description=Accton AS7816-64X Platform initialization service
|
||||
Before=pmon.service
|
||||
After=sysinit.target
|
||||
DefaultDependencies=no
|
||||
|
||||
[Service]
|
||||
ExecStartPre=/usr/local/bin/accton_as7816_util.py install
|
||||
ExecStart=/usr/local/bin/accton_as7816_monitor.py
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -1 +0,0 @@
|
||||
../../../../pddf/i2c/service/pddf-platform-init.service
|
@ -1,5 +1,8 @@
|
||||
from setuptools import setup
|
||||
|
||||
DEVICE_NAME = 'accton'
|
||||
HW_SKU = 'x86_64-accton_as7816_64x-r0'
|
||||
|
||||
setup(
|
||||
name='sonic-platform',
|
||||
version='1.0',
|
||||
@ -8,7 +11,13 @@ setup(
|
||||
author='SONiC Team',
|
||||
author_email='linuxnetdev@microsoft.com',
|
||||
url='https://github.com/Azure/sonic-buildimage',
|
||||
packages=['sonic_platform'],
|
||||
maintainer='Jostar Yang',
|
||||
maintainer_email='jostar_yang@edge-core.com',
|
||||
packages=[
|
||||
'sonic_platform',
|
||||
],
|
||||
package_dir={
|
||||
'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)},
|
||||
classifiers=[
|
||||
'Development Status :: 3 - Alpha',
|
||||
'Environment :: Plugins',
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (C) 2017 Accton Technology Corporation
|
||||
#
|
@ -48,8 +48,8 @@ FORCE = 0
|
||||
|
||||
|
||||
if DEBUG == True:
|
||||
print((sys.argv[0]))
|
||||
print(('ARGV :', sys.argv[1:] ))
|
||||
print(sys.argv[0])
|
||||
print('ARGV :', sys.argv[1:] )
|
||||
|
||||
|
||||
def main():
|
||||
@ -67,7 +67,7 @@ def main():
|
||||
if DEBUG == True:
|
||||
print(options)
|
||||
print(args)
|
||||
print((len(sys.argv)))
|
||||
print(len(sys.argv))
|
||||
|
||||
for opt, arg in options:
|
||||
if opt in ('-h', '--help'):
|
||||
@ -81,9 +81,14 @@ def main():
|
||||
logging.info('no option')
|
||||
for arg in args:
|
||||
if arg == 'install':
|
||||
do_install()
|
||||
do_install()
|
||||
elif arg == 'clean':
|
||||
do_uninstall()
|
||||
do_uninstall()
|
||||
elif arg == 'api':
|
||||
do_sonic_platform_install()
|
||||
elif arg == 'api_clean':
|
||||
do_sonic_platform_clean()
|
||||
|
||||
else:
|
||||
show_help()
|
||||
|
||||
@ -91,7 +96,7 @@ def main():
|
||||
return 0
|
||||
|
||||
def show_help():
|
||||
print(( __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]}))
|
||||
print( __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]})
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
@ -114,13 +119,13 @@ def ir3570_check():
|
||||
else:
|
||||
ret = 0
|
||||
except Exception as e:
|
||||
print(("Error on ir3570_check() e:" + str(e)))
|
||||
print("Error on ir3570_check() e:" + str(e))
|
||||
return -1
|
||||
return ret
|
||||
|
||||
def my_log(txt):
|
||||
if DEBUG == True:
|
||||
print(("[ROY]"+txt))
|
||||
print("[ROY]"+txt)
|
||||
return
|
||||
|
||||
def log_os_system(cmd, show):
|
||||
@ -131,7 +136,7 @@ def log_os_system(cmd, show):
|
||||
if status:
|
||||
logging.info('Failed :'+cmd)
|
||||
if show:
|
||||
print(('Failed :'+cmd))
|
||||
print('Failed :'+cmd)
|
||||
return status, output
|
||||
|
||||
def driver_check():
|
||||
@ -298,7 +303,44 @@ def system_ready():
|
||||
if not device_exist():
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
PLATFORM_ROOT_PATH = '/usr/share/sonic/device'
|
||||
PLATFORM_API2_WHL_FILE_PY3 ='sonic_platform-1.0-py3-none-any.whl'
|
||||
def do_sonic_platform_install():
|
||||
device_path = "{}{}{}{}".format(PLATFORM_ROOT_PATH, '/x86_64-accton_', PROJECT_NAME, '-r0')
|
||||
SONIC_PLATFORM_BSP_WHL_PKG_PY3 = "/".join([device_path, PLATFORM_API2_WHL_FILE_PY3])
|
||||
|
||||
#Check API2.0 on py whl file
|
||||
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0)
|
||||
if status:
|
||||
if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3):
|
||||
status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG_PY3, 1)
|
||||
if status:
|
||||
print("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
return status
|
||||
else:
|
||||
print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
else:
|
||||
print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
else:
|
||||
print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
|
||||
return
|
||||
|
||||
def do_sonic_platform_clean():
|
||||
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0)
|
||||
if status:
|
||||
print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
|
||||
else:
|
||||
status, output = log_os_system("pip3 uninstall sonic-platform -y", 0)
|
||||
if status:
|
||||
print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
return status
|
||||
else:
|
||||
print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
|
||||
return
|
||||
def do_install():
|
||||
print("Checking system....")
|
||||
if driver_check() == False:
|
||||
@ -308,7 +350,7 @@ def do_install():
|
||||
if FORCE == 0:
|
||||
return status
|
||||
else:
|
||||
print((PROJECT_NAME.upper()+" drivers detected...."))
|
||||
print(PROJECT_NAME.upper()+" drivers detected....")
|
||||
|
||||
ir3570_check()
|
||||
|
||||
@ -319,13 +361,15 @@ def do_install():
|
||||
if FORCE == 0:
|
||||
return status
|
||||
else:
|
||||
print((PROJECT_NAME.upper()+" devices detected...."))
|
||||
print(PROJECT_NAME.upper()+" devices detected....")
|
||||
do_sonic_platform_install()
|
||||
|
||||
return
|
||||
|
||||
def do_uninstall():
|
||||
print("Checking system....")
|
||||
if not device_exist():
|
||||
print((PROJECT_NAME.upper() +" has no device installed...."))
|
||||
print(PROJECT_NAME.upper() +" has no device installed....")
|
||||
else:
|
||||
print("Removing device....")
|
||||
status = device_uninstall()
|
||||
@ -334,7 +378,7 @@ def do_uninstall():
|
||||
return status
|
||||
|
||||
if driver_check()== False :
|
||||
print((PROJECT_NAME.upper() +" has no driver installed...."))
|
||||
print(PROJECT_NAME.upper() +" has no driver installed....")
|
||||
else:
|
||||
print("Removing installed driver....")
|
||||
status = driver_uninstall()
|
||||
@ -342,6 +386,8 @@ def do_uninstall():
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
do_sonic_platform_clean()
|
||||
|
||||
return
|
||||
|
||||
def device_exist():
|
@ -42,7 +42,8 @@ enum chips {
|
||||
YM2651,
|
||||
YM2401,
|
||||
YM2851,
|
||||
YPEB1200AM
|
||||
YM1401A,
|
||||
YPEB1200AM
|
||||
};
|
||||
|
||||
/* Each client has this additional data
|
||||
@ -66,8 +67,9 @@ struct ym2651y_data {
|
||||
u16 fan_duty_cycle[2]; /* Register value */
|
||||
u8 fan_dir[4]; /* Register value */
|
||||
u8 pmbus_revision; /* Register value */
|
||||
u8 mfr_serial[21]; /* Register value */
|
||||
u8 mfr_id[10]; /* Register value */
|
||||
u8 mfr_model[10]; /* Register value */
|
||||
u8 mfr_model[16]; /* Register value */
|
||||
u8 mfr_revsion[3]; /* Register value */
|
||||
u16 mfr_vin_min; /* Register value */
|
||||
u16 mfr_vin_max; /* Register value */
|
||||
@ -113,9 +115,11 @@ enum ym2651y_sysfs_attributes {
|
||||
PSU_FAN1_SPEED,
|
||||
PSU_FAN1_DUTY_CYCLE,
|
||||
PSU_PMBUS_REVISION,
|
||||
PSU_SERIAL_NUM,
|
||||
PSU_MFR_ID,
|
||||
PSU_MFR_MODEL,
|
||||
PSU_MFR_REVISION,
|
||||
PSU_MFR_SERIAL,
|
||||
PSU_MFR_VIN_MIN,
|
||||
PSU_MFR_VIN_MAX,
|
||||
PSU_MFR_VOUT_MIN,
|
||||
@ -141,9 +145,11 @@ static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FA
|
||||
static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, show_linear, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE);
|
||||
static SENSOR_DEVICE_ATTR(psu_fan_dir, S_IRUGO, show_ascii, NULL, PSU_FAN_DIRECTION);
|
||||
static SENSOR_DEVICE_ATTR(psu_pmbus_revision, S_IRUGO, show_byte, NULL, PSU_PMBUS_REVISION);
|
||||
static SENSOR_DEVICE_ATTR(psu_serial_num, S_IRUGO, show_ascii, NULL, PSU_SERIAL_NUM);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_id, S_IRUGO, show_ascii, NULL, PSU_MFR_ID);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, show_ascii, NULL, PSU_MFR_MODEL);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_revision, S_IRUGO, show_ascii, NULL, PSU_MFR_REVISION);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_serial, S_IRUGO, show_ascii, NULL, PSU_MFR_SERIAL);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_vin_min, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MIN);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_vin_max, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MAX);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_vout_min, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MIN);
|
||||
@ -175,9 +181,11 @@ static struct attribute *ym2651y_attributes[] = {
|
||||
&sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_fan_dir.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_pmbus_revision.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_serial_num.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_id.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_model.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_revision.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_serial.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_vin_min.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_vin_max.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_pout_max.dev_attr.attr,
|
||||
@ -362,14 +370,17 @@ static ssize_t show_ascii(struct device *dev, struct device_attribute *da,
|
||||
}
|
||||
ptr = data->fan_dir;
|
||||
break;
|
||||
case PSU_MFR_SERIAL: /* psu_mfr_serial */
|
||||
ptr = data->mfr_serial+1; /* The first byte is the count byte of string. */
|
||||
break;
|
||||
case PSU_MFR_ID: /* psu_mfr_id */
|
||||
ptr = data->mfr_id;
|
||||
ptr = data->mfr_id+1; /* The first byte is the count byte of string. */
|
||||
break;
|
||||
case PSU_MFR_MODEL: /* psu_mfr_model */
|
||||
ptr = data->mfr_model;
|
||||
ptr = data->mfr_model+1; /* The first byte is the count byte of string. */
|
||||
break;
|
||||
case PSU_MFR_REVISION: /* psu_mfr_revision */
|
||||
ptr = data->mfr_revsion;
|
||||
ptr = data->mfr_revsion+1;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
@ -415,7 +426,7 @@ static ssize_t show_vout(struct device *dev, struct device_attribute *da,
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ym2651y_data *data = i2c_get_clientdata(client);
|
||||
|
||||
if (data->chip == YM2401) {
|
||||
if (data->chip == YM2401 || data->chip==YM1401A) {
|
||||
return show_vout_by_mode(dev, da, buf);
|
||||
}
|
||||
else {
|
||||
@ -493,6 +504,7 @@ static const struct i2c_device_id ym2651y_id[] = {
|
||||
{ "ym2651", YM2651 },
|
||||
{ "ym2401", YM2401 },
|
||||
{ "ym2851", YM2851 },
|
||||
{ "ym1401a",YM1401A},
|
||||
{ "ype1200am", YPEB1200AM },
|
||||
{}
|
||||
};
|
||||
@ -561,8 +573,8 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev)
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||
|| !data->valid) {
|
||||
int i, status;
|
||||
u8 command;
|
||||
int i, status, length;
|
||||
u8 command, buf;
|
||||
u8 fan_dir[5] = {0};
|
||||
struct reg_data_byte regs_byte[] = { {0x19, &data->capability},
|
||||
{0x20, &data->vout_mode},
|
||||
@ -599,6 +611,7 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev)
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n",
|
||||
regs_byte[i].reg, status);
|
||||
*(regs_byte[i].value) = 0;
|
||||
goto exit;
|
||||
}
|
||||
else {
|
||||
*(regs_byte[i].value) = status;
|
||||
@ -614,6 +627,7 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev)
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n",
|
||||
regs_word[i].reg, status);
|
||||
*(regs_word[i].value) = 0;
|
||||
goto exit;
|
||||
}
|
||||
else {
|
||||
*(regs_word[i].value) = status;
|
||||
@ -626,6 +640,7 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev)
|
||||
|
||||
if (status < 0) {
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
strncpy(data->fan_dir, fan_dir+1, ARRAY_SIZE(data->fan_dir)-1);
|
||||
@ -642,12 +657,61 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev)
|
||||
|
||||
/* Read mfr_model */
|
||||
command = 0x9a;
|
||||
status = ym2651y_read_block(client, command, data->mfr_model,
|
||||
ARRAY_SIZE(data->mfr_model)-1);
|
||||
data->mfr_model[ARRAY_SIZE(data->mfr_model)-1] = '\0';
|
||||
length = 1;
|
||||
/* Read first byte to determine the length of data */
|
||||
status = ym2651y_read_block(client, command, &buf, length);
|
||||
if (status < 0) {
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
|
||||
goto exit;
|
||||
}
|
||||
status = ym2651y_read_block(client, command, data->mfr_model, buf+1);
|
||||
|
||||
if ((buf+1) >= (ARRAY_SIZE(data->mfr_model)-1))
|
||||
{
|
||||
data->mfr_model[ARRAY_SIZE(data->mfr_model)-1] = '\0';
|
||||
}
|
||||
else
|
||||
data->mfr_model[buf+1] = '\0';
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*YM-1401A PSU doens't support to get serial_num, so ignore it.
|
||||
*It's vout doesn't support linear, so let it use show_vout_by_mode().
|
||||
*/
|
||||
if(!strncmp("YM-1401A", data->mfr_model+1, strlen("YM-1401A")))
|
||||
{
|
||||
data->chip=YM1401A;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Read mfr_serial */
|
||||
command = 0x9e;
|
||||
length = 1;
|
||||
/* Read first byte to determine the length of data */
|
||||
status = ym2651y_read_block(client, command, &buf, length);
|
||||
if (status < 0) {
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
|
||||
goto exit;
|
||||
}
|
||||
status = ym2651y_read_block(client, command, data->mfr_serial, buf+1);
|
||||
|
||||
if ((buf+1) >= (ARRAY_SIZE(data->mfr_serial)-1))
|
||||
{
|
||||
data->mfr_serial[ARRAY_SIZE(data->mfr_serial)-1] = '\0';
|
||||
}
|
||||
else
|
||||
data->mfr_serial[buf+1] = '\0';
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read mfr_revsion */
|
||||
command = 0x9b;
|
||||
@ -656,12 +720,16 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev)
|
||||
data->mfr_revsion[ARRAY_SIZE(data->mfr_revsion)-1] = '\0';
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
|
@ -1 +1 @@
|
||||
as4630-54pe/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as4630_54pe-r0/pddf
|
||||
as4630-54pe/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as4630_54pe-r0
|
||||
|
@ -1,8 +0,0 @@
|
||||
# Special arrangement to make PDDF mode default
|
||||
# Disable monitor, monitor-fan, monitor-psu (not enabling them would imply they will be disabled by default)
|
||||
# Enable pddf-platform-monitor
|
||||
depmod -a
|
||||
systemctl enable pddf-platform-init.service
|
||||
systemctl start pddf-platform-init.service
|
||||
systemctl enable as4630-54pe-pddf-platform-monitor.service
|
||||
systemctl start as4630-54pe-pddf-platform-monitor.service
|
@ -1 +1,2 @@
|
||||
as7326-56x/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as7326_56x-r0/pddf
|
||||
as7326-56x/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as7326_56x-r0
|
||||
|
||||
|
@ -1 +1,2 @@
|
||||
as7816-64x/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as7816_64x-r0/pddf
|
||||
as7816-64x/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as7816_64x-r0
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user