class Chassis(ChassisBase): """Platform-specific Chassis class""" # System status LED _led = None def __init__(self): super(Chassis, self).__init__() self.name = "Undefined" self.model = "Undefined" # Initialize Platform name self.platform_name = device_info.get_platform() # move the initialization of each components to their dedicated initializer # which will be called from platform self.sfp_module_initialized = False self.sfp_event_initialized = False self.reboot_cause_initialized = False logger.log_info("Chassis loaded successfully") def __del__(self): if self.sfp_event_initialized: self.sfp_event.deinitialize() if self.sfp_module_initialized: from sonic_platform.sfp import deinitialize_sdk_handle deinitialize_sdk_handle(self.sdk_handle) def initialize_psu(self): from sonic_platform.psu import Psu # Initialize PSU list self.psu_module = Psu for index in range(MLNX_NUM_PSU): psu = Psu(index, self.platform_name) self._psu_list.append(psu) def initialize_fan(self): from .device_data import DEVICE_DATA from sonic_platform.fan import Fan from .fan_drawer import RealDrawer, VirtualDrawer fan_data = DEVICE_DATA[self.platform_name]['fans'] drawer_num = fan_data['drawer_num'] drawer_type = fan_data['drawer_type'] fan_num_per_drawer = fan_data['fan_num_per_drawer'] drawer_ctor = RealDrawer if drawer_type == 'real' else VirtualDrawer fan_index = 0 for drawer_index in range(drawer_num): drawer = drawer_ctor(drawer_index, fan_data) self._fan_drawer_list.append(drawer) for index in range(fan_num_per_drawer): fan = Fan(fan_index, drawer, index + 1) fan_index += 1 drawer._fan_list.append(fan) self._fan_list.append(fan) def initialize_sfp(self): from sonic_platform.sfp import SFP from sonic_platform.sfp import initialize_sdk_handle self.sfp_module = SFP self.sdk_handle = initialize_sdk_handle() if self.sdk_handle is None: self.sfp_module_initialized = False return # Initialize SFP list port_position_tuple = self._get_port_position_tuple_by_platform_name() self.PORT_START = port_position_tuple[0] self.QSFP_PORT_START = port_position_tuple[1] self.PORT_END = port_position_tuple[2] self.PORTS_IN_BLOCK = port_position_tuple[3] for index in range(self.PORT_START, self.PORT_END + 1): if index in range(self.QSFP_PORT_START, self.PORTS_IN_BLOCK + 1): sfp_module = SFP(index, 'QSFP', self.sdk_handle, self.platform_name) else: sfp_module = SFP(index, 'SFP', self.sdk_handle, self.platform_name) self._sfp_list.append(sfp_module) self.sfp_module_initialized = True def initialize_thermals(self): from sonic_platform.thermal import initialize_chassis_thermals # Initialize thermals initialize_chassis_thermals(self.platform_name, self._thermal_list) def initialize_eeprom(self): from eeprom import Eeprom # Initialize EEPROM self._eeprom = Eeprom() # Get chassis name and model from eeprom self.name = self._eeprom.get_product_name() self.model = self._eeprom.get_part_number() def initialize_components(self): # Initialize component list from sonic_platform.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()) def initizalize_system_led(self): from .led import SystemLed Chassis._led = SystemLed() def get_name(self): """ Retrieves the name of the device Returns: string: The name of the device """ return self.name def get_model(self): """ Retrieves the model number (or part number) of the device Returns: string: Model/part number of device """ return self.model ############################################## # SFP methods ############################################## def get_num_sfps(self): """ Retrieves the number of sfps available on this chassis Returns: An integer, the number of sfps available on this chassis """ if not self.sfp_module_initialized: self.initialize_sfp() return len(self._sfp_list) def get_all_sfps(self): """ Retrieves all sfps available on this chassis Returns: A list of objects derived from SfpBase representing all sfps available on this chassis """ if not self.sfp_module_initialized: self.initialize_sfp() return self._sfp_list def get_sfp(self, index): """ Retrieves sfp represented by (1-based) index <index> Args: index: An integer, the index (1-based) of the sfp to retrieve. The index should be the sequence of a physical port in a chassis, starting from 1. For example, 1 for Ethernet0, 2 for Ethernet4 and so on. Returns: An object dervied from SfpBase representing the specified sfp """ if not self.sfp_module_initialized: self.initialize_sfp() sfp = None index -= 1 try: sfp = self._sfp_list[index] except IndexError: sys.stderr.write("SFP index {} out of range (0-{})\n".format( index, len(self._sfp_list) - 1)) return sfp def _extract_num_of_fans_and_fan_drawers(self): num_of_fan = 0 num_of_drawer = 0 for f in listdir(self.fan_path): if isfile(join(self.fan_path, f)): match_obj = re.match('fan(\d+)_speed_get', f) if match_obj != None: if int(match_obj.group(1)) > num_of_fan: num_of_fan = int(match_obj.group(1)) else: match_obj = re.match('fan(\d+)_status', f) if match_obj != None and int( match_obj.group(1)) > num_of_drawer: num_of_drawer = int(match_obj.group(1)) return num_of_fan, num_of_drawer def _get_port_position_tuple_by_platform_name(self): position_tuple = port_position_tuple_list[platform_dict_port[ self.platform_name]] return position_tuple def get_watchdog(self): """ Retrieves hardware watchdog device on this chassis Returns: An object derived from WatchdogBase representing the hardware watchdog device Note: We overload this method to ensure that watchdog is only initialized when it is referenced. Currently, only one daemon can open the watchdog. To initialize watchdog in the constructor causes multiple daemon try opening watchdog when loading and constructing a chassis object and fail. By doing so we can eliminate that risk. """ try: if self._watchdog is None: from sonic_platform.watchdog import get_watchdog self._watchdog = get_watchdog() except Exception as e: logger.log_info("Fail to load watchdog due to {}".format(repr(e))) return self._watchdog def get_base_mac(self): """ Retrieves the base MAC address for the chassis Returns: A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ return self._eeprom.get_base_mac() def get_serial(self): """ Retrieves the hardware serial number for the chassis Returns: A string containing the hardware serial number for this chassis. """ return self._eeprom.get_serial_number() def get_system_eeprom_info(self): """ Retrieves the full content of system EEPROM information for the chassis Returns: A dictionary where keys are the type code defined in OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ return self._eeprom.get_system_eeprom_info() def _read_generic_file(self, filename, len): """ Read a generic file, returns the contents of the file """ result = '' try: fileobj = io.open(filename) result = fileobj.read(len) fileobj.close() return result except Exception as e: logger.log_info("Fail to read file {} due to {}".format( filename, repr(e))) return '0' def _verify_reboot_cause(self, filename): ''' Open and read the reboot cause file in /var/run/hwmanagement/system (which is defined as REBOOT_CAUSE_ROOT) If a reboot cause file doesn't exists, returns '0'. ''' return bool( int( self._read_generic_file( join(REBOOT_CAUSE_ROOT, filename), REBOOT_CAUSE_FILE_LENGTH).rstrip('\n'))) def initialize_reboot_cause(self): self.reboot_major_cause_dict = { 'reset_main_pwr_fail': self.REBOOT_CAUSE_POWER_LOSS, 'reset_aux_pwr_or_ref': self.REBOOT_CAUSE_POWER_LOSS, 'reset_asic_thermal': self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC, 'reset_hotswap_or_wd': self.REBOOT_CAUSE_WATCHDOG, 'reset_swb_wd': self.REBOOT_CAUSE_WATCHDOG, 'reset_sff_wd': self.REBOOT_CAUSE_WATCHDOG } self.reboot_minor_cause_dict = { 'reset_fw_reset': "Reset by ASIC firmware", 'reset_long_pb': "Reset by long press on power button", 'reset_short_pb': "Reset by short press on power button", 'reset_comex_thermal': "ComEx thermal shutdown", 'reset_comex_pwr_fail': "ComEx power fail", 'reset_comex_wd': "Reset requested from ComEx", 'reset_from_asic': "Reset requested from ASIC", 'reset_reload_bios': "Reset caused by BIOS reload", 'reset_hotswap_or_halt': "Reset caused by hotswap or halt", 'reset_from_comex': "Reset from ComEx", 'reset_voltmon_upgrade_fail': "Reset due to voltage monitor devices upgrade failure" } self.reboot_by_software = 'reset_sw_reset' self.reboot_cause_initialized = True def get_reboot_cause(self): """ Retrieves the cause of the previous reboot Returns: A tuple (string, string) where the first element is a string containing the cause of the previous reboot. This string must be one of the predefined strings in this class. If the first string is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used to pass a description of the reboot cause. """ #read reboot causes files in the following order if not self.reboot_cause_initialized: self.initialize_reboot_cause() for reset_file, reset_cause in self.reboot_major_cause_dict.iteritems( ): if self._verify_reboot_cause(reset_file): return reset_cause, '' for reset_file, reset_cause in self.reboot_minor_cause_dict.iteritems( ): if self._verify_reboot_cause(reset_file): return self.REBOOT_CAUSE_HARDWARE_OTHER, reset_cause if self._verify_reboot_cause(self.reboot_by_software): logger.log_info( "Hardware reboot cause: the system was rebooted due to software requesting" ) else: logger.log_info( "Hardware reboot cause: no hardware reboot cause found") return self.REBOOT_CAUSE_NON_HARDWARE, '' def _show_capabilities(self): """ This function is for debug purpose Some features require a xSFP module to support some capabilities but it's unrealistic to check those modules one by one. So this function is introduce to show some capabilities of all xSFP modules mounted on the device. """ for s in self._sfp_list: try: print "index {} tx disable {} dom {} calibration {} temp {} volt {} power (tx {} rx {})".format( s.index, s.dom_tx_disable_supported, s.dom_supported, s.calibration, s.dom_temp_supported, s.dom_volt_supported, s.dom_rx_power_supported, s.dom_tx_power_supported) except: print "fail to retrieve capabilities for module index {}".format( s.index) def get_change_event(self, timeout=0): """ Returns a nested dictionary containing all devices which have experienced a change at chassis level Args: timeout: Timeout in milliseconds (optional). If timeout == 0, this method will block until a change is detected. Returns: (bool, dict): - True if call successful, False if not; - A nested dictionary where key is a device type, value is a dictionary with key:value pairs in the format of {'device_id':'device_event'}, where device_id is the device ID for this device and device_event, status='1' represents device inserted, status='0' represents device removed. Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}} indicates that fan 0 has been removed, fan 2 has been inserted and sfp 11 has been removed. """ # Initialize SFP event first if not self.sfp_event_initialized: from sonic_platform.sfp_event import sfp_event self.sfp_event = sfp_event() self.sfp_event.initialize() self.MAX_SELECT_EVENT_RETURNED = self.PORT_END self.sfp_event_initialized = True wait_for_ever = (timeout == 0) port_dict = {} if wait_for_ever: timeout = MAX_SELECT_DELAY while True: status = self.sfp_event.check_sfp_status(port_dict, timeout) if bool(port_dict): break else: status = self.sfp_event.check_sfp_status(port_dict, timeout) if status: self.reinit_sfps(port_dict) return True, {'sfp': port_dict} else: return True, {'sfp': {}} def reinit_sfps(self, port_dict): """ Re-initialize SFP if there is any newly inserted SFPs :param port_dict: SFP event data :return: """ # SFP not initialize yet, do nothing if not self.sfp_module_initialized: return from . import sfp for index, status in port_dict.items(): if status == sfp.SFP_STATUS_INSERTED: try: self.get_sfp(index).reinit() except Exception as e: logger.log_error( "Fail to re-initialize SFP {} - {}".format( index, repr(e))) def get_thermal_manager(self): from .thermal_manager import ThermalManager return ThermalManager def set_status_led(self, color): """ Sets the state of the system LED Args: color: A string representing the color with which to set the system LED Returns: bool: True if system LED state is set successfully, False if not """ return False if not Chassis._led else Chassis._led.set_status(color) def get_status_led(self): """ Gets the state of the system LED Returns: A string, one of the valid LED color strings which could be vendor specified. """ return None if not Chassis._led else Chassis._led.get_status() def get_position_in_parent(self): """ Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned Returns: integer: The 1-based relative physical position in parent device or -1 if cannot determine the position """ return -1 def is_replaceable(self): """ Indicate whether this device is replaceable. Returns: bool: True if it is replaceable. """ return False
def _eeprom(self): if self.__eeprom is None: self.__eeprom = Eeprom() return self.__eeprom
class Chassis(ChassisBase): """Platform-specific Chassis class""" def __init__(self): super(Chassis, self).__init__() # Initialize SKU name self.sku_name = self._get_sku_name() # move the initialization of each components to their dedicated initializer # which will be called from platform self.sfp_module_initialized = False self.sfp_event_initialized = False self.reboot_cause_initialized = False logger.log_info("Chassis loaded successfully") def __del__(self): if self.sfp_event_initialized: self.sfp_event.deinitialize() def initialize_psu(self): from sonic_platform.psu import Psu # Initialize PSU list self.psu_module = Psu for index in range(MLNX_NUM_PSU): psu = Psu(index, self.sku_name) self._psu_list.append(psu) def initialize_fan(self): from sonic_platform.fan import Fan from sonic_platform.fan import FAN_PATH self.fan_module = Fan self.fan_path = FAN_PATH # Initialize FAN list multi_rotor_in_drawer = False num_of_fan, num_of_drawer = self._extract_num_of_fans_and_fan_drawers() multi_rotor_in_drawer = num_of_fan > num_of_drawer for index in range(num_of_fan): if multi_rotor_in_drawer: fan = Fan(index, index/2) else: fan = Fan(index, index) self._fan_list.append(fan) def initialize_sfp(self): from sonic_platform.sfp import SFP self.sfp_module = SFP # Initialize SFP list port_position_tuple = self._get_port_position_tuple_by_sku_name() self.PORT_START = port_position_tuple[0] self.QSFP_PORT_START = port_position_tuple[1] self.PORT_END = port_position_tuple[2] self.PORTS_IN_BLOCK = port_position_tuple[3] for index in range(self.PORT_START, self.PORT_END + 1): if index in range(self.QSFP_PORT_START, self.PORTS_IN_BLOCK + 1): sfp_module = SFP(index, 'QSFP') else: sfp_module = SFP(index, 'SFP') self._sfp_list.append(sfp_module) self.sfp_module_initialized = True def initialize_thermals(self): from sonic_platform.thermal import initialize_thermals # Initialize thermals initialize_thermals(self.sku_name, self._thermal_list, self._psu_list) def initialize_eeprom(self): from eeprom import Eeprom # Initialize EEPROM self._eeprom = Eeprom() def initialize_components_list(self): # Initialize component list self._component_name_list.append(COMPONENT_BIOS) self._component_name_list.append(COMPONENT_FIRMWARE) self._component_name_list.append(COMPONENT_CPLD1) self._component_name_list.append(COMPONENT_CPLD2) ############################################## # SFP methods ############################################## def get_num_sfps(self): """ Retrieves the number of sfps available on this chassis Returns: An integer, the number of sfps available on this chassis """ if not self.sfp_module_initialized: self.initialize_sfp() return len(self._sfp_list) def get_all_sfps(self): """ Retrieves all sfps available on this chassis Returns: A list of objects derived from SfpBase representing all sfps available on this chassis """ if not self.sfp_module_initialized: self.initialize_sfp() return self._sfp_list def get_sfp(self, index): """ Retrieves sfp represented by (0-based) index <index> Args: index: An integer, the index (0-based) of the sfp to retrieve. The index should be the sequence of a physical port in a chassis, starting from 0. For example, 0 for Ethernet0, 1 for Ethernet4 and so on. Returns: An object dervied from SfpBase representing the specified sfp """ if not self.sfp_module_initialized: self.initialize_sfp() sfp = None try: sfp = self._sfp_list[index] except IndexError: sys.stderr.write("SFP index {} out of range (0-{})\n".format( index, len(self._sfp_list)-1)) return sfp def _extract_num_of_fans_and_fan_drawers(self): num_of_fan = 0 num_of_drawer = 0 for f in listdir(self.fan_path): if isfile(join(self.fan_path, f)): match_obj = re.match('fan(\d+)_speed_get', f) if match_obj != None: if int(match_obj.group(1)) > num_of_fan: num_of_fan = int(match_obj.group(1)) else: match_obj = re.match('fan(\d+)_status', f) if match_obj != None and int(match_obj.group(1)) > num_of_drawer: num_of_drawer = int(match_obj.group(1)) return num_of_fan, num_of_drawer def _get_sku_name(self): p = subprocess.Popen(GET_HWSKU_CMD, shell=True, stdout=subprocess.PIPE) out, err = p.communicate() return out.rstrip('\n') def _get_port_position_tuple_by_sku_name(self): position_tuple = port_position_tuple_list[hwsku_dict_port[self.sku_name]] return position_tuple def get_watchdog(self): """ Retrieves hardware watchdog device on this chassis Returns: An object derived from WatchdogBase representing the hardware watchdog device Note: We overload this method to ensure that watchdog is only initialized when it is referenced. Currently, only one daemon can open the watchdog. To initialize watchdog in the constructor causes multiple daemon try opening watchdog when loading and constructing a chassis object and fail. By doing so we can eliminate that risk. """ try: if self._watchdog is None: from sonic_platform.watchdog import get_watchdog self._watchdog = get_watchdog() except Exception as e: logger.log_info("Fail to load watchdog due to {}".format(repr(e))) return self._watchdog def get_base_mac(self): """ Retrieves the base MAC address for the chassis Returns: A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ return self._eeprom.get_base_mac() def get_serial_number(self): """ Retrieves the hardware serial number for the chassis Returns: A string containing the hardware serial number for this chassis. """ return self._eeprom.get_serial_number() def get_system_eeprom_info(self): """ Retrieves the full content of system EEPROM information for the chassis Returns: A dictionary where keys are the type code defined in OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ return self._eeprom.get_system_eeprom_info() def _read_generic_file(self, filename, len): """ Read a generic file, returns the contents of the file """ result = '' try: fileobj = io.open(filename) result = fileobj.read(len) fileobj.close() return result except Exception as e: logger.log_info("Fail to read file {} due to {}".format(filename, repr(e))) return '0' def _verify_reboot_cause(self, filename): ''' Open and read the reboot cause file in /var/run/hwmanagement/system (which is defined as REBOOT_CAUSE_ROOT) If a reboot cause file doesn't exists, returns '0'. ''' return bool(int(self._read_generic_file(join(REBOOT_CAUSE_ROOT, filename), REBOOT_CAUSE_FILE_LENGTH).rstrip('\n'))) def initialize_reboot_cause(self): self.reboot_major_cause_dict = { 'reset_main_pwr_fail' : self.REBOOT_CAUSE_POWER_LOSS, 'reset_aux_pwr_or_ref' : self.REBOOT_CAUSE_POWER_LOSS, 'reset_asic_thermal' : self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC, 'reset_hotswap_or_wd' : self.REBOOT_CAUSE_WATCHDOG, 'reset_swb_wd' : self.REBOOT_CAUSE_WATCHDOG, 'reset_sff_wd' : self.REBOOT_CAUSE_WATCHDOG } self.reboot_minor_cause_dict = { 'reset_fw_reset' : "Reset by ASIC firmware", 'reset_long_pb' : "Reset by long press on power button", 'reset_short_pb' : "Reset by short press on power button", 'reset_comex_thermal' : "ComEx thermal shutdown", 'reset_comex_pwr_fail' : "ComEx power fail", 'reset_comex_wd' : "Reset requested from ComEx", 'reset_from_asic' : "Reset requested from ASIC", 'reset_reload_bios' : "Reset caused by BIOS reload", 'reset_sw_reset' : "Software reset", 'reset_hotswap_or_halt' : "Reset caused by hotswap or halt", 'reset_from_comex' : "Reset from ComEx", 'reset_voltmon_upgrade_fail': "Reset due to voltage monitor devices upgrade failure" } self.reboot_cause_initialized = True def get_reboot_cause(self): """ Retrieves the cause of the previous reboot Returns: A tuple (string, string) where the first element is a string containing the cause of the previous reboot. This string must be one of the predefined strings in this class. If the first string is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used to pass a description of the reboot cause. """ #read reboot causes files in the following order if not self.reboot_cause_initialized: self.initialize_reboot_cause() for reset_file, reset_cause in self.reboot_major_cause_dict.iteritems(): if self._verify_reboot_cause(reset_file): return reset_cause, '' for reset_file, reset_cause in self.reboot_minor_cause_dict.iteritems(): if self._verify_reboot_cause(reset_file): return self.REBOOT_CAUSE_HARDWARE_OTHER, reset_cause return self.REBOOT_CAUSE_NON_HARDWARE, '' def _get_cpld_version(self, version_file): cpld_version = self._read_generic_file(join(CPLD_VERSION_ROOT, version_file), CPLD_VERSION_MAX_LENGTH) return cpld_version.rstrip('\n') def _get_command_result(self, cmdline): try: proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE, shell=True, stderr=subprocess.STDOUT) stdout = proc.communicate()[0] proc.wait() result = stdout.rstrip('\n') except OSError, e: result = '' return result
class Chassis(ChassisBase): """ DELLEMC Platform-specific Chassis class """ HWMON_DIR = "/sys/devices/platform/SMF.512/hwmon/" HWMON_NODE = os.listdir(HWMON_DIR)[0] MAILBOX_DIR = HWMON_DIR + HWMON_NODE EEPROM_I2C_MAPPING = { 0: [9, 18], 1: [9, 19], 2: [9, 20], 3: [9, 21], 4: [9, 22], 5: [9, 23], 6: [9, 24], 7: [9, 25], 8: [8, 26], 9: [8, 27], 10: [8, 28], 11: [8, 29], 12: [8, 31], 13: [8, 30], 14: [8, 33], 15: [8, 32], # Remapped 4 entries 16: [7, 34], 17: [7, 35], 18: [7, 36], 19: [7, 37], 20: [7, 38], 21: [7, 39], 22: [7, 40], 23: [7, 41], 24: [6, 42], 25: [6, 43], 26: [6, 44], 27: [6, 45], 28: [6, 46], 29: [6, 47], 30: [6, 48], 31: [6, 49] } PORT_I2C_MAPPING = { # 0th Index = i2cLine, 1st Index = portIdx in i2cLine 0: [14, 0], 1: [14, 1], 2: [14, 2], 3: [14, 3], 4: [14, 4], 5: [14, 5], 6: [14, 6], 7: [14, 7], 8: [14, 8], 9: [14, 9], 10: [14, 10], 11: [14, 11], 12: [15, 0], 13: [15, 1], 14: [15, 2], 15: [15, 3], 16: [15, 4], 17: [15, 5], 18: [15, 6], 19: [15, 7], 20: [15, 8], 21: [15, 9], 22: [16, 0], 23: [16, 1], 24: [16, 2], 25: [16, 3], 26: [16, 4], 27: [16, 5], 28: [16, 6], 29: [16, 7], 30: [16, 8], 31: [16, 9] } reset_reason_dict = {} reset_reason_dict[11] = ChassisBase.REBOOT_CAUSE_POWER_LOSS reset_reason_dict[33] = ChassisBase.REBOOT_CAUSE_WATCHDOG reset_reason_dict[44] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE reset_reason_dict[55] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE power_reason_dict = {} power_reason_dict[11] = ChassisBase.REBOOT_CAUSE_POWER_LOSS power_reason_dict[22] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU power_reason_dict[33] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC power_reason_dict[44] = ChassisBase.REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED def __init__(self): ChassisBase.__init__(self) PORT_START = 0 PORT_END = 31 PORTS_IN_BLOCK = (PORT_END + 1) # sfp.py will read eeprom contents and retrive the eeprom data. # It will also provide support sfp controls like reset and setting # low power mode. # We pass the eeprom path and sfp control path from chassis.py # So that sfp.py implementation can be generic to all platforms eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/i2c-{1}/{1}-0050/eeprom" sfp_ctrl_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-003e/" for index in range(0, PORTS_IN_BLOCK): eeprom_path = eeprom_base.format(self.EEPROM_I2C_MAPPING[index][0], self.EEPROM_I2C_MAPPING[index][1]) sfp_control = sfp_ctrl_base.format(self.PORT_I2C_MAPPING[index][0]) sfp_node = Sfp(index, 'QSFP', eeprom_path, sfp_control, self.PORT_I2C_MAPPING[index][1]) self._sfp_list.append(sfp_node) # Initialize EEPROM self._eeprom = Eeprom() for i in range(MAX_Z9100_FANTRAY): for j in range(MAX_Z9100_FAN): fan = Fan(i, j) self._fan_list.append(fan) for i in range(MAX_Z9100_PSU): psu = Psu(i) self._psu_list.append(psu) for i in range(MAX_Z9100_THERMAL): thermal = Thermal(i) self._thermal_list.append(thermal) for i in range(MAX_Z9100_COMPONENT): component = Component(i) self._component_list.append(component) def _get_pmc_register(self, reg_name): # On successful read, returns the value read from given # reg_name and on failure returns 'ERR' rv = 'ERR' mb_reg_file = self.MAILBOX_DIR + '/' + reg_name if (not os.path.isfile(mb_reg_file)): return rv try: with open(mb_reg_file, 'r') as fd: rv = fd.read() except Exception as error: rv = 'ERR' rv = rv.rstrip('\r\n') rv = rv.lstrip(" ") return rv def get_name(self): """ Retrieves the name of the chassis Returns: string: The name of the chassis """ return self._eeprom.modelstr() def get_presence(self): """ Retrieves the presence of the chassis Returns: bool: True if chassis is present, False if not """ return True def get_model(self): """ Retrieves the model number (or part number) of the chassis Returns: string: Model/part number of chassis """ return self._eeprom.part_number_str() def get_serial(self): """ Retrieves the serial number of the chassis (Service tag) Returns: string: Serial number of chassis """ return self._eeprom.serial_str() def get_status(self): """ Retrieves the operational status of the chassis Returns: bool: A boolean value, True if chassis is operating properly False if not """ return True def get_base_mac(self): """ Retrieves the base MAC address for the chassis Returns: A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ return self._eeprom.base_mac_addr() def get_serial_number(self): """ Retrieves the hardware serial number for the chassis Returns: A string containing the hardware serial number for this chassis. """ return self._eeprom.serial_number_str() def get_system_eeprom_info(self): """ Retrieves the full content of system EEPROM information for the chassis Returns: A dictionary where keys are the type code defined in OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ return self._eeprom.system_eeprom_info() def get_reboot_cause(self): """ Retrieves the cause of the previous reboot Returns: A tuple (string, string) where the first element is a string containing the cause of the previous reboot. This string must be one of the predefined strings in this class. If the first string is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used to pass a description of the reboot cause. """ reset_reason = int(self._get_pmc_register('smf_reset_reason')) power_reason = int(self._get_pmc_register('smf_poweron_reason')) # Reset_Reason = 11 ==> PowerLoss # So return the reboot reason from Last Power_Reason Dictionary # If Reset_Reason is not 11 return from Reset_Reason dictionary # Also check if power_reason, reset_reason are valid values by # checking key presence in dictionary else return # REBOOT_CAUSE_HARDWARE_OTHER as the Power_Reason and Reset_Reason # registers returned invalid data if (reset_reason == 11): if (power_reason in self.power_reason_dict): return (self.power_reason_dict[power_reason], None) else: if (reset_reason in self.reset_reason_dict): return (self.reset_reason_dict[reset_reason], None) return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Invalid Reason")
class Chassis(ChassisBase): """ DELLEMC Platform-specific Chassis class """ HWMON_DIR = "/sys/devices/platform/SMF.512/hwmon/" HWMON_NODE = os.listdir(HWMON_DIR)[0] MAILBOX_DIR = HWMON_DIR + HWMON_NODE PORT_START = 0 PORT_END = 63 PORTS_IN_BLOCK = (PORT_END + 1) IOM1_PORT_START = 0 IOM2_PORT_START = 16 IOM3_PORT_START = 32 IOM4_PORT_START = 48 PORT_I2C_MAPPING = {} # 0th Index = i2cLine, 1st Index = EepromIdx in i2cLine EEPROM_I2C_MAPPING = { # IOM 1 0: [6, 66], 1: [6, 67], 2: [6, 68], 3: [6, 69], 4: [6, 70], 5: [6, 71], 6: [6, 72], 7: [6, 73], 8: [6, 74], 9: [6, 75], 10: [6, 76], 11: [6, 77], 12: [6, 78], 13: [6, 79], 14: [6, 80], 15: [6, 81], # IOM 2 16: [8, 50], 17: [8, 51], 18: [8, 52], 19: [8, 53], 20: [8, 54], 21: [8, 55], 22: [8, 56], 23: [8, 57], 24: [8, 58], 25: [8, 59], 26: [8, 60], 27: [8, 61], 28: [8, 62], 29: [8, 63], 30: [8, 64], 31: [8, 65], # IOM 3 32: [7, 34], 33: [7, 35], 34: [7, 36], 35: [7, 37], 36: [7, 38], 37: [7, 39], 38: [7, 40], 39: [7, 41], 40: [7, 42], 41: [7, 43], 42: [7, 44], 43: [7, 45], 44: [7, 46], 45: [7, 47], 46: [7, 48], 47: [7, 49], # IOM 4 48: [9, 18], 49: [9, 19], 50: [9, 20], 51: [9, 21], 52: [9, 22], 53: [9, 23], 54: [9, 24], 55: [9, 25], 56: [9, 26], 57: [9, 27], 58: [9, 28], 59: [9, 29], 60: [9, 30], 61: [9, 31], 62: [9, 32], 63: [9, 33] } reset_reason_dict = {} reset_reason_dict[11] = ChassisBase.REBOOT_CAUSE_POWER_LOSS reset_reason_dict[33] = ChassisBase.REBOOT_CAUSE_WATCHDOG reset_reason_dict[44] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE reset_reason_dict[55] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE power_reason_dict = {} power_reason_dict[11] = ChassisBase.REBOOT_CAUSE_POWER_LOSS power_reason_dict[22] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU power_reason_dict[33] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC power_reason_dict[44] = ChassisBase.REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED _component_name_list = ["BIOS", "CPLD1", "CPLD2", "FPGA"] def __init__(self): ChassisBase.__init__(self) # Initialize EEPROM self.sys_eeprom = Eeprom() for i in range(MAX_S6100_FAN): fan = Fan(i) self._fan_list.append(fan) for i in range(MAX_S6100_PSU): psu = Psu(i) self._psu_list.append(psu) self._populate_port_i2c_mapping() # sfp.py will read eeprom contents and retrive the eeprom data. # It will also provide support sfp controls like reset and setting # low power mode. # We pass the eeprom path and sfp control path from chassis.py # So that sfp.py implementation can be generic to all platforms eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/i2c-{1}/{1}-0050/eeprom" sfp_ctrl_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-003e/" for index in range(0, self.PORTS_IN_BLOCK): eeprom_path = eeprom_base.format(self.EEPROM_I2C_MAPPING[index][0], self.EEPROM_I2C_MAPPING[index][1]) sfp_control = sfp_ctrl_base.format(self.PORT_I2C_MAPPING[index]) sfp_node = Sfp(index, 'QSFP', eeprom_path, sfp_control, index) self._sfp_list.append(sfp_node) def _populate_port_i2c_mapping(self): # port_num and i2c match for port_num in range(0, self.PORTS_IN_BLOCK): if ((port_num >= self.IOM1_PORT_START) and (port_num < self.IOM2_PORT_START)): i2c_line = 14 elif ((port_num >= self.IOM2_PORT_START) and (port_num < self.IOM3_PORT_START)): i2c_line = 16 elif ((port_num >= self.IOM3_PORT_START) and (port_num < self.IOM4_PORT_START)): i2c_line = 15 elif ((port_num >= self.IOM4_PORT_START) and (port_num < self.PORTS_IN_BLOCK)): i2c_line = 17 self.PORT_I2C_MAPPING[port_num] = i2c_line def _get_pmc_register(self, reg_name): # On successful read, returns the value read from given # reg_name and on failure returns 'ERR' rv = 'ERR' mb_reg_file = self.MAILBOX_DIR + '/' + reg_name if (not os.path.isfile(mb_reg_file)): return rv try: with open(mb_reg_file, 'r') as fd: rv = fd.read() except Exception as error: rv = 'ERR' rv = rv.rstrip('\r\n') rv = rv.lstrip(" ") return rv # Run bash command and print output to stdout def run_command(self, command): click.echo( click.style("Command: ", fg='cyan') + click.style(command, fg='green')) proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) (out, err) = proc.communicate() click.echo(out) if proc.returncode != 0: sys.exit(proc.returncode) def get_name(self): """ Retrieves the name of the device Returns: string: The name of the device """ return self.sys_eeprom.modelstr() def get_presence(self): """ Retrieves the presence of the device Returns: bool: True if device is present, False if not """ return True def get_model(self): """ Retrieves the model number (or part number) of the device Returns: string: Model/part number of device """ return self.sys_eeprom.part_number_str() def get_serial(self): """ Retrieves the serial number of the device (Service tag) Returns: string: Serial number of device """ return self.sys_eeprom.serial_str() def get_base_mac(self): """ Retrieves the base MAC address for the chassis Returns: A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ return self.sys_eeprom.base_mac_addr() def get_serial_number(self): """ Retrieves the hardware serial number for the chassis Returns: A string containing the hardware serial number for this chassis. """ return self.sys_eeprom.serial_number_str() def get_system_eeprom_info(self): """ Retrieves the full content of system EEPROM information for the chassis Returns: A dictionary where keys are the type code defined in OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ def get_reboot_cause(self): """ Retrieves the cause of the previous reboot Returns: A tuple (string, string) where the first element is a string containing the cause of the previous reboot. This string must be one of the predefined strings in this class. If the first string is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used to pass a description of the reboot cause. """ reset_reason = int(self._get_pmc_register('smf_reset_reason')) power_reason = int(self._get_pmc_register('smf_poweron_reason')) # Reset_Reason = 11 ==> PowerLoss # So return the reboot reason from Last Power_Reason Dictionary # If Reset_Reason is not 11 return from Reset_Reason dictionary # Also check if power_reason, reset_reason are valid values by # checking key presence in dictionary else return # REBOOT_CAUSE_HARDWARE_OTHER as the Power_Reason and Reset_Reason # registers returned invalid data if (reset_reason == 11): if (power_reason in self.power_reason_dict): return (self.power_reason_dict[power_reason], None) else: if (reset_reason in self.reset_reason_dict): return (self.reset_reason_dict[reset_reason], None) return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Invalid Reason") def get_component_name_list(self): """ Retrieves chassis components list such as BIOS, CPLD, FPGA, etc. Returns: A list containing component name. """ return self._component_name_list def get_firmware_version(self, component_name): version = None if component_name in self._component_name_list: if component_name == self._component_name_list[0]: # BIOS status, version = getstatusoutput( "dmidecode -s system-version") elif component_name == self._component_name_list[1]: # CPLD1 version = None elif component_name == self._component_name_list[2]: # CPLD2 version = None elif component_name == self._component_name_list[3]: # SMF version = None return version def install_component_firmware(self, component_name, image_path): bios_image = None bios_version = "3.25.0." bios_file_name = "S6100*BIOS*" flashrom = "/usr/local/bin/flashrom" PLATFORM_ROOT_PATH = '/usr/share/sonic/device' machine_info = sonic_device_util.get_machine_info() platform = sonic_device_util.get_platform_info(machine_info) platform_path = "/".join([PLATFORM_ROOT_PATH, platform, "bin"]) warning = """ ******************************************************************** * Warning - Upgrading BIOS is inherently risky and should only be * * attempted when necessary. A failure at this upgrade may cause * * a board RMA. Proceed with caution ! * ******************************************************************** """ if component_name in self._component_name_list: if component_name == self._component_name_list[0]: # BIOS # current BIOS version current_bios_version = self.get_firmware_version("BIOS") # Construct BIOS image path if image_path is not None: image_path = image_path + platform_path for name in glob.glob( os.path.join(image_path, bios_file_name)): bios_image = image_path = name if not bios_image: print "BIOS image file not found:", image_path return False # Extract BIOS image version bios_image = os.path.basename(bios_image) bios_image = bios_image.strip('S6100-BIOS-') bios_image_version = bios_image.strip('.bin') if bios_image_version.startswith(bios_version): bios_image_minor = bios_image_version.replace( bios_image_version[:7], '') if bios_image_minor.startswith("2"): bios_image_minor = bios_image_minor.split("-")[1] if current_bios_version.startswith(bios_version): current_bios_minor = current_bios_version.replace( current_bios_version[:7], '') if current_bios_minor.startswith("2"): current_bios_minor = current_bios_minor.split("-")[1] # BIOS version check if bios_image_minor > current_bios_minor: print warning prompt_text = "New BIOS image " + bios_image_version + \ " available to install, continue?" yes = click.confirm(prompt_text) elif current_bios_minor > bios_image_minor: print warning prompt_text = "Do you want to downgrade BIOS image from " \ + current_bios_version + " to " + \ bios_image_version + " continue?" yes = click.confirm(prompt_text) else: print("BIOS is already with {} latest version".format( current_bios_version)) return True if yes: command = flashrom + " -p" + " internal" + " -w " + \ image_path self.run_command(command) elif component_name == self._component_name_list[1]: # CPLD1 return False elif component_name == self._component_name_list[2]: # CPLD2 return False elif component_name == self._component_name_list[3]: # SMF return False else: print "Invalid component Name:", component_name return True
class Chassis(ChassisBase): """Platform-specific Chassis class""" def __init__(self): super(Chassis, self).__init__() # Initialize SKU name self.sku_name = self._get_sku_name() # move the initialization of each components to their dedicated initializer # which will be called from platform self.sfp_module_initialized = False self.sfp_event_initialized = False self.reboot_cause_initialized = False logger.log_info("Chassis loaded successfully") def __del__(self): if self.sfp_event_initialized: self.sfp_event.deinitialize() def initialize_psu(self): from sonic_platform.psu import Psu # Initialize PSU list self.psu_module = Psu for index in range(MLNX_NUM_PSU): psu = Psu(index, self.sku_name) self._psu_list.append(psu) def initialize_fan(self): from sonic_platform.fan import Fan from sonic_platform.fan import FAN_PATH self.fan_module = Fan self.fan_path = FAN_PATH # Initialize FAN list multi_rotor_in_drawer = False num_of_fan, num_of_drawer = self._extract_num_of_fans_and_fan_drawers() multi_rotor_in_drawer = num_of_fan > num_of_drawer for index in range(num_of_fan): if multi_rotor_in_drawer: fan = Fan(index, index / 2) else: fan = Fan(index, index) self._fan_list.append(fan) def initialize_sfp(self): from sonic_platform.sfp import SFP self.sfp_module = SFP # Initialize SFP list port_position_tuple = self._get_port_position_tuple_by_sku_name() self.PORT_START = port_position_tuple[0] self.QSFP_PORT_START = port_position_tuple[1] self.PORT_END = port_position_tuple[2] self.PORTS_IN_BLOCK = port_position_tuple[3] for index in range(self.PORT_START, self.PORT_END + 1): if index in range(self.QSFP_PORT_START, self.PORTS_IN_BLOCK + 1): sfp_module = SFP(index, 'QSFP') else: sfp_module = SFP(index, 'SFP') self._sfp_list.append(sfp_module) self.sfp_module_initialized = True def initialize_thermals(self): from sonic_platform.thermal import initialize_thermals # Initialize thermals initialize_thermals(self.sku_name, self._thermal_list, self._psu_list) def initialize_eeprom(self): from eeprom import Eeprom # Initialize EEPROM self._eeprom = Eeprom() def initialize_components(self): # Initialize component list from sonic_platform.component import ComponentBIOS, ComponentCPLD self._component_list.append(ComponentBIOS()) self._component_list.append(ComponentCPLD()) ############################################## # SFP methods ############################################## def get_num_sfps(self): """ Retrieves the number of sfps available on this chassis Returns: An integer, the number of sfps available on this chassis """ if not self.sfp_module_initialized: self.initialize_sfp() return len(self._sfp_list) def get_all_sfps(self): """ Retrieves all sfps available on this chassis Returns: A list of objects derived from SfpBase representing all sfps available on this chassis """ if not self.sfp_module_initialized: self.initialize_sfp() return self._sfp_list def get_sfp(self, index): """ Retrieves sfp represented by (0-based) index <index> Args: index: An integer, the index (0-based) of the sfp to retrieve. The index should be the sequence of a physical port in a chassis, starting from 0. For example, 0 for Ethernet0, 1 for Ethernet4 and so on. Returns: An object dervied from SfpBase representing the specified sfp """ if not self.sfp_module_initialized: self.initialize_sfp() sfp = None try: sfp = self._sfp_list[index] except IndexError: sys.stderr.write("SFP index {} out of range (0-{})\n".format( index, len(self._sfp_list) - 1)) return sfp def _extract_num_of_fans_and_fan_drawers(self): num_of_fan = 0 num_of_drawer = 0 for f in listdir(self.fan_path): if isfile(join(self.fan_path, f)): match_obj = re.match('fan(\d+)_speed_get', f) if match_obj != None: if int(match_obj.group(1)) > num_of_fan: num_of_fan = int(match_obj.group(1)) else: match_obj = re.match('fan(\d+)_status', f) if match_obj != None and int( match_obj.group(1)) > num_of_drawer: num_of_drawer = int(match_obj.group(1)) return num_of_fan, num_of_drawer def _get_sku_name(self): p = subprocess.Popen(GET_HWSKU_CMD, shell=True, stdout=subprocess.PIPE) out, err = p.communicate() return out.rstrip('\n') def _get_port_position_tuple_by_sku_name(self): position_tuple = port_position_tuple_list[hwsku_dict_port[ self.sku_name]] return position_tuple def get_watchdog(self): """ Retrieves hardware watchdog device on this chassis Returns: An object derived from WatchdogBase representing the hardware watchdog device Note: We overload this method to ensure that watchdog is only initialized when it is referenced. Currently, only one daemon can open the watchdog. To initialize watchdog in the constructor causes multiple daemon try opening watchdog when loading and constructing a chassis object and fail. By doing so we can eliminate that risk. """ try: if self._watchdog is None: from sonic_platform.watchdog import get_watchdog self._watchdog = get_watchdog() except Exception as e: logger.log_info("Fail to load watchdog due to {}".format(repr(e))) return self._watchdog def get_base_mac(self): """ Retrieves the base MAC address for the chassis Returns: A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ return self._eeprom.get_base_mac() def get_serial_number(self): """ Retrieves the hardware serial number for the chassis Returns: A string containing the hardware serial number for this chassis. """ return self._eeprom.get_serial_number() def get_system_eeprom_info(self): """ Retrieves the full content of system EEPROM information for the chassis Returns: A dictionary where keys are the type code defined in OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ return self._eeprom.get_system_eeprom_info() def _read_generic_file(self, filename, len): """ Read a generic file, returns the contents of the file """ result = '' try: fileobj = io.open(filename) result = fileobj.read(len) fileobj.close() return result except Exception as e: logger.log_info("Fail to read file {} due to {}".format( filename, repr(e))) return '0' def _verify_reboot_cause(self, filename): ''' Open and read the reboot cause file in /var/run/hwmanagement/system (which is defined as REBOOT_CAUSE_ROOT) If a reboot cause file doesn't exists, returns '0'. ''' return bool( int( self._read_generic_file( join(REBOOT_CAUSE_ROOT, filename), REBOOT_CAUSE_FILE_LENGTH).rstrip('\n'))) def initialize_reboot_cause(self): self.reboot_major_cause_dict = { 'reset_main_pwr_fail': self.REBOOT_CAUSE_POWER_LOSS, 'reset_aux_pwr_or_ref': self.REBOOT_CAUSE_POWER_LOSS, 'reset_asic_thermal': self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC, 'reset_hotswap_or_wd': self.REBOOT_CAUSE_WATCHDOG, 'reset_swb_wd': self.REBOOT_CAUSE_WATCHDOG, 'reset_sff_wd': self.REBOOT_CAUSE_WATCHDOG } self.reboot_minor_cause_dict = { 'reset_fw_reset': "Reset by ASIC firmware", 'reset_long_pb': "Reset by long press on power button", 'reset_short_pb': "Reset by short press on power button", 'reset_comex_thermal': "ComEx thermal shutdown", 'reset_comex_pwr_fail': "ComEx power fail", 'reset_comex_wd': "Reset requested from ComEx", 'reset_from_asic': "Reset requested from ASIC", 'reset_reload_bios': "Reset caused by BIOS reload", 'reset_sw_reset': "Software reset", 'reset_hotswap_or_halt': "Reset caused by hotswap or halt", 'reset_from_comex': "Reset from ComEx", 'reset_voltmon_upgrade_fail': "Reset due to voltage monitor devices upgrade failure" } self.reboot_cause_initialized = True def get_reboot_cause(self): """ Retrieves the cause of the previous reboot Returns: A tuple (string, string) where the first element is a string containing the cause of the previous reboot. This string must be one of the predefined strings in this class. If the first string is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used to pass a description of the reboot cause. """ #read reboot causes files in the following order if not self.reboot_cause_initialized: self.initialize_reboot_cause() for reset_file, reset_cause in self.reboot_major_cause_dict.iteritems( ): if self._verify_reboot_cause(reset_file): return reset_cause, '' for reset_file, reset_cause in self.reboot_minor_cause_dict.iteritems( ): if self._verify_reboot_cause(reset_file): return self.REBOOT_CAUSE_HARDWARE_OTHER, reset_cause return self.REBOOT_CAUSE_NON_HARDWARE, '' def _show_capabilities(self): """ This function is for debug purpose Some features require a xSFP module to support some capabilities but it's unrealistic to check those modules one by one. So this function is introduce to show some capabilities of all xSFP modules mounted on the device. """ for s in self._sfp_list: try: print "index {} tx disable {} dom {} calibration {} temp {} volt {} power (tx {} rx {})".format( s.index, s.dom_tx_disable_supported, s.dom_supported, s.calibration, s.dom_temp_supported, s.dom_volt_supported, s.dom_rx_power_supported, s.dom_tx_power_supported) except: print "fail to retrieve capabilities for module index {}".format( s.index) def get_change_event(self, timeout=0): """ Returns a nested dictionary containing all devices which have experienced a change at chassis level Args: timeout: Timeout in milliseconds (optional). If timeout == 0, this method will block until a change is detected. Returns: (bool, dict): - True if call successful, False if not; - A nested dictionary where key is a device type, value is a dictionary with key:value pairs in the format of {'device_id':'device_event'}, where device_id is the device ID for this device and device_event, status='1' represents device inserted, status='0' represents device removed. Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}} indicates that fan 0 has been removed, fan 2 has been inserted and sfp 11 has been removed. """ # Initialize SFP event first if not self.sfp_event_initialized: from sonic_platform.sfp_event import sfp_event self.sfp_event = sfp_event() self.sfp_event.initialize() self.MAX_SELECT_EVENT_RETURNED = self.PORT_END self.sfp_event_initialized = True wait_for_ever = (timeout == 0) port_dict = {} if wait_for_ever: timeout = MAX_SELECT_DELAY while True: status = self.sfp_event.check_sfp_status(port_dict, timeout) if not port_dict == {}: break else: status = self.sfp_event.check_sfp_status(port_dict, timeout) if status: # get_change_event has the meaning of retrieving all the notifications through a single call. # Typically this is implemented via a select framework which requires the underlay file-reading # interface able to retrieve all notifications without blocking once the fd has been selected. # However, sdk doesn't provide any interface satisfied the requirement. as a result, # check_sfp_status returns only one notification may indicate more notifications in its queue. # In this sense, we have to iterate in a loop to get all the notifications in case that # the first call returns at least one. i = 0 while i < self.MAX_SELECT_EVENT_RETURNED: status = self.sfp_event.check_sfp_status(port_dict, 0) if not status: break i = i + 1 return True, {'sfp': port_dict} else: return True, {'sfp': {}}
class Chassis(ChassisBase): """ DELLEMC Platform-specific Chassis class """ HWMON_DIR = "/sys/devices/platform/SMF.512/hwmon/" HWMON_NODE = os.listdir(HWMON_DIR)[0] MAILBOX_DIR = HWMON_DIR + HWMON_NODE POLL_INTERVAL = 1 # Poll interval in seconds reset_reason_dict = {} reset_reason_dict[11] = ChassisBase.REBOOT_CAUSE_POWER_LOSS reset_reason_dict[33] = ChassisBase.REBOOT_CAUSE_WATCHDOG reset_reason_dict[44] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE reset_reason_dict[55] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE reset_reason_dict[66] = ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER reset_reason_dict[77] = ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER power_reason_dict = {} power_reason_dict[11] = ChassisBase.REBOOT_CAUSE_POWER_LOSS power_reason_dict[22] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU power_reason_dict[33] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC power_reason_dict[44] = ChassisBase.REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED def __init__(self): ChassisBase.__init__(self) # Initialize EEPROM self._eeprom = Eeprom() for i in range(MAX_S6100_MODULE): module = Module(i) self._module_list.append(module) self._sfp_list.extend(module._sfp_list) for i in range(MAX_S6100_FAN): fan = Fan(i) self._fan_list.append(fan) for i in range(MAX_S6100_PSU): psu = Psu(i) self._psu_list.append(psu) for i in range(MAX_S6100_THERMAL): thermal = Thermal(i) self._thermal_list.append(thermal) for i in range(MAX_S6100_COMPONENT): component = Component(i) self._component_list.append(component) self._watchdog = Watchdog() self._transceiver_presence = self._get_transceiver_presence() def _get_reboot_reason_smf_register(self): # In S6100, mb_poweron_reason register will # Returns 0xaa or 0xcc on software reload # Returns 0xff or 0xbb on power-cycle # Returns 0xdd on Watchdog # Returns 0xee on Thermal Shutdown # Returns 0x99 on Unknown reset smf_mb_reg_reason = self._get_pmc_register('mb_poweron_reason') return int(smf_mb_reg_reason, 16) def _get_pmc_register(self, reg_name): # On successful read, returns the value read from given # reg_name and on failure returns 'ERR' rv = 'ERR' mb_reg_file = self.MAILBOX_DIR + '/' + reg_name if (not os.path.isfile(mb_reg_file)): return rv try: with open(mb_reg_file, 'r') as fd: rv = fd.read() except Exception as error: rv = 'ERR' rv = rv.rstrip('\r\n') rv = rv.lstrip(" ") return rv def _get_register(self, reg_file): # On successful read, returns the value read from given # reg_name and on failure returns 'ERR' rv = 'ERR' if (not os.path.isfile(reg_file)): return rv try: with open(reg_file, 'r') as fd: rv = fd.read() except Exception as error: rv = 'ERR' rv = rv.rstrip('\r\n') rv = rv.lstrip(" ") return rv def get_name(self): """ Retrieves the name of the chassis Returns: string: The name of the chassis """ return self._eeprom.modelstr() def get_presence(self): """ Retrieves the presence of the chassis Returns: bool: True if chassis is present, False if not """ return True def get_model(self): """ Retrieves the model number (or part number) of the chassis Returns: string: Model/part number of chassis """ return self._eeprom.part_number_str() def get_serial(self): """ Retrieves the serial number of the chassis (Service tag) Returns: string: Serial number of chassis """ return self._eeprom.serial_str() def get_status(self): """ Retrieves the operational status of the chassis Returns: bool: A boolean value, True if chassis is operating properly False if not """ return True def get_base_mac(self): """ Retrieves the base MAC address for the chassis Returns: A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ return self._eeprom.base_mac_addr() def get_serial_number(self): """ Retrieves the hardware serial number for the chassis Returns: A string containing the hardware serial number for this chassis. """ return self._eeprom.serial_number_str() def get_system_eeprom_info(self): """ Retrieves the full content of system EEPROM information for the chassis Returns: A dictionary where keys are the type code defined in OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ return self._eeprom.system_eeprom_info() def get_reboot_cause(self): """ Retrieves the cause of the previous reboot Returns: A tuple (string, string) where the first element is a string containing the cause of the previous reboot. This string must be one of the predefined strings in this class. If the first string is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used to pass a description of the reboot cause. """ reset_reason = int(self._get_pmc_register('smf_reset_reason')) power_reason = int(self._get_pmc_register('smf_poweron_reason')) smf_mb_reg_reason = self._get_reboot_reason_smf_register() if ((smf_mb_reg_reason == 0xbb) or (smf_mb_reg_reason == 0xff)): return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None) elif ((smf_mb_reg_reason == 0xaa) or (smf_mb_reg_reason == 0xcc)): return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None) elif (smf_mb_reg_reason == 0xdd): return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None) elif (smf_mb_reg_reason == 0xee): return (self.power_reason_dict[power_reason], None) elif (reset_reason == 66): return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Emulated Cold Reset") elif (reset_reason == 77): return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Emulated Warm Reset") else: return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None) return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Invalid Reason") def _get_transceiver_presence(self): cpld2_modprs = self._get_register( "/sys/class/i2c-adapter/i2c-14/14-003e/qsfp_modprs") cpld3_modprs = self._get_register( "/sys/class/i2c-adapter/i2c-15/15-003e/qsfp_modprs") cpld4_modprs = self._get_register( "/sys/class/i2c-adapter/i2c-16/16-003e/qsfp_modprs") cpld5_modprs = self._get_register( "/sys/class/i2c-adapter/i2c-17/17-003e/qsfp_modprs") # If IOM is not present, register read will fail. # Handle the scenario gracefully if (cpld2_modprs == 'read error') or (cpld2_modprs == 'ERR'): cpld2_modprs = '0x0' if (cpld3_modprs == 'read error') or (cpld3_modprs == 'ERR'): cpld3_modprs = '0x0' if (cpld4_modprs == 'read error') or (cpld4_modprs == 'ERR'): cpld4_modprs = '0x0' if (cpld5_modprs == 'read error') or (cpld5_modprs == 'ERR'): cpld5_modprs = '0x0' # Make it contiguous transceiver_presence = (int(cpld2_modprs, 16) & 0xffff) |\ ((int(cpld4_modprs, 16) & 0xffff) << 16) |\ ((int(cpld3_modprs, 16) & 0xffff) << 32) |\ ((int(cpld5_modprs, 16) & 0xffff) << 48) return transceiver_presence def get_change_event(self, timeout=0): """ Returns a nested dictionary containing all devices which have experienced a change at chassis level Args: timeout: Timeout in milliseconds (optional). If timeout == 0, this method will block until a change is detected. Returns: (bool, dict): - True if call successful, False if not; - A nested dictionary where key is a device type, value is a dictionary with key:value pairs in the format of {'device_id':'device_event'}, where device_id is the device ID for this device and device_event, status='1' represents device inserted, status='0' represents device removed. Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}} indicates that fan 0 has been removed, fan 2 has been inserted and sfp 11 has been removed. """ port_dict = {} ret_dict = {'sfp': port_dict} forever = False if timeout == 0: forever = True elif timeout > 0: timeout = timeout / float(1000) # Convert to secs else: return False, ret_dict # Incorrect timeout while True: if forever: timer = self.POLL_INTERVAL else: timer = min(timeout, self.POLL_INTERVAL) start_time = time.time() time.sleep(timer) cur_presence = self._get_transceiver_presence() # Update dict only if a change has been detected if cur_presence != self._transceiver_presence: changed_ports = self._transceiver_presence ^ cur_presence for port in range(self.get_num_sfps()): # Mask off the bit corresponding to particular port mask = 1 << port if changed_ports & mask: # qsfp_modprs 1 => optics is removed if cur_presence & mask: port_dict[port] = '0' # qsfp_modprs 0 => optics is inserted else: port_dict[port] = '1' # Update current presence self._transceiver_presence = cur_presence break if not forever: elapsed_time = time.time() - start_time timeout = round(timeout - elapsed_time, 3) if timeout <= 0: break return True, ret_dict
class Chassis(ChassisBase): """ DELLEMC Platform-specific Chassis class """ HWMON_DIR = "/sys/devices/platform/SMF.512/hwmon/" HWMON_NODE = os.listdir(HWMON_DIR)[0] MAILBOX_DIR = HWMON_DIR + HWMON_NODE PORT_START = 0 PORT_END = 63 PORTS_IN_BLOCK = (PORT_END + 1) IOM1_PORT_START = 0 IOM2_PORT_START = 16 IOM3_PORT_START = 32 IOM4_PORT_START = 48 PORT_I2C_MAPPING = {} # 0th Index = i2cLine, 1st Index = EepromIdx in i2cLine EEPROM_I2C_MAPPING = { # IOM 1 0: [6, 66], 1: [6, 67], 2: [6, 68], 3: [6, 69], 4: [6, 70], 5: [6, 71], 6: [6, 72], 7: [6, 73], 8: [6, 74], 9: [6, 75], 10: [6, 76], 11: [6, 77], 12: [6, 78], 13: [6, 79], 14: [6, 80], 15: [6, 81], # IOM 2 16: [8, 50], 17: [8, 51], 18: [8, 52], 19: [8, 53], 20: [8, 54], 21: [8, 55], 22: [8, 56], 23: [8, 57], 24: [8, 58], 25: [8, 59], 26: [8, 60], 27: [8, 61], 28: [8, 62], 29: [8, 63], 30: [8, 64], 31: [8, 65], # IOM 3 32: [7, 34], 33: [7, 35], 34: [7, 36], 35: [7, 37], 36: [7, 38], 37: [7, 39], 38: [7, 40], 39: [7, 41], 40: [7, 42], 41: [7, 43], 42: [7, 44], 43: [7, 45], 44: [7, 46], 45: [7, 47], 46: [7, 48], 47: [7, 49], # IOM 4 48: [9, 18], 49: [9, 19], 50: [9, 20], 51: [9, 21], 52: [9, 22], 53: [9, 23], 54: [9, 24], 55: [9, 25], 56: [9, 26], 57: [9, 27], 58: [9, 28], 59: [9, 29], 60: [9, 30], 61: [9, 31], 62: [9, 32], 63: [9, 33] } reset_reason_dict = {} reset_reason_dict[11] = ChassisBase.REBOOT_CAUSE_POWER_LOSS reset_reason_dict[33] = ChassisBase.REBOOT_CAUSE_WATCHDOG reset_reason_dict[44] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE reset_reason_dict[55] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE power_reason_dict = {} power_reason_dict[11] = ChassisBase.REBOOT_CAUSE_POWER_LOSS power_reason_dict[22] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU power_reason_dict[33] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC power_reason_dict[44] = ChassisBase.REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED def __init__(self): ChassisBase.__init__(self) # Initialize EEPROM self.sys_eeprom = Eeprom() for i in range(MAX_S6100_FAN): fan = Fan(i) self._fan_list.append(fan) for i in range(MAX_S6100_PSU): psu = Psu(i) self._psu_list.append(psu) self._populate_port_i2c_mapping() # sfp.py will read eeprom contents and retrive the eeprom data. # It will also provide support sfp controls like reset and setting # low power mode. # We pass the eeprom path and sfp control path from chassis.py # So that sfp.py implementation can be generic to all platforms eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/i2c-{1}/{1}-0050/eeprom" sfp_ctrl_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-003e/" for index in range(0, self.PORTS_IN_BLOCK): eeprom_path = eeprom_base.format(self.EEPROM_I2C_MAPPING[index][0], self.EEPROM_I2C_MAPPING[index][1]) sfp_control = sfp_ctrl_base.format(self.PORT_I2C_MAPPING[index]) sfp_node = Sfp(index, 'QSFP', eeprom_path, sfp_control, index) self._sfp_list.append(sfp_node) def _populate_port_i2c_mapping(self): # port_num and i2c match for port_num in range(0, self.PORTS_IN_BLOCK): if ((port_num >= self.IOM1_PORT_START) and (port_num < self.IOM2_PORT_START)): i2c_line = 14 elif ((port_num >= self.IOM2_PORT_START) and (port_num < self.IOM3_PORT_START)): i2c_line = 16 elif ((port_num >= self.IOM3_PORT_START) and (port_num < self.IOM4_PORT_START)): i2c_line = 15 elif ((port_num >= self.IOM4_PORT_START) and (port_num < self.PORTS_IN_BLOCK)): i2c_line = 17 self.PORT_I2C_MAPPING[port_num] = i2c_line def _get_pmc_register(self, reg_name): # On successful read, returns the value read from given # reg_name and on failure returns 'ERR' rv = 'ERR' mb_reg_file = self.MAILBOX_DIR + '/' + reg_name if (not os.path.isfile(mb_reg_file)): return rv try: with open(mb_reg_file, 'r') as fd: rv = fd.read() except Exception as error: rv = 'ERR' rv = rv.rstrip('\r\n') rv = rv.lstrip(" ") return rv def get_name(self): """ Retrieves the name of the device Returns: string: The name of the device """ return self.sys_eeprom.modelstr() def get_presence(self): """ Retrieves the presence of the device Returns: bool: True if device is present, False if not """ return True def get_model(self): """ Retrieves the model number (or part number) of the device Returns: string: Model/part number of device """ return self.sys_eeprom.part_number_str() def get_serial(self): """ Retrieves the serial number of the device (Service tag) Returns: string: Serial number of device """ return self.sys_eeprom.serial_str() def get_base_mac(self): """ Retrieves the base MAC address for the chassis Returns: A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ return self.sys_eeprom.base_mac_addr() def get_serial_number(self): """ Retrieves the hardware serial number for the chassis Returns: A string containing the hardware serial number for this chassis. """ return self.sys_eeprom.serial_number_str() def get_system_eeprom_info(self): """ Retrieves the full content of system EEPROM information for the chassis Returns: A dictionary where keys are the type code defined in OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ def get_reboot_cause(self): """ Retrieves the cause of the previous reboot Returns: A tuple (string, string) where the first element is a string containing the cause of the previous reboot. This string must be one of the predefined strings in this class. If the first string is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used to pass a description of the reboot cause. """ reset_reason = int(self._get_pmc_register('smf_reset_reason')) power_reason = int(self._get_pmc_register('smf_poweron_reason')) # Reset_Reason = 11 ==> PowerLoss # So return the reboot reason from Last Power_Reason Dictionary # If Reset_Reason is not 11 return from Reset_Reason dictionary # Also check if power_reason, reset_reason are valid values by # checking key presence in dictionary else return # REBOOT_CAUSE_HARDWARE_OTHER as the Power_Reason and Reset_Reason # registers returned invalid data if (reset_reason == 11): if (power_reason in self.power_reason_dict): return (self.power_reason_dict[power_reason], None) else: if (reset_reason in self.reset_reason_dict): return (self.reset_reason_dict[reset_reason], None) return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Invalid Reason")
d = [] for d_ in data: d.append(d_[3]) d.append(d_[2]) d.append(d_[1]) d.append(d_[0]) return bytes(d) if __name__ == '__main__': data = big2little(patch_bin) code = vsdsp.Code.disassemble(data, 0) codes = vsdsp.Codes() codes.append(code) print(codes.text()) if len(sys.argv) == 2: eeprom = open(sys.argv[1], 'rb').read() eeprom = Eeprom.decode(eeprom) for blob in eeprom[0]: for idx in range(0, len(blob.data) - 3, 4): if blob.data[idx + 3] == 0x29: if len(blob.data) > len(data) + 8: blob.data = blob.data[:idx + 8] + data + blob.data[idx + 8 + len(data):] open(sys.argv[1] + '.patch_0000.bin', 'wb').write(eeprom.blob()) sys.exit(0) raise RuntimeError('szz')
class Chassis(ChassisBase): """ DELLEMC Platform-specific Chassis class """ HWMON_DIR = "/sys/devices/platform/SMF.512/hwmon/" HWMON_NODE = os.listdir(HWMON_DIR)[0] MAILBOX_DIR = HWMON_DIR + HWMON_NODE reset_reason_dict = {} reset_reason_dict[11] = ChassisBase.REBOOT_CAUSE_POWER_LOSS reset_reason_dict[33] = ChassisBase.REBOOT_CAUSE_WATCHDOG reset_reason_dict[44] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE reset_reason_dict[55] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE power_reason_dict = {} power_reason_dict[11] = ChassisBase.REBOOT_CAUSE_POWER_LOSS power_reason_dict[22] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU power_reason_dict[33] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC power_reason_dict[44] = ChassisBase.REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED def __init__(self): ChassisBase.__init__(self) # Initialize EEPROM self.sys_eeprom = Eeprom() for i in range(MAX_S6100_MODULE): module = Module(i) self._module_list.append(module) for i in range(MAX_S6100_FAN): fan = Fan(i) self._fan_list.append(fan) for i in range(MAX_S6100_PSU): psu = Psu(i) self._psu_list.append(psu) for i in range(MAX_S6100_THERMAL): thermal = Thermal(i) self._thermal_list.append(thermal) # Initialize component list self._component_name_list.append(COMPONENT_BIOS) self._component_name_list.append(SWITCH_CPLD) self._component_name_list.append(SMF_FPGA) def _get_reboot_reason_smf_register(self): # Returns 0xAA on software reload # Returns 0xFF on power-cycle # Returns 0x01 on first-boot smf_mb_reg_reason = self._get_pmc_register('mb_poweron_reason') return int(smf_mb_reg_reason, 16) def _get_pmc_register(self, reg_name): # On successful read, returns the value read from given # reg_name and on failure returns 'ERR' rv = 'ERR' mb_reg_file = self.MAILBOX_DIR + '/' + reg_name if (not os.path.isfile(mb_reg_file)): return rv try: with open(mb_reg_file, 'r') as fd: rv = fd.read() except Exception as error: rv = 'ERR' rv = rv.rstrip('\r\n') rv = rv.lstrip(" ") return rv # Run bash command and print output to stdout def run_command(self, command): click.echo(click.style("Command: ", fg='cyan') + click.style(command, fg='green')) proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) (out, err) = proc.communicate() click.echo(out) if proc.returncode != 0: sys.exit(proc.returncode) def get_name(self): """ Retrieves the name of the chassis Returns: string: The name of the chassis """ return self.sys_eeprom.modelstr() def get_presence(self): """ Retrieves the presence of the chassis Returns: bool: True if chassis is present, False if not """ return True def get_model(self): """ Retrieves the model number (or part number) of the chassis Returns: string: Model/part number of chassis """ return self.sys_eeprom.part_number_str() def get_serial(self): """ Retrieves the serial number of the chassis (Service tag) Returns: string: Serial number of chassis """ return self.sys_eeprom.serial_str() def get_status(self): """ Retrieves the operational status of the chassis Returns: bool: A boolean value, True if chassis is operating properly False if not """ return True def get_base_mac(self): """ Retrieves the base MAC address for the chassis Returns: A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ return self.sys_eeprom.base_mac_addr() def get_serial_number(self): """ Retrieves the hardware serial number for the chassis Returns: A string containing the hardware serial number for this chassis. """ return self.sys_eeprom.serial_number_str() def get_system_eeprom_info(self): """ Retrieves the full content of system EEPROM information for the chassis Returns: A dictionary where keys are the type code defined in OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ return self.sys_eeprom.system_eeprom_info() def get_reboot_cause(self): """ Retrieves the cause of the previous reboot Returns: A tuple (string, string) where the first element is a string containing the cause of the previous reboot. This string must be one of the predefined strings in this class. If the first string is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used to pass a description of the reboot cause. """ reset_reason = int(self._get_pmc_register('smf_reset_reason')) power_reason = int(self._get_pmc_register('smf_poweron_reason')) smf_mb_reg_reason = self._get_reboot_reason_smf_register() if ((smf_mb_reg_reason == 0x01) and (power_reason == 0x11)): return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None) # Reset_Reason = 11 ==> PowerLoss # So return the reboot reason from Last Power_Reason Dictionary # If Reset_Reason is not 11 return from Reset_Reason dictionary # Also check if power_reason, reset_reason are valid values by # checking key presence in dictionary else return # REBOOT_CAUSE_HARDWARE_OTHER as the Power_Reason and Reset_Reason # registers returned invalid data # In S6100, if Reset_Reason is not 11 and smf_mb_reg_reason # is ff or bb, then it is PowerLoss if (reset_reason == 11): if (power_reason in self.power_reason_dict): return (self.power_reason_dict[power_reason], None) else: if ((smf_mb_reg_reason == 0xbb) or (smf_mb_reg_reason == 0xff)): return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None) if (reset_reason in self.reset_reason_dict): return (self.reset_reason_dict[reset_reason], None) return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Invalid Reason") def _get_command_result(self, cmdline): try: proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE, shell=True, stderr=subprocess.STDOUT) stdout = proc.communicate()[0] proc.wait() result = stdout.rstrip('\n') except OSError: result = '' return result def _get_cpld_version(self): io_resource = "/dev/port" CPLD1_VERSION_ADDR = 0x100 fd = os.open(io_resource, os.O_RDONLY) if (fd < 0): return 'NA' if (os.lseek(fd, CPLD1_VERSION_ADDR, os.SEEK_SET) != CPLD1_VERSION_ADDR): return 'NA' buf = os.read(fd, 1) cpld_version = ord(buf) os.close(fd) return "%d.%d" % (((cpld_version & 0xF0) >> 4), cpld_version & 0xF) def _get_fpga_version(self): fpga_ver = float(self._get_pmc_register('smf_firmware_ver')) return fpga_ver def get_firmware_version(self, component_name): """ Retrieves platform-specific hardware/firmware versions for chassis componenets such as BIOS, CPLD, FPGA, etc. Args: component_name: A string, the component name. Returns: A string containing platform-specific component versions """ if component_name in self._component_name_list : if component_name == COMPONENT_BIOS: return self._get_command_result(BIOS_QUERY_VERSION_COMMAND) elif component_name == SWITCH_CPLD: return self._get_cpld_version() elif component_name == SMF_FPGA: return self._get_fpga_version() return None def install_component_firmware(self, component_name, image_path): bios_image = None bios_version = "3.25.0." bios_file_name = "S6100*BIOS*" flashrom = "/usr/local/bin/flashrom" PLATFORM_ROOT_PATH = '/usr/share/sonic/device' machine_info = sonic_device_util.get_machine_info() platform = sonic_device_util.get_platform_info(machine_info) platform_path = "/".join([PLATFORM_ROOT_PATH, platform, "bin"]) warning = """ ******************************************************************** * Warning - Upgrading BIOS is inherently risky and should only be * * attempted when necessary. A failure at this upgrade may cause * * a board RMA. Proceed with caution ! * ******************************************************************** """ if component_name in self._component_name_list: if component_name == COMPONENT_BIOS: # BIOS # current BIOS version current_bios_version = self.get_firmware_version("BIOS") # Construct BIOS image path if image_path is not None: image_path = image_path + platform_path for name in glob.glob( os.path.join(image_path, bios_file_name)): bios_image = image_path = name if not bios_image: print "BIOS image file not found:", image_path return False # Extract BIOS image version bios_image = os.path.basename(bios_image) bios_image = bios_image.strip('S6100-BIOS-') bios_image_version = bios_image.strip('.bin') if bios_image_version.startswith(bios_version): bios_image_minor = bios_image_version.replace( bios_image_version[:7], '') if bios_image_minor.startswith("2"): bios_image_minor = bios_image_minor.split("-")[1] if current_bios_version.startswith(bios_version): current_bios_minor = current_bios_version.replace( current_bios_version[:7], '') if current_bios_minor.startswith("2"): current_bios_minor = current_bios_minor.split("-")[1] # BIOS version check if bios_image_minor > current_bios_minor: print warning prompt_text = "New BIOS image " + bios_image_version + \ " available to install, continue?" yes = click.confirm(prompt_text) elif current_bios_minor > bios_image_minor: print warning prompt_text = "Do you want to downgrade BIOS image from " \ + current_bios_version + " to " + \ bios_image_version + " continue?" yes = click.confirm(prompt_text) else: print("BIOS is already with {} latest version".format( current_bios_version)) return True if yes: command = flashrom + " -p" + " internal" + " -w " + \ image_path self.run_command(command) elif component_name == SWITCH_CPLD: # CPLD return False elif component_name == SMF_FPGA: # SMF return False else: print "Invalid component Name:", component_name return True
def big2little(data): """Convert 4B ints from big to little endian (and vice versa).""" d = [] for d_ in data: d.append(d_[3]) d.append(d_[2]) d.append(d_[1]) d.append(d_[0]) return bytes(d) if __name__ == "__main__": data = big2little(patch_bin) code = vsdsp.Code.disassemble(data, 0) codes = vsdsp.Codes() codes.append(code) print(codes.text()) if len(sys.argv) == 2: eeprom = open(sys.argv[1], "rb").read() eeprom = Eeprom.decode(eeprom) for blob in eeprom[0]: for idx in range(0, len(blob.data) - 3, 4): if blob.data[idx + 3] == 0x29: if len(blob.data) > len(data) + 8: blob.data = blob.data[: idx + 8] + data + blob.data[idx + 8 + len(data) :] open(sys.argv[1] + ".patch_0000.bin", "wb").write(eeprom.blob()) sys.exit(0) raise RuntimeError("szz")
class Chassis(ChassisBase): """Platform-specific Chassis class""" def __init__(self): super(Chassis, self).__init__() # Initialize SKU name self.sku_name = self._get_sku_name() # Initialize PSU list for index in range(MLNX_NUM_PSU): psu = Psu(index, self.sku_name) self._psu_list.append(psu) # Initialize watchdog self._watchdog = get_watchdog() # Initialize FAN list multi_rotor_in_drawer = False num_of_fan, num_of_drawer = self._extract_num_of_fans_and_fan_drawers() multi_rotor_in_drawer = num_of_fan > num_of_drawer for index in range(num_of_fan): if multi_rotor_in_drawer: fan = Fan(index, index / 2) else: fan = Fan(index, index) self._fan_list.append(fan) # Initialize SFP list port_position_tuple = self._get_port_position_tuple_by_sku_name() self.PORT_START = port_position_tuple[0] self.QSFP_PORT_START = port_position_tuple[1] self.PORT_END = port_position_tuple[2] self.PORTS_IN_BLOCK = port_position_tuple[3] for index in range(self.PORT_START, self.PORT_END + 1): if index in range(self.QSFP_PORT_START, self.PORTS_IN_BLOCK + 1): sfp_module = SFP(index, 'QSFP') else: sfp_module = SFP(index, 'SFP') self._sfp_list.append(sfp_module) # Initialize thermals initialize_thermals(self.sku_name, self._thermal_list, self._psu_list) # Initialize EEPROM self.eeprom = Eeprom() # Initialize component list self._component_name_list.append(COMPONENT_BIOS) self._component_name_list.append(COMPONENT_FIRMWARE) self._component_name_list.append(COMPONENT_CPLD1) self._component_name_list.append(COMPONENT_CPLD2) def _extract_num_of_fans_and_fan_drawers(self): num_of_fan = 0 num_of_drawer = 0 for f in listdir(FAN_PATH): if isfile(join(FAN_PATH, f)): match_obj = re.match('fan(\d+)_speed_get', f) if match_obj != None: if int(match_obj.group(1)) > num_of_fan: num_of_fan = int(match_obj.group(1)) else: match_obj = re.match('fan(\d+)_status', f) if match_obj != None and int( match_obj.group(1)) > num_of_drawer: num_of_drawer = int(match_obj.group(1)) return num_of_fan, num_of_drawer def _get_sku_name(self): p = subprocess.Popen(GET_HWSKU_CMD, shell=True, stdout=subprocess.PIPE) out, err = p.communicate() return out.rstrip('\n') def _get_port_position_tuple_by_sku_name(self): position_tuple = port_position_tuple_list[hwsku_dict_port[ self.sku_name]] return position_tuple def get_base_mac(self): """ Retrieves the base MAC address for the chassis Returns: A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ return self.eeprom.get_base_mac() def get_serial_number(self): """ Retrieves the hardware serial number for the chassis Returns: A string containing the hardware serial number for this chassis. """ return self.eeprom.get_serial_number() def get_system_eeprom_info(self): """ Retrieves the full content of system EEPROM information for the chassis Returns: A dictionary where keys are the type code defined in OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ return self.eeprom.get_system_eeprom_info() def _read_generic_file(self, filename, len): """ Read a generic file, returns the contents of the file """ result = '' try: fileobj = io.open(filename) result = fileobj.read(len) fileobj.close() return result except Exception as e: logger.log_info("Fail to read file {} due to {}".format( filename, repr(e))) return '' def _verify_reboot_cause(self, filename): ''' Open and read the reboot cause file in /var/run/hwmanagement/system (which is defined as REBOOT_CAUSE_ROOT) If a reboot cause file doesn't exists, returns '0'. ''' return bool( int( self._read_generic_file( join(REBOOT_CAUSE_ROOT, filename), REBOOT_CAUSE_FILE_LENGTH).rstrip('\n'))) def get_reboot_cause(self): """ Retrieves the cause of the previous reboot Returns: A tuple (string, string) where the first element is a string containing the cause of the previous reboot. This string must be one of the predefined strings in this class. If the first string is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used to pass a description of the reboot cause. """ #read reboot causes files in the following order minor_cause = '' if self._verify_reboot_cause(REBOOT_CAUSE_POWER_LOSS_FILE): major_cause = self.REBOOT_CAUSE_POWER_LOSS elif self._verify_reboot_cause( REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC_FILE): major_cause = self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC elif self._verify_reboot_cause(REBOOT_CAUSE_WATCHDOG_FILE): major_cause = self.REBOOT_CAUSE_WATCHDOG else: major_cause = self.REBOOT_CAUSE_HARDWARE_OTHER if self._verify_reboot_cause(REBOOT_CAUSE_MLNX_FIRMWARE_RESET): minor_cause = "Reset by ASIC firmware" else: major_cause = self.REBOOT_CAUSE_NON_HARDWARE return major_cause, minor_cause def _get_cpld_version(self, version_file): cpld_version = self._read_generic_file( join(CPLD_VERSION_ROOT, version_file), CPLD_VERSION_MAX_LENGTH) return cpld_version.rstrip('\n') def _get_command_result(self, cmdline): try: proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE, shell=True, stderr=subprocess.STDOUT) stdout = proc.communicate()[0] proc.wait() result = stdout.rstrip('\n') except OSError, e: result = '' return result
class Chassis(ChassisBase): """ DELLEMC Platform-specific Chassis class """ HWMON_DIR = "/sys/devices/platform/SMF.512/hwmon/" HWMON_NODE = os.listdir(HWMON_DIR)[0] MAILBOX_DIR = HWMON_DIR + HWMON_NODE EEPROM_I2C_MAPPING = { 0: [9, 18], 1: [9, 19], 2: [9, 20], 3: [9, 21], 4: [9, 22], 5: [9, 23], 6: [9, 24], 7: [9, 25], 8: [8, 26], 9: [8, 27], 10: [8, 28], 11: [8, 29], 12: [8, 31], 13: [8, 30], 14: [8, 33], 15: [8, 32], # Remapped 4 entries 16: [7, 34], 17: [7, 35], 18: [7, 36], 19: [7, 37], 20: [7, 38], 21: [7, 39], 22: [7, 40], 23: [7, 41], 24: [6, 42], 25: [6, 43], 26: [6, 44], 27: [6, 45], 28: [6, 46], 29: [6, 47], 30: [6, 48], 31: [6, 49] } PORT_I2C_MAPPING = { # 0th Index = i2cLine, 1st Index = portIdx in i2cLine 0: [14, 0], 1: [14, 1], 2: [14, 2], 3: [14, 3], 4: [14, 4], 5: [14, 5], 6: [14, 6], 7: [14, 7], 8: [14, 8], 9: [14, 9], 10: [14, 10], 11: [14, 11], 12: [15, 0], 13: [15, 1], 14: [15, 2], 15: [15, 3], 16: [15, 4], 17: [15, 5], 18: [15, 6], 19: [15, 7], 20: [15, 8], 21: [15, 9], 22: [16, 0], 23: [16, 1], 24: [16, 2], 25: [16, 3], 26: [16, 4], 27: [16, 5], 28: [16, 6], 29: [16, 7], 30: [16, 8], 31: [16, 9] } reset_reason_dict = {} reset_reason_dict[11] = ChassisBase.REBOOT_CAUSE_POWER_LOSS reset_reason_dict[33] = ChassisBase.REBOOT_CAUSE_WATCHDOG reset_reason_dict[44] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE reset_reason_dict[55] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE power_reason_dict = {} power_reason_dict[11] = ChassisBase.REBOOT_CAUSE_POWER_LOSS power_reason_dict[22] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU power_reason_dict[33] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC power_reason_dict[44] = ChassisBase.REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED def __init__(self): PORT_START = 0 PORT_END = 31 PORTS_IN_BLOCK = (PORT_END + 1) # sfp.py will read eeprom contents and retrive the eeprom data. # It will also provide support sfp controls like reset and setting # low power mode. # We pass the eeprom path and sfp control path from chassis.py # So that sfp.py implementation can be generic to all platforms eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/i2c-{1}/{1}-0050/eeprom" sfp_ctrl_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-003e/" for index in range(0, PORTS_IN_BLOCK): eeprom_path = eeprom_base.format(self.EEPROM_I2C_MAPPING[index][0], self.EEPROM_I2C_MAPPING[index][1]) sfp_control = sfp_ctrl_base.format(self.PORT_I2C_MAPPING[index][0]) sfp_node = Sfp(index, 'QSFP', eeprom_path, sfp_control, self.PORT_I2C_MAPPING[index][1]) self._sfp_list.append(sfp_node) ChassisBase.__init__(self) # Initialize EEPROM self.sys_eeprom = Eeprom() for i in range(MAX_Z9100_FANTRAY): for j in range(MAX_Z9100_FAN): fan = Fan(i, j) self._fan_list.append(fan) # Initialize component list self._component_name_list.append(COMPONENT_BIOS) self._component_name_list.append(SWITCH_CPLD1) self._component_name_list.append(SWITCH_CPLD2) self._component_name_list.append(SWITCH_CPLD3) self._component_name_list.append(SWITCH_CPLD4) self._component_name_list.append(SMF_FPGA) def _get_pmc_register(self, reg_name): # On successful read, returns the value read from given # reg_name and on failure returns 'ERR' rv = 'ERR' mb_reg_file = self.MAILBOX_DIR + '/' + reg_name if (not os.path.isfile(mb_reg_file)): return rv try: with open(mb_reg_file, 'r') as fd: rv = fd.read() except Exception as error: rv = 'ERR' rv = rv.rstrip('\r\n') rv = rv.lstrip(" ") return rv def get_name(self): """ Retrieves the name of the chassis Returns: string: The name of the chassis """ return self.sys_eeprom.modelstr() def get_presence(self): """ Retrieves the presence of the chassis Returns: bool: True if chassis is present, False if not """ return True def get_model(self): """ Retrieves the model number (or part number) of the chassis Returns: string: Model/part number of chassis """ return self.sys_eeprom.part_number_str() def get_serial(self): """ Retrieves the serial number of the chassis (Service tag) Returns: string: Serial number of chassis """ return self.sys_eeprom.serial_str() def get_status(self): """ Retrieves the operational status of the chassis Returns: bool: A boolean value, True if chassis is operating properly False if not """ return True def get_base_mac(self): """ Retrieves the base MAC address for the chassis Returns: A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ return self.sys_eeprom.base_mac_addr() def get_serial_number(self): """ Retrieves the hardware serial number for the chassis Returns: A string containing the hardware serial number for this chassis. """ return self.sys_eeprom.serial_number_str() def get_reboot_cause(self): """ Retrieves the cause of the previous reboot Returns: A tuple (string, string) where the first element is a string containing the cause of the previous reboot. This string must be one of the predefined strings in this class. If the first string is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used to pass a description of the reboot cause. """ reset_reason = int(self._get_pmc_register('smf_reset_reason')) power_reason = int(self._get_pmc_register('smf_poweron_reason')) # Reset_Reason = 11 ==> PowerLoss # So return the reboot reason from Last Power_Reason Dictionary # If Reset_Reason is not 11 return from Reset_Reason dictionary # Also check if power_reason, reset_reason are valid values by # checking key presence in dictionary else return # REBOOT_CAUSE_HARDWARE_OTHER as the Power_Reason and Reset_Reason # registers returned invalid data if (reset_reason == 11): if (power_reason in self.power_reason_dict): return (self.power_reason_dict[power_reason], None) else: if (reset_reason in self.reset_reason_dict): return (self.reset_reason_dict[reset_reason], None) return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Invalid Reason") def _get_command_result(self, cmdline): try: proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE, shell=True, stderr=subprocess.STDOUT) stdout = proc.communicate()[0] proc.wait() result = stdout.rstrip('\n') except OSError: result = '' return result def _get_cpld_version(self, cpld_number): io_resource = "/dev/port" CPLD1_VERSION_ADDR = 0x100 if (cpld_number == 1): fd = os.open(io_resource, os.O_RDONLY) if (fd < 0): return 'NA' if (os.lseek(fd, CPLD1_VERSION_ADDR, os.SEEK_SET) != CPLD1_VERSION_ADDR): return 'NA' buf = os.read(fd, 1) cpld_version = ord(buf) os.close(fd) return "%d.%d" % (((cpld_version & 0xF0) >> 4), cpld_version & 0xF) else: cpld_version_file = ("/sys/class/i2c-adapter/i2c-{0}/{0}-003e" "/iom_cpld_vers").format(12 + cpld_number) if (not os.path.isfile(cpld_version_file)): return 'NA' try: with open(cpld_version_file, 'r') as fd: ver_str = fd.read() except Exception as error: return 'NA' if ver_str == "read error": return 'NA' else: ver_str = ver_str.rstrip("\r\n") cpld_version = int(ver_str.split(":")[1], 16) return "%d.%d" % (((cpld_version & 0xF0) >> 4), cpld_version & 0xF) def _get_fpga_version(self): fpga_ver = float(self._get_pmc_register('smf_firmware_ver')) return fpga_ver def get_firmware_version(self, component_name): """ Retrieves platform-specific hardware/firmware versions for chassis componenets such as BIOS, CPLD, FPGA, etc. Args: component_name: A string, the component name. Returns: A string containing platform-specific component versions """ if component_name in self._component_name_list: if component_name == COMPONENT_BIOS: return self._get_command_result(BIOS_QUERY_VERSION_COMMAND) elif component_name == SWITCH_CPLD1: return self._get_cpld_version(1) elif component_name == SWITCH_CPLD2: return self._get_cpld_version(2) elif component_name == SWITCH_CPLD3: return self._get_cpld_version(3) elif component_name == SWITCH_CPLD4: return self._get_cpld_version(4) elif component_name == SMF_FPGA: return self._get_fpga_version() return None
class Chassis(ChassisBase): """ Platform-specific Chassis class """ def __init__(self): ChassisBase.__init__(self) self._eeprom = Eeprom() for index in range(Sfp.port_start(), Sfp.port_end() + 1): sfp_node = Sfp(index) self._sfp_list.append(sfp_node) for i in range(1, Psu.get_num_psus() + 1): psu = Psu(i) self._psu_list.append(psu) def get_name(self): """ Retrieves the name of the chassis Returns: string: The name of the chassis """ return self._eeprom.modelstr() def get_presence(self): """ Retrieves the presence of the chassis Returns: bool: True if chassis is present, False if not """ return True def get_model(self): """ Retrieves the model number (or part number) of the chassis Returns: string: Model/part number of chassis """ return self._eeprom.part_number_str() def get_serial(self): """ Retrieves the serial number of the chassis (Service tag) Returns: string: Serial number of chassis """ return self._eeprom.serial_str() def get_sfp(self, index): """ Retrieves sfp represented by (1-based) index <index> Args: index: An integer, the index (1-based) of the sfp to retrieve. The index should be the sequence of a physical port in a chassis, starting from 1. For example, 0 for Ethernet0, 1 for Ethernet4 and so on. Returns: An object dervied from SfpBase representing the specified sfp """ sfp = None try: sfp = self._sfp_list[index - 1] except IndexError: sys.stderr.write("SFP index {} out of range (1-{})\n".format( index, len(self._sfp_list) - 1)) return sfp def get_status(self): """ Retrieves the operational status of the chassis Returns: bool: A boolean value, True if chassis is operating properly False if not """ return True def get_base_mac(self): """ Retrieves the base MAC address for the chassis Returns: A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ return self._eeprom.base_mac_addr() def get_system_eeprom_info(self): """ Retrieves the full content of system EEPROM information for the chassis Returns: A dictionary where keys are the type code defined in OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ return self._eeprom.system_eeprom_info() def get_change_event(self, timeout=0): ready, event_sfp = Sfp.get_transceiver_change_event(timeout) return ready, {'sfp': event_sfp} if ready else {}
class Chassis(ChassisBase): """ DELLEMC Platform-specific Chassis class """ HWMON_DIR = "/sys/devices/platform/SMF.512/hwmon/" HWMON_NODE = os.listdir(HWMON_DIR)[0] MAILBOX_DIR = HWMON_DIR + HWMON_NODE reset_reason_dict = {} reset_reason_dict[11] = ChassisBase.REBOOT_CAUSE_POWER_LOSS reset_reason_dict[33] = ChassisBase.REBOOT_CAUSE_WATCHDOG reset_reason_dict[44] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE reset_reason_dict[55] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE power_reason_dict = {} power_reason_dict[11] = ChassisBase.REBOOT_CAUSE_POWER_LOSS power_reason_dict[22] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU power_reason_dict[33] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC power_reason_dict[44] = ChassisBase.REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED def __init__(self): ChassisBase.__init__(self) # Initialize EEPROM self._eeprom = Eeprom() for i in range(MAX_S6100_MODULE): module = Module(i) self._module_list.append(module) self._sfp_list.extend(module._sfp_list) for i in range(MAX_S6100_FAN): fan = Fan(i) self._fan_list.append(fan) for i in range(MAX_S6100_PSU): psu = Psu(i) self._psu_list.append(psu) for i in range(MAX_S6100_THERMAL): thermal = Thermal(i) self._thermal_list.append(thermal) for i in range(MAX_S6100_COMPONENT): component = Component(i) self._component_list.append(component) def _get_reboot_reason_smf_register(self): # Returns 0xAA on software reload # Returns 0xFF on power-cycle # Returns 0x01 on first-boot smf_mb_reg_reason = self._get_pmc_register('mb_poweron_reason') return int(smf_mb_reg_reason, 16) def _get_pmc_register(self, reg_name): # On successful read, returns the value read from given # reg_name and on failure returns 'ERR' rv = 'ERR' mb_reg_file = self.MAILBOX_DIR + '/' + reg_name if (not os.path.isfile(mb_reg_file)): return rv try: with open(mb_reg_file, 'r') as fd: rv = fd.read() except Exception as error: rv = 'ERR' rv = rv.rstrip('\r\n') rv = rv.lstrip(" ") return rv def get_name(self): """ Retrieves the name of the chassis Returns: string: The name of the chassis """ return self._eeprom.modelstr() def get_presence(self): """ Retrieves the presence of the chassis Returns: bool: True if chassis is present, False if not """ return True def get_model(self): """ Retrieves the model number (or part number) of the chassis Returns: string: Model/part number of chassis """ return self._eeprom.part_number_str() def get_serial(self): """ Retrieves the serial number of the chassis (Service tag) Returns: string: Serial number of chassis """ return self._eeprom.serial_str() def get_status(self): """ Retrieves the operational status of the chassis Returns: bool: A boolean value, True if chassis is operating properly False if not """ return True def get_base_mac(self): """ Retrieves the base MAC address for the chassis Returns: A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ return self._eeprom.base_mac_addr() def get_serial_number(self): """ Retrieves the hardware serial number for the chassis Returns: A string containing the hardware serial number for this chassis. """ return self._eeprom.serial_number_str() def get_system_eeprom_info(self): """ Retrieves the full content of system EEPROM information for the chassis Returns: A dictionary where keys are the type code defined in OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ return self._eeprom.system_eeprom_info() def get_reboot_cause(self): """ Retrieves the cause of the previous reboot Returns: A tuple (string, string) where the first element is a string containing the cause of the previous reboot. This string must be one of the predefined strings in this class. If the first string is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used to pass a description of the reboot cause. """ reset_reason = int(self._get_pmc_register('smf_reset_reason')) power_reason = int(self._get_pmc_register('smf_poweron_reason')) smf_mb_reg_reason = self._get_reboot_reason_smf_register() if ((smf_mb_reg_reason == 0x01) and (power_reason == 0x11)): return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None) # Reset_Reason = 11 ==> PowerLoss # So return the reboot reason from Last Power_Reason Dictionary # If Reset_Reason is not 11 return from Reset_Reason dictionary # Also check if power_reason, reset_reason are valid values by # checking key presence in dictionary else return # REBOOT_CAUSE_HARDWARE_OTHER as the Power_Reason and Reset_Reason # registers returned invalid data # In S6100, if Reset_Reason is not 11 and smf_mb_reg_reason # is ff or bb, then it is PowerLoss if (reset_reason == 11): if (power_reason in self.power_reason_dict): return (self.power_reason_dict[power_reason], None) else: if ((smf_mb_reg_reason == 0xbb) or (smf_mb_reg_reason == 0xff)): return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None) if (reset_reason in self.reset_reason_dict): return (self.reset_reason_dict[reset_reason], None) return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Invalid Reason")
def initialize_eeprom(self): from eeprom import Eeprom # Initialize EEPROM self._eeprom = Eeprom()
class Chassis(ChassisBase): """ DELLEMC Platform-specific Chassis class """ HWMON_DIR = "/sys/devices/platform/SMF.512/hwmon/" HWMON_NODE = os.listdir(HWMON_DIR)[0] MAILBOX_DIR = HWMON_DIR + HWMON_NODE reset_reason_dict = {} reset_reason_dict[11] = ChassisBase.REBOOT_CAUSE_POWER_LOSS reset_reason_dict[33] = ChassisBase.REBOOT_CAUSE_WATCHDOG reset_reason_dict[44] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE reset_reason_dict[55] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE power_reason_dict = {} power_reason_dict[11] = ChassisBase.REBOOT_CAUSE_POWER_LOSS power_reason_dict[22] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU power_reason_dict[33] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC power_reason_dict[44] = ChassisBase.REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED def __init__(self): ChassisBase.__init__(self) # Initialize EEPROM self.sys_eeprom = Eeprom() for i in range(MAX_Z9100_FANTRAY): for j in range(MAX_Z9100_FAN): fan = Fan(i, j) self._fan_list.append(fan) def _get_pmc_register(self, reg_name): # On successful read, returns the value read from given # reg_name and on failure returns 'ERR' rv = 'ERR' mb_reg_file = self.MAILBOX_DIR + '/' + reg_name if (not os.path.isfile(mb_reg_file)): return rv try: with open(mb_reg_file, 'r') as fd: rv = fd.read() except Exception as error: rv = 'ERR' rv = rv.rstrip('\r\n') rv = rv.lstrip(" ") return rv def get_name(self): """ Retrieves the name of the device Returns: string: The name of the device """ return self.sys_eeprom.modelstr() def get_presence(self): """ Retrieves the presence of the device Returns: bool: True if device is present, False if not """ return True def get_model(self): """ Retrieves the model number (or part number) of the device Returns: string: Model/part number of device """ return self.sys_eeprom.part_number_str() def get_serial(self): """ Retrieves the serial number of the device (Service tag) Returns: string: Serial number of device """ return self.sys_eeprom.serial_str() def get_base_mac(self): """ Retrieves the base MAC address for the chassis Returns: A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ return self.sys_eeprom.base_mac_addr() def get_serial_number(self): """ Retrieves the hardware serial number for the chassis Returns: A string containing the hardware serial number for this chassis. """ return self.sys_eeprom.serial_number_str() def get_reboot_cause(self): """ Retrieves the cause of the previous reboot Returns: A tuple (string, string) where the first element is a string containing the cause of the previous reboot. This string must be one of the predefined strings in this class. If the first string is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used to pass a description of the reboot cause. """ reset_reason = int(self._get_pmc_register('smf_reset_reason')) power_reason = int(self._get_pmc_register('smf_poweron_reason')) # Reset_Reason = 11 ==> PowerLoss # So return the reboot reason from Last Power_Reason Dictionary # If Reset_Reason is not 11 return from Reset_Reason dictionary # Also check if power_reason, reset_reason are valid values by # checking key presence in dictionary else return # REBOOT_CAUSE_HARDWARE_OTHER as the Power_Reason and Reset_Reason # registers returned invalid data if (reset_reason == 11): if (power_reason in self.power_reason_dict): return (self.power_reason_dict[power_reason], None) else: if (reset_reason in self.reset_reason_dict): return (self.reset_reason_dict[reset_reason], None) return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Invalid Reason")