From dbbad6b3e07200f0ed9ac5386f9adb1886737756 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Tue, 27 Apr 2021 11:40:20 +0800 Subject: [PATCH 01/31] [AS7326-56X] Support API2.0 Signed-off-by: Jostar Yang --- .../plugins/eeprom.py | 16 +- .../sonic_platform/__init__.py | 2 + .../sonic_platform/chassis.py | 184 +++ .../sonic_platform/component.py | 113 ++ .../sonic_platform/eeprom.py | 108 ++ .../sonic_platform/fan.py | 185 +++ .../sonic_platform/fan_drawer.py | 43 + .../sonic_platform/platform.py | 22 + .../sonic_platform/psu.py | 197 +++ .../sonic_platform/sfp.py | 1374 +++++++++++++++++ .../sonic_platform/thermal.py | 200 +++ .../as7326-56x/sonic_platform_setup.py | 34 + .../as7326-56x/utils/accton_as7326_util.py | 97 +- .../sonic-platform-accton-as7326-56x.install | 2 + 14 files changed, 2568 insertions(+), 9 deletions(-) create mode 100644 device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/__init__.py create mode 100644 device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py create mode 100644 device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/component.py create mode 100644 device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py create mode 100644 device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py create mode 100644 device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan_drawer.py create mode 100644 device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/platform.py create mode 100644 device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py create mode 100644 device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py create mode 100644 device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/thermal.py create mode 100644 platform/broadcom/sonic-platform-modules-accton/as7326-56x/sonic_platform_setup.py create mode 100644 platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7326-56x.install diff --git a/device/accton/x86_64-accton_as7326_56x-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as7326_56x-r0/plugins/eeprom.py index 4241483d68eb..28db26eddd31 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/plugins/eeprom.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/plugins/eeprom.py @@ -1,4 +1,7 @@ +#!/usr/bin/env python + try: + import exceptions import binascii import time import optparse @@ -8,13 +11,16 @@ from sonic_eeprom import eeprom_base from sonic_eeprom import eeprom_tlvinfo import subprocess -except ImportError as e: - raise ImportError(str(e) + "- required module not found") - +except ImportError, e: + raise ImportError (str(e) + "- required module not found") 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) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/__init__.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/__init__.py new file mode 100644 index 000000000000..73a7720e8979 --- /dev/null +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = [ "platform", "chassis", "sfp", "eeprom", "component", "psu", "thermal", "fan", "fan_drawer" ] +from . import platform diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py new file mode 100644 index 000000000000..a1dcf04a1af5 --- /dev/null +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python + +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Chassis information which are available in the platform +# +############################################################################# + +import os + +try: + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.sfp import Sfp + from sonic_platform.fan_drawer import FanDrawer + from sonic_platform.psu import Psu + from sonic_platform.thermal import Thermal + from sonic_platform.eeprom import Tlv + from sonic_platform.component import Component + 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 = 56 +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 = "docker > /dev/null 2>&1" + + +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): + for index in range(NUM_PORT): + sfp = Sfp(index) + self._sfp_list.append(sfp) + self.sfp_module_initialized = True + + def __initialize_fan(self): + 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): + for index in range(NUM_PSU): + psu = Psu(index) + self._psu_list.append(psu) + + def __initialize_thermals(self): + for index in range(NUM_THERMAL): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + def __initialize_eeprom(self): + self._eeprom = Tlv() + + def __initialize_components(self): + 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 get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return self.hwsku + + 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_serial_number(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_sfp(self, index): + """ + Retrieves sfp represented by (1-based) 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 \ No newline at end of file diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/component.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/component.py new file mode 100644 index 000000000000..2d06b6295f8b --- /dev/null +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/component.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python + +############################################################################# +# 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 +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 diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py new file mode 100644 index 000000000000..7321ad6ffcfe --- /dev/null +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py @@ -0,0 +1,108 @@ + +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' + + +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 get_eeprom(self): + return self._eeprom + + def get_serial(self): + return self._eeprom.get('0x23') + + def get_mac(self): + return self._eeprom.get('0x24', "Undefined.") diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py new file mode 100644 index 000000000000..bf341524580a --- /dev/null +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py @@ -0,0 +1,185 @@ + +############################################################################# +# Edgecor +# +# 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 +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" + }, +} + + +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) + "_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 False #Not supported + + 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 False #Not supported + + 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_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) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan_drawer.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan_drawer.py new file mode 100644 index 000000000000..8e4dc8172369 --- /dev/null +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan_drawer.py @@ -0,0 +1,43 @@ + +######################################################################## +# +# 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 + from sonic_platform.fan import Fan +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 + for i in range(FANS_PER_FANTRAY): + self._fan_list.append(Fan(fantray_index, i)) + + def get_name(self): + """ + Retrieves the fan drawer name + Returns: + string: The name of the device + """ + return "FanTray{}".format(self.fantrayindex) + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/platform.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/platform.py new file mode 100644 index 000000000000..b752b64f11f8 --- /dev/null +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/platform.py @@ -0,0 +1,22 @@ + +############################################################################# +# 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() diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py new file mode 100644 index 000000000000..ddc1b14dd633 --- /dev/null +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py @@ -0,0 +1,197 @@ + +############################################################################# +# 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.fan import Fan + 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._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 "" + + 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") + return float(val) / 1000 + + 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") + return float(val) / 1000 + + 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") + return float(val) / 1000 + + 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 + """ + + return False #Controlled by HW + + 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") + return float(val) / 1000 + + 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") + return float(val) / 1000 + + 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") + 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 + """ + val = self.__read_txt_file(self.cpld_path + "psu_power_good") + return int(val, 10) == 1 diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py new file mode 100644 index 000000000000..b541fbac5edb --- /dev/null +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py @@ -0,0 +1,1374 @@ +############################################################################# +# 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.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 +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{}/" + +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): + """Platform-specific Sfp class""" + + # Port number + PORT_START = 1 + PORT_END = 56 + + # 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" + + 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], + } + + def __init__(self, sfp_index=0): + # 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]) + + self.info_dict_keys = [ + 'type', 'hardware_rev', 'serial', 'manufacturer', 'model', + 'connector', 'encoding', 'ext_identifier', + 'ext_rateselect_compliance', 'cable_type', 'cable_length', + 'nominal_bit_rate', 'specification_compliance', 'vendor_date', + 'vendor_oui','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) + + 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 __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', buffering=0) 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_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 + hardware_rev |1*255VCHAR |hardware version 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 <= 48: + sfpi_obj = sff8472InterfaceId() #SFP + elif self.port_num <= 56: + sfpi_obj = sff8436InterfaceId() #QSFP + if not self.get_presence() or not sfpi_obj: + return {} + + if self.port_num <= 48: + 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 <= 48: + 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['hardware_rev'] = sfp_vendor_rev_data['data'][ + 'Vendor Rev']['value'] if sfp_vendor_rev_data else 'N/A' + transceiver_info_dict['serial'] = sfp_vendor_sn_data['data'][ + 'Vendor SN']['value'] if sfp_vendor_sn_data else 'N/A' + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data'][ + 'Vendor OUI']['value'] if sfp_vendor_oui_data else 'N/A' + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data['data'][ + 'VendorDataCode(YYYY-MM-DD Lot)'][ + 'value'] if sfp_vendor_date_data else 'N/A' + transceiver_info_dict['cable_type'] = "Unknown" + transceiver_info_dict['cable_length'] = "Unknown" + + if self.port_num <= 48: + 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 + txbias |INT |TX Bias Current in mA, n is the channel number, + | |for example, tx2bias stands for tx bias of channel 2. + rxpower |INT |received optical power in mW, n is the channel number, + | |for example, rx2power stands for rx power of channel 2. + txpower |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 <= 48: #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_qsfp_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 <= 48: + 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: #QSFP case + 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 + Returns: + A Boolean, True if reset enabled, False if disabled + """ + if self.port_num <= 48: + 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. + """ + rx_los = False + if self.port_num <= 48: + cpld_val = self.__read_txt_file( + self.cpld_path + "module_rx_los_" + str(self.port_num)) + rx_los = (int(cpld_val, 10) == 1) + #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) + 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 <= 48: + cpld_val = self.__read_txt_file( + self.cpld_path + "module_tx_fault_" + str(self.port_num)) + tx_fault = (int(cpld_val, 10) == 1) + #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) + 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 <= 48: + 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 + + return tx_disable + 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 <= 48: + # 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 <= 48: + # 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: + # 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_POWEROVERRIDE_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: + 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_POWEROVERRIDE_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 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 <= 48: + 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 <= 48: + 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 <= 48: + 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. + Returns: + A boolean, True if successful, False if not + """ + # Check for invalid port_num + if self.port_num <= 48: + 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: + 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: + 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: + return False # SFP doesn't support this feature + + if lpmode is True: + 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: + 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_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() diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/thermal.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/thermal.py new file mode 100644 index 000000000000..673bf95192aa --- /dev/null +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/thermal.py @@ -0,0 +1,200 @@ + +############################################################################# +# 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: { + "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_I2C_MAPPING[psu_index]["bus"] + 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]["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): + temp = int() + + 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 + """ + temp_file = str() + + 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 + """ + #Not supported + return False + + 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 diff --git a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/sonic_platform_setup.py new file mode 100644 index 000000000000..a106db0b178c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/sonic_platform_setup.py @@ -0,0 +1,34 @@ +from setuptools import setup + +DEVICE_NAME = 'accton' +HW_SKU = 'x86_64-accton_as7326_56x-r0' + +setup( + name='sonic-platform', + version='1.0', + 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', + maintainer='Brandon Chuang', + maintainer_email='brandon_chuang@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', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/utils/accton_as7326_util.py b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/utils/accton_as7326_util.py index c5d047e9d4e0..6983ed4a210c 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/utils/accton_as7326_util.py +++ b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/utils/accton_as7326_util.py @@ -45,7 +45,7 @@ import logging import re import time - +import os @@ -78,7 +78,7 @@ def main(): 'debug', 'force', ]) - if DEBUG == True: + if DEBUG == True: print options print args print len(sys.argv) @@ -96,6 +96,10 @@ 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': @@ -199,7 +203,7 @@ def driver_check(): def driver_install(): global FORCE - + status, output = log_os_system('modprobe i2c_dev', 1) status, output = log_os_system("depmod", 1) for i in range(0,len(kos)): @@ -268,7 +272,6 @@ def driver_uninstall(): '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 +289,22 @@ def driver_uninstall(): 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 = commands.getstatusoutput(cmd) + return status + def device_install(): global FORCE @@ -320,6 +333,22 @@ def device_install(): 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) @@ -364,6 +393,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 +418,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 +478,9 @@ def do_install(): return status else: print PROJECT_NAME.upper()+" devices detected...." + + do_sonic_platform_install() + return def do_uninstall(): @@ -416,6 +503,8 @@ def do_uninstall(): if FORCE == 0: return status + do_sonic_platform_clean() + return def devices_info(): diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7326-56x.install b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7326-56x.install new file mode 100644 index 000000000000..593fa9332763 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7326-56x.install @@ -0,0 +1,2 @@ +as7326-56x/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as7326_56x-r0/pddf + From 9ce97de5634ab247baef26d46a3847ec1defcf8f Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Tue, 27 Apr 2021 16:19:53 +0800 Subject: [PATCH 02/31] Fix LGTM alerts --- .../plugins/eeprom.py | 1 - .../sonic_platform/chassis.py | 3 +- .../sonic_platform/component.py | 7 +-- .../sonic_platform/fan.py | 3 +- .../sonic_platform/fan_drawer.py | 9 ++-- .../sonic_platform/platform.py | 1 - .../sonic_platform/psu.py | 7 +-- .../sonic_platform/sfp.py | 51 ++++++++++--------- .../sonic_platform/thermal.py | 5 -- 9 files changed, 41 insertions(+), 46 deletions(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as7326_56x-r0/plugins/eeprom.py index 28db26eddd31..78da4145c21e 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/plugins/eeprom.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/plugins/eeprom.py @@ -1,7 +1,6 @@ #!/usr/bin/env python try: - import exceptions import binascii import time import optparse diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py index a1dcf04a1af5..9ca0a1bc2f5b 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py @@ -9,6 +9,7 @@ ############################################################################# import os +import sys try: from sonic_platform_base.chassis_base import ChassisBase @@ -26,7 +27,7 @@ NUM_FAN_TRAY = 6 NUM_PSU = 2 NUM_THERMAL = 4 -NUM_PORT = 56 +NUM_PORT = 58 NUM_COMPONENT = 4 HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/component.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/component.py index 2d06b6295f8b..a588e343b56c 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/component.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/component.py @@ -1,16 +1,11 @@ -#!/usr/bin/env python - ############################################################################# -# Edgecore +# 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 except ImportError as e: diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py index bf341524580a..91af071784ac 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py @@ -1,6 +1,5 @@ - ############################################################################# -# Edgecor +# Edgecore # # Module contains an implementation of SONiC Platform Base API and # provides the fan status which are available in the platform diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan_drawer.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan_drawer.py index 8e4dc8172369..94357d5d82ba 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan_drawer.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan_drawer.py @@ -1,4 +1,3 @@ - ######################################################################## # # Module contains an implementation of SONiC Platform Base API and @@ -8,7 +7,6 @@ try: from sonic_platform_base.fan_drawer_base import FanDrawerBase - from sonic_platform.fan import Fan except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -23,8 +21,13 @@ 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(fantray_index, i)) + self._fan_list.append(Fan(self.fantrayindex, i)) def get_name(self): """ diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/platform.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/platform.py index b752b64f11f8..2f2c2a447fcf 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/platform.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/platform.py @@ -1,4 +1,3 @@ - ############################################################################# # Edgecore # diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py index ddc1b14dd633..8d002d5dc8ee 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py @@ -1,4 +1,3 @@ - ############################################################################# # Edgecore # @@ -11,7 +10,6 @@ try: from sonic_platform_base.psu_base import PsuBase - from sonic_platform.fan import Fan from sonic_platform.thermal import Thermal except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -59,7 +57,10 @@ def __init__(self, psu_index=0): 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, diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py index b541fbac5edb..687437425d82 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py @@ -131,7 +131,7 @@ class Sfp(SfpBase): # Port number PORT_START = 1 - PORT_END = 56 + PORT_END = 58 # Path to sysfs PLATFORM_ROOT_PATH = "/usr/share/sonic/device" @@ -198,6 +198,8 @@ class Sfp(SfpBase): 54: [30], 55: [31], 56: [32], + 57: [22], + 58: [23] } def __init__(self, sfp_index=0): @@ -343,14 +345,15 @@ def get_transceiver_info(self): ======================================================================== """ # check present status - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >=57: sfpi_obj = sff8472InterfaceId() #SFP elif self.port_num <= 56: sfpi_obj = sff8436InterfaceId() #QSFP + if not self.get_presence() or not sfpi_obj: return {} - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >=57: offset = SFP_INFO_OFFSET sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes( (offset + XCVR_INTFACE_BULK_OFFSET), @@ -373,7 +376,7 @@ def get_transceiver_info(self): (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 <= 48: + if self.port_num <= 48 or self.port_num >=57: sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes( (offset + XCVR_HW_REV_OFFSET), XCVR_HW_REV_WIDTH_SFP) else: @@ -431,7 +434,7 @@ def get_transceiver_info(self): transceiver_info_dict['cable_type'] = "Unknown" transceiver_info_dict['cable_length'] = "Unknown" - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >=57: for key in sfp_cable_length_tup: if key in sfp_interface_bulk_data['data']: transceiver_info_dict['cable_type'] = key @@ -498,7 +501,7 @@ def get_transceiver_bulk_status(self): ======================================================================== """ # check present status - if self.port_num <= 48: #SFP case + if self.port_num <= 48 or self.port_num >=57: #SFP case sfpd_obj = sff8472Dom() if not self.get_presence() or not sfpd_obj: return {} @@ -560,7 +563,7 @@ def get_transceiver_bulk_status(self): (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_qsfp_dom_capability( + qspf_dom_capability_data = sfpi_obj.parse_dom_capability( qsfp_dom_capability_raw, 0) else: return None @@ -692,7 +695,7 @@ def get_transceiver_threshold_info(self): ======================================================================== """ # check present status - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >=57: sfpd_obj = sff8472Dom() if not self.get_presence() and not sfpd_obj: @@ -872,7 +875,7 @@ def get_reset_status(self): Returns: A Boolean, True if reset enabled, False if disabled """ - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >=57: return False # SPF port doesn't support this feature val = self.__read_txt_file( @@ -887,7 +890,7 @@ def get_rx_los(self): Note : RX LOS status is latched until a call to get_rx_los or a reset. """ rx_los = False - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >=57: cpld_val = self.__read_txt_file( self.cpld_path + "module_rx_los_" + str(self.port_num)) rx_los = (int(cpld_val, 10) == 1) @@ -919,7 +922,7 @@ def get_tx_fault(self): Note : TX fault status is lached until a call to get_tx_fault or a reset. """ tx_fault = False - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >=57: cpld_val = self.__read_txt_file( self.cpld_path + "module_tx_fault_" + str(self.port_num)) tx_fault = (int(cpld_val, 10) == 1) @@ -950,7 +953,7 @@ def get_tx_disable(self): Returns: A Boolean, True if tx_disable is enabled, False if disabled """ - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >=57: tx_disable = False status_control_raw = self.__read_eeprom_specific_bytes( @@ -1000,7 +1003,7 @@ def get_tx_disable_channel(self): As an example, a returned value of 0x5 indicates that channel 0 and channel 2 have been disabled. """ - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >=57: # SFP doesn't support this feature return False else: @@ -1019,7 +1022,7 @@ def get_lpmode(self): Returns: A Boolean, True if lpmode is enabled, False if disabled """ - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >= 57: # SFP doesn't support this feature return False @@ -1029,7 +1032,7 @@ def get_lpmode(self): def get_power_set(self): - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >= 57: # SFP doesn't support this feature return False else: @@ -1056,7 +1059,7 @@ def get_power_override(self): Returns: A Boolean, True if power-override is enabled, False if disabled """ - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >= 57: return False # SFP doesn't support this feature else: power_override = False @@ -1105,7 +1108,7 @@ def get_tx_bias(self): transceiver_dom_info_dict = self.get_transceiver_bulk_status() tx1_bs = transceiver_dom_info_dict.get("tx1bias", "N/A") - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >=57: return [tx1_bs, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else [] @@ -1126,7 +1129,7 @@ def get_rx_power(self): transceiver_dom_info_dict = self.get_transceiver_bulk_status() rx1_pw = transceiver_dom_info_dict.get("rx1power", "N/A") - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >=57: 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") @@ -1145,7 +1148,7 @@ def get_tx_power(self): """ transceiver_dom_info_dict = self.get_transceiver_bulk_status() tx1_pw = transceiver_dom_info_dict.get("tx1power", "N/A") - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >=57: 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") @@ -1160,7 +1163,7 @@ def reset(self): A boolean, True if successful, False if not """ # Check for invalid port_num - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >=57: return False # SFP doesn't support this feature ret = self.__write_txt_file( @@ -1183,7 +1186,7 @@ def tx_disable(self, tx_disable): Returns: A boolean, True if tx_disable is set successfully, False if not """ - if self.port_num <= 48: + 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) @@ -1227,7 +1230,7 @@ def tx_disable_channel(self, channel, disable): A boolean, True if successful, False if not """ - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >=57: return False # SFP doesn't support this feature else: if not self.get_presence(): @@ -1275,7 +1278,7 @@ def set_lpmode(self, lpmode): Returns: A boolean, True if lpmode is set successfully, False if not """ - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >=57: return False # SFP doesn't support this feature if lpmode is True: @@ -1300,7 +1303,7 @@ def set_power_override(self, power_override, power_set): A boolean, True if power-override and power_set are set successfully, False if not """ - if self.port_num <= 48: + if self.port_num <= 48 or self.port_num >=57: return False # SFP doesn't support this feature else: if not self.get_presence(): diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/thermal.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/thermal.py index 673bf95192aa..5dce996f80ad 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/thermal.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/thermal.py @@ -1,4 +1,3 @@ - ############################################################################# # Edgecore # @@ -90,8 +89,6 @@ def __read_txt_file(self, file_path): pass def __get_temp(self, temp_file): - temp = int() - if not self.is_psu: temp_file_path = os.path.join(self.hwmon_path, temp_file) else: @@ -119,8 +116,6 @@ def get_temperature(self): A float number of current temperature in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ - temp_file = str() - if not self.is_psu: temp_file = "temp{}_input".format(self.ss_index) else: From 7dccda3086258edfb4433b8b45d7535117730f57 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Wed, 28 Apr 2021 13:57:01 +0800 Subject: [PATCH 03/31] Fix error path in install file --- .../debian/sonic-platform-accton-as7326-56x.install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7326-56x.install b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7326-56x.install index 593fa9332763..a6b7094e0e03 100644 --- a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7326-56x.install +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as7326-56x.install @@ -1,2 +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 From 6d2b4a216c39b373e4147e877f23e9230792d939 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Thu, 6 May 2021 17:16:36 +0800 Subject: [PATCH 04/31] Add port evt change api and update psu.py --- .../sonic_platform/chassis.py | 50 ++++++++++--- .../sonic_platform/eeprom.py | 37 ++++++++-- .../sonic_platform/event.py | 53 ++++++++++++++ .../sonic_platform/psu.py | 70 ++++++++++++++++--- 4 files changed, 186 insertions(+), 24 deletions(-) create mode 100644 device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/event.py diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py index 9ca0a1bc2f5b..3e38c14680bf 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################# # Edgecore # @@ -9,16 +7,10 @@ ############################################################################# import os -import sys try: from sonic_platform_base.chassis_base import ChassisBase - from sonic_platform.sfp import Sfp - from sonic_platform.fan_drawer import FanDrawer - from sonic_platform.psu import Psu - from sonic_platform.thermal import Thermal - from sonic_platform.eeprom import Tlv - from sonic_platform.component import Component + from .event import SfpEvent from sonic_py_common import device_info except ImportError as e: @@ -53,31 +45,37 @@ def __init__(self): 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.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) @@ -104,6 +102,21 @@ def get_name(self): """ return self.hwsku + 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 @@ -113,6 +126,14 @@ def get_base_mac(self): """ 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_number(self): """ Retrieves the hardware serial number for the chassis @@ -160,7 +181,16 @@ def get_reboot_cause(self): 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() + + status, sfp_event = SfpEvent(self._sfp_list).get_sfp_event(timeout) + + return status, sfp_event + def get_sfp(self, index): """ Retrieves sfp represented by (1-based) index diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py index 7321ad6ffcfe..5ade5bf0cdf0 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py @@ -13,7 +13,7 @@ CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' CACHE_FILE = 'syseeprom_cache' - +NULL = 'N/A' class Tlv(eeprom_tlvinfo.TlvInfoDecoder): @@ -98,11 +98,40 @@ def _load_eeprom(self): return self.__parse_output(decode_output) + def _valid_tlv(self, eeprom_data): + tlvinfo_type_codes_list = [ + self._TLV_CODE_PRODUCT_NAME, + self._TLV_CODE_PART_NUMBER, + self._TLV_CODE_SERIAL_NUMBER, + self._TLV_CODE_MAC_BASE, + self._TLV_CODE_MANUF_DATE, + self._TLV_CODE_DEVICE_VERSION, + self._TLV_CODE_LABEL_REVISION, + self._TLV_CODE_PLATFORM_NAME, + self._TLV_CODE_ONIE_VERSION, + self._TLV_CODE_MAC_SIZE, + self._TLV_CODE_MANUF_NAME, + self._TLV_CODE_MANUF_COUNTRY, + self._TLV_CODE_VENDOR_NAME, + self._TLV_CODE_DIAG_VERSION, + self._TLV_CODE_SERVICE_TAG, + self._TLV_CODE_VENDOR_EXT, + self._TLV_CODE_CRC_32 + ] + + for code in tlvinfo_type_codes_list: + code_str = "0x{:X}".format(code) + eeprom_data[code_str] = eeprom_data.get(code_str, NULL) + return eeprom_data + def get_eeprom(self): - return self._eeprom + 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') + return self._eeprom.get('0x23', NULL) def get_mac(self): - return self._eeprom.get('0x24', "Undefined.") + return self._eeprom.get('0x24', NULL) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/event.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/event.py new file mode 100644 index 000000000000..b0f9f1c15d67 --- /dev/null +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/event.py @@ -0,0 +1,53 @@ +try: + import time + from sonic_py_common.logger import Logger +except ImportError as e: + raise ImportError(repr(e) + " - required module not found") + + +class SfpEvent: + ''' Listen to insert/remove sfp events ''' + + def __init__(self, sfp_list): + self._sfp_list = sfp_list + self._logger = Logger() + + 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 + + bitmap = 0 + for sfp in self._sfp_list: + modpres = sfp.get_presence() + i=sfp.port_num-1 + if modpres: + bitmap = bitmap | (1 << i) + + changed_ports = self.sfp_change_event_data['present'] ^ bitmap + if changed_ports: + 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 + self.sfp_change_event_data['last'] = now + self.sfp_change_event_data['valid'] = 1 + return True, change_dict + else: + return True, change_dict diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py index 8d002d5dc8ee..dce2946d459e 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py @@ -83,7 +83,10 @@ def get_voltage(self): e.g. 12.1 """ val = self.__read_txt_file(self.hwmon_path + "psu_v_out") - return float(val) / 1000 + if val is not None: + return float(val)/ 1000 + else: + return 0 def get_current(self): """ @@ -92,7 +95,10 @@ def get_current(self): A float number, the electric current in amperes, e.g 15.4 """ val = self.__read_txt_file(self.hwmon_path + "psu_i_out") - return float(val) / 1000 + if val is not None: + return float(val)/1000 + else: + return 0 def get_power(self): """ @@ -101,8 +107,11 @@ def get_power(self): A float number, the power in watts, e.g. 302.6 """ val = self.__read_txt_file(self.hwmon_path + "psu_p_out") - return float(val) / 1000 - + if val is not None: + return float(val)/1000 + else: + return 0 + def get_powergood_status(self): """ Retrieves the powergood status of PSU @@ -130,8 +139,15 @@ def get_status_led(self): Returns: A string, one of the predefined STATUS_LED_COLOR_* strings above """ - - return False #Controlled by HW + status=self.get_status() + if not status: + return self.STATUS_LED_COLOR_RED + + if status==1: + return self.STATUS_LED_COLOR_GREEN + else: + return self.STATUS_LED_COLOR_RED + def get_temperature(self): """ @@ -159,7 +175,10 @@ def get_voltage_high_threshold(self): e.g. 12.1 """ val = self.__read_txt_file(self.hwmon_path + "psu_mfr_vout_max") - return float(val) / 1000 + if val is not None: + return float(val)/ 1000 + else: + return 0 def get_voltage_low_threshold(self): """ @@ -169,7 +188,10 @@ def get_voltage_low_threshold(self): e.g. 12.1 """ val = self.__read_txt_file(self.hwmon_path + "psu_mfr_vout_min") - return float(val) / 1000 + if val is not None: + return float(val)/ 1000 + else: + return 0 def get_name(self): """ @@ -186,7 +208,10 @@ def get_presence(self): bool: True if PSU is present, False if not """ val = self.__read_txt_file(self.cpld_path + "psu_present") - return int(val, 10) == 1 + if val is not None: + return int(val, 10) == 1 + else: + return 0 def get_status(self): """ @@ -195,4 +220,29 @@ def get_status(self): A boolean value, True if device is operating properly, False if not """ val = self.__read_txt_file(self.cpld_path + "psu_power_good") - return int(val, 10) == 1 + 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 not model: + 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_numer") + if not serial: + return "N/A" + return serial From 52d87fd5c557c1016085f1ed657d735e50d6efe6 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Fri, 7 May 2021 16:00:39 +0800 Subject: [PATCH 05/31] Fix error path for get serial_num --- device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py index dce2946d459e..727b6d6a715c 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py @@ -242,7 +242,7 @@ def get_serial(self): Returns: string: Serial number of device """ - serial = self.__read_txt_file(self.cpld_path + "psu_serial_numer") + serial = self.__read_txt_file(self.cpld_path + "psu_serial_number") if not serial: return "N/A" return serial From a81b70962eccc07cfd15d11b8ccd1152652c61bc Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Mon, 10 May 2021 16:16:40 +0800 Subject: [PATCH 06/31] Add import sys to chassis.py --- .../accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py | 1 + 1 file changed, 1 insertion(+) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py index 3e38c14680bf..abf15ff151d2 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py @@ -7,6 +7,7 @@ ############################################################################# import os +import sys try: from sonic_platform_base.chassis_base import ChassisBase From 5bcfd9a5134d8f445ac56327a12728ae16341068 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Wed, 19 May 2021 10:18:15 +0800 Subject: [PATCH 07/31] Fix port range error for port-30 --- device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py index 687437425d82..084b46ee7ea3 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py @@ -207,7 +207,7 @@ def __init__(self, sfp_index=0): self.index = sfp_index self.port_num = self.index + 1 - cpld_idx = 0 if self.port_num >= 30 else 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) From bb1dc4a0380d62154d655b0ab6e666b8eced1e94 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Fri, 21 May 2021 16:35:57 +0800 Subject: [PATCH 08/31] Fix to use QSFP_CONTROL_OFFSET for dom_control_raw --- .../accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py index 084b46ee7ea3..9e7672fc414b 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py @@ -1043,7 +1043,7 @@ def get_power_set(self): return False dom_control_raw = self.__read_eeprom_specific_bytes( - QSFP_POWEROVERRIDE_OFFSET, + 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( @@ -1069,7 +1069,7 @@ def get_power_override(self): return False dom_control_raw = self.__read_eeprom_specific_bytes( - QSFP_POWEROVERRIDE_OFFSET, + 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( From 0fc6abde4574fd942a2cf552688c980ca71278c8 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Fri, 28 May 2021 10:57:51 +0800 Subject: [PATCH 09/31] Fix write api in sfp.py --- device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py index 9e7672fc414b..fda6d7e4dbbf 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py @@ -277,7 +277,7 @@ def __read_txt_file(self, file_path): def __write_txt_file(self, file_path, value): try: - with open(file_path, 'w', buffering=0) as fd: + with open(file_path, 'w') as fd: fd.write(str(value)) except Exception: return False From 7e5b86aba39ebc2b6148f7348a516153f5dca843 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Fri, 11 Jun 2021 14:12:06 +0800 Subject: [PATCH 10/31] Add fan get_name() and get_status() --- .../sonic_platform/fan.py | 68 +++++++++++++++++- .../sonic_platform/psu.py | 6 +- .../sonic_platform/sfp.py | 70 ++++++++++++------- 3 files changed, 113 insertions(+), 31 deletions(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py index 91af071784ac..5e5431577508 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py @@ -37,6 +37,9 @@ }, } +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""" @@ -87,7 +90,7 @@ def get_direction(self): """ if not self.is_psu_fan: val = self.__read_txt_file( - CPLD_I2C_PATH + str(self.fan_tray_index) + "_direction") + CPLD_I2C_PATH + str(self.fan_tray_index+1) + "_direction") direction = self.FAN_DIRECTION_EXHAUST if ( val == "0") else self.FAN_DIRECTION_INTAKE else: @@ -169,6 +172,31 @@ def set_status_led(self, color): """ 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) + def get_presence(self): """ Retrieves the presence of the PSU @@ -182,3 +210,41 @@ def get_presence(self): val = self.__read_txt_file( CPLD_I2C_PATH + str(self.fan_tray_index + 1) + "_present") return int(val, 10) + + 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" diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py index 727b6d6a715c..0b3905d326e1 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py @@ -73,7 +73,7 @@ def __read_txt_file(self, file_path): return fd.read().strip() except IOError: pass - return "" + return None def get_voltage(self): """ @@ -232,7 +232,7 @@ def get_model(self): string: Model/part number of device """ model = self.__read_txt_file(self.cpld_path + "psu_model_name") - if not model: + if model is None: return "N/A" return model @@ -243,6 +243,6 @@ def get_serial(self): string: Serial number of device """ serial = self.__read_txt_file(self.cpld_path + "psu_serial_number") - if not serial: + if serial is None: return "N/A" return serial diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py index fda6d7e4dbbf..d15702f55461 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py @@ -889,11 +889,13 @@ def get_rx_los(self): 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 <= 48 or self.port_num >=57: - cpld_val = self.__read_txt_file( + rx_los = self.__read_txt_file( self.cpld_path + "module_rx_los_" + str(self.port_num)) - rx_los = (int(cpld_val, 10) == 1) + 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: @@ -911,21 +913,28 @@ def get_rx_los(self): 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 if self.port_num <= 48 or self.port_num >=57: - cpld_val = self.__read_txt_file( + tx_fault = self.__read_txt_file( self.cpld_path + "module_tx_fault_" + str(self.port_num)) - tx_fault = (int(cpld_val, 10) == 1) + 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: @@ -943,15 +952,19 @@ def get_tx_fault(self): 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 <= 48 or self.port_num >=57: tx_disable = False @@ -968,14 +981,20 @@ def get_tx_disable(self): 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] - return tx_disable else: tx_disable_list = [] sfpd_obj = sff8436Dom() if sfpd_obj is None: - return False + return [False] dom_control_raw = self.__read_eeprom_specific_bytes( QSFP_CONTROL_OFFSET, @@ -991,8 +1010,9 @@ def get_tx_disable(self): '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): """ @@ -1003,18 +1023,14 @@ def get_tx_disable_channel(self): As an example, a returned value of 0x5 indicates that channel 0 and channel 2 have been disabled. """ - if self.port_num <= 48 or self.port_num >=57: - # 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): """ From bc267e4a670a2fe72b6f211c9cc76b577c3db727 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Fri, 11 Jun 2021 14:31:18 +0800 Subject: [PATCH 11/31] Add retrun fan_name to fan.py --- device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py index 5e5431577508..11f1c599e698 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py @@ -197,6 +197,8 @@ def get_name(self): 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 From 44e58c3c7a5ccb147dcab6be250a829278de3a51 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Fri, 11 Jun 2021 15:32:13 +0800 Subject: [PATCH 12/31] Modify get_status_led() in psu.py --- .../sonic_platform/psu.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py index 0b3905d326e1..eaa98c13cb0f 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py @@ -140,14 +140,13 @@ def get_status_led(self): A string, one of the predefined STATUS_LED_COLOR_* strings above """ status=self.get_status() - if not status: - return self.STATUS_LED_COLOR_RED - - if status==1: - return self.STATUS_LED_COLOR_GREEN - else: - return self.STATUS_LED_COLOR_RED + 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): """ From 314f0931e35dd4ad749494b34f931ec803c4f2cd Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Mon, 21 Jun 2021 17:42:56 +0800 Subject: [PATCH 13/31] Fix set_lpmode() in sfp.py --- .../x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py | 2 +- device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py index abf15ff151d2..8722d8830ee5 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py @@ -135,7 +135,7 @@ def get_model(self): """ return self._eeprom.get_pn() - def get_serial_number(self): + def get_serial(self): """ Retrieves the hardware serial number for the chassis Returns: diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py index d15702f55461..c26b77e1dc9e 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py @@ -1297,7 +1297,7 @@ def set_lpmode(self, lpmode): if self.port_num <= 48 or self.port_num >=57: return False # SFP doesn't support this feature - if lpmode is True: + if lpmode: return self.set_power_override(True, True) else: return self.set_power_override(True, False) From 22d32d82fa441b337d08bcb0940a9eb3a1b59327 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Thu, 15 Jul 2021 16:00:20 +0800 Subject: [PATCH 14/31] Support show system-health --- .../sonic_platform/chassis.py | 56 ++++++++++++++++++- .../sonic_platform/component.py | 53 ++++++++++++++++++ .../sonic_platform/eeprom.py | 2 +- .../sonic_platform/fan.py | 29 +++++++++- .../sonic_platform/fan_drawer.py | 46 ++++++++++++++- .../sonic_platform/psu.py | 17 ++++++ .../sonic_platform/sfp.py | 17 ++++++ .../sonic_platform/thermal.py | 47 ++++++++++++++-- 8 files changed, 255 insertions(+), 12 deletions(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py index 8722d8830ee5..a98cd493a99d 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py @@ -28,6 +28,13 @@ REBOOT_CAUSE_FILE = "reboot-cause.txt" PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" HOST_CHK_CMD = "docker > /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", + "2" : "STATUS_LED_COLOR_AMBER", + "5" : "STATUS_LED_COLOR_GREEN_BLINK" +} class Chassis(ChassisBase): @@ -94,7 +101,15 @@ def __read_txt_file(self, file_path): 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 @@ -213,4 +228,41 @@ def get_sfp(self, index): except IndexError: sys.stderr.write("SFP index {} out of range (1-{})\n".format( index, len(self._sfp_list))) - return sfp \ No newline at end of file + 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) + diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/component.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/component.py index a588e343b56c..75c2d3b918d4 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/component.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/component.py @@ -106,3 +106,56 @@ def install_firmware(self, image_path): 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 + diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py index 5ade5bf0cdf0..082fc28e78f2 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py @@ -26,7 +26,7 @@ def __init__(self): 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() diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py index 11f1c599e698..5e0707442603 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py @@ -13,6 +13,7 @@ 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 = { @@ -133,7 +134,7 @@ def get_target_speed(self): 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): """ @@ -142,7 +143,7 @@ def get_speed_tolerance(self): 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): """ @@ -211,7 +212,7 @@ def get_presence(self): val = self.__read_txt_file( CPLD_I2C_PATH + str(self.fan_tray_index + 1) + "_present") - return int(val, 10) + return int(val, 10)==1 def get_status(self): """ @@ -250,3 +251,25 @@ def get_serial(self): 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_tray_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 + diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan_drawer.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan_drawer.py index 94357d5d82ba..17d339ee55f6 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan_drawer.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan_drawer.py @@ -35,7 +35,51 @@ def get_name(self): Returns: string: The name of the device """ - return "FanTray{}".format(self.fantrayindex) + 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): """ diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py index eaa98c13cb0f..600c78f7a32c 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/psu.py @@ -245,3 +245,20 @@ def get_serial(self): 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 diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py index c26b77e1dc9e..7e4c55718734 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py @@ -1391,3 +1391,20 @@ def get_status(self): A boolean value, True if device is operating properly, False if not """ return self.get_presence() and self.get_transceiver_bulk_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.port_num + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/thermal.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/thermal.py index 5dce996f80ad..6524d68d2d8f 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/thermal.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/thermal.py @@ -16,7 +16,7 @@ raise ImportError(str(e) + "- required module not found") PSU_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/" -PSU_I2C_MAPPING = { +PSU_HWMON_I2C_MAPPING = { 0: { "bus": 17, "addr": "59" @@ -52,8 +52,8 @@ def __init__(self, thermal_index=0, is_psu=False, psu_index=0): self.psu_index = psu_index if self.is_psu: - psu_i2c_bus = PSU_I2C_MAPPING[psu_index]["bus"] - psu_i2c_addr = PSU_I2C_MAPPING[psu_index]["addr"] + 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"] @@ -145,8 +145,11 @@ def set_high_threshold(self, temperature): Returns: A boolean, True if threshold is set successfully, False if not """ - #Not supported - return False + temp_file = "temp{}_max".format(self.ss_index) + temperature = temperature *1000 + self.__set_threshold(temp_file, temperature) + + return True def get_name(self): """ @@ -193,3 +196,37 @@ def get_status(self): 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 -1 + + def is_replaceable(self): + """ + Retrieves whether thermal module is replaceable + Returns: + A boolean value, True if replaceable, False if not + """ + return False From fac784285b01bfcef5bfe13182cd4dc710035586 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Thu, 15 Jul 2021 16:01:37 +0800 Subject: [PATCH 15/31] Remove not need import os --- device/accton/x86_64-accton_as7326_56x-r0/plugins/eeprom.py | 1 - 1 file changed, 1 deletion(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as7326_56x-r0/plugins/eeprom.py index 78da4145c21e..65dbe400864b 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/plugins/eeprom.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/plugins/eeprom.py @@ -5,7 +5,6 @@ import time import optparse import warnings - import os import sys from sonic_eeprom import eeprom_base from sonic_eeprom import eeprom_tlvinfo From 81d57db81df4dad3f0ac271b68648f5ff987f8bc Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Thu, 15 Jul 2021 16:34:37 +0800 Subject: [PATCH 16/31] Remvoe not needed code and support python3 for util --- .../as7326-56x/utils/accton_as7326_util.py | 301 +++--------------- 1 file changed, 40 insertions(+), 261 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/utils/accton_as7326_util.py b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/utils/accton_as7326_util.py index 6983ed4a210c..7a63f73d7843 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as7326-56x/utils/accton_as7326_util.py +++ b/platform/broadcom/sonic-platform-modules-accton/as7326-56x/utils/accton_as7326_util.py @@ -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 . -# -# -# 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,12 +25,8 @@ 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 commands +import subprocess import getopt import sys import logging @@ -62,8 +49,8 @@ if DEBUG == True: - print sys.argv[0] - print 'ARGV :', sys.argv[1:] + print(sys.argv[0]) + print('ARGV :', sys.argv[1:]) def main(): @@ -79,9 +66,9 @@ def main(): 'force', ]) if DEBUG == True: - print options - print args - print len(sys.argv) + print(options) + print(args) + print(len(sys.argv)) for opt, arg in options: if opt in ('-h', '--help'): @@ -101,52 +88,28 @@ def main(): 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 + do_uninstall() else: show_help() - - 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 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 - status, output = commands.getstatusoutput(cmd) + status, output = subprocess.getstatusoutput(cmd) cmd = "i2cset -y 0 0x%x 0x12 0x02" % addr - status, output = commands.getstatusoutput(cmd) + status, output = subprocess.getstatusoutput(cmd) return status def ir3570_check(): cmd = "i2cdump -y 0 0x42 s 0x9a" try: - status, output = commands.getstatusoutput(cmd) + status, output = subprocess.getstatusoutput(cmd) lines = output.split('\n') hn = re.findall(r'\w+', lines[-1]) version = int(hn[1], 16) @@ -155,24 +118,19 @@ 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 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 + print("[ROY]"+txt) return def log_os_system(cmd, show): logging.info('Run :'+cmd) - status, output = commands.getstatusoutput(cmd) + status, output = subprocess.getstatusoutput(cmd) my_log (cmd +"with result:" + str(status)) my_log (" output:"+output) if status: @@ -211,6 +169,8 @@ def driver_install(): if status: if FORCE == 0: return status + print("Done driver_install") + return 0 def driver_uninstall(): @@ -228,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'], @@ -242,7 +198,7 @@ def driver_uninstall(): '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, @@ -302,7 +258,7 @@ def i2c_order_check(): def eeprom_check(): cmd = "i2cget -y -f 0 0x56" - status, output = commands.getstatusoutput(cmd) + status, output = subprocess.getstatusoutput(cmd) return status def device_install(): @@ -319,7 +275,7 @@ def device_install(): status, output = log_os_system(mknod2[i], 1) if status: - print output + print(output) if FORCE == 0: return status else: @@ -330,7 +286,7 @@ def device_install(): status, output = log_os_system(mknod[i], 1) if status: - print output + print(output) if FORCE == 0: return status @@ -355,9 +311,10 @@ def device_install(): else: status, output =log_os_system("echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1) if status: - print output + print(output) if FORCE == 0: return status + print("Done device_install") return def device_uninstall(): @@ -373,7 +330,7 @@ def device_uninstall(): target = "/sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/delete_device" status, output =log_os_system("echo 0x50 > "+ target, 1) if status: - print output + print(output) if FORCE == 0: return status @@ -389,7 +346,7 @@ def device_uninstall(): temp[-1] = temp[-1].replace('new_device', 'delete_device') status, output = log_os_system(" ".join(temp), 1) if status: - print output + print(output) if FORCE == 0: return status @@ -406,7 +363,7 @@ def device_uninstall(): temp[-1] = temp[-1].replace('new_device', 'delete_device') status, output = log_os_system(" ".join(temp), 1) if status: - print output + print(output) if FORCE == 0: return status @@ -430,10 +387,10 @@ 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)) else: @@ -458,46 +415,46 @@ def do_sonic_platform_clean(): return def do_install(): - print "Checking system...." + print("Checking system....") if driver_check() == False: - print "No driver, installing...." + print("No driver, installing....") status = driver_install() if status: if FORCE == 0: return status else: - print PROJECT_NAME.upper()+" drivers detected...." + print(PROJECT_NAME.upper()+" drivers detected....") ir3570_check() if not device_exist(): - print "No device, installing...." + print("No device, installing....") status = device_install() if status: 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...." + 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...." + print("Removing device....") status = device_uninstall() if status: if FORCE == 0: 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...." + print("Removing installed driver....") status = driver_uninstall() if status: if FORCE == 0: @@ -507,184 +464,6 @@ def do_uninstall(): return -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(ALL_DEVICE[i].keys(), key=get_value): - print " "+j+":", - 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+" ", - else: - print func+"="+"X"+" ", - print - print("----------------------------------------------------------------") - - print - return def device_exist(): ret1, log = log_os_system("ls "+i2c_prefix+"*0070", 0) From a47d0837f984c4a7b1e71eb5a89d11a68942d1d7 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Mon, 9 Aug 2021 16:27:02 +0800 Subject: [PATCH 17/31] Add system-health needed json file --- .../pmon_daemon_control.json | 2 +- .../system_health_monitoring_config.json | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 device/accton/x86_64-accton_as7326_56x-r0/system_health_monitoring_config.json diff --git a/device/accton/x86_64-accton_as7326_56x-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as7326_56x-r0/pmon_daemon_control.json index 584a14b9d942..a3b204e20d8d 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/pmon_daemon_control.json +++ b/device/accton/x86_64-accton_as7326_56x-r0/pmon_daemon_control.json @@ -1,5 +1,5 @@ { "skip_ledd": true, - "skip_thermalctld": true + "skip_pcied": true } diff --git a/device/accton/x86_64-accton_as7326_56x-r0/system_health_monitoring_config.json b/device/accton/x86_64-accton_as7326_56x-r0/system_health_monitoring_config.json new file mode 100644 index 000000000000..5f3b3b07e73f --- /dev/null +++ b/device/accton/x86_64-accton_as7326_56x-r0/system_health_monitoring_config.json @@ -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" + } +} From 2b0901f9ffc3c45eba46b51a33a65c476ec8b52a Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Fri, 20 Aug 2021 17:31:48 +0800 Subject: [PATCH 18/31] Fix booting to green_blink for health-monitor --- .../x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py | 2 +- .../system_health_monitoring_config.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py index a98cd493a99d..bc123920e427 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py @@ -32,7 +32,7 @@ SYSLED_MODES = { "0" : "STATUS_LED_COLOR_OFF", "1" : "STATUS_LED_COLOR_GREEN", - "2" : "STATUS_LED_COLOR_AMBER", + "3" : "STATUS_LED_COLOR_RED", "5" : "STATUS_LED_COLOR_GREEN_BLINK" } diff --git a/device/accton/x86_64-accton_as7326_56x-r0/system_health_monitoring_config.json b/device/accton/x86_64-accton_as7326_56x-r0/system_health_monitoring_config.json index 5f3b3b07e73f..5cd35e93cdbf 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/system_health_monitoring_config.json +++ b/device/accton/x86_64-accton_as7326_56x-r0/system_health_monitoring_config.json @@ -8,8 +8,8 @@ "user_defined_checkers": [], "polling_interval": 60, "led_color": { - "fault": "STATUS_LED_COLOR_AMBER", + "fault": "STATUS_LED_COLOR_RED", "normal": "STATUS_LED_COLOR_GREEN", - "booting": "STATUS_LED_COLOR_GREEN" + "booting": "STATUS_LED_COLOR_GREEN_BLINK" } } From 7534afd44600ac5b1b04fef864c33bfd1c926114 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Tue, 31 Aug 2021 13:55:48 +0800 Subject: [PATCH 19/31] Fix qsfp threshold offset --- .../x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py index 7e4c55718734..cd547ef9b4ff 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py @@ -81,6 +81,7 @@ QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1 QSFP_POWEROVERRIDE_OFFSET = 93 QSFP_POWEROVERRIDE_WIDTH = 1 +QSFP_PAGE03_OFFSET = 384 QSFP_MODULE_THRESHOLD_OFFSET = 128 QSFP_MODULE_THRESHOLD_WIDTH = 24 QSFP_CHANNEL_THRESHOLD_OFFSET = 176 @@ -789,11 +790,13 @@ def get_transceiver_threshold_info(self): if not self.get_presence() or not sfpd_obj: return {} - + + offset = QSFP_PAGE03_OFFSET + 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 + offset + QSFP_MODULE_THRESHOLD_OFFSET, QSFP_MODULE_THRESHOLD_WIDTH ) if self.get_presence() and sfpd_obj else None if dom_thres_raw: @@ -827,7 +830,7 @@ def get_transceiver_threshold_info(self): 'VccLowWarning']['value'] dom_thres_raw = self.__read_eeprom_specific_bytes( - QSFP_CHANNEL_THRESHOLD_OFFSET, QSFP_CHANNEL_THRESHOLD_WIDTH + offset + 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) From 85c2529761a9d060b4369c8353431d45770d96a6 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Thu, 16 Sep 2021 15:48:22 +0800 Subject: [PATCH 20/31] Modify get_name to use product_name --- .../x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py | 2 +- .../x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py index bc123920e427..c6309e368646 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py @@ -116,7 +116,7 @@ def get_name(self): Returns: string: The name of the device """ - return self.hwsku + return self._eeprom.get_product_name() def get_presence(self): """ diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py index 082fc28e78f2..292f297f399a 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py @@ -129,9 +129,12 @@ def get_eeprom(self): 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) From 239c6b5d6e5e66bc3fc2696ada0b641d3f87b52a Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Fri, 17 Sep 2021 15:54:55 +0800 Subject: [PATCH 21/31] Fix get_position_in_parent in fan and thermal --- device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py | 2 +- .../x86_64-accton_as7326_56x-r0/sonic_platform/thermal.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py index 5e0707442603..05dbd66e81ef 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py @@ -262,7 +262,7 @@ def get_position_in_parent(self): integer: The 1-based relative physical position in parent device or -1 if cannot determine the position """ - return (self.fan_tray_index+1) \ + return (self.fan_index+1) \ if not self.is_psu_fan else (self.psu_index+1) def is_replaceable(self): diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/thermal.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/thermal.py index 6524d68d2d8f..10256e941050 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/thermal.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/thermal.py @@ -221,7 +221,7 @@ def get_position_in_parent(self): Returns: integer: The 1-based relative physical position in parent device or -1 if cannot determine the position """ - return -1 + return self.index+1 def is_replaceable(self): """ From b868e04613447739ea4763aa9c42d401d3f0c68f Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Fri, 15 Oct 2021 17:19:17 +0800 Subject: [PATCH 22/31] Correct the wait and timeout mechanism for better CPU usage --- .../sonic_platform/chassis.py | 8 ++-- .../sonic_platform/event.py | 45 +++++++++++-------- .../sonic_platform/sfp.py | 2 +- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py index c6309e368646..c7a6d6ccf64c 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/chassis.py @@ -27,7 +27,7 @@ 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/accton_as7326_56x_led::diag/brightness" SYSLED_MODES = { "0" : "STATUS_LED_COLOR_OFF", @@ -57,6 +57,7 @@ def __initialize_sfp(self): 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): @@ -202,10 +203,7 @@ def get_change_event(self, timeout=0): # 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): """ diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/event.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/event.py index b0f9f1c15d67..7ce2598732e2 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/event.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/event.py @@ -4,6 +4,7 @@ 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 ''' @@ -11,30 +12,38 @@ class SfpEvent: def __init__(self, sfp_list): 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)): @@ -45,9 +54,7 @@ def get_sfp_event(self, timeout=2000): # 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 diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py index cd547ef9b4ff..c1561c37f526 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/sfp.py @@ -137,7 +137,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_as7326_56x-r0" HWSKU = "Accton-AS7326-56X" From 104e55977f057a3a28b87f35cf7b476dba9c4a42 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Fri, 15 Apr 2022 16:13:31 +0800 Subject: [PATCH 23/31] Fix read cpld_version from hex to dec. --- .../x86_64-accton_as7326_56x-r0/sonic_platform/component.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/component.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/component.py index 75c2d3b918d4..e6c465472a5f 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/component.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/component.py @@ -59,7 +59,7 @@ def __get_cpld_version(self): 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)) + int(cpld_version_raw, 10)) except Exception as e: cpld_version[cpld_name] = 'None' From 5928195f6efa2865d1cb3dc16ead2b78d5b7dca1 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Tue, 10 May 2022 16:30:49 +0800 Subject: [PATCH 24/31] Fix wrong system eeprom data of 0x25 field --- .../x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py index 292f297f399a..90ebbc73a0a1 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/eeprom.py @@ -20,7 +20,6 @@ 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" @@ -38,7 +37,7 @@ def __parse_output(self, decode_output): for line in lines: try: - match = re.search('(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', + match = re.search('(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)(.+)', line) if match is not None: idx = match.group(1) From ca3c39adffc2f8a9b5ee716a04d80d9ebe15e31a Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Thu, 14 Jul 2022 17:57:12 +0800 Subject: [PATCH 25/31] Add pcie.py to fix show pcieinfo fail log --- .../sonic_platform/pcie.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/pcie.py diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/pcie.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/pcie.py new file mode 100644 index 000000000000..0d972249af09 --- /dev/null +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/pcie.py @@ -0,0 +1,23 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# Base PCIe class +############################################################################# + +import logging + + +try: + from sonic_platform.component import Component + from sonic_platform_base.sonic_pcie.pcie_common import PcieUtil +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Pcie(PcieUtil): + """Edgecore Platform-specific PCIe class""" + + def __init__(self, platform_path): + PcieUtil.__init__(self, platform_path) From c74a2c9ccf0f45d9c92792fd3cf89fbd9ccb5797 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Thu, 14 Jul 2022 18:19:44 +0800 Subject: [PATCH 26/31] Fix LGM alert --- .../accton/x86_64-accton_as7326_56x-r0/sonic_platform/pcie.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/pcie.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/pcie.py index 0d972249af09..e4da32adf9f8 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/pcie.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/pcie.py @@ -6,11 +6,7 @@ # Base PCIe class ############################################################################# -import logging - - try: - from sonic_platform.component import Component from sonic_platform_base.sonic_pcie.pcie_common import PcieUtil except ImportError as e: raise ImportError(str(e) + "- required module not found") From ed97225dcd571c1dd24d8c7ee7b950c90961c786 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Fri, 22 Jul 2022 15:11:58 +0800 Subject: [PATCH 27/31] Add pcie.yaml file --- .../x86_64-accton_as7326_56x-r0/pcie.yaml | 459 ++++++++++++++++++ 1 file changed, 459 insertions(+) create mode 100644 device/accton/x86_64-accton_as7326_56x-r0/pcie.yaml diff --git a/device/accton/x86_64-accton_as7326_56x-r0/pcie.yaml b/device/accton/x86_64-accton_as7326_56x-r0/pcie.yaml new file mode 100644 index 000000000000..af10930e3e0c --- /dev/null +++ b/device/accton/x86_64-accton_as7326_56x-r0/pcie.yaml @@ -0,0 +1,459 @@ +- bus: '00' + dev: '00' + fn: '0' + id: 6f00 + name: 'Host bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DMI2 + (rev 03)' +- bus: '00' + dev: '01' + fn: '0' + id: 6f02 + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 1 (rev 03)' +- bus: '00' + dev: '01' + fn: '1' + id: 6f03 + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 1 (rev 03)' +- bus: '00' + dev: '02' + fn: '0' + id: 6f04 + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 2 (rev 03)' +- bus: '00' + dev: '02' + fn: '1' + id: 6f05 + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 2 (rev 03)' +- bus: '00' + dev: '02' + fn: '2' + id: 6f06 + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 2 (rev 03)' +- bus: '00' + dev: '02' + fn: '3' + id: 6f07 + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 2 (rev 03)' +- bus: '00' + dev: '03' + fn: '0' + id: 6f08 + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 3 (rev 03)' +- bus: '00' + dev: '03' + fn: '1' + id: 6f09 + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 3 (rev 03)' +- bus: '00' + dev: '03' + fn: '2' + id: 6f0a + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 3 (rev 03)' +- bus: '00' + dev: '03' + fn: '3' + id: 6f0b + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 3 (rev 03)' +- bus: '00' + dev: '05' + fn: '0' + id: 6f28 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Map/VTd_Misc/System Management (rev 03)' +- bus: '00' + dev: '05' + fn: '1' + id: 6f29 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D IIO Hot Plug (rev 03)' +- bus: '00' + dev: '05' + fn: '2' + id: 6f2a + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D IIO RAS/Control Status/Global Errors (rev 03)' +- bus: '00' + dev: '05' + fn: '4' + id: 6f2c + name: 'PIC: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D I/O APIC (rev + 03)' +- bus: '00' + dev: '14' + fn: '0' + id: 8c31 + name: 'USB controller: Intel Corporation 8 Series/C220 Series Chipset Family USB + xHCI (rev 05)' +- bus: '00' + dev: 1c + fn: '0' + id: 8c10 + name: 'PCI bridge: Intel Corporation 8 Series/C220 Series Chipset Family PCI Express + Root Port #1 (rev d5)' +- bus: '00' + dev: 1c + fn: '1' + id: 8c12 + name: 'PCI bridge: Intel Corporation 8 Series/C220 Series Chipset Family PCI Express + Root Port #2 (rev d5)' +- bus: '00' + dev: 1d + fn: '0' + id: 8c26 + name: 'USB controller: Intel Corporation 8 Series/C220 Series Chipset Family USB + EHCI #1 (rev 05)' +- bus: '00' + dev: 1f + fn: '0' + id: 8c54 + name: 'ISA bridge: Intel Corporation C224 Series Chipset Family Server Standard + SKU LPC Controller (rev 05)' +- bus: '00' + dev: 1f + fn: '2' + id: 8c02 + name: 'SATA controller: Intel Corporation 8 Series/C220 Series Chipset Family 6-port + SATA Controller 1 [AHCI mode] (rev 05)' +- bus: '00' + dev: 1f + fn: '3' + id: 8c22 + name: 'SMBus: Intel Corporation 8 Series/C220 Series Chipset Family SMBus Controller + (rev 05)' +- bus: '00' + dev: 1f + fn: '6' + id: 8c24 + name: 'Signal processing controller: Intel Corporation 8 Series Chipset Family Thermal + Management Controller (rev 05)' +- bus: '03' + dev: '00' + fn: '0' + id: 6f50 + name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology + Register DMA Channel 0' +- bus: '03' + dev: '00' + fn: '1' + id: 6f51 + name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology + Register DMA Channel 1' +- bus: '03' + dev: '00' + fn: '2' + id: 6f52 + name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology + Register DMA Channel 2' +- bus: '03' + dev: '00' + fn: '3' + id: 6f53 + name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology + Register DMA Channel 3' +- bus: '05' + dev: '00' + fn: '0' + id: 15ab + name: 'Ethernet controller: Intel Corporation Ethernet Connection X552 10 GbE Backplane' +- bus: '05' + dev: '00' + fn: '1' + id: 15ab + name: 'Ethernet controller: Intel Corporation Ethernet Connection X552 10 GbE Backplane' +- bus: '07' + dev: '00' + fn: '0' + id: b873 + name: 'Ethernet controller: Broadcom Inc. and subsidiaries Device b873 (rev 01)' +- bus: 0b + dev: '00' + fn: '0' + id: 165f + name: 'Ethernet controller: Broadcom Inc. and subsidiaries NetXtreme BCM5720 2-port + Gigabit Ethernet PCIe' +- bus: ff + dev: 0b + fn: '0' + id: 6f81 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D R3 QPI Link 0/1 (rev 03)' +- bus: ff + dev: 0b + fn: '1' + id: 6f36 + name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D R3 QPI Link 0/1 (rev 03)' +- bus: ff + dev: 0b + fn: '2' + id: 6f37 + name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D R3 QPI Link 0/1 (rev 03)' +- bus: ff + dev: 0b + fn: '3' + id: 6f76 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D R3 QPI Link Debug (rev 03)' +- bus: ff + dev: 0c + fn: '0' + id: 6fe0 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0c + fn: '1' + id: 6fe1 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0c + fn: '2' + id: 6fe2 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0c + fn: '3' + id: 6fe3 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0f + fn: '0' + id: 6ff8 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0f + fn: '4' + id: 6ffc + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0f + fn: '5' + id: 6ffd + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0f + fn: '6' + id: 6ffe + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: '10' + fn: '0' + id: 6f1d + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D R2PCIe Agent (rev 03)' +- bus: ff + dev: '10' + fn: '1' + id: 6f34 + name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D R2PCIe Agent (rev 03)' +- bus: ff + dev: '10' + fn: '5' + id: 6f1e + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Ubox (rev 03)' +- bus: ff + dev: '10' + fn: '6' + id: 6f7d + name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Ubox (rev 03)' +- bus: ff + dev: '10' + fn: '7' + id: 6f1f + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Ubox (rev 03)' +- bus: ff + dev: '12' + fn: '0' + id: 6fa0 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Home Agent 0 (rev 03)' +- bus: ff + dev: '12' + fn: '1' + id: 6f30 + name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Home Agent 0 (rev 03)' +- bus: ff + dev: '13' + fn: '0' + id: 6fa8 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Target Address/Thermal/RAS (rev 03)' +- bus: ff + dev: '13' + fn: '1' + id: 6f71 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Target Address/Thermal/RAS (rev 03)' +- bus: ff + dev: '13' + fn: '2' + id: 6faa + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel Target Address Decoder (rev 03)' +- bus: ff + dev: '13' + fn: '3' + id: 6fab + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel Target Address Decoder (rev 03)' +- bus: ff + dev: '13' + fn: '4' + id: 6fac + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel Target Address Decoder (rev 03)' +- bus: ff + dev: '13' + fn: '5' + id: 6fad + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel Target Address Decoder (rev 03)' +- bus: ff + dev: '13' + fn: '6' + id: 6fae + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D DDRIO Channel 0/1 Broadcast (rev 03)' +- bus: ff + dev: '13' + fn: '7' + id: 6faf + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D DDRIO Global Broadcast (rev 03)' +- bus: ff + dev: '14' + fn: '0' + id: 6fb0 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 0 Thermal Control (rev 03)' +- bus: ff + dev: '14' + fn: '1' + id: 6fb1 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 1 Thermal Control (rev 03)' +- bus: ff + dev: '14' + fn: '2' + id: 6fb2 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 0 Error (rev 03)' +- bus: ff + dev: '14' + fn: '3' + id: 6fb3 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 1 Error (rev 03)' +- bus: ff + dev: '14' + fn: '4' + id: 6fbc + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D DDRIO Channel 0/1 Interface (rev 03)' +- bus: ff + dev: '14' + fn: '5' + id: 6fbd + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D DDRIO Channel 0/1 Interface (rev 03)' +- bus: ff + dev: '14' + fn: '6' + id: 6fbe + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D DDRIO Channel 0/1 Interface (rev 03)' +- bus: ff + dev: '14' + fn: '7' + id: 6fbf + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D DDRIO Channel 0/1 Interface (rev 03)' +- bus: ff + dev: '15' + fn: '0' + id: 6fb4 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 2 Thermal Control (rev 03)' +- bus: ff + dev: '15' + fn: '1' + id: 6fb5 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 3 Thermal Control (rev 03)' +- bus: ff + dev: '15' + fn: '2' + id: 6fb6 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 2 Error (rev 03)' +- bus: ff + dev: '15' + fn: '3' + id: 6fb7 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 3 Error (rev 03)' +- bus: ff + dev: 1e + fn: '0' + id: 6f98 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' +- bus: ff + dev: 1e + fn: '1' + id: 6f99 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' +- bus: ff + dev: 1e + fn: '2' + id: 6f9a + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' +- bus: ff + dev: 1e + fn: '3' + id: 6fc0 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' +- bus: ff + dev: 1e + fn: '4' + id: 6f9c + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' +- bus: ff + dev: 1f + fn: '0' + id: 6f88 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' +- bus: ff + dev: 1f + fn: '2' + id: 6f8a + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' From 3d506e8c9d8396e2b36573f943ff4dcff13609d1 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Mon, 8 Aug 2022 14:19:53 +0800 Subject: [PATCH 28/31] Remove "skip_pcied": true --- .../x86_64-accton_as7326_56x-r0/pmon_daemon_control.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as7326_56x-r0/pmon_daemon_control.json index a3b204e20d8d..44bad6494229 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/pmon_daemon_control.json +++ b/device/accton/x86_64-accton_as7326_56x-r0/pmon_daemon_control.json @@ -1,5 +1,4 @@ { - "skip_ledd": true, - "skip_pcied": true + "skip_ledd": true } From cda162f92456a10ecbfd664fef536b1740811da2 Mon Sep 17 00:00:00 2001 From: jostar-yang Date: Tue, 4 Oct 2022 10:43:10 +0800 Subject: [PATCH 29/31] Add set_status_led to fan_drawer.py --- .../sonic_platform/fan_drawer.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan_drawer.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan_drawer.py index 17d339ee55f6..260a052dbc9d 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan_drawer.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan_drawer.py @@ -81,6 +81,17 @@ def get_position_in_parent(self): """ return (self.fantrayindex+1) + 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 is_replaceable(self): """ Indicate whether this device is replaceable. From 0b5a6a981321aaa5de9fc23c2426632646014ecd Mon Sep 17 00:00:00 2001 From: jostar-yang Date: Fri, 14 Oct 2022 14:56:57 +0800 Subject: [PATCH 30/31] Add check power_good for get psu-fan status --- .../accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py index 05dbd66e81ef..1a324176f8f3 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py @@ -221,6 +221,11 @@ def get_status(self): A boolean value, True if device is operating properly, False if not """ if self.is_psu_fan: + psu_path = "{}{}".format(self.cpld_path, 'psu_power_good') + val = self.__read_txt_file(psu_path) + if val is None or int(val, 10)==0: + return False + psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_fault') val=self.__read_txt_file(psu_fan_path) if val is not None: From 14a0d726c76a49b4e7ed3ce8a1454d6e469d4e37 Mon Sep 17 00:00:00 2001 From: jostar-yang Date: Mon, 17 Oct 2022 17:36:56 +0800 Subject: [PATCH 31/31] Fix to show psu-fan dir when no power --- .../accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py index 1a324176f8f3..737cca995612 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/sonic_platform/fan.py @@ -89,6 +89,9 @@ def get_direction(self): A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST depending on fan direction """ + if self.get_status() == False: + return None + if not self.is_psu_fan: val = self.__read_txt_file( CPLD_I2C_PATH + str(self.fan_tray_index+1) + "_direction") @@ -179,7 +182,7 @@ def get_status_led(self): Returns: A string, one of the predefined STATUS_LED_COLOR_* strings above """ - status=self.get_presence() + status=self.get_status() if status is None: return self.STATUS_LED_COLOR_OFF