diff --git a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py index 40c4bb4ef73b..b6e2dea0f67c 100644 --- a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py @@ -13,13 +13,11 @@ import json try: + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper from sonic_platform_base.chassis_base import ChassisBase - from sonic_platform.fan import Fan - from sonic_platform.psu import Psu - from sonic_platform.component import Component - from sonic_platform.thermal import Thermal - from sonic_platform.sfp import Sfp - from sonic_platform.eeprom import Tlv + from sonic_py_common import device_info + from .event import SfpEvent + from .helper import APIHelper except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -40,29 +38,62 @@ class Chassis(ChassisBase): def __init__(self): ChassisBase.__init__(self) - self.config_data = {} + self._api_helper = APIHelper() + self.sfp_module_initialized = False + self.__initialize_eeprom() + self.is_host = self._api_helper.is_host() + + + if not self.is_host: + self.__initialize_fan() + self.__initialize_psu() + self.__initialize_thermals() + else: + self.__initialize_components() + + self._reboot_cause_path = HOST_REBOOT_CAUSE_PATH if self.__is_host( + ) else PMON_REBOOT_CAUSE_PATH + + def __initialize_sfp(self): + sfputil_helper = SfpUtilHelper() + port_config_file_path = device_info.get_path_to_port_config_file() + sfputil_helper.read_porttab_mappings(port_config_file_path, 0) + + from sonic_platform.sfp import Sfp + for index in range(0, NUM_SFP): + name_idx = 0 if index+1 == NUM_SFP else index+1 + sfp = Sfp(index, sfputil_helper.logical[name_idx]) + self._sfp_list.append(sfp) + self.sfp_module_initialized = True + + 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_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) - 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) - # sfp index start from 1 - self._sfp_list.append(None) - for index in range(1, NUM_SFP+1): - sfp = Sfp(index) - self._sfp_list.append(sfp) + + 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) - self._reboot_cause_path = HOST_REBOOT_CAUSE_PATH if self.__is_host( - ) else PMON_REBOOT_CAUSE_PATH - - self._eeprom = Tlv() def __is_host(self): return os.system(HOST_CHK_CMD) == 0 @@ -85,14 +116,6 @@ def get_base_mac(self): """ return self._eeprom.get_mac() - 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 @@ -116,7 +139,8 @@ def get_reboot_cause(self): """ description = 'None' reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER - hw_reboot_cause = self._component_list[0].get_register_value(RESET_REGISTER) + hw_reboot_cause = self._component_list[0].get_register_value( + RESET_REGISTER) sw_reboot_cause = self.__read_txt_file( self._reboot_cause_path) or "Unknown" @@ -145,3 +169,128 @@ def get_watchdog(self): self._watchdog = Watchdog() return self._watchdog + + def get_change_event(self, timeout=0): + """ + Returns a nested dictionary containing all devices which have + experienced a change at chassis level + Args: + timeout: Timeout in milliseconds (optional). If timeout == 0, + this method will block until a change is detected. + Returns: + (bool, dict): + - True if call successful, False if not; + - A nested dictionary where key is a device type, + value is a dictionary with key:value pairs in the format of + {'device_id':'device_event'}, + where device_id is the device ID for this device and + device_event, + status='1' represents device inserted, + status='0' represents device removed. + Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}} + indicates that fan 0 has been removed, fan 2 + has been inserted and sfp 11 has been removed. + """ + # SFP event + if not self.sfp_module_initialized: + self.__initialize_sfp() + + sfp_event = SfpEvent(self._sfp_list).get_sfp_event(timeout) + if sfp_event: + return True, {'sfp': sfp_event} + + return False, {'sfp': {}} + + ############################################################## + ######################## SFP methods ######################### + ############################################################## + + def get_num_sfps(self): + """ + Retrieves the number of sfps available on this chassis + Returns: + An integer, the number of sfps available on this chassis + """ + if not self.sfp_module_initialized: + self.__initialize_sfp() + + return len(self._sfp_list) + + def get_all_sfps(self): + """ + Retrieves all sfps available on this chassis + Returns: + A list of objects derived from SfpBase representing all sfps + available on this chassis + """ + if not self.sfp_module_initialized: + self.__initialize_sfp() + + return self._sfp_list + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + For example, 1 for Ethernet0, 2 for Ethernet4 and so on. + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + if not self.sfp_module_initialized: + self.__initialize_sfp() + + try: + # The index will start from 1 + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + return sfp + + ############################################################## + ###################### Device methods ######################## + ############################################################## + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return self._api_helper.hwsku + + def get_presence(self): + """ + Retrieves the presence of the Chassis + Returns: + bool: True if Chassis is present, False if not + """ + return True + + def get_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 serial number of the device + Returns: + string: Serial number of device + """ + return self._eeprom.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 True diff --git a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/event.py b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/event.py new file mode 100644 index 000000000000..c8a487f383ea --- /dev/null +++ b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/event.py @@ -0,0 +1,62 @@ +try: + import time + import select + from .helper import APIHelper + from sonic_py_common.logger import Logger +except ImportError as e: + raise ImportError(repr(e) + " - required module not found") + + +class SfpEvent: + ''' Listen to insert/remove sfp events ''' + + SFP_NUM_START = 49 + DELAY = 0.05 + INT_PATH = '/sys/devices/platform/e1031.smc/SFP/modabs_int' + GPIO_SUS7 = '/sys/devices/platform/hlx-ich.0/sci_int_gpio_sus7' + + def __init__(self, sfp_list): + self._api_helper = APIHelper() + self._sfp_list = sfp_list + self._logger = Logger() + + # clear interrupt + self._api_helper.read_one_line_file(self.INT_PATH) + + def get_sfp_event(self, timeout): + epoll = select.epoll() + port_dict = {} + timeout_sec = timeout/1000 + + try: + # We get notified when there is an SCI interrupt from GPIO SUS7 + fd = open(self.GPIO_SUS7, "r") + fd.read() + + epoll.register(fd.fileno(), select.EPOLLIN & select.EPOLLET) + events = epoll.poll(timeout=timeout_sec if timeout != 0 else -1) + if events: + # Read the QSFP ABS interrupt & status registers + port_changes = self._api_helper.read_one_line_file( + self.INT_PATH) + changes = int(port_changes, 16) + for sfp in self._sfp_list: + if sfp.port_num < self.SFP_NUM_START: + continue + + change = (changes >> sfp.port_num-self.SFP_NUM_START) & 1 + if change == 1: + time.sleep(self.DELAY) + port_status = sfp.get_presence() + port_dict[str(sfp.port_num)] = '1' if port_status else '0' + + return port_dict + except Exception as e: + self._logger.log_error("Failed to detect SfpEvent - " + repr(e)) + return False + + finally: + fd.close() + epoll.close() + + return False diff --git a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/fan.py b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/fan.py index 18cf513800aa..cebed613db92 100644 --- a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/fan.py +++ b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/fan.py @@ -247,3 +247,11 @@ def get_presence(self): present_str = self.__read_txt_file(fan_direction_file) or '1' return int(present_str) == 0 if not self.is_psu_fan else 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 self.get_presence() and self.get_speed() > 0 \ No newline at end of file diff --git a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/helper.py b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/helper.py new file mode 100644 index 000000000000..75449ab55185 --- /dev/null +++ b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/helper.py @@ -0,0 +1,133 @@ +import os +import struct +import subprocess +from mmap import * + +from sonic_py_common import device_info + +HOST_CHK_CMD = "docker > /dev/null 2>&1" +EMPTY_STRING = "" + + +class APIHelper(): + + def __init__(self): + (self.platform, self.hwsku) = device_info.get_platform_and_hwsku() + + def is_host(self): + return os.system(HOST_CHK_CMD) == 0 + + def pci_get_value(self, resource, offset): + status = True + result = "" + try: + fd = os.open(resource, os.O_RDWR) + mm = mmap(fd, 0) + mm.seek(int(offset)) + read_data_stream = mm.read(4) + result = struct.unpack('I', read_data_stream) + except Exception: + status = False + return status, result + + def run_command(self, cmd): + status = True + result = "" + try: + p = subprocess.Popen( + cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + except Exception: + status = False + return status, result + + def run_interactive_command(self, cmd): + try: + os.system(cmd) + except Exception: + return False + return True + + def read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return None + + def read_one_line_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.readline() + return data.strip() + except IOError: + pass + return None + + def write_txt_file(self, file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(str(value)) + except Exception: + return False + return True + + def get_cpld_reg_value(self, getreg_path, register): + cmd = "echo {1} > {0}; cat {0}".format(getreg_path, register) + status, result = self.run_command(cmd) + return result if status else None + + def ipmi_raw(self, netfn, cmd): + status = True + result = "" + try: + cmd = "ipmitool raw {} {}".format(str(netfn), str(cmd)) + p = subprocess.Popen( + cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_fru_id(self, id, key=None): + status = True + result = "" + try: + cmd = "ipmitool fru print {}".format(str( + id)) if not key else "ipmitool fru print {0} | grep '{1}' ".format(str(id), str(key)) + + p = subprocess.Popen( + cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_set_ss_thres(self, id, threshold_key, value): + status = True + result = "" + try: + cmd = "ipmitool sensor thresh '{}' {} {}".format( + str(id), str(threshold_key), str(value)) + p = subprocess.Popen( + cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result diff --git a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/sfp.py b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/sfp.py index 608111d7e2fd..36ee9cbc01a0 100644 --- a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/sfp.py +++ b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/sfp.py @@ -16,7 +16,6 @@ from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId from sonic_platform_base.sonic_sfp.sff8472 import sffbase - from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -88,10 +87,10 @@ class Sfp(SfpBase): PLATFORM = "x86_64-cel_e1031-r0" HWSKU = "Celestica-E1031-T48S4" - def __init__(self, sfp_index): + def __init__(self, sfp_index, sfp_name): # Init index self.index = sfp_index - self.port_num = self.index + self.port_num = self.index + 1 # Init eeprom path eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' @@ -111,6 +110,7 @@ def __init__(self, sfp_index): self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', 'rxpowerhighwarning', 'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] + self.name = sfp_name SfpBase.__init__(self) def _convert_string_to_num(self, value_str): @@ -145,12 +145,6 @@ def __read_txt_file(self, file_path): 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 = [] @@ -670,11 +664,7 @@ def get_name(self): 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 + return self.name def get_presence(self): """ diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.install index 167de45532db..ec56777b9ffb 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.install +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.install @@ -4,6 +4,7 @@ haliburton/script/fancontrol.sh etc/init.d haliburton/script/fancontrol.service lib/systemd/system services/fancontrol/fancontrol usr/local/bin haliburton/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_e1031-r0 +haliburton/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-cel_e1031-r0 services/platform_api/platform_api_mgnt.sh usr/local/bin haliburton/script/popmsg.sh usr/local/bin haliburton/script/udev_prefix.sh usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/rules b/platform/broadcom/sonic-platform-modules-cel/debian/rules index a7293e0b6700..efb5aa47b437 100755 --- a/platform/broadcom/sonic-platform-modules-cel/debian/rules +++ b/platform/broadcom/sonic-platform-modules-cel/debian/rules @@ -13,13 +13,15 @@ MODULE_DIRS:= dx010 haliburton silverstone seastone2 override_dh_auto_build: (for mod in $(MODULE_DIRS); do \ make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \ - cd $(MOD_SRC_DIR)/$${mod}; \ - python2.7 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ - cd $(MOD_SRC_DIR); \ if [ $$mod = "seastone2" ]; then \ cd services/platform_api; \ - python2 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ - fi \ + python2.7 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ + python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ + continue; \ + fi; \ + cd $(MOD_SRC_DIR)/$${mod}; \ + python2.7 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ + python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ done) override_dh_auto_install: @@ -37,4 +39,3 @@ override_dh_clean: (for mod in $(MODULE_DIRS); do \ make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules clean; \ done) - diff --git a/platform/broadcom/sonic-platform-modules-cel/services/platform_api/platform_api_mgnt.sh b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/platform_api_mgnt.sh index e1d330357894..493119bd37f6 100755 --- a/platform/broadcom/sonic-platform-modules-cel/services/platform_api/platform_api_mgnt.sh +++ b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/platform_api_mgnt.sh @@ -9,6 +9,7 @@ install() { # Install sonic-platform package if [ -e $DEVICE/$PLATFORM/sonic_platform-1.0-py2-none-any.whl ]; then pip install $DEVICE/$PLATFORM/sonic_platform-1.0-py2-none-any.whl + pip3 install $device/$platform/sonic_platform-1.0-py3-none-any.whl fi }