class Chassis(ChassisBase): """ DELLEMC Platform-specific Chassis class """ REBOOT_CAUSE_PATH = "/host/reboot-cause/platform/reboot_reason" OIR_FD_PATH = "/sys/bus/pci/devices/0000:03:00.0/port_msi" pci_res = "/sys/bus/pci/devices/0000:03:00.0/resource0" oir_fd = -1 epoll = -1 sysled_offset = 0x0024 SYSLED_COLOR_TO_REG = { "blinking_green": 0x0, "green" : 0x10, "amber" : 0x20, "blinking_amber": 0x30 } REG_TO_SYSLED_COLOR = { 0x0 : "blinking_green", 0x10 : "green", 0x20 : "amber", 0x30 : "blinking_amber" } _global_port_pres_dict = {} def __init__(self): ChassisBase.__init__(self) self.STATUS_LED_COLOR_BLUE_BLINK = "blinking blue" self.STATUS_LED_COLOR_OFF = "off" # sfp.py will read eeprom contents and retrive the eeprom data. # We pass the eeprom path from chassis.py self.PORT_START = 1 self.PORT_END = 15 PORTS_IN_BLOCK = (self.PORT_END + 1) _qsfp_port = range(13, self.PORT_END + 1) eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" for index in range(self.PORT_START, PORTS_IN_BLOCK): port_num = index + 1 eeprom_path = eeprom_base.format(port_num) if index in _qsfp_port: sfp_node = Sfp(index, 'QSFP', eeprom_path) else: sfp_node = Sfp(index, 'SFP', eeprom_path) self._sfp_list.append(sfp_node) self._eeprom = Eeprom() self._watchdog = Watchdog() self._num_sfps = self.PORT_END self._num_fans = MAX_S5212F_FAN * MAX_S5212F_FANTRAY for i in range(MAX_S5212F_THERMAL): thermal = Thermal(i) self._thermal_list.append(thermal) for i in range(MAX_S5212F_COMPONENT): component = Component(i) self._component_list.append(component) for i in range(MAX_S5212F_PSU): psu = Psu(i) self._psu_list.append(psu) for i in range(MAX_S5212F_FANTRAY): fandrawer = FanDrawer(i) self._fan_drawer_list.append(fandrawer) self._fan_list.extend(fandrawer._fan_list) for port_num in range(self.PORT_START, (self.PORT_END + 1)): # sfp get uses zero-indexing, but port numbers start from 1 presence = self.get_sfp(port_num-1).get_presence() if presence: self._global_port_pres_dict[port_num] = '1' else: self._global_port_pres_dict[port_num] = '0' self.LOCATOR_LED_ON = self.STATUS_LED_COLOR_BLUE_BLINK self.LOCATOR_LED_OFF = self.STATUS_LED_COLOR_OFF def __del__(self): if self.oir_fd != -1: self.epoll.unregister(self.oir_fd.fileno()) self.epoll.close() self.oir_fd.close() # not needed /delete after validation def _get_register(self, reg_file): retval = 'ERR' if (not os.path.isfile(reg_file)): print(reg_file, 'not found !') return retval try: with os.fdopen(os.open(reg_file, os.O_RDONLY)) as fd: retval = fd.read() except Exception: pass retval = retval.rstrip('\r\n') retval = retval.lstrip(" ") return retval # not needed /delete after validation def _check_interrupts(self, port_dict): retval = 0 is_port_dict_updated = False for port_num in range(self.PORT_START, (self.PORT_END + 1)): # sfp get uses zero-indexing, but port numbers start from 1 sfp = self.get_sfp(port_num-1) presence = sfp.get_presence() if(presence and (self._global_port_pres_dict[port_num] == '0')): is_port_dict_updated = True self._global_port_pres_dict[port_num] = '1' port_dict[port_num] = '1' elif(not presence and (self._global_port_pres_dict[port_num] == '1')): is_port_dict_updated = True self._global_port_pres_dict[port_num] = '0' port_dict[port_num] = '0' return retval, is_port_dict_updated # check for this event change for sfp / do we need to handle timeout/sleep def get_change_event(self, timeout=0): """ Returns a nested dictionary containing all devices which have experienced a change at chassis level """ start_ms = time.time() * 1000 port_dict = {} change_dict = {} change_dict['sfp'] = port_dict while True: time.sleep(0.5) for port_num in range(self.PORT_START, (self.PORT_END + 1)): presence = self.get_sfp(port_num-1).get_presence() if(presence and self._global_port_pres_dict[port_num] == '0'): self._global_port_pres_dict[port_num] = '1' port_dict[port_num] = '1' self.get_sfp(port_num-1)._initialize_media(delay=True) elif(not presence and self._global_port_pres_dict[port_num] == '1'): self._global_port_pres_dict[port_num] = '0' port_dict[port_num] = '0' if(len(port_dict) > 0): return True, change_dict if timeout: now_ms = time.time() * 1000 if (now_ms - start_ms >= timeout): return True, change_dict 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 """ sfp = None try: # The index will start from 0 sfp = self._sfp_list[index-1] except IndexError: sys.stderr.write("SFP index {} out of range (0-{})\n".format( index, len(self._sfp_list)-1)) return sfp 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_revision(self): """ Retrieves the revision number of the chassis (Service tag) Returns: string: Revision number of chassis """ return self._eeprom.revision_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_eeprom(self): """ Retrieves the Sys Eeprom instance for the chassis. Returns : The instance of the Sys Eeprom """ return self._eeprom def get_num_fans(self): """ Retrives the number of Fans on the chassis. Returns : An integer represents the number of Fans on the chassis. """ return self._num_fans def get_num_sfps(self): """ Retrives the numnber of Media on the chassis. Returns: An integer represences the number of SFPs on the chassis. """ return self._num_sfps def initizalize_system_led(self): self.sys_ledcolor = "green" 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. """ try: with open(self.REBOOT_CAUSE_PATH) as fd: reboot_cause = int(fd.read(), 16) except Exception: return (self.REBOOT_CAUSE_NON_HARDWARE, None) if reboot_cause & 0x1: return (self.REBOOT_CAUSE_POWER_LOSS, "Power on reset") elif reboot_cause & 0x2: return (self.REBOOT_CAUSE_NON_HARDWARE, None) elif reboot_cause & 0x4: return (self.REBOOT_CAUSE_HARDWARE_OTHER, "PSU Shutdown") elif reboot_cause & 0x8: return (self.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU, "Thermal overload") elif reboot_cause & 0x10: return (self.REBOOT_CAUSE_WATCHDOG, "Watchdog reset") elif reboot_cause & 0x20: return (self.REBOOT_CAUSE_HARDWARE_OTHER, "BMC Shutdown") elif reboot_cause & 0x40: return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Hot-Swap Shutdown") elif reboot_cause & 0x80: return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Reset Button Shutdown") elif reboot_cause & 0x100: return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Reset Button Cold Reboot") else: return (self.REBOOT_CAUSE_NON_HARDWARE, None) def get_qualified_media_list(self): return media_part_num_list def set_locator_led(self, color): """ Sets the state of the Chassis Locator LED Args: color: A string representing the color with which to set the Chassis Locator LED Returns: bool: True if the Chassis Locator LED state is set successfully, False if not """ resource = "/sys/bus/pci/devices/0000:04:00.0/resource0" val = pci_get_value(resource, SYSTEM_LED_REG) if self.LOCATOR_LED_ON == color: val = int(val) | SYSTEM_BEACON_LED_SET elif self.LOCATOR_LED_OFF == color: val = int(val) & SYSTEM_BEACON_LED_CLEAR else: return False pci_set_value(resource, val, SYSTEM_LED_REG) return True def get_locator_led(self): """ Gets the state of the Chassis Locator LED Returns: LOCATOR_LED_ON or LOCATOR_LED_OFF """ resource = "/sys/bus/pci/devices/0000:04:00.0/resource0" val = pci_get_value(resource, SYSTEM_LED_REG) val = int(val) & SYSTEM_BEACON_LED_SET if not val: return self.LOCATOR_LED_OFF else: return self.LOCATOR_LED_ON def get_position_in_parent(self): """ Retrieves 1-based relative physical position in parent device. 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 Chassis is replaceable. Returns: bool: True if it is replaceable. """ return False 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 """ if color not in list(self.SYSLED_COLOR_TO_REG.keys()): return False val = pci_get_value(self.pci_res, self.sysled_offset) val = (val & 0xFFCF) | self.SYSLED_COLOR_TO_REG[color] pci_set_value(self.pci_res, val, self.sysled_offset) self.sys_ledcolor = color return True 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. """ val = pci_get_value(self.pci_res, self.sysled_offset) if val != -1: val = val & 0x30 return self.REG_TO_SYSLED_COLOR.get(val) return self.sys_ledcolor
class Chassis(ChassisBase): """ DELLEMC Platform-specific Chassis class """ CPLD_DIR = '/sys/devices/platform/dell-n3248te-cpld.0/' _global_port_pres_dict = {} _sfpp_port_to_i2c_mapping = { 49: 20, 50: 21, 51: 22, 52: 23, 53: 24, 54: 25, } SYSTEM_LED_COLORS = { "green", "blink_green", "yellow", "blink_yellow" } def __init__(self): ChassisBase.__init__(self) # sfp.py will read eeprom contents and retrive the eeprom data. # We pass the eeprom path from chassis.py self.PORT_START = 1 self.PORT_END = 54 self.PORTS_IN_BLOCK = (self.PORT_END + 1) self.SFP_PORT_START = 49 self._sfp_port = range(self.SFP_PORT_START, self.PORTS_IN_BLOCK) eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" for index in range(self.PORT_START, self.PORTS_IN_BLOCK): eeprom_path = '' if index in self._sfp_port: eeprom_path = eeprom_base.format(self._sfpp_port_to_i2c_mapping[index]) if(index < 53): port_type = 'SFP' else: port_type = 'QSFP' sfp_node = Sfp(index, port_type, eeprom_path) self._sfp_list.append(sfp_node) self._eeprom = Eeprom() self._watchdog = Watchdog() self._num_sfps = 54 self._num_fans = MAX_N3248TE_FANTRAY * MAX_N3248TE_FAN for k in range(MAX_N3248TE_FANTRAY): fandrawer = FanDrawer(k) self._fan_drawer_list.append(fandrawer) self._fan_list.extend(fandrawer._fan_list) self._psu_list = [Psu(i) for i in range(MAX_N3248TE_PSU)] self._thermal_list = [Thermal(i) for i in range(MAX_N3248TE_THERMAL)] self._component_list = [Component(i) for i in range(MAX_N3248TE_COMPONENT)] for port_num in self._sfp_port: # sfp get uses zero-indexing, but port numbers start from 1 presence = self.get_sfp(port_num-1).get_presence() self._global_port_pres_dict[port_num] = '1' if presence else '0' self._watchdog = Watchdog() self.status_led_reg = "system_led" self.locator_led_reg = "locator_led" self.LOCATOR_LED_ON = "blink_blue" self.LOCATOR_LED_OFF = self.STATUS_LED_COLOR_OFF def _get_cpld_register(self, reg_name): # On successful read, returns the value read from given # reg name and on failure rethrns 'ERR' cpld_reg_file = self.CPLD_DIR + '/' + reg_name try: with open(cpld_reg_file, 'r') as fd: rv = fd.read() except IOError : return 'ERR' return rv.strip('\r\n').lstrip(' ') def _set_cpld_register(self, reg_name, value): # On successful write, returns the value will be written on # reg_name and on failure returns 'ERR' rv = 'ERR' cpld_reg_file = self.CPLD_DIR + '/' + reg_name if (not os.path.isfile(cpld_reg_file)): return rv try: with open(cpld_reg_file, 'w') as fd: rv = fd.write(str(value)) except Exception: rv = 'ERR' return rv def get_status_led(self): """ Gets the current system LED color Returns: A string that represents the supported color """ color = self._get_cpld_register(self.status_led_reg) if color not in list(self.SYSTEM_LED_COLORS): return self.sys_ledcolor return color def initizalize_system_led(self): self.sys_ledcolor = "green" def set_status_led(self,color): """ Set system LED status based on the color type passed in the argument. Argument: Color to be set Returns: bool: True is specified color is set, Otherwise return False """ if color not in list(self.SYSTEM_LED_COLORS): return False if(not self._set_cpld_register(self.status_led_reg, color)): return False self.sys_ledcolor = color return True # check for this event change for sfp / do we need to handle timeout/sleep def get_change_event(self, timeout=0): """ Returns a nested dictionary containing all devices which have experienced a change at chassis level """ port_dict = {} change_dict = {} change_dict['sfp'] = port_dict while True: for port_num in self._sfp_port: # sfp get uses zero-indexing, but port numbers start from 1 presence = self.get_sfp(port_num-1).get_presence() if(presence and self._global_port_pres_dict[port_num] == '0'): self._global_port_pres_dict[port_num] = '1' port_dict[port_num] = '1' elif(not presence and self._global_port_pres_dict[port_num] == '1'): self._global_port_pres_dict[port_num] = '0' port_dict[port_num] = '0' if(len(port_dict) > 0): return True, change_dict time.sleep(0.5) 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 """ sfp = None try: # The index will start from 0 sfp = self._sfp_list[index-1] except IndexError: sys.stderr.write("SFP index {} out of range (1-{})\n".format( index, len(self._sfp_list))) return sfp 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_cpld_register('reboot_cause'), 16) if (reset_reason & 0x02) : return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, 'Shutdown by CPU') elif (reset_reason & 0x04) : return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, "Failed to boot from configured boot device") elif (reset_reason & 0x8) : return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, "Booted from Backup BIOS") elif (reset_reason & 0x10) : return(ChassisBase.REBOOT_CAUSE_WATCHDOG, None) elif (reset_reason & 0x20): return(ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU) elif (reset_reason & 0x40) : return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, 'Warm Reset') elif (reset_reason & 0x80) : return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, 'Cold Reset') elif (reset_reason & 0x01) : return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None) def get_eeprom(self): """ Retrieves the Sys Eeprom instance for the chassis. Returns : The instance of the Sys Eeprom """ return self._eeprom def get_num_fans(self): """ Retrives the number of Fans on the chassis. Returns : An integer represents the number of Fans on the chassis. """ return self._num_fans def get_num_sfps(self): """ Retrives the numnber of Media on the chassis. Returns: An integer represences the number of SFPs on the chassis. """ return self._num_sfps def get_qualified_media_list(self): return media_part_num_list def set_locator_led(self, color): """ Sets the state of the Chassis Locator LED Args: color: A string representing the color with which to set the Chassis Locator LED Returns: bool: True if the Chassis Locator LED state is set successfully, False if not """ if color == self.LOCATOR_LED_ON or color == self.LOCATOR_LED_OFF: rv = self._set_cpld_register(self.locator_led_reg, color) if (rv != 'ERR'): return True else: return False def get_locator_led(self): """ Gets the state of the Chassis Locator LED Returns: LOCATOR_LED_ON or LOCATOR_LED_OFF """ loc_led = self._get_cpld_register(self.locator_led_reg) if (loc_led != 'ERR'): # Actually driver returns the color code 'blink_blue' # Returning "blue_blink" to make it common to all platforms output if (loc_led == self.LOCATOR_LED_ON): self.LOCATOR_LED_ON = self.STATUS_LED_COLOR_BLUE_BLINK return self.LOCATOR_LED_ON else: return self.LOCATOR_LED_OFF else: return self.LOCATOR_LED_OFF def get_position_in_parent(self): """ Retrieves 1-based relative physical position in parent device. 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 Chassis is replaceable. Returns: bool: True if it is replaceable. """ return False def get_revision(self): """ Retrives the hardware revision of the device Returns: string: Revision value of device """ return self._eeprom.revision_str()
class Chassis(ChassisBase): """ DELLEMC Platform-specific Chassis class """ REBOOT_CAUSE_PATH = "/host/reboot-cause/platform/reboot_reason" OIR_FD_PATH = "/sys/bus/pci/devices/0000:03:00.0/port_msi" oir_fd = -1 epoll = -1 _global_port_pres_dict = {} def __init__(self): ChassisBase.__init__(self) # sfp.py will read eeprom contents and retrive the eeprom data. # We pass the eeprom path from chassis.py self.PORT_START = 1 self.PORT_END = 15 PORTS_IN_BLOCK = (self.PORT_END + 1) _qsfp_port = range(13, self.PORT_END + 1) eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" for index in range(self.PORT_START, PORTS_IN_BLOCK): port_num = index + 1 eeprom_path = eeprom_base.format(port_num) if index in _qsfp_port: sfp_node = Sfp(index, 'QSFP', eeprom_path) else: sfp_node = Sfp(index, 'SFP', eeprom_path) self._sfp_list.append(sfp_node) self._eeprom = Eeprom() for i in range(MAX_S5212F_THERMAL): thermal = Thermal(i) self._thermal_list.append(thermal) for i in range(MAX_S5212F_COMPONENT): component = Component(i) self._component_list.append(component) for i in range(MAX_S5212F_PSU): psu = Psu(i) self._psu_list.append(psu) for i in range(MAX_S5212F_FANTRAY): for j in range(MAX_S5212F_FAN): fan = Fan(i, j) self._fan_list.append(fan) for i in range(MAX_S5212F_FANTRAY): fandrawer = FanDrawer(i) self._fan_drawer_list.append(fandrawer) self._fan_list.extend(fandrawer._fan_list) for port_num in range(self.PORT_START, (self.PORT_END + 1)): # sfp get uses zero-indexing, but port numbers start from 1 presence = self.get_sfp(port_num).get_presence() if presence: self._global_port_pres_dict[port_num] = '1' else: self._global_port_pres_dict[port_num] = '0' self._watchdog = Watchdog() def __del__(self): if self.oir_fd != -1: self.epoll.unregister(self.oir_fd.fileno()) self.epoll.close() self.oir_fd.close() # not needed /delete after validation def _get_register(self, reg_file): retval = 'ERR' if (not os.path.isfile(reg_file)): print(reg_file, 'not found !') return retval try: with os.fdopen(os.open(reg_file, os.O_RDONLY)) as fd: retval = fd.read() except Exception: pass retval = retval.rstrip('\r\n') retval = retval.lstrip(" ") return retval # not needed /delete after validation def _check_interrupts(self, port_dict): retval = 0 is_port_dict_updated = False for port_num in range(self.PORT_START, (self.PORT_END + 1)): # sfp get uses zero-indexing, but port numbers start from 1 sfp = self.get_sfp(port_num - 1) presence = sfp.get_presence() if (presence and (self._global_port_pres_dict[port_num] == '0')): is_port_dict_updated = True self._global_port_pres_dict[port_num] = '1' port_dict[port_num] = '1' elif (not presence and (self._global_port_pres_dict[port_num] == '1')): is_port_dict_updated = True self._global_port_pres_dict[port_num] = '0' port_dict[port_num] = '0' return retval, is_port_dict_updated # check for this event change for sfp / do we need to handle timeout/sleep def get_change_event(self, timeout=0): """ Returns a nested dictionary containing all devices which have experienced a change at chassis level """ start_ms = time.time() * 1000 port_dict = {} change_dict = {} change_dict['sfp'] = port_dict while True: time.sleep(0.5) for port_num in range(self.PORT_START, (self.PORT_END + 1)): presence = self.get_sfp(port_num - 1).get_presence() if (presence and self._global_port_pres_dict[port_num] == '0'): self._global_port_pres_dict[port_num] = '1' port_dict[port_num] = '1' self.get_sfp(port_num - 1)._initialize_media(delay=True) elif (not presence and self._global_port_pres_dict[port_num] == '1'): self._global_port_pres_dict[port_num] = '0' port_dict[port_num] = '0' if (len(port_dict) > 0): return True, change_dict if timeout: now_ms = time.time() * 1000 if (now_ms - start_ms >= timeout): return True, change_dict 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 """ sfp = None try: # The index will start from 0 sfp = self._sfp_list[index - 1] except IndexError: sys.stderr.write("SFP index {} out of range (0-{})\n".format( index, len(self._sfp_list) - 1)) return sfp 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_revision(self): """ Retrieves the revision number of the chassis (Service tag) Returns: string: Revision number of chassis """ return self._eeprom.revision_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. """ try: with open(self.REBOOT_CAUSE_PATH) as fd: reboot_cause = int(fd.read(), 16) except Exception: return (self.REBOOT_CAUSE_NON_HARDWARE, None) if reboot_cause & 0x1: return (self.REBOOT_CAUSE_POWER_LOSS, "Power on reset") elif reboot_cause & 0x2: return (self.REBOOT_CAUSE_NON_HARDWARE, None) elif reboot_cause & 0x4: return (self.REBOOT_CAUSE_HARDWARE_OTHER, "PSU Shutdown") elif reboot_cause & 0x8: return (self.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU, "Thermal overload") elif reboot_cause & 0x10: return (self.REBOOT_CAUSE_WATCHDOG, "Watchdog reset") elif reboot_cause & 0x20: return (self.REBOOT_CAUSE_HARDWARE_OTHER, "BMC Shutdown") elif reboot_cause & 0x40: return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Hot-Swap Shutdown") elif reboot_cause & 0x80: return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Reset Button Shutdown") elif reboot_cause & 0x100: return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Reset Button Cold Reboot") else: return (self.REBOOT_CAUSE_NON_HARDWARE, None) def get_qualified_media_list(self): return media_part_num_list
class Chassis(ChassisBase): """ DELLEMC Platform-specific Chassis class """ sysled_offset = 0x0024 SYSLED_COLOR_TO_REG = { "blinking_green": 0x0, "green": 0x10, "amber": 0x20, "blinking_amber": 0x30 } REG_TO_SYSLED_COLOR = { 0x0: "blinking_green", 0x10: "green", 0x20: "amber", 0x30: "blinking_amber" } _global_port_pres_dict = {} def __init__(self): ChassisBase.__init__(self) # sfp.py will read eeprom contents and retrive the eeprom data. # We pass the eeprom path from chassis.py _sfp_port = list(range(33, PORTS_IN_BLOCK)) i2c_bus_for_port = 2 i2c_mux_to_populate = 603 i2c_mux_address = 70 i2c_mux_is_good = False eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" mux_channel = "/sys/class/i2c-adapter/i2c-{0}/{0}-00{1}/channel-0" for index in range(PORT_START, PORTS_IN_BLOCK): eeprom_path = "" if index % 8 == 1: # 8 buses per i2c mux i2c_mux_is_good = True if os.path.exists( mux_channel.format(i2c_mux_to_populate, i2c_mux_address)) else False i2c_mux_to_populate += 1 i2c_mux_address += 1 if i2c_mux_is_good: eeprom_path = eeprom_base.format(i2c_bus_for_port) i2c_bus_for_port += 1 port_type = 'QSFP_DD' if index not in _sfp_port else 'SFP' sfp_node = Sfp(index, port_type, eeprom_path) self._sfp_list.append(sfp_node) self._eeprom = Eeprom() self._watchdog = Watchdog() self._num_sfps = PORT_END self._num_fans = MAX_Z9432F_FANTRAY * MAX_Z9432F_FAN for i in range(MAX_Z9432F_FANTRAY): fandrawer = FanDrawer(i) self._fan_drawer_list.append(fandrawer) self._fan_list.extend(fandrawer._fan_list) self._psu_list = [Psu(i) for i in range(MAX_Z9432F_PSU)] self._thermal_list = [Thermal(i) for i in range(MAX_Z9432F_THERMAL)] self._component_list = [ Component(i) for i in range(MAX_Z9432F_COMPONENT) ] for port_num in range(PORT_START, PORTS_IN_BLOCK): presence = self.get_sfp(port_num).get_presence() self._global_port_pres_dict[port_num] = '1' if presence else '0' self._watchdog = Watchdog() #self.LOCATOR_LED_ON = self.STATUS_LED_COLOR_BLUE_BLINK #self.LOCATOR_LED_OFF = self.STATUS_LED_COLOR_OFF #ext_media_override() # check for this event change for sfp / do we need to handle timeout/sleep def get_change_event(self, timeout=0): """ Returns a nested dictionary containing all devices which have experienced a change at chassis level """ start_ms = time.time() * 1000 port_dict = {} change_dict = {} change_dict['sfp'] = port_dict while True: time.sleep(0.5) for port_num in range(PORT_START, (PORT_END + 1)): presence = self.get_sfp(port_num).get_presence() if presence and self._global_port_pres_dict[port_num] == '0': self._global_port_pres_dict[port_num] = '1' port_dict[port_num] = '1' elif (not presence and self._global_port_pres_dict[port_num] == '1'): self._global_port_pres_dict[port_num] = '0' port_dict[port_num] = '0' if len(port_dict) > 0: return True, change_dict if timeout: now_ms = time.time() * 1000 if now_ms - start_ms >= timeout: return True, change_dict 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. """ val = hwaccess.pci_get_value(PCI_RES, self.sysled_offset) if val != -1: val = val & 0x30 return self.REG_TO_SYSLED_COLOR.get(val) return self.sys_ledcolor def initizalize_system_led(self): self.sys_ledcolor = "green" 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 """ if color not in list(self.SYSLED_COLOR_TO_REG.keys()): return False val = hwaccess.pci_get_value(PCI_RES, self.sysled_offset) val = (val & 0xFFCF) | self.SYSLED_COLOR_TO_REG[color] hwaccess.pci_set_value(PCI_RES, val, self.sysled_offset) self.sys_ledcolor = color return True 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 """ sfp = None try: # The 'index' is 1-based sfp = self._sfp_list[index - 1] except IndexError: sys.stderr.write("SFP index {} out of range (1-{})\n".format( index, len(self._sfp_list))) return sfp 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_revision(self): """ Retrieves the hardware revision of the device Returns: string: Revision value of device """ return self._eeprom.revision_str() def get_system_eeprom_info(self): """ 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_eeprom(self): """ Retrieves the Sys Eeprom instance for the chassis. Returns : The instance of the Sys Eeprom """ return self._eeprom def get_num_fans(self): """ Retrives the number of Fans on the chassis. Returns : An integer represents the number of Fans on the chassis. """ return self._num_fans def get_num_sfps(self): """ Retrives the numnber of Media on the chassis. Returns: An integer represences the number of SFPs on the chassis. """ return self._num_sfps 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. """ try: with open(REBOOT_CAUSE_PATH) as filed: reboot_cause = int(filed.read(), 16) except EnvironmentError: return (self.REBOOT_CAUSE_NON_HARDWARE, None) if reboot_cause & 0x1: retval = (self.REBOOT_CAUSE_POWER_LOSS, None) elif reboot_cause & 0x2: retval = (self.REBOOT_CAUSE_NON_HARDWARE, None) elif reboot_cause & 0x4: retval = (self.REBOOT_CAUSE_HARDWARE_OTHER, "PSU Shutdown") elif reboot_cause & 0x8: retval = (self.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU, None) elif reboot_cause & 0x10: retval = (self.REBOOT_CAUSE_WATCHDOG, None) elif reboot_cause & 0x20: retval = (self.REBOOT_CAUSE_HARDWARE_OTHER, "BMC Shutdown") elif reboot_cause & 0x40: retval = (self.REBOOT_CAUSE_HARDWARE_OTHER, "Hot-Swap Shutdown") elif reboot_cause & 0x80: retval = (self.REBOOT_CAUSE_HARDWARE_OTHER, "Reset Button Shutdown") elif reboot_cause & 0x100: retval = (self.REBOOT_CAUSE_HARDWARE_OTHER, "Reset Button Cold Reboot") else: retval = (self.REBOOT_CAUSE_NON_HARDWARE, None) return retval @staticmethod def get_qualified_media_list(): """ Returns Dell Qualified Media List """ return MEDIA_PART_NUM_LIST def set_locator_led(self, color): """ Sets the state of the Chassis Locator LED Args: color: A string representing the color with which to set the Chassis Locator LED Returns: bool: True if the Chassis Locator LED state is set successfully, False if not """ val = hwaccess.pci_get_value(PCI_RES, SYSTEM_LED_REG) if self.LOCATOR_LED_ON == color: val = int(val) | SYSTEM_BEACON_LED_SET elif self.LOCATOR_LED_OFF == color: val = int(val) & SYSTEM_BEACON_LED_CLEAR else: return False hwaccess.pci_set_value(PCI_RES, val, SYSTEM_LED_REG) return True def get_locator_led(self): """ Gets the state of the Chassis Locator LED Returns: LOCATOR_LED_ON or LOCATOR_LED_OFF """ val = hwaccess.pci_get_value(PCI_RES, SYSTEM_LED_REG) val = int(val) & SYSTEM_BEACON_LED_SET if not val: return self.LOCATOR_LED_OFF else: return self.LOCATOR_LED_ON def get_position_in_parent(self): """ Retrieves 1-based relative physical position in parent device. 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 Chassis is replaceable. Returns: bool: True if it is replaceable. """ return False
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 status_led_reg_to_color = { 0x00: 'green', 0x01: 'blinking green', 0x02: 'amber', 0x04: 'amber', 0x08: 'blinking amber', 0x10: 'blinking amber' } color_to_status_led_reg = { 'green': 0x00, 'blinking green': 0x01, 'amber': 0x02, 'blinking amber': 0x08 } def __init__(self): ChassisBase.__init__(self) self.status_led_reg = "sys_status_led" self.supported_led_color = [ 'green', 'blinking green', 'amber', 'blinking amber' ] # 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_FANTRAY): fandrawer = FanDrawer(i) self._fan_drawer_list.append(fandrawer) self._fan_list.extend(fandrawer._fan_list) 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) bios_ver = self.get_component(0).get_firmware_version() bios_minor_ver = bios_ver.split("-")[-1] if bios_minor_ver.isdigit() and (int(bios_minor_ver) >= 9): self._watchdog = WatchdogTCO() else: 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 0x88 on cold-reboot happened during 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 _set_pmc_register(self, reg_name, value): # On successful write, returns the length of value written on # 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, 'w') as fd: rv = fd.write(str(value)) except IOError: rv = 'ERR' 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_position_in_parent(self): """ Retrieves 1-based relative physical position in parent device. 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 Chassis is replaceable. Returns: bool: True if it is replaceable. """ return False 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_revision(self): """ Retrieves the hardware revision of the device Returns: string: Revision value of device """ return self._eeprom.revision_str() def get_system_eeprom_info(self): """ 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_module_index(self, module_name): """ Retrieves module index from the module name Args: module_name: A string, prefixed by SUPERVISOR, LINE-CARD or FABRIC-CARD Ex. SUPERVISOR0, LINE-CARD1, FABRIC-CARD5 Returns: An integer, the index of the ModuleBase object in the module_list """ module_index = re.match(r'IOM([1-4])', module_name).group(1) return int(module_index) - 1 def get_reboot_cause(self): """ 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 == 0x88): return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "CPU Reset") 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 def initizalize_system_led(self): return True 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 """ if color not in self.supported_led_color: return False value = self.color_to_status_led_reg[color] rv = self._set_pmc_register(self.status_led_reg, value) if (rv != 'ERR'): return True else: return False 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. """ reg_val = self._get_pmc_register(self.status_led_reg) if (reg_val != 'ERR'): return self.status_led_reg_to_color.get(int(reg_val, 16), None) else: return None
class Chassis(ChassisBase): """ DELLEMC Platform-specific Chassis class """ REBOOT_CAUSE_PATH = "/host/reboot-cause/platform/reboot_reason" oir_fd = -1 epoll = -1 io_res = "/dev/port" sysled_offset = 0xA162 SYSLED_COLOR_TO_REG = { "green": 0xd0, "yellow": 0xe0, "flash_green": 0xd2, "flash_yellow": 0xe2 } REG_TO_SYSLED_COLOR = { 0xd0: "green", 0xe0: "yellow", 0xd2: "flash_green", 0xd1: "flash_green", 0xe2: "flash_yellow", 0xe1: "flash_yellow" } _global_port_pres_dict = {} _port_to_i2c_mapping = { 1: 4, 2: 5, 3: 6, 4: 7, 5: 8, 6: 9, 7: 10, 8: 11, 9: 12, 10: 13, 11: 14, 12: 15, 13: 16, 14: 17, 15: 18, 16: 19, 17: 20, 18: 21, 19: 22, 20: 23, 21: 24, 22: 25, 23: 26, 24: 27, 25: 28, 26: 29, 27: 30, 28: 31, 29: 32, 30: 33, 31: 34, 32: 35, 33: 1, 34: 2, } reboot_reason_dict = { 0x11: (ChassisBase.REBOOT_CAUSE_POWER_LOSS, "Power on reset"), 0x22: (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Soft-set CPU warm reset"), 0x33: (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Soft-set CPU cold reset"), 0x66: (ChassisBase.REBOOT_CAUSE_WATCHDOG, "GPIO watchdog reset"), 0x77: (ChassisBase.REBOOT_CAUSE_POWER_LOSS, "Power cycle reset"), 0x88: (ChassisBase.REBOOT_CAUSE_WATCHDOG, "CPLD watchdog reset") } def __init__(self): ChassisBase.__init__(self) # sfp.py will read eeprom contents and retrive the eeprom data. # We pass the eeprom path from chassis.py self.PORT_START = 1 self.PORT_END = 34 self.PORTS_IN_BLOCK = (self.PORT_END + 1) _sfp_port = range(33, self.PORTS_IN_BLOCK) eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" for index in range(self.PORT_START, self.PORTS_IN_BLOCK): eeprom_path = eeprom_base.format(self._port_to_i2c_mapping[index]) port_type = 'SFP' if index in _sfp_port else 'QSFP_DD' sfp_node = Sfp(index, port_type, eeprom_path) self._sfp_list.append(sfp_node) self._eeprom = Eeprom() self._watchdog = Watchdog() for i in range(MAX_Z9332F_FANTRAY): fandrawer = FanDrawer(i) self._fan_drawer_list.append(fandrawer) self._fan_list.extend(fandrawer._fan_list) self._num_sfps = self.PORT_END self._num_fans = MAX_Z9332F_FANTRAY * MAX_Z9332F_FAN self._psu_list = [Psu(i) for i in range(MAX_Z9332F_PSU)] self._thermal_list = [Thermal(i) for i in range(MAX_Z9332F_THERMAL)] self._component_list = [ Component(i) for i in range(MAX_Z9332F_COMPONENT) ] for port_num in range(self.PORT_START, self.PORTS_IN_BLOCK): # sfp get uses zero-indexing, but port numbers start from 1 presence = self.get_sfp(port_num).get_presence() self._global_port_pres_dict[port_num] = '1' if presence else '0' self._watchdog = Watchdog() def __del__(self): if self.oir_fd != -1: self.epoll.unregister(self.oir_fd.fileno()) self.epoll.close() self.oir_fd.close() # check for this event change for sfp / do we need to handle timeout/sleep def get_change_event(self, timeout=0): """ Returns a nested dictionary containing all devices which have experienced a change at chassis level """ start_ms = time.time() * 1000 port_dict = {} change_dict = {} change_dict['sfp'] = port_dict while True: time.sleep(0.5) for port_num in range(self.PORT_START, (self.PORT_END + 1)): presence = self.get_sfp(port_num).get_presence() if (presence and self._global_port_pres_dict[port_num] == '0'): self._global_port_pres_dict[port_num] = '1' port_dict[port_num] = '1' elif (not presence and self._global_port_pres_dict[port_num] == '1'): self._global_port_pres_dict[port_num] = '0' port_dict[port_num] = '0' if (len(port_dict) > 0): return True, change_dict if timeout: now_ms = time.time() * 1000 if (now_ms - start_ms >= timeout): return True, change_dict 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 """ sfp = None try: # The index will start from 0 sfp = self._sfp_list[index - 1] except IndexError: sys.stderr.write("SFP index {} out of range (1-{})\n".format( index, len(self._sfp_list))) return sfp 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_revision(self): """ Retrieves the hardware revision of the device Returns: string: Revision value of device """ return self._eeprom.revision_str() def get_system_eeprom_info(self): """ 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_eeprom(self): """ Retrieves the Sys Eeprom instance for the chassis. Returns : The instance of the Sys Eeprom """ return self._eeprom def get_num_fans(self): """ Retrives the number of Fans on the chassis. Returns : An integer represents the number of Fans on the chassis. """ return self._num_fans def get_num_sfps(self): """ Retrives the numnber of Media on the chassis. Returns: An integer represences the number of SFPs on the chassis. """ return self._num_sfps 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. """ try: with open(self.REBOOT_CAUSE_PATH) as fd: reboot_cause = int(fd.read(), 16) except EnvironmentError: return (self.REBOOT_CAUSE_NON_HARDWARE, None) if reboot_cause in self.reboot_reason_dict.keys(): return self.reboot_reason_dict.get(reboot_cause) else: return (self.REBOOT_CAUSE_NON_HARDWARE, None) def get_qualified_media_list(self): return media_part_num_list def initizalize_system_led(self): self.sys_ledcolor = "green" def get_status_led(self): """ Gets the current system LED color Returns: A string that represents the supported color """ val = hwaccess.io_reg_read(self.io_res, self.sysled_offset) if val != -1: return self.REG_TO_SYSLED_COLOR.get(val) return self.sys_ledcolor def set_status_led(self, color): """ Set system LED status based on the color type passed in the argument. Argument: Color to be set Returns: bool: True is specified color is set, Otherwise return False """ if color not in list(self.SYSLED_COLOR_TO_REG.keys()): return False if (not hwaccess.io_reg_write(self.io_res, self.sysled_offset, self.SYSLED_COLOR_TO_REG[color])): return False self.sys_ledcolor = color return True def get_position_in_parent(self): """ Retrieves 1-based relative physical position in parent device. 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 Chassis is replaceable. Returns: bool: True if it is replaceable. """ return False