[Mellanox] Enhance Platform API to support SN2201 - RJ45 ports and new components mgmt. (#10377)
* Support new platform SN2201 and RJ45 port Signed-off-by: Kebo Liu <kebol@nvidia.com> * remove unused import and redundant function Signed-off-by: Kebo Liu <kebol@nvidia.com> * fix error introduced by rebase Signed-off-by: Kebo Liu <kebol@nvidia.com> * Revert the special handling of RJ45 ports (#56) * Revert the special handling of RJ45 ports sfp.py sfp_event.py chassis.py Signed-off-by: Stephen Sun <stephens@nvidia.com> * Remove deadcode Signed-off-by: Stephen Sun <stephens@nvidia.com> * Support CPLD update for SN2201 A new class is introduced, deriving from ComponentCPLD and overloading _install_firmware Change _install_firmware from private (starting with __) to protected, making it overloadable Signed-off-by: Stephen Sun <stephens@nvidia.com> * Initialize component BIOS/CPLD Signed-off-by: Stephen Sun <stephens@nvidia.com> * Remove swb_amb which doesn't on DVT board any more Signed-off-by: Stephen Sun <stephens@nvidia.com> * Remove the unexisted sensor - switch board ambient - from platform.json Signed-off-by: Stephen Sun <stephens@nvidia.com> * Do not report error on receiving unknown status on RJ45 ports Translate it to disconnect for RJ45 ports Report error for xSFP ports Signed-off-by: Stephen Sun <stephens@nvidia.com> * Add reinit for RJ45 to avoid exception Signed-off-by: Stephen Sun <stephens@nvidia.com> Co-authored-by: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Co-authored-by: Stephen Sun <stephens@nvidia.com>
This commit is contained in:
parent
71f47ed15b
commit
2f59460fc4
@ -90,9 +90,6 @@
|
||||
{
|
||||
"name": "Ambient CPU Board Temp"
|
||||
},
|
||||
{
|
||||
"name": "Ambient Switch Board Temp"
|
||||
},
|
||||
{
|
||||
"name": "CPU Pack Temp"
|
||||
},
|
||||
|
@ -4,6 +4,7 @@
|
||||
"component": {
|
||||
"ONIE": { },
|
||||
"SSD": { },
|
||||
"BIOS": { },
|
||||
"CPLD1": { },
|
||||
"CPLD2": { }
|
||||
}
|
||||
|
@ -27,14 +27,17 @@ try:
|
||||
from sonic_py_common.logger import Logger
|
||||
import os
|
||||
from functools import reduce
|
||||
|
||||
from .utils import extract_RJ45_ports_index
|
||||
from . import utils
|
||||
from .device_data import DeviceDataManager
|
||||
from .sfp import SFP, RJ45Port, deinitialize_sdk_handle
|
||||
except ImportError as e:
|
||||
raise ImportError (str(e) + "- required module not found")
|
||||
|
||||
MAX_SELECT_DELAY = 3600
|
||||
|
||||
RJ45_TYPE = "RJ45"
|
||||
|
||||
DMI_FILE = '/sys/firmware/dmi/entries/2-0/raw'
|
||||
DMI_HEADER_LEN = 15
|
||||
DMI_PRODUCT_NAME = "Product Name"
|
||||
@ -106,6 +109,10 @@ class Chassis(ChassisBase):
|
||||
self.sfp_initialized_count = 0
|
||||
self.sfp_event = None
|
||||
self.reboot_cause_initialized = False
|
||||
|
||||
# Build the RJ45 port list from platform.json and hwsku.json
|
||||
self.RJ45_port_list = extract_RJ45_ports_index()
|
||||
|
||||
logger.log_info("Chassis loaded successfully")
|
||||
|
||||
def __del__(self):
|
||||
@ -242,6 +249,9 @@ class Chassis(ChassisBase):
|
||||
|
||||
if not self._sfp_list[index]:
|
||||
from .sfp import SFP
|
||||
if self.RJ45_port_list and index in self.RJ45_port_list:
|
||||
self._sfp_list[index] = RJ45Port(index)
|
||||
else:
|
||||
self._sfp_list[index] = SFP(index)
|
||||
self.sfp_initialized_count += 1
|
||||
|
||||
@ -250,6 +260,9 @@ class Chassis(ChassisBase):
|
||||
from .sfp import SFP
|
||||
sfp_count = self.get_num_sfps()
|
||||
for index in range(sfp_count):
|
||||
if self.RJ45_port_list and index in self.RJ45_port_list:
|
||||
sfp_module = RJ45Port(index)
|
||||
else:
|
||||
sfp_module = SFP(index)
|
||||
self._sfp_list.append(sfp_module)
|
||||
self.sfp_initialized_count = sfp_count
|
||||
@ -257,6 +270,9 @@ class Chassis(ChassisBase):
|
||||
from .sfp import SFP
|
||||
for index in range(len(self._sfp_list)):
|
||||
if self._sfp_list[index] is None:
|
||||
if self.RJ45_port_list and index in self.RJ45_port_list:
|
||||
self._sfp_list[index] = RJ45Port(index)
|
||||
else:
|
||||
self._sfp_list[index] = SFP(index)
|
||||
self.sfp_initialized_count = len(self._sfp_list)
|
||||
|
||||
@ -324,7 +340,7 @@ class Chassis(ChassisBase):
|
||||
# Initialize SFP event first
|
||||
if not self.sfp_event:
|
||||
from .sfp_event import sfp_event
|
||||
self.sfp_event = sfp_event()
|
||||
self.sfp_event = sfp_event(self.RJ45_port_list)
|
||||
self.sfp_event.initialize()
|
||||
|
||||
wait_for_ever = (timeout == 0)
|
||||
@ -340,6 +356,7 @@ class Chassis(ChassisBase):
|
||||
status = self.sfp_event.check_sfp_status(port_dict, error_dict, timeout)
|
||||
|
||||
if status:
|
||||
if port_dict:
|
||||
self.reinit_sfps(port_dict)
|
||||
result_dict = {'sfp':port_dict}
|
||||
if error_dict:
|
||||
@ -515,8 +532,8 @@ class Chassis(ChassisBase):
|
||||
from .component import ComponentONIE, ComponentSSD, ComponentBIOS, ComponentCPLD
|
||||
self._component_list.append(ComponentONIE())
|
||||
self._component_list.append(ComponentSSD())
|
||||
self._component_list.append(ComponentBIOS())
|
||||
self._component_list.extend(ComponentCPLD.get_component_list())
|
||||
self._component_list.append(DeviceDataManager.get_bios_component())
|
||||
self._component_list.extend(DeviceDataManager.get_cpld_component_list())
|
||||
|
||||
def get_num_components(self):
|
||||
"""
|
||||
|
@ -29,6 +29,7 @@ try:
|
||||
import glob
|
||||
import tempfile
|
||||
import subprocess
|
||||
from sonic_py_common import device_info
|
||||
if sys.version_info[0] > 2:
|
||||
import configparser
|
||||
else:
|
||||
@ -136,8 +137,18 @@ class ONIEUpdater(object):
|
||||
|
||||
ONIE_IMAGE_INFO_COMMAND = '/bin/bash {} -q -i'
|
||||
|
||||
# Upgrading fireware from ONIE is not supported from the beginning on some platforms, like SN2700.
|
||||
# There is a logic to check the ONIE version in order to know whether it is supported.
|
||||
# If it is not supported, we will not proceed and print some error message.
|
||||
# For SN2201, upgrading fireware from ONIE is supported from day one so we do not need to check it.
|
||||
PLATFORM_ALWAYS_SUPPORT_UPGRADE = ['x86_64-nvidia_sn2201-r0']
|
||||
|
||||
BIOS_UPDATE_FILE_EXT = '.rom'
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.platform = device_info.get_platform()
|
||||
|
||||
def __add_prefix(self, image_path):
|
||||
if self.BIOS_UPDATE_FILE_EXT not in image_path:
|
||||
rename_path = "/tmp/00-{}".format(os.path.basename(image_path))
|
||||
@ -336,6 +347,9 @@ class ONIEUpdater(object):
|
||||
raise
|
||||
|
||||
def is_non_onie_firmware_update_supported(self):
|
||||
if self.platform in self.PLATFORM_ALWAYS_SUPPORT_UPGRADE:
|
||||
return True
|
||||
|
||||
current_version = self.get_onie_version()
|
||||
_, _, major1, minor1, release1, _ = self.parse_onie_version(current_version)
|
||||
version1 = int("{}{}{}".format(major1, minor1, release1))
|
||||
@ -698,6 +712,37 @@ class ComponentBIOS(Component):
|
||||
self.__install_firmware(image_path)
|
||||
|
||||
|
||||
class ComponentBIOSSN2201(Component):
|
||||
COMPONENT_NAME = 'BIOS'
|
||||
COMPONENT_DESCRIPTION = 'BIOS - Basic Input/Output System'
|
||||
|
||||
BIOS_VERSION_COMMAND = 'dmidecode -t0'
|
||||
|
||||
def __init__(self):
|
||||
super(ComponentBIOSSN2201, self).__init__()
|
||||
|
||||
self.name = self.COMPONENT_NAME
|
||||
self.description = self.COMPONENT_DESCRIPTION
|
||||
|
||||
def get_firmware_version(self):
|
||||
cmd = self.BIOS_VERSION_COMMAND
|
||||
|
||||
try:
|
||||
output = subprocess.check_output(cmd.split(),
|
||||
stderr=subprocess.STDOUT,
|
||||
universal_newlines=True).rstrip('\n')
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise RuntimeError("Failed to get {} version: {}".format(self.name, str(e)))
|
||||
|
||||
match = re.search('Version: (.*)', output)
|
||||
if match:
|
||||
version = match.group(1)
|
||||
else:
|
||||
version = 'Unknown version'
|
||||
|
||||
return version
|
||||
|
||||
|
||||
class ComponentCPLD(Component):
|
||||
COMPONENT_NAME = 'CPLD{}'
|
||||
COMPONENT_DESCRIPTION = 'CPLD - Complex Programmable Logic Device'
|
||||
@ -744,7 +789,7 @@ class ComponentCPLD(Component):
|
||||
|
||||
return mst_dev_list[0]
|
||||
|
||||
def __install_firmware(self, image_path):
|
||||
def _install_firmware(self, image_path):
|
||||
if not self._check_file_validity(image_path):
|
||||
return False
|
||||
|
||||
@ -830,9 +875,9 @@ class ComponentCPLD(Component):
|
||||
burn_firmware = mpfa.get_metadata().get('firmware', 'burn')
|
||||
|
||||
print("INFO: Processing {} burn file: firmware install".format(self.name))
|
||||
return self.__install_firmware(os.path.join(mpfa.get_path(), burn_firmware))
|
||||
return self._install_firmware(os.path.join(mpfa.get_path(), burn_firmware))
|
||||
else:
|
||||
return self.__install_firmware(image_path)
|
||||
return self._install_firmware(image_path)
|
||||
|
||||
def update_firmware(self, image_path):
|
||||
with MPFAManager(image_path) as mpfa:
|
||||
@ -845,11 +890,11 @@ class ComponentCPLD(Component):
|
||||
refresh_firmware = mpfa.get_metadata().get('firmware', 'refresh')
|
||||
|
||||
print("INFO: Processing {} burn file: firmware install".format(self.name))
|
||||
if not self.__install_firmware(os.path.join(mpfa.get_path(), burn_firmware)):
|
||||
if not self._install_firmware(os.path.join(mpfa.get_path(), burn_firmware)):
|
||||
return
|
||||
|
||||
print("INFO: Processing {} refresh file: firmware update".format(self.name))
|
||||
self.__install_firmware(os.path.join(mpfa.get_path(), refresh_firmware))
|
||||
self._install_firmware(os.path.join(mpfa.get_path(), refresh_firmware))
|
||||
|
||||
@classmethod
|
||||
def get_component_list(cls):
|
||||
@ -862,3 +907,19 @@ class ComponentCPLD(Component):
|
||||
component_list.append(cls(cpld_idx))
|
||||
|
||||
return component_list
|
||||
|
||||
|
||||
class ComponentCPLDSN2201(ComponentCPLD):
|
||||
CPLD_FIRMWARE_UPDATE_COMMAND = 'cpldupdate --gpio {} --uncustomized --print-progress'
|
||||
|
||||
def _install_firmware(self, image_path):
|
||||
cmd = self.CPLD_FIRMWARE_UPDATE_COMMAND.format(image_path)
|
||||
|
||||
try:
|
||||
print("INFO: Installing {} firmware update: path={}".format(self.name, image_path))
|
||||
subprocess.check_call(cmd.split(), universal_newlines=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print("ERROR: Failed to update {} firmware: {}".format(self.name, str(e)))
|
||||
return False
|
||||
|
||||
return True
|
||||
|
@ -158,8 +158,7 @@ DEVICE_DATA = {
|
||||
'thermal': {
|
||||
"capability": {
|
||||
"comex_amb": False,
|
||||
"cpu_amb": True,
|
||||
"swb_amb": True
|
||||
"cpu_amb": True
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -281,3 +280,21 @@ class DeviceDataManager:
|
||||
return None, None
|
||||
|
||||
return thermal_data.get('cpu_threshold', (None, None))
|
||||
|
||||
@classmethod
|
||||
def get_bios_component(cls):
|
||||
from .component import ComponentBIOS, ComponentBIOSSN2201
|
||||
if cls.get_platform_name() in ['x86_64-nvidia_sn2201-r0']:
|
||||
# For SN2201, special chass is required for handle BIOS
|
||||
# Currently, only fetching BIOS version is supported
|
||||
return ComponentBIOSSN2201()
|
||||
return ComponentBIOS()
|
||||
|
||||
@classmethod
|
||||
def get_cpld_component_list(cls):
|
||||
from .component import ComponentCPLD, ComponentCPLDSN2201
|
||||
if cls.get_platform_name() in ['x86_64-nvidia_sn2201-r0']:
|
||||
# For SN2201, special chass is required for handle BIOS
|
||||
# Currently, only fetching BIOS version is supported
|
||||
return ComponentCPLDSN2201.get_component_list()
|
||||
return ComponentCPLD.get_component_list()
|
||||
|
@ -80,6 +80,8 @@ QSFP_DD_TYPE_CODE_LIST = [
|
||||
'18' # QSFP-DD Double Density 8X Pluggable Transceiver
|
||||
]
|
||||
|
||||
RJ45_TYPE = "RJ45"
|
||||
|
||||
#variables for sdk
|
||||
REGISTER_NUM = 1
|
||||
DEVICE_ID = 1
|
||||
@ -235,7 +237,44 @@ class SdkHandleContext(object):
|
||||
deinitialize_sdk_handle(self.sdk_handle)
|
||||
|
||||
|
||||
class SFP(SfpOptoeBase):
|
||||
class NvidiaSFPCommon(SfpOptoeBase):
|
||||
def __init__(self, sfp_index):
|
||||
super(NvidiaSFPCommon, self).__init__()
|
||||
self.index = sfp_index + 1
|
||||
self.sdk_index = sfp_index
|
||||
|
||||
@property
|
||||
def sdk_handle(self):
|
||||
if not SFP.shared_sdk_handle:
|
||||
SFP.shared_sdk_handle = initialize_sdk_handle()
|
||||
if not SFP.shared_sdk_handle:
|
||||
logger.log_error('Failed to open SDK handle')
|
||||
return SFP.shared_sdk_handle
|
||||
|
||||
@classmethod
|
||||
def _get_module_info(self, sdk_handle, sdk_index):
|
||||
"""
|
||||
Get error code of the SFP module
|
||||
|
||||
Returns:
|
||||
The error code fetch from SDK API
|
||||
"""
|
||||
module_id_info_list = new_sx_mgmt_module_id_info_t_arr(1)
|
||||
module_info_list = new_sx_mgmt_phy_module_info_t_arr(1)
|
||||
|
||||
module_id_info = sx_mgmt_module_id_info_t()
|
||||
module_id_info.slot_id = 0
|
||||
module_id_info.module_id = sdk_index
|
||||
sx_mgmt_module_id_info_t_arr_setitem(module_id_info_list, 0, module_id_info)
|
||||
|
||||
rc = sx_mgmt_phy_module_info_get(sdk_handle, module_id_info_list, 1, module_info_list)
|
||||
assert SX_STATUS_SUCCESS == rc, "sx_mgmt_phy_module_info_get failed, error code {}".format(rc)
|
||||
|
||||
mod_info = sx_mgmt_phy_module_info_t_arr_getitem(module_info_list, 0)
|
||||
return mod_info.module_state.oper_state, mod_info.module_state.error_type
|
||||
|
||||
|
||||
class SFP(NvidiaSFPCommon):
|
||||
"""Platform-specific SFP class"""
|
||||
shared_sdk_handle = None
|
||||
SFP_MLNX_ERROR_DESCRIPTION_LONGRANGE_NON_MLNX_CABLE = 'Long range for non-Mellanox cable or module'
|
||||
@ -250,13 +289,11 @@ class SFP(SfpOptoeBase):
|
||||
SFP_MLNX_ERROR_BIT_PCIE_POWER_SLOT_EXCEEDED = 0x00080000
|
||||
SFP_MLNX_ERROR_BIT_RESERVED = 0x80000000
|
||||
|
||||
def __init__(self, sfp_index, slot_id=0, linecard_port_count=0, lc_name=None):
|
||||
super(SFP, self).__init__()
|
||||
def __init__(self, sfp_index, sfp_type=None, slot_id=0, linecard_port_count=0, lc_name=None):
|
||||
super(SFP, self).__init__(sfp_index)
|
||||
self._sfp_type = sfp_type
|
||||
|
||||
if slot_id == 0: # For non-modular chassis
|
||||
self.index = sfp_index + 1
|
||||
self.sdk_index = sfp_index
|
||||
|
||||
from .thermal import initialize_sfp_thermal
|
||||
self._thermal_list = initialize_sfp_thermal(sfp_index)
|
||||
else: # For modular chassis
|
||||
@ -281,6 +318,7 @@ class SFP(SfpOptoeBase):
|
||||
logger.log_error("Failed to find mst PCI device rc={} err.msg={}".format(e.returncode, e.output))
|
||||
return device_name
|
||||
|
||||
'''
|
||||
@property
|
||||
def sdk_handle(self):
|
||||
if not SFP.shared_sdk_handle:
|
||||
@ -288,6 +326,7 @@ class SFP(SfpOptoeBase):
|
||||
if not SFP.shared_sdk_handle:
|
||||
logger.log_error('Failed to open SDK handle')
|
||||
return SFP.shared_sdk_handle
|
||||
'''
|
||||
|
||||
def reinit(self):
|
||||
"""
|
||||
@ -512,7 +551,7 @@ class SFP(SfpOptoeBase):
|
||||
|
||||
|
||||
@classmethod
|
||||
def is_port_admin_status_up(cls, sdk_handle, log_port):
|
||||
def _fetch_port_status(cls, sdk_handle, log_port):
|
||||
oper_state_p = new_sx_port_oper_state_t_p()
|
||||
admin_state_p = new_sx_port_admin_state_t_p()
|
||||
module_state_p = new_sx_port_module_state_t_p()
|
||||
@ -520,12 +559,19 @@ class SFP(SfpOptoeBase):
|
||||
assert rc == SXD_STATUS_SUCCESS, "sx_api_port_state_get failed, rc = %d" % rc
|
||||
|
||||
admin_state = sx_port_admin_state_t_p_value(admin_state_p)
|
||||
oper_state = sx_port_oper_state_t_p_value(oper_state_p)
|
||||
|
||||
delete_sx_port_oper_state_t_p(oper_state_p)
|
||||
delete_sx_port_admin_state_t_p(admin_state_p)
|
||||
delete_sx_port_module_state_t_p(module_state_p)
|
||||
|
||||
return admin_state == SX_PORT_ADMIN_STATUS_UP
|
||||
return oper_state, admin_state
|
||||
|
||||
|
||||
@classmethod
|
||||
def is_port_admin_status_up(cls, sdk_handle, log_port):
|
||||
_, admin_state = cls._fetch_port_status(sdk_handle, log_port);
|
||||
admin_state == SX_PORT_ADMIN_STATUS_UP
|
||||
|
||||
|
||||
@classmethod
|
||||
@ -663,27 +709,6 @@ class SFP(SfpOptoeBase):
|
||||
"""
|
||||
return True
|
||||
|
||||
def _get_error_code(self):
|
||||
"""
|
||||
Get error code of the SFP module
|
||||
|
||||
Returns:
|
||||
The error code fetch from SDK API
|
||||
"""
|
||||
module_id_info_list = new_sx_mgmt_module_id_info_t_arr(1)
|
||||
module_info_list = new_sx_mgmt_phy_module_info_t_arr(1)
|
||||
|
||||
module_id_info = sx_mgmt_module_id_info_t()
|
||||
module_id_info.slot_id = 0
|
||||
module_id_info.module_id = self.sdk_index
|
||||
sx_mgmt_module_id_info_t_arr_setitem(module_id_info_list, 0, module_id_info)
|
||||
|
||||
rc = sx_mgmt_phy_module_info_get(self.sdk_handle, module_id_info_list, 1, module_info_list)
|
||||
assert SX_STATUS_SUCCESS == rc, "sx_mgmt_phy_module_info_get failed, error code {}".format(rc)
|
||||
|
||||
mod_info = sx_mgmt_phy_module_info_t_arr_getitem(module_info_list, 0)
|
||||
return mod_info.module_state.oper_state, mod_info.module_state.error_type
|
||||
|
||||
@classmethod
|
||||
def _get_error_description_dict(cls):
|
||||
return {0: cls.SFP_ERROR_DESCRIPTION_POWER_BUDGET_EXCEEDED,
|
||||
@ -704,12 +729,12 @@ class SFP(SfpOptoeBase):
|
||||
Get error description
|
||||
|
||||
Args:
|
||||
error_code: The error code returned by _get_error_code
|
||||
error_code: The error code returned by _get_module_info
|
||||
|
||||
Returns:
|
||||
The error description
|
||||
"""
|
||||
oper_status, error_code = self._get_error_code()
|
||||
oper_status, error_code = self._get_module_info(self.sdk_handle, self.sdk_index)
|
||||
if oper_status == SX_PORT_MODULE_STATUS_INITIALIZING:
|
||||
error_description = self.SFP_STATUS_INITIALIZING
|
||||
elif oper_status == SX_PORT_MODULE_STATUS_PLUGGED:
|
||||
@ -727,3 +752,271 @@ class SFP(SfpOptoeBase):
|
||||
else:
|
||||
error_description = "Unknow SFP module status ({})".format(oper_status)
|
||||
return error_description
|
||||
|
||||
|
||||
class RJ45Port(NvidiaSFPCommon):
|
||||
"""class derived from SFP, representing RJ45 ports"""
|
||||
|
||||
def __init__(self, sfp_index):
|
||||
super(RJ45Port, self).__init__(sfp_index)
|
||||
self.sfp_type = RJ45_TYPE
|
||||
|
||||
@classmethod
|
||||
def _get_presence(cls, sdk_handle, sdk_index):
|
||||
"""Class level method to get low power mode.
|
||||
|
||||
Args:
|
||||
sdk_handle: SDK handle
|
||||
sdk_index (integer): SDK port index
|
||||
slot_id (integer): Slot ID
|
||||
|
||||
Returns:
|
||||
[boolean]: True if low power mode is on else off
|
||||
"""
|
||||
oper_status, _ = cls._get_module_info(sdk_handle, sdk_index)
|
||||
return print(oper_status == SX_PORT_MODULE_STATUS_PLUGGED)
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the device
|
||||
For RJ45 ports, it always return True
|
||||
|
||||
Returns:
|
||||
bool: True if device is present, False if not
|
||||
"""
|
||||
if utils.is_host():
|
||||
# To avoid performance issue,
|
||||
# call class level method to avoid initialize the whole sonic platform API
|
||||
get_presence_code = 'from sonic_platform import sfp;\n' \
|
||||
'with sfp.SdkHandleContext() as sdk_handle:' \
|
||||
'print(sfp.RJ45Port._get_presence(sdk_handle, {}))'.format(self.sdk_index)
|
||||
presence_cmd = "docker exec pmon python3 -c \"{}\"".format(get_presence_code)
|
||||
try:
|
||||
output = subprocess.check_output(presence_cmd, shell=True, universal_newlines=True)
|
||||
return 'True' in output
|
||||
except subprocess.CalledProcessError as e:
|
||||
print("Error! Unable to get presence for {}, rc = {}, err msg: {}".format(self.sdk_index, e.returncode, e.output))
|
||||
return False
|
||||
else:
|
||||
oper_status, _ = self._get_module_info(self.sdk_handle, self.sdk_index);
|
||||
return (oper_status == SX_PORT_MODULE_STATUS_PLUGGED)
|
||||
|
||||
def get_transceiver_info(self):
|
||||
"""
|
||||
Retrieves transceiver info of this port.
|
||||
For RJ45, all fields are N/A
|
||||
|
||||
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
|
||||
mominal_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
|
||||
================================================================================
|
||||
"""
|
||||
transceiver_info_keys = ['manufacturer',
|
||||
'model',
|
||||
'vendor_rev',
|
||||
'serial',
|
||||
'vendor_oui',
|
||||
'vendor_date',
|
||||
'connector',
|
||||
'encoding',
|
||||
'ext_identifier',
|
||||
'ext_rateselect_compliance',
|
||||
'cable_type',
|
||||
'cable_length',
|
||||
'specification_compliance',
|
||||
'nominal_bit_rate',
|
||||
'application_advertisement']
|
||||
transceiver_info_dict = dict.fromkeys(transceiver_info_keys, 'N/A')
|
||||
transceiver_info_dict['type'] = self.sfp_type
|
||||
|
||||
return transceiver_info_dict
|
||||
|
||||
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
|
||||
"""
|
||||
return False
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset SFP and return all user module settings to their default state.
|
||||
|
||||
Returns:
|
||||
A boolean, True if successful, False if not
|
||||
|
||||
refer plugins/sfpreset.py
|
||||
"""
|
||||
return False
|
||||
|
||||
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
|
||||
"""
|
||||
return False
|
||||
|
||||
def get_error_description(self):
|
||||
"""
|
||||
Get error description
|
||||
|
||||
Args:
|
||||
error_code: Always false on SN2201
|
||||
|
||||
Returns:
|
||||
The error description
|
||||
"""
|
||||
return False
|
||||
|
||||
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 lost-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 channles 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 bias |INT |TX Bias Current in mA
|
||||
RX power |INT |received optical power in mW
|
||||
TX power |INT |TX output power in mW
|
||||
========================================================================
|
||||
"""
|
||||
transceiver_dom_info_dict = {}
|
||||
|
||||
dom_info_dict_keys = ['temperature', 'voltage',
|
||||
'rx1power', 'rx2power',
|
||||
'rx3power', 'rx4power',
|
||||
'rx5power', 'rx6power',
|
||||
'rx7power', 'rx8power',
|
||||
'tx1bias', 'tx2bias',
|
||||
'tx3bias', 'tx4bias',
|
||||
'tx5bias', 'tx6bias',
|
||||
'tx7bias', 'tx8bias',
|
||||
'tx1power', 'tx2power',
|
||||
'tx3power', 'tx4power',
|
||||
'tx5power', 'tx6power',
|
||||
'tx7power', 'tx8power'
|
||||
]
|
||||
transceiver_dom_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A')
|
||||
|
||||
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.
|
||||
========================================================================
|
||||
"""
|
||||
transceiver_dom_threshold_info_dict = {}
|
||||
|
||||
dom_info_dict_keys = ['temphighalarm', 'temphighwarning',
|
||||
'templowalarm', 'templowwarning',
|
||||
'vcchighalarm', 'vcchighwarning',
|
||||
'vcclowalarm', 'vcclowwarning',
|
||||
'rxpowerhighalarm', 'rxpowerhighwarning',
|
||||
'rxpowerlowalarm', 'rxpowerlowwarning',
|
||||
'txpowerhighalarm', 'txpowerhighwarning',
|
||||
'txpowerlowalarm', 'txpowerlowwarning',
|
||||
'txbiashighalarm', 'txbiashighwarning',
|
||||
'txbiaslowalarm', 'txbiaslowwarning'
|
||||
]
|
||||
transceiver_dom_threshold_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A')
|
||||
|
||||
return transceiver_dom_threshold_info_dict
|
||||
|
||||
def get_reset_status(self):
|
||||
"""
|
||||
Retrieves the reset status of SFP
|
||||
|
||||
Returns:
|
||||
A Boolean, True if reset enabled, False if disabled
|
||||
|
||||
for QSFP, originally I would like to make use of Initialization complete flag bit
|
||||
which is at Page a0 offset 6 bit 0 to test whether reset is complete.
|
||||
However as unit testing was carried out I find this approach may fail because:
|
||||
1. we make use of ethtool to read data on I2C bus rather than to read directly
|
||||
2. ethtool is unable to access I2C during QSFP module being reset
|
||||
In other words, whenever the flag is able to be retrived, the value is always be 1
|
||||
As a result, it doesn't make sense to retrieve that flag. Just treat successfully
|
||||
retrieving data as "data ready".
|
||||
for SFP it seems that there is not flag indicating whether reset succeed. However,
|
||||
we can also do it in the way for QSFP.
|
||||
"""
|
||||
return False
|
||||
|
||||
def read_eeprom(self, offset, num_bytes):
|
||||
return None
|
||||
|
||||
def reinit(self):
|
||||
"""
|
||||
Nothing to do for RJ45. Just provide it to avoid exception
|
||||
:return:
|
||||
"""
|
||||
return
|
||||
|
@ -50,6 +50,7 @@ SDK_SFP_STATE_IN = 0x1
|
||||
SDK_SFP_STATE_OUT = 0x2
|
||||
SDK_SFP_STATE_ERR = 0x3
|
||||
SDK_SFP_STATE_DIS = 0x4
|
||||
SDK_SFP_STATE_UNKNOWN = 0x5
|
||||
|
||||
# SFP status used in this file only, will not expose to XCVRD
|
||||
# STATUS_ERROR will be mapped to different status according to the error code
|
||||
@ -134,13 +135,17 @@ class sfp_event:
|
||||
SX_OPEN_TIMEOUT = 5
|
||||
SELECT_TIMEOUT = 1
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, rj45_port_list=None):
|
||||
self.swid = 0
|
||||
self.handle = None
|
||||
|
||||
# Allocate SDK fd and user channel structures
|
||||
self.rx_fd_p = new_sx_fd_t_p()
|
||||
self.user_channel_p = new_sx_user_channel_t_p()
|
||||
if rj45_port_list:
|
||||
self.RJ45_port_set = set(rj45_port_list)
|
||||
else:
|
||||
self.RJ45_port_set = set()
|
||||
|
||||
def initialize(self):
|
||||
swid_cnt_p = None
|
||||
@ -340,6 +345,7 @@ class sfp_event:
|
||||
status = False
|
||||
else:
|
||||
status = True
|
||||
unknown = False
|
||||
pmpe_t = recv_info_p.event_info.pmpe
|
||||
port_list_size = pmpe_t.list_size
|
||||
logical_port_list = pmpe_t.log_port_list
|
||||
@ -354,8 +360,11 @@ class sfp_event:
|
||||
logger.log_info("Receive PMPE disable event on module {}: status {}".format(module_id, module_state))
|
||||
elif module_state == SDK_SFP_STATE_IN or module_state == SDK_SFP_STATE_OUT:
|
||||
logger.log_info("Receive PMPE plug in/out event on module {}: status {}".format(module_id, module_state))
|
||||
elif module_state == SDK_SFP_STATE_UNKNOWN:
|
||||
unknown = True
|
||||
else:
|
||||
logger.log_error("Receive PMPE unknown event on module {}: status {}".format(module_id, module_state))
|
||||
|
||||
for i in range(port_list_size):
|
||||
logical_port = sx_port_log_id_t_arr_getitem(logical_port_list, i)
|
||||
rc = sx_api_port_device_get(self.handle, 1 , 0, port_attributes_list, port_cnt_p)
|
||||
@ -369,6 +378,14 @@ class sfp_event:
|
||||
if label_port is not None:
|
||||
label_port_list.append(label_port)
|
||||
|
||||
if unknown:
|
||||
SFP_ports_with_unknown_event = set(label_port_list) - self.RJ45_port_set
|
||||
if SFP_ports_with_unknown_event:
|
||||
logger.log_error("Receive PMPE unknown event on module {}: status {}".format(module_id, module_state))
|
||||
else:
|
||||
# For RJ45 ports, we treat unknown as disconnect
|
||||
module_state = SDK_SFP_STATE_DIS
|
||||
|
||||
delete_uint32_t_p(pkt_size_p)
|
||||
delete_uint8_t_arr(pkt)
|
||||
delete_sx_receive_info_t_p(recv_info_p)
|
||||
|
@ -16,8 +16,18 @@
|
||||
#
|
||||
import functools
|
||||
import subprocess
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
from sonic_py_common import device_info
|
||||
from sonic_py_common.logger import Logger
|
||||
|
||||
HWSKU_JSON = 'hwsku.json'
|
||||
|
||||
PORT_INDEX_KEY = "index"
|
||||
PORT_TYPE_KEY = "port_type"
|
||||
RJ45_PORT_TYPE = "RJ45"
|
||||
|
||||
logger = Logger()
|
||||
|
||||
|
||||
@ -207,3 +217,50 @@ def run_command(command):
|
||||
return process.communicate()[0].strip()
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def load_json_file(filename, log_func=logger.log_error):
|
||||
# load 'platform.json' or 'hwsku.json' file
|
||||
data = None
|
||||
try:
|
||||
with open(filename) as fp:
|
||||
try:
|
||||
data = json.load(fp)
|
||||
except json.JSONDecodeError:
|
||||
if log_func:
|
||||
log_func("failed to decode Json file.")
|
||||
return data
|
||||
except Exception as e:
|
||||
if log_func:
|
||||
log_func("error occurred while parsing json file: {}".format(sys.exc_info()[1]))
|
||||
return None
|
||||
|
||||
|
||||
def extract_RJ45_ports_index():
|
||||
# Cross check 'platform.json' and 'hwsku.json' to extract the RJ45 port index if exists.
|
||||
hwsku_path = device_info.get_path_to_hwsku_dir()
|
||||
platform_file = device_info.get_path_to_port_config_file()
|
||||
platform_dict = load_json_file(platform_file)['interfaces']
|
||||
hwsku_file = os.path.join(hwsku_path, HWSKU_JSON)
|
||||
hwsku_dict = load_json_file(hwsku_file)['interfaces']
|
||||
port_name_to_index_map_dict = {}
|
||||
RJ45_port_index_list = []
|
||||
|
||||
# Compose a interface name to index mapping from 'platform.json'
|
||||
for i, (key, value) in enumerate(platform_dict.items()):
|
||||
if PORT_INDEX_KEY in value:
|
||||
index_raw = value[PORT_INDEX_KEY]
|
||||
# The index could be "1" or "1, 1, 1, 1"
|
||||
index = index_raw.split(',')[0]
|
||||
port_name_to_index_map_dict[key] = index
|
||||
|
||||
if not bool(port_name_to_index_map_dict):
|
||||
return None
|
||||
|
||||
# Check if "port_type" specified as "RJ45", if yes, add the port index to the list.
|
||||
for i, (key, value) in enumerate(hwsku_dict.items()):
|
||||
if key in port_name_to_index_map_dict and PORT_TYPE_KEY in value and value[PORT_TYPE_KEY] == RJ45_PORT_TYPE:
|
||||
RJ45_port_index_list.append(int(port_name_to_index_map_dict[key])-1)
|
||||
|
||||
return RJ45_port_index_list if bool(RJ45_port_index_list) else None
|
||||
|
||||
|
@ -32,6 +32,7 @@ import sonic_platform.chassis
|
||||
from sonic_platform.chassis import Chassis
|
||||
from sonic_platform.device_data import DeviceDataManager
|
||||
|
||||
sonic_platform.chassis.extract_RJ45_ports_index = mock.MagicMock(return_value=[])
|
||||
|
||||
class TestChassis:
|
||||
"""Test class to test chassis.py. The test cases covers:
|
||||
|
@ -30,11 +30,11 @@ sys.path.insert(0, modules_path)
|
||||
from sonic_platform.chassis import Chassis
|
||||
from sonic_platform.eeprom import Eeprom, EepromContentVisitor
|
||||
|
||||
|
||||
class TestEeprom:
|
||||
@patch('os.path.exists', MagicMock(return_value=True))
|
||||
@patch('os.path.islink', MagicMock(return_value=True))
|
||||
@patch('sonic_platform.eeprom.Eeprom.get_system_eeprom_info')
|
||||
@patch('sonic_platform.chassis.extract_RJ45_ports_index', MagicMock(return_value=[]))
|
||||
def test_chassis_eeprom(self, mock_eeprom_info):
|
||||
mock_eeprom_info.return_value = {
|
||||
hex(Eeprom._TLV_CODE_PRODUCT_NAME): 'MSN3420',
|
||||
@ -102,7 +102,3 @@ class TestEeprom:
|
||||
v.visit_tlv('tlv3', Eeprom._TLV_CODE_VENDOR_EXT, 4, 'ext2')
|
||||
assert content[hex(Eeprom._TLV_CODE_PRODUCT_NAME)] == 'MSN3420'
|
||||
assert content[hex(Eeprom._TLV_CODE_VENDOR_EXT)] == ['ext1', 'ext2']
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -35,6 +35,7 @@ from sonic_platform.psu import FixedPsu, Psu
|
||||
|
||||
class TestLed:
|
||||
@mock.patch('sonic_platform.led.Led._wait_files_ready', mock.MagicMock(return_value=True))
|
||||
@mock.patch('sonic_platform.chassis.extract_RJ45_ports_index', mock.MagicMock(return_value=True))
|
||||
def test_chassis_led(self):
|
||||
chassis = Chassis()
|
||||
assert chassis._led is None
|
||||
|
@ -26,6 +26,7 @@ test_path = os.path.dirname(os.path.abspath(__file__))
|
||||
modules_path = os.path.dirname(test_path)
|
||||
sys.path.insert(0, modules_path)
|
||||
|
||||
import sonic_platform.chassis
|
||||
from sonic_platform import utils
|
||||
from sonic_platform.chassis import ModularChassis
|
||||
from sonic_platform.device_data import DeviceDataManager
|
||||
@ -37,6 +38,7 @@ class TestModule:
|
||||
def setup_class(cls):
|
||||
DeviceDataManager.get_linecard_sfp_count = mock.MagicMock(return_value=2)
|
||||
DeviceDataManager.get_linecard_count = mock.MagicMock(return_value=2)
|
||||
sonic_platform.chassis.extract_RJ45_ports_index = mock.MagicMock(return_value=[])
|
||||
|
||||
def test_chassis_get_num_sfp(self):
|
||||
chassis = ModularChassis()
|
||||
|
@ -53,8 +53,10 @@ class TestSfp:
|
||||
assert sfp.index == 5
|
||||
|
||||
@mock.patch('sonic_platform.sfp.SFP.read_eeprom', mock.MagicMock(return_value=None))
|
||||
@mock.patch('sonic_platform.sfp.SFP._get_error_code')
|
||||
@mock.patch('sonic_platform.sfp.SFP.shared_sdk_handle', mock.MagicMock(return_value=2))
|
||||
@mock.patch('sonic_platform.sfp.SFP._get_module_info')
|
||||
@mock.patch('sonic_platform.chassis.Chassis.get_num_sfps', mock.MagicMock(return_value=2))
|
||||
@mock.patch('sonic_platform.chassis.extract_RJ45_ports_index', mock.MagicMock(return_value=[]))
|
||||
def test_sfp_get_error_status(self, mock_get_error_code):
|
||||
chassis = Chassis()
|
||||
|
||||
|
@ -28,9 +28,11 @@ test_path = os.path.dirname(os.path.abspath(__file__))
|
||||
modules_path = os.path.dirname(test_path)
|
||||
sys.path.insert(0, modules_path)
|
||||
|
||||
import sonic_platform.chassis
|
||||
from sonic_platform.chassis import Chassis
|
||||
from sonic_platform.device_data import DeviceDataManager
|
||||
|
||||
sonic_platform.chassis.extract_RJ45_ports_index = mock.MagicMock(return_value=[])
|
||||
|
||||
class TestThermal:
|
||||
@mock.patch('os.path.exists', mock.MagicMock(return_value=True))
|
||||
|
@ -21,9 +21,8 @@
|
||||
#= Global variable #
|
||||
#=
|
||||
#=====
|
||||
VERSION="1.5"
|
||||
VERSION="1.6"
|
||||
#=====
|
||||
SWITCH_SSD_DEV="/dev/sda"
|
||||
UTIL_TITLE="This is MLNX SSD firmware update utility to read and write SSD FW. Version ${VERSION}"
|
||||
DEPENDECIES=("smartctl" "sha256sum" "tar" "/bin/bash" "gpg" "sed" "realpath" "dirname")
|
||||
TRUE="0"
|
||||
@ -37,6 +36,7 @@ DEBUG_MSG="DEBUG" # remove all instance after script is ready.
|
||||
#=====
|
||||
PKG_EXTRACTED=$FALSE
|
||||
LOGGER_UTIL=$FALSE
|
||||
SSD_DEV_NAME=""
|
||||
SSD_FW_VER=""
|
||||
SSD_DEVICE_MODEL=""
|
||||
SSD_SERIAL=""
|
||||
@ -230,7 +230,7 @@ function get_ssd_fw_version() {
|
||||
[ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; }
|
||||
|
||||
local device_fw_version
|
||||
device_fw_version=$(smartctl -i $SWITCH_SSD_DEV | grep -Po "Firmware Version: +\K[^,]+")
|
||||
device_fw_version=$(smartctl -i $SSD_DEV_NAME | grep -Po "Firmware Version: +\K[^,]+")
|
||||
LOG_MSG "device_fw_version: $device_fw_version" ${DEBUG_MSG}
|
||||
eval $1='$device_fw_version'
|
||||
}
|
||||
@ -242,7 +242,7 @@ function get_ssd_device_model() {
|
||||
[ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; }
|
||||
|
||||
local device_model_name
|
||||
device_model_name=$(smartctl -i $SWITCH_SSD_DEV | grep -Po "Device Model: +\K[^,]+")
|
||||
device_model_name=$(smartctl -i $SSD_DEV_NAME | grep -E "Device Model:|Model Number:" | awk '{$1=$2="";print $0}'| sed 's/^ *//g')
|
||||
LOG_MSG "device_model_name: $device_model_name" ${DEBUG_MSG}
|
||||
eval $1='$device_model_name'
|
||||
}
|
||||
@ -254,7 +254,7 @@ function get_ssd_size() {
|
||||
[ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; }
|
||||
|
||||
local device_size
|
||||
device_size=$(smartctl -i $SWITCH_SSD_DEV | grep -Po "User Capacity:.+bytes \[\K[^ ]+")
|
||||
device_size=$(smartctl -i $SSD_DEV_NAME | grep -E "User Capacity:|Size/Capacity" | awk -F '\[|\]' '{print $2}' | awk '{print $1}')
|
||||
LOG_MSG "device_size: $device_size" ${DEBUG_MSG}
|
||||
eval $1='$device_size'
|
||||
}
|
||||
@ -266,16 +266,56 @@ function get_ssd_serial() {
|
||||
[ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; }
|
||||
|
||||
local device_serial
|
||||
device_serial=$(smartctl -i $SWITCH_SSD_DEV | grep -Po "Serial Number: +\K[^,]+")
|
||||
device_serial=$(smartctl -i $SSD_DEV_NAME | grep -Po "Serial Number: +\K[^,]+")
|
||||
LOG_MSG "device_serial: $device_serial" ${DEBUG_MSG}
|
||||
eval $1='$device_serial'
|
||||
}
|
||||
|
||||
#==============================================================================#
|
||||
#= This function check if given argument is valid and return boolean result. #
|
||||
# This function check SSD device name #
|
||||
#
|
||||
function get_ssd_device_name() {
|
||||
[ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; }
|
||||
|
||||
non_rem_mount_disks=""
|
||||
non_rem_mount_disks_count=0
|
||||
mount_parts=$(cat /proc/partitions | grep -v "^major" | grep -v ram | awk '{{print $4}}')
|
||||
for blk_dev_name in ${mount_parts}
|
||||
do
|
||||
blk_dev_link=$(find /sys/bus /sys/class /sys/block/ -name ${blk_dev_name})
|
||||
for first_blk_dev_link in ${blk_dev_link}
|
||||
do
|
||||
if ls -l ${first_blk_dev_link} | grep -q virtual; then
|
||||
continue
|
||||
fi
|
||||
if [ -e ${first_blk_dev_link}/removable ] ; then
|
||||
if [ "0" = $(cat ${first_blk_dev_link}/removable) ] ; then
|
||||
let non_rem_mount_disks_count=${non_rem_mount_disks_count}+1
|
||||
if [ "1" == "${non_rem_mount_disks_count}" ] ; then
|
||||
non_rem_mount_disks="${blk_dev_name}"
|
||||
else
|
||||
non_rem_mount_disks="${non_rem_mount_disks} ${blk_dev_name}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
break
|
||||
done
|
||||
done
|
||||
if [ "1" == "${non_rem_mount_disks_count}" ] ; then
|
||||
device_name="/dev/${non_rem_mount_disks}"
|
||||
else
|
||||
$1="/dev/sda"
|
||||
fi
|
||||
LOG_MSG "device_name: $device_name" ${DEBUG_MSG}
|
||||
eval $1='$device_name'
|
||||
}
|
||||
|
||||
#==============================================================================#
|
||||
#= This function check if given argument. #
|
||||
#=
|
||||
function get_ssd_info() {
|
||||
LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG}
|
||||
get_ssd_device_name SSD_DEV_NAME
|
||||
get_ssd_fw_version SSD_FW_VER
|
||||
get_ssd_device_model SSD_DEVICE_MODEL
|
||||
get_ssd_serial SSD_SERIAL
|
||||
|
Loading…
Reference in New Issue
Block a user