class Thermal(ThermalBase): """Platform-specific Thermal class""" THERMAL_NAME_LIST = [] I2C_ADAPTER_PATH = "/sys/class/i2c-adapter" SS_CONFIG_PATH = "/usr/share/sonic/device/x86_64-cel_seastone-r0/sensors.conf" def __init__(self, thermal_index): self.index = thermal_index self._api_helper = APIHelper() # Add thermal name self.THERMAL_NAME_LIST.append("Front-panel temp sensor 1") self.THERMAL_NAME_LIST.append("Front-panel temp sensor 2") self.THERMAL_NAME_LIST.append("ASIC temp sensor") self.THERMAL_NAME_LIST.append("Rear-panel temp sensor 1") self.THERMAL_NAME_LIST.append("Rear-panel temp sensor 2") # Set hwmon path i2c_path = { 0: "i2c-5/5-0048/hwmon/hwmon1", # u4 system-inlet 1: "i2c-6/6-0049/hwmon/hwmon2", # u2 system-inlet 2: "i2c-7/7-004a/hwmon/hwmon3", # u44 bmc56960-on-board 3: "i2c-14/14-0048/hwmon/hwmon4", # u9200 cpu-on-board 4: "i2c-15/15-004e/hwmon/hwmon5" # u9201 system-outlet }.get(self.index, None) self.hwmon_path = "{}/{}".format(self.I2C_ADAPTER_PATH, i2c_path) self.ss_key = self.THERMAL_NAME_LIST[self.index] self.ss_index = 1 def __get_temp(self, temp_file): temp_file_path = os.path.join(self.hwmon_path, temp_file) raw_temp = self._api_helper.read_txt_file(temp_file_path) temp = float(raw_temp) / 1000 return float("{:.3f}".format(temp)) def __set_threshold(self, file_name, temperature): temp_file_path = os.path.join(self.hwmon_path, file_name) try: with open(temp_file_path, 'w') as fd: fd.write(str(temperature)) return True except IOError: return False def get_temperature(self): """ Retrieves current temperature reading from thermal Returns: A float number of current temperature in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ temp_file = "temp{}_input".format(self.ss_index) return self.__get_temp(temp_file) def get_high_threshold(self): """ Retrieves the high threshold temperature of thermal Returns: A float number, the high threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ temp_file = "temp{}_max".format(self.ss_index) return self.__get_temp(temp_file) def set_high_threshold(self, temperature): """ Sets the high threshold temperature of thermal Args : temperature: A float number up to nearest thousandth of one degree Celsius, e.g. 30.125 Returns: A boolean, True if threshold is set successfully, False if not """ temp_file = "temp{}_max".format(self.ss_index) is_set = self.__set_threshold(temp_file, int(temperature * 1000)) file_set = False if is_set: try: with open(self.SS_CONFIG_PATH, 'r+') as f: content = f.readlines() f.seek(0) ss_found = False for idx, val in enumerate(content): if self.ss_key in val: ss_found = True elif ss_found and temp_file in val: content[idx] = " set {} {}\n".format( temp_file, temperature) f.writelines(content) file_set = True break except IOError: file_set = False return is_set & file_set def get_name(self): """ Retrieves the name of the thermal device Returns: string: The name of the thermal device """ return self.THERMAL_NAME_LIST[self.index] def get_presence(self): """ Retrieves the presence of the PSU Returns: bool: True if PSU is present, False if not """ temp_file = "temp{}_input".format(self.ss_index) temp_file_path = os.path.join(self.hwmon_path, temp_file) return os.path.isfile(temp_file_path) def get_status(self): """ Retrieves the operational status of the device Returns: A boolean value, True if device is operating properly, False if not """ if not self.get_presence(): return False fault_file = "temp{}_fault".format(self.ss_index) fault_file_path = os.path.join(self.hwmon_path, fault_file) if not os.path.isfile(fault_file_path): return True raw_txt = self.__read_txt_file(fault_file_path) return int(raw_txt) == 0
class Chassis(ChassisBase): """Platform-specific Chassis class""" def __init__(self): ChassisBase.__init__(self) self._api_helper = APIHelper() self.sfp_module_initialized = False self.__initialize_eeprom() self.is_host = self._api_helper.is_host() if not self.is_host: self.__initialize_fan() self.__initialize_psu() self.__initialize_thermals() else: self.__initialize_components() def __initialize_sfp(self): from sonic_platform.sfp import Sfp for index in range(0, NUM_SFP): sfp = Sfp(index) self._sfp_list.append(sfp) self.sfp_module_initialized = True def __initialize_psu(self): from sonic_platform.psu import Psu for index in range(0, NUM_PSU): psu = Psu(index) self._psu_list.append(psu) def __initialize_fan(self): from sonic_platform.fan import Fan for fant_index in range(0, NUM_FAN_TRAY): for fan_index in range(0, NUM_FAN): fan = Fan(fant_index, fan_index) self._fan_list.append(fan) def __initialize_thermals(self): from sonic_platform.thermal import Thermal for index in range(0, NUM_THERMAL): thermal = Thermal(index) self._thermal_list.append(thermal) def __initialize_eeprom(self): from sonic_platform.eeprom import Tlv self._eeprom = Tlv() def __initialize_components(self): from sonic_platform.component import Component for index in range(0, NUM_COMPONENT): component = Component(index) self._component_list.append(component) 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_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.get_eeprom() 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. REBOOT_CAUSE_POWER_LOSS = "Power Loss" REBOOT_CAUSE_THERMAL_OVERLOAD_CPU = "Thermal Overload: CPU" REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC = "Thermal Overload: ASIC" REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER = "Thermal Overload: Other" REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED = "Insufficient Fan Speed" REBOOT_CAUSE_WATCHDOG = "Watchdog" REBOOT_CAUSE_HARDWARE_OTHER = "Hardware - Other" REBOOT_CAUSE_NON_HARDWARE = "Non-Hardware" """ reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) sw_reboot_cause = self._api_helper.read_txt_file( reboot_cause_path) or "Unknown" hw_reboot_cause = self._api_helper.get_cpld_reg_value( GETREG_PATH, RESET_REGISTER) prev_reboot_cause = { '0x11': (self.REBOOT_CAUSE_POWER_LOSS, 'Power on reset'), '0x22': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'CPLD_WD_RESET'), '0x33': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'Power cycle reset triggered by CPU'), '0x44': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'Power cycle reset triggered by reset button'), '0x55': (self.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU, ''), '0x66': (self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC, ''), '0x77': (self.REBOOT_CAUSE_WATCHDOG, '') }.get(hw_reboot_cause, (self.REBOOT_CAUSE_HARDWARE_OTHER, 'Unknown reason')) if sw_reboot_cause != 'Unknown' and hw_reboot_cause == '0x11': prev_reboot_cause = ( self.REBOOT_CAUSE_NON_HARDWARE, sw_reboot_cause) return prev_reboot_cause ############################################################## ######################## SFP methods ######################### ############################################################## def get_num_sfps(self): """ Retrieves the number of sfps available on this chassis Returns: An integer, the number of sfps available on this chassis """ if not self.sfp_module_initialized: self.__initialize_sfp() return len(self._sfp_list) def get_all_sfps(self): """ Retrieves all sfps available on this chassis Returns: A list of objects derived from SfpBase representing all sfps available on this chassis """ if not self.sfp_module_initialized: self.__initialize_sfp() return self._sfp_list def get_sfp(self, index): """ Retrieves sfp represented by (1-based) index <index> Args: index: An integer, the index (1-based) of the sfp to retrieve. The index should be the sequence of a physical port in a chassis, starting from 1. For example, 1 for Ethernet0, 2 for Ethernet4 and so on. Returns: An object dervied from SfpBase representing the specified sfp """ 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: sys.stderr.write("SFP index {} out of range (1-{})\n".format( index, len(self._sfp_list))) return sfp ############################################################## ####################### Other methods ######################## ############################################################## def get_watchdog(self): """ Retreives hardware watchdog device on this chassis Returns: An object derived from WatchdogBase representing the hardware watchdog device """ if self._watchdog is None: from sonic_platform.watchdog import Watchdog self._watchdog = Watchdog() return self._watchdog ############################################################## ###################### Device methods ######################## ############################################################## def get_name(self): """ Retrieves the name of the device Returns: string: The name of the device """ return self._api_helper.hwsku 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 device Returns: string: Model/part number of device """ return self._eeprom.get_pn() def get_serial(self): """ Retrieves the serial number of the device Returns: string: Serial number of device """ return self._eeprom.get_serial() def get_status(self): """ Retrieves the operational status of the device Returns: A boolean value, True if device is operating properly, False if not """ return True
class Chassis(ChassisBase): """Platform-specific Chassis class""" def __init__(self): ChassisBase.__init__(self) self._api_helper = APIHelper() self.sfp_module_initialized = False self.__initialize_eeprom() self.is_host = self._api_helper.is_host() if not self.is_host: self.__initialize_fan() self.__initialize_psu() self.__initialize_thermals() else: self.__initialize_components() def __initialize_sfp(self): from sonic_platform.sfp import Sfp for index in range(0, NUM_SFP): sfp = Sfp(index) self._sfp_list.append(sfp) self.sfp_module_initialized = True def __initialize_psu(self): from sonic_platform.psu import Psu for index in range(0, NUM_PSU): psu = Psu(index) self._psu_list.append(psu) def __initialize_fan(self): from sonic_platform.fan import Fan for fant_index in range(0, NUM_FAN_TRAY): for fan_index in range(0, NUM_FAN): fan = Fan(fant_index, fan_index) self._fan_list.append(fan) def __initialize_thermals(self): from sonic_platform.thermal import Thermal for index in range(0, NUM_THERMAL): thermal = Thermal(index) self._thermal_list.append(thermal) def __initialize_eeprom(self): from sonic_platform.eeprom import Tlv self._eeprom = Tlv() def __initialize_components(self): from sonic_platform.component import Component for index in range(0, NUM_COMPONENT): component = Component(index) self._component_list.append(component) 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_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() 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_eeprom() 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 = ( HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE ) if self.is_host else PMON_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE prev_reboot_cause_path = ( HOST_REBOOT_CAUSE_PATH + PREV_REBOOT_CAUSE_FILE ) if self.is_host else PMON_REBOOT_CAUSE_PATH + PREV_REBOOT_CAUSE_FILE hw_reboot_cause = self._component_list[0].get_register_value( RESET_REGISTER) sw_reboot_cause = self._api_helper.read_txt_file( reboot_cause_path) or "Unknown" prev_sw_reboot_cause = self._api_helper.read_txt_file( prev_reboot_cause_path) or "Unknown" if sw_reboot_cause == "Unknown" and ( prev_sw_reboot_cause == "Unknown" or prev_sw_reboot_cause == self.REBOOT_CAUSE_POWER_LOSS) and hw_reboot_cause == "0x11": reboot_cause = self.REBOOT_CAUSE_POWER_LOSS elif sw_reboot_cause != "Unknown" and hw_reboot_cause == "0x11": reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE description = sw_reboot_cause elif prev_reboot_cause_path != "Unknown" and hw_reboot_cause == "0x11": reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE description = prev_sw_reboot_cause elif hw_reboot_cause == "0x22": reboot_cause = self.REBOOT_CAUSE_WATCHDOG, else: reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER description = 'Unknown reason' return (reboot_cause, description) ############################################################## ######################## SFP methods ######################### ############################################################## def get_num_sfps(self): """ Retrieves the number of sfps available on this chassis Returns: An integer, the number of sfps available on this chassis """ if not self.sfp_module_initialized: self.__initialize_sfp() return len(self._sfp_list) def get_all_sfps(self): """ Retrieves all sfps available on this chassis Returns: A list of objects derived from SfpBase representing all sfps available on this chassis """ if not self.sfp_module_initialized: self.__initialize_sfp() return self._sfp_list def get_sfp(self, index): """ Retrieves sfp represented by (1-based) index <index> Args: index: An integer, the index (1-based) of the sfp to retrieve. The index should be the sequence of a physical port in a chassis, starting from 1. For example, 1 for Ethernet0, 2 for Ethernet4 and so on. Returns: An object dervied from SfpBase representing the specified sfp """ 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: sys.stderr.write("SFP index {} out of range (1-{})\n".format( index, len(self._sfp_list))) return sfp ############################################################## ####################### Other methods ######################## ############################################################## def get_watchdog(self): """ Retreives hardware watchdog device on this chassis Returns: An object derived from WatchdogBase representing the hardware watchdog device """ if self._watchdog is None: from sonic_platform.watchdog import Watchdog self._watchdog = Watchdog() return self._watchdog ############################################################## ###################### Device methods ######################## ############################################################## def get_name(self): """ Retrieves the name of the device Returns: string: The name of the device """ return self._api_helper.hwsku def get_presence(self): """ Retrieves the presence of the PSU Returns: bool: True if PSU is present, False if not """ return True def get_model(self): """ Retrieves the model number (or part number) of the device Returns: string: Model/part number of device """ return self._eeprom.get_pn() def get_serial(self): """ Retrieves the serial number of the device Returns: string: Serial number of device """ return self.get_serial_number() def get_status(self): """ Retrieves the operational status of the device Returns: A boolean value, True if device is operating properly, False if not """ return True
class Psu(PsuBase): """Platform-specific Psu class""" def __init__(self, psu_index): PsuBase.__init__(self) self.index = psu_index self._api_helper = APIHelper() self.green_led_path = GREEN_LED_PATH.format(self.index + 1) self.dx010_psu_gpio = [{ 'base': self.__get_gpio_base() }, { 'prs': 27, 'status': 22 }, { 'prs': 28, 'status': 25 }] self.i2c_num = PSU_I2C_MAPPING[self.index]["num"] self.i2c_addr = PSU_I2C_MAPPING[self.index]["addr"] self.hwmon_path = HWMON_PATH.format(self.i2c_num, self.i2c_addr) for fan_index in range(0, PSU_NUM_FAN[self.index]): fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) self._fan_list.append(fan) def __search_file_by_contain(self, directory, search_str, file_start): for dirpath, dirnames, files in os.walk(directory): for name in files: file_path = os.path.join(dirpath, name) if name.startswith( file_start ) and search_str in self._api_helper.read_txt_file(file_path): return file_path return None def __get_gpio_base(self): for r in os.listdir(GPIO_DIR): label_path = os.path.join(GPIO_DIR, r, "label") if "gpiochip" in r and GPIO_LABEL in self._api_helper.read_txt_file( label_path): return int(r[8:], 10) return 216 # Reserve def __get_gpio_value(self, pinnum): gpio_base = self.dx010_psu_gpio[0]['base'] gpio_dir = GPIO_DIR + '/gpio' + str(gpio_base + pinnum) gpio_file = gpio_dir + "/value" retval = self._api_helper.read_txt_file(gpio_file) return retval.rstrip('\r\n') def get_voltage(self): """ Retrieves current PSU voltage output Returns: A float number, the output voltage in volts, e.g. 12.1 """ psu_voltage = 0.0 voltage_name = "in{}_input" voltage_label = "vout1" vout_label_path = self.__search_file_by_contain( self.hwmon_path, voltage_label, "in") if vout_label_path: dir_name = os.path.dirname(vout_label_path) basename = os.path.basename(vout_label_path) in_num = filter(str.isdigit, basename) vout_path = os.path.join(dir_name, voltage_name.format(in_num)) vout_val = self._api_helper.read_txt_file(vout_path) psu_voltage = float(vout_val) / 1000 return psu_voltage def get_current(self): """ Retrieves present electric current supplied by PSU Returns: A float number, the electric current in amperes, e.g 15.4 """ psu_current = 0.0 current_name = "curr{}_input" current_label = "iout1" curr_label_path = self.__search_file_by_contain( self.hwmon_path, current_label, "cur") if curr_label_path: dir_name = os.path.dirname(curr_label_path) basename = os.path.basename(curr_label_path) cur_num = filter(str.isdigit, basename) cur_path = os.path.join(dir_name, current_name.format(cur_num)) cur_val = self._api_helper.read_txt_file(cur_path) psu_current = float(cur_val) / 1000 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 = 0.0 current_name = "power{}_input" current_label = "pout1" pw_label_path = self.__search_file_by_contain(self.hwmon_path, current_label, "power") if pw_label_path: dir_name = os.path.dirname(pw_label_path) basename = os.path.basename(pw_label_path) pw_num = filter(str.isdigit, basename) pw_path = os.path.join(dir_name, current_name.format(pw_num)) pw_val = self._api_helper.read_txt_file(pw_path) psu_power = float(pw_val) / 1000000 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. """ return self.get_status() 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 Note: Only support green and off Returns: bool: True if status LED state is set successfully, False if not """ set_status_str = { self.STATUS_LED_COLOR_GREEN: '1', self.STATUS_LED_COLOR_OFF: '0' }.get(color, None) if not set_status_str: return False try: with open(self.green_led_path, 'w') as file: file.write(set_status_str) except IOError: return False return True def get_status_led(self): """ Gets the state of the PSU status LED Returns: A string, one of the predefined STATUS_LED_COLOR_* strings above """ status = self._api_helper.read_txt_file(self.green_led_path) status_str = { '255': self.STATUS_LED_COLOR_GREEN, '0': self.STATUS_LED_COLOR_OFF }.get(status, None) return status_str def get_name(self): """ Retrieves the name of the device Returns: string: The name of the device """ return PSU_NAME_LIST[self.index] def get_presence(self): """ Retrieves the presence of the PSU Returns: bool: True if PSU is present, False if not """ raw = self.__get_gpio_value(self.dx010_psu_gpio[self.index + 1]['prs']) return int(raw, 10) == 0 def get_status(self): """ Retrieves the operational status of the device Returns: A boolean value, True if device is operating properly, False if not """ raw = self.__get_gpio_value(self.dx010_psu_gpio[self.index + 1]['status']) return int(raw, 10) == 1
class Fan(FanBase): """Platform-specific Fan class""" def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): FanBase.__init__(self) self.fan_index = fan_index self._api_helper = APIHelper() self.fan_tray_index = fan_tray_index self.is_psu_fan = is_psu_fan if self.is_psu_fan: self.psu_index = psu_index self.psu_i2c_num = PSU_I2C_MAPPING[self.psu_index]["num"] self.psu_i2c_addr = PSU_I2C_MAPPING[self.psu_index]["addr"] self.psu_hwmon_path = PSU_HWMON_PATH.format( self.psu_i2c_num, self.psu_i2c_addr) # dx010 fan attributes # Two EMC2305s located at i2c-13-4d and i2c-13-2e # to control a dual-fan module. self.emc2305_chip_mapping = [ { 'device': "13-002e", 'index_map': [2, 1, 4, 5, 3] }, { 'device': "13-004d", 'index_map': [2, 4, 5, 3, 1] } ] self.dx010_fan_gpio = [ {'base': self.__get_gpio_base()}, {'prs': 11, 'dir': 16, 'color': {'red': 31, 'green': 32}}, # 1 {'prs': 10, 'dir': 15, 'color': {'red': 29, 'green': 30}}, # 2 {'prs': 13, 'dir': 18, 'color': {'red': 35, 'green': 36}}, # 3 {'prs': 14, 'dir': 19, 'color': {'red': 37, 'green': 38}}, # 4 {'prs': 12, 'dir': 17, 'color': {'red': 33, 'green': 34}}, # 5 ] def __write_txt_file(self, file_path, value): try: with open(file_path, 'w') as fd: fd.write(str(value)) except: return False return True def __search_file_by_name(self, directory, file_name): for dirpath, dirnames, files in os.walk(directory): for name in files: file_path = os.path.join(dirpath, name) if name in file_name: return file_path return None def __get_gpio_base(self): for r in os.listdir(GPIO_DIR): label_path = os.path.join(GPIO_DIR, r, "label") if "gpiochip" in r and GPIO_LABEL in self._api_helper.read_txt_file(label_path): return int(r[8:], 10) return 216 # Reserve def __get_gpio_value(self, pinnum): gpio_base = self.dx010_fan_gpio[0]['base'] gpio_dir = GPIO_DIR + '/gpio' + str(gpio_base+pinnum) gpio_file = gpio_dir + "/value" retval = self._api_helper.read_txt_file(gpio_file) return retval.rstrip('\r\n') def __set_gpio_value(self, pinnum, value=0): gpio_base = self.dx010_fan_gpio[0]['base'] gpio_dir = GPIO_DIR + '/gpio' + str(gpio_base+pinnum) gpio_file = gpio_dir + "/value" return self.__write_txt_file(gpio_file, value) def get_direction(self): """ Retrieves the direction of fan Returns: A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST depending on fan direction """ direction = self.FAN_DIRECTION_EXHAUST if not self.is_psu_fan: raw = self.__get_gpio_value( self.dx010_fan_gpio[self.fan_tray_index+1]['dir']) direction = self.FAN_DIRECTION_INTAKE if int( raw, 10) == 0 else self.FAN_DIRECTION_EXHAUST return direction def get_speed(self): """ Retrieves the speed of fan as a percentage of full speed Returns: An integer, the percentage of full fan speed, in the range 0 (off) to 100 (full speed) Note: speed = pwm_in/255*100 """ speed = 0 if self.is_psu_fan: fan_speed_sysfs_name = "fan{}_input".format(self.fan_index+1) fan_speed_sysfs_path = self.__search_file_by_name( self.psu_hwmon_path, fan_speed_sysfs_name) fan_speed_rpm = self._api_helper.read_txt_file( fan_speed_sysfs_path) or 0 fan_speed_raw = float(fan_speed_rpm)/PSU_FAN_MAX_RPM * 100 speed = math.ceil(float(fan_speed_rpm) * 100 / PSU_FAN_MAX_RPM) elif self.get_presence(): chip = self.emc2305_chip_mapping[self.fan_index] device = chip['device'] fan_index = chip['index_map'] sysfs_path = "%s%s/%s" % ( EMC2305_PATH, device, EMC2305_FAN_INPUT) sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index]) raw = self._api_helper.read_txt_file(sysfs_path).strip('\r\n') pwm = int(raw, 10) if raw else 0 speed = math.ceil(float(pwm * 100 / EMC2305_MAX_PWM)) return int(speed) 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) Note: speed_pc = pwm_target/255*100 0 : when PWM mode is use pwm : when pwm mode is not use """ return 'N/A' 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 """ return 10 def set_speed(self, speed): """ Sets the fan speed Args: speed: An integer, the percentage of full fan speed to set fan to, in the range 0 (off) to 100 (full speed) Returns: A boolean, True if speed is set successfully, False if not Note: Depends on pwm or target mode is selected: 1) pwm = speed_pc * 255 <-- Currently use this mode. 2) target_pwm = speed_pc * 100 / 255 2.1) set pwm{}_enable to 3 """ pwm = speed * 255 / 100 if not self.is_psu_fan and self.get_presence(): chip = self.emc2305_chip_mapping[self.fan_index] device = chip['device'] fan_index = chip['index_map'] sysfs_path = "%s%s/%s" % ( EMC2305_PATH, device, EMC2305_FAN_PWM) sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index]) return self.__write_txt_file(sysfs_path, int(pwm)) return False def set_status_led(self, color): """ Sets the state of the fan module status LED Args: color: A string representing the color with which to set the fan module status LED Returns: bool: True if status LED state is set successfully, False if not """ set_status_led = False if not self.is_psu_fan: s1, s2 = False, False try: if color == self.STATUS_LED_COLOR_GREEN: s1 = self.__set_gpio_value( self.dx010_fan_gpio[self.fan_tray_index+1]['color']['red'], 1) s2 = self.__set_gpio_value( self.dx010_fan_gpio[self.fan_tray_index+1]['color']['green'], 0) elif color == self.STATUS_LED_COLOR_RED: s1 = self.__set_gpio_value( self.dx010_fan_gpio[self.fan_tray_index+1]['color']['red'], 0) s2 = self.__set_gpio_value( self.dx010_fan_gpio[self.fan_tray_index+1]['color']['green'], 1) elif color == self.STATUS_LED_COLOR_OFF: s1 = self.__set_gpio_value( self.dx010_fan_gpio[self.fan_tray_index+1]['color']['red'], 1) s2 = self.__set_gpio_value( self.dx010_fan_gpio[self.fan_tray_index+1]['color']['green'], 1) set_status_led = s1 and s2 return set_status_led except IOError: return False return set_status_led def get_name(self): """ Retrieves the name of the device Returns: string: The name of the device """ fan_name = FAN_NAME_LIST[self.fan_tray_index*2 + self.fan_index] if not self.is_psu_fan else "PSU-{} FAN-{}".format( self.psu_index+1, self.fan_index+1) return fan_name def get_presence(self): """ Retrieves the presence of the FAN Returns: bool: True if FAN is present, False if not """ present_str = self.__get_gpio_value( self.dx010_fan_gpio[self.fan_tray_index+1]['prs']) return int(present_str, 10) == 0 if not self.is_psu_fan else True def get_model(self): """ Retrieves the model number (or part number) of the device Returns: string: Model/part number of device """ if self.is_psu_fan: return NULL_VAL model = NULL_VAL return model def get_serial(self): """ Retrieves the serial number of the device Returns: string: Serial number of device """ if self.is_psu_fan: return NULL_VAL serial = NULL_VAL return serial def get_status(self): """ Retrieves the operational status of the device Returns: A boolean value, True if device is operating properly, False if not """ status = 1 if self.is_psu_fan: fan_fault_sysfs_name = "fan1_fault" fan_fault_sysfs_path = self.__search_file_by_name( self.psu_hwmon_path, fan_fault_sysfs_name) status = self._api_helper.read_one_line_file(fan_fault_sysfs_path) elif self.get_presence(): chip = self.emc2305_chip_mapping[self.fan_index] device = chip['device'] fan_index = chip['index_map'] sysfs_path = "%s%s/%s" % ( EMC2305_PATH, device, 'fan{}_fault') sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index]) status = self._api_helper.read_one_line_file(sysfs_path) return False if int(status) != 0 else True
class Component(ComponentBase): """Platform-specific Component class""" DEVICE_TYPE = "component" def __init__(self, component_index): ComponentBase.__init__(self) self.index = component_index self.name = self.get_name() self._api_helper = APIHelper() def __get_bmc_ver(self): bmc_ver = "Unknown" status, raw_bmc_data = self._api_helper.run_command(BMC_VER_CMD) if status: bmc_ver_data = raw_bmc_data.split(":") bmc_ver = bmc_ver_data[-1].strip( ) if len(bmc_ver_data) > 1 else bmc_ver return bmc_ver def __get_fpga_ver(self): fpga_ver = "Unknown" status, reg_val = self._api_helper.pci_get_value( MEM_PCI_RESOURCE, FPGA_VER_MEM_OFFSET) if status: major = reg_val[0] >> 16 minor = int(bin(reg_val[0])[16:32], 2) fpga_ver = '{}.{}'.format(major, minor) return fpga_ver def get_name(self): """ Retrieves the name of the component Returns: A string containing the name of the component """ return COMPONENT_LIST[self.index][0] def get_description(self): """ Retrieves the description of the component Returns: A string containing the description of the component """ return COMPONENT_LIST[self.index][1] def get_firmware_version(self): """ Retrieves the firmware version of module Returns: string: The firmware versions of the module """ fw_version = { "BIOS": self._api_helper.read_txt_file(BIOS_VER_PATH), "BMC": self.__get_bmc_ver(), "FPGA": self.__get_fpga_ver(), "SWITCH_CPLD": self._api_helper.read_txt_file(SW_CPLD_VER_PATH), "BASE_CPLD": self._api_helper.read_txt_file(BASE_CPLD_VER_PATH), }.get(self.name, "Unknown") return fw_version def install_firmware(self, image_path): """ Install firmware to module Args: image_path: A string, path to firmware image Returns: A boolean, True if install successfully, False if not """ install_command = { "BMC": CFUFLASH_FW_UPGRADE_CMD.format(BMC_UPGRADE_OPT, image_path), "BIOS": CFUFLASH_FW_UPGRADE_CMD.format(BIOS__UPGRADE_OPT, image_path), "SWITCH_CPLD": CFUFLASH_FW_UPGRADE_CMD.format(CPLD_UPGRADE_OPT, image_path), "BASE_CPLD": CFUFLASH_FW_UPGRADE_CMD.format(CPLD_UPGRADE_OPT, image_path) }.get(self.name, None) if not os.path.isfile(image_path) or install_command is None: return False # print(install_command) status = self._api_helper.run_interactive_command(install_command) return status
class Thermal(ThermalBase): """Platform-specific Thermal class""" SS_CONFIG_PATH = "/usr/share/sonic/device/x86_64-cel_seastone-r0/sensors.conf" def __init__(self, thermal_index, airflow): self.index = thermal_index self._api_helper = APIHelper() self._airflow = airflow self._thermal_info = THERMAL_INFO[self.index] self._hwmon_path = "{}/{}".format(I2C_ADAPTER_PATH, self._thermal_info["i2c_path"]) self.name = self.get_name() self.postion = self._thermal_info["postion"] self.ss_index = 1 def __get_temp(self, temp_file): temp_file_path = os.path.join(self._hwmon_path, temp_file) raw_temp = self._api_helper.read_txt_file(temp_file_path) temp = float(raw_temp) / 1000 return float("{:.3f}".format(temp)) def __set_threshold(self, file_name, temperature): temp_file_path = os.path.join(self._hwmon_path, file_name) try: with open(temp_file_path, 'w') as fd: fd.write(str(temperature)) return True except IOError: return False def get_temperature(self): """ Retrieves current temperature reading from thermal Returns: A float number of current temperature in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ temp_file = "temp{}_input".format(self.ss_index) return self.__get_temp(temp_file) def get_high_threshold(self): """ Retrieves the high threshold temperature of thermal Returns: A float number, the high threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ max_crit_key = '{}_max'.format(self._airflow) return self._thermal_info.get(max_crit_key, None) def get_low_threshold(self): """ Retrieves the low threshold temperature of thermal Returns: A float number, the low threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ return 0.0 def set_high_threshold(self, temperature): """ Sets the high threshold temperature of thermal Args : temperature: A float number up to nearest thousandth of one degree Celsius, e.g. 30.125 Returns: A boolean, True if threshold is set successfully, False if not """ temp_file = "temp{}_max".format(self.ss_index) is_set = self.__set_threshold(temp_file, int(temperature * 1000)) file_set = False if is_set: try: with open(self.SS_CONFIG_PATH, 'r+') as f: content = f.readlines() f.seek(0) ss_found = False for idx, val in enumerate(content): if self.name in val: ss_found = True elif ss_found and temp_file in val: content[idx] = " set {} {}\n".format( temp_file, temperature) f.writelines(content) file_set = True break except IOError: file_set = False return is_set & file_set def set_low_threshold(self, temperature): """ Sets the low threshold temperature of thermal Args : temperature: A float number up to nearest thousandth of one degree Celsius, e.g. 30.125 Returns: A boolean, True if threshold is set successfully, False if not """ return False def get_high_critical_threshold(self): """ Retrieves the high critical threshold temperature of thermal Returns: A float number, the high critical threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ max_crit_key = '{}_max_crit'.format(self._airflow) return self._thermal_info.get(max_crit_key, None) def get_low_critical_threshold(self): """ Retrieves the low critical threshold temperature of thermal Returns: A float number, the low critical threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ return 0.0 def get_name(self): """ Retrieves the name of the thermal device Returns: string: The name of the thermal device """ return self._thermal_info["name"] def get_presence(self): """ Retrieves the presence of the PSU Returns: bool: True if PSU is present, False if not """ temp_file = "temp{}_input".format(self.ss_index) temp_file_path = os.path.join(self._hwmon_path, temp_file) return os.path.isfile(temp_file_path) def get_model(self): """ Retrieves the model number (or part number) of the device Returns: string: Model/part number of device """ return NULL_VAL def get_serial(self): """ Retrieves the serial number of the device Returns: string: Serial number of device """ return NULL_VAL def get_status(self): """ Retrieves the operational status of the device Returns: A boolean value, True if device is operating properly, False if not """ if not self.get_presence(): return False fault_file = "temp{}_fault".format(self.ss_index) fault_file_path = os.path.join(self._hwmon_path, fault_file) if not os.path.isfile(fault_file_path): return True raw_txt = self.__read_txt_file(fault_file_path) return int(raw_txt) == 0