Edgecore 4630/5835/7326/7816 API2.0 platform support (#10053)

* Initial pass of EdgeCore platform changes.

* Remove libevent dependency from lldpd.

* Remove python2 dependencies python3.7 force from platform install script.

* Include usbmount support changes.

* Add missing 4630 install file.

* Update a few file permissions.  Add umask line to Makefile.  Specify python3.9 in install script.

* Misc platform updates:
- Add missing fan drawer component to sonic_platform
- Remove kernel version specification from Makefile
- Update to 4630 utility

* - Fix file permissions on source files
- Fix compile issue with 4630 driver modules (set_fs, get_fs, no longer supported in kernel 5.10)

* Fix missing/extra parens in 4630 util script.

* Fix indentation in fanutil.py.

* Integrate deltas from Edgecore to ec_platform branch.

* Installer update from Edgecore to resolve smbus serial console errors.

* Update stable_size for warm boot.

* Fix SFP dictionary key to match xcvrd.

* - Add missing define in event.py files needed for xcvrd
- Fix SFP info dict key for 7xxx switches

* 5835 platform file updates including installer and 5835 utility.

* 5835 fix for DMAR errors on serial console.

* Don't skip starting thermalctld in the pmon container.

* Revert several changes that were not related to platform.

* Run thermalctld in pmon container.

* Don't disable thermalctld in the pmon container.

* Fix prints/parens in 7816 install utility.

* - Incorporate 7816 changes from Edgecore
- Fix 7326 driver file using old kernel function

* Update kernel modules to use kernel_read().

* Fix compile errors with 7816 and 7326 driver modules.

* Fix some indents preventing platform files from loading.

* Update 7816 platform sfp dictionary to match field names in xcvrd.

* Add missing service and util files for 7816.

* Update file names, etc. based on full SKU for 7816.

* Delete pddf files not needed.  These were causing conflicts with API2.0
implementation.

* Remove pddf files suggested by Edgecore that were preventing API2.0 support from starting.

* Install API2.0 file instead of pddf.

* Update 7326 mac service file to not use pddf.  Fix syntax errors in 7326 utility script.

* Fix sonic_platform setup file for 7326.

* Fix syntax errors in python scripts.

* Updates to 7326 platform files.

* Fix some tab errors pulled down from master merge.

* Remove pddf files that were added from previous merge.

* Updates for 5835.

* Fix missing command byte for 5835 psu status.

* Fix permission bits on 4630 service files.

* Update platforms to use new SFP refactoring.

* Fix unused var warnings.
This commit is contained in:
Jeff Henning 2022-03-17 19:47:08 -05:00 committed by GitHub
parent 52c2a3ad23
commit ad6200029f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
99 changed files with 7429 additions and 4364 deletions

View File

@ -1,4 +1,4 @@
stable_size=71303168
stable_size=76303168
#polarity/lanemap is using TH2 style.
core_clock_frequency=893

View File

@ -1,66 +0,0 @@
{
"XCVR":
{
"xcvr_present":
{
"i2c":
{
"valmap-SFP28": {"1":true, "0":false },
"valmap-QSFP28": {"1":true, "0":false}
}
}
},
"PSU":
{
"psu_present":
{
"i2c":
{
"valmap": { "1":true, "0":false }
}
},
"psu_power_good":
{
"i2c":
{
"valmap": { "1": true, "0":false }
}
},
"psu_fan_dir":
{
"i2c":
{
"valmap": { "F2B":"EXHAUST", "B2F":"INTAKE" }
}
},
"PSU_FAN_MAX_SPEED":"18000"
},
"FAN":
{
"direction":
{
"i2c":
{
"valmap": {"1":"EXHAUST", "0":"INTAKE"}
}
},
"present":
{
"i2c":
{
"valmap": {"1":true, "0":false}
}
},
"duty_cycle_to_pwm": "lambda dc: ((dc*100.0)/625)",
"pwm_to_duty_cycle": "lambda pwm: ((pwm*625.0)/100)"
}
}

View File

@ -0,0 +1,2 @@
__all__ = [ "platform", "chassis", "sfp", "eeprom", "component", "psu", "thermal", "fan", "fan_drawer" ]
from . import platform

View File

@ -0,0 +1,255 @@
#############################################################################
# Edgecore
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Chassis information which are available in the platform
#
#############################################################################
import os
import sys
try:
from sonic_platform_base.chassis_base import ChassisBase
from .helper import APIHelper
from .event import SfpEvent
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
NUM_FAN_TRAY = 3
NUM_FAN = 2
NUM_PSU = 2
NUM_THERMAL = 3
PORT_START = 49
PORT_END = 54
NUM_COMPONENT = 2
HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/"
PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/"
REBOOT_CAUSE_FILE = "reboot-cause.txt"
PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt"
HOST_CHK_CMD = "which systemctl > /dev/null 2>&1"
SYSLED_FNODE = "/sys/class/leds/diag/brightness"
SYSLED_MODES = {
"0" : "STATUS_LED_COLOR_OFF",
"1" : "STATUS_LED_COLOR_GREEN",
"2" : "STATUS_LED_COLOR_AMBER",
"5" : "STATUS_LED_COLOR_GREEN_BLINK"
}
class Chassis(ChassisBase):
"""Platform-specific Chassis class"""
def __init__(self):
ChassisBase.__init__(self)
self._api_helper = APIHelper()
self.is_host = self._api_helper.is_host()
self.config_data = {}
self.__initialize_fan()
self.__initialize_psu()
self.__initialize_thermals()
self.__initialize_components()
self.__initialize_sfp()
self.__initialize_eeprom()
def __initialize_sfp(self):
from sonic_platform.sfp import Sfp
for index in range(0, PORT_END):
sfp = Sfp(index)
self._sfp_list.append(sfp)
self._sfpevent = SfpEvent(self._sfp_list)
self.sfp_module_initialized = True
def __initialize_fan(self):
from sonic_platform.fan_drawer import FanDrawer
for fant_index in range(NUM_FAN_TRAY):
fandrawer = FanDrawer(fant_index)
self._fan_drawer_list.append(fandrawer)
self._fan_list.extend(fandrawer._fan_list)
def __initialize_psu(self):
from sonic_platform.psu import Psu
for index in range(0, NUM_PSU):
psu = Psu(index)
self._psu_list.append(psu)
def __initialize_thermals(self):
from sonic_platform.thermal import Thermal
for index in range(0, NUM_THERMAL):
thermal = Thermal(index)
self._thermal_list.append(thermal)
def __initialize_eeprom(self):
from sonic_platform.eeprom import Tlv
self._eeprom = Tlv()
def __initialize_components(self):
from sonic_platform.component import Component
for index in range(0, NUM_COMPONENT):
component = Component(index)
self._component_list.append(component)
def __initialize_watchdog(self):
from sonic_platform.watchdog import Watchdog
self._watchdog = Watchdog()
def __is_host(self):
return os.system(HOST_CHK_CMD) == 0
def __read_txt_file(self, file_path):
try:
with open(file_path, 'r') as fd:
data = fd.read()
return data.strip()
except IOError:
pass
return None
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
return self._eeprom.get_product_name()
def get_presence(self):
"""
Retrieves the presence of the Chassis
Returns:
bool: True if Chassis is present, False if not
"""
return True
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return True
def get_base_mac(self):
"""
Retrieves the base MAC address for the chassis
Returns:
A string containing the MAC address in the format
'XX:XX:XX:XX:XX:XX'
"""
return self._eeprom.get_mac()
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return self._eeprom.get_pn()
def get_serial(self):
"""
Retrieves the hardware serial number for the chassis
Returns:
A string containing the hardware serial number for this chassis.
"""
return self._eeprom.get_serial()
def get_system_eeprom_info(self):
"""
Retrieves the full content of system EEPROM information for the chassis
Returns:
A dictionary where keys are the type code defined in
OCP ONIE TlvInfo EEPROM format and values are their corresponding
values.
"""
return self._eeprom.get_eeprom()
def get_reboot_cause(self):
"""
Retrieves the cause of the previous reboot
Returns:
A tuple (string, string) where the first element is a string
containing the cause of the previous reboot. This string must be
one of the predefined strings in this class. If the first string
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
to pass a description of the reboot cause.
"""
reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE)
sw_reboot_cause = self._api_helper.read_txt_file(
reboot_cause_path) or "Unknown"
return ('REBOOT_CAUSE_NON_HARDWARE', sw_reboot_cause)
def get_change_event(self, timeout=0):
# SFP event
if not self.sfp_module_initialized:
self.__initialize_sfp()
return self._sfpevent.get_sfp_event(timeout)
def get_sfp(self, index):
"""
Retrieves sfp represented by (1-based) index <index>
Args:
index: An integer, the index (1-based) of the sfp to retrieve.
The index should be the sequence of a physical port in a chassis,
starting from 1.
For example, 1 for Ethernet0, 2 for Ethernet4 and so on.
Returns:
An object dervied from SfpBase representing the specified sfp
"""
sfp = None
if not self.sfp_module_initialized:
self.__initialize_sfp()
try:
# The index will start from 1
sfp = self._sfp_list[index-1]
except IndexError:
sys.stderr.write("SFP index {} out of range (1-{})\n".format(
index, len(self._sfp_list)))
return sfp
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
"""
return -1
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return False
def initizalize_system_led(self):
return True
def get_status_led(self):
val = self._api_helper.read_txt_file(SYSLED_FNODE)
return SYSLED_MODES[val] if val in SYSLED_MODES else "UNKNOWN"
def set_status_led(self, color):
mode = None
for key, val in SYSLED_MODES.items():
if val == color:
mode = key
break
if mode is None:
return False
else:
return self._api_helper.write_txt_file(SYSLED_FNODE, mode)

View File

@ -0,0 +1,172 @@
#############################################################################
# Edgecore
#
# Component contains an implementation of SONiC Platform Base API and
# provides the components firmware management function
#
#############################################################################
import shlex
import subprocess
try:
from sonic_platform_base.component_base import ComponentBase
from .helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
CPLD_ADDR_MAPPING = {
"CPLD1": "3-0060"
}
SYSFS_PATH = "/sys/bus/i2c/devices/"
BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version"
COMPONENT_LIST= [
("CPLD1", "CPLD 1"),
("BIOS", "Basic Input/Output System")
]
class Component(ComponentBase):
"""Platform-specific Component class"""
DEVICE_TYPE = "component"
def __init__(self, component_index=0):
self._api_helper=APIHelper()
ComponentBase.__init__(self)
self.index = component_index
self.name = self.get_name()
def __run_command(self, command):
# Run bash command and print output to stdout
try:
process = subprocess.Popen(
shlex.split(command), stdout=subprocess.PIPE)
while True:
output = process.stdout.readline()
if output == '' and process.poll() is not None:
break
rc = process.poll()
if rc != 0:
return False
except Exception:
return False
return True
def __get_bios_version(self):
# Retrieves the BIOS firmware version
try:
with open(BIOS_VERSION_PATH, 'r') as fd:
bios_version = fd.read()
return bios_version.strip()
except Exception as e:
return None
def __get_cpld_version(self):
# Retrieves the CPLD firmware version
cpld_version = dict()
for cpld_name in CPLD_ADDR_MAPPING:
try:
cpld_path = "{}{}{}".format(SYSFS_PATH, CPLD_ADDR_MAPPING[cpld_name], '/version')
cpld_version_raw= self._api_helper.read_txt_file(cpld_path)
cpld_version[cpld_name] = "{}".format(int(cpld_version_raw,16))
except Exception as e:
print('Get exception when read cpld')
cpld_version[cpld_name] = 'None'
return cpld_version
def get_name(self):
"""
Retrieves the name of the component
Returns:
A string containing the name of the component
"""
return COMPONENT_LIST[self.index][0]
def get_description(self):
"""
Retrieves the description of the component
Returns:
A string containing the description of the component
"""
return COMPONENT_LIST[self.index][1]
def get_firmware_version(self):
"""
Retrieves the firmware version of module
Returns:
string: The firmware versions of the module
"""
fw_version = None
if self.name == "BIOS":
fw_version = self.__get_bios_version()
elif "CPLD" in self.name:
cpld_version = self.__get_cpld_version()
fw_version = cpld_version.get(self.name)
return fw_version
def install_firmware(self, image_path):
"""
Install firmware to module
Args:
image_path: A string, path to firmware image
Returns:
A boolean, True if install successfully, False if not
"""
raise NotImplementedError
def get_presence(self):
"""
Retrieves the presence of the device
Returns:
bool: True if device is present, False if not
"""
return True
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return 'N/A'
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return 'N/A'
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return True
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device.
If the agent cannot determine the parent-relative position
for some reason, or if the associated value of
entPhysicalContainedIn is'0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device
or -1 if cannot determine the position
"""
return -1
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return False

View File

@ -0,0 +1,134 @@
try:
import os
import sys
import re
if sys.version_info[0] >= 3:
from io import StringIO
else:
from cStringIO import StringIO
from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
CACHE_ROOT = '/var/cache/sonic/decode-syseeprom'
CACHE_FILE = 'syseeprom_cache'
NULL = 'N/A'
class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
EEPROM_DECODE_HEADLINES = 6
def __init__(self):
self._eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom"
super(Tlv, self).__init__(self._eeprom_path, 0, '', True)
self._eeprom = self._load_eeprom()
def __parse_output(self, decode_output):
decode_output.replace('\0', '')
lines = decode_output.split('\n')
lines = lines[self.EEPROM_DECODE_HEADLINES:]
_eeprom_info_dict = dict()
for line in lines:
try:
match = re.search(
'(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line)
if match is not None:
idx = match.group(1)
value = match.group(3).rstrip('\0')
_eeprom_info_dict[idx] = value
except Exception:
pass
return _eeprom_info_dict
def _load_eeprom(self):
original_stdout = sys.stdout
sys.stdout = StringIO()
try:
self.read_eeprom_db()
except Exception:
decode_output = sys.stdout.getvalue()
sys.stdout = original_stdout
return self.__parse_output(decode_output)
status = self.check_status()
if 'ok' not in status:
return False
if not os.path.exists(CACHE_ROOT):
try:
os.makedirs(CACHE_ROOT)
except Exception:
pass
#
# only the eeprom classes that inherit from eeprom_base
# support caching. Others will work normally
#
try:
self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE))
except Exception:
pass
e = self.read_eeprom()
if e is None:
return 0
try:
self.update_cache(e)
except Exception:
pass
self.decode_eeprom(e)
decode_output = sys.stdout.getvalue()
sys.stdout = original_stdout
(is_valid, valid_crc) = self.is_checksum_valid(e)
if not is_valid:
return False
return self.__parse_output(decode_output)
def _valid_tlv(self, eeprom_data):
tlvinfo_type_codes_list = [
self._TLV_CODE_PRODUCT_NAME,
self._TLV_CODE_PART_NUMBER,
self._TLV_CODE_SERIAL_NUMBER,
self._TLV_CODE_MAC_BASE,
self._TLV_CODE_MANUF_DATE,
self._TLV_CODE_DEVICE_VERSION,
self._TLV_CODE_LABEL_REVISION,
self._TLV_CODE_PLATFORM_NAME,
self._TLV_CODE_ONIE_VERSION,
self._TLV_CODE_MAC_SIZE,
self._TLV_CODE_MANUF_NAME,
self._TLV_CODE_MANUF_COUNTRY,
self._TLV_CODE_VENDOR_NAME,
self._TLV_CODE_DIAG_VERSION,
self._TLV_CODE_SERVICE_TAG,
self._TLV_CODE_VENDOR_EXT,
self._TLV_CODE_CRC_32
]
for code in tlvinfo_type_codes_list:
code_str = "0x{:X}".format(code)
eeprom_data[code_str] = eeprom_data.get(code_str, NULL)
return eeprom_data
def get_eeprom(self):
return self._valid_tlv(self._eeprom)
def get_pn(self):
return self._eeprom.get('0x22', NULL)
def get_serial(self):
return self._eeprom.get('0x23', NULL)
def get_mac(self):
return self._eeprom.get('0x24', NULL)
def get_product_name(self):
return self._eeprom.get('0x21', NULL)

View File

@ -0,0 +1,63 @@
try:
import time
from .helper import APIHelper
from sonic_py_common.logger import Logger
except ImportError as e:
raise ImportError(repr(e) + " - required module not found")
POLL_INTERVAL_IN_SEC = 1
class SfpEvent:
''' Listen to insert/remove sfp events '''
def __init__(self, sfp_list):
self._api_helper = APIHelper()
self._sfp_list = sfp_list
self._logger = Logger()
self._sfp_change_event_data = {'present': 0}
def get_presence_bitmap(self):
bitmap = 0
for sfp in self._sfp_list:
modpres = sfp.get_presence()
i=sfp.port_num-1
if modpres:
bitmap = bitmap | (1 << i)
return bitmap
def get_sfp_event(self, timeout=2000):
#now = time.time()
port_dict = {}
change_dict = {}
change_dict['sfp'] = port_dict
if timeout < 1000:
cd_ms = 1000
else:
cd_ms = timeout
while cd_ms > 0:
bitmap = self.get_presence_bitmap()
changed_ports = self._sfp_change_event_data['present'] ^ bitmap
if changed_ports != 0:
break
time.sleep(POLL_INTERVAL_IN_SEC)
# timeout=0 means wait for event forever
if timeout != 0:
cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000
if changed_ports != 0:
for sfp in self._sfp_list:
i=sfp.port_num-1
if (changed_ports & (1 << i)):
if (bitmap & (1 << i)) == 0:
port_dict[i+1] = '0'
else:
port_dict[i+1] = '1'
# Update the cache dict
self._sfp_change_event_data['present'] = bitmap
return True, change_dict
else:
return True, change_dict

View File

@ -0,0 +1,284 @@
#############################################################################
# Edgecore
#
# Module contains an implementation of SONiC Platform Base API and
# provides the fan status which are available in the platform
#
#############################################################################
try:
from sonic_platform_base.fan_base import FanBase
from .helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
PSU_FAN_MAX_RPM = 26688
SPEED_TOLERANCE = 15
CPLD_FAN_I2C_PATH = "/sys/bus/i2c/devices/3-0060/fan_"
I2C_PATH ="/sys/bus/i2c/devices/{}-00{}/"
PSU_HWMON_I2C_MAPPING = {
0: {
"num": 10,
"addr": "58"
},
1: {
"num": 11,
"addr": "59"
},
}
PSU_CPLD_I2C_MAPPING = {
0: {
"num": 10,
"addr": "50"
},
1: {
"num": 11,
"addr": "51"
},
}
FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R",
"FAN-3F", "FAN-3R"]
class Fan(FanBase):
"""Platform-specific Fan class"""
def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0):
self._api_helper=APIHelper()
self.fan_index = fan_index
self.fan_tray_index = fan_tray_index
self.is_psu_fan = is_psu_fan
if self.is_psu_fan:
self.psu_index = psu_index
self.psu_i2c_num = PSU_HWMON_I2C_MAPPING[self.psu_index]['num']
self.psu_i2c_addr = PSU_HWMON_I2C_MAPPING[self.psu_index]['addr']
self.psu_hwmon_path = I2C_PATH.format(
self.psu_i2c_num, self.psu_i2c_addr)
self.psu_i2c_num = PSU_CPLD_I2C_MAPPING[self.psu_index]['num']
self.psu_i2c_addr = PSU_CPLD_I2C_MAPPING[self.psu_index]['addr']
self.psu_cpld_path = I2C_PATH.format(
self.psu_i2c_num, self.psu_i2c_addr)
FanBase.__init__(self)
def get_direction(self):
"""
Retrieves the direction of fan
Returns:
A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST
depending on fan direction
"""
if not self.is_psu_fan:
dir_str = "{}{}{}".format(CPLD_FAN_I2C_PATH, 'direction_', self.fan_tray_index+1)
val=self._api_helper.read_txt_file(dir_str)
if val is not None:
if int(val, 10)==0:#F2B
direction=self.FAN_DIRECTION_EXHAUST
else:
direction=self.FAN_DIRECTION_INTAKE
else:
direction=self.FAN_DIRECTION_EXHAUST
else: #For PSU
dir_str = "{}{}".format(self.psu_hwmon_path,'psu_fan_dir')
val=self._api_helper.read_txt_file(dir_str)
if val is not None:
if val=='F2B':
direction=self.FAN_DIRECTION_EXHAUST
else:
direction=self.FAN_DIRECTION_INTAKE
else:
direction=self.FAN_DIRECTION_EXHAUST
return direction
def get_speed(self):
"""
Retrieves the speed of fan as a percentage of full speed
Returns:
An integer, the percentage of full fan speed, in the range 0 (off)
to 100 (full speed)
"""
speed = 0
if self.is_psu_fan:
psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_speed_rpm')
fan_speed_rpm = self._api_helper.read_txt_file(psu_fan_path)
if fan_speed_rpm is not None:
speed = (int(fan_speed_rpm,10))*100/26688
if speed > 100:
speed=100
else:
return 0
elif self.get_presence():
speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, 'duty_cycle_percentage')
speed=self._api_helper.read_txt_file(speed_path)
if speed is None:
return 0
return int(speed)
def get_target_speed(self):
"""
Retrieves the target (expected) speed of the fan
Returns:
An integer, the percentage of full fan speed, in the range 0 (off)
to 100 (full speed)
Note:
speed_pc = pwm_target/255*100
0 : when PWM mode is use
pwm : when pwm mode is not use
"""
return self.get_speed()
def get_speed_tolerance(self):
"""
Retrieves the speed tolerance of the fan
Returns:
An integer, the percentage of variance from target speed which is
considered tolerable
"""
return SPEED_TOLERANCE
def set_speed(self, speed):
"""
Sets the fan speed
Args:
speed: An integer, the percentage of full fan speed to set fan to,
in the range 0 (off) to 100 (full speed)
Returns:
A boolean, True if speed is set successfully, False if not
"""
if not self.is_psu_fan and self.get_presence():
speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, 'duty_cycle_percentage')
return self._api_helper.write_txt_file(speed_path, int(speed))
return False
def set_status_led(self, color):
"""
Sets the state of the fan module status LED
Args:
color: A string representing the color with which to set the
fan module status LED
Returns:
bool: True if status LED state is set successfully, False if not
"""
return False #Not supported
def get_status_led(self):
"""
Gets the state of the fan status LED
Returns:
A string, one of the predefined STATUS_LED_COLOR_* strings above
"""
status=self.get_presence()
if status is None:
return self.STATUS_LED_COLOR_OFF
return {
1: self.STATUS_LED_COLOR_GREEN,
0: self.STATUS_LED_COLOR_RED
}.get(status, self.STATUS_LED_COLOR_OFF)
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
fan_name = FAN_NAME_LIST[self.fan_tray_index*2 + self.fan_index] \
if not self.is_psu_fan \
else "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1)
return fan_name
def get_presence(self):
"""
Retrieves the presence of the FAN
Returns:
bool: True if FAN is present, False if not
"""
if self.is_psu_fan:
present_path="{}{}".format(self.psu_cpld_path, 'psu_present')
else:
present_path = "{}{}{}".format(CPLD_FAN_I2C_PATH, 'present_', self.fan_tray_index+1)
val=self._api_helper.read_txt_file(present_path)
if val is not None:
return int(val, 10)==1
else:
return False
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
if self.is_psu_fan:
psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_fault')
val=self._api_helper.read_txt_file(psu_fan_path)
if val is not None:
return int(val, 10)==0
else:
return False
else:
path = "{}{}{}".format(CPLD_FAN_I2C_PATH, 'fault_', self.fan_tray_index+1)
val=self._api_helper.read_txt_file(path)
if val is not None:
return int(val, 10)==0
else:
return False
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return "N/A"
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return "N/A"
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device.
If the agent cannot determine the parent-relative position
for some reason, or if the associated value of
entPhysicalContainedIn is'0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device
or -1 if cannot determine the position
"""
return (self.fan_index+1) \
if not self.is_psu_fan else (self.psu_index+1)
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True if not self.is_psu_fan else False

View File

@ -0,0 +1,90 @@
########################################################################
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Fan-Drawers' information available in the platform.
#
########################################################################
try:
from sonic_platform_base.fan_drawer_base import FanDrawerBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
FANS_PER_FANTRAY = 2
class FanDrawer(FanDrawerBase):
"""Platform-specific Fan class"""
def __init__(self, fantray_index):
FanDrawerBase.__init__(self)
# FanTray is 0-based in platforms
self.fantrayindex = fantray_index
self.__initialize_fan_drawer()
def __initialize_fan_drawer(self):
from sonic_platform.fan import Fan
for i in range(FANS_PER_FANTRAY):
self._fan_list.append(Fan(self.fantrayindex, i))
def get_name(self):
"""
Retrieves the fan drawer name
Returns:
string: The name of the device
"""
return "FanTray{}".format(self.fantrayindex+1)
def get_presence(self):
"""
Retrieves the presence of the device
Returns:
bool: True if device is present, False if not
"""
return self._fan_list[0].get_presence()
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return self._fan_list[0].get_model()
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return self._fan_list[0].get_serial()
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return self._fan_list[0].get_status()
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device.
If the agent cannot determine the parent-relative position
for some reason, or if the associated value of
entPhysicalContainedIn is'0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device
or -1 if cannot determine the position
"""
return (self.fantrayindex+1)
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True

View File

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

View File

@ -0,0 +1,21 @@
#############################################################################
# Edgecore
#
# Module contains an implementation of SONiC Platform Base API and
# provides the platform information
#
#############################################################################
try:
from sonic_platform_base.platform_base import PlatformBase
from sonic_platform.chassis import Chassis
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class Platform(PlatformBase):
"""Platform-specific Platform class"""
def __init__(self):
PlatformBase.__init__(self)
self._chassis = Chassis()

View File

@ -0,0 +1,269 @@
#############################################################################
# Edgecore
#
# Module contains an implementation of SONiC Platform Base API and
# provides the PSUs status which are available in the platform
#
#############################################################################
#import sonic_platform
try:
from sonic_platform_base.psu_base import PsuBase
from .helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
I2C_PATH ="/sys/bus/i2c/devices/{0}-00{1}/"
PSU_NAME_LIST = ["PSU-1", "PSU-2"]
PSU_NUM_FAN = [1, 1]
PSU_HWMON_I2C_MAPPING = {
0: {
"num": 10,
"addr": "58"
},
1: {
"num": 11,
"addr": "59"
},
}
PSU_CPLD_I2C_MAPPING = {
0: {
"num": 10,
"addr": "50"
},
1: {
"num": 11,
"addr": "51"
},
}
class Psu(PsuBase):
"""Platform-specific Psu class"""
def __init__(self, psu_index=0):
PsuBase.__init__(self)
self.index = psu_index
self._api_helper = APIHelper()
self.i2c_num = PSU_HWMON_I2C_MAPPING[self.index]["num"]
self.i2c_addr = PSU_HWMON_I2C_MAPPING[self.index]["addr"]
self.hwmon_path = I2C_PATH.format(self.i2c_num, self.i2c_addr)
self.i2c_num = PSU_CPLD_I2C_MAPPING[self.index]["num"]
self.i2c_addr = PSU_CPLD_I2C_MAPPING[self.index]["addr"]
self.cpld_path = I2C_PATH.format(self.i2c_num, self.i2c_addr)
self.__initialize_fan()
def __initialize_fan(self):
from sonic_platform.fan import Fan
for fan_index in range(0, PSU_NUM_FAN[self.index]):
fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index)
self._fan_list.append(fan)
def get_voltage(self):
"""
Retrieves current PSU voltage output
Returns:
A float number, the output voltage in volts,
e.g. 12.1
"""
vout_path = "{}{}".format(self.hwmon_path, 'psu_v_out')
vout_val=self._api_helper.read_txt_file(vout_path)
if vout_val is not None:
return float(vout_val)/ 1000
else:
return 0
def get_current(self):
"""
Retrieves present electric current supplied by PSU
Returns:
A float number, the electric current in amperes, e.g 15.4
"""
iout_path = "{}{}".format(self.hwmon_path, 'psu_i_out')
val=self._api_helper.read_txt_file(iout_path)
if val is not None:
return float(val)/1000
else:
return 0
def get_power(self):
"""
Retrieves current energy supplied by PSU
Returns:
A float number, the power in watts, e.g. 302.6
"""
pout_path = "{}{}".format(self.hwmon_path, 'psu_p_out')
val=self._api_helper.read_txt_file(pout_path)
if val is not None:
return float(val)/1000
else:
return 0
def get_powergood_status(self):
"""
Retrieves the powergood status of PSU
Returns:
A boolean, True if PSU has stablized its output voltages and passed all
its internal self-tests, False if not.
"""
return self.get_status()
def set_status_led(self, color):
"""
Sets the state of the PSU status LED
Args:
color: A string representing the color with which to set the PSU status LED
Note: Only support green and off
Returns:
bool: True if status LED state is set successfully, False if not
"""
return False #Controlled by HW
def get_status_led(self):
"""
Gets the state of the PSU status LED
Returns:
A string, one of the predefined STATUS_LED_COLOR_* strings above
"""
status=self.get_status()
if status is None:
return self.STATUS_LED_COLOR_OFF
return {
1: self.STATUS_LED_COLOR_GREEN,
0: self.STATUS_LED_COLOR_RED
}.get(status, self.STATUS_LED_COLOR_OFF)
def get_temperature(self):
"""
Retrieves current temperature reading from PSU
Returns:
A float number of current temperature in Celsius up to nearest thousandth
of one degree Celsius, e.g. 30.125
"""
temp_path = "{}{}".format(self.hwmon_path, 'psu_temp1_input')
val=self._api_helper.read_txt_file(temp_path)
if val is not None:
return float(val)/1000
else:
return 0
def get_temperature_high_threshold(self):
"""
Retrieves the high threshold temperature of PSU
Returns:
A float number, the high threshold temperature of PSU in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
return False #Not supported
def get_voltage_high_threshold(self):
"""
Retrieves the high threshold PSU voltage output
Returns:
A float number, the high threshold output voltage in volts,
e.g. 12.1
"""
vout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_vout_max')
vout_val=self._api_helper.read_txt_file(vout_path)
if vout_val is not None:
return float(vout_val)/ 1000
else:
return 0
def get_voltage_low_threshold(self):
"""
Retrieves the low threshold PSU voltage output
Returns:
A float number, the low threshold output voltage in volts,
e.g. 12.1
"""
vout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_vout_min')
vout_val=self._api_helper.read_txt_file(vout_path)
if vout_val is not None:
return float(vout_val)/ 1000
else:
return 0
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
return PSU_NAME_LIST[self.index]
def get_presence(self):
"""
Retrieves the presence of the PSU
Returns:
bool: True if PSU is present, False if not
"""
presence_path="{}{}".format(self.cpld_path, 'psu_present')
val=self._api_helper.read_txt_file(presence_path)
if val is not None:
return int(val, 10) == 1
else:
return 0
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
power_path="{}{}".format(self.cpld_path, 'psu_power_good')
val=self._api_helper.read_txt_file(power_path)
if val is not None:
return int(val, 10) == 1
else:
return 0
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
model_path="{}{}".format(self.cpld_path, 'psu_model_name')
model=self._api_helper.read_txt_file(model_path)
if model is None:
return "N/A"
return model
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
serial_path="{}{}".format(self.cpld_path, 'psu_serial_number')
serial=self._api_helper.read_txt_file(serial_path)
if serial is None:
return "N/A"
return serial
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
"""
return self.index+1
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True

View File

@ -0,0 +1,484 @@
#############################################################################
# Edgecore
#
# Sfp contains an implementation of SONiC Platform Base API and
# provides the sfp device status which are available in the platform
#
#############################################################################
import os
import time
import sys
from ctypes import create_string_buffer
try:
from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase
from .helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
CPLD_I2C_PATH = "/sys/bus/i2c/devices/3-0060/"
class Sfp(SfpOptoeBase):
"""Platform-specific Sfp class"""
# Port number
PORT_START = 49
PORT_END = 54
# Path to sysfs
PLATFORM_ROOT_PATH = "/usr/share/sonic/device"
PMON_HWSKU_PATH = "/usr/share/sonic/hwsku"
HOST_CHK_CMD = "which systemctl > /dev/null 2>&1"
PLATFORM = "x86_64-accton_as4630_54pe-r0"
HWSKU = "Accton-AS4630-54PE"
_port_to_i2c_mapping = {
49: 18,
50: 19,
51: 20,
52: 21,
53: 22,
54: 23,
}
def __init__(self, sfp_index=0):
SfpOptoeBase.__init__(self)
self._api_helper=APIHelper()
# Init index
self.index = sfp_index
self.port_num = self.index + 1
# Init eeprom path
eeprom_path = '/sys/bus/i2c/devices/{0}-0050/eeprom'
self.port_to_eeprom_mapping = {}
for x in range(self.PORT_START, self.PORT_END + 1):
self.port_to_eeprom_mapping[x] = eeprom_path.format(self._port_to_i2c_mapping[x])
def get_eeprom_path(self):
return self.port_to_eeprom_mapping[self.port_num]
def __is_host(self):
return os.system(self.HOST_CHK_CMD) == 0
def __get_path_to_port_config_file(self):
platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM])
hwsku_path = "/".join([platform_path, self.HWSKU]
) if self.__is_host() else self.PMON_HWSKU_PATH
return "/".join([hwsku_path, "port_config.ini"])
def __read_eeprom_specific_bytes(self, offset, num_bytes):
sysfsfile_eeprom = None
eeprom_raw = []
for i in range(0, num_bytes):
eeprom_raw.append("0x00")
sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num]
try:
sysfsfile_eeprom = open(
sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0)
sysfsfile_eeprom.seek(offset)
raw = sysfsfile_eeprom.read(num_bytes)
if sys.version_info[0] >= 3:
for n in range(0, num_bytes):
eeprom_raw[n] = hex(raw[n])[2:].zfill(2)
else:
for n in range(0, num_bytes):
eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2)
except Exception:
pass
finally:
if sysfsfile_eeprom:
sysfsfile_eeprom.close()
return eeprom_raw
def get_reset_status(self):
"""
Retrieves the reset status of SFP
Returns:
A Boolean, True if reset enabled, False if disabled
"""
if self.port_num < 53: #Copper port and sfp ports are suported.
return False
reset_path="{}{}{}".format(CPLD_I2C_PATH , "module_reset_" , str(self.port_num))
val = self._api_helper.read_txt_file(reset_path)
if val is not None:
return int(val, 10) == 1
else:
return False
def get_rx_los(self):
"""
Retrieves the RX LOS (lost-of-signal) status of SFP
Returns:
A Boolean, True if SFP has RX LOS, False if not.
Note : RX LOS status is latched until a call to get_rx_los or a reset.
"""
rx_los = False
if self.port_num < 49: #Copper port, no sysfs
return False
if self.port_num < 53:
rx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_rx_los_', self.port_num)
rx_los=self._api_helper.read_txt_file(rx_path)
if rx_los is None:
return False
else:
rx_los_list = []
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
QSFP_CHANNL_RX_LOS_STATUS_OFFSET, QSFP_CHANNL_RX_LOS_STATUS_WIDTH) if self.get_presence() else None
if dom_channel_monitor_raw is not None:
rx_los_data = int(dom_channel_monitor_raw[0], 16)
rx_los_list.append(rx_los_data & 0x01 != 0)
rx_los_list.append(rx_los_data & 0x02 != 0)
rx_los_list.append(rx_los_data & 0x04 != 0)
rx_los_list.append(rx_los_data & 0x08 != 0)
rx_los = rx_los_list[0] and rx_los_list[1] and rx_los_list[2] and rx_los_list[3]
return rx_los
def get_tx_fault(self):
"""
Retrieves the TX fault status of SFP
Returns:
A Boolean, True if SFP has TX fault, False if not
Note : TX fault status is lached until a call to get_tx_fault or a reset.
"""
tx_fault = False
if self.port_num < 49: #Copper port, no sysfs
return False
if self.port_num < 53:
tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_fault_', self.port_num)
tx_fault=self._api_helper.read_txt_file(tx_path)
if tx_fault is None:
return False
else:
tx_fault_list = []
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
QSFP_CHANNL_TX_FAULT_STATUS_OFFSET, QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) if self.get_presence() else None
if dom_channel_monitor_raw is not None:
tx_fault_data = int(dom_channel_monitor_raw[0], 16)
tx_fault_list.append(tx_fault_data & 0x01 != 0)
tx_fault_list.append(tx_fault_data & 0x02 != 0)
tx_fault_list.append(tx_fault_data & 0x04 != 0)
tx_fault_list.append(tx_fault_data & 0x08 != 0)
tx_fault = tx_fault_list[0] and tx_fault_list[1] and tx_fault_list[2] and tx_fault_list[3]
return tx_fault
def get_tx_disable(self):
"""
Retrieves the tx_disable status of this SFP
Returns:
A Boolean, True if tx_disable is enabled, False if disabled
"""
if self.port_num < 49: #Copper port, no sysfs
return False
if self.port_num < 53:
tx_disable = False
tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_disable_', self.port_num)
tx_disable=self._api_helper.read_txt_file(tx_path)
if tx_disable is not None:
return tx_disable
else:
return False
else:
tx_disable_list = []
sfpd_obj = sff8436Dom()
if sfpd_obj is None:
return False
dom_control_raw = self.__read_eeprom_specific_bytes(
QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None
if dom_control_raw is not None:
dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0)
tx_disable_list.append(
'On' == dom_control_data['data']['TX1Disable']['value'])
tx_disable_list.append(
'On' == dom_control_data['data']['TX2Disable']['value'])
tx_disable_list.append(
'On' == dom_control_data['data']['TX3Disable']['value'])
tx_disable_list.append(
'On' == dom_control_data['data']['TX4Disable']['value'])
return tx_disable_list
def get_tx_disable_channel(self):
"""
Retrieves the TX disabled channels in this SFP
Returns:
A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent
TX channels which have been disabled in this SFP.
As an example, a returned value of 0x5 indicates that channel 0
and channel 2 have been disabled.
"""
if self.port_num < 53:
# SFP doesn't support this feature
return False
else:
tx_disable_list = self.get_tx_disable()
if tx_disable_list is None:
return 0
tx_disabled = 0
for i in range(len(tx_disable_list)):
if tx_disable_list[i]:
tx_disabled |= 1 << i
return tx_disabled
def get_lpmode(self):
"""
Retrieves the lpmode (low power mode) status of this SFP
Returns:
A Boolean, True if lpmode is enabled, False if disabled
"""
if self.port_num < 53:
# SFP doesn't support this feature
return False
else:
power_set=self.get_power_set()
power_override = self.get_power_override()
return power_set and power_override
def reset(self):
"""
Reset SFP and return all user module settings to their default srate.
Returns:
A boolean, True if successful, False if not
"""
# Check for invalid port_num
if self.port_num < 53: #Copper port and sfp ports are not supported.
return False
reset_path = "{}{}{}".format(CPLD_I2C_PATH, 'module_reset_', self.port_num)
ret = self._api_helper.write_txt_file(reset_path, 1)
if ret is not True:
return ret
time.sleep(0.01)
ret = self._api_helper.write_txt_file(reset_path, 0)
time.sleep(0.2)
return ret
def tx_disable(self, tx_disable):
"""
Disable SFP TX for all channels
Args:
tx_disable : A Boolean, True to enable tx_disable mode, False to disable
tx_disable mode.
Returns:
A boolean, True if tx_disable is set successfully, False if not
"""
if self.port_num < 49: #Copper port, no sysfs
return False
if self.port_num < 53:
tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_disable_', self.port_num)
ret = self._api_helper.write_txt_file(tx_path, 1 if tx_disable else 0)
if ret is not None:
time.sleep(0.01)
return ret
else:
return False
else:
if not self.get_presence():
return False
sysfsfile_eeprom = None
try:
tx_disable_ctl = 0xf if tx_disable else 0x0
buffer = create_string_buffer(1)
if sys.version_info[0] >= 3:
buffer[0] = tx_disable_ctl
else:
buffer[0] = chr(tx_disable_ctl)
# Write to eeprom
sysfsfile_eeprom = open(
self.port_to_eeprom_mapping[self.port_num], "r+b")
sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET)
sysfsfile_eeprom.write(buffer[0])
except IOError as e:
print ('Error: unable to open file: ',str(e))
return False
finally:
if sysfsfile_eeprom is not None:
sysfsfile_eeprom.close()
time.sleep(0.01)
return True
def tx_disable_channel(self, channel, disable):
"""
Sets the tx_disable for specified SFP channels
Args:
channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3,
e.g. 0x5 for channel 0 and channel 2.
disable : A boolean, True to disable TX channels specified in channel,
False to enable
Returns:
A boolean, True if successful, False if not
"""
if self.port_num < 53:
return False # SFP doesn't support this feature
else:
if not self.get_presence():
return False
sysfsfile_eeprom = None
try:
channel_state = self.get_tx_disable_channel()
for i in range(4):
channel_mask = (1 << i)
if not (channel & channel_mask):
continue
if disable:
channel_state |= channel_mask
else:
channel_state &= ~channel_mask
buffer = create_string_buffer(1)
if sys.version_info[0] >= 3:
buffer[0] = channel_state
else:
buffer[0] = chr(channel_state)
# Write to eeprom
sysfsfile_eeprom = open(
self.port_to_eeprom_mapping[self.port_num], "r+b")
sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET)
sysfsfile_eeprom.write(buffer[0])
except IOError as e:
print ('Error: unable to open file: ', str(e))
return False
finally:
if sysfsfile_eeprom is not None:
sysfsfile_eeprom.close()
time.sleep(0.01)
return True
def set_lpmode(self, lpmode):
"""
Sets the lpmode (low power mode) of SFP
Args:
lpmode: A Boolean, True to enable lpmode, False to disable it
Note : lpmode can be overridden by set_power_override
Returns:
A boolean, True if lpmode is set successfully, False if not
"""
if self.port_num < 53:
return False # SFP doesn't support this feature
else:
if lpmode is True:
self.set_power_override(True, True)
else:
self.set_power_override(False, False)
return True
def set_power_override(self, power_override, power_set):
"""
Sets SFP power level using power_override and power_set
Args:
power_override :
A Boolean, True to override set_lpmode and use power_set
to control SFP power, False to disable SFP power control
through power_override/power_set and use set_lpmode
to control SFP power.
power_set :
Only valid when power_override is True.
A Boolean, True to set SFP to low power mode, False to set
SFP to high power mode.
Returns:
A boolean, True if power-override and power_set are set successfully,
False if not
"""
if self.port_num < 53:
return False # SFP doesn't support this feature
else:
if not self.get_presence():
return False
try:
power_override_bit = (1 << 0) if power_override else 0
power_set_bit = (1 << 1) if power_set else (1 << 3)
buffer = create_string_buffer(1)
if sys.version_info[0] >= 3:
buffer[0] = (power_override_bit | power_set_bit)
else:
buffer[0] = chr(power_override_bit | power_set_bit)
# Write to eeprom
with open(self.port_to_eeprom_mapping[self.port_num], "r+b") as fd:
fd.seek(QSFP_POWEROVERRIDE_OFFSET)
fd.write(buffer[0])
time.sleep(0.01)
except IOError as e:
print ('Error: unable to open file: ', str(e))
return False
return True
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
name = None
sfputil_helper = SfpUtilHelper()
sfputil_helper.read_porttab_mappings(
self.__get_path_to_port_config_file())
name = sfputil_helper.logical[self.index] or "Unknown"
return name
def get_presence(self):
"""
Retrieves the presence of the device
Returns:
bool: True if device is present, False if not
"""
if self.port_num < 49: #Copper port, no sysfs
return False
present_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_present_', self.port_num)
val=self._api_helper.read_txt_file(present_path)
if val is not None:
return int(val, 10)==1
else:
return False
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return self.get_presence()
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
"""
return self.port_num
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True

View File

@ -0,0 +1,236 @@
#############################################################################
# Edgecore
#
# Thermal contains an implementation of SONiC Platform Base API and
# provides the thermal device status which are available in the platform
#
#############################################################################
import os
import os.path
import glob
try:
from sonic_platform_base.thermal_base import ThermalBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
PSU_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/"
PSU_I2C_MAPPING = {
0: {
"num": 10,
"addr": "58"
},
1: {
"num": 11,
"addr": "59"
},
}
PSU_CPLD_I2C_MAPPING = {
0: {
"num": 10,
"addr": "50"
},
1: {
"num": 11,
"addr": "51"
},
}
class Thermal(ThermalBase):
"""Platform-specific Thermal class"""
THERMAL_NAME_LIST = []
PSU_THERMAL_NAME_LIST = []
SYSFS_PATH = "/sys/bus/i2c/devices"
def __init__(self, thermal_index=0, is_psu=False, psu_index=0):
self.index = thermal_index
self.is_psu = is_psu
self.psu_index = psu_index
if self.is_psu:
psu_i2c_bus = PSU_I2C_MAPPING[psu_index]["num"]
psu_i2c_addr = PSU_I2C_MAPPING[psu_index]["addr"]
self.psu_hwmon_path = PSU_I2C_PATH.format(psu_i2c_bus,
psu_i2c_addr)
psu_i2c_bus = PSU_CPLD_I2C_MAPPING[psu_index]["num"]
psu_i2c_addr = PSU_CPLD_I2C_MAPPING[psu_index]["addr"]
self.cpld_path = PSU_I2C_PATH.format(psu_i2c_bus, psu_i2c_addr)
# Add thermal name
self.THERMAL_NAME_LIST.append("Temp sensor 1")
self.THERMAL_NAME_LIST.append("Temp sensor 2")
self.THERMAL_NAME_LIST.append("Temp sensor 3")
self.PSU_THERMAL_NAME_LIST.append("PSU-1 temp sensor 1")
self.PSU_THERMAL_NAME_LIST.append("PSU-2 temp sensor 1")
# Set hwmon path
i2c_path = {
0: "14-0048/hwmon/hwmon*/",
1: "24-004b/hwmon/hwmon*/",
2: "25-004a/hwmon/hwmon*/"
}.get(self.index, None)
self.hwmon_path = "{}/{}".format(self.SYSFS_PATH, i2c_path)
self.ss_key = self.THERMAL_NAME_LIST[self.index]
self.ss_index = 1
def __read_txt_file(self, file_path):
for filename in glob.glob(file_path):
try:
with open(filename, 'r') as fd:
data =fd.readline().rstrip()
return data
except IOError as e:
pass
return None
def __get_temp(self, temp_file):
if not self.is_psu:
temp_file_path = os.path.join(self.hwmon_path, temp_file)
else:
temp_file_path = temp_file
raw_temp = self.__read_txt_file(temp_file_path)
if raw_temp is not None:
return float(raw_temp)/1000
else:
return 0
def __set_threshold(self, file_name, temperature):
if self.is_psu:
return True
temp_file_path = os.path.join(self.hwmon_path, file_name)
for filename in glob.glob(temp_file_path):
try:
with open(filename, 'w') as fd:
fd.write(str(temperature))
return True
except IOError as e:
print("IOError")
def get_temperature(self):
"""
Retrieves current temperature reading from thermal
Returns:
A float number of current temperature in Celsius up to nearest thousandth
of one degree Celsius, e.g. 30.125
"""
if not self.is_psu:
temp_file = "temp{}_input".format(self.ss_index)
else:
temp_file = self.psu_hwmon_path + "psu_temp1_input"
return self.__get_temp(temp_file)
def get_high_threshold(self):
"""
Retrieves the high threshold temperature of thermal
Returns:
A float number, the high threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
if self.is_psu:
return 0
temp_file = "temp{}_max".format(self.ss_index)
return self.__get_temp(temp_file)
def set_high_threshold(self, temperature):
"""
Sets the high threshold temperature of thermal
Args :
temperature: A float number up to nearest thousandth of one degree Celsius,
e.g. 30.125
Returns:
A boolean, True if threshold is set successfully, False if not
"""
temp_file = "temp{}_max".format(self.ss_index)
temperature = temperature *1000
self.__set_threshold(temp_file, temperature)
return True
def get_name(self):
"""
Retrieves the name of the thermal device
Returns:
string: The name of the thermal device
"""
if self.is_psu:
return self.PSU_THERMAL_NAME_LIST[self.psu_index]
else:
return self.THERMAL_NAME_LIST[self.index]
def get_presence(self):
"""
Retrieves the presence of the Thermal
Returns:
bool: True if Thermal is present, False if not
"""
if self.is_psu:
val = self.__read_txt_file(self.cpld_path + "psu_present")
return int(val, 10) == 1
temp_file = "temp{}_input".format(self.ss_index)
temp_file_path = os.path.join(self.hwmon_path, temp_file)
raw_txt = self.__read_txt_file(temp_file_path)
if raw_txt is not None:
return True
else:
return False
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
if self.is_psu:
temp_file = self.psu_hwmon_path + "psu_temp_fault"
return self.get_presence() and (not int(
self.__read_txt_file(temp_file)))
file_str = "temp{}_input".format(self.ss_index)
file_path = os.path.join(self.hwmon_path, file_str)
raw_txt = self.__read_txt_file(file_path)
if raw_txt is None:
return False
else:
return int(raw_txt) != 0
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return "N/A"
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return "N/A"
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
"""
return self.index+1
def is_replaceable(self):
"""
Retrieves whether thermal module is replaceable
Returns:
A boolean value, True if replaceable, False if not
"""
return False

View File

@ -2,4 +2,3 @@ CONSOLE_PORT=0x3f8
CONSOLE_DEV=0
CONSOLE_SPEED=115200
ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="intel_iommu=off modprobe.blacklist=i2c-ismt,i2c_ismt,i2c-i801,i2c_i801"

View File

@ -148,7 +148,7 @@ class SfpUtil(SfpUtilBase):
cage_num = port_num
if (port_num >= self.QSFP_PORT_START):
cage_num = (port_num - self.QSFP_PORT_START)/4
cage_num = cage_num + self.QSFP_PORT_START
cage_num = int(cage_num + self.QSFP_PORT_START)
return cage_num

View File

@ -1,5 +1,5 @@
{
"skip_ledd": true,
"skip_thermalctld": true
"skip_pcied": true
}

View File

@ -1,2 +1,2 @@
__all__ = ['chassis', 'eeprom', 'platform', 'psu', 'sfp', 'thermal', 'fan']
__all__ = [ "platform", "chassis", "sfp", "eeprom", "component", "psu", "thermal", "fan", "fan_drawer" ]
from . import platform

View File

@ -28,7 +28,14 @@ HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/"
PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/"
REBOOT_CAUSE_FILE = "reboot-cause.txt"
PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt"
HOST_CHK_CMD = "docker > /dev/null 2>&1"
HOST_CHK_CMD = "which systemctl > /dev/null 2>&1"
SYSLED_FNODE= "/sys/class/leds/as5835_54x_led::diag/brightness"
SYSLED_MODES = {
"0" : "STATUS_LED_COLOR_OFF",
"1" : "STATUS_LED_COLOR_GREEN",
"3" : "STATUS_LED_COLOR_AMBER"
}
class Chassis(ChassisBase):
@ -37,7 +44,6 @@ class Chassis(ChassisBase):
def __init__(self):
ChassisBase.__init__(self)
self._api_helper = APIHelper()
self._api_helper = APIHelper()
self.is_host = self._api_helper.is_host()
self.config_data = {}
@ -54,15 +60,16 @@ class Chassis(ChassisBase):
for index in range(0, PORT_END):
sfp = Sfp(index)
self._sfp_list.append(sfp)
self._sfpevent = SfpEvent(self._sfp_list)
self.sfp_module_initialized = True
def __initialize_fan(self):
from sonic_platform.fan import Fan
for fant_index in range(0, NUM_FAN_TRAY):
for fan_index in range(0, NUM_FAN):
fan = Fan(fant_index, fan_index)
self._fan_list.append(fan)
from sonic_platform.fan_drawer import FanDrawer
for fant_index in range(NUM_FAN_TRAY):
fandrawer = FanDrawer(fant_index)
self._fan_drawer_list.append(fandrawer)
self._fan_list.extend(fandrawer._fan_list)
def __initialize_psu(self):
from sonic_platform.psu import Psu
for index in range(0, NUM_PSU):
@ -84,12 +91,12 @@ class Chassis(ChassisBase):
for index in range(0, NUM_COMPONENT):
component = Component(index)
self._component_list.append(component)
def __initialize_watchdog(self):
from sonic_platform.watchdog import Watchdog
self._watchdog = Watchdog()
def __is_host(self):
return os.system(HOST_CHK_CMD) == 0
@ -101,23 +108,14 @@ class Chassis(ChassisBase):
except IOError:
pass
return None
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return self._eeprom.get_pn()
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
return self._api_helper.hwsku
return self._eeprom.get_product_name()
def get_presence(self):
"""
@ -144,7 +142,15 @@ class Chassis(ChassisBase):
"""
return self._eeprom.get_mac()
def get_serial_number(self):
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return self._eeprom.get_pn()
def get_serial(self):
"""
Retrieves the hardware serial number for the chassis
Returns:
@ -173,7 +179,7 @@ class Chassis(ChassisBase):
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
to pass a description of the reboot cause.
"""
reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE)
sw_reboot_cause = self._api_helper.read_txt_file(
reboot_cause_path) or "Unknown"
@ -185,10 +191,7 @@ class Chassis(ChassisBase):
# SFP event
if not self.sfp_module_initialized:
self.__initialize_sfp()
status, sfp_event = SfpEvent(self._sfp_list).get_sfp_event(timeout)
return status, sfp_event
return self._sfpevent.get_sfp_event(timeout)
def get_sfp(self, index):
"""
@ -212,3 +215,40 @@ class Chassis(ChassisBase):
sys.stderr.write("SFP index {} out of range (1-{})\n".format(
index, len(self._sfp_list)))
return sfp
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
"""
return -1
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return False
def initizalize_system_led(self):
return True
def get_status_led(self):
val = self._api_helper.read_txt_file(SYSLED_FNODE)
return SYSLED_MODES[val] if val in SYSLED_MODES else "UNKNOWN"
def set_status_led(self, color):
mode = None
for key, val in SYSLED_MODES.items():
if val == color:
mode = key
break
if mode is None:
return False
else:
return self._api_helper.write_txt_file(SYSLED_FNODE, mode)

View File

@ -1,5 +1,5 @@
#############################################################################
# Celestica
# Edgecore
#
# Component contains an implementation of SONiC Platform Base API and
# provides the components firmware management function
@ -67,14 +67,14 @@ class Component(ComponentBase):
with open(BIOS_VERSION_PATH, 'r') as fd:
bios_version = fd.read()
return bios_version.strip()
except Exception as e:
except Exception as e:
print('Get exception when read bios')
return None
def __get_cpld_version(self):
# Retrieves the CPLD firmware version
cpld_version = dict()
for cpld_name in CPLD_ADDR_MAPPING:
for cpld_name in CPLD_ADDR_MAPPING:
try:
cpld_path = "{}{}{}".format(SYSFS_PATH, CPLD_ADDR_MAPPING[cpld_name], '/version')
cpld_version_raw= self._api_helper.read_txt_file(cpld_path)
@ -126,3 +126,55 @@ class Component(ComponentBase):
A boolean, True if install successfully, False if not
"""
raise NotImplementedError
def get_presence(self):
"""
Retrieves the presence of the device
Returns:
bool: True if device is present, False if not
"""
return True
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return 'N/A'
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return 'N/A'
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return True
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device.
If the agent cannot determine the parent-relative position
for some reason, or if the associated value of
entPhysicalContainedIn is'0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device
or -1 if cannot determine the position
"""
return -1
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return False

View File

@ -20,7 +20,7 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
EEPROM_DECODE_HEADLINES = 6
def __init__(self):
self._eeprom_path = "/sys/bus/i2c/devices/0-0057/eeprom"
self._eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom"
super(Tlv, self).__init__(self._eeprom_path, 0, '', True)
self._eeprom = self._load_eeprom()
@ -123,9 +123,12 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
def get_pn(self):
return self._eeprom.get('0x22', NULL)
def get_serial(self):
return self._eeprom.get('0x23', NULL)
def get_mac(self):
return self._eeprom.get('0x24', NULL)
def get_product_name(self):
return self._eeprom.get('0x21', NULL)

View File

@ -1,42 +1,49 @@
try:
import time
from .helper import APIHelper
from sonic_py_common.logger import Logger
except ImportError as e:
raise ImportError(repr(e) + " - required module not found")
POLL_INTERVAL_IN_SEC = 1
class SfpEvent:
''' Listen to insert/remove sfp events '''
def __init__(self, sfp_list):
self._api_helper = APIHelper()
self._sfp_list = sfp_list
self._logger = Logger()
self._sfp_change_event_data = {'present': 0}
sfp_change_event_data = {'valid': 0, 'last': 0, 'present': 0}
def get_sfp_event(self, timeout=2000):
now = time.time()
port_dict = {}
change_dict = {}
change_dict['sfp'] = port_dict
if timeout < 1000:
timeout = 1000
timeout = timeout / float(1000) # Convert to secs
if now < (self.sfp_change_event_data['last'] + timeout) and self.sfp_change_event_data['valid']:
return True, change_dict
def get_presence_bitmap(self):
bitmap = 0
for sfp in self._sfp_list:
modpres = sfp.get_presence()
i=sfp.port_num-1
if modpres:
bitmap = bitmap | (1 << i)
return bitmap
changed_ports = self.sfp_change_event_data['present'] ^ bitmap
if changed_ports:
def get_sfp_event(self, timeout=2000):
port_dict = {}
change_dict = {}
change_dict['sfp'] = port_dict
if timeout < 1000:
cd_ms = 1000
else:
cd_ms = timeout
while cd_ms > 0:
bitmap = self.get_presence_bitmap()
changed_ports = self._sfp_change_event_data['present'] ^ bitmap
if changed_ports != 0:
break
time.sleep(POLL_INTERVAL_IN_SEC)
# timeout=0 means wait for event forever
if timeout != 0:
cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000
if changed_ports != 0:
for sfp in self._sfp_list:
i=sfp.port_num-1
if (changed_ports & (1 << i)):
@ -47,9 +54,7 @@ class SfpEvent:
# Update the cache dict
self.sfp_change_event_data['present'] = bitmap
self.sfp_change_event_data['last'] = now
self.sfp_change_event_data['valid'] = 1
self._sfp_change_event_data['present'] = bitmap
return True, change_dict
else:
return True, change_dict

View File

@ -15,9 +15,10 @@ except ImportError as e:
raise ImportError(str(e) + "- required module not found")
PSU_FAN_MAX_RPM = 26688
CPLD_I2C_PATH = "/sys/bus/i2c/devices/3-0063/fan"
PSU_HWMON_I2C_PATH ="/sys/bus/i2c/devices/{}-00{}/"
PSU_I2C_MAPPING = {
SPEED_TOLERANCE = 15
CPLD_FAN_I2C_PATH = "/sys/bus/i2c/devices/3-0063/fan"
I2C_PATH ="/sys/bus/i2c/devices/{}-00{}/"
PSU_HWMON_I2C_MAPPING = {
0: {
"num": 11,
"addr": "58"
@ -28,6 +29,20 @@ PSU_I2C_MAPPING = {
},
}
PSU_CPLD_I2C_MAPPING = {
0: {
"num": 11,
"addr": "50"
},
1: {
"num": 12,
"addr": "53"
},
}
FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R",
"FAN-3F", "FAN-3R", "FAN-4F", "FAN-4R",
"FAN-5F", "FAN-5R"]
@ -42,13 +57,18 @@ class Fan(FanBase):
self.is_psu_fan = is_psu_fan
if self.is_psu_fan:
self.psu_index = psu_index
self.psu_i2c_num = PSU_I2C_MAPPING[self.psu_index]['num']
self.psu_i2c_addr = PSU_I2C_MAPPING[self.psu_index]['addr']
self.psu_hwmon_path = PSU_HWMON_I2C_PATH.format(
self.psu_i2c_num = PSU_HWMON_I2C_MAPPING[self.psu_index]['num']
self.psu_i2c_addr = PSU_HWMON_I2C_MAPPING[self.psu_index]['addr']
self.psu_hwmon_path = I2C_PATH.format(
self.psu_i2c_num, self.psu_i2c_addr)
self.psu_i2c_num = PSU_CPLD_I2C_MAPPING[self.psu_index]['num']
self.psu_i2c_addr = PSU_CPLD_I2C_MAPPING[self.psu_index]['addr']
self.psu_cpld_path = I2C_PATH.format(
self.psu_i2c_num, self.psu_i2c_addr)
FanBase.__init__(self)
def get_direction(self):
"""
@ -60,9 +80,9 @@ class Fan(FanBase):
if not self.is_psu_fan:
dir_str = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_direction')
dir_str = "{}{}{}".format(CPLD_FAN_I2C_PATH, self.fan_tray_index+1, '_direction')
val=self._api_helper.read_txt_file(dir_str)
if val is not None:
if val is not None:
if int(val, 10)==0:
direction=self.FAN_DIRECTION_EXHAUST
else:
@ -90,26 +110,26 @@ class Fan(FanBase):
Returns:
An integer, the percentage of full fan speed, in the range 0 (off)
to 100 (full speed)
"""
speed = 0
if self.is_psu_fan:
psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_speed_rpm')
fan_speed_rpm = self._api_helper.read_txt_file(psu_fan_path)
if fan_speed_rpm is not None:
speed = (int(fan_speed_rpm,10))*100/26688
speed = (int(fan_speed_rpm,10))*100/26688
if speed > 100:
speed=100
else:
return 0
elif self.get_presence():
speed_path = "{}{}".format(CPLD_I2C_PATH, '_duty_cycle_percentage')
speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, '_duty_cycle_percentage')
speed=self._api_helper.read_txt_file(speed_path)
if speed is None:
return 0
return int(speed)
def get_target_speed(self):
"""
Retrieves the target (expected) speed of the fan
@ -123,7 +143,7 @@ class Fan(FanBase):
0 : when PWM mode is use
pwm : when pwm mode is not use
"""
return False #Not supported
return self.get_speed()
def get_speed_tolerance(self):
"""
@ -132,7 +152,7 @@ class Fan(FanBase):
An integer, the percentage of variance from target speed which is
considered tolerable
"""
return False #Not supported
return SPEED_TOLERANCE
def set_speed(self, speed):
"""
@ -146,7 +166,7 @@ class Fan(FanBase):
"""
if not self.is_psu_fan and self.get_presence():
speed_path = "{}{}".format(CPLD_I2C_PATH, '_duty_cycle_percentage')
speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, '_duty_cycle_percentage')
return self._api_helper.write_txt_file(speed_path, int(speed))
return False
@ -195,17 +215,18 @@ class Fan(FanBase):
Returns:
bool: True if FAN is present, False if not
"""
present_path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_present')
val=self._api_helper.read_txt_file(present_path)
if not self.is_psu_fan:
if val is not None:
return int(val, 10)==1
else:
return False
if self.is_psu_fan:
present_path="{}{}".format(self.psu_cpld_path, 'psu_present')
else:
return True
present_path = "{}{}{}".format(CPLD_FAN_I2C_PATH, self.fan_tray_index+1, '_present')
val=self._api_helper.read_txt_file(present_path)
if val is not None:
return int(val, 10)==1
else:
return False
def get_status(self):
"""
@ -221,7 +242,7 @@ class Fan(FanBase):
else:
return False
else:
path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_index+1, '_fault')
path = "{}{}{}".format(CPLD_FAN_I2C_PATH, self.fan_tray_index+1, '_fault')
val=self._api_helper.read_txt_file(path)
if val is not None:
return int(val, 10)==0
@ -245,3 +266,25 @@ class Fan(FanBase):
string: Serial number of device
"""
return "N/A"
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device.
If the agent cannot determine the parent-relative position
for some reason, or if the associated value of
entPhysicalContainedIn is'0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device
or -1 if cannot determine the position
"""
return (self.fan_index+1) \
if not self.is_psu_fan else (self.psu_index+1)
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True if not self.is_psu_fan else False

View File

@ -0,0 +1,90 @@
########################################################################
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Fan-Drawers' information available in the platform.
#
########################################################################
try:
from sonic_platform_base.fan_drawer_base import FanDrawerBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
FANS_PER_FANTRAY = 2
class FanDrawer(FanDrawerBase):
"""Platform-specific Fan class"""
def __init__(self, fantray_index):
FanDrawerBase.__init__(self)
# FanTray is 0-based in platforms
self.fantrayindex = fantray_index
self.__initialize_fan_drawer()
def __initialize_fan_drawer(self):
from sonic_platform.fan import Fan
for i in range(FANS_PER_FANTRAY):
self._fan_list.append(Fan(self.fantrayindex, i))
def get_name(self):
"""
Retrieves the fan drawer name
Returns:
string: The name of the device
"""
return "FanTray{}".format(self.fantrayindex+1)
def get_presence(self):
"""
Retrieves the presence of the device
Returns:
bool: True if device is present, False if not
"""
return self._fan_list[0].get_presence()
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return self._fan_list[0].get_model()
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return self._fan_list[0].get_serial()
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return self._fan_list[0].get_status()
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device.
If the agent cannot determine the parent-relative position
for some reason, or if the associated value of
entPhysicalContainedIn is'0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device
or -1 if cannot determine the position
"""
return (self.fantrayindex+1)
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True

View File

@ -51,7 +51,7 @@ class APIHelper():
def read_txt_file(self, file_path):
try:
with open(file_path, 'r') as fd:
with open(file_path, 'r', errors='replace') as fd:
data = fd.read()
return data.strip()
except IOError:

View File

@ -10,7 +10,7 @@
try:
from sonic_platform_base.psu_base import PsuBase
#from sonic_platform.fan import Fan
from sonic_platform.thermal import Thermal
from .helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
@ -64,6 +64,8 @@ class Psu(PsuBase):
for fan_index in range(0, PSU_NUM_FAN[self.index]):
fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index)
self._fan_list.append(fan)
self._thermal_list.append(Thermal(is_psu=True, psu_index=self.index))
def get_voltage(self):
"""
@ -154,7 +156,7 @@ class Psu(PsuBase):
return float(val)/1000
else:
return 0
def get_temperature_high_threshold(self):
"""
Retrieves the high threshold temperature of PSU
@ -251,3 +253,20 @@ class Psu(PsuBase):
if serial is None:
return "N/A"
return serial
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
"""
return self.index+1
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True

View File

@ -13,108 +13,14 @@ import sys
from ctypes import create_string_buffer
try:
from sonic_platform_base.sfp_base import SfpBase
from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom
from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId
from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom
from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId
#from sonic_platform_base.sonic_sfp.sff8472 import sffbase
from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper
from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase
from .helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
CPLD_I2C_PATH = "/sys/bus/i2c/devices/"
QSFP_INFO_OFFSET = 128
QSFP_DOM_OFFSET = 0
SFP_INFO_OFFSET = 0
SFP_DOM_OFFSET = 256
XCVR_INTFACE_BULK_OFFSET = 0
XCVR_INTFACE_BULK_WIDTH_QSFP = 20
XCVR_INTFACE_BULK_WIDTH_SFP = 21
XCVR_HW_REV_WIDTH_QSFP = 2
XCVR_HW_REV_WIDTH_SFP = 4
XCVR_CABLE_LENGTH_WIDTH_QSFP = 5
XCVR_VENDOR_NAME_OFFSET = 20
XCVR_VENDOR_NAME_WIDTH = 16
XCVR_VENDOR_OUI_OFFSET = 37
XCVR_VENDOR_OUI_WIDTH = 3
XCVR_VENDOR_PN_OFFSET = 40
XCVR_VENDOR_PN_WIDTH = 16
XCVR_HW_REV_OFFSET = 56
XCVR_HW_REV_WIDTH_OSFP = 2
XCVR_HW_REV_WIDTH_SFP = 4
XCVR_VENDOR_SN_OFFSET = 68
XCVR_VENDOR_SN_WIDTH = 16
XCVR_VENDOR_DATE_OFFSET = 84
XCVR_VENDOR_DATE_WIDTH = 8
XCVR_DOM_CAPABILITY_OFFSET = 92
XCVR_DOM_CAPABILITY_WIDTH = 1
# Offset for values in QSFP eeprom
QSFP_DOM_REV_OFFSET = 1
QSFP_DOM_REV_WIDTH = 1
QSFP_TEMPE_OFFSET = 22
QSFP_TEMPE_WIDTH = 2
QSFP_VOLT_OFFSET = 26
QSFP_VOLT_WIDTH = 2
QSFP_CHANNL_MON_OFFSET = 34
QSFP_CHANNL_MON_WIDTH = 16
QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24
QSFP_CONTROL_OFFSET = 86
QSFP_CONTROL_WIDTH = 8
QSFP_CHANNL_RX_LOS_STATUS_OFFSET = 3
QSFP_CHANNL_RX_LOS_STATUS_WIDTH = 1
QSFP_CHANNL_TX_FAULT_STATUS_OFFSET = 4
QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1
QSFP_POWEROVERRIDE_OFFSET = 93
QSFP_POWEROVERRIDE_WIDTH = 1
QSFP_MODULE_THRESHOLD_OFFSET = 128
QSFP_MODULE_THRESHOLD_WIDTH = 24
QSFP_CHANNEL_THRESHOLD_OFFSET = 176
QSFP_CHANNEL_THRESHOLD_WIDTH = 16
qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)',
'Length OM2(m)', 'Length OM1(m)',
'Length Cable Assembly(m)')
qsfp_compliance_code_tup = ('10/40G Ethernet Compliance Code', 'SONET Compliance codes',
'SAS/SATA compliance codes', 'Gigabit Ethernet Compliant codes',
'Fibre Channel link length/Transmitter Technology',
'Fibre Channel transmission media', 'Fibre Channel Speed')
# Offset for values in SFP eeprom
SFP_TEMPE_OFFSET = 96
SFP_TEMPE_WIDTH = 2
SFP_VOLT_OFFSET = 98
SFP_VOLT_WIDTH = 2
SFP_CHANNL_MON_OFFSET = 100
SFP_CHANNL_MON_WIDTH = 6
SFP_MODULE_THRESHOLD_OFFSET = 0
SFP_MODULE_THRESHOLD_WIDTH = 40
SFP_CHANNL_THRESHOLD_OFFSET = 112
SFP_CHANNL_THRESHOLD_WIDTH = 2
SFP_STATUS_CONTROL_OFFSET = 110
SFP_STATUS_CONTROL_WIDTH = 1
SFP_TX_DISABLE_HARD_BIT = 7
SFP_TX_DISABLE_SOFT_BIT = 6
sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)',
'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)',
'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)')
sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode',
'ESCONComplianceCodes', 'SONETComplianceCodes',
'EthernetComplianceCodes', 'FibreChannelLinkLength',
'FibreChannelTechnology', 'SFP+CableTechnology',
'FibreChannelTransmissionMedia', 'FibreChannelSpeed')
class Sfp(SfpBase):
class Sfp(SfpOptoeBase):
"""Platform-specific Sfp class"""
# Port number
@ -125,7 +31,7 @@ class Sfp(SfpBase):
# Path to sysfs
PLATFORM_ROOT_PATH = "/usr/share/sonic/device"
PMON_HWSKU_PATH = "/usr/share/sonic/hwsku"
HOST_CHK_CMD = "docker > /dev/null 2>&1"
HOST_CHK_CMD = "which systemctl > /dev/null 2>&1"
PLATFORM = "x86_64-accton_as5835_54x-r0"
HWSKU = "Accton-AS5835-54X"
@ -194,6 +100,7 @@ class Sfp(SfpBase):
}
def __init__(self, sfp_index=0):
SfpOptoeBase.__init__(self)
self._api_helper=APIHelper()
# Init index
self.index = sfp_index
@ -204,44 +111,15 @@ class Sfp(SfpBase):
self.port_to_eeprom_mapping = {}
for x in range(self.PORT_START, self.PORT_END + 1):
self.port_to_eeprom_mapping[x] = eeprom_path.format(self._port_to_i2c_mapping[x])
def get_eeprom_path(self):
return self.port_to_eeprom_mapping[self.port_num]
self.info_dict_keys = ['type', 'vendor_rev', 'serial', 'manufacturer', 'model', 'connector', 'encoding', 'ext_identifier',
'ext_rateselect_compliance', 'cable_type', 'cable_length', 'nominal_bit_rate', 'specification_compliance', 'vendor_date', 'vendor_oui',
'application_advertisement', 'type_abbrv_name']
self.dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage',
'rx1power', 'rx2power', 'rx3power', 'rx4power', 'tx1bias', 'tx2bias', 'tx3bias', 'tx4bias', 'tx1power', 'tx2power', 'tx3power', 'tx4power']
self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', 'rxpowerhighwarning',
'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning']
SfpBase.__init__(self)
# For cage 1~38 are at cpld2, others are at cpld3.
def __get_cpld_num(self, port_num):
return 1 if (port_num < 39) else 2
def _convert_string_to_num(self, value_str):
if "-inf" in value_str:
return 'N/A'
elif "Unknown" in value_str:
return 'N/A'
elif 'dBm' in value_str:
t_str = value_str.rstrip('dBm')
return float(t_str)
elif 'mA' in value_str:
t_str = value_str.rstrip('mA')
return float(t_str)
elif 'C' in value_str:
t_str = value_str.rstrip('C')
return float(t_str)
elif 'Volts' in value_str:
t_str = value_str.rstrip('Volts')
return float(t_str)
else:
return 'N/A'
def __is_host(self):
return os.system(self.HOST_CHK_CMD) == 0
@ -277,422 +155,6 @@ class Sfp(SfpBase):
return eeprom_raw
def get_transceiver_info(self):
"""
Retrieves transceiver info of this SFP
Returns:
A dict which contains following keys/values :
========================================================================
keys |Value Format |Information
---------------------------|---------------|----------------------------
type |1*255VCHAR |type of SFP
vendor_rev |1*255VCHAR |vendor revision of SFP
serial |1*255VCHAR |serial number of the SFP
manufacturer |1*255VCHAR |SFP vendor name
model |1*255VCHAR |SFP model name
connector |1*255VCHAR |connector information
encoding |1*255VCHAR |encoding information
ext_identifier |1*255VCHAR |extend identifier
ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance
cable_length |INT |cable length in m
nominal_bit_rate |INT |nominal bit rate by 100Mbs
specification_compliance |1*255VCHAR |specification compliance
vendor_date |1*255VCHAR |vendor date
vendor_oui |1*255VCHAR |vendor OUI
application_advertisement |1*255VCHAR |supported applications advertisement
========================================================================
"""
# check present status
if self.port_num < 49:
sfpi_obj = sff8472InterfaceId() #SFP
else:
sfpi_obj = sff8436InterfaceId() #QSFP
if not self.get_presence() or not sfpi_obj:
return {}
if self.port_num < 49:
offset = SFP_INFO_OFFSET
sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes(
(offset + XCVR_INTFACE_BULK_OFFSET), XCVR_INTFACE_BULK_WIDTH_SFP)
else:
offset = QSFP_INFO_OFFSET
sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes(
(offset + XCVR_INTFACE_BULK_OFFSET), XCVR_INTFACE_BULK_WIDTH_QSFP)
sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(
sfp_interface_bulk_raw, 0)
sfp_vendor_name_raw = self.__read_eeprom_specific_bytes(
(offset + XCVR_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH)
sfp_vendor_name_data = sfpi_obj.parse_vendor_name(
sfp_vendor_name_raw, 0)
sfp_vendor_pn_raw = self.__read_eeprom_specific_bytes(
(offset + XCVR_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH)
sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(
sfp_vendor_pn_raw, 0)
if self.port_num < 49:
sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes(
(offset + XCVR_HW_REV_OFFSET), XCVR_HW_REV_WIDTH_SFP)
else:
sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes(
(offset + XCVR_HW_REV_OFFSET), XCVR_HW_REV_WIDTH_QSFP)
sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(
sfp_vendor_rev_raw, 0)
sfp_vendor_sn_raw = self.__read_eeprom_specific_bytes(
(offset + XCVR_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH)
sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(
sfp_vendor_sn_raw, 0)
sfp_vendor_oui_raw = self.__read_eeprom_specific_bytes(
(offset + XCVR_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH)
if sfp_vendor_oui_raw is not None:
sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(
sfp_vendor_oui_raw, 0)
sfp_vendor_date_raw = self.__read_eeprom_specific_bytes(
(offset + XCVR_VENDOR_DATE_OFFSET), XCVR_VENDOR_DATE_WIDTH)
sfp_vendor_date_data = sfpi_obj.parse_vendor_date(
sfp_vendor_date_raw, 0)
transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A')
compliance_code_dict = dict()
if sfp_interface_bulk_data:
transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value']
transceiver_info_dict['connector'] = sfp_interface_bulk_data['data']['Connector']['value']
transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value']
transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value']
transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value']
transceiver_info_dict['type_abbrv_name'] = sfp_interface_bulk_data['data']['type_abbrv_name']['value']
transceiver_info_dict['manufacturer'] = sfp_vendor_name_data[
'data']['Vendor Name']['value'] if sfp_vendor_name_data else 'N/A'
transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] if sfp_vendor_pn_data else 'N/A'
transceiver_info_dict['vendor_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] if sfp_vendor_rev_data else 'N/A'
transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] if sfp_vendor_sn_data else 'N/A'
transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] if sfp_vendor_oui_data else 'N/A'
transceiver_info_dict['vendor_date'] = sfp_vendor_date_data[
'data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] if sfp_vendor_date_data else 'N/A'
transceiver_info_dict['cable_type'] = "Unknown"
transceiver_info_dict['cable_length'] = "Unknown"
if self.port_num < 49:
for key in sfp_cable_length_tup:
if key in sfp_interface_bulk_data['data']:
transceiver_info_dict['cable_type'] = key
transceiver_info_dict['cable_length'] = str(
sfp_interface_bulk_data['data'][key]['value'])
for key in sfp_compliance_code_tup:
if key in sfp_interface_bulk_data['data']['Specification compliance']['value']:
compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value']
transceiver_info_dict['specification_compliance'] = str(
compliance_code_dict)
transceiver_info_dict['nominal_bit_rate'] = str(
sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value'])
else:
for key in qsfp_cable_length_tup:
if key in sfp_interface_bulk_data['data']:
transceiver_info_dict['cable_type'] = key
transceiver_info_dict['cable_length'] = str(
sfp_interface_bulk_data['data'][key]['value'])
for key in qsfp_compliance_code_tup:
if key in sfp_interface_bulk_data['data']['Specification compliance']['value']:
compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value']
transceiver_info_dict['specification_compliance'] = str(
compliance_code_dict)
transceiver_info_dict['nominal_bit_rate'] = str(
sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value'])
return transceiver_info_dict
def get_transceiver_bulk_status(self):
"""
Retrieves transceiver bulk status of this SFP
Returns:
A dict which contains following keys/values :
========================================================================
keys |Value Format |Information
---------------------------|---------------|----------------------------
rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not.
tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not.
reset_status |BOOLEAN |reset status, True if SFP in reset, False if not.
lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not.
tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not.
tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0
| |to channel 3.
temperature |INT |module temperature in Celsius
voltage |INT |supply voltage in mV
tx<n>bias |INT |TX Bias Current in mA, n is the channel number,
| |for example, tx2bias stands for tx bias of channel 2.
rx<n>power |INT |received optical power in mW, n is the channel number,
| |for example, rx2power stands for rx power of channel 2.
tx<n>power |INT |TX output power in mW, n is the channel number,
| |for example, tx2power stands for tx power of channel 2.
========================================================================
"""
# check present status
if self.port_num < 49: #SFP case
sfpd_obj = sff8472Dom()
if not self.get_presence() or not sfpd_obj:
return {}
eeprom_ifraw = self.__read_eeprom_specific_bytes(0, SFP_DOM_OFFSET)
sfpi_obj = sff8472InterfaceId(eeprom_ifraw)
cal_type = sfpi_obj.get_calibration_type()
sfpd_obj._calibration_type = cal_type
offset = SFP_DOM_OFFSET
transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A')
dom_temperature_raw = self.__read_eeprom_specific_bytes(
(offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH)
if dom_temperature_raw is not None:
dom_temperature_data = sfpd_obj.parse_temperature(
dom_temperature_raw, 0)
transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value']
dom_voltage_raw = self.__read_eeprom_specific_bytes(
(offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH)
if dom_voltage_raw is not None:
dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0)
transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value']
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
(offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH)
if dom_channel_monitor_raw is not None:
dom_voltage_data = sfpd_obj.parse_channel_monitor_params(
dom_channel_monitor_raw, 0)
transceiver_dom_info_dict['tx1power'] = dom_voltage_data['data']['TXPower']['value']
transceiver_dom_info_dict['rx1power'] = dom_voltage_data['data']['RXPower']['value']
transceiver_dom_info_dict['tx1bias'] = dom_voltage_data['data']['TXBias']['value']
else: #QSFP case
sfpd_obj = sff8436Dom()
sfpi_obj = sff8436InterfaceId()
if not self.get_presence() or not sfpi_obj or not sfpd_obj:
return {}
transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A')
offset = QSFP_DOM_OFFSET
offset_xcvr = QSFP_INFO_OFFSET
# QSFP capability byte parse, through this byte can know whether it support tx_power or not.
# TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436,
# need to add more code for determining the capability and version compliance
# in SFF-8636 dom capability definitions evolving with the versions.
qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes(
(offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH)
if qsfp_dom_capability_raw is not None:
qspf_dom_capability_data = sfpi_obj.parse_dom_capability(
qsfp_dom_capability_raw, 0)
else:
return None
dom_temperature_raw = self.__read_eeprom_specific_bytes(
(offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH)
if dom_temperature_raw is not None:
dom_temperature_data = sfpd_obj.parse_temperature(
dom_temperature_raw, 0)
transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value']
dom_voltage_raw = self.__read_eeprom_specific_bytes(
(offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH)
if dom_voltage_raw is not None:
dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0)
transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value']
qsfp_dom_rev_raw = self.__read_eeprom_specific_bytes(
(offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH)
if qsfp_dom_rev_raw is not None:
qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0)
qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value']
# The tx_power monitoring is only available on QSFP which compliant with SFF-8636
# and claimed that it support tx_power with one indicator bit.
dom_channel_monitor_data = {}
dom_channel_monitor_raw = None
qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['value']
if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')):
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
(offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WIDTH)
if dom_channel_monitor_raw is not None:
dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(
dom_channel_monitor_raw, 0)
else:
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
(offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH)
if dom_channel_monitor_raw is not None:
dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(
dom_channel_monitor_raw, 0)
transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TX1Power']['value']
transceiver_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value']
transceiver_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value']
transceiver_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value']
if dom_channel_monitor_raw:
transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value']
transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value']
transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value']
transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value']
transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value']
transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value']
transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value']
transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value']
#End of else
for key in transceiver_dom_info_dict:
transceiver_dom_info_dict[key] = self._convert_string_to_num(
transceiver_dom_info_dict[key])
transceiver_dom_info_dict['rx_los'] = self.get_rx_los()
transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault()
transceiver_dom_info_dict['reset_status'] = self.get_reset_status()
transceiver_dom_info_dict['lp_mode'] = self.get_lpmode()
return transceiver_dom_info_dict
def get_transceiver_threshold_info(self):
"""
Retrieves transceiver threshold info of this SFP
Returns:
A dict which contains following keys/values :
========================================================================
keys |Value Format |Information
---------------------------|---------------|----------------------------
temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius.
templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius.
temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius.
templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius.
vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV.
vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV.
vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV.
vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV.
rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm.
rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm.
rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm.
rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm.
txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm.
txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm.
txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm.
txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm.
txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA.
txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA.
txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA.
txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA.
========================================================================
"""
# check present status
if self.port_num < 49:
sfpd_obj = sff8472Dom()
if not self.get_presence() and not sfpd_obj:
return {}
eeprom_ifraw = self.__read_eeprom_specific_bytes(0, SFP_DOM_OFFSET)
sfpi_obj = sff8472InterfaceId(eeprom_ifraw)
cal_type = sfpi_obj.get_calibration_type()
sfpd_obj._calibration_type = cal_type
offset = SFP_DOM_OFFSET
transceiver_dom_threshold_info_dict = dict.fromkeys(
self.threshold_dict_keys, 'N/A')
dom_module_threshold_raw = self.__read_eeprom_specific_bytes(
(offset + SFP_MODULE_THRESHOLD_OFFSET), SFP_MODULE_THRESHOLD_WIDTH)
if dom_module_threshold_raw is not None:
dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold(
dom_module_threshold_raw, 0)
transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value']
transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value']
transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value']
transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value']
transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value']
transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value']
transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data[
'data']['VoltageHighWarning']['value']
transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value']
transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value']
transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value']
transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value']
transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value']
transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value']
transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value']
transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value']
transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value']
transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value']
transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value']
transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value']
transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value']
for key in transceiver_dom_threshold_info_dict:
transceiver_dom_threshold_info_dict[key] = self._convert_string_to_num(
transceiver_dom_threshold_info_dict[key])
return transceiver_dom_threshold_info_dict
else:
sfpd_obj = sff8436Dom()
if not self.get_presence() or not sfpd_obj:
return {}
transceiver_dom_threshold_dict = dict.fromkeys(
self.threshold_dict_keys, 'N/A')
dom_thres_raw = self.__read_eeprom_specific_bytes(
QSFP_MODULE_THRESHOLD_OFFSET, QSFP_MODULE_THRESHOLD_WIDTH) if self.get_presence() and sfpd_obj else None
if dom_thres_raw:
module_threshold_values = sfpd_obj.parse_module_threshold_values(
dom_thres_raw, 0)
module_threshold_data = module_threshold_values.get('data')
if module_threshold_data:
transceiver_dom_threshold_dict['temphighalarm'] = module_threshold_data['TempHighAlarm']['value']
transceiver_dom_threshold_dict['templowalarm'] = module_threshold_data['TempLowAlarm']['value']
transceiver_dom_threshold_dict['temphighwarning'] = module_threshold_data['TempHighWarning']['value']
transceiver_dom_threshold_dict['templowwarning'] = module_threshold_data['TempLowWarning']['value']
transceiver_dom_threshold_dict['vcchighalarm'] = module_threshold_data['VccHighAlarm']['value']
transceiver_dom_threshold_dict['vcclowalarm'] = module_threshold_data['VccLowAlarm']['value']
transceiver_dom_threshold_dict['vcchighwarning'] = module_threshold_data['VccHighWarning']['value']
transceiver_dom_threshold_dict['vcclowwarning'] = module_threshold_data['VccLowWarning']['value']
dom_thres_raw = self.__read_eeprom_specific_bytes(
QSFP_CHANNEL_THRESHOLD_OFFSET, QSFP_CHANNEL_THRESHOLD_WIDTH) if self.get_presence() and sfpd_obj else None
channel_threshold_values = sfpd_obj.parse_channel_threshold_values(
dom_thres_raw, 0)
channel_threshold_data = channel_threshold_values.get('data')
if channel_threshold_data:
transceiver_dom_threshold_dict['rxpowerhighalarm'] = channel_threshold_data['RxPowerHighAlarm']['value']
transceiver_dom_threshold_dict['rxpowerlowalarm'] = channel_threshold_data['RxPowerLowAlarm']['value']
transceiver_dom_threshold_dict['rxpowerhighwarning'] = channel_threshold_data['RxPowerHighWarning']['value']
transceiver_dom_threshold_dict['rxpowerlowwarning'] = channel_threshold_data['RxPowerLowWarning']['value']
transceiver_dom_threshold_dict['txpowerhighalarm'] = "0.0dBm"
transceiver_dom_threshold_dict['txpowerlowalarm'] = "0.0dBm"
transceiver_dom_threshold_dict['txpowerhighwarning'] = "0.0dBm"
transceiver_dom_threshold_dict['txpowerlowwarning'] = "0.0dBm"
transceiver_dom_threshold_dict['txbiashighalarm'] = channel_threshold_data['TxBiasHighAlarm']['value']
transceiver_dom_threshold_dict['txbiaslowalarm'] = channel_threshold_data['TxBiasLowAlarm']['value']
transceiver_dom_threshold_dict['txbiashighwarning'] = channel_threshold_data['TxBiasHighWarning']['value']
transceiver_dom_threshold_dict['txbiaslowwarning'] = channel_threshold_data['TxBiasLowWarning']['value']
for key in transceiver_dom_threshold_dict:
transceiver_dom_threshold_dict[key] = self._convert_string_to_num(
transceiver_dom_threshold_dict[key])
return transceiver_dom_threshold_dict
def get_reset_status(self):
"""
Retrieves the reset status of SFP
@ -725,8 +187,10 @@ class Sfp(SfpBase):
rx_path = "{}{}{}{}".format(CPLD_I2C_PATH, cpld_path, '/module_rx_los_', self.port_num)
rx_los=self._api_helper.read_txt_file(rx_path)
if rx_los is None:
return False
if int(rx_los, 10) == 1:
return [True]
else:
return [False]
#status_control_raw = self.__read_eeprom_specific_bytes(
# SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH)
#if status_control_raw:
@ -743,15 +207,18 @@ class Sfp(SfpBase):
rx_los_list.append(rx_los_data & 0x02 != 0)
rx_los_list.append(rx_los_data & 0x04 != 0)
rx_los_list.append(rx_los_data & 0x08 != 0)
rx_los = rx_los_list[0] and rx_los_list[1] and rx_los_list[2] and rx_los_list[3]
return rx_los
return rx_los_list
else:
return [False]*4
def get_tx_fault(self):
"""
Retrieves the TX fault status of SFP
Returns:
A Boolean, True if SFP has TX fault, False if not
A list of boolean values, representing the TX fault status
of each available channel, value is True if SFP channel
has TX fault, False if not.
E.g., for a tranceiver with four channels: [False, False, True, False]
Note : TX fault status is lached until a call to get_tx_fault or a reset.
"""
tx_fault = False
@ -761,8 +228,10 @@ class Sfp(SfpBase):
tx_path = "{}{}{}{}".format(CPLD_I2C_PATH, cpld_path, '/module_tx_fault_', self.port_num)
tx_fault=self._api_helper.read_txt_file(tx_path)
if tx_fault is None:
return False
if int(tx_fault, 10) == 1:
return [True]
else:
return [False]
#status_control_raw = self.__read_eeprom_specific_bytes(
# SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH)
#if status_control_raw:
@ -778,15 +247,19 @@ class Sfp(SfpBase):
tx_fault_list.append(tx_fault_data & 0x02 != 0)
tx_fault_list.append(tx_fault_data & 0x04 != 0)
tx_fault_list.append(tx_fault_data & 0x08 != 0)
tx_fault = tx_fault_list[0] and tx_fault_list[1] and tx_fault_list[2] and tx_fault_list[3]
return tx_fault_list
else:
return [False]*4
return tx_fault
def get_tx_disable(self):
"""
Retrieves the tx_disable status of this SFP
Returns:
A Boolean, True if tx_disable is enabled, False if disabled
A list of boolean values, representing the TX disable status
of each available channel, value is True if SFP channel
is TX disabled, False if not.
E.g., for a tranceiver with four channels: [False, False, True, False]
"""
if self.port_num < 49:
tx_disable = False
@ -806,10 +279,11 @@ class Sfp(SfpBase):
# tx_disable_soft = (sffbase().test_bit(
# data, SFP_TX_DISABLE_SOFT_BIT) != 0)
# tx_disable = tx_disable_hard | tx_disable_soft
if tx_disable is not None:
return tx_disable
if int(tx_disable, 10)==0:
return [False]
else:
return False
return [True]
else:
tx_disable_list = []
@ -829,8 +303,9 @@ class Sfp(SfpBase):
'On' == dom_control_data['data']['TX3Disable']['value'])
tx_disable_list.append(
'On' == dom_control_data['data']['TX4Disable']['value'])
return tx_disable_list
return tx_disable_list
else:
return [False]*4
def get_tx_disable_channel(self):
"""
@ -841,18 +316,14 @@ class Sfp(SfpBase):
As an example, a returned value of 0x5 indicates that channel 0
and channel 2 have been disabled.
"""
if self.port_num < 49:
# SFP doesn't support this feature
return False
else:
tx_disable_list = self.get_tx_disable()
if tx_disable_list is None:
return 0
tx_disabled = 0
for i in range(len(tx_disable_list)):
if tx_disable_list[i]:
tx_disabled |= 1 << i
return tx_disabled
tx_disable_list = self.get_tx_disable()
if tx_disable_list is None:
return 0
tx_disabled = 0
for i in range(len(tx_disable_list)):
if tx_disable_list[i]:
tx_disabled |= 1 << i
return tx_disabled
def get_lpmode(self):
"""
@ -915,78 +386,6 @@ class Sfp(SfpBase):
return power_override
def get_temperature(self):
"""
Retrieves the temperature of this SFP
Returns:
An integer number of current temperature in Celsius
"""
transceiver_dom_info_dict = self.get_transceiver_bulk_status()
return transceiver_dom_info_dict.get("temperature", "N/A")
def get_voltage(self):
"""
Retrieves the supply voltage of this SFP
Returns:
An integer number of supply voltage in mV
"""
transceiver_dom_info_dict = self.get_transceiver_bulk_status()
return transceiver_dom_info_dict.get("voltage", "N/A")
def get_tx_bias(self):
"""
Retrieves the TX bias current of this SFP
Returns:
A list of four integer numbers, representing TX bias in mA
for channel 0 to channel 4.
Ex. ['110.09', '111.12', '108.21', '112.09']
"""
transceiver_dom_info_dict = self.get_transceiver_bulk_status()
tx1_bs = transceiver_dom_info_dict.get("tx1bias", "N/A")
if self.port_num < 49:
return [tx1_bs, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else []
tx2_bs = transceiver_dom_info_dict.get("tx2bias", "N/A")
tx3_bs = transceiver_dom_info_dict.get("tx3bias", "N/A")
tx4_bs = transceiver_dom_info_dict.get("tx4bias", "N/A")
return [tx1_bs, tx2_bs, tx3_bs, tx4_bs] if transceiver_dom_info_dict else []
def get_rx_power(self):
"""
Retrieves the received optical power for this SFP
Returns:
A list of four integer numbers, representing received optical
power in mW for channel 0 to channel 4.
Ex. ['1.77', '1.71', '1.68', '1.70']
"""
transceiver_dom_info_dict = self.get_transceiver_bulk_status()
rx1_pw = transceiver_dom_info_dict.get("rx1power", "N/A")
if self.port_num < 49:
return [rx1_pw, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else []
rx2_pw = transceiver_dom_info_dict.get("rx2power", "N/A")
rx3_pw = transceiver_dom_info_dict.get("rx3power", "N/A")
rx4_pw = transceiver_dom_info_dict.get("rx4power", "N/A")
return [rx1_pw, rx2_pw, rx3_pw, rx4_pw] if transceiver_dom_info_dict else []
def get_tx_power(self):
"""
Retrieves the TX power of this SFP
Returns:
A list of four integer numbers, representing TX power in mW
for channel 0 to channel 4.
Ex. ['1.86', '1.86', '1.86', '1.86']
"""
transceiver_dom_info_dict = self.get_transceiver_bulk_status()
tx1_pw = transceiver_dom_info_dict.get("tx1power", "N/A")
if self.port_num < 49:
return [tx1_pw, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else []
tx2_pw = transceiver_dom_info_dict.get("tx2power", "N/A")
tx3_pw = transceiver_dom_info_dict.get("tx3power", "N/A")
tx4_pw = transceiver_dom_info_dict.get("tx4power", "N/A")
return [tx1_pw, tx2_pw, tx3_pw, tx4_pw]
def reset(self):
"""
Reset SFP and return all user module settings to their default srate.
@ -1000,15 +399,15 @@ class Sfp(SfpBase):
cpld_path = self._cpld_mapping[cpld_i]
reset_path = "{}{}{}{}".format(CPLD_I2C_PATH, cpld_path, '/module_reset_', self.port_num)
ret = self._api_helper.write_txt_file(reset_path, 1)
if ret is not True:
time.sleep(0.01)
ret = self.self._api_helper.write_txt_file(reset_path, 0)
time.sleep(0.2)
return ret
else:
return False
if ret is not True:
return ret
time.sleep(0.01)
ret = self._api_helper.write_txt_file(reset_path, 0)
time.sleep(0.2)
return ret
def tx_disable(self, tx_disable):
"""
@ -1120,7 +519,7 @@ class Sfp(SfpBase):
if self.port_num < 49:
return False # SFP doesn't support this feature
else:
if lpmode is True:
if lpmode:
self.set_power_override(True, True)
else:
self.set_power_override(False, False)
@ -1195,28 +594,27 @@ class Sfp(SfpBase):
else:
return False
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
transceiver_dom_info_dict = self.get_transceiver_info()
return transceiver_dom_info_dict.get("model", "N/A")
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
transceiver_dom_info_dict = self.get_transceiver_info()
return transceiver_dom_info_dict.get("serial", "N/A")
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return self.get_presence() and self.get_transceiver_bulk_status()
return self.get_presence()
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
"""
return self.port_num
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True

View File

@ -15,22 +15,53 @@ try:
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
PSU_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/"
PSU_HWMON_I2C_MAPPING = {
0: {
"num": 11,
"addr": "58"
},
1: {
"num": 12,
"addr": "5b"
},
}
PSU_CPLD_I2C_MAPPING = {
0: {
"num": 11,
"addr": "50"
},
1: {
"num": 12,
"addr": "53"
},
}
THERMAL_NAME_LIST = ["Temp sensor 1", "Temp sensor 2",
"Temp sensor 3", "Temp sensor 4"]
PSU_THERMAL_NAME_LIST = ["PSU-1 temp sensor 1", "PSU-2 temp sensor 2"]
SYSFS_PATH = "/sys/bus/i2c/devices"
class Thermal(ThermalBase):
"""Platform-specific Thermal class"""
THERMAL_NAME_LIST = []
SYSFS_PATH = "/sys/bus/i2c/devices"
def __init__(self, thermal_index=0):
def __init__(self, thermal_index=0, is_psu=False, psu_index=0):
self.index = thermal_index
self.is_psu = is_psu
self.psu_index = psu_index
# Add thermal name
self.THERMAL_NAME_LIST.append("Temp sensor 1")
self.THERMAL_NAME_LIST.append("Temp sensor 2")
self.THERMAL_NAME_LIST.append("Temp sensor 3")
self.THERMAL_NAME_LIST.append("Temp sensor 4")
if self.is_psu:
psu_i2c_bus = PSU_HWMON_I2C_MAPPING[psu_index]["num"]
psu_i2c_addr = PSU_HWMON_I2C_MAPPING[psu_index]["addr"]
self.psu_hwmon_path = PSU_I2C_PATH.format(psu_i2c_bus,
psu_i2c_addr)
psu_i2c_bus = PSU_CPLD_I2C_MAPPING[psu_index]["num"]
psu_i2c_addr = PSU_CPLD_I2C_MAPPING[psu_index]["addr"]
self.cpld_path = PSU_I2C_PATH.format(psu_i2c_bus, psu_i2c_addr)
# Set hwmon path
i2c_path = {
0: "18-004b/hwmon/hwmon*/",
@ -38,9 +69,9 @@ class Thermal(ThermalBase):
2: "20-0049/hwmon/hwmon*/",
3: "21-004a/hwmon/hwmon*/"
}.get(self.index, None)
self.hwmon_path = "{}/{}".format(self.SYSFS_PATH, i2c_path)
self.ss_key = self.THERMAL_NAME_LIST[self.index]
self.hwmon_path = "{}/{}".format(SYSFS_PATH, i2c_path)
self.ss_key = THERMAL_NAME_LIST[self.index]
self.ss_index = 1
def __read_txt_file(self, file_path):
@ -51,20 +82,23 @@ class Thermal(ThermalBase):
return data
except IOError as e:
pass
return None
def __get_temp(self, temp_file):
temp_file_path = os.path.join(self.hwmon_path, temp_file)
if not self.is_psu:
temp_file_path = os.path.join(self.hwmon_path, temp_file)
else:
temp_file_path = temp_file
raw_temp = self.__read_txt_file(temp_file_path)
if raw_temp is not None:
return float(raw_temp)/1000
else:
return 0
return 0
def __set_threshold(self, file_name, temperature):
if self.is_psu:
return True
temp_file_path = os.path.join(self.hwmon_path, file_name)
for filename in glob.glob(temp_file_path):
try:
@ -73,6 +107,8 @@ class Thermal(ThermalBase):
return True
except IOError as e:
print("IOError")
return False
def get_temperature(self):
@ -82,7 +118,11 @@ class Thermal(ThermalBase):
A float number of current temperature in Celsius up to nearest thousandth
of one degree Celsius, e.g. 30.125
"""
temp_file = "temp{}_input".format(self.ss_index)
if not self.is_psu:
temp_file = "temp{}_input".format(self.ss_index)
else:
temp_file = self.psu_hwmon_path + "psu_temp1_input"
return self.__get_temp(temp_file)
def get_high_threshold(self):
@ -92,6 +132,9 @@ class Thermal(ThermalBase):
A float number, the high threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
if self.is_psu:
return 80
temp_file = "temp{}_max".format(self.ss_index)
return self.__get_temp(temp_file)
@ -116,7 +159,10 @@ class Thermal(ThermalBase):
Returns:
string: The name of the thermal device
"""
return self.THERMAL_NAME_LIST[self.index]
if self.is_psu:
return PSU_THERMAL_NAME_LIST[self.psu_index]
else:
return THERMAL_NAME_LIST[self.index]
def get_presence(self):
"""
@ -124,6 +170,9 @@ class Thermal(ThermalBase):
Returns:
bool: True if Thermal is present, False if not
"""
if self.is_psu:
val = self.__read_txt_file(self.cpld_path + "psu_present")
return int(val, 10) == 1
temp_file = "temp{}_input".format(self.ss_index)
temp_file_path = os.path.join(self.hwmon_path, temp_file)
raw_txt = self.__read_txt_file(temp_file_path)
@ -138,11 +187,49 @@ class Thermal(ThermalBase):
Returns:
A boolean value, True if device is operating properly, False if not
"""
if self.is_psu:
temp_file = self.psu_hwmon_path + "psu_temp_fault"
return self.get_presence() and (not int(
self.__read_txt_file(temp_file)))
file_str = "temp{}_input".format(self.ss_index)
file_path = os.path.join(self.hwmon_path, file_str)
raw_txt = self.__read_txt_file(file_path)
if raw_txt is None:
return False
else:
else:
return int(raw_txt) != 0
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return "N/A"
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return "N/A"
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
"""
return self.index+1
def is_replaceable(self):
"""
Retrieves whether thermal module is replaceable
Returns:
A boolean value, True if replaceable, False if not
"""
return False

View File

@ -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"
}
}

View File

@ -1,67 +0,0 @@
{
"XCVR":
{
"xcvr_present":
{
"i2c":
{
"valmap-SFP": {"1":true, "0":false },
"valmap-SFP28": {"1":true, "0":false },
"valmap-QSFP28": {"1":true, "0":false}
}
}
},
"PSU":
{
"psu_present":
{
"i2c":
{
"valmap": { "1":true, "0":false }
}
},
"psu_power_good":
{
"i2c":
{
"valmap": { "1": true, "0":false }
}
},
"psu_fan_dir":
{
"i2c":
{
"valmap": { "F2B":"EXHAUST", "B2F":"INTAKE" }
}
},
"PSU_FAN_MAX_SPEED":"18000"
},
"FAN":
{
"direction":
{
"i2c":
{
"valmap": {"1":"INTAKE", "0":"EXHAUST"}
}
},
"present":
{
"i2c":
{
"valmap": {"1":true, "0":false}
}
},
"duty_cycle_to_pwm": "lambda dc: ((dc*100)/625 -1)",
"pwm_to_duty_cycle": "lambda pwm: (((pwm+1)*625+75)/100)"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -16,5 +16,10 @@ class board(eeprom_tlvinfo.TlvInfoDecoder):
_TLV_INFO_MAX_LEN = 256
def __init__(self, name, path, cpld_root, ro):
self.eeprom_path = "/sys/bus/i2c/devices/0-0056/eeprom"
exists = os.path.isfile('/sys/bus/i2c/devices/0-0056/eeprom')
if (exists is True):
self.eeprom_path = "/sys/bus/i2c/devices/0-0056/eeprom"
else:
self.eeprom_path = "/sys/bus/i2c/devices/0-0057/eeprom"
super(board, self).__init__(self.eeprom_path, 0, '', True)

View File

@ -1,5 +1,5 @@
{
"skip_ledd": true,
"skip_thermalctld": true
"skip_pcied": true
}

View File

@ -0,0 +1,2 @@
__all__ = [ "platform", "chassis", "sfp", "eeprom", "component", "psu", "thermal", "fan", "fan_drawer" ]
from . import platform

View File

@ -0,0 +1,264 @@
#############################################################################
# Edgecore
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Chassis information which are available in the platform
#
#############################################################################
import os
import sys
try:
from sonic_platform_base.chassis_base import ChassisBase
from .event import SfpEvent
from sonic_py_common import device_info
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
NUM_FAN_TRAY = 6
NUM_PSU = 2
NUM_THERMAL = 4
NUM_PORT = 58
NUM_COMPONENT = 4
HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/"
PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/"
REBOOT_CAUSE_FILE = "reboot-cause.txt"
PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt"
HOST_CHK_CMD = "which systemctl > /dev/null 2>&1"
SYSLED_FNODE= "/sys/class/leds/accton_as7326_56x_led::diag/brightness"
SYSLED_MODES = {
"0" : "STATUS_LED_COLOR_OFF",
"1" : "STATUS_LED_COLOR_GREEN",
"3" : "STATUS_LED_COLOR_RED",
"5" : "STATUS_LED_COLOR_GREEN_BLINK"
}
class Chassis(ChassisBase):
"""Platform-specific Chassis class"""
def __init__(self):
ChassisBase.__init__(self)
self.config_data = {}
(self.platform, self.hwsku) = device_info.get_platform_and_hwsku()
self.__initialize_fan()
self.__initialize_psu()
self.__initialize_thermals()
self.__initialize_components()
self.__initialize_sfp()
self.__initialize_eeprom()
def __initialize_sfp(self):
from sonic_platform.sfp import Sfp
for index in range(NUM_PORT):
sfp = Sfp(index)
self._sfp_list.append(sfp)
self._sfpevent = SfpEvent(self._sfp_list)
self.sfp_module_initialized = True
def __initialize_fan(self):
from sonic_platform.fan_drawer import FanDrawer
for fant_index in range(NUM_FAN_TRAY):
fandrawer = FanDrawer(fant_index)
self._fan_drawer_list.append(fandrawer)
self._fan_list.extend(fandrawer._fan_list)
def __initialize_psu(self):
from sonic_platform.psu import Psu
for index in range(NUM_PSU):
psu = Psu(index)
self._psu_list.append(psu)
def __initialize_thermals(self):
from sonic_platform.thermal import Thermal
for index in range(NUM_THERMAL):
thermal = Thermal(index)
self._thermal_list.append(thermal)
def __initialize_eeprom(self):
from sonic_platform.eeprom import Tlv
self._eeprom = Tlv()
def __initialize_components(self):
from sonic_platform.component import Component
for index in range(NUM_COMPONENT):
component = Component(index)
self._component_list.append(component)
def __initialize_watchdog(self):
self._watchdog = Watchdog()
def __is_host(self):
return os.system(HOST_CHK_CMD) == 0
def __read_txt_file(self, file_path):
try:
with open(file_path, 'r') as fd:
return fd.read().strip()
except IOError:
pass
return None
def __write_txt_file(self, file_path, value):
try:
with open(file_path, 'w') as fd:
fd.write(str(value))
except Exception:
return False
return True
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
return self._eeprom.get_product_name()
def get_presence(self):
"""
Retrieves the presence of the Chassis
Returns:
bool: True if Chassis is present, False if not
"""
return True
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return True
def get_base_mac(self):
"""
Retrieves the base MAC address for the chassis
Returns:
A string containing the MAC address in the format
'XX:XX:XX:XX:XX:XX'
"""
return self._eeprom.get_mac()
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return self._eeprom.get_pn()
def get_serial(self):
"""
Retrieves the hardware serial number for the chassis
Returns:
A string containing the hardware serial number for this chassis.
"""
return self._eeprom.get_serial()
def get_system_eeprom_info(self):
"""
Retrieves the full content of system EEPROM information for the chassis
Returns:
A dictionary where keys are the type code defined in
OCP ONIE TlvInfo EEPROM format and values are their corresponding
values.
"""
return self._eeprom.get_eeprom()
def get_reboot_cause(self):
"""
Retrieves the cause of the previous reboot
Returns:
A tuple (string, string) where the first element is a string
containing the cause of the previous reboot. This string must be
one of the predefined strings in this class. If the first string
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
to pass a description of the reboot cause.
"""
description = 'None'
reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) if self.__is_host(
) else (PMON_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE)
prev_reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + PREV_REBOOT_CAUSE_FILE) if self.__is_host(
) else (PMON_REBOOT_CAUSE_PATH + PREV_REBOOT_CAUSE_FILE)
sw_reboot_cause = self.__read_txt_file(reboot_cause_path) or "Unknown"
prev_sw_reboot_cause = self.__read_txt_file(prev_reboot_cause_path) or "Unknown"
if sw_reboot_cause != "Unknown":
reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE
description = sw_reboot_cause
elif prev_reboot_cause_path != "Unknown":
reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE
description = prev_sw_reboot_cause
return (reboot_cause, description)
def get_change_event(self, timeout=0):
# SFP event
if not self.sfp_module_initialized:
self.__initialize_sfp()
return self._sfpevent.get_sfp_event(timeout)
def get_sfp(self, index):
"""
Retrieves sfp represented by (1-based) index <index>
Args:
index: An integer, the index (1-based) of the sfp to retrieve.
The index should be the sequence of a physical port in a chassis,
starting from 1.
For example, 1 for Ethernet0, 2 for Ethernet4 and so on.
Returns:
An object dervied from SfpBase representing the specified sfp
"""
sfp = None
if not self.sfp_module_initialized:
self.__initialize_sfp()
try:
# The index will start from 1
sfp = self._sfp_list[index-1]
except IndexError:
sys.stderr.write("SFP index {} out of range (1-{})\n".format(
index, len(self._sfp_list)))
return sfp
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
"""
return -1
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return False
def initizalize_system_led(self):
return True
def get_status_led(self):
val = self.__read_txt_file(SYSLED_FNODE)
return SYSLED_MODES[val] if val in SYSLED_MODES else "UNKNOWN"
def set_status_led(self, color):
mode = None
for key, val in SYSLED_MODES.items():
if val == color:
mode = key
break
if mode is None:
return False
else:
return self.__write_txt_file(SYSLED_FNODE, mode)

View File

@ -0,0 +1,161 @@
#############################################################################
# Edgecore
#
# Component contains an implementation of SONiC Platform Base API and
# provides the components firmware management function
#
#############################################################################
try:
from sonic_platform_base.component_base import ComponentBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
CPLD_ADDR_MAPPING = {
"CPLD-1": "18-0060",
"CPLD-2": "12-0062",
"CPLD-3": "19-0064",
}
SYSFS_PATH = "/sys/bus/i2c/devices/"
BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version"
COMPONENT_NAME_LIST = ["CPLD-1", "CPLD-2", "CPLD-3", "BIOS"]
COMPONENT_DES_LIST = [
"CPLD-1", "CPLD-2", "CPLD-3", "Basic Input/Output System"
]
class Component(ComponentBase):
"""Platform-specific Component class"""
DEVICE_TYPE = "component"
def __init__(self, component_index=0):
ComponentBase.__init__(self)
self.index = component_index
self.name = self.get_name()
def __get_bios_version(self):
# Retrieves the BIOS firmware version
try:
with open(BIOS_VERSION_PATH, 'r') as fd:
bios_version = fd.read()
return bios_version.strip()
except Exception as e:
return None
def __get_sysfs_value(self, addr, name):
# Retrieves the cpld register value
try:
with open(SYSFS_PATH + addr + '/' + name, 'r') as fd:
return fd.read().strip()
except Exception as e:
return None
def __get_cpld_version(self):
# Retrieves the CPLD firmware version
cpld_version = dict()
for cpld_name in CPLD_ADDR_MAPPING:
try:
cpld_addr = CPLD_ADDR_MAPPING[cpld_name]
cpld_version_raw = self.__get_sysfs_value(cpld_addr, "version")
cpld_version[cpld_name] = "{}".format(
int(cpld_version_raw, 16))
except Exception as e:
cpld_version[cpld_name] = 'None'
return cpld_version
def get_name(self):
"""
Retrieves the name of the component
Returns:
A string containing the name of the component
"""
return COMPONENT_NAME_LIST[self.index]
def get_description(self):
"""
Retrieves the description of the component
Returns:
A string containing the description of the component
"""
return COMPONENT_DES_LIST[self.index]
def get_firmware_version(self):
"""
Retrieves the firmware version of module
Returns:
string: The firmware versions of the module
"""
fw_version = None
if self.name == "BIOS":
fw_version = self.__get_bios_version()
elif "CPLD" in self.name:
cpld_version = self.__get_cpld_version()
fw_version = cpld_version.get(self.name)
return fw_version
def install_firmware(self, image_path):
"""
Install firmware to module
Args:
image_path: A string, path to firmware image
Returns:
A boolean, True if install successfully, False if not
"""
raise NotImplementedError
def get_presence(self):
"""
Retrieves the presence of the device
Returns:
bool: True if device is present, False if not
"""
return True
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return 'N/A'
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return 'N/A'
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return True
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device.
If the agent cannot determine the parent-relative position
for some reason, or if the associated value of
entPhysicalContainedIn is'0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device
or -1 if cannot determine the position
"""
return -1
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return False

View File

@ -0,0 +1,139 @@
try:
import os
import sys
import re
from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo
if sys.version_info[0] >= 3:
from io import StringIO
else:
from cStringIO import StringIO
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
CACHE_ROOT = '/var/cache/sonic/decode-syseeprom'
CACHE_FILE = 'syseeprom_cache'
NULL = 'N/A'
class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
EEPROM_DECODE_HEADLINES = 6
def __init__(self):
#self._eeprom_path = "/sys/bus/i2c/devices/0-0056/eeprom"
exists = os.path.isfile('/sys/bus/i2c/devices/0-0056/eeprom')
if (exists is True):
self._eeprom_path = "/sys/bus/i2c/devices/0-0056/eeprom"
else:
self._eeprom_path = "/sys/bus/i2c/devices/0-0057/eeprom"
super(Tlv, self).__init__(self._eeprom_path, 0, '', True)
self._eeprom = self._load_eeprom()
def __parse_output(self, decode_output):
decode_output.replace('\0', '')
lines = decode_output.split('\n')
lines = lines[self.EEPROM_DECODE_HEADLINES:]
_eeprom_info_dict = dict()
for line in lines:
try:
match = re.search('(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)',
line)
if match is not None:
idx = match.group(1)
value = match.group(3).rstrip('\0')
_eeprom_info_dict[idx] = value
except Exception:
pass
return _eeprom_info_dict
def _load_eeprom(self):
original_stdout = sys.stdout
sys.stdout = StringIO()
try:
self.read_eeprom_db()
except Exception:
decode_output = sys.stdout.getvalue()
sys.stdout = original_stdout
return self.__parse_output(decode_output)
status = self.check_status()
if 'ok' not in status:
return False
if not os.path.exists(CACHE_ROOT):
try:
os.makedirs(CACHE_ROOT)
except Exception:
pass
#
# only the eeprom classes that inherit from eeprom_base
# support caching. Others will work normally
#
try:
self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE))
except Exception:
pass
e = self.read_eeprom()
if e is None:
return 0
try:
self.update_cache(e)
except Exception:
pass
self.decode_eeprom(e)
decode_output = sys.stdout.getvalue()
sys.stdout = original_stdout
(is_valid, valid_crc) = self.is_checksum_valid(e)
if not is_valid:
return False
return self.__parse_output(decode_output)
def _valid_tlv(self, eeprom_data):
tlvinfo_type_codes_list = [
self._TLV_CODE_PRODUCT_NAME,
self._TLV_CODE_PART_NUMBER,
self._TLV_CODE_SERIAL_NUMBER,
self._TLV_CODE_MAC_BASE,
self._TLV_CODE_MANUF_DATE,
self._TLV_CODE_DEVICE_VERSION,
self._TLV_CODE_LABEL_REVISION,
self._TLV_CODE_PLATFORM_NAME,
self._TLV_CODE_ONIE_VERSION,
self._TLV_CODE_MAC_SIZE,
self._TLV_CODE_MANUF_NAME,
self._TLV_CODE_MANUF_COUNTRY,
self._TLV_CODE_VENDOR_NAME,
self._TLV_CODE_DIAG_VERSION,
self._TLV_CODE_SERVICE_TAG,
self._TLV_CODE_VENDOR_EXT,
self._TLV_CODE_CRC_32
]
for code in tlvinfo_type_codes_list:
code_str = "0x{:X}".format(code)
eeprom_data[code_str] = eeprom_data.get(code_str, NULL)
return eeprom_data
def get_eeprom(self):
return self._valid_tlv(self._eeprom)
def get_pn(self):
return self._eeprom.get('0x22', NULL)
def get_serial(self):
return self._eeprom.get('0x23', NULL)
def get_mac(self):
return self._eeprom.get('0x24', NULL)
def get_product_name(self):
return self._eeprom.get('0x21', NULL)

View File

@ -0,0 +1,60 @@
try:
import time
from sonic_py_common.logger import Logger
except ImportError as e:
raise ImportError(repr(e) + " - required module not found")
POLL_INTERVAL_IN_SEC = 1
class SfpEvent:
''' Listen to insert/remove sfp events '''
def __init__(self, sfp_list):
self._sfp_list = sfp_list
self._logger = Logger()
self._sfp_change_event_data = {'present': 0}
def get_presence_bitmap(self):
bitmap = 0
for sfp in self._sfp_list:
modpres = sfp.get_presence()
i=sfp.port_num-1
if modpres:
bitmap = bitmap | (1 << i)
return bitmap
def get_sfp_event(self, timeout=2000):
port_dict = {}
change_dict = {}
change_dict['sfp'] = port_dict
if timeout < 1000:
cd_ms = 1000
else:
cd_ms = timeout
while cd_ms > 0:
bitmap = self.get_presence_bitmap()
changed_ports = self._sfp_change_event_data['present'] ^ bitmap
if changed_ports != 0:
break
time.sleep(POLL_INTERVAL_IN_SEC)
# timeout=0 means wait for event forever
if timeout != 0:
cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000
if changed_ports != 0:
for sfp in self._sfp_list:
i=sfp.port_num-1
if (changed_ports & (1 << i)):
if (bitmap & (1 << i)) == 0:
port_dict[i+1] = '0'
else:
port_dict[i+1] = '1'
# Update the cache dict
self._sfp_change_event_data['present'] = bitmap
return True, change_dict
else:
return True, change_dict

View File

@ -0,0 +1,270 @@
#############################################################################
# Edgecore
#
# Module contains an implementation of SONiC Platform Base API and
# provides the fan status which are available in the platform
#
#############################################################################
try:
from sonic_platform_base.fan_base import FanBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
FAN_MAX_RPM = 25500
PSU_FAN_MAX_RPM = 25500
SPEED_TOLERANCE = 15
CPLD_I2C_PATH = "/sys/bus/i2c/devices/11-0066/fan"
PSU_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/"
PSU_HWMON_I2C_MAPPING = {
0: {
"bus": 17,
"addr": "59"
},
1: {
"bus": 13,
"addr": "5b"
},
}
PSU_CPLD_I2C_MAPPING = {
0: {
"bus": 17,
"addr": "51"
},
1: {
"bus": 13,
"addr": "53"
},
}
FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R",
"FAN-3F", "FAN-3R", "FAN-4F", "FAN-4R",
"FAN-5F", "FAN-5R", "FAN-6F", "FAN-6R"]
class Fan(FanBase):
"""Platform-specific Fan class"""
def __init__(self,
fan_tray_index,
fan_index=0,
is_psu_fan=False,
psu_index=0):
self.fan_index = fan_index
self.fan_tray_index = fan_tray_index
self.is_psu_fan = is_psu_fan
self.psu_index = psu_index
if self.is_psu_fan:
psu_i2c_bus = PSU_HWMON_I2C_MAPPING[psu_index]["bus"]
psu_i2c_addr = PSU_HWMON_I2C_MAPPING[psu_index]["addr"]
self.psu_hwmon_path = PSU_I2C_PATH.format(psu_i2c_bus,
psu_i2c_addr)
psu_i2c_bus = PSU_CPLD_I2C_MAPPING[psu_index]["bus"]
psu_i2c_addr = PSU_CPLD_I2C_MAPPING[psu_index]["addr"]
self.cpld_path = PSU_I2C_PATH.format(psu_i2c_bus, psu_i2c_addr)
FanBase.__init__(self)
def __read_txt_file(self, file_path):
try:
with open(file_path, 'r') as fd:
return fd.read().strip()
except IOError:
pass
return ""
def __write_txt_file(self, file_path, value):
try:
with open(file_path, 'w') as fd:
fd.write(str(value))
except Exception:
return False
return True
def get_direction(self):
"""
Retrieves the direction of fan
Returns:
A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST
depending on fan direction
"""
if not self.is_psu_fan:
val = self.__read_txt_file(
CPLD_I2C_PATH + str(self.fan_tray_index+1) + "_direction")
direction = self.FAN_DIRECTION_EXHAUST if (
val == "0") else self.FAN_DIRECTION_INTAKE
else:
val = self.__read_txt_file(self.psu_hwmon_path + "psu_fan_dir")
direction = self.FAN_DIRECTION_EXHAUST if (
val == "F2B") else self.FAN_DIRECTION_INTAKE
return direction
def get_speed(self):
"""
Retrieves the speed of fan as a percentage of full speed
Returns:
An integer, the percentage of full fan speed, in the range 0 (off)
to 100 (full speed)
"""
speed = 0
if self.is_psu_fan:
speed = self.__read_txt_file(
self.psu_hwmon_path + "psu_fan1_speed_rpm")
speed = (int(speed, 10)) * 100 / PSU_FAN_MAX_RPM
speed = 100 if (speed > 100) else speed
elif self.get_presence():
speed = self.__read_txt_file(CPLD_I2C_PATH + str(
self.fan_index * 10 + self.fan_tray_index + 1) + "_input")
speed = (int(speed, 10)) * 100 / FAN_MAX_RPM
speed = 100 if (speed > 100) else speed
return int(speed)
def get_target_speed(self):
"""
Retrieves the target (expected) speed of the fan
Returns:
An integer, the percentage of full fan speed, in the range 0 (off)
to 100 (full speed)
Note:
speed_pc = pwm_target/255*100
0 : when PWM mode is use
pwm : when pwm mode is not use
"""
return self.get_speed()
def get_speed_tolerance(self):
"""
Retrieves the speed tolerance of the fan
Returns:
An integer, the percentage of variance from target speed which is
considered tolerable
"""
return SPEED_TOLERANCE
def set_speed(self, speed):
"""
Sets the fan speed
Args:
speed: An integer, the percentage of full fan speed to set fan to,
in the range 0 (off) to 100 (full speed)
Returns:
A boolean, True if speed is set successfully, False if not
"""
if not self.is_psu_fan and self.get_presence():
return self.__write_txt_file(
CPLD_I2C_PATH + "_duty_cycle_percentage", int(speed))
return False
def set_status_led(self, color):
"""
Sets the state of the fan module status LED
Args:
color: A string representing the color with which to set the
fan module status LED
Returns:
bool: True if status LED state is set successfully, False if not
"""
return False #Not supported
def get_status_led(self):
"""
Gets the state of the fan status LED
Returns:
A string, one of the predefined STATUS_LED_COLOR_* strings above
"""
status=self.get_presence()
if status is None:
return self.STATUS_LED_COLOR_OFF
return {
1: self.STATUS_LED_COLOR_GREEN,
0: self.STATUS_LED_COLOR_RED
}.get(status, self.STATUS_LED_COLOR_OFF)
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
fan_name = FAN_NAME_LIST[self.fan_tray_index*2 + self.fan_index] \
if not self.is_psu_fan \
else "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1)
return fan_name
def get_presence(self):
"""
Retrieves the presence of the PSU
Returns:
bool: True if PSU is present, False if not
"""
if self.is_psu_fan:
val = self.__read_txt_file(self.cpld_path + "psu_present")
return int(val, 10) == 1
val = self.__read_txt_file(
CPLD_I2C_PATH + str(self.fan_tray_index + 1) + "_present")
return int(val, 10)==1
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
if self.is_psu_fan:
psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_fault')
val=self.__read_txt_file(psu_fan_path)
if val is not None:
return int(val, 10)==0
else:
return False
else:
path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_fault')
val=self.__read_txt_file(path)
if val is not None:
return int(val, 10)==0
else:
return False
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return "N/A"
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return "N/A"
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device.
If the agent cannot determine the parent-relative position
for some reason, or if the associated value of
entPhysicalContainedIn is'0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device
or -1 if cannot determine the position
"""
return (self.fan_index+1) \
if not self.is_psu_fan else (self.psu_index+1)
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True if not self.is_psu_fan else False

View File

@ -0,0 +1,90 @@
########################################################################
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Fan-Drawers' information available in the platform.
#
########################################################################
try:
from sonic_platform_base.fan_drawer_base import FanDrawerBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
FANS_PER_FANTRAY = 2
class FanDrawer(FanDrawerBase):
"""Platform-specific Fan class"""
def __init__(self, fantray_index):
FanDrawerBase.__init__(self)
# FanTray is 0-based in platforms
self.fantrayindex = fantray_index
self.__initialize_fan_drawer()
def __initialize_fan_drawer(self):
from sonic_platform.fan import Fan
for i in range(FANS_PER_FANTRAY):
self._fan_list.append(Fan(self.fantrayindex, i))
def get_name(self):
"""
Retrieves the fan drawer name
Returns:
string: The name of the device
"""
return "FanTray{}".format(self.fantrayindex+1)
def get_presence(self):
"""
Retrieves the presence of the device
Returns:
bool: True if device is present, False if not
"""
return self._fan_list[0].get_presence()
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return self._fan_list[0].get_model()
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return self._fan_list[0].get_serial()
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return self._fan_list[0].get_status()
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device.
If the agent cannot determine the parent-relative position
for some reason, or if the associated value of
entPhysicalContainedIn is'0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device
or -1 if cannot determine the position
"""
return (self.fantrayindex+1)
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True

View File

@ -0,0 +1,21 @@
#############################################################################
# Edgecore
#
# Module contains an implementation of SONiC Platform Base API and
# provides the platform information
#
#############################################################################
try:
from sonic_platform_base.platform_base import PlatformBase
from sonic_platform.chassis import Chassis
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class Platform(PlatformBase):
"""Platform-specific Platform class"""
def __init__(self):
PlatformBase.__init__(self)
self._chassis = Chassis()

View File

@ -0,0 +1,264 @@
#############################################################################
# Edgecore
#
# Module contains an implementation of SONiC Platform Base API and
# provides the PSUs status which are available in the platform
#
#############################################################################
#import sonic_platform
try:
from sonic_platform_base.psu_base import PsuBase
from sonic_platform.thermal import Thermal
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/"
PSU_NAME_LIST = ["PSU-1", "PSU-2"]
PSU_NUM_FAN = [1, 1]
PSU_HWMON_I2C_MAPPING = {
0: {
"bus": 17,
"addr": "59"
},
1: {
"bus": 13,
"addr": "5b"
},
}
PSU_CPLD_I2C_MAPPING = {
0: {
"bus": 17,
"addr": "51"
},
1: {
"bus": 13,
"addr": "53"
},
}
NUM_FAN_TRAY = 6
class Psu(PsuBase):
"""Platform-specific Psu class"""
def __init__(self, psu_index=0):
PsuBase.__init__(self)
self.index = psu_index
bus = PSU_HWMON_I2C_MAPPING[self.index]["bus"]
addr = PSU_HWMON_I2C_MAPPING[self.index]["addr"]
self.hwmon_path = I2C_PATH.format(bus, addr)
bus = PSU_CPLD_I2C_MAPPING[self.index]["bus"]
addr = PSU_CPLD_I2C_MAPPING[self.index]["addr"]
self.cpld_path = I2C_PATH.format(bus, addr)
self.__initialize_fan()
def __initialize_fan(self):
from sonic_platform.fan import Fan
self._fan_list.append(
Fan(NUM_FAN_TRAY + self.index,
is_psu_fan=True,
psu_index=self.index))
self._thermal_list.append(Thermal(is_psu=True, psu_index=self.index))
def __read_txt_file(self, file_path):
try:
with open(file_path, 'r') as fd:
return fd.read().strip()
except IOError:
pass
return None
def get_voltage(self):
"""
Retrieves current PSU voltage output
Returns:
A float number, the output voltage in volts,
e.g. 12.1
"""
val = self.__read_txt_file(self.hwmon_path + "psu_v_out")
if val is not None:
return float(val)/ 1000
else:
return 0
def get_current(self):
"""
Retrieves present electric current supplied by PSU
Returns:
A float number, the electric current in amperes, e.g 15.4
"""
val = self.__read_txt_file(self.hwmon_path + "psu_i_out")
if val is not None:
return float(val)/1000
else:
return 0
def get_power(self):
"""
Retrieves current energy supplied by PSU
Returns:
A float number, the power in watts, e.g. 302.6
"""
val = self.__read_txt_file(self.hwmon_path + "psu_p_out")
if val is not None:
return float(val)/1000
else:
return 0
def get_powergood_status(self):
"""
Retrieves the powergood status of PSU
Returns:
A boolean, True if PSU has stablized its output voltages and passed all
its internal self-tests, False if not.
"""
return self.get_status()
def set_status_led(self, color):
"""
Sets the state of the PSU status LED
Args:
color: A string representing the color with which to set the PSU status LED
Note: Only support green and off
Returns:
bool: True if status LED state is set successfully, False if not
"""
return False #Controlled by HW
def get_status_led(self):
"""
Gets the state of the PSU status LED
Returns:
A string, one of the predefined STATUS_LED_COLOR_* strings above
"""
status=self.get_status()
if status is None:
return self.STATUS_LED_COLOR_OFF
return {
1: self.STATUS_LED_COLOR_GREEN,
0: self.STATUS_LED_COLOR_RED
}.get(status, self.STATUS_LED_COLOR_OFF)
def get_temperature(self):
"""
Retrieves current temperature reading from PSU
Returns:
A float number of current temperature in Celsius up to nearest thousandth
of one degree Celsius, e.g. 30.125
"""
return self._thermal_list[0].get_temperature()
def get_temperature_high_threshold(self):
"""
Retrieves the high threshold temperature of PSU
Returns:
A float number, the high threshold temperature of PSU in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
return False #Not supported
def get_voltage_high_threshold(self):
"""
Retrieves the high threshold PSU voltage output
Returns:
A float number, the high threshold output voltage in volts,
e.g. 12.1
"""
val = self.__read_txt_file(self.hwmon_path + "psu_mfr_vout_max")
if val is not None:
return float(val)/ 1000
else:
return 0
def get_voltage_low_threshold(self):
"""
Retrieves the low threshold PSU voltage output
Returns:
A float number, the low threshold output voltage in volts,
e.g. 12.1
"""
val = self.__read_txt_file(self.hwmon_path + "psu_mfr_vout_min")
if val is not None:
return float(val)/ 1000
else:
return 0
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
return PSU_NAME_LIST[self.index]
def get_presence(self):
"""
Retrieves the presence of the PSU
Returns:
bool: True if PSU is present, False if not
"""
val = self.__read_txt_file(self.cpld_path + "psu_present")
if val is not None:
return int(val, 10) == 1
else:
return 0
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
val = self.__read_txt_file(self.cpld_path + "psu_power_good")
if val is not None:
return int(val, 10) == 1
else:
return 0
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
model = self.__read_txt_file(self.cpld_path + "psu_model_name")
if model is None:
return "N/A"
return model
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
serial = self.__read_txt_file(self.cpld_path + "psu_serial_number")
if serial is None:
return "N/A"
return serial
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
"""
return self.index+1
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True

View File

@ -0,0 +1,626 @@
#############################################################################
# Edgecore
#
# Sfp contains an implementation of SONiC Platform Base API and
# provides the sfp device status which are available in the platform
#
#############################################################################
import os
import time
import sys
from ctypes import create_string_buffer
try:
from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase
from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
CPLD_ADDR_MAPPING = {
0: {
"bus": 18,
"addr": "60"
}, # port 31-56
1: {
"bus": 12,
"addr": "62"
}, # port 1-30
}
CPLD_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/"
class Sfp(SfpOptoeBase):
"""Platform-specific Sfp class"""
# Port number
PORT_START = 1
PORT_END = 58
# Path to sysfs
PLATFORM_ROOT_PATH = "/usr/share/sonic/device"
PMON_HWSKU_PATH = "/usr/share/sonic/hwsku"
HOST_CHK_CMD = "which systemctl > /dev/null 2>&1"
PLATFORM = "x86_64-accton_as7326_56x-r0"
HWSKU = "Accton-AS7326-56X"
_port_to_i2c_mapping = {
1: [42],
2: [41],
3: [44],
4: [43],
5: [47],
6: [45],
7: [46],
8: [50],
9: [48],
10: [49],
11: [52],
12: [51],
13: [53],
14: [56],
15: [55],
16: [54],
17: [58],
18: [57],
19: [60],
20: [59],
21: [61],
22: [63],
23: [62],
24: [64],
25: [66],
26: [68],
27: [65],
28: [67],
29: [69],
30: [71],
31: [72],
32: [70],
33: [74],
34: [73],
35: [76],
36: [75],
37: [77],
38: [79],
39: [78],
40: [80],
41: [81],
42: [82],
43: [84],
44: [85],
45: [83],
46: [87],
47: [88],
48: [86],
49: [25],
50: [26],
51: [27],
52: [28],
53: [29],
54: [30],
55: [31],
56: [32],
57: [22],
58: [23]
}
def __init__(self, sfp_index=0):
SfpOptoeBase.__init__(self)
# Init index
self.index = sfp_index
self.port_num = self.index + 1
cpld_idx = 0 if self.port_num > 30 else 1
bus = CPLD_ADDR_MAPPING[cpld_idx]["bus"]
addr = CPLD_ADDR_MAPPING[cpld_idx]["addr"]
self.cpld_path = CPLD_I2C_PATH.format(bus, addr)
# Init eeprom path
eeprom_path = '/sys/bus/i2c/devices/{0}-0050/eeprom'
self.port_to_eeprom_mapping = {}
for x in range(self.PORT_START, self.PORT_END + 1):
self.port_to_eeprom_mapping[x] = eeprom_path.format(
self._port_to_i2c_mapping[x][0])
def get_eeprom_path(self):
return self.port_to_eeprom_mapping[self.port_num]
def __read_txt_file(self, file_path):
try:
with open(file_path, 'r') as fd:
return fd.read().strip()
except IOError:
pass
return ""
def __write_txt_file(self, file_path, value):
try:
with open(file_path, 'w') as fd:
fd.write(str(value))
except Exception:
return False
return True
def __is_host(self):
return os.system(self.HOST_CHK_CMD) == 0
def __get_path_to_port_config_file(self):
platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM])
hwsku_path = "/".join(
[platform_path,
self.HWSKU]) if self.__is_host() else self.PMON_HWSKU_PATH
return "/".join([hwsku_path, "port_config.ini"])
def __read_eeprom_specific_bytes(self, offset, num_bytes):
sysfsfile_eeprom = None
eeprom_raw = []
for i in range(0, num_bytes):
eeprom_raw.append("0x00")
sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[
self.port_num]
try:
sysfsfile_eeprom = open(
sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0)
sysfsfile_eeprom.seek(offset)
raw = sysfsfile_eeprom.read(num_bytes)
for n in range(0, num_bytes):
if sys.version_info[0] >= 3:
eeprom_raw[n] = hex(raw[n])[2:].zfill(2)
else:
eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2)
except Exception:
pass
finally:
if sysfsfile_eeprom:
sysfsfile_eeprom.close()
return eeprom_raw
def get_reset_status(self):
"""
Retrieves the reset status of SFP
Returns:
A Boolean, True if reset enabled, False if disabled
"""
if self.port_num <= 48 or self.port_num >=57:
return False # SPF port doesn't support this feature
val = self.__read_txt_file(
self.cpld_path + "module_reset_" + str(self.port_num))
return int(val, 10) == 1
def get_rx_los(self):
"""
Retrieves the RX LOS (lost-of-signal) status of SFP
Returns:
A Boolean, True if SFP has RX LOS, False if not.
Note : RX LOS status is latched until a call to get_rx_los or a reset.
"""
if self.port_num <= 48 or self.port_num >=57:
rx_los = self.__read_txt_file(
self.cpld_path + "module_rx_los_" + str(self.port_num))
if int(rx_los, 10) == 1:
return [True]
else:
return [False]
#status_control_raw = self.__read_eeprom_specific_bytes(
# SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH)
#if status_control_raw:
# data = int(status_control_raw[0], 16)
# rx_los = (sffbase().test_bit(data, 1) != 0)
else:
rx_los_list = []
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
QSFP_CHANNL_RX_LOS_STATUS_OFFSET,
QSFP_CHANNL_RX_LOS_STATUS_WIDTH) if self.get_presence(
) else None
if dom_channel_monitor_raw is not None:
rx_los_data = int(dom_channel_monitor_raw[0], 16)
rx_los_list.append(rx_los_data & 0x01 != 0)
rx_los_list.append(rx_los_data & 0x02 != 0)
rx_los_list.append(rx_los_data & 0x04 != 0)
rx_los_list.append(rx_los_data & 0x08 != 0)
return rx_los_list
else:
return [False]*4
def get_tx_fault(self):
"""
Retrieves the TX fault status of SFP
Returns:
A list of boolean values, representing the TX fault status
of each available channel, value is True if SFP channel
has TX fault, False if not.
E.g., for a tranceiver with four channels: [False, False, True, False]
Note : TX fault status is lached until a call to get_tx_fault or a reset.
"""
tx_fault = False
if self.port_num <= 48 or self.port_num >=57:
tx_fault = self.__read_txt_file(
self.cpld_path + "module_tx_fault_" + str(self.port_num))
if int(tx_fault, 10) == 1:
return [True]
else:
return [False]
#status_control_raw = self.__read_eeprom_specific_bytes(
# SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH)
#if status_control_raw:
# data = int(status_control_raw[0], 16)
# tx_fault = (sffbase().test_bit(data, 2) != 0)
else:
tx_fault_list = []
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
QSFP_CHANNL_TX_FAULT_STATUS_OFFSET,
QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) if self.get_presence(
) else None
if dom_channel_monitor_raw is not None:
tx_fault_data = int(dom_channel_monitor_raw[0], 16)
tx_fault_list.append(tx_fault_data & 0x01 != 0)
tx_fault_list.append(tx_fault_data & 0x02 != 0)
tx_fault_list.append(tx_fault_data & 0x04 != 0)
tx_fault_list.append(tx_fault_data & 0x08 != 0)
return tx_fault_list
else:
return [False]*4
def get_tx_disable(self):
"""
Retrieves the tx_disable status of this SFP
Returns:
A list of boolean values, representing the TX disable status
of each available channel, value is True if SFP channel
is TX disabled, False if not.
E.g., for a tranceiver with four channels: [False, False, True, False]
"""
if self.port_num <= 48 or self.port_num >=57:
tx_disable = False
status_control_raw = self.__read_eeprom_specific_bytes(
SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH)
if status_control_raw:
cpld_val = self.__read_txt_file(
self.cpld_path + "module_tx_disable_" + str(self.port_num))
tx_disable_hard = (int(cpld_val, 10) == 1)
data = int(status_control_raw[0], 16)
#tx_disable_hard = (sffbase().test_bit(
# data, SFP_TX_DISABLE_HARD_BIT) != 0)
tx_disable_soft = (sffbase().test_bit(
data, SFP_TX_DISABLE_SOFT_BIT) != 0)
tx_disable = tx_disable_hard | tx_disable_soft
if tx_disable==0:
return [False]
else:
return [True]
else:
return [False]
else:
tx_disable_list = []
sfpd_obj = sff8436Dom()
if sfpd_obj is None:
return [False]
dom_control_raw = self.__read_eeprom_specific_bytes(
QSFP_CONTROL_OFFSET,
QSFP_CONTROL_WIDTH) if self.get_presence() else None
if dom_control_raw is not None:
dom_control_data = sfpd_obj.parse_control_bytes(
dom_control_raw, 0)
tx_disable_list.append(
'On' == dom_control_data['data']['TX1Disable']['value'])
tx_disable_list.append(
'On' == dom_control_data['data']['TX2Disable']['value'])
tx_disable_list.append(
'On' == dom_control_data['data']['TX3Disable']['value'])
tx_disable_list.append(
'On' == dom_control_data['data']['TX4Disable']['value'])
return tx_disable_list
else:
return [False]*4
def get_tx_disable_channel(self):
"""
Retrieves the TX disabled channels in this SFP
Returns:
A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent
TX channels which have been disabled in this SFP.
As an example, a returned value of 0x5 indicates that channel 0
and channel 2 have been disabled.
"""
tx_disable_list = self.get_tx_disable()
if tx_disable_list is None:
return 0
tx_disabled = 0
for i in range(len(tx_disable_list)):
if tx_disable_list[i]:
tx_disabled |= 1 << i
return tx_disabled
def get_lpmode(self):
"""
Retrieves the lpmode (low power mode) status of this SFP
Returns:
A Boolean, True if lpmode is enabled, False if disabled
"""
if self.port_num <= 48 or self.port_num >= 57:
# SFP doesn't support this feature
return False
power_set = self.get_power_set()
power_override = self.get_power_override()
return power_set and power_override
def get_power_set(self):
if self.port_num <= 48 or self.port_num >= 57:
# SFP doesn't support this feature
return False
else:
power_set = False
sfpd_obj = sff8436Dom()
if sfpd_obj is None:
return False
dom_control_raw = self.__read_eeprom_specific_bytes(
QSFP_CONTROL_OFFSET,
QSFP_CONTROL_WIDTH) if self.get_presence() else None
if dom_control_raw is not None:
dom_control_data = sfpd_obj.parse_control_bytes(
dom_control_raw, 0)
power_set = (
'On' == dom_control_data['data']['PowerSet']['value'])
return power_set
def get_power_override(self):
"""
Retrieves the power-override status of this SFP
Returns:
A Boolean, True if power-override is enabled, False if disabled
"""
if self.port_num <= 48 or self.port_num >= 57:
return False # SFP doesn't support this feature
else:
power_override = False
sfpd_obj = sff8436Dom()
if sfpd_obj is None:
return False
dom_control_raw = self.__read_eeprom_specific_bytes(
QSFP_CONTROL_OFFSET,
QSFP_CONTROL_WIDTH) if self.get_presence() else None
if dom_control_raw is not None:
dom_control_data = sfpd_obj.parse_control_bytes(
dom_control_raw, 0)
power_override = (
'On' == dom_control_data['data']['PowerOverride']['value'])
return power_override
def reset(self):
"""
Reset SFP and return all user module settings to their default srate.
Returns:
A boolean, True if successful, False if not
"""
# Check for invalid port_num
if self.port_num <= 48 or self.port_num >=57:
return False # SFP doesn't support this feature
ret = self.__write_txt_file(
self.cpld_path + "module_reset_" + str(self.port_num), 1)
if ret is not True:
return ret
time.sleep(0.01)
ret = self.__write_txt_file(
self.cpld_path + "module_reset_" + str(self.port_num), 0)
time.sleep(0.2)
return ret
def tx_disable(self, tx_disable):
"""
Disable SFP TX for all channels
Args:
tx_disable : A Boolean, True to enable tx_disable mode, False to disable
tx_disable mode.
Returns:
A boolean, True if tx_disable is set successfully, False if not
"""
if self.port_num <= 48 or self.port_num >=57:
ret = self.__write_txt_file(
self.cpld_path + "module_tx_disable_" + str(self.port_num), 1
if tx_disable else 0)
time.sleep(0.01)
return ret
else:
if not self.get_presence():
return False
sysfsfile_eeprom = None
try:
tx_disable_ctl = 0xf if tx_disable else 0x0
buffer = create_string_buffer(1)
if sys.version_info[0] >= 3:
buffer[0] = tx_disable_ctl
else:
buffer[0] = chr(tx_disable_ctl)
# Write to eeprom
sysfsfile_eeprom = open(
self.port_to_eeprom_mapping[self.port_num], "r+b")
sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET)
sysfsfile_eeprom.write(buffer[0])
except IOError as e:
print("Error: unable to open file: %s" % str(e))
return False
finally:
if sysfsfile_eeprom is not None:
sysfsfile_eeprom.close()
time.sleep(0.01)
return True
def tx_disable_channel(self, channel, disable):
"""
Sets the tx_disable for specified SFP channels
Args:
channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3,
e.g. 0x5 for channel 0 and channel 2.
disable : A boolean, True to disable TX channels specified in channel,
False to enable
Returns:
A boolean, True if successful, False if not
"""
if self.port_num <= 48 or self.port_num >=57:
return False # SFP doesn't support this feature
else:
if not self.get_presence():
return False
sysfsfile_eeprom = None
try:
channel_state = self.get_tx_disable_channel()
for i in range(4):
channel_mask = (1 << i)
if not (channel & channel_mask):
continue
if disable:
channel_state |= channel_mask
else:
channel_state &= ~channel_mask
buffer = create_string_buffer(1)
if sys.version_info[0] >= 3:
buffer[0] = channel_state
else:
buffer[0] = chr(channel_state)
# Write to eeprom
sysfsfile_eeprom = open(
self.port_to_eeprom_mapping[self.port_num], "r+b")
sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET)
sysfsfile_eeprom.write(buffer[0])
except IOError as e:
print("Error: unable to open file: %s" % str(e))
return False
finally:
if sysfsfile_eeprom is not None:
sysfsfile_eeprom.close()
time.sleep(0.01)
return True
def set_lpmode(self, lpmode):
"""
Sets the lpmode (low power mode) of SFP
Args:
lpmode: A Boolean, True to enable lpmode, False to disable it
Note : lpmode can be overridden by set_power_override
Returns:
A boolean, True if lpmode is set successfully, False if not
"""
if self.port_num <= 48 or self.port_num >=57:
return False # SFP doesn't support this feature
if lpmode:
return self.set_power_override(True, True)
else:
return self.set_power_override(True, False)
def set_power_override(self, power_override, power_set):
"""
Sets SFP power level using power_override and power_set
Args:
power_override :
A Boolean, True to override set_lpmode and use power_set
to control SFP power, False to disable SFP power control
through power_override/power_set and use set_lpmode
to control SFP power.
power_set :
Only valid when power_override is True.
A Boolean, True to set SFP to low power mode, False to set
SFP to high power mode.
Returns:
A boolean, True if power-override and power_set are set successfully,
False if not
"""
if self.port_num <= 48 or self.port_num >=57:
return False # SFP doesn't support this feature
else:
if not self.get_presence():
return False
try:
power_override_bit = (1 << 0) if power_override else 0
power_set_bit = (1 << 1) if power_set else (1 << 3)
buffer = create_string_buffer(1)
if sys.version_info[0] >= 3:
buffer[0] = (power_override_bit | power_set_bit)
else:
buffer[0] = chr(power_override_bit | power_set_bit)
# Write to eeprom
with open(self.port_to_eeprom_mapping[self.port_num],
"r+b") as fd:
fd.seek(QSFP_POWEROVERRIDE_OFFSET)
fd.write(buffer[0])
time.sleep(0.01)
except Exception:
print("Error: unable to open file: %s" % str(e))
return False
return True
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
sfputil_helper = SfpUtilHelper()
sfputil_helper.read_porttab_mappings(
self.__get_path_to_port_config_file())
name = sfputil_helper.logical[self.index] or "Unknown"
return name
def get_presence(self):
"""
Retrieves the presence of the device
Returns:
bool: True if device is present, False if not
"""
val = self.__read_txt_file(
self.cpld_path + "module_present_" + str(self.port_num))
return val == '1'
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return self.get_presence()
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
"""
return self.port_num
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True

View File

@ -0,0 +1,232 @@
#############################################################################
# Edgecore
#
# Thermal contains an implementation of SONiC Platform Base API and
# provides the thermal device status which are available in the platform
#
#############################################################################
import os
import os.path
import glob
try:
from sonic_platform_base.thermal_base import ThermalBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
PSU_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/"
PSU_HWMON_I2C_MAPPING = {
0: {
"bus": 17,
"addr": "59"
},
1: {
"bus": 13,
"addr": "5b"
},
}
PSU_CPLD_I2C_MAPPING = {
0: {
"bus": 17,
"addr": "51"
},
1: {
"bus": 13,
"addr": "53"
},
}
class Thermal(ThermalBase):
"""Platform-specific Thermal class"""
THERMAL_NAME_LIST = []
PSU_THERMAL_NAME_LIST = []
SYSFS_PATH = "/sys/bus/i2c/devices"
def __init__(self, thermal_index=0, is_psu=False, psu_index=0):
self.index = thermal_index
self.is_psu = is_psu
self.psu_index = psu_index
if self.is_psu:
psu_i2c_bus = PSU_HWMON_I2C_MAPPING[psu_index]["bus"]
psu_i2c_addr = PSU_HWMON_I2C_MAPPING[psu_index]["addr"]
self.psu_hwmon_path = PSU_I2C_PATH.format(psu_i2c_bus,
psu_i2c_addr)
psu_i2c_bus = PSU_CPLD_I2C_MAPPING[psu_index]["bus"]
psu_i2c_addr = PSU_CPLD_I2C_MAPPING[psu_index]["addr"]
self.cpld_path = PSU_I2C_PATH.format(psu_i2c_bus, psu_i2c_addr)
# Add thermal name
self.THERMAL_NAME_LIST.append("Temp sensor 1")
self.THERMAL_NAME_LIST.append("Temp sensor 2")
self.THERMAL_NAME_LIST.append("Temp sensor 3")
self.THERMAL_NAME_LIST.append("Temp sensor 4")
self.PSU_THERMAL_NAME_LIST.append("PSU-1 temp sensor 1")
self.PSU_THERMAL_NAME_LIST.append("PSU-2 temp sensor 1")
# Set hwmon path
i2c_path = {
0: "15-0048/hwmon/hwmon*/",
1: "15-0049/hwmon/hwmon*/",
2: "15-004a/hwmon/hwmon*/",
3: "15-004b/hwmon/hwmon*/"
}.get(self.index, None)
self.hwmon_path = "{}/{}".format(self.SYSFS_PATH, i2c_path)
self.ss_key = self.THERMAL_NAME_LIST[self.index]
self.ss_index = 1
def __read_txt_file(self, file_path):
for filename in glob.glob(file_path):
try:
with open(filename, 'r') as fd:
return fd.readline().rstrip()
except IOError as e:
pass
def __get_temp(self, temp_file):
if not self.is_psu:
temp_file_path = os.path.join(self.hwmon_path, temp_file)
else:
temp_file_path = temp_file
raw_temp = self.__read_txt_file(temp_file_path)
return float(raw_temp) / 1000
def __set_threshold(self, file_name, temperature):
if self.is_psu:
return True
temp_file_path = os.path.join(self.hwmon_path, file_name)
try:
with open(temp_file_path, 'w') as fd:
fd.write(str(temperature))
return True
except IOError:
return False
def get_temperature(self):
"""
Retrieves current temperature reading from thermal
Returns:
A float number of current temperature in Celsius up to nearest thousandth
of one degree Celsius, e.g. 30.125
"""
if not self.is_psu:
temp_file = "temp{}_input".format(self.ss_index)
else:
temp_file = self.psu_hwmon_path + "psu_temp1_input"
return self.__get_temp(temp_file)
def get_high_threshold(self):
"""
Retrieves the high threshold temperature of thermal
Returns:
A float number, the high threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
if self.is_psu:
return 0
temp_file = "temp{}_max".format(self.ss_index)
return self.__get_temp(temp_file)
def set_high_threshold(self, temperature):
"""
Sets the high threshold temperature of thermal
Args :
temperature: A float number up to nearest thousandth of one degree Celsius,
e.g. 30.125
Returns:
A boolean, True if threshold is set successfully, False if not
"""
temp_file = "temp{}_max".format(self.ss_index)
temperature = temperature *1000
self.__set_threshold(temp_file, temperature)
return True
def get_name(self):
"""
Retrieves the name of the thermal device
Returns:
string: The name of the thermal device
"""
if self.is_psu:
return self.PSU_THERMAL_NAME_LIST[self.psu_index]
else:
return self.THERMAL_NAME_LIST[self.index]
def get_presence(self):
"""
Retrieves the presence of the PSU
Returns:
bool: True if PSU is present, False if not
"""
if self.is_psu:
val = self.__read_txt_file(self.cpld_path + "psu_present")
return int(val, 10) == 1
temp_file = "temp{}_input".format(self.ss_index)
temp_file_path = os.path.join(self.hwmon_path, temp_file)
raw_txt = self.__read_txt_file(temp_file_path)
return raw_txt != None
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
if self.is_psu:
temp_file = self.psu_hwmon_path + "psu_temp_fault"
return self.get_presence() and (not int(
self.__read_txt_file(temp_file)))
file_str = "temp{}_input".format(self.ss_index)
file_path = os.path.join(self.hwmon_path, file_str)
raw_txt = self.__read_txt_file(file_path)
if raw_txt is None:
return False
else:
return int(raw_txt) != 0
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return "N/A"
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return "N/A"
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
"""
return self.index+1
def is_replaceable(self):
"""
Retrieves whether thermal module is replaceable
Returns:
A boolean value, True if replaceable, False if not
"""
return False

View File

@ -0,0 +1,15 @@
{
"services_to_ignore": [],
"devices_to_ignore": [
"asic",
"psu.temperature"
],
"user_defined_checkers": [],
"polling_interval": 60,
"led_color": {
"fault": "STATUS_LED_COLOR_RED",
"normal": "STATUS_LED_COLOR_GREEN",
"booting": "STATUS_LED_COLOR_GREEN_BLINK"
}
}

View File

@ -1,64 +0,0 @@
{
"XCVR":
{
"xcvr_present":
{
"i2c":
{
"valmap-QSFP28": {"1":true, "0":false}
}
}
},
"PSU":
{
"psu_present":
{
"i2c":
{
"valmap": { "1":true, "0":false }
}
},
"psu_power_good":
{
"i2c":
{
"valmap": { "1": true, "0":false }
}
},
"psu_fan_dir":
{
"i2c":
{
"valmap": { "F2B":"EXHAUST", "B2F":"INTAKE" }
}
},
"PSU_FAN_MAX_SPEED":"18000"
},
"FAN":
{
"direction":
{
"i2c":
{
"valmap": {"1":"INTAKE", "0":"EXHAUST"}
}
},
"present":
{
"i2c":
{
"valmap": {"1":true, "0":false}
}
},
"duty_cycle_to_pwm": "lambda dc: ((dc - 10) / 6)",
"pwm_to_duty_cycle": "lambda pwm: ( (pwm * 6) + 10)"
}
}

View File

@ -1,6 +1,5 @@
{
"skip_ledd": true,
"skip_pcied": true,
"skip_thermalctld": true
"skip_pcied": true
}

View File

@ -0,0 +1,2 @@
__all__ = [ "platform", "chassis", "sfp", "eeprom", "component", "psu", "thermal", "fan", "fan_drawer" ]
from . import platform

View File

@ -0,0 +1,250 @@
#############################################################################
# Edgecore
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Chassis information which are available in the platform
#
#############################################################################
import os
import sys
try:
from sonic_platform_base.chassis_base import ChassisBase
from .helper import APIHelper
from .event import SfpEvent
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
NUM_FAN_TRAY = 4
NUM_FAN = 2
NUM_PSU = 2
NUM_THERMAL = 6
NUM_PORT = 64
NUM_COMPONENT = 5
HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/"
PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/"
REBOOT_CAUSE_FILE = "reboot-cause.txt"
PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt"
HOST_CHK_CMD = "which systemctl > /dev/null 2>&1"
SYSLED_FNODE = "/sys/class/leds/as7816_64x_led::diag/brightness"
SYSLED_MODES = {
"0" : "STATUS_LED_COLOR_OFF",
"16" : "STATUS_LED_COLOR_GREEN",
"10" : "STATUS_LED_COLOR_RED"
}
class Chassis(ChassisBase):
"""Platform-specific Chassis class"""
def __init__(self):
ChassisBase.__init__(self)
self._api_helper = APIHelper()
self.is_host = self._api_helper.is_host()
self.config_data = {}
self.__initialize_fan()
self.__initialize_psu()
self.__initialize_thermals()
self.__initialize_components()
self.__initialize_sfp()
self.__initialize_eeprom()
def __initialize_sfp(self):
from sonic_platform.sfp import Sfp
for index in range(0, NUM_PORT):
sfp = Sfp(index)
self._sfp_list.append(sfp)
self._sfpevent = SfpEvent(self._sfp_list)
self.sfp_module_initialized = True
def __initialize_fan(self):
from sonic_platform.fan_drawer import FanDrawer
for fant_index in range(NUM_FAN_TRAY):
fandrawer = FanDrawer(fant_index)
self._fan_drawer_list.append(fandrawer)
self._fan_list.extend(fandrawer._fan_list)
def __initialize_psu(self):
from sonic_platform.psu import Psu
for index in range(0, NUM_PSU):
psu = Psu(index)
self._psu_list.append(psu)
def __initialize_thermals(self):
from sonic_platform.thermal import Thermal
for index in range(0, NUM_THERMAL):
thermal = Thermal(index)
self._thermal_list.append(thermal)
def __initialize_eeprom(self):
from sonic_platform.eeprom import Tlv
self._eeprom = Tlv()
def __initialize_components(self):
from sonic_platform.component import Component
for index in range(0, NUM_COMPONENT):
component = Component(index)
self._component_list.append(component)
def __initialize_watchdog(self):
from sonic_platform.watchdog import Watchdog
self._watchdog = Watchdog()
def __is_host(self):
return os.system(HOST_CHK_CMD) == 0
def __read_txt_file(self, file_path):
try:
with open(file_path, 'r') as fd:
data = fd.read()
return data.strip()
except IOError:
pass
return None
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
return self._eeprom.get_product_name()
def get_presence(self):
"""
Retrieves the presence of the Chassis
Returns:
bool: True if Chassis is present, False if not
"""
return True
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return True
def get_base_mac(self):
"""
Retrieves the base MAC address for the chassis
Returns:
A string containing the MAC address in the format
'XX:XX:XX:XX:XX:XX'
"""
return self._eeprom.get_mac()
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return self._eeprom.get_pn()
def get_serial(self):
"""
Retrieves the hardware serial number for the chassis
Returns:
A string containing the hardware serial number for this chassis.
"""
return self._eeprom.get_serial()
def get_system_eeprom_info(self):
"""
Retrieves the full content of system EEPROM information for the chassis
Returns:
A dictionary where keys are the type code defined in
OCP ONIE TlvInfo EEPROM format and values are their corresponding
values.
"""
return self._eeprom.get_eeprom()
def get_reboot_cause(self):
"""
Retrieves the cause of the previous reboot
Returns:
A tuple (string, string) where the first element is a string
containing the cause of the previous reboot. This string must be
one of the predefined strings in this class. If the first string
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
to pass a description of the reboot cause.
"""
reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE)
sw_reboot_cause = self._api_helper.read_txt_file(
reboot_cause_path) or "Unknown"
return ('REBOOT_CAUSE_NON_HARDWARE', sw_reboot_cause)
def get_change_event(self, timeout=0):
# SFP event
if not self.sfp_module_initialized:
self.__initialize_sfp()
return self._sfpevent.get_sfp_event(timeout)
def get_sfp(self, index):
"""
Retrieves sfp represented by (1-based) index <index>
Args:
index: An integer, the index (1-based) of the sfp to retrieve.
The index should be the sequence of a physical port in a chassis,
starting from 1.
For example, 1 for Ethernet0, 2 for Ethernet4 and so on.
Returns:
An object dervied from SfpBase representing the specified sfp
"""
sfp = None
if not self.sfp_module_initialized:
self.__initialize_sfp()
try:
# The index will start from 1
sfp = self._sfp_list[index-1]
except IndexError:
sys.stderr.write("SFP index {} out of range (1-{})\n".format(
index, len(self._sfp_list)))
return sfp
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
"""
return -1
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return False
def initizalize_system_led(self):
return True
def get_status_led(self):
val = self._api_helper.read_txt_file(SYSLED_FNODE)
return SYSLED_MODES[val] if val in SYSLED_MODES else "UNKNOWN"
def set_status_led(self, color):
mode = None
for key, val in SYSLED_MODES.items():
if val == color:
mode = key
break
if mode is None:
return False
else:
return self._api_helper.write_txt_file(SYSLED_FNODE, mode)

View File

@ -0,0 +1,177 @@
#############################################################################
# Edgecore
#
# Component contains an implementation of SONiC Platform Base API and
# provides the components firmware management function
#
#############################################################################
import shlex
import subprocess
try:
from sonic_platform_base.component_base import ComponentBase
from .helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
CPLD_ADDR_MAPPING = {
"CPLD1": "19-0060",
"CPLD2": "20-0062",
"CPLD3": "21-0064",
"CPLD4": "22-0066",
}
SYSFS_PATH = "/sys/bus/i2c/devices/"
BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version"
COMPONENT_LIST= [
("CPLD1", "CPLD 1"),
("CPLD2", "CPLD 2"),
("CPLD3", "CPLD 3"),
("CPLD4", "CPLD 4"),
("BIOS", "Basic Input/Output System")
]
class Component(ComponentBase):
"""Platform-specific Component class"""
DEVICE_TYPE = "component"
def __init__(self, component_index=0):
self._api_helper=APIHelper()
ComponentBase.__init__(self)
self.index = component_index
self.name = self.get_name()
def __run_command(self, command):
# Run bash command and print output to stdout
try:
process = subprocess.Popen(
shlex.split(command), stdout=subprocess.PIPE)
while True:
output = process.stdout.readline()
if output == '' and process.poll() is not None:
break
rc = process.poll()
if rc != 0:
return False
except Exception:
return False
return True
def __get_bios_version(self):
# Retrieves the BIOS firmware version
try:
with open(BIOS_VERSION_PATH, 'r') as fd:
bios_version = fd.read()
return bios_version.strip()
except Exception as e:
return None
def __get_cpld_version(self):
# Retrieves the CPLD firmware version
cpld_version = dict()
for cpld_name in CPLD_ADDR_MAPPING:
try:
cpld_path = "{}{}{}".format(SYSFS_PATH, CPLD_ADDR_MAPPING[cpld_name], '/version')
cpld_version_raw= self._api_helper.read_txt_file(cpld_path)
cpld_version[cpld_name] = "{}".format(int(cpld_version_raw,16))
except Exception as e:
print('Get exception when read cpld')
cpld_version[cpld_name] = 'None'
return cpld_version
def get_name(self):
"""
Retrieves the name of the component
Returns:
A string containing the name of the component
"""
return COMPONENT_LIST[self.index][0]
def get_description(self):
"""
Retrieves the description of the component
Returns:
A string containing the description of the component
"""
return COMPONENT_LIST[self.index][1]
def get_firmware_version(self):
"""
Retrieves the firmware version of module
Returns:
string: The firmware versions of the module
"""
fw_version = None
if self.name == "BIOS":
fw_version = self.__get_bios_version()
elif "CPLD" in self.name:
cpld_version = self.__get_cpld_version()
fw_version = cpld_version.get(self.name)
return fw_version
def install_firmware(self, image_path):
"""
Install firmware to module
Args:
image_path: A string, path to firmware image
Returns:
A boolean, True if install successfully, False if not
"""
raise NotImplementedError
def get_presence(self):
"""
Retrieves the presence of the device
Returns:
bool: True if device is present, False if not
"""
return True
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return 'N/A'
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return 'N/A'
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return True
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device.
If the agent cannot determine the parent-relative position
for some reason, or if the associated value of
entPhysicalContainedIn is'0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device
or -1 if cannot determine the position
"""
return -1
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return False

View File

@ -0,0 +1,134 @@
try:
import os
import sys
import re
if sys.version_info[0] >= 3:
from io import StringIO
else:
from cStringIO import StringIO
from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
CACHE_ROOT = '/var/cache/sonic/decode-syseeprom'
CACHE_FILE = 'syseeprom_cache'
NULL = 'N/A'
class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
EEPROM_DECODE_HEADLINES = 6
def __init__(self):
self._eeprom_path = "/sys/bus/i2c/devices/0-0056/eeprom"
super(Tlv, self).__init__(self._eeprom_path, 0, '', True)
self._eeprom = self._load_eeprom()
def __parse_output(self, decode_output):
decode_output.replace('\0', '')
lines = decode_output.split('\n')
lines = lines[self.EEPROM_DECODE_HEADLINES:]
_eeprom_info_dict = dict()
for line in lines:
try:
match = re.search(
'(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line)
if match is not None:
idx = match.group(1)
value = match.group(3).rstrip('\0')
_eeprom_info_dict[idx] = value
except Exception:
pass
return _eeprom_info_dict
def _load_eeprom(self):
original_stdout = sys.stdout
sys.stdout = StringIO()
try:
self.read_eeprom_db()
except Exception:
decode_output = sys.stdout.getvalue()
sys.stdout = original_stdout
return self.__parse_output(decode_output)
status = self.check_status()
if 'ok' not in status:
return False
if not os.path.exists(CACHE_ROOT):
try:
os.makedirs(CACHE_ROOT)
except Exception:
pass
#
# only the eeprom classes that inherit from eeprom_base
# support caching. Others will work normally
#
try:
self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE))
except Exception:
pass
e = self.read_eeprom()
if e is None:
return 0
try:
self.update_cache(e)
except Exception:
pass
self.decode_eeprom(e)
decode_output = sys.stdout.getvalue()
sys.stdout = original_stdout
(is_valid, valid_crc) = self.is_checksum_valid(e)
if not is_valid:
return False
return self.__parse_output(decode_output)
def _valid_tlv(self, eeprom_data):
tlvinfo_type_codes_list = [
self._TLV_CODE_PRODUCT_NAME,
self._TLV_CODE_PART_NUMBER,
self._TLV_CODE_SERIAL_NUMBER,
self._TLV_CODE_MAC_BASE,
self._TLV_CODE_MANUF_DATE,
self._TLV_CODE_DEVICE_VERSION,
self._TLV_CODE_LABEL_REVISION,
self._TLV_CODE_PLATFORM_NAME,
self._TLV_CODE_ONIE_VERSION,
self._TLV_CODE_MAC_SIZE,
self._TLV_CODE_MANUF_NAME,
self._TLV_CODE_MANUF_COUNTRY,
self._TLV_CODE_VENDOR_NAME,
self._TLV_CODE_DIAG_VERSION,
self._TLV_CODE_SERVICE_TAG,
self._TLV_CODE_VENDOR_EXT,
self._TLV_CODE_CRC_32
]
for code in tlvinfo_type_codes_list:
code_str = "0x{:X}".format(code)
eeprom_data[code_str] = eeprom_data.get(code_str, NULL)
return eeprom_data
def get_eeprom(self):
return self._valid_tlv(self._eeprom)
def get_pn(self):
return self._eeprom.get('0x22', NULL)
def get_serial(self):
return self._eeprom.get('0x23', NULL)
def get_mac(self):
return self._eeprom.get('0x24', NULL)
def get_product_name(self):
return self._eeprom.get('0x21', NULL)

View File

@ -0,0 +1,62 @@
try:
import time
from .helper import APIHelper
from sonic_py_common.logger import Logger
except ImportError as e:
raise ImportError(repr(e) + " - required module not found")
POLL_INTERVAL_IN_SEC = 1
class SfpEvent:
''' Listen to insert/remove sfp events '''
def __init__(self, sfp_list):
self._api_helper = APIHelper()
self._sfp_list = sfp_list
self._logger = Logger()
self._sfp_change_event_data = {'present': 0}
def get_presence_bitmap(self):
bitmap = 0
for sfp in self._sfp_list:
modpres = sfp.get_presence()
i=sfp.port_num-1
if modpres:
bitmap = bitmap | (1 << i)
return bitmap
def get_sfp_event(self, timeout=2000):
port_dict = {}
change_dict = {}
change_dict['sfp'] = port_dict
if timeout < 1000:
cd_ms = 1000
else:
cd_ms = timeout
while cd_ms > 0:
bitmap = self.get_presence_bitmap()
changed_ports = self._sfp_change_event_data['present'] ^ bitmap
if changed_ports != 0:
break
time.sleep(POLL_INTERVAL_IN_SEC)
# timeout=0 means wait for event forever
if timeout != 0:
cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000
if changed_ports != 0:
for sfp in self._sfp_list:
i=sfp.port_num-1
if (changed_ports & (1 << i)):
if (bitmap & (1 << i)) == 0:
port_dict[i+1] = '0'
else:
port_dict[i+1] = '1'
# Update the cache dict
self._sfp_change_event_data['present'] = bitmap
return True, change_dict
else:
return True, change_dict

View File

@ -0,0 +1,263 @@
#############################################################################
# Edgecore
#
# Module contains an implementation of SONiC Platform Base API and
# provides the fan status which are available in the platform
#
#############################################################################
try:
from sonic_platform_base.fan_base import FanBase
from .helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
SPEED_TOLERANCE = 15
CPLD_FAN_I2C_PATH = "/sys/bus/i2c/devices/17-0068/fan"
I2C_PATH ="/sys/bus/i2c/devices/{}-00{}/"
PSU_HWMON_I2C_MAPPING = {
0: {
"num": 10,
"addr": "5b"
},
1: {
"num": 9,
"addr": "58"
},
}
PSU_CPLD_I2C_MAPPING = {
0: {
"num": 10,
"addr": "53"
},
1: {
"num": 9,
"addr": "50"
},
}
FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R",
"FAN-3F", "FAN-3R", "FAN-4F", "FAN-4R"]
class Fan(FanBase):
"""Platform-specific Fan class"""
def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0):
self._api_helper=APIHelper()
self.fan_index = fan_index
self.fan_tray_index = fan_tray_index
self.is_psu_fan = is_psu_fan
if self.is_psu_fan:
self.psu_index = psu_index
self.psu_i2c_num = PSU_HWMON_I2C_MAPPING[self.psu_index]['num']
self.psu_i2c_addr = PSU_HWMON_I2C_MAPPING[self.psu_index]['addr']
self.psu_hwmon_path = I2C_PATH.format(
self.psu_i2c_num, self.psu_i2c_addr)
self.psu_i2c_num = PSU_CPLD_I2C_MAPPING[self.psu_index]['num']
self.psu_i2c_addr = PSU_CPLD_I2C_MAPPING[self.psu_index]['addr']
self.psu_cpld_path = I2C_PATH.format(
self.psu_i2c_num, self.psu_i2c_addr)
FanBase.__init__(self)
def get_direction(self):
"""
Retrieves the direction of fan
Returns:
A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST
depending on fan direction
"""
if not self.is_psu_fan:
dir_str = "{}{}{}".format(CPLD_FAN_I2C_PATH, self.fan_tray_index+1, '_direction')
val=self._api_helper.read_txt_file(dir_str)
if val is not None: #F2B is FAN_DIRECTION_EXHAUST
direction = self.FAN_DIRECTION_EXHAUST if (
val == "0") else self.FAN_DIRECTION_INTAKE
else:
direction=self.FAN_DIRECTION_EXHAUST
else: #For PSU
direction=self.FAN_DIRECTION_EXHAUST
return direction
def get_speed(self):
"""
Retrieves the speed of fan as a percentage of full speed
Returns:
An integer, the percentage of full fan speed, in the range 0 (off)
to 100 (full speed)
"""
speed = 0
if self.is_psu_fan:
psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_speed_rpm')
fan_speed_rpm = self._api_helper.read_txt_file(psu_fan_path)
if fan_speed_rpm is not None:
speed = (int(fan_speed_rpm,10))*100/26688
if speed > 100:
speed=100
else:
return 0
elif self.get_presence():
speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, '_duty_cycle_percentage')
speed=self._api_helper.read_txt_file(speed_path)
if speed is None:
return 0
return int(speed)
def get_target_speed(self):
"""
Retrieves the target (expected) speed of the fan
Returns:
An integer, the percentage of full fan speed, in the range 0 (off)
to 100 (full speed)
Note:
speed_pc = pwm_target/255*100
0 : when PWM mode is use
pwm : when pwm mode is not use
"""
return self.get_speed()
def get_speed_tolerance(self):
"""
Retrieves the speed tolerance of the fan
Returns:
An integer, the percentage of variance from target speed which is
considered tolerable
"""
return SPEED_TOLERANCE
def set_speed(self, speed):
"""
Sets the fan speed
Args:
speed: An integer, the percentage of full fan speed to set fan to,
in the range 0 (off) to 100 (full speed)
Returns:
A boolean, True if speed is set successfully, False if not
"""
if not self.is_psu_fan and self.get_presence():
speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, '_duty_cycle_percentage')
return self._api_helper.write_txt_file(speed_path, int(speed))
return False
def set_status_led(self, color):
"""
Sets the state of the fan module status LED
Args:
color: A string representing the color with which to set the
fan module status LED
Returns:
bool: True if status LED state is set successfully, False if not
"""
return False #Not supported
def get_status_led(self):
"""
Gets the state of the fan status LED
Returns:
A string, one of the predefined STATUS_LED_COLOR_* strings above
"""
status=self.get_presence()
if status is None:
return self.STATUS_LED_COLOR_OFF
return {
1: self.STATUS_LED_COLOR_GREEN,
0: self.STATUS_LED_COLOR_RED
}.get(status, self.STATUS_LED_COLOR_OFF)
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
fan_name = FAN_NAME_LIST[self.fan_tray_index*2 + self.fan_index] \
if not self.is_psu_fan \
else "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1)
return fan_name
def get_presence(self):
"""
Retrieves the presence of the FAN
Returns:
bool: True if FAN is present, False if not
"""
present_path = "{}{}{}".format(CPLD_FAN_I2C_PATH, self.fan_tray_index+1, '_present')
val=self._api_helper.read_txt_file(present_path)
if not self.is_psu_fan:
if val is not None:
return int(val, 10)==1
else:
return False
else:
return True
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
if self.is_psu_fan:
psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_fault')
val=self._api_helper.read_txt_file(psu_fan_path)
if val is not None:
return int(val, 10)==0
else:
return False
else:
path = "{}{}{}".format(CPLD_FAN_I2C_PATH, self.fan_tray_index+1, '_fault')
val=self._api_helper.read_txt_file(path)
if val is not None:
return int(val, 10)==0
else:
return False
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return "N/A"
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return "N/A"
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device.
If the agent cannot determine the parent-relative position
for some reason, or if the associated value of
entPhysicalContainedIn is'0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device
or -1 if cannot determine the position
"""
return (self.fan_index+1) \
if not self.is_psu_fan else (self.psu_index+1)
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True if not self.is_psu_fan else False

View File

@ -0,0 +1,90 @@
########################################################################
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Fan-Drawers' information available in the platform.
#
########################################################################
try:
from sonic_platform_base.fan_drawer_base import FanDrawerBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
FANS_PER_FANTRAY = 2
class FanDrawer(FanDrawerBase):
"""Platform-specific Fan class"""
def __init__(self, fantray_index):
FanDrawerBase.__init__(self)
# FanTray is 0-based in platforms
self.fantrayindex = fantray_index
self.__initialize_fan_drawer()
def __initialize_fan_drawer(self):
from sonic_platform.fan import Fan
for i in range(FANS_PER_FANTRAY):
self._fan_list.append(Fan(self.fantrayindex, i))
def get_name(self):
"""
Retrieves the fan drawer name
Returns:
string: The name of the device
"""
return "FanTray{}".format(self.fantrayindex+1)
def get_presence(self):
"""
Retrieves the presence of the device
Returns:
bool: True if device is present, False if not
"""
return self._fan_list[0].get_presence()
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return self._fan_list[0].get_model()
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return self._fan_list[0].get_serial()
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return self._fan_list[0].get_status()
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device.
If the agent cannot determine the parent-relative position
for some reason, or if the associated value of
entPhysicalContainedIn is'0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device
or -1 if cannot determine the position
"""
return (self.fantrayindex+1)
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True

View File

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

View File

@ -0,0 +1,21 @@
#############################################################################
# Edgecore
#
# Module contains an implementation of SONiC Platform Base API and
# provides the platform information
#
#############################################################################
try:
from sonic_platform_base.platform_base import PlatformBase
from sonic_platform.chassis import Chassis
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class Platform(PlatformBase):
"""Platform-specific Platform class"""
def __init__(self):
PlatformBase.__init__(self)
self._chassis = Chassis()

View File

@ -0,0 +1,283 @@
#############################################################################
# Edgecore
#
# Module contains an implementation of SONiC Platform Base API and
# provides the PSUs status which are available in the platform
#
#############################################################################
try:
from sonic_platform_base.psu_base import PsuBase
from sonic_platform.thermal import Thermal
from .helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
I2C_PATH ="/sys/bus/i2c/devices/{0}-00{1}/"
PSU_NAME_LIST = ["PSU-1", "PSU-2"]
PSU_NUM_FAN = [1, 1]
PSU_CPLD_I2C_MAPPING = {
0: {
"num": 10,
"addr": "53"
},
1: {
"num": 9,
"addr": "50"
},
}
PSU_HWMON_I2C_MAPPING = {
0: {
"num": 10,
"addr": "5b"
},
1: {
"num": 9,
"addr": "58"
},
}
NUM_FAN_TRAY = 4
class Psu(PsuBase):
"""Platform-specific Psu class"""
def __init__(self, psu_index=0):
PsuBase.__init__(self)
self.index = psu_index
self._api_helper = APIHelper()
self.i2c_num = PSU_HWMON_I2C_MAPPING[self.index]["num"]
self.i2c_addr = PSU_HWMON_I2C_MAPPING[self.index]["addr"]
self.hwmon_path = I2C_PATH.format(self.i2c_num, self.i2c_addr)
self.i2c_num = PSU_CPLD_I2C_MAPPING[self.index]["num"]
self.i2c_addr = PSU_CPLD_I2C_MAPPING[self.index]["addr"]
self.cpld_path = I2C_PATH.format(self.i2c_num, self.i2c_addr)
self.__initialize_fan()
def __initialize_fan(self):
from sonic_platform.fan import Fan
self._fan_list.append(
Fan(NUM_FAN_TRAY + self.index,
is_psu_fan=True,
psu_index=self.index))
self._thermal_list.append(Thermal(is_psu=True, psu_index=self.index))
def __read_txt_file(self, file_path):
try:
with open(file_path, 'r') as fd:
return fd.read().strip()
except IOError:
pass
return None
def get_voltage(self):
"""
Retrieves current PSU voltage output
Returns:
A float number, the output voltage in volts,
e.g. 12.1
"""
vout_path = "{}{}".format(self.hwmon_path, 'psu_v_out')
vout_val=self._api_helper.read_txt_file(vout_path)
if vout_val is not None:
return float(vout_val)/ 1000
else:
return 0
def get_current(self):
"""
Retrieves present electric current supplied by PSU
Returns:
A float number, the electric current in amperes, e.g 15.4
"""
iout_path = "{}{}".format(self.hwmon_path, 'psu_i_out')
val=self._api_helper.read_txt_file(iout_path)
if val is not None:
return float(val)/1000
else:
return 0
def get_power(self):
"""
Retrieves current energy supplied by PSU
Returns:
A float number, the power in watts, e.g. 302.6
"""
pout_path = "{}{}".format(self.hwmon_path, 'psu_p_out')
val=self._api_helper.read_txt_file(pout_path)
if val is not None:
return float(val)/1000
else:
return 0
def get_powergood_status(self):
"""
Retrieves the powergood status of PSU
Returns:
A boolean, True if PSU has stablized its output voltages and passed all
its internal self-tests, False if not.
"""
return self.get_status()
def set_status_led(self, color):
"""
Sets the state of the PSU status LED
Args:
color: A string representing the color with which to set the PSU status LED
Note: Only support green and off
Returns:
bool: True if status LED state is set successfully, False if not
"""
return False #Controlled by HW
def get_status_led(self):
"""
Gets the state of the PSU status LED
Returns:
A string, one of the predefined STATUS_LED_COLOR_* strings above
"""
status=self.get_status()
if status is None:
return self.STATUS_LED_COLOR_OFF
return {
1: self.STATUS_LED_COLOR_GREEN,
0: self.STATUS_LED_COLOR_RED
}.get(status, self.STATUS_LED_COLOR_OFF)
def get_temperature(self):
"""
Retrieves current temperature reading from PSU
Returns:
A float number of current temperature in Celsius up to nearest thousandth
of one degree Celsius, e.g. 30.125
"""
temp_path = "{}{}".format(self.hwmon_path, 'psu_temp1_input')
val=self._api_helper.read_txt_file(temp_path)
if val is not None:
return float(val)/1000
else:
return 0
def get_temperature_high_threshold(self):
"""
Retrieves the high threshold temperature of PSU
Returns:
A float number, the high threshold temperature of PSU in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
return False #Not supported
def get_voltage_high_threshold(self):
"""
Retrieves the high threshold PSU voltage output
Returns:
A float number, the high threshold output voltage in volts,
e.g. 12.1
"""
vout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_vout_max')
vout_val=self._api_helper.read_txt_file(vout_path)
if vout_val is not None:
return float(vout_val)/ 1000
else:
return 0
def get_voltage_low_threshold(self):
"""
Retrieves the low threshold PSU voltage output
Returns:
A float number, the low threshold output voltage in volts,
e.g. 12.1
"""
vout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_vout_min')
vout_val=self._api_helper.read_txt_file(vout_path)
if vout_val is not None:
return float(vout_val)/ 1000
else:
return 0
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
return PSU_NAME_LIST[self.index]
def get_presence(self):
"""
Retrieves the presence of the PSU
Returns:
bool: True if PSU is present, False if not
"""
presence_path="{}{}".format(self.cpld_path, 'psu_present')
val=self._api_helper.read_txt_file(presence_path)
if val is not None:
return int(val, 10) == 1
else:
return 0
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
power_path="{}{}".format(self.cpld_path, 'psu_power_good')
val=self._api_helper.read_txt_file(power_path)
if val is not None:
return int(val, 10) == 1
else:
return 0
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
model_path="{}{}".format(self.hwmon_path, 'psu_mfr_model')
val=self._api_helper.read_txt_file(model_path)
if val is None:
return "N/A"
model=val[1:]
return model
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
serial_path="{}{}".format(self.hwmon_path, 'psu_mfr_serial')
val=self._api_helper.read_txt_file(serial_path)
if val is None:
return "N/A"
serial=val[1:]
return serial
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
"""
return self.index+1
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True

View File

@ -0,0 +1,506 @@
#############################################################################
# Edgecore
#
# Sfp contains an implementation of SONiC Platform Base API and
# provides the sfp device status which are available in the platform
#
#############################################################################
import os
import time
import sys
from ctypes import create_string_buffer
try:
from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase
from .helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
CPLD_I2C_PATH = "/sys/bus/i2c/devices/19-0060/"
class Sfp(SfpOptoeBase):
"""Platform-specific Sfp class"""
# Port number
PORT_START = 1
PORT_END = 64
# Path to sysfs
PLATFORM_ROOT_PATH = "/usr/share/sonic/device"
PMON_HWSKU_PATH = "/usr/share/sonic/hwsku"
HOST_CHK_CMD = "which systemctl > /dev/null 2>&1"
PLATFORM = "x86_64-accton_as7816_64x-r0"
HWSKU = "Accton-AS7816-64X"
_port_to_i2c_mapping = {
61: 25,
62: 26,
63: 27,
64: 28,
55: 29,
56: 30,
53: 31,
54: 32,
9: 33,
10: 34,
11: 35,
12: 36,
1: 37,
2: 38,
3: 39,
4: 40,
6: 41,
5: 42,
8: 43,
7: 44,
13: 45,
14: 46,
15: 47,
16: 48,
17: 49,
18: 50,
19: 51,
20: 52,
25: 53,
26: 54,
27: 55,
28: 56,
29: 57,
30: 58,
31: 59,
32: 60,
21: 61,
22: 62,
23: 63,
24: 64,
41: 65,
42: 66,
43: 67,
44: 68,
33: 69,
34: 70,
35: 71,
36: 72,
45: 73,
46: 74,
47: 75,
48: 76,
37: 77,
38: 78,
39: 79,
40: 80,
57: 81,
58: 82,
59: 83,
60: 84,
49: 85,
50: 86,
51: 87,
52: 88
}
def __init__(self, sfp_index=0):
SfpOptoeBase.__init__(self)
self._api_helper=APIHelper()
# Init index
self.index = sfp_index
self.port_num = self.index + 1
# Init eeprom path
eeprom_path = '/sys/bus/i2c/devices/{0}-0050/eeprom'
self.port_to_eeprom_mapping = {}
for x in range(self.PORT_START, self.PORT_END + 1):
self.port_to_eeprom_mapping[x] = eeprom_path.format(self._port_to_i2c_mapping[x])
def get_eeprom_path(self):
return self.port_to_eeprom_mapping[self.port_num]
def __is_host(self):
return os.system(self.HOST_CHK_CMD) == 0
def __get_path_to_port_config_file(self):
platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM])
hwsku_path = "/".join([platform_path, self.HWSKU]
) if self.__is_host() else self.PMON_HWSKU_PATH
return "/".join([hwsku_path, "port_config.ini"])
def __read_eeprom_specific_bytes(self, offset, num_bytes):
sysfsfile_eeprom = None
eeprom_raw = []
for i in range(0, num_bytes):
eeprom_raw.append("0x00")
sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num]
try:
sysfsfile_eeprom = open(
sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0)
sysfsfile_eeprom.seek(offset)
raw = sysfsfile_eeprom.read(num_bytes)
if sys.version_info[0] >= 3:
for n in range(0, num_bytes):
eeprom_raw[n] = hex(raw[n])[2:].zfill(2)
else:
for n in range(0, num_bytes):
eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2)
except Exception:
pass
finally:
if sysfsfile_eeprom:
sysfsfile_eeprom.close()
return eeprom_raw
def get_reset_status(self):
"""
Retrieves the reset status of SFP
Returns:
A Boolean, True if reset enabled, False if disabled
"""
reset_path="{}{}{}".format(CPLD_I2C_PATH , "module_reset_" , str(self.port_num))
val = self._api_helper.read_txt_file(reset_path)
if val is not None:
return int(val, 10) == 1
else:
return False
def get_rx_los(self):
"""
Retrieves the RX LOS (lost-of-signal) status of SFP
Returns:
A Boolean, True if SFP has RX LOS, False if not.
Note : RX LOS status is latched until a call to get_rx_los or a reset.
"""
rx_los_list = []
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
QSFP_CHANNL_RX_LOS_STATUS_OFFSET, QSFP_CHANNL_RX_LOS_STATUS_WIDTH) if self.get_presence() else None
if dom_channel_monitor_raw is not None:
rx_los_data = int(dom_channel_monitor_raw[0], 16)
rx_los_list.append(rx_los_data & 0x01 != 0)
rx_los_list.append(rx_los_data & 0x02 != 0)
rx_los_list.append(rx_los_data & 0x04 != 0)
rx_los_list.append(rx_los_data & 0x08 != 0)
return rx_los_list
else:
return [False]*4
def get_tx_fault(self):
"""
Retrieves the TX fault status of SFP
Returns:
A Boolean, True if SFP has TX fault, False if not
Note : TX fault status is lached until a call to get_tx_fault or a reset.
"""
tx_fault_list = []
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
QSFP_CHANNL_TX_FAULT_STATUS_OFFSET, QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) if self.get_presence() else None
if dom_channel_monitor_raw is not None:
tx_fault_data = int(dom_channel_monitor_raw[0], 16)
tx_fault_list.append(tx_fault_data & 0x01 != 0)
tx_fault_list.append(tx_fault_data & 0x02 != 0)
tx_fault_list.append(tx_fault_data & 0x04 != 0)
tx_fault_list.append(tx_fault_data & 0x08 != 0)
return tx_fault_list
else:
return [False]*4
def get_tx_disable(self):
"""
Retrieves the tx_disable status of this SFP
Returns:
A Boolean, True if tx_disable is enabled, False if disabled
"""
tx_disable_list = []
sfpd_obj = sff8436Dom()
if sfpd_obj is None:
return False
dom_control_raw = self.__read_eeprom_specific_bytes(
QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None
if dom_control_raw is not None:
dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0)
tx_disable_list.append(
'On' == dom_control_data['data']['TX1Disable']['value'])
tx_disable_list.append(
'On' == dom_control_data['data']['TX2Disable']['value'])
tx_disable_list.append(
'On' == dom_control_data['data']['TX3Disable']['value'])
tx_disable_list.append(
'On' == dom_control_data['data']['TX4Disable']['value'])
return tx_disable_list
else:
return [False]*4
def get_tx_disable_channel(self):
"""
Retrieves the TX disabled channels in this SFP
Returns:
A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent
TX channels which have been disabled in this SFP.
As an example, a returned value of 0x5 indicates that channel 0
and channel 2 have been disabled.
"""
tx_disable_list = self.get_tx_disable()
if tx_disable_list is None:
return 0
tx_disabled = 0
for i in range(len(tx_disable_list)):
if tx_disable_list[i]:
tx_disabled |= 1 << i
return tx_disabled
def get_lpmode(self):
"""
Retrieves the lpmode (low power mode) status of this SFP
Returns:
A Boolean, True if lpmode is enabled, False if disabled
"""
power_set=self.get_power_set()
power_override = self.get_power_override()
return power_set and power_override
def get_power_set(self):
power_set = False
sfpd_obj = sff8436Dom()
if sfpd_obj is None:
return False
dom_control_raw = self.__read_eeprom_specific_bytes(
QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None
if dom_control_raw is not None:
dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0)
power_set = (
'On' == dom_control_data['data']['PowerSet']['value'])
return power_set
def get_power_override(self):
"""
Retrieves the power-override status of this SFP
Returns:
A Boolean, True if power-override is enabled, False if disabled
"""
power_override = False
sfpd_obj = sff8436Dom()
if sfpd_obj is None:
return False
dom_control_raw = self.__read_eeprom_specific_bytes(
QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None
if dom_control_raw is not None:
dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0)
power_override = (
'On' == dom_control_data['data']['PowerOverride']['value'])
return power_override
def reset(self):
"""
Reset SFP and return all user module settings to their default srate.
Returns:
A boolean, True if successful, False if not
"""
reset_path = "{}{}{}".format(CPLD_I2C_PATH , 'module_reset_' , self.port_num)
ret = self._api_helper.write_txt_file(reset_path, 1)
if ret is not True:
return ret
time.sleep(0.01)
ret = self._api_helper.write_txt_file(reset_path, 0)
time.sleep(0.2)
return ret
def tx_disable(self, tx_disable):
"""
Disable SFP TX for all channels
Args:
tx_disable : A Boolean, True to enable tx_disable mode, False to disable
tx_disable mode.
Returns:
A boolean, True if tx_disable is set successfully, False if not
"""
if not self.get_presence():
return False
sysfsfile_eeprom = None
try:
tx_disable_ctl = 0xf if tx_disable else 0x0
buffer = create_string_buffer(1)
if sys.version_info[0] >= 3:
buffer[0] = tx_disable_ctl
else:
buffer[0] = chr(tx_disable_ctl)
# Write to eeprom
sysfsfile_eeprom = open(
self.port_to_eeprom_mapping[self.port_num], "r+b")
sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET)
sysfsfile_eeprom.write(buffer[0])
except IOError as e:
print ('Error: unable to open file: ',str(e))
return False
finally:
if sysfsfile_eeprom is not None:
sysfsfile_eeprom.close()
time.sleep(0.01)
return True
def tx_disable_channel(self, channel, disable):
"""
Sets the tx_disable for specified SFP channels
Args:
channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3,
e.g. 0x5 for channel 0 and channel 2.
disable : A boolean, True to disable TX channels specified in channel,
False to enable
Returns:
A boolean, True if successful, False if not
"""
if not self.get_presence():
return False
sysfsfile_eeprom = None
try:
channel_state = self.get_tx_disable_channel()
for i in range(4):
channel_mask = (1 << i)
if not (channel & channel_mask):
continue
if disable:
channel_state |= channel_mask
else:
channel_state &= ~channel_mask
buffer = create_string_buffer(1)
if sys.version_info[0] >= 3:
buffer[0] = channel_state
else:
buffer[0] = chr(channel_state)
# Write to eeprom
sysfsfile_eeprom = open(
self.port_to_eeprom_mapping[self.port_num], "r+b")
sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET)
sysfsfile_eeprom.write(buffer[0])
except IOError as e:
print ('Error: unable to open file: ', str(e))
return False
finally:
if sysfsfile_eeprom is not None:
sysfsfile_eeprom.close()
time.sleep(0.01)
return True
def set_lpmode(self, lpmode):
"""
Sets the lpmode (low power mode) of SFP
Args:
lpmode: A Boolean, True to enable lpmode, False to disable it
Note : lpmode can be overridden by set_power_override
Returns:
A boolean, True if lpmode is set successfully, False if not
"""
if lpmode:
self.set_power_override(True, True)
else:
self.set_power_override(False, False)
return True
def set_power_override(self, power_override, power_set):
"""
Sets SFP power level using power_override and power_set
Args:
power_override :
A Boolean, True to override set_lpmode and use power_set
to control SFP power, False to disable SFP power control
through power_override/power_set and use set_lpmode
to control SFP power.
power_set :
Only valid when power_override is True.
A Boolean, True to set SFP to low power mode, False to set
SFP to high power mode.
Returns:
A boolean, True if power-override and power_set are set successfully,
False if not
"""
if not self.get_presence():
return False
try:
power_override_bit = (1 << 0) if power_override else 0
power_set_bit = (1 << 1) if power_set else (1 << 3)
buffer = create_string_buffer(1)
if sys.version_info[0] >= 3:
buffer[0] = (power_override_bit | power_set_bit)
else:
buffer[0] = chr(power_override_bit | power_set_bit)
# Write to eeprom
with open(self.port_to_eeprom_mapping[self.port_num], "r+b") as fd:
fd.seek(QSFP_POWEROVERRIDE_OFFSET)
fd.write(buffer[0])
time.sleep(0.01)
except Exception:
print ('Error: unable to open file: ', str(e))
return False
return True
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
sfputil_helper = SfpUtilHelper()
sfputil_helper.read_porttab_mappings(
self.__get_path_to_port_config_file())
name = sfputil_helper.logical[self.index] or "Unknown"
return name
def get_presence(self):
"""
Retrieves the presence of the device
Returns:
bool: True if device is present, False if not
"""
present_path = "{}{}{}".format(CPLD_I2C_PATH , '/module_present_' , self.port_num)
val=self._api_helper.read_txt_file(present_path)
if val is not None:
return int(val, 10)==1
else:
return False
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return self.get_presence()
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
"""
return self.port_num
def is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True

View File

@ -0,0 +1,236 @@
#############################################################################
# Edgecore
#
# Thermal contains an implementation of SONiC Platform Base API and
# provides the thermal device status which are available in the platform
#
#############################################################################
import os
import os.path
import glob
try:
from sonic_platform_base.thermal_base import ThermalBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
PSU_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/"
PSU_HWMON_I2C_MAPPING = {
0: {
"num": 10,
"addr": "5b"
},
1: {
"num": 9,
"addr": "58"
},
}
PSU_CPLD_I2C_MAPPING = {
0: {
"num": 10,
"addr": "53"
},
1: {
"num": 9,
"addr": "50"
},
}
THERMAL_NAME_LIST = ["Temp sensor 1", "Temp sensor 2", "Temp sensor 3",
"Temp sensor 4", "Temp sensor 5", "Temp sensor 6"]
PSU_THERMAL_NAME_LIST = ["PSU-1 temp sensor 1", "PSU-2 temp sensor 2"]
SYSFS_PATH = "/sys/bus/i2c/devices"
class Thermal(ThermalBase):
"""Platform-specific Thermal class"""
def __init__(self, thermal_index=0, is_psu=False, psu_index=0):
self.index = thermal_index
self.is_psu = is_psu
self.psu_index = psu_index
if self.is_psu:
psu_i2c_bus = PSU_HWMON_I2C_MAPPING[psu_index]["num"]
psu_i2c_addr = PSU_HWMON_I2C_MAPPING[psu_index]["addr"]
self.psu_hwmon_path = PSU_I2C_PATH.format(psu_i2c_bus,
psu_i2c_addr)
psu_i2c_bus = PSU_CPLD_I2C_MAPPING[psu_index]["num"]
psu_i2c_addr = PSU_CPLD_I2C_MAPPING[psu_index]["addr"]
self.cpld_path = PSU_I2C_PATH.format(psu_i2c_bus, psu_i2c_addr)
# Set hwmon path
i2c_path = {
0: "18-0048/hwmon/hwmon*/",
1: "18-0049/hwmon/hwmon*/",
2: "18-004a/hwmon/hwmon*/",
3: "18-004b/hwmon/hwmon*/",
4: "17-004d/hwmon/hwmon*/",
5: "17-004d/hwmon/hwmon*/"
}.get(self.index, None)
self.hwmon_path = "{}/{}".format(SYSFS_PATH, i2c_path)
self.ss_key = THERMAL_NAME_LIST[self.index]
self.ss_index = 1
def __read_txt_file(self, file_path):
for filename in glob.glob(file_path):
try:
with open(filename, 'r') as fd:
data =fd.readline().rstrip()
return data
except IOError as e:
pass
return None
def __get_temp(self, temp_file):
if not self.is_psu:
temp_file_path = os.path.join(self.hwmon_path, temp_file)
else:
temp_file_path = temp_file
raw_temp = self.__read_txt_file(temp_file_path)
if raw_temp is not None:
return float(raw_temp)/1000
else:
return 0
def __set_threshold(self, file_name, temperature):
if self.is_psu:
return True
temp_file_path = os.path.join(self.hwmon_path, file_name)
for filename in glob.glob(temp_file_path):
try:
with open(filename, 'w') as fd:
fd.write(str(temperature))
return True
except IOError as e:
print("IOError")
return False
def get_temperature(self):
"""
Retrieves current temperature reading from thermal
Returns:
A float number of current temperature in Celsius up to nearest thousandth
of one degree Celsius, e.g. 30.125
"""
if not self.is_psu:
temp_file = "temp{}_input".format(self.ss_index)
else:
temp_file = self.psu_hwmon_path + "psu_temp1_input"
return self.__get_temp(temp_file)
def get_high_threshold(self):
"""
Retrieves the high threshold temperature of thermal
Returns:
A float number, the high threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
if self.is_psu:
return 80
temp_file = "temp{}_max".format(self.ss_index)
return self.__get_temp(temp_file)
def set_high_threshold(self, temperature):
"""
Sets the high threshold temperature of thermal
Args :
temperature: A float number up to nearest thousandth of one degree Celsius,
e.g. 30.125
Returns:
A boolean, True if threshold is set successfully, False if not
"""
temp_file = "temp{}_max".format(self.ss_index)
temperature = temperature *1000
self.__set_threshold(temp_file, temperature)
return True
def get_name(self):
"""
Retrieves the name of the thermal device
Returns:
string: The name of the thermal device
"""
if self.is_psu:
return PSU_THERMAL_NAME_LIST[self.psu_index]
else:
return THERMAL_NAME_LIST[self.index]
def get_presence(self):
"""
Retrieves the presence of the Thermal
Returns:
bool: True if Thermal is present, False if not
"""
if self.is_psu:
val = self.__read_txt_file(self.cpld_path + "psu_present")
return int(val, 10) == 1
temp_file = "temp{}_input".format(self.ss_index)
temp_file_path = os.path.join(self.hwmon_path, temp_file)
raw_txt = self.__read_txt_file(temp_file_path)
if raw_txt is not None:
return True
else:
return False
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
if self.is_psu:
temp_file = self.psu_hwmon_path + "psu_temp_fault"
return self.get_presence() and (not int(
self.__read_txt_file(temp_file)))
file_str = "temp{}_input".format(self.ss_index)
file_path = os.path.join(self.hwmon_path, file_str)
raw_txt = self.__read_txt_file(file_path)
if raw_txt is None:
return False
else:
return int(raw_txt) != 0
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return "N/A"
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return "N/A"
def get_position_in_parent(self):
"""
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
Returns:
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
"""
return self.index+1
def is_replaceable(self):
"""
Retrieves whether thermal module is replaceable
Returns:
A boolean value, True if replaceable, False if not
"""
return False

View File

@ -0,0 +1,15 @@
{
"services_to_ignore": [],
"devices_to_ignore": [
"asic",
"psu.temperature"
],
"user_defined_checkers": [],
"polling_interval": 60,
"led_color": {
"fault": "STATUS_LED_COLOR_RED",
"normal": "STATUS_LED_COLOR_GREEN",
"booting": "STATUS_LED_COLOR_GREEN"
}
}

View File

@ -4,10 +4,7 @@ obj-m:= x86-64-accton-as4630-54pe-cpld.o x86-64-accton-as4630-54pe-psu.o \
else
ifeq (,$(KERNEL_SRC))
#$(error KERNEL_SRC is not defined)
KVERSION=3.16.0-8-amd64
KERNEL_DIR = /usr/src/linux-headers-$(KVERSION)/
KERNELDIR:=$(KERNEL_DIR)
$(error KERNEL_SRC is not defined)
else
KERNELDIR:=$(KERNEL_SRC)
endif

View File

@ -598,7 +598,6 @@ static u8 is_fan_fault(struct as4630_54pe_cpld_data *data, enum fan_id id)
return ret;
}
static ssize_t fan_show_value(struct device *dev, struct device_attribute *da,
char *buf)
{

View File

@ -64,7 +64,7 @@ static struct accton_as4630_54pe_led_data *ledctl = NULL;
#define LED_TYPE_POE_REG_MASK (0x2|0x1)
#define LED_MODE_POE_GREEN_VALUE 0x1
#define LED_MODE_POE_AMBER_VALUE 0x2
#define LED_MODE_POE_OFF_VALUE 0x0
#define LED_MODE_POE_OFF_VALUE 0x3
#define LED_TYPE_STK1_REG_MASK 0x20
#define LED_MODE_STK1_GREEN_VALUE 0x0
@ -74,20 +74,20 @@ static struct accton_as4630_54pe_led_data *ledctl = NULL;
#define LED_MODE_STK2_GREEN_VALUE 0x0
#define LED_MODE_STK2_OFF_VALUE 0x10
#define LED_TYPE_FAN_REG_MASK (0x20|0x10)
#define LED_MODE_FAN_AMBER_VALUE 0x20
#define LED_MODE_FAN_GREEN_VALUE 0x10
#define LED_MODE_FAN_OFF_VALUE (0x0)
#define LED_TYPE_FAN_REG_MASK (0x8|0x4)
#define LED_MODE_FAN_AMBER_VALUE 0x8
#define LED_MODE_FAN_GREEN_VALUE 0x4
#define LED_MODE_FAN_OFF_VALUE (0xC)
#define LED_TYPE_PSU2_REG_MASK (0x8|0x4)
#define LED_MODE_PSU2_AMBER_VALUE 0x8
#define LED_MODE_PSU2_GREEN_VALUE 0x4
#define LED_MODE_PSU2_OFF_VALUE (0x0)
#define LED_TYPE_PSU2_REG_MASK (0x80|0x40)
#define LED_MODE_PSU2_AMBER_VALUE 0x80
#define LED_MODE_PSU2_GREEN_VALUE 0x40
#define LED_MODE_PSU2_OFF_VALUE (0xC0)
#define LED_TYPE_PSU1_REG_MASK (0x2|0x1)
#define LED_MODE_PSU1_AMBER_VALUE 0x2
#define LED_MODE_PSU1_GREEN_VALUE 0x1
#define LED_MODE_PSU1_OFF_VALUE (0x0)
#define LED_MODE_PSU1_OFF_VALUE (0x3)
enum led_type {
LED_TYPE_DIAG,
@ -106,8 +106,8 @@ struct led_reg {
};
static const struct led_reg led_reg_map[] = {
{(1<<LED_TYPE_DIAG)| (1<<LED_TYPE_PRI) | (1<<LED_TYPE_PSU2) , 0x30},
{(1<<LED_TYPE_PSU1) | (1<<LED_TYPE_FAN) | (1<<LED_TYPE_POE) |(1<<LED_TYPE_STK1) | (1<<LED_TYPE_STK2) , 0x31},
{(1<<LED_TYPE_DIAG)| (1<<LED_TYPE_PRI) | (1<<LED_TYPE_PSU1) , 0x30},
{(1<<LED_TYPE_PSU2) | (1<<LED_TYPE_FAN) | (1<<LED_TYPE_POE) |(1<<LED_TYPE_STK1) | (1<<LED_TYPE_STK2) , 0x31},
};
@ -371,7 +371,7 @@ static void accton_as4630_54pe_led_fan_set(struct led_classdev *led_cdev,
static enum led_brightness accton_as4630_54pe_led_fan_get(struct led_classdev *cdev)
{
accton_as4630_54pe_led_update();
return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[0]);
return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[1]);
}
static void accton_as4630_54pe_led_psu1_set(struct led_classdev *led_cdev,
@ -395,7 +395,7 @@ static void accton_as4630_54pe_led_psu2_set(struct led_classdev *led_cdev,
static enum led_brightness accton_as4630_54pe_led_psu2_get(struct led_classdev *cdev)
{
accton_as4630_54pe_led_update();
return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[0]);
return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[1]);
}
static struct led_classdev accton_as4630_54pe_leds[] = {
@ -405,7 +405,7 @@ static struct led_classdev accton_as4630_54pe_leds[] = {
.brightness_set = accton_as4630_54pe_led_diag_set,
.brightness_get = accton_as4630_54pe_led_diag_get,
.flags = LED_CORE_SUSPENDRESUME,
.max_brightness = LED_MODE_GREEN,
.max_brightness = LED_MODE_GREEN_BLINK,
},
[LED_TYPE_PRI] = {
.name = "pri",

View File

@ -1,16 +0,0 @@
[Unit]
Description=Accton AS4630-54PE Platform Monitoring service
Before=pmon.service
After=pddf-platform-init.service
DefaultDependencies=no
[Service]
ExecStart=/usr/local/bin/accton_as4630_54pe_pddf_monitor.py
KillSignal=SIGKILL
SuccessExitStatus=SIGKILL
# Resource Limitations
LimitCORE=infinity
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,11 @@
[Unit]
Description=Accton AS4630-54PE Platform handle management interface service
After=sysinit.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/handle_mgmt_interface.sh
[Install]
WantedBy=multi-user.target

View File

@ -1 +0,0 @@
../../../../pddf/i2c/service/pddf-platform-init.service

View File

@ -1,14 +1,23 @@
from setuptools import setup
DEVICE_NAME = 'accton'
HW_SKU = 'x86_64-accton_as4630_54pe-r0'
setup(
name='sonic-platform',
version='1.0',
description='SONiC platform API implementation on Accton Platforms using PDDF',
description='SONiC platform API implementation on Accton Platforms',
license='Apache 2.0',
author='SONiC Team',
author_email='linuxnetdev@microsoft.com',
url='https://github.com/Azure/sonic-buildimage',
packages=['sonic_platform'],
maintainer='Jostar Yang',
maintainer_email='jostar_yang@edge-core.com',
packages=[
'sonic_platform',
],
package_dir={
'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)},
classifiers=[
'Development Status :: 3 - Alpha',
'Environment :: Plugins',

View File

@ -30,6 +30,7 @@ import getopt
import sys
import logging
import time
import os
PROJECT_NAME = 'as4630_54pe'
version = '0.0.1'
@ -88,8 +89,8 @@ logging.basicConfig(level=logging.INFO)
if DEBUG == True:
print((sys.argv[0]))
print(('ARGV :', sys.argv[1:]))
print(sys.argv[0])
print('ARGV :', sys.argv[1:])
def main():
@ -107,7 +108,7 @@ def main():
if DEBUG == True:
print(options)
print(args)
print((len(sys.argv)))
print(len(sys.argv))
for opt, arg in options:
if opt in ('-h', '--help'):
@ -124,6 +125,10 @@ def main():
do_install()
elif arg == 'clean':
do_uninstall()
elif arg == 'api':
do_sonic_platform_install()
elif arg == 'api_clean':
do_sonic_platform_clean()
else:
show_help()
@ -131,12 +136,12 @@ def main():
return 0
def show_help():
print(( __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]}))
print( __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]})
sys.exit(0)
def my_log(txt):
if DEBUG == True:
print(("[ACCTON DBG]: ",txt))
print("[ACCTON DBG]: ",txt)
return
def log_os_system(cmd, show):
@ -150,7 +155,7 @@ def log_os_system(cmd, show):
if status:
logging.info('Failed :'+cmd)
if show:
print(('Failed :'+cmd))
print('Failed :'+cmd)
return status, output
def driver_inserted():
@ -168,7 +173,7 @@ kos = [
'modprobe i2c_dev',
'modprobe i2c_i801',
'modprobe i2c_ismt',
'modprobe i2c_mux_pca954x',
'modprobe i2c_mux_pca954x force_deselect_on_exit=1',
'modprobe ym2651y',
'modprobe x86_64_accton_as4630_54pe_cpld',
'modprobe x86_64_accton_as4630_54pe_leds',
@ -285,6 +290,44 @@ def system_ready():
return False
return True
PLATFORM_ROOT_PATH = '/usr/share/sonic/device'
PLATFORM_API2_WHL_FILE_PY3 ='sonic_platform-1.0-py3-none-any.whl'
def do_sonic_platform_install():
device_path = "{}{}{}{}".format(PLATFORM_ROOT_PATH, '/x86_64-accton_', PROJECT_NAME, '-r0')
SONIC_PLATFORM_BSP_WHL_PKG_PY3 = "/".join([device_path, PLATFORM_API2_WHL_FILE_PY3])
#Check API2.0 on py whl file
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0)
if status:
if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3):
status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG_PY3, 1)
if status:
print ("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3))
return status
else:
print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3))
else:
print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3))
else:
print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3))
return
def do_sonic_platform_clean():
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0)
if status:
print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY2))
else:
status, output = log_os_system("pip3 uninstall sonic-platform -y", 0)
if status:
print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3))
return status
else:
print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3))
return
def do_install():
if driver_inserted() == False:
status = driver_install()
@ -292,25 +335,28 @@ def do_install():
if FORCE == 0:
return status
else:
print((PROJECT_NAME.upper()+" drivers detected...."))
print(PROJECT_NAME.upper()+" drivers detected....")
if not device_exist():
status = device_install()
if status:
if FORCE == 0:
return status
else:
print((PROJECT_NAME.upper()+" devices detected...."))
print(PROJECT_NAME.upper()+" devices detected....")
for i in range(len(cpld_set)):
status, output = log_os_system(cpld_set[i], 1)
if status:
if FORCE == 0:
return status
do_sonic_platform_install()
return
def do_uninstall():
if not device_exist():
print((PROJECT_NAME.upper()+" has no device installed...."))
print(PROJECT_NAME.upper()+" has no device installed....")
else:
print("Removing device....")
status = device_uninstall()
@ -319,7 +365,7 @@ def do_uninstall():
return status
if driver_inserted()== False :
print((PROJECT_NAME.upper()+" has no driver installed...."))
print(PROJECT_NAME.upper()+" has no driver installed....")
else:
print("Removing installed driver....")
status = driver_uninstall()
@ -327,6 +373,8 @@ def do_uninstall():
if FORCE == 0:
return status
do_sonic_platform_clean()
return
def device_exist():

View File

@ -0,0 +1,9 @@
#!/bin/bash
#Due to the hardware design, as4630-54pe use "eth2" instead of "eth0" as management interface.
#Rename netdev "eth0" and "eth2" to swap original "eth2" to "eth0".
ifconfig eth0 down
ip link set eth0 name eth3
ip link set eth2 name eth0
ifconfig eth0 up

View File

@ -104,7 +104,7 @@ class FanUtil(object):
return None
try:
val_file.close()
val_file.close()
except:
logging.debug('GET. unable to close file. device_path:%s', device_path)
return None
@ -135,7 +135,7 @@ class FanUtil(object):
val_file.write(content)
try:
val_file.close()
val_file.close()
except:
logging.debug('GET. unable to close file. device_path:%s', device_path)
return None
@ -224,14 +224,3 @@ class FanUtil(object):
return True
#def main():
# fan = FanUtil()
#
# print 'get_size_node_map : %d' % fan.get_size_node_map()
# print 'get_size_path_map : %d' % fan.get_size_path_map()
# for x in range(fan.get_idx_fan_start(), fan.get_num_fans()+1):
# for y in range(fan.get_idx_node_start(), fan.get_num_nodes()+1):
# print fan.get_fan_to_device_path(x, y)
#
#if __name__ == '__main__':
# main()

View File

@ -22,7 +22,6 @@
# ------------------------------------------------------------------
try:
import os
import time
import logging
import glob
@ -34,7 +33,7 @@ except ImportError as e:
class ThermalUtil(object):
"""Platform-specific ThermalUtil class"""
THERMAL_NUM_MAX = 4
THERMAL_NUM_1_IDX = 1 # 1_ON_CPU_BROAD. LM75
THERMAL_NUM_1_IDX = 1 # 1_ON_CPU_BROAD. LM75
THERMAL_NUM_2_IDX = 2 # 2_ON_MAIN_BROAD. LM75
THERMAL_NUM_3_IDX = 3 # 3_ON_MAIN_BROAD. LM75
THERMAL_NUM_4_IDX = 4 # 4_ON_MAIN_BROAD. LM75
@ -42,88 +41,52 @@ class ThermalUtil(object):
""" Dictionary where
key1 = thermal id index (integer) starting from 1
value = path to fan device file (string) """
#_thermal_to_device_path_mapping = {}
_thermal_to_device_node_mapping = {
THERMAL_NUM_1_IDX: ['18', '4b'],
THERMAL_NUM_2_IDX: ['19', '4c'],
THERMAL_NUM_3_IDX: ['20', '49'],
THERMAL_NUM_4_IDX: ['21', '4a'],
}
thermal_sysfspath ={
THERMAL_NUM_1_IDX: ["/sys/bus/i2c/devices/18-004b/hwmon/hwmon3/temp1_input"],
THERMAL_NUM_2_IDX: ["/sys/bus/i2c/devices/19-004c/hwmon/hwmon4/temp1_input"],
THERMAL_NUM_3_IDX: ["/sys/bus/i2c/devices/20-0049/hwmon/hwmon5/temp1_input"],
THERMAL_NUM_4_IDX: ["/sys/bus/i2c/devices/21-004a/hwmon/hwmon6/temp1_input"],
THERMAL_NUM_1_IDX: ["/sys/bus/i2c/devices/18-004b/hwmon/hwmon*/temp1_input"],
THERMAL_NUM_2_IDX: ["/sys/bus/i2c/devices/19-004c/hwmon/hwmon*/temp1_input"],
THERMAL_NUM_3_IDX: ["/sys/bus/i2c/devices/20-0049/hwmon/hwmon*/temp1_input"],
THERMAL_NUM_4_IDX: ["/sys/bus/i2c/devices/21-004a/hwmon/hwmon*/temp1_input"],
}
#def __init__(self):
def _get_thermal_val(self, thermal_num):
def get_thermal_val(self, thermal_num):
if thermal_num < self.THERMAL_NUM_1_IDX or thermal_num > self.THERMAL_NUM_MAX:
logging.debug('GET. Parameter error. thermal_num, %d', thermal_num)
return None
device_path = self.get_thermal_to_device_path(thermal_num)
if(os.path.isfile(device_path)):
for filename in glob.glob(device_path):
try:
val_file = open(filename, 'r')
except IOError as e:
logging.error('GET. unable to open file: %s', str(e))
return None
device_path = self.get_thermal_path(thermal_num)
for filename in glob.glob(device_path):
try:
val_file = open(filename, 'r')
except IOError as e:
logging.error('GET. unable to open file: %s', str(e))
return None
content = val_file.readline().rstrip()
if content == '':
logging.debug('GET. content is NULL. device_path:%s', device_path)
return None
try:
val_file.close()
val_file.close()
except:
logging.debug('GET. unable to close file. device_path:%s', device_path)
return None
return int(content)
else:
print("No such device_path=%s"%device_path)
return 0
return 0
def get_num_thermals(self):
return self.THERMAL_NUM_MAX
def get_idx_thermal_start(self):
return self.THERMAL_NUM_1_IDX
def get_size_node_map(self):
return len(self._thermal_to_device_node_mapping)
def get_size_path_map(self):
return len(self.thermal_sysfspath)
def get_thermal_to_device_path(self, thermal_num):
def get_thermal_path(self, thermal_num):
return self.thermal_sysfspath[thermal_num][0]
def get_thermal_1_val(self):
return self._get_thermal_val(self.THERMAL_NUM_1_IDX)
def get_thermal_2_val(self):
return self._get_thermal_val(self.THERMAL_NUM_2_IDX)
def get_thermal_3_val(self):
return self._get_thermal_val(self.THERMAL_NUM_3_IDX)
def get_thermal_temp(self):
return (self._get_thermal_val(self.THERMAL_NUM_1_IDX) + self._get_thermal_val(self.THERMAL_NUM_2_IDX) +self._get_thermal_val(self.THERMAL_NUM_3_IDX))
def main():
thermal = ThermalUtil()
print("termal1=%d" %thermal._get_thermal_val(1))
print("termal2=%d" %thermal._get_thermal_val(2))
print("termal3=%d" %thermal._get_thermal_val(3))
print("termal4=%d" %thermal._get_thermal_val(4))
#
# print 'get_size_node_map : %d' % thermal.get_size_node_map()
# print 'get_size_path_map : %d' % thermal.get_size_path_map()
# for x in range(thermal.get_idx_thermal_start(), thermal.get_num_thermals()+1):
# print thermal.get_thermal_to_device_path(x)
#
logging.basicConfig(level=logging.DEBUG)
logging.debug('thermal1=%d', thermal.get_thermal_val(1))
logging.debug('thermal2=%d', thermal.get_thermal_val(2))
logging.debug('thermal3=%d', thermal.get_thermal_val(3))
logging.debug('thermal4=%d', thermal.get_thermal_val(4))
if __name__ == '__main__':
main()
main()

View File

@ -91,11 +91,11 @@ class accton_as5835_54x_monitor(object):
thermal = ThermalUtil()
fan = FanUtil()
temp2 = thermal.get_thermal_2_val()
temp2 = thermal.get_thermal_val(2)
if temp2 is None:
return False
temp3 = thermal.get_thermal_3_val()
temp3 = thermal.get_thermal_val(3)
if temp3 is None:
return False

View File

@ -48,8 +48,8 @@ FORCE = 0
if DEBUG == True:
print((sys.argv[0]))
print(("ARGV :", sys.argv[1:]))
print(sys.argv[0])
print("ARGV :", sys.argv[1:])
def main():
@ -67,7 +67,7 @@ def main():
if DEBUG == True:
print(options)
print(args)
print((len(sys.argv)))
print(len(sys.argv))
for opt, arg in options:
if opt in ('-h', '--help'):
@ -96,13 +96,13 @@ def main():
return 0
def show_help():
print((__doc__ % {'scriptName' : sys.argv[0].split("/")[-1]}))
print(__doc__ % {'scriptName' : sys.argv[0].split("/")[-1]})
sys.exit(0)
def my_log(txt):
if DEBUG == True:
print(("[Debug]"+txt))
print("[Debug]"+txt)
return
def log_os_system(cmd, show):
@ -113,7 +113,7 @@ def log_os_system(cmd, show):
if status:
logging.info('Failed :'+cmd)
if show:
print(('Failed :'+cmd))
print('Failed :'+cmd)
return status, output
def driver_check():
@ -295,6 +295,10 @@ def device_install():
for i in range(49, 55): #Set qsfp port to normal state
log_os_system("echo 0 > /sys/bus/i2c/devices/3-0062/module_reset_" + str(i), 1)
for i in range(1, 39): #Set disable tx_disable to sfp port
log_os_system("echo 0 > /sys/bus/i2c/devices/3-0061/module_tx_disable_" + str(i), 1)
for i in range(39, 49): #Set disable tx_disable to sfp port
log_os_system("echo 0 > /sys/bus/i2c/devices/3-0062/module_tx_disable_" + str(i), 1)
for i in range(0,len(sfp_map)):
if i < qsfp_start:
@ -358,31 +362,29 @@ def do_sonic_platform_install():
if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3):
status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG_PY3, 1)
if status:
print(("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3) ))
print("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3) )
return status
else:
print(("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3) ))
print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3) )
else:
print(('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3)))
print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3))
else:
print(('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3)))
print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3))
return
def do_sonic_platform_clean():
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0)
if status:
print(('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3)))
print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3))
else:
status, output = log_os_system("pip3 uninstall sonic-platform -y", 0)
if status:
print(('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3)))
print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3))
return status
else:
print(('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3)))
return
print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3))
def do_install():
print("Checking system....")
@ -393,7 +395,7 @@ def do_install():
if FORCE == 0:
return status
else:
print((PROJECT_NAME.upper()+" drivers detected...."))
print(PROJECT_NAME.upper()+" drivers detected....")
if not device_exist():
print("No device, installing....")
status = device_install()
@ -401,7 +403,7 @@ def do_install():
if FORCE == 0:
return status
else:
print((PROJECT_NAME.upper()+" devices detected...."))
print(PROJECT_NAME.upper()+" devices detected....")
do_sonic_platform_install()
@ -410,7 +412,7 @@ def do_install():
def do_uninstall():
print("Checking system....")
if not device_exist():
print((PROJECT_NAME.upper() +" has no device installed...."))
print(PROJECT_NAME.upper() +" has no device installed....")
else:
print("Removing device....")
status = device_uninstall()
@ -419,7 +421,7 @@ def do_uninstall():
return status
if driver_check()== False :
print((PROJECT_NAME.upper() +" has no driver installed...."))
print(PROJECT_NAME.upper() +" has no driver installed....")
else:
print("Removing installed driver....")
status = driver_uninstall()

View File

@ -112,7 +112,7 @@ class FanUtil(object):
return None
try:
val_file.close()
val_file.close()
except:
logging.debug('GET. unable to close file. device_path:%s', device_path)
return None
@ -143,7 +143,7 @@ class FanUtil(object):
val_file.write(content)
try:
val_file.close()
val_file.close()
except:
logging.debug('GET. unable to close file. device_path:%s', device_path)
return None

View File

@ -146,7 +146,7 @@ static int accton_getLedReg(enum led_type type, u8 *reg)
int i;
for (i = 0; i < ARRAY_SIZE(led_reg_map); i++) {
if(led_reg_map[i].types ==type) {
if (led_reg_map[i].types ==type) {
*reg = led_reg_map[i].reg_addr;
return 0;
}

View File

@ -1,16 +0,0 @@
[Unit]
Description=Accton AS7326-56X Platform Monitoring service
Before=pmon.service
After=pddf-platform-init.service
DefaultDependencies=no
[Service]
ExecStart=/usr/local/bin/accton_as7326_pddf_monitor.py
KillSignal=SIGKILL
SuccessExitStatus=SIGKILL
# Resource Limitations
LimitCORE=infinity
[Install]
WantedBy=multi-user.target

View File

@ -1,6 +1,6 @@
[Unit]
Description=Accton AS7326-56X Platform MAC handle service
Before=opennsl-modules.service pddf-platform-init.service
Before=opennsl-modules.service
After=local-fs.target
[Service]

View File

@ -1 +0,0 @@
../../../../pddf/i2c/service/pddf-platform-init.service

View File

@ -1,5 +1,8 @@
from setuptools import setup
DEVICE_NAME = 'accton'
HW_SKU = 'x86_64-accton_as7326_56x-r0'
setup(
name='sonic-platform',
version='1.0',
@ -8,7 +11,11 @@ setup(
author='SONiC Team',
author_email='linuxnetdev@microsoft.com',
url='https://github.com/Azure/sonic-buildimage',
packages=['sonic_platform'],
packages=[
'sonic_platform'
],
package_dir={
'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)},
classifiers=[
'Development Status :: 3 - Alpha',
'Environment :: Plugins',

View File

@ -166,14 +166,14 @@ class device_monitor(object):
thermal = ThermalUtil()
fan = FanUtil()
fan_dir=fan.get_fan_dir(1)
if fan_dir > 1:
fan_dri=1 #something wrong, set fan_dir to default val
if fan_dir < 0:
fan_dri=1 #something wrong, set fan_dir to default val
#fan_dir=fan.get_fan_dir(1)
#if fan_dir > 1:
# fan_dri=1 #something wrong, set fan_dir to default val
#if fan_dir < 0:
# fan_dri=1 #something wrong, set fan_dir to default val
ori_pwm=fan.get_fan_duty_cycle()
new_pwm=0
logging.debug('fan_dir=%d, ori_pwm=%d', fan_dir, ori_pwm)
#logging.debug('fan_dir=%d, ori_pwm=%d', fan_dir, ori_pwm)
logging.debug('test_temp=%d', test_temp)
if test_temp==0:
temp1 = thermal._get_thermal_val(1)

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
#
# Copyright (C) 2016 Accton Networks, Inc.
#
@ -14,15 +14,6 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#
# Description:
# Due to adoption of optoe drivers, sideband signals of SFPs are moved
# into cpld drivers. Add a new dict, cpld_of_module, for mapping this
# attributes to corresponding cpld nodes.
#
"""
Usage: %(scriptName)s [options] command object
@ -34,18 +25,14 @@ options:
command:
install : install drivers and generate related sysfs nodes
clean : uninstall drivers and remove related sysfs nodes
show : show all systen status
sff : dump SFP eeprom
set : change board setting with fan|led|sfp
"""
import subprocess
import getopt
import sys
import logging
import re
import time
import os
@ -96,41 +83,21 @@ def main():
for arg in args:
if arg == 'install':
do_install()
elif arg == 'api':
do_sonic_platform_install()
elif arg == 'api_clean':
do_sonic_platform_clean()
elif arg == 'clean':
do_uninstall()
elif arg == 'show':
device_traversal()
elif arg == 'sff':
if len(args)!=2:
show_eeprom_help()
elif int(args[1]) ==0 or int(args[1]) > DEVICE_NO['sfp']:
show_eeprom_help()
else:
show_eeprom(args[1])
return
elif arg == 'set':
if len(args)<3:
show_set_help()
else:
set_device(args[1:])
return
else:
show_help()
return 0
def show_help():
print(__doc__ % {'scriptName' : sys.argv[0].split("/")[-1]})
sys.exit(0)
def show_set_help():
cmd = sys.argv[0].split("/")[-1]+ " " + args[0]
print(cmd +" [led|sfp|fan]")
print(" use \""+ cmd + " led 0-4 \" to set led color")
print(" use \""+ cmd + " fan 0-100\" to set fan duty percetage")
print(" use \""+ cmd + " sfp 1-56 {0|1}\" to set sfp# tx_disable")
sys.exit(0)
def dis_i2c_ir3570a(addr):
cmd = "i2cset -y 0 0x%x 0xE5 0x01" % addr
@ -156,11 +123,6 @@ def ir3570_check():
return ret
def show_eeprom_help():
cmd = sys.argv[0].split("/")[-1]+ " " + args[0]
print(" use \""+ cmd + " 1-56 \" to dump sfp# eeprom")
sys.exit(0)
def my_log(txt):
if DEBUG == True:
print("[ROY]"+txt)
@ -174,7 +136,7 @@ def log_os_system(cmd, show):
if status:
logging.info('Failed :'+cmd)
if show:
print(('Failed :'+cmd))
print('Failed :'+cmd)
return status, output
def driver_check():
@ -189,7 +151,7 @@ def driver_check():
kos = [
'modprobe i2c_dev',
'modprobe i2c_mux_pca954x force_deselect_on_exit=1',
'modprobe i2c_mux_pca954x',
'modprobe accton_i2c_cpld' ,
'modprobe ym2651y' ,
'modprobe accton_as7326_56x_fan' ,
@ -207,6 +169,8 @@ def driver_install():
if status:
if FORCE == 0:
return status
print("Done driver_install")
return 0
def driver_uninstall():
@ -224,12 +188,8 @@ def driver_uninstall():
return status
return 0
led_prefix ='/sys/class/leds/accton_'+PROJECT_NAME+'_led::'
hwmon_types = {'led': ['diag','fan','loc','psu1','psu2']}
hwmon_nodes = {'led': ['brightness'] }
hwmon_prefix ={'led': led_prefix}
i2c_prefix = '/sys/bus/i2c/devices/'
'''
i2c_bus = {'fan': ['11-0066'] ,
'thermal': ['15-0048','15-0049', '15-004a', '15-004b'] ,
'psu': ['17-0051','13-0053'],
@ -238,7 +198,7 @@ i2c_nodes = {'fan': ['present', 'front_speed_rpm', 'rear_speed_rpm'] ,
'thermal': ['hwmon/hwmon*/temp1_input'] ,
'psu': ['psu_present ', 'psu_power_good'] ,
'sfp': ['module_present_', 'module_tx_disable_']}
'''
sfp_map = [
42,41,44,43,47,45,46,50,
48,49,52,51,53,56,55,54,
@ -268,7 +228,6 @@ mknod =[
'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-36/new_device',
'echo pca9548 0x75 > /sys/bus/i2c/devices/i2c-37/new_device',
'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-38/new_device',
'echo 24c04 0x56 > /sys/bus/i2c/devices/i2c-0/new_device',
'echo as7326_56x_fan 0x66 > /sys/bus/i2c/devices/i2c-11/new_device ',
'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-15/new_device',
@ -286,12 +245,22 @@ mknod =[
mknod2 =[
]
#EERPOM
eeprom_mknod =[
'echo 24c04 0x56 > /sys/bus/i2c/devices/i2c-0/new_device',
'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-0/new_device'
]
def i2c_order_check():
# This project has only 1 i2c bus.
return 0
def eeprom_check():
cmd = "i2cget -y -f 0 0x56"
status, output = subprocess.getstatusoutput(cmd)
return status
def device_install():
global FORCE
@ -320,6 +289,30 @@ def device_install():
print(output)
if FORCE == 0:
return status
# set all pca954x idle_disconnect
cmd = 'echo -2 | tee /sys/bus/i2c/drivers/pca954x/*-00*/idle_state'
status, output = log_os_system(cmd, 1)
if status:
print(output)
if FORCE == 0:
return status
# initiate IDPROM
# Close 0x77 mux to make sure if the I2C address of IDPROM is 0x56 or 0x57
log_os_system("i2cset -f -y 0 0x77 0 ", 1)
ret=eeprom_check()
if ret==0:
log_os_system(eeprom_mknod[0], 1) #old board, 0x56 eeprom
time.sleep(0.2)
exists = os.path.isfile('/sys/bus/i2c/devices/0-0056/eeprom')
if (exists is False):
subprocess.call('echo 0x56 > /sys/bus/i2c/devices/i2c-0/delete_device', shell=True)
log_os_system(eeprom_mknod[1], 1)
else:
log_os_system(eeprom_mknod[1], 1) #new board, 0x57 eeprom
for i in range(0,len(sfp_map)):
if i < qsfp_start or i >= qsfp_end:
status, output =log_os_system("echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1)
@ -329,6 +322,7 @@ def device_install():
print(output)
if FORCE == 0:
return status
print("Done device_install")
return
def device_uninstall():
@ -364,6 +358,23 @@ def device_uninstall():
if FORCE == 0:
return status
#Deal with for del 0x56 or 0x57 sysfs device
exists = os.path.isfile('/sys/bus/i2c/devices/0-0056/eeprom')
if (exists is True):
target = eeprom_mknod[0] #0x56
else:
target = eeprom_mknod[1] #0x57
temp = target.split()
del temp[1]
temp[-1] = temp[-1].replace('new_device', 'delete_device')
status, output = log_os_system(" ".join(temp), 1)
if status:
print(output)
if FORCE == 0:
return status
return
def system_ready():
@ -372,6 +383,44 @@ def system_ready():
if not device_exist():
return False
return True
PLATFORM_ROOT_PATH = '/usr/share/sonic/device'
PLATFORM_API2_WHL_FILE_PY3 ='sonic_platform-1.0-py3-none-any.whl'
def do_sonic_platform_install():
device_path = "{}{}{}{}".format(PLATFORM_ROOT_PATH, '/x86_64-accton_', PROJECT_NAME, '-r0')
SONIC_PLATFORM_BSP_WHL_PKG_PY3 = "/".join([device_path, PLATFORM_API2_WHL_FILE_PY3])
#Check API2.0 on py whl file
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0)
if status:
if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3):
status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG_PY3, 1)
if status:
print("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3))
return status
else:
print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3))
else:
print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3))
else:
print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3))
return
def do_sonic_platform_clean():
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0)
if status:
print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3))
else:
status, output = log_os_system("pip3 uninstall sonic-platform -y", 0)
if status:
print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3))
return status
else:
print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3))
return
def do_install():
print("Checking system....")
@ -394,6 +443,9 @@ def do_install():
return status
else:
print(PROJECT_NAME.upper()+" devices detected....")
do_sonic_platform_install()
return
def do_uninstall():
@ -416,185 +468,8 @@ def do_uninstall():
if FORCE == 0:
return status
return
do_sonic_platform_clean()
def devices_info():
global DEVICE_NO
global ALL_DEVICE
global i2c_bus, hwmon_types
for key in DEVICE_NO:
ALL_DEVICE[key]= {}
for i in range(0,DEVICE_NO[key]):
ALL_DEVICE[key][key+str(i+1)] = []
for key in i2c_bus:
buses = i2c_bus[key]
nodes = i2c_nodes[key]
for i in range(0,len(buses)):
for j in range(0,len(nodes)):
if 'fan' == key:
for k in range(0,DEVICE_NO[key]):
node = key+str(k+1)
path = i2c_prefix+ buses[i]+"/fan"+str(k+1)+"_"+ nodes[j]
my_log(node+": "+ path)
ALL_DEVICE[key][node].append(path)
elif 'sfp' == key:
for k in range(0,DEVICE_NO[key]):
for lk in cpld_of_module:
if k in cpld_of_module[lk]:
cpld_str = lk
node = key+str(k+1)
path = i2c_prefix+ lk + "/"+ nodes[j] + str(k+1)
my_log(node+": "+ path)
ALL_DEVICE[key][node].append(path)
else:
node = key+str(i+1)
path = i2c_prefix+ buses[i]+"/"+ nodes[j]
my_log(node+": "+ path)
ALL_DEVICE[key][node].append(path)
for key in hwmon_types:
itypes = hwmon_types[key]
nodes = hwmon_nodes[key]
for i in range(0,len(itypes)):
for j in range(0,len(nodes)):
node = key+"_"+itypes[i]
path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j]
my_log(node+": "+ path)
ALL_DEVICE[key][ key+str(i+1)].append(path)
#show dict all in the order
if DEBUG == True:
for i in sorted(ALL_DEVICE.keys()):
print((i+": "))
for j in sorted(ALL_DEVICE[i].keys()):
print((" "+j))
for k in (ALL_DEVICE[i][j]):
print((" "+" "+k))
return
def show_eeprom(index):
if system_ready()==False:
print("System's not ready.")
print("Please install first!")
return
if len(ALL_DEVICE)==0:
devices_info()
node = ALL_DEVICE['sfp'] ['sfp'+str(index)][0]
node = node.replace(node.split("/")[-1], 'eeprom')
# check if got hexdump command in current environment
ret, log = log_os_system("which hexdump", 0)
ret, log2 = log_os_system("which busybox hexdump", 0)
if len(log):
hex_cmd = 'hexdump'
elif len(log2):
hex_cmd = ' busybox hexdump'
else:
log = 'Failed : no hexdump cmd!!'
logging.info(log)
print(log)
return 1
print(node + ":")
ret, log = log_os_system("cat "+node+"| "+hex_cmd+" -C", 1)
if ret==0:
print(log)
else:
print("**********device no found**********")
return
def set_device(args):
global DEVICE_NO
global ALL_DEVICE
if system_ready()==False:
print("System's not ready.")
print("Please install first!")
return
if len(ALL_DEVICE)==0:
devices_info()
if args[0]=='led':
if int(args[1])>4:
show_set_help()
return
#print ALL_DEVICE['led']
for i in range(0,len(ALL_DEVICE['led'])):
for k in (ALL_DEVICE['led']['led'+str(i+1)]):
ret, log = log_os_system("echo "+args[1]+" >"+k, 1)
if ret:
return ret
elif args[0]=='fan':
if int(args[1])>100:
show_set_help()
return
#print ALL_DEVICE['fan']
#fan1~6 is all fine, all fan share same setting
node = ALL_DEVICE['fan'] ['fan1'][0]
node = node.replace(node.split("/")[-1], 'fan_duty_cycle_percentage')
ret, log = log_os_system("cat "+ node, 1)
if ret==0:
print(("Previous fan duty: " + log.strip() +"%"))
ret, log = log_os_system("echo "+args[1]+" >"+node, 1)
if ret==0:
print(("Current fan duty: " + args[1] +"%"))
return ret
elif args[0]=='sfp':
if int(args[1])> DEVICE_NO[args[0]] or int(args[1])==0:
show_set_help()
return
if len(args)<2:
show_set_help()
return
if int(args[2])>1:
show_set_help()
return
#print ALL_DEVICE[args[0]]
for i in range(0,len(ALL_DEVICE[args[0]])):
for j in ALL_DEVICE[args[0]][args[0]+str(args[1])]:
if j.find('tx_disable')!= -1:
ret, log = log_os_system("echo "+args[2]+" >"+ j, 1)
if ret:
return ret
return
#get digits inside a string.
#Ex: 31 for "sfp31"
def get_value(input):
digit = re.findall('\d+', input)
return int(digit[0])
def device_traversal():
if system_ready()==False:
print("System's not ready.")
print("Please install first!")
return
if len(ALL_DEVICE)==0:
devices_info()
for i in sorted(ALL_DEVICE.keys()):
print("============================================")
print((i.upper()+": "))
print("============================================")
for j in sorted(list(ALL_DEVICE[i].keys()), key=get_value):
print(" "+j+":", end=' ')
for k in (ALL_DEVICE[i][j]):
ret, log = log_os_system("cat "+k, 0)
func = k.split("/")[-1].strip()
func = re.sub(j+'_','',func,1)
func = re.sub(i.lower()+'_','',func,1)
if ret==0:
print(func+"="+log+" ", end=' ')
else:
print(func+"="+"X"+" ", end=' ')
print()
print("----------------------------------------------------------------")
print()
return
def device_exist():

View File

@ -104,7 +104,7 @@ class FanUtil(object):
return None
try:
val_file.close()
val_file.close()
except:
logging.debug('GET. unable to close file. device_path:%s', device_path)
return None
@ -135,7 +135,7 @@ class FanUtil(object):
val_file.write(content)
try:
val_file.close()
val_file.close()
except:
logging.debug('GET. unable to close file. device_path:%s', device_path)
return None

View File

@ -81,11 +81,11 @@ class ThermalUtil(object):
return None
try:
val_file.close()
val_file.close()
except:
logging.debug('GET. unable to close file. device_path:%s', device_path)
return None
return int(content)

View File

@ -0,0 +1,17 @@
[Unit]
Description=Accton AS7816-64X Platform initialization service
Before=pmon.service determine-reboot-cause.service
After=sysinit.target
DefaultDependencies=no
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/accton_as7816_64x_util.py install
ExecStop=/usr/local/bin/accton_as7816_64x_util.py clean
# Resource Limitations
LimitCORE=infinity
[Install]
WantedBy=multi-user.target

View File

@ -1,11 +1,12 @@
[Unit]
Description=Accton AS7816-64X Platform Monitoring service
Before=pmon.service
After=pddf-platform-init.service
After=as7816-64x-platform-init.service
Requires=as7816-64x-platform-init.service
DefaultDependencies=no
[Service]
ExecStart=/usr/local/bin/accton_as7816_pddf_monitor.py
ExecStart=/usr/local/bin/accton_as7816_64x_monitor.py
KillSignal=SIGKILL
SuccessExitStatus=SIGKILL

View File

@ -1,13 +0,0 @@
[Unit]
Description=Accton AS7816-64X Platform initialization service
Before=pmon.service
After=sysinit.target
DefaultDependencies=no
[Service]
ExecStartPre=/usr/local/bin/accton_as7816_util.py install
ExecStart=/usr/local/bin/accton_as7816_monitor.py
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

View File

@ -1 +0,0 @@
../../../../pddf/i2c/service/pddf-platform-init.service

View File

@ -1,5 +1,8 @@
from setuptools import setup
DEVICE_NAME = 'accton'
HW_SKU = 'x86_64-accton_as7816_64x-r0'
setup(
name='sonic-platform',
version='1.0',
@ -8,7 +11,13 @@ setup(
author='SONiC Team',
author_email='linuxnetdev@microsoft.com',
url='https://github.com/Azure/sonic-buildimage',
packages=['sonic_platform'],
maintainer='Jostar Yang',
maintainer_email='jostar_yang@edge-core.com',
packages=[
'sonic_platform',
],
package_dir={
'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)},
classifiers=[
'Development Status :: 3 - Alpha',
'Environment :: Plugins',

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
#
# Copyright (C) 2017 Accton Technology Corporation
#

View File

@ -48,8 +48,8 @@ FORCE = 0
if DEBUG == True:
print((sys.argv[0]))
print(('ARGV :', sys.argv[1:] ))
print(sys.argv[0])
print('ARGV :', sys.argv[1:] )
def main():
@ -67,7 +67,7 @@ def main():
if DEBUG == True:
print(options)
print(args)
print((len(sys.argv)))
print(len(sys.argv))
for opt, arg in options:
if opt in ('-h', '--help'):
@ -81,9 +81,14 @@ def main():
logging.info('no option')
for arg in args:
if arg == 'install':
do_install()
do_install()
elif arg == 'clean':
do_uninstall()
do_uninstall()
elif arg == 'api':
do_sonic_platform_install()
elif arg == 'api_clean':
do_sonic_platform_clean()
else:
show_help()
@ -91,7 +96,7 @@ def main():
return 0
def show_help():
print(( __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]}))
print( __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]})
sys.exit(0)
@ -114,13 +119,13 @@ def ir3570_check():
else:
ret = 0
except Exception as e:
print(("Error on ir3570_check() e:" + str(e)))
print("Error on ir3570_check() e:" + str(e))
return -1
return ret
def my_log(txt):
if DEBUG == True:
print(("[ROY]"+txt))
print("[ROY]"+txt)
return
def log_os_system(cmd, show):
@ -131,7 +136,7 @@ def log_os_system(cmd, show):
if status:
logging.info('Failed :'+cmd)
if show:
print(('Failed :'+cmd))
print('Failed :'+cmd)
return status, output
def driver_check():
@ -298,7 +303,44 @@ def system_ready():
if not device_exist():
return False
return True
PLATFORM_ROOT_PATH = '/usr/share/sonic/device'
PLATFORM_API2_WHL_FILE_PY3 ='sonic_platform-1.0-py3-none-any.whl'
def do_sonic_platform_install():
device_path = "{}{}{}{}".format(PLATFORM_ROOT_PATH, '/x86_64-accton_', PROJECT_NAME, '-r0')
SONIC_PLATFORM_BSP_WHL_PKG_PY3 = "/".join([device_path, PLATFORM_API2_WHL_FILE_PY3])
#Check API2.0 on py whl file
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0)
if status:
if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3):
status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG_PY3, 1)
if status:
print("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3))
return status
else:
print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3))
else:
print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3))
else:
print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3))
return
def do_sonic_platform_clean():
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0)
if status:
print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3))
else:
status, output = log_os_system("pip3 uninstall sonic-platform -y", 0)
if status:
print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3))
return status
else:
print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3))
return
def do_install():
print("Checking system....")
if driver_check() == False:
@ -308,7 +350,7 @@ def do_install():
if FORCE == 0:
return status
else:
print((PROJECT_NAME.upper()+" drivers detected...."))
print(PROJECT_NAME.upper()+" drivers detected....")
ir3570_check()
@ -319,13 +361,15 @@ def do_install():
if FORCE == 0:
return status
else:
print((PROJECT_NAME.upper()+" devices detected...."))
print(PROJECT_NAME.upper()+" devices detected....")
do_sonic_platform_install()
return
def do_uninstall():
print("Checking system....")
if not device_exist():
print((PROJECT_NAME.upper() +" has no device installed...."))
print(PROJECT_NAME.upper() +" has no device installed....")
else:
print("Removing device....")
status = device_uninstall()
@ -334,7 +378,7 @@ def do_uninstall():
return status
if driver_check()== False :
print((PROJECT_NAME.upper() +" has no driver installed...."))
print(PROJECT_NAME.upper() +" has no driver installed....")
else:
print("Removing installed driver....")
status = driver_uninstall()
@ -342,6 +386,8 @@ def do_uninstall():
if FORCE == 0:
return status
do_sonic_platform_clean()
return
def device_exist():

View File

@ -42,7 +42,8 @@ enum chips {
YM2651,
YM2401,
YM2851,
YPEB1200AM
YM1401A,
YPEB1200AM
};
/* Each client has this additional data
@ -66,8 +67,9 @@ struct ym2651y_data {
u16 fan_duty_cycle[2]; /* Register value */
u8 fan_dir[4]; /* Register value */
u8 pmbus_revision; /* Register value */
u8 mfr_serial[21]; /* Register value */
u8 mfr_id[10]; /* Register value */
u8 mfr_model[10]; /* Register value */
u8 mfr_model[16]; /* Register value */
u8 mfr_revsion[3]; /* Register value */
u16 mfr_vin_min; /* Register value */
u16 mfr_vin_max; /* Register value */
@ -113,9 +115,11 @@ enum ym2651y_sysfs_attributes {
PSU_FAN1_SPEED,
PSU_FAN1_DUTY_CYCLE,
PSU_PMBUS_REVISION,
PSU_SERIAL_NUM,
PSU_MFR_ID,
PSU_MFR_MODEL,
PSU_MFR_REVISION,
PSU_MFR_SERIAL,
PSU_MFR_VIN_MIN,
PSU_MFR_VIN_MAX,
PSU_MFR_VOUT_MIN,
@ -141,9 +145,11 @@ static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FA
static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, show_linear, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE);
static SENSOR_DEVICE_ATTR(psu_fan_dir, S_IRUGO, show_ascii, NULL, PSU_FAN_DIRECTION);
static SENSOR_DEVICE_ATTR(psu_pmbus_revision, S_IRUGO, show_byte, NULL, PSU_PMBUS_REVISION);
static SENSOR_DEVICE_ATTR(psu_serial_num, S_IRUGO, show_ascii, NULL, PSU_SERIAL_NUM);
static SENSOR_DEVICE_ATTR(psu_mfr_id, S_IRUGO, show_ascii, NULL, PSU_MFR_ID);
static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, show_ascii, NULL, PSU_MFR_MODEL);
static SENSOR_DEVICE_ATTR(psu_mfr_revision, S_IRUGO, show_ascii, NULL, PSU_MFR_REVISION);
static SENSOR_DEVICE_ATTR(psu_mfr_serial, S_IRUGO, show_ascii, NULL, PSU_MFR_SERIAL);
static SENSOR_DEVICE_ATTR(psu_mfr_vin_min, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MIN);
static SENSOR_DEVICE_ATTR(psu_mfr_vin_max, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MAX);
static SENSOR_DEVICE_ATTR(psu_mfr_vout_min, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MIN);
@ -175,9 +181,11 @@ static struct attribute *ym2651y_attributes[] = {
&sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr,
&sensor_dev_attr_psu_fan_dir.dev_attr.attr,
&sensor_dev_attr_psu_pmbus_revision.dev_attr.attr,
&sensor_dev_attr_psu_serial_num.dev_attr.attr,
&sensor_dev_attr_psu_mfr_id.dev_attr.attr,
&sensor_dev_attr_psu_mfr_model.dev_attr.attr,
&sensor_dev_attr_psu_mfr_revision.dev_attr.attr,
&sensor_dev_attr_psu_mfr_serial.dev_attr.attr,
&sensor_dev_attr_psu_mfr_vin_min.dev_attr.attr,
&sensor_dev_attr_psu_mfr_vin_max.dev_attr.attr,
&sensor_dev_attr_psu_mfr_pout_max.dev_attr.attr,
@ -362,14 +370,17 @@ static ssize_t show_ascii(struct device *dev, struct device_attribute *da,
}
ptr = data->fan_dir;
break;
case PSU_MFR_SERIAL: /* psu_mfr_serial */
ptr = data->mfr_serial+1; /* The first byte is the count byte of string. */
break;
case PSU_MFR_ID: /* psu_mfr_id */
ptr = data->mfr_id;
ptr = data->mfr_id+1; /* The first byte is the count byte of string. */
break;
case PSU_MFR_MODEL: /* psu_mfr_model */
ptr = data->mfr_model;
ptr = data->mfr_model+1; /* The first byte is the count byte of string. */
break;
case PSU_MFR_REVISION: /* psu_mfr_revision */
ptr = data->mfr_revsion;
ptr = data->mfr_revsion+1;
break;
default:
return 0;
@ -415,7 +426,7 @@ static ssize_t show_vout(struct device *dev, struct device_attribute *da,
struct i2c_client *client = to_i2c_client(dev);
struct ym2651y_data *data = i2c_get_clientdata(client);
if (data->chip == YM2401) {
if (data->chip == YM2401 || data->chip==YM1401A) {
return show_vout_by_mode(dev, da, buf);
}
else {
@ -493,6 +504,7 @@ static const struct i2c_device_id ym2651y_id[] = {
{ "ym2651", YM2651 },
{ "ym2401", YM2401 },
{ "ym2851", YM2851 },
{ "ym1401a",YM1401A},
{ "ype1200am", YPEB1200AM },
{}
};
@ -561,8 +573,8 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev)
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
int i, status;
u8 command;
int i, status, length;
u8 command, buf;
u8 fan_dir[5] = {0};
struct reg_data_byte regs_byte[] = { {0x19, &data->capability},
{0x20, &data->vout_mode},
@ -599,6 +611,7 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev)
dev_dbg(&client->dev, "reg %d, err %d\n",
regs_byte[i].reg, status);
*(regs_byte[i].value) = 0;
goto exit;
}
else {
*(regs_byte[i].value) = status;
@ -614,6 +627,7 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev)
dev_dbg(&client->dev, "reg %d, err %d\n",
regs_word[i].reg, status);
*(regs_word[i].value) = 0;
goto exit;
}
else {
*(regs_word[i].value) = status;
@ -626,6 +640,7 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev)
if (status < 0) {
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
goto exit;
}
strncpy(data->fan_dir, fan_dir+1, ARRAY_SIZE(data->fan_dir)-1);
@ -642,12 +657,61 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev)
/* Read mfr_model */
command = 0x9a;
status = ym2651y_read_block(client, command, data->mfr_model,
ARRAY_SIZE(data->mfr_model)-1);
data->mfr_model[ARRAY_SIZE(data->mfr_model)-1] = '\0';
length = 1;
/* Read first byte to determine the length of data */
status = ym2651y_read_block(client, command, &buf, length);
if (status < 0) {
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
goto exit;
}
status = ym2651y_read_block(client, command, data->mfr_model, buf+1);
if ((buf+1) >= (ARRAY_SIZE(data->mfr_model)-1))
{
data->mfr_model[ARRAY_SIZE(data->mfr_model)-1] = '\0';
}
else
data->mfr_model[buf+1] = '\0';
if (status < 0)
{
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
goto exit;
}
/*YM-1401A PSU doens't support to get serial_num, so ignore it.
*It's vout doesn't support linear, so let it use show_vout_by_mode().
*/
if(!strncmp("YM-1401A", data->mfr_model+1, strlen("YM-1401A")))
{
data->chip=YM1401A;
}
else
{
/* Read mfr_serial */
command = 0x9e;
length = 1;
/* Read first byte to determine the length of data */
status = ym2651y_read_block(client, command, &buf, length);
if (status < 0) {
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
goto exit;
}
status = ym2651y_read_block(client, command, data->mfr_serial, buf+1);
if ((buf+1) >= (ARRAY_SIZE(data->mfr_serial)-1))
{
data->mfr_serial[ARRAY_SIZE(data->mfr_serial)-1] = '\0';
}
else
data->mfr_serial[buf+1] = '\0';
if (status < 0)
{
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
goto exit;
}
}
/* Read mfr_revsion */
command = 0x9b;
@ -656,12 +720,16 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev)
data->mfr_revsion[ARRAY_SIZE(data->mfr_revsion)-1] = '\0';
if (status < 0)
{
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
goto exit;
}
data->last_updated = jiffies;
data->valid = 1;
}
exit:
mutex_unlock(&data->update_lock);
return data;

View File

@ -1 +1 @@
as4630-54pe/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as4630_54pe-r0/pddf
as4630-54pe/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as4630_54pe-r0

View File

@ -1,8 +0,0 @@
# Special arrangement to make PDDF mode default
# Disable monitor, monitor-fan, monitor-psu (not enabling them would imply they will be disabled by default)
# Enable pddf-platform-monitor
depmod -a
systemctl enable pddf-platform-init.service
systemctl start pddf-platform-init.service
systemctl enable as4630-54pe-pddf-platform-monitor.service
systemctl start as4630-54pe-pddf-platform-monitor.service

View File

@ -1 +1,2 @@
as7326-56x/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as7326_56x-r0/pddf
as7326-56x/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as7326_56x-r0

View File

@ -1 +1,2 @@
as7816-64x/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as7816_64x-r0/pddf
as7816-64x/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as7816_64x-r0