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

/**
 ***************************************************************************
 * @file 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_drbg.h"
#include "cpa_cy_ln.h"
#include "cpa_cy_dh.h"
#include "cpa_cy_dsa.h"
#include "cpa_cy_rsa.h"
#include "cpa_cy_ec.h"
#include "cpa_cy_ecdh.h"
#include "cpa_cy_ecdsa.h"
#include "cpa_cy_prime.h"
#include "cpa_cy_key.h"
#include "cpa_cy_sym.h"

/* Osal includes */
#include "Osal.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"

/* SAL includes */
#include "lac_log.h"
#include "lac_mem.h"
#include "lac_mem_pools.h"
#include "lac_sw_responses.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_pke_utils.h"
#include "lac_pke_qat_comms.h"
#include "lac_ec.h"
#include "lac_sal_types_crypto.h"
#include "lac_sal.h"
#include "lac_sal_ctrl.h"
#include "lac_kpt_crypto_qat_comms.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 "dc_chain.h"

#define MAX_CY_RX_RINGS 2
#define TH_CY_RX_0 0
#define TH_CY_RX_1 1
#define DOUBLE_INCR 2

#define NUM_CRYPTO_SYM_RX_RINGS 1
#define NUM_CRYPTO_ASYM_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;
}

STATIC
CpaStatus SalCtrl_AsymGetFileDescriptor(sal_crypto_service_t *crypto_handle,
                                        int *fd)
{
    int ret = 0;
    int fd_asym = -1;

    if (NULL == crypto_handle->trans_handle_asym_rx)
    {
        return CPA_STATUS_FAIL;
    }
    ret = icp_adf_transGetFdForHandle(crypto_handle->trans_handle_asym_rx,
                                      &fd_asym);

    if (ret != CPA_STATUS_SUCCESS)
    {
        LAC_LOG_ERROR("Error getting file descriptor for asym instance");
        return CPA_STATUS_FAIL;
    }

    *fd = fd_asym;
    return CPA_STATUS_SUCCESS;
}

STATIC
CpaStatus SalCtrl_SymGetFileDescriptor(sal_crypto_service_t *crypto_handle,
                                       int *fd)
{
    int ret = 0;
    int fd_sym = -1;

    if (NULL == crypto_handle->trans_handle_sym_rx)
    {
        return CPA_STATUS_FAIL;
    }
    ret = icp_adf_transGetFdForHandle(crypto_handle->trans_handle_sym_rx,
                                      &fd_sym);

    if (ret != CPA_STATUS_SUCCESS)
    {
        LAC_LOG_ERROR("Error getting file descriptor for sym instance");
        return CPA_STATUS_FAIL;
    }

    *fd = fd_sym;
    return CPA_STATUS_SUCCESS;
}

STATIC
CpaStatus SalCtrl_CyGetFileDescriptor(sal_crypto_service_t *crypto_handle,
                                      int *fd)
{
    CpaStatus ret_sym = CPA_STATUS_SUCCESS;
    CpaStatus ret_asym = CPA_STATUS_SUCCESS;
    int fd_sym = -1;
    int fd_asym = -1;

    ret_sym = SalCtrl_SymGetFileDescriptor(crypto_handle, &fd_sym);
    ret_asym = SalCtrl_AsymGetFileDescriptor(crypto_handle, &fd_asym);

    if (ret_sym != CPA_STATUS_SUCCESS || ret_asym != CPA_STATUS_SUCCESS)
    {
        LAC_LOG_ERROR("Error getting file descriptor for crypto instance");
        return CPA_STATUS_FAIL;
    }

    /* They should always be the same. Otherwise, return error */
    if (fd_sym != fd_asym)
    {
        LAC_LOG_ERROR("Symmetric and asymmetric crypto cannot be used"
                      " within the same instance across different bundles");
        return CPA_STATUS_FAIL;
    }

    *fd = fd_sym;
    return CPA_STATUS_SUCCESS;
}

#ifndef ASYM_NOT_SUPPORTED
STATIC void SalCtrl_AsymMemPoolDisable(sal_crypto_service_t *pCryptoService)
{
    Lac_MemPoolDisable(pCryptoService->lac_pke_req_pool);
}
#endif

STATIC void SalCtrl_SymMemPoolDisable(sal_crypto_service_t *pCryptoService)
{
    Lac_MemPoolDisable(pCryptoService->lac_sym_cookie_pool);
}

STATIC void SalCtrl_CyMemPoolDisable(sal_service_t *service)
{
    sal_service_type_t svc_type = service->type;
    sal_crypto_service_t *pCryptoService = (sal_crypto_service_t *)service;

    switch (svc_type)
    {
#ifndef ASYM_NOT_SUPPORTED
        case SAL_SERVICE_TYPE_CRYPTO_ASYM:
            SalCtrl_AsymMemPoolDisable(pCryptoService);
            break;
#endif
        case SAL_SERVICE_TYPE_CRYPTO_SYM:
            SalCtrl_SymMemPoolDisable(pCryptoService);
            break;
        case SAL_SERVICE_TYPE_CRYPTO:
#ifndef ASYM_NOT_SUPPORTED
            SalCtrl_AsymMemPoolDisable(pCryptoService);
#endif
            SalCtrl_SymMemPoolDisable(pCryptoService);
            break;
        default:
            break;
    }
    return;
}

STATIC void SalCtrl_CyUpdatePoolsBusy(sal_service_t *service)
{
    sal_service_type_t svc_type = service->type;
    CpaBoolean isInstanceStarted = service->isInstanceStarted;
    sal_crypto_service_t *pCryptoService = (sal_crypto_service_t *)service;

    if (CPA_TRUE == isInstanceStarted)
    {
        switch (svc_type)
        {
#ifndef ASYM_NOT_SUPPORTED
            case SAL_SERVICE_TYPE_CRYPTO_ASYM:
                LacSwResp_IncNumPoolsBusy(pCryptoService->lac_pke_req_pool);
                break;
#endif
            case SAL_SERVICE_TYPE_CRYPTO_SYM:
                LacSwResp_IncNumPoolsBusy(pCryptoService->lac_sym_cookie_pool);
                break;
            case SAL_SERVICE_TYPE_CRYPTO:
#ifndef ASYM_NOT_SUPPORTED
                LacSwResp_IncNumPoolsBusy(pCryptoService->lac_pke_req_pool);
#endif
                LacSwResp_IncNumPoolsBusy(pCryptoService->lac_sym_cookie_pool);
                break;
            default:
                break;
        }
    }
    return;
}

STATIC
CpaStatus SalCtrl_CyGenResponseCrypto(sal_crypto_service_t *crypto_handle)
{
    CpaStatus status = CPA_STATUS_RETRY;
#ifndef ASYM_NOT_SUPPORTED
    CpaStatus asymStatus = CPA_STATUS_RETRY;
#endif

    status = LacSwResp_GenResp(crypto_handle->lac_sym_cookie_pool,
                               SAL_SERVICE_TYPE_CRYPTO_SYM);
    if ((CPA_STATUS_SUCCESS != status) && (CPA_STATUS_RETRY != status))
    {
        LAC_LOG_ERROR1("Failed to generate SYM SW responses with status %d\n",
                       status);
    }
#ifndef ASYM_NOT_SUPPORTED
    else
    {
        asymStatus = LacSwResp_GenResp(crypto_handle->lac_pke_req_pool,
                                       SAL_SERVICE_TYPE_CRYPTO_ASYM);
        if ((CPA_STATUS_SUCCESS != asymStatus) &&
            (CPA_STATUS_RETRY != asymStatus))
        {
            LAC_LOG_ERROR1(
                "Failed to generate ASYM SW responses with status %d\n",
                asymStatus);
            status = asymStatus;
        }
        else
        {
            if (CPA_STATUS_SUCCESS == status ||
                CPA_STATUS_SUCCESS == asymStatus)
                status = CPA_STATUS_SUCCESS;
        }
    }
#endif
    return status;
}

/* Generates dummy responses when the device is in error state */
STATIC
CpaStatus SalCtrl_CyGenResponses(sal_crypto_service_t *crypto_handle,
                                 sal_service_t *gen_handle)
{
    CpaStatus status = CPA_STATUS_RETRY;
    switch (gen_handle->type)
    {
#ifndef ASYM_NOT_SUPPORTED
        case SAL_SERVICE_TYPE_CRYPTO_ASYM:
            status = LacSwResp_GenResp(crypto_handle->lac_pke_req_pool,
                                       gen_handle->type);
            if ((CPA_STATUS_SUCCESS != status) && (CPA_STATUS_RETRY != status))
            {
                LAC_LOG_ERROR1(
                    "Failed to generate ASYM SW responses with status %d\n",
                    status);
            }
            break;
#endif
        case SAL_SERVICE_TYPE_CRYPTO_SYM:
            status = LacSwResp_GenResp(crypto_handle->lac_sym_cookie_pool,
                                       gen_handle->type);
            if ((CPA_STATUS_SUCCESS != status) && (CPA_STATUS_RETRY != status))
            {
                LAC_LOG_ERROR1(
                    "Failed to generate SYM SW responses with status %d\n",
                    status);
            }
            break;
        case SAL_SERVICE_TYPE_CRYPTO:
            status = SalCtrl_CyGenResponseCrypto(crypto_handle);
            break;
        default:
            break;
    }

    return status;
}

STATIC CpaStatus SalCtrl_CyCheckRespInstance(sal_service_t *service)
{
    sal_crypto_service_t *crypto_handle = (sal_crypto_service_t *)service;
    icp_comms_trans_handle trans_hndTable[MAX_CY_RX_RINGS];
    Cpa32U num_rx_rings = 0;

    switch (service->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;
    }
    return icp_adf_check_RespInstance(trans_hndTable, num_rx_rings);
}

#ifndef ASYM_NOT_SUPPORTED
/* Function to release the asym handles. */
STATIC CpaStatus SalCtrl_AsymReleaseTransHandle(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_asym_tx)
    {
        status =
            icp_adf_transReleaseHandle(pCryptoService->trans_handle_asym_tx);
        if (CPA_STATUS_SUCCESS != status)
        {
            ret_status = status;
        }
    }

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

/* Function to reset the asym handles. */
STATIC CpaStatus SalCtrl_AsymResetTransHandle(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_asym_tx)
    {
        status = icp_adf_transResetHandle(pCryptoService->trans_handle_asym_tx);
        if (CPA_STATUS_SUCCESS != status)
        {
            ret_status = status;
        }
    }

    if (NULL != pCryptoService->trans_handle_asym_rx)
    {
        status = icp_adf_transResetHandle(pCryptoService->trans_handle_asym_rx);
        if (CPA_STATUS_SUCCESS != status)
        {
            ret_status = status;
        }
    }
    return ret_status;
}
#endif

/* 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;
}

/* Function to reset the sym handles. */
STATIC CpaStatus SalCtrl_SymResetTransHandle(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_transResetHandle(pCryptoService->trans_handle_sym_tx);
        if (CPA_STATUS_SUCCESS != status)
        {
            ret_status = status;
        }
    }
    if (NULL != pCryptoService->trans_handle_sym_rx)
    {
        status = icp_adf_transResetHandle(pCryptoService->trans_handle_sym_rx);
        if (CPA_STATUS_SUCCESS != status)
        {
            ret_status = status;
        }
    }

    return ret_status;
}

#ifndef ASYM_NOT_SUPPORTED
/*
 * @ingroup sal_crypto
 *     Frees resources (memory and transhandles) if allocated
 *
 * @param[in]  pCryptoService       Pointer to asym service instance
 * @retval                          SUCCESS if transhandles released
 *                                  successfully
 */
STATIC CpaStatus SalCtrl_AsymFreeResources(sal_crypto_service_t *pCryptoService)
{

    CpaStatus status = CPA_STATUS_SUCCESS;

    /* Free memory pools if not NULL */
    Lac_MemPoolDestroy(pCryptoService->lac_pke_align_pool);
    Lac_MemPoolDestroy(pCryptoService->lac_pke_req_pool);
    Lac_MemPoolDestroy(pCryptoService->lac_ec_pool);
    Lac_MemPoolDestroy(pCryptoService->lac_prime_pool);
    SAL_GET_INSTANCE_CRYPTO_CAPABILITY_STATUS(status, pCryptoService, kpt);
    if (CPA_STATUS_SUCCESS == status)
    {
        Lac_MemPoolDestroy(pCryptoService->lac_pke_kpt_pool);
    }

    /* Free the statistics */
    LacDh_StatsFree(pCryptoService);
    LacDsa_StatsFree(pCryptoService);
    LacRsa_StatsFree(pCryptoService);
    LacEc_StatsFree(pCryptoService);
    LacPrime_StatsFree(pCryptoService);
    LacLn_StatsFree(pCryptoService);

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

/*
 * @ingroup sal_crypto
 *     Resets resources (memory and transhandles)
 *
 * @param[in]  pCryptoService       Pointer to asym service instance
 * @retval                          SUCCESS if transhandles released
 *                                  successfully
 */
STATIC CpaStatus
SalCtrl_AsymResetResources(sal_crypto_service_t *pCryptoService)
{
    /* Reset the statistics */
    LacDh_StatsReset(pCryptoService);
    LacDsa_StatsReset(pCryptoService);
    LacRsa_StatsReset(pCryptoService);
    LacEc_StatsReset(pCryptoService);
    LacPrime_StatsReset(pCryptoService);
    LacLn_StatsReset(pCryptoService);

    /* Reset transport handles */
    return SalCtrl_AsymResetTransHandle((sal_service_t *)pCryptoService);
}
#endif

/*
 * @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 key stats */
    LacSymKey_StatsFree(pCryptoService);
    /* 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 sal_crypto
 *     Resets resources (memory and transhandles)
 *
 * @param[in]  pCryptoService       Pointer to sym service instance
 * @retval                          SUCCESS if transhandles released
 *                                  successfully.
 */
STATIC CpaStatus SalCtrl_SymResetResources(sal_crypto_service_t *pCryptoService)
{
    LacSymKey_StatsReset(pCryptoService);

    /* Reset transport handles */
    return SalCtrl_SymResetTransHandle((sal_service_t *)pCryptoService);
}

#ifndef ASYM_NOT_SUPPORTED
/**
 ***********************************************************************
 * @ingroup SalCtrl
 *   This macro verifies that the status is _SUCCESS
 *   If status is not _SUCCESS then Asym 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_ASYM_INIT(status)                                     \
    do                                                                         \
    {                                                                          \
        if (CPA_STATUS_SUCCESS != status)                                      \
        {                                                                      \
            SalCtrl_AsymFreeResources(pCryptoService);                         \
            return status;                                                     \
        }                                                                      \
    } while (0)
#endif

/**
 ***********************************************************************
 * @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)

#ifndef ASYM_NOT_SUPPORTED
/* Function that creates the Asym Handles. */
STATIC CpaStatus SalCtrl_AsymCreateTransHandle(icp_accel_dev_t *device,
                                               sal_service_t *service,
                                               Cpa32U numAsymRequests,
                                               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;
    }
    section = icpGetProcessName();
    /* Parse Asym ring details first */
    status = Sal_StringParsing(SAL_CFG_CY,
                               pCryptoService->generic_service_info.instance,
                               SAL_CFG_RING_ASYM_TX,
                               temp_string);
    /* Need to free resources in case not _SUCCESS from here */
    LAC_CHECK_STATUS_ASYM_INIT(status);

    {
        msgSize = LAC_QAT_ASYM_REQ_SZ_IN_BYTES;
    }
    status = icp_adf_transCreateHandle(
        device,
        ICP_TRANS_TYPE_ETR,
        section,
        pCryptoService->acceleratorNum,
        pCryptoService->bankNumAsym,
        temp_string,
        lac_getRingType(SAL_RING_TYPE_A_ASYM),
        NULL,
        ICP_RESP_TYPE_NONE,
        numAsymRequests,
        msgSize,
        (icp_comms_trans_handle *)&(pCryptoService->trans_handle_asym_tx));
    LAC_CHECK_STATUS_ASYM_INIT(status);

    status = Sal_StringParsing(SAL_CFG_CY,
                               pCryptoService->generic_service_info.instance,
                               SAL_CFG_RING_ASYM_RX,
                               temp_string);
    LAC_CHECK_STATUS_ASYM_INIT(status);

    msgSize = LAC_QAT_ASYM_RESP_SZ_LW * LAC_LONG_WORD_IN_BYTES;
    status = icp_adf_transCreateHandle(
        device,
        ICP_TRANS_TYPE_ETR,
        section,
        pCryptoService->acceleratorNum,
        pCryptoService->bankNumAsym,
        temp_string,
        lac_getRingType(SAL_RING_TYPE_NONE),
        LacPke_MsgCallback,
        rx_resp_type,
        numAsymRequests,
        msgSize,
        (icp_comms_trans_handle *)&(pCryptoService->trans_handle_asym_rx));
    LAC_CHECK_STATUS_ASYM_INIT(status);

    return status;
}

/* Function that reinitializes the Asym Handles after restart. */
STATIC CpaStatus SalCtrl_AsymReinitTransHandle(icp_accel_dev_t *device,
                                               sal_service_t *service,
                                               Cpa32U numAsymRequests,
                                               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;
    }
    section = icpGetProcessName();
    /* Parse Asym ring details first */
    status = Sal_StringParsing(SAL_CFG_CY,
                               pCryptoService->generic_service_info.instance,
                               SAL_CFG_RING_ASYM_TX,
                               temp_string);
    /* Need to free resources in case not _SUCCESS from here */
    LAC_CHECK_STATUS_ASYM_INIT(status);

    {
        msgSize = LAC_QAT_ASYM_REQ_SZ_IN_BYTES;
    }

    status = icp_adf_transReinitHandle(
        device,
        ICP_TRANS_TYPE_ETR,
        section,
        pCryptoService->acceleratorNum,
        pCryptoService->bankNumAsym,
        temp_string,
        lac_getRingType(SAL_RING_TYPE_A_ASYM),
        NULL,
        ICP_RESP_TYPE_NONE,
        numAsymRequests,
        msgSize,
        (icp_comms_trans_handle *)&(pCryptoService->trans_handle_asym_tx));
    LAC_CHECK_STATUS_ASYM_INIT(status);

    status = Sal_StringParsing(SAL_CFG_CY,
                               pCryptoService->generic_service_info.instance,
                               SAL_CFG_RING_ASYM_RX,
                               temp_string);
    LAC_CHECK_STATUS_ASYM_INIT(status);

    msgSize = LAC_QAT_ASYM_RESP_SZ_LW * LAC_LONG_WORD_IN_BYTES;
    status = icp_adf_transReinitHandle(
        device,
        ICP_TRANS_TYPE_ETR,
        section,
        pCryptoService->acceleratorNum,
        pCryptoService->bankNumAsym,
        temp_string,
        lac_getRingType(SAL_RING_TYPE_NONE),
        LacPke_MsgCallback,
        rx_resp_type,
        numAsymRequests,
        msgSize,
        (icp_comms_trans_handle *)&(pCryptoService->trans_handle_asym_rx));
    LAC_CHECK_STATUS_ASYM_INIT(status);

    return status;
}

#endif

/* 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;
    }
    section = icpGetProcessName();
    /* Parse Sym ring details */
    status = Sal_StringParsing(SAL_CFG_CY,
                               pCryptoService->generic_service_info.instance,
                               SAL_CFG_RING_SYM_TX,
                               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(SAL_CFG_CY,
                               pCryptoService->generic_service_info.instance,
                               SAL_CFG_RING_SYM_RX,
                               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;
}

/* Function that reinitializes the Sym Handles after restart. */
STATIC CpaStatus SalCtrl_SymReinitTransHandle(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;
    }
    section = icpGetProcessName();
    /* Parse Sym ring details */
    status = Sal_StringParsing(SAL_CFG_CY,
                               pCryptoService->generic_service_info.instance,
                               SAL_CFG_RING_SYM_TX,
                               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_transReinitHandle(
        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(SAL_CFG_CY,
                               pCryptoService->generic_service_info.instance,
                               SAL_CFG_RING_SYM_RX,
                               temp_string);
    LAC_CHECK_STATUS_SYM_INIT(status);

    msgSize = LAC_QAT_SYM_RESP_SZ_LW * LAC_LONG_WORD_IN_BYTES;
    status = icp_adf_transReinitHandle(
        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 CpaStatus
SalCtrl_GetCyConcurrentReqNum(char *string1,
                              char *section,
                              char *string2,
                              sal_crypto_service_t *pCryptoService,
                              Cpa32U *pNumCyConcurrentReq,
                              icp_accel_dev_t *device)
{
    CpaStatus status = CPA_STATUS_SUCCESS;
    char adfGetParam[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {0};
    char temp_string[SAL_CFG_MAX_VAL_LEN_IN_BYTES] = {0};
    Cpa32U numCyConcurrentReq = 0;

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

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

    *pNumCyConcurrentReq = numCyConcurrentReq;

    return status;
}

#ifndef ASYM_NOT_SUPPORTED
STATIC CpaStatus SalCtrl_AsymInit(icp_accel_dev_t *device,
                                  sal_service_t *service)
{
    CpaStatus status = CPA_STATUS_SUCCESS;
    Cpa32U numAsymConcurrentReq = 0;
    char temp_string[SAL_CFG_MAX_VAL_LEN_IN_BYTES] = {0};
    sal_crypto_service_t *pCryptoService = (sal_crypto_service_t *)service;
    char *section = icpGetProcessName();

    /* get num concurrent requests from config file */
    if (CPA_STATUS_SUCCESS !=
        SalCtrl_GetCyConcurrentReqNum(SAL_CFG_CY,
                                      section,
                                      SAL_CFG_RING_ASYM_SIZE,
                                      pCryptoService,
                                      &numAsymConcurrentReq,
                                      device))
    {
        LAC_LOG_ERROR("Failed to get NumConcurrentAsymRequests");
        return CPA_STATUS_FAIL;
    }

    /* Create transport handles */
    status = SalCtrl_AsymCreateTransHandle(
        device, service, numAsymConcurrentReq, section);
    LAC_CHECK_STATUS(status);

    /* Allocates memory pools */
    pCryptoService->lac_pke_align_pool = LAC_MEM_POOL_INIT_POOL_ID;
    status = Sal_StringParsing(SAL_CFG_CY,
                               pCryptoService->generic_service_info.instance,
                               SAL_CFG_ASYM_RESIZE_POOL,
                               temp_string);
    LAC_CHECK_STATUS_ASYM_INIT(status);
    status = Lac_MemPoolCreate(
        &pCryptoService->lac_pke_align_pool,
        temp_string,
        (((numAsymConcurrentReq + 1)) * LAC_PKE_BUFFERS_PER_OP_MAX),
        LAC_BITS_TO_BYTES(LAC_MAX_OP_SIZE_IN_BITS),
        LAC_64BYTE_ALIGNMENT,
        CPA_FALSE,
        pCryptoService->nodeAffinity);
    LAC_CHECK_STATUS_ASYM_INIT(status);

    /* Allocate pke request memory pool */
    pCryptoService->lac_pke_req_pool = LAC_MEM_POOL_INIT_POOL_ID;
    status = Sal_StringParsing(SAL_CFG_CY,
                               pCryptoService->generic_service_info.instance,
                               SAL_CFG_ASYM_REQ_POOL,
                               temp_string);
    LAC_CHECK_STATUS_ASYM_INIT(status);
    status = Lac_MemPoolCreate(
        &(pCryptoService->lac_pke_req_pool),
        temp_string,
        (((numAsymConcurrentReq + 1)) * LAC_PKE_MAX_CHAIN_LENGTH),
        sizeof(lac_pke_qat_req_data_t),
        LAC_64BYTE_ALIGNMENT,
        CPA_TRUE,
        pCryptoService->nodeAffinity);
    LAC_CHECK_STATUS_ASYM_INIT(status);

    /* Allocate prime memory pool */
    pCryptoService->lac_prime_pool = LAC_MEM_POOL_INIT_POOL_ID;
    status = Sal_StringParsing(SAL_CFG_CY,
                               pCryptoService->generic_service_info.instance,
                               SAL_CFG_ASYM_PRIME_POOL,
                               temp_string);
    LAC_CHECK_STATUS_ASYM_INIT(status);
    status = Lac_MemPoolCreate(&pCryptoService->lac_prime_pool,
                               temp_string,
                               (numAsymConcurrentReq * 2 + 1),
                               (sizeof(CpaFlatBuffer) * (LAC_PRIME_MAX_MR + 1)),
                               LAC_64BYTE_ALIGNMENT,
                               CPA_FALSE,
                               pCryptoService->nodeAffinity);
    LAC_CHECK_STATUS_ASYM_INIT(status);

    /* Allocate EC memory pool */
    pCryptoService->lac_ec_pool = LAC_MEM_POOL_INIT_POOL_ID;
    status = Sal_StringParsing(SAL_CFG_CY,
                               pCryptoService->generic_service_info.instance,
                               SAL_CFG_ASYM_EC_MEM_POOL,
                               temp_string);
    LAC_CHECK_STATUS_ASYM_INIT(status);
    status =
        Lac_MemPoolCreate(&pCryptoService->lac_ec_pool,
                          temp_string,
                          ((numAsymConcurrentReq + 1)),
                          ((LAC_EC_NUM_CONCAT_INPUTS * LAC_EC_SIZE_BYTES_MAX) +
                           sizeof(CpaFlatBuffer)),
                          LAC_64BYTE_ALIGNMENT,
                          CPA_FALSE,
                          pCryptoService->nodeAffinity);
    LAC_CHECK_STATUS_ASYM_INIT(status);

    SAL_GET_INSTANCE_CRYPTO_CAPABILITY_STATUS(status, service, kpt);
    if (CPA_STATUS_SUCCESS == status)
    {
        /* Allocate KPT asymmetric service memory pool */
        pCryptoService->lac_pke_kpt_pool = LAC_MEM_POOL_INIT_POOL_ID;
        status =
            Sal_StringParsing(SAL_CFG_CY,
                              pCryptoService->generic_service_info.instance,
                              SAL_CFG_ASYM_KPT_UNWRAP_CTX_MEM_POOL,
                              temp_string);
        LAC_CHECK_STATUS_ASYM_INIT(status);
        status = Lac_MemPoolCreate(
            &pCryptoService->lac_pke_kpt_pool,
            temp_string,
            numAsymConcurrentReq + 1,
            (LAC_KPT_UNWRAP_CTX_SIZE_IN_BYTES + sizeof(CpaFlatBuffer)),
            LAC_64BYTE_ALIGNMENT,
            CPA_FALSE,
            pCryptoService->nodeAffinity);
        LAC_CHECK_STATUS_ASYM_INIT(status);
    }

    /* Clear Key stats and allocate memory of SSL and TLS labels
        These labels are initialised to standard values */

#ifdef QAT_LEGACY_ALGORITHMS
    /* Init DH stats */
    status = LacDh_Init(pCryptoService);
    LAC_CHECK_STATUS_ASYM_INIT(status);
#endif

#ifdef QAT_LEGACY_ALGORITHMS
    /* Init Dsa stats */
    status = LacDsa_Init(pCryptoService);
    LAC_CHECK_STATUS_ASYM_INIT(status);
#endif

    /* Init Ec stats */
    status = LacEc_Init(pCryptoService);
    LAC_CHECK_STATUS_ASYM_INIT(status);

    /* Init Ln Stats */
    status = LacLn_Init(pCryptoService);
    LAC_CHECK_STATUS_ASYM_INIT(status);

    /* Init Prime stats */
    status = LacPrime_Init(pCryptoService);
    LAC_CHECK_STATUS_ASYM_INIT(status);

    /* Init Rsa Stats */
    status = LacRsa_Init(pCryptoService);
    LAC_CHECK_STATUS_ASYM_INIT(status);

    /* Build Flow ID for all pke request sent on this instance */
    pCryptoService->pkeFlowId =
        (LAC_PKE_FLOW_ID_TAG |
         (pCryptoService->acceleratorNum << LAC_PKE_ACCEL_ID_BIT_POS) |
         (pCryptoService->executionEngine << LAC_PKE_SLICE_ID_BIT_POS));

    /* For all asym requests fill out known data */
    Lac_MemPoolInitAsymCookies(pCryptoService->lac_pke_req_pool,
                               pCryptoService);

    return status;
}

STATIC CpaStatus SalCtrl_AsymReinit(icp_accel_dev_t *device,
                                    sal_service_t *service)
{
    CpaStatus status = CPA_STATUS_SUCCESS;
    Cpa32U numAsymConcurrentReq = 0;
    sal_crypto_service_t *pCryptoService = (sal_crypto_service_t *)service;
    char *section = icpGetProcessName();

    /* get num concurrent requests from config file */
    if (CPA_STATUS_SUCCESS !=
        SalCtrl_GetCyConcurrentReqNum(SAL_CFG_CY,
                                      section,
                                      SAL_CFG_RING_ASYM_SIZE,
                                      pCryptoService,
                                      &numAsymConcurrentReq,
                                      device))
    {
        LAC_LOG_ERROR("Failed to get NumConcurrentAsymRequests");
        return CPA_STATUS_FAIL;
    }

    /* Create transport handles */
    status = SalCtrl_AsymReinitTransHandle(
        device, service, numAsymConcurrentReq, section);
    LAC_CHECK_STATUS(status);

    /* Enables memory pools for allocation */
    Lac_MemPoolEnable(pCryptoService->lac_pke_req_pool);

    /* Build Flow ID for all pke request sent on this instance */
    pCryptoService->pkeFlowId =
        (LAC_PKE_FLOW_ID_TAG |
         (pCryptoService->acceleratorNum << LAC_PKE_ACCEL_ID_BIT_POS) |
         (pCryptoService->executionEngine << LAC_PKE_SLICE_ID_BIT_POS));

    /* For all asym requests fill out known data */
    Lac_MemPoolInitAsymCookies(pCryptoService->lac_pke_req_pool,
                               pCryptoService);

    return status;
}
#endif

STATIC CpaStatus SalCtrl_SymInit(icp_accel_dev_t *device,
                                 sal_service_t *service)
{
    CpaStatus status = CPA_STATUS_SUCCESS;
    Cpa32U numSymConcurrentReq = 0;
    char temp_string[SAL_CFG_MAX_VAL_LEN_IN_BYTES] = {0};
    sal_crypto_service_t *pCryptoService = (sal_crypto_service_t *)service;
    char *section = icpGetProcessName();

    /* Gen6 supports only AUTH_MODE2 for HMAC */
    if (pCryptoService->generic_service_info.isGen6)
        pCryptoService->qatHmacMode = ICP_QAT_HW_AUTH_MODE2;
    else
        pCryptoService->qatHmacMode = ICP_QAT_HW_AUTH_MODE1;

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

    /* Get num concurrent requests from config file */
    if (CPA_STATUS_SUCCESS !=
        SalCtrl_GetCyConcurrentReqNum(SAL_CFG_CY,
                                      section,
                                      SAL_CFG_RING_SYM_SIZE,
                                      pCryptoService,
                                      &numSymConcurrentReq,
                                      device))
    {
        LAC_LOG_ERROR("Failed to get NumConcurrentSymRequests");
        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(SAL_CFG_CY,
                               pCryptoService->generic_service_info.instance,
                               SAL_CFG_SYM_POOL,
                               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_TRUE,
        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,
                                     pCryptoService);

    /* Clear stats */
    status = LacSymKey_StatsInit(pCryptoService);
    LAC_CHECK_STATUS_SYM_INIT(status);

    /* 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 CpaStatus SalCtrl_SymReinit(icp_accel_dev_t *device,
                                   sal_service_t *service)
{
    CpaStatus status = CPA_STATUS_SUCCESS;
    Cpa32U numSymConcurrentReq = 0;
    sal_crypto_service_t *pCryptoService = (sal_crypto_service_t *)service;
    char *section = icpGetProcessName();

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

    /* Get num concurrent requests from config file */
    if (CPA_STATUS_SUCCESS !=
        SalCtrl_GetCyConcurrentReqNum(SAL_CFG_CY,
                                      section,
                                      SAL_CFG_RING_SYM_SIZE,
                                      pCryptoService,
                                      &numSymConcurrentReq,
                                      device))
    {
        LAC_LOG_ERROR("Failed to get NumConcurrentSymRequests");
        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_SymReinitTransHandle(
        device, service, numSymConcurrentReq, section);
    LAC_CHECK_STATUS(status);

    /* Enables memory pools for allocation */
    Lac_MemPoolEnable(pCryptoService->lac_sym_cookie_pool);
    /* For all sym cookies fill out the physical address of data that
       will be set to QAT */
    Lac_MemPoolInitSymCookiesPhyAddr(pCryptoService->lac_sym_cookie_pool,
                                     pCryptoService);

    return status;
}

STATIC void SalCtrl_StatsShutdown(icp_accel_dev_t *device,
                                  sal_service_t *service)
{
    sal_crypto_service_t *pCryptoService = (sal_crypto_service_t *)service;
    pCryptoService->generic_service_info.stats = NULL;
}

STATIC void SalCtrl_StatsInit(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;

    pCryptoService->generic_service_info.stats = pStatsCollection;
}

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(SAL_CFG_CY, inst, bank_name, adfParamName);
    LAC_CHECK_STATUS(status);
    status =
        icp_adf_cfgGetParamValue(device, section, adfParamName, adfParamValue);
    if (CPA_STATUS_SUCCESS != status)
    {
        LAC_LOG_STRING_ERROR1("Failed to get %s from configuration file",
                              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 = icpGetProcessName();
    Cpa32S strSize = 0;

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

    pCryptoService->acceleratorNum = (Cpa16U)device->accelId;

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

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

    /* User instances only support poll and epoll mode */
    if (SAL_RESP_POLL_CFG_FILE != pCryptoService->isPolled &&
        SAL_RESP_EPOLL_CFG_FILE != pCryptoService->isPolled)
    {
        LAC_LOG_ERROR_PARAMS("IsPolled %u is not supported for "
                             "user 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)
    {
        LAC_LOG_STRING_ERROR1("Failed to get %s from configuration file",
                              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)
    {
        LAC_LOG_STRING_ERROR1("Failed to get %s from configuration file",
                              ADF_DEV_NODE_ID);
        return status;
    }
    pCryptoService->nodeAffinity =
        (Cpa32U)Sal_Strtoul(adfGetParam, NULL, SAL_CFG_BASE_DEC);

    strSize = snprintf(temp_string2, sizeof(temp_string2), "%s", section);
    LAC_CHECK_PARAM_RANGE(strSize, 1, sizeof(temp_string2));

    status = Sal_StringParsing(SAL_CFG_CY,
                               pCryptoService->generic_service_info.instance,
                               SAL_CFG_ETRMGR_CORE_AFFINITY,
                               temp_string);
    LAC_CHECK_STATUS(status);

    status = icp_adf_cfgGetParamValue(
        device, temp_string2, temp_string, adfGetParam);
    if (CPA_STATUS_SUCCESS != status)
    {
        LAC_LOG_STRING_ERROR1("Failed to get %s from configuration file",
                              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);

    SalCtrl_CyQueryCapabilities(service, &pCryptoService->capInfo);

    SalCtrl_StatsInit(device, service);

    switch (svc_type)
    {
#ifndef ASYM_NOT_SUPPORTED
        case SAL_SERVICE_TYPE_CRYPTO_ASYM:
            status = SalCtrl_AsymInit(device, service);
            if (CPA_STATUS_SUCCESS != status)
            {
                SalCtrl_StatsShutdown(device, service);
                return status;
            }
            break;
#endif
        case SAL_SERVICE_TYPE_CRYPTO_SYM:
            status = SalCtrl_SymInit(device, service);
            if (CPA_STATUS_SUCCESS != status)
            {
                SalCtrl_StatsShutdown(device, service);
                return status;
            }
            break;
        case SAL_SERVICE_TYPE_CRYPTO:
#ifndef ASYM_NOT_SUPPORTED
            status = SalCtrl_AsymInit(device, service);
            if (CPA_STATUS_SUCCESS != status)
            {
                SalCtrl_StatsShutdown(device, service);
                return status;
            }
#endif
            status = SalCtrl_SymInit(device, service);
            if (CPA_STATUS_SUCCESS != status)
            {
                SalCtrl_StatsShutdown(device, service);
#ifndef ASYM_NOT_SUPPORTED
                SalCtrl_AsymFreeResources(pCryptoService);
#endif
                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) &&
        (SAL_SERVICE_STATE_RESTARTING !=
         pCryptoService->generic_service_info.state))
    {
        LAC_LOG_ERROR("Not in the correct state to call shutdown\n");
        return CPA_STATUS_FAIL;
    }

    if (pCryptoService->generic_service_info.virt2PhysClient)
    {
        osalMemFree(pCryptoService->generic_service_info.virt2PhysClient);
        pCryptoService->generic_service_info.virt2PhysClient = NULL;
    }

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

    SalCtrl_StatsShutdown(device, service);

    pCryptoService->generic_service_info.state = SAL_SERVICE_STATE_SHUTDOWN;

    return status;
}

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

    LAC_CHECK_NULL_PARAM(service);

    SalCtrl_CyMemPoolDisable(service);
    SalCtrl_CyUpdatePoolsBusy(service);

    /* Considering the detachment of the VFs, the device is still alive and
     * can generate responses normally. After the state of the service is
     * set to ERROR, if it goes to the function to check responses in such
     * cases, it will indicate there are some responses on the ring. However,
     * icp_sal_CyPollInstance() function will only call
     * SalCtrl_CyGenResponses() to generate dummy responses not poll the
     * instance with icp_adf_pollInstance() as the service has been set to
     * ERROR. So adding a judgment condition here to avoid to check the
     * response ring again. */
    if (SAL_SERVICE_STATE_ERROR != pCryptoService->generic_service_info.state)
    {
        status = SalCtrl_CyCheckRespInstance(service);
        /* The polling functions would be prevented to poll due to
         * SAL_RUNNING_CHECK check which may cause missing retrieving in-flight
         * responses. Hence the error status is only set after there are no
         * remained responses on the response ring. */
        if (CPA_STATUS_SUCCESS == status)
        {
            pCryptoService->generic_service_info.state =
                SAL_SERVICE_STATE_ERROR;
        }
    }
    return status;
}

CpaStatus SalCtrl_CryptoRestarting(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_RUNNING !=
         pCryptoService->generic_service_info.state) &&
        (SAL_SERVICE_STATE_ERROR != pCryptoService->generic_service_info.state))
    {
        LAC_LOG_ERROR("Not in the correct state to call restarting\n");
        return CPA_STATUS_FAIL;
    }

    switch (svc_type)
    {
#ifndef ASYM_NOT_SUPPORTED
        case SAL_SERVICE_TYPE_CRYPTO_ASYM:
            if (SalCtrl_AsymResetResources(pCryptoService))
            {
                status = CPA_STATUS_FAIL;
            }
            break;
#endif
        case SAL_SERVICE_TYPE_CRYPTO_SYM:
            if (SalCtrl_SymResetResources(pCryptoService))
            {
                status = CPA_STATUS_FAIL;
            }
            break;
        case SAL_SERVICE_TYPE_CRYPTO:
#ifndef ASYM_NOT_SUPPORTED
            if (SalCtrl_AsymResetResources(pCryptoService))
            {
                status = CPA_STATUS_FAIL;
            }
#endif
            if (SalCtrl_SymResetResources(pCryptoService))
            {
                status = CPA_STATUS_FAIL;
            }
            break;
        default:
            LAC_LOG_ERROR("Invalid service type\n");
            status = CPA_STATUS_FAIL;
            break;
    }

    pCryptoService->generic_service_info.state = SAL_SERVICE_STATE_RESTARTING;

    return status;
}

CpaStatus SalCtrl_CryptoRestarted(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_RESTARTED(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);

    SalCtrl_CyQueryCapabilities(service, &pCryptoService->capInfo);

    SalCtrl_StatsInit(device, service);

    switch (svc_type)
    {
#ifndef ASYM_NOT_SUPPORTED
        case SAL_SERVICE_TYPE_CRYPTO_ASYM:
            status = SalCtrl_AsymReinit(device, service);
            if (CPA_STATUS_SUCCESS != status)
            {
                SalCtrl_StatsShutdown(device, service);
                return status;
            }
            break;
#endif
        case SAL_SERVICE_TYPE_CRYPTO_SYM:
            status = SalCtrl_SymReinit(device, service);
            if (CPA_STATUS_SUCCESS != status)
            {
                SalCtrl_StatsShutdown(device, service);
                return status;
            }
            break;
        case SAL_SERVICE_TYPE_CRYPTO:
#ifndef ASYM_NOT_SUPPORTED
            status = SalCtrl_AsymReinit(device, service);
            if (CPA_STATUS_SUCCESS != status)
            {
                SalCtrl_StatsShutdown(device, service);
                return status;
            }
#endif
            status = SalCtrl_SymReinit(device, service);
            if (CPA_STATUS_SUCCESS != status)
            {
                SalCtrl_StatsShutdown(device, service);
#ifndef ASYM_NOT_SUPPORTED
                SalCtrl_AsymFreeResources(pCryptoService);
#endif
                return status;
            }
            break;
        default:
            SalCtrl_StatsShutdown(device, service);
            LAC_LOG_ERROR("Invalid service type\n");
            status = CPA_STATUS_FAIL;
            break;
    }

    pCryptoService->generic_service_info.state = SAL_SERVICE_STATE_RUNNING;

    return status;
}

void SalCtrl_CyQueryCapabilities(sal_service_t *pGenericService,
                                 CpaCyCapabilitiesInfo *pCapInfo)
{
    osalMemSet(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 (SAL_SERVICE_TYPE_CRYPTO == pGenericService->type ||
        SAL_SERVICE_TYPE_CRYPTO_ASYM == pGenericService->type)
    {
        if (pGenericService->capabilitiesMask & ICP_ACCEL_CAPABILITIES_KPT)
        {
            /* Enable KPT only when KPT capability is set */
            pCapInfo->kptSupported = CPA_TRUE;
        }
        else
        {
#ifdef ASYM_NOT_SUPPORTED
            pCapInfo->dhSupported = CPA_FALSE;
            pCapInfo->dsaSupported = CPA_FALSE;
            pCapInfo->rsaSupported = CPA_FALSE;
            pCapInfo->ecSupported = CPA_FALSE;
            pCapInfo->ecdhSupported = CPA_FALSE;
            pCapInfo->ecdsaSupported = CPA_FALSE;
            pCapInfo->keySupported = CPA_FALSE;
            pCapInfo->lnSupported = CPA_FALSE;
            pCapInfo->primeSupported = CPA_FALSE;
            pCapInfo->ecEdMontSupported = CPA_FALSE;
#else
#ifdef QAT_LEGACY_ALGORITHMS
            pCapInfo->dhSupported = CPA_TRUE;
            pCapInfo->dsaSupported = CPA_TRUE;
#else
            pCapInfo->dhSupported = CPA_FALSE;
            pCapInfo->dsaSupported = CPA_FALSE;
#endif
            pCapInfo->rsaSupported = CPA_TRUE;
            pCapInfo->ecSupported = CPA_TRUE;
            pCapInfo->ecdhSupported = CPA_TRUE;
            pCapInfo->ecdsaSupported = CPA_TRUE;
            pCapInfo->keySupported = CPA_TRUE;
            pCapInfo->lnSupported = CPA_TRUE;
            pCapInfo->primeSupported = CPA_TRUE;
            if (pGenericService->capabilitiesMask &
                ICP_ACCEL_CAPABILITIES_ECEDMONT)
            {
                pCapInfo->ecEdMontSupported = CPA_TRUE;
            }

            if (pGenericService->capabilitiesMask & ICP_ACCEL_CAPABILITIES_SM2)
            {
                pCapInfo->ecSm2Supported = CPA_TRUE;
            }
            else
            {
                pCapInfo->ecSm2Supported = CPA_FALSE;
            }
#endif
        }
    }
    pCapInfo->drbgSupported = CPA_FALSE;
    pCapInfo->nrbgSupported = CPA_FALSE;
    pCapInfo->randSupported = CPA_FALSE;
}

CpaStatus SalCtrl_CySymQueryCapabilities(sal_service_t *pGenericService,
                                         CpaCySymCapabilitiesInfo *pCapInfo)
{
    LAC_CHECK_NULL_PARAM(pGenericService);
    LAC_CHECK_NULL_PARAM(pCapInfo);

    osalMemSet(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;
    }

    if (pGenericService->capabilitiesMask & ICP_ACCEL_CAPABILITIES_CIPHER)
    {
#ifdef QAT_LEGACY_ALGORITHMS
        CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_ECB);
#endif
        CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_NULL);

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

    /* Report hashes supported if capability supports authentication. This
     * is also used for a compression instance (DC Chaining) to determine if
     * DC Chaining supports hash operations.
     */
    if (pGenericService->capabilitiesMask &
        ICP_ACCEL_CAPABILITIES_AUTHENTICATION)
    {
#ifdef QAT_LEGACY_ALGORITHMS
        CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SHA1);
        CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SHA224);
#endif
        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_CMAC);
        CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_AES_CBC_MAC);
    }

    if ((pGenericService->capabilitiesMask & ICP_ACCEL_CAPABILITIES_CIPHER) &&
        (pGenericService->capabilitiesMask &
         ICP_ACCEL_CAPABILITIES_AUTHENTICATION))
    {
        /* When one of the following cipher algorithms is used, the elements of
         * the CpaCySymHashAlgorithm enum MUST be used to set up the related
         * CpaCySymHashSetupData structure in the session context.
         *    CPA_CY_SYM_CIPHER_AES_CCM
         *    CPA_CY_SYM_CIPHER_AES_GCM
         */
        CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_CCM);
        CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_GCM);

        /* When one of the following hash algorithms is used, the elements of
         * the CpaCySymCipherAlgorithm enum MUST be used to set up the related
         * CpaCySymCipherSetupData structure in the session context.
         *    CPA_CY_SYM_HASH_AES_CCM
         *    CPA_CY_SYM_HASH_AES_GCM
         *    CPA_CY_SYM_HASH_AES_GMAC
         */
        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_GMAC);
    }

    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_CRYPTO_SHA3)
    {
        CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SHA3_256);
    }
    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);
    }

    pCapInfo->partialPacketSupported = CPA_TRUE;

    if (pGenericService->capabilitiesMask & ICP_ACCEL_CAPABILITIES_SHA3_EXT)
    {
#ifdef QAT_LEGACY_ALGORITHMS
        CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SHA3_224);
#endif
        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);
    }

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

    if (pGenericService->capabilitiesMask & ICP_ACCEL_CAPABILITIES_SM4)
    {
#ifdef QAT_LEGACY_ALGORITHMS
        CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_SM4_ECB);
#endif
        CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_SM4_CBC);
        CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_SM4_CTR);
    }

    if (pGenericService->capabilitiesMask &
        ICP_ACCEL_CAPABILITIES_WIRELESS_CRYPTO_EXT)
    {
#ifdef QAT_LEGACY_ALGORITHMS
        CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_F8);
#endif
        CPA_BITMAP_BIT_SET(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_SNOW3G_UEA2);
        CPA_BITMAP_BIT_SET(pCapInfo->hashes, CPA_CY_SYM_HASH_SNOW3G_UIA2);
    }

    /* Enable only supported algorithm list for Cipher and Hash for Gen6 device
     */
    if (pGenericService->isGen6)
    {
        CPA_BITMAP_BIT_CLEAR(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_CBC);
        CPA_BITMAP_BIT_CLEAR(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_CCM);
        CPA_BITMAP_BIT_CLEAR(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_AES_ECB);
        CPA_BITMAP_BIT_CLEAR(pCapInfo->hashes, CPA_CY_SYM_HASH_AES_GMAC);
        CPA_BITMAP_BIT_CLEAR(pCapInfo->hashes, CPA_CY_SYM_HASH_AES_CCM);
        CPA_BITMAP_BIT_CLEAR(pCapInfo->hashes, CPA_CY_SYM_HASH_AES_XCBC);
        if (!(pGenericService->capabilitiesMask &
              ICP_ACCEL_CAPABILITIES_WIRELESS_CRYPTO_EXT))
        {
            CPA_BITMAP_BIT_CLEAR(pCapInfo->hashes, CPA_CY_SYM_HASH_AES_CMAC);
            CPA_BITMAP_BIT_CLEAR(pCapInfo->hashes, CPA_CY_SYM_HASH_SNOW3G_UIA2);
            CPA_BITMAP_BIT_CLEAR(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_NULL);
        }
        CPA_BITMAP_BIT_CLEAR(pCapInfo->hashes, CPA_CY_SYM_HASH_AES_CBC_MAC);
        CPA_BITMAP_BIT_CLEAR(pCapInfo->hashes, CPA_CY_SYM_HASH_KASUMI_F9);
        CPA_BITMAP_BIT_CLEAR(pCapInfo->hashes, CPA_CY_SYM_HASH_SM3);
        CPA_BITMAP_BIT_CLEAR(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_SM4_ECB);
        CPA_BITMAP_BIT_CLEAR(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_SM4_CBC);
        CPA_BITMAP_BIT_CLEAR(pCapInfo->ciphers, CPA_CY_SYM_CIPHER_SM4_CTR);
        pCapInfo->partialPacketSupported = CPA_FALSE;
    }

    return CPA_STATUS_SUCCESS;
}

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

#ifdef ICP_TRACE
    LAC_LOG3("Called with params (0x%lx, %d, 0x%lx)\n",
             (LAC_ARCH_UINT)instanceHandle,
             errStatus,
             (LAC_ARCH_UINT)pStatusText);
#endif

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

/**
 ******************************************************************************
 * @ingroup cpaCyCommon
 *****************************************************************************/
CpaStatus cpaCyStartInstance(CpaInstanceHandle instanceHandle_in)
{
    CpaInstanceHandle instanceHandle = NULL;
    icp_accel_dev_t *dev = NULL;
    sal_crypto_service_t *pService = NULL;

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

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

    pService = (sal_crypto_service_t *)instanceHandle;

    dev = icp_adf_getAccelDevByAccelId(pService->acceleratorNum);
    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_adf_qaDevGet(dev);
    return CPA_STATUS_SUCCESS;
}

/**
 ******************************************************************************
 * @ingroup cpaCyCommon
 *****************************************************************************/
CpaStatus cpaCyStopInstance(CpaInstanceHandle instanceHandle_in)
{
    CpaInstanceHandle instanceHandle = NULL;
    icp_accel_dev_t *dev = NULL;
    sal_crypto_service_t *pService = NULL;

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

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

    pService = (sal_crypto_service_t *)instanceHandle;

    dev = icp_adf_getAccelDevByAccelId(pService->acceleratorNum);
    if (NULL == dev)
    {
        LAC_LOG_ERROR("Can not find device for the instance\n");
        return CPA_STATUS_FAIL;
    }

    pService->generic_service_info.isInstanceStarted = CPA_FALSE;

    /* Decrement dev ref counter */
    icp_adf_qaDevPut(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;

#ifdef ICP_TRACE
    LAC_LOG3("Called with params (0x%lx, 0x%lx, 0x%lx)\n",
             (LAC_ARCH_UINT)instanceHandle,
             (LAC_ARCH_UINT)pInstanceNotificationCb,
             (LAC_ARCH_UINT)pCallbackTag);
#endif

    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,
                               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";
#ifdef ICP_TRACE
    LAC_LOG2("Called with params (0x%lx, 0x%lx)\n",
             (LAC_ARCH_UINT)instanceHandle_in,
             (LAC_ARCH_UINT)pInstanceInfo);
#endif

    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[CPA_INST_NAME_SIZE] = { 0 };
    char valStrInstName[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 };
    char *section = NULL;
    Cpa32S strSize = 0;

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

    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));
    pCryptoService = (sal_crypto_service_t *)instanceHandle;
    switch (pCryptoService->generic_service_info.type)
    {
        case SAL_SERVICE_TYPE_CRYPTO:
            pInstanceInfo2->accelerationServiceType = CPA_ACC_SVC_TYPE_CRYPTO;
            break;
        case SAL_SERVICE_TYPE_CRYPTO_ASYM:
            pInstanceInfo2->accelerationServiceType =
                CPA_ACC_SVC_TYPE_CRYPTO_ASYM;
            break;
        case SAL_SERVICE_TYPE_CRYPTO_SYM:
            pInstanceInfo2->accelerationServiceType =
                CPA_ACC_SVC_TYPE_CRYPTO_SYM;
            break;
        default:
            LAC_LOG_ERROR("Invalid service type!\n");
            return CPA_STATUS_FAIL;
    }
    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",
             QAT_LIBRARY_VERSION_MAJOR,
             QAT_LIBRARY_VERSION_MINOR);
    pInstanceInfo2->swVersion[CPA_INST_SW_VERSION_SIZE - 1] = '\0';

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

    /* 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 (CPA_TRUE == pCryptoService->generic_service_info.isInstanceStarted)
    {
        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 ||
        SAL_RESP_EPOLL_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->acceleratorNum);
    if (NULL == dev)
    {
        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(SAL_CFG_CY,
                               pCryptoService->generic_service_info.instance,
                               SAL_CFG_NAME,
                               keyStr);
    LAC_CHECK_STATUS(status);
    section = icpGetProcessName();
    status = icp_adf_cfgGetParamValue(dev, section, keyStr, valStrInstName);

    LAC_CHECK_STATUS(status);

    strSize = strnlen(valStrInstName, sizeof(valStrInstName));
    LAC_CHECK_PARAM_RANGE(strSize, 1, CPA_INST_NAME_SIZE);
    snprintf((char *)pInstanceInfo2->instName,
             CPA_INST_NAME_SIZE,
             "%.*s",
             CPA_INST_NAME_SIZE - 1,
             valStrInstName);

    /* Copy valStrInstName to valStr for safe instID concatenation */
    strncpy(valStr, valStrInstName, CPA_INST_NAME_SIZE - 1);
    valStr[CPA_INST_NAME_SIZE - 1] = '\0';

    strSize = strnlen(valStr, sizeof(valStr)) +
              strnlen(section, LAC_USER_PROCESS_NAME_MAX_LEN) + 1;

    LAC_CHECK_PARAM_RANGE(strSize, 1, CPA_INST_ID_SIZE);
    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;

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

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

    *pCapInfo = ((sal_crypto_service_t *)instanceHandle)->capInfo;

    return CPA_STATUS_SUCCESS;
}

CpaStatus cpaCySymQueryCapabilities(const CpaInstanceHandle instanceHandle_in,
                                    CpaCySymCapabilitiesInfo *pCapInfo)
{
    CpaInstanceHandle instanceHandle = NULL;

#ifdef ICP_TRACE
    LAC_LOG2("Called with params (0x%lx, 0x%lx)\n",
             (LAC_ARCH_UINT)instanceHandle_in,
             (LAC_ARCH_UINT)pCapInfo);
#endif
    /* Verify Instance exists */
    if (CPA_INSTANCE_HANDLE_SINGLE == instanceHandle_in)
    {
        instanceHandle = Lac_GetFirstHandle(SAL_SERVICE_TYPE_CRYPTO_SYM);
        if (!instanceHandle)
        {
            instanceHandle = Lac_GetFirstHandle(SAL_SERVICE_TYPE_CRYPTO);
        }
    }
    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));

    return SalCtrl_CySymQueryCapabilities((sal_service_t *)instanceHandle,
                                          pCapInfo);
}

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

    CpaInstanceHandle instanceHandle = NULL;
    sal_service_t *pService = NULL;

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

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

    if ((Sal_ServiceIsInError(crypto_handle)))
    {

        LAC_LOG_DEBUG("PollCyInstance: generate dummy responses\n");
        status = SalCtrl_CyGenResponses(crypto_handle, gen_handle);
        if ((CPA_STATUS_SUCCESS != status) && (CPA_STATUS_RETRY != status))
        {
            LAC_LOG_ERROR("Failed to generate SW responses for CY\n");
        }
        return status;
    }

    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.
     */
    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 a symmetric instance.
 *****************************************************************************/
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 trans handle table with the appropriate handle.
     */
    trans_hndTable[TH_CY_RX_0] = 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 asymmetric instance.
 *****************************************************************************/
CpaStatus icp_sal_CyPollAsymRing(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[NUM_CRYPTO_ASYM_RX_RINGS] = {0};

    if (CPA_INSTANCE_HANDLE_SINGLE == instanceHandle_in)
    {
        crypto_handle = (sal_crypto_service_t *)Lac_GetFirstHandle(
            SAL_SERVICE_TYPE_CRYPTO_ASYM);
    }
    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_ASYM));

    gen_handle = &(crypto_handle->generic_service_info);

    if ((Sal_ServiceIsInError(crypto_handle)))
    {
        LAC_LOG_DEBUG("Generate dummy responses\n");
        status = SalCtrl_CyGenResponses(crypto_handle, gen_handle);
        if ((CPA_STATUS_SUCCESS != status) && (CPA_STATUS_RETRY != status))
        {
            LAC_LOG_ERROR("Failed to generate dummy Responses\n");
        }
        return status;
    }

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

/* Polling CY instances' memory pool in progress of all banks for one device */
STATIC CpaStatus Lac_CyService_GenResponses(sal_list_t **services)
{
    CpaInstanceHandle cyInstHandle = NULL;
    sal_list_t *sal_service = NULL;
    sal_crypto_service_t *crypto_handle = NULL;
    sal_service_t *gen_handle = NULL;
    CpaStatus status = CPA_STATUS_SUCCESS;

    LAC_CHECK_NULL_PARAM(services);

    sal_service = *services;
    while (sal_service)
    {
        cyInstHandle = (void *)SalList_getObject(sal_service);
        crypto_handle = (sal_crypto_service_t *)cyInstHandle;
        LAC_CHECK_NULL_PARAM(crypto_handle);

        gen_handle = &(crypto_handle->generic_service_info);
        status = SalCtrl_CyGenResponses(crypto_handle, gen_handle);
        if (CPA_STATUS_SUCCESS != status)
        {
            break;
        }
        sal_service = SalList_next(sal_service);
    }
    return status;
}

CpaStatus SalCtrl_CyDevErr_GenResponses(icp_accel_dev_t *accel_dev,
                                        Cpa32U enabled_services)
{
    sal_t *service_container = NULL;
    CpaStatus status = CPA_STATUS_SUCCESS;
    CpaStatus symStatus = CPA_STATUS_SUCCESS;
    service_container = accel_dev->pSalHandle;

    if (SalCtrl_IsServiceEnabled(enabled_services,
                                 SAL_SERVICE_TYPE_CRYPTO_ASYM))
    {
        status = Lac_CyService_GenResponses(&service_container->asym_services);
        if (CPA_STATUS_SUCCESS != status && CPA_STATUS_RETRY != status)
        {
            LAC_LOG_ERROR(
                "Failed to generate dummy responses for asym service");
            return status;
        }
    }
    if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO_SYM))
    {
        symStatus =
            Lac_CyService_GenResponses(&service_container->sym_services);
        if (CPA_STATUS_SUCCESS != symStatus && CPA_STATUS_RETRY != symStatus)
        {
            LAC_LOG_ERROR("Failed to generate dummy responses for sym service");
            return symStatus;
        }
        if (CPA_STATUS_SUCCESS == status || CPA_STATUS_SUCCESS == symStatus)
            status = CPA_STATUS_SUCCESS;
    }
    else if (SalCtrl_IsServiceEnabled(enabled_services,
                                      SAL_SERVICE_TYPE_CRYPTO))
    {
        status =
            Lac_CyService_GenResponses(&service_container->crypto_services);
        if (CPA_STATUS_SUCCESS != status && CPA_STATUS_RETRY != status)
        {
            LAC_LOG_ERROR(
                "Failed to generate dummy responses for crypto service");
            return status;
        }
    }
    return status;
}

/* Returns the handle to the first asym crypto instance */
STATIC CpaInstanceHandle
Lac_GetFirstAsymHandle(icp_accel_dev_t *adfInsts[ADF_MAX_DEVICES],
                       Cpa16U num_dev)
{
    icp_accel_dev_t *dev_addr = NULL;
    sal_t *base_addr = NULL;
    sal_list_t *list_temp = NULL;
    CpaInstanceHandle cyInst = NULL;
    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) && (NULL != base_addr->asym_services))
        {
            list_temp = base_addr->asym_services;
            cyInst = SalList_getObject(list_temp);
            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)
{
    icp_accel_dev_t *dev_addr = NULL;
    sal_t *base_addr = NULL;
    sal_list_t *list_temp = NULL;
    CpaInstanceHandle cyInst = NULL;
    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) && (NULL != base_addr->sym_services))
        {
            list_temp = base_addr->sym_services;
            cyInst = SalList_getObject(list_temp);
            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)
{
    icp_accel_dev_t *dev_addr = NULL;
    sal_t *base_addr = NULL;
    sal_list_t *list_temp = NULL;
    CpaInstanceHandle cyInst = NULL;
    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) && (NULL != base_addr->crypto_services))
        {
            list_temp = base_addr->crypto_services;
            cyInst = SalList_getObject(list_temp);
            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;
    char *service = NULL;

    switch (svc_type)
    {
        case SAL_SERVICE_TYPE_CRYPTO_ASYM:
            capabilities = ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC;
            service = "asym";
            break;
        case SAL_SERVICE_TYPE_CRYPTO_SYM:
            capabilities = ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC;
            service = "sym";
            break;
        case SAL_SERVICE_TYPE_CRYPTO:
            capabilities = ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC;
            capabilities |= ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC;
            service = "cy";
            break;
        default:
            LAC_LOG_ERROR("Invalid service type\n");
            return NULL;
    }
    /* Only need 1 dev with crypto enabled - so check all devices*/
    status = icp_adf_getAllAccelDevByEachCapability(
        capabilities, adfInsts, &num_cy_dev);
    if ((0 == num_cy_dev) || (CPA_STATUS_SUCCESS != status))
    {
        LAC_LOG1("No %s devices enabled in the system\n", service);
        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:
            /* All other types are rejected by the first switch above */
            break;
    }
    if (NULL == cyInst)
    {
        LAC_LOG_ERROR("No remaining crypto instances available\n");
    }
    return cyInst;
}

CpaStatus icp_sal_CyGetFileDescriptor(CpaInstanceHandle instanceHandle, int *fd)
{
    sal_crypto_service_t *crypto_handle = NULL;
    sal_service_t *gen_handle = NULL;
    CpaStatus status = CPA_STATUS_SUCCESS;

    crypto_handle = (sal_crypto_service_t *)instanceHandle;

    /* Make sure that we zero file descriptor
     * in case of error or unsupported. */
    LAC_CHECK_NULL_PARAM(fd);
    *fd = 0;

    LAC_CHECK_NULL_PARAM(crypto_handle);
    SAL_RUNNING_CHECK(crypto_handle);
    if (SAL_RESP_EPOLL_CFG_FILE != crypto_handle->isPolled)
    {
        return CPA_STATUS_UNSUPPORTED;
    }

    gen_handle = &(crypto_handle->generic_service_info);

    switch (gen_handle->type)
    {
        case SAL_SERVICE_TYPE_CRYPTO:
        {
            status = SalCtrl_CyGetFileDescriptor(crypto_handle, fd);
            break;
        }
        case SAL_SERVICE_TYPE_CRYPTO_ASYM:
        {
            status = SalCtrl_AsymGetFileDescriptor(crypto_handle, fd);
            break;
        }
        case SAL_SERVICE_TYPE_CRYPTO_SYM:
        {
            status = SalCtrl_SymGetFileDescriptor(crypto_handle, fd);
            break;
        }
        default:
            LAC_LOG_ERROR("The instance handle is the wrong type");
            return CPA_STATUS_FAIL;
    }

    return status;
}

CpaStatus icp_sal_CyPutFileDescriptor(CpaInstanceHandle instanceHandle, int fd)
{
    sal_crypto_service_t *crypto_handle = NULL;

    crypto_handle = (sal_crypto_service_t *)instanceHandle;

    LAC_CHECK_NULL_PARAM(crypto_handle);
    SAL_RUNNING_CHECK(crypto_handle);
    SAL_CHECK_INSTANCE_TYPE(instanceHandle,
                            (SAL_SERVICE_TYPE_CRYPTO |
                             SAL_SERVICE_TYPE_CRYPTO_ASYM |
                             SAL_SERVICE_TYPE_CRYPTO_SYM));

    if (SAL_RESP_EPOLL_CFG_FILE != crypto_handle->isPolled)
    {
        return CPA_STATUS_UNSUPPORTED;
    }

    return CPA_STATUS_SUCCESS;
}
