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 """ REBOOT_CAUSE_PATH = "/host/reboot-cause/platform/reboot_reason" OIR_FD_PATH = "/sys/bus/pci/devices/0000:04:00.0/port_msi" _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 = 28 self.SFP28_PORT_END = 24 PORTS_IN_BLOCK = (self.PORT_END + 1) _sfp_port = range(1, self.SFP28_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 not in _sfp_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_S5224F_FAN * MAX_S5224F_FANTRAY for i in range(MAX_S5224F_THERMAL): thermal = Thermal(i) self._thermal_list.append(thermal) for i in range(MAX_S5224F_COMPONENT): component = Component(i) self._component_list.append(component) for i in range(MAX_S5224F_PSU): psu = Psu(i) self._psu_list.append(psu) for i in range(MAX_S5224F_FANTRAY): for j in range(MAX_S5224F_FAN): fan = Fan(i,j) self._fan_list.append(fan) for i in range(MAX_S5224F_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' # 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 (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_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 & 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
class PddfChassis(ChassisBase): """ PDDF Generic Chassis class """ pddf_obj = {} plugin_data = {} def __init__(self, pddf_data=None, pddf_plugin_data=None): ChassisBase.__init__(self) self.pddf_obj = pddf_data if pddf_data else None self.plugin_data = pddf_plugin_data if pddf_plugin_data else None if not self.pddf_obj or not self.plugin_data: try: from . import pddfparse import json self.pddf_obj = pddfparse.PddfParse() with open( '/usr/share/sonic/platform/pddf/pd-plugin.json') as pd: self.plugin_data = json.load(pd) except Exception as e: raise Exception("Error: Unable to load PDDF JSON data - %s" % str(e)) self.platform_inventory = self.pddf_obj.get_platform() # Initialize EEPROM self.sys_eeprom = Eeprom(self.pddf_obj, self.plugin_data) # FANs for i in range(self.platform_inventory['num_fantrays']): for j in range(self.platform_inventory['num_fans_pertray']): fan = Fan(i, j, self.pddf_obj, self.plugin_data) self._fan_list.append(fan) # PSUs for i in range(self.platform_inventory['num_psus']): psu = Psu(i, self.pddf_obj, self.plugin_data) self._psu_list.append(psu) # OPTICs for index in range(self.platform_inventory['num_ports']): sfp = Sfp(index, self.pddf_obj, self.plugin_data) self._sfp_list.append(sfp) # THERMALs for i in range(self.platform_inventory['num_temps']): thermal = Thermal(i, self.pddf_obj, self.plugin_data) self._thermal_list.append(thermal) # SYSTEM LED Test Cases """ #comment out test cases sys_led_list= { "LOC":0, "DIAG":0, "FAN":0, "SYS":0, "PSU1":0, "PSU2":1 } for led in sys_led_list: color=self.get_system_led(led, sys_led_list[led]) print color self.set_system_led("LOC_LED","STATUS_LED_COLOR_GREEN") color=self.get_system_led("LOC_LED") print "Set Green: " + color self.set_system_led("LOC_LED", "STATUS_LED_COLOR_OFF") color=self.get_system_led("LOC_LED") print "Set off: " + color """ 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. """ raise NotImplementedError def get_component_name_list(self): """ Retrieves a list of the names of components available on the chassis (e.g., BIOS, CPLD, FPGA, etc.) Returns: A list containing the names of components available on the chassis """ return self._component_name_list 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 """ raise NotImplementedError def install_component_firmware(self, component_name, image_path): """ Install firmware to component Args: component_name: A string, the component name. image_path: A string, path to firmware image. Returns: A boolean, True if install was successful, False if not """ raise NotImplementedError ############################################## # Module methods ############################################## def get_num_modules(self): """ Retrieves the number of modules available on this chassis Returns: An integer, the number of modules available on this chassis """ return len(self._module_list) def get_all_modules(self): """ Retrieves all modules available on this chassis Returns: A list of objects derived from ModuleBase representing all modules available on this chassis """ return self._module_list def get_module(self, index): """ Retrieves module represented by (0-based) index <index> Args: index: An integer, the index (0-based) of the module to retrieve Returns: An object dervied from ModuleBase representing the specified module """ module = None try: module = self._module_list[index] except IndexError: sys.stderr.write("Module index {} out of range (0-{})\n".format( index, len(self._module_list) - 1)) return module ############################################## # Fan methods ############################################## def get_num_fans(self): """ Retrieves the number of fans available on this chassis Returns: An integer, the number of fan modules available on this chassis """ return len(self._fan_list) def get_all_fans(self): """ Retrieves all fan modules available on this chassis Returns: A list of objects derived from FanBase representing all fan modules available on this chassis """ return self._fan_list def get_fan(self, index): """ Retrieves fan module represented by (0-based) index <index> Args: index: An integer, the index (0-based) of the fan module to retrieve Returns: An object dervied from FanBase representing the specified fan module """ fan = None try: fan = self._fan_list[index] except IndexError: sys.stderr.write("Fan index {} out of range (0-{})\n".format( index, len(self._fan_list) - 1)) return fan ############################################## # PSU methods ############################################## def get_num_psus(self): """ Retrieves the number of power supply units available on this chassis Returns: An integer, the number of power supply units available on this chassis """ return len(self._psu_list) def get_all_psus(self): """ Retrieves all power supply units available on this chassis Returns: A list of objects derived from PsuBase representing all power supply units available on this chassis """ return self._psu_list def get_psu(self, index): """ Retrieves power supply unit represented by (0-based) index <index> Args: index: An integer, the index (0-based) of the power supply unit to retrieve Returns: An object dervied from PsuBase representing the specified power supply unit """ psu = None try: psu = self._psu_list[index] except IndexError: sys.stderr.write("PSU index {} out of range (0-{})\n".format( index, len(self._psu_list) - 1)) return psu ############################################## # THERMAL methods ############################################## def get_num_thermals(self): """ Retrieves the number of thermals available on this chassis Returns: An integer, the number of thermals available on this chassis """ return len(self._thermal_list) def get_all_thermals(self): """ Retrieves all thermals available on this chassis Returns: A list of objects derived from ThermalBase representing all thermals available on this chassis """ return self._thermal_list def get_thermal(self, index): """ Retrieves thermal unit represented by (0-based) index <index> Args: index: An integer, the index (0-based) of the thermal to retrieve Returns: An object dervied from ThermalBase representing the specified thermal """ thermal = None try: thermal = self._thermal_list[index] except IndexError: sys.stderr.write("THERMAL index {} out of range (0-{})\n".format( index, len(self._thermal_list) - 1)) return thermal ############################################## # SFP methods ############################################## def get_num_sfps(self): """ Retrieves the number of sfps available on this chassis Returns: An integer, the number of sfps available on this chassis """ return len(self._sfp_list) def get_all_sfps(self): """ Retrieves all sfps available on this chassis Returns: A list of objects derived from SfpBase representing all sfps available on this chassis """ return self._sfp_list def get_sfp(self, index): """ Retrieves sfp represented by (0-based) index <index> Args: index: An integer, the index (0-based) of the sfp to retrieve. The index should be the sequence of a physical port in a chassis, starting from 0. For example, 0 for Ethernet0, 1 for Ethernet4 and so on. Returns: An object dervied from SfpBase representing the specified sfp """ sfp = None try: sfp = self._sfp_list[index] except IndexError: sys.stderr.write("SFP index {} out of range (0-{})\n".format( index, len(self._sfp_list) - 1)) return sfp ############################################## # System LED methods ############################################## def set_system_led(self, led_device_name, color): result, msg = self.pddf_obj.is_supported_sysled_state( led_device_name, color) if result == False: print(msg) return (False) index = self.pddf_obj.data[led_device_name]['dev_attr']['index'] device_name = self.pddf_obj.data[led_device_name]['dev_info'][ 'device_name'] self.pddf_obj.create_attr('device_name', device_name, self.pddf_obj.get_led_path()) self.pddf_obj.create_attr('index', index, self.pddf_obj.get_led_path()) self.pddf_obj.create_attr('color', color, self.pddf_obj.get_led_cur_state_path()) self.pddf_obj.create_attr('dev_ops', 'set_status', self.pddf_obj.get_led_path()) return (True) def get_system_led(self, led_device_name): if led_device_name not in self.pddf_obj.data.keys(): status = "[FAILED] " + led_device_name + " is not configured" return (status) index = self.pddf_obj.data[led_device_name]['dev_attr']['index'] device_name = self.pddf_obj.data[led_device_name]['dev_info'][ 'device_name'] self.pddf_obj.create_attr('device_name', device_name, self.pddf_obj.get_led_path()) self.pddf_obj.create_attr('index', index, self.pddf_obj.get_led_path()) self.pddf_obj.create_attr('dev_ops', 'get_status', self.pddf_obj.get_led_path()) color = self.pddf_obj.get_led_color() return (color) ############################################## # Other methods ############################################## def get_watchdog(self): """ Retreives hardware watchdog device on this chassis Returns: An object derived from WatchdogBase representing the hardware watchdog device """ return self._watchdog def get_eeprom(self): """ Retreives eeprom device on this chassis Returns: An object derived from WatchdogBase representing the hardware eeprom device """ return self.sys_eeprom 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. """ raise NotImplementedError
class Chassis(ChassisBase): """Platform-specific Chassis class""" _global_port_pres_dict = {} def __init__(self): super(Chassis, self).__init__() # Initialize SKU name and Platform name self.sku_name = self._get_sku_name() self.platform_name = self._get_platform_name() self.name = self.sku_name # get the device infomation of platform self.platdev = PlatDev() #self._component_list = [] #self._module_list = [] #self._fan_drawer_list = [] self._eeprom = Eeprom() # init component for i in range(self.platdev.get_component_count()): component = Component(i, self.platdev.get_component_name(i), self.platdev.get_component_descript(i)) self._component_list.append(component) # init fan list if self.platdev.get_fan_support(): fanlist = self.platdev.get_fan_list() for index in range(0, len(fanlist)): fan_name = fanlist[index] for pos in range(0, self.platdev.get_fan_num_by_name(fan_name)): fan = Fan(index, pos, [ self.platdev.get_fan_sysfile_path_by_name(fan_name), '' ]) self._fan_list.append(fan) # init psu list psulist = self.platdev.get_psu_list() for index in range(0, len(psulist)): psu_name = psulist[index] psu = Psu(index, [ self.platdev.get_psu_attr_path_by_name(psu_name), self.platdev.get_psu_status_path_by_name(psu_name) ], self.platdev.bmc_is_exist()) self._psu_list.append(psu) # init thermal list thermal_info_list = self.platdev.get_thermal_dev_info_all() for index in range(0, len(thermal_info_list)): if len(self.platdev.get_thermal_dev_tempidx_by_idx(index)) > 1: for idx in self.platdev.get_thermal_dev_tempidx_by_idx(index): thermal = Thermal( idx, self.platdev.get_thermal_dev_name_by_idx(index) + "-{}".format(idx), self.platdev.get_thermal_dev_sysfile_path_by_idx( index), self.platdev.bmc_is_exist(), self.platdev.get_thermal_dev_support_mask_by_idx( index), self.platdev.get_thermal_dev_ext_sysfile_list_by_idx( index)) self._thermal_list.append(thermal) else: thermal = Thermal( 1, self.platdev.get_thermal_dev_name_by_idx(index), self.platdev.get_thermal_dev_sysfile_path_by_idx(index), self.platdev.bmc_is_exist(), self.platdev.get_thermal_dev_support_mask_by_idx(index), self.platdev.get_thermal_dev_ext_sysfile_list_by_idx( index)) self._thermal_list.append(thermal) # init sfp list port_num = 1 for sfpg_name in self.platdev.get_sfp_group_list(): if self.platdev.get_sfp_group_type_by_name(sfpg_name) == 'QSFP28': sfp_type = QSFP_TYPE else: sfp_type = SFP_TYPE for x in range( 0, self.platdev.get_sfp_group_number_by_name(sfpg_name)): eeprom_path_list = ['n/a', 'n/a'] if self.platdev.get_sfp_group_path_by_name( sfpg_name)[x] != 'n/a': eeprom_path_list[ 0] = self.platdev.get_sfp_group_path_by_name( sfpg_name)[x] + '/eeprom' if os.path.exists(eeprom_path_list[0].replace( "0050", "0051")): eeprom_path_list[1] = eeprom_path_list[0].replace( "0050", "0051") # index: port index, start from 0 # eeprom_path_list : a list of path to eeprom sysfile # [0]: for 0x50 # [1]: for 0x51 # ext_sysfile_list: used to get other function of sfp # [0]: present # [1]: reset # [2]: get lowpower mode # [3]: set lowpower mode sfp = Sfp(port_num, eeprom_path_list, sfp_type, self.platdev.get_sfp_ext_sysfile_list()) port_num += 1 self._sfp_list.append(sfp) self.init_global_port_presence() def _get_sku_name(self): pipe = subprocess.Popen(GET_HWSKU_CMD, shell=True, stdout=subprocess.PIPE) out, err = pipe.communicate() return out.decode().rstrip('\n') def _get_platform_name(self): pipe = subprocess.Popen(GET_PLATFORM_CMD, shell=True, stdout=subprocess.PIPE) out, err = pipe.communicate() return out.decode().rstrip('\n') def get_name(self): """ Retrieves the name of the device Returns: string: The name of the device """ return self.name 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_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_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. """ # not support any hardware reboot, just return REBOOT_CAUSE_NON_HARDWARE # to keep reboot cause as software reboot return (self.REBOOT_CAUSE_NON_HARDWARE, None) ############################################## # System LED methods ############################################## def set_status_led(self, color): """ Sets the state of the system LED Args: color: A string representing the color with which to set the system LED Returns: bool: True if system LED state is set successfully, False if not """ return False 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. """ raise NotImplementedError ############################################## # Other methods ############################################## def init_global_port_presence(self): for port_num in range(0, self.platdev.get_sfp_num()): presence = self._sfp_list[port_num].get_presence() self._global_port_pres_dict[port_num] = '1' if presence else '0' 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. Specifically for SFP event, besides SFP plug in and plug out, there are some other error event could be raised from SFP, when these error happened, SFP eeprom will not be avalaible, XCVRD shall stop to read eeprom before SFP recovered from error status. status='2' I2C bus stuck, status='3' Bad eeprom, status='4' Unsupported cable, status='5' High Temperature, status='6' Bad cable. """ port_dict = {} while True: for port_num in range(0, self.platdev.get_sfp_num()): presence = self._sfp_list[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, {'sfp': port_dict} time.sleep(1) def sfp_debugger(self): """ Try to show all parameters read from eeprom with sfp methods """ print("SFP EEPROM data:") for sfp_n in range(0, len(self._sfp_list)): print("======SFP{}==TYPE {}====".format( sfp_n, self._sfp_list[sfp_n].sfp_type)) print("get_transceiver_info:") print(self._sfp_list[sfp_n].get_transceiver_info()) print(" ") print("get_transceiver_threshold_info:") print(self._sfp_list[sfp_n].get_transceiver_threshold_info()) print(" ") print("get_transceiver_bulk_status:") print(self._sfp_list[sfp_n].get_transceiver_bulk_status()) print(" ") print("get_lpmode:") for sfp_n in range(0, len(self._sfp_list)): print("\tsfp{}: {}".format(sfp_n, self._sfp_list[sfp_n].get_lpmode())) # set_lpmode print("get_power_override:") for sfp_n in range(0, len(self._sfp_list)): print("\tsfp{}: {}".format( sfp_n, self._sfp_list[sfp_n].get_power_override())) print("get_temperature:") for sfp_n in range(0, len(self._sfp_list)): print("\tsfp{}: {}".format( sfp_n, self._sfp_list[sfp_n].get_temperature())) print("get_voltage") for sfp_n in range(0, len(self._sfp_list)): print("\tsfp{}: {}".format(sfp_n, self._sfp_list[sfp_n].get_voltage())) print("get_tx_bias") for sfp_n in range(0, len(self._sfp_list)): print("\tsfp{}: {}".format(sfp_n, self._sfp_list[sfp_n].get_tx_bias())) print("get_rx_power") for sfp_n in range(0, len(self._sfp_list)): print("\tsfp{}: {}".format(sfp_n, self._sfp_list[sfp_n].get_rx_power())) print("get_tx_power") for sfp_n in range(0, len(self._sfp_list)): print("\tsfp{}: {}".format(sfp_n, self._sfp_list[sfp_n].get_tx_power()))
class Chassis(ChassisBase): """ DELLEMC Platform-specific Chassis class """ 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 = 34 self.PORTS_IN_BLOCK = (self.PORT_END + 1) _sfp_port = list(range(33, self.PORT_END + 1)) eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" for index in range(self.PORT_START, self.PORTS_IN_BLOCK): port_num = index + 1 eeprom_path = eeprom_base.format(port_num) if index not in _sfp_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() for i in range(MAX_S5232F_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_S5232F_FANTRAY * MAX_S5232F_FAN self._psu_list = [Psu(i) for i in range(MAX_S5232F_PSU)] self._thermal_list = [Thermal(i) for i in range(MAX_S5232F_THERMAL)] self._component_list = [Component(i) for i in range(MAX_S5232F_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-1).get_presence() self._global_port_pres_dict[port_num] = '1' if presence else '0' 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): from time import sleep """ 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' 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] 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_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_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 & 0x1: return (self.REBOOT_CAUSE_POWER_LOSS, None) 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, None) elif reboot_cause & 0x10: return (self.REBOOT_CAUSE_WATCHDOG, None) 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)
class Chassis(ChassisBase): """ DELLEMC Platform-specific Chassis class """ CPLD_DIR = "/sys/devices/platform/dell-s6000-cpld.0" sfp_control = "" PORT_START = 0 PORT_END = 0 reset_reason_dict = {} reset_reason_dict[0xe] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE reset_reason_dict[0x6] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE def __init__(self): ChassisBase.__init__(self) # Initialize SFP list self.PORT_START = 0 self.PORT_END = 31 EEPROM_OFFSET = 20 PORTS_IN_BLOCK = (self.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}/{0}-0050/eeprom" self.sfp_control = "/sys/devices/platform/dell-s6000-cpld.0/" for index in range(0, PORTS_IN_BLOCK): eeprom_path = eeprom_base.format(index + EEPROM_OFFSET) sfp_node = Sfp(index, 'QSFP', eeprom_path, self.sfp_control, index) self._sfp_list.append(sfp_node) # Get Transceiver status self.modprs_register = self._get_transceiver_status() self._eeprom = Eeprom() for i in range(MAX_S6000_FAN): fan = Fan(i) self._fan_list.append(fan) for i in range(MAX_S6000_PSU): psu = Psu(i) self._psu_list.append(psu) for i in range(MAX_S6000_THERMAL): thermal = Thermal(i) self._thermal_list.append(thermal) for i in range(MAX_S6000_COMPONENT): component = Component(i) self._component_list.append(component) def _get_cpld_register(self, reg_name): rv = 'ERR' mb_reg_file = self.CPLD_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 """ # In S6000, We track the reboot reason by writing the reason in # NVRAM. Only Warmboot and Coldboot reason are supported here. # Since it does not support any hardware reason, we return # non_hardware as default lrr = self._get_cpld_register('last_reboot_reason') if (lrr != 'ERR'): reset_reason = int(lrr, base=16) if (reset_reason in self.reset_reason_dict): return (self.reset_reason_dict[reset_reason], None) return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None) def _get_transceiver_status(self): presence_ctrl = self.sfp_control + 'qsfp_modprs' try: reg_file = open(presence_ctrl) except IOError as e: return False content = reg_file.readline().rstrip() reg_file.close() return int(content, 16) def get_transceiver_change_event(self, timeout=0): """ Returns a dictionary containing sfp changes which have experienced a change at chassis level """ start_time = time.time() port_dict = {} port = self.PORT_START forever = False if timeout == 0: forever = True elif timeout > 0: timeout = timeout / float(1000) # Convert to secs else: return False, {} end_time = start_time + timeout if (start_time > end_time): return False, {} # Time wrap or possibly incorrect timeout while (timeout >= 0): # Check for OIR events and return updated port_dict reg_value = self._get_transceiver_status() if (reg_value != self.modprs_register): changed_ports = (self.modprs_register ^ reg_value) while (port >= self.PORT_START and port <= self.PORT_END): # Mask off the bit corresponding to our port mask = (1 << port) if (changed_ports & mask): # ModPrsL is active low if reg_value & mask == 0: port_dict[port] = '1' else: port_dict[port] = '0' port += 1 # Update reg value self.modprs_register = reg_value return True, port_dict if forever: time.sleep(1) else: timeout = end_time - time.time() if timeout >= 1: time.sleep(1) # We poll at 1 second granularity else: if timeout > 0: time.sleep(timeout) return True, {} return False, {}
class Chassis(ChassisBase): # System status LED _led = None def __init__(self): ChassisBase.__init__(self) self.data = {'valid': 0, 'last': 0} self.sfp_presence = {} if os.path.isdir(CONTAINER_PLATFORM_PATH): platform_path = CONTAINER_PLATFORM_PATH else: platform = device_info.get_platform() if platform is None: raise platform_path = os.path.join(HOST_DEVICE_PATH, platform) port_config_file = "/".join( [platform_path, "V682-48y8c", "port_config.ini"]) try: f = open(port_config_file) except: raise for line in f: line.strip() if re.search('^#', line) is not None: Port_cfg = collections.namedtuple('Port_cfg', line.split()[1:]) break f.close() f = open(port_config_file) _port_cfgs = [ Port_cfg(*tuple((line.strip().split()))) for line in f if re.search('^#', line) is None ] f.close() # Initialize EEPROM self._eeprom = Eeprom() # Initialize FAN for i in range(NUM_FAN_TRAY): fandrawer = FanDrawer(i + 1) self._fan_drawer_list.append(fandrawer) self._fan_list.extend(fandrawer._fan_list) # Initialize PSU for index in range(0, NUM_PSU): psu = Psu(index + 1) self._psu_list.append(psu) # Initialize THERMAL for index in range(0, NUM_THERMAL): thermal = Thermal(index) self._thermal_list.append(thermal) # Initialize SFP for port_cfg in _port_cfgs: sfp = Sfp(int(port_cfg.index), 'SFP' if int(port_cfg.index) < 48 else 'QSFP') self._sfp_list.append(sfp) self.sfp_presence[int(port_cfg.index)] = False ############################################## # Device methods ############################################## 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 Returns: string: Serial number of chassis """ return self._eeprom.serial_number_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 ############################################## # Chassis methods ############################################## 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. Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} """ 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. """ if os.path.exists(REBOOT_CAUSE_FILE): with open(REBOOT_CAUSE_FILE) as reboot_cause_file: reboot_cause = reboot_cause_file.readline() if re.search(r'User issued', reboot_cause) is None: return (self.REBOOT_CAUSE_POWER_LOSS, None) else: return (self.REBOOT_CAUSE_NON_HARDWARE, None) else: return (self.REBOOT_CAUSE_POWER_LOSS, None) def get_change_event(self, timeout=2000): """ 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. """ SFP_STATUS_INSERTED = '1' SFP_STATUS_REMOVED = '0' now = time.time() port_dict = {} if timeout < 1000: timeout = 1000 timeout = (timeout) / float(1000) # Convert to secs if now < (self.data['last'] + timeout) and self.data['valid']: return False, {'sfp': {}} for sfp in self._sfp_list: sfp_presence = sfp.get_presence() if sfp_presence != self.sfp_presence[sfp.index]: self.sfp_presence[sfp.index] = sfp_presence if sfp_presence: port_dict[sfp.index] = SFP_STATUS_INSERTED else: port_dict[sfp.index] = SFP_STATUS_REMOVED if bool(port_dict): self.data['last'] = now self.data['valid'] = 1 ret = True else: time.sleep(0.5) ret = False ret_dict = {'sfp': port_dict} return ret, ret_dict def get_num_psus(self): return len(self._psu_list) def get_psu(self, psu_index): return self._psu_list[psu_index] def initizalize_system_led(self): from .led import SystemLed Chassis._led = SystemLed() def set_status_led(self, color): """ Sets the state of the system LED Args: color: A string representing the color with which to set the system LED Returns: bool: True if system LED state is set successfully, False if not """ return False if not Chassis._led else Chassis._led.set_status(color) def get_status_led(self): """ Gets the state of the system LED Returns: A string, one of the valid LED color strings which could be vendor specified. """ return None if not Chassis._led else Chassis._led.get_status()
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): def __init__(self): ChassisBase.__init__(self) self.__num_of_psus = 2 self.__num_of_ports = 32 self.__num_of_sfps = 0 self.__num_of_fans = 5 self.__num_of_thermals = 6 # Initialize EEPROM self._eeprom = Eeprom() # Initialize watchdog #self._watchdog = Watchdog() # Initialize FAN for index in range(1, self.__num_of_fans + 1): fan = Fan(index) self._fan_list.append(fan) # Initialize thermal for index in range(1, self.__num_of_thermals + 1): thermal = Thermal(index) self._thermal_list.append(thermal) # Initialize PSU and PSU_FAN for index in range(1, self.__num_of_psus + 1): psu = Psu(index) self._psu_list.append(psu) fan = Fan(index, True) self._fan_list.append(fan) # Initialize SFP for index in range(0, self.__num_of_ports): if index in range(0, self.__num_of_sfps): sfp = Sfp(index, 'SFP') else: sfp = Sfp(index, 'QSFP') self._sfp_list.append(sfp) # Initialize TRANSCEIVER EVENT self.__xcvr_event = TransceiverEvent() ############################################## # Device methods ############################################## 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 Returns: string: Serial number of chassis """ return self._eeprom.serial_number_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 ############################################## # Chassis methods ############################################## 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. Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} """ 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. """ raise NotImplementedError ############################################## # Other methods ############################################## 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. """ rc, xcvr_event = self.__xcvr_event.get_transceiver_change_event( timeout) return rc, {'sfp': xcvr_event}
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_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): def __init__(self): ChassisBase.__init__(self) # Initialize EEPROM self._eeprom = Eeprom() # Initialize FAN for i in range(NUM_FAN_TRAY): fandrawer = FanDrawer(i) self._fan_drawer_list.append(fandrawer) self._fan_list.extend(fandrawer._fan_list) # Initialize THERMAL for index in range(0, NUM_THERMAL): thermal = Thermal(index) self._thermal_list.append(thermal) # Initialize SFP for index in range(0, NUM_PORT): sfp = Sfp(index) self._sfp_list.append(sfp) # Initialize PSU for index in range(0, NUM_PSU): psu = Psu(index + 1) self._psu_list.append(psu) ############################################## # Device methods ############################################## 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 Returns: string: Serial number of chassis """ return self._eeprom.serial_number_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 ############################################## # Chassis methods ############################################## 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. Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} """ 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. """ return (None, None) def get_change_event(self, timeout=2000): """ 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. """ ret, port_dict = self._sfp_list[0].get_transceiver_change_event(timeout) ret_dict = {"sfp": port_dict} return ret, ret_dict def get_num_psus(self): return len(self._psu_list) def get_psu(self, psu_index): return self._psu_list[psu_index]
class Chassis(ChassisBase): """ DELLEMC Platform-specific Chassis class """ 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 = 34 self.PORTS_IN_BLOCK = (self.PORT_END + 1) _sfp_port = range(33, self.PORT_END + 1) eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" for index in range(self.PORT_START, self.PORTS_IN_BLOCK): port_num = index + 1 eeprom_path = eeprom_base.format(port_num) if index not in _sfp_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_S5232F_FANTRAY * MAX_S5232F_FAN self._fan_list = [Fan(i, j) for i in range(MAX_S5232F_FANTRAY) \ for j in range(MAX_S5232F_FAN)] self._psu_list = [Psu(i) for i in range(MAX_S5232F_PSU)] self._thermal_list = [Thermal(i) for i in range(MAX_S5232F_THERMAL)] self._component_list = [Component(i) for i in range(MAX_S5232F_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' 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): from time import sleep """ Returns a nested dictionary containing all devices which have experienced a change at chassis level """ port_dict = {} change_dict = {} change_dict['sfp'] = port_dict elapsed_time_ms = 0 sleep_time_ms = 500 sleep_time = sleep_time_ms / 1000 while True: 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 != 0: elapsed_time_ms += sleep_time_ms if elapsed_time_ms > timeout: break sleep(sleep_time) 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_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
class Chassis(ChassisBase): """ DELLEMC Platform-specific Chassis class """ REBOOT_CAUSE_PATH = "/host/reboot-cause/platform/reboot_reason" oir_fd = -1 epoll = -1 _global_port_pres_dict = {} _port_to_i2c_mapping = { 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 30: 31, 31: 32, 32: 33, 33: 34, 34: 35, 35: 36, 36: 37, 37: 38, 38: 39, 39: 40, 40: 41, 41: 42, 42: 43, 43: 44, 44: 45, 45: 46, 46: 47, 47: 48, 48: 49, # DD + QSFP28 49: 50, 50: 50, 51: 51, 52: 51, 53: 52, 54: 53, 55: 54, 56: 55, } 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 = 56 self.PORTS_IN_BLOCK = (self.PORT_END + 1) _sfp_port = range(49, 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 = 'QSFP' if index 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 = self.PORT_END self._num_fans = MAX_S5248F_FANTRAY * MAX_S5248F_FAN self._fan_list = [Fan(i, j) for i in range(MAX_S5248F_FANTRAY) \ for j in range(MAX_S5248F_FAN)] for i in range(MAX_S5248F_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_S5248F_PSU)] self._thermal_list = [Thermal(i) for i in range(MAX_S5248F_THERMAL)] self._component_list = [ Component(i) for i in range(MAX_S5248F_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 - 1).get_presence() self._global_port_pres_dict[port_num] = '1' if presence else '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() # 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' 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 Ethernet1 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_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 & 0x1: return (self.REBOOT_CAUSE_POWER_LOSS, None) 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, None) elif reboot_cause & 0x10: return (self.REBOOT_CAUSE_WATCHDOG, None) 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
class Chassis(ChassisBase): """ DELLEMC Platform-specific Chassis class """ OIR_FD_PATH = "/sys/bus/pci/devices/0000:04: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 = 66 PORTS_IN_BLOCK = (self.PORT_END + 1) _sfp_port = range(65, 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 not in _sfp_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_Z9264F_PSU): psu = Psu(i) self._psu_list.append(psu) for i in range(MAX_Z9264F_THERMAL): thermal = Thermal(i) self._thermal_list.append(thermal) for port_num in range(self.PORT_START, (self.PORT_END + 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' def __del__(self): if self.oir_fd != -1: self.epoll.unregister(self.oir_fd.fileno()) self.epoll.close() self.oir_fd.close() 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: pass retval = retval.rstrip('\r\n') retval = retval.lstrip(" ") return retval 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 = self.get_sfp(port_num) 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 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 try: # We get notified when there is a MSI interrupt (vector 4/5)CVR # Open the sysfs file and register the epoll object self.oir_fd = os.fdopen(os.open(self.OIR_FD_PATH, os.O_RDONLY)) 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: print("get_transceiver_change_event : unable to create fd") return False, change_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 == 0) and (is_port_dict_updated is True)): return True, change_dict interrupt_count_end = self._get_register(self.OIR_FD_PATH) if (interrupt_count_start == 'ERR' or interrupt_count_end == 'ERR'): print("get_transceiver_change_event : \ unable to retrive interrupt count") 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 change_dict retval, is_port_dict_updated = \ self._check_interrupts(port_dict) if (retval != 0): return False, change_dict return True, change_dict except: return False, change_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 return False, change_dict def get_sfp(self, index): """ Retrieves sfp represented by (1-based) index <index> Args: index: An integer, the index (1-based) of the sfp to retrieve. The index should be the sequence of a physical port in a chassis, starting from 1. For example, 1 for Ethernet0, 2 for Ethernet4 and so on. Returns: An object dervied from SfpBase representing the specified sfp """ sfp = None try: # The index will start from 1 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()
class Chassis(ChassisBase): def __init__(self): ChassisBase.__init__(self) self.__num_of_psus = 2 self.__num_of_ports = 56 self.__num_of_sfps = 48 self.__num_of_fan_drawers = 6 self.__fan_per_drawer = 2 self.__num_of_thermals = 28 self.__xcvr_presence = {} # Initialize EEPROM self._eeprom = Eeprom() # Initialize watchdog #self._watchdog = Watchdog() # Initialize FAN fan_index = 1 for drawer_index in range(1, self.__num_of_fan_drawers + 1): drawer_fan_list = [] for index in range(0, self.__fan_per_drawer): fan = Fan(fan_index, False) fan_index += 1 self._fan_list.append(fan) drawer_fan_list.append(fan) fan_drawer = FanDrawer(drawer_index, drawer_fan_list) self._fan_drawer_list.append(fan_drawer) # Initialize thermal for index in range(1, self.__num_of_thermals + 1): thermal = Thermal(index) self._thermal_list.append(thermal) # Initialize PSU and PSU_FAN for index in range(1, self.__num_of_psus + 1): psu = Psu(index) self._psu_list.append(psu) # Initialize SFP for index in range(1, self.__num_of_ports + 1): if index in range(1, self.__num_of_sfps + 1): sfp = Sfp(index, 'SFP') else: sfp = Sfp(index, 'QSFP') self._sfp_list.append(sfp) for index in range(1, self.__num_of_ports + 1): self.__xcvr_presence[index] = self._sfp_list[index-1].get_presence() ############################################## # Device methods ############################################## def get_sfp(self, index): """ Retrieves sfp represented by (1-based) index <index> For Quanta IX8A the index in sfputil.py starts from 1, so override 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. Returns: An object dervied from SfpBase representing the specified sfp """ sfp = None try: if (index == 0): raise IndexError sfp = self._sfp_list[index-1] except IndexError: sys.stderr.write("override: 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 Returns: string: Serial number of chassis """ return self._eeprom.serial_number_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 ############################################## # Chassis methods ############################################## 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. Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} """ return self._eeprom.system_eeprom_info() ############################################## # Other methods ############################################## def get_watchdog(self): """ Retreives hardware watchdog device on this chassis Returns: An object derived from WatchdogBase representing the hardware watchdog device """ try: if self._watchdog is None: from sonic_platform.watchdog import Watchdog # Create the watchdog Instance self._watchdog = Watchdog() except Exception as e: syslog.syslog(syslog.LOG_ERR, "Fail to load watchdog due to {}".format(e)) return self._watchdog def get_change_event(self, timeout=0): """ Currently only support transceiver change events """ start_ms = time.time() * 1000 xcvr_change_event_dict = {} event = False while True: time.sleep(0.5) for index in range(1, self.__num_of_ports + 1): cur_xcvr_presence = self._sfp_list[index-1].get_presence() if cur_xcvr_presence != self.__xcvr_presence[index]: if cur_xcvr_presence is True: xcvr_change_event_dict[str(index)] = '1' self.__xcvr_presence[index] = True elif cur_xcvr_presence is False: xcvr_change_event_dict[str(index)] = '0' self.__xcvr_presence[index] = False event = True if event is True: return True, {'sfp':xcvr_change_event_dict} if timeout: now_ms = time.time() * 1000 if (now_ms - start_ms >= timeout): return True, {'sfp':xcvr_change_event_dict}
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: 10, 2: 11, 3: 12, 4: 13, 5: 14, 6: 15, 7: 16, 8: 17, 9: 18, 10: 19, 11: 20, 12: 21, 13: 22, 14: 23, 15: 24, 16: 25, 17: 26, 18: 27, 19: 28, 20: 29, 21: 30, 22: 31, 23: 32, 24: 33, 25: 34, 26: 35, 27: 36, 28: 37, 29: 38, 30: 39, 31: 40, 32: 41, 33: 1, 34: 2, } 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' 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 (0-{})\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_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 & 0x1: return (self.REBOOT_CAUSE_POWER_LOSS, None) elif reboot_cause & 0x2: return (self.REBOOT_CAUSE_NON_HARDWARE, None) elif reboot_cause & 0x44: return (self.REBOOT_CAUSE_HARDWARE_OTHER, "CPU warm reset") elif reboot_cause & 0x8: return (self.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU, None) elif reboot_cause & 0x66: return (self.REBOOT_CAUSE_WATCHDOG, None) elif reboot_cause & 0x55: return (self.REBOOT_CAUSE_HARDWARE_OTHER, "CPU cold reset") elif reboot_cause & 0x11: return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Power on reset") elif reboot_cause & 0x77: return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Power Cycle reset") 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
class Chassis(ChassisBase): __num_of_fans = 4 __num_of_psus = 2 __num_of_sfps = 56 __start_of_qsfp = 48 __num_of_thermals = 15 __num_of_components = 4 def __init__(self): ChassisBase.__init__(self) # Initialize EEPROM self._eeprom = Eeprom() self._eeprom_data = self._eeprom.get_eeprom_data() # Initialize FAN for index in range(self.__num_of_fans): fandrawer = FanDrawer(index) self._fan_drawer_list.append(fandrawer) self._fan_list.extend(fandrawer._fan_list) # Initialize PSU for index in range(self.__num_of_psus): psu = Psu(index) self._psu_list.append(psu) # Initialize SFP for index in range(self.__num_of_sfps): if index < self.__start_of_qsfp: sfp = Sfp(index) else: sfp = QSfp(index) self._sfp_list.append(sfp) # Initialize THERMAL for index in range(self.__num_of_thermals): thermal = Thermal(index) self._thermal_list.append(thermal) # Initialize COMPONENT for index in range(self.__num_of_components): component = Component(index) self._component_list.append(component) # Initialize WATCHDOG self._watchdog = Watchdog() def __read_txt_file(self, file_path): try: with open(file_path, 'r') as fd: data = fd.read() return data.strip() except IOError: pass return None ############################################## # Device methods ############################################## 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 Returns: string: Serial number of chassis """ return self._eeprom.serial_number_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 ############################################## # Chassis methods ############################################## 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(self._eeprom_data) 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(self._eeprom_data) 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. Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} """ 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. """ description = 'None' reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER reboot_cause_path = PMON_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE prev_reboot_cause_path = PMON_REBOOT_CAUSE_PATH + PREV_REBOOT_CAUSE_FILE sw_reboot_cause = self.__read_txt_file(reboot_cause_path) or "Unknown" prev_sw_reboot_cause = self.__read_txt_file( prev_reboot_cause_path) or "Unknown" if sw_reboot_cause == "Unknown" and prev_sw_reboot_cause in ( "Unknown", self.REBOOT_CAUSE_POWER_LOSS): reboot_cause = self.REBOOT_CAUSE_POWER_LOSS description = prev_sw_reboot_cause elif sw_reboot_cause != "Unknown": reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE description = sw_reboot_cause elif prev_reboot_cause_path != "Unknown": reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE description = prev_sw_reboot_cause return (reboot_cause, description) 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. """ global monitor port_dict = {} while True: with EventMonitor(timeout) as monitor: while True: event = monitor.get_events() if not bool(event): return True, {'sfp': port_dict} else: if event['SUBSYSTEM'] == 'swps': portname = event['DEVPATH'].split("/")[-1] rc = re.match(r"port(?P<num>\d+)", portname) if rc is not None: if event['ACTION'] == "remove": remove_num = int(rc.group("num")) port_dict[remove_num] = "0" elif event['ACTION'] == "add": add_num = int(rc.group("num")) port_dict[add_num] = "1" return True, {'sfp': port_dict} return False, {'sfp': port_dict} else: pass
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, } 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 self._fan_list = [Fan(i, j) for i in range(MAX_N3248TE_FANTRAY) \ for j in range(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.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: rv = open(cpld_reg_file, 'r').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)): #print "open error" return rv try: with open(cpld_reg_file, 'w') as fd: rv = fd.write(str(value)) except Exception: rv = 'ERR' return rv # 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().decode() 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
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 PddfChassis(ChassisBase): """ PDDF Generic Chassis class """ pddf_obj = {} plugin_data = {} def __init__(self, pddf_data=None, pddf_plugin_data=None): ChassisBase.__init__(self) self.pddf_obj = pddf_data if pddf_data else None self.plugin_data = pddf_plugin_data if pddf_plugin_data else None if not self.pddf_obj or not self.plugin_data: try: from . import pddfapi import json self.pddf_obj = pddfapi.PddfApi() with open( '/usr/share/sonic/platform/pddf/pd-plugin.json') as pd: self.plugin_data = json.load(pd) except Exception as e: raise Exception("Error: Unable to load PDDF JSON data - %s" % str(e)) self.platform_inventory = self.pddf_obj.get_platform() # Initialize EEPROM try: self._eeprom = Eeprom(self.pddf_obj, self.plugin_data) except Exception as err: sys.stderr.write("Unable to initialize syseeprom - {}".format( repr(err))) # Dont exit as we dont want failure in loading other components # FANs for i in range(self.platform_inventory['num_fantrays']): fandrawer = FanDrawer(i, self.pddf_obj, self.plugin_data) self._fan_drawer_list.append(fandrawer) self._fan_list.extend(fandrawer._fan_list) # PSUs for i in range(self.platform_inventory['num_psus']): psu = Psu(i, self.pddf_obj, self.plugin_data) self._psu_list.append(psu) # OPTICs for index in range(self.platform_inventory['num_ports']): sfp = Sfp(index, self.pddf_obj, self.plugin_data) self._sfp_list.append(sfp) # THERMALs for i in range(self.platform_inventory['num_temps']): thermal = Thermal(i, self.pddf_obj, self.plugin_data) self._thermal_list.append(thermal) 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_service_tag(self): """ Retrieves the service tag of the chassis Returns: string: Sevice tag 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(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. """ raise NotImplementedError ############################################## # Component methods ############################################## ############################################## # Module methods ############################################## # All module methods are part of chassis_base.py # if they need to be overwritten, define them here ############################################## # Fan methods ############################################## # All fan methods are part of chassis_base.py # if they need to be overwritten, define them here ############################################## # PSU methods ############################################## # All psu methods are part of chassis_base.py # if they need to be overwritten, define them here ############################################## # THERMAL methods ############################################## # All thermal methods are part of chassis_base.py # if they need to be overwritten, define them here ############################################## # SFP methods ############################################## # All sfp methods are part of chassis_base.py # if they need to be overwritten, define them here ############################################## # System LED methods ############################################## def set_system_led(self, led_device_name, color): result, msg = self.pddf_obj.is_supported_sysled_state( led_device_name, color) if result == False: print(msg) return (False) index = self.pddf_obj.data[led_device_name]['dev_attr']['index'] device_name = self.pddf_obj.data[led_device_name]['dev_info'][ 'device_name'] self.pddf_obj.create_attr('device_name', device_name, self.pddf_obj.get_led_path()) self.pddf_obj.create_attr('index', index, self.pddf_obj.get_led_path()) self.pddf_obj.create_attr('color', color, self.pddf_obj.get_led_cur_state_path()) self.pddf_obj.create_attr('dev_ops', 'set_status', self.pddf_obj.get_led_path()) return (True) def get_system_led(self, led_device_name): if led_device_name not in self.pddf_obj.data.keys(): status = "[FAILED] " + led_device_name + " is not configured" return (status) index = self.pddf_obj.data[led_device_name]['dev_attr']['index'] device_name = self.pddf_obj.data[led_device_name]['dev_info'][ 'device_name'] self.pddf_obj.create_attr('device_name', device_name, self.pddf_obj.get_led_path()) self.pddf_obj.create_attr('index', index, self.pddf_obj.get_led_path()) self.pddf_obj.create_attr('dev_ops', 'get_status', self.pddf_obj.get_led_path()) color = self.pddf_obj.get_led_color() return (color)
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 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_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): def __init__(self): ChassisBase.__init__(self) self.__num_of_psus = 2 self.__num_of_ports = 54 self.__num_of_sfps = 48 self.__num_of_fans = 4 self.__num_of_thermals = 6 # Initialize EEPROM self._eeprom = Eeprom() # Initialize watchdog #self._watchdog = Watchdog() # Initialize FAN for index in range(1, self.__num_of_fans + 1): fan = Fan(index) self._fan_list.append(fan) # Initialize thermal for index in range(1, self.__num_of_thermals + 1): thermal = Thermal(index) self._thermal_list.append(thermal) # Initialize PSU and PSU_FAN for index in range(1, self.__num_of_psus + 1): psu = Psu(index) self._psu_list.append(psu) fan = Fan(index, True) self._fan_list.append(fan) # Initialize SFP for index in range(0, self.__num_of_ports): if index in range(0, self.__num_of_sfps): sfp = Sfp(index, 'SFP') else: sfp = Sfp(index, 'QSFP') self._sfp_list.append(sfp) ############################################## # Device methods ############################################## 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 Returns: string: Serial number of chassis """ return self._eeprom.serial_number_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 ############################################## # Chassis methods ############################################## 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. Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} """ 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. """ raise NotImplementedError
class Chassis(ChassisBase): """ Nokia platform-specific Chassis class Derived from Dell S6000 platform. customized for the 7215 platform. """ def __init__(self): ChassisBase.__init__(self) self.system_led_supported_color = [ 'off', 'amber', 'green', 'amber_blink', 'green_blink' ] # Port numbers for SFP List Initialization self.COPPER_PORT_START = COPPER_PORT_START self.COPPER_PORT_END = COPPER_PORT_END self.SFP_PORT_START = SFP_PORT_START self.SFP_PORT_END = SFP_PORT_END self.PORT_END = PORT_END # for non-sfp ports create dummy objects for copper / non-sfp ports for index in range(self.COPPER_PORT_START, self.COPPER_PORT_END + 1): sfp_node = Sfp(index, 'COPPER', 'N/A', 'N/A') self._sfp_list.append(sfp_node) # Verify optoe2 driver SFP eeprom devices were enumerated and exist # then create the sfp nodes eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" mux_dev = sorted(glob.glob("/sys/class/i2c-adapter/i2c-0/i2c-[0-9]")) y = 0 for index in range(self.SFP_PORT_START, self.SFP_PORT_END + 1): mux_dev_num = mux_dev[y] port_i2c_map = mux_dev_num[-1] y = y + 1 port_eeprom_path = eeprom_path.format(port_i2c_map) if not os.path.exists(port_eeprom_path): sonic_logger.log_info("path %s didnt exist" % port_eeprom_path) sfp_node = Sfp(index, 'SFP', port_eeprom_path, port_i2c_map) self._sfp_list.append(sfp_node) self.sfp_event_initialized = False # Instantiate system eeprom object self._eeprom = Eeprom() # Construct lists fans, power supplies, thermals & components drawer_num = MAX_7215_FAN_DRAWERS fan_num_per_drawer = MAX_7215_FANS_PER_DRAWER drawer_ctor = RealDrawer fan_index = 0 for drawer_index in range(drawer_num): drawer = drawer_ctor(drawer_index) self._fan_drawer_list.append(drawer) for index in range(fan_num_per_drawer): fan = Fan(fan_index, drawer) fan_index += 1 drawer._fan_list.append(fan) self._fan_list.append(fan) for i in range(MAX_7215_PSU): psu = Psu(i) self._psu_list.append(psu) for i in range(MAX_7215_THERMAL): thermal = Thermal(i) self._thermal_list.append(thermal) for i in range(MAX_7215_COMPONENT): component = Component(i) self._component_list.append(component) 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 physical SFP ports in a chassis starting from 1. Returns: An object dervied from SfpBase representing the specified sfp """ sfp = None try: # The index will start from 1 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_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(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. """ # The ixs7215 CPLD does not have a hardware reboot cause register so # the hardware portion of reboot cause can't be implemented return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None) def get_change_event(self, timeout=0): """ Returns a nested dictionary containing all devices which have experienced a change at chassis level Args: timeout: Timeout in milliseconds (optional). If timeout == 0, this method will block until a change is detected. Returns: (bool, dict): - True if call successful, False if not; - A nested dictionary where key is a device type, value is a dictionary with key:value pairs in the format of {'device_id':'device_event'}, where device_id is the device ID for this device and device_event, status='1' represents device inserted, status='0' represents device removed. Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}} indicates that fan 0 has been removed, fan 2 has been inserted and sfp 11 has been removed. """ # Initialize SFP event first if not self.sfp_event_initialized: from sonic_platform.sfp_event import sfp_event self.sfp_event = sfp_event() self.sfp_event.initialize() self.MAX_SELECT_EVENT_RETURNED = self.PORT_END self.sfp_event_initialized = True wait_for_ever = (timeout == 0) port_dict = {} if wait_for_ever: # xrcvd will call this monitor loop in the "SYSTEM_READY" state timeout = MAX_SELECT_DELAY while True: status = self.sfp_event.check_sfp_status(port_dict, timeout) if not port_dict == {}: break else: # At boot up and in "INIT" state call from xrcvd will have timeout # value return true without change after timeout and will # transition to "SYSTEM_READY" status = self.sfp_event.check_sfp_status(port_dict, timeout) if status: return True, {'sfp': port_dict} else: return True, {'sfp': {}} def get_thermal_manager(self): from .thermal_manager import ThermalManager return ThermalManager def set_status_led(self, color): """ Sets the state of the system LED Args: color: A string representing the color with which to set the system LED Returns: bool: True if system LED state is set successfully, False if not """ if color not in self.system_led_supported_color: return False if (color == 'off'): value = 0x00 elif (color == 'amber'): value = 0x01 elif (color == 'green'): value = 0x02 elif (color == 'amber_blink'): value = 0x03 elif (color == 'green_blink'): value = 0x04 else: return False # Write sys led if smbus_present == 0: sonic_logger.log_warning("PMON LED SET -> smbus present = 0") else: bus = smbus.SMBus(0) DEVICE_ADDRESS = 0x41 DEVICEREG = 0x7 bus.write_byte_data(DEVICE_ADDRESS, DEVICEREG, value) sonic_logger.log_info(" System LED set O.K. ") return True 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. """ # Read sys led if smbus_present == 0: sonic_logger.log_warning("PMON LED GET -> smbus present = 0") return False else: bus = smbus.SMBus(0) DEVICE_ADDRESS = 0x41 DEVICE_REG = 0x7 value = bus.read_byte_data(DEVICE_ADDRESS, DEVICE_REG) if value == 0x00: color = 'off' elif value == 0x01: color = 'amber' elif value == 0x02: color = 'green' elif value == 0x03: color = 'amber_blink' elif value == 0x04: color = 'green_blink' else: return False return color def get_watchdog(self): """ Retrieves hardware watchdog device on this chassis Returns: An object derived from WatchdogBase representing the hardware watchdog device Note: We overload this method to ensure that watchdog is only initialized when it is referenced. Currently, only one daemon can open the watchdog. To initialize watchdog in the constructor causes multiple daemon try opening watchdog when loading and constructing a chassis object and fail. By doing so we can eliminate that risk. """ try: if self._watchdog is None: from sonic_platform.watchdog import WatchdogImplBase watchdog_device_path = "/dev/watchdog0" self._watchdog = WatchdogImplBase(watchdog_device_path) except Exception as e: sonic_logger.log_warning(" Fail to load watchdog {}".format( repr(e))) return self._watchdog def get_position_in_parent(self): """ Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned Returns: integer: The 1-based relative physical position in parent device or -1 if cannot determine the position """ return -1 def is_replaceable(self): """ Indicate whether this device is replaceable. Returns: bool: True if it is replaceable. """ return False
class Chassis(ChassisBase): """ Ruijie B6510-48VS8CQ Platform-specific Chassis class """ def __init__(self): ChassisBase.__init__(self) self.CHASSIS_CONFIG = 'chassis.json' self.THERMAL_CONFIG = 'thermal.json' self.SFP_CONFIG = 'sfp.json' self.PSU_CONFIG = 'psu.json' self.FAN_CONFIG = 'fan.json' self.COMPONENT_CONFIG = 'component.json' self.SFP_STATUS_INSERTED = "1" self.SFP_STATUS_REMOVED = "0" self.port_dict = {} self.enable_read = "i2cset -f -y 2 0x35 0x2a 0x01" self.disable_read = "i2cset -f -y 2 0x35 0x2a 0x00" self.enable_write = "i2cset -f -y 2 0x35 0x2b 0x00" self.disable_write = "i2cset -f -y 2 0x35 0x2b 0x01" self.enable_erase = "i2cset -f -y 2 0x35 0x2c 0x01" self.disable_erase = "i2cset -f -y 2 0x35 0x2c 0x00" self.read_value = "i2cget -f -y 2 0x35 0x25" self.write_value = "i2cset -f -y 2 0x35 0x21 0x0a" self.set_sys_led_cmd = "i2cset -f -y 2 0x33 0xb2 " self.get_sys_led_cmd = "i2cget -f -y 2 0x33 0xb2" self.led_status = "red" # Initialize SFP list # 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 for index in range(PORT_START, PORTS_IN_BLOCK): sfp_node = Sfp(index) self._sfp_list.append(sfp_node) if sfp_node.get_presence(): self.port_dict[index] = self.SFP_STATUS_INSERTED else: self.port_dict[index] = self.SFP_STATUS_REMOVED self._api_common = Common() config_path = self._api_common.get_config_path(self.CHASSIS_CONFIG) self._config = self._api_common.load_json_file(config_path) self.__initialize_eeprom() if self._api_common.is_host(): self.__initialize_fan() self.__initialize_psu() self.__initialize_thermals() else: self.__initialize_components() def __initialize_fan(self): from sonic_platform.fan import Fan from sonic_platform.fan_drawer import FanDrawer fan_config_path = self._api_common.get_config_path(self.FAN_CONFIG) self.fan_config = self._api_common.load_json_file( fan_config_path)["fans"] if self.fan_config: drawer_fan_list = [] for index in range(0, len(self.fan_config)): fan = Fan(index, config=self.fan_config[index]) self._fan_list.append(fan) drawer_fan_list.append(fan) fan_drawer = FanDrawer(0, fan_list=drawer_fan_list) self._fan_drawer_list.append(fan_drawer) def __initialize_psu(self): from sonic_platform.psu import Psu psu_config_path = self._api_common.get_config_path(self.PSU_CONFIG) self.psu_config = self._api_common.load_json_file( psu_config_path)["psus"] if self.psu_config: for index in range(0, len(self.psu_config)): psu = Psu(index, config=self.psu_config[index]) self._psu_list.append(psu) def __initialize_thermals(self): from sonic_platform.thermal import Thermal thermal_config_path = self._api_common.get_config_path( self.THERMAL_CONFIG) self.thermal_config = self._api_common.load_json_file( thermal_config_path)['thermals'] if self.thermal_config: for index in range(0, len(self.thermal_config)): thermal = Thermal(index, config=self.thermal_config[index]) self._thermal_list.append(thermal) def __initialize_eeprom(self): from sonic_platform.eeprom import Eeprom self._eeprom = Eeprom(config=self._config["eeprom"]) def __initialize_components(self): from sonic_platform.component import Component component_config_path = self._api_common.get_config_path( self.COMPONENT_CONFIG) self.component_config = self._api_common.load_json_file( component_config_path)['components'] if self.component_config: for index in range(0, len(self.component_config)): component = Component(index, config=self.component_config[index]) self._component_list.append(component) def _init_standard_config(self, conflist, class_name, objlist): for conf in conflist: obj = globals()[class_name](conf.get("name"), config=conf) objlist.append(obj) def _init_by_hal(self, hal_interface): self.hal_interface = hal_interface self.hal_interface.get_fans() 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_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: is_power_loss = False # enable read subprocess.getstatusoutput(self.disable_write) subprocess.getstatusoutput(self.enable_read) ret, log = subprocess.getstatusoutput(self.read_value) if ret == 0 and "0x0a" in log: is_power_loss = True # erase i2c and e2 subprocess.getstatusoutput(self.enable_erase) time.sleep(1) subprocess.getstatusoutput(self.disable_erase) # clear data subprocess.getstatusoutput(self.enable_write) subprocess.getstatusoutput(self.disable_read) subprocess.getstatusoutput(self.disable_write) subprocess.getstatusoutput(self.enable_read) # enable write and set data subprocess.getstatusoutput(self.enable_write) subprocess.getstatusoutput(self.disable_read) subprocess.getstatusoutput(self.write_value) if is_power_loss: return (self.REBOOT_CAUSE_POWER_LOSS, None) except Exception as e: logger.error(str(e)) return (self.REBOOT_CAUSE_NON_HARDWARE, None) 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. Specifically for SFP event, besides SFP plug in and plug out, there are some other error event could be raised from SFP, when these error happened, SFP eeprom will not be avalaible, XCVRD shall stop to read eeprom before SFP recovered from error status. status='2' I2C bus stuck, status='3' Bad eeprom, status='4' Unsupported cable, status='5' High Temperature, status='6' Bad cable. """ change_event_dict = {"fan": {}, "sfp": {}} sfp_status, sfp_change_dict = self.get_transceiver_change_event( timeout) change_event_dict["sfp"] = sfp_change_dict if sfp_status is True: return True, change_event_dict return False, {} def get_transceiver_change_event(self, timeout=0): start_time = time.time() currernt_port_dict = {} forever = False if timeout == 0: forever = True elif timeout > 0: timeout = timeout / float(1000) # Convert to secs else: print("get_transceiver_change_event:Invalid timeout value", timeout) return False, {} end_time = start_time + timeout if start_time > end_time: print( "get_transceiver_change_event:" "time wrap / invalid timeout value", timeout, ) return False, {} # Time wrap or possibly incorrect timeout while timeout >= 0: # Check for OIR events and return updated port_dict for index in range(PORT_START, PORTS_IN_BLOCK): if self._sfp_list[index].get_presence(): currernt_port_dict[index] = self.SFP_STATUS_INSERTED else: currernt_port_dict[index] = self.SFP_STATUS_REMOVED if currernt_port_dict == self.port_dict: if forever: time.sleep(1) else: timeout = end_time - time.time() if timeout >= 1: time.sleep(1) # We poll at 1 second granularity else: if timeout > 0: time.sleep(timeout) return True, {} else: # Update reg value self.port_dict = currernt_port_dict print(self.port_dict) return True, self.port_dict print("get_transceiver_change_event: Should not reach here.") return False, {} def get_all_components(self): return self._component_list def get_all_fans(self): return self._fan_list def get_all_psus(self): return self._psu_list def get_all_thermals(self): return self._thermal_list def get_supervisor_slot(self): """ Retrieves the physical-slot of the supervisor-module in the modular chassis. On the supervisor or line-card modules, it will return the physical-slot of the supervisor-module. On the fixed-platforms, the API can be ignored. Users of the API can catch the exception and return a default ModuleBase.MODULE_INVALID_SLOT and bypass code for fixed-platforms. Returns: An integer, the vendor specific physical slot identifier of the supervisor module in the modular-chassis. """ return 0 def get_my_slot(self): """ Retrieves the physical-slot of this module in the modular chassis. On the supervisor, it will return the physical-slot of the supervisor module. On the linecard, it will return the physical-slot of the linecard module where this instance of SONiC is running. On the fixed-platforms, the API can be ignored. Users of the API can catch the exception and return a default ModuleBase.MODULE_INVALID_SLOT and bypass code for fixed-platforms. Returns: An integer, the vendor specific physical slot identifier of this module in the modular-chassis. """ return 0 def is_modular_chassis(self): """ Retrieves whether the sonic instance is part of modular chassis Returns: A bool value, should return False by default or for fixed-platforms. Should return True for supervisor-cards, line-cards etc running as part of modular-chassis. """ return True def init_midplane_switch(self): """ Initializes the midplane functionality of the modular chassis. For example, any validation of midplane, populating any lookup tables etc can be done here. The expectation is that the required kernel modules, ip-address assignment etc are done before the pmon, database dockers are up. Returns: A bool value, should return True if the midplane initialized successfully. """ return True 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 """ return 0 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 """ colors = {"amber": "0x00", "red": "0x02", "green": "0x04"} regval = colors.get(color, None) if regval is None: print("Invaild color input.") return False ret, log = subprocess.getstatusoutput(self.set_sys_led_cmd + regval) if ret != 0: print("Cannot execute %s" % self.set_sys_led_cmd + regval) return False self.led_status = 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. """ ret, log = subprocess.getstatusoutput(self.get_sys_led_cmd) if ret != 0: print("Cannot execute %s" % self.get_sys_led_cmd) return False colors = {"0x00": "amber", "0x02": "red", "0x04": "green"} color = colors.get(log, None) if color is None: return "Unknown color status" self.led_status = color return self.led_status