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 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 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 55688f8b78aSgm89044 _info(struct modinfo *modinfop) 55788f8b78aSgm89044 { 55888f8b78aSgm89044 DBG(NULL, DMOD, "dca: in _info"); 55988f8b78aSgm89044 56088f8b78aSgm89044 return (mod_info(&modlinkage, modinfop)); 56188f8b78aSgm89044 } 56288f8b78aSgm89044 56388f8b78aSgm89044 int 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 * 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 * 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 * 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 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 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 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 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 * 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 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 * 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 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 * 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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