/* 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 "utils/file_securec.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_misc.h"
#include "sl.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>

#define LSI_STORELIB_MR "/usr/lib64/libraidblib.so"
#define LSI_STORELIB_IR "/usr/lib64/libstorelibir.so"
#define LSI_STORELIB_IR2 "/usr/lib64/libstorelibir2.so"
#define LSI_STORELIB_IR3 "/usr/lib64/libraidblibir3.so"
#define LSI_STORELIB_IT "/usr/lib64/libraidblibit.so"
#define LSI_STORELIB_CUSTOM "/usr/lib64/libraidbcustom.so"

#define SML_EVENT_LOG_PATH      "/var/log"
#define SML_EVENT_LOG_NAME      "RAID_Controller_Log"

typedef struct {
    gint32 sl_err;
    gint32 sml_err;
} SL_ERROR_CODE_MAP;

// refer to LSI storelib_test tool's implementation
static gint32 LoadStorelibMR(I2C_WRITE_FUNC i2c_write_func, I2C_WRITEREAD_FUNC i2c_writeread_func);
static gint32 LoadStorelibIR(I2C_WRITE_FUNC i2c_write_func, I2C_WRITEREAD_FUNC i2c_writeread_func);
static gint32 LoadStorelibIR2(I2C_WRITE_FUNC i2c_write_func, I2C_WRITEREAD_FUNC i2c_writeread_func);
static gint32 LoadStorelibIR3(I2C_WRITE_FUNC i2c_write_func, I2C_WRITEREAD_FUNC i2c_writeread_func);
static gint32 LoadStorelibIT(I2C_WRITE_FUNC i2c_write_func, I2C_WRITEREAD_FUNC i2c_writeread_func);
static gint32 LoadStorelibCustom(I2C_WRITE_FUNC i2c_write_func, I2C_WRITEREAD_FUNC i2c_writeread_func);
static gint32 InitializeStorelib(guint8 libType, SL_CTRL_LIST_T *pctrl);
static void ExitStorelib(guint8 libType);
static gint32 RegisterAENCall(guint32 ctrl_id, SL_REG_AEN_INPUT_T *pRegAENInput, SL_REG_AEN_OUTPUT_T *PregAENOutput);
static gint32 RegisterAEN(SL_CTRL_LIST_T *pCtrlList);
static gint32 UnRegisterAENCall(guint32 ctrl_id, guint32 unique_id);
static gint32 UnRegisterAEN(void);
static gint32 GetOOBStatus(guint32 ctrl_id);
static void lsi_mutex_init(void);
static void lsi_rearrange_ctrlId(SL_CTRL_LIST_T *pctrllist, guint8 idx);
static void HexDump(FILE *fp, const guint8 *dump, guint32 count);
static gint32 isLeap(gint32 year);
static void InterpretTime(guint32 seconds, gchar *pbuf, guint32 buf_szie);
static void GetLocalTime(gchar *timeBuf, guint32 buf_szie);
static void GenerateEventTextInfo(FILE *fp, guint32 ctrl_id, const MR_EVT_DETAIL *evtDetail);
static gint32 AENCallBack(SL_EVENT_DETAIL_T *pEventDetail);

/* ----------------------------------------------*
 *  全局变量                                     *
 * ---------------------------------------------- */
static void *libInstanceMR = NULL;
static void *libInstanceIR = NULL;
static void *libInstanceIR2 = NULL;
static void *libInstanceIR3 = NULL;
static void *libInstanceIT = NULL;
static void *libInstanceCustom = NULL;
static GMutex gLSICtrlMutex[SL_LIB_TYPE_STORELIBCUSTOM + 1];

typedef void (*RegisterI2CFunc)(I2C_WRITE_FUNC i2c_write_func, I2C_WRITEREAD_FUNC i2c_writeread_func);
typedef guint32 (*ProcessLibCommandFunc)(SL_LIB_CMD_PARAM_T *plcp);
static ProcessLibCommandFunc pfnProcessLibCommandMR = NULL;
static ProcessLibCommandFunc pfnProcessLibCommandIR = NULL;
static ProcessLibCommandFunc pfnProcessLibCommandIR2 = NULL;
static ProcessLibCommandFunc pfnProcessLibCommandIR3 = NULL;
static ProcessLibCommandFunc pfnProcessLibCommandIT = NULL;
static ProcessLibCommandFunc pfnProcessLibCommandCustom = NULL;

typedef void (*SetInitDoneFunc)(guint8 initDone);
static SetInitDoneFunc pfnSetInitDone = NULL;

static SL_CTRL_LIST_T gLSICtrlListMR = { 0 };
static SL_CTRL_LIST_T gLSICtrlListIR = { 0 };
static SL_CTRL_LIST_T gLSICtrlListIR2 = { 0 };
static SL_CTRL_LIST_T gLSICtrlListIR3 = { 0 };
static SL_CTRL_LIST_T gLSICtrlListIT = { 0 };
static SL_CTRL_LIST_T gLSICtrlListCustom = { 0 };
static SLT_AEN_INFO_S gRegistrationInfo[SL_MAX_AEN_REGISTRATIONS];
static guint32 gRegCount = 0;
static guint8 gLogFlag = 0;
static guint8 gSLMrInit = FALSE;
static HANDLE_EVENT_INFO_FUNC g_handle_event_info_func = NULL;

#define lsi_init_debug_log(level, format, arg...) do {                                          \
        if (gLogFlag) {                           \
            debug_log(level, format, ##arg);      \
        }                                         \
    } while (0)

static gint32 LoadStorelibMR(I2C_WRITE_FUNC i2c_write_func, I2C_WRITEREAD_FUNC i2c_writeread_func)
{
    RegisterI2CFunc pfnRegisterI2CFunc = NULL;

    libInstanceMR = dlopen(LSI_STORELIB_MR, RTLD_LAZY);
    if (libInstanceMR == NULL) {
        debug_log(DLOG_ERROR, "Failed to load library %s for MegaRAID SAS Controller. error : %s",
            LSI_STORELIB_MR, dlerror());
        return SML_ERR_CTRL_LSI_SL_LOAD_FAILED;
    }

    if (i2c_write_func != NULL && i2c_writeread_func != NULL) {
        pfnRegisterI2CFunc = (RegisterI2CFunc)dlsym(libInstanceMR, "RegisterI2CFunc");
        if (pfnRegisterI2CFunc == NULL) {
            debug_log(DLOG_ERROR, "Unable to get Entry Point function address-%s.", "RegisterI2CFunc");
            dlclose(libInstanceMR);
            libInstanceMR = NULL;
            return SML_ERR_CTRL_LSI_SL_GET_FUNC_ADDR_FAILED;
        }

        pfnRegisterI2CFunc(i2c_write_func, i2c_writeread_func);
    }

    pfnProcessLibCommandMR = (ProcessLibCommandFunc)dlsym(libInstanceMR, "ProcessLibCommand");
    if (pfnProcessLibCommandMR == NULL) {
        debug_log(DLOG_ERROR, "Unable to get Entry Point function address-%s.", "ProcessLibCommand");
        dlclose(libInstanceMR);
        libInstanceMR = NULL;
        return SML_ERR_CTRL_LSI_SL_GET_FUNC_ADDR_FAILED;
    }

    return SML_SUCCESS;
}

static gint32 LoadStorelibIR(I2C_WRITE_FUNC i2c_write_func, I2C_WRITEREAD_FUNC i2c_writeread_func)
{
    libInstanceIR = dlopen(LSI_STORELIB_IR, RTLD_LAZY);
    if (libInstanceIR == NULL) {
        debug_log(DLOG_ERROR, "Failed to load library %s for IR SAS Controller. error : %s", LSI_STORELIB_IR,
            dlerror());
        return SML_ERR_CTRL_LSI_SL_LOAD_FAILED;
    }

    pfnProcessLibCommandIR = (ProcessLibCommandFunc)dlsym(libInstanceIR, "ProcessLibCommandIR");
    if (pfnProcessLibCommandIR == NULL) {
        debug_log(DLOG_ERROR, "Unable to get Entry Point function address-%s.", "ProcessLibCommandIR");
        dlclose(libInstanceIR);
        libInstanceIR = NULL;
        return SML_ERR_CTRL_LSI_SL_GET_FUNC_ADDR_FAILED;
    }

    return SML_SUCCESS;
}

static gint32 LoadStorelibIR2(I2C_WRITE_FUNC i2c_write_func, I2C_WRITEREAD_FUNC i2c_writeread_func)
{
    libInstanceIR2 = dlopen(LSI_STORELIB_IR2, RTLD_LAZY);
    if (libInstanceIR2 == NULL) {
        debug_log(DLOG_ERROR, "Failed to load library %s for IR2 SAS Controller. error : %s", LSI_STORELIB_IR2,
            dlerror());
        return SML_ERR_CTRL_LSI_SL_LOAD_FAILED;
    }

    pfnProcessLibCommandIR2 = (ProcessLibCommandFunc)dlsym(libInstanceIR2, "ProcessLibCommandIR2");
    if (pfnProcessLibCommandIR2 == NULL) {
        debug_log(DLOG_ERROR, "Unable to get Entry Point function address-%s.", "ProcessLibCommandIR2");
        dlclose(libInstanceIR2);
        libInstanceIR2 = NULL;
        return SML_ERR_CTRL_LSI_SL_GET_FUNC_ADDR_FAILED;
    }

    return SML_SUCCESS;
}

static gint32 LoadStorelibIR3(I2C_WRITE_FUNC i2c_write_func, I2C_WRITEREAD_FUNC i2c_writeread_func)
{
    RegisterI2CFunc pfnRegisterI2CFunc = NULL;

    libInstanceIR3 = dlopen(LSI_STORELIB_IR3, RTLD_LAZY);
    if (libInstanceIR3 == NULL) {
        debug_log(DLOG_ERROR, "Failed to load library %s for IR3 SAS Controller : %s.", LSI_STORELIB_IR3,
            dlerror());
        return SML_ERR_CTRL_LSI_SL_LOAD_FAILED;
    }

    if (i2c_write_func != NULL && i2c_writeread_func != NULL) {
        pfnRegisterI2CFunc = (RegisterI2CFunc)dlsym(libInstanceIR3, "MPCI_RegisterI2CFunc");
        if (pfnRegisterI2CFunc == NULL) {
            debug_log(DLOG_ERROR, "Unable to get Entry Point function address-%s.", "RegisterI2CFunc");
            dlclose(libInstanceIR3);
            libInstanceIR3 = NULL;
            return SML_ERR_CTRL_LSI_SL_GET_FUNC_ADDR_FAILED;
        }

        pfnRegisterI2CFunc(i2c_write_func, i2c_writeread_func);
    }

    pfnProcessLibCommandIR3 = (ProcessLibCommandFunc)dlsym(libInstanceIR3, "ProcessLibCommandIR3");
    if (pfnProcessLibCommandIR3 == NULL) {
        debug_log(DLOG_ERROR, "Unable to get Entry Point function address-%s.", "ProcessLibCommandIR3");
        dlclose(libInstanceIR3);
        libInstanceIR3 = NULL;
        return SML_ERR_CTRL_LSI_SL_GET_FUNC_ADDR_FAILED;
    }

    pfnSetInitDone = (SetInitDoneFunc)dlsym(libInstanceIR3, "SetInitDone");
    if (pfnSetInitDone == NULL) {
        debug_log(DLOG_ERROR, "Unable to get Entry Point function address-%s.", "SetInitDone");
        dlclose(libInstanceIR3);
        libInstanceIR3 = NULL;
        pfnProcessLibCommandIR3 = NULL;
        return SML_ERR_CTRL_LSI_SL_GET_FUNC_ADDR_FAILED;
    }

    return SML_SUCCESS;
}

/* BEGIN: Added on 2017/6/13   问题单号:SF-0000276589 */
static gint32 LoadStorelibIT(I2C_WRITE_FUNC i2c_write_func, I2C_WRITEREAD_FUNC i2c_writeread_func)
{
    RegisterI2CFunc pfnRegisterI2CFunc = NULL;

    libInstanceIT = dlopen(LSI_STORELIB_IT, RTLD_LAZY);
    if (libInstanceIT == NULL) {
        debug_log(DLOG_ERROR, "Failed to load library %s for IT SAS Controller. error: %s", LSI_STORELIB_IT,
            dlerror());
        return SML_ERR_CTRL_LSI_SL_LOAD_FAILED;
    }

    if (i2c_write_func != NULL && i2c_writeread_func != NULL) {
        pfnRegisterI2CFunc = (RegisterI2CFunc)dlsym(libInstanceIT, "RegisterI2CFunc");
        if (pfnRegisterI2CFunc == NULL) {
            debug_log(DLOG_ERROR, "Unable to get Entry Point function address-%s.", "RegisterI2CFunc");
            dlclose(libInstanceIT);
            libInstanceIT = NULL;
            return SML_ERR_CTRL_LSI_SL_GET_FUNC_ADDR_FAILED;
        }

        pfnRegisterI2CFunc(i2c_write_func, i2c_writeread_func);
    }

    pfnProcessLibCommandIT = (ProcessLibCommandFunc)dlsym(libInstanceIT, "ProcessLibCommandIT");
    if (pfnProcessLibCommandIT == NULL) {
        debug_log(DLOG_ERROR, "Unable to get Entry Point function address-%s.", "ProcessLibCommandIT");
        dlclose(libInstanceIT);
        libInstanceIT = NULL;
        return SML_ERR_CTRL_LSI_SL_GET_FUNC_ADDR_FAILED;
    }

    pfnSetInitDone = (SetInitDoneFunc)dlsym(libInstanceIT, "SetInitDone");
    if (pfnSetInitDone == NULL) {
        debug_log(DLOG_ERROR, "Unable to get Entry Point function address-%s.", "SetInitDone");
        dlclose(libInstanceIT);
        libInstanceIT = NULL;
        pfnProcessLibCommandIT = NULL;
        return SML_ERR_CTRL_LSI_SL_GET_FUNC_ADDR_FAILED;
    }

    return SML_SUCCESS;
}

static gint32 LoadStorelibCustom(I2C_WRITE_FUNC i2c_write_func, I2C_WRITEREAD_FUNC i2c_writeread_func)
{
    RegisterI2CFunc pfnRegisterI2CFunc = NULL;
 
    libInstanceCustom = dlopen(LSI_STORELIB_CUSTOM, RTLD_LAZY);
    if (libInstanceCustom == NULL) {
        debug_log(DLOG_ERROR, "Failed to load library %s for IT SAS Controller. error: %s", LSI_STORELIB_IT,
            dlerror());
        return SML_ERR_CTRL_LSI_SL_LOAD_FAILED;
    }

    if (i2c_write_func != NULL && i2c_writeread_func != NULL) {
        pfnRegisterI2CFunc = (RegisterI2CFunc)dlsym(libInstanceCustom, "RegisterI2CFunc");
        if (pfnRegisterI2CFunc == NULL) {
            debug_log(DLOG_ERROR, "Unable to get Entry Point function address-%s.", "RegisterI2CFunc");
            dlclose(libInstanceCustom);
            libInstanceCustom = NULL;
            return SML_ERR_CTRL_LSI_SL_GET_FUNC_ADDR_FAILED;
        }
 
        pfnRegisterI2CFunc(i2c_write_func, i2c_writeread_func);
    }

    pfnProcessLibCommandCustom = (ProcessLibCommandFunc)dlsym(libInstanceCustom, "ProcessLibCommandIT");
    if (pfnProcessLibCommandCustom == NULL) {
        debug_log(DLOG_ERROR, "Unable to get Entry Point function address-%s.", "ProcessLibCommandIT");
        dlclose(libInstanceCustom);
        libInstanceCustom = NULL;
        return SML_ERR_CTRL_LSI_SL_GET_FUNC_ADDR_FAILED;
    }

    pfnSetInitDone = (SetInitDoneFunc)dlsym(libInstanceCustom, "SetInitDone");
    if (pfnSetInitDone == NULL) {
        debug_log(DLOG_ERROR, "Unable to get Entry Point function address-%s.", "SetInitDone");
        dlclose(libInstanceCustom);
        libInstanceCustom = NULL;
        pfnProcessLibCommandCustom = NULL;
        return SML_ERR_CTRL_LSI_SL_GET_FUNC_ADDR_FAILED;
    }

    return SML_SUCCESS;
}

/*
 * Description: storelib返回的错误类型转换成相应SML_ERR
*/
static gint32 ParseErrCode(gint32 err)
{
    const SL_ERROR_CODE_MAP g_err_code_map[] = {
        {MFI_STAT_OK_REBOOT_REQUIRED,            SML_ERR_REBOOT_REQUIRED},
        {MFI_STAT_PD_MAX_UNCONFIGURED,           SML_ERR_PD_MAX_UNCONFIGURED},
        {MFI_STAT_FEATURE_SECURITY_NOT_ENABLED,  SML_ERR_PD_OPERATION_NOT_SUPPORT},
        {MFI_STAT_INVALID_PARAMETER,             SML_ERR_INVALID_PARAMETER},
        {MFI_STAT_INVALID_POLICY,                SML_ERR_LD_INVALID_POLICY},
        {MFI_STAT_INVALID_CMD,                   SML_ERR_INVALID_CMD},
        {MFI_STAT_LD_INIT_IN_PROGRESS,           SML_ERR_LD_INIT_IN_PROGRESS},
        {MFI_STAT_LD_BLOCK_SIZE_MISMATCH,        SML_ERR_CONFIG_BLOCK_SIZE_NOT_SAME},
        {MFI_STAT_FOREIGN_CONFIG_INCOMPLETE,     SML_ERR_CONFIG_INCOMPLETE_FOREIGN_CONFIG},
        {MFI_STAT_OPERATION_NOT_POSSIBLE,        SML_ERR_OPERATION_NOT_POSSIBLE},
        {MFI_STAT_CONFIG_PRESENT_ERROR,          SML_ERR_CONFIG_PRESENT_ERROR},
        {MFI_STAT_CONFIG_RESOURCE_CONFLICT,      SML_ERR_CONFIG_RESOURCE_CONFLICT},
        {MFI_STAT_DRIVE_TOO_SMALL,               SML_ERR_CONFIG_ASSOCIATED_LD_SIZE_OUT_OF_RANGE},
        {MFI_STAT_PD_CLEAR_IN_PROGRESS,          SML_ERR_PD_CLEAR_IN_PROGRESS},
        {SL_ERR_CMD_FAILED_BY_OS,                SML_ERR_CTRL_STATUS_INVALID},
        {SL_ERR_INVALID_CTRL,                    SML_ERR_CTRL_INIT_NOT_COMPLETED},
        {SL_ERR_OOB_CANNOT_RESUME,               SML_ERR_CTRL_STATUS_INVALID},
        {SL_ERR_OOB_I2C_READ_FAILED,             SML_ERR_I2C_READ_WRITE_FAILED},
        {SL_ERR_OOB_I2C_WRITE_FAILED,            SML_ERR_I2C_READ_WRITE_FAILED},
        {SL_ERR_OOB_WRONG_STATE,                 SML_ERR_CTRL_STATUS_INVALID},
        {SL_ERR_INVALID_DATA,                    SML_ERR_DATA_INVALID},
        {SL_ERR_OOB_NOT_READY,                   SML_ERR_CTRL_STATUS_INVALID},
    };

    size_t cnt = sizeof(g_err_code_map) / sizeof(SL_ERROR_CODE_MAP);
    for (guint32 i = 0; i < cnt; i++) {
        if (g_err_code_map[i].sl_err == err) {
            return g_err_code_map[i].sml_err;
        }
    }

    return err;
}

/* END:   Added on 2017/6/13 */
 
// 设置pfnProcessLibCommand 命令
static ProcessLibCommandFunc GetpfnProcessLibCommand(guint8 libType)
{
    ProcessLibCommandFunc pfnProcessLibCommand = NULL;

    if (libType == SL_LIB_TYPE_STORELIB && pfnProcessLibCommandMR != NULL) {
        pfnProcessLibCommand = pfnProcessLibCommandMR;
    } else if (libType == SL_LIB_TYPE_STORELIBIR && pfnProcessLibCommandIR != NULL) {
        pfnProcessLibCommand = pfnProcessLibCommandIR;
    } else if (libType == SL_LIB_TYPE_STORELIBIR_2 && pfnProcessLibCommandIR2 != NULL) {
        pfnProcessLibCommand = pfnProcessLibCommandIR2;
    } else if (libType == SL_LIB_TYPE_STORELIBIR_3 && pfnProcessLibCommandIR3 != NULL) {
        pfnProcessLibCommand = pfnProcessLibCommandIR3;
    } else if (libType == SL_LIB_TYPE_STORELIBIT && pfnProcessLibCommandIT != NULL) {
        pfnProcessLibCommand = pfnProcessLibCommandIT;
    } else if (libType == SL_LIB_TYPE_STORELIBCUSTOM && pfnProcessLibCommandCustom != NULL) {
        pfnProcessLibCommand = pfnProcessLibCommandCustom;
    }

    return pfnProcessLibCommand;
}

/*
 * Description: storelib发送命令的公共入口函数
 * History: 2016年3月3日  新生成函数
 *          2018年7月5日  storelib不支持多线程，发送命了增加互斥锁
*/
gint32 ProcessLibCommandCall(guint8 libType, SL_LIB_CMD_PARAM_T *plcp)
{
    ProcessLibCommandFunc pfnProcessLibCommand;
    gint32 retval = SML_ERR_NULL_INFTERFACE;
    gint32 retval_try;

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

    if (libType > SL_LIB_TYPE_STORELIBCUSTOM) {
        return SML_ERR_EXCEED_LIMIT;
    }

    g_mutex_lock(&gLSICtrlMutex[libType]);

    pfnProcessLibCommand = GetpfnProcessLibCommand(libType);

    plcp->ctrlId = LSI_CTRL_ID_RESVED_BIT_MASK(plcp->ctrlId);

    if (pfnProcessLibCommand != NULL) {
        retval = (gint32)pfnProcessLibCommand(plcp);
        // 针对创建和删除逻辑盘失败作特殊处理
        if ((retval != SL_SUCCESS) && (((plcp->cmdType == SL_CONFIG_CMD_TYPE) && (plcp->cmd == SL_ADD_CONFIG)) ||
            ((plcp->cmdType == SL_LD_CMD_TYPE) && (plcp->cmd == SL_DELETE_LD)))) {
            // 创建删除逻辑盘返回0x802d，长时间测试结果表明，这种情况实际命令已经执行成功
            if (retval == SL_ERR_OOB_NOT_READY) {
                debug_log(DLOG_ERROR, "[%s]SL command %s failed, retval = 0x%x, delay 200ms and retry\n", __FUNCTION__,
                    (plcp->cmd == SL_ADD_CONFIG) ? "Create(Add) Ld" : "Delete Ld", retval);

                vos_task_delay(200);
                retval_try = (gint32)pfnProcessLibCommand(plcp);
                debug_log(DLOG_ERROR, "[%s]SL command retry %s, retval = 0x%x\n", __FUNCTION__,
                    (retval_try == SL_SUCCESS) ? "successfully" : "still failed", retval_try);

                // 实际测试结果表明，误报创建删除逻辑盘时再次重试，返回码为0x04(创建)或0x0c(删除)
                if ((retval_try == MFI_STAT_INVALID_SEQUENCE_NUMBER) || (retval_try == MFI_STAT_DEVICE_NOT_FOUND)) {
                    retval = SL_SUCCESS;
                } else {
                    // 如果重试返回成功，则返回最终结果成功，否则返回重试之前的错误码
                    if (retval_try == SL_SUCCESS) {
                        retval = SL_SUCCESS;
                    }
                }
            }
        }

        retval = ParseErrCode(retval);
    }
    g_mutex_unlock(&gLSICtrlMutex[libType]);
    return retval;
}

/*
 * Description: 根据sense data解析出sense code
 * History: 2018-12-27   新生成函数       PN:UADP135084
*/
gint8 ParsePDSenseCode(guint8 *sense_data, guint32 data_len, SCSI_SENSE_DISECT_S *sense_info)
{
    if (NULL == sense_data || data_len < SL_SCSI_MAX_SENSE_LENGTH || NULL == sense_info) {
        return -1;
    }

    sense_info->error_code = sense_data[0] & 0x7F;
    sense_info->asc = 0;
    sense_info->ascq = 0;
    // formate is fixed
    if ((SCSI_FIXED_SENSE_DATA_RESP_CUR_INFO == sense_info->error_code) ||
        (SCSI_FIXED_SENSE_DATA_RESP_DEFERRD_ERR == sense_info->error_code)) {
        sense_info->sense_key = sense_data[2] & 0x0F; // sense key
        if (5 < sense_data[7]) {                      // 判断是否有足够的数据
            sense_info->asc = sense_data[12];         // sense asc
            sense_info->ascq = sense_data[13];        // sense ascq
        }
    // formate is descriptor
    } else if ((SCSI_DESC_SENSE_DATA_RESP_CUR_INFO == sense_info->error_code) ||
        (SCSI_DESC_SENSE_DATA_RESP_DEFERRD_ERR == sense_info->error_code)) {
        sense_info->sense_key = sense_data[1] & 0x0F; // sense key
        sense_info->asc = sense_data[2];              // sense asc
        sense_info->ascq = sense_data[3];             // sense ascq
    }
    return 0;
}

/*
 * Description: 校验直通命令失败后的scsiStatus状态
 * History: 2018-12-25  新生成函数 PN:UADP135084
*/
static gint32 GetErrorByScsiStatus(guint32 ctrl_id, SL_SCSI_PASSTHRU_T *scsi_passthru_cmd)
{
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_NULL_DATA;
    }

    gint32 retval = SML_ERR_PD_SCSI_STATUS_FAIL;
    SCSI_SENSE_DISECT_S sense_info;

    debug_log(DLOG_DEBUG, "%s: Fire SCSI passthru command failed, DeviceId = %d , CtrlId = %d, Status 0x%02x",
        __FUNCTION__, scsi_passthru_cmd->targetId, SML_CTRL_ID_VALID_BIT(ctrl_id), scsi_passthru_cmd->scsiStatus);

    /* 检查SCSI命令返回值状态 */
    switch (scsi_passthru_cmd->scsiStatus) {
        case SCSI_STATUS_BUSY:
            retval = SML_ERR_PD_SCSI_STATUS_BUSY; // 命令需要重发
            break;
        case SCSI_STATUS_CHECK_CONDITION:
            /* 解析出sense data */
            (void)memset_s(&sense_info, sizeof(SCSI_SENSE_DISECT_S), 0, sizeof(SCSI_SENSE_DISECT_S));
            if (0 == ParsePDSenseCode(scsi_passthru_cmd->pRequestSenseData, SL_SCSI_MAX_SENSE_LENGTH, &sense_info)) {
                /* 根据key、asc、ascq判断硬盘故障 */
                if (TRUE == CheckPDSenseCode(&sense_info, NULL)) {
                    debug_log(DLOG_DEBUG,
                        "Fire SCSI passthru command failed because of sense error, DeviceId = %d , CtrlId = %d, key = "
                        "0x%02x, asc = 0x%02x, ascq = 0x%02x",
                        scsi_passthru_cmd->targetId, SML_CTRL_ID_VALID_BIT(ctrl_id), sense_info.sense_key,
                        sense_info.asc, sense_info.ascq);
                    retval = SML_ERR_PD_SCSI_DEVICE_FAULT;
                }
            }
            break;
        /* 其他状态返回SML_ERR_PD_SCSI_STATUS_FAIL，后续结合链路检查进行诊断 */
        default:
            break;
    }
    return retval;
}

/*
 * Description: 发送SCSI命令
 * History: 2016-04-14   新生成函数
 *          2019-01-26   增加对2d 2e错误码的校验处理   PN:UADP135084
*/
gint32 FireSCSIPassthruCmd(guint32 ctrl_id, SL_SCSI_PASSTHRU_T *scsi_passthru_cmd)
{
    gint32 retval = SML_SUCCESS;
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;

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

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    (void)memset_s(&libCmdParam, sizeof(SL_LIB_CMD_PARAM_T), 0, sizeof(SL_LIB_CMD_PARAM_T));

    libCmdParam.cmdType = SL_PASSTHRU_CMD_TYPE;
    libCmdParam.cmd = SL_SCSI_PASSTHRU;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.pdRef.deviceId = scsi_passthru_cmd->targetId;
    libCmdParam.pData = scsi_passthru_cmd;
    libCmdParam.dataSize = sizeof(SL_SCSI_PASSTHRU_T) + scsi_passthru_cmd->dataSize;

    retval = ProcessLibCommandCall(libType, &libCmdParam);
    if (SML_SUCCESS == retval) {
        /* 检查SCSI命令返回值状态 */
        switch (scsi_passthru_cmd->scsiStatus) {
            case SCSI_STATUS_SUCCESS:
                retval = SML_SUCCESS;
                break;

            case SCSI_STATUS_BUSY:
                retval = SML_ERR_PD_SCSI_STATUS_BUSY; /* 命令可能需要重发 */
                break;

            default:
                debug_log(DLOG_DEBUG, "DeviceId = %d , CtrlId = %d, passthru command return status 0x%02x",
                    scsi_passthru_cmd->targetId, SML_CTRL_ID_VALID_BIT(ctrl_id), scsi_passthru_cmd->scsiStatus);
                retval = SML_ERR_PD_SCSI_CMD_FAIL;
                break;
        }
    } else {
        debug_log(DLOG_DEBUG,
            "Fire SCSI passthru command failed, DeviceId = %d , CtrlId = %d, Status 0x%02x, return 0x%04x",
            scsi_passthru_cmd->targetId, SML_CTRL_ID_VALID_BIT(ctrl_id), scsi_passthru_cmd->scsiStatus, retval);

        // 对MFI_STAT_SCSI_DONE_WITH_ERROR/MFI_STAT_SCSI_IO_FAILED错误进行校验处理
        if (MFI_STAT_SCSI_DONE_WITH_ERROR == retval || MFI_STAT_SCSI_IO_FAILED == retval) {
            retval = GetErrorByScsiStatus(ctrl_id, scsi_passthru_cmd);
        }
    }

    return retval;
}

/*
 * Description: 将8字节的SAS地址转成字符串格式
 * History: 2016-03-10  新生成函数
*/
void format_sas_addr(guint64 addr, gchar *pAddrBuff, guint32 buffSize)
{
    SML_SAS_ADDR_64 addr64;
    addr64.addr64 = addr;

    if (NULL == pAddrBuff || buffSize == 0) {
        return;
    }

#ifdef BD_BIG_ENDIAN
    /* * BEGIN: Added by lichangdi,  安全排查 20170808，snprintf_s 参数3不能大于等于参数2 */
    (void)snprintf_s(pAddrBuff, buffSize, buffSize - 1, "%08x%08x", addr64.u.addr32Low, addr64.u.addr32High);
#else
    (void)snprintf_s(pAddrBuff, buffSize, buffSize - 1, "%08x%08x", addr64.u.addr32High, addr64.u.addr32Low);
    /* * END:   Added by lichangdi, 20170808 */
#endif
}

static void HexDump(FILE *fp, const guint8 *dump, guint32 count)
{
    guint32 i = 0;

    if (NULL == fp || NULL == dump) {
        return;
    }

    for (i = 0; i < count; i++) {
        if (i % 16 == 0) {
            (void)fprintf(fp, "\n");
        }

        (void)fprintf(fp, "%02X  ", dump[i]);
    }

    (void)fprintf(fp, "\n");

    return;
}

static gint32 isLeap(gint32 year)
{
    if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) {
        return 1;
    } else {
        return 0;
    }
}

static void InterpretTime(guint32 seconds, gchar *pbuf, guint32 buf_szie)
{
    gint32 numYears = 0, numMonths = 0;
    glong numDays = 0;
    gint32 numHours = 0, numMinutes = 0, numSeconds = 0;
    gint32 startYear = 2000, startMonth = 1, startDay = 1, startHour = 0, startMinute = 0, startSecond = 0;
    gint32 month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    gint32 remainingSeconds, chkYear = 2000;
    gint32 msbCleared = 0; // Most Significant Byte Cleared
    guint32 i = 0;

    if (NULL == pbuf || 0 == buf_szie) {
        return;
    }

    if ((seconds & 0xff000000) == 0xff000000) {
        seconds &= 0x00ffffff;
        msbCleared = 1;
    }

    numDays = (glong)(seconds / 86400.0);
    remainingSeconds = (gint32)seconds - numDays * 86400;
    numHours = (gint32)(remainingSeconds / 3600.0);
    remainingSeconds = remainingSeconds - numHours * 3600;
    numMinutes = (gint32)(remainingSeconds / 60);
    numSeconds = remainingSeconds - numMinutes * 60;

    while (numDays >= 365) {
        numDays -= 365;

        if (isLeap(chkYear)) {
            numDays -= 1;
        }

        chkYear++;
        numYears++;
    }

    if (numDays >= month[0]) {
        numDays -= month[0];
        numMonths++;
    }

    if (numDays >= month[1]) {
        numDays -= month[1];

        if (isLeap(chkYear)) {
            numDays -= 1;
        }

        numMonths++;
    }

    for (i = 2; i < sizeof(month) / sizeof(month[0]) && numDays >= month[i]; i++) {
        numDays -= month[i];
        numMonths++;
    }

    if (msbCleared) {
        (void)snprintf_s(pbuf, buf_szie, buf_szie - 1,
            "Time elapsed since power on : %d years, %d months, %d days; %d:%d:%d (h:m:s)", numYears, numMonths,
            numDays, numHours, numMinutes, numSeconds);
    } else {
        (void)snprintf_s(pbuf, buf_szie, buf_szie - 1, "%d/%ld/%d ; %d:%d:%d", startMonth + numMonths,
            startDay + numDays, startYear + numYears, startHour + numHours, startMinute + numMinutes,
            startSecond + numSeconds);
    }

    return;
}

/*
 * Description: 获取当前BMC的时间
*/
static void GetLocalTime(gchar *timeBuf, guint32 buf_szie)
{
    gint32 ret = 0;
    struct timeval tv;
    time_t local_time = 0;
    struct tm local_time_tm = {};

    if (NULL == timeBuf || 0 == buf_szie) {
        return;
    }

    ret = gettimeofday(&tv, NULL);
    if (ret != 0) {
        (void)snprintf_s(timeBuf, buf_szie, buf_szie - 1, "0000-00-00 00:00:00");
    } else {
        local_time = tv.tv_sec;
        tzset();
        (void)localtime_r(&local_time, &local_time_tm);
        (void)snprintf_s(timeBuf, buf_szie, buf_szie - 1, "%04d-%02d-%02d %02d:%02d:%02d",
            (1900 + local_time_tm.tm_year), (1 + local_time_tm.tm_mon), local_time_tm.tm_mday, local_time_tm.tm_hour,
            local_time_tm.tm_min, local_time_tm.tm_sec);
    }
    return;
}

/*
 * Description: 读取控制器RAID组配置信息大小
 * History: 2016-11-4 yangshigui () 新生成函数
*/
static gint32 GetConfigSize(guint32 ctrl_id, MR_CONFIG_DATA *config)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;

    if (config == NULL) {
        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_CONFIG_CMD_TYPE;
    libCmdParam.cmd = SL_READ_CONFIG;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = sizeof(MR_CONFIG_DATA);
    libCmdParam.pData = config;

    return ProcessLibCommandCall(libType, &libCmdParam);
}

/*
 * Description: 读取控制器的指定大小的RAID组配置信息
 * History: 2016-11-4  () 新生成函数
*/
static gint32 GetConfig(guint32 ctrl_id, guint32 buf_len, MR_CONFIG_DATA *pBuffer)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;

    if (NULL == pBuffer) {
        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_CONFIG_CMD_TYPE;
    libCmdParam.cmd = SL_READ_CONFIG;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = buf_len;
    libCmdParam.pData = pBuffer;

    return ProcessLibCommandCall(libType, &libCmdParam);
}

/*
 * Description: 读取控制器的当前RAID组所有配置信息(自动检测信息大小)，使用完后需要调用者释放用来保存配置信息的内存
 * History: 2016-11-4  () 新生成函数
*/
gint32 ReadConfig(guint32 ctrl_id, MR_CONFIG_DATA **ppConfig)
{
    gint32 rval;
    MR_CONFIG_DATA config;
    guint32 caculated_size = 0;

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

    (void)memset_s(&config, sizeof(MR_CONFIG_DATA), 0, sizeof(MR_CONFIG_DATA));

    rval = GetConfigSize(ctrl_id, &config);
    if (SML_SUCCESS != rval) {
        *ppConfig = NULL;
        return rval;
    }

    // 代码检视，乘数强制转化为guint32类型，避免中间结果溢出
    // 检查计算出来的大小和实际config.size返回的大小是否一致，不一致则表明RAID控制器工作不正常
    caculated_size = offsetof(MR_CONFIG_DATA, array) + (guint32)config.arrayCount * config.arraySize +
        (guint32)config.logDrvCount * config.logDrvSize + (guint32)config.sparesCount * config.sparesSize;
    /* END:   Modified on 2017/1/5 */
    if (config.size != caculated_size) {
        *ppConfig = NULL;
        return SML_ERR_CONFIG_INCORRECT_CONFIG_DATA_SIZE;
    }

    *ppConfig = NULL;
    *ppConfig = (MR_CONFIG_DATA *)g_malloc0(config.size);

    if (*ppConfig == NULL) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    rval = GetConfig(ctrl_id, config.size, *ppConfig);
    if (SML_SUCCESS != rval) {
        g_free(*ppConfig);
        *ppConfig = NULL;
    }

    return rval;
}

/*
 * Description: 发送命令给storelib获取PD详细信息
 * History: 2016-04-7  新生成函数
*/
gint32 GetPDInfo(guint32 ctrl_id, guint16 deviceId, MR_PD_INFO *pPdInfo)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;
    gint32 ret;

    if (NULL == pPdInfo) {
        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_PD_CMD_TYPE;
    libCmdParam.cmd = SL_GET_PD_INFO;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = sizeof(MR_PD_INFO);
    libCmdParam.pData = pPdInfo;
    libCmdParam.pdRef.deviceId = deviceId;

    ret = ProcessLibCommandCall(libType, &libCmdParam);
    if (ret == SML_SUCCESS && pPdInfo->ref.deviceId != deviceId) {
        debug_log(DLOG_ERROR,
            "smlib: LSI:GetPDInfo failed, CtrlId = %d, deviceId = %u, returned deviceId = %u, device id is not match",
            SML_CTRL_ID_VALID_BIT(ctrl_id), deviceId, pPdInfo->ref.deviceId);
        return SML_ERR_DATA_INVALID;
    }

    return ret;
}

/*
 * Description: 读取PD的UserDataBlockSize，用于计算LD的实际大小
 * History: 2016-04-08   新生成函数
*/
guint16 GetBlockSizeOfPDInLD(guint32 ctrl_id, guint8 target_id)
{
    gint32 retval = SML_SUCCESS;
    SL_PD_IN_LD_T PdInLd;
    MR_PD_INFO PdInfo;
    guint32 idx = 0;
    guint16 block_size = 0;

    (void)memset_s(&PdInLd, sizeof(SL_PD_IN_LD_T), 0, sizeof(SL_PD_IN_LD_T));
    (void)memset_s(&PdInfo, sizeof(MR_PD_INFO), 0, sizeof(MR_PD_INFO));

    retval = GetPDInLD(ctrl_id, target_id, &PdInLd);
    if (SML_SUCCESS == retval) {
        for (idx = 0; idx < PdInLd.count; idx++) {
            retval = GetPDInfo(ctrl_id, PdInLd.deviceId[idx], &PdInfo);
            if (SML_SUCCESS == retval) {
                if (PdInfo.userDataBlockSize == 0) {
                    block_size = PD_BLOCK_SIZE_512;
                    continue;
                } else {
                    block_size = PdInfo.userDataBlockSize;
                    break;
                }
            } else {
                block_size = 0;
            }
        }
    } else {
        block_size = 0;
    }

    return block_size;
}

/*
 * Description: 通过AEN获取Event之后的解析接口
 * History: 2016-04-27  新生成函数
*/
static void GenerateEventTextInfo(FILE *fp, guint32 ctrl_id, const MR_EVT_DETAIL *evtDetail)
{
    gchar timeBuf[100] = { 0 };
    gchar tmpBuf[100] = { 0 };
    guint16 userDataBlockSize = 0;
    MR_PD_INFO pPdInfo;
    gint32 retval = SML_SUCCESS;

    if (NULL == fp || NULL == evtDetail) {
        return;
    }

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

    (void)fprintf(fp, "Event Sequence Number : %u\n", evtDetail->seqNum);

    InterpretTime(evtDetail->timeStamp, timeBuf, sizeof(timeBuf));
    (void)fprintf(fp, "Message Timestamp : %s\n", timeBuf);
    (void)memset_s(timeBuf, sizeof(timeBuf), 0, sizeof(timeBuf));
    (void)GetLocalTime(timeBuf, sizeof(timeBuf));
    (void)fprintf(fp, "Local Timestamp : %s\n", timeBuf);
    (void)fprintf(fp, "Event code : %u\n", evtDetail->code);

    (void)fprintf(fp, "Locale : ");

    switch (evtDetail->cl.locale) {
        case MR_EVT_LOCALE_LD:
            (void)fprintf(fp, "LD event\n");
            break;

        case MR_EVT_LOCALE_PD:
            (void)fprintf(fp, "PD event\n");
            break;

        case MR_EVT_LOCALE_ENCL:
            (void)fprintf(fp, "Enclosure event\n");
            break;

        case MR_EVT_LOCALE_BBU:
            (void)fprintf(fp, "BBU event\n");
            break;

        case MR_EVT_LOCALE_SAS:
            (void)fprintf(fp, "SAS event\n");
            break;

        case MR_EVT_LOCALE_CTRL:
            (void)fprintf(fp, "Controller event\n");
            break;

        case MR_EVT_LOCALE_CONFIG:
            (void)fprintf(fp, "Configuration change event\n");
            break;

        case MR_EVT_LOCALE_CLUSTER:
            (void)fprintf(fp, "Cluster event\n");
            break;

        case MR_EVT_LOCALE_ALL:
            (void)fprintf(fp, "All\n");
            break;

        default:
            if (evtDetail->code == MR_EVT_LD_CREATED || evtDetail->code == MR_EVT_LD_DELETED ||
                evtDetail->code == MR_EVT_LD_RECON_RESUME_FAILED) {
                (void)fprintf(fp, "LD event\n");
            }

            if (evtDetail->code == MR_EVT_PD_DEDICATED_SPARE_NO_LONGER_USEFUL ||
                evtDetail->code == MR_EVT_PD_SPARE_DEDICATED_CREATED ||
                evtDetail->code == MR_EVT_PD_SPARE_DEDICATED_DISABLED ||
                evtDetail->code == MR_EVT_PD_SPARE_DEDICATED_NOT_USEFUL_FOR_ALL_ARRAYS ||
                evtDetail->code == MR_EVT_PD_SPARE_GLOBAL_CREATED ||
                evtDetail->code == MR_EVT_PD_SPARE_GLOBAL_DISABLED ||
                evtDetail->code == MR_EVT_PD_SPARE_GLOBAL_NOT_COVERING_ALL_ARRAYS ||
                evtDetail->code == MR_EVT_PD_SPARE_DEDICATED_IMPORTED_AS_GLOBAL ||
                evtDetail->code == MR_EVT_PD_NO_REBUILD_SAS_SATA_MIX_NOT_ALLOWED_IN_LD ||
                evtDetail->code == MR_EVT_PD_SPARE_AFFINITY_IGNORED ||
                evtDetail->code == MR_EVT_PD_SAS_REDUNDANT_PATH_RESTORED ||
                evtDetail->code == MR_EVT_PD_SAS_REDUNDANT_PATH_BROKEN ||
                evtDetail->code == MR_EVT_PD_NO_COPYBACK_SAS_SATA_MIX_NOT_ALLOWED_IN_LD ||
                evtDetail->code == MR_EVT_PD_NO_REBUILD_HDD_SSD_MIX_NOT_ALLOWED_IN_LD ||
                evtDetail->code == MR_EVT_PD_NO_COPYBACK_HDD_SSD_MIX_NOT_ALLOWED_IN_LD ||
                evtDetail->code == MR_EVT_PD_SAS_WIDE_PORT_LINK_FAILURE ||
                evtDetail->code == MR_EVT_PD_SAS_WIDE_PORT_LINK_RESTORED ||
                evtDetail->code == MR_EVT_PD_NO_REBUILD_HDD_SSD_MIX_NOT_ALLOWED_IN_LD ||
                evtDetail->code == MR_EVT_PD_NO_COPYBACK_HDD_SSD_MIX_NOT_ALLOWED_IN_LD) {
                (void)fprintf(fp, "PD event\n");
            }

            if (evtDetail->code == MR_EVT_LD_CACHE_PINNED || evtDetail->code == MR_EVT_LD_CACHE_DESTAGED ||
                evtDetail->code == MR_EVT_CTRL_BOOT_LDS_CACHE_PINNED ||
                evtDetail->code == MR_EVT_CTRL_LDS_CACHE_DISCARDED_BY_USER ||
                evtDetail->code == MR_EVT_CTRL_CACHE_REBOOT_CANT_RECOVER) {
                (void)fprintf(fp, "Controller event\n");
            }

            if (evtDetail->code == MR_EVT_BBU_TBBU_DIRTY_CACHE_CONFIG_MISMATCH) {
                (void)fprintf(fp, "BBU event\n");
            }

            if (evtDetail->code == MR_EVT_PD_MARK_MISSING || evtDetail->code == MR_EVT_PD_REPLACE_MISSING) {
                (void)fprintf(fp, "Configuration change event\n");
            }

            break;
    }

    (void)fprintf(fp, "Class : ");

    switch (evtDetail->cl.eventClass + 2) { // +2 消除编译告警
        case MR_EVT_CLASS_DEBUG + 2:
            (void)fprintf(fp, "Debug information\n");
            break;

        case MR_EVT_CLASS_PROGRESS + 2:
            (void)fprintf(fp, "Rebuild/BGI/CC/FGI/Reconstruct progress posting\n");
            break;

        case MR_EVT_CLASS_INFO + 2:
            (void)fprintf(fp, "Information\n");
            break;

        case MR_EVT_CLASS_WARNING + 2:
            (void)fprintf(fp, "Warning\n");
            break;

        case MR_EVT_CLASS_CRITICAL + 2:
            (void)fprintf(fp, "Critical\n");
            break;

        case MR_EVT_CLASS_FATAL + 2:
            (void)fprintf(fp, "Fatal\n");
            break;

        case MR_EVT_CLASS_DEAD + 2:
            (void)fprintf(fp, "Dead (visible after next controller boot)\n");
            break;

        default:
            (void)fprintf(fp, "Undefined : %X\n", evtDetail->cl.eventClass);
            break;
    }

    (void)fprintf(fp, "Description of the event : %s\n", evtDetail->description);
    (void)fprintf(fp, "Argument Type Value: %u\n", evtDetail->argType);

    switch (evtDetail->argType) {
        case MR_EVT_ARGS_CDB_SENSE:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_CDB_SENSE\n");
            (void)fprintf(fp, "\tPhysical Device ID : 0x%X\n", evtDetail->args.cdbSense.pd.deviceId);
            (void)fprintf(fp, "\tEnclosure Index : %u\n", evtDetail->args.cdbSense.pd.enclIndex);
            (void)fprintf(fp, "\tSlot Number : %u\n", evtDetail->args.cdbSense.pd.slotNumber);
            (void)fprintf(fp, "\tLength of CDB : %u\n", evtDetail->args.cdbSense.cdbLength);
            (void)fprintf(fp, "\tLength of request sense data : %u\n", evtDetail->args.cdbSense.senseLength);
            (void)fprintf(fp, "\tCDB : \n");
            HexDump(fp, evtDetail->args.cdbSense.cdb, 16);
            (void)fprintf(fp, "\tSense Data :\n");
            HexDump(fp, evtDetail->args.cdbSense.sense, 64);
            break;

        case MR_EVT_ARGS_LD:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_LD\n");
            (void)fprintf(fp, "\tLogical Drive Target ID : %u\n", evtDetail->args.ld.targetId);
            (void)fprintf(fp, "\tFirmware LD Number : %u\n", evtDetail->args.ld.ldIndex);
            break;

        case MR_EVT_ARGS_LD_COUNT:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_LD_COUNT\n");
            (void)fprintf(fp, "\tLogical Drive Target ID : %u\n", evtDetail->args.ldCount.ld.targetId);
            (void)fprintf(fp, "\tFirmware LD Number : %u\n", evtDetail->args.ldCount.ld.ldIndex);
            (void)fprintf(fp, "\tCount : %u\n", evtDetail->args.ldCount.count);
            break;

        case MR_EVT_ARGS_LD_LBA:
            userDataBlockSize = GetBlockSizeOfPDInLD(ctrl_id, evtDetail->args.ldLba.ld.ldIndex);
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_LD_LBA\n");
            (void)fprintf(fp, "\tLBA : %llu MB\n",
                BLK2MB(evtDetail->args.ldLba.lba, userDataBlockSize)); // 4K Sector Changes 4KCheck
            (void)fprintf(fp, "\tLogical Drive Target ID : %u\n", evtDetail->args.ldLba.ld.targetId);
            (void)fprintf(fp, "\tFirmware LD Number : %u\n", evtDetail->args.ldLba.ld.ldIndex);
            break;

        case MR_EVT_ARGS_LD_OWNER:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_LD_OWNER\n");
            (void)fprintf(fp, "\tLogical Drive Target ID : %u\n", evtDetail->args.ldOwner.ld.targetId);
            (void)fprintf(fp, "\tFirmware LD Number : %u\n", evtDetail->args.ldOwner.ld.ldIndex);
            (void)fprintf(fp, "\tPrevious Owner : %u\n", evtDetail->args.ldOwner.prevOwner);
            (void)fprintf(fp, "\tNew Owner : %u\n", evtDetail->args.ldOwner.newOwner);
            break;

        case MR_EVT_ARGS_LD_LBA_PD_LBA:
            userDataBlockSize = GetBlockSizeOfPDInLD(ctrl_id, evtDetail->args.ldLba.ld.ldIndex);
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_LD_LBA_PD_LBA\n");
            (void)fprintf(fp, "\tLD LBA : %llu MB\n",
                BLK2MB(evtDetail->args.ldLbaPdLba.ldLba, userDataBlockSize)); // 4K Sector Changes 4KCheck
            (void)fprintf(fp, "\tPD LBA : %llu MB\n",
                BLK2MB(evtDetail->args.ldLbaPdLba.pdLba, userDataBlockSize)); // 4K Sector Changes 4KCheck
            (void)fprintf(fp, "\tLogical Drive Target ID : %u\n", evtDetail->args.ldLbaPdLba.ld.targetId);
            (void)fprintf(fp, "\tFirmware LD Number : %u\n", evtDetail->args.ldLbaPdLba.ld.ldIndex);
            (void)fprintf(fp, "\tPhysical Device ID : 0x%X\n", evtDetail->args.ldLbaPdLba.pd.deviceId);
            (void)fprintf(fp, "\tEnclosure Index : %u\n", evtDetail->args.ldLbaPdLba.pd.enclIndex);
            (void)fprintf(fp, "\tSlot Number : %u\n", evtDetail->args.ldLbaPdLba.pd.slotNumber);
            break;

        case MR_EVT_ARGS_LD_PROG:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_LD_PROG\n");
            (void)fprintf(fp, "\tLogical Drive Target ID : %u\n", evtDetail->args.ldProg.ld.targetId);
            (void)fprintf(fp, "\tFirmware LD Number : %u\n", evtDetail->args.ldProg.ld.ldIndex);
            (void)fprintf(fp, "\tProgress : %f\n", ((gfloat)evtDetail->args.ldProg.prog.progress / 0xffff) * 100);
            (void)fprintf(fp, "\tElapsed Seconds : %u\n", evtDetail->args.ldProg.prog.elapsedSecs);
            break;

        case MR_EVT_ARGS_LD_STATE:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_LD_STATE\n");
            (void)fprintf(fp, "\tLogical Drive Target ID : %u\n", evtDetail->args.ldState.ld.targetId);
            (void)fprintf(fp, "\tFirmware LD Number : %u\n", evtDetail->args.ldState.ld.ldIndex);
            (void)fprintf(fp, "\tPrevious State : %u\n", evtDetail->args.ldState.prevState);
            (void)fprintf(fp, "\tNew State : %u\n", evtDetail->args.ldState.newState);
            break;

        case MR_EVT_ARGS_LD_STRIP:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_STRIP\n");
            (void)fprintf(fp, "\tStrip : %-llu\n", evtDetail->args.ldStrip.strip);
            (void)fprintf(fp, "\tLogical Drive Target ID : %u\n", evtDetail->args.ldStrip.ld.targetId);
            (void)fprintf(fp, "\tFirmware LD Number : %u\n", evtDetail->args.ldStrip.ld.ldIndex);
            break;

        case MR_EVT_ARGS_PD:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_PD\n");
            (void)fprintf(fp, "\tPhysical Device ID : 0x%X\n", evtDetail->args.pd.deviceId);

            (void)fprintf(fp, "\tEnclosure Index : %u\n", evtDetail->args.pd.enclIndex);
            (void)fprintf(fp, "\tSlot Number : %u\n", evtDetail->args.pd.slotNumber);
            break;

        case MR_EVT_ARGS_PD_ERR:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_PD_ERR\n");
            (void)fprintf(fp, "\tPhysical Device ID : 0x%X\n", evtDetail->args.pdErr.pd.deviceId);
            (void)fprintf(fp, "\tEnclosure Index : %u\n", evtDetail->args.pdErr.pd.enclIndex);
            (void)fprintf(fp, "\tSlot Number : %u\n", evtDetail->args.pdErr.pd.slotNumber);
            (void)fprintf(fp, "\tError : %u\n", evtDetail->args.pdErr.err);
            break;

        case MR_EVT_ARGS_PD_LBA:
            retval = GetPDInfo(ctrl_id, evtDetail->args.pdLba.pd.deviceId, &pPdInfo);
            if (SML_SUCCESS == retval) {
                (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_PD_LBA\n");
                (void)fprintf(fp, "\tLBA : %llu MB\n",
                    BLK2MB(evtDetail->args.pdLba.lba, pPdInfo.userDataBlockSize)); // 4K Sector Changes 4KCheck
                (void)fprintf(fp, "\tPhysical Device ID : 0x%X\n", evtDetail->args.pdLba.pd.deviceId);
                (void)fprintf(fp, "\tEnclosure Index : %u\n", evtDetail->args.pdLba.pd.enclIndex);
                (void)fprintf(fp, "\tSlot Number : %u\n", evtDetail->args.pdLba.pd.slotNumber);
            }
            break;

        case MR_EVT_ARGS_PD_LBA_LD:
            retval = GetPDInfo(ctrl_id, evtDetail->args.pdLba.pd.deviceId, &pPdInfo);
            if (SML_SUCCESS == retval) {
                (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_PD_LBA_LD\n");
                (void)fprintf(fp, "\tLBA : %llu MB\n",
                    BLK2MB(evtDetail->args.pdLba.lba, pPdInfo.userDataBlockSize)); // 4K Sector Changes 4KCheck
                (void)fprintf(fp, "\tPhysical Device ID : 0x%X\n", evtDetail->args.pdLbaLd.pd.deviceId);
                (void)fprintf(fp, "\tEnclosure Index : %u\n", evtDetail->args.pdLbaLd.pd.enclIndex);
                (void)fprintf(fp, "\tSlot Number : %u\n", evtDetail->args.pdLbaLd.pd.slotNumber);
                (void)fprintf(fp, "\tLogical Drive Target ID : %u\n", evtDetail->args.pdLbaLd.ld.targetId);
                (void)fprintf(fp, "\tFirmware LD Number : %u\n", evtDetail->args.pdLbaLd.ld.ldIndex);
            }
            break;

        case MR_EVT_ARGS_PD_PROG:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_PD_PROG\n");
            (void)fprintf(fp, "\tPhysical Device ID : 0x%X\n", evtDetail->args.pdProg.pd.deviceId);
            (void)fprintf(fp, "\tEnclosure Index : %u\n", evtDetail->args.pdProg.pd.enclIndex);
            (void)fprintf(fp, "\tSlot Number : %u\n", evtDetail->args.pdProg.pd.slotNumber);
            (void)fprintf(fp, "\tProgress : %f\n", ((gfloat)evtDetail->args.pdProg.prog.progress / 0xffff) * 100);
            (void)fprintf(fp, "\tElapsed Seconds : %u\n", evtDetail->args.pdProg.prog.elapsedSecs);

            break;
        case MR_EVT_ARGS_PD_STATE:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_PD_STATE\n");
            (void)fprintf(fp, "\tPhysical Device ID : 0x%X\n", evtDetail->args.pdState.pd.deviceId);
            (void)fprintf(fp, "\tEnclosure Index : %u\n", evtDetail->args.pdState.pd.enclIndex);
            (void)fprintf(fp, "\tSlot Number : %u\n", evtDetail->args.pdState.pd.slotNumber);
            (void)fprintf(fp, "\tPrevious State : %x\n", evtDetail->args.pdState.prevState);
            (void)fprintf(fp, "\tNew State : %x\n", evtDetail->args.pdState.newState);
            break;

        case MR_EVT_ARGS_PCI:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_PCI\n");
            (void)fprintf(fp, "\tVendor ID : 0x%X\n", evtDetail->args.pci.vendorId);
            (void)fprintf(fp, "\tDevice ID : 0x%X\n", evtDetail->args.pci.deviceId);
            (void)fprintf(fp, "\tSub-Vendor ID : 0x%X\n", evtDetail->args.pci.subVendorId);
            (void)fprintf(fp, "\tSub-Device ID : 0x%X\n", evtDetail->args.pci.subDeviceId);
            break;

        case MR_EVT_ARGS_RATE:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_RATE\n");
            (void)fprintf(fp, "\tRate : %u\n", evtDetail->args.rate);
            break;

        case MR_EVT_ARGS_STR:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_STR\n");
            (void)fprintf(fp, "\tString : %s\n", evtDetail->args.str);
            break;

        case MR_EVT_ARGS_TIME:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_TIME\n");
            InterpretTime(evtDetail->args.time.rtc, timeBuf, sizeof(timeBuf));
            (void)fprintf(fp, "\tRTC : %s\n", timeBuf);
            (void)fprintf(fp, "\tElapsed Seconds since power-on : %u\n", evtDetail->args.time.elapsedSeconds);
            break;

        case MR_EVT_ARGS_PD_ADDRESS:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_PD_ADDRESS\n");
            (void)fprintf(fp, "\tPhysical Device ID : 0x%X\n", evtDetail->args.pdAddr.deviceId);
            (void)fprintf(fp, "\tEnclosure DeviceID : %u\n", evtDetail->args.pdAddr.enclDeviceId);
            (void)fprintf(fp, "\tScsi Device Type : %u\n", evtDetail->args.pdAddr.scsiDevType);
            (void)memset_s(tmpBuf, sizeof(tmpBuf), 0, sizeof(tmpBuf));
            format_sas_addr(evtDetail->args.pdAddr.sasAddr[0], tmpBuf, sizeof(tmpBuf));
            (void)fprintf(fp, "\tSas Addr for port 0 : %s\n", tmpBuf);
            (void)memset_s(tmpBuf, sizeof(tmpBuf), 0, sizeof(tmpBuf));
            format_sas_addr(evtDetail->args.pdAddr.sasAddr[1], tmpBuf, sizeof(tmpBuf));
            (void)fprintf(fp, "\tSas Addr for port 1 : %s\n", tmpBuf);

            (void)fprintf(fp, "\tEnclosure Index : %u\n", evtDetail->args.pdAddr.enclIndex);
            (void)fprintf(fp, "\tSlot Number : %u\n", evtDetail->args.pdAddr.slotNumber);

            (void)fprintf(fp, "\tConnected port numbers : ");
            /* BEGIN: Modified on 2019/4/25 14:8:18   问题单号:UADP202927 */
            guint32 i = 0;
            guint32 j = 0;
            /* END:   Modified on 2019/4/25 11:49:22 */

            for (i = 1, j = 0; j < 8; j++) {
                if (evtDetail->args.pdAddr.connectedPortBitmap & i) {
                    (void)fprintf(fp, "%u , ", j);
                }

                i = i * 2;
            }

            (void)fprintf(fp, "\n");
            break;

        case MR_EVT_ARGS_PD_PATHINFO:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_PD_PATHINFO\n");
            (void)fprintf(fp, "\tPhysical Device ID : 0x%X\n", evtDetail->args.pdPathInfo.pd.deviceId);
            (void)fprintf(fp, "\tEnclosure Index : %u\n", evtDetail->args.pdPathInfo.pd.enclIndex);
            (void)fprintf(fp, "\tSlot Number : %u\n", evtDetail->args.pdPathInfo.pd.slotNumber);

            if ((evtDetail->code == MR_EVT_PD_SAS_REDUNDANT_PATH_RESTORED) ||
                (evtDetail->code == MR_EVT_PD_SAS_REDUNDANT_PATH_BROKEN)) {
                (void)fprintf(fp, "\tPath : %u\n", evtDetail->args.pdPathInfo.path);
            } else {
                (void)fprintf(fp, "\tError : %u\n", evtDetail->args.pdPathInfo.err);
            }

            (void)memset_s(tmpBuf, sizeof(tmpBuf), 0, sizeof(tmpBuf));
            format_sas_addr(evtDetail->args.pdPathInfo.sasAddr, tmpBuf, sizeof(tmpBuf));
            (void)fprintf(fp, "\tSAS Addr : %s\n", tmpBuf);
            break;

        case MR_EVT_ARGS_PD_PD:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_PD_PD\n");
            (void)fprintf(fp, "\tSrc Physical Device ID : 0x%X\n", evtDetail->args.pdPair.srcPd.deviceId);
            (void)fprintf(fp, "\tEnclosure Index : %u\n", evtDetail->args.pdPair.srcPd.enclIndex);
            (void)fprintf(fp, "\tSlot Number : %u\n", evtDetail->args.pdPair.srcPd.slotNumber);
            (void)fprintf(fp, "\tDest Physical Device ID : 0x%X\n", evtDetail->args.pdPair.destPd.deviceId);
            (void)fprintf(fp, "\tEnclosure Index : %u\n", evtDetail->args.pdPair.destPd.enclIndex);
            (void)fprintf(fp, "\tSlot Number : %u\n", evtDetail->args.pdPair.destPd.slotNumber);
            break;

        case MR_EVT_ARGS_PD_FRU:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_PD_FRU\n");
            (void)fprintf(fp, "\tPhysical Device ID : 0x%X\n", evtDetail->args.pdFRU.pd.deviceId);
            (void)fprintf(fp, "\tEnclosure Index : %u\n", evtDetail->args.pdFRU.pd.enclIndex);
            (void)fprintf(fp, "\tSlot Number : %u\n", evtDetail->args.pdFRU.pd.slotNumber);
            (void)fprintf(fp, "\tFRU : %s\n", evtDetail->args.pdFRU.FRU);
            break;

        case MR_EVT_ARGS_LD_PROP:
            (void)fprintf(fp, "Argument Type : MR_EVT_ARGS_LD_PROP\n");
            (void)fprintf(fp, "\tLogical Device ID : 0x%X\n", evtDetail->args.ldProp.ld.targetId);
            (void)fprintf(fp, "\tLD New Disk Cache Pplicy : 0x%X\n", evtDetail->args.ldProp.newProp.diskCachePolicy);
            (void)fprintf(fp, "\tLD OLD Disk Cache Pplicy : 0x%X\n", evtDetail->args.ldProp.prevProp.diskCachePolicy);
            break;

        default:
            (void)fprintf(fp, "Alternate argument access via byte : \n");
            HexDump(fp, evtDetail->args.b, 96);
            break;
    }

    (void)fprintf(fp, "\n\n");

    return;
}

/*
    * 函 数 名  : handle_event_info
    * 功能描述  : 调用app层的函数，对event信息进行处理
*/
static void handle_event_info(const MR_EVT_DETAIL *evtDetail)
{
    if (evtDetail == NULL) {
        return;
    }

    if ((evtDetail->code != EVENT_CODE_UNEXPECTED_SENSE) && (evtDetail->code != EVENT_CODE_COMMAND_TIMEOUT)
        && (evtDetail->code != EVENT_CODE_RESET_TYPE) && (evtDetail->code != EVENT_CODE_POWER_RESET)) {
        return;
    }
    SML_EVENT_DETAIL sml_evt_detail = {0};
    guint8 slot_num = 0;
    switch (evtDetail->argType) {
        case MR_EVT_ARGS_CDB_SENSE:
            slot_num = evtDetail->args.cdbSense.pd.slotNumber;
            break;
        case MR_EVT_ARGS_PD_ERR:
            slot_num = evtDetail->args.pdErr.pd.slotNumber;
            break;
        default:
            debug_log(DLOG_DEBUG, "%s: event code : %u evtDetail->argType:%u",
                __FUNCTION__, evtDetail->code, evtDetail->argType);
            return;
    }
    sml_evt_detail.pd_event.code = evtDetail->code;
    sml_evt_detail.pd_event.slot_num = slot_num;
    if (!g_handle_event_info_func) {
        debug_log(DLOG_ERROR, "%s: g_handle_event_info_func is NULL", __FUNCTION__);
        return;
    }
    gint32 ret = g_handle_event_info_func(&sml_evt_detail);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "%s: handle event info failed, ret = %d", __FUNCTION__, ret);
    }
    return;
}
 
/*
    * 函 数 名  : lsi_register_event_handler
    * 功能描述  : 注册pfnHandleEventInfo函数给smlib层调用
*/
gint32 lsi_register_event_handler(HANDLE_EVENT_INFO_FUNC event_handler)
{
    if (event_handler != NULL) {
        g_handle_event_info_func = event_handler;
        return SML_SUCCESS;
    }
    debug_log(DLOG_ERROR, "%s: invalid input", __FUNCTION__);
    return SML_ERR_INVALID_PARAMETER;
}

/*
 * Description: AEN机制的回调接口
 * History: 2016-04-27  新生成函数
*/
static gint32 AENCallBack(SL_EVENT_DETAIL_T *pEventDetail)
{
    gint32 ret;
    gchar evtFileName[128] = { 0 };
    guint32 ctrlId = 0;

    if (pEventDetail == NULL) {
        debug_log(DLOG_ERROR, "AENCallBack : Event Details is NULL\n");
        return SML_ERR_NULL_DATA;
    }

    if (pEventDetail->status != SL_SUCCESS) {
        debug_log(DLOG_DEBUG, "AENCallBack : Event Status 0x%X\n", pEventDetail->status);
        return pEventDetail->status;
    }

    ret = snprintf_s(evtFileName, sizeof(evtFileName), sizeof(evtFileName) - 1, "%s/%s_%s", SML_EVENT_LOG_PATH, "LSI",
        SML_EVENT_LOG_NAME);
    if (ret <= 0) {
        debug_log(DLOG_ERROR, "%s: snprintf_s failed, ret = %d", __FUNCTION__, ret);
        return SML_ERR_SEC_FUNC_FAILED;
    }

    FILE *fp = fopen_s(evtFileName, "a", evtFileName);

    if (fp == NULL) {
        debug_log(DLOG_ERROR, "AENCallBack : Open event log file %s failed\n", evtFileName);
        return SML_ERR_CANNOT_OPEN_FILE;
    }

    (void)fchmod(fileno(fp), 0600);

    ctrlId = pEventDetail->ctrlId & SL_CTRL_ID_MASK;
    (void)fprintf(fp, "Controller ID : %u\n", ctrlId);
    (void)fprintf(fp, "Registration ID : %u\n", pEventDetail->registrationId);

    (pEventDetail->isNonPersistent) ? (void)fprintf(fp, "NonPersistent\n") : (void)fprintf(fp, "Persistent\n");

    GenerateEventTextInfo(fp, pEventDetail->ctrlId, &pEventDetail->evtDetail);

    (void)fclose_s(fp);
    handle_event_info(&pEventDetail->evtDetail);
    /* 记录日志用于诊断 */
    RecordCtrlDiagEvent(ctrlId, &pEventDetail->evtDetail);

    return pEventDetail->status;
}

/*
 * Description: 向storelib发送AEN注册命令
 * History: 2016-04-27  新生成函数
*/
static gint32 RegisterAENCall(guint32 ctrl_id, SL_REG_AEN_INPUT_T *pRegAENInput, SL_REG_AEN_OUTPUT_T *pRegAENOutput)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;

    if (NULL == pRegAENInput || NULL == pRegAENOutput) {
        return SML_ERR_NULL_DATA;
    }

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

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

    libCmdParam.cmdType = SL_SYSTEM_CMD_TYPE;
    libCmdParam.cmd = SL_REGISTER_AEN;
    libCmdParam.pCmdParam = pRegAENInput;
    libCmdParam.dataSize = SL_REG_AEN_OUTPUT_S;
    libCmdParam.pData = pRegAENOutput;

    return ProcessLibCommandCall(libType, &libCmdParam);
}

/*
 * Description: 向storelib注册AEN
 * History: 2016-04-27  新生成函数
*/
static gint32 RegisterAEN(SL_CTRL_LIST_T *pCtrlList)
{
    gint32 retval = SML_SUCCESS;
    guint32 i = 0, j = 0, k = 0;
    SL_REG_AEN_INPUT_T regAENInput;
    SL_REG_AEN_OUTPUT_T regAENOutput;

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

    if (gRegCount >= SL_MAX_AEN_REGISTRATIONS) {
        debug_log(DLOG_ERROR, "smlib: LSI:RegisterAEN maximum AEN registration limit reached\n");
        return SML_ERR_EXCEED_LIMIT;
    }

    (void)memset_s(&regAENInput, SL_REG_AEN_INPUT_S, 0, SL_REG_AEN_INPUT_S);
    (void)memset_s(&regAENOutput, SL_REG_AEN_OUTPUT_S, 0, SL_REG_AEN_OUTPUT_S);

    regAENInput.count = pCtrlList->count;

    j = 0;

    for (i = 0; i < MIN(regAENInput.count, SL_MAX_CONTROLLERS); i++) {
        for (; j < SL_MAX_CONTROLLERS; j++) {
            if (pCtrlList->ctrlId[j] != INVALID_CTRL_ID) {
                break;
            }
        }

        if (j == SL_MAX_CONTROLLERS) {
            debug_log(DLOG_ERROR, "smlib: LSI:RegisterAEN not found valid controller ID\n");
            return SML_ERR_EXCEED_LIMIT;
        }

        regAENInput.regAenInfo[i].ctrlId = LSI_CTRL_ID_RESVED_BIT_MASK(pCtrlList->ctrlId[j]);
        regAENInput.regAenInfo[i].eventMask.locale = MR_EVT_LOCALE_ALL;
        regAENInput.regAenInfo[i].eventMask.eventClass = MR_EVT_CLASS_INFO;
        regAENInput.regAenInfo[i].eventMask.oobLocale = 0;
        debug_log(DLOG_DEBUG, "smlib: LSI:RegisterAEN Info[%d] controller ID %d\n", i, pCtrlList->ctrlId[j]);
        j++;
    }

    regAENInput.pFunc = &AENCallBack;

    retval = RegisterAENCall(regAENInput.regAenInfo[0].ctrlId, &regAENInput, &regAENOutput);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "smlib: LSI:RegisterAEN failed, return 0x%0x\n", retval);
        return retval;
    }

    for (k = 0; k < SL_MAX_AEN_REGISTRATIONS; k++) {
        if (gRegistrationInfo[k].valid == 0) {
            gRegistrationInfo[k].valid = 1;
            break;
        }
    }

    if (k == SL_MAX_AEN_REGISTRATIONS) {
        debug_log(DLOG_ERROR, "smlib: LSI:RegisterAEN maximum AEN registration limit reached\n");
        return SML_ERR_EXCEED_LIMIT;
    }

    gRegistrationInfo[k].regAenOutput = regAENOutput;

    debug_log(DLOG_DEBUG, "smlib: LSI:RegisterAEN RegistrationInfo[%d] count %d\n", k, regAENOutput.regCtrlCount);

    for (i = 0; i < regAENOutput.regCtrlCount; i++) {
        for (j = 0; j < MIN(regAENInput.count, SL_MAX_CONTROLLERS); j++) {
            if (regAENOutput.regCtrlId[i] == regAENInput.regAenInfo[j].ctrlId) {
                gRegistrationInfo[k].eventMask[i] = regAENInput.regAenInfo[j].eventMask;
                break;
            }
        }
    }

    debug_log(DLOG_DEBUG, "smlib: LSI:RegisterAEN registration info %d unique ID %d\n", k, regAENOutput.uniqueId);

    gRegCount++;

    return retval;
}

/*
 * Description: 向storelib发送AEN解除注册命令
 * History: 2016-04-27   新生成函数
*/
static gint32 UnRegisterAENCall(guint32 ctrl_id, guint32 unique_id)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

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

    libCmdParam.cmdType = SL_SYSTEM_CMD_TYPE;
    libCmdParam.cmd = SL_UNREGISTER_AEN;
    libCmdParam.cmdParam_4b[0] = unique_id;

    return ProcessLibCommandCall(libType, &libCmdParam);
}

/*
 * Description: 解除AEN注册
 * History: 2016年4月27日  新生成函数
*/
static gint32 UnRegisterAEN(void)
{
    gint32 retval = SML_SUCCESS;
    guint32 i;
    gint8 retryCount = 3;

    for (i = 0; i < SL_MAX_AEN_REGISTRATIONS; i++) {
        if (gRegistrationInfo[i].valid == 1) {
            retryCount = 3;

            while (retryCount-- > 0) {
                retval = UnRegisterAENCall(gRegistrationInfo[i].regAenOutput.regCtrlId[0],
                    gRegistrationInfo[i].regAenOutput.uniqueId);
                if (SL_SUCCESS != retval) {
                    vos_task_delay(5000);
                } else {
                    gRegistrationInfo[i].valid = 0;
                    gRegCount--;
                    debug_log(DLOG_DEBUG, "UnregisterAEN[%u].%u Successful\n", i,
                        gRegistrationInfo[i].regAenOutput.uniqueId);
                    break;
                }

                debug_log(DLOG_ERROR, "UnregisterAEN[%u].%u Failed, return 0x%04X\n", i,
                    gRegistrationInfo[i].regAenOutput.uniqueId, retval);
            }
        }
    }

    return SML_SUCCESS;
}

/*
 * Description: 初始化LSI RAID控制器的互斥锁
*/
static void lsi_mutex_init(void)
{
    guint32 i = 0;
    static guint8 sl_mutex_init = FALSE;
    if (FALSE == sl_mutex_init) {
        sl_mutex_init = TRUE;
        for (i = 0; i < sizeof(gLSICtrlMutex) / sizeof(gLSICtrlMutex[0]); i++) {
            g_mutex_init(&gLSICtrlMutex[i]);
        }
    }
    return;
}

/*
 * Description: 添加RAID控制器到管理列表中
 * History: 2016年6月15日  新生成函数
 *          2018年12月4日  修改支持热插拔
*/
gint32 lsi_add_ctrl(guint32 ctrl_id)
{
    guint32 idx = 0;
    guint8 libType = 0;

    lsi_mutex_init();
    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);
    debug_log(DLOG_DEBUG, "ADD Ctrl 0x%08x\n", ctrl_id);

    if (libType == SL_LIB_TYPE_STORELIB) {
        g_mutex_lock(&gLSICtrlMutex[libType]);
        if (gLSICtrlListMR.count == 0) {
            (void)memset_s(gLSICtrlListMR.ctrlId, sizeof(gLSICtrlListMR.ctrlId), 0xFF, sizeof(gLSICtrlListMR.ctrlId));
        }

        for (idx = 0; idx < SL_MAX_CONTROLLERS; idx++) {
            if (ctrl_id == gLSICtrlListMR.ctrlId[idx]) {
                break;
            }
            // 重新添加的时候count不需要累加
            if (INVALID_CTRL_ID == gLSICtrlListMR.ctrlId[idx]) {
                gLSICtrlListMR.count++;
                gSLMrInit = FALSE;
                break;
            }
        }

        if (idx == SL_MAX_CONTROLLERS) {
            g_mutex_unlock(&gLSICtrlMutex[libType]);
            return SML_ERR_EXCEED_LIMIT;
        }

        gLSICtrlListMR.ctrlId[idx] = ctrl_id;
        g_mutex_unlock(&gLSICtrlMutex[libType]);
    } else if (libType == SL_LIB_TYPE_STORELIBIR) {
        if (gLSICtrlListIR.count == 0) {
            (void)memset_s(gLSICtrlListIR.ctrlId, sizeof(gLSICtrlListIR.ctrlId), 0xFF, sizeof(gLSICtrlListIR.ctrlId));
        }
    } else if (libType == SL_LIB_TYPE_STORELIBIR_2) {
        if (gLSICtrlListIR2.count == 0) {
            (void)memset_s(gLSICtrlListIR2.ctrlId, sizeof(gLSICtrlListIR2.ctrlId), 0xFF,
                sizeof(gLSICtrlListIR2.ctrlId));
        }
    } else if (libType == SL_LIB_TYPE_STORELIBIR_3) {
        if (gLSICtrlListIR3.count == 0) {
            (void)memset_s(gLSICtrlListIR3.ctrlId, sizeof(gLSICtrlListIR3.ctrlId), 0xFF,
                sizeof(gLSICtrlListIR3.ctrlId));
        }

        for (idx = 0; idx < SL_MAX_CONTROLLERS; idx++) {
            if (ctrl_id == gLSICtrlListIR3.ctrlId[idx]) {
                break;
            }
            // 重新添加的时候count不需要累加

            if (INVALID_CTRL_ID == gLSICtrlListIR3.ctrlId[idx]) {
                gLSICtrlListIR3.count++;
                break;
            }
        }

        if (idx == SL_MAX_CONTROLLERS) {
            return SML_ERR_EXCEED_LIMIT;
        }

        gLSICtrlListIR3.ctrlId[idx] = ctrl_id;
    } else if (libType == SL_LIB_TYPE_STORELIBIT) {
        if (gLSICtrlListIT.count == 0) {
            (void)memset_s(gLSICtrlListIT.ctrlId, sizeof(gLSICtrlListIT.ctrlId), 0xFF, sizeof(gLSICtrlListIT.ctrlId));
        }

        for (idx = 0; idx < SL_MAX_CONTROLLERS; idx++) {
            if (ctrl_id == gLSICtrlListIT.ctrlId[idx]) {
                break;
            }
            // 重新添加的时候count不需要累加

            if (INVALID_CTRL_ID == gLSICtrlListIT.ctrlId[idx]) {
                gLSICtrlListIT.count++;
                break;
            }
        }

        if (idx == SL_MAX_CONTROLLERS) {
            return SML_ERR_EXCEED_LIMIT;
        }

        gLSICtrlListIT.ctrlId[idx] = ctrl_id;
    } else if (libType == SL_LIB_TYPE_STORELIBCUSTOM) {
        if (gLSICtrlListCustom.count == 0) {
            (void)memset_s(gLSICtrlListCustom.ctrlId, sizeof(gLSICtrlListCustom.ctrlId), 0xFF,
                sizeof(gLSICtrlListCustom.ctrlId));
        }
 
        for (idx = 0; idx < SL_MAX_CONTROLLERS; idx++) {
            if (ctrl_id == gLSICtrlListCustom.ctrlId[idx]) {
                break;
            }
            // 重新添加的时候count不需要累加
 
            if (INVALID_CTRL_ID == gLSICtrlListCustom.ctrlId[idx]) {
                gLSICtrlListCustom.count++;
                break;
            }
        }
 
        if (idx == SL_MAX_CONTROLLERS) {
            return SML_ERR_EXCEED_LIMIT;
        }
 
        gLSICtrlListCustom.ctrlId[idx] = ctrl_id;
    }

    return SML_SUCCESS;
}

/*
 * Description: 初始化storelib的公共入口函数
 * History: 2016年3月3日  新生成函数
 *          2018年9月1日  日志优化
*/
static gint32 InitializeStorelib(guint8 libType, SL_CTRL_LIST_T *pctrl)
{
    SL_LIB_CMD_PARAM_T libCmdParam;

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

    libCmdParam.cmdType = SL_SYSTEM_CMD_TYPE;
    libCmdParam.cmd = SL_INIT_LIB;
    libCmdParam.dataSize = SL_CTRL_LIST_S;
    libCmdParam.pData = pctrl;
    libCmdParam.AppsSupportEXTConfig = 1;

    return ProcessLibCommandCall(libType, &libCmdParam);
}

/*
 * Description: 获取RAID控制器firmware的OOB状态
 * History: 2016年3月21日  新生成函数
 *          2018年9月1日  优化错误打印，10分钟打印一条
*/
static gint32 GetOOBStatus(guint32 ctrl_id)
{
    MFI_REG_STATE regState;
    SL_LIB_CMD_PARAM_T lcp;
    SL_DCMD_INPUT_T dcmdInput;
    guint8 retry = 0;
    guint8 libType = 0;
    gint32 retval = SL_SUCCESS;
    guint32 fwState = 0;
    gchar errorBuffer[256];

    (void)memset_s(&regState, sizeof(MFI_REG_STATE), 0, sizeof(MFI_REG_STATE));
    (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);

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    dcmdInput.opCode = MR_DCMD_OOB_STATUS;
    dcmdInput.dataTransferLength = sizeof(MFI_REG_STATE);
    dcmdInput.flags = SL_DIR_READ;
    dcmdInput.pData = &regState;

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

    do {
        (void)memset_s(errorBuffer, sizeof(errorBuffer), 0, sizeof(errorBuffer));
        if (SL_SUCCESS != (retval = ProcessLibCommandCall(libType, &lcp))) {
            if (retval == SL_ERR_OOB_SUSPENDED_STATE) {
                (void)snprintf_s(errorBuffer, sizeof(errorBuffer), sizeof(errorBuffer) - 1,
                    "LSI RAID controller firmware OOB in Suspended state\n");
            } else {
                (void)snprintf_s(errorBuffer, sizeof(errorBuffer), sizeof(errorBuffer) - 1,
                    "ProcessLibCommandCall [GetOOBStatus] Failed. retval = 0x%x\n", retval);
            }
        } else {
            retval = SML_ERR_CTRL_STATUS_INVALID;
            fwState = regState.reg & 0x0000000F;

            switch (fwState) {
                case MFI_STATE_UNDEFINED:
                    (void)snprintf_s(errorBuffer, sizeof(errorBuffer), sizeof(errorBuffer) - 1,
                        "LSI RAID Firmware in Undefined state.\n");
                    break;

                case MFI_STATE_BB_INIT:
                    (void)snprintf_s(errorBuffer, sizeof(errorBuffer), sizeof(errorBuffer) - 1,
                        "LSI RAID Firmware in Boot Block Init state.\n");
                    break;

                case MFI_STATE_FW_INIT:
                    (void)snprintf_s(errorBuffer, sizeof(errorBuffer), sizeof(errorBuffer) - 1,
                        "LSI RAID Firmware is initializing.\n");
                    break;

                case MFI_STATE_WAIT_HANDSHAKE:
                    (void)snprintf_s(errorBuffer, sizeof(errorBuffer), sizeof(errorBuffer) - 1,
                        "LSI RAID Firmware waiting for handshake to continue.\n");
                    break;

                case MFI_STATE_FW_INIT_2:
                    (void)snprintf_s(errorBuffer, sizeof(errorBuffer), sizeof(errorBuffer) - 1,
                        "LSI RAID Firmware is intializing (post handshake).\n");
                    break;

                case MFI_STATE_DEVICE_SCAN:
                    (void)snprintf_s(errorBuffer, sizeof(errorBuffer), sizeof(errorBuffer) - 1,
                        "LSI RAID Firmware scanning and initializing attached devices.\n");
                    break;

                case MFI_STATE_BOOT_MSG_PENDING:
                    (void)snprintf_s(errorBuffer, sizeof(errorBuffer), sizeof(errorBuffer) - 1,
                        "LSI RAID Firmware has boot messages pending for BIOS to process.\n");
                    break;

                case MFI_STATE_FLUSH_CACHE:
                    (void)snprintf_s(errorBuffer, sizeof(errorBuffer), sizeof(errorBuffer) - 1,
                        "LSI RAID Firmware is flushing dirty data to cache.\n");
                    break;

                case MFI_STATE_READY:
                    (void)snprintf_s(errorBuffer, sizeof(errorBuffer), sizeof(errorBuffer) - 1,
                        "LSI RAID Firmware ready to receive cmds - response queue not valid.\n");
                    retval = SML_SUCCESS;
                    break;

                case MFI_STATE_OPERATIONAL:
                    (void)snprintf_s(errorBuffer, sizeof(errorBuffer), sizeof(errorBuffer) - 1,
                        "LSI RAID Firmware operational - response queue valid.\n");
                    retval = SML_SUCCESS;
                    break;

                case MFI_STATE_FAULT:
                    (void)snprintf_s(errorBuffer, sizeof(errorBuffer), sizeof(errorBuffer) - 1,
                        "LSI RAID Firmware state: fault condition occurred.\n");
                    break;

                default:
                    (void)snprintf_s(errorBuffer, sizeof(errorBuffer), sizeof(errorBuffer) - 1,
                        "LSI RAID Firmware in Unknown state.\n");
                    break;
            }
        }

        if (retval != SML_SUCCESS) {
            vos_task_delay(5000);
        } else {
            break;
        }

        retry++;
    } while (retry < 3);
    lsi_init_debug_log(DLOG_ERROR, "LSI RAID [CtrlId : %d] GetOOBStatus %d: %s", SML_CTRL_ID_VALID_BIT(ctrl_id), retry,
        errorBuffer);

    return retval;
}

/*
 * Description: 获取拓扑结构数据
 * History: 2018年10月31日  新生成函数 AR.SR.SFEA02130924.009.011
*/
gint32 GetTopologyInfo(guint32 ctrl_id, guint32 buff_len, void *topology_buffer)
{
    gint32 rval = SL_SUCCESS;
    SL_LIB_CMD_PARAM_T libCmdParam;
    guint8 libType = 0;

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

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);
    (void)memset_s(&libCmdParam, sizeof(SL_LIB_CMD_PARAM_T), 0, sizeof(SL_LIB_CMD_PARAM_T));
    libCmdParam.cmdType = SL_CTRL_CMD_TYPE;
    libCmdParam.cmd = SL_GET_TOPOLOGY_INFO;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = buff_len;
    libCmdParam.pData = topology_buffer;

    rval = ProcessLibCommandCall(libType, &libCmdParam);

    return rval;
}

/*
 * Description: 发送命令给storelib获取LD的基本信息
 * History: 2016年3月10日  新生成函数
*/
gint32 GetLDInfo(guint32 ctrl_id, guint8 target_id, MR_LD_INFO *pLdInfo)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;
    gint32 ret;

    if (NULL == pLdInfo) {
        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_GET_LD_INFO;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = sizeof(MR_LD_INFO);
    libCmdParam.pData = pLdInfo;
    libCmdParam.ldRef.targetId = target_id;

    ret = ProcessLibCommandCall(libType, &libCmdParam);
    if (ret == SML_SUCCESS && target_id != pLdInfo->ldConfig.properties.ldRef.targetId) {
        debug_log(DLOG_ERROR,
            "smlib: LSI:GetLDInfo failed, CtrlId = %d, TargetId = %d, returned TargetId = %d, target id is not match",
            SML_CTRL_ID_VALID_BIT(ctrl_id), target_id, pLdInfo->ldConfig.properties.ldRef.targetId);
        return SML_ERR_DATA_INVALID;
    }

    return ret;
}

/*
 * Description: 发送命令给storelib获取LD中的PD列表
 * History: 2016年3月11日  新生成函数
*/
gint32 GetPDInLD(guint32 ctrl_id, guint8 target_id, SL_PD_IN_LD_T *pLdInfo)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;
    gint32 ret;

    if (NULL == pLdInfo) {
        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_GET_PD_IN_LD;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = sizeof(SL_PD_IN_LD_T);
    libCmdParam.pData = pLdInfo;
    libCmdParam.ldRef.targetId = target_id;

    ret = ProcessLibCommandCall(libType, &libCmdParam);
    if (ret == SML_SUCCESS) {
        if (pLdInfo->count >= SML_MAX_PHYSICAL_DRIVES) {
            debug_log(DLOG_ERROR,
                "smlib: LSI:GetPDInLD failed, CtrlId = %d, returned count = %u, count is larger than %d",
                SML_CTRL_ID_VALID_BIT(ctrl_id), pLdInfo->count, SML_MAX_PHYSICAL_DRIVES);
            return SML_ERR_DATA_INVALID;
        }

        if (check_duplicate_pd_id(pLdInfo->deviceId, (gsize)pLdInfo->count, GET_ARRAY_ITEMS(pLdInfo->deviceId)) !=
            SML_SUCCESS) {
            debug_log(DLOG_ERROR,
                "smlib: LSI:GetPDInLD failed, check duplicate pd id failed, CtrlId = %d, TargetId = %d",
                SML_CTRL_ID_VALID_BIT(ctrl_id), target_id);
            return SML_ERR_DATA_INVALID;
        }
    }
    return ret;
}

/*
 * Description: 发送命令给storelib获取RAID控制器的信息
 * History: 2016年3月7日  新生成函数
*/
gint32 GetCtrlInfo(guint32 ctrl_id, MR_CTRL_INFO *pCtrlInfo)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;

    if (NULL == pCtrlInfo) {
        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_CTRL_CMD_TYPE;
    libCmdParam.cmd = SL_GET_CTRL_INFO;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = sizeof(MR_CTRL_INFO);
    libCmdParam.pData = pCtrlInfo;

    return ProcessLibCommandCall(libType, &libCmdParam);
}

/*
 * Description: 检查逻辑盘是否存在
 */
guint32 check_ld_exist(guint32 ctrl_id, guint8 target_id)
{
    guint8 *targetIdList = NULL;
    guint8 ld_count = 0;
    gint32 ret;
    int i;

    // 获取逻辑盘列表
    targetIdList = (guint8 *)g_malloc0(SML_MAX_NUM_OF_IDS * sizeof(guint8));
    if (targetIdList == NULL) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    ret = GetLDListQuery(ctrl_id, targetIdList, MR_LD_QUERY_TYPE_USED_TGT_IDS, &ld_count);
    if (ret != SML_SUCCESS) {
        g_free(targetIdList);
        return FALSE;
    }
    // 查询逻辑盘列表中有没有预期id
    for (i = 0; i < ld_count; i++) {
        if (targetIdList[i] == target_id) {
            g_free(targetIdList);
            return TRUE;
        }
    }

    g_free(targetIdList);
    return FALSE;
}
 

/*
 * Description: 执行创建逻辑盘的LSI命令
 * History: 2016年11月5日  新生成函数
*/
gint32 AddConfig(guint32 ctrl_id, MR_CONFIG_DATA *pConfigData, guint32 config_size, guint16 target_id)
{
    gint32 retval;
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;

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

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

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

    // 执行 SL_ADD_CONFIG 命令
    libCmdParam.cmdType = SL_CONFIG_CMD_TYPE;
    libCmdParam.cmd = SL_ADD_CONFIG;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = config_size;
    libCmdParam.pData = pConfigData;

    retval = ProcessLibCommandCall(libType, &libCmdParam);
    /* storelib的resume机制会导致概率性出现创建逻辑盘失败，返回0x4或者0xc，但实际创建成功的问题 */
    if (retval == MFI_STAT_INVALID_SEQUENCE_NUMBER || retval == MFI_STAT_DEVICE_NOT_FOUND ||
        retval == MFI_STAT_ARRAY_INDEX_INVALID || retval == SML_ERR_CTRL_STATUS_INVALID ||
        retval == SML_ERR_I2C_READ_WRITE_FAILED || retval == SML_ERR_INVALID_PARAMETER) {
        if (check_ld_exist(ctrl_id, target_id) == TRUE) {
            return SML_SUCCESS;
        } else if (retval == SML_ERR_INVALID_PARAMETER) { // 有不支持创建逻辑盘的场景，按原值返回
            return retval;
        } else {
            return SML_ERR_CTRL_STATUS_INVALID;
        }
    }

    return retval;
}

/*
 * Description: 执行删除逻辑盘的LSI libstore命令
 * History: 2016年11月7日  () 新生成函数
*/
gint32 GetArrayInfo(guint32 ctrl_id, guint16 array_ref, SL_ARRAY_INFO_T *pArrayInfo)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;
    gint32 ret;

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

    (void)memset_s(pArrayInfo, SL_ARRAY_INFO_S, 0, SL_ARRAY_INFO_S);
    (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_CONFIG_CMD_TYPE;
    libCmdParam.cmd = SL_GET_ARRAY_INFO;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = SL_ARRAY_INFO_S;
    libCmdParam.arrayRef.ref = array_ref;
    libCmdParam.pData = pArrayInfo;

    ret = ProcessLibCommandCall(libType, &libCmdParam);
    if (ret == SML_SUCCESS && pArrayInfo->array.arrayRef != array_ref) {
        debug_log(DLOG_ERROR,
            "smlib: LSI:GetCtrlInfo failed, CtrlId = %d, arrayRef = %u, returned arrayRef = %u, arrayRef is not "
            "match",
            SML_CTRL_ID_VALID_BIT(ctrl_id), array_ref, pArrayInfo->array.arrayRef);
        return SML_ERR_DATA_INVALID;
    }
    return ret;
}

/*
 * Description: 获取指定逻辑盘关联的所有Array列表，也就是该逻辑盘创建于哪些Array
 * History: 2016年11月10日  () 新生成函数
*/
gint32 GetLDAssociatedArrays(guint32 ctrl_id, guint8 target_id, SML_ARRAY_LIST_S *pArrayList, MR_LD_INFO *pLdPreInfo)
{
    gint32 retval;
    MR_LD_INFO ldInfo;
    MR_LD_INFO *pLdInfo = NULL;
    gint32 i = 0;

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

    (void)memset_s(pArrayList, sizeof(SML_ARRAY_LIST_S), 0, sizeof(SML_ARRAY_LIST_S));

    if (NULL == pLdPreInfo) {
        (void)memset_s(&ldInfo, sizeof(MR_LD_INFO), 0, sizeof(MR_LD_INFO));
        retval = GetLDInfo(ctrl_id, target_id, &ldInfo);
        if (SML_SUCCESS != retval) {
            return retval;
        }

        pLdInfo = &ldInfo;
    } else {
        pLdInfo = pLdPreInfo;
    }

    pArrayList->array_count = pLdInfo->ldConfig.params.spanDepth;
    if (pArrayList->array_count > MAX_SPAN_DEPTH) {
        return SML_ERR_EXCEED_LIMIT;
    }

    for (i = 0; i < pArrayList->array_count; i++) {
        pArrayList->array_refs[i] = pLdInfo->ldConfig.span[i].arrayRef;
    }

    return SML_SUCCESS;
}

/*
 * Description: 发送命令给storelib获取LSI RAID控制器的MFC默认信息
 * History: 2016年3月7日  新生成函数
*/
gint32 GetCtrlMFCDefault(guint32 ctrl_id, MR_MFC_DEFAULTS *pCtrlMfc)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;
    SL_DCMD_INPUT_T dcmdInput;

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

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);
    if (libType != SL_LIB_TYPE_STORELIB) {
        return SL_ERR_INVALID_CMD;
    }

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

    dcmdInput.dataTransferLength = sizeof(MR_MFC_DEFAULTS);
    dcmdInput.opCode = MR_DCMD_CTRL_MFC_DEFAULTS_GET;
    dcmdInput.flags = SL_DIR_READ;
    dcmdInput.pData = pCtrlMfc;

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

    return ProcessLibCommandCall(libType, &libCmdParam);
}

/*
 * Description: 初始化LSI RAID控制器管理信息，并初始化第三方软件库
 * History: 2016年4月6日  新生成函数
 *          2018年9月1日  优化错误打印，10分钟打印一条
*/
gint32 lsi_init_ctrl_manage(guint32 ctrl_id, I2C_WRITE_FUNC i2c_write_func, I2C_WRITEREAD_FUNC i2c_writeread_func)
{
    gint32 retval = 0;
    guint8 libType = 0;
    SL_CTRL_LIST_T tmpCtrlList = { 0 };
    static guint32 gLastLogTimestamp = 0;
    guint32 interval = 10 * 60; // 10mins
    guint32 currentTimestamp = vos_get_cur_time_stamp();
    if ((currentTimestamp > gLastLogTimestamp && (currentTimestamp - gLastLogTimestamp) > interval) ||
        (gLastLogTimestamp > currentTimestamp && (G_MAXUINT32 - gLastLogTimestamp + currentTimestamp) > interval)) {
        gLogFlag = 1;
        gLastLogTimestamp = currentTimestamp;
    } else {
        gLogFlag = 0;
    }

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    lsi_mutex_init();

    /* 初始化背板和硬盘sense_code诊断数据 */
    InitCtrlDiagEvent(ctrl_id);

    if (libType == SL_LIB_TYPE_STORELIB) {
        // 加载 storelib库
        if (NULL == pfnProcessLibCommandMR) {
            retval = LoadStorelibMR(i2c_write_func, i2c_writeread_func);
            if (SML_SUCCESS != retval) {
                return retval;
            }
        }

        debug_log(DLOG_DEBUG, "Init MR Ctrl %d : 0x%08x 0x%08x 0x%08x 0x%08x\n", gLSICtrlListMR.count,
            gLSICtrlListMR.ctrlId[0], gLSICtrlListMR.ctrlId[1], gLSICtrlListMR.ctrlId[2], gLSICtrlListMR.ctrlId[3]);

        /* 在storelib中SL_INIT_LIB命令处理过程中DiscoverOOBCtrl无论成功失败都返回0,
         * 因此需要获取一下RAID firmware的状态确认Discover是否正常完成，如果firmware状态不是ready, 那么返回初始化失败,
         * 当前Contorller在smlib中的初始化状态会标记为INIT_FAILED, 应用程序调用接口获取RAID控制器信息时,
         * 检测到初始化状态是INIT_FAILED，需要再次尝试初始化, 直至成功。
         */
        memcpy_s(&tmpCtrlList, sizeof(SL_CTRL_LIST_T), &gLSICtrlListMR, sizeof(SL_CTRL_LIST_T));
        tmpCtrlList.oob_cl[0].reDiscover = 1; // 这里应该为 oob_cl[0]. 这是 storelib的bug.
        retval = InitializeStorelib(libType, &tmpCtrlList);
        if (retval == SML_SUCCESS) {
            if (FALSE == gSLMrInit) {
                // 注册AEN来收集控制器的日志
                UnRegisterAEN();
                RegisterAEN(&gLSICtrlListMR);
                gSLMrInit = TRUE;
            }
            retval = GetOOBStatus(ctrl_id);
            if (retval != SML_SUCCESS) {
                lsi_init_debug_log(DLOG_ERROR,
                    "LSI contorller firmware OOB status is not operational: CtrlId = %d, Count = %d, return 0x%0x\n",
                    SML_CTRL_ID_VALID_BIT(ctrl_id), gLSICtrlListMR.count, retval);
            }
        } else {
            lsi_init_debug_log(DLOG_ERROR, "LSI storelib initialize : CtrlId = %d, Count = %d, return 0x%0x\n",
                SML_CTRL_ID_VALID_BIT(ctrl_id), gLSICtrlListMR.count, retval);
        }
    } else if (libType == SL_LIB_TYPE_STORELIBIR) {
        // 加载 storelibir 库
        if (NULL == pfnProcessLibCommandMR) {
            retval = LoadStorelibIR(i2c_write_func, i2c_writeread_func);
            if (SML_SUCCESS == retval) {
                retval = InitializeStorelib(libType, &gLSICtrlListIR);
            }
        }
    } else if (libType == SL_LIB_TYPE_STORELIBIR_2) {
        // 加载 storelibir2 库
        if (NULL == pfnProcessLibCommandMR) {
            retval = LoadStorelibIR2(i2c_write_func, i2c_writeread_func);
            if (SML_SUCCESS == retval) {
                retval = InitializeStorelib(libType, &gLSICtrlListIR2);
            }
        }
    } else if (libType == SL_LIB_TYPE_STORELIBIR_3) {
        // 加载 storelibir-3 库
        if (NULL == pfnProcessLibCommandIR3) {
            retval = LoadStorelibIR3(i2c_write_func, i2c_writeread_func);
            if (SML_SUCCESS != retval) {
                return retval;
            }
        }

        // 多个3008卡时，需要多次init，而storelibir-3在调用过一次InitLib之后，会将gLibraryInitialized置为TRUE.

        debug_log(DLOG_DEBUG, "Init IT/IR Ctrl %d : 0x%08x 0x%08x 0x%08x 0x%08x\n", gLSICtrlListIR3.count,
            gLSICtrlListIR3.ctrlId[0], gLSICtrlListIR3.ctrlId[1], gLSICtrlListIR3.ctrlId[2], gLSICtrlListIR3.ctrlId[3]);
        memcpy_s(&tmpCtrlList, sizeof(SL_CTRL_LIST_T), &gLSICtrlListIR3, sizeof(SL_CTRL_LIST_T));
        tmpCtrlList.oob_cl[0].reDiscover = 1;
        retval = InitializeStorelib(libType, &tmpCtrlList);
        if (retval == SML_SUCCESS) {
            /* 在storelibir-3中SL_INIT_LIB命令处理过程中DiscoverI2cCtrl无论成功失败都返回0,
             * 因此需要获取一下RAID控制器的其它信息以确认Discover是否正常完成，如果firmware状态不是ready,
             * 那么返回初始化失败, 当前Contorller在smlib中的初始化状态会标记为INIT_FAILED,
             * 应用程序调用接口获取RAID控制器信息时, 检测到初始化状态是INIT_FAILED，需要再次尝试初始化，直至成功。
             */
            MR_MFC_DEFAULTS CtrlMfcDefault;
            (void)memset_s(&CtrlMfcDefault, sizeof(MR_MFC_DEFAULTS), 0, sizeof(MR_MFC_DEFAULTS));
            retval = GetCtrlMFCDefault(ctrl_id, &CtrlMfcDefault);
            if (retval == SL_ERR_INVALID_CMD) { // IT FW不支持这个命令, MCTP 会以无效命令返回
                retval = SML_SUCCESS;
            } else {
                lsi_init_debug_log(DLOG_ERROR,
                    "LSI contorller firmware OOB status is not operational: CtrlId = %d, Count = %d, return 0x%0x\n",
                    SML_CTRL_ID_VALID_BIT(ctrl_id), gLSICtrlListIR3.count, retval);
            }
        } else {
            lsi_init_debug_log(DLOG_ERROR, "LSI storelibir3 initialize : CtrlId = %d, Count = %d, return 0x%0x\n",
                SML_CTRL_ID_VALID_BIT(ctrl_id), gLSICtrlListIR3.count, retval);
        }
    } else if (libType == SL_LIB_TYPE_STORELIBIT) {
        // IT库需要多次卸载/加载
        // 加载 storelibit库
        if (NULL == pfnProcessLibCommandIT) {
            retval = LoadStorelibIT(i2c_write_func, i2c_writeread_func);
            if (SML_SUCCESS != retval) {
                return retval;
            }
        }

        debug_log(DLOG_DEBUG, "Init IT Ctrl %d : 0x%08x 0x%08x 0x%08x 0x%08x\n", gLSICtrlListIT.count,
            gLSICtrlListIT.ctrlId[0], gLSICtrlListIT.ctrlId[1], gLSICtrlListIT.ctrlId[2], gLSICtrlListIT.ctrlId[3]);
        memcpy_s(&tmpCtrlList, sizeof(SL_CTRL_LIST_T), &gLSICtrlListIT, sizeof(SL_CTRL_LIST_T));
        tmpCtrlList.oob_cl[0].reDiscover = 1;
        retval = InitializeStorelib(libType, &tmpCtrlList);
        if (retval == SML_SUCCESS) {
            MR_MFC_DEFAULTS CtrlMfcDefault;
            (void)memset_s(&CtrlMfcDefault, sizeof(MR_MFC_DEFAULTS), 0, sizeof(MR_MFC_DEFAULTS));
            retval = GetCtrlMFCDefault(ctrl_id, &CtrlMfcDefault);
            if (retval == SL_ERR_INVALID_CMD) { // IT FW不支持这个命令, MCTP 会以无效命令返回
                retval = SML_SUCCESS;
            } else {
                lsi_init_debug_log(DLOG_ERROR,
                    "LSI contorller firmware OOB status is not operational: CtrlId = %d, Count = %d, return 0x%0x\n",
                    SML_CTRL_ID_VALID_BIT(ctrl_id), gLSICtrlListIT.count, retval);
            }
        } else {
            lsi_init_debug_log(DLOG_ERROR, "LSI storelibit initialize : CtrlId = %d, Count = %d, return 0x%0x\n",
                SML_CTRL_ID_VALID_BIT(ctrl_id), gLSICtrlListIT.count, retval);
        }
    } else if (libType == SL_LIB_TYPE_STORELIBCUSTOM) {
        // 加载 storelibcustom库
        if (NULL == pfnProcessLibCommandCustom) {
            retval = LoadStorelibCustom(i2c_write_func, i2c_writeread_func);
            if (SML_SUCCESS != retval) {
                return retval;
            }
        }
 
        debug_log(DLOG_DEBUG, "Init IT Ctrl %d : 0x%08x 0x%08x 0x%08x 0x%08x\n", gLSICtrlListCustom.count,
            gLSICtrlListCustom.ctrlId[0], gLSICtrlListCustom.ctrlId[1],
            gLSICtrlListCustom.ctrlId[2], gLSICtrlListCustom.ctrlId[3]);
        memcpy_s(&tmpCtrlList, sizeof(SL_CTRL_LIST_T), &gLSICtrlListCustom, sizeof(SL_CTRL_LIST_T));
        tmpCtrlList.oob_cl[0].reDiscover = 1;
        retval = InitializeStorelib(libType, &tmpCtrlList);
        if (retval == SML_SUCCESS) {
            MR_MFC_DEFAULTS CtrlMfcDefault;
            (void)memset_s(&CtrlMfcDefault, sizeof(MR_MFC_DEFAULTS), 0, sizeof(MR_MFC_DEFAULTS));
            retval = GetCtrlMFCDefault(ctrl_id, &CtrlMfcDefault);
            if (retval == SL_ERR_INVALID_CMD) { // IT FW不支持这个命令, MCTP 会以无效命令返回
                retval = SML_SUCCESS;
            } else {
                lsi_init_debug_log(DLOG_ERROR,
                    "LSI contorller firmware OOB status is not operational: CtrlId = %d, Count = %d, return 0x%0x\n",
                    SML_CTRL_ID_VALID_BIT(ctrl_id), gLSICtrlListCustom.count, retval);
            }
        } else {
            lsi_init_debug_log(DLOG_ERROR, "LSI storelibit initialize : CtrlId = %d, Count = %d, return 0x%0x\n",
                SML_CTRL_ID_VALID_BIT(ctrl_id), gLSICtrlListCustom.count, retval);
        }
    }

    return retval;
}

/*
 * Description: 退出storelib，释放资源
 * History: 2016年5月25日  新生成函数
*/
static void ExitStorelib(guint8 libType)
{
    gint32 retval = SL_SUCCESS;
    SL_LIB_CMD_PARAM_T libCmdParam;

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

    libCmdParam.cmdType = SL_SYSTEM_CMD_TYPE;
    libCmdParam.cmd = SL_EXIT_LIB;

    if (SL_SUCCESS != (retval = ProcessLibCommandCall(libType, &libCmdParam))) {
        debug_log(DLOG_ERROR, "Exit storelib failed, return 0x%04X", retval);
    }

    return;
}

/*
 * Description: 退出LSI RAID控制器的管理
 * History: 2016年3月3日  新生成函数
 *          2017年7月4日  () 只退出带外管理，不清除数据
 *          2018年12月4日   修改支持热插拔
*/
gint32 lsi_exit_ctrl_manage(guint32 ctrl_id, I2C_WRITE_FUNC i2c_write_func, I2C_WRITEREAD_FUNC i2c_writeread_func)
{
    guint8 libType = 0;

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);
    if (libType == SL_LIB_TYPE_STORELIB) {
        if (libInstanceMR != NULL) {
            ExitStorelib(libType);
            gRegCount = 0;
            (void)memset_s(gRegistrationInfo, sizeof(gRegistrationInfo), 0, sizeof(gRegistrationInfo));
            g_mutex_lock(&gLSICtrlMutex[libType]);
            dlclose(libInstanceMR);
            libInstanceMR = NULL;
            pfnProcessLibCommandMR = NULL;
            g_mutex_unlock(&gLSICtrlMutex[libType]);
        }
    } else if (libType == SL_LIB_TYPE_STORELIBIR) {
        if (libInstanceIR != NULL) {
            ExitStorelib(libType);
            g_mutex_lock(&gLSICtrlMutex[libType]);
            dlclose(libInstanceIR);
            libInstanceIR = NULL;
            pfnProcessLibCommandIR = NULL;
            g_mutex_unlock(&gLSICtrlMutex[libType]);
        }
    } else if (libType == SL_LIB_TYPE_STORELIBIR_2) {
        if (libInstanceIR2 != NULL) {
            ExitStorelib(libType);
            g_mutex_lock(&gLSICtrlMutex[libType]);
            dlclose(libInstanceIR2);
            libInstanceIR2 = NULL;
            pfnProcessLibCommandIR2 = NULL;
            g_mutex_unlock(&gLSICtrlMutex[libType]);
        }
    } else if (libType == SL_LIB_TYPE_STORELIBIR_3) {
        if (libInstanceIR3 != NULL) {
            ExitStorelib(libType);
            g_mutex_lock(&gLSICtrlMutex[libType]);
            dlclose(libInstanceIR3);
            libInstanceIR3 = NULL;
            pfnProcessLibCommandIR3 = NULL;
            g_mutex_unlock(&gLSICtrlMutex[libType]);
        }
    } else if (libType == SL_LIB_TYPE_STORELIBIT) {
        if (libInstanceIT != NULL) {
            ExitStorelib(libType);
            g_mutex_lock(&gLSICtrlMutex[libType]);
            dlclose(libInstanceIT);
            libInstanceIT = NULL;
            pfnProcessLibCommandIT = NULL;
            g_mutex_unlock(&gLSICtrlMutex[libType]);
        }
    } else if (libType == SL_LIB_TYPE_STORELIBCUSTOM) {
        if (libInstanceCustom != NULL) {
            ExitStorelib(libType);
            g_mutex_lock(&gLSICtrlMutex[libType]);
            dlclose(libInstanceCustom);
            libInstanceCustom = NULL;
            pfnProcessLibCommandCustom = NULL;
            g_mutex_unlock(&gLSICtrlMutex[libType]);
        }
    }

    /* 清除背板和硬盘sense_code诊断数据 */
    debug_log(DLOG_DEBUG, "%s : remove ctrl diag event, ctrl_id=0x%08x", __FUNCTION__, ctrl_id);
    RemoveCtrlDiagEvent(ctrl_id);

    // 在这里增加取消AEN注册的代码

    return SML_SUCCESS;
}

/*
 * Description: 将无效的控制器Id移动到最末
*/
static void lsi_rearrange_ctrlId(SL_CTRL_LIST_T *pctrllist, guint8 idx)
{
    if (pctrllist == NULL) {
        return;
    }

    if (pctrllist->count && (SL_MAX_CONTROLLERS != idx)) {
        for (; idx < SL_MAX_CONTROLLERS - 1; idx++) {
            pctrllist->ctrlId[idx] = pctrllist->ctrlId[idx + 1];
        }
        pctrllist->ctrlId[idx] = INVALID_CTRL_ID;
    }

    return;
}

/*
 * Description: 删除控制器节点的数据
 * History: 2017年7月4日  () 新生成函数
 *          2018年12月4日  修改支持热插拔
*/
gint32 lsi_remove_ctrl(guint32 ctrl_id)
{
    guint8 libType;
    guint8 idx = 0;

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);
    if (libType == SL_LIB_TYPE_STORELIB) {
        g_mutex_lock(&gLSICtrlMutex[libType]);
        // 清除数据
        gLSICtrlListMR.flags = SL_FLAGS_NONE;

        for (idx = 0; idx < SL_MAX_CONTROLLERS; idx++) {
            if (ctrl_id == gLSICtrlListMR.ctrlId[idx]) {
                gLSICtrlListMR.ctrlId[idx] = INVALID_CTRL_ID;
                gLSICtrlListMR.count--;
                gSLMrInit = FALSE;
                break;
            }
        }

        lsi_rearrange_ctrlId(&gLSICtrlListMR, idx);

        g_mutex_unlock(&gLSICtrlMutex[libType]);
    } else if (libType == SL_LIB_TYPE_STORELIBIR) {
        // 清除数据

        gLSICtrlListIR.count--;
    } else if (libType == SL_LIB_TYPE_STORELIBIR_2) {
        // 清除数据

        gLSICtrlListIR2.count--;
    } else if (libType == SL_LIB_TYPE_STORELIBIR_3) {
        g_mutex_lock(&gLSICtrlMutex[libType]);
        // 清除数据
        gLSICtrlListIR3.flags = SL_FLAGS_NONE;

        for (idx = 0; idx < SL_MAX_CONTROLLERS; idx++) {
            if (ctrl_id == gLSICtrlListIR3.ctrlId[idx]) {
                gLSICtrlListIR3.ctrlId[idx] = INVALID_CTRL_ID;
                gLSICtrlListIR3.count--;
                break;
            }
        }

        lsi_rearrange_ctrlId(&gLSICtrlListIR3, idx);

        g_mutex_unlock(&gLSICtrlMutex[libType]);
    } else if (libType == SL_LIB_TYPE_STORELIBIT) {
        g_mutex_lock(&gLSICtrlMutex[libType]);

        gLSICtrlListIT.flags = SL_FLAGS_NONE;

        for (idx = 0; idx < SL_MAX_CONTROLLERS; idx++) {
            if (ctrl_id == gLSICtrlListIT.ctrlId[idx]) {
                gLSICtrlListIT.ctrlId[idx] = INVALID_CTRL_ID;
                gLSICtrlListIT.count--;
                break;
            }
        }

        lsi_rearrange_ctrlId(&gLSICtrlListIT, idx);

        g_mutex_unlock(&gLSICtrlMutex[libType]);
    } else if (libType == SL_LIB_TYPE_STORELIBCUSTOM) {
        g_mutex_lock(&gLSICtrlMutex[libType]);

        gLSICtrlListCustom.flags = SL_FLAGS_NONE;

        for (idx = 0; idx < SL_MAX_CONTROLLERS; idx++) {
            if (ctrl_id == gLSICtrlListCustom.ctrlId[idx]) {
                gLSICtrlListCustom.ctrlId[idx] = INVALID_CTRL_ID;
                gLSICtrlListCustom.count--;
                break;
            }
        }

        lsi_rearrange_ctrlId(&gLSICtrlListCustom, idx);

        g_mutex_unlock(&gLSICtrlMutex[libType]);
    }

    /* 清除背板和硬盘sense_code诊断数据 */
    debug_log(DLOG_DEBUG, "%s : remove ctrl diag event, ctrl_id=%d", __FUNCTION__, ctrl_id);
    RemoveCtrlDiagEvent(ctrl_id);

    return SML_SUCCESS;
}

/*
 * Description: 获取逻辑盘的sequence number
 * History: 2016年11月5日  ()  新生成函数
*/
static gint32 GetLDSequenceNumber(guint32 ctrl_id, guint8 target_id, guint16 *seq_num)
{
    gint32 retval;
    MR_LD_INFO ldInfo;

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

    retval = GetLDInfo(ctrl_id, target_id, &ldInfo);
    // 代码检视，格式问题
    if (retval == SML_SUCCESS) {
        *seq_num = ldInfo.ldConfig.properties.ldRef.seqNum;
    }

    return retval;
}

/*
 * Description: 判断指定的逻辑盘是否使能了快照功能
 * History: 2016年11月7日  ()  新生成函数
*/
static gint32 IsSnapshotEnabledLD(guint32 ctrl_id, guint8 target_id, guint8 *enabled)
{
    gint32 rval, i;
    MR_CONFIG_DATA *pConfigData = NULL;
    MR_LD_CONFIG *pLdConfig = NULL;

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

    *enabled = FALSE;

    rval = ReadConfig(ctrl_id, &pConfigData);
    if (rval != SML_SUCCESS) {
        return rval;
    }

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

    for (i = 0; i < pConfigData->logDrvCount; i++, pLdConfig++) {
        if (pLdConfig->properties.ldRef.targetId == target_id) {
            if (pLdConfig->params.snapshotEnabled) {
                *enabled = TRUE;
                break;
            }
        }
    }

    g_free(pConfigData);

    return SML_SUCCESS;
}

/*
 * Description: 执行删除逻辑盘的LSI libstore命令
 * History: 2016年11月7日  ()  新生成函数
*/
static gint32 DeleteLDCmd(guint32 ctrl_id, guint8 target_id, guint16 seq_num)
{
    guint8 libType;
    SL_LIB_CMD_PARAM_T libCmdParam;

    (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_DELETE_LD;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.ldRef.targetId = target_id;
    libCmdParam.ldRef.seqNum = seq_num;

    return ProcessLibCommandCall(libType, &libCmdParam);
}

/*
 * Description: 删除指定的逻辑盘
 * History: 2016年11月5日  ()  新生成函数
*/
gint32 DeleteLD(guint32 ctrl_id, guint8 target_id)
{
    gint32 retval = SML_SUCCESS;
    MR_LD_INFO ldInfo;
    guint16 seq_num = 0;
    guint8 enabled = 0;

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

    retval = GetLDSequenceNumber(ctrl_id, target_id, &seq_num);
    if (retval != SL_SUCCESS) {
        debug_log(DLOG_ERROR, "smlib: LSI:DeleteLD -> GetLDSequenceNumber failed, return 0x%0x", retval);
        return retval;
    }

    // 检查逻辑盘上是否有快照存在(snapshot)
    retval = IsSnapshotEnabledLD(ctrl_id, target_id, &enabled);
    if ((retval == SL_SUCCESS) && enabled) {
        debug_log(DLOG_ERROR,
            "smlib: LSI:DeleteLD -> LD deleted failed, Snapshot is Enabled on this VD, target id = %d, return 0x%0x",
            target_id, retval);

        retval = SML_ERR_LD_DELETE_ON_SNAPSHOTS_ENABLED;
        return retval;
    }

    retval = DeleteLDCmd(ctrl_id, target_id, seq_num);
    if (retval != SML_SUCCESS) {
        /* storelib的resume机制会导致概率性出现删除逻辑盘失败，返回0x4或者0xc，但实际创建成功的问题 */
        if ((retval == MFI_STAT_INVALID_SEQUENCE_NUMBER || retval == MFI_STAT_DEVICE_NOT_FOUND) &&
            (check_ld_exist(ctrl_id, target_id) == FALSE)) {
            return SML_SUCCESS;
        }
        debug_log(DLOG_ERROR, "smlib: LSI:DeleteLD -> LD deleted failed, target id = %d, return 0x%0x", target_id,
            retval);
    }

    return retval;
}

/*
 * Description: 发送SCSI RequestSense命令
 * History: 2016年4月14日  新生成函数
*/
gint32 SendSCSIRequestSenseCommand(guint32 ctrl_id, guint16 device_id, SCSI_SENSE_DISECT_S *sense_info)
{
    gint32 retval = SML_SUCCESS;
    SL_SCSI_PASSTHRU_T *scsi_passthru_cmd = NULL;
    guint32 pscsi_passthru_len = 0;

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

    pscsi_passthru_len = sizeof(SL_SCSI_PASSTHRU_T) + SCSI_LOG_PAGE_RESP_LENGTH;

    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc(pscsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    (void)memset_s(scsi_passthru_cmd, pscsi_passthru_len, 0, pscsi_passthru_len);

    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_READ;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdbLength = SCSI_CDB_LENGTH6;
    // refers to SPC-4 Table 312
    scsi_passthru_cmd->cdb[0] = SCSI_CMD_REQUEST_SENSE;
    scsi_passthru_cmd->cdb[4] = SCSI_LOG_PAGE_RESP_LENGTH;

    scsi_passthru_cmd->dataSize = SCSI_LOG_PAGE_RESP_LENGTH;

    retval = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_DEBUG, "Get Log Sense data failed, DeviceId = %d, CtrlId = %d, return 0x%04X", device_id,
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        g_free(scsi_passthru_cmd);
        return retval;
    }

    /* BEGIN: Modified by, 2019/2/21   PN:UADP135084 */
    (void)ParsePDSenseCode(scsi_passthru_cmd->data, SCSI_LOG_PAGE_RESP_LENGTH, sense_info);
    /* END:   Modified by, 2019/2/21 */

    g_free(scsi_passthru_cmd);

    return SML_SUCCESS;
}
/*
 * Description: 发送Diagnostic命令
 * History: 2019年1月5日 新生成函数
*/
gint32 SendSCSIDiagnosticCommand(guint32 ctrl_id, guint16 device_id, guint8 func_code)
{
    gint32 ret = 0;
    SL_SCSI_PASSTHRU_T *scsi_passthru_cmd = NULL;
    guint32 scsi_passthru_len = 0;
    SCSI_SENSE_DISECT_S sense_info;

    scsi_passthru_len = sizeof(SL_SCSI_PASSTHRU_T);
    scsi_passthru_cmd = (SL_SCSI_PASSTHRU_T *)g_malloc0(scsi_passthru_len);
    if (NULL == scsi_passthru_cmd) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    scsi_passthru_cmd->targetId = device_id;
    scsi_passthru_cmd->cmd = SL_CMD_OP_PD_SCSI;
    scsi_passthru_cmd->lun = 0;
    scsi_passthru_cmd->dir = SL_DIR_NONE;
    scsi_passthru_cmd->timeout = SCSI_CMD_TIME_OUT;
    scsi_passthru_cmd->cdbLength = SCSI_CDB_LENGTH6;
    // refers to SPC-4 Table 173
    scsi_passthru_cmd->cdb[0] = SCSI_CMD_SEND_DIAGNOSTIC;
    scsi_passthru_cmd->cdb[1] = (func_code & 0x7) << 5; // 获取命令字

    scsi_passthru_cmd->dataSize = 0;

    ret = FireSCSIPassthruCmd(ctrl_id, scsi_passthru_cmd);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_DEBUG, "Send Diagnostic command failed, DeviceId = %d, CtrlId = %d, return 0x%04X", device_id,
            SML_CTRL_ID_VALID_BIT(ctrl_id), ret);

        g_free(scsi_passthru_cmd);
        return ret;
    }

    if (SCSI_STATUS_CHECK_CONDITION == scsi_passthru_cmd->scsiStatus &&
        0 == ParsePDSenseCode(scsi_passthru_cmd->pRequestSenseData, SL_SCSI_MAX_SENSE_LENGTH, &sense_info)) {
        /* 根据key判断命令是否发送成功 */
        if (SCSI_KEY_NO_SENSE == sense_info.sense_key || SCSI_KEY_RECOVERED_ERROR == sense_info.sense_key) {
            g_free(scsi_passthru_cmd);
            return SML_SUCCESS;
        }
        debug_log(DLOG_DEBUG,
            "Send Diagnostic command failed because of sense error, DeviceId = %d , CtrlId = %d, key = 0x%02x, asc = "
            "0x%02x, ascq = 0x%02x",
            scsi_passthru_cmd->targetId, SML_CTRL_ID_VALID_BIT(ctrl_id), sense_info.sense_key, sense_info.asc,
            sense_info.ascq);
        g_free(scsi_passthru_cmd);
        return SML_ERR_PD_SCSI_STATUS_FAIL;
    }

    g_free(scsi_passthru_cmd);

    return SML_SUCCESS;
}