root/sys/dev/qat/qat_api/common/ctrl/sal_compression.c
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright(c) 2007-2025 Intel Corporation */
/**
 *****************************************************************************
 * @file sal_compression.c
 *
 * @ingroup SalCtrl
 *
 * @description
 *    This file contains the sal implementation for compression.
 *
 *****************************************************************************/

/* QAT-API includes */
#include "cpa.h"
#include "cpa_dc.h"

/* QAT utils includes */
#include "qat_utils.h"

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

/* SAL includes */
#include "lac_mem.h"
#include "lac_common.h"
#include "lac_mem_pools.h"
#include "sal_statistics.h"
#include "lac_list.h"
#include "icp_sal_poll.h"
#include "sal_types_compression.h"
#include "dc_session.h"
#include "dc_datapath.h"
#include "dc_stats.h"
#include "lac_sal.h"
#include "lac_sal_ctrl.h"
#include "sal_string_parse.h"
#include "sal_service_state.h"
#include "lac_buffer_desc.h"
#include "icp_qat_fw_comp.h"
#include "icp_qat_hw_20_comp_defs.h"
#include "icp_sal_versions.h"

/* C string null terminator size */
#define SAL_NULL_TERM_SIZE 1

/*
 * Prints statistics for a compression instance
 */
static int
SalCtrl_CompresionDebug(void *private_data, char *data, int size, int offset)
{
        sal_compression_service_t *pCompressionService =
            (sal_compression_service_t *)private_data;
        CpaStatus status = CPA_STATUS_SUCCESS;
        CpaDcStats dcStats = { 0 };
        Cpa32S len = 0;

        status = cpaDcGetStats(pCompressionService, &dcStats);
        if (status != CPA_STATUS_SUCCESS) {
                QAT_UTILS_LOG("cpaDcGetStats returned error.\n");
                return (-1);
        }

        /* Engine Info */
        if (NULL != pCompressionService->debug_file) {
                len += snprintf(data + len,
                                size - len,
                                SEPARATOR BORDER
                                " Statistics for Instance %24s | \n" SEPARATOR,
                                pCompressionService->debug_file->name);
        }

        /* Perform Info */
        len += snprintf(data + len,
                        size - len,
                        BORDER " DC comp Requests:               %16llu " BORDER
                               "\n" BORDER
                               " DC comp Request Errors:         %16llu " BORDER
                               "\n" BORDER
                               " DC comp Completed:              %16llu " BORDER
                               "\n" BORDER
                               " DC comp Completed Errors:       %16llu " BORDER
                               "\n" SEPARATOR,
                        (long long unsigned int)dcStats.numCompRequests,
                        (long long unsigned int)dcStats.numCompRequestsErrors,
                        (long long unsigned int)dcStats.numCompCompleted,
                        (long long unsigned int)dcStats.numCompCompletedErrors);

        /* Perform Info */
        len += snprintf(
            data + len,
            size - len,
            BORDER " DC decomp Requests:             %16llu " BORDER "\n" BORDER
                   " DC decomp Request Errors:       %16llu " BORDER "\n" BORDER
                   " DC decomp Completed:            %16llu " BORDER "\n" BORDER
                   " DC decomp Completed Errors:     %16llu " BORDER
                   "\n" SEPARATOR,
            (long long unsigned int)dcStats.numDecompRequests,
            (long long unsigned int)dcStats.numDecompRequestsErrors,
            (long long unsigned int)dcStats.numDecompCompleted,
            (long long unsigned int)dcStats.numDecompCompletedErrors);
        return 0;
}

/* Initialise device specific information needed by compression service */
static CpaStatus
SalCtrl_CompressionInit_CompData(icp_accel_dev_t *device,
                                 sal_compression_service_t *pCompService)
{
        int level = 0;
        pCompService->comp_device_data.asbEnableSupport = CPA_FALSE;
        pCompService->comp_device_data.uniqueCompressionLevels[0] = CPA_FALSE;

        switch (device->deviceType) {
        case DEVICE_DH895XCC:
        case DEVICE_DH895XCCVF:
                pCompService->generic_service_info.integrityCrcCheck =
                    CPA_FALSE;
                pCompService->numInterBuffs =
                    DC_QAT_MAX_NUM_INTER_BUFFERS_6COMP_SLICES;
                pCompService->comp_device_data.minOutputBuffSize =
                    DC_DEST_BUFFER_STA_MIN_SIZE;
                pCompService->comp_device_data.oddByteDecompNobFinal = CPA_TRUE;
                pCompService->comp_device_data.oddByteDecompInterim = CPA_FALSE;
                pCompService->comp_device_data.translatorOverflow = CPA_FALSE;
                pCompService->comp_device_data.useDevRam =
                    ICP_QAT_FW_COMP_ENABLE_SECURE_RAM_USED_AS_INTMD_BUF;
                pCompService->comp_device_data.enableDmm =
                    ICP_QAT_HW_COMPRESSION_DELAYED_MATCH_DISABLED;

                pCompService->comp_device_data.inflateContextSize =
                    DC_INFLATE_CONTEXT_SIZE;
                pCompService->comp_device_data.highestHwCompressionDepth =
                    ICP_QAT_HW_COMPRESSION_DEPTH_16;

                pCompService->comp_device_data.windowSizeMask =
                    (1 << DC_8K_WINDOW_SIZE | 1 << DC_32K_WINDOW_SIZE);
                pCompService->comp_device_data.cnvnrSupported = CPA_FALSE;
                for (level = CPA_DC_L1; level <= CPA_DC_L12; level++) {
                        switch (level) {
                        case CPA_DC_L1:
                        case CPA_DC_L2:
                        case CPA_DC_L3:
                        case CPA_DC_L4:
                                pCompService->comp_device_data
                                    .uniqueCompressionLevels[level] = CPA_TRUE;
                                break;
                        default:
                                pCompService->comp_device_data
                                    .uniqueCompressionLevels[level] = CPA_FALSE;
                                break;
                        }
                }
                pCompService->comp_device_data.numCompressionLevels =
                    DC_NUM_COMPRESSION_LEVELS;
                break;
        case DEVICE_C3XXX:
        case DEVICE_C3XXXVF:
        case DEVICE_200XX:
        case DEVICE_200XXVF:
                pCompService->generic_service_info.integrityCrcCheck =
                    CPA_FALSE;
                pCompService->numInterBuffs =
                    DC_QAT_MAX_NUM_INTER_BUFFERS_6COMP_SLICES;
                pCompService->comp_device_data.oddByteDecompNobFinal =
                    CPA_FALSE;
                pCompService->comp_device_data.oddByteDecompInterim = CPA_TRUE;
                pCompService->comp_device_data.translatorOverflow = CPA_FALSE;
                pCompService->comp_device_data.useDevRam =
                    ICP_QAT_FW_COMP_DISABLE_SECURE_RAM_USED_AS_INTMD_BUF;
                pCompService->comp_device_data.inflateContextSize =
                    DC_INFLATE_EH_CONTEXT_SIZE;
                pCompService->comp_device_data.highestHwCompressionDepth =
                    ICP_QAT_HW_COMPRESSION_DEPTH_16;
                pCompService->comp_device_data.windowSizeMask =
                    (1 << DC_16K_WINDOW_SIZE | 1 << DC_32K_WINDOW_SIZE);
                pCompService->comp_device_data.minOutputBuffSize =
                    DC_DEST_BUFFER_STA_MIN_SIZE;
                pCompService->comp_device_data.enableDmm =
                    ICP_QAT_HW_COMPRESSION_DELAYED_MATCH_ENABLED;

                pCompService->comp_device_data.cnvnrSupported = CPA_TRUE;

                for (level = CPA_DC_L1; level <= CPA_DC_L12; level++) {
                        switch (level) {
                        case CPA_DC_L1:
                        case CPA_DC_L2:
                        case CPA_DC_L3:
                        case CPA_DC_L4:
                                pCompService->comp_device_data
                                    .uniqueCompressionLevels[level] = CPA_TRUE;
                                break;
                        default:
                                pCompService->comp_device_data
                                    .uniqueCompressionLevels[level] = CPA_FALSE;
                                break;
                        }
                }
                pCompService->comp_device_data.numCompressionLevels =
                    DC_NUM_COMPRESSION_LEVELS;
                break;
        case DEVICE_C62X:
        case DEVICE_C62XVF:
                pCompService->generic_service_info.integrityCrcCheck =
                    CPA_FALSE;
                pCompService->numInterBuffs =
                    DC_QAT_MAX_NUM_INTER_BUFFERS_10COMP_SLICES;
                pCompService->comp_device_data.oddByteDecompNobFinal =
                    CPA_FALSE;
                pCompService->comp_device_data.oddByteDecompInterim = CPA_TRUE;
                pCompService->comp_device_data.translatorOverflow = CPA_FALSE;
                pCompService->comp_device_data.useDevRam =
                    ICP_QAT_FW_COMP_ENABLE_SECURE_RAM_USED_AS_INTMD_BUF;
                pCompService->comp_device_data.inflateContextSize =
                    DC_INFLATE_EH_CONTEXT_SIZE;
                pCompService->comp_device_data.highestHwCompressionDepth =
                    ICP_QAT_HW_COMPRESSION_DEPTH_16;
                pCompService->comp_device_data.windowSizeMask =
                    (1 << DC_4K_WINDOW_SIZE | 1 << DC_8K_WINDOW_SIZE |
                     1 << DC_16K_WINDOW_SIZE | 1 << DC_32K_WINDOW_SIZE);
                pCompService->comp_device_data.minOutputBuffSize =
                    DC_DEST_BUFFER_STA_MIN_SIZE;
                pCompService->comp_device_data.minOutputBuffSizeDynamic =
                    pCompService->comp_device_data.minOutputBuffSize;
                pCompService->comp_device_data.enableDmm =
                    ICP_QAT_HW_COMPRESSION_DELAYED_MATCH_ENABLED;
                pCompService->comp_device_data.cnvnrSupported = CPA_TRUE;

                for (level = CPA_DC_L1; level <= CPA_DC_L12; level++) {
                        switch (level) {
                        case CPA_DC_L1:
                        case CPA_DC_L2:
                        case CPA_DC_L3:
                        case CPA_DC_L4:
                                pCompService->comp_device_data
                                    .uniqueCompressionLevels[level] = CPA_TRUE;
                                break;
                        default:
                                pCompService->comp_device_data
                                    .uniqueCompressionLevels[level] = CPA_FALSE;
                                break;
                        }
                }
                pCompService->comp_device_data.numCompressionLevels =
                    DC_NUM_COMPRESSION_LEVELS;
                break;
        case DEVICE_C4XXX:
        case DEVICE_C4XXXVF:
                pCompService->generic_service_info.integrityCrcCheck = CPA_TRUE;
                pCompService->numInterBuffs =
                    DC_QAT_MAX_NUM_INTER_BUFFERS_24COMP_SLICES;
                pCompService->comp_device_data.minOutputBuffSize =
                    DC_DEST_BUFFER_MIN_SIZE;
                pCompService->comp_device_data.oddByteDecompNobFinal = CPA_TRUE;
                pCompService->comp_device_data.oddByteDecompInterim = CPA_TRUE;
                pCompService->comp_device_data.translatorOverflow = CPA_TRUE;
                if (pCompService->generic_service_info.capabilitiesMask &
                    ICP_ACCEL_CAPABILITIES_INLINE) {
                        pCompService->comp_device_data.useDevRam =
                            ICP_QAT_FW_COMP_DISABLE_SECURE_RAM_USED_AS_INTMD_BUF;
                } else {
                        pCompService->comp_device_data.useDevRam =
                            ICP_QAT_FW_COMP_ENABLE_SECURE_RAM_USED_AS_INTMD_BUF;
                }
                pCompService->comp_device_data.enableDmm =
                    ICP_QAT_HW_COMPRESSION_DELAYED_MATCH_ENABLED;
                pCompService->comp_device_data.inflateContextSize =
                    DC_INFLATE_EH_CONTEXT_SIZE;
                pCompService->comp_device_data.highestHwCompressionDepth =
                    ICP_QAT_HW_COMPRESSION_DEPTH_128;
                pCompService->comp_device_data.windowSizeMask =
                    (1 << DC_16K_WINDOW_SIZE | 1 << DC_32K_WINDOW_SIZE);
                pCompService->comp_device_data.cnvnrSupported = CPA_TRUE;

                for (level = CPA_DC_L1; level <= CPA_DC_L12; level++) {
                        switch (level) {
                        case CPA_DC_L1:
                        case CPA_DC_L2:
                        case CPA_DC_L3:
                        case CPA_DC_L4:
                        case CPA_DC_L5:
                                pCompService->comp_device_data
                                    .uniqueCompressionLevels[level] = CPA_TRUE;
                                break;
                        default:
                                pCompService->comp_device_data
                                    .uniqueCompressionLevels[level] = CPA_FALSE;
                                break;
                        }
                }
                pCompService->comp_device_data.numCompressionLevels =
                    DC_NUM_COMPRESSION_LEVELS;
                break;
        case DEVICE_4XXX:
        case DEVICE_4XXXVF:
                pCompService->generic_service_info.integrityCrcCheck = CPA_TRUE;
                pCompService->numInterBuffs = 0;
                pCompService->comp_device_data.minOutputBuffSize =
                    DC_DEST_BUFFER_STA_MIN_SIZE_GEN4;
                pCompService->comp_device_data.minOutputBuffSizeDynamic =
                    DC_DEST_BUFFER_DYN_MIN_SIZE_GEN4;
                pCompService->comp_device_data.oddByteDecompNobFinal = CPA_TRUE;
                pCompService->comp_device_data.oddByteDecompInterim = CPA_FALSE;
                pCompService->comp_device_data.translatorOverflow = CPA_TRUE;
                pCompService->comp_device_data.useDevRam =
                    ICP_QAT_FW_COMP_ENABLE_SECURE_RAM_USED_AS_INTMD_BUF;
                pCompService->comp_device_data.enableDmm =
                    ICP_QAT_HW_COMPRESSION_DELAYED_MATCH_ENABLED;

                pCompService->comp_device_data.inflateContextSize =
                    DC_INFLATE_CONTEXT_SIZE;
                pCompService->comp_device_data.highestHwCompressionDepth =
                    ICP_QAT_HW_COMP_20_SEARCH_DEPTH_LEVEL_9;
                pCompService->comp_device_data.windowSizeMask =
                    (1 << DC_4K_WINDOW_SIZE | 1 << DC_8K_WINDOW_SIZE |
                     1 << DC_16K_WINDOW_SIZE | 1 << DC_32K_WINDOW_SIZE);
                for (level = CPA_DC_L1; level <= CPA_DC_L12; level++) {
                        switch (level) {
                        case CPA_DC_L1:
                        case CPA_DC_L6:
                        case CPA_DC_L9:
                                pCompService->comp_device_data
                                    .uniqueCompressionLevels[level] = CPA_TRUE;
                                break;
                        default:
                                pCompService->comp_device_data
                                    .uniqueCompressionLevels[level] = CPA_FALSE;
                                break;
                        }
                }
                pCompService->comp_device_data.numCompressionLevels =
                    DC_NUM_COMPRESSION_LEVELS;
                break;
        default:
                QAT_UTILS_LOG("Unknown device type! - %d.\n",
                              device->deviceType);
                return CPA_STATUS_FAIL;
        }
        return CPA_STATUS_SUCCESS;
}

CpaStatus
SalCtrl_CompressionInit(icp_accel_dev_t *device, sal_service_t *service)
{
        CpaStatus status = CPA_STATUS_SUCCESS;
        Cpa32U numCompConcurrentReq = 0;
        Cpa32U request_ring_id = 0;
        Cpa32U response_ring_id = 0;

        char adfGetParam[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 };
        char compMemPool[SAL_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 };
        char *instance_name = NULL;
        sal_statistics_collection_t *pStatsCollection =
            (sal_statistics_collection_t *)device->pQatStats;
        icp_resp_deliv_method rx_resp_type = ICP_RESP_TYPE_IRQ;
        sal_compression_service_t *pCompressionService =
            (sal_compression_service_t *)service;
        Cpa32U msgSize = 0;
        char *section = DYN_SEC;

        SAL_SERVICE_GOOD_FOR_INIT(pCompressionService);

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

        if (pStatsCollection == NULL) {
                return CPA_STATUS_FAIL;
        }

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

        pCompressionService->acceleratorNum = 0;

        /* Initialise device specific compression data */
        SalCtrl_CompressionInit_CompData(device, pCompressionService);

        status = Sal_StringParsing(
            "Dc",
            pCompressionService->generic_service_info.instance,
            "BankNumber",
            temp_string);
        LAC_CHECK_STATUS(status);
        status =
            icp_adf_cfgGetParamValue(device, section, temp_string, adfGetParam);
        if (CPA_STATUS_SUCCESS != status) {
                QAT_UTILS_LOG("Failed to get %s from configuration.\n",
                              temp_string);
                return status;
        }

        pCompressionService->bankNum =
            Sal_Strtoul(adfGetParam, NULL, SAL_CFG_BASE_DEC);

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

        /* User instances only support poll and epoll mode */
        if (SAL_RESP_POLL_CFG_FILE != pCompressionService->isPolled) {
                QAT_UTILS_LOG(
                    "IsPolled %u is not supported for user instance %s.\n",
                    pCompressionService->isPolled,
                    temp_string);
                return CPA_STATUS_FAIL;
        }

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

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

        status = icp_adf_cfgGetParamValue(device,
                                          LAC_CFG_SECTION_GENERAL,
                                          ADF_DEV_NODE_ID,
                                          adfGetParam);
        if (CPA_STATUS_SUCCESS != status) {
                QAT_UTILS_LOG("Failed to get %s from configuration.\n",
                              ADF_DEV_NODE_ID);
                return status;
        }
        pCompressionService->nodeAffinity =
            (Cpa32U)Sal_Strtoul(adfGetParam, NULL, SAL_CFG_BASE_DEC);

        /* In case of interrupt instance, use the bank affinity set by adf_ctl
         * Otherwise, use the instance affinity for backwards compatibility */
        if (SAL_RESP_POLL_CFG_FILE != pCompressionService->isPolled) {
                /* Next need to read the [AcceleratorX] section of the config
                 * file */
                status = Sal_StringParsing("Accelerator",
                                           pCompressionService->acceleratorNum,
                                           "",
                                           temp_string2);
                LAC_CHECK_STATUS(status);

                status = Sal_StringParsing("Bank",
                                           pCompressionService->bankNum,
                                           "CoreAffinity",
                                           temp_string);
                LAC_CHECK_STATUS(status);
        } else {
                strncpy(temp_string2,
                        section,
                        sizeof(temp_string2) - SAL_NULL_TERM_SIZE);
                temp_string2[SAL_CFG_MAX_VAL_LEN_IN_BYTES -
                             SAL_NULL_TERM_SIZE] = '\0';

                status = Sal_StringParsing(
                    "Dc",
                    pCompressionService->generic_service_info.instance,
                    "CoreAffinity",
                    temp_string);
                LAC_CHECK_STATUS(status);
        }

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

        status = Sal_StringParsing(
            "Dc",
            pCompressionService->generic_service_info.instance,
            "NumConcurrentRequests",
            temp_string);
        LAC_CHECK_STATUS(status);
        status =
            icp_adf_cfgGetParamValue(device, section, temp_string, adfGetParam);
        if (CPA_STATUS_SUCCESS != status) {
                QAT_UTILS_LOG("Failed to get %s from configuration.\n",
                              temp_string);
                return status;
        }

        numCompConcurrentReq =
            (Cpa32U)Sal_Strtoul(adfGetParam, NULL, SAL_CFG_BASE_DEC);
        if (validateConcurrRequest(numCompConcurrentReq)) {
                QAT_UTILS_LOG(
                    "Invalid NumConcurrentRequests, valid values are: {64, 128, 256, ... 32768, 65536}.\n");
                return CPA_STATUS_FAIL;
        }

        /* ADF does not allow us to completely fill the ring for batch requests
         */
        pCompressionService->maxNumCompConcurrentReq =
            (numCompConcurrentReq - SAL_BATCH_SUBMIT_FREE_SPACE);

        /* 1. Create transport handles */
        status = Sal_StringParsing(
            "Dc",
            pCompressionService->generic_service_info.instance,
            "RingTx",
            temp_string);
        LAC_CHECK_STATUS(status);

        msgSize = LAC_QAT_DC_REQ_SZ_LW * LAC_LONG_WORD_IN_BYTES;
        status = icp_adf_transCreateHandle(
            device,
            ICP_TRANS_TYPE_ETR,
            section,
            pCompressionService->acceleratorNum,
            pCompressionService->bankNum,
            temp_string,
            lac_getRingType(SAL_RING_TYPE_DC),
            NULL,
            ICP_RESP_TYPE_NONE,
            numCompConcurrentReq,
            msgSize,
            (icp_comms_trans_handle *)&(
                pCompressionService->trans_handle_compression_tx));
        LAC_CHECK_STATUS(status);

        if (icp_adf_transGetRingNum(
                pCompressionService->trans_handle_compression_tx,
                &request_ring_id) != CPA_STATUS_SUCCESS) {
                icp_adf_transReleaseHandle(
                    pCompressionService->trans_handle_compression_tx);

                QAT_UTILS_LOG("Failed to get DC TX ring number.\n");
                return CPA_STATUS_FAIL;
        }

        status = Sal_StringParsing(
            "Dc",
            pCompressionService->generic_service_info.instance,
            "RingRx",
            temp_string);
        if (CPA_STATUS_SUCCESS != status) {
                icp_adf_transReleaseHandle(
                    pCompressionService->trans_handle_compression_tx);
                return status;
        }

        msgSize = LAC_QAT_DC_RESP_SZ_LW * LAC_LONG_WORD_IN_BYTES;
        status = icp_adf_transCreateHandle(
            device,
            ICP_TRANS_TYPE_ETR,
            section,
            pCompressionService->acceleratorNum,
            pCompressionService->bankNum,
            temp_string,
            lac_getRingType(SAL_RING_TYPE_NONE),
            (icp_trans_callback)dcCompression_ProcessCallback,
            rx_resp_type,
            numCompConcurrentReq,
            msgSize,
            (icp_comms_trans_handle *)&(
                pCompressionService->trans_handle_compression_rx));
        if (CPA_STATUS_SUCCESS != status) {
                icp_adf_transReleaseHandle(
                    pCompressionService->trans_handle_compression_tx);
                return status;
        }

        if (icp_adf_transGetRingNum(
                pCompressionService->trans_handle_compression_rx,
                &response_ring_id) != CPA_STATUS_SUCCESS) {
                icp_adf_transReleaseHandle(
                    pCompressionService->trans_handle_compression_tx);

                icp_adf_transReleaseHandle(
                    pCompressionService->trans_handle_compression_rx);

                QAT_UTILS_LOG("Failed to get DC RX ring number.\n");
                return CPA_STATUS_FAIL;
        }

        /* 2. Allocates memory pools */

        /* Valid initialisation value for a pool ID */
        pCompressionService->compression_mem_pool = LAC_MEM_POOL_INIT_POOL_ID;

        status = Sal_StringParsing(
            "Comp",
            pCompressionService->generic_service_info.instance,
            "_MemPool",
            compMemPool);
        if (CPA_STATUS_SUCCESS != status) {
                icp_adf_transReleaseHandle(
                    pCompressionService->trans_handle_compression_tx);

                icp_adf_transReleaseHandle(
                    pCompressionService->trans_handle_compression_rx);

                return status;
        }

        status = Lac_MemPoolCreate(&pCompressionService->compression_mem_pool,
                                   compMemPool,
                                   (numCompConcurrentReq + 1),
                                   sizeof(dc_compression_cookie_t),
                                   LAC_64BYTE_ALIGNMENT,
                                   CPA_FALSE,
                                   pCompressionService->nodeAffinity);
        if (CPA_STATUS_SUCCESS != status) {
                icp_adf_transReleaseHandle(
                    pCompressionService->trans_handle_compression_tx);

                icp_adf_transReleaseHandle(
                    pCompressionService->trans_handle_compression_rx);

                return status;
        }

        /* Init compression statistics */
        status = dcStatsInit(pCompressionService);
        if (CPA_STATUS_SUCCESS != status) {
                Lac_MemPoolDestroy(pCompressionService->compression_mem_pool);

                icp_adf_transReleaseHandle(
                    pCompressionService->trans_handle_compression_tx);

                icp_adf_transReleaseHandle(
                    pCompressionService->trans_handle_compression_rx);

                return status;
        }
        if (CPA_TRUE == pStatsCollection->bDcStatsEnabled) {
                /* Get instance name for stats */
                instance_name = LAC_OS_MALLOC(ADF_CFG_MAX_VAL_LEN_IN_BYTES);
                if (NULL == instance_name) {
                        Lac_MemPoolDestroy(
                            pCompressionService->compression_mem_pool);

                        icp_adf_transReleaseHandle(
                            pCompressionService->trans_handle_compression_tx);

                        icp_adf_transReleaseHandle(
                            pCompressionService->trans_handle_compression_rx);

                        return CPA_STATUS_RESOURCE;
                }

                status = Sal_StringParsing(
                    "Dc",
                    pCompressionService->generic_service_info.instance,
                    "Name",
                    temp_string);
                if (CPA_STATUS_SUCCESS != status) {
                        Lac_MemPoolDestroy(
                            pCompressionService->compression_mem_pool);

                        icp_adf_transReleaseHandle(
                            pCompressionService->trans_handle_compression_tx);

                        icp_adf_transReleaseHandle(
                            pCompressionService->trans_handle_compression_rx);
                        LAC_OS_FREE(instance_name);
                        return status;
                }
                status = icp_adf_cfgGetParamValue(device,
                                                  section,
                                                  temp_string,
                                                  adfGetParam);
                if (CPA_STATUS_SUCCESS != status) {
                        QAT_UTILS_LOG("Failed to get %s from configuration.\n",
                                      temp_string);

                        Lac_MemPoolDestroy(
                            pCompressionService->compression_mem_pool);

                        icp_adf_transReleaseHandle(
                            pCompressionService->trans_handle_compression_tx);

                        icp_adf_transReleaseHandle(
                            pCompressionService->trans_handle_compression_rx);
                        LAC_OS_FREE(instance_name);
                        return status;
                }

                snprintf(instance_name,
                         ADF_CFG_MAX_VAL_LEN_IN_BYTES,
                         "%s",
                         adfGetParam);

                pCompressionService->debug_file =
                    LAC_OS_MALLOC(sizeof(debug_file_info_t));
                if (NULL == pCompressionService->debug_file) {
                        Lac_MemPoolDestroy(
                            pCompressionService->compression_mem_pool);

                        icp_adf_transReleaseHandle(
                            pCompressionService->trans_handle_compression_tx);

                        icp_adf_transReleaseHandle(
                            pCompressionService->trans_handle_compression_rx);
                        LAC_OS_FREE(instance_name);
                        return CPA_STATUS_RESOURCE;
                }

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

                status = icp_adf_debugAddFile(device,
                                              pCompressionService->debug_file);
                if (CPA_STATUS_SUCCESS != status) {
                        Lac_MemPoolDestroy(
                            pCompressionService->compression_mem_pool);

                        icp_adf_transReleaseHandle(
                            pCompressionService->trans_handle_compression_tx);

                        icp_adf_transReleaseHandle(
                            pCompressionService->trans_handle_compression_rx);
                        LAC_OS_FREE(instance_name);
                        LAC_OS_FREE(pCompressionService->debug_file);
                        return status;
                }
        }
        pCompressionService->generic_service_info.stats = pStatsCollection;
        pCompressionService->generic_service_info.state =
            SAL_SERVICE_STATE_INITIALIZED;

        return status;
}

CpaStatus
SalCtrl_CompressionStart(icp_accel_dev_t *device, sal_service_t *service)
{
        CpaStatus status = CPA_STATUS_SUCCESS;

        sal_compression_service_t *pCompressionService =
            (sal_compression_service_t *)service;

        if (SAL_SERVICE_STATE_INITIALIZED !=
            pCompressionService->generic_service_info.state) {
                QAT_UTILS_LOG("Not in the correct state to call start.\n");
                return CPA_STATUS_FAIL;
        }
        /**************************************************************/
        /* Obtain Extended Features. I.e. Compress And Verify         */
        /**************************************************************/
        pCompressionService->generic_service_info.dcExtendedFeatures =
            device->dcExtendedFeatures;
        pCompressionService->generic_service_info.state =
            SAL_SERVICE_STATE_RUNNING;

        return status;
}

CpaStatus
SalCtrl_CompressionStop(icp_accel_dev_t *device, sal_service_t *service)
{
        sal_compression_service_t *pCompressionService =
            (sal_compression_service_t *)service;

        if (SAL_SERVICE_STATE_RUNNING !=
            pCompressionService->generic_service_info.state) {
                QAT_UTILS_LOG("Not in the correct state to call stop.\n");
                return CPA_STATUS_FAIL;
        }

        if (icp_adf_is_dev_in_reset(device)) {
                pCompressionService->generic_service_info.state =
                    SAL_SERVICE_STATE_RESTARTING;
                return CPA_STATUS_SUCCESS;
        }

        pCompressionService->generic_service_info.state =
            SAL_SERVICE_STATE_SHUTTING_DOWN;
        return CPA_STATUS_RETRY;
}

CpaStatus
SalCtrl_CompressionShutdown(icp_accel_dev_t *device, sal_service_t *service)
{
        CpaStatus status = CPA_STATUS_SUCCESS;

        sal_compression_service_t *pCompressionService =
            (sal_compression_service_t *)service;
        sal_statistics_collection_t *pStatsCollection =
            (sal_statistics_collection_t *)device->pQatStats;

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

        Lac_MemPoolDestroy(pCompressionService->compression_mem_pool);

        status = icp_adf_transReleaseHandle(
            pCompressionService->trans_handle_compression_tx);
        LAC_CHECK_STATUS(status);

        status = icp_adf_transReleaseHandle(
            pCompressionService->trans_handle_compression_rx);
        LAC_CHECK_STATUS(status);

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

        if (icp_adf_is_dev_in_reset(device)) {
                pCompressionService->generic_service_info.state =
                    SAL_SERVICE_STATE_RESTARTING;
                return CPA_STATUS_SUCCESS;
        }
        pCompressionService->generic_service_info.state =
            SAL_SERVICE_STATE_SHUTDOWN;
        return status;
}

CpaStatus
cpaDcGetStatusText(const CpaInstanceHandle dcInstance,
                   const CpaStatus errStatus,
                   Cpa8S *pStatusText)
{
        CpaStatus status = CPA_STATUS_SUCCESS;

        LAC_CHECK_NULL_PARAM(pStatusText);

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

        return status;
}

CpaStatus
cpaDcGetNumIntermediateBuffers(CpaInstanceHandle dcInstance,
                               Cpa16U *pNumBuffers)
{
        CpaInstanceHandle insHandle = NULL;
        sal_compression_service_t *pService = NULL;

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

        LAC_CHECK_NULL_PARAM(insHandle);
        LAC_CHECK_NULL_PARAM(pNumBuffers);

        pService = (sal_compression_service_t *)insHandle;
        *pNumBuffers = pService->numInterBuffs;

        return CPA_STATUS_SUCCESS;
}

CpaStatus
cpaDcStartInstance(CpaInstanceHandle instanceHandle,
                   Cpa16U numBuffers,
                   CpaBufferList **pIntermediateBufferPtrsArray)
{
        icp_qat_addr_width_t *pInterBuffPtrsArray = NULL;
        icp_qat_addr_width_t pArrayBufferListDescPhyAddr = 0;
        icp_qat_addr_width_t bufListDescPhyAddr;
        icp_qat_addr_width_t bufListAlignedPhyAddr;
        CpaFlatBuffer *pClientCurrFlatBuffer = NULL;
        icp_buffer_list_desc_t *pBufferListDesc = NULL;
        icp_flat_buffer_desc_t *pCurrFlatBufDesc = NULL;
        CpaInstanceInfo2 info = { 0 };
        icp_accel_dev_t *dev = NULL;
        CpaStatus status = CPA_STATUS_SUCCESS;
        sal_compression_service_t *pService = NULL;
        CpaInstanceHandle insHandle = NULL;
        Cpa16U bufferIndex = 0;
        Cpa32U numFlatBuffers = 0;
        Cpa64U clientListSize = 0;
        CpaBufferList *pClientCurrentIntermediateBuffer = NULL;
        Cpa32U bufferIndex2 = 0;
        CpaBufferList **pTempIntermediateBufferPtrsArray;
        Cpa64U lastClientListSize = 0;

        if (CPA_INSTANCE_HANDLE_SINGLE == instanceHandle) {
                insHandle = dcGetFirstHandle();
        } else {
                insHandle = instanceHandle;
        }
        LAC_CHECK_NULL_PARAM(insHandle);

        status = cpaDcInstanceGetInfo2(insHandle, &info);
        if (CPA_STATUS_SUCCESS != status) {
                QAT_UTILS_LOG("Can not get instance info.\n");
                return status;
        }

        dev = icp_adf_getAccelDevByAccelId(info.physInstId.packageId);
        if (NULL == dev) {
                QAT_UTILS_LOG("Can not find device for the instance\n");
                return CPA_STATUS_FAIL;
        }

        if (NULL == pIntermediateBufferPtrsArray) {
                /* Increment dev ref counter and return - DRAM is not used */
                icp_qa_dev_get(dev);
                return CPA_STATUS_SUCCESS;
        }

        if (0 == numBuffers) {
                /* Increment dev ref counter and return - DRAM is not used */
                icp_qa_dev_get(dev);
                return CPA_STATUS_SUCCESS;
        }

        pService = (sal_compression_service_t *)insHandle;

        LAC_CHECK_NULL_PARAM(insHandle);

        if ((numBuffers > 0) && (NULL == pIntermediateBufferPtrsArray)) {
                QAT_UTILS_LOG("Invalid Intermediate Buffers Array pointer\n");
                return CPA_STATUS_INVALID_PARAM;
        }

        /* Check number of intermediate buffers allocated by user */
        if ((pService->numInterBuffs != numBuffers)) {
                QAT_UTILS_LOG("Invalid number of buffers\n");
                return CPA_STATUS_INVALID_PARAM;
        }

        pTempIntermediateBufferPtrsArray = pIntermediateBufferPtrsArray;
        for (bufferIndex = 0; bufferIndex < numBuffers; bufferIndex++) {
                if (NULL == *pTempIntermediateBufferPtrsArray) {
                        QAT_UTILS_LOG(
                            "Intermediate Buffer - Invalid Buffer List pointer\n");
                        return CPA_STATUS_INVALID_PARAM;
                }

                if (NULL == (*pTempIntermediateBufferPtrsArray)->pBuffers) {
                        QAT_UTILS_LOG(
                            "Intermediate Buffer - Invalid Flat Buffer descriptor pointer\n");
                        return CPA_STATUS_INVALID_PARAM;
                }

                if (NULL ==
                    (*pTempIntermediateBufferPtrsArray)->pPrivateMetaData) {
                        QAT_UTILS_LOG(
                            "Intermediate Buffer - Invalid Private MetaData descriptor pointer\n");
                        return CPA_STATUS_INVALID_PARAM;
                }

                clientListSize = 0;
                for (bufferIndex2 = 0; bufferIndex2 <
                     (*pTempIntermediateBufferPtrsArray)->numBuffers;
                     bufferIndex2++) {

                        if ((0 !=
                             (*pTempIntermediateBufferPtrsArray)
                                 ->pBuffers[bufferIndex2]
                                 .dataLenInBytes) &&
                            NULL ==
                                (*pTempIntermediateBufferPtrsArray)
                                    ->pBuffers[bufferIndex2]
                                    .pData) {
                                QAT_UTILS_LOG(
                                    "Intermediate Buffer - Invalid Flat Buffer pointer\n");
                                return CPA_STATUS_INVALID_PARAM;
                        }

                        clientListSize += (*pTempIntermediateBufferPtrsArray)
                                              ->pBuffers[bufferIndex2]
                                              .dataLenInBytes;
                }

                if (bufferIndex != 0) {
                        if (lastClientListSize != clientListSize) {
                                QAT_UTILS_LOG(
                                    "SGLs have to be of the same size.\n");
                                return CPA_STATUS_INVALID_PARAM;
                        }
                } else {
                        lastClientListSize = clientListSize;
                }
                pTempIntermediateBufferPtrsArray++;
        }

        /* Allocate array of physical pointers to icp_buffer_list_desc_t */
        status = LAC_OS_CAMALLOC(&pInterBuffPtrsArray,
                                 (numBuffers * sizeof(icp_qat_addr_width_t)),
                                 LAC_64BYTE_ALIGNMENT,
                                 pService->nodeAffinity);
        if (CPA_STATUS_SUCCESS != status) {
                QAT_UTILS_LOG("Can not allocate Intermediate Buffers array.\n");
                return status;
        }

        /* Get physical address of the intermediate buffer pointers array */
        pArrayBufferListDescPhyAddr = LAC_MEM_CAST_PTR_TO_UINT64(
            LAC_OS_VIRT_TO_PHYS_INTERNAL(pInterBuffPtrsArray));

        pService->pInterBuffPtrsArray = pInterBuffPtrsArray;
        pService->pInterBuffPtrsArrayPhyAddr = pArrayBufferListDescPhyAddr;

        /* Get the full size of the buffer list */
        /* Assumption: all the SGLs allocated by the user have the same size */
        clientListSize = 0;
        for (bufferIndex = 0;
             bufferIndex < (*pIntermediateBufferPtrsArray)->numBuffers;
             bufferIndex++) {
                clientListSize += ((*pIntermediateBufferPtrsArray)
                                       ->pBuffers[bufferIndex]
                                       .dataLenInBytes);
        }
        pService->minInterBuffSizeInBytes = clientListSize;

        for (bufferIndex = 0; bufferIndex < numBuffers; bufferIndex++) {

                /* Get pointer to the client Intermediate Buffer List
                 * (CpaBufferList) */
                pClientCurrentIntermediateBuffer =
                    *pIntermediateBufferPtrsArray;

                /* Get number of flat buffers in the buffer list */
                numFlatBuffers = pClientCurrentIntermediateBuffer->numBuffers;

                /* Get pointer to the client array of CpaFlatBuffers */
                pClientCurrFlatBuffer =
                    pClientCurrentIntermediateBuffer->pBuffers;

                /* Calculate Physical address of current private SGL */
                bufListDescPhyAddr = LAC_OS_VIRT_TO_PHYS_EXTERNAL(
                    (*pService),
                    pClientCurrentIntermediateBuffer->pPrivateMetaData);
                if (bufListDescPhyAddr == 0) {
                        QAT_UTILS_LOG(
                            "Unable to get the physical address of the metadata.\n");
                        return CPA_STATUS_FAIL;
                }

                /* Align SGL physical address */
                bufListAlignedPhyAddr =
                    LAC_ALIGN_POW2_ROUNDUP(bufListDescPhyAddr,
                                           ICP_DESCRIPTOR_ALIGNMENT_BYTES);

                /* Set physical address of the Intermediate Buffer SGL in the
                 * SGLs array
                 */
                *pInterBuffPtrsArray =
                    LAC_MEM_CAST_PTR_TO_UINT64(bufListAlignedPhyAddr);

                /* Calculate (virtual) offset to the buffer list descriptor */
                pBufferListDesc =
                    (icp_buffer_list_desc_t
                         *)((LAC_ARCH_UINT)pClientCurrentIntermediateBuffer
                                ->pPrivateMetaData +
                            (LAC_ARCH_UINT)(bufListAlignedPhyAddr -
                                            bufListDescPhyAddr));

                /* Set number of flat buffers in the physical Buffer List
                 * descriptor */
                pBufferListDesc->numBuffers = numFlatBuffers;

                /* Go past the Buffer List descriptor to the list of buffer
                 * descriptors
                 */
                pCurrFlatBufDesc =
                    (icp_flat_buffer_desc_t *)((pBufferListDesc->phyBuffers));

                /* Loop for each flat buffer in the SGL */
                while (0 != numFlatBuffers) {
                        /* Set length of the current flat buffer */
                        pCurrFlatBufDesc->dataLenInBytes =
                            pClientCurrFlatBuffer->dataLenInBytes;

                        /* Set physical address of the flat buffer */
                        pCurrFlatBufDesc->phyBuffer =
                            LAC_MEM_CAST_PTR_TO_UINT64(
                                LAC_OS_VIRT_TO_PHYS_EXTERNAL(
                                    (*pService), pClientCurrFlatBuffer->pData));

                        if (pCurrFlatBufDesc->phyBuffer == 0) {
                                QAT_UTILS_LOG(
                                    "Unable to get the physical address of the flat buffer.\n");
                                return CPA_STATUS_FAIL;
                        }

                        pCurrFlatBufDesc++;
                        pClientCurrFlatBuffer++;
                        numFlatBuffers--;
                }
                pIntermediateBufferPtrsArray++;
                pInterBuffPtrsArray++;
        }

        pService->generic_service_info.isInstanceStarted = CPA_TRUE;

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

CpaStatus
cpaDcStopInstance(CpaInstanceHandle instanceHandle)
{
        CpaInstanceHandle insHandle = NULL;
        CpaInstanceInfo2 info = { 0 };
        icp_accel_dev_t *dev = NULL;
        CpaStatus status = CPA_STATUS_SUCCESS;
        sal_compression_service_t *pService = NULL;

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

        LAC_CHECK_NULL_PARAM(insHandle);
        pService = (sal_compression_service_t *)insHandle;

        /* Free Intermediate Buffer Pointers Array */
        if (pService->pInterBuffPtrsArray != NULL) {
                LAC_OS_CAFREE(pService->pInterBuffPtrsArray);
                pService->pInterBuffPtrsArray = 0;
        }

        pService->pInterBuffPtrsArrayPhyAddr = 0;

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

        pService->generic_service_info.isInstanceStarted = CPA_FALSE;

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

CpaStatus
cpaDcGetNumInstances(Cpa16U *pNumInstances)
{
        CpaStatus status = CPA_STATUS_SUCCESS;
        icp_accel_dev_t **pAdfInsts = NULL;
        icp_accel_dev_t *dev_addr = NULL;
        sal_t *base_addr = NULL;
        sal_list_t *list_temp = NULL;
        Cpa16U num_accel_dev = 0;
        Cpa16U num = 0;
        Cpa16U i = 0;

        LAC_CHECK_NULL_PARAM(pNumInstances);

        /* Get the number of accel_dev in the system */
        status = icp_amgr_getNumInstances(&num_accel_dev);
        LAC_CHECK_STATUS(status);

        /* Allocate memory to store addr of accel_devs */
        pAdfInsts =
            malloc(num_accel_dev * sizeof(icp_accel_dev_t *), M_QAT, M_WAITOK);
        num_accel_dev = 0;

        /* Get ADF to return accel_devs with dc enabled */
        status = icp_amgr_getAllAccelDevByCapabilities(
            ICP_ACCEL_CAPABILITIES_COMPRESSION, pAdfInsts, &num_accel_dev);
        if (CPA_STATUS_SUCCESS == status) {
                for (i = 0; i < num_accel_dev; i++) {
                        dev_addr = (icp_accel_dev_t *)pAdfInsts[i];
                        if (NULL != dev_addr) {
                                base_addr = dev_addr->pSalHandle;
                                if (NULL != base_addr) {
                                        list_temp =
                                            base_addr->compression_services;
                                        while (NULL != list_temp) {
                                                num++;
                                                list_temp =
                                                    SalList_next(list_temp);
                                        }
                                }
                        }
                }

                *pNumInstances = num;
        }

        free(pAdfInsts, M_QAT);

        return status;
}

CpaStatus
cpaDcGetInstances(Cpa16U numInstances, CpaInstanceHandle *dcInstances)
{
        CpaStatus status = CPA_STATUS_SUCCESS;
        icp_accel_dev_t **pAdfInsts = NULL;
        icp_accel_dev_t *dev_addr = NULL;
        sal_t *base_addr = NULL;
        sal_list_t *list_temp = NULL;
        Cpa16U num_accel_dev = 0;
        Cpa16U index = 0;
        Cpa16U i = 0;

        LAC_CHECK_NULL_PARAM(dcInstances);
        if (0 == numInstances) {
                QAT_UTILS_LOG("numInstances is 0.\n");
                return CPA_STATUS_INVALID_PARAM;
        }

        /* Get the number of accel_dev in the system */
        status = icp_amgr_getNumInstances(&num_accel_dev);
        LAC_CHECK_STATUS(status);

        /* Allocate memory to store addr of accel_devs */
        pAdfInsts =
            malloc(num_accel_dev * sizeof(icp_accel_dev_t *), M_QAT, M_WAITOK);

        num_accel_dev = 0;
        /* Get ADF to return accel_devs with dc enabled */
        status = icp_amgr_getAllAccelDevByCapabilities(
            ICP_ACCEL_CAPABILITIES_COMPRESSION, pAdfInsts, &num_accel_dev);

        if (CPA_STATUS_SUCCESS == status) {
                /* First check the number of instances in the system */
                for (i = 0; i < num_accel_dev; i++) {
                        dev_addr = (icp_accel_dev_t *)pAdfInsts[i];
                        if (NULL != dev_addr) {
                                base_addr = dev_addr->pSalHandle;
                                if (NULL != base_addr) {
                                        list_temp =
                                            base_addr->compression_services;
                                        while (NULL != list_temp) {
                                                if (index >
                                                    (numInstances - 1)) {
                                                        break;
                                                }

                                                dcInstances[index] =
                                                    SalList_getObject(
                                                        list_temp);
                                                list_temp =
                                                    SalList_next(list_temp);
                                                index++;
                                        }
                                }
                        }
                }

                if (numInstances > index) {
                        QAT_UTILS_LOG("Only %d dc instances available.\n",
                                      index);
                        status = CPA_STATUS_RESOURCE;
                }
        }

        if (CPA_STATUS_SUCCESS == status) {
                index = 0;
                for (i = 0; i < num_accel_dev; i++) {
                        dev_addr = (icp_accel_dev_t *)pAdfInsts[i];
                        /* Note dev_addr cannot be NULL here as numInstances=0
                           is not valid and if dev_addr=NULL then index=0 (which
                           is less than numInstances and status is set to
                           _RESOURCE
                           above */
                        base_addr = dev_addr->pSalHandle;
                        if (NULL != base_addr) {
                                list_temp = base_addr->compression_services;
                                while (NULL != list_temp) {
                                        if (index > (numInstances - 1)) {
                                                break;
                                        }

                                        dcInstances[index] =
                                            SalList_getObject(list_temp);
                                        list_temp = SalList_next(list_temp);
                                        index++;
                                }
                        }
                }
        }

        free(pAdfInsts, M_QAT);

        return status;
}

CpaStatus
cpaDcInstanceGetInfo2(const CpaInstanceHandle instanceHandle,
                      CpaInstanceInfo2 *pInstanceInfo2)
{
        sal_compression_service_t *pCompressionService = NULL;
        CpaInstanceHandle insHandle = NULL;
        icp_accel_dev_t *dev = NULL;
        CpaStatus status = CPA_STATUS_SUCCESS;
        char keyStr[ADF_CFG_MAX_KEY_LEN_IN_BYTES] = { 0 };
        char valStr[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 };
        char *section = DYN_SEC;

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

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

        LAC_OS_BZERO(pInstanceInfo2, sizeof(CpaInstanceInfo2));
        pInstanceInfo2->accelerationServiceType =
            CPA_ACC_SVC_TYPE_DATA_COMPRESSION;

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

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

        /* Note we can safely read the contents of the compression service
           instance
           here because icp_amgr_getAccelDevByCapabilities() only returns devs
           that have started */
        pCompressionService = (sal_compression_service_t *)insHandle;
        pInstanceInfo2->physInstId.packageId = pCompressionService->pkgID;
        pInstanceInfo2->physInstId.acceleratorId =
            pCompressionService->acceleratorNum;
        pInstanceInfo2->physInstId.executionEngineId = 0;
        pInstanceInfo2->physInstId.busAddress =
            icp_adf_get_busAddress(pInstanceInfo2->physInstId.packageId);

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

        pInstanceInfo2->nodeAffinity = pCompressionService->nodeAffinity;

        if (CPA_TRUE ==
            pCompressionService->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 == pCompressionService->isPolled) {
                pInstanceInfo2->isPolled = CPA_TRUE;
        } else {
                pInstanceInfo2->isPolled = CPA_FALSE;
        }

        pInstanceInfo2->isOffloaded = CPA_TRUE;
        /* Get the instance name and part name from the config file */
        dev = icp_adf_getAccelDevByAccelId(pCompressionService->pkgID);
        if (NULL == dev ||
            0 == strnlen(dev->deviceName, ADF_DEVICE_TYPE_LENGTH + 1)) {
                QAT_UTILS_LOG("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';

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

        status = Sal_StringParsing(
            "Dc",
            pCompressionService->generic_service_info.instance,
            "Name",
            keyStr);
        LAC_CHECK_STATUS(status);
        status = icp_adf_cfgGetParamValue(dev, section, keyStr, valStr);
        LAC_CHECK_STATUS(status);
        strncpy((char *)pInstanceInfo2->instName,
                valStr,
                sizeof(pInstanceInfo2->instName) - 1);
        pInstanceInfo2->instName[CPA_INST_NAME_SIZE - 1] = '\0';

#if __GNUC__ >= 7
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-truncation"
#endif
        snprintf((char *)pInstanceInfo2->instID,
                 CPA_INST_ID_SIZE,
                 "%s_%s",
                 section,
                 valStr);
#if __GNUC__ >= 7
#pragma GCC diagnostic pop
#endif

        return CPA_STATUS_SUCCESS;
}

CpaStatus
cpaDcQueryCapabilities(CpaInstanceHandle dcInstance,
                       CpaDcInstanceCapabilities *pInstanceCapabilities)
{
        CpaInstanceHandle insHandle = NULL;
        sal_compression_service_t *pService = NULL;
        Cpa32U capabilitiesMask = 0;
        dc_extd_ftrs_t *pExtendedFtrs = NULL;

        if (CPA_INSTANCE_HANDLE_SINGLE == dcInstance) {
                insHandle = dcGetFirstHandle();
                if (NULL == insHandle) {
                        QAT_UTILS_LOG("Can not get the instance.\n");
                        return CPA_STATUS_FAIL;
                }
        } else {
                insHandle = dcInstance;
        }

        pService = (sal_compression_service_t *)insHandle;

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

        memset(pInstanceCapabilities, 0, sizeof(CpaDcInstanceCapabilities));

        capabilitiesMask = pService->generic_service_info.capabilitiesMask;

        /* Set compression capabilities */
        if (capabilitiesMask & ICP_ACCEL_CAPABILITIES_CNV_INTEGRITY) {
                pInstanceCapabilities->integrityCrcs = CPA_TRUE;
        }

        pInstanceCapabilities->endOfLastBlock = CPA_TRUE;
        pInstanceCapabilities->statefulDeflateCompression = CPA_FALSE;
        pInstanceCapabilities->statefulDeflateDecompression = CPA_TRUE;
        pInstanceCapabilities->statelessDeflateCompression = CPA_TRUE;
        pInstanceCapabilities->statelessDeflateDecompression = CPA_TRUE;
        pInstanceCapabilities->checksumCRC32 = CPA_TRUE;
        pInstanceCapabilities->checksumAdler32 = CPA_TRUE;
        pInstanceCapabilities->dynamicHuffman = CPA_TRUE;
        pInstanceCapabilities->precompiledHuffman = CPA_FALSE;
        pInstanceCapabilities->dynamicHuffmanBufferReq = CPA_TRUE;
        pInstanceCapabilities->autoSelectBestHuffmanTree = CPA_TRUE;

        pInstanceCapabilities->validWindowSizeMaskCompression =
            pService->comp_device_data.windowSizeMask;
        pInstanceCapabilities->validWindowSizeMaskDecompression =
            pService->comp_device_data.windowSizeMask;
        pExtendedFtrs = (dc_extd_ftrs_t *)&(
            ((sal_service_t *)insHandle)->dcExtendedFeatures);
        pInstanceCapabilities->batchAndPack = CPA_FALSE;
        pInstanceCapabilities->compressAndVerify =
            (CpaBoolean)pExtendedFtrs->is_cnv;
        pInstanceCapabilities->compressAndVerifyStrict = CPA_TRUE;
        pInstanceCapabilities->compressAndVerifyAndRecover =
            (CpaBoolean)pExtendedFtrs->is_cnvnr;
        return CPA_STATUS_SUCCESS;
}

CpaStatus
cpaDcSetAddressTranslation(const CpaInstanceHandle instanceHandle,
                           CpaVirtualToPhysical virtual2Physical)
{
        sal_service_t *pService = NULL;
        CpaInstanceHandle insHandle = NULL;

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

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

        pService = (sal_service_t *)insHandle;

        pService->virt2PhysClient = virtual2Physical;

        return CPA_STATUS_SUCCESS;
}

/**
 ******************************************************************************
 * @ingroup cpaDcCommon
 * Data compression specific polling function which polls a DC instance.
 *****************************************************************************/

CpaStatus
icp_sal_DcPollInstance(CpaInstanceHandle instanceHandle_in,
                       Cpa32U response_quota)
{
        CpaStatus status = CPA_STATUS_SUCCESS;
        sal_compression_service_t *dc_handle = NULL;
        sal_service_t *gen_handle = NULL;
        icp_comms_trans_handle trans_hndTable[DC_NUM_RX_RINGS];

        if (CPA_INSTANCE_HANDLE_SINGLE == instanceHandle_in) {
                dc_handle = (sal_compression_service_t *)dcGetFirstHandle();
        } else {
                dc_handle = (sal_compression_service_t *)instanceHandle_in;
        }

        LAC_CHECK_NULL_PARAM(dc_handle);
        SAL_RUNNING_CHECK(dc_handle);

        gen_handle = &(dc_handle->generic_service_info);
        if (SAL_SERVICE_TYPE_COMPRESSION != gen_handle->type) {
                QAT_UTILS_LOG("Instance handle type is incorrect.\n");
                return CPA_STATUS_FAIL;
        }

        /*
         * From the instanceHandle we must get the trans_handle and send
         * down to adf for polling.
         * Populate our trans handle table with the appropriate handles.
         */
        trans_hndTable[0] = dc_handle->trans_handle_compression_rx;

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

/**
 ******************************************************************************
 * @ingroup cpaDcCommon
 *****************************************************************************/
CpaStatus
cpaDcInstanceSetNotificationCb(
    const CpaInstanceHandle instanceHandle,
    const CpaDcInstanceNotificationCbFunc pInstanceNotificationCb,
    void *pCallbackTag)
{
        CpaStatus status = CPA_STATUS_SUCCESS;
        sal_service_t *gen_handle = instanceHandle;

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

CpaInstanceHandle
dcGetFirstHandle(void)
{
        CpaStatus status = CPA_STATUS_SUCCESS;
        static icp_accel_dev_t *adfInsts[ADF_MAX_DEVICES] = { 0 };
        CpaInstanceHandle dcInst = NULL;
        icp_accel_dev_t *dev_addr = NULL;
        sal_t *base_addr = NULL;
        sal_list_t *list_temp = NULL;
        Cpa16U i, num_dc = 0;

        /* Only need 1 dev with compression enabled - so check all devices */
        status = icp_amgr_getAllAccelDevByCapabilities(
            ICP_ACCEL_CAPABILITIES_COMPRESSION, adfInsts, &num_dc);
        if ((0 == num_dc) || (CPA_STATUS_SUCCESS != status)) {
                QAT_UTILS_LOG(
                    "No compression devices enabled in the system.\n");
                return dcInst;
        }

        for (i = 0; i < num_dc; i++) {
                dev_addr = (icp_accel_dev_t *)adfInsts[i];
                if (NULL != dev_addr) {
                        base_addr = dev_addr->pSalHandle;
                        if (NULL != base_addr) {
                                list_temp = base_addr->compression_services;
                                if (NULL != list_temp) {
                                        dcInst = SalList_getObject(list_temp);
                                        break;
                                }
                        }
                }
        }
        return dcInst;
}