/* Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

// don't change the include order
#include <stdio.h>
#include "adapter.h"
#include "sml_errcodes.h"
#include "utils/file_securec.h"
#include "pd.h"

#ifdef ITEST_ENABLED
#include "ibmc_itest_sml.h"
#endif

#define SMLIB_DUMP_SMART_INFO_INTREVAL 600 // 每隔10分钟写一次物理盘SMART信息到文件
#define SMLIB_DUMP_SMART_INFO_BUF_SIZE 512
#define MAX_ATA_SMART_ATTRIBUTE_LEN    64

typedef struct pd_ata_smart_attr_name {
    guint8 attr_id;
    const gchar ata_smart_attr_name[MAX_ATA_SMART_ATTRIBUTE_LEN];
} PD_ATA_SMART_ATTR_NAME_S;

static const PD_ATA_SMART_ATTR_NAME_S g_pd_ata_smart_attr_array[] = {
    {ATA_SMART_ATTRIBUTE_ID_RAW_READ_ERROR_RATE, "Raw_Read_Error_Rate"},
    {ATA_SMART_ATTRIBUTE_ID_THROUGHPUT_PERFORMANCE, "Throughput_Performance"},
    {ATA_SMART_ATTRIBUTE_ID_SPIN_UP_TIME, "Spin_Up_Time"},
    {ATA_SMART_ATTRIBUTE_ID_START_STOP_COUNT, "Start_Stop_Count"},
    {ATA_SMART_ATTRIBUTE_ID_REALLOCATED_SECTORS_COUNT, "Reallocated_Sectors_Count"},
    {ATA_SMART_ATTRIBUTE_ID_READ_CHANNEL_MARGIN, "Read_Channel_Margin"},
    {ATA_SMART_ATTRIBUTE_ID_SEEK_ERROR_RATE, "Seek_Error_Rate"},
    {ATA_SMART_ATTRIBUTE_ID_SEEK_TIME_PERFORMANCE, "Seek_Time_Performance"},
    {ATA_SMART_ATTRIBUTE_ID_POWER_ON_HOURS, "Power_On_Hours"},
    {ATA_SMART_ATTRIBUTE_ID_SPIN_RETRY_COUNT, "Spin_Retry_Count"},
    {ATA_SMART_ATTRIBUTE_ID_CALIBRATION_RETRY_COUNT, "Calibration_Retry_Count"},
    {ATA_SMART_ATTRIBUTE_ID_POWER_CYCLE_COUNT, "Power_Cycle_Count"},
    {ATA_SMART_ATTRIBUTE_ID_SOFT_READ_ERROR_RATE_13, "Soft_Read_Error_Rate"},
    {ATA_SMART_ATTRIBUTE_ID_RESERVED_BLOCK_COUNT, "Reserved_Block_Count"},
    {ATA_SMART_ATTRIBUTE_ID_PROGRAM_FAIL_COUNT, "Program_Fail_Count"},
    {ATA_SMART_ATTRIBUTE_ID_ERASE_FAIL_COUNT, "Erase_Fail_Count"},
    {ATA_SMART_ATTRIBUTE_ID_UNEXPECT_POWER_LOSS_COUNT, "Unexpect_Power_Loss_Count"},
    {ATA_SMART_ATTRIBUTE_ID_PROGRAM_FAIL_COUNT_CHIP, "Program_Fail_Count_Chip"},
    {ATA_SMART_ATTRIBUTE_ID_ERASE_FAIL_COUNT_CHIP, "Erase_Fail_Count_Chip"},
    {ATA_SMART_ATTRIBUTE_ID_WEAR_LEVELING_COUNT, "Wear_Leveling_Count"},
    {ATA_SMART_ATTRIBUTE_ID_USED_RSVD_BLK_CNT_CHIP, "Used_Rsvd_Blk_Count_Chip"},
    {ATA_SMART_ATTRIBUTE_ID_USED_RSVD_BLK_CNT_TOTAL, "Used_Rsvd_Blk_Count_ToTal"},
    {ATA_SMART_ATTRIBUTE_ID_UNUSED_RSVD_BLK_CNT_TOTAL, "Unused_Rsvd_Blk_Count_ToTal"},
    {ATA_SMART_ATTRIBUTE_ID_PROGRAM_FAIL_CNT_TOTAL, "Program_Fail_Count_Total"},
    {ATA_SMART_ATTRIBUTE_ID_ERASE_FAIL_COUNT_TOTAL, "Erase_Fail_Count_Total"},
    {ATA_SMART_ATTRIBUTE_ID_RUNTIME_BAD_BLOCK, "Runtime_Bad_Block"},
    {ATA_SMART_ATTRIBUTE_ID_END_TO_END_ERROR, "End-To-End_Error"},
    {ATA_SMART_ATTRIBUTE_ID_REPORTED_UNCORRECTABLE_ERRORS, "Reported_Uncorrectable_Error"},
    {ATA_SMART_ATTRIBUTE_ID_COMMAND_TIMEOUT, "Command_Timeout"},
    {ATA_SMART_ATTRIBUTE_ID_HIGH_FLY_WRITES, "High_Fly_Writes"},
    {ATA_SMART_ATTRIBUTE_ID_AIRFLOW_TEMPERATURE_CELSIUS, "Airflow_Temperature_Celsius"},
    {ATA_SMART_ATTRIBUTE_ID_G_SENSE_ERROR_RATE_191, "G-Sense_Error_Rate"},
    {ATA_SMART_ATTRIBUTE_ID_POWER_OFF_RETRACT_COUNT_192, "Power-Off_Retract_Count"},
    {ATA_SMART_ATTRIBUTE_ID_LOAD_CYCLE_COUNT_193, "Load_Cycle_Count"},
    {ATA_SMART_ATTRIBUTE_ID_TEMPERATURE_CELSIUS, "Temperature_Celsius"},
    {ATA_SMART_ATTRIBUTE_ID_HARDWARE_ECC_RECOVERED, "Hardware_ECC_Recovered"},
    {ATA_SMART_ATTRIBUTE_ID_REALLOCATED_EVENT_COUNT, "Reallocated_Event_Count"},
    {ATA_SMART_ATTRIBUTE_ID_CURRENT_PENDING_SECTOR, "Current_Pending_Sector"},
    {ATA_SMART_ATTRIBUTE_ID_OFFLINE_UNCORRECTABLE, "Offline_Uncorrectable"},
    {ATA_SMART_ATTRIBUTE_ID_UDMA_CRC_ERROR_COUNT, "UltraDMA_CRC_Error_Count"},
    {ATA_SMART_ATTRIBUTE_ID_MULTI_ZONE_ERROR_RATE, "Multi-Zone_Error_Rate"},
    {ATA_SMART_ATTRIBUTE_ID_SOFT_READ_ERROR_RATE_201, "Soft_Read_Error_Rate"},
    {ATA_SMART_ATTRIBUTE_ID_PERCENT_LIFETIME_REMAINING, "Mircon_SSD_Lifetime_Remain"},
    {ATA_SMART_ATTRIBUTE_ID_RUN_OUT_CANCEL, "Run_Out_Cancel"},
    {ATA_SMART_ATTRIBUTE_ID_SOFT_ECC_CORRECTION, "Soft_ECC_Correction"},
    {ATA_SMART_ATTRIBUTE_ID_THERMAL_ASPERITY_RATE, "Thermal_Asperity_Rate"},
    {ATA_SMART_ATTRIBUTE_ID_FLYING_HEIGHT, "Flying_Height"},
    {ATA_SMART_ATTRIBUTE_ID_SPIN_HIGH_CURRENT, "Spin_High_Current"},
    {ATA_SMART_ATTRIBUTE_ID_SPIN_BUZZ, "Spin_Buzz"},
    {ATA_SMART_ATTRIBUTE_ID_OFFLINE_SEEK_PERFORMNCE, "Offline_Seek_Performance"},
    {ATA_SMART_ATTRIBUTE_ID_DISK_SHIFT, "Disk_Shift"},
    {ATA_SMART_ATTRIBUTE_ID_G_SENSE_ERROR_RATE_221, "G-Sense_Error_Rate"},
    {ATA_SMART_ATTRIBUTE_ID_LOADED_HOURS, "Loaded_Hours"},
    {ATA_SMART_ATTRIBUTE_ID_LOAD_RETRY_COUNT, "Load_Retry_Count"},
    {ATA_SMART_ATTRIBUTE_ID_LOAD_FRICTION, "Load_Friction"},
    {ATA_SMART_ATTRIBUTE_ID_LOAD_CYCLE_COUNT_225, "Load_Cycle_Count"},
    {ATA_SMART_ATTRIBUTE_ID_LOAD_IN_TIME, "Load_In_Time"},
    {ATA_SMART_ATTRIBUTE_ID_TORQUE_AMPLIFICATION_COUNT, "Torque_Amplification_Count"},
    {ATA_SMART_ATTRIBUTE_ID_POWER_OFF_RETRACT_COUNT_228, "Power-Off Retract Cycle"},
    {ATA_SMART_ATTRIBUTE_ID_HEAD_AMPLITUDE, "Head_Amplitude"},
    {ATA_SMART_ATTRIBUTE_ID_DRIVE_TEMPERATURE, "Drive_Temperature"},
    {ATA_SMART_ATTRIBUTE_ID_AVAILABLE_RESERVED_SPACE, "Avaliable_Reserved_Space"},
    {ATA_SMART_ATTRIBUTE_ID_MEDIA_WEAROUT_INDICATOR, "Media_Wearout_Indicator"},
    {ATA_SMART_ATTRIBUTE_ID_HEAD_FLYING_HOURS, "Head_Flying_Hours"},
    {ATA_SMART_ATTRIBUTE_ID_TOTAL_LBAS_WRITTEN, "Total_LBAS_Written"},
    {ATA_SMART_ATTRIBUTE_ID_TOTAL_LBAS_READ, "Total_LBAS_Read"},
    {ATA_SMART_ATTRIBUTE_ID_DRIVE_LIFETIME_REMAINNING, "SanDisk_SSD_Lifetim_Remain"},
    {ATA_SMART_ATTRIBUTE_ID_READ_ERROR_RETRY_RATE, "Read_Error_Retry_Rate"},
    {ATA_SMART_ATTRIBUTE_ID_FREE_FALL_SENSOR, "Free_Fall_Sensor"},
};

/*
 * Description: 获取硬盘的SMART信息
 * History: 1.2018年5月19日
 *          新生成函数
 */
gint32 smlib_get_pd_smart_info(guint8 ctrl_index, guint16 pd_device_id, SML_PD_SMART_INFO_S *pd_smart_info)
{
    gint32 retval = SML_SUCCESS;
    guint16 pd_index = 0;
    SML_CTRL_S* sml_ctrl = NULL;

    if (SML_SUCCESS != (retval = check_input_parameters(ctrl_index, pd_smart_info))) {
        return retval;
    }
    lock_ctrl_list_mutex(ctrl_index);
    sml_ctrl = get_ctrl_by_index(ctrl_index);
    if (sml_ctrl == NULL) {
        unlock_ctrl_list_mutex(ctrl_index);
        return SML_ERR_CTRL_NOT_REGISTERED;
    }
    if (RET_OK != check_pd_device_id(pd_device_id, &sml_ctrl->controller.pdlist, &pd_index)) {
        unlock_ctrl_list_mutex(ctrl_index);
        return SML_ERR_PD_INVALID_DEVICE_ID;
    }

    g_mutex_lock(&sml_ctrl->ctrl_mutex);

    memcpy_s(pd_smart_info, sizeof(SML_PD_SMART_INFO_S), &sml_ctrl->controller.pd[pd_index].smartinfo,
        sizeof(SML_PD_SMART_INFO_S));

    g_mutex_unlock(&sml_ctrl->ctrl_mutex);
    unlock_ctrl_list_mutex(ctrl_index);

    return SML_SUCCESS;
}

/*
 * Description : 获取SATA硬盘SMART属性名称
 */
static const gchar *get_ata_smart_attr_name(guint8 attr_id)
{
    gint32 cnt = (gint32)(sizeof(g_pd_ata_smart_attr_array) / sizeof(PD_ATA_SMART_ATTR_NAME_S));

    for (gint32 i = 0; i < cnt; i++) {
        if (g_pd_ata_smart_attr_array[i].attr_id == attr_id) {
            return g_pd_ata_smart_attr_array[i].ata_smart_attr_name;
        }
    }

    return "Unknown_Attribute";
}

/*
 * Description: 打印SATA硬盘的SMART Power on时间属性的原始值
 * History: 1.2016年4月16日
 *          新生成函数
 */
static void print_ata_smart_attr_raw_value_power_on(gchar *buf, guint32 buf_size, guint8 select_mode, guint64 raw_value)
{
    if (buf_size == 0) {
        debug_log(DLOG_ERROR, "%s failed:input param error, buf_size is 0.", __FUNCTION__);
        return;
    }
    if (select_mode == 1) {
        // 单位: 分
        guint64 tmp1 = raw_value / 60;
        guint64 tmp2 = raw_value % 60;
        (void)snprintf_s(buf, buf_size, buf_size - 1, "%"G_GUINT64_FORMAT"h+%02"G_GUINT64_FORMAT"m", tmp1, tmp2);
    } else if (select_mode == 3) {
        // 单位: 秒
        guint64 hours = raw_value / 3600;
        guint64 minutes = (raw_value - 3600 * hours) / 60;
        guint64 seconds = raw_value % 60;
        (void)snprintf_s(buf, buf_size, buf_size - 1,
                        "%"G_GUINT64_FORMAT"h+%02"G_GUINT64_FORMAT"m+%02"G_GUINT64_FORMAT"s",
                        hours, minutes, seconds);
    } else if (select_mode == 4) {
        // 30秒计数单位
        guint64 tmp1 = raw_value / 120;
        guint64 tmp2 = (raw_value - 120 * tmp1) / 2;
        (void)snprintf_s(buf, buf_size, buf_size - 1, "%"G_GUINT64_FORMAT"h+%02"G_GUINT64_FORMAT"m", tmp1, tmp2);
    } else {
        // 单位为小时
        (void)snprintf_s(buf, buf_size, buf_size - 1, "%"G_GUINT64_FORMAT, raw_value);
    }
}

/*
 * Description: 打印SATA硬盘是SMART温度属性的原始值
 * History: 1.2016年4月16日
 *          新生成函数
 */
static void print_ata_smart_attr_raw_value_temperature(gchar *buf, guint32 buf_size, const guint8 *raw_value,
    const guint16 *word_grp)
{
    guint16 low = 0;
    guint16 high = 0;
    gint32 count = 0;

    if (buf_size == 0) {
        debug_log(DLOG_ERROR, "%s failed:input param error, buf_size is 0.", __FUNCTION__);
        return;
    }
    count = snprintf_s(buf, buf_size, buf_size - 1, "%u", word_grp[0]);
    if (count < 0) {
        debug_log(DLOG_ERROR, "%s snprintf_s failed.", __FUNCTION__);
        return;
    }
    if (!word_grp[1] && !word_grp[2]) {
        return; // No Min/Max
    }

    low = ~0, high = ~0;

    if (!raw_value[3]) {
        // 数据格式(IBM) 00 HH 00 LL 00 TT
        high = word_grp[2];
        low = word_grp[1];
    } else if (!word_grp[2]) {
        // 数据格式(Maxtor) 00 00 HH LL 00 TT
        high = raw_value[3];
        low = raw_value[2];
    }

    if (low > high) {
        // swap low and high
        low = low ^ high;
        high = low ^ high;
        low = low ^ high;
    }

    if (buf_size - 1 < (guint32)count) {
        debug_log(DLOG_ERROR, "%s failed:input param error, buf_size < count + 1.", __FUNCTION__);
        return;
    }

    if ((low <= word_grp[0]) && (word_grp[0] <= high)) {
        (void)snprintf_s(buf + count, buf_size - count, buf_size - count - 1, " (Lifetime Min/Max %u/%u)", low, high);
    } else {
        (void)snprintf_s(buf + count, buf_size - count, buf_size - count - 1, " (%u %u %u %u)", raw_value[5],
            raw_value[4], raw_value[3], raw_value[2]);
    }

    return;
}

/*
 * Description: 打印SATA硬盘的SMART Load/Unload cycle属性的原始值
 * History: 1.2016年4月16日
 *          新生成函数
 */
static void print_ata_smart_attr_raw_value_cycles(gchar *buf, guint32 buf_size, ATA_SMART_ATTRIBUTE_S *attr,
    guint8 select_mode, guint64 raw_value)
{
    if (buf_size == 0) {
        debug_log(DLOG_ERROR, "%s failed:input param error, buf_size is 0.", __FUNCTION__);
        return;
    }
    if (1 == select_mode) {
        // load unload
        guint32 load = attr->raw[0] + (attr->raw[1] << 8) + (attr->raw[2] << 16);
        guint32 unload = attr->raw[3] + (attr->raw[4] << 8) + (attr->raw[5] << 16);
        (void)snprintf_s(buf, buf_size, buf_size - 1, "%u/%u", load, unload);
    } else {
        // associated
        (void)snprintf_s(buf, buf_size, buf_size - 1, "%"G_GUINT64_FORMAT, raw_value);
    }

    return;
}

/*
 * Description: 打印SATA硬盘的SMART属性原始值
 * History: 1.2016年4月16日
 *          新生成函数
 */
static void parse_ata_smart_attr_raw_value(gchar *buf, guint32 buf_size, ATA_SMART_ATTRIBUTE_S *smart_attr,
    guint8 *format)
{
    guint64 raw_value = 0;
    guint64 temp_value = 0;
    guint8 raw_value_size = 0;
    guint16 word_group[3];
    guint32 idx = 0;
    guint8 select_mode = 0;
    gint32 count = 0;

    raw_value = 0;
    raw_value_size = (guint8)(sizeof(smart_attr->raw) / sizeof(smart_attr->raw[0]));

    for (idx = 0; idx < raw_value_size; idx++) { /* 结构体中数组的大小为6 */
        temp_value = smart_attr->raw[idx];
        temp_value = temp_value << (8 * idx);
        raw_value |= temp_value;
    }

    debug_log(DLOG_DEBUG,
        "SMART Attribute %d Raw Value in 64bit :  %"G_GUINT64_FORMAT" , in Byte : %02x %02x %02x %02x %02x %02x",
        smart_attr->id, raw_value, smart_attr->raw[5], smart_attr->raw[4], smart_attr->raw[3], smart_attr->raw[2],
        smart_attr->raw[1], smart_attr->raw[0]);

    // 转化为三个双字节数值
    for (idx = 0; idx < raw_value_size / 2; idx++) {
        word_group[idx] = smart_attr->raw[2 * idx + 1];
        word_group[idx] <<= 8;
        word_group[idx] |= smart_attr->raw[2 * idx];
    }

    // 如果没有数值序列，属性值有默认的含义
    select_mode = (format) ? format[smart_attr->id] : 0;

    if (buf_size == 0) {
        debug_log(DLOG_ERROR, "%s failed:input param error, buf_size is 0.", __FUNCTION__);
        return;
    }
    /* 打印6个1字节的原始数值. */
    if (253 == select_mode) {
        (void)snprintf_s(buf, buf_size, buf_size - 1, "%d %d %d %d %d %d", smart_attr->raw[5], smart_attr->raw[4],
            smart_attr->raw[3], smart_attr->raw[2], smart_attr->raw[1], smart_attr->raw[0]);
        return;
    }

    // 打印3个2字节的原始数值
    if (254 == select_mode) {
        (void)snprintf_s(buf, buf_size, buf_size - 1, "%d %d %d", word_group[2], word_group[1], word_group[0]);
        return;
    }

    // 打印一个6字节的原始数值
    if (255 == select_mode) {
        (void)snprintf_s(buf, buf_size, buf_size - 1, "%"G_GUINT64_FORMAT, raw_value);
        return;
    }

    switch (smart_attr->id) {
        // Spin-up 时间
        case ATA_SMART_ATTRIBUTE_ID_SPIN_UP_TIME:
            count = snprintf_s(buf, buf_size, buf_size - 1, "%d", word_group[0]);
            if (count < 0) {
                debug_log(DLOG_ERROR, "%s: snprintf_s failed.", __FUNCTION__);
                break;
            }
            // 如果第二个值非0存储平均spin-up时间
            if (word_group[1]) {
                (void)snprintf_s(buf + count, buf_size - count, buf_size - count - 1, " (Average %d)", word_group[1]);
            }
            break;

        // 上电时间
        case ATA_SMART_ATTRIBUTE_ID_POWER_ON_HOURS:
            print_ata_smart_attr_raw_value_power_on(buf, buf_size, select_mode, raw_value);
            break;

        // 硬盘环境温度
        case ATA_SMART_ATTRIBUTE_ID_AIRFLOW_TEMPERATURE_CELSIUS:
            print_ata_smart_attr_raw_value_temperature(buf, buf_size, smart_attr->raw, word_group);
            break;

        // 加载卸载周期
        case ATA_SMART_ATTRIBUTE_ID_LOAD_CYCLE_COUNT_193:
            print_ata_smart_attr_raw_value_cycles(buf, buf_size, smart_attr, select_mode, raw_value);
            break;

        // 硬盘内部温度
        case ATA_SMART_ATTRIBUTE_ID_TEMPERATURE_CELSIUS:
            if (select_mode == 1) {
                (void)snprintf_s(buf, buf_size, buf_size - 1, "%d.%d", word_group[0] / 10, word_group[0] % 10);
            } else if (select_mode == 2) {
                // 未知属性
                (void)snprintf_s(buf, buf_size, buf_size - 1, "%"G_GUINT64_FORMAT, raw_value);
            } else {
                print_ata_smart_attr_raw_value_temperature(buf, buf_size, smart_attr->raw, word_group);
            }
            break;

        default:
            (void)snprintf_s(buf, buf_size, buf_size - 1, "%"G_GUINT64_FORMAT, raw_value);
            break;
    }

    return;
}

/*
 Description: 按条目dump SATA硬盘smart attribute
 */
static void dump_sata_smart_attribute_by_entry(ATA_SMART_ATTRIBUTE_S *attr_info,
    ATA_SMART_THRESHOLD_ENTRY_S *threshold_entry, gchar *write_buf, gsize write_buf_size, gint32 fd)
{
    gchar *attr_status = NULL;
    gint32 failed_now = 0;
    gint32 failed_ever = 0;
    gchar thresholdstr[16] = { 0 };

    if (attr_info == NULL || threshold_entry == NULL || write_buf == NULL ||
        write_buf_size < SMLIB_DUMP_SMART_INFO_BUF_SIZE) {
        debug_log(DLOG_ERROR, "%s: invalid input.", __FUNCTION__);
        return;
    }

    if (threshold_entry->threshold == 0) {
        failed_now = (attr_info->current <= threshold_entry->threshold);
        failed_ever = (attr_info->worst <= threshold_entry->threshold);
    }

    if (attr_info->id != threshold_entry->id) {
        (void)snprintf_s(thresholdstr, sizeof(thresholdstr), sizeof(thresholdstr) - 1, "---");
    } else {
        (void)snprintf_s(thresholdstr, sizeof(thresholdstr), sizeof(thresholdstr) - 1, "%u",
            threshold_entry->threshold);
    }

    // 判断是否有历史失败记录
    if (failed_now) {
        attr_status = "FAILING_NOW";
    } else if (failed_ever) {
        attr_status = "IN_THE_PAST";
    } else {
        attr_status = "    -";
    }

    const gchar *disk_type = IS_ATA_SMART_ATTRIBUTE_FLAGS_VALID(attr_info->flags, 0) ? "Pre-fail" : "Old_age";
    const gchar *disk_update = IS_ATA_SMART_ATTRIBUTE_FLAGS_VALID(attr_info->flags, 1) ? "Always" : "Offline";

    errno_t securec_rv = snprintf_s(write_buf, write_buf_size, write_buf_size - 1, "%3hu %-30s  ", attr_info->id,
        get_ata_smart_attr_name(attr_info->id));
    if (securec_rv != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s failed, ret = %d", __FUNCTION__, securec_rv);
    }

    gint32 retval = snprintf_s(write_buf + strlen(write_buf), write_buf_size - strlen(write_buf),
        write_buf_size - strlen(write_buf) - 1, "0x%u   %u   %u   %s       %-10s%-9s%-12s",
        attr_info->flags, attr_info->current, attr_info->worst, thresholdstr, disk_type, disk_update,
        attr_status);
    if (retval <= 0) {
        debug_log(DLOG_ERROR, "%s: snprintf_s fail, ret = %d", __FUNCTION__, retval);
    }

    // 打印属性的原始值
    parse_ata_smart_attr_raw_value(write_buf + strlen(write_buf), write_buf_size - strlen(write_buf),
        attr_info, NULL);

    (void)snprintf_s(write_buf + strlen(write_buf), write_buf_size - strlen(write_buf),
        write_buf_size - strlen(write_buf) - 1, "\n");
    if (write(fd, write_buf, strlen(write_buf)) != strlen(write_buf)) {
        debug_log(DLOG_ERROR, "%s: write fail", __FUNCTION__);
    }

    return;
}

/*
 Description: dump SATA硬盘smart attribute
 */
static void dump_sata_smart_attribute(ATA_SMART_DATA_S *smart_data, ATA_SMART_THRESHOLDS_S *smart_threshold,
    gchar *write_buf, gsize write_buf_size, gint32 fd)
{
    guint32 idx;

    for (idx = 0; idx < G_N_ELEMENTS(smart_data->smartAttribute); idx++) { /* smart 信息的个数为30 */
        ATA_SMART_ATTRIBUTE_S *attr_info = &smart_data->smartAttribute[idx];
        ATA_SMART_THRESHOLD_ENTRY_S *threshold_entry = &smart_threshold->thresholdEntries[idx];

        if (attr_info->id == 0) {
            continue;
        }

        dump_sata_smart_attribute_by_entry(attr_info, threshold_entry, write_buf, write_buf_size, fd);
    }

    return;
}

/*
 Description: dump SATA硬盘smart信息
 */
static void dump_sata_smart_info(SML_CTRL_S* sml_ctrl, guint32 idx, gchar* write_buf, gsize write_buf_size, gint32 fd)
{
    gint32 retval;

    if (sml_ctrl == NULL || write_buf == NULL || write_buf_size < SMLIB_DUMP_SMART_INFO_BUF_SIZE) {
        debug_log(DLOG_ERROR, "%s: invalid input.", __FUNCTION__);
        return;
    }

    if (snprintf_s(write_buf, write_buf_size, write_buf_size - 1, "%-30s : %s\n", "Interface Type",
        "SATA") <= 0) {
        debug_log(DLOG_ERROR, "%s: snprintf_s failed.", __FUNCTION__);
        return;
    }
    retval = write(fd, write_buf, strlen(write_buf));
    if (retval != strlen(write_buf)) {
        return;
    }

    ATA_SMART_DATA_S *smart_data =
        (ATA_SMART_DATA_S *)sml_ctrl->controller.pd[idx].smartinfo.SATADevice.smart_data;
    ATA_SMART_THRESHOLDS_S *smart_threshold =
        (ATA_SMART_THRESHOLDS_S *)sml_ctrl->controller.pd[idx].smartinfo.SATADevice.smart_threshold;

    (void)snprintf_s(write_buf, write_buf_size, write_buf_size - 1,
        "SMART Attributes Data Revision Number: %u\n", smart_data->revNumber);
    retval = write(fd, write_buf, strlen(write_buf));
    if (retval != strlen(write_buf)) {
        return;
    }

    (void)snprintf_s(write_buf, write_buf_size, write_buf_size - 1,
        "Vender Specific SMART Attributes with Thresholds:\n");
    retval = write(fd, write_buf, strlen(write_buf));
    if (retval != strlen(write_buf)) {
        return;
    }

    (void)snprintf_s(write_buf, write_buf_size, write_buf_size - 1,
        "ID# ATTRIBUTE_NAME                  FLAG     VALUE WORST THRESHOLD TYPE      UPDATED  WHEN_FAILED "
        "RAW_VALUE\n");
    retval = write(fd, write_buf, strlen(write_buf));
    if (retval != strlen(write_buf)) {
        return;
    }

    dump_sata_smart_attribute(smart_data, smart_threshold, write_buf, write_buf_size, fd);

    (void)snprintf_s(write_buf, write_buf_size, write_buf_size - 1, "\n\n\n");
    retval = write(fd, write_buf, strlen(write_buf));
    if (retval != strlen(write_buf)) {
        return;
    }

    return;
}

/*
 Description: dump SAS硬盘smart信息
 */
static void dump_sas_smart_info(SML_CTRL_S* sml_ctrl, guint32 idx, gchar* write_buf, gsize write_buf_size, gint32 fd)
{
    gint32 retval = 0;

    if (sml_ctrl == NULL || write_buf == NULL || write_buf_size < SMLIB_DUMP_SMART_INFO_BUF_SIZE) {
        debug_log(DLOG_ERROR, "%s: invalid input.", __FUNCTION__);
        return;
    }

    if (snprintf_s(write_buf, write_buf_size, write_buf_size - 1, "%-30s : %s\n", "Interface Type",
        "SAS") <= 0) {
        debug_log(DLOG_ERROR, "%s: snprintf_s failed.", __FUNCTION__);
        return;
    }
    retval = write(fd, write_buf, strlen(write_buf));
    if (retval != strlen(write_buf)) {
        return;
    }

    retval = snprintf_s(write_buf, write_buf_size, write_buf_size - 1,
                        "%-30s : ASC = 0x%02X  ASCQ = 0x%02X\n\n\n",
                        "SMART Health Status", sml_ctrl->controller.pd[idx].smartinfo.SASDevice.ASC,
                        sml_ctrl->controller.pd[idx].smartinfo.SASDevice.ASCQ);
    if (retval <= 0) {
        debug_log(DLOG_ERROR, "%s: snprintf_s failed.", __FUNCTION__);
        return;
    }

    retval = write(fd, write_buf, strlen(write_buf));
    if (retval != strlen(write_buf)) {
        return;
    }

    return;
}

/*
 * Description: Dump硬盘SMART信息，写入文件句柄fd指定的文件中
 * History: 1.2016年4月16日
 *          新生成函数
 */
static void dump_pd_smart_info(guint8 ctrl_index, gint32 fd)
{
    gint32 retval = 0;
    guint32 idx = 0;
    gchar write_buf[SMLIB_DUMP_SMART_INFO_BUF_SIZE] = { 0 };
    SML_CTRL_S* sml_ctrl = NULL;

    (void)snprintf_s(write_buf, sizeof(write_buf), sizeof(write_buf) - 1,
        "Physical Drive SMART information attached to RAID Controller %u\n\n", ctrl_index);
    retval = write(fd, write_buf, strlen(write_buf));
    if (retval != strlen(write_buf)) {
        return;
    }

    lock_ctrl_list_mutex(ctrl_index);
    sml_ctrl = get_ctrl_by_index(ctrl_index);
    if (sml_ctrl == NULL) {
        unlock_ctrl_list_mutex(ctrl_index);
        return;
    }
    g_mutex_lock(&sml_ctrl->ctrl_mutex);

    for (idx = 0; idx < sml_ctrl->controller.pdlist.pd_count; idx++) {
        (void)snprintf_s(write_buf, sizeof(write_buf), sizeof(write_buf) - 1, "%-30s : %u\n", "Device Id",
            sml_ctrl->controller.pd[idx].pdinfo.device_id);
        retval = write(fd, write_buf, strlen(write_buf));
        if (retval != strlen(write_buf)) {
            break;
        }

        (void)snprintf_s(write_buf, sizeof(write_buf), sizeof(write_buf) - 1, "%-30s : %u\n", "Slot Number",
            sml_ctrl->controller.pd[idx].pdinfo.slot_num);
        retval = write(fd, write_buf, strlen(write_buf));
        if (retval != strlen(write_buf)) {
            break;
        }

        if (sml_ctrl->controller.pd[idx].smartinfo.valid_flag == FALSE) {
            (void)snprintf_s(write_buf, sizeof(write_buf), sizeof(write_buf) - 1, "SMART Data is Unavailable\n\n\n");
            retval = write(fd, write_buf, strlen(write_buf));
            if (retval != strlen(write_buf)) {
                break;
            }
            continue;
        }

        if (sml_ctrl->controller.pd[idx].pdinfo.interface_type == PD_INTERFACE_TYPE_SATA) {
            dump_sata_smart_info(sml_ctrl, idx, write_buf, sizeof(write_buf), fd);
        } else if (sml_ctrl->controller.pd[idx].pdinfo.interface_type == PD_INTERFACE_TYPE_SAS) {
            dump_sas_smart_info(sml_ctrl, idx, write_buf, sizeof(write_buf), fd);
        } else {
            if (snprintf_s(write_buf, sizeof(write_buf), sizeof(write_buf) - 1, "%-30s : %s\n\n\n", "Interface Type",
                "Unknown") <= 0) {
                debug_log(DLOG_ERROR, "%s: snprintf_s failed.", __FUNCTION__);
                break;
            }
            retval = write(fd, write_buf, strlen(write_buf));
            if (retval != strlen(write_buf)) {
                break;
            }
        }
    }

    g_mutex_unlock(&sml_ctrl->ctrl_mutex);
    unlock_ctrl_list_mutex(ctrl_index);

    return;
}

/*
 * Description: 检查物理盘信息中是否包含产生状态异常告警的信息，并标记检查结果，标记的结果给物理盘告警信息防抖使用
 */
static void check_pd_status_abnomal_warning_infos(SML_PD_INFO_S *pd_info, guint8 *warnning_cfm_cnt,
    guint8 *no_warnning_info, guint32 warnning_cfm_size)
{
    if ((pd_info->pdinfo.fw_state == PD_STATE_UNCONFIGURED_BAD) || (pd_info->pdinfo.fw_state == PD_STATE_OFFLINE) ||
        (pd_info->pdinfo.fw_state == PD_STATE_FAILED) || (pd_info->pdinfo.fw_state == PD_STATE_FOREIGN)) {
        if (pd_info->pd_warnig_info_reported[PD_WARNNING_INFO_FW_STATE]) { // 已经上报的信息，直接标记信息确认次数为最大
            warnning_cfm_cnt[PD_WARNNING_INFO_FW_STATE] = MAX_WARNNING_INFO_DEBOUNCE_COUNT;
        } else {
            warnning_cfm_cnt[PD_WARNNING_INFO_FW_STATE]++;
        }
    } else {
        no_warnning_info[PD_WARNNING_INFO_FW_STATE] = TRUE; // 只要出现过1次不包含告警信息的标记，防抖就不可能成功
        if (pd_info->pd_warnig_info_reported[PD_WARNNING_INFO_FW_STATE]) {
            pd_info->pd_warnig_info_reported[PD_WARNNING_INFO_FW_STATE] = 0;
            warnning_cfm_cnt[PD_WARNNING_INFO_FW_STATE] = 0;
        }
    }
}

/*
 * Description: 检查物理盘信息中是否包含产生容量异常告警的信息，并标记检查结果，标记的结果给物理盘告警信息防抖使用
 */
static void check_pd_capacity_error_warning_infos(SML_PD_INFO_S *pd_info, guint8 *warnning_cfm_cnt,
    guint8 *no_warnning_info, guint32 warnning_cfm_size)
{
    if (pd_info->pdinfo.coerced_size < (5 * 1024)) {
        if (pd_info->pd_warnig_info_reported[PD_WARNNING_INFO_CAPACITY]) { // 已经上报的信息，直接标记信息确认次数为最大
            warnning_cfm_cnt[PD_WARNNING_INFO_CAPACITY] = MAX_WARNNING_INFO_DEBOUNCE_COUNT;
        } else {
            warnning_cfm_cnt[PD_WARNNING_INFO_CAPACITY]++;
        }
    } else {
        no_warnning_info[PD_WARNNING_INFO_CAPACITY] = TRUE; // 只要出现过1次不包含告警信息的标记，防抖就不可能成功
        if (pd_info->pd_warnig_info_reported[PD_WARNNING_INFO_CAPACITY]) {
            pd_info->pd_warnig_info_reported[PD_WARNNING_INFO_CAPACITY] = 0;
            warnning_cfm_cnt[PD_WARNNING_INFO_CAPACITY] = 0;
        }
    }
}

/*
 * Description: 检查物理盘信息中是否包含产生媒介错误计数告警的信息，并标记检查结果，标记的结果给物理盘告警信息防抖使用
 */
static void check_pd_media_error_warnning_infos(SML_PD_INFO_S *pd_info, guint8 *warnning_cfm_cnt,
    guint8 *no_warnning_info, guint32 warnning_cfm_size)
{
    if (pd_info->pdinfo.media_err_count != 0) {
        if (pd_info->pd_warnig_info_reported[PD_WARNNING_INFO_MEDIA_ERR_COUNT]) { // 已经上报的信息，直接标记信息确认次数为最大
            warnning_cfm_cnt[PD_WARNNING_INFO_MEDIA_ERR_COUNT] = MAX_WARNNING_INFO_DEBOUNCE_COUNT;
        } else {
            warnning_cfm_cnt[PD_WARNNING_INFO_MEDIA_ERR_COUNT]++;
        }
    } else {
        no_warnning_info[PD_WARNNING_INFO_MEDIA_ERR_COUNT] =
            TRUE; // 只要出现过1次不包含告警信息的标记，防抖就不可能成功
        if (pd_info->pd_warnig_info_reported[PD_WARNNING_INFO_MEDIA_ERR_COUNT]) {
            pd_info->pd_warnig_info_reported[PD_WARNNING_INFO_MEDIA_ERR_COUNT] = 0;
            warnning_cfm_cnt[PD_WARNNING_INFO_MEDIA_ERR_COUNT] = 0;
        }
    }
}

/*
 * Description: 检查物理盘信息中是否包含产生预故障告警的信息，并标记检查结果，标记的结果给物理盘告警信息防抖使用
 */
static void check_pd_prefail_warnning_infos(SML_PD_INFO_S *pd_info, guint8 *warnning_cfm_cnt,
    guint8 *no_warnning_info, guint32 warnning_cfm_size)
{
    if (pd_info->pdinfo.prefail_count != 0 || pd_info->pdinfo.fw_state == PD_STATE_PREDICTIVE_FAILURE) {
        if (pd_info->pd_warnig_info_reported[PD_WARNNING_INFO_PREFAIL_COUNT]) { // 已经上报的信息，直接标记信息确认次数为最大
            warnning_cfm_cnt[PD_WARNNING_INFO_PREFAIL_COUNT] = MAX_WARNNING_INFO_DEBOUNCE_COUNT;
        } else {
            warnning_cfm_cnt[PD_WARNNING_INFO_PREFAIL_COUNT]++;
        }
    } else {
        no_warnning_info[PD_WARNNING_INFO_PREFAIL_COUNT] = TRUE; // 只要出现过1次不包含告警信息的标记，防抖就不可能成功
        if (pd_info->pd_warnig_info_reported[PD_WARNNING_INFO_PREFAIL_COUNT]) {
            pd_info->pd_warnig_info_reported[PD_WARNNING_INFO_PREFAIL_COUNT] = 0;
            warnning_cfm_cnt[PD_WARNNING_INFO_PREFAIL_COUNT] = 0;
        }
    }
}

/* ****************************************************************************
 函 数 名  : check_pd_warnning_infos
 功能描述  : 检查物理盘信息中是否包含产生告警的信息，并标记检查结果，标记的结果给物理盘告警信息防抖使用
 输入参数  : SML_LD_INFO_S *ld_info
             guint8 *warnning_cfm_cnt
             guint8 *no_warnning_info
 输出参数  : 无
 返 回 值  : static void

 修改历史      :
  1.日    期   : 2017年4月19日
    作    者   :  ()
    修改内容   : 新生成函数

**************************************************************************** */
static void check_pd_warnning_infos(SML_PD_INFO_S *pd_info, guint8 *warnning_cfm_cnt, guint8 *no_warnning_info,
    guint32 warnning_cfm_size)
{
    if ((NULL == pd_info) || (NULL == warnning_cfm_cnt) || (NULL == no_warnning_info) ||
        (warnning_cfm_size < MAX_PD_WARNNING_INFO)) {
        return;
    }

    // 硬盘固件状态
    check_pd_status_abnomal_warning_infos(pd_info, warnning_cfm_cnt, no_warnning_info, warnning_cfm_size);

    // 硬盘容量小于5GB
    check_pd_capacity_error_warning_infos(pd_info, warnning_cfm_cnt, no_warnning_info, warnning_cfm_size);

    // 硬盘媒介错误计数
    check_pd_media_error_warnning_infos(pd_info, warnning_cfm_cnt, no_warnning_info, warnning_cfm_size);

    // 硬盘预失效计数
    check_pd_prefail_warnning_infos(pd_info, warnning_cfm_cnt, no_warnning_info, warnning_cfm_size);
}

// 检查当前能否获取物理盘信息
static void check_get_pd_info_valid(SML_CTRL_S* sml_ctrl, gint32 *locked, guint16 pd_index)
{
    guint32 current_timestamp;
    guint32 last_udate_timestamp;
    guint8 refresh_polciy;
    guint8 slot_id;
    gint32 data_validity;

#ifdef ITEST_ENABLED
    current_timestamp = iTest_get_cur_time_stamp();
#else
    current_timestamp = (guint32)time(0);
#endif

    g_mutex_lock(&sml_ctrl->ctrl_mutex);

    last_udate_timestamp = sml_ctrl->controller.pd[pd_index].last_update_timestamp;
    slot_id = sml_ctrl->controller.pdlist.slot_num[pd_index];
    refresh_polciy = sml_ctrl->controller.pd_refresh_ctrl[slot_id];

    g_mutex_unlock(&sml_ctrl->ctrl_mutex);

    // 上次更新数据的时间是0或者距离上次更新数据已经超过数据更新时间间隔，并且当前控制器没有在执行任何操作，否则直接取缓存数据
    data_validity = check_cache_data_is_expired(refresh_polciy, current_timestamp, last_udate_timestamp,
        SMLIB_UPDATE_CACHE_DATA_INTREVAL);
    // 超时刷新，试探获取操作锁；如果是无效数据或者强制刷新，必须等待获取操作锁
    if (data_validity == CACHE_DATA_INVALID_TIMEOUT) {
        if (g_mutex_trylock(&sml_ctrl->op_mutex)) {
            *locked = TRUE;
        } else {
            debug_log(DLOG_DEBUG, "smlib_get_pd_info: op_mutex locked, skip operation\n");
        }
    } else if ((data_validity == CACHE_DATA_INVALID_NO_DATA) || (data_validity == CACHE_DATA_INVALID_FORCED)) {
        g_mutex_lock(&sml_ctrl->op_mutex);
        *locked = TRUE;
    }
    return;
}

/*
 * Description: 获取物理盘的详细信息
 * History: 1.2016年4月7日
 *          新生成函数
 */
gint32 smlib_get_pd_info(guint8 ctrl_index, guint16 pd_device_id, SML_PD_BASIC_INFO_S *pd)
{
    gint32 retval = SML_SUCCESS;
    guint16 pd_index = 0;
    guint32 current_timestamp = 0;
    guint32 last_udate_timestamp = 0;
    guint8 updated = FALSE;
    SML_PD_INFO_S new_pd_info = { 0 };
    guint8 refresh_polciy = 0;
    guint8 slot_id = 0;
    gint32 data_validity = 0;
    gint32 locked = FALSE;

    guint8 try_count = 0;
    guint8 i = 0;
    guint8 warnning_cfm_cnt[MAX_PD_WARNNING_INFO];
    guint8 no_warnning_info[MAX_PD_WARNNING_INFO];
    guint8 debounce_failed[MAX_PD_WARNNING_INFO];

    guint8 bak_fw_state = 0;
    guint32 bak_coerced_size = 0;
    guint32 bak_media_err_count = 0;
    guint32 bak_prefail_count = 0;
    SML_CTRL_S* sml_ctrl = NULL;

    if (SML_SUCCESS != (retval = check_input_parameters(ctrl_index, pd))) {
        return retval;
    }
    lock_ctrl_list_mutex(ctrl_index);
    sml_ctrl = get_ctrl_by_index(ctrl_index);
    if (sml_ctrl == NULL) {
        unlock_ctrl_list_mutex(ctrl_index);
        return SML_ERR_CTRL_NOT_REGISTERED;
    }
    if (RET_OK != check_pd_device_id(pd_device_id, &sml_ctrl->controller.pdlist, &pd_index)) {
        unlock_ctrl_list_mutex(ctrl_index);
        return SML_ERR_PD_INVALID_DEVICE_ID;
    }

#ifdef ITEST_ENABLED
    current_timestamp = iTest_get_cur_time_stamp();
#else
    current_timestamp = (guint32)time(0);
#endif

    g_mutex_lock(&sml_ctrl->ctrl_mutex);

    // 因为获取物理盘的SMART信息时，会使用到全局缓存中的SMART信息更新时间作为输入参数，所以这里必须将缓存数据拷贝过来
    memcpy_s(&new_pd_info, sizeof(SML_PD_INFO_S), &sml_ctrl->controller.pd[pd_index],
        sizeof(SML_PD_INFO_S));

    last_udate_timestamp = sml_ctrl->controller.pd[pd_index].last_update_timestamp;
    slot_id = sml_ctrl->controller.pdlist.slot_num[pd_index];
    refresh_polciy = sml_ctrl->controller.pd_refresh_ctrl[slot_id];

    g_mutex_unlock(&sml_ctrl->ctrl_mutex);

    (void)memset_s(warnning_cfm_cnt, MAX_PD_WARNNING_INFO, 0, MAX_PD_WARNNING_INFO);
    (void)memset_s(no_warnning_info, MAX_PD_WARNNING_INFO, FALSE, MAX_PD_WARNNING_INFO);
    (void)memset_s(debounce_failed, MAX_PD_WARNNING_INFO, FALSE, MAX_PD_WARNNING_INFO);

    // 备份可能的告警信息以备防抖失败时恢复
    bak_fw_state = new_pd_info.pdinfo.fw_state;
    bak_coerced_size = new_pd_info.pdinfo.coerced_size;
    bak_media_err_count = new_pd_info.pdinfo.media_err_count;
    bak_prefail_count = new_pd_info.pdinfo.prefail_count;

    // 上次更新数据的时间是0或者距离上次更新数据已经超过数据更新时间间隔，并且当前控制器没有在执行任何操作，否则直接取缓存数据
    data_validity = check_cache_data_is_expired(refresh_polciy, current_timestamp, last_udate_timestamp,
        SMLIB_UPDATE_CACHE_DATA_INTREVAL);
    // 超时刷新，试探获取操作锁；如果是无效数据或者强制刷新，必须等待获取操作锁
    if (CACHE_DATA_INVALID_TIMEOUT == data_validity) {
        if (g_mutex_trylock(&sml_ctrl->op_mutex)) {
            locked = TRUE;
        } else {
            debug_log(DLOG_DEBUG, "smlib_get_pd_info: op_mutex locked, skip operation\n");
        }
    } else if ((CACHE_DATA_INVALID_NO_DATA == data_validity) || (CACHE_DATA_INVALID_FORCED == data_validity)) {
        g_mutex_lock(&sml_ctrl->op_mutex);
        locked = TRUE;
    }

    if (locked) {
        if (NULL != sml_ctrl->pfn_get_pd_info) {
            do {
                try_count++;

                // 调用适配层接口获取数据，成功则将数据更新至全局缓存数据区
                retval = sml_ctrl->pfn_get_pd_info(sml_ctrl->controller_id, pd_device_id,
                    &new_pd_info);
                if (SML_SUCCESS == retval) {
                    check_pd_warnning_infos(&new_pd_info, warnning_cfm_cnt, no_warnning_info, sizeof(warnning_cfm_cnt));

                    // 判断是否需要从RAID卡读下一次数据，不需要则直接退出防抖
                    // 全部数据都出现过无告警的信息或者告警信息已经确认上报过，退出防抖读取
                    if (((no_warnning_info[PD_WARNNING_INFO_FW_STATE] == TRUE) ||
                        (warnning_cfm_cnt[PD_WARNNING_INFO_FW_STATE] == MAX_WARNNING_INFO_DEBOUNCE_COUNT)) &&
                        ((no_warnning_info[PD_WARNNING_INFO_CAPACITY] == TRUE) ||
                        (warnning_cfm_cnt[PD_WARNNING_INFO_CAPACITY] == MAX_WARNNING_INFO_DEBOUNCE_COUNT)) &&
                        ((no_warnning_info[PD_WARNNING_INFO_MEDIA_ERR_COUNT] == TRUE) ||
                        (warnning_cfm_cnt[PD_WARNNING_INFO_MEDIA_ERR_COUNT] == MAX_WARNNING_INFO_DEBOUNCE_COUNT)) &&
                        ((no_warnning_info[PD_WARNNING_INFO_PREFAIL_COUNT] == TRUE) ||
                        (warnning_cfm_cnt[PD_WARNNING_INFO_PREFAIL_COUNT] == MAX_WARNNING_INFO_DEBOUNCE_COUNT))) {
                        break;
                    }
                } else {
                    debug_log(DLOG_DEBUG,
                        "smlib: Get RAID controller [Ctrl index %d, Ctrl ID %d] PD info failed, return 0x%04x\n",
                        ctrl_index, SML_CTRL_ID_VALID_BIT(sml_ctrl->controller_id), retval);
                    break;
                }

                // 如果还需要读控制器，需要延时
                /* BEGIN: Modified for PN:CSEC on 2018/12/7 */
                if (MAX_WARNNING_INFO_DEBOUNCE_COUNT > try_count) {
                    // delay前先解锁，避免阻塞其他进程对控制器的读写操作
                    g_mutex_unlock(&sml_ctrl->op_mutex);
                    unlock_ctrl_list_mutex(ctrl_index);
                    vos_task_delay(RAID_INFO_DEBOUNCE_DELAY);
                    lock_ctrl_list_mutex(ctrl_index);
                    if (sml_ctrl == NULL) {
                        unlock_ctrl_list_mutex(ctrl_index);
                        return SML_ERR_CTRL_NOT_REGISTERED;
                    }
                    g_mutex_lock(&sml_ctrl->op_mutex);
                }

                /* END:   Modified for PN:CSEC on 2018/12/7 */
            } while (try_count < MAX_WARNNING_INFO_DEBOUNCE_COUNT);
        } else {
            retval = SML_ERR_NULL_INFTERFACE;
        }

        g_mutex_unlock(&sml_ctrl->op_mutex);
    }

    // 设置防抖上报结果, 检查防抖结果中是否有启动了防抖但是防抖失败的情况
    if (try_count != 0) {
        for (i = 0; i < MAX_PD_WARNNING_INFO; i++) {
            if (warnning_cfm_cnt[i] == MAX_WARNNING_INFO_DEBOUNCE_COUNT) {
                new_pd_info.pd_warnig_info_reported[i] = 1;
            } else {
                new_pd_info.pd_warnig_info_reported[i] = 0;
            }

            if ((warnning_cfm_cnt[i] != MAX_WARNNING_INFO_DEBOUNCE_COUNT) && (warnning_cfm_cnt[i] != 0)) {
                debounce_failed[i] = TRUE;
            }
        }
    }

    // 从RAID卡读取数据成功的就可以更新数据
    updated = ((try_count != 0) && (SML_SUCCESS == retval)) ? TRUE : FALSE;

    // 实际从RAID卡更新数据会耗费几百毫秒到几秒的时间，这里再次获取当前系统时间记录更准确
#ifdef ITEST_ENABLED
    current_timestamp = iTest_get_cur_time_stamp();
#else
    current_timestamp = (guint32)time(0);
#endif
    /* END:   Modified on 2017/4/19 */

    // 集中更新缓存数据，拷贝需要返回的数据
    g_mutex_lock(&sml_ctrl->ctrl_mutex);

    // 从RAID卡实际执行结果更新数据到全局缓存
    if (updated) {
        if (TRUE == debounce_failed[PD_WARNNING_INFO_FW_STATE]) {
            new_pd_info.pdinfo.fw_state = bak_fw_state;
        }
        if (TRUE == debounce_failed[PD_WARNNING_INFO_CAPACITY]) {
            new_pd_info.pdinfo.coerced_size = bak_coerced_size;
        }
        if (TRUE == debounce_failed[PD_WARNNING_INFO_MEDIA_ERR_COUNT]) {
            new_pd_info.pdinfo.media_err_count = bak_media_err_count;
        }
        if (TRUE == debounce_failed[PD_WARNNING_INFO_PREFAIL_COUNT]) {
            new_pd_info.pdinfo.prefail_count = bak_prefail_count;
        }

        memcpy_s(&sml_ctrl->controller.pd[pd_index], sizeof(SML_PD_INFO_S), &new_pd_info,
            sizeof(SML_PD_INFO_S));
        sml_ctrl->controller.pd[pd_index].last_update_timestamp = current_timestamp;
        sml_ctrl->controller.pd_refresh_ctrl[slot_id] = update_refresh_policy(refresh_polciy);

        if (sml_ctrl->controller.ctrl.operations.pd_operations.support_temperature == 0) {
            sml_ctrl->controller.pd[pd_index].pdinfo.temperature = 0xFF; // invalid temperature
        }
    } else {
        // 如果强制从缓存读取数据，则需要刷新最后更新的时间
        if ((RAID_REFRESH_INTERNAL_CACHE == (refresh_polciy & 0x0f)) && (refresh_polciy & 0xf0)) {
            sml_ctrl->controller.pd[pd_index].last_update_timestamp = current_timestamp;
            sml_ctrl->controller.pd_refresh_ctrl[slot_id] = update_refresh_policy(refresh_polciy);
        }
    }

    if (SML_SUCCESS != retval) {
        (void)memset_s(sml_ctrl->controller.pd[pd_index].pd_warnig_info_reported, MAX_PD_WARNNING_INFO, 0,
            MAX_PD_WARNNING_INFO);
    }
    memcpy_s(pd, sizeof(SML_PD_BASIC_INFO_S), &sml_ctrl->controller.pd[pd_index].pdinfo,
        sizeof(SML_PD_BASIC_INFO_S));

    g_mutex_unlock(&sml_ctrl->ctrl_mutex);
    unlock_ctrl_list_mutex(ctrl_index);

    return retval;
}

// 获取SAS硬盘SMART信息
gint32 smlib_get_pd_sas_smart_info(guint8 ctrl_index, guint16 pd_device_id, SML_PD_SAS_SMART_INFO *smart_info)
{
    gint32 retval = SML_SUCCESS;
    guint16 pd_index = 0;
    SML_PD_SAS_SMART_INFO new_smart_info = { 0 };
    gint32 locked = FALSE;

    SML_CTRL_S* sml_ctrl = NULL;

    if ((retval = check_input_parameters(ctrl_index, smart_info)) != SML_SUCCESS) {
        return retval;
    }
    lock_ctrl_list_mutex(ctrl_index);
    sml_ctrl = get_ctrl_by_index(ctrl_index);
    if (RET_OK != check_pd_device_id(pd_device_id, &sml_ctrl->controller.pdlist, &pd_index)) {
        unlock_ctrl_list_mutex(ctrl_index);
        return SML_ERR_PD_INVALID_DEVICE_ID;
    }

    check_get_pd_info_valid(sml_ctrl, &locked, pd_index);

    if (!locked) {
        unlock_ctrl_list_mutex(ctrl_index);
        return retval;
    }

    if (sml_ctrl->pfn_get_pd_smart_info == NULL) {
        retval = SML_ERR_NULL_INFTERFACE;
    } else {
        // 调用适配层接口获取数据
        retval = sml_ctrl->pfn_get_pd_smart_info(sml_ctrl->controller_id, pd_device_id, &new_smart_info);
        if (retval != SML_SUCCESS) {
            debug_log(DLOG_DEBUG,
                "smlib: Get RAID controller [Ctrl index %u, Ctrl ID %u] PD SMART info failed, return 0x%04x",
                ctrl_index, SML_CTRL_ID_VALID_BIT(sml_ctrl->controller_id), retval);
        } else {
            retval = memcpy_s(smart_info, sizeof(SML_PD_SAS_SMART_INFO), &new_smart_info,
                sizeof(SML_PD_SAS_SMART_INFO));
        }
    }
    g_mutex_unlock(&sml_ctrl->op_mutex);
    unlock_ctrl_list_mutex(ctrl_index);
    return retval;
}

// 动态获取SAS硬盘SMART信息
gint32 smlib_get_pd_sas_smart_info_spec(
    guint8 ctrl_index, guint16 pd_device_id, SML_PD_SAS_SMART_INFO *smart_info, guint8 filter)
{
    gint32 retval = SML_SUCCESS;
    guint16 pd_index = 0;
    SML_PD_SAS_SMART_INFO new_smart_info = { 0 };
    gint32 locked = FALSE;

    SML_CTRL_S* sml_ctrl = NULL;

    if ((retval = check_input_parameters(ctrl_index, smart_info)) != SML_SUCCESS) {
        return retval;
    }
    lock_ctrl_list_mutex(ctrl_index);
    sml_ctrl = get_ctrl_by_index(ctrl_index);
    if (RET_OK != check_pd_device_id(pd_device_id, &sml_ctrl->controller.pdlist, &pd_index)) {
        unlock_ctrl_list_mutex(ctrl_index);
        return SML_ERR_PD_INVALID_DEVICE_ID;
    }

    check_get_pd_info_valid(sml_ctrl, &locked, pd_index);

    if (!locked) {
        unlock_ctrl_list_mutex(ctrl_index);
        return retval;
    }

    if (sml_ctrl->pfn_get_pd_smart_info == NULL) {
        retval = SML_ERR_NULL_INFTERFACE;
    } else {
        // 调用适配层接口获取数据
        retval = sml_ctrl->pfn_get_pd_smart_info_spec(sml_ctrl->controller_id, pd_device_id, &new_smart_info, filter);
        if (retval != SML_SUCCESS) {
            debug_log(DLOG_ERROR,
                "smlib: Get RAID controller [Ctrl index %u, Ctrl ID %u] PD SMART info failed, return 0x%04x",
                ctrl_index, SML_CTRL_ID_VALID_BIT(sml_ctrl->controller_id), retval);
        } else {
            retval = memcpy_s(smart_info, sizeof(SML_PD_SAS_SMART_INFO), &new_smart_info,
                sizeof(SML_PD_SAS_SMART_INFO));
        }
    }
    g_mutex_unlock(&sml_ctrl->op_mutex);
    unlock_ctrl_list_mutex(ctrl_index);
    return retval;
}

// 获取硬盘慢盘检测信息
gint32 smlib_get_pd_slow_disk_info(guint8 ctrl_index, guint16 pd_device_id, void *slow_disk_info)
{
    gint32 retval = SML_SUCCESS;
    guint16 pd_index = 0;
    SML_CTRL_S* sml_ctrl = NULL;

    if ((retval = check_input_parameters(ctrl_index, slow_disk_info)) != SML_SUCCESS) {
        return retval;
    }
    lock_ctrl_list_mutex(ctrl_index);
    sml_ctrl = get_ctrl_by_index(ctrl_index);
    if (sml_ctrl == NULL) {
        unlock_ctrl_list_mutex(ctrl_index);
        return SML_ERR_CTRL_NOT_REGISTERED;
    }
    if (RET_OK != check_pd_device_id(pd_device_id, &sml_ctrl->controller.pdlist, &pd_index)) {
        unlock_ctrl_list_mutex(ctrl_index);
        return SML_ERR_PD_INVALID_DEVICE_ID;
    }
    g_mutex_lock(&sml_ctrl->ctrl_mutex);
    retval = memcpy_s(slow_disk_info, sizeof(SML_PD_SLOW_DATA), &sml_ctrl->controller.pd[pd_index].slow_disk_info,
        sizeof(SML_PD_SLOW_DATA));
    if (retval != SML_SUCCESS) {
        g_mutex_unlock(&sml_ctrl->ctrl_mutex);
        unlock_ctrl_list_mutex(ctrl_index);
        debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, retval);
        return retval;
    }
    (void)memset_s(&sml_ctrl->controller.pd[pd_index].slow_disk_info, sizeof(SML_PD_SLOW_DATA), 0,
        sizeof(SML_PD_SLOW_DATA));
    g_mutex_unlock(&sml_ctrl->ctrl_mutex);
    unlock_ctrl_list_mutex(ctrl_index);
    return retval;
}

/*
 * Description: 获取物理盘的日志数据
 * History: 1.2018年1月6日
 *          新生成函数
 */
gint32 smlib_get_pd_log(guint8 ctrl_index, guint16 pd_device_id, SML_PD_LOG_DATA_S *pd_log)
{
    gint32 retval = SML_SUCCESS;
    guint16 pd_index = 0;
    SML_PD_INFO_S pd_info = { 0 };
    SML_CTRL_S* sml_ctrl = NULL;

    if (SML_SUCCESS != (retval = check_input_parameters(ctrl_index, pd_log))) {
        return retval;
    }
    lock_ctrl_list_mutex(ctrl_index);
    sml_ctrl = get_ctrl_by_index(ctrl_index);
    if (sml_ctrl == NULL) {
        unlock_ctrl_list_mutex(ctrl_index);
        return SML_ERR_CTRL_NOT_REGISTERED;
    }
    if (RET_OK != check_pd_device_id(pd_device_id, &sml_ctrl->controller.pdlist, &pd_index)) {
        unlock_ctrl_list_mutex(ctrl_index);
        return SML_ERR_PD_INVALID_DEVICE_ID;
    }

    g_mutex_lock(&sml_ctrl->ctrl_mutex);
    // 获取物理盘的日志信息时, 需要使用硬盘的基本信息作为参数, 将缓存数据拷贝过来
    memcpy_s(&pd_info, sizeof(SML_PD_INFO_S), &sml_ctrl->controller.pd[pd_index], sizeof(SML_PD_INFO_S));
    g_mutex_unlock(&sml_ctrl->ctrl_mutex);

    if (NULL != sml_ctrl->pfn_get_pd_log) {
        retval =
            sml_ctrl->pfn_get_pd_log(sml_ctrl->controller_id, pd_device_id, &pd_info, pd_log);
    }
    unlock_ctrl_list_mutex(ctrl_index);

    return retval;
}

/*
 * Description: 检查时间是否超过指定的间隔
 * History: 1.2017年1月11日,  ()
 *          新生成函数
 */
static gint32 _check_time_expired(guint32 current, guint32 last, guint32 interval)
{
    if ((last == 0) || (current > last && (current - last) > interval) ||
        (last > current && (G_MAXUINT32 - last + current) > interval)) {
        return TRUE;
    }

    return FALSE;
}
/*
 * Description: 打印SATA硬盘的SMART属性原始值
 * History: 1.2016年4月16日
 *          新生成函数
 */
void smlib_parse_ata_smart_attr_raw_value(gchar *buf, guint32 buf_size, ATA_SMART_ATTRIBUTE_S *smart_attr,
    guint8 *format)
{
    parse_ata_smart_attr_raw_value(buf, buf_size, smart_attr, format);

    return;
}

/*
 * Description: 根据SMART属性ID获取SMART属性的名称
 * History: 1.2018年1月13日
 *          新生成函数
 */
const gchar *smlib_get_ata_smart_attr_name(guint8 attr_id)
{
    return get_ata_smart_attr_name(attr_id);
}
/*
 * Description: dump指定RAID控制器下的PD SMART信息至指定的路径下
 * History: 1.2016年4月15日
 *          新生成函数
 */
gint32 smlib_dump_smart_info(guint8 ctrl_index, gchar *file_path, gchar *file_short_name)
{
    gint32 iRet = -1;
    gint32 retval = SML_SUCCESS;
    gint32 dumpfile = 0;
    gchar *resolved_path = NULL;
    gchar file_name[NAME_MAX] = { 0 };
    guint32 current_timestamp = 0;
    guint32 last_timestamp = 0;
    SML_CTRL_S* sml_ctrl = NULL;

    if (SML_SUCCESS != (retval = check_input_parameters(ctrl_index, file_short_name))) {
        return retval;
    }

#ifdef ITEST_ENABLED
    current_timestamp = iTest_get_cur_time_stamp();
#else
    current_timestamp = (guint32)time(0);
#endif

    lock_ctrl_list_mutex(ctrl_index);
    sml_ctrl = get_ctrl_by_index(ctrl_index);
    if (sml_ctrl == NULL) {
        unlock_ctrl_list_mutex(ctrl_index);
        return SML_ERR_CTRL_NOT_REGISTERED;
    }
    g_mutex_lock(&sml_ctrl->ctrl_mutex);
    last_timestamp = sml_ctrl->controller.last_smart_dump_timestamp;
    g_mutex_unlock(&sml_ctrl->ctrl_mutex);
    unlock_ctrl_list_mutex(ctrl_index);

    // 只有超过指定时间后，才会执行将物理盘SMART信息写入文件
    if (!(_check_time_expired(current_timestamp, last_timestamp, SMLIB_DUMP_SMART_INFO_INTREVAL))) {
        return SML_SUCCESS;
    }

    // 路径检查
    resolved_path = realpath(file_path, NULL);
    if (NULL == resolved_path) {
        debug_log(DLOG_ERROR, "smlib:Dump all info failed, path is illegal");
        return SML_ERR_FILE_PATH_ILLEGAL;
    }

    if (strstr(resolved_path, "&") || strstr(resolved_path, "|") || strstr(resolved_path, ";")) {
        debug_log(DLOG_ERROR, "smlib:Dump all info failed, path is illegal");
        g_free(resolved_path);
        return SML_ERR_FILE_PATH_ILLEGAL;
    }

    if (file_short_name == NULL) {
        file_short_name = "SMART_INFO";
    }

    lock_ctrl_list_mutex(ctrl_index);
    if (sml_ctrl == NULL) {
        unlock_ctrl_list_mutex(ctrl_index);
        g_free(resolved_path);
        return SML_ERR_CTRL_NOT_REGISTERED;
    }
    g_mutex_lock(&sml_ctrl->ctrl_mutex);
    iRet = snprintf_s(file_name, sizeof(file_name), sizeof(file_name) - 1, "%s/%s_C%u", resolved_path, file_short_name,
        SML_CTRL_ID_VALID_BIT(sml_ctrl->controller_id));
    if (iRet <= 0) {
        debug_log(DLOG_ERROR, "%s: snprintf_s fail, ret = %d", __FUNCTION__, iRet);
    }
    g_mutex_unlock(&sml_ctrl->ctrl_mutex);
    unlock_ctrl_list_mutex(ctrl_index);

    g_free(resolved_path);

    // 创建文件
    dumpfile = open_s(file_name, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, NULL);
    if (dumpfile < 0) {
        debug_log(DLOG_ERROR, "smlib:Open file %s failed [errno %d]", file_name, errno);
        return SML_ERR_CANNOT_OPEN_FILE;
    }
    (void)chmod_s(file_name, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    // dump PhysicalDrive SMART信息
    dump_pd_smart_info(ctrl_index, dumpfile);

    close_s(dumpfile);

    // 实际从RAID卡更新数据会耗费几百毫秒到几秒的时间，这里再次获取当前系统时间记录更准确
#ifdef ITEST_ENABLED
    current_timestamp = iTest_get_cur_time_stamp();
#else
    current_timestamp = (guint32)time(0);
#endif

    // 更新写SMART信息到文件的时间戳
    lock_ctrl_list_mutex(ctrl_index);
    if (sml_ctrl == NULL) {
        unlock_ctrl_list_mutex(ctrl_index);
        return SML_ERR_CTRL_NOT_REGISTERED;
    }
    g_mutex_lock(&sml_ctrl->ctrl_mutex);
    sml_ctrl->controller.last_smart_dump_timestamp = current_timestamp;
    g_mutex_unlock(&sml_ctrl->ctrl_mutex);
    unlock_ctrl_list_mutex(ctrl_index);

    return retval;
}

/*
 * Description: 更新PD缓存数据中的启动优先级
 */
static void smlib_refresh_pd_boot_priority(SML_CTRL_S *sml_ctrl, guint16 pd_device_id, gpointer param)
{
    guint16 pd_index = 0;
    if (check_pd_device_id(pd_device_id, &sml_ctrl->controller.pdlist, &pd_index) != RET_OK) {
        return;
    }

    g_mutex_lock(&sml_ctrl->ctrl_mutex);
    guint8 boot_priority = *(guint8 *)param;
    /* 先清除再设置 */
    smlib_clear_boot_priority_from_cache(sml_ctrl, boot_priority);
    sml_ctrl->controller.pd[pd_index].pdinfo.boot_priority = boot_priority;
    g_mutex_unlock(&sml_ctrl->ctrl_mutex);
    return;
}

static void smlib_refresh_pd_cache(SML_CTRL_S *sml_ctrl, guint8 ctrl_index, guint16 pd_device_id, guint8 operation,
    gpointer param)
{
    switch (operation) {
        case PD_OPERATION_SET_GLOBAL_HOTSPARE:
            smlib_refresh_specfied_pds_from_hw_next(ctrl_index, &pd_device_id, 1, 1);

            smlib_refresh_all_lds_from_cache_next(ctrl_index, 1);
            smlib_refresh_all_arrays_from_cache_next(ctrl_index, 1);
            smlib_refresh_all_other_from_cache_next(ctrl_index, 1);
            break;

        case PD_OPERATION_SET_DEDICATED_HOTSPARE:
        case PD_OPERATION_SET_AUTO_REPLACE_HOTSPARE:
            smlib_refresh_specfied_pds_from_hw_next(ctrl_index, &pd_device_id, 1, 1);

            smlib_invalid_ctrl_cached_info(ctrl_index, CTRL_INFO_TYPE_LD);
            smlib_refresh_all_arrays_from_cache_next(ctrl_index, 1);
            smlib_refresh_all_other_from_cache_next(ctrl_index, 1);
            break;

        case PD_OPERATION_CANCEL_HOTSPARE:
            smlib_refresh_specfied_pds_from_hw_next(ctrl_index, &pd_device_id, 1, 1);

            smlib_invalid_ctrl_cached_info(ctrl_index, CTRL_INFO_TYPE_LD);
            smlib_refresh_all_arrays_from_cache_next(ctrl_index, 1);
            smlib_refresh_all_other_from_cache_next(ctrl_index, 1);
            break;

        case PD_OPERATION_SET_STATE:
            smlib_refresh_specfied_pds_from_hw_next(ctrl_index, &pd_device_id, 1, 1);

            smlib_invalid_ctrl_cached_info(ctrl_index, CTRL_INFO_TYPE_LD);
            smlib_refresh_all_arrays_from_cache_next(ctrl_index, 1);
            smlib_refresh_all_other_from_cache_next(ctrl_index, 1);
            break;

        case PD_OPERATION_SET_BOOTABLE:
            smlib_refresh_pd_boot_priority(sml_ctrl, pd_device_id, (guint8 *)param);
            break;

        default:
            break;
    }

    return;
}

/*
 * Description: 对物理盘执行操作
 * History: 1.2016年5月7日
 *          新生成函数
 */
gint32 smlib_exec_pd_operation(guint8 ctrl_index, guint16 pd_device_id, guint8 operation, gpointer param,
    guint32 param_length)
{
    gint32 retval = SML_SUCCESS;
    guint16 pd_index = 0;

    retval = check_input_parameters(ctrl_index, param);
    if (SML_SUCCESS != retval && SML_ERR_NULL_DATA != retval) {
        return retval;
    }
    // 有的操作不需要参数，param可能为空
    lock_ctrl_list_mutex(ctrl_index);
    SML_CTRL_S* sml_ctrl = get_ctrl_by_index(ctrl_index);
    if (sml_ctrl == NULL) {
        unlock_ctrl_list_mutex(ctrl_index);
        return SML_ERR_CTRL_NOT_REGISTERED;
    }
    if (RET_OK != check_pd_device_id(pd_device_id, &sml_ctrl->controller.pdlist, &pd_index)) {
        unlock_ctrl_list_mutex(ctrl_index);
        return SML_ERR_PD_INVALID_DEVICE_ID;
    }

    g_mutex_lock(&sml_ctrl->op_mutex);

    if (NULL != sml_ctrl->pfn_pd_operation) {
        // 调用适配层接口执行操作
        retval = sml_ctrl->pfn_pd_operation(sml_ctrl->controller_id, pd_device_id, operation,
            param, param_length);
        if (SML_SUCCESS != retval) {
            debug_log(DLOG_DEBUG,
                "smlib: RAID controller [Ctrl index %d, Ctrl ID %d] exec PD operation %d failed, return 0x%04x\n",
                ctrl_index, SML_CTRL_ID_VALID_BIT(sml_ctrl->controller_id), operation, retval);
        }
    } else {
        retval = SML_ERR_NULL_INFTERFACE;
    }

    g_mutex_unlock(&sml_ctrl->op_mutex);
    unlock_ctrl_list_mutex(ctrl_index);

    if (SML_SUCCESS == retval) {
        smlib_refresh_pd_cache(sml_ctrl, ctrl_index, pd_device_id, operation, param);
    }

    return retval;
}
