/* Copyright (c) 2024 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_phyerrorcode.h"
#include "ctrl.h"
#include "diagnose.h"
#include "sml_ctrl.h"
#include "l_sml_adapter.h"

namespace sml {
static int32_t diagnose_link_phy_error(lua_State *L, SML_PD_FAULT_ANALYSIS *diag_info, uint8_t ctrl_index,
    uint8_t pd_device_id, uint8_t encl_device_id, uint8_t pd_error, uint32_t serial_threshold,
    uint32_t recent_threshold)
{
    diag_info->i_controller_index = ctrl_index;
    diag_info->i_pd_device_id = pd_device_id;
    diag_info->i_encl_device_id = encl_device_id;
    diag_info->i_pd_error = pd_error;
    if (auto ret = l_sml_adapter::sml_adapter_diagnose_link_phy_error(diag_info,
        serial_threshold, recent_threshold); ret != RET_OK) {
        lua_pushinteger(L, ret);
        lua_error(L);
    }
    return 1;
}

static int32_t update_ctrl_exp_sas_phy_err_count(lua_State *L, SML_CTRL_EXP_SAS_PHY_INFO_S *expander,
    uint8_t ctrl_index)
{
    expander->i_controller_index = ctrl_index;
    if (auto ret = l_sml_adapter::sml_adapter_get_ctrl_exp_sas_phy_err_count(expander); ret != RET_OK) {
        lua_pushinteger(L, ret);
        lua_error(L);
    }
    return 1;
}

static int32_t update_ctrl_sas_phy_err_count(lua_State *L, SML_SASPHY_INFO_S *ctrl, uint8_t ctrl_index,
    uint8_t force_update)
{
    if (auto ret = l_sml_adapter::sml_adapter_get_ctrl_phy_err_count(ctrl_index, ctrl, force_update); ret != RET_OK) {
        lua_pushinteger(L, ret);
        lua_error(L);
    }
    return 1;
}

static uint8_t get_pd_short_dst_error(SML_PD_FAULT_ANALYSIS *info)
{
    return info->o_fault_bitmap.pd_short_dst_error;
}

static uint8_t get_pd_passthru_cmd_fail(SML_PD_FAULT_ANALYSIS *info)
{
    return info->o_fault_bitmap.pd_passthru_cmd_fail;
}

static uint8_t get_pd_crc_error(SML_PD_FAULT_ANALYSIS *info)
{
    return info->o_fault_bitmap.pd_crc_error;
}

static uint8_t get_pd_smart_log_error(SML_PD_FAULT_ANALYSIS *info)
{
    return info->o_fault_bitmap.pd_smart_log_error;
}

static uint8_t get_encl_encl_link_error(SML_PD_FAULT_ANALYSIS *info)
{
    return info->o_fault_bitmap.encl_encl_link_error;
}

static uint8_t get_ctrl_pd_link_error(SML_PD_FAULT_ANALYSIS *info)
{
    return info->o_fault_bitmap.ctrl_pd_link_error;
}

static uint8_t get_encl_pd_link_error(SML_PD_FAULT_ANALYSIS *info)
{
    return info->o_fault_bitmap.encl_pd_link_error;
}

static uint8_t get_ctrl_encl_link_error(SML_PD_FAULT_ANALYSIS *info)
{
    return info->o_fault_bitmap.ctrl_encl_link_error;
}

static uint8_t get_encl_comm_error(SML_PD_FAULT_ANALYSIS *info)
{
    return info->o_fault_bitmap.encl_comm_error;
}

static uint8_t get_sense_error(SML_PD_FAULT_ANALYSIS *info)
{
    return info->o_fault_bitmap.sense_error;
}

static uint8_t get_o_fault_dword(SML_PD_FAULT_ANALYSIS *info)
{
    return info->o_fault_dword;
}

static const char *get_io_buf(SML_PD_FAULT_ANALYSIS *info)
{
    if (!(g_utf8_validate(info->io_buf, strlen(info->io_buf), nullptr)) || strlen(info->io_buf) == 0) {
        return "";
    }
    return info->io_buf;
}

static uint8_t get_sas_phy_count(SML_CTRL_EXP_SAS_PHY_INFO_S *info)
{
    return info->o_expander_phy->phy_count;
}
static uint8_t get_sas_phy_id(SML_CTRL_EXP_SAS_PHY_INFO_S *info)
{
    return info->o_expander_phy->phy_info->phy_id;
}
static uint8_t get_sas_invalid_dword_count(SML_CTRL_EXP_SAS_PHY_INFO_S *info)
{
    return info->o_expander_phy->phy_info->invalid_dword_count;
}
static uint8_t get_sas_loss_dword_sync_count(SML_CTRL_EXP_SAS_PHY_INFO_S *info)
{
    return info->o_expander_phy->phy_info->loss_dword_sync_count;
}
static uint8_t get_sas_phy_reset_problem_count(SML_CTRL_EXP_SAS_PHY_INFO_S *info)
{
    return info->o_expander_phy->phy_info->phy_reset_problem_count;
}
static uint8_t get_sas_running_disparity_error_count(SML_CTRL_EXP_SAS_PHY_INFO_S *info)
{
    return info->o_expander_phy->phy_info->running_disparity_error_count;
}

static uint8_t get_ctrl_phy_invalid_dword_count(SML_SASPHY_INFO_S *info)
{
    return info->phy_err->invalid_dword_count;
}

static uint8_t get_ctrl_phy_loss_dword_sync_count(SML_SASPHY_INFO_S *info)
{
    return info->phy_err->loss_dword_sync_count;
}

static uint8_t get_ctrl_phy_phy_reset_problem_count(SML_SASPHY_INFO_S *info)
{
    return info->phy_err->phy_reset_problem_count;
}

static uint8_t get_ctrl_phy_running_disparity_error_count(SML_SASPHY_INFO_S *info)
{
    return info->phy_err->running_disparity_error_count;
}

void l_phyerrorcode::def_diagnose_link_phy_error_properties(lua_State *L,
    luawrap::lua_class<SML_PD_FAULT_ANALYSIS> &cls)
{
    cls.def_readonly("i_controller_index", &SML_PD_FAULT_ANALYSIS::i_controller_index);
    cls.def_readonly("i_pd_device_id", &SML_PD_FAULT_ANALYSIS::i_pd_device_id);
    cls.def_readonly("i_encl_device_id", &SML_PD_FAULT_ANALYSIS::i_encl_device_id);
    cls.def_readonly("i_pd_error", &SML_PD_FAULT_ANALYSIS::i_pd_error);

    cls.def_property("pd_short_dst_error", c_func_wrap(L, get_pd_short_dst_error));
    cls.def_property("pd_passthru_cmd_fail", c_func_wrap(L, get_pd_passthru_cmd_fail));
    cls.def_property("pd_crc_error", c_func_wrap(L, get_pd_crc_error));
    cls.def_property("pd_smart_log_error", c_func_wrap(L, get_pd_smart_log_error));
    cls.def_property("encl_encl_link_error", c_func_wrap(L, get_encl_encl_link_error));
    cls.def_property("ctrl_pd_link_error", c_func_wrap(L, get_ctrl_pd_link_error));
    cls.def_property("encl_pd_link_error", c_func_wrap(L, get_encl_pd_link_error));
    cls.def_property("ctrl_encl_link_error", c_func_wrap(L, get_ctrl_encl_link_error));
    cls.def_property("encl_comm_error", c_func_wrap(L, get_encl_comm_error));
    cls.def_property("sense_error", c_func_wrap(L, get_sense_error));

    cls.def_property("o_fault_dword", c_func_wrap(L, get_o_fault_dword));
    cls.def_property("io_buf", c_func_wrap(L, get_io_buf));
}

void l_phyerrorcode::def_ctrl_exp_sas_phy_err_count_properties(lua_State *L,
    luawrap::lua_class<SML_CTRL_EXP_SAS_PHY_INFO_S> &cls)
{
    cls.def_readonly("i_controller_index", &SML_CTRL_EXP_SAS_PHY_INFO_S::i_controller_index);
    cls.def_readonly("o_expander_count", &SML_CTRL_EXP_SAS_PHY_INFO_S::o_expander_count);
    cls.def_property("phy_count", c_func_wrap(L, get_sas_phy_count));
    cls.def_property("phy_id", c_func_wrap(L, get_sas_phy_id));
    cls.def_property("invalid_dword_count", c_func_wrap(L, get_sas_invalid_dword_count));
    cls.def_property("loss_dword_sync_count", c_func_wrap(L, get_sas_loss_dword_sync_count));
    cls.def_property("phy_reset_problem_count", c_func_wrap(L, get_sas_phy_reset_problem_count));
    cls.def_property("running_disparity_error_count", c_func_wrap(L, get_sas_running_disparity_error_count));
}

// def_ctrl_phy_err_count
void l_phyerrorcode::def_ctrl_phy_err_count(lua_State *L, luawrap::lua_class<SML_SASPHY_INFO_S> &cls)
{
    cls.def_readonly("phy_count", &SML_SASPHY_INFO_S::phy_count);
    cls.def_property("invalid_dword_count", c_func_wrap(L, get_ctrl_phy_invalid_dword_count));
    cls.def_property("loss_dword_sync_count", c_func_wrap(L, get_ctrl_phy_loss_dword_sync_count));
    cls.def_property("phy_reset_problem_count", c_func_wrap(L, get_ctrl_phy_phy_reset_problem_count));
    cls.def_property("running_disparity_error_count", c_func_wrap(L, get_ctrl_phy_running_disparity_error_count));
}

void l_phyerrorcode::register_diagnose_link_phy_error(lua_State *L, luawrap::stack_table &t)
{
    // 导出 SML_PD_FAULT_ANALYSIS 结构给 lua 使用
    auto cls = luawrap::lua_class<SML_PD_FAULT_ANALYSIS>(L).ctor<>();
    cls.def("reset_zero", c_func_wrap(L, reset_zero<SML_PD_FAULT_ANALYSIS>));
    cls.def("update", c_func_wrap(L, diagnose_link_phy_error));
    def_diagnose_link_phy_error_properties(L, cls);

    t.set("SML_PD_FAULT_ANALYSIS", cls);
}

void l_phyerrorcode::register_ctrl_exp_sas_phy_err_count(lua_State *L, luawrap::stack_table &t)
{
    // 导出 SML_CTRL_EXP_SAS_PHY_INFO_S 结构给 lua 使用
    auto cls = luawrap::lua_class<SML_CTRL_EXP_SAS_PHY_INFO_S>(L).ctor<>();
    cls.def("reset_zero", c_func_wrap(L, reset_zero<SML_CTRL_EXP_SAS_PHY_INFO_S>));
    cls.def("update", c_func_wrap(L, update_ctrl_exp_sas_phy_err_count));
    def_ctrl_exp_sas_phy_err_count_properties(L, cls);

    t.set("SML_CTRL_EXP_SAS_PHY_INFO_S", cls);
}

void l_phyerrorcode::register_ctrl_sas_phy_err_count(lua_State *L, luawrap::stack_table &t)
{
    // 导出 SML_SASPHY_INFO_S 结构给 lua 使用
    auto cls = luawrap::lua_class<SML_SASPHY_INFO_S>(L).ctor<>();
    cls.def("reset_zero", c_func_wrap(L, reset_zero<SML_SASPHY_INFO_S>));
    cls.def("update", c_func_wrap(L, update_ctrl_sas_phy_err_count));
    def_ctrl_phy_err_count(L, cls);

    t.set("SML_SASPHY_INFO_S", cls);
}

static luawrap::n_ret get_ctrl_sas_phy_err(lua_State *L, uint8_t ctrl_index, uint8_t force_update)
{
    SML_SASPHY_INFO_S info;
    reset_zero(&info);
    if (auto ret = l_sml_adapter::sml_adapter_get_ctrl_phy_err_count(ctrl_index, &info, force_update); ret != RET_OK) {
        lua_pushinteger(L, ret);
        lua_error(L);
    }

    auto t = luawrap::stack::new_table(L);
    for (auto i = 0; i < info.phy_count; ++i) {
        luawrap::restore_stack_top _s(L);

        auto phy = luawrap::stack::new_table(L, 0, 4);
        phy.set("invalid_dword_count", info.phy_err[i].invalid_dword_count);
        phy.set("loss_dword_sync_count", info.phy_err[i].loss_dword_sync_count);
        phy.set("phy_reset_problem_count", info.phy_err[i].phy_reset_problem_count);
        phy.set("running_disparity_error_count", info.phy_err[i].running_disparity_error_count);
        t.set(i, phy);
    }
    return 1;
}

void l_phyerrorcode::register_to(lua_State *L, luawrap::stack_table &t)
{
    luawrap::restore_stack_top _s(L);

    t.set("get_ctrl_sas_phy_err", c_func_wrap(L, get_ctrl_sas_phy_err));
    register_diagnose_link_phy_error(L, t);
    register_ctrl_exp_sas_phy_err_count(L, t);
    register_ctrl_sas_phy_err_count(L, t);
}
}