/****************************************************************************
 *
 *   BSD LICENSE
 * 
 *   Copyright(c) 2007-2023 Intel Corporation. All rights reserved.
 *   All rights reserved.
 * 
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
 *   are met:
 * 
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided with the
 *       distribution.
 *     * Neither the name of Intel Corporation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 * 
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 *  version: QAT20.L.1.2.30-00078
 *
 ***************************************************************************/

/**
 *****************************************************************************
 * @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_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"
#include "sal_hw_gen.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;

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

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

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

    /* 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_TRUE != pOpData->compressAndVerify) &&
        (CPA_FALSE != pOpData->compressAndVerify))
    {
        LAC_INVALID_PARAM_LOG("Invalid compressAndVerify");
        return CPA_STATUS_INVALID_PARAM;
    }
    if ((CPA_TRUE == pOpData->compressAndVerify) &&
        !(pService->generic_service_info.dcExtendedFeatures &
          DC_CNV_EXTENDED_CAPABILITY))
    {
        LAC_INVALID_PARAM_LOG("Invalid compressAndVerify, no CNV capability");
        return CPA_STATUS_UNSUPPORTED;
    }
    if ((CPA_TRUE != pOpData->compressAndVerifyAndRecover) &&
        (CPA_FALSE != pOpData->compressAndVerifyAndRecover))
    {
        LAC_INVALID_PARAM_LOG("Invalid compressAndVerifyAndRecover");
        return CPA_STATUS_INVALID_PARAM;
    }
    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 == pOpData->compressAndVerifyAndRecover) &&
        !(pService->generic_service_info.dcExtendedFeatures &
          DC_CNVNR_EXTENDED_CAPABILITY))
    {
        LAC_INVALID_PARAM_LOG("Invalid CnVnR option 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 (isDcGen2x(pService) &&
                ((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 128B */
            if (pOpData->bufferLenForData < DC_DEST_BUFFER_DYN_MIN_SIZE)
            {
                LAC_INVALID_PARAM_LOG("Destination buffer length for data "
                                      "should be greater or equal to 128B");
                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 min output buffsize */
            if (pOpData->bufferLenForData <
                pService->comp_device_data.minOutputBuffSize)
            {
                LAC_INVALID_PARAM_LOG1(
                    "Destination buffer size should be "
                    "greater or equal to %d bytes",
                    pService->comp_device_data.minOutputBuffSize);
                return CPA_STATUS_INVALID_PARAM;
            }
        }
    }

    return CPA_STATUS_SUCCESS;
}
#endif

CpaStatus cpaDcDpGetSessionSize(CpaInstanceHandle dcInstance,
                                CpaDcSessionSetupData *pSessionData,
                                Cpa32U *pSessionSize)
{
#ifdef ICP_TRACE
    CpaStatus status = CPA_STATUS_SUCCESS;
    status = dcGetSessionSize(dcInstance, pSessionData, pSessionSize, NULL);

    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);

    return status;
#else
    return dcGetSessionSize(dcInstance, pSessionData, pSessionSize, NULL);
#endif
}

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);
    SAL_CHECK_INSTANCE_TYPE(dcInstance, SAL_SERVICE_TYPE_COMPRESSION);
#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);
        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 cpaDcDpUpdateSession(const CpaInstanceHandle dcInstance,
                               CpaDcSessionHandle pSessionHandle,
                               CpaDcSessionUpdateData *pSessionUpdateData)
{
    return CPA_STATUS_UNSUPPORTED;
}

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 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);
    SAL_CHECK_INSTANCE_TYPE(dcInstance, SAL_SERVICE_TYPE_COMPRESSION);
    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 cnvDecompReq = ICP_QAT_FW_COMP_NO_CNV;
    Cpa8U cnvnrCompReq = ICP_QAT_FW_COMP_NO_CNV_RECOVERY;
    CpaBoolean cnvErrorInjection = ICP_QAT_FW_COMP_NO_CNV_DFX;
    sal_compression_service_t *pService = NULL;
    CpaStatus status;

    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);
        }
    }

    if (CPA_DC_DIR_COMPRESS == pOpData->sessDirection)
    {
        /* CNV check */
        if (CPA_TRUE == pOpData->compressAndVerify)
        {
            cnvDecompReq = ICP_QAT_FW_COMP_CNV;

            if (isDcGen4x(pService))
            {
                if (pOpData->pSessionHandle)
                {
                    cnvErrorInjection = pSessionDesc->cnvErrorInjection;
                }
                else
                {
                    cnvErrorInjection =
                        pService->generic_service_info.ns_isCnvErrorInjection;
                }
            }

            /* CNVNR check */
            if (CPA_TRUE == pOpData->compressAndVerifyAndRecover)
            {
                cnvnrCompReq = 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,
                                              cnvDecompReq,
                                              cnvnrCompReq,
                                              cnvErrorInjection,
                                              ICP_QAT_FW_COMP_CRC_MODE_LEGACY);

    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;
    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

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

#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);

    trans_handle = ((sal_compression_service_t *)pOpData->dcInstance)
                       ->trans_handle_compression_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_RETRY == status && 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;
    Cpa32U i = 0;
    CpaStatus status = CPA_STATUS_SUCCESS;
#ifdef ICP_DC_DYN_NOT_SUPPORTED
    CpaDcHuffType huffType;
#endif
#ifdef ICP_PARAM_CHECK
    CpaDcSessionDir sessDirection;

    sal_compression_service_t *pService = NULL;

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

    pService = (sal_compression_service_t *)(pOpData[0]->dcInstance);
    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

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

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

    trans_handle = ((sal_compression_service_t *)pOpData[0]->dcInstance)
                       ->trans_handle_compression_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 (pSessionDesc)
    {
        pSessionDesc->pendingDpStatelessCbCount += numberRequests;
    }

    if (CPA_TRUE == performOpNow)
    {
        status = icp_adf_updateQueueTail(trans_handle);
        if (CPA_STATUS_RETRY == status)
        {
            if (pSessionDesc)
            {
                pSessionDesc->pendingDpStatelessCbCount -= numberRequests;
            }
        }
        return status;
    }

    return CPA_STATUS_SUCCESS;
}

CpaStatus icp_sal_DcPollDpInstance(CpaInstanceHandle dcInstance,
                                   Cpa32U responseQuota)
{
    icp_comms_trans_handle trans_handle = 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);
    SAL_CHECK_INSTANCE_TYPE(dcInstance, SAL_SERVICE_TYPE_COMPRESSION);
#endif

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

    trans_handle =
        ((sal_compression_service_t *)dcInstance)->trans_handle_compression_rx;

    return icp_adf_pollQueue(trans_handle, responseQuota);
}

CpaStatus cpaDcDpPerformOpNow(CpaInstanceHandle dcInstance)
{
    icp_comms_trans_handle trans_handle = 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);
    SAL_CHECK_INSTANCE_TYPE(dcInstance, SAL_SERVICE_TYPE_COMPRESSION);
#endif

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

    trans_handle =
        ((sal_compression_service_t *)dcInstance)->trans_handle_compression_tx;

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

    return CPA_STATUS_SUCCESS;
}
