Beispiel #1
0
    def update_zones(self, dead_fans, time_difference):
        """
            TODO: Need to change logic here.

            # Platforms with chassis_intrusion mode enabled
            if chassis_intrusion:
                set the chassis_intrusion_boost_flag to 0
                and then do necessary checks to set flag to 1
                if chassis_intrusion_boost_flag:
                    run boost mode
                else:
                    run normal mode
            else
                # Platforms WITHOUT chassis_intrusion mode
                run normal mode

        """
        sensors_tuples = self.machine.read_sensors(self.sensors)
        self.fsc_safe_guards(sensors_tuples)
        for zone in self.zones:
            Logger.info("PWM: %s" % (json.dumps(zone.pwm_output)))

            chassis_intrusion_boost_flag = 0
            if self.chassis_intrusion:
                self_tray_pull_out = board_callout(
                    callout='chassis_intrusion')
                if self_tray_pull_out == 1:
                    chassis_intrusion_boost_flag = 1

            if chassis_intrusion_boost_flag == 0:
                pwmval = zone.run(sensors=sensors_tuples, dt=time_difference)
            else:
                pwmval = self.boost

            if self.fan_fail:
                if self.boost_type == 'progressive' and self.fan_dead_boost:
                    # Cases where we want to progressively bump PWMs
                    dead = len(dead_fans)
                    if dead > 0:
                        Logger.info("Progressive mode: Failed fans: %s" %
                              (', '.join([str(i.label) for i in dead_fans],)))
                        for fan_count, rate in self.fan_dead_boost["data"]:
                            if dead <= fan_count:
                                pwmval = clamp(pwmval + (dead * rate), 0, 100)
                                break
                        else:
                            pwmval = self.boost
                else:
                    if dead_fans:
                        # If not progressive ,when there is 1 fan failed, boost all fans
                        Logger.info("Failed fans: %s" % (
                            ', '.join([str(i.label) for i in dead_fans],)))
                        pwmval = self.boost
                    if self.fan_dead_boost:
                        # If all the fans failed take action after a few cycles
                        if len(dead_fans) == len(self.fans):
                            self.all_fan_fail_counter = self.all_fan_fail_counter + 1
                            Logger.warn("Currently all fans failed for {} cycles".format(self.all_fan_fail_counter))
                            if self.fan_dead_boost["threshold"] and self.fan_dead_boost["action"]:
                                if self.all_fan_fail_counter >= self.fan_dead_boost["threshold"]:
                                    self.fsc_host_action(
                                        action=self.fan_dead_boost["action"],
                                        cause="All fans are bad for more than "
                                              + str(self.fan_dead_boost["threshold"])
                                              + " cycles"
                                        )
                        else:
                            # If atleast 1 fan is working reset the counter
                            self.all_fan_fail_counter = 0

            if abs(zone.last_pwm - pwmval) > self.ramp_rate:
                if pwmval < zone.last_pwm:
                    pwmval = zone.last_pwm - self.ramp_rate
                else:
                    pwmval = zone.last_pwm + self.ramp_rate
            zone.last_pwm = pwmval

            if hasattr(zone.pwm_output, '__iter__'):
                for output in zone.pwm_output:
                    self.machine.set_pwm(self.fans.get(
                        str(output)), pwmval)
            else:
                self.machine.set_pwm(self.fans[zone.pwm_output], pwmval)
Beispiel #2
0
    def run(self, sensors, dt):
        ctx = {'dt': dt}
        outmin = 0
        fail_ssd_count = 0
        sensor_index = 0

        for v in self.expr_meta['ext_vars']:
            sensor_valid_flag = 1
            board, sname = v.split(":")
            if self.sensor_valid_check != None:
                for check_name in self.sensor_valid_check:
                    if re.match(check_name, sname, re.IGNORECASE) != None:
                        self.sensor_valid_cur[sensor_index] = fsc_board.sensor_valid_check(board, sname, check_name, self.sensor_valid_check[check_name]["attribute"])
                        #If current or previous sensor valid status is 0, ignore this sensor reading.
                        #Only when both are 1, goes to sensor check process
                        if (self.sensor_valid_cur[sensor_index] == 0) or (self.sensor_valid_pre[sensor_index] == 0):
                            sensor_valid_flag = 0
                            self.missing_sensor_assert_retry[sensor_index] = 0
                        break

            if sensor_valid_flag == 1:
                if sname in sensors[board]:
                    self.missing_sensor_assert_retry[sensor_index] = 0
                    if self.missing_sensor_assert_flag[sensor_index]:
                        Logger.crit('DEASSERT: Zone%d Missing sensors: %s' % (self.counter, v))
                        self.missing_sensor_assert_flag[sensor_index] = False

                    sensor = sensors[board][sname]
                    ctx[v] = sensor.value
                    if sensor.status in ['ucr']:
                        Logger.warn('Sensor %s reporting status %s' % (sensor.name, sensor.status))
                        outmin = max(outmin, self.transitional)
                    else:
                        if self.sensor_fail == True:
                            if (sensor.status in ['na']) and (self.sensor_valid_cur[sensor_index] != -1):
                                if re.match(r'.+_C[2-4]_[0-3]_NVME_.+', sensor.name) != None:
                                    Logger.warn("%s Fail" % v)
                                    outmin = max(outmin, self.boost)
                                elif re.match(r'SSD', sensor.name) != None or re.match(r'(.*)nvme(.*)', sname) != None:
                                    fail_ssd_count = fail_ssd_count + 1
                                else:
                                    Logger.warn("%s Fail" % v)
                                    outmin = max(outmin, self.boost)
                else:
                    if (not self.missing_sensor_assert_flag[sensor_index]) and (self.missing_sensor_assert_retry[sensor_index] >= 2):
                        Logger.crit('ASSERT: Zone%d Missing sensors: %s' % (self.counter, v))
                        self.missing_sensor_assert_flag[sensor_index] = True
                    if (self.missing_sensor_assert_retry[sensor_index] < 2):
                        self.missing_sensor_assert_retry[sensor_index] += 1
                    # evaluation tries to ignore the effects of None values
                    # (e.g. acts as 0 in max/+)
                    ctx[v] = None
            self.sensor_valid_pre[sensor_index] = self.sensor_valid_cur[sensor_index]
            sensor_index += 1

        if verbose:
            (exprout, dxstr) = self.expr.dbgeval(ctx)
            Logger.info(dxstr + " = " + str(exprout))
        else:
            exprout = self.expr.eval(ctx)
            Logger.info(self.expr_str + " = " + str(exprout))
        # If *all* sensors in the top level max() report None, the
        # expression will report None
        if (not exprout) and (outmin == 0):
            if not self.transitional_assert_flag:
                Logger.crit('ASSERT: Zone%d No sane fan speed could be \
                    calculated! Using transitional speed.' % (self.counter))
            exprout = self.transitional
            self.transitional_assert_flag = True
        else:
            if self.transitional_assert_flag:
                Logger.crit('DEASSERT: Zone%d No sane fan speed could be \
                    calculated! Using transitional speed.' % (self.counter))
            self.transitional_assert_flag = False

        if self.fail_sensor_type != None:
            if 'SSD_sensor_fail' in list(self.fail_sensor_type.keys()):
                if self.fail_sensor_type['SSD_sensor_fail'] == True:
                    if fail_ssd_count != 0:
                        if self.ssd_progressive_algorithm != None:
                            if 'offset_algorithm' in list(self.ssd_progressive_algorithm.keys()):
                                list_index = 0
                                for i in self.ssd_progressive_algorithm['offset_algorithm']:
                                    list_index = list_index + 1
                                    if fail_ssd_count <= i[0]:
                                        exprout = exprout + i[1]
                                        break
                                    else:
                                        if list_index == len(self.ssd_progressive_algorithm['offset_algorithm']):
                                           outmin = max(outmin, self.boost)
        if not exprout:
            exprout = 0
        if exprout < outmin:
            exprout = outmin
        exprout = clamp(exprout, 0, 100)
        return exprout
Beispiel #3
0
    def run(self, sensors, dt):
        ctx = {'dt': dt}
        outmin = 0
        fail_ssd_count = 0
        missing = set()

        for v in self.expr_meta['ext_vars']:
            board, sname = v.split(":")
            if sname in sensors[board]:
                sensor = sensors[board][sname]
                ctx[v] = sensor.value
                if sensor.status in ['ucr']:
                    Logger.warn('Sensor %s reporting status %s' %
                                (sensor.name, sensor.status))
                    outmin = self.transitional

                if self.fail_sensor_type != None:
                    if 'standby_sensor_fail' in self.fail_sensor_type.keys():
                        if self.fail_sensor_type[
                                'standby_sensor_fail'] == True:
                            if sensor.status in ['na']:
                                if re.match(r'SOC', sensor.name) != None:
                                    if 'server_sensor_fail' in self.fail_sensor_type.keys(
                                    ):
                                        if self.fail_sensor_type[
                                                'server_sensor_fail'] == True:
                                            ret = fsc_board.get_power_status(
                                                board)
                                            if ret:
                                                Logger.debug(
                                                    "Server Sensor Fail")
                                                outmin = self.boost
                                                break
                                elif re.match(r'SSD', sensor.name) != None:
                                    if 'SSD_sensor_fail' in self.fail_sensor_type.keys(
                                    ):
                                        if self.fail_sensor_type[
                                                'SSD_sensor_fail'] == True:
                                            fail_ssd_count = fail_ssd_count + 1
                                else:
                                    Logger.debug("Standby Sensor Fail")
                                    outmin = self.boost
                                    break
            else:
                missing.add(v)
                # evaluation tries to ignore the effects of None values
                # (e.g. acts as 0 in max/+)
                ctx[v] = None
        if missing:
            Logger.warn('Missing sensors: %s' % (', '.join(missing), ))
        if verbose:
            (exprout, dxstr) = self.expr.dbgeval(ctx)
            Logger.info(dxstr + " = " + str(exprout))
        else:
            exprout = self.expr.eval(ctx)
            Logger.info(self.expr_str + " = " + str(exprout))
        # If *all* sensors in the top level max() report None, the
        # expression will report None
        if not exprout:
            if not self.transitional_assert_flag:
                Logger.crit('ASSERT: Zone%d No sane fan speed could be \
                    calculated! Using transitional speed.' % (self.counter))
            exprout = self.transitional
            self.transitional_assert_flag = True
        else:
            if self.transitional_assert_flag:
                Logger.crit('DEASSERT: Zone%d No sane fan speed could be \
                    calculated! Using transitional speed.' % (self.counter))
            self.transitional_assert_flag = False

        if self.fail_sensor_type != None:
            if 'SSD_sensor_fail' in self.fail_sensor_type.keys():
                if self.fail_sensor_type['SSD_sensor_fail'] == True:
                    if fail_ssd_count != 0:
                        if self.ssd_progressive_algorithm != None:
                            if 'offset_algorithm' in self.ssd_progressive_algorithm.keys(
                            ):
                                list_index = 0
                                for i in self.ssd_progressive_algorithm[
                                        'offset_algorithm']:
                                    list_index = list_index + 1
                                    if fail_ssd_count <= i[0]:
                                        exprout = exprout + i[1]
                                        break
                                    else:
                                        if list_index == len(
                                                self.ssd_progressive_algorithm[
                                                    'offset_algorithm']):
                                            outmin = self.boost

        if exprout < outmin:
            exprout = outmin
        exprout = clamp(exprout, 0, 100)
        return exprout
    def run(self, sensors, dt):
        ctx = {"dt": dt}
        outmin = 0
        fail_ssd_count = 0
        sensor_index = 0
        cause_boost_count = 0
        no_sane_flag = 0
        mode = 0

        for v in self.expr_meta["ext_vars"]:
            sensor_valid_flag = 1
            sdata = v.split(":")
            board = sdata[0]
            sname = sdata[1]
            if self.sensor_valid_check != None:
                for check_name in self.sensor_valid_check:
                    if re.match(check_name, sname, re.IGNORECASE) != None:
                        self.sensor_valid_cur[
                            sensor_index] = fsc_board.sensor_valid_check(
                                board,
                                sname,
                                check_name,
                                self.sensor_valid_check[check_name]
                                ["attribute"],
                            )
                        # If current or previous sensor valid status is 0, ignore this sensor reading.
                        # Only when both are 1, goes to sensor check process
                        if (self.sensor_valid_cur[sensor_index]
                                == 0) or (self.sensor_valid_pre[sensor_index]
                                          == 0):
                            sensor_valid_flag = 0
                            self.missing_sensor_assert_retry[sensor_index] = 0
                        break

            if sensor_valid_flag == 1:
                if sname in sensors[board]:
                    self.missing_sensor_assert_retry[sensor_index] = 0
                    if self.missing_sensor_assert_flag[sensor_index]:
                        Logger.crit("DEASSERT: Zone%d Missing sensors: %s" %
                                    (self.counter, v))
                        self.missing_sensor_assert_flag[sensor_index] = False

                    sensor = sensors[board][sname]
                    ctx[v] = sensor.value
                    if sensor.status in ["ucr"]:
                        Logger.warn("Sensor %s reporting status %s" %
                                    (sensor.name, sensor.status))
                        outmin = max(outmin, self.transitional)
                        if outmin == self.transitional:
                            mode = fan_mode["trans_mode"]
                    else:
                        if self.sensor_fail == True:
                            sensor_fail_record_path = SENSOR_FAIL_RECORD_DIR + v
                            if not os.path.isdir(SENSOR_FAIL_RECORD_DIR):
                                os.mkdir(SENSOR_FAIL_RECORD_DIR)
                            if (sensor.status in [
                                    "na"
                            ]) and (self.sensor_valid_cur[sensor_index] != -1):
                                if re.match(r"SSD", sensor.name) != None:
                                    fail_ssd_count = fail_ssd_count + 1
                                else:
                                    Logger.warn("%s Fail" % v)
                                    outmin = max(outmin, self.boost)
                                    cause_boost_count += 1
                                if not os.path.isfile(sensor_fail_record_path):
                                    sensor_fail_record = open(
                                        sensor_fail_record_path, "w")
                                    sensor_fail_record.close()
                                if outmin == self.boost:
                                    mode = fan_mode["boost_mode"]
                            else:
                                if os.path.isfile(sensor_fail_record_path):
                                    os.remove(sensor_fail_record_path)
                else:
                    if (not self.missing_sensor_assert_flag[sensor_index]
                        ) and (self.missing_sensor_assert_retry[sensor_index]
                               >= 2):
                        Logger.crit("ASSERT: Zone%d Missing sensors: %s" %
                                    (self.counter, v))
                        self.missing_sensor_assert_flag[sensor_index] = True
                    if self.missing_sensor_assert_retry[sensor_index] < 2:
                        self.missing_sensor_assert_retry[sensor_index] += 1
                    # evaluation tries to ignore the effects of None values
                    # (e.g. acts as 0 in max/+)
                    ctx[v] = None
            self.sensor_valid_pre[sensor_index] = self.sensor_valid_cur[
                sensor_index]
            sensor_index += 1

        if verbose:
            (exprout, dxstr) = self.expr.dbgeval(ctx)
            Logger.info(dxstr + " = " + str(exprout))
        else:
            exprout = self.expr.eval(ctx)
            Logger.info(self.expr_str + " = " + str(exprout))
        # If *all* sensors in the top level max() report None, the
        # expression will report None
        if (not exprout) and (outmin == 0):
            if not self.transitional_assert_flag:
                Logger.crit("ASSERT: Zone%d No sane fan speed could be \
                    calculated! Using transitional speed." % (self.counter))
            exprout = self.transitional
            mode = fan_mode["trans_mode"]
            no_sane_flag = 1
            self.transitional_assert_flag = True
        else:
            if self.transitional_assert_flag:
                Logger.crit("DEASSERT: Zone%d No sane fan speed could be \
                    calculated! Using transitional speed." % (self.counter))
            self.transitional_assert_flag = False

        if self.fail_sensor_type != None:
            if "SSD_sensor_fail" in list(self.fail_sensor_type.keys()):
                if self.fail_sensor_type["SSD_sensor_fail"] == True:
                    if fail_ssd_count != 0:
                        if self.ssd_progressive_algorithm != None:
                            if "offset_algorithm" in list(
                                    self.ssd_progressive_algorithm.keys()):
                                list_index = 0
                                for i in self.ssd_progressive_algorithm[
                                        "offset_algorithm"]:
                                    list_index = list_index + 1
                                    if fail_ssd_count <= i[0]:
                                        exprout = exprout + i[1]
                                        no_sane_flag = 0
                                        break
                                    else:
                                        if list_index == len(
                                                self.ssd_progressive_algorithm[
                                                    "offset_algorithm"]):
                                            outmin = max(outmin, self.boost)
                                            cause_boost_count += 1
                                            if outmin == self.boost:
                                                mode = fan_mode["boost_mode"]

        boost_record_path = RECORD_DIR + "sensor_fail_boost"
        if cause_boost_count != 0:
            if not os.path.isfile(boost_record_path):
                sensor_fail_boost_record = open(boost_record_path, "w")
                sensor_fail_boost_record.close()
        else:
            if os.path.isfile(boost_record_path):
                os.remove(boost_record_path)

        if not exprout:
            exprout = 0
        if exprout < outmin:
            exprout = outmin
        else:
            if no_sane_flag != 1:
                mode = fan_mode["normal_mode"]
        self.get_set_fan_mode(mode, action="write")
        exprout = clamp(exprout, 0, 100)
        return exprout
Beispiel #5
0
    def update_zones(self, dead_fans, time_difference):
        """
            TODO: Need to change logic here.

            # Platforms with chassis_intrusion mode enabled
            if chassis_intrusion:
                set the chassis_intrusion_boost_flag to 0
                and then do necessary checks to set flag to 1
                if chassis_intrusion_boost_flag:
                    run boost mode
                else:
                    run normal mode
            else
                # Platforms WITHOUT chassis_intrusion mode
                run normal mode

            # Platforms with enable_fsc_sensor_check mode enabled
            if enable_fsc_sensor_check:
                set the sensor_violated_flag to 0
                and then do necessary checks to set flag to 1
                if sensor_violated_flag:
                    run boost mode
                else:
                    run normal mode
            else
                # Platforms WITHOUT enable_fsc_sensor_check mode
                run normal mode

        """
        ctx = {}
        if not self.sensor_filter_all:
            sensors_tuples = self.machine.read_sensors(self.sensors, None)
            self.fsc_safe_guards(sensors_tuples)
        for zone in self.zones:
            if self.sensor_filter_all:
                sensors_tuples = self.machine.read_sensors(
                    self.sensors, zone.expr_meta)
                self.fsc_safe_guards(sensors_tuples)
            Logger.info("PWM: %s" % (json.dumps(zone.pwm_output)))
            mode = 0
            chassis_intrusion_boost_flag = 0
            sensor_violated_flag = 0
            if self.chassis_intrusion:
                self_tray_pull_out = board_callout(callout="chassis_intrusion")
                if self_tray_pull_out == 1:
                    chassis_intrusion_boost_flag = 1
            if self.enable_fsc_sensor_check:
                Logger.info("enable_fsc_sensor_check")
                if self.fsc_sensor_check(sensors_tuples) != 0:
                    sensor_violated_flag = 1
            Logger.debug(" dead_fans(%d) " % len(dead_fans))
            Logger.debug("Calculate")

            if chassis_intrusion_boost_flag == 0 and sensor_violated_flag == 0:
                ctx["dt"] = time_difference
                ctx["dead_fans"] = dead_fans
                ctx["last_pwm"] = zone.last_pwm
                ignore_fan_mode = False
                if self.non_fanfail_limited_boost and dead_fans:
                    ignore_fan_mode = True
                pwmval = zone.run(sensors=sensors_tuples,
                                  ctx=ctx,
                                  ignore_mode=ignore_fan_mode)
                mode = zone.get_set_fan_mode(mode, action="read")
                # if we set pwm_sensor_boost_value option, assign it to pwmval
                if self.pwm_sensor_boost_value != None and \
                    int(mode) == fan_mode["boost_mode"]:
                    if pwmval == self.boost:
                        pwmval = self.pwm_sensor_boost_value
            else:
                pwmval = self.boost
                mode = fan_mode["boost_mode"]

            if self.fan_fail:
                boost_record_path = RECORD_DIR + "fan_fail_boost"
                if self.boost_type == "progressive" and self.fan_dead_boost:
                    # Cases where we want to progressively bump PWMs
                    dead = len(dead_fans)
                    if dead > 0:
                        Logger.info(
                            "Progressive mode: Failed fans: %s" %
                            (", ".join([str(i.label) for i in dead_fans])))
                        for fan_count, rate in self.fan_dead_boost["data"]:
                            if dead <= fan_count:
                                pwmval = clamp(pwmval + (dead * rate), 0, 100)
                                mode = fan_mode["normal_mode"]
                                if os.path.isfile(boost_record_path):
                                    os.remove(boost_record_path)
                                break
                        else:
                            pwmval = self.boost
                            mode = fan_mode["boost_mode"]
                            if not os.path.isfile(boost_record_path):
                                fan_fail_boost_record = open(
                                    boost_record_path, "w")
                                fan_fail_boost_record.close()
                    else:
                        if os.path.isfile(boost_record_path):
                            os.remove(boost_record_path)
                else:
                    if dead_fans:
                        # If not progressive ,when there is 1 fan failed, boost all fans
                        Logger.info(
                            "Failed fans: %s" %
                            (", ".join([str(i.label) for i in dead_fans])))
                        # choose the higher PWM
                        if self.output_max_boost_pwm:
                            pwmval = self.boost if pwmval < self.boost else pwmval
                        else:
                            pwmval = self.boost
                        mode = fan_mode["boost_mode"]
                        if not os.path.isfile(boost_record_path):
                            fan_fail_boost_record = open(
                                boost_record_path, "w")
                            fan_fail_boost_record.close()
                    else:
                        if os.path.isfile(boost_record_path):
                            os.remove(boost_record_path)
                    if self.fan_dead_boost:
                        # If all the fans failed take action after a few cycles
                        if len(dead_fans) == len(self.fans):
                            self.all_fan_fail_counter = self.all_fan_fail_counter + 1
                            Logger.warn(
                                "Currently all fans failed for {} cycles".
                                format(self.all_fan_fail_counter))
                            if (self.fan_dead_boost["threshold"]
                                    and self.fan_dead_boost["action"]):
                                if (self.all_fan_fail_counter >=
                                        self.fan_dead_boost["threshold"]):
                                    self.fsc_host_action(
                                        action=self.fan_dead_boost["action"],
                                        cause="All fans are bad for more than "
                                        +
                                        str(self.fan_dead_boost["threshold"]) +
                                        " cycles",
                                    )
                        else:
                            # If atleast 1 fan is working reset the counter
                            self.all_fan_fail_counter = 0

            if self.fan_limit_upper_pwm:
                if pwmval > self.fan_limit_upper_pwm:
                    pwmval = self.fan_limit_upper_pwm

            if self.fan_limit_lower_pwm:
                if pwmval < self.fan_limit_lower_pwm:
                    pwmval = self.fan_limit_lower_pwm

            # if no fan fail, the max of pwm is non_fanfail_limited_boost pwm:
            if self.non_fanfail_limited_boost and not dead_fans:
                pwmval = clamp(pwmval, 0, self.non_fanfail_limited_boost)

            if abs(zone.last_pwm - pwmval) > self.ramp_rate:
                if pwmval < zone.last_pwm:
                    pwmval = zone.last_pwm - self.ramp_rate
                else:
                    pwmval = zone.last_pwm + self.ramp_rate
            zone.last_pwm = pwmval

            if hasattr(zone.pwm_output, "__iter__"):
                for output in zone.pwm_output:
                    self.machine.set_pwm(self.fans.get(str(output)), pwmval)
            else:
                self.machine.set_pwm(self.fans[zone.pwm_output], pwmval)

            zone.get_set_fan_mode(mode, action="write")
Beispiel #6
0
    def run(self, sensors, ctx, ignore_mode):
        outmin = 0
        fail_ssd_count = 0
        valid_m2_count = 0
        sensor_index = 0
        cause_boost_count = 0
        no_sane_flag = 0
        display_progressive_flag = 0
        mode = 0

        for v in self.expr_meta["ext_vars"]:
            sensor_valid_flag = 1
            sdata = v.split(":")
            board = sdata[0]
            sname = sdata[1]
            if self.sensor_valid_check != None:
                for check_name in self.sensor_valid_check:
                    if re.match(check_name, sname, re.IGNORECASE) != None:
                        self.sensor_valid_cur[
                            sensor_index] = fsc_board.sensor_valid_check(
                                board,
                                sname,
                                check_name,
                                self.sensor_valid_check[check_name]
                                ["attribute"],
                            )
                        # If current or previous sensor valid status is 0, ignore this sensor reading.
                        # Only when both are 1, goes to sensor check process
                        if (self.sensor_valid_cur[sensor_index]
                                == 0) or (self.sensor_valid_pre[sensor_index]
                                          == 0):
                            sensor_valid_flag = 0
                            self.missing_sensor_assert_retry[sensor_index] = 0
                        break

            if sensor_valid_flag == 1:
                if sname in sensors[board]:
                    self.missing_sensor_assert_retry[sensor_index] = 0
                    if self.missing_sensor_assert_flag[sensor_index]:
                        Logger.crit("DEASSERT: Zone%d Missing sensors: %s" %
                                    (self.counter, v))
                        self.missing_sensor_assert_flag[sensor_index] = False

                    sensor = sensors[board][sname]
                    ctx[v] = sensor.value
                    if re.match(r".*temp_dev", sname) != None:
                        valid_m2_count = valid_m2_count + 1
                    if sensor.status in ["ucr"]:
                        Logger.warn("Sensor %s reporting status %s" %
                                    (sensor.name, sensor.status))
                        outmin = max(outmin, self.transitional)
                        if outmin == self.transitional:
                            mode = fan_mode["trans_mode"]
                    else:
                        if self.sensor_fail == True:
                            sensor_fail_record_path = SENSOR_FAIL_RECORD_DIR + v
                            if not os.path.isdir(SENSOR_FAIL_RECORD_DIR):
                                os.mkdir(SENSOR_FAIL_RECORD_DIR)
                            if (sensor.status in [
                                    "na"
                            ]) and (self.sensor_valid_cur[sensor_index] != -1):
                                if (re.match(r"SSD", sensor.name) !=
                                        None) or (re.match(
                                            r".*temp_dev", sname) != None):
                                    fail_ssd_count = fail_ssd_count + 1
                                    Logger.warn("M.2 Device %s Fail" % v)
                                else:
                                    Logger.warn("%s Fail" % v)
                                    outmin = max(outmin, self.boost)
                                    cause_boost_count += 1
                                if not os.path.isfile(sensor_fail_record_path):
                                    sensor_fail_record = open(
                                        sensor_fail_record_path, "w")
                                    sensor_fail_record.close()
                                if outmin == self.boost:
                                    mode = fan_mode["boost_mode"]
                            else:
                                if os.path.isfile(sensor_fail_record_path):
                                    os.remove(sensor_fail_record_path)
                else:
                    if (not self.missing_sensor_assert_flag[sensor_index]
                        ) and (self.missing_sensor_assert_retry[sensor_index]
                               >= 2):
                        Logger.crit("ASSERT: Zone%d Missing sensors: %s" %
                                    (self.counter, v))
                        self.missing_sensor_assert_flag[sensor_index] = True
                    if self.missing_sensor_assert_retry[sensor_index] < 2:
                        self.missing_sensor_assert_retry[sensor_index] += 1
                    # evaluation tries to ignore the effects of None values
                    # (e.g. acts as 0 in max/+)
                    ctx[v] = None
            else:
                if sname in sensors[board]:
                    if self.sensor_fail == True:
                        sensor_fail_record_path = SENSOR_FAIL_RECORD_DIR + v
                        if os.path.isfile(sensor_fail_record_path):
                            os.remove(sensor_fail_record_path)

            self.sensor_valid_pre[sensor_index] = self.sensor_valid_cur[
                sensor_index]
            sensor_index += 1

        if verbose:
            (exprout, dxstr) = self.expr.dbgeval(ctx)
            Logger.info(dxstr + " = " + str(exprout))
        else:
            exprout = self.expr.eval_driver(ctx)
            Logger.info(self.expr_str + " = " + str(exprout))
        # If *all* sensors in the top level max() report None, the
        # expression will report None
        if (not exprout) and (outmin == 0):
            if not self.transitional_assert_flag:
                Logger.crit(
                    "ASSERT: Zone%d No sane fan speed could be calculated! Using transitional speed."
                    % (self.counter))
            exprout = self.transitional
            mode = fan_mode["trans_mode"]
            no_sane_flag = 1
            self.transitional_assert_flag = True
        else:
            if self.transitional_assert_flag:
                Logger.crit(
                    "DEASSERT: Zone%d No sane fan speed could be calculated! Using transitional speed."
                    % (self.counter))
            self.transitional_assert_flag = False

        if self.fail_sensor_type != None:
            progressive_mode = True
            if ("M2_sensor_fail" in list(self.fail_sensor_type.keys())) and (
                    "M2_sensor_count" in list(self.fail_sensor_type.keys())):
                if (self.fail_sensor_type["M2_sensor_fail"] == True) and (
                        self.fail_sensor_type["M2_sensor_count"] > 0):
                    if valid_m2_count == 0:
                        if fsc_board.all_slots_power_off() == False:
                            # Missing all module (no M.2 device)
                            outmin = max(outmin, self.boost)
                            cause_boost_count += 1
                            mode = fan_mode["boost_mode"]
                            progressive_mode = False
                        else:
                            # All slots power off, do not boost up
                            progressive_mode = False
                    elif valid_m2_count != self.fail_sensor_type[
                            "M2_sensor_count"]:
                        # Missing some module (M.2 devices partially populated)
                        progressive_mode = False
                        cause_boost_count += 1
                    else:
                        # M.2 devices fully populated
                        if cause_boost_count != 0:
                            # other boost reasons: e.g. other sensors (not M.2 devices' sensors) fail to read sensors
                            progressive_mode = False
                        else:
                            if fail_ssd_count != 0:
                                # M.2 devices progressive_mode
                                # handle M.2 devices/SSD fail to read case
                                cause_boost_count += 1  # show out sensor fail record
                                display_progressive_flag = (
                                    1)  # do not override by normal mode
                                mode = fan_mode["progressive_mode"]
                            else:
                                # M.2 devices noraml mode
                                progressive_mode = False

            if progressive_mode and ("SSD_sensor_fail" in list(
                    self.fail_sensor_type.keys())):
                if self.fail_sensor_type["SSD_sensor_fail"] == True:
                    if fail_ssd_count != 0:
                        if self.ssd_progressive_algorithm != None:
                            if "offset_algorithm" in list(
                                    self.ssd_progressive_algorithm.keys()):
                                list_index = 0
                                for i in self.ssd_progressive_algorithm[
                                        "offset_algorithm"]:
                                    list_index = list_index + 1
                                    if fail_ssd_count <= i[0]:
                                        exprout = exprout + i[1]
                                        no_sane_flag = 0
                                        break
                                    else:
                                        if list_index == len(
                                                self.ssd_progressive_algorithm[
                                                    "offset_algorithm"]):
                                            outmin = max(outmin, self.boost)
                                            cause_boost_count += 1
                                            if outmin == self.boost:
                                                mode = fan_mode["boost_mode"]

        boost_record_path = RECORD_DIR + "sensor_fail_boost"
        if cause_boost_count != 0:
            if not os.path.isfile(boost_record_path):
                sensor_fail_boost_record = open(boost_record_path, "w")
                sensor_fail_boost_record.close()
        else:
            if os.path.isfile(boost_record_path):
                os.remove(boost_record_path)

        if not exprout:
            exprout = 0
        if exprout < outmin:
            exprout = outmin
        else:
            if (no_sane_flag != 1) and (display_progressive_flag != 1):
                mode = fan_mode["normal_mode"]
        if not ignore_mode:
            self.get_set_fan_mode(mode, action="write")
        exprout = clamp(exprout, 0, 100)
        return exprout