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] } OIR_FD_PATH = "/sys/devices/platform/dell_ich.0/sci_int_gpio_sus6" 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) self.oir_fd = -1 self.epoll = -1 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 __del__(self): if self.oir_fd != -1: self.epoll.unregister(self.oir_fd.fileno()) self.epoll.close() self.oir_fd.close() 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_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_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") def _check_interrupts(self, port_dict): is_port_dict_updated = False cpld2_abs_int = self._get_register( "/sys/class/i2c-adapter/i2c-14/14-003e/qsfp_abs_int") cpld2_abs_sta = self._get_register( "/sys/class/i2c-adapter/i2c-14/14-003e/qsfp_abs_sta") cpld3_abs_int = self._get_register( "/sys/class/i2c-adapter/i2c-15/15-003e/qsfp_abs_int") cpld3_abs_sta = self._get_register( "/sys/class/i2c-adapter/i2c-15/15-003e/qsfp_abs_sta") cpld4_abs_int = self._get_register( "/sys/class/i2c-adapter/i2c-16/16-003e/qsfp_abs_int") cpld4_abs_sta = self._get_register( "/sys/class/i2c-adapter/i2c-16/16-003e/qsfp_abs_sta") if (cpld2_abs_int == 'ERR' or cpld2_abs_sta == 'ERR' or cpld3_abs_int == 'ERR' or cpld3_abs_sta == 'ERR' or cpld4_abs_int == 'ERR' or cpld4_abs_sta == 'ERR'): return False, is_port_dict_updated cpld2_abs_int = int(cpld2_abs_int, 16) cpld2_abs_sta = int(cpld2_abs_sta, 16) cpld3_abs_int = int(cpld3_abs_int, 16) cpld3_abs_sta = int(cpld3_abs_sta, 16) cpld4_abs_int = int(cpld4_abs_int, 16) cpld4_abs_sta = int(cpld4_abs_sta, 16) # Make it contiguous (discard reserved bits) interrupt_reg = (cpld2_abs_int & 0xfff) |\ ((cpld3_abs_int & 0x3ff) << 12) |\ ((cpld4_abs_int & 0x3ff) << 22) status_reg = (cpld2_abs_sta & 0xfff) |\ ((cpld3_abs_sta & 0x3ff) << 12) |\ ((cpld4_abs_sta & 0x3ff) << 22) for port in range(self.get_num_sfps()): if interrupt_reg & (1 << port): # update only if atleast one port has generated # interrupt is_port_dict_updated = True if status_reg & (1 << port): # status reg 1 => optics is removed port_dict[port + 1] = '0' else: # status reg 0 => optics is inserted port_dict[port + 1] = '1' return True, is_port_dict_updated 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} if timeout != 0: timeout = timeout / 1000 try: # We get notified when there is an SCI interrupt from GPIO SUS6 # Open the sysfs file and register the epoll object self.oir_fd = open(self.OIR_FD_PATH, "r") if self.oir_fd != -1: # Do a dummy read before epoll register self.oir_fd.read() self.epoll = select.epoll() self.epoll.register(self.oir_fd.fileno(), select.EPOLLIN & select.EPOLLET) else: return False, ret_dict # Check for missed interrupts by invoking self.check_interrupts # which will update the port_dict. while True: interrupt_count_start = self._get_register(self.OIR_FD_PATH) retval, is_port_dict_updated = \ self._check_interrupts(port_dict) if (retval is True) and (is_port_dict_updated is True): return True, ret_dict interrupt_count_end = self._get_register(self.OIR_FD_PATH) if (interrupt_count_start == 'ERR' or interrupt_count_end == 'ERR'): break # check_interrupts() itself may take upto 100s of msecs. # We detect a missed interrupt based on the count if interrupt_count_start == interrupt_count_end: break # Block until an xcvr is inserted or removed with timeout = -1 events = self.epoll.poll(timeout=timeout if timeout != 0 else -1) if events: # check interrupts and return the port_dict retval, is_port_dict_updated = \ self._check_interrupts(port_dict) return retval, ret_dict except Exception: return False, ret_dict finally: if self.oir_fd != -1: self.epoll.unregister(self.oir_fd.fileno()) self.epoll.close() self.oir_fd.close() self.oir_fd = -1 self.epoll = -1
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): """ 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")
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): """ 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 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
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): """ 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")
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")