#include "cpa.h"
#include "cpa_cy_sym.h"
#include "icp_accel_devices.h"
#include "icp_adf_init.h"
#include "icp_qat_fw_la.h"
#include "icp_adf_transport.h"
#include "icp_adf_debug.h"
#include "lac_sym.h"
#include "lac_sym_cipher.h"
#include "lac_common.h"
#include "lac_list.h"
#include "lac_sal_types_crypto.h"
#include "lac_sal.h"
#include "lac_sal_ctrl.h"
#include "lac_session.h"
#include "lac_sym_stats.h"
#include "lac_log.h"
#include "lac_sym_cb.h"
#include "lac_sym_hash.h"
#include "lac_sym_qat_cipher.h"
#include "lac_sym_qat.h"
#define DEQUEUE_MSGPUT_MAX_RETRIES 10000
static void
LacSymCb_CleanUserData(const lac_session_desc_t *pSessionDesc,
CpaBufferList *pBufferList,
const CpaCySymOpData *pOpData,
CpaBoolean isCCM)
{
Cpa32U authTagLen = 0;
authTagLen = pSessionDesc->hashResultSize;
if (isCCM) {
LacBuffDesc_BufferListZeroFromOffset(
pBufferList,
pOpData->cryptoStartSrcOffsetInBytes,
pOpData->messageLenToCipherInBytes + authTagLen);
} else {
LacBuffDesc_BufferListZeroFromOffset(
pBufferList,
pOpData->cryptoStartSrcOffsetInBytes,
pOpData->messageLenToCipherInBytes);
}
if ((CPA_TRUE != pSessionDesc->digestIsAppended) &&
(NULL != pOpData->pDigestResult)) {
memset(pOpData->pDigestResult, 0, authTagLen);
}
}
static void
LacSymCb_ProcessCallbackInternal(lac_sym_bulk_cookie_t *pCookie,
CpaBoolean qatRespStatusOkFlag,
CpaStatus status,
lac_session_desc_t *pSessionDesc)
{
CpaCySymCbFunc pSymCb = NULL;
void *pCallbackTag = NULL;
CpaCySymOpData *pOpData = NULL;
CpaBufferList *pDstBuffer = NULL;
CpaCySymOp operationType = CPA_CY_SYM_OP_NONE;
CpaStatus dequeueStatus = CPA_STATUS_SUCCESS;
CpaInstanceHandle instanceHandle = CPA_INSTANCE_HANDLE_SINGLE;
instanceHandle = pCookie->instanceHandle;
pOpData = (CpaCySymOpData *)LAC_CONST_PTR_CAST(pCookie->pOpData);
operationType = pSessionDesc->symOperation;
pDstBuffer = pCookie->pDstBuffer;
if (((SPC == pSessionDesc->singlePassState) ||
(CPA_CY_SYM_OP_CIPHER != operationType)) &&
(CPA_TRUE == pSessionDesc->digestVerify) &&
((CPA_CY_SYM_PACKET_TYPE_FULL == pOpData->packetType) ||
(CPA_CY_SYM_PACKET_TYPE_LAST_PARTIAL == pOpData->packetType))) {
if (CPA_FALSE == qatRespStatusOkFlag) {
LAC_SYM_STAT_INC(numSymOpVerifyFailures,
instanceHandle);
if (pSessionDesc->cipherAlgorithm ==
CPA_CY_SYM_CIPHER_AES_CCM) {
LacSymCb_CleanUserData(pSessionDesc,
pDstBuffer,
pOpData,
CPA_TRUE);
} else if (pSessionDesc->cipherAlgorithm ==
CPA_CY_SYM_CIPHER_AES_GCM) {
LacSymCb_CleanUserData(pSessionDesc,
pDstBuffer,
pOpData,
CPA_FALSE);
}
}
} else {
if ((CPA_STATUS_SUCCESS == status) &&
(CPA_TRUE != qatRespStatusOkFlag)) {
LAC_LOG_ERROR("Response status value not as expected");
status = CPA_STATUS_FAIL;
}
}
pSymCb = pSessionDesc->pSymCb;
pCallbackTag = pCookie->pCallbackTag;
if (CPA_CY_SYM_PACKET_TYPE_PARTIAL == pOpData->packetType) {
if ((CPA_CY_SYM_OP_CIPHER == operationType) ||
(CPA_CY_SYM_OP_ALGORITHM_CHAINING == operationType)) {
if (CPA_TRUE == pCookie->updateUserIvOnRecieve) {
memcpy(pCookie->pOpData->pIv,
pSessionDesc->cipherPartialOpState,
pCookie->pOpData->ivLenInBytes);
}
if (CPA_TRUE == pCookie->updateKeySizeOnRecieve &&
LAC_CIPHER_IS_XTS_MODE(
pSessionDesc->cipherAlgorithm)) {
LacSymQat_CipherXTSModeUpdateKeyLen(
pSessionDesc,
pSessionDesc->cipherKeyLenInBytes / 2);
}
}
} else if (CPA_CY_SYM_PACKET_TYPE_LAST_PARTIAL == pOpData->packetType) {
if ((CPA_CY_SYM_OP_CIPHER == operationType) ||
(CPA_CY_SYM_OP_ALGORITHM_CHAINING == operationType)) {
if (CPA_TRUE ==
LAC_CIPHER_IS_XTS_MODE(
pSessionDesc->cipherAlgorithm)) {
LacSymQat_CipherXTSModeUpdateKeyLen(
pSessionDesc,
pSessionDesc->cipherKeyLenInBytes);
}
}
}
if ((CPA_CY_SYM_PACKET_TYPE_FULL != pOpData->packetType) &&
(qatRespStatusOkFlag != CPA_FALSE)) {
dequeueStatus = LacSymCb_PendingReqsDequeue(pSessionDesc);
if (CPA_STATUS_SUCCESS != dequeueStatus) {
LAC_SYM_STAT_INC(numSymOpCompletedErrors,
instanceHandle);
qatRespStatusOkFlag = CPA_FALSE;
if (CPA_STATUS_SUCCESS == status) {
status = dequeueStatus;
}
}
}
if (CPA_STATUS_SUCCESS == status) {
if (pSessionDesc->internalSession == CPA_FALSE) {
LAC_SYM_STAT_INC(numSymOpCompleted, instanceHandle);
if (CPA_STATUS_SUCCESS != status) {
LAC_SYM_STAT_INC(numSymOpCompletedErrors,
instanceHandle);
}
}
}
qatUtilsAtomicDec(&(pSessionDesc->u.pendingCbCount));
Lac_MemPoolEntryFree(pCookie);
pSymCb(pCallbackTag,
status,
operationType,
pOpData,
pDstBuffer,
qatRespStatusOkFlag);
}
static void
LacSymCb_ProcessDpCallback(CpaCySymDpOpData *pResponse,
CpaBoolean qatRespStatusOkFlag,
CpaStatus status,
lac_session_desc_t *pSessionDesc)
{
CpaCySymDpCbFunc pSymDpCb = NULL;
if (((CPA_CY_SYM_OP_CIPHER == pSessionDesc->symOperation) &&
SPC != pSessionDesc->singlePassState) ||
(CPA_FALSE == pSessionDesc->digestVerify)) {
if ((CPA_FALSE == qatRespStatusOkFlag) &&
(status != CPA_STATUS_UNSUPPORTED)) {
LAC_LOG_ERROR("Response status value not as expected");
status = CPA_STATUS_FAIL;
}
}
pSymDpCb =
((sal_crypto_service_t *)pResponse->instanceHandle)->pSymDpCb;
pSymDpCb(pResponse, status, qatRespStatusOkFlag);
qatUtilsAtomicDec(&pSessionDesc->u.pendingDpCbCount);
}
static void
LacSymCb_ProcessCallback(icp_qat_fw_la_cmd_id_t lacCmdId,
void *pOpaqueData,
icp_qat_fw_comn_flags cmnRespFlags)
{
CpaStatus status = CPA_STATUS_SUCCESS;
CpaCySymDpOpData *pDpOpData = (CpaCySymDpOpData *)pOpaqueData;
lac_session_desc_t *pSessionDesc =
LAC_SYM_SESSION_DESC_FROM_CTX_GET(pDpOpData->sessionCtx);
CpaBoolean qatRespStatusOkFlag =
(CpaBoolean)(ICP_QAT_FW_COMN_STATUS_FLAG_OK ==
ICP_QAT_FW_COMN_RESP_CRYPTO_STAT_GET(cmnRespFlags));
if (CPA_TRUE == pSessionDesc->isDPSession) {
if (ICP_QAT_FW_COMN_RESP_UNSUPPORTED_REQUEST_STAT_GET(
cmnRespFlags)) {
status = CPA_STATUS_UNSUPPORTED;
}
LacSymCb_ProcessDpCallback(pDpOpData,
qatRespStatusOkFlag,
status,
pSessionDesc);
} else {
LacSymCb_ProcessCallbackInternal((lac_sym_bulk_cookie_t *)
pOpaqueData,
qatRespStatusOkFlag,
CPA_STATUS_SUCCESS,
pSessionDesc);
}
}
CpaStatus
LacSymCb_PendingReqsDequeue(lac_session_desc_t *pSessionDesc)
{
CpaStatus status = CPA_STATUS_SUCCESS;
sal_crypto_service_t *pService = NULL;
Cpa32U retries = 0;
pService = (sal_crypto_service_t *)pSessionDesc->pInstance;
LAC_SPINLOCK(&pSessionDesc->requestQueueLock);
pSessionDesc->nonBlockingOpsInProgress = CPA_TRUE;
while ((NULL != pSessionDesc->pRequestQueueHead) &&
(CPA_TRUE == pSessionDesc->nonBlockingOpsInProgress)) {
if (CPA_CY_SYM_PACKET_TYPE_FULL !=
pSessionDesc->pRequestQueueHead->pOpData->packetType) {
pSessionDesc->nonBlockingOpsInProgress = CPA_FALSE;
}
if (CPA_TRUE ==
pSessionDesc->pRequestQueueHead->updateSessionIvOnSend) {
if (LAC_CIPHER_IS_ARC4(pSessionDesc->cipherAlgorithm)) {
memcpy(pSessionDesc->cipherPartialOpState,
pSessionDesc->cipherARC4InitialState,
LAC_CIPHER_ARC4_STATE_LEN_BYTES);
} else {
memcpy(pSessionDesc->cipherPartialOpState,
pSessionDesc->pRequestQueueHead->pOpData
->pIv,
pSessionDesc->pRequestQueueHead->pOpData
->ivLenInBytes);
}
}
retries = 0;
do {
status = icp_adf_transPutMsg(
pService->trans_handle_sym_tx,
(void *)&(pSessionDesc->pRequestQueueHead->qatMsg),
LAC_QAT_SYM_REQ_SZ_LW);
retries++;
if (CPA_STATUS_SUCCESS != status) {
qatUtilsYield();
}
} while ((CPA_STATUS_SUCCESS != status) &&
(retries < DEQUEUE_MSGPUT_MAX_RETRIES));
if ((CPA_STATUS_SUCCESS != status) ||
(retries >= DEQUEUE_MSGPUT_MAX_RETRIES)) {
LAC_LOG_ERROR(
"Failed to SalQatMsg_transPutMsg, maximum retries exceeded.");
goto cleanup;
}
pSessionDesc->pRequestQueueHead =
pSessionDesc->pRequestQueueHead->pNext;
}
if (NULL == pSessionDesc->pRequestQueueHead) {
pSessionDesc->pRequestQueueTail = NULL;
}
cleanup:
LAC_SPINUNLOCK(&pSessionDesc->requestQueueLock);
return status;
}
void
LacSymCb_CallbacksRegister(void)
{
LacSymQat_RespHandlerRegister(ICP_QAT_FW_LA_CMD_AUTH,
LacSymCb_ProcessCallback);
LacSymQat_RespHandlerRegister(ICP_QAT_FW_LA_CMD_CIPHER_HASH,
LacSymCb_ProcessCallback);
LacSymQat_RespHandlerRegister(ICP_QAT_FW_LA_CMD_HASH_CIPHER,
LacSymCb_ProcessCallback);
LacSymQat_RespHandlerRegister(ICP_QAT_FW_LA_CMD_CIPHER,
LacSymCb_ProcessCallback);
LacSym_CompileTimeAssertions();
}