188f8b78aSgm89044 /*
288f8b78aSgm89044 * CDDL HEADER START
388f8b78aSgm89044 *
488f8b78aSgm89044 * The contents of this file are subject to the terms of the
588f8b78aSgm89044 * Common Development and Distribution License (the "License").
688f8b78aSgm89044 * You may not use this file except in compliance with the License.
788f8b78aSgm89044 *
888f8b78aSgm89044 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
988f8b78aSgm89044 * or http://www.opensolaris.org/os/licensing.
1088f8b78aSgm89044 * See the License for the specific language governing permissions
1188f8b78aSgm89044 * and limitations under the License.
1288f8b78aSgm89044 *
1388f8b78aSgm89044 * When distributing Covered Code, include this CDDL HEADER in each
1488f8b78aSgm89044 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1588f8b78aSgm89044 * If applicable, add the following below this CDDL HEADER, with the
1688f8b78aSgm89044 * fields enclosed by brackets "[]" replaced with your own identifying
1788f8b78aSgm89044 * information: Portions Copyright [yyyy] [name of copyright owner]
1888f8b78aSgm89044 *
1988f8b78aSgm89044 * CDDL HEADER END
2088f8b78aSgm89044 */
2188f8b78aSgm89044
2288f8b78aSgm89044 /*
23*95014fbbSDan OpenSolaris Anderson * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
2488f8b78aSgm89044 * Use is subject to license terms.
2588f8b78aSgm89044 */
2688f8b78aSgm89044
2788f8b78aSgm89044
2888f8b78aSgm89044 /*
2988f8b78aSgm89044 * Deimos - cryptographic acceleration based upon Broadcom 582x.
3088f8b78aSgm89044 */
3188f8b78aSgm89044
3288f8b78aSgm89044 #include <sys/types.h>
3388f8b78aSgm89044 #include <sys/modctl.h>
3488f8b78aSgm89044 #include <sys/conf.h>
3588f8b78aSgm89044 #include <sys/devops.h>
3688f8b78aSgm89044 #include <sys/ddi.h>
3788f8b78aSgm89044 #include <sys/sunddi.h>
3888f8b78aSgm89044 #include <sys/cmn_err.h>
3988f8b78aSgm89044 #include <sys/varargs.h>
4088f8b78aSgm89044 #include <sys/file.h>
4188f8b78aSgm89044 #include <sys/stat.h>
4288f8b78aSgm89044 #include <sys/kmem.h>
4388f8b78aSgm89044 #include <sys/ioccom.h>
4488f8b78aSgm89044 #include <sys/open.h>
4588f8b78aSgm89044 #include <sys/cred.h>
4688f8b78aSgm89044 #include <sys/kstat.h>
4788f8b78aSgm89044 #include <sys/strsun.h>
4888f8b78aSgm89044 #include <sys/note.h>
4988f8b78aSgm89044 #include <sys/crypto/common.h>
5088f8b78aSgm89044 #include <sys/crypto/spi.h>
5188f8b78aSgm89044 #include <sys/ddifm.h>
5288f8b78aSgm89044 #include <sys/fm/protocol.h>
5388f8b78aSgm89044 #include <sys/fm/util.h>
5488f8b78aSgm89044 #include <sys/fm/io/ddi.h>
5588f8b78aSgm89044 #include <sys/crypto/dca.h>
5688f8b78aSgm89044
5788f8b78aSgm89044 /*
5888f8b78aSgm89044 * Core Deimos driver.
5988f8b78aSgm89044 */
6088f8b78aSgm89044
6188f8b78aSgm89044 static void dca_enlist2(dca_listnode_t *, dca_listnode_t *,
6288f8b78aSgm89044 kmutex_t *);
6388f8b78aSgm89044 static void dca_rmlist2(dca_listnode_t *node, kmutex_t *);
6488f8b78aSgm89044 static dca_listnode_t *dca_delist2(dca_listnode_t *q, kmutex_t *);
6588f8b78aSgm89044 static void dca_free_context_list(dca_t *dca);
6688f8b78aSgm89044 static int dca_free_context_low(crypto_ctx_t *ctx);
6788f8b78aSgm89044 static int dca_attach(dev_info_t *, ddi_attach_cmd_t);
6888f8b78aSgm89044 static int dca_detach(dev_info_t *, ddi_detach_cmd_t);
6988f8b78aSgm89044 static int dca_suspend(dca_t *);
7088f8b78aSgm89044 static int dca_resume(dca_t *);
7188f8b78aSgm89044 static int dca_init(dca_t *);
7288f8b78aSgm89044 static int dca_reset(dca_t *, int);
7388f8b78aSgm89044 static int dca_initworklist(dca_t *, dca_worklist_t *);
7488f8b78aSgm89044 static void dca_uninit(dca_t *);
7588f8b78aSgm89044 static void dca_initq(dca_listnode_t *);
7688f8b78aSgm89044 static void dca_enqueue(dca_listnode_t *, dca_listnode_t *);
7788f8b78aSgm89044 static dca_listnode_t *dca_dequeue(dca_listnode_t *);
7888f8b78aSgm89044 static dca_listnode_t *dca_unqueue(dca_listnode_t *);
7988f8b78aSgm89044 static dca_request_t *dca_newreq(dca_t *);
8088f8b78aSgm89044 static dca_work_t *dca_getwork(dca_t *, int);
8188f8b78aSgm89044 static void dca_freework(dca_work_t *);
8288f8b78aSgm89044 static dca_work_t *dca_newwork(dca_t *);
8388f8b78aSgm89044 static void dca_destroywork(dca_work_t *);
8488f8b78aSgm89044 static void dca_schedule(dca_t *, int);
8588f8b78aSgm89044 static void dca_reclaim(dca_t *, int);
8688f8b78aSgm89044 static uint_t dca_intr(char *);
8788f8b78aSgm89044 static void dca_failure(dca_t *, ddi_fault_location_t,
8888f8b78aSgm89044 dca_fma_eclass_t index, uint64_t, int, char *, ...);
8988f8b78aSgm89044 static void dca_jobtimeout(void *);
9088f8b78aSgm89044 static int dca_drain(dca_t *);
9188f8b78aSgm89044 static void dca_undrain(dca_t *);
9288f8b78aSgm89044 static void dca_rejectjobs(dca_t *);
9388f8b78aSgm89044
9488f8b78aSgm89044 #ifdef SCHEDDELAY
9588f8b78aSgm89044 static void dca_schedtimeout(void *);
9688f8b78aSgm89044 #endif
9788f8b78aSgm89044
9888f8b78aSgm89044 /*
9988f8b78aSgm89044 * We want these inlined for performance.
10088f8b78aSgm89044 */
10188f8b78aSgm89044 #ifndef DEBUG
10288f8b78aSgm89044 #pragma inline(dca_freereq, dca_getreq, dca_freework, dca_getwork)
10388f8b78aSgm89044 #pragma inline(dca_enqueue, dca_dequeue, dca_rmqueue, dca_done)
10488f8b78aSgm89044 #pragma inline(dca_reverse, dca_length)
10588f8b78aSgm89044 #endif
10688f8b78aSgm89044
10788f8b78aSgm89044 /*
10888f8b78aSgm89044 * Device operations.
10988f8b78aSgm89044 */
11088f8b78aSgm89044 static struct dev_ops devops = {
11188f8b78aSgm89044 DEVO_REV, /* devo_rev */
11288f8b78aSgm89044 0, /* devo_refcnt */
11388f8b78aSgm89044 nodev, /* devo_getinfo */
11488f8b78aSgm89044 nulldev, /* devo_identify */
11588f8b78aSgm89044 nulldev, /* devo_probe */
11688f8b78aSgm89044 dca_attach, /* devo_attach */
11788f8b78aSgm89044 dca_detach, /* devo_detach */
11888f8b78aSgm89044 nodev, /* devo_reset */
11988f8b78aSgm89044 NULL, /* devo_cb_ops */
12088f8b78aSgm89044 NULL, /* devo_bus_ops */
12119397407SSherry Moore ddi_power, /* devo_power */
12219397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */
12388f8b78aSgm89044 };
12488f8b78aSgm89044
12519397407SSherry Moore #define IDENT "PCI Crypto Accelerator"
12688f8b78aSgm89044 #define IDENT_SYM "Crypto Accel Sym 2.0"
12788f8b78aSgm89044 #define IDENT_ASYM "Crypto Accel Asym 2.0"
12888f8b78aSgm89044
12988f8b78aSgm89044 /* Space-padded, will be filled in dynamically during registration */
13088f8b78aSgm89044 #define IDENT3 "PCI Crypto Accelerator Mod 2.0"
13188f8b78aSgm89044
13288f8b78aSgm89044 #define VENDOR "Sun Microsystems, Inc."
13388f8b78aSgm89044
13488f8b78aSgm89044 #define STALETIME (30 * SECOND)
13588f8b78aSgm89044
13688f8b78aSgm89044 #define crypto_prov_notify crypto_provider_notification
13788f8b78aSgm89044 /* A 28 char function name doesn't leave much line space */
13888f8b78aSgm89044
13988f8b78aSgm89044 /*
14088f8b78aSgm89044 * Module linkage.
14188f8b78aSgm89044 */
14288f8b78aSgm89044 static struct modldrv modldrv = {
14388f8b78aSgm89044 &mod_driverops, /* drv_modops */
14488f8b78aSgm89044 IDENT, /* drv_linkinfo */
14588f8b78aSgm89044 &devops, /* drv_dev_ops */
14688f8b78aSgm89044 };
14788f8b78aSgm89044
14888f8b78aSgm89044 extern struct mod_ops mod_cryptoops;
14988f8b78aSgm89044
15088f8b78aSgm89044 static struct modlcrypto modlcrypto = {
15188f8b78aSgm89044 &mod_cryptoops,
15288f8b78aSgm89044 IDENT3
15388f8b78aSgm89044 };
15488f8b78aSgm89044
15588f8b78aSgm89044 static struct modlinkage modlinkage = {
15688f8b78aSgm89044 MODREV_1, /* ml_rev */
15788f8b78aSgm89044 &modldrv, /* ml_linkage */
15888f8b78aSgm89044 &modlcrypto,
15988f8b78aSgm89044 NULL
16088f8b78aSgm89044 };
16188f8b78aSgm89044
16288f8b78aSgm89044 /*
16388f8b78aSgm89044 * CSPI information (entry points, provider info, etc.)
16488f8b78aSgm89044 */
16588f8b78aSgm89044
16688f8b78aSgm89044 /* Mechanisms for the symmetric cipher provider */
16788f8b78aSgm89044 static crypto_mech_info_t dca_mech_info_tab1[] = {
16888f8b78aSgm89044 /* DES-CBC */
16988f8b78aSgm89044 {SUN_CKM_DES_CBC, DES_CBC_MECH_INFO_TYPE,
17088f8b78aSgm89044 CRYPTO_FG_ENCRYPT | CRYPTO_FG_DECRYPT |
17188f8b78aSgm89044 CRYPTO_FG_ENCRYPT_ATOMIC | CRYPTO_FG_DECRYPT_ATOMIC,
17288f8b78aSgm89044 DES_KEY_LEN, DES_KEY_LEN, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
17388f8b78aSgm89044 /* 3DES-CBC */
17488f8b78aSgm89044 {SUN_CKM_DES3_CBC, DES3_CBC_MECH_INFO_TYPE,
17588f8b78aSgm89044 CRYPTO_FG_ENCRYPT | CRYPTO_FG_DECRYPT |
17688f8b78aSgm89044 CRYPTO_FG_ENCRYPT_ATOMIC | CRYPTO_FG_DECRYPT_ATOMIC,
177436935a1SVladimir Kotal DES3_MIN_KEY_LEN, DES3_MAX_KEY_LEN, CRYPTO_KEYSIZE_UNIT_IN_BYTES}
17888f8b78aSgm89044 };
17988f8b78aSgm89044
18088f8b78aSgm89044 /* Mechanisms for the asymmetric cipher provider */
18188f8b78aSgm89044 static crypto_mech_info_t dca_mech_info_tab2[] = {
18288f8b78aSgm89044 /* DSA */
18388f8b78aSgm89044 {SUN_CKM_DSA, DSA_MECH_INFO_TYPE,
18488f8b78aSgm89044 CRYPTO_FG_SIGN | CRYPTO_FG_VERIFY |
18588f8b78aSgm89044 CRYPTO_FG_SIGN_ATOMIC | CRYPTO_FG_VERIFY_ATOMIC,
186*95014fbbSDan OpenSolaris Anderson CRYPTO_BYTES2BITS(DSA_MIN_KEY_LEN),
187*95014fbbSDan OpenSolaris Anderson CRYPTO_BYTES2BITS(DSA_MAX_KEY_LEN),
18888f8b78aSgm89044 CRYPTO_KEYSIZE_UNIT_IN_BITS},
18988f8b78aSgm89044
19088f8b78aSgm89044 /* RSA */
19188f8b78aSgm89044 {SUN_CKM_RSA_X_509, RSA_X_509_MECH_INFO_TYPE,
19288f8b78aSgm89044 CRYPTO_FG_ENCRYPT | CRYPTO_FG_DECRYPT | CRYPTO_FG_SIGN |
19388f8b78aSgm89044 CRYPTO_FG_SIGN_RECOVER | CRYPTO_FG_VERIFY |
19488f8b78aSgm89044 CRYPTO_FG_VERIFY_RECOVER |
19588f8b78aSgm89044 CRYPTO_FG_ENCRYPT_ATOMIC | CRYPTO_FG_DECRYPT_ATOMIC |
19688f8b78aSgm89044 CRYPTO_FG_SIGN_ATOMIC | CRYPTO_FG_SIGN_RECOVER_ATOMIC |
19788f8b78aSgm89044 CRYPTO_FG_VERIFY_ATOMIC | CRYPTO_FG_VERIFY_RECOVER_ATOMIC,
198*95014fbbSDan OpenSolaris Anderson CRYPTO_BYTES2BITS(RSA_MIN_KEY_LEN),
199*95014fbbSDan OpenSolaris Anderson CRYPTO_BYTES2BITS(RSA_MAX_KEY_LEN),
20088f8b78aSgm89044 CRYPTO_KEYSIZE_UNIT_IN_BITS},
20188f8b78aSgm89044 {SUN_CKM_RSA_PKCS, RSA_PKCS_MECH_INFO_TYPE,
20288f8b78aSgm89044 CRYPTO_FG_ENCRYPT | CRYPTO_FG_DECRYPT | CRYPTO_FG_SIGN |
20388f8b78aSgm89044 CRYPTO_FG_SIGN_RECOVER | CRYPTO_FG_VERIFY |
20488f8b78aSgm89044 CRYPTO_FG_VERIFY_RECOVER |
20588f8b78aSgm89044 CRYPTO_FG_ENCRYPT_ATOMIC | CRYPTO_FG_DECRYPT_ATOMIC |
20688f8b78aSgm89044 CRYPTO_FG_SIGN_ATOMIC | CRYPTO_FG_SIGN_RECOVER_ATOMIC |
20788f8b78aSgm89044 CRYPTO_FG_VERIFY_ATOMIC | CRYPTO_FG_VERIFY_RECOVER_ATOMIC,
208*95014fbbSDan OpenSolaris Anderson CRYPTO_BYTES2BITS(RSA_MIN_KEY_LEN),
209*95014fbbSDan OpenSolaris Anderson CRYPTO_BYTES2BITS(RSA_MAX_KEY_LEN),
21088f8b78aSgm89044 CRYPTO_KEYSIZE_UNIT_IN_BITS}
21188f8b78aSgm89044 };
21288f8b78aSgm89044
21388f8b78aSgm89044 static void dca_provider_status(crypto_provider_handle_t, uint_t *);
21488f8b78aSgm89044
21588f8b78aSgm89044 static crypto_control_ops_t dca_control_ops = {
21688f8b78aSgm89044 dca_provider_status
21788f8b78aSgm89044 };
21888f8b78aSgm89044
21988f8b78aSgm89044 static int dca_encrypt_init(crypto_ctx_t *, crypto_mechanism_t *,
22088f8b78aSgm89044 crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
22188f8b78aSgm89044 static int dca_encrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
22288f8b78aSgm89044 crypto_req_handle_t);
22388f8b78aSgm89044 static int dca_encrypt_update(crypto_ctx_t *, crypto_data_t *,
22488f8b78aSgm89044 crypto_data_t *, crypto_req_handle_t);
22588f8b78aSgm89044 static int dca_encrypt_final(crypto_ctx_t *, crypto_data_t *,
22688f8b78aSgm89044 crypto_req_handle_t);
22788f8b78aSgm89044 static int dca_encrypt_atomic(crypto_provider_handle_t, crypto_session_id_t,
22888f8b78aSgm89044 crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
22988f8b78aSgm89044 crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
23088f8b78aSgm89044
23188f8b78aSgm89044 static int dca_decrypt_init(crypto_ctx_t *, crypto_mechanism_t *,
23288f8b78aSgm89044 crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
23388f8b78aSgm89044 static int dca_decrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
23488f8b78aSgm89044 crypto_req_handle_t);
23588f8b78aSgm89044 static int dca_decrypt_update(crypto_ctx_t *, crypto_data_t *,
23688f8b78aSgm89044 crypto_data_t *, crypto_req_handle_t);
23788f8b78aSgm89044 static int dca_decrypt_final(crypto_ctx_t *, crypto_data_t *,
23888f8b78aSgm89044 crypto_req_handle_t);
23988f8b78aSgm89044 static int dca_decrypt_atomic(crypto_provider_handle_t, crypto_session_id_t,
24088f8b78aSgm89044 crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
24188f8b78aSgm89044 crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
24288f8b78aSgm89044
24388f8b78aSgm89044 static crypto_cipher_ops_t dca_cipher_ops = {
24488f8b78aSgm89044 dca_encrypt_init,
24588f8b78aSgm89044 dca_encrypt,
24688f8b78aSgm89044 dca_encrypt_update,
24788f8b78aSgm89044 dca_encrypt_final,
24888f8b78aSgm89044 dca_encrypt_atomic,
24988f8b78aSgm89044 dca_decrypt_init,
25088f8b78aSgm89044 dca_decrypt,
25188f8b78aSgm89044 dca_decrypt_update,
25288f8b78aSgm89044 dca_decrypt_final,
25388f8b78aSgm89044 dca_decrypt_atomic
25488f8b78aSgm89044 };
25588f8b78aSgm89044
25688f8b78aSgm89044 static int dca_sign_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *,
25788f8b78aSgm89044 crypto_spi_ctx_template_t, crypto_req_handle_t);
25888f8b78aSgm89044 static int dca_sign(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
25988f8b78aSgm89044 crypto_req_handle_t);
26088f8b78aSgm89044 static int dca_sign_update(crypto_ctx_t *, crypto_data_t *,
26188f8b78aSgm89044 crypto_req_handle_t);
26288f8b78aSgm89044 static int dca_sign_final(crypto_ctx_t *, crypto_data_t *,
26388f8b78aSgm89044 crypto_req_handle_t);
26488f8b78aSgm89044 static int dca_sign_atomic(crypto_provider_handle_t, crypto_session_id_t,
26588f8b78aSgm89044 crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
26688f8b78aSgm89044 crypto_spi_ctx_template_t, crypto_req_handle_t);
26788f8b78aSgm89044 static int dca_sign_recover_init(crypto_ctx_t *, crypto_mechanism_t *,
26888f8b78aSgm89044 crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
26988f8b78aSgm89044 static int dca_sign_recover(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
27088f8b78aSgm89044 crypto_req_handle_t);
27188f8b78aSgm89044 static int dca_sign_recover_atomic(crypto_provider_handle_t,
27288f8b78aSgm89044 crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
27388f8b78aSgm89044 crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
27488f8b78aSgm89044
27588f8b78aSgm89044 static crypto_sign_ops_t dca_sign_ops = {
27688f8b78aSgm89044 dca_sign_init,
27788f8b78aSgm89044 dca_sign,
27888f8b78aSgm89044 dca_sign_update,
27988f8b78aSgm89044 dca_sign_final,
28088f8b78aSgm89044 dca_sign_atomic,
28188f8b78aSgm89044 dca_sign_recover_init,
28288f8b78aSgm89044 dca_sign_recover,
28388f8b78aSgm89044 dca_sign_recover_atomic
28488f8b78aSgm89044 };
28588f8b78aSgm89044
28688f8b78aSgm89044 static int dca_verify_init(crypto_ctx_t *, crypto_mechanism_t *,
28788f8b78aSgm89044 crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
28888f8b78aSgm89044 static int dca_verify(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
28988f8b78aSgm89044 crypto_req_handle_t);
29088f8b78aSgm89044 static int dca_verify_update(crypto_ctx_t *, crypto_data_t *,
29188f8b78aSgm89044 crypto_req_handle_t);
29288f8b78aSgm89044 static int dca_verify_final(crypto_ctx_t *, crypto_data_t *,
29388f8b78aSgm89044 crypto_req_handle_t);
29488f8b78aSgm89044 static int dca_verify_atomic(crypto_provider_handle_t, crypto_session_id_t,
29588f8b78aSgm89044 crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
29688f8b78aSgm89044 crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
29788f8b78aSgm89044 static int dca_verify_recover_init(crypto_ctx_t *, crypto_mechanism_t *,
29888f8b78aSgm89044 crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
29988f8b78aSgm89044 static int dca_verify_recover(crypto_ctx_t *, crypto_data_t *,
30088f8b78aSgm89044 crypto_data_t *, crypto_req_handle_t);
30188f8b78aSgm89044 static int dca_verify_recover_atomic(crypto_provider_handle_t,
30288f8b78aSgm89044 crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
30388f8b78aSgm89044 crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
30488f8b78aSgm89044
30588f8b78aSgm89044 static crypto_verify_ops_t dca_verify_ops = {
30688f8b78aSgm89044 dca_verify_init,
30788f8b78aSgm89044 dca_verify,
30888f8b78aSgm89044 dca_verify_update,
30988f8b78aSgm89044 dca_verify_final,
31088f8b78aSgm89044 dca_verify_atomic,
31188f8b78aSgm89044 dca_verify_recover_init,
31288f8b78aSgm89044 dca_verify_recover,
31388f8b78aSgm89044 dca_verify_recover_atomic
31488f8b78aSgm89044 };
31588f8b78aSgm89044
31688f8b78aSgm89044 static int dca_generate_random(crypto_provider_handle_t, crypto_session_id_t,
31788f8b78aSgm89044 uchar_t *, size_t, crypto_req_handle_t);
31888f8b78aSgm89044
31988f8b78aSgm89044 static crypto_random_number_ops_t dca_random_number_ops = {
32088f8b78aSgm89044 NULL,
32188f8b78aSgm89044 dca_generate_random
32288f8b78aSgm89044 };
32388f8b78aSgm89044
32488f8b78aSgm89044 static int ext_info_sym(crypto_provider_handle_t prov,
32588f8b78aSgm89044 crypto_provider_ext_info_t *ext_info, crypto_req_handle_t cfreq);
32688f8b78aSgm89044 static int ext_info_asym(crypto_provider_handle_t prov,
32788f8b78aSgm89044 crypto_provider_ext_info_t *ext_info, crypto_req_handle_t cfreq);
32888f8b78aSgm89044 static int ext_info_base(crypto_provider_handle_t prov,
32988f8b78aSgm89044 crypto_provider_ext_info_t *ext_info, crypto_req_handle_t cfreq, char *id);
33088f8b78aSgm89044
33188f8b78aSgm89044 static crypto_provider_management_ops_t dca_provmanage_ops_1 = {
33288f8b78aSgm89044 ext_info_sym, /* ext_info */
33388f8b78aSgm89044 NULL, /* init_token */
33488f8b78aSgm89044 NULL, /* init_pin */
33588f8b78aSgm89044 NULL /* set_pin */
33688f8b78aSgm89044 };
33788f8b78aSgm89044
33888f8b78aSgm89044 static crypto_provider_management_ops_t dca_provmanage_ops_2 = {
33988f8b78aSgm89044 ext_info_asym, /* ext_info */
34088f8b78aSgm89044 NULL, /* init_token */
34188f8b78aSgm89044 NULL, /* init_pin */
34288f8b78aSgm89044 NULL /* set_pin */
34388f8b78aSgm89044 };
34488f8b78aSgm89044
34588f8b78aSgm89044 int dca_free_context(crypto_ctx_t *);
34688f8b78aSgm89044
34788f8b78aSgm89044 static crypto_ctx_ops_t dca_ctx_ops = {
34888f8b78aSgm89044 NULL,
34988f8b78aSgm89044 dca_free_context
35088f8b78aSgm89044 };
35188f8b78aSgm89044
35288f8b78aSgm89044 /* Operations for the symmetric cipher provider */
35388f8b78aSgm89044 static crypto_ops_t dca_crypto_ops1 = {
35488f8b78aSgm89044 &dca_control_ops,
35588f8b78aSgm89044 NULL, /* digest_ops */
35688f8b78aSgm89044 &dca_cipher_ops,
35788f8b78aSgm89044 NULL, /* mac_ops */
35888f8b78aSgm89044 NULL, /* sign_ops */
35988f8b78aSgm89044 NULL, /* verify_ops */
36088f8b78aSgm89044 NULL, /* dual_ops */
36188f8b78aSgm89044 NULL, /* cipher_mac_ops */
36288f8b78aSgm89044 NULL, /* random_number_ops */
36388f8b78aSgm89044 NULL, /* session_ops */
36488f8b78aSgm89044 NULL, /* object_ops */
36588f8b78aSgm89044 NULL, /* key_ops */
36688f8b78aSgm89044 &dca_provmanage_ops_1, /* management_ops */
36788f8b78aSgm89044 &dca_ctx_ops
36888f8b78aSgm89044 };
36988f8b78aSgm89044
37088f8b78aSgm89044 /* Operations for the asymmetric cipher provider */
37188f8b78aSgm89044 static crypto_ops_t dca_crypto_ops2 = {
37288f8b78aSgm89044 &dca_control_ops,
37388f8b78aSgm89044 NULL, /* digest_ops */
37488f8b78aSgm89044 &dca_cipher_ops,
37588f8b78aSgm89044 NULL, /* mac_ops */
37688f8b78aSgm89044 &dca_sign_ops,
37788f8b78aSgm89044 &dca_verify_ops,
37888f8b78aSgm89044 NULL, /* dual_ops */
37988f8b78aSgm89044 NULL, /* cipher_mac_ops */
38088f8b78aSgm89044 &dca_random_number_ops,
38188f8b78aSgm89044 NULL, /* session_ops */
38288f8b78aSgm89044 NULL, /* object_ops */
38388f8b78aSgm89044 NULL, /* key_ops */
38488f8b78aSgm89044 &dca_provmanage_ops_2, /* management_ops */
38588f8b78aSgm89044 &dca_ctx_ops
38688f8b78aSgm89044 };
38788f8b78aSgm89044
38888f8b78aSgm89044 /* Provider information for the symmetric cipher provider */
38988f8b78aSgm89044 static crypto_provider_info_t dca_prov_info1 = {
39088f8b78aSgm89044 CRYPTO_SPI_VERSION_1,
39188f8b78aSgm89044 NULL, /* pi_provider_description */
39288f8b78aSgm89044 CRYPTO_HW_PROVIDER,
39388f8b78aSgm89044 NULL, /* pi_provider_dev */
39488f8b78aSgm89044 NULL, /* pi_provider_handle */
39588f8b78aSgm89044 &dca_crypto_ops1,
39688f8b78aSgm89044 sizeof (dca_mech_info_tab1)/sizeof (crypto_mech_info_t),
39788f8b78aSgm89044 dca_mech_info_tab1,
39888f8b78aSgm89044 0, /* pi_logical_provider_count */
39988f8b78aSgm89044 NULL /* pi_logical_providers */
40088f8b78aSgm89044 };
40188f8b78aSgm89044
40288f8b78aSgm89044 /* Provider information for the asymmetric cipher provider */
40388f8b78aSgm89044 static crypto_provider_info_t dca_prov_info2 = {
40488f8b78aSgm89044 CRYPTO_SPI_VERSION_1,
40588f8b78aSgm89044 NULL, /* pi_provider_description */
40688f8b78aSgm89044 CRYPTO_HW_PROVIDER,
40788f8b78aSgm89044 NULL, /* pi_provider_dev */
40888f8b78aSgm89044 NULL, /* pi_provider_handle */
40988f8b78aSgm89044 &dca_crypto_ops2,
41088f8b78aSgm89044 sizeof (dca_mech_info_tab2)/sizeof (crypto_mech_info_t),
41188f8b78aSgm89044 dca_mech_info_tab2,
41288f8b78aSgm89044 0, /* pi_logical_provider_count */
41388f8b78aSgm89044 NULL /* pi_logical_providers */
41488f8b78aSgm89044 };
41588f8b78aSgm89044
41688f8b78aSgm89044 /* Convenience macros */
41788f8b78aSgm89044 /* Retrieve the softc and instance number from a SPI crypto context */
41888f8b78aSgm89044 #define DCA_SOFTC_FROM_CTX(ctx, softc, instance) { \
41988f8b78aSgm89044 (softc) = (dca_t *)(ctx)->cc_provider; \
42088f8b78aSgm89044 (instance) = ddi_get_instance((softc)->dca_dip); \
42188f8b78aSgm89044 }
42288f8b78aSgm89044
42388f8b78aSgm89044 #define DCA_MECH_FROM_CTX(ctx) \
42488f8b78aSgm89044 (((dca_request_t *)(ctx)->cc_provider_private)->dr_ctx.ctx_cm_type)
42588f8b78aSgm89044
42688f8b78aSgm89044 static int dca_bindchains_one(dca_request_t *reqp, size_t cnt, int dr_offset,
42788f8b78aSgm89044 caddr_t kaddr, ddi_dma_handle_t handle, uint_t flags,
42888f8b78aSgm89044 dca_chain_t *head, int *n_chain);
42988f8b78aSgm89044 static uint64_t dca_ena(uint64_t ena);
43088f8b78aSgm89044 static caddr_t dca_bufdaddr_out(crypto_data_t *data);
43188f8b78aSgm89044 static char *dca_fma_eclass_string(char *model, dca_fma_eclass_t index);
43288f8b78aSgm89044 static int dca_check_acc_handle(dca_t *dca, ddi_acc_handle_t handle,
43388f8b78aSgm89044 dca_fma_eclass_t eclass_index);
43488f8b78aSgm89044
43588f8b78aSgm89044 static void dca_fma_init(dca_t *dca);
43688f8b78aSgm89044 static void dca_fma_fini(dca_t *dca);
43788f8b78aSgm89044 static int dca_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err,
43888f8b78aSgm89044 const void *impl_data);
43988f8b78aSgm89044
44088f8b78aSgm89044
44188f8b78aSgm89044 static dca_device_t dca_devices[] = {
44288f8b78aSgm89044 /* Broadcom vanilla variants */
44388f8b78aSgm89044 { 0x14e4, 0x5820, "Broadcom 5820" },
44488f8b78aSgm89044 { 0x14e4, 0x5821, "Broadcom 5821" },
44588f8b78aSgm89044 { 0x14e4, 0x5822, "Broadcom 5822" },
44688f8b78aSgm89044 { 0x14e4, 0x5825, "Broadcom 5825" },
44788f8b78aSgm89044 /* Sun specific OEMd variants */
44888f8b78aSgm89044 { 0x108e, 0x5454, "SCA" },
44988f8b78aSgm89044 { 0x108e, 0x5455, "SCA 1000" },
45088f8b78aSgm89044 { 0x108e, 0x5457, "SCA 500" },
45188f8b78aSgm89044 /* subsysid should be 0x5457, but got 0x1 from HW. Assume both here. */
45288f8b78aSgm89044 { 0x108e, 0x1, "SCA 500" },
45388f8b78aSgm89044 };
45488f8b78aSgm89044
45588f8b78aSgm89044 /*
45688f8b78aSgm89044 * Device attributes.
45788f8b78aSgm89044 */
45888f8b78aSgm89044 static struct ddi_device_acc_attr dca_regsattr = {
459837c1ac4SStephen Hanson DDI_DEVICE_ATTR_V1,
46088f8b78aSgm89044 DDI_STRUCTURE_LE_ACC,
46188f8b78aSgm89044 DDI_STRICTORDER_ACC,
46288f8b78aSgm89044 DDI_FLAGERR_ACC
46388f8b78aSgm89044 };
46488f8b78aSgm89044
46588f8b78aSgm89044 static struct ddi_device_acc_attr dca_devattr = {
46688f8b78aSgm89044 DDI_DEVICE_ATTR_V0,
46788f8b78aSgm89044 DDI_STRUCTURE_LE_ACC,
468837c1ac4SStephen Hanson DDI_STRICTORDER_ACC
46988f8b78aSgm89044 };
47088f8b78aSgm89044
47188f8b78aSgm89044 #if !defined(i386) && !defined(__i386)
47288f8b78aSgm89044 static struct ddi_device_acc_attr dca_bufattr = {
47388f8b78aSgm89044 DDI_DEVICE_ATTR_V0,
47488f8b78aSgm89044 DDI_NEVERSWAP_ACC,
475837c1ac4SStephen Hanson DDI_STRICTORDER_ACC
47688f8b78aSgm89044 };
47788f8b78aSgm89044 #endif
47888f8b78aSgm89044
47988f8b78aSgm89044 static struct ddi_dma_attr dca_dmaattr = {
48088f8b78aSgm89044 DMA_ATTR_V0, /* dma_attr_version */
48188f8b78aSgm89044 0x0, /* dma_attr_addr_lo */
48288f8b78aSgm89044 0xffffffffUL, /* dma_attr_addr_hi */
48388f8b78aSgm89044 0x00ffffffUL, /* dma_attr_count_max */
48488f8b78aSgm89044 0x40, /* dma_attr_align */
48588f8b78aSgm89044 0x40, /* dma_attr_burstsizes */
48688f8b78aSgm89044 0x1, /* dma_attr_minxfer */
48788f8b78aSgm89044 0x00ffffffUL, /* dma_attr_maxxfer */
48888f8b78aSgm89044 0xffffffffUL, /* dma_attr_seg */
48988f8b78aSgm89044 #if defined(i386) || defined(__i386) || defined(__amd64)
49088f8b78aSgm89044 512, /* dma_attr_sgllen */
49188f8b78aSgm89044 #else
49288f8b78aSgm89044 1, /* dma_attr_sgllen */
49388f8b78aSgm89044 #endif
49488f8b78aSgm89044 1, /* dma_attr_granular */
49588f8b78aSgm89044 DDI_DMA_FLAGERR /* dma_attr_flags */
49688f8b78aSgm89044 };
49788f8b78aSgm89044
49888f8b78aSgm89044 static void *dca_state = NULL;
49988f8b78aSgm89044 int dca_mindma = 2500;
50088f8b78aSgm89044
50188f8b78aSgm89044 /*
50288f8b78aSgm89044 * FMA eclass string definitions. Note that these string arrays must be
50388f8b78aSgm89044 * consistent with the dca_fma_eclass_t enum.
50488f8b78aSgm89044 */
50588f8b78aSgm89044 static char *dca_fma_eclass_sca1000[] = {
50688f8b78aSgm89044 "sca1000.hw.device",
50788f8b78aSgm89044 "sca1000.hw.timeout",
50888f8b78aSgm89044 "sca1000.none"
50988f8b78aSgm89044 };
51088f8b78aSgm89044
51188f8b78aSgm89044 static char *dca_fma_eclass_sca500[] = {
51288f8b78aSgm89044 "sca500.hw.device",
51388f8b78aSgm89044 "sca500.hw.timeout",
51488f8b78aSgm89044 "sca500.none"
51588f8b78aSgm89044 };
51688f8b78aSgm89044
51788f8b78aSgm89044 /*
51888f8b78aSgm89044 * DDI entry points.
51988f8b78aSgm89044 */
52088f8b78aSgm89044 int
_init(void)52188f8b78aSgm89044 _init(void)
52288f8b78aSgm89044 {
52388f8b78aSgm89044 int rv;
52488f8b78aSgm89044
52588f8b78aSgm89044 DBG(NULL, DMOD, "dca: in _init");
52688f8b78aSgm89044
52788f8b78aSgm89044 if ((rv = ddi_soft_state_init(&dca_state, sizeof (dca_t), 1)) != 0) {
52888f8b78aSgm89044 /* this should *never* happen! */
52988f8b78aSgm89044 return (rv);
53088f8b78aSgm89044 }
53188f8b78aSgm89044
53288f8b78aSgm89044 if ((rv = mod_install(&modlinkage)) != 0) {
53388f8b78aSgm89044 /* cleanup here */
53488f8b78aSgm89044 ddi_soft_state_fini(&dca_state);
53588f8b78aSgm89044 return (rv);
53688f8b78aSgm89044 }
53788f8b78aSgm89044
53888f8b78aSgm89044 return (0);
53988f8b78aSgm89044 }
54088f8b78aSgm89044
54188f8b78aSgm89044 int
_fini(void)54288f8b78aSgm89044 _fini(void)
54388f8b78aSgm89044 {
54488f8b78aSgm89044 int rv;
54588f8b78aSgm89044
54688f8b78aSgm89044 DBG(NULL, DMOD, "dca: in _fini");
54788f8b78aSgm89044
54888f8b78aSgm89044 if ((rv = mod_remove(&modlinkage)) == 0) {
54988f8b78aSgm89044 /* cleanup here */
55088f8b78aSgm89044 ddi_soft_state_fini(&dca_state);
55188f8b78aSgm89044 }
55288f8b78aSgm89044 return (rv);
55388f8b78aSgm89044 }
55488f8b78aSgm89044
55588f8b78aSgm89044 int
_info(struct modinfo * modinfop)55688f8b78aSgm89044 _info(struct modinfo *modinfop)
55788f8b78aSgm89044 {
55888f8b78aSgm89044 DBG(NULL, DMOD, "dca: in _info");
55988f8b78aSgm89044
56088f8b78aSgm89044 return (mod_info(&modlinkage, modinfop));
56188f8b78aSgm89044 }
56288f8b78aSgm89044
56388f8b78aSgm89044 int
dca_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)56488f8b78aSgm89044 dca_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
56588f8b78aSgm89044 {
56688f8b78aSgm89044 ddi_acc_handle_t pci;
56788f8b78aSgm89044 int instance;
56888f8b78aSgm89044 ddi_iblock_cookie_t ibc;
56988f8b78aSgm89044 int intr_added = 0;
57088f8b78aSgm89044 dca_t *dca;
57188f8b78aSgm89044 ushort_t venid;
57288f8b78aSgm89044 ushort_t devid;
57388f8b78aSgm89044 ushort_t revid;
57488f8b78aSgm89044 ushort_t subsysid;
57588f8b78aSgm89044 ushort_t subvenid;
57688f8b78aSgm89044 int i;
57788f8b78aSgm89044 int ret;
57888f8b78aSgm89044 char ID[64];
57988f8b78aSgm89044 static char *unknowndev = "Unknown device";
58088f8b78aSgm89044
58188f8b78aSgm89044 #if DEBUG
58288f8b78aSgm89044 /* these are only used for debugging */
58388f8b78aSgm89044 ushort_t pcicomm;
58488f8b78aSgm89044 ushort_t pcistat;
58588f8b78aSgm89044 uchar_t cachelinesz;
58688f8b78aSgm89044 uchar_t mingnt;
58788f8b78aSgm89044 uchar_t maxlat;
58888f8b78aSgm89044 uchar_t lattmr;
58988f8b78aSgm89044 #endif
59088f8b78aSgm89044
59188f8b78aSgm89044 instance = ddi_get_instance(dip);
59288f8b78aSgm89044
59388f8b78aSgm89044 DBG(NULL, DMOD, "dca: in dca_attach() for %d", instance);
59488f8b78aSgm89044
59588f8b78aSgm89044 switch (cmd) {
59688f8b78aSgm89044 case DDI_RESUME:
59788f8b78aSgm89044 if ((dca = (dca_t *)ddi_get_driver_private(dip)) == NULL) {
59888f8b78aSgm89044 dca_diperror(dip, "no soft state in detach");
59988f8b78aSgm89044 return (DDI_FAILURE);
60088f8b78aSgm89044 }
60188f8b78aSgm89044 /* assumption: we won't be DDI_DETACHed until we return */
60288f8b78aSgm89044 return (dca_resume(dca));
60388f8b78aSgm89044 case DDI_ATTACH:
60488f8b78aSgm89044 break;
60588f8b78aSgm89044 default:
60688f8b78aSgm89044 return (DDI_FAILURE);
60788f8b78aSgm89044 }
60888f8b78aSgm89044
60988f8b78aSgm89044 if (ddi_slaveonly(dip) == DDI_SUCCESS) {
61088f8b78aSgm89044 dca_diperror(dip, "slot does not support PCI bus-master");
61188f8b78aSgm89044 return (DDI_FAILURE);
61288f8b78aSgm89044 }
61388f8b78aSgm89044
61488f8b78aSgm89044 if (ddi_intr_hilevel(dip, 0) != 0) {
61588f8b78aSgm89044 dca_diperror(dip, "hilevel interrupts not supported");
61688f8b78aSgm89044 return (DDI_FAILURE);
61788f8b78aSgm89044 }
61888f8b78aSgm89044
61988f8b78aSgm89044 if (pci_config_setup(dip, &pci) != DDI_SUCCESS) {
62088f8b78aSgm89044 dca_diperror(dip, "unable to setup PCI config handle");
62188f8b78aSgm89044 return (DDI_FAILURE);
62288f8b78aSgm89044 }
62388f8b78aSgm89044
62488f8b78aSgm89044 /* common PCI attributes */
62588f8b78aSgm89044 venid = pci_config_get16(pci, PCI_VENID);
62688f8b78aSgm89044 devid = pci_config_get16(pci, PCI_DEVID);
62788f8b78aSgm89044 revid = pci_config_get8(pci, PCI_REVID);
62888f8b78aSgm89044 subvenid = pci_config_get16(pci, PCI_SUBVENID);
62988f8b78aSgm89044 subsysid = pci_config_get16(pci, PCI_SUBSYSID);
63088f8b78aSgm89044
63188f8b78aSgm89044 /*
63288f8b78aSgm89044 * Broadcom-specific timings.
63388f8b78aSgm89044 * We disable these timers/counters since they can cause
63488f8b78aSgm89044 * incorrect false failures when the bus is just a little
63588f8b78aSgm89044 * bit slow, or busy.
63688f8b78aSgm89044 */
63788f8b78aSgm89044 pci_config_put8(pci, PCI_TRDYTO, 0);
63888f8b78aSgm89044 pci_config_put8(pci, PCI_RETRIES, 0);
63988f8b78aSgm89044
64088f8b78aSgm89044 /* initialize PCI access settings */
64188f8b78aSgm89044 pci_config_put16(pci, PCI_COMM, PCICOMM_SEE |
64288f8b78aSgm89044 PCICOMM_PEE | PCICOMM_BME | PCICOMM_MAE);
64388f8b78aSgm89044
64488f8b78aSgm89044 /* set up our PCI latency timer */
64588f8b78aSgm89044 pci_config_put8(pci, PCI_LATTMR, 0x40);
64688f8b78aSgm89044
64788f8b78aSgm89044 #if DEBUG
64888f8b78aSgm89044 /* read registers (for debugging) */
64988f8b78aSgm89044 pcicomm = pci_config_get16(pci, PCI_COMM);
65088f8b78aSgm89044 pcistat = pci_config_get16(pci, PCI_STATUS);
65188f8b78aSgm89044 cachelinesz = pci_config_get8(pci, PCI_CACHELINESZ);
65288f8b78aSgm89044 mingnt = pci_config_get8(pci, PCI_MINGNT);
65388f8b78aSgm89044 maxlat = pci_config_get8(pci, PCI_MAXLAT);
65488f8b78aSgm89044 lattmr = pci_config_get8(pci, PCI_LATTMR);
65588f8b78aSgm89044 #endif
65688f8b78aSgm89044
65788f8b78aSgm89044 pci_config_teardown(&pci);
65888f8b78aSgm89044
65988f8b78aSgm89044 if (ddi_get_iblock_cookie(dip, 0, &ibc) != DDI_SUCCESS) {
66088f8b78aSgm89044 dca_diperror(dip, "unable to get iblock cookie");
66188f8b78aSgm89044 return (DDI_FAILURE);
66288f8b78aSgm89044 }
66388f8b78aSgm89044
66488f8b78aSgm89044 if (ddi_soft_state_zalloc(dca_state, instance) != DDI_SUCCESS) {
66588f8b78aSgm89044 dca_diperror(dip, "unable to allocate soft state");
66688f8b78aSgm89044 return (DDI_FAILURE);
66788f8b78aSgm89044 }
66888f8b78aSgm89044
66988f8b78aSgm89044 dca = ddi_get_soft_state(dca_state, instance);
67088f8b78aSgm89044 ASSERT(dca != NULL);
67188f8b78aSgm89044 dca->dca_dip = dip;
67288f8b78aSgm89044 WORKLIST(dca, MCR1)->dwl_prov = NULL;
67388f8b78aSgm89044 WORKLIST(dca, MCR2)->dwl_prov = NULL;
67488f8b78aSgm89044 /* figure pagesize */
67588f8b78aSgm89044 dca->dca_pagesize = ddi_ptob(dip, 1);
67688f8b78aSgm89044
67788f8b78aSgm89044 /*
67888f8b78aSgm89044 * Search for the device in our supported devices table. This
67988f8b78aSgm89044 * is here for two reasons. First, we want to ensure that
68088f8b78aSgm89044 * only Sun-qualified (and presumably Sun-labeled) devices can
68188f8b78aSgm89044 * be used with this driver. Second, some devices have
68288f8b78aSgm89044 * specific differences. E.g. the 5821 has support for a
68388f8b78aSgm89044 * special mode of RC4, deeper queues, power management, and
68488f8b78aSgm89044 * other changes. Also, the export versions of some of these
68588f8b78aSgm89044 * chips don't support RC4 or 3DES, so we catch that here.
68688f8b78aSgm89044 *
68788f8b78aSgm89044 * Note that we only look at the upper nibble of the device
68888f8b78aSgm89044 * id, which is used to distinguish export vs. domestic
68988f8b78aSgm89044 * versions of the chip. (The lower nibble is used for
69088f8b78aSgm89044 * stepping information.)
69188f8b78aSgm89044 */
69288f8b78aSgm89044 for (i = 0; i < (sizeof (dca_devices) / sizeof (dca_device_t)); i++) {
69388f8b78aSgm89044 /*
69488f8b78aSgm89044 * Try to match the subsystem information first.
69588f8b78aSgm89044 */
69688f8b78aSgm89044 if (subvenid && (subvenid == dca_devices[i].dd_vendor_id) &&
69788f8b78aSgm89044 subsysid && (subsysid == dca_devices[i].dd_device_id)) {
69888f8b78aSgm89044 dca->dca_model = dca_devices[i].dd_model;
6993383b6ddSqs148142 dca->dca_devid = dca_devices[i].dd_device_id;
70088f8b78aSgm89044 break;
70188f8b78aSgm89044 }
70288f8b78aSgm89044 /*
70388f8b78aSgm89044 * Failing that, try the generic vendor and device id.
70488f8b78aSgm89044 * Even if we find a match, we keep searching anyway,
70588f8b78aSgm89044 * since we would prefer to find a match based on the
70688f8b78aSgm89044 * subsystem ids.
70788f8b78aSgm89044 */
70888f8b78aSgm89044 if ((venid == dca_devices[i].dd_vendor_id) &&
70988f8b78aSgm89044 (devid == dca_devices[i].dd_device_id)) {
71088f8b78aSgm89044 dca->dca_model = dca_devices[i].dd_model;
7113383b6ddSqs148142 dca->dca_devid = dca_devices[i].dd_device_id;
71288f8b78aSgm89044 }
71388f8b78aSgm89044 }
71488f8b78aSgm89044 /* try and handle an unrecognized device */
71588f8b78aSgm89044 if (dca->dca_model == NULL) {
71688f8b78aSgm89044 dca->dca_model = unknowndev;
71788f8b78aSgm89044 dca_error(dca, "device not recognized, not supported");
71888f8b78aSgm89044 DBG(dca, DPCI, "i=%d venid=%x devid=%x rev=%d",
71988f8b78aSgm89044 i, venid, devid, revid);
72088f8b78aSgm89044 }
72188f8b78aSgm89044
72288f8b78aSgm89044 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "description",
72388f8b78aSgm89044 dca->dca_model) != DDI_SUCCESS) {
72488f8b78aSgm89044 dca_error(dca, "unable to create description property");
72588f8b78aSgm89044 return (DDI_FAILURE);
72688f8b78aSgm89044 }
72788f8b78aSgm89044
72888f8b78aSgm89044 DBG(dca, DPCI, "PCI command=0x%x status=%x cachelinesz=%x",
72988f8b78aSgm89044 pcicomm, pcistat, cachelinesz);
73088f8b78aSgm89044 DBG(dca, DPCI, "mingnt=0x%x maxlat=0x%x lattmr=0x%x",
73188f8b78aSgm89044 mingnt, maxlat, lattmr);
73288f8b78aSgm89044
73388f8b78aSgm89044 /*
73488f8b78aSgm89044 * initialize locks, etc.
73588f8b78aSgm89044 */
73688f8b78aSgm89044 (void) mutex_init(&dca->dca_intrlock, NULL, MUTEX_DRIVER, ibc);
73788f8b78aSgm89044
73888f8b78aSgm89044 /* use RNGSHA1 by default */
73988f8b78aSgm89044 if (ddi_getprop(DDI_DEV_T_ANY, dip,
74088f8b78aSgm89044 DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "rngdirect", 0) == 0) {
74188f8b78aSgm89044 dca->dca_flags |= DCA_RNGSHA1;
74288f8b78aSgm89044 }
74388f8b78aSgm89044
74488f8b78aSgm89044 /* initialize FMA */
74588f8b78aSgm89044 dca_fma_init(dca);
74688f8b78aSgm89044
74788f8b78aSgm89044 /* initialize some key data structures */
74888f8b78aSgm89044 if (dca_init(dca) != DDI_SUCCESS) {
74988f8b78aSgm89044 goto failed;
75088f8b78aSgm89044 }
75188f8b78aSgm89044
75288f8b78aSgm89044 /* initialize kstats */
75388f8b78aSgm89044 dca_ksinit(dca);
75488f8b78aSgm89044
75588f8b78aSgm89044 /* setup access to registers */
75688f8b78aSgm89044 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&dca->dca_regs,
75788f8b78aSgm89044 0, 0, &dca_regsattr, &dca->dca_regs_handle) != DDI_SUCCESS) {
75888f8b78aSgm89044 dca_error(dca, "unable to map registers");
75988f8b78aSgm89044 goto failed;
76088f8b78aSgm89044 }
76188f8b78aSgm89044
76288f8b78aSgm89044 DBG(dca, DCHATTY, "MCR1 = %x", GETCSR(dca, CSR_MCR1));
76388f8b78aSgm89044 DBG(dca, DCHATTY, "CONTROL = %x", GETCSR(dca, CSR_DMACTL));
76488f8b78aSgm89044 DBG(dca, DCHATTY, "STATUS = %x", GETCSR(dca, CSR_DMASTAT));
76588f8b78aSgm89044 DBG(dca, DCHATTY, "DMAEA = %x", GETCSR(dca, CSR_DMAEA));
76688f8b78aSgm89044 DBG(dca, DCHATTY, "MCR2 = %x", GETCSR(dca, CSR_MCR2));
76788f8b78aSgm89044
76888f8b78aSgm89044 /* reset the chip */
76988f8b78aSgm89044 if (dca_reset(dca, 0) < 0) {
77088f8b78aSgm89044 goto failed;
77188f8b78aSgm89044 }
77288f8b78aSgm89044
77388f8b78aSgm89044 /* initialize the chip */
77488f8b78aSgm89044 PUTCSR(dca, CSR_DMACTL, DMACTL_BE32 | DMACTL_BE64);
77588f8b78aSgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle,
77688f8b78aSgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
77788f8b78aSgm89044 goto failed;
77888f8b78aSgm89044 }
77988f8b78aSgm89044
78088f8b78aSgm89044 /* add the interrupt */
78188f8b78aSgm89044 if (ddi_add_intr(dip, 0, &dca->dca_icookie, NULL, dca_intr,
78288f8b78aSgm89044 (void *)dca) != DDI_SUCCESS) {
78388f8b78aSgm89044 DBG(dca, DWARN, "ddi_add_intr failed");
78488f8b78aSgm89044 goto failed;
78588f8b78aSgm89044 } else {
78688f8b78aSgm89044 intr_added = 1;
78788f8b78aSgm89044 }
78888f8b78aSgm89044
78988f8b78aSgm89044 /* enable interrupts on the device */
79088f8b78aSgm89044 /*
79188f8b78aSgm89044 * XXX: Note, 5820A1 errata indicates that this may clobber
79288f8b78aSgm89044 * bits 24 and 23, which affect the speed of the RNG. Since
79388f8b78aSgm89044 * we always want to run in full-speed mode, this should be
79488f8b78aSgm89044 * harmless.
79588f8b78aSgm89044 */
7963383b6ddSqs148142 if (dca->dca_devid == 0x5825) {
7973383b6ddSqs148142 /* for 5825 - increase the DMA read size */
7983383b6ddSqs148142 SETBIT(dca, CSR_DMACTL,
7993383b6ddSqs148142 DMACTL_MCR1IE | DMACTL_MCR2IE | DMACTL_EIE | DMACTL_RD256);
8003383b6ddSqs148142 } else {
8013383b6ddSqs148142 SETBIT(dca, CSR_DMACTL,
8023383b6ddSqs148142 DMACTL_MCR1IE | DMACTL_MCR2IE | DMACTL_EIE);
8033383b6ddSqs148142 }
80488f8b78aSgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle,
80588f8b78aSgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
80688f8b78aSgm89044 goto failed;
80788f8b78aSgm89044 }
80888f8b78aSgm89044
80988f8b78aSgm89044 /* register MCR1 with the crypto framework */
81088f8b78aSgm89044 /* Be careful not to exceed 32 chars */
81188f8b78aSgm89044 (void) sprintf(ID, "%s/%d %s",
81288f8b78aSgm89044 ddi_driver_name(dip), ddi_get_instance(dip), IDENT_SYM);
81388f8b78aSgm89044 dca_prov_info1.pi_provider_description = ID;
81488f8b78aSgm89044 dca_prov_info1.pi_provider_dev.pd_hw = dip;
81588f8b78aSgm89044 dca_prov_info1.pi_provider_handle = dca;
81688f8b78aSgm89044 if ((ret = crypto_register_provider(&dca_prov_info1,
81788f8b78aSgm89044 &WORKLIST(dca, MCR1)->dwl_prov)) != CRYPTO_SUCCESS) {
81888f8b78aSgm89044 cmn_err(CE_WARN,
81988f8b78aSgm89044 "crypto_register_provider() failed (%d) for MCR1", ret);
82088f8b78aSgm89044 goto failed;
82188f8b78aSgm89044 }
82288f8b78aSgm89044
82388f8b78aSgm89044 /* register MCR2 with the crypto framework */
82488f8b78aSgm89044 /* Be careful not to exceed 32 chars */
82588f8b78aSgm89044 (void) sprintf(ID, "%s/%d %s",
82688f8b78aSgm89044 ddi_driver_name(dip), ddi_get_instance(dip), IDENT_ASYM);
82788f8b78aSgm89044 dca_prov_info2.pi_provider_description = ID;
82888f8b78aSgm89044 dca_prov_info2.pi_provider_dev.pd_hw = dip;
82988f8b78aSgm89044 dca_prov_info2.pi_provider_handle = dca;
83088f8b78aSgm89044 if ((ret = crypto_register_provider(&dca_prov_info2,
83188f8b78aSgm89044 &WORKLIST(dca, MCR2)->dwl_prov)) != CRYPTO_SUCCESS) {
83288f8b78aSgm89044 cmn_err(CE_WARN,
83388f8b78aSgm89044 "crypto_register_provider() failed (%d) for MCR2", ret);
83488f8b78aSgm89044 goto failed;
83588f8b78aSgm89044 }
83688f8b78aSgm89044
83788f8b78aSgm89044 crypto_prov_notify(WORKLIST(dca, MCR1)->dwl_prov,
83888f8b78aSgm89044 CRYPTO_PROVIDER_READY);
83988f8b78aSgm89044 crypto_prov_notify(WORKLIST(dca, MCR2)->dwl_prov,
84088f8b78aSgm89044 CRYPTO_PROVIDER_READY);
84188f8b78aSgm89044
84288f8b78aSgm89044 /* Initialize the local random number pool for this instance */
84388f8b78aSgm89044 if ((ret = dca_random_init(dca)) != CRYPTO_SUCCESS) {
84488f8b78aSgm89044 goto failed;
84588f8b78aSgm89044 }
84688f8b78aSgm89044
84788f8b78aSgm89044 mutex_enter(&dca->dca_intrlock);
84888f8b78aSgm89044 dca->dca_jobtid = timeout(dca_jobtimeout, (void *)dca,
84988f8b78aSgm89044 drv_usectohz(SECOND));
85088f8b78aSgm89044 mutex_exit(&dca->dca_intrlock);
85188f8b78aSgm89044
85288f8b78aSgm89044 ddi_set_driver_private(dip, (caddr_t)dca);
85388f8b78aSgm89044
85488f8b78aSgm89044 ddi_report_dev(dip);
85588f8b78aSgm89044
85688f8b78aSgm89044 if (ddi_get_devstate(dca->dca_dip) != DDI_DEVSTATE_UP) {
85788f8b78aSgm89044 ddi_fm_service_impact(dca->dca_dip, DDI_SERVICE_RESTORED);
85888f8b78aSgm89044 }
85988f8b78aSgm89044
86088f8b78aSgm89044 return (DDI_SUCCESS);
86188f8b78aSgm89044
86288f8b78aSgm89044 failed:
86388f8b78aSgm89044 /* unregister from the crypto framework */
86488f8b78aSgm89044 if (WORKLIST(dca, MCR1)->dwl_prov != NULL) {
865d8dd9913Sgm89044 (void) crypto_unregister_provider(
866d8dd9913Sgm89044 WORKLIST(dca, MCR1)->dwl_prov);
86788f8b78aSgm89044 }
86888f8b78aSgm89044 if (WORKLIST(dca, MCR2)->dwl_prov != NULL) {
869d8dd9913Sgm89044 (void) crypto_unregister_provider(
870d8dd9913Sgm89044 WORKLIST(dca, MCR2)->dwl_prov);
87188f8b78aSgm89044 }
87288f8b78aSgm89044 if (intr_added) {
87388f8b78aSgm89044 CLRBIT(dca, CSR_DMACTL,
87488f8b78aSgm89044 DMACTL_MCR1IE | DMACTL_MCR2IE | DMACTL_EIE);
87588f8b78aSgm89044 /* unregister intr handler */
87688f8b78aSgm89044 ddi_remove_intr(dip, 0, dca->dca_icookie);
87788f8b78aSgm89044 }
87888f8b78aSgm89044 if (dca->dca_regs_handle) {
87988f8b78aSgm89044 ddi_regs_map_free(&dca->dca_regs_handle);
88088f8b78aSgm89044 }
88188f8b78aSgm89044 if (dca->dca_intrstats) {
88288f8b78aSgm89044 kstat_delete(dca->dca_intrstats);
88388f8b78aSgm89044 }
88488f8b78aSgm89044 if (dca->dca_ksp) {
88588f8b78aSgm89044 kstat_delete(dca->dca_ksp);
88688f8b78aSgm89044 }
88788f8b78aSgm89044 dca_uninit(dca);
88888f8b78aSgm89044
88988f8b78aSgm89044 /* finalize FMA */
89088f8b78aSgm89044 dca_fma_fini(dca);
89188f8b78aSgm89044
89288f8b78aSgm89044 mutex_destroy(&dca->dca_intrlock);
89388f8b78aSgm89044 ddi_soft_state_free(dca_state, instance);
89488f8b78aSgm89044 return (DDI_FAILURE);
89588f8b78aSgm89044
89688f8b78aSgm89044 }
89788f8b78aSgm89044
89888f8b78aSgm89044 int
dca_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)89988f8b78aSgm89044 dca_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
90088f8b78aSgm89044 {
90188f8b78aSgm89044 int instance;
90288f8b78aSgm89044 dca_t *dca;
90388f8b78aSgm89044 timeout_id_t tid;
90488f8b78aSgm89044
90588f8b78aSgm89044 instance = ddi_get_instance(dip);
90688f8b78aSgm89044
90788f8b78aSgm89044 DBG(NULL, DMOD, "dca: in dca_detach() for %d", instance);
90888f8b78aSgm89044
90988f8b78aSgm89044 switch (cmd) {
91088f8b78aSgm89044 case DDI_SUSPEND:
91188f8b78aSgm89044 if ((dca = (dca_t *)ddi_get_driver_private(dip)) == NULL) {
91288f8b78aSgm89044 dca_diperror(dip, "no soft state in detach");
91388f8b78aSgm89044 return (DDI_FAILURE);
91488f8b78aSgm89044 }
91588f8b78aSgm89044 /* assumption: we won't be DDI_DETACHed until we return */
91688f8b78aSgm89044 return (dca_suspend(dca));
91788f8b78aSgm89044
91888f8b78aSgm89044 case DDI_DETACH:
91988f8b78aSgm89044 break;
92088f8b78aSgm89044 default:
92188f8b78aSgm89044 return (DDI_FAILURE);
92288f8b78aSgm89044 }
92388f8b78aSgm89044
92488f8b78aSgm89044 if ((dca = (dca_t *)ddi_get_driver_private(dip)) == NULL) {
92588f8b78aSgm89044 dca_diperror(dip, "no soft state in detach");
92688f8b78aSgm89044 return (DDI_FAILURE);
92788f8b78aSgm89044 }
92888f8b78aSgm89044
92988f8b78aSgm89044 /*
93088f8b78aSgm89044 * Unregister from kCF.
93188f8b78aSgm89044 * This needs to be done at the beginning of detach.
93288f8b78aSgm89044 */
93388f8b78aSgm89044 if (WORKLIST(dca, MCR1)->dwl_prov != NULL) {
934d8dd9913Sgm89044 if (crypto_unregister_provider(
935d8dd9913Sgm89044 WORKLIST(dca, MCR1)->dwl_prov) != CRYPTO_SUCCESS) {
93688f8b78aSgm89044 dca_error(dca, "unable to unregister MCR1 from kcf");
93788f8b78aSgm89044 return (DDI_FAILURE);
93888f8b78aSgm89044 }
93988f8b78aSgm89044 }
94088f8b78aSgm89044
94188f8b78aSgm89044 if (WORKLIST(dca, MCR2)->dwl_prov != NULL) {
942d8dd9913Sgm89044 if (crypto_unregister_provider(
943d8dd9913Sgm89044 WORKLIST(dca, MCR2)->dwl_prov) != CRYPTO_SUCCESS) {
94488f8b78aSgm89044 dca_error(dca, "unable to unregister MCR2 from kcf");
94588f8b78aSgm89044 return (DDI_FAILURE);
94688f8b78aSgm89044 }
94788f8b78aSgm89044 }
94888f8b78aSgm89044
94988f8b78aSgm89044 /*
95088f8b78aSgm89044 * Cleanup the private context list. Once the
95188f8b78aSgm89044 * crypto_unregister_provider returns, it is safe to do so.
95288f8b78aSgm89044 */
95388f8b78aSgm89044 dca_free_context_list(dca);
95488f8b78aSgm89044
95588f8b78aSgm89044 /* Cleanup the local random number pool */
95688f8b78aSgm89044 dca_random_fini(dca);
95788f8b78aSgm89044
95888f8b78aSgm89044 /* send any jobs in the waitq back to kCF */
95988f8b78aSgm89044 dca_rejectjobs(dca);
96088f8b78aSgm89044
96188f8b78aSgm89044 /* untimeout the timeouts */
96288f8b78aSgm89044 mutex_enter(&dca->dca_intrlock);
96388f8b78aSgm89044 tid = dca->dca_jobtid;
96488f8b78aSgm89044 dca->dca_jobtid = 0;
96588f8b78aSgm89044 mutex_exit(&dca->dca_intrlock);
96688f8b78aSgm89044 if (tid) {
96788f8b78aSgm89044 (void) untimeout(tid);
96888f8b78aSgm89044 }
96988f8b78aSgm89044
97088f8b78aSgm89044 /* disable device interrupts */
97188f8b78aSgm89044 CLRBIT(dca, CSR_DMACTL, DMACTL_MCR1IE | DMACTL_MCR2IE | DMACTL_EIE);
97288f8b78aSgm89044
97388f8b78aSgm89044 /* unregister interrupt handlers */
97488f8b78aSgm89044 ddi_remove_intr(dip, 0, dca->dca_icookie);
97588f8b78aSgm89044
97688f8b78aSgm89044 /* release our regs handle */
97788f8b78aSgm89044 ddi_regs_map_free(&dca->dca_regs_handle);
97888f8b78aSgm89044
97988f8b78aSgm89044 /* toss out kstats */
98088f8b78aSgm89044 if (dca->dca_intrstats) {
98188f8b78aSgm89044 kstat_delete(dca->dca_intrstats);
98288f8b78aSgm89044 }
98388f8b78aSgm89044 if (dca->dca_ksp) {
98488f8b78aSgm89044 kstat_delete(dca->dca_ksp);
98588f8b78aSgm89044 }
98688f8b78aSgm89044
98788f8b78aSgm89044 mutex_destroy(&dca->dca_intrlock);
98888f8b78aSgm89044 dca_uninit(dca);
98988f8b78aSgm89044
99088f8b78aSgm89044 /* finalize FMA */
99188f8b78aSgm89044 dca_fma_fini(dca);
99288f8b78aSgm89044
99388f8b78aSgm89044 ddi_soft_state_free(dca_state, instance);
99488f8b78aSgm89044
99588f8b78aSgm89044 return (DDI_SUCCESS);
99688f8b78aSgm89044 }
99788f8b78aSgm89044
99888f8b78aSgm89044 int
dca_resume(dca_t * dca)99988f8b78aSgm89044 dca_resume(dca_t *dca)
100088f8b78aSgm89044 {
100188f8b78aSgm89044 ddi_acc_handle_t pci;
100288f8b78aSgm89044
100388f8b78aSgm89044 if (pci_config_setup(dca->dca_dip, &pci) != DDI_SUCCESS) {
100488f8b78aSgm89044 dca_error(dca, "unable to setup PCI config handle");
100588f8b78aSgm89044 return (DDI_FAILURE);
100688f8b78aSgm89044 }
100788f8b78aSgm89044
100888f8b78aSgm89044 /*
100988f8b78aSgm89044 * Reprogram registers in PCI configuration space.
101088f8b78aSgm89044 */
101188f8b78aSgm89044
101288f8b78aSgm89044 /* Broadcom-specific timers -- we disable them. */
101388f8b78aSgm89044 pci_config_put8(pci, PCI_TRDYTO, 0);
101488f8b78aSgm89044 pci_config_put8(pci, PCI_RETRIES, 0);
101588f8b78aSgm89044
101688f8b78aSgm89044 /* initialize PCI access settings */
101788f8b78aSgm89044 pci_config_put16(pci, PCI_COMM, PCICOMM_SEE |
101888f8b78aSgm89044 PCICOMM_PEE | PCICOMM_BME | PCICOMM_MAE);
101988f8b78aSgm89044
102088f8b78aSgm89044 /* set up our PCI latency timer */
102188f8b78aSgm89044 pci_config_put8(pci, PCI_LATTMR, 0x40);
102288f8b78aSgm89044
102388f8b78aSgm89044 pci_config_teardown(&pci);
102488f8b78aSgm89044
102588f8b78aSgm89044 if (dca_reset(dca, 0) < 0) {
102688f8b78aSgm89044 dca_error(dca, "unable to reset device during resume");
102788f8b78aSgm89044 return (DDI_FAILURE);
102888f8b78aSgm89044 }
102988f8b78aSgm89044
103088f8b78aSgm89044 /*
103188f8b78aSgm89044 * Now restore the card-specific CSRs.
103288f8b78aSgm89044 */
103388f8b78aSgm89044
103488f8b78aSgm89044 /* restore endianness settings */
103588f8b78aSgm89044 PUTCSR(dca, CSR_DMACTL, DMACTL_BE32 | DMACTL_BE64);
103688f8b78aSgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle,
103788f8b78aSgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS)
103888f8b78aSgm89044 return (DDI_FAILURE);
103988f8b78aSgm89044
104088f8b78aSgm89044 /* restore interrupt enables */
10413383b6ddSqs148142 if (dca->dca_devid == 0x5825) {
10423383b6ddSqs148142 /* for 5825 set 256 byte read size to improve performance */
10433383b6ddSqs148142 SETBIT(dca, CSR_DMACTL,
10443383b6ddSqs148142 DMACTL_MCR1IE | DMACTL_MCR2IE | DMACTL_EIE | DMACTL_RD256);
10453383b6ddSqs148142 } else {
10463383b6ddSqs148142 SETBIT(dca, CSR_DMACTL,
10473383b6ddSqs148142 DMACTL_MCR1IE | DMACTL_MCR2IE | DMACTL_EIE);
10483383b6ddSqs148142 }
104988f8b78aSgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle,
105088f8b78aSgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS)
105188f8b78aSgm89044 return (DDI_FAILURE);
105288f8b78aSgm89044
105388f8b78aSgm89044 /* resume scheduling jobs on the device */
105488f8b78aSgm89044 dca_undrain(dca);
105588f8b78aSgm89044
105688f8b78aSgm89044 return (DDI_SUCCESS);
105788f8b78aSgm89044 }
105888f8b78aSgm89044
105988f8b78aSgm89044 int
dca_suspend(dca_t * dca)106088f8b78aSgm89044 dca_suspend(dca_t *dca)
106188f8b78aSgm89044 {
106288f8b78aSgm89044 if ((dca_drain(dca)) != 0) {
106388f8b78aSgm89044 return (DDI_FAILURE);
106488f8b78aSgm89044 }
106588f8b78aSgm89044 if (dca_reset(dca, 0) < 0) {
106688f8b78aSgm89044 dca_error(dca, "unable to reset device during suspend");
106788f8b78aSgm89044 return (DDI_FAILURE);
106888f8b78aSgm89044 }
106988f8b78aSgm89044 return (DDI_SUCCESS);
107088f8b78aSgm89044 }
107188f8b78aSgm89044
107288f8b78aSgm89044 /*
107388f8b78aSgm89044 * Hardware access stuff.
107488f8b78aSgm89044 */
107588f8b78aSgm89044 int
dca_reset(dca_t * dca,int failreset)107688f8b78aSgm89044 dca_reset(dca_t *dca, int failreset)
107788f8b78aSgm89044 {
107888f8b78aSgm89044 int i;
107988f8b78aSgm89044
108088f8b78aSgm89044 if (dca->dca_regs_handle == NULL) {
108188f8b78aSgm89044 return (-1);
108288f8b78aSgm89044 }
108388f8b78aSgm89044
108488f8b78aSgm89044 PUTCSR(dca, CSR_DMACTL, DMACTL_RESET);
108588f8b78aSgm89044 if (!failreset) {
108688f8b78aSgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle,
108788f8b78aSgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS)
108888f8b78aSgm89044 return (-1);
108988f8b78aSgm89044 }
109088f8b78aSgm89044
109188f8b78aSgm89044 /* now wait for a reset */
109288f8b78aSgm89044 for (i = 1; i < 100; i++) {
109388f8b78aSgm89044 uint32_t dmactl;
109488f8b78aSgm89044 drv_usecwait(100);
109588f8b78aSgm89044 dmactl = GETCSR(dca, CSR_DMACTL);
109688f8b78aSgm89044 if (!failreset) {
109788f8b78aSgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle,
109888f8b78aSgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS)
109988f8b78aSgm89044 return (-1);
110088f8b78aSgm89044 }
110188f8b78aSgm89044 if ((dmactl & DMACTL_RESET) == 0) {
110288f8b78aSgm89044 DBG(dca, DCHATTY, "reset in %d usec", i * 100);
110388f8b78aSgm89044 return (0);
110488f8b78aSgm89044 }
110588f8b78aSgm89044 }
110688f8b78aSgm89044 if (!failreset) {
110788f8b78aSgm89044 dca_failure(dca, DDI_DEVICE_FAULT,
110888f8b78aSgm89044 DCA_FM_ECLASS_NONE, dca_ena(0), CRYPTO_DEVICE_ERROR,
110988f8b78aSgm89044 "timeout waiting for reset after %d usec", i * 100);
111088f8b78aSgm89044 }
111188f8b78aSgm89044 return (-1);
111288f8b78aSgm89044 }
111388f8b78aSgm89044
111488f8b78aSgm89044 int
dca_initworklist(dca_t * dca,dca_worklist_t * wlp)111588f8b78aSgm89044 dca_initworklist(dca_t *dca, dca_worklist_t *wlp)
111688f8b78aSgm89044 {
111788f8b78aSgm89044 int i;
111888f8b78aSgm89044 int reqprealloc = wlp->dwl_hiwater + (MAXWORK * MAXREQSPERMCR);
111988f8b78aSgm89044
112088f8b78aSgm89044 /*
112188f8b78aSgm89044 * Set up work queue.
112288f8b78aSgm89044 */
112388f8b78aSgm89044 mutex_init(&wlp->dwl_lock, NULL, MUTEX_DRIVER, dca->dca_icookie);
112488f8b78aSgm89044 mutex_init(&wlp->dwl_freereqslock, NULL, MUTEX_DRIVER,
112588f8b78aSgm89044 dca->dca_icookie);
11263383b6ddSqs148142 mutex_init(&wlp->dwl_freelock, NULL, MUTEX_DRIVER, dca->dca_icookie);
112788f8b78aSgm89044 cv_init(&wlp->dwl_cv, NULL, CV_DRIVER, NULL);
112888f8b78aSgm89044
112988f8b78aSgm89044 mutex_enter(&wlp->dwl_lock);
113088f8b78aSgm89044
113188f8b78aSgm89044 dca_initq(&wlp->dwl_freereqs);
113288f8b78aSgm89044 dca_initq(&wlp->dwl_waitq);
113388f8b78aSgm89044 dca_initq(&wlp->dwl_freework);
113488f8b78aSgm89044 dca_initq(&wlp->dwl_runq);
113588f8b78aSgm89044
113688f8b78aSgm89044 for (i = 0; i < MAXWORK; i++) {
113788f8b78aSgm89044 dca_work_t *workp;
113888f8b78aSgm89044
113988f8b78aSgm89044 if ((workp = dca_newwork(dca)) == NULL) {
114088f8b78aSgm89044 dca_error(dca, "unable to allocate work");
114188f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
114288f8b78aSgm89044 return (DDI_FAILURE);
114388f8b78aSgm89044 }
114488f8b78aSgm89044 workp->dw_wlp = wlp;
114588f8b78aSgm89044 dca_freework(workp);
114688f8b78aSgm89044 }
114788f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
114888f8b78aSgm89044
114988f8b78aSgm89044 for (i = 0; i < reqprealloc; i++) {
115088f8b78aSgm89044 dca_request_t *reqp;
115188f8b78aSgm89044
115288f8b78aSgm89044 if ((reqp = dca_newreq(dca)) == NULL) {
115388f8b78aSgm89044 dca_error(dca, "unable to allocate request");
115488f8b78aSgm89044 return (DDI_FAILURE);
115588f8b78aSgm89044 }
115688f8b78aSgm89044 reqp->dr_dca = dca;
115788f8b78aSgm89044 reqp->dr_wlp = wlp;
115888f8b78aSgm89044 dca_freereq(reqp);
115988f8b78aSgm89044 }
116088f8b78aSgm89044 return (DDI_SUCCESS);
116188f8b78aSgm89044 }
116288f8b78aSgm89044
116388f8b78aSgm89044 int
dca_init(dca_t * dca)116488f8b78aSgm89044 dca_init(dca_t *dca)
116588f8b78aSgm89044 {
116688f8b78aSgm89044 dca_worklist_t *wlp;
116788f8b78aSgm89044
116888f8b78aSgm89044 /* Initialize the private context list and the corresponding lock. */
116988f8b78aSgm89044 mutex_init(&dca->dca_ctx_list_lock, NULL, MUTEX_DRIVER, NULL);
117088f8b78aSgm89044 dca_initq(&dca->dca_ctx_list);
117188f8b78aSgm89044
117288f8b78aSgm89044 /*
117388f8b78aSgm89044 * MCR1 algorithms.
117488f8b78aSgm89044 */
117588f8b78aSgm89044 wlp = WORKLIST(dca, MCR1);
117688f8b78aSgm89044 (void) sprintf(wlp->dwl_name, "dca%d:mcr1",
117788f8b78aSgm89044 ddi_get_instance(dca->dca_dip));
117888f8b78aSgm89044 wlp->dwl_lowater = ddi_getprop(DDI_DEV_T_ANY,
117988f8b78aSgm89044 dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
118088f8b78aSgm89044 "mcr1_lowater", MCR1LOWATER);
118188f8b78aSgm89044 wlp->dwl_hiwater = ddi_getprop(DDI_DEV_T_ANY,
118288f8b78aSgm89044 dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
118388f8b78aSgm89044 "mcr1_hiwater", MCR1HIWATER);
118488f8b78aSgm89044 wlp->dwl_reqspermcr = min(ddi_getprop(DDI_DEV_T_ANY,
118588f8b78aSgm89044 dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
118688f8b78aSgm89044 "mcr1_maxreqs", MCR1MAXREQS), MAXREQSPERMCR);
118788f8b78aSgm89044 wlp->dwl_dca = dca;
118888f8b78aSgm89044 wlp->dwl_mcr = MCR1;
118988f8b78aSgm89044 if (dca_initworklist(dca, wlp) != DDI_SUCCESS) {
119088f8b78aSgm89044 return (DDI_FAILURE);
119188f8b78aSgm89044 }
119288f8b78aSgm89044
119388f8b78aSgm89044 /*
119488f8b78aSgm89044 * MCR2 algorithms.
119588f8b78aSgm89044 */
119688f8b78aSgm89044 wlp = WORKLIST(dca, MCR2);
119788f8b78aSgm89044 (void) sprintf(wlp->dwl_name, "dca%d:mcr2",
119888f8b78aSgm89044 ddi_get_instance(dca->dca_dip));
119988f8b78aSgm89044 wlp->dwl_lowater = ddi_getprop(DDI_DEV_T_ANY,
120088f8b78aSgm89044 dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
120188f8b78aSgm89044 "mcr2_lowater", MCR2LOWATER);
120288f8b78aSgm89044 wlp->dwl_hiwater = ddi_getprop(DDI_DEV_T_ANY,
120388f8b78aSgm89044 dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
120488f8b78aSgm89044 "mcr2_hiwater", MCR2HIWATER);
120588f8b78aSgm89044 wlp->dwl_reqspermcr = min(ddi_getprop(DDI_DEV_T_ANY,
120688f8b78aSgm89044 dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
120788f8b78aSgm89044 "mcr2_maxreqs", MCR2MAXREQS), MAXREQSPERMCR);
120888f8b78aSgm89044 wlp->dwl_dca = dca;
120988f8b78aSgm89044 wlp->dwl_mcr = MCR2;
121088f8b78aSgm89044 if (dca_initworklist(dca, wlp) != DDI_SUCCESS) {
121188f8b78aSgm89044 return (DDI_FAILURE);
121288f8b78aSgm89044 }
121388f8b78aSgm89044 return (DDI_SUCCESS);
121488f8b78aSgm89044 }
121588f8b78aSgm89044
121688f8b78aSgm89044 /*
121788f8b78aSgm89044 * Uninitialize worklists. This routine should only be called when no
121888f8b78aSgm89044 * active jobs (hence DMA mappings) exist. One way to ensure this is
121988f8b78aSgm89044 * to unregister from kCF before calling this routine. (This is done
122088f8b78aSgm89044 * e.g. in detach(9e).)
122188f8b78aSgm89044 */
122288f8b78aSgm89044 void
dca_uninit(dca_t * dca)122388f8b78aSgm89044 dca_uninit(dca_t *dca)
122488f8b78aSgm89044 {
122588f8b78aSgm89044 int mcr;
122688f8b78aSgm89044
122788f8b78aSgm89044 mutex_destroy(&dca->dca_ctx_list_lock);
122888f8b78aSgm89044
122988f8b78aSgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) {
123088f8b78aSgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr);
123188f8b78aSgm89044 dca_work_t *workp;
123288f8b78aSgm89044 dca_request_t *reqp;
123388f8b78aSgm89044
123488f8b78aSgm89044 if (dca->dca_regs_handle == NULL) {
123588f8b78aSgm89044 continue;
123688f8b78aSgm89044 }
123788f8b78aSgm89044
123888f8b78aSgm89044 mutex_enter(&wlp->dwl_lock);
123988f8b78aSgm89044 while ((workp = dca_getwork(dca, mcr)) != NULL) {
124088f8b78aSgm89044 dca_destroywork(workp);
124188f8b78aSgm89044 }
124288f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
124388f8b78aSgm89044 while ((reqp = dca_getreq(dca, mcr, 0)) != NULL) {
124488f8b78aSgm89044 dca_destroyreq(reqp);
124588f8b78aSgm89044 }
124688f8b78aSgm89044
124788f8b78aSgm89044 mutex_destroy(&wlp->dwl_lock);
124888f8b78aSgm89044 mutex_destroy(&wlp->dwl_freereqslock);
12493383b6ddSqs148142 mutex_destroy(&wlp->dwl_freelock);
125088f8b78aSgm89044 cv_destroy(&wlp->dwl_cv);
125188f8b78aSgm89044 wlp->dwl_prov = NULL;
125288f8b78aSgm89044 }
125388f8b78aSgm89044 }
125488f8b78aSgm89044
125588f8b78aSgm89044 static void
dca_enlist2(dca_listnode_t * q,dca_listnode_t * node,kmutex_t * lock)125688f8b78aSgm89044 dca_enlist2(dca_listnode_t *q, dca_listnode_t *node, kmutex_t *lock)
125788f8b78aSgm89044 {
125888f8b78aSgm89044 if (!q || !node)
125988f8b78aSgm89044 return;
126088f8b78aSgm89044
126188f8b78aSgm89044 mutex_enter(lock);
126288f8b78aSgm89044 node->dl_next2 = q;
126388f8b78aSgm89044 node->dl_prev2 = q->dl_prev2;
126488f8b78aSgm89044 node->dl_next2->dl_prev2 = node;
126588f8b78aSgm89044 node->dl_prev2->dl_next2 = node;
126688f8b78aSgm89044 mutex_exit(lock);
126788f8b78aSgm89044 }
126888f8b78aSgm89044
126988f8b78aSgm89044 static void
dca_rmlist2(dca_listnode_t * node,kmutex_t * lock)127088f8b78aSgm89044 dca_rmlist2(dca_listnode_t *node, kmutex_t *lock)
127188f8b78aSgm89044 {
127288f8b78aSgm89044 if (!node)
127388f8b78aSgm89044 return;
127488f8b78aSgm89044
127588f8b78aSgm89044 mutex_enter(lock);
127688f8b78aSgm89044 node->dl_next2->dl_prev2 = node->dl_prev2;
127788f8b78aSgm89044 node->dl_prev2->dl_next2 = node->dl_next2;
127888f8b78aSgm89044 node->dl_next2 = NULL;
127988f8b78aSgm89044 node->dl_prev2 = NULL;
128088f8b78aSgm89044 mutex_exit(lock);
128188f8b78aSgm89044 }
128288f8b78aSgm89044
128388f8b78aSgm89044 static dca_listnode_t *
dca_delist2(dca_listnode_t * q,kmutex_t * lock)128488f8b78aSgm89044 dca_delist2(dca_listnode_t *q, kmutex_t *lock)
128588f8b78aSgm89044 {
128688f8b78aSgm89044 dca_listnode_t *node;
128788f8b78aSgm89044
128888f8b78aSgm89044 mutex_enter(lock);
128988f8b78aSgm89044 if ((node = q->dl_next2) == q) {
129088f8b78aSgm89044 mutex_exit(lock);
129188f8b78aSgm89044 return (NULL);
129288f8b78aSgm89044 }
129388f8b78aSgm89044
129488f8b78aSgm89044 node->dl_next2->dl_prev2 = node->dl_prev2;
129588f8b78aSgm89044 node->dl_prev2->dl_next2 = node->dl_next2;
129688f8b78aSgm89044 node->dl_next2 = NULL;
129788f8b78aSgm89044 node->dl_prev2 = NULL;
129888f8b78aSgm89044 mutex_exit(lock);
129988f8b78aSgm89044
130088f8b78aSgm89044 return (node);
130188f8b78aSgm89044 }
130288f8b78aSgm89044
130388f8b78aSgm89044 void
dca_initq(dca_listnode_t * q)130488f8b78aSgm89044 dca_initq(dca_listnode_t *q)
130588f8b78aSgm89044 {
130688f8b78aSgm89044 q->dl_next = q;
130788f8b78aSgm89044 q->dl_prev = q;
130888f8b78aSgm89044 q->dl_next2 = q;
130988f8b78aSgm89044 q->dl_prev2 = q;
131088f8b78aSgm89044 }
131188f8b78aSgm89044
131288f8b78aSgm89044 void
dca_enqueue(dca_listnode_t * q,dca_listnode_t * node)131388f8b78aSgm89044 dca_enqueue(dca_listnode_t *q, dca_listnode_t *node)
131488f8b78aSgm89044 {
131588f8b78aSgm89044 /*
131688f8b78aSgm89044 * Enqueue submits at the "tail" of the list, i.e. just
131788f8b78aSgm89044 * behind the sentinel.
131888f8b78aSgm89044 */
131988f8b78aSgm89044 node->dl_next = q;
132088f8b78aSgm89044 node->dl_prev = q->dl_prev;
132188f8b78aSgm89044 node->dl_next->dl_prev = node;
132288f8b78aSgm89044 node->dl_prev->dl_next = node;
132388f8b78aSgm89044 }
132488f8b78aSgm89044
132588f8b78aSgm89044 void
dca_rmqueue(dca_listnode_t * node)132688f8b78aSgm89044 dca_rmqueue(dca_listnode_t *node)
132788f8b78aSgm89044 {
132888f8b78aSgm89044 node->dl_next->dl_prev = node->dl_prev;
132988f8b78aSgm89044 node->dl_prev->dl_next = node->dl_next;
133088f8b78aSgm89044 node->dl_next = NULL;
133188f8b78aSgm89044 node->dl_prev = NULL;
133288f8b78aSgm89044 }
133388f8b78aSgm89044
133488f8b78aSgm89044 dca_listnode_t *
dca_dequeue(dca_listnode_t * q)133588f8b78aSgm89044 dca_dequeue(dca_listnode_t *q)
133688f8b78aSgm89044 {
133788f8b78aSgm89044 dca_listnode_t *node;
133888f8b78aSgm89044 /*
133988f8b78aSgm89044 * Dequeue takes from the "head" of the list, i.e. just after
134088f8b78aSgm89044 * the sentinel.
134188f8b78aSgm89044 */
134288f8b78aSgm89044 if ((node = q->dl_next) == q) {
134388f8b78aSgm89044 /* queue is empty */
134488f8b78aSgm89044 return (NULL);
134588f8b78aSgm89044 }
134688f8b78aSgm89044 dca_rmqueue(node);
134788f8b78aSgm89044 return (node);
134888f8b78aSgm89044 }
134988f8b78aSgm89044
135088f8b78aSgm89044 /* this is the opposite of dequeue, it takes things off in LIFO order */
135188f8b78aSgm89044 dca_listnode_t *
dca_unqueue(dca_listnode_t * q)135288f8b78aSgm89044 dca_unqueue(dca_listnode_t *q)
135388f8b78aSgm89044 {
135488f8b78aSgm89044 dca_listnode_t *node;
135588f8b78aSgm89044 /*
135688f8b78aSgm89044 * unqueue takes from the "tail" of the list, i.e. just before
135788f8b78aSgm89044 * the sentinel.
135888f8b78aSgm89044 */
1359d8dd9913Sgm89044 if ((node = q->dl_prev) == q) {
136088f8b78aSgm89044 /* queue is empty */
136188f8b78aSgm89044 return (NULL);
136288f8b78aSgm89044 }
136388f8b78aSgm89044 dca_rmqueue(node);
136488f8b78aSgm89044 return (node);
136588f8b78aSgm89044 }
136688f8b78aSgm89044
136788f8b78aSgm89044 dca_listnode_t *
dca_peekqueue(dca_listnode_t * q)136888f8b78aSgm89044 dca_peekqueue(dca_listnode_t *q)
136988f8b78aSgm89044 {
137088f8b78aSgm89044 dca_listnode_t *node;
137188f8b78aSgm89044
137288f8b78aSgm89044 if ((node = q->dl_next) == q) {
137388f8b78aSgm89044 return (NULL);
137488f8b78aSgm89044 } else {
137588f8b78aSgm89044 return (node);
137688f8b78aSgm89044 }
137788f8b78aSgm89044 }
137888f8b78aSgm89044
137988f8b78aSgm89044 /*
138088f8b78aSgm89044 * Interrupt service routine.
138188f8b78aSgm89044 */
138288f8b78aSgm89044 uint_t
dca_intr(char * arg)138388f8b78aSgm89044 dca_intr(char *arg)
138488f8b78aSgm89044 {
138588f8b78aSgm89044 dca_t *dca = (dca_t *)arg;
138688f8b78aSgm89044 uint32_t status;
138788f8b78aSgm89044
138888f8b78aSgm89044 mutex_enter(&dca->dca_intrlock);
138988f8b78aSgm89044 status = GETCSR(dca, CSR_DMASTAT);
139088f8b78aSgm89044 PUTCSR(dca, CSR_DMASTAT, status & DMASTAT_INTERRUPTS);
139188f8b78aSgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle,
139288f8b78aSgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
139388f8b78aSgm89044 mutex_exit(&dca->dca_intrlock);
139488f8b78aSgm89044 return ((uint_t)DDI_FAILURE);
139588f8b78aSgm89044 }
139688f8b78aSgm89044
139788f8b78aSgm89044 DBG(dca, DINTR, "interrupted, status = 0x%x!", status);
139888f8b78aSgm89044
139988f8b78aSgm89044 if ((status & DMASTAT_INTERRUPTS) == 0) {
140088f8b78aSgm89044 /* increment spurious interrupt kstat */
140188f8b78aSgm89044 if (dca->dca_intrstats) {
140288f8b78aSgm89044 KIOIP(dca)->intrs[KSTAT_INTR_SPURIOUS]++;
140388f8b78aSgm89044 }
140488f8b78aSgm89044 mutex_exit(&dca->dca_intrlock);
140588f8b78aSgm89044 return (DDI_INTR_UNCLAIMED);
140688f8b78aSgm89044 }
140788f8b78aSgm89044
140888f8b78aSgm89044 if (dca->dca_intrstats) {
140988f8b78aSgm89044 KIOIP(dca)->intrs[KSTAT_INTR_HARD]++;
141088f8b78aSgm89044 }
141188f8b78aSgm89044 if (status & DMASTAT_MCR1INT) {
141288f8b78aSgm89044 DBG(dca, DINTR, "MCR1 interrupted");
141388f8b78aSgm89044 mutex_enter(&(WORKLIST(dca, MCR1)->dwl_lock));
141488f8b78aSgm89044 dca_schedule(dca, MCR1);
141588f8b78aSgm89044 dca_reclaim(dca, MCR1);
141688f8b78aSgm89044 mutex_exit(&(WORKLIST(dca, MCR1)->dwl_lock));
141788f8b78aSgm89044 }
141888f8b78aSgm89044
141988f8b78aSgm89044 if (status & DMASTAT_MCR2INT) {
142088f8b78aSgm89044 DBG(dca, DINTR, "MCR2 interrupted");
142188f8b78aSgm89044 mutex_enter(&(WORKLIST(dca, MCR2)->dwl_lock));
142288f8b78aSgm89044 dca_schedule(dca, MCR2);
142388f8b78aSgm89044 dca_reclaim(dca, MCR2);
142488f8b78aSgm89044 mutex_exit(&(WORKLIST(dca, MCR2)->dwl_lock));
142588f8b78aSgm89044 }
142688f8b78aSgm89044
142788f8b78aSgm89044 if (status & DMASTAT_ERRINT) {
142888f8b78aSgm89044 uint32_t erraddr;
142988f8b78aSgm89044 erraddr = GETCSR(dca, CSR_DMAEA);
143088f8b78aSgm89044 mutex_exit(&dca->dca_intrlock);
143188f8b78aSgm89044
143288f8b78aSgm89044 /*
143388f8b78aSgm89044 * bit 1 of the error address indicates failure during
143488f8b78aSgm89044 * read if set, during write otherwise.
143588f8b78aSgm89044 */
143688f8b78aSgm89044 dca_failure(dca, DDI_DEVICE_FAULT,
143788f8b78aSgm89044 DCA_FM_ECLASS_HW_DEVICE, dca_ena(0), CRYPTO_DEVICE_ERROR,
143888f8b78aSgm89044 "DMA master access error %s address 0x%x",
143988f8b78aSgm89044 erraddr & 0x1 ? "reading" : "writing", erraddr & ~1);
144088f8b78aSgm89044 return (DDI_INTR_CLAIMED);
144188f8b78aSgm89044 }
144288f8b78aSgm89044
144388f8b78aSgm89044 mutex_exit(&dca->dca_intrlock);
144488f8b78aSgm89044
144588f8b78aSgm89044 return (DDI_INTR_CLAIMED);
144688f8b78aSgm89044 }
144788f8b78aSgm89044
144888f8b78aSgm89044 /*
144988f8b78aSgm89044 * Reverse a string of bytes from s1 into s2. The reversal happens
145088f8b78aSgm89044 * from the tail of s1. If len1 < len2, then null bytes will be
145188f8b78aSgm89044 * padded to the end of s2. If len2 < len1, then (presumably null)
145288f8b78aSgm89044 * bytes will be dropped from the start of s1.
145388f8b78aSgm89044 *
145488f8b78aSgm89044 * The rationale here is that when s1 (source) is shorter, then we
145588f8b78aSgm89044 * are reversing from big-endian ordering, into device ordering, and
145688f8b78aSgm89044 * want to add some extra nulls to the tail (MSB) side of the device.
145788f8b78aSgm89044 *
145888f8b78aSgm89044 * Similarly, when s2 (dest) is shorter, then we are truncating what
145988f8b78aSgm89044 * are presumably null MSB bits from the device.
146088f8b78aSgm89044 *
146188f8b78aSgm89044 * There is an expectation when reversing from the device back into
146288f8b78aSgm89044 * big-endian, that the number of bytes to reverse and the target size
146388f8b78aSgm89044 * will match, and no truncation or padding occurs.
146488f8b78aSgm89044 */
146588f8b78aSgm89044 void
dca_reverse(void * s1,void * s2,int len1,int len2)146688f8b78aSgm89044 dca_reverse(void *s1, void *s2, int len1, int len2)
146788f8b78aSgm89044 {
146888f8b78aSgm89044 caddr_t src, dst;
146988f8b78aSgm89044
147088f8b78aSgm89044 if (len1 == 0) {
147188f8b78aSgm89044 if (len2) {
147288f8b78aSgm89044 bzero(s2, len2);
147388f8b78aSgm89044 }
147488f8b78aSgm89044 return;
147588f8b78aSgm89044 }
147688f8b78aSgm89044 src = (caddr_t)s1 + len1 - 1;
147788f8b78aSgm89044 dst = s2;
147888f8b78aSgm89044 while ((src >= (caddr_t)s1) && (len2)) {
147988f8b78aSgm89044 *dst++ = *src--;
148088f8b78aSgm89044 len2--;
148188f8b78aSgm89044 }
148288f8b78aSgm89044 while (len2 > 0) {
148388f8b78aSgm89044 *dst++ = 0;
148488f8b78aSgm89044 len2--;
148588f8b78aSgm89044 }
148688f8b78aSgm89044 }
148788f8b78aSgm89044
148888f8b78aSgm89044 uint16_t
dca_padfull(int num)148988f8b78aSgm89044 dca_padfull(int num)
149088f8b78aSgm89044 {
149188f8b78aSgm89044 if (num <= 512) {
149288f8b78aSgm89044 return (BITS2BYTES(512));
149388f8b78aSgm89044 }
149488f8b78aSgm89044 if (num <= 768) {
149588f8b78aSgm89044 return (BITS2BYTES(768));
149688f8b78aSgm89044 }
149788f8b78aSgm89044 if (num <= 1024) {
149888f8b78aSgm89044 return (BITS2BYTES(1024));
149988f8b78aSgm89044 }
150088f8b78aSgm89044 if (num <= 1536) {
150188f8b78aSgm89044 return (BITS2BYTES(1536));
150288f8b78aSgm89044 }
150388f8b78aSgm89044 if (num <= 2048) {
150488f8b78aSgm89044 return (BITS2BYTES(2048));
150588f8b78aSgm89044 }
150688f8b78aSgm89044 return (0);
150788f8b78aSgm89044 }
150888f8b78aSgm89044
150988f8b78aSgm89044 uint16_t
dca_padhalf(int num)151088f8b78aSgm89044 dca_padhalf(int num)
151188f8b78aSgm89044 {
151288f8b78aSgm89044 if (num <= 256) {
151388f8b78aSgm89044 return (BITS2BYTES(256));
151488f8b78aSgm89044 }
151588f8b78aSgm89044 if (num <= 384) {
151688f8b78aSgm89044 return (BITS2BYTES(384));
151788f8b78aSgm89044 }
151888f8b78aSgm89044 if (num <= 512) {
151988f8b78aSgm89044 return (BITS2BYTES(512));
152088f8b78aSgm89044 }
152188f8b78aSgm89044 if (num <= 768) {
152288f8b78aSgm89044 return (BITS2BYTES(768));
152388f8b78aSgm89044 }
152488f8b78aSgm89044 if (num <= 1024) {
152588f8b78aSgm89044 return (BITS2BYTES(1024));
152688f8b78aSgm89044 }
152788f8b78aSgm89044 return (0);
152888f8b78aSgm89044 }
152988f8b78aSgm89044
153088f8b78aSgm89044 dca_work_t *
dca_newwork(dca_t * dca)153188f8b78aSgm89044 dca_newwork(dca_t *dca)
153288f8b78aSgm89044 {
153388f8b78aSgm89044 dca_work_t *workp;
153488f8b78aSgm89044 size_t size;
153588f8b78aSgm89044 ddi_dma_cookie_t c;
153688f8b78aSgm89044 unsigned nc;
153788f8b78aSgm89044 int rv;
153888f8b78aSgm89044
153988f8b78aSgm89044 workp = kmem_zalloc(sizeof (dca_work_t), KM_SLEEP);
154088f8b78aSgm89044
154188f8b78aSgm89044 rv = ddi_dma_alloc_handle(dca->dca_dip, &dca_dmaattr,
154288f8b78aSgm89044 DDI_DMA_SLEEP, NULL, &workp->dw_mcr_dmah);
154388f8b78aSgm89044 if (rv != 0) {
154488f8b78aSgm89044 dca_error(dca, "unable to alloc MCR DMA handle");
154588f8b78aSgm89044 dca_destroywork(workp);
154688f8b78aSgm89044 return (NULL);
154788f8b78aSgm89044 }
154888f8b78aSgm89044
154988f8b78aSgm89044 rv = ddi_dma_mem_alloc(workp->dw_mcr_dmah,
155088f8b78aSgm89044 ROUNDUP(MCR_SIZE, dca->dca_pagesize),
155188f8b78aSgm89044 &dca_devattr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
155288f8b78aSgm89044 &workp->dw_mcr_kaddr, &size, &workp->dw_mcr_acch);
155388f8b78aSgm89044 if (rv != 0) {
155488f8b78aSgm89044 dca_error(dca, "unable to alloc MCR DMA memory");
155588f8b78aSgm89044 dca_destroywork(workp);
155688f8b78aSgm89044 return (NULL);
155788f8b78aSgm89044 }
155888f8b78aSgm89044
155988f8b78aSgm89044 rv = ddi_dma_addr_bind_handle(workp->dw_mcr_dmah, NULL,
156088f8b78aSgm89044 workp->dw_mcr_kaddr, size, DDI_DMA_CONSISTENT | DDI_DMA_RDWR,
156188f8b78aSgm89044 DDI_DMA_SLEEP, NULL, &c, &nc);
156288f8b78aSgm89044 if (rv != DDI_DMA_MAPPED) {
156388f8b78aSgm89044 dca_error(dca, "unable to map MCR DMA memory");
156488f8b78aSgm89044 dca_destroywork(workp);
156588f8b78aSgm89044 return (NULL);
156688f8b78aSgm89044 }
156788f8b78aSgm89044
156888f8b78aSgm89044 workp->dw_mcr_paddr = c.dmac_address;
156988f8b78aSgm89044 return (workp);
157088f8b78aSgm89044 }
157188f8b78aSgm89044
157288f8b78aSgm89044 void
dca_destroywork(dca_work_t * workp)157388f8b78aSgm89044 dca_destroywork(dca_work_t *workp)
157488f8b78aSgm89044 {
157588f8b78aSgm89044 if (workp->dw_mcr_paddr) {
157688f8b78aSgm89044 (void) ddi_dma_unbind_handle(workp->dw_mcr_dmah);
157788f8b78aSgm89044 }
157888f8b78aSgm89044 if (workp->dw_mcr_acch) {
157988f8b78aSgm89044 ddi_dma_mem_free(&workp->dw_mcr_acch);
158088f8b78aSgm89044 }
158188f8b78aSgm89044 if (workp->dw_mcr_dmah) {
158288f8b78aSgm89044 ddi_dma_free_handle(&workp->dw_mcr_dmah);
158388f8b78aSgm89044 }
158488f8b78aSgm89044 kmem_free(workp, sizeof (dca_work_t));
158588f8b78aSgm89044 }
158688f8b78aSgm89044
158788f8b78aSgm89044 dca_request_t *
dca_newreq(dca_t * dca)158888f8b78aSgm89044 dca_newreq(dca_t *dca)
158988f8b78aSgm89044 {
159088f8b78aSgm89044 dca_request_t *reqp;
159188f8b78aSgm89044 size_t size;
159288f8b78aSgm89044 ddi_dma_cookie_t c;
159388f8b78aSgm89044 unsigned nc;
159488f8b78aSgm89044 int rv;
159588f8b78aSgm89044 int n_chain = 0;
159688f8b78aSgm89044
159788f8b78aSgm89044 size = (DESC_SIZE * MAXFRAGS) + CTX_MAXLENGTH;
159888f8b78aSgm89044
159988f8b78aSgm89044 reqp = kmem_zalloc(sizeof (dca_request_t), KM_SLEEP);
160088f8b78aSgm89044
160188f8b78aSgm89044 reqp->dr_dca = dca;
160288f8b78aSgm89044
160388f8b78aSgm89044 /*
160488f8b78aSgm89044 * Setup the DMA region for the context and descriptors.
160588f8b78aSgm89044 */
160688f8b78aSgm89044 rv = ddi_dma_alloc_handle(dca->dca_dip, &dca_dmaattr, DDI_DMA_SLEEP,
160788f8b78aSgm89044 NULL, &reqp->dr_ctx_dmah);
160888f8b78aSgm89044 if (rv != DDI_SUCCESS) {
160988f8b78aSgm89044 dca_error(dca, "failure allocating request DMA handle");
161088f8b78aSgm89044 dca_destroyreq(reqp);
161188f8b78aSgm89044 return (NULL);
161288f8b78aSgm89044 }
161388f8b78aSgm89044
161488f8b78aSgm89044 /* for driver hardening, allocate in whole pages */
161588f8b78aSgm89044 rv = ddi_dma_mem_alloc(reqp->dr_ctx_dmah,
161688f8b78aSgm89044 ROUNDUP(size, dca->dca_pagesize), &dca_devattr, DDI_DMA_CONSISTENT,
161788f8b78aSgm89044 DDI_DMA_SLEEP, NULL, &reqp->dr_ctx_kaddr, &size,
161888f8b78aSgm89044 &reqp->dr_ctx_acch);
161988f8b78aSgm89044 if (rv != DDI_SUCCESS) {
162088f8b78aSgm89044 dca_error(dca, "unable to alloc request DMA memory");
162188f8b78aSgm89044 dca_destroyreq(reqp);
162288f8b78aSgm89044 return (NULL);
162388f8b78aSgm89044 }
162488f8b78aSgm89044
162588f8b78aSgm89044 rv = ddi_dma_addr_bind_handle(reqp->dr_ctx_dmah, NULL,
162688f8b78aSgm89044 reqp->dr_ctx_kaddr, size, DDI_DMA_CONSISTENT | DDI_DMA_WRITE,
162788f8b78aSgm89044 DDI_DMA_SLEEP, 0, &c, &nc);
162888f8b78aSgm89044 if (rv != DDI_DMA_MAPPED) {
162988f8b78aSgm89044 dca_error(dca, "failed binding request DMA handle");
163088f8b78aSgm89044 dca_destroyreq(reqp);
163188f8b78aSgm89044 return (NULL);
163288f8b78aSgm89044 }
163388f8b78aSgm89044 reqp->dr_ctx_paddr = c.dmac_address;
163488f8b78aSgm89044
163588f8b78aSgm89044 reqp->dr_dma_size = size;
163688f8b78aSgm89044
163788f8b78aSgm89044 /*
163888f8b78aSgm89044 * Set up the dma for our scratch/shared buffers.
163988f8b78aSgm89044 */
164088f8b78aSgm89044 rv = ddi_dma_alloc_handle(dca->dca_dip, &dca_dmaattr,
164188f8b78aSgm89044 DDI_DMA_SLEEP, NULL, &reqp->dr_ibuf_dmah);
164288f8b78aSgm89044 if (rv != DDI_SUCCESS) {
164388f8b78aSgm89044 dca_error(dca, "failure allocating ibuf DMA handle");
164488f8b78aSgm89044 dca_destroyreq(reqp);
164588f8b78aSgm89044 return (NULL);
164688f8b78aSgm89044 }
164788f8b78aSgm89044 rv = ddi_dma_alloc_handle(dca->dca_dip, &dca_dmaattr,
164888f8b78aSgm89044 DDI_DMA_SLEEP, NULL, &reqp->dr_obuf_dmah);
164988f8b78aSgm89044 if (rv != DDI_SUCCESS) {
165088f8b78aSgm89044 dca_error(dca, "failure allocating obuf DMA handle");
165188f8b78aSgm89044 dca_destroyreq(reqp);
165288f8b78aSgm89044 return (NULL);
165388f8b78aSgm89044 }
165488f8b78aSgm89044
165588f8b78aSgm89044 rv = ddi_dma_alloc_handle(dca->dca_dip, &dca_dmaattr,
165688f8b78aSgm89044 DDI_DMA_SLEEP, NULL, &reqp->dr_chain_in_dmah);
165788f8b78aSgm89044 if (rv != DDI_SUCCESS) {
165888f8b78aSgm89044 dca_error(dca, "failure allocating chain_in DMA handle");
165988f8b78aSgm89044 dca_destroyreq(reqp);
166088f8b78aSgm89044 return (NULL);
166188f8b78aSgm89044 }
166288f8b78aSgm89044
166388f8b78aSgm89044 rv = ddi_dma_alloc_handle(dca->dca_dip, &dca_dmaattr,
166488f8b78aSgm89044 DDI_DMA_SLEEP, NULL, &reqp->dr_chain_out_dmah);
166588f8b78aSgm89044 if (rv != DDI_SUCCESS) {
166688f8b78aSgm89044 dca_error(dca, "failure allocating chain_out DMA handle");
166788f8b78aSgm89044 dca_destroyreq(reqp);
166888f8b78aSgm89044 return (NULL);
166988f8b78aSgm89044 }
167088f8b78aSgm89044
167188f8b78aSgm89044 /*
167288f8b78aSgm89044 * for driver hardening, allocate in whole pages.
167388f8b78aSgm89044 */
167488f8b78aSgm89044 size = ROUNDUP(MAXPACKET, dca->dca_pagesize);
167588f8b78aSgm89044 #if defined(i386) || defined(__i386)
167688f8b78aSgm89044 /*
167788f8b78aSgm89044 * Use kmem_alloc instead of ddi_dma_mem_alloc here since the latter
1678*95014fbbSDan OpenSolaris Anderson * may fail on x86 platform if a physically contiguous memory chunk
167988f8b78aSgm89044 * cannot be found. From initial testing, we did not see performance
1680*95014fbbSDan OpenSolaris Anderson * degradation as seen on Sparc.
168188f8b78aSgm89044 */
168288f8b78aSgm89044 if ((reqp->dr_ibuf_kaddr = kmem_alloc(size, KM_SLEEP)) == NULL) {
168388f8b78aSgm89044 dca_error(dca, "unable to alloc request ibuf memory");
168488f8b78aSgm89044 dca_destroyreq(reqp);
168588f8b78aSgm89044 return (NULL);
168688f8b78aSgm89044 }
168788f8b78aSgm89044 if ((reqp->dr_obuf_kaddr = kmem_alloc(size, KM_SLEEP)) == NULL) {
168888f8b78aSgm89044 dca_error(dca, "unable to alloc request obuf memory");
168988f8b78aSgm89044 dca_destroyreq(reqp);
169088f8b78aSgm89044 return (NULL);
169188f8b78aSgm89044 }
169288f8b78aSgm89044 #else
169388f8b78aSgm89044 /*
1694*95014fbbSDan OpenSolaris Anderson * We could kmem_alloc for Sparc too. However, it gives worse
1695*95014fbbSDan OpenSolaris Anderson * performance when transferring more than one page data. For example,
1696*95014fbbSDan OpenSolaris Anderson * using 4 threads and 12032 byte data and 3DES on 900MHZ Sparc system,
169788f8b78aSgm89044 * kmem_alloc uses 80% CPU and ddi_dma_mem_alloc uses 50% CPU for
169888f8b78aSgm89044 * the same throughput.
169988f8b78aSgm89044 */
170088f8b78aSgm89044 rv = ddi_dma_mem_alloc(reqp->dr_ibuf_dmah,
170188f8b78aSgm89044 size, &dca_bufattr,
170288f8b78aSgm89044 DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &reqp->dr_ibuf_kaddr,
170388f8b78aSgm89044 &size, &reqp->dr_ibuf_acch);
170488f8b78aSgm89044 if (rv != DDI_SUCCESS) {
170588f8b78aSgm89044 dca_error(dca, "unable to alloc request DMA memory");
170688f8b78aSgm89044 dca_destroyreq(reqp);
170788f8b78aSgm89044 return (NULL);
170888f8b78aSgm89044 }
170988f8b78aSgm89044
171088f8b78aSgm89044 rv = ddi_dma_mem_alloc(reqp->dr_obuf_dmah,
171188f8b78aSgm89044 size, &dca_bufattr,
171288f8b78aSgm89044 DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &reqp->dr_obuf_kaddr,
171388f8b78aSgm89044 &size, &reqp->dr_obuf_acch);
171488f8b78aSgm89044 if (rv != DDI_SUCCESS) {
171588f8b78aSgm89044 dca_error(dca, "unable to alloc request DMA memory");
171688f8b78aSgm89044 dca_destroyreq(reqp);
171788f8b78aSgm89044 return (NULL);
171888f8b78aSgm89044 }
171988f8b78aSgm89044 #endif
172088f8b78aSgm89044
172188f8b78aSgm89044 /* Skip the used portion in the context page */
172288f8b78aSgm89044 reqp->dr_offset = CTX_MAXLENGTH;
172388f8b78aSgm89044 if ((rv = dca_bindchains_one(reqp, size, reqp->dr_offset,
172488f8b78aSgm89044 reqp->dr_ibuf_kaddr, reqp->dr_ibuf_dmah,
172588f8b78aSgm89044 DDI_DMA_WRITE | DDI_DMA_STREAMING,
172688f8b78aSgm89044 &reqp->dr_ibuf_head, &n_chain)) != DDI_SUCCESS) {
172788f8b78aSgm89044 (void) dca_destroyreq(reqp);
172888f8b78aSgm89044 return (NULL);
172988f8b78aSgm89044 }
173088f8b78aSgm89044 reqp->dr_ibuf_paddr = reqp->dr_ibuf_head.dc_buffer_paddr;
173188f8b78aSgm89044 /* Skip the space used by the input buffer */
173288f8b78aSgm89044 reqp->dr_offset += DESC_SIZE * n_chain;
173388f8b78aSgm89044
173488f8b78aSgm89044 if ((rv = dca_bindchains_one(reqp, size, reqp->dr_offset,
173588f8b78aSgm89044 reqp->dr_obuf_kaddr, reqp->dr_obuf_dmah,
173688f8b78aSgm89044 DDI_DMA_READ | DDI_DMA_STREAMING,
173788f8b78aSgm89044 &reqp->dr_obuf_head, &n_chain)) != DDI_SUCCESS) {
173888f8b78aSgm89044 (void) dca_destroyreq(reqp);
173988f8b78aSgm89044 return (NULL);
174088f8b78aSgm89044 }
174188f8b78aSgm89044 reqp->dr_obuf_paddr = reqp->dr_obuf_head.dc_buffer_paddr;
174288f8b78aSgm89044 /* Skip the space used by the output buffer */
174388f8b78aSgm89044 reqp->dr_offset += DESC_SIZE * n_chain;
174488f8b78aSgm89044
174588f8b78aSgm89044 DBG(dca, DCHATTY, "CTX is 0x%p, phys 0x%x, len %d",
174688f8b78aSgm89044 reqp->dr_ctx_kaddr, reqp->dr_ctx_paddr, CTX_MAXLENGTH);
174788f8b78aSgm89044 return (reqp);
174888f8b78aSgm89044 }
174988f8b78aSgm89044
175088f8b78aSgm89044 void
dca_destroyreq(dca_request_t * reqp)175188f8b78aSgm89044 dca_destroyreq(dca_request_t *reqp)
175288f8b78aSgm89044 {
175388f8b78aSgm89044 #if defined(i386) || defined(__i386)
175488f8b78aSgm89044 dca_t *dca = reqp->dr_dca;
175588f8b78aSgm89044 size_t size = ROUNDUP(MAXPACKET, dca->dca_pagesize);
175688f8b78aSgm89044 #endif
175788f8b78aSgm89044
175888f8b78aSgm89044 /*
175988f8b78aSgm89044 * Clean up DMA for the context structure.
176088f8b78aSgm89044 */
176188f8b78aSgm89044 if (reqp->dr_ctx_paddr) {
176288f8b78aSgm89044 (void) ddi_dma_unbind_handle(reqp->dr_ctx_dmah);
176388f8b78aSgm89044 }
176488f8b78aSgm89044
176588f8b78aSgm89044 if (reqp->dr_ctx_acch) {
176688f8b78aSgm89044 ddi_dma_mem_free(&reqp->dr_ctx_acch);
176788f8b78aSgm89044 }
176888f8b78aSgm89044
176988f8b78aSgm89044 if (reqp->dr_ctx_dmah) {
177088f8b78aSgm89044 ddi_dma_free_handle(&reqp->dr_ctx_dmah);
177188f8b78aSgm89044 }
177288f8b78aSgm89044
177388f8b78aSgm89044 /*
177488f8b78aSgm89044 * Clean up DMA for the scratch buffer.
177588f8b78aSgm89044 */
177688f8b78aSgm89044 #if defined(i386) || defined(__i386)
177788f8b78aSgm89044 if (reqp->dr_ibuf_dmah) {
177888f8b78aSgm89044 (void) ddi_dma_unbind_handle(reqp->dr_ibuf_dmah);
177988f8b78aSgm89044 ddi_dma_free_handle(&reqp->dr_ibuf_dmah);
178088f8b78aSgm89044 }
178188f8b78aSgm89044 if (reqp->dr_obuf_dmah) {
178288f8b78aSgm89044 (void) ddi_dma_unbind_handle(reqp->dr_obuf_dmah);
178388f8b78aSgm89044 ddi_dma_free_handle(&reqp->dr_obuf_dmah);
178488f8b78aSgm89044 }
178588f8b78aSgm89044
178688f8b78aSgm89044 kmem_free(reqp->dr_ibuf_kaddr, size);
178788f8b78aSgm89044 kmem_free(reqp->dr_obuf_kaddr, size);
178888f8b78aSgm89044 #else
178988f8b78aSgm89044 if (reqp->dr_ibuf_paddr) {
179088f8b78aSgm89044 (void) ddi_dma_unbind_handle(reqp->dr_ibuf_dmah);
179188f8b78aSgm89044 }
179288f8b78aSgm89044 if (reqp->dr_obuf_paddr) {
179388f8b78aSgm89044 (void) ddi_dma_unbind_handle(reqp->dr_obuf_dmah);
179488f8b78aSgm89044 }
179588f8b78aSgm89044
179688f8b78aSgm89044 if (reqp->dr_ibuf_acch) {
179788f8b78aSgm89044 ddi_dma_mem_free(&reqp->dr_ibuf_acch);
179888f8b78aSgm89044 }
179988f8b78aSgm89044 if (reqp->dr_obuf_acch) {
180088f8b78aSgm89044 ddi_dma_mem_free(&reqp->dr_obuf_acch);
180188f8b78aSgm89044 }
180288f8b78aSgm89044
180388f8b78aSgm89044 if (reqp->dr_ibuf_dmah) {
180488f8b78aSgm89044 ddi_dma_free_handle(&reqp->dr_ibuf_dmah);
180588f8b78aSgm89044 }
180688f8b78aSgm89044 if (reqp->dr_obuf_dmah) {
180788f8b78aSgm89044 ddi_dma_free_handle(&reqp->dr_obuf_dmah);
180888f8b78aSgm89044 }
180988f8b78aSgm89044 #endif
181088f8b78aSgm89044 /*
181188f8b78aSgm89044 * These two DMA handles should have been unbinded in
181288f8b78aSgm89044 * dca_unbindchains() function
181388f8b78aSgm89044 */
181488f8b78aSgm89044 if (reqp->dr_chain_in_dmah) {
181588f8b78aSgm89044 ddi_dma_free_handle(&reqp->dr_chain_in_dmah);
181688f8b78aSgm89044 }
181788f8b78aSgm89044 if (reqp->dr_chain_out_dmah) {
181888f8b78aSgm89044 ddi_dma_free_handle(&reqp->dr_chain_out_dmah);
181988f8b78aSgm89044 }
182088f8b78aSgm89044
182188f8b78aSgm89044 kmem_free(reqp, sizeof (dca_request_t));
182288f8b78aSgm89044 }
182388f8b78aSgm89044
182488f8b78aSgm89044 dca_work_t *
dca_getwork(dca_t * dca,int mcr)182588f8b78aSgm89044 dca_getwork(dca_t *dca, int mcr)
182688f8b78aSgm89044 {
182788f8b78aSgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr);
182888f8b78aSgm89044 dca_work_t *workp;
182988f8b78aSgm89044
18303383b6ddSqs148142 mutex_enter(&wlp->dwl_freelock);
183188f8b78aSgm89044 workp = (dca_work_t *)dca_dequeue(&wlp->dwl_freework);
18323383b6ddSqs148142 mutex_exit(&wlp->dwl_freelock);
183388f8b78aSgm89044 if (workp) {
183488f8b78aSgm89044 int nreqs;
183588f8b78aSgm89044 bzero(workp->dw_mcr_kaddr, 8);
183688f8b78aSgm89044
183788f8b78aSgm89044 /* clear out old requests */
183888f8b78aSgm89044 for (nreqs = 0; nreqs < MAXREQSPERMCR; nreqs++) {
183988f8b78aSgm89044 workp->dw_reqs[nreqs] = NULL;
184088f8b78aSgm89044 }
184188f8b78aSgm89044 }
184288f8b78aSgm89044 return (workp);
184388f8b78aSgm89044 }
184488f8b78aSgm89044
184588f8b78aSgm89044 void
dca_freework(dca_work_t * workp)184688f8b78aSgm89044 dca_freework(dca_work_t *workp)
184788f8b78aSgm89044 {
18483383b6ddSqs148142 mutex_enter(&workp->dw_wlp->dwl_freelock);
184988f8b78aSgm89044 dca_enqueue(&workp->dw_wlp->dwl_freework, (dca_listnode_t *)workp);
18503383b6ddSqs148142 mutex_exit(&workp->dw_wlp->dwl_freelock);
185188f8b78aSgm89044 }
185288f8b78aSgm89044
185388f8b78aSgm89044 dca_request_t *
dca_getreq(dca_t * dca,int mcr,int tryhard)185488f8b78aSgm89044 dca_getreq(dca_t *dca, int mcr, int tryhard)
185588f8b78aSgm89044 {
185688f8b78aSgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr);
185788f8b78aSgm89044 dca_request_t *reqp;
185888f8b78aSgm89044
185988f8b78aSgm89044 mutex_enter(&wlp->dwl_freereqslock);
186088f8b78aSgm89044 reqp = (dca_request_t *)dca_dequeue(&wlp->dwl_freereqs);
186188f8b78aSgm89044 mutex_exit(&wlp->dwl_freereqslock);
186288f8b78aSgm89044 if (reqp) {
186388f8b78aSgm89044 reqp->dr_flags = 0;
186488f8b78aSgm89044 reqp->dr_callback = NULL;
186588f8b78aSgm89044 } else if (tryhard) {
186688f8b78aSgm89044 /*
186788f8b78aSgm89044 * failed to get a free one, try an allocation, the hard way.
186888f8b78aSgm89044 * XXX: Kstat desired here.
186988f8b78aSgm89044 */
187088f8b78aSgm89044 if ((reqp = dca_newreq(dca)) != NULL) {
187188f8b78aSgm89044 reqp->dr_wlp = wlp;
187288f8b78aSgm89044 reqp->dr_dca = dca;
187388f8b78aSgm89044 reqp->dr_flags = 0;
187488f8b78aSgm89044 reqp->dr_callback = NULL;
187588f8b78aSgm89044 }
187688f8b78aSgm89044 }
187788f8b78aSgm89044 return (reqp);
187888f8b78aSgm89044 }
187988f8b78aSgm89044
188088f8b78aSgm89044 void
dca_freereq(dca_request_t * reqp)188188f8b78aSgm89044 dca_freereq(dca_request_t *reqp)
188288f8b78aSgm89044 {
188388f8b78aSgm89044 reqp->dr_kcf_req = NULL;
188488f8b78aSgm89044 if (!(reqp->dr_flags & DR_NOCACHE)) {
188588f8b78aSgm89044 mutex_enter(&reqp->dr_wlp->dwl_freereqslock);
188688f8b78aSgm89044 dca_enqueue(&reqp->dr_wlp->dwl_freereqs,
188788f8b78aSgm89044 (dca_listnode_t *)reqp);
188888f8b78aSgm89044 mutex_exit(&reqp->dr_wlp->dwl_freereqslock);
188988f8b78aSgm89044 }
189088f8b78aSgm89044 }
189188f8b78aSgm89044
189288f8b78aSgm89044 /*
189388f8b78aSgm89044 * Binds user buffers to DMA handles dynamically. On Sparc, a user buffer
1894*95014fbbSDan OpenSolaris Anderson * is mapped to a single physical address. On x86, a user buffer is mapped
1895*95014fbbSDan OpenSolaris Anderson * to multiple physical addresses. These physical addresses are chained
1896*95014fbbSDan OpenSolaris Anderson * using the method specified in Broadcom BCM5820 specification.
189788f8b78aSgm89044 */
189888f8b78aSgm89044 int
dca_bindchains(dca_request_t * reqp,size_t incnt,size_t outcnt)189988f8b78aSgm89044 dca_bindchains(dca_request_t *reqp, size_t incnt, size_t outcnt)
190088f8b78aSgm89044 {
190188f8b78aSgm89044 int rv;
190288f8b78aSgm89044 caddr_t kaddr;
190388f8b78aSgm89044 uint_t flags;
190488f8b78aSgm89044 int n_chain = 0;
190588f8b78aSgm89044
190688f8b78aSgm89044 if (reqp->dr_flags & DR_INPLACE) {
190788f8b78aSgm89044 flags = DDI_DMA_RDWR | DDI_DMA_CONSISTENT;
190888f8b78aSgm89044 } else {
190988f8b78aSgm89044 flags = DDI_DMA_WRITE | DDI_DMA_STREAMING;
191088f8b78aSgm89044 }
191188f8b78aSgm89044
191288f8b78aSgm89044 /* first the input */
191388f8b78aSgm89044 if (incnt) {
191488f8b78aSgm89044 if ((kaddr = dca_bufdaddr(reqp->dr_in)) == NULL) {
191588f8b78aSgm89044 DBG(NULL, DWARN, "unrecognised crypto data format");
191688f8b78aSgm89044 return (DDI_FAILURE);
191788f8b78aSgm89044 }
191888f8b78aSgm89044 if ((rv = dca_bindchains_one(reqp, incnt, reqp->dr_offset,
191988f8b78aSgm89044 kaddr, reqp->dr_chain_in_dmah, flags,
192088f8b78aSgm89044 &reqp->dr_chain_in_head, &n_chain)) != DDI_SUCCESS) {
192188f8b78aSgm89044 (void) dca_unbindchains(reqp);
192288f8b78aSgm89044 return (rv);
192388f8b78aSgm89044 }
192488f8b78aSgm89044
192588f8b78aSgm89044 /*
192688f8b78aSgm89044 * The offset and length are altered by the calling routine
192788f8b78aSgm89044 * reqp->dr_in->cd_offset += incnt;
192888f8b78aSgm89044 * reqp->dr_in->cd_length -= incnt;
192988f8b78aSgm89044 */
193088f8b78aSgm89044 /* Save the first one in the chain for MCR */
193188f8b78aSgm89044 reqp->dr_in_paddr = reqp->dr_chain_in_head.dc_buffer_paddr;
193288f8b78aSgm89044 reqp->dr_in_next = reqp->dr_chain_in_head.dc_next_paddr;
193388f8b78aSgm89044 reqp->dr_in_len = reqp->dr_chain_in_head.dc_buffer_length;
193488f8b78aSgm89044 } else {
193588f8b78aSgm89044 reqp->dr_in_paddr = NULL;
193688f8b78aSgm89044 reqp->dr_in_next = 0;
193788f8b78aSgm89044 reqp->dr_in_len = 0;
193888f8b78aSgm89044 }
193988f8b78aSgm89044
194088f8b78aSgm89044 if (reqp->dr_flags & DR_INPLACE) {
194188f8b78aSgm89044 reqp->dr_out_paddr = reqp->dr_in_paddr;
194288f8b78aSgm89044 reqp->dr_out_len = reqp->dr_in_len;
194388f8b78aSgm89044 reqp->dr_out_next = reqp->dr_in_next;
194488f8b78aSgm89044 return (DDI_SUCCESS);
194588f8b78aSgm89044 }
194688f8b78aSgm89044
194788f8b78aSgm89044 /* then the output */
194888f8b78aSgm89044 if (outcnt) {
194988f8b78aSgm89044 flags = DDI_DMA_READ | DDI_DMA_STREAMING;
195088f8b78aSgm89044 if ((kaddr = dca_bufdaddr_out(reqp->dr_out)) == NULL) {
195188f8b78aSgm89044 DBG(NULL, DWARN, "unrecognised crypto data format");
195288f8b78aSgm89044 (void) dca_unbindchains(reqp);
195388f8b78aSgm89044 return (DDI_FAILURE);
195488f8b78aSgm89044 }
195588f8b78aSgm89044 rv = dca_bindchains_one(reqp, outcnt, reqp->dr_offset +
195688f8b78aSgm89044 n_chain * DESC_SIZE, kaddr, reqp->dr_chain_out_dmah,
195788f8b78aSgm89044 flags, &reqp->dr_chain_out_head, &n_chain);
195888f8b78aSgm89044 if (rv != DDI_SUCCESS) {
195988f8b78aSgm89044 (void) dca_unbindchains(reqp);
196088f8b78aSgm89044 return (DDI_FAILURE);
196188f8b78aSgm89044 }
196288f8b78aSgm89044
196388f8b78aSgm89044 /* Save the first one in the chain for MCR */
196488f8b78aSgm89044 reqp->dr_out_paddr = reqp->dr_chain_out_head.dc_buffer_paddr;
196588f8b78aSgm89044 reqp->dr_out_next = reqp->dr_chain_out_head.dc_next_paddr;
196688f8b78aSgm89044 reqp->dr_out_len = reqp->dr_chain_out_head.dc_buffer_length;
196788f8b78aSgm89044 } else {
196888f8b78aSgm89044 reqp->dr_out_paddr = NULL;
196988f8b78aSgm89044 reqp->dr_out_next = 0;
197088f8b78aSgm89044 reqp->dr_out_len = 0;
197188f8b78aSgm89044 }
197288f8b78aSgm89044
197388f8b78aSgm89044 return (DDI_SUCCESS);
197488f8b78aSgm89044 }
197588f8b78aSgm89044
197688f8b78aSgm89044 /*
197788f8b78aSgm89044 * Unbind the user buffers from the DMA handles.
197888f8b78aSgm89044 */
197988f8b78aSgm89044 int
dca_unbindchains(dca_request_t * reqp)198088f8b78aSgm89044 dca_unbindchains(dca_request_t *reqp)
198188f8b78aSgm89044 {
198288f8b78aSgm89044 int rv = DDI_SUCCESS;
198388f8b78aSgm89044 int rv1 = DDI_SUCCESS;
198488f8b78aSgm89044
198588f8b78aSgm89044 /* Clear the input chain */
198688f8b78aSgm89044 if (reqp->dr_chain_in_head.dc_buffer_paddr != NULL) {
198788f8b78aSgm89044 (void) ddi_dma_unbind_handle(reqp->dr_chain_in_dmah);
198888f8b78aSgm89044 reqp->dr_chain_in_head.dc_buffer_paddr = 0;
198988f8b78aSgm89044 }
199088f8b78aSgm89044
1991d8dd9913Sgm89044 if (reqp->dr_flags & DR_INPLACE) {
1992d8dd9913Sgm89044 return (rv);
1993d8dd9913Sgm89044 }
1994d8dd9913Sgm89044
199588f8b78aSgm89044 /* Clear the output chain */
199688f8b78aSgm89044 if (reqp->dr_chain_out_head.dc_buffer_paddr != NULL) {
199788f8b78aSgm89044 (void) ddi_dma_unbind_handle(reqp->dr_chain_out_dmah);
199888f8b78aSgm89044 reqp->dr_chain_out_head.dc_buffer_paddr = 0;
199988f8b78aSgm89044 }
200088f8b78aSgm89044
200188f8b78aSgm89044 return ((rv != DDI_SUCCESS)? rv : rv1);
200288f8b78aSgm89044 }
200388f8b78aSgm89044
200488f8b78aSgm89044 /*
200588f8b78aSgm89044 * Build either input chain or output chain. It is single-item chain for Sparc,
200688f8b78aSgm89044 * and possible mutiple-item chain for x86.
200788f8b78aSgm89044 */
200888f8b78aSgm89044 static int
dca_bindchains_one(dca_request_t * reqp,size_t cnt,int dr_offset,caddr_t kaddr,ddi_dma_handle_t handle,uint_t flags,dca_chain_t * head,int * n_chain)200988f8b78aSgm89044 dca_bindchains_one(dca_request_t *reqp, size_t cnt, int dr_offset,
201088f8b78aSgm89044 caddr_t kaddr, ddi_dma_handle_t handle, uint_t flags,
201188f8b78aSgm89044 dca_chain_t *head, int *n_chain)
201288f8b78aSgm89044 {
201388f8b78aSgm89044 ddi_dma_cookie_t c;
201488f8b78aSgm89044 uint_t nc;
201588f8b78aSgm89044 int rv;
201688f8b78aSgm89044 caddr_t chain_kaddr_pre;
201788f8b78aSgm89044 caddr_t chain_kaddr;
201888f8b78aSgm89044 uint32_t chain_paddr;
201988f8b78aSgm89044 int i;
202088f8b78aSgm89044
202188f8b78aSgm89044 /* Advance past the context structure to the starting address */
202288f8b78aSgm89044 chain_paddr = reqp->dr_ctx_paddr + dr_offset;
202388f8b78aSgm89044 chain_kaddr = reqp->dr_ctx_kaddr + dr_offset;
202488f8b78aSgm89044
202588f8b78aSgm89044 /*
202688f8b78aSgm89044 * Bind the kernel address to the DMA handle. On x86, the actual
202788f8b78aSgm89044 * buffer is mapped into multiple physical addresses. On Sparc,
202888f8b78aSgm89044 * the actual buffer is mapped into a single address.
202988f8b78aSgm89044 */
203088f8b78aSgm89044 rv = ddi_dma_addr_bind_handle(handle,
203188f8b78aSgm89044 NULL, kaddr, cnt, flags, DDI_DMA_DONTWAIT, NULL, &c, &nc);
203288f8b78aSgm89044 if (rv != DDI_DMA_MAPPED) {
203388f8b78aSgm89044 return (DDI_FAILURE);
203488f8b78aSgm89044 }
203588f8b78aSgm89044
203688f8b78aSgm89044 (void) ddi_dma_sync(handle, 0, cnt, DDI_DMA_SYNC_FORDEV);
203788f8b78aSgm89044 if ((rv = dca_check_dma_handle(reqp->dr_dca, handle,
203888f8b78aSgm89044 DCA_FM_ECLASS_NONE)) != DDI_SUCCESS) {
203988f8b78aSgm89044 reqp->destroy = TRUE;
204088f8b78aSgm89044 return (rv);
204188f8b78aSgm89044 }
204288f8b78aSgm89044
204388f8b78aSgm89044 *n_chain = nc;
204488f8b78aSgm89044
204588f8b78aSgm89044 /* Setup the data buffer chain for DMA transfer */
204688f8b78aSgm89044 chain_kaddr_pre = NULL;
204788f8b78aSgm89044 head->dc_buffer_paddr = 0;
204888f8b78aSgm89044 head->dc_next_paddr = 0;
204988f8b78aSgm89044 head->dc_buffer_length = 0;
205088f8b78aSgm89044 for (i = 0; i < nc; i++) {
205188f8b78aSgm89044 /* PIO */
205288f8b78aSgm89044 PUTDESC32(reqp, chain_kaddr, DESC_BUFADDR, c.dmac_address);
205388f8b78aSgm89044 PUTDESC16(reqp, chain_kaddr, DESC_RSVD, 0);
205488f8b78aSgm89044 PUTDESC16(reqp, chain_kaddr, DESC_LENGTH, c.dmac_size);
205588f8b78aSgm89044
205688f8b78aSgm89044 /* Remember the head of the chain */
205788f8b78aSgm89044 if (head->dc_buffer_paddr == 0) {
205888f8b78aSgm89044 head->dc_buffer_paddr = c.dmac_address;
205988f8b78aSgm89044 head->dc_buffer_length = c.dmac_size;
206088f8b78aSgm89044 }
206188f8b78aSgm89044
206288f8b78aSgm89044 /* Link to the previous one if one exists */
206388f8b78aSgm89044 if (chain_kaddr_pre) {
206488f8b78aSgm89044 PUTDESC32(reqp, chain_kaddr_pre, DESC_NEXT,
206588f8b78aSgm89044 chain_paddr);
206688f8b78aSgm89044 if (head->dc_next_paddr == 0)
206788f8b78aSgm89044 head->dc_next_paddr = chain_paddr;
206888f8b78aSgm89044 }
206988f8b78aSgm89044 chain_kaddr_pre = chain_kaddr;
207088f8b78aSgm89044
207188f8b78aSgm89044 /* Maintain pointers */
207288f8b78aSgm89044 chain_paddr += DESC_SIZE;
207388f8b78aSgm89044 chain_kaddr += DESC_SIZE;
207488f8b78aSgm89044
207588f8b78aSgm89044 /* Retrieve the next cookie if there is one */
207688f8b78aSgm89044 if (i < nc-1)
207788f8b78aSgm89044 ddi_dma_nextcookie(handle, &c);
207888f8b78aSgm89044 }
207988f8b78aSgm89044
208088f8b78aSgm89044 /* Set the next pointer in the last entry to NULL */
208188f8b78aSgm89044 PUTDESC32(reqp, chain_kaddr_pre, DESC_NEXT, 0);
208288f8b78aSgm89044
208388f8b78aSgm89044 return (DDI_SUCCESS);
208488f8b78aSgm89044 }
208588f8b78aSgm89044
208688f8b78aSgm89044 /*
208788f8b78aSgm89044 * Schedule some work.
208888f8b78aSgm89044 */
208988f8b78aSgm89044 int
dca_start(dca_t * dca,dca_request_t * reqp,int mcr,int dosched)209088f8b78aSgm89044 dca_start(dca_t *dca, dca_request_t *reqp, int mcr, int dosched)
209188f8b78aSgm89044 {
209288f8b78aSgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr);
209388f8b78aSgm89044
209488f8b78aSgm89044 mutex_enter(&wlp->dwl_lock);
209588f8b78aSgm89044
209688f8b78aSgm89044 DBG(dca, DCHATTY, "req=%p, in=%p, out=%p, ctx=%p, ibuf=%p, obuf=%p",
209788f8b78aSgm89044 reqp, reqp->dr_in, reqp->dr_out, reqp->dr_ctx_kaddr,
209888f8b78aSgm89044 reqp->dr_ibuf_kaddr, reqp->dr_obuf_kaddr);
209988f8b78aSgm89044 DBG(dca, DCHATTY, "ctx paddr = %x, ibuf paddr = %x, obuf paddr = %x",
210088f8b78aSgm89044 reqp->dr_ctx_paddr, reqp->dr_ibuf_paddr, reqp->dr_obuf_paddr);
210188f8b78aSgm89044 /* sync out the entire context and descriptor chains */
210288f8b78aSgm89044 (void) ddi_dma_sync(reqp->dr_ctx_dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
210388f8b78aSgm89044 if (dca_check_dma_handle(dca, reqp->dr_ctx_dmah,
210488f8b78aSgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
210588f8b78aSgm89044 reqp->destroy = TRUE;
210688f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
210788f8b78aSgm89044 return (CRYPTO_DEVICE_ERROR);
210888f8b78aSgm89044 }
210988f8b78aSgm89044
211088f8b78aSgm89044 dca_enqueue(&wlp->dwl_waitq, (dca_listnode_t *)reqp);
211188f8b78aSgm89044 wlp->dwl_count++;
211288f8b78aSgm89044 wlp->dwl_lastsubmit = ddi_get_lbolt();
211388f8b78aSgm89044 reqp->dr_wlp = wlp;
211488f8b78aSgm89044
211588f8b78aSgm89044 if ((wlp->dwl_count == wlp->dwl_hiwater) && (wlp->dwl_busy == 0)) {
211688f8b78aSgm89044 /* we are fully loaded now, let kCF know */
211788f8b78aSgm89044
211888f8b78aSgm89044 wlp->dwl_flowctl++;
211988f8b78aSgm89044 wlp->dwl_busy = 1;
212088f8b78aSgm89044
212188f8b78aSgm89044 crypto_prov_notify(wlp->dwl_prov, CRYPTO_PROVIDER_BUSY);
212288f8b78aSgm89044 }
212388f8b78aSgm89044
212488f8b78aSgm89044 if (dosched) {
212588f8b78aSgm89044 #ifdef SCHEDDELAY
212688f8b78aSgm89044 /* possibly wait for more work to arrive */
212788f8b78aSgm89044 if (wlp->dwl_count >= wlp->dwl_reqspermcr) {
212888f8b78aSgm89044 dca_schedule(dca, mcr);
212988f8b78aSgm89044 } else if (!wlp->dwl_schedtid) {
213088f8b78aSgm89044 /* wait 1 msec for more work before doing it */
213188f8b78aSgm89044 wlp->dwl_schedtid = timeout(dca_schedtimeout,
213288f8b78aSgm89044 (void *)wlp, drv_usectohz(MSEC));
213388f8b78aSgm89044 }
213488f8b78aSgm89044 #else
213588f8b78aSgm89044 dca_schedule(dca, mcr);
213688f8b78aSgm89044 #endif
213788f8b78aSgm89044 }
213888f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
213988f8b78aSgm89044
214088f8b78aSgm89044 return (CRYPTO_QUEUED);
214188f8b78aSgm89044 }
214288f8b78aSgm89044
214388f8b78aSgm89044 void
dca_schedule(dca_t * dca,int mcr)214488f8b78aSgm89044 dca_schedule(dca_t *dca, int mcr)
214588f8b78aSgm89044 {
214688f8b78aSgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr);
214788f8b78aSgm89044 int csr;
214888f8b78aSgm89044 int full;
214988f8b78aSgm89044 uint32_t status;
215088f8b78aSgm89044
215188f8b78aSgm89044 ASSERT(mutex_owned(&wlp->dwl_lock));
215288f8b78aSgm89044 /*
215388f8b78aSgm89044 * If the card is draining or has an outstanding failure,
215488f8b78aSgm89044 * don't schedule any more work on it right now
215588f8b78aSgm89044 */
215688f8b78aSgm89044 if (wlp->dwl_drain || (dca->dca_flags & DCA_FAILED)) {
215788f8b78aSgm89044 return;
215888f8b78aSgm89044 }
215988f8b78aSgm89044
216088f8b78aSgm89044 if (mcr == MCR2) {
216188f8b78aSgm89044 csr = CSR_MCR2;
216288f8b78aSgm89044 full = DMASTAT_MCR2FULL;
216388f8b78aSgm89044 } else {
216488f8b78aSgm89044 csr = CSR_MCR1;
216588f8b78aSgm89044 full = DMASTAT_MCR1FULL;
216688f8b78aSgm89044 }
216788f8b78aSgm89044
216888f8b78aSgm89044 for (;;) {
216988f8b78aSgm89044 dca_work_t *workp;
217088f8b78aSgm89044 uint32_t offset;
217188f8b78aSgm89044 int nreqs;
217288f8b78aSgm89044
217388f8b78aSgm89044 status = GETCSR(dca, CSR_DMASTAT);
217488f8b78aSgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle,
217588f8b78aSgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS)
217688f8b78aSgm89044 return;
217788f8b78aSgm89044
217888f8b78aSgm89044 if ((status & full) != 0)
217988f8b78aSgm89044 break;
218088f8b78aSgm89044
218188f8b78aSgm89044 #ifdef SCHEDDELAY
218288f8b78aSgm89044 /* if there isn't enough to do, don't bother now */
218388f8b78aSgm89044 if ((wlp->dwl_count < wlp->dwl_reqspermcr) &&
218488f8b78aSgm89044 (ddi_get_lbolt() < (wlp->dwl_lastsubmit +
218588f8b78aSgm89044 drv_usectohz(MSEC)))) {
218688f8b78aSgm89044 /* wait a bit longer... */
218788f8b78aSgm89044 if (wlp->dwl_schedtid == 0) {
218888f8b78aSgm89044 wlp->dwl_schedtid = timeout(dca_schedtimeout,
218988f8b78aSgm89044 (void *)wlp, drv_usectohz(MSEC));
219088f8b78aSgm89044 }
219188f8b78aSgm89044 return;
219288f8b78aSgm89044 }
219388f8b78aSgm89044 #endif
219488f8b78aSgm89044
219588f8b78aSgm89044 /* grab a work structure */
219688f8b78aSgm89044 workp = dca_getwork(dca, mcr);
219788f8b78aSgm89044
219888f8b78aSgm89044 if (workp == NULL) {
219988f8b78aSgm89044 /*
220088f8b78aSgm89044 * There must be work ready to be reclaimed,
220188f8b78aSgm89044 * in this case, since the chip can only hold
220288f8b78aSgm89044 * less work outstanding than there are total.
220388f8b78aSgm89044 */
220488f8b78aSgm89044 dca_reclaim(dca, mcr);
220588f8b78aSgm89044 continue;
220688f8b78aSgm89044 }
220788f8b78aSgm89044
220888f8b78aSgm89044 nreqs = 0;
220988f8b78aSgm89044 offset = MCR_CTXADDR;
221088f8b78aSgm89044
221188f8b78aSgm89044 while (nreqs < wlp->dwl_reqspermcr) {
221288f8b78aSgm89044 dca_request_t *reqp;
221388f8b78aSgm89044
221488f8b78aSgm89044 reqp = (dca_request_t *)dca_dequeue(&wlp->dwl_waitq);
221588f8b78aSgm89044 if (reqp == NULL) {
221688f8b78aSgm89044 /* nothing left to process */
221788f8b78aSgm89044 break;
221888f8b78aSgm89044 }
221988f8b78aSgm89044 /*
222088f8b78aSgm89044 * Update flow control.
222188f8b78aSgm89044 */
222288f8b78aSgm89044 wlp->dwl_count--;
222388f8b78aSgm89044 if ((wlp->dwl_count == wlp->dwl_lowater) &&
222488f8b78aSgm89044 (wlp->dwl_busy)) {
222588f8b78aSgm89044 wlp->dwl_busy = 0;
222688f8b78aSgm89044 crypto_prov_notify(wlp->dwl_prov,
222788f8b78aSgm89044 CRYPTO_PROVIDER_READY);
222888f8b78aSgm89044 }
222988f8b78aSgm89044
223088f8b78aSgm89044 /*
223188f8b78aSgm89044 * Context address.
223288f8b78aSgm89044 */
223388f8b78aSgm89044 PUTMCR32(workp, offset, reqp->dr_ctx_paddr);
223488f8b78aSgm89044 offset += 4;
223588f8b78aSgm89044
223688f8b78aSgm89044 /*
223788f8b78aSgm89044 * Input chain.
223888f8b78aSgm89044 */
223988f8b78aSgm89044 /* input buffer address */
224088f8b78aSgm89044 PUTMCR32(workp, offset, reqp->dr_in_paddr);
224188f8b78aSgm89044 offset += 4;
224288f8b78aSgm89044 /* next input buffer entry */
224388f8b78aSgm89044 PUTMCR32(workp, offset, reqp->dr_in_next);
224488f8b78aSgm89044 offset += 4;
224588f8b78aSgm89044 /* input buffer length */
224688f8b78aSgm89044 PUTMCR16(workp, offset, reqp->dr_in_len);
224788f8b78aSgm89044 offset += 2;
224888f8b78aSgm89044 /* zero the reserved field */
224988f8b78aSgm89044 PUTMCR16(workp, offset, 0);
225088f8b78aSgm89044 offset += 2;
225188f8b78aSgm89044
225288f8b78aSgm89044 /*
225388f8b78aSgm89044 * Overall length.
225488f8b78aSgm89044 */
225588f8b78aSgm89044 /* reserved field */
225688f8b78aSgm89044 PUTMCR16(workp, offset, 0);
225788f8b78aSgm89044 offset += 2;
225888f8b78aSgm89044 /* total packet length */
225988f8b78aSgm89044 PUTMCR16(workp, offset, reqp->dr_pkt_length);
226088f8b78aSgm89044 offset += 2;
226188f8b78aSgm89044
226288f8b78aSgm89044 /*
226388f8b78aSgm89044 * Output chain.
226488f8b78aSgm89044 */
226588f8b78aSgm89044 /* output buffer address */
226688f8b78aSgm89044 PUTMCR32(workp, offset, reqp->dr_out_paddr);
226788f8b78aSgm89044 offset += 4;
226888f8b78aSgm89044 /* next output buffer entry */
226988f8b78aSgm89044 PUTMCR32(workp, offset, reqp->dr_out_next);
227088f8b78aSgm89044 offset += 4;
227188f8b78aSgm89044 /* output buffer length */
227288f8b78aSgm89044 PUTMCR16(workp, offset, reqp->dr_out_len);
227388f8b78aSgm89044 offset += 2;
227488f8b78aSgm89044 /* zero the reserved field */
227588f8b78aSgm89044 PUTMCR16(workp, offset, 0);
227688f8b78aSgm89044 offset += 2;
227788f8b78aSgm89044
227888f8b78aSgm89044 /*
227988f8b78aSgm89044 * Note submission.
228088f8b78aSgm89044 */
228188f8b78aSgm89044 workp->dw_reqs[nreqs] = reqp;
228288f8b78aSgm89044 nreqs++;
228388f8b78aSgm89044 }
228488f8b78aSgm89044
228588f8b78aSgm89044 if (nreqs == 0) {
228688f8b78aSgm89044 /* nothing in the queue! */
228788f8b78aSgm89044 dca_freework(workp);
228888f8b78aSgm89044 return;
228988f8b78aSgm89044 }
229088f8b78aSgm89044
229188f8b78aSgm89044 wlp->dwl_submit++;
229288f8b78aSgm89044
229388f8b78aSgm89044 PUTMCR16(workp, MCR_FLAGS, 0);
229488f8b78aSgm89044 PUTMCR16(workp, MCR_COUNT, nreqs);
229588f8b78aSgm89044
229688f8b78aSgm89044 DBG(dca, DCHATTY,
229788f8b78aSgm89044 "posting work (phys %x, virt 0x%p) (%d reqs) to MCR%d",
229888f8b78aSgm89044 workp->dw_mcr_paddr, workp->dw_mcr_kaddr,
229988f8b78aSgm89044 nreqs, mcr);
230088f8b78aSgm89044
230188f8b78aSgm89044 workp->dw_lbolt = ddi_get_lbolt();
230288f8b78aSgm89044 /* Make sure MCR is synced out to device. */
230388f8b78aSgm89044 (void) ddi_dma_sync(workp->dw_mcr_dmah, 0, 0,
230488f8b78aSgm89044 DDI_DMA_SYNC_FORDEV);
230588f8b78aSgm89044 if (dca_check_dma_handle(dca, workp->dw_mcr_dmah,
230688f8b78aSgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
230788f8b78aSgm89044 dca_destroywork(workp);
230888f8b78aSgm89044 return;
230988f8b78aSgm89044 }
231088f8b78aSgm89044
231188f8b78aSgm89044 PUTCSR(dca, csr, workp->dw_mcr_paddr);
231288f8b78aSgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle,
231388f8b78aSgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
231488f8b78aSgm89044 dca_destroywork(workp);
231588f8b78aSgm89044 return;
231688f8b78aSgm89044 } else {
231788f8b78aSgm89044 dca_enqueue(&wlp->dwl_runq, (dca_listnode_t *)workp);
231888f8b78aSgm89044 }
231988f8b78aSgm89044
232088f8b78aSgm89044 DBG(dca, DCHATTY, "posted");
232188f8b78aSgm89044 }
232288f8b78aSgm89044 }
232388f8b78aSgm89044
232488f8b78aSgm89044 /*
232588f8b78aSgm89044 * Reclaim completed work, called in interrupt context.
232688f8b78aSgm89044 */
232788f8b78aSgm89044 void
dca_reclaim(dca_t * dca,int mcr)232888f8b78aSgm89044 dca_reclaim(dca_t *dca, int mcr)
232988f8b78aSgm89044 {
233088f8b78aSgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr);
233188f8b78aSgm89044 dca_work_t *workp;
233288f8b78aSgm89044 ushort_t flags;
233388f8b78aSgm89044 int nreclaimed = 0;
233488f8b78aSgm89044 int i;
233588f8b78aSgm89044
233688f8b78aSgm89044 DBG(dca, DRECLAIM, "worklist = 0x%p (MCR%d)", wlp, mcr);
233788f8b78aSgm89044 ASSERT(mutex_owned(&wlp->dwl_lock));
233888f8b78aSgm89044 /*
233988f8b78aSgm89044 * For each MCR in the submitted (runq), we check to see if
234088f8b78aSgm89044 * it has been processed. If so, then we note each individual
234188f8b78aSgm89044 * job in the MCR, and and do the completion processing for
234288f8b78aSgm89044 * each of such job.
234388f8b78aSgm89044 */
234488f8b78aSgm89044 for (;;) {
234588f8b78aSgm89044
234688f8b78aSgm89044 workp = (dca_work_t *)dca_peekqueue(&wlp->dwl_runq);
234788f8b78aSgm89044 if (workp == NULL) {
234888f8b78aSgm89044 break;
234988f8b78aSgm89044 }
235088f8b78aSgm89044
235188f8b78aSgm89044 /* only sync the MCR flags, since that's all we need */
235288f8b78aSgm89044 (void) ddi_dma_sync(workp->dw_mcr_dmah, 0, 4,
235388f8b78aSgm89044 DDI_DMA_SYNC_FORKERNEL);
235488f8b78aSgm89044 if (dca_check_dma_handle(dca, workp->dw_mcr_dmah,
235588f8b78aSgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
235688f8b78aSgm89044 dca_rmqueue((dca_listnode_t *)workp);
235788f8b78aSgm89044 dca_destroywork(workp);
235888f8b78aSgm89044 return;
235988f8b78aSgm89044 }
236088f8b78aSgm89044
236188f8b78aSgm89044 flags = GETMCR16(workp, MCR_FLAGS);
236288f8b78aSgm89044 if ((flags & MCRFLAG_FINISHED) == 0) {
236388f8b78aSgm89044 /* chip is still working on it */
236488f8b78aSgm89044 DBG(dca, DRECLAIM,
236588f8b78aSgm89044 "chip still working on it (MCR%d)", mcr);
236688f8b78aSgm89044 break;
236788f8b78aSgm89044 }
236888f8b78aSgm89044
236988f8b78aSgm89044 /* its really for us, so remove it from the queue */
237088f8b78aSgm89044 dca_rmqueue((dca_listnode_t *)workp);
237188f8b78aSgm89044
237288f8b78aSgm89044 /* if we were draining, signal on the cv */
237388f8b78aSgm89044 if (wlp->dwl_drain && QEMPTY(&wlp->dwl_runq)) {
237488f8b78aSgm89044 cv_signal(&wlp->dwl_cv);
237588f8b78aSgm89044 }
237688f8b78aSgm89044
237788f8b78aSgm89044 /* update statistics, done under the lock */
237888f8b78aSgm89044 for (i = 0; i < wlp->dwl_reqspermcr; i++) {
237988f8b78aSgm89044 dca_request_t *reqp = workp->dw_reqs[i];
238088f8b78aSgm89044 if (reqp == NULL) {
238188f8b78aSgm89044 continue;
238288f8b78aSgm89044 }
238388f8b78aSgm89044 if (reqp->dr_byte_stat >= 0) {
238488f8b78aSgm89044 dca->dca_stats[reqp->dr_byte_stat] +=
238588f8b78aSgm89044 reqp->dr_pkt_length;
238688f8b78aSgm89044 }
238788f8b78aSgm89044 if (reqp->dr_job_stat >= 0) {
238888f8b78aSgm89044 dca->dca_stats[reqp->dr_job_stat]++;
238988f8b78aSgm89044 }
239088f8b78aSgm89044 }
239188f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
239288f8b78aSgm89044
239388f8b78aSgm89044 for (i = 0; i < wlp->dwl_reqspermcr; i++) {
239488f8b78aSgm89044 dca_request_t *reqp = workp->dw_reqs[i];
239588f8b78aSgm89044
239688f8b78aSgm89044 if (reqp == NULL) {
239788f8b78aSgm89044 continue;
239888f8b78aSgm89044 }
239988f8b78aSgm89044
240088f8b78aSgm89044 /* Do the callback. */
240188f8b78aSgm89044 workp->dw_reqs[i] = NULL;
240288f8b78aSgm89044 dca_done(reqp, CRYPTO_SUCCESS);
240388f8b78aSgm89044
240488f8b78aSgm89044 nreclaimed++;
240588f8b78aSgm89044 }
240688f8b78aSgm89044
240788f8b78aSgm89044 /* now we can release the work */
240888f8b78aSgm89044 dca_freework(workp);
24093383b6ddSqs148142
24103383b6ddSqs148142 mutex_enter(&wlp->dwl_lock);
241188f8b78aSgm89044 }
241288f8b78aSgm89044 DBG(dca, DRECLAIM, "reclaimed %d cmds", nreclaimed);
241388f8b78aSgm89044 }
241488f8b78aSgm89044
241588f8b78aSgm89044 int
dca_length(crypto_data_t * cdata)241688f8b78aSgm89044 dca_length(crypto_data_t *cdata)
241788f8b78aSgm89044 {
241888f8b78aSgm89044 return (cdata->cd_length);
241988f8b78aSgm89044 }
242088f8b78aSgm89044
242188f8b78aSgm89044 /*
242288f8b78aSgm89044 * This is the callback function called from the interrupt when a kCF job
242388f8b78aSgm89044 * completes. It does some driver-specific things, and then calls the
242488f8b78aSgm89044 * kCF-provided callback. Finally, it cleans up the state for the work
242588f8b78aSgm89044 * request and drops the reference count to allow for DR.
242688f8b78aSgm89044 */
242788f8b78aSgm89044 void
dca_done(dca_request_t * reqp,int err)242888f8b78aSgm89044 dca_done(dca_request_t *reqp, int err)
242988f8b78aSgm89044 {
243088f8b78aSgm89044 uint64_t ena = 0;
243188f8b78aSgm89044
243288f8b78aSgm89044 /* unbind any chains we were using */
243388f8b78aSgm89044 if (dca_unbindchains(reqp) != DDI_SUCCESS) {
243488f8b78aSgm89044 /* DMA failure */
243588f8b78aSgm89044 ena = dca_ena(ena);
243688f8b78aSgm89044 dca_failure(reqp->dr_dca, DDI_DATAPATH_FAULT,
243788f8b78aSgm89044 DCA_FM_ECLASS_NONE, ena, CRYPTO_DEVICE_ERROR,
243888f8b78aSgm89044 "fault on buffer DMA handle");
243988f8b78aSgm89044 if (err == CRYPTO_SUCCESS) {
244088f8b78aSgm89044 err = CRYPTO_DEVICE_ERROR;
244188f8b78aSgm89044 }
244288f8b78aSgm89044 }
244388f8b78aSgm89044
244488f8b78aSgm89044 if (reqp->dr_callback != NULL) {
244588f8b78aSgm89044 reqp->dr_callback(reqp, err);
244688f8b78aSgm89044 } else {
244788f8b78aSgm89044 dca_freereq(reqp);
244888f8b78aSgm89044 }
244988f8b78aSgm89044 }
245088f8b78aSgm89044
245188f8b78aSgm89044 /*
245288f8b78aSgm89044 * Call this when a failure is detected. It will reset the chip,
245388f8b78aSgm89044 * log a message, alert kCF, and mark jobs in the runq as failed.
245488f8b78aSgm89044 */
245588f8b78aSgm89044 /* ARGSUSED */
245688f8b78aSgm89044 void
dca_failure(dca_t * dca,ddi_fault_location_t loc,dca_fma_eclass_t index,uint64_t ena,int errno,char * mess,...)245788f8b78aSgm89044 dca_failure(dca_t *dca, ddi_fault_location_t loc, dca_fma_eclass_t index,
245888f8b78aSgm89044 uint64_t ena, int errno, char *mess, ...)
245988f8b78aSgm89044 {
246088f8b78aSgm89044 va_list ap;
246188f8b78aSgm89044 char buf[256];
246288f8b78aSgm89044 int mcr;
246388f8b78aSgm89044 char *eclass;
246488f8b78aSgm89044 int have_mutex;
246588f8b78aSgm89044
246688f8b78aSgm89044 va_start(ap, mess);
246788f8b78aSgm89044 (void) vsprintf(buf, mess, ap);
246888f8b78aSgm89044 va_end(ap);
246988f8b78aSgm89044
247088f8b78aSgm89044 eclass = dca_fma_eclass_string(dca->dca_model, index);
247188f8b78aSgm89044
247288f8b78aSgm89044 if (DDI_FM_EREPORT_CAP(dca->fm_capabilities) &&
247388f8b78aSgm89044 index != DCA_FM_ECLASS_NONE) {
247488f8b78aSgm89044 ddi_fm_ereport_post(dca->dca_dip, eclass, ena,
247588f8b78aSgm89044 DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8,
247688f8b78aSgm89044 FM_EREPORT_VERS0, NULL);
247788f8b78aSgm89044
247888f8b78aSgm89044 /* Report the impact of the failure to the DDI. */
247988f8b78aSgm89044 ddi_fm_service_impact(dca->dca_dip, DDI_SERVICE_LOST);
248088f8b78aSgm89044 } else {
248188f8b78aSgm89044 /* Just log the error string to the message log */
248288f8b78aSgm89044 dca_error(dca, buf);
248388f8b78aSgm89044 }
248488f8b78aSgm89044
248588f8b78aSgm89044 /*
248688f8b78aSgm89044 * Indicate a failure (keeps schedule from running).
248788f8b78aSgm89044 */
248888f8b78aSgm89044 dca->dca_flags |= DCA_FAILED;
248988f8b78aSgm89044
249088f8b78aSgm89044 /*
249188f8b78aSgm89044 * Reset the chip. This should also have as a side effect, the
249288f8b78aSgm89044 * disabling of all interrupts from the device.
249388f8b78aSgm89044 */
249488f8b78aSgm89044 (void) dca_reset(dca, 1);
249588f8b78aSgm89044
249688f8b78aSgm89044 /*
249788f8b78aSgm89044 * Report the failure to kCF.
249888f8b78aSgm89044 */
249988f8b78aSgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) {
250088f8b78aSgm89044 if (WORKLIST(dca, mcr)->dwl_prov) {
250188f8b78aSgm89044 crypto_prov_notify(WORKLIST(dca, mcr)->dwl_prov,
250288f8b78aSgm89044 CRYPTO_PROVIDER_FAILED);
250388f8b78aSgm89044 }
250488f8b78aSgm89044 }
250588f8b78aSgm89044
250688f8b78aSgm89044 /*
250788f8b78aSgm89044 * Return jobs not sent to hardware back to kCF.
250888f8b78aSgm89044 */
250988f8b78aSgm89044 dca_rejectjobs(dca);
251088f8b78aSgm89044
251188f8b78aSgm89044 /*
251288f8b78aSgm89044 * From this point on, no new work should be arriving, and the
251388f8b78aSgm89044 * chip should not be doing any active DMA.
251488f8b78aSgm89044 */
251588f8b78aSgm89044
251688f8b78aSgm89044 /*
251788f8b78aSgm89044 * Now find all the work submitted to the device and fail
251888f8b78aSgm89044 * them.
251988f8b78aSgm89044 */
252088f8b78aSgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) {
252188f8b78aSgm89044 dca_worklist_t *wlp;
252288f8b78aSgm89044 int i;
252388f8b78aSgm89044
252488f8b78aSgm89044 wlp = WORKLIST(dca, mcr);
252588f8b78aSgm89044
252688f8b78aSgm89044 if (wlp == NULL || wlp->dwl_waitq.dl_prev == NULL) {
252788f8b78aSgm89044 continue;
252888f8b78aSgm89044 }
252988f8b78aSgm89044 for (;;) {
253088f8b78aSgm89044 dca_work_t *workp;
253188f8b78aSgm89044
253288f8b78aSgm89044 have_mutex = mutex_tryenter(&wlp->dwl_lock);
253388f8b78aSgm89044 workp = (dca_work_t *)dca_dequeue(&wlp->dwl_runq);
253488f8b78aSgm89044 if (workp == NULL) {
253588f8b78aSgm89044 if (have_mutex)
253688f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
253788f8b78aSgm89044 break;
253888f8b78aSgm89044 }
253988f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
254088f8b78aSgm89044
254188f8b78aSgm89044 /*
254288f8b78aSgm89044 * Free up requests
254388f8b78aSgm89044 */
254488f8b78aSgm89044 for (i = 0; i < wlp->dwl_reqspermcr; i++) {
254588f8b78aSgm89044 dca_request_t *reqp = workp->dw_reqs[i];
254688f8b78aSgm89044 if (reqp) {
254788f8b78aSgm89044 dca_done(reqp, errno);
254888f8b78aSgm89044 workp->dw_reqs[i] = NULL;
254988f8b78aSgm89044 }
255088f8b78aSgm89044 }
255188f8b78aSgm89044
255288f8b78aSgm89044 mutex_enter(&wlp->dwl_lock);
255388f8b78aSgm89044 /*
255488f8b78aSgm89044 * If waiting to drain, signal on the waiter.
255588f8b78aSgm89044 */
255688f8b78aSgm89044 if (wlp->dwl_drain && QEMPTY(&wlp->dwl_runq)) {
255788f8b78aSgm89044 cv_signal(&wlp->dwl_cv);
255888f8b78aSgm89044 }
255988f8b78aSgm89044
256088f8b78aSgm89044 /*
256188f8b78aSgm89044 * Return the work and request structures to
256288f8b78aSgm89044 * the free pool.
256388f8b78aSgm89044 */
256488f8b78aSgm89044 dca_freework(workp);
256588f8b78aSgm89044 if (have_mutex)
256688f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
256788f8b78aSgm89044 }
256888f8b78aSgm89044 }
256988f8b78aSgm89044
257088f8b78aSgm89044 }
257188f8b78aSgm89044
257288f8b78aSgm89044 #ifdef SCHEDDELAY
257388f8b78aSgm89044 /*
257488f8b78aSgm89044 * Reschedule worklist as needed.
257588f8b78aSgm89044 */
257688f8b78aSgm89044 void
dca_schedtimeout(void * arg)257788f8b78aSgm89044 dca_schedtimeout(void *arg)
257888f8b78aSgm89044 {
257988f8b78aSgm89044 dca_worklist_t *wlp = (dca_worklist_t *)arg;
258088f8b78aSgm89044 mutex_enter(&wlp->dwl_lock);
258188f8b78aSgm89044 wlp->dwl_schedtid = 0;
258288f8b78aSgm89044 dca_schedule(wlp->dwl_dca, wlp->dwl_mcr);
258388f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
258488f8b78aSgm89044 }
258588f8b78aSgm89044 #endif
258688f8b78aSgm89044
258788f8b78aSgm89044 /*
258888f8b78aSgm89044 * Check for stalled jobs.
258988f8b78aSgm89044 */
259088f8b78aSgm89044 void
dca_jobtimeout(void * arg)259188f8b78aSgm89044 dca_jobtimeout(void *arg)
259288f8b78aSgm89044 {
259388f8b78aSgm89044 int mcr;
259488f8b78aSgm89044 dca_t *dca = (dca_t *)arg;
259588f8b78aSgm89044 int hung = 0;
259688f8b78aSgm89044
259788f8b78aSgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) {
259888f8b78aSgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr);
259988f8b78aSgm89044 dca_work_t *workp;
260088f8b78aSgm89044 clock_t when;
260188f8b78aSgm89044
260288f8b78aSgm89044 mutex_enter(&wlp->dwl_lock);
260388f8b78aSgm89044 when = ddi_get_lbolt();
260488f8b78aSgm89044
260588f8b78aSgm89044 workp = (dca_work_t *)dca_peekqueue(&wlp->dwl_runq);
260688f8b78aSgm89044 if (workp == NULL) {
260788f8b78aSgm89044 /* nothing sitting in the queue */
260888f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
260988f8b78aSgm89044 continue;
261088f8b78aSgm89044 }
261188f8b78aSgm89044
261288f8b78aSgm89044 if ((when - workp->dw_lbolt) < drv_usectohz(STALETIME)) {
261388f8b78aSgm89044 /* request has been queued for less than STALETIME */
261488f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
261588f8b78aSgm89044 continue;
261688f8b78aSgm89044 }
261788f8b78aSgm89044
261888f8b78aSgm89044 /* job has been sitting around for over 1 second, badness */
261988f8b78aSgm89044 DBG(dca, DWARN, "stale job (0x%p) found in MCR%d!", workp,
262088f8b78aSgm89044 mcr);
262188f8b78aSgm89044
262288f8b78aSgm89044 /* put it back in the queue, until we reset the chip */
262388f8b78aSgm89044 hung++;
262488f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
262588f8b78aSgm89044 }
262688f8b78aSgm89044
262788f8b78aSgm89044 if (hung) {
262888f8b78aSgm89044 dca_failure(dca, DDI_DEVICE_FAULT,
262988f8b78aSgm89044 DCA_FM_ECLASS_HW_TIMEOUT, dca_ena(0), CRYPTO_DEVICE_ERROR,
263088f8b78aSgm89044 "timeout processing job.)");
263188f8b78aSgm89044 }
263288f8b78aSgm89044
263388f8b78aSgm89044 /* reschedule ourself */
263488f8b78aSgm89044 mutex_enter(&dca->dca_intrlock);
263588f8b78aSgm89044 if (dca->dca_jobtid == 0) {
263688f8b78aSgm89044 /* timeout has been canceled, prior to DR */
263788f8b78aSgm89044 mutex_exit(&dca->dca_intrlock);
263888f8b78aSgm89044 return;
263988f8b78aSgm89044 }
264088f8b78aSgm89044
264188f8b78aSgm89044 /* check again in 1 second */
264288f8b78aSgm89044 dca->dca_jobtid = timeout(dca_jobtimeout, arg,
264388f8b78aSgm89044 drv_usectohz(SECOND));
264488f8b78aSgm89044 mutex_exit(&dca->dca_intrlock);
264588f8b78aSgm89044 }
264688f8b78aSgm89044
264788f8b78aSgm89044 /*
264888f8b78aSgm89044 * This returns all jobs back to kCF. It assumes that processing
264988f8b78aSgm89044 * on the worklist has halted.
265088f8b78aSgm89044 */
265188f8b78aSgm89044 void
dca_rejectjobs(dca_t * dca)265288f8b78aSgm89044 dca_rejectjobs(dca_t *dca)
265388f8b78aSgm89044 {
265488f8b78aSgm89044 int mcr;
265588f8b78aSgm89044 int have_mutex;
265688f8b78aSgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) {
265788f8b78aSgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr);
265888f8b78aSgm89044 dca_request_t *reqp;
265988f8b78aSgm89044
266088f8b78aSgm89044 if (wlp == NULL || wlp->dwl_waitq.dl_prev == NULL) {
266188f8b78aSgm89044 continue;
266288f8b78aSgm89044 }
266388f8b78aSgm89044 have_mutex = mutex_tryenter(&wlp->dwl_lock);
266488f8b78aSgm89044 for (;;) {
266588f8b78aSgm89044 reqp = (dca_request_t *)dca_unqueue(&wlp->dwl_waitq);
266688f8b78aSgm89044 if (reqp == NULL) {
266788f8b78aSgm89044 break;
266888f8b78aSgm89044 }
266988f8b78aSgm89044 /* update flow control */
267088f8b78aSgm89044 wlp->dwl_count--;
267188f8b78aSgm89044 if ((wlp->dwl_count == wlp->dwl_lowater) &&
267288f8b78aSgm89044 (wlp->dwl_busy)) {
267388f8b78aSgm89044 wlp->dwl_busy = 0;
267488f8b78aSgm89044 crypto_prov_notify(wlp->dwl_prov,
267588f8b78aSgm89044 CRYPTO_PROVIDER_READY);
267688f8b78aSgm89044 }
267788f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
267888f8b78aSgm89044
267988f8b78aSgm89044 (void) dca_unbindchains(reqp);
268088f8b78aSgm89044 reqp->dr_callback(reqp, EAGAIN);
268188f8b78aSgm89044 mutex_enter(&wlp->dwl_lock);
268288f8b78aSgm89044 }
268388f8b78aSgm89044 if (have_mutex)
268488f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
268588f8b78aSgm89044 }
268688f8b78aSgm89044 }
268788f8b78aSgm89044
268888f8b78aSgm89044 int
dca_drain(dca_t * dca)268988f8b78aSgm89044 dca_drain(dca_t *dca)
269088f8b78aSgm89044 {
269188f8b78aSgm89044 int mcr;
269288f8b78aSgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) {
269388f8b78aSgm89044 #ifdef SCHEDDELAY
269488f8b78aSgm89044 timeout_id_t tid;
269588f8b78aSgm89044 #endif
269688f8b78aSgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr);
269788f8b78aSgm89044
269888f8b78aSgm89044 mutex_enter(&wlp->dwl_lock);
269988f8b78aSgm89044 wlp->dwl_drain = 1;
270088f8b78aSgm89044
270188f8b78aSgm89044 /* give it up to a second to drain from the chip */
270288f8b78aSgm89044 if (!QEMPTY(&wlp->dwl_runq)) {
2703d3d50737SRafael Vanoni (void) cv_reltimedwait(&wlp->dwl_cv, &wlp->dwl_lock,
2704d3d50737SRafael Vanoni drv_usectohz(STALETIME), TR_CLOCK_TICK);
270588f8b78aSgm89044
270688f8b78aSgm89044 if (!QEMPTY(&wlp->dwl_runq)) {
270788f8b78aSgm89044 dca_error(dca, "unable to drain device");
270888f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
270988f8b78aSgm89044 dca_undrain(dca);
271088f8b78aSgm89044 return (EBUSY);
271188f8b78aSgm89044 }
271288f8b78aSgm89044 }
271388f8b78aSgm89044
271488f8b78aSgm89044 #ifdef SCHEDDELAY
271588f8b78aSgm89044 tid = wlp->dwl_schedtid;
271688f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
271788f8b78aSgm89044
271888f8b78aSgm89044 /*
271988f8b78aSgm89044 * untimeout outside the lock -- this is safe because we
272088f8b78aSgm89044 * have set the drain flag, so dca_schedule() will not
272188f8b78aSgm89044 * reschedule another timeout
272288f8b78aSgm89044 */
272388f8b78aSgm89044 if (tid) {
272488f8b78aSgm89044 untimeout(tid);
272588f8b78aSgm89044 }
272688f8b78aSgm89044 #else
272788f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
272888f8b78aSgm89044 #endif
272988f8b78aSgm89044 }
273088f8b78aSgm89044 return (0);
273188f8b78aSgm89044 }
273288f8b78aSgm89044
273388f8b78aSgm89044 void
dca_undrain(dca_t * dca)273488f8b78aSgm89044 dca_undrain(dca_t *dca)
273588f8b78aSgm89044 {
273688f8b78aSgm89044 int mcr;
273788f8b78aSgm89044
273888f8b78aSgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) {
273988f8b78aSgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr);
274088f8b78aSgm89044 mutex_enter(&wlp->dwl_lock);
274188f8b78aSgm89044 wlp->dwl_drain = 0;
274288f8b78aSgm89044 dca_schedule(dca, mcr);
274388f8b78aSgm89044 mutex_exit(&wlp->dwl_lock);
274488f8b78aSgm89044 }
274588f8b78aSgm89044 }
274688f8b78aSgm89044
274788f8b78aSgm89044 /*
274888f8b78aSgm89044 * Duplicate the crypto_data_t structure, but point to the original
274988f8b78aSgm89044 * buffers.
275088f8b78aSgm89044 */
275188f8b78aSgm89044 int
dca_dupcrypto(crypto_data_t * input,crypto_data_t * ninput)275288f8b78aSgm89044 dca_dupcrypto(crypto_data_t *input, crypto_data_t *ninput)
275388f8b78aSgm89044 {
275488f8b78aSgm89044 ninput->cd_format = input->cd_format;
275588f8b78aSgm89044 ninput->cd_offset = input->cd_offset;
275688f8b78aSgm89044 ninput->cd_length = input->cd_length;
275788f8b78aSgm89044 ninput->cd_miscdata = input->cd_miscdata;
275888f8b78aSgm89044
275988f8b78aSgm89044 switch (input->cd_format) {
276088f8b78aSgm89044 case CRYPTO_DATA_RAW:
276188f8b78aSgm89044 ninput->cd_raw.iov_base = input->cd_raw.iov_base;
276288f8b78aSgm89044 ninput->cd_raw.iov_len = input->cd_raw.iov_len;
276388f8b78aSgm89044 break;
276488f8b78aSgm89044
276588f8b78aSgm89044 case CRYPTO_DATA_UIO:
276688f8b78aSgm89044 ninput->cd_uio = input->cd_uio;
276788f8b78aSgm89044 break;
276888f8b78aSgm89044
276988f8b78aSgm89044 case CRYPTO_DATA_MBLK:
277088f8b78aSgm89044 ninput->cd_mp = input->cd_mp;
277188f8b78aSgm89044 break;
277288f8b78aSgm89044
277388f8b78aSgm89044 default:
277488f8b78aSgm89044 DBG(NULL, DWARN,
277588f8b78aSgm89044 "dca_dupcrypto: unrecognised crypto data format");
277688f8b78aSgm89044 return (CRYPTO_FAILED);
277788f8b78aSgm89044 }
277888f8b78aSgm89044
277988f8b78aSgm89044 return (CRYPTO_SUCCESS);
278088f8b78aSgm89044 }
278188f8b78aSgm89044
278288f8b78aSgm89044 /*
278388f8b78aSgm89044 * Performs validation checks on the input and output data structures.
278488f8b78aSgm89044 */
278588f8b78aSgm89044 int
dca_verifyio(crypto_data_t * input,crypto_data_t * output)278688f8b78aSgm89044 dca_verifyio(crypto_data_t *input, crypto_data_t *output)
278788f8b78aSgm89044 {
278888f8b78aSgm89044 int rv = CRYPTO_SUCCESS;
278988f8b78aSgm89044
279088f8b78aSgm89044 switch (input->cd_format) {
279188f8b78aSgm89044 case CRYPTO_DATA_RAW:
279288f8b78aSgm89044 break;
279388f8b78aSgm89044
279488f8b78aSgm89044 case CRYPTO_DATA_UIO:
279588f8b78aSgm89044 /* we support only kernel buffer */
279688f8b78aSgm89044 if (input->cd_uio->uio_segflg != UIO_SYSSPACE) {
279788f8b78aSgm89044 DBG(NULL, DWARN, "non kernel input uio buffer");
279888f8b78aSgm89044 rv = CRYPTO_ARGUMENTS_BAD;
279988f8b78aSgm89044 }
280088f8b78aSgm89044 break;
280188f8b78aSgm89044
280288f8b78aSgm89044 case CRYPTO_DATA_MBLK:
280388f8b78aSgm89044 break;
280488f8b78aSgm89044
280588f8b78aSgm89044 default:
280688f8b78aSgm89044 DBG(NULL, DWARN, "unrecognised input crypto data format");
280788f8b78aSgm89044 rv = CRYPTO_ARGUMENTS_BAD;
280888f8b78aSgm89044 }
280988f8b78aSgm89044
281088f8b78aSgm89044 switch (output->cd_format) {
281188f8b78aSgm89044 case CRYPTO_DATA_RAW:
281288f8b78aSgm89044 break;
281388f8b78aSgm89044
281488f8b78aSgm89044 case CRYPTO_DATA_UIO:
281588f8b78aSgm89044 /* we support only kernel buffer */
281688f8b78aSgm89044 if (output->cd_uio->uio_segflg != UIO_SYSSPACE) {
281788f8b78aSgm89044 DBG(NULL, DWARN, "non kernel output uio buffer");
281888f8b78aSgm89044 rv = CRYPTO_ARGUMENTS_BAD;
281988f8b78aSgm89044 }
282088f8b78aSgm89044 break;
282188f8b78aSgm89044
282288f8b78aSgm89044 case CRYPTO_DATA_MBLK:
282388f8b78aSgm89044 break;
282488f8b78aSgm89044
282588f8b78aSgm89044 default:
282688f8b78aSgm89044 DBG(NULL, DWARN, "unrecognised output crypto data format");
282788f8b78aSgm89044 rv = CRYPTO_ARGUMENTS_BAD;
282888f8b78aSgm89044 }
282988f8b78aSgm89044
283088f8b78aSgm89044 return (rv);
283188f8b78aSgm89044 }
283288f8b78aSgm89044
283388f8b78aSgm89044 /*
283488f8b78aSgm89044 * data: source crypto_data_t struct
283588f8b78aSgm89044 * off: offset into the source before commencing copy
283688f8b78aSgm89044 * count: the amount of data to copy
283788f8b78aSgm89044 * dest: destination buffer
283888f8b78aSgm89044 */
283988f8b78aSgm89044 int
dca_getbufbytes(crypto_data_t * data,size_t off,int count,uchar_t * dest)284088f8b78aSgm89044 dca_getbufbytes(crypto_data_t *data, size_t off, int count, uchar_t *dest)
284188f8b78aSgm89044 {
284288f8b78aSgm89044 int rv = CRYPTO_SUCCESS;
284388f8b78aSgm89044 uio_t *uiop;
284488f8b78aSgm89044 uint_t vec_idx;
284588f8b78aSgm89044 size_t cur_len;
284688f8b78aSgm89044 mblk_t *mp;
284788f8b78aSgm89044
284888f8b78aSgm89044 if (count == 0) {
284988f8b78aSgm89044 /* We don't want anything so we're done. */
285088f8b78aSgm89044 return (rv);
285188f8b78aSgm89044 }
285288f8b78aSgm89044
285388f8b78aSgm89044 /*
285488f8b78aSgm89044 * Sanity check that we haven't specified a length greater than the
285588f8b78aSgm89044 * offset adjusted size of the buffer.
285688f8b78aSgm89044 */
285788f8b78aSgm89044 if (count > (data->cd_length - off)) {
285888f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
285988f8b78aSgm89044 }
286088f8b78aSgm89044
286188f8b78aSgm89044 /* Add the internal crypto_data offset to the requested offset. */
286288f8b78aSgm89044 off += data->cd_offset;
286388f8b78aSgm89044
286488f8b78aSgm89044 switch (data->cd_format) {
286588f8b78aSgm89044 case CRYPTO_DATA_RAW:
286688f8b78aSgm89044 bcopy(data->cd_raw.iov_base + off, dest, count);
286788f8b78aSgm89044 break;
286888f8b78aSgm89044
286988f8b78aSgm89044 case CRYPTO_DATA_UIO:
287088f8b78aSgm89044 /*
287188f8b78aSgm89044 * Jump to the first iovec containing data to be
287288f8b78aSgm89044 * processed.
287388f8b78aSgm89044 */
287488f8b78aSgm89044 uiop = data->cd_uio;
287588f8b78aSgm89044 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
287688f8b78aSgm89044 off >= uiop->uio_iov[vec_idx].iov_len;
2877d8dd9913Sgm89044 off -= uiop->uio_iov[vec_idx++].iov_len)
2878d8dd9913Sgm89044 ;
287988f8b78aSgm89044 if (vec_idx == uiop->uio_iovcnt) {
288088f8b78aSgm89044 /*
288188f8b78aSgm89044 * The caller specified an offset that is larger than
288288f8b78aSgm89044 * the total size of the buffers it provided.
288388f8b78aSgm89044 */
288488f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
288588f8b78aSgm89044 }
288688f8b78aSgm89044
288788f8b78aSgm89044 /*
288888f8b78aSgm89044 * Now process the iovecs.
288988f8b78aSgm89044 */
289088f8b78aSgm89044 while (vec_idx < uiop->uio_iovcnt && count > 0) {
289188f8b78aSgm89044 cur_len = min(uiop->uio_iov[vec_idx].iov_len -
289288f8b78aSgm89044 off, count);
289388f8b78aSgm89044 bcopy(uiop->uio_iov[vec_idx].iov_base + off, dest,
289488f8b78aSgm89044 cur_len);
289588f8b78aSgm89044 count -= cur_len;
289688f8b78aSgm89044 dest += cur_len;
289788f8b78aSgm89044 vec_idx++;
289888f8b78aSgm89044 off = 0;
289988f8b78aSgm89044 }
290088f8b78aSgm89044
290188f8b78aSgm89044 if (vec_idx == uiop->uio_iovcnt && count > 0) {
290288f8b78aSgm89044 /*
290388f8b78aSgm89044 * The end of the specified iovec's was reached but
290488f8b78aSgm89044 * the length requested could not be processed
290588f8b78aSgm89044 * (requested to digest more data than it provided).
290688f8b78aSgm89044 */
290788f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
290888f8b78aSgm89044 }
290988f8b78aSgm89044 break;
291088f8b78aSgm89044
291188f8b78aSgm89044 case CRYPTO_DATA_MBLK:
291288f8b78aSgm89044 /*
291388f8b78aSgm89044 * Jump to the first mblk_t containing data to be processed.
291488f8b78aSgm89044 */
291588f8b78aSgm89044 for (mp = data->cd_mp; mp != NULL && off >= MBLKL(mp);
2916d8dd9913Sgm89044 off -= MBLKL(mp), mp = mp->b_cont)
2917d8dd9913Sgm89044 ;
291888f8b78aSgm89044 if (mp == NULL) {
291988f8b78aSgm89044 /*
292088f8b78aSgm89044 * The caller specified an offset that is larger than
292188f8b78aSgm89044 * the total size of the buffers it provided.
292288f8b78aSgm89044 */
292388f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
292488f8b78aSgm89044 }
292588f8b78aSgm89044
292688f8b78aSgm89044 /*
292788f8b78aSgm89044 * Now do the processing on the mblk chain.
292888f8b78aSgm89044 */
292988f8b78aSgm89044 while (mp != NULL && count > 0) {
293088f8b78aSgm89044 cur_len = min(MBLKL(mp) - off, count);
293188f8b78aSgm89044 bcopy((char *)(mp->b_rptr + off), dest, cur_len);
293288f8b78aSgm89044 count -= cur_len;
293388f8b78aSgm89044 dest += cur_len;
293488f8b78aSgm89044 mp = mp->b_cont;
293588f8b78aSgm89044 off = 0;
293688f8b78aSgm89044 }
293788f8b78aSgm89044
293888f8b78aSgm89044 if (mp == NULL && count > 0) {
293988f8b78aSgm89044 /*
294088f8b78aSgm89044 * The end of the mblk was reached but the length
294188f8b78aSgm89044 * requested could not be processed, (requested to
294288f8b78aSgm89044 * digest more data than it provided).
294388f8b78aSgm89044 */
294488f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
294588f8b78aSgm89044 }
294688f8b78aSgm89044 break;
294788f8b78aSgm89044
294888f8b78aSgm89044 default:
294988f8b78aSgm89044 DBG(NULL, DWARN, "unrecognised crypto data format");
295088f8b78aSgm89044 rv = CRYPTO_ARGUMENTS_BAD;
295188f8b78aSgm89044 }
295288f8b78aSgm89044 return (rv);
295388f8b78aSgm89044 }
295488f8b78aSgm89044
295588f8b78aSgm89044
295688f8b78aSgm89044 /*
295788f8b78aSgm89044 * Performs the input, output or hard scatter/gather checks on the specified
295888f8b78aSgm89044 * crypto_data_t struct. Returns true if the data is scatter/gather in nature
295988f8b78aSgm89044 * ie fails the test.
296088f8b78aSgm89044 */
296188f8b78aSgm89044 int
dca_sgcheck(dca_t * dca,crypto_data_t * data,dca_sg_param_t val)296288f8b78aSgm89044 dca_sgcheck(dca_t *dca, crypto_data_t *data, dca_sg_param_t val)
296388f8b78aSgm89044 {
296488f8b78aSgm89044 uio_t *uiop;
296588f8b78aSgm89044 mblk_t *mp;
296688f8b78aSgm89044 int rv = FALSE;
296788f8b78aSgm89044
296888f8b78aSgm89044 switch (val) {
296988f8b78aSgm89044 case DCA_SG_CONTIG:
297088f8b78aSgm89044 /*
297188f8b78aSgm89044 * Check for a contiguous data buffer.
297288f8b78aSgm89044 */
297388f8b78aSgm89044 switch (data->cd_format) {
297488f8b78aSgm89044 case CRYPTO_DATA_RAW:
297588f8b78aSgm89044 /* Contiguous in nature */
297688f8b78aSgm89044 break;
297788f8b78aSgm89044
297888f8b78aSgm89044 case CRYPTO_DATA_UIO:
297988f8b78aSgm89044 if (data->cd_uio->uio_iovcnt > 1)
298088f8b78aSgm89044 rv = TRUE;
298188f8b78aSgm89044 break;
298288f8b78aSgm89044
298388f8b78aSgm89044 case CRYPTO_DATA_MBLK:
298488f8b78aSgm89044 mp = data->cd_mp;
298588f8b78aSgm89044 if (mp->b_cont != NULL)
298688f8b78aSgm89044 rv = TRUE;
298788f8b78aSgm89044 break;
298888f8b78aSgm89044
298988f8b78aSgm89044 default:
299088f8b78aSgm89044 DBG(NULL, DWARN, "unrecognised crypto data format");
299188f8b78aSgm89044 }
299288f8b78aSgm89044 break;
299388f8b78aSgm89044
299488f8b78aSgm89044 case DCA_SG_WALIGN:
299588f8b78aSgm89044 /*
299688f8b78aSgm89044 * Check for a contiguous data buffer that is 32-bit word
299788f8b78aSgm89044 * aligned and is of word multiples in size.
299888f8b78aSgm89044 */
299988f8b78aSgm89044 switch (data->cd_format) {
300088f8b78aSgm89044 case CRYPTO_DATA_RAW:
300188f8b78aSgm89044 if ((data->cd_raw.iov_len % sizeof (uint32_t)) ||
300288f8b78aSgm89044 ((uintptr_t)data->cd_raw.iov_base %
300388f8b78aSgm89044 sizeof (uint32_t))) {
300488f8b78aSgm89044 rv = TRUE;
300588f8b78aSgm89044 }
300688f8b78aSgm89044 break;
300788f8b78aSgm89044
300888f8b78aSgm89044 case CRYPTO_DATA_UIO:
300988f8b78aSgm89044 uiop = data->cd_uio;
301088f8b78aSgm89044 if (uiop->uio_iovcnt > 1) {
301188f8b78aSgm89044 return (TRUE);
301288f8b78aSgm89044 }
301388f8b78aSgm89044 /* So there is only one iovec */
301488f8b78aSgm89044 if ((uiop->uio_iov[0].iov_len % sizeof (uint32_t)) ||
301588f8b78aSgm89044 ((uintptr_t)uiop->uio_iov[0].iov_base %
301688f8b78aSgm89044 sizeof (uint32_t))) {
301788f8b78aSgm89044 rv = TRUE;
301888f8b78aSgm89044 }
301988f8b78aSgm89044 break;
302088f8b78aSgm89044
302188f8b78aSgm89044 case CRYPTO_DATA_MBLK:
302288f8b78aSgm89044 mp = data->cd_mp;
302388f8b78aSgm89044 if (mp->b_cont != NULL) {
302488f8b78aSgm89044 return (TRUE);
302588f8b78aSgm89044 }
302688f8b78aSgm89044 /* So there is only one mblk in the chain */
302788f8b78aSgm89044 if ((MBLKL(mp) % sizeof (uint32_t)) ||
302888f8b78aSgm89044 ((uintptr_t)mp->b_rptr % sizeof (uint32_t))) {
302988f8b78aSgm89044 rv = TRUE;
303088f8b78aSgm89044 }
303188f8b78aSgm89044 break;
303288f8b78aSgm89044
303388f8b78aSgm89044 default:
303488f8b78aSgm89044 DBG(NULL, DWARN, "unrecognised crypto data format");
303588f8b78aSgm89044 }
303688f8b78aSgm89044 break;
303788f8b78aSgm89044
303888f8b78aSgm89044 case DCA_SG_PALIGN:
303988f8b78aSgm89044 /*
304088f8b78aSgm89044 * Check that the data buffer is page aligned and is of
304188f8b78aSgm89044 * page multiples in size.
304288f8b78aSgm89044 */
304388f8b78aSgm89044 switch (data->cd_format) {
304488f8b78aSgm89044 case CRYPTO_DATA_RAW:
304588f8b78aSgm89044 if ((data->cd_length % dca->dca_pagesize) ||
304688f8b78aSgm89044 ((uintptr_t)data->cd_raw.iov_base %
304788f8b78aSgm89044 dca->dca_pagesize)) {
304888f8b78aSgm89044 rv = TRUE;
304988f8b78aSgm89044 }
305088f8b78aSgm89044 break;
305188f8b78aSgm89044
305288f8b78aSgm89044 case CRYPTO_DATA_UIO:
305388f8b78aSgm89044 uiop = data->cd_uio;
305488f8b78aSgm89044 if ((uiop->uio_iov[0].iov_len % dca->dca_pagesize) ||
305588f8b78aSgm89044 ((uintptr_t)uiop->uio_iov[0].iov_base %
305688f8b78aSgm89044 dca->dca_pagesize)) {
305788f8b78aSgm89044 rv = TRUE;
305888f8b78aSgm89044 }
305988f8b78aSgm89044 break;
306088f8b78aSgm89044
306188f8b78aSgm89044 case CRYPTO_DATA_MBLK:
306288f8b78aSgm89044 mp = data->cd_mp;
306388f8b78aSgm89044 if ((MBLKL(mp) % dca->dca_pagesize) ||
306488f8b78aSgm89044 ((uintptr_t)mp->b_rptr % dca->dca_pagesize)) {
306588f8b78aSgm89044 rv = TRUE;
306688f8b78aSgm89044 }
306788f8b78aSgm89044 break;
306888f8b78aSgm89044
306988f8b78aSgm89044 default:
307088f8b78aSgm89044 DBG(NULL, DWARN, "unrecognised crypto data format");
307188f8b78aSgm89044 }
307288f8b78aSgm89044 break;
307388f8b78aSgm89044
307488f8b78aSgm89044 default:
307588f8b78aSgm89044 DBG(NULL, DWARN, "unrecognised scatter/gather param type");
307688f8b78aSgm89044 }
307788f8b78aSgm89044
307888f8b78aSgm89044 return (rv);
307988f8b78aSgm89044 }
308088f8b78aSgm89044
308188f8b78aSgm89044 /*
308288f8b78aSgm89044 * Increments the cd_offset and decrements the cd_length as the data is
308388f8b78aSgm89044 * gathered from the crypto_data_t struct.
308488f8b78aSgm89044 * The data is reverse-copied into the dest buffer if the flag is true.
308588f8b78aSgm89044 */
308688f8b78aSgm89044 int
dca_gather(crypto_data_t * in,char * dest,int count,int reverse)308788f8b78aSgm89044 dca_gather(crypto_data_t *in, char *dest, int count, int reverse)
308888f8b78aSgm89044 {
308988f8b78aSgm89044 int rv = CRYPTO_SUCCESS;
309088f8b78aSgm89044 uint_t vec_idx;
309188f8b78aSgm89044 uio_t *uiop;
309288f8b78aSgm89044 off_t off = in->cd_offset;
309388f8b78aSgm89044 size_t cur_len;
309488f8b78aSgm89044 mblk_t *mp;
309588f8b78aSgm89044
309688f8b78aSgm89044 switch (in->cd_format) {
309788f8b78aSgm89044 case CRYPTO_DATA_RAW:
309888f8b78aSgm89044 if (count > in->cd_length) {
309988f8b78aSgm89044 /*
310088f8b78aSgm89044 * The caller specified a length greater than the
310188f8b78aSgm89044 * size of the buffer.
310288f8b78aSgm89044 */
310388f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
310488f8b78aSgm89044 }
310588f8b78aSgm89044 if (reverse)
310688f8b78aSgm89044 dca_reverse(in->cd_raw.iov_base + off, dest, count,
310788f8b78aSgm89044 count);
310888f8b78aSgm89044 else
310988f8b78aSgm89044 bcopy(in->cd_raw.iov_base + in->cd_offset, dest, count);
311088f8b78aSgm89044 in->cd_offset += count;
311188f8b78aSgm89044 in->cd_length -= count;
311288f8b78aSgm89044 break;
311388f8b78aSgm89044
311488f8b78aSgm89044 case CRYPTO_DATA_UIO:
311588f8b78aSgm89044 /*
311688f8b78aSgm89044 * Jump to the first iovec containing data to be processed.
311788f8b78aSgm89044 */
311888f8b78aSgm89044 uiop = in->cd_uio;
311988f8b78aSgm89044 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
312088f8b78aSgm89044 off >= uiop->uio_iov[vec_idx].iov_len;
3121d8dd9913Sgm89044 off -= uiop->uio_iov[vec_idx++].iov_len)
3122d8dd9913Sgm89044 ;
312388f8b78aSgm89044 if (vec_idx == uiop->uio_iovcnt) {
312488f8b78aSgm89044 /*
312588f8b78aSgm89044 * The caller specified an offset that is larger than
312688f8b78aSgm89044 * the total size of the buffers it provided.
312788f8b78aSgm89044 */
312888f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
312988f8b78aSgm89044 }
313088f8b78aSgm89044
313188f8b78aSgm89044 /*
313288f8b78aSgm89044 * Now process the iovecs.
313388f8b78aSgm89044 */
313488f8b78aSgm89044 while (vec_idx < uiop->uio_iovcnt && count > 0) {
313588f8b78aSgm89044 cur_len = min(uiop->uio_iov[vec_idx].iov_len -
313688f8b78aSgm89044 off, count);
313788f8b78aSgm89044 count -= cur_len;
313888f8b78aSgm89044 if (reverse) {
313988f8b78aSgm89044 /* Fill the dest buffer from the end */
314088f8b78aSgm89044 dca_reverse(uiop->uio_iov[vec_idx].iov_base +
314188f8b78aSgm89044 off, dest+count, cur_len, cur_len);
314288f8b78aSgm89044 } else {
314388f8b78aSgm89044 bcopy(uiop->uio_iov[vec_idx].iov_base + off,
314488f8b78aSgm89044 dest, cur_len);
314588f8b78aSgm89044 dest += cur_len;
314688f8b78aSgm89044 }
314788f8b78aSgm89044 in->cd_offset += cur_len;
314888f8b78aSgm89044 in->cd_length -= cur_len;
314988f8b78aSgm89044 vec_idx++;
315088f8b78aSgm89044 off = 0;
315188f8b78aSgm89044 }
315288f8b78aSgm89044
315388f8b78aSgm89044 if (vec_idx == uiop->uio_iovcnt && count > 0) {
315488f8b78aSgm89044 /*
315588f8b78aSgm89044 * The end of the specified iovec's was reached but
315688f8b78aSgm89044 * the length requested could not be processed
315788f8b78aSgm89044 * (requested to digest more data than it provided).
315888f8b78aSgm89044 */
315988f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
316088f8b78aSgm89044 }
316188f8b78aSgm89044 break;
316288f8b78aSgm89044
316388f8b78aSgm89044 case CRYPTO_DATA_MBLK:
316488f8b78aSgm89044 /*
316588f8b78aSgm89044 * Jump to the first mblk_t containing data to be processed.
316688f8b78aSgm89044 */
316788f8b78aSgm89044 for (mp = in->cd_mp; mp != NULL && off >= MBLKL(mp);
3168d8dd9913Sgm89044 off -= MBLKL(mp), mp = mp->b_cont)
3169d8dd9913Sgm89044 ;
317088f8b78aSgm89044 if (mp == NULL) {
317188f8b78aSgm89044 /*
317288f8b78aSgm89044 * The caller specified an offset that is larger than
317388f8b78aSgm89044 * the total size of the buffers it provided.
317488f8b78aSgm89044 */
317588f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
317688f8b78aSgm89044 }
317788f8b78aSgm89044
317888f8b78aSgm89044 /*
317988f8b78aSgm89044 * Now do the processing on the mblk chain.
318088f8b78aSgm89044 */
318188f8b78aSgm89044 while (mp != NULL && count > 0) {
318288f8b78aSgm89044 cur_len = min(MBLKL(mp) - off, count);
318388f8b78aSgm89044 count -= cur_len;
318488f8b78aSgm89044 if (reverse) {
318588f8b78aSgm89044 /* Fill the dest buffer from the end */
318688f8b78aSgm89044 dca_reverse((char *)(mp->b_rptr + off),
318788f8b78aSgm89044 dest+count, cur_len, cur_len);
318888f8b78aSgm89044 } else {
318988f8b78aSgm89044 bcopy((char *)(mp->b_rptr + off), dest,
319088f8b78aSgm89044 cur_len);
319188f8b78aSgm89044 dest += cur_len;
319288f8b78aSgm89044 }
319388f8b78aSgm89044 in->cd_offset += cur_len;
319488f8b78aSgm89044 in->cd_length -= cur_len;
319588f8b78aSgm89044 mp = mp->b_cont;
319688f8b78aSgm89044 off = 0;
319788f8b78aSgm89044 }
319888f8b78aSgm89044
319988f8b78aSgm89044 if (mp == NULL && count > 0) {
320088f8b78aSgm89044 /*
320188f8b78aSgm89044 * The end of the mblk was reached but the length
320288f8b78aSgm89044 * requested could not be processed, (requested to
320388f8b78aSgm89044 * digest more data than it provided).
320488f8b78aSgm89044 */
320588f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
320688f8b78aSgm89044 }
320788f8b78aSgm89044 break;
320888f8b78aSgm89044
320988f8b78aSgm89044 default:
321088f8b78aSgm89044 DBG(NULL, DWARN, "dca_gather: unrecognised crypto data format");
321188f8b78aSgm89044 rv = CRYPTO_ARGUMENTS_BAD;
321288f8b78aSgm89044 }
321388f8b78aSgm89044 return (rv);
321488f8b78aSgm89044 }
321588f8b78aSgm89044
321688f8b78aSgm89044 /*
321788f8b78aSgm89044 * Increments the cd_offset and decrements the cd_length as the data is
321888f8b78aSgm89044 * gathered from the crypto_data_t struct.
321988f8b78aSgm89044 */
322088f8b78aSgm89044 int
dca_resid_gather(crypto_data_t * in,char * resid,int * residlen,char * dest,int count)322188f8b78aSgm89044 dca_resid_gather(crypto_data_t *in, char *resid, int *residlen, char *dest,
322288f8b78aSgm89044 int count)
322388f8b78aSgm89044 {
322488f8b78aSgm89044 int rv = CRYPTO_SUCCESS;
322588f8b78aSgm89044 caddr_t baddr;
322688f8b78aSgm89044 uint_t vec_idx;
322788f8b78aSgm89044 uio_t *uiop;
322888f8b78aSgm89044 off_t off = in->cd_offset;
322988f8b78aSgm89044 size_t cur_len;
323088f8b78aSgm89044 mblk_t *mp;
323188f8b78aSgm89044
323288f8b78aSgm89044 /* Process the residual first */
323388f8b78aSgm89044 if (*residlen > 0) {
323488f8b78aSgm89044 uint_t num = min(count, *residlen);
323588f8b78aSgm89044 bcopy(resid, dest, num);
323688f8b78aSgm89044 *residlen -= num;
323788f8b78aSgm89044 if (*residlen > 0) {
323888f8b78aSgm89044 /*
323988f8b78aSgm89044 * Requested amount 'count' is less than what's in
324088f8b78aSgm89044 * the residual, so shuffle any remaining resid to
324188f8b78aSgm89044 * the front.
324288f8b78aSgm89044 */
324388f8b78aSgm89044 baddr = resid + num;
324488f8b78aSgm89044 bcopy(baddr, resid, *residlen);
324588f8b78aSgm89044 }
324688f8b78aSgm89044 dest += num;
324788f8b78aSgm89044 count -= num;
324888f8b78aSgm89044 }
324988f8b78aSgm89044
325088f8b78aSgm89044 /* Now process what's in the crypto_data_t structs */
325188f8b78aSgm89044 switch (in->cd_format) {
325288f8b78aSgm89044 case CRYPTO_DATA_RAW:
325388f8b78aSgm89044 if (count > in->cd_length) {
325488f8b78aSgm89044 /*
325588f8b78aSgm89044 * The caller specified a length greater than the
325688f8b78aSgm89044 * size of the buffer.
325788f8b78aSgm89044 */
325888f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
325988f8b78aSgm89044 }
326088f8b78aSgm89044 bcopy(in->cd_raw.iov_base + in->cd_offset, dest, count);
326188f8b78aSgm89044 in->cd_offset += count;
326288f8b78aSgm89044 in->cd_length -= count;
326388f8b78aSgm89044 break;
326488f8b78aSgm89044
326588f8b78aSgm89044 case CRYPTO_DATA_UIO:
326688f8b78aSgm89044 /*
326788f8b78aSgm89044 * Jump to the first iovec containing data to be processed.
326888f8b78aSgm89044 */
326988f8b78aSgm89044 uiop = in->cd_uio;
327088f8b78aSgm89044 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
327188f8b78aSgm89044 off >= uiop->uio_iov[vec_idx].iov_len;
3272d8dd9913Sgm89044 off -= uiop->uio_iov[vec_idx++].iov_len)
3273d8dd9913Sgm89044 ;
327488f8b78aSgm89044 if (vec_idx == uiop->uio_iovcnt) {
327588f8b78aSgm89044 /*
327688f8b78aSgm89044 * The caller specified an offset that is larger than
327788f8b78aSgm89044 * the total size of the buffers it provided.
327888f8b78aSgm89044 */
327988f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
328088f8b78aSgm89044 }
328188f8b78aSgm89044
328288f8b78aSgm89044 /*
328388f8b78aSgm89044 * Now process the iovecs.
328488f8b78aSgm89044 */
328588f8b78aSgm89044 while (vec_idx < uiop->uio_iovcnt && count > 0) {
328688f8b78aSgm89044 cur_len = min(uiop->uio_iov[vec_idx].iov_len -
328788f8b78aSgm89044 off, count);
328888f8b78aSgm89044 bcopy(uiop->uio_iov[vec_idx].iov_base + off, dest,
328988f8b78aSgm89044 cur_len);
329088f8b78aSgm89044 count -= cur_len;
329188f8b78aSgm89044 dest += cur_len;
329288f8b78aSgm89044 in->cd_offset += cur_len;
329388f8b78aSgm89044 in->cd_length -= cur_len;
329488f8b78aSgm89044 vec_idx++;
329588f8b78aSgm89044 off = 0;
329688f8b78aSgm89044 }
329788f8b78aSgm89044
329888f8b78aSgm89044 if (vec_idx == uiop->uio_iovcnt && count > 0) {
329988f8b78aSgm89044 /*
330088f8b78aSgm89044 * The end of the specified iovec's was reached but
330188f8b78aSgm89044 * the length requested could not be processed
330288f8b78aSgm89044 * (requested to digest more data than it provided).
330388f8b78aSgm89044 */
330488f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
330588f8b78aSgm89044 }
330688f8b78aSgm89044 break;
330788f8b78aSgm89044
330888f8b78aSgm89044 case CRYPTO_DATA_MBLK:
330988f8b78aSgm89044 /*
331088f8b78aSgm89044 * Jump to the first mblk_t containing data to be processed.
331188f8b78aSgm89044 */
331288f8b78aSgm89044 for (mp = in->cd_mp; mp != NULL && off >= MBLKL(mp);
3313d8dd9913Sgm89044 off -= MBLKL(mp), mp = mp->b_cont)
3314d8dd9913Sgm89044 ;
331588f8b78aSgm89044 if (mp == NULL) {
331688f8b78aSgm89044 /*
331788f8b78aSgm89044 * The caller specified an offset that is larger than
331888f8b78aSgm89044 * the total size of the buffers it provided.
331988f8b78aSgm89044 */
332088f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
332188f8b78aSgm89044 }
332288f8b78aSgm89044
332388f8b78aSgm89044 /*
332488f8b78aSgm89044 * Now do the processing on the mblk chain.
332588f8b78aSgm89044 */
332688f8b78aSgm89044 while (mp != NULL && count > 0) {
332788f8b78aSgm89044 cur_len = min(MBLKL(mp) - off, count);
332888f8b78aSgm89044 bcopy((char *)(mp->b_rptr + off), dest, cur_len);
332988f8b78aSgm89044 count -= cur_len;
333088f8b78aSgm89044 dest += cur_len;
333188f8b78aSgm89044 in->cd_offset += cur_len;
333288f8b78aSgm89044 in->cd_length -= cur_len;
333388f8b78aSgm89044 mp = mp->b_cont;
333488f8b78aSgm89044 off = 0;
333588f8b78aSgm89044 }
333688f8b78aSgm89044
333788f8b78aSgm89044 if (mp == NULL && count > 0) {
333888f8b78aSgm89044 /*
333988f8b78aSgm89044 * The end of the mblk was reached but the length
334088f8b78aSgm89044 * requested could not be processed, (requested to
334188f8b78aSgm89044 * digest more data than it provided).
334288f8b78aSgm89044 */
334388f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
334488f8b78aSgm89044 }
334588f8b78aSgm89044 break;
334688f8b78aSgm89044
334788f8b78aSgm89044 default:
334888f8b78aSgm89044 DBG(NULL, DWARN,
334988f8b78aSgm89044 "dca_resid_gather: unrecognised crypto data format");
335088f8b78aSgm89044 rv = CRYPTO_ARGUMENTS_BAD;
335188f8b78aSgm89044 }
335288f8b78aSgm89044 return (rv);
335388f8b78aSgm89044 }
335488f8b78aSgm89044
335588f8b78aSgm89044 /*
335688f8b78aSgm89044 * Appends the data to the crypto_data_t struct increasing cd_length.
335788f8b78aSgm89044 * cd_offset is left unchanged.
335888f8b78aSgm89044 * Data is reverse-copied if the flag is TRUE.
335988f8b78aSgm89044 */
336088f8b78aSgm89044 int
dca_scatter(const char * src,crypto_data_t * out,int count,int reverse)336188f8b78aSgm89044 dca_scatter(const char *src, crypto_data_t *out, int count, int reverse)
336288f8b78aSgm89044 {
336388f8b78aSgm89044 int rv = CRYPTO_SUCCESS;
336488f8b78aSgm89044 off_t offset = out->cd_offset + out->cd_length;
336588f8b78aSgm89044 uint_t vec_idx;
336688f8b78aSgm89044 uio_t *uiop;
336788f8b78aSgm89044 size_t cur_len;
336888f8b78aSgm89044 mblk_t *mp;
336988f8b78aSgm89044
337088f8b78aSgm89044 switch (out->cd_format) {
337188f8b78aSgm89044 case CRYPTO_DATA_RAW:
337288f8b78aSgm89044 if (out->cd_raw.iov_len - offset < count) {
337388f8b78aSgm89044 /* Trying to write out more than space available. */
337488f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
337588f8b78aSgm89044 }
337688f8b78aSgm89044 if (reverse)
337788f8b78aSgm89044 dca_reverse((void*) src, out->cd_raw.iov_base + offset,
337888f8b78aSgm89044 count, count);
337988f8b78aSgm89044 else
338088f8b78aSgm89044 bcopy(src, out->cd_raw.iov_base + offset, count);
338188f8b78aSgm89044 out->cd_length += count;
338288f8b78aSgm89044 break;
338388f8b78aSgm89044
338488f8b78aSgm89044 case CRYPTO_DATA_UIO:
338588f8b78aSgm89044 /*
338688f8b78aSgm89044 * Jump to the first iovec that can be written to.
338788f8b78aSgm89044 */
338888f8b78aSgm89044 uiop = out->cd_uio;
338988f8b78aSgm89044 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
339088f8b78aSgm89044 offset >= uiop->uio_iov[vec_idx].iov_len;
3391d8dd9913Sgm89044 offset -= uiop->uio_iov[vec_idx++].iov_len)
3392d8dd9913Sgm89044 ;
339388f8b78aSgm89044 if (vec_idx == uiop->uio_iovcnt) {
339488f8b78aSgm89044 /*
339588f8b78aSgm89044 * The caller specified an offset that is larger than
339688f8b78aSgm89044 * the total size of the buffers it provided.
339788f8b78aSgm89044 */
339888f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
339988f8b78aSgm89044 }
340088f8b78aSgm89044
340188f8b78aSgm89044 /*
340288f8b78aSgm89044 * Now process the iovecs.
340388f8b78aSgm89044 */
340488f8b78aSgm89044 while (vec_idx < uiop->uio_iovcnt && count > 0) {
340588f8b78aSgm89044 cur_len = min(uiop->uio_iov[vec_idx].iov_len -
340688f8b78aSgm89044 offset, count);
340788f8b78aSgm89044 count -= cur_len;
340888f8b78aSgm89044 if (reverse) {
340988f8b78aSgm89044 dca_reverse((void*) (src+count),
341088f8b78aSgm89044 uiop->uio_iov[vec_idx].iov_base +
341188f8b78aSgm89044 offset, cur_len, cur_len);
341288f8b78aSgm89044 } else {
341388f8b78aSgm89044 bcopy(src, uiop->uio_iov[vec_idx].iov_base +
341488f8b78aSgm89044 offset, cur_len);
341588f8b78aSgm89044 src += cur_len;
341688f8b78aSgm89044 }
341788f8b78aSgm89044 out->cd_length += cur_len;
341888f8b78aSgm89044 vec_idx++;
341988f8b78aSgm89044 offset = 0;
342088f8b78aSgm89044 }
342188f8b78aSgm89044
342288f8b78aSgm89044 if (vec_idx == uiop->uio_iovcnt && count > 0) {
342388f8b78aSgm89044 /*
342488f8b78aSgm89044 * The end of the specified iovec's was reached but
342588f8b78aSgm89044 * the length requested could not be processed
342688f8b78aSgm89044 * (requested to write more data than space provided).
342788f8b78aSgm89044 */
342888f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
342988f8b78aSgm89044 }
343088f8b78aSgm89044 break;
343188f8b78aSgm89044
343288f8b78aSgm89044 case CRYPTO_DATA_MBLK:
343388f8b78aSgm89044 /*
343488f8b78aSgm89044 * Jump to the first mblk_t that can be written to.
343588f8b78aSgm89044 */
343688f8b78aSgm89044 for (mp = out->cd_mp; mp != NULL && offset >= MBLKL(mp);
3437d8dd9913Sgm89044 offset -= MBLKL(mp), mp = mp->b_cont)
3438d8dd9913Sgm89044 ;
343988f8b78aSgm89044 if (mp == NULL) {
344088f8b78aSgm89044 /*
344188f8b78aSgm89044 * The caller specified an offset that is larger than
344288f8b78aSgm89044 * the total size of the buffers it provided.
344388f8b78aSgm89044 */
344488f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
344588f8b78aSgm89044 }
344688f8b78aSgm89044
344788f8b78aSgm89044 /*
344888f8b78aSgm89044 * Now do the processing on the mblk chain.
344988f8b78aSgm89044 */
345088f8b78aSgm89044 while (mp != NULL && count > 0) {
345188f8b78aSgm89044 cur_len = min(MBLKL(mp) - offset, count);
345288f8b78aSgm89044 count -= cur_len;
345388f8b78aSgm89044 if (reverse) {
345488f8b78aSgm89044 dca_reverse((void*) (src+count),
345588f8b78aSgm89044 (char *)(mp->b_rptr + offset), cur_len,
345688f8b78aSgm89044 cur_len);
345788f8b78aSgm89044 } else {
345888f8b78aSgm89044 bcopy(src, (char *)(mp->b_rptr + offset),
345988f8b78aSgm89044 cur_len);
346088f8b78aSgm89044 src += cur_len;
346188f8b78aSgm89044 }
346288f8b78aSgm89044 out->cd_length += cur_len;
346388f8b78aSgm89044 mp = mp->b_cont;
346488f8b78aSgm89044 offset = 0;
346588f8b78aSgm89044 }
346688f8b78aSgm89044
346788f8b78aSgm89044 if (mp == NULL && count > 0) {
346888f8b78aSgm89044 /*
346988f8b78aSgm89044 * The end of the mblk was reached but the length
347088f8b78aSgm89044 * requested could not be processed, (requested to
347188f8b78aSgm89044 * digest more data than it provided).
347288f8b78aSgm89044 */
347388f8b78aSgm89044 return (CRYPTO_DATA_LEN_RANGE);
347488f8b78aSgm89044 }
347588f8b78aSgm89044 break;
347688f8b78aSgm89044
347788f8b78aSgm89044 default:
347888f8b78aSgm89044 DBG(NULL, DWARN, "unrecognised crypto data format");
347988f8b78aSgm89044 rv = CRYPTO_ARGUMENTS_BAD;
348088f8b78aSgm89044 }
348188f8b78aSgm89044 return (rv);
348288f8b78aSgm89044 }
348388f8b78aSgm89044
348488f8b78aSgm89044 /*
348588f8b78aSgm89044 * Compare two byte arrays in reverse order.
348688f8b78aSgm89044 * Return 0 if they are identical, 1 otherwise.
348788f8b78aSgm89044 */
348888f8b78aSgm89044 int
dca_bcmp_reverse(const void * s1,const void * s2,size_t n)348988f8b78aSgm89044 dca_bcmp_reverse(const void *s1, const void *s2, size_t n)
349088f8b78aSgm89044 {
349188f8b78aSgm89044 int i;
349288f8b78aSgm89044 caddr_t src, dst;
349388f8b78aSgm89044
349488f8b78aSgm89044 if (!n)
349588f8b78aSgm89044 return (0);
349688f8b78aSgm89044
349788f8b78aSgm89044 src = ((caddr_t)s1) + n - 1;
349888f8b78aSgm89044 dst = (caddr_t)s2;
349988f8b78aSgm89044 for (i = 0; i < n; i++) {
350088f8b78aSgm89044 if (*src != *dst)
350188f8b78aSgm89044 return (1);
350288f8b78aSgm89044 src--;
350388f8b78aSgm89044 dst++;
350488f8b78aSgm89044 }
350588f8b78aSgm89044
350688f8b78aSgm89044 return (0);
350788f8b78aSgm89044 }
350888f8b78aSgm89044
350988f8b78aSgm89044
351088f8b78aSgm89044 /*
351188f8b78aSgm89044 * This calculates the size of a bignum in bits, specifically not counting
351288f8b78aSgm89044 * leading zero bits. This size calculation must be done *before* any
351388f8b78aSgm89044 * endian reversal takes place (i.e. the numbers are in absolute big-endian
351488f8b78aSgm89044 * order.)
351588f8b78aSgm89044 */
351688f8b78aSgm89044 int
dca_bitlen(unsigned char * bignum,int bytelen)351788f8b78aSgm89044 dca_bitlen(unsigned char *bignum, int bytelen)
351888f8b78aSgm89044 {
351988f8b78aSgm89044 unsigned char msbyte;
352088f8b78aSgm89044 int i, j;
352188f8b78aSgm89044
352288f8b78aSgm89044 for (i = 0; i < bytelen - 1; i++) {
352388f8b78aSgm89044 if (bignum[i] != 0) {
352488f8b78aSgm89044 break;
352588f8b78aSgm89044 }
352688f8b78aSgm89044 }
352788f8b78aSgm89044 msbyte = bignum[i];
352888f8b78aSgm89044 for (j = 8; j > 1; j--) {
352988f8b78aSgm89044 if (msbyte & 0x80) {
353088f8b78aSgm89044 break;
353188f8b78aSgm89044 }
353288f8b78aSgm89044 msbyte <<= 1;
353388f8b78aSgm89044 }
353488f8b78aSgm89044 return ((8 * (bytelen - i - 1)) + j);
353588f8b78aSgm89044 }
353688f8b78aSgm89044
353788f8b78aSgm89044 /*
353888f8b78aSgm89044 * This compares to bignums (in big-endian order). It ignores leading
353988f8b78aSgm89044 * null bytes. The result semantics follow bcmp, mempcmp, strcmp, etc.
354088f8b78aSgm89044 */
354188f8b78aSgm89044 int
dca_numcmp(caddr_t n1,int n1len,caddr_t n2,int n2len)354288f8b78aSgm89044 dca_numcmp(caddr_t n1, int n1len, caddr_t n2, int n2len)
354388f8b78aSgm89044 {
354488f8b78aSgm89044 while ((n1len > 1) && (*n1 == 0)) {
354588f8b78aSgm89044 n1len--;
354688f8b78aSgm89044 n1++;
354788f8b78aSgm89044 }
354888f8b78aSgm89044 while ((n2len > 1) && (*n2 == 0)) {
354988f8b78aSgm89044 n2len--;
355088f8b78aSgm89044 n2++;
355188f8b78aSgm89044 }
355288f8b78aSgm89044 if (n1len != n2len) {
355388f8b78aSgm89044 return (n1len - n2len);
355488f8b78aSgm89044 }
355588f8b78aSgm89044 while ((n1len > 1) && (*n1 == *n2)) {
355688f8b78aSgm89044 n1++;
355788f8b78aSgm89044 n2++;
355888f8b78aSgm89044 n1len--;
355988f8b78aSgm89044 }
356088f8b78aSgm89044 return ((int)(*(uchar_t *)n1) - (int)(*(uchar_t *)n2));
356188f8b78aSgm89044 }
356288f8b78aSgm89044
356388f8b78aSgm89044 /*
356488f8b78aSgm89044 * Return array of key attributes.
356588f8b78aSgm89044 */
356688f8b78aSgm89044 crypto_object_attribute_t *
dca_get_key_attr(crypto_key_t * key)356788f8b78aSgm89044 dca_get_key_attr(crypto_key_t *key)
356888f8b78aSgm89044 {
356988f8b78aSgm89044 if ((key->ck_format != CRYPTO_KEY_ATTR_LIST) ||
357088f8b78aSgm89044 (key->ck_count == 0)) {
357188f8b78aSgm89044 return (NULL);
357288f8b78aSgm89044 }
357388f8b78aSgm89044
357488f8b78aSgm89044 return (key->ck_attrs);
357588f8b78aSgm89044 }
357688f8b78aSgm89044
357788f8b78aSgm89044 /*
357888f8b78aSgm89044 * If attribute type exists valp points to it's 32-bit value.
357988f8b78aSgm89044 */
358088f8b78aSgm89044 int
dca_attr_lookup_uint32(crypto_object_attribute_t * attrp,uint_t atnum,uint64_t atype,uint32_t * valp)358188f8b78aSgm89044 dca_attr_lookup_uint32(crypto_object_attribute_t *attrp, uint_t atnum,
358288f8b78aSgm89044 uint64_t atype, uint32_t *valp)
358388f8b78aSgm89044 {
358488f8b78aSgm89044 crypto_object_attribute_t *bap;
358588f8b78aSgm89044
358688f8b78aSgm89044 bap = dca_find_attribute(attrp, atnum, atype);
358788f8b78aSgm89044 if (bap == NULL) {
358888f8b78aSgm89044 return (CRYPTO_ATTRIBUTE_TYPE_INVALID);
358988f8b78aSgm89044 }
359088f8b78aSgm89044
359188f8b78aSgm89044 *valp = *bap->oa_value;
359288f8b78aSgm89044
359388f8b78aSgm89044 return (CRYPTO_SUCCESS);
359488f8b78aSgm89044 }
359588f8b78aSgm89044
359688f8b78aSgm89044 /*
359788f8b78aSgm89044 * If attribute type exists data contains the start address of the value,
359888f8b78aSgm89044 * and numelems contains it's length.
359988f8b78aSgm89044 */
360088f8b78aSgm89044 int
dca_attr_lookup_uint8_array(crypto_object_attribute_t * attrp,uint_t atnum,uint64_t atype,void ** data,unsigned int * numelems)360188f8b78aSgm89044 dca_attr_lookup_uint8_array(crypto_object_attribute_t *attrp, uint_t atnum,
360288f8b78aSgm89044 uint64_t atype, void **data, unsigned int *numelems)
360388f8b78aSgm89044 {
360488f8b78aSgm89044 crypto_object_attribute_t *bap;
360588f8b78aSgm89044
360688f8b78aSgm89044 bap = dca_find_attribute(attrp, atnum, atype);
360788f8b78aSgm89044 if (bap == NULL) {
360888f8b78aSgm89044 return (CRYPTO_ATTRIBUTE_TYPE_INVALID);
360988f8b78aSgm89044 }
361088f8b78aSgm89044
361188f8b78aSgm89044 *data = bap->oa_value;
361288f8b78aSgm89044 *numelems = bap->oa_value_len;
361388f8b78aSgm89044
361488f8b78aSgm89044 return (CRYPTO_SUCCESS);
361588f8b78aSgm89044 }
361688f8b78aSgm89044
361788f8b78aSgm89044 /*
361888f8b78aSgm89044 * Finds entry of specified name. If it is not found dca_find_attribute returns
361988f8b78aSgm89044 * NULL.
362088f8b78aSgm89044 */
362188f8b78aSgm89044 crypto_object_attribute_t *
dca_find_attribute(crypto_object_attribute_t * attrp,uint_t atnum,uint64_t atype)362288f8b78aSgm89044 dca_find_attribute(crypto_object_attribute_t *attrp, uint_t atnum,
362388f8b78aSgm89044 uint64_t atype)
362488f8b78aSgm89044 {
362588f8b78aSgm89044 while (atnum) {
362688f8b78aSgm89044 if (attrp->oa_type == atype)
362788f8b78aSgm89044 return (attrp);
362888f8b78aSgm89044 atnum--;
362988f8b78aSgm89044 attrp++;
363088f8b78aSgm89044 }
363188f8b78aSgm89044 return (NULL);
363288f8b78aSgm89044 }
363388f8b78aSgm89044
363488f8b78aSgm89044 /*
363588f8b78aSgm89044 * Return the address of the first data buffer. If the data format is
363688f8b78aSgm89044 * unrecognised return NULL.
363788f8b78aSgm89044 */
363888f8b78aSgm89044 caddr_t
dca_bufdaddr(crypto_data_t * data)363988f8b78aSgm89044 dca_bufdaddr(crypto_data_t *data)
364088f8b78aSgm89044 {
364188f8b78aSgm89044 switch (data->cd_format) {
364288f8b78aSgm89044 case CRYPTO_DATA_RAW:
364388f8b78aSgm89044 return (data->cd_raw.iov_base + data->cd_offset);
364488f8b78aSgm89044 case CRYPTO_DATA_UIO:
364588f8b78aSgm89044 return (data->cd_uio->uio_iov[0].iov_base + data->cd_offset);
364688f8b78aSgm89044 case CRYPTO_DATA_MBLK:
364788f8b78aSgm89044 return ((char *)data->cd_mp->b_rptr + data->cd_offset);
364888f8b78aSgm89044 default:
364988f8b78aSgm89044 DBG(NULL, DWARN,
365088f8b78aSgm89044 "dca_bufdaddr: unrecognised crypto data format");
365188f8b78aSgm89044 return (NULL);
365288f8b78aSgm89044 }
365388f8b78aSgm89044 }
365488f8b78aSgm89044
365588f8b78aSgm89044 static caddr_t
dca_bufdaddr_out(crypto_data_t * data)365688f8b78aSgm89044 dca_bufdaddr_out(crypto_data_t *data)
365788f8b78aSgm89044 {
365888f8b78aSgm89044 size_t offset = data->cd_offset + data->cd_length;
365988f8b78aSgm89044
366088f8b78aSgm89044 switch (data->cd_format) {
366188f8b78aSgm89044 case CRYPTO_DATA_RAW:
366288f8b78aSgm89044 return (data->cd_raw.iov_base + offset);
366388f8b78aSgm89044 case CRYPTO_DATA_UIO:
366488f8b78aSgm89044 return (data->cd_uio->uio_iov[0].iov_base + offset);
366588f8b78aSgm89044 case CRYPTO_DATA_MBLK:
366688f8b78aSgm89044 return ((char *)data->cd_mp->b_rptr + offset);
366788f8b78aSgm89044 default:
366888f8b78aSgm89044 DBG(NULL, DWARN,
366988f8b78aSgm89044 "dca_bufdaddr_out: unrecognised crypto data format");
367088f8b78aSgm89044 return (NULL);
367188f8b78aSgm89044 }
367288f8b78aSgm89044 }
367388f8b78aSgm89044
367488f8b78aSgm89044 /*
367588f8b78aSgm89044 * Control entry points.
367688f8b78aSgm89044 */
367788f8b78aSgm89044
367888f8b78aSgm89044 /* ARGSUSED */
367988f8b78aSgm89044 static void
dca_provider_status(crypto_provider_handle_t provider,uint_t * status)368088f8b78aSgm89044 dca_provider_status(crypto_provider_handle_t provider, uint_t *status)
368188f8b78aSgm89044 {
368288f8b78aSgm89044 *status = CRYPTO_PROVIDER_READY;
368388f8b78aSgm89044 }
368488f8b78aSgm89044
368588f8b78aSgm89044 /*
368688f8b78aSgm89044 * Cipher (encrypt/decrypt) entry points.
368788f8b78aSgm89044 */
368888f8b78aSgm89044
368988f8b78aSgm89044 /* ARGSUSED */
369088f8b78aSgm89044 static int
dca_encrypt_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)369188f8b78aSgm89044 dca_encrypt_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
369288f8b78aSgm89044 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
369388f8b78aSgm89044 crypto_req_handle_t req)
369488f8b78aSgm89044 {
369588f8b78aSgm89044 int error = CRYPTO_FAILED;
369688f8b78aSgm89044 dca_t *softc;
369788f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
369888f8b78aSgm89044 int instance;
369988f8b78aSgm89044
370088f8b78aSgm89044 /* extract softc and instance number from context */
370188f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
370288f8b78aSgm89044 DBG(softc, DENTRY, "dca_encrypt_init: started");
370388f8b78aSgm89044
370488f8b78aSgm89044 /* check mechanism */
370588f8b78aSgm89044 switch (mechanism->cm_type) {
370688f8b78aSgm89044 case DES_CBC_MECH_INFO_TYPE:
370788f8b78aSgm89044 error = dca_3desctxinit(ctx, mechanism, key, KM_SLEEP,
370888f8b78aSgm89044 DR_ENCRYPT);
370988f8b78aSgm89044 break;
371088f8b78aSgm89044 case DES3_CBC_MECH_INFO_TYPE:
371188f8b78aSgm89044 error = dca_3desctxinit(ctx, mechanism, key, KM_SLEEP,
371288f8b78aSgm89044 DR_ENCRYPT | DR_TRIPLE);
371388f8b78aSgm89044 break;
371488f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
371588f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
371688f8b78aSgm89044 error = dca_rsainit(ctx, mechanism, key, KM_SLEEP);
371788f8b78aSgm89044 break;
371888f8b78aSgm89044 default:
371988f8b78aSgm89044 cmn_err(CE_WARN, "dca_encrypt_init: unexpected mech type "
372088f8b78aSgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type);
372188f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
372288f8b78aSgm89044 }
372388f8b78aSgm89044
372488f8b78aSgm89044 DBG(softc, DENTRY, "dca_encrypt_init: done, err = 0x%x", error);
372588f8b78aSgm89044
372688f8b78aSgm89044 if (error == CRYPTO_SUCCESS)
372788f8b78aSgm89044 dca_enlist2(&softc->dca_ctx_list, ctx->cc_provider_private,
372888f8b78aSgm89044 &softc->dca_ctx_list_lock);
372988f8b78aSgm89044
373088f8b78aSgm89044 return (error);
373188f8b78aSgm89044 }
373288f8b78aSgm89044
373388f8b78aSgm89044 /* ARGSUSED */
373488f8b78aSgm89044 static int
dca_encrypt(crypto_ctx_t * ctx,crypto_data_t * plaintext,crypto_data_t * ciphertext,crypto_req_handle_t req)373588f8b78aSgm89044 dca_encrypt(crypto_ctx_t *ctx, crypto_data_t *plaintext,
373688f8b78aSgm89044 crypto_data_t *ciphertext, crypto_req_handle_t req)
373788f8b78aSgm89044 {
373888f8b78aSgm89044 int error = CRYPTO_FAILED;
373988f8b78aSgm89044 dca_t *softc;
374088f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
374188f8b78aSgm89044 int instance;
374288f8b78aSgm89044
374388f8b78aSgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private)
374488f8b78aSgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED);
374588f8b78aSgm89044
374688f8b78aSgm89044 /* extract softc and instance number from context */
374788f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
374888f8b78aSgm89044 DBG(softc, DENTRY, "dca_encrypt: started");
374988f8b78aSgm89044
3750d8dd9913Sgm89044 /* handle inplace ops */
3751d8dd9913Sgm89044 if (!ciphertext) {
3752d8dd9913Sgm89044 dca_request_t *reqp = ctx->cc_provider_private;
3753d8dd9913Sgm89044 reqp->dr_flags |= DR_INPLACE;
3754d8dd9913Sgm89044 ciphertext = plaintext;
3755d8dd9913Sgm89044 }
3756d8dd9913Sgm89044
375788f8b78aSgm89044 /* check mechanism */
375888f8b78aSgm89044 switch (DCA_MECH_FROM_CTX(ctx)) {
375988f8b78aSgm89044 case DES_CBC_MECH_INFO_TYPE:
376088f8b78aSgm89044 error = dca_3des(ctx, plaintext, ciphertext, req, DR_ENCRYPT);
376188f8b78aSgm89044 break;
376288f8b78aSgm89044 case DES3_CBC_MECH_INFO_TYPE:
376388f8b78aSgm89044 error = dca_3des(ctx, plaintext, ciphertext, req,
376488f8b78aSgm89044 DR_ENCRYPT | DR_TRIPLE);
376588f8b78aSgm89044 break;
376688f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
376788f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
376888f8b78aSgm89044 error = dca_rsastart(ctx, plaintext, ciphertext, req,
376988f8b78aSgm89044 DCA_RSA_ENC);
377088f8b78aSgm89044 break;
377188f8b78aSgm89044 default:
377288f8b78aSgm89044 /* Should never reach here */
377388f8b78aSgm89044 cmn_err(CE_WARN, "dca_encrypt: unexpected mech type "
377488f8b78aSgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx));
377588f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
377688f8b78aSgm89044 }
377788f8b78aSgm89044
377888f8b78aSgm89044 if ((error != CRYPTO_QUEUED) && (error != CRYPTO_SUCCESS) &&
377988f8b78aSgm89044 (error != CRYPTO_BUFFER_TOO_SMALL)) {
378088f8b78aSgm89044 ciphertext->cd_length = 0;
378188f8b78aSgm89044 }
378288f8b78aSgm89044
378388f8b78aSgm89044 DBG(softc, DENTRY, "dca_encrypt: done, err = 0x%x", error);
378488f8b78aSgm89044
378588f8b78aSgm89044 return (error);
378688f8b78aSgm89044 }
378788f8b78aSgm89044
378888f8b78aSgm89044 /* ARGSUSED */
378988f8b78aSgm89044 static int
dca_encrypt_update(crypto_ctx_t * ctx,crypto_data_t * plaintext,crypto_data_t * ciphertext,crypto_req_handle_t req)379088f8b78aSgm89044 dca_encrypt_update(crypto_ctx_t *ctx, crypto_data_t *plaintext,
379188f8b78aSgm89044 crypto_data_t *ciphertext, crypto_req_handle_t req)
379288f8b78aSgm89044 {
379388f8b78aSgm89044 int error = CRYPTO_FAILED;
379488f8b78aSgm89044 dca_t *softc;
379588f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
379688f8b78aSgm89044 int instance;
379788f8b78aSgm89044
379888f8b78aSgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private)
379988f8b78aSgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED);
380088f8b78aSgm89044
380188f8b78aSgm89044 /* extract softc and instance number from context */
380288f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
380388f8b78aSgm89044 DBG(softc, DENTRY, "dca_encrypt_update: started");
380488f8b78aSgm89044
3805d8dd9913Sgm89044 /* handle inplace ops */
3806d8dd9913Sgm89044 if (!ciphertext) {
3807d8dd9913Sgm89044 dca_request_t *reqp = ctx->cc_provider_private;
3808d8dd9913Sgm89044 reqp->dr_flags |= DR_INPLACE;
3809d8dd9913Sgm89044 ciphertext = plaintext;
3810d8dd9913Sgm89044 }
3811d8dd9913Sgm89044
381288f8b78aSgm89044 /* check mechanism */
381388f8b78aSgm89044 switch (DCA_MECH_FROM_CTX(ctx)) {
381488f8b78aSgm89044 case DES_CBC_MECH_INFO_TYPE:
381588f8b78aSgm89044 error = dca_3desupdate(ctx, plaintext, ciphertext, req,
381688f8b78aSgm89044 DR_ENCRYPT);
381788f8b78aSgm89044 break;
381888f8b78aSgm89044 case DES3_CBC_MECH_INFO_TYPE:
381988f8b78aSgm89044 error = dca_3desupdate(ctx, plaintext, ciphertext, req,
382088f8b78aSgm89044 DR_ENCRYPT | DR_TRIPLE);
382188f8b78aSgm89044 break;
382288f8b78aSgm89044 default:
382388f8b78aSgm89044 /* Should never reach here */
382488f8b78aSgm89044 cmn_err(CE_WARN, "dca_encrypt_update: unexpected mech type "
382588f8b78aSgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx));
382688f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
382788f8b78aSgm89044 }
382888f8b78aSgm89044
382988f8b78aSgm89044 DBG(softc, DENTRY, "dca_encrypt_update: done, err = 0x%x", error);
383088f8b78aSgm89044
383188f8b78aSgm89044 return (error);
383288f8b78aSgm89044 }
383388f8b78aSgm89044
383488f8b78aSgm89044 /* ARGSUSED */
383588f8b78aSgm89044 static int
dca_encrypt_final(crypto_ctx_t * ctx,crypto_data_t * ciphertext,crypto_req_handle_t req)383688f8b78aSgm89044 dca_encrypt_final(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
383788f8b78aSgm89044 crypto_req_handle_t req)
383888f8b78aSgm89044 {
383988f8b78aSgm89044 int error = CRYPTO_FAILED;
384088f8b78aSgm89044 dca_t *softc;
384188f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
384288f8b78aSgm89044 int instance;
384388f8b78aSgm89044
384488f8b78aSgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private)
384588f8b78aSgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED);
384688f8b78aSgm89044
384788f8b78aSgm89044 /* extract softc and instance number from context */
384888f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
384988f8b78aSgm89044 DBG(softc, DENTRY, "dca_encrypt_final: started");
385088f8b78aSgm89044
385188f8b78aSgm89044 /* check mechanism */
385288f8b78aSgm89044 switch (DCA_MECH_FROM_CTX(ctx)) {
385388f8b78aSgm89044 case DES_CBC_MECH_INFO_TYPE:
385488f8b78aSgm89044 error = dca_3desfinal(ctx, ciphertext, DR_ENCRYPT);
385588f8b78aSgm89044 break;
385688f8b78aSgm89044 case DES3_CBC_MECH_INFO_TYPE:
385788f8b78aSgm89044 error = dca_3desfinal(ctx, ciphertext, DR_ENCRYPT | DR_TRIPLE);
385888f8b78aSgm89044 break;
385988f8b78aSgm89044 default:
386088f8b78aSgm89044 /* Should never reach here */
386188f8b78aSgm89044 cmn_err(CE_WARN, "dca_encrypt_final: unexpected mech type "
386288f8b78aSgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx));
386388f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
386488f8b78aSgm89044 }
386588f8b78aSgm89044
386688f8b78aSgm89044 DBG(softc, DENTRY, "dca_encrypt_final: done, err = 0x%x", error);
386788f8b78aSgm89044
386888f8b78aSgm89044 return (error);
386988f8b78aSgm89044 }
387088f8b78aSgm89044
387188f8b78aSgm89044 /* ARGSUSED */
387288f8b78aSgm89044 static int
dca_encrypt_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * plaintext,crypto_data_t * ciphertext,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)387388f8b78aSgm89044 dca_encrypt_atomic(crypto_provider_handle_t provider,
387488f8b78aSgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
387588f8b78aSgm89044 crypto_key_t *key, crypto_data_t *plaintext, crypto_data_t *ciphertext,
387688f8b78aSgm89044 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
387788f8b78aSgm89044 {
387888f8b78aSgm89044 int error = CRYPTO_FAILED;
387988f8b78aSgm89044 dca_t *softc = (dca_t *)provider;
388088f8b78aSgm89044
388188f8b78aSgm89044 DBG(softc, DENTRY, "dca_encrypt_atomic: started");
388288f8b78aSgm89044
388388f8b78aSgm89044 if (ctx_template != NULL)
388488f8b78aSgm89044 return (CRYPTO_ARGUMENTS_BAD);
388588f8b78aSgm89044
3886d8dd9913Sgm89044 /* handle inplace ops */
3887d8dd9913Sgm89044 if (!ciphertext) {
3888d8dd9913Sgm89044 ciphertext = plaintext;
3889d8dd9913Sgm89044 }
3890d8dd9913Sgm89044
389188f8b78aSgm89044 /* check mechanism */
389288f8b78aSgm89044 switch (mechanism->cm_type) {
389388f8b78aSgm89044 case DES_CBC_MECH_INFO_TYPE:
389488f8b78aSgm89044 error = dca_3desatomic(provider, session_id, mechanism, key,
389588f8b78aSgm89044 plaintext, ciphertext, KM_SLEEP, req,
389688f8b78aSgm89044 DR_ENCRYPT | DR_ATOMIC);
389788f8b78aSgm89044 break;
389888f8b78aSgm89044 case DES3_CBC_MECH_INFO_TYPE:
389988f8b78aSgm89044 error = dca_3desatomic(provider, session_id, mechanism, key,
390088f8b78aSgm89044 plaintext, ciphertext, KM_SLEEP, req,
390188f8b78aSgm89044 DR_ENCRYPT | DR_TRIPLE | DR_ATOMIC);
390288f8b78aSgm89044 break;
390388f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
390488f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
390588f8b78aSgm89044 error = dca_rsaatomic(provider, session_id, mechanism, key,
390688f8b78aSgm89044 plaintext, ciphertext, KM_SLEEP, req, DCA_RSA_ENC);
390788f8b78aSgm89044 break;
390888f8b78aSgm89044 default:
390988f8b78aSgm89044 cmn_err(CE_WARN, "dca_encrypt_atomic: unexpected mech type "
391088f8b78aSgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type);
391188f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
391288f8b78aSgm89044 }
391388f8b78aSgm89044
391488f8b78aSgm89044 if ((error != CRYPTO_QUEUED) && (error != CRYPTO_SUCCESS)) {
391588f8b78aSgm89044 ciphertext->cd_length = 0;
391688f8b78aSgm89044 }
391788f8b78aSgm89044
391888f8b78aSgm89044 DBG(softc, DENTRY, "dca_encrypt_atomic: done, err = 0x%x", error);
391988f8b78aSgm89044
392088f8b78aSgm89044 return (error);
392188f8b78aSgm89044 }
392288f8b78aSgm89044
392388f8b78aSgm89044 /* ARGSUSED */
392488f8b78aSgm89044 static int
dca_decrypt_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)392588f8b78aSgm89044 dca_decrypt_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
392688f8b78aSgm89044 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
392788f8b78aSgm89044 crypto_req_handle_t req)
392888f8b78aSgm89044 {
392988f8b78aSgm89044 int error = CRYPTO_FAILED;
393088f8b78aSgm89044 dca_t *softc;
393188f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
393288f8b78aSgm89044 int instance;
393388f8b78aSgm89044
393488f8b78aSgm89044 /* extract softc and instance number from context */
393588f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
393688f8b78aSgm89044 DBG(softc, DENTRY, "dca_decrypt_init: started");
393788f8b78aSgm89044
393888f8b78aSgm89044 /* check mechanism */
393988f8b78aSgm89044 switch (mechanism->cm_type) {
394088f8b78aSgm89044 case DES_CBC_MECH_INFO_TYPE:
394188f8b78aSgm89044 error = dca_3desctxinit(ctx, mechanism, key, KM_SLEEP,
394288f8b78aSgm89044 DR_DECRYPT);
394388f8b78aSgm89044 break;
394488f8b78aSgm89044 case DES3_CBC_MECH_INFO_TYPE:
394588f8b78aSgm89044 error = dca_3desctxinit(ctx, mechanism, key, KM_SLEEP,
394688f8b78aSgm89044 DR_DECRYPT | DR_TRIPLE);
394788f8b78aSgm89044 break;
394888f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
394988f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
395088f8b78aSgm89044 error = dca_rsainit(ctx, mechanism, key, KM_SLEEP);
395188f8b78aSgm89044 break;
395288f8b78aSgm89044 default:
395388f8b78aSgm89044 cmn_err(CE_WARN, "dca_decrypt_init: unexpected mech type "
395488f8b78aSgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type);
395588f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
395688f8b78aSgm89044 }
395788f8b78aSgm89044
395888f8b78aSgm89044 DBG(softc, DENTRY, "dca_decrypt_init: done, err = 0x%x", error);
395988f8b78aSgm89044
396088f8b78aSgm89044 if (error == CRYPTO_SUCCESS)
396188f8b78aSgm89044 dca_enlist2(&softc->dca_ctx_list, ctx->cc_provider_private,
396288f8b78aSgm89044 &softc->dca_ctx_list_lock);
396388f8b78aSgm89044
396488f8b78aSgm89044 return (error);
396588f8b78aSgm89044 }
396688f8b78aSgm89044
396788f8b78aSgm89044 /* ARGSUSED */
396888f8b78aSgm89044 static int
dca_decrypt(crypto_ctx_t * ctx,crypto_data_t * ciphertext,crypto_data_t * plaintext,crypto_req_handle_t req)396988f8b78aSgm89044 dca_decrypt(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
397088f8b78aSgm89044 crypto_data_t *plaintext, crypto_req_handle_t req)
397188f8b78aSgm89044 {
397288f8b78aSgm89044 int error = CRYPTO_FAILED;
397388f8b78aSgm89044 dca_t *softc;
397488f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
397588f8b78aSgm89044 int instance;
397688f8b78aSgm89044
397788f8b78aSgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private)
397888f8b78aSgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED);
397988f8b78aSgm89044
398088f8b78aSgm89044 /* extract softc and instance number from context */
398188f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
398288f8b78aSgm89044 DBG(softc, DENTRY, "dca_decrypt: started");
398388f8b78aSgm89044
3984d8dd9913Sgm89044 /* handle inplace ops */
3985d8dd9913Sgm89044 if (!plaintext) {
3986d8dd9913Sgm89044 dca_request_t *reqp = ctx->cc_provider_private;
3987d8dd9913Sgm89044 reqp->dr_flags |= DR_INPLACE;
3988d8dd9913Sgm89044 plaintext = ciphertext;
3989d8dd9913Sgm89044 }
3990d8dd9913Sgm89044
399188f8b78aSgm89044 /* check mechanism */
399288f8b78aSgm89044 switch (DCA_MECH_FROM_CTX(ctx)) {
399388f8b78aSgm89044 case DES_CBC_MECH_INFO_TYPE:
399488f8b78aSgm89044 error = dca_3des(ctx, ciphertext, plaintext, req, DR_DECRYPT);
399588f8b78aSgm89044 break;
399688f8b78aSgm89044 case DES3_CBC_MECH_INFO_TYPE:
399788f8b78aSgm89044 error = dca_3des(ctx, ciphertext, plaintext, req,
399888f8b78aSgm89044 DR_DECRYPT | DR_TRIPLE);
399988f8b78aSgm89044 break;
400088f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
400188f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
400288f8b78aSgm89044 error = dca_rsastart(ctx, ciphertext, plaintext, req,
400388f8b78aSgm89044 DCA_RSA_DEC);
400488f8b78aSgm89044 break;
400588f8b78aSgm89044 default:
400688f8b78aSgm89044 /* Should never reach here */
400788f8b78aSgm89044 cmn_err(CE_WARN, "dca_decrypt: unexpected mech type "
400888f8b78aSgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx));
400988f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
401088f8b78aSgm89044 }
401188f8b78aSgm89044
401288f8b78aSgm89044 if ((error != CRYPTO_QUEUED) && (error != CRYPTO_SUCCESS) &&
401388f8b78aSgm89044 (error != CRYPTO_BUFFER_TOO_SMALL)) {
401488f8b78aSgm89044 if (plaintext)
401588f8b78aSgm89044 plaintext->cd_length = 0;
401688f8b78aSgm89044 }
401788f8b78aSgm89044
401888f8b78aSgm89044 DBG(softc, DENTRY, "dca_decrypt: done, err = 0x%x", error);
401988f8b78aSgm89044
402088f8b78aSgm89044 return (error);
402188f8b78aSgm89044 }
402288f8b78aSgm89044
402388f8b78aSgm89044 /* ARGSUSED */
402488f8b78aSgm89044 static int
dca_decrypt_update(crypto_ctx_t * ctx,crypto_data_t * ciphertext,crypto_data_t * plaintext,crypto_req_handle_t req)402588f8b78aSgm89044 dca_decrypt_update(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
402688f8b78aSgm89044 crypto_data_t *plaintext, crypto_req_handle_t req)
402788f8b78aSgm89044 {
402888f8b78aSgm89044 int error = CRYPTO_FAILED;
402988f8b78aSgm89044 dca_t *softc;
403088f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
403188f8b78aSgm89044 int instance;
403288f8b78aSgm89044
403388f8b78aSgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private)
403488f8b78aSgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED);
403588f8b78aSgm89044
403688f8b78aSgm89044 /* extract softc and instance number from context */
403788f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
403888f8b78aSgm89044 DBG(softc, DENTRY, "dca_decrypt_update: started");
403988f8b78aSgm89044
4040d8dd9913Sgm89044 /* handle inplace ops */
4041d8dd9913Sgm89044 if (!plaintext) {
4042d8dd9913Sgm89044 dca_request_t *reqp = ctx->cc_provider_private;
4043d8dd9913Sgm89044 reqp->dr_flags |= DR_INPLACE;
4044d8dd9913Sgm89044 plaintext = ciphertext;
4045d8dd9913Sgm89044 }
4046d8dd9913Sgm89044
404788f8b78aSgm89044 /* check mechanism */
404888f8b78aSgm89044 switch (DCA_MECH_FROM_CTX(ctx)) {
404988f8b78aSgm89044 case DES_CBC_MECH_INFO_TYPE:
405088f8b78aSgm89044 error = dca_3desupdate(ctx, ciphertext, plaintext, req,
405188f8b78aSgm89044 DR_DECRYPT);
405288f8b78aSgm89044 break;
405388f8b78aSgm89044 case DES3_CBC_MECH_INFO_TYPE:
405488f8b78aSgm89044 error = dca_3desupdate(ctx, ciphertext, plaintext, req,
405588f8b78aSgm89044 DR_DECRYPT | DR_TRIPLE);
405688f8b78aSgm89044 break;
405788f8b78aSgm89044 default:
405888f8b78aSgm89044 /* Should never reach here */
405988f8b78aSgm89044 cmn_err(CE_WARN, "dca_decrypt_update: unexpected mech type "
406088f8b78aSgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx));
406188f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
406288f8b78aSgm89044 }
406388f8b78aSgm89044
406488f8b78aSgm89044 DBG(softc, DENTRY, "dca_decrypt_update: done, err = 0x%x", error);
406588f8b78aSgm89044
406688f8b78aSgm89044 return (error);
406788f8b78aSgm89044 }
406888f8b78aSgm89044
406988f8b78aSgm89044 /* ARGSUSED */
407088f8b78aSgm89044 static int
dca_decrypt_final(crypto_ctx_t * ctx,crypto_data_t * plaintext,crypto_req_handle_t req)407188f8b78aSgm89044 dca_decrypt_final(crypto_ctx_t *ctx, crypto_data_t *plaintext,
407288f8b78aSgm89044 crypto_req_handle_t req)
407388f8b78aSgm89044 {
407488f8b78aSgm89044 int error = CRYPTO_FAILED;
407588f8b78aSgm89044 dca_t *softc;
407688f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
407788f8b78aSgm89044 int instance;
407888f8b78aSgm89044
407988f8b78aSgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private)
408088f8b78aSgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED);
408188f8b78aSgm89044
408288f8b78aSgm89044 /* extract softc and instance number from context */
408388f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
408488f8b78aSgm89044 DBG(softc, DENTRY, "dca_decrypt_final: started");
408588f8b78aSgm89044
408688f8b78aSgm89044 /* check mechanism */
408788f8b78aSgm89044 switch (DCA_MECH_FROM_CTX(ctx)) {
408888f8b78aSgm89044 case DES_CBC_MECH_INFO_TYPE:
408988f8b78aSgm89044 error = dca_3desfinal(ctx, plaintext, DR_DECRYPT);
409088f8b78aSgm89044 break;
409188f8b78aSgm89044 case DES3_CBC_MECH_INFO_TYPE:
409288f8b78aSgm89044 error = dca_3desfinal(ctx, plaintext, DR_DECRYPT | DR_TRIPLE);
409388f8b78aSgm89044 break;
409488f8b78aSgm89044 default:
409588f8b78aSgm89044 /* Should never reach here */
409688f8b78aSgm89044 cmn_err(CE_WARN, "dca_decrypt_final: unexpected mech type "
409788f8b78aSgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx));
409888f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
409988f8b78aSgm89044 }
410088f8b78aSgm89044
410188f8b78aSgm89044 DBG(softc, DENTRY, "dca_decrypt_final: done, err = 0x%x", error);
410288f8b78aSgm89044
410388f8b78aSgm89044 return (error);
410488f8b78aSgm89044 }
410588f8b78aSgm89044
410688f8b78aSgm89044 /* ARGSUSED */
410788f8b78aSgm89044 static int
dca_decrypt_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * ciphertext,crypto_data_t * plaintext,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)410888f8b78aSgm89044 dca_decrypt_atomic(crypto_provider_handle_t provider,
410988f8b78aSgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
411088f8b78aSgm89044 crypto_key_t *key, crypto_data_t *ciphertext, crypto_data_t *plaintext,
411188f8b78aSgm89044 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
411288f8b78aSgm89044 {
411388f8b78aSgm89044 int error = CRYPTO_FAILED;
411488f8b78aSgm89044 dca_t *softc = (dca_t *)provider;
411588f8b78aSgm89044
411688f8b78aSgm89044 DBG(softc, DENTRY, "dca_decrypt_atomic: started");
411788f8b78aSgm89044
411888f8b78aSgm89044 if (ctx_template != NULL)
411988f8b78aSgm89044 return (CRYPTO_ARGUMENTS_BAD);
412088f8b78aSgm89044
4121d8dd9913Sgm89044 /* handle inplace ops */
4122d8dd9913Sgm89044 if (!plaintext) {
4123d8dd9913Sgm89044 plaintext = ciphertext;
4124d8dd9913Sgm89044 }
4125d8dd9913Sgm89044
412688f8b78aSgm89044 /* check mechanism */
412788f8b78aSgm89044 switch (mechanism->cm_type) {
412888f8b78aSgm89044 case DES_CBC_MECH_INFO_TYPE:
412988f8b78aSgm89044 error = dca_3desatomic(provider, session_id, mechanism, key,
413088f8b78aSgm89044 ciphertext, plaintext, KM_SLEEP, req,
413188f8b78aSgm89044 DR_DECRYPT | DR_ATOMIC);
413288f8b78aSgm89044 break;
413388f8b78aSgm89044 case DES3_CBC_MECH_INFO_TYPE:
413488f8b78aSgm89044 error = dca_3desatomic(provider, session_id, mechanism, key,
413588f8b78aSgm89044 ciphertext, plaintext, KM_SLEEP, req,
413688f8b78aSgm89044 DR_DECRYPT | DR_TRIPLE | DR_ATOMIC);
413788f8b78aSgm89044 break;
413888f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
413988f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
414088f8b78aSgm89044 error = dca_rsaatomic(provider, session_id, mechanism, key,
414188f8b78aSgm89044 ciphertext, plaintext, KM_SLEEP, req, DCA_RSA_DEC);
414288f8b78aSgm89044 break;
414388f8b78aSgm89044 default:
414488f8b78aSgm89044 cmn_err(CE_WARN, "dca_decrypt_atomic: unexpected mech type "
414588f8b78aSgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type);
414688f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
414788f8b78aSgm89044 }
414888f8b78aSgm89044
414988f8b78aSgm89044 if ((error != CRYPTO_QUEUED) && (error != CRYPTO_SUCCESS)) {
415088f8b78aSgm89044 plaintext->cd_length = 0;
415188f8b78aSgm89044 }
415288f8b78aSgm89044
415388f8b78aSgm89044 DBG(softc, DENTRY, "dca_decrypt_atomic: done, err = 0x%x", error);
415488f8b78aSgm89044
415588f8b78aSgm89044 return (error);
415688f8b78aSgm89044 }
415788f8b78aSgm89044
415888f8b78aSgm89044 /*
415988f8b78aSgm89044 * Sign entry points.
416088f8b78aSgm89044 */
416188f8b78aSgm89044
416288f8b78aSgm89044 /* ARGSUSED */
416388f8b78aSgm89044 static int
dca_sign_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)416488f8b78aSgm89044 dca_sign_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
416588f8b78aSgm89044 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
416688f8b78aSgm89044 crypto_req_handle_t req)
416788f8b78aSgm89044 {
416888f8b78aSgm89044 int error = CRYPTO_FAILED;
416988f8b78aSgm89044 dca_t *softc;
417088f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
417188f8b78aSgm89044 int instance;
417288f8b78aSgm89044
417388f8b78aSgm89044 /* extract softc and instance number from context */
417488f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
417588f8b78aSgm89044 DBG(softc, DENTRY, "dca_sign_init: started\n");
417688f8b78aSgm89044
417788f8b78aSgm89044 if (ctx_template != NULL)
417888f8b78aSgm89044 return (CRYPTO_ARGUMENTS_BAD);
417988f8b78aSgm89044
418088f8b78aSgm89044 /* check mechanism */
418188f8b78aSgm89044 switch (mechanism->cm_type) {
418288f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
418388f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
418488f8b78aSgm89044 error = dca_rsainit(ctx, mechanism, key, KM_SLEEP);
418588f8b78aSgm89044 break;
418688f8b78aSgm89044 case DSA_MECH_INFO_TYPE:
418788f8b78aSgm89044 error = dca_dsainit(ctx, mechanism, key, KM_SLEEP,
418888f8b78aSgm89044 DCA_DSA_SIGN);
418988f8b78aSgm89044 break;
419088f8b78aSgm89044 default:
419188f8b78aSgm89044 cmn_err(CE_WARN, "dca_sign_init: unexpected mech type "
419288f8b78aSgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type);
419388f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
419488f8b78aSgm89044 }
419588f8b78aSgm89044
419688f8b78aSgm89044 DBG(softc, DENTRY, "dca_sign_init: done, err = 0x%x", error);
419788f8b78aSgm89044
419888f8b78aSgm89044 if (error == CRYPTO_SUCCESS)
419988f8b78aSgm89044 dca_enlist2(&softc->dca_ctx_list, ctx->cc_provider_private,
420088f8b78aSgm89044 &softc->dca_ctx_list_lock);
420188f8b78aSgm89044
420288f8b78aSgm89044 return (error);
420388f8b78aSgm89044 }
420488f8b78aSgm89044
420588f8b78aSgm89044 static int
dca_sign(crypto_ctx_t * ctx,crypto_data_t * data,crypto_data_t * signature,crypto_req_handle_t req)420688f8b78aSgm89044 dca_sign(crypto_ctx_t *ctx, crypto_data_t *data,
420788f8b78aSgm89044 crypto_data_t *signature, crypto_req_handle_t req)
420888f8b78aSgm89044 {
420988f8b78aSgm89044 int error = CRYPTO_FAILED;
421088f8b78aSgm89044 dca_t *softc;
421188f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
421288f8b78aSgm89044 int instance;
421388f8b78aSgm89044
421488f8b78aSgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private)
421588f8b78aSgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED);
421688f8b78aSgm89044
421788f8b78aSgm89044 /* extract softc and instance number from context */
421888f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
421988f8b78aSgm89044 DBG(softc, DENTRY, "dca_sign: started\n");
422088f8b78aSgm89044
422188f8b78aSgm89044 /* check mechanism */
422288f8b78aSgm89044 switch (DCA_MECH_FROM_CTX(ctx)) {
422388f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
422488f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
422588f8b78aSgm89044 error = dca_rsastart(ctx, data, signature, req, DCA_RSA_SIGN);
422688f8b78aSgm89044 break;
422788f8b78aSgm89044 case DSA_MECH_INFO_TYPE:
422888f8b78aSgm89044 error = dca_dsa_sign(ctx, data, signature, req);
422988f8b78aSgm89044 break;
423088f8b78aSgm89044 default:
423188f8b78aSgm89044 cmn_err(CE_WARN, "dca_sign: unexpected mech type "
423288f8b78aSgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx));
423388f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
423488f8b78aSgm89044 }
423588f8b78aSgm89044
423688f8b78aSgm89044 DBG(softc, DENTRY, "dca_sign: done, err = 0x%x", error);
423788f8b78aSgm89044
423888f8b78aSgm89044 return (error);
423988f8b78aSgm89044 }
424088f8b78aSgm89044
424188f8b78aSgm89044 /* ARGSUSED */
424288f8b78aSgm89044 static int
dca_sign_update(crypto_ctx_t * ctx,crypto_data_t * data,crypto_req_handle_t req)424388f8b78aSgm89044 dca_sign_update(crypto_ctx_t *ctx, crypto_data_t *data,
424488f8b78aSgm89044 crypto_req_handle_t req)
424588f8b78aSgm89044 {
424688f8b78aSgm89044 int error = CRYPTO_MECHANISM_INVALID;
424788f8b78aSgm89044 dca_t *softc;
424888f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
424988f8b78aSgm89044 int instance;
425088f8b78aSgm89044
425188f8b78aSgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private)
425288f8b78aSgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED);
425388f8b78aSgm89044
425488f8b78aSgm89044 /* extract softc and instance number from context */
425588f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
425688f8b78aSgm89044 DBG(softc, DENTRY, "dca_sign_update: started\n");
425788f8b78aSgm89044
425888f8b78aSgm89044 cmn_err(CE_WARN, "dca_sign_update: unexpected mech type "
425988f8b78aSgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx));
426088f8b78aSgm89044
426188f8b78aSgm89044 DBG(softc, DENTRY, "dca_sign_update: done, err = 0x%x", error);
426288f8b78aSgm89044
426388f8b78aSgm89044 return (error);
426488f8b78aSgm89044 }
426588f8b78aSgm89044
426688f8b78aSgm89044 /* ARGSUSED */
426788f8b78aSgm89044 static int
dca_sign_final(crypto_ctx_t * ctx,crypto_data_t * signature,crypto_req_handle_t req)426888f8b78aSgm89044 dca_sign_final(crypto_ctx_t *ctx, crypto_data_t *signature,
426988f8b78aSgm89044 crypto_req_handle_t req)
427088f8b78aSgm89044 {
427188f8b78aSgm89044 int error = CRYPTO_MECHANISM_INVALID;
427288f8b78aSgm89044 dca_t *softc;
427388f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
427488f8b78aSgm89044 int instance;
427588f8b78aSgm89044
427688f8b78aSgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private)
427788f8b78aSgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED);
427888f8b78aSgm89044
427988f8b78aSgm89044 /* extract softc and instance number from context */
428088f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
428188f8b78aSgm89044 DBG(softc, DENTRY, "dca_sign_final: started\n");
428288f8b78aSgm89044
428388f8b78aSgm89044 cmn_err(CE_WARN, "dca_sign_final: unexpected mech type "
428488f8b78aSgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx));
428588f8b78aSgm89044
428688f8b78aSgm89044 DBG(softc, DENTRY, "dca_sign_final: done, err = 0x%x", error);
428788f8b78aSgm89044
428888f8b78aSgm89044 return (error);
428988f8b78aSgm89044 }
429088f8b78aSgm89044
429188f8b78aSgm89044 static int
dca_sign_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * data,crypto_data_t * signature,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)429288f8b78aSgm89044 dca_sign_atomic(crypto_provider_handle_t provider,
429388f8b78aSgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
429488f8b78aSgm89044 crypto_key_t *key, crypto_data_t *data, crypto_data_t *signature,
429588f8b78aSgm89044 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
429688f8b78aSgm89044 {
429788f8b78aSgm89044 int error = CRYPTO_FAILED;
429888f8b78aSgm89044 dca_t *softc = (dca_t *)provider;
429988f8b78aSgm89044
430088f8b78aSgm89044 DBG(softc, DENTRY, "dca_sign_atomic: started\n");
430188f8b78aSgm89044
430288f8b78aSgm89044 if (ctx_template != NULL)
430388f8b78aSgm89044 return (CRYPTO_ARGUMENTS_BAD);
430488f8b78aSgm89044
430588f8b78aSgm89044 /* check mechanism */
430688f8b78aSgm89044 switch (mechanism->cm_type) {
430788f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
430888f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
430988f8b78aSgm89044 error = dca_rsaatomic(provider, session_id, mechanism, key,
431088f8b78aSgm89044 data, signature, KM_SLEEP, req, DCA_RSA_SIGN);
431188f8b78aSgm89044 break;
431288f8b78aSgm89044 case DSA_MECH_INFO_TYPE:
431388f8b78aSgm89044 error = dca_dsaatomic(provider, session_id, mechanism, key,
431488f8b78aSgm89044 data, signature, KM_SLEEP, req, DCA_DSA_SIGN);
431588f8b78aSgm89044 break;
431688f8b78aSgm89044 default:
431788f8b78aSgm89044 cmn_err(CE_WARN, "dca_sign_atomic: unexpected mech type "
431888f8b78aSgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type);
431988f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
432088f8b78aSgm89044 }
432188f8b78aSgm89044
432288f8b78aSgm89044 DBG(softc, DENTRY, "dca_sign_atomic: done, err = 0x%x", error);
432388f8b78aSgm89044
432488f8b78aSgm89044 return (error);
432588f8b78aSgm89044 }
432688f8b78aSgm89044
432788f8b78aSgm89044 /* ARGSUSED */
432888f8b78aSgm89044 static int
dca_sign_recover_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)432988f8b78aSgm89044 dca_sign_recover_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
433088f8b78aSgm89044 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
433188f8b78aSgm89044 crypto_req_handle_t req)
433288f8b78aSgm89044 {
433388f8b78aSgm89044 int error = CRYPTO_FAILED;
433488f8b78aSgm89044 dca_t *softc;
433588f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
433688f8b78aSgm89044 int instance;
433788f8b78aSgm89044
433888f8b78aSgm89044 /* extract softc and instance number from context */
433988f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
434088f8b78aSgm89044 DBG(softc, DENTRY, "dca_sign_recover_init: started\n");
434188f8b78aSgm89044
434288f8b78aSgm89044 if (ctx_template != NULL)
434388f8b78aSgm89044 return (CRYPTO_ARGUMENTS_BAD);
434488f8b78aSgm89044
434588f8b78aSgm89044 /* check mechanism */
434688f8b78aSgm89044 switch (mechanism->cm_type) {
434788f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
434888f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
434988f8b78aSgm89044 error = dca_rsainit(ctx, mechanism, key, KM_SLEEP);
435088f8b78aSgm89044 break;
435188f8b78aSgm89044 default:
435288f8b78aSgm89044 cmn_err(CE_WARN, "dca_sign_recover_init: unexpected mech type "
435388f8b78aSgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type);
435488f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
435588f8b78aSgm89044 }
435688f8b78aSgm89044
435788f8b78aSgm89044 DBG(softc, DENTRY, "dca_sign_recover_init: done, err = 0x%x", error);
435888f8b78aSgm89044
435988f8b78aSgm89044 if (error == CRYPTO_SUCCESS)
436088f8b78aSgm89044 dca_enlist2(&softc->dca_ctx_list, ctx->cc_provider_private,
436188f8b78aSgm89044 &softc->dca_ctx_list_lock);
436288f8b78aSgm89044
436388f8b78aSgm89044 return (error);
436488f8b78aSgm89044 }
436588f8b78aSgm89044
436688f8b78aSgm89044 static int
dca_sign_recover(crypto_ctx_t * ctx,crypto_data_t * data,crypto_data_t * signature,crypto_req_handle_t req)436788f8b78aSgm89044 dca_sign_recover(crypto_ctx_t *ctx, crypto_data_t *data,
436888f8b78aSgm89044 crypto_data_t *signature, crypto_req_handle_t req)
436988f8b78aSgm89044 {
437088f8b78aSgm89044 int error = CRYPTO_FAILED;
437188f8b78aSgm89044 dca_t *softc;
437288f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
437388f8b78aSgm89044 int instance;
437488f8b78aSgm89044
437588f8b78aSgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private)
437688f8b78aSgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED);
437788f8b78aSgm89044
437888f8b78aSgm89044 /* extract softc and instance number from context */
437988f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
438088f8b78aSgm89044 DBG(softc, DENTRY, "dca_sign_recover: started\n");
438188f8b78aSgm89044
438288f8b78aSgm89044 /* check mechanism */
438388f8b78aSgm89044 switch (DCA_MECH_FROM_CTX(ctx)) {
438488f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
438588f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
438688f8b78aSgm89044 error = dca_rsastart(ctx, data, signature, req, DCA_RSA_SIGNR);
438788f8b78aSgm89044 break;
438888f8b78aSgm89044 default:
438988f8b78aSgm89044 cmn_err(CE_WARN, "dca_sign_recover: unexpected mech type "
439088f8b78aSgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx));
439188f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
439288f8b78aSgm89044 }
439388f8b78aSgm89044
439488f8b78aSgm89044 DBG(softc, DENTRY, "dca_sign_recover: done, err = 0x%x", error);
439588f8b78aSgm89044
439688f8b78aSgm89044 return (error);
439788f8b78aSgm89044 }
439888f8b78aSgm89044
439988f8b78aSgm89044 static int
dca_sign_recover_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * data,crypto_data_t * signature,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)440088f8b78aSgm89044 dca_sign_recover_atomic(crypto_provider_handle_t provider,
440188f8b78aSgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
440288f8b78aSgm89044 crypto_key_t *key, crypto_data_t *data, crypto_data_t *signature,
440388f8b78aSgm89044 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
440488f8b78aSgm89044 {
440588f8b78aSgm89044 int error = CRYPTO_FAILED;
440688f8b78aSgm89044 dca_t *softc = (dca_t *)provider;
440788f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
440888f8b78aSgm89044 int instance;
440988f8b78aSgm89044
441088f8b78aSgm89044 instance = ddi_get_instance(softc->dca_dip);
441188f8b78aSgm89044 DBG(softc, DENTRY, "dca_sign_recover_atomic: started\n");
441288f8b78aSgm89044
441388f8b78aSgm89044 if (ctx_template != NULL)
441488f8b78aSgm89044 return (CRYPTO_ARGUMENTS_BAD);
441588f8b78aSgm89044
441688f8b78aSgm89044 /* check mechanism */
441788f8b78aSgm89044 switch (mechanism->cm_type) {
441888f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
441988f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
442088f8b78aSgm89044 error = dca_rsaatomic(provider, session_id, mechanism, key,
442188f8b78aSgm89044 data, signature, KM_SLEEP, req, DCA_RSA_SIGNR);
442288f8b78aSgm89044 break;
442388f8b78aSgm89044 default:
442488f8b78aSgm89044 cmn_err(CE_WARN, "dca_sign_recover_atomic: unexpected mech type"
442588f8b78aSgm89044 " 0x%llx\n", (unsigned long long)mechanism->cm_type);
442688f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
442788f8b78aSgm89044 }
442888f8b78aSgm89044
442988f8b78aSgm89044 DBG(softc, DENTRY, "dca_sign_recover_atomic: done, err = 0x%x", error);
443088f8b78aSgm89044
443188f8b78aSgm89044 return (error);
443288f8b78aSgm89044 }
443388f8b78aSgm89044
443488f8b78aSgm89044 /*
443588f8b78aSgm89044 * Verify entry points.
443688f8b78aSgm89044 */
443788f8b78aSgm89044
443888f8b78aSgm89044 /* ARGSUSED */
443988f8b78aSgm89044 static int
dca_verify_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)444088f8b78aSgm89044 dca_verify_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
444188f8b78aSgm89044 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
444288f8b78aSgm89044 crypto_req_handle_t req)
444388f8b78aSgm89044 {
444488f8b78aSgm89044 int error = CRYPTO_FAILED;
444588f8b78aSgm89044 dca_t *softc;
444688f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
444788f8b78aSgm89044 int instance;
444888f8b78aSgm89044
444988f8b78aSgm89044 /* extract softc and instance number from context */
445088f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
445188f8b78aSgm89044 DBG(softc, DENTRY, "dca_verify_init: started\n");
445288f8b78aSgm89044
445388f8b78aSgm89044 if (ctx_template != NULL)
445488f8b78aSgm89044 return (CRYPTO_ARGUMENTS_BAD);
445588f8b78aSgm89044
445688f8b78aSgm89044 /* check mechanism */
445788f8b78aSgm89044 switch (mechanism->cm_type) {
445888f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
445988f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
446088f8b78aSgm89044 error = dca_rsainit(ctx, mechanism, key, KM_SLEEP);
446188f8b78aSgm89044 break;
446288f8b78aSgm89044 case DSA_MECH_INFO_TYPE:
446388f8b78aSgm89044 error = dca_dsainit(ctx, mechanism, key, KM_SLEEP,
446488f8b78aSgm89044 DCA_DSA_VRFY);
446588f8b78aSgm89044 break;
446688f8b78aSgm89044 default:
446788f8b78aSgm89044 cmn_err(CE_WARN, "dca_verify_init: unexpected mech type "
446888f8b78aSgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type);
446988f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
447088f8b78aSgm89044 }
447188f8b78aSgm89044
447288f8b78aSgm89044 DBG(softc, DENTRY, "dca_verify_init: done, err = 0x%x", error);
447388f8b78aSgm89044
447488f8b78aSgm89044 if (error == CRYPTO_SUCCESS)
447588f8b78aSgm89044 dca_enlist2(&softc->dca_ctx_list, ctx->cc_provider_private,
447688f8b78aSgm89044 &softc->dca_ctx_list_lock);
447788f8b78aSgm89044
447888f8b78aSgm89044 return (error);
447988f8b78aSgm89044 }
448088f8b78aSgm89044
448188f8b78aSgm89044 static int
dca_verify(crypto_ctx_t * ctx,crypto_data_t * data,crypto_data_t * signature,crypto_req_handle_t req)448288f8b78aSgm89044 dca_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *signature,
448388f8b78aSgm89044 crypto_req_handle_t req)
448488f8b78aSgm89044 {
448588f8b78aSgm89044 int error = CRYPTO_FAILED;
448688f8b78aSgm89044 dca_t *softc;
448788f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
448888f8b78aSgm89044 int instance;
448988f8b78aSgm89044
449088f8b78aSgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private)
449188f8b78aSgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED);
449288f8b78aSgm89044
449388f8b78aSgm89044 /* extract softc and instance number from context */
449488f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
449588f8b78aSgm89044 DBG(softc, DENTRY, "dca_verify: started\n");
449688f8b78aSgm89044
449788f8b78aSgm89044 /* check mechanism */
449888f8b78aSgm89044 switch (DCA_MECH_FROM_CTX(ctx)) {
449988f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
450088f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
450188f8b78aSgm89044 error = dca_rsastart(ctx, signature, data, req, DCA_RSA_VRFY);
450288f8b78aSgm89044 break;
450388f8b78aSgm89044 case DSA_MECH_INFO_TYPE:
450488f8b78aSgm89044 error = dca_dsa_verify(ctx, data, signature, req);
450588f8b78aSgm89044 break;
450688f8b78aSgm89044 default:
450788f8b78aSgm89044 cmn_err(CE_WARN, "dca_verify: unexpected mech type "
450888f8b78aSgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx));
450988f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
451088f8b78aSgm89044 }
451188f8b78aSgm89044
451288f8b78aSgm89044 DBG(softc, DENTRY, "dca_verify: done, err = 0x%x", error);
451388f8b78aSgm89044
451488f8b78aSgm89044 return (error);
451588f8b78aSgm89044 }
451688f8b78aSgm89044
451788f8b78aSgm89044 /* ARGSUSED */
451888f8b78aSgm89044 static int
dca_verify_update(crypto_ctx_t * ctx,crypto_data_t * data,crypto_req_handle_t req)451988f8b78aSgm89044 dca_verify_update(crypto_ctx_t *ctx, crypto_data_t *data,
452088f8b78aSgm89044 crypto_req_handle_t req)
452188f8b78aSgm89044 {
452288f8b78aSgm89044 int error = CRYPTO_MECHANISM_INVALID;
452388f8b78aSgm89044 dca_t *softc;
452488f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
452588f8b78aSgm89044 int instance;
452688f8b78aSgm89044
452788f8b78aSgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private)
452888f8b78aSgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED);
452988f8b78aSgm89044
453088f8b78aSgm89044 /* extract softc and instance number from context */
453188f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
453288f8b78aSgm89044 DBG(softc, DENTRY, "dca_verify_update: started\n");
453388f8b78aSgm89044
453488f8b78aSgm89044 cmn_err(CE_WARN, "dca_verify_update: unexpected mech type "
453588f8b78aSgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx));
453688f8b78aSgm89044
453788f8b78aSgm89044 DBG(softc, DENTRY, "dca_verify_update: done, err = 0x%x", error);
453888f8b78aSgm89044
453988f8b78aSgm89044 return (error);
454088f8b78aSgm89044 }
454188f8b78aSgm89044
454288f8b78aSgm89044 /* ARGSUSED */
454388f8b78aSgm89044 static int
dca_verify_final(crypto_ctx_t * ctx,crypto_data_t * signature,crypto_req_handle_t req)454488f8b78aSgm89044 dca_verify_final(crypto_ctx_t *ctx, crypto_data_t *signature,
454588f8b78aSgm89044 crypto_req_handle_t req)
454688f8b78aSgm89044 {
454788f8b78aSgm89044 int error = CRYPTO_MECHANISM_INVALID;
454888f8b78aSgm89044 dca_t *softc;
454988f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
455088f8b78aSgm89044 int instance;
455188f8b78aSgm89044
455288f8b78aSgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private)
455388f8b78aSgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED);
455488f8b78aSgm89044
455588f8b78aSgm89044 /* extract softc and instance number from context */
455688f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
455788f8b78aSgm89044 DBG(softc, DENTRY, "dca_verify_final: started\n");
455888f8b78aSgm89044
455988f8b78aSgm89044 cmn_err(CE_WARN, "dca_verify_final: unexpected mech type "
456088f8b78aSgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx));
456188f8b78aSgm89044
456288f8b78aSgm89044 DBG(softc, DENTRY, "dca_verify_final: done, err = 0x%x", error);
456388f8b78aSgm89044
456488f8b78aSgm89044 return (error);
456588f8b78aSgm89044 }
456688f8b78aSgm89044
456788f8b78aSgm89044 static int
dca_verify_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * data,crypto_data_t * signature,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)456888f8b78aSgm89044 dca_verify_atomic(crypto_provider_handle_t provider,
456988f8b78aSgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
457088f8b78aSgm89044 crypto_key_t *key, crypto_data_t *data, crypto_data_t *signature,
457188f8b78aSgm89044 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
457288f8b78aSgm89044 {
457388f8b78aSgm89044 int error = CRYPTO_FAILED;
457488f8b78aSgm89044 dca_t *softc = (dca_t *)provider;
457588f8b78aSgm89044
457688f8b78aSgm89044 DBG(softc, DENTRY, "dca_verify_atomic: started\n");
457788f8b78aSgm89044
457888f8b78aSgm89044 if (ctx_template != NULL)
457988f8b78aSgm89044 return (CRYPTO_ARGUMENTS_BAD);
458088f8b78aSgm89044
458188f8b78aSgm89044 /* check mechanism */
458288f8b78aSgm89044 switch (mechanism->cm_type) {
458388f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
458488f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
458588f8b78aSgm89044 error = dca_rsaatomic(provider, session_id, mechanism, key,
458688f8b78aSgm89044 signature, data, KM_SLEEP, req, DCA_RSA_VRFY);
458788f8b78aSgm89044 break;
458888f8b78aSgm89044 case DSA_MECH_INFO_TYPE:
458988f8b78aSgm89044 error = dca_dsaatomic(provider, session_id, mechanism, key,
459088f8b78aSgm89044 data, signature, KM_SLEEP, req, DCA_DSA_VRFY);
459188f8b78aSgm89044 break;
459288f8b78aSgm89044 default:
459388f8b78aSgm89044 cmn_err(CE_WARN, "dca_verify_atomic: unexpected mech type "
459488f8b78aSgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type);
459588f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
459688f8b78aSgm89044 }
459788f8b78aSgm89044
459888f8b78aSgm89044 DBG(softc, DENTRY, "dca_verify_atomic: done, err = 0x%x", error);
459988f8b78aSgm89044
460088f8b78aSgm89044 return (error);
460188f8b78aSgm89044 }
460288f8b78aSgm89044
460388f8b78aSgm89044 /* ARGSUSED */
460488f8b78aSgm89044 static int
dca_verify_recover_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)460588f8b78aSgm89044 dca_verify_recover_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
460688f8b78aSgm89044 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
460788f8b78aSgm89044 crypto_req_handle_t req)
460888f8b78aSgm89044 {
460988f8b78aSgm89044 int error = CRYPTO_MECHANISM_INVALID;
461088f8b78aSgm89044 dca_t *softc;
461188f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
461288f8b78aSgm89044 int instance;
461388f8b78aSgm89044
461488f8b78aSgm89044 /* extract softc and instance number from context */
461588f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
461688f8b78aSgm89044 DBG(softc, DENTRY, "dca_verify_recover_init: started\n");
461788f8b78aSgm89044
461888f8b78aSgm89044 if (ctx_template != NULL)
461988f8b78aSgm89044 return (CRYPTO_ARGUMENTS_BAD);
462088f8b78aSgm89044
462188f8b78aSgm89044 /* check mechanism */
462288f8b78aSgm89044 switch (mechanism->cm_type) {
462388f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
462488f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
462588f8b78aSgm89044 error = dca_rsainit(ctx, mechanism, key, KM_SLEEP);
462688f8b78aSgm89044 break;
462788f8b78aSgm89044 default:
462888f8b78aSgm89044 cmn_err(CE_WARN, "dca_verify_recover_init: unexpected mech type"
462988f8b78aSgm89044 " 0x%llx\n", (unsigned long long)mechanism->cm_type);
463088f8b78aSgm89044 }
463188f8b78aSgm89044
463288f8b78aSgm89044 DBG(softc, DENTRY, "dca_verify_recover_init: done, err = 0x%x", error);
463388f8b78aSgm89044
463488f8b78aSgm89044 if (error == CRYPTO_SUCCESS)
463588f8b78aSgm89044 dca_enlist2(&softc->dca_ctx_list, ctx->cc_provider_private,
463688f8b78aSgm89044 &softc->dca_ctx_list_lock);
463788f8b78aSgm89044
463888f8b78aSgm89044 return (error);
463988f8b78aSgm89044 }
464088f8b78aSgm89044
464188f8b78aSgm89044 static int
dca_verify_recover(crypto_ctx_t * ctx,crypto_data_t * signature,crypto_data_t * data,crypto_req_handle_t req)464288f8b78aSgm89044 dca_verify_recover(crypto_ctx_t *ctx, crypto_data_t *signature,
464388f8b78aSgm89044 crypto_data_t *data, crypto_req_handle_t req)
464488f8b78aSgm89044 {
464588f8b78aSgm89044 int error = CRYPTO_MECHANISM_INVALID;
464688f8b78aSgm89044 dca_t *softc;
464788f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
464888f8b78aSgm89044 int instance;
464988f8b78aSgm89044
465088f8b78aSgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private)
465188f8b78aSgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED);
465288f8b78aSgm89044
465388f8b78aSgm89044 /* extract softc and instance number from context */
465488f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
465588f8b78aSgm89044 DBG(softc, DENTRY, "dca_verify_recover: started\n");
465688f8b78aSgm89044
465788f8b78aSgm89044 /* check mechanism */
465888f8b78aSgm89044 switch (DCA_MECH_FROM_CTX(ctx)) {
465988f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
466088f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
466188f8b78aSgm89044 error = dca_rsastart(ctx, signature, data, req, DCA_RSA_VRFYR);
466288f8b78aSgm89044 break;
466388f8b78aSgm89044 default:
466488f8b78aSgm89044 cmn_err(CE_WARN, "dca_verify_recover: unexpected mech type "
466588f8b78aSgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx));
466688f8b78aSgm89044 }
466788f8b78aSgm89044
466888f8b78aSgm89044 DBG(softc, DENTRY, "dca_verify_recover: done, err = 0x%x", error);
466988f8b78aSgm89044
467088f8b78aSgm89044 return (error);
467188f8b78aSgm89044 }
467288f8b78aSgm89044
467388f8b78aSgm89044 static int
dca_verify_recover_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * data,crypto_data_t * signature,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)467488f8b78aSgm89044 dca_verify_recover_atomic(crypto_provider_handle_t provider,
467588f8b78aSgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
467688f8b78aSgm89044 crypto_key_t *key, crypto_data_t *data, crypto_data_t *signature,
467788f8b78aSgm89044 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
467888f8b78aSgm89044 {
467988f8b78aSgm89044 int error = CRYPTO_MECHANISM_INVALID;
468088f8b78aSgm89044 dca_t *softc = (dca_t *)provider;
468188f8b78aSgm89044
468288f8b78aSgm89044 DBG(softc, DENTRY, "dca_verify_recover_atomic: started\n");
468388f8b78aSgm89044
468488f8b78aSgm89044 if (ctx_template != NULL)
468588f8b78aSgm89044 return (CRYPTO_ARGUMENTS_BAD);
468688f8b78aSgm89044
468788f8b78aSgm89044 /* check mechanism */
468888f8b78aSgm89044 switch (mechanism->cm_type) {
468988f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
469088f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
469188f8b78aSgm89044 error = dca_rsaatomic(provider, session_id, mechanism, key,
469288f8b78aSgm89044 signature, data, KM_SLEEP, req, DCA_RSA_VRFYR);
469388f8b78aSgm89044 break;
469488f8b78aSgm89044 default:
469588f8b78aSgm89044 cmn_err(CE_WARN, "dca_verify_recover_atomic: unexpected mech "
469688f8b78aSgm89044 "type 0x%llx\n", (unsigned long long)mechanism->cm_type);
469788f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
469888f8b78aSgm89044 }
469988f8b78aSgm89044
470088f8b78aSgm89044 DBG(softc, DENTRY,
470188f8b78aSgm89044 "dca_verify_recover_atomic: done, err = 0x%x", error);
470288f8b78aSgm89044
470388f8b78aSgm89044 return (error);
470488f8b78aSgm89044 }
470588f8b78aSgm89044
470688f8b78aSgm89044 /*
470788f8b78aSgm89044 * Random number entry points.
470888f8b78aSgm89044 */
470988f8b78aSgm89044
471088f8b78aSgm89044 /* ARGSUSED */
471188f8b78aSgm89044 static int
dca_generate_random(crypto_provider_handle_t provider,crypto_session_id_t session_id,uchar_t * buf,size_t len,crypto_req_handle_t req)471288f8b78aSgm89044 dca_generate_random(crypto_provider_handle_t provider,
471388f8b78aSgm89044 crypto_session_id_t session_id,
471488f8b78aSgm89044 uchar_t *buf, size_t len, crypto_req_handle_t req)
471588f8b78aSgm89044 {
471688f8b78aSgm89044 int error = CRYPTO_FAILED;
471788f8b78aSgm89044 dca_t *softc = (dca_t *)provider;
471888f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
471988f8b78aSgm89044 int instance;
472088f8b78aSgm89044
472188f8b78aSgm89044 instance = ddi_get_instance(softc->dca_dip);
472288f8b78aSgm89044 DBG(softc, DENTRY, "dca_generate_random: started");
472388f8b78aSgm89044
472488f8b78aSgm89044 error = dca_rng(softc, buf, len, req);
472588f8b78aSgm89044
472688f8b78aSgm89044 DBG(softc, DENTRY, "dca_generate_random: done, err = 0x%x", error);
472788f8b78aSgm89044
472888f8b78aSgm89044 return (error);
472988f8b78aSgm89044 }
473088f8b78aSgm89044
473188f8b78aSgm89044 /*
473288f8b78aSgm89044 * Context management entry points.
473388f8b78aSgm89044 */
473488f8b78aSgm89044
473588f8b78aSgm89044 int
dca_free_context(crypto_ctx_t * ctx)473688f8b78aSgm89044 dca_free_context(crypto_ctx_t *ctx)
473788f8b78aSgm89044 {
473888f8b78aSgm89044 int error = CRYPTO_SUCCESS;
473988f8b78aSgm89044 dca_t *softc;
474088f8b78aSgm89044 /* LINTED E_FUNC_SET_NOT_USED */
474188f8b78aSgm89044 int instance;
474288f8b78aSgm89044
474388f8b78aSgm89044 /* extract softc and instance number from context */
474488f8b78aSgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance);
474588f8b78aSgm89044 DBG(softc, DENTRY, "dca_free_context: entered");
474688f8b78aSgm89044
474788f8b78aSgm89044 if (ctx->cc_provider_private == NULL)
474888f8b78aSgm89044 return (error);
474988f8b78aSgm89044
475088f8b78aSgm89044 dca_rmlist2(ctx->cc_provider_private, &softc->dca_ctx_list_lock);
475188f8b78aSgm89044
475288f8b78aSgm89044 error = dca_free_context_low(ctx);
475388f8b78aSgm89044
475488f8b78aSgm89044 DBG(softc, DENTRY, "dca_free_context: done, err = 0x%x", error);
475588f8b78aSgm89044
475688f8b78aSgm89044 return (error);
475788f8b78aSgm89044 }
475888f8b78aSgm89044
475988f8b78aSgm89044 static int
dca_free_context_low(crypto_ctx_t * ctx)476088f8b78aSgm89044 dca_free_context_low(crypto_ctx_t *ctx)
476188f8b78aSgm89044 {
476288f8b78aSgm89044 int error = CRYPTO_SUCCESS;
476388f8b78aSgm89044
476488f8b78aSgm89044 /* check mechanism */
476588f8b78aSgm89044 switch (DCA_MECH_FROM_CTX(ctx)) {
476688f8b78aSgm89044 case DES_CBC_MECH_INFO_TYPE:
476788f8b78aSgm89044 case DES3_CBC_MECH_INFO_TYPE:
476888f8b78aSgm89044 dca_3desctxfree(ctx);
476988f8b78aSgm89044 break;
477088f8b78aSgm89044 case RSA_PKCS_MECH_INFO_TYPE:
477188f8b78aSgm89044 case RSA_X_509_MECH_INFO_TYPE:
477288f8b78aSgm89044 dca_rsactxfree(ctx);
477388f8b78aSgm89044 break;
477488f8b78aSgm89044 case DSA_MECH_INFO_TYPE:
477588f8b78aSgm89044 dca_dsactxfree(ctx);
477688f8b78aSgm89044 break;
477788f8b78aSgm89044 default:
477888f8b78aSgm89044 /* Should never reach here */
477988f8b78aSgm89044 cmn_err(CE_WARN, "dca_free_context_low: unexpected mech type "
478088f8b78aSgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx));
478188f8b78aSgm89044 error = CRYPTO_MECHANISM_INVALID;
478288f8b78aSgm89044 }
478388f8b78aSgm89044
478488f8b78aSgm89044 return (error);
478588f8b78aSgm89044 }
478688f8b78aSgm89044
478788f8b78aSgm89044
478888f8b78aSgm89044 /* Free any unfreed private context. It is called in detach. */
478988f8b78aSgm89044 static void
dca_free_context_list(dca_t * dca)479088f8b78aSgm89044 dca_free_context_list(dca_t *dca)
479188f8b78aSgm89044 {
479288f8b78aSgm89044 dca_listnode_t *node;
479388f8b78aSgm89044 crypto_ctx_t ctx;
479488f8b78aSgm89044
479588f8b78aSgm89044 (void) memset(&ctx, 0, sizeof (ctx));
479688f8b78aSgm89044 ctx.cc_provider = dca;
479788f8b78aSgm89044
479888f8b78aSgm89044 while ((node = dca_delist2(&dca->dca_ctx_list,
479988f8b78aSgm89044 &dca->dca_ctx_list_lock)) != NULL) {
480088f8b78aSgm89044 ctx.cc_provider_private = node;
480188f8b78aSgm89044 (void) dca_free_context_low(&ctx);
480288f8b78aSgm89044 }
480388f8b78aSgm89044 }
480488f8b78aSgm89044
480588f8b78aSgm89044 static int
ext_info_sym(crypto_provider_handle_t prov,crypto_provider_ext_info_t * ext_info,crypto_req_handle_t cfreq)480688f8b78aSgm89044 ext_info_sym(crypto_provider_handle_t prov,
480788f8b78aSgm89044 crypto_provider_ext_info_t *ext_info, crypto_req_handle_t cfreq)
480888f8b78aSgm89044 {
480988f8b78aSgm89044 return (ext_info_base(prov, ext_info, cfreq, IDENT_SYM));
481088f8b78aSgm89044 }
481188f8b78aSgm89044
481288f8b78aSgm89044 static int
ext_info_asym(crypto_provider_handle_t prov,crypto_provider_ext_info_t * ext_info,crypto_req_handle_t cfreq)481388f8b78aSgm89044 ext_info_asym(crypto_provider_handle_t prov,
481488f8b78aSgm89044 crypto_provider_ext_info_t *ext_info, crypto_req_handle_t cfreq)
481588f8b78aSgm89044 {
481688f8b78aSgm89044 int rv;
481788f8b78aSgm89044
481888f8b78aSgm89044 rv = ext_info_base(prov, ext_info, cfreq, IDENT_ASYM);
481988f8b78aSgm89044 /* The asymmetric cipher slot supports random */
482088f8b78aSgm89044 ext_info->ei_flags |= CRYPTO_EXTF_RNG;
482188f8b78aSgm89044
482288f8b78aSgm89044 return (rv);
482388f8b78aSgm89044 }
482488f8b78aSgm89044
482588f8b78aSgm89044 /* ARGSUSED */
482688f8b78aSgm89044 static int
ext_info_base(crypto_provider_handle_t prov,crypto_provider_ext_info_t * ext_info,crypto_req_handle_t cfreq,char * id)482788f8b78aSgm89044 ext_info_base(crypto_provider_handle_t prov,
482888f8b78aSgm89044 crypto_provider_ext_info_t *ext_info, crypto_req_handle_t cfreq, char *id)
482988f8b78aSgm89044 {
483088f8b78aSgm89044 dca_t *dca = (dca_t *)prov;
483188f8b78aSgm89044 int len;
483288f8b78aSgm89044
483388f8b78aSgm89044 /* Label */
483488f8b78aSgm89044 (void) sprintf((char *)ext_info->ei_label, "%s/%d %s",
483588f8b78aSgm89044 ddi_driver_name(dca->dca_dip), ddi_get_instance(dca->dca_dip), id);
483688f8b78aSgm89044 len = strlen((char *)ext_info->ei_label);
483788f8b78aSgm89044 (void) memset(ext_info->ei_label + len, ' ',
483888f8b78aSgm89044 CRYPTO_EXT_SIZE_LABEL - len);
483988f8b78aSgm89044
484088f8b78aSgm89044 /* Manufacturer ID */
484188f8b78aSgm89044 (void) sprintf((char *)ext_info->ei_manufacturerID, "%s",
484288f8b78aSgm89044 DCA_MANUFACTURER_ID);
484388f8b78aSgm89044 len = strlen((char *)ext_info->ei_manufacturerID);
484488f8b78aSgm89044 (void) memset(ext_info->ei_manufacturerID + len, ' ',
484588f8b78aSgm89044 CRYPTO_EXT_SIZE_MANUF - len);
484688f8b78aSgm89044
484788f8b78aSgm89044 /* Model */
484888f8b78aSgm89044 (void) sprintf((char *)ext_info->ei_model, dca->dca_model);
484988f8b78aSgm89044
485088f8b78aSgm89044 DBG(dca, DWARN, "kCF MODEL: %s", (char *)ext_info->ei_model);
485188f8b78aSgm89044
485288f8b78aSgm89044 len = strlen((char *)ext_info->ei_model);
485388f8b78aSgm89044 (void) memset(ext_info->ei_model + len, ' ',
485488f8b78aSgm89044 CRYPTO_EXT_SIZE_MODEL - len);
485588f8b78aSgm89044
485688f8b78aSgm89044 /* Serial Number. Blank for Deimos */
485788f8b78aSgm89044 (void) memset(ext_info->ei_serial_number, ' ', CRYPTO_EXT_SIZE_SERIAL);
485888f8b78aSgm89044
485988f8b78aSgm89044 ext_info->ei_flags = CRYPTO_EXTF_WRITE_PROTECTED;
486088f8b78aSgm89044
486188f8b78aSgm89044 ext_info->ei_max_session_count = CRYPTO_UNAVAILABLE_INFO;
486288f8b78aSgm89044 ext_info->ei_max_pin_len = CRYPTO_UNAVAILABLE_INFO;
486388f8b78aSgm89044 ext_info->ei_min_pin_len = CRYPTO_UNAVAILABLE_INFO;
486488f8b78aSgm89044 ext_info->ei_total_public_memory = CRYPTO_UNAVAILABLE_INFO;
486588f8b78aSgm89044 ext_info->ei_free_public_memory = CRYPTO_UNAVAILABLE_INFO;
486688f8b78aSgm89044 ext_info->ei_total_private_memory = CRYPTO_UNAVAILABLE_INFO;
486788f8b78aSgm89044 ext_info->ei_free_private_memory = CRYPTO_UNAVAILABLE_INFO;
486888f8b78aSgm89044 ext_info->ei_hardware_version.cv_major = 0;
486988f8b78aSgm89044 ext_info->ei_hardware_version.cv_minor = 0;
487088f8b78aSgm89044 ext_info->ei_firmware_version.cv_major = 0;
487188f8b78aSgm89044 ext_info->ei_firmware_version.cv_minor = 0;
487288f8b78aSgm89044
487388f8b78aSgm89044 /* Time. No need to be supplied for token without a clock */
487488f8b78aSgm89044 ext_info->ei_time[0] = '\000';
487588f8b78aSgm89044
487688f8b78aSgm89044 return (CRYPTO_SUCCESS);
487788f8b78aSgm89044 }
487888f8b78aSgm89044
487988f8b78aSgm89044 static void
dca_fma_init(dca_t * dca)488088f8b78aSgm89044 dca_fma_init(dca_t *dca)
488188f8b78aSgm89044 {
488288f8b78aSgm89044 ddi_iblock_cookie_t fm_ibc;
488388f8b78aSgm89044 int fm_capabilities = DDI_FM_EREPORT_CAPABLE |
488488f8b78aSgm89044 DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE |
488588f8b78aSgm89044 DDI_FM_ERRCB_CAPABLE;
488688f8b78aSgm89044
488788f8b78aSgm89044 /* Read FMA capabilities from dca.conf file (if present) */
488888f8b78aSgm89044 dca->fm_capabilities = ddi_getprop(DDI_DEV_T_ANY, dca->dca_dip,
488988f8b78aSgm89044 DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "fm-capable",
489088f8b78aSgm89044 fm_capabilities);
489188f8b78aSgm89044
489288f8b78aSgm89044 DBG(dca, DWARN, "dca->fm_capabilities = 0x%x", dca->fm_capabilities);
489388f8b78aSgm89044
489488f8b78aSgm89044 /* Only register with IO Fault Services if we have some capability */
489588f8b78aSgm89044 if (dca->fm_capabilities) {
489688f8b78aSgm89044 dca_regsattr.devacc_attr_access = DDI_FLAGERR_ACC;
489788f8b78aSgm89044 dca_dmaattr.dma_attr_flags = DDI_DMA_FLAGERR;
489888f8b78aSgm89044
489988f8b78aSgm89044 /* Register capabilities with IO Fault Services */
490088f8b78aSgm89044 ddi_fm_init(dca->dca_dip, &dca->fm_capabilities, &fm_ibc);
490188f8b78aSgm89044 DBG(dca, DWARN, "fm_capable() = 0x%x",
490288f8b78aSgm89044 ddi_fm_capable(dca->dca_dip));
490388f8b78aSgm89044
490488f8b78aSgm89044 /*
490588f8b78aSgm89044 * Initialize pci ereport capabilities if ereport capable
490688f8b78aSgm89044 */
490700d0963fSdilpreet if (DDI_FM_EREPORT_CAP(dca->fm_capabilities) ||
490800d0963fSdilpreet DDI_FM_ERRCB_CAP(dca->fm_capabilities))
490988f8b78aSgm89044 pci_ereport_setup(dca->dca_dip);
491088f8b78aSgm89044
491188f8b78aSgm89044 /*
491288f8b78aSgm89044 * Initialize callback mutex and register error callback if
491388f8b78aSgm89044 * error callback capable.
491488f8b78aSgm89044 */
491588f8b78aSgm89044 if (DDI_FM_ERRCB_CAP(dca->fm_capabilities)) {
491688f8b78aSgm89044 ddi_fm_handler_register(dca->dca_dip, dca_fm_error_cb,
491788f8b78aSgm89044 (void *)dca);
491888f8b78aSgm89044 }
491988f8b78aSgm89044 } else {
492088f8b78aSgm89044 /*
492188f8b78aSgm89044 * These fields have to be cleared of FMA if there are no
492288f8b78aSgm89044 * FMA capabilities at runtime.
492388f8b78aSgm89044 */
492488f8b78aSgm89044 dca_regsattr.devacc_attr_access = DDI_DEFAULT_ACC;
492588f8b78aSgm89044 dca_dmaattr.dma_attr_flags = 0;
492688f8b78aSgm89044 }
492788f8b78aSgm89044 }
492888f8b78aSgm89044
492988f8b78aSgm89044
493088f8b78aSgm89044 static void
dca_fma_fini(dca_t * dca)493188f8b78aSgm89044 dca_fma_fini(dca_t *dca)
493288f8b78aSgm89044 {
493388f8b78aSgm89044 /* Only unregister FMA capabilities if we registered some */
493488f8b78aSgm89044 if (dca->fm_capabilities) {
493588f8b78aSgm89044
493688f8b78aSgm89044 /*
493788f8b78aSgm89044 * Release any resources allocated by pci_ereport_setup()
493888f8b78aSgm89044 */
493900d0963fSdilpreet if (DDI_FM_EREPORT_CAP(dca->fm_capabilities) ||
494000d0963fSdilpreet DDI_FM_ERRCB_CAP(dca->fm_capabilities)) {
494188f8b78aSgm89044 pci_ereport_teardown(dca->dca_dip);
494288f8b78aSgm89044 }
494388f8b78aSgm89044
494488f8b78aSgm89044 /*
494588f8b78aSgm89044 * Free callback mutex and un-register error callback if
494688f8b78aSgm89044 * error callback capable.
494788f8b78aSgm89044 */
494888f8b78aSgm89044 if (DDI_FM_ERRCB_CAP(dca->fm_capabilities)) {
494988f8b78aSgm89044 ddi_fm_handler_unregister(dca->dca_dip);
495088f8b78aSgm89044 }
495188f8b78aSgm89044
495288f8b78aSgm89044 /* Unregister from IO Fault Services */
495388f8b78aSgm89044 ddi_fm_fini(dca->dca_dip);
495488f8b78aSgm89044 DBG(dca, DWARN, "fm_capable() = 0x%x",
495588f8b78aSgm89044 ddi_fm_capable(dca->dca_dip));
495688f8b78aSgm89044 }
495788f8b78aSgm89044 }
495888f8b78aSgm89044
495988f8b78aSgm89044
496088f8b78aSgm89044 /*
496188f8b78aSgm89044 * The IO fault service error handling callback function
496288f8b78aSgm89044 */
496300d0963fSdilpreet /*ARGSUSED*/
496488f8b78aSgm89044 static int
dca_fm_error_cb(dev_info_t * dip,ddi_fm_error_t * err,const void * impl_data)496588f8b78aSgm89044 dca_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
496688f8b78aSgm89044 {
496788f8b78aSgm89044 dca_t *dca = (dca_t *)impl_data;
496888f8b78aSgm89044
496900d0963fSdilpreet pci_ereport_post(dip, err, NULL);
497000d0963fSdilpreet if (err->fme_status == DDI_FM_FATAL) {
497188f8b78aSgm89044 dca_failure(dca, DDI_DATAPATH_FAULT,
497288f8b78aSgm89044 DCA_FM_ECLASS_NONE, dca_ena(0), CRYPTO_DEVICE_ERROR,
497388f8b78aSgm89044 "fault PCI in FMA callback.");
497488f8b78aSgm89044 }
497500d0963fSdilpreet return (err->fme_status);
497688f8b78aSgm89044 }
497788f8b78aSgm89044
497888f8b78aSgm89044
497988f8b78aSgm89044 static int
dca_check_acc_handle(dca_t * dca,ddi_acc_handle_t handle,dca_fma_eclass_t eclass_index)498088f8b78aSgm89044 dca_check_acc_handle(dca_t *dca, ddi_acc_handle_t handle,
498188f8b78aSgm89044 dca_fma_eclass_t eclass_index)
498288f8b78aSgm89044 {
498388f8b78aSgm89044 ddi_fm_error_t de;
498488f8b78aSgm89044 int version = 0;
498588f8b78aSgm89044
498688f8b78aSgm89044 ddi_fm_acc_err_get(handle, &de, version);
498788f8b78aSgm89044 if (de.fme_status != DDI_FM_OK) {
498888f8b78aSgm89044 dca_failure(dca, DDI_DATAPATH_FAULT,
498988f8b78aSgm89044 eclass_index, fm_ena_increment(de.fme_ena),
499088f8b78aSgm89044 CRYPTO_DEVICE_ERROR, "");
499188f8b78aSgm89044 return (DDI_FAILURE);
499288f8b78aSgm89044 }
499388f8b78aSgm89044
499488f8b78aSgm89044 return (DDI_SUCCESS);
499588f8b78aSgm89044 }
499688f8b78aSgm89044
499788f8b78aSgm89044 int
dca_check_dma_handle(dca_t * dca,ddi_dma_handle_t handle,dca_fma_eclass_t eclass_index)499888f8b78aSgm89044 dca_check_dma_handle(dca_t *dca, ddi_dma_handle_t handle,
499988f8b78aSgm89044 dca_fma_eclass_t eclass_index)
500088f8b78aSgm89044 {
500188f8b78aSgm89044 ddi_fm_error_t de;
500288f8b78aSgm89044 int version = 0;
500388f8b78aSgm89044
500488f8b78aSgm89044 ddi_fm_dma_err_get(handle, &de, version);
500588f8b78aSgm89044 if (de.fme_status != DDI_FM_OK) {
500688f8b78aSgm89044 dca_failure(dca, DDI_DATAPATH_FAULT,
500788f8b78aSgm89044 eclass_index, fm_ena_increment(de.fme_ena),
500888f8b78aSgm89044 CRYPTO_DEVICE_ERROR, "");
500988f8b78aSgm89044 return (DDI_FAILURE);
501088f8b78aSgm89044 }
501188f8b78aSgm89044 return (DDI_SUCCESS);
501288f8b78aSgm89044 }
501388f8b78aSgm89044
501488f8b78aSgm89044 static uint64_t
dca_ena(uint64_t ena)501588f8b78aSgm89044 dca_ena(uint64_t ena)
501688f8b78aSgm89044 {
501788f8b78aSgm89044 if (ena == 0)
501888f8b78aSgm89044 ena = fm_ena_generate(0, FM_ENA_FMT1);
501988f8b78aSgm89044 else
502088f8b78aSgm89044 ena = fm_ena_increment(ena);
502188f8b78aSgm89044 return (ena);
502288f8b78aSgm89044 }
502388f8b78aSgm89044
502488f8b78aSgm89044 static char *
dca_fma_eclass_string(char * model,dca_fma_eclass_t index)502588f8b78aSgm89044 dca_fma_eclass_string(char *model, dca_fma_eclass_t index)
502688f8b78aSgm89044 {
502788f8b78aSgm89044 if (strstr(model, "500"))
502888f8b78aSgm89044 return (dca_fma_eclass_sca500[index]);
502988f8b78aSgm89044 else
503088f8b78aSgm89044 return (dca_fma_eclass_sca1000[index]);
503188f8b78aSgm89044 }
5032