DellEMC: S6100, S6000 - Platform API implementation (#9586)
Why I did it To incorporate the below changes in DellEMC S6100, S6000 platforms. S6100, S6000: Implement 'get_revision' method for Chassis Implement 'get_maximum_consumed_power' method for FanDrawer Implement 'get_revision', 'get_maximum_supplied_power' methods for PSU Implement 'get_error_description' method for SFP. S6100: Implement 'get_module_index' method for Chassis Implement 'get_description', 'get_maximum_consumed_power', 'get_oper_status', 'get_slot' methods for Module Update component names in platform.json How I did it Implement the platform API methods in the respective device files How to verify it Verified that the respective sonic-mgmt platform API test cases report success.
This commit is contained in:
parent
a888a2d98d
commit
174833d319
@ -10,11 +10,14 @@
|
|||||||
{
|
{
|
||||||
"name": "BIOS"
|
"name": "BIOS"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "FPGA"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "CPLD"
|
"name": "CPLD"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "FPGA"
|
"name": "SSD"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"fans": [
|
"fans": [
|
||||||
|
@ -231,6 +231,15 @@ class Chassis(ChassisBase):
|
|||||||
"""
|
"""
|
||||||
return self._eeprom.get_base_mac()
|
return self._eeprom.get_base_mac()
|
||||||
|
|
||||||
|
def get_revision(self):
|
||||||
|
"""
|
||||||
|
Retrieves the hardware revision of the device
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
string: Revision value of device
|
||||||
|
"""
|
||||||
|
return self._eeprom.get_revision()
|
||||||
|
|
||||||
def get_system_eeprom_info(self):
|
def get_system_eeprom_info(self):
|
||||||
"""
|
"""
|
||||||
Retrieves the full content of system EEPROM information for the
|
Retrieves the full content of system EEPROM information for the
|
||||||
|
@ -105,6 +105,7 @@ class Eeprom(TlvInfoDecoder):
|
|||||||
self.part_number = 'NA'
|
self.part_number = 'NA'
|
||||||
self.model_str = 'NA'
|
self.model_str = 'NA'
|
||||||
self.serial = 'NA'
|
self.serial = 'NA'
|
||||||
|
self.revision = 'NA'
|
||||||
return
|
return
|
||||||
|
|
||||||
total_length = (eeprom[9] << 8) | (eeprom[10])
|
total_length = (eeprom[9] << 8) | (eeprom[10])
|
||||||
@ -142,6 +143,8 @@ class Eeprom(TlvInfoDecoder):
|
|||||||
"0x%X" % (self._TLV_CODE_PRODUCT_NAME), 'NA')
|
"0x%X" % (self._TLV_CODE_PRODUCT_NAME), 'NA')
|
||||||
self.serial = self.eeprom_tlv_dict.get(
|
self.serial = self.eeprom_tlv_dict.get(
|
||||||
"0x%X" % (self._TLV_CODE_SERVICE_TAG), 'NA')
|
"0x%X" % (self._TLV_CODE_SERVICE_TAG), 'NA')
|
||||||
|
self.revision = self.eeprom_tlv_dict.get(
|
||||||
|
"0x%X" % (self._TLV_CODE_LABEL_REVISION), 'NA')
|
||||||
|
|
||||||
def _load_device_eeprom(self):
|
def _load_device_eeprom(self):
|
||||||
"""
|
"""
|
||||||
@ -154,6 +157,7 @@ class Eeprom(TlvInfoDecoder):
|
|||||||
except:
|
except:
|
||||||
self.serial_number = 'NA'
|
self.serial_number = 'NA'
|
||||||
self.part_number = 'NA'
|
self.part_number = 'NA'
|
||||||
|
self.revision = 'NA'
|
||||||
if self.is_psu_eeprom:
|
if self.is_psu_eeprom:
|
||||||
self.psu_type = 'NA'
|
self.psu_type = 'NA'
|
||||||
else:
|
else:
|
||||||
@ -167,9 +171,13 @@ class Eeprom(TlvInfoDecoder):
|
|||||||
+ "-" + ppid[16:])
|
+ "-" + ppid[16:])
|
||||||
(valid, data) = self._get_eeprom_field("DPN Rev")
|
(valid, data) = self._get_eeprom_field("DPN Rev")
|
||||||
if valid:
|
if valid:
|
||||||
|
self.revision = data
|
||||||
self.serial_number += "-" + data
|
self.serial_number += "-" + data
|
||||||
|
else:
|
||||||
|
self.revision = 'NA'
|
||||||
else:
|
else:
|
||||||
self.serial_number = 'NA'
|
self.serial_number = 'NA'
|
||||||
|
self.revision = 'NA'
|
||||||
|
|
||||||
(valid, data) = self._get_eeprom_field("Part Number")
|
(valid, data) = self._get_eeprom_field("Part Number")
|
||||||
if valid:
|
if valid:
|
||||||
@ -219,6 +227,12 @@ class Eeprom(TlvInfoDecoder):
|
|||||||
"""
|
"""
|
||||||
return self.part_number
|
return self.part_number
|
||||||
|
|
||||||
|
def get_revision(self):
|
||||||
|
"""
|
||||||
|
Returns the hardware revision.
|
||||||
|
"""
|
||||||
|
return self.revision
|
||||||
|
|
||||||
def airflow_fan_type(self):
|
def airflow_fan_type(self):
|
||||||
"""
|
"""
|
||||||
Returns the airflow fan type.
|
Returns the airflow fan type.
|
||||||
@ -449,7 +463,7 @@ class EepromS6000(EepromDecoder):
|
|||||||
(valid, data) = self._get_eeprom_field(self.eeprom_data,
|
(valid, data) = self._get_eeprom_field(self.eeprom_data,
|
||||||
self._BLK_CODE_MFG, "Part Number")
|
self._BLK_CODE_MFG, "Part Number")
|
||||||
if valid:
|
if valid:
|
||||||
return data
|
return data.rstrip('\x00')
|
||||||
else:
|
else:
|
||||||
return 'NA'
|
return 'NA'
|
||||||
|
|
||||||
@ -475,6 +489,17 @@ class EepromS6000(EepromDecoder):
|
|||||||
else:
|
else:
|
||||||
return 'NA'
|
return 'NA'
|
||||||
|
|
||||||
|
def get_revision(self):
|
||||||
|
"""
|
||||||
|
Returns the hardware revision.
|
||||||
|
"""
|
||||||
|
(valid, data) = self._get_eeprom_field(self.eeprom_data,
|
||||||
|
self._BLK_CODE_MFG, "DPN Rev")
|
||||||
|
if valid:
|
||||||
|
return data
|
||||||
|
else:
|
||||||
|
return 'NA'
|
||||||
|
|
||||||
# EEPROM Plugin specific methods
|
# EEPROM Plugin specific methods
|
||||||
def is_checksum_valid(self, e):
|
def is_checksum_valid(self, e):
|
||||||
# Checksum is already calculated before
|
# Checksum is already calculated before
|
||||||
|
@ -182,3 +182,13 @@ class FanDrawer(FanDrawerBase):
|
|||||||
return fantray_led
|
return fantray_led
|
||||||
else:
|
else:
|
||||||
return self.STATUS_LED_COLOR_OFF
|
return self.STATUS_LED_COLOR_OFF
|
||||||
|
|
||||||
|
def get_maximum_consumed_power(self):
|
||||||
|
"""
|
||||||
|
Retrives the maximum power drawn by Fan Drawer
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A float, with value of the maximum consumable power of the
|
||||||
|
component.
|
||||||
|
"""
|
||||||
|
return 18.0
|
||||||
|
@ -161,6 +161,15 @@ class Psu(PsuBase):
|
|||||||
# Sample Serial number format "US-01234D-54321-25A-0123-A00"
|
# Sample Serial number format "US-01234D-54321-25A-0123-A00"
|
||||||
return self.eeprom.get_serial_number()
|
return self.eeprom.get_serial_number()
|
||||||
|
|
||||||
|
def get_revision(self):
|
||||||
|
"""
|
||||||
|
Retrieves the hardware revision of the device
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
string: Revision value of device
|
||||||
|
"""
|
||||||
|
return self.eeprom.get_revision()
|
||||||
|
|
||||||
def get_status(self):
|
def get_status(self):
|
||||||
"""
|
"""
|
||||||
Retrieves the operational status of the PSU
|
Retrieves the operational status of the PSU
|
||||||
@ -248,6 +257,21 @@ class Psu(PsuBase):
|
|||||||
|
|
||||||
return psu_power
|
return psu_power
|
||||||
|
|
||||||
|
def get_maximum_supplied_power(self):
|
||||||
|
"""
|
||||||
|
Retrieves the maximum supplied power by PSU
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A float number, the maximum power output in Watts.
|
||||||
|
e.g. 1200.1
|
||||||
|
"""
|
||||||
|
if self.get_presence():
|
||||||
|
psu_maxpower = 460.0
|
||||||
|
else:
|
||||||
|
psu_maxpower = 0.0
|
||||||
|
|
||||||
|
return psu_maxpower
|
||||||
|
|
||||||
def get_powergood_status(self):
|
def get_powergood_status(self):
|
||||||
"""
|
"""
|
||||||
Retrieves the powergood status of PSU
|
Retrieves the powergood status of PSU
|
||||||
|
@ -9,14 +9,17 @@
|
|||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
import fcntl
|
||||||
|
import os
|
||||||
import time
|
import time
|
||||||
from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase
|
from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase
|
||||||
import fcntl
|
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
raise ImportError(str(e) + "- required module not found")
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
|
QSFP_INFO_OFFSET = 128
|
||||||
SFP_LOCK_FILE="/etc/sonic/sfp_lock"
|
SFP_LOCK_FILE="/etc/sonic/sfp_lock"
|
||||||
|
|
||||||
|
|
||||||
class Sfp(SfpOptoeBase):
|
class Sfp(SfpOptoeBase):
|
||||||
"""
|
"""
|
||||||
DELLEMC Platform-specific Sfp class
|
DELLEMC Platform-specific Sfp class
|
||||||
@ -331,3 +334,27 @@ class Sfp(SfpOptoeBase):
|
|||||||
bool: True if it is replaceable.
|
bool: True if it is replaceable.
|
||||||
"""
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def get_error_description(self):
|
||||||
|
"""
|
||||||
|
Retrives the error descriptions of the SFP module
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
String that represents the current error descriptions of vendor specific errors
|
||||||
|
In case there are multiple errors, they should be joined by '|',
|
||||||
|
like: "Bad EEPROM|Unsupported cable"
|
||||||
|
"""
|
||||||
|
if not self.get_presence():
|
||||||
|
return self.SFP_STATUS_UNPLUGGED
|
||||||
|
else:
|
||||||
|
if not os.path.isfile(self.eeprom_path):
|
||||||
|
return "EEPROM driver is not attached"
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(self.eeprom_path, mode="rb", buffering=0) as eeprom:
|
||||||
|
eeprom.seek(QSFP_INFO_OFFSET)
|
||||||
|
eeprom.read(1)
|
||||||
|
except OSError as e:
|
||||||
|
return "EEPROM read failed ({})".format(e.strerror)
|
||||||
|
|
||||||
|
return self.SFP_STATUS_OK
|
||||||
|
@ -10,16 +10,16 @@
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
import time
|
||||||
from sonic_platform_base.chassis_base import ChassisBase
|
from sonic_platform_base.chassis_base import ChassisBase
|
||||||
from sonic_platform.sfp import Sfp
|
from sonic_platform.component import Component
|
||||||
from sonic_platform.psu import Psu
|
from sonic_platform.eeprom import Eeprom
|
||||||
from sonic_platform.fan_drawer import FanDrawer
|
from sonic_platform.fan_drawer import FanDrawer
|
||||||
from sonic_platform.module import Module
|
from sonic_platform.module import Module
|
||||||
|
from sonic_platform.psu import Psu
|
||||||
from sonic_platform.thermal import Thermal
|
from sonic_platform.thermal import Thermal
|
||||||
from sonic_platform.component import Component
|
|
||||||
from sonic_platform.watchdog import Watchdog, WatchdogTCO
|
from sonic_platform.watchdog import Watchdog, WatchdogTCO
|
||||||
from sonic_platform.eeprom import Eeprom
|
|
||||||
import time
|
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
raise ImportError(str(e) + "- required module not found")
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
@ -235,6 +235,15 @@ class Chassis(ChassisBase):
|
|||||||
"""
|
"""
|
||||||
return self._eeprom.base_mac_addr()
|
return self._eeprom.base_mac_addr()
|
||||||
|
|
||||||
|
def get_revision(self):
|
||||||
|
"""
|
||||||
|
Retrieves the hardware revision of the device
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
string: Revision value of device
|
||||||
|
"""
|
||||||
|
return self._eeprom.revision_str()
|
||||||
|
|
||||||
def get_system_eeprom_info(self):
|
def get_system_eeprom_info(self):
|
||||||
"""
|
"""
|
||||||
Retrieves the full content of system EEPROM information for the chassis
|
Retrieves the full content of system EEPROM information for the chassis
|
||||||
@ -245,6 +254,19 @@ class Chassis(ChassisBase):
|
|||||||
"""
|
"""
|
||||||
return self._eeprom.system_eeprom_info()
|
return self._eeprom.system_eeprom_info()
|
||||||
|
|
||||||
|
def get_module_index(self, module_name):
|
||||||
|
"""
|
||||||
|
Retrieves module index from the module name
|
||||||
|
|
||||||
|
Args:
|
||||||
|
module_name: A string, prefixed by SUPERVISOR, LINE-CARD or FABRIC-CARD
|
||||||
|
Ex. SUPERVISOR0, LINE-CARD1, FABRIC-CARD5
|
||||||
|
Returns:
|
||||||
|
An integer, the index of the ModuleBase object in the module_list
|
||||||
|
"""
|
||||||
|
module_index = re.match(r'IOM([1-4])', module_name).group(1)
|
||||||
|
return int(module_index) - 1
|
||||||
|
|
||||||
def get_reboot_cause(self):
|
def get_reboot_cause(self):
|
||||||
"""
|
"""
|
||||||
Retrieves the cause of the previous reboot
|
Retrieves the cause of the previous reboot
|
||||||
|
@ -123,7 +123,7 @@ class Eeprom(eeprom_tlvinfo.TlvInfoDecoder):
|
|||||||
|
|
||||||
def revision_str(self):
|
def revision_str(self):
|
||||||
(is_valid, results) = self.get_tlv_field(
|
(is_valid, results) = self.get_tlv_field(
|
||||||
self.eeprom_data, self._TLV_CODE_DEVICE_VERSION)
|
self.eeprom_data, self._TLV_CODE_LABEL_REVISION)
|
||||||
if not is_valid:
|
if not is_valid:
|
||||||
return "N/A"
|
return "N/A"
|
||||||
|
|
||||||
|
@ -159,3 +159,13 @@ class FanDrawer(FanDrawerBase):
|
|||||||
return self.STATUS_LED_COLOR_AMBER
|
return self.STATUS_LED_COLOR_AMBER
|
||||||
else:
|
else:
|
||||||
return self.STATUS_LED_COLOR_OFF
|
return self.STATUS_LED_COLOR_OFF
|
||||||
|
|
||||||
|
def get_maximum_consumed_power(self):
|
||||||
|
"""
|
||||||
|
Retrives the maximum power drawn by Fan Drawer
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A float, with value of the maximum consumable power of the
|
||||||
|
component.
|
||||||
|
"""
|
||||||
|
return 54.0
|
||||||
|
@ -198,3 +198,48 @@ class Module(ModuleBase):
|
|||||||
‘0x26’:’01’, ‘0x27’:’REV01’, ‘0x28’:’AG9064-C2358-16G’}
|
‘0x26’:’01’, ‘0x27’:’REV01’, ‘0x28’:’AG9064-C2358-16G’}
|
||||||
"""
|
"""
|
||||||
return self._eeprom.system_eeprom_info()
|
return self._eeprom.system_eeprom_info()
|
||||||
|
|
||||||
|
def get_description(self):
|
||||||
|
"""
|
||||||
|
Retrieves the platform vendor's product description of the module
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A string, providing the vendor's product description of the module.
|
||||||
|
"""
|
||||||
|
return self._eeprom.modelstr()
|
||||||
|
|
||||||
|
def get_slot(self):
|
||||||
|
"""
|
||||||
|
Retrieves the platform vendor's slot number of the module
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
An integer, indicating the slot number in the chassis
|
||||||
|
"""
|
||||||
|
return self.index
|
||||||
|
|
||||||
|
def get_oper_status(self):
|
||||||
|
"""
|
||||||
|
Retrieves the operational status of the module
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A string, the operational status of the module from one of the
|
||||||
|
predefined status values: MODULE_STATUS_EMPTY, MODULE_STATUS_OFFLINE,
|
||||||
|
MODULE_STATUS_FAULT, MODULE_STATUS_PRESENT or MODULE_STATUS_ONLINE
|
||||||
|
"""
|
||||||
|
if self.get_presence():
|
||||||
|
if self.get_status():
|
||||||
|
return self.MODULE_STATUS_ONLINE
|
||||||
|
else:
|
||||||
|
return self.MODULE_STATUS_PRESENT
|
||||||
|
else:
|
||||||
|
return self.MODULE_STATUS_EMPTY
|
||||||
|
|
||||||
|
def get_maximum_consumed_power(self):
|
||||||
|
"""
|
||||||
|
Retrives the maximum power drawn by this module
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A float, with value of the maximum consumable power of the
|
||||||
|
module.
|
||||||
|
"""
|
||||||
|
return 97.23
|
||||||
|
@ -34,11 +34,13 @@ class Psu(PsuBase):
|
|||||||
self.psu_voltage_reg = "in30_input"
|
self.psu_voltage_reg = "in30_input"
|
||||||
self.psu_current_reg = "curr602_input"
|
self.psu_current_reg = "curr602_input"
|
||||||
self.psu_power_reg = "power2_input"
|
self.psu_power_reg = "power2_input"
|
||||||
|
self.psu_maxpower_reg = "power2_max"
|
||||||
self.psu_temperature_reg = "temp14_input"
|
self.psu_temperature_reg = "temp14_input"
|
||||||
elif self.index == 2:
|
elif self.index == 2:
|
||||||
self.psu_voltage_reg = "in32_input"
|
self.psu_voltage_reg = "in32_input"
|
||||||
self.psu_current_reg = "curr702_input"
|
self.psu_current_reg = "curr702_input"
|
||||||
self.psu_power_reg = "power4_input"
|
self.psu_power_reg = "power4_input"
|
||||||
|
self.psu_maxpower_reg = "power4_max"
|
||||||
self.psu_temperature_reg = "temp15_input"
|
self.psu_temperature_reg = "temp15_input"
|
||||||
|
|
||||||
# Passing True to specify it is a PSU fan
|
# Passing True to specify it is a PSU fan
|
||||||
@ -124,6 +126,19 @@ class Psu(PsuBase):
|
|||||||
|
|
||||||
return psu_serialno
|
return psu_serialno
|
||||||
|
|
||||||
|
def get_revision(self):
|
||||||
|
"""
|
||||||
|
Retrieves the hardware revision of the device
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
string: Revision value of device
|
||||||
|
"""
|
||||||
|
serial = self.get_serial()
|
||||||
|
if serial != "NA" and len(serial) == 28:
|
||||||
|
return serial[-3:]
|
||||||
|
else:
|
||||||
|
return "NA"
|
||||||
|
|
||||||
def get_status(self):
|
def get_status(self):
|
||||||
"""
|
"""
|
||||||
Retrieves the operational status of the PSU
|
Retrieves the operational status of the PSU
|
||||||
@ -195,6 +210,24 @@ class Psu(PsuBase):
|
|||||||
|
|
||||||
return psu_power
|
return psu_power
|
||||||
|
|
||||||
|
def get_maximum_supplied_power(self):
|
||||||
|
"""
|
||||||
|
Retrieves the maximum supplied power by PSU
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A float number, the maximum power output in Watts.
|
||||||
|
e.g. 1200.1
|
||||||
|
"""
|
||||||
|
psu_maxpower = self._get_pmc_register(self.psu_maxpower_reg)
|
||||||
|
if (psu_maxpower != 'ERR') and self.get_presence():
|
||||||
|
# Converting the value returned by driver which is in
|
||||||
|
# microwatts to watts
|
||||||
|
psu_maxpower = float(psu_maxpower) / 1000000
|
||||||
|
else:
|
||||||
|
psu_maxpower = 0.0
|
||||||
|
|
||||||
|
return psu_maxpower
|
||||||
|
|
||||||
def get_powergood_status(self):
|
def get_powergood_status(self):
|
||||||
"""
|
"""
|
||||||
Retrieves the powergood status of PSU
|
Retrieves the powergood status of PSU
|
||||||
|
@ -9,11 +9,15 @@
|
|||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
import os
|
||||||
import time
|
import time
|
||||||
from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase
|
from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
raise ImportError(str(e) + "- required module not found")
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
|
QSFP_INFO_OFFSET = 128
|
||||||
|
|
||||||
|
|
||||||
class Sfp(SfpOptoeBase):
|
class Sfp(SfpOptoeBase):
|
||||||
"""
|
"""
|
||||||
DELLEMC Platform-specific Sfp class
|
DELLEMC Platform-specific Sfp class
|
||||||
@ -238,3 +242,27 @@ class Sfp(SfpOptoeBase):
|
|||||||
bool: True if it is replaceable.
|
bool: True if it is replaceable.
|
||||||
"""
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def get_error_description(self):
|
||||||
|
"""
|
||||||
|
Retrives the error descriptions of the SFP module
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
String that represents the current error descriptions of vendor specific errors
|
||||||
|
In case there are multiple errors, they should be joined by '|',
|
||||||
|
like: "Bad EEPROM|Unsupported cable"
|
||||||
|
"""
|
||||||
|
if not self.get_presence():
|
||||||
|
return self.SFP_STATUS_UNPLUGGED
|
||||||
|
else:
|
||||||
|
if not os.path.isfile(self.eeprom_path):
|
||||||
|
return "EEPROM driver is not attached"
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(self.eeprom_path, mode="rb", buffering=0) as eeprom:
|
||||||
|
eeprom.seek(QSFP_INFO_OFFSET)
|
||||||
|
eeprom.read(1)
|
||||||
|
except OSError as e:
|
||||||
|
return "EEPROM read failed ({})".format(e.strerror)
|
||||||
|
|
||||||
|
return self.SFP_STATUS_OK
|
||||||
|
Reference in New Issue
Block a user