/* 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 "utils/file_securec.h"
#include "ctrl.h"
#include "sml.h"
#include "sml_errcodes.h"
#include "ld.h"

void __attribute__((constructor)) sml_init(void);

typedef struct _tag_raid_ctrl_mode_name {
    guint8 ctrl_mode;
    const gchar* name;
}RAID_CTRL_MODE_NAME;

typedef struct _tag_raid_ctrl_wcp_name {
    guint8 policy;
    const gchar* name;
}RAID_CTRL_WCP_NAME;

typedef struct tag_ctrl_boot_priority {
    guint8 priority;
    const gchar* desc;
} CTRL_BOOT_PRIORITY;

typedef struct _tag_raid_ctrl_ccheck_rate {
    guint8 rate;
    const gchar* speed;
} RAID_CTRL_CCHECK_RATE;

typedef struct _tag_raid_ctrl_ccheck_status {
    guint8 status;
    const gchar* status_s;
} RAID_CTRL_CCHECK_STATUS;

const RAID_CTRL_WCP_NAME g_raid_ctrl_wcp_name[] = {
    {CTRL_DRIVE_WCP_DEFAULT, CTRL_WCP_DEFAULT_STR},
    {CTRL_DRIVE_WCP_ENABLED,  CTRL_WCP_ENABLE_STR},
    {CTRL_DRIVE_WCP_DISABLED, CTRL_WCP_DISABLE_STR},
    {CTRL_DRIVE_WCP_INVALID, CTRL_WCP_UNKNOWN_STR}
};

const RAID_CTRL_MODE_NAME g_raid_ctrl_mode_name[] = {
    {CTRL_MODE_RAID, CTRL_MODE_RAID_STR},
    {CTRL_MODE_HBA,  CTRL_MODE_HBA_STR},
    {CTRL_MODE_JBOD, CTRL_MODE_JBOD_STR},
    {CTRL_MODE_MIXED, CTRL_MODE_MIXED_STR}
};

static CTRL_BOOT_PRIORITY g_ctrl_boot_priority[] = {
    {BOOT_PRIORITY_NONE,      SML_BOOT_PRIORITY_NONE},
    {BOOT_PRIORITY_PRIMARY,   SML_BOOT_PRIORITY_PRIMARY},
    {BOOT_PRIORITY_SECONDARY, SML_BOOT_PRIORITY_SECONDARY},
    {BOOT_PRIORITY_ALL,       SML_BOOT_PRIORITY_ALL},
};

static RAID_CTRL_CCHECK_RATE g_ctrl_ccheck_rate[] = {
    {CTRL_CCHECK_RATE_LOW,      CTRL_CC_RATE_LOW_STR},
    {CTRL_CCHECK_RATE_MIDDLE,   CTRL_CC_RATE_MIDDLE_STR},
    {CTRL_CCHECK_RATE_HIGH,     CTRL_CC_RATE_HIGH_STR},
};

static RAID_CTRL_CCHECK_STATUS g_ctrl_ccheck_status[] = {
    {DISABLE,   CTRL_CC_STATUS_OFF},
    {ENABLE,    CTRL_CC_STATUS_ON},
};

guint16 IS_ATA_SMART_ATTRIBUTE_FLAGS_VALID(guint16 num, guint16 offset)
{
    return num & (1 << offset);
}

/*
 * Description: APP向SML注册RAID控制器的管理信息，SML会初始化对应的全局数据，并
 *              根据注册信息调用第三方的初始化接口
 * History: 1.2016年2月26日
 *          新生成函数
 */
gint32 sml_register_controller(SML_CTRL_OOB_INFO_S *ctrl)
{
    guint8 oob_operate = 0;

    // Check paramters
    if (NULL == ctrl) {
        return SML_ERR_NULL_DATA;
    }

    oob_operate = ctrl->i_oob_operate;

    // 注册管理RAID控制器
    if (SML_ADD_CTRL == oob_operate) {
        return smlib_add_ctrl(ctrl);
    }

    if (SML_REGISTER_CTRL == oob_operate) {
        return smlib_init_ctrl_manage(ctrl);
    } else {
        return SML_ERR_CTRL_PARAM_ILLEGAL;
    }
}

/*
 * Description: APP通知SML退出RAID控制器的管理，SML会清除全局数据，并调用第三方的
 *              清理接口
 * History: 1.2016年2月26日
 *          新生成函数
 */
gint32 sml_unregister_controller(SML_CTRL_OOB_INFO_S *ctrl)
{
    guint8 oob_operate = 0;

    // 参数检查
    if (NULL == ctrl) {
        return SML_ERR_NULL_DATA;
    }

    oob_operate = ctrl->i_oob_operate;

    /* BEGIN: Added on 2017/7/4   问题单号:SF-0000276589 */
    // 移除RAID控制器的信息
    if (SML_DEL_CTRL == oob_operate) {
        return smlib_remove_ctrl(ctrl->i_controller_index);
    }
    /* END:   Added on 2017/7/4 */

    // 注销管理RAID控制器
    if (SML_UNREGISTER_CTRL == oob_operate) {
        return smlib_exit_ctrl_manage(ctrl);
    } else {
        return SML_ERR_CTRL_PARAM_ILLEGAL;
    }
}

/*
 * Description: 更新第三方软件中的缓存数据，非必须操作
 * History: 1.2017年6月1日
 *          新生成函数
 */
gint32 sml_update_cache(guint8 ctrl_index)
{
    return smlib_update_ctrl_cache(ctrl_index);
}

/*
 * Description: APP调用该接口清空缓存的控制器信息，在退出带外管理时调用
 */
void sml_clear_all_controller_info(void)
{
    smlib_clear_all_controller_info();
}

/*
 * Description: 获取RAID控制器的初始化状态
 *              修改历史
 * History: 1.2020年1月3日
 */
guint8 sml_get_ctrl_init_state(guint8 ctrl_index)
{
    return smlib_get_ctrl_init_state(ctrl_index);
}

/*
 * Description: APP向SML获取RAID控制器的SAS地址
 * History: 1.2016年2月27日
 *          新生成函数
 */
gint32 sml_get_ctrl_sas_addr(SML_CTRL_SAS_ADDR_S *ctrl)
{
    gint32 ret_val = 0;
    guint8 ctrl_index = 0;
    SML_SAS_ADDR_S sas_addr;

    if (ctrl == NULL) {
        return SML_ERR_NULL_DATA;
    }

    ctrl_index = ctrl->i_controller_index;

    (void)memset_s(&sas_addr, sizeof(SML_SAS_ADDR_S), 0, sizeof(SML_SAS_ADDR_S));

    ret_val = smlib_get_ctrl_sas_addr(ctrl_index, &sas_addr);
    if (SML_SUCCESS == ret_val) {
        memcpy_s(ctrl->o_sas_addr, sizeof(ctrl->o_sas_addr), sas_addr.addr, sizeof(sas_addr.addr));
    }

    return ret_val;
}

/*
 * Description: APP向SML获取RAID控制器下的Expander背板的PHY错误统计
 * History: 1.2018年10月31日,
 *          新生成函数
 */
gint32 sml_get_ctrl_exp_sas_phy_err_count(SML_CTRL_EXP_SAS_PHY_INFO_S *expander)
{
    gint32 ret_val = 0;
    guint8 ctrl_index = 0;
    guint8 idx = 0;
    guint8 idy = 0;
    SML_CTRL_EXP_SASPHY_INFO_S expander_info;

    if (expander == NULL) {
        return SML_ERR_NULL_DATA;
    }

    ctrl_index = expander->i_controller_index;

    (void)memset_s(&expander_info, sizeof(SML_CTRL_EXP_SASPHY_INFO_S), 0, sizeof(SML_CTRL_EXP_SASPHY_INFO_S));
    ret_val = smlib_get_ctrl_exp_phy_err_count(ctrl_index, &expander_info);
    if (SML_SUCCESS == ret_val) {
        expander->o_expander_count = expander_info.expander_count;

        if (expander->o_expander_count > SML_MAX_EXPANDER_PER_CONTROLLER) {
            expander->o_expander_count = SML_MAX_EXPANDER_PER_CONTROLLER;
            debug_log(DLOG_DEBUG, "This RAID controller (index %d) has more than %d expander", ctrl_index,
                SML_MAX_EXPANDER_PER_CONTROLLER);
        }

        for (idx = 0; idx < expander->o_expander_count; idx++) {
            expander->o_expander_phy[idx].phy_count = expander_info.expander_phy[idx].phy_count;

            if (expander->o_expander_phy[idx].phy_count > SML_MAX_SAS_PHY_PER_EXPANDER) {
                expander->o_expander_phy[idx].phy_count = SML_MAX_SAS_PHY_PER_EXPANDER;
                debug_log(DLOG_DEBUG, "This expander (ctrl_id:%d, expander_id:%d) has more than %d phy", ctrl_index,
                    idx, SML_MAX_SAS_PHY_PER_EXPANDER);
            }

            for (idy = 0; idy < expander->o_expander_phy[idx].phy_count; idy++) {
                expander->o_expander_phy[idx].phy_info[idy].phy_id = idy;
                expander->o_expander_phy[idx].phy_info[idy].invalid_dword_count =
                    expander_info.expander_phy[idx].phy_err[idy].invalid_dword_count;
                expander->o_expander_phy[idx].phy_info[idy].loss_dword_sync_count =
                    expander_info.expander_phy[idx].phy_err[idy].loss_dword_sync_count;
                expander->o_expander_phy[idx].phy_info[idy].phy_reset_problem_count =
                    expander_info.expander_phy[idx].phy_err[idy].phy_reset_problem_count;
                expander->o_expander_phy[idx].phy_info[idy].running_disparity_error_count =
                    expander_info.expander_phy[idx].phy_err[idy].running_disparity_error_count;
            }
        }
    }

    return ret_val;
}

/*
 * Description: APP向SML获取RAID控制器的PHY错误统计
 * History: 1.2016年2月27日
 *          新生成函数
 */
gint32 sml_get_ctrl_sas_phy_err_count(SML_CTRL_SAS_PHY_ERR_S *ctrl)
{
    gint32 ret_val = 0;
    guint8 ctrl_index = 0;
    guint8 idx = 0;
    SML_SASPHY_INFO_S ctrl_info;
    guint8 force_update = 0;

    if (NULL == ctrl) {
        return SML_ERR_NULL_DATA;
    }

    ctrl_index = ctrl->i_controller_index;
    force_update = ctrl->i_force_update;

    (void)memset_s(&ctrl_info, sizeof(SML_SASPHY_INFO_S), 0, sizeof(SML_SASPHY_INFO_S));

    ret_val = smlib_get_ctrl_phy_err_count(ctrl_index, &ctrl_info, force_update);
    if (SML_SUCCESS == ret_val) {
        ctrl->o_phy_count = ctrl_info.phy_count;

        if (ctrl->o_phy_count >= SML_MAX_SAS_PHY_PER_CTRL) {
            ctrl->o_phy_count = SML_MAX_SAS_PHY_PER_CTRL;
            debug_log(DLOG_DEBUG, "This RAID controller (index %d) has more than %d phy", ctrl_index,
                SML_MAX_SAS_PHY_PER_CTRL);
        }

        for (idx = 0; idx < ctrl->o_phy_count; idx++) {
            ctrl->o_phy[idx].phy_id = idx;
            ctrl->o_phy[idx].invalid_dword_count = ctrl_info.phy_err[idx].invalid_dword_count;
            ctrl->o_phy[idx].loss_dword_sync_count = ctrl_info.phy_err[idx].loss_dword_sync_count;
            ctrl->o_phy[idx].phy_reset_problem_count = ctrl_info.phy_err[idx].phy_reset_problem_count;
            ctrl->o_phy[idx].running_disparity_error_count = ctrl_info.phy_err[idx].running_disparity_error_count;
        }
    }

    return ret_val;
}

/*
 * Description: APP通过SML获取RAID控制器的属性
 * History: 1.2016年11月7日
 *          新生成函数
 */
gint32 sml_get_ctrl_properties(SML_CTRL_PROPERTIES_STATE_S *ctrl)
{
    gint32 ret_val = 0;
    guint8 ctrl_index = 0;
    SML_CTRL_BASIC_INFO_S ctrl_info;

    if (ctrl == NULL) {
        return SML_ERR_NULL_DATA;
    }

    ctrl_index = ctrl->i_controller_index;

    (void)memset_s(&ctrl_info, sizeof(SML_CTRL_BASIC_INFO_S), 0, sizeof(SML_CTRL_BASIC_INFO_S));

    ret_val = smlib_get_ctrl_info(ctrl_index, &ctrl_info);
    if (SML_SUCCESS == ret_val) {
        ctrl->o_copyback_enabled = ctrl_info.properties.copyback_enabled;
        ctrl->o_smarter_copyback_enabled = ctrl_info.properties.smarter_copyback_enabled;
        if (ctrl_info.operations.ctrl_operations.support_jbod_state) {
            ctrl->o_jbod_enabled = ctrl_info.properties.jbod_enabled;
        } else {
            ctrl->o_jbod_enabled = 0xFF;
        }
        ctrl->o_consis_check_enabled = ctrl_info.consis_check_enabled;
        ctrl->o_consis_check_period = ctrl_info.consis_check_period;
        ctrl->o_consis_check_rate = ctrl_info.consis_check_rate;
        ctrl->o_consis_check_repair = ctrl_info.consis_check_repair;
        ctrl->o_consis_check_delay = ctrl_info.consis_check_delay;
        ctrl->o_consis_check_totalvd = ctrl_info.consis_check_totalvd;
        ctrl->o_consis_check_completedvd = ctrl_info.consis_check_completedvd;
        ctrl->o_consis_check_status = ctrl_info.consis_check_status;
    }

    return ret_val;
}

/*
 * Description: 收集控制器日志数据
 */
static gint32 dump_ctrl_log_data(guint8 ctrl_id, SML_CTRL_LOG_DATA_S *log_data)
{
    SML_CTRL_OPERTATION_S param;
    (void)memset_s(&param, sizeof(param), 0, sizeof(param));

    param.i_controller_index = ctrl_id;
    param.i_operation = CTRL_OPERATION_DUMP_LOG;
    param.i_param_ptr = log_data;
    param.i_param_size = sizeof(SML_CTRL_LOG_DATA_S);
    return sml_ctrl_operation(&param);
}

/*
 * Description: 收集单个日志
 */
gint32 sml_dump_ctrl_single_log(guint8 ctrl_id, const gchar *src_dir, guint8 log_type, const gchar *log_name)
{
    SML_CTRL_LOG_DATA_S log_data = {0};
    log_data.log_type = log_type;

    gint32 ret = dump_ctrl_log_data(ctrl_id, &log_data);
    if (ret != SML_SUCCESS) {
        /* 如果单个文件收集失败则记录失败原因，生成空文件 */
        debug_log(DLOG_ERROR, "%s: dump_ctrl_log_data log[%s] failed ret[0x%x]", log_name, __FUNCTION__, ret);
    }

    gchar file_name[MAX_FILEPATH_LENGTH] = {0};
    ret = snprintf_s(file_name, sizeof(file_name), sizeof(file_name) - 1, "%s/%s", src_dir, log_name);
    if (ret <= 0) {
        debug_log(DLOG_ERROR, "%s: snprintf_s log[%s] failed, ret = %d", log_name, __FUNCTION__, ret);
        g_free(log_data.log_buffer);
        return RET_ERR;
    }

    FILE *fp = fopen_s(file_name, "w+", file_name);
    if (fp == NULL) {
        debug_log(DLOG_ERROR, "%s: open %s failed", __FUNCTION__, log_name);
        g_free(log_data.log_buffer);
        return RET_ERR;
    }

    (void)fchmod(fileno(fp), S_IRUSR | S_IRGRP);

    if (log_data.log_length > 0 && fwrite(log_data.log_buffer, log_data.log_length, 1, fp) != 1) {
        debug_log(DLOG_ERROR, "%s: write %s failed, %s", __FUNCTION__, log_name, g_strerror(errno));
        (void)fclose_s(fp);
        g_free(log_data.log_buffer);
        return RET_ERR;
    }

    (void)fflush(fp);
    (void)fsync(fileno(fp));
    (void)fclose_s(fp);
    g_free(log_data.log_buffer);
    return RET_OK;
}

/*
 * Description: APP向SML获取将RAID卡固件日志解析成文本
 * History: 1.2025年7月10日
 *          新生成函数
 */
gint32 sml_parse_controller_bin_log(guint8 ctrl_id, const gchar *src_dir, const gchar *dest_dir)
{
    gint32 ret = smlib_exec_parse_ctrl_log(ctrl_id, src_dir, dest_dir);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "%s: parse controller bin log failed ret[0x%x]", __FUNCTION__, ret);
    }
    return ret;
}

/*
 * Description: APP向SML获取RAID控制器的健康状态
 * History: 1.2016年2月27日
 *          新生成函数
 */
gint32 sml_get_ctrl_health_status(SML_CTRL_HEALTH_STATUS_S *ctrl)
{
    gint32 ret_val = 0;
    guint8 ctrl_index = 0;
    SML_CTRL_HEALTH_S ctrl_info;

    if (ctrl == NULL) {
        return SML_ERR_NULL_DATA;
    }

    ctrl_index = ctrl->i_controller_index;

    (void)memset_s(&ctrl_info, sizeof(SML_CTRL_HEALTH_S), 0, sizeof(SML_CTRL_HEALTH_S));

    ret_val = smlib_get_ctrl_health(ctrl_index, &ctrl_info);
    if (SML_SUCCESS == ret_val) {
        ctrl->o_health_status_code = ctrl_info.health_status;
        ctrl->o_hw_err = ctrl_info.hw_err;
        ctrl->o_clk_err = ctrl_info.clk_err;
        ctrl->o_power_err = ctrl_info.power_err;
        ctrl->o_capacity_err = ctrl_info.capacity_err;
        ctrl->o_flash_err = ctrl_info.flash_err;
        ctrl->o_err_change = ctrl_info.err_change;
    }

    return ret_val;
}

/*
 * Description: APP通过SML获取指定RAID控制器的启动盘
 */
gint32 sml_get_ctrl_boot_devices(SML_CTRL_BOOTABLE_DEVICES_S *boot_devices)
{
    if (boot_devices == NULL) {
        return SML_ERR_NULL_DATA;
    }

    return smlib_get_ctrl_boot_devices(boot_devices);
}

/*
 * Description : 判断逻辑盘是不是EPD
 * History：2020年11月5日 新生成函数
 */
static gboolean is_logical_drive_epd(guint8 ctrl_index, guint16 ld_target_id)
{
    gint32 ret;
    SML_LD_BASIC_INFO_S ld;

    (void)memset_s(&ld, sizeof(ld), 0, sizeof(ld));

    ret = smlib_get_ld_info(ctrl_index, ld_target_id, &ld);
    if (ret != RET_OK) {
        debug_log(DLOG_ERROR, "%s:Get LD target id failed, return %d", __FUNCTION__, ret);
        return FALSE;
    }

    if (ld.is_epd == 1) {
        return TRUE;
    }

    return FALSE;
}

/*
 * Description : 过滤掉EPD的逻辑盘
 */
static void sml_filter_epd_logical_drive(SML_CTRL_LD_LIST_S *lds)
{
    guint32 idx;
    SML_CTRL_LD_LIST_S tmp_lds;
    guint16 ld_count = 0;

    if (lds == NULL) {
        debug_log(DLOG_ERROR, "%s:Input parameter is invalid", __FUNCTION__);
        return;
    }

    (void)memset_s(&tmp_lds, sizeof(tmp_lds), 0, sizeof(tmp_lds));

    tmp_lds.i_controller_index = lds->i_controller_index;

    for (idx = 0; idx < lds->o_ld_count; idx++) {
        if (is_logical_drive_epd(lds->i_controller_index, lds->o_ld_targetIDs[idx]) == TRUE) {
            continue;
        }

        tmp_lds.o_ld_targetIDs[ld_count] = lds->o_ld_targetIDs[idx];
        ld_count++;
    }

    tmp_lds.o_ld_count = ld_count;
    (void)memcpy_s(lds, sizeof(SML_CTRL_LD_LIST_S), &tmp_lds, sizeof(SML_CTRL_LD_LIST_S));

    return;
}

/*
 * Description: APP向SML获取RAID控制器的LD列表
 * History: 1.2016年2月27日
 *          新生成函数
 */
gint32 sml_get_ctrl_ld_list(SML_CTRL_LD_LIST_S *ctrl)
{
    gint32 ret_val = 0;
    guint8 ctrl_index = 0;
    SML_LD_LIST_S ctrl_info;
    size_t data_len = 0;

    if (ctrl == NULL) {
        return SML_ERR_NULL_DATA;
    }

    ctrl_index = ctrl->i_controller_index;

    (void)memset_s(&ctrl_info, sizeof(SML_LD_LIST_S), 0, sizeof(SML_LD_LIST_S));

    ret_val = smlib_get_ctrl_ld_list(ctrl_index, &ctrl_info);
    if (SML_SUCCESS == ret_val) {
        ctrl->o_ld_count = ctrl_info.ld_count;

        if (ctrl->o_ld_count >= SML_MAX_LOGIC_DRIVES) {
            ctrl->o_ld_count = SML_MAX_LOGIC_DRIVES;
            debug_log(DLOG_DEBUG, "smlib: this controller (index %d) has more than %d logic drives", ctrl_index,
                SML_MAX_LOGIC_DRIVES);
        }

        data_len = ctrl->o_ld_count * sizeof(ctrl->o_ld_targetIDs[0]);
        ret_val = memcpy_s(ctrl->o_ld_targetIDs, sizeof(ctrl->o_ld_targetIDs), ctrl_info.target_ids, data_len);
        if (EOK != ret_val) {
            debug_log(DLOG_ERROR, "%s, %d: memcpy_s failed, ret = 0x%X.", __FUNCTION__, __LINE__, ret_val);
            return SML_ERR_SEC_FUNC_FAILED;
        }
        sml_filter_epd_logical_drive(ctrl);
    }

    return ret_val;
}

/*
 * Description: APP向SML获取RAID控制器的PD列表
 * History: 1.2016年2月27日
 *          新生成函数
 */
gint32 sml_get_ctrl_pd_list(SML_CTRL_PD_LIST_S *ctrl)
{
    gint32 ret_val = 0;
    guint8 ctrl_index = 0;
    SML_PD_LIST_S ctrl_info;
    size_t data_len = 0;

    if (ctrl == NULL) {
        return SML_ERR_NULL_DATA;
    }

    ctrl_index = ctrl->i_controller_index;

    (void)memset_s(&ctrl_info, sizeof(SML_PD_LIST_S), 0, sizeof(SML_PD_LIST_S));

    ret_val = smlib_get_ctrl_pd_list(ctrl_index, &ctrl_info);
    if (SML_SUCCESS == ret_val) {
        ctrl->o_pd_count = ctrl_info.pd_count;

        if (ctrl->o_pd_count >= SML_MAX_PHYSICAL_DRIVES) {
            ctrl->o_pd_count = SML_MAX_PHYSICAL_DRIVES;
            debug_log(DLOG_DEBUG, "smlib: this controller (index %d) has more than %d physical drives", ctrl_index,
                SML_MAX_PHYSICAL_DRIVES);
        }

        data_len = ctrl->o_pd_count * sizeof(ctrl->o_pd_deviceIDs[0]);
        ret_val = memcpy_s(ctrl->o_pd_deviceIDs, sizeof(ctrl->o_pd_deviceIDs), ctrl_info.device_ids, data_len);
        if (EOK != ret_val) {
            debug_log(DLOG_ERROR, "%s, %d: memcpy_s failed, ret = 0x%X.", __FUNCTION__, __LINE__, ret_val);
            return SML_ERR_SEC_FUNC_FAILED;
        }

        data_len = ctrl->o_pd_count * sizeof(ctrl->o_pd_slot_num[0]);
        ret_val = memcpy_s(ctrl->o_pd_slot_num, sizeof(ctrl->o_pd_slot_num), ctrl_info.slot_num, data_len);
        if (EOK != ret_val) {
            debug_log(DLOG_ERROR, "%s, %d: memcpy_s failed, ret = 0x%X.", __FUNCTION__, __LINE__, ret_val);
            return SML_ERR_SEC_FUNC_FAILED;
        }

        data_len = ctrl->o_pd_count * sizeof(ctrl->o_pd_enclosure_id[0]);
        ret_val = memcpy_s(ctrl->o_pd_enclosure_id, sizeof(ctrl->o_pd_enclosure_id), ctrl_info.enclosure_ids, data_len);
        if (EOK != ret_val) {
            debug_log(DLOG_ERROR, "%s, %d: memcpy_s failed, ret = 0x%X.", __FUNCTION__, __LINE__, ret_val);
            return SML_ERR_SEC_FUNC_FAILED;
        }
    }

    return ret_val;
}
/*
 * Description: 过滤掉带有EPD的阵列
 * History: 1.2020年11月5日
 *          新生成函数
 */
static void sml_filter_epd_array(SML_CTRL_ARRAY_LIST_S *arrays)
{
    guint8 i;
    guint8 j;
    SML_CTRL_ARRAY_INFO_S array;
    SML_CTRL_ARRAY_LIST_S tmp_arrays;
    guint8 array_count = 0;
    gboolean is_epd;

    if (arrays == NULL) {
        debug_log(DLOG_ERROR, "%s:Input parameter is invalid", __FUNCTION__);
        return;
    }

    (void)memset_s(&tmp_arrays, sizeof(tmp_arrays), 0, sizeof(tmp_arrays));

    tmp_arrays.i_controller_index = arrays->i_controller_index;

    for (i = 0; i < arrays->o_array_count; i++) {
        (void)memset_s(&array, sizeof(array), 0, sizeof(array));
        array.i_controller_index = arrays->i_controller_index;
        array.i_array_ref = arrays->o_array_refs[i];
        if (sml_get_array_info(&array) != SML_SUCCESS) {
            debug_log(DLOG_ERROR, "%s:Get array information failed!", __FUNCTION__);
            continue;
        }

        is_epd = FALSE;
        for (j = 0; j < array.o_ld_count; j++) {
            is_epd = is_logical_drive_epd(arrays->i_controller_index, array.o_ld_ids[j]);
            if (is_epd == TRUE) {
                break;
            }
        }
        if (is_epd == TRUE) {
            continue;
        }

        tmp_arrays.o_array_refs[array_count] = array.i_array_ref;
        array_count++;
    }

    tmp_arrays.o_array_count = array_count;
    (void)memcpy_s(arrays, sizeof(SML_CTRL_ARRAY_LIST_S), &tmp_arrays, sizeof(SML_CTRL_ARRAY_LIST_S));
    return;
}

/*
 * Description: APP通过SML获取指定RAID控制器下的array列表
 * History: 1.2016年11月8日,  ()
 *          新生成函数
 */
gint32 sml_get_ctrl_array_list(SML_CTRL_ARRAY_LIST_S *ctrl)
{
    gint32 ret_val = 0;
    guint8 ctrl_index = 0;
    SML_ARRAY_LIST_S ctrl_info;
    size_t data_len = 0;

    if (ctrl == NULL) {
        return SML_ERR_NULL_DATA;
    }

    ctrl_index = ctrl->i_controller_index;

    (void)memset_s(&ctrl_info, sizeof(SML_ARRAY_LIST_S), 0, sizeof(SML_ARRAY_LIST_S));

    ret_val = smlib_get_ctrl_array_list(ctrl_index, &ctrl_info);
    if (SML_SUCCESS == ret_val) {
        ctrl->o_array_count = ctrl_info.array_count;

        if (ctrl->o_array_count >= SML_MAX_ARRAY) {
            ctrl->o_array_count = SML_MAX_ARRAY;
            debug_log(DLOG_DEBUG, "smlib: this controller (index %d) has more than %d arrays", ctrl_index,
                SML_MAX_ARRAY);
        }

        data_len = ctrl->o_array_count * sizeof(ctrl->o_array_refs[0]);
        ret_val = memcpy_s(ctrl->o_array_refs, sizeof(ctrl->o_array_refs), ctrl_info.array_refs, data_len);
        if (EOK != ret_val) {
            debug_log(DLOG_ERROR, "%s, %d: memcpy_s failed, ret = 0x%X.", __FUNCTION__, __LINE__, ret_val);
            return SML_ERR_SEC_FUNC_FAILED;
        }
        sml_filter_epd_array(ctrl);
    }

    return ret_val;
}

/*
 * Description: APP通过SML获取指定RAID控制器支持的特性或操作
 * History: 1.2017年4月5日,  ()
 *          新生成函数
 */
gint32 sml_get_ctrl_support_operations(SML_CTRL_SUPPORT_OPERATIONS_S *ctrl)
{
    gint32 ret_val = 0;
    guint8 ctrl_index = 0;
    SML_CTRL_BASIC_INFO_S ctrl_info;

    if (ctrl == NULL) {
        return SML_ERR_NULL_DATA;
    }

    ctrl_index = ctrl->i_controller_index;

    (void)memset_s(&ctrl_info, sizeof(SML_CTRL_BASIC_INFO_S), 0, sizeof(SML_CTRL_BASIC_INFO_S));

    ret_val = smlib_get_ctrl_info(ctrl_index, &ctrl_info);
    if (SML_SUCCESS == ret_val) {
        ctrl->ctrl_operations.o_support_jbod = ctrl_info.operations.ctrl_operations.support_jbod;
        ctrl->ctrl_operations.o_support_raid0 = ctrl_info.raid0_supported ? 1 : 0;
        ctrl->ctrl_operations.o_support_raid1 = ctrl_info.raid1_supported ? 1 : 0;
        ctrl->ctrl_operations.o_support_raid5 = ctrl_info.raid5_supported ? 1 : 0;
        ctrl->ctrl_operations.o_support_raid6 = ctrl_info.raid6_supported ? 1 : 0;
        ctrl->ctrl_operations.o_support_raid10 = ctrl_info.raid10_supported ? 1 : 0;
        ctrl->ctrl_operations.o_support_raid50 = ctrl_info.raid50_supported ? 1 : 0;
        ctrl->ctrl_operations.o_support_raid60 = ctrl_info.raid60_supported ? 1 : 0;
        ctrl->ctrl_operations.o_support_raid1adm = ctrl_info.raid1adm_supported ? 1 : 0;
        ctrl->ctrl_operations.o_support_raid10adm = ctrl_info.raid10adm_supported ? 1 : 0;
        ctrl->ctrl_operations.o_support_raid1triple = ctrl_info.raid1triple_supported ? 1 : 0;
        ctrl->ctrl_operations.o_support_raid10triple = ctrl_info.raid10triple_supported ? 1 : 0;

        ctrl->ld_operations.o_support_read_policy = ctrl_info.operations.ld_operations.support_read_policy;
        ctrl->ld_operations.o_support_write_policy = ctrl_info.operations.ld_operations.support_write_policy;
        ctrl->ld_operations.o_support_io_policy = ctrl_info.operations.ld_operations.support_io_policy;
        ctrl->ld_operations.o_support_access_policy = ctrl_info.operations.ld_operations.support_access_policy;
        ctrl->ld_operations.o_support_disk_cache_policy = ctrl_info.operations.ld_operations.support_disk_cache_policy;
        ctrl->ld_operations.o_default_write_policy = ctrl_info.operations.ld_operations.default_write_policy;

        ctrl->pd_operations.o_support_temperature = ctrl_info.operations.pd_operations.support_temperature;
        ctrl->pd_operations.o_support_crypto_erase = ctrl_info.operations.pd_operations.support_crypto_erase;

        ctrl->ctrl_operations.o_support_jbod_state = ctrl_info.operations.ctrl_operations.support_jbod_state;
        ctrl->ctrl_operations.o_support_mode_set = ctrl_info.operations.ctrl_operations.support_mode_set;
        ctrl->ctrl_operations.o_support_raid = ctrl_info.operations.ctrl_operations.support_raid;
        ctrl->ctrl_operations.o_support_hba = ctrl_info.operations.ctrl_operations.support_hba;
        ctrl->ctrl_operations.o_support_mixed = ctrl_info.operations.ctrl_operations.support_mixed;
        ctrl->ctrl_operations.o_support_epd = ctrl_info.operations.ctrl_operations.support_epd;

        ctrl->ctrl_operations.o_configured_drive_wcp = ctrl_info.operations.ctrl_operations.configured_drive_wcp;
        ctrl->ctrl_operations.o_unconfigured_drive_wcp = ctrl_info.operations.ctrl_operations.unconfigured_drive_wcp;
        ctrl->ctrl_operations.o_hba_drive_wcp = ctrl_info.operations.ctrl_operations.hba_drive_wcp;
    }

    return ret_val;
}

/*
 * Description: APP通过SML对PD执行操作
 * History: 1.2016年11月10日,  ()
 *          新生成函数
 */
gint32 sml_ctrl_operation(SML_CTRL_OPERTATION_S *ctrl)
{
    gint32 ret_val = 0;
    guint8 ctrl_index = 0;
    guint8 operation = 0;

    if (ctrl == NULL) {
        return SML_ERR_NULL_DATA;
    }

    ctrl_index = ctrl->i_controller_index;
    operation = ctrl->i_operation;

    ret_val = smlib_exec_ctrl_operation(ctrl_index, operation, (gpointer)ctrl->i_param_ptr, ctrl->i_param_size);
    if (ret_val != SML_SUCCESS && ret_val != SML_ERR_REBOOT_REQUIRED) {
        debug_log(DLOG_ERROR, "sml_ctrl_operation failed, ctrl index = %d, return 0x%0x\n", ctrl_index, ret_val);
    }

    return ret_val;
}
/* END:   Added on 2016/11/10 */

guint8 sml_raid_ctrl_wcp_str2num(const gchar* name)
{
    guint32 i;

    if (name == NULL) {
        debug_log(DLOG_ERROR, "%s input null\n", __FUNCTION__);
        return CTRL_MODE_UNKNOWN;
    }
    for (i = 0; i < sizeof(g_raid_ctrl_wcp_name) / sizeof(RAID_CTRL_MODE_NAME); i++) {
        if (g_strcmp0(name, g_raid_ctrl_wcp_name[i].name) == 0) {
            return g_raid_ctrl_wcp_name[i].policy;
        }
    }

    return CTRL_MODE_UNKNOWN;
}


guint8 sml_raid_ctrl_mode_str2num(const gchar* name)
{
    guint32 i;

    if (name == NULL) {
        debug_log(DLOG_ERROR, "%s input null\n", __FUNCTION__);
        return CTRL_MODE_UNKNOWN;
    }

    for (i = 0; i < sizeof(g_raid_ctrl_mode_name) / sizeof(RAID_CTRL_MODE_NAME); i++) {
        if (g_strcmp0(name, g_raid_ctrl_mode_name[i].name) == 0) {
            return g_raid_ctrl_mode_name[i].ctrl_mode;
        }
    }

    return CTRL_MODE_UNKNOWN;
}

const gchar* sml_ctrl_wcp_type_num2str(guint8 type)
{
    switch (type) {
        case CTRL_DRIVE_WCP_CONFIG:
            return "ConfiguredDrive";
        case CTRL_DRIVE_WCP_UNCONFIG:
            return "UnconfiguredDrive";
        case CTRL_DRIVE_WCP_HBA:
            return "HBADrive";
        default:
            return "NA";
    }
}

const gchar* sml_ctrl_drive_wcp2str(guint8 wcp)
{
    if (wcp >= sizeof(g_raid_ctrl_wcp_name) / sizeof(RAID_CTRL_WCP_NAME)) {
        return CTRL_MODE_UNKNOWN_STR;
    }

    return g_raid_ctrl_wcp_name[wcp].name;
}

const gchar* sml_raid_ctrl_mode_num2str(guint8 mode)
{
    if (mode >= sizeof(g_raid_ctrl_mode_name) / sizeof(RAID_CTRL_MODE_NAME)) {
        return CTRL_MODE_UNKNOWN_STR;
    }

    return g_raid_ctrl_mode_name[mode].name;
}

/*
 * Description: 启动优先级从字符串转数字
 */
guint8 sml_ctrl_boot_priority_str2num(const gchar* str)
{
    if (str == NULL) {
        return BOOT_PRIORITY_INVALID;
    }

    for (guint8 i = 0; i < G_N_ELEMENTS(g_ctrl_boot_priority); i++) {
        if (g_strcmp0(str, g_ctrl_boot_priority[i].desc) == 0) {
            return g_ctrl_boot_priority[i].priority;
        }
    }

    return BOOT_PRIORITY_INVALID;
}

/*
 * Description: 启动优先级从数字转字符串
 */
const gchar* sml_ctrl_boot_priority_num2str(guint8 priority)
{
    for (guint8 i = 0; i < G_N_ELEMENTS(g_ctrl_boot_priority); i++) {
        if (priority == g_ctrl_boot_priority[i].priority) {
            return g_ctrl_boot_priority[i].desc;
        }
    }

    return STORAGE_INFO_INVALID_STRING;
}

/*
 * Description: 一致性校验速度从字符串转数字
 * History: 2022年5月16日   ()  新生成函数
*/
guint8 sml_ctrl_ccheck_rate_str2num(const gchar* speed)
{
    if (speed == NULL) {
        return STORAGE_INFO_INVALID_BYTE;
    }

    for (guint8 i = 0; i < G_N_ELEMENTS(g_ctrl_ccheck_rate); i++) {
        if (g_strcmp0(speed, g_ctrl_ccheck_rate[i].speed) == 0) {
            return g_ctrl_ccheck_rate[i].rate;
        }
    }

    return STORAGE_INFO_INVALID_BYTE;
}

/*
 * Description: 一致性校验速度从数字转字符串
 * History: 2022年5月16日   ()  新生成函数
*/
const gchar* sml_ctrl_ccheck_rate_num2str(guint8 rate)
{
    for (guint8 i = 0; i < G_N_ELEMENTS(g_ctrl_ccheck_rate); i++) {
        if (rate == g_ctrl_ccheck_rate[i].rate) {
            return g_ctrl_ccheck_rate[i].speed;
        }
    }

    return STORAGE_INFO_INVALID_STRING;
}

/*
 * Description: 一致性校验运行状态从字符串转数字
 * History: 2022年5月16日   ()  新生成函数
*/
guint8 sml_ctrl_ccheck_status_str2num(const gchar* status_s)
{
    if (status_s == NULL) {
        return STORAGE_INFO_INVALID_BYTE;
    }

    for (guint8 i = 0; i < G_N_ELEMENTS(g_ctrl_ccheck_status); i++) {
        if (g_strcmp0(status_s, g_ctrl_ccheck_status[i].status_s) == 0) {
            return g_ctrl_ccheck_status[i].status;
        }
    }

    return STORAGE_INFO_INVALID_BYTE;
}

/*
 * Description: 一致性校验运行状态从数字转字符串
 * History: 2022年5月16日   ()  新生成函数
*/
const gchar* sml_ctrl_ccheck_status_num2str(guint8 status)
{
    for (guint8 i = 0; i < G_N_ELEMENTS(g_ctrl_ccheck_status); i++) {
        if (status == g_ctrl_ccheck_status[i].status) {
            return g_ctrl_ccheck_status[i].status_s;
        }
    }

    return STORAGE_INFO_INVALID_STRING;
}

/*
 * Description: SML库加载之后的构造函数，初始化库内部的数据
 * History: 1.2016年3月3日
 *          新生成函数
 */
void sml_init(void)
{
    debug_log(DLOG_DEBUG, "Load smlib and initialize...\n");
    smlib_init();
    debug_log(DLOG_DEBUG, "Load smlib and initialize done\n");
    return;
}

gint32 sml_pd_trans_drive_data(guint8 ctrl_id, const gchar *json_raw_str)
{
    gint32 ret = smlib_exec_pd_trans_drive_data(ctrl_id, json_raw_str);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "%s: trans drive data failed ret[0x%x]", __FUNCTION__, ret);
    }
    return ret;
}
