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

typedef struct _tag_sml_ld_state_desc {
    guint8 state;
    const gchar* desc;
    guint8 level;
} SML_LD_STATE_DESC;

typedef struct _tag_sml_ld_level_desc {
    guint8 level;
    const gchar* desc;
} SML_LD_LEVEL_DESC;

static SML_LD_STATE_DESC g_ld_state_desc[] = {
    {LD_STATE_OFFLINE, "Offline", LEVEL_CRITICAL},
    {LD_STATE_PARTIALLY_DEGRADED, "Partially degraded", LEVEL_WARNING},
    {LD_STATE_DEGRADED, "Degraded", LEVEL_WARNING},
    {LD_STATE_OPTIMAL, "Optimal", LEVEL_NORMAL},
    {LD_STATE_FAILED, "Failed", LEVEL_CRITICAL},
    {LD_STATE_NOT_CONFIGURED, "Not Configured", LEVEL_WARNING},
    {LD_STATE_INTERIM_RECOVERY, "Interim recovery", LEVEL_WARNING},
    {LD_STATE_READY_FOR_RECOVERY, "Ready for recovery", LEVEL_WARNING},
    {LD_STATE_RECOVERYING, "Recovering", LEVEL_WARNING},
    {LD_STATE_WRONG_DRIVE_REPLACED, "Wrong drive replaced", LEVEL_WARNING},
    {LD_STATE_DRVIE_IMPROPERLY_CONNECTED, "Drive improperly connected", LEVEL_WARNING},
    {LD_STATE_EXPANDING, "Expanding", LEVEL_WARNING},
    {LD_STATE_NOT_YET_AVAILABLE, "Not available", LEVEL_WARNING},
    {LD_STATE_QUEUED_FOR_EXPANSION, "Queued for expansion", LEVEL_WARNING},
    {LD_STATE_DISABLED_FROM_SCSIID_CONFLICT, "Disabled from SCSI conflict", LEVEL_CRITICAL},
    {LD_STATE_EJECTED, "Ejected", LEVEL_WARNING},
    {LD_STATE_ERASE_IN_PROGRESS, "Erase in progress", LEVEL_WARNING},
    {LD_STATE_UNUSED, "Unused", LEVEL_NORMAL},
    {LD_STATE_READY_TO_PERFORM_PREDICTIVE_SPARE_REBUILD, "Ready to perform predictive spare rebuild", LEVEL_NORMAL},
    {LD_STATE_RPI_IN_PROGRESS, "RPI in progress", LEVEL_WARNING},
    {LD_STATE_RPI_QUEUED, "RPI queued", LEVEL_WARNING},
    {LD_STATE_ENCRYPTED_VOLUME_WITHOUT_KEY, "Encrypted without key", LEVEL_NORMAL},
    {LD_STATE_ENCRYPTION_MIGRATION, "Encryption migration", LEVEL_NORMAL},
    {LD_STATE_ENCRYPTED_VOLUME_REKEYING, "Encrypted & re-keying", LEVEL_NORMAL},
    {LD_STATE_ENCRYPTED_VOLUME_ENCRYPTION_OFF, "Encrypted with encryption off", LEVEL_CRITICAL},
    {LD_STATE_VOLUME_ENCODE_REQUESTED, "Volume encode requested", LEVEL_NORMAL},
    {LD_STATE_ENCRYPTED_VOLUME_REKEY_REQUESTED, "Encrypted with re-key request", LEVEL_NORMAL},
    {LD_STATE_UNSUPPORTED_ON_THIS_CONTROLLER, "Unsupported", LEVEL_CRITICAL},
    {LD_STATE_NOT_FORMATTED, "Not Formatted", LEVEL_NORMAL},
    {LD_STATE_FORMATTING, "Formatting", LEVEL_NORMAL},
    {LD_STATE_SANITIZING, "Sanitizing", LEVEL_NORMAL},
    {LD_STATE_INITIALIZING, "Initializing", LEVEL_NORMAL},
    {LD_STATE_INITIALIZEFAIL, "Initialize fail", LEVEL_NORMAL},
    {LD_STATE_DELETING, "Deleting", LEVEL_NORMAL},
    {LD_STATE_DELETEFAIL, "Delete fail", LEVEL_NORMAL},
    {LD_STATE_WRITE_PROTECT, "Write protect", LEVEL_NORMAL},
};

static SML_LD_LEVEL_DESC g_ld_level_desc[] = {
    {RAID_LEVEL_0, SML_RAID_LEVEL_0},
    {RAID_LEVEL_1, SML_RAID_LEVEL_1},
    {RAID_LEVEL_5, SML_RAID_LEVEL_5},
    {RAID_LEVEL_6, SML_RAID_LEVEL_6},
    {RAID_LEVEL_10, SML_RAID_LEVEL_10},
    {RAID_LEVEL_50, SML_RAID_LEVEL_50},
    {RAID_LEVEL_60, SML_RAID_LEVEL_60},
    {RAID_LEVEL_1ADM, SML_RAID_LEVEL_1ADM},
    {RAID_LEVEL_10ADM, SML_RAID_LEVEL_10ADM},
    {RAID_LEVEL_1TRIPLE, SML_RAID_LEVEL_1TRIPLE},
    {RAID_LEVEL_10TRIPLE, SML_RAID_LEVEL_10TRIPLE},
};

const gchar* sml_ld_state2str(guint8 state, guint8 *level)
{
    for (guint8 i = 0; i < G_N_ELEMENTS(g_ld_state_desc); i++) {
        if (state == g_ld_state_desc[i].state) {
            if (level != NULL) {
                *level = g_ld_state_desc[i].level;
            }
            return g_ld_state_desc[i].desc;
        }
    }

    return STORAGE_INFO_INVALID_STRING;
}

const gchar* sml_ld_level2str(guint8 level)
{
    for (guint8 i = 0; i < G_N_ELEMENTS(g_ld_level_desc); i++) {
        if (level == g_ld_level_desc[i].level) {
            return g_ld_level_desc[i].desc;
        }
    }

    return STORAGE_INFO_INVALID_STRING;
}

/*
 * Description: APP通过SML获取指定RAID控制器下的特定Array的信息
 * History: 1.2016年11月8日, ()
 *          新生成函数
 */
gint32 sml_get_array_info(SML_CTRL_ARRAY_INFO_S *array)
{
    gint32 ret_val = 0;
    guint8 idx = 0;
    guint8 ctrl_index = 0;
    guint16 array_ref = 0;
    SML_ARRAY_INFO_S array_info;

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

    ctrl_index = array->i_controller_index;
    array_ref = array->i_array_ref;

    (void)memset_s(&array_info, sizeof(SML_ARRAY_INFO_S), 0, sizeof(SML_ARRAY_INFO_S));

    ret_val = smlib_get_array_info(ctrl_index, array_ref, &array_info);
    if (SML_SUCCESS == ret_val) {
        array->o_used_space = array_info.used_space;
        array->o_total_free_space = array_info.total_free_space;
        array->o_free_blocks_count = array_info.free_blocks_count;
        if (array->o_free_blocks_count > 0) {
            (void)memcpy_s(array->o_free_blocks_space, sizeof(array->o_free_blocks_space), array_info.free_blocks_space,
                sizeof(array->o_free_blocks_space));
        } else {
            (void)memset_s(array->o_free_blocks_space, sizeof(array->o_free_blocks_space), 0,
                sizeof(array->o_free_blocks_space));
        }
        array->o_ld_count = array_info.ld_count;

        if (array->o_ld_count >= SML_MAX_LOGICAL_DRIVES_PER_ARRAY) {
            array->o_ld_count = SML_MAX_LOGICAL_DRIVES_PER_ARRAY;
            debug_log(DLOG_DEBUG, "smlib: this array (index %d) has more than %d logical drives", array_ref,
                SML_MAX_LOGICAL_DRIVES_PER_ARRAY);
        }

        for (idx = 0; idx < array->o_ld_count; idx++) {
            array->o_ld_ids[idx] = array_info.ld_ids[idx];
        }

        array->o_pd_count = array_info.pd_count;

        if (array->o_pd_count >= SML_MAX_PHYSICAL_DRIVES_PER_ARRAY) {
            array->o_pd_count = SML_MAX_PHYSICAL_DRIVES_PER_ARRAY;
            debug_log(DLOG_DEBUG, "smlib: this array (index %d) has more than %d physical drives", array_ref,
                SML_MAX_PHYSICAL_DRIVES_PER_ARRAY);
        }

        for (idx = 0; idx < array->o_pd_count; idx++) {
            array->o_pd_ids[idx] = array_info.pd_ids[idx];
            array->o_pd_slots[idx] = array_info.pd_slots[idx];
            array->o_pd_enclosure[idx] = array_info.pd_enclosures[idx];
        }
    }

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

/*
 * Description: APP通过SML执行在新的阵列上创建逻辑盘的命令
 * History: 1.2016年11月4日, ()
 *          新生成函数
 */
gint32 sml_create_ld_on_new_array(SML_RAID_ON_NEW_ARRAY_PARAM_S *config)
{
    gint32 ret_val = 0;
    guint8 ctrl_index = 0;
    guint8 operation = 0;
    SML_CREATE_LD_ON_NEW_ARRAY_S *cfg = NULL;
    guint32 param_size = 0;
    guint32 copy_len;
    errno_t safe_fun_ret = EOK;

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

    cfg = (SML_CREATE_LD_ON_NEW_ARRAY_S *)g_malloc0(sizeof(SML_CREATE_LD_ON_NEW_ARRAY_S));
    if (NULL == cfg) {
        ret_val = SML_ERR_CANNOT_ALLOC_MEM;
        debug_log(DLOG_ERROR, "sml_create_ld_on_new_array -> malloc for cfg failed, CtrlIndex = %d, return 0x%0x\n",
            ctrl_index, ret_val);
        goto quit;
    }

    // 获取用户输入的参数
    ctrl_index = config->i_controller_index;
    operation = CONFIG_OPERATION_CREATE_LD_ON_NEW_ARRAY;
    copy_len = (guint32)(sizeof(SML_RAID_ON_NEW_ARRAY_PARAM_S) - sizeof(SML_CREATE_LD_RETURN_PARAM_S) -
                         sizeof(config->i_controller_index));
    safe_fun_ret = memcpy_s(cfg, copy_len, &config->i_span_depth, copy_len);
    if (safe_fun_ret != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
    }

    // 获取创建LD需要的物理盘信息
    ret_val = smlib_get_pds_info_for_ld_creation(ctrl_index, cfg->pd_sel, cfg->span_depth * cfg->num_drive_per_span,
        cfg->pd_infos);
    if (SML_SUCCESS != ret_val) {
        debug_log(DLOG_ERROR,
            "sml_create_ld_on_new_array -> get pd info for ld creation failed, CtrlIndex = %d, return 0x%0x\n",
            ctrl_index, ret_val);
        goto quit;
    }

    // 获取创建LD需要的控制器信息
    ret_val = smlib_get_ctrl_info_for_ld_creation(ctrl_index, &cfg->ctrl_info);
    if (SML_SUCCESS != ret_val) {
        debug_log(DLOG_ERROR,
            "sml_create_ld_on_new_array -> get ctrl info for ld creation failed, CtrlIndex = %d, return 0x%0x\n",
            ctrl_index, ret_val);
        goto quit;
    }

    param_size = (guint32)sizeof(SML_CREATE_LD_ON_NEW_ARRAY_S);

    ret_val = smlib_exec_config_operation(ctrl_index, operation, (gpointer)cfg, param_size);

    // 拷贝执行返回结果
    if (NULL != cfg) {
        memcpy_s(&config->o_ret_param, sizeof(SML_CREATE_LD_RETURN_PARAM_S), &cfg->ret_param,
            sizeof(SML_CREATE_LD_RETURN_PARAM_S));
    }

quit:
    if (SML_SUCCESS != ret_val) {
        // 对于个别错误，下层调用可以直接设置具体的错误信息
        // 上层检测到错误码已经设置，就认为错误信息也已经由下层填充了，这里不再处理
        if (cfg && (SML_SUCCESS != cfg->ret_param.err_code)) {
            config->o_ret_param.err_code = cfg->ret_param.err_code;
            memcpy_s(config->o_ret_param.err_short_brief, sizeof(config->o_ret_param.err_short_brief),
                cfg->ret_param.err_short_brief, sizeof(cfg->ret_param.err_short_brief));
        } else {
            config->o_ret_param.err_code = ret_val;
            smlib_fill_err_msg(config->o_ret_param.err_code, config->o_ret_param.err_short_brief,
                SML_ERR_SHORT_BRIEF_LEN);
        }

        debug_log(DLOG_ERROR, "sml_create_ld_on_new_array failed, ctrl index = %d, return 0x%0x\n", ctrl_index,
            ret_val);
    } else {
        smlib_refresh_specfied_ld_from_hw_next(ctrl_index, config->o_ret_param.ld_target_id, 1);
        smlib_refresh_specfied_arrays_from_hw_next(ctrl_index, config->o_ret_param.array_refs,
            config->o_ret_param.array_count, 1);
        if (cfg != NULL) {
            smlib_refresh_specfied_pds_from_hw_next(ctrl_index, cfg->pd_sel, cfg->span_depth * cfg->num_drive_per_span,
                1);
        }
        // 其余控制器的信息强制从缓存刷新
        smlib_refresh_all_other_from_cache_next(ctrl_index, 1);
    }

    if (cfg != NULL) {
        g_free(cfg);
    }

    return ret_val;
}

/*
 * Description: APP通过SML执行在现有阵列上创建逻辑盘的命令
 * History: 1.2016年11月4日, ()
 *          新生成函数
 */
gint32 sml_create_ld_on_existed_array(SML_RAID_ON_EXISTED_ARRAY_PARAM_S *config)
{
    gint32 ret_val = 0;
    guint8 ctrl_index = 0;
    guint8 operation = 0;
    SML_CREATE_LD_ON_EXISTED_ARRAY_S *cfg = NULL;
    guint32 param_size = 0;
    guint32 copy_len;
    errno_t safe_fun_ret = EOK;

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

    cfg = (SML_CREATE_LD_ON_EXISTED_ARRAY_S *)g_malloc0(sizeof(SML_CREATE_LD_ON_EXISTED_ARRAY_S));
    if (NULL == cfg) {
        ret_val = SML_ERR_CANNOT_ALLOC_MEM;
        debug_log(DLOG_ERROR, "sml_create_ld_on_existed_array -> malloc for cfg failed, CtrlIndex = %d, return 0x%0x\n",
            ctrl_index, ret_val);
        goto quit;
    }

    // 获取用户输入的参数
    ctrl_index = config->i_controller_index;
    operation = CONFIG_OPERATION_CREATE_LD_ON_EXISTED_ARRAY;
    copy_len = (guint32)(sizeof(SML_RAID_ON_EXISTED_ARRAY_PARAM_S) - sizeof(SML_CREATE_LD_RETURN_PARAM_S) -
                         sizeof(config->i_controller_index));
    safe_fun_ret = memcpy_s(cfg, copy_len, &config->i_array_ref, copy_len);
    if (safe_fun_ret != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
    }

    // 获取创建LD需要的控制器信息
    ret_val = smlib_get_ctrl_info_for_ld_creation(ctrl_index, &cfg->ctrl_info);
    if (SML_SUCCESS != ret_val) {
        debug_log(DLOG_ERROR,
            "sml_create_ld_on_existed_array -> get ctrl info for ld creation failed, CtrlIndex = %d, return 0x%0x\n",
            ctrl_index, ret_val);
        goto quit;
    }

    cfg->pd_block_size = smlib_get_pd_block_size_in_array(ctrl_index, cfg->array_ref);

    param_size = (guint32)sizeof(SML_CREATE_LD_ON_EXISTED_ARRAY_S);

    ret_val = smlib_exec_config_operation(ctrl_index, operation, (gpointer)cfg, param_size);

    // 拷贝执行返回结果
    if (NULL != cfg) {
        memcpy_s(&config->o_ret_param, sizeof(SML_CREATE_LD_RETURN_PARAM_S), &cfg->ret_param,
            sizeof(SML_CREATE_LD_RETURN_PARAM_S));
    }

quit:
    if (SML_SUCCESS != ret_val) {
        // 对于个别错误，下层调用可以直接设置具体的错误信息
        // 上层检测到错误码已经设置，就认为错误信息也已经由下层填充了，这里不再处理
        if (cfg && (SML_SUCCESS != cfg->ret_param.err_code)) {
            config->o_ret_param.err_code = cfg->ret_param.err_code;
            memcpy_s(config->o_ret_param.err_short_brief, sizeof(config->o_ret_param.err_short_brief),
                cfg->ret_param.err_short_brief, sizeof(cfg->ret_param.err_short_brief));
        } else {
            config->o_ret_param.err_code = ret_val;
            smlib_fill_err_msg(config->o_ret_param.err_code, config->o_ret_param.err_short_brief,
                SML_ERR_SHORT_BRIEF_LEN);
        }

        debug_log(DLOG_ERROR, "sml_create_ld_on_existed_array failed, ctrl index = %d, return 0x%0x\n", ctrl_index,
            ret_val);
    } else {
        smlib_refresh_specfied_ld_from_hw_next(ctrl_index, config->o_ret_param.ld_target_id, 1);
        smlib_refresh_specfied_arrays_from_hw_next(ctrl_index, config->o_ret_param.array_refs,
            config->o_ret_param.array_count, 1);
        smlib_refresh_all_pds_from_cache_next(ctrl_index, 1);
        // 其余控制器的信息强制从缓存刷新
        smlib_refresh_all_other_from_cache_next(ctrl_index, 1);
    }

    if (cfg != NULL) {
        g_free(cfg);
    }
    return ret_val;
}

/*
 * Description: APP通过SML执行使用SSD硬盘创建CacheCade逻辑盘的命令
 * History: 1.2016年11月4日, ()
 *          新生成函数
 */
gint32 sml_create_ld_as_cachecade(SML_RAID_CACHECADE_PARAM_S *config)
{
    gint32 ret_val = SML_SUCCESS;
    guint8 ctrl_index = 0;
    guint8 operation = 0;
    SML_CREATE_CACHECADE_LD_S *cfg = NULL;
    guint32 param_size = 0;
    guint32 copy_len;
    errno_t safe_fun_ret = EOK;

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

    cfg = (SML_CREATE_CACHECADE_LD_S *)g_malloc0(sizeof(SML_CREATE_CACHECADE_LD_S));
    if (NULL == cfg) {
        ret_val = SML_ERR_CANNOT_ALLOC_MEM;
        debug_log(DLOG_ERROR, "sml_create_ld_as_cachecade -> malloc for cfg failed, CtrlIndex = %d, return 0x%0x\n",
            ctrl_index, ret_val);
        goto quit;
    }

    // 获取用户输入的参数
    ctrl_index = config->i_controller_index;
    operation = CONFIG_OPERATION_CREATE_CACHECADE_LD;
    copy_len = (guint32)(sizeof(SML_RAID_CACHECADE_PARAM_S) - sizeof(SML_CREATE_LD_RETURN_PARAM_S) -
                         sizeof(config->i_controller_index));
    safe_fun_ret = memcpy_s(cfg, copy_len, &config->i_pd_count, copy_len);
    if (safe_fun_ret != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
    }

    // 获取创建LD需要的物理盘信息
    ret_val = smlib_get_pds_info_for_ld_creation(ctrl_index, cfg->pd_sel, cfg->pd_count, cfg->pd_infos);
    if (SML_SUCCESS != ret_val) {
        debug_log(DLOG_ERROR,
            "sml_create_ld_as_cachecade -> get pd info for ld creation failed, CtrlIndex = %d, return 0x%0x\n",
            ctrl_index, ret_val);
        goto quit;
    }

    // 获取创建LD需要的控制器信息
    ret_val = smlib_get_ctrl_info_for_ld_creation(ctrl_index, &cfg->ctrl_info);
    if (SML_SUCCESS != ret_val) {
        debug_log(DLOG_ERROR,
            "sml_create_ld_as_cachecade -> get ctrl info for ld creation failed, CtrlIndex = %d, return 0x%0x\n",
            ctrl_index, ret_val);
        goto quit;
    }

    param_size = (guint32)sizeof(SML_CREATE_CACHECADE_LD_S);

    ret_val = smlib_exec_config_operation(ctrl_index, operation, (gpointer)cfg, param_size);

    // 拷贝执行返回结果
    if (NULL != cfg) {
        memcpy_s(&config->o_ret_param, sizeof(SML_CREATE_LD_RETURN_PARAM_S), &cfg->ret_param,
            sizeof(SML_CREATE_LD_RETURN_PARAM_S));
    }

quit:
    if (SML_SUCCESS != ret_val) {
        // 对于个别错误，下层调用可以直接设置具体的错误信息
        // 上层检测到错误码已经设置，就认为错误信息也已经由下层填充了，这里不再处理
        if (cfg && (SML_SUCCESS != cfg->ret_param.err_code)) {
            config->o_ret_param.err_code = cfg->ret_param.err_code;
            memcpy_s(config->o_ret_param.err_short_brief, sizeof(config->o_ret_param.err_short_brief),
                cfg->ret_param.err_short_brief, sizeof(cfg->ret_param.err_short_brief));
        } else {
            config->o_ret_param.err_code = ret_val;
            smlib_fill_err_msg(config->o_ret_param.err_code, config->o_ret_param.err_short_brief,
                SML_ERR_SHORT_BRIEF_LEN);
        }

        debug_log(DLOG_ERROR, "sml_create_ld_as_cachecade failed, ctrl index = %d, return 0x%0x\n", ctrl_index,
            ret_val);
    } else {
        smlib_refresh_specfied_ld_from_hw_next(ctrl_index, config->o_ret_param.ld_target_id, 1);
        smlib_refresh_specfied_arrays_from_hw_next(ctrl_index, config->o_ret_param.array_refs,
            config->o_ret_param.array_count, 1);
        if (cfg != NULL) {
            smlib_refresh_specfied_pds_from_hw_next(ctrl_index, cfg->pd_sel, cfg->pd_count, 1);
        }
        // 其余控制器的信息强制从缓存刷新
        smlib_refresh_all_other_from_cache_next(ctrl_index, 1);
    }

    if (cfg != NULL) {
        g_free(cfg);
    }

    return ret_val;
}

/*
 * Description: APP通过SML执行删除逻辑盘的命令
 * History: 1.2016年11月7日, ()
 *          新生成函数
 */
gint32 sml_set_ld_delete(SML_LD_TARGET_S *ld)
{
    gint32 ret_val = 0;
    guint8 ctrl_index = 0;
    guint16 ld_target_id = 0;
    guint8 operation = 0;

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

    ctrl_index = ld->i_controller_index;
    ld_target_id = ld->i_target_id;
    operation = LD_OPERATION_DELETE;

    ret_val = smlib_exec_ld_operation(ctrl_index, ld_target_id, operation, NULL, 0);
    if (SML_SUCCESS != ret_val) {
        debug_log(DLOG_ERROR, "sml_set_ld_delete failed, ctrl index = %d, ld id = %d, return 0x%0x\n", ctrl_index,
            ld_target_id, ret_val);
    }

    return ret_val;
}

/*
 * Description: APP通过SML执行设置指定的逻辑盘为启动盘的命令
 * History: 1.2016年11月8日, ()
 *          新生成函数
 */
gint32 sml_set_ld_boot_priority(SML_LD_TARGET_S *ld)
{
    guint8 ctrl_index;
    guint16 ld_target_id;
    guint8 operation;
    gpointer param = NULL;
    guint32 param_length;

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

    ctrl_index = ld->i_controller_index;
    ld_target_id = ld->i_target_id;
    operation = LD_OPERATION_SET_BOOTABLE;
    param = ld->i_param_ptr;
    param_length = ld->i_param_size;

    gint32 ret_val = smlib_exec_ld_operation(ctrl_index, ld_target_id, operation, param, param_length);
    if (ret_val != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "sml_set_ld_boot_priority failed, ctrl index = %d, ld id = %d, return 0x%0x", ctrl_index,
                  ld_target_id, ret_val);
    }

    return ret_val;
}

/*
 * Description: APP通过SML设置指定逻辑盘是否关联到指定的CacheCade逻辑盘
 * History: 1.2016年11月17日, ()
 *          新生成函数
 */
gint32 sml_set_ld_cachecade_association(SML_LD_SET_CACHECADE_ASSOCIATION_S *ld)
{
    gint32 ret_val = 0;
    guint8 ctrl_index = 0;
    guint16 ld_target_id = 0;
    guint8 operation = 0;
    SML_LD_SET_SSCD_CACHING_ENABLE_S ssd_caching;

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

    ctrl_index = ld->i_controller_index;
    ld_target_id = ld->i_target_id;
    operation = LD_OPERATION_SET_SSCD_CACHING_ENABLE;

    // 判断指定的逻辑盘是否是含有SSD硬盘，如果是则不能为该逻辑盘设置cache使能，返回错误
    if (smlib_is_ssd_in_ld(ctrl_index, ld_target_id)) {
        ret_val = SML_ERR_LD_SET_CACHING_ENABLE_FOR_LD_WITH_SSD;
        debug_log(DLOG_ERROR,
            "sml_set_ld_cachecade_association -> Attemp to set caching enable for ld with ssd, CtrlIndex = %d, "
            "target_id = %d, return 0x%0x\n",
            ctrl_index, ld_target_id, ret_val);
        return ret_val;
    }

    (void)memset_s(&ssd_caching, sizeof(SML_LD_SET_SSCD_CACHING_ENABLE_S), 0, sizeof(SML_LD_SET_SSCD_CACHING_ENABLE_S));
    ssd_caching.enable = ld->i_associate;
    // 获取cachecade ld列表
    ret_val = smlib_get_sscd_list(ctrl_index, ssd_caching.sscd_target_ids, &ssd_caching.sscd_count);
    if (SML_SUCCESS != ret_val) {
        return ret_val;
    }

    ret_val = smlib_exec_ld_operation(ctrl_index, ld_target_id, operation, (gpointer)&ssd_caching,
        sizeof(SML_LD_SET_SSCD_CACHING_ENABLE_S));
    if (SML_SUCCESS != ret_val) {
        debug_log(DLOG_ERROR, "sml_set_ld_cachecade_association failed, ctrl index = %d, ld id = %d, return 0x%0x\n",
            ctrl_index, ld_target_id, ret_val);
    }

    return ret_val;
}

/*
 * Description: APP通过SML获取指定CacheCade LD关联的逻辑盘列表
 * History: 1.2016年11月18日, ()
 *          新生成函数
 */
gint32 sml_get_sscd_associated_ld_list(SML_SSCD_ASSOCIATED_LD_LIST_S *ld)
{
    gint32 ret_val = 0;
    guint8 ctrl_index = 0;
    guint16 target_id = 0;
    SML_LD_BASIC_INFO_S ld_info;
    guint16 idx = 0;

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

    ctrl_index = ld->i_controller_index;
    target_id = ld->i_sscd_id;

    (void)memset_s(&ld_info, sizeof(SML_LD_BASIC_INFO_S), 0, sizeof(SML_LD_BASIC_INFO_S));

    ret_val = smlib_get_ld_info(ctrl_index, target_id, &ld_info);

    ld->o_ld_count = 0;
    (void)memset_s(ld->o_ld_ids, SML_MAX_LOGIC_DRIVES, 0xff, SML_MAX_LOGIC_DRIVES);

    if (SML_SUCCESS == ret_val) {
        // 只有cachecade ld才有这个列表
        if (1 != ld_info.is_sscd) {
            return SML_ERR_LD_INVALID_TARGET_ID;
        }

        ld->o_ld_count = ld_info.sscd_ld_count;

        if (ld->o_ld_count > SML_MAX_LOGIC_DRIVES) {
            ld->o_ld_count = SML_MAX_LOGIC_DRIVES;
        }

        for (idx = 0; idx < ld->o_ld_count; idx++) {
            ld->o_ld_ids[idx] = ld_info.sscd_ld_list[idx];
        }
    }

    return ret_val;
}

/*
 * Description: APP通过SML获取指定逻辑盘关联的CacheCade LD列表
*/
gint32 sml_get_ld_associated_sscd_list(SML_LD_ASSOCIATED_SSCD_LIST_S* ld)
{
    if (ld == NULL) {
        return SML_ERR_NULL_DATA;
    }

    return smlib_get_ld_associated_sscd_list(ld);
}

/*
 * Description: APP通过SML获取指定LD是否关联了CacheCade LD
 * History: 1.2016年11月18日, ()
 *          新生成函数
 */
gint32 sml_get_ld_sscd_caching_enable(SML_LD_SSCD_CACHING_ENABLE_S *ld)
{
    gint32 ret_val = 0;
    guint8 ctrl_index = 0;
    guint16 target_id = 0;

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

    ctrl_index = ld->i_controller_index;
    target_id = ld->i_target_id;

    ld->o_sscd_caching_enable = 0;
    // SSD盘组成的逻辑盘，不需要设置Caching关联，属性值为N/A，直接返回
    if (smlib_is_ssd_in_ld(ctrl_index, target_id)) {
        ld->o_sscd_caching_enable = 0xFF;
        return SML_SUCCESS;
    }

    ret_val = smlib_get_ld_sscd_caching_enable(ctrl_index, target_id, &ld->o_sscd_caching_enable);

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