/* 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 "math.h"
#include "sml_errcodes.h"
#include "sml_public.h"
#include "sml_oob.h"
#include "pmc/pstorc.h"
#include "pmc/sysc_struct.h"
#include "pmc/sysc_cmd.h"
#include "sc_misc.h"
#include "sc_ctrl.h"

#define SC_LOG_LAST_CRASH_DUMP_MAX_LEN (1024 * 256) /* 256KB */
#define SC_LOG_SERIAL_OUTPUT_MAX_LEN (1024 * 1024 * 3) /* 3MB */

typedef struct {
    SML_CTRL_LOG_TYPE_E log_type;
    SC_LOG_TYPE collect_type;
    guint32 log_max_len;
} SC_LOG_CMD;

LOCAL SC_LOG_CMD g_sc_log_cmd[] = {
    {CTRL_LOG_LAST_CRASH_DUMP, SC_LOG_LAST_CRASH_DUMP, SC_LOG_LAST_CRASH_DUMP_MAX_LEN},
    {CTRL_LOG_SERIAL_OUTPUT, SC_LOG_SERIAL_OUTPUT, SC_LOG_SERIAL_OUTPUT_MAX_LEN},
};

/*
 * Description: 添加控制器，当前为空函数
 */
gint32 pmc_add_ctrl(guint32 ctrl_id)
{
    return SML_SUCCESS;
}

/*
 * Description: 去初始化CDA
 */
LOCAL gint32 uninit_cda(guint32 ctrl_id)
{
    SC_LIB_CMD_PARAM_T lcp;

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

    lcp.cmdType = SC_CTRL_CMD_TYPE;
    lcp.cmd = SC_UNINIT_CDA;
    lcp.ctrlId = ctrl_id;

    return ProcessSCCommandCall(&lcp);
}

/*
 * Description: 移除控制器
 */
gint32 pmc_remove_ctrl(guint32 ctrl_id)
{
    return uninit_cda(ctrl_id);
}

/*
 * Description: 初始化CDA
 */
LOCAL gint32 init_cda(guint32 ctrl_id)
{
    SC_LIB_CMD_PARAM_T lcp;

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

    lcp.cmdType = SC_CTRL_CMD_TYPE;
    lcp.cmd = SC_INIT_CDA;
    lcp.ctrlId = ctrl_id;
    lcp.timeout = MAX_SET_CMD_TIMEOUT;

    return ProcessSCCommandCall(&lcp);
}

/*
 * Description: 初始化某个控制器的CDA
 */
gint32 pmc_init_ctrl_manage(guint32 ctrl_id, MCTP_WRITEREAD_FUNC mctp_writeread_func)
{
    gint32 ret = load_storagecore(mctp_writeread_func);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    return init_cda(ctrl_id);
}

/*
 * Description: 退出PMC RAID带外管理
 */
gint32 pmc_exit_ctrl_manage(guint32 ctrl_id, MCTP_WRITEREAD_FUNC mctp_writeread_func)
{
    return unload_storagecore();
}

/*
 * Description: 重新初始化CDA
 */
LOCAL gint32 reinit_cda(guint32 ctrl_id)
{
    SC_LIB_CMD_PARAM_T lcp;

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

    lcp.cmdType = SC_CTRL_CMD_TYPE;
    lcp.cmd = SC_REINIT_CDA;
    lcp.ctrlId = ctrl_id;
    lcp.timeout = MAX_SET_CMD_TIMEOUT;

    return ProcessSCCommandCall(&lcp);
}

/*
 * Description: 更新控制器缓存
 */
gint32 pmc_update_ctrl_cache(guint32 ctrl_id)
{
    return reinit_cda(ctrl_id);
}

/*
 * Description: 获取控制器信息
 */
LOCAL gint32 get_ctrl_info(guint32 ctrl_id, SC_CTRL_INFO *ctrl_info)
{
    SC_LIB_CMD_PARAM_T lcp;

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

    lcp.cmdType = SC_CTRL_CMD_TYPE;
    lcp.cmd = SC_GET_CTRL_INFO;
    lcp.ctrlId = ctrl_id;
    lcp.dataSize = (guint32)sizeof(SC_CTRL_INFO);
    lcp.pData = ctrl_info;

    return ProcessSCCommandCall(&lcp);
}

LOCAL guint8 parse_mode_info(guint8 mode_info)
{
    guint8 mode;
    switch (mode_info & kControllerModeCurrentMask) {
        case kControllerModeCurrentRAID:
            mode = CTRL_MODE_RAID;
            break;
        case kControllerModeCurrentHBA:
            mode = CTRL_MODE_HBA;
            break;
        case kControllerModeCurrentMixed:
            mode = CTRL_MODE_MIXED;
            break;
        default:
            mode = CTRL_MODE_UNKNOWN;
    }
    return mode;
}

/*
 * Description: 解析控制器 Sas link rate
 */
LOCAL guint8 parse_ctrl_link_rate(guint8 phy_rate)
{
    switch (phy_rate) {
        case kPhyRate3G:
            return CTRL_DEVICE_INTERFACE_SAS_3G;
        case kPhyRate6G:
            return CTRL_DEVICE_INTERFACE_SAS_6G;
        case kPhyRate12G:
            return CTRL_DEVICE_INTERFACE_SAS_12G;
        default:
            return CTRL_DEVICE_INTERFACE_INVALID;
    }
}

/*
 * Description: 获取控制器支持的raid级别
 */
LOCAL void get_ctrl_support_raid_level(SML_CTRL_BASIC_INFO_S *ctrl, SC_CTRL_INFO *ctrl_info)
{
    ctrl->raid0_supported = ctrl_info->operations.support_raid0;
    ctrl->raid1_supported = ctrl_info->operations.support_raid1;
    ctrl->raid5_supported = ctrl_info->operations.support_raid5;
    ctrl->raid6_supported = ctrl_info->operations.support_raid6;
    ctrl->raid10_supported = ctrl_info->operations.support_raid10;
    ctrl->raid50_supported = ctrl_info->operations.support_raid50;
    ctrl->raid60_supported = ctrl_info->operations.support_raid60;
    ctrl->raid1adm_supported = ctrl_info->operations.support_raid1ADM;
    ctrl->raid10adm_supported = ctrl_info->operations.support_raid10ADM;
    ctrl->raid1triple_supported = ctrl_info->operations.support_raid1triple;
    ctrl->raid10triple_supported = ctrl_info->operations.support_raid10triple;
    return;
}

/*
 * Description: 获取控制器支持的操作
 */
LOCAL void get_ctrl_support_operation(SML_CTRL_BASIC_INFO_S *ctrl, SC_CTRL_INFO *ctrl_info)
{
    // 如果支持Mixed模式，说明同时支持RAID和HBA模式
    if (ctrl_info->mode_info & kControllerModeSupportsMixedMode) {
        ctrl->operations.ctrl_operations.support_mixed = 1;
        ctrl->operations.ctrl_operations.support_raid = 1;
        ctrl->operations.ctrl_operations.support_hba = 1;
    }

    ctrl->operations.ctrl_operations.support_mode_set = 1; // 默认支持工作模式切换
    ctrl->operations.ctrl_operations.configured_drive_wcp = ctrl_info->properties.configured_drive_wcp;
    ctrl->operations.ctrl_operations.unconfigured_drive_wcp = ctrl_info->properties.unconfigured_drive_wcp;
    ctrl->operations.ctrl_operations.hba_drive_wcp = ctrl_info->properties.hba_drive_wcp;
    ctrl->operations.pd_operations.support_temperature = 1; // 默认支持获取硬盘温度
    ctrl->operations.ld_operations.support_write_policy = 1; // 默认支持写策略
    return;
}

/*
 * Description: 不支持的字段，赋无效值
 */
LOCAL void set_ctrl_properties_unsupported(SML_CTRL_BASIC_INFO_S *ctrl)
{
    ctrl->cache_pinned = STORAGE_INFO_INVALID_BYTE;
    ctrl->maint_pd_fail_history = STORAGE_INFO_INVALID_BYTE;
    return;
}

/*
 * Description: 获取控制器信息
 */
gint32 pmc_get_ctrl_info(guint32 ctrl_id, gpointer data)
{
    if (data == NULL) {
        return SML_ERR_NULL_DATA;
    }

    SC_CTRL_INFO ctrl_info;

    (void)memset_s(&ctrl_info, sizeof(SC_CTRL_INFO), 0, sizeof(SC_CTRL_INFO));
    ctrl_info.cur_temp_reading = STORAGE_INFO_INVALID_BYTE;

    gint32 ret = get_ctrl_info(ctrl_id, &ctrl_info);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    SML_CTRL_BASIC_INFO_S *ctrl = (SML_CTRL_BASIC_INFO_S *)data;
    strncpy_s(ctrl->ctrl_name, sizeof(ctrl->ctrl_name), ctrl_info.productID, strlen(ctrl_info.productID));
    strncpy_s(ctrl->fw_version, sizeof(ctrl->fw_version), ctrl_info.fwVersion, strlen(ctrl_info.fwVersion));
    strncpy_s(ctrl->ctrl_sn, sizeof(ctrl->ctrl_sn), ctrl_info.sn, strlen(ctrl_info.sn));

    ctrl->memory_size = ctrl_info.memorySize;
    ctrl->min_strip = log2(ctrl_info.properties.min_strip_size_bytes / CAPACITY_CONVERSION_SIZE) + 1; // 以2为底进行转换
    ctrl->max_strip = log2(ctrl_info.properties.max_strip_size_bytes / CAPACITY_CONVERSION_SIZE) + 1; // 以2为底进行转换

    get_ctrl_support_raid_level(ctrl, &ctrl_info); // 获取控制器支持的raid级别
    ctrl->ctrl_temp = ctrl_info.cur_temp_reading;
    debug_log(DLOG_INFO, "cur_temp_reading = %u", ctrl_info.cur_temp_reading);
    ctrl->mode = parse_mode_info(ctrl_info.mode_info);
    ctrl->spare_activation_mode = ctrl_info.spare_activation_mode; // spare activation mode
    ctrl->pcie_link_width = ctrl_info.pcie_link_width;
    if (ctrl_info.nobattery_write_cache == kControllerNBWCEnabled) {
        ctrl->nobattery_write_cache = 1; // 对应业务场景设置为1
    } else if (ctrl_info.nobattery_write_cache == kControllerNBWCDisabled) {
        ctrl->nobattery_write_cache = 0; // 对应业务场景设置为0
    } else {
        ctrl->nobattery_write_cache = ctrl_info.nobattery_write_cache; // 无电池写缓存模式
    }
    ctrl->read_cache_percent = ctrl_info.read_cache_percent;
    (void)strncpy_s(ctrl->hardware_revision, sizeof(ctrl->hardware_revision),
                    ctrl_info.hardware_revision, strlen(ctrl_info.hardware_revision));

    ctrl->device_interface = parse_ctrl_link_rate(ctrl_info.max_phy_rate);
    get_ctrl_support_operation(ctrl, &ctrl_info);
    set_ctrl_properties_unsupported(ctrl);
    return SML_SUCCESS;
}

/*
 * Description: 获取控制器sas地址
 */
gint32 pmc_get_ctrl_sas_addr(guint32 ctrl_id, gpointer data)
{
    if (data == NULL) {
        return SML_ERR_NULL_DATA;
    }

    SC_CTRL_INFO ctrl_info;

    (void)memset_s(&ctrl_info, sizeof(SC_CTRL_INFO), 0, sizeof(SC_CTRL_INFO));

    gint32 ret = get_ctrl_info(ctrl_id, &ctrl_info);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    SML_SAS_ADDR_S *ctrl = (SML_SAS_ADDR_S *)data;
    strncpy_s(ctrl->addr, sizeof(ctrl->addr), ctrl_info.wwn, strlen(ctrl_info.wwn));

    return SML_SUCCESS;
}
/*
 * Description: 设置无电池写缓存策略
 */
LOCAL gint32 set_ctrl_nbwc(guint32 ctrl_id, guint8 *state)
{
    SC_LIB_CMD_PARAM_T lcp;
    (void)memset_s(&lcp, sizeof(lcp), 0, sizeof(lcp));
    lcp.cmdType = SC_CTRL_CMD_TYPE;
    lcp.cmd = SC_SET_CTRL_NBWC;
    lcp.ctrlId = ctrl_id;
    lcp.timeout = MAX_SET_CMD_TIMEOUT;
    lcp.dataSize = (guint32)sizeof(guint8);
    lcp.pData = state;
    return ProcessSCCommandCall(&lcp);
}
/*
 * Description: 设置读缓存百分比
 */
LOCAL gint32 set_ctrl_read_cache_percnet(guint32 ctrl_id, guint8 *value)
{
    SC_LIB_CMD_PARAM_T lcp;
    (void)memset_s(&lcp, sizeof(lcp), 0, sizeof(lcp));
    lcp.cmdType = SC_CTRL_CMD_TYPE;
    lcp.cmd = SC_SET_CTRL_READ_CACHE_PERCENT;
    lcp.ctrlId = ctrl_id;
    lcp.timeout = MAX_SET_CMD_TIMEOUT;
    lcp.dataSize = (guint32)sizeof(guint8);
    lcp.pData = value;
    return ProcessSCCommandCall(&lcp);
}
/*
 * Description: 设置默认写缓存策略
 */
LOCAL gint32 set_ctrl_wcp(guint32 ctrl_id, SC_DRIVE_WCP_INFO *data)
{
    SC_LIB_CMD_PARAM_T lcp;
    (void)memset_s(&lcp, sizeof(lcp), 0, sizeof(lcp));
    lcp.cmdType = SC_CTRL_CMD_TYPE;
    lcp.cmd = SC_SET_CTRL_WRITE_CACHE_POLICY;
    lcp.ctrlId = ctrl_id;
    lcp.timeout = MAX_SET_CMD_TIMEOUT;
    lcp.dataSize = (guint32)sizeof(SC_DRIVE_WCP_INFO);
    lcp.pData = data;
    return ProcessSCCommandCall(&lcp);
}

/*
 * Description: 获取BBU信息
 */
LOCAL gint32 get_bbu_info(guint32 ctrl_id, SC_BBU_INFO *bbu_info)
{
    SC_LIB_CMD_PARAM_T lcp;

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

    lcp.cmdType = SC_BBU_CMD_TYPE;
    lcp.cmd = SC_GET_BBU_INFO;
    lcp.ctrlId = ctrl_id;
    lcp.dataSize = (guint32)sizeof(SC_BBU_INFO);
    lcp.pData = bbu_info;

    return ProcessSCCommandCall(&lcp);
}

gint32 pmc_get_ctrl_health(guint32 ctrl_id, gpointer data)
{
    if (data == NULL) {
        return SML_ERR_NULL_DATA;
    }

    SC_BBU_INFO bbu_info;

    (void)memset_s(&bbu_info, sizeof(SC_BBU_INFO), 0, sizeof(SC_BBU_INFO));

    gint32 ret = get_bbu_info(ctrl_id, &bbu_info);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    SML_CTRL_HEALTH_DATA_S *ctrl = (SML_CTRL_HEALTH_DATA_S *)data;
    ctrl->bbu_present =  (bbu_info.status == kControllerBackupPowerSourceNotPresent) ? FALSE : TRUE;

    return SML_SUCCESS;
}

/*
 * Description: 获取BBU状态
 */
gint32 pmc_get_ctrl_bbu_status(guint32 ctrl_id, gpointer data)
{
#define BBU_TYPE_NONE          "None"
#define BBU_TYPE_CAPACITOR     "Super Capacitor"
#define BBU_TYPE_BATTERY       "Battery"
#define BBU_TYPE_SMART_BATTERY "Smart Battery"
#define BBU_TYPE_UNKNOWN       "Unknown"

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

    SC_BBU_INFO bbu_info;

    (void)memset_s(&bbu_info, sizeof(SC_BBU_INFO), 0, sizeof(SC_BBU_INFO));

    gint32 ret = get_bbu_info(ctrl_id, &bbu_info);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    SML_BBU_STATUS_S *bbu = (SML_BBU_STATUS_S *)data;

    bbu->temperature = STORAGE_INFO_INVALID_BYTE;    // 不支持获取温度

    const gchar *type_desc = NULL;
    if (bbu_info.type == kBackupPowerSourceTypeNone) {
        type_desc = BBU_TYPE_NONE;
    } else if (bbu_info.type == kBackupPowerSourceTypeCapacitor) {
        type_desc = BBU_TYPE_CAPACITOR;
    } else if (bbu_info.type == kBackupPowerSourceTypeBattery) {
        type_desc = BBU_TYPE_BATTERY;
    } else if (bbu_info.type == kBackupPowerSourceTypeSmartBattery) {
        type_desc = BBU_TYPE_SMART_BATTERY;
    } else {
        type_desc = BBU_TYPE_UNKNOWN;
    }

    errno_t securec_rv = strncpy_s(bbu->type, sizeof(bbu->type), type_desc, strlen(type_desc));
    if (securec_rv != EOK) {
        debug_log(DLOG_ERROR, "%s: strncpy_s failed, ret = %d", __FUNCTION__, securec_rv);
        return SML_ERR_SEC_FUNC_FAILED;
    }

    bbu->failed = (bbu_info.status == kControllerBackupPowerSourceFailed) ? 1 : 0;
    return SML_SUCCESS;
}

gint32 pmc_get_ctrl_phy_err_count(guint32 ctrl_id, gpointer data)
{
    return SML_SUCCESS;
}

/*
 * Description: 无电池写状态前端和后台的对应关系转换
 */
LOCAL void nbwc_web_third_lib_map(guint8 raw_data, guint8* state)
{
    if (raw_data == 1) {
        *state = kControllerNBWCEnabled;
    } else if (raw_data == 0) {
        *state = kControllerNBWCDisabled;
    } else {
        *state = kControllerNBWCInvalid;
    }
}

/*
 * Description: 写策略前端和后台的对应关系转换
 */
LOCAL void wcp_web_third_lib_map(SC_DRIVE_WCP_INFO *raw_policy, SC_DRIVE_WCP_INFO *write_policy)
{
    switch (raw_policy->type) {
        case CTRL_DRIVE_WCP_CONFIG:
            write_policy->type = kDriveWriteCacheUsageTypeConfigured;
            break;
        case CTRL_DRIVE_WCP_UNCONFIG:
            write_policy->type = kDriveWriteCacheUsageTypeUnconfigured;
            break;
        case CTRL_DRIVE_WCP_HBA:
            write_policy->type = kDriveWriteCacheUsageTypeHBA;
            break;
        default:
            write_policy->type = kControllerDriveWriteCacheInvalid;
            break;
    }

    switch (raw_policy->policy) {
        case CTRL_DRIVE_WCP_DEFAULT:
            write_policy->policy = kControllerDriveWriteCacheDefault;
            break;
        case CTRL_DRIVE_WCP_ENABLED:
            write_policy->policy = kControllerDriveWriteCacheEnabled;
            break;
        case CTRL_DRIVE_WCP_DISABLED:
            write_policy->policy = kControllerDriveWriteCacheDisabled;
            break;
        default:
            write_policy->policy = kControllerDriveWriteCacheInvalid;
            break;
    }
}


LOCAL guint8 parse_intended_mode(guint8 mode)
{
    switch (mode) {
        case CTRL_MODE_RAID:
            return kControllerModeRAID;
        case CTRL_MODE_HBA:
            return kControllerModeHBA;
        case CTRL_MODE_MIXED:
            return kControllerModeMixed;
        default:
            return STORAGE_INFO_INVALID_BYTE;
    }
}

LOCAL gint32 set_ctrl_mode(guint32 ctrl_id, guint8 mode)
{
    SC_LIB_CMD_PARAM_T lcp;

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

    lcp.cmdType = SC_CTRL_CMD_TYPE;
    lcp.cmd = SC_SET_CTRL_MODE;
    lcp.ctrlId = ctrl_id;
    lcp.dataSize = (guint32)sizeof(guint8);
    lcp.pData = &mode;

    return ProcessSCCommandCall(&lcp);
}

LOCAL gint32 dump_ctrl_log(guint32 ctrl_id, SML_CTRL_LOG_DATA_S* log_data)
{
    gsize i = 0;
    gsize list_len = (gsize)G_N_ELEMENTS(g_sc_log_cmd);
    for (; i < list_len; i++) {
        if (g_sc_log_cmd[i].log_type == log_data->log_type) {
            break;
        }
    }

    if (i == list_len) {
        return RET_ERR;
    }

    /* convert log type */
    log_data->log_type = g_sc_log_cmd[i].collect_type;

    SC_LIB_CMD_PARAM_T lcp = {0};
    lcp.cmdType = SC_CTRL_CMD_TYPE;
    lcp.cmd = SC_GET_CTRL_LOG;
    lcp.ctrlId = ctrl_id;
    lcp.pData = log_data;

    gint32 ret = ProcessSCCommandCall(&lcp);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    if (log_data->log_length > g_sc_log_cmd[i].log_max_len) {
        gsize offset = log_data->log_length - g_sc_log_cmd[i].log_max_len;
        guint8* real_buf = (guint8*)g_malloc0(g_sc_log_cmd[i].log_max_len);
        if (real_buf == NULL) {
            debug_log(DLOG_ERROR, "%s: g_malloc0 failed[size:%u], errno[%s]", __FUNCTION__,
                g_sc_log_cmd[i].log_max_len, strerror(errno));
            return RET_ERR;
        }
        (void)memcpy_s(real_buf, g_sc_log_cmd[i].log_max_len, log_data->log_buffer + offset,
            g_sc_log_cmd[i].log_max_len);
        g_free(log_data->log_buffer);
        log_data->log_buffer = real_buf;
        log_data->log_length = g_sc_log_cmd[i].log_max_len;
    }

    return ret;
}

/*
 * Description: 对控制器操作
 */
gint32 pmc_ctrl_operations(guint32 ctrl_id, guint8 operation, gpointer param, guint32 param_length)
{
    SC_DRIVE_WCP_INFO write_policy;
    guint8 nbwc_third_lib_data;
    guint8 web_data;

    /* 恢复默认值，导入、清除配置没有参数，不需要判断 */
    if (param == NULL && operation != CTRL_OPERATION_RESTORE_DEFAULT &&
        operation != CTRL_OPERATION_IMPORT_FOREIGN_CONFIG && operation != CTRL_OPERATION_CLEAR_FOREIGN_CONFIG) {
        return SML_ERR_NULL_DATA;
    }

    switch (operation) {
        case CTRL_OPERATION_SET_PERSONALITY_MODE:
            if (param_length != sizeof(SML_CTRL_PERSONALITY_MODE)) {
                return SML_ERR_NULL_DATA;
            }
            SML_CTRL_PERSONALITY_MODE *mode_param = (SML_CTRL_PERSONALITY_MODE *)param;
            guint8 mode = parse_intended_mode(mode_param->mode);
            if (mode == STORAGE_INFO_INVALID_BYTE) {
                return SML_ERR_DATA_INVALID;
            }
            return set_ctrl_mode(ctrl_id, mode);

        case CTRL_OPERATION_ENABLE_NBWC:
            if (param == NULL) {
                return SML_ERR_NULL_DATA;
            }
            web_data = *(guint8 *)param;
            nbwc_web_third_lib_map(web_data, &nbwc_third_lib_data);
            return set_ctrl_nbwc(ctrl_id, &nbwc_third_lib_data);

        case CTRL_OPERATION_READ_CACHE_POLICY:
            return set_ctrl_read_cache_percnet(ctrl_id, param);

        case CTRL_OPERATION_WCP_VALUE:
            if (param_length != sizeof(SC_DRIVE_WCP_INFO)) {
                return SML_ERR_NULL_DATA;
            }
            SC_DRIVE_WCP_INFO *raw_policy = (SC_DRIVE_WCP_INFO *)param;
            wcp_web_third_lib_map(raw_policy, &write_policy);
            return set_ctrl_wcp(ctrl_id, &write_policy);

        case CTRL_OPERATION_DUMP_LOG:
            return dump_ctrl_log(ctrl_id, (SML_CTRL_LOG_DATA_S*)param);

        default:
            return SML_ERR_CTRL_OPERATION_NOT_SUPPORT;
    }
}