xref: /spdk/lib/mlx5/mlx5_crypto.c (revision c6c1234de9e0015e670dd0b51bf6ce39ee0e07bd)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  */
4 
5 #include <rdma/rdma_cma.h>
6 #include <infiniband/verbs.h>
7 #include <infiniband/mlx5dv.h>
8 
9 #include "spdk/stdinc.h"
10 #include "spdk/queue.h"
11 #include "spdk/log.h"
12 #include "spdk/likely.h"
13 #include "spdk/util.h"
14 #include "spdk_internal/mlx5.h"
15 #include "spdk_internal/rdma_utils.h"
16 #include "mlx5_ifc.h"
17 #include "mlx5_priv.h"
18 
19 /* Plaintext key sizes */
20 /* 64b keytag */
21 #define SPDK_MLX5_AES_XTS_KEYTAG_SIZE 8
22 /* key1_128b + key2_128b */
23 #define SPDK_MLX5_AES_XTS_128_DEK_BYTES 32
24 /* key1_256b + key2_256b */
25 #define SPDK_MLX5_AES_XTS_256_DEK_BYTES 64
26 /* key1_128b + key2_128b + 64b_keytag */
27 #define SPDK_MLX5_AES_XTS_128_DEK_BYTES_WITH_KEYTAG (SPDK_MLX5_AES_XTS_128_DEK_BYTES + SPDK_MLX5_AES_XTS_KEYTAG_SIZE)
28 /* key1_256b + key2_256b + 64b_keytag */
29 #define SPDK_MLX5_AES_XTS_256_DEK_BYTES_WITH_KEYTAG (SPDK_MLX5_AES_XTS_256_DEK_BYTES + SPDK_MLX5_AES_XTS_KEYTAG_SIZE)
30 
31 struct mlx5_crypto_dek_init_attr {
32 	char *dek;
33 	uint64_t opaque;
34 	uint32_t key_size_bytes;
35 	uint8_t key_size; /* driver representation of \b key_size_bytes */
36 	uint8_t keytag;
37 };
38 
39 struct mlx5_crypto_dek_query_attr {
40 	/* state either MLX5_ENCRYPTION_KEY_OBJ_STATE_READY or MLX5_ENCRYPTION_KEY_OBJ_STATE_ERROR */
41 	uint8_t state;
42 	uint64_t opaque;
43 };
44 
45 struct spdk_mlx5_crypto_dek_legacy {
46 	struct mlx5dv_dek *dek_obj;
47 	struct ibv_pd *pd;
48 	struct ibv_context *context;
49 };
50 
51 struct mlx5_crypto_dek {
52 	struct mlx5dv_devx_obj *devx_obj;
53 	struct ibv_pd *pd;
54 	struct ibv_context *context;
55 	/* Cached dek_obj_id */
56 	uint32_t dek_obj_id;
57 	enum spdk_mlx5_crypto_key_tweak_mode tweak_mode;
58 };
59 
60 struct spdk_mlx5_crypto_keytag {
61 	struct mlx5_crypto_dek *deks;
62 	struct spdk_mlx5_crypto_dek_legacy *deks_legacy;
63 	uint32_t deks_num;
64 	bool has_keytag;
65 	char keytag[8];
66 };
67 
68 static char **g_allowed_devices;
69 static size_t g_allowed_devices_count;
70 
71 static void
72 mlx5_crypto_devs_free(void)
73 {
74 	size_t i;
75 
76 	if (!g_allowed_devices) {
77 		return;
78 	}
79 
80 	for (i = 0; i < g_allowed_devices_count; i++) {
81 		free(g_allowed_devices[i]);
82 	}
83 	free(g_allowed_devices);
84 	g_allowed_devices = NULL;
85 	g_allowed_devices_count = 0;
86 }
87 
88 static bool
89 mlx5_crypto_dev_allowed(const char *dev)
90 {
91 	size_t i;
92 
93 	if (!g_allowed_devices || !g_allowed_devices_count) {
94 		return true;
95 	}
96 
97 	for (i = 0; i < g_allowed_devices_count; i++) {
98 		if (strcmp(g_allowed_devices[i], dev) == 0) {
99 			return true;
100 		}
101 	}
102 
103 	return false;
104 }
105 
106 int
107 spdk_mlx5_crypto_devs_allow(const char *const dev_names[], size_t devs_count)
108 {
109 	size_t i;
110 
111 	mlx5_crypto_devs_free();
112 
113 	if (!dev_names || !devs_count) {
114 		return 0;
115 	}
116 
117 	g_allowed_devices = calloc(devs_count, sizeof(char *));
118 	if (!g_allowed_devices) {
119 		return -ENOMEM;
120 	}
121 	for (i = 0; i < devs_count; i++) {
122 		g_allowed_devices[i] = strndup(dev_names[i], SPDK_MLX5_DEV_MAX_NAME_LEN);
123 		if (!g_allowed_devices[i]) {
124 			mlx5_crypto_devs_free();
125 			return -ENOMEM;
126 		}
127 		g_allowed_devices_count++;
128 	}
129 
130 	return 0;
131 }
132 
133 struct ibv_context **
134 spdk_mlx5_crypto_devs_get(int *dev_num)
135 {
136 	struct ibv_context **rdma_devs, **rdma_devs_out = NULL, *dev;
137 	struct ibv_device_attr dev_attr;
138 	struct ibv_port_attr port_attr;
139 	struct spdk_mlx5_device_caps dev_caps;
140 	uint8_t in[DEVX_ST_SZ_BYTES(query_nic_vport_context_in)];
141 	uint8_t out[DEVX_ST_SZ_BYTES(query_nic_vport_context_out)];
142 	uint8_t devx_v;
143 	int num_rdma_devs = 0, i, rc;
144 	int num_crypto_devs = 0;
145 
146 	/* query all devices, save mlx5 with crypto support */
147 	rdma_devs = rdma_get_devices(&num_rdma_devs);
148 	if (!rdma_devs || !num_rdma_devs) {
149 		*dev_num = 0;
150 		return NULL;
151 	}
152 
153 	rdma_devs_out = calloc(num_rdma_devs + 1, sizeof(*rdma_devs_out));
154 	if (!rdma_devs_out) {
155 		SPDK_ERRLOG("Memory allocation failed\n");
156 		return NULL;
157 	}
158 
159 	for (i = 0; i < num_rdma_devs; i++) {
160 		dev = rdma_devs[i];
161 		rc = ibv_query_device(dev, &dev_attr);
162 		if (rc) {
163 			SPDK_ERRLOG("Failed to query dev %s, skipping\n", dev->device->name);
164 			continue;
165 		}
166 		if (dev_attr.vendor_id != SPDK_MLX5_VENDOR_ID_MELLANOX) {
167 			SPDK_DEBUGLOG(mlx5, "dev %s is not Mellanox device, skipping\n", dev->device->name);
168 			continue;
169 		}
170 
171 		if (!mlx5_crypto_dev_allowed(dev->device->name)) {
172 			continue;
173 		}
174 
175 		rc = ibv_query_port(dev, 1, &port_attr);
176 		if (rc) {
177 			SPDK_ERRLOG("Failed to query port attributes for device %s, rc %d\n", dev->device->name, rc);
178 			continue;
179 		}
180 
181 		if (port_attr.link_layer == IBV_LINK_LAYER_ETHERNET) {
182 			/* Port may be ethernet but roce is still disabled */
183 			memset(in, 0, sizeof(in));
184 			memset(out, 0, sizeof(out));
185 			DEVX_SET(query_nic_vport_context_in, in, opcode, MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT);
186 			rc = mlx5dv_devx_general_cmd(dev, in, sizeof(in), out, sizeof(out));
187 			if (rc) {
188 				SPDK_ERRLOG("Failed to get VPORT context for device %s. Assuming ROCE is disabled\n",
189 					    dev->device->name);
190 				continue;
191 			}
192 
193 			devx_v = DEVX_GET(query_nic_vport_context_out, out, nic_vport_context.roce_en);
194 			if (!devx_v) {
195 				SPDK_ERRLOG("Device %s, RoCE disabled\n", dev->device->name);
196 				continue;
197 			}
198 		}
199 
200 		memset(&dev_caps, 0, sizeof(dev_caps));
201 		rc = spdk_mlx5_device_query_caps(dev, &dev_caps);
202 		if (rc) {
203 			SPDK_ERRLOG("Failed to query mlx5 dev %s, skipping\n", dev->device->name);
204 			continue;
205 		}
206 		if (!dev_caps.crypto_supported) {
207 			SPDK_WARNLOG("dev %s crypto engine doesn't support crypto\n", dev->device->name);
208 			continue;
209 		}
210 		if (!(dev_caps.crypto.single_block_le_tweak || dev_caps.crypto.multi_block_le_tweak ||
211 		      dev_caps.crypto.multi_block_be_tweak)) {
212 			SPDK_WARNLOG("dev %s crypto engine doesn't support AES_XTS\n", dev->device->name);
213 			continue;
214 		}
215 		if (dev_caps.crypto.wrapped_import_method_aes_xts) {
216 			SPDK_WARNLOG("dev %s uses wrapped import method which is not supported by mlx5 lib\n",
217 				     dev->device->name);
218 			continue;
219 		}
220 
221 		rdma_devs_out[num_crypto_devs++] = dev;
222 	}
223 
224 	if (!num_crypto_devs) {
225 		SPDK_DEBUGLOG(mlx5, "Found no mlx5 crypto devices\n");
226 		goto err_out;
227 	}
228 
229 	rdma_free_devices(rdma_devs);
230 	*dev_num = num_crypto_devs;
231 
232 	return rdma_devs_out;
233 
234 err_out:
235 	free(rdma_devs_out);
236 	rdma_free_devices(rdma_devs);
237 	*dev_num = 0;
238 	return NULL;
239 }
240 
241 void
242 spdk_mlx5_crypto_devs_release(struct ibv_context **rdma_devs)
243 {
244 	if (rdma_devs) {
245 		free(rdma_devs);
246 	}
247 }
248 
249 int
250 spdk_mlx5_device_query_caps(struct ibv_context *context, struct spdk_mlx5_device_caps *caps)
251 {
252 	uint16_t opmod = MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE |
253 			 HCA_CAP_OPMOD_GET_CUR;
254 	uint32_t out[DEVX_ST_SZ_DW(query_hca_cap_out)] = {};
255 	uint32_t in[DEVX_ST_SZ_DW(query_hca_cap_in)] = {};
256 	int rc;
257 
258 	DEVX_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP);
259 	DEVX_SET(query_hca_cap_in, in, op_mod, opmod);
260 
261 	rc = mlx5dv_devx_general_cmd(context, in, sizeof(in), out, sizeof(out));
262 	if (rc) {
263 		return rc;
264 	}
265 
266 	caps->crypto_supported = DEVX_GET(query_hca_cap_out, out, capability.cmd_hca_cap.crypto);
267 	if (!caps->crypto_supported) {
268 		return 0;
269 	}
270 
271 	caps->crypto.single_block_le_tweak = DEVX_GET(query_hca_cap_out,
272 					     out, capability.cmd_hca_cap.aes_xts_single_block_le_tweak);
273 	caps->crypto.multi_block_be_tweak = DEVX_GET(query_hca_cap_out, out,
274 					    capability.cmd_hca_cap.aes_xts_multi_block_be_tweak);
275 	caps->crypto.multi_block_le_tweak = DEVX_GET(query_hca_cap_out, out,
276 					    capability.cmd_hca_cap.aes_xts_multi_block_le_tweak);
277 
278 	opmod = MLX5_SET_HCA_CAP_OP_MOD_CRYPTO | HCA_CAP_OPMOD_GET_CUR;
279 	memset(&out, 0, sizeof(out));
280 	memset(&in, 0, sizeof(in));
281 
282 	DEVX_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP);
283 	DEVX_SET(query_hca_cap_in, in, op_mod, opmod);
284 
285 	rc = mlx5dv_devx_general_cmd(context, in, sizeof(in), out, sizeof(out));
286 	if (rc) {
287 		return rc;
288 	}
289 
290 	caps->crypto.wrapped_crypto_operational = DEVX_GET(query_hca_cap_out, out,
291 			capability.crypto_caps.wrapped_crypto_operational);
292 	caps->crypto.wrapped_crypto_going_to_commissioning = DEVX_GET(query_hca_cap_out, out,
293 			capability.crypto_caps .wrapped_crypto_going_to_commissioning);
294 	caps->crypto.wrapped_import_method_aes_xts = (DEVX_GET(query_hca_cap_out, out,
295 			capability.crypto_caps.wrapped_import_method) &
296 			MLX5_CRYPTO_CAPS_WRAPPED_IMPORT_METHOD_AES) != 0;
297 
298 	return 0;
299 }
300 
301 static void
302 mlx5_crypto_dek_deinit(struct mlx5_crypto_dek *dek)
303 {
304 	int rc;
305 
306 	rc = mlx5dv_devx_obj_destroy(dek->devx_obj);
307 	if (rc) {
308 		SPDK_ERRLOG("Failed to destroy crypto obj:%p, rc %d\n", dek->devx_obj, rc);
309 	}
310 }
311 
312 void
313 spdk_mlx5_crypto_keytag_destroy(struct spdk_mlx5_crypto_keytag *keytag)
314 {
315 	struct mlx5_crypto_dek *dek;
316 	uint32_t i;
317 
318 	if (!keytag) {
319 		return;
320 	}
321 
322 	for (i = 0; i < keytag->deks_num; i++) {
323 		dek = &keytag->deks[i];
324 		if (dek->devx_obj) {
325 			mlx5_crypto_dek_deinit(dek);
326 		}
327 		if (dek->pd) {
328 			spdk_rdma_utils_put_pd(dek->pd);
329 		}
330 
331 		if (keytag->deks_legacy[i].dek_obj) {
332 			mlx5dv_dek_destroy(keytag->deks_legacy[i].dek_obj);
333 		}
334 
335 	}
336 	spdk_memset_s(keytag->keytag, sizeof(keytag->keytag), 0, sizeof(keytag->keytag));
337 	free(keytag->deks_legacy);
338 	free(keytag->deks);
339 	free(keytag);
340 }
341 
342 static int
343 mlx5_crypto_dek_init(struct ibv_pd *pd, struct mlx5_crypto_dek_init_attr *attr,
344 		     struct mlx5_crypto_dek *dek)
345 {
346 	uint32_t in[DEVX_ST_SZ_DW(create_encryption_key_obj_in)] = {};
347 	uint32_t out[DEVX_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
348 	uint8_t *dek_in;
349 	uint32_t pdn;
350 	int rc;
351 
352 	rc = mlx5_get_pd_id(pd, &pdn);
353 	if (rc) {
354 		return rc;
355 	}
356 
357 	dek_in = DEVX_ADDR_OF(create_encryption_key_obj_in, in, hdr);
358 	DEVX_SET(general_obj_in_cmd_hdr, dek_in, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
359 	DEVX_SET(general_obj_in_cmd_hdr, dek_in, obj_type, MLX5_OBJ_TYPE_DEK);
360 	dek_in = DEVX_ADDR_OF(create_encryption_key_obj_in, in, key_obj);
361 	DEVX_SET(encryption_key_obj, dek_in, key_size, attr->key_size);
362 	DEVX_SET(encryption_key_obj, dek_in, has_keytag, attr->keytag);
363 	DEVX_SET(encryption_key_obj, dek_in, key_purpose, MLX5_ENCRYPTION_KEY_OBJ_KEY_PURPOSE_AES_XTS);
364 	DEVX_SET(encryption_key_obj, dek_in, pd, pdn);
365 	memcpy(DEVX_ADDR_OF(encryption_key_obj, dek_in, opaque), &attr->opaque, sizeof(attr->opaque));
366 	memcpy(DEVX_ADDR_OF(encryption_key_obj, dek_in, key), attr->dek, attr->key_size_bytes);
367 
368 	dek->devx_obj = mlx5dv_devx_obj_create(pd->context, in, sizeof(in), out, sizeof(out));
369 	spdk_memset_s(DEVX_ADDR_OF(encryption_key_obj, dek_in, key), attr->key_size_bytes, 0,
370 		      attr->key_size_bytes);
371 	if (!dek->devx_obj) {
372 		return -errno;
373 	}
374 	dek->dek_obj_id = DEVX_GET(general_obj_out_cmd_hdr, out, obj_id);
375 
376 	return 0;
377 }
378 
379 static int
380 mlx5_crypto_dek_query(struct mlx5_crypto_dek *dek, struct mlx5_crypto_dek_query_attr *attr)
381 {
382 	uint32_t out[DEVX_ST_SZ_DW(query_encryption_key_obj_out)] = {};
383 	uint32_t in[DEVX_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
384 	uint8_t *dek_out;
385 	int rc;
386 
387 	assert(attr);
388 	DEVX_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_QUERY_GENERAL_OBJECT);
389 	DEVX_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_DEK);
390 	DEVX_SET(general_obj_in_cmd_hdr, in, obj_id, dek->dek_obj_id);
391 
392 	rc = mlx5dv_devx_obj_query(dek->devx_obj, in, sizeof(in), out, sizeof(out));
393 	if (rc) {
394 		return rc;
395 	}
396 
397 	dek_out = DEVX_ADDR_OF(query_encryption_key_obj_out, out, obj);
398 	attr->state = DEVX_GET(encryption_key_obj, dek_out, state);
399 	memcpy(&attr->opaque, DEVX_ADDR_OF(encryption_key_obj, dek_out, opaque), sizeof(attr->opaque));
400 
401 	return 0;
402 }
403 
404 static int
405 mlx5_crypto_dek_create_legacy(struct spdk_mlx5_crypto_dek_legacy *dek,
406 			      struct mlx5dv_dek_init_attr *init_attr_legacy)
407 {
408 	struct mlx5dv_dek_attr query_attr_legacy;
409 	int rc;
410 
411 	init_attr_legacy->pd = dek->pd;
412 
413 	dek->dek_obj = mlx5dv_dek_create(dek->context, init_attr_legacy);
414 	if (!dek->dek_obj) {
415 		SPDK_ERRLOG("mlx5dv_dek_create failed on dev %s, errno %d\n", dek->context->device->name, errno);
416 		return -EINVAL;
417 	}
418 
419 	rc = mlx5dv_dek_query(dek->dek_obj, &query_attr_legacy);
420 	if (rc) {
421 		SPDK_ERRLOG("Failed to query DEK on dev %s, rc %d\n", dek->context->device->name, rc);
422 		return rc;
423 	}
424 	if (query_attr_legacy.state != MLX5DV_DEK_STATE_READY) {
425 		SPDK_ERRLOG("DEK on dev %s state %d\n", dek->context->device->name, query_attr_legacy.state);
426 		return -EINVAL;
427 	}
428 
429 	return 0;
430 }
431 
432 int
433 spdk_mlx5_crypto_keytag_create(struct spdk_mlx5_crypto_dek_create_attr *attr,
434 			       struct spdk_mlx5_crypto_keytag **out)
435 {
436 	struct mlx5_crypto_dek *dek;
437 	struct spdk_mlx5_crypto_keytag *keytag;
438 	struct ibv_context **devs;
439 	struct ibv_pd *pd;
440 	struct mlx5_crypto_dek_init_attr dek_attr = {};
441 	struct mlx5_crypto_dek_query_attr query_attr;
442 	struct mlx5dv_dek_init_attr init_attr_legacy = {};
443 	struct spdk_mlx5_crypto_dek_legacy *dek_legacy;
444 	struct spdk_mlx5_device_caps dev_caps;
445 	int num_devs = 0, i, rc;
446 
447 	dek_attr.dek = attr->dek;
448 	dek_attr.key_size_bytes = attr->dek_len;
449 	dek_attr.opaque = 0;
450 	switch (dek_attr.key_size_bytes) {
451 	case SPDK_MLX5_AES_XTS_128_DEK_BYTES_WITH_KEYTAG:
452 		init_attr_legacy.key_size = MLX5DV_CRYPTO_KEY_SIZE_128;
453 		init_attr_legacy.has_keytag = true;
454 		dek_attr.key_size = MLX5_ENCRYPTION_KEY_OBJ_KEY_SIZE_SIZE_128;
455 		dek_attr.keytag = 1;
456 		SPDK_DEBUGLOG(mlx5, "128b AES_XTS with keytag\n");
457 		break;
458 	case SPDK_MLX5_AES_XTS_256_DEK_BYTES_WITH_KEYTAG:
459 		init_attr_legacy.key_size = MLX5DV_CRYPTO_KEY_SIZE_256;
460 		init_attr_legacy.has_keytag = true;
461 		dek_attr.key_size = MLX5_ENCRYPTION_KEY_OBJ_KEY_SIZE_SIZE_256;
462 		dek_attr.keytag = 1;
463 		SPDK_DEBUGLOG(mlx5, "256b AES_XTS with keytag\n");
464 		break;
465 	case SPDK_MLX5_AES_XTS_128_DEK_BYTES:
466 		init_attr_legacy.key_size = MLX5DV_CRYPTO_KEY_SIZE_128;
467 		init_attr_legacy.has_keytag = false;
468 		dek_attr.key_size = MLX5_ENCRYPTION_KEY_OBJ_KEY_SIZE_SIZE_128;
469 		dek_attr.keytag = 0;
470 		SPDK_DEBUGLOG(mlx5, "128b AES_XTS\n");
471 		break;
472 	case SPDK_MLX5_AES_XTS_256_DEK_BYTES:
473 		init_attr_legacy.key_size = MLX5DV_CRYPTO_KEY_SIZE_256;
474 		init_attr_legacy.has_keytag = false;
475 		dek_attr.key_size = MLX5_ENCRYPTION_KEY_OBJ_KEY_SIZE_SIZE_256;
476 		dek_attr.keytag = 0;
477 		SPDK_DEBUGLOG(mlx5, "256b AES_XTS\n");
478 		break;
479 	default:
480 		SPDK_ERRLOG("Invalid key length %zu. The following keys are supported:\n"
481 			    "128b key + key2, %u bytes;\n"
482 			    "256b key + key2, %u bytes\n"
483 			    "128b key + key2 + keytag, %u bytes\n"
484 			    "256b lye + key2 + keytag, %u bytes\n",
485 			    attr->dek_len, SPDK_MLX5_AES_XTS_128_DEK_BYTES, SPDK_MLX5_AES_XTS_256_DEK_BYTES,
486 			    SPDK_MLX5_AES_XTS_128_DEK_BYTES_WITH_KEYTAG, SPDK_MLX5_AES_XTS_256_DEK_BYTES_WITH_KEYTAG);
487 		return -EINVAL;
488 	}
489 
490 	devs = spdk_mlx5_crypto_devs_get(&num_devs);
491 	if (!devs || !num_devs) {
492 		SPDK_DEBUGLOG(mlx5, "No crypto devices found\n");
493 		return -ENOTSUP;
494 	}
495 
496 	keytag = calloc(1, sizeof(*keytag));
497 	if (!keytag) {
498 		SPDK_ERRLOG("Memory allocation failed\n");
499 		spdk_mlx5_crypto_devs_release(devs);
500 		return -ENOMEM;
501 	}
502 	keytag->deks = calloc(num_devs, sizeof(struct mlx5_crypto_dek));
503 	if (!keytag->deks) {
504 		SPDK_ERRLOG("Memory allocation failed\n");
505 		spdk_mlx5_crypto_devs_release(devs);
506 		free(keytag);
507 		return -ENOMEM;
508 	}
509 
510 	/* Legacy part, to be removed soon */
511 	memcpy(init_attr_legacy.key, attr->dek, attr->dek_len);
512 	keytag->deks_legacy = calloc(num_devs, sizeof(struct spdk_mlx5_crypto_dek_legacy));
513 	if (!keytag->deks_legacy) {
514 		SPDK_ERRLOG("Memory allocation failed\n");
515 		spdk_mlx5_crypto_devs_release(devs);
516 		free(keytag->deks);
517 		free(keytag);
518 		return -ENOMEM;
519 	}
520 	init_attr_legacy.key_purpose = MLX5DV_CRYPTO_KEY_PURPOSE_AES_XTS;
521 	init_attr_legacy.comp_mask = MLX5DV_DEK_INIT_ATTR_CRYPTO_LOGIN;
522 	init_attr_legacy.crypto_login = NULL;
523 
524 	for (i = 0; i < num_devs; i++) {
525 		keytag->deks_num++;
526 		dek = &keytag->deks[i];
527 		pd = spdk_rdma_utils_get_pd(devs[i]);
528 		if (!pd) {
529 			SPDK_ERRLOG("Failed to get PD on device %s\n", devs[i]->device->name);
530 			rc = -EINVAL;
531 			goto err_out;
532 		}
533 
534 		memset(&dev_caps, 0, sizeof(dev_caps));
535 		rc =  spdk_mlx5_device_query_caps(devs[i], &dev_caps);
536 		if (rc) {
537 			SPDK_ERRLOG("Failed to get device %s crypto caps\n", devs[i]->device->name);
538 			goto err_out;
539 		}
540 		rc = mlx5_crypto_dek_init(pd, &dek_attr, dek);
541 		if (rc) {
542 			SPDK_ERRLOG("Failed to create DEK on dev %s, rc %d\n", pd->context->device->name, rc);
543 			goto err_out;
544 		}
545 		memset(&query_attr, 0, sizeof(query_attr));
546 		rc = mlx5_crypto_dek_query(dek, &query_attr);
547 		if (rc) {
548 			SPDK_ERRLOG("Failed to query DEK on dev %s, rc %d\n", pd->context->device->name, rc);
549 			goto err_out;
550 		}
551 		if (query_attr.opaque != 0 || query_attr.state != MLX5_ENCRYPTION_KEY_OBJ_STATE_READY) {
552 			SPDK_ERRLOG("DEK on dev %s in bad state %d, oapque %"PRIu64"\n", pd->context->device->name,
553 				    query_attr.state, query_attr.opaque);
554 			rc = -EINVAL;
555 			goto err_out;
556 		}
557 
558 		dek->pd = pd;
559 		dek->context = devs[i];
560 		dek->tweak_mode = dev_caps.crypto.multi_block_be_tweak ?
561 				  SPDK_MLX5_CRYPTO_KEY_TWEAK_MODE_SIMPLE_LBA_BE : SPDK_MLX5_CRYPTO_KEY_TWEAK_MODE_SIMPLE_LBA_LE;
562 
563 		/* Legacy part, to be removed soon */
564 		dek_legacy = &keytag->deks_legacy[i];
565 		dek_legacy->pd = pd;
566 		dek_legacy->context = devs[i];
567 		rc = mlx5_crypto_dek_create_legacy(dek_legacy, &init_attr_legacy);
568 		if (rc) {
569 			SPDK_ERRLOG("Failed to create legacy DEK on dev %s, rc %d\n", pd->context->device->name, rc);
570 			goto err_out;
571 		}
572 	}
573 
574 	spdk_memset_s(init_attr_legacy.key, sizeof(init_attr_legacy.key), 0, sizeof(init_attr_legacy.key));
575 
576 	if (dek_attr.keytag) {
577 		/* Save keytag, it will be used to configure crypto MKEY */
578 		keytag->has_keytag = true;
579 		memcpy(keytag->keytag, attr->dek + attr->dek_len - SPDK_MLX5_AES_XTS_KEYTAG_SIZE,
580 		       SPDK_MLX5_AES_XTS_KEYTAG_SIZE);
581 	}
582 
583 	spdk_mlx5_crypto_devs_release(devs);
584 	*out = keytag;
585 
586 	return 0;
587 
588 err_out:
589 	spdk_mlx5_crypto_keytag_destroy(keytag);
590 	spdk_mlx5_crypto_devs_release(devs);
591 
592 	return rc;
593 }
594 
595 static inline struct mlx5_crypto_dek *
596 mlx5_crypto_get_dek_by_pd(struct spdk_mlx5_crypto_keytag *keytag, struct ibv_pd *pd)
597 {
598 	struct mlx5_crypto_dek *dek;
599 	uint32_t i;
600 
601 	for (i = 0; i < keytag->deks_num; i++) {
602 		dek = &keytag->deks[i];
603 		if (dek->pd == pd) {
604 			return dek;
605 		}
606 	}
607 
608 	return NULL;
609 }
610 
611 int
612 spdk_mlx5_crypto_get_dek_data(struct spdk_mlx5_crypto_keytag *keytag, struct ibv_pd *pd,
613 			      struct spdk_mlx5_crypto_dek_data *data)
614 {
615 	struct mlx5_crypto_dek *dek;
616 
617 	dek = mlx5_crypto_get_dek_by_pd(keytag, pd);
618 	if (spdk_unlikely(!dek)) {
619 		SPDK_ERRLOG("No DEK for pd %p (dev %s)\n", pd, pd->context->device->name);
620 		return -EINVAL;
621 	}
622 	data->dek_obj_id = dek->dek_obj_id;
623 	data->tweak_mode = dek->tweak_mode;
624 
625 	return 0;
626 }
627 
628 SPDK_LOG_REGISTER_COMPONENT(mlx5)
629