/* 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 <dlfcn.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/time.h>
#include "platform.h"
#include "sml_errcodes.h"
#include "sml.h"
#include "sml_common.h"

// include LSI storelib header files start
#include "lsi/storelib.h"
#include "mfi.h"

#include "sl_diagnose.h"
#include "sl.h"
#include "sl_misc.h"
#include "sl_ld.h"

/* 解决包含mpi2.h、mpi2_cnfg.h的编译问题 */
#define MPI2_POINTER *

#include "lsi/mpi2.h"
#include "lsi/mpi2_cnfg.h"
// include LSI storelib header files end

#include <errno.h>

#pragma pack(1)
// ------------创建过程中需要使用的参数设置共用结构体
typedef struct tag_sl_create_ld_common_param {
    guint8 op_type;                     // ld创建的方式
    guint8 raid_level;                  // RAID级别:0/1/5/6/10/50/60, 在已有Array上创建时该参数不使用
    gchar ld_name[SL_LD_NAME_LENGTH];  // 逻辑盘的名称，以'\0'结束的ASCII字符串
    guint8 strip_size;                  // 条带大小 64K/128K/256K/512K/1024K(7~11)
    guint8 read_policy;                 // 读策略 Read Ahead/No Read Ahead/ Adaptive Read Ahead
    guint8 write_policy;                // 写策略 Write Through/Write Back/Write caching ok if bad BBU
    guint8 io_policy;                   // IO策略 Direct IO/Cached IO
    guint8 access_policy;               // 访问策略 Read Write/Read Only/Blocked
    guint8 disk_cache_policy;           // 硬盘缓存策略 Unchanged/Enable/Disable
    guint8 init_state;                  // 初始化状态 No Init/Quick Init/Full Init

    // 以下参数为创建过程中计算出来的
    guint64 start_block;  // 创建的逻辑盘在Array上的起始位置
    guint64 num_blocks;   // 创建的逻辑盘在Array上占用的空间大小
    guint8 span_depth;    // 创建的逻辑盘的span个数
    guint8 num_drives;    // 创建的逻辑盘的每个span的物理硬盘数
} SL_CREATE_LD_COMMON_PARAM_S;

#pragma pack()

static void FindFreeTargetIDs(MR_CONFIG_DATA *pConfigData, guint8 freeTargetIds[SML_MAX_NUM_OF_IDS]);
static gint32 GenerateNextId(guint32 ctrl_id, guint8 freeIds[], SML_CREATE_LD_CTRL_INFO_S *pLdCtrlInfo,
    guint16 *next_id);
static guint8 SetCachePolicy(MR_MFC_DEFAULTS *pMfcDefaults, guint8 read_policy, guint8 write_policy, guint8 io_policy);
static guint8 SetSSCDCachePolicy(MR_MFC_DEFAULTS *pMfcDefaults, guint8 raid_level, guint8 write_policy);
static void SetWritePolicy(guint8 *policy, guint8 write_policy);
static guint8 SetAccessPolicy(guint8 access_policy);
static gint32 SetLdPropertiesForCreation(guint32 ctrl_id, MR_LD_CONFIG *pld, SL_CREATE_LD_COMMON_PARAM_S *common_param,
    guint16 *pArrayRef, SML_CREATE_LD_CTRL_INFO_S *pCtrlInfo, MR_MFC_DEFAULTS *pMfcDefaults);
static gint32 CheckPDsSuitableForNewLD(guint32 ctrl_id, MR_ARRAY *pArray, guint16 arrayCount, guint16 *pd_sel,
    SML_CREATE_LD_PD_INFO_S *pd_infos, SML_CREATE_LD_CTRL_INFO_S *pCtrlInfo, guint8 usedForSSCD);
static gint32 CreateLd(guint32 ctrl_id, guint8 op_type, gpointer param);

static gint32 IsArrayValid(MR_CONFIG_DATA *pCurrentConfig, guint16 arrayRef, guint16 *index);
static gint32 CheckCapacityForNewLD(guint64 usable_block, guint64 i_capacity_blk, guint8 op_type, guint64 *o_used_block,
    guint16 block_size);
static gint32 CvtCapacityLD2PD(guint32 ld_capacity_mb, const SLT_RAID_LEVEL_INFO_S *raid_info,
    const SML_CREATE_LD_CTRL_INFO_S *pCtrlInfo, guint64 *o_pd_used_capcity_blk, guint16 block_size);

static gint32 SetLDBootable(guint32 ctrl_id, guint8 target_id);

static gint32 SetLDPropertiesCmd(guint32 ctrl_id, guint8 target_id, guint16 seq_num, MR_LD_PROPERTIES *pProp);
static gint32 SetLDProperties(guint32 ctrl_id, guint8 target_id, SML_LD_SET_PROPERTIES_S *prop);
//  2016/11/5

static gint32 SetLDListOfSSCDCmd(guint32 ctrl_id, guint8 sscd_id, guint32 buf_len, MR_LD_TARGETID_LIST *pLdListBuf);
static gint32 GetLDListOfSSCDCmd(guint32 ctrl_id, guint8 sscd_id, guint32 buf_len, MR_LD_TARGETID_LIST *pLdListBuf);

static gint32 GetLDListOfSSCD(guint32 ctrl_id, guint8 sscd_id, guint16 *ld_count, guint16 ld_ids[SML_MAX_LOGIC_DRIVES]);
static gint32 GetLDNumOfSSCD(guint32 ctrl_id, guint8 sscd_id, guint16 *num);

static gint32 AssociateLDWithSSCD(guint32 ctrl_id, guint8 target_id, guint8 sscd_id, guint8 enable);
static gint32 SetLDSscdCachingEnable(guint32 ctrl_id, guint8 target_id,
    SML_LD_SET_SSCD_CACHING_ENABLE_S *caching_enable);
static gint32 FindFreeHoleIndex(SL_ARRAY_INFO_T *pArrayInfo, SML_CREATE_LD_CTRL_INFO_S *pLdCtrlInfo, guint32 *idx,
    guint16 block_size);
static guint8 GetSpanDepthFromConfig(MR_CONFIG_DATA *pConfig, guint8 ld_target_id, guint8 *ld_idx);
static guint8 FillArrayDataFromConfig(MR_ARRAY *pArray, guint16 *pArrayRef, guint8 count, MR_CONFIG_DATA *pConfig);
static void FillCommonParam(SL_CREATE_LD_COMMON_PARAM_S *pCommon, guint8 op_type, gpointer param);
static guint64 SetNewArrayCfgData(guint16 *pArrayRef, MR_ARRAY *pArray, guint16 count);

/*
 * Description: 解析LD的读策略
 * History: 2016年3月10日   新生成函数
*/
static guint8 GetReadCachePolicy(guint8 cachePolicy)
{
    // 读策略
    if (cachePolicy & MR_LD_CACHE_READ_AHEAD) {
        return LD_CACHE_READ_AHEAD;
    } else {
        return LD_CACHE_NO_READ_AHEAD;
    }
}

/*
 * Description: 解析LD的写策略
 * History: 2016年3月10日   新生成函数
*/
static guint8 GetWriteCachePolicy(guint8 cachePolicy)
{
    // 写策略
    if ((cachePolicy & MR_LD_CACHE_POLICY_WRITE_CACHE_BAD_BBU) == MR_LD_CACHE_POLICY_WRITE_CACHE_BAD_BBU) {
        return LD_CACHE_WRITE_CACHE_IF_BAD_BBU;
    } else if (cachePolicy & MR_LD_CACHE_WRITE_BACK) {
        return LD_CACHE_WRITE_BACK;
    } else {
        return LD_CACHE_WRITE_THROUGH;
    }
}

/*
 * Description: 解析LD的cache策略
 * History: 2016年3月25日   新生成函数
*/
static guint8 GetCachePolicy(guint8 cachePolicy)
{
    // IO策略
    if ((cachePolicy & MR_LD_CACHE_ALLOW_WRITE_CACHE) && (cachePolicy & MR_LD_CACHE_ALLOW_READ_CACHE)) {
        return LD_CACHE_CACHED_IO;
    } else {
        return LD_CACHE_DIRECT_IO;
    }
}

/*
 * Description: 解析LD的访问策略
 * History: 2016年11月7日   新生成函数
*/
static guint8 GetAccessPolicy(guint8 accessPolicy)
{
    // 访问策略
    switch (accessPolicy) {
        case MR_LD_ACCESS_RW:
            return LD_ACCESS_RW;

        case MR_LD_ACCESS_READ_ONLY:
            return LD_ACCESS_READ_ONLY;

        case MR_LD_ACCESS_BLOCKED:
            return LD_ACCESS_BLOCKED;

        case MR_LD_ACCESS_HIDDEN:
            return LD_ACCESS_HIDDEN;

        default:
            return LD_ACCESS_RW;
    }
}

/*
 * Description: 检查逻辑盘是否是启动盘
 * History: 2016年3月29日   新生成函数
*/
static void CheckLDBootable(guint32 ctrl_id, guint8 targetId, guint8 *bootable)
{
    MR_BIOS_DATA biosData;
    gint32 retval = 0;

    if (NULL == bootable) {
        return;
    }

    if ((retval = GetBIOSData(ctrl_id, &biosData)) != SL_SUCCESS) {
        debug_log(DLOG_DEBUG, "CheckVDBootable : ProcessLibCommandCall failed, retval = 0x%X\n", retval);
        *bootable = 0xFF;
        return;
    }

    debug_log(DLOG_DEBUG, "CheckVDBootable : biosData.bootTargetId = %d, checked targetId = %d\n",
        biosData.bootTargetId, targetId);
    *bootable = (biosData.bootTargetId == targetId) ? TRUE : FALSE;

    return;
}

/*
 * Description: 标记已占用的逻辑盘ID
 * History: 2016年11月4日  ()  新生成函数
*/
static void FindFreeTargetIDs(MR_CONFIG_DATA *pConfigData, guint8 freeTargetIds[SML_MAX_NUM_OF_IDS])
{
    MR_LD_CONFIG *pld = NULL;
    gint32 i = 0;

    if (NULL == pConfigData) {
        return;
    }

    (void)memset_s(freeTargetIds, SML_MAX_NUM_OF_IDS, 1, SML_MAX_NUM_OF_IDS); // 初始化标记所有id为空闲状态

    pld = (MR_LD_CONFIG *)(pConfigData->array + pConfigData->arrayCount);

    for (i = 0; i < pConfigData->logDrvCount; i++) {
        freeTargetIds[pld[i].properties.ldRef.targetId] = 0; // 标记该id已经被占用
    }

    return;
}
/* END:   Modified on 2016/12/22 */
/*
 * Description: 执行查询逻辑盘的LSI libstore命令
 */
static gint32 GetLDListQueryCount(guint32 ctrl_id, guint8 *count)
{
    gint32 rval = SML_SUCCESS;
    MR_LD_TARGETID_LIST *tempList = NULL;
    SL_DCMD_INPUT_T dcmdInput;
    SL_LIB_CMD_PARAM_T lcp;
    guint8 libType = 0;

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    tempList = (MR_LD_TARGETID_LIST *)g_malloc0(sizeof(MR_LD_TARGETID_LIST));
    if (NULL == tempList) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    (void)memset_s(&lcp, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);
    (void)memset_s(&dcmdInput, SL_DCMD_INPUT_S, 0, SL_DCMD_INPUT_S);

    lcp.cmdType = SL_PASSTHRU_CMD_TYPE;
    lcp.cmd = SL_DCMD_PASSTHRU;
    lcp.ctrlId = ctrl_id;
    lcp.dataSize = (guint32)SL_DCMD_INPUT_S;
    lcp.pData = &dcmdInput;

    dcmdInput.opCode = MR_DCMD_LD_LIST_QUERY;

    dcmdInput.flags = SL_DIR_READ;
    dcmdInput.dataTransferLength = (guint32)sizeof(MR_LD_TARGETID_LIST);
    dcmdInput.mbox.b[0] = MR_LD_QUERY_TYPE_USED_TGT_IDS;
    dcmdInput.mbox.b[1] = 0;
    dcmdInput.pData = tempList;

    if (SML_SUCCESS != (rval = ProcessLibCommandCall(libType, &lcp))) {
        g_free(tempList);
        return rval;
    }
    if (tempList->count > MAX_API_LOGICAL_DRIVES_EXT) {
        debug_log(DLOG_ERROR,
            "smlib: LSI:GetLDListQueryCount failed, CtrlId = %d, returned count = %u, count is larger than %d",
            SML_CTRL_ID_VALID_BIT(ctrl_id), tempList->count, SML_MAX_NUM_OF_IDS);
        g_free(tempList);
        return SML_ERR_DATA_INVALID;
    }

    *count = tempList->count;
    g_free(tempList);
    return SML_SUCCESS;
}

/*
 * Description: 获取所有的LD ID，返回结果在targetIdList
 * History: 2016年11月4日  ()  新生成函数
*/
gint32 GetLDListQuery(guint32 ctrl_id, guint8 *targetIdList, guint8 qtype, guint8 *number)
{
    volatile guint32 i = 0;
    gint32 rval = SML_SUCCESS;
    SL_DCMD_INPUT_T dcmdInput;
    SL_LIB_CMD_PARAM_T lcp;
    guint32 reqSize = 0;
    guint8 libType = 0;
    MR_LD_TARGETID_LIST *tempListPtr = NULL;

    if (targetIdList == NULL || number == NULL) {
        return SML_ERR_NULL_DATA;
    }

    if ((rval = GetLDListQueryCount(ctrl_id, number)) != SML_SUCCESS) {
        return rval;
    }

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    (void)memset_s(&lcp, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);
    (void)memset_s(&dcmdInput, SL_DCMD_INPUT_S, 0, SL_DCMD_INPUT_S);

    lcp.cmdType = SL_PASSTHRU_CMD_TYPE;
    lcp.cmd = SL_DCMD_PASSTHRU;
    lcp.ctrlId = ctrl_id;
    lcp.dataSize = (guint32)SL_DCMD_INPUT_S;
    lcp.pData = &dcmdInput;

    dcmdInput.opCode = MR_DCMD_LD_LIST_QUERY;
    dcmdInput.flags = SL_DIR_READ;
    dcmdInput.mbox.b[0] = qtype;
    dcmdInput.mbox.b[1] = 0;

    // 当前博通所有支持带外管理的RAID卡能支持的逻辑盘个数最大为256
    reqSize = (guint32)(sizeof(MR_LD_TARGETID_LIST) + ((*number - 1) * (sizeof(MR_LD_TARGETID_LIST))));
    tempListPtr = (MR_LD_TARGETID_LIST *)g_malloc0(reqSize);
    if (tempListPtr == NULL) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    dcmdInput.pData = tempListPtr;
    dcmdInput.dataTransferLength = reqSize;

    if ((rval = ProcessLibCommandCall(libType, &lcp)) != SL_SUCCESS) {
        g_free(tempListPtr);
        return rval;
    }

    if (tempListPtr->count > MAX_API_LOGICAL_DRIVES_EXT ||
        check_duplicate_ld_id(tempListPtr->targetId, (gsize)*number, MAX_API_LOGICAL_DRIVES_EXT) != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "smlib: LSI:GetLDListQuery Failed. Invalid data");
        g_free(tempListPtr);
        return SML_ERR_DATA_INVALID;
    }

    for (i = 0; i < *number; i++) {
        targetIdList[i] = tempListPtr->targetId[i];
    }

    g_free(tempListPtr);
    return rval;
}

/*
 * Description: 逻辑盘id是否被占用
 */
static gboolean is_ld_id_occupied(guint8 ld_target_id, guint8* ld_id_list, guint8 ld_id_count)
{
    guint8 i = 0;

    while (i < ld_id_count) {
        if (ld_target_id == ld_id_list[i]) {
            // 在控制器返回的id列表中找到了该id，说明该id已经被占用
            return TRUE;
        }

        i++;
    }

    return FALSE;
}

/*
 * Descripition: 获取下一个不支持EPD情况下可用的逻辑盘ID
 */
static guint16 generate_next_id_under_no_epd(guint8 freeIds[], SML_CREATE_LD_CTRL_INFO_S *pLdCtrlInfo, gint32 rval,
    guint8 *targetIdList, guint8 number)
{
    guint16 i;

    for (i = 0; i < pLdCtrlInfo->max_lds; i++) {
        if (freeIds[i] && (rval != SML_SUCCESS || is_ld_id_occupied(i, targetIdList, number) == FALSE)) {
            return i;
        }
    }

    return STORAGE_INFO_INVALID_WORD;
}

/*
 * Descripition: 获取下一个支持EPD情况下可用的逻辑盘ID
 */
static guint16 generate_next_id_under_epd(guint8 freeIds[], SML_CREATE_LD_CTRL_INFO_S *pLdCtrlInfo, gint32 rval,
    guint8 *targetIdList, guint8 number)
{
    gint16 i;

    for (i = pLdCtrlInfo->max_lds - 1; i >= 0; i--) {
        if (freeIds[i] && (rval != SML_SUCCESS || is_ld_id_occupied(i, targetIdList, number) == FALSE)) {
            return (guint16)i;
        }
    }

    return STORAGE_INFO_INVALID_WORD;
}

/*
 * Description: 获取下一个可用的逻辑盘ID，返回的ID为next_id指针内的值
 * History: 2016年11月4日  ()  新生成函数
*/
static gint32 GenerateNextId(guint32 ctrl_id, guint8 freeIds[], SML_CREATE_LD_CTRL_INFO_S *pLdCtrlInfo,
    guint16 *next_id)
{
    gint32 rval = SML_SUCCESS;
    guint8 *targetIdList = NULL;
    guint8 number = 0;

    if ((NULL == freeIds) || (NULL == next_id)) {
        return SML_ERR_NULL_DATA;
    }

    *next_id = 0xffff;

    targetIdList = (guint8 *)g_malloc0(SML_MAX_NUM_OF_IDS * sizeof(guint8));
    if (NULL == targetIdList) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    rval = GetLDListQuery(ctrl_id, targetIdList, MR_LD_QUERY_TYPE_USED_TGT_IDS, &number);
    if (pLdCtrlInfo->support_epd) {
        *next_id = generate_next_id_under_epd(freeIds, pLdCtrlInfo, rval, targetIdList, number);
    } else {
        *next_id = generate_next_id_under_no_epd(freeIds, pLdCtrlInfo, rval, targetIdList, number);
    }

    g_free(targetIdList);
    return SML_SUCCESS;
}

/*
 * Description: 将读/写/IO缓存策略设置转化为供LSI设置LD的缓存策略格式
 * History: 2016年11月5日  ()  新生成函数
*/
static guint8 SetCachePolicy(MR_MFC_DEFAULTS *pMfcDefaults, guint8 read_policy, guint8 write_policy, guint8 io_policy)
{
    guint8 cachePolicy = 0;
    guint8 default_read_policy = LD_CACHE_READ_AHEAD, default_write_policy = LD_CACHE_WRITE_THROUGH,
           default_io_policy = LD_CACHE_DIRECT_IO;

    if (NULL != pMfcDefaults) {
        default_read_policy = pMfcDefaults->readAhead;  // 默认值: LD_CACHE_READ_AHEAD
        default_write_policy = pMfcDefaults->writeBack; // 默认值: LD_CACHE_WRITE_THROUGH

        if (pMfcDefaults->cachedIo) { // 默认值: LD_CACHE_DIRECT_IO，数值定义与输入参数相反
            default_io_policy = LD_CACHE_CACHED_IO;
        } else {
            default_io_policy = LD_CACHE_DIRECT_IO;
        }
    }

    if (read_policy > LD_CACHE_READ_AHEAD) {
        read_policy = default_read_policy;
    }

    switch (read_policy) {
        case LD_CACHE_NO_READ_AHEAD:
            cachePolicy = MR_LD_CACHE_POLICY_READ_AHEAD_NONE;
            break;

        case LD_CACHE_READ_AHEAD:
        default:
            cachePolicy = MR_LD_CACHE_POLICY_READ_AHEAD_ALWAYS;
            break;
    }

    if (write_policy > LD_CACHE_WRITE_CACHE_IF_BAD_BBU) {
        write_policy = default_write_policy;
    }

    switch (write_policy) {
        case LD_CACHE_WRITE_THROUGH:
            cachePolicy |= MR_LD_CACHE_POLICY_WRITE_THROUGH;
            break;

        case LD_CACHE_WRITE_CACHE_IF_BAD_BBU:
            cachePolicy |= MR_LD_CACHE_POLICY_WRITE_CACHE_BAD_BBU;
            break;

        case LD_CACHE_WRITE_BACK:
        default:
            cachePolicy |= MR_LD_CACHE_POLICY_WRITE_BACK;
            break;
    }

    if (io_policy > LD_CACHE_DIRECT_IO) {
        io_policy = default_io_policy;
    }

    if (io_policy == LD_CACHE_CACHED_IO) {
        cachePolicy |= MR_LD_CACHE_POLICY_IO_CACHED;
    } else {
        cachePolicy |= MR_LD_CACHE_POLICY_IO_DIRECT;
    }

    return cachePolicy;
}

/*
 * Description: 设置CacheCade LD的缓存策略,只能设置写策略,其他策略默认设置
 * History: 2016年11月16日  ()  新生成函数
*/
static guint8 SetSSCDCachePolicy(MR_MFC_DEFAULTS *pMfcDefaults, guint8 raid_level, guint8 write_policy)
{
    guint8 cachePolicy = 0, defaul_policy = 0;

    if ((NULL != pMfcDefaults) && pMfcDefaults->writeBack && (raid_level != 0)) {
        defaul_policy = MR_LD_CACHE_POLICY_WRITE_BACK;
    } else {
        defaul_policy = MR_LD_CACHE_POLICY_WRITE_THROUGH;
    }

    switch (write_policy) {
        case LD_CACHE_WRITE_THROUGH:
            cachePolicy = MR_LD_CACHE_POLICY_WRITE_THROUGH;
            break;

        case LD_CACHE_WRITE_BACK:
            cachePolicy = MR_LD_CACHE_POLICY_WRITE_BACK;
            break;

        case LD_CACHE_WRITE_CACHE_IF_BAD_BBU:
            cachePolicy = MR_LD_CACHE_POLICY_WRITE_CACHE_BAD_BBU;
            break;

        default:
            cachePolicy = defaul_policy;
            break;
    }

    return cachePolicy;
}

/*
 * Description: 只设置LD的写策略
 * History: 2016年11月9日  ()  新生成函数
*/
static void SetWritePolicy(guint8 *policy, guint8 write_policy)
{
    guint8 cachePolicy = 0;
    guint8 default_write_policy = LD_CACHE_WRITE_THROUGH;

    if (write_policy > LD_CACHE_WRITE_CACHE_IF_BAD_BBU) {
        write_policy = default_write_policy;
    }

    // 设置前先清除相关的位
    cachePolicy = *policy;
    cachePolicy = cachePolicy & (~MR_LD_CACHE_POLICY_WRITE_CACHE_BAD_BBU);

    switch (write_policy) {
        case LD_CACHE_WRITE_THROUGH:
            cachePolicy |= MR_LD_CACHE_POLICY_WRITE_THROUGH;
            break;

        case LD_CACHE_WRITE_CACHE_IF_BAD_BBU:
            cachePolicy |= MR_LD_CACHE_POLICY_WRITE_CACHE_BAD_BBU;
            break;

        case LD_CACHE_WRITE_BACK:
        default:
            cachePolicy |= MR_LD_CACHE_POLICY_WRITE_BACK;
            break;
    }

    *policy = cachePolicy;
}

/*
 * Description: 设置LD的访问策略
 * History: 2016年11月9日  ()  新生成函数
*/
static guint8 SetAccessPolicy(guint8 access_policy)
{
    guint8 policy = MR_LD_ACCESS_RW;

    switch (access_policy) {
        case LD_ACCESS_RW:
            policy = MR_LD_ACCESS_RW;
            break;

        case LD_ACCESS_READ_ONLY:
            policy = MR_LD_ACCESS_READ_ONLY;
            break;

        case LD_ACCESS_BLOCKED:
            policy = MR_LD_ACCESS_BLOCKED;
            break;

        default:
            policy = MR_LD_ACCESS_RW;
            break;
    }

    return policy;
}

/*
 * Description: 利用指定的参数填充创建逻辑盘需要的MR_LD_CONFIG结构体相关参数和属性
 * History: 2016年11月5日  ()  新生成函数
*/
static gint32 SetLdPropertiesForCreation(guint32 ctrl_id, MR_LD_CONFIG *pld, SL_CREATE_LD_COMMON_PARAM_S *common_param,
    guint16 *pArrayRef, SML_CREATE_LD_CTRL_INFO_S *pCtrlInfo, MR_MFC_DEFAULTS *pMfcDefaults)
{
    gint32 i = 0;

    guint32 PRL = 0, stripeSize = 0, stripeSizeInBlks = 0;
    guint64 numBlocks = 0;
    guint8 libType = 0;
    guint8 is_sscd = 0;

    if ((pld == NULL) || (common_param == NULL) || (pArrayRef == NULL) || (pCtrlInfo == NULL)) {
        return SML_ERR_NULL_DATA;
    }

    numBlocks = common_param->num_blocks;

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    // 设置新建Array的RAID级别
    is_sscd = (CONFIG_OPERATION_CREATE_CACHECADE_LD == common_param->op_type) ? 1 : 0;

    if (CONFIG_OPERATION_CREATE_LD_ON_EXISTED_ARRAY != common_param->op_type) {
        PRL = common_param->raid_level;
        // 除以10，用来从RAID级别10/50/60中获取基本级别
        if (!(PRL % 10)) {
            PRL = PRL / 10;
        }

        // 检查指定的RAID级别是否支持
        if (is_sscd) {
            if (!(IsValidRaidLevelForSSCD(common_param->raid_level, common_param->num_drives, pCtrlInfo))) {
                return SML_ERR_CONFIG_INVALID_PARAM_RAID_LEVEL;
            }
        } else {
            if (!(IsValidRaidLevel(common_param->raid_level, common_param->num_drives, common_param->span_depth,
                pCtrlInfo))) {
                return SML_ERR_CONFIG_INVALID_PARAM_RAID_LEVEL;
            }
        }

        // 对于在已有Array上创建LD的情况，基本RAID级别在这个函数外设置(沿用原先逻辑盘的设置)
        pld->params.PRL = (guint8)PRL;
    }

    if (NULL != pMfcDefaults) {
        stripeSize = pMfcDefaults->stripeSize;

        if ((stripeSize == 0) || (stripeSize < pCtrlInfo->min_strip) || (stripeSize > pCtrlInfo->max_strip)) {
            stripeSize = DEFAULT_STRIP_SIZE;
        }
    } else {
        stripeSize = DEFAULT_STRIP_SIZE;
    }

    if (!is_sscd && (common_param->strip_size >= pCtrlInfo->min_strip) &&
        (common_param->strip_size <= pCtrlInfo->max_strip)) {
        stripeSize = common_param->strip_size;
    }

    pld->params.stripeSize = (guint8)stripeSize;

    // 设置每个span的起始block和占用block的大小，这些值要和条带大小边界对齐
    stripeSizeInBlks = (1 << pld->params.stripeSize);

    for (i = 0; i < common_param->span_depth; i++) {
        pld->span[i].startBlock = common_param->start_block;

        // 设置空间大小要和条带边界对齐
        if (numBlocks % stripeSizeInBlks) {
            numBlocks = (numBlocks / stripeSizeInBlks) * stripeSizeInBlks;
        }

        pld->span[i].numBlocks = numBlocks;
        pld->span[i].arrayRef = pArrayRef[i];
    }

    // 设置逻辑盘的名称
    /* * BEGIN: Added by lichangdi,  安全排查 20170808，strncpy_s 参数4不能大于等于参数2 */
    strncpy_s(pld->properties.name, sizeof(pld->properties.name), common_param->ld_name,
        sizeof(pld->properties.name) - 1);
    /* * END:   Added by lichangdi, 20170808 */
    pld->properties.name[SL_LD_NAME_LENGTH - 1] = '\0'; // 确保有结束符

    if (is_sscd) {
        // CacheCade LD只设置写策略，其余默认
        pld->properties.defaultCachePolicy = SetSSCDCachePolicy(pMfcDefaults, PRL, common_param->write_policy);

        // 以下参数均为直接指定
        pld->properties.accessPolicy = MR_LD_ACCESS_RW;
        pld->properties.diskCachePolicy = MR_PD_CACHE_UNCHANGED;
        pld->params.RLQ = RLQ_0;
        pld->params.SRL = SRL_0;
        pld->params.isSSCD = 1; // CacheCade LD与普通LD的区别属性

        pld->params.initState = LD_INIT_STATE_NO_INIT;
    } else {
        pld->properties.defaultCachePolicy = SetCachePolicy(pMfcDefaults, common_param->read_policy,
            common_param->write_policy, common_param->io_policy);

        // 设置逻辑盘的访问策略
        switch (common_param->access_policy) {
            case LD_ACCESS_RW:
                pld->properties.accessPolicy = MR_LD_ACCESS_RW;
                break;

            case LD_ACCESS_READ_ONLY:
                pld->properties.accessPolicy = MR_LD_ACCESS_READ_ONLY;
                break;

            case LD_ACCESS_BLOCKED:
                pld->properties.accessPolicy = MR_LD_ACCESS_BLOCKED;
                break;

            default:
                debug_log(DLOG_DEBUG,
                    "smlib: LSI:SetLdPropertiesForCreation -> Invalid Access Policy setting. Default (Read Write) "
                    "taken\n");
                pld->properties.accessPolicy = MR_LD_ACCESS_RW;
                break;
        }

        // 设置逻辑盘的成员物理盘的缓存策略
        // 物理盘缓存策略设置只允许在storelib设置. 对于storelibIR, 这个值由FW依据NVDATA配置来管理.
        if (libType == SL_LIB_TYPE_STORELIB) {
            if (common_param->disk_cache_policy > MR_PD_CACHE_DISABLE) {
                common_param->disk_cache_policy = MR_PD_CACHE_UNCHANGED;
                debug_log(DLOG_DEBUG,
                    "smlib: LSI:SetLdPropertiesForCreation -> Invalid Disk Cache Policy setting. Default (Unchanged) "
                    "taken\n");
            }

            pld->properties.diskCachePolicy = common_param->disk_cache_policy;
        } else {
            debug_log(DLOG_DEBUG,
                "smlib: LSI:SetLdPropertiesForCreation -> Disk Cache Policy is taken care by FW based on NVDATA\n");
        }

        pld->params.RLQ = RLQ_0;

        if (pld->params.PRL == PRL_5 || pld->params.PRL == PRL_6) {
            pld->params.RLQ = RLQ_3;
        }

        pld->params.SRL = SRL_0; // 不支持SRL_03

        if (common_param->init_state > LD_INIT_STATE_FULL_INIT) {
            common_param->init_state = LD_INIT_STATE_NO_INIT;
            debug_log(DLOG_DEBUG,
                "smlib: LSI:SetLdPropertiesForCreation -> Invalid Init State setting. Default (No Init) taken\n");
        }

        pld->params.initState = common_param->init_state;
    }

    pld->params.numDrives = common_param->num_drives;
    pld->params.spanDepth = common_param->span_depth;
    pld->params.state = MR_LD_STATE_OPTIMAL;

    return SL_SUCCESS;
}

/*
 * Description: 判断指定的物理盘是否适合创建新的逻辑盘
 * History: 2016年11月5日  ()  新生成函数
 *          2017年1月14日  ()  增加物理盘的block size判断
*/
static gint32 CheckPDsSuitableForNewLD(guint32 ctrl_id, MR_ARRAY *pArray, guint16 arrayCount, guint16 *pd_sel,
    SML_CREATE_LD_PD_INFO_S *pd_infos, SML_CREATE_LD_CTRL_INFO_S *pCtrlInfo, guint8 usedForSSCD)
{
    gint32 retval = SML_SUCCESS;
    gint32 i = 0, j = 0, pdCount = 0;
    gint32 ssdFound = FALSE;
    guint8 mediatype = 0, ssdType = 0; // mediatype: HDD/SSD  ssdType(ssd interface type): SAS/SATA
    guint8 numDrives = 0;
    guint16 baseArrayRef = 0;
    SML_CREATE_LD_PD_INFO_S *pPdInfo = NULL;
    guint16 block_size = PD_BLOCK_SIZE_512;

    if ((pArray == NULL) || (pd_infos == NULL) || (pCtrlInfo == NULL) || (pd_sel == NULL) || (arrayCount <= 0)) {
        return SML_ERR_NULL_DATA;
    }

    numDrives = pArray[0].numDrives;
    baseArrayRef = pArray[0].arrayRef;

    // 判断pd_Sel[]数组中的前span_depth * num_drive_per_span个物理盘ID是否有重复
    pdCount = arrayCount * numDrives;

    for (i = 0; i < pdCount; i++) {
        for (j = i + 1; j < pdCount; j++) {
            if (pd_sel[i] == pd_sel[j]) {
                retval = SML_ERR_CONFIG_INVALID_PARAM_REPEATED_PD_ID;
                debug_log(DLOG_ERROR,
                    "smlib: LSI:CheckPDsSuitableForNewLD -> invalid PD ID list, pd_sel[%d] = pd_sel[%d] = %d, return "
                    "0x%0x\n",
                    i, j, pd_sel[i], retval);
                return retval;
            }
        }
    }

    // 取第一个物理盘的block size，作为比较的标准
    block_size = pd_infos[0].block_size;

    for (i = 0; i < arrayCount; i++) {
        // Array ref ID为控制器动态顺序分配(0,1,2...)， Array ref
        // ID不是一直不变的，比如由于处于Array上的所有逻辑盘都已经删除， Array也会相应的删除，其他Array的ref
        // ID会自动调整
        pArray[i].arrayRef = baseArrayRef + i;
        debug_log(DLOG_DEBUG, "smlib: LSI:CheckPDsSuitableForNewLD -> Array ID : %d\n", pArray[i].arrayRef);

        pArray[i].numDrives = numDrives;

        // 检查物理盘列表是否适合创建逻辑盘
        for (j = 0; j < pArray[i].numDrives; j++) {
            pPdInfo = &pd_infos[i * numDrives + j];

            if (NULL == pPdInfo) {
                debug_log(DLOG_ERROR,
                    "smlib: LSI:CheckPDsSuitableForNewLD -> Could not fetch PD info, PdId[%d] = %d, return 0x%0x\n",
                    i * numDrives + j, pd_sel[i * numDrives + j], retval);
                retval = SML_ERR_CONFIG_INVALID_PD_GETINFO_FAILED;
                return retval;
            }

            // 对于创建CacheCade LD的情况，需要所有的物理硬盘为SSD，任何一个硬盘不是SSD则返回错误
            if (usedForSSCD && (MR_PD_MEDIA_TYPE_SSD != pPdInfo->media_type)) {
                retval = SML_ERR_CONFIG_INVALID_PD_NON_SDD_FOR_CACHECADE;
                debug_log(DLOG_ERROR,
                    "smlib: LSI:CheckPDsSuitableForNewLD -> Selected non-SSD for CacheCade LD, PdId[%d] = %d, return "
                    "0x%0x\n",
                    i * numDrives + j, pPdInfo->device_id, retval);
                return retval;
            }

            // 如果用于创建逻辑盘的物理盘的block size不一致，则返回错误
            if (block_size != pPdInfo->block_size) {
                retval = SML_ERR_CONFIG_BLOCK_SIZE_NOT_SAME;
                debug_log(DLOG_ERROR,
                    "smlib: LSI:CheckPDsSuitableForNewLD -> Pd block size is not same, PdId[%d] = %d, pd block size = "
                    "%d, "
                    "block size = %d, return 0x%0x\n",
                    i * numDrives + j, pPdInfo->device_id, pPdInfo->block_size, block_size, retval);

                return retval;
            }

            if (pPdInfo->not_supported || pPdInfo->scsi_dev_type != SPC_HARDDISK ||
                pPdInfo->fw_state != MR_PD_STATE_UNCONFIGURED_GOOD || pPdInfo->is_foreign ||
                ((j) && (pCtrlInfo->allow_mix_ssd_hdd == 0) && (pPdInfo->media_type != mediatype)) ||
                ((ssdFound) && (pCtrlInfo->allow_ssd_mix == 0) && (pPdInfo->interface_type != ssdType))) {
                retval = SML_ERR_CONFIG_INVALID_PD_OTHER_ERROR;

                // 物理设备不支持
                if (pPdInfo->not_supported) {
                    retval = SML_ERR_CONFIG_INVALID_PD_NON_SUPPORTED;
                    debug_log(DLOG_ERROR,
                        "smlib: LSI:CheckPDsSuitableForNewLD -> Non-supported Pd, PdId[%d] = %d, return 0x%0x\n",
                        i * numDrives + j, pPdInfo->device_id, retval);
                    return retval;
                }

                // 物理设备类型不对，比如指定的ID为CDROM
                if (pPdInfo->scsi_dev_type != SPC_HARDDISK) {
                    retval = SML_ERR_CONFIG_INVALID_PD_SCSI_DEV_TYPE;
                    debug_log(DLOG_ERROR,
                        "smlib: LSI:CheckPDsSuitableForNewLD -> Pd SCSI Device type is not Hard disk, PdId[%d] = %d, "
                        "scsiDevType = %d, return 0x%0x\n",
                        i * numDrives + j, pPdInfo->device_id, pPdInfo->scsi_dev_type, retval);
                    return retval;
                }

                // 物理盘不是空闲的
                if (pPdInfo->fw_state != MR_PD_STATE_UNCONFIGURED_GOOD) {
                    retval = SML_ERR_CONFIG_INVALID_PD_IN_USE;
                    debug_log(DLOG_ERROR,
                        "smlib: LSI:CheckPDsSuitableForNewLD -> PD in use, PdId[%d] = %d, fwState = %d, return 0x%0x\n",
                        i * numDrives + j, pPdInfo->device_id, pPdInfo->fw_state, retval);
                    return retval;
                }

                // 物理盘包含外部配置
                if (pPdInfo->is_foreign) {
                    retval = SML_ERR_CONFIG_INVALID_PD_WITH_FOREIGN_CONFIG;
                    debug_log(DLOG_ERROR,
                        "smlib: LSI:CheckPDsSuitableForNewLD -> PD with foreign configuration, PdId[%d] = %d, fwState "
                        "= "
                        "%d, return 0x%0x\n",
                        i * numDrives + j, pPdInfo->device_id, pPdInfo->fw_state, retval);
                    return retval;
                }

                // 控制器不支持HDD/SSD在同一个逻辑盘中
                if (pPdInfo->media_type != mediatype) {
                    retval = SML_ERR_CONFIG_INVALID_PD_SDD_HDD_MIXED;
                    debug_log(DLOG_ERROR,
                        "smlib: LSI:CheckPDsSuitableForNewLD -> SSD HDD mixing not allowed, PdId[%d] = %d, mediaType = "
                        "%d, "
                        "return 0x%0x\n",
                        i * numDrives + j, pPdInfo->device_id, pPdInfo->media_type, retval);
                    return retval;
                }

                // 控制器不支持不同接口(SATA/SAS)的SSD在同一个逻辑盘中
                if (pPdInfo->interface_type != ssdType) {
                    retval = SML_ERR_CONFIG_INVALID_PD_SDD_SAS_SATA_MIXED;
                    debug_log(DLOG_ERROR,
                        "smlib: LSI:CheckPDsSuitableForNewLD -> SSD SATA and SSD SAS drives cannot be mixed, PdId[%d] "
                        "= %d, interfaceType = %d, return 0x%0x\n",
                        i * numDrives + j, pPdInfo->device_id, pPdInfo->interface_type, retval);
                    return retval;
                }

                return retval;
            }

            // 记下第一个物理盘的媒介类型(SSD/HDD)作为比较的依据
            if (j == 0) {
                mediatype = pPdInfo->media_type;
            }

            // 找到SSD硬盘，作标记
            if ((ssdFound == FALSE) && (pPdInfo->media_type == MR_PD_MEDIA_TYPE_SSD)) {
                ssdType = pPdInfo->interface_type;
                ssdFound = TRUE;
            }

            // 设置组成Array的物理盘ID和固件状态
            pArray[i].pd[j].ref.deviceId = pPdInfo->device_id;
            pArray[i].pd[j].ref.seqNum = pPdInfo->seq_num;
            pArray[i].pd[j].fwState = MR_PD_STATE_ONLINE;

            // 设置Array的容量, 为组成Array的物理盘中的最小容量(对齐后的)
            if (j == 0) {
                pArray[i].size = pPdInfo->coerced_size_blk;
            } else if (pPdInfo->coerced_size_blk < pArray[i].size) {
                pArray[i].size = pPdInfo->coerced_size_blk;
            }
        }
    }

    return SML_SUCCESS;
}

/*
 * Description: 判断指定的Array是否存在于指定的config内，找到Array，通过*idx传回
 * History: 2016年11月4日  ()  新生成函数
*/
static gint32 IsArrayValid(MR_CONFIG_DATA *pCurrentConfig, guint16 arrayRef, guint16 *idx)
{
    volatile guint16 i = 0;
    MR_ARRAY *pArray = NULL;

    if (pCurrentConfig == NULL || idx == NULL) {
        return SML_ERR_NULL_DATA;
    }

    pArray = pCurrentConfig->array;

    for (i = 0; i < pCurrentConfig->arrayCount; i++) {
        if (pArray[i].arrayRef == arrayRef) {
            *idx = i;
            return TRUE;
        }
    }

    return FALSE;
}

/*
 * Description: 检查新建逻辑盘要使用的单个物理盘上的容量空间
 * History: 2016年12月1日  ()  新生成函数
 *          2017年1月14日  ()  增加判断物理盘的block size
*/
static gint32 CheckCapacityForNewLD(guint64 usable_block, guint64 i_capacity_blk, guint8 op_type, guint64 *o_used_block,
    guint16 block_size)
{
    if (NULL == o_used_block) {
        return SML_ERR_CONFIG_ARRAY_NO_AVAILABLE_SPACE;
    }

    if (0 == block_size) {
        block_size = PD_BLOCK_SIZE_512;
    }

    // 可用的Array空间小于最小逻辑盘分配的单盘空间
    if (usable_block < MB2BLK(SML_LD_MIN_SIZE, block_size)) {
        return SML_ERR_CONFIG_ARRAY_SIZE_TOO_SMALL;
    }

    // 使用默认值或者创建的是CacheCade逻辑盘，使用全部的可用空间
    if ((0xFFFFFFFF == i_capacity_blk) || (CONFIG_OPERATION_CREATE_CACHECADE_LD == op_type)) {
        *o_used_block = usable_block;
        return SML_SUCCESS;
    }

    *o_used_block = i_capacity_blk;

    // 输入的空间大于可用空间
    if (*o_used_block > usable_block) {
        return SML_ERR_CONFIG_INVALID_PARAM_CAPACITY_TOO_LARGE;
    }

    // 输入空间小于最小逻辑盘分配的单盘空间
    if (*o_used_block < MB2BLK(SML_LD_MIN_SIZE, block_size)) {
        return SML_ERR_CONFIG_INVALID_PARAM_CAPACITY_TOO_SMALL;
    }

    return SML_SUCCESS;
}

/*
 * Description: 将逻辑盘容量转化成单个物理盘上占用的容量
 * History: 2016年12月2日  ()  新生成函数
 *          2017年1月14日  ()  增加判断物理盘的block size
*/
static gint32 CvtCapacityLD2PD(guint32 ld_capacity_mb, const SLT_RAID_LEVEL_INFO_S *raid_info,
    const SML_CREATE_LD_CTRL_INFO_S *pCtrlInfo, guint64 *o_pd_used_capcity_blk, guint16 block_size)
{
    gint32 retval = SML_SUCCESS;
    guint64 capacity_blk = 0, div_factor = 1;
    guint64 ld_capacity_blk = 0;

    if ((NULL == o_pd_used_capcity_blk) || (NULL == raid_info) || (NULL == pCtrlInfo)) {
        return SML_ERR_CONFIG_ARRAY_NO_AVAILABLE_SPACE;
    }

    if (!IsValidRaidLevel(raid_info->raid_level, raid_info->num_drive_per_span, raid_info->span_depth, pCtrlInfo)) {
        return SML_ERR_CONFIG_INVALID_PARAM_RAID_LEVEL;
    }

    if (0 == block_size) {
        block_size = PD_BLOCK_SIZE_512;
    }

    *o_pd_used_capcity_blk = 0;
    ld_capacity_blk = MB2BLK((guint64)ld_capacity_mb, block_size);

    // 计算单个span内的容量
    capacity_blk = ld_capacity_blk / raid_info->span_depth;

    // 已经检查过RAID级别的有效性，以下不再做有效性的任何检查
    switch (raid_info->raid_level) {
        case RAID_LEVEL_0:
            capacity_blk = capacity_blk / raid_info->num_drive_per_span;
            break;

        case RAID_LEVEL_1:
        case RAID_LEVEL_10:
            break;

        case RAID_LEVEL_5:
        case RAID_LEVEL_50:
            div_factor = raid_info->num_drive_per_span - 1;
            capacity_blk = capacity_blk / div_factor;
            break;

        case RAID_LEVEL_6:
        case RAID_LEVEL_60:
            div_factor = raid_info->num_drive_per_span - 2;
            capacity_blk = capacity_blk / div_factor;
            break;

        // 实际不可能走这个分支
        default:
            retval = SML_ERR_CONFIG_INVALID_PARAM_RAID_LEVEL;
            break;
    }

    if (SML_SUCCESS == retval) {
        *o_pd_used_capcity_blk = capacity_blk;
    }

    return retval;
}

// 代码检视，拆分CreatLd
/*
 * Description: 判断指定的Array是否存在可用的空闲空间，找到空闲空间的索引，通过*FreeHoleIndex传回
 * History: 2017年1月7日  ()  新生成函数
 *          2017年1月14日  () 增加判断物理盘的block size
 *          2019年7月5日 函数名  IsFreeSpaceOnArray  -> FindFreeHoleIndex
 *          FreeHoleIndex为0xFF时查找可用的空洞，否则校验FreeHoleIndex是否合法
*/
static gint32 FindFreeHoleIndex(SL_ARRAY_INFO_T *pArrayInfo, SML_CREATE_LD_CTRL_INFO_S *pLdCtrlInfo,
    guint32 *FreeHoleIndex, guint16 block_size)
{
    guint32 i = 0;
    gint32 existing = FALSE;
    guint8 maxLdsPerArray = MAX_LDS_PER_ARRAY;
    guint32 inner_index = 0;

    if ((NULL == pArrayInfo) || (NULL == pLdCtrlInfo) || (NULL == FreeHoleIndex)) {
        return FALSE;
    }

    maxLdsPerArray = pLdCtrlInfo->max_lds_per_array;
    if ((maxLdsPerArray <= 0) || (maxLdsPerArray > MAX_LDS_PER_ARRAY)) {
        maxLdsPerArray = MAX_LDS_PER_ARRAY;
    }

    if (0 == block_size) {
        block_size = PD_BLOCK_SIZE_512;
    }

    if (pArrayInfo->freeCount != 0 && pArrayInfo->ldCount < maxLdsPerArray) {
        // 在Array上找到第一块空闲空间
        for (i = 0; i < pArrayInfo->freeCount; i++) {
            if (pArrayInfo->freeInfo[i].numBlocks >= MB2BLK(SML_LD_MIN_SIZE, block_size)) {
                // 如果用户未选择空闲块，默认选择第一块
                // 输入了且改块存在，返回TRUE
                if (*FreeHoleIndex == STORAGE_INFO_INVALID_BYTE || inner_index == *FreeHoleIndex) {
                    *FreeHoleIndex = i;
                    existing = TRUE;
                    break;
                }
                inner_index++;
            }
        }
    }

    return existing;
}

/*
 * Description: 从当前RAID配置数据获取指定id的逻辑盘的spandepth，并返回逻辑盘在配置数据中的索引
 * History: 2017年1月7日  ()  新生成函数
*/
static guint8 GetSpanDepthFromConfig(MR_CONFIG_DATA *pConfig, guint8 ld_target_id, guint8 *ld_idx)
{
    guint16 i = 0;
    guint8 span_depth = 0;
    MR_LD_CONFIG *pLdConfig = NULL;

    if ((NULL == pConfig) || (NULL == ld_idx)) {
        return 0;
    }

    *ld_idx = 0;
    pLdConfig = (MR_LD_CONFIG *)(pConfig->array + pConfig->arrayCount);

    // 查找匹配ld id的配置项，如果没有找到，span depth会返回0，表明异常
    for (i = 0; i < pConfig->logDrvCount; i++) {
        if (pLdConfig[i].properties.ldRef.targetId == ld_target_id) {
            span_depth = pLdConfig[i].params.spanDepth;
            *ld_idx = i;
            break;
        }
    }

    return span_depth;
}

/*
 * Description: 从当前RAID配置数据获取指定id的array信息并填充到MR_ARRAY数组
 * History: 2017年1月7日  ()  新生成函数
*/
static guint8 FillArrayDataFromConfig(MR_ARRAY *pArray, guint16 *pArrayRef, guint8 count, MR_CONFIG_DATA *pConfig)
{
    guint8 i = 0;
    volatile guint16 j = 0;
    guint8 span_cnt = 0;

    if ((NULL == pArray) || (NULL == pArrayRef) || (NULL == pConfig)) {
        return 0;
    }

    for (i = 0; i < count; i++) {
        for (j = 0; j < pConfig->arrayCount; j++) {
            if (pArrayRef[i] == pConfig->array[j].arrayRef) {
                memcpy_s(&pArray[i], sizeof(MR_ARRAY), &pConfig->array[j], sizeof(MR_ARRAY));
                span_cnt++;
                break;
            }
        }
    }

    return span_cnt;
}

/*
 * Description: 用上层传下来的参数填充逻辑盘设置的公共参数
 * History: 2017年1月7日  ()  新生成函数
*/
static void FillCommonParam(SL_CREATE_LD_COMMON_PARAM_S *pCommon, guint8 op_type, gpointer param)
{
    SML_CREATE_LD_ON_NEW_ARRAY_S *pLdNewArray = NULL;
    SML_CREATE_LD_ON_EXISTED_ARRAY_S *pLdExistedArray = NULL;
    SML_CREATE_CACHECADE_LD_S *pLdCacheCade = NULL;

    if ((NULL == pCommon) || (NULL == param)) {
        return;
    }

    pLdNewArray = (SML_CREATE_LD_ON_NEW_ARRAY_S *)param;
    pLdExistedArray = (SML_CREATE_LD_ON_EXISTED_ARRAY_S *)param;
    pLdCacheCade = (SML_CREATE_CACHECADE_LD_S *)param;

    (void)memset_s(pCommon, sizeof(SL_CREATE_LD_COMMON_PARAM_S), 0, sizeof(SL_CREATE_LD_COMMON_PARAM_S));

    pCommon->op_type = op_type;

    if (CONFIG_OPERATION_CREATE_LD_ON_NEW_ARRAY == op_type) {
        pCommon->raid_level = pLdNewArray->raid_level;
        /* * BEGIN: Added by lichangdi,  安全排查 20170808，strncpy_s 参数4不能大于等于参数2 */
        strncpy_s(pCommon->ld_name, sizeof(pCommon->ld_name), pLdNewArray->props.ld_name, sizeof(pCommon->ld_name) - 1);
        /* * END:   Added by lichangdi, 20170808 */
        pCommon->strip_size = pLdNewArray->props.strip_size;
        pCommon->read_policy = pLdNewArray->props.read_policy;
        pCommon->write_policy = pLdNewArray->props.write_policy;
        pCommon->io_policy = pLdNewArray->props.io_policy;
        pCommon->access_policy = pLdNewArray->props.access_policy;
        pCommon->disk_cache_policy = pLdNewArray->props.disk_cache_policy;
        pCommon->init_state = pLdNewArray->props.init_state;
    } else if (CONFIG_OPERATION_CREATE_LD_ON_EXISTED_ARRAY ==
        op_type) { /* * BEGIN: Added by lichangdi,  安全排查 20170808，strncpy_s 参数4不能大于等于参数2 */
        strncpy_s(pCommon->ld_name, sizeof(pCommon->ld_name), pLdExistedArray->props.ld_name,
            sizeof(pCommon->ld_name) - 1);
        /* * END:   Added by lichangdi, 20170808 */
        pCommon->strip_size = pLdExistedArray->props.strip_size;
        pCommon->read_policy = pLdExistedArray->props.read_policy;
        pCommon->write_policy = pLdExistedArray->props.write_policy;
        pCommon->io_policy = pLdExistedArray->props.io_policy;
        pCommon->access_policy = pLdExistedArray->props.access_policy;
        pCommon->disk_cache_policy = pLdExistedArray->props.disk_cache_policy;
        pCommon->init_state = pLdExistedArray->props.init_state;
    } else {
        pCommon->raid_level = pLdCacheCade->raid_level;
        /* * BEGIN: Added by lichangdi,  安全排查 20170808，strncpy_s 参数4不能大于等于参数2 */
        strncpy_s(pCommon->ld_name, sizeof(pCommon->ld_name), pLdCacheCade->ld_name, sizeof(pCommon->ld_name) - 1);
        /* * END:   Added by lichangdi, 20170808 */
        pCommon->write_policy = pLdCacheCade->write_policy;
    }
}

/*
 * Description: 设置array的空间大小
 * History: 2017年1月7日  ()  新生成函数
*/
static guint64 SetNewArrayCfgData(guint16 *pArrayRef, MR_ARRAY *pArray, guint16 count)
{
    guint16 i = 0;
    guint64 arraySize = 0, minArraySize = 0;

    if ((NULL == pArrayRef) || (NULL == pArray)) {
        return 0;
    }

    // 获取最小的arraySize
    for (i = 0; i < count; i++) {
        arraySize = pArray[i].size * pArray[i].numDrives;

        if (0 == i) {
            minArraySize = arraySize;
        } else if (minArraySize > arraySize) {
            minArraySize = arraySize;
        }
    }

    // 所有Span对应的Array设置为同样的空间大小，取最小Array的大小
    for (i = 0; i < count; i++) {
        if (0 != pArray[i].numDrives) {
            pArray[i].size = minArraySize / pArray[i].numDrives;
        }

        pArrayRef[i] = pArray[i].arrayRef;
    }

    return minArraySize;
}

/*
 * Description: 创建逻辑盘
 * History: 2016年11月11日  ()  新生成函数
*/
static gint32 CreateLd(guint32 ctrl_id, guint8 op_type, gpointer param)
{
    gint32 retval = SML_SUCCESS;

    SML_CREATE_LD_CTRL_INFO_S *pLdCtrlInfo = NULL;
    MR_MFC_DEFAULTS mfcDefaults, *pMfcDefaults = NULL;
    // pConfigData指向要创建的LD的配置信息，pCurrentConfig指向当前已存在的配置信息
    MR_CONFIG_DATA *pConfigData = NULL, *pCurrentConfig = NULL;
    guint32 configDataSize;

    guint16 maxArrays = 0, arrayCount = 0, logDrvCount = 0, sparesCount = 0;
    MR_ARRAY *tmpArray = NULL;

    guint8 numDrives = 1, spanDepth = 1;
    guint64 startBlock = 0;
    guint64 totalFreeBlocks = 0, usableNumBlocks = 0;

    volatile guint32 i = 0;

    guint32 ld_capacity_mb = 0;
    guint64 capacity_blk = 0, pd_used_capacity_blk = 0;

    guint16 arrayRef[MAX_SPAN_DEPTH] = { 0 };
    /* Brief: 2018-12-29  UK整改 CodeDEX3_C UADP120836 */
    guint8 freeTargetIds[SML_MAX_NUM_OF_IDS] = { 0 }; // 此处初始值无意义
    guint16 next_id = 0XFFFF;
    MR_LD_CONFIG *pld = NULL, *ldAddr = NULL;

    guint16 array_index = 0;
    SL_ARRAY_INFO_T arrayInfo;
    guint32 FreeHoleIndex = 0;
    gint32 existing = 0;
    guint8 firstLdIdx = 0, span_cnt = 0;
    MR_LD_CONFIG *pLdConfig = NULL;

    SL_CREATE_LD_COMMON_PARAM_S common_param;

    SML_CREATE_LD_RETURN_PARAM_S *pRetParam = NULL;
    SLT_RAID_LEVEL_INFO_S rl_info;

    guint16 block_size = PD_BLOCK_SIZE_512;

    if (((NULL == param) || (op_type > CONFIG_OPERATION_CREATE_CACHECADE_LD))) {
        retval = SML_ERR_NULL_DATA;
        debug_log(DLOG_ERROR, "smlib LSI: CreateLd -> param is NULL, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        return retval;
    }

    SML_CREATE_LD_ON_NEW_ARRAY_S *pLdNewArray = (SML_CREATE_LD_ON_NEW_ARRAY_S *)param;
    SML_CREATE_LD_ON_EXISTED_ARRAY_S *pLdExistedArray = (SML_CREATE_LD_ON_EXISTED_ARRAY_S *)param;
    SML_CREATE_CACHECADE_LD_S *pLdCacheCade = (SML_CREATE_CACHECADE_LD_S *)param;

    // 获取返回参数的指针
    if (CONFIG_OPERATION_CREATE_LD_ON_NEW_ARRAY == op_type) {
        pRetParam = &pLdNewArray->ret_param;
        pLdCtrlInfo = &pLdNewArray->ctrl_info;

        block_size =
            (0 != pLdNewArray->pd_infos[0].block_size) ? pLdNewArray->pd_infos[0].block_size : PD_BLOCK_SIZE_512;
    } else if (CONFIG_OPERATION_CREATE_LD_ON_EXISTED_ARRAY == op_type) {
        pRetParam = &pLdExistedArray->ret_param;
        pLdCtrlInfo = &pLdExistedArray->ctrl_info;
        FreeHoleIndex = pLdExistedArray->block_index;
        block_size = (0 != pLdExistedArray->pd_block_size) ? pLdExistedArray->pd_block_size : PD_BLOCK_SIZE_512;
    } else {
        pRetParam = &pLdCacheCade->ret_param;
        pLdCtrlInfo = &pLdCacheCade->ctrl_info;

        block_size =
            (0 != pLdCacheCade->pd_infos[0].block_size) ? pLdCacheCade->pd_infos[0].block_size : PD_BLOCK_SIZE_512;
    }

    (void)memset_s(&arrayInfo, sizeof(SL_ARRAY_INFO_T), 0, sizeof(SL_ARRAY_INFO_T));

    // 获取控制器的MFC默认值，用于后面设置默认条带大小和默认Cache策略
    pMfcDefaults = &mfcDefaults;
    (void)memset_s(&mfcDefaults, sizeof(MR_MFC_DEFAULTS), 0, sizeof(MR_MFC_DEFAULTS));
    retval = GetCtrlMFCDefault(ctrl_id, &mfcDefaults);
    if (SML_SUCCESS == retval) {
        pMfcDefaults = &mfcDefaults;
    }

    // 获取当前已存在的RAID配置信息
    retval = ReadConfig(ctrl_id, &pCurrentConfig);
    if (SML_SUCCESS != retval) {
        debug_log(DLOG_ERROR, "smlib LSI: CreateLd -> ReadConfig failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        goto free_and_return;
    }

    if ((CONFIG_OPERATION_CREATE_LD_ON_NEW_ARRAY == op_type) || (CONFIG_OPERATION_CREATE_CACHECADE_LD == op_type)) {
        // 判断span_depth参数，要创建的Array个数与span个数相等,cachecade ld不支持多个span
        maxArrays = MAX_ARRAYS - pCurrentConfig->arrayCount;
        arrayCount = (CONFIG_OPERATION_CREATE_LD_ON_NEW_ARRAY == op_type) ? pLdNewArray->span_depth : 1;

        if ((arrayCount < 1) || (arrayCount > MAX_SPAN_DEPTH)) {
            retval = SML_ERR_CONFIG_INVALID_PARAM_SPAN_DEPTH;
        }

        if (maxArrays < arrayCount) {
            retval = SML_ERR_CONFIG_ARRAY_NUM_REACHED_LIMIT;
        }

        if (SML_SUCCESS != retval) {
            debug_log(DLOG_ERROR,
                "smlib LSI: CreateLd(NEW) -> invalid array count setting, arrayCount = %d, maxArrays = %d, return "
                "0x%0x\n",
                arrayCount, maxArrays, retval);
            goto free_and_return;
        }

        // 判断num_drive_per_span参数
        numDrives = (CONFIG_OPERATION_CREATE_LD_ON_NEW_ARRAY == op_type) ? pLdNewArray->num_drive_per_span :
                                                                           pLdCacheCade->pd_count;

        if ((numDrives < 1) || (numDrives > MAX_ROW_SIZE)) {
            retval = SML_ERR_CONFIG_INVALID_PARAM_NUM_DRIVE_PER_SPAN;
            debug_log(DLOG_ERROR,
                "smlib LSI: CreateLd(NEW) -> invalid number drives per span setting, num_drive_per_span = %d, return "
                "0x%0x\n",
                numDrives, retval);
            goto free_and_return;
        }

        // allocate memory for arrayCount arrays
        tmpArray = (MR_ARRAY *)g_malloc0(arrayCount * sizeof(MR_ARRAY));
        if (NULL == tmpArray) {
            retval = SML_ERR_CANNOT_ALLOC_MEM;
            debug_log(DLOG_ERROR, "smlib LSI: CreateLd(NEW) -> malloc for tmpArray failed, CtrlId = %d, return 0x%0x\n",
                SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
            goto free_and_return;
        }

        tmpArray[0].arrayRef = pCurrentConfig->arrayCount;
        tmpArray[0].numDrives = numDrives;

        if (CONFIG_OPERATION_CREATE_LD_ON_NEW_ARRAY == op_type) {
            retval = CheckPDsSuitableForNewLD(ctrl_id, tmpArray, arrayCount, pLdNewArray->pd_sel, pLdNewArray->pd_infos,
                pLdCtrlInfo, 0);
        } else {
            retval = CheckPDsSuitableForNewLD(ctrl_id, tmpArray, arrayCount, pLdCacheCade->pd_sel,
                pLdCacheCade->pd_infos, pLdCtrlInfo, 1);
        }

        if (SML_SUCCESS != retval) {
            debug_log(DLOG_ERROR, "smlib LSI: CreateLd(NEW) -> PD list is not suitable for new LD, return 0x%0x\n",
                retval);
            goto free_and_return;
        }

        spanDepth = arrayCount;

        for (i = 0; i < arrayCount; i++) {
            arrayRef[i] = tmpArray[i].arrayRef;
        }

        // 获取所有span的容量大小 = spanDepth * 所有span中最小容量的Array
        // 获取Array中最小容量的物理盘. 我们认为所有Array中含有相同的物理盘个数
        guint64 minArraySize = SetNewArrayCfgData(arrayRef, tmpArray, arrayCount);

        totalFreeBlocks = spanDepth * minArraySize;
        usableNumBlocks = minArraySize / numDrives;
        startBlock = 0; // for new arrays
    } else {
        // 检查指定的Array是否有效
        if (!IsArrayValid(pCurrentConfig, pLdExistedArray->array_ref, &array_index)) {
            retval = SML_ERR_CONFIG_INVALID_PARAM_ARRAY_REF;
            debug_log(DLOG_ERROR, "smlib LSI: CreateLd(EXISTED) -> Invalid Array ref %d, return 0x%0x\n",
                pLdExistedArray->array_ref, retval);
            goto free_and_return;
        }

        // 读取Array信息
        retval = GetArrayInfo(ctrl_id, pLdExistedArray->array_ref, &arrayInfo);
        if (SML_SUCCESS != retval) {
            debug_log(DLOG_ERROR,
                "smlib LSI: CreateLd(EXISTED) -> Get Array info failed, Array ref = %d, return 0x%0x\n",
                pLdExistedArray->array_ref, retval);
            goto free_and_return;
        }

        // 检测指定的Array上是否有可以创建LD的空间
        existing = FindFreeHoleIndex(&arrayInfo, pLdCtrlInfo, &FreeHoleIndex, block_size);
        if (!existing) {
            retval = SML_ERR_CONFIG_ARRAY_NO_AVAILABLE_SPACE;
            debug_log(DLOG_ERROR,
                "smlib LSI: CreateLd(EXISTED) -> No available space on array for new ld , Array ref = %d, "
                "FreeHoleIndex = %u, return 0x%0x\n",
                pLdExistedArray->array_ref, FreeHoleIndex, retval);
            goto free_and_return;
        }

        // 找出在这个Array上已经创建的第一个LD
        spanDepth = GetSpanDepthFromConfig(pCurrentConfig, arrayInfo.ldInfo[0].targetId, &firstLdIdx);
        pLdConfig = (MR_LD_CONFIG *)(pCurrentConfig->array + pCurrentConfig->arrayCount);

        arrayCount = spanDepth;
        if ((arrayCount < 1) || (arrayCount > MAX_SPAN_DEPTH)) {
            retval = SML_ERR_CONFIG_INVALID_PARAM_SPAN_DEPTH;
            debug_log(DLOG_ERROR,
                "smlib LSI: CreateLd(EXISTED) -> malloc for spanDepth failed, CtrlId = %d, return 0x%0x\n",
                SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
            goto free_and_return;
        }

        // 查找出关联第一个LD的所有Array，这也是新添加ld依赖的array
        for (i = 0; i < spanDepth; i++) {
            arrayRef[i] = pLdConfig[firstLdIdx].span[i].arrayRef;
        }

        // 获取必要的信息，后面需要这些信息来填充新建LD的span设置参数
        usableNumBlocks = arrayInfo.freeInfo[FreeHoleIndex].numBlocks;
        startBlock = arrayInfo.freeInfo[FreeHoleIndex].startBlock;
        numDrives = arrayInfo.array.numDrives;
        totalFreeBlocks = usableNumBlocks * numDrives;
        debug_log(DLOG_DEBUG,
            "smlib LSI: CreateLd(EXISTED) -> Avialable space for Ld: totalFreeBlocks: %" G_GUINT64_FORMAT
            ", usableNumBlocks: %" G_GUINT64_FORMAT "\n",
            totalFreeBlocks, usableNumBlocks);

        // 申请空间用于存储创建LD用到的Array信息
        tmpArray = (MR_ARRAY *)g_malloc0(arrayCount * sizeof(MR_ARRAY));
        if (NULL == tmpArray) {
            retval = SML_ERR_CANNOT_ALLOC_MEM;
            debug_log(DLOG_ERROR,
                "smlib LSI: CreateLd(EXISTED) -> malloc for tmpArray failed, CtrlId = %d, return 0x%0x\n",
                SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
            goto free_and_return;
        }

        // 根据每个span的array ref
        // 找到当前配置中的MR_ARRAY配置数据，将它拷贝到tmpArray，作为新建LD的Array配置数据
        // 新的LD继承了原先的Array配置数据
        span_cnt = FillArrayDataFromConfig(tmpArray, arrayRef, spanDepth, pCurrentConfig);
        if (span_cnt != spanDepth) {
            retval = SML_ERR_CONFIG_ARRAY_INCORRECT_DATA_SIZE;
            debug_log(DLOG_ERROR,
                "smlib LSI: CreateLd(EXISTED) -> Array data size incorrect, CtrlId = %d, return 0x%0x\n",
                SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
            goto free_and_return;
        }
    }

    debug_log(DLOG_DEBUG,
        "smlib LSI: CreateLd -> TotalFreeBlocks: %" G_GUINT64_FORMAT ", usableNumBlocks: %" G_GUINT64_FORMAT "\n",
        totalFreeBlocks, usableNumBlocks);

    // 准备RAID级别等参数，用来计算需要使用的单个物理盘空间
    (void)memset_s(&rl_info, sizeof(SLT_RAID_LEVEL_INFO_S), 0, sizeof(SLT_RAID_LEVEL_INFO_S));

    if (CONFIG_OPERATION_CREATE_LD_ON_NEW_ARRAY == op_type) {
        ld_capacity_mb = pLdNewArray->props.capacity;
        rl_info.raid_level = pLdNewArray->raid_level;
        rl_info.span_depth = spanDepth;
        rl_info.num_drive_per_span = numDrives;
    } else if (CONFIG_OPERATION_CREATE_LD_ON_EXISTED_ARRAY == op_type) {
        ld_capacity_mb = pLdExistedArray->props.capacity;
        rl_info.raid_level = arrayInfo.ldInfo[0].PRL;

        if (spanDepth > 1) {
            rl_info.raid_level = rl_info.raid_level * 10;
        }

        rl_info.span_depth = spanDepth;
        rl_info.num_drive_per_span = numDrives;
    }

    // 根据指定的逻辑盘空间及RAID级别，计算单个物理盘需要占用的空间
    if ((0xFFFFFFFF == ld_capacity_mb) || (CONFIG_OPERATION_CREATE_CACHECADE_LD == op_type)) {
        pd_used_capacity_blk = 0xFFFFFFFF;
    } else {
        retval = CvtCapacityLD2PD(ld_capacity_mb, &rl_info, pLdCtrlInfo, &pd_used_capacity_blk, block_size);
        if (SML_SUCCESS != retval) {
            debug_log(DLOG_ERROR,
                "smlib LSI: CreateLd -> Invalid RAID level specified, RAID level = %d, span depth = %d, num drive per "
                "span = %d, return 0x%0x\n",
                rl_info.raid_level, rl_info.span_depth, rl_info.num_drive_per_span, retval);
            goto free_and_return;
        }
    }

    // 根据可用空间和指定需要占用的空间来检查是否满足创建逻辑盘的容量需求
    retval = CheckCapacityForNewLD(usableNumBlocks, pd_used_capacity_blk, op_type, &capacity_blk, block_size);
    // 如果容量参数设置错误，则返回相应的错误码
    if (SML_SUCCESS != retval) {
        debug_log(DLOG_ERROR,
            "smlib LSI: CreateLd -> Invalid capacity specified, usableNumBlocks = %" G_GUINT64_FORMAT
            " blocks, capacity used per pd = %" G_GUINT64_FORMAT "blk, return 0x%0x\n",
            usableNumBlocks, pd_used_capacity_blk, retval);
        goto free_and_return;
    }

    usableNumBlocks = capacity_blk;

    // 代码检视，增加注释说明logDrvCount为什么设置为1
    logDrvCount = 1; // 现有的需求不支持一次创建多个逻辑盘，这里设置为1，表示要创建1个逻辑盘
    sparesCount = 0;

    // 代码检视，乘数强制转化为guint32类型，避免中间结果溢出
    // 计算MR_CONFIG_DATA结构体实际需要申请空间的大小
    configDataSize = offsetof(MR_CONFIG_DATA, array) + (guint32)arrayCount * pCurrentConfig->arraySize +
        (guint32)logDrvCount * pCurrentConfig->logDrvSize + (guint32)sparesCount * pCurrentConfig->sparesSize;

    // 申请MR_CONFIG_DATA空间
    pConfigData = (MR_CONFIG_DATA *)g_malloc0(configDataSize);
    if (NULL == pConfigData) {
        retval = SML_ERR_CANNOT_ALLOC_MEM;
        debug_log(DLOG_ERROR, "smlib LSI: CreateLd -> malloc for pConfigData failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        goto free_and_return;
    }

    pConfigData->arrayCount = (guint16)arrayCount;
    pConfigData->arraySize = pCurrentConfig->arraySize;
    pConfigData->logDrvCount = (guint16)logDrvCount;
    pConfigData->logDrvSize = pCurrentConfig->logDrvSize;
    pConfigData->sparesCount = (guint16)sparesCount;
    pConfigData->sparesSize = pCurrentConfig->sparesSize;
    pConfigData->size = configDataSize;

    // 填充MR_CONFIG_DATA中的MR_ARRRAY结构体数据
    memcpy_s(pConfigData->array, sizeof(MR_ARRAY) * arrayCount, tmpArray, sizeof(MR_ARRAY) * arrayCount);

    // 为MR_LD_CONFIG数据结构申请空间
    pld = (MR_LD_CONFIG *)g_malloc0(logDrvCount * sizeof(MR_LD_CONFIG));
    if (NULL == pld) {
        retval = SML_ERR_CANNOT_ALLOC_MEM;
        debug_log(DLOG_ERROR, "smlib LSI: CreateLd -> malloc for pld failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        goto free_and_return;
    }

    // 查找可用的逻辑盘ID
    FindFreeTargetIDs(pCurrentConfig, freeTargetIds);

    if (0 == pLdCtrlInfo->max_lds) {
        pLdCtrlInfo->max_lds = 255;
        debug_log(DLOG_ERROR, "smlib LSI: CreateLd -> maxLDs is 0, this should not happen, set to default value 255\n");
    }
    retval = GenerateNextId(ctrl_id, freeTargetIds, pLdCtrlInfo, &next_id);
    if ((SML_SUCCESS != retval) || (next_id >= pLdCtrlInfo->max_lds)) {
        if (next_id >= pLdCtrlInfo->max_lds) {
            retval = SML_ERR_CONFIG_TARGET_LD_ID_EXHAUSTED;
        }

        debug_log(DLOG_ERROR, "smlib LSI: CreateLd -> Target IDs exhausted, maxLDs = %d, return 0x%0x\n",
            pLdCtrlInfo->max_lds, retval);
        goto free_and_return;
    }

    pld->properties.ldRef.targetId = (guint8)next_id;

    // 完成逻辑盘参数的所有设置
    FillCommonParam(&common_param, op_type, param);
    if (CONFIG_OPERATION_CREATE_LD_ON_EXISTED_ARRAY == op_type) {
        // 使用已存RAID级别为下一个创建的LD的RAID级别
        // 同一个Array上的所有LD有相同的基本RAID级别
        pld->params.PRL = arrayInfo.ldInfo[0].PRL;
    }

    common_param.start_block = startBlock;
    common_param.num_blocks = usableNumBlocks;
    common_param.span_depth = spanDepth;
    common_param.num_drives = numDrives;

    if (SL_SUCCESS !=
        (retval = SetLdPropertiesForCreation(ctrl_id, pld, &common_param, arrayRef, pLdCtrlInfo, pMfcDefaults))) {
        debug_log(DLOG_ERROR, "smlib LSI: CreateLd -> Fill MR_LD_CONFIG failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        goto free_and_return;
    }

    ldAddr = (MR_LD_CONFIG *)(pConfigData->array + pConfigData->arrayCount);
    memcpy_s(ldAddr, logDrvCount * sizeof(MR_LD_CONFIG), pld, logDrvCount * sizeof(MR_LD_CONFIG));

    // 执行最终的创建命令
    if ((retval = AddConfig(ctrl_id, pConfigData, configDataSize, next_id)) != SL_SUCCESS) {
        debug_log(DLOG_ERROR, "smlib LSI: CreateLd -> Add Config failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
    } else {
        debug_log(DLOG_DEBUG, "smlib LSI: CreateLd -> Add Config successfully, CtrlId = %d, LdId = %d\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), next_id);

        // 设置返回参数，只有创建完全成功，返回的ID才有意义
        pRetParam->ld_target_id = next_id; // 不要使用pConfigData->ld->properties.ldRef.targetId赋值，LSI的Add
                                                   // Config指令会修改传入的参数
        (void)memset_s(pRetParam->array_refs, SML_MAX_SPAN_DEPTH * sizeof(guint16), 0xff,
            SML_MAX_SPAN_DEPTH * sizeof(guint16));
        pRetParam->array_count = pConfigData->arrayCount;

        for (i = 0; i < pRetParam->array_count; i++) {
            pRetParam->array_refs[i] = pConfigData->array[i].arrayRef;
        }
    }

free_and_return:
    // 释放申请的内存，返回错误码
    if (NULL != tmpArray) {
        g_free(tmpArray);
    }
    if (NULL != pld) {
        g_free(pld);
    }
    if (NULL != pCurrentConfig) {
        g_free(pCurrentConfig);
    }
    if (NULL != pConfigData) {
        g_free(pConfigData);
    }

    return retval;
}

/*
 * Description: 设置指定的逻辑盘为启动盘
 * History: 2016年11月8日  ()  新生成函数
*/
static gint32 SetLDBootable(guint32 ctrl_id, guint8 target_id)
{
    gint32 retval = SML_SUCCESS;
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;
    SL_DCMD_INPUT_T dcmdInput;
    MR_BIOS_DATA biosData;
    MR_LD_INFO ldInfo;

    // 获取BIOS DATA
    (void)memset_s(&biosData, sizeof(MR_BIOS_DATA), 0, sizeof(MR_BIOS_DATA));
    (void)memset_s(&ldInfo, sizeof(MR_LD_INFO), 0, sizeof(MR_LD_INFO));
    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);
    (void)memset_s(&dcmdInput, SL_DCMD_INPUT_S, 0, SL_DCMD_INPUT_S);

    retval = GetBIOSData(ctrl_id, &biosData);
    if (SL_SUCCESS != retval) {
        debug_log(DLOG_ERROR, "smlib: LSI:SetLDBootable -> MR_DCMD_CTRL_BIOS_DATA_GET cmd failed, return 0x%0x\n",
            retval);
        return retval;
    }

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    // 通过读取LD信息的方式来检查输入的Target id是否合法
    retval = GetLDInfo(ctrl_id, target_id, &ldInfo);
    if (SL_SUCCESS != retval) {
        debug_log(DLOG_ERROR, "smlib: LSI:SetLDBootable -> Get LD info failed, target id = %d, return 0x%0x\n",
            target_id, retval);
        return retval;
    }

    // 检查指定的LD是否应设置为启动盘，如果没有设置则执行设置操作
    if (biosData.bootTargetId != target_id) {
        biosData.bootTargetId = target_id;
        biosData.bootDeviceIsPD = 0;

        dcmdInput.dataTransferLength = (guint32)sizeof(MR_BIOS_DATA);
        dcmdInput.opCode = MR_DCMD_CTRL_BIOS_DATA_SET;
        dcmdInput.flags = SL_DIR_WRITE;
        dcmdInput.pData = &biosData;

        libCmdParam.cmdType = SL_PASSTHRU_CMD_TYPE;
        libCmdParam.cmd = SL_DCMD_PASSTHRU;
        libCmdParam.ctrlId = ctrl_id;
        libCmdParam.dataSize = SL_DCMD_INPUT_S;
        libCmdParam.pData = &dcmdInput;

        retval = ProcessLibCommandCall(libType, &libCmdParam);
    } else {
        debug_log(DLOG_ERROR, "smlib: LSI:SetLDBootable -> Logical drive %d is already set as boot drive\n", target_id);
        return retval;
    }

    if (SML_SUCCESS != retval) {
        debug_log(DLOG_ERROR, "smlib: LSI:SetLDBootable -> Set LD as boot drive failed, target id = %d, return 0x%0x\n",
            target_id, retval);
    }

    return retval;
}

/*
 * Description: 开始指定逻辑盘FGI
 * History: 2017/11/21 AR.SR.SFEA02109379.004.006  支持逻辑盘初始化
*/
static gint32 StartLDFGI(guint32 ctrl_id, guint8 target_id, guint8 init_type)
{
    gint32 retval = SML_SUCCESS;
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;
    MR_LD_INFO ldInfo;

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    (void)memset_s(&ldInfo, sizeof(MR_LD_INFO), 0, sizeof(MR_LD_INFO));
    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);

    // 校验传入的init_type是否合法
    if (init_type < LD_INIT_STATE_QUICK_INIT || init_type > LD_INIT_STATE_FULL_INIT) {
        debug_log(DLOG_ERROR, "smlib: LSI:StartLDFGI -> invalid init type is %d, target id = %d\n", init_type,
            target_id);
        return SML_ERR_DATA_INVALID;
    }

    // 通过读取LD信息，判断是否支持指定的初始化操作
    retval = GetLDInfo(ctrl_id, target_id, &ldInfo);
    if (SL_SUCCESS != retval) {
        debug_log(DLOG_ERROR, "smlib: LSI:StartLDFGI -> Get LD info failed, target id = %d, return 0x%0x\n", target_id,
            retval);
        return retval;
    }

    // 不支持FGI或者不支持full fgi返回不支持消息
    // startFGI fullFGDisallow             Meaning
    // ---------------------------------------------------
    // 0       -           No foreground Init operation allowed
    // 1       1           Only Fast Init allowed
    // 1       0           Both fast and full foreground init allowed
    if (0 == ldInfo.allowedOps.startFGI ||
        (ldInfo.allowedOps.fullFGDisallow == 1 && LD_INIT_STATE_FULL_INIT == init_type)) {
        debug_log(DLOG_ERROR,
            "smlib: LSI:StartLDFGI -> not support start FGI, startFGI = %d, fullFGDisallow = %d, target id = %d\n",
            ldInfo.allowedOps.startFGI, ldInfo.allowedOps.fullFGDisallow, target_id);
        return SML_ERR_LD_OPERATION_NOT_SUPPORT;
    }

    libCmdParam.cmdType = SL_LD_CMD_TYPE;
    libCmdParam.cmd = SL_START_INITIALIZATION;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.ldRef.targetId = target_id;
    libCmdParam.ldRef.seqNum = ldInfo.ldConfig.properties.ldRef.seqNum;
    libCmdParam.cmdParam_1b[0] = init_type - 1; // 减一是因为复用的创建接口的值

    retval = ProcessLibCommandCall(libType, &libCmdParam);
    if (SML_SUCCESS != retval) {
        debug_log(DLOG_ERROR, "smlib: LSI:StartLDFGI -> start FGI failed, target id = %d, return 0x%0x\n", target_id,
            retval);
    }

    return retval;
}

/*
 * Description: 取消指定逻辑盘FGI
 * History: 2017/11/21 AR.SR.SFEA02109379.004.006  支持逻辑盘初始化
*/
static gint32 CancelLDFGI(guint32 ctrl_id, guint8 target_id)
{
    gint32 retval = SML_SUCCESS;
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;
    MR_LD_INFO ldInfo;

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    (void)memset_s(&ldInfo, sizeof(MR_LD_INFO), 0, sizeof(MR_LD_INFO));
    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);

    // 通过读取LD信息，判断是否支持指定的初始化操作
    retval = GetLDInfo(ctrl_id, target_id, &ldInfo);
    if (SL_SUCCESS != retval) {
        debug_log(DLOG_ERROR, "smlib: LSI:CancelLDFGI -> Get LD info failed, target id = %d, return 0x%0x\n", target_id,
            retval);
        return retval;
    }

    // 不支持stop FGI返回不支持错误
    if (0 == ldInfo.allowedOps.stopFGI) {
        debug_log(DLOG_ERROR, "smlib: LSI:CancelLDFGI -> not support cancel FGI, target id = %d\n", target_id);
        return SML_ERR_LD_OPERATION_NOT_SUPPORT;
    }

    libCmdParam.cmdType = SL_LD_CMD_TYPE;
    libCmdParam.cmd = SL_CANCEL_INITIALIZATION;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.ldRef.targetId = target_id;
    // 该命令的注释中没有seqNum，但是源码中有使用
    libCmdParam.ldRef.seqNum = ldInfo.ldConfig.properties.ldRef.seqNum;

    retval = ProcessLibCommandCall(libType, &libCmdParam);
    if (SML_SUCCESS != retval) {
        debug_log(DLOG_ERROR, "smlib: LSI:CancelLDFGI -> Cancel FGI failed, target id = %d, return 0x%0x\n", target_id,
            retval);
    }

    return retval;
}

/*
 * Description: 向控制器发送设置逻辑盘属性的命令
 * History: 2016年11月9日  () 新生成函数
*/
static gint32 SetLDPropertiesCmd(guint32 ctrl_id, guint8 target_id, guint16 seq_num, MR_LD_PROPERTIES *pProp)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;

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

    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    libCmdParam.cmdType = SL_LD_CMD_TYPE;
    libCmdParam.cmd = SL_SET_LD_PROPERTIES;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.ldRef.targetId = target_id;
    libCmdParam.ldRef.seqNum = seq_num;
    libCmdParam.dataSize = sizeof(MR_LD_PROPERTIES);
    libCmdParam.pData = pProp;

    return ProcessLibCommandCall(libType, &libCmdParam);
}

/*
 * Description: 设置指定逻辑盘的属性值
 * History: 2016年11月9日  () 新生成函数
 *          2017年11月28日  ()
 *          取消对使用SSD创建的逻辑盘的Disk Cache Policy修改限定，与带内工具保持一致
*/
static gint32 SetLDProperties(guint32 ctrl_id, guint8 target_id, SML_LD_SET_PROPERTIES_S *prop)
{
    gint32 retval = SML_SUCCESS;
    MR_LD_PROPERTIES ldProp;
    MR_LD_INFO ldInfo;
    guint8 isSSCD = 0;
    guint8 libType = 0;
    guint8 read_policy, write_policy, io_policy;
    guint16 seq_num = 0;

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

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    // 读取逻辑盘信息
    (void)memset_s(&ldInfo, sizeof(MR_LD_INFO), 0, sizeof(MR_LD_INFO));
    retval = GetLDInfo(ctrl_id, target_id, &ldInfo);
    if (SML_SUCCESS != retval) {
        debug_log(DLOG_ERROR,
            "smlib: LSI:SetLDProperties -> Get LD info failed, ctrl_id = %d, target id = %d, return 0x%0x\n", ctrl_id,
            target_id, retval);
        return retval;
    }

    isSSCD = ldInfo.ldConfig.params.isSSCD;
    seq_num = ldInfo.ldConfig.properties.ldRef.seqNum;

    // 判断是否能够修改逻辑盘的这个属性
    // 当前条件下不提供这个属性的修改
    if ((prop->setting_options & (LD_PROP_SETTING_READ_POLICY | LD_PROP_SETTING_IO_POLICY |
        LD_PROP_SETTING_ACCESS_POLICY | LD_PROP_SETTING_BGI_ENABLE)) &&
        ((SL_LIB_TYPE_STORELIB != libType) || isSSCD)) {
        retval = SML_ERR_LD_PROPERTY_SET_NOT_ALLOWED;
        debug_log(DLOG_ERROR,
            "smlib: LSI:SetLDProperties -> Property set operation not allowed, ctrl_id = %d, target id = %d, return "
            "0x%0x\n",
            ctrl_id, target_id, retval);
        return retval;
    }

    // 当前条件下不提供这个属性的修改
    if ((prop->setting_options & LD_PROP_SETTING_WRITE_POLICY) && (SL_LIB_TYPE_STORELIB != libType)) {
        retval = SML_ERR_LD_PROPERTY_SET_NOT_ALLOWED;
        debug_log(DLOG_ERROR,
            "smlib: LSI:SetLDProperties -> Property set operation not allowed, ctrl_id = %d, target id = %d, return "
            "0x%0x\n",
            ctrl_id, target_id, retval);
        return retval;
    }

    // 拷贝已有的逻辑盘属性到要设置的变量中，作为设置的基础，不设置的属性保持不变
    memcpy_s(&ldProp, sizeof(MR_LD_PROPERTIES), &ldInfo.ldConfig.properties, sizeof(MR_LD_PROPERTIES));

    // 设置逻辑盘名称
    if (prop->setting_options & LD_PROP_SETTING_NAME) {
        memcpy_s(ldProp.name, SL_LD_NAME_LENGTH, prop->ld_name, SL_LD_NAME_LENGTH);
    }

    // 设置cache policy(Read/Write/IO policy)
    read_policy = (prop->setting_options & LD_PROP_SETTING_READ_POLICY) ? prop->read_policy :
                                                                          GetReadCachePolicy(ldProp.defaultCachePolicy);
    write_policy = (prop->setting_options & LD_PROP_SETTING_WRITE_POLICY) ?
        prop->write_policy :
        GetWriteCachePolicy(ldProp.defaultCachePolicy);
    io_policy = (prop->setting_options & LD_PROP_SETTING_IO_POLICY) ? prop->io_policy :
                                                                      GetCachePolicy(ldProp.defaultCachePolicy);

    if (SL_LIB_TYPE_STORELIB == libType) {
        if (!isSSCD) {
            ldProp.defaultCachePolicy = SetCachePolicy(NULL, read_policy, write_policy, io_policy);
        } else {
            if (prop->setting_options & LD_PROP_SETTING_WRITE_POLICY) {
                // CacheCade不支持LD_CACHE_WRITE_CACHE_IF_BAD_BBU选项设置
                // 当前条件下不提供这个属性的修改
                if (prop->write_policy > LD_CACHE_WRITE_BACK) {
                    retval = SML_ERR_LD_PROPERTY_SET_NOT_ALLOWED;
                    debug_log(DLOG_ERROR,
                        "smlib: LSI:SetLDProperties -> LD_CACHE_WRITE_CACHE_IF_BAD_BBU not allowed for CacheCade LD, "
                        "ctrl_id = %d, target id = %d, return 0x%0x\n",
                        ctrl_id, target_id, retval);
                    return retval;
                }

                SetWritePolicy(&ldProp.defaultCachePolicy, write_policy);
            }
        }
    }

    // 设置Access policy
    if ((SL_LIB_TYPE_STORELIB == libType) && (!isSSCD) && (prop->setting_options & LD_PROP_SETTING_ACCESS_POLICY) &&
        (prop->access_policy <= LD_ACCESS_BLOCKED)) {
        ldProp.accessPolicy = SetAccessPolicy(prop->access_policy);
    }

    // 设置disk cache policy
    if (((prop->setting_options & LD_PROP_SETTING_DISK_CACHE_POLICY) &&
        (prop->disk_cache_policy <= MR_PD_CACHE_DISABLE))) {
        ldProp.diskCachePolicy = prop->disk_cache_policy;
    }

    // 设置BGI使能
    if ((SL_LIB_TYPE_STORELIB == libType) && (!isSSCD) && (prop->setting_options & LD_PROP_SETTING_BGI_ENABLE)) {
        ldProp.noBGI = (prop->bgi_enable) ? 0 : 1;
    }

    // 执行修改LD属性的命令
    retval = SetLDPropertiesCmd(ctrl_id, target_id, seq_num, &ldProp);
    if ((retval != SML_SUCCESS && retval != SML_ERR_REBOOT_REQUIRED)) {
        debug_log(DLOG_ERROR,
            "smlib: LSI:SetLDProperties -> Ctrl_id[%d], ld[%d], Set properties failed, return = 0x%0x\n", ctrl_id,
            target_id, retval);
    }

    return retval;
}

/*
 * Description: 向控制器发送命令设置SSCD关联的普通LD列表
 * History: 2016年11月17日  () 新生成函数
*/
static gint32 SetLDListOfSSCDCmd(guint32 ctrl_id, guint8 sscd_id, guint32 buf_len, MR_LD_TARGETID_LIST *pLdListBuf)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;
    SL_DCMD_INPUT_T dcmdInput;

    if (pLdListBuf == NULL) {
        return SML_ERR_NULL_DATA;
    }
    if (sizeof(MR_LD_TARGETID_LIST) > buf_len) {
        return SML_ERR_NULL_DATA;
    }

    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);
    (void)memset_s(&dcmdInput, SL_DCMD_INPUT_S, 0, SL_DCMD_INPUT_S);

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    libCmdParam.cmdType = SL_PASSTHRU_CMD_TYPE;
    libCmdParam.cmd = SL_DCMD_PASSTHRU;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = SL_DCMD_INPUT_S;
    libCmdParam.pData = &dcmdInput;

    dcmdInput.opCode = MR_DCMD_LD_SSCD_SET_LDS;
    dcmdInput.dataTransferLength = buf_len;
    dcmdInput.flags = SL_DIR_WRITE;
    dcmdInput.pData = pLdListBuf;
    // 代码检视，增加注释说明为什么设置w[0]
    dcmdInput.mbox.w[0] =
        sscd_id; // MR_DCMD_LD_SSCD_SET_LDS命令的附加参数第一个word(4 bytes)值为cachecade逻辑盘的id

    return ProcessLibCommandCall(libType, &libCmdParam);
}

/*
 * Description: 向控制器发送命令读取SSCD关联的普通LD列表
 * History: 2016年11月17日  () 新生成函数
*/
static gint32 GetLDListOfSSCDCmd(guint32 ctrl_id, guint8 sscd_id, guint32 buf_len, MR_LD_TARGETID_LIST *pLdListBuf)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;
    SL_DCMD_INPUT_T dcmdInput;
    gint32 ret;

    if (pLdListBuf == NULL) {
        return SML_ERR_NULL_DATA;
    }
    if (sizeof(MR_LD_TARGETID_LIST) > buf_len) {
        return SML_ERR_NULL_DATA;
    }

    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);
    (void)memset_s(&dcmdInput, SL_DCMD_INPUT_S, 0, SL_DCMD_INPUT_S);

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    libCmdParam.cmdType = SL_PASSTHRU_CMD_TYPE;
    libCmdParam.cmd = SL_DCMD_PASSTHRU;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = SL_DCMD_INPUT_S;
    libCmdParam.pData = &dcmdInput;

    dcmdInput.opCode = MR_DCMD_LD_SSCD_GET_LDS;
    dcmdInput.dataTransferLength = buf_len;
    dcmdInput.flags = SL_DIR_READ;
    dcmdInput.pData = pLdListBuf;
    dcmdInput.mbox.w[0] = sscd_id;

    ret = ProcessLibCommandCall(libType, &libCmdParam);
    if (ret == SML_SUCCESS) {
        if (pLdListBuf->count > SML_MAX_LOGIC_DRIVES) {
            debug_log(DLOG_ERROR,
                "smlib: LSI:GetLDListOfSSCDCmd failed, CtrlId = 0x%08x, sscd_id = %d, returned count = %u, count is "
                "larger than %d",
                SML_CTRL_ID_VALID_BIT(ctrl_id), sscd_id, pLdListBuf->count, SML_MAX_LOGIC_DRIVES);
            return SML_ERR_DATA_INVALID;
        }

        if (check_duplicate_ld_id(pLdListBuf->targetId, (gsize)pLdListBuf->count, SML_MAX_LOGIC_DRIVES) !=
            SML_SUCCESS) {
            debug_log(DLOG_ERROR,
                "smlib: LSI: GetLDListOfSSCDCmd failed, check duplicate ld id failed, CtrlId = %d, sscd_id = %d",
                SML_CTRL_ID_VALID_BIT(ctrl_id), sscd_id);
            return SML_ERR_DATA_INVALID;
        }
    }
    return ret;
}

/*
 * Description: 获取SSCD关联的普通LD列表，确保ld_ids指向的内存空间大于或等于SML_MAX_LOGIC_DRIVES bytes
 * History: 2016年11月17日  () 新生成函数
*/
static gint32 GetLDListOfSSCD(guint32 ctrl_id, guint8 sscd_id, guint16 *ld_count, guint16 ld_ids[SML_MAX_LOGIC_DRIVES])
{
    gint32 retval = SML_SUCCESS;
    MR_LD_TARGETID_LIST *pLdList = NULL;
    guint32 req_size = 0;
    guint8 ld_ids_lsb[SML_MAX_LOGIC_DRIVES] = {0};  // 8bit的逻辑盘ID

    if ((NULL == ld_count) || (NULL == ld_ids)) {
        return SML_ERR_NULL_DATA;
    }

    retval = GetLDNumOfSSCD(ctrl_id, sscd_id, ld_count);
    if (SML_SUCCESS != retval) {
        return retval;
    }

    if (*ld_count != 0) {
        if (SML_MAX_LOGIC_DRIVES < *ld_count) {
            *ld_count = SML_MAX_LOGIC_DRIVES;
        }

        req_size = (guint32)(sizeof(MR_LD_TARGETID_LIST) + (*ld_count - 1) * sizeof(guint8));
        pLdList = (MR_LD_TARGETID_LIST *)g_malloc0(req_size);
        if (NULL == pLdList) {
            return SML_ERR_CANNOT_ALLOC_MEM;
        }

        retval = GetLDListOfSSCDCmd(ctrl_id, sscd_id, req_size, pLdList);
        if (SML_SUCCESS != retval) {
            if (NULL != pLdList) {
                g_free(pLdList);
            }
            debug_log(DLOG_ERROR,
                "smlib LSI: GetLDListOfSSCD -> perform cmd to get ld list from sscd failed, CtrlId = %d, sscd_id = %d, "
                "return 0x%0x\n",
                SML_CTRL_ID_VALID_BIT(ctrl_id), sscd_id, retval);
            return retval;
        }

        (void)memcpy_s(ld_ids, SML_MAX_LOGIC_DRIVES, pLdList->targetId, *ld_count);

        g_free(pLdList);
    }

    for (guint32 i = 0; i < SML_MAX_LOGIC_DRIVES && i < *ld_count; i++) {
        ld_ids[i] = (guint16)ld_ids_lsb[i];
    }

    return SML_SUCCESS;
}

/*
 * Description: 获取指定的sscd已经关联的普通逻辑盘个数
 * History: 2016年11月17日  () 新生成函数
*/
static gint32 GetLDNumOfSSCD(guint32 ctrl_id, guint8 sscd_id, guint16 *num)
{
    gint32 retval = SML_SUCCESS;
    MR_LD_TARGETID_LIST ld_list;

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

    *num = 0;
    (void)memset_s(&ld_list, sizeof(MR_LD_TARGETID_LIST), 0, sizeof(MR_LD_TARGETID_LIST));

    retval = GetLDListOfSSCDCmd(ctrl_id, sscd_id, sizeof(MR_LD_TARGETID_LIST), &ld_list);
    if (SML_SUCCESS == retval) {
        *num = ld_list.count;
    }

    return retval;
}

/*
 * Description: 设置指定逻辑盘是否关联到指定的cachecade ld
 * History: 2016年11月17日  () 新生成函数
*/
static gint32 AssociateLDWithSSCD(guint32 ctrl_id, guint8 target_id, guint8 sscd_id, guint8 enable)
{
    gint32 retval = SML_SUCCESS;
    guint16 num_of_ld = 0;
    MR_LD_TARGETID_LIST *pLdList = NULL;
    guint8 ld_ids[SML_MAX_LOGIC_DRIVES]; // 用来临时存储获取到的ld id列表，需要进行id的增加或者删除操作
    guint32 req_size = 0;
    guint16 idx = 0, ld_count = 0;
    gint32 ld_in_list = FALSE;    // 标记普通ld是否已经存在于sscd的ld列表中
    gint32 need_set_list = FALSE; // 标记是否需要发送命令重新设置ld列表

    // 获取sscd当前关联的普通LD的个数
    retval = GetLDNumOfSSCD(ctrl_id, sscd_id, &num_of_ld);
    if (SML_SUCCESS != retval) {
        debug_log(DLOG_ERROR,
            "smlib LSI: AssociateLDWithSSCD -> get ld num associate to sscd failed, CtrlId = %d, sscd_id = %d, return "
            "0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), sscd_id, retval);
        return retval;
    }

    (void)memset_s(ld_ids, SML_MAX_LOGIC_DRIVES, 0xff, SML_MAX_LOGIC_DRIVES);

    // 多申请一个ld id的占用空间，用来存储可能需要增加关联的ld id
    req_size = (guint32)(sizeof(MR_LD_TARGETID_LIST) + (num_of_ld - 1) * sizeof(guint8) + sizeof(guint8));
    pLdList = (MR_LD_TARGETID_LIST *)g_malloc0(req_size);
    if (NULL == pLdList) {
        retval = SML_ERR_CANNOT_ALLOC_MEM;
        debug_log(DLOG_ERROR,
            "smlib LSI: AssociateLDWithSSCD -> malloc for pLdList failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        return retval;
    }

    // 获取关联的普通LD列表
    if (num_of_ld != 0) {
        retval = GetLDListOfSSCDCmd(ctrl_id, sscd_id, req_size, pLdList);
        if (SML_SUCCESS != retval) {
            if (NULL != pLdList) {
                g_free(pLdList);
            }
            debug_log(DLOG_ERROR,
                "smlib LSI: AssociateLDWithSSCD -> perform cmd to get ld list from sscd failed, CtrlId = %d, sscd_id = "
                "%d, return 0x%0x\n",
                SML_CTRL_ID_VALID_BIT(ctrl_id), sscd_id, retval);
            return retval;
        }

        memcpy_s(ld_ids, SML_MAX_LOGIC_DRIVES, pLdList->targetId, num_of_ld);
    }

    // 判断普通ld是否已经存在于sscd的ld列表中
    for (idx = 0; idx < num_of_ld; idx++) {
        if (target_id == ld_ids[idx]) {
            ld_in_list = TRUE;
            break;
        }
    }

    // 将要设置关联的普通ld加入或者从列表中删除
    ld_count = num_of_ld;

    if (enable) {
        // 要关联且当前ld id不在关联列表中
        if (FALSE == ld_in_list) {
            pLdList->targetId[num_of_ld] = target_id;
            ld_count = num_of_ld + 1;
            need_set_list = TRUE;
        }
    } else {
        // 要取消关联且当前ld id在关联列表中
        if (TRUE == ld_in_list) {
            ld_count = 0;

            for (idx = 0; idx < num_of_ld; idx++) {
                if (target_id != ld_ids[idx]) {
                    pLdList->targetId[ld_count] = ld_ids[idx];
                    ld_count++;
                }
            }

            need_set_list = TRUE;
        }
    }

    // 向LSI FW发送命令更新sscd关联列表
    if (TRUE == need_set_list) {
        pLdList->size = req_size;
        pLdList->count = ld_count;
        retval = SetLDListOfSSCDCmd(ctrl_id, sscd_id, req_size, pLdList);
    } else {
        debug_log(DLOG_DEBUG,
            "smlib LSI: AssociateLDWithSSCD -> no need to set sscd ld list, CtrlId = %d, target_id = %d, sscd_id = %d, "
            "enable = %d\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), target_id, sscd_id, enable);
    }

    g_free(pLdList);
    return retval;
}

/*
 * Description: 设置指定逻辑盘是否使能SSD缓存功能，使能打开，任何一个CacheCade逻辑盘可以给该逻辑盘做缓存
 * History: 2016年11月17日  () 新生成函数
*/
static gint32 SetLDSscdCachingEnable(guint32 ctrl_id, guint8 target_id,
    SML_LD_SET_SSCD_CACHING_ENABLE_S *caching_enable)
{
    gint32 retval = SML_SUCCESS;

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

    if ((caching_enable->sscd_count <= 0) || (caching_enable->sscd_count > SML_MAX_LOGIC_DRIVES)) {
        // 如果打开使能caching,但是没有cachecade逻辑盘，直接返回错误
        // 如果关闭使能caching,但是没有cachecade逻辑盘，直接返回执行成功
        if (caching_enable->enable) {
            retval = SML_ERR_LD_NO_SSCD_OR_INVALID_NUM_OF_SSCD;
            debug_log(DLOG_ERROR,
                "smlib: LSI:SetLDSscdCachingEnable ->  sscd count invalid, Ctrl_id[%d], ld[%d], sscd_count[%d], return "
                "= 0x%0x\n",
                ctrl_id, target_id, caching_enable->sscd_count, retval);
        }

        return retval;
    }

    // 所有CacheCade逻辑盘的共用一份关联列表，检查第一个CacheCade逻辑盘的关联列表，把该普通LD从列表中加入或删除后再重新设置关联列表
    retval = AssociateLDWithSSCD(ctrl_id, target_id, caching_enable->sscd_target_ids[0], caching_enable->enable);
    if (SML_SUCCESS != retval) {
        debug_log(DLOG_ERROR,
            "smlib: LSI:SetLDSscdCachingEnable -> AssociateLDWithSSCD failed, Ctrl_id[%d], ld[%d], sscd[%d], return = "
            "0x%0x\n",
            ctrl_id, target_id, caching_enable->sscd_target_ids[0], retval);
    }

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

/*
 * Description: 获取指定逻辑盘的热备物理盘列表
 * History: 2016年11月23日  () 新生成函数
*/
static gint32 GetPDsSpareForLD(guint32 ctrl_id, guint8 ld_target_id, guint8 *pd_count, guint16 *pd_ids,
    MR_LD_INFO *pLdPreInfo)
{
    gint32 retval = SML_SUCCESS;
    SML_ARRAY_LIST_S array_list;
    guint16 first_ld_array_ref = 0;
    MR_CONFIG_DATA *pCurrentConfig = NULL;
    MR_SPARE *pSpare = NULL;
    MR_LD_CONFIG *ldAddr = NULL;
    guint16 i = 0, j = 0;
    gint32 array_found = FALSE;
    guint8 tmp_pd_cnt = 0;

    if ((NULL == pd_ids) || (NULL == pd_count)) {
        return SML_ERR_NULL_DATA;
    }

    // 获取指定的逻辑盘关联的Array列表
    retval = GetLDAssociatedArrays(ctrl_id, ld_target_id, &array_list, pLdPreInfo);
    if (SML_SUCCESS != retval) {
        debug_log(DLOG_ERROR,
            "smlib LSI: GetPDsSpareForLD -> Get LD associated arrays failed, CtrlId = %d, ld id = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), ld_target_id, retval);
        return retval;
    }

    first_ld_array_ref = array_list.array_refs[0];

    // 获取当前已存在的RAID配置信息, 需要使用返回的所有热备配置的信息
    retval = ReadConfig(ctrl_id, &pCurrentConfig);
    if (SML_SUCCESS != retval || pCurrentConfig == NULL) {
        if (NULL != pCurrentConfig) {
            g_free(pCurrentConfig);
        }
        debug_log(DLOG_ERROR, "smlib LSI: GetPDsSpareForLD -> ReadConfig failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        return retval;
    }

    ldAddr = (MR_LD_CONFIG *)(pCurrentConfig->array + pCurrentConfig->arrayCount);
    pSpare = (MR_SPARE *)(ldAddr + pCurrentConfig->logDrvCount);

    tmp_pd_cnt = 0;

    for (i = 0; i < pCurrentConfig->sparesCount; i++) {
        if (pSpare[i].spareType.isDedicated) { // 是否为局部热备
            for (j = 0; j < pSpare[i].arrayCount; j++) {
                array_found = FALSE;

                // 判断这个热备是否关联了逻辑盘的Array
                if (first_ld_array_ref == pSpare[i].arrayRef[j]) {
                    array_found = TRUE;
                    break;
                }
            }

            if (TRUE == array_found) {
                pd_ids[tmp_pd_cnt] = pSpare[i].ref.deviceId;
                tmp_pd_cnt++;
            }
        }
    }

    *pd_count = tmp_pd_cnt;

    g_free(pCurrentConfig);

    return retval;
}

/*
 * Description: 将RAID1E转换为RAID1或RAID10
 * History: 2017年11月27日  () 新生成函数
*/
static gint32 ConvertRaidLevel1E(guint32 ctrl_id, MR_LD_INFO *pLDinfo, guint8 *level)
{
    guint8 raid_level = 0;
    MR_MFC_DEFAULTS CtrlMfcDefault;

    if (pLDinfo == NULL || level == NULL) {
        return FALSE;
    }

    if (pLDinfo->ldConfig.params.PRL != RAID_LEVEL_1E) {
        return FALSE;
    }

    if (GetCtrlMFCDefault(ctrl_id, &CtrlMfcDefault) != SML_SUCCESS) {
        return FALSE;
    }

    if (pLDinfo->ldConfig.params.spanDepth > 1) {
        raid_level = RAID_LEVEL_10;
    } else {
        if (!((pLDinfo->ldConfig.params.RLQ == 1) &&
            (pLDinfo->ldConfig.params.SSCDType == MR_LD_SSCD_TYPE_ELASTIC_CACHE))) {
            // added for EC.
            if (CtrlMfcDefault.treatR1EAsR10 && (pLDinfo->ldConfig.params.numDrives > 2)) {
                raid_level = RAID_LEVEL_10;
            } else {
                raid_level = RAID_LEVEL_1;
            }
        } else {
            raid_level = RAID_LEVEL_0;
        }
    }

    *level = raid_level;

    return TRUE;
}

static void get_ld_policy(SML_LD_BASIC_INFO_S *pLDinfo, MR_LD_INFO *LDinfo)
{
    pLDinfo->default_read_policy = GetReadCachePolicy(LDinfo->ldConfig.properties.defaultCachePolicy);
    pLDinfo->default_write_policy = GetWriteCachePolicy(LDinfo->ldConfig.properties.defaultCachePolicy);
    pLDinfo->default_cache_policy = GetCachePolicy(LDinfo->ldConfig.properties.defaultCachePolicy);
    pLDinfo->current_read_policy = GetReadCachePolicy(LDinfo->ldConfig.properties.currentCachePolicy);
    pLDinfo->current_write_policy = GetWriteCachePolicy(LDinfo->ldConfig.properties.currentCachePolicy);
    pLDinfo->current_cache_policy = GetCachePolicy(LDinfo->ldConfig.properties.currentCachePolicy);
    pLDinfo->access_policy = GetAccessPolicy(LDinfo->ldConfig.properties.accessPolicy);
    pLDinfo->disk_cache_policy = LDinfo->ldConfig.properties.diskCachePolicy;
    return;
}

/*
 * Description: 不支持的字段，赋无效值
 */
static void set_ld_properties_unsupported(SML_LD_BASIC_INFO_S *pLDinfo)
{
    pLDinfo->accelerator = STORAGE_INFO_INVALID_BYTE;
    pLDinfo->cache_line_size = STORAGE_INFO_INVALID_BYTE;
    pLDinfo->progress_info.rebuild_state = STORAGE_INFO_INVALID_BYTE;
    pLDinfo->progress_info.rebuild_progress = STORAGE_INFO_INVALID_BYTE;
    pLDinfo->max_resizeable_size = STORAGE_INFO_INVALID_DWORD;
    return;
}

/*
 * Description: 通过LSI storelib获取LD基本信息
 * History: 2016年3月10日  新生成函数
 *          校验返回数据有效性，调用该接口的上层APP，在获取异常时不能更新数据
*/
gint32 lsi_get_ld_info(guint32 ctrl_id, guint16 target_id, gpointer data)
{
    guint16 block_size = 0;
    MR_LD_INFO LDinfo;

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

    SML_LD_BASIC_INFO_S *pLDinfo = (SML_LD_BASIC_INFO_S *)data;
    (void)memset_s(&LDinfo, sizeof(MR_LD_INFO), 0, sizeof(MR_LD_INFO));

    gint32 retval = GetLDInfo(ctrl_id, (guint8)target_id, &LDinfo);
    if (SML_SUCCESS == retval) {
        pLDinfo->target_id = (guint16)LDinfo.ldConfig.properties.ldRef.targetId;

        strncpy_s(pLDinfo->name, sizeof(pLDinfo->name), LDinfo.ldConfig.properties.name, sizeof(pLDinfo->name) - 1);

        pLDinfo->drive_state = LDinfo.ldConfig.params.state;
        get_ld_policy(pLDinfo, &LDinfo);
        pLDinfo->consistent_check = (LDinfo.progInfo.active.cc) ? TRUE : FALSE;
        pLDinfo->span_depth = LDinfo.ldConfig.params.spanDepth;
        pLDinfo->num_drive_per_span = LDinfo.ldConfig.params.numDrives;
        pLDinfo->is_epd = LDinfo.ldConfig.params.characteristics.isEPD;
        // 需要读取PD的Block大小之后计算真实大小，真实大小(Byte) = 返回值 * Block大小
        block_size = GetBlockSizeOfPDInLD(ctrl_id, (guint8)target_id);
        pLDinfo->size = BLK2MB_PLUS_HALF_MB(LDinfo.size, block_size);
        pLDinfo->strip_size = LDinfo.ldConfig.params.stripeSize;

        pLDinfo->bgi_enabled = (LDinfo.ldConfig.properties.noBGI == TRUE) ? FALSE : TRUE;

        /* BEGIN: Modified on 2017/12/2   PN:AR.SR.SFEA02109379.004.006 */
        pLDinfo->progress_info.current_fgi_state = LDinfo.progInfo.active.fgi;
        // 0-0xFFFF - %complete: progress*100/0xFFFF
        pLDinfo->progress_info.fgi = (guint8)((guint32)(LDinfo.progInfo.fgi.progress * 100) / 0xFFFF);
        /* END:   Modified on 2017/12/2 */

        debug_log(DLOG_DEBUG, "smlib: LSI:in GetLDInfo, CtrlId = %d, TargetId = %d, pLDinfo->drive_state = %d\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), (guint8)target_id, pLDinfo->drive_state);
        if (LDinfo.ldConfig.params.PRL == RAID_LEVEL_1E) {
            if (FALSE == ConvertRaidLevel1E(ctrl_id, &LDinfo, &pLDinfo->raid_level)) {
                pLDinfo->raid_level = RAID_LEVEL_1E;
            }
        } else if (LDinfo.ldConfig.params.spanDepth > 1) {
            pLDinfo->raid_level = LDinfo.ldConfig.params.PRL * 10 + LDinfo.ldConfig.params.SRL;
        } else {
            pLDinfo->raid_level = LDinfo.ldConfig.params.PRL;
        }

        pLDinfo->is_sscd = LDinfo.ldConfig.params.isSSCD;

        pLDinfo->array_count = LDinfo.ldConfig.params.spanDepth;

        if (MAX_SPAN_DEPTH < pLDinfo->array_count) {
            pLDinfo->array_count = MAX_SPAN_DEPTH;
        }

        (void)memset_s(pLDinfo->ref_array, sizeof(pLDinfo->ref_array), 0xff, sizeof(pLDinfo->ref_array));

        for (guint32 idx = 0; idx < pLDinfo->array_count; idx++) {
            pLDinfo->ref_array[idx] = LDinfo.ldConfig.span[idx].arrayRef;
        }

        // 获取sscd关联的普通逻辑盘列表
        pLDinfo->sscd_ld_count = 0;
        (void)memset_s(pLDinfo->sscd_ld_list, sizeof(pLDinfo->sscd_ld_list), 0xff, sizeof(pLDinfo->sscd_ld_list));

        if (pLDinfo->is_sscd) {
            retval = GetLDListOfSSCD(ctrl_id, (guint8)target_id, &pLDinfo->sscd_ld_count, pLDinfo->sscd_ld_list);
            if (SML_SUCCESS != retval) {
                debug_log(DLOG_ERROR,
                    "smlib: LSI:in GetLDInfo, GetLDListOfSSCD failed, CtrlId = %d, TargetId = %d, return 0x%0x",
                    SML_CTRL_ID_VALID_BIT(ctrl_id), (guint8)target_id, retval);
            }
        }

        // 逻辑盘关联的局部热备盘列表
        retval = GetPDsSpareForLD(ctrl_id, (guint8)target_id, &pLDinfo->spare_count, pLDinfo->spare_pd_ids, &LDinfo);
        if (SML_SUCCESS != retval) {
            debug_log(DLOG_ERROR,
                "smlib: LSI:in GetLDInfo, GetPDsSpareForLD failed, CtrlId = %d, TargetId = %d, return 0x%0x\n",
                SML_CTRL_ID_VALID_BIT(ctrl_id), (guint8)target_id, retval);
        }

        pLDinfo->init_state = LDinfo.ldConfig.params.initState;
    } else {
        debug_log(DLOG_ERROR, "smlib: LSI:GetLDInfo failed, CtrlId = %d, TargetId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), (guint8)target_id, retval);
    }

    CheckLDBootable(ctrl_id, (guint8)target_id, &(pLDinfo->bootable));
    pLDinfo->boot_priority = ((pLDinfo->bootable == TRUE) ? 1 : 0); // 只有一个优先级

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

    return retval;
}

/*
 * Description: 通过LSI storelib对PD执行相应的操作
 * History: 2016年11月4日  () 新生成函数
*/
gint32 lsi_config_operations(guint32 ctrl_id, guint8 operation, gpointer param, guint32 param_length)
{
    gint32 retval = SML_SUCCESS;
    guint8 libType = 0;

    if ((NULL == param) || (0 == param_length)) {
        return SML_ERR_NULL_DATA;
    }

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);
    if (libType == SL_LIB_TYPE_STORELIBIR || libType == SL_LIB_TYPE_STORELIBIR_2 ||
        libType == SL_LIB_TYPE_STORELIBIR_3 || libType == SL_LIB_TYPE_STORELIBIT ||
        libType == SL_LIB_TYPE_STORELIBCUSTOM) {
        return SML_ERR_CONFIG_OPERATION_NOT_SUPPORT;
    }

    switch (operation) {
        case CONFIG_OPERATION_CREATE_LD_ON_NEW_ARRAY:
        case CONFIG_OPERATION_CREATE_LD_ON_EXISTED_ARRAY:
        case CONFIG_OPERATION_CREATE_CACHECADE_LD:
            if ((NULL == param) || (0 == param_length)) {
                return SML_ERR_NULL_DATA;
            }
            retval = CreateLd(ctrl_id, operation, param);
            break;

        default:
            retval = SML_ERR_CONFIG_OPERATION_NOT_SUPPORT;
            break;
    }

    return retval;
}

/*
 * Description: 通过LSI storelib对LD执行相应的操作
 * History: 2016年11月5日  () 新生成函数
*/
gint32 lsi_ld_operations(guint32 ctrl_id, guint16 target_id, guint8 operation, gpointer param, guint32 param_length)
{
    gint32 retval;
    guint8 libType = 0;
    SML_LD_SET_PROPERTIES_S *properties = NULL;
    SML_LD_SET_SSCD_CACHING_ENABLE_S *caching_enable = NULL;
    guint8 init_type = 0;

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);
    if (libType == SL_LIB_TYPE_STORELIBIR || libType == SL_LIB_TYPE_STORELIBIR_2 ||
        libType == SL_LIB_TYPE_STORELIBIR_3 || libType == SL_LIB_TYPE_STORELIBIT ||
        libType == SL_LIB_TYPE_STORELIBCUSTOM) {
        return SML_ERR_LD_OPERATION_NOT_SUPPORT;
    }

    switch (operation) {
        case LD_OPERATION_DELETE:
            retval = DeleteLD(ctrl_id, (guint8)target_id);
            break;

        case LD_OPERATION_SET_BOOTABLE:
            retval = SetLDBootable(ctrl_id, (guint8)target_id);
            break;

        case LD_OPERATION_SET_PROPERTIES:
            if ((NULL == param) || (0 == param_length)) {
                return SML_ERR_NULL_DATA;
            }
            properties = (SML_LD_SET_PROPERTIES_S *)param;
            retval = SetLDProperties(ctrl_id, (guint8)target_id, properties);
            break;

        case LD_OPERATION_SET_SSCD_CACHING_ENABLE:
            if ((NULL == param) || (0 == param_length)) {
                return SML_ERR_NULL_DATA;
            }
            caching_enable = (SML_LD_SET_SSCD_CACHING_ENABLE_S *)param;
            retval = SetLDSscdCachingEnable(ctrl_id, (guint8)target_id, caching_enable);
            break;

        /* BEGIN: Modified on 2017/12/2   PN:AR.SR.SFEA02109379.004.006 */
        case LD_OPERATION_START_FGI:
            if (NULL == param) {
                return SML_ERR_NULL_DATA;
            }
            init_type = *(guint8 *)param;
            retval = StartLDFGI(ctrl_id, (guint8)target_id, init_type);
            break;

        case LD_OPERATION_CANCEL_FGI:
            retval = CancelLDFGI(ctrl_id, (guint8)target_id);
            break;
            /* END:   Modified on 2017/12/2 */

        default:
            retval = SML_ERR_LD_OPERATION_NOT_SUPPORT;
            break;
    }

    return retval;
}

/*
 * Description: 通过LSI storelib获取LD的成员盘
 * History: 2016年3月10日    新生成函数
*/
gint32 lsi_get_ld_pd_list(guint32 ctrl_id, guint16 target_id, gpointer data)
{
    gint32 retval = SML_SUCCESS;
    guint32 idx = 0;
    SL_PD_IN_LD_T pdInld;
    SML_PD_LIST_S *pLDinfo = NULL;

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

    pLDinfo = (SML_PD_LIST_S *)data;
    (void)memset_s(&pdInld, sizeof(SL_PD_IN_LD_T), 0, sizeof(SL_PD_IN_LD_T));

    retval = GetPDInLD(ctrl_id, (guint8)target_id, &pdInld);
    if (SML_SUCCESS == retval) {
        pLDinfo->pd_count = (guint16)pdInld.count;

        for (idx = 0; idx < pLDinfo->pd_count; idx++) {
            pLDinfo->device_ids[idx] = pdInld.deviceId[idx];
        }
    } else {
        debug_log(DLOG_ERROR, "smlib: LSI:GetPDInLD failed, CtrlId = %d, TargetId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), (guint8)target_id, retval);
    }

    return retval;
}

