xref: /spdk/lib/mlx5/mlx5_crypto.c (revision 9bdeb23a42ecfa6fbcdbf952595406cedc2b28de)
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