/**
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
 * CANN Open Software License Agreement Version 2.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * 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 FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 */
#include <limits.h>
#include "ascend_hal.h"
#include "drv_user_common.h"
#include "trs_user_pub_def.h"
#include "trs_ioctl.h"
#include "trs_res.h"
#include "trs_sqcq.h"
#include "trs_master_urma.h"
#include "trs_master_async.h"
#include "trs_master_event.h"
#include "trs_urma_async.h"

#ifndef EMU_ST
drvError_t __attribute__((weak)) trs_urma_res_config(uint32_t dev_id, struct halResourceIdInputInfo *in,
    struct halResourceConfigInfo *para)
{
    (void)dev_id;
    (void)in;
    (void)para;
    return DRV_ERROR_NOT_SUPPORT;
}

drvError_t __attribute__((weak)) trs_sqcq_urma_alloc(uint32_t dev_id, struct halSqCqInputInfo *in,
    struct halSqCqOutputInfo *out)
{
    (void)dev_id;
    (void)in;
    (void)out;
    return DRV_ERROR_NOT_SUPPORT;
}

drvError_t __attribute__((weak)) trs_sqcq_urma_free(uint32_t dev_id, struct halSqCqFreeInfo *info, bool remote_free_flag)
{
    (void)dev_id;
    (void)info;
    (void)remote_free_flag;
    return DRV_ERROR_NOT_SUPPORT;
}

drvError_t __attribute__((weak)) trs_sq_cq_query_sync(uint32_t dev_id, struct halSqCqQueryInfo *info)
{
    (void)dev_id;
    (void)info;
    return DRV_ERROR_NOT_SUPPORT;
}

drvError_t __attribute__((weak)) trs_sq_cq_config_sync(uint32_t dev_id, struct halSqCqConfigInfo *info)
{
    (void)dev_id;
    (void)info;
    return DRV_ERROR_NOT_SUPPORT;
}

drvError_t __attribute__((weak)) trs_sq_task_args_async_copy(uint32_t dev_id, struct halSqTaskArgsInfo *info,
    struct sqcq_usr_info *sq_info)
{
    (void)dev_id;
    (void)info;
    (void)sq_info;
    return DRV_ERROR_NOT_SUPPORT;
}

drvError_t __attribute__((weak)) trs_async_dma_wqe_create(uint32_t dev_id, struct trs_async_dma_input_para *in,
    struct halAsyncDmaOutputPara *out)
{
    (void)dev_id;
    (void)in;
    (void)out;
    return DRV_ERROR_NOT_SUPPORT;
}

drvError_t __attribute__((weak)) trs_async_dma_wqe_destory(uint32_t dev_id, struct trs_async_dma_destroy_para *para)
{
    (void)dev_id;
    (void)para;
    return DRV_ERROR_NOT_SUPPORT;
}

drvError_t __attribute__((weak)) trs_sq_task_send_urma(uint32_t dev_id, struct halTaskSendInfo *info,
    struct sqcq_usr_info *sq_info)
{
    (void)dev_id;
    (void)info;
    (void)sq_info;
    return DRV_ERROR_NOT_SUPPORT;
}

drvError_t __attribute__((weak)) trs_get_urma_tseg_info_by_va(uint32_t devid, uint64_t va, uint64_t size, uint32_t flag,
    struct halTsegInfo *tsegInfo)
{
    (void)devid;
    (void)va;
    (void)size;
    (void)flag;
    (void)tsegInfo;
    return DRV_ERROR_NOT_SUPPORT;
}

drvError_t __attribute__((weak)) trs_put_urma_tseg_info(uint32_t devid, struct halTsegInfo *tsegInfo)
{
    (void)devid;
    (void)tsegInfo;
    return DRV_ERROR_NOT_SUPPORT;
}

drvError_t __attribute__((weak)) trs_sq_jetty_info_query(uint32_t devid, struct halSqCqQueryInfo *info)
{
    (void)devid;
    (void)info;
    return DRV_ERROR_NOT_SUPPORT;
}

drvError_t __attribute__((weak)) trs_urma_sq_switch_stream_batch(uint32_t dev_id, struct sq_switch_stream_info *info,
    uint32_t num)
{
    (void)dev_id;
    (void)info;
    (void)num;
    return DRV_ERROR_NOT_SUPPORT;
}

#endif

static bool trs_is_remote_res_config_ops(uint32_t flag)
{
    if (drvGetRuntimeApiVer() >= TRS_MC2_BIND_LOGICCQ_FEATURE) {
        if ((flag & TSDRV_FLAG_REMOTE_ID) != 0) {
            return true;
        }
    } else {
        trs_debug("Not support. (runtime_ver=0x%x; drv_ver=0x%x)\n", drvGetRuntimeApiVer(), __HAL_API_VERSION);
    }
    return false;
}

drvError_t halResourceConfig(uint32_t devId, struct halResourceIdInputInfo *in, struct halResourceConfigInfo *para)
{
    drvError_t ret;

    ret = trs_res_config_para_check(devId, in, para);
    if (ret != DRV_ERROR_NONE) {
        return ret;
    }
    if ((trs_is_remote_res_config_ops(in->res[RESOURCEID_RESV_FLAG]))) {
        return trs_remote_res_config(devId, in, para);
    }

    if (((in->type == DRV_NOTIFY_ID) || (in->type == DRV_CNT_NOTIFY_ID)) && 
        ((para->prop == DRV_ID_RECORD) || (para->prop == DRV_ID_RESET))) {
        int connection_type = trs_get_connection_type(devId);
        switch (connection_type) {
            case TRS_CONNECT_PROTOCOL_PCIE:
            case TRS_CONNECT_PROTOCOL_HCCS:
            case TRS_CONNECT_PROTOCOL_RC:
                return trs_local_res_config(devId, in, para);
            case TRS_CONNECT_PROTOCOL_UB:
                return trs_urma_res_config(devId, in, para);
            default:
                trs_err("Invalid connection type. (dev_id=%u; connection_type=%d)\n", devId, connection_type);
                return DRV_ERROR_INVALID_DEVICE;
        }
    } else {
        return trs_local_res_config(devId, in, para);
    }
}

#define TRS_STREAM_TASK_QUEUE_MAX_DEPTH 32768U
drvError_t halStreamTaskFill(uint32_t dev_id, uint32_t stream_id, void *stream_mem, void *task_info, uint32_t task_cnt)
{
    drvError_t ret = 0;

    if (dev_id >= TRS_DEV_NUM) {
        trs_err("Invalid devId. (dev_id=%u)\n", dev_id);
        return DRV_ERROR_INVALID_VALUE;
    }

    if ((task_info == NULL) || (task_cnt == 0) || (task_cnt > TRS_STREAM_TASK_QUEUE_MAX_DEPTH)) {
        trs_err("Null ptr or task_cnt invalid. (ptr_is_NULL=%d; task_cnt=%u)\n", (task_info == NULL), task_cnt);
        return DRV_ERROR_INVALID_VALUE;
    }

    trs_dev_ctx_stream_mutex_lock(dev_id);
    ret = trs_stream_task_fill(dev_id, stream_id, stream_mem, task_info, task_cnt);
    trs_dev_ctx_stream_mutex_unlock(dev_id);

    return ret;
}

drvError_t halSqSwitchStreamBatch(uint32_t dev_id, struct sq_switch_stream_info *info, uint32_t num)
{
    int connection_type = TRS_CONNECT_PROTOCOL_UNKNOWN;
    drvError_t ret = 0;

    if (dev_id >= TRS_DEV_NUM) {
        trs_err("Invalid devId. (dev_id=%u)\n", dev_id);
        return DRV_ERROR_INVALID_VALUE;
    }

    if (info == NULL) {
        trs_err("Null ptr.\n");
        return DRV_ERROR_INVALID_VALUE;
    }

    trs_dev_ctx_stream_mutex_lock(dev_id);
    ret = trs_sq_switch_stream_batch(dev_id, info, num);
    if (ret != 0) {
        trs_dev_ctx_stream_mutex_unlock(dev_id);
        return ret;
    }

    connection_type = trs_get_connection_type(dev_id);
    switch (connection_type) {
        case TRS_CONNECT_PROTOCOL_PCIE:
        case TRS_CONNECT_PROTOCOL_HCCS:
        case TRS_CONNECT_PROTOCOL_RC:
            ret = DRV_ERROR_NONE;
            break;
        case TRS_CONNECT_PROTOCOL_UB:
            ret = trs_urma_sq_switch_stream_batch(dev_id, info, num);
            break;
        default:
            trs_err("Invalid connection type. (dev_id=%u; connection_type=%d)\n", dev_id, connection_type);
            ret = DRV_ERROR_INVALID_DEVICE;
            break;
    }

    trs_dev_ctx_stream_mutex_unlock(dev_id);
    return ret;
}

drvError_t halSqCqAllocate(uint32_t devId, struct halSqCqInputInfo *in, struct halSqCqOutputInfo *out)
{
    drvError_t ret;

    ret = trs_sqcq_alloc_para_check(devId, in, out);
    if (ret != DRV_ERROR_NONE) {
        return ret;
    }

    if ((in->type == DRV_NORMAL_TYPE) && !trs_is_remote_sqcq_ops(in->type, in->flag)) {
        int connection_type = trs_get_connection_type(devId);
        switch (connection_type) {
            case TRS_CONNECT_PROTOCOL_PCIE:
            case TRS_CONNECT_PROTOCOL_HCCS:
            case TRS_CONNECT_PROTOCOL_RC:
                return trs_sqcq_alloc(devId, in, out);
            case TRS_CONNECT_PROTOCOL_UB:
                return trs_sqcq_urma_alloc(devId, in, out);
            default:
                trs_err("Invalid connection type. (dev_id=%u; connection_type=%d)\n", devId, connection_type);
                return DRV_ERROR_INVALID_DEVICE;
        }
    } else {
        return trs_sqcq_alloc(devId, in, out);
    }
}

drvError_t halSqCqFree(uint32_t devId, struct halSqCqFreeInfo *info)
{
    drvError_t ret;

    ret = trs_sqcq_free_para_check(devId, info);
    if (ret != DRV_ERROR_NONE) {
        return ret;
    }

    if ((info->type == DRV_NORMAL_TYPE) && !trs_is_remote_sqcq_ops(info->type, info->flag)) {
        int connection_type = trs_get_connection_type(devId);
        switch (connection_type) {
            case TRS_CONNECT_PROTOCOL_PCIE:
            case TRS_CONNECT_PROTOCOL_HCCS:
            case TRS_CONNECT_PROTOCOL_RC:
                return trs_sqcq_free(devId, info);
            case TRS_CONNECT_PROTOCOL_UB:
                return trs_sqcq_urma_free(devId, info, true);
            default:
                trs_err("Invalid connection type. (dev_id=%u; connection_type=%d)\n", devId, connection_type);
                return DRV_ERROR_INVALID_DEVICE;
        }
    } else {
        return trs_sqcq_free(devId, info);
    }
}

drvError_t halSqCqQuery(uint32_t devId, struct halSqCqQueryInfo *info)
{
    if (info == NULL) {
        trs_err("Null ptr.\n");
        return DRV_ERROR_INVALID_VALUE;
    }

    if ((devId >= TRS_DEV_NUM) || (info->tsId >= TRS_TS_NUM)) {
        trs_err("Invalid para. (dev_id=%u; ts_id=%u)\n", devId, info->tsId);
        return DRV_ERROR_INVALID_VALUE;
    }

    if (info->type == DRV_NORMAL_TYPE) {
        int connection_type = trs_get_connection_type(devId);
        switch (connection_type) {
            case TRS_CONNECT_PROTOCOL_PCIE:
            case TRS_CONNECT_PROTOCOL_HCCS:
            case TRS_CONNECT_PROTOCOL_RC:
                if ((info->type == DRV_NORMAL_TYPE) && ((info->prop == DRV_SQCQ_PROP_H2D_ASYNC_JETTY_INFO) ||
                    (info->prop == DRV_SQCQ_PROP_D2D_ASYNC_JETTY_INFO))) {
                    return DRV_ERROR_NOT_SUPPORT;
                }
                return trs_sq_cq_query(devId, info);
            case TRS_CONNECT_PROTOCOL_UB:
                if ((info->type == DRV_NORMAL_TYPE) && ((info->prop == DRV_SQCQ_PROP_H2D_ASYNC_JETTY_INFO) ||
                    (info->prop == DRV_SQCQ_PROP_D2D_ASYNC_JETTY_INFO))) {
                    return trs_sq_jetty_info_query(devId, info);
                }
                if ((info->type == DRV_NORMAL_TYPE) &&
                    ((info->prop == DRV_SQCQ_PROP_SQ_HEAD) || (info->prop == DRV_SQCQ_PROP_SQ_CQE_STATUS) ||
                    (info->prop == DRV_SQCQ_PROP_SQ_DEPTH) || (info->prop == DRV_SQCQ_PROP_SQ_MEM_ATTR) ||
                    (info->prop == DRV_SQCQ_PROP_SQ_BASE))) {
                    return trs_sq_cq_query(devId, info);
                }
                return trs_sq_cq_query_sync(devId, info);
            default:
                trs_err("Invalid connection type. (dev_id=%u; connection_type=%d)\n", devId, connection_type);
                return DRV_ERROR_INVALID_DEVICE;
        }
    } else {
        return trs_sq_cq_query(devId, info);
    }
}

static bool trs_is_remote_sq_cq_config(struct halSqCqConfigInfo *info)
{
    if (trs_is_remote_sqcq_ops(info->type, info->value[SQCQ_CONFIG_INFO_FLAG])) {
        if (info->prop == DRV_SQCQ_PROP_SQCQ_RESET) {
            return true;
        }
        if ((info->sqId == UINT_MAX) && (info->cqId == UINT_MAX) &&
            ((info->prop == DRV_SQCQ_PROP_SQ_PAUSE) || (info->prop == DRV_SQCQ_PROP_SQ_RESUME))) {
            return true;
        }
    }
    return false;
}

static bool trs_is_support_sq_cq_ops(struct halSqCqConfigInfo *info)
{
#ifndef CFG_FEATURE_SQCQ_RESET
    if (info->prop == DRV_SQCQ_PROP_SQCQ_RESET) {
        return false;
    }
#else
    (void)info;
#endif
    return true;
}

drvError_t halSqCqConfig(uint32_t devId, struct halSqCqConfigInfo *info)
{
    if (info == NULL) {
        trs_err("Null ptr.\n");
        return DRV_ERROR_INVALID_VALUE;
    }

    if ((devId >= TRS_DEV_NUM) || (info->tsId >= TRS_TS_NUM)) {
        trs_err("Invalid para. (dev_id=%u; ts_id=%u)\n", devId, info->tsId);
        return DRV_ERROR_INVALID_VALUE;
    }

    if (!trs_is_support_sq_cq_ops(info)) {
        return DRV_ERROR_NOT_SUPPORT;
    }

    if (trs_is_remote_sq_cq_config(info)) {
        return trs_sq_cq_config_sync(devId, info);
    }
    info->value[SQCQ_CONFIG_INFO_FLAG] = 0;

    if (info->type == DRV_NORMAL_TYPE) {
        int connection_type = trs_get_connection_type(devId);
        drvError_t ret = 0;
        switch (connection_type) {
            case TRS_CONNECT_PROTOCOL_PCIE:
            case TRS_CONNECT_PROTOCOL_HCCS:
            case TRS_CONNECT_PROTOCOL_RC:
                return trs_sq_cq_config(devId, info);
            case TRS_CONNECT_PROTOCOL_UB:
                if ((info->prop == DRV_SQCQ_PROP_SQCQ_RESET) || (info->prop == DRV_SQCQ_PROP_SQ_PAUSE) ||
                    (info->prop == DRV_SQCQ_PROP_SQ_RESUME)) {
                    return trs_sq_cq_config(devId, info);
                }

                if ((info->prop == DRV_SQCQ_PROP_SQ_HEAD) || (info->prop == DRV_SQCQ_PROP_SQ_TAIL)) {
                    ret = trs_sq_cq_config(devId, info);
                }

                if (ret != 0) {
                    return ret;
                }

                return trs_sq_cq_config_sync(devId, info); /* UB scene: set sq register should complete remotely */
            default:
                trs_err("Invalid connection type. (dev_id=%u; connection_type=%d)\n", devId, connection_type);
                return DRV_ERROR_INVALID_DEVICE;
        }
    } else {
        return trs_sq_cq_config(devId, info);
    }
}

drvError_t halSqTaskArgsAsyncCopy(uint32_t devId, struct halSqTaskArgsInfo *info)
{
#ifndef EMU_ST
    struct sqcq_usr_info *sq_info = NULL;
    drvError_t ret;

    if (info == NULL) {
        trs_err("Null ptr.\n");
        return DRV_ERROR_INVALID_VALUE;
    }

    if ((devId >= TRS_DEV_NUM) || (info->tsId >= TRS_TS_NUM) ||
        (info->src == 0) || (info->dst == 0) || (info->size == 0) || (info->type != DRV_NORMAL_TYPE)) {
        trs_err("Invalid para. (dev_id=%u; ts_id=%u; src=0x%llx; dst=0x%llx; size=%u; type=%d)\n",
            devId, info->tsId, info->src, info->dst, info->size, info->type);
        return DRV_ERROR_INVALID_VALUE;
    }

    if (trs_get_connection_type(devId) != TRS_CONNECT_PROTOCOL_UB) {
        return DRV_ERROR_NOT_SUPPORT;
    }

    sq_info = trs_get_sq_info(devId, info->tsId, info->type, info->sqId);
    if (sq_info == NULL) {
        trs_err("Invalid para. (dev_id=%u; ts_id=%u; sq_id=%u)\n", devId, info->tsId, info->sqId);
        return DRV_ERROR_INVALID_VALUE;
    }

    ret = trs_sq_task_args_async_copy(devId, info, sq_info);
    if (ret != 0) {
        trs_warn_limit("Copy sq args warn. (devid=%u; sqid=%u)\n", devId, info->sqId);
        return ret;
    }
    return DRV_ERROR_NONE;
#endif
}

static drvError_t trs_async_para_check(uint32_t dev_id, struct halAsyncDmaInputPara *in,
    struct halAsyncDmaOutputPara *out)
{
    if ((in == NULL) || (out == NULL)) {
        trs_err("Invalid para.\n");
        return DRV_ERROR_INVALID_VALUE;
    }

    if ((dev_id >= TRS_DEV_NUM) || (in->tsId >= TRS_TS_NUM) || (in->src == NULL) || (in->len == 0) ||
        (in->type != DRV_NORMAL_TYPE)) {
        trs_err("Invalid para. (dev_id=%u; ts_id=%u; len=%u; type=%d)\n", dev_id, in->tsId, in->len, in->type);
        return DRV_ERROR_INVALID_VALUE;
    }

    if ((in->dir != TRS_ASYNC_HOST_TO_DEVICE) && (in->dir != TRS_ASYNC_DEVICE_TO_HOST) &&
        (in->dir != TRS_ASYNC_DEVICE_TO_DEVICE)) {
        return DRV_ERROR_NOT_SUPPORT;
    }

    if (in->async_dma_type >= DRV_ASYNC_DMA_TYPE_MAX) {
        return DRV_ERROR_NOT_SUPPORT;
    }

    return 0;
}

drvError_t halAsyncDmaCreate(uint32_t devId, struct halAsyncDmaInputPara *in, struct halAsyncDmaOutputPara *out)
{
    struct trs_async_dma_input_para input_para = {0};
    int connection_type;
    drvError_t ret;

    ret = trs_async_para_check(devId, in, out);
    if (ret != 0) {
        return ret;
    }

    connection_type = trs_get_connection_type(devId);
    switch (connection_type) {
        case TRS_CONNECT_PROTOCOL_PCIE:
            return trs_async_dma_desc_create(devId, in, out);
        case TRS_CONNECT_PROTOCOL_UB:
            input_para = trs_pack_async_dma_input_para(in, (enum trs_async_dma_type)in->async_dma_type, in->type,
                in->tsId, in->sqId);
            return trs_async_dma_wqe_create(devId, &input_para, out);
        default:
            return DRV_ERROR_NOT_SUPPORT;
    }
}

drvError_t halAsyncDmaWqeCreate(uint32_t devId, struct halAsyncDmaInputPara *in, struct halAsyncDmaOutputPara *out)
{
    return halAsyncDmaCreate(devId, in, out);
}

drvError_t halAsyncDmaDestory(uint32_t devId, struct halAsyncDmaDestoryPara *para)
{
    struct trs_async_dma_destroy_para destroy_para = {0};
    int connection_type;

    if (para == NULL) {
        trs_err("Invalid para.\n");
        return DRV_ERROR_INVALID_VALUE;
    }

    if (devId >= TRS_DEV_NUM || para->tsId >= TRS_TS_NUM) {
        trs_err("Invalid para. (dev_id=%u; ts_id=%u)\n", devId, para->tsId);
        return DRV_ERROR_INVALID_VALUE;
    }

    connection_type = trs_get_connection_type(devId);
    switch (connection_type) {
        case TRS_CONNECT_PROTOCOL_PCIE:
            return trs_async_dma_destory(devId, para);
        case TRS_CONNECT_PROTOCOL_UB:
            destroy_para = trs_pack_async_dma_destroy_para(para, TRS_ASYNC_DMA_TYPE_NORMAL, para->type, para->tsId, para->sqId);
            return trs_async_dma_wqe_destory(devId, &destroy_para);
        default:
            return DRV_ERROR_NOT_SUPPORT;
    }
}

drvError_t halAsyncDmaWqeDestory(uint32_t devId, struct halAsyncDmaDestoryPara *para)
{
    return halAsyncDmaDestory(devId, para);
}

#define TRS_2D_HEIGHT_MAX 2048ULL
static inline int trs_async_2d_para_check(uint32_t devId, struct halAsyncDmaInput2DPara *in,
    struct halAsyncDmaOutputPara *out)
{
    if ((in == NULL) || (out == NULL)) {
        trs_err("Invalid para.\n");
        return DRV_ERROR_INVALID_VALUE;
    }

    if ((devId >= TRS_DEV_NUM) || (in->tsId >= TRS_TS_NUM) || (in->type != DRV_NORMAL_TYPE)) {
        trs_err("Invalid para. (dev_id=%u; ts_id=%u; type=%d)\n", devId, in->tsId, in->type);
        return DRV_ERROR_INVALID_VALUE;
    }

    if ((in->src == NULL) || (in->dst == NULL) || (in->width == 0) || (in->height == 0) ||
        (in->dpitch < in->width) || (in->spitch < in->width) || (in->height > TRS_2D_HEIGHT_MAX)) {
        trs_err("Invalid para. (src_null=%d; dst_null=%d; width=%u; height=%u; dpitch=%d; spitch=%d)\n",
            (in->src == NULL), (in->dst == NULL), in->width, in->height, in->dpitch, in->spitch);
        return DRV_ERROR_INVALID_VALUE;
    }

    if (in->fixedSize != 0) {
        return DRV_ERROR_NOT_SUPPORT;
    }

    if ((in->height != 1) && (((uintptr_t)((char *)in->src + in->spitch) < (uintptr_t)in->src) ||
        ((uintptr_t)((char *)in->dst + in->dpitch) < (uintptr_t)in->dst))) {
        trs_err("Invalid para. (src=%p; dst=%p; spitch=%llu; dpitch=%llu)\n", in->src, in->dst, in->spitch, in->dpitch);
        return DRV_ERROR_INVALID_VALUE;
    }

    if ((in->dir != TRS_ASYNC_HOST_TO_DEVICE) && (in->dir != TRS_ASYNC_DEVICE_TO_HOST)) {
        return DRV_ERROR_NOT_SUPPORT;
    }

    return 0;
}

drvError_t halAsyncDmaCreate2D(uint32_t devId, struct halAsyncDmaInput2DPara *in, struct halAsyncDmaOutputPara *out)
{
    struct trs_async_dma_input_para input_para = {0};
    int connection_type;
    drvError_t ret = 0;

    ret = trs_async_2d_para_check(devId, in, out);
    if (ret != 0) {
        return ret;
    }

    connection_type = trs_get_connection_type(devId);
    switch (connection_type) {
        case TRS_CONNECT_PROTOCOL_PCIE:
            return DRV_ERROR_NOT_SUPPORT;
        case TRS_CONNECT_PROTOCOL_UB:
            input_para = trs_pack_async_dma_input_para(in, TRS_ASYNC_DMA_TYPE_2D, in->type, in->tsId, in->sqId);
            return trs_async_dma_wqe_create(devId, &input_para, out);
        default:
            return DRV_ERROR_NOT_SUPPORT;
    }

    return ret;
}

drvError_t halAsyncDmaDestroy2D(uint32_t devId, struct halAsyncDmaDestroy2DPara *para)
{
    struct trs_async_dma_destroy_para destroy_para = {0};
    int connection_type;

    if (para == NULL) {
        trs_err("Invalid para.\n");
        return DRV_ERROR_INVALID_VALUE;
    }

    if (devId >= TRS_DEV_NUM || para->tsId >= TRS_TS_NUM) {
        trs_err("Invalid para. (dev_id=%u; ts_id=%u)\n", devId, para->tsId);
        return DRV_ERROR_INVALID_VALUE;
    }

    connection_type = trs_get_connection_type(devId);
    switch (connection_type) {
        case TRS_CONNECT_PROTOCOL_PCIE:
            return DRV_ERROR_NOT_SUPPORT;
        case TRS_CONNECT_PROTOCOL_UB:
            destroy_para = trs_pack_async_dma_destroy_para(para, TRS_ASYNC_DMA_TYPE_2D, para->type, para->tsId, para->sqId);
            return trs_async_dma_wqe_destory(devId, &destroy_para);
        default:
            return DRV_ERROR_NOT_SUPPORT;
    }
}

#define TRS_CPY_BATCH_MAX_COUNT 2048ULL
static inline int trs_async_batch_para_check(uint32_t devId, struct halAsyncDmaInputBatchPara *in,
    struct halAsyncDmaOutputPara *out)
{
    if ((in == NULL) || (out == NULL)) {
        trs_err("Invalid para.\n");
        return DRV_ERROR_INVALID_VALUE;
    }

    if ((devId >= TRS_DEV_NUM) || (in->tsId >= TRS_TS_NUM) || (in->type != DRV_NORMAL_TYPE)) {
        trs_err("Invalid para. (dev_id=%u; ts_id=%u; type=%d)\n", devId, in->tsId, in->type);
        return DRV_ERROR_INVALID_VALUE;
    }

    if ((in->src == NULL) || (in->dst == NULL) || (in->len == NULL)) {
        trs_err("Invalid para. (src_is_null=%d; dst_is_null=%d; size_is_null=%d)\n",
            (in->src == NULL), (in->dst == NULL), (in->len == NULL));
        return DRV_ERROR_INVALID_VALUE;
    }

    if (in->fixedSize != 0) {
        return DRV_ERROR_NOT_SUPPORT;
    }

    if ((in->count == 0) || (in->count > TRS_CPY_BATCH_MAX_COUNT)) {
        trs_err("Invalid count. (count=%llu)\n", in->count);
        return DRV_ERROR_INVALID_VALUE;
    }

    if ((in->dir != TRS_ASYNC_HOST_TO_DEVICE) && (in->dir != TRS_ASYNC_DEVICE_TO_HOST)) {
        return DRV_ERROR_NOT_SUPPORT;
    }

    return 0;
}

drvError_t halAsyncDmaCreateBatch(uint32_t devId, struct halAsyncDmaInputBatchPara *in,
    struct halAsyncDmaOutputPara *out)
{
    struct trs_async_dma_input_para input_para = {0};
    int connection_type;
    drvError_t ret = 0;

    ret = trs_async_batch_para_check(devId, in, out);
    if (ret != 0) {
        return ret;
    }

    connection_type = trs_get_connection_type(devId);
    switch (connection_type) {
        case TRS_CONNECT_PROTOCOL_PCIE:
            return DRV_ERROR_NOT_SUPPORT;
        case TRS_CONNECT_PROTOCOL_UB:
            input_para = trs_pack_async_dma_input_para(in, TRS_ASYNC_DMA_TYPE_BATCH, in->type, in->tsId, in->sqId);
            return trs_async_dma_wqe_create(devId, &input_para, out);
        default:
            return DRV_ERROR_NOT_SUPPORT;
    }

    return ret;
}

drvError_t halAsyncDmaDestroyBatch(uint32_t devId, struct halAsyncDmaDestroyBatchPara *para)
{
    struct trs_async_dma_destroy_para destroy_para = {0};
    int connection_type;

    if (para == NULL) {
        trs_err("Invalid para.\n");
        return DRV_ERROR_INVALID_VALUE;
    }

    if (devId >= TRS_DEV_NUM || para->tsId >= TRS_TS_NUM) {
        trs_err("Invalid para. (dev_id=%u; ts_id=%u)\n", devId, para->tsId);
        return DRV_ERROR_INVALID_VALUE;
    }

    connection_type = trs_get_connection_type(devId);
    switch (connection_type) {
        case TRS_CONNECT_PROTOCOL_PCIE:
            return DRV_ERROR_NOT_SUPPORT;
        case TRS_CONNECT_PROTOCOL_UB:
            destroy_para = trs_pack_async_dma_destroy_para(para, TRS_ASYNC_DMA_TYPE_BATCH, para->type, para->tsId, para->sqId);
            return trs_async_dma_wqe_destory(devId, &destroy_para);
        default:
            return DRV_ERROR_NOT_SUPPORT;
    }
}

drvError_t halSqTaskSend(uint32_t devId, struct halTaskSendInfo *info)
{
    struct sqcq_usr_info *sq_info = NULL;
    int ret = 0;

    if (info == NULL) {
        trs_err("Null ptr.\n");
        return DRV_ERROR_INVALID_VALUE;
    }

    if ((devId >= TRS_DEV_NUM) || (info->tsId >= TRS_TS_NUM)) {
        trs_err("Invalid para. (dev_id=%u; ts_id=%u)\n", devId, info->tsId);
        return DRV_ERROR_INVALID_VALUE;
    }

    sq_info = trs_get_sq_info(devId, info->tsId, info->type, info->sqId);
    if (sq_info == NULL) {
        trs_err("Invalid para. (dev_id=%u; ts_id=%u; type=%d; sq_id=%u)\n", devId, info->tsId, info->type, info->sqId);
        return DRV_ERROR_INVALID_VALUE;
    }

    if ((!trs_is_sq_support_send(sq_info)) || (trs_is_sq_init_without_sq_mem(sq_info->flag))) {
        trs_warn("Sq is only id type, not support task send. (dev_id=%u; ts_id=%u; sq_id=%u; flag=%u)\n",
            devId, info->tsId, info->sqId, sq_info->flag);
        return DRV_ERROR_NOT_SUPPORT;
    }

    if (info->type == DRV_NORMAL_TYPE) {
        int connection_type = trs_get_connection_type(devId);
        switch (connection_type) {
            case TRS_CONNECT_PROTOCOL_PCIE:
            case TRS_CONNECT_PROTOCOL_HCCS:
            case TRS_CONNECT_PROTOCOL_RC:
                ret = trs_sq_task_send(devId, info, sq_info);
                break;
            case TRS_CONNECT_PROTOCOL_UB:
                ret = trs_sq_task_send_urma(devId, info, sq_info);
                break;
            default:
                trs_err("Invalid connection type. (dev_id=%u; connection_type=%d)\n", devId, connection_type);
                return DRV_ERROR_INVALID_DEVICE;
        }
    } else {
        ret = trs_sq_task_send(devId, info, sq_info);
    }

    return ret;
}

drvError_t halGetTsegInfoByVa(uint32_t devid, uint64_t va, uint64_t size, uint32_t flag,
    struct halTsegInfo *tsegInfo)
{
    int connection_type;

    if (devid >= TRS_DEV_NUM) {
        trs_err("Invalid para. (dev_id=%u)\n", devid);
        return DRV_ERROR_INVALID_VALUE;
    }

    if (tsegInfo == NULL) {
        trs_err("Invalid NULL tsegInfo. (devid=%u)\n", devid);
        return DRV_ERROR_INVALID_VALUE;
    }

    connection_type = trs_get_connection_type(devid);
    switch (connection_type) {
        case TRS_CONNECT_PROTOCOL_PCIE:
            return DRV_ERROR_NOT_SUPPORT;
        case TRS_CONNECT_PROTOCOL_UB:
            return trs_get_urma_tseg_info_by_va(devid, va, size, flag, tsegInfo);
        default:
            return DRV_ERROR_NOT_SUPPORT;
    }

    return 0;
}

drvError_t halPutTsegInfo(uint32_t devid, struct halTsegInfo *tsegInfo)
{
    int connection_type;

    if (devid >= TRS_DEV_NUM) {
        trs_err("Invalid para. (dev_id=%u)\n", devid);
        return DRV_ERROR_INVALID_VALUE;
    }

    if (tsegInfo == NULL) {
        trs_err("Invalid NULL tsegInfo. (devid=%u)\n", devid);
        return DRV_ERROR_INVALID_VALUE;
    }

    connection_type = trs_get_connection_type(devid);
    switch (connection_type) {
        case TRS_CONNECT_PROTOCOL_PCIE:
            return DRV_ERROR_NOT_SUPPORT;
        case TRS_CONNECT_PROTOCOL_UB:
            return trs_put_urma_tseg_info(devid, tsegInfo);
        default:
            return DRV_ERROR_NOT_SUPPORT;
    }

    return 0;
}