/****************************************************************************
 *
 *   SPDX-License-Identifier: BSD-3-Clause
 *   Copyright(c) 2007-2026 Intel Corporation
 * 
 *   These contents may have been developed with support from one or more
 *   Intel-operated generative artificial intelligence solutions.
 *
 ***************************************************************************/

/**
 *****************************************************************************
 * @file dc_dp.c
 *
 * @defgroup cpaDcDp Data Compression Data Plane API
 *
 * @ingroup cpaDcDp
 *
 * @description
 *      Implementation of the Data Compression DP operations.
 *
 *****************************************************************************/

/*
*******************************************************************************
* Include public/global header files
*******************************************************************************
*/
#include "cpa.h"
#include "cpa_dc.h"
#include "cpa_dc_dp.h"

#include "icp_qat_fw_comp.h"

/*
*******************************************************************************
* Include private header files
*******************************************************************************
*/
#include "dc_session.h"
#include "dc_datapath.h"
#include "dc_capabilities.h"
#include "dc_ns_datapath.h"
#include "lac_common.h"
#include "lac_mem.h"
#include "lac_mem_pools.h"
#include "lac_log.h"
#include "sal_types_compression.h"
#include "lac_sal.h"
#include "lac_sync.h"
#include "sal_service_state.h"
#include "sal_qat_cmn_msg.h"
#include "icp_sal_poll.h"

#ifdef ICP_PARAM_CHECK
/**
 *****************************************************************************
 * @ingroup cpaDcDp
 *      Check that pOpData is valid
 *
 * @description
 *      Check that all the parameters defined in the pOpData are valid
 *
 * @param[in]       pOpData          Pointer to a structure containing the
 *                                   request parameters
 *
 * @retval CPA_STATUS_SUCCESS        Function executed successfully
 * @retval CPA_STATUS_INVALID_PARAM  Invalid parameter passed in
 *
 *****************************************************************************/
STATIC CpaStatus dcDataPlaneParamCheck(const CpaDcDpOpData *pOpData)
{
    sal_compression_service_t *pService = NULL;
    dc_session_desc_t *pSessionDesc = NULL;
    CpaDcSessionDir sessDirection;
    CpaDcHuffType huffType;
    dc_capabilities_t *pDcCapabilities = NULL;
    Cpa16U numInterBuffs = 0;

    LAC_CHECK_NULL_PARAM(pOpData);
    LAC_CHECK_NULL_PARAM(pOpData->dcInstance);

    /* Ensure this is a compression or a decompression instance */
    SAL_CHECK_INSTANCE_TYPE(
        pOpData->dcInstance,
        (SAL_SERVICE_TYPE_COMPRESSION | SAL_SERVICE_TYPE_DECOMPRESSION));

    pService = (sal_compression_service_t *)(pOpData->dcInstance);

    /* Retrieve capabilities */
    pDcCapabilities = &pService->dc_capabilities;
    numInterBuffs = pDcCapabilities->numInterBuffs;

    /* Allow either only session or only NS setup data. One of these objects
     * must be present, and the other must be NULL. */
    if (!pOpData->pSessionHandle == !pOpData->pSetupData)
    {
        LAC_INVALID_PARAM_LOG("Application must select either a session or NS "
                              "setup data");
        return CPA_STATUS_INVALID_PARAM;
    }

    if (pOpData->pSessionHandle)
    {
        pSessionDesc = DC_SESSION_DESC_FROM_CTX_GET(pOpData->pSessionHandle);
        if (NULL == pSessionDesc)
        {
            LAC_INVALID_PARAM_LOG("Session handle not as expected");
            return CPA_STATUS_INVALID_PARAM;
        }

        if (CPA_FALSE == pSessionDesc->isDcDp)
        {
            LAC_INVALID_PARAM_LOG("The session type should be data plane");
            return CPA_STATUS_INVALID_PARAM;
        }

        sessDirection = pSessionDesc->sessDirection;
        huffType = pSessionDesc->huffType;
    }
    else
    {
        /* Stateful is not supported */
        if (CPA_DC_STATELESS != pOpData->pSetupData->sessState)
        {
            LAC_INVALID_PARAM_LOG("Invalid sessState value");
            return CPA_STATUS_INVALID_PARAM;
        }

        if (CPA_STATUS_SUCCESS !=
            dcCheckSessionData(pOpData->pSetupData, pOpData->dcInstance))
        {
            return CPA_STATUS_INVALID_PARAM;
        }

        sessDirection = pOpData->pSetupData->sessDirection;
        huffType = pOpData->pSetupData->huffType;

        if (CPA_DC_DIR_DECOMPRESS < sessDirection)
        {
            LAC_INVALID_PARAM_LOG("Invalid direction of operation");
            return CPA_STATUS_INVALID_PARAM;
        }
    }

    /* Compressing zero byte is not supported */
    if ((CPA_DC_DIR_COMPRESS == sessDirection) &&
        (0 == pOpData->bufferLenToCompress))
    {
        LAC_INVALID_PARAM_LOG("The source buffer length to compress needs to "
                              "be greater than zero byte");
        return CPA_STATUS_INVALID_PARAM;
    }

    if (pOpData->sessDirection > CPA_DC_DIR_DECOMPRESS)
    {
        LAC_INVALID_PARAM_LOG("Invalid direction of operation");
        return CPA_STATUS_INVALID_PARAM;
    }

    if (0 == pOpData->srcBuffer)
    {
        LAC_INVALID_PARAM_LOG("Invalid srcBuffer");
        return CPA_STATUS_INVALID_PARAM;
    }
    if (0 == pOpData->destBuffer)
    {
        LAC_INVALID_PARAM_LOG("Invalid destBuffer");
        return CPA_STATUS_INVALID_PARAM;
    }
    if (pOpData->srcBuffer == pOpData->destBuffer)
    {
        LAC_INVALID_PARAM_LOG("In place operation is not supported");
        return CPA_STATUS_INVALID_PARAM;
    }
    if (0 == pOpData->thisPhys)
    {
        LAC_INVALID_PARAM_LOG("Invalid thisPhys");
        return CPA_STATUS_INVALID_PARAM;
    }
    if (CPA_FALSE == pDcCapabilities->cnv.supported)
    {
        LAC_UNSUPPORTED_PARAM_LOG("CNV Strict mode set, no CnV capability");
        return CPA_STATUS_UNSUPPORTED;
    }
    if ((CPA_FALSE == pDcCapabilities->cnv.supported) &&
        (CPA_TRUE == pOpData->compressAndVerify))
    {
        LAC_UNSUPPORTED_PARAM_LOG(
            "CompressAndVerify not set, no CNV capability");
        return CPA_STATUS_UNSUPPORTED;
    }
    if ((CPA_TRUE == pDcCapabilities->cnv.supported) &&
        (CPA_TRUE == pDcCapabilities->cnv.recovery))
    {
        if ((CPA_TRUE == pOpData->compressAndVerifyAndRecover) &&
            (CPA_FALSE == pOpData->compressAndVerify))
        {
            LAC_INVALID_PARAM_LOG("CnVnR option set, without setting CnV");
            return CPA_STATUS_INVALID_PARAM;
        }
    }
    if (CPA_TRUE == pDcCapabilities->cnv.supported)
    {
        if ((CPA_FALSE == pDcCapabilities->cnv.recovery) &&
            (CPA_TRUE == pOpData->compressAndVerifyAndRecover))
        {
            LAC_UNSUPPORTED_PARAM_LOG("CnVnR not set, no CnVnR capability");
            return CPA_STATUS_UNSUPPORTED;
        }
    }
    if ((CPA_DP_BUFLIST == pOpData->srcBufferLen) &&
        (CPA_DP_BUFLIST != pOpData->destBufferLen))
    {
        LAC_INVALID_PARAM_LOG(
            "The source and destination buffers need to be "
            "of the same type (both flat buffers or buffer lists)");
        return CPA_STATUS_INVALID_PARAM;
    }
    if ((CPA_DP_BUFLIST != pOpData->srcBufferLen) &&
        (CPA_DP_BUFLIST == pOpData->destBufferLen))
    {
        LAC_INVALID_PARAM_LOG(
            "The source and destination buffers need to be "
            "of the same type (both flat buffers or buffer lists)");
        return CPA_STATUS_INVALID_PARAM;
    }

    if (CPA_DP_BUFLIST != pOpData->srcBufferLen)
    {
        if (pOpData->srcBufferLen < pOpData->bufferLenToCompress)
        {
            LAC_INVALID_PARAM_LOG("srcBufferLen is smaller than "
                                  "bufferLenToCompress");
            return CPA_STATUS_INVALID_PARAM;
        }

        if (pOpData->destBufferLen < pOpData->bufferLenForData)
        {
            LAC_INVALID_PARAM_LOG("destBufferLen is smaller than "
                                  "bufferLenForData");
            return CPA_STATUS_INVALID_PARAM;
        }
    }
    else
    {
        /* We are assuming that there is enough memory in the source and
         * destination buffer lists. We only receive physical addresses of the
         * buffers so we are unable to test it here */
        LAC_CHECK_8_BYTE_ALIGNMENT(pOpData->srcBuffer);
        LAC_CHECK_8_BYTE_ALIGNMENT(pOpData->destBuffer);
    }

    LAC_CHECK_8_BYTE_ALIGNMENT(pOpData->thisPhys);

    if ((CPA_DC_DIR_COMPRESS == sessDirection) ||
        (CPA_DC_DIR_COMBINED == sessDirection))
    {
#ifndef ICP_DC_DYN_NOT_SUPPORTED
        if (CPA_DC_HT_FULL_DYNAMIC == huffType)
        {
            /* Check if Intermediate Buffer Array pointer is NULL */
            if ((numInterBuffs > 0) &&
                ((0 == pService->pInterBuffPtrsArrayPhyAddr) ||
                 (NULL == pService->pInterBuffPtrsArray)))
            {
                LAC_LOG_ERROR(
                    "No intermediate buffer defined for this instance "
                    "- see cpaDcStartInstance");
                return CPA_STATUS_INVALID_PARAM;
            }

            /* Ensure that the destination buffer length for data is greater
             * or equal to minOutputBuffSizeDynamic */
            if (pOpData->bufferLenForData <
                pDcCapabilities->deviceData.minOutputBuffSizeDynamic)
            {
                LAC_INVALID_PARAM_LOG1(
                    "Destination buffer length for data "
                    "should be greater or equal to %d",
                    pDcCapabilities->deviceData.minOutputBuffSizeDynamic);
                return CPA_STATUS_INVALID_PARAM;
            }
        }
        else
#else
        if (CPA_DC_HT_FULL_DYNAMIC == huffType)
        {
            LAC_INVALID_PARAM_LOG("Invalid huffType value, dynamic compression "
                                  "not supported");
            return CPA_STATUS_INVALID_PARAM;
        }
        else
#endif
        {
            /* Ensure that the destination buffer length for data is greater
             * or equal to minimal output buffer size */
            if (pOpData->bufferLenForData <
                pDcCapabilities->deviceData.minOutputBuffSize)
            {
                LAC_INVALID_PARAM_LOG1(
                    "Destination buffer size should be "
                    "greater or equal to %d bytes",
                    pDcCapabilities->deviceData.minOutputBuffSize);
                return CPA_STATUS_INVALID_PARAM;
            }
        }
    }

    return CPA_STATUS_SUCCESS;
}
#endif

CpaStatus cpaDcDpGetSessionSize(CpaInstanceHandle dcInstance,
                                CpaDcSessionSetupData *pSessionData,
                                Cpa32U *pSessionSize)
{
    CpaStatus status = CPA_STATUS_SUCCESS;
#ifdef ICP_PARAM_CHECK
    LAC_CHECK_NULL_PARAM(pSessionSize);
#endif
    status = dcGetSessionSize(dcInstance, pSessionData, pSessionSize, NULL);
#ifdef ICP_TRACE
    LAC_LOG4("Called with params (0x%lx, 0x%lx, 0x%lx[%d])\n",
             (LAC_ARCH_UINT)dcInstance,
             (LAC_ARCH_UINT)pSessionData,
             (LAC_ARCH_UINT)pSessionSize,
             *pSessionSize);
#endif
    return status;
}

CpaStatus cpaDcDpInitSession(CpaInstanceHandle dcInstance,
                             CpaDcSessionHandle pSessionHandle,
                             CpaDcSessionSetupData *pSessionData)
{
    CpaStatus status = CPA_STATUS_SUCCESS;
    dc_session_desc_t *pSessionDesc = NULL;
    sal_compression_service_t *pService = NULL;

#ifdef ICP_TRACE
    LAC_LOG3("Called with params (0x%lx, 0x%lx, 0x%lx)\n",
             (LAC_ARCH_UINT)dcInstance,
             (LAC_ARCH_UINT)pSessionHandle,
             (LAC_ARCH_UINT)pSessionData);
#endif

#ifdef ICP_PARAM_CHECK
    LAC_CHECK_INSTANCE_HANDLE(dcInstance);
    SAL_CHECK_ADDR_TRANS_SETUP(dcInstance);
    /* Ensure this is a compression or a decompression instance */
    SAL_CHECK_INSTANCE_TYPE(
        dcInstance,
        (SAL_SERVICE_TYPE_COMPRESSION | SAL_SERVICE_TYPE_DECOMPRESSION));
#endif

    pService = (sal_compression_service_t *)dcInstance;

    /* Check if SAL is initialised otherwise return an error */
    SAL_RUNNING_CHECK(pService);

#ifdef ICP_PARAM_CHECK
    /* Stateful is not supported */
    if (CPA_DC_STATELESS != pSessionData->sessState)
    {
        LAC_INVALID_PARAM_LOG("Invalid sessState value");
        return CPA_STATUS_INVALID_PARAM;
    }
#endif

    status =
        dcInitSession(dcInstance, pSessionHandle, pSessionData, NULL, NULL);
    if (CPA_STATUS_SUCCESS == status)
    {
        pSessionDesc = DC_SESSION_DESC_FROM_CTX_GET(pSessionHandle);
        LAC_CHECK_NULL_PARAM(pSessionDesc);
        pSessionDesc->isDcDp = CPA_TRUE;

        ICP_QAT_FW_COMN_PTR_TYPE_SET(
            pSessionDesc->reqCacheDecomp.comn_hdr.comn_req_flags,
            DC_DP_QAT_PTR_TYPE);
        ICP_QAT_FW_COMN_PTR_TYPE_SET(
            pSessionDesc->reqCacheComp.comn_hdr.comn_req_flags,
            DC_DP_QAT_PTR_TYPE);
    }

    return status;
}

CpaStatus cpaDcDpRemoveSession(const CpaInstanceHandle dcInstance,
                               CpaDcSessionHandle pSessionHandle)
{
#ifdef ICP_TRACE
    LAC_LOG2("Called with params (0x%lx, 0x%lx)\n",
             (LAC_ARCH_UINT)dcInstance,
             (LAC_ARCH_UINT)pSessionHandle);
#endif
    return cpaDcRemoveSession(dcInstance, pSessionHandle);
}

CpaStatus cpaDcDpUpdateSession(const CpaInstanceHandle dcInstance,
                               CpaDcSessionHandle pSessionHandle,
                               CpaDcSessionUpdateData *pUpdateSessionData)
{
    return cpaDcUpdateSession(dcInstance, pSessionHandle, pUpdateSessionData);
}

CpaStatus cpaDcDpRegCbFunc(const CpaInstanceHandle dcInstance,
                           const CpaDcDpCallbackFn pNewCb)
{
    sal_compression_service_t *pService = NULL;

#ifdef ICP_TRACE
    LAC_LOG2("Called with params (0x%lx, 0x%lx)\n",
             (LAC_ARCH_UINT)dcInstance,
             (LAC_ARCH_UINT)pNewCb);
#endif

/* Check parameters */
#ifdef ICP_PARAM_CHECK
    LAC_CHECK_NULL_PARAM(dcInstance);
    /* Ensure this is a compression or a decompression instance */
    SAL_CHECK_INSTANCE_TYPE(
        dcInstance,
        (SAL_SERVICE_TYPE_COMPRESSION | SAL_SERVICE_TYPE_DECOMPRESSION));
    LAC_CHECK_NULL_PARAM(pNewCb);
#endif

    /* Check if SAL is initialised otherwise return an error */
    SAL_RUNNING_CHECK(dcInstance);

    pService = (sal_compression_service_t *)dcInstance;
    pService->pDcDpCb = pNewCb;

    return CPA_STATUS_SUCCESS;
}

/**
 *****************************************************************************
 * @ingroup cpaDcDp
 *
 * @description
 *      Writes the message to the ring
 *
 * @param[in]       pOpData          Pointer to a structure containing the
 *                                   request parameters
 * @param[in]       pCurrentQatMsg   Pointer to current QAT message on the ring
 * @param[in]       pNsRefQatMsg     Pointer to QAT NS reference message on the
 *                                   ring
 *
 * @retval CPA_STATUS_SUCCESS        Function executed successfully
 * @retval CPA_STATUS_UNSUPPORTED    Unsupported algorithm/feature
 *****************************************************************************/
STATIC CpaStatus dcDpWriteRingMsg(CpaDcDpOpData *pOpData,
                                  icp_qat_fw_comp_req_t *pCurrentQatMsg,
                                  icp_qat_fw_comp_req_t *pNsRefQatMsg)
{
    icp_qat_fw_comp_req_t *pReqCache = NULL;
    dc_session_desc_t *pSessionDesc = NULL;
    Cpa8U bufferFormat;
    Cpa8U cnv = ICP_QAT_FW_COMP_NO_CNV;
    Cpa8U cnvnr = ICP_QAT_FW_COMP_NO_CNV_RECOVERY;
    CpaBoolean cnvErrorInjection = ICP_QAT_FW_COMP_NO_CNV_DFX;
    sal_compression_service_t *pService = NULL;
    CpaStatus status;
    dc_capabilities_t *pDcCapabilities = NULL;
    CpaBoolean asbSupported = CPA_FALSE;
    CpaBoolean asbRatioSupported = CPA_FALSE;
    CpaBoolean asbThresholdSupported = CPA_FALSE;
    Cpa32U asbRegValue = 0;

    pService = (sal_compression_service_t *)(pOpData->dcInstance);

    if (pOpData->pSessionHandle)
    {
        pSessionDesc = DC_SESSION_DESC_FROM_CTX_GET(pOpData->pSessionHandle);

        if (CPA_DC_DIR_COMPRESS == pOpData->sessDirection)
        {
            pReqCache = &(pSessionDesc->reqCacheComp);
        }
        else
        {
            pReqCache = &(pSessionDesc->reqCacheDecomp);
        }

        /* Fills in the template DC ET ring message - cached from the
         * session descriptor */
        osalMemCopy((void *)pCurrentQatMsg,
                    (void *)(pReqCache),
                    (LAC_QAT_DC_REQ_SZ_LW * LAC_LONG_WORD_IN_BYTES));
    }
    else
    {
        if (pNsRefQatMsg)
        {
            /* Fills in the template DC ET ring message - cached from the
             * first request in the batch */
            osalMemCopy((void *)pCurrentQatMsg,
                        (void *)pNsRefQatMsg,
                        (LAC_QAT_DC_REQ_SZ_LW * LAC_LONG_WORD_IN_BYTES));
        }
        else
        {
            status = dcNsCreateBaseRequest(
                pCurrentQatMsg, pService, pOpData->pSetupData);

            if (CPA_STATUS_SUCCESS != status)
            {
                return status;
            }

            ICP_QAT_FW_COMN_PTR_TYPE_SET(
                pCurrentQatMsg->comn_hdr.comn_req_flags, DC_DP_QAT_PTR_TYPE);
        }
    }

    /* Retrieve capabilities */
    pDcCapabilities = &pService->dc_capabilities;
    asbSupported = pDcCapabilities->asb.supported;
    asbRatioSupported = pDcCapabilities->asb.asbRatioSupported;
    asbThresholdSupported = pDcCapabilities->asb.asbTshSupported;

    if (CPA_DC_DIR_COMPRESS == pOpData->sessDirection)
    {
        /* CNV check */
        if (CPA_TRUE == pOpData->compressAndVerify)
        {
            cnv = ICP_QAT_FW_COMP_CNV;
            if (CPA_TRUE == pDcCapabilities->cnv.errorInjection)
            {
                if (pOpData->pSessionHandle)
                {
                    cnvErrorInjection = pSessionDesc->cnvErrorInjection;
                }
                else
                {
                    cnvErrorInjection =
                        pService->generic_service_info.ns_isCnvErrorInjection;
                }
            }

            /* CNVNR check */
            if (CPA_TRUE == pOpData->compressAndVerifyAndRecover)
            {
                cnvnr = ICP_QAT_FW_COMP_CNV_RECOVERY;
            }
        }
    }

    if (CPA_DP_BUFLIST == pOpData->srcBufferLen)
    {
        bufferFormat = QAT_COMN_PTR_TYPE_SGL;
    }
    else
    {
        bufferFormat = QAT_COMN_PTR_TYPE_FLAT;
    }

    pCurrentQatMsg->comp_pars.req_par_flags =
        ICP_QAT_FW_COMP_REQ_PARAM_FLAGS_BUILD(
            ICP_QAT_FW_COMP_SOP,
            ICP_QAT_FW_COMP_EOP,
            ICP_QAT_FW_COMP_BFINAL,
            cnv,
            cnvnr,
            cnvErrorInjection,
            ICP_QAT_FW_COMP_CRC_MODE_LEGACY,
            ICP_QAT_FW_COMP_NO_XXHASH_ACC,
            ICP_QAT_FW_COMP_CNV_ERROR_NONE,
            ICP_QAT_FW_COMP_NO_APPEND_CRC,
            ICP_QAT_FW_COMP_NO_DROP_DATA,
            ICP_QAT_FW_COMP_NO_PARTIAL_DECOMPRESS);

    if ((asbSupported) && (asbRatioSupported || asbThresholdSupported))
    {
        /* Check if ASB is enabled */
        if (ICP_QAT_FW_COMP_AUTO_SELECT_BEST_GET(
                pCurrentQatMsg->comn_hdr.serv_specif_flags))
        {
            if (pOpData->pSessionHandle)
            {
                asbRegValue = dcCalcAsbRegValue(pOpData->bufferLenToCompress,
                                                pSessionDesc->asb_mode,
                                                pSessionDesc->asb_value);

                /* Capping asb value to asb max block size */
                if (asbRegValue > pSessionDesc->asb_max_block_size)
                    asbRegValue = pSessionDesc->asb_max_block_size;
            }
            else
            {
                asbRegValue = dcCalcAsbRegValue(
                    pOpData->bufferLenToCompress, DC_ASB_RATIO_MODE, 1);

                /* Capping asb value to asb max block size */
                if (asbRegValue > DC_ASB_MAX_BLOCK_SIZE)
                    asbRegValue = DC_ASB_MAX_BLOCK_SIZE;
            }
            pCurrentQatMsg->u3.asb_threshold.asb_value = asbRegValue;
        }
    }

    SalQatMsg_CmnMidWrite((icp_qat_fw_la_bulk_req_t *)pCurrentQatMsg,
                          pOpData,
                          bufferFormat,
                          pOpData->srcBuffer,
                          pOpData->destBuffer,
                          pOpData->srcBufferLen,
                          pOpData->destBufferLen);

    pCurrentQatMsg->comp_pars.comp_len = pOpData->bufferLenToCompress;
    pCurrentQatMsg->comp_pars.out_buffer_sz = pOpData->bufferLenForData;

    return CPA_STATUS_SUCCESS;
}

CpaStatus cpaDcDpEnqueueOp(CpaDcDpOpData *pOpData,
                           const CpaBoolean performOpNow)
{
    icp_qat_fw_comp_req_t *pCurrentQatMsg = NULL;
    icp_comms_trans_handle trans_handle = NULL;
    dc_session_desc_t *pSessionDesc = NULL;
    sal_compression_service_t *pService = NULL;
    CpaStatus status = CPA_STATUS_SUCCESS;
#ifdef ICP_DC_DYN_NOT_SUPPORTED
    CpaDcHuffType huffType;
#endif
#ifdef ICP_PARAM_CHECK
    CpaDcSessionDir sessDirection;

    status = dcDataPlaneParamCheck(pOpData);
    if (CPA_STATUS_SUCCESS != status)
    {
        return status;
    }
#endif

    if ((CPA_FALSE == pOpData->compressAndVerify) &&
        (CPA_DC_DIR_COMPRESS == pOpData->sessDirection))
    {
        return CPA_STATUS_UNSUPPORTED;
    }

#ifdef ICP_TRACE
    LAC_LOG2("Called with params (0x%lx, %d)\n",
             (LAC_ARCH_UINT)pOpData,
             performOpNow);
#endif

    /* Check if SAL is initialised otherwise return an error */
    SAL_RUNNING_CHECK(pOpData->dcInstance);

    pService = (sal_compression_service_t *)(pOpData->dcInstance);

    if (pService->generic_service_info.type == SAL_SERVICE_TYPE_COMPRESSION)
    {
        trans_handle = ((sal_compression_service_t *)pOpData->dcInstance)
                           ->trans_handle_compression_tx;
    }
    else
    {
        trans_handle = ((sal_compression_service_t *)pOpData->dcInstance)
                           ->trans_handle_decompression_tx;
    }

    if (pOpData->pSessionHandle)
    {
        pSessionDesc = DC_SESSION_DESC_FROM_CTX_GET(pOpData->pSessionHandle);

#ifdef ICP_PARAM_CHECK
        sessDirection = pSessionDesc->sessDirection;
#endif
#ifdef ICP_DC_DYN_NOT_SUPPORTED
        huffType = pSessionDesc->huffType;
#endif
    }
    else
    {
#ifdef ICP_PARAM_CHECK
        sessDirection = pOpData->pSetupData->sessDirection;
#endif
#ifdef ICP_DC_DYN_NOT_SUPPORTED
        huffType = pOpData->pSetupData->huffType;
#endif
    }

#ifdef ICP_PARAM_CHECK
    if ((CPA_DC_DIR_COMPRESS == pOpData->sessDirection) &&
        (CPA_DC_DIR_DECOMPRESS == sessDirection))
    {
        LAC_INVALID_PARAM_LOG("(a) The session or (b) the NS setup data does "
                              "not support this direction of operation");
        return CPA_STATUS_INVALID_PARAM;
    }
    else if ((CPA_DC_DIR_DECOMPRESS == pOpData->sessDirection) &&
             (CPA_DC_DIR_COMPRESS == sessDirection))
    {
        LAC_INVALID_PARAM_LOG("(a) The session or (b) the NS setup data does "
                              "not support this direction of operation");
        return CPA_STATUS_INVALID_PARAM;
    }
#endif

#ifdef ICP_DC_DYN_NOT_SUPPORTED
    if (CPA_DC_HT_FULL_DYNAMIC == huffType)
    {
        LAC_INVALID_PARAM_LOG("Invalid huffType value, dynamic compression "
                              "not supported");
        return CPA_STATUS_INVALID_PARAM;
    }
#endif

    icp_adf_getSingleQueueAddr(trans_handle, (void **)&pCurrentQatMsg);
    if (NULL == pCurrentQatMsg)
    {
        return CPA_STATUS_RETRY;
    }

    status = dcDpWriteRingMsg(pOpData, pCurrentQatMsg, NULL);

    if (CPA_STATUS_SUCCESS != status)
    {
        return status;
    }

    if (pOpData->pSessionHandle)
    {
        pSessionDesc->pendingDpStatelessCbCount++;
    }

    if (CPA_TRUE == performOpNow)
    {
        status = icp_adf_updateQueueTail(trans_handle);
        if (CPA_STATUS_SUCCESS != status)
        {
            if (pOpData->pSessionHandle)
            {
                pSessionDesc->pendingDpStatelessCbCount--;
            }
            return status;
        }
    }

    return CPA_STATUS_SUCCESS;
}

CpaStatus cpaDcDpEnqueueOpBatch(const Cpa32U numberRequests,
                                CpaDcDpOpData *pOpData[],
                                const CpaBoolean performOpNow)
{
    icp_qat_fw_comp_req_t *pCurrentQatMsg = NULL;
    icp_qat_fw_comp_req_t *pNsRefQatMsg = NULL;
    icp_comms_trans_handle trans_handle = NULL;
    dc_session_desc_t *pSessionDesc = NULL;
    CpaStatus status = CPA_STATUS_SUCCESS;
    Cpa32U i = 0;
    sal_compression_service_t *pService = NULL;
#ifdef ICP_DC_DYN_NOT_SUPPORTED
    CpaDcHuffType huffType;
#endif
#ifdef ICP_PARAM_CHECK
    CpaDcSessionDir sessDirection;

    LAC_CHECK_NULL_PARAM(pOpData);
    LAC_CHECK_NULL_PARAM(pOpData[0]);
    LAC_CHECK_NULL_PARAM(pOpData[0]->dcInstance);
#endif

    pService = (sal_compression_service_t *)(pOpData[0]->dcInstance);

#ifdef ICP_PARAM_CHECK
    if ((numberRequests == 0) ||
        (numberRequests > pService->maxNumCompConcurrentReq))
    {
        LAC_INVALID_PARAM_LOG1("The number of requests needs to be between 1 "
                               "and %d",
                               pService->maxNumCompConcurrentReq);
        return CPA_STATUS_INVALID_PARAM;
    }

    for (i = 0; i < numberRequests; i++)
    {
        status = dcDataPlaneParamCheck(pOpData[i]);
        if (CPA_STATUS_SUCCESS != status)
        {
            return status;
        }

        /* Check that all instance handles and session handles are the same */
        if (pOpData[i]->dcInstance != pOpData[0]->dcInstance)
        {
            LAC_INVALID_PARAM_LOG("All instance handles should be the same "
                                  "in the pOpData");
            return CPA_STATUS_INVALID_PARAM;
        }

        if (pOpData[0]->pSessionHandle)
        {
            if (pOpData[i]->pSessionHandle != pOpData[0]->pSessionHandle)
            {
                LAC_INVALID_PARAM_LOG("All session handles should be the same "
                                      "in the pOpData");
                return CPA_STATUS_INVALID_PARAM;
            }
        }
        else
        {
            if (pOpData[i]->pSetupData != pOpData[0]->pSetupData)
            {
                LAC_INVALID_PARAM_LOG("All NS setup data should be the same "
                                      "in the pOpData");
                return CPA_STATUS_INVALID_PARAM;
            }
        }
    }
#endif

#ifdef ICP_TRACE
    LAC_LOG3("Called with params (%d, 0x%lx, %d)\n",
             numberRequests,
             (LAC_ARCH_UINT)pOpData,
             performOpNow);
#endif

    for (i = 0; i < numberRequests; i++)
    {
        if ((CPA_FALSE == pOpData[i]->compressAndVerify) &&
            (CPA_DC_DIR_COMPRESS == pOpData[i]->sessDirection))
        {
            return CPA_STATUS_UNSUPPORTED;
        }
    }

    /* Check if SAL is initialised otherwise return an error */
    SAL_RUNNING_CHECK(pOpData[0]->dcInstance);

    if (pService->generic_service_info.type == SAL_SERVICE_TYPE_COMPRESSION)
    {
        trans_handle = ((sal_compression_service_t *)pOpData[0]->dcInstance)
                           ->trans_handle_compression_tx;
    }
    else
    {
        trans_handle = ((sal_compression_service_t *)pOpData[0]->dcInstance)
                           ->trans_handle_decompression_tx;
    }

    if (pOpData[0]->pSessionHandle)
    {
        pSessionDesc = DC_SESSION_DESC_FROM_CTX_GET(pOpData[0]->pSessionHandle);

#ifdef ICP_PARAM_CHECK
        sessDirection = pSessionDesc->sessDirection;
#endif
#ifdef ICP_DC_DYN_NOT_SUPPORTED
        huffType = pSessionDesc->huffType;
#endif
    }
    else
    {
#ifdef ICP_PARAM_CHECK
        sessDirection = pOpData[0]->pSetupData->sessDirection;
#endif
#ifdef ICP_DC_DYN_NOT_SUPPORTED
        huffType = pOpData[0]->pSetupData->huffType;
#endif
    }

#ifdef ICP_PARAM_CHECK
    for (i = 0; i < numberRequests; i++)
    {
        if ((CPA_DC_DIR_COMPRESS == pOpData[i]->sessDirection) &&
            (CPA_DC_DIR_DECOMPRESS == sessDirection))
        {
            LAC_INVALID_PARAM_LOG("(a) The session or (b) the NS setup data "
                                  "does not support this direction of "
                                  "operation");
            return CPA_STATUS_INVALID_PARAM;
        }
        else if ((CPA_DC_DIR_DECOMPRESS == pOpData[i]->sessDirection) &&
                 (CPA_DC_DIR_COMPRESS == sessDirection))
        {
            LAC_INVALID_PARAM_LOG("(a) The session or (b) the NS setup data "
                                  "does not support this direction of "
                                  "operation");
            return CPA_STATUS_INVALID_PARAM;
        }
    }
#endif

#ifdef ICP_DC_DYN_NOT_SUPPORTED
    if (CPA_DC_HT_FULL_DYNAMIC == huffType)
    {
        LAC_INVALID_PARAM_LOG("Invalid huffType value, dynamic sessions "
                              "not supported");
        return CPA_STATUS_INVALID_PARAM;
    }
#endif

    icp_adf_getQueueMemory(
        trans_handle, numberRequests, (void **)&pCurrentQatMsg);
    if (NULL == pCurrentQatMsg)
    {
        return CPA_STATUS_RETRY;
    }

    pNsRefQatMsg = NULL;

    for (i = 0; i < numberRequests; i++)
    {
        status = dcDpWriteRingMsg(pOpData[i], pCurrentQatMsg, pNsRefQatMsg);

        if (CPA_STATUS_SUCCESS != status)
        {
            return status;
        }

        if (!pNsRefQatMsg && pOpData[0]->pSetupData)
        {
            pNsRefQatMsg = pCurrentQatMsg;
        }

        icp_adf_getQueueNext(trans_handle, (void **)&pCurrentQatMsg);
    }

    if (pOpData[0]->pSessionHandle)
    {
        pSessionDesc->pendingDpStatelessCbCount += numberRequests;
    }

    if (CPA_TRUE == performOpNow)
    {
        status = icp_adf_updateQueueTail(trans_handle);
        if (CPA_STATUS_SUCCESS != status)
        {
            if (pOpData[0]->pSessionHandle)
            {
                pSessionDesc->pendingDpStatelessCbCount -= numberRequests;
            }
            return status;
        }
    }

    return CPA_STATUS_SUCCESS;
}

CpaStatus icp_sal_DcPollDpInstance(CpaInstanceHandle dcInstance,
                                   Cpa32U responseQuota)
{
    icp_comms_trans_handle trans_handle = NULL;
    sal_compression_service_t *pService = NULL;

#ifdef ICP_TRACE
    LAC_LOG2("Called with params (0x%lx, %d)\n",
             (LAC_ARCH_UINT)dcInstance,
             responseQuota);
#endif

#ifdef ICP_PARAM_CHECK
    LAC_CHECK_INSTANCE_HANDLE(dcInstance);
    /* Ensure this is a compression or a decompression instance */
    SAL_CHECK_INSTANCE_TYPE(
        dcInstance,
        (SAL_SERVICE_TYPE_COMPRESSION | SAL_SERVICE_TYPE_DECOMPRESSION));
#endif

    /* Check if SAL is initialised otherwise return an error */
    SAL_RUNNING_CHECK(dcInstance);

    pService = (sal_compression_service_t *)(dcInstance);

    if (pService->generic_service_info.type == SAL_SERVICE_TYPE_COMPRESSION)
    {
        trans_handle = ((sal_compression_service_t *)dcInstance)
                           ->trans_handle_compression_rx;
    }
    else
    {
        trans_handle = ((sal_compression_service_t *)dcInstance)
                           ->trans_handle_decompression_rx;
    }

    return icp_adf_pollQueue(trans_handle, responseQuota);
}

CpaStatus cpaDcDpPerformOpNow(CpaInstanceHandle dcInstance)
{
    icp_comms_trans_handle trans_handle = NULL;
    sal_compression_service_t *pService = NULL;

#ifdef ICP_TRACE
    LAC_LOG1("Called with params (0x%lx)\n", (LAC_ARCH_UINT)dcInstance);
#endif

#ifdef ICP_PARAM_CHECK
    LAC_CHECK_NULL_PARAM(dcInstance);
    /* Ensure this is a compression or a decompression instance */
    SAL_CHECK_INSTANCE_TYPE(
        dcInstance,
        (SAL_SERVICE_TYPE_COMPRESSION | SAL_SERVICE_TYPE_DECOMPRESSION));
#endif

    /* Check if SAL is initialised otherwise return an error */
    SAL_RUNNING_CHECK(dcInstance);

    pService = (sal_compression_service_t *)(dcInstance);

    if (pService->generic_service_info.type == SAL_SERVICE_TYPE_COMPRESSION)
    {
        trans_handle = ((sal_compression_service_t *)dcInstance)
                           ->trans_handle_compression_tx;
    }
    else
    {
        trans_handle = ((sal_compression_service_t *)dcInstance)
                           ->trans_handle_decompression_tx;
    }

    if (CPA_TRUE == icp_adf_queueDataToSend(trans_handle))
    {
        return icp_adf_updateQueueTail(trans_handle);
    }

    return CPA_STATUS_SUCCESS;
}

CpaStatus cpaDcDpEnqueueOpWithPartRead(CpaDcDpOpData *pOpData,
                                       CpaDcDpPartialReadData *pPartReadData,
                                       const CpaBoolean performOpNow)
{
    return CPA_STATUS_UNSUPPORTED;
}

CpaStatus cpaDcDpEnqueueOpWithZeroPad(CpaDcDpOpData *pOpData,
                                      const CpaBoolean performOpNow)
{
    return CPA_STATUS_UNSUPPORTED;
}

CpaStatus cpaDcDpEnqueueOpWithPartReadBatch(
    const Cpa32U numberRequests,
    CpaDcDpOpData *pOpData[],
    CpaDcDpPartialReadData *pPartReadData[],
    const CpaBoolean performOpNow)
{
    return CPA_STATUS_UNSUPPORTED;
}

CpaStatus cpaDcDpEnqueueOpWithZeroPadBatch(const Cpa32U numberRequests,
                                           CpaDcDpOpData *pOpData[],
                                           const CpaBoolean performOpNow)
{
    return CPA_STATUS_UNSUPPORTED;
}

CpaStatus cpaDcDpIsPartReadSupported(const CpaInstanceHandle instanceHandle,
                                     CpaBoolean *pFlag)
{
    return CPA_STATUS_UNSUPPORTED;
}

CpaStatus cpaDcDpIsZeroPadSupported(const CpaInstanceHandle instanceHandle,
                                    CpaBoolean *pFlag)
{
    return CPA_STATUS_UNSUPPORTED;
}
