/* 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 <limits.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <errno.h>

// don't change the include order
#include "sml_errcodes.h"
#include "sml.h"
#include "vendor.h"
#include "adapter.h"

#ifndef LSI_SML_LIB_PATH
    #ifdef BUILD_SML_OPEN
        #define LSI_SML_LIB_PATH "/usr/lib64/libsml_lsi_open.so"
    #else
        #define LSI_SML_LIB_PATH "/usr/lib64/libsml_lsi.so"
    #endif
#endif

static void fd_remove_phy_diag_history_info(SML_PHY_DIAG_HISTORY_INFO_S *history_info);
gint32 handle_event_info(SML_EVENT_DETAIL*);

/* ----------------------------------------------*
 * 全局变量                                     *
 * ---------------------------------------------- */
static SML_CTRL_S *gCtrlList[SML_MAX_RAID_CONTROLLER] = {NULL}; /* 用于RAID控制器及LD/PD信息的全局缓存数据，此全局数据仅限本文件内接口访问
                                              */
static void *gLibSmLsi = NULL;
static void *gLibSmPmc = NULL;
static void *gLibSmHw = NULL;
static GMutex g_ctrl_list_mutex[SML_MAX_RAID_CONTROLLER];
/* ----------------------------------------------*
 * 模块级变量                                   *
 * ---------------------------------------------- */

typedef struct _tag_sml_err_msg_map {
    gint32 err_code;
    const gchar *err_msg;
} SML_ERR_MSG_MAP;

/* ----------------------------------------------*
 * 常量定义                                     *
 * ---------------------------------------------- */

static const SML_ERR_MSG_MAP err_info_map[] = {
    // LSI MegRAID FW Interface error, start with "MFI"
    { 0x01, "MFI: invalid command" },                                                // MFI_STAT_INVALID_CMD
    { 0x02, "MFI: DCMD opcode is invalid" },                                         // MFI_STAT_INVALID_DCMD
    { 0x03, "MFI: input parameters are invalid" },                                   // MFI_STAT_INVALID_PARAMETER
    { 0x04, "MFI: invalid sequence number" },                                        // MFI_STAT_INVALID_SEQUENCE_NUMBER
    { 0x05, "MFI: abort isn't possible for the requested command" },                 // MFI_STAT_ABORT_NOT_POSSIBLE
    { 0x09, "MFI: given array index is invalid" },                                   // MFI_STAT_ARRAY_INDEX_INVALID
    { 0x0a, "MFI: unable to add missing drive to array, as row has no empty slots" }, // MFI_STAT_ARRAY_ROW_NOT_EMPTY
    { 0x0b, "MFI: some of the CFG resources conflict with each other or the current config" },
                                                                                    // MFI_STAT_CONFIG_RESOURCE_CONFLICT
    { 0x0c, "MFI: invalid device ID / select-timeout" },                            // MFI_STAT_DEVICE_NOT_FOUND
    { 0x0d, "MFI: drive is too small for requrested operation" },                   // MFI_STAT_DRIVE_TOO_SMALL
    { 0x17, "MFI: LD operation not possibe - CC is in progress" },                  // MFI_STAT_LD_CC_IN_PROGRESS
    { 0x18, "MFI: LD initialization in progress" },                                 // MFI_STAT_LD_INIT_IN_PROGRESS
    { 0x19, "MFI: LBA is out of range" },                                           // MFI_STAT_LD_LBA_OUT_OF_RANGE
    { 0x1a, "MFI: maximum LDs are already configured" },                            // MFI_STAT_LD_MAX_CONFIGURED
    { 0x1b, "MFI: LD is not OPTIMAL" },                                             // MFI_STAT_LD_NOT_OPTIMAL
    { 0x1c, "MFI: LD Rebuild is in progress" },                                     // MFI_STAT_LD_RBLD_IN_PROGRESS
    { 0x1d, "MFI: LD is undergoing reconstruction" },                               // MFI_STAT_LD_RECON_IN_PROGRESS
    { 0x1e, "MFI: LD RAID level is wrong for requested operation" },                // MFI_STAT_LD_WRONG_RAID_LEVEL
    { 0x1f, "MFI: too many spares assigned" },                                      // MFI_STAT_MAX_SPARES_EXCEEDED
    { 0x20, "MFI: scratch memory not available - try command again later" },        // MFI_STAT_MEMORY_NOT_AVAILABLE
    { 0x21, "MFI: error writing MFC data to SEEPROM" },                             // MFI_STAT_MFC_HW_ERROR
    { 0x22, "MFI: required HW is missing (i.e. Alarm or BBU)" },                    // MFI_STAT_NO_HW_PRESENT
    { 0x24, "MFI: LD drives are not within an enclosure" },                         // MFI_STAT_NOT_IN_ENCL
    { 0x25, "MFI: PD CLEAR operation is in progress" },                             // MFI_STAT_PD_CLEAR_IN_PROGRESS
    { 0x26, "MFI: unable to use SATA(SAS) drive to replace SAS(SATA)" },            // MFI_STAT_PD_TYPE_WRONG
    { 0x27, "MFI: Patrol Read is disabled" },                                       // MFI_STAT_PR_DISABLED
    { 0x28, "MFI: given row index is invalid" },                                    // MFI_STAT_ROW_INDEX_INVALID
    { 0x2d, "MFI: SCSI command done, but non-GOOD status was received-see mf.hdr.extStatus for SCSI_STATUS" },
                                                                                    // MFI_STAT_SCSI_DONE_WITH_ERROR
    { 0x2e, "MFI: IO request for MFI_CMD_OP_PD_SCSI failed - see extStatus for DM error" }, // MFI_STAT_SCSI_IO_FAILED
    { 0x2f, "MFI: matches SCSI RESERVATION_CONFLICT" },                           // MFI_STAT_SCSI_RESERVATION_CONFLICT
    { 0x30, "MFI: one or more of the flush operations failed" },                  // MFI_STAT_SHUTDOWN_FAILED
    { 0x31, "MFI: FW real-time currently not set" },                              // MFI_STAT_TIME_NOT_SET
    { 0x32, "MFI: command issues while FW in wrong state (i.e. GET RECON when op not active)" },
                                                                                   // MFI_STAT_WRONG_STATE
    { 0x33, "MFI: LD is not OFFLINE - IO not possible" },                          // MFI_STAT_LD_OFFLINE
    { 0x36, "MFI: LD reservation already in progress" },                           // MFI_STAT_RESERVATION_IN_PROGRESS
    { 0x37, "MFI: I2C errors were detected" },                                     // MFI_STAT_I2C_ERRORS_DETECTED
    { 0x3a, "MFI: unable to process command as boot messages are pending" },       // MFI_STAT_BOOT_MSG_PENDING
    { 0x3b, "MFI: Returned in case if foreign configurations are imcomplete" },    // MFI_STAT_FOREIGN_CONFIG_INCOMPLETE
    { 0x3e, "MFI: CC scheduling is disabled" },                                    // MFI_STAT_CC_SCHEDULE_DISABLED
    { 0x3f, "MFI: PD CopyBack operation is in progress" },                         // MFI_STAT_PD_COPYBACK_IN_PROGRESS
    { 0x40, "MFI: selected more than one PD per array" },                          // MFI_STAT_MULTIPLE_PDS_IN_ARRAY
    { 0x42, "MFI: unable to process command as drive security feature is not enabled" },
                                                                                // MFI_STAT_FEATURE_SECURITY_NOT_ENABLED
    { 0x43, "MFI: controller already has a lock key" },                         // MFI_STAT_LOCK_KEY_ALREADY_EXISTS
    { 0x4b, "MFI: secure LD exist" },                                           // MFI_STAT_SECURE_LD_EXISTS
    { 0x4c, "MFI: LD secure operation is not allowed" },                        // MFI_STAT_LD_SECURE_NOT_ALLOWED
    { 0x4d, "MFI: reprovisioning is not allowed" },                             // MFI_STAT_REPROVISION_NOT_ALLOWED
    { 0x4e, "MFI: drive security type (FDE or non-FDE) is not appropriate for requested operation" },
                                                                       // MFI_STAT_PD_SECURITY_TYPE_WRONG
    { 0x4f, "MFI: LD encryption type is not supported" },              // MFI_STAT_LD_ENCRYPTION_TYPE_INVALID
    { 0x50, "MFI: cannot mix FDE and non-FDE drives in same array" },  // MFI_STAT_CONFIG_FDE_NON_FDE_MIX_NOT_ALLOWED
    { 0x51, "MFI: cannot mix secure and unsecured LD in same array" },
                                                                   // MFI_STAT_CONFIG_LD_ENCRYPTION_TYPE_MIX_NOT_ALLOWED
    { 0x52, "MFI: secret key not allowed" },                           // MFI_STAT_SECRET_KEY_NOT_ALLOWED
    { 0x53, "MFI: Physical device errors were detected" },             // MFI_STAT_PD_HW_ERRORS_DETECTED
    { 0x54, "MFI: Controller has LD cache pinned" },                   // MFI_STAT_LD_CACHE_PINNED
    { 0x55, "MFI: Requested operation is already in progress" },       // MFI_STAT_POWER_STATE_SET_IN_PROGRESS
    { 0x56, "MFI: Another power state set operation is in progress" }, // MFI_STAT_POWER_STATE_SET_BUSY
    { 0x57, "MFI: Power state of device is not correct" },             // MFI_STAT_POWER_STATE_WRONG
    { 0x58, "MFI: No PD is available for patrol read" },               // MFI_STAT_PR_NO_AVAILABLE_PD_FOUND
    { 0x59, "MFI: Controller resert is required" },                    // MFI_STAT_CTRL_RESET_REQUIRED
    { 0x5a, "MFI: No EKM boot agent detected" },                       // MFI_STAT_LOCK_KEY_EKM_NO_BOOT_AGENT
    { 0x5b, "MFI: No space on the snapshot repositiry VD" },           // MFI_STAT_SNAP_NO_SPACE
    { 0x5c, "MFI: For consistency SET PiTs, some PiT creations may fail and some succeed" },
                                                                                    // MFI_STAT_SNAP_PARTIAL_FAILURE
    { 0x5d, "MFI: Secondary iButton cannot be used and is incompatible with controller" },
                                                                                    // MFI_STAT_UPGRADE_KEY_INCOMPATIBLE
    { 0x5e, "MFI: PFK doesn't match or cannot be applied to the controller" },      // MFI_STAT_PFK_INCOMPATIBLE
    { 0x5f, "MFI: maximum allowed unconfigured (configurable) PDs exist" },         // MFI_STAT_PD_MAX_UNCONFIGURED
    { 0x60, "MFI: IO metrics are not being collected" },                            // MFI_STAT_IO_METRICS_DISABLED
    { 0x61, "MFI: AEC capture need to be stopped before proceeding" },              // MFI_STAT_AEC_NOT_STOPPED
    { 0x62, "MFI: Unsupported level of protection information" },                   // MFI_STAT_PI_TYPE_WRONG
    { 0x63, "MFI: PDs in LD have incompatible EEDP types" },                        // MFI_STAT_LD_PD_PI_INCOMPATIBLE
    { 0x64, "MFI: Request cannot be completed because protection information is not enabled" },
                                                                                    // MFI_STAT_PI_NOT_ENABLED
    { 0x65, "MFI: PDs in LD have different block sizes" },                          // MFI_STAT_LD_BLOCK_SIZE_MISMATCH
    { 0x66, "MFI: LD Cached data is present on a (this) SSCD" },                    // MFI_STAT_LD_SSCD_CACHE_PRESENT
    { 0x67, "MFI: config sequence number mismatch" },                               // MFI_STAT_CONFIG_SEQ_MISMATCH
    { 0x6d, "MFI: Dedicated hot spare assignment is limited to array(s) with same LDs" },
                                                                                 // MFI_STAT_DEDICATED_SPARE_NOT_ALLOWED
    { 0x74, "MFI: Status ok but reboot is required to take effect" },                 // MFI_STAT_OK_REBOOT_REQUIRED
    { 0x75, "MFI: Operation can't perform due to background operation in progress" }, // MFI_STAT_BGOP_IN_PROGRESS
    { 0x76, "MFI: Operation is not possible" },                                       // MFI_STAT_OPERATION_NOT_POSSIBLE
    { 0x78, "MFI: Hidden policy not set for all LDs in Drive Group containing this LD" },
                                                                                      // MFI_STAT_LD_PARTIALLY_HIDDEN

    // SML interface error
    { SML_ERR_NULL_DATA,         "SML: Parameter with NULL pointer" },
    { SML_ERR_INVALID_CMD,       "SML: Invalid command" },
    { SML_ERR_NULL_INFTERFACE,   "SML: Not supported interface" },
    { SML_ERR_CANNOT_ALLOC_MEM,  "SML: Allocate memory failed" },
    { SML_ERR_FILE_PATH_ILLEGAL, "SML: File path illegal" },
    { SML_ERR_CANNOT_OPEN_FILE,  "SML: Can not open file" },
    { SML_ERR_BUF_NOT_ENOUGH,    "SML: Buffer size not enough" },
    { SML_ERR_EXCEED_LIMIT,      "SML: Exceed limit" },

    { SML_ERR_CTRL_INDEX_INVALID,               "SML: Invalid RAID controller index" },
    { SML_ERR_CTRL_DUPLICATE_REGISTERED,        "SML: RAID controller duplicate registered" },
    { SML_ERR_CTRL_NOT_REGISTERED,              "SML: RAID controller not registered" },
    { SML_ERR_CTRL_INIT_NOT_COMPLETED,          "SML: RAID controller init not completed" },
    { SML_ERR_CTRL_INIT_FAILED,                 "SML: RAID controller init failed" },
    { SML_ERR_CTRL_LSI_SL_LOAD_FAILED,          "SML: LSI lib load failed" },
    { SML_ERR_CTRL_LSI_SL_GET_FUNC_ADDR_FAILED, "SML: LSI lib function address get failed" },
    { SML_ERR_CTRL_STATUS_INVALID,              "SML: Invalid RAID controller status" },
    { SML_ERR_CTRL_PARAM_ILLEGAL,               "SML: RAID controller parameter illegal" },
    { SML_ERR_CTRL_OPERATION_NOT_SUPPORT,       "SML: RAID controller operation not supported" },

    { SML_ERR_LD_INVALID_TARGET_ID,                  "SML: Invalid LD target ID" },
    { SML_ERR_LD_DELETE_ON_SNAPSHOTS_ENABLED,        "SML: Attempt to delete LD with snapshots enabled" },
    { SML_ERR_LD_PROPERTY_SET_NOT_ALLOWED,           "SML: LD property not allowed" },
    { SML_ERR_LD_PROPERTY_SET_ONLY_DEFAULT_ALLOWED,  "SML: LD property only default allowed" },
    { SML_ERR_LD_NO_SSCD_OR_INVALID_NUM_OF_SSCD,     "SML: No CacheCade LD" },
    { SML_ERR_LD_SET_CACHING_ENABLE_FOR_LD_WITH_SSD, "SML: Attemp to set Caching enable for LD with SSD" },
    { SML_ERR_LD_OPERATION_NOT_SUPPORT,              "SML: LD opertation not supported" },

    { SML_ERR_PD_INVALID_DEVICE_ID,        "SML: Invalid PD device ID" },
    { SML_ERR_PD_MAKESPARE_NOT_ALLOWED,    "SML: PD makespare not allowed" },
    { SML_ERR_PD_SPARE_SDD_SAS_SATA_MIXED, "SML: PD can't be used as spare, SSD SAS/SATA interface mixed" },
    { SML_ERR_PD_SPARE_SDD_HDD_MIXED,      "SML: PD can't be used as spare, SSD/HDD media type mixed" },
    { SML_ERR_PD_SPARE_TOO_MANY_ARRAYS,    "SML: PD can't be used as spare, too many array to spare" },
    { SML_ERR_PD_SPARE_FOR_RAID0_LD,       "SML: PD can't be used as spare for RAID0 LD" },
    { SML_ERR_PD_STATE_UNSUPPORTED_TO_SET, "SML: Unsupported PD Set opertaiton under current state" },
    { SML_ERR_PD_SCSI_RESP_INCORRECT,      "SML: PD SCSI response incorrect" },
    { SML_ERR_PD_SCSI_STATUS_BUSY,         "SML: PD SCSI status busy" },
    { SML_ERR_PD_SCSI_CMD_FAIL,            "SML: PD SCSI command failed" },
    { SML_ERR_PD_OPERATION_NOT_SUPPORT,    "SML: PD operation not supported" },

    { SML_ERR_CONFIG_INCORRECT_CONFIG_DATA_SIZE,       "SML: RAID configuartion data size incorrect" },
    { SML_ERR_CONFIG_INVALID_PARAM_SPAN_DEPTH,         "SML: Invalid span depth" },
    { SML_ERR_CONFIG_INVALID_PARAM_NUM_DRIVE_PER_SPAN, "SML: Invalid number drives per span" },
    { SML_ERR_CONFIG_INVALID_PARAM_REPEATED_PD_ID,     "SML: Found repeated PD ID in PD list" },
    { SML_ERR_CONFIG_INVALID_PARAM_RAID_LEVEL,         "SML: Invalid RAID level setting" },
    { SML_ERR_CONFIG_INVALID_PARAM_CAPACITY_TOO_SMALL, "SML: Input capacity too small" },
    { SML_ERR_CONFIG_INVALID_PARAM_CAPACITY_TOO_LARGE, "SML: Input capacity too large" },
    { SML_ERR_CONFIG_INVALID_PARAM_ARRAY_REF,          "SML: Invalid array ref ID for adding new LD" },
    { SML_ERR_CONFIG_ARRAY_NUM_REACHED_LIMIT,          "SML: Array number reached to limit" },
    { SML_ERR_CONFIG_ARRAY_SIZE_TOO_SMALL,             "SML: Array size to small to add new ld" },
    { SML_ERR_CONFIG_ARRAY_NO_AVAILABLE_SPACE,         "SML: No available space on array" },
    { SML_ERR_CONFIG_ARRAY_INCORRECT_DATA_SIZE,        "SML: Array data size incorrect" },
    { SML_ERR_CONFIG_INVALID_PD_GETINFO_FAILED,        "SML: Get PD info failed" },
    { SML_ERR_CONFIG_INVALID_PD_BOOT_SECTOR_FOUND,     "SML: Found boot sectoron PD, not suitable for new LD" },
    { SML_ERR_CONFIG_INVALID_PD_NON_SUPPORTED,         "SML: PD not supported by controller, not suitable for new LD" },
    { SML_ERR_CONFIG_INVALID_PD_SCSI_DEV_TYPE,         "SML: PD is not a SCSI hard disk, not suitable for new LD" },
    { SML_ERR_CONFIG_INVALID_PD_IN_USE,                "SML: PD in used, not suitable for new LD" },
    { SML_ERR_CONFIG_INVALID_PD_SDD_HDD_MIXED,         "SML: PDs SSD/HDD media type mixed, not suitable for new LD" },
    { SML_ERR_CONFIG_INVALID_PD_SDD_SAS_SATA_MIXED,    "SML: PDs SSD SAS/SATA interface mixed, not suitable for new LD" },
    { SML_ERR_CONFIG_INVALID_PD_WITH_FOREIGN_CONFIG,   "SML: PDs with foreign configuration, not suitable for new LD" },
    { SML_ERR_CONFIG_INVALID_PD_NON_SDD_FOR_CACHECADE, "SML: Non SSD not suitable for new CacheCade LD" },
    { SML_ERR_CONFIG_INVALID_PD_OTHER_ERROR,           "SML: Other error, PDs not suitable for new LD" },
    { SML_ERR_CONFIG_TARGET_LD_ID_EXHAUSTED,           "SML: No available ID for new LD" },
    { SML_ERR_CONFIG_OPERATION_NOT_SUPPORT,            "SML: RAID config operation not supported" },

    { SML_ERR_ARRAY_INVALID_ARRAY_REF, "SML: Invalid array ref ID specified" },
};

#define ERR_MSG_CNT (sizeof(err_info_map) / sizeof(SML_ERR_MSG_MAP))

/* ----------------------------------------------*
 * 宏定义                                       *
 * ---------------------------------------------- */
#define SMLIB_DUMP_SMART_INFO_INTREVAL 600 // 每隔10分钟写一次物理盘SMART信息到文件

/*
 * Description: 根据控制器序号获取全局控制器变量地址
 * History:2020-12-08  新生成函数
 */
SML_CTRL_S* get_ctrl_by_index(guint8 ctrl_index)
{
    return gCtrlList[ctrl_index];
}

void lock_ctrl_list_mutex(guint8 ctrl_index)
{
    g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
}

void unlock_ctrl_list_mutex(guint8 ctrl_index)
{
    g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
}

/*
 * Description: 检查RAID控制器是否已被注册
 * History: 1.2016年3月7日
 *          新生成函数
 */
static gint32 _check_ctrl_is_registered(guint8 ctrl_index)
{
    g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
    if (gCtrlList[ctrl_index] == NULL) {
        g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
        return FALSE;
    }

    g_mutex_lock(&gCtrlList[ctrl_index]->ctrl_mutex);

    if (gCtrlList[ctrl_index]->is_registered == TRUE) {
        g_mutex_unlock(&gCtrlList[ctrl_index]->ctrl_mutex);
        g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
        return TRUE;
    }

    g_mutex_unlock(&gCtrlList[ctrl_index]->ctrl_mutex);
    g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
    return FALSE;
}

/*
 * Description: 检查RAID控制器注册时是否初始化成功
 * History: 1.2016年3月13日
 *          新生成函数
 *          2.2018年7月5日
 */
static gint32 _check_ctrl_init_state(guint8 ctrl_index)
{
    g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
    if (gCtrlList[ctrl_index] == NULL) {
        g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
        return SML_ERR_CTRL_INIT_FAILED;
    }
    gint32 retval = SML_ERR_CTRL_INIT_FAILED;

    g_mutex_lock(&gCtrlList[ctrl_index]->ctrl_mutex);

    if (gCtrlList[ctrl_index]->init_state == INIT_DONE) {
        retval = SML_SUCCESS;
    }

    g_mutex_unlock(&gCtrlList[ctrl_index]->ctrl_mutex);
    g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);

    return retval;
}

/*
 * Description: 检查全局缓存的数据是否过期
 * History: 1.2016年3月9日
 *          新生成函数
 *          2.2017年1月11日,  ()
 *          3.2017年11月29日,  ()
 *          4.2020-12-03,
 *          改成外部接口
 */
gint32 check_cache_data_is_expired(guint8 refresh_policy, guint32 current, guint32 last, guint32 interval)
{
    guint8 refresh_type = 0;
    guint8 refresh_count = 0;
    refresh_type = refresh_policy & 0x0f;
    refresh_count = (refresh_policy >> 4) & 0x0f;

    // last = 0表示缓冲区为空，需要从硬件获取信息
    if (last == 0) {
        return CACHE_DATA_INVALID_NO_DATA;
    }

    // 根据数据刷新策略直接返回数据有效性
    switch (refresh_type) {
        case RAID_REFRESH_DEFAULT:
            break;

        case RAID_REFRESH_CONTROLLER:
            if (refresh_count) {
                return CACHE_DATA_INVALID_FORCED;
            }
            break;

        case RAID_REFRESH_INTERNAL_CACHE:
            if (refresh_count) {
                return CACHE_DATA_VALID;
            }
            break;

        default:
            break;
    }

    if ((current > last && (current - last) > interval) ||
        (last > current && (G_MAXUINT32 - last + current) > interval)) {
        return CACHE_DATA_INVALID_TIMEOUT;
    }

    return CACHE_DATA_VALID;
}

/*
 * Description: 更新缓存刷新策略
 * History: 1.2016年12月21日,  ()
 *          新生成函数
 *          2.2020-12-03,
 *          改成外部接口
 */
guint8 update_refresh_policy(guint8 refresh_polciy)
{
    guint8 refresh_type = 0;
    guint8 refresh_count = 0;
    guint8 new_refresh_ctrl = 0;

    refresh_type = refresh_polciy & 0x0f;
    refresh_count = (refresh_polciy >> 4) & 0x0f;

    // 每次刷新计数减1
    if (refresh_count) {
        refresh_count--;
    }

    // 刷新计数为0时，恢复默认刷新策略
    if (refresh_count == 0) {
        refresh_type = RAID_REFRESH_DEFAULT;
    }

    new_refresh_ctrl = ((refresh_count << 4) & 0xf0) | refresh_type;

    return new_refresh_ctrl;
}

/*
 * Description: smlib_get*** 函数族入参检查
 * History: 1.2016年3月9日
 *          新生成函数
 *          2.2020-12-03,
 *          改成外部接口
 */
gint32 check_input_parameters(guint8 ctrl_index, gpointer input)
{
    // 检查control index是否超出范围
    if (ctrl_index >= SML_MAX_RAID_CONTROLLER) {
        return SML_ERR_CTRL_INDEX_INVALID;
    }
    if (TRUE != _check_ctrl_is_registered(ctrl_index)) {
        return SML_ERR_CTRL_NOT_REGISTERED;
    }
    if (SML_SUCCESS != _check_ctrl_init_state(ctrl_index)) {
        return SML_ERR_CTRL_INIT_NOT_COMPLETED;
    }

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

    return SML_SUCCESS;
}

/*
 * Description: 检查TargetID是否在该RAID控制器的LD列表中
 * History: 1.2016年3月10日
 *          新生成函数
 *          2.2020-12-03,
 *          改成外部接口
 */
gint32 check_ld_target_id(guint16 ld_target_id, SML_LD_LIST_S *ld_list, guint8 *ld_index)
{
    guint16 idx = 0;
    gint32 result = RET_OK;

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

    for (idx = 0; idx < ld_list->ld_count; idx++) {
        if (ld_target_id == ld_list->target_ids[idx]) {
            *ld_index = idx;
            break;
        }
    }

    if (idx == ld_list->ld_count) {
        result = RET_ERR;
    }

    return result;
}

/*
 * Description: 检查PD的DeviceId是否在控制器的PD列表中
 * History: 1.2016年4月14日
 *          新生成函数
 *          2.2020-12-03,
 *          改成外部接口
 */
gint32 check_pd_device_id(guint16 pd_device_id, SML_PD_LIST_S *pd_list, guint16 *pd_index)
{
    guint16 idx = 0;
    gint32 result = RET_OK;

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

    for (idx = 0; idx < pd_list->pd_count; idx++) {
        if (pd_device_id == pd_list->device_ids[idx]) {
            *pd_index = idx;
            break;
        }
    }

    if (idx == pd_list->pd_count) {
        result = RET_ERR;
    }

    return result;
}

/*
 * Description: 记录RAID卡PHY误码数据到历史数据中
 * History: 1.2019年1月21日,
 *          新生成函数
 *          2.2020-12-08
 *          改成外部接口
 */
gint32 fd_record_ctrl_phy_err_info(SML_PHY_DIAG_HISTORY_INFO_S *history_info, SML_SASPHY_INFO_S *ctrl_phy_info,
    guint32 collect_timestamp)
{
    SML_SASPHY_INFO_S *temp_info = NULL;
    GList *list_temp = NULL;

    if (history_info == NULL || ctrl_phy_info == NULL) {
        return SML_ERR_NULL_DATA;
    }

    temp_info = (SML_SASPHY_INFO_S *)g_malloc0(sizeof(SML_SASPHY_INFO_S));
    if (temp_info == NULL) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    /* 复制数据，并记录时间戳 */
    (void)memcpy_s(temp_info, sizeof(SML_SASPHY_INFO_S), ctrl_phy_info, sizeof(SML_SASPHY_INFO_S));
    temp_info->collect_timestamp = collect_timestamp;

    /* 将最新收集的数据插入到链表的最后 */
    history_info->ctrl_phy_list = g_list_append(history_info->ctrl_phy_list, temp_info);

    /* 如果链表数据大于链表最大长度，则去除链表头的数据 */
    if (g_list_length(history_info->ctrl_phy_list) > SMLIB_PHY_DIAG_HISTORY_RECORD_COUNT) {
        list_temp = g_list_first(history_info->ctrl_phy_list);
        history_info->ctrl_phy_list = g_list_remove_link(history_info->ctrl_phy_list, list_temp);
        g_list_free_full(list_temp, g_free);
    }

    return SML_SUCCESS;
}

/*
 * Description: 记录Expander的PHY误码数据到历史数据中
 * History: 1.2019年1月21日,
 *          新生成函数
 *          2.2020-12-08
 *          改成外部接口
 */
gint32 fd_record_exp_phy_err_info(SML_PHY_DIAG_HISTORY_INFO_S *history_info,
    SML_CTRL_EXP_SASPHY_INFO_S *exp_phy_info, guint32 collect_timestamp)
{
    SML_CTRL_EXP_SASPHY_INFO_S *temp_info = NULL;
    GList *list_temp = NULL;

    if (history_info == NULL || exp_phy_info == NULL) {
        return SML_ERR_NULL_DATA;
    }

    temp_info = (SML_CTRL_EXP_SASPHY_INFO_S *)g_malloc0(sizeof(SML_CTRL_EXP_SASPHY_INFO_S));
    if (temp_info == NULL) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    /* 复制数据，并记录时间戳 */
    (void)memcpy_s(temp_info, sizeof(SML_CTRL_EXP_SASPHY_INFO_S), exp_phy_info, sizeof(SML_CTRL_EXP_SASPHY_INFO_S));
    temp_info->collect_timestamp = collect_timestamp;

    /* 将最新收集的数据插入到链表的最后 */
    history_info->exp_phy_list = g_list_append(history_info->exp_phy_list, temp_info);

    /* 如果链表数据大于链表最大长度，则去除链表头的数据 */
    if (g_list_length(history_info->exp_phy_list) > SMLIB_PHY_DIAG_HISTORY_RECORD_COUNT) {
        list_temp = g_list_first(history_info->exp_phy_list);
        history_info->exp_phy_list = g_list_remove_link(history_info->exp_phy_list, list_temp);
        g_list_free_full(list_temp, g_free);
    }

    return SML_SUCCESS;
}

/*
 * Description: smlib的初始化接口，非线程安全
 * History: 1.2016年3月1日
 *          新生成函数
 */
void smlib_init(void)
{
    for (guint8 i = 0; i < SML_MAX_RAID_CONTROLLER; i++) {
        g_mutex_init(&g_ctrl_list_mutex[i]);
    }
}

/*
 * Description: 清空全局缓存数组中控制器的所有信息，包括硬盘，逻辑盘等
 */
void smlib_clear_all_controller_info(void)
{
    guint8 i = 0;
    guint8 present = 0;

    for (i = 0; i < SML_MAX_RAID_CONTROLLER; i++) {
        g_mutex_lock(&g_ctrl_list_mutex[i]);
        if (gCtrlList[i] == NULL) {
            g_mutex_unlock(&g_ctrl_list_mutex[i]);
            continue;
        }
        g_mutex_lock(&gCtrlList[i]->ctrl_mutex);

        /* 保留上一次获取的BBU在位状态 */
        present = gCtrlList[i]->controller.bbu.present;

        /* 清除RAID卡诊断事件数据 */
        if (gCtrlList[i]->pfn_clear_ctrl_diag_event != NULL) {
            (void)gCtrlList[i]->pfn_clear_ctrl_diag_event(gCtrlList[i]->controller_id);
        }

        /* 清空PHY误码诊断历史数据 */
        fd_remove_phy_diag_history_info(&gCtrlList[i]->controller.phy_history);

        /* 清空controller结构体 */
        (void)memset_s(&gCtrlList[i]->controller, sizeof(gCtrlList[i]->controller), 0,
            sizeof(gCtrlList[i]->controller));

        /* os下电controller结构体清空后，bbu.present和bbu.present_updated也被清理，
           为了保证os下电不影响BBU在位状态，present重新赋值为上一次获取的在位状态值，
           待上电后重新获取到新的在位状态，在smlib_get_ctrl_health接口会再更新 */
        gCtrlList[i]->controller.bbu.present = present;

        g_mutex_unlock(&gCtrlList[i]->ctrl_mutex);
        g_mutex_unlock(&g_ctrl_list_mutex[i]);
    }
}

static gint32 register_libsml_lsi_fun(SMLIB_SDK_FUNC_S *lsi_fun_table, gint32 fun_num)
{
    int i = 0;

    // 之前未加载过libsml_lsi.so
    if (gLibSmLsi == NULL) {
        gLibSmLsi = dlopen(LSI_SML_LIB_PATH, RTLD_LAZY);
        // 默认路径加载失败尝试备份路径
        if (gLibSmLsi == NULL) {
            debug_log(DLOG_ERROR, "Failed to load lsi sml library %s for MegaRAID SAS Controller. error : %s",
                LSI_SML_LIB_PATH, dlerror());
            return SML_ERR_CTRL_LIB_LOAD_FAILED;
        }
    }
    for (i = 0; i < fun_num; i++) {
        *(lsi_fun_table[i].pfunc) = dlsym(gLibSmLsi, lsi_fun_table[i].func_name);
        if (*(lsi_fun_table[i].pfunc) == NULL) {
            debug_log(DLOG_ERROR, "Unable to get Entry Point function address-%s.", lsi_fun_table[i].func_name);
            continue;
        }
    }

    return SML_SUCCESS;
}

/*
 * Description: 动态连接lsi接口封装库，更新函数指针
 * History: 1.2019年10月23日,
 *          新生成函数 UADP432406
 */
static gint32 register_storelib_function(SML_CTRL_S *ctrl)
{
    SMLIB_SDK_FUNC_S lsi_fun_table[] = {
        { (void **)&ctrl->pfn_add_ctrl,                   "lsi_add_ctrl" },
        { (void **)&ctrl->pfn_remove_ctrl,                "lsi_remove_ctrl" },
        { (void **)&ctrl->pfn_init_ctrl_over_i2c,         "lsi_init_ctrl_manage" },
        { (void **)&ctrl->pfn_exit_ctrl_over_i2c,         "lsi_exit_ctrl_manage" },
        { (void **)&ctrl->pfn_update_ctrl_cache,          "lsi_update_ctrl_cache" },
        { (void **)&ctrl->pfn_get_ctrl_info,              "lsi_get_ctrl_info" },
        { (void **)&ctrl->pfn_get_ctrl_sas_addr,          "lsi_get_ctrl_sas_addr" },
        { (void **)&ctrl->pfn_get_ctrl_health,            "lsi_get_ctrl_health" },
        { (void **)&ctrl->pfn_get_ctrl_bbu_status,        "lsi_get_ctrl_bbu_status" },
        { (void **)&ctrl->pfn_get_ctrl_phy_err_count,     "lsi_get_ctrl_phy_err_count" },
        { (void **)&ctrl->pfn_get_ctrl_exp_phy_err_count, "lsi_get_ctrl_exp_phy_err_count" },
        { (void **)&ctrl->pfn_get_ctrl_ld_list,           "lsi_get_ctrl_ld_list" },
        { (void **)&ctrl->pfn_get_ctrl_pd_list,           "lsi_get_ctrl_pd_list" },
        { (void **)&ctrl->pfn_get_ld_info,                "lsi_get_ld_info" },
        { (void **)&ctrl->pfn_get_ctrl_exp_list,          "lsi_get_ctrl_exp_list" },
        { (void **)&ctrl->pfn_get_exp_phy_err_count,      "lsi_get_exp_phy_err_count" },
        { (void **)&ctrl->pfn_get_ld_pd_list,             "lsi_get_ld_pd_list" },
        { (void **)&ctrl->pfn_get_pd_info,                "lsi_get_pd_info" },
        { (void **)&ctrl->pfn_get_pd_smart_info,          "lsi_get_pd_smart_info" },
        { (void **)&ctrl->pfn_get_pd_smart_info_spec,     "lsi_get_pd_smart_info_spec" },
        { (void **)&ctrl->pfn_pd_operation,               "lsi_pd_operations" },
        { (void **)&ctrl->pfn_get_pd_log,                 "lsi_get_pd_log" },
        { (void **)&ctrl->pfn_get_ctrl_array_list,        "lsi_get_ctrl_array_list" },
        { (void **)&ctrl->pfn_get_array_info,             "lsi_get_array_info" },
        { (void **)&ctrl->pfn_get_ctrl_boot_mode,         "lsi_get_ctrl_boot_mode" },
        { (void **)&ctrl->pfn_config_operation,           "lsi_config_operations" },
        { (void **)&ctrl->pfn_ld_operation,               "lsi_ld_operations" },
        { (void **)&ctrl->pfn_ctrl_operation,             "lsi_ctrl_operations" },
        { (void **)&ctrl->pfn_diag_encl_comm_error,       "lsi_diag_encl_comm_error" },
        { (void **)&ctrl->pfn_diag_pd_sense_error,        "lsi_diag_pd_sense_error" },
        { (void **)&ctrl->pfn_mock_diag_ctrl_event,       "lsi_mock_insert_ctrl_event" },
        { (void **)&ctrl->pfn_get_phy_diag_topo_info,     "lsi_get_phy_diag_topo_info" },
        { (void **)&ctrl->pfn_clear_ctrl_diag_event,      "lsi_clear_ctrl_diag_event" },
        { (void **)&ctrl->pfn_register_handle_event_info, "lsi_register_event_handler" },
        { (void **)&ctrl->pfn_trans_drive_data,           "lsi_trans_drive_data"}
    };

    gint32 num = (gint32)(sizeof(lsi_fun_table) / sizeof(lsi_fun_table[0]));
    return register_libsml_lsi_fun(lsi_fun_table, num);
}

static gint32 register_storagecore_function(SML_CTRL_S *ctrl)
{
#ifdef BUILD_SML_OPEN
    #define PMC_SML_LIB_PATH "/usr/lib64/libsml_pmc_open.so"
#else
    #define PMC_SML_LIB_PATH "/usr/lib64/libsml_pmc.so"
#endif

    SMLIB_SDK_FUNC_S pmc_fun_table[] = {
        { (void **)&ctrl->pfn_add_ctrl,                   "pmc_add_ctrl"},
        { (void **)&ctrl->pfn_remove_ctrl,                "pmc_remove_ctrl"},
        { (void **)&ctrl->pfn_init_ctrl_over_pcie,        "pmc_init_ctrl_manage"},
        { (void **)&ctrl->pfn_exit_ctrl_over_pcie,        "pmc_exit_ctrl_manage"},
        { (void **)&ctrl->pfn_update_ctrl_cache,          "pmc_update_ctrl_cache"},
        { (void **)&ctrl->pfn_get_ctrl_info,              "pmc_get_ctrl_info"},
        { (void **)&ctrl->pfn_get_ctrl_sas_addr,          "pmc_get_ctrl_sas_addr"},
        { (void **)&ctrl->pfn_get_ctrl_health,            "pmc_get_ctrl_health"},
        { (void **)&ctrl->pfn_get_ctrl_bbu_status,        "pmc_get_ctrl_bbu_status"},
        { (void **)&ctrl->pfn_get_ctrl_phy_err_count,     "pmc_get_ctrl_phy_err_count"},
        { (void **)&ctrl->pfn_get_ctrl_pd_list,           "pmc_get_ctrl_pd_list"},
        { (void **)&ctrl->pfn_get_ctrl_ld_list,           "pmc_get_ctrl_ld_list"},
        { (void **)&ctrl->pfn_get_ld_info,                "pmc_get_ld_info" },
        { (void **)&ctrl->pfn_get_ld_pd_list,             "pmc_get_ld_pd_list"},
        { (void **)&ctrl->pfn_get_pd_info,                "pmc_get_pd_info"},
        { (void **)&ctrl->pfn_pd_operation,               "pmc_pd_operations"},
        { (void **)&ctrl->pfn_get_ctrl_array_list,        "pmc_get_ctrl_array_list"},
        { (void **)&ctrl->pfn_get_array_info,             "pmc_get_array_info"},
        { (void **)&ctrl->pfn_config_operation,           "pmc_config_operations"},
        { (void **)&ctrl->pfn_ld_operation,               "pmc_ld_operations"},
        { (void **)&ctrl->pfn_ctrl_operation,             "pmc_ctrl_operations"},
    };

    gLibSmPmc = dlopen(PMC_SML_LIB_PATH, RTLD_LAZY);
    if (gLibSmPmc == NULL) {
        return SML_ERR_CTRL_LIB_LOAD_FAILED;
    }

    guint8 i;
    for (i = 0; i < G_N_ELEMENTS(pmc_fun_table); i++) {
        *(pmc_fun_table[i].pfunc) = dlsym(gLibSmPmc, pmc_fun_table[i].func_name);
        if (*(pmc_fun_table[i].pfunc) == NULL) {
            debug_log(DLOG_ERROR, "Unable to get Entry Point function address-%s.", pmc_fun_table[i].func_name);
            goto ERROR;
        }
    }

    return SML_SUCCESS;

ERROR:
    dlclose(gLibSmPmc);
    gLibSmPmc = NULL;
    for (i = 0; i < G_N_ELEMENTS(pmc_fun_table); i++) {
        *(pmc_fun_table[i].pfunc) = NULL;
    }
    return SML_ERR_CTRL_NO_FUNC_SYMBOL;
}

static gint32 register_libsml_histore_fun(SMLIB_SDK_FUNC_S *fun_table, guint8 num)
{
#ifdef BUILD_SML_OPEN
    #define HISTORE_SML_LIB_PATH "/usr/lib64/libsml_histore_open.so"
#else
    #define HISTORE_SML_LIB_PATH "/usr/lib64/libsml_histore.so"
#endif

    if (gLibSmHw == NULL) {
        gLibSmHw = dlopen(HISTORE_SML_LIB_PATH, RTLD_LAZY);
        if (gLibSmHw == NULL) {
            debug_log(DLOG_ERROR, "Failed to load histore sml library %s for RAID Controller. error : %s",
                      HISTORE_SML_LIB_PATH, dlerror());
            return SML_ERR_CTRL_LIB_LOAD_FAILED;
        }
    }
    guint8 i;
    for (i = 0; i < num; i++) {
        *(fun_table[i].pfunc) = dlsym(gLibSmHw, fun_table[i].func_name);
        if (*(fun_table[i].pfunc) == NULL) {
            debug_log(DLOG_ERROR, "Unable to get Entry Point function address-%s.", fun_table[i].func_name);
            continue;
        }
    }
    return SML_SUCCESS;
}

static gint32 register_histore_function(SML_CTRL_S *ctrl)
{
    SMLIB_SDK_FUNC_S histore_fun_table[] = {
        { (void **)&ctrl->pfn_add_ctrl,               "histore_add_ctrl"},
        { (void **)&ctrl->pfn_remove_ctrl,            "histore_remove_ctrl"},
        { (void **)&ctrl->pfn_init_ctrl_over_pcie,    "histore_init_ctrl_manage"},
        { (void **)&ctrl->pfn_exit_ctrl_over_pcie,    "histore_exit_ctrl_manage"},
        { (void **)&ctrl->pfn_get_ctrl_info,          "histore_get_ctrl_info"},
        { (void **)&ctrl->pfn_get_ctrl_sas_addr,      "histore_get_ctrl_sas_addr"},
        { (void **)&ctrl->pfn_get_ctrl_health,        "histore_get_ctrl_health" },
        { (void **)&ctrl->pfn_get_ctrl_bbu_status,    "histore_get_ctrl_bbu_status" },
        { (void **)&ctrl->pfn_get_ctrl_phy_err_count, "histore_get_ctrl_phy_err_count" },
        { (void **)&ctrl->pfn_get_ctrl_pd_list,       "histore_get_ctrl_pd_list"},
        { (void **)&ctrl->pfn_get_ctrl_ld_list,       "histore_get_ctrl_ld_list"},
        { (void **)&ctrl->pfn_get_ctrl_array_list,    "histore_get_ctrl_array_list"},
        { (void **)&ctrl->pfn_get_pd_info,            "histore_get_pd_info"},
        { (void **)&ctrl->pfn_get_ld_info,            "histore_get_ld_info"},
        { (void **)&ctrl->pfn_get_ld_pd_list,         "histore_get_ld_pd_list"},
        { (void **)&ctrl->pfn_get_array_info,         "histore_get_array_info"},
        { (void **)&ctrl->pfn_pd_operation,           "histore_pd_operations"},
        { (void **)&ctrl->pfn_config_operation,       "histore_config_operations"},
        { (void **)&ctrl->pfn_ld_operation,           "histore_ld_operations"},
        { (void **)&ctrl->pfn_ctrl_operation,         "histore_ctrl_operations"},
        { (void **)&ctrl->pfn_get_ctrl_parsed_log,    "histore_get_ctrl_parsed_log"},
        { (void **)&ctrl->pfn_trans_drive_data,       "histore_trans_drive_data"}
    };
    return register_libsml_histore_fun(histore_fun_table, G_N_ELEMENTS(histore_fun_table));
}

/*
 * Description: 初始化RAID控制器管理对象的构造函数
 * History: 1.2016年3月1日
 *          新生成函数
 */
static gint32 ctrl_manage_object_constructor(guint8 vender_index, SML_CTRL_S *ctrl)
{
    if (ctrl == NULL) {
        return SML_ERR_NULL_DATA;
    }

    if (vender_index == VENDER_LSI) {
        return register_storelib_function(ctrl);
    } else if (vender_index == VENDER_PMC) {
        return register_storagecore_function(ctrl);
    } else if (vender_index == VENDER_HUAWEI) {
        return register_histore_function(ctrl);
    } else {
        debug_log(DLOG_ERROR, "smlib : create controller management object failed, invalid vender index %d",
            vender_index);
        return SML_ERR_CTRL_PARAM_ILLEGAL;
    }

    return SML_SUCCESS;
}

/*
 * Description: smlib退出RAID控制器管理时的析构函数
 * History: 1.2016年3月1日
 *          新生成函数
 */
static void ctrl_manage_object_deconstructor(SML_CTRL_S *ctrl)
{
    if (ctrl == NULL) {
        return;
    }

    ctrl->pfn_add_ctrl = NULL;
    ctrl->pfn_remove_ctrl = NULL;
    ctrl->pfn_init_ctrl_over_i2c = NULL;
    ctrl->pfn_exit_ctrl_over_i2c = NULL;
    ctrl->pfn_init_ctrl_over_pcie = NULL;
    ctrl->pfn_exit_ctrl_over_pcie = NULL;
    ctrl->pfn_update_ctrl_cache = NULL;
    ctrl->pfn_get_ctrl_info = NULL;
    ctrl->pfn_get_ctrl_health = NULL;
    ctrl->pfn_get_ctrl_sas_addr = NULL;
    ctrl->pfn_get_ctrl_bbu_status = NULL;
    ctrl->pfn_get_ctrl_phy_err_count = NULL;
    ctrl->pfn_get_ctrl_ld_list = NULL;
    ctrl->pfn_get_ctrl_ld_list = NULL;
    ctrl->pfn_get_ld_info = NULL;
    ctrl->pfn_get_ld_pd_list = NULL;
    ctrl->pfn_get_pd_info = NULL;
    ctrl->pfn_get_pd_smart_info = NULL;
    ctrl->pfn_get_pd_smart_info_spec = NULL;
    ctrl->pfn_pd_operation = NULL;

    ctrl->pfn_get_ctrl_array_list = NULL;
    ctrl->pfn_get_array_info = NULL;
    ctrl->pfn_config_operation = NULL;
    ctrl->pfn_ld_operation = NULL;
    ctrl->pfn_ctrl_operation = NULL;
    // Do Here: 释放数据结构中的动态分配的内存
    ctrl->pfn_get_ctrl_boot_mode = NULL;

    ctrl->pfn_diag_encl_comm_error = NULL;
    ctrl->pfn_diag_pd_sense_error = NULL;
    ctrl->pfn_mock_diag_ctrl_event = NULL;
    ctrl->pfn_get_phy_diag_topo_info = NULL;
    ctrl->pfn_clear_ctrl_diag_event = NULL;
    ctrl->pfn_register_handle_event_info = NULL;
    ctrl->pfn_trans_drive_data = NULL;

    return;
}

static gint32 smlib_malloc_init(guint8 ctrl_index)
{
    if (gCtrlList[ctrl_index] == NULL) {
        g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
        if (gCtrlList[ctrl_index] == NULL) {
            gCtrlList[ctrl_index] = (SML_CTRL_S *)g_malloc0(sizeof(SML_CTRL_S));
            if (gCtrlList[ctrl_index] == NULL) {
                g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
                return SML_ERR_CANNOT_ALLOC_MEM;
            }
            g_mutex_init(&gCtrlList[ctrl_index]->ctrl_mutex);
            g_mutex_init(&gCtrlList[ctrl_index]->op_mutex);
            gCtrlList[ctrl_index]->controller.bbu.present = STORAGE_INFO_INVALID_BYTE;
        }
        g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
    }
    return SML_SUCCESS;
}

/*
 * Description: 添加控制器到smlib管理列表中
 * History: 1.2016年6月4日
 *          新生成函数
 *          2.2017年1月11日,  ()
 *          3.2017年10月28日,  ()
 *          增加3004 raid卡适配
 *          4.2018年5月3日
 *          3004 raid卡下硬盘温度更新30s一次
 */
gint32 smlib_add_ctrl(SML_CTRL_OOB_INFO_S *ctrl)
{
    if (ctrl == NULL) {
        return SML_ERR_NULL_DATA;
    }

    gint32 retval = SML_SUCCESS;
    guint8 ctrl_index = ctrl->i_controller_index;
    guint32 controller_id = 0;
    gint8 vender_index = 0;

    // 检查control index是否超出范围
    if (ctrl_index >= SML_MAX_RAID_CONTROLLER) {
        return SML_ERR_CTRL_INDEX_INVALID;
    }

    /* BEGIN: Modified on 2017/4/6   问题单号:SR-0000276589-001 */
    // 根据typeid组装controllerID
    retval = construct_ctrl_id(ctrl, &controller_id, &vender_index);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "smlib : construct ctrl id failed, return 0x%04x", retval);
        return retval;
    }
    /* END:   Modified on 2017/4/6 */
    if (smlib_malloc_init(ctrl_index) != SML_SUCCESS) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
    g_mutex_lock(&gCtrlList[ctrl_index]->ctrl_mutex);
    (void)memset_s(&gCtrlList[ctrl_index]->controller, sizeof(SML_CTRL_INFO_S), 0, sizeof(SML_CTRL_INFO_S));

    retval = ctrl_manage_object_constructor(vender_index, gCtrlList[ctrl_index]);
    if (retval != SML_SUCCESS) {
        g_mutex_unlock(&gCtrlList[ctrl_index]->ctrl_mutex);
        g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
        debug_log(DLOG_ERROR, "smlib : Add controller management [Ctrl index %d, Ctrl ID %d] failed, return 0x%04x\n",
            ctrl_index, SML_CTRL_ID_VALID_BIT(controller_id), retval);
        return SML_ERR_CTRL_INIT_FAILED;
    }

    g_mutex_unlock(&gCtrlList[ctrl_index]->ctrl_mutex);
    g_mutex_lock(&gCtrlList[ctrl_index]->op_mutex);

    if (gCtrlList[ctrl_index]->pfn_add_ctrl != NULL) {
        // 调用控制器对应的初始化接口
        retval = gCtrlList[ctrl_index]->pfn_add_ctrl(controller_id);
        if (SML_SUCCESS != retval) {
            debug_log(DLOG_ERROR,
                "smlib : Add controller management [Ctrl index %d, Ctrl ID %d] failed, return 0x%04x\n", ctrl_index,
                SML_CTRL_ID_VALID_BIT(controller_id), retval);
        }
    }

    g_mutex_unlock(&gCtrlList[ctrl_index]->op_mutex);
    g_mutex_lock(&gCtrlList[ctrl_index]->ctrl_mutex);

    gCtrlList[ctrl_index]->init_state = INIT_UNKNOWN_STATE;
    gCtrlList[ctrl_index]->controller_index = ctrl_index;
    gCtrlList[ctrl_index]->controller_id = controller_id;
    gCtrlList[ctrl_index]->is_registered = FALSE;

    g_mutex_unlock(&gCtrlList[ctrl_index]->ctrl_mutex);
    g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
    return retval;
}

static void register_handle_event_info(RegisterHandleEventInfoFunc register_handle,
    HANDLE_EVENT_INFO_FUNC handle_event_info_func)
{
    if (register_handle != NULL) {
        register_handle(handle_event_info_func);
    }
}

/*
 * 函 数 名  : pd_io_deterioration_record_event_info
 * 功能描述  : 用于smlib层调用的记录感兴趣的code信息
 */
gint32 pd_io_deterioration_record_event_info(guint8 slot_num, guint32 code)
{
    size_t ctrl_index = 0;
    size_t pd_index = 0;
    size_t pd_count = 0;
    gint32 retval = RET_ERR;
    SML_CTRL_S *sml_ctrl = NULL;
    SML_PD_INFO_S *pd_info = NULL;
    debug_log(DLOG_DEBUG, "%s: slot num:%u code:%u", __FUNCTION__, slot_num, code);
    for (; ctrl_index < SML_MAX_RAID_CONTROLLER; ++ctrl_index) {
        lock_ctrl_list_mutex(ctrl_index);
        sml_ctrl = get_ctrl_by_index(ctrl_index);
        if (sml_ctrl == NULL) {
            unlock_ctrl_list_mutex(ctrl_index);
            continue;
        }
        g_mutex_lock(&sml_ctrl->ctrl_mutex);
        pd_count = sml_ctrl->controller.pdlist.pd_count > SML_MAX_PHYSICAL_DRIVES ?
            SML_MAX_PHYSICAL_DRIVES : sml_ctrl->controller.pdlist.pd_count;
        for (pd_index = 0; pd_index < pd_count; ++pd_index) {
            if (slot_num == sml_ctrl->controller.pdlist.slot_num[pd_index]) {
                pd_info = &sml_ctrl->controller.pd[pd_index];
                g_mutex_unlock(&sml_ctrl->ctrl_mutex);
                unlock_ctrl_list_mutex(ctrl_index);
                break;
            }
        }
        if (pd_info != NULL) {
            break;
        }
        g_mutex_unlock(&sml_ctrl->ctrl_mutex);
        unlock_ctrl_list_mutex(ctrl_index);
    }
    if (pd_info != NULL) {
        switch (code) {
            case EVENT_CODE_UNEXPECTED_SENSE:
                pd_info->slow_disk_info.unexpected_sense_times++;
                retval = RET_OK;
                break;
            case EVENT_CODE_COMMAND_TIMEOUT:
                pd_info->slow_disk_info.cmd_timeout_times++;
                retval = RET_OK;
                break;
            default:
                retval = RET_ERR;
        }
    }
    return retval;
}

gint32 handle_event_info(SML_EVENT_DETAIL *evt_detail)
{
    if (evt_detail == NULL) {
        debug_log(DLOG_DEBUG, "%s: input is NULL", __FUNCTION__);
        return RET_ERR;
    }
    return pd_io_deterioration_record_event_info(evt_detail->pd_event.slot_num, evt_detail->pd_event.code);
}

/*
 * Description: smlib初始化控制器管理对象入口函数
 * History: 1.2016年4月6日
 *          新生成函数
 *          2.2017年1月11日,  ()
 */
gint32 smlib_init_ctrl_manage(SML_CTRL_OOB_INFO_S *ctrl)
{
    if (ctrl == NULL) {
        return SML_ERR_NULL_DATA;
    }

    guint8 ctrl_index = ctrl->i_controller_index;
    guint8 oob_interface_type = ctrl->i_oob_interface_type;
    I2C_WRITE_FUNC i2c_write_func = ctrl->register_info.over_i2c.i2c_write_func;
    I2C_WRITEREAD_FUNC i2c_writeread_func = ctrl->register_info.over_i2c.i2c_writeread_func;
    MCTP_WRITEREAD_FUNC mctp_writeread_func = ctrl->register_info.over_mctp.mctp_writeread_func;
    gint32 retval = SML_SUCCESS;

    // 检查control index是否超出范围
    if (ctrl_index >= SML_MAX_RAID_CONTROLLER) {
        return SML_ERR_CTRL_INDEX_INVALID;
    }
    g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
    if (gCtrlList[ctrl_index] == NULL) {
        g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
        return SML_ERR_CTRL_INIT_FAILED;
    }
    g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
    if (TRUE == _check_ctrl_is_registered(ctrl_index) && SML_SUCCESS == _check_ctrl_init_state(ctrl_index)) {
        return SML_ERR_CTRL_DUPLICATE_REGISTERED;
    }

    g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
    g_mutex_lock(&gCtrlList[ctrl_index]->ctrl_mutex);

    guint32 controller_id = gCtrlList[ctrl_index]->controller_id;
    g_mutex_unlock(&gCtrlList[ctrl_index]->ctrl_mutex);

    g_mutex_lock(&gCtrlList[ctrl_index]->op_mutex);
    register_handle_event_info(gCtrlList[ctrl_index]->pfn_register_handle_event_info, &handle_event_info);
    // 调用控制器对应的初始化接口
    if (oob_interface_type == OOB_TYPE_OVER_PCIE && gCtrlList[ctrl_index]->pfn_init_ctrl_over_pcie != NULL) {
        retval = gCtrlList[ctrl_index]->pfn_init_ctrl_over_pcie(controller_id, mctp_writeread_func);
    } else if (oob_interface_type == OOB_TYPE_OVER_I2C && gCtrlList[ctrl_index]->pfn_init_ctrl_over_i2c != NULL) {
        retval = gCtrlList[ctrl_index]->pfn_init_ctrl_over_i2c(controller_id, i2c_write_func, i2c_writeread_func);
    }

    if (SML_SUCCESS == retval) {
        gCtrlList[ctrl_index]->init_state = INIT_DONE;
    } else {
        gCtrlList[ctrl_index]->init_state = INIT_FAILED;
        debug_log(DLOG_DEBUG,
            "smlib : Initialize controller management [Ctrl index %d, Ctrl ID %d] failed, return 0x%04x\n",
            ctrl_index, SML_CTRL_ID_VALID_BIT(controller_id), retval);
    }
    g_mutex_unlock(&gCtrlList[ctrl_index]->op_mutex);

    g_mutex_lock(&gCtrlList[ctrl_index]->ctrl_mutex);
    gCtrlList[ctrl_index]->is_registered = TRUE;

    /* 初始化PHY误码历史数据的链表 */
    gCtrlList[ctrl_index]->controller.phy_history.ctrl_phy_list = NULL;
    gCtrlList[ctrl_index]->controller.phy_history.exp_phy_list = NULL;

    g_mutex_unlock(&gCtrlList[ctrl_index]->ctrl_mutex);
    g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
    return retval;
}

/*
 * Description: smlib退出RAID控制器管理的入口函数
 * History: 1.2016年3月1日
 *          新生成函数
 *          2.2017年1月11日,  ()
 *          3.2017年7月4日,  ()
 *          只退出带外管理，不清除控制器节点数据
 */
gint32 smlib_exit_ctrl_manage(SML_CTRL_OOB_INFO_S *ctrl)
{
    if (ctrl == NULL) {
        return SML_ERR_NULL_DATA;
    }

    gint32 retval = SML_SUCCESS;
    guint8 ctrl_index = ctrl->i_controller_index;
    guint8 oob_interface_type = ctrl->i_oob_interface_type;

    if (ctrl_index >= SML_MAX_RAID_CONTROLLER) {
        return SML_ERR_CTRL_INDEX_INVALID;
    }
    g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
    if (gCtrlList[ctrl_index] == NULL) {
        g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
        return SML_ERR_CTRL_INIT_FAILED;
    }
    g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);

    if (TRUE != _check_ctrl_is_registered(ctrl_index)) {
        return SML_ERR_CTRL_NOT_REGISTERED;
    }

    g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
    g_mutex_lock(&gCtrlList[ctrl_index]->op_mutex);
    if (oob_interface_type == OOB_TYPE_OVER_PCIE && gCtrlList[ctrl_index]->pfn_exit_ctrl_over_pcie != NULL) {
        retval = gCtrlList[ctrl_index]->pfn_exit_ctrl_over_pcie(gCtrlList[ctrl_index]->controller_id, NULL);
    } else if (oob_interface_type == OOB_TYPE_OVER_I2C && gCtrlList[ctrl_index]->pfn_exit_ctrl_over_i2c != NULL) {
        retval = gCtrlList[ctrl_index]->pfn_exit_ctrl_over_i2c(gCtrlList[ctrl_index]->controller_id, NULL, NULL);
    }
    g_mutex_unlock(&gCtrlList[ctrl_index]->op_mutex);

    g_mutex_lock(&gCtrlList[ctrl_index]->ctrl_mutex);

    /* 清空PHY误码诊断历史数据 */
    fd_remove_phy_diag_history_info(&gCtrlList[ctrl_index]->controller.phy_history);

    (void)memset_s(&gCtrlList[ctrl_index]->controller, sizeof(SML_CTRL_INFO_S), 0x00, sizeof(SML_CTRL_INFO_S));

    gCtrlList[ctrl_index]->init_state = INIT_UNKNOWN_STATE;
    gCtrlList[ctrl_index]->is_registered = FALSE;

    g_mutex_unlock(&gCtrlList[ctrl_index]->ctrl_mutex);

    // 开始清空内存
    if (gCtrlList[ctrl_index] != NULL) {
        g_free(gCtrlList[ctrl_index]);
        gCtrlList[ctrl_index] = NULL;
    }
    g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);

    return retval;
}

/*
 * Description: smlib删除RAID控制器节点信息的入口函数
 * History: 1.2017年7月4日,  ()
 *          新生成函数
 *          2.2018年12月4日
 */
gint32 smlib_remove_ctrl(guint8 ctrl_index)
{
    gint32 retval = SML_SUCCESS;
    guint32 tmp_ctrl_id = 0;

    if (ctrl_index >= SML_MAX_RAID_CONTROLLER) {
        return SML_ERR_CTRL_INDEX_INVALID;
    }
    g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
    if (gCtrlList[ctrl_index] == NULL) {
        g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
        return SML_ERR_CTRL_INIT_FAILED;
    }

    g_mutex_lock(&gCtrlList[ctrl_index]->op_mutex);
    if (gCtrlList[ctrl_index]->pfn_remove_ctrl) {
        retval = gCtrlList[ctrl_index]->pfn_remove_ctrl(gCtrlList[ctrl_index]->controller_id);
    }
    g_mutex_unlock(&gCtrlList[ctrl_index]->op_mutex);

    g_mutex_lock(&gCtrlList[ctrl_index]->ctrl_mutex);
    ctrl_manage_object_deconstructor(gCtrlList[ctrl_index]);

    /* 清空PHY误码诊断历史数据 */
    fd_remove_phy_diag_history_info(&gCtrlList[ctrl_index]->controller.phy_history);

    (void)memset_s(&gCtrlList[ctrl_index]->controller, sizeof(SML_CTRL_INFO_S), 0x00, sizeof(SML_CTRL_INFO_S));

    tmp_ctrl_id = gCtrlList[ctrl_index]->controller_id;
    gCtrlList[ctrl_index]->controller_id = 0;
    gCtrlList[ctrl_index]->controller_index = 0xff;
    gCtrlList[ctrl_index]->init_state = INIT_UNKNOWN_STATE;
    gCtrlList[ctrl_index]->is_registered = FALSE;
    g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);

    /* 为避免死锁，剔除i等于ctrl_index的情况，该情况已经在上面赋值成功 */
    for (gint32 i = 0; i < SML_MAX_RAID_CONTROLLER; i++) {
        if (i == ctrl_index) {
            continue;
        }
        g_mutex_lock(&g_ctrl_list_mutex[i]);
        if (gCtrlList[i] == NULL) {
            g_mutex_unlock(&g_ctrl_list_mutex[i]);
            continue;
        }
        if (gCtrlList[i]->controller_index == 0xff ||
            (LSI_STORELIB_TYPE_VALID_BIT(tmp_ctrl_id) != LSI_STORELIB_TYPE_VALID_BIT(gCtrlList[i]->controller_id))) {
            g_mutex_unlock(&g_ctrl_list_mutex[i]);
            continue;
        }

        gCtrlList[i]->init_state = INIT_UNKNOWN_STATE;
        gCtrlList[i]->is_registered = FALSE;
        g_mutex_unlock(&g_ctrl_list_mutex[i]);
    }

    g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
    g_mutex_unlock(&gCtrlList[ctrl_index]->ctrl_mutex);
    g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);

    return retval;
}

/*
 * Description: 调用第三方软件接口更新缓存数据
 * History: 1.2017年6月1日
 *          新生成函数
 */
gint32 smlib_update_ctrl_cache(guint8 ctrl_index)
{
    gint32 retval = SML_SUCCESS;
    g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
    if (gCtrlList[ctrl_index] == NULL) {
        g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
        return SML_ERR_CTRL_INIT_FAILED;
    }

    g_mutex_lock(&gCtrlList[ctrl_index]->op_mutex);
    if (gCtrlList[ctrl_index]->pfn_update_ctrl_cache) {
        retval = gCtrlList[ctrl_index]->pfn_update_ctrl_cache(gCtrlList[ctrl_index]->controller_id);
    }
    g_mutex_unlock(&gCtrlList[ctrl_index]->op_mutex);
    g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);

    return retval;
}

/*
 * Description: 标记对应的RAID缓存已经失效，下次如果请求该信息，直接从RAID控制器实时存取
 * History: 1.2016年11月12日,  ()
 *          新生成函数
 */
void smlib_invalid_ctrl_cached_info(guint8 ctrl_index, guint32 type_mask)
{
    gint32 retval = SML_SUCCESS;
    guint16 info_idx = 0;

    retval = check_input_parameters(ctrl_index, (gpointer)1);
    if (SML_SUCCESS != retval) {
        return;
    }
    g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
    if (gCtrlList[ctrl_index] == NULL) {
        g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
        return;
    }

    g_mutex_lock(&gCtrlList[ctrl_index]->ctrl_mutex);
    if (type_mask & CTRL_INFO_TYPE_CTRL) {
        gCtrlList[ctrl_index]->controller.ctrl.last_update_timestamp = 0;
    }
    if (type_mask & CTRL_INFO_TYPE_HEALTH) {
        gCtrlList[ctrl_index]->controller.health.last_update_timestamp = 0;
    }
    if (type_mask & CTRL_INFO_TYPE_SAS_ADDR) {
        gCtrlList[ctrl_index]->controller.sas_addr.last_update_timestamp = 0;
    }
    if (type_mask & CTRL_INFO_TYPE_BBU) {
        gCtrlList[ctrl_index]->controller.bbu.last_update_timestamp = 0;
    }
    if (type_mask & CTRL_INFO_TYPE_PHY) {
        gCtrlList[ctrl_index]->controller.phy.last_update_timestamp = 0;
    }

    if (type_mask & CTRL_INFO_TYPE_LDLIST) {
        gCtrlList[ctrl_index]->controller.ldlist.last_update_timestamp = 0;
    }

    if (type_mask & CTRL_INFO_TYPE_LD) {
        for (info_idx = 0; info_idx < gCtrlList[ctrl_index]->controller.ldlist.ld_count; info_idx++) {
            gCtrlList[ctrl_index]->controller.ld[info_idx].ldinfo.last_update_timestamp = 0;
        }
    }

    if (type_mask & CTRL_INFO_TYPE_ARRAYLIST) {
        gCtrlList[ctrl_index]->controller.arraylist.last_update_timestamp = 0;
    }

    g_mutex_unlock(&gCtrlList[ctrl_index]->ctrl_mutex);
    g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
}

/*
 * Description: 标记逻辑盘信息下次刷新方式: 从RAID控制器刷新指定的逻辑盘的信息，而其它的逻辑盘信息全部从全局缓存获取
 * History: 1.2016年12月22日,  ()
 *          新生成函数
 */
void smlib_refresh_specfied_ld_from_hw_next(guint8 ctrl_index, guint16 ld_target_id, guint8 refresh_cnt)
{
    gint32 retval = SML_SUCCESS;
    gint32 i = 0;
    guint8 refresh_from_hw = 0;
    guint8 refresh_from_cache = 0;

    retval = check_input_parameters(ctrl_index, (gpointer)1);
    if (SML_SUCCESS != retval) {
        return;
    }
    g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
    if (gCtrlList[ctrl_index] == NULL) {
        g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
        return;
    }

    refresh_from_hw = ((refresh_cnt << 4) & 0xf0) | RAID_REFRESH_CONTROLLER;
    refresh_from_cache = ((refresh_cnt << 4) & 0xf0) | RAID_REFRESH_INTERNAL_CACHE;

    g_mutex_lock(&gCtrlList[ctrl_index]->ctrl_mutex);

    for (i = 0; i < SML_MAX_NUM_OF_IDS; i++) {
        if (ld_target_id == i) {
            gCtrlList[ctrl_index]->controller.ld_refresh_ctrl[i] = refresh_from_hw;
            gCtrlList[ctrl_index]->controller.pd_in_ld_refresh_ctrl[i] = refresh_from_hw;
        } else {
            // 只有使用默认刷新策略的才强制从缓存刷新，避免覆盖掉已经设置为强制刷新的策略
            if (RAID_REFRESH_DEFAULT == (gCtrlList[ctrl_index]->controller.ld_refresh_ctrl[i] & 0x0f)) {
                gCtrlList[ctrl_index]->controller.ld_refresh_ctrl[i] = refresh_from_cache;
            }

            if (RAID_REFRESH_DEFAULT == (gCtrlList[ctrl_index]->controller.pd_in_ld_refresh_ctrl[i] & 0x0f)) {
                gCtrlList[ctrl_index]->controller.pd_in_ld_refresh_ctrl[i] = refresh_from_cache;
            }
        }
    }

    g_mutex_unlock(&gCtrlList[ctrl_index]->ctrl_mutex);
    g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
}

/*
 * Description: 标记array信息下次刷新方式: 从RAID控制器刷新指定的array的信息，而其它的array信息全部从全局缓存获取
 * History: 1.2016年12月29日,  ()
 *          新生成函数
 */
void smlib_refresh_specfied_arrays_from_hw_next(guint8 ctrl_index, guint16 *array_refs, guint8 array_count,
    guint8 refresh_cnt)
{
    gint32 retval = SML_SUCCESS;
    gint32 i = 0;
    guint8 refresh_from_hw = 0;
    guint8 refresh_from_cache = 0;
    guint8 refresh_idx;

    retval = check_input_parameters(ctrl_index, array_refs);
    if (SML_SUCCESS != retval) {
        return;
    }

    if (array_count > SML_MAX_SPAN_DEPTH) {
        return;
    }
    g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
    if (gCtrlList[ctrl_index] == NULL) {
        g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
        return;
    }

    refresh_from_hw = ((refresh_cnt << 4) & 0xf0) | RAID_REFRESH_CONTROLLER;
    refresh_from_cache = ((refresh_cnt << 4) & 0xf0) | RAID_REFRESH_INTERNAL_CACHE;

    g_mutex_lock(&gCtrlList[ctrl_index]->ctrl_mutex);

    // 先设置所有array信息从cache刷新
    for (i = 0; i < SML_MAX_NUM_OF_IDS; i++) {
        // 只有使用默认刷新策略的才强制从缓存刷新，避免覆盖掉已经设置为强制刷新的策略
        if (RAID_REFRESH_DEFAULT == (gCtrlList[ctrl_index]->controller.array_refresh_ctrl[i] & 0x0f)) {
            gCtrlList[ctrl_index]->controller.array_refresh_ctrl[i] = refresh_from_cache;
        }
    }

    // 设置从控制器刷新指定array的信息，array的id为两个字节，实际上array个数不可能超过最大物理盘个数
    for (i = 0; i < array_count; i++) {
        refresh_idx = array_refs[i] & 0x00ff;
        gCtrlList[ctrl_index]->controller.array_refresh_ctrl[refresh_idx] = refresh_from_hw;
    }

    g_mutex_unlock(&gCtrlList[ctrl_index]->ctrl_mutex);
    g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
}

/*
 * Description: 标记array信息下次刷新方式: 从RAID控制器刷新指定物理盘的信息，而其它的物理盘信息全部从全局缓存获取
 * History: 1.2017年1月3日,  ()
 *          新生成函数
 */
void smlib_refresh_specfied_pds_from_hw_next(guint8 ctrl_index, guint16 *pd_ids, guint8 pd_count, guint8 refresh_cnt)
{
    gint32 retval = SML_SUCCESS;
    gint32 i = 0;
    guint8 refresh_from_hw = 0;
    guint8 refresh_from_cache = 0;
    guint8 slot_id = 0;
    guint16 pd_index = 0;

    retval = check_input_parameters(ctrl_index, pd_ids);
    if (SML_SUCCESS != retval) {
        return;
    }
    g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
    if (gCtrlList[ctrl_index] == NULL) {
        g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
        return;
    }

    refresh_from_hw = ((refresh_cnt << 4) & 0xf0) | RAID_REFRESH_CONTROLLER;
    refresh_from_cache = ((refresh_cnt << 4) & 0xf0) | RAID_REFRESH_INTERNAL_CACHE;

    g_mutex_lock(&gCtrlList[ctrl_index]->ctrl_mutex);

    // 先设置所有物理盘信息从cache刷新
    for (i = 0; i < SML_MAX_NUM_OF_IDS; i++) {
        // 只有使用默认刷新策略的才强制从缓存刷新，避免覆盖掉已经设置为强制刷新的策略
        if (RAID_REFRESH_DEFAULT == (gCtrlList[ctrl_index]->controller.pd_refresh_ctrl[i] & 0x0f)) {
            gCtrlList[ctrl_index]->controller.pd_refresh_ctrl[i] = refresh_from_cache;
        }
    }

    // 设置从控制器刷新指定物理盘的信息，数组下标为物理盘的槽位号
    for (i = 0; i < pd_count; i++) {
        if (RET_OK == check_pd_device_id(pd_ids[i], &gCtrlList[ctrl_index]->controller.pdlist, &pd_index)) {
            slot_id = gCtrlList[ctrl_index]->controller.pdlist.slot_num[pd_index];
            gCtrlList[ctrl_index]->controller.pd_refresh_ctrl[slot_id] = refresh_from_hw;
        }
    }

    g_mutex_unlock(&gCtrlList[ctrl_index]->ctrl_mutex);
    g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
}

/*
 * Description: 标记逻辑盘信息下次刷新方式: 从内部缓存刷新所有的逻辑盘的信息，用于删除逻辑盘的情形
 * History: 1.2016年12月22日,  ()
 *          新生成函数
 */
void smlib_refresh_all_lds_from_cache_next(guint8 ctrl_index, guint8 refresh_cnt)
{
    gint32 retval = SML_SUCCESS;
    gint32 i = 0;
    guint8 refresh_from_cache = 0;

    retval = check_input_parameters(ctrl_index, (gpointer)1);
    if (SML_SUCCESS != retval) {
        return;
    }
    g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
    if (gCtrlList[ctrl_index] == NULL) {
        g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
        return;
    }

    refresh_from_cache = ((refresh_cnt << 4) & 0xf0) | RAID_REFRESH_INTERNAL_CACHE;

    g_mutex_lock(&gCtrlList[ctrl_index]->ctrl_mutex);

    for (i = 0; i < SML_MAX_NUM_OF_IDS; i++) {
        // 只有使用默认刷新策略的才强制从缓存刷新，避免覆盖掉已经设置为强制刷新的策略
        if (RAID_REFRESH_DEFAULT == (gCtrlList[ctrl_index]->controller.ld_refresh_ctrl[i] & 0x0f)) {
            gCtrlList[ctrl_index]->controller.ld_refresh_ctrl[i] = refresh_from_cache;
        }

        if (RAID_REFRESH_DEFAULT == (gCtrlList[ctrl_index]->controller.pd_in_ld_refresh_ctrl[i] & 0x0f)) {
            gCtrlList[ctrl_index]->controller.pd_in_ld_refresh_ctrl[i] = refresh_from_cache;
        }
    }

    g_mutex_unlock(&gCtrlList[ctrl_index]->ctrl_mutex);
    g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
}

/*
 * Description: 标记array信息下次刷新方式: 从RAID控制器刷新所有的array的信息
 * History: 1.2016年12月29日,  ()
 *          新生成函数
 */
void smlib_refresh_all_arrays_from_cache_next(guint8 ctrl_index, guint8 refresh_cnt)
{
    gint32 retval = SML_SUCCESS;
    gint32 i = 0;
    guint8 refresh_from_cache = 0;

    retval = check_input_parameters(ctrl_index, (gpointer)1);
    if (SML_SUCCESS != retval) {
        return;
    }
    g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
    if (gCtrlList[ctrl_index] == NULL) {
        g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
        return;
    }

    refresh_from_cache = ((refresh_cnt << 4) & 0xf0) | RAID_REFRESH_INTERNAL_CACHE;

    g_mutex_lock(&gCtrlList[ctrl_index]->ctrl_mutex);

    // 设置所有array信息从cache刷新
    for (i = 0; i < SML_MAX_NUM_OF_IDS; i++) {
        // 只有使用默认刷新策略的才强制从缓存刷新，避免覆盖掉已经设置为强制刷新的策略
        if (RAID_REFRESH_DEFAULT == (gCtrlList[ctrl_index]->controller.array_refresh_ctrl[i] & 0x0f)) {
            gCtrlList[ctrl_index]->controller.array_refresh_ctrl[i] = refresh_from_cache;
        }
    }

    g_mutex_unlock(&gCtrlList[ctrl_index]->ctrl_mutex);
    g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
}

/*
 * Description: 标记array信息下次刷新方式: 从RAID控制器刷新所有的物理盘的信息
 * History: 1.2017年1月3日,  ()
 *          新生成函数
 */
void smlib_refresh_all_pds_from_cache_next(guint8 ctrl_index, guint8 refresh_cnt)
{
    gint32 retval = SML_SUCCESS;
    gint32 i = 0;
    guint8 refresh_from_cache = 0;

    retval = check_input_parameters(ctrl_index, (gpointer)1);
    if (SML_SUCCESS != retval) {
        return;
    }
    g_mutex_lock(&g_ctrl_list_mutex[ctrl_index]);
    if (gCtrlList[ctrl_index] == NULL) {
        g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
        return;
    }

    refresh_from_cache = ((refresh_cnt << 4) & 0xf0) | RAID_REFRESH_INTERNAL_CACHE;

    g_mutex_lock(&gCtrlList[ctrl_index]->ctrl_mutex);

    // 设置所有array信息从cache刷新
    for (i = 0; i < SML_MAX_NUM_OF_IDS; i++) {
        // 只有使用默认刷新策略的才强制从缓存刷新，避免覆盖掉已经设置为强制刷新的策略
        if (RAID_REFRESH_DEFAULT == (gCtrlList[ctrl_index]->controller.pd_refresh_ctrl[i] & 0x0f)) {
            gCtrlList[ctrl_index]->controller.pd_refresh_ctrl[i] = refresh_from_cache;
        }
    }

    g_mutex_unlock(&gCtrlList[ctrl_index]->ctrl_mutex);
    g_mutex_unlock(&g_ctrl_list_mutex[ctrl_index]);
}

/*
 * Description: 标记信息下次刷新方式:设置除指定控制器外的其余控制器的所有信息从缓存刷新
 * History: 1.2017年1月11日,  ()
 *          新生成函数
 */
void smlib_refresh_all_other_from_cache_next(guint8 ctrl_index, guint8 refresh_cnt)
{
    gint32 retval = SML_SUCCESS;
    gint32 i = 0;

    retval = check_input_parameters(ctrl_index, (gpointer)1);
    if (SML_SUCCESS != retval) {
        return;
    }

    for (i = 0; i < SML_MAX_RAID_CONTROLLER; i++) {
        if (SML_SUCCESS == check_input_parameters(i, (gpointer)1)) {
            if (ctrl_index != i) {
                smlib_refresh_all_lds_from_cache_next(i, refresh_cnt);
                smlib_refresh_all_arrays_from_cache_next(i, refresh_cnt);
                smlib_refresh_all_pds_from_cache_next(i, refresh_cnt);
            }
        }
    }
}
/* END:   Added on 2017/1/11 */
/*
 * Description: 从缓存中清除启动优先级
 */
void smlib_clear_boot_priority_from_cache(SML_CTRL_S* sml_ctrl, guint8 boot_priority)
{
    /* 1.设置当前设备为None，所有设备的优先级不需要清除 */
    if (boot_priority == BOOT_PRIORITY_NONE) {
        return;
    }
    
    /* 2.设置当前设备为All，将所有设备的优先级清除 */
    guint16 i;

    if (boot_priority == BOOT_PRIORITY_ALL) {
        for (i = 0; i < sml_ctrl->controller.ldlist.ld_count; i++) {
            if (sml_ctrl->controller.ld[i].ldinfo.boot_priority != BOOT_PRIORITY_NONE) {
                sml_ctrl->controller.ld[i].ldinfo.boot_priority = BOOT_PRIORITY_NONE;
            }
        }

        for (i = 0; i < sml_ctrl->controller.pdlist.pd_count; i++) {
            if (sml_ctrl->controller.pd[i].pdinfo.boot_priority != BOOT_PRIORITY_NONE) {
                sml_ctrl->controller.pd[i].pdinfo.boot_priority = BOOT_PRIORITY_NONE;
            }
        }
        return;
    /* 3.设置当前设备为Primary或Secondary，1)如果已存在对应的Primary或Secondary，要清除;2)如果已存在All，要清掉Primary或Secondary */
    } else {
        for (i = 0; i < sml_ctrl->controller.ldlist.ld_count; i++) {
            if (sml_ctrl->controller.ld[i].ldinfo.boot_priority == boot_priority) {
                sml_ctrl->controller.ld[i].ldinfo.boot_priority = BOOT_PRIORITY_NONE;
                return; // 匹配上了就可以返回
            }

            if (sml_ctrl->controller.ld[i].ldinfo.boot_priority == BOOT_PRIORITY_ALL) {
                sml_ctrl->controller.ld[i].ldinfo.boot_priority = BOOT_PRIORITY_ALL - boot_priority;
                return; // 匹配上了就可以返回
            }
        }

        for (i = 0; i < sml_ctrl->controller.pdlist.pd_count; i++) {
            if (sml_ctrl->controller.pd[i].pdinfo.boot_priority == boot_priority) {
                sml_ctrl->controller.pd[i].pdinfo.boot_priority = BOOT_PRIORITY_NONE;
                return; // 匹配上了就可以返回
            }

            if (sml_ctrl->controller.pd[i].pdinfo.boot_priority == BOOT_PRIORITY_ALL) {
                sml_ctrl->controller.pd[i].pdinfo.boot_priority = BOOT_PRIORITY_ALL - boot_priority;
                return; // 匹配上了就可以返回
            }
        }

        return;
    }
}

/*
 * Description: 根据错误代码填充错误描述信息
 * History: 1.2016年11月28日,  ()
 *          新生成函数
 */
void smlib_fill_err_msg(gint32 err_code, gchar *err_msg, gint32 max_len)
{
    guint32 idx = 0;

    if (NULL == err_msg) {
        return;
    }
    errno_t securec_rv = memset_s(err_msg, max_len, 0, max_len);
    if (securec_rv != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s failed, ret = %d", __FUNCTION__, securec_rv);
    }

    for (idx = 0; idx < ERR_MSG_CNT; idx++) {
        if (err_info_map[idx].err_code == err_code) {
            break;
        }
    }
    if (idx >= ERR_MSG_CNT) {
        return;
    }
    securec_rv = strncpy_s(err_msg, max_len, err_info_map[idx].err_msg, max_len - 1);
    if (securec_rv != EOK) {
        debug_log(DLOG_ERROR, "%s: strncpy_s failed, ret = %d", __FUNCTION__, securec_rv);
    }
}

/*
 * Description: 移除PHY误码诊断历史数据
 * History: 1.2019年1月21日,
 *          新生成函数
 */
static void fd_remove_phy_diag_history_info(SML_PHY_DIAG_HISTORY_INFO_S *history_info)
{
    if (history_info == NULL) {
        return;
    }

    g_list_free_full(history_info->ctrl_phy_list, g_free);
    history_info->ctrl_phy_list = NULL;

    g_list_free_full(history_info->exp_phy_list, g_free);
    history_info->exp_phy_list = NULL;

    return;
}