1906Sgm89044 /* 2906Sgm89044 * CDDL HEADER START 3906Sgm89044 * 4906Sgm89044 * The contents of this file are subject to the terms of the 5906Sgm89044 * Common Development and Distribution License (the "License"). 6906Sgm89044 * You may not use this file except in compliance with the License. 7906Sgm89044 * 8906Sgm89044 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9906Sgm89044 * or http://www.opensolaris.org/os/licensing. 10906Sgm89044 * See the License for the specific language governing permissions 11906Sgm89044 * and limitations under the License. 12906Sgm89044 * 13906Sgm89044 * When distributing Covered Code, include this CDDL HEADER in each 14906Sgm89044 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15906Sgm89044 * If applicable, add the following below this CDDL HEADER, with the 16906Sgm89044 * fields enclosed by brackets "[]" replaced with your own identifying 17906Sgm89044 * information: Portions Copyright [yyyy] [name of copyright owner] 18906Sgm89044 * 19906Sgm89044 * CDDL HEADER END 20906Sgm89044 */ 21906Sgm89044 22906Sgm89044 /* 23*5063Sgm89044 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24906Sgm89044 * Use is subject to license terms. 25906Sgm89044 */ 26906Sgm89044 27906Sgm89044 #pragma ident "%Z%%M% %I% %E% SMI" 28906Sgm89044 29906Sgm89044 /* 30906Sgm89044 * Deimos - cryptographic acceleration based upon Broadcom 582x. 31906Sgm89044 */ 32906Sgm89044 33906Sgm89044 #include <sys/types.h> 34906Sgm89044 #include <sys/modctl.h> 35906Sgm89044 #include <sys/conf.h> 36906Sgm89044 #include <sys/devops.h> 37906Sgm89044 #include <sys/ddi.h> 38906Sgm89044 #include <sys/sunddi.h> 39906Sgm89044 #include <sys/cmn_err.h> 40906Sgm89044 #include <sys/varargs.h> 41906Sgm89044 #include <sys/file.h> 42906Sgm89044 #include <sys/stat.h> 43906Sgm89044 #include <sys/kmem.h> 44906Sgm89044 #include <sys/ioccom.h> 45906Sgm89044 #include <sys/open.h> 46906Sgm89044 #include <sys/cred.h> 47906Sgm89044 #include <sys/kstat.h> 48906Sgm89044 #include <sys/strsun.h> 49906Sgm89044 #include <sys/note.h> 50906Sgm89044 #include <sys/crypto/common.h> 51906Sgm89044 #include <sys/crypto/spi.h> 52906Sgm89044 #include <sys/ddifm.h> 53906Sgm89044 #include <sys/fm/protocol.h> 54906Sgm89044 #include <sys/fm/util.h> 55906Sgm89044 #include <sys/fm/io/ddi.h> 56906Sgm89044 #include <sys/crypto/dca.h> 57906Sgm89044 58906Sgm89044 /* 59906Sgm89044 * Core Deimos driver. 60906Sgm89044 */ 61906Sgm89044 62906Sgm89044 static void dca_enlist2(dca_listnode_t *, dca_listnode_t *, 63906Sgm89044 kmutex_t *); 64906Sgm89044 static void dca_rmlist2(dca_listnode_t *node, kmutex_t *); 65906Sgm89044 static dca_listnode_t *dca_delist2(dca_listnode_t *q, kmutex_t *); 66906Sgm89044 static void dca_free_context_list(dca_t *dca); 67906Sgm89044 static int dca_free_context_low(crypto_ctx_t *ctx); 68906Sgm89044 static int dca_attach(dev_info_t *, ddi_attach_cmd_t); 69906Sgm89044 static int dca_detach(dev_info_t *, ddi_detach_cmd_t); 70906Sgm89044 static int dca_suspend(dca_t *); 71906Sgm89044 static int dca_resume(dca_t *); 72906Sgm89044 static int dca_init(dca_t *); 73906Sgm89044 static int dca_reset(dca_t *, int); 74906Sgm89044 static int dca_initworklist(dca_t *, dca_worklist_t *); 75906Sgm89044 static void dca_uninit(dca_t *); 76906Sgm89044 static void dca_initq(dca_listnode_t *); 77906Sgm89044 static void dca_enqueue(dca_listnode_t *, dca_listnode_t *); 78906Sgm89044 static dca_listnode_t *dca_dequeue(dca_listnode_t *); 79906Sgm89044 static dca_listnode_t *dca_unqueue(dca_listnode_t *); 80906Sgm89044 static dca_request_t *dca_newreq(dca_t *); 81906Sgm89044 static dca_work_t *dca_getwork(dca_t *, int); 82906Sgm89044 static void dca_freework(dca_work_t *); 83906Sgm89044 static dca_work_t *dca_newwork(dca_t *); 84906Sgm89044 static void dca_destroywork(dca_work_t *); 85906Sgm89044 static void dca_schedule(dca_t *, int); 86906Sgm89044 static void dca_reclaim(dca_t *, int); 87906Sgm89044 static uint_t dca_intr(char *); 88906Sgm89044 static void dca_failure(dca_t *, ddi_fault_location_t, 89906Sgm89044 dca_fma_eclass_t index, uint64_t, int, char *, ...); 90906Sgm89044 static void dca_jobtimeout(void *); 91906Sgm89044 static int dca_drain(dca_t *); 92906Sgm89044 static void dca_undrain(dca_t *); 93906Sgm89044 static void dca_rejectjobs(dca_t *); 94906Sgm89044 95906Sgm89044 #ifdef SCHEDDELAY 96906Sgm89044 static void dca_schedtimeout(void *); 97906Sgm89044 #endif 98906Sgm89044 99906Sgm89044 /* 100906Sgm89044 * We want these inlined for performance. 101906Sgm89044 */ 102906Sgm89044 #ifndef DEBUG 103906Sgm89044 #pragma inline(dca_freereq, dca_getreq, dca_freework, dca_getwork) 104906Sgm89044 #pragma inline(dca_enqueue, dca_dequeue, dca_rmqueue, dca_done) 105906Sgm89044 #pragma inline(dca_reverse, dca_length) 106906Sgm89044 #endif 107906Sgm89044 108906Sgm89044 /* 109906Sgm89044 * Device operations. 110906Sgm89044 */ 111906Sgm89044 static struct dev_ops devops = { 112906Sgm89044 DEVO_REV, /* devo_rev */ 113906Sgm89044 0, /* devo_refcnt */ 114906Sgm89044 nodev, /* devo_getinfo */ 115906Sgm89044 nulldev, /* devo_identify */ 116906Sgm89044 nulldev, /* devo_probe */ 117906Sgm89044 dca_attach, /* devo_attach */ 118906Sgm89044 dca_detach, /* devo_detach */ 119906Sgm89044 nodev, /* devo_reset */ 120906Sgm89044 NULL, /* devo_cb_ops */ 121906Sgm89044 NULL, /* devo_bus_ops */ 122906Sgm89044 ddi_power /* devo_power */ 123906Sgm89044 }; 124906Sgm89044 125906Sgm89044 #define IDENT "PCI Crypto Accelerator 2.0" 126906Sgm89044 #define IDENT_SYM "Crypto Accel Sym 2.0" 127906Sgm89044 #define IDENT_ASYM "Crypto Accel Asym 2.0" 128906Sgm89044 129906Sgm89044 /* Space-padded, will be filled in dynamically during registration */ 130906Sgm89044 #define IDENT3 "PCI Crypto Accelerator Mod 2.0" 131906Sgm89044 132906Sgm89044 #define VENDOR "Sun Microsystems, Inc." 133906Sgm89044 134906Sgm89044 #define STALETIME (30 * SECOND) 135906Sgm89044 136906Sgm89044 #define crypto_prov_notify crypto_provider_notification 137906Sgm89044 /* A 28 char function name doesn't leave much line space */ 138906Sgm89044 139906Sgm89044 /* 140906Sgm89044 * Module linkage. 141906Sgm89044 */ 142906Sgm89044 static struct modldrv modldrv = { 143906Sgm89044 &mod_driverops, /* drv_modops */ 144906Sgm89044 IDENT, /* drv_linkinfo */ 145906Sgm89044 &devops, /* drv_dev_ops */ 146906Sgm89044 }; 147906Sgm89044 148906Sgm89044 extern struct mod_ops mod_cryptoops; 149906Sgm89044 150906Sgm89044 static struct modlcrypto modlcrypto = { 151906Sgm89044 &mod_cryptoops, 152906Sgm89044 IDENT3 153906Sgm89044 }; 154906Sgm89044 155906Sgm89044 static struct modlinkage modlinkage = { 156906Sgm89044 MODREV_1, /* ml_rev */ 157906Sgm89044 &modldrv, /* ml_linkage */ 158906Sgm89044 &modlcrypto, 159906Sgm89044 NULL 160906Sgm89044 }; 161906Sgm89044 162906Sgm89044 /* 163906Sgm89044 * CSPI information (entry points, provider info, etc.) 164906Sgm89044 */ 165906Sgm89044 166906Sgm89044 /* Mechanisms for the symmetric cipher provider */ 167906Sgm89044 static crypto_mech_info_t dca_mech_info_tab1[] = { 168906Sgm89044 /* DES-CBC */ 169906Sgm89044 {SUN_CKM_DES_CBC, DES_CBC_MECH_INFO_TYPE, 170906Sgm89044 CRYPTO_FG_ENCRYPT | CRYPTO_FG_DECRYPT | 171906Sgm89044 CRYPTO_FG_ENCRYPT_ATOMIC | CRYPTO_FG_DECRYPT_ATOMIC, 172906Sgm89044 DES_KEY_LEN, DES_KEY_LEN, CRYPTO_KEYSIZE_UNIT_IN_BYTES}, 173906Sgm89044 /* 3DES-CBC */ 174906Sgm89044 {SUN_CKM_DES3_CBC, DES3_CBC_MECH_INFO_TYPE, 175906Sgm89044 CRYPTO_FG_ENCRYPT | CRYPTO_FG_DECRYPT | 176906Sgm89044 CRYPTO_FG_ENCRYPT_ATOMIC | CRYPTO_FG_DECRYPT_ATOMIC, 177906Sgm89044 DES3_KEY_LEN, DES3_KEY_LEN, CRYPTO_KEYSIZE_UNIT_IN_BYTES} 178906Sgm89044 }; 179906Sgm89044 180906Sgm89044 /* Mechanisms for the asymmetric cipher provider */ 181906Sgm89044 static crypto_mech_info_t dca_mech_info_tab2[] = { 182906Sgm89044 /* DSA */ 183906Sgm89044 {SUN_CKM_DSA, DSA_MECH_INFO_TYPE, 184906Sgm89044 CRYPTO_FG_SIGN | CRYPTO_FG_VERIFY | 185906Sgm89044 CRYPTO_FG_SIGN_ATOMIC | CRYPTO_FG_VERIFY_ATOMIC, 186906Sgm89044 DSA_MIN_KEY_LEN * 8, DSA_MAX_KEY_LEN * 8, 187906Sgm89044 CRYPTO_KEYSIZE_UNIT_IN_BITS}, 188906Sgm89044 189906Sgm89044 /* RSA */ 190906Sgm89044 {SUN_CKM_RSA_X_509, RSA_X_509_MECH_INFO_TYPE, 191906Sgm89044 CRYPTO_FG_ENCRYPT | CRYPTO_FG_DECRYPT | CRYPTO_FG_SIGN | 192906Sgm89044 CRYPTO_FG_SIGN_RECOVER | CRYPTO_FG_VERIFY | 193906Sgm89044 CRYPTO_FG_VERIFY_RECOVER | 194906Sgm89044 CRYPTO_FG_ENCRYPT_ATOMIC | CRYPTO_FG_DECRYPT_ATOMIC | 195906Sgm89044 CRYPTO_FG_SIGN_ATOMIC | CRYPTO_FG_SIGN_RECOVER_ATOMIC | 196906Sgm89044 CRYPTO_FG_VERIFY_ATOMIC | CRYPTO_FG_VERIFY_RECOVER_ATOMIC, 197906Sgm89044 RSA_MIN_KEY_LEN * 8, RSA_MAX_KEY_LEN * 8, 198906Sgm89044 CRYPTO_KEYSIZE_UNIT_IN_BITS}, 199906Sgm89044 {SUN_CKM_RSA_PKCS, RSA_PKCS_MECH_INFO_TYPE, 200906Sgm89044 CRYPTO_FG_ENCRYPT | CRYPTO_FG_DECRYPT | CRYPTO_FG_SIGN | 201906Sgm89044 CRYPTO_FG_SIGN_RECOVER | CRYPTO_FG_VERIFY | 202906Sgm89044 CRYPTO_FG_VERIFY_RECOVER | 203906Sgm89044 CRYPTO_FG_ENCRYPT_ATOMIC | CRYPTO_FG_DECRYPT_ATOMIC | 204906Sgm89044 CRYPTO_FG_SIGN_ATOMIC | CRYPTO_FG_SIGN_RECOVER_ATOMIC | 205906Sgm89044 CRYPTO_FG_VERIFY_ATOMIC | CRYPTO_FG_VERIFY_RECOVER_ATOMIC, 206906Sgm89044 RSA_MIN_KEY_LEN * 8, RSA_MAX_KEY_LEN * 8, 207906Sgm89044 CRYPTO_KEYSIZE_UNIT_IN_BITS} 208906Sgm89044 }; 209906Sgm89044 210906Sgm89044 static void dca_provider_status(crypto_provider_handle_t, uint_t *); 211906Sgm89044 212906Sgm89044 static crypto_control_ops_t dca_control_ops = { 213906Sgm89044 dca_provider_status 214906Sgm89044 }; 215906Sgm89044 216906Sgm89044 static int dca_encrypt_init(crypto_ctx_t *, crypto_mechanism_t *, 217906Sgm89044 crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t); 218906Sgm89044 static int dca_encrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *, 219906Sgm89044 crypto_req_handle_t); 220906Sgm89044 static int dca_encrypt_update(crypto_ctx_t *, crypto_data_t *, 221906Sgm89044 crypto_data_t *, crypto_req_handle_t); 222906Sgm89044 static int dca_encrypt_final(crypto_ctx_t *, crypto_data_t *, 223906Sgm89044 crypto_req_handle_t); 224906Sgm89044 static int dca_encrypt_atomic(crypto_provider_handle_t, crypto_session_id_t, 225906Sgm89044 crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, 226906Sgm89044 crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t); 227906Sgm89044 228906Sgm89044 static int dca_decrypt_init(crypto_ctx_t *, crypto_mechanism_t *, 229906Sgm89044 crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t); 230906Sgm89044 static int dca_decrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *, 231906Sgm89044 crypto_req_handle_t); 232906Sgm89044 static int dca_decrypt_update(crypto_ctx_t *, crypto_data_t *, 233906Sgm89044 crypto_data_t *, crypto_req_handle_t); 234906Sgm89044 static int dca_decrypt_final(crypto_ctx_t *, crypto_data_t *, 235906Sgm89044 crypto_req_handle_t); 236906Sgm89044 static int dca_decrypt_atomic(crypto_provider_handle_t, crypto_session_id_t, 237906Sgm89044 crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, 238906Sgm89044 crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t); 239906Sgm89044 240906Sgm89044 static crypto_cipher_ops_t dca_cipher_ops = { 241906Sgm89044 dca_encrypt_init, 242906Sgm89044 dca_encrypt, 243906Sgm89044 dca_encrypt_update, 244906Sgm89044 dca_encrypt_final, 245906Sgm89044 dca_encrypt_atomic, 246906Sgm89044 dca_decrypt_init, 247906Sgm89044 dca_decrypt, 248906Sgm89044 dca_decrypt_update, 249906Sgm89044 dca_decrypt_final, 250906Sgm89044 dca_decrypt_atomic 251906Sgm89044 }; 252906Sgm89044 253906Sgm89044 static int dca_sign_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *, 254906Sgm89044 crypto_spi_ctx_template_t, crypto_req_handle_t); 255906Sgm89044 static int dca_sign(crypto_ctx_t *, crypto_data_t *, crypto_data_t *, 256906Sgm89044 crypto_req_handle_t); 257906Sgm89044 static int dca_sign_update(crypto_ctx_t *, crypto_data_t *, 258906Sgm89044 crypto_req_handle_t); 259906Sgm89044 static int dca_sign_final(crypto_ctx_t *, crypto_data_t *, 260906Sgm89044 crypto_req_handle_t); 261906Sgm89044 static int dca_sign_atomic(crypto_provider_handle_t, crypto_session_id_t, 262906Sgm89044 crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *, 263906Sgm89044 crypto_spi_ctx_template_t, crypto_req_handle_t); 264906Sgm89044 static int dca_sign_recover_init(crypto_ctx_t *, crypto_mechanism_t *, 265906Sgm89044 crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t); 266906Sgm89044 static int dca_sign_recover(crypto_ctx_t *, crypto_data_t *, crypto_data_t *, 267906Sgm89044 crypto_req_handle_t); 268906Sgm89044 static int dca_sign_recover_atomic(crypto_provider_handle_t, 269906Sgm89044 crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, 270906Sgm89044 crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t); 271906Sgm89044 272906Sgm89044 static crypto_sign_ops_t dca_sign_ops = { 273906Sgm89044 dca_sign_init, 274906Sgm89044 dca_sign, 275906Sgm89044 dca_sign_update, 276906Sgm89044 dca_sign_final, 277906Sgm89044 dca_sign_atomic, 278906Sgm89044 dca_sign_recover_init, 279906Sgm89044 dca_sign_recover, 280906Sgm89044 dca_sign_recover_atomic 281906Sgm89044 }; 282906Sgm89044 283906Sgm89044 static int dca_verify_init(crypto_ctx_t *, crypto_mechanism_t *, 284906Sgm89044 crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t); 285906Sgm89044 static int dca_verify(crypto_ctx_t *, crypto_data_t *, crypto_data_t *, 286906Sgm89044 crypto_req_handle_t); 287906Sgm89044 static int dca_verify_update(crypto_ctx_t *, crypto_data_t *, 288906Sgm89044 crypto_req_handle_t); 289906Sgm89044 static int dca_verify_final(crypto_ctx_t *, crypto_data_t *, 290906Sgm89044 crypto_req_handle_t); 291906Sgm89044 static int dca_verify_atomic(crypto_provider_handle_t, crypto_session_id_t, 292906Sgm89044 crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, 293906Sgm89044 crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t); 294906Sgm89044 static int dca_verify_recover_init(crypto_ctx_t *, crypto_mechanism_t *, 295906Sgm89044 crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t); 296906Sgm89044 static int dca_verify_recover(crypto_ctx_t *, crypto_data_t *, 297906Sgm89044 crypto_data_t *, crypto_req_handle_t); 298906Sgm89044 static int dca_verify_recover_atomic(crypto_provider_handle_t, 299906Sgm89044 crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, 300906Sgm89044 crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t); 301906Sgm89044 302906Sgm89044 static crypto_verify_ops_t dca_verify_ops = { 303906Sgm89044 dca_verify_init, 304906Sgm89044 dca_verify, 305906Sgm89044 dca_verify_update, 306906Sgm89044 dca_verify_final, 307906Sgm89044 dca_verify_atomic, 308906Sgm89044 dca_verify_recover_init, 309906Sgm89044 dca_verify_recover, 310906Sgm89044 dca_verify_recover_atomic 311906Sgm89044 }; 312906Sgm89044 313906Sgm89044 static int dca_generate_random(crypto_provider_handle_t, crypto_session_id_t, 314906Sgm89044 uchar_t *, size_t, crypto_req_handle_t); 315906Sgm89044 316906Sgm89044 static crypto_random_number_ops_t dca_random_number_ops = { 317906Sgm89044 NULL, 318906Sgm89044 dca_generate_random 319906Sgm89044 }; 320906Sgm89044 321906Sgm89044 static int ext_info_sym(crypto_provider_handle_t prov, 322906Sgm89044 crypto_provider_ext_info_t *ext_info, crypto_req_handle_t cfreq); 323906Sgm89044 static int ext_info_asym(crypto_provider_handle_t prov, 324906Sgm89044 crypto_provider_ext_info_t *ext_info, crypto_req_handle_t cfreq); 325906Sgm89044 static int ext_info_base(crypto_provider_handle_t prov, 326906Sgm89044 crypto_provider_ext_info_t *ext_info, crypto_req_handle_t cfreq, char *id); 327906Sgm89044 328906Sgm89044 static crypto_provider_management_ops_t dca_provmanage_ops_1 = { 329906Sgm89044 ext_info_sym, /* ext_info */ 330906Sgm89044 NULL, /* init_token */ 331906Sgm89044 NULL, /* init_pin */ 332906Sgm89044 NULL /* set_pin */ 333906Sgm89044 }; 334906Sgm89044 335906Sgm89044 static crypto_provider_management_ops_t dca_provmanage_ops_2 = { 336906Sgm89044 ext_info_asym, /* ext_info */ 337906Sgm89044 NULL, /* init_token */ 338906Sgm89044 NULL, /* init_pin */ 339906Sgm89044 NULL /* set_pin */ 340906Sgm89044 }; 341906Sgm89044 342906Sgm89044 int dca_free_context(crypto_ctx_t *); 343906Sgm89044 344906Sgm89044 static crypto_ctx_ops_t dca_ctx_ops = { 345906Sgm89044 NULL, 346906Sgm89044 dca_free_context 347906Sgm89044 }; 348906Sgm89044 349906Sgm89044 /* Operations for the symmetric cipher provider */ 350906Sgm89044 static crypto_ops_t dca_crypto_ops1 = { 351906Sgm89044 &dca_control_ops, 352906Sgm89044 NULL, /* digest_ops */ 353906Sgm89044 &dca_cipher_ops, 354906Sgm89044 NULL, /* mac_ops */ 355906Sgm89044 NULL, /* sign_ops */ 356906Sgm89044 NULL, /* verify_ops */ 357906Sgm89044 NULL, /* dual_ops */ 358906Sgm89044 NULL, /* cipher_mac_ops */ 359906Sgm89044 NULL, /* random_number_ops */ 360906Sgm89044 NULL, /* session_ops */ 361906Sgm89044 NULL, /* object_ops */ 362906Sgm89044 NULL, /* key_ops */ 363906Sgm89044 &dca_provmanage_ops_1, /* management_ops */ 364906Sgm89044 &dca_ctx_ops 365906Sgm89044 }; 366906Sgm89044 367906Sgm89044 /* Operations for the asymmetric cipher provider */ 368906Sgm89044 static crypto_ops_t dca_crypto_ops2 = { 369906Sgm89044 &dca_control_ops, 370906Sgm89044 NULL, /* digest_ops */ 371906Sgm89044 &dca_cipher_ops, 372906Sgm89044 NULL, /* mac_ops */ 373906Sgm89044 &dca_sign_ops, 374906Sgm89044 &dca_verify_ops, 375906Sgm89044 NULL, /* dual_ops */ 376906Sgm89044 NULL, /* cipher_mac_ops */ 377906Sgm89044 &dca_random_number_ops, 378906Sgm89044 NULL, /* session_ops */ 379906Sgm89044 NULL, /* object_ops */ 380906Sgm89044 NULL, /* key_ops */ 381906Sgm89044 &dca_provmanage_ops_2, /* management_ops */ 382906Sgm89044 &dca_ctx_ops 383906Sgm89044 }; 384906Sgm89044 385906Sgm89044 /* Provider information for the symmetric cipher provider */ 386906Sgm89044 static crypto_provider_info_t dca_prov_info1 = { 387906Sgm89044 CRYPTO_SPI_VERSION_1, 388906Sgm89044 NULL, /* pi_provider_description */ 389906Sgm89044 CRYPTO_HW_PROVIDER, 390906Sgm89044 NULL, /* pi_provider_dev */ 391906Sgm89044 NULL, /* pi_provider_handle */ 392906Sgm89044 &dca_crypto_ops1, 393906Sgm89044 sizeof (dca_mech_info_tab1)/sizeof (crypto_mech_info_t), 394906Sgm89044 dca_mech_info_tab1, 395906Sgm89044 0, /* pi_logical_provider_count */ 396906Sgm89044 NULL /* pi_logical_providers */ 397906Sgm89044 }; 398906Sgm89044 399906Sgm89044 /* Provider information for the asymmetric cipher provider */ 400906Sgm89044 static crypto_provider_info_t dca_prov_info2 = { 401906Sgm89044 CRYPTO_SPI_VERSION_1, 402906Sgm89044 NULL, /* pi_provider_description */ 403906Sgm89044 CRYPTO_HW_PROVIDER, 404906Sgm89044 NULL, /* pi_provider_dev */ 405906Sgm89044 NULL, /* pi_provider_handle */ 406906Sgm89044 &dca_crypto_ops2, 407906Sgm89044 sizeof (dca_mech_info_tab2)/sizeof (crypto_mech_info_t), 408906Sgm89044 dca_mech_info_tab2, 409906Sgm89044 0, /* pi_logical_provider_count */ 410906Sgm89044 NULL /* pi_logical_providers */ 411906Sgm89044 }; 412906Sgm89044 413906Sgm89044 /* Convenience macros */ 414906Sgm89044 /* Retrieve the softc and instance number from a SPI crypto context */ 415906Sgm89044 #define DCA_SOFTC_FROM_CTX(ctx, softc, instance) { \ 416906Sgm89044 (softc) = (dca_t *)(ctx)->cc_provider; \ 417906Sgm89044 (instance) = ddi_get_instance((softc)->dca_dip); \ 418906Sgm89044 } 419906Sgm89044 420906Sgm89044 #define DCA_MECH_FROM_CTX(ctx) \ 421906Sgm89044 (((dca_request_t *)(ctx)->cc_provider_private)->dr_ctx.ctx_cm_type) 422906Sgm89044 423906Sgm89044 static int dca_bindchains_one(dca_request_t *reqp, size_t cnt, int dr_offset, 424906Sgm89044 caddr_t kaddr, ddi_dma_handle_t handle, uint_t flags, 425906Sgm89044 dca_chain_t *head, int *n_chain); 426906Sgm89044 static uint64_t dca_ena(uint64_t ena); 427906Sgm89044 static caddr_t dca_bufdaddr_out(crypto_data_t *data); 428906Sgm89044 static char *dca_fma_eclass_string(char *model, dca_fma_eclass_t index); 429906Sgm89044 static int dca_check_acc_handle(dca_t *dca, ddi_acc_handle_t handle, 430906Sgm89044 dca_fma_eclass_t eclass_index); 431906Sgm89044 432906Sgm89044 static void dca_fma_init(dca_t *dca); 433906Sgm89044 static void dca_fma_fini(dca_t *dca); 434906Sgm89044 static int dca_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, 435906Sgm89044 const void *impl_data); 436906Sgm89044 437906Sgm89044 438906Sgm89044 static dca_device_t dca_devices[] = { 439906Sgm89044 /* Broadcom vanilla variants */ 440906Sgm89044 { 0x14e4, 0x5820, "Broadcom 5820" }, 441906Sgm89044 { 0x14e4, 0x5821, "Broadcom 5821" }, 442906Sgm89044 { 0x14e4, 0x5822, "Broadcom 5822" }, 443906Sgm89044 { 0x14e4, 0x5825, "Broadcom 5825" }, 444906Sgm89044 /* Sun specific OEMd variants */ 445906Sgm89044 { 0x108e, 0x5454, "SCA" }, 446906Sgm89044 { 0x108e, 0x5455, "SCA 1000" }, 447906Sgm89044 { 0x108e, 0x5457, "SCA 500" }, 448906Sgm89044 /* subsysid should be 0x5457, but got 0x1 from HW. Assume both here. */ 449906Sgm89044 { 0x108e, 0x1, "SCA 500" }, 450906Sgm89044 }; 451906Sgm89044 452906Sgm89044 /* 453906Sgm89044 * Device attributes. 454906Sgm89044 */ 455906Sgm89044 static struct ddi_device_acc_attr dca_regsattr = { 456906Sgm89044 DDI_DEVICE_ATTR_V0, 457906Sgm89044 DDI_STRUCTURE_LE_ACC, 458906Sgm89044 DDI_STRICTORDER_ACC, 459906Sgm89044 DDI_FLAGERR_ACC 460906Sgm89044 }; 461906Sgm89044 462906Sgm89044 static struct ddi_device_acc_attr dca_devattr = { 463906Sgm89044 DDI_DEVICE_ATTR_V0, 464906Sgm89044 DDI_STRUCTURE_LE_ACC, 465906Sgm89044 DDI_STRICTORDER_ACC, 466906Sgm89044 DDI_FLAGERR_ACC 467906Sgm89044 }; 468906Sgm89044 469906Sgm89044 #if !defined(i386) && !defined(__i386) 470906Sgm89044 static struct ddi_device_acc_attr dca_bufattr = { 471906Sgm89044 DDI_DEVICE_ATTR_V0, 472906Sgm89044 DDI_NEVERSWAP_ACC, 473906Sgm89044 DDI_STRICTORDER_ACC, 474906Sgm89044 DDI_FLAGERR_ACC 475906Sgm89044 }; 476906Sgm89044 #endif 477906Sgm89044 478906Sgm89044 static struct ddi_dma_attr dca_dmaattr = { 479906Sgm89044 DMA_ATTR_V0, /* dma_attr_version */ 480906Sgm89044 0x0, /* dma_attr_addr_lo */ 481906Sgm89044 0xffffffffUL, /* dma_attr_addr_hi */ 482906Sgm89044 0x00ffffffUL, /* dma_attr_count_max */ 483906Sgm89044 0x40, /* dma_attr_align */ 484906Sgm89044 0x40, /* dma_attr_burstsizes */ 485906Sgm89044 0x1, /* dma_attr_minxfer */ 486906Sgm89044 0x00ffffffUL, /* dma_attr_maxxfer */ 487906Sgm89044 0xffffffffUL, /* dma_attr_seg */ 488906Sgm89044 #if defined(i386) || defined(__i386) || defined(__amd64) 489906Sgm89044 512, /* dma_attr_sgllen */ 490906Sgm89044 #else 491906Sgm89044 1, /* dma_attr_sgllen */ 492906Sgm89044 #endif 493906Sgm89044 1, /* dma_attr_granular */ 494906Sgm89044 DDI_DMA_FLAGERR /* dma_attr_flags */ 495906Sgm89044 }; 496906Sgm89044 497906Sgm89044 static void *dca_state = NULL; 498906Sgm89044 int dca_mindma = 2500; 499906Sgm89044 500906Sgm89044 /* 501906Sgm89044 * FMA eclass string definitions. Note that these string arrays must be 502906Sgm89044 * consistent with the dca_fma_eclass_t enum. 503906Sgm89044 */ 504906Sgm89044 static char *dca_fma_eclass_sca1000[] = { 505906Sgm89044 "sca1000.hw.device", 506906Sgm89044 "sca1000.hw.timeout", 507906Sgm89044 "sca1000.none" 508906Sgm89044 }; 509906Sgm89044 510906Sgm89044 static char *dca_fma_eclass_sca500[] = { 511906Sgm89044 "sca500.hw.device", 512906Sgm89044 "sca500.hw.timeout", 513906Sgm89044 "sca500.none" 514906Sgm89044 }; 515906Sgm89044 516906Sgm89044 /* 517906Sgm89044 * DDI entry points. 518906Sgm89044 */ 519906Sgm89044 int 520906Sgm89044 _init(void) 521906Sgm89044 { 522906Sgm89044 int rv; 523906Sgm89044 524906Sgm89044 DBG(NULL, DMOD, "dca: in _init"); 525906Sgm89044 526906Sgm89044 if ((rv = ddi_soft_state_init(&dca_state, sizeof (dca_t), 1)) != 0) { 527906Sgm89044 /* this should *never* happen! */ 528906Sgm89044 return (rv); 529906Sgm89044 } 530906Sgm89044 531906Sgm89044 if ((rv = mod_install(&modlinkage)) != 0) { 532906Sgm89044 /* cleanup here */ 533906Sgm89044 ddi_soft_state_fini(&dca_state); 534906Sgm89044 return (rv); 535906Sgm89044 } 536906Sgm89044 537906Sgm89044 return (0); 538906Sgm89044 } 539906Sgm89044 540906Sgm89044 int 541906Sgm89044 _fini(void) 542906Sgm89044 { 543906Sgm89044 int rv; 544906Sgm89044 545906Sgm89044 DBG(NULL, DMOD, "dca: in _fini"); 546906Sgm89044 547906Sgm89044 if ((rv = mod_remove(&modlinkage)) == 0) { 548906Sgm89044 /* cleanup here */ 549906Sgm89044 ddi_soft_state_fini(&dca_state); 550906Sgm89044 } 551906Sgm89044 return (rv); 552906Sgm89044 } 553906Sgm89044 554906Sgm89044 int 555906Sgm89044 _info(struct modinfo *modinfop) 556906Sgm89044 { 557906Sgm89044 DBG(NULL, DMOD, "dca: in _info"); 558906Sgm89044 559906Sgm89044 return (mod_info(&modlinkage, modinfop)); 560906Sgm89044 } 561906Sgm89044 562906Sgm89044 int 563906Sgm89044 dca_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 564906Sgm89044 { 565906Sgm89044 ddi_acc_handle_t pci; 566906Sgm89044 int instance; 567906Sgm89044 ddi_iblock_cookie_t ibc; 568906Sgm89044 int intr_added = 0; 569906Sgm89044 dca_t *dca; 570906Sgm89044 ushort_t venid; 571906Sgm89044 ushort_t devid; 572906Sgm89044 ushort_t revid; 573906Sgm89044 ushort_t subsysid; 574906Sgm89044 ushort_t subvenid; 575906Sgm89044 int i; 576906Sgm89044 int ret; 577906Sgm89044 char ID[64]; 578906Sgm89044 static char *unknowndev = "Unknown device"; 579906Sgm89044 580906Sgm89044 #if DEBUG 581906Sgm89044 /* these are only used for debugging */ 582906Sgm89044 ushort_t pcicomm; 583906Sgm89044 ushort_t pcistat; 584906Sgm89044 uchar_t cachelinesz; 585906Sgm89044 uchar_t mingnt; 586906Sgm89044 uchar_t maxlat; 587906Sgm89044 uchar_t lattmr; 588906Sgm89044 #endif 589906Sgm89044 590906Sgm89044 instance = ddi_get_instance(dip); 591906Sgm89044 592906Sgm89044 DBG(NULL, DMOD, "dca: in dca_attach() for %d", instance); 593906Sgm89044 594906Sgm89044 switch (cmd) { 595906Sgm89044 case DDI_RESUME: 596906Sgm89044 if ((dca = (dca_t *)ddi_get_driver_private(dip)) == NULL) { 597906Sgm89044 dca_diperror(dip, "no soft state in detach"); 598906Sgm89044 return (DDI_FAILURE); 599906Sgm89044 } 600906Sgm89044 /* assumption: we won't be DDI_DETACHed until we return */ 601906Sgm89044 return (dca_resume(dca)); 602906Sgm89044 case DDI_ATTACH: 603906Sgm89044 break; 604906Sgm89044 default: 605906Sgm89044 return (DDI_FAILURE); 606906Sgm89044 } 607906Sgm89044 608906Sgm89044 if (ddi_slaveonly(dip) == DDI_SUCCESS) { 609906Sgm89044 dca_diperror(dip, "slot does not support PCI bus-master"); 610906Sgm89044 return (DDI_FAILURE); 611906Sgm89044 } 612906Sgm89044 613906Sgm89044 if (ddi_intr_hilevel(dip, 0) != 0) { 614906Sgm89044 dca_diperror(dip, "hilevel interrupts not supported"); 615906Sgm89044 return (DDI_FAILURE); 616906Sgm89044 } 617906Sgm89044 618906Sgm89044 if (pci_config_setup(dip, &pci) != DDI_SUCCESS) { 619906Sgm89044 dca_diperror(dip, "unable to setup PCI config handle"); 620906Sgm89044 return (DDI_FAILURE); 621906Sgm89044 } 622906Sgm89044 623906Sgm89044 /* common PCI attributes */ 624906Sgm89044 venid = pci_config_get16(pci, PCI_VENID); 625906Sgm89044 devid = pci_config_get16(pci, PCI_DEVID); 626906Sgm89044 revid = pci_config_get8(pci, PCI_REVID); 627906Sgm89044 subvenid = pci_config_get16(pci, PCI_SUBVENID); 628906Sgm89044 subsysid = pci_config_get16(pci, PCI_SUBSYSID); 629906Sgm89044 630906Sgm89044 /* 631906Sgm89044 * Broadcom-specific timings. 632906Sgm89044 * We disable these timers/counters since they can cause 633906Sgm89044 * incorrect false failures when the bus is just a little 634906Sgm89044 * bit slow, or busy. 635906Sgm89044 */ 636906Sgm89044 pci_config_put8(pci, PCI_TRDYTO, 0); 637906Sgm89044 pci_config_put8(pci, PCI_RETRIES, 0); 638906Sgm89044 639906Sgm89044 /* initialize PCI access settings */ 640906Sgm89044 pci_config_put16(pci, PCI_COMM, PCICOMM_SEE | 641906Sgm89044 PCICOMM_PEE | PCICOMM_BME | PCICOMM_MAE); 642906Sgm89044 643906Sgm89044 /* set up our PCI latency timer */ 644906Sgm89044 pci_config_put8(pci, PCI_LATTMR, 0x40); 645906Sgm89044 646906Sgm89044 #if DEBUG 647906Sgm89044 /* read registers (for debugging) */ 648906Sgm89044 pcicomm = pci_config_get16(pci, PCI_COMM); 649906Sgm89044 pcistat = pci_config_get16(pci, PCI_STATUS); 650906Sgm89044 cachelinesz = pci_config_get8(pci, PCI_CACHELINESZ); 651906Sgm89044 mingnt = pci_config_get8(pci, PCI_MINGNT); 652906Sgm89044 maxlat = pci_config_get8(pci, PCI_MAXLAT); 653906Sgm89044 lattmr = pci_config_get8(pci, PCI_LATTMR); 654906Sgm89044 #endif 655906Sgm89044 656906Sgm89044 pci_config_teardown(&pci); 657906Sgm89044 658906Sgm89044 if (ddi_get_iblock_cookie(dip, 0, &ibc) != DDI_SUCCESS) { 659906Sgm89044 dca_diperror(dip, "unable to get iblock cookie"); 660906Sgm89044 return (DDI_FAILURE); 661906Sgm89044 } 662906Sgm89044 663906Sgm89044 if (ddi_soft_state_zalloc(dca_state, instance) != DDI_SUCCESS) { 664906Sgm89044 dca_diperror(dip, "unable to allocate soft state"); 665906Sgm89044 return (DDI_FAILURE); 666906Sgm89044 } 667906Sgm89044 668906Sgm89044 dca = ddi_get_soft_state(dca_state, instance); 669906Sgm89044 ASSERT(dca != NULL); 670906Sgm89044 dca->dca_dip = dip; 671906Sgm89044 WORKLIST(dca, MCR1)->dwl_prov = NULL; 672906Sgm89044 WORKLIST(dca, MCR2)->dwl_prov = NULL; 673906Sgm89044 /* figure pagesize */ 674906Sgm89044 dca->dca_pagesize = ddi_ptob(dip, 1); 675906Sgm89044 676906Sgm89044 /* 677906Sgm89044 * Search for the device in our supported devices table. This 678906Sgm89044 * is here for two reasons. First, we want to ensure that 679906Sgm89044 * only Sun-qualified (and presumably Sun-labeled) devices can 680906Sgm89044 * be used with this driver. Second, some devices have 681906Sgm89044 * specific differences. E.g. the 5821 has support for a 682906Sgm89044 * special mode of RC4, deeper queues, power management, and 683906Sgm89044 * other changes. Also, the export versions of some of these 684906Sgm89044 * chips don't support RC4 or 3DES, so we catch that here. 685906Sgm89044 * 686906Sgm89044 * Note that we only look at the upper nibble of the device 687906Sgm89044 * id, which is used to distinguish export vs. domestic 688906Sgm89044 * versions of the chip. (The lower nibble is used for 689906Sgm89044 * stepping information.) 690906Sgm89044 */ 691906Sgm89044 for (i = 0; i < (sizeof (dca_devices) / sizeof (dca_device_t)); i++) { 692906Sgm89044 /* 693906Sgm89044 * Try to match the subsystem information first. 694906Sgm89044 */ 695906Sgm89044 if (subvenid && (subvenid == dca_devices[i].dd_vendor_id) && 696906Sgm89044 subsysid && (subsysid == dca_devices[i].dd_device_id)) { 697906Sgm89044 dca->dca_model = dca_devices[i].dd_model; 6983124Sqs148142 dca->dca_devid = dca_devices[i].dd_device_id; 699906Sgm89044 break; 700906Sgm89044 } 701906Sgm89044 /* 702906Sgm89044 * Failing that, try the generic vendor and device id. 703906Sgm89044 * Even if we find a match, we keep searching anyway, 704906Sgm89044 * since we would prefer to find a match based on the 705906Sgm89044 * subsystem ids. 706906Sgm89044 */ 707906Sgm89044 if ((venid == dca_devices[i].dd_vendor_id) && 708906Sgm89044 (devid == dca_devices[i].dd_device_id)) { 709906Sgm89044 dca->dca_model = dca_devices[i].dd_model; 7103124Sqs148142 dca->dca_devid = dca_devices[i].dd_device_id; 711906Sgm89044 } 712906Sgm89044 } 713906Sgm89044 /* try and handle an unrecognized device */ 714906Sgm89044 if (dca->dca_model == NULL) { 715906Sgm89044 dca->dca_model = unknowndev; 716906Sgm89044 dca_error(dca, "device not recognized, not supported"); 717906Sgm89044 DBG(dca, DPCI, "i=%d venid=%x devid=%x rev=%d", 718906Sgm89044 i, venid, devid, revid); 719906Sgm89044 } 720906Sgm89044 721906Sgm89044 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "description", 722906Sgm89044 dca->dca_model) != DDI_SUCCESS) { 723906Sgm89044 dca_error(dca, "unable to create description property"); 724906Sgm89044 return (DDI_FAILURE); 725906Sgm89044 } 726906Sgm89044 727906Sgm89044 DBG(dca, DPCI, "PCI command=0x%x status=%x cachelinesz=%x", 728906Sgm89044 pcicomm, pcistat, cachelinesz); 729906Sgm89044 DBG(dca, DPCI, "mingnt=0x%x maxlat=0x%x lattmr=0x%x", 730906Sgm89044 mingnt, maxlat, lattmr); 731906Sgm89044 732906Sgm89044 /* 733906Sgm89044 * initialize locks, etc. 734906Sgm89044 */ 735906Sgm89044 (void) mutex_init(&dca->dca_intrlock, NULL, MUTEX_DRIVER, ibc); 736906Sgm89044 737906Sgm89044 /* use RNGSHA1 by default */ 738906Sgm89044 if (ddi_getprop(DDI_DEV_T_ANY, dip, 739906Sgm89044 DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "rngdirect", 0) == 0) { 740906Sgm89044 dca->dca_flags |= DCA_RNGSHA1; 741906Sgm89044 } 742906Sgm89044 743906Sgm89044 /* initialize FMA */ 744906Sgm89044 dca_fma_init(dca); 745906Sgm89044 746906Sgm89044 /* initialize some key data structures */ 747906Sgm89044 if (dca_init(dca) != DDI_SUCCESS) { 748906Sgm89044 goto failed; 749906Sgm89044 } 750906Sgm89044 751906Sgm89044 /* initialize kstats */ 752906Sgm89044 dca_ksinit(dca); 753906Sgm89044 754906Sgm89044 /* setup access to registers */ 755906Sgm89044 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&dca->dca_regs, 756906Sgm89044 0, 0, &dca_regsattr, &dca->dca_regs_handle) != DDI_SUCCESS) { 757906Sgm89044 dca_error(dca, "unable to map registers"); 758906Sgm89044 goto failed; 759906Sgm89044 } 760906Sgm89044 761906Sgm89044 DBG(dca, DCHATTY, "MCR1 = %x", GETCSR(dca, CSR_MCR1)); 762906Sgm89044 DBG(dca, DCHATTY, "CONTROL = %x", GETCSR(dca, CSR_DMACTL)); 763906Sgm89044 DBG(dca, DCHATTY, "STATUS = %x", GETCSR(dca, CSR_DMASTAT)); 764906Sgm89044 DBG(dca, DCHATTY, "DMAEA = %x", GETCSR(dca, CSR_DMAEA)); 765906Sgm89044 DBG(dca, DCHATTY, "MCR2 = %x", GETCSR(dca, CSR_MCR2)); 766906Sgm89044 767906Sgm89044 /* reset the chip */ 768906Sgm89044 if (dca_reset(dca, 0) < 0) { 769906Sgm89044 goto failed; 770906Sgm89044 } 771906Sgm89044 772906Sgm89044 /* initialize the chip */ 773906Sgm89044 PUTCSR(dca, CSR_DMACTL, DMACTL_BE32 | DMACTL_BE64); 774906Sgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle, 775906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 776906Sgm89044 goto failed; 777906Sgm89044 } 778906Sgm89044 779906Sgm89044 /* add the interrupt */ 780906Sgm89044 if (ddi_add_intr(dip, 0, &dca->dca_icookie, NULL, dca_intr, 781906Sgm89044 (void *)dca) != DDI_SUCCESS) { 782906Sgm89044 DBG(dca, DWARN, "ddi_add_intr failed"); 783906Sgm89044 goto failed; 784906Sgm89044 } else { 785906Sgm89044 intr_added = 1; 786906Sgm89044 } 787906Sgm89044 788906Sgm89044 /* enable interrupts on the device */ 789906Sgm89044 /* 790906Sgm89044 * XXX: Note, 5820A1 errata indicates that this may clobber 791906Sgm89044 * bits 24 and 23, which affect the speed of the RNG. Since 792906Sgm89044 * we always want to run in full-speed mode, this should be 793906Sgm89044 * harmless. 794906Sgm89044 */ 7953124Sqs148142 if (dca->dca_devid == 0x5825) { 7963124Sqs148142 /* for 5825 - increase the DMA read size */ 7973124Sqs148142 SETBIT(dca, CSR_DMACTL, 7983124Sqs148142 DMACTL_MCR1IE | DMACTL_MCR2IE | DMACTL_EIE | DMACTL_RD256); 7993124Sqs148142 } else { 8003124Sqs148142 SETBIT(dca, CSR_DMACTL, 8013124Sqs148142 DMACTL_MCR1IE | DMACTL_MCR2IE | DMACTL_EIE); 8023124Sqs148142 } 803906Sgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle, 804906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 805906Sgm89044 goto failed; 806906Sgm89044 } 807906Sgm89044 808906Sgm89044 /* register MCR1 with the crypto framework */ 809906Sgm89044 /* Be careful not to exceed 32 chars */ 810906Sgm89044 (void) sprintf(ID, "%s/%d %s", 811906Sgm89044 ddi_driver_name(dip), ddi_get_instance(dip), IDENT_SYM); 812906Sgm89044 dca_prov_info1.pi_provider_description = ID; 813906Sgm89044 dca_prov_info1.pi_provider_dev.pd_hw = dip; 814906Sgm89044 dca_prov_info1.pi_provider_handle = dca; 815906Sgm89044 if ((ret = crypto_register_provider(&dca_prov_info1, 816906Sgm89044 &WORKLIST(dca, MCR1)->dwl_prov)) != CRYPTO_SUCCESS) { 817906Sgm89044 cmn_err(CE_WARN, 818906Sgm89044 "crypto_register_provider() failed (%d) for MCR1", ret); 819906Sgm89044 goto failed; 820906Sgm89044 } 821906Sgm89044 822906Sgm89044 /* register MCR2 with the crypto framework */ 823906Sgm89044 /* Be careful not to exceed 32 chars */ 824906Sgm89044 (void) sprintf(ID, "%s/%d %s", 825906Sgm89044 ddi_driver_name(dip), ddi_get_instance(dip), IDENT_ASYM); 826906Sgm89044 dca_prov_info2.pi_provider_description = ID; 827906Sgm89044 dca_prov_info2.pi_provider_dev.pd_hw = dip; 828906Sgm89044 dca_prov_info2.pi_provider_handle = dca; 829906Sgm89044 if ((ret = crypto_register_provider(&dca_prov_info2, 830906Sgm89044 &WORKLIST(dca, MCR2)->dwl_prov)) != CRYPTO_SUCCESS) { 831906Sgm89044 cmn_err(CE_WARN, 832906Sgm89044 "crypto_register_provider() failed (%d) for MCR2", ret); 833906Sgm89044 goto failed; 834906Sgm89044 } 835906Sgm89044 836906Sgm89044 crypto_prov_notify(WORKLIST(dca, MCR1)->dwl_prov, 837*5063Sgm89044 CRYPTO_PROVIDER_READY); 838906Sgm89044 crypto_prov_notify(WORKLIST(dca, MCR2)->dwl_prov, 839*5063Sgm89044 CRYPTO_PROVIDER_READY); 840906Sgm89044 841906Sgm89044 /* Initialize the local random number pool for this instance */ 842906Sgm89044 if ((ret = dca_random_init(dca)) != CRYPTO_SUCCESS) { 843906Sgm89044 goto failed; 844906Sgm89044 } 845906Sgm89044 846906Sgm89044 mutex_enter(&dca->dca_intrlock); 847906Sgm89044 dca->dca_jobtid = timeout(dca_jobtimeout, (void *)dca, 848906Sgm89044 drv_usectohz(SECOND)); 849906Sgm89044 mutex_exit(&dca->dca_intrlock); 850906Sgm89044 851906Sgm89044 ddi_set_driver_private(dip, (caddr_t)dca); 852906Sgm89044 853906Sgm89044 ddi_report_dev(dip); 854906Sgm89044 855906Sgm89044 if (ddi_get_devstate(dca->dca_dip) != DDI_DEVSTATE_UP) { 856906Sgm89044 ddi_fm_service_impact(dca->dca_dip, DDI_SERVICE_RESTORED); 857906Sgm89044 } 858906Sgm89044 859906Sgm89044 return (DDI_SUCCESS); 860906Sgm89044 861906Sgm89044 failed: 862906Sgm89044 /* unregister from the crypto framework */ 863906Sgm89044 if (WORKLIST(dca, MCR1)->dwl_prov != NULL) { 864*5063Sgm89044 (void) crypto_unregister_provider( 865*5063Sgm89044 WORKLIST(dca, MCR1)->dwl_prov); 866906Sgm89044 } 867906Sgm89044 if (WORKLIST(dca, MCR2)->dwl_prov != NULL) { 868*5063Sgm89044 (void) crypto_unregister_provider( 869*5063Sgm89044 WORKLIST(dca, MCR2)->dwl_prov); 870906Sgm89044 } 871906Sgm89044 if (intr_added) { 872906Sgm89044 CLRBIT(dca, CSR_DMACTL, 873906Sgm89044 DMACTL_MCR1IE | DMACTL_MCR2IE | DMACTL_EIE); 874906Sgm89044 /* unregister intr handler */ 875906Sgm89044 ddi_remove_intr(dip, 0, dca->dca_icookie); 876906Sgm89044 } 877906Sgm89044 if (dca->dca_regs_handle) { 878906Sgm89044 ddi_regs_map_free(&dca->dca_regs_handle); 879906Sgm89044 } 880906Sgm89044 if (dca->dca_intrstats) { 881906Sgm89044 kstat_delete(dca->dca_intrstats); 882906Sgm89044 } 883906Sgm89044 if (dca->dca_ksp) { 884906Sgm89044 kstat_delete(dca->dca_ksp); 885906Sgm89044 } 886906Sgm89044 dca_uninit(dca); 887906Sgm89044 888906Sgm89044 /* finalize FMA */ 889906Sgm89044 dca_fma_fini(dca); 890906Sgm89044 891906Sgm89044 mutex_destroy(&dca->dca_intrlock); 892906Sgm89044 ddi_soft_state_free(dca_state, instance); 893906Sgm89044 return (DDI_FAILURE); 894906Sgm89044 895906Sgm89044 } 896906Sgm89044 897906Sgm89044 int 898906Sgm89044 dca_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 899906Sgm89044 { 900906Sgm89044 int instance; 901906Sgm89044 dca_t *dca; 902906Sgm89044 timeout_id_t tid; 903906Sgm89044 904906Sgm89044 instance = ddi_get_instance(dip); 905906Sgm89044 906906Sgm89044 DBG(NULL, DMOD, "dca: in dca_detach() for %d", instance); 907906Sgm89044 908906Sgm89044 switch (cmd) { 909906Sgm89044 case DDI_SUSPEND: 910906Sgm89044 if ((dca = (dca_t *)ddi_get_driver_private(dip)) == NULL) { 911906Sgm89044 dca_diperror(dip, "no soft state in detach"); 912906Sgm89044 return (DDI_FAILURE); 913906Sgm89044 } 914906Sgm89044 /* assumption: we won't be DDI_DETACHed until we return */ 915906Sgm89044 return (dca_suspend(dca)); 916906Sgm89044 917906Sgm89044 case DDI_DETACH: 918906Sgm89044 break; 919906Sgm89044 default: 920906Sgm89044 return (DDI_FAILURE); 921906Sgm89044 } 922906Sgm89044 923906Sgm89044 if ((dca = (dca_t *)ddi_get_driver_private(dip)) == NULL) { 924906Sgm89044 dca_diperror(dip, "no soft state in detach"); 925906Sgm89044 return (DDI_FAILURE); 926906Sgm89044 } 927906Sgm89044 928906Sgm89044 /* 929906Sgm89044 * Unregister from kCF. 930906Sgm89044 * This needs to be done at the beginning of detach. 931906Sgm89044 */ 932906Sgm89044 if (WORKLIST(dca, MCR1)->dwl_prov != NULL) { 933*5063Sgm89044 if (crypto_unregister_provider( 934*5063Sgm89044 WORKLIST(dca, MCR1)->dwl_prov) != CRYPTO_SUCCESS) { 935*5063Sgm89044 dca_error(dca, "unable to unregister MCR1 from kcf"); 936*5063Sgm89044 return (DDI_FAILURE); 937*5063Sgm89044 } 938906Sgm89044 } 939906Sgm89044 940906Sgm89044 if (WORKLIST(dca, MCR2)->dwl_prov != NULL) { 941*5063Sgm89044 if (crypto_unregister_provider( 942*5063Sgm89044 WORKLIST(dca, MCR2)->dwl_prov) != CRYPTO_SUCCESS) { 943*5063Sgm89044 dca_error(dca, "unable to unregister MCR2 from kcf"); 944*5063Sgm89044 return (DDI_FAILURE); 945*5063Sgm89044 } 946906Sgm89044 } 947906Sgm89044 948906Sgm89044 /* 949906Sgm89044 * Cleanup the private context list. Once the 950906Sgm89044 * crypto_unregister_provider returns, it is safe to do so. 951906Sgm89044 */ 952906Sgm89044 dca_free_context_list(dca); 953906Sgm89044 954906Sgm89044 /* Cleanup the local random number pool */ 955906Sgm89044 dca_random_fini(dca); 956906Sgm89044 957906Sgm89044 /* send any jobs in the waitq back to kCF */ 958906Sgm89044 dca_rejectjobs(dca); 959906Sgm89044 960906Sgm89044 /* untimeout the timeouts */ 961906Sgm89044 mutex_enter(&dca->dca_intrlock); 962906Sgm89044 tid = dca->dca_jobtid; 963906Sgm89044 dca->dca_jobtid = 0; 964906Sgm89044 mutex_exit(&dca->dca_intrlock); 965906Sgm89044 if (tid) { 966906Sgm89044 (void) untimeout(tid); 967906Sgm89044 } 968906Sgm89044 969906Sgm89044 /* disable device interrupts */ 970906Sgm89044 CLRBIT(dca, CSR_DMACTL, DMACTL_MCR1IE | DMACTL_MCR2IE | DMACTL_EIE); 971906Sgm89044 972906Sgm89044 /* unregister interrupt handlers */ 973906Sgm89044 ddi_remove_intr(dip, 0, dca->dca_icookie); 974906Sgm89044 975906Sgm89044 /* release our regs handle */ 976906Sgm89044 ddi_regs_map_free(&dca->dca_regs_handle); 977906Sgm89044 978906Sgm89044 /* toss out kstats */ 979906Sgm89044 if (dca->dca_intrstats) { 980906Sgm89044 kstat_delete(dca->dca_intrstats); 981906Sgm89044 } 982906Sgm89044 if (dca->dca_ksp) { 983906Sgm89044 kstat_delete(dca->dca_ksp); 984906Sgm89044 } 985906Sgm89044 986906Sgm89044 mutex_destroy(&dca->dca_intrlock); 987906Sgm89044 dca_uninit(dca); 988906Sgm89044 989906Sgm89044 /* finalize FMA */ 990906Sgm89044 dca_fma_fini(dca); 991906Sgm89044 992906Sgm89044 ddi_soft_state_free(dca_state, instance); 993906Sgm89044 994906Sgm89044 return (DDI_SUCCESS); 995906Sgm89044 } 996906Sgm89044 997906Sgm89044 int 998906Sgm89044 dca_resume(dca_t *dca) 999906Sgm89044 { 1000906Sgm89044 ddi_acc_handle_t pci; 1001906Sgm89044 1002906Sgm89044 if (pci_config_setup(dca->dca_dip, &pci) != DDI_SUCCESS) { 1003906Sgm89044 dca_error(dca, "unable to setup PCI config handle"); 1004906Sgm89044 return (DDI_FAILURE); 1005906Sgm89044 } 1006906Sgm89044 1007906Sgm89044 /* 1008906Sgm89044 * Reprogram registers in PCI configuration space. 1009906Sgm89044 */ 1010906Sgm89044 1011906Sgm89044 /* Broadcom-specific timers -- we disable them. */ 1012906Sgm89044 pci_config_put8(pci, PCI_TRDYTO, 0); 1013906Sgm89044 pci_config_put8(pci, PCI_RETRIES, 0); 1014906Sgm89044 1015906Sgm89044 /* initialize PCI access settings */ 1016906Sgm89044 pci_config_put16(pci, PCI_COMM, PCICOMM_SEE | 1017906Sgm89044 PCICOMM_PEE | PCICOMM_BME | PCICOMM_MAE); 1018906Sgm89044 1019906Sgm89044 /* set up our PCI latency timer */ 1020906Sgm89044 pci_config_put8(pci, PCI_LATTMR, 0x40); 1021906Sgm89044 1022906Sgm89044 pci_config_teardown(&pci); 1023906Sgm89044 1024906Sgm89044 if (dca_reset(dca, 0) < 0) { 1025906Sgm89044 dca_error(dca, "unable to reset device during resume"); 1026906Sgm89044 return (DDI_FAILURE); 1027906Sgm89044 } 1028906Sgm89044 1029906Sgm89044 /* 1030906Sgm89044 * Now restore the card-specific CSRs. 1031906Sgm89044 */ 1032906Sgm89044 1033906Sgm89044 /* restore endianness settings */ 1034906Sgm89044 PUTCSR(dca, CSR_DMACTL, DMACTL_BE32 | DMACTL_BE64); 1035906Sgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle, 1036906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) 1037906Sgm89044 return (DDI_FAILURE); 1038906Sgm89044 1039906Sgm89044 /* restore interrupt enables */ 10403124Sqs148142 if (dca->dca_devid == 0x5825) { 10413124Sqs148142 /* for 5825 set 256 byte read size to improve performance */ 10423124Sqs148142 SETBIT(dca, CSR_DMACTL, 10433124Sqs148142 DMACTL_MCR1IE | DMACTL_MCR2IE | DMACTL_EIE | DMACTL_RD256); 10443124Sqs148142 } else { 10453124Sqs148142 SETBIT(dca, CSR_DMACTL, 10463124Sqs148142 DMACTL_MCR1IE | DMACTL_MCR2IE | DMACTL_EIE); 10473124Sqs148142 } 1048906Sgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle, 1049906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) 1050906Sgm89044 return (DDI_FAILURE); 1051906Sgm89044 1052906Sgm89044 /* resume scheduling jobs on the device */ 1053906Sgm89044 dca_undrain(dca); 1054906Sgm89044 1055906Sgm89044 return (DDI_SUCCESS); 1056906Sgm89044 } 1057906Sgm89044 1058906Sgm89044 int 1059906Sgm89044 dca_suspend(dca_t *dca) 1060906Sgm89044 { 1061906Sgm89044 if ((dca_drain(dca)) != 0) { 1062906Sgm89044 return (DDI_FAILURE); 1063906Sgm89044 } 1064906Sgm89044 if (dca_reset(dca, 0) < 0) { 1065906Sgm89044 dca_error(dca, "unable to reset device during suspend"); 1066906Sgm89044 return (DDI_FAILURE); 1067906Sgm89044 } 1068906Sgm89044 return (DDI_SUCCESS); 1069906Sgm89044 } 1070906Sgm89044 1071906Sgm89044 /* 1072906Sgm89044 * Hardware access stuff. 1073906Sgm89044 */ 1074906Sgm89044 int 1075906Sgm89044 dca_reset(dca_t *dca, int failreset) 1076906Sgm89044 { 1077906Sgm89044 int i; 1078906Sgm89044 1079906Sgm89044 if (dca->dca_regs_handle == NULL) { 1080906Sgm89044 return (-1); 1081906Sgm89044 } 1082906Sgm89044 1083906Sgm89044 PUTCSR(dca, CSR_DMACTL, DMACTL_RESET); 1084906Sgm89044 if (!failreset) { 1085906Sgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle, 1086906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) 1087906Sgm89044 return (-1); 1088906Sgm89044 } 1089906Sgm89044 1090906Sgm89044 /* now wait for a reset */ 1091906Sgm89044 for (i = 1; i < 100; i++) { 1092906Sgm89044 uint32_t dmactl; 1093906Sgm89044 drv_usecwait(100); 1094906Sgm89044 dmactl = GETCSR(dca, CSR_DMACTL); 1095906Sgm89044 if (!failreset) { 1096906Sgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle, 1097906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) 1098906Sgm89044 return (-1); 1099906Sgm89044 } 1100906Sgm89044 if ((dmactl & DMACTL_RESET) == 0) { 1101906Sgm89044 DBG(dca, DCHATTY, "reset in %d usec", i * 100); 1102906Sgm89044 return (0); 1103906Sgm89044 } 1104906Sgm89044 } 1105906Sgm89044 if (!failreset) { 1106906Sgm89044 dca_failure(dca, DDI_DEVICE_FAULT, 1107906Sgm89044 DCA_FM_ECLASS_NONE, dca_ena(0), CRYPTO_DEVICE_ERROR, 1108906Sgm89044 "timeout waiting for reset after %d usec", i * 100); 1109906Sgm89044 } 1110906Sgm89044 return (-1); 1111906Sgm89044 } 1112906Sgm89044 1113906Sgm89044 int 1114906Sgm89044 dca_initworklist(dca_t *dca, dca_worklist_t *wlp) 1115906Sgm89044 { 1116906Sgm89044 int i; 1117906Sgm89044 int reqprealloc = wlp->dwl_hiwater + (MAXWORK * MAXREQSPERMCR); 1118906Sgm89044 1119906Sgm89044 /* 1120906Sgm89044 * Set up work queue. 1121906Sgm89044 */ 1122906Sgm89044 mutex_init(&wlp->dwl_lock, NULL, MUTEX_DRIVER, dca->dca_icookie); 1123906Sgm89044 mutex_init(&wlp->dwl_freereqslock, NULL, MUTEX_DRIVER, 1124906Sgm89044 dca->dca_icookie); 11253124Sqs148142 mutex_init(&wlp->dwl_freelock, NULL, MUTEX_DRIVER, dca->dca_icookie); 1126906Sgm89044 cv_init(&wlp->dwl_cv, NULL, CV_DRIVER, NULL); 1127906Sgm89044 1128906Sgm89044 mutex_enter(&wlp->dwl_lock); 1129906Sgm89044 1130906Sgm89044 dca_initq(&wlp->dwl_freereqs); 1131906Sgm89044 dca_initq(&wlp->dwl_waitq); 1132906Sgm89044 dca_initq(&wlp->dwl_freework); 1133906Sgm89044 dca_initq(&wlp->dwl_runq); 1134906Sgm89044 1135906Sgm89044 for (i = 0; i < MAXWORK; i++) { 1136906Sgm89044 dca_work_t *workp; 1137906Sgm89044 1138906Sgm89044 if ((workp = dca_newwork(dca)) == NULL) { 1139906Sgm89044 dca_error(dca, "unable to allocate work"); 1140906Sgm89044 mutex_exit(&wlp->dwl_lock); 1141906Sgm89044 return (DDI_FAILURE); 1142906Sgm89044 } 1143906Sgm89044 workp->dw_wlp = wlp; 1144906Sgm89044 dca_freework(workp); 1145906Sgm89044 } 1146906Sgm89044 mutex_exit(&wlp->dwl_lock); 1147906Sgm89044 1148906Sgm89044 for (i = 0; i < reqprealloc; i++) { 1149906Sgm89044 dca_request_t *reqp; 1150906Sgm89044 1151906Sgm89044 if ((reqp = dca_newreq(dca)) == NULL) { 1152906Sgm89044 dca_error(dca, "unable to allocate request"); 1153906Sgm89044 return (DDI_FAILURE); 1154906Sgm89044 } 1155906Sgm89044 reqp->dr_dca = dca; 1156906Sgm89044 reqp->dr_wlp = wlp; 1157906Sgm89044 dca_freereq(reqp); 1158906Sgm89044 } 1159906Sgm89044 return (DDI_SUCCESS); 1160906Sgm89044 } 1161906Sgm89044 1162906Sgm89044 int 1163906Sgm89044 dca_init(dca_t *dca) 1164906Sgm89044 { 1165906Sgm89044 dca_worklist_t *wlp; 1166906Sgm89044 1167906Sgm89044 /* Initialize the private context list and the corresponding lock. */ 1168906Sgm89044 mutex_init(&dca->dca_ctx_list_lock, NULL, MUTEX_DRIVER, NULL); 1169906Sgm89044 dca_initq(&dca->dca_ctx_list); 1170906Sgm89044 1171906Sgm89044 /* 1172906Sgm89044 * MCR1 algorithms. 1173906Sgm89044 */ 1174906Sgm89044 wlp = WORKLIST(dca, MCR1); 1175906Sgm89044 (void) sprintf(wlp->dwl_name, "dca%d:mcr1", 1176*5063Sgm89044 ddi_get_instance(dca->dca_dip)); 1177906Sgm89044 wlp->dwl_lowater = ddi_getprop(DDI_DEV_T_ANY, 1178906Sgm89044 dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, 1179906Sgm89044 "mcr1_lowater", MCR1LOWATER); 1180906Sgm89044 wlp->dwl_hiwater = ddi_getprop(DDI_DEV_T_ANY, 1181906Sgm89044 dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, 1182906Sgm89044 "mcr1_hiwater", MCR1HIWATER); 1183906Sgm89044 wlp->dwl_reqspermcr = min(ddi_getprop(DDI_DEV_T_ANY, 1184906Sgm89044 dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, 1185906Sgm89044 "mcr1_maxreqs", MCR1MAXREQS), MAXREQSPERMCR); 1186906Sgm89044 wlp->dwl_dca = dca; 1187906Sgm89044 wlp->dwl_mcr = MCR1; 1188906Sgm89044 if (dca_initworklist(dca, wlp) != DDI_SUCCESS) { 1189906Sgm89044 return (DDI_FAILURE); 1190906Sgm89044 } 1191906Sgm89044 1192906Sgm89044 /* 1193906Sgm89044 * MCR2 algorithms. 1194906Sgm89044 */ 1195906Sgm89044 wlp = WORKLIST(dca, MCR2); 1196906Sgm89044 (void) sprintf(wlp->dwl_name, "dca%d:mcr2", 1197*5063Sgm89044 ddi_get_instance(dca->dca_dip)); 1198906Sgm89044 wlp->dwl_lowater = ddi_getprop(DDI_DEV_T_ANY, 1199906Sgm89044 dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, 1200906Sgm89044 "mcr2_lowater", MCR2LOWATER); 1201906Sgm89044 wlp->dwl_hiwater = ddi_getprop(DDI_DEV_T_ANY, 1202906Sgm89044 dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, 1203906Sgm89044 "mcr2_hiwater", MCR2HIWATER); 1204906Sgm89044 wlp->dwl_reqspermcr = min(ddi_getprop(DDI_DEV_T_ANY, 1205906Sgm89044 dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, 1206906Sgm89044 "mcr2_maxreqs", MCR2MAXREQS), MAXREQSPERMCR); 1207906Sgm89044 wlp->dwl_dca = dca; 1208906Sgm89044 wlp->dwl_mcr = MCR2; 1209906Sgm89044 if (dca_initworklist(dca, wlp) != DDI_SUCCESS) { 1210906Sgm89044 return (DDI_FAILURE); 1211906Sgm89044 } 1212906Sgm89044 return (DDI_SUCCESS); 1213906Sgm89044 } 1214906Sgm89044 1215906Sgm89044 /* 1216906Sgm89044 * Uninitialize worklists. This routine should only be called when no 1217906Sgm89044 * active jobs (hence DMA mappings) exist. One way to ensure this is 1218906Sgm89044 * to unregister from kCF before calling this routine. (This is done 1219906Sgm89044 * e.g. in detach(9e).) 1220906Sgm89044 */ 1221906Sgm89044 void 1222906Sgm89044 dca_uninit(dca_t *dca) 1223906Sgm89044 { 1224906Sgm89044 int mcr; 1225906Sgm89044 1226906Sgm89044 mutex_destroy(&dca->dca_ctx_list_lock); 1227906Sgm89044 1228906Sgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) { 1229906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 1230906Sgm89044 dca_work_t *workp; 1231906Sgm89044 dca_request_t *reqp; 1232906Sgm89044 1233906Sgm89044 if (dca->dca_regs_handle == NULL) { 1234906Sgm89044 continue; 1235906Sgm89044 } 1236906Sgm89044 1237906Sgm89044 mutex_enter(&wlp->dwl_lock); 1238906Sgm89044 while ((workp = dca_getwork(dca, mcr)) != NULL) { 1239906Sgm89044 dca_destroywork(workp); 1240906Sgm89044 } 1241906Sgm89044 mutex_exit(&wlp->dwl_lock); 1242906Sgm89044 while ((reqp = dca_getreq(dca, mcr, 0)) != NULL) { 1243906Sgm89044 dca_destroyreq(reqp); 1244906Sgm89044 } 1245906Sgm89044 1246906Sgm89044 mutex_destroy(&wlp->dwl_lock); 1247906Sgm89044 mutex_destroy(&wlp->dwl_freereqslock); 12483124Sqs148142 mutex_destroy(&wlp->dwl_freelock); 1249906Sgm89044 cv_destroy(&wlp->dwl_cv); 1250906Sgm89044 wlp->dwl_prov = NULL; 1251906Sgm89044 } 1252906Sgm89044 } 1253906Sgm89044 1254906Sgm89044 static void 1255906Sgm89044 dca_enlist2(dca_listnode_t *q, dca_listnode_t *node, kmutex_t *lock) 1256906Sgm89044 { 1257906Sgm89044 if (!q || !node) 1258906Sgm89044 return; 1259906Sgm89044 1260906Sgm89044 mutex_enter(lock); 1261906Sgm89044 node->dl_next2 = q; 1262906Sgm89044 node->dl_prev2 = q->dl_prev2; 1263906Sgm89044 node->dl_next2->dl_prev2 = node; 1264906Sgm89044 node->dl_prev2->dl_next2 = node; 1265906Sgm89044 mutex_exit(lock); 1266906Sgm89044 } 1267906Sgm89044 1268906Sgm89044 static void 1269906Sgm89044 dca_rmlist2(dca_listnode_t *node, kmutex_t *lock) 1270906Sgm89044 { 1271906Sgm89044 if (!node) 1272906Sgm89044 return; 1273906Sgm89044 1274906Sgm89044 mutex_enter(lock); 1275906Sgm89044 node->dl_next2->dl_prev2 = node->dl_prev2; 1276906Sgm89044 node->dl_prev2->dl_next2 = node->dl_next2; 1277906Sgm89044 node->dl_next2 = NULL; 1278906Sgm89044 node->dl_prev2 = NULL; 1279906Sgm89044 mutex_exit(lock); 1280906Sgm89044 } 1281906Sgm89044 1282906Sgm89044 static dca_listnode_t * 1283906Sgm89044 dca_delist2(dca_listnode_t *q, kmutex_t *lock) 1284906Sgm89044 { 1285906Sgm89044 dca_listnode_t *node; 1286906Sgm89044 1287906Sgm89044 mutex_enter(lock); 1288906Sgm89044 if ((node = q->dl_next2) == q) { 1289906Sgm89044 mutex_exit(lock); 1290906Sgm89044 return (NULL); 1291906Sgm89044 } 1292906Sgm89044 1293906Sgm89044 node->dl_next2->dl_prev2 = node->dl_prev2; 1294906Sgm89044 node->dl_prev2->dl_next2 = node->dl_next2; 1295906Sgm89044 node->dl_next2 = NULL; 1296906Sgm89044 node->dl_prev2 = NULL; 1297906Sgm89044 mutex_exit(lock); 1298906Sgm89044 1299906Sgm89044 return (node); 1300906Sgm89044 } 1301906Sgm89044 1302906Sgm89044 void 1303906Sgm89044 dca_initq(dca_listnode_t *q) 1304906Sgm89044 { 1305906Sgm89044 q->dl_next = q; 1306906Sgm89044 q->dl_prev = q; 1307906Sgm89044 q->dl_next2 = q; 1308906Sgm89044 q->dl_prev2 = q; 1309906Sgm89044 } 1310906Sgm89044 1311906Sgm89044 void 1312906Sgm89044 dca_enqueue(dca_listnode_t *q, dca_listnode_t *node) 1313906Sgm89044 { 1314906Sgm89044 /* 1315906Sgm89044 * Enqueue submits at the "tail" of the list, i.e. just 1316906Sgm89044 * behind the sentinel. 1317906Sgm89044 */ 1318906Sgm89044 node->dl_next = q; 1319906Sgm89044 node->dl_prev = q->dl_prev; 1320906Sgm89044 node->dl_next->dl_prev = node; 1321906Sgm89044 node->dl_prev->dl_next = node; 1322906Sgm89044 } 1323906Sgm89044 1324906Sgm89044 void 1325906Sgm89044 dca_rmqueue(dca_listnode_t *node) 1326906Sgm89044 { 1327906Sgm89044 node->dl_next->dl_prev = node->dl_prev; 1328906Sgm89044 node->dl_prev->dl_next = node->dl_next; 1329906Sgm89044 node->dl_next = NULL; 1330906Sgm89044 node->dl_prev = NULL; 1331906Sgm89044 } 1332906Sgm89044 1333906Sgm89044 dca_listnode_t * 1334906Sgm89044 dca_dequeue(dca_listnode_t *q) 1335906Sgm89044 { 1336906Sgm89044 dca_listnode_t *node; 1337906Sgm89044 /* 1338906Sgm89044 * Dequeue takes from the "head" of the list, i.e. just after 1339906Sgm89044 * the sentinel. 1340906Sgm89044 */ 1341906Sgm89044 if ((node = q->dl_next) == q) { 1342906Sgm89044 /* queue is empty */ 1343906Sgm89044 return (NULL); 1344906Sgm89044 } 1345906Sgm89044 dca_rmqueue(node); 1346906Sgm89044 return (node); 1347906Sgm89044 } 1348906Sgm89044 1349906Sgm89044 /* this is the opposite of dequeue, it takes things off in LIFO order */ 1350906Sgm89044 dca_listnode_t * 1351906Sgm89044 dca_unqueue(dca_listnode_t *q) 1352906Sgm89044 { 1353906Sgm89044 dca_listnode_t *node; 1354906Sgm89044 /* 1355906Sgm89044 * unqueue takes from the "tail" of the list, i.e. just before 1356906Sgm89044 * the sentinel. 1357906Sgm89044 */ 1358*5063Sgm89044 if ((node = q->dl_prev) == q) { 1359906Sgm89044 /* queue is empty */ 1360906Sgm89044 return (NULL); 1361906Sgm89044 } 1362906Sgm89044 dca_rmqueue(node); 1363906Sgm89044 return (node); 1364906Sgm89044 } 1365906Sgm89044 1366906Sgm89044 dca_listnode_t * 1367906Sgm89044 dca_peekqueue(dca_listnode_t *q) 1368906Sgm89044 { 1369906Sgm89044 dca_listnode_t *node; 1370906Sgm89044 1371906Sgm89044 if ((node = q->dl_next) == q) { 1372906Sgm89044 return (NULL); 1373906Sgm89044 } else { 1374906Sgm89044 return (node); 1375906Sgm89044 } 1376906Sgm89044 } 1377906Sgm89044 1378906Sgm89044 /* 1379906Sgm89044 * Interrupt service routine. 1380906Sgm89044 */ 1381906Sgm89044 uint_t 1382906Sgm89044 dca_intr(char *arg) 1383906Sgm89044 { 1384906Sgm89044 dca_t *dca = (dca_t *)arg; 1385906Sgm89044 uint32_t status; 1386906Sgm89044 1387906Sgm89044 mutex_enter(&dca->dca_intrlock); 1388906Sgm89044 status = GETCSR(dca, CSR_DMASTAT); 1389906Sgm89044 PUTCSR(dca, CSR_DMASTAT, status & DMASTAT_INTERRUPTS); 1390906Sgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle, 1391906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 1392906Sgm89044 mutex_exit(&dca->dca_intrlock); 1393906Sgm89044 return ((uint_t)DDI_FAILURE); 1394906Sgm89044 } 1395906Sgm89044 1396906Sgm89044 DBG(dca, DINTR, "interrupted, status = 0x%x!", status); 1397906Sgm89044 1398906Sgm89044 if ((status & DMASTAT_INTERRUPTS) == 0) { 1399906Sgm89044 /* increment spurious interrupt kstat */ 1400906Sgm89044 if (dca->dca_intrstats) { 1401906Sgm89044 KIOIP(dca)->intrs[KSTAT_INTR_SPURIOUS]++; 1402906Sgm89044 } 1403906Sgm89044 mutex_exit(&dca->dca_intrlock); 1404906Sgm89044 return (DDI_INTR_UNCLAIMED); 1405906Sgm89044 } 1406906Sgm89044 1407906Sgm89044 if (dca->dca_intrstats) { 1408906Sgm89044 KIOIP(dca)->intrs[KSTAT_INTR_HARD]++; 1409906Sgm89044 } 1410906Sgm89044 if (status & DMASTAT_MCR1INT) { 1411906Sgm89044 DBG(dca, DINTR, "MCR1 interrupted"); 1412906Sgm89044 mutex_enter(&(WORKLIST(dca, MCR1)->dwl_lock)); 1413906Sgm89044 dca_schedule(dca, MCR1); 1414906Sgm89044 dca_reclaim(dca, MCR1); 1415906Sgm89044 mutex_exit(&(WORKLIST(dca, MCR1)->dwl_lock)); 1416906Sgm89044 } 1417906Sgm89044 1418906Sgm89044 if (status & DMASTAT_MCR2INT) { 1419906Sgm89044 DBG(dca, DINTR, "MCR2 interrupted"); 1420906Sgm89044 mutex_enter(&(WORKLIST(dca, MCR2)->dwl_lock)); 1421906Sgm89044 dca_schedule(dca, MCR2); 1422906Sgm89044 dca_reclaim(dca, MCR2); 1423906Sgm89044 mutex_exit(&(WORKLIST(dca, MCR2)->dwl_lock)); 1424906Sgm89044 } 1425906Sgm89044 1426906Sgm89044 if (status & DMASTAT_ERRINT) { 1427906Sgm89044 uint32_t erraddr; 1428906Sgm89044 erraddr = GETCSR(dca, CSR_DMAEA); 1429906Sgm89044 mutex_exit(&dca->dca_intrlock); 1430906Sgm89044 1431906Sgm89044 /* 1432906Sgm89044 * bit 1 of the error address indicates failure during 1433906Sgm89044 * read if set, during write otherwise. 1434906Sgm89044 */ 1435906Sgm89044 dca_failure(dca, DDI_DEVICE_FAULT, 1436906Sgm89044 DCA_FM_ECLASS_HW_DEVICE, dca_ena(0), CRYPTO_DEVICE_ERROR, 1437906Sgm89044 "DMA master access error %s address 0x%x", 1438906Sgm89044 erraddr & 0x1 ? "reading" : "writing", erraddr & ~1); 1439906Sgm89044 return (DDI_INTR_CLAIMED); 1440906Sgm89044 } 1441906Sgm89044 1442906Sgm89044 mutex_exit(&dca->dca_intrlock); 1443906Sgm89044 1444906Sgm89044 return (DDI_INTR_CLAIMED); 1445906Sgm89044 } 1446906Sgm89044 1447906Sgm89044 /* 1448906Sgm89044 * Reverse a string of bytes from s1 into s2. The reversal happens 1449906Sgm89044 * from the tail of s1. If len1 < len2, then null bytes will be 1450906Sgm89044 * padded to the end of s2. If len2 < len1, then (presumably null) 1451906Sgm89044 * bytes will be dropped from the start of s1. 1452906Sgm89044 * 1453906Sgm89044 * The rationale here is that when s1 (source) is shorter, then we 1454906Sgm89044 * are reversing from big-endian ordering, into device ordering, and 1455906Sgm89044 * want to add some extra nulls to the tail (MSB) side of the device. 1456906Sgm89044 * 1457906Sgm89044 * Similarly, when s2 (dest) is shorter, then we are truncating what 1458906Sgm89044 * are presumably null MSB bits from the device. 1459906Sgm89044 * 1460906Sgm89044 * There is an expectation when reversing from the device back into 1461906Sgm89044 * big-endian, that the number of bytes to reverse and the target size 1462906Sgm89044 * will match, and no truncation or padding occurs. 1463906Sgm89044 */ 1464906Sgm89044 void 1465906Sgm89044 dca_reverse(void *s1, void *s2, int len1, int len2) 1466906Sgm89044 { 1467906Sgm89044 caddr_t src, dst; 1468906Sgm89044 1469906Sgm89044 if (len1 == 0) { 1470906Sgm89044 if (len2) { 1471906Sgm89044 bzero(s2, len2); 1472906Sgm89044 } 1473906Sgm89044 return; 1474906Sgm89044 } 1475906Sgm89044 src = (caddr_t)s1 + len1 - 1; 1476906Sgm89044 dst = s2; 1477906Sgm89044 while ((src >= (caddr_t)s1) && (len2)) { 1478906Sgm89044 *dst++ = *src--; 1479906Sgm89044 len2--; 1480906Sgm89044 } 1481906Sgm89044 while (len2 > 0) { 1482906Sgm89044 *dst++ = 0; 1483906Sgm89044 len2--; 1484906Sgm89044 } 1485906Sgm89044 } 1486906Sgm89044 1487906Sgm89044 uint16_t 1488906Sgm89044 dca_padfull(int num) 1489906Sgm89044 { 1490906Sgm89044 if (num <= 512) { 1491906Sgm89044 return (BITS2BYTES(512)); 1492906Sgm89044 } 1493906Sgm89044 if (num <= 768) { 1494906Sgm89044 return (BITS2BYTES(768)); 1495906Sgm89044 } 1496906Sgm89044 if (num <= 1024) { 1497906Sgm89044 return (BITS2BYTES(1024)); 1498906Sgm89044 } 1499906Sgm89044 if (num <= 1536) { 1500906Sgm89044 return (BITS2BYTES(1536)); 1501906Sgm89044 } 1502906Sgm89044 if (num <= 2048) { 1503906Sgm89044 return (BITS2BYTES(2048)); 1504906Sgm89044 } 1505906Sgm89044 return (0); 1506906Sgm89044 } 1507906Sgm89044 1508906Sgm89044 uint16_t 1509906Sgm89044 dca_padhalf(int num) 1510906Sgm89044 { 1511906Sgm89044 if (num <= 256) { 1512906Sgm89044 return (BITS2BYTES(256)); 1513906Sgm89044 } 1514906Sgm89044 if (num <= 384) { 1515906Sgm89044 return (BITS2BYTES(384)); 1516906Sgm89044 } 1517906Sgm89044 if (num <= 512) { 1518906Sgm89044 return (BITS2BYTES(512)); 1519906Sgm89044 } 1520906Sgm89044 if (num <= 768) { 1521906Sgm89044 return (BITS2BYTES(768)); 1522906Sgm89044 } 1523906Sgm89044 if (num <= 1024) { 1524906Sgm89044 return (BITS2BYTES(1024)); 1525906Sgm89044 } 1526906Sgm89044 return (0); 1527906Sgm89044 } 1528906Sgm89044 1529906Sgm89044 dca_work_t * 1530906Sgm89044 dca_newwork(dca_t *dca) 1531906Sgm89044 { 1532906Sgm89044 dca_work_t *workp; 1533906Sgm89044 size_t size; 1534906Sgm89044 ddi_dma_cookie_t c; 1535906Sgm89044 unsigned nc; 1536906Sgm89044 int rv; 1537906Sgm89044 1538906Sgm89044 workp = kmem_zalloc(sizeof (dca_work_t), KM_SLEEP); 1539906Sgm89044 1540906Sgm89044 rv = ddi_dma_alloc_handle(dca->dca_dip, &dca_dmaattr, 1541906Sgm89044 DDI_DMA_SLEEP, NULL, &workp->dw_mcr_dmah); 1542906Sgm89044 if (rv != 0) { 1543906Sgm89044 dca_error(dca, "unable to alloc MCR DMA handle"); 1544906Sgm89044 dca_destroywork(workp); 1545906Sgm89044 return (NULL); 1546906Sgm89044 } 1547906Sgm89044 1548906Sgm89044 rv = ddi_dma_mem_alloc(workp->dw_mcr_dmah, 1549906Sgm89044 ROUNDUP(MCR_SIZE, dca->dca_pagesize), 1550906Sgm89044 &dca_devattr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 1551906Sgm89044 &workp->dw_mcr_kaddr, &size, &workp->dw_mcr_acch); 1552906Sgm89044 if (rv != 0) { 1553906Sgm89044 dca_error(dca, "unable to alloc MCR DMA memory"); 1554906Sgm89044 dca_destroywork(workp); 1555906Sgm89044 return (NULL); 1556906Sgm89044 } 1557906Sgm89044 1558906Sgm89044 rv = ddi_dma_addr_bind_handle(workp->dw_mcr_dmah, NULL, 1559906Sgm89044 workp->dw_mcr_kaddr, size, DDI_DMA_CONSISTENT | DDI_DMA_RDWR, 1560906Sgm89044 DDI_DMA_SLEEP, NULL, &c, &nc); 1561906Sgm89044 if (rv != DDI_DMA_MAPPED) { 1562906Sgm89044 dca_error(dca, "unable to map MCR DMA memory"); 1563906Sgm89044 dca_destroywork(workp); 1564906Sgm89044 return (NULL); 1565906Sgm89044 } 1566906Sgm89044 1567906Sgm89044 workp->dw_mcr_paddr = c.dmac_address; 1568906Sgm89044 return (workp); 1569906Sgm89044 } 1570906Sgm89044 1571906Sgm89044 void 1572906Sgm89044 dca_destroywork(dca_work_t *workp) 1573906Sgm89044 { 1574906Sgm89044 if (workp->dw_mcr_paddr) { 1575906Sgm89044 (void) ddi_dma_unbind_handle(workp->dw_mcr_dmah); 1576906Sgm89044 } 1577906Sgm89044 if (workp->dw_mcr_acch) { 1578906Sgm89044 ddi_dma_mem_free(&workp->dw_mcr_acch); 1579906Sgm89044 } 1580906Sgm89044 if (workp->dw_mcr_dmah) { 1581906Sgm89044 ddi_dma_free_handle(&workp->dw_mcr_dmah); 1582906Sgm89044 } 1583906Sgm89044 kmem_free(workp, sizeof (dca_work_t)); 1584906Sgm89044 } 1585906Sgm89044 1586906Sgm89044 dca_request_t * 1587906Sgm89044 dca_newreq(dca_t *dca) 1588906Sgm89044 { 1589906Sgm89044 dca_request_t *reqp; 1590906Sgm89044 size_t size; 1591906Sgm89044 ddi_dma_cookie_t c; 1592906Sgm89044 unsigned nc; 1593906Sgm89044 int rv; 1594906Sgm89044 int n_chain = 0; 1595906Sgm89044 1596906Sgm89044 size = (DESC_SIZE * MAXFRAGS) + CTX_MAXLENGTH; 1597906Sgm89044 1598906Sgm89044 reqp = kmem_zalloc(sizeof (dca_request_t), KM_SLEEP); 1599906Sgm89044 1600906Sgm89044 reqp->dr_dca = dca; 1601906Sgm89044 1602906Sgm89044 /* 1603906Sgm89044 * Setup the DMA region for the context and descriptors. 1604906Sgm89044 */ 1605906Sgm89044 rv = ddi_dma_alloc_handle(dca->dca_dip, &dca_dmaattr, DDI_DMA_SLEEP, 1606906Sgm89044 NULL, &reqp->dr_ctx_dmah); 1607906Sgm89044 if (rv != DDI_SUCCESS) { 1608906Sgm89044 dca_error(dca, "failure allocating request DMA handle"); 1609906Sgm89044 dca_destroyreq(reqp); 1610906Sgm89044 return (NULL); 1611906Sgm89044 } 1612906Sgm89044 1613906Sgm89044 /* for driver hardening, allocate in whole pages */ 1614906Sgm89044 rv = ddi_dma_mem_alloc(reqp->dr_ctx_dmah, 1615906Sgm89044 ROUNDUP(size, dca->dca_pagesize), &dca_devattr, DDI_DMA_CONSISTENT, 1616906Sgm89044 DDI_DMA_SLEEP, NULL, &reqp->dr_ctx_kaddr, &size, 1617906Sgm89044 &reqp->dr_ctx_acch); 1618906Sgm89044 if (rv != DDI_SUCCESS) { 1619906Sgm89044 dca_error(dca, "unable to alloc request DMA memory"); 1620906Sgm89044 dca_destroyreq(reqp); 1621906Sgm89044 return (NULL); 1622906Sgm89044 } 1623906Sgm89044 1624906Sgm89044 rv = ddi_dma_addr_bind_handle(reqp->dr_ctx_dmah, NULL, 1625906Sgm89044 reqp->dr_ctx_kaddr, size, DDI_DMA_CONSISTENT | DDI_DMA_WRITE, 1626906Sgm89044 DDI_DMA_SLEEP, 0, &c, &nc); 1627906Sgm89044 if (rv != DDI_DMA_MAPPED) { 1628906Sgm89044 dca_error(dca, "failed binding request DMA handle"); 1629906Sgm89044 dca_destroyreq(reqp); 1630906Sgm89044 return (NULL); 1631906Sgm89044 } 1632906Sgm89044 reqp->dr_ctx_paddr = c.dmac_address; 1633906Sgm89044 1634906Sgm89044 reqp->dr_dma_size = size; 1635906Sgm89044 1636906Sgm89044 /* 1637906Sgm89044 * Set up the dma for our scratch/shared buffers. 1638906Sgm89044 */ 1639906Sgm89044 rv = ddi_dma_alloc_handle(dca->dca_dip, &dca_dmaattr, 1640906Sgm89044 DDI_DMA_SLEEP, NULL, &reqp->dr_ibuf_dmah); 1641906Sgm89044 if (rv != DDI_SUCCESS) { 1642906Sgm89044 dca_error(dca, "failure allocating ibuf DMA handle"); 1643906Sgm89044 dca_destroyreq(reqp); 1644906Sgm89044 return (NULL); 1645906Sgm89044 } 1646906Sgm89044 rv = ddi_dma_alloc_handle(dca->dca_dip, &dca_dmaattr, 1647906Sgm89044 DDI_DMA_SLEEP, NULL, &reqp->dr_obuf_dmah); 1648906Sgm89044 if (rv != DDI_SUCCESS) { 1649906Sgm89044 dca_error(dca, "failure allocating obuf DMA handle"); 1650906Sgm89044 dca_destroyreq(reqp); 1651906Sgm89044 return (NULL); 1652906Sgm89044 } 1653906Sgm89044 1654906Sgm89044 rv = ddi_dma_alloc_handle(dca->dca_dip, &dca_dmaattr, 1655906Sgm89044 DDI_DMA_SLEEP, NULL, &reqp->dr_chain_in_dmah); 1656906Sgm89044 if (rv != DDI_SUCCESS) { 1657906Sgm89044 dca_error(dca, "failure allocating chain_in DMA handle"); 1658906Sgm89044 dca_destroyreq(reqp); 1659906Sgm89044 return (NULL); 1660906Sgm89044 } 1661906Sgm89044 1662906Sgm89044 rv = ddi_dma_alloc_handle(dca->dca_dip, &dca_dmaattr, 1663906Sgm89044 DDI_DMA_SLEEP, NULL, &reqp->dr_chain_out_dmah); 1664906Sgm89044 if (rv != DDI_SUCCESS) { 1665906Sgm89044 dca_error(dca, "failure allocating chain_out DMA handle"); 1666906Sgm89044 dca_destroyreq(reqp); 1667906Sgm89044 return (NULL); 1668906Sgm89044 } 1669906Sgm89044 1670906Sgm89044 /* 1671906Sgm89044 * for driver hardening, allocate in whole pages. 1672906Sgm89044 */ 1673906Sgm89044 size = ROUNDUP(MAXPACKET, dca->dca_pagesize); 1674906Sgm89044 #if defined(i386) || defined(__i386) 1675906Sgm89044 /* 1676906Sgm89044 * Use kmem_alloc instead of ddi_dma_mem_alloc here since the latter 1677906Sgm89044 * may fail on x86 platform if a physically contigous memory chunk 1678906Sgm89044 * cannot be found. From initial testing, we did not see performance 1679906Sgm89044 * degration as seen on Sparc. 1680906Sgm89044 */ 1681906Sgm89044 if ((reqp->dr_ibuf_kaddr = kmem_alloc(size, KM_SLEEP)) == NULL) { 1682906Sgm89044 dca_error(dca, "unable to alloc request ibuf memory"); 1683906Sgm89044 dca_destroyreq(reqp); 1684906Sgm89044 return (NULL); 1685906Sgm89044 } 1686906Sgm89044 if ((reqp->dr_obuf_kaddr = kmem_alloc(size, KM_SLEEP)) == NULL) { 1687906Sgm89044 dca_error(dca, "unable to alloc request obuf memory"); 1688906Sgm89044 dca_destroyreq(reqp); 1689906Sgm89044 return (NULL); 1690906Sgm89044 } 1691906Sgm89044 #else 1692906Sgm89044 /* 1693906Sgm89044 * We could kmem_alloc for sparc too. However, it gives worse 1694906Sgm89044 * performance when transfering more than one page data. For example, 1695906Sgm89044 * using 4 threads and 12032 byte data and 3DES on 900MHZ sparc system, 1696906Sgm89044 * kmem_alloc uses 80% CPU and ddi_dma_mem_alloc uses 50% CPU for 1697906Sgm89044 * the same throughput. 1698906Sgm89044 */ 1699906Sgm89044 rv = ddi_dma_mem_alloc(reqp->dr_ibuf_dmah, 1700906Sgm89044 size, &dca_bufattr, 1701906Sgm89044 DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &reqp->dr_ibuf_kaddr, 1702906Sgm89044 &size, &reqp->dr_ibuf_acch); 1703906Sgm89044 if (rv != DDI_SUCCESS) { 1704906Sgm89044 dca_error(dca, "unable to alloc request DMA memory"); 1705906Sgm89044 dca_destroyreq(reqp); 1706906Sgm89044 return (NULL); 1707906Sgm89044 } 1708906Sgm89044 1709906Sgm89044 rv = ddi_dma_mem_alloc(reqp->dr_obuf_dmah, 1710906Sgm89044 size, &dca_bufattr, 1711906Sgm89044 DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &reqp->dr_obuf_kaddr, 1712906Sgm89044 &size, &reqp->dr_obuf_acch); 1713906Sgm89044 if (rv != DDI_SUCCESS) { 1714906Sgm89044 dca_error(dca, "unable to alloc request DMA memory"); 1715906Sgm89044 dca_destroyreq(reqp); 1716906Sgm89044 return (NULL); 1717906Sgm89044 } 1718906Sgm89044 #endif 1719906Sgm89044 1720906Sgm89044 /* Skip the used portion in the context page */ 1721906Sgm89044 reqp->dr_offset = CTX_MAXLENGTH; 1722906Sgm89044 if ((rv = dca_bindchains_one(reqp, size, reqp->dr_offset, 1723906Sgm89044 reqp->dr_ibuf_kaddr, reqp->dr_ibuf_dmah, 1724906Sgm89044 DDI_DMA_WRITE | DDI_DMA_STREAMING, 1725906Sgm89044 &reqp->dr_ibuf_head, &n_chain)) != DDI_SUCCESS) { 1726906Sgm89044 (void) dca_destroyreq(reqp); 1727906Sgm89044 return (NULL); 1728906Sgm89044 } 1729906Sgm89044 reqp->dr_ibuf_paddr = reqp->dr_ibuf_head.dc_buffer_paddr; 1730906Sgm89044 /* Skip the space used by the input buffer */ 1731906Sgm89044 reqp->dr_offset += DESC_SIZE * n_chain; 1732906Sgm89044 1733906Sgm89044 if ((rv = dca_bindchains_one(reqp, size, reqp->dr_offset, 1734906Sgm89044 reqp->dr_obuf_kaddr, reqp->dr_obuf_dmah, 1735906Sgm89044 DDI_DMA_READ | DDI_DMA_STREAMING, 1736906Sgm89044 &reqp->dr_obuf_head, &n_chain)) != DDI_SUCCESS) { 1737906Sgm89044 (void) dca_destroyreq(reqp); 1738906Sgm89044 return (NULL); 1739906Sgm89044 } 1740906Sgm89044 reqp->dr_obuf_paddr = reqp->dr_obuf_head.dc_buffer_paddr; 1741906Sgm89044 /* Skip the space used by the output buffer */ 1742906Sgm89044 reqp->dr_offset += DESC_SIZE * n_chain; 1743906Sgm89044 1744906Sgm89044 DBG(dca, DCHATTY, "CTX is 0x%p, phys 0x%x, len %d", 1745906Sgm89044 reqp->dr_ctx_kaddr, reqp->dr_ctx_paddr, CTX_MAXLENGTH); 1746906Sgm89044 return (reqp); 1747906Sgm89044 } 1748906Sgm89044 1749906Sgm89044 void 1750906Sgm89044 dca_destroyreq(dca_request_t *reqp) 1751906Sgm89044 { 1752906Sgm89044 #if defined(i386) || defined(__i386) 1753906Sgm89044 dca_t *dca = reqp->dr_dca; 1754906Sgm89044 size_t size = ROUNDUP(MAXPACKET, dca->dca_pagesize); 1755906Sgm89044 #endif 1756906Sgm89044 1757906Sgm89044 /* 1758906Sgm89044 * Clean up DMA for the context structure. 1759906Sgm89044 */ 1760906Sgm89044 if (reqp->dr_ctx_paddr) { 1761906Sgm89044 (void) ddi_dma_unbind_handle(reqp->dr_ctx_dmah); 1762906Sgm89044 } 1763906Sgm89044 1764906Sgm89044 if (reqp->dr_ctx_acch) { 1765906Sgm89044 ddi_dma_mem_free(&reqp->dr_ctx_acch); 1766906Sgm89044 } 1767906Sgm89044 1768906Sgm89044 if (reqp->dr_ctx_dmah) { 1769906Sgm89044 ddi_dma_free_handle(&reqp->dr_ctx_dmah); 1770906Sgm89044 } 1771906Sgm89044 1772906Sgm89044 /* 1773906Sgm89044 * Clean up DMA for the scratch buffer. 1774906Sgm89044 */ 1775906Sgm89044 #if defined(i386) || defined(__i386) 1776906Sgm89044 if (reqp->dr_ibuf_dmah) { 1777906Sgm89044 (void) ddi_dma_unbind_handle(reqp->dr_ibuf_dmah); 1778906Sgm89044 ddi_dma_free_handle(&reqp->dr_ibuf_dmah); 1779906Sgm89044 } 1780906Sgm89044 if (reqp->dr_obuf_dmah) { 1781906Sgm89044 (void) ddi_dma_unbind_handle(reqp->dr_obuf_dmah); 1782906Sgm89044 ddi_dma_free_handle(&reqp->dr_obuf_dmah); 1783906Sgm89044 } 1784906Sgm89044 1785906Sgm89044 kmem_free(reqp->dr_ibuf_kaddr, size); 1786906Sgm89044 kmem_free(reqp->dr_obuf_kaddr, size); 1787906Sgm89044 #else 1788906Sgm89044 if (reqp->dr_ibuf_paddr) { 1789906Sgm89044 (void) ddi_dma_unbind_handle(reqp->dr_ibuf_dmah); 1790906Sgm89044 } 1791906Sgm89044 if (reqp->dr_obuf_paddr) { 1792906Sgm89044 (void) ddi_dma_unbind_handle(reqp->dr_obuf_dmah); 1793906Sgm89044 } 1794906Sgm89044 1795906Sgm89044 if (reqp->dr_ibuf_acch) { 1796906Sgm89044 ddi_dma_mem_free(&reqp->dr_ibuf_acch); 1797906Sgm89044 } 1798906Sgm89044 if (reqp->dr_obuf_acch) { 1799906Sgm89044 ddi_dma_mem_free(&reqp->dr_obuf_acch); 1800906Sgm89044 } 1801906Sgm89044 1802906Sgm89044 if (reqp->dr_ibuf_dmah) { 1803906Sgm89044 ddi_dma_free_handle(&reqp->dr_ibuf_dmah); 1804906Sgm89044 } 1805906Sgm89044 if (reqp->dr_obuf_dmah) { 1806906Sgm89044 ddi_dma_free_handle(&reqp->dr_obuf_dmah); 1807906Sgm89044 } 1808906Sgm89044 #endif 1809906Sgm89044 /* 1810906Sgm89044 * These two DMA handles should have been unbinded in 1811906Sgm89044 * dca_unbindchains() function 1812906Sgm89044 */ 1813906Sgm89044 if (reqp->dr_chain_in_dmah) { 1814906Sgm89044 ddi_dma_free_handle(&reqp->dr_chain_in_dmah); 1815906Sgm89044 } 1816906Sgm89044 if (reqp->dr_chain_out_dmah) { 1817906Sgm89044 ddi_dma_free_handle(&reqp->dr_chain_out_dmah); 1818906Sgm89044 } 1819906Sgm89044 1820906Sgm89044 kmem_free(reqp, sizeof (dca_request_t)); 1821906Sgm89044 } 1822906Sgm89044 1823906Sgm89044 dca_work_t * 1824906Sgm89044 dca_getwork(dca_t *dca, int mcr) 1825906Sgm89044 { 1826906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 1827906Sgm89044 dca_work_t *workp; 1828906Sgm89044 18293124Sqs148142 mutex_enter(&wlp->dwl_freelock); 1830906Sgm89044 workp = (dca_work_t *)dca_dequeue(&wlp->dwl_freework); 18313124Sqs148142 mutex_exit(&wlp->dwl_freelock); 1832906Sgm89044 if (workp) { 1833906Sgm89044 int nreqs; 1834906Sgm89044 bzero(workp->dw_mcr_kaddr, 8); 1835906Sgm89044 1836906Sgm89044 /* clear out old requests */ 1837906Sgm89044 for (nreqs = 0; nreqs < MAXREQSPERMCR; nreqs++) { 1838906Sgm89044 workp->dw_reqs[nreqs] = NULL; 1839906Sgm89044 } 1840906Sgm89044 } 1841906Sgm89044 return (workp); 1842906Sgm89044 } 1843906Sgm89044 1844906Sgm89044 void 1845906Sgm89044 dca_freework(dca_work_t *workp) 1846906Sgm89044 { 18473124Sqs148142 mutex_enter(&workp->dw_wlp->dwl_freelock); 1848906Sgm89044 dca_enqueue(&workp->dw_wlp->dwl_freework, (dca_listnode_t *)workp); 18493124Sqs148142 mutex_exit(&workp->dw_wlp->dwl_freelock); 1850906Sgm89044 } 1851906Sgm89044 1852906Sgm89044 dca_request_t * 1853906Sgm89044 dca_getreq(dca_t *dca, int mcr, int tryhard) 1854906Sgm89044 { 1855906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 1856906Sgm89044 dca_request_t *reqp; 1857906Sgm89044 1858906Sgm89044 mutex_enter(&wlp->dwl_freereqslock); 1859906Sgm89044 reqp = (dca_request_t *)dca_dequeue(&wlp->dwl_freereqs); 1860906Sgm89044 mutex_exit(&wlp->dwl_freereqslock); 1861906Sgm89044 if (reqp) { 1862906Sgm89044 reqp->dr_flags = 0; 1863906Sgm89044 reqp->dr_callback = NULL; 1864906Sgm89044 } else if (tryhard) { 1865906Sgm89044 /* 1866906Sgm89044 * failed to get a free one, try an allocation, the hard way. 1867906Sgm89044 * XXX: Kstat desired here. 1868906Sgm89044 */ 1869906Sgm89044 if ((reqp = dca_newreq(dca)) != NULL) { 1870906Sgm89044 reqp->dr_wlp = wlp; 1871906Sgm89044 reqp->dr_dca = dca; 1872906Sgm89044 reqp->dr_flags = 0; 1873906Sgm89044 reqp->dr_callback = NULL; 1874906Sgm89044 } 1875906Sgm89044 } 1876906Sgm89044 return (reqp); 1877906Sgm89044 } 1878906Sgm89044 1879906Sgm89044 void 1880906Sgm89044 dca_freereq(dca_request_t *reqp) 1881906Sgm89044 { 1882906Sgm89044 reqp->dr_kcf_req = NULL; 1883906Sgm89044 if (!(reqp->dr_flags & DR_NOCACHE)) { 1884906Sgm89044 mutex_enter(&reqp->dr_wlp->dwl_freereqslock); 1885906Sgm89044 dca_enqueue(&reqp->dr_wlp->dwl_freereqs, 1886906Sgm89044 (dca_listnode_t *)reqp); 1887906Sgm89044 mutex_exit(&reqp->dr_wlp->dwl_freereqslock); 1888906Sgm89044 } 1889906Sgm89044 } 1890906Sgm89044 1891906Sgm89044 /* 1892906Sgm89044 * Binds user buffers to DMA handles dynamically. On Sparc, a user buffer 1893906Sgm89044 * is mapped to a single physicall address. On x86, a user buffer is mapped 1894906Sgm89044 * to multiple physically addresses. These phsyical addresses are chained 1895906Sgm89044 * using the method specified in Broadcom BCM5820 specification 1896906Sgm89044 */ 1897906Sgm89044 int 1898906Sgm89044 dca_bindchains(dca_request_t *reqp, size_t incnt, size_t outcnt) 1899906Sgm89044 { 1900906Sgm89044 int rv; 1901906Sgm89044 caddr_t kaddr; 1902906Sgm89044 uint_t flags; 1903906Sgm89044 int n_chain = 0; 1904906Sgm89044 1905906Sgm89044 if (reqp->dr_flags & DR_INPLACE) { 1906906Sgm89044 flags = DDI_DMA_RDWR | DDI_DMA_CONSISTENT; 1907906Sgm89044 } else { 1908906Sgm89044 flags = DDI_DMA_WRITE | DDI_DMA_STREAMING; 1909906Sgm89044 } 1910906Sgm89044 1911906Sgm89044 /* first the input */ 1912906Sgm89044 if (incnt) { 1913906Sgm89044 if ((kaddr = dca_bufdaddr(reqp->dr_in)) == NULL) { 1914906Sgm89044 DBG(NULL, DWARN, "unrecognised crypto data format"); 1915906Sgm89044 return (DDI_FAILURE); 1916906Sgm89044 } 1917906Sgm89044 if ((rv = dca_bindchains_one(reqp, incnt, reqp->dr_offset, 1918906Sgm89044 kaddr, reqp->dr_chain_in_dmah, flags, 1919906Sgm89044 &reqp->dr_chain_in_head, &n_chain)) != DDI_SUCCESS) { 1920906Sgm89044 (void) dca_unbindchains(reqp); 1921906Sgm89044 return (rv); 1922906Sgm89044 } 1923906Sgm89044 1924906Sgm89044 /* 1925906Sgm89044 * The offset and length are altered by the calling routine 1926906Sgm89044 * reqp->dr_in->cd_offset += incnt; 1927906Sgm89044 * reqp->dr_in->cd_length -= incnt; 1928906Sgm89044 */ 1929906Sgm89044 /* Save the first one in the chain for MCR */ 1930906Sgm89044 reqp->dr_in_paddr = reqp->dr_chain_in_head.dc_buffer_paddr; 1931906Sgm89044 reqp->dr_in_next = reqp->dr_chain_in_head.dc_next_paddr; 1932906Sgm89044 reqp->dr_in_len = reqp->dr_chain_in_head.dc_buffer_length; 1933906Sgm89044 } else { 1934906Sgm89044 reqp->dr_in_paddr = NULL; 1935906Sgm89044 reqp->dr_in_next = 0; 1936906Sgm89044 reqp->dr_in_len = 0; 1937906Sgm89044 } 1938906Sgm89044 1939906Sgm89044 if (reqp->dr_flags & DR_INPLACE) { 1940906Sgm89044 reqp->dr_out_paddr = reqp->dr_in_paddr; 1941906Sgm89044 reqp->dr_out_len = reqp->dr_in_len; 1942906Sgm89044 reqp->dr_out_next = reqp->dr_in_next; 1943906Sgm89044 return (DDI_SUCCESS); 1944906Sgm89044 } 1945906Sgm89044 1946906Sgm89044 /* then the output */ 1947906Sgm89044 if (outcnt) { 1948906Sgm89044 flags = DDI_DMA_READ | DDI_DMA_STREAMING; 1949906Sgm89044 if ((kaddr = dca_bufdaddr_out(reqp->dr_out)) == NULL) { 1950906Sgm89044 DBG(NULL, DWARN, "unrecognised crypto data format"); 1951906Sgm89044 (void) dca_unbindchains(reqp); 1952906Sgm89044 return (DDI_FAILURE); 1953906Sgm89044 } 1954906Sgm89044 rv = dca_bindchains_one(reqp, outcnt, reqp->dr_offset + 1955906Sgm89044 n_chain * DESC_SIZE, kaddr, reqp->dr_chain_out_dmah, 1956906Sgm89044 flags, &reqp->dr_chain_out_head, &n_chain); 1957906Sgm89044 if (rv != DDI_SUCCESS) { 1958906Sgm89044 (void) dca_unbindchains(reqp); 1959906Sgm89044 return (DDI_FAILURE); 1960906Sgm89044 } 1961906Sgm89044 1962906Sgm89044 /* Save the first one in the chain for MCR */ 1963906Sgm89044 reqp->dr_out_paddr = reqp->dr_chain_out_head.dc_buffer_paddr; 1964906Sgm89044 reqp->dr_out_next = reqp->dr_chain_out_head.dc_next_paddr; 1965906Sgm89044 reqp->dr_out_len = reqp->dr_chain_out_head.dc_buffer_length; 1966906Sgm89044 } else { 1967906Sgm89044 reqp->dr_out_paddr = NULL; 1968906Sgm89044 reqp->dr_out_next = 0; 1969906Sgm89044 reqp->dr_out_len = 0; 1970906Sgm89044 } 1971906Sgm89044 1972906Sgm89044 return (DDI_SUCCESS); 1973906Sgm89044 } 1974906Sgm89044 1975906Sgm89044 /* 1976906Sgm89044 * Unbind the user buffers from the DMA handles. 1977906Sgm89044 */ 1978906Sgm89044 int 1979906Sgm89044 dca_unbindchains(dca_request_t *reqp) 1980906Sgm89044 { 1981906Sgm89044 int rv = DDI_SUCCESS; 1982906Sgm89044 int rv1 = DDI_SUCCESS; 1983906Sgm89044 1984906Sgm89044 /* Clear the input chain */ 1985906Sgm89044 if (reqp->dr_chain_in_head.dc_buffer_paddr != NULL) { 1986906Sgm89044 (void) ddi_dma_unbind_handle(reqp->dr_chain_in_dmah); 1987906Sgm89044 reqp->dr_chain_in_head.dc_buffer_paddr = 0; 1988906Sgm89044 } 1989906Sgm89044 1990*5063Sgm89044 if (reqp->dr_flags & DR_INPLACE) { 1991*5063Sgm89044 return (rv); 1992*5063Sgm89044 } 1993*5063Sgm89044 1994906Sgm89044 /* Clear the output chain */ 1995906Sgm89044 if (reqp->dr_chain_out_head.dc_buffer_paddr != NULL) { 1996906Sgm89044 (void) ddi_dma_unbind_handle(reqp->dr_chain_out_dmah); 1997906Sgm89044 reqp->dr_chain_out_head.dc_buffer_paddr = 0; 1998906Sgm89044 } 1999906Sgm89044 2000906Sgm89044 return ((rv != DDI_SUCCESS)? rv : rv1); 2001906Sgm89044 } 2002906Sgm89044 2003906Sgm89044 /* 2004906Sgm89044 * Build either input chain or output chain. It is single-item chain for Sparc, 2005906Sgm89044 * and possible mutiple-item chain for x86. 2006906Sgm89044 */ 2007906Sgm89044 static int 2008906Sgm89044 dca_bindchains_one(dca_request_t *reqp, size_t cnt, int dr_offset, 2009906Sgm89044 caddr_t kaddr, ddi_dma_handle_t handle, uint_t flags, 2010906Sgm89044 dca_chain_t *head, int *n_chain) 2011906Sgm89044 { 2012906Sgm89044 ddi_dma_cookie_t c; 2013906Sgm89044 uint_t nc; 2014906Sgm89044 int rv; 2015906Sgm89044 caddr_t chain_kaddr_pre; 2016906Sgm89044 caddr_t chain_kaddr; 2017906Sgm89044 uint32_t chain_paddr; 2018906Sgm89044 int i; 2019906Sgm89044 2020906Sgm89044 /* Advance past the context structure to the starting address */ 2021906Sgm89044 chain_paddr = reqp->dr_ctx_paddr + dr_offset; 2022906Sgm89044 chain_kaddr = reqp->dr_ctx_kaddr + dr_offset; 2023906Sgm89044 2024906Sgm89044 /* 2025906Sgm89044 * Bind the kernel address to the DMA handle. On x86, the actual 2026906Sgm89044 * buffer is mapped into multiple physical addresses. On Sparc, 2027906Sgm89044 * the actual buffer is mapped into a single address. 2028906Sgm89044 */ 2029906Sgm89044 rv = ddi_dma_addr_bind_handle(handle, 2030906Sgm89044 NULL, kaddr, cnt, flags, DDI_DMA_DONTWAIT, NULL, &c, &nc); 2031906Sgm89044 if (rv != DDI_DMA_MAPPED) { 2032906Sgm89044 return (DDI_FAILURE); 2033906Sgm89044 } 2034906Sgm89044 2035906Sgm89044 (void) ddi_dma_sync(handle, 0, cnt, DDI_DMA_SYNC_FORDEV); 2036906Sgm89044 if ((rv = dca_check_dma_handle(reqp->dr_dca, handle, 2037906Sgm89044 DCA_FM_ECLASS_NONE)) != DDI_SUCCESS) { 2038906Sgm89044 reqp->destroy = TRUE; 2039906Sgm89044 return (rv); 2040906Sgm89044 } 2041906Sgm89044 2042906Sgm89044 *n_chain = nc; 2043906Sgm89044 2044906Sgm89044 /* Setup the data buffer chain for DMA transfer */ 2045906Sgm89044 chain_kaddr_pre = NULL; 2046906Sgm89044 head->dc_buffer_paddr = 0; 2047906Sgm89044 head->dc_next_paddr = 0; 2048906Sgm89044 head->dc_buffer_length = 0; 2049906Sgm89044 for (i = 0; i < nc; i++) { 2050906Sgm89044 /* PIO */ 2051906Sgm89044 PUTDESC32(reqp, chain_kaddr, DESC_BUFADDR, c.dmac_address); 2052906Sgm89044 PUTDESC16(reqp, chain_kaddr, DESC_RSVD, 0); 2053906Sgm89044 PUTDESC16(reqp, chain_kaddr, DESC_LENGTH, c.dmac_size); 2054906Sgm89044 2055906Sgm89044 /* Remember the head of the chain */ 2056906Sgm89044 if (head->dc_buffer_paddr == 0) { 2057906Sgm89044 head->dc_buffer_paddr = c.dmac_address; 2058906Sgm89044 head->dc_buffer_length = c.dmac_size; 2059906Sgm89044 } 2060906Sgm89044 2061906Sgm89044 /* Link to the previous one if one exists */ 2062906Sgm89044 if (chain_kaddr_pre) { 2063906Sgm89044 PUTDESC32(reqp, chain_kaddr_pre, DESC_NEXT, 2064906Sgm89044 chain_paddr); 2065906Sgm89044 if (head->dc_next_paddr == 0) 2066906Sgm89044 head->dc_next_paddr = chain_paddr; 2067906Sgm89044 } 2068906Sgm89044 chain_kaddr_pre = chain_kaddr; 2069906Sgm89044 2070906Sgm89044 /* Maintain pointers */ 2071906Sgm89044 chain_paddr += DESC_SIZE; 2072906Sgm89044 chain_kaddr += DESC_SIZE; 2073906Sgm89044 2074906Sgm89044 /* Retrieve the next cookie if there is one */ 2075906Sgm89044 if (i < nc-1) 2076906Sgm89044 ddi_dma_nextcookie(handle, &c); 2077906Sgm89044 } 2078906Sgm89044 2079906Sgm89044 /* Set the next pointer in the last entry to NULL */ 2080906Sgm89044 PUTDESC32(reqp, chain_kaddr_pre, DESC_NEXT, 0); 2081906Sgm89044 2082906Sgm89044 return (DDI_SUCCESS); 2083906Sgm89044 } 2084906Sgm89044 2085906Sgm89044 /* 2086906Sgm89044 * Schedule some work. 2087906Sgm89044 */ 2088906Sgm89044 int 2089906Sgm89044 dca_start(dca_t *dca, dca_request_t *reqp, int mcr, int dosched) 2090906Sgm89044 { 2091906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 2092906Sgm89044 2093906Sgm89044 mutex_enter(&wlp->dwl_lock); 2094906Sgm89044 2095906Sgm89044 DBG(dca, DCHATTY, "req=%p, in=%p, out=%p, ctx=%p, ibuf=%p, obuf=%p", 2096906Sgm89044 reqp, reqp->dr_in, reqp->dr_out, reqp->dr_ctx_kaddr, 2097906Sgm89044 reqp->dr_ibuf_kaddr, reqp->dr_obuf_kaddr); 2098906Sgm89044 DBG(dca, DCHATTY, "ctx paddr = %x, ibuf paddr = %x, obuf paddr = %x", 2099906Sgm89044 reqp->dr_ctx_paddr, reqp->dr_ibuf_paddr, reqp->dr_obuf_paddr); 2100906Sgm89044 /* sync out the entire context and descriptor chains */ 2101906Sgm89044 (void) ddi_dma_sync(reqp->dr_ctx_dmah, 0, 0, DDI_DMA_SYNC_FORDEV); 2102906Sgm89044 if (dca_check_dma_handle(dca, reqp->dr_ctx_dmah, 2103906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 2104906Sgm89044 reqp->destroy = TRUE; 2105906Sgm89044 mutex_exit(&wlp->dwl_lock); 2106906Sgm89044 return (CRYPTO_DEVICE_ERROR); 2107906Sgm89044 } 2108906Sgm89044 2109906Sgm89044 dca_enqueue(&wlp->dwl_waitq, (dca_listnode_t *)reqp); 2110906Sgm89044 wlp->dwl_count++; 2111906Sgm89044 wlp->dwl_lastsubmit = ddi_get_lbolt(); 2112906Sgm89044 reqp->dr_wlp = wlp; 2113906Sgm89044 2114906Sgm89044 if ((wlp->dwl_count == wlp->dwl_hiwater) && (wlp->dwl_busy == 0)) { 2115906Sgm89044 /* we are fully loaded now, let kCF know */ 2116906Sgm89044 2117906Sgm89044 wlp->dwl_flowctl++; 2118906Sgm89044 wlp->dwl_busy = 1; 2119906Sgm89044 2120906Sgm89044 crypto_prov_notify(wlp->dwl_prov, CRYPTO_PROVIDER_BUSY); 2121906Sgm89044 } 2122906Sgm89044 2123906Sgm89044 if (dosched) { 2124906Sgm89044 #ifdef SCHEDDELAY 2125906Sgm89044 /* possibly wait for more work to arrive */ 2126906Sgm89044 if (wlp->dwl_count >= wlp->dwl_reqspermcr) { 2127906Sgm89044 dca_schedule(dca, mcr); 2128906Sgm89044 } else if (!wlp->dwl_schedtid) { 2129906Sgm89044 /* wait 1 msec for more work before doing it */ 2130906Sgm89044 wlp->dwl_schedtid = timeout(dca_schedtimeout, 2131906Sgm89044 (void *)wlp, drv_usectohz(MSEC)); 2132906Sgm89044 } 2133906Sgm89044 #else 2134906Sgm89044 dca_schedule(dca, mcr); 2135906Sgm89044 #endif 2136906Sgm89044 } 2137906Sgm89044 mutex_exit(&wlp->dwl_lock); 2138906Sgm89044 2139906Sgm89044 return (CRYPTO_QUEUED); 2140906Sgm89044 } 2141906Sgm89044 2142906Sgm89044 void 2143906Sgm89044 dca_schedule(dca_t *dca, int mcr) 2144906Sgm89044 { 2145906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 2146906Sgm89044 int csr; 2147906Sgm89044 int full; 2148906Sgm89044 uint32_t status; 2149906Sgm89044 2150906Sgm89044 ASSERT(mutex_owned(&wlp->dwl_lock)); 2151906Sgm89044 /* 2152906Sgm89044 * If the card is draining or has an outstanding failure, 2153906Sgm89044 * don't schedule any more work on it right now 2154906Sgm89044 */ 2155906Sgm89044 if (wlp->dwl_drain || (dca->dca_flags & DCA_FAILED)) { 2156906Sgm89044 return; 2157906Sgm89044 } 2158906Sgm89044 2159906Sgm89044 if (mcr == MCR2) { 2160906Sgm89044 csr = CSR_MCR2; 2161906Sgm89044 full = DMASTAT_MCR2FULL; 2162906Sgm89044 } else { 2163906Sgm89044 csr = CSR_MCR1; 2164906Sgm89044 full = DMASTAT_MCR1FULL; 2165906Sgm89044 } 2166906Sgm89044 2167906Sgm89044 for (;;) { 2168906Sgm89044 dca_work_t *workp; 2169906Sgm89044 uint32_t offset; 2170906Sgm89044 int nreqs; 2171906Sgm89044 2172906Sgm89044 status = GETCSR(dca, CSR_DMASTAT); 2173906Sgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle, 2174906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) 2175906Sgm89044 return; 2176906Sgm89044 2177906Sgm89044 if ((status & full) != 0) 2178906Sgm89044 break; 2179906Sgm89044 2180906Sgm89044 #ifdef SCHEDDELAY 2181906Sgm89044 /* if there isn't enough to do, don't bother now */ 2182906Sgm89044 if ((wlp->dwl_count < wlp->dwl_reqspermcr) && 2183906Sgm89044 (ddi_get_lbolt() < (wlp->dwl_lastsubmit + 2184*5063Sgm89044 drv_usectohz(MSEC)))) { 2185906Sgm89044 /* wait a bit longer... */ 2186906Sgm89044 if (wlp->dwl_schedtid == 0) { 2187906Sgm89044 wlp->dwl_schedtid = timeout(dca_schedtimeout, 2188906Sgm89044 (void *)wlp, drv_usectohz(MSEC)); 2189906Sgm89044 } 2190906Sgm89044 return; 2191906Sgm89044 } 2192906Sgm89044 #endif 2193906Sgm89044 2194906Sgm89044 /* grab a work structure */ 2195906Sgm89044 workp = dca_getwork(dca, mcr); 2196906Sgm89044 2197906Sgm89044 if (workp == NULL) { 2198906Sgm89044 /* 2199906Sgm89044 * There must be work ready to be reclaimed, 2200906Sgm89044 * in this case, since the chip can only hold 2201906Sgm89044 * less work outstanding than there are total. 2202906Sgm89044 */ 2203906Sgm89044 dca_reclaim(dca, mcr); 2204906Sgm89044 continue; 2205906Sgm89044 } 2206906Sgm89044 2207906Sgm89044 nreqs = 0; 2208906Sgm89044 offset = MCR_CTXADDR; 2209906Sgm89044 2210906Sgm89044 while (nreqs < wlp->dwl_reqspermcr) { 2211906Sgm89044 dca_request_t *reqp; 2212906Sgm89044 2213906Sgm89044 reqp = (dca_request_t *)dca_dequeue(&wlp->dwl_waitq); 2214906Sgm89044 if (reqp == NULL) { 2215906Sgm89044 /* nothing left to process */ 2216906Sgm89044 break; 2217906Sgm89044 } 2218906Sgm89044 /* 2219906Sgm89044 * Update flow control. 2220906Sgm89044 */ 2221906Sgm89044 wlp->dwl_count--; 2222906Sgm89044 if ((wlp->dwl_count == wlp->dwl_lowater) && 2223906Sgm89044 (wlp->dwl_busy)) { 2224906Sgm89044 wlp->dwl_busy = 0; 2225906Sgm89044 crypto_prov_notify(wlp->dwl_prov, 2226906Sgm89044 CRYPTO_PROVIDER_READY); 2227906Sgm89044 } 2228906Sgm89044 2229906Sgm89044 /* 2230906Sgm89044 * Context address. 2231906Sgm89044 */ 2232906Sgm89044 PUTMCR32(workp, offset, reqp->dr_ctx_paddr); 2233906Sgm89044 offset += 4; 2234906Sgm89044 2235906Sgm89044 /* 2236906Sgm89044 * Input chain. 2237906Sgm89044 */ 2238906Sgm89044 /* input buffer address */ 2239906Sgm89044 PUTMCR32(workp, offset, reqp->dr_in_paddr); 2240906Sgm89044 offset += 4; 2241906Sgm89044 /* next input buffer entry */ 2242906Sgm89044 PUTMCR32(workp, offset, reqp->dr_in_next); 2243906Sgm89044 offset += 4; 2244906Sgm89044 /* input buffer length */ 2245906Sgm89044 PUTMCR16(workp, offset, reqp->dr_in_len); 2246906Sgm89044 offset += 2; 2247906Sgm89044 /* zero the reserved field */ 2248906Sgm89044 PUTMCR16(workp, offset, 0); 2249906Sgm89044 offset += 2; 2250906Sgm89044 2251906Sgm89044 /* 2252906Sgm89044 * Overall length. 2253906Sgm89044 */ 2254906Sgm89044 /* reserved field */ 2255906Sgm89044 PUTMCR16(workp, offset, 0); 2256906Sgm89044 offset += 2; 2257906Sgm89044 /* total packet length */ 2258906Sgm89044 PUTMCR16(workp, offset, reqp->dr_pkt_length); 2259906Sgm89044 offset += 2; 2260906Sgm89044 2261906Sgm89044 /* 2262906Sgm89044 * Output chain. 2263906Sgm89044 */ 2264906Sgm89044 /* output buffer address */ 2265906Sgm89044 PUTMCR32(workp, offset, reqp->dr_out_paddr); 2266906Sgm89044 offset += 4; 2267906Sgm89044 /* next output buffer entry */ 2268906Sgm89044 PUTMCR32(workp, offset, reqp->dr_out_next); 2269906Sgm89044 offset += 4; 2270906Sgm89044 /* output buffer length */ 2271906Sgm89044 PUTMCR16(workp, offset, reqp->dr_out_len); 2272906Sgm89044 offset += 2; 2273906Sgm89044 /* zero the reserved field */ 2274906Sgm89044 PUTMCR16(workp, offset, 0); 2275906Sgm89044 offset += 2; 2276906Sgm89044 2277906Sgm89044 /* 2278906Sgm89044 * Note submission. 2279906Sgm89044 */ 2280906Sgm89044 workp->dw_reqs[nreqs] = reqp; 2281906Sgm89044 nreqs++; 2282906Sgm89044 } 2283906Sgm89044 2284906Sgm89044 if (nreqs == 0) { 2285906Sgm89044 /* nothing in the queue! */ 2286906Sgm89044 dca_freework(workp); 2287906Sgm89044 return; 2288906Sgm89044 } 2289906Sgm89044 2290906Sgm89044 wlp->dwl_submit++; 2291906Sgm89044 2292906Sgm89044 PUTMCR16(workp, MCR_FLAGS, 0); 2293906Sgm89044 PUTMCR16(workp, MCR_COUNT, nreqs); 2294906Sgm89044 2295906Sgm89044 DBG(dca, DCHATTY, 2296906Sgm89044 "posting work (phys %x, virt 0x%p) (%d reqs) to MCR%d", 2297906Sgm89044 workp->dw_mcr_paddr, workp->dw_mcr_kaddr, 2298906Sgm89044 nreqs, mcr); 2299906Sgm89044 2300906Sgm89044 workp->dw_lbolt = ddi_get_lbolt(); 2301906Sgm89044 /* Make sure MCR is synced out to device. */ 2302906Sgm89044 (void) ddi_dma_sync(workp->dw_mcr_dmah, 0, 0, 2303*5063Sgm89044 DDI_DMA_SYNC_FORDEV); 2304906Sgm89044 if (dca_check_dma_handle(dca, workp->dw_mcr_dmah, 2305906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 2306906Sgm89044 dca_destroywork(workp); 2307906Sgm89044 return; 2308906Sgm89044 } 2309906Sgm89044 2310906Sgm89044 PUTCSR(dca, csr, workp->dw_mcr_paddr); 2311906Sgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle, 2312906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 2313906Sgm89044 dca_destroywork(workp); 2314906Sgm89044 return; 2315906Sgm89044 } else { 2316906Sgm89044 dca_enqueue(&wlp->dwl_runq, (dca_listnode_t *)workp); 2317906Sgm89044 } 2318906Sgm89044 2319906Sgm89044 DBG(dca, DCHATTY, "posted"); 2320906Sgm89044 } 2321906Sgm89044 } 2322906Sgm89044 2323906Sgm89044 /* 2324906Sgm89044 * Reclaim completed work, called in interrupt context. 2325906Sgm89044 */ 2326906Sgm89044 void 2327906Sgm89044 dca_reclaim(dca_t *dca, int mcr) 2328906Sgm89044 { 2329906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 2330906Sgm89044 dca_work_t *workp; 2331906Sgm89044 ushort_t flags; 2332906Sgm89044 int nreclaimed = 0; 2333906Sgm89044 int i; 2334906Sgm89044 2335906Sgm89044 DBG(dca, DRECLAIM, "worklist = 0x%p (MCR%d)", wlp, mcr); 2336906Sgm89044 ASSERT(mutex_owned(&wlp->dwl_lock)); 2337906Sgm89044 /* 2338906Sgm89044 * For each MCR in the submitted (runq), we check to see if 2339906Sgm89044 * it has been processed. If so, then we note each individual 2340906Sgm89044 * job in the MCR, and and do the completion processing for 2341906Sgm89044 * each of such job. 2342906Sgm89044 */ 2343906Sgm89044 for (;;) { 2344906Sgm89044 2345906Sgm89044 workp = (dca_work_t *)dca_peekqueue(&wlp->dwl_runq); 2346906Sgm89044 if (workp == NULL) { 2347906Sgm89044 break; 2348906Sgm89044 } 2349906Sgm89044 2350906Sgm89044 /* only sync the MCR flags, since that's all we need */ 2351906Sgm89044 (void) ddi_dma_sync(workp->dw_mcr_dmah, 0, 4, 2352*5063Sgm89044 DDI_DMA_SYNC_FORKERNEL); 2353906Sgm89044 if (dca_check_dma_handle(dca, workp->dw_mcr_dmah, 2354906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 2355906Sgm89044 dca_rmqueue((dca_listnode_t *)workp); 2356906Sgm89044 dca_destroywork(workp); 2357906Sgm89044 return; 2358906Sgm89044 } 2359906Sgm89044 2360906Sgm89044 flags = GETMCR16(workp, MCR_FLAGS); 2361906Sgm89044 if ((flags & MCRFLAG_FINISHED) == 0) { 2362906Sgm89044 /* chip is still working on it */ 2363906Sgm89044 DBG(dca, DRECLAIM, 2364906Sgm89044 "chip still working on it (MCR%d)", mcr); 2365906Sgm89044 break; 2366906Sgm89044 } 2367906Sgm89044 2368906Sgm89044 /* its really for us, so remove it from the queue */ 2369906Sgm89044 dca_rmqueue((dca_listnode_t *)workp); 2370906Sgm89044 2371906Sgm89044 /* if we were draining, signal on the cv */ 2372906Sgm89044 if (wlp->dwl_drain && QEMPTY(&wlp->dwl_runq)) { 2373906Sgm89044 cv_signal(&wlp->dwl_cv); 2374906Sgm89044 } 2375906Sgm89044 2376906Sgm89044 /* update statistics, done under the lock */ 2377906Sgm89044 for (i = 0; i < wlp->dwl_reqspermcr; i++) { 2378906Sgm89044 dca_request_t *reqp = workp->dw_reqs[i]; 2379906Sgm89044 if (reqp == NULL) { 2380906Sgm89044 continue; 2381906Sgm89044 } 2382906Sgm89044 if (reqp->dr_byte_stat >= 0) { 2383906Sgm89044 dca->dca_stats[reqp->dr_byte_stat] += 2384906Sgm89044 reqp->dr_pkt_length; 2385906Sgm89044 } 2386906Sgm89044 if (reqp->dr_job_stat >= 0) { 2387906Sgm89044 dca->dca_stats[reqp->dr_job_stat]++; 2388906Sgm89044 } 2389906Sgm89044 } 2390906Sgm89044 mutex_exit(&wlp->dwl_lock); 2391906Sgm89044 2392906Sgm89044 for (i = 0; i < wlp->dwl_reqspermcr; i++) { 2393906Sgm89044 dca_request_t *reqp = workp->dw_reqs[i]; 2394906Sgm89044 2395906Sgm89044 if (reqp == NULL) { 2396906Sgm89044 continue; 2397906Sgm89044 } 2398906Sgm89044 2399906Sgm89044 /* Do the callback. */ 2400906Sgm89044 workp->dw_reqs[i] = NULL; 2401906Sgm89044 dca_done(reqp, CRYPTO_SUCCESS); 2402906Sgm89044 2403906Sgm89044 nreclaimed++; 2404906Sgm89044 } 2405906Sgm89044 2406906Sgm89044 /* now we can release the work */ 2407906Sgm89044 dca_freework(workp); 24083124Sqs148142 24093124Sqs148142 mutex_enter(&wlp->dwl_lock); 2410906Sgm89044 } 2411906Sgm89044 DBG(dca, DRECLAIM, "reclaimed %d cmds", nreclaimed); 2412906Sgm89044 } 2413906Sgm89044 2414906Sgm89044 int 2415906Sgm89044 dca_length(crypto_data_t *cdata) 2416906Sgm89044 { 2417906Sgm89044 return (cdata->cd_length); 2418906Sgm89044 } 2419906Sgm89044 2420906Sgm89044 /* 2421906Sgm89044 * This is the callback function called from the interrupt when a kCF job 2422906Sgm89044 * completes. It does some driver-specific things, and then calls the 2423906Sgm89044 * kCF-provided callback. Finally, it cleans up the state for the work 2424906Sgm89044 * request and drops the reference count to allow for DR. 2425906Sgm89044 */ 2426906Sgm89044 void 2427906Sgm89044 dca_done(dca_request_t *reqp, int err) 2428906Sgm89044 { 2429906Sgm89044 uint64_t ena = 0; 2430906Sgm89044 2431906Sgm89044 /* unbind any chains we were using */ 2432906Sgm89044 if (dca_unbindchains(reqp) != DDI_SUCCESS) { 2433906Sgm89044 /* DMA failure */ 2434906Sgm89044 ena = dca_ena(ena); 2435906Sgm89044 dca_failure(reqp->dr_dca, DDI_DATAPATH_FAULT, 2436906Sgm89044 DCA_FM_ECLASS_NONE, ena, CRYPTO_DEVICE_ERROR, 2437906Sgm89044 "fault on buffer DMA handle"); 2438906Sgm89044 if (err == CRYPTO_SUCCESS) { 2439906Sgm89044 err = CRYPTO_DEVICE_ERROR; 2440906Sgm89044 } 2441906Sgm89044 } 2442906Sgm89044 2443906Sgm89044 if (reqp->dr_callback != NULL) { 2444906Sgm89044 reqp->dr_callback(reqp, err); 2445906Sgm89044 } else { 2446906Sgm89044 dca_freereq(reqp); 2447906Sgm89044 } 2448906Sgm89044 } 2449906Sgm89044 2450906Sgm89044 /* 2451906Sgm89044 * Call this when a failure is detected. It will reset the chip, 2452906Sgm89044 * log a message, alert kCF, and mark jobs in the runq as failed. 2453906Sgm89044 */ 2454906Sgm89044 /* ARGSUSED */ 2455906Sgm89044 void 2456906Sgm89044 dca_failure(dca_t *dca, ddi_fault_location_t loc, dca_fma_eclass_t index, 2457906Sgm89044 uint64_t ena, int errno, char *mess, ...) 2458906Sgm89044 { 2459906Sgm89044 va_list ap; 2460906Sgm89044 char buf[256]; 2461906Sgm89044 int mcr; 2462906Sgm89044 char *eclass; 2463906Sgm89044 int have_mutex; 2464906Sgm89044 2465906Sgm89044 va_start(ap, mess); 2466906Sgm89044 (void) vsprintf(buf, mess, ap); 2467906Sgm89044 va_end(ap); 2468906Sgm89044 2469906Sgm89044 eclass = dca_fma_eclass_string(dca->dca_model, index); 2470906Sgm89044 2471906Sgm89044 if (DDI_FM_EREPORT_CAP(dca->fm_capabilities) && 2472906Sgm89044 index != DCA_FM_ECLASS_NONE) { 2473906Sgm89044 ddi_fm_ereport_post(dca->dca_dip, eclass, ena, 2474906Sgm89044 DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 2475906Sgm89044 FM_EREPORT_VERS0, NULL); 2476906Sgm89044 2477906Sgm89044 /* Report the impact of the failure to the DDI. */ 2478906Sgm89044 ddi_fm_service_impact(dca->dca_dip, DDI_SERVICE_LOST); 2479906Sgm89044 } else { 2480906Sgm89044 /* Just log the error string to the message log */ 2481906Sgm89044 dca_error(dca, buf); 2482906Sgm89044 } 2483906Sgm89044 2484906Sgm89044 /* 2485906Sgm89044 * Indicate a failure (keeps schedule from running). 2486906Sgm89044 */ 2487906Sgm89044 dca->dca_flags |= DCA_FAILED; 2488906Sgm89044 2489906Sgm89044 /* 2490906Sgm89044 * Reset the chip. This should also have as a side effect, the 2491906Sgm89044 * disabling of all interrupts from the device. 2492906Sgm89044 */ 2493906Sgm89044 (void) dca_reset(dca, 1); 2494906Sgm89044 2495906Sgm89044 /* 2496906Sgm89044 * Report the failure to kCF. 2497906Sgm89044 */ 2498906Sgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) { 2499906Sgm89044 if (WORKLIST(dca, mcr)->dwl_prov) { 2500906Sgm89044 crypto_prov_notify(WORKLIST(dca, mcr)->dwl_prov, 2501906Sgm89044 CRYPTO_PROVIDER_FAILED); 2502906Sgm89044 } 2503906Sgm89044 } 2504906Sgm89044 2505906Sgm89044 /* 2506906Sgm89044 * Return jobs not sent to hardware back to kCF. 2507906Sgm89044 */ 2508906Sgm89044 dca_rejectjobs(dca); 2509906Sgm89044 2510906Sgm89044 /* 2511906Sgm89044 * From this point on, no new work should be arriving, and the 2512906Sgm89044 * chip should not be doing any active DMA. 2513906Sgm89044 */ 2514906Sgm89044 2515906Sgm89044 /* 2516906Sgm89044 * Now find all the work submitted to the device and fail 2517906Sgm89044 * them. 2518906Sgm89044 */ 2519906Sgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) { 2520906Sgm89044 dca_worklist_t *wlp; 2521906Sgm89044 int i; 2522906Sgm89044 2523906Sgm89044 wlp = WORKLIST(dca, mcr); 2524906Sgm89044 2525906Sgm89044 if (wlp == NULL || wlp->dwl_waitq.dl_prev == NULL) { 2526906Sgm89044 continue; 2527906Sgm89044 } 2528906Sgm89044 for (;;) { 2529906Sgm89044 dca_work_t *workp; 2530906Sgm89044 2531906Sgm89044 have_mutex = mutex_tryenter(&wlp->dwl_lock); 2532906Sgm89044 workp = (dca_work_t *)dca_dequeue(&wlp->dwl_runq); 2533906Sgm89044 if (workp == NULL) { 2534906Sgm89044 if (have_mutex) 2535906Sgm89044 mutex_exit(&wlp->dwl_lock); 2536906Sgm89044 break; 2537906Sgm89044 } 2538906Sgm89044 mutex_exit(&wlp->dwl_lock); 2539906Sgm89044 2540906Sgm89044 /* 2541906Sgm89044 * Free up requests 2542906Sgm89044 */ 2543906Sgm89044 for (i = 0; i < wlp->dwl_reqspermcr; i++) { 2544906Sgm89044 dca_request_t *reqp = workp->dw_reqs[i]; 2545906Sgm89044 if (reqp) { 2546*5063Sgm89044 dca_done(reqp, errno); 2547906Sgm89044 workp->dw_reqs[i] = NULL; 2548906Sgm89044 } 2549906Sgm89044 } 2550906Sgm89044 2551906Sgm89044 mutex_enter(&wlp->dwl_lock); 2552906Sgm89044 /* 2553906Sgm89044 * If waiting to drain, signal on the waiter. 2554906Sgm89044 */ 2555906Sgm89044 if (wlp->dwl_drain && QEMPTY(&wlp->dwl_runq)) { 2556906Sgm89044 cv_signal(&wlp->dwl_cv); 2557906Sgm89044 } 2558906Sgm89044 2559906Sgm89044 /* 2560906Sgm89044 * Return the work and request structures to 2561906Sgm89044 * the free pool. 2562906Sgm89044 */ 2563906Sgm89044 dca_freework(workp); 2564906Sgm89044 if (have_mutex) 2565906Sgm89044 mutex_exit(&wlp->dwl_lock); 2566906Sgm89044 } 2567906Sgm89044 } 2568906Sgm89044 2569906Sgm89044 } 2570906Sgm89044 2571906Sgm89044 #ifdef SCHEDDELAY 2572906Sgm89044 /* 2573906Sgm89044 * Reschedule worklist as needed. 2574906Sgm89044 */ 2575906Sgm89044 void 2576906Sgm89044 dca_schedtimeout(void *arg) 2577906Sgm89044 { 2578906Sgm89044 dca_worklist_t *wlp = (dca_worklist_t *)arg; 2579906Sgm89044 mutex_enter(&wlp->dwl_lock); 2580906Sgm89044 wlp->dwl_schedtid = 0; 2581906Sgm89044 dca_schedule(wlp->dwl_dca, wlp->dwl_mcr); 2582906Sgm89044 mutex_exit(&wlp->dwl_lock); 2583906Sgm89044 } 2584906Sgm89044 #endif 2585906Sgm89044 2586906Sgm89044 /* 2587906Sgm89044 * Check for stalled jobs. 2588906Sgm89044 */ 2589906Sgm89044 void 2590906Sgm89044 dca_jobtimeout(void *arg) 2591906Sgm89044 { 2592906Sgm89044 int mcr; 2593906Sgm89044 dca_t *dca = (dca_t *)arg; 2594906Sgm89044 int hung = 0; 2595906Sgm89044 2596906Sgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) { 2597906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 2598906Sgm89044 dca_work_t *workp; 2599906Sgm89044 clock_t when; 2600906Sgm89044 2601906Sgm89044 mutex_enter(&wlp->dwl_lock); 2602906Sgm89044 when = ddi_get_lbolt(); 2603906Sgm89044 2604906Sgm89044 workp = (dca_work_t *)dca_peekqueue(&wlp->dwl_runq); 2605906Sgm89044 if (workp == NULL) { 2606906Sgm89044 /* nothing sitting in the queue */ 2607906Sgm89044 mutex_exit(&wlp->dwl_lock); 2608906Sgm89044 continue; 2609906Sgm89044 } 2610906Sgm89044 2611906Sgm89044 if ((when - workp->dw_lbolt) < drv_usectohz(STALETIME)) { 2612906Sgm89044 /* request has been queued for less than STALETIME */ 2613906Sgm89044 mutex_exit(&wlp->dwl_lock); 2614906Sgm89044 continue; 2615906Sgm89044 } 2616906Sgm89044 2617906Sgm89044 /* job has been sitting around for over 1 second, badness */ 2618906Sgm89044 DBG(dca, DWARN, "stale job (0x%p) found in MCR%d!", workp, 2619906Sgm89044 mcr); 2620906Sgm89044 2621906Sgm89044 /* put it back in the queue, until we reset the chip */ 2622906Sgm89044 hung++; 2623906Sgm89044 mutex_exit(&wlp->dwl_lock); 2624906Sgm89044 } 2625906Sgm89044 2626906Sgm89044 if (hung) { 2627906Sgm89044 dca_failure(dca, DDI_DEVICE_FAULT, 2628906Sgm89044 DCA_FM_ECLASS_HW_TIMEOUT, dca_ena(0), CRYPTO_DEVICE_ERROR, 2629906Sgm89044 "timeout processing job.)"); 2630906Sgm89044 } 2631906Sgm89044 2632906Sgm89044 /* reschedule ourself */ 2633906Sgm89044 mutex_enter(&dca->dca_intrlock); 2634906Sgm89044 if (dca->dca_jobtid == 0) { 2635906Sgm89044 /* timeout has been canceled, prior to DR */ 2636906Sgm89044 mutex_exit(&dca->dca_intrlock); 2637906Sgm89044 return; 2638906Sgm89044 } 2639906Sgm89044 2640906Sgm89044 /* check again in 1 second */ 2641906Sgm89044 dca->dca_jobtid = timeout(dca_jobtimeout, arg, 2642906Sgm89044 drv_usectohz(SECOND)); 2643906Sgm89044 mutex_exit(&dca->dca_intrlock); 2644906Sgm89044 } 2645906Sgm89044 2646906Sgm89044 /* 2647906Sgm89044 * This returns all jobs back to kCF. It assumes that processing 2648906Sgm89044 * on the worklist has halted. 2649906Sgm89044 */ 2650906Sgm89044 void 2651906Sgm89044 dca_rejectjobs(dca_t *dca) 2652906Sgm89044 { 2653906Sgm89044 int mcr; 2654906Sgm89044 int have_mutex; 2655906Sgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) { 2656906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 2657906Sgm89044 dca_request_t *reqp; 2658906Sgm89044 2659906Sgm89044 if (wlp == NULL || wlp->dwl_waitq.dl_prev == NULL) { 2660906Sgm89044 continue; 2661906Sgm89044 } 2662906Sgm89044 have_mutex = mutex_tryenter(&wlp->dwl_lock); 2663906Sgm89044 for (;;) { 2664906Sgm89044 reqp = (dca_request_t *)dca_unqueue(&wlp->dwl_waitq); 2665906Sgm89044 if (reqp == NULL) { 2666906Sgm89044 break; 2667906Sgm89044 } 2668906Sgm89044 /* update flow control */ 2669906Sgm89044 wlp->dwl_count--; 2670906Sgm89044 if ((wlp->dwl_count == wlp->dwl_lowater) && 2671906Sgm89044 (wlp->dwl_busy)) { 2672906Sgm89044 wlp->dwl_busy = 0; 2673906Sgm89044 crypto_prov_notify(wlp->dwl_prov, 2674906Sgm89044 CRYPTO_PROVIDER_READY); 2675906Sgm89044 } 2676906Sgm89044 mutex_exit(&wlp->dwl_lock); 2677906Sgm89044 2678906Sgm89044 (void) dca_unbindchains(reqp); 2679906Sgm89044 reqp->dr_callback(reqp, EAGAIN); 2680906Sgm89044 mutex_enter(&wlp->dwl_lock); 2681906Sgm89044 } 2682906Sgm89044 if (have_mutex) 2683906Sgm89044 mutex_exit(&wlp->dwl_lock); 2684906Sgm89044 } 2685906Sgm89044 } 2686906Sgm89044 2687906Sgm89044 int 2688906Sgm89044 dca_drain(dca_t *dca) 2689906Sgm89044 { 2690906Sgm89044 int mcr; 2691906Sgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) { 2692906Sgm89044 #ifdef SCHEDDELAY 2693906Sgm89044 timeout_id_t tid; 2694906Sgm89044 #endif 2695906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 2696906Sgm89044 2697906Sgm89044 mutex_enter(&wlp->dwl_lock); 2698906Sgm89044 wlp->dwl_drain = 1; 2699906Sgm89044 2700906Sgm89044 /* give it up to a second to drain from the chip */ 2701906Sgm89044 if (!QEMPTY(&wlp->dwl_runq)) { 2702906Sgm89044 (void) cv_timedwait(&wlp->dwl_cv, &wlp->dwl_lock, 2703906Sgm89044 ddi_get_time() + drv_usectohz(STALETIME)); 2704906Sgm89044 2705906Sgm89044 if (!QEMPTY(&wlp->dwl_runq)) { 2706906Sgm89044 dca_error(dca, "unable to drain device"); 2707906Sgm89044 mutex_exit(&wlp->dwl_lock); 2708906Sgm89044 dca_undrain(dca); 2709906Sgm89044 return (EBUSY); 2710906Sgm89044 } 2711906Sgm89044 } 2712906Sgm89044 2713906Sgm89044 #ifdef SCHEDDELAY 2714906Sgm89044 tid = wlp->dwl_schedtid; 2715906Sgm89044 mutex_exit(&wlp->dwl_lock); 2716906Sgm89044 2717906Sgm89044 /* 2718906Sgm89044 * untimeout outside the lock -- this is safe because we 2719906Sgm89044 * have set the drain flag, so dca_schedule() will not 2720906Sgm89044 * reschedule another timeout 2721906Sgm89044 */ 2722906Sgm89044 if (tid) { 2723906Sgm89044 untimeout(tid); 2724906Sgm89044 } 2725906Sgm89044 #else 2726906Sgm89044 mutex_exit(&wlp->dwl_lock); 2727906Sgm89044 #endif 2728906Sgm89044 } 2729906Sgm89044 return (0); 2730906Sgm89044 } 2731906Sgm89044 2732906Sgm89044 void 2733906Sgm89044 dca_undrain(dca_t *dca) 2734906Sgm89044 { 2735906Sgm89044 int mcr; 2736906Sgm89044 2737906Sgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) { 2738906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 2739906Sgm89044 mutex_enter(&wlp->dwl_lock); 2740906Sgm89044 wlp->dwl_drain = 0; 2741906Sgm89044 dca_schedule(dca, mcr); 2742906Sgm89044 mutex_exit(&wlp->dwl_lock); 2743906Sgm89044 } 2744906Sgm89044 } 2745906Sgm89044 2746906Sgm89044 /* 2747906Sgm89044 * Duplicate the crypto_data_t structure, but point to the original 2748906Sgm89044 * buffers. 2749906Sgm89044 */ 2750906Sgm89044 int 2751906Sgm89044 dca_dupcrypto(crypto_data_t *input, crypto_data_t *ninput) 2752906Sgm89044 { 2753906Sgm89044 ninput->cd_format = input->cd_format; 2754906Sgm89044 ninput->cd_offset = input->cd_offset; 2755906Sgm89044 ninput->cd_length = input->cd_length; 2756906Sgm89044 ninput->cd_miscdata = input->cd_miscdata; 2757906Sgm89044 2758906Sgm89044 switch (input->cd_format) { 2759906Sgm89044 case CRYPTO_DATA_RAW: 2760906Sgm89044 ninput->cd_raw.iov_base = input->cd_raw.iov_base; 2761906Sgm89044 ninput->cd_raw.iov_len = input->cd_raw.iov_len; 2762906Sgm89044 break; 2763906Sgm89044 2764906Sgm89044 case CRYPTO_DATA_UIO: 2765906Sgm89044 ninput->cd_uio = input->cd_uio; 2766906Sgm89044 break; 2767906Sgm89044 2768906Sgm89044 case CRYPTO_DATA_MBLK: 2769906Sgm89044 ninput->cd_mp = input->cd_mp; 2770906Sgm89044 break; 2771906Sgm89044 2772906Sgm89044 default: 2773906Sgm89044 DBG(NULL, DWARN, 2774906Sgm89044 "dca_dupcrypto: unrecognised crypto data format"); 2775906Sgm89044 return (CRYPTO_FAILED); 2776906Sgm89044 } 2777906Sgm89044 2778906Sgm89044 return (CRYPTO_SUCCESS); 2779906Sgm89044 } 2780906Sgm89044 2781906Sgm89044 /* 2782906Sgm89044 * Performs validation checks on the input and output data structures. 2783906Sgm89044 */ 2784906Sgm89044 int 2785906Sgm89044 dca_verifyio(crypto_data_t *input, crypto_data_t *output) 2786906Sgm89044 { 2787906Sgm89044 int rv = CRYPTO_SUCCESS; 2788906Sgm89044 2789906Sgm89044 switch (input->cd_format) { 2790906Sgm89044 case CRYPTO_DATA_RAW: 2791906Sgm89044 break; 2792906Sgm89044 2793906Sgm89044 case CRYPTO_DATA_UIO: 2794906Sgm89044 /* we support only kernel buffer */ 2795906Sgm89044 if (input->cd_uio->uio_segflg != UIO_SYSSPACE) { 2796906Sgm89044 DBG(NULL, DWARN, "non kernel input uio buffer"); 2797906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 2798906Sgm89044 } 2799906Sgm89044 break; 2800906Sgm89044 2801906Sgm89044 case CRYPTO_DATA_MBLK: 2802906Sgm89044 break; 2803906Sgm89044 2804906Sgm89044 default: 2805906Sgm89044 DBG(NULL, DWARN, "unrecognised input crypto data format"); 2806906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 2807906Sgm89044 } 2808906Sgm89044 2809906Sgm89044 switch (output->cd_format) { 2810906Sgm89044 case CRYPTO_DATA_RAW: 2811906Sgm89044 break; 2812906Sgm89044 2813906Sgm89044 case CRYPTO_DATA_UIO: 2814906Sgm89044 /* we support only kernel buffer */ 2815906Sgm89044 if (output->cd_uio->uio_segflg != UIO_SYSSPACE) { 2816906Sgm89044 DBG(NULL, DWARN, "non kernel output uio buffer"); 2817906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 2818906Sgm89044 } 2819906Sgm89044 break; 2820906Sgm89044 2821906Sgm89044 case CRYPTO_DATA_MBLK: 2822906Sgm89044 break; 2823906Sgm89044 2824906Sgm89044 default: 2825906Sgm89044 DBG(NULL, DWARN, "unrecognised output crypto data format"); 2826906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 2827906Sgm89044 } 2828906Sgm89044 2829906Sgm89044 return (rv); 2830906Sgm89044 } 2831906Sgm89044 2832906Sgm89044 /* 2833906Sgm89044 * data: source crypto_data_t struct 2834906Sgm89044 * off: offset into the source before commencing copy 2835906Sgm89044 * count: the amount of data to copy 2836906Sgm89044 * dest: destination buffer 2837906Sgm89044 */ 2838906Sgm89044 int 2839906Sgm89044 dca_getbufbytes(crypto_data_t *data, size_t off, int count, uchar_t *dest) 2840906Sgm89044 { 2841906Sgm89044 int rv = CRYPTO_SUCCESS; 2842906Sgm89044 uio_t *uiop; 2843906Sgm89044 uint_t vec_idx; 2844906Sgm89044 size_t cur_len; 2845906Sgm89044 mblk_t *mp; 2846906Sgm89044 2847906Sgm89044 if (count == 0) { 2848906Sgm89044 /* We don't want anything so we're done. */ 2849906Sgm89044 return (rv); 2850906Sgm89044 } 2851906Sgm89044 2852906Sgm89044 /* 2853906Sgm89044 * Sanity check that we haven't specified a length greater than the 2854906Sgm89044 * offset adjusted size of the buffer. 2855906Sgm89044 */ 2856906Sgm89044 if (count > (data->cd_length - off)) { 2857906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 2858906Sgm89044 } 2859906Sgm89044 2860906Sgm89044 /* Add the internal crypto_data offset to the requested offset. */ 2861906Sgm89044 off += data->cd_offset; 2862906Sgm89044 2863906Sgm89044 switch (data->cd_format) { 2864906Sgm89044 case CRYPTO_DATA_RAW: 2865906Sgm89044 bcopy(data->cd_raw.iov_base + off, dest, count); 2866906Sgm89044 break; 2867906Sgm89044 2868906Sgm89044 case CRYPTO_DATA_UIO: 2869906Sgm89044 /* 2870906Sgm89044 * Jump to the first iovec containing data to be 2871906Sgm89044 * processed. 2872906Sgm89044 */ 2873906Sgm89044 uiop = data->cd_uio; 2874906Sgm89044 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 2875906Sgm89044 off >= uiop->uio_iov[vec_idx].iov_len; 2876*5063Sgm89044 off -= uiop->uio_iov[vec_idx++].iov_len) 2877*5063Sgm89044 ; 2878906Sgm89044 if (vec_idx == uiop->uio_iovcnt) { 2879906Sgm89044 /* 2880906Sgm89044 * The caller specified an offset that is larger than 2881906Sgm89044 * the total size of the buffers it provided. 2882906Sgm89044 */ 2883906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 2884906Sgm89044 } 2885906Sgm89044 2886906Sgm89044 /* 2887906Sgm89044 * Now process the iovecs. 2888906Sgm89044 */ 2889906Sgm89044 while (vec_idx < uiop->uio_iovcnt && count > 0) { 2890906Sgm89044 cur_len = min(uiop->uio_iov[vec_idx].iov_len - 2891906Sgm89044 off, count); 2892906Sgm89044 bcopy(uiop->uio_iov[vec_idx].iov_base + off, dest, 2893906Sgm89044 cur_len); 2894906Sgm89044 count -= cur_len; 2895906Sgm89044 dest += cur_len; 2896906Sgm89044 vec_idx++; 2897906Sgm89044 off = 0; 2898906Sgm89044 } 2899906Sgm89044 2900906Sgm89044 if (vec_idx == uiop->uio_iovcnt && count > 0) { 2901906Sgm89044 /* 2902906Sgm89044 * The end of the specified iovec's was reached but 2903906Sgm89044 * the length requested could not be processed 2904906Sgm89044 * (requested to digest more data than it provided). 2905906Sgm89044 */ 2906906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 2907906Sgm89044 } 2908906Sgm89044 break; 2909906Sgm89044 2910906Sgm89044 case CRYPTO_DATA_MBLK: 2911906Sgm89044 /* 2912906Sgm89044 * Jump to the first mblk_t containing data to be processed. 2913906Sgm89044 */ 2914906Sgm89044 for (mp = data->cd_mp; mp != NULL && off >= MBLKL(mp); 2915*5063Sgm89044 off -= MBLKL(mp), mp = mp->b_cont) 2916*5063Sgm89044 ; 2917906Sgm89044 if (mp == NULL) { 2918906Sgm89044 /* 2919906Sgm89044 * The caller specified an offset that is larger than 2920906Sgm89044 * the total size of the buffers it provided. 2921906Sgm89044 */ 2922906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 2923906Sgm89044 } 2924906Sgm89044 2925906Sgm89044 /* 2926906Sgm89044 * Now do the processing on the mblk chain. 2927906Sgm89044 */ 2928906Sgm89044 while (mp != NULL && count > 0) { 2929906Sgm89044 cur_len = min(MBLKL(mp) - off, count); 2930906Sgm89044 bcopy((char *)(mp->b_rptr + off), dest, cur_len); 2931906Sgm89044 count -= cur_len; 2932906Sgm89044 dest += cur_len; 2933906Sgm89044 mp = mp->b_cont; 2934906Sgm89044 off = 0; 2935906Sgm89044 } 2936906Sgm89044 2937906Sgm89044 if (mp == NULL && count > 0) { 2938906Sgm89044 /* 2939906Sgm89044 * The end of the mblk was reached but the length 2940906Sgm89044 * requested could not be processed, (requested to 2941906Sgm89044 * digest more data than it provided). 2942906Sgm89044 */ 2943906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 2944906Sgm89044 } 2945906Sgm89044 break; 2946906Sgm89044 2947906Sgm89044 default: 2948906Sgm89044 DBG(NULL, DWARN, "unrecognised crypto data format"); 2949906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 2950906Sgm89044 } 2951906Sgm89044 return (rv); 2952906Sgm89044 } 2953906Sgm89044 2954906Sgm89044 2955906Sgm89044 /* 2956906Sgm89044 * Performs the input, output or hard scatter/gather checks on the specified 2957906Sgm89044 * crypto_data_t struct. Returns true if the data is scatter/gather in nature 2958906Sgm89044 * ie fails the test. 2959906Sgm89044 */ 2960906Sgm89044 int 2961906Sgm89044 dca_sgcheck(dca_t *dca, crypto_data_t *data, dca_sg_param_t val) 2962906Sgm89044 { 2963906Sgm89044 uio_t *uiop; 2964906Sgm89044 mblk_t *mp; 2965906Sgm89044 int rv = FALSE; 2966906Sgm89044 2967906Sgm89044 switch (val) { 2968906Sgm89044 case DCA_SG_CONTIG: 2969906Sgm89044 /* 2970906Sgm89044 * Check for a contiguous data buffer. 2971906Sgm89044 */ 2972906Sgm89044 switch (data->cd_format) { 2973906Sgm89044 case CRYPTO_DATA_RAW: 2974906Sgm89044 /* Contiguous in nature */ 2975906Sgm89044 break; 2976906Sgm89044 2977906Sgm89044 case CRYPTO_DATA_UIO: 2978906Sgm89044 if (data->cd_uio->uio_iovcnt > 1) 2979906Sgm89044 rv = TRUE; 2980906Sgm89044 break; 2981906Sgm89044 2982906Sgm89044 case CRYPTO_DATA_MBLK: 2983906Sgm89044 mp = data->cd_mp; 2984906Sgm89044 if (mp->b_cont != NULL) 2985906Sgm89044 rv = TRUE; 2986906Sgm89044 break; 2987906Sgm89044 2988906Sgm89044 default: 2989906Sgm89044 DBG(NULL, DWARN, "unrecognised crypto data format"); 2990906Sgm89044 } 2991906Sgm89044 break; 2992906Sgm89044 2993906Sgm89044 case DCA_SG_WALIGN: 2994906Sgm89044 /* 2995906Sgm89044 * Check for a contiguous data buffer that is 32-bit word 2996906Sgm89044 * aligned and is of word multiples in size. 2997906Sgm89044 */ 2998906Sgm89044 switch (data->cd_format) { 2999906Sgm89044 case CRYPTO_DATA_RAW: 3000906Sgm89044 if ((data->cd_raw.iov_len % sizeof (uint32_t)) || 3001906Sgm89044 ((uintptr_t)data->cd_raw.iov_base % 3002906Sgm89044 sizeof (uint32_t))) { 3003906Sgm89044 rv = TRUE; 3004906Sgm89044 } 3005906Sgm89044 break; 3006906Sgm89044 3007906Sgm89044 case CRYPTO_DATA_UIO: 3008906Sgm89044 uiop = data->cd_uio; 3009906Sgm89044 if (uiop->uio_iovcnt > 1) { 3010906Sgm89044 return (TRUE); 3011906Sgm89044 } 3012906Sgm89044 /* So there is only one iovec */ 3013906Sgm89044 if ((uiop->uio_iov[0].iov_len % sizeof (uint32_t)) || 3014906Sgm89044 ((uintptr_t)uiop->uio_iov[0].iov_base % 3015906Sgm89044 sizeof (uint32_t))) { 3016906Sgm89044 rv = TRUE; 3017906Sgm89044 } 3018906Sgm89044 break; 3019906Sgm89044 3020906Sgm89044 case CRYPTO_DATA_MBLK: 3021906Sgm89044 mp = data->cd_mp; 3022906Sgm89044 if (mp->b_cont != NULL) { 3023906Sgm89044 return (TRUE); 3024906Sgm89044 } 3025906Sgm89044 /* So there is only one mblk in the chain */ 3026906Sgm89044 if ((MBLKL(mp) % sizeof (uint32_t)) || 3027906Sgm89044 ((uintptr_t)mp->b_rptr % sizeof (uint32_t))) { 3028906Sgm89044 rv = TRUE; 3029906Sgm89044 } 3030906Sgm89044 break; 3031906Sgm89044 3032906Sgm89044 default: 3033906Sgm89044 DBG(NULL, DWARN, "unrecognised crypto data format"); 3034906Sgm89044 } 3035906Sgm89044 break; 3036906Sgm89044 3037906Sgm89044 case DCA_SG_PALIGN: 3038906Sgm89044 /* 3039906Sgm89044 * Check that the data buffer is page aligned and is of 3040906Sgm89044 * page multiples in size. 3041906Sgm89044 */ 3042906Sgm89044 switch (data->cd_format) { 3043906Sgm89044 case CRYPTO_DATA_RAW: 3044906Sgm89044 if ((data->cd_length % dca->dca_pagesize) || 3045906Sgm89044 ((uintptr_t)data->cd_raw.iov_base % 3046906Sgm89044 dca->dca_pagesize)) { 3047906Sgm89044 rv = TRUE; 3048906Sgm89044 } 3049906Sgm89044 break; 3050906Sgm89044 3051906Sgm89044 case CRYPTO_DATA_UIO: 3052906Sgm89044 uiop = data->cd_uio; 3053906Sgm89044 if ((uiop->uio_iov[0].iov_len % dca->dca_pagesize) || 3054906Sgm89044 ((uintptr_t)uiop->uio_iov[0].iov_base % 3055906Sgm89044 dca->dca_pagesize)) { 3056906Sgm89044 rv = TRUE; 3057906Sgm89044 } 3058906Sgm89044 break; 3059906Sgm89044 3060906Sgm89044 case CRYPTO_DATA_MBLK: 3061906Sgm89044 mp = data->cd_mp; 3062906Sgm89044 if ((MBLKL(mp) % dca->dca_pagesize) || 3063906Sgm89044 ((uintptr_t)mp->b_rptr % dca->dca_pagesize)) { 3064906Sgm89044 rv = TRUE; 3065906Sgm89044 } 3066906Sgm89044 break; 3067906Sgm89044 3068906Sgm89044 default: 3069906Sgm89044 DBG(NULL, DWARN, "unrecognised crypto data format"); 3070906Sgm89044 } 3071906Sgm89044 break; 3072906Sgm89044 3073906Sgm89044 default: 3074906Sgm89044 DBG(NULL, DWARN, "unrecognised scatter/gather param type"); 3075906Sgm89044 } 3076906Sgm89044 3077906Sgm89044 return (rv); 3078906Sgm89044 } 3079906Sgm89044 3080906Sgm89044 /* 3081906Sgm89044 * Increments the cd_offset and decrements the cd_length as the data is 3082906Sgm89044 * gathered from the crypto_data_t struct. 3083906Sgm89044 * The data is reverse-copied into the dest buffer if the flag is true. 3084906Sgm89044 */ 3085906Sgm89044 int 3086906Sgm89044 dca_gather(crypto_data_t *in, char *dest, int count, int reverse) 3087906Sgm89044 { 3088906Sgm89044 int rv = CRYPTO_SUCCESS; 3089906Sgm89044 uint_t vec_idx; 3090906Sgm89044 uio_t *uiop; 3091906Sgm89044 off_t off = in->cd_offset; 3092906Sgm89044 size_t cur_len; 3093906Sgm89044 mblk_t *mp; 3094906Sgm89044 3095906Sgm89044 switch (in->cd_format) { 3096906Sgm89044 case CRYPTO_DATA_RAW: 3097906Sgm89044 if (count > in->cd_length) { 3098906Sgm89044 /* 3099906Sgm89044 * The caller specified a length greater than the 3100906Sgm89044 * size of the buffer. 3101906Sgm89044 */ 3102906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3103906Sgm89044 } 3104906Sgm89044 if (reverse) 3105906Sgm89044 dca_reverse(in->cd_raw.iov_base + off, dest, count, 3106906Sgm89044 count); 3107906Sgm89044 else 3108906Sgm89044 bcopy(in->cd_raw.iov_base + in->cd_offset, dest, count); 3109906Sgm89044 in->cd_offset += count; 3110906Sgm89044 in->cd_length -= count; 3111906Sgm89044 break; 3112906Sgm89044 3113906Sgm89044 case CRYPTO_DATA_UIO: 3114906Sgm89044 /* 3115906Sgm89044 * Jump to the first iovec containing data to be processed. 3116906Sgm89044 */ 3117906Sgm89044 uiop = in->cd_uio; 3118906Sgm89044 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 3119906Sgm89044 off >= uiop->uio_iov[vec_idx].iov_len; 3120*5063Sgm89044 off -= uiop->uio_iov[vec_idx++].iov_len) 3121*5063Sgm89044 ; 3122906Sgm89044 if (vec_idx == uiop->uio_iovcnt) { 3123906Sgm89044 /* 3124906Sgm89044 * The caller specified an offset that is larger than 3125906Sgm89044 * the total size of the buffers it provided. 3126906Sgm89044 */ 3127906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3128906Sgm89044 } 3129906Sgm89044 3130906Sgm89044 /* 3131906Sgm89044 * Now process the iovecs. 3132906Sgm89044 */ 3133906Sgm89044 while (vec_idx < uiop->uio_iovcnt && count > 0) { 3134906Sgm89044 cur_len = min(uiop->uio_iov[vec_idx].iov_len - 3135906Sgm89044 off, count); 3136906Sgm89044 count -= cur_len; 3137906Sgm89044 if (reverse) { 3138906Sgm89044 /* Fill the dest buffer from the end */ 3139906Sgm89044 dca_reverse(uiop->uio_iov[vec_idx].iov_base + 3140906Sgm89044 off, dest+count, cur_len, cur_len); 3141906Sgm89044 } else { 3142906Sgm89044 bcopy(uiop->uio_iov[vec_idx].iov_base + off, 3143906Sgm89044 dest, cur_len); 3144906Sgm89044 dest += cur_len; 3145906Sgm89044 } 3146906Sgm89044 in->cd_offset += cur_len; 3147906Sgm89044 in->cd_length -= cur_len; 3148906Sgm89044 vec_idx++; 3149906Sgm89044 off = 0; 3150906Sgm89044 } 3151906Sgm89044 3152906Sgm89044 if (vec_idx == uiop->uio_iovcnt && count > 0) { 3153906Sgm89044 /* 3154906Sgm89044 * The end of the specified iovec's was reached but 3155906Sgm89044 * the length requested could not be processed 3156906Sgm89044 * (requested to digest more data than it provided). 3157906Sgm89044 */ 3158906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3159906Sgm89044 } 3160906Sgm89044 break; 3161906Sgm89044 3162906Sgm89044 case CRYPTO_DATA_MBLK: 3163906Sgm89044 /* 3164906Sgm89044 * Jump to the first mblk_t containing data to be processed. 3165906Sgm89044 */ 3166906Sgm89044 for (mp = in->cd_mp; mp != NULL && off >= MBLKL(mp); 3167*5063Sgm89044 off -= MBLKL(mp), mp = mp->b_cont) 3168*5063Sgm89044 ; 3169906Sgm89044 if (mp == NULL) { 3170906Sgm89044 /* 3171906Sgm89044 * The caller specified an offset that is larger than 3172906Sgm89044 * the total size of the buffers it provided. 3173906Sgm89044 */ 3174906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3175906Sgm89044 } 3176906Sgm89044 3177906Sgm89044 /* 3178906Sgm89044 * Now do the processing on the mblk chain. 3179906Sgm89044 */ 3180906Sgm89044 while (mp != NULL && count > 0) { 3181906Sgm89044 cur_len = min(MBLKL(mp) - off, count); 3182906Sgm89044 count -= cur_len; 3183906Sgm89044 if (reverse) { 3184906Sgm89044 /* Fill the dest buffer from the end */ 3185906Sgm89044 dca_reverse((char *)(mp->b_rptr + off), 3186906Sgm89044 dest+count, cur_len, cur_len); 3187906Sgm89044 } else { 3188906Sgm89044 bcopy((char *)(mp->b_rptr + off), dest, 3189906Sgm89044 cur_len); 3190906Sgm89044 dest += cur_len; 3191906Sgm89044 } 3192906Sgm89044 in->cd_offset += cur_len; 3193906Sgm89044 in->cd_length -= cur_len; 3194906Sgm89044 mp = mp->b_cont; 3195906Sgm89044 off = 0; 3196906Sgm89044 } 3197906Sgm89044 3198906Sgm89044 if (mp == NULL && count > 0) { 3199906Sgm89044 /* 3200906Sgm89044 * The end of the mblk was reached but the length 3201906Sgm89044 * requested could not be processed, (requested to 3202906Sgm89044 * digest more data than it provided). 3203906Sgm89044 */ 3204906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3205906Sgm89044 } 3206906Sgm89044 break; 3207906Sgm89044 3208906Sgm89044 default: 3209906Sgm89044 DBG(NULL, DWARN, "dca_gather: unrecognised crypto data format"); 3210906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 3211906Sgm89044 } 3212906Sgm89044 return (rv); 3213906Sgm89044 } 3214906Sgm89044 3215906Sgm89044 /* 3216906Sgm89044 * Increments the cd_offset and decrements the cd_length as the data is 3217906Sgm89044 * gathered from the crypto_data_t struct. 3218906Sgm89044 */ 3219906Sgm89044 int 3220906Sgm89044 dca_resid_gather(crypto_data_t *in, char *resid, int *residlen, char *dest, 3221906Sgm89044 int count) 3222906Sgm89044 { 3223906Sgm89044 int rv = CRYPTO_SUCCESS; 3224906Sgm89044 caddr_t baddr; 3225906Sgm89044 uint_t vec_idx; 3226906Sgm89044 uio_t *uiop; 3227906Sgm89044 off_t off = in->cd_offset; 3228906Sgm89044 size_t cur_len; 3229906Sgm89044 mblk_t *mp; 3230906Sgm89044 3231906Sgm89044 /* Process the residual first */ 3232906Sgm89044 if (*residlen > 0) { 3233906Sgm89044 uint_t num = min(count, *residlen); 3234906Sgm89044 bcopy(resid, dest, num); 3235906Sgm89044 *residlen -= num; 3236906Sgm89044 if (*residlen > 0) { 3237906Sgm89044 /* 3238906Sgm89044 * Requested amount 'count' is less than what's in 3239906Sgm89044 * the residual, so shuffle any remaining resid to 3240906Sgm89044 * the front. 3241906Sgm89044 */ 3242906Sgm89044 baddr = resid + num; 3243906Sgm89044 bcopy(baddr, resid, *residlen); 3244906Sgm89044 } 3245906Sgm89044 dest += num; 3246906Sgm89044 count -= num; 3247906Sgm89044 } 3248906Sgm89044 3249906Sgm89044 /* Now process what's in the crypto_data_t structs */ 3250906Sgm89044 switch (in->cd_format) { 3251906Sgm89044 case CRYPTO_DATA_RAW: 3252906Sgm89044 if (count > in->cd_length) { 3253906Sgm89044 /* 3254906Sgm89044 * The caller specified a length greater than the 3255906Sgm89044 * size of the buffer. 3256906Sgm89044 */ 3257906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3258906Sgm89044 } 3259906Sgm89044 bcopy(in->cd_raw.iov_base + in->cd_offset, dest, count); 3260906Sgm89044 in->cd_offset += count; 3261906Sgm89044 in->cd_length -= count; 3262906Sgm89044 break; 3263906Sgm89044 3264906Sgm89044 case CRYPTO_DATA_UIO: 3265906Sgm89044 /* 3266906Sgm89044 * Jump to the first iovec containing data to be processed. 3267906Sgm89044 */ 3268906Sgm89044 uiop = in->cd_uio; 3269906Sgm89044 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 3270906Sgm89044 off >= uiop->uio_iov[vec_idx].iov_len; 3271*5063Sgm89044 off -= uiop->uio_iov[vec_idx++].iov_len) 3272*5063Sgm89044 ; 3273906Sgm89044 if (vec_idx == uiop->uio_iovcnt) { 3274906Sgm89044 /* 3275906Sgm89044 * The caller specified an offset that is larger than 3276906Sgm89044 * the total size of the buffers it provided. 3277906Sgm89044 */ 3278906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3279906Sgm89044 } 3280906Sgm89044 3281906Sgm89044 /* 3282906Sgm89044 * Now process the iovecs. 3283906Sgm89044 */ 3284906Sgm89044 while (vec_idx < uiop->uio_iovcnt && count > 0) { 3285906Sgm89044 cur_len = min(uiop->uio_iov[vec_idx].iov_len - 3286906Sgm89044 off, count); 3287906Sgm89044 bcopy(uiop->uio_iov[vec_idx].iov_base + off, dest, 3288906Sgm89044 cur_len); 3289906Sgm89044 count -= cur_len; 3290906Sgm89044 dest += cur_len; 3291906Sgm89044 in->cd_offset += cur_len; 3292906Sgm89044 in->cd_length -= cur_len; 3293906Sgm89044 vec_idx++; 3294906Sgm89044 off = 0; 3295906Sgm89044 } 3296906Sgm89044 3297906Sgm89044 if (vec_idx == uiop->uio_iovcnt && count > 0) { 3298906Sgm89044 /* 3299906Sgm89044 * The end of the specified iovec's was reached but 3300906Sgm89044 * the length requested could not be processed 3301906Sgm89044 * (requested to digest more data than it provided). 3302906Sgm89044 */ 3303906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3304906Sgm89044 } 3305906Sgm89044 break; 3306906Sgm89044 3307906Sgm89044 case CRYPTO_DATA_MBLK: 3308906Sgm89044 /* 3309906Sgm89044 * Jump to the first mblk_t containing data to be processed. 3310906Sgm89044 */ 3311906Sgm89044 for (mp = in->cd_mp; mp != NULL && off >= MBLKL(mp); 3312*5063Sgm89044 off -= MBLKL(mp), mp = mp->b_cont) 3313*5063Sgm89044 ; 3314906Sgm89044 if (mp == NULL) { 3315906Sgm89044 /* 3316906Sgm89044 * The caller specified an offset that is larger than 3317906Sgm89044 * the total size of the buffers it provided. 3318906Sgm89044 */ 3319906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3320906Sgm89044 } 3321906Sgm89044 3322906Sgm89044 /* 3323906Sgm89044 * Now do the processing on the mblk chain. 3324906Sgm89044 */ 3325906Sgm89044 while (mp != NULL && count > 0) { 3326906Sgm89044 cur_len = min(MBLKL(mp) - off, count); 3327906Sgm89044 bcopy((char *)(mp->b_rptr + off), dest, cur_len); 3328906Sgm89044 count -= cur_len; 3329906Sgm89044 dest += cur_len; 3330906Sgm89044 in->cd_offset += cur_len; 3331906Sgm89044 in->cd_length -= cur_len; 3332906Sgm89044 mp = mp->b_cont; 3333906Sgm89044 off = 0; 3334906Sgm89044 } 3335906Sgm89044 3336906Sgm89044 if (mp == NULL && count > 0) { 3337906Sgm89044 /* 3338906Sgm89044 * The end of the mblk was reached but the length 3339906Sgm89044 * requested could not be processed, (requested to 3340906Sgm89044 * digest more data than it provided). 3341906Sgm89044 */ 3342906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3343906Sgm89044 } 3344906Sgm89044 break; 3345906Sgm89044 3346906Sgm89044 default: 3347906Sgm89044 DBG(NULL, DWARN, 3348906Sgm89044 "dca_resid_gather: unrecognised crypto data format"); 3349906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 3350906Sgm89044 } 3351906Sgm89044 return (rv); 3352906Sgm89044 } 3353906Sgm89044 3354906Sgm89044 /* 3355906Sgm89044 * Appends the data to the crypto_data_t struct increasing cd_length. 3356906Sgm89044 * cd_offset is left unchanged. 3357906Sgm89044 * Data is reverse-copied if the flag is TRUE. 3358906Sgm89044 */ 3359906Sgm89044 int 3360906Sgm89044 dca_scatter(const char *src, crypto_data_t *out, int count, int reverse) 3361906Sgm89044 { 3362906Sgm89044 int rv = CRYPTO_SUCCESS; 3363906Sgm89044 off_t offset = out->cd_offset + out->cd_length; 3364906Sgm89044 uint_t vec_idx; 3365906Sgm89044 uio_t *uiop; 3366906Sgm89044 size_t cur_len; 3367906Sgm89044 mblk_t *mp; 3368906Sgm89044 3369906Sgm89044 switch (out->cd_format) { 3370906Sgm89044 case CRYPTO_DATA_RAW: 3371906Sgm89044 if (out->cd_raw.iov_len - offset < count) { 3372906Sgm89044 /* Trying to write out more than space available. */ 3373906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3374906Sgm89044 } 3375906Sgm89044 if (reverse) 3376906Sgm89044 dca_reverse((void*) src, out->cd_raw.iov_base + offset, 3377906Sgm89044 count, count); 3378906Sgm89044 else 3379906Sgm89044 bcopy(src, out->cd_raw.iov_base + offset, count); 3380906Sgm89044 out->cd_length += count; 3381906Sgm89044 break; 3382906Sgm89044 3383906Sgm89044 case CRYPTO_DATA_UIO: 3384906Sgm89044 /* 3385906Sgm89044 * Jump to the first iovec that can be written to. 3386906Sgm89044 */ 3387906Sgm89044 uiop = out->cd_uio; 3388906Sgm89044 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 3389906Sgm89044 offset >= uiop->uio_iov[vec_idx].iov_len; 3390*5063Sgm89044 offset -= uiop->uio_iov[vec_idx++].iov_len) 3391*5063Sgm89044 ; 3392906Sgm89044 if (vec_idx == uiop->uio_iovcnt) { 3393906Sgm89044 /* 3394906Sgm89044 * The caller specified an offset that is larger than 3395906Sgm89044 * the total size of the buffers it provided. 3396906Sgm89044 */ 3397906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3398906Sgm89044 } 3399906Sgm89044 3400906Sgm89044 /* 3401906Sgm89044 * Now process the iovecs. 3402906Sgm89044 */ 3403906Sgm89044 while (vec_idx < uiop->uio_iovcnt && count > 0) { 3404906Sgm89044 cur_len = min(uiop->uio_iov[vec_idx].iov_len - 3405906Sgm89044 offset, count); 3406906Sgm89044 count -= cur_len; 3407906Sgm89044 if (reverse) { 3408906Sgm89044 dca_reverse((void*) (src+count), 3409906Sgm89044 uiop->uio_iov[vec_idx].iov_base + 3410906Sgm89044 offset, cur_len, cur_len); 3411906Sgm89044 } else { 3412906Sgm89044 bcopy(src, uiop->uio_iov[vec_idx].iov_base + 3413906Sgm89044 offset, cur_len); 3414906Sgm89044 src += cur_len; 3415906Sgm89044 } 3416906Sgm89044 out->cd_length += cur_len; 3417906Sgm89044 vec_idx++; 3418906Sgm89044 offset = 0; 3419906Sgm89044 } 3420906Sgm89044 3421906Sgm89044 if (vec_idx == uiop->uio_iovcnt && count > 0) { 3422906Sgm89044 /* 3423906Sgm89044 * The end of the specified iovec's was reached but 3424906Sgm89044 * the length requested could not be processed 3425906Sgm89044 * (requested to write more data than space provided). 3426906Sgm89044 */ 3427906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3428906Sgm89044 } 3429906Sgm89044 break; 3430906Sgm89044 3431906Sgm89044 case CRYPTO_DATA_MBLK: 3432906Sgm89044 /* 3433906Sgm89044 * Jump to the first mblk_t that can be written to. 3434906Sgm89044 */ 3435906Sgm89044 for (mp = out->cd_mp; mp != NULL && offset >= MBLKL(mp); 3436*5063Sgm89044 offset -= MBLKL(mp), mp = mp->b_cont) 3437*5063Sgm89044 ; 3438906Sgm89044 if (mp == NULL) { 3439906Sgm89044 /* 3440906Sgm89044 * The caller specified an offset that is larger than 3441906Sgm89044 * the total size of the buffers it provided. 3442906Sgm89044 */ 3443906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3444906Sgm89044 } 3445906Sgm89044 3446906Sgm89044 /* 3447906Sgm89044 * Now do the processing on the mblk chain. 3448906Sgm89044 */ 3449906Sgm89044 while (mp != NULL && count > 0) { 3450906Sgm89044 cur_len = min(MBLKL(mp) - offset, count); 3451906Sgm89044 count -= cur_len; 3452906Sgm89044 if (reverse) { 3453906Sgm89044 dca_reverse((void*) (src+count), 3454906Sgm89044 (char *)(mp->b_rptr + offset), cur_len, 3455906Sgm89044 cur_len); 3456906Sgm89044 } else { 3457906Sgm89044 bcopy(src, (char *)(mp->b_rptr + offset), 3458906Sgm89044 cur_len); 3459906Sgm89044 src += cur_len; 3460906Sgm89044 } 3461906Sgm89044 out->cd_length += cur_len; 3462906Sgm89044 mp = mp->b_cont; 3463906Sgm89044 offset = 0; 3464906Sgm89044 } 3465906Sgm89044 3466906Sgm89044 if (mp == NULL && count > 0) { 3467906Sgm89044 /* 3468906Sgm89044 * The end of the mblk was reached but the length 3469906Sgm89044 * requested could not be processed, (requested to 3470906Sgm89044 * digest more data than it provided). 3471906Sgm89044 */ 3472906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3473906Sgm89044 } 3474906Sgm89044 break; 3475906Sgm89044 3476906Sgm89044 default: 3477906Sgm89044 DBG(NULL, DWARN, "unrecognised crypto data format"); 3478906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 3479906Sgm89044 } 3480906Sgm89044 return (rv); 3481906Sgm89044 } 3482906Sgm89044 3483906Sgm89044 /* 3484906Sgm89044 * Compare two byte arrays in reverse order. 3485906Sgm89044 * Return 0 if they are identical, 1 otherwise. 3486906Sgm89044 */ 3487906Sgm89044 int 3488906Sgm89044 dca_bcmp_reverse(const void *s1, const void *s2, size_t n) 3489906Sgm89044 { 3490906Sgm89044 int i; 3491906Sgm89044 caddr_t src, dst; 3492906Sgm89044 3493906Sgm89044 if (!n) 3494906Sgm89044 return (0); 3495906Sgm89044 3496906Sgm89044 src = ((caddr_t)s1) + n - 1; 3497906Sgm89044 dst = (caddr_t)s2; 3498906Sgm89044 for (i = 0; i < n; i++) { 3499906Sgm89044 if (*src != *dst) 3500906Sgm89044 return (1); 3501906Sgm89044 src--; 3502906Sgm89044 dst++; 3503906Sgm89044 } 3504906Sgm89044 3505906Sgm89044 return (0); 3506906Sgm89044 } 3507906Sgm89044 3508906Sgm89044 3509906Sgm89044 /* 3510906Sgm89044 * This calculates the size of a bignum in bits, specifically not counting 3511906Sgm89044 * leading zero bits. This size calculation must be done *before* any 3512906Sgm89044 * endian reversal takes place (i.e. the numbers are in absolute big-endian 3513906Sgm89044 * order.) 3514906Sgm89044 */ 3515906Sgm89044 int 3516906Sgm89044 dca_bitlen(unsigned char *bignum, int bytelen) 3517906Sgm89044 { 3518906Sgm89044 unsigned char msbyte; 3519906Sgm89044 int i, j; 3520906Sgm89044 3521906Sgm89044 for (i = 0; i < bytelen - 1; i++) { 3522906Sgm89044 if (bignum[i] != 0) { 3523906Sgm89044 break; 3524906Sgm89044 } 3525906Sgm89044 } 3526906Sgm89044 msbyte = bignum[i]; 3527906Sgm89044 for (j = 8; j > 1; j--) { 3528906Sgm89044 if (msbyte & 0x80) { 3529906Sgm89044 break; 3530906Sgm89044 } 3531906Sgm89044 msbyte <<= 1; 3532906Sgm89044 } 3533906Sgm89044 return ((8 * (bytelen - i - 1)) + j); 3534906Sgm89044 } 3535906Sgm89044 3536906Sgm89044 /* 3537906Sgm89044 * This compares to bignums (in big-endian order). It ignores leading 3538906Sgm89044 * null bytes. The result semantics follow bcmp, mempcmp, strcmp, etc. 3539906Sgm89044 */ 3540906Sgm89044 int 3541906Sgm89044 dca_numcmp(caddr_t n1, int n1len, caddr_t n2, int n2len) 3542906Sgm89044 { 3543906Sgm89044 while ((n1len > 1) && (*n1 == 0)) { 3544906Sgm89044 n1len--; 3545906Sgm89044 n1++; 3546906Sgm89044 } 3547906Sgm89044 while ((n2len > 1) && (*n2 == 0)) { 3548906Sgm89044 n2len--; 3549906Sgm89044 n2++; 3550906Sgm89044 } 3551906Sgm89044 if (n1len != n2len) { 3552906Sgm89044 return (n1len - n2len); 3553906Sgm89044 } 3554906Sgm89044 while ((n1len > 1) && (*n1 == *n2)) { 3555906Sgm89044 n1++; 3556906Sgm89044 n2++; 3557906Sgm89044 n1len--; 3558906Sgm89044 } 3559906Sgm89044 return ((int)(*(uchar_t *)n1) - (int)(*(uchar_t *)n2)); 3560906Sgm89044 } 3561906Sgm89044 3562906Sgm89044 /* 3563906Sgm89044 * Return array of key attributes. 3564906Sgm89044 */ 3565906Sgm89044 crypto_object_attribute_t * 3566906Sgm89044 dca_get_key_attr(crypto_key_t *key) 3567906Sgm89044 { 3568906Sgm89044 if ((key->ck_format != CRYPTO_KEY_ATTR_LIST) || 3569906Sgm89044 (key->ck_count == 0)) { 3570906Sgm89044 return (NULL); 3571906Sgm89044 } 3572906Sgm89044 3573906Sgm89044 return (key->ck_attrs); 3574906Sgm89044 } 3575906Sgm89044 3576906Sgm89044 /* 3577906Sgm89044 * If attribute type exists valp points to it's 32-bit value. 3578906Sgm89044 */ 3579906Sgm89044 int 3580906Sgm89044 dca_attr_lookup_uint32(crypto_object_attribute_t *attrp, uint_t atnum, 3581906Sgm89044 uint64_t atype, uint32_t *valp) 3582906Sgm89044 { 3583906Sgm89044 crypto_object_attribute_t *bap; 3584906Sgm89044 3585906Sgm89044 bap = dca_find_attribute(attrp, atnum, atype); 3586906Sgm89044 if (bap == NULL) { 3587906Sgm89044 return (CRYPTO_ATTRIBUTE_TYPE_INVALID); 3588906Sgm89044 } 3589906Sgm89044 3590906Sgm89044 *valp = *bap->oa_value; 3591906Sgm89044 3592906Sgm89044 return (CRYPTO_SUCCESS); 3593906Sgm89044 } 3594906Sgm89044 3595906Sgm89044 /* 3596906Sgm89044 * If attribute type exists data contains the start address of the value, 3597906Sgm89044 * and numelems contains it's length. 3598906Sgm89044 */ 3599906Sgm89044 int 3600906Sgm89044 dca_attr_lookup_uint8_array(crypto_object_attribute_t *attrp, uint_t atnum, 3601906Sgm89044 uint64_t atype, void **data, unsigned int *numelems) 3602906Sgm89044 { 3603906Sgm89044 crypto_object_attribute_t *bap; 3604906Sgm89044 3605906Sgm89044 bap = dca_find_attribute(attrp, atnum, atype); 3606906Sgm89044 if (bap == NULL) { 3607906Sgm89044 return (CRYPTO_ATTRIBUTE_TYPE_INVALID); 3608906Sgm89044 } 3609906Sgm89044 3610906Sgm89044 *data = bap->oa_value; 3611906Sgm89044 *numelems = bap->oa_value_len; 3612906Sgm89044 3613906Sgm89044 return (CRYPTO_SUCCESS); 3614906Sgm89044 } 3615906Sgm89044 3616906Sgm89044 /* 3617906Sgm89044 * Finds entry of specified name. If it is not found dca_find_attribute returns 3618906Sgm89044 * NULL. 3619906Sgm89044 */ 3620906Sgm89044 crypto_object_attribute_t * 3621906Sgm89044 dca_find_attribute(crypto_object_attribute_t *attrp, uint_t atnum, 3622906Sgm89044 uint64_t atype) 3623906Sgm89044 { 3624906Sgm89044 while (atnum) { 3625906Sgm89044 if (attrp->oa_type == atype) 3626906Sgm89044 return (attrp); 3627906Sgm89044 atnum--; 3628906Sgm89044 attrp++; 3629906Sgm89044 } 3630906Sgm89044 return (NULL); 3631906Sgm89044 } 3632906Sgm89044 3633906Sgm89044 /* 3634906Sgm89044 * Return the address of the first data buffer. If the data format is 3635906Sgm89044 * unrecognised return NULL. 3636906Sgm89044 */ 3637906Sgm89044 caddr_t 3638906Sgm89044 dca_bufdaddr(crypto_data_t *data) 3639906Sgm89044 { 3640906Sgm89044 switch (data->cd_format) { 3641906Sgm89044 case CRYPTO_DATA_RAW: 3642906Sgm89044 return (data->cd_raw.iov_base + data->cd_offset); 3643906Sgm89044 case CRYPTO_DATA_UIO: 3644906Sgm89044 return (data->cd_uio->uio_iov[0].iov_base + data->cd_offset); 3645906Sgm89044 case CRYPTO_DATA_MBLK: 3646906Sgm89044 return ((char *)data->cd_mp->b_rptr + data->cd_offset); 3647906Sgm89044 default: 3648906Sgm89044 DBG(NULL, DWARN, 3649906Sgm89044 "dca_bufdaddr: unrecognised crypto data format"); 3650906Sgm89044 return (NULL); 3651906Sgm89044 } 3652906Sgm89044 } 3653906Sgm89044 3654906Sgm89044 static caddr_t 3655906Sgm89044 dca_bufdaddr_out(crypto_data_t *data) 3656906Sgm89044 { 3657906Sgm89044 size_t offset = data->cd_offset + data->cd_length; 3658906Sgm89044 3659906Sgm89044 switch (data->cd_format) { 3660906Sgm89044 case CRYPTO_DATA_RAW: 3661906Sgm89044 return (data->cd_raw.iov_base + offset); 3662906Sgm89044 case CRYPTO_DATA_UIO: 3663906Sgm89044 return (data->cd_uio->uio_iov[0].iov_base + offset); 3664906Sgm89044 case CRYPTO_DATA_MBLK: 3665906Sgm89044 return ((char *)data->cd_mp->b_rptr + offset); 3666906Sgm89044 default: 3667906Sgm89044 DBG(NULL, DWARN, 3668906Sgm89044 "dca_bufdaddr_out: unrecognised crypto data format"); 3669906Sgm89044 return (NULL); 3670906Sgm89044 } 3671906Sgm89044 } 3672906Sgm89044 3673906Sgm89044 /* 3674906Sgm89044 * Control entry points. 3675906Sgm89044 */ 3676906Sgm89044 3677906Sgm89044 /* ARGSUSED */ 3678906Sgm89044 static void 3679906Sgm89044 dca_provider_status(crypto_provider_handle_t provider, uint_t *status) 3680906Sgm89044 { 3681906Sgm89044 *status = CRYPTO_PROVIDER_READY; 3682906Sgm89044 } 3683906Sgm89044 3684906Sgm89044 /* 3685906Sgm89044 * Cipher (encrypt/decrypt) entry points. 3686906Sgm89044 */ 3687906Sgm89044 3688906Sgm89044 /* ARGSUSED */ 3689906Sgm89044 static int 3690906Sgm89044 dca_encrypt_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 3691906Sgm89044 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, 3692906Sgm89044 crypto_req_handle_t req) 3693906Sgm89044 { 3694906Sgm89044 int error = CRYPTO_FAILED; 3695906Sgm89044 dca_t *softc; 3696906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 3697906Sgm89044 int instance; 3698906Sgm89044 3699906Sgm89044 /* extract softc and instance number from context */ 3700906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 3701906Sgm89044 DBG(softc, DENTRY, "dca_encrypt_init: started"); 3702906Sgm89044 3703906Sgm89044 /* check mechanism */ 3704906Sgm89044 switch (mechanism->cm_type) { 3705906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 3706906Sgm89044 error = dca_3desctxinit(ctx, mechanism, key, KM_SLEEP, 3707906Sgm89044 DR_ENCRYPT); 3708906Sgm89044 break; 3709906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 3710906Sgm89044 error = dca_3desctxinit(ctx, mechanism, key, KM_SLEEP, 3711906Sgm89044 DR_ENCRYPT | DR_TRIPLE); 3712906Sgm89044 break; 3713906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 3714906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 3715906Sgm89044 error = dca_rsainit(ctx, mechanism, key, KM_SLEEP); 3716906Sgm89044 break; 3717906Sgm89044 default: 3718906Sgm89044 cmn_err(CE_WARN, "dca_encrypt_init: unexpected mech type " 3719906Sgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type); 3720906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 3721906Sgm89044 } 3722906Sgm89044 3723906Sgm89044 DBG(softc, DENTRY, "dca_encrypt_init: done, err = 0x%x", error); 3724906Sgm89044 3725906Sgm89044 if (error == CRYPTO_SUCCESS) 3726906Sgm89044 dca_enlist2(&softc->dca_ctx_list, ctx->cc_provider_private, 3727906Sgm89044 &softc->dca_ctx_list_lock); 3728906Sgm89044 3729906Sgm89044 return (error); 3730906Sgm89044 } 3731906Sgm89044 3732906Sgm89044 /* ARGSUSED */ 3733906Sgm89044 static int 3734906Sgm89044 dca_encrypt(crypto_ctx_t *ctx, crypto_data_t *plaintext, 3735906Sgm89044 crypto_data_t *ciphertext, crypto_req_handle_t req) 3736906Sgm89044 { 3737906Sgm89044 int error = CRYPTO_FAILED; 3738906Sgm89044 dca_t *softc; 3739906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 3740906Sgm89044 int instance; 3741906Sgm89044 3742906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 3743906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 3744906Sgm89044 3745906Sgm89044 /* extract softc and instance number from context */ 3746906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 3747906Sgm89044 DBG(softc, DENTRY, "dca_encrypt: started"); 3748906Sgm89044 3749*5063Sgm89044 /* handle inplace ops */ 3750*5063Sgm89044 if (!ciphertext) { 3751*5063Sgm89044 dca_request_t *reqp = ctx->cc_provider_private; 3752*5063Sgm89044 reqp->dr_flags |= DR_INPLACE; 3753*5063Sgm89044 ciphertext = plaintext; 3754*5063Sgm89044 } 3755*5063Sgm89044 3756906Sgm89044 /* check mechanism */ 3757906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 3758906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 3759906Sgm89044 error = dca_3des(ctx, plaintext, ciphertext, req, DR_ENCRYPT); 3760906Sgm89044 break; 3761906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 3762906Sgm89044 error = dca_3des(ctx, plaintext, ciphertext, req, 3763906Sgm89044 DR_ENCRYPT | DR_TRIPLE); 3764906Sgm89044 break; 3765906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 3766906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 3767906Sgm89044 error = dca_rsastart(ctx, plaintext, ciphertext, req, 3768906Sgm89044 DCA_RSA_ENC); 3769906Sgm89044 break; 3770906Sgm89044 default: 3771906Sgm89044 /* Should never reach here */ 3772906Sgm89044 cmn_err(CE_WARN, "dca_encrypt: unexpected mech type " 3773906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 3774906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 3775906Sgm89044 } 3776906Sgm89044 3777906Sgm89044 if ((error != CRYPTO_QUEUED) && (error != CRYPTO_SUCCESS) && 3778906Sgm89044 (error != CRYPTO_BUFFER_TOO_SMALL)) { 3779906Sgm89044 ciphertext->cd_length = 0; 3780906Sgm89044 } 3781906Sgm89044 3782906Sgm89044 DBG(softc, DENTRY, "dca_encrypt: done, err = 0x%x", error); 3783906Sgm89044 3784906Sgm89044 return (error); 3785906Sgm89044 } 3786906Sgm89044 3787906Sgm89044 /* ARGSUSED */ 3788906Sgm89044 static int 3789906Sgm89044 dca_encrypt_update(crypto_ctx_t *ctx, crypto_data_t *plaintext, 3790906Sgm89044 crypto_data_t *ciphertext, crypto_req_handle_t req) 3791906Sgm89044 { 3792906Sgm89044 int error = CRYPTO_FAILED; 3793906Sgm89044 dca_t *softc; 3794906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 3795906Sgm89044 int instance; 3796906Sgm89044 3797906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 3798906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 3799906Sgm89044 3800906Sgm89044 /* extract softc and instance number from context */ 3801906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 3802906Sgm89044 DBG(softc, DENTRY, "dca_encrypt_update: started"); 3803906Sgm89044 3804*5063Sgm89044 /* handle inplace ops */ 3805*5063Sgm89044 if (!ciphertext) { 3806*5063Sgm89044 dca_request_t *reqp = ctx->cc_provider_private; 3807*5063Sgm89044 reqp->dr_flags |= DR_INPLACE; 3808*5063Sgm89044 ciphertext = plaintext; 3809*5063Sgm89044 } 3810*5063Sgm89044 3811906Sgm89044 /* check mechanism */ 3812906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 3813906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 3814906Sgm89044 error = dca_3desupdate(ctx, plaintext, ciphertext, req, 3815906Sgm89044 DR_ENCRYPT); 3816906Sgm89044 break; 3817906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 3818906Sgm89044 error = dca_3desupdate(ctx, plaintext, ciphertext, req, 3819906Sgm89044 DR_ENCRYPT | DR_TRIPLE); 3820906Sgm89044 break; 3821906Sgm89044 default: 3822906Sgm89044 /* Should never reach here */ 3823906Sgm89044 cmn_err(CE_WARN, "dca_encrypt_update: unexpected mech type " 3824906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 3825906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 3826906Sgm89044 } 3827906Sgm89044 3828906Sgm89044 DBG(softc, DENTRY, "dca_encrypt_update: done, err = 0x%x", error); 3829906Sgm89044 3830906Sgm89044 return (error); 3831906Sgm89044 } 3832906Sgm89044 3833906Sgm89044 /* ARGSUSED */ 3834906Sgm89044 static int 3835906Sgm89044 dca_encrypt_final(crypto_ctx_t *ctx, crypto_data_t *ciphertext, 3836906Sgm89044 crypto_req_handle_t req) 3837906Sgm89044 { 3838906Sgm89044 int error = CRYPTO_FAILED; 3839906Sgm89044 dca_t *softc; 3840906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 3841906Sgm89044 int instance; 3842906Sgm89044 3843906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 3844906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 3845906Sgm89044 3846906Sgm89044 /* extract softc and instance number from context */ 3847906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 3848906Sgm89044 DBG(softc, DENTRY, "dca_encrypt_final: started"); 3849906Sgm89044 3850906Sgm89044 /* check mechanism */ 3851906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 3852906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 3853906Sgm89044 error = dca_3desfinal(ctx, ciphertext, DR_ENCRYPT); 3854906Sgm89044 break; 3855906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 3856906Sgm89044 error = dca_3desfinal(ctx, ciphertext, DR_ENCRYPT | DR_TRIPLE); 3857906Sgm89044 break; 3858906Sgm89044 default: 3859906Sgm89044 /* Should never reach here */ 3860906Sgm89044 cmn_err(CE_WARN, "dca_encrypt_final: unexpected mech type " 3861906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 3862906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 3863906Sgm89044 } 3864906Sgm89044 3865906Sgm89044 DBG(softc, DENTRY, "dca_encrypt_final: done, err = 0x%x", error); 3866906Sgm89044 3867906Sgm89044 return (error); 3868906Sgm89044 } 3869906Sgm89044 3870906Sgm89044 /* ARGSUSED */ 3871906Sgm89044 static int 3872906Sgm89044 dca_encrypt_atomic(crypto_provider_handle_t provider, 3873906Sgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 3874906Sgm89044 crypto_key_t *key, crypto_data_t *plaintext, crypto_data_t *ciphertext, 3875906Sgm89044 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 3876906Sgm89044 { 3877906Sgm89044 int error = CRYPTO_FAILED; 3878906Sgm89044 dca_t *softc = (dca_t *)provider; 3879906Sgm89044 3880906Sgm89044 DBG(softc, DENTRY, "dca_encrypt_atomic: started"); 3881906Sgm89044 3882906Sgm89044 if (ctx_template != NULL) 3883906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 3884906Sgm89044 3885*5063Sgm89044 /* handle inplace ops */ 3886*5063Sgm89044 if (!ciphertext) { 3887*5063Sgm89044 ciphertext = plaintext; 3888*5063Sgm89044 } 3889*5063Sgm89044 3890906Sgm89044 /* check mechanism */ 3891906Sgm89044 switch (mechanism->cm_type) { 3892906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 3893906Sgm89044 error = dca_3desatomic(provider, session_id, mechanism, key, 3894906Sgm89044 plaintext, ciphertext, KM_SLEEP, req, 3895906Sgm89044 DR_ENCRYPT | DR_ATOMIC); 3896906Sgm89044 break; 3897906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 3898906Sgm89044 error = dca_3desatomic(provider, session_id, mechanism, key, 3899906Sgm89044 plaintext, ciphertext, KM_SLEEP, req, 3900906Sgm89044 DR_ENCRYPT | DR_TRIPLE | DR_ATOMIC); 3901906Sgm89044 break; 3902906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 3903906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 3904906Sgm89044 error = dca_rsaatomic(provider, session_id, mechanism, key, 3905906Sgm89044 plaintext, ciphertext, KM_SLEEP, req, DCA_RSA_ENC); 3906906Sgm89044 break; 3907906Sgm89044 default: 3908906Sgm89044 cmn_err(CE_WARN, "dca_encrypt_atomic: unexpected mech type " 3909906Sgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type); 3910906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 3911906Sgm89044 } 3912906Sgm89044 3913906Sgm89044 if ((error != CRYPTO_QUEUED) && (error != CRYPTO_SUCCESS)) { 3914906Sgm89044 ciphertext->cd_length = 0; 3915906Sgm89044 } 3916906Sgm89044 3917906Sgm89044 DBG(softc, DENTRY, "dca_encrypt_atomic: done, err = 0x%x", error); 3918906Sgm89044 3919906Sgm89044 return (error); 3920906Sgm89044 } 3921906Sgm89044 3922906Sgm89044 /* ARGSUSED */ 3923906Sgm89044 static int 3924906Sgm89044 dca_decrypt_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 3925906Sgm89044 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, 3926906Sgm89044 crypto_req_handle_t req) 3927906Sgm89044 { 3928906Sgm89044 int error = CRYPTO_FAILED; 3929906Sgm89044 dca_t *softc; 3930906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 3931906Sgm89044 int instance; 3932906Sgm89044 3933906Sgm89044 /* extract softc and instance number from context */ 3934906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 3935906Sgm89044 DBG(softc, DENTRY, "dca_decrypt_init: started"); 3936906Sgm89044 3937906Sgm89044 /* check mechanism */ 3938906Sgm89044 switch (mechanism->cm_type) { 3939906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 3940906Sgm89044 error = dca_3desctxinit(ctx, mechanism, key, KM_SLEEP, 3941906Sgm89044 DR_DECRYPT); 3942906Sgm89044 break; 3943906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 3944906Sgm89044 error = dca_3desctxinit(ctx, mechanism, key, KM_SLEEP, 3945906Sgm89044 DR_DECRYPT | DR_TRIPLE); 3946906Sgm89044 break; 3947906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 3948906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 3949906Sgm89044 error = dca_rsainit(ctx, mechanism, key, KM_SLEEP); 3950906Sgm89044 break; 3951906Sgm89044 default: 3952906Sgm89044 cmn_err(CE_WARN, "dca_decrypt_init: unexpected mech type " 3953906Sgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type); 3954906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 3955906Sgm89044 } 3956906Sgm89044 3957906Sgm89044 DBG(softc, DENTRY, "dca_decrypt_init: done, err = 0x%x", error); 3958906Sgm89044 3959906Sgm89044 if (error == CRYPTO_SUCCESS) 3960906Sgm89044 dca_enlist2(&softc->dca_ctx_list, ctx->cc_provider_private, 3961906Sgm89044 &softc->dca_ctx_list_lock); 3962906Sgm89044 3963906Sgm89044 return (error); 3964906Sgm89044 } 3965906Sgm89044 3966906Sgm89044 /* ARGSUSED */ 3967906Sgm89044 static int 3968906Sgm89044 dca_decrypt(crypto_ctx_t *ctx, crypto_data_t *ciphertext, 3969906Sgm89044 crypto_data_t *plaintext, crypto_req_handle_t req) 3970906Sgm89044 { 3971906Sgm89044 int error = CRYPTO_FAILED; 3972906Sgm89044 dca_t *softc; 3973906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 3974906Sgm89044 int instance; 3975906Sgm89044 3976906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 3977906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 3978906Sgm89044 3979906Sgm89044 /* extract softc and instance number from context */ 3980906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 3981906Sgm89044 DBG(softc, DENTRY, "dca_decrypt: started"); 3982906Sgm89044 3983*5063Sgm89044 /* handle inplace ops */ 3984*5063Sgm89044 if (!plaintext) { 3985*5063Sgm89044 dca_request_t *reqp = ctx->cc_provider_private; 3986*5063Sgm89044 reqp->dr_flags |= DR_INPLACE; 3987*5063Sgm89044 plaintext = ciphertext; 3988*5063Sgm89044 } 3989*5063Sgm89044 3990906Sgm89044 /* check mechanism */ 3991906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 3992906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 3993906Sgm89044 error = dca_3des(ctx, ciphertext, plaintext, req, DR_DECRYPT); 3994906Sgm89044 break; 3995906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 3996906Sgm89044 error = dca_3des(ctx, ciphertext, plaintext, req, 3997906Sgm89044 DR_DECRYPT | DR_TRIPLE); 3998906Sgm89044 break; 3999906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4000906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4001906Sgm89044 error = dca_rsastart(ctx, ciphertext, plaintext, req, 4002906Sgm89044 DCA_RSA_DEC); 4003906Sgm89044 break; 4004906Sgm89044 default: 4005906Sgm89044 /* Should never reach here */ 4006906Sgm89044 cmn_err(CE_WARN, "dca_decrypt: unexpected mech type " 4007906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4008906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4009906Sgm89044 } 4010906Sgm89044 4011906Sgm89044 if ((error != CRYPTO_QUEUED) && (error != CRYPTO_SUCCESS) && 4012906Sgm89044 (error != CRYPTO_BUFFER_TOO_SMALL)) { 4013906Sgm89044 if (plaintext) 4014906Sgm89044 plaintext->cd_length = 0; 4015906Sgm89044 } 4016906Sgm89044 4017906Sgm89044 DBG(softc, DENTRY, "dca_decrypt: done, err = 0x%x", error); 4018906Sgm89044 4019906Sgm89044 return (error); 4020906Sgm89044 } 4021906Sgm89044 4022906Sgm89044 /* ARGSUSED */ 4023906Sgm89044 static int 4024906Sgm89044 dca_decrypt_update(crypto_ctx_t *ctx, crypto_data_t *ciphertext, 4025906Sgm89044 crypto_data_t *plaintext, crypto_req_handle_t req) 4026906Sgm89044 { 4027906Sgm89044 int error = CRYPTO_FAILED; 4028906Sgm89044 dca_t *softc; 4029906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4030906Sgm89044 int instance; 4031906Sgm89044 4032906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4033906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4034906Sgm89044 4035906Sgm89044 /* extract softc and instance number from context */ 4036906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4037906Sgm89044 DBG(softc, DENTRY, "dca_decrypt_update: started"); 4038906Sgm89044 4039*5063Sgm89044 /* handle inplace ops */ 4040*5063Sgm89044 if (!plaintext) { 4041*5063Sgm89044 dca_request_t *reqp = ctx->cc_provider_private; 4042*5063Sgm89044 reqp->dr_flags |= DR_INPLACE; 4043*5063Sgm89044 plaintext = ciphertext; 4044*5063Sgm89044 } 4045*5063Sgm89044 4046906Sgm89044 /* check mechanism */ 4047906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 4048906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 4049906Sgm89044 error = dca_3desupdate(ctx, ciphertext, plaintext, req, 4050906Sgm89044 DR_DECRYPT); 4051906Sgm89044 break; 4052906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 4053906Sgm89044 error = dca_3desupdate(ctx, ciphertext, plaintext, req, 4054906Sgm89044 DR_DECRYPT | DR_TRIPLE); 4055906Sgm89044 break; 4056906Sgm89044 default: 4057906Sgm89044 /* Should never reach here */ 4058906Sgm89044 cmn_err(CE_WARN, "dca_decrypt_update: unexpected mech type " 4059906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4060906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4061906Sgm89044 } 4062906Sgm89044 4063906Sgm89044 DBG(softc, DENTRY, "dca_decrypt_update: done, err = 0x%x", error); 4064906Sgm89044 4065906Sgm89044 return (error); 4066906Sgm89044 } 4067906Sgm89044 4068906Sgm89044 /* ARGSUSED */ 4069906Sgm89044 static int 4070906Sgm89044 dca_decrypt_final(crypto_ctx_t *ctx, crypto_data_t *plaintext, 4071906Sgm89044 crypto_req_handle_t req) 4072906Sgm89044 { 4073906Sgm89044 int error = CRYPTO_FAILED; 4074906Sgm89044 dca_t *softc; 4075906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4076906Sgm89044 int instance; 4077906Sgm89044 4078906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4079906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4080906Sgm89044 4081906Sgm89044 /* extract softc and instance number from context */ 4082906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4083906Sgm89044 DBG(softc, DENTRY, "dca_decrypt_final: started"); 4084906Sgm89044 4085906Sgm89044 /* check mechanism */ 4086906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 4087906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 4088906Sgm89044 error = dca_3desfinal(ctx, plaintext, DR_DECRYPT); 4089906Sgm89044 break; 4090906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 4091906Sgm89044 error = dca_3desfinal(ctx, plaintext, DR_DECRYPT | DR_TRIPLE); 4092906Sgm89044 break; 4093906Sgm89044 default: 4094906Sgm89044 /* Should never reach here */ 4095906Sgm89044 cmn_err(CE_WARN, "dca_decrypt_final: unexpected mech type " 4096906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4097906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4098906Sgm89044 } 4099906Sgm89044 4100906Sgm89044 DBG(softc, DENTRY, "dca_decrypt_final: done, err = 0x%x", error); 4101906Sgm89044 4102906Sgm89044 return (error); 4103906Sgm89044 } 4104906Sgm89044 4105906Sgm89044 /* ARGSUSED */ 4106906Sgm89044 static int 4107906Sgm89044 dca_decrypt_atomic(crypto_provider_handle_t provider, 4108906Sgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 4109906Sgm89044 crypto_key_t *key, crypto_data_t *ciphertext, crypto_data_t *plaintext, 4110906Sgm89044 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 4111906Sgm89044 { 4112906Sgm89044 int error = CRYPTO_FAILED; 4113906Sgm89044 dca_t *softc = (dca_t *)provider; 4114906Sgm89044 4115906Sgm89044 DBG(softc, DENTRY, "dca_decrypt_atomic: started"); 4116906Sgm89044 4117906Sgm89044 if (ctx_template != NULL) 4118906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 4119906Sgm89044 4120*5063Sgm89044 /* handle inplace ops */ 4121*5063Sgm89044 if (!plaintext) { 4122*5063Sgm89044 plaintext = ciphertext; 4123*5063Sgm89044 } 4124*5063Sgm89044 4125906Sgm89044 /* check mechanism */ 4126906Sgm89044 switch (mechanism->cm_type) { 4127906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 4128906Sgm89044 error = dca_3desatomic(provider, session_id, mechanism, key, 4129906Sgm89044 ciphertext, plaintext, KM_SLEEP, req, 4130906Sgm89044 DR_DECRYPT | DR_ATOMIC); 4131906Sgm89044 break; 4132906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 4133906Sgm89044 error = dca_3desatomic(provider, session_id, mechanism, key, 4134906Sgm89044 ciphertext, plaintext, KM_SLEEP, req, 4135906Sgm89044 DR_DECRYPT | DR_TRIPLE | DR_ATOMIC); 4136906Sgm89044 break; 4137906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4138906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4139906Sgm89044 error = dca_rsaatomic(provider, session_id, mechanism, key, 4140906Sgm89044 ciphertext, plaintext, KM_SLEEP, req, DCA_RSA_DEC); 4141906Sgm89044 break; 4142906Sgm89044 default: 4143906Sgm89044 cmn_err(CE_WARN, "dca_decrypt_atomic: unexpected mech type " 4144906Sgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type); 4145906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4146906Sgm89044 } 4147906Sgm89044 4148906Sgm89044 if ((error != CRYPTO_QUEUED) && (error != CRYPTO_SUCCESS)) { 4149906Sgm89044 plaintext->cd_length = 0; 4150906Sgm89044 } 4151906Sgm89044 4152906Sgm89044 DBG(softc, DENTRY, "dca_decrypt_atomic: done, err = 0x%x", error); 4153906Sgm89044 4154906Sgm89044 return (error); 4155906Sgm89044 } 4156906Sgm89044 4157906Sgm89044 /* 4158906Sgm89044 * Sign entry points. 4159906Sgm89044 */ 4160906Sgm89044 4161906Sgm89044 /* ARGSUSED */ 4162906Sgm89044 static int 4163906Sgm89044 dca_sign_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 4164906Sgm89044 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, 4165906Sgm89044 crypto_req_handle_t req) 4166906Sgm89044 { 4167906Sgm89044 int error = CRYPTO_FAILED; 4168906Sgm89044 dca_t *softc; 4169906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4170906Sgm89044 int instance; 4171906Sgm89044 4172906Sgm89044 /* extract softc and instance number from context */ 4173906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4174906Sgm89044 DBG(softc, DENTRY, "dca_sign_init: started\n"); 4175906Sgm89044 4176906Sgm89044 if (ctx_template != NULL) 4177906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 4178906Sgm89044 4179906Sgm89044 /* check mechanism */ 4180906Sgm89044 switch (mechanism->cm_type) { 4181906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4182906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4183906Sgm89044 error = dca_rsainit(ctx, mechanism, key, KM_SLEEP); 4184906Sgm89044 break; 4185906Sgm89044 case DSA_MECH_INFO_TYPE: 4186906Sgm89044 error = dca_dsainit(ctx, mechanism, key, KM_SLEEP, 4187906Sgm89044 DCA_DSA_SIGN); 4188906Sgm89044 break; 4189906Sgm89044 default: 4190906Sgm89044 cmn_err(CE_WARN, "dca_sign_init: unexpected mech type " 4191906Sgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type); 4192906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4193906Sgm89044 } 4194906Sgm89044 4195906Sgm89044 DBG(softc, DENTRY, "dca_sign_init: done, err = 0x%x", error); 4196906Sgm89044 4197906Sgm89044 if (error == CRYPTO_SUCCESS) 4198906Sgm89044 dca_enlist2(&softc->dca_ctx_list, ctx->cc_provider_private, 4199906Sgm89044 &softc->dca_ctx_list_lock); 4200906Sgm89044 4201906Sgm89044 return (error); 4202906Sgm89044 } 4203906Sgm89044 4204906Sgm89044 static int 4205906Sgm89044 dca_sign(crypto_ctx_t *ctx, crypto_data_t *data, 4206906Sgm89044 crypto_data_t *signature, crypto_req_handle_t req) 4207906Sgm89044 { 4208906Sgm89044 int error = CRYPTO_FAILED; 4209906Sgm89044 dca_t *softc; 4210906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4211906Sgm89044 int instance; 4212906Sgm89044 4213906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4214906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4215906Sgm89044 4216906Sgm89044 /* extract softc and instance number from context */ 4217906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4218906Sgm89044 DBG(softc, DENTRY, "dca_sign: started\n"); 4219906Sgm89044 4220906Sgm89044 /* check mechanism */ 4221906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 4222906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4223906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4224906Sgm89044 error = dca_rsastart(ctx, data, signature, req, DCA_RSA_SIGN); 4225906Sgm89044 break; 4226906Sgm89044 case DSA_MECH_INFO_TYPE: 4227906Sgm89044 error = dca_dsa_sign(ctx, data, signature, req); 4228906Sgm89044 break; 4229906Sgm89044 default: 4230906Sgm89044 cmn_err(CE_WARN, "dca_sign: unexpected mech type " 4231906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4232906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4233906Sgm89044 } 4234906Sgm89044 4235906Sgm89044 DBG(softc, DENTRY, "dca_sign: done, err = 0x%x", error); 4236906Sgm89044 4237906Sgm89044 return (error); 4238906Sgm89044 } 4239906Sgm89044 4240906Sgm89044 /* ARGSUSED */ 4241906Sgm89044 static int 4242906Sgm89044 dca_sign_update(crypto_ctx_t *ctx, crypto_data_t *data, 4243906Sgm89044 crypto_req_handle_t req) 4244906Sgm89044 { 4245906Sgm89044 int error = CRYPTO_MECHANISM_INVALID; 4246906Sgm89044 dca_t *softc; 4247906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4248906Sgm89044 int instance; 4249906Sgm89044 4250906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4251906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4252906Sgm89044 4253906Sgm89044 /* extract softc and instance number from context */ 4254906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4255906Sgm89044 DBG(softc, DENTRY, "dca_sign_update: started\n"); 4256906Sgm89044 4257906Sgm89044 cmn_err(CE_WARN, "dca_sign_update: unexpected mech type " 4258906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4259906Sgm89044 4260906Sgm89044 DBG(softc, DENTRY, "dca_sign_update: done, err = 0x%x", error); 4261906Sgm89044 4262906Sgm89044 return (error); 4263906Sgm89044 } 4264906Sgm89044 4265906Sgm89044 /* ARGSUSED */ 4266906Sgm89044 static int 4267906Sgm89044 dca_sign_final(crypto_ctx_t *ctx, crypto_data_t *signature, 4268906Sgm89044 crypto_req_handle_t req) 4269906Sgm89044 { 4270906Sgm89044 int error = CRYPTO_MECHANISM_INVALID; 4271906Sgm89044 dca_t *softc; 4272906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4273906Sgm89044 int instance; 4274906Sgm89044 4275906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4276906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4277906Sgm89044 4278906Sgm89044 /* extract softc and instance number from context */ 4279906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4280906Sgm89044 DBG(softc, DENTRY, "dca_sign_final: started\n"); 4281906Sgm89044 4282906Sgm89044 cmn_err(CE_WARN, "dca_sign_final: unexpected mech type " 4283906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4284906Sgm89044 4285906Sgm89044 DBG(softc, DENTRY, "dca_sign_final: done, err = 0x%x", error); 4286906Sgm89044 4287906Sgm89044 return (error); 4288906Sgm89044 } 4289906Sgm89044 4290906Sgm89044 static int 4291906Sgm89044 dca_sign_atomic(crypto_provider_handle_t provider, 4292906Sgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 4293906Sgm89044 crypto_key_t *key, crypto_data_t *data, crypto_data_t *signature, 4294906Sgm89044 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 4295906Sgm89044 { 4296906Sgm89044 int error = CRYPTO_FAILED; 4297906Sgm89044 dca_t *softc = (dca_t *)provider; 4298906Sgm89044 4299906Sgm89044 DBG(softc, DENTRY, "dca_sign_atomic: started\n"); 4300906Sgm89044 4301906Sgm89044 if (ctx_template != NULL) 4302906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 4303906Sgm89044 4304906Sgm89044 /* check mechanism */ 4305906Sgm89044 switch (mechanism->cm_type) { 4306906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4307906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4308906Sgm89044 error = dca_rsaatomic(provider, session_id, mechanism, key, 4309906Sgm89044 data, signature, KM_SLEEP, req, DCA_RSA_SIGN); 4310906Sgm89044 break; 4311906Sgm89044 case DSA_MECH_INFO_TYPE: 4312906Sgm89044 error = dca_dsaatomic(provider, session_id, mechanism, key, 4313906Sgm89044 data, signature, KM_SLEEP, req, DCA_DSA_SIGN); 4314906Sgm89044 break; 4315906Sgm89044 default: 4316906Sgm89044 cmn_err(CE_WARN, "dca_sign_atomic: unexpected mech type " 4317906Sgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type); 4318906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4319906Sgm89044 } 4320906Sgm89044 4321906Sgm89044 DBG(softc, DENTRY, "dca_sign_atomic: done, err = 0x%x", error); 4322906Sgm89044 4323906Sgm89044 return (error); 4324906Sgm89044 } 4325906Sgm89044 4326906Sgm89044 /* ARGSUSED */ 4327906Sgm89044 static int 4328906Sgm89044 dca_sign_recover_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 4329906Sgm89044 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, 4330906Sgm89044 crypto_req_handle_t req) 4331906Sgm89044 { 4332906Sgm89044 int error = CRYPTO_FAILED; 4333906Sgm89044 dca_t *softc; 4334906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4335906Sgm89044 int instance; 4336906Sgm89044 4337906Sgm89044 /* extract softc and instance number from context */ 4338906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4339906Sgm89044 DBG(softc, DENTRY, "dca_sign_recover_init: started\n"); 4340906Sgm89044 4341906Sgm89044 if (ctx_template != NULL) 4342906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 4343906Sgm89044 4344906Sgm89044 /* check mechanism */ 4345906Sgm89044 switch (mechanism->cm_type) { 4346906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4347906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4348906Sgm89044 error = dca_rsainit(ctx, mechanism, key, KM_SLEEP); 4349906Sgm89044 break; 4350906Sgm89044 default: 4351906Sgm89044 cmn_err(CE_WARN, "dca_sign_recover_init: unexpected mech type " 4352906Sgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type); 4353906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4354906Sgm89044 } 4355906Sgm89044 4356906Sgm89044 DBG(softc, DENTRY, "dca_sign_recover_init: done, err = 0x%x", error); 4357906Sgm89044 4358906Sgm89044 if (error == CRYPTO_SUCCESS) 4359906Sgm89044 dca_enlist2(&softc->dca_ctx_list, ctx->cc_provider_private, 4360906Sgm89044 &softc->dca_ctx_list_lock); 4361906Sgm89044 4362906Sgm89044 return (error); 4363906Sgm89044 } 4364906Sgm89044 4365906Sgm89044 static int 4366906Sgm89044 dca_sign_recover(crypto_ctx_t *ctx, crypto_data_t *data, 4367906Sgm89044 crypto_data_t *signature, crypto_req_handle_t req) 4368906Sgm89044 { 4369906Sgm89044 int error = CRYPTO_FAILED; 4370906Sgm89044 dca_t *softc; 4371906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4372906Sgm89044 int instance; 4373906Sgm89044 4374906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4375906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4376906Sgm89044 4377906Sgm89044 /* extract softc and instance number from context */ 4378906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4379906Sgm89044 DBG(softc, DENTRY, "dca_sign_recover: started\n"); 4380906Sgm89044 4381906Sgm89044 /* check mechanism */ 4382906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 4383906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4384906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4385906Sgm89044 error = dca_rsastart(ctx, data, signature, req, DCA_RSA_SIGNR); 4386906Sgm89044 break; 4387906Sgm89044 default: 4388906Sgm89044 cmn_err(CE_WARN, "dca_sign_recover: unexpected mech type " 4389906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4390906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4391906Sgm89044 } 4392906Sgm89044 4393906Sgm89044 DBG(softc, DENTRY, "dca_sign_recover: done, err = 0x%x", error); 4394906Sgm89044 4395906Sgm89044 return (error); 4396906Sgm89044 } 4397906Sgm89044 4398906Sgm89044 static int 4399906Sgm89044 dca_sign_recover_atomic(crypto_provider_handle_t provider, 4400906Sgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 4401906Sgm89044 crypto_key_t *key, crypto_data_t *data, crypto_data_t *signature, 4402906Sgm89044 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 4403906Sgm89044 { 4404906Sgm89044 int error = CRYPTO_FAILED; 4405906Sgm89044 dca_t *softc = (dca_t *)provider; 4406906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4407906Sgm89044 int instance; 4408906Sgm89044 4409906Sgm89044 instance = ddi_get_instance(softc->dca_dip); 4410906Sgm89044 DBG(softc, DENTRY, "dca_sign_recover_atomic: started\n"); 4411906Sgm89044 4412906Sgm89044 if (ctx_template != NULL) 4413906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 4414906Sgm89044 4415906Sgm89044 /* check mechanism */ 4416906Sgm89044 switch (mechanism->cm_type) { 4417906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4418906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4419906Sgm89044 error = dca_rsaatomic(provider, session_id, mechanism, key, 4420906Sgm89044 data, signature, KM_SLEEP, req, DCA_RSA_SIGNR); 4421906Sgm89044 break; 4422906Sgm89044 default: 4423906Sgm89044 cmn_err(CE_WARN, "dca_sign_recover_atomic: unexpected mech type" 4424906Sgm89044 " 0x%llx\n", (unsigned long long)mechanism->cm_type); 4425906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4426906Sgm89044 } 4427906Sgm89044 4428906Sgm89044 DBG(softc, DENTRY, "dca_sign_recover_atomic: done, err = 0x%x", error); 4429906Sgm89044 4430906Sgm89044 return (error); 4431906Sgm89044 } 4432906Sgm89044 4433906Sgm89044 /* 4434906Sgm89044 * Verify entry points. 4435906Sgm89044 */ 4436906Sgm89044 4437906Sgm89044 /* ARGSUSED */ 4438906Sgm89044 static int 4439906Sgm89044 dca_verify_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 4440906Sgm89044 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, 4441906Sgm89044 crypto_req_handle_t req) 4442906Sgm89044 { 4443906Sgm89044 int error = CRYPTO_FAILED; 4444906Sgm89044 dca_t *softc; 4445906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4446906Sgm89044 int instance; 4447906Sgm89044 4448906Sgm89044 /* extract softc and instance number from context */ 4449906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4450906Sgm89044 DBG(softc, DENTRY, "dca_verify_init: started\n"); 4451906Sgm89044 4452906Sgm89044 if (ctx_template != NULL) 4453906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 4454906Sgm89044 4455906Sgm89044 /* check mechanism */ 4456906Sgm89044 switch (mechanism->cm_type) { 4457906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4458906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4459906Sgm89044 error = dca_rsainit(ctx, mechanism, key, KM_SLEEP); 4460906Sgm89044 break; 4461906Sgm89044 case DSA_MECH_INFO_TYPE: 4462906Sgm89044 error = dca_dsainit(ctx, mechanism, key, KM_SLEEP, 4463906Sgm89044 DCA_DSA_VRFY); 4464906Sgm89044 break; 4465906Sgm89044 default: 4466906Sgm89044 cmn_err(CE_WARN, "dca_verify_init: unexpected mech type " 4467906Sgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type); 4468906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4469906Sgm89044 } 4470906Sgm89044 4471906Sgm89044 DBG(softc, DENTRY, "dca_verify_init: done, err = 0x%x", error); 4472906Sgm89044 4473906Sgm89044 if (error == CRYPTO_SUCCESS) 4474906Sgm89044 dca_enlist2(&softc->dca_ctx_list, ctx->cc_provider_private, 4475906Sgm89044 &softc->dca_ctx_list_lock); 4476906Sgm89044 4477906Sgm89044 return (error); 4478906Sgm89044 } 4479906Sgm89044 4480906Sgm89044 static int 4481906Sgm89044 dca_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *signature, 4482906Sgm89044 crypto_req_handle_t req) 4483906Sgm89044 { 4484906Sgm89044 int error = CRYPTO_FAILED; 4485906Sgm89044 dca_t *softc; 4486906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4487906Sgm89044 int instance; 4488906Sgm89044 4489906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4490906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4491906Sgm89044 4492906Sgm89044 /* extract softc and instance number from context */ 4493906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4494906Sgm89044 DBG(softc, DENTRY, "dca_verify: started\n"); 4495906Sgm89044 4496906Sgm89044 /* check mechanism */ 4497906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 4498906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4499906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4500906Sgm89044 error = dca_rsastart(ctx, signature, data, req, DCA_RSA_VRFY); 4501906Sgm89044 break; 4502906Sgm89044 case DSA_MECH_INFO_TYPE: 4503906Sgm89044 error = dca_dsa_verify(ctx, data, signature, req); 4504906Sgm89044 break; 4505906Sgm89044 default: 4506906Sgm89044 cmn_err(CE_WARN, "dca_verify: unexpected mech type " 4507906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4508906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4509906Sgm89044 } 4510906Sgm89044 4511906Sgm89044 DBG(softc, DENTRY, "dca_verify: done, err = 0x%x", error); 4512906Sgm89044 4513906Sgm89044 return (error); 4514906Sgm89044 } 4515906Sgm89044 4516906Sgm89044 /* ARGSUSED */ 4517906Sgm89044 static int 4518906Sgm89044 dca_verify_update(crypto_ctx_t *ctx, crypto_data_t *data, 4519906Sgm89044 crypto_req_handle_t req) 4520906Sgm89044 { 4521906Sgm89044 int error = CRYPTO_MECHANISM_INVALID; 4522906Sgm89044 dca_t *softc; 4523906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4524906Sgm89044 int instance; 4525906Sgm89044 4526906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4527906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4528906Sgm89044 4529906Sgm89044 /* extract softc and instance number from context */ 4530906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4531906Sgm89044 DBG(softc, DENTRY, "dca_verify_update: started\n"); 4532906Sgm89044 4533906Sgm89044 cmn_err(CE_WARN, "dca_verify_update: unexpected mech type " 4534906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4535906Sgm89044 4536906Sgm89044 DBG(softc, DENTRY, "dca_verify_update: done, err = 0x%x", error); 4537906Sgm89044 4538906Sgm89044 return (error); 4539906Sgm89044 } 4540906Sgm89044 4541906Sgm89044 /* ARGSUSED */ 4542906Sgm89044 static int 4543906Sgm89044 dca_verify_final(crypto_ctx_t *ctx, crypto_data_t *signature, 4544906Sgm89044 crypto_req_handle_t req) 4545906Sgm89044 { 4546906Sgm89044 int error = CRYPTO_MECHANISM_INVALID; 4547906Sgm89044 dca_t *softc; 4548906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4549906Sgm89044 int instance; 4550906Sgm89044 4551906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4552906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4553906Sgm89044 4554906Sgm89044 /* extract softc and instance number from context */ 4555906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4556906Sgm89044 DBG(softc, DENTRY, "dca_verify_final: started\n"); 4557906Sgm89044 4558906Sgm89044 cmn_err(CE_WARN, "dca_verify_final: unexpected mech type " 4559906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4560906Sgm89044 4561906Sgm89044 DBG(softc, DENTRY, "dca_verify_final: done, err = 0x%x", error); 4562906Sgm89044 4563906Sgm89044 return (error); 4564906Sgm89044 } 4565906Sgm89044 4566906Sgm89044 static int 4567906Sgm89044 dca_verify_atomic(crypto_provider_handle_t provider, 4568906Sgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 4569906Sgm89044 crypto_key_t *key, crypto_data_t *data, crypto_data_t *signature, 4570906Sgm89044 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 4571906Sgm89044 { 4572906Sgm89044 int error = CRYPTO_FAILED; 4573906Sgm89044 dca_t *softc = (dca_t *)provider; 4574906Sgm89044 4575906Sgm89044 DBG(softc, DENTRY, "dca_verify_atomic: started\n"); 4576906Sgm89044 4577906Sgm89044 if (ctx_template != NULL) 4578906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 4579906Sgm89044 4580906Sgm89044 /* check mechanism */ 4581906Sgm89044 switch (mechanism->cm_type) { 4582906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4583906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4584906Sgm89044 error = dca_rsaatomic(provider, session_id, mechanism, key, 4585906Sgm89044 signature, data, KM_SLEEP, req, DCA_RSA_VRFY); 4586906Sgm89044 break; 4587906Sgm89044 case DSA_MECH_INFO_TYPE: 4588906Sgm89044 error = dca_dsaatomic(provider, session_id, mechanism, key, 4589906Sgm89044 data, signature, KM_SLEEP, req, DCA_DSA_VRFY); 4590906Sgm89044 break; 4591906Sgm89044 default: 4592906Sgm89044 cmn_err(CE_WARN, "dca_verify_atomic: unexpected mech type " 4593906Sgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type); 4594906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4595906Sgm89044 } 4596906Sgm89044 4597906Sgm89044 DBG(softc, DENTRY, "dca_verify_atomic: done, err = 0x%x", error); 4598906Sgm89044 4599906Sgm89044 return (error); 4600906Sgm89044 } 4601906Sgm89044 4602906Sgm89044 /* ARGSUSED */ 4603906Sgm89044 static int 4604906Sgm89044 dca_verify_recover_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 4605906Sgm89044 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, 4606906Sgm89044 crypto_req_handle_t req) 4607906Sgm89044 { 4608906Sgm89044 int error = CRYPTO_MECHANISM_INVALID; 4609906Sgm89044 dca_t *softc; 4610906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4611906Sgm89044 int instance; 4612906Sgm89044 4613906Sgm89044 /* extract softc and instance number from context */ 4614906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4615906Sgm89044 DBG(softc, DENTRY, "dca_verify_recover_init: started\n"); 4616906Sgm89044 4617906Sgm89044 if (ctx_template != NULL) 4618906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 4619906Sgm89044 4620906Sgm89044 /* check mechanism */ 4621906Sgm89044 switch (mechanism->cm_type) { 4622906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4623906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4624906Sgm89044 error = dca_rsainit(ctx, mechanism, key, KM_SLEEP); 4625906Sgm89044 break; 4626906Sgm89044 default: 4627906Sgm89044 cmn_err(CE_WARN, "dca_verify_recover_init: unexpected mech type" 4628906Sgm89044 " 0x%llx\n", (unsigned long long)mechanism->cm_type); 4629906Sgm89044 } 4630906Sgm89044 4631906Sgm89044 DBG(softc, DENTRY, "dca_verify_recover_init: done, err = 0x%x", error); 4632906Sgm89044 4633906Sgm89044 if (error == CRYPTO_SUCCESS) 4634906Sgm89044 dca_enlist2(&softc->dca_ctx_list, ctx->cc_provider_private, 4635906Sgm89044 &softc->dca_ctx_list_lock); 4636906Sgm89044 4637906Sgm89044 return (error); 4638906Sgm89044 } 4639906Sgm89044 4640906Sgm89044 static int 4641906Sgm89044 dca_verify_recover(crypto_ctx_t *ctx, crypto_data_t *signature, 4642906Sgm89044 crypto_data_t *data, crypto_req_handle_t req) 4643906Sgm89044 { 4644906Sgm89044 int error = CRYPTO_MECHANISM_INVALID; 4645906Sgm89044 dca_t *softc; 4646906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4647906Sgm89044 int instance; 4648906Sgm89044 4649906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4650906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4651906Sgm89044 4652906Sgm89044 /* extract softc and instance number from context */ 4653906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4654906Sgm89044 DBG(softc, DENTRY, "dca_verify_recover: started\n"); 4655906Sgm89044 4656906Sgm89044 /* check mechanism */ 4657906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 4658906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4659906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4660906Sgm89044 error = dca_rsastart(ctx, signature, data, req, DCA_RSA_VRFYR); 4661906Sgm89044 break; 4662906Sgm89044 default: 4663906Sgm89044 cmn_err(CE_WARN, "dca_verify_recover: unexpected mech type " 4664906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4665906Sgm89044 } 4666906Sgm89044 4667906Sgm89044 DBG(softc, DENTRY, "dca_verify_recover: done, err = 0x%x", error); 4668906Sgm89044 4669906Sgm89044 return (error); 4670906Sgm89044 } 4671906Sgm89044 4672906Sgm89044 static int 4673906Sgm89044 dca_verify_recover_atomic(crypto_provider_handle_t provider, 4674906Sgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 4675906Sgm89044 crypto_key_t *key, crypto_data_t *data, crypto_data_t *signature, 4676906Sgm89044 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 4677906Sgm89044 { 4678906Sgm89044 int error = CRYPTO_MECHANISM_INVALID; 4679906Sgm89044 dca_t *softc = (dca_t *)provider; 4680906Sgm89044 4681906Sgm89044 DBG(softc, DENTRY, "dca_verify_recover_atomic: started\n"); 4682906Sgm89044 4683906Sgm89044 if (ctx_template != NULL) 4684906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 4685906Sgm89044 4686906Sgm89044 /* check mechanism */ 4687906Sgm89044 switch (mechanism->cm_type) { 4688906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4689906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4690906Sgm89044 error = dca_rsaatomic(provider, session_id, mechanism, key, 4691906Sgm89044 signature, data, KM_SLEEP, req, DCA_RSA_VRFYR); 4692906Sgm89044 break; 4693906Sgm89044 default: 4694906Sgm89044 cmn_err(CE_WARN, "dca_verify_recover_atomic: unexpected mech " 4695906Sgm89044 "type 0x%llx\n", (unsigned long long)mechanism->cm_type); 4696906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4697906Sgm89044 } 4698906Sgm89044 4699906Sgm89044 DBG(softc, DENTRY, 4700906Sgm89044 "dca_verify_recover_atomic: done, err = 0x%x", error); 4701906Sgm89044 4702906Sgm89044 return (error); 4703906Sgm89044 } 4704906Sgm89044 4705906Sgm89044 /* 4706906Sgm89044 * Random number entry points. 4707906Sgm89044 */ 4708906Sgm89044 4709906Sgm89044 /* ARGSUSED */ 4710906Sgm89044 static int 4711906Sgm89044 dca_generate_random(crypto_provider_handle_t provider, 4712906Sgm89044 crypto_session_id_t session_id, 4713906Sgm89044 uchar_t *buf, size_t len, crypto_req_handle_t req) 4714906Sgm89044 { 4715906Sgm89044 int error = CRYPTO_FAILED; 4716906Sgm89044 dca_t *softc = (dca_t *)provider; 4717906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4718906Sgm89044 int instance; 4719906Sgm89044 4720906Sgm89044 instance = ddi_get_instance(softc->dca_dip); 4721906Sgm89044 DBG(softc, DENTRY, "dca_generate_random: started"); 4722906Sgm89044 4723906Sgm89044 error = dca_rng(softc, buf, len, req); 4724906Sgm89044 4725906Sgm89044 DBG(softc, DENTRY, "dca_generate_random: done, err = 0x%x", error); 4726906Sgm89044 4727906Sgm89044 return (error); 4728906Sgm89044 } 4729906Sgm89044 4730906Sgm89044 /* 4731906Sgm89044 * Context management entry points. 4732906Sgm89044 */ 4733906Sgm89044 4734906Sgm89044 int 4735906Sgm89044 dca_free_context(crypto_ctx_t *ctx) 4736906Sgm89044 { 4737906Sgm89044 int error = CRYPTO_SUCCESS; 4738906Sgm89044 dca_t *softc; 4739906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4740906Sgm89044 int instance; 4741906Sgm89044 4742906Sgm89044 /* extract softc and instance number from context */ 4743906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4744906Sgm89044 DBG(softc, DENTRY, "dca_free_context: entered"); 4745906Sgm89044 4746906Sgm89044 if (ctx->cc_provider_private == NULL) 4747906Sgm89044 return (error); 4748906Sgm89044 4749906Sgm89044 dca_rmlist2(ctx->cc_provider_private, &softc->dca_ctx_list_lock); 4750906Sgm89044 4751906Sgm89044 error = dca_free_context_low(ctx); 4752906Sgm89044 4753906Sgm89044 DBG(softc, DENTRY, "dca_free_context: done, err = 0x%x", error); 4754906Sgm89044 4755906Sgm89044 return (error); 4756906Sgm89044 } 4757906Sgm89044 4758906Sgm89044 static int 4759906Sgm89044 dca_free_context_low(crypto_ctx_t *ctx) 4760906Sgm89044 { 4761906Sgm89044 int error = CRYPTO_SUCCESS; 4762906Sgm89044 4763906Sgm89044 /* check mechanism */ 4764906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 4765906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 4766906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 4767906Sgm89044 dca_3desctxfree(ctx); 4768906Sgm89044 break; 4769906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4770906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4771906Sgm89044 dca_rsactxfree(ctx); 4772906Sgm89044 break; 4773906Sgm89044 case DSA_MECH_INFO_TYPE: 4774906Sgm89044 dca_dsactxfree(ctx); 4775906Sgm89044 break; 4776906Sgm89044 default: 4777906Sgm89044 /* Should never reach here */ 4778906Sgm89044 cmn_err(CE_WARN, "dca_free_context_low: unexpected mech type " 4779906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4780906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4781906Sgm89044 } 4782906Sgm89044 4783906Sgm89044 return (error); 4784906Sgm89044 } 4785906Sgm89044 4786906Sgm89044 4787906Sgm89044 /* Free any unfreed private context. It is called in detach. */ 4788906Sgm89044 static void 4789906Sgm89044 dca_free_context_list(dca_t *dca) 4790906Sgm89044 { 4791906Sgm89044 dca_listnode_t *node; 4792906Sgm89044 crypto_ctx_t ctx; 4793906Sgm89044 4794906Sgm89044 (void) memset(&ctx, 0, sizeof (ctx)); 4795906Sgm89044 ctx.cc_provider = dca; 4796906Sgm89044 4797906Sgm89044 while ((node = dca_delist2(&dca->dca_ctx_list, 4798906Sgm89044 &dca->dca_ctx_list_lock)) != NULL) { 4799906Sgm89044 ctx.cc_provider_private = node; 4800906Sgm89044 (void) dca_free_context_low(&ctx); 4801906Sgm89044 } 4802906Sgm89044 } 4803906Sgm89044 4804906Sgm89044 static int 4805906Sgm89044 ext_info_sym(crypto_provider_handle_t prov, 4806906Sgm89044 crypto_provider_ext_info_t *ext_info, crypto_req_handle_t cfreq) 4807906Sgm89044 { 4808906Sgm89044 return (ext_info_base(prov, ext_info, cfreq, IDENT_SYM)); 4809906Sgm89044 } 4810906Sgm89044 4811906Sgm89044 static int 4812906Sgm89044 ext_info_asym(crypto_provider_handle_t prov, 4813906Sgm89044 crypto_provider_ext_info_t *ext_info, crypto_req_handle_t cfreq) 4814906Sgm89044 { 4815906Sgm89044 int rv; 4816906Sgm89044 4817906Sgm89044 rv = ext_info_base(prov, ext_info, cfreq, IDENT_ASYM); 4818906Sgm89044 /* The asymmetric cipher slot supports random */ 4819906Sgm89044 ext_info->ei_flags |= CRYPTO_EXTF_RNG; 4820906Sgm89044 4821906Sgm89044 return (rv); 4822906Sgm89044 } 4823906Sgm89044 4824906Sgm89044 /* ARGSUSED */ 4825906Sgm89044 static int 4826906Sgm89044 ext_info_base(crypto_provider_handle_t prov, 4827906Sgm89044 crypto_provider_ext_info_t *ext_info, crypto_req_handle_t cfreq, char *id) 4828906Sgm89044 { 4829906Sgm89044 dca_t *dca = (dca_t *)prov; 4830906Sgm89044 int len; 4831906Sgm89044 4832906Sgm89044 /* Label */ 4833906Sgm89044 (void) sprintf((char *)ext_info->ei_label, "%s/%d %s", 4834906Sgm89044 ddi_driver_name(dca->dca_dip), ddi_get_instance(dca->dca_dip), id); 4835906Sgm89044 len = strlen((char *)ext_info->ei_label); 4836906Sgm89044 (void) memset(ext_info->ei_label + len, ' ', 4837906Sgm89044 CRYPTO_EXT_SIZE_LABEL - len); 4838906Sgm89044 4839906Sgm89044 /* Manufacturer ID */ 4840906Sgm89044 (void) sprintf((char *)ext_info->ei_manufacturerID, "%s", 4841*5063Sgm89044 DCA_MANUFACTURER_ID); 4842906Sgm89044 len = strlen((char *)ext_info->ei_manufacturerID); 4843906Sgm89044 (void) memset(ext_info->ei_manufacturerID + len, ' ', 4844906Sgm89044 CRYPTO_EXT_SIZE_MANUF - len); 4845906Sgm89044 4846906Sgm89044 /* Model */ 4847906Sgm89044 (void) sprintf((char *)ext_info->ei_model, dca->dca_model); 4848906Sgm89044 4849906Sgm89044 DBG(dca, DWARN, "kCF MODEL: %s", (char *)ext_info->ei_model); 4850906Sgm89044 4851906Sgm89044 len = strlen((char *)ext_info->ei_model); 4852906Sgm89044 (void) memset(ext_info->ei_model + len, ' ', 4853*5063Sgm89044 CRYPTO_EXT_SIZE_MODEL - len); 4854906Sgm89044 4855906Sgm89044 /* Serial Number. Blank for Deimos */ 4856906Sgm89044 (void) memset(ext_info->ei_serial_number, ' ', CRYPTO_EXT_SIZE_SERIAL); 4857906Sgm89044 4858906Sgm89044 ext_info->ei_flags = CRYPTO_EXTF_WRITE_PROTECTED; 4859906Sgm89044 4860906Sgm89044 ext_info->ei_max_session_count = CRYPTO_UNAVAILABLE_INFO; 4861906Sgm89044 ext_info->ei_max_pin_len = CRYPTO_UNAVAILABLE_INFO; 4862906Sgm89044 ext_info->ei_min_pin_len = CRYPTO_UNAVAILABLE_INFO; 4863906Sgm89044 ext_info->ei_total_public_memory = CRYPTO_UNAVAILABLE_INFO; 4864906Sgm89044 ext_info->ei_free_public_memory = CRYPTO_UNAVAILABLE_INFO; 4865906Sgm89044 ext_info->ei_total_private_memory = CRYPTO_UNAVAILABLE_INFO; 4866906Sgm89044 ext_info->ei_free_private_memory = CRYPTO_UNAVAILABLE_INFO; 4867906Sgm89044 ext_info->ei_hardware_version.cv_major = 0; 4868906Sgm89044 ext_info->ei_hardware_version.cv_minor = 0; 4869906Sgm89044 ext_info->ei_firmware_version.cv_major = 0; 4870906Sgm89044 ext_info->ei_firmware_version.cv_minor = 0; 4871906Sgm89044 4872906Sgm89044 /* Time. No need to be supplied for token without a clock */ 4873906Sgm89044 ext_info->ei_time[0] = '\000'; 4874906Sgm89044 4875906Sgm89044 return (CRYPTO_SUCCESS); 4876906Sgm89044 } 4877906Sgm89044 4878906Sgm89044 static void 4879906Sgm89044 dca_fma_init(dca_t *dca) 4880906Sgm89044 { 4881906Sgm89044 ddi_iblock_cookie_t fm_ibc; 4882906Sgm89044 int fm_capabilities = DDI_FM_EREPORT_CAPABLE | 4883*5063Sgm89044 DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE | 4884*5063Sgm89044 DDI_FM_ERRCB_CAPABLE; 4885906Sgm89044 4886906Sgm89044 /* Read FMA capabilities from dca.conf file (if present) */ 4887906Sgm89044 dca->fm_capabilities = ddi_getprop(DDI_DEV_T_ANY, dca->dca_dip, 4888906Sgm89044 DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "fm-capable", 4889906Sgm89044 fm_capabilities); 4890906Sgm89044 4891906Sgm89044 DBG(dca, DWARN, "dca->fm_capabilities = 0x%x", dca->fm_capabilities); 4892906Sgm89044 4893906Sgm89044 /* Only register with IO Fault Services if we have some capability */ 4894906Sgm89044 if (dca->fm_capabilities) { 4895906Sgm89044 dca_regsattr.devacc_attr_access = DDI_FLAGERR_ACC; 4896906Sgm89044 dca_devattr.devacc_attr_access = DDI_FLAGERR_ACC; 4897906Sgm89044 dca_dmaattr.dma_attr_flags = DDI_DMA_FLAGERR; 4898906Sgm89044 4899906Sgm89044 /* Register capabilities with IO Fault Services */ 4900906Sgm89044 ddi_fm_init(dca->dca_dip, &dca->fm_capabilities, &fm_ibc); 4901906Sgm89044 DBG(dca, DWARN, "fm_capable() = 0x%x", 4902906Sgm89044 ddi_fm_capable(dca->dca_dip)); 4903906Sgm89044 4904906Sgm89044 /* 4905906Sgm89044 * Initialize pci ereport capabilities if ereport capable 4906906Sgm89044 */ 49071865Sdilpreet if (DDI_FM_EREPORT_CAP(dca->fm_capabilities) || 49081865Sdilpreet DDI_FM_ERRCB_CAP(dca->fm_capabilities)) 4909906Sgm89044 pci_ereport_setup(dca->dca_dip); 4910906Sgm89044 4911906Sgm89044 /* 4912906Sgm89044 * Initialize callback mutex and register error callback if 4913906Sgm89044 * error callback capable. 4914906Sgm89044 */ 4915906Sgm89044 if (DDI_FM_ERRCB_CAP(dca->fm_capabilities)) { 4916906Sgm89044 ddi_fm_handler_register(dca->dca_dip, dca_fm_error_cb, 4917906Sgm89044 (void *)dca); 4918906Sgm89044 } 4919906Sgm89044 } else { 4920906Sgm89044 /* 4921906Sgm89044 * These fields have to be cleared of FMA if there are no 4922906Sgm89044 * FMA capabilities at runtime. 4923906Sgm89044 */ 4924906Sgm89044 dca_regsattr.devacc_attr_access = DDI_DEFAULT_ACC; 4925906Sgm89044 dca_devattr.devacc_attr_access = DDI_DEFAULT_ACC; 4926906Sgm89044 dca_dmaattr.dma_attr_flags = 0; 4927906Sgm89044 } 4928906Sgm89044 } 4929906Sgm89044 4930906Sgm89044 4931906Sgm89044 static void 4932906Sgm89044 dca_fma_fini(dca_t *dca) 4933906Sgm89044 { 4934906Sgm89044 /* Only unregister FMA capabilities if we registered some */ 4935906Sgm89044 if (dca->fm_capabilities) { 4936906Sgm89044 4937906Sgm89044 /* 4938906Sgm89044 * Release any resources allocated by pci_ereport_setup() 4939906Sgm89044 */ 49401865Sdilpreet if (DDI_FM_EREPORT_CAP(dca->fm_capabilities) || 49411865Sdilpreet DDI_FM_ERRCB_CAP(dca->fm_capabilities)) { 4942906Sgm89044 pci_ereport_teardown(dca->dca_dip); 4943906Sgm89044 } 4944906Sgm89044 4945906Sgm89044 /* 4946906Sgm89044 * Free callback mutex and un-register error callback if 4947906Sgm89044 * error callback capable. 4948906Sgm89044 */ 4949906Sgm89044 if (DDI_FM_ERRCB_CAP(dca->fm_capabilities)) { 4950906Sgm89044 ddi_fm_handler_unregister(dca->dca_dip); 4951906Sgm89044 } 4952906Sgm89044 4953906Sgm89044 /* Unregister from IO Fault Services */ 4954906Sgm89044 ddi_fm_fini(dca->dca_dip); 4955906Sgm89044 DBG(dca, DWARN, "fm_capable() = 0x%x", 4956906Sgm89044 ddi_fm_capable(dca->dca_dip)); 4957906Sgm89044 } 4958906Sgm89044 } 4959906Sgm89044 4960906Sgm89044 4961906Sgm89044 /* 4962906Sgm89044 * The IO fault service error handling callback function 4963906Sgm89044 */ 49641865Sdilpreet /*ARGSUSED*/ 4965906Sgm89044 static int 4966906Sgm89044 dca_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) 4967906Sgm89044 { 4968906Sgm89044 dca_t *dca = (dca_t *)impl_data; 49691865Sdilpreet 49701865Sdilpreet pci_ereport_post(dip, err, NULL); 49711865Sdilpreet if (err->fme_status == DDI_FM_FATAL) { 4972906Sgm89044 dca_failure(dca, DDI_DATAPATH_FAULT, 4973906Sgm89044 DCA_FM_ECLASS_NONE, dca_ena(0), CRYPTO_DEVICE_ERROR, 4974906Sgm89044 "fault PCI in FMA callback."); 4975906Sgm89044 } 49761865Sdilpreet return (err->fme_status); 4977906Sgm89044 } 4978906Sgm89044 4979906Sgm89044 4980906Sgm89044 static int 4981906Sgm89044 dca_check_acc_handle(dca_t *dca, ddi_acc_handle_t handle, 4982906Sgm89044 dca_fma_eclass_t eclass_index) 4983906Sgm89044 { 4984906Sgm89044 ddi_fm_error_t de; 4985906Sgm89044 int version = 0; 49861865Sdilpreet 49871865Sdilpreet ddi_fm_acc_err_get(handle, &de, version); 49881865Sdilpreet if (de.fme_status != DDI_FM_OK) { 49891865Sdilpreet dca_failure(dca, DDI_DATAPATH_FAULT, 49901865Sdilpreet eclass_index, fm_ena_increment(de.fme_ena), 49911865Sdilpreet CRYPTO_DEVICE_ERROR, ""); 49921865Sdilpreet return (DDI_FAILURE); 4993906Sgm89044 } 4994906Sgm89044 4995906Sgm89044 return (DDI_SUCCESS); 4996906Sgm89044 } 4997906Sgm89044 4998906Sgm89044 int 4999906Sgm89044 dca_check_dma_handle(dca_t *dca, ddi_dma_handle_t handle, 5000906Sgm89044 dca_fma_eclass_t eclass_index) 5001906Sgm89044 { 5002906Sgm89044 ddi_fm_error_t de; 5003906Sgm89044 int version = 0; 50041865Sdilpreet 50051865Sdilpreet ddi_fm_dma_err_get(handle, &de, version); 50061865Sdilpreet if (de.fme_status != DDI_FM_OK) { 50071865Sdilpreet dca_failure(dca, DDI_DATAPATH_FAULT, 50081865Sdilpreet eclass_index, fm_ena_increment(de.fme_ena), 50091865Sdilpreet CRYPTO_DEVICE_ERROR, ""); 50101865Sdilpreet return (DDI_FAILURE); 5011906Sgm89044 } 5012906Sgm89044 return (DDI_SUCCESS); 5013906Sgm89044 } 5014906Sgm89044 5015906Sgm89044 static uint64_t 5016906Sgm89044 dca_ena(uint64_t ena) 5017906Sgm89044 { 5018906Sgm89044 if (ena == 0) 5019906Sgm89044 ena = fm_ena_generate(0, FM_ENA_FMT1); 5020906Sgm89044 else 5021906Sgm89044 ena = fm_ena_increment(ena); 5022906Sgm89044 return (ena); 5023906Sgm89044 } 5024906Sgm89044 5025906Sgm89044 static char * 5026906Sgm89044 dca_fma_eclass_string(char *model, dca_fma_eclass_t index) 5027906Sgm89044 { 5028906Sgm89044 if (strstr(model, "500")) 5029906Sgm89044 return (dca_fma_eclass_sca500[index]); 5030906Sgm89044 else 5031906Sgm89044 return (dca_fma_eclass_sca1000[index]); 5032906Sgm89044 } 5033