-
Notifications
You must be signed in to change notification settings - Fork 0
[sonic_platform]support install firmware #18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
2c8e646
80ecdaa
f73b20b
b411566
37b11ca
30a4ae7
9477140
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,13 +5,14 @@ | |
| # | ||
| # implementation of new platform api | ||
| ############################################################################# | ||
|
|
||
| from __future__ import print_function | ||
| try: | ||
| from sonic_platform_base.component_base import ComponentBase | ||
| from glob import glob | ||
| import subprocess | ||
| import io | ||
| import re | ||
| import sys | ||
| except ImportError as e: | ||
| raise ImportError(str(e) + "- required module not found") | ||
|
|
||
|
|
@@ -23,6 +24,26 @@ | |
| CPLD_VERSION_FILE_PATTERN = '/var/run/hw-management/system/cpld[0-9]_version' | ||
| CPLD_VERSION_MAX_LENGTH = 4 | ||
stephenxs marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| CPLD_UPDATE_COMMAND = "cpldupdate --dev {} {}" | ||
| CPLD_INSTALL_SUCCESS_FLAG = "PASS!" | ||
|
|
||
| MST_DEVICE_PATTERN = "/dev/mst/mt[0-9]*_pciconf0" | ||
| MACHINE_CONF_FILE = "/host/machine.conf" | ||
stephenxs marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
stephenxs marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| MACHINE_CONF_MAX_SIZE = 2048 | ||
|
|
||
| BIOS_VERSION_PARSE_PATTERN = 'OEM[\s]*Strings\n[\s]*String[\s]*1:[\s]*([0-9a-zA-Z_\.]*)' | ||
| ONIE_VERSION_PARSE_PATTERN = 'onie_version=[0-9]{4}\.[0-9]{2}-([0-9]+)\.([0-9]+)\.([0-9]+)' | ||
| ONIE_VERSION_MAJOR_OFFSET = 1 | ||
| ONIE_VERSION_MINOR_OFFSET = 2 | ||
| ONIE_VERSION_RELEASE_OFFSET = 3 | ||
| # To update BIOS requires the ONIE with version 5.2.0016 or upper | ||
| ONIE_REQUIRED_MAJOR = "5" | ||
| ONIE_REQUIRED_MINOR = "2" | ||
| ONIE_REQUIRED_RELEASE = "0016" | ||
|
|
||
| ONIE_FW_UPDATE_CMD_ADD = "/usr/bin/onie-fw-update add {}" | ||
| ONIE_FW_UPDATE_CMD_UPDATE = "/usr/bin/onie-fw-update update" | ||
stephenxs marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| class Component(ComponentBase): | ||
| def get_name(self): | ||
| """ | ||
|
|
@@ -60,10 +81,16 @@ def _get_command_result(self, cmdline): | |
| return result | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @stephenxs do we need also check Exit Code here?
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's OK here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @stephenxs ok. |
||
|
|
||
|
|
||
| class ComponentBIOS(Component): | ||
| BIOS_VERSION_PARSE_PATTERN = 'OEM[\s]*Strings\n[\s]*String[\s]*1:[\s]*([0-9a-zA-Z_\.]*)' | ||
| def _does_file_exist(self, image_path): | ||
| image = glob(image_path) | ||
| if not image: | ||
| return False, "Failed to get the image file via {} or multiple files matched".format(image_path) | ||
stephenxs marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if len(image) != 1: | ||
| return False, "Multiple files {} matched {}".format(image, image_path) | ||
| return True, "" | ||
|
|
||
|
|
||
| class ComponentBIOS(Component): | ||
| def __init__(self): | ||
| self.name = COMPONENT_BIOS | ||
|
|
||
|
|
@@ -101,15 +128,63 @@ def get_firmware_version(self): | |
| """ | ||
| bios_ver_str = self._get_command_result(BIOS_QUERY_VERSION_COMMAND) | ||
| try: | ||
| m = re.search(self.BIOS_VERSION_PARSE_PATTERN, bios_ver_str) | ||
stephenxs marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| m = re.search(BIOS_VERSION_PARSE_PATTERN, bios_ver_str) | ||
| result = m.group(1) | ||
| except AttributeError as e: | ||
| raise RuntimeError("Failed to parse BIOS version by {} from {} due to {}".format( | ||
| self.BIOS_VERSION_PARSE_PATTERN, bios_ver_str, repr(e))) | ||
| BIOS_VERSION_PARSE_PATTERN, bios_ver_str, repr(e))) | ||
|
|
||
| return result | ||
|
|
||
|
|
||
| def install_firmware(self, image_path): | ||
| """ | ||
| Installs firmware to the component | ||
|
|
||
| Args: | ||
| image_path: A string, path to firmware image | ||
|
|
||
| Returns: | ||
| A boolean, True if install was successful, False if not | ||
| """ | ||
| # check ONIE version. To update ONIE requires version 5.2.0016 or later. | ||
| machine_conf = self._read_generic_file(MACHINE_CONF_FILE, MACHINE_CONF_MAX_SIZE) | ||
stephenxs marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| try: | ||
| m = re.search(ONIE_VERSION_PARSE_PATTERN, machine_conf) | ||
| onie_major = m.group(ONIE_VERSION_MAJOR_OFFSET) | ||
| onie_minor = m.group(ONIE_VERSION_MINOR_OFFSET) | ||
| onie_release = m.group(ONIE_VERSION_RELEASE_OFFSET) | ||
stephenxs marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| except AttributeError as e: | ||
| print("Failed to parse ONIE version by {} from {} due to {}".format( | ||
| BIOS_VERSION_PARSE_PATTERN, machine_conf, repr(e))) | ||
| return False | ||
| if onie_major < ONIE_REQUIRED_MAJOR or onie_minor < ONIE_REQUIRED_MINOR or onie_release < ONIE_REQUIRED_RELEASE: | ||
| print("ONIE {}.{}.{} or later is required".format(ONIE_REQUIRED_MAJOR, ONIE_REQUIRED_MINOR, ONIE_REQUIRED_RELEASE)) | ||
| return False | ||
|
|
||
| # check whether the file exists | ||
| image_exists, message = self._does_file_exist(image_path) | ||
stephenxs marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if not image_exists: | ||
| print(message) | ||
| return False | ||
|
|
||
| # do the real work. | ||
stephenxs marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| try: | ||
| result = subprocess.call(ONIE_FW_UPDATE_CMD_ADD.format(image_path).split()) | ||
stephenxs marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if result: | ||
| return False | ||
| result = subprocess.call(ONIE_FW_UPDATE_CMD_UPDATE.split()) | ||
stephenxs marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if result: | ||
| return False | ||
| except Exception as e: | ||
| print("Installing BIOS failed due to {}".format(repr(e))) | ||
| return False | ||
|
|
||
| print("Reboot via \"/sbin/reboot\" is required to finish BIOS installation.") | ||
| print("Please don't try installing a new sonic image before BIOS installation finishing") | ||
| return True | ||
|
|
||
|
|
||
| class ComponentCPLD(Component): | ||
| def __init__(self): | ||
| self.name = COMPONENT_CPLD | ||
|
|
@@ -146,3 +221,67 @@ def get_firmware_version(self): | |
|
|
||
| return cpld_version | ||
|
|
||
|
|
||
| def install_firmware(self, image_path): | ||
| """ | ||
| Installs firmware to the component | ||
|
|
||
| Args: | ||
| image_path: A string, path to firmware image | ||
|
|
||
| Returns: | ||
| A boolean, True if install was successful, False if not | ||
|
|
||
| Details: | ||
| The command "cpldupdate" is provided to install CPLD. There are two ways to do it: | ||
| 1. To burn CPLD via gpio, which is faster but only supported on new systems, like Anaconda, ... | ||
| 2. To install CPLD via firmware, which is slower but supported on older systems. | ||
| This also requires the mst device designated. | ||
| "cpldupdate --dev <devname> <vme_file>" has the logic of testing whether to update via gpio is supported, | ||
| and if so then go this way, otherwise tries updating software via fw. So we take advantage of it to update the CPLD. | ||
| By doing so we don't have to mind whether to update via gpio supported, which belongs to hardware details. | ||
|
|
||
| So the procedure should be: | ||
| 1. Test whether the file exists | ||
| 2. Fetch the mst device name | ||
| 3. Update CPLD via executing "cpldupdate --dev <devname> <vme_file>" | ||
| 4. Check the result | ||
| """ | ||
| # check whether the file exists | ||
| image_exists, message = self._does_file_exist(image_path) | ||
| if not image_exists: | ||
| print(message) | ||
| return False | ||
|
|
||
| mst_dev_list = glob(MST_DEVICE_PATTERN) | ||
stephenxs marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if not mst_dev_list or not len(mst_dev_list) == 1: | ||
| print("Failed to get mst device which is required for CPLD updating or multiple device files matched") | ||
| return False | ||
|
|
||
| cmdline = CPLD_UPDATE_COMMAND.format(mst_dev_list[0], image_path) | ||
| outputline = "" | ||
| success_flag = False | ||
| try: | ||
| proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE, shell=True, stderr=subprocess.STDOUT) | ||
| while True: | ||
| out = proc.stdout.read(1) | ||
| if out == '' and proc.poll() != None: | ||
| break | ||
| if out != '': | ||
| sys.stdout.write(out) | ||
| sys.stdout.flush() | ||
| outputline += out | ||
| if (out == '\n' or out == '\r') and len(outputline): | ||
| m = re.search(CPLD_INSTALL_SUCCESS_FLAG, outputline) | ||
| if m and m.group(0) == CPLD_INSTALL_SUCCESS_FLAG: | ||
| success_flag = True | ||
|
|
||
| except OSError as e: | ||
| raise RuntimeError("Failed to execute command {} due to {}".format(cmdline, repr(e))) | ||
|
|
||
| if success_flag: | ||
| print("Success. Refresh or power cycle is required to finish CPLD installation.") | ||
stephenxs marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| else: | ||
| print("Failed to install CPLD") | ||
|
|
||
| return success_flag | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,150 @@ | ||
| #!/bin/sh | ||
|
|
||
| # Copyright (C) 2019 Mellanox Technologies Ltd. | ||
| # Copyright (C) 2019 Michael Shych <michaelsh@mellanox.com> | ||
| # | ||
| # SPDX-License-Identifier: GPL-2.0 | ||
|
|
||
| this_script=${ONIE_FWPKG_PROGRAM_NAME:-$(basename $(realpath $0))} | ||
|
|
||
| onie_mount=/mnt/onie-boot | ||
| os_boot=/host | ||
| onie_partition= | ||
| onie_entry=0 | ||
|
|
||
| export ONIE_FWPKG_PROGRAM_NAME=$(basename $(realpath $0)) | ||
|
|
||
| usage() | ||
| { | ||
| cat <<EOF | ||
| update | ||
| The 'update' command will reboot system to ONIE update mode | ||
| and ONIE will perform automatically update of previously | ||
| added (i.e. pending) FW (ONIE itself, BIOS or CPLD) image. | ||
|
|
||
| EOF | ||
| } | ||
|
|
||
| enable_onie_access() | ||
| { | ||
| onie_partition=$(fdisk -l | grep "ONIE boot" | awk '{print $1}') | ||
| if [ ! -d $onie_mount ]; then | ||
| mkdir /mnt/onie-boot | ||
| fi | ||
| mount $onie_partition /mnt/onie-boot | ||
| if [ ! -e /lib/onie ]; then | ||
| ln -s /mnt/onie-boot/onie/tools/lib/onie /lib/onie | ||
| fi | ||
| PATH=/sbin:/usr/sbin:/bin:/usr/bin:$onie_mount/onie/tools/bin/ | ||
| export PATH | ||
| } | ||
|
|
||
| clean_onie_access() | ||
| { | ||
| rm -f /lib/onie | ||
| umount $onie_partition | ||
| } | ||
|
|
||
| # ONIE entry must exist in grub config | ||
| find_onie_menuentry() | ||
| { | ||
| onie_entry="$(cat $os_boot/grub/grub.cfg | grep -e 'menuentry' | cat -n | awk '$0~/ONIE/ {print $1-1}')" | ||
| entries_num="$(echo "$onie_entry" | grep -E '^[0-9]+$' | wc -l)" | ||
| if [ $entries_num -eq 1 ] && [ $onie_entry -ge 1 ]; then | ||
| return 0 | ||
| fi | ||
| return 1 | ||
| } | ||
|
|
||
| change_grub_boot_order() | ||
| { | ||
| find_onie_menuentry | ||
| rc=$? | ||
| if [ $rc -eq 0 ]; then | ||
| grub-reboot --boot-directory=$os_boot $onie_entry | ||
| else | ||
| echo "ERROR: ONIE entry wasn't found in grub config" | ||
| return 1 | ||
| fi | ||
|
|
||
| grub-editenv $onie_mount/grub/grubenv set onie_mode=update | ||
| return 0 | ||
| } | ||
|
|
||
| show_pending() | ||
| { | ||
| curr_dir=$(pwd) | ||
| cd $onie_mount/onie/update/pending || return 0 | ||
| num=$(find . -type f | wc -l) | ||
| if [ $num -ge 1 ]; then | ||
| echo "Number of FW update pending files are: "$num | ||
| ls -l * | awk {'print $9" "$5" "$7"-"$6" "$8'} | ||
| else | ||
| echo "There is no pending files for FW update." | ||
| fi | ||
| cd $curr_dir | ||
|
|
||
| return $num | ||
| } | ||
|
|
||
| system_reboot() | ||
| { | ||
| echo "Reboot will be done after 5 sec." | ||
| sleep 5 | ||
| /sbin/reboot | ||
| } | ||
|
|
||
| # Process command arguments | ||
| cmd=$1 | ||
| # optional argument | ||
| name="$2" | ||
|
|
||
| if [ -z "$cmd" ] ; then | ||
| # Default to 'show' if no command is specified. | ||
| cmd="show" | ||
| fi | ||
|
|
||
| case "$cmd" in | ||
| add | remove) | ||
| [ -z "$name" ] && { | ||
| echo "ERROR: This command requires a firmware update file name." | ||
| echo "Run '$this_script help' for complete details." | ||
| exit 1 | ||
| } | ||
| ;; | ||
| update) | ||
| enable_onie_access | ||
| show_pending | ||
| rc=$? | ||
| if [ $rc -ne 0 ]; then | ||
| change_grub_boot_order | ||
| rc=$? | ||
| clean_onie_access | ||
| if [ $rc -eq 0 ]; then | ||
| system_reboot | ||
|
||
| fi | ||
| exit $rc | ||
| else | ||
| echo "ERROR: NO FW images for update." | ||
| echo "Run: $this_script add <image> before update." | ||
| clean_onie_access | ||
| exit 1 | ||
| fi | ||
| ;; | ||
| purge | show | show-results | show-log | show-pending | help) | ||
| ;; | ||
| *) | ||
| echo "Unknown command: $cmd" | ||
| exit 1 | ||
| ;; | ||
| esac | ||
|
|
||
| enable_onie_access | ||
| $onie_mount/onie/tools/bin/onie-fwpkg "$@" | ||
| rc=$? | ||
| if [ $cmd = "help" ]; then | ||
| usage | ||
| fi | ||
| clean_onie_access | ||
|
|
||
| exit $rc | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # bios update tool | ||
|
|
||
| ONIE_FW_UPDATE= onie-fw-update | ||
| $(ONIE_FW_UPDATE)_PATH = platform/mellanox/ | ||
| SONIC_COPY_FILES += $(ONIE_FW_UPDATE) | ||
|
|
||
| export ONIE_FW_UPDATE |
Uh oh!
There was an error while loading. Please reload this page.