/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright(c) 2007-2025 Intel Corporation */

/**
 ***************************************************************************
 * @file sal_crypto.c     Instance handling functions for crypto
 *
 * @ingroup SalCtrl
 *
 ***************************************************************************/

/*
*******************************************************************************
* Include public/global header files
*******************************************************************************
*/

/* QAT-API includes */
#include "cpa.h"
#include "cpa_types.h"
#include "cpa_cy_common.h"
#include "cpa_cy_im.h"
#include "cpa_cy_key.h"
#include "cpa_cy_sym.h"

#include "qat_utils.h"

/* ADF includes */
#include "icp_adf_init.h"
#include "icp_adf_transport.h"
#include "icp_accel_devices.h"
#include "icp_adf_cfg.h"
#include "icp_adf_accel_mgr.h"
#include "icp_adf_poll.h"
#include "icp_adf_debug.h"

/* SAL includes */
#include "lac_log.h"
#include "lac_mem.h"
#include "lac_mem_pools.h"
#include "sal_statistics.h"
#include "lac_common.h"
#include "lac_list.h"
#include "lac_hooks.h"
#include "lac_sym_qat_hash_defs_lookup.h"
#include "lac_sym.h"
#include "lac_sym_key.h"
#include "lac_sym_hash.h"
#include "lac_sym_cb.h"
#include "lac_sym_stats.h"
#include "lac_sal_types_crypto.h"
#include "lac_sal.h"
#include "lac_sal_ctrl.h"
#include "sal_string_parse.h"
#include "sal_service_state.h"
#include "icp_sal_poll.h"
#include "lac_sync.h"
#include "lac_sym_qat.h"
#include "icp_sal_versions.h"
#include "icp_sal_user.h"
#include "sal_hw_gen.h"

#define HMAC_MODE_1 1
#define HMAC_MODE_2 2
#define TH_CY_RX_0 0
#define TH_CY_RX_1 1
#define MAX_CY_RX_RINGS 2

#define DOUBLE_INCR 2

#define TH_SINGLE_RX 0
#define NUM_CRYPTO_SYM_RX_RINGS 1
#define NUM_CRYPTO_ASYM_RX_RINGS 1
#define NUM_CRYPTO_NRBG_RX_RINGS 1

CpaStatus Lac_GetCyInstancesByType(
    const CpaAccelerationServiceType accelerationServiceType,
    Cpa16U numInstances,
    CpaInstanceHandle *pInstances);

CpaStatus Lac_GetCyNumInstancesByType(
    const CpaAccelerationServiceType accelerationServiceType,
    Cpa16U *pNumInstances);

static CpaInstanceHandle
Lac_CryptoGetFirstHandle(void)
{
	CpaInstanceHandle instHandle;
	instHandle = Lac_GetFirstHandle(SAL_SERVICE_TYPE_CRYPTO);
	if (!instHandle) {
		instHandle = Lac_GetFirstHandle(SAL_SERVICE_TYPE_CRYPTO_SYM);
		if (!instHandle) {
			instHandle =
			    Lac_GetFirstHandle(SAL_SERVICE_TYPE_CRYPTO_ASYM);
		}
	}
	return instHandle;
}

/* Function to release the sym handles. */
static CpaStatus
SalCtrl_SymReleaseTransHandle(sal_service_t *service)
{

	CpaStatus status = CPA_STATUS_SUCCESS;
	CpaStatus ret_status = CPA_STATUS_SUCCESS;
	sal_crypto_service_t *pCryptoService = (sal_crypto_service_t *)service;

	if (NULL != pCryptoService->trans_handle_sym_tx) {
		status = icp_adf_transReleaseHandle(
		    pCryptoService->trans_handle_sym_tx);
		if (CPA_STATUS_SUCCESS != status) {
			ret_status = status;
		}
	}
	if (NULL != pCryptoService->trans_handle_sym_rx) {
		status = icp_adf_transReleaseHandle(
		    pCryptoService->trans_handle_sym_rx);
		if (CPA_STATUS_SUCCESS != status) {
			ret_status = status;
		}
	}

	return ret_status;
}

/*
 * @ingroup sal_crypto
 *     Frees resources (memory and transhandles) if allocated
 *
 * @param[in]  pCryptoService       Pointer to sym service instance
 * @retval                          SUCCESS if transhandles released
 *                                  successfully.
*/
static CpaStatus
SalCtrl_SymFreeResources(sal_crypto_service_t *pCryptoService)
{

	CpaStatus status = CPA_STATUS_SUCCESS;

	/* Free memory pools if not NULL */
	Lac_MemPoolDestroy(pCryptoService->lac_sym_cookie_pool);

	/* Free misc memory if allocated */
	/* Frees memory allocated for Hmac precomputes */
	LacSymHash_HmacPrecompShutdown(pCryptoService);
	/* Free memory allocated for key labels
	   Also clears key stats  */
	LacSymKey_Shutdown(pCryptoService);
	/* Free hash lookup table if allocated */
	if (NULL != pCryptoService->pLacHashLookupDefs) {
		LAC_OS_FREE(pCryptoService->pLacHashLookupDefs);
	}

	/* Free statistics */
	LacSym_StatsFree(pCryptoService);

	/* Free transport handles */
	status = SalCtrl_SymReleaseTransHandle((sal_service_t *)pCryptoService);
	return status;
}

/**
 ***********************************************************************
 * @ingroup SalCtrl
 *   This macro verifies that the status is _SUCCESS
 *   If status is not _SUCCESS then Sym Instance resources are
 *   freed before the function returns the error
 *
 * @param[in] status    status we are checking
 *
 * @return void         status is ok (CPA_STATUS_SUCCESS)
 * @return status       The value in the status parameter is an error one
 *
 ****************************************************************************/
#define LAC_CHECK_STATUS_SYM_INIT(status)                                      \
	do {                                                                   \
		if (CPA_STATUS_SUCCESS != status) {                            \
			SalCtrl_SymFreeResources(pCryptoService);              \
			return status;                                         \
		}                                                              \
	} while (0)

/* Function that creates the Sym Handles. */
static CpaStatus
SalCtrl_SymCreateTransHandle(icp_accel_dev_t *device,
			     sal_service_t *service,
			     Cpa32U numSymRequests,
			     char *section)
{
	CpaStatus status = CPA_STATUS_SUCCESS;
	char temp_string[SAL_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 };
	sal_crypto_service_t *pCryptoService = (sal_crypto_service_t *)service;
	icp_resp_deliv_method rx_resp_type = ICP_RESP_TYPE_IRQ;
	Cpa32U msgSize = 0;

	if (SAL_RESP_POLL_CFG_FILE == pCryptoService->isPolled) {
		rx_resp_type = ICP_RESP_TYPE_POLL;
	}

	if (CPA_FALSE == pCryptoService->generic_service_info.is_dyn) {
		section = icpGetProcessName();
	}

	/* Parse Sym ring details */
	status =
	    Sal_StringParsing("Cy",
			      pCryptoService->generic_service_info.instance,
			      "RingSymTx",
			      temp_string);

	/* Need to free resources in case not _SUCCESS from here */
	LAC_CHECK_STATUS_SYM_INIT(status);

	msgSize = LAC_QAT_SYM_REQ_SZ_LW * LAC_LONG_WORD_IN_BYTES;
	status =
	    icp_adf_transCreateHandle(device,
				      ICP_TRANS_TYPE_ETR,
				      section,
				      pCryptoService->acceleratorNum,
				      pCryptoService->bankNumSym,
				      temp_string,
				      lac_getRingType(SAL_RING_TYPE_A_SYM_HI),
				      NULL,
				      ICP_RESP_TYPE_NONE,
				      numSymRequests,
				      msgSize,
				      (icp_comms_trans_handle *)&(
					  pCryptoService->trans_handle_sym_tx));
	LAC_CHECK_STATUS_SYM_INIT(status);

	status =
	    Sal_StringParsing("Cy",
			      pCryptoService->generic_service_info.instance,
			      "RingSymRx",
			      temp_string);
	LAC_CHECK_STATUS_SYM_INIT(status);

	msgSize = LAC_QAT_SYM_RESP_SZ_LW * LAC_LONG_WORD_IN_BYTES;
	status = icp_adf_transCreateHandle(
	    device,
	    ICP_TRANS_TYPE_ETR,
	    section,
	    pCryptoService->acceleratorNum,
	    pCryptoService->bankNumSym,
	    temp_string,
	    lac_getRingType(SAL_RING_TYPE_NONE),
	    (icp_trans_callback)LacSymQat_SymRespHandler,
	    rx_resp_type,
	    numSymRequests,
	    msgSize,
	    (icp_comms_trans_handle *)&(pCryptoService->trans_handle_sym_rx));
	LAC_CHECK_STATUS_SYM_INIT(status);

	return status;
}

static int
SalCtrl_CryptoDebug(void *private_data, char *data, int size, int offset)
{
	CpaStatus status = CPA_STATUS_SUCCESS;
	Cpa32U len = 0;
	sal_crypto_service_t *pCryptoService =
	    (sal_crypto_service_t *)private_data;

	switch (offset) {
	case SAL_STATS_SYM: {
		CpaCySymStats64 symStats = { 0 };
		if (CPA_TRUE !=
		    pCryptoService->generic_service_info.stats
			->bSymStatsEnabled) {
			break;
		}
		status = cpaCySymQueryStats64(pCryptoService, &symStats);
		if (status != CPA_STATUS_SUCCESS) {
			LAC_LOG_ERROR("cpaCySymQueryStats64 returned error\n");
			return 0;
		}

		/* Engine Info */
		len += snprintf(
		    data + len,
		    size - len,
		    SEPARATOR BORDER
		    " Statistics for Instance %24s |\n" BORDER
		    " Symmetric Stats                                  " BORDER
		    "\n" SEPARATOR,
		    pCryptoService->debug_file->name);

		/* Session Info */
		len += snprintf(
		    data + len,
		    size - len,
		    BORDER " Sessions Initialized:           %16llu " BORDER
			   "\n" BORDER
			   " Sessions Removed:               %16llu " BORDER
			   "\n" BORDER
			   " Session Errors:                 %16llu " BORDER
			   "\n" SEPARATOR,
		    (long long unsigned int)symStats.numSessionsInitialized,
		    (long long unsigned int)symStats.numSessionsRemoved,
		    (long long unsigned int)symStats.numSessionErrors);

		/* Session info */
		len += snprintf(
		    data + len,
		    size - len,
		    BORDER " Symmetric Requests:             %16llu " BORDER
			   "\n" BORDER
			   " Symmetric Request Errors:       %16llu " BORDER
			   "\n" BORDER
			   " Symmetric Completed:            %16llu " BORDER
			   "\n" BORDER
			   " Symmetric Completed Errors:     %16llu " BORDER
			   "\n" BORDER
			   " Symmetric Verify Failures:      %16llu " BORDER
			   "\n",
		    (long long unsigned int)symStats.numSymOpRequests,
		    (long long unsigned int)symStats.numSymOpRequestErrors,
		    (long long unsigned int)symStats.numSymOpCompleted,
		    (long long unsigned int)symStats.numSymOpCompletedErrors,
		    (long long unsigned int)symStats.numSymOpVerifyFailures);
		break;
	}
	default: {
		len += snprintf(data + len, size - len, SEPARATOR);
		return 0;
	}
	}
	return ++offset;
}

static CpaStatus
SalCtrl_SymInit(icp_accel_dev_t *device, sal_service_t *service)
{
	CpaStatus status = CPA_STATUS_SUCCESS;
	Cpa32U qatHmacMode = 0;
	Cpa32U numSymConcurrentReq = 0;
	char adfGetParam[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 };
	char temp_string[SAL_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 };
	sal_crypto_service_t *pCryptoService = (sal_crypto_service_t *)service;
	char *section = DYN_SEC;

	/*Instance may not in the DYN section*/
	if (CPA_FALSE == pCryptoService->generic_service_info.is_dyn) {
		section = icpGetProcessName();
	}

	/* Register callbacks for the symmetric services
	* (Hash, Cipher, Algorithm-Chaining) (returns void)*/
	LacSymCb_CallbacksRegister();

	qatHmacMode = (Cpa32U)Sal_Strtoul(adfGetParam, NULL, SAL_CFG_BASE_DEC);
	switch (qatHmacMode) {
	case HMAC_MODE_1:
		pCryptoService->qatHmacMode = ICP_QAT_HW_AUTH_MODE1;
		break;
	case HMAC_MODE_2:
		pCryptoService->qatHmacMode = ICP_QAT_HW_AUTH_MODE2;
		break;
	default:
		pCryptoService->qatHmacMode = ICP_QAT_HW_AUTH_MODE1;
		break;
	}

	/* Get num concurrent requests from config file */
	status =
	    Sal_StringParsing("Cy",
			      pCryptoService->generic_service_info.instance,
			      "NumConcurrentSymRequests",
			      temp_string);
	LAC_CHECK_STATUS(status);
	status =
	    icp_adf_cfgGetParamValue(device, section, temp_string, adfGetParam);
	if (CPA_STATUS_SUCCESS != status) {
		QAT_UTILS_LOG("Failed to get %s from configuration file\n",
			      temp_string);
		return status;
	}

	numSymConcurrentReq =
	    (Cpa32U)Sal_Strtoul(adfGetParam, NULL, SAL_CFG_BASE_DEC);
	if (CPA_STATUS_FAIL == validateConcurrRequest(numSymConcurrentReq)) {
		LAC_LOG_ERROR("Invalid NumConcurrentSymRequests, valid "
			      "values {64, 128, 256, ... 32768, 65536}");
		return CPA_STATUS_FAIL;
	}

	/* ADF does not allow us to completely fill the ring for batch requests
	 */
	pCryptoService->maxNumSymReqBatch =
	    (numSymConcurrentReq - SAL_BATCH_SUBMIT_FREE_SPACE);

	/* Create transport handles */
	status = SalCtrl_SymCreateTransHandle(device,
					      service,
					      numSymConcurrentReq,
					      section);
	LAC_CHECK_STATUS(status);

	/* Allocates memory pools */

	/* Create and initialise symmetric cookie memory pool */
	pCryptoService->lac_sym_cookie_pool = LAC_MEM_POOL_INIT_POOL_ID;
	status =
	    Sal_StringParsing("Cy",
			      pCryptoService->generic_service_info.instance,
			      "SymPool",
			      temp_string);
	LAC_CHECK_STATUS_SYM_INIT(status);
	/* Note we need twice (i.e. <<1) the number of sym cookies to
	   support sym ring pairs (and some, for partials) */
	status =
	    Lac_MemPoolCreate(&pCryptoService->lac_sym_cookie_pool,
			      temp_string,
			      ((numSymConcurrentReq + numSymConcurrentReq + 1)
			       << 1),
			      sizeof(lac_sym_cookie_t),
			      LAC_64BYTE_ALIGNMENT,
			      CPA_FALSE,
			      pCryptoService->nodeAffinity);
	LAC_CHECK_STATUS_SYM_INIT(status);
	/* For all sym cookies fill out the physical address of data that
	   will be set to QAT */
	Lac_MemPoolInitSymCookiesPhyAddr(pCryptoService->lac_sym_cookie_pool);

	/* Clear stats */
	/* Clears Key stats and allocate memory of SSL and TLS labels
	    These labels are initialised to standard values */
	status = LacSymKey_Init(pCryptoService);
	LAC_CHECK_STATUS_SYM_INIT(status);

	/* Initialises the hash lookup table*/
	status = LacSymQat_Init(pCryptoService);
	LAC_CHECK_STATUS_SYM_INIT(status);

	/* Fills out content descriptor for precomputes and registers the
	   hash precompute callback */
	status = LacSymHash_HmacPrecompInit(pCryptoService);
	LAC_CHECK_STATUS_SYM_INIT(status);

	/* Init the Sym stats */
	status = LacSym_StatsInit(pCryptoService);
	LAC_CHECK_STATUS_SYM_INIT(status);

	return status;
}

static void
SalCtrl_DebugShutdown(icp_accel_dev_t *device, sal_service_t *service)
{
	sal_crypto_service_t *pCryptoService = (sal_crypto_service_t *)service;
	sal_statistics_collection_t *pStatsCollection =
	    (sal_statistics_collection_t *)device->pQatStats;

	if (CPA_TRUE == pStatsCollection->bStatsEnabled) {
		/* Clean stats */
		if (NULL != pCryptoService->debug_file) {
			icp_adf_debugRemoveFile(pCryptoService->debug_file);
			LAC_OS_FREE(pCryptoService->debug_file->name);
			LAC_OS_FREE(pCryptoService->debug_file);
			pCryptoService->debug_file = NULL;
		}
	}
	pCryptoService->generic_service_info.stats = NULL;
}

static CpaStatus
SalCtrl_DebugInit(icp_accel_dev_t *device, sal_service_t *service)
{
	char adfGetParam[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 };
	char temp_string[SAL_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 };
	char *instance_name = NULL;
	sal_crypto_service_t *pCryptoService = (sal_crypto_service_t *)service;
	sal_statistics_collection_t *pStatsCollection =
	    (sal_statistics_collection_t *)device->pQatStats;
	CpaStatus status = CPA_STATUS_SUCCESS;
	char *section = DYN_SEC;

	/*Instance may not in the DYN section*/
	if (CPA_FALSE == pCryptoService->generic_service_info.is_dyn) {
		section = icpGetProcessName();
	}

	if (CPA_TRUE == pStatsCollection->bStatsEnabled) {
		/* Get instance name for stats */
		instance_name = LAC_OS_MALLOC(ADF_CFG_MAX_VAL_LEN_IN_BYTES);
		if (NULL == instance_name) {
			return CPA_STATUS_RESOURCE;
		}

		status = Sal_StringParsing(
		    "Cy",
		    pCryptoService->generic_service_info.instance,
		    "Name",
		    temp_string);
		if (CPA_STATUS_SUCCESS != status) {
			LAC_OS_FREE(instance_name);
			return status;
		}
		status = icp_adf_cfgGetParamValue(device,
						  section,
						  temp_string,
						  adfGetParam);
		if (CPA_STATUS_SUCCESS != status) {
			QAT_UTILS_LOG(
			    "Failed to get %s from configuration file\n",
			    temp_string);
			LAC_OS_FREE(instance_name);
			return status;
		}
		snprintf(instance_name,
			 ADF_CFG_MAX_VAL_LEN_IN_BYTES,
			 "%s",
			 adfGetParam);

		pCryptoService->debug_file =
		    LAC_OS_MALLOC(sizeof(debug_file_info_t));
		if (NULL == pCryptoService->debug_file) {
			LAC_OS_FREE(instance_name);
			return CPA_STATUS_RESOURCE;
		}

		memset(pCryptoService->debug_file,
		       0,
		       sizeof(debug_file_info_t));
		pCryptoService->debug_file->name = instance_name;
		pCryptoService->debug_file->seq_read = SalCtrl_CryptoDebug;
		pCryptoService->debug_file->private_data = pCryptoService;
		pCryptoService->debug_file->parent =
		    pCryptoService->generic_service_info.debug_parent_dir;

		status =
		    icp_adf_debugAddFile(device, pCryptoService->debug_file);
		if (CPA_STATUS_SUCCESS != status) {
			LAC_OS_FREE(instance_name);
			LAC_OS_FREE(pCryptoService->debug_file);
			return status;
		}
	}
	pCryptoService->generic_service_info.stats = pStatsCollection;

	return status;
}

static CpaStatus
SalCtrl_GetBankNum(icp_accel_dev_t *device,
		   Cpa32U inst,
		   char *section,
		   char *bank_name,
		   Cpa16U *bank)
{
	char adfParamValue[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 };
	char adfParamName[SAL_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 };
	CpaStatus status = CPA_STATUS_SUCCESS;

	status = Sal_StringParsing("Cy", inst, bank_name, adfParamName);
	LAC_CHECK_STATUS(status);
	status = icp_adf_cfgGetParamValue(device,
					  section,
					  adfParamName,
					  adfParamValue);
	if (CPA_STATUS_SUCCESS != status) {
		QAT_UTILS_LOG("Failed to get %s from configuration file\n",
			      adfParamName);
		return status;
	}
	*bank = (Cpa16U)Sal_Strtoul(adfParamValue, NULL, SAL_CFG_BASE_DEC);
	return status;
}

static CpaStatus
SalCtr_InstInit(icp_accel_dev_t *device, sal_service_t *service)
{
	char adfGetParam[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 };
	char temp_string[SAL_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 };
	char temp_string2[SAL_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 };
	sal_crypto_service_t *pCryptoService = (sal_crypto_service_t *)service;
	CpaStatus status = CPA_STATUS_SUCCESS;
	char *section = DYN_SEC;

	/*Instance may not in the DYN section*/
	if (CPA_FALSE == pCryptoService->generic_service_info.is_dyn) {
		section = icpGetProcessName();
	}

	/* Get Config Info: Accel Num, bank Num, packageID,
				coreAffinity, nodeAffinity and response mode */

	pCryptoService->acceleratorNum = 0;

	/* Gen4, a bank only has 2 rings (1 ring pair), only one type of service
	   can be assigned one time. asym and sym will be in different bank*/
	if (isCyGen4x(pCryptoService)) {
		switch (service->type) {
		case SAL_SERVICE_TYPE_CRYPTO_ASYM:
			status = SalCtrl_GetBankNum(
			    device,
			    pCryptoService->generic_service_info.instance,
			    section,
			    "BankNumberAsym",
			    &pCryptoService->bankNumAsym);
			if (CPA_STATUS_SUCCESS != status)
				return status;
			break;
		case SAL_SERVICE_TYPE_CRYPTO_SYM:
			status = SalCtrl_GetBankNum(
			    device,
			    pCryptoService->generic_service_info.instance,
			    section,
			    "BankNumberSym",
			    &pCryptoService->bankNumSym);
			if (CPA_STATUS_SUCCESS != status)
				return status;
			break;
		case SAL_SERVICE_TYPE_CRYPTO:
			status = SalCtrl_GetBankNum(
			    device,
			    pCryptoService->generic_service_info.instance,
			    section,
			    "BankNumberAsym",
			    &pCryptoService->bankNumAsym);
			if (CPA_STATUS_SUCCESS != status)
				return status;
			status = SalCtrl_GetBankNum(
			    device,
			    pCryptoService->generic_service_info.instance,
			    section,
			    "BankNumberSym",
			    &pCryptoService->bankNumSym);
			if (CPA_STATUS_SUCCESS != status)
				return status;
			break;
		default:
			return CPA_STATUS_FAIL;
		}
	} else {
		status = SalCtrl_GetBankNum(
		    device,
		    pCryptoService->generic_service_info.instance,
		    section,
		    "BankNumber",
		    &pCryptoService->bankNumSym);
		if (CPA_STATUS_SUCCESS != status)
			return status;
		pCryptoService->bankNumAsym = pCryptoService->bankNumSym;
	}

	status =
	    Sal_StringParsing("Cy",
			      pCryptoService->generic_service_info.instance,
			      "IsPolled",
			      temp_string);
	LAC_CHECK_STATUS(status);
	status =
	    icp_adf_cfgGetParamValue(device, section, temp_string, adfGetParam);
	if (CPA_STATUS_SUCCESS != status) {
		QAT_UTILS_LOG("Failed to get %s from configuration file\n",
			      temp_string);
		return status;
	}
	pCryptoService->isPolled =
	    (Cpa8U)Sal_Strtoul(adfGetParam, NULL, SAL_CFG_BASE_DEC);

	/* Kernel instances do not support epoll mode */
	if (SAL_RESP_EPOLL_CFG_FILE == pCryptoService->isPolled) {
		QAT_UTILS_LOG(
		    "IsPolled %u is not supported for kernel instance %s",
		    pCryptoService->isPolled,
		    temp_string);
		return CPA_STATUS_FAIL;
	}

	status = icp_adf_cfgGetParamValue(device,
					  LAC_CFG_SECTION_GENERAL,
					  ADF_DEV_PKG_ID,
					  adfGetParam);
	if (CPA_STATUS_SUCCESS != status) {
		QAT_UTILS_LOG("Failed to get %s from configuration file\n",
			      ADF_DEV_PKG_ID);
		return status;
	}
	pCryptoService->pkgID =
	    (Cpa16U)Sal_Strtoul(adfGetParam, NULL, SAL_CFG_BASE_DEC);

	status = icp_adf_cfgGetParamValue(device,
					  LAC_CFG_SECTION_GENERAL,
					  ADF_DEV_NODE_ID,
					  adfGetParam);
	if (CPA_STATUS_SUCCESS != status) {
		QAT_UTILS_LOG("Failed to get %s from configuration file\n",
			      ADF_DEV_NODE_ID);
		return status;
	}
	pCryptoService->nodeAffinity =
	    (Cpa32U)Sal_Strtoul(adfGetParam, NULL, SAL_CFG_BASE_DEC);
	/* In case of interrupt instance, use the bank affinity set by adf_ctl
	 * Otherwise, use the instance affinity for backwards compatibility */
	if (SAL_RESP_POLL_CFG_FILE != pCryptoService->isPolled) {
		/* Next need to read the [AcceleratorX] section of the config
		 * file */
		status = Sal_StringParsing("Accelerator",
					   pCryptoService->acceleratorNum,
					   "",
					   temp_string2);
		LAC_CHECK_STATUS(status);
		if (service->type == SAL_SERVICE_TYPE_CRYPTO_ASYM)
			status = Sal_StringParsing("Bank",
						   pCryptoService->bankNumAsym,
						   "CoreAffinity",
						   temp_string);
		else
			/* For cy service, asym bank and sym bank will set the
			   same core affinity. So Just read one*/
			status = Sal_StringParsing("Bank",
						   pCryptoService->bankNumSym,
						   "CoreAffinity",
						   temp_string);
		LAC_CHECK_STATUS(status);
	} else {
		strncpy(temp_string2, section, (strlen(section) + 1));
		status = Sal_StringParsing(
		    "Cy",
		    pCryptoService->generic_service_info.instance,
		    "CoreAffinity",
		    temp_string);
		LAC_CHECK_STATUS(status);
	}

	status = icp_adf_cfgGetParamValue(device,
					  temp_string2,
					  temp_string,
					  adfGetParam);
	if (CPA_STATUS_SUCCESS != status) {
		QAT_UTILS_LOG("Failed to get %s from configuration file\n",
			      temp_string);
		return status;
	}
	pCryptoService->coreAffinity =
	    (Cpa32U)Sal_Strtoul(adfGetParam, NULL, SAL_CFG_BASE_DEC);

	/*No Execution Engine in DH895xcc, so make sure it is zero*/
	pCryptoService->executionEngine = 0;

	return status;
}

/* This function:
 * 1. Creates sym and asym transport handles
 * 2. Allocates memory pools required by sym and asym services
.* 3. Clears the sym and asym stats counters
 * 4. In case service asym or sym is enabled then this function
 *    only allocates resources for these services. i.e if the
 *    service asym is enabled then only asym transport handles
 *    are created and vice versa.
 */
CpaStatus
SalCtrl_CryptoInit(icp_accel_dev_t *device, sal_service_t *service)
{
	CpaStatus status = CPA_STATUS_SUCCESS;
	sal_crypto_service_t *pCryptoService = (sal_crypto_service_t *)service;
	sal_service_type_t svc_type = service->type;

	SAL_SERVICE_GOOD_FOR_INIT(pCryptoService);
	pCryptoService->generic_service_info.state =
	    SAL_SERVICE_STATE_INITIALIZING;

	/* Set up the instance parameters such as bank number,
	 * coreAffinity, pkgId and node affinity etc
	 */
	status = SalCtr_InstInit(device, service);
	LAC_CHECK_STATUS(status);
	/* Create debug directory for service */
	status = SalCtrl_DebugInit(device, service);
	LAC_CHECK_STATUS(status);

	switch (svc_type) {
	case SAL_SERVICE_TYPE_CRYPTO_ASYM:
		break;
	case SAL_SERVICE_TYPE_CRYPTO_SYM:
		status = SalCtrl_SymInit(device, service);
		if (CPA_STATUS_SUCCESS != status) {
			SalCtrl_DebugShutdown(device, service);
			return status;
		}
		break;
	case SAL_SERVICE_TYPE_CRYPTO:
		status = SalCtrl_SymInit(device, service);
		if (CPA_STATUS_SUCCESS != status) {
			SalCtrl_DebugShutdown(device, service);
			return status;
		}
		break;
	default:
		LAC_LOG_ERROR("Invalid service type\n");
		status = CPA_STATUS_FAIL;
		break;
	}

	pCryptoService->generic_service_info.state =
	    SAL_SERVICE_STATE_INITIALIZED;

	return status;
}

CpaStatus
SalCtrl_CryptoStart(icp_accel_dev_t *device, sal_service_t *service)
{
	sal_crypto_service_t *pCryptoService = (sal_crypto_service_t *)service;
	CpaStatus status = CPA_STATUS_SUCCESS;

	if (pCryptoService->generic_service_info.state !=
	    SAL_SERVICE_STATE_INITIALIZED) {
		LAC_LOG_ERROR("Not in the correct state to call start\n");
		return CPA_STATUS_FAIL;
	}

	pCryptoService->generic_service_info.state = SAL_SERVICE_STATE_RUNNING;
	return status;
}

CpaStatus
SalCtrl_CryptoStop(icp_accel_dev_t *device, sal_service_t *service)
{
	sal_crypto_service_t *pCryptoService = (sal_crypto_service_t *)service;

	if (SAL_SERVICE_STATE_RUNNING !=
	    pCryptoService->generic_service_info.state) {
		LAC_LOG_ERROR("Not in the correct state to call stop");
	}

	pCryptoService->generic_service_info.state =
	    SAL_SERVICE_STATE_SHUTTING_DOWN;
	return CPA_STATUS_SUCCESS;
}

CpaStatus
SalCtrl_CryptoShutdown(icp_accel_dev_t *device, sal_service_t *service)
{
	sal_crypto_service_t *pCryptoService = (sal_crypto_service_t *)service;
	CpaStatus status = CPA_STATUS_SUCCESS;
	sal_service_type_t svc_type = service->type;

	if ((SAL_SERVICE_STATE_INITIALIZED !=
	     pCryptoService->generic_service_info.state) &&
	    (SAL_SERVICE_STATE_SHUTTING_DOWN !=
	     pCryptoService->generic_service_info.state)) {
		LAC_LOG_ERROR("Not in the correct state to call shutdown \n");
		return CPA_STATUS_FAIL;
	}

	/* Free memory and transhandles */
	switch (svc_type) {
	case SAL_SERVICE_TYPE_CRYPTO_ASYM:
		break;
	case SAL_SERVICE_TYPE_CRYPTO_SYM:
		if (SalCtrl_SymFreeResources(pCryptoService)) {
			status = CPA_STATUS_FAIL;
		}
		break;
	case SAL_SERVICE_TYPE_CRYPTO:
		if (SalCtrl_SymFreeResources(pCryptoService)) {
			status = CPA_STATUS_FAIL;
		}
		break;
	default:
		LAC_LOG_ERROR("Invalid service type\n");
		status = CPA_STATUS_FAIL;
		break;
	}

	SalCtrl_DebugShutdown(device, service);

	pCryptoService->generic_service_info.state = SAL_SERVICE_STATE_SHUTDOWN;

	return status;
}

/**
 ******************************************************************************
 * @ingroup cpaCyCommon
 *****************************************************************************/
CpaStatus
cpaCyGetStatusText(const CpaInstanceHandle instanceHandle,
		   CpaStatus errStatus,
		   Cpa8S *pStatusText)
{
	CpaStatus status = CPA_STATUS_SUCCESS;

	LAC_CHECK_NULL_PARAM(pStatusText);

	switch (errStatus) {
	case CPA_STATUS_SUCCESS:
		LAC_COPY_STRING(pStatusText, CPA_STATUS_STR_SUCCESS);
		break;
	case CPA_STATUS_FAIL:
		LAC_COPY_STRING(pStatusText, CPA_STATUS_STR_FAIL);
		break;
	case CPA_STATUS_RETRY:
		LAC_COPY_STRING(pStatusText, CPA_STATUS_STR_RETRY);
		break;
	case CPA_STATUS_RESOURCE:
		LAC_COPY_STRING(pStatusText, CPA_STATUS_STR_RESOURCE);
		break;
	case CPA_STATUS_INVALID_PARAM:
		LAC_COPY_STRING(pStatusText, CPA_STATUS_STR_INVALID_PARAM);
		break;
	case CPA_STATUS_FATAL:
		LAC_COPY_STRING(pStatusText, CPA_STATUS_STR_FATAL);
		break;
	case CPA_STATUS_UNSUPPORTED:
		LAC_COPY_STRING(pStatusText, CPA_STATUS_STR_UNSUPPORTED);
		break;
	default:
		status = CPA_STATUS_INVALID_PARAM;
		break;
	}
	return status;
}

void
SalCtrl_CyQueryCapabilities(sal_service_t *pGenericService,
			    CpaCyCapabilitiesInfo *pCapInfo)
{
	memset(pCapInfo, 0, sizeof(CpaCyCapabilitiesInfo));

	if (SAL_SERVICE_TYPE_CRYPTO == pGenericService->type ||
	    SAL_SERVICE_TYPE_CRYPTO_SYM == pGenericService->type) {
		pCapInfo->symSupported = CPA_TRUE;
		if (pGenericService->capabilitiesMask &
		    ICP_ACCEL_CAPABILITIES_EXT_ALGCHAIN) {
			pCapInfo->extAlgchainSupported = CPA_TRUE;
		}

		if (pGenericService->capabilitiesMask &
		    ICP_ACCEL_CAPABILITIES_HKDF) {
			pCapInfo->hkdfSupported = CPA_TRUE;
		}
	}

	if (pGenericService->capabilitiesMask &
	    ICP_ACCEL_CAPABILITIES_ECEDMONT) {
		pCapInfo->ecEdMontSupported = CPA_TRUE;
	}

	if (pGenericService->capabilitiesMask &
	    ICP_ACCEL_CAPABILITIES_RANDOM_NUMBER) {
		pCapInfo->nrbgSupported = CPA_TRUE;
	}

	pCapInfo->drbgSupported = CPA_FALSE;
	pCapInfo->randSupported = CPA_FALSE;
	pCapInfo->nrbgSupported = CPA_FALSE;
}

/**
 ******************************************************************************
 * @ingroup cpaCyCommon
 *****************************************************************************/
CpaStatus
cpaCyStartInstance(CpaInstanceHandle instanceHandle_in)
{
	CpaInstanceHandle instanceHandle = NULL;
/* Structure initializer is supported by C99, but it is
 * not supported by some former Intel compilers.
 */
	CpaInstanceInfo2 info = { 0 };
	icp_accel_dev_t *dev = NULL;
	CpaStatus status = CPA_STATUS_SUCCESS;
	sal_crypto_service_t *pService = NULL;

	if (CPA_INSTANCE_HANDLE_SINGLE == instanceHandle_in) {
		instanceHandle = Lac_GetFirstHandle(SAL_SERVICE_TYPE_CRYPTO);
		if (!instanceHandle) {
			instanceHandle =
			    Lac_GetFirstHandle(SAL_SERVICE_TYPE_CRYPTO_SYM);
		}
	} else {
		instanceHandle = instanceHandle_in;
	}
	LAC_CHECK_NULL_PARAM(instanceHandle);
	SAL_CHECK_INSTANCE_TYPE(instanceHandle,
				(SAL_SERVICE_TYPE_CRYPTO |
				 SAL_SERVICE_TYPE_CRYPTO_ASYM |
				 SAL_SERVICE_TYPE_CRYPTO_SYM));

	pService = (sal_crypto_service_t *)instanceHandle;

	status = cpaCyInstanceGetInfo2(instanceHandle, &info);
	if (CPA_STATUS_SUCCESS != status) {
		LAC_LOG_ERROR("Can not get instance info\n");
		return status;
	}
	dev = icp_adf_getAccelDevByAccelId(info.physInstId.packageId);
	if (NULL == dev) {
		LAC_LOG_ERROR("Can not find device for the instance\n");
		return CPA_STATUS_FAIL;
	}

	pService->generic_service_info.isInstanceStarted = CPA_TRUE;

	/* Increment dev ref counter */
	icp_qa_dev_get(dev);
	return CPA_STATUS_SUCCESS;
}

/**
 ******************************************************************************
 * @ingroup cpaCyCommon
 *****************************************************************************/
CpaStatus
cpaCyStopInstance(CpaInstanceHandle instanceHandle_in)
{
	CpaInstanceHandle instanceHandle = NULL;
/* Structure initializer is supported by C99, but it is
 * not supported by some former Intel compilers.
 */
	CpaInstanceInfo2 info = { 0 };
	icp_accel_dev_t *dev = NULL;
	CpaStatus status = CPA_STATUS_SUCCESS;
	sal_crypto_service_t *pService = NULL;

	if (CPA_INSTANCE_HANDLE_SINGLE == instanceHandle_in) {
		instanceHandle = Lac_CryptoGetFirstHandle();
	} else {
		instanceHandle = instanceHandle_in;
	}
	LAC_CHECK_NULL_PARAM(instanceHandle);
	SAL_CHECK_INSTANCE_TYPE(instanceHandle,
				(SAL_SERVICE_TYPE_CRYPTO |
				 SAL_SERVICE_TYPE_CRYPTO_ASYM |
				 SAL_SERVICE_TYPE_CRYPTO_SYM));

	status = cpaCyInstanceGetInfo2(instanceHandle, &info);
	if (CPA_STATUS_SUCCESS != status) {
		LAC_LOG_ERROR("Can not get instance info\n");
		return status;
	}
	dev = icp_adf_getAccelDevByAccelId(info.physInstId.packageId);
	if (NULL == dev) {
		LAC_LOG_ERROR("Can not find device for the instance\n");
		return CPA_STATUS_FAIL;
	}

	pService = (sal_crypto_service_t *)instanceHandle;

	pService->generic_service_info.isInstanceStarted = CPA_FALSE;

	/* Decrement dev ref counter */
	icp_qa_dev_put(dev);
	return CPA_STATUS_SUCCESS;
}

/**
 ******************************************************************************
 * @ingroup cpaCyCommon
 *****************************************************************************/
CpaStatus
cpaCyInstanceSetNotificationCb(
    const CpaInstanceHandle instanceHandle,
    const CpaCyInstanceNotificationCbFunc pInstanceNotificationCb,
    void *pCallbackTag)
{
	CpaStatus status = CPA_STATUS_SUCCESS;
	sal_service_t *gen_handle = instanceHandle;

	LAC_CHECK_NULL_PARAM(gen_handle);
	gen_handle->notification_cb = pInstanceNotificationCb;
	gen_handle->cb_tag = pCallbackTag;
	return status;
}

/**
 ******************************************************************************
 * @ingroup cpaCyCommon
 *****************************************************************************/
CpaStatus
cpaCyGetNumInstances(Cpa16U *pNumInstances)
{
	return Lac_GetCyNumInstancesByType(CPA_ACC_SVC_TYPE_CRYPTO,
					   pNumInstances);
}

/**
 ******************************************************************************
 * @ingroup cpaCyCommon
 *****************************************************************************/
CpaStatus
cpaCyGetInstances(Cpa16U numInstances, CpaInstanceHandle *pCyInstances)
{
	return Lac_GetCyInstancesByType(CPA_ACC_SVC_TYPE_CRYPTO,
					numInstances,
					pCyInstances);
}

/**
 ******************************************************************************
 * @ingroup cpaCyCommon
 *****************************************************************************/
CpaStatus
cpaCyInstanceGetInfo(const CpaInstanceHandle instanceHandle_in,
		     struct _CpaInstanceInfo *pInstanceInfo)
{
	CpaInstanceHandle instanceHandle = NULL;
	sal_crypto_service_t *pCryptoService = NULL;
	sal_service_t *pGenericService = NULL;

	Cpa8U name[CPA_INST_NAME_SIZE] =
	    "Intel(R) DH89XXCC instance number: %02x, type: Crypto";

	if (CPA_INSTANCE_HANDLE_SINGLE == instanceHandle_in) {
		instanceHandle = Lac_CryptoGetFirstHandle();
	} else {
		instanceHandle = instanceHandle_in;
	}

	LAC_CHECK_NULL_PARAM(instanceHandle);
	LAC_CHECK_NULL_PARAM(pInstanceInfo);
	SAL_CHECK_INSTANCE_TYPE(instanceHandle,
				(SAL_SERVICE_TYPE_CRYPTO |
				 SAL_SERVICE_TYPE_CRYPTO_ASYM |
				 SAL_SERVICE_TYPE_CRYPTO_SYM));

	pCryptoService = (sal_crypto_service_t *)instanceHandle;

	pInstanceInfo->type = CPA_INSTANCE_TYPE_CRYPTO;

	/* According to cpa.h instance state is initialized and ready for use
	 * or shutdown. Therefore need to map our running state to initialised
	 * or shutdown */
	if (SAL_SERVICE_STATE_RUNNING ==
	    pCryptoService->generic_service_info.state) {
		pInstanceInfo->state = CPA_INSTANCE_STATE_INITIALISED;
	} else {
		pInstanceInfo->state = CPA_INSTANCE_STATE_SHUTDOWN;
	}

	pGenericService = (sal_service_t *)instanceHandle;
	snprintf((char *)pInstanceInfo->name,
		 CPA_INST_NAME_SIZE,
		 (char *)name,
		 pGenericService->instance);

	pInstanceInfo->name[CPA_INST_NAME_SIZE - 1] = '\0';

	snprintf((char *)pInstanceInfo->version,
		 CPA_INSTANCE_MAX_NAME_SIZE_IN_BYTES,
		 "%d.%d",
		 CPA_CY_API_VERSION_NUM_MAJOR,
		 CPA_CY_API_VERSION_NUM_MINOR);

	pInstanceInfo->version[CPA_INSTANCE_MAX_VERSION_SIZE_IN_BYTES - 1] =
	    '\0';
	return CPA_STATUS_SUCCESS;
}

/**
 ******************************************************************************
 * @ingroup cpaCyCommon
 *****************************************************************************/
CpaStatus
cpaCyInstanceGetInfo2(const CpaInstanceHandle instanceHandle_in,
		      CpaInstanceInfo2 *pInstanceInfo2)
{
	CpaInstanceHandle instanceHandle = NULL;
	sal_crypto_service_t *pCryptoService = NULL;
	icp_accel_dev_t *dev = NULL;
	CpaStatus status = CPA_STATUS_SUCCESS;
	char keyStr[ADF_CFG_MAX_KEY_LEN_IN_BYTES] = { 0 };
	char valStr[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 };
	char *section = DYN_SEC;

	if (CPA_INSTANCE_HANDLE_SINGLE == instanceHandle_in) {
		instanceHandle = Lac_CryptoGetFirstHandle();
	} else {
		instanceHandle = instanceHandle_in;
	}

	LAC_CHECK_NULL_PARAM(instanceHandle);
	LAC_CHECK_NULL_PARAM(pInstanceInfo2);
	SAL_CHECK_INSTANCE_TYPE(instanceHandle,
				(SAL_SERVICE_TYPE_CRYPTO |
				 SAL_SERVICE_TYPE_CRYPTO_ASYM |
				 SAL_SERVICE_TYPE_CRYPTO_SYM));

	LAC_OS_BZERO(pInstanceInfo2, sizeof(CpaInstanceInfo2));
	pInstanceInfo2->accelerationServiceType = CPA_ACC_SVC_TYPE_CRYPTO;
	snprintf((char *)pInstanceInfo2->vendorName,
		 CPA_INST_VENDOR_NAME_SIZE,
		 "%s",
		 SAL_INFO2_VENDOR_NAME);
	pInstanceInfo2->vendorName[CPA_INST_VENDOR_NAME_SIZE - 1] = '\0';

	snprintf((char *)pInstanceInfo2->swVersion,
		 CPA_INST_SW_VERSION_SIZE,
		 "Version %d.%d",
		 SAL_INFO2_DRIVER_SW_VERSION_MAJ_NUMBER,
		 SAL_INFO2_DRIVER_SW_VERSION_MIN_NUMBER);
	pInstanceInfo2->swVersion[CPA_INST_SW_VERSION_SIZE - 1] = '\0';

	/* Note we can safely read the contents of the crypto service instance
	   here because icp_amgr_getAllAccelDevByCapabilities() only returns
	   devs
	   that have started */
	pCryptoService = (sal_crypto_service_t *)instanceHandle;
	pInstanceInfo2->physInstId.packageId = pCryptoService->pkgID;
	pInstanceInfo2->physInstId.acceleratorId =
	    pCryptoService->acceleratorNum;
	pInstanceInfo2->physInstId.executionEngineId =
	    pCryptoService->executionEngine;
	pInstanceInfo2->physInstId.busAddress =
	    icp_adf_get_busAddress(pInstanceInfo2->physInstId.packageId);

	/*set coreAffinity to zero before use */
	LAC_OS_BZERO(pInstanceInfo2->coreAffinity,
		     sizeof(pInstanceInfo2->coreAffinity));
	CPA_BITMAP_BIT_SET(pInstanceInfo2->coreAffinity,
			   pCryptoService->coreAffinity);
	pInstanceInfo2->nodeAffinity = pCryptoService->nodeAffinity;

	if (SAL_SERVICE_STATE_RUNNING ==
	    pCryptoService->generic_service_info.state) {
		pInstanceInfo2->operState = CPA_OPER_STATE_UP;
	} else {
		pInstanceInfo2->operState = CPA_OPER_STATE_DOWN;
	}

	pInstanceInfo2->requiresPhysicallyContiguousMemory = CPA_TRUE;
	if (SAL_RESP_POLL_CFG_FILE == pCryptoService->isPolled) {
		pInstanceInfo2->isPolled = CPA_TRUE;
	} else {
		pInstanceInfo2->isPolled = CPA_FALSE;
	}
	pInstanceInfo2->isOffloaded = CPA_TRUE;

	/* Get the instance name and part name */
	dev = icp_adf_getAccelDevByAccelId(pCryptoService->pkgID);
	if (NULL == dev ||
	    0 == strnlen(dev->deviceName, ADF_DEVICE_TYPE_LENGTH + 1)) {
		LAC_LOG_ERROR("Can not find device for the instance\n");
		LAC_OS_BZERO(pInstanceInfo2, sizeof(CpaInstanceInfo2));
		return CPA_STATUS_FAIL;
	}
	snprintf((char *)pInstanceInfo2->partName,
		 CPA_INST_PART_NAME_SIZE,
		 SAL_INFO2_PART_NAME,
		 dev->deviceName);
	pInstanceInfo2->partName[CPA_INST_PART_NAME_SIZE - 1] = '\0';

	status =
	    Sal_StringParsing("Cy",
			      pCryptoService->generic_service_info.instance,
			      "Name",
			      keyStr);
	LAC_CHECK_STATUS(status);

	if (CPA_FALSE == pCryptoService->generic_service_info.is_dyn) {
		section = icpGetProcessName();
	}

	status = icp_adf_cfgGetParamValue(dev, section, keyStr, valStr);
	LAC_CHECK_STATUS(status);

	snprintf((char *)pInstanceInfo2->instName,
		 CPA_INST_NAME_SIZE,
		 "%s",
		 valStr);
	snprintf((char *)pInstanceInfo2->instID,
		 CPA_INST_ID_SIZE,
		 "%s_%s",
		 section,
		 valStr);
	return CPA_STATUS_SUCCESS;
}

/**
 ******************************************************************************
 * @ingroup cpaCyCommon
 *****************************************************************************/

CpaStatus
cpaCyQueryCapabilities(const CpaInstanceHandle instanceHandle_in,
		       CpaCyCapabilitiesInfo *pCapInfo)
{
	/* Verify Instance exists */
	CpaInstanceHandle instanceHandle = NULL;

	if (CPA_INSTANCE_HANDLE_SINGLE == instanceHandle_in) {
		instanceHandle = Lac_CryptoGetFirstHandle();
	} else {
		instanceHandle = instanceHandle_in;
	}

	LAC_CHECK_NULL_PARAM(instanceHandle);
	SAL_CHECK_INSTANCE_TYPE(instanceHandle,
				(SAL_SERVICE_TYPE_CRYPTO |
				 SAL_SERVICE_TYPE_CRYPTO_ASYM |
				 SAL_SERVICE_TYPE_CRYPTO_SYM));
	LAC_CHECK_NULL_PARAM(pCapInfo);

	SalCtrl_CyQueryCapabilities((sal_service_t *)instanceHandle, pCapInfo);

	return CPA_STATUS_SUCCESS;
}

/**
 ******************************************************************************
 * @ingroup cpaCySym
 *****************************************************************************/
CpaStatus
cpaCySymQueryCapabilities(const CpaInstanceHandle instanceHandle_in,
			  CpaCySymCapabilitiesInfo *pCapInfo)
{
	sal_crypto_service_t *pCryptoService = NULL;
	sal_service_t *pGenericService = NULL;
	CpaInstanceHandle instanceHandle = NULL;

	/* Verify Instance exists */
	if (CPA_INSTANCE_HANDLE_SINGLE == instanceHandle_in) {
		instanceHandle = Lac_GetFirstHandle(SAL_SERVICE_TYPE_CRYPTO);
		if (!instanceHandle) {
			instanceHandle =
			    Lac_GetFirstHandle(SAL_SERVICE_TYPE_CRYPTO_SYM);
		}
	} else {
		instanceHandle = instanceHandle_in;
	}

	LAC_CHECK_NULL_PARAM(instanceHandle);
	SAL_CHECK_INSTANCE_TYPE(instanceHandle,
				(SAL_SERVICE_TYPE_CRYPTO |
				 SAL_SERVICE_TYPE_CRYPTO_ASYM |
				 SAL_SERVICE_TYPE_CRYPTO_SYM));
	LAC_CHECK_NULL_PARAM(pCapInfo);

	pCryptoService = (sal_crypto_service_t *)instanceHandle;
	pGenericService = &(pCryptoService->generic_service_info);

	memset(pCapInfo, '\0', sizeof(CpaCySymCapabilitiesInfo));
	/* An asym crypto instance does not support sym service */
	if (SAL_SERVICE_TYPE_CRYPTO_ASYM == pGenericService->type) {
		return CPA_STATUS_SUCCESS;
	}

	CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_NULL);
	CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_ECB);
	CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_CBC);
	CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_CTR);
	CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_CCM);
	CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_GCM);
	CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_XTS);
	if (isCyGen2x(pCryptoService)) {
		CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_ARC4);
		CPA_BITMAP_BIT_SET(pCapInfo->ciphers,
				   CPA_CY_SYM_CIPHER_DES_ECB);
		CPA_BITMAP_BIT_SET(pCapInfo->ciphers,
				   CPA_CY_SYM_CIPHER_DES_CBC);
		CPA_BITMAP_BIT_SET(pCapInfo->ciphers,
				   CPA_CY_SYM_CIPHER_3DES_ECB);
		CPA_BITMAP_BIT_SET(pCapInfo->ciphers,
				   CPA_CY_SYM_CIPHER_3DES_CBC);
		CPA_BITMAP_BIT_SET(pCapInfo->ciphers,
				   CPA_CY_SYM_CIPHER_3DES_CTR);
		CPA_BITMAP_BIT_SET(pCapInfo->ciphers,
				   CPA_CY_SYM_CIPHER_KASUMI_F8);
		CPA_BITMAP_BIT_SET(pCapInfo->ciphers,
				   CPA_CY_SYM_CIPHER_SNOW3G_UEA2);
		CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_F8);
	}

	CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SHA1);
	CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SHA224);
	CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SHA256);
	CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SHA384);
	CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SHA512);
	CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_AES_XCBC);
	CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_AES_CCM);
	CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_AES_GCM);
	CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_AES_CMAC);
	CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_AES_GMAC);
	CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_AES_CBC_MAC);
	if (isCyGen2x(pCryptoService)) {
		CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_MD5);
		CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_KASUMI_F9);
		CPA_BITMAP_BIT_SET(pCapInfo->hashes,
				   CPA_CY_SYM_HASH_SNOW3G_UIA2);
	}

	if (pGenericService->capabilitiesMask &
	    ICP_ACCEL_CAPABILITIES_CRYPTO_ZUC) {
		CPA_BITMAP_BIT_SET(pCapInfo->ciphers,
				   CPA_CY_SYM_CIPHER_ZUC_EEA3);
		CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_ZUC_EIA3);
	}

	if (pGenericService->capabilitiesMask &
	    ICP_ACCEL_CAPABILITIES_CHACHA_POLY) {
		CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_POLY);
		CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_CHACHA);
	}

	if (pGenericService->capabilitiesMask & ICP_ACCEL_CAPABILITIES_SM3) {
		CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SM3);
	}

	pCapInfo->partialPacketSupported = CPA_TRUE;

	if (pGenericService->capabilitiesMask & ICP_ACCEL_CAPABILITIES_SHA3) {
		CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SHA3_256);
		pCapInfo->partialPacketSupported = CPA_FALSE;
	}

	if (pGenericService->capabilitiesMask &
	    ICP_ACCEL_CAPABILITIES_SHA3_EXT) {
		CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SHA3_224);
		CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SHA3_256);
		CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SHA3_384);
		CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SHA3_512);
		pCapInfo->partialPacketSupported = CPA_FALSE;
	}

	if (pGenericService->capabilitiesMask & ICP_ACCEL_CAPABILITIES_SM4) {
		CPA_BITMAP_BIT_SET(pCapInfo->ciphers,
				   CPA_CY_SYM_CIPHER_SM4_ECB);
		CPA_BITMAP_BIT_SET(pCapInfo->ciphers,
				   CPA_CY_SYM_CIPHER_SM4_CBC);
		CPA_BITMAP_BIT_SET(pCapInfo->ciphers,
				   CPA_CY_SYM_CIPHER_SM4_CTR);
		pCapInfo->partialPacketSupported = CPA_FALSE;
	}

	return CPA_STATUS_SUCCESS;
}

/**
 ******************************************************************************
 * @ingroup cpaCyCommon
 *****************************************************************************/
CpaStatus
cpaCySetAddressTranslation(const CpaInstanceHandle instanceHandle_in,
			   CpaVirtualToPhysical virtual2physical)
{

	CpaInstanceHandle instanceHandle = NULL;
	sal_service_t *pService = NULL;

	if (CPA_INSTANCE_HANDLE_SINGLE == instanceHandle_in) {
		instanceHandle = Lac_CryptoGetFirstHandle();
	} else {
		instanceHandle = instanceHandle_in;
	}

	LAC_CHECK_NULL_PARAM(instanceHandle);
	SAL_CHECK_INSTANCE_TYPE(instanceHandle,
				(SAL_SERVICE_TYPE_CRYPTO |
				 SAL_SERVICE_TYPE_CRYPTO_ASYM |
				 SAL_SERVICE_TYPE_CRYPTO_SYM));
	LAC_CHECK_NULL_PARAM(virtual2physical);

	pService = (sal_service_t *)instanceHandle;

	pService->virt2PhysClient = virtual2physical;

	return CPA_STATUS_SUCCESS;
}

/**
 ******************************************************************************
 * @ingroup cpaCyCommon
 * Crypto specific polling function which polls a crypto instance.
 *****************************************************************************/
CpaStatus
icp_sal_CyPollInstance(CpaInstanceHandle instanceHandle_in,
		       Cpa32U response_quota)
{
	CpaStatus status = CPA_STATUS_SUCCESS;
	sal_crypto_service_t *crypto_handle = NULL;
	sal_service_t *gen_handle = NULL;
	icp_comms_trans_handle trans_hndTable[MAX_CY_RX_RINGS] = { 0 };
	Cpa32U num_rx_rings = 0;

	if (CPA_INSTANCE_HANDLE_SINGLE == instanceHandle_in) {
		crypto_handle =
		    (sal_crypto_service_t *)Lac_CryptoGetFirstHandle();
	} else {
		crypto_handle = (sal_crypto_service_t *)instanceHandle_in;
	}
	LAC_CHECK_NULL_PARAM(crypto_handle);
	SAL_RUNNING_CHECK(crypto_handle);
	SAL_CHECK_INSTANCE_TYPE(crypto_handle,
				(SAL_SERVICE_TYPE_CRYPTO |
				 SAL_SERVICE_TYPE_CRYPTO_ASYM |
				 SAL_SERVICE_TYPE_CRYPTO_SYM));

	gen_handle = &(crypto_handle->generic_service_info);

	/*
	 * From the instanceHandle we must get the trans_handle and send
	 * down to adf for polling.
	 * Populate our trans handle table with the appropriate handles.
	 */

	switch (gen_handle->type) {
	case SAL_SERVICE_TYPE_CRYPTO_ASYM:
		trans_hndTable[TH_CY_RX_0] =
		    crypto_handle->trans_handle_asym_rx;
		num_rx_rings = 1;
		break;
	case SAL_SERVICE_TYPE_CRYPTO_SYM:
		trans_hndTable[TH_CY_RX_0] = crypto_handle->trans_handle_sym_rx;
		num_rx_rings = 1;
		break;
	case SAL_SERVICE_TYPE_CRYPTO:
		trans_hndTable[TH_CY_RX_0] = crypto_handle->trans_handle_sym_rx;
		trans_hndTable[TH_CY_RX_1] =
		    crypto_handle->trans_handle_asym_rx;
		num_rx_rings = MAX_CY_RX_RINGS;
		break;
	default:
		break;
	}

	/* Call adf to do the polling. */
	status =
	    icp_adf_pollInstance(trans_hndTable, num_rx_rings, response_quota);

	return status;
}

/**
 ******************************************************************************
 * @ingroup cpaCyCommon
 * Crypto specific polling function which polls sym crypto ring.
 *****************************************************************************/
CpaStatus
icp_sal_CyPollSymRing(CpaInstanceHandle instanceHandle_in,
		      Cpa32U response_quota)
{
	CpaStatus status = CPA_STATUS_SUCCESS;
	sal_crypto_service_t *crypto_handle = NULL;
	icp_comms_trans_handle trans_hndTable[NUM_CRYPTO_SYM_RX_RINGS] = { 0 };

	if (CPA_INSTANCE_HANDLE_SINGLE == instanceHandle_in) {
		crypto_handle = (sal_crypto_service_t *)Lac_GetFirstHandle(
		    SAL_SERVICE_TYPE_CRYPTO_SYM);
	} else {
		crypto_handle = (sal_crypto_service_t *)instanceHandle_in;
	}
	LAC_CHECK_NULL_PARAM(crypto_handle);
	SAL_CHECK_INSTANCE_TYPE(crypto_handle,
				(SAL_SERVICE_TYPE_CRYPTO |
				 SAL_SERVICE_TYPE_CRYPTO_SYM));
	SAL_RUNNING_CHECK(crypto_handle);

	/*
	 * From the instanceHandle we must get the trans_handle and send
	 * down to adf for polling.
	 * Populate our trans handle table with the appropriate handles.
	 */
	trans_hndTable[TH_SINGLE_RX] = crypto_handle->trans_handle_sym_rx;
	/* Call adf to do the polling. */
	status = icp_adf_pollInstance(trans_hndTable,
				      NUM_CRYPTO_SYM_RX_RINGS,
				      response_quota);
	return status;
}

/**
 ******************************************************************************
 * @ingroup cpaCyCommon
 * Crypto specific polling function which polls an nrbg crypto ring.
 *****************************************************************************/
CpaStatus
icp_sal_CyPollNRBGRing(CpaInstanceHandle instanceHandle_in,
		       Cpa32U response_quota)
{
	return CPA_STATUS_UNSUPPORTED;
}

/* Returns the handle to the first asym crypto instance */
static CpaInstanceHandle
Lac_GetFirstAsymHandle(icp_accel_dev_t *adfInsts[ADF_MAX_DEVICES],
		       Cpa16U num_dev)
{
	CpaStatus status = CPA_STATUS_SUCCESS;
	icp_accel_dev_t *dev_addr = NULL;
	sal_t *base_addr = NULL;
	sal_list_t *list_temp = NULL;
	CpaInstanceHandle cyInst = NULL;
	CpaInstanceInfo2 info;
	Cpa16U i = 0;

	for (i = 0; i < num_dev; i++) {
		dev_addr = (icp_accel_dev_t *)adfInsts[i];
		base_addr = dev_addr->pSalHandle;
		if (NULL == base_addr) {
			continue;
		}
		list_temp = base_addr->asym_services;
		while (NULL != list_temp) {
			cyInst = SalList_getObject(list_temp);
			status = cpaCyInstanceGetInfo2(cyInst, &info);
			list_temp = SalList_next(list_temp);
			if (CPA_STATUS_SUCCESS != status ||
			    CPA_TRUE != info.isPolled) {
				cyInst = NULL;
				continue;
			}
			break;
		}
		if (cyInst) {
			break;
		}
	}

	return cyInst;
}

/* Returns the handle to the first sym crypto instance */
static CpaInstanceHandle
Lac_GetFirstSymHandle(icp_accel_dev_t *adfInsts[ADF_MAX_DEVICES],
		      Cpa16U num_dev)
{
	CpaStatus status = CPA_STATUS_SUCCESS;
	icp_accel_dev_t *dev_addr = NULL;
	sal_t *base_addr = NULL;
	sal_list_t *list_temp = NULL;
	CpaInstanceHandle cyInst = NULL;
	CpaInstanceInfo2 info;
	Cpa16U i = 0;

	for (i = 0; i < num_dev; i++) {
		dev_addr = (icp_accel_dev_t *)adfInsts[i];
		base_addr = dev_addr->pSalHandle;
		if (NULL == base_addr) {
			continue;
		}
		list_temp = base_addr->sym_services;
		while (NULL != list_temp) {
			cyInst = SalList_getObject(list_temp);
			status = cpaCyInstanceGetInfo2(cyInst, &info);
			list_temp = SalList_next(list_temp);
			if (CPA_STATUS_SUCCESS != status ||
			    CPA_TRUE != info.isPolled) {
				cyInst = NULL;
				continue;
			}
			break;
		}
		if (cyInst) {
			break;
		}
	}

	return cyInst;
}

/* Returns the handle to the first crypto instance
 * Note that the crypto instance in this case supports
 * both asym and sym services */
static CpaInstanceHandle
Lac_GetFirstCyHandle(icp_accel_dev_t *adfInsts[ADF_MAX_DEVICES], Cpa16U num_dev)
{
	CpaStatus status = CPA_STATUS_SUCCESS;
	icp_accel_dev_t *dev_addr = NULL;
	sal_t *base_addr = NULL;
	sal_list_t *list_temp = NULL;
	CpaInstanceHandle cyInst = NULL;
	CpaInstanceInfo2 info;
	Cpa16U i = 0;

	for (i = 0; i < num_dev; i++) {
		dev_addr = (icp_accel_dev_t *)adfInsts[i];
		base_addr = dev_addr->pSalHandle;
		if (NULL == base_addr) {
			continue;
		}
		list_temp = base_addr->crypto_services;
		while (NULL != list_temp) {
			cyInst = SalList_getObject(list_temp);
			status = cpaCyInstanceGetInfo2(cyInst, &info);
			list_temp = SalList_next(list_temp);
			if (CPA_STATUS_SUCCESS != status ||
			    CPA_TRUE != info.isPolled) {
				cyInst = NULL;
				continue;
			}
			break;
		}
		if (cyInst) {
			break;
		}
	}

	return cyInst;
}

CpaInstanceHandle
Lac_GetFirstHandle(sal_service_type_t svc_type)
{
	CpaStatus status = CPA_STATUS_SUCCESS;
	static icp_accel_dev_t *adfInsts[ADF_MAX_DEVICES] = { 0 };
	CpaInstanceHandle cyInst = NULL;
	Cpa16U num_cy_dev = 0;
	Cpa32U capabilities = 0;

	switch (svc_type) {
	case SAL_SERVICE_TYPE_CRYPTO_ASYM:
		capabilities = ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC;
		break;
	case SAL_SERVICE_TYPE_CRYPTO_SYM:
		capabilities = ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC;
		break;
	case SAL_SERVICE_TYPE_CRYPTO:
		capabilities = ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC;
		capabilities |= ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC;
		break;
	default:
		LAC_LOG_ERROR("Invalid service type\n");
		return NULL;
	}
	/* Only need 1 dev with crypto enabled - so check all devices*/
	status = icp_amgr_getAllAccelDevByEachCapability(capabilities,
							 adfInsts,
							 &num_cy_dev);
	if ((0 == num_cy_dev) || (CPA_STATUS_SUCCESS != status)) {
		LAC_LOG_ERROR("No crypto devices enabled in the system\n");
		return NULL;
	}

	switch (svc_type) {
	case SAL_SERVICE_TYPE_CRYPTO_ASYM:
		/* Try to find an asym only instance first */
		cyInst = Lac_GetFirstAsymHandle(adfInsts, num_cy_dev);
		/* Try to find a cy instance since it also supports asym */
		if (NULL == cyInst) {
			cyInst = Lac_GetFirstCyHandle(adfInsts, num_cy_dev);
		}
		break;
	case SAL_SERVICE_TYPE_CRYPTO_SYM:
		/* Try to find a sym only instance first */
		cyInst = Lac_GetFirstSymHandle(adfInsts, num_cy_dev);
		/* Try to find a cy instance since it also supports sym */
		if (NULL == cyInst) {
			cyInst = Lac_GetFirstCyHandle(adfInsts, num_cy_dev);
		}
		break;
	case SAL_SERVICE_TYPE_CRYPTO:
		/* Try to find a cy instance */
		cyInst = Lac_GetFirstCyHandle(adfInsts, num_cy_dev);
		break;
	default:
		break;
	}
	if (NULL == cyInst) {
		LAC_LOG_ERROR("No remaining crypto instances available\n");
	}
	return cyInst;
}

CpaStatus
icp_sal_NrbgGetInflightRequests(CpaInstanceHandle instanceHandle_in,
				Cpa32U *maxInflightRequests,
				Cpa32U *numInflightRequests)
{
	return CPA_STATUS_UNSUPPORTED;
}

CpaStatus
icp_sal_SymGetInflightRequests(CpaInstanceHandle instanceHandle,
			       Cpa32U *maxInflightRequests,
			       Cpa32U *numInflightRequests)
{
	sal_crypto_service_t *crypto_handle = NULL;

	crypto_handle = (sal_crypto_service_t *)instanceHandle;

	LAC_CHECK_NULL_PARAM(crypto_handle);
	LAC_CHECK_NULL_PARAM(maxInflightRequests);
	LAC_CHECK_NULL_PARAM(numInflightRequests);
	SAL_RUNNING_CHECK(crypto_handle);

	return icp_adf_getInflightRequests(crypto_handle->trans_handle_sym_tx,
					   maxInflightRequests,
					   numInflightRequests);
}

CpaStatus
icp_sal_dp_SymGetInflightRequests(CpaInstanceHandle instanceHandle,
				  Cpa32U *maxInflightRequests,
				  Cpa32U *numInflightRequests)
{
	sal_crypto_service_t *crypto_handle = NULL;

	crypto_handle = (sal_crypto_service_t *)instanceHandle;

	return icp_adf_dp_getInflightRequests(
	    crypto_handle->trans_handle_sym_tx,
	    maxInflightRequests,
	    numInflightRequests);
}

CpaStatus
icp_sal_setForceAEADMACVerify(CpaInstanceHandle instanceHandle,
			      CpaBoolean forceAEADMacVerify)
{
	sal_crypto_service_t *crypto_handle = NULL;

	crypto_handle = (sal_crypto_service_t *)instanceHandle;
	LAC_CHECK_NULL_PARAM(crypto_handle);
	crypto_handle->forceAEADMacVerify = forceAEADMacVerify;

	return CPA_STATUS_SUCCESS;
}
