]> git.proxmox.com Git - mirror_zfs.git/blame - module/zfs/qat_crypt.c
SHA256 QAT acceleration
[mirror_zfs.git] / module / zfs / qat_crypt.c
CommitLineData
cf637391
TC
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
38742209
TC
22/*
23 * This file represents the QAT implementation of checksums and encryption.
24 * Internally, QAT shares the same cryptographic instances for both of these
25 * operations, so the code has been combined here. QAT data compression uses
26 * compression instances, so that code is separated into qat_compress.c
27 */
28
cf637391
TC
29#if defined(_KERNEL) && defined(HAVE_QAT)
30#include <linux/slab.h>
31#include <linux/vmalloc.h>
32#include <linux/pagemap.h>
33#include <linux/completion.h>
34#include <sys/zfs_context.h>
35#include <sys/zio_crypt.h>
36#include "lac/cpa_cy_im.h"
38742209 37#include "lac/cpa_cy_common.h"
cf637391
TC
38#include "qat.h"
39
40/*
41 * Max instances in QAT device, each instance is a channel to submit
42 * jobs to QAT hardware, this is only for pre-allocating instance,
43 * and session arrays, the actual number of instances are defined in
44 * the QAT driver's configure file.
45 */
46#define QAT_CRYPT_MAX_INSTANCES 48
47
48#define MAX_PAGE_NUM 1024
49
cf637391
TC
50static Cpa16U inst_num = 0;
51static Cpa16U num_inst = 0;
52static CpaInstanceHandle cy_inst_handles[QAT_CRYPT_MAX_INSTANCES];
38742209
TC
53static boolean_t qat_crypt_init_done = B_FALSE;
54int zfs_qat_encrypt_disable = 0;
55int zfs_qat_checksum_disable = 0;
cf637391
TC
56
57typedef struct cy_callback {
58 CpaBoolean verify_result;
59 struct completion complete;
60} cy_callback_t;
61
62static void
63symcallback(void *p_callback, CpaStatus status, const CpaCySymOp operation,
64 void *op_data, CpaBufferList *buf_list_dst, CpaBoolean verify)
65{
66 cy_callback_t *cb = p_callback;
67
68 if (cb != NULL) {
69 /* indicate that the function has been called */
70 cb->verify_result = verify;
71 complete(&cb->complete);
72 }
73}
74
75boolean_t
76qat_crypt_use_accel(size_t s_len)
77{
38742209
TC
78 return (!zfs_qat_encrypt_disable &&
79 qat_crypt_init_done &&
80 s_len >= QAT_MIN_BUF_SIZE &&
81 s_len <= QAT_MAX_BUF_SIZE);
82}
83
84boolean_t
85qat_checksum_use_accel(size_t s_len)
86{
87 return (!zfs_qat_checksum_disable &&
cf637391
TC
88 qat_crypt_init_done &&
89 s_len >= QAT_MIN_BUF_SIZE &&
90 s_len <= QAT_MAX_BUF_SIZE);
91}
92
93void
94qat_crypt_clean(void)
95{
96 for (Cpa32U i = 0; i < num_inst; i++)
97 cpaCyStopInstance(cy_inst_handles[i]);
98
99 num_inst = 0;
100 qat_crypt_init_done = B_FALSE;
101}
102
103int
104qat_crypt_init(void)
105{
106 Cpa32U i;
107 CpaStatus status = CPA_STATUS_FAIL;
108
109 status = cpaCyGetNumInstances(&num_inst);
110 if (status != CPA_STATUS_SUCCESS)
111 return (-1);
112
113 /* if the user has configured no QAT encryption units just return */
114 if (num_inst == 0)
115 return (0);
116
117 if (num_inst > QAT_CRYPT_MAX_INSTANCES)
118 num_inst = QAT_CRYPT_MAX_INSTANCES;
119
120 status = cpaCyGetInstances(num_inst, &cy_inst_handles[0]);
121 if (status != CPA_STATUS_SUCCESS)
122 return (-1);
123
124 for (i = 0; i < num_inst; i++) {
125 status = cpaCySetAddressTranslation(cy_inst_handles[i],
126 (void *)virt_to_phys);
127 if (status != CPA_STATUS_SUCCESS)
128 goto error;
129
130 status = cpaCyStartInstance(cy_inst_handles[i]);
131 if (status != CPA_STATUS_SUCCESS)
132 goto error;
133 }
134
135 qat_crypt_init_done = B_TRUE;
136 return (0);
137
138error:
139 qat_crypt_clean();
140 return (-1);
141}
142
143void
144qat_crypt_fini(void)
145{
146 if (!qat_crypt_init_done)
147 return;
148
149 qat_crypt_clean();
150}
151
152static CpaStatus
38742209 153qat_init_crypt_session_ctx(qat_encrypt_dir_t dir, CpaInstanceHandle inst_handle,
cf637391
TC
154 CpaCySymSessionCtx **cy_session_ctx, crypto_key_t *key,
155 Cpa64U crypt, Cpa32U aad_len)
156{
157 CpaStatus status = CPA_STATUS_SUCCESS;
158 Cpa32U ctx_size;
159 Cpa32U ciper_algorithm;
160 Cpa32U hash_algorithm;
161 CpaCySymSessionSetupData sd = { 0 };
162
163 if (zio_crypt_table[crypt].ci_crypt_type == ZC_TYPE_CCM) {
164 return (CPA_STATUS_FAIL);
165 } else {
166 ciper_algorithm = CPA_CY_SYM_CIPHER_AES_GCM;
167 hash_algorithm = CPA_CY_SYM_HASH_AES_GCM;
168 }
169
170 sd.cipherSetupData.cipherAlgorithm = ciper_algorithm;
171 sd.cipherSetupData.pCipherKey = key->ck_data;
172 sd.cipherSetupData.cipherKeyLenInBytes = key->ck_length / 8;
173 sd.hashSetupData.hashAlgorithm = hash_algorithm;
174 sd.hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH;
175 sd.hashSetupData.digestResultLenInBytes = ZIO_DATA_MAC_LEN;
176 sd.hashSetupData.authModeSetupData.aadLenInBytes = aad_len;
177 sd.sessionPriority = CPA_CY_PRIORITY_NORMAL;
178 sd.symOperation = CPA_CY_SYM_OP_ALGORITHM_CHAINING;
179 sd.digestIsAppended = CPA_FALSE;
180 sd.verifyDigest = CPA_FALSE;
181
182 if (dir == QAT_ENCRYPT) {
183 sd.cipherSetupData.cipherDirection =
184 CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT;
185 sd.algChainOrder =
186 CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER;
187 } else {
188 ASSERT3U(dir, ==, QAT_DECRYPT);
189 sd.cipherSetupData.cipherDirection =
190 CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT;
191 sd.algChainOrder =
192 CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH;
193 }
194
195 status = cpaCySymSessionCtxGetSize(inst_handle, &sd, &ctx_size);
196 if (status != CPA_STATUS_SUCCESS)
197 return (status);
198
199 status = QAT_PHYS_CONTIG_ALLOC(cy_session_ctx, ctx_size);
200 if (status != CPA_STATUS_SUCCESS)
201 return (status);
202
203 status = cpaCySymInitSession(inst_handle, symcallback, &sd,
204 *cy_session_ctx);
205 if (status != CPA_STATUS_SUCCESS) {
206 QAT_PHYS_CONTIG_FREE(*cy_session_ctx);
207 return (status);
208 }
209
210 return (CPA_STATUS_SUCCESS);
211}
212
213static CpaStatus
38742209
TC
214qat_init_checksum_session_ctx(CpaInstanceHandle inst_handle,
215 CpaCySymSessionCtx **cy_session_ctx, Cpa64U cksum)
216{
217 CpaStatus status = CPA_STATUS_SUCCESS;
218 Cpa32U ctx_size;
219 Cpa32U hash_algorithm;
220 CpaCySymSessionSetupData sd = { 0 };
221
222 /*
223 * ZFS's SHA512 checksum is actually SHA512/256, which uses
224 * a different IV from standard SHA512. QAT does not support
225 * SHA512/256, so we can only support SHA256.
226 */
227 if (cksum == ZIO_CHECKSUM_SHA256)
228 hash_algorithm = CPA_CY_SYM_HASH_SHA256;
229 else
230 return (CPA_STATUS_FAIL);
231
232 sd.sessionPriority = CPA_CY_PRIORITY_NORMAL;
233 sd.symOperation = CPA_CY_SYM_OP_HASH;
234 sd.hashSetupData.hashAlgorithm = hash_algorithm;
235 sd.hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN;
236 sd.hashSetupData.digestResultLenInBytes = sizeof (zio_cksum_t);
237 sd.digestIsAppended = CPA_FALSE;
238 sd.verifyDigest = CPA_FALSE;
239
240 status = cpaCySymSessionCtxGetSize(inst_handle, &sd, &ctx_size);
241 if (status != CPA_STATUS_SUCCESS)
242 return (status);
243
244 status = QAT_PHYS_CONTIG_ALLOC(cy_session_ctx, ctx_size);
245 if (status != CPA_STATUS_SUCCESS)
246 return (status);
247
248 status = cpaCySymInitSession(inst_handle, symcallback, &sd,
249 *cy_session_ctx);
250 if (status != CPA_STATUS_SUCCESS) {
251 QAT_PHYS_CONTIG_FREE(*cy_session_ctx);
252 return (status);
253 }
254
255 return (CPA_STATUS_SUCCESS);
256}
257
258static CpaStatus
259qat_init_cy_buffer_lists(CpaInstanceHandle inst_handle, uint32_t nr_bufs,
cf637391
TC
260 CpaBufferList *src, CpaBufferList *dst)
261{
262 CpaStatus status = CPA_STATUS_SUCCESS;
263 Cpa32U meta_size = 0;
264
265 status = cpaCyBufferListGetMetaSize(inst_handle, nr_bufs, &meta_size);
266 if (status != CPA_STATUS_SUCCESS)
267 return (status);
268
269 src->numBuffers = nr_bufs;
270 status = QAT_PHYS_CONTIG_ALLOC(&src->pPrivateMetaData, meta_size);
271 if (status != CPA_STATUS_SUCCESS)
272 goto error;
273
274 if (src != dst) {
275 dst->numBuffers = nr_bufs;
276 status = QAT_PHYS_CONTIG_ALLOC(&dst->pPrivateMetaData,
277 meta_size);
278 if (status != CPA_STATUS_SUCCESS)
279 goto error;
280 }
281
282 return (CPA_STATUS_SUCCESS);
283
284error:
285 QAT_PHYS_CONTIG_FREE(src->pPrivateMetaData);
286 if (src != dst)
287 QAT_PHYS_CONTIG_FREE(dst->pPrivateMetaData);
288
289 return (status);
290}
291
292int
293qat_crypt(qat_encrypt_dir_t dir, uint8_t *src_buf, uint8_t *dst_buf,
294 uint8_t *aad_buf, uint32_t aad_len, uint8_t *iv_buf, uint8_t *digest_buf,
295 crypto_key_t *key, uint64_t crypt, uint32_t enc_len)
296{
297 CpaStatus status = CPA_STATUS_SUCCESS;
298 Cpa16U i;
299 CpaInstanceHandle cy_inst_handle;
38742209 300 Cpa16U nr_bufs = (enc_len + PAGE_CACHE_SIZE - 1) / PAGE_CACHE_SIZE;
cf637391
TC
301 Cpa32U bytes_left = 0;
302 Cpa8S *in = NULL;
303 Cpa8S *out = NULL;
304 CpaCySymSessionCtx *cy_session_ctx = NULL;
305 cy_callback_t cb;
306 CpaCySymOpData op_data = { 0 };
307 CpaBufferList src_buffer_list = { 0 };
308 CpaBufferList dst_buffer_list = { 0 };
309 CpaFlatBuffer *flat_src_buf_array = NULL;
310 CpaFlatBuffer *flat_src_buf = NULL;
311 CpaFlatBuffer *flat_dst_buf_array = NULL;
312 CpaFlatBuffer *flat_dst_buf = NULL;
313 struct page *in_pages[MAX_PAGE_NUM];
314 struct page *out_pages[MAX_PAGE_NUM];
315 Cpa32S page_num = 0;
38742209
TC
316 Cpa32U in_page_off = 0;
317 Cpa32U out_page_off = 0;
cf637391
TC
318
319 if (dir == QAT_ENCRYPT) {
320 QAT_STAT_BUMP(encrypt_requests);
321 QAT_STAT_INCR(encrypt_total_in_bytes, enc_len);
322 } else {
323 QAT_STAT_BUMP(decrypt_requests);
324 QAT_STAT_INCR(decrypt_total_in_bytes, enc_len);
325 }
326
327 i = atomic_inc_32_nv(&inst_num) % num_inst;
328 cy_inst_handle = cy_inst_handles[i];
329
38742209
TC
330 status = qat_init_crypt_session_ctx(dir, cy_inst_handle,
331 &cy_session_ctx, key, crypt, aad_len);
332 if (status != CPA_STATUS_SUCCESS) {
333 /* don't count CCM as a failure since it's not supported */
334 if (zio_crypt_table[crypt].ci_crypt_type == ZC_TYPE_GCM)
335 QAT_STAT_BUMP(crypt_fails);
cf637391 336 return (status);
38742209 337 }
cf637391 338
38742209
TC
339 status = qat_init_cy_buffer_lists(cy_inst_handle, nr_bufs,
340 &src_buffer_list, &dst_buffer_list);
cf637391
TC
341 if (status != CPA_STATUS_SUCCESS)
342 goto fail;
343
344 status = QAT_PHYS_CONTIG_ALLOC(&flat_src_buf_array,
345 nr_bufs * sizeof (CpaFlatBuffer));
346 if (status != CPA_STATUS_SUCCESS)
347 goto fail;
348 status = QAT_PHYS_CONTIG_ALLOC(&flat_dst_buf_array,
349 nr_bufs * sizeof (CpaFlatBuffer));
350 if (status != CPA_STATUS_SUCCESS)
351 goto fail;
352
353 bytes_left = enc_len;
354 in = src_buf;
355 out = dst_buf;
356 flat_src_buf = flat_src_buf_array;
357 flat_dst_buf = flat_dst_buf_array;
358 while (bytes_left > 0) {
38742209
TC
359 in_page_off = ((long)in & ~PAGE_MASK);
360 out_page_off = ((long)out & ~PAGE_MASK);
cf637391
TC
361 in_pages[page_num] = qat_mem_to_page(in);
362 out_pages[page_num] = qat_mem_to_page(out);
38742209
TC
363 flat_src_buf->pData = kmap(in_pages[page_num]) + in_page_off;
364 flat_dst_buf->pData = kmap(out_pages[page_num]) + out_page_off;
365 flat_src_buf->dataLenInBytes =
366 min((long)PAGE_CACHE_SIZE - in_page_off, (long)bytes_left);
367 flat_dst_buf->dataLenInBytes =
368 min((long)PAGE_CACHE_SIZE - out_page_off, (long)bytes_left);
cf637391
TC
369 in += flat_src_buf->dataLenInBytes;
370 out += flat_dst_buf->dataLenInBytes;
371 bytes_left -= flat_src_buf->dataLenInBytes;
372 flat_src_buf++;
373 flat_dst_buf++;
374 page_num++;
375 }
376 src_buffer_list.pBuffers = flat_src_buf_array;
377 dst_buffer_list.pBuffers = flat_dst_buf_array;
378
379 op_data.sessionCtx = cy_session_ctx;
380 op_data.packetType = CPA_CY_SYM_PACKET_TYPE_FULL;
381 op_data.pIv = NULL; /* set this later as the J0 block */
382 op_data.ivLenInBytes = 0;
383 op_data.cryptoStartSrcOffsetInBytes = 0;
384 op_data.messageLenToCipherInBytes = 0;
385 op_data.hashStartSrcOffsetInBytes = 0;
386 op_data.messageLenToHashInBytes = 0;
387 op_data.pDigestResult = 0;
388 op_data.messageLenToCipherInBytes = enc_len;
389 op_data.ivLenInBytes = ZIO_DATA_IV_LEN;
390 op_data.pDigestResult = digest_buf;
391 op_data.pAdditionalAuthData = aad_buf;
392 op_data.pIv = iv_buf;
393
394 cb.verify_result = CPA_FALSE;
395 init_completion(&cb.complete);
396 status = cpaCySymPerformOp(cy_inst_handle, &cb, &op_data,
397 &src_buffer_list, &dst_buffer_list, NULL);
398 if (status != CPA_STATUS_SUCCESS)
399 goto fail;
400
401 if (!wait_for_completion_interruptible_timeout(&cb.complete,
402 QAT_TIMEOUT_MS)) {
403 status = CPA_STATUS_FAIL;
404 goto fail;
405 }
406
407 if (cb.verify_result == CPA_FALSE) {
408 status = CPA_STATUS_FAIL;
409 goto fail;
410 }
411
412 if (dir == QAT_ENCRYPT)
413 QAT_STAT_INCR(encrypt_total_out_bytes, enc_len);
414 else
415 QAT_STAT_INCR(decrypt_total_out_bytes, enc_len);
416
417fail:
38742209 418 if (status != CPA_STATUS_SUCCESS)
cf637391
TC
419 QAT_STAT_BUMP(crypt_fails);
420
38742209 421 for (i = 0; i < page_num; i++) {
cf637391
TC
422 kunmap(in_pages[i]);
423 kunmap(out_pages[i]);
424 }
425
426 cpaCySymRemoveSession(cy_inst_handle, cy_session_ctx);
427 QAT_PHYS_CONTIG_FREE(src_buffer_list.pPrivateMetaData);
428 QAT_PHYS_CONTIG_FREE(dst_buffer_list.pPrivateMetaData);
429 QAT_PHYS_CONTIG_FREE(cy_session_ctx);
430 QAT_PHYS_CONTIG_FREE(flat_src_buf_array);
431 QAT_PHYS_CONTIG_FREE(flat_dst_buf_array);
432
433 return (status);
434}
435
38742209
TC
436int
437qat_checksum(uint64_t cksum, uint8_t *buf, uint64_t size, zio_cksum_t *zcp)
438{
439 CpaStatus status;
440 Cpa16U i;
441 CpaInstanceHandle cy_inst_handle;
442 Cpa16U nr_bufs = (size + PAGE_CACHE_SIZE - 1) / PAGE_CACHE_SIZE;
443 Cpa32U bytes_left = 0;
444 Cpa8S *data = NULL;
445 CpaCySymSessionCtx *cy_session_ctx = NULL;
446 cy_callback_t cb;
447 Cpa8U digest_buffer[sizeof (zio_cksum_t)];
448 CpaCySymOpData op_data = { 0 };
449 CpaBufferList src_buffer_list = { 0 };
450 CpaFlatBuffer *flat_src_buf_array = NULL;
451 CpaFlatBuffer *flat_src_buf = NULL;
452 struct page *in_pages[MAX_PAGE_NUM];
453 Cpa32S page_num = 0;
454 Cpa32U page_off = 0;
455
456 QAT_STAT_BUMP(cksum_requests);
457 QAT_STAT_INCR(cksum_total_in_bytes, size);
458
459 i = atomic_inc_32_nv(&inst_num) % num_inst;
460 cy_inst_handle = cy_inst_handles[i];
461
462 status = qat_init_checksum_session_ctx(cy_inst_handle,
463 &cy_session_ctx, cksum);
464 if (status != CPA_STATUS_SUCCESS) {
465 /* don't count unsupported checksums as a failure */
466 if (cksum == ZIO_CHECKSUM_SHA256 ||
467 cksum == ZIO_CHECKSUM_SHA512)
468 QAT_STAT_BUMP(cksum_fails);
469 return (status);
470 }
471
472 status = qat_init_cy_buffer_lists(cy_inst_handle, nr_bufs,
473 &src_buffer_list, &src_buffer_list);
474 if (status != CPA_STATUS_SUCCESS)
475 goto fail;
476
477 status = QAT_PHYS_CONTIG_ALLOC(&flat_src_buf_array,
478 nr_bufs * sizeof (CpaFlatBuffer));
479 if (status != CPA_STATUS_SUCCESS)
480 goto fail;
481
482 bytes_left = size;
483 data = buf;
484 flat_src_buf = flat_src_buf_array;
485 while (bytes_left > 0) {
486 page_off = ((long)data & ~PAGE_MASK);
487 in_pages[page_num] = qat_mem_to_page(data);
488 flat_src_buf->pData = kmap(in_pages[page_num]) + page_off;
489 flat_src_buf->dataLenInBytes =
490 min((long)PAGE_CACHE_SIZE - page_off, (long)bytes_left);
491 data += flat_src_buf->dataLenInBytes;
492 bytes_left -= flat_src_buf->dataLenInBytes;
493 flat_src_buf++;
494 page_num++;
495 }
496 src_buffer_list.pBuffers = flat_src_buf_array;
497
498 op_data.sessionCtx = cy_session_ctx;
499 op_data.packetType = CPA_CY_SYM_PACKET_TYPE_FULL;
500 op_data.hashStartSrcOffsetInBytes = 0;
501 op_data.messageLenToHashInBytes = size;
502 op_data.pDigestResult = digest_buffer;
503
504 cb.verify_result = CPA_FALSE;
505 init_completion(&cb.complete);
506 status = cpaCySymPerformOp(cy_inst_handle, &cb, &op_data,
507 &src_buffer_list, &src_buffer_list, NULL);
508 if (status != CPA_STATUS_SUCCESS)
509 goto fail;
510
511 if (!wait_for_completion_interruptible_timeout(&cb.complete,
512 QAT_TIMEOUT_MS)) {
513 status = CPA_STATUS_FAIL;
514 goto fail;
515 }
516
517 bcopy(digest_buffer, zcp, sizeof (zio_cksum_t));
518
519fail:
520 if (status != CPA_STATUS_SUCCESS)
521 QAT_STAT_BUMP(cksum_fails);
522
523 for (i = 0; i < page_num; i++)
524 kunmap(in_pages[i]);
525
526 cpaCySymRemoveSession(cy_inst_handle, cy_session_ctx);
527 QAT_PHYS_CONTIG_FREE(src_buffer_list.pPrivateMetaData);
528 QAT_PHYS_CONTIG_FREE(cy_session_ctx);
529 QAT_PHYS_CONTIG_FREE(flat_src_buf_array);
530
531 return (status);
532}
533
534module_param(zfs_qat_encrypt_disable, int, 0644);
535MODULE_PARM_DESC(zfs_qat_encrypt_disable, "Disable QAT encryption");
536
537module_param(zfs_qat_checksum_disable, int, 0644);
538MODULE_PARM_DESC(zfs_qat_checksum_disable, "Disable QAT checksumming");
cf637391
TC
539
540#endif