/* 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 "platform.h"
#include "sml_errcodes.h"
#include "sml_public.h"
#include "histore/tool_lib.h"
#include "histore/error_code.h"
#include "hs_misc.h"

/* ----------------------------------------------*
 * 宏定义                                       *
 * ---------------------------------------------- */

#define LOW(a) ((guint8)((a) & 0xff))
#define HISTORE_LIB "/usr/lib64/raidlib.so"

typedef struct _ERROR_CODE_MAP {
    guint32 hs_error_code;
    guint32 sml_error_code;
} ERROR_CODE_MAP;

typedef int (*ExitLibhistore)(void);
typedef int (*InitLibhistore)(struct store_lib_conf *conf);
typedef gint32 (*HISTORE_MCTP_WRITEREAD_FUNC)(guint8 pci_eid, guint32 request_length, const guint8 *request,
    guint32 *response_length, guint8 *response);
typedef void (*RegisterMCTPFunc)(HISTORE_MCTP_WRITEREAD_FUNC mctp_writeread_func);
typedef int (*HISTORE_GETS_EID_FUNC)(guint8 ctrl_id, guint8 *pci_eid);
typedef void (*RegisterGetEidFunc)(HISTORE_GETS_EID_FUNC get_eid_func);
typedef guint32 (*ProcessHistoreCmdFunc)(struct lib_cmd_param *param);
typedef int (*HistoreAddAdapter)(struct adapter_descriptor *adpater);
typedef gint32 (*HistoreGetParsedLog)(const gchar *source_file_path, const gchar *parsed_file_path);

// 用于保存RAID卡的各项数据，保证app一次轮询周期内每种get类命令对RAID卡只下发一次
typedef struct tag_ctrl_cache_info {
    GMutex mutex;
    GHashTable *hash_table[CACHE_TYPE_BUTT];
} CTRL_CACHE_INFO_S;

/* ----------------------------------------------*
 * 本地全局变量                                   *
 * ---------------------------------------------- */
static void *g_lib_handle = NULL;
static ProcessHistoreCmdFunc g_pfn_process_command = NULL;
static CTRL_CACHE_INFO_S g_cache_info[SML_MAX_RAID_CONTROLLER];
static ERROR_CODE_MAP g_error_code_map[] = {
    { SC_SUBOPCODE_INVALID,          SML_SUCCESS },    /* 对于卡侧暂不支持的subopcode的情况按照成功处理 */
    { SC_OPERATE_UNSUPPORT,          SML_ERR_CTRL_STATUS_INVALID },    /* 卡侧不支持的操作 */
    { SC_DISK_ID_INVALID,            SML_ERR_PD_INVALID_DEVICE_ID },            /* Disk ID无效（如关phy） */
    { SC_RAID_LOCAL_HSP_INCOMPATIBE, SML_ERR_PD_STATE_UNSUPPORTED_TO_SET },     /* 局部热备与RAID组不匹配 */
    { SC_RAID_LOCAL_HSP_REPEATE_SET, SML_ERR_PD_STATE_UNSUPPORTED_TO_SET },     /* 局部热备重复设置 */
    { SC_RAID_LOCAL_HSP_NUM_EXCEED,  SML_ERR_PD_OPERATION_NOT_SUPPORT },  /* 局部热备设置数目超上限 */
    { SC_RAID_HSP_IS_HALF_LIFE,      SML_ERR_PD_STATE_UNSUPPORTED_TO_SET },     /* 盘半条命,不能设置为热备盘 */
    { SC_RAID_HSP_IS_FAULT,          SML_ERR_PD_STATE_UNSUPPORTED_TO_SET },     /* 盘已失效,不能设置为热备盘 */
    { SC_RAID_HSP_SET_INVALID,       SML_ERR_PD_STATE_UNSUPPORTED_TO_SET },     /* 未选择空闲盘设置设置热备,或未选择热备盘设置设置空闲 */
    { SC_RAID_GLOBAL_HSP_NUM_EXCEED, SML_ERR_PD_OPERATION_NOT_SUPPORT },  /* 全局热备设置数目超上限 */
    { SC_RAID_LOCAL_HSP_TOO_SMALL_CAPACITY,  SML_ERR_CONFIG_ASSOCIATED_LD_SIZE_OUT_OF_RANGE }, /* 热备盘容量小于成员盘最小容量 */
    { SC_RAID_LOCAL_HSP_RG_NOT_SUPPORT,      SML_ERR_PD_SPARE_FOR_RAID0_LD }, /* 该RAID组不支持局部热备 */
    { SC_RAID_LOCAL_HSP_MEDIA_MISMATCH,      SML_ERR_PD_SPARE_SDD_HDD_MIXED }, /* 局部热备与RAID组介质不匹配 */
    { SC_RAID_LOCAL_HSP_BLOCK_SIZE_MISMATCH, SML_ERR_CONFIG_BLOCK_SIZE_NOT_SAME}, /* 局部热备与成员盘块大小不匹配 */
    { SC_PARAM_INVALID,              SML_ERR_INVALID_PARAMETER}, /* 参数不在可接受的范围内 */

    /* RAID组管理 */
    { SC_RAID_RG_LEVEL_NOT_MATCH,           SML_ERR_CONFIG_INVALID_PARAM_RAID_LEVEL}, /* 创建RAID组失败,因为级别不匹配 */
    { SC_RAID_RG_MEMBER_DISK_NUM_INVALID,   SML_ERR_CONFIG_OPERATION_NOT_SUPPORT }, /* 创建RAID组失败,因为成员盘数量非法 */
    { SC_RAID_RG_ID_USE_UP,                 SML_ERR_CONFIG_ARRAY_NUM_REACHED_LIMIT }, /* 创建RAID组失败,因为RAID组数目超上限 */
    { SC_RAID_RG_NAME_REPEAT,               SML_ERR_CONFIG_OPERATION_NOT_SUPPORT }, /* 创建RAID组失败,因为RAID组名字重复 */
    { SC_RAID_RG_CACHE_SW_INVALID,          SML_ERR_CTRL_STATUS_INVALID }, /* 创建RAID组失败,因为cache开关非法 */
    { SC_RAID_RG_PHYSICS_TYPE_INVALID,      SML_ERR_CONFIG_INVALID_PD_SDD_HDD_MIXED }, /* 创建RAID组失败,因为成员盘物理类型不兼容 */
    { SC_RAID_RG_MEMBER_DISK_REPEAT,        SML_ERR_CONFIG_INVALID_PARAM_REPEATED_PD_ID }, /* 创建RAID组失败,因为成员盘重复选择 */
    { SC_RAID_RG_DISK_NOT_BELONG,           SML_ERR_CONFIG_OPERATION_NOT_SUPPORT }, /* 创建RAID组失败,因为盘不属于该RAID组 */
    { SC_RAID_RG_NAME_LENGTH_EXCEED,        SML_ERR_INVALID_PARAMETER }, /* 创建RAID组失败,因为RAID组名字太长 */
    { SC_RAID_RG_MEMBER_DISK_STATUS_INVALID,    SML_ERR_CONFIG_INVALID_PD_IN_USE }, /* 创建RAID组失败,因为成员盘状态非法 */

    /* LUN管理 */
    { SC_RAID_LUN_PF_NOT_MATCH,             SML_ERR_CONFIG_OPERATION_NOT_SUPPORT }, /* 创建LUN失败,因为PF类型和上报类型不一致 */
    { SC_RAID_LUN_WRITE_CACHE_NOT_MATCH,    SML_ERR_CONFIG_OPERATION_NOT_SUPPORT }, /* 创建LUN失败,因为LUN cache类型和RAID组不匹配 */
    { SC_RAID_LUN_RG_LEVEL_NOT_MATCH,       SML_ERR_CONFIG_INVALID_PARAM_RAID_LEVEL }, /* 创建LUN失败,因为LUN 级别和RAID组不匹配 */
    { SC_RAID_LUN_TYPE_NOT_MATCH,           SML_ERR_CONFIG_OPERATION_NOT_SUPPORT }, /* 创建LUN失败,因为LUN物理类型和RAID组不匹配 */
    { SC_RAID_LUN_DIRTY_DATA_EXIST,         SML_ERR_CONFIG_OPERATION_NOT_SUPPORT }, /* 创建LUN失败,因为失效LUN脏数据未清除 */
    { SC_RAID_LUN_NUM_PER_RG_EXCEED,        SML_ERR_CONFIG_OPERATION_NOT_SUPPORT }, /* 创建LUN失败,因为单RAID组LUN数量超上限 */
    { SC_RAID_LUN_DYNAMIC_IS_RUNNING,       SML_ERR_CONFIG_OPERATION_NOT_SUPPORT }, /* 创建LUN失败,因为扩盘任务存在 */
    { SC_RAID_LUN_DISK_STATUS_INVALID,      SML_ERR_CONFIG_INVALID_PD_OTHER_ERROR }, /* 创建LUN失败,因为成员盘状态非法 */
    { SC_RAID_LUN_SIZE_ZERO,                SML_ERR_CONFIG_INVALID_PARAM_CAPACITY_TOO_SMALL }, /* 创建LUN失败,因为创LUN容量为0 */
    { SC_RAID_LUN_TYPE_INVALID,             SML_ERR_CONFIG_OPERATION_NOT_SUPPORT }, /* 创建LUN失败,因为物理类型(ST/NT)非法 */
    { SC_RAID_LUN_CACHE_WRITE_MODE_INVALID, SML_ERR_CONFIG_OPERATION_NOT_SUPPORT }, /* 创建LUN失败,因为cache类型非法 */
    { SC_RAID_LUN_READ_AHEAD_MODE_INVALID,  SML_ERR_CONFIG_OPERATION_NOT_SUPPORT }, /* 创建LUN失败,因为预读类型非法 */
    { SC_RAID_LUN_SU_SIZE_INVALID,          SML_ERR_CONFIG_OPERATION_NOT_SUPPORT }, /* 创建LUN失败,因为SU SIZE非法 */
    { SC_RAID_LUN_STRIPE_SIZE_INVALID,      SML_ERR_INVALID_PARAMETER }, /* 创建LUN失败,因为STRIPE SIZE非法 */
    { SC_RAID_LUN_COLD_HOT_INVALID,         SML_ERR_CONFIG_OPERATION_NOT_SUPPORT }, /* 创建LUN失败,因为冷热类型非法 */
    { SC_RAID_LUN_PF_TYPE_INVALID,          SML_ERR_CONFIG_OPERATION_NOT_SUPPORT }, /* 创建LUN失败,因为PF类型非法 */
    { SC_RAID_LUN_NAME_REPEAT,              SML_ERR_CONFIG_OPERATION_NOT_SUPPORT }, /* 创建LUN失败,因为LUN名字重复 */
    { SC_RAID_LUN_NAME_LENGTH_EXCEED,       SML_ERR_INVALID_PARAMETER }, /* 创建LUN失败,因为LUN名字太长 */
    { SC_RAID_LUN_NO_CAPACITY,              SML_ERR_CONFIG_INVALID_PARAM_CAPACITY_TOO_LARGE }, /* 创建LUN失败,因为RAID组容量不够 */
    { SC_RAID_LUN_CRATE_MODE_INVALID,       SML_ERR_CONFIG_OPERATION_NOT_SUPPORT }, /* 创建LUN失败,因为创LUN方式错误 */
    { SC_RAID_LUN_ID_USE_UP,                SML_ERR_CONFIG_ARRAY_NUM_REACHED_LIMIT }, /* 创建LUN失败,因为LUN数目超上限 */
    { SC_FEATURE_HAS_BEEN_ENABLED,          SML_ERR_CTRL_OPERATION_NOT_SUPPORT }, /* 功能已经启动/打开（如巡检、擦除等） */
    { SC_FEATURE_HAS_BEEN_DISABLED,         SML_ERR_CTRL_OPERATION_NOT_SUPPORT }, /* 功能已经停止/关闭 */
    { SC_INCORRECT_FORMAT,                  SML_ERR_INVALID_PARAMETER }, /* 格式错误 */
    { SC_RAID_CCHECK_PERIOD_INVALID,        SML_ERR_INVALID_PARAMETER }, /* 一致性校验周期为非法值 */
    { SC_RAID_CCHECK_RATE_INVALID,          SML_ERR_INVALID_PARAMETER }, /* 一致性校验速率为非法值 */
    { SC_RAID_CCHECK_REPAIRE_MODE_INVALID,  SML_ERR_INVALID_PARAMETER }, /* 一致性校验修复模式为非法值 */
    { SC_RAID_CCHECK_IS_ABNORMAL,           SML_ERR_INVALID_PARAMETER }, /* 一致性校验被打断或未执行,不支持查询一致性记录 */
    { SC_RAID_CCHECK_DELAY_INVALID,         SML_ERR_INVALID_PARAMETER }, /* 一致性校验延迟启动时间为非法值 */
    { SC_RAID_NO_FOREIGN_CONFIG,            SML_ERR_CONFIG_NO_FOREIGN_CONFIG}, /* 没有外部配置 */
    { SC_RAID_CONFIG_INCOMPLETE,            SML_ERR_CONFIG_INCOMPLETE_FOREIGN_CONFIG}, /* 不完整的外部配置 */

    { (guint32)RET_ERR,                     SML_ERR_MCTP_READ_WRITE_FAILED }, /* MCTP超时等情况下返回-1 */
};

/*
 * Description: 新建一个缓存hash表
 */
static void new_cache_hash_table(guint32 ctrl_id)
{
    guint8 index = LOW(ctrl_id);   // 取控制器下标
    if (index >= G_N_ELEMENTS(g_cache_info)) {
        debug_log(DLOG_ERROR, "%s: invalid ctrl id = 0x%x", __FUNCTION__, ctrl_id);
        return;
    }

    for (guint8 i = 0; i < CACHE_TYPE_BUTT; i++) {
        if (g_cache_info[index].hash_table[i] != NULL) {
            continue;
        }

        GHashTable* tmp = g_hash_table_new_full(NULL, NULL, NULL, g_free);
        if (tmp == NULL) {
            debug_log(DLOG_ERROR, "%s: g_hash_table_new_full failed.", __FUNCTION__);
        } else {
            g_cache_info[index].hash_table[i] = tmp;
        }
    }

    g_mutex_init(&g_cache_info[index].mutex);

    return;
}

/*
 * Description: 获取缓存hash表
 */
GHashTable *get_cache_hash_table(guint32 ctrl_id, guint8 cache_type)
{
    guint8 index = LOW(ctrl_id);   // 取控制器下标
    if (index >= G_N_ELEMENTS(g_cache_info) || cache_type >= CACHE_TYPE_BUTT) {
        debug_log(DLOG_ERROR, "%s: invalid ctrl id[0x%x] or cache_type[%d]", __FUNCTION__, ctrl_id, cache_type);
        return NULL;
    }

    return g_cache_info[index].hash_table[cache_type];
}

/*
 * Description: 获取缓存hash表互斥锁
 */
static void lock_cache_hash_table(guint32 ctrl_id)
{
    guint8 index = LOW(ctrl_id);   // 取控制器下标
    if (index >= G_N_ELEMENTS(g_cache_info)) {
        debug_log(DLOG_ERROR, "%s: invalid ctrl id[0x%x]", __FUNCTION__, ctrl_id);
        return;
    }

    g_mutex_lock(&g_cache_info[index].mutex);
    return;
}

/*
 * Description: 释放缓存hash表互斥锁
 */
static void unlock_cache_hash_table(guint32 ctrl_id)
{
    guint8 index = LOW(ctrl_id);   // 取控制器下标
    if (index >= G_N_ELEMENTS(g_cache_info)) {
        debug_log(DLOG_ERROR, "%s: invalid ctrl id[0x%x]", __FUNCTION__, ctrl_id);
        return;
    }

    g_mutex_unlock(&g_cache_info[index].mutex);
    return;
}

/*
 * Description: 插入数据到缓存hash表
 */
void insert_data_to_hash_table(guint32 ctrl_id, guint16 target_id, gpointer data, gsize data_len, guint8 cache_type)
{
    GHashTable *hash_table = get_cache_hash_table(ctrl_id, cache_type);
    if (hash_table == NULL) {
        return;
    }

    gpointer tmp = g_malloc0(data_len);
    if (tmp == NULL) {
        debug_log(DLOG_ERROR, "%s: g_malloc0 failed.", __FUNCTION__);
        return;
    }

    errno_t securec_rv = memcpy_s(tmp, data_len, data, data_len);
    if (securec_rv != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s failed, ret = %d", __FUNCTION__, securec_rv);
        g_free(tmp);
        return;
    }

    lock_cache_hash_table(ctrl_id);
    g_hash_table_insert(hash_table, UINT16_TO_POINTER(target_id), tmp);
    unlock_cache_hash_table(ctrl_id);

    return;
}

/*
 * Description: 从缓存hash表查找数据
 */
gint32 find_data_from_hash_table(guint32 ctrl_id, guint16 target_id, gpointer data, gsize data_len, guint8 cache_type)
{
    GHashTable *hash_table = get_cache_hash_table(ctrl_id, cache_type);
    if (hash_table == NULL) {
        return RET_ERR;
    }

    gpointer *tmp = g_hash_table_lookup(hash_table, UINT16_TO_POINTER(target_id));
    if (tmp == NULL) {
        return RET_ERR;
    }

    errno_t securec_rv = memcpy_s(data, data_len, tmp, data_len);
    if (securec_rv != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s failed, ret = %d", __FUNCTION__, securec_rv);
        return RET_ERR;
    }
    return RET_OK;
}

/*
 * Description: 检查vd id是否无效
 */
static gboolean check_vd_id_invalid(gpointer key, gpointer value, gpointer user_data)
{
    struct cmd_vds_id *vds_list = (struct cmd_vds_id *)user_data;

    for (guint16 i = 0; i < vds_list->num && i < VDS_ID_NODE_NUM; i++) {
        if (key == UINT16_TO_POINTER(vds_list->ids[i])) {
            return FALSE;  // 还能找到不用删
        }
    }

    return TRUE;  // 找不到了需要删
}

/*
 * Description: 从缓存hash表删除无效的vd
 */
void remove_invalid_vd_cache(guint32 ctrl_id, struct cmd_vds_id *vds_id)
{
    if (vds_id == NULL) {
        return;
    }

    GHashTable *hash_table = get_cache_hash_table(ctrl_id, CACHE_TYPE_VD);
    if (hash_table == NULL) {
        return;
    }

    lock_cache_hash_table(ctrl_id);
    (void)g_hash_table_foreach_remove(hash_table, check_vd_id_invalid, (gpointer)vds_id);
    unlock_cache_hash_table(ctrl_id);
    return;
}

/*
 * Description: 检查rg id是否无效
 */
static gboolean check_rg_id_invalid(gpointer key, gpointer value, gpointer user_data)
{
    struct cmd_rgs_id *rgs_id = (struct cmd_rgs_id *)user_data;

    for (guint16 i = 0; i < rgs_id->num && i < RGS_ID_NODE_NUM; i++) {
        if (key == UINT16_TO_POINTER(rgs_id->ids[i])) {
            return FALSE;  // 还能找到不用删
        }
    }

    return TRUE;  // 找不到了需要删
}

/*
 * Description: 从缓存hash表删除无效的rg
 */
void remove_invalid_rg_cache(guint32 ctrl_id, struct cmd_rgs_id *rgs_id)
{
    if (rgs_id == NULL) {
        return;
    }

    GHashTable *hash_table = get_cache_hash_table(ctrl_id, CACHE_TYPE_RG);
    if (hash_table == NULL) {
        return;
    }

    lock_cache_hash_table(ctrl_id);
    (void)g_hash_table_foreach_remove(hash_table, check_rg_id_invalid, (gpointer)rgs_id);
    unlock_cache_hash_table(ctrl_id);
    return;
}

/*
 * Description: 销毁一个缓存hash表
 */
static void destroy_cache_hash_table(guint32 ctrl_id)
{
    guint8 index = LOW(ctrl_id);   // 取控制器下标
    if (index >= G_N_ELEMENTS(g_cache_info)) {
        debug_log(DLOG_ERROR, "%s: invalid ctrl id = 0x%x", __FUNCTION__, ctrl_id);
        return;
    }

    for (guint8 i = 0; i < CACHE_TYPE_BUTT; i++) {
        if (g_cache_info[index].hash_table[i] == NULL) {
            continue;
        }

        g_hash_table_destroy(g_cache_info[index].hash_table[i]);
        g_cache_info[index].hash_table[i] = NULL;
    }

    g_mutex_clear(&g_cache_info[index].mutex);

    return;
}

/*
 * Description: 将hash表中对应vd信息的可读取次数清零（意图尽快从卡侧重新获取最新信息）
 */
void clear_vd_cache_read_count(guint32 ctrl_id, guint16 target_id)
{
    CACHED_VD_INFO cached_vd_info;
    (void)memset_s(&cached_vd_info, sizeof(cached_vd_info), 0, sizeof(cached_vd_info));

    if (find_data_from_hash_table(ctrl_id, target_id, (gpointer)&cached_vd_info, sizeof(cached_vd_info),
        CACHE_TYPE_VD) == RET_OK) {
        cached_vd_info.read_count = 0;
        insert_data_to_hash_table(ctrl_id, target_id, (gpointer)&cached_vd_info, sizeof(cached_vd_info),
            CACHE_TYPE_VD);
    }
}

/*
 * Description: 获取虚拟盘ID列表
 */
gint32 get_vd_list(guint8 ctrl_id, struct cmd_vds_id *vd_list)
{
    struct lib_cmd_param lib_param;
    (void)memset_s(&lib_param, sizeof(lib_param), 0, sizeof(lib_param));
    lib_param.opcode = ADM_RAID_READ;
    lib_param.subopcode = ADM_CMD_SHOW_VDS_ID;
    lib_param.card_id = ctrl_id;
    lib_param.channel = PCIE_PHYSICAL_FUCTION0;
    lib_param.data = vd_list;
    lib_param.data_len = (guint16)sizeof(struct cmd_vds_id);
    return process_histore_cmd(&lib_param);
}

/*
 * Description: 将hash表中全部vd信息的可读取次数清零（意图尽快从卡侧重新获取最新信息）
 */
void clear_vd_cache_read_count_all(guint32 ctrl_id)
{
    struct cmd_vds_id vd_list;
    (void)memset_s(&vd_list, sizeof(vd_list), 0, sizeof(vd_list));
    gint32 ret = get_vd_list(ctrl_id, &vd_list);
    if (ret != SML_SUCCESS) {
        return;
    }

    for (guint16 i = 0; i < vd_list.num && i < VDS_ID_NODE_NUM; i++) {
        clear_vd_cache_read_count(ctrl_id, vd_list.ids[i]);
    }

    return;
}

/*
 * Description: 获取虚拟盘信息
 */
gint32 get_vd_info(guint32 ctrl_id, guint16 target_id, struct cmd_vd_info *vd_info)
{
    struct lib_cmd_param lib_param;
    (void)memset_s(&lib_param, sizeof(lib_param), 0, sizeof(lib_param));
    lib_param.opcode = ADM_RAID_READ;
    lib_param.subopcode = ADM_CMD_SHOW_VD_INFO;
    lib_param.card_id = ctrl_id;
    lib_param.channel = PCIE_PHYSICAL_FUCTION0;
    lib_param.data = vd_info;
    lib_param.data_len = (guint16)sizeof(struct cmd_vd_info);
    lib_param.param_len = (guint16)sizeof(struct cmd_vd_id);

    struct cmd_vd_id vd_id;
    (void)memset_s(&vd_id, sizeof(vd_id), 0, sizeof(vd_id));
    vd_id.vd_id = target_id;

    errno_t securec_rv = memcpy_s(lib_param.cmd_param, sizeof(lib_param.cmd_param), &vd_id,
                                  sizeof(vd_id));
    if (securec_rv != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s failed, ret = %d", __FUNCTION__, securec_rv);
    }
    return process_histore_cmd(&lib_param);
}

/*
 * Description: 获取RAID组信息
 */
gint32 get_rg_info(guint32 ctrl_id, guint16 target_id, struct cmd_rg_info *rg_info)
{
    struct lib_cmd_param lib_param;
    (void)memset_s(&lib_param, sizeof(lib_param), 0, sizeof(lib_param));
    lib_param.opcode = ADM_RAID_READ;
    lib_param.subopcode = ADM_CMD_SHOW_RG_INFO;
    lib_param.card_id = ctrl_id;
    lib_param.channel = PCIE_PHYSICAL_FUCTION0;
    lib_param.data = rg_info;
    lib_param.data_len = (guint16)sizeof(struct cmd_rg_info);
    lib_param.param_len = (guint16)sizeof(struct cmd_rg_id);

    struct cmd_rg_id rg_id;
    (void)memset_s(&rg_id, sizeof(rg_id), 0, sizeof(rg_id));
    rg_id.rg_id = target_id;

    errno_t securec_rv = memcpy_s(lib_param.cmd_param, sizeof(lib_param.cmd_param), &rg_id, sizeof(rg_id));
    if (securec_rv != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s failed, ret = %d", __FUNCTION__, securec_rv);
    }
    return process_histore_cmd(&lib_param);
}

/*
 * Description: 查询全局直通JBOD开关
 */
guint32 get_ctrl_jbod_enabled(guint32 ctrl_id)
{
    struct lib_cmd_param lib_param;
    (void)memset_s(&lib_param, sizeof(lib_param), 0, sizeof(lib_param));
    lib_param.opcode = ADM_RAID_READ_FROM_CQE;
    lib_param.subopcode = ADM_CMD_SHOW_PASSTHRU_TYPE;
    lib_param.card_id = ctrl_id;
    lib_param.channel = PCIE_PHYSICAL_FUCTION0;
    lib_param.param_len = 0;
    gint32 ret = process_histore_cmd(&lib_param);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "get_ctrl_jbod_enabled failed, ret = %d", ret);
        return 0; // 默认关闭
    }

    return lib_param.result0;
}

/*
 * Description: 发送命令给histore lib获取PD详细信息
 * History: 2021-08-14  新生成函数
 */
gint32 get_pd_basic_info(guint32 ctrl_id, guint16 device_id, struct cmd_show_disk *pd_info)
{
    struct lib_cmd_param lib_param;
    struct multi_disk_location disk_location;
    (void)memset_s(&lib_param, sizeof(lib_param), 0, sizeof(lib_param));
    (void)memset_s(&disk_location, sizeof(disk_location), 0, sizeof(disk_location));
    disk_location.did = device_id;
    disk_location.flag = DISK_LOC_DID; // flag为1 ，表示根据did 进行定位
    lib_param.opcode = ADM_RAID_READ;
    lib_param.subopcode = ADM_CMD_SHOW_DISK;
    lib_param.card_id = ctrl_id;
    lib_param.channel = PCIE_PHYSICAL_FUCTION0;
    lib_param.data_len = (guint16)sizeof(struct cmd_show_disk);
    lib_param.data = pd_info;
    lib_param.param_len = (guint16)sizeof(struct multi_disk_location);
    errno_t securec_rv = memcpy_s(lib_param.cmd_param, sizeof(lib_param.cmd_param), &disk_location,
                                  sizeof(disk_location));
    if (securec_rv != EOK) {
        debug_log(DLOG_ERROR, "%s: memcpy_s failed, ret = %d", __FUNCTION__, securec_rv);
    }
    return process_histore_cmd(&lib_param);
}

/*
 * Description: 动态加载libhistore、完成回调函数注册、完成初始化
 */
gint32 libhistore_init(struct store_lib_conf *conf)
{
    static guint8 init_flag = FALSE;

    // 多卡只做一次初始化动作
    if (init_flag == TRUE) {
        return SML_SUCCESS;
    }
    if (g_lib_handle == NULL) {
        return SML_ERR_CTRL_HISTORE_LOAD_FAILED;
    }

    /* 1、找到libhistore处理命令的函数地址并赋给全局指针 */
    ProcessHistoreCmdFunc pfn_process_histore_cmd =
        (ProcessHistoreCmdFunc)dlsym(g_lib_handle, "store_send_cmd");
    if (pfn_process_histore_cmd == NULL) {
        debug_log(DLOG_ERROR, "%s: no ProcessHistoreCmdFunc.", __FUNCTION__);
        dlclose(g_lib_handle);
        g_lib_handle = NULL;
        return SML_ERR_CTRL_HISTORE_GET_FUNC_ADDR_FAILED;
    }
    g_pfn_process_command = pfn_process_histore_cmd;

	/* 2、初始化libhistore */
    InitLibhistore pfn_init_libhistore = (InitLibhistore)dlsym(g_lib_handle, "store_lib_init");
    if (pfn_init_libhistore == NULL) {
        debug_log(DLOG_ERROR, "%s: no store_lib_init.", __FUNCTION__);
        g_pfn_process_command = NULL;
        dlclose(g_lib_handle);
        g_lib_handle = NULL;
        return SML_ERR_CTRL_INIT_FAILED;
    }

    gint32 ret = pfn_init_libhistore(conf);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "%s: init libhistore failed.", __FUNCTION__);
        return SML_ERR_CTRL_INIT_FAILED;
    }
    init_flag = TRUE;
    return SML_SUCCESS;
}

/*
 * Description: 去初始化libhistore
 */
gint32 libhistore_exit(void)
{
    if (g_lib_handle == NULL) {
        return SML_SUCCESS;
    }

    ExitLibhistore pfn_exit_libhistore = (ExitLibhistore)dlsym(g_lib_handle, "store_lib_exit");
    if (pfn_exit_libhistore == NULL) {
        debug_log(DLOG_ERROR, "%s: exit libhistore failed.", __FUNCTION__);
        return SML_ERR_CTRL_HISTORE_GET_FUNC_ADDR_FAILED;
    }
    pfn_exit_libhistore();

    dlclose(g_lib_handle);
    g_lib_handle = NULL;
    g_pfn_process_command = NULL;
    return SML_SUCCESS;
}

/*
 * Description: 发送SCSI命令
 * History: 2022-10-08  新生成函数
*/
gint32 send_scsi_passthru_cmd(guint32 ctrl_id, struct cmd_scsi_passthrough *scsi_passthru_cmd,
    gpointer data, guint32 data_length)
{
    if (scsi_passthru_cmd == NULL || data == NULL) {
        return SML_ERR_NULL_DATA;
    }

    struct lib_cmd_param lib_param;
    (void)memset_s(&lib_param, sizeof(lib_param), 0, sizeof(lib_param));

    lib_param.opcode = ADM_RAID_READ;
    lib_param.subopcode = ADM_CMD_SCSI_PASSTHROUGH;
    lib_param.card_id = ctrl_id;
    lib_param.channel = PCIE_PHYSICAL_FUCTION0;
    lib_param.param_len = (guint16)sizeof(struct cmd_scsi_passthrough);
    lib_param.p_param = scsi_passthru_cmd;

    lib_param.data = data;
    lib_param.data_len = data_length;

    return process_histore_cmd(&lib_param);
}

/*
 * Description: 移除控制器
 */
gint32 histore_remove_ctrl(guint32 ctrl_id)
{
    /* 销毁缓存hash表 */
    destroy_cache_hash_table(ctrl_id);
    return SML_SUCCESS;
}

/*
 * Description: 向lib中添加新卡_add_adapter
 */
gint32 histore_add_ctrl(guint32 ctrl_id)
{
    struct adapter_descriptor adapter;

    if (g_lib_handle == NULL) {
        g_lib_handle = dlopen(HISTORE_LIB, RTLD_LAZY);
        if (g_lib_handle == NULL) {
            debug_log(DLOG_ERROR, "%s: dlopen %s failed, %s.", __FUNCTION__, HISTORE_LIB, dlerror());
            return SML_ERR_CTRL_HISTORE_LOAD_FAILED;
        }
    }
    memset_s(&adapter, sizeof(adapter), 0, sizeof(adapter));
    adapter.adapter_idx = ctrl_id;
    adapter.pf_num = 1;  // physical fuction num 1
    adapter.channel = 1; // channel 通过 PCIE
    HistoreAddAdapter pfn_add_adapter = (HistoreAddAdapter)dlsym(g_lib_handle, "store_add_adapter");
    if (pfn_add_adapter == NULL) {
        debug_log(DLOG_ERROR, "%s: add adapter failed.", __FUNCTION__);
        dlclose(g_lib_handle);
        g_lib_handle = NULL;
        return SML_ERR_CTRL_HISTORE_GET_FUNC_ADDR_FAILED;
    }
    pfn_add_adapter(&adapter);
    /* 为每张卡新建一个hash表，用来保存vd、rg、sg信息 */
    new_cache_hash_table(ctrl_id);
    return SML_SUCCESS;
}

gint32 histore_get_ctrl_parsed_log(const char *bin_file_path, const char *txt_file_path)
{
    debug_log(DLOG_NOTICE, "start histore_get_ctrl_parsed_log");
    if (g_lib_handle == NULL) {
        g_lib_handle = dlopen(HISTORE_LIB, RTLD_LAZY);
        if (g_lib_handle == NULL) {
            debug_log(DLOG_ERROR, "%s: dlopen %s failed, %s.", __FUNCTION__, HISTORE_LIB, dlerror());
            return SML_ERR_CTRL_HISTORE_LOAD_FAILED;
        }
    }
    HistoreGetParsedLog pfn_parse_log = (HistoreGetParsedLog)dlsym(g_lib_handle, "ParseBinLog");
    if (pfn_parse_log == NULL) {
        debug_log(DLOG_ERROR, "%s: unable to get Entry Point function address-%s.", __FUNCTION__, "ParseBinLog");
        return SML_ERR_CTRL_HISTORE_GET_FUNC_ADDR_FAILED;
    }
    debug_log(DLOG_NOTICE, "start pfn_parse_log");
    int ret = pfn_parse_log(bin_file_path, txt_file_path);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "[%s]: ParseBinLog fail, ret:%d", __FUNCTION__, ret);
    }
    return ret;
}

/*
 * Description: 转成sml层的错误码
 */
static gint32 convert_error_code(guint32 ret)
{
    if (ret == SC_SUCCESS) {
        return SML_SUCCESS;
    }

    for (guint16 i = 0; i < G_N_ELEMENTS(g_error_code_map); i++) {
        if (ret == g_error_code_map[i].hs_error_code) {
            return (gint32)g_error_code_map[i].sml_error_code;
        }
    }

    return (gint32)ret;
}

/*
 * Description: libhistore命令处理函数入口
 */
gint32 process_histore_cmd(struct lib_cmd_param *param)
{
    if (g_pfn_process_command == NULL) {
        return SML_ERR_CTRL_HISTORE_GET_FUNC_ADDR_FAILED;
    }

    guint32 ret = g_pfn_process_command(param);
    if (ret != SC_SUCCESS) {
        debug_log(DLOG_ERROR, "%s: process_histore_cmd return error 0x%x", __FUNCTION__, ret);
    }
    return convert_error_code(ret);
}

/*
 * Description: 发送SCSI LogSense命令 获取LogSense头信息
 * History: 2022年10月23日  新生成函数
*/
static gint32 get_scsi_log_sense_info(guint32 ctrl_id, guint16 device_id, guint8 page_code, guint8 sub_page_code,
    guint16 page_length, guint8 *data, guint32 *scsi_status)
{
    struct cmd_scsi_passthrough scsi_passthru_cmd;
    (void)memset_s(&scsi_passthru_cmd, sizeof(scsi_passthru_cmd), 0, sizeof(scsi_passthru_cmd));

    struct multi_disk_location disk_location;
    (void)memset_s(&disk_location, sizeof(disk_location), 0, sizeof(disk_location));
    disk_location.did = device_id;
    disk_location.flag = DISK_LOC_DID;
    (void)memcpy_s(&scsi_passthru_cmd.loc, sizeof(scsi_passthru_cmd.loc), &disk_location, sizeof(disk_location));

    scsi_passthru_cmd.loc = disk_location;
    scsi_passthru_cmd.lun = 0;
    scsi_passthru_cmd.cdb_len = SCSI_CDB_LENGTH10;
    scsi_passthru_cmd.cdb[0] = SCSI_CMD_LOG_SENSE;
    scsi_passthru_cmd.cdb[1] = 0x00;
    scsi_passthru_cmd.cdb[2] = 0x40 | (page_code & 0x3F);  // 0x40: describe the cumulative value of the page control
    scsi_passthru_cmd.cdb[3] = sub_page_code;
    scsi_passthru_cmd.cdb[7] = (page_length >> 8) & 0xff;  // 8：page_length右移8位
    scsi_passthru_cmd.cdb[8] = page_length & 0xff;

    gint32 ret = send_scsi_passthru_cmd(ctrl_id, &scsi_passthru_cmd, data, page_length);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_ERROR, "Get log page length failed, DeviceId = %u, CtrlId = %u, return 0x%04X", device_id,
            SML_CTRL_ID_VALID_BIT(ctrl_id), ret);
        if (scsi_status != NULL) {
            *scsi_status = ret;
        }

        return ret;
    }

    if ((page_code != SCSI_LOG_PAGE_SUPPORTED_LOG_PAGES) && ((data[0] & 0x3F) != page_code)) {
        debug_log(DLOG_ERROR, "Responsed with incorrect page code 0x%02x, should be 0x%02x", data[0], page_code);
        return SML_ERR_PD_SCSI_RESP_INCORRECT;
    }
    
    return SML_SUCCESS;
}

/*
 * Description: 获取 LogSense数据长度
 * History: 2022年10月18日 新生成函数
*/
static gint32 get_scsi_log_sense_data_len(page_code_info_req *device_info, guint16 *page_len, guint32 buf_size,
    guint32 *scsi_status)
{
    guint8 data[SCSI_LOG_PAGE_HEADER_SIZE] = { 0 };

    gint32 ret = get_scsi_log_sense_info(device_info->ctrl_id, device_info->device_id, device_info->page_code,
        device_info->sub_page_code, SCSI_LOG_PAGE_HEADER_SIZE, data, scsi_status);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    // (data[2] << 8) + data[3]：scsi协议 page length值
    *page_len = (data[2] << 8) + data[3];
    if (*page_len == 0) {
        debug_log(DLOG_ERROR, "Responsed log page length is ZERO.");
        return SML_ERR_NULL_DATA;
    }

    *page_len += SCSI_LOG_PAGE_HEADER_SIZE;
    if (buf_size > SCSI_LOG_PAGE_HEADER_SIZE) {
        *page_len = *page_len > buf_size ? buf_size : *page_len;
    }

    return SML_SUCCESS;
}

/*
 * Description: 获取 LogSense数据内容
 * History: 2022年10月18日  新生成函数
*/
static gint32 get_scsi_log_sense_body(page_code_info_req *device_info, guint16 page_len,
    guint8 *data, guint32 *scsi_status)
{
    gint32 ret = get_scsi_log_sense_info(device_info->ctrl_id, device_info->device_id, device_info->page_code,
        device_info->sub_page_code, page_len, data, scsi_status);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    if ((device_info->page_code != SCSI_LOG_PAGE_SUPPORTED_LOG_PAGES) &&
        ((data[0] & 0x3F) != device_info->page_code)) {
        debug_log(DLOG_ERROR, "Responsed with incorrect page code 0x%02x, should be 0x%02x.",
            data[0], device_info->page_code);
        return SML_ERR_PD_SCSI_RESP_INCORRECT;
    }

    return SML_SUCCESS;
}

/*
 * Description: 发送SCSI LogSense命令
 * History: 2022年10月18日  新生成函数
*/
gint32 send_scsi_log_sense_command(page_code_info_req *req, guint8 **pbuf, guint32 *buf_size, guint32 *scsi_status)
{
    if (pbuf == NULL || buf_size == NULL) {
        return SML_ERR_NULL_DATA;
    }

    // 获取LogSense 数据长度
    guint16 page_len = 0;
    gint32 ret = get_scsi_log_sense_data_len(req, &page_len, *buf_size, scsi_status);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    // 获取LogSense 数据内容
    if (page_len == 0) {
        return SML_ERR_DATA_INVALID;
    }

    guint8 *data = (guint8 *)g_malloc0(page_len);
    if (data == NULL) {
        debug_log(DLOG_ERROR, "%s, g_malloc0 failed.", __FUNCTION__);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    ret = get_scsi_log_sense_body(req, page_len, data, scsi_status);
    if (ret != SML_SUCCESS) {
        g_free(data);
        return ret;
    }

    if ((*pbuf = (guint8 *)g_malloc0(page_len)) == NULL) {
        debug_log(DLOG_ERROR, "%s, g_malloc0 failed.", __FUNCTION__);
        g_free(data);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    if (memcpy_s(*pbuf, page_len, data, page_len) != EOK) {
        debug_log(DLOG_ERROR, "%s, memcpy_s failed.", __FUNCTION__);
        g_free(data);
        g_free(*pbuf);
        *pbuf = NULL;
        return SML_ERR_SEC_FUNC_FAILED;
    }

    *buf_size = page_len;
    g_free(data);

    return SML_SUCCESS;
}

/*
 * Description: 获取当前设备是否支持指定的LogPage
 * History: 2022年10月17日 新生成函数
*/
gint32 get_scsi_device_support_log_pages(guint32 ctrl_id, guint16 device_id, guint8 page_code, guint8 *lp_support)
{
    guint32 idx = 0;
    guint8 *buf = NULL;
    guint32 buf_size = 0;

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

    page_code_info_req req = { 0 };
    req.ctrl_id = ctrl_id;
    req.device_id = device_id;
    req.page_code = SCSI_LOG_PAGE_SUPPORTED_LOG_PAGES;
    req.sub_page_code = 0;

    gint32 retval = send_scsi_log_sense_command(&req, &buf, &buf_size, NULL);
    if (retval != SML_SUCCESS) {
        return retval;
    }

    if (buf == NULL) {
        return SML_ERR_DATA_LEN_INVALID;
    }

    // buf[3]: parameter length
    if (buf_size < (buf[3] + SCSI_LOG_PAGE_HEADER_SIZE)) {
        g_free(buf);
        return SML_ERR_DATA_LEN_INVALID;
    }
    *lp_support = FALSE;

    // buf[3]: parameter length
    for (idx = SCSI_LOG_PAGE_HEADER_SIZE; idx < buf[3] + SCSI_LOG_PAGE_HEADER_SIZE; idx++) {
        if (buf[idx] == page_code) {
            *lp_support = TRUE;
            break;
        }
    }

    g_free(buf);
    return SML_SUCCESS;
}

/*
 * Description: 删除字符串前后的空格
 * History: 2026年3月19日   新生成函数
*/
void remove_string_space(gchar *src, guint32 src_length)
{
    errno_t safe_fun_ret = EOK;
    gchar *tmp_buf = NULL;
    guint32 start = 0;
    guint32 end = 0;

    if (src == NULL || src_length == 0) {
        return;
    }

    for (start = 0; start < src_length; start++) {
        if (src[start] == ' ') {
            continue;
        } else {
            break;
        }
    }

    if (start == src_length) {
        return;
    }

    for (end = src_length - 1; end > 0; end--) {
        if (src[end] == ' ' || src[end] == '\0') {
            continue;
        } else {
            break;
        }
    }

    if (end == 0) {
        return;
    }

    tmp_buf = (gchar *)g_malloc(src_length);
    if (tmp_buf == NULL) {
        return;
    }

    (void)memset_s(tmp_buf, src_length, 0, src_length);

    safe_fun_ret = strncpy_s(tmp_buf, src_length, src + start, end - start + 1);
    if (safe_fun_ret != EOK) {
        debug_log(DLOG_ERROR, "%s: strncpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
    }
    safe_fun_ret = strncpy_s(src, src_length, tmp_buf, src_length - 1);
    if (safe_fun_ret != EOK) {
        debug_log(DLOG_ERROR, "%s: strncpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
    }

    g_free(tmp_buf);
    return;
}

void swapBytes(const guint8 *src, guint8 *dest, guint32 len)
{
    errno_t safe_fun_ret = EOK;
    guint32 start = 0;
    guint32 end = 0;
    guint32 dest_size = 1;

    if (len == 0) {
        debug_log(DLOG_ERROR, "%s failed:input param error, len is 0.", __FUNCTION__);
        return;
    }
    if (src == NULL || dest == NULL) {
        return;
    }

    (void)memset_s(dest, len, 0, len);

    for (start = 0, end = len - 1; start < end; start++, end--) {
        safe_fun_ret = memcpy_s(dest + start, dest_size, src + end, 1);
        if (safe_fun_ret != EOK) {
            debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
            return;
        }
        safe_fun_ret = memcpy_s(dest + end, dest_size, src + start, 1);
        if (safe_fun_ret != EOK) {
            debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
            return;
        }
    }

    return;
}