/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright(c) 2007-2022 Intel Corporation */
/**
 *****************************************************************************
 * @file dc_session.c
 *
 * @ingroup Dc_DataCompression
 *
 * @description
 *      Implementation of the Data Compression session operations.
 *
 *****************************************************************************/

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

#include "icp_qat_fw.h"
#include "icp_qat_fw_comp.h"
#include "icp_qat_hw.h"
#include "icp_qat_hw_20_comp.h"

/*
 *******************************************************************************
 * Include private header files
 *******************************************************************************
 */
#include "dc_session.h"
#include "dc_datapath.h"
#include "lac_mem_pools.h"
#include "sal_types_compression.h"
#include "lac_buffer_desc.h"
#include "sal_service_state.h"
#include "sal_qat_cmn_msg.h"
#include "sal_hw_gen.h"

/**
 *****************************************************************************
 * @ingroup Dc_DataCompression
 *      Check that pSessionData is valid
 *
 * @description
 *      Check that all the parameters defined in the pSessionData are valid
 *
 * @param[in]       pSessionData     Pointer to a user instantiated structure
 *                                   containing session data
 *
 * @retval CPA_STATUS_SUCCESS        Function executed successfully
 * @retval CPA_STATUS_FAIL           Function failed to find device
 * @retval CPA_STATUS_INVALID_PARAM  Invalid parameter passed in
 * @retval CPA_STATUS_UNSUPPORTED    Unsupported algorithm/feature
 *
 *****************************************************************************/
CpaStatus
dcCheckSessionData(const CpaDcSessionSetupData *pSessionData,
		   CpaInstanceHandle dcInstance)
{
	CpaDcInstanceCapabilities instanceCapabilities = { 0 };

	cpaDcQueryCapabilities(dcInstance, &instanceCapabilities);

	if ((pSessionData->compLevel < CPA_DC_L1) ||
	    (pSessionData->compLevel > CPA_DC_L12)) {
		QAT_UTILS_LOG("Invalid compLevel value\n");
		return CPA_STATUS_INVALID_PARAM;
	}

	if ((pSessionData->autoSelectBestHuffmanTree < CPA_DC_ASB_DISABLED) ||
	    (pSessionData->autoSelectBestHuffmanTree > CPA_DC_ASB_ENABLED)) {
		QAT_UTILS_LOG("Invalid autoSelectBestHuffmanTree value\n");
		return CPA_STATUS_INVALID_PARAM;
	}
	if (pSessionData->compType != CPA_DC_DEFLATE) {
		QAT_UTILS_LOG("Invalid compType value\n");
		return CPA_STATUS_INVALID_PARAM;
	}

	if ((pSessionData->huffType < CPA_DC_HT_STATIC) ||
	    (pSessionData->huffType > CPA_DC_HT_FULL_DYNAMIC) ||
	    (CPA_DC_HT_PRECOMP == pSessionData->huffType)) {
		QAT_UTILS_LOG("Invalid huffType value\n");
		return CPA_STATUS_INVALID_PARAM;
	}

	if ((pSessionData->sessDirection < CPA_DC_DIR_COMPRESS) ||
	    (pSessionData->sessDirection > CPA_DC_DIR_COMBINED)) {
		QAT_UTILS_LOG("Invalid sessDirection value\n");
		return CPA_STATUS_INVALID_PARAM;
	}

	if ((pSessionData->sessState < CPA_DC_STATEFUL) ||
	    (pSessionData->sessState > CPA_DC_STATELESS)) {
		QAT_UTILS_LOG("Invalid sessState value\n");
		return CPA_STATUS_INVALID_PARAM;
	}

	if ((pSessionData->checksum < CPA_DC_NONE) ||
	    (pSessionData->checksum > CPA_DC_ADLER32)) {
		QAT_UTILS_LOG("Invalid checksum value\n");
		return CPA_STATUS_INVALID_PARAM;
	}

	return CPA_STATUS_SUCCESS;
}

/**
 *****************************************************************************
 * @ingroup Dc_DataCompression
 *      Populate the compression hardware block
 *
 * @description
 *      This function will populate the compression hardware block and update
 *      the size in bytes of the block
 *
 * @param[in]   pSessionDesc            Pointer to the session descriptor
 * @param[in]   pCompConfig             Pointer to slice config word
 * @param[in]   compDecomp              Direction of the operation
 * @param[in]   enableDmm               Delayed Match Mode
 *
 *****************************************************************************/
static void
dcCompHwBlockPopulate(sal_compression_service_t *pService,
		      dc_session_desc_t *pSessionDesc,
		      icp_qat_hw_compression_config_t *pCompConfig,
		      dc_request_dir_t compDecomp)
{
	icp_qat_hw_compression_direction_t dir =
	    ICP_QAT_HW_COMPRESSION_DIR_COMPRESS;
	icp_qat_hw_compression_algo_t algo =
	    ICP_QAT_HW_COMPRESSION_ALGO_DEFLATE;
	icp_qat_hw_compression_depth_t depth = ICP_QAT_HW_COMPRESSION_DEPTH_1;
	icp_qat_hw_compression_file_type_t filetype =
	    ICP_QAT_HW_COMPRESSION_FILE_TYPE_0;
	icp_qat_hw_compression_delayed_match_t dmm;

	/* Set the direction */
	if (DC_COMPRESSION_REQUEST == compDecomp) {
		dir = ICP_QAT_HW_COMPRESSION_DIR_COMPRESS;
	} else {
		dir = ICP_QAT_HW_COMPRESSION_DIR_DECOMPRESS;
	}

	if (CPA_DC_DEFLATE == pSessionDesc->compType) {
		algo = ICP_QAT_HW_COMPRESSION_ALGO_DEFLATE;
	} else {
		QAT_UTILS_LOG("Algorithm not supported for Compression\n");
	}

	/* Set delay match mode */
	if (ICP_QAT_HW_COMPRESSION_DELAYED_MATCH_ENABLED ==
	    pService->comp_device_data.enableDmm) {
		dmm = ICP_QAT_HW_COMPRESSION_DELAYED_MATCH_ENABLED;
	} else {
		dmm = ICP_QAT_HW_COMPRESSION_DELAYED_MATCH_DISABLED;
	}

	/* Set the depth */
	if (DC_DECOMPRESSION_REQUEST == compDecomp) {
		depth = ICP_QAT_HW_COMPRESSION_DEPTH_1;
	} else {
		switch (pSessionDesc->compLevel) {
		case CPA_DC_L1:
			depth = ICP_QAT_HW_COMPRESSION_DEPTH_1;
			break;
		case CPA_DC_L2:
			depth = ICP_QAT_HW_COMPRESSION_DEPTH_4;
			break;
		case CPA_DC_L3:
			depth = ICP_QAT_HW_COMPRESSION_DEPTH_8;
			break;
		case CPA_DC_L4:
			depth = ICP_QAT_HW_COMPRESSION_DEPTH_16;
			break;
		default:
			depth = pService->comp_device_data
				    .highestHwCompressionDepth;
			break;
		}
	}

	/* The file type is set to ICP_QAT_HW_COMPRESSION_FILE_TYPE_0. The other
	 * modes will be used in the future for precompiled huffman trees */
	filetype = ICP_QAT_HW_COMPRESSION_FILE_TYPE_0;

	pCompConfig->lower_val = ICP_QAT_HW_COMPRESSION_CONFIG_BUILD(
	    dir, dmm, algo, depth, filetype);

	/* Upper 32-bits of the configuration word do not need to be
	 * configured with legacy devices.
	 */
	pCompConfig->upper_val = 0;
}

static void
dcCompHwBlockPopulateGen4(sal_compression_service_t *pService,
			  dc_session_desc_t *pSessionDesc,
			  icp_qat_hw_compression_config_t *pCompConfig,
			  dc_request_dir_t compDecomp)
{
	/* Compression related */
	if (DC_COMPRESSION_REQUEST == compDecomp) {
		icp_qat_hw_comp_20_config_csr_upper_t hw_comp_upper_csr;
		icp_qat_hw_comp_20_config_csr_lower_t hw_comp_lower_csr;

		memset(&hw_comp_upper_csr, 0, sizeof hw_comp_upper_csr);
		memset(&hw_comp_lower_csr, 0, sizeof hw_comp_lower_csr);

		/* Disable Literal + Length Limit Block Drop by default and
		 * enable it only for dynamic deflate compression.
		 */
		hw_comp_lower_csr.lllbd =
		    ICP_QAT_HW_COMP_20_LLLBD_CTRL_LLLBD_DISABLED;

		switch (pSessionDesc->compType) {
		case CPA_DC_DEFLATE:
			/* DEFLATE algorithm settings */
			hw_comp_lower_csr.skip_ctrl =
			    ICP_QAT_HW_COMP_20_BYTE_SKIP_3BYTE_LITERAL;

			if (CPA_DC_HT_FULL_DYNAMIC == pSessionDesc->huffType) {
				hw_comp_lower_csr.algo =
				    ICP_QAT_HW_COMP_20_HW_COMP_FORMAT_ILZ77;
			} else /* Static DEFLATE */
			{
				hw_comp_lower_csr.algo =
				    ICP_QAT_HW_COMP_20_HW_COMP_FORMAT_DEFLATE;
				hw_comp_upper_csr.scb_ctrl =
				    ICP_QAT_HW_COMP_20_SCB_CONTROL_DISABLE;
			}

			if (CPA_DC_STATEFUL == pSessionDesc->sessState) {
				hw_comp_upper_csr.som_ctrl =
				    ICP_QAT_HW_COMP_20_SOM_CONTROL_REPLAY_MODE;
			}
			break;
		default:
			QAT_UTILS_LOG("Compression algorithm not supported\n");
			break;
		}
		/* Set the search depth */
		switch (pSessionDesc->compLevel) {
		case CPA_DC_L1:
		case CPA_DC_L2:
		case CPA_DC_L3:
		case CPA_DC_L4:
		case CPA_DC_L5:
			hw_comp_lower_csr.sd =
			    ICP_QAT_HW_COMP_20_SEARCH_DEPTH_LEVEL_1;
			hw_comp_lower_csr.hash_col =
			    ICP_QAT_HW_COMP_20_SKIP_HASH_COLLISION_DONT_ALLOW;
			break;
		case CPA_DC_L6:
		case CPA_DC_L7:
		case CPA_DC_L8:
			hw_comp_lower_csr.sd =
			    ICP_QAT_HW_COMP_20_SEARCH_DEPTH_LEVEL_6;
			break;
		case CPA_DC_L9:
			hw_comp_lower_csr.sd =
			    ICP_QAT_HW_COMP_20_SEARCH_DEPTH_LEVEL_9;
			break;
		default:
			hw_comp_lower_csr.sd = pService->comp_device_data
						   .highestHwCompressionDepth;
			if ((CPA_DC_HT_FULL_DYNAMIC ==
			     pSessionDesc->huffType) &&
			    (CPA_DC_DEFLATE == pSessionDesc->compType)) {
				/* Enable Literal + Length Limit Block Drop
				 * with dynamic deflate compression when
				 * highest compression levels are selected.
				 */
				hw_comp_lower_csr.lllbd =
				    ICP_QAT_HW_COMP_20_LLLBD_CTRL_LLLBD_ENABLED;
			}
			break;
		}
		/* Same for all algorithms */
		hw_comp_lower_csr.abd = ICP_QAT_HW_COMP_20_ABD_ABD_DISABLED;
		hw_comp_lower_csr.hash_update =
		    ICP_QAT_HW_COMP_20_SKIP_HASH_UPDATE_DONT_ALLOW;
		hw_comp_lower_csr.edmm =
		    (ICP_QAT_HW_COMPRESSION_DELAYED_MATCH_ENABLED ==
			pService->comp_device_data.enableDmm) ?
		    ICP_QAT_HW_COMP_20_EXTENDED_DELAY_MATCH_MODE_EDMM_ENABLED :
		    ICP_QAT_HW_COMP_20_EXTENDED_DELAY_MATCH_MODE_EDMM_DISABLED;

		/* Hard-coded HW-specific values */
		hw_comp_upper_csr.nice =
		    ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_DEFAULT_VAL;
		hw_comp_upper_csr.lazy =
		    ICP_QAT_HW_COMP_20_CONFIG_CSR_LAZY_PARAM_DEFAULT_VAL;

		pCompConfig->upper_val =
		    ICP_QAT_FW_COMP_20_BUILD_CONFIG_UPPER(hw_comp_upper_csr);

		pCompConfig->lower_val =
		    ICP_QAT_FW_COMP_20_BUILD_CONFIG_LOWER(hw_comp_lower_csr);
	} else /* Decompress */
	{
		icp_qat_hw_decomp_20_config_csr_lower_t hw_decomp_lower_csr;

		memset(&hw_decomp_lower_csr, 0, sizeof hw_decomp_lower_csr);

		/* Set the algorithm */
		if (CPA_DC_DEFLATE == pSessionDesc->compType) {
			hw_decomp_lower_csr.algo =
			    ICP_QAT_HW_DECOMP_20_HW_DECOMP_FORMAT_DEFLATE;
		} else {
			QAT_UTILS_LOG("Algorithm not supported for "
				      "Decompression\n");
		}

		pCompConfig->upper_val = 0;
		pCompConfig->lower_val =
		    ICP_QAT_FW_DECOMP_20_BUILD_CONFIG_LOWER(
			hw_decomp_lower_csr);
	}
}

/**
 *****************************************************************************
 * @ingroup Dc_DataCompression
 *      Populate the compression content descriptor
 *
 * @description
 *      This function will populate the compression content descriptor
 *
 * @param[in]   pService                Pointer to the service
 * @param[in]   pSessionDesc            Pointer to the session descriptor
 * @param[in]   contextBufferAddrPhys   Physical address of the context buffer
 * @param[out]  pMsg                    Pointer to the compression message
 * @param[in]   nextSlice               Next slice
 * @param[in]   compDecomp              Direction of the operation
 *
 *****************************************************************************/
static void
dcCompContentDescPopulate(sal_compression_service_t *pService,
			  dc_session_desc_t *pSessionDesc,
			  CpaPhysicalAddr contextBufferAddrPhys,
			  icp_qat_fw_comp_req_t *pMsg,
			  icp_qat_fw_slice_t nextSlice,
			  dc_request_dir_t compDecomp)
{

	icp_qat_fw_comp_cd_hdr_t *pCompControlBlock = NULL;
	icp_qat_hw_compression_config_t *pCompConfig = NULL;
	CpaBoolean bankEnabled = CPA_FALSE;

	pCompControlBlock = (icp_qat_fw_comp_cd_hdr_t *)&(pMsg->comp_cd_ctrl);
	pCompConfig =
	    (icp_qat_hw_compression_config_t *)(pMsg->cd_pars.sl
						    .comp_slice_cfg_word);

	ICP_QAT_FW_COMN_NEXT_ID_SET(pCompControlBlock, nextSlice);
	ICP_QAT_FW_COMN_CURR_ID_SET(pCompControlBlock, ICP_QAT_FW_SLICE_COMP);

	pCompControlBlock->comp_cfg_offset = 0;

	if ((CPA_DC_STATEFUL == pSessionDesc->sessState) &&
	    (CPA_DC_DEFLATE == pSessionDesc->compType) &&
	    (DC_DECOMPRESSION_REQUEST == compDecomp)) {
		/* Enable A, B, C, D, and E (CAMs).  */
		pCompControlBlock->ram_bank_flags =
		    ICP_QAT_FW_COMP_RAM_FLAGS_BUILD(
			ICP_QAT_FW_COMP_BANK_DISABLED, /* Bank I */
			ICP_QAT_FW_COMP_BANK_DISABLED, /* Bank H */
			ICP_QAT_FW_COMP_BANK_DISABLED, /* Bank G */
			ICP_QAT_FW_COMP_BANK_DISABLED, /* Bank F */
			ICP_QAT_FW_COMP_BANK_ENABLED,  /* Bank E */
			ICP_QAT_FW_COMP_BANK_ENABLED,  /* Bank D */
			ICP_QAT_FW_COMP_BANK_ENABLED,  /* Bank C */
			ICP_QAT_FW_COMP_BANK_ENABLED,  /* Bank B */
			ICP_QAT_FW_COMP_BANK_ENABLED); /* Bank A */
		bankEnabled = CPA_TRUE;
	} else {
		/* Disable all banks */
		pCompControlBlock->ram_bank_flags =
		    ICP_QAT_FW_COMP_RAM_FLAGS_BUILD(
			ICP_QAT_FW_COMP_BANK_DISABLED,  /* Bank I */
			ICP_QAT_FW_COMP_BANK_DISABLED,  /* Bank H */
			ICP_QAT_FW_COMP_BANK_DISABLED,  /* Bank G */
			ICP_QAT_FW_COMP_BANK_DISABLED,  /* Bank F */
			ICP_QAT_FW_COMP_BANK_DISABLED,  /* Bank E */
			ICP_QAT_FW_COMP_BANK_DISABLED,  /* Bank D */
			ICP_QAT_FW_COMP_BANK_DISABLED,  /* Bank C */
			ICP_QAT_FW_COMP_BANK_DISABLED,  /* Bank B */
			ICP_QAT_FW_COMP_BANK_DISABLED); /* Bank A */
	}

	if (DC_COMPRESSION_REQUEST == compDecomp) {
		LAC_MEM_SHARED_WRITE_VIRT_TO_PHYS_PTR_EXTERNAL(
		    pService->generic_service_info,
		    pCompControlBlock->comp_state_addr,
		    pSessionDesc->stateRegistersComp);
	} else {
		LAC_MEM_SHARED_WRITE_VIRT_TO_PHYS_PTR_EXTERNAL(
		    pService->generic_service_info,
		    pCompControlBlock->comp_state_addr,
		    pSessionDesc->stateRegistersDecomp);
	}

	if (CPA_TRUE == bankEnabled) {
		pCompControlBlock->ram_banks_addr = contextBufferAddrPhys;
	} else {
		pCompControlBlock->ram_banks_addr = 0;
	}

	pCompControlBlock->resrvd = 0;

	/* Populate Compression Hardware Setup Block */
	if (isDcGen4x(pService)) {
		dcCompHwBlockPopulateGen4(pService,
					  pSessionDesc,
					  pCompConfig,
					  compDecomp);
	} else if (isDcGen2x(pService)) {
		dcCompHwBlockPopulate(pService,
				      pSessionDesc,
				      pCompConfig,
				      compDecomp);
	} else {
		QAT_UTILS_LOG("Invalid QAT generation value\n");
	}
}

/**
 *****************************************************************************
 * @ingroup Dc_DataCompression
 *      Populate the translator content descriptor
 *
 * @description
 *      This function will populate the translator content descriptor
 *
 * @param[out]  pMsg                     Pointer to the compression message
 * @param[in]   nextSlice                Next slice
 *
 *****************************************************************************/
void
dcTransContentDescPopulate(icp_qat_fw_comp_req_t *pMsg,
			   icp_qat_fw_slice_t nextSlice)
{

	icp_qat_fw_xlt_cd_hdr_t *pTransControlBlock = NULL;
	pTransControlBlock = (icp_qat_fw_xlt_cd_hdr_t *)&(pMsg->u2.xlt_cd_ctrl);

	ICP_QAT_FW_COMN_NEXT_ID_SET(pTransControlBlock, nextSlice);
	ICP_QAT_FW_COMN_CURR_ID_SET(pTransControlBlock, ICP_QAT_FW_SLICE_XLAT);

	pTransControlBlock->resrvd1 = 0;
	pTransControlBlock->resrvd2 = 0;
	pTransControlBlock->resrvd3 = 0;
}

/**
 *****************************************************************************
 * @ingroup Dc_DataCompression
 *      Get the context size and the history size
 *
 * @description
 *      This function will get the size of the context buffer and the history
 *      buffer. The history buffer is a subset of the context buffer and its
 *      size is needed for stateful compression.

 * @param[in]   dcInstance         DC Instance Handle
 *
 * @param[in]   pSessionData       Pointer to a user instantiated
 *                                 structure containing session data
 * @param[out]  pContextSize       Pointer to the context size
 *
 * @retval CPA_STATUS_SUCCESS      Function executed successfully
 *
 *
 *****************************************************************************/
static CpaStatus
dcGetContextSize(CpaInstanceHandle dcInstance,
		 CpaDcSessionSetupData *pSessionData,
		 Cpa32U *pContextSize)
{
	sal_compression_service_t *pCompService = NULL;

	pCompService = (sal_compression_service_t *)dcInstance;

	*pContextSize = 0;
	if ((CPA_DC_STATEFUL == pSessionData->sessState) &&
	    (CPA_DC_DIR_COMPRESS != pSessionData->sessDirection)) {
		switch (pSessionData->compType) {
		case CPA_DC_DEFLATE:
			*pContextSize =
			    pCompService->comp_device_data.inflateContextSize;
			break;
		default:
			QAT_UTILS_LOG("Invalid compression algorithm.");
			return CPA_STATUS_FAIL;
		}
	}
	return CPA_STATUS_SUCCESS;
}

CpaStatus
dcGetCompressCommandId(sal_compression_service_t *pService,
		       CpaDcSessionSetupData *pSessionData,
		       Cpa8U *pDcCmdId)
{
	CpaStatus status = CPA_STATUS_SUCCESS;
	LAC_CHECK_NULL_PARAM(pService);
	LAC_CHECK_NULL_PARAM(pSessionData);
	LAC_CHECK_NULL_PARAM(pDcCmdId);

	switch (pSessionData->compType) {
	case CPA_DC_DEFLATE:
		*pDcCmdId = (CPA_DC_HT_FULL_DYNAMIC == pSessionData->huffType) ?
		    ICP_QAT_FW_COMP_CMD_DYNAMIC :
		    ICP_QAT_FW_COMP_CMD_STATIC;
		break;
	default:
		QAT_UTILS_LOG("Algorithm not supported for "
			      "compression\n");
		status = CPA_STATUS_UNSUPPORTED;
		break;
	}

	return status;
}

CpaStatus
dcGetDecompressCommandId(sal_compression_service_t *pService,
			 CpaDcSessionSetupData *pSessionData,
			 Cpa8U *pDcCmdId)
{
	CpaStatus status = CPA_STATUS_SUCCESS;
	LAC_CHECK_NULL_PARAM(pService);
	LAC_CHECK_NULL_PARAM(pSessionData);
	LAC_CHECK_NULL_PARAM(pDcCmdId);

	switch (pSessionData->compType) {
	case CPA_DC_DEFLATE:
		*pDcCmdId = ICP_QAT_FW_COMP_CMD_DECOMPRESS;
		break;
	default:
		QAT_UTILS_LOG("Algorithm not supported for "
			      "decompression\n");
		status = CPA_STATUS_UNSUPPORTED;
		break;
	}

	return status;
}

CpaStatus
dcInitSession(CpaInstanceHandle dcInstance,
	      CpaDcSessionHandle pSessionHandle,
	      CpaDcSessionSetupData *pSessionData,
	      CpaBufferList *pContextBuffer,
	      CpaDcCallbackFn callbackFn)
{
	CpaStatus status = CPA_STATUS_SUCCESS;
	sal_compression_service_t *pService = NULL;
	icp_qat_fw_comp_req_t *pReqCache = NULL;
	dc_session_desc_t *pSessionDesc = NULL;
	CpaPhysicalAddr contextAddrPhys = 0;
	CpaPhysicalAddr physAddress = 0;
	CpaPhysicalAddr physAddressAligned = 0;
	Cpa32U minContextSize = 0, historySize = 0;
	Cpa32U rpCmdFlags = 0;
	icp_qat_fw_serv_specif_flags cmdFlags = 0;
	Cpa8U secureRam = ICP_QAT_FW_COMP_ENABLE_SECURE_RAM_USED_AS_INTMD_BUF;
	Cpa8U sessType = ICP_QAT_FW_COMP_STATELESS_SESSION;
	Cpa8U autoSelectBest = ICP_QAT_FW_COMP_NOT_AUTO_SELECT_BEST;
	Cpa8U enhancedAutoSelectBest = ICP_QAT_FW_COMP_NOT_ENH_AUTO_SELECT_BEST;
	Cpa8U disableType0EnhancedAutoSelectBest =
	    ICP_QAT_FW_COMP_NOT_DISABLE_TYPE0_ENH_AUTO_SELECT_BEST;
	icp_qat_fw_la_cmd_id_t dcCmdId =
	    (icp_qat_fw_la_cmd_id_t)ICP_QAT_FW_COMP_CMD_STATIC;
	icp_qat_fw_comn_flags cmnRequestFlags = 0;
	dc_integrity_crc_fw_t *pDataIntegrityCrcs = NULL;

	cmnRequestFlags =
	    ICP_QAT_FW_COMN_FLAGS_BUILD(DC_DEFAULT_QAT_PTR_TYPE,
					QAT_COMN_CD_FLD_TYPE_16BYTE_DATA);

	pService = (sal_compression_service_t *)dcInstance;

	secureRam = pService->comp_device_data.useDevRam;

	LAC_CHECK_NULL_PARAM(pSessionHandle);
	LAC_CHECK_NULL_PARAM(pSessionData);

	/* Check that the parameters defined in the pSessionData are valid for
	 * the
	 * device */
	if (CPA_STATUS_SUCCESS !=
	    dcCheckSessionData(pSessionData, dcInstance)) {
		return CPA_STATUS_INVALID_PARAM;
	}

	if ((CPA_DC_STATEFUL == pSessionData->sessState) &&
	    (CPA_DC_DIR_DECOMPRESS != pSessionData->sessDirection)) {
		QAT_UTILS_LOG("Stateful sessions are not supported.\n");
		return CPA_STATUS_UNSUPPORTED;
	}

	/* Check for Gen4 and stateful, return error if both exist */
	if ((isDcGen4x(pService)) &&
	    (CPA_DC_STATEFUL == pSessionData->sessState &&
	     CPA_DC_DIR_DECOMPRESS != pSessionData->sessDirection)) {
		QAT_UTILS_LOG("Stateful sessions are not supported for "
			      "compression direction");
		return CPA_STATUS_UNSUPPORTED;
	}

	if ((isDcGen2x(pService)) &&
	    (CPA_DC_HT_FULL_DYNAMIC == pSessionData->huffType)) {
		/* Test if DRAM is available for the intermediate buffers */
		if ((NULL == pService->pInterBuffPtrsArray) &&
		    (0 == pService->pInterBuffPtrsArrayPhyAddr)) {
			if (CPA_DC_ASB_STATIC_DYNAMIC ==
			    pSessionData->autoSelectBestHuffmanTree) {
				/* Define the Huffman tree as static */
				pSessionData->huffType = CPA_DC_HT_STATIC;
			} else {
				QAT_UTILS_LOG(
				    "No buffer defined for this instance - "
				    "see cpaDcStartInstance.\n");
				return CPA_STATUS_RESOURCE;
			}
		}
	}

	if ((CPA_DC_STATEFUL == pSessionData->sessState) &&
	    (CPA_DC_DEFLATE == pSessionData->compType)) {
		/* Get the size of the context buffer */
		status =
		    dcGetContextSize(dcInstance, pSessionData, &minContextSize);

		if (CPA_STATUS_SUCCESS != status) {
			QAT_UTILS_LOG(
			    "Unable to get the context size of the session.\n");
			return CPA_STATUS_FAIL;
		}

		/* If the minContextSize is zero it means we will not save or
		 * restore
		 * any history */
		if (0 != minContextSize) {
			Cpa64U contextBuffSize = 0;

			LAC_CHECK_NULL_PARAM(pContextBuffer);

			if (LacBuffDesc_BufferListVerify(
				pContextBuffer,
				&contextBuffSize,
				LAC_NO_ALIGNMENT_SHIFT) != CPA_STATUS_SUCCESS) {
				return CPA_STATUS_INVALID_PARAM;
			}

			/* Ensure that the context buffer size is greater or
			 * equal
			 * to minContextSize */
			if (contextBuffSize < minContextSize) {
				QAT_UTILS_LOG(
				    "Context buffer size should be greater or equal to %d.\n",
				    minContextSize);
				return CPA_STATUS_INVALID_PARAM;
			}
		}
	}

	/* Re-align the session structure to 64 byte alignment */
	physAddress =
	    LAC_OS_VIRT_TO_PHYS_EXTERNAL(pService->generic_service_info,
					 (Cpa8U *)pSessionHandle +
					     sizeof(void *));

	if (physAddress == 0) {
		QAT_UTILS_LOG(
		    "Unable to get the physical address of the session.\n");
		return CPA_STATUS_FAIL;
	}

	physAddressAligned =
	    (CpaPhysicalAddr)LAC_ALIGN_POW2_ROUNDUP(physAddress,
						    LAC_64BYTE_ALIGNMENT);

	pSessionDesc = (dc_session_desc_t *)
	    /* Move the session pointer by the physical offset
	    between aligned and unaligned memory */
	    ((Cpa8U *)pSessionHandle + sizeof(void *) +
	     (physAddressAligned - physAddress));

	/* Save the aligned pointer in the first bytes (size of LAC_ARCH_UINT)
	 * of the session memory */
	*((LAC_ARCH_UINT *)pSessionHandle) = (LAC_ARCH_UINT)pSessionDesc;

	/* Zero the compression session */
	LAC_OS_BZERO(pSessionDesc, sizeof(dc_session_desc_t));

	/* Write the buffer descriptor for context/history */
	if (0 != minContextSize) {
		status = LacBuffDesc_BufferListDescWrite(
		    pContextBuffer,
		    &contextAddrPhys,
		    CPA_FALSE,
		    &(pService->generic_service_info));

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

		pSessionDesc->pContextBuffer = pContextBuffer;
		pSessionDesc->historyBuffSize = historySize;
	}

	pSessionDesc->cumulativeConsumedBytes = 0;

	/* Initialise pSessionDesc */
	pSessionDesc->requestType = DC_REQUEST_FIRST;
	pSessionDesc->huffType = pSessionData->huffType;
	pSessionDesc->compType = pSessionData->compType;
	pSessionDesc->checksumType = pSessionData->checksum;
	pSessionDesc->autoSelectBestHuffmanTree =
	    pSessionData->autoSelectBestHuffmanTree;
	pSessionDesc->sessDirection = pSessionData->sessDirection;
	pSessionDesc->sessState = pSessionData->sessState;
	pSessionDesc->compLevel = pSessionData->compLevel;
	pSessionDesc->isDcDp = CPA_FALSE;
	pSessionDesc->minContextSize = minContextSize;
	pSessionDesc->isSopForCompressionProcessed = CPA_FALSE;
	pSessionDesc->isSopForDecompressionProcessed = CPA_FALSE;

	if (CPA_DC_ADLER32 == pSessionDesc->checksumType) {
		pSessionDesc->previousChecksum = 1;
	} else {
		pSessionDesc->previousChecksum = 0;
	}

	if (CPA_DC_STATEFUL == pSessionData->sessState) {
		/* Init the spinlock used to lock the access to the number of
		 * stateful
		 * in-flight requests */
		status = LAC_SPINLOCK_INIT(&(pSessionDesc->sessionLock));
		if (CPA_STATUS_SUCCESS != status) {
			QAT_UTILS_LOG(
			    "Spinlock init failed for sessionLock.\n");
			return CPA_STATUS_RESOURCE;
		}
	}

	/* For asynchronous - use the user supplied callback
	 * for synchronous - use the internal synchronous callback */
	pSessionDesc->pCompressionCb = ((void *)NULL != (void *)callbackFn) ?
	    callbackFn :
	    LacSync_GenWakeupSyncCaller;

	/* Reset the pending callback counters */
	qatUtilsAtomicSet(0, &pSessionDesc->pendingStatelessCbCount);
	qatUtilsAtomicSet(0, &pSessionDesc->pendingStatefulCbCount);
	pSessionDesc->pendingDpStatelessCbCount = 0;

	if (CPA_DC_DIR_DECOMPRESS != pSessionData->sessDirection) {
		if ((isDcGen2x(pService)) &&
		    CPA_DC_HT_FULL_DYNAMIC == pSessionData->huffType) {
			/* Populate the compression section of the content
			 * descriptor */
			dcCompContentDescPopulate(pService,
						  pSessionDesc,
						  contextAddrPhys,
						  &(pSessionDesc->reqCacheComp),
						  ICP_QAT_FW_SLICE_XLAT,
						  DC_COMPRESSION_REQUEST);

			/* Populate the translator section of the content
			 * descriptor */
			dcTransContentDescPopulate(
			    &(pSessionDesc->reqCacheComp),
			    ICP_QAT_FW_SLICE_DRAM_WR);

			if (0 != pService->pInterBuffPtrsArrayPhyAddr) {
				pReqCache = &(pSessionDesc->reqCacheComp);

				pReqCache->u1.xlt_pars.inter_buff_ptr =
				    pService->pInterBuffPtrsArrayPhyAddr;
			}
		} else {
			dcCompContentDescPopulate(pService,
						  pSessionDesc,
						  contextAddrPhys,
						  &(pSessionDesc->reqCacheComp),
						  ICP_QAT_FW_SLICE_DRAM_WR,
						  DC_COMPRESSION_REQUEST);
		}
	}

	/* Populate the compression section of the content descriptor for
	 * the decompression case or combined */
	if (CPA_DC_DIR_COMPRESS != pSessionData->sessDirection) {
		dcCompContentDescPopulate(pService,
					  pSessionDesc,
					  contextAddrPhys,
					  &(pSessionDesc->reqCacheDecomp),
					  ICP_QAT_FW_SLICE_DRAM_WR,
					  DC_DECOMPRESSION_REQUEST);
	}

	if (CPA_DC_STATEFUL == pSessionData->sessState) {
		sessType = ICP_QAT_FW_COMP_STATEFUL_SESSION;

		LAC_OS_BZERO(&pSessionDesc->stateRegistersComp,
			     sizeof(pSessionDesc->stateRegistersComp));

		LAC_OS_BZERO(&pSessionDesc->stateRegistersDecomp,
			     sizeof(pSessionDesc->stateRegistersDecomp));
	}

	/* Get physical address of E2E CRC buffer */
	pSessionDesc->physDataIntegrityCrcs = (icp_qat_addr_width_t)
	    LAC_OS_VIRT_TO_PHYS_EXTERNAL(pService->generic_service_info,
					 &pSessionDesc->dataIntegrityCrcs);
	if (0 == pSessionDesc->physDataIntegrityCrcs) {
		QAT_UTILS_LOG(
		    "Unable to get the physical address of Data Integrity buffer.\n");
		return CPA_STATUS_FAIL;
	}
	/* Initialize default CRC parameters */
	pDataIntegrityCrcs = &pSessionDesc->dataIntegrityCrcs;
	pDataIntegrityCrcs->crc32 = 0;
	pDataIntegrityCrcs->adler32 = 1;

	if (isDcGen2x(pService)) {
		pDataIntegrityCrcs->oCrc32Cpr = DC_INVALID_CRC;
		pDataIntegrityCrcs->iCrc32Cpr = DC_INVALID_CRC;
		pDataIntegrityCrcs->oCrc32Xlt = DC_INVALID_CRC;
		pDataIntegrityCrcs->iCrc32Xlt = DC_INVALID_CRC;
		pDataIntegrityCrcs->xorFlags = DC_XOR_FLAGS_DEFAULT;
		pDataIntegrityCrcs->crcPoly = DC_CRC_POLY_DEFAULT;
		pDataIntegrityCrcs->xorOut = DC_XOR_OUT_DEFAULT;
	} else {
		pDataIntegrityCrcs->iCrc64Cpr = DC_INVALID_CRC;
		pDataIntegrityCrcs->oCrc64Cpr = DC_INVALID_CRC;
		pDataIntegrityCrcs->iCrc64Xlt = DC_INVALID_CRC;
		pDataIntegrityCrcs->oCrc64Xlt = DC_INVALID_CRC;
		pDataIntegrityCrcs->crc64Poly = DC_CRC64_POLY_DEFAULT;
		pDataIntegrityCrcs->xor64Out = DC_XOR64_OUT_DEFAULT;
	}

	/* Initialise seed checksums.
	 * It initializes swCrc32I, swCrc32O, too(union).
	 */
	pSessionDesc->seedSwCrc.swCrc64I = 0;
	pSessionDesc->seedSwCrc.swCrc64O = 0;

	/* Populate the cmdFlags */
	switch (pSessionDesc->autoSelectBestHuffmanTree) {
	case CPA_DC_ASB_DISABLED:
		break;
	case CPA_DC_ASB_STATIC_DYNAMIC:
		autoSelectBest = ICP_QAT_FW_COMP_AUTO_SELECT_BEST;
		break;
	case CPA_DC_ASB_UNCOMP_STATIC_DYNAMIC_WITH_STORED_HDRS:
		autoSelectBest = ICP_QAT_FW_COMP_AUTO_SELECT_BEST;
		enhancedAutoSelectBest = ICP_QAT_FW_COMP_ENH_AUTO_SELECT_BEST;
		break;
	case CPA_DC_ASB_UNCOMP_STATIC_DYNAMIC_WITH_NO_HDRS:
		autoSelectBest = ICP_QAT_FW_COMP_AUTO_SELECT_BEST;
		enhancedAutoSelectBest = ICP_QAT_FW_COMP_ENH_AUTO_SELECT_BEST;
		disableType0EnhancedAutoSelectBest =
		    ICP_QAT_FW_COMP_DISABLE_TYPE0_ENH_AUTO_SELECT_BEST;
		break;
	case CPA_DC_ASB_ENABLED:
		if (pService->comp_device_data.asbEnableSupport == CPA_FALSE) {
			autoSelectBest = ICP_QAT_FW_COMP_AUTO_SELECT_BEST;
			enhancedAutoSelectBest =
			    ICP_QAT_FW_COMP_ENH_AUTO_SELECT_BEST;
		}
		break;
	default:
		break;
	}

	rpCmdFlags = ICP_QAT_FW_COMP_REQ_PARAM_FLAGS_BUILD(
	    ICP_QAT_FW_COMP_SOP,
	    ICP_QAT_FW_COMP_EOP,
	    ICP_QAT_FW_COMP_BFINAL,
	    ICP_QAT_FW_COMP_NO_CNV,
	    ICP_QAT_FW_COMP_NO_CNV_RECOVERY,
	    ICP_QAT_FW_COMP_NO_CNV_DFX,
	    ICP_QAT_FW_COMP_CRC_MODE_LEGACY);

	cmdFlags =
	    ICP_QAT_FW_COMP_FLAGS_BUILD(sessType,
					autoSelectBest,
					enhancedAutoSelectBest,
					disableType0EnhancedAutoSelectBest,
					secureRam);

	if (CPA_DC_DIR_DECOMPRESS != pSessionData->sessDirection) {
		status = dcGetCompressCommandId(pService,
						pSessionData,
						(Cpa8U *)&dcCmdId);
		if (CPA_STATUS_SUCCESS != status) {
			QAT_UTILS_LOG(
			    "Couldn't get compress command ID for current "
			    "session data.");

			return status;
		}
		pReqCache = &(pSessionDesc->reqCacheComp);
		pReqCache->comp_pars.req_par_flags = rpCmdFlags;
		pReqCache->comp_pars.crc.legacy.initial_adler = 1;
		pReqCache->comp_pars.crc.legacy.initial_crc32 = 0;

		/* Populate header of the common request message */
		SalQatMsg_CmnHdrWrite((icp_qat_fw_comn_req_t *)pReqCache,
				      ICP_QAT_FW_COMN_REQ_CPM_FW_COMP,
				      (uint8_t)dcCmdId,
				      cmnRequestFlags,
				      cmdFlags);
	}

	if (CPA_DC_DIR_COMPRESS != pSessionData->sessDirection) {
		status = dcGetDecompressCommandId(pService,
						  pSessionData,
						  (Cpa8U *)&dcCmdId);
		if (CPA_STATUS_SUCCESS != status) {
			QAT_UTILS_LOG(
			    "Couldn't get decompress command ID for current "
			    "session data.");

			return status;
		}
		pReqCache = &(pSessionDesc->reqCacheDecomp);
		pReqCache->comp_pars.req_par_flags = rpCmdFlags;
		pReqCache->comp_pars.crc.legacy.initial_adler = 1;
		pReqCache->comp_pars.crc.legacy.initial_crc32 = 0;

		/* Populate header of the common request message */
		SalQatMsg_CmnHdrWrite((icp_qat_fw_comn_req_t *)pReqCache,
				      ICP_QAT_FW_COMN_REQ_CPM_FW_COMP,
				      (uint8_t)dcCmdId,
				      cmnRequestFlags,
				      cmdFlags);
	}

	return status;
}

CpaStatus
cpaDcInitSession(CpaInstanceHandle dcInstance,
		 CpaDcSessionHandle pSessionHandle,
		 CpaDcSessionSetupData *pSessionData,
		 CpaBufferList *pContextBuffer,
		 CpaDcCallbackFn callbackFn)
{
	CpaInstanceHandle insHandle = NULL;
	sal_compression_service_t *pService = NULL;

	if (CPA_INSTANCE_HANDLE_SINGLE == dcInstance) {
		insHandle = dcGetFirstHandle();
	} else {
		insHandle = dcInstance;
	}

	LAC_CHECK_INSTANCE_HANDLE(insHandle);
	SAL_CHECK_INSTANCE_TYPE(insHandle, SAL_SERVICE_TYPE_COMPRESSION);

	pService = (sal_compression_service_t *)insHandle;

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

	return dcInitSession(insHandle,
			     pSessionHandle,
			     pSessionData,
			     pContextBuffer,
			     callbackFn);
}

CpaStatus
cpaDcResetSession(const CpaInstanceHandle dcInstance,
		  CpaDcSessionHandle pSessionHandle)
{
	CpaStatus status = CPA_STATUS_SUCCESS;
	CpaInstanceHandle insHandle = NULL;
	sal_compression_service_t *pService = NULL;
	dc_session_desc_t *pSessionDesc = NULL;
	Cpa64U numPendingStateless = 0;
	Cpa64U numPendingStateful = 0;
	icp_comms_trans_handle trans_handle = NULL;
	dc_integrity_crc_fw_t *pDataIntegrityCrcs = NULL;
	dc_sw_checksums_t *pSwCrcs = NULL;

	LAC_CHECK_NULL_PARAM(pSessionHandle);
	pSessionDesc = DC_SESSION_DESC_FROM_CTX_GET(pSessionHandle);
	LAC_CHECK_NULL_PARAM(pSessionDesc);

	if (CPA_TRUE == pSessionDesc->isDcDp) {
		insHandle = dcInstance;
	} else {
		if (CPA_INSTANCE_HANDLE_SINGLE == dcInstance) {
			insHandle = dcGetFirstHandle();
		} else {
			insHandle = dcInstance;
		}
	}
	LAC_CHECK_NULL_PARAM(insHandle);
	SAL_CHECK_INSTANCE_TYPE(insHandle, SAL_SERVICE_TYPE_COMPRESSION);
	/* Check if SAL is running otherwise return an error */
	SAL_RUNNING_CHECK(insHandle);
	if (CPA_TRUE == pSessionDesc->isDcDp) {
		trans_handle = ((sal_compression_service_t *)insHandle)
				   ->trans_handle_compression_tx;
		if (CPA_TRUE == icp_adf_queueDataToSend(trans_handle)) {
			/* Process the remaining messages on the ring */
			SalQatMsg_updateQueueTail(trans_handle);
			QAT_UTILS_LOG(
			    "There are remaining messages on the ring\n");
			return CPA_STATUS_RETRY;
		}

		/* Check if there are stateless pending requests */
		if (0 != pSessionDesc->pendingDpStatelessCbCount) {
			QAT_UTILS_LOG(
			    "There are %llu stateless DP requests pending.\n",
			    (unsigned long long)
				pSessionDesc->pendingDpStatelessCbCount);
			return CPA_STATUS_RETRY;
		}
	} else {
		numPendingStateless =
		    qatUtilsAtomicGet(&(pSessionDesc->pendingStatelessCbCount));
		numPendingStateful =
		    qatUtilsAtomicGet(&(pSessionDesc->pendingStatefulCbCount));
		/* Check if there are stateless pending requests */
		if (0 != numPendingStateless) {
			QAT_UTILS_LOG(
			    "There are %llu stateless requests pending.\n",
			    (unsigned long long)numPendingStateless);
			return CPA_STATUS_RETRY;
		}
		/* Check if there are stateful pending requests */
		if (0 != numPendingStateful) {
			QAT_UTILS_LOG(
			    "There are %llu stateful requests pending.\n",
			    (unsigned long long)numPendingStateful);
			return CPA_STATUS_RETRY;
		}

		/* Reset pSessionDesc */
		pSessionDesc->requestType = DC_REQUEST_FIRST;
		pSessionDesc->cumulativeConsumedBytes = 0;
		if (CPA_DC_ADLER32 == pSessionDesc->checksumType) {
			pSessionDesc->previousChecksum = 1;
		} else {
			pSessionDesc->previousChecksum = 0;
		}
		pSessionDesc->cnvErrorInjection = ICP_QAT_FW_COMP_NO_CNV_DFX;

		/* Reset integrity CRCs to default parameters. */
		pDataIntegrityCrcs = &pSessionDesc->dataIntegrityCrcs;
		memset(pDataIntegrityCrcs, 0, sizeof(dc_integrity_crc_fw_t));
		pDataIntegrityCrcs->adler32 = 1;

		pService = (sal_compression_service_t *)insHandle;
		if (isDcGen2x(pService)) {
			pDataIntegrityCrcs->xorFlags = DC_XOR_FLAGS_DEFAULT;
			pDataIntegrityCrcs->crcPoly = DC_CRC_POLY_DEFAULT;
			pDataIntegrityCrcs->xorOut = DC_XOR_OUT_DEFAULT;
		} else {
			pDataIntegrityCrcs->crc64Poly = DC_CRC64_POLY_DEFAULT;
			pDataIntegrityCrcs->xor64Out = DC_XOR64_OUT_DEFAULT;
		}

		/* Reset seed SW checksums. */
		pSwCrcs = &pSessionDesc->seedSwCrc;
		memset(pSwCrcs, 0, sizeof(dc_sw_checksums_t));

		/* Reset integrity SW checksums. */
		pSwCrcs = &pSessionDesc->integritySwCrc;
		memset(pSwCrcs, 0, sizeof(dc_sw_checksums_t));
	}

	/* Reset the pending callback counters */
	qatUtilsAtomicSet(0, &pSessionDesc->pendingStatelessCbCount);
	qatUtilsAtomicSet(0, &pSessionDesc->pendingStatefulCbCount);
	pSessionDesc->pendingDpStatelessCbCount = 0;
	if (CPA_DC_STATEFUL == pSessionDesc->sessState) {
		LAC_OS_BZERO(&pSessionDesc->stateRegistersComp,
			     sizeof(pSessionDesc->stateRegistersComp));
		LAC_OS_BZERO(&pSessionDesc->stateRegistersDecomp,
			     sizeof(pSessionDesc->stateRegistersDecomp));
	}
	return status;
}

CpaStatus
cpaDcResetXXHashState(const CpaInstanceHandle dcInstance,
		      CpaDcSessionHandle pSessionHandle)
{
	return CPA_STATUS_UNSUPPORTED;
}

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

CpaStatus
cpaDcRemoveSession(const CpaInstanceHandle dcInstance,
		   CpaDcSessionHandle pSessionHandle)
{
	CpaStatus status = CPA_STATUS_SUCCESS;
	CpaInstanceHandle insHandle = NULL;
	dc_session_desc_t *pSessionDesc = NULL;
	Cpa64U numPendingStateless = 0;
	Cpa64U numPendingStateful = 0;
	icp_comms_trans_handle trans_handle = NULL;

	LAC_CHECK_NULL_PARAM(pSessionHandle);
	pSessionDesc = DC_SESSION_DESC_FROM_CTX_GET(pSessionHandle);
	LAC_CHECK_NULL_PARAM(pSessionDesc);

	if (CPA_TRUE == pSessionDesc->isDcDp) {
		insHandle = dcInstance;
	} else {
		if (CPA_INSTANCE_HANDLE_SINGLE == dcInstance) {
			insHandle = dcGetFirstHandle();
		} else {
			insHandle = dcInstance;
		}
	}

	LAC_CHECK_NULL_PARAM(insHandle);
	SAL_CHECK_INSTANCE_TYPE(insHandle, SAL_SERVICE_TYPE_COMPRESSION);

	/* Check if SAL is running otherwise return an error */
	SAL_RUNNING_CHECK(insHandle);

	if (CPA_TRUE == pSessionDesc->isDcDp) {
		trans_handle = ((sal_compression_service_t *)insHandle)
				   ->trans_handle_compression_tx;

		if (CPA_TRUE == icp_adf_queueDataToSend(trans_handle)) {
			/* Process the remaining messages on the ring */
			SalQatMsg_updateQueueTail(trans_handle);
			QAT_UTILS_LOG(
			    "There are remaining messages on the ring.\n");
			return CPA_STATUS_RETRY;
		}

		/* Check if there are stateless pending requests */
		if (0 != pSessionDesc->pendingDpStatelessCbCount) {
			QAT_UTILS_LOG(
			    "There are %llu stateless DP requests pending.\n",
			    (unsigned long long)
				pSessionDesc->pendingDpStatelessCbCount);
			return CPA_STATUS_RETRY;
		}
	} else {
		numPendingStateless =
		    qatUtilsAtomicGet(&(pSessionDesc->pendingStatelessCbCount));
		numPendingStateful =
		    qatUtilsAtomicGet(&(pSessionDesc->pendingStatefulCbCount));

		/* Check if there are stateless pending requests */
		if (0 != numPendingStateless) {
			QAT_UTILS_LOG(
			    "There are %llu stateless requests pending.\n",
			    (unsigned long long)numPendingStateless);
			status = CPA_STATUS_RETRY;
		}

		/* Check if there are stateful pending requests */
		if (0 != numPendingStateful) {
			QAT_UTILS_LOG(
			    "There are %llu stateful requests pending.\n",
			    (unsigned long long)numPendingStateful);
			status = CPA_STATUS_RETRY;
		}
		if ((CPA_DC_STATEFUL == pSessionDesc->sessState) &&
		    (CPA_STATUS_SUCCESS == status)) {
			LAC_SPINLOCK_DESTROY(&(pSessionDesc->sessionLock));
		}
	}

	return status;
}

CpaStatus
dcGetSessionSize(CpaInstanceHandle dcInstance,
		 CpaDcSessionSetupData *pSessionData,
		 Cpa32U *pSessionSize,
		 Cpa32U *pContextSize)
{

	CpaStatus status = CPA_STATUS_SUCCESS;
	CpaInstanceHandle insHandle = NULL;

	if (CPA_INSTANCE_HANDLE_SINGLE == dcInstance) {
		insHandle = dcGetFirstHandle();
	} else {
		insHandle = dcInstance;
	}

	/* Check parameters */
	LAC_CHECK_NULL_PARAM(insHandle);
	LAC_CHECK_NULL_PARAM(pSessionData);
	LAC_CHECK_NULL_PARAM(pSessionSize);

	if (dcCheckSessionData(pSessionData, insHandle) != CPA_STATUS_SUCCESS) {
		return CPA_STATUS_INVALID_PARAM;
	}

	/* Get session size for session data */
	*pSessionSize = sizeof(dc_session_desc_t) + LAC_64BYTE_ALIGNMENT +
	    sizeof(LAC_ARCH_UINT);

	if (NULL != pContextSize) {
		status =
		    dcGetContextSize(insHandle, pSessionData, pContextSize);

		if (CPA_STATUS_SUCCESS != status) {
			QAT_UTILS_LOG(
			    "Unable to get the context size of the session.\n");
			return CPA_STATUS_FAIL;
		}
	}

	return CPA_STATUS_SUCCESS;
}

CpaStatus
cpaDcGetSessionSize(CpaInstanceHandle dcInstance,
		    CpaDcSessionSetupData *pSessionData,
		    Cpa32U *pSessionSize,
		    Cpa32U *pContextSize)
{

	LAC_CHECK_NULL_PARAM(pContextSize);

	return dcGetSessionSize(dcInstance,
				pSessionData,
				pSessionSize,
				pContextSize);
}

CpaStatus
dcSetCnvError(CpaInstanceHandle dcInstance, CpaDcSessionHandle pSessionHandle)
{
	LAC_CHECK_NULL_PARAM(pSessionHandle);

	dc_session_desc_t *pSessionDesc = NULL;
	CpaInstanceHandle insHandle = NULL;
	sal_compression_service_t *pService = NULL;

	if (CPA_INSTANCE_HANDLE_SINGLE == dcInstance) {
		insHandle = dcGetFirstHandle();
	} else {
		insHandle = dcInstance;
	}

	pService = (sal_compression_service_t *)insHandle;

	if (isDcGen2x(pService)) {
		QAT_UTILS_LOG("Unsupported compression feature.\n");
		return CPA_STATUS_UNSUPPORTED;
	}
	pSessionDesc = DC_SESSION_DESC_FROM_CTX_GET(pSessionHandle);

	LAC_CHECK_NULL_PARAM(pSessionDesc);

	pSessionDesc->cnvErrorInjection = ICP_QAT_FW_COMP_CNV_DFX;

	return CPA_STATUS_SUCCESS;
}
