1a1dfa7ecSAlexey Marchuk /* SPDX-License-Identifier: BSD-3-Clause 2cf151d60SAlexey Marchuk * Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3a1dfa7ecSAlexey Marchuk */ 4a1dfa7ecSAlexey Marchuk 5a1dfa7ecSAlexey Marchuk #include <rdma/rdma_cma.h> 6a1dfa7ecSAlexey Marchuk #include <infiniband/verbs.h> 7a1dfa7ecSAlexey Marchuk #include <infiniband/mlx5dv.h> 8a1dfa7ecSAlexey Marchuk 9a1dfa7ecSAlexey Marchuk #include "spdk/stdinc.h" 10a1dfa7ecSAlexey Marchuk #include "spdk/queue.h" 11a1dfa7ecSAlexey Marchuk #include "spdk/log.h" 12a1dfa7ecSAlexey Marchuk #include "spdk/likely.h" 13a1dfa7ecSAlexey Marchuk #include "spdk/util.h" 14a1dfa7ecSAlexey Marchuk #include "spdk_internal/mlx5.h" 158a01b4d6SAlexey Marchuk #include "spdk_internal/rdma_utils.h" 168ffbc77dSAlexey Marchuk #include "mlx5_ifc.h" 176ab03daeSAlexey Marchuk #include "mlx5_priv.h" 18a1dfa7ecSAlexey Marchuk 19a1dfa7ecSAlexey Marchuk /* Plaintext key sizes */ 20a1dfa7ecSAlexey Marchuk /* 64b keytag */ 21a1dfa7ecSAlexey Marchuk #define SPDK_MLX5_AES_XTS_KEYTAG_SIZE 8 22a1dfa7ecSAlexey Marchuk /* key1_128b + key2_128b */ 23a1dfa7ecSAlexey Marchuk #define SPDK_MLX5_AES_XTS_128_DEK_BYTES 32 24a1dfa7ecSAlexey Marchuk /* key1_256b + key2_256b */ 25a1dfa7ecSAlexey Marchuk #define SPDK_MLX5_AES_XTS_256_DEK_BYTES 64 26a1dfa7ecSAlexey Marchuk /* key1_128b + key2_128b + 64b_keytag */ 27a1dfa7ecSAlexey Marchuk #define SPDK_MLX5_AES_XTS_128_DEK_BYTES_WITH_KEYTAG (SPDK_MLX5_AES_XTS_128_DEK_BYTES + SPDK_MLX5_AES_XTS_KEYTAG_SIZE) 28a1dfa7ecSAlexey Marchuk /* key1_256b + key2_256b + 64b_keytag */ 29a1dfa7ecSAlexey Marchuk #define SPDK_MLX5_AES_XTS_256_DEK_BYTES_WITH_KEYTAG (SPDK_MLX5_AES_XTS_256_DEK_BYTES + SPDK_MLX5_AES_XTS_KEYTAG_SIZE) 30a1dfa7ecSAlexey Marchuk 316ab03daeSAlexey Marchuk struct mlx5_crypto_dek_init_attr { 326ab03daeSAlexey Marchuk char *dek; 336ab03daeSAlexey Marchuk uint64_t opaque; 346ab03daeSAlexey Marchuk uint32_t key_size_bytes; 356ab03daeSAlexey Marchuk uint8_t key_size; /* driver representation of \b key_size_bytes */ 366ab03daeSAlexey Marchuk uint8_t keytag; 376ab03daeSAlexey Marchuk }; 383f657ddbSAlexey Marchuk 396ab03daeSAlexey Marchuk struct mlx5_crypto_dek_query_attr { 406ab03daeSAlexey Marchuk /* state either MLX5_ENCRYPTION_KEY_OBJ_STATE_READY or MLX5_ENCRYPTION_KEY_OBJ_STATE_ERROR */ 416ab03daeSAlexey Marchuk uint8_t state; 426ab03daeSAlexey Marchuk uint64_t opaque; 436ab03daeSAlexey Marchuk }; 446ab03daeSAlexey Marchuk 456ab03daeSAlexey Marchuk struct mlx5_crypto_dek { 466ab03daeSAlexey Marchuk struct mlx5dv_devx_obj *devx_obj; 476ab03daeSAlexey Marchuk struct ibv_pd *pd; 486ab03daeSAlexey Marchuk struct ibv_context *context; 496ab03daeSAlexey Marchuk /* Cached dek_obj_id */ 506ab03daeSAlexey Marchuk uint32_t dek_obj_id; 516ab03daeSAlexey Marchuk enum spdk_mlx5_crypto_key_tweak_mode tweak_mode; 526ab03daeSAlexey Marchuk }; 536ab03daeSAlexey Marchuk 54a1dfa7ecSAlexey Marchuk struct spdk_mlx5_crypto_keytag { 556ab03daeSAlexey Marchuk struct mlx5_crypto_dek *deks; 56a1dfa7ecSAlexey Marchuk uint32_t deks_num; 57a1dfa7ecSAlexey Marchuk bool has_keytag; 58a1dfa7ecSAlexey Marchuk char keytag[8]; 59a1dfa7ecSAlexey Marchuk }; 60a1dfa7ecSAlexey Marchuk 616ab03daeSAlexey Marchuk static char **g_allowed_devices; 626ab03daeSAlexey Marchuk static size_t g_allowed_devices_count; 636ab03daeSAlexey Marchuk 643f657ddbSAlexey Marchuk static void 653f657ddbSAlexey Marchuk mlx5_crypto_devs_free(void) 663f657ddbSAlexey Marchuk { 673f657ddbSAlexey Marchuk size_t i; 683f657ddbSAlexey Marchuk 693f657ddbSAlexey Marchuk if (!g_allowed_devices) { 703f657ddbSAlexey Marchuk return; 713f657ddbSAlexey Marchuk } 723f657ddbSAlexey Marchuk 733f657ddbSAlexey Marchuk for (i = 0; i < g_allowed_devices_count; i++) { 743f657ddbSAlexey Marchuk free(g_allowed_devices[i]); 753f657ddbSAlexey Marchuk } 763f657ddbSAlexey Marchuk free(g_allowed_devices); 773f657ddbSAlexey Marchuk g_allowed_devices = NULL; 783f657ddbSAlexey Marchuk g_allowed_devices_count = 0; 793f657ddbSAlexey Marchuk } 803f657ddbSAlexey Marchuk 813f657ddbSAlexey Marchuk static bool 823f657ddbSAlexey Marchuk mlx5_crypto_dev_allowed(const char *dev) 833f657ddbSAlexey Marchuk { 843f657ddbSAlexey Marchuk size_t i; 853f657ddbSAlexey Marchuk 863f657ddbSAlexey Marchuk if (!g_allowed_devices || !g_allowed_devices_count) { 873f657ddbSAlexey Marchuk return true; 883f657ddbSAlexey Marchuk } 893f657ddbSAlexey Marchuk 903f657ddbSAlexey Marchuk for (i = 0; i < g_allowed_devices_count; i++) { 913f657ddbSAlexey Marchuk if (strcmp(g_allowed_devices[i], dev) == 0) { 923f657ddbSAlexey Marchuk return true; 933f657ddbSAlexey Marchuk } 943f657ddbSAlexey Marchuk } 953f657ddbSAlexey Marchuk 963f657ddbSAlexey Marchuk return false; 973f657ddbSAlexey Marchuk } 983f657ddbSAlexey Marchuk 993f657ddbSAlexey Marchuk int 1003f657ddbSAlexey Marchuk spdk_mlx5_crypto_devs_allow(const char *const dev_names[], size_t devs_count) 1013f657ddbSAlexey Marchuk { 1023f657ddbSAlexey Marchuk size_t i; 1033f657ddbSAlexey Marchuk 1043f657ddbSAlexey Marchuk mlx5_crypto_devs_free(); 1053f657ddbSAlexey Marchuk 1063f657ddbSAlexey Marchuk if (!dev_names || !devs_count) { 1073f657ddbSAlexey Marchuk return 0; 1083f657ddbSAlexey Marchuk } 1093f657ddbSAlexey Marchuk 1103f657ddbSAlexey Marchuk g_allowed_devices = calloc(devs_count, sizeof(char *)); 1113f657ddbSAlexey Marchuk if (!g_allowed_devices) { 1123f657ddbSAlexey Marchuk return -ENOMEM; 1133f657ddbSAlexey Marchuk } 1143f657ddbSAlexey Marchuk for (i = 0; i < devs_count; i++) { 1153f657ddbSAlexey Marchuk g_allowed_devices[i] = strndup(dev_names[i], SPDK_MLX5_DEV_MAX_NAME_LEN); 1163f657ddbSAlexey Marchuk if (!g_allowed_devices[i]) { 1173f657ddbSAlexey Marchuk mlx5_crypto_devs_free(); 1183f657ddbSAlexey Marchuk return -ENOMEM; 1193f657ddbSAlexey Marchuk } 1203f657ddbSAlexey Marchuk g_allowed_devices_count++; 1213f657ddbSAlexey Marchuk } 1223f657ddbSAlexey Marchuk 1233f657ddbSAlexey Marchuk return 0; 1243f657ddbSAlexey Marchuk } 1253f657ddbSAlexey Marchuk 126a1dfa7ecSAlexey Marchuk struct ibv_context ** 127a1dfa7ecSAlexey Marchuk spdk_mlx5_crypto_devs_get(int *dev_num) 128a1dfa7ecSAlexey Marchuk { 129a1dfa7ecSAlexey Marchuk struct ibv_context **rdma_devs, **rdma_devs_out = NULL, *dev; 130a1dfa7ecSAlexey Marchuk struct ibv_device_attr dev_attr; 1318ffbc77dSAlexey Marchuk struct ibv_port_attr port_attr; 1328ffbc77dSAlexey Marchuk struct spdk_mlx5_device_caps dev_caps; 1338ffbc77dSAlexey Marchuk uint8_t in[DEVX_ST_SZ_BYTES(query_nic_vport_context_in)]; 1348ffbc77dSAlexey Marchuk uint8_t out[DEVX_ST_SZ_BYTES(query_nic_vport_context_out)]; 1358ffbc77dSAlexey Marchuk uint8_t devx_v; 136a1dfa7ecSAlexey Marchuk int num_rdma_devs = 0, i, rc; 137a1dfa7ecSAlexey Marchuk int num_crypto_devs = 0; 138a1dfa7ecSAlexey Marchuk 139a1dfa7ecSAlexey Marchuk /* query all devices, save mlx5 with crypto support */ 140a1dfa7ecSAlexey Marchuk rdma_devs = rdma_get_devices(&num_rdma_devs); 141a1dfa7ecSAlexey Marchuk if (!rdma_devs || !num_rdma_devs) { 142a1dfa7ecSAlexey Marchuk *dev_num = 0; 143a1dfa7ecSAlexey Marchuk return NULL; 144a1dfa7ecSAlexey Marchuk } 145a1dfa7ecSAlexey Marchuk 146a1dfa7ecSAlexey Marchuk rdma_devs_out = calloc(num_rdma_devs + 1, sizeof(*rdma_devs_out)); 147a1dfa7ecSAlexey Marchuk if (!rdma_devs_out) { 148a1dfa7ecSAlexey Marchuk SPDK_ERRLOG("Memory allocation failed\n"); 149a1dfa7ecSAlexey Marchuk return NULL; 150a1dfa7ecSAlexey Marchuk } 151a1dfa7ecSAlexey Marchuk 152a1dfa7ecSAlexey Marchuk for (i = 0; i < num_rdma_devs; i++) { 153a1dfa7ecSAlexey Marchuk dev = rdma_devs[i]; 154a1dfa7ecSAlexey Marchuk rc = ibv_query_device(dev, &dev_attr); 155a1dfa7ecSAlexey Marchuk if (rc) { 156a1dfa7ecSAlexey Marchuk SPDK_ERRLOG("Failed to query dev %s, skipping\n", dev->device->name); 157a1dfa7ecSAlexey Marchuk continue; 158a1dfa7ecSAlexey Marchuk } 1596ab03daeSAlexey Marchuk if (dev_attr.vendor_id != SPDK_MLX5_VENDOR_ID_MELLANOX) { 160a1dfa7ecSAlexey Marchuk SPDK_DEBUGLOG(mlx5, "dev %s is not Mellanox device, skipping\n", dev->device->name); 161a1dfa7ecSAlexey Marchuk continue; 162a1dfa7ecSAlexey Marchuk } 163a1dfa7ecSAlexey Marchuk 1643f657ddbSAlexey Marchuk if (!mlx5_crypto_dev_allowed(dev->device->name)) { 1653f657ddbSAlexey Marchuk continue; 1663f657ddbSAlexey Marchuk } 1673f657ddbSAlexey Marchuk 1688ffbc77dSAlexey Marchuk rc = ibv_query_port(dev, 1, &port_attr); 1698ffbc77dSAlexey Marchuk if (rc) { 1708ffbc77dSAlexey Marchuk SPDK_ERRLOG("Failed to query port attributes for device %s, rc %d\n", dev->device->name, rc); 1718ffbc77dSAlexey Marchuk continue; 1728ffbc77dSAlexey Marchuk } 1738ffbc77dSAlexey Marchuk 1748ffbc77dSAlexey Marchuk if (port_attr.link_layer == IBV_LINK_LAYER_ETHERNET) { 1758ffbc77dSAlexey Marchuk /* Port may be ethernet but roce is still disabled */ 1768ffbc77dSAlexey Marchuk memset(in, 0, sizeof(in)); 1778ffbc77dSAlexey Marchuk memset(out, 0, sizeof(out)); 1788ffbc77dSAlexey Marchuk DEVX_SET(query_nic_vport_context_in, in, opcode, MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT); 1798ffbc77dSAlexey Marchuk rc = mlx5dv_devx_general_cmd(dev, in, sizeof(in), out, sizeof(out)); 1808ffbc77dSAlexey Marchuk if (rc) { 1818ffbc77dSAlexey Marchuk SPDK_ERRLOG("Failed to get VPORT context for device %s. Assuming ROCE is disabled\n", 1828ffbc77dSAlexey Marchuk dev->device->name); 1838ffbc77dSAlexey Marchuk continue; 1848ffbc77dSAlexey Marchuk } 1858ffbc77dSAlexey Marchuk 1868ffbc77dSAlexey Marchuk devx_v = DEVX_GET(query_nic_vport_context_out, out, nic_vport_context.roce_en); 1878ffbc77dSAlexey Marchuk if (!devx_v) { 1888ffbc77dSAlexey Marchuk SPDK_ERRLOG("Device %s, RoCE disabled\n", dev->device->name); 1898ffbc77dSAlexey Marchuk continue; 1908ffbc77dSAlexey Marchuk } 1918ffbc77dSAlexey Marchuk } 1928ffbc77dSAlexey Marchuk 1938ffbc77dSAlexey Marchuk memset(&dev_caps, 0, sizeof(dev_caps)); 1948ffbc77dSAlexey Marchuk rc = spdk_mlx5_device_query_caps(dev, &dev_caps); 195a1dfa7ecSAlexey Marchuk if (rc) { 196a1dfa7ecSAlexey Marchuk SPDK_ERRLOG("Failed to query mlx5 dev %s, skipping\n", dev->device->name); 197a1dfa7ecSAlexey Marchuk continue; 198a1dfa7ecSAlexey Marchuk } 1998ffbc77dSAlexey Marchuk if (!dev_caps.crypto_supported) { 2008ffbc77dSAlexey Marchuk SPDK_WARNLOG("dev %s crypto engine doesn't support crypto\n", dev->device->name); 201a1dfa7ecSAlexey Marchuk continue; 202a1dfa7ecSAlexey Marchuk } 2038ffbc77dSAlexey Marchuk if (!(dev_caps.crypto.single_block_le_tweak || dev_caps.crypto.multi_block_le_tweak || 2048ffbc77dSAlexey Marchuk dev_caps.crypto.multi_block_be_tweak)) { 2058ffbc77dSAlexey Marchuk SPDK_WARNLOG("dev %s crypto engine doesn't support AES_XTS\n", dev->device->name); 206a1dfa7ecSAlexey Marchuk continue; 207a1dfa7ecSAlexey Marchuk } 2088ffbc77dSAlexey Marchuk if (dev_caps.crypto.wrapped_import_method_aes_xts) { 2098ffbc77dSAlexey Marchuk SPDK_WARNLOG("dev %s uses wrapped import method which is not supported by mlx5 lib\n", 2108ffbc77dSAlexey Marchuk dev->device->name); 211a1dfa7ecSAlexey Marchuk continue; 212a1dfa7ecSAlexey Marchuk } 213a1dfa7ecSAlexey Marchuk 214a1dfa7ecSAlexey Marchuk rdma_devs_out[num_crypto_devs++] = dev; 215a1dfa7ecSAlexey Marchuk } 216a1dfa7ecSAlexey Marchuk 217a1dfa7ecSAlexey Marchuk if (!num_crypto_devs) { 218a1dfa7ecSAlexey Marchuk SPDK_DEBUGLOG(mlx5, "Found no mlx5 crypto devices\n"); 219a1dfa7ecSAlexey Marchuk goto err_out; 220a1dfa7ecSAlexey Marchuk } 221a1dfa7ecSAlexey Marchuk 222a1dfa7ecSAlexey Marchuk rdma_free_devices(rdma_devs); 223a1dfa7ecSAlexey Marchuk *dev_num = num_crypto_devs; 224a1dfa7ecSAlexey Marchuk 225a1dfa7ecSAlexey Marchuk return rdma_devs_out; 226a1dfa7ecSAlexey Marchuk 227a1dfa7ecSAlexey Marchuk err_out: 228a1dfa7ecSAlexey Marchuk free(rdma_devs_out); 229a1dfa7ecSAlexey Marchuk rdma_free_devices(rdma_devs); 230a1dfa7ecSAlexey Marchuk *dev_num = 0; 231a1dfa7ecSAlexey Marchuk return NULL; 232a1dfa7ecSAlexey Marchuk } 233a1dfa7ecSAlexey Marchuk 234a1dfa7ecSAlexey Marchuk void 235a1dfa7ecSAlexey Marchuk spdk_mlx5_crypto_devs_release(struct ibv_context **rdma_devs) 236a1dfa7ecSAlexey Marchuk { 237a1dfa7ecSAlexey Marchuk if (rdma_devs) { 238a1dfa7ecSAlexey Marchuk free(rdma_devs); 239a1dfa7ecSAlexey Marchuk } 240a1dfa7ecSAlexey Marchuk } 241a1dfa7ecSAlexey Marchuk 2428ffbc77dSAlexey Marchuk int 2438ffbc77dSAlexey Marchuk spdk_mlx5_device_query_caps(struct ibv_context *context, struct spdk_mlx5_device_caps *caps) 2448ffbc77dSAlexey Marchuk { 2458ffbc77dSAlexey Marchuk uint16_t opmod = MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE | 2468ffbc77dSAlexey Marchuk HCA_CAP_OPMOD_GET_CUR; 2478ffbc77dSAlexey Marchuk uint32_t out[DEVX_ST_SZ_DW(query_hca_cap_out)] = {}; 2488ffbc77dSAlexey Marchuk uint32_t in[DEVX_ST_SZ_DW(query_hca_cap_in)] = {}; 2498ffbc77dSAlexey Marchuk int rc; 2508ffbc77dSAlexey Marchuk 2518ffbc77dSAlexey Marchuk DEVX_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); 2528ffbc77dSAlexey Marchuk DEVX_SET(query_hca_cap_in, in, op_mod, opmod); 2538ffbc77dSAlexey Marchuk 2548ffbc77dSAlexey Marchuk rc = mlx5dv_devx_general_cmd(context, in, sizeof(in), out, sizeof(out)); 2558ffbc77dSAlexey Marchuk if (rc) { 2568ffbc77dSAlexey Marchuk return rc; 2578ffbc77dSAlexey Marchuk } 2588ffbc77dSAlexey Marchuk 259*c9ec1e2bSAlexey Marchuk caps->crc32c_supported = DEVX_GET(query_hca_cap_out, out, capability.cmd_hca_cap.sho) && 260*c9ec1e2bSAlexey Marchuk DEVX_GET(query_hca_cap_out, out, capability.cmd_hca_cap.sig_crc32c); 261*c9ec1e2bSAlexey Marchuk 2628ffbc77dSAlexey Marchuk caps->crypto_supported = DEVX_GET(query_hca_cap_out, out, capability.cmd_hca_cap.crypto); 2638ffbc77dSAlexey Marchuk if (!caps->crypto_supported) { 2648ffbc77dSAlexey Marchuk return 0; 2658ffbc77dSAlexey Marchuk } 2668ffbc77dSAlexey Marchuk 2678ffbc77dSAlexey Marchuk caps->crypto.single_block_le_tweak = DEVX_GET(query_hca_cap_out, 2688ffbc77dSAlexey Marchuk out, capability.cmd_hca_cap.aes_xts_single_block_le_tweak); 2698ffbc77dSAlexey Marchuk caps->crypto.multi_block_be_tweak = DEVX_GET(query_hca_cap_out, out, 2708ffbc77dSAlexey Marchuk capability.cmd_hca_cap.aes_xts_multi_block_be_tweak); 2718ffbc77dSAlexey Marchuk caps->crypto.multi_block_le_tweak = DEVX_GET(query_hca_cap_out, out, 2728ffbc77dSAlexey Marchuk capability.cmd_hca_cap.aes_xts_multi_block_le_tweak); 2738ffbc77dSAlexey Marchuk 2748ffbc77dSAlexey Marchuk opmod = MLX5_SET_HCA_CAP_OP_MOD_CRYPTO | HCA_CAP_OPMOD_GET_CUR; 2758ffbc77dSAlexey Marchuk memset(&out, 0, sizeof(out)); 2768ffbc77dSAlexey Marchuk memset(&in, 0, sizeof(in)); 2778ffbc77dSAlexey Marchuk 2788ffbc77dSAlexey Marchuk DEVX_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); 2798ffbc77dSAlexey Marchuk DEVX_SET(query_hca_cap_in, in, op_mod, opmod); 2808ffbc77dSAlexey Marchuk 2818ffbc77dSAlexey Marchuk rc = mlx5dv_devx_general_cmd(context, in, sizeof(in), out, sizeof(out)); 2828ffbc77dSAlexey Marchuk if (rc) { 2838ffbc77dSAlexey Marchuk return rc; 2848ffbc77dSAlexey Marchuk } 2858ffbc77dSAlexey Marchuk 2868ffbc77dSAlexey Marchuk caps->crypto.wrapped_crypto_operational = DEVX_GET(query_hca_cap_out, out, 2878ffbc77dSAlexey Marchuk capability.crypto_caps.wrapped_crypto_operational); 2888ffbc77dSAlexey Marchuk caps->crypto.wrapped_crypto_going_to_commissioning = DEVX_GET(query_hca_cap_out, out, 2898ffbc77dSAlexey Marchuk capability.crypto_caps .wrapped_crypto_going_to_commissioning); 2908ffbc77dSAlexey Marchuk caps->crypto.wrapped_import_method_aes_xts = (DEVX_GET(query_hca_cap_out, out, 2918ffbc77dSAlexey Marchuk capability.crypto_caps.wrapped_import_method) & 2928ffbc77dSAlexey Marchuk MLX5_CRYPTO_CAPS_WRAPPED_IMPORT_METHOD_AES) != 0; 2938ffbc77dSAlexey Marchuk 2948ffbc77dSAlexey Marchuk return 0; 2958ffbc77dSAlexey Marchuk } 2968ffbc77dSAlexey Marchuk 2976ab03daeSAlexey Marchuk static void 2986ab03daeSAlexey Marchuk mlx5_crypto_dek_deinit(struct mlx5_crypto_dek *dek) 2996ab03daeSAlexey Marchuk { 3006ab03daeSAlexey Marchuk int rc; 3016ab03daeSAlexey Marchuk 3026ab03daeSAlexey Marchuk rc = mlx5dv_devx_obj_destroy(dek->devx_obj); 3036ab03daeSAlexey Marchuk if (rc) { 3046ab03daeSAlexey Marchuk SPDK_ERRLOG("Failed to destroy crypto obj:%p, rc %d\n", dek->devx_obj, rc); 3056ab03daeSAlexey Marchuk } 3066ab03daeSAlexey Marchuk } 3076ab03daeSAlexey Marchuk 308a1dfa7ecSAlexey Marchuk void 309a1dfa7ecSAlexey Marchuk spdk_mlx5_crypto_keytag_destroy(struct spdk_mlx5_crypto_keytag *keytag) 310a1dfa7ecSAlexey Marchuk { 3116ab03daeSAlexey Marchuk struct mlx5_crypto_dek *dek; 312a1dfa7ecSAlexey Marchuk uint32_t i; 313a1dfa7ecSAlexey Marchuk 314a1dfa7ecSAlexey Marchuk if (!keytag) { 315a1dfa7ecSAlexey Marchuk return; 316a1dfa7ecSAlexey Marchuk } 317a1dfa7ecSAlexey Marchuk 318a1dfa7ecSAlexey Marchuk for (i = 0; i < keytag->deks_num; i++) { 319a1dfa7ecSAlexey Marchuk dek = &keytag->deks[i]; 3206ab03daeSAlexey Marchuk if (dek->devx_obj) { 3216ab03daeSAlexey Marchuk mlx5_crypto_dek_deinit(dek); 322a1dfa7ecSAlexey Marchuk } 323a1dfa7ecSAlexey Marchuk if (dek->pd) { 3248a01b4d6SAlexey Marchuk spdk_rdma_utils_put_pd(dek->pd); 325a1dfa7ecSAlexey Marchuk } 326a1dfa7ecSAlexey Marchuk } 327a1dfa7ecSAlexey Marchuk spdk_memset_s(keytag->keytag, sizeof(keytag->keytag), 0, sizeof(keytag->keytag)); 328a1dfa7ecSAlexey Marchuk free(keytag->deks); 329a1dfa7ecSAlexey Marchuk free(keytag); 330a1dfa7ecSAlexey Marchuk } 331a1dfa7ecSAlexey Marchuk 3326ab03daeSAlexey Marchuk static int 3336ab03daeSAlexey Marchuk mlx5_crypto_dek_init(struct ibv_pd *pd, struct mlx5_crypto_dek_init_attr *attr, 3346ab03daeSAlexey Marchuk struct mlx5_crypto_dek *dek) 3356ab03daeSAlexey Marchuk { 3366ab03daeSAlexey Marchuk uint32_t in[DEVX_ST_SZ_DW(create_encryption_key_obj_in)] = {}; 3376ab03daeSAlexey Marchuk uint32_t out[DEVX_ST_SZ_DW(general_obj_out_cmd_hdr)] = {}; 3386ab03daeSAlexey Marchuk uint8_t *dek_in; 3396ab03daeSAlexey Marchuk uint32_t pdn; 3406ab03daeSAlexey Marchuk int rc; 3416ab03daeSAlexey Marchuk 3426ab03daeSAlexey Marchuk rc = mlx5_get_pd_id(pd, &pdn); 3436ab03daeSAlexey Marchuk if (rc) { 3446ab03daeSAlexey Marchuk return rc; 3456ab03daeSAlexey Marchuk } 3466ab03daeSAlexey Marchuk 3476ab03daeSAlexey Marchuk dek_in = DEVX_ADDR_OF(create_encryption_key_obj_in, in, hdr); 3486ab03daeSAlexey Marchuk DEVX_SET(general_obj_in_cmd_hdr, dek_in, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); 3496ab03daeSAlexey Marchuk DEVX_SET(general_obj_in_cmd_hdr, dek_in, obj_type, MLX5_OBJ_TYPE_DEK); 3506ab03daeSAlexey Marchuk dek_in = DEVX_ADDR_OF(create_encryption_key_obj_in, in, key_obj); 3516ab03daeSAlexey Marchuk DEVX_SET(encryption_key_obj, dek_in, key_size, attr->key_size); 3526ab03daeSAlexey Marchuk DEVX_SET(encryption_key_obj, dek_in, has_keytag, attr->keytag); 3536ab03daeSAlexey Marchuk DEVX_SET(encryption_key_obj, dek_in, key_purpose, MLX5_ENCRYPTION_KEY_OBJ_KEY_PURPOSE_AES_XTS); 3546ab03daeSAlexey Marchuk DEVX_SET(encryption_key_obj, dek_in, pd, pdn); 3556ab03daeSAlexey Marchuk memcpy(DEVX_ADDR_OF(encryption_key_obj, dek_in, opaque), &attr->opaque, sizeof(attr->opaque)); 3566ab03daeSAlexey Marchuk memcpy(DEVX_ADDR_OF(encryption_key_obj, dek_in, key), attr->dek, attr->key_size_bytes); 3576ab03daeSAlexey Marchuk 3586ab03daeSAlexey Marchuk dek->devx_obj = mlx5dv_devx_obj_create(pd->context, in, sizeof(in), out, sizeof(out)); 3596ab03daeSAlexey Marchuk spdk_memset_s(DEVX_ADDR_OF(encryption_key_obj, dek_in, key), attr->key_size_bytes, 0, 3606ab03daeSAlexey Marchuk attr->key_size_bytes); 3616ab03daeSAlexey Marchuk if (!dek->devx_obj) { 3626ab03daeSAlexey Marchuk return -errno; 3636ab03daeSAlexey Marchuk } 3646ab03daeSAlexey Marchuk dek->dek_obj_id = DEVX_GET(general_obj_out_cmd_hdr, out, obj_id); 3656ab03daeSAlexey Marchuk 3666ab03daeSAlexey Marchuk return 0; 3676ab03daeSAlexey Marchuk } 3686ab03daeSAlexey Marchuk 3696ab03daeSAlexey Marchuk static int 3706ab03daeSAlexey Marchuk mlx5_crypto_dek_query(struct mlx5_crypto_dek *dek, struct mlx5_crypto_dek_query_attr *attr) 3716ab03daeSAlexey Marchuk { 3726ab03daeSAlexey Marchuk uint32_t out[DEVX_ST_SZ_DW(query_encryption_key_obj_out)] = {}; 3736ab03daeSAlexey Marchuk uint32_t in[DEVX_ST_SZ_DW(general_obj_in_cmd_hdr)] = {}; 3746ab03daeSAlexey Marchuk uint8_t *dek_out; 3756ab03daeSAlexey Marchuk int rc; 3766ab03daeSAlexey Marchuk 3776ab03daeSAlexey Marchuk assert(attr); 3786ab03daeSAlexey Marchuk DEVX_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_QUERY_GENERAL_OBJECT); 3796ab03daeSAlexey Marchuk DEVX_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_DEK); 3806ab03daeSAlexey Marchuk DEVX_SET(general_obj_in_cmd_hdr, in, obj_id, dek->dek_obj_id); 3816ab03daeSAlexey Marchuk 3826ab03daeSAlexey Marchuk rc = mlx5dv_devx_obj_query(dek->devx_obj, in, sizeof(in), out, sizeof(out)); 3836ab03daeSAlexey Marchuk if (rc) { 3846ab03daeSAlexey Marchuk return rc; 3856ab03daeSAlexey Marchuk } 3866ab03daeSAlexey Marchuk 3876ab03daeSAlexey Marchuk dek_out = DEVX_ADDR_OF(query_encryption_key_obj_out, out, obj); 3886ab03daeSAlexey Marchuk attr->state = DEVX_GET(encryption_key_obj, dek_out, state); 3896ab03daeSAlexey Marchuk memcpy(&attr->opaque, DEVX_ADDR_OF(encryption_key_obj, dek_out, opaque), sizeof(attr->opaque)); 3906ab03daeSAlexey Marchuk 3916ab03daeSAlexey Marchuk return 0; 3926ab03daeSAlexey Marchuk } 3936ab03daeSAlexey Marchuk 394a1dfa7ecSAlexey Marchuk int 395a1dfa7ecSAlexey Marchuk spdk_mlx5_crypto_keytag_create(struct spdk_mlx5_crypto_dek_create_attr *attr, 396a1dfa7ecSAlexey Marchuk struct spdk_mlx5_crypto_keytag **out) 397a1dfa7ecSAlexey Marchuk { 3986ab03daeSAlexey Marchuk struct mlx5_crypto_dek *dek; 399a1dfa7ecSAlexey Marchuk struct spdk_mlx5_crypto_keytag *keytag; 400a1dfa7ecSAlexey Marchuk struct ibv_context **devs; 4016ab03daeSAlexey Marchuk struct ibv_pd *pd; 4026ab03daeSAlexey Marchuk struct mlx5_crypto_dek_init_attr dek_attr = {}; 4036ab03daeSAlexey Marchuk struct mlx5_crypto_dek_query_attr query_attr; 4046ab03daeSAlexey Marchuk struct spdk_mlx5_device_caps dev_caps; 405a1dfa7ecSAlexey Marchuk int num_devs = 0, i, rc; 406a1dfa7ecSAlexey Marchuk 4076ab03daeSAlexey Marchuk dek_attr.dek = attr->dek; 4086ab03daeSAlexey Marchuk dek_attr.key_size_bytes = attr->dek_len; 4096ab03daeSAlexey Marchuk dek_attr.opaque = 0; 4106ab03daeSAlexey Marchuk switch (dek_attr.key_size_bytes) { 411a1dfa7ecSAlexey Marchuk case SPDK_MLX5_AES_XTS_128_DEK_BYTES_WITH_KEYTAG: 4126ab03daeSAlexey Marchuk dek_attr.key_size = MLX5_ENCRYPTION_KEY_OBJ_KEY_SIZE_SIZE_128; 4136ab03daeSAlexey Marchuk dek_attr.keytag = 1; 414a1dfa7ecSAlexey Marchuk SPDK_DEBUGLOG(mlx5, "128b AES_XTS with keytag\n"); 415a1dfa7ecSAlexey Marchuk break; 416a1dfa7ecSAlexey Marchuk case SPDK_MLX5_AES_XTS_256_DEK_BYTES_WITH_KEYTAG: 4176ab03daeSAlexey Marchuk dek_attr.key_size = MLX5_ENCRYPTION_KEY_OBJ_KEY_SIZE_SIZE_256; 4186ab03daeSAlexey Marchuk dek_attr.keytag = 1; 419a1dfa7ecSAlexey Marchuk SPDK_DEBUGLOG(mlx5, "256b AES_XTS with keytag\n"); 420a1dfa7ecSAlexey Marchuk break; 421a1dfa7ecSAlexey Marchuk case SPDK_MLX5_AES_XTS_128_DEK_BYTES: 4226ab03daeSAlexey Marchuk dek_attr.key_size = MLX5_ENCRYPTION_KEY_OBJ_KEY_SIZE_SIZE_128; 4236ab03daeSAlexey Marchuk dek_attr.keytag = 0; 424a1dfa7ecSAlexey Marchuk SPDK_DEBUGLOG(mlx5, "128b AES_XTS\n"); 425a1dfa7ecSAlexey Marchuk break; 426a1dfa7ecSAlexey Marchuk case SPDK_MLX5_AES_XTS_256_DEK_BYTES: 4276ab03daeSAlexey Marchuk dek_attr.key_size = MLX5_ENCRYPTION_KEY_OBJ_KEY_SIZE_SIZE_256; 4286ab03daeSAlexey Marchuk dek_attr.keytag = 0; 429a1dfa7ecSAlexey Marchuk SPDK_DEBUGLOG(mlx5, "256b AES_XTS\n"); 430a1dfa7ecSAlexey Marchuk break; 431a1dfa7ecSAlexey Marchuk default: 432a1dfa7ecSAlexey Marchuk SPDK_ERRLOG("Invalid key length %zu. The following keys are supported:\n" 433a1dfa7ecSAlexey Marchuk "128b key + key2, %u bytes;\n" 434a1dfa7ecSAlexey Marchuk "256b key + key2, %u bytes\n" 435a1dfa7ecSAlexey Marchuk "128b key + key2 + keytag, %u bytes\n" 436a1dfa7ecSAlexey Marchuk "256b lye + key2 + keytag, %u bytes\n", 4376ab03daeSAlexey Marchuk attr->dek_len, SPDK_MLX5_AES_XTS_128_DEK_BYTES, SPDK_MLX5_AES_XTS_256_DEK_BYTES, 438a1dfa7ecSAlexey Marchuk SPDK_MLX5_AES_XTS_128_DEK_BYTES_WITH_KEYTAG, SPDK_MLX5_AES_XTS_256_DEK_BYTES_WITH_KEYTAG); 439a1dfa7ecSAlexey Marchuk return -EINVAL; 440a1dfa7ecSAlexey Marchuk } 441a1dfa7ecSAlexey Marchuk 442a1dfa7ecSAlexey Marchuk devs = spdk_mlx5_crypto_devs_get(&num_devs); 443a1dfa7ecSAlexey Marchuk if (!devs || !num_devs) { 444a1dfa7ecSAlexey Marchuk SPDK_DEBUGLOG(mlx5, "No crypto devices found\n"); 445a1dfa7ecSAlexey Marchuk return -ENOTSUP; 446a1dfa7ecSAlexey Marchuk } 447a1dfa7ecSAlexey Marchuk 448a1dfa7ecSAlexey Marchuk keytag = calloc(1, sizeof(*keytag)); 449a1dfa7ecSAlexey Marchuk if (!keytag) { 450a1dfa7ecSAlexey Marchuk SPDK_ERRLOG("Memory allocation failed\n"); 451a1dfa7ecSAlexey Marchuk spdk_mlx5_crypto_devs_release(devs); 452a1dfa7ecSAlexey Marchuk return -ENOMEM; 453a1dfa7ecSAlexey Marchuk } 4546ab03daeSAlexey Marchuk keytag->deks = calloc(num_devs, sizeof(struct mlx5_crypto_dek)); 455a1dfa7ecSAlexey Marchuk if (!keytag->deks) { 456a1dfa7ecSAlexey Marchuk SPDK_ERRLOG("Memory allocation failed\n"); 457a1dfa7ecSAlexey Marchuk spdk_mlx5_crypto_devs_release(devs); 458a1dfa7ecSAlexey Marchuk free(keytag); 459a1dfa7ecSAlexey Marchuk return -ENOMEM; 460a1dfa7ecSAlexey Marchuk } 461a1dfa7ecSAlexey Marchuk 462a1dfa7ecSAlexey Marchuk for (i = 0; i < num_devs; i++) { 463a1dfa7ecSAlexey Marchuk keytag->deks_num++; 464a1dfa7ecSAlexey Marchuk dek = &keytag->deks[i]; 4656ab03daeSAlexey Marchuk pd = spdk_rdma_utils_get_pd(devs[i]); 4666ab03daeSAlexey Marchuk if (!pd) { 467a1dfa7ecSAlexey Marchuk SPDK_ERRLOG("Failed to get PD on device %s\n", devs[i]->device->name); 468a1dfa7ecSAlexey Marchuk rc = -EINVAL; 469a1dfa7ecSAlexey Marchuk goto err_out; 470a1dfa7ecSAlexey Marchuk } 471a1dfa7ecSAlexey Marchuk 4726ab03daeSAlexey Marchuk memset(&dev_caps, 0, sizeof(dev_caps)); 4736ab03daeSAlexey Marchuk rc = spdk_mlx5_device_query_caps(devs[i], &dev_caps); 474a1dfa7ecSAlexey Marchuk if (rc) { 4756ab03daeSAlexey Marchuk SPDK_ERRLOG("Failed to get device %s crypto caps\n", devs[i]->device->name); 476a1dfa7ecSAlexey Marchuk goto err_out; 477a1dfa7ecSAlexey Marchuk } 4786ab03daeSAlexey Marchuk rc = mlx5_crypto_dek_init(pd, &dek_attr, dek); 4796ab03daeSAlexey Marchuk if (rc) { 4806ab03daeSAlexey Marchuk SPDK_ERRLOG("Failed to create DEK on dev %s, rc %d\n", pd->context->device->name, rc); 4816ab03daeSAlexey Marchuk goto err_out; 4826ab03daeSAlexey Marchuk } 4836ab03daeSAlexey Marchuk memset(&query_attr, 0, sizeof(query_attr)); 4846ab03daeSAlexey Marchuk rc = mlx5_crypto_dek_query(dek, &query_attr); 4856ab03daeSAlexey Marchuk if (rc) { 4866ab03daeSAlexey Marchuk SPDK_ERRLOG("Failed to query DEK on dev %s, rc %d\n", pd->context->device->name, rc); 4876ab03daeSAlexey Marchuk goto err_out; 4886ab03daeSAlexey Marchuk } 4896ab03daeSAlexey Marchuk if (query_attr.opaque != 0 || query_attr.state != MLX5_ENCRYPTION_KEY_OBJ_STATE_READY) { 4906ab03daeSAlexey Marchuk SPDK_ERRLOG("DEK on dev %s in bad state %d, oapque %"PRIu64"\n", pd->context->device->name, 4916ab03daeSAlexey Marchuk query_attr.state, query_attr.opaque); 492a1dfa7ecSAlexey Marchuk rc = -EINVAL; 493a1dfa7ecSAlexey Marchuk goto err_out; 494a1dfa7ecSAlexey Marchuk } 4956ab03daeSAlexey Marchuk 4966ab03daeSAlexey Marchuk dek->pd = pd; 4976ab03daeSAlexey Marchuk dek->context = devs[i]; 4986ab03daeSAlexey Marchuk dek->tweak_mode = dev_caps.crypto.multi_block_be_tweak ? 4996ab03daeSAlexey Marchuk SPDK_MLX5_CRYPTO_KEY_TWEAK_MODE_SIMPLE_LBA_BE : SPDK_MLX5_CRYPTO_KEY_TWEAK_MODE_SIMPLE_LBA_LE; 5006ab03daeSAlexey Marchuk } 5016ab03daeSAlexey Marchuk 5026ab03daeSAlexey Marchuk if (dek_attr.keytag) { 503a1dfa7ecSAlexey Marchuk /* Save keytag, it will be used to configure crypto MKEY */ 504a1dfa7ecSAlexey Marchuk keytag->has_keytag = true; 505a1dfa7ecSAlexey Marchuk memcpy(keytag->keytag, attr->dek + attr->dek_len - SPDK_MLX5_AES_XTS_KEYTAG_SIZE, 506a1dfa7ecSAlexey Marchuk SPDK_MLX5_AES_XTS_KEYTAG_SIZE); 507a1dfa7ecSAlexey Marchuk } 508a1dfa7ecSAlexey Marchuk 509a1dfa7ecSAlexey Marchuk spdk_mlx5_crypto_devs_release(devs); 510a1dfa7ecSAlexey Marchuk *out = keytag; 511a1dfa7ecSAlexey Marchuk 512a1dfa7ecSAlexey Marchuk return 0; 513a1dfa7ecSAlexey Marchuk 514a1dfa7ecSAlexey Marchuk err_out: 515a1dfa7ecSAlexey Marchuk spdk_mlx5_crypto_keytag_destroy(keytag); 516a1dfa7ecSAlexey Marchuk spdk_mlx5_crypto_devs_release(devs); 517a1dfa7ecSAlexey Marchuk 518a1dfa7ecSAlexey Marchuk return rc; 519a1dfa7ecSAlexey Marchuk } 520a1dfa7ecSAlexey Marchuk 5216ab03daeSAlexey Marchuk static inline struct mlx5_crypto_dek * 522a1dfa7ecSAlexey Marchuk mlx5_crypto_get_dek_by_pd(struct spdk_mlx5_crypto_keytag *keytag, struct ibv_pd *pd) 523a1dfa7ecSAlexey Marchuk { 5246ab03daeSAlexey Marchuk struct mlx5_crypto_dek *dek; 525a1dfa7ecSAlexey Marchuk uint32_t i; 526a1dfa7ecSAlexey Marchuk 527a1dfa7ecSAlexey Marchuk for (i = 0; i < keytag->deks_num; i++) { 528a1dfa7ecSAlexey Marchuk dek = &keytag->deks[i]; 529a1dfa7ecSAlexey Marchuk if (dek->pd == pd) { 530a1dfa7ecSAlexey Marchuk return dek; 531a1dfa7ecSAlexey Marchuk } 532a1dfa7ecSAlexey Marchuk } 533a1dfa7ecSAlexey Marchuk 534a1dfa7ecSAlexey Marchuk return NULL; 535a1dfa7ecSAlexey Marchuk } 536a1dfa7ecSAlexey Marchuk 537a1dfa7ecSAlexey Marchuk int 5386ab03daeSAlexey Marchuk spdk_mlx5_crypto_get_dek_data(struct spdk_mlx5_crypto_keytag *keytag, struct ibv_pd *pd, 5396ab03daeSAlexey Marchuk struct spdk_mlx5_crypto_dek_data *data) 5406ab03daeSAlexey Marchuk { 5416ab03daeSAlexey Marchuk struct mlx5_crypto_dek *dek; 5426ab03daeSAlexey Marchuk 5436ab03daeSAlexey Marchuk dek = mlx5_crypto_get_dek_by_pd(keytag, pd); 5446ab03daeSAlexey Marchuk if (spdk_unlikely(!dek)) { 5456ab03daeSAlexey Marchuk SPDK_ERRLOG("No DEK for pd %p (dev %s)\n", pd, pd->context->device->name); 5466ab03daeSAlexey Marchuk return -EINVAL; 5476ab03daeSAlexey Marchuk } 5486ab03daeSAlexey Marchuk data->dek_obj_id = dek->dek_obj_id; 5496ab03daeSAlexey Marchuk data->tweak_mode = dek->tweak_mode; 5506ab03daeSAlexey Marchuk 5516ab03daeSAlexey Marchuk return 0; 5526ab03daeSAlexey Marchuk } 5536ab03daeSAlexey Marchuk 554a1dfa7ecSAlexey Marchuk SPDK_LOG_REGISTER_COMPONENT(mlx5) 555