From 1616f482e7b8a8c05a53ebe22f1b8211049caa5b Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Wed, 3 Jul 2019 01:05:18 +0700 Subject: [PATCH] [device/celestica]: Add firmware management api based on the new platform API (#3013) --- .../sonic_platform/chassis.py | 67 ++++----- .../sonic_platform/component.py | 128 +++++++++++++++++ .../sonic_platform/device.py | 47 +++++++ .../sonic_platform/chassis.py | 68 ++++----- .../sonic_platform/component.py | 130 ++++++++++++++++++ .../sonic_platform/device.py | 47 +++++++ src/sonic-platform-common | 2 +- 7 files changed, 403 insertions(+), 86 deletions(-) create mode 100644 device/celestica/x86_64-cel_e1031-r0/sonic_platform/component.py create mode 100644 device/celestica/x86_64-cel_e1031-r0/sonic_platform/device.py create mode 100644 device/celestica/x86_64-cel_seastone-r0/sonic_platform/component.py create mode 100644 device/celestica/x86_64-cel_seastone-r0/sonic_platform/device.py 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 4dee5ac87784..25668e2113f7 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 @@ -18,14 +18,12 @@ from sonic_platform_base.chassis_base import ChassisBase from sonic_platform.fan import Fan from sonic_platform.psu import Psu + from sonic_platform.device import Device + from sonic_platform.component import Component except ImportError as e: raise ImportError(str(e) + "- required module not found") -MMC_CPLD_ADDR = '0x100' -BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" CONFIG_DB_PATH = "/etc/sonic/config_db.json" -SMC_CPLD_PATH = "/sys/devices/platform/e1031.smc/version" -MMC_CPLD_PATH = "/sys/devices/platform/e1031.smc/getreg" NUM_FAN = 3 NUM_PSU = 2 @@ -42,16 +40,8 @@ def __init__(self): psu = Psu(index) self._psu_list.append(psu) ChassisBase.__init__(self) - - def __get_register_value(self, path, register): - cmd = "echo {1} > {0}; cat {0}".format(path, register) - p = subprocess.Popen( - cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - raw_data, err = p.communicate() - if err is not '': - return 'None' - else: - return raw_data.strip() + self._component_device = Device("component") + self._component_name_list = self._component_device.get_name_list() def __read_config_db(self): try: @@ -75,39 +65,32 @@ def get_base_mac(self): except KeyError: raise KeyError("Base MAC not found") - def get_component_versions(self): + def get_firmware_version(self, component_name): """ Retrieves platform-specific hardware/firmware versions for chassis componenets such as BIOS, CPLD, FPGA, etc. + Args: + type: A string, component name + Returns: A string containing platform-specific component versions """ + self.component = Component(component_name) + if component_name not in self._component_name_list: + return None + return self.component.get_firmware_version() - component_versions = dict() - - # Get BIOS version - try: - with open(BIOS_VERSION_PATH, 'r') as fd: - bios_version = fd.read() - except IOError: - raise IOError("Unable to open version file !") - - # Get CPLD version - cpld_version = dict() - - with open(SMC_CPLD_PATH, 'r') as fd: - smc_cpld_version = fd.read() - smc_cpld_version = 'None' if smc_cpld_version is 'None' else "{}.{}".format( - int(smc_cpld_version[2], 16), int(smc_cpld_version[3], 16)) - - mmc_cpld_version = self.__get_register_value( - MMC_CPLD_PATH, MMC_CPLD_ADDR) - mmc_cpld_version = 'None' if mmc_cpld_version is 'None' else "{}.{}".format( - int(mmc_cpld_version[2], 16), int(mmc_cpld_version[3], 16)) - - cpld_version["SMC"] = smc_cpld_version - cpld_version["MMC"] = mmc_cpld_version + def install_component_firmware(self, component_name, image_path): + """ + Install firmware to module + Args: + type: A string, component name. + image_path: A string, path to firmware image. - component_versions["CPLD"] = cpld_version - component_versions["BIOS"] = bios_version.strip() - return str(component_versions) + Returns: + A boolean, True if install successfully, False if not + """ + self.component = Component(component_name) + if component_name not in self._component_name_list: + return False + return self.component.upgrade_firmware(image_path) diff --git a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/component.py b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/component.py new file mode 100644 index 000000000000..7a3e05b4828d --- /dev/null +++ b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/component.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Component contains an implementation of SONiC Platform Base API and +# provides the components firmware management function +# +############################################################################# + +import json +import os.path +import shutil +import shlex +import subprocess + +try: + from sonic_platform_base.device_base import DeviceBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +MMC_CPLD_ADDR = '0x100' +BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" +CONFIG_DB_PATH = "/etc/sonic/config_db.json" +SMC_CPLD_PATH = "/sys/devices/platform/e1031.smc/version" +MMC_CPLD_PATH = "/sys/devices/platform/e1031.smc/getreg" + + +class Component(DeviceBase): + """Platform-specific Component class""" + + DEVICE_TYPE = "component" + + def __init__(self, component_name): + DeviceBase.__init__(self) + self.name = component_name.upper() + + 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: + return False + return True + + def __get_register_value(self, path, register): + # Retrieves the cpld register value + cmd = "echo {1} > {0}; cat {0}".format(path, register) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err is not '': + return None + return raw_data.strip() + + 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() + with open(SMC_CPLD_PATH, 'r') as fd: + smc_cpld_version = fd.read() + smc_cpld_version = 'None' if smc_cpld_version is 'None' else "{}.{}".format( + int(smc_cpld_version[2], 16), int(smc_cpld_version[3], 16)) + + mmc_cpld_version = self.__get_register_value( + MMC_CPLD_PATH, MMC_CPLD_ADDR) + mmc_cpld_version = 'None' if mmc_cpld_version is 'None' else "{}.{}".format( + int(mmc_cpld_version[2], 16), int(mmc_cpld_version[3], 16)) + + cpld_version["SMC_CPLD"] = smc_cpld_version + cpld_version["MMC_CPLD"] = mmc_cpld_version + return cpld_version + + 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 upgrade_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 + """ + if not os.path.isfile(image_path): + return False + + if "CPLD" in self.name: + img_name = os.path.basename(image_path) + root, ext = os.path.splitext(img_name) + ext = ".vme" if ext == "" else ext + new_image_path = os.path.join("/tmp", (root.lower() + ext)) + shutil.copy(image_path, new_image_path) + install_command = "ispvm %s" % new_image_path + elif self.name == "BIOS": + print("Not supported") + return False + + return self.__run_command(install_command) diff --git a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/device.py b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/device.py new file mode 100644 index 000000000000..e95d372510d1 --- /dev/null +++ b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/device.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Device contains an implementation of SONiC Platform Base API and +# provides the device information +# +############################################################################# + +try: + from sonic_platform_base.device_base import DeviceBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Device(DeviceBase): + """Platform-specific Device class""" + + COMPONENTS_NAME = ["SMC_CPLD", "MMC_CPLD", "BIOS"] + + def __init__(self, device_type, index=None): + self.device_type = device_type + self.index = index + DeviceBase.__init__(self) + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + device_name = { + "component": self.COMPONENTS_NAME[self.index] + }.get(self.device_type, None) + return device_name + + def get_name_list(self): + """ + Retrieves list of the device name that available in this device type + Returns: + string: The list of device name + """ + name_list = { + "component": self.COMPONENTS_NAME + }.get(self.device_type, None) + return name_list diff --git a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/chassis.py index e7c62e372b34..91e456e094ca 100644 --- a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/chassis.py @@ -18,21 +18,14 @@ from sonic_platform_base.chassis_base import ChassisBase from sonic_platform.fan import Fan from sonic_platform.psu import Psu + from sonic_platform.device import Device + from sonic_platform.component import Component except ImportError as e: raise ImportError(str(e) + "- required module not found") -BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" -GETREG_PATH = "/sys/devices/platform/dx010_cpld/getreg" CONFIG_DB_PATH = "/etc/sonic/config_db.json" NUM_FAN = 5 NUM_PSU = 2 -CPLD_ADDR_MAPPING = { - "CPLD1": "0x100", - "CPLD2": "0x200", - "CPLD3": "0x280", - "CPLD4": "0x300", - "CPLD5": "0x380" -} class Chassis(ChassisBase): @@ -47,16 +40,8 @@ def __init__(self): psu = Psu(index) self._psu_list.append(psu) ChassisBase.__init__(self) - - def __get_register_value(self, path, register): - cmd = "echo {1} > {0}; cat {0}".format(path, register) - p = subprocess.Popen( - cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - raw_data, err = p.communicate() - if err is not '': - return 'None' - else: - return raw_data.strip() + self._component_device = Device("component") + self._component_name_list = self._component_device.get_name_list() def __read_config_db(self): try: @@ -80,35 +65,32 @@ def get_base_mac(self): except KeyError: raise KeyError("Base MAC not found") - def get_component_versions(self): + def get_firmware_version(self, component_name): """ Retrieves platform-specific hardware/firmware versions for chassis componenets such as BIOS, CPLD, FPGA, etc. + Args: + type: A string, component name + Returns: A string containing platform-specific component versions """ + self.component = Component(component_name) + if component_name not in self._component_name_list: + return None + return self.component.get_firmware_version() - component_versions = dict() - - # Get BIOS version - try: - with open(BIOS_VERSION_PATH, 'r') as fd: - bios_version = fd.read() - except IOError: - raise IOError("Unable to open version file !") + def install_component_firmware(self, component_name, image_path): + """ + Install firmware to module + Args: + type: A string, component name. + image_path: A string, path to firmware image. - # Get CPLD version - cpld_version = dict() - for cpld_name in CPLD_ADDR_MAPPING: - try: - cpld_addr = CPLD_ADDR_MAPPING[cpld_name] - cpld_version_raw = self.__get_register_value( - GETREG_PATH, cpld_addr) - cpld_version_str = "{}.{}".format(int(cpld_version_raw[2], 16), int( - cpld_version_raw[3], 16)) if cpld_version_raw is not None else 'None' - cpld_version[cpld_name] = cpld_version_str - except Exception, e: - cpld_version[cpld_name] = 'None' - component_versions["CPLD"] = cpld_version - component_versions["BIOS"] = bios_version.strip() - return str(component_versions) + Returns: + A boolean, True if install successfully, False if not + """ + self.component = Component(component_name) + if component_name not in self._component_name_list: + return False + return self.component.upgrade_firmware(image_path) diff --git a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/component.py b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/component.py new file mode 100644 index 000000000000..b85bab7432eb --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/component.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Component contains an implementation of SONiC Platform Base API and +# provides the components firmware management function +# +############################################################################# + +import json +import os.path +import shutil +import shlex +import subprocess + +try: + from sonic_platform_base.device_base import DeviceBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CPLD_ADDR_MAPPING = { + "CPLD1": "0x100", + "CPLD2": "0x200", + "CPLD3": "0x280", + "CPLD4": "0x300", + "CPLD5": "0x380" +} +GETREG_PATH = "/sys/devices/platform/dx010_cpld/getreg" +BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" + + +class Component(DeviceBase): + """Platform-specific Component class""" + + DEVICE_TYPE = "component" + + def __init__(self, component_name): + DeviceBase.__init__(self) + self.name = component_name.upper() + + 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: + return False + return True + + def __get_register_value(self, path, register): + # Retrieves the cpld register value + cmd = "echo {1} > {0}; cat {0}".format(path, register) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err is not '': + return None + return raw_data.strip() + + 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_addr = CPLD_ADDR_MAPPING[cpld_name] + cpld_version_raw = self.__get_register_value( + GETREG_PATH, cpld_addr) + cpld_version_str = "{}.{}".format(int(cpld_version_raw[2], 16), int( + cpld_version_raw[3], 16)) if cpld_version_raw is not None else 'None' + cpld_version[cpld_name] = cpld_version_str + except Exception as e: + cpld_version[cpld_name] = 'None' + return cpld_version + + 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 upgrade_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 + """ + if not os.path.isfile(image_path): + return False + + if "CPLD" in self.name: + img_name = os.path.basename(image_path) + root, ext = os.path.splitext(img_name) + ext = ".vme" if ext == "" else ext + new_image_path = os.path.join("/tmp", (root.lower() + ext)) + shutil.copy(image_path, new_image_path) + install_command = "ispvm %s" % new_image_path + elif self.name == "BIOS": + print("Not supported") + return False + + return self.__run_command(install_command) diff --git a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/device.py b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/device.py new file mode 100644 index 000000000000..2d717beed3a8 --- /dev/null +++ b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/device.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Device contains an implementation of SONiC Platform Base API and +# provides the device information +# +############################################################################# + +try: + from sonic_platform_base.device_base import DeviceBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Device(DeviceBase): + """Platform-specific Device class""" + + COMPONENTS_NAME = ["CPLD1", "CPLD2", "CPLD3", "CPLD4", "BIOS"] + + def __init__(self, device_type, index=None): + self.device_type = device_type + self.index = index + DeviceBase.__init__(self) + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + device_name = { + "component": self.COMPONENTS_NAME[self.index] + }.get(self.device_type, None) + return device_name + + def get_name_list(self): + """ + Retrieves list of the device name that available in this device type + Returns: + string: The list of device name + """ + name_list = { + "component": self.COMPONENTS_NAME + }.get(self.device_type, None) + return name_list diff --git a/src/sonic-platform-common b/src/sonic-platform-common index 7f95a2a6f09b..56b5b14dec17 160000 --- a/src/sonic-platform-common +++ b/src/sonic-platform-common @@ -1 +1 @@ -Subproject commit 7f95a2a6f09b4dbaec9101fc9545bda95f541bea +Subproject commit 56b5b14dec179ddf445849fae2e7783ead0475b7