/* Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * 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 "l_sml_adapter.h"
#include "pd_log_process.h"

namespace sml {
static void *g_sml_base = NULL;
static SML_ADAPTER_S *g_sml_adapter = NULL;
static PD_LOG_PARSE *g_pd_log_parse = NULL;

guint8 VENDER_OTHER = 0;
guint8 VENDER_HISOTRE = 1;
guint8 VENDER_INVALID = 255;
guint8 PMC_2100_8I_SMART_HBA = 65;
guint8 HI1880_SP186_M_16i = 96;
guint8 HI1880_SP186_M_8i = 113;
const char* SML_BASE_LIB_PATH = "/usr/lib64/libsml_base.so";
const char* SML_CUSTOM_BASE_LIB_PATH = "/usr/lib64/libsml_custom_base.so";

static const char *get_sml_base_lib_path(guint8 type_id)
{
    if (type_id <= PMC_2100_8I_SMART_HBA) {
        return SML_CUSTOM_BASE_LIB_PATH;
    }

    if (type_id >= HI1880_SP186_M_16i and type_id <= HI1880_SP186_M_8i) {
        return SML_BASE_LIB_PATH;
    }
    return NULL;
}

static void register_sml_adapter_fun(const char *sml_base_lib_path, SML_ADAPTER_FUNC_S *sml_adapter_fun_table,
    guint8 num)
{
    if (g_sml_base == NULL) {
        g_sml_base = dlopen(sml_base_lib_path, RTLD_LAZY);
        if (g_sml_base == NULL) {
            debug_log(DLOG_ERROR, "dlopen %s failed %s", sml_base_lib_path, dlerror());
            return;
        }
    }

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

    return;

ERROR:
    dlclose(g_sml_base);
    g_sml_base = NULL;
    for (i = 0; i < num; i++) {
        *(sml_adapter_fun_table[i].pfunc) = NULL;
    }
    g_free(g_sml_adapter);
    g_sml_adapter = NULL;
    return;
}

static void register_pd_log_parse()
{
    if (g_sml_base == NULL) {
        return;
    }
    if (g_pd_log_parse != NULL) {
        debug_log(DLOG_ERROR, "%s: g_pd_log_parse is already generate", __FUNCTION__);
        return;
    }

    if (g_pd_log_parse == NULL) {
        g_pd_log_parse = (PD_LOG_PARSE *)g_malloc0(sizeof(PD_LOG_PARSE));
    }

    PD_LOG_PARSE_FUNC_S pd_log_parse_fun_table[] = {
        { (void **)&g_pd_log_parse->sml_get_pd_log, "sml_get_pd_log"},
        { (void **)&g_pd_log_parse->sml_get_ata_smart_attr_name, "sml_get_ata_smart_attr_name"},
        { (void **)&g_pd_log_parse->sml_parse_ata_smart_attr_raw_value, "sml_parse_ata_smart_attr_raw_value"}
    };

    guint8 i;
    for (i = 0; i < G_N_ELEMENTS(pd_log_parse_fun_table); i++) {
        *(pd_log_parse_fun_table[i].pfunc) = dlsym(g_sml_base, pd_log_parse_fun_table[i].func_name);
        if (*(pd_log_parse_fun_table[i].pfunc) == NULL) {
            debug_log(DLOG_ERROR, "Unable to get Entry Point function address-%s", pd_log_parse_fun_table[i].func_name);
            goto ERROR;
        }
    }
    save_pd_log_parse_fun_table(&g_pd_log_parse);
    return;
ERROR:
    for (i = 0; i < G_N_ELEMENTS(pd_log_parse_fun_table); i++) {
        *(pd_log_parse_fun_table[i].pfunc) = NULL;
    }
    g_free(g_pd_log_parse);
    g_pd_log_parse = NULL;
    return;
}

static void register_sml_adapter_fun_table(const char *sml_base_lib_path)
{
    if (g_sml_adapter != NULL) {
        debug_log(DLOG_ERROR, "%s: g_sml_adapter is already generate", __FUNCTION__);
        return;
    }

    if (g_sml_adapter == NULL) {
        g_sml_adapter = (SML_ADAPTER_S *)g_malloc0(sizeof(SML_ADAPTER_S));
    }

    SML_ADAPTER_FUNC_S sml_adapter_fun_table[] = {
        { (void **)&g_sml_adapter->sml_register_controller, "sml_register_controller"},
        { (void **)&g_sml_adapter->smlib_get_array_info, "smlib_get_array_info"},
        { (void **)&g_sml_adapter->sml_unregister_controller, "sml_unregister_controller"},
        { (void **)&g_sml_adapter->smlib_get_ctrl_info, "smlib_get_ctrl_info"},
        { (void **)&g_sml_adapter->sml_get_ctrl_pd_list, "sml_get_ctrl_pd_list"},
        { (void **)&g_sml_adapter->sml_get_ctrl_ld_list, "sml_get_ctrl_ld_list"},
        { (void **)&g_sml_adapter->sml_get_ctrl_array_list, "sml_get_ctrl_array_list"},
        { (void **)&g_sml_adapter->sml_get_ctrl_boot_devices, "sml_get_ctrl_boot_devices"},
        { (void **)&g_sml_adapter->sml_get_ctrl_sas_addr, "sml_get_ctrl_sas_addr"},
        { (void **)&g_sml_adapter->sml_ctrl_operation, "sml_ctrl_operation"},
        { (void **)&g_sml_adapter->sml_get_ctrl_health_status, "sml_get_ctrl_health_status"},
        { (void **)&g_sml_adapter->sml_dump_ctrl_single_log, "sml_dump_ctrl_single_log"},
        { (void **)&g_sml_adapter->smlib_get_ctrl_bbu_status, "smlib_get_ctrl_bbu_status"},
        { (void **)&g_sml_adapter->smlib_get_ld_info, "smlib_get_ld_info"},
        { (void **)&g_sml_adapter->smlib_exec_ld_operation, "smlib_exec_ld_operation"},
        { (void **)&g_sml_adapter->sml_set_ld_boot_priority, "sml_set_ld_boot_priority"},
        { (void **)&g_sml_adapter->sml_set_ld_delete, "sml_set_ld_delete"},
        { (void **)&g_sml_adapter->sml_create_ld_on_existed_array, "sml_create_ld_on_existed_array"},
        { (void **)&g_sml_adapter->sml_create_ld_on_new_array, "sml_create_ld_on_new_array"},
        { (void **)&g_sml_adapter->sml_get_ld_sscd_caching_enable, "sml_get_ld_sscd_caching_enable"},
        { (void **)&g_sml_adapter->sml_get_sscd_associated_ld_list, "sml_get_sscd_associated_ld_list"},
        { (void **)&g_sml_adapter->sml_get_ld_associated_sscd_list, "sml_get_ld_associated_sscd_list"},
        { (void **)&g_sml_adapter->sml_set_ld_cachecade_association, "sml_set_ld_cachecade_association"},
        { (void **)&g_sml_adapter->sml_create_ld_as_cachecade, "sml_create_ld_as_cachecade"},
        { (void **)&g_sml_adapter->smlib_get_pd_info, "smlib_get_pd_info"},
        { (void **)&g_sml_adapter->smlib_get_pd_sas_smart_info, "smlib_get_pd_sas_smart_info"},
        { (void **)&g_sml_adapter->sml_pd_operation, "sml_pd_operation"},
        { (void **)&g_sml_adapter->sml_diagnose_encl_comm_error, "sml_diagnose_encl_comm_error"},
        { (void **)&g_sml_adapter->sml_diagnose_pd_sense_error, "sml_diagnose_pd_sense_error"},
        { (void **)&g_sml_adapter->sml_get_smart_data_str, "sml_get_smart_data_str"},
        { (void **)&g_sml_adapter->smlib_diagnose_link_phy_error, "smlib_diagnose_link_phy_error"},
        { (void **)&g_sml_adapter->sml_get_ctrl_exp_sas_phy_err_count, "sml_get_ctrl_exp_sas_phy_err_count"},
        { (void **)&g_sml_adapter->smlib_get_ctrl_phy_err_count, "smlib_get_ctrl_phy_err_count"},
        { (void **)&g_sml_adapter->sml_clear_all_controller_info, "sml_clear_all_controller_info"},
        { (void **)&g_sml_adapter->sml_get_ctrl_init_state, "sml_get_ctrl_init_state"}
    };

    register_sml_adapter_fun(sml_base_lib_path, sml_adapter_fun_table, G_N_ELEMENTS(sml_adapter_fun_table));
    return;
}

void l_sml_adapter::register_sml_adapter_function(SML_CTRL_OOB_INFO_S *ctrl)
{
    if (ctrl == NULL) {
        debug_log(DLOG_ERROR, "%s: ctrl is NULL", __FUNCTION__);
        return;
    }

    const char *sml_base_lib_path = get_sml_base_lib_path(ctrl->i_controller_typeid);
    if (sml_base_lib_path == NULL) {
        debug_log(DLOG_ERROR, "%s: sml base lib path is invalid", __FUNCTION__);
        return;
    }
    debug_log(DLOG_NOTICE, "%s: controller type id is %u", __FUNCTION__, ctrl->i_controller_typeid);
    register_sml_adapter_fun_table(sml_base_lib_path);
    register_pd_log_parse();
    return;
}

gint32 l_sml_adapter::sml_adapter_register_controller(SML_CTRL_OOB_INFO_S *ctrl)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_register_controller != NULL) {
        return g_sml_adapter->sml_register_controller(ctrl);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_get_array_info(guint8 ctrl_index, guint16 array_ref, SML_ARRAY_INFO_S *array)
{
    if (g_sml_adapter != NULL && g_sml_adapter->smlib_get_array_info != NULL) {
        return g_sml_adapter->smlib_get_array_info(ctrl_index, array_ref, array);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_unregister_controller(SML_CTRL_OOB_INFO_S *ctrl)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_unregister_controller != NULL) {
        return g_sml_adapter->sml_unregister_controller(ctrl);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_get_ctrl_info(guint8 ctrl_index, SML_CTRL_BASIC_INFO_S *ctrl)
{
    if (g_sml_adapter != NULL && g_sml_adapter->smlib_get_ctrl_info != NULL) {
        return g_sml_adapter->smlib_get_ctrl_info(ctrl_index, ctrl);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_get_ctrl_pd_list(SML_CTRL_PD_LIST_S *ctrl)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_get_ctrl_pd_list != NULL) {
        return g_sml_adapter->sml_get_ctrl_pd_list(ctrl);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_get_ctrl_ld_list(SML_CTRL_LD_LIST_S *ctrl)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_get_ctrl_ld_list != NULL) {
        return g_sml_adapter->sml_get_ctrl_ld_list(ctrl);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_get_ctrl_array_list(SML_CTRL_ARRAY_LIST_S *ctrl)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_get_ctrl_array_list != NULL) {
        return g_sml_adapter->sml_get_ctrl_array_list(ctrl);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_get_ctrl_boot_devices(SML_CTRL_BOOTABLE_DEVICES_S *boot_devices)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_get_ctrl_boot_devices != NULL) {
        return g_sml_adapter->sml_get_ctrl_boot_devices(boot_devices);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_get_ctrl_sas_addr(SML_CTRL_SAS_ADDR_S *ctrl)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_get_ctrl_sas_addr != NULL) {
        return g_sml_adapter->sml_get_ctrl_sas_addr(ctrl);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_ctrl_operation(SML_CTRL_OPERTATION_S *ctrl)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_ctrl_operation != NULL) {
        return g_sml_adapter->sml_ctrl_operation(ctrl);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_get_ctrl_health_status(SML_CTRL_HEALTH_STATUS_S *ctrl)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_get_ctrl_health_status != NULL) {
        return g_sml_adapter->sml_get_ctrl_health_status(ctrl);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_dump_ctrl_single_log(guint8 ctrl_id, const gchar *src_dir,
    guint8 log_type, const gchar *log_name)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_dump_ctrl_single_log != NULL) {
        return g_sml_adapter->sml_dump_ctrl_single_log(ctrl_id, src_dir, log_type, log_name);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_get_ctrl_bbu_status(guint8 ctrl_index, SML_BBU_STATUS_S *ctrl)
{
    if (g_sml_adapter != NULL && g_sml_adapter->smlib_get_ctrl_bbu_status != NULL) {
        return g_sml_adapter->smlib_get_ctrl_bbu_status(ctrl_index, ctrl);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_get_ld_info(guint8 ctrl_index, guint16 ld_target_id, SML_LD_BASIC_INFO_S *ld)
{
    if (g_sml_adapter != NULL && g_sml_adapter->smlib_get_ld_info != NULL) {
        return g_sml_adapter->smlib_get_ld_info(ctrl_index, ld_target_id, ld);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_exec_ld_operation(guint8 ctrl_index, guint16 ld_target_id,
    guint8 operation, gpointer param, guint32 param_length)
{
    if (g_sml_adapter != NULL && g_sml_adapter->smlib_exec_ld_operation != NULL) {
        return g_sml_adapter->smlib_exec_ld_operation(ctrl_index, ld_target_id, operation, param, param_length);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_set_ld_boot_priority(SML_LD_TARGET_S *ld)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_set_ld_boot_priority != NULL) {
        return g_sml_adapter->sml_set_ld_boot_priority(ld);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_set_ld_delete(SML_LD_TARGET_S *ld)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_set_ld_delete != NULL) {
        return g_sml_adapter->sml_set_ld_delete(ld);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_create_ld_on_existed_array(SML_RAID_ON_EXISTED_ARRAY_PARAM_S *config)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_create_ld_on_existed_array != NULL) {
        return g_sml_adapter->sml_create_ld_on_existed_array(config);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_create_ld_on_new_array(SML_RAID_ON_NEW_ARRAY_PARAM_S *config)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_create_ld_on_new_array != NULL) {
        return g_sml_adapter->sml_create_ld_on_new_array(config);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_get_ld_sscd_caching_enable(SML_LD_SSCD_CACHING_ENABLE_S *ld)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_get_ld_sscd_caching_enable != NULL) {
        return g_sml_adapter->sml_get_ld_sscd_caching_enable(ld);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_get_sscd_associated_ld_list(SML_SSCD_ASSOCIATED_LD_LIST_S *ld)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_get_sscd_associated_ld_list != NULL) {
        return g_sml_adapter->sml_get_sscd_associated_ld_list(ld);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_get_ld_associated_sscd_list(SML_LD_ASSOCIATED_SSCD_LIST_S *ld)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_get_ld_associated_sscd_list != NULL) {
        return g_sml_adapter->sml_get_ld_associated_sscd_list(ld);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_set_ld_cachecade_association(SML_LD_SET_CACHECADE_ASSOCIATION_S *ld)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_set_ld_cachecade_association != NULL) {
        return g_sml_adapter->sml_set_ld_cachecade_association(ld);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_create_ld_as_cachecade(SML_RAID_CACHECADE_PARAM_S *config)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_create_ld_as_cachecade != NULL) {
        return g_sml_adapter->sml_create_ld_as_cachecade(config);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_get_pd_info(guint8 ctrl_index, guint16 pd_device_id, SML_PD_BASIC_INFO_S *pd)
{
    if (g_sml_adapter != NULL && g_sml_adapter->smlib_get_pd_info != NULL) {
        return g_sml_adapter->smlib_get_pd_info(ctrl_index, pd_device_id, pd);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_get_pd_sas_smart_info(guint8 ctrl_index, guint16 pd_device_id,
    SML_PD_SAS_SMART_INFO *smart_info)
{
    if (g_sml_adapter != NULL && g_sml_adapter->smlib_get_pd_sas_smart_info != NULL) {
        return g_sml_adapter->smlib_get_pd_sas_smart_info(ctrl_index, pd_device_id, smart_info);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_pd_operation(SML_PD_OPERTATION_S *pd)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_pd_operation != NULL) {
        return g_sml_adapter->sml_pd_operation(pd);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_diagnose_encl_comm_error(SML_PD_FAULT_ANALYSIS *diag_info)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_diagnose_encl_comm_error != NULL) {
        return g_sml_adapter->sml_diagnose_encl_comm_error(diag_info);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_diagnose_pd_sense_error(SML_PD_FAULT_ANALYSIS* diag_info)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_diagnose_pd_sense_error != NULL) {
        return g_sml_adapter->sml_diagnose_pd_sense_error(diag_info);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_get_smart_data_str(guint8 controller_index, guint16 pd_device_id,
    guint8 hdd_intf_type, GVariant **smart_info_var)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_get_smart_data_str != NULL) {
        return g_sml_adapter->sml_get_smart_data_str(controller_index, pd_device_id, hdd_intf_type, smart_info_var);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_diagnose_link_phy_error(SML_PD_FAULT_ANALYSIS *diag_info, guint32 serial_threshold,
    guint32 recent_threshold)
{
    if (g_sml_adapter != NULL && g_sml_adapter->smlib_diagnose_link_phy_error != NULL) {
        return g_sml_adapter->smlib_diagnose_link_phy_error(diag_info, serial_threshold, recent_threshold);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_get_ctrl_exp_sas_phy_err_count(SML_CTRL_EXP_SAS_PHY_INFO_S *expander)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_get_ctrl_exp_sas_phy_err_count != NULL) {
        return g_sml_adapter->sml_get_ctrl_exp_sas_phy_err_count(expander);
    }
    return 0;
}

gint32 l_sml_adapter::sml_adapter_get_ctrl_phy_err_count(guint8 ctrl_index, SML_SASPHY_INFO_S *ctrl,
    guint8 force_update)
{
    if (g_sml_adapter != NULL && g_sml_adapter->smlib_get_ctrl_phy_err_count != NULL) {
        return g_sml_adapter->smlib_get_ctrl_phy_err_count(ctrl_index, ctrl, force_update);
    }
    return 0;
}

void l_sml_adapter::sml_adapter_clear_all_controller_info(void)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_clear_all_controller_info != NULL) {
        return g_sml_adapter->sml_clear_all_controller_info();
    }
}

gint8 l_sml_adapter::sml_adapter_get_ctrl_init_state(guint8 ctrl_index)
{
    if (g_sml_adapter != NULL && g_sml_adapter->sml_get_ctrl_init_state != NULL) {
        return g_sml_adapter->sml_get_ctrl_init_state(ctrl_index);
    }
    return 0;
}
} // namespace