/* 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.
 */

#include <math.h>
#include "sml_errcodes.h"
#include "sml_public.h"
#include "sml_ld.h"
#include "pmc/pstorc.h"
#include "pmc/sysc_struct.h"
#include "pmc/sysc_cmd.h"
#include "sc_misc.h"
#include "sc_ld.h"

typedef struct {
    guint32 raw_value;
    guint8 state;
} LD_STATE_MAP;

typedef struct {
    guint8 raw_value;
    guint8 raid_level;
} RAID_LEVEL_MAP;

LOCAL LD_STATE_MAP g_ld_state_maps[] = {
    {kLogicalDriveUnitStatusOK, LD_STATE_OPTIMAL},
    {kLogicalDriveUnitStatus1Failed, LD_STATE_FAILED},
    {kLogicalDriveUnitStatus2NotConfigured, LD_STATE_NOT_CONFIGURED},
    {kLogicalDriveUnitStatus3InterimRecovery, LD_STATE_INTERIM_RECOVERY},
    {kLogicalDriveUnitStatus4ReadyForRecovery, LD_STATE_READY_FOR_RECOVERY},
    {kLogicalDriveUnitStatus5Recovering, LD_STATE_RECOVERYING},
    {kLogicalDriveUnitStatus6WrongDriveReplaced, LD_STATE_WRONG_DRIVE_REPLACED},
    {kLogicalDriveUnitStatus7DriveImproperlyConnected, LD_STATE_DRVIE_IMPROPERLY_CONNECTED},
    {kLogicalDriveUnitStatus10Expanding, LD_STATE_EXPANDING},
    {kLogicalDriveUnitStatus11NotYetAvailable, LD_STATE_NOT_YET_AVAILABLE},
    {kLogicalDriveUnitStatus12QueuedForExpansion, LD_STATE_QUEUED_FOR_EXPANSION},
    {kLogicalDriveUnitStatus13DisabledFromSCSIIDConflict, LD_STATE_DISABLED_FROM_SCSIID_CONFLICT},
    {kLogicalDriveUnitStatus14Ejected, LD_STATE_EJECTED},
    {kLogicalDriveUnitStatus15EraseInProgress, LD_STATE_ERASE_IN_PROGRESS},
    {kLogicalDriveUnitStatus16Unused, LD_STATE_UNUSED},
    {kLogicalDriveUnitStatus17ReadyToPerformPredictiveSpareRebuild, LD_STATE_READY_TO_PERFORM_PREDICTIVE_SPARE_REBUILD},
    {kLogicalDriveUnitStatus18RPIInProgress, LD_STATE_RPI_QUEUED},
    {kLogicalDriveUnitStatus19RPIQueued, LD_STATE_RPI_QUEUED},
    {kLogicalDriveUnitStatus20EncryptedVolumeWithoutKey, LD_STATE_ENCRYPTED_VOLUME_WITHOUT_KEY},
    {kLogicalDriveUnitStatus22EncryptionMigration, LD_STATE_ENCRYPTION_MIGRATION},
    {kLogicalDriveUnitStatus23EncryptedVolumeRekeying, LD_STATE_ENCRYPTED_VOLUME_REKEYING},
    {kLogicalDriveUnitStatus24EncryptedVolumeEncryptionOff, LD_STATE_ENCRYPTED_VOLUME_ENCRYPTION_OFF},
    {kLogicalDriveUnitStatus25VolumeEncodeRequested, LD_STATE_VOLUME_ENCODE_REQUESTED},
    {kLogicalDriveUnitStatus26EncryptedVolumeRekeyRequested, LD_STATE_ENCRYPTED_VOLUME_REKEY_REQUESTED},
    {kLogicalDriveUnitStatus27UnsupportedOnThisController, LD_STATE_UNSUPPORTED_ON_THIS_CONTROLLER},
};

LOCAL RAID_LEVEL_MAP g_raid_level_maps[] = {
    {kRAID0, RAID_LEVEL_0},
    {kRAID1, RAID_LEVEL_1},
    {kRAID10, RAID_LEVEL_10},
    {kRAID5, RAID_LEVEL_5},
    {kRAID50, RAID_LEVEL_50},
    {kRAID6, RAID_LEVEL_6},
    {kRAID60, RAID_LEVEL_60},
    {kRAID1ADM, RAID_LEVEL_1ADM},
    {kRAID10ADM, RAID_LEVEL_10ADM},
    {SC_RAID1_TRIPLE, RAID_LEVEL_1TRIPLE},
    {SC_RAID10_TRIPLE, RAID_LEVEL_10TRIPLE},
};

/*
 * Description: 获取逻辑盘ID列表
 */
LOCAL gint32 get_ld_list(guint32 ctrl_id, SC_LD_LIST *ld_list)
{
    SC_LIB_CMD_PARAM_T lcp;

    (void)memset_s(&lcp, SC_LIB_CMD_PARAM_S, 0, SC_LIB_CMD_PARAM_S);

    lcp.cmdType = SC_LD_CMD_TYPE;
    lcp.cmd = SC_GET_LD_LIST;
    lcp.ctrlId = ctrl_id;
    lcp.dataSize = (guint32)sizeof(SC_LD_LIST);
    lcp.pData = ld_list;

    return ProcessSCCommandCall(&lcp);
}

/*
 * Description: 获取逻辑盘ID列表
 */
gint32 pmc_get_ctrl_ld_list(guint32 ctrl_id, gpointer data)
{
    if (data == NULL) {
        return SML_ERR_NULL_DATA;
    }

    SC_LD_LIST ld_list;

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

    gint32 ret = get_ld_list(ctrl_id, &ld_list);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    SML_LD_LIST_S *pLDlist = (SML_LD_LIST_S *)data;

    pLDlist->ld_count = ld_list.count;
    for (guint16 i = 0; i < ld_list.count; i++) {
        pLDlist->target_ids[i] = ld_list.ld_number[i];
    }

    return SML_SUCCESS;
}

/*
 * Description: 解析逻辑盘状态
 */
LOCAL guint8 parse_ld_status(guint32 raw_value)
{
    for (guint8 i = 0; i < G_N_ELEMENTS(g_ld_state_maps); i++) {
        if (raw_value == g_ld_state_maps[i].raw_value) {
            return g_ld_state_maps[i].state;
        }
    }

    return LD_STATE_UNKNOWN;
}

/*
 * Description: 解析逻辑盘RAID级别
 */
LOCAL guint8 parse_raid_level(guint8 raw_value)
{
    for (guint8 i = 0; i < G_N_ELEMENTS(g_raid_level_maps); i++) {
        if (raw_value == g_raid_level_maps[i].raw_value) {
            return g_raid_level_maps[i].raid_level;
        }
    }

    return RAID_LEVEL_UNKNOWN;
}

/*
 * Description: 转换逻辑盘RAID级别为原始值
 */
LOCAL guint8 convert_raid_level(guint8 raid_level)
{
    for (guint8 i = 0; i < G_N_ELEMENTS(g_raid_level_maps); i++) {
        if (raid_level == g_raid_level_maps[i].raid_level) {
            return g_raid_level_maps[i].raw_value;
        }
    }

    return STORAGE_INFO_INVALID_BYTE;
}

/*
 * Description: 获取逻辑盘信息
 */
LOCAL gint32 get_ld_info(guint32 ctrl_id, guint16 target_id, SC_LD_INFO *ld_info)
{
    SC_LIB_CMD_PARAM_T lcp;

    (void)memset_s(&lcp, SC_LIB_CMD_PARAM_S, 0, SC_LIB_CMD_PARAM_S);

    lcp.cmdType = SC_LD_CMD_TYPE;
    lcp.cmd = SC_GET_LD_INFO;
    lcp.ctrlId = ctrl_id;
    lcp.ldRef.targetId = target_id;
    lcp.dataSize = (guint32)sizeof(SC_LD_INFO);
    lcp.pData = ld_info;

    return ProcessSCCommandCall(&lcp);
}

/*
 * Description: 获取逻辑盘的成员盘列表
 */
LOCAL gint32 get_pd_in_ld(guint32 ctrl_id, guint16 target_id, SC_PD_IN_LD *pd_in_ld_info)
{
    SC_LIB_CMD_PARAM_T lcp;

    (void)memset_s(&lcp, SC_LIB_CMD_PARAM_S, 0, SC_LIB_CMD_PARAM_S);

    lcp.cmdType = SC_LD_CMD_TYPE;
    lcp.cmd = SC_GET_PD_IN_LD;
    lcp.ctrlId = ctrl_id;
    lcp.ldRef.targetId = target_id;
    lcp.dataSize = (guint32)sizeof(SC_PD_IN_LD);
    lcp.pData = pd_in_ld_info;

    return ProcessSCCommandCall(&lcp);
}

/*
 * Description: 获取子组信息
 */
LOCAL void get_span_info(guint32 ctrl_id, guint16 target_id, SML_LD_BASIC_INFO_S *pLDinfo, guint8 parity_group_count)
{
    SC_PD_IN_LD pd_in_ld_info;

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

    gint32 ret = get_pd_in_ld(ctrl_id, target_id, &pd_in_ld_info);
    if (ret != SML_SUCCESS) {
        return;
    }

    if (pLDinfo->raid_level == RAID_LEVEL_0 || pLDinfo->raid_level == RAID_LEVEL_1 ||
        pLDinfo->raid_level == RAID_LEVEL_5 || pLDinfo->raid_level == RAID_LEVEL_6 ||
        pLDinfo->raid_level == RAID_LEVEL_1ADM || pLDinfo->raid_level == RAID_LEVEL_1TRIPLE) {
        pLDinfo->span_depth = 1;
        pLDinfo->num_drive_per_span = pd_in_ld_info.count;
    } else if (pLDinfo->raid_level == RAID_LEVEL_50 || pLDinfo->raid_level == RAID_LEVEL_60) {
        pLDinfo->span_depth = MAX(parity_group_count, 2); // RAID50/60至少有2个子组
        pLDinfo->num_drive_per_span = pd_in_ld_info.count / pLDinfo->span_depth;
    } else if (pLDinfo->raid_level == RAID_LEVEL_10) {
        pLDinfo->span_depth = pd_in_ld_info.count / 2;    // 2重镜像
        pLDinfo->num_drive_per_span = 2;     // 2重镜像
    } else if (pLDinfo->raid_level == RAID_LEVEL_10ADM || pLDinfo->raid_level == RAID_LEVEL_10TRIPLE) {
        pLDinfo->span_depth = pd_in_ld_info.count / 3;    // 3重镜像
        pLDinfo->num_drive_per_span = 3;    // 3重镜像
    }

    return;
}

/*
 * Description: 填充与SSD Caching有关的字段
 */
LOCAL void get_ssd_caching_info(SML_LD_BASIC_INFO_S *pLDinfo, SC_LD_INFO *ld_info)
{
    pLDinfo->is_sscd = (ld_info->type == kLogicalDriveTypeCache) ? TRUE : FALSE;
    if (pLDinfo->is_sscd == TRUE) {  // 与普通硬盘一一对应
        pLDinfo->sscd_ld_count = 1;
        pLDinfo->sscd_ld_list[0] = ld_info->editable_info.data_ld_number;
        pLDinfo->cache_line_size = ld_info->editable_info.cache_line_size;
    } else {
        pLDinfo->cache_line_size = STORAGE_INFO_INVALID_BYTE;
    }

    pLDinfo->current_write_policy = STORAGE_INFO_INVALID_BYTE;
    if (pLDinfo->is_sscd == TRUE) {
        if (ld_info->editable_info.lu_write_policy == kLUCacheWritePolicyWriteThru) {
            pLDinfo->current_write_policy = LD_CACHE_WRITE_THROUGH;
        } else if (ld_info->editable_info.lu_write_policy == kLUCacheWritePolicyWriteBack) {
            pLDinfo->current_write_policy = LD_CACHE_WRITE_BACK;
        } else if (ld_info->editable_info.lu_write_policy == kLUCacheWritePolicyReadOnly) {
            pLDinfo->current_write_policy = LD_CACHE_READ_ONLY;
        }
    }

    pLDinfo->default_write_policy = pLDinfo->current_write_policy;

    return;
}

/*
 * Description: 不支持的字段，赋无效值
 */
LOCAL void set_ld_properties_unsupported(SML_LD_BASIC_INFO_S *pLDinfo)
{
    pLDinfo->default_read_policy = STORAGE_INFO_INVALID_BYTE;
    pLDinfo->default_cache_policy = STORAGE_INFO_INVALID_BYTE;
    pLDinfo->current_read_policy = STORAGE_INFO_INVALID_BYTE;
    pLDinfo->current_cache_policy = STORAGE_INFO_INVALID_BYTE;
    pLDinfo->access_policy = STORAGE_INFO_INVALID_BYTE;
    pLDinfo->disk_cache_policy = STORAGE_INFO_INVALID_BYTE;
    pLDinfo->bgi_enabled = STORAGE_INFO_INVALID_BYTE;
    pLDinfo->init_state = STORAGE_INFO_INVALID_BYTE;
    pLDinfo->consistent_check = STORAGE_INFO_INVALID_BYTE;
    pLDinfo->progress_info.current_fgi_state = STORAGE_INFO_INVALID_BYTE;
    pLDinfo->progress_info.fgi = STORAGE_INFO_INVALID_BYTE;
    return;
}

/*
 * Description: 获取逻辑盘信息
 */
gint32 pmc_get_ld_info(guint32 ctrl_id, guint16 target_id, gpointer data)
{
    if (data == NULL) {
        return SML_ERR_NULL_DATA;
    }

    SC_LD_INFO ld_info;

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

    gint32 ret = get_ld_info(ctrl_id, target_id, &ld_info);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    SML_LD_BASIC_INFO_S *pLDinfo = (SML_LD_BASIC_INFO_S *)data;
    pLDinfo->target_id = target_id;
    strncpy_s(pLDinfo->name, sizeof(pLDinfo->name), ld_info.editable_info.label, strlen(ld_info.editable_info.label));

    pLDinfo->strip_size = log2(ld_info.editable_info.strip_size / CAPACITY_CONVERSION_SIZE) + 1; // 以2为底进行转换
    pLDinfo->size = ld_info.editable_info.capacity / CAPACITY_CONVERSION_SIZE / CAPACITY_CONVERSION_SIZE;
    pLDinfo->drive_state = parse_ld_status(LOGICAL_DRIVE_UNIT_STATUS(ld_info.status));
    pLDinfo->raid_level = parse_raid_level(ld_info.editable_info.raid_level);
    pLDinfo->boot_priority = ld_info.boot_priority;
    pLDinfo->accelerator = ld_info.editable_info.accelerator;
    pLDinfo->max_resizeable_size =
        ld_info.editable_info.max_resizeable_size / CAPACITY_CONVERSION_SIZE / CAPACITY_CONVERSION_SIZE;
    pLDinfo->progress_info.rebuild_state = (ld_info.status == kLogicalDriveUnitStatus5Recovering);
    pLDinfo->progress_info.rebuild_progress = (ld_info.rebuild_progress == kInvalidOperationProgressPercent) ?
        STORAGE_INFO_INVALID_BYTE : ld_info.rebuild_progress;
    pLDinfo->array_count = ld_info.array_count;
    for (guint16 i = 0; i < ld_info.array_count && i < SML_MAX_SPAN_DEPTH; i++) {
        pLDinfo->ref_array[i] = ld_info.ref_array[i];
    }

    get_ssd_caching_info(pLDinfo, &ld_info);

    pLDinfo->boot_priority = ld_info.boot_priority;  // 适用PMC的2,3优先级的配置
    pLDinfo->bootable = (ld_info.boot_priority == kBootableVolumePrecedenceNone) ? FALSE : TRUE;
    get_span_info(ctrl_id, target_id, pLDinfo, ld_info.editable_info.parity_group_count);

    /* PMC不支持的字段，赋无效值 */
    set_ld_properties_unsupported(pLDinfo);

    // 热备盘信息
    pLDinfo->spare_count = ld_info.spare_count;
    for (guint16 i = 0; i < ld_info.spare_count && i < MAX_SPARE_PD_NUM; i++) {
        pLDinfo->spare_pd_ids[i] = ld_info.spare_pd_ids[i];
        pLDinfo->spare_pd_slots[i] = ld_info.spare_pd_sids[i];
        pLDinfo->spare_pd_enclosure_ids[i] = ld_info.spare_pd_eids[i];
    }

    return SML_SUCCESS;
}

/*
 * Description: 获取逻辑盘的成员盘列表
 */
gint32 pmc_get_ld_pd_list(guint32 ctrl_id, guint16 target_id, gpointer data)
{
    if (data == NULL) {
        return SML_ERR_NULL_DATA;
    }

    SC_PD_IN_LD pd_in_ld_info;

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

    gint32 ret = get_pd_in_ld(ctrl_id, target_id, &pd_in_ld_info);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    SML_PD_LIST_S *pLDinfo = (SML_PD_LIST_S *)data;
    pLDinfo->pd_count = pd_in_ld_info.count;
    for (guint8 i = 0; i < pd_in_ld_info.count; i++) {
        pLDinfo->device_ids[i] = pd_in_ld_info.pd_number[i];
    }

    return SML_SUCCESS;
}

/*
 * Description: 填充通用参数
 */
LOCAL void fill_common_param(SC_CREATE_LD_INFO *create_ld_info, SML_CREATE_LD_COMMON_PROPERTIES_S *prop)
{
    if (create_ld_info == NULL || prop == NULL) {
        return;
    }

    SC_EDITABLE_LD_INFO *editable_info = &create_ld_info->editable_info;

    /* 名称 */
    if (strlen(prop->ld_name) == 0) {
        strncpy_s(editable_info->label, sizeof(editable_info->label), STORAGE_INFO_INVALID_STRING,
            strlen(STORAGE_INFO_INVALID_STRING));
    } else {
        strncpy_s(editable_info->label, sizeof(editable_info->label), prop->ld_name, sizeof(editable_info->label) - 1);
    }

    /* 容量 */
    if (prop->capacity == STORAGE_INFO_INVALID_DWORD || prop->capacity == 0) {
        editable_info->capacity = STORAGE_INFO_INVALID_QWORD;  // 按默认容量创建，也就是最大值
    } else {
        editable_info->capacity = (guint64)prop->capacity * CAPACITY_CONVERSION_SIZE * CAPACITY_CONVERSION_SIZE;
    }
    /* 条带大小 */
    if (prop->strip_size == STORAGE_INFO_INVALID_BYTE || prop->strip_size == 0) {
        editable_info->strip_size = STORAGE_INFO_INVALID_QWORD;  // 按默认条带大小创建
    } else {
        editable_info->strip_size = (guint64)(pow(2, prop->strip_size - 1) * CAPACITY_CONVERSION_SIZE); // 以2为底进行转换
    }

    /* 加速方法 */
    if (prop->accelerator == STORAGE_INFO_INVALID_BYTE || prop->accelerator == 0) {
        editable_info->accelerator = kLogicalDriveAcceleratorNone;
    } else {
        editable_info->accelerator = prop->accelerator;
    }

    /* 初始化方法 */
    if (prop->init_state == LD_INIT_STATE_RPI) {
        create_ld_info->init_method = kLogicalDriveInitializationMethodRapidParityInit;
    } else if (prop->init_state == LD_INIT_STATE_OPO) {
        create_ld_info->init_method = kLogicalDriveInitializationMethodOPO;
    } else {
        create_ld_info->init_method = kLogicalDriveInitializationMethodDefault;
    }

    return;
}

/*
 * Description: 填充在新阵列上创建逻辑盘的参数
 */
LOCAL void  fill_on_new_array_param(SC_CREATE_LD_INFO *create_ld_info, SML_CREATE_LD_ON_NEW_ARRAY_S *ld_new_array)
{
    create_ld_info->is_max_cache = kFalse;
    create_ld_info->relate_array_number = kInvalidArrayNumber;
    create_ld_info->editable_info.raid_level = convert_raid_level(ld_new_array->raid_level);

    if (ld_new_array->raid_level == RAID_LEVEL_50 || ld_new_array->raid_level == RAID_LEVEL_60) {
        create_ld_info->editable_info.parity_group_count = ld_new_array->span_depth;
    }

    create_ld_info->pd_count = ld_new_array->span_depth * ld_new_array->num_drive_per_span;
    for (guint16 i = 0; i < create_ld_info->pd_count; i++) {
        create_ld_info->pd_number[i] = ld_new_array->pd_sel[i];
    }

    return;
}

/*
 * Description: 填充在已有阵列上创建逻辑盘的参数
 */
LOCAL void fill_on_existed_array_param(SC_CREATE_LD_INFO *create_ld_info,
    SML_CREATE_LD_ON_EXISTED_ARRAY_S *ld_existed_array)
{
    create_ld_info->is_max_cache = kFalse;

    create_ld_info->relate_array_number = ld_existed_array->array_ref;
    create_ld_info->editable_info.raid_level = convert_raid_level(ld_existed_array->raid_level);

    if (ld_existed_array->raid_level == RAID_LEVEL_50 || ld_existed_array->raid_level == RAID_LEVEL_60) {
        create_ld_info->editable_info.parity_group_count = ld_existed_array->span_depth;
    }

    return;
}

/*
 * Description: 填充创建SSD caching逻辑盘的参数
 */
LOCAL void fill_cachecade_param(SC_CREATE_LD_INFO *create_ld_info, SML_CREATE_CACHECADE_LD_S *ld_cachecade)
{
    create_ld_info->is_max_cache = kTrue;

    create_ld_info->relate_array_number = ld_cachecade->array_ref;
    create_ld_info->editable_info.raid_level = convert_raid_level(ld_cachecade->raid_level);
    create_ld_info->pd_count = ld_cachecade->pd_count;
    for (guint16 i = 0; i < create_ld_info->pd_count; i++) {
        create_ld_info->pd_number[i] = ld_cachecade->pd_sel[i];
    }

    if (ld_cachecade->capacity == STORAGE_INFO_INVALID_DWORD || ld_cachecade->capacity == 0) {
        create_ld_info->editable_info.capacity = STORAGE_INFO_INVALID_QWORD;  // 按默认容量创建，也就是最大值
    } else {
        create_ld_info->editable_info.capacity =
            (guint64)ld_cachecade->capacity * CAPACITY_CONVERSION_SIZE * CAPACITY_CONVERSION_SIZE;
    }

    create_ld_info->editable_info.data_ld_number = ld_cachecade->target_ld_id;
    if (ld_cachecade->write_policy == LD_CACHE_READ_ONLY) {
        create_ld_info->editable_info.lu_write_policy = kLUCacheWritePolicyReadOnly;
    } else if (ld_cachecade->write_policy == LD_CACHE_WRITE_THROUGH) {
        create_ld_info->editable_info.lu_write_policy = kLUCacheWritePolicyWriteThru;
    } else if (ld_cachecade->write_policy == LD_CACHE_WRITE_BACK) {
        create_ld_info->editable_info.lu_write_policy = kLUCacheWritePolicyWriteBack;
    }

    create_ld_info->editable_info.cache_line_size = ld_cachecade->cache_line_size;

    return;
}

/*
 * Description: 创建逻辑盘
 */
LOCAL gint32 create_ld(guint32 ctrl_id, SC_CREATE_LD_INFO *create_ld_info)
{
    SC_LIB_CMD_PARAM_T lcp;

    (void)memset_s(&lcp, SC_LIB_CMD_PARAM_S, 0, SC_LIB_CMD_PARAM_S);

    lcp.cmdType = SC_LD_CMD_TYPE;
    lcp.cmd = SC_CREATE_LD;
    lcp.ctrlId = ctrl_id;
    lcp.timeout = MAX_SET_CMD_TIMEOUT;
    lcp.dataSize = (guint32)sizeof(SC_CREATE_LD_INFO);
    lcp.pData = create_ld_info;

    return ProcessSCCommandCall(&lcp);
}

/*
 * Description: RAID配置相关操作
 */
gint32 pmc_config_operations(guint32 ctrl_id, guint8 operation, gpointer param, guint32 param_length)
{
    SC_CREATE_LD_INFO create_ld_info;

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

    SML_CREATE_LD_COMMON_PROPERTIES_S *prop = NULL;
    SML_CREATE_LD_RETURN_PARAM_S *ret_param = NULL;
    SML_CREATE_LD_ON_NEW_ARRAY_S *ld_new_array = (SML_CREATE_LD_ON_NEW_ARRAY_S *)param;
    SML_CREATE_LD_ON_EXISTED_ARRAY_S *ld_existed_array = (SML_CREATE_LD_ON_EXISTED_ARRAY_S *)param;
    SML_CREATE_CACHECADE_LD_S *ld_cachecade = (SML_CREATE_CACHECADE_LD_S *)param;

    if (operation == CONFIG_OPERATION_CREATE_LD_ON_NEW_ARRAY) {
        fill_on_new_array_param(&create_ld_info, ld_new_array);
        prop = &ld_new_array->props;
        ret_param = &ld_new_array->ret_param;
    } else if (operation == CONFIG_OPERATION_CREATE_LD_ON_EXISTED_ARRAY) {
        fill_on_existed_array_param(&create_ld_info, ld_existed_array);
        prop = &ld_existed_array->props;
        ret_param = &ld_existed_array->ret_param;
    } else if (operation == CONFIG_OPERATION_CREATE_CACHECADE_LD) {
        fill_cachecade_param(&create_ld_info, ld_cachecade);
        ret_param = &ld_cachecade->ret_param;
    }

    fill_common_param(&create_ld_info, prop);

    gint32 ret = create_ld(ctrl_id, &create_ld_info);
    if (ret == SML_SUCCESS) {
        if (ret_param == NULL) {
            return SML_ERR_NULL_DATA;
        }
        ret_param->ld_target_id = create_ld_info.new_ld_number;
    }

    return ret;
}

/*
 * Description: 删除逻辑盘
 */
LOCAL gint32 delete_ld(guint32 ctrl_id, guint8 target_id)
{
    SC_LIB_CMD_PARAM_T lcp;

    (void)memset_s(&lcp, SC_LIB_CMD_PARAM_S, 0, SC_LIB_CMD_PARAM_S);

    lcp.cmdType = SC_LD_CMD_TYPE;
    lcp.cmd = SC_DELETE_LD;
    lcp.ctrlId = ctrl_id;
    lcp.timeout = MAX_SET_CMD_TIMEOUT;
    lcp.ldRef.targetId = target_id;

    return ProcessSCCommandCall(&lcp);
}

LOCAL gint32 set_ld_boot_priority_cmd(guint32 ctrl_id, guint8 target_id, guint8 boot_priority)
{
    SC_LIB_CMD_PARAM_T lcp;

    (void)memset_s(&lcp, SC_LIB_CMD_PARAM_S, 0, SC_LIB_CMD_PARAM_S);

    lcp.cmdType = SC_LD_CMD_TYPE;
    lcp.cmd = SC_SET_LD_BOOT_PRIORITY;
    lcp.ctrlId = ctrl_id;
    lcp.timeout = MAX_SET_CMD_TIMEOUT;
    lcp.ldRef.targetId = target_id;
    lcp.dataSize = (guint32)sizeof(boot_priority);
    lcp.pData = &boot_priority;

    return ProcessSCCommandCall(&lcp);
}

/*
 * Description: 设置指定逻辑盘的启动优先级
 */
LOCAL gint32 set_ld_boot_priority(guint32 ctrl_id, guint8 target_id, guint8 boot_priority)
{
    SC_LD_INFO ldInfo;

    (void)memset_s(&ldInfo, sizeof(SC_LD_INFO), 0, sizeof(SC_LD_INFO));

    gint32 ret = get_ld_info(ctrl_id, target_id, &ldInfo);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    // 检查设置的参数是否和当前的设置一致
    if (ldInfo.boot_priority == boot_priority) {
        debug_log(DLOG_INFO, "smllib: PMC: %s --> Logical drive %d is already set as boot drive.",
                  __FUNCTION__, target_id);
    } else {
        ret = set_ld_boot_priority_cmd(ctrl_id, target_id, boot_priority);
        if (ret != SML_SUCCESS) {
            debug_log(DLOG_ERROR, "smllib: PMC: %s --> Set LD as boot drive failed, target id = %d, return 0x%0x ",
                      __FUNCTION__, target_id, ret);
        }
    }

    return ret;
}

/*
 * Description: 填充设置逻辑盘属性参数
 */
LOCAL void fill_ld_prop(SC_SET_LD_PROP *set_ld_prop, SML_LD_SET_PROPERTIES_S *properties)
{
    SC_EDITABLE_LD_INFO *editable_info = &set_ld_prop->editable_info;

    if (properties->setting_options & LD_PROP_SETTING_NAME) {
        set_ld_prop->setting_options |= SC_SET_LD_LABLE;
        (void)strncpy_s(editable_info->label, sizeof(editable_info->label), properties->ld_name,
            sizeof(editable_info->label) - 1);
    }

    if (properties->setting_options & LD_PROP_SETTING_ACCELERATOR) {
        set_ld_prop->setting_options |= SC_SET_LD_ACCELERATOR;
        editable_info->accelerator = properties->accelerator;
    }

    if (properties->setting_options & LD_PROP_SETTING_WRITE_POLICY) {
        set_ld_prop->setting_options |= SC_SET_LD_WRITE_POLICY;
        if (properties->write_policy == LD_CACHE_WRITE_THROUGH) {
            editable_info->lu_write_policy = kLUCacheWritePolicyWriteThru;
        } else if (properties->write_policy == LD_CACHE_WRITE_BACK) {
            editable_info->lu_write_policy = kLUCacheWritePolicyWriteBack;
        } else if (properties->write_policy == LD_CACHE_READ_ONLY) {
            editable_info->lu_write_policy = kLUCacheWritePolicyReadOnly;
        }
    }

    if (properties->setting_options & LD_PROP_SETTING_CAPACITY_SIZE) {
        set_ld_prop->setting_options |= SC_SET_LD_SIZE;
        if (properties->capacity == STORAGE_INFO_INVALID_DWORD || properties->capacity == 0) {
            editable_info->capacity = STORAGE_INFO_INVALID_QWORD;  // 按默认容量创建，也就是最大值
        } else {
            editable_info->capacity =
                (guint64)properties->capacity * CAPACITY_CONVERSION_SIZE * CAPACITY_CONVERSION_SIZE;
        }
    }

    if (properties->setting_options & LD_PROP_SETTING_STRIP_SIZE) {
        set_ld_prop->setting_options |= SC_SET_LD_STRIP_SIZE;
        editable_info->strip_size = (guint64)(pow(2, properties->strip_size - 1) *
            CAPACITY_CONVERSION_SIZE); // 以2为底进行转换
    }

    return;
}

/*
 * Description: 设置逻辑盘属性
 */
LOCAL gint32 set_ld_properties(guint32 ctrl_id, guint8 target_id, SC_SET_LD_PROP *set_ld_prop)
{
    SC_LIB_CMD_PARAM_T lcp;

    (void)memset_s(&lcp, SC_LIB_CMD_PARAM_S, 0, SC_LIB_CMD_PARAM_S);

    lcp.cmdType = SC_LD_CMD_TYPE;
    lcp.cmd = SC_SET_LD_PROPERTIES;
    lcp.ctrlId = ctrl_id;
    lcp.ldRef.targetId = target_id;
    lcp.dataSize = (guint32)sizeof(SC_SET_LD_PROP);
    lcp.pData = set_ld_prop;

    return ProcessSCCommandCall(&lcp);
}

/*
 * Description: 设置逻辑盘属性
 */
LOCAL gint32 set_ld_prop(guint32 ctrl_id, guint8 target_id, SML_LD_SET_PROPERTIES_S *properties)
{
    SC_SET_LD_PROP set_ld_prop;

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

    fill_ld_prop(&set_ld_prop, properties);

    return set_ld_properties(ctrl_id, target_id, &set_ld_prop);
}

/*
 * Description: 逻辑盘相关操作
 */
gint32 pmc_ld_operations(guint32 ctrl_id, guint16 target_id, guint8 operation, gpointer param, guint32 param_length)
{
    gint32 ret;

    switch (operation) {
        case LD_OPERATION_DELETE:
            ret = delete_ld(ctrl_id, (guint8)target_id);
            break;
        case LD_OPERATION_SET_BOOTABLE:
            if ((param == NULL) || (param_length == 0)) {
                return SML_ERR_NULL_DATA;
            }
            ret = set_ld_boot_priority(ctrl_id, (guint8)target_id, *(guint8 *)param);
            break;
        case LD_OPERATION_SET_PROPERTIES:
            if ((param == NULL) || (param_length == 0)) {
                return SML_ERR_NULL_DATA;
            }
            SML_LD_SET_PROPERTIES_S *properties = (SML_LD_SET_PROPERTIES_S *)param;
            ret = set_ld_prop(ctrl_id, target_id, properties);
            break;
        default:
            ret = SML_ERR_LD_OPERATION_NOT_SUPPORT;
            break;
    }

    return ret;
}