def test_get_system_eeprom_info_from_db(self): return_values = { ('EEPROM_INFO|State', 'Initialized'): '1', ('EEPROM_INFO|{}'.format(hex(Eeprom._TLV_CODE_PRODUCT_NAME)), 'Value'): 'MSN3420', ('EEPROM_INFO|{}'.format(hex(Eeprom._TLV_CODE_PART_NUMBER)), 'Value'): 'MSN3420-CB2FO', ('EEPROM_INFO|{}'.format(hex(Eeprom._TLV_CODE_MAC_BASE)), 'Value'): '1C:34:DA:1C:9F:00', ('EEPROM_INFO|{}'.format(hex(Eeprom._TLV_CODE_SERIAL_NUMBER)), 'Value'): 'MT2019X13878', ('EEPROM_INFO|{}'.format(hex(Eeprom._TLV_CODE_VENDOR_EXT)), 'Num_vendor_ext'): '2', ('EEPROM_INFO|{}'.format(hex(Eeprom._TLV_CODE_VENDOR_EXT)), 'Value_0'): 'ext1', ('EEPROM_INFO|{}'.format(hex(Eeprom._TLV_CODE_VENDOR_EXT)), 'Value_1'): 'ext2', ('EEPROM_INFO|{}'.format(hex(Eeprom._TLV_CODE_CRC_32)), 'Value'): 'CRC_VALUE', } def side_effect(key, field): return return_values.get((key, field)) eeprom = Eeprom() eeprom._redis_hget = MagicMock(side_effect=side_effect) info = eeprom.get_system_eeprom_info() assert eeprom.get_product_name() == 'MSN3420' assert eeprom.get_part_number() == 'MSN3420-CB2FO' assert eeprom.get_base_mac() == '1C:34:DA:1C:9F:00' assert eeprom.get_serial_number() == 'MT2019X13878' assert info[hex(Eeprom._TLV_CODE_VENDOR_EXT)] == ['ext1', 'ext2'] assert info[hex(Eeprom._TLV_CODE_CRC_32)] == 'CRC_VALUE'
def test_get_system_eeprom_info_from_hardware(self): eeprom = Eeprom() eeprom.p = os.path.join(test_path, 'mock_eeprom_data') eeprom._redis_hget = MagicMock() info = eeprom.get_system_eeprom_info() assert eeprom.get_product_name() == 'MSN3800' assert eeprom.get_part_number() == 'MSN3800-CS2FO' assert eeprom.get_base_mac() == 'B8:59:9F:A9:34:00' assert eeprom.get_serial_number() == 'MT1937X00537' assert info[hex(Eeprom._TLV_CODE_CRC_32)] == '0x9EFF0119'
class Psu(PsuBase): """DellEMC Platform-specific PSU class""" CPLD_DIR = "/sys/devices/platform/dell-s6000-cpld.0/" I2C_DIR = "/sys/class/i2c-adapter/" def __init__(self, psu_index): PsuBase.__init__(self) # PSU is 1-based in DellEMC platforms self.index = psu_index + 1 self.psu_presence_reg = "psu{}_prs".format(psu_index) self.psu_status_reg = "powersupply_status" self.is_driver_initialized = False if self.index == 1: ltc_dir = self.I2C_DIR + "i2c-11/11-0042/hwmon/" else: ltc_dir = self.I2C_DIR + "i2c-11/11-0040/hwmon/" try: hwmon_node = os.listdir(ltc_dir)[0] except OSError: hwmon_node = "hwmon*" else: self.is_driver_initialized = True self.HWMON_DIR = ltc_dir + hwmon_node + '/' self.psu_voltage_reg = self.HWMON_DIR + "in1_input" self.psu_current_reg = self.HWMON_DIR + "curr1_input" self.psu_power_reg = self.HWMON_DIR + "power1_input" self.eeprom = Eeprom(is_psu=True, psu_index=self.index) self._fan_list.append( Fan(psu_index=self.index, psu_fan=True, dependency=self)) for i in range(1, MAX_S6000_THERMALS_PER_PSU + 1): self._thermal_list.append( Thermal(psu_index=self.index, thermal_index=i, psu_thermal=True, dependency=self)) def _get_cpld_register(self, reg_name): # On successful read, returns the value read from given # reg_name and on failure returns 'ERR' rv = 'ERR' cpld_reg_file = self.CPLD_DIR + reg_name if (not os.path.isfile(cpld_reg_file)): return rv try: with open(cpld_reg_file, 'r') as fd: rv = fd.read() except: rv = 'ERR' rv = rv.rstrip('\r\n') rv = rv.lstrip(" ") return rv def _get_i2c_register(self, reg_file): # On successful read, returns the value read from given # reg_name and on failure returns 'ERR' rv = 'ERR' if not self.is_driver_initialized: reg_file_path = glob.glob(reg_file) if len(reg_file_path): reg_file = reg_file_path[0] self._get_sysfs_path() else: return rv if (not os.path.isfile(reg_file)): return rv try: with open(reg_file, 'r') as fd: rv = fd.read() except: rv = 'ERR' rv = rv.rstrip('\r\n') rv = rv.lstrip(" ") return rv def _get_sysfs_path(self): voltage_reg = glob.glob(self.psu_voltage_reg) current_reg = glob.glob(self.psu_current_reg) power_reg = glob.glob(self.psu_power_reg) if len(voltage_reg) and len(current_reg) and len(power_reg): self.psu_voltage_reg = voltage_reg[0] self.psu_current_reg = current_reg[0] self.psu_power_reg = power_reg[0] self.is_driver_initialized = True def get_name(self): """ Retrieves the name of the device Returns: string: The name of the device """ return "PSU{}".format(self.index) def get_presence(self): """ Retrieves the presence of the Power Supply Unit (PSU) Returns: bool: True if PSU is present, False if not """ status = False psu_presence = self._get_cpld_register(self.psu_presence_reg) if (psu_presence != 'ERR'): psu_presence = int(psu_presence) if psu_presence: status = True return status def get_model(self): """ Retrieves the part number of the PSU Returns: string: Part number of PSU """ return self.eeprom.get_part_number() def get_serial(self): """ Retrieves the serial number of the PSU Returns: string: Serial number of PSU """ # Sample Serial number format "US-01234D-54321-25A-0123-A00" return self.eeprom.get_serial_number() def get_status(self): """ Retrieves the operational status of the PSU Returns: bool: True if PSU is operating properly, False if not """ status = False psu_status = self._get_cpld_register(self.psu_status_reg) if (psu_status != 'ERR'): psu_status = (int(psu_status, 16) >> int( (2 - self.index) * 4)) & 0xF if (~psu_status & 0b1000) and (~psu_status & 0b0100): status = True return status 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 self.index def is_replaceable(self): """ Indicate whether PSU is replaceable. Returns: bool: True if it is replaceable. """ return True def get_voltage(self): """ Retrieves current PSU voltage output Returns: A float number, the output voltage in volts, e.g. 12.1 """ psu_voltage = self._get_i2c_register(self.psu_voltage_reg) if (psu_voltage != 'ERR') and self.get_status(): # Converting the value returned by driver which is in # millivolts to volts psu_voltage = float(psu_voltage) / 1000 else: psu_voltage = 0.0 return psu_voltage def get_current(self): """ Retrieves present electric current supplied by PSU Returns: A float number, electric current in amperes, e.g. 15.4 """ psu_current = self._get_i2c_register(self.psu_current_reg) if (psu_current != 'ERR') and self.get_status(): # Converting the value returned by driver which is in # milliamperes to amperes psu_current = float(psu_current) / 1000 else: psu_current = 0.0 return psu_current def get_power(self): """ Retrieves current energy supplied by PSU Returns: A float number, the power in watts, e.g. 302.6 """ psu_power = self._get_i2c_register(self.psu_power_reg) if (psu_power != 'ERR') and self.get_status(): # Converting the value returned by driver which is in # microwatts to watts psu_power = float(psu_power) / 1000000 else: psu_power = 0.0 return psu_power def get_powergood_status(self): """ Retrieves the powergood status of PSU Returns: A boolean, True if PSU has stablized its output voltages and passed all its internal self-tests, False if not. """ status = False psu_status = self._get_cpld_register(self.psu_status_reg) if (psu_status != 'ERR'): psu_status = (int(psu_status, 16) >> ((2 - self.index) * 4)) & 0xF if (psu_status == 0x2): status = True return status def get_status_led(self): """ Gets the state of the PSU status LED Returns: A string, one of the predefined STATUS_LED_COLOR_* strings. """ if self.get_powergood_status(): return self.STATUS_LED_COLOR_GREEN else: return self.STATUS_LED_COLOR_OFF def set_status_led(self, color): """ Sets the state of the PSU status LED Args: color: A string representing the color with which to set the PSU status LED Returns: bool: True if status LED state is set successfully, False if not """ # In S6000, the firmware running in the PSU controls the LED # and the PSU LED state cannot be changed from CPU. return False def get_temperature(self): """ Retrieves current temperature reading from PSU Returns: A float number of current temperature in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ if self.get_presence(): return self.get_thermal(0).get_temperature() else: return 0.0 def get_temperature_high_threshold(self): """ Retrieves the high threshold temperature of PSU Returns: A float number, the high threshold temperature of PSU in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ if self.get_presence(): return self.get_thermal(0).get_high_threshold() else: return 0.0 def get_voltage_high_threshold(self): """ Retrieves the high threshold PSU voltage output Returns: A float number, the high threshold output voltage in volts, e.g. 12.1 """ return 12.6 def get_voltage_low_threshold(self): """ Retrieves the low threshold PSU voltage output Returns: A float number, the low threshold output voltage in volts, e.g. 12.1 """ return 11.4
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 reset_reason_dict[0x7] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER 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() with open("/sys/class/dmi/id/product_name", "r") as fd: board_type = fd.read() if 'S6000-ON' in board_type: self._eeprom = Eeprom() else: self._eeprom = EepromS6000() 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 _nvram_write(self, offset, val): resource = "/dev/nvram" fd = os.open(resource, os.O_RDWR) if (fd < 0): print('File open failed ', resource) return if (os.lseek(fd, offset, os.SEEK_SET) != offset): print('lseek failed on ', resource) return ret = os.write(fd, struct.pack('B', val)) if ret != 1: print('Write failed ', str(ret)) return os.close(fd) def _get_thermal_reset(self): reset_file = "/host/reboot-cause/reboot-cause.txt" if (not os.path.isfile(reset_file)): return False try: with open(reset_file, 'r') as fd: rv = fd.read() except Exception as error: return False if "Thermal Overload" in rv: return True return False def get_name(self): """ Retrieves the name of the chassis Returns: string: The name of the chassis """ return self._eeprom.get_model() 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.get_part_number() def get_serial(self): """ Retrieves the serial number of the chassis (Service tag) Returns: string: Serial number of chassis """ return self._eeprom.get_serial() 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.get_base_mac() def get_serial_number(self): """ Retrieves the hardware serial number for the chassis Returns: A string containing the hardware serial number for this chassis. """ return self._eeprom.get_serial_number() def get_system_eeprom_info(self): """ Retrieves the full content of system EEPROM information for the chassis Returns: A dictionary where keys are the type code defined in OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ return self._eeprom.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 if self._get_thermal_reset() == True: self._nvram_write(0x49, 0x7) 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_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. """ start_time = time.time() port_dict = {} ret_dict = {"sfp": 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, ret_dict # 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, ret_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, ret_dict return False, ret_dict
class Fan(FanBase): """DellEMC Platform-specific Fan class""" CPLD_DIR = "/sys/devices/platform/dell-s6000-cpld.0/" I2C_DIR = "/sys/class/i2c-adapter/" def __init__(self, fan_index, psu_fan=False, dependency=None): self.is_psu_fan = psu_fan self.is_driver_initialized = True if not self.is_psu_fan: # Fan is 1-based in DellEMC platforms self.index = fan_index + 1 self.fan_presence_reg = "fan_prs" self.fan_led_reg = "fan{}_led".format(fan_index) self.get_fan_speed_reg = self.I2C_DIR + "i2c-11/11-0029/" +\ "fan{}_input".format(self.index) self.set_fan_speed_reg = self.I2C_DIR + "i2c-11/11-0029/" +\ "fan{}_target".format(self.index) self.eeprom = Eeprom(is_fan=True, fan_index=self.index) self.max_fan_speed = MAX_S6000_FAN_SPEED self.supported_led_color = ['off', 'green', 'amber'] else: self.index = fan_index self.dependency = dependency self.set_fan_speed_reg = self.I2C_DIR +\ "i2c-1/1-005{}/fan1_target".format(10 - self.index) hwmon_dir = self.I2C_DIR +\ "i2c-1/1-005{}/hwmon/".format(10 - self.index) try: hwmon_node = os.listdir(hwmon_dir)[0] except OSError: hwmon_node = "hwmon*" self.is_driver_initialized = False self.get_fan_speed_reg = hwmon_dir + hwmon_node + '/fan1_input' self.max_fan_speed = MAX_S6000_PSU_FAN_SPEED def _get_cpld_register(self, reg_name): # On successful read, returns the value read from given # reg_name and on failure returns 'ERR' rv = 'ERR' cpld_reg_file = self.CPLD_DIR + reg_name if (not os.path.isfile(cpld_reg_file)): return rv try: with open(cpld_reg_file, 'r') as fd: rv = fd.read() except: rv = 'ERR' rv = rv.rstrip('\r\n') rv = rv.lstrip(" ") return rv 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: rv = 'ERR' return rv def _get_i2c_register(self, reg_file): # On successful read, returns the value read from given # reg_name and on failure returns 'ERR' rv = 'ERR' if not self.is_driver_initialized: reg_file_path = glob.glob(reg_file) if len(reg_file_path): reg_file = reg_file_path[0] self._get_sysfs_path() else: return rv if (not os.path.isfile(reg_file)): return rv try: with open(reg_file, 'r') as fd: rv = fd.read() except: rv = 'ERR' rv = rv.rstrip('\r\n') rv = rv.lstrip(" ") return rv def _set_i2c_register(self, reg_file, value): # On successful write, the value read will be written on # reg_name and on failure returns 'ERR' rv = 'ERR' if (not os.path.isfile(reg_file)): return rv try: with open(reg_file, 'w') as fd: rv = fd.write(str(value)) except: rv = 'ERR' return rv def _get_sysfs_path(self): fan_speed_reg = glob.glob(self.get_fan_speed_reg) if len(fan_speed_reg): self.get_fan_speed_reg = fan_speed_reg[0] self.is_driver_initialized = True def get_name(self): """ Retrieves the name of the Fan Returns: string: The name of the Fan """ if not self.is_psu_fan: return "FanTray{}-Fan1".format(self.index) else: return "PSU{} Fan".format(self.index) def get_presence(self): """ Retrieves the presence of the Fan Unit Returns: bool: True if Fan is present, False if not """ status = False if self.is_psu_fan: return self.dependency.get_presence() fan_presence = self._get_cpld_register(self.fan_presence_reg) if (fan_presence != 'ERR'): fan_presence = int(fan_presence, 16) & self.index if fan_presence: status = True return status def get_model(self): """ Retrieves the part number of the Fan Returns: string: Part number of Fan """ if not self.is_psu_fan: return self.eeprom.get_part_number() else: return 'NA' def get_serial(self): """ Retrieves the serial number of the Fan Returns: string: Serial number of Fan """ # Sample Serial number format "US-01234D-54321-25A-0123-A00" if not self.is_psu_fan: return self.eeprom.get_serial_number() else: return 'NA' def get_status(self): """ Retrieves the operational status of the Fan Returns: bool: True if Fan is operating properly, False if not """ status = False fan_speed = self._get_i2c_register(self.get_fan_speed_reg) if (fan_speed != 'ERR'): if (int(fan_speed) > 1000): status = True return status def get_direction(self): """ Retrieves the fan airflow direction Returns: A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST depending on fan direction Notes: In DellEMC platforms, - Forward/Exhaust : Air flows from Port side to Fan side. - Reverse/Intake : Air flows from Fan side to Port side. """ if self.is_psu_fan: direction = { 1: self.FAN_DIRECTION_EXHAUST, 2: self.FAN_DIRECTION_INTAKE, 3: self.FAN_DIRECTION_EXHAUST, 4: self.FAN_DIRECTION_INTAKE } fan_direction = self.dependency.eeprom.airflow_fan_type() else: direction = { 1: self.FAN_DIRECTION_EXHAUST, 2: self.FAN_DIRECTION_INTAKE } fan_direction = self.eeprom.airflow_fan_type() return direction.get(fan_direction, self.FAN_DIRECTION_NOT_APPLICABLE) def get_speed(self): """ Retrieves the speed of fan Returns: int: percentage of the max fan speed """ fan_speed = self._get_i2c_register(self.get_fan_speed_reg) if (fan_speed != 'ERR') and self.get_presence(): speed_in_rpm = int(fan_speed, 10) speed = (100 * speed_in_rpm) // self.max_fan_speed else: speed = 0 return speed def get_speed_tolerance(self): """ Retrieves the speed tolerance of the fan Returns: An integer, the percentage of variance from target speed which is considered tolerable """ if self.get_presence(): # The tolerance value is fixed as 20% for all the DellEmc platform tolerance = 20 else: tolerance = 0 return tolerance def set_speed(self, speed): """ Set fan speed to expected value Args: speed: An integer, the percentage of full fan speed to set fan to, in the range 0 (off) to 100 (full speed) Returns: bool: True if set success, False if fail. """ fan_set = (speed * self.max_fan_speed) / 100 rv = self._set_i2c_register(self.set_fan_speed_reg, fan_set) if (rv != 'ERR'): return True else: return False def set_status_led(self, color): """ Set led to expected color Args: color: A string representing the color with which to set the fan module status LED Returns: bool: True if set success, False if fail. """ if self.is_psu_fan or (color not in self.supported_led_color): return False if (color == self.STATUS_LED_COLOR_AMBER): color = 'yellow' rv = self._set_cpld_register(self.fan_led_reg, color) if (rv != 'ERR'): return True else: return False def get_status_led(self): """ Gets the state of the fan status LED Returns: A string, one of the predefined STATUS_LED_COLOR_* strings. """ if self.is_psu_fan: # No LED available for PSU Fan return None fan_led = self._get_cpld_register(self.fan_led_reg) if (fan_led != 'ERR'): if (fan_led == 'yellow'): return self.STATUS_LED_COLOR_AMBER else: return fan_led else: return self.STATUS_LED_COLOR_OFF def get_target_speed(self): """ Retrieves the target (expected) speed of the fan Returns: An integer, the percentage of full fan speed, in the range 0 (off) to 100 (full speed) """ # Fan speeds are controlled by fancontrol.sh return self.get_speed()
class Chassis(ChassisBase): """ NOKIA IXR7250 Platform-specific Chassis class """ REBOOT_CAUSE_DICT = { 'powerloss': ChassisBase.REBOOT_CAUSE_POWER_LOSS, 'overtemp': ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER, 'reboot': ChassisBase.REBOOT_CAUSE_NON_HARDWARE, 'watchdog': ChassisBase.REBOOT_CAUSE_WATCHDOG, 'under-voltage': ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, 'over-voltage': ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, } def __init__(self): ChassisBase.__init__(self) # logger.set_min_log_priority_info() # Chassis specific slot numbering self.is_chassis_modular = nokia_common.is_chassis_modular() self.cpm_instance = nokia_common._get_cpm_slot() self.my_instance = nokia_common._get_my_slot() self.is_cpm = nokia_common.is_cpm() # Create a GRPC channel self.chassis_stub = None self.fan_stub = None self.thermal_stub = None self.psu_stub = None self.firmware_stub = None # Get maximum power consumed by each module like cards, fan-trays etc self._get_modules_consumed_power() # Module list self.get_module_list() # PSU list self._get_psu_list() # FAN list self._get_fantray_list() # Thermal list self.get_thermal_list() # Component List self._get_component_list() # SFP self.sfp_module_initialized = False self.sfp_event_initialized = False # Watchdog if self._watchdog is None: self._watchdog = Watchdog("dog") logger.log_info('HW Watchdog initialized') # system eeprom self._eeprom = Eeprom() def get_presence(self): module = self._get_my_module() if module is not None: return module.get_presence() return False def get_status(self): module = self._get_my_module() if module is not None: return module.get_status() return False def get_reboot_cause(self): unknown = (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None) # if reboot cause is non-hardware, return NON_HARDWARE return unknown def _get_my_module(self): module = None my_slot = self.get_my_slot() supervisor_slot = self.get_supervisor_slot() if supervisor_slot == my_slot: index = 0 else: index = self.get_module_index(ModuleBase.MODULE_TYPE_LINE+str(my_slot-1)) module = self.get_module(index) return module def get_status_led(self): color = Chassis.STATUS_LED_COLOR_OFF led_type = platform_ndk_pb2.ReqLedType.LED_TYPE_BOARD_STATUS channel, stub = nokia_common.channel_setup(nokia_common.NOKIA_GRPC_LED_SERVICE) if not channel or not stub: return color ret, response = nokia_common.try_grpc(stub.GetLed, platform_ndk_pb2.ReqLedInfoPb(led_type=led_type)) nokia_common.channel_shutdown(channel) if ret is False: return color color = nokia_common.led_info_to_color(response.led_get.led_info[0]) return color def set_status_led(self, color): led_type = platform_ndk_pb2.ReqLedType.LED_TYPE_BOARD_STATUS _led_info = nokia_common.led_color_to_info(color) channel, stub = nokia_common.channel_setup(nokia_common.NOKIA_GRPC_LED_SERVICE) if not channel or not stub: return False ret, response = nokia_common.try_grpc(stub.SetLed, platform_ndk_pb2.ReqLedInfoPb(led_type=led_type, led_info=_led_info)) nokia_common.channel_shutdown(channel) if ret is False: return False return True def is_modular_chassis(self): return self.is_chassis_modular def get_supervisor_slot(self): return self.cpm_instance def get_my_slot(self): return self.my_instance def get_module_list(self): channel, stub = nokia_common.channel_setup(nokia_common.NOKIA_GRPC_CHASSIS_SERVICE) if not channel or not stub: return ret, response = nokia_common.try_grpc(stub.GetChassisProperties, platform_ndk_pb2.ReqModuleInfoPb()) nokia_common.channel_shutdown(channel) if ret is False: return if self.is_modular_chassis() and not self.is_cpm: index = 0 supervisor = Module(index, ModuleBase.MODULE_TYPE_SUPERVISOR+str(index), ModuleBase.MODULE_TYPE_SUPERVISOR, self.get_supervisor_slot(), self.chassis_stub) supervisor.set_maximum_consumed_power(self.supervisor_power) index = 1 module = Module(index, ModuleBase.MODULE_TYPE_LINE+str(self.get_my_slot()-1), ModuleBase.MODULE_TYPE_LINE, self.get_my_slot(), self.chassis_stub) module.set_maximum_consumed_power(self.line_card_power) self._module_list.append(supervisor) self._module_list.append(module) logger.log_info('Not control card. Adding self into module list') return if self.is_modular_chassis() and self.is_cpm: for property_index in range(len(response.chassis_property.hw_property)): hw_property = response.chassis_property.hw_property[property_index] if hw_property.module_type == platform_ndk_pb2.HwModuleType.HW_MODULE_TYPE_CONTROL: # Single CPM is supported in chassis num_control_cards = 1 for j in range(num_control_cards): module = Module(property_index, ModuleBase.MODULE_TYPE_SUPERVISOR+str(j), ModuleBase.MODULE_TYPE_SUPERVISOR, self.get_supervisor_slot(), self.chassis_stub) module.set_maximum_consumed_power(self.supervisor_power) self._module_list.append(module) elif hw_property.module_type == platform_ndk_pb2.HwModuleType.HW_MODULE_TYPE_LINE: for j in range(hw_property.max_num): module = Module(property_index, ModuleBase.MODULE_TYPE_LINE+str(j), ModuleBase.MODULE_TYPE_LINE, hw_property.slot[j], self.chassis_stub) module.set_maximum_consumed_power(self.line_card_power) self._module_list.append(module) elif hw_property.module_type == platform_ndk_pb2.HwModuleType.HW_MODULE_TYPE_FABRIC: for j in range(hw_property.max_num): module = Module(property_index, ModuleBase.MODULE_TYPE_FABRIC+str(j), ModuleBase.MODULE_TYPE_FABRIC, hw_property.slot[j], self.chassis_stub) module.set_maximum_consumed_power(self.fabric_card_power) self._module_list.append(module) def get_module_index(self, module_name): if not self.is_modular_chassis(): return -1 # For IMM on chassis, return supervisor-index as 0 and self index as 1 if not self.is_cpm: if module_name.startswith(ModuleBase.MODULE_TYPE_SUPERVISOR): return 0 else: return 1 # For CPM on chassis module_index = -1 channel, stub = nokia_common.channel_setup(nokia_common.NOKIA_GRPC_CHASSIS_SERVICE) if not channel or not stub: return module_index ret, response = nokia_common.try_grpc(stub.GetChassisProperties, platform_ndk_pb2.ReqModuleInfoPb()) nokia_common.channel_shutdown(channel) if ret is False: return module_index for property_index in range(len(response.chassis_property.hw_property)): hw_property = response.chassis_property.hw_property[property_index] if hw_property.module_type == platform_ndk_pb2.HwModuleType.HW_MODULE_TYPE_CONTROL: # Single CPM is supported in chassis num_control_cards = 1 elif hw_property.module_type == platform_ndk_pb2.HwModuleType.HW_MODULE_TYPE_LINE: num_line_cards = hw_property.max_num # elif hw_property.module_type == platform_ndk_pb2.HwModuleType.HW_MODULE_TYPE_FABRIC: # num_fabric_cards = hw_property.max_num if module_name.startswith(ModuleBase.MODULE_TYPE_SUPERVISOR): module_index = 0 elif module_name.startswith(ModuleBase.MODULE_TYPE_LINE): import re parse_nums = re.findall(r'\d+', module_name) module_number = int(parse_nums[0]) module_index = num_control_cards + int(module_number) elif module_name.startswith(ModuleBase.MODULE_TYPE_FABRIC): import re parse_nums = re.findall(r'\d+', module_name) module_number = int(parse_nums[0]) module_index = num_control_cards + num_line_cards + int(module_number) return module_index # PSU and power related def _get_psu_list(self): if not self.is_cpm: return [] channel, stub = nokia_common.channel_setup(nokia_common.NOKIA_GRPC_PSU_SERVICE) if not channel or not stub: return ret, response = nokia_common.try_grpc(stub.GetPsuNum, platform_ndk_pb2.ReqPsuInfoPb()) nokia_common.channel_shutdown(channel) if ret is False: return self.num_psus = response.num_psus for i in range(self.num_psus): psu = Psu(i, self.psu_stub) self._psu_list.append(psu) return self._psu_list def _get_modules_consumed_power(self): channel, stub = nokia_common.channel_setup(nokia_common.NOKIA_GRPC_CHASSIS_SERVICE) if not channel or not stub: return ret, response = nokia_common.try_grpc(stub.GetModuleMaxPower, platform_ndk_pb2.ReqModuleInfoPb()) nokia_common.channel_shutdown(channel) if ret is False: return i = 0 while i < len(response.power_info.module_power): module_info = response.power_info.module_power[i] i = i + 1 type = module_info.module_type if type == platform_ndk_pb2.HwModuleType.HW_MODULE_TYPE_CONTROL: self.supervisor_power = module_info.module_maxpower elif type == platform_ndk_pb2.HwModuleType.HW_MODULE_TYPE_LINE: self.line_card_power = module_info.module_maxpower elif type == platform_ndk_pb2.HwModuleType.HW_MODULE_TYPE_FABRIC: self.fabric_card_power = module_info.module_maxpower elif type == platform_ndk_pb2.HwModuleType.HW_MODULE_TYPE_FANTRAY: self.fantray_power = module_info.module_maxpower # Fan related def _get_fantray_list(self): if not self.is_cpm: return [] channel, stub = nokia_common.channel_setup(nokia_common.NOKIA_GRPC_FAN_SERVICE) if not channel or not stub: return ret, response = nokia_common.try_grpc(stub.GetFanNum, platform_ndk_pb2.ReqFanTrayOpsPb()) nokia_common.channel_shutdown(channel) if ret is False: return self.num_fantrays = response.fan_nums.num_fantrays fan_index = 0 for drawer_index in range(self.num_fantrays): fan_drawer = FanDrawer(drawer_index) fan_drawer.set_maximum_consumed_power(self.fantray_power) fan = Fan(fan_index, drawer_index, False, self.fan_stub) fan_drawer._fan_list.append(fan) fan_index = fan_index + 1 self._fan_drawer_list.append(fan_drawer) return self._fan_drawer_list def allow_fan_platform_override(self): from os import path if path.exists(nokia_common.NOKIA_ALLOW_FAN_OVERRIDE_FILE): return True return False # Thermal related def get_thermal_list(self): channel, stub = nokia_common.channel_setup(nokia_common.NOKIA_GRPC_THERMAL_SERVICE) if not channel or not stub: return ret, response = nokia_common.try_grpc(stub.GetThermalDevicesInfo, platform_ndk_pb2.ReqTempParamsPb()) nokia_common.channel_shutdown(channel) if ret is False: return all_temp_devices = response.temp_devices self.num_thermals = len(all_temp_devices.temp_device) i = 0 # Empty previous list if len(self._thermal_list) != self.num_thermals: del self._thermal_list[:] for i in range(self.num_thermals): temp_device_ = all_temp_devices.temp_device[i] thermal = Thermal(i, temp_device_.device_idx, temp_device_.sensor_name, self.thermal_stub) self._thermal_list.append(thermal) def get_all_thermals(self): self.get_thermal_list() return self._thermal_list def get_thermal_manager(self): from .thermal_manager import ThermalManager return ThermalManager def _get_component_list(self): channel, stub = nokia_common.channel_setup(nokia_common.NOKIA_GRPC_FIRMWARE_SERVICE) if not channel or not stub: return ret, response = nokia_common.try_grpc(stub.HwFirmwareGetComponents, platform_ndk_pb2.ReqHwFirmwareInfoPb()) nokia_common.channel_shutdown(channel) if ret is False: return for i in range(len(response.firmware_info.component)): hw_dev = response.firmware_info.component[i] component = Component(i, hw_dev.dev_type, hw_dev.dev_name, hw_dev.dev_desc, self.firmware_stub) self._component_list.append(component) # SFP operations below def initialize_sfp(self): from sonic_platform.sfp import Sfp if not nokia_common.is_cpm(): if self.sfp_module_initialized: logger.log_error("SFPs are already initialized! stub {}".format(self.sfp_stub)) return self.sfp_stub = None for index in range(1, NUM_SFP+1): logger.log_info("Creating SFP '%d'" % index) # default to QSFP-DD type for the moment. Type gets set dynamically when module is read sfp = Sfp(index, 'QSFP-DD', self.sfp_stub) self._sfp_list.append(sfp) # force 1st read to dynamically set type and detect dom capability sfp.get_transceiver_info() sfp._dom_capability_detect() self.sfp_module_initialized = True logger.log_info("SFPs are now initialized... stub {}".format(self.sfp_stub)) def get_change_event(self, timeout=0): # logger.log_error("Get-change-event with thread-{} start ".format( # str(os.getpid())+str(threading.current_thread().ident))) if not self.sfp_event_initialized: from sonic_platform.sfp_event import sfp_event # use the same stub as direct sfp ops does self.sfp_event_stub = self.sfp_stub logger.log_info("Initializing sfp_event with num {} and stub {} : sfp stub {}".format( NUM_SFP, self.sfp_event_stub, self.sfp_stub)) self.sfp_event_list = sfp_event(NUM_SFP, self.sfp_event_stub) self.sfp_event_list.initialize() self.sfp_event_initialized = True timeout = 0 port_dict = {} self.sfp_event_list.check_sfp_status(port_dict, timeout) return True, {'sfp': port_dict} def get_num_sfps(self): """ Retrieves the number of sfps available on this chassis Returns: An integer, the number of sfps available on this chassis """ if not self.sfp_module_initialized: self.initialize_sfp() return len(self._sfp_list) def get_all_sfps(self): """ Retrieves all sfps available on this chassis Returns: A list of objects derived from SfpBase representing all sfps available on this chassis """ if not self.sfp_module_initialized: self.initialize_sfp() return self._sfp_list def get_sfp(self, index): """ Retrieves sfp represented by (1-based) index <index> Args: index: An integer, the index (1-based) of the sfp to retrieve. The index should be the sequence of a physical port in a chassis, starting from 1. For example, 1 for Ethernet0, 2 for Ethernet4 and so on. Returns: An object dervied from SfpBase representing the specified sfp """ sfp = None if not self.sfp_module_initialized: self.initialize_sfp() try: # The index will start from 1 sfp = self._sfp_list[index-1] except IndexError: logger.log_error("SFP index {} out of range (1-{})\n".format( index, len(self._sfp_list))) return sfp # System eeprom below def get_name(self): """ Retrieves the hardware product name for the chassis Returns: A string containing the hardware product name for this chassis. """ return self._eeprom.get_product_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.get_base_mac() def get_serial(self): """ Retrieves the hardware serial number for the chassis Returns: A string containing the hardware serial number for this chassis. """ return self._eeprom.get_serial_number() def get_serial_number(self): """ Retrieves the hardware serial number for the chassis Returns: A string containing the hardware serial number for this chassis. """ return self._eeprom.get_serial_number() def get_model(self): """ Retrieves the model number (or part number) of the chassis Returns: string: Model/part number of chassis """ return self._eeprom.get_part_number() def get_system_eeprom_info(self): """ Retrieves the full content of system EEPROM information for the chassis Returns: A dictionary where keys are the type code defined in OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ return self._eeprom.get_system_eeprom_info() def get_eeprom(self): """ Retrieves the Sys Eeprom instance for the chassis. Returns : The instance of the Sys Eeprom """ return self._eeprom # Midplane def init_midplane_switch(self): 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 this device is replaceable. Returns: bool: True if it is replaceable. """ return False # Test suitest def test_suite_chassis(self): print("Starting Chassis UT") from sonic_platform.test import test_chassis test_chassis.run_all(self) def test_suite_psu(self): print("Starting PSUs UT") from sonic_platform.test import test_psu test_psu.run_all(self._psu_list) # UT related helper apis def empty_fan_drawer_list(self): for fantray in self.get_all_fan_drawers(): del fantray._fan_list[:] del self._fan_drawer_list[:] def empty_fan_list(self, fantray_idx): fantray = self.get_fan_drawer(fantray_idx) del fantray._fan_list[:]
class FanDrawer(FanDrawerBase): """DellEMC Platform-specific Fan Drawer class""" CPLD_DIR = "/sys/devices/platform/dell-s6000-cpld.0/" def __init__(self, fantray_index): FanDrawerBase.__init__(self) # FanTray is 1-based in DellEMC platforms self.index = fantray_index + 1 self.eeprom = Eeprom(is_fantray=True, fantray_index=self.index) self.fantray_presence_reg = "fan_prs" self.fantray_led_reg = "fan{}_led".format(self.index - 1) self.supported_led_color = ['off', 'green', 'amber'] for i in range(1, MAX_S6000_FANS_PER_FANTRAY + 1): self._fan_list.append( Fan(fantray_index=self.index, fan_index=i, dependency=self)) def _get_cpld_register(self, reg_name): # On successful read, returns the value read from given # reg_name and on failure returns 'ERR' rv = 'ERR' cpld_reg_file = self.CPLD_DIR + reg_name if (not os.path.isfile(cpld_reg_file)): return rv try: with open(cpld_reg_file, 'r') as fd: rv = fd.read() except IOError: rv = 'ERR' rv = rv.rstrip('\r\n') rv = rv.lstrip(" ") return rv def _set_cpld_register(self, reg_name, value): # On successful write, returns the value will be written on # reg_name and on failure returns 'ERR' rv = 'ERR' cpld_reg_file = self.CPLD_DIR + reg_name if (not os.path.isfile(cpld_reg_file)): return rv try: with open(cpld_reg_file, 'w') as fd: rv = fd.write(str(value)) except IOError: rv = 'ERR' return rv def get_name(self): """ Retrieves the Fandrawer name Returns: string: The name of the device """ return "FanTray{}".format(self.index) def get_presence(self): """ Retrieves the presence of the Fandrawer Returns: bool: True if Fandrawer is present, False if not """ presence = False fantray_presence = self._get_cpld_register(self.fantray_presence_reg) if (fantray_presence != 'ERR'): fantray_presence = int(fantray_presence, 16) & (1 << (self.index - 1)) if fantray_presence: presence = True return presence def get_model(self): """ Retrieves the part number of the Fandrawer Returns: string: Part number of Fandrawer """ return self.eeprom.get_part_number() def get_serial(self): """ Retrieves the serial number of the Fandrawer Returns: string: Serial number of Fandrawer """ # Sample Serial number format "US-01234D-54321-25A-0123-A00" return self.eeprom.get_serial_number() def get_status(self): """ Retrieves the operational status of the Fandrawer Returns: bool: True if Fandrawer is operating properly, False if not """ status = True for fan in self.get_all_fans(): status &= fan.get_status() return status 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 self.index def is_replaceable(self): """ Indicate whether this fan drawer is replaceable. Returns: bool: True if it is replaceable. """ return True def set_status_led(self, color): """ Set led to expected color Args: color: A string representing the color with which to set the fandrawer status LED Returns: bool: True if set success, False if fail. """ if color not in self.supported_led_color: return False if color == self.STATUS_LED_COLOR_AMBER: color = 'yellow' rv = self._set_cpld_register(self.fantray_led_reg, color) if (rv != 'ERR'): return True else: return False def get_status_led(self): """ Gets the state of the fandrawer status LED Returns: A string, one of the predefined STATUS_LED_COLOR_* strings. """ fantray_led = self._get_cpld_register(self.fantray_led_reg) if (fantray_led != 'ERR'): if (fantray_led == 'yellow'): return self.STATUS_LED_COLOR_AMBER else: return fantray_led else: return self.STATUS_LED_COLOR_OFF def get_maximum_consumed_power(self): """ Retrives the maximum power drawn by Fan Drawer Returns: A float, with value of the maximum consumable power of the component. """ return 18.0
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 reset_reason_dict[0x7] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER _num_monitor_thermals = 3 _monitor_thermal_list = [] _is_fan_control_enabled = False _fan_control_initialised = False def __init__(self): ChassisBase.__init__(self) self.status_led_reg = "system_led" self.supported_led_color = [ 'green', 'blinking green', 'amber', 'blinking amber' ] # 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() with open("/sys/class/dmi/id/product_name", "r") as fd: board_type = fd.read() if 'S6000-ON' in board_type: self._eeprom = Eeprom() else: self._eeprom = EepromS6000() for i in range(MAX_S6000_FANTRAY): fandrawer = FanDrawer(i) self._fan_drawer_list.append(fandrawer) self._fan_list.extend(fandrawer._fan_list) 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 IOError: rv = 'ERR' rv = rv.rstrip('\r\n') rv = rv.lstrip(" ") return rv def _set_cpld_register(self, reg_name, value): # On successful write, returns the value will be written on # reg_name and on failure returns 'ERR' rv = 'ERR' cpld_reg_file = self.CPLD_DIR + '/' + reg_name if (not os.path.isfile(cpld_reg_file)): return rv try: with open(cpld_reg_file, 'w') as fd: rv = fd.write(str(value)) except IOError: rv = 'ERR' return rv def _nvram_write(self, offset, val): resource = "/dev/nvram" fd = os.open(resource, os.O_RDWR) if (fd < 0): print('File open failed ', resource) return if (os.lseek(fd, offset, os.SEEK_SET) != offset): print('lseek failed on ', resource) return ret = os.write(fd, struct.pack('B', val)) if ret != 1: print('Write failed ', str(ret)) return os.close(fd) def _init_fan_control(self): if not self._fan_control_initialised: for i in range(self._num_monitor_thermals): self._monitor_thermal_list.append(Thermal(i)) self._fan_control_initialised = True def get_name(self): """ Retrieves the name of the chassis Returns: string: The name of the chassis """ return self._eeprom.get_model() 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.get_part_number() def get_serial(self): """ Retrieves the serial number of the chassis (Service tag) Returns: string: Serial number of chassis """ return self._eeprom.get_serial() 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.get_base_mac() 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_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. """ start_time = time.time() port_dict = {} ret_dict = {"sfp": 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, ret_dict # 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, ret_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, ret_dict return False, 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 # Change color string format to the one used by driver color = color.replace('amber', 'yellow') color = color.replace('blinking ', 'blink_') rv = self._set_cpld_register(self.status_led_reg, color) 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. """ status_led = self._get_cpld_register(self.status_led_reg) if (status_led != 'ERR'): status_led = status_led.replace('yellow', 'amber') status_led = status_led.replace('blink_', 'blinking ') return status_led else: return None def get_thermal_manager(self): """ Retrieves thermal manager class on this chassis Returns: A class derived from ThermalManagerBase representing the specified thermal manager """ from .thermal_manager import ThermalManager return ThermalManager def set_fan_control_status(self, enable): if enable and not self._is_fan_control_enabled: self._init_fan_control() for thermal in self._monitor_thermal_list: thermal.set_high_threshold(LEVEL5_THRESHOLD, force=True) self._is_fan_control_enabled = True elif not enable and self._is_fan_control_enabled: for thermal in self._monitor_thermal_list: thermal.set_high_threshold(LEVEL4_THRESHOLD, force=True) self._is_fan_control_enabled = False def get_monitor_thermals(self): return self._monitor_thermal_list def thermal_shutdown(self): # Update reboot cause self._nvram_write(0x49, 0x7) subprocess.call('sync') time.sleep(1) for thermal in self._monitor_thermal_list: thermal.set_high_threshold(LEVEL4_THRESHOLD, force=True) @staticmethod def get_system_thermal_level(curr_thermal_level, system_temperature): def get_level_in_hystersis(curr_level, level1, level2): if curr_level != level1 and curr_level != level2: return level1 if abs(curr_level - level1) < abs(curr_level - level2) else level2 else: return curr_level if system_temperature < LEVEL0_THRESHOLD: curr_thermal_level = 0 elif LEVEL0_THRESHOLD <= system_temperature < LEVEL1_THRESHOLD: curr_thermal_level = get_level_in_hystersis( curr_thermal_level, 0, 1) elif LEVEL1_THRESHOLD <= system_temperature <= (LEVEL2_THRESHOLD - HYST_RANGE): curr_thermal_level = 1 elif (LEVEL2_THRESHOLD - HYST_RANGE) < system_temperature < LEVEL2_THRESHOLD: curr_thermal_level = get_level_in_hystersis( curr_thermal_level, 1, 2) elif LEVEL2_THRESHOLD <= system_temperature <= (LEVEL3_THRESHOLD - HYST_RANGE): curr_thermal_level = 2 elif (LEVEL3_THRESHOLD - HYST_RANGE) < system_temperature < LEVEL3_THRESHOLD: curr_thermal_level = get_level_in_hystersis( curr_thermal_level, 2, 3) elif LEVEL3_THRESHOLD <= system_temperature < LEVEL4_THRESHOLD: curr_thermal_level = 3 else: curr_thermal_level = 4 return curr_thermal_level @staticmethod def is_over_temperature(temperature_list): over_temperature = False for temperature in temperature_list: if temperature > LEVEL4_THRESHOLD: over_temperature = True break return over_temperature