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 /* 231865Sdilpreet * Copyright 2006 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; 698*3124Sqs148142 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; 710*3124Sqs148142 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 */ 795*3124Sqs148142 if (dca->dca_devid == 0x5825) { 796*3124Sqs148142 /* for 5825 - increase the DMA read size */ 797*3124Sqs148142 SETBIT(dca, CSR_DMACTL, 798*3124Sqs148142 DMACTL_MCR1IE | DMACTL_MCR2IE | DMACTL_EIE | DMACTL_RD256); 799*3124Sqs148142 } else { 800*3124Sqs148142 SETBIT(dca, CSR_DMACTL, 801*3124Sqs148142 DMACTL_MCR1IE | DMACTL_MCR2IE | DMACTL_EIE); 802*3124Sqs148142 } 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, 837906Sgm89044 CRYPTO_PROVIDER_READY); 838906Sgm89044 crypto_prov_notify(WORKLIST(dca, MCR2)->dwl_prov, 839906Sgm89044 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) { 864906Sgm89044 (void) crypto_unregister_provider(WORKLIST(dca, MCR1)->dwl_prov); 865906Sgm89044 } 866906Sgm89044 if (WORKLIST(dca, MCR2)->dwl_prov != NULL) { 867906Sgm89044 (void) crypto_unregister_provider(WORKLIST(dca, MCR2)->dwl_prov); 868906Sgm89044 } 869906Sgm89044 if (intr_added) { 870906Sgm89044 CLRBIT(dca, CSR_DMACTL, 871906Sgm89044 DMACTL_MCR1IE | DMACTL_MCR2IE | DMACTL_EIE); 872906Sgm89044 /* unregister intr handler */ 873906Sgm89044 ddi_remove_intr(dip, 0, dca->dca_icookie); 874906Sgm89044 } 875906Sgm89044 if (dca->dca_regs_handle) { 876906Sgm89044 ddi_regs_map_free(&dca->dca_regs_handle); 877906Sgm89044 } 878906Sgm89044 if (dca->dca_intrstats) { 879906Sgm89044 kstat_delete(dca->dca_intrstats); 880906Sgm89044 } 881906Sgm89044 if (dca->dca_ksp) { 882906Sgm89044 kstat_delete(dca->dca_ksp); 883906Sgm89044 } 884906Sgm89044 dca_uninit(dca); 885906Sgm89044 886906Sgm89044 /* finalize FMA */ 887906Sgm89044 dca_fma_fini(dca); 888906Sgm89044 889906Sgm89044 mutex_destroy(&dca->dca_intrlock); 890906Sgm89044 ddi_soft_state_free(dca_state, instance); 891906Sgm89044 return (DDI_FAILURE); 892906Sgm89044 893906Sgm89044 } 894906Sgm89044 895906Sgm89044 int 896906Sgm89044 dca_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 897906Sgm89044 { 898906Sgm89044 int instance; 899906Sgm89044 dca_t *dca; 900906Sgm89044 timeout_id_t tid; 901906Sgm89044 902906Sgm89044 instance = ddi_get_instance(dip); 903906Sgm89044 904906Sgm89044 DBG(NULL, DMOD, "dca: in dca_detach() for %d", instance); 905906Sgm89044 906906Sgm89044 switch (cmd) { 907906Sgm89044 case DDI_SUSPEND: 908906Sgm89044 if ((dca = (dca_t *)ddi_get_driver_private(dip)) == NULL) { 909906Sgm89044 dca_diperror(dip, "no soft state in detach"); 910906Sgm89044 return (DDI_FAILURE); 911906Sgm89044 } 912906Sgm89044 /* assumption: we won't be DDI_DETACHed until we return */ 913906Sgm89044 return (dca_suspend(dca)); 914906Sgm89044 915906Sgm89044 case DDI_DETACH: 916906Sgm89044 break; 917906Sgm89044 default: 918906Sgm89044 return (DDI_FAILURE); 919906Sgm89044 } 920906Sgm89044 921906Sgm89044 if ((dca = (dca_t *)ddi_get_driver_private(dip)) == NULL) { 922906Sgm89044 dca_diperror(dip, "no soft state in detach"); 923906Sgm89044 return (DDI_FAILURE); 924906Sgm89044 } 925906Sgm89044 926906Sgm89044 /* 927906Sgm89044 * Unregister from kCF. 928906Sgm89044 * This needs to be done at the beginning of detach. 929906Sgm89044 */ 930906Sgm89044 if (WORKLIST(dca, MCR1)->dwl_prov != NULL) { 931906Sgm89044 if (crypto_unregister_provider(WORKLIST(dca, MCR1)->dwl_prov) != 932906Sgm89044 CRYPTO_SUCCESS) { 933906Sgm89044 dca_error(dca, "unable to unregister MCR1 from kcf"); 934906Sgm89044 return (DDI_FAILURE); 935906Sgm89044 } 936906Sgm89044 } 937906Sgm89044 938906Sgm89044 if (WORKLIST(dca, MCR2)->dwl_prov != NULL) { 939906Sgm89044 if (crypto_unregister_provider(WORKLIST(dca, MCR2)->dwl_prov) != 940906Sgm89044 CRYPTO_SUCCESS) { 941906Sgm89044 dca_error(dca, "unable to unregister MCR2 from kcf"); 942906Sgm89044 return (DDI_FAILURE); 943906Sgm89044 } 944906Sgm89044 } 945906Sgm89044 946906Sgm89044 /* 947906Sgm89044 * Cleanup the private context list. Once the 948906Sgm89044 * crypto_unregister_provider returns, it is safe to do so. 949906Sgm89044 */ 950906Sgm89044 dca_free_context_list(dca); 951906Sgm89044 952906Sgm89044 /* Cleanup the local random number pool */ 953906Sgm89044 dca_random_fini(dca); 954906Sgm89044 955906Sgm89044 /* send any jobs in the waitq back to kCF */ 956906Sgm89044 dca_rejectjobs(dca); 957906Sgm89044 958906Sgm89044 /* untimeout the timeouts */ 959906Sgm89044 mutex_enter(&dca->dca_intrlock); 960906Sgm89044 tid = dca->dca_jobtid; 961906Sgm89044 dca->dca_jobtid = 0; 962906Sgm89044 mutex_exit(&dca->dca_intrlock); 963906Sgm89044 if (tid) { 964906Sgm89044 (void) untimeout(tid); 965906Sgm89044 } 966906Sgm89044 967906Sgm89044 /* disable device interrupts */ 968906Sgm89044 CLRBIT(dca, CSR_DMACTL, DMACTL_MCR1IE | DMACTL_MCR2IE | DMACTL_EIE); 969906Sgm89044 970906Sgm89044 /* unregister interrupt handlers */ 971906Sgm89044 ddi_remove_intr(dip, 0, dca->dca_icookie); 972906Sgm89044 973906Sgm89044 /* release our regs handle */ 974906Sgm89044 ddi_regs_map_free(&dca->dca_regs_handle); 975906Sgm89044 976906Sgm89044 /* toss out kstats */ 977906Sgm89044 if (dca->dca_intrstats) { 978906Sgm89044 kstat_delete(dca->dca_intrstats); 979906Sgm89044 } 980906Sgm89044 if (dca->dca_ksp) { 981906Sgm89044 kstat_delete(dca->dca_ksp); 982906Sgm89044 } 983906Sgm89044 984906Sgm89044 mutex_destroy(&dca->dca_intrlock); 985906Sgm89044 dca_uninit(dca); 986906Sgm89044 987906Sgm89044 /* finalize FMA */ 988906Sgm89044 dca_fma_fini(dca); 989906Sgm89044 990906Sgm89044 ddi_soft_state_free(dca_state, instance); 991906Sgm89044 992906Sgm89044 return (DDI_SUCCESS); 993906Sgm89044 } 994906Sgm89044 995906Sgm89044 int 996906Sgm89044 dca_resume(dca_t *dca) 997906Sgm89044 { 998906Sgm89044 ddi_acc_handle_t pci; 999906Sgm89044 1000906Sgm89044 if (pci_config_setup(dca->dca_dip, &pci) != DDI_SUCCESS) { 1001906Sgm89044 dca_error(dca, "unable to setup PCI config handle"); 1002906Sgm89044 return (DDI_FAILURE); 1003906Sgm89044 } 1004906Sgm89044 1005906Sgm89044 /* 1006906Sgm89044 * Reprogram registers in PCI configuration space. 1007906Sgm89044 */ 1008906Sgm89044 1009906Sgm89044 /* Broadcom-specific timers -- we disable them. */ 1010906Sgm89044 pci_config_put8(pci, PCI_TRDYTO, 0); 1011906Sgm89044 pci_config_put8(pci, PCI_RETRIES, 0); 1012906Sgm89044 1013906Sgm89044 /* initialize PCI access settings */ 1014906Sgm89044 pci_config_put16(pci, PCI_COMM, PCICOMM_SEE | 1015906Sgm89044 PCICOMM_PEE | PCICOMM_BME | PCICOMM_MAE); 1016906Sgm89044 1017906Sgm89044 /* set up our PCI latency timer */ 1018906Sgm89044 pci_config_put8(pci, PCI_LATTMR, 0x40); 1019906Sgm89044 1020906Sgm89044 pci_config_teardown(&pci); 1021906Sgm89044 1022906Sgm89044 if (dca_reset(dca, 0) < 0) { 1023906Sgm89044 dca_error(dca, "unable to reset device during resume"); 1024906Sgm89044 return (DDI_FAILURE); 1025906Sgm89044 } 1026906Sgm89044 1027906Sgm89044 /* 1028906Sgm89044 * Now restore the card-specific CSRs. 1029906Sgm89044 */ 1030906Sgm89044 1031906Sgm89044 /* restore endianness settings */ 1032906Sgm89044 PUTCSR(dca, CSR_DMACTL, DMACTL_BE32 | DMACTL_BE64); 1033906Sgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle, 1034906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) 1035906Sgm89044 return (DDI_FAILURE); 1036906Sgm89044 1037906Sgm89044 /* restore interrupt enables */ 1038*3124Sqs148142 if (dca->dca_devid == 0x5825) { 1039*3124Sqs148142 /* for 5825 set 256 byte read size to improve performance */ 1040*3124Sqs148142 SETBIT(dca, CSR_DMACTL, 1041*3124Sqs148142 DMACTL_MCR1IE | DMACTL_MCR2IE | DMACTL_EIE | DMACTL_RD256); 1042*3124Sqs148142 } else { 1043*3124Sqs148142 SETBIT(dca, CSR_DMACTL, 1044*3124Sqs148142 DMACTL_MCR1IE | DMACTL_MCR2IE | DMACTL_EIE); 1045*3124Sqs148142 } 1046906Sgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle, 1047906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) 1048906Sgm89044 return (DDI_FAILURE); 1049906Sgm89044 1050906Sgm89044 /* resume scheduling jobs on the device */ 1051906Sgm89044 dca_undrain(dca); 1052906Sgm89044 1053906Sgm89044 return (DDI_SUCCESS); 1054906Sgm89044 } 1055906Sgm89044 1056906Sgm89044 int 1057906Sgm89044 dca_suspend(dca_t *dca) 1058906Sgm89044 { 1059906Sgm89044 if ((dca_drain(dca)) != 0) { 1060906Sgm89044 return (DDI_FAILURE); 1061906Sgm89044 } 1062906Sgm89044 if (dca_reset(dca, 0) < 0) { 1063906Sgm89044 dca_error(dca, "unable to reset device during suspend"); 1064906Sgm89044 return (DDI_FAILURE); 1065906Sgm89044 } 1066906Sgm89044 return (DDI_SUCCESS); 1067906Sgm89044 } 1068906Sgm89044 1069906Sgm89044 /* 1070906Sgm89044 * Hardware access stuff. 1071906Sgm89044 */ 1072906Sgm89044 int 1073906Sgm89044 dca_reset(dca_t *dca, int failreset) 1074906Sgm89044 { 1075906Sgm89044 int i; 1076906Sgm89044 1077906Sgm89044 if (dca->dca_regs_handle == NULL) { 1078906Sgm89044 return (-1); 1079906Sgm89044 } 1080906Sgm89044 1081906Sgm89044 PUTCSR(dca, CSR_DMACTL, DMACTL_RESET); 1082906Sgm89044 if (!failreset) { 1083906Sgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle, 1084906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) 1085906Sgm89044 return (-1); 1086906Sgm89044 } 1087906Sgm89044 1088906Sgm89044 /* now wait for a reset */ 1089906Sgm89044 for (i = 1; i < 100; i++) { 1090906Sgm89044 uint32_t dmactl; 1091906Sgm89044 drv_usecwait(100); 1092906Sgm89044 dmactl = GETCSR(dca, CSR_DMACTL); 1093906Sgm89044 if (!failreset) { 1094906Sgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle, 1095906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) 1096906Sgm89044 return (-1); 1097906Sgm89044 } 1098906Sgm89044 if ((dmactl & DMACTL_RESET) == 0) { 1099906Sgm89044 DBG(dca, DCHATTY, "reset in %d usec", i * 100); 1100906Sgm89044 return (0); 1101906Sgm89044 } 1102906Sgm89044 } 1103906Sgm89044 if (!failreset) { 1104906Sgm89044 dca_failure(dca, DDI_DEVICE_FAULT, 1105906Sgm89044 DCA_FM_ECLASS_NONE, dca_ena(0), CRYPTO_DEVICE_ERROR, 1106906Sgm89044 "timeout waiting for reset after %d usec", i * 100); 1107906Sgm89044 } 1108906Sgm89044 return (-1); 1109906Sgm89044 } 1110906Sgm89044 1111906Sgm89044 int 1112906Sgm89044 dca_initworklist(dca_t *dca, dca_worklist_t *wlp) 1113906Sgm89044 { 1114906Sgm89044 int i; 1115906Sgm89044 int reqprealloc = wlp->dwl_hiwater + (MAXWORK * MAXREQSPERMCR); 1116906Sgm89044 1117906Sgm89044 /* 1118906Sgm89044 * Set up work queue. 1119906Sgm89044 */ 1120906Sgm89044 mutex_init(&wlp->dwl_lock, NULL, MUTEX_DRIVER, dca->dca_icookie); 1121906Sgm89044 mutex_init(&wlp->dwl_freereqslock, NULL, MUTEX_DRIVER, 1122906Sgm89044 dca->dca_icookie); 1123*3124Sqs148142 mutex_init(&wlp->dwl_freelock, NULL, MUTEX_DRIVER, dca->dca_icookie); 1124906Sgm89044 cv_init(&wlp->dwl_cv, NULL, CV_DRIVER, NULL); 1125906Sgm89044 1126906Sgm89044 mutex_enter(&wlp->dwl_lock); 1127906Sgm89044 1128906Sgm89044 dca_initq(&wlp->dwl_freereqs); 1129906Sgm89044 dca_initq(&wlp->dwl_waitq); 1130906Sgm89044 dca_initq(&wlp->dwl_freework); 1131906Sgm89044 dca_initq(&wlp->dwl_runq); 1132906Sgm89044 1133906Sgm89044 for (i = 0; i < MAXWORK; i++) { 1134906Sgm89044 dca_work_t *workp; 1135906Sgm89044 1136906Sgm89044 if ((workp = dca_newwork(dca)) == NULL) { 1137906Sgm89044 dca_error(dca, "unable to allocate work"); 1138906Sgm89044 mutex_exit(&wlp->dwl_lock); 1139906Sgm89044 return (DDI_FAILURE); 1140906Sgm89044 } 1141906Sgm89044 workp->dw_wlp = wlp; 1142906Sgm89044 dca_freework(workp); 1143906Sgm89044 } 1144906Sgm89044 mutex_exit(&wlp->dwl_lock); 1145906Sgm89044 1146906Sgm89044 for (i = 0; i < reqprealloc; i++) { 1147906Sgm89044 dca_request_t *reqp; 1148906Sgm89044 1149906Sgm89044 if ((reqp = dca_newreq(dca)) == NULL) { 1150906Sgm89044 dca_error(dca, "unable to allocate request"); 1151906Sgm89044 return (DDI_FAILURE); 1152906Sgm89044 } 1153906Sgm89044 reqp->dr_dca = dca; 1154906Sgm89044 reqp->dr_wlp = wlp; 1155906Sgm89044 dca_freereq(reqp); 1156906Sgm89044 } 1157906Sgm89044 return (DDI_SUCCESS); 1158906Sgm89044 } 1159906Sgm89044 1160906Sgm89044 int 1161906Sgm89044 dca_init(dca_t *dca) 1162906Sgm89044 { 1163906Sgm89044 dca_worklist_t *wlp; 1164906Sgm89044 1165906Sgm89044 /* Initialize the private context list and the corresponding lock. */ 1166906Sgm89044 mutex_init(&dca->dca_ctx_list_lock, NULL, MUTEX_DRIVER, NULL); 1167906Sgm89044 dca_initq(&dca->dca_ctx_list); 1168906Sgm89044 1169906Sgm89044 /* 1170906Sgm89044 * MCR1 algorithms. 1171906Sgm89044 */ 1172906Sgm89044 wlp = WORKLIST(dca, MCR1); 1173906Sgm89044 (void) sprintf(wlp->dwl_name, "dca%d:mcr1", 1174906Sgm89044 ddi_get_instance(dca->dca_dip)); 1175906Sgm89044 wlp->dwl_lowater = ddi_getprop(DDI_DEV_T_ANY, 1176906Sgm89044 dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, 1177906Sgm89044 "mcr1_lowater", MCR1LOWATER); 1178906Sgm89044 wlp->dwl_hiwater = ddi_getprop(DDI_DEV_T_ANY, 1179906Sgm89044 dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, 1180906Sgm89044 "mcr1_hiwater", MCR1HIWATER); 1181906Sgm89044 wlp->dwl_reqspermcr = min(ddi_getprop(DDI_DEV_T_ANY, 1182906Sgm89044 dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, 1183906Sgm89044 "mcr1_maxreqs", MCR1MAXREQS), MAXREQSPERMCR); 1184906Sgm89044 wlp->dwl_dca = dca; 1185906Sgm89044 wlp->dwl_mcr = MCR1; 1186906Sgm89044 if (dca_initworklist(dca, wlp) != DDI_SUCCESS) { 1187906Sgm89044 return (DDI_FAILURE); 1188906Sgm89044 } 1189906Sgm89044 1190906Sgm89044 /* 1191906Sgm89044 * MCR2 algorithms. 1192906Sgm89044 */ 1193906Sgm89044 wlp = WORKLIST(dca, MCR2); 1194906Sgm89044 (void) sprintf(wlp->dwl_name, "dca%d:mcr2", 1195906Sgm89044 ddi_get_instance(dca->dca_dip)); 1196906Sgm89044 wlp->dwl_lowater = ddi_getprop(DDI_DEV_T_ANY, 1197906Sgm89044 dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, 1198906Sgm89044 "mcr2_lowater", MCR2LOWATER); 1199906Sgm89044 wlp->dwl_hiwater = ddi_getprop(DDI_DEV_T_ANY, 1200906Sgm89044 dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, 1201906Sgm89044 "mcr2_hiwater", MCR2HIWATER); 1202906Sgm89044 wlp->dwl_reqspermcr = min(ddi_getprop(DDI_DEV_T_ANY, 1203906Sgm89044 dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, 1204906Sgm89044 "mcr2_maxreqs", MCR2MAXREQS), MAXREQSPERMCR); 1205906Sgm89044 wlp->dwl_dca = dca; 1206906Sgm89044 wlp->dwl_mcr = MCR2; 1207906Sgm89044 if (dca_initworklist(dca, wlp) != DDI_SUCCESS) { 1208906Sgm89044 return (DDI_FAILURE); 1209906Sgm89044 } 1210906Sgm89044 return (DDI_SUCCESS); 1211906Sgm89044 } 1212906Sgm89044 1213906Sgm89044 /* 1214906Sgm89044 * Uninitialize worklists. This routine should only be called when no 1215906Sgm89044 * active jobs (hence DMA mappings) exist. One way to ensure this is 1216906Sgm89044 * to unregister from kCF before calling this routine. (This is done 1217906Sgm89044 * e.g. in detach(9e).) 1218906Sgm89044 */ 1219906Sgm89044 void 1220906Sgm89044 dca_uninit(dca_t *dca) 1221906Sgm89044 { 1222906Sgm89044 int mcr; 1223906Sgm89044 1224906Sgm89044 mutex_destroy(&dca->dca_ctx_list_lock); 1225906Sgm89044 1226906Sgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) { 1227906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 1228906Sgm89044 dca_work_t *workp; 1229906Sgm89044 dca_request_t *reqp; 1230906Sgm89044 1231906Sgm89044 if (dca->dca_regs_handle == NULL) { 1232906Sgm89044 continue; 1233906Sgm89044 } 1234906Sgm89044 1235906Sgm89044 mutex_enter(&wlp->dwl_lock); 1236906Sgm89044 while ((workp = dca_getwork(dca, mcr)) != NULL) { 1237906Sgm89044 dca_destroywork(workp); 1238906Sgm89044 } 1239906Sgm89044 mutex_exit(&wlp->dwl_lock); 1240906Sgm89044 while ((reqp = dca_getreq(dca, mcr, 0)) != NULL) { 1241906Sgm89044 dca_destroyreq(reqp); 1242906Sgm89044 } 1243906Sgm89044 1244906Sgm89044 mutex_destroy(&wlp->dwl_lock); 1245906Sgm89044 mutex_destroy(&wlp->dwl_freereqslock); 1246*3124Sqs148142 mutex_destroy(&wlp->dwl_freelock); 1247906Sgm89044 cv_destroy(&wlp->dwl_cv); 1248906Sgm89044 wlp->dwl_prov = NULL; 1249906Sgm89044 } 1250906Sgm89044 } 1251906Sgm89044 1252906Sgm89044 static void 1253906Sgm89044 dca_enlist2(dca_listnode_t *q, dca_listnode_t *node, kmutex_t *lock) 1254906Sgm89044 { 1255906Sgm89044 if (!q || !node) 1256906Sgm89044 return; 1257906Sgm89044 1258906Sgm89044 mutex_enter(lock); 1259906Sgm89044 node->dl_next2 = q; 1260906Sgm89044 node->dl_prev2 = q->dl_prev2; 1261906Sgm89044 node->dl_next2->dl_prev2 = node; 1262906Sgm89044 node->dl_prev2->dl_next2 = node; 1263906Sgm89044 mutex_exit(lock); 1264906Sgm89044 } 1265906Sgm89044 1266906Sgm89044 static void 1267906Sgm89044 dca_rmlist2(dca_listnode_t *node, kmutex_t *lock) 1268906Sgm89044 { 1269906Sgm89044 if (!node) 1270906Sgm89044 return; 1271906Sgm89044 1272906Sgm89044 mutex_enter(lock); 1273906Sgm89044 node->dl_next2->dl_prev2 = node->dl_prev2; 1274906Sgm89044 node->dl_prev2->dl_next2 = node->dl_next2; 1275906Sgm89044 node->dl_next2 = NULL; 1276906Sgm89044 node->dl_prev2 = NULL; 1277906Sgm89044 mutex_exit(lock); 1278906Sgm89044 } 1279906Sgm89044 1280906Sgm89044 static dca_listnode_t * 1281906Sgm89044 dca_delist2(dca_listnode_t *q, kmutex_t *lock) 1282906Sgm89044 { 1283906Sgm89044 dca_listnode_t *node; 1284906Sgm89044 1285906Sgm89044 mutex_enter(lock); 1286906Sgm89044 if ((node = q->dl_next2) == q) { 1287906Sgm89044 mutex_exit(lock); 1288906Sgm89044 return (NULL); 1289906Sgm89044 } 1290906Sgm89044 1291906Sgm89044 node->dl_next2->dl_prev2 = node->dl_prev2; 1292906Sgm89044 node->dl_prev2->dl_next2 = node->dl_next2; 1293906Sgm89044 node->dl_next2 = NULL; 1294906Sgm89044 node->dl_prev2 = NULL; 1295906Sgm89044 mutex_exit(lock); 1296906Sgm89044 1297906Sgm89044 return (node); 1298906Sgm89044 } 1299906Sgm89044 1300906Sgm89044 void 1301906Sgm89044 dca_initq(dca_listnode_t *q) 1302906Sgm89044 { 1303906Sgm89044 q->dl_next = q; 1304906Sgm89044 q->dl_prev = q; 1305906Sgm89044 q->dl_next2 = q; 1306906Sgm89044 q->dl_prev2 = q; 1307906Sgm89044 } 1308906Sgm89044 1309906Sgm89044 void 1310906Sgm89044 dca_enqueue(dca_listnode_t *q, dca_listnode_t *node) 1311906Sgm89044 { 1312906Sgm89044 /* 1313906Sgm89044 * Enqueue submits at the "tail" of the list, i.e. just 1314906Sgm89044 * behind the sentinel. 1315906Sgm89044 */ 1316906Sgm89044 node->dl_next = q; 1317906Sgm89044 node->dl_prev = q->dl_prev; 1318906Sgm89044 node->dl_next->dl_prev = node; 1319906Sgm89044 node->dl_prev->dl_next = node; 1320906Sgm89044 } 1321906Sgm89044 1322906Sgm89044 void 1323906Sgm89044 dca_rmqueue(dca_listnode_t *node) 1324906Sgm89044 { 1325906Sgm89044 node->dl_next->dl_prev = node->dl_prev; 1326906Sgm89044 node->dl_prev->dl_next = node->dl_next; 1327906Sgm89044 node->dl_next = NULL; 1328906Sgm89044 node->dl_prev = NULL; 1329906Sgm89044 } 1330906Sgm89044 1331906Sgm89044 dca_listnode_t * 1332906Sgm89044 dca_dequeue(dca_listnode_t *q) 1333906Sgm89044 { 1334906Sgm89044 dca_listnode_t *node; 1335906Sgm89044 /* 1336906Sgm89044 * Dequeue takes from the "head" of the list, i.e. just after 1337906Sgm89044 * the sentinel. 1338906Sgm89044 */ 1339906Sgm89044 if ((node = q->dl_next) == q) { 1340906Sgm89044 /* queue is empty */ 1341906Sgm89044 return (NULL); 1342906Sgm89044 } 1343906Sgm89044 dca_rmqueue(node); 1344906Sgm89044 return (node); 1345906Sgm89044 } 1346906Sgm89044 1347906Sgm89044 /* this is the opposite of dequeue, it takes things off in LIFO order */ 1348906Sgm89044 dca_listnode_t * 1349906Sgm89044 dca_unqueue(dca_listnode_t *q) 1350906Sgm89044 { 1351906Sgm89044 dca_listnode_t *node; 1352906Sgm89044 /* 1353906Sgm89044 * unqueue takes from the "tail" of the list, i.e. just before 1354906Sgm89044 * the sentinel. 1355906Sgm89044 */ 1356906Sgm89044 if ((node = q->dl_prev) == q) {; 1357906Sgm89044 /* queue is empty */ 1358906Sgm89044 return (NULL); 1359906Sgm89044 } 1360906Sgm89044 dca_rmqueue(node); 1361906Sgm89044 return (node); 1362906Sgm89044 } 1363906Sgm89044 1364906Sgm89044 dca_listnode_t * 1365906Sgm89044 dca_peekqueue(dca_listnode_t *q) 1366906Sgm89044 { 1367906Sgm89044 dca_listnode_t *node; 1368906Sgm89044 1369906Sgm89044 if ((node = q->dl_next) == q) { 1370906Sgm89044 return (NULL); 1371906Sgm89044 } else { 1372906Sgm89044 return (node); 1373906Sgm89044 } 1374906Sgm89044 } 1375906Sgm89044 1376906Sgm89044 /* 1377906Sgm89044 * Interrupt service routine. 1378906Sgm89044 */ 1379906Sgm89044 uint_t 1380906Sgm89044 dca_intr(char *arg) 1381906Sgm89044 { 1382906Sgm89044 dca_t *dca = (dca_t *)arg; 1383906Sgm89044 uint32_t status; 1384906Sgm89044 1385906Sgm89044 mutex_enter(&dca->dca_intrlock); 1386906Sgm89044 status = GETCSR(dca, CSR_DMASTAT); 1387906Sgm89044 PUTCSR(dca, CSR_DMASTAT, status & DMASTAT_INTERRUPTS); 1388906Sgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle, 1389906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 1390906Sgm89044 mutex_exit(&dca->dca_intrlock); 1391906Sgm89044 return ((uint_t)DDI_FAILURE); 1392906Sgm89044 } 1393906Sgm89044 1394906Sgm89044 DBG(dca, DINTR, "interrupted, status = 0x%x!", status); 1395906Sgm89044 1396906Sgm89044 if ((status & DMASTAT_INTERRUPTS) == 0) { 1397906Sgm89044 /* increment spurious interrupt kstat */ 1398906Sgm89044 if (dca->dca_intrstats) { 1399906Sgm89044 KIOIP(dca)->intrs[KSTAT_INTR_SPURIOUS]++; 1400906Sgm89044 } 1401906Sgm89044 mutex_exit(&dca->dca_intrlock); 1402906Sgm89044 return (DDI_INTR_UNCLAIMED); 1403906Sgm89044 } 1404906Sgm89044 1405906Sgm89044 if (dca->dca_intrstats) { 1406906Sgm89044 KIOIP(dca)->intrs[KSTAT_INTR_HARD]++; 1407906Sgm89044 } 1408906Sgm89044 if (status & DMASTAT_MCR1INT) { 1409906Sgm89044 DBG(dca, DINTR, "MCR1 interrupted"); 1410906Sgm89044 mutex_enter(&(WORKLIST(dca, MCR1)->dwl_lock)); 1411906Sgm89044 dca_schedule(dca, MCR1); 1412906Sgm89044 dca_reclaim(dca, MCR1); 1413906Sgm89044 mutex_exit(&(WORKLIST(dca, MCR1)->dwl_lock)); 1414906Sgm89044 } 1415906Sgm89044 1416906Sgm89044 if (status & DMASTAT_MCR2INT) { 1417906Sgm89044 DBG(dca, DINTR, "MCR2 interrupted"); 1418906Sgm89044 mutex_enter(&(WORKLIST(dca, MCR2)->dwl_lock)); 1419906Sgm89044 dca_schedule(dca, MCR2); 1420906Sgm89044 dca_reclaim(dca, MCR2); 1421906Sgm89044 mutex_exit(&(WORKLIST(dca, MCR2)->dwl_lock)); 1422906Sgm89044 } 1423906Sgm89044 1424906Sgm89044 if (status & DMASTAT_ERRINT) { 1425906Sgm89044 uint32_t erraddr; 1426906Sgm89044 erraddr = GETCSR(dca, CSR_DMAEA); 1427906Sgm89044 mutex_exit(&dca->dca_intrlock); 1428906Sgm89044 1429906Sgm89044 /* 1430906Sgm89044 * bit 1 of the error address indicates failure during 1431906Sgm89044 * read if set, during write otherwise. 1432906Sgm89044 */ 1433906Sgm89044 dca_failure(dca, DDI_DEVICE_FAULT, 1434906Sgm89044 DCA_FM_ECLASS_HW_DEVICE, dca_ena(0), CRYPTO_DEVICE_ERROR, 1435906Sgm89044 "DMA master access error %s address 0x%x", 1436906Sgm89044 erraddr & 0x1 ? "reading" : "writing", erraddr & ~1); 1437906Sgm89044 return (DDI_INTR_CLAIMED); 1438906Sgm89044 } 1439906Sgm89044 1440906Sgm89044 mutex_exit(&dca->dca_intrlock); 1441906Sgm89044 1442906Sgm89044 return (DDI_INTR_CLAIMED); 1443906Sgm89044 } 1444906Sgm89044 1445906Sgm89044 /* 1446906Sgm89044 * Reverse a string of bytes from s1 into s2. The reversal happens 1447906Sgm89044 * from the tail of s1. If len1 < len2, then null bytes will be 1448906Sgm89044 * padded to the end of s2. If len2 < len1, then (presumably null) 1449906Sgm89044 * bytes will be dropped from the start of s1. 1450906Sgm89044 * 1451906Sgm89044 * The rationale here is that when s1 (source) is shorter, then we 1452906Sgm89044 * are reversing from big-endian ordering, into device ordering, and 1453906Sgm89044 * want to add some extra nulls to the tail (MSB) side of the device. 1454906Sgm89044 * 1455906Sgm89044 * Similarly, when s2 (dest) is shorter, then we are truncating what 1456906Sgm89044 * are presumably null MSB bits from the device. 1457906Sgm89044 * 1458906Sgm89044 * There is an expectation when reversing from the device back into 1459906Sgm89044 * big-endian, that the number of bytes to reverse and the target size 1460906Sgm89044 * will match, and no truncation or padding occurs. 1461906Sgm89044 */ 1462906Sgm89044 void 1463906Sgm89044 dca_reverse(void *s1, void *s2, int len1, int len2) 1464906Sgm89044 { 1465906Sgm89044 caddr_t src, dst; 1466906Sgm89044 1467906Sgm89044 if (len1 == 0) { 1468906Sgm89044 if (len2) { 1469906Sgm89044 bzero(s2, len2); 1470906Sgm89044 } 1471906Sgm89044 return; 1472906Sgm89044 } 1473906Sgm89044 src = (caddr_t)s1 + len1 - 1; 1474906Sgm89044 dst = s2; 1475906Sgm89044 while ((src >= (caddr_t)s1) && (len2)) { 1476906Sgm89044 *dst++ = *src--; 1477906Sgm89044 len2--; 1478906Sgm89044 } 1479906Sgm89044 while (len2 > 0) { 1480906Sgm89044 *dst++ = 0; 1481906Sgm89044 len2--; 1482906Sgm89044 } 1483906Sgm89044 } 1484906Sgm89044 1485906Sgm89044 uint16_t 1486906Sgm89044 dca_padfull(int num) 1487906Sgm89044 { 1488906Sgm89044 if (num <= 512) { 1489906Sgm89044 return (BITS2BYTES(512)); 1490906Sgm89044 } 1491906Sgm89044 if (num <= 768) { 1492906Sgm89044 return (BITS2BYTES(768)); 1493906Sgm89044 } 1494906Sgm89044 if (num <= 1024) { 1495906Sgm89044 return (BITS2BYTES(1024)); 1496906Sgm89044 } 1497906Sgm89044 if (num <= 1536) { 1498906Sgm89044 return (BITS2BYTES(1536)); 1499906Sgm89044 } 1500906Sgm89044 if (num <= 2048) { 1501906Sgm89044 return (BITS2BYTES(2048)); 1502906Sgm89044 } 1503906Sgm89044 return (0); 1504906Sgm89044 } 1505906Sgm89044 1506906Sgm89044 uint16_t 1507906Sgm89044 dca_padhalf(int num) 1508906Sgm89044 { 1509906Sgm89044 if (num <= 256) { 1510906Sgm89044 return (BITS2BYTES(256)); 1511906Sgm89044 } 1512906Sgm89044 if (num <= 384) { 1513906Sgm89044 return (BITS2BYTES(384)); 1514906Sgm89044 } 1515906Sgm89044 if (num <= 512) { 1516906Sgm89044 return (BITS2BYTES(512)); 1517906Sgm89044 } 1518906Sgm89044 if (num <= 768) { 1519906Sgm89044 return (BITS2BYTES(768)); 1520906Sgm89044 } 1521906Sgm89044 if (num <= 1024) { 1522906Sgm89044 return (BITS2BYTES(1024)); 1523906Sgm89044 } 1524906Sgm89044 return (0); 1525906Sgm89044 } 1526906Sgm89044 1527906Sgm89044 dca_work_t * 1528906Sgm89044 dca_newwork(dca_t *dca) 1529906Sgm89044 { 1530906Sgm89044 dca_work_t *workp; 1531906Sgm89044 size_t size; 1532906Sgm89044 ddi_dma_cookie_t c; 1533906Sgm89044 unsigned nc; 1534906Sgm89044 int rv; 1535906Sgm89044 1536906Sgm89044 workp = kmem_zalloc(sizeof (dca_work_t), KM_SLEEP); 1537906Sgm89044 1538906Sgm89044 rv = ddi_dma_alloc_handle(dca->dca_dip, &dca_dmaattr, 1539906Sgm89044 DDI_DMA_SLEEP, NULL, &workp->dw_mcr_dmah); 1540906Sgm89044 if (rv != 0) { 1541906Sgm89044 dca_error(dca, "unable to alloc MCR DMA handle"); 1542906Sgm89044 dca_destroywork(workp); 1543906Sgm89044 return (NULL); 1544906Sgm89044 } 1545906Sgm89044 1546906Sgm89044 rv = ddi_dma_mem_alloc(workp->dw_mcr_dmah, 1547906Sgm89044 ROUNDUP(MCR_SIZE, dca->dca_pagesize), 1548906Sgm89044 &dca_devattr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 1549906Sgm89044 &workp->dw_mcr_kaddr, &size, &workp->dw_mcr_acch); 1550906Sgm89044 if (rv != 0) { 1551906Sgm89044 dca_error(dca, "unable to alloc MCR DMA memory"); 1552906Sgm89044 dca_destroywork(workp); 1553906Sgm89044 return (NULL); 1554906Sgm89044 } 1555906Sgm89044 1556906Sgm89044 rv = ddi_dma_addr_bind_handle(workp->dw_mcr_dmah, NULL, 1557906Sgm89044 workp->dw_mcr_kaddr, size, DDI_DMA_CONSISTENT | DDI_DMA_RDWR, 1558906Sgm89044 DDI_DMA_SLEEP, NULL, &c, &nc); 1559906Sgm89044 if (rv != DDI_DMA_MAPPED) { 1560906Sgm89044 dca_error(dca, "unable to map MCR DMA memory"); 1561906Sgm89044 dca_destroywork(workp); 1562906Sgm89044 return (NULL); 1563906Sgm89044 } 1564906Sgm89044 1565906Sgm89044 workp->dw_mcr_paddr = c.dmac_address; 1566906Sgm89044 return (workp); 1567906Sgm89044 } 1568906Sgm89044 1569906Sgm89044 void 1570906Sgm89044 dca_destroywork(dca_work_t *workp) 1571906Sgm89044 { 1572906Sgm89044 if (workp->dw_mcr_paddr) { 1573906Sgm89044 (void) ddi_dma_unbind_handle(workp->dw_mcr_dmah); 1574906Sgm89044 } 1575906Sgm89044 if (workp->dw_mcr_acch) { 1576906Sgm89044 ddi_dma_mem_free(&workp->dw_mcr_acch); 1577906Sgm89044 } 1578906Sgm89044 if (workp->dw_mcr_dmah) { 1579906Sgm89044 ddi_dma_free_handle(&workp->dw_mcr_dmah); 1580906Sgm89044 } 1581906Sgm89044 kmem_free(workp, sizeof (dca_work_t)); 1582906Sgm89044 } 1583906Sgm89044 1584906Sgm89044 dca_request_t * 1585906Sgm89044 dca_newreq(dca_t *dca) 1586906Sgm89044 { 1587906Sgm89044 dca_request_t *reqp; 1588906Sgm89044 size_t size; 1589906Sgm89044 ddi_dma_cookie_t c; 1590906Sgm89044 unsigned nc; 1591906Sgm89044 int rv; 1592906Sgm89044 int n_chain = 0; 1593906Sgm89044 1594906Sgm89044 size = (DESC_SIZE * MAXFRAGS) + CTX_MAXLENGTH; 1595906Sgm89044 1596906Sgm89044 reqp = kmem_zalloc(sizeof (dca_request_t), KM_SLEEP); 1597906Sgm89044 1598906Sgm89044 reqp->dr_dca = dca; 1599906Sgm89044 1600906Sgm89044 /* 1601906Sgm89044 * Setup the DMA region for the context and descriptors. 1602906Sgm89044 */ 1603906Sgm89044 rv = ddi_dma_alloc_handle(dca->dca_dip, &dca_dmaattr, DDI_DMA_SLEEP, 1604906Sgm89044 NULL, &reqp->dr_ctx_dmah); 1605906Sgm89044 if (rv != DDI_SUCCESS) { 1606906Sgm89044 dca_error(dca, "failure allocating request DMA handle"); 1607906Sgm89044 dca_destroyreq(reqp); 1608906Sgm89044 return (NULL); 1609906Sgm89044 } 1610906Sgm89044 1611906Sgm89044 /* for driver hardening, allocate in whole pages */ 1612906Sgm89044 rv = ddi_dma_mem_alloc(reqp->dr_ctx_dmah, 1613906Sgm89044 ROUNDUP(size, dca->dca_pagesize), &dca_devattr, DDI_DMA_CONSISTENT, 1614906Sgm89044 DDI_DMA_SLEEP, NULL, &reqp->dr_ctx_kaddr, &size, 1615906Sgm89044 &reqp->dr_ctx_acch); 1616906Sgm89044 if (rv != DDI_SUCCESS) { 1617906Sgm89044 dca_error(dca, "unable to alloc request DMA memory"); 1618906Sgm89044 dca_destroyreq(reqp); 1619906Sgm89044 return (NULL); 1620906Sgm89044 } 1621906Sgm89044 1622906Sgm89044 rv = ddi_dma_addr_bind_handle(reqp->dr_ctx_dmah, NULL, 1623906Sgm89044 reqp->dr_ctx_kaddr, size, DDI_DMA_CONSISTENT | DDI_DMA_WRITE, 1624906Sgm89044 DDI_DMA_SLEEP, 0, &c, &nc); 1625906Sgm89044 if (rv != DDI_DMA_MAPPED) { 1626906Sgm89044 dca_error(dca, "failed binding request DMA handle"); 1627906Sgm89044 dca_destroyreq(reqp); 1628906Sgm89044 return (NULL); 1629906Sgm89044 } 1630906Sgm89044 reqp->dr_ctx_paddr = c.dmac_address; 1631906Sgm89044 1632906Sgm89044 reqp->dr_dma_size = size; 1633906Sgm89044 1634906Sgm89044 /* 1635906Sgm89044 * Set up the dma for our scratch/shared buffers. 1636906Sgm89044 */ 1637906Sgm89044 rv = ddi_dma_alloc_handle(dca->dca_dip, &dca_dmaattr, 1638906Sgm89044 DDI_DMA_SLEEP, NULL, &reqp->dr_ibuf_dmah); 1639906Sgm89044 if (rv != DDI_SUCCESS) { 1640906Sgm89044 dca_error(dca, "failure allocating ibuf DMA handle"); 1641906Sgm89044 dca_destroyreq(reqp); 1642906Sgm89044 return (NULL); 1643906Sgm89044 } 1644906Sgm89044 rv = ddi_dma_alloc_handle(dca->dca_dip, &dca_dmaattr, 1645906Sgm89044 DDI_DMA_SLEEP, NULL, &reqp->dr_obuf_dmah); 1646906Sgm89044 if (rv != DDI_SUCCESS) { 1647906Sgm89044 dca_error(dca, "failure allocating obuf DMA handle"); 1648906Sgm89044 dca_destroyreq(reqp); 1649906Sgm89044 return (NULL); 1650906Sgm89044 } 1651906Sgm89044 1652906Sgm89044 rv = ddi_dma_alloc_handle(dca->dca_dip, &dca_dmaattr, 1653906Sgm89044 DDI_DMA_SLEEP, NULL, &reqp->dr_chain_in_dmah); 1654906Sgm89044 if (rv != DDI_SUCCESS) { 1655906Sgm89044 dca_error(dca, "failure allocating chain_in DMA handle"); 1656906Sgm89044 dca_destroyreq(reqp); 1657906Sgm89044 return (NULL); 1658906Sgm89044 } 1659906Sgm89044 1660906Sgm89044 rv = ddi_dma_alloc_handle(dca->dca_dip, &dca_dmaattr, 1661906Sgm89044 DDI_DMA_SLEEP, NULL, &reqp->dr_chain_out_dmah); 1662906Sgm89044 if (rv != DDI_SUCCESS) { 1663906Sgm89044 dca_error(dca, "failure allocating chain_out DMA handle"); 1664906Sgm89044 dca_destroyreq(reqp); 1665906Sgm89044 return (NULL); 1666906Sgm89044 } 1667906Sgm89044 1668906Sgm89044 /* 1669906Sgm89044 * for driver hardening, allocate in whole pages. 1670906Sgm89044 */ 1671906Sgm89044 size = ROUNDUP(MAXPACKET, dca->dca_pagesize); 1672906Sgm89044 #if defined(i386) || defined(__i386) 1673906Sgm89044 /* 1674906Sgm89044 * Use kmem_alloc instead of ddi_dma_mem_alloc here since the latter 1675906Sgm89044 * may fail on x86 platform if a physically contigous memory chunk 1676906Sgm89044 * cannot be found. From initial testing, we did not see performance 1677906Sgm89044 * degration as seen on Sparc. 1678906Sgm89044 */ 1679906Sgm89044 if ((reqp->dr_ibuf_kaddr = kmem_alloc(size, KM_SLEEP)) == NULL) { 1680906Sgm89044 dca_error(dca, "unable to alloc request ibuf memory"); 1681906Sgm89044 dca_destroyreq(reqp); 1682906Sgm89044 return (NULL); 1683906Sgm89044 } 1684906Sgm89044 if ((reqp->dr_obuf_kaddr = kmem_alloc(size, KM_SLEEP)) == NULL) { 1685906Sgm89044 dca_error(dca, "unable to alloc request obuf memory"); 1686906Sgm89044 dca_destroyreq(reqp); 1687906Sgm89044 return (NULL); 1688906Sgm89044 } 1689906Sgm89044 #else 1690906Sgm89044 /* 1691906Sgm89044 * We could kmem_alloc for sparc too. However, it gives worse 1692906Sgm89044 * performance when transfering more than one page data. For example, 1693906Sgm89044 * using 4 threads and 12032 byte data and 3DES on 900MHZ sparc system, 1694906Sgm89044 * kmem_alloc uses 80% CPU and ddi_dma_mem_alloc uses 50% CPU for 1695906Sgm89044 * the same throughput. 1696906Sgm89044 */ 1697906Sgm89044 rv = ddi_dma_mem_alloc(reqp->dr_ibuf_dmah, 1698906Sgm89044 size, &dca_bufattr, 1699906Sgm89044 DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &reqp->dr_ibuf_kaddr, 1700906Sgm89044 &size, &reqp->dr_ibuf_acch); 1701906Sgm89044 if (rv != DDI_SUCCESS) { 1702906Sgm89044 dca_error(dca, "unable to alloc request DMA memory"); 1703906Sgm89044 dca_destroyreq(reqp); 1704906Sgm89044 return (NULL); 1705906Sgm89044 } 1706906Sgm89044 1707906Sgm89044 rv = ddi_dma_mem_alloc(reqp->dr_obuf_dmah, 1708906Sgm89044 size, &dca_bufattr, 1709906Sgm89044 DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &reqp->dr_obuf_kaddr, 1710906Sgm89044 &size, &reqp->dr_obuf_acch); 1711906Sgm89044 if (rv != DDI_SUCCESS) { 1712906Sgm89044 dca_error(dca, "unable to alloc request DMA memory"); 1713906Sgm89044 dca_destroyreq(reqp); 1714906Sgm89044 return (NULL); 1715906Sgm89044 } 1716906Sgm89044 #endif 1717906Sgm89044 1718906Sgm89044 /* Skip the used portion in the context page */ 1719906Sgm89044 reqp->dr_offset = CTX_MAXLENGTH; 1720906Sgm89044 if ((rv = dca_bindchains_one(reqp, size, reqp->dr_offset, 1721906Sgm89044 reqp->dr_ibuf_kaddr, reqp->dr_ibuf_dmah, 1722906Sgm89044 DDI_DMA_WRITE | DDI_DMA_STREAMING, 1723906Sgm89044 &reqp->dr_ibuf_head, &n_chain)) != DDI_SUCCESS) { 1724906Sgm89044 (void) dca_destroyreq(reqp); 1725906Sgm89044 return (NULL); 1726906Sgm89044 } 1727906Sgm89044 reqp->dr_ibuf_paddr = reqp->dr_ibuf_head.dc_buffer_paddr; 1728906Sgm89044 /* Skip the space used by the input buffer */ 1729906Sgm89044 reqp->dr_offset += DESC_SIZE * n_chain; 1730906Sgm89044 1731906Sgm89044 if ((rv = dca_bindchains_one(reqp, size, reqp->dr_offset, 1732906Sgm89044 reqp->dr_obuf_kaddr, reqp->dr_obuf_dmah, 1733906Sgm89044 DDI_DMA_READ | DDI_DMA_STREAMING, 1734906Sgm89044 &reqp->dr_obuf_head, &n_chain)) != DDI_SUCCESS) { 1735906Sgm89044 (void) dca_destroyreq(reqp); 1736906Sgm89044 return (NULL); 1737906Sgm89044 } 1738906Sgm89044 reqp->dr_obuf_paddr = reqp->dr_obuf_head.dc_buffer_paddr; 1739906Sgm89044 /* Skip the space used by the output buffer */ 1740906Sgm89044 reqp->dr_offset += DESC_SIZE * n_chain; 1741906Sgm89044 1742906Sgm89044 DBG(dca, DCHATTY, "CTX is 0x%p, phys 0x%x, len %d", 1743906Sgm89044 reqp->dr_ctx_kaddr, reqp->dr_ctx_paddr, CTX_MAXLENGTH); 1744906Sgm89044 return (reqp); 1745906Sgm89044 } 1746906Sgm89044 1747906Sgm89044 void 1748906Sgm89044 dca_destroyreq(dca_request_t *reqp) 1749906Sgm89044 { 1750906Sgm89044 #if defined(i386) || defined(__i386) 1751906Sgm89044 dca_t *dca = reqp->dr_dca; 1752906Sgm89044 size_t size = ROUNDUP(MAXPACKET, dca->dca_pagesize); 1753906Sgm89044 #endif 1754906Sgm89044 1755906Sgm89044 /* 1756906Sgm89044 * Clean up DMA for the context structure. 1757906Sgm89044 */ 1758906Sgm89044 if (reqp->dr_ctx_paddr) { 1759906Sgm89044 (void) ddi_dma_unbind_handle(reqp->dr_ctx_dmah); 1760906Sgm89044 } 1761906Sgm89044 1762906Sgm89044 if (reqp->dr_ctx_acch) { 1763906Sgm89044 ddi_dma_mem_free(&reqp->dr_ctx_acch); 1764906Sgm89044 } 1765906Sgm89044 1766906Sgm89044 if (reqp->dr_ctx_dmah) { 1767906Sgm89044 ddi_dma_free_handle(&reqp->dr_ctx_dmah); 1768906Sgm89044 } 1769906Sgm89044 1770906Sgm89044 /* 1771906Sgm89044 * Clean up DMA for the scratch buffer. 1772906Sgm89044 */ 1773906Sgm89044 #if defined(i386) || defined(__i386) 1774906Sgm89044 if (reqp->dr_ibuf_dmah) { 1775906Sgm89044 (void) ddi_dma_unbind_handle(reqp->dr_ibuf_dmah); 1776906Sgm89044 ddi_dma_free_handle(&reqp->dr_ibuf_dmah); 1777906Sgm89044 } 1778906Sgm89044 if (reqp->dr_obuf_dmah) { 1779906Sgm89044 (void) ddi_dma_unbind_handle(reqp->dr_obuf_dmah); 1780906Sgm89044 ddi_dma_free_handle(&reqp->dr_obuf_dmah); 1781906Sgm89044 } 1782906Sgm89044 1783906Sgm89044 kmem_free(reqp->dr_ibuf_kaddr, size); 1784906Sgm89044 kmem_free(reqp->dr_obuf_kaddr, size); 1785906Sgm89044 #else 1786906Sgm89044 if (reqp->dr_ibuf_paddr) { 1787906Sgm89044 (void) ddi_dma_unbind_handle(reqp->dr_ibuf_dmah); 1788906Sgm89044 } 1789906Sgm89044 if (reqp->dr_obuf_paddr) { 1790906Sgm89044 (void) ddi_dma_unbind_handle(reqp->dr_obuf_dmah); 1791906Sgm89044 } 1792906Sgm89044 1793906Sgm89044 if (reqp->dr_ibuf_acch) { 1794906Sgm89044 ddi_dma_mem_free(&reqp->dr_ibuf_acch); 1795906Sgm89044 } 1796906Sgm89044 if (reqp->dr_obuf_acch) { 1797906Sgm89044 ddi_dma_mem_free(&reqp->dr_obuf_acch); 1798906Sgm89044 } 1799906Sgm89044 1800906Sgm89044 if (reqp->dr_ibuf_dmah) { 1801906Sgm89044 ddi_dma_free_handle(&reqp->dr_ibuf_dmah); 1802906Sgm89044 } 1803906Sgm89044 if (reqp->dr_obuf_dmah) { 1804906Sgm89044 ddi_dma_free_handle(&reqp->dr_obuf_dmah); 1805906Sgm89044 } 1806906Sgm89044 #endif 1807906Sgm89044 /* 1808906Sgm89044 * These two DMA handles should have been unbinded in 1809906Sgm89044 * dca_unbindchains() function 1810906Sgm89044 */ 1811906Sgm89044 if (reqp->dr_chain_in_dmah) { 1812906Sgm89044 ddi_dma_free_handle(&reqp->dr_chain_in_dmah); 1813906Sgm89044 } 1814906Sgm89044 if (reqp->dr_chain_out_dmah) { 1815906Sgm89044 ddi_dma_free_handle(&reqp->dr_chain_out_dmah); 1816906Sgm89044 } 1817906Sgm89044 1818906Sgm89044 kmem_free(reqp, sizeof (dca_request_t)); 1819906Sgm89044 } 1820906Sgm89044 1821906Sgm89044 dca_work_t * 1822906Sgm89044 dca_getwork(dca_t *dca, int mcr) 1823906Sgm89044 { 1824906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 1825906Sgm89044 dca_work_t *workp; 1826906Sgm89044 1827*3124Sqs148142 mutex_enter(&wlp->dwl_freelock); 1828906Sgm89044 workp = (dca_work_t *)dca_dequeue(&wlp->dwl_freework); 1829*3124Sqs148142 mutex_exit(&wlp->dwl_freelock); 1830906Sgm89044 if (workp) { 1831906Sgm89044 int nreqs; 1832906Sgm89044 bzero(workp->dw_mcr_kaddr, 8); 1833906Sgm89044 1834906Sgm89044 /* clear out old requests */ 1835906Sgm89044 for (nreqs = 0; nreqs < MAXREQSPERMCR; nreqs++) { 1836906Sgm89044 workp->dw_reqs[nreqs] = NULL; 1837906Sgm89044 } 1838906Sgm89044 } 1839906Sgm89044 return (workp); 1840906Sgm89044 } 1841906Sgm89044 1842906Sgm89044 void 1843906Sgm89044 dca_freework(dca_work_t *workp) 1844906Sgm89044 { 1845*3124Sqs148142 mutex_enter(&workp->dw_wlp->dwl_freelock); 1846906Sgm89044 dca_enqueue(&workp->dw_wlp->dwl_freework, (dca_listnode_t *)workp); 1847*3124Sqs148142 mutex_exit(&workp->dw_wlp->dwl_freelock); 1848906Sgm89044 } 1849906Sgm89044 1850906Sgm89044 dca_request_t * 1851906Sgm89044 dca_getreq(dca_t *dca, int mcr, int tryhard) 1852906Sgm89044 { 1853906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 1854906Sgm89044 dca_request_t *reqp; 1855906Sgm89044 1856906Sgm89044 mutex_enter(&wlp->dwl_freereqslock); 1857906Sgm89044 reqp = (dca_request_t *)dca_dequeue(&wlp->dwl_freereqs); 1858906Sgm89044 mutex_exit(&wlp->dwl_freereqslock); 1859906Sgm89044 if (reqp) { 1860906Sgm89044 reqp->dr_flags = 0; 1861906Sgm89044 reqp->dr_callback = NULL; 1862906Sgm89044 } else if (tryhard) { 1863906Sgm89044 /* 1864906Sgm89044 * failed to get a free one, try an allocation, the hard way. 1865906Sgm89044 * XXX: Kstat desired here. 1866906Sgm89044 */ 1867906Sgm89044 if ((reqp = dca_newreq(dca)) != NULL) { 1868906Sgm89044 reqp->dr_wlp = wlp; 1869906Sgm89044 reqp->dr_dca = dca; 1870906Sgm89044 reqp->dr_flags = 0; 1871906Sgm89044 reqp->dr_callback = NULL; 1872906Sgm89044 } 1873906Sgm89044 } 1874906Sgm89044 return (reqp); 1875906Sgm89044 } 1876906Sgm89044 1877906Sgm89044 void 1878906Sgm89044 dca_freereq(dca_request_t *reqp) 1879906Sgm89044 { 1880906Sgm89044 reqp->dr_kcf_req = NULL; 1881906Sgm89044 if (!(reqp->dr_flags & DR_NOCACHE)) { 1882906Sgm89044 mutex_enter(&reqp->dr_wlp->dwl_freereqslock); 1883906Sgm89044 dca_enqueue(&reqp->dr_wlp->dwl_freereqs, 1884906Sgm89044 (dca_listnode_t *)reqp); 1885906Sgm89044 mutex_exit(&reqp->dr_wlp->dwl_freereqslock); 1886906Sgm89044 } 1887906Sgm89044 } 1888906Sgm89044 1889906Sgm89044 /* 1890906Sgm89044 * Binds user buffers to DMA handles dynamically. On Sparc, a user buffer 1891906Sgm89044 * is mapped to a single physicall address. On x86, a user buffer is mapped 1892906Sgm89044 * to multiple physically addresses. These phsyical addresses are chained 1893906Sgm89044 * using the method specified in Broadcom BCM5820 specification 1894906Sgm89044 */ 1895906Sgm89044 int 1896906Sgm89044 dca_bindchains(dca_request_t *reqp, size_t incnt, size_t outcnt) 1897906Sgm89044 { 1898906Sgm89044 int rv; 1899906Sgm89044 caddr_t kaddr; 1900906Sgm89044 uint_t flags; 1901906Sgm89044 int n_chain = 0; 1902906Sgm89044 1903906Sgm89044 if (reqp->dr_flags & DR_INPLACE) { 1904906Sgm89044 flags = DDI_DMA_RDWR | DDI_DMA_CONSISTENT; 1905906Sgm89044 } else { 1906906Sgm89044 flags = DDI_DMA_WRITE | DDI_DMA_STREAMING; 1907906Sgm89044 } 1908906Sgm89044 1909906Sgm89044 /* first the input */ 1910906Sgm89044 if (incnt) { 1911906Sgm89044 if ((kaddr = dca_bufdaddr(reqp->dr_in)) == NULL) { 1912906Sgm89044 DBG(NULL, DWARN, "unrecognised crypto data format"); 1913906Sgm89044 return (DDI_FAILURE); 1914906Sgm89044 } 1915906Sgm89044 if ((rv = dca_bindchains_one(reqp, incnt, reqp->dr_offset, 1916906Sgm89044 kaddr, reqp->dr_chain_in_dmah, flags, 1917906Sgm89044 &reqp->dr_chain_in_head, &n_chain)) != DDI_SUCCESS) { 1918906Sgm89044 (void) dca_unbindchains(reqp); 1919906Sgm89044 return (rv); 1920906Sgm89044 } 1921906Sgm89044 1922906Sgm89044 /* 1923906Sgm89044 * The offset and length are altered by the calling routine 1924906Sgm89044 * reqp->dr_in->cd_offset += incnt; 1925906Sgm89044 * reqp->dr_in->cd_length -= incnt; 1926906Sgm89044 */ 1927906Sgm89044 /* Save the first one in the chain for MCR */ 1928906Sgm89044 reqp->dr_in_paddr = reqp->dr_chain_in_head.dc_buffer_paddr; 1929906Sgm89044 reqp->dr_in_next = reqp->dr_chain_in_head.dc_next_paddr; 1930906Sgm89044 reqp->dr_in_len = reqp->dr_chain_in_head.dc_buffer_length; 1931906Sgm89044 } else { 1932906Sgm89044 reqp->dr_in_paddr = NULL; 1933906Sgm89044 reqp->dr_in_next = 0; 1934906Sgm89044 reqp->dr_in_len = 0; 1935906Sgm89044 } 1936906Sgm89044 1937906Sgm89044 if (reqp->dr_flags & DR_INPLACE) { 1938906Sgm89044 reqp->dr_out_paddr = reqp->dr_in_paddr; 1939906Sgm89044 reqp->dr_out_len = reqp->dr_in_len; 1940906Sgm89044 reqp->dr_out_next = reqp->dr_in_next; 1941906Sgm89044 return (DDI_SUCCESS); 1942906Sgm89044 } 1943906Sgm89044 1944906Sgm89044 /* then the output */ 1945906Sgm89044 if (outcnt) { 1946906Sgm89044 flags = DDI_DMA_READ | DDI_DMA_STREAMING; 1947906Sgm89044 if ((kaddr = dca_bufdaddr_out(reqp->dr_out)) == NULL) { 1948906Sgm89044 DBG(NULL, DWARN, "unrecognised crypto data format"); 1949906Sgm89044 (void) dca_unbindchains(reqp); 1950906Sgm89044 return (DDI_FAILURE); 1951906Sgm89044 } 1952906Sgm89044 rv = dca_bindchains_one(reqp, outcnt, reqp->dr_offset + 1953906Sgm89044 n_chain * DESC_SIZE, kaddr, reqp->dr_chain_out_dmah, 1954906Sgm89044 flags, &reqp->dr_chain_out_head, &n_chain); 1955906Sgm89044 if (rv != DDI_SUCCESS) { 1956906Sgm89044 (void) dca_unbindchains(reqp); 1957906Sgm89044 return (DDI_FAILURE); 1958906Sgm89044 } 1959906Sgm89044 1960906Sgm89044 /* Save the first one in the chain for MCR */ 1961906Sgm89044 reqp->dr_out_paddr = reqp->dr_chain_out_head.dc_buffer_paddr; 1962906Sgm89044 reqp->dr_out_next = reqp->dr_chain_out_head.dc_next_paddr; 1963906Sgm89044 reqp->dr_out_len = reqp->dr_chain_out_head.dc_buffer_length; 1964906Sgm89044 } else { 1965906Sgm89044 reqp->dr_out_paddr = NULL; 1966906Sgm89044 reqp->dr_out_next = 0; 1967906Sgm89044 reqp->dr_out_len = 0; 1968906Sgm89044 } 1969906Sgm89044 1970906Sgm89044 return (DDI_SUCCESS); 1971906Sgm89044 } 1972906Sgm89044 1973906Sgm89044 /* 1974906Sgm89044 * Unbind the user buffers from the DMA handles. 1975906Sgm89044 */ 1976906Sgm89044 int 1977906Sgm89044 dca_unbindchains(dca_request_t *reqp) 1978906Sgm89044 { 1979906Sgm89044 int rv = DDI_SUCCESS; 1980906Sgm89044 int rv1 = DDI_SUCCESS; 1981906Sgm89044 1982906Sgm89044 /* Clear the input chain */ 1983906Sgm89044 if (reqp->dr_chain_in_head.dc_buffer_paddr != NULL) { 1984906Sgm89044 (void) ddi_dma_unbind_handle(reqp->dr_chain_in_dmah); 1985906Sgm89044 reqp->dr_chain_in_head.dc_buffer_paddr = 0; 1986906Sgm89044 } 1987906Sgm89044 1988906Sgm89044 /* Clear the output chain */ 1989906Sgm89044 if (reqp->dr_chain_out_head.dc_buffer_paddr != NULL) { 1990906Sgm89044 (void) ddi_dma_unbind_handle(reqp->dr_chain_out_dmah); 1991906Sgm89044 reqp->dr_chain_out_head.dc_buffer_paddr = 0; 1992906Sgm89044 } 1993906Sgm89044 1994906Sgm89044 return ((rv != DDI_SUCCESS)? rv : rv1); 1995906Sgm89044 } 1996906Sgm89044 1997906Sgm89044 /* 1998906Sgm89044 * Build either input chain or output chain. It is single-item chain for Sparc, 1999906Sgm89044 * and possible mutiple-item chain for x86. 2000906Sgm89044 */ 2001906Sgm89044 static int 2002906Sgm89044 dca_bindchains_one(dca_request_t *reqp, size_t cnt, int dr_offset, 2003906Sgm89044 caddr_t kaddr, ddi_dma_handle_t handle, uint_t flags, 2004906Sgm89044 dca_chain_t *head, int *n_chain) 2005906Sgm89044 { 2006906Sgm89044 ddi_dma_cookie_t c; 2007906Sgm89044 uint_t nc; 2008906Sgm89044 int rv; 2009906Sgm89044 caddr_t chain_kaddr_pre; 2010906Sgm89044 caddr_t chain_kaddr; 2011906Sgm89044 uint32_t chain_paddr; 2012906Sgm89044 int i; 2013906Sgm89044 2014906Sgm89044 /* Advance past the context structure to the starting address */ 2015906Sgm89044 chain_paddr = reqp->dr_ctx_paddr + dr_offset; 2016906Sgm89044 chain_kaddr = reqp->dr_ctx_kaddr + dr_offset; 2017906Sgm89044 2018906Sgm89044 /* 2019906Sgm89044 * Bind the kernel address to the DMA handle. On x86, the actual 2020906Sgm89044 * buffer is mapped into multiple physical addresses. On Sparc, 2021906Sgm89044 * the actual buffer is mapped into a single address. 2022906Sgm89044 */ 2023906Sgm89044 rv = ddi_dma_addr_bind_handle(handle, 2024906Sgm89044 NULL, kaddr, cnt, flags, DDI_DMA_DONTWAIT, NULL, &c, &nc); 2025906Sgm89044 if (rv != DDI_DMA_MAPPED) { 2026906Sgm89044 return (DDI_FAILURE); 2027906Sgm89044 } 2028906Sgm89044 2029906Sgm89044 (void) ddi_dma_sync(handle, 0, cnt, DDI_DMA_SYNC_FORDEV); 2030906Sgm89044 if ((rv = dca_check_dma_handle(reqp->dr_dca, handle, 2031906Sgm89044 DCA_FM_ECLASS_NONE)) != DDI_SUCCESS) { 2032906Sgm89044 reqp->destroy = TRUE; 2033906Sgm89044 return (rv); 2034906Sgm89044 } 2035906Sgm89044 2036906Sgm89044 *n_chain = nc; 2037906Sgm89044 2038906Sgm89044 /* Setup the data buffer chain for DMA transfer */ 2039906Sgm89044 chain_kaddr_pre = NULL; 2040906Sgm89044 head->dc_buffer_paddr = 0; 2041906Sgm89044 head->dc_next_paddr = 0; 2042906Sgm89044 head->dc_buffer_length = 0; 2043906Sgm89044 for (i = 0; i < nc; i++) { 2044906Sgm89044 /* PIO */ 2045906Sgm89044 PUTDESC32(reqp, chain_kaddr, DESC_BUFADDR, c.dmac_address); 2046906Sgm89044 PUTDESC16(reqp, chain_kaddr, DESC_RSVD, 0); 2047906Sgm89044 PUTDESC16(reqp, chain_kaddr, DESC_LENGTH, c.dmac_size); 2048906Sgm89044 2049906Sgm89044 /* Remember the head of the chain */ 2050906Sgm89044 if (head->dc_buffer_paddr == 0) { 2051906Sgm89044 head->dc_buffer_paddr = c.dmac_address; 2052906Sgm89044 head->dc_buffer_length = c.dmac_size; 2053906Sgm89044 } 2054906Sgm89044 2055906Sgm89044 /* Link to the previous one if one exists */ 2056906Sgm89044 if (chain_kaddr_pre) { 2057906Sgm89044 PUTDESC32(reqp, chain_kaddr_pre, DESC_NEXT, 2058906Sgm89044 chain_paddr); 2059906Sgm89044 if (head->dc_next_paddr == 0) 2060906Sgm89044 head->dc_next_paddr = chain_paddr; 2061906Sgm89044 } 2062906Sgm89044 chain_kaddr_pre = chain_kaddr; 2063906Sgm89044 2064906Sgm89044 /* Maintain pointers */ 2065906Sgm89044 chain_paddr += DESC_SIZE; 2066906Sgm89044 chain_kaddr += DESC_SIZE; 2067906Sgm89044 2068906Sgm89044 /* Retrieve the next cookie if there is one */ 2069906Sgm89044 if (i < nc-1) 2070906Sgm89044 ddi_dma_nextcookie(handle, &c); 2071906Sgm89044 } 2072906Sgm89044 2073906Sgm89044 /* Set the next pointer in the last entry to NULL */ 2074906Sgm89044 PUTDESC32(reqp, chain_kaddr_pre, DESC_NEXT, 0); 2075906Sgm89044 2076906Sgm89044 return (DDI_SUCCESS); 2077906Sgm89044 } 2078906Sgm89044 2079906Sgm89044 /* 2080906Sgm89044 * Schedule some work. 2081906Sgm89044 */ 2082906Sgm89044 int 2083906Sgm89044 dca_start(dca_t *dca, dca_request_t *reqp, int mcr, int dosched) 2084906Sgm89044 { 2085906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 2086906Sgm89044 2087906Sgm89044 mutex_enter(&wlp->dwl_lock); 2088906Sgm89044 2089906Sgm89044 DBG(dca, DCHATTY, "req=%p, in=%p, out=%p, ctx=%p, ibuf=%p, obuf=%p", 2090906Sgm89044 reqp, reqp->dr_in, reqp->dr_out, reqp->dr_ctx_kaddr, 2091906Sgm89044 reqp->dr_ibuf_kaddr, reqp->dr_obuf_kaddr); 2092906Sgm89044 DBG(dca, DCHATTY, "ctx paddr = %x, ibuf paddr = %x, obuf paddr = %x", 2093906Sgm89044 reqp->dr_ctx_paddr, reqp->dr_ibuf_paddr, reqp->dr_obuf_paddr); 2094906Sgm89044 /* sync out the entire context and descriptor chains */ 2095906Sgm89044 (void) ddi_dma_sync(reqp->dr_ctx_dmah, 0, 0, DDI_DMA_SYNC_FORDEV); 2096906Sgm89044 if (dca_check_dma_handle(dca, reqp->dr_ctx_dmah, 2097906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 2098906Sgm89044 reqp->destroy = TRUE; 2099906Sgm89044 mutex_exit(&wlp->dwl_lock); 2100906Sgm89044 return (CRYPTO_DEVICE_ERROR); 2101906Sgm89044 } 2102906Sgm89044 2103906Sgm89044 dca_enqueue(&wlp->dwl_waitq, (dca_listnode_t *)reqp); 2104906Sgm89044 wlp->dwl_count++; 2105906Sgm89044 wlp->dwl_lastsubmit = ddi_get_lbolt(); 2106906Sgm89044 reqp->dr_wlp = wlp; 2107906Sgm89044 2108906Sgm89044 if ((wlp->dwl_count == wlp->dwl_hiwater) && (wlp->dwl_busy == 0)) { 2109906Sgm89044 /* we are fully loaded now, let kCF know */ 2110906Sgm89044 2111906Sgm89044 wlp->dwl_flowctl++; 2112906Sgm89044 wlp->dwl_busy = 1; 2113906Sgm89044 2114906Sgm89044 crypto_prov_notify(wlp->dwl_prov, CRYPTO_PROVIDER_BUSY); 2115906Sgm89044 } 2116906Sgm89044 2117906Sgm89044 if (dosched) { 2118906Sgm89044 #ifdef SCHEDDELAY 2119906Sgm89044 /* possibly wait for more work to arrive */ 2120906Sgm89044 if (wlp->dwl_count >= wlp->dwl_reqspermcr) { 2121906Sgm89044 dca_schedule(dca, mcr); 2122906Sgm89044 } else if (!wlp->dwl_schedtid) { 2123906Sgm89044 /* wait 1 msec for more work before doing it */ 2124906Sgm89044 wlp->dwl_schedtid = timeout(dca_schedtimeout, 2125906Sgm89044 (void *)wlp, drv_usectohz(MSEC)); 2126906Sgm89044 } 2127906Sgm89044 #else 2128906Sgm89044 dca_schedule(dca, mcr); 2129906Sgm89044 #endif 2130906Sgm89044 } 2131906Sgm89044 mutex_exit(&wlp->dwl_lock); 2132906Sgm89044 2133906Sgm89044 return (CRYPTO_QUEUED); 2134906Sgm89044 } 2135906Sgm89044 2136906Sgm89044 void 2137906Sgm89044 dca_schedule(dca_t *dca, int mcr) 2138906Sgm89044 { 2139906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 2140906Sgm89044 int csr; 2141906Sgm89044 int full; 2142906Sgm89044 uint32_t status; 2143906Sgm89044 2144906Sgm89044 ASSERT(mutex_owned(&wlp->dwl_lock)); 2145906Sgm89044 /* 2146906Sgm89044 * If the card is draining or has an outstanding failure, 2147906Sgm89044 * don't schedule any more work on it right now 2148906Sgm89044 */ 2149906Sgm89044 if (wlp->dwl_drain || (dca->dca_flags & DCA_FAILED)) { 2150906Sgm89044 return; 2151906Sgm89044 } 2152906Sgm89044 2153906Sgm89044 if (mcr == MCR2) { 2154906Sgm89044 csr = CSR_MCR2; 2155906Sgm89044 full = DMASTAT_MCR2FULL; 2156906Sgm89044 } else { 2157906Sgm89044 csr = CSR_MCR1; 2158906Sgm89044 full = DMASTAT_MCR1FULL; 2159906Sgm89044 } 2160906Sgm89044 2161906Sgm89044 for (;;) { 2162906Sgm89044 dca_work_t *workp; 2163906Sgm89044 uint32_t offset; 2164906Sgm89044 int nreqs; 2165906Sgm89044 2166906Sgm89044 status = GETCSR(dca, CSR_DMASTAT); 2167906Sgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle, 2168906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) 2169906Sgm89044 return; 2170906Sgm89044 2171906Sgm89044 if ((status & full) != 0) 2172906Sgm89044 break; 2173906Sgm89044 2174906Sgm89044 #ifdef SCHEDDELAY 2175906Sgm89044 /* if there isn't enough to do, don't bother now */ 2176906Sgm89044 if ((wlp->dwl_count < wlp->dwl_reqspermcr) && 2177906Sgm89044 (ddi_get_lbolt() < (wlp->dwl_lastsubmit + 2178906Sgm89044 drv_usectohz(MSEC)))) { 2179906Sgm89044 /* wait a bit longer... */ 2180906Sgm89044 if (wlp->dwl_schedtid == 0) { 2181906Sgm89044 wlp->dwl_schedtid = timeout(dca_schedtimeout, 2182906Sgm89044 (void *)wlp, drv_usectohz(MSEC)); 2183906Sgm89044 } 2184906Sgm89044 return; 2185906Sgm89044 } 2186906Sgm89044 #endif 2187906Sgm89044 2188906Sgm89044 /* grab a work structure */ 2189906Sgm89044 workp = dca_getwork(dca, mcr); 2190906Sgm89044 2191906Sgm89044 if (workp == NULL) { 2192906Sgm89044 /* 2193906Sgm89044 * There must be work ready to be reclaimed, 2194906Sgm89044 * in this case, since the chip can only hold 2195906Sgm89044 * less work outstanding than there are total. 2196906Sgm89044 */ 2197906Sgm89044 dca_reclaim(dca, mcr); 2198906Sgm89044 continue; 2199906Sgm89044 } 2200906Sgm89044 2201906Sgm89044 nreqs = 0; 2202906Sgm89044 offset = MCR_CTXADDR; 2203906Sgm89044 2204906Sgm89044 while (nreqs < wlp->dwl_reqspermcr) { 2205906Sgm89044 dca_request_t *reqp; 2206906Sgm89044 2207906Sgm89044 reqp = (dca_request_t *)dca_dequeue(&wlp->dwl_waitq); 2208906Sgm89044 if (reqp == NULL) { 2209906Sgm89044 /* nothing left to process */ 2210906Sgm89044 break; 2211906Sgm89044 } 2212906Sgm89044 /* 2213906Sgm89044 * Update flow control. 2214906Sgm89044 */ 2215906Sgm89044 wlp->dwl_count--; 2216906Sgm89044 if ((wlp->dwl_count == wlp->dwl_lowater) && 2217906Sgm89044 (wlp->dwl_busy)) { 2218906Sgm89044 wlp->dwl_busy = 0; 2219906Sgm89044 crypto_prov_notify(wlp->dwl_prov, 2220906Sgm89044 CRYPTO_PROVIDER_READY); 2221906Sgm89044 } 2222906Sgm89044 2223906Sgm89044 /* 2224906Sgm89044 * Context address. 2225906Sgm89044 */ 2226906Sgm89044 PUTMCR32(workp, offset, reqp->dr_ctx_paddr); 2227906Sgm89044 offset += 4; 2228906Sgm89044 2229906Sgm89044 /* 2230906Sgm89044 * Input chain. 2231906Sgm89044 */ 2232906Sgm89044 /* input buffer address */ 2233906Sgm89044 PUTMCR32(workp, offset, reqp->dr_in_paddr); 2234906Sgm89044 offset += 4; 2235906Sgm89044 /* next input buffer entry */ 2236906Sgm89044 PUTMCR32(workp, offset, reqp->dr_in_next); 2237906Sgm89044 offset += 4; 2238906Sgm89044 /* input buffer length */ 2239906Sgm89044 PUTMCR16(workp, offset, reqp->dr_in_len); 2240906Sgm89044 offset += 2; 2241906Sgm89044 /* zero the reserved field */ 2242906Sgm89044 PUTMCR16(workp, offset, 0); 2243906Sgm89044 offset += 2; 2244906Sgm89044 2245906Sgm89044 /* 2246906Sgm89044 * Overall length. 2247906Sgm89044 */ 2248906Sgm89044 /* reserved field */ 2249906Sgm89044 PUTMCR16(workp, offset, 0); 2250906Sgm89044 offset += 2; 2251906Sgm89044 /* total packet length */ 2252906Sgm89044 PUTMCR16(workp, offset, reqp->dr_pkt_length); 2253906Sgm89044 offset += 2; 2254906Sgm89044 2255906Sgm89044 /* 2256906Sgm89044 * Output chain. 2257906Sgm89044 */ 2258906Sgm89044 /* output buffer address */ 2259906Sgm89044 PUTMCR32(workp, offset, reqp->dr_out_paddr); 2260906Sgm89044 offset += 4; 2261906Sgm89044 /* next output buffer entry */ 2262906Sgm89044 PUTMCR32(workp, offset, reqp->dr_out_next); 2263906Sgm89044 offset += 4; 2264906Sgm89044 /* output buffer length */ 2265906Sgm89044 PUTMCR16(workp, offset, reqp->dr_out_len); 2266906Sgm89044 offset += 2; 2267906Sgm89044 /* zero the reserved field */ 2268906Sgm89044 PUTMCR16(workp, offset, 0); 2269906Sgm89044 offset += 2; 2270906Sgm89044 2271906Sgm89044 /* 2272906Sgm89044 * Note submission. 2273906Sgm89044 */ 2274906Sgm89044 workp->dw_reqs[nreqs] = reqp; 2275906Sgm89044 nreqs++; 2276906Sgm89044 } 2277906Sgm89044 2278906Sgm89044 if (nreqs == 0) { 2279906Sgm89044 /* nothing in the queue! */ 2280906Sgm89044 dca_freework(workp); 2281906Sgm89044 return; 2282906Sgm89044 } 2283906Sgm89044 2284906Sgm89044 wlp->dwl_submit++; 2285906Sgm89044 2286906Sgm89044 PUTMCR16(workp, MCR_FLAGS, 0); 2287906Sgm89044 PUTMCR16(workp, MCR_COUNT, nreqs); 2288906Sgm89044 2289906Sgm89044 DBG(dca, DCHATTY, 2290906Sgm89044 "posting work (phys %x, virt 0x%p) (%d reqs) to MCR%d", 2291906Sgm89044 workp->dw_mcr_paddr, workp->dw_mcr_kaddr, 2292906Sgm89044 nreqs, mcr); 2293906Sgm89044 2294906Sgm89044 workp->dw_lbolt = ddi_get_lbolt(); 2295906Sgm89044 /* Make sure MCR is synced out to device. */ 2296906Sgm89044 (void) ddi_dma_sync(workp->dw_mcr_dmah, 0, 0, 2297906Sgm89044 DDI_DMA_SYNC_FORDEV); 2298906Sgm89044 if (dca_check_dma_handle(dca, workp->dw_mcr_dmah, 2299906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 2300906Sgm89044 dca_destroywork(workp); 2301906Sgm89044 return; 2302906Sgm89044 } 2303906Sgm89044 2304906Sgm89044 PUTCSR(dca, csr, workp->dw_mcr_paddr); 2305906Sgm89044 if (dca_check_acc_handle(dca, dca->dca_regs_handle, 2306906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 2307906Sgm89044 dca_destroywork(workp); 2308906Sgm89044 return; 2309906Sgm89044 } else { 2310906Sgm89044 dca_enqueue(&wlp->dwl_runq, (dca_listnode_t *)workp); 2311906Sgm89044 } 2312906Sgm89044 2313906Sgm89044 DBG(dca, DCHATTY, "posted"); 2314906Sgm89044 } 2315906Sgm89044 } 2316906Sgm89044 2317906Sgm89044 /* 2318906Sgm89044 * Reclaim completed work, called in interrupt context. 2319906Sgm89044 */ 2320906Sgm89044 void 2321906Sgm89044 dca_reclaim(dca_t *dca, int mcr) 2322906Sgm89044 { 2323906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 2324906Sgm89044 dca_work_t *workp; 2325906Sgm89044 ushort_t flags; 2326906Sgm89044 int nreclaimed = 0; 2327906Sgm89044 int i; 2328906Sgm89044 2329906Sgm89044 DBG(dca, DRECLAIM, "worklist = 0x%p (MCR%d)", wlp, mcr); 2330906Sgm89044 ASSERT(mutex_owned(&wlp->dwl_lock)); 2331906Sgm89044 /* 2332906Sgm89044 * For each MCR in the submitted (runq), we check to see if 2333906Sgm89044 * it has been processed. If so, then we note each individual 2334906Sgm89044 * job in the MCR, and and do the completion processing for 2335906Sgm89044 * each of such job. 2336906Sgm89044 */ 2337906Sgm89044 for (;;) { 2338906Sgm89044 2339906Sgm89044 workp = (dca_work_t *)dca_peekqueue(&wlp->dwl_runq); 2340906Sgm89044 if (workp == NULL) { 2341906Sgm89044 break; 2342906Sgm89044 } 2343906Sgm89044 2344906Sgm89044 /* only sync the MCR flags, since that's all we need */ 2345906Sgm89044 (void) ddi_dma_sync(workp->dw_mcr_dmah, 0, 4, 2346906Sgm89044 DDI_DMA_SYNC_FORKERNEL); 2347906Sgm89044 if (dca_check_dma_handle(dca, workp->dw_mcr_dmah, 2348906Sgm89044 DCA_FM_ECLASS_NONE) != DDI_SUCCESS) { 2349906Sgm89044 dca_rmqueue((dca_listnode_t *)workp); 2350906Sgm89044 dca_destroywork(workp); 2351906Sgm89044 return; 2352906Sgm89044 } 2353906Sgm89044 2354906Sgm89044 flags = GETMCR16(workp, MCR_FLAGS); 2355906Sgm89044 if ((flags & MCRFLAG_FINISHED) == 0) { 2356906Sgm89044 /* chip is still working on it */ 2357906Sgm89044 DBG(dca, DRECLAIM, 2358906Sgm89044 "chip still working on it (MCR%d)", mcr); 2359906Sgm89044 break; 2360906Sgm89044 } 2361906Sgm89044 2362906Sgm89044 /* its really for us, so remove it from the queue */ 2363906Sgm89044 dca_rmqueue((dca_listnode_t *)workp); 2364906Sgm89044 2365906Sgm89044 /* if we were draining, signal on the cv */ 2366906Sgm89044 if (wlp->dwl_drain && QEMPTY(&wlp->dwl_runq)) { 2367906Sgm89044 cv_signal(&wlp->dwl_cv); 2368906Sgm89044 } 2369906Sgm89044 2370906Sgm89044 /* update statistics, done under the lock */ 2371906Sgm89044 for (i = 0; i < wlp->dwl_reqspermcr; i++) { 2372906Sgm89044 dca_request_t *reqp = workp->dw_reqs[i]; 2373906Sgm89044 if (reqp == NULL) { 2374906Sgm89044 continue; 2375906Sgm89044 } 2376906Sgm89044 if (reqp->dr_byte_stat >= 0) { 2377906Sgm89044 dca->dca_stats[reqp->dr_byte_stat] += 2378906Sgm89044 reqp->dr_pkt_length; 2379906Sgm89044 } 2380906Sgm89044 if (reqp->dr_job_stat >= 0) { 2381906Sgm89044 dca->dca_stats[reqp->dr_job_stat]++; 2382906Sgm89044 } 2383906Sgm89044 } 2384906Sgm89044 mutex_exit(&wlp->dwl_lock); 2385906Sgm89044 2386906Sgm89044 for (i = 0; i < wlp->dwl_reqspermcr; i++) { 2387906Sgm89044 dca_request_t *reqp = workp->dw_reqs[i]; 2388906Sgm89044 2389906Sgm89044 if (reqp == NULL) { 2390906Sgm89044 continue; 2391906Sgm89044 } 2392906Sgm89044 2393906Sgm89044 /* Do the callback. */ 2394906Sgm89044 workp->dw_reqs[i] = NULL; 2395906Sgm89044 dca_done(reqp, CRYPTO_SUCCESS); 2396906Sgm89044 2397906Sgm89044 nreclaimed++; 2398906Sgm89044 } 2399906Sgm89044 2400906Sgm89044 /* now we can release the work */ 2401906Sgm89044 dca_freework(workp); 2402*3124Sqs148142 2403*3124Sqs148142 mutex_enter(&wlp->dwl_lock); 2404906Sgm89044 } 2405906Sgm89044 DBG(dca, DRECLAIM, "reclaimed %d cmds", nreclaimed); 2406906Sgm89044 } 2407906Sgm89044 2408906Sgm89044 int 2409906Sgm89044 dca_length(crypto_data_t *cdata) 2410906Sgm89044 { 2411906Sgm89044 return (cdata->cd_length); 2412906Sgm89044 } 2413906Sgm89044 2414906Sgm89044 /* 2415906Sgm89044 * This is the callback function called from the interrupt when a kCF job 2416906Sgm89044 * completes. It does some driver-specific things, and then calls the 2417906Sgm89044 * kCF-provided callback. Finally, it cleans up the state for the work 2418906Sgm89044 * request and drops the reference count to allow for DR. 2419906Sgm89044 */ 2420906Sgm89044 void 2421906Sgm89044 dca_done(dca_request_t *reqp, int err) 2422906Sgm89044 { 2423906Sgm89044 uint64_t ena = 0; 2424906Sgm89044 2425906Sgm89044 /* unbind any chains we were using */ 2426906Sgm89044 if (dca_unbindchains(reqp) != DDI_SUCCESS) { 2427906Sgm89044 /* DMA failure */ 2428906Sgm89044 ena = dca_ena(ena); 2429906Sgm89044 dca_failure(reqp->dr_dca, DDI_DATAPATH_FAULT, 2430906Sgm89044 DCA_FM_ECLASS_NONE, ena, CRYPTO_DEVICE_ERROR, 2431906Sgm89044 "fault on buffer DMA handle"); 2432906Sgm89044 if (err == CRYPTO_SUCCESS) { 2433906Sgm89044 err = CRYPTO_DEVICE_ERROR; 2434906Sgm89044 } 2435906Sgm89044 } 2436906Sgm89044 2437906Sgm89044 if (reqp->dr_callback != NULL) { 2438906Sgm89044 reqp->dr_callback(reqp, err); 2439906Sgm89044 } else { 2440906Sgm89044 dca_freereq(reqp); 2441906Sgm89044 } 2442906Sgm89044 } 2443906Sgm89044 2444906Sgm89044 /* 2445906Sgm89044 * Call this when a failure is detected. It will reset the chip, 2446906Sgm89044 * log a message, alert kCF, and mark jobs in the runq as failed. 2447906Sgm89044 */ 2448906Sgm89044 /* ARGSUSED */ 2449906Sgm89044 void 2450906Sgm89044 dca_failure(dca_t *dca, ddi_fault_location_t loc, dca_fma_eclass_t index, 2451906Sgm89044 uint64_t ena, int errno, char *mess, ...) 2452906Sgm89044 { 2453906Sgm89044 va_list ap; 2454906Sgm89044 char buf[256]; 2455906Sgm89044 int mcr; 2456906Sgm89044 char *eclass; 2457906Sgm89044 int have_mutex; 2458906Sgm89044 2459906Sgm89044 va_start(ap, mess); 2460906Sgm89044 (void) vsprintf(buf, mess, ap); 2461906Sgm89044 va_end(ap); 2462906Sgm89044 2463906Sgm89044 eclass = dca_fma_eclass_string(dca->dca_model, index); 2464906Sgm89044 2465906Sgm89044 if (DDI_FM_EREPORT_CAP(dca->fm_capabilities) && 2466906Sgm89044 index != DCA_FM_ECLASS_NONE) { 2467906Sgm89044 ddi_fm_ereport_post(dca->dca_dip, eclass, ena, 2468906Sgm89044 DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 2469906Sgm89044 FM_EREPORT_VERS0, NULL); 2470906Sgm89044 2471906Sgm89044 /* Report the impact of the failure to the DDI. */ 2472906Sgm89044 ddi_fm_service_impact(dca->dca_dip, DDI_SERVICE_LOST); 2473906Sgm89044 } else { 2474906Sgm89044 /* Just log the error string to the message log */ 2475906Sgm89044 dca_error(dca, buf); 2476906Sgm89044 } 2477906Sgm89044 2478906Sgm89044 /* 2479906Sgm89044 * Indicate a failure (keeps schedule from running). 2480906Sgm89044 */ 2481906Sgm89044 dca->dca_flags |= DCA_FAILED; 2482906Sgm89044 2483906Sgm89044 /* 2484906Sgm89044 * Reset the chip. This should also have as a side effect, the 2485906Sgm89044 * disabling of all interrupts from the device. 2486906Sgm89044 */ 2487906Sgm89044 (void) dca_reset(dca, 1); 2488906Sgm89044 2489906Sgm89044 /* 2490906Sgm89044 * Report the failure to kCF. 2491906Sgm89044 */ 2492906Sgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) { 2493906Sgm89044 if (WORKLIST(dca, mcr)->dwl_prov) { 2494906Sgm89044 crypto_prov_notify(WORKLIST(dca, mcr)->dwl_prov, 2495906Sgm89044 CRYPTO_PROVIDER_FAILED); 2496906Sgm89044 } 2497906Sgm89044 } 2498906Sgm89044 2499906Sgm89044 /* 2500906Sgm89044 * Return jobs not sent to hardware back to kCF. 2501906Sgm89044 */ 2502906Sgm89044 dca_rejectjobs(dca); 2503906Sgm89044 2504906Sgm89044 /* 2505906Sgm89044 * From this point on, no new work should be arriving, and the 2506906Sgm89044 * chip should not be doing any active DMA. 2507906Sgm89044 */ 2508906Sgm89044 2509906Sgm89044 /* 2510906Sgm89044 * Now find all the work submitted to the device and fail 2511906Sgm89044 * them. 2512906Sgm89044 */ 2513906Sgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) { 2514906Sgm89044 dca_worklist_t *wlp; 2515906Sgm89044 int i; 2516906Sgm89044 2517906Sgm89044 wlp = WORKLIST(dca, mcr); 2518906Sgm89044 2519906Sgm89044 if (wlp == NULL || wlp->dwl_waitq.dl_prev == NULL) { 2520906Sgm89044 continue; 2521906Sgm89044 } 2522906Sgm89044 for (;;) { 2523906Sgm89044 dca_work_t *workp; 2524906Sgm89044 2525906Sgm89044 have_mutex = mutex_tryenter(&wlp->dwl_lock); 2526906Sgm89044 workp = (dca_work_t *)dca_dequeue(&wlp->dwl_runq); 2527906Sgm89044 if (workp == NULL) { 2528906Sgm89044 if (have_mutex) 2529906Sgm89044 mutex_exit(&wlp->dwl_lock); 2530906Sgm89044 break; 2531906Sgm89044 } 2532906Sgm89044 mutex_exit(&wlp->dwl_lock); 2533906Sgm89044 2534906Sgm89044 /* 2535906Sgm89044 * Free up requests 2536906Sgm89044 */ 2537906Sgm89044 for (i = 0; i < wlp->dwl_reqspermcr; i++) { 2538906Sgm89044 dca_request_t *reqp = workp->dw_reqs[i]; 2539906Sgm89044 if (reqp) { 2540906Sgm89044 if (reqp->dr_flags & DR_INPLACE) { 2541906Sgm89044 dca_done(reqp, errno); 2542906Sgm89044 } else { 2543906Sgm89044 /* 2544906Sgm89044 * cause it to get retried 2545906Sgm89044 * elsewhere (software) 2546906Sgm89044 */ 2547906Sgm89044 dca_done(reqp, CRYPTO_FAILED); 2548906Sgm89044 } 2549906Sgm89044 workp->dw_reqs[i] = NULL; 2550906Sgm89044 } 2551906Sgm89044 } 2552906Sgm89044 2553906Sgm89044 mutex_enter(&wlp->dwl_lock); 2554906Sgm89044 /* 2555906Sgm89044 * If waiting to drain, signal on the waiter. 2556906Sgm89044 */ 2557906Sgm89044 if (wlp->dwl_drain && QEMPTY(&wlp->dwl_runq)) { 2558906Sgm89044 cv_signal(&wlp->dwl_cv); 2559906Sgm89044 } 2560906Sgm89044 2561906Sgm89044 /* 2562906Sgm89044 * Return the work and request structures to 2563906Sgm89044 * the free pool. 2564906Sgm89044 */ 2565906Sgm89044 dca_freework(workp); 2566906Sgm89044 if (have_mutex) 2567906Sgm89044 mutex_exit(&wlp->dwl_lock); 2568906Sgm89044 } 2569906Sgm89044 } 2570906Sgm89044 2571906Sgm89044 } 2572906Sgm89044 2573906Sgm89044 #ifdef SCHEDDELAY 2574906Sgm89044 /* 2575906Sgm89044 * Reschedule worklist as needed. 2576906Sgm89044 */ 2577906Sgm89044 void 2578906Sgm89044 dca_schedtimeout(void *arg) 2579906Sgm89044 { 2580906Sgm89044 dca_worklist_t *wlp = (dca_worklist_t *)arg; 2581906Sgm89044 mutex_enter(&wlp->dwl_lock); 2582906Sgm89044 wlp->dwl_schedtid = 0; 2583906Sgm89044 dca_schedule(wlp->dwl_dca, wlp->dwl_mcr); 2584906Sgm89044 mutex_exit(&wlp->dwl_lock); 2585906Sgm89044 } 2586906Sgm89044 #endif 2587906Sgm89044 2588906Sgm89044 /* 2589906Sgm89044 * Check for stalled jobs. 2590906Sgm89044 */ 2591906Sgm89044 void 2592906Sgm89044 dca_jobtimeout(void *arg) 2593906Sgm89044 { 2594906Sgm89044 int mcr; 2595906Sgm89044 dca_t *dca = (dca_t *)arg; 2596906Sgm89044 int hung = 0; 2597906Sgm89044 2598906Sgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) { 2599906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 2600906Sgm89044 dca_work_t *workp; 2601906Sgm89044 clock_t when; 2602906Sgm89044 2603906Sgm89044 mutex_enter(&wlp->dwl_lock); 2604906Sgm89044 when = ddi_get_lbolt(); 2605906Sgm89044 2606906Sgm89044 workp = (dca_work_t *)dca_peekqueue(&wlp->dwl_runq); 2607906Sgm89044 if (workp == NULL) { 2608906Sgm89044 /* nothing sitting in the queue */ 2609906Sgm89044 mutex_exit(&wlp->dwl_lock); 2610906Sgm89044 continue; 2611906Sgm89044 } 2612906Sgm89044 2613906Sgm89044 if ((when - workp->dw_lbolt) < drv_usectohz(STALETIME)) { 2614906Sgm89044 /* request has been queued for less than STALETIME */ 2615906Sgm89044 mutex_exit(&wlp->dwl_lock); 2616906Sgm89044 continue; 2617906Sgm89044 } 2618906Sgm89044 2619906Sgm89044 /* job has been sitting around for over 1 second, badness */ 2620906Sgm89044 DBG(dca, DWARN, "stale job (0x%p) found in MCR%d!", workp, 2621906Sgm89044 mcr); 2622906Sgm89044 2623906Sgm89044 /* put it back in the queue, until we reset the chip */ 2624906Sgm89044 hung++; 2625906Sgm89044 mutex_exit(&wlp->dwl_lock); 2626906Sgm89044 } 2627906Sgm89044 2628906Sgm89044 if (hung) { 2629906Sgm89044 dca_failure(dca, DDI_DEVICE_FAULT, 2630906Sgm89044 DCA_FM_ECLASS_HW_TIMEOUT, dca_ena(0), CRYPTO_DEVICE_ERROR, 2631906Sgm89044 "timeout processing job.)"); 2632906Sgm89044 } 2633906Sgm89044 2634906Sgm89044 /* reschedule ourself */ 2635906Sgm89044 mutex_enter(&dca->dca_intrlock); 2636906Sgm89044 if (dca->dca_jobtid == 0) { 2637906Sgm89044 /* timeout has been canceled, prior to DR */ 2638906Sgm89044 mutex_exit(&dca->dca_intrlock); 2639906Sgm89044 return; 2640906Sgm89044 } 2641906Sgm89044 2642906Sgm89044 /* check again in 1 second */ 2643906Sgm89044 dca->dca_jobtid = timeout(dca_jobtimeout, arg, 2644906Sgm89044 drv_usectohz(SECOND)); 2645906Sgm89044 mutex_exit(&dca->dca_intrlock); 2646906Sgm89044 } 2647906Sgm89044 2648906Sgm89044 /* 2649906Sgm89044 * This returns all jobs back to kCF. It assumes that processing 2650906Sgm89044 * on the worklist has halted. 2651906Sgm89044 */ 2652906Sgm89044 void 2653906Sgm89044 dca_rejectjobs(dca_t *dca) 2654906Sgm89044 { 2655906Sgm89044 int mcr; 2656906Sgm89044 int have_mutex; 2657906Sgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) { 2658906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 2659906Sgm89044 dca_request_t *reqp; 2660906Sgm89044 2661906Sgm89044 if (wlp == NULL || wlp->dwl_waitq.dl_prev == NULL) { 2662906Sgm89044 continue; 2663906Sgm89044 } 2664906Sgm89044 have_mutex = mutex_tryenter(&wlp->dwl_lock); 2665906Sgm89044 for (;;) { 2666906Sgm89044 reqp = (dca_request_t *)dca_unqueue(&wlp->dwl_waitq); 2667906Sgm89044 if (reqp == NULL) { 2668906Sgm89044 break; 2669906Sgm89044 } 2670906Sgm89044 /* update flow control */ 2671906Sgm89044 wlp->dwl_count--; 2672906Sgm89044 if ((wlp->dwl_count == wlp->dwl_lowater) && 2673906Sgm89044 (wlp->dwl_busy)) { 2674906Sgm89044 wlp->dwl_busy = 0; 2675906Sgm89044 crypto_prov_notify(wlp->dwl_prov, 2676906Sgm89044 CRYPTO_PROVIDER_READY); 2677906Sgm89044 } 2678906Sgm89044 mutex_exit(&wlp->dwl_lock); 2679906Sgm89044 2680906Sgm89044 (void) dca_unbindchains(reqp); 2681906Sgm89044 reqp->dr_callback(reqp, EAGAIN); 2682906Sgm89044 mutex_enter(&wlp->dwl_lock); 2683906Sgm89044 } 2684906Sgm89044 if (have_mutex) 2685906Sgm89044 mutex_exit(&wlp->dwl_lock); 2686906Sgm89044 } 2687906Sgm89044 } 2688906Sgm89044 2689906Sgm89044 int 2690906Sgm89044 dca_drain(dca_t *dca) 2691906Sgm89044 { 2692906Sgm89044 int mcr; 2693906Sgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) { 2694906Sgm89044 #ifdef SCHEDDELAY 2695906Sgm89044 timeout_id_t tid; 2696906Sgm89044 #endif 2697906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 2698906Sgm89044 2699906Sgm89044 mutex_enter(&wlp->dwl_lock); 2700906Sgm89044 wlp->dwl_drain = 1; 2701906Sgm89044 2702906Sgm89044 /* give it up to a second to drain from the chip */ 2703906Sgm89044 if (!QEMPTY(&wlp->dwl_runq)) { 2704906Sgm89044 (void) cv_timedwait(&wlp->dwl_cv, &wlp->dwl_lock, 2705906Sgm89044 ddi_get_time() + drv_usectohz(STALETIME)); 2706906Sgm89044 2707906Sgm89044 if (!QEMPTY(&wlp->dwl_runq)) { 2708906Sgm89044 dca_error(dca, "unable to drain device"); 2709906Sgm89044 mutex_exit(&wlp->dwl_lock); 2710906Sgm89044 dca_undrain(dca); 2711906Sgm89044 return (EBUSY); 2712906Sgm89044 } 2713906Sgm89044 } 2714906Sgm89044 2715906Sgm89044 #ifdef SCHEDDELAY 2716906Sgm89044 tid = wlp->dwl_schedtid; 2717906Sgm89044 mutex_exit(&wlp->dwl_lock); 2718906Sgm89044 2719906Sgm89044 /* 2720906Sgm89044 * untimeout outside the lock -- this is safe because we 2721906Sgm89044 * have set the drain flag, so dca_schedule() will not 2722906Sgm89044 * reschedule another timeout 2723906Sgm89044 */ 2724906Sgm89044 if (tid) { 2725906Sgm89044 untimeout(tid); 2726906Sgm89044 } 2727906Sgm89044 #else 2728906Sgm89044 mutex_exit(&wlp->dwl_lock); 2729906Sgm89044 #endif 2730906Sgm89044 } 2731906Sgm89044 return (0); 2732906Sgm89044 } 2733906Sgm89044 2734906Sgm89044 void 2735906Sgm89044 dca_undrain(dca_t *dca) 2736906Sgm89044 { 2737906Sgm89044 int mcr; 2738906Sgm89044 2739906Sgm89044 for (mcr = MCR1; mcr <= MCR2; mcr++) { 2740906Sgm89044 dca_worklist_t *wlp = WORKLIST(dca, mcr); 2741906Sgm89044 mutex_enter(&wlp->dwl_lock); 2742906Sgm89044 wlp->dwl_drain = 0; 2743906Sgm89044 dca_schedule(dca, mcr); 2744906Sgm89044 mutex_exit(&wlp->dwl_lock); 2745906Sgm89044 } 2746906Sgm89044 } 2747906Sgm89044 2748906Sgm89044 /* 2749906Sgm89044 * Duplicate the crypto_data_t structure, but point to the original 2750906Sgm89044 * buffers. 2751906Sgm89044 */ 2752906Sgm89044 int 2753906Sgm89044 dca_dupcrypto(crypto_data_t *input, crypto_data_t *ninput) 2754906Sgm89044 { 2755906Sgm89044 ninput->cd_format = input->cd_format; 2756906Sgm89044 ninput->cd_offset = input->cd_offset; 2757906Sgm89044 ninput->cd_length = input->cd_length; 2758906Sgm89044 ninput->cd_miscdata = input->cd_miscdata; 2759906Sgm89044 2760906Sgm89044 switch (input->cd_format) { 2761906Sgm89044 case CRYPTO_DATA_RAW: 2762906Sgm89044 ninput->cd_raw.iov_base = input->cd_raw.iov_base; 2763906Sgm89044 ninput->cd_raw.iov_len = input->cd_raw.iov_len; 2764906Sgm89044 break; 2765906Sgm89044 2766906Sgm89044 case CRYPTO_DATA_UIO: 2767906Sgm89044 ninput->cd_uio = input->cd_uio; 2768906Sgm89044 break; 2769906Sgm89044 2770906Sgm89044 case CRYPTO_DATA_MBLK: 2771906Sgm89044 ninput->cd_mp = input->cd_mp; 2772906Sgm89044 break; 2773906Sgm89044 2774906Sgm89044 default: 2775906Sgm89044 DBG(NULL, DWARN, 2776906Sgm89044 "dca_dupcrypto: unrecognised crypto data format"); 2777906Sgm89044 return (CRYPTO_FAILED); 2778906Sgm89044 } 2779906Sgm89044 2780906Sgm89044 return (CRYPTO_SUCCESS); 2781906Sgm89044 } 2782906Sgm89044 2783906Sgm89044 /* 2784906Sgm89044 * Performs validation checks on the input and output data structures. 2785906Sgm89044 */ 2786906Sgm89044 int 2787906Sgm89044 dca_verifyio(crypto_data_t *input, crypto_data_t *output) 2788906Sgm89044 { 2789906Sgm89044 int rv = CRYPTO_SUCCESS; 2790906Sgm89044 2791906Sgm89044 switch (input->cd_format) { 2792906Sgm89044 case CRYPTO_DATA_RAW: 2793906Sgm89044 break; 2794906Sgm89044 2795906Sgm89044 case CRYPTO_DATA_UIO: 2796906Sgm89044 /* we support only kernel buffer */ 2797906Sgm89044 if (input->cd_uio->uio_segflg != UIO_SYSSPACE) { 2798906Sgm89044 DBG(NULL, DWARN, "non kernel input uio buffer"); 2799906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 2800906Sgm89044 } 2801906Sgm89044 break; 2802906Sgm89044 2803906Sgm89044 case CRYPTO_DATA_MBLK: 2804906Sgm89044 break; 2805906Sgm89044 2806906Sgm89044 default: 2807906Sgm89044 DBG(NULL, DWARN, "unrecognised input crypto data format"); 2808906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 2809906Sgm89044 } 2810906Sgm89044 2811906Sgm89044 switch (output->cd_format) { 2812906Sgm89044 case CRYPTO_DATA_RAW: 2813906Sgm89044 break; 2814906Sgm89044 2815906Sgm89044 case CRYPTO_DATA_UIO: 2816906Sgm89044 /* we support only kernel buffer */ 2817906Sgm89044 if (output->cd_uio->uio_segflg != UIO_SYSSPACE) { 2818906Sgm89044 DBG(NULL, DWARN, "non kernel output uio buffer"); 2819906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 2820906Sgm89044 } 2821906Sgm89044 break; 2822906Sgm89044 2823906Sgm89044 case CRYPTO_DATA_MBLK: 2824906Sgm89044 break; 2825906Sgm89044 2826906Sgm89044 default: 2827906Sgm89044 DBG(NULL, DWARN, "unrecognised output crypto data format"); 2828906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 2829906Sgm89044 } 2830906Sgm89044 2831906Sgm89044 return (rv); 2832906Sgm89044 } 2833906Sgm89044 2834906Sgm89044 /* 2835906Sgm89044 * data: source crypto_data_t struct 2836906Sgm89044 * off: offset into the source before commencing copy 2837906Sgm89044 * count: the amount of data to copy 2838906Sgm89044 * dest: destination buffer 2839906Sgm89044 */ 2840906Sgm89044 int 2841906Sgm89044 dca_getbufbytes(crypto_data_t *data, size_t off, int count, uchar_t *dest) 2842906Sgm89044 { 2843906Sgm89044 int rv = CRYPTO_SUCCESS; 2844906Sgm89044 uio_t *uiop; 2845906Sgm89044 uint_t vec_idx; 2846906Sgm89044 size_t cur_len; 2847906Sgm89044 mblk_t *mp; 2848906Sgm89044 2849906Sgm89044 if (count == 0) { 2850906Sgm89044 /* We don't want anything so we're done. */ 2851906Sgm89044 return (rv); 2852906Sgm89044 } 2853906Sgm89044 2854906Sgm89044 /* 2855906Sgm89044 * Sanity check that we haven't specified a length greater than the 2856906Sgm89044 * offset adjusted size of the buffer. 2857906Sgm89044 */ 2858906Sgm89044 if (count > (data->cd_length - off)) { 2859906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 2860906Sgm89044 } 2861906Sgm89044 2862906Sgm89044 /* Add the internal crypto_data offset to the requested offset. */ 2863906Sgm89044 off += data->cd_offset; 2864906Sgm89044 2865906Sgm89044 switch (data->cd_format) { 2866906Sgm89044 case CRYPTO_DATA_RAW: 2867906Sgm89044 bcopy(data->cd_raw.iov_base + off, dest, count); 2868906Sgm89044 break; 2869906Sgm89044 2870906Sgm89044 case CRYPTO_DATA_UIO: 2871906Sgm89044 /* 2872906Sgm89044 * Jump to the first iovec containing data to be 2873906Sgm89044 * processed. 2874906Sgm89044 */ 2875906Sgm89044 uiop = data->cd_uio; 2876906Sgm89044 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 2877906Sgm89044 off >= uiop->uio_iov[vec_idx].iov_len; 2878906Sgm89044 off -= uiop->uio_iov[vec_idx++].iov_len); 2879906Sgm89044 if (vec_idx == uiop->uio_iovcnt) { 2880906Sgm89044 /* 2881906Sgm89044 * The caller specified an offset that is larger than 2882906Sgm89044 * the total size of the buffers it provided. 2883906Sgm89044 */ 2884906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 2885906Sgm89044 } 2886906Sgm89044 2887906Sgm89044 /* 2888906Sgm89044 * Now process the iovecs. 2889906Sgm89044 */ 2890906Sgm89044 while (vec_idx < uiop->uio_iovcnt && count > 0) { 2891906Sgm89044 cur_len = min(uiop->uio_iov[vec_idx].iov_len - 2892906Sgm89044 off, count); 2893906Sgm89044 bcopy(uiop->uio_iov[vec_idx].iov_base + off, dest, 2894906Sgm89044 cur_len); 2895906Sgm89044 count -= cur_len; 2896906Sgm89044 dest += cur_len; 2897906Sgm89044 vec_idx++; 2898906Sgm89044 off = 0; 2899906Sgm89044 } 2900906Sgm89044 2901906Sgm89044 if (vec_idx == uiop->uio_iovcnt && count > 0) { 2902906Sgm89044 /* 2903906Sgm89044 * The end of the specified iovec's was reached but 2904906Sgm89044 * the length requested could not be processed 2905906Sgm89044 * (requested to digest more data than it provided). 2906906Sgm89044 */ 2907906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 2908906Sgm89044 } 2909906Sgm89044 break; 2910906Sgm89044 2911906Sgm89044 case CRYPTO_DATA_MBLK: 2912906Sgm89044 /* 2913906Sgm89044 * Jump to the first mblk_t containing data to be processed. 2914906Sgm89044 */ 2915906Sgm89044 for (mp = data->cd_mp; mp != NULL && off >= MBLKL(mp); 2916906Sgm89044 off -= MBLKL(mp), mp = mp->b_cont); 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; 3120906Sgm89044 off -= uiop->uio_iov[vec_idx++].iov_len); 3121906Sgm89044 if (vec_idx == uiop->uio_iovcnt) { 3122906Sgm89044 /* 3123906Sgm89044 * The caller specified an offset that is larger than 3124906Sgm89044 * the total size of the buffers it provided. 3125906Sgm89044 */ 3126906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3127906Sgm89044 } 3128906Sgm89044 3129906Sgm89044 /* 3130906Sgm89044 * Now process the iovecs. 3131906Sgm89044 */ 3132906Sgm89044 while (vec_idx < uiop->uio_iovcnt && count > 0) { 3133906Sgm89044 cur_len = min(uiop->uio_iov[vec_idx].iov_len - 3134906Sgm89044 off, count); 3135906Sgm89044 count -= cur_len; 3136906Sgm89044 if (reverse) { 3137906Sgm89044 /* Fill the dest buffer from the end */ 3138906Sgm89044 dca_reverse(uiop->uio_iov[vec_idx].iov_base + 3139906Sgm89044 off, dest+count, cur_len, cur_len); 3140906Sgm89044 } else { 3141906Sgm89044 bcopy(uiop->uio_iov[vec_idx].iov_base + off, 3142906Sgm89044 dest, cur_len); 3143906Sgm89044 dest += cur_len; 3144906Sgm89044 } 3145906Sgm89044 in->cd_offset += cur_len; 3146906Sgm89044 in->cd_length -= cur_len; 3147906Sgm89044 vec_idx++; 3148906Sgm89044 off = 0; 3149906Sgm89044 } 3150906Sgm89044 3151906Sgm89044 if (vec_idx == uiop->uio_iovcnt && count > 0) { 3152906Sgm89044 /* 3153906Sgm89044 * The end of the specified iovec's was reached but 3154906Sgm89044 * the length requested could not be processed 3155906Sgm89044 * (requested to digest more data than it provided). 3156906Sgm89044 */ 3157906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3158906Sgm89044 } 3159906Sgm89044 break; 3160906Sgm89044 3161906Sgm89044 case CRYPTO_DATA_MBLK: 3162906Sgm89044 /* 3163906Sgm89044 * Jump to the first mblk_t containing data to be processed. 3164906Sgm89044 */ 3165906Sgm89044 for (mp = in->cd_mp; mp != NULL && off >= MBLKL(mp); 3166906Sgm89044 off -= MBLKL(mp), mp = mp->b_cont); 3167906Sgm89044 if (mp == NULL) { 3168906Sgm89044 /* 3169906Sgm89044 * The caller specified an offset that is larger than 3170906Sgm89044 * the total size of the buffers it provided. 3171906Sgm89044 */ 3172906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3173906Sgm89044 } 3174906Sgm89044 3175906Sgm89044 /* 3176906Sgm89044 * Now do the processing on the mblk chain. 3177906Sgm89044 */ 3178906Sgm89044 while (mp != NULL && count > 0) { 3179906Sgm89044 cur_len = min(MBLKL(mp) - off, count); 3180906Sgm89044 count -= cur_len; 3181906Sgm89044 if (reverse) { 3182906Sgm89044 /* Fill the dest buffer from the end */ 3183906Sgm89044 dca_reverse((char *)(mp->b_rptr + off), 3184906Sgm89044 dest+count, cur_len, cur_len); 3185906Sgm89044 } else { 3186906Sgm89044 bcopy((char *)(mp->b_rptr + off), dest, 3187906Sgm89044 cur_len); 3188906Sgm89044 dest += cur_len; 3189906Sgm89044 } 3190906Sgm89044 in->cd_offset += cur_len; 3191906Sgm89044 in->cd_length -= cur_len; 3192906Sgm89044 mp = mp->b_cont; 3193906Sgm89044 off = 0; 3194906Sgm89044 } 3195906Sgm89044 3196906Sgm89044 if (mp == NULL && count > 0) { 3197906Sgm89044 /* 3198906Sgm89044 * The end of the mblk was reached but the length 3199906Sgm89044 * requested could not be processed, (requested to 3200906Sgm89044 * digest more data than it provided). 3201906Sgm89044 */ 3202906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3203906Sgm89044 } 3204906Sgm89044 break; 3205906Sgm89044 3206906Sgm89044 default: 3207906Sgm89044 DBG(NULL, DWARN, "dca_gather: unrecognised crypto data format"); 3208906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 3209906Sgm89044 } 3210906Sgm89044 return (rv); 3211906Sgm89044 } 3212906Sgm89044 3213906Sgm89044 /* 3214906Sgm89044 * Increments the cd_offset and decrements the cd_length as the data is 3215906Sgm89044 * gathered from the crypto_data_t struct. 3216906Sgm89044 */ 3217906Sgm89044 int 3218906Sgm89044 dca_resid_gather(crypto_data_t *in, char *resid, int *residlen, char *dest, 3219906Sgm89044 int count) 3220906Sgm89044 { 3221906Sgm89044 int rv = CRYPTO_SUCCESS; 3222906Sgm89044 caddr_t baddr; 3223906Sgm89044 uint_t vec_idx; 3224906Sgm89044 uio_t *uiop; 3225906Sgm89044 off_t off = in->cd_offset; 3226906Sgm89044 size_t cur_len; 3227906Sgm89044 mblk_t *mp; 3228906Sgm89044 3229906Sgm89044 /* Process the residual first */ 3230906Sgm89044 if (*residlen > 0) { 3231906Sgm89044 uint_t num = min(count, *residlen); 3232906Sgm89044 bcopy(resid, dest, num); 3233906Sgm89044 *residlen -= num; 3234906Sgm89044 if (*residlen > 0) { 3235906Sgm89044 /* 3236906Sgm89044 * Requested amount 'count' is less than what's in 3237906Sgm89044 * the residual, so shuffle any remaining resid to 3238906Sgm89044 * the front. 3239906Sgm89044 */ 3240906Sgm89044 baddr = resid + num; 3241906Sgm89044 bcopy(baddr, resid, *residlen); 3242906Sgm89044 } 3243906Sgm89044 dest += num; 3244906Sgm89044 count -= num; 3245906Sgm89044 } 3246906Sgm89044 3247906Sgm89044 /* Now process what's in the crypto_data_t structs */ 3248906Sgm89044 switch (in->cd_format) { 3249906Sgm89044 case CRYPTO_DATA_RAW: 3250906Sgm89044 if (count > in->cd_length) { 3251906Sgm89044 /* 3252906Sgm89044 * The caller specified a length greater than the 3253906Sgm89044 * size of the buffer. 3254906Sgm89044 */ 3255906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3256906Sgm89044 } 3257906Sgm89044 bcopy(in->cd_raw.iov_base + in->cd_offset, dest, count); 3258906Sgm89044 in->cd_offset += count; 3259906Sgm89044 in->cd_length -= count; 3260906Sgm89044 break; 3261906Sgm89044 3262906Sgm89044 case CRYPTO_DATA_UIO: 3263906Sgm89044 /* 3264906Sgm89044 * Jump to the first iovec containing data to be processed. 3265906Sgm89044 */ 3266906Sgm89044 uiop = in->cd_uio; 3267906Sgm89044 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 3268906Sgm89044 off >= uiop->uio_iov[vec_idx].iov_len; 3269906Sgm89044 off -= uiop->uio_iov[vec_idx++].iov_len); 3270906Sgm89044 if (vec_idx == uiop->uio_iovcnt) { 3271906Sgm89044 /* 3272906Sgm89044 * The caller specified an offset that is larger than 3273906Sgm89044 * the total size of the buffers it provided. 3274906Sgm89044 */ 3275906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3276906Sgm89044 } 3277906Sgm89044 3278906Sgm89044 /* 3279906Sgm89044 * Now process the iovecs. 3280906Sgm89044 */ 3281906Sgm89044 while (vec_idx < uiop->uio_iovcnt && count > 0) { 3282906Sgm89044 cur_len = min(uiop->uio_iov[vec_idx].iov_len - 3283906Sgm89044 off, count); 3284906Sgm89044 bcopy(uiop->uio_iov[vec_idx].iov_base + off, dest, 3285906Sgm89044 cur_len); 3286906Sgm89044 count -= cur_len; 3287906Sgm89044 dest += cur_len; 3288906Sgm89044 in->cd_offset += cur_len; 3289906Sgm89044 in->cd_length -= cur_len; 3290906Sgm89044 vec_idx++; 3291906Sgm89044 off = 0; 3292906Sgm89044 } 3293906Sgm89044 3294906Sgm89044 if (vec_idx == uiop->uio_iovcnt && count > 0) { 3295906Sgm89044 /* 3296906Sgm89044 * The end of the specified iovec's was reached but 3297906Sgm89044 * the length requested could not be processed 3298906Sgm89044 * (requested to digest more data than it provided). 3299906Sgm89044 */ 3300906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3301906Sgm89044 } 3302906Sgm89044 break; 3303906Sgm89044 3304906Sgm89044 case CRYPTO_DATA_MBLK: 3305906Sgm89044 /* 3306906Sgm89044 * Jump to the first mblk_t containing data to be processed. 3307906Sgm89044 */ 3308906Sgm89044 for (mp = in->cd_mp; mp != NULL && off >= MBLKL(mp); 3309906Sgm89044 off -= MBLKL(mp), mp = mp->b_cont); 3310906Sgm89044 if (mp == NULL) { 3311906Sgm89044 /* 3312906Sgm89044 * The caller specified an offset that is larger than 3313906Sgm89044 * the total size of the buffers it provided. 3314906Sgm89044 */ 3315906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3316906Sgm89044 } 3317906Sgm89044 3318906Sgm89044 /* 3319906Sgm89044 * Now do the processing on the mblk chain. 3320906Sgm89044 */ 3321906Sgm89044 while (mp != NULL && count > 0) { 3322906Sgm89044 cur_len = min(MBLKL(mp) - off, count); 3323906Sgm89044 bcopy((char *)(mp->b_rptr + off), dest, cur_len); 3324906Sgm89044 count -= cur_len; 3325906Sgm89044 dest += cur_len; 3326906Sgm89044 in->cd_offset += cur_len; 3327906Sgm89044 in->cd_length -= cur_len; 3328906Sgm89044 mp = mp->b_cont; 3329906Sgm89044 off = 0; 3330906Sgm89044 } 3331906Sgm89044 3332906Sgm89044 if (mp == NULL && count > 0) { 3333906Sgm89044 /* 3334906Sgm89044 * The end of the mblk was reached but the length 3335906Sgm89044 * requested could not be processed, (requested to 3336906Sgm89044 * digest more data than it provided). 3337906Sgm89044 */ 3338906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3339906Sgm89044 } 3340906Sgm89044 break; 3341906Sgm89044 3342906Sgm89044 default: 3343906Sgm89044 DBG(NULL, DWARN, 3344906Sgm89044 "dca_resid_gather: unrecognised crypto data format"); 3345906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 3346906Sgm89044 } 3347906Sgm89044 return (rv); 3348906Sgm89044 } 3349906Sgm89044 3350906Sgm89044 /* 3351906Sgm89044 * Appends the data to the crypto_data_t struct increasing cd_length. 3352906Sgm89044 * cd_offset is left unchanged. 3353906Sgm89044 * Data is reverse-copied if the flag is TRUE. 3354906Sgm89044 */ 3355906Sgm89044 int 3356906Sgm89044 dca_scatter(const char *src, crypto_data_t *out, int count, int reverse) 3357906Sgm89044 { 3358906Sgm89044 int rv = CRYPTO_SUCCESS; 3359906Sgm89044 off_t offset = out->cd_offset + out->cd_length; 3360906Sgm89044 uint_t vec_idx; 3361906Sgm89044 uio_t *uiop; 3362906Sgm89044 size_t cur_len; 3363906Sgm89044 mblk_t *mp; 3364906Sgm89044 3365906Sgm89044 switch (out->cd_format) { 3366906Sgm89044 case CRYPTO_DATA_RAW: 3367906Sgm89044 if (out->cd_raw.iov_len - offset < count) { 3368906Sgm89044 /* Trying to write out more than space available. */ 3369906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3370906Sgm89044 } 3371906Sgm89044 if (reverse) 3372906Sgm89044 dca_reverse((void*) src, out->cd_raw.iov_base + offset, 3373906Sgm89044 count, count); 3374906Sgm89044 else 3375906Sgm89044 bcopy(src, out->cd_raw.iov_base + offset, count); 3376906Sgm89044 out->cd_length += count; 3377906Sgm89044 break; 3378906Sgm89044 3379906Sgm89044 case CRYPTO_DATA_UIO: 3380906Sgm89044 /* 3381906Sgm89044 * Jump to the first iovec that can be written to. 3382906Sgm89044 */ 3383906Sgm89044 uiop = out->cd_uio; 3384906Sgm89044 for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && 3385906Sgm89044 offset >= uiop->uio_iov[vec_idx].iov_len; 3386906Sgm89044 offset -= uiop->uio_iov[vec_idx++].iov_len); 3387906Sgm89044 if (vec_idx == uiop->uio_iovcnt) { 3388906Sgm89044 /* 3389906Sgm89044 * The caller specified an offset that is larger than 3390906Sgm89044 * the total size of the buffers it provided. 3391906Sgm89044 */ 3392906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3393906Sgm89044 } 3394906Sgm89044 3395906Sgm89044 /* 3396906Sgm89044 * Now process the iovecs. 3397906Sgm89044 */ 3398906Sgm89044 while (vec_idx < uiop->uio_iovcnt && count > 0) { 3399906Sgm89044 cur_len = min(uiop->uio_iov[vec_idx].iov_len - 3400906Sgm89044 offset, count); 3401906Sgm89044 count -= cur_len; 3402906Sgm89044 if (reverse) { 3403906Sgm89044 dca_reverse((void*) (src+count), 3404906Sgm89044 uiop->uio_iov[vec_idx].iov_base + 3405906Sgm89044 offset, cur_len, cur_len); 3406906Sgm89044 } else { 3407906Sgm89044 bcopy(src, uiop->uio_iov[vec_idx].iov_base + 3408906Sgm89044 offset, cur_len); 3409906Sgm89044 src += cur_len; 3410906Sgm89044 } 3411906Sgm89044 out->cd_length += cur_len; 3412906Sgm89044 vec_idx++; 3413906Sgm89044 offset = 0; 3414906Sgm89044 } 3415906Sgm89044 3416906Sgm89044 if (vec_idx == uiop->uio_iovcnt && count > 0) { 3417906Sgm89044 /* 3418906Sgm89044 * The end of the specified iovec's was reached but 3419906Sgm89044 * the length requested could not be processed 3420906Sgm89044 * (requested to write more data than space provided). 3421906Sgm89044 */ 3422906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3423906Sgm89044 } 3424906Sgm89044 break; 3425906Sgm89044 3426906Sgm89044 case CRYPTO_DATA_MBLK: 3427906Sgm89044 /* 3428906Sgm89044 * Jump to the first mblk_t that can be written to. 3429906Sgm89044 */ 3430906Sgm89044 for (mp = out->cd_mp; mp != NULL && offset >= MBLKL(mp); 3431906Sgm89044 offset -= MBLKL(mp), mp = mp->b_cont); 3432906Sgm89044 if (mp == NULL) { 3433906Sgm89044 /* 3434906Sgm89044 * The caller specified an offset that is larger than 3435906Sgm89044 * the total size of the buffers it provided. 3436906Sgm89044 */ 3437906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3438906Sgm89044 } 3439906Sgm89044 3440906Sgm89044 /* 3441906Sgm89044 * Now do the processing on the mblk chain. 3442906Sgm89044 */ 3443906Sgm89044 while (mp != NULL && count > 0) { 3444906Sgm89044 cur_len = min(MBLKL(mp) - offset, count); 3445906Sgm89044 count -= cur_len; 3446906Sgm89044 if (reverse) { 3447906Sgm89044 dca_reverse((void*) (src+count), 3448906Sgm89044 (char *)(mp->b_rptr + offset), cur_len, 3449906Sgm89044 cur_len); 3450906Sgm89044 } else { 3451906Sgm89044 bcopy(src, (char *)(mp->b_rptr + offset), 3452906Sgm89044 cur_len); 3453906Sgm89044 src += cur_len; 3454906Sgm89044 } 3455906Sgm89044 out->cd_length += cur_len; 3456906Sgm89044 mp = mp->b_cont; 3457906Sgm89044 offset = 0; 3458906Sgm89044 } 3459906Sgm89044 3460906Sgm89044 if (mp == NULL && count > 0) { 3461906Sgm89044 /* 3462906Sgm89044 * The end of the mblk was reached but the length 3463906Sgm89044 * requested could not be processed, (requested to 3464906Sgm89044 * digest more data than it provided). 3465906Sgm89044 */ 3466906Sgm89044 return (CRYPTO_DATA_LEN_RANGE); 3467906Sgm89044 } 3468906Sgm89044 break; 3469906Sgm89044 3470906Sgm89044 default: 3471906Sgm89044 DBG(NULL, DWARN, "unrecognised crypto data format"); 3472906Sgm89044 rv = CRYPTO_ARGUMENTS_BAD; 3473906Sgm89044 } 3474906Sgm89044 return (rv); 3475906Sgm89044 } 3476906Sgm89044 3477906Sgm89044 /* 3478906Sgm89044 * Compare two byte arrays in reverse order. 3479906Sgm89044 * Return 0 if they are identical, 1 otherwise. 3480906Sgm89044 */ 3481906Sgm89044 int 3482906Sgm89044 dca_bcmp_reverse(const void *s1, const void *s2, size_t n) 3483906Sgm89044 { 3484906Sgm89044 int i; 3485906Sgm89044 caddr_t src, dst; 3486906Sgm89044 3487906Sgm89044 if (!n) 3488906Sgm89044 return (0); 3489906Sgm89044 3490906Sgm89044 src = ((caddr_t)s1) + n - 1; 3491906Sgm89044 dst = (caddr_t)s2; 3492906Sgm89044 for (i = 0; i < n; i++) { 3493906Sgm89044 if (*src != *dst) 3494906Sgm89044 return (1); 3495906Sgm89044 src--; 3496906Sgm89044 dst++; 3497906Sgm89044 } 3498906Sgm89044 3499906Sgm89044 return (0); 3500906Sgm89044 } 3501906Sgm89044 3502906Sgm89044 3503906Sgm89044 /* 3504906Sgm89044 * This calculates the size of a bignum in bits, specifically not counting 3505906Sgm89044 * leading zero bits. This size calculation must be done *before* any 3506906Sgm89044 * endian reversal takes place (i.e. the numbers are in absolute big-endian 3507906Sgm89044 * order.) 3508906Sgm89044 */ 3509906Sgm89044 int 3510906Sgm89044 dca_bitlen(unsigned char *bignum, int bytelen) 3511906Sgm89044 { 3512906Sgm89044 unsigned char msbyte; 3513906Sgm89044 int i, j; 3514906Sgm89044 3515906Sgm89044 for (i = 0; i < bytelen - 1; i++) { 3516906Sgm89044 if (bignum[i] != 0) { 3517906Sgm89044 break; 3518906Sgm89044 } 3519906Sgm89044 } 3520906Sgm89044 msbyte = bignum[i]; 3521906Sgm89044 for (j = 8; j > 1; j--) { 3522906Sgm89044 if (msbyte & 0x80) { 3523906Sgm89044 break; 3524906Sgm89044 } 3525906Sgm89044 msbyte <<= 1; 3526906Sgm89044 } 3527906Sgm89044 return ((8 * (bytelen - i - 1)) + j); 3528906Sgm89044 } 3529906Sgm89044 3530906Sgm89044 /* 3531906Sgm89044 * This compares to bignums (in big-endian order). It ignores leading 3532906Sgm89044 * null bytes. The result semantics follow bcmp, mempcmp, strcmp, etc. 3533906Sgm89044 */ 3534906Sgm89044 int 3535906Sgm89044 dca_numcmp(caddr_t n1, int n1len, caddr_t n2, int n2len) 3536906Sgm89044 { 3537906Sgm89044 while ((n1len > 1) && (*n1 == 0)) { 3538906Sgm89044 n1len--; 3539906Sgm89044 n1++; 3540906Sgm89044 } 3541906Sgm89044 while ((n2len > 1) && (*n2 == 0)) { 3542906Sgm89044 n2len--; 3543906Sgm89044 n2++; 3544906Sgm89044 } 3545906Sgm89044 if (n1len != n2len) { 3546906Sgm89044 return (n1len - n2len); 3547906Sgm89044 } 3548906Sgm89044 while ((n1len > 1) && (*n1 == *n2)) { 3549906Sgm89044 n1++; 3550906Sgm89044 n2++; 3551906Sgm89044 n1len--; 3552906Sgm89044 } 3553906Sgm89044 return ((int)(*(uchar_t *)n1) - (int)(*(uchar_t *)n2)); 3554906Sgm89044 } 3555906Sgm89044 3556906Sgm89044 /* 3557906Sgm89044 * Return array of key attributes. 3558906Sgm89044 */ 3559906Sgm89044 crypto_object_attribute_t * 3560906Sgm89044 dca_get_key_attr(crypto_key_t *key) 3561906Sgm89044 { 3562906Sgm89044 if ((key->ck_format != CRYPTO_KEY_ATTR_LIST) || 3563906Sgm89044 (key->ck_count == 0)) { 3564906Sgm89044 return (NULL); 3565906Sgm89044 } 3566906Sgm89044 3567906Sgm89044 return (key->ck_attrs); 3568906Sgm89044 } 3569906Sgm89044 3570906Sgm89044 /* 3571906Sgm89044 * If attribute type exists valp points to it's 32-bit value. 3572906Sgm89044 */ 3573906Sgm89044 int 3574906Sgm89044 dca_attr_lookup_uint32(crypto_object_attribute_t *attrp, uint_t atnum, 3575906Sgm89044 uint64_t atype, uint32_t *valp) 3576906Sgm89044 { 3577906Sgm89044 crypto_object_attribute_t *bap; 3578906Sgm89044 3579906Sgm89044 bap = dca_find_attribute(attrp, atnum, atype); 3580906Sgm89044 if (bap == NULL) { 3581906Sgm89044 return (CRYPTO_ATTRIBUTE_TYPE_INVALID); 3582906Sgm89044 } 3583906Sgm89044 3584906Sgm89044 *valp = *bap->oa_value; 3585906Sgm89044 3586906Sgm89044 return (CRYPTO_SUCCESS); 3587906Sgm89044 } 3588906Sgm89044 3589906Sgm89044 /* 3590906Sgm89044 * If attribute type exists data contains the start address of the value, 3591906Sgm89044 * and numelems contains it's length. 3592906Sgm89044 */ 3593906Sgm89044 int 3594906Sgm89044 dca_attr_lookup_uint8_array(crypto_object_attribute_t *attrp, uint_t atnum, 3595906Sgm89044 uint64_t atype, void **data, unsigned int *numelems) 3596906Sgm89044 { 3597906Sgm89044 crypto_object_attribute_t *bap; 3598906Sgm89044 3599906Sgm89044 bap = dca_find_attribute(attrp, atnum, atype); 3600906Sgm89044 if (bap == NULL) { 3601906Sgm89044 return (CRYPTO_ATTRIBUTE_TYPE_INVALID); 3602906Sgm89044 } 3603906Sgm89044 3604906Sgm89044 *data = bap->oa_value; 3605906Sgm89044 *numelems = bap->oa_value_len; 3606906Sgm89044 3607906Sgm89044 return (CRYPTO_SUCCESS); 3608906Sgm89044 } 3609906Sgm89044 3610906Sgm89044 /* 3611906Sgm89044 * Finds entry of specified name. If it is not found dca_find_attribute returns 3612906Sgm89044 * NULL. 3613906Sgm89044 */ 3614906Sgm89044 crypto_object_attribute_t * 3615906Sgm89044 dca_find_attribute(crypto_object_attribute_t *attrp, uint_t atnum, 3616906Sgm89044 uint64_t atype) 3617906Sgm89044 { 3618906Sgm89044 while (atnum) { 3619906Sgm89044 if (attrp->oa_type == atype) 3620906Sgm89044 return (attrp); 3621906Sgm89044 atnum--; 3622906Sgm89044 attrp++; 3623906Sgm89044 } 3624906Sgm89044 return (NULL); 3625906Sgm89044 } 3626906Sgm89044 3627906Sgm89044 /* 3628906Sgm89044 * Return the address of the first data buffer. If the data format is 3629906Sgm89044 * unrecognised return NULL. 3630906Sgm89044 */ 3631906Sgm89044 caddr_t 3632906Sgm89044 dca_bufdaddr(crypto_data_t *data) 3633906Sgm89044 { 3634906Sgm89044 switch (data->cd_format) { 3635906Sgm89044 case CRYPTO_DATA_RAW: 3636906Sgm89044 return (data->cd_raw.iov_base + data->cd_offset); 3637906Sgm89044 case CRYPTO_DATA_UIO: 3638906Sgm89044 return (data->cd_uio->uio_iov[0].iov_base + data->cd_offset); 3639906Sgm89044 case CRYPTO_DATA_MBLK: 3640906Sgm89044 return ((char *)data->cd_mp->b_rptr + data->cd_offset); 3641906Sgm89044 default: 3642906Sgm89044 DBG(NULL, DWARN, 3643906Sgm89044 "dca_bufdaddr: unrecognised crypto data format"); 3644906Sgm89044 return (NULL); 3645906Sgm89044 } 3646906Sgm89044 } 3647906Sgm89044 3648906Sgm89044 static caddr_t 3649906Sgm89044 dca_bufdaddr_out(crypto_data_t *data) 3650906Sgm89044 { 3651906Sgm89044 size_t offset = data->cd_offset + data->cd_length; 3652906Sgm89044 3653906Sgm89044 switch (data->cd_format) { 3654906Sgm89044 case CRYPTO_DATA_RAW: 3655906Sgm89044 return (data->cd_raw.iov_base + offset); 3656906Sgm89044 case CRYPTO_DATA_UIO: 3657906Sgm89044 return (data->cd_uio->uio_iov[0].iov_base + offset); 3658906Sgm89044 case CRYPTO_DATA_MBLK: 3659906Sgm89044 return ((char *)data->cd_mp->b_rptr + offset); 3660906Sgm89044 default: 3661906Sgm89044 DBG(NULL, DWARN, 3662906Sgm89044 "dca_bufdaddr_out: unrecognised crypto data format"); 3663906Sgm89044 return (NULL); 3664906Sgm89044 } 3665906Sgm89044 } 3666906Sgm89044 3667906Sgm89044 /* 3668906Sgm89044 * Control entry points. 3669906Sgm89044 */ 3670906Sgm89044 3671906Sgm89044 /* ARGSUSED */ 3672906Sgm89044 static void 3673906Sgm89044 dca_provider_status(crypto_provider_handle_t provider, uint_t *status) 3674906Sgm89044 { 3675906Sgm89044 *status = CRYPTO_PROVIDER_READY; 3676906Sgm89044 } 3677906Sgm89044 3678906Sgm89044 /* 3679906Sgm89044 * Cipher (encrypt/decrypt) entry points. 3680906Sgm89044 */ 3681906Sgm89044 3682906Sgm89044 /* ARGSUSED */ 3683906Sgm89044 static int 3684906Sgm89044 dca_encrypt_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 3685906Sgm89044 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, 3686906Sgm89044 crypto_req_handle_t req) 3687906Sgm89044 { 3688906Sgm89044 int error = CRYPTO_FAILED; 3689906Sgm89044 dca_t *softc; 3690906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 3691906Sgm89044 int instance; 3692906Sgm89044 3693906Sgm89044 /* extract softc and instance number from context */ 3694906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 3695906Sgm89044 DBG(softc, DENTRY, "dca_encrypt_init: started"); 3696906Sgm89044 3697906Sgm89044 /* check mechanism */ 3698906Sgm89044 switch (mechanism->cm_type) { 3699906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 3700906Sgm89044 error = dca_3desctxinit(ctx, mechanism, key, KM_SLEEP, 3701906Sgm89044 DR_ENCRYPT); 3702906Sgm89044 break; 3703906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 3704906Sgm89044 error = dca_3desctxinit(ctx, mechanism, key, KM_SLEEP, 3705906Sgm89044 DR_ENCRYPT | DR_TRIPLE); 3706906Sgm89044 break; 3707906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 3708906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 3709906Sgm89044 error = dca_rsainit(ctx, mechanism, key, KM_SLEEP); 3710906Sgm89044 break; 3711906Sgm89044 default: 3712906Sgm89044 cmn_err(CE_WARN, "dca_encrypt_init: unexpected mech type " 3713906Sgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type); 3714906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 3715906Sgm89044 } 3716906Sgm89044 3717906Sgm89044 DBG(softc, DENTRY, "dca_encrypt_init: done, err = 0x%x", error); 3718906Sgm89044 3719906Sgm89044 if (error == CRYPTO_SUCCESS) 3720906Sgm89044 dca_enlist2(&softc->dca_ctx_list, ctx->cc_provider_private, 3721906Sgm89044 &softc->dca_ctx_list_lock); 3722906Sgm89044 3723906Sgm89044 return (error); 3724906Sgm89044 } 3725906Sgm89044 3726906Sgm89044 /* ARGSUSED */ 3727906Sgm89044 static int 3728906Sgm89044 dca_encrypt(crypto_ctx_t *ctx, crypto_data_t *plaintext, 3729906Sgm89044 crypto_data_t *ciphertext, crypto_req_handle_t req) 3730906Sgm89044 { 3731906Sgm89044 int error = CRYPTO_FAILED; 3732906Sgm89044 dca_t *softc; 3733906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 3734906Sgm89044 int instance; 3735906Sgm89044 3736906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 3737906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 3738906Sgm89044 3739906Sgm89044 /* extract softc and instance number from context */ 3740906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 3741906Sgm89044 DBG(softc, DENTRY, "dca_encrypt: started"); 3742906Sgm89044 3743906Sgm89044 /* check mechanism */ 3744906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 3745906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 3746906Sgm89044 error = dca_3des(ctx, plaintext, ciphertext, req, DR_ENCRYPT); 3747906Sgm89044 break; 3748906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 3749906Sgm89044 error = dca_3des(ctx, plaintext, ciphertext, req, 3750906Sgm89044 DR_ENCRYPT | DR_TRIPLE); 3751906Sgm89044 break; 3752906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 3753906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 3754906Sgm89044 error = dca_rsastart(ctx, plaintext, ciphertext, req, 3755906Sgm89044 DCA_RSA_ENC); 3756906Sgm89044 break; 3757906Sgm89044 default: 3758906Sgm89044 /* Should never reach here */ 3759906Sgm89044 cmn_err(CE_WARN, "dca_encrypt: unexpected mech type " 3760906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 3761906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 3762906Sgm89044 } 3763906Sgm89044 3764906Sgm89044 if ((error != CRYPTO_QUEUED) && (error != CRYPTO_SUCCESS) && 3765906Sgm89044 (error != CRYPTO_BUFFER_TOO_SMALL)) { 3766906Sgm89044 ciphertext->cd_length = 0; 3767906Sgm89044 } 3768906Sgm89044 3769906Sgm89044 DBG(softc, DENTRY, "dca_encrypt: done, err = 0x%x", error); 3770906Sgm89044 3771906Sgm89044 return (error); 3772906Sgm89044 } 3773906Sgm89044 3774906Sgm89044 /* ARGSUSED */ 3775906Sgm89044 static int 3776906Sgm89044 dca_encrypt_update(crypto_ctx_t *ctx, crypto_data_t *plaintext, 3777906Sgm89044 crypto_data_t *ciphertext, crypto_req_handle_t req) 3778906Sgm89044 { 3779906Sgm89044 int error = CRYPTO_FAILED; 3780906Sgm89044 dca_t *softc; 3781906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 3782906Sgm89044 int instance; 3783906Sgm89044 3784906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 3785906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 3786906Sgm89044 3787906Sgm89044 /* extract softc and instance number from context */ 3788906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 3789906Sgm89044 DBG(softc, DENTRY, "dca_encrypt_update: started"); 3790906Sgm89044 3791906Sgm89044 /* check mechanism */ 3792906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 3793906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 3794906Sgm89044 error = dca_3desupdate(ctx, plaintext, ciphertext, req, 3795906Sgm89044 DR_ENCRYPT); 3796906Sgm89044 break; 3797906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 3798906Sgm89044 error = dca_3desupdate(ctx, plaintext, ciphertext, req, 3799906Sgm89044 DR_ENCRYPT | DR_TRIPLE); 3800906Sgm89044 break; 3801906Sgm89044 default: 3802906Sgm89044 /* Should never reach here */ 3803906Sgm89044 cmn_err(CE_WARN, "dca_encrypt_update: unexpected mech type " 3804906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 3805906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 3806906Sgm89044 } 3807906Sgm89044 3808906Sgm89044 DBG(softc, DENTRY, "dca_encrypt_update: done, err = 0x%x", error); 3809906Sgm89044 3810906Sgm89044 return (error); 3811906Sgm89044 } 3812906Sgm89044 3813906Sgm89044 /* ARGSUSED */ 3814906Sgm89044 static int 3815906Sgm89044 dca_encrypt_final(crypto_ctx_t *ctx, crypto_data_t *ciphertext, 3816906Sgm89044 crypto_req_handle_t req) 3817906Sgm89044 { 3818906Sgm89044 int error = CRYPTO_FAILED; 3819906Sgm89044 dca_t *softc; 3820906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 3821906Sgm89044 int instance; 3822906Sgm89044 3823906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 3824906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 3825906Sgm89044 3826906Sgm89044 /* extract softc and instance number from context */ 3827906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 3828906Sgm89044 DBG(softc, DENTRY, "dca_encrypt_final: started"); 3829906Sgm89044 3830906Sgm89044 /* check mechanism */ 3831906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 3832906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 3833906Sgm89044 error = dca_3desfinal(ctx, ciphertext, DR_ENCRYPT); 3834906Sgm89044 break; 3835906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 3836906Sgm89044 error = dca_3desfinal(ctx, ciphertext, DR_ENCRYPT | DR_TRIPLE); 3837906Sgm89044 break; 3838906Sgm89044 default: 3839906Sgm89044 /* Should never reach here */ 3840906Sgm89044 cmn_err(CE_WARN, "dca_encrypt_final: unexpected mech type " 3841906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 3842906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 3843906Sgm89044 } 3844906Sgm89044 3845906Sgm89044 DBG(softc, DENTRY, "dca_encrypt_final: done, err = 0x%x", error); 3846906Sgm89044 3847906Sgm89044 return (error); 3848906Sgm89044 } 3849906Sgm89044 3850906Sgm89044 /* ARGSUSED */ 3851906Sgm89044 static int 3852906Sgm89044 dca_encrypt_atomic(crypto_provider_handle_t provider, 3853906Sgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 3854906Sgm89044 crypto_key_t *key, crypto_data_t *plaintext, crypto_data_t *ciphertext, 3855906Sgm89044 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 3856906Sgm89044 { 3857906Sgm89044 int error = CRYPTO_FAILED; 3858906Sgm89044 dca_t *softc = (dca_t *)provider; 3859906Sgm89044 3860906Sgm89044 DBG(softc, DENTRY, "dca_encrypt_atomic: started"); 3861906Sgm89044 3862906Sgm89044 if (ctx_template != NULL) 3863906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 3864906Sgm89044 3865906Sgm89044 /* check mechanism */ 3866906Sgm89044 switch (mechanism->cm_type) { 3867906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 3868906Sgm89044 error = dca_3desatomic(provider, session_id, mechanism, key, 3869906Sgm89044 plaintext, ciphertext, KM_SLEEP, req, 3870906Sgm89044 DR_ENCRYPT | DR_ATOMIC); 3871906Sgm89044 break; 3872906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 3873906Sgm89044 error = dca_3desatomic(provider, session_id, mechanism, key, 3874906Sgm89044 plaintext, ciphertext, KM_SLEEP, req, 3875906Sgm89044 DR_ENCRYPT | DR_TRIPLE | DR_ATOMIC); 3876906Sgm89044 break; 3877906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 3878906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 3879906Sgm89044 error = dca_rsaatomic(provider, session_id, mechanism, key, 3880906Sgm89044 plaintext, ciphertext, KM_SLEEP, req, DCA_RSA_ENC); 3881906Sgm89044 break; 3882906Sgm89044 default: 3883906Sgm89044 cmn_err(CE_WARN, "dca_encrypt_atomic: unexpected mech type " 3884906Sgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type); 3885906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 3886906Sgm89044 } 3887906Sgm89044 3888906Sgm89044 if ((error != CRYPTO_QUEUED) && (error != CRYPTO_SUCCESS)) { 3889906Sgm89044 ciphertext->cd_length = 0; 3890906Sgm89044 } 3891906Sgm89044 3892906Sgm89044 DBG(softc, DENTRY, "dca_encrypt_atomic: done, err = 0x%x", error); 3893906Sgm89044 3894906Sgm89044 return (error); 3895906Sgm89044 } 3896906Sgm89044 3897906Sgm89044 /* ARGSUSED */ 3898906Sgm89044 static int 3899906Sgm89044 dca_decrypt_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 3900906Sgm89044 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, 3901906Sgm89044 crypto_req_handle_t req) 3902906Sgm89044 { 3903906Sgm89044 int error = CRYPTO_FAILED; 3904906Sgm89044 dca_t *softc; 3905906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 3906906Sgm89044 int instance; 3907906Sgm89044 3908906Sgm89044 /* extract softc and instance number from context */ 3909906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 3910906Sgm89044 DBG(softc, DENTRY, "dca_decrypt_init: started"); 3911906Sgm89044 3912906Sgm89044 /* check mechanism */ 3913906Sgm89044 switch (mechanism->cm_type) { 3914906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 3915906Sgm89044 error = dca_3desctxinit(ctx, mechanism, key, KM_SLEEP, 3916906Sgm89044 DR_DECRYPT); 3917906Sgm89044 break; 3918906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 3919906Sgm89044 error = dca_3desctxinit(ctx, mechanism, key, KM_SLEEP, 3920906Sgm89044 DR_DECRYPT | DR_TRIPLE); 3921906Sgm89044 break; 3922906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 3923906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 3924906Sgm89044 error = dca_rsainit(ctx, mechanism, key, KM_SLEEP); 3925906Sgm89044 break; 3926906Sgm89044 default: 3927906Sgm89044 cmn_err(CE_WARN, "dca_decrypt_init: unexpected mech type " 3928906Sgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type); 3929906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 3930906Sgm89044 } 3931906Sgm89044 3932906Sgm89044 DBG(softc, DENTRY, "dca_decrypt_init: done, err = 0x%x", error); 3933906Sgm89044 3934906Sgm89044 if (error == CRYPTO_SUCCESS) 3935906Sgm89044 dca_enlist2(&softc->dca_ctx_list, ctx->cc_provider_private, 3936906Sgm89044 &softc->dca_ctx_list_lock); 3937906Sgm89044 3938906Sgm89044 return (error); 3939906Sgm89044 } 3940906Sgm89044 3941906Sgm89044 /* ARGSUSED */ 3942906Sgm89044 static int 3943906Sgm89044 dca_decrypt(crypto_ctx_t *ctx, crypto_data_t *ciphertext, 3944906Sgm89044 crypto_data_t *plaintext, crypto_req_handle_t req) 3945906Sgm89044 { 3946906Sgm89044 int error = CRYPTO_FAILED; 3947906Sgm89044 dca_t *softc; 3948906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 3949906Sgm89044 int instance; 3950906Sgm89044 3951906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 3952906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 3953906Sgm89044 3954906Sgm89044 /* extract softc and instance number from context */ 3955906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 3956906Sgm89044 DBG(softc, DENTRY, "dca_decrypt: started"); 3957906Sgm89044 3958906Sgm89044 /* check mechanism */ 3959906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 3960906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 3961906Sgm89044 error = dca_3des(ctx, ciphertext, plaintext, req, DR_DECRYPT); 3962906Sgm89044 break; 3963906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 3964906Sgm89044 error = dca_3des(ctx, ciphertext, plaintext, req, 3965906Sgm89044 DR_DECRYPT | DR_TRIPLE); 3966906Sgm89044 break; 3967906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 3968906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 3969906Sgm89044 error = dca_rsastart(ctx, ciphertext, plaintext, req, 3970906Sgm89044 DCA_RSA_DEC); 3971906Sgm89044 break; 3972906Sgm89044 default: 3973906Sgm89044 /* Should never reach here */ 3974906Sgm89044 cmn_err(CE_WARN, "dca_decrypt: unexpected mech type " 3975906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 3976906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 3977906Sgm89044 } 3978906Sgm89044 3979906Sgm89044 if ((error != CRYPTO_QUEUED) && (error != CRYPTO_SUCCESS) && 3980906Sgm89044 (error != CRYPTO_BUFFER_TOO_SMALL)) { 3981906Sgm89044 if (plaintext) 3982906Sgm89044 plaintext->cd_length = 0; 3983906Sgm89044 } 3984906Sgm89044 3985906Sgm89044 DBG(softc, DENTRY, "dca_decrypt: done, err = 0x%x", error); 3986906Sgm89044 3987906Sgm89044 return (error); 3988906Sgm89044 } 3989906Sgm89044 3990906Sgm89044 /* ARGSUSED */ 3991906Sgm89044 static int 3992906Sgm89044 dca_decrypt_update(crypto_ctx_t *ctx, crypto_data_t *ciphertext, 3993906Sgm89044 crypto_data_t *plaintext, crypto_req_handle_t req) 3994906Sgm89044 { 3995906Sgm89044 int error = CRYPTO_FAILED; 3996906Sgm89044 dca_t *softc; 3997906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 3998906Sgm89044 int instance; 3999906Sgm89044 4000906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4001906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4002906Sgm89044 4003906Sgm89044 /* extract softc and instance number from context */ 4004906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4005906Sgm89044 DBG(softc, DENTRY, "dca_decrypt_update: started"); 4006906Sgm89044 4007906Sgm89044 /* check mechanism */ 4008906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 4009906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 4010906Sgm89044 error = dca_3desupdate(ctx, ciphertext, plaintext, req, 4011906Sgm89044 DR_DECRYPT); 4012906Sgm89044 break; 4013906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 4014906Sgm89044 error = dca_3desupdate(ctx, ciphertext, plaintext, req, 4015906Sgm89044 DR_DECRYPT | DR_TRIPLE); 4016906Sgm89044 break; 4017906Sgm89044 default: 4018906Sgm89044 /* Should never reach here */ 4019906Sgm89044 cmn_err(CE_WARN, "dca_decrypt_update: unexpected mech type " 4020906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4021906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4022906Sgm89044 } 4023906Sgm89044 4024906Sgm89044 DBG(softc, DENTRY, "dca_decrypt_update: done, err = 0x%x", error); 4025906Sgm89044 4026906Sgm89044 return (error); 4027906Sgm89044 } 4028906Sgm89044 4029906Sgm89044 /* ARGSUSED */ 4030906Sgm89044 static int 4031906Sgm89044 dca_decrypt_final(crypto_ctx_t *ctx, crypto_data_t *plaintext, 4032906Sgm89044 crypto_req_handle_t req) 4033906Sgm89044 { 4034906Sgm89044 int error = CRYPTO_FAILED; 4035906Sgm89044 dca_t *softc; 4036906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4037906Sgm89044 int instance; 4038906Sgm89044 4039906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4040906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4041906Sgm89044 4042906Sgm89044 /* extract softc and instance number from context */ 4043906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4044906Sgm89044 DBG(softc, DENTRY, "dca_decrypt_final: started"); 4045906Sgm89044 4046906Sgm89044 /* check mechanism */ 4047906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 4048906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 4049906Sgm89044 error = dca_3desfinal(ctx, plaintext, DR_DECRYPT); 4050906Sgm89044 break; 4051906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 4052906Sgm89044 error = dca_3desfinal(ctx, plaintext, DR_DECRYPT | DR_TRIPLE); 4053906Sgm89044 break; 4054906Sgm89044 default: 4055906Sgm89044 /* Should never reach here */ 4056906Sgm89044 cmn_err(CE_WARN, "dca_decrypt_final: unexpected mech type " 4057906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4058906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4059906Sgm89044 } 4060906Sgm89044 4061906Sgm89044 DBG(softc, DENTRY, "dca_decrypt_final: done, err = 0x%x", error); 4062906Sgm89044 4063906Sgm89044 return (error); 4064906Sgm89044 } 4065906Sgm89044 4066906Sgm89044 /* ARGSUSED */ 4067906Sgm89044 static int 4068906Sgm89044 dca_decrypt_atomic(crypto_provider_handle_t provider, 4069906Sgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 4070906Sgm89044 crypto_key_t *key, crypto_data_t *ciphertext, crypto_data_t *plaintext, 4071906Sgm89044 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 4072906Sgm89044 { 4073906Sgm89044 int error = CRYPTO_FAILED; 4074906Sgm89044 dca_t *softc = (dca_t *)provider; 4075906Sgm89044 4076906Sgm89044 DBG(softc, DENTRY, "dca_decrypt_atomic: started"); 4077906Sgm89044 4078906Sgm89044 if (ctx_template != NULL) 4079906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 4080906Sgm89044 4081906Sgm89044 /* check mechanism */ 4082906Sgm89044 switch (mechanism->cm_type) { 4083906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 4084906Sgm89044 error = dca_3desatomic(provider, session_id, mechanism, key, 4085906Sgm89044 ciphertext, plaintext, KM_SLEEP, req, 4086906Sgm89044 DR_DECRYPT | DR_ATOMIC); 4087906Sgm89044 break; 4088906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 4089906Sgm89044 error = dca_3desatomic(provider, session_id, mechanism, key, 4090906Sgm89044 ciphertext, plaintext, KM_SLEEP, req, 4091906Sgm89044 DR_DECRYPT | DR_TRIPLE | DR_ATOMIC); 4092906Sgm89044 break; 4093906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4094906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4095906Sgm89044 error = dca_rsaatomic(provider, session_id, mechanism, key, 4096906Sgm89044 ciphertext, plaintext, KM_SLEEP, req, DCA_RSA_DEC); 4097906Sgm89044 break; 4098906Sgm89044 default: 4099906Sgm89044 cmn_err(CE_WARN, "dca_decrypt_atomic: unexpected mech type " 4100906Sgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type); 4101906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4102906Sgm89044 } 4103906Sgm89044 4104906Sgm89044 if ((error != CRYPTO_QUEUED) && (error != CRYPTO_SUCCESS)) { 4105906Sgm89044 plaintext->cd_length = 0; 4106906Sgm89044 } 4107906Sgm89044 4108906Sgm89044 DBG(softc, DENTRY, "dca_decrypt_atomic: done, err = 0x%x", error); 4109906Sgm89044 4110906Sgm89044 return (error); 4111906Sgm89044 } 4112906Sgm89044 4113906Sgm89044 /* 4114906Sgm89044 * Sign entry points. 4115906Sgm89044 */ 4116906Sgm89044 4117906Sgm89044 /* ARGSUSED */ 4118906Sgm89044 static int 4119906Sgm89044 dca_sign_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 4120906Sgm89044 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, 4121906Sgm89044 crypto_req_handle_t req) 4122906Sgm89044 { 4123906Sgm89044 int error = CRYPTO_FAILED; 4124906Sgm89044 dca_t *softc; 4125906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4126906Sgm89044 int instance; 4127906Sgm89044 4128906Sgm89044 /* extract softc and instance number from context */ 4129906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4130906Sgm89044 DBG(softc, DENTRY, "dca_sign_init: started\n"); 4131906Sgm89044 4132906Sgm89044 if (ctx_template != NULL) 4133906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 4134906Sgm89044 4135906Sgm89044 /* check mechanism */ 4136906Sgm89044 switch (mechanism->cm_type) { 4137906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4138906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4139906Sgm89044 error = dca_rsainit(ctx, mechanism, key, KM_SLEEP); 4140906Sgm89044 break; 4141906Sgm89044 case DSA_MECH_INFO_TYPE: 4142906Sgm89044 error = dca_dsainit(ctx, mechanism, key, KM_SLEEP, 4143906Sgm89044 DCA_DSA_SIGN); 4144906Sgm89044 break; 4145906Sgm89044 default: 4146906Sgm89044 cmn_err(CE_WARN, "dca_sign_init: unexpected mech type " 4147906Sgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type); 4148906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4149906Sgm89044 } 4150906Sgm89044 4151906Sgm89044 DBG(softc, DENTRY, "dca_sign_init: done, err = 0x%x", error); 4152906Sgm89044 4153906Sgm89044 if (error == CRYPTO_SUCCESS) 4154906Sgm89044 dca_enlist2(&softc->dca_ctx_list, ctx->cc_provider_private, 4155906Sgm89044 &softc->dca_ctx_list_lock); 4156906Sgm89044 4157906Sgm89044 return (error); 4158906Sgm89044 } 4159906Sgm89044 4160906Sgm89044 static int 4161906Sgm89044 dca_sign(crypto_ctx_t *ctx, crypto_data_t *data, 4162906Sgm89044 crypto_data_t *signature, crypto_req_handle_t req) 4163906Sgm89044 { 4164906Sgm89044 int error = CRYPTO_FAILED; 4165906Sgm89044 dca_t *softc; 4166906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4167906Sgm89044 int instance; 4168906Sgm89044 4169906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4170906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4171906Sgm89044 4172906Sgm89044 /* extract softc and instance number from context */ 4173906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4174906Sgm89044 DBG(softc, DENTRY, "dca_sign: started\n"); 4175906Sgm89044 4176906Sgm89044 /* check mechanism */ 4177906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 4178906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4179906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4180906Sgm89044 error = dca_rsastart(ctx, data, signature, req, DCA_RSA_SIGN); 4181906Sgm89044 break; 4182906Sgm89044 case DSA_MECH_INFO_TYPE: 4183906Sgm89044 error = dca_dsa_sign(ctx, data, signature, req); 4184906Sgm89044 break; 4185906Sgm89044 default: 4186906Sgm89044 cmn_err(CE_WARN, "dca_sign: unexpected mech type " 4187906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4188906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4189906Sgm89044 } 4190906Sgm89044 4191906Sgm89044 DBG(softc, DENTRY, "dca_sign: done, err = 0x%x", error); 4192906Sgm89044 4193906Sgm89044 return (error); 4194906Sgm89044 } 4195906Sgm89044 4196906Sgm89044 /* ARGSUSED */ 4197906Sgm89044 static int 4198906Sgm89044 dca_sign_update(crypto_ctx_t *ctx, crypto_data_t *data, 4199906Sgm89044 crypto_req_handle_t req) 4200906Sgm89044 { 4201906Sgm89044 int error = CRYPTO_MECHANISM_INVALID; 4202906Sgm89044 dca_t *softc; 4203906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4204906Sgm89044 int instance; 4205906Sgm89044 4206906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4207906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4208906Sgm89044 4209906Sgm89044 /* extract softc and instance number from context */ 4210906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4211906Sgm89044 DBG(softc, DENTRY, "dca_sign_update: started\n"); 4212906Sgm89044 4213906Sgm89044 cmn_err(CE_WARN, "dca_sign_update: unexpected mech type " 4214906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4215906Sgm89044 4216906Sgm89044 DBG(softc, DENTRY, "dca_sign_update: done, err = 0x%x", error); 4217906Sgm89044 4218906Sgm89044 return (error); 4219906Sgm89044 } 4220906Sgm89044 4221906Sgm89044 /* ARGSUSED */ 4222906Sgm89044 static int 4223906Sgm89044 dca_sign_final(crypto_ctx_t *ctx, crypto_data_t *signature, 4224906Sgm89044 crypto_req_handle_t req) 4225906Sgm89044 { 4226906Sgm89044 int error = CRYPTO_MECHANISM_INVALID; 4227906Sgm89044 dca_t *softc; 4228906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4229906Sgm89044 int instance; 4230906Sgm89044 4231906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4232906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4233906Sgm89044 4234906Sgm89044 /* extract softc and instance number from context */ 4235906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4236906Sgm89044 DBG(softc, DENTRY, "dca_sign_final: started\n"); 4237906Sgm89044 4238906Sgm89044 cmn_err(CE_WARN, "dca_sign_final: unexpected mech type " 4239906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4240906Sgm89044 4241906Sgm89044 DBG(softc, DENTRY, "dca_sign_final: done, err = 0x%x", error); 4242906Sgm89044 4243906Sgm89044 return (error); 4244906Sgm89044 } 4245906Sgm89044 4246906Sgm89044 static int 4247906Sgm89044 dca_sign_atomic(crypto_provider_handle_t provider, 4248906Sgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 4249906Sgm89044 crypto_key_t *key, crypto_data_t *data, crypto_data_t *signature, 4250906Sgm89044 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 4251906Sgm89044 { 4252906Sgm89044 int error = CRYPTO_FAILED; 4253906Sgm89044 dca_t *softc = (dca_t *)provider; 4254906Sgm89044 4255906Sgm89044 DBG(softc, DENTRY, "dca_sign_atomic: started\n"); 4256906Sgm89044 4257906Sgm89044 if (ctx_template != NULL) 4258906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 4259906Sgm89044 4260906Sgm89044 /* check mechanism */ 4261906Sgm89044 switch (mechanism->cm_type) { 4262906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4263906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4264906Sgm89044 error = dca_rsaatomic(provider, session_id, mechanism, key, 4265906Sgm89044 data, signature, KM_SLEEP, req, DCA_RSA_SIGN); 4266906Sgm89044 break; 4267906Sgm89044 case DSA_MECH_INFO_TYPE: 4268906Sgm89044 error = dca_dsaatomic(provider, session_id, mechanism, key, 4269906Sgm89044 data, signature, KM_SLEEP, req, DCA_DSA_SIGN); 4270906Sgm89044 break; 4271906Sgm89044 default: 4272906Sgm89044 cmn_err(CE_WARN, "dca_sign_atomic: unexpected mech type " 4273906Sgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type); 4274906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4275906Sgm89044 } 4276906Sgm89044 4277906Sgm89044 DBG(softc, DENTRY, "dca_sign_atomic: done, err = 0x%x", error); 4278906Sgm89044 4279906Sgm89044 return (error); 4280906Sgm89044 } 4281906Sgm89044 4282906Sgm89044 /* ARGSUSED */ 4283906Sgm89044 static int 4284906Sgm89044 dca_sign_recover_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 4285906Sgm89044 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, 4286906Sgm89044 crypto_req_handle_t req) 4287906Sgm89044 { 4288906Sgm89044 int error = CRYPTO_FAILED; 4289906Sgm89044 dca_t *softc; 4290906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4291906Sgm89044 int instance; 4292906Sgm89044 4293906Sgm89044 /* extract softc and instance number from context */ 4294906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4295906Sgm89044 DBG(softc, DENTRY, "dca_sign_recover_init: started\n"); 4296906Sgm89044 4297906Sgm89044 if (ctx_template != NULL) 4298906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 4299906Sgm89044 4300906Sgm89044 /* check mechanism */ 4301906Sgm89044 switch (mechanism->cm_type) { 4302906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4303906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4304906Sgm89044 error = dca_rsainit(ctx, mechanism, key, KM_SLEEP); 4305906Sgm89044 break; 4306906Sgm89044 default: 4307906Sgm89044 cmn_err(CE_WARN, "dca_sign_recover_init: unexpected mech type " 4308906Sgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type); 4309906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4310906Sgm89044 } 4311906Sgm89044 4312906Sgm89044 DBG(softc, DENTRY, "dca_sign_recover_init: done, err = 0x%x", error); 4313906Sgm89044 4314906Sgm89044 if (error == CRYPTO_SUCCESS) 4315906Sgm89044 dca_enlist2(&softc->dca_ctx_list, ctx->cc_provider_private, 4316906Sgm89044 &softc->dca_ctx_list_lock); 4317906Sgm89044 4318906Sgm89044 return (error); 4319906Sgm89044 } 4320906Sgm89044 4321906Sgm89044 static int 4322906Sgm89044 dca_sign_recover(crypto_ctx_t *ctx, crypto_data_t *data, 4323906Sgm89044 crypto_data_t *signature, crypto_req_handle_t req) 4324906Sgm89044 { 4325906Sgm89044 int error = CRYPTO_FAILED; 4326906Sgm89044 dca_t *softc; 4327906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4328906Sgm89044 int instance; 4329906Sgm89044 4330906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4331906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4332906Sgm89044 4333906Sgm89044 /* extract softc and instance number from context */ 4334906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4335906Sgm89044 DBG(softc, DENTRY, "dca_sign_recover: started\n"); 4336906Sgm89044 4337906Sgm89044 /* check mechanism */ 4338906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 4339906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4340906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4341906Sgm89044 error = dca_rsastart(ctx, data, signature, req, DCA_RSA_SIGNR); 4342906Sgm89044 break; 4343906Sgm89044 default: 4344906Sgm89044 cmn_err(CE_WARN, "dca_sign_recover: unexpected mech type " 4345906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4346906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4347906Sgm89044 } 4348906Sgm89044 4349906Sgm89044 DBG(softc, DENTRY, "dca_sign_recover: done, err = 0x%x", error); 4350906Sgm89044 4351906Sgm89044 return (error); 4352906Sgm89044 } 4353906Sgm89044 4354906Sgm89044 static int 4355906Sgm89044 dca_sign_recover_atomic(crypto_provider_handle_t provider, 4356906Sgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 4357906Sgm89044 crypto_key_t *key, crypto_data_t *data, crypto_data_t *signature, 4358906Sgm89044 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 4359906Sgm89044 { 4360906Sgm89044 int error = CRYPTO_FAILED; 4361906Sgm89044 dca_t *softc = (dca_t *)provider; 4362906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4363906Sgm89044 int instance; 4364906Sgm89044 4365906Sgm89044 instance = ddi_get_instance(softc->dca_dip); 4366906Sgm89044 DBG(softc, DENTRY, "dca_sign_recover_atomic: started\n"); 4367906Sgm89044 4368906Sgm89044 if (ctx_template != NULL) 4369906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 4370906Sgm89044 4371906Sgm89044 /* check mechanism */ 4372906Sgm89044 switch (mechanism->cm_type) { 4373906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4374906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4375906Sgm89044 error = dca_rsaatomic(provider, session_id, mechanism, key, 4376906Sgm89044 data, signature, KM_SLEEP, req, DCA_RSA_SIGNR); 4377906Sgm89044 break; 4378906Sgm89044 default: 4379906Sgm89044 cmn_err(CE_WARN, "dca_sign_recover_atomic: unexpected mech type" 4380906Sgm89044 " 0x%llx\n", (unsigned long long)mechanism->cm_type); 4381906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4382906Sgm89044 } 4383906Sgm89044 4384906Sgm89044 DBG(softc, DENTRY, "dca_sign_recover_atomic: done, err = 0x%x", error); 4385906Sgm89044 4386906Sgm89044 return (error); 4387906Sgm89044 } 4388906Sgm89044 4389906Sgm89044 /* 4390906Sgm89044 * Verify entry points. 4391906Sgm89044 */ 4392906Sgm89044 4393906Sgm89044 /* ARGSUSED */ 4394906Sgm89044 static int 4395906Sgm89044 dca_verify_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 4396906Sgm89044 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, 4397906Sgm89044 crypto_req_handle_t req) 4398906Sgm89044 { 4399906Sgm89044 int error = CRYPTO_FAILED; 4400906Sgm89044 dca_t *softc; 4401906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4402906Sgm89044 int instance; 4403906Sgm89044 4404906Sgm89044 /* extract softc and instance number from context */ 4405906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4406906Sgm89044 DBG(softc, DENTRY, "dca_verify_init: started\n"); 4407906Sgm89044 4408906Sgm89044 if (ctx_template != NULL) 4409906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 4410906Sgm89044 4411906Sgm89044 /* check mechanism */ 4412906Sgm89044 switch (mechanism->cm_type) { 4413906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4414906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4415906Sgm89044 error = dca_rsainit(ctx, mechanism, key, KM_SLEEP); 4416906Sgm89044 break; 4417906Sgm89044 case DSA_MECH_INFO_TYPE: 4418906Sgm89044 error = dca_dsainit(ctx, mechanism, key, KM_SLEEP, 4419906Sgm89044 DCA_DSA_VRFY); 4420906Sgm89044 break; 4421906Sgm89044 default: 4422906Sgm89044 cmn_err(CE_WARN, "dca_verify_init: unexpected mech type " 4423906Sgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type); 4424906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4425906Sgm89044 } 4426906Sgm89044 4427906Sgm89044 DBG(softc, DENTRY, "dca_verify_init: done, err = 0x%x", error); 4428906Sgm89044 4429906Sgm89044 if (error == CRYPTO_SUCCESS) 4430906Sgm89044 dca_enlist2(&softc->dca_ctx_list, ctx->cc_provider_private, 4431906Sgm89044 &softc->dca_ctx_list_lock); 4432906Sgm89044 4433906Sgm89044 return (error); 4434906Sgm89044 } 4435906Sgm89044 4436906Sgm89044 static int 4437906Sgm89044 dca_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *signature, 4438906Sgm89044 crypto_req_handle_t req) 4439906Sgm89044 { 4440906Sgm89044 int error = CRYPTO_FAILED; 4441906Sgm89044 dca_t *softc; 4442906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4443906Sgm89044 int instance; 4444906Sgm89044 4445906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4446906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4447906Sgm89044 4448906Sgm89044 /* extract softc and instance number from context */ 4449906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4450906Sgm89044 DBG(softc, DENTRY, "dca_verify: started\n"); 4451906Sgm89044 4452906Sgm89044 /* check mechanism */ 4453906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 4454906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4455906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4456906Sgm89044 error = dca_rsastart(ctx, signature, data, req, DCA_RSA_VRFY); 4457906Sgm89044 break; 4458906Sgm89044 case DSA_MECH_INFO_TYPE: 4459906Sgm89044 error = dca_dsa_verify(ctx, data, signature, req); 4460906Sgm89044 break; 4461906Sgm89044 default: 4462906Sgm89044 cmn_err(CE_WARN, "dca_verify: unexpected mech type " 4463906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4464906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4465906Sgm89044 } 4466906Sgm89044 4467906Sgm89044 DBG(softc, DENTRY, "dca_verify: done, err = 0x%x", error); 4468906Sgm89044 4469906Sgm89044 return (error); 4470906Sgm89044 } 4471906Sgm89044 4472906Sgm89044 /* ARGSUSED */ 4473906Sgm89044 static int 4474906Sgm89044 dca_verify_update(crypto_ctx_t *ctx, crypto_data_t *data, 4475906Sgm89044 crypto_req_handle_t req) 4476906Sgm89044 { 4477906Sgm89044 int error = CRYPTO_MECHANISM_INVALID; 4478906Sgm89044 dca_t *softc; 4479906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4480906Sgm89044 int instance; 4481906Sgm89044 4482906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4483906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4484906Sgm89044 4485906Sgm89044 /* extract softc and instance number from context */ 4486906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4487906Sgm89044 DBG(softc, DENTRY, "dca_verify_update: started\n"); 4488906Sgm89044 4489906Sgm89044 cmn_err(CE_WARN, "dca_verify_update: unexpected mech type " 4490906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4491906Sgm89044 4492906Sgm89044 DBG(softc, DENTRY, "dca_verify_update: done, err = 0x%x", error); 4493906Sgm89044 4494906Sgm89044 return (error); 4495906Sgm89044 } 4496906Sgm89044 4497906Sgm89044 /* ARGSUSED */ 4498906Sgm89044 static int 4499906Sgm89044 dca_verify_final(crypto_ctx_t *ctx, crypto_data_t *signature, 4500906Sgm89044 crypto_req_handle_t req) 4501906Sgm89044 { 4502906Sgm89044 int error = CRYPTO_MECHANISM_INVALID; 4503906Sgm89044 dca_t *softc; 4504906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4505906Sgm89044 int instance; 4506906Sgm89044 4507906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4508906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4509906Sgm89044 4510906Sgm89044 /* extract softc and instance number from context */ 4511906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4512906Sgm89044 DBG(softc, DENTRY, "dca_verify_final: started\n"); 4513906Sgm89044 4514906Sgm89044 cmn_err(CE_WARN, "dca_verify_final: unexpected mech type " 4515906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4516906Sgm89044 4517906Sgm89044 DBG(softc, DENTRY, "dca_verify_final: done, err = 0x%x", error); 4518906Sgm89044 4519906Sgm89044 return (error); 4520906Sgm89044 } 4521906Sgm89044 4522906Sgm89044 static int 4523906Sgm89044 dca_verify_atomic(crypto_provider_handle_t provider, 4524906Sgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 4525906Sgm89044 crypto_key_t *key, crypto_data_t *data, crypto_data_t *signature, 4526906Sgm89044 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 4527906Sgm89044 { 4528906Sgm89044 int error = CRYPTO_FAILED; 4529906Sgm89044 dca_t *softc = (dca_t *)provider; 4530906Sgm89044 4531906Sgm89044 DBG(softc, DENTRY, "dca_verify_atomic: started\n"); 4532906Sgm89044 4533906Sgm89044 if (ctx_template != NULL) 4534906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 4535906Sgm89044 4536906Sgm89044 /* check mechanism */ 4537906Sgm89044 switch (mechanism->cm_type) { 4538906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4539906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4540906Sgm89044 error = dca_rsaatomic(provider, session_id, mechanism, key, 4541906Sgm89044 signature, data, KM_SLEEP, req, DCA_RSA_VRFY); 4542906Sgm89044 break; 4543906Sgm89044 case DSA_MECH_INFO_TYPE: 4544906Sgm89044 error = dca_dsaatomic(provider, session_id, mechanism, key, 4545906Sgm89044 data, signature, KM_SLEEP, req, DCA_DSA_VRFY); 4546906Sgm89044 break; 4547906Sgm89044 default: 4548906Sgm89044 cmn_err(CE_WARN, "dca_verify_atomic: unexpected mech type " 4549906Sgm89044 "0x%llx\n", (unsigned long long)mechanism->cm_type); 4550906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4551906Sgm89044 } 4552906Sgm89044 4553906Sgm89044 DBG(softc, DENTRY, "dca_verify_atomic: done, err = 0x%x", error); 4554906Sgm89044 4555906Sgm89044 return (error); 4556906Sgm89044 } 4557906Sgm89044 4558906Sgm89044 /* ARGSUSED */ 4559906Sgm89044 static int 4560906Sgm89044 dca_verify_recover_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 4561906Sgm89044 crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, 4562906Sgm89044 crypto_req_handle_t req) 4563906Sgm89044 { 4564906Sgm89044 int error = CRYPTO_MECHANISM_INVALID; 4565906Sgm89044 dca_t *softc; 4566906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4567906Sgm89044 int instance; 4568906Sgm89044 4569906Sgm89044 /* extract softc and instance number from context */ 4570906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4571906Sgm89044 DBG(softc, DENTRY, "dca_verify_recover_init: started\n"); 4572906Sgm89044 4573906Sgm89044 if (ctx_template != NULL) 4574906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 4575906Sgm89044 4576906Sgm89044 /* check mechanism */ 4577906Sgm89044 switch (mechanism->cm_type) { 4578906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4579906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4580906Sgm89044 error = dca_rsainit(ctx, mechanism, key, KM_SLEEP); 4581906Sgm89044 break; 4582906Sgm89044 default: 4583906Sgm89044 cmn_err(CE_WARN, "dca_verify_recover_init: unexpected mech type" 4584906Sgm89044 " 0x%llx\n", (unsigned long long)mechanism->cm_type); 4585906Sgm89044 } 4586906Sgm89044 4587906Sgm89044 DBG(softc, DENTRY, "dca_verify_recover_init: done, err = 0x%x", error); 4588906Sgm89044 4589906Sgm89044 if (error == CRYPTO_SUCCESS) 4590906Sgm89044 dca_enlist2(&softc->dca_ctx_list, ctx->cc_provider_private, 4591906Sgm89044 &softc->dca_ctx_list_lock); 4592906Sgm89044 4593906Sgm89044 return (error); 4594906Sgm89044 } 4595906Sgm89044 4596906Sgm89044 static int 4597906Sgm89044 dca_verify_recover(crypto_ctx_t *ctx, crypto_data_t *signature, 4598906Sgm89044 crypto_data_t *data, crypto_req_handle_t req) 4599906Sgm89044 { 4600906Sgm89044 int error = CRYPTO_MECHANISM_INVALID; 4601906Sgm89044 dca_t *softc; 4602906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4603906Sgm89044 int instance; 4604906Sgm89044 4605906Sgm89044 if (!ctx || !ctx->cc_provider || !ctx->cc_provider_private) 4606906Sgm89044 return (CRYPTO_OPERATION_NOT_INITIALIZED); 4607906Sgm89044 4608906Sgm89044 /* extract softc and instance number from context */ 4609906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4610906Sgm89044 DBG(softc, DENTRY, "dca_verify_recover: started\n"); 4611906Sgm89044 4612906Sgm89044 /* check mechanism */ 4613906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 4614906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4615906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4616906Sgm89044 error = dca_rsastart(ctx, signature, data, req, DCA_RSA_VRFYR); 4617906Sgm89044 break; 4618906Sgm89044 default: 4619906Sgm89044 cmn_err(CE_WARN, "dca_verify_recover: unexpected mech type " 4620906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4621906Sgm89044 } 4622906Sgm89044 4623906Sgm89044 DBG(softc, DENTRY, "dca_verify_recover: done, err = 0x%x", error); 4624906Sgm89044 4625906Sgm89044 return (error); 4626906Sgm89044 } 4627906Sgm89044 4628906Sgm89044 static int 4629906Sgm89044 dca_verify_recover_atomic(crypto_provider_handle_t provider, 4630906Sgm89044 crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 4631906Sgm89044 crypto_key_t *key, crypto_data_t *data, crypto_data_t *signature, 4632906Sgm89044 crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 4633906Sgm89044 { 4634906Sgm89044 int error = CRYPTO_MECHANISM_INVALID; 4635906Sgm89044 dca_t *softc = (dca_t *)provider; 4636906Sgm89044 4637906Sgm89044 DBG(softc, DENTRY, "dca_verify_recover_atomic: started\n"); 4638906Sgm89044 4639906Sgm89044 if (ctx_template != NULL) 4640906Sgm89044 return (CRYPTO_ARGUMENTS_BAD); 4641906Sgm89044 4642906Sgm89044 /* check mechanism */ 4643906Sgm89044 switch (mechanism->cm_type) { 4644906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4645906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4646906Sgm89044 error = dca_rsaatomic(provider, session_id, mechanism, key, 4647906Sgm89044 signature, data, KM_SLEEP, req, DCA_RSA_VRFYR); 4648906Sgm89044 break; 4649906Sgm89044 default: 4650906Sgm89044 cmn_err(CE_WARN, "dca_verify_recover_atomic: unexpected mech " 4651906Sgm89044 "type 0x%llx\n", (unsigned long long)mechanism->cm_type); 4652906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4653906Sgm89044 } 4654906Sgm89044 4655906Sgm89044 DBG(softc, DENTRY, 4656906Sgm89044 "dca_verify_recover_atomic: done, err = 0x%x", error); 4657906Sgm89044 4658906Sgm89044 return (error); 4659906Sgm89044 } 4660906Sgm89044 4661906Sgm89044 /* 4662906Sgm89044 * Random number entry points. 4663906Sgm89044 */ 4664906Sgm89044 4665906Sgm89044 /* ARGSUSED */ 4666906Sgm89044 static int 4667906Sgm89044 dca_generate_random(crypto_provider_handle_t provider, 4668906Sgm89044 crypto_session_id_t session_id, 4669906Sgm89044 uchar_t *buf, size_t len, crypto_req_handle_t req) 4670906Sgm89044 { 4671906Sgm89044 int error = CRYPTO_FAILED; 4672906Sgm89044 dca_t *softc = (dca_t *)provider; 4673906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4674906Sgm89044 int instance; 4675906Sgm89044 4676906Sgm89044 instance = ddi_get_instance(softc->dca_dip); 4677906Sgm89044 DBG(softc, DENTRY, "dca_generate_random: started"); 4678906Sgm89044 4679906Sgm89044 error = dca_rng(softc, buf, len, req); 4680906Sgm89044 4681906Sgm89044 DBG(softc, DENTRY, "dca_generate_random: done, err = 0x%x", error); 4682906Sgm89044 4683906Sgm89044 return (error); 4684906Sgm89044 } 4685906Sgm89044 4686906Sgm89044 /* 4687906Sgm89044 * Context management entry points. 4688906Sgm89044 */ 4689906Sgm89044 4690906Sgm89044 int 4691906Sgm89044 dca_free_context(crypto_ctx_t *ctx) 4692906Sgm89044 { 4693906Sgm89044 int error = CRYPTO_SUCCESS; 4694906Sgm89044 dca_t *softc; 4695906Sgm89044 /* LINTED E_FUNC_SET_NOT_USED */ 4696906Sgm89044 int instance; 4697906Sgm89044 4698906Sgm89044 /* extract softc and instance number from context */ 4699906Sgm89044 DCA_SOFTC_FROM_CTX(ctx, softc, instance); 4700906Sgm89044 DBG(softc, DENTRY, "dca_free_context: entered"); 4701906Sgm89044 4702906Sgm89044 if (ctx->cc_provider_private == NULL) 4703906Sgm89044 return (error); 4704906Sgm89044 4705906Sgm89044 dca_rmlist2(ctx->cc_provider_private, &softc->dca_ctx_list_lock); 4706906Sgm89044 4707906Sgm89044 error = dca_free_context_low(ctx); 4708906Sgm89044 4709906Sgm89044 DBG(softc, DENTRY, "dca_free_context: done, err = 0x%x", error); 4710906Sgm89044 4711906Sgm89044 return (error); 4712906Sgm89044 } 4713906Sgm89044 4714906Sgm89044 static int 4715906Sgm89044 dca_free_context_low(crypto_ctx_t *ctx) 4716906Sgm89044 { 4717906Sgm89044 int error = CRYPTO_SUCCESS; 4718906Sgm89044 4719906Sgm89044 /* check mechanism */ 4720906Sgm89044 switch (DCA_MECH_FROM_CTX(ctx)) { 4721906Sgm89044 case DES_CBC_MECH_INFO_TYPE: 4722906Sgm89044 case DES3_CBC_MECH_INFO_TYPE: 4723906Sgm89044 dca_3desctxfree(ctx); 4724906Sgm89044 break; 4725906Sgm89044 case RSA_PKCS_MECH_INFO_TYPE: 4726906Sgm89044 case RSA_X_509_MECH_INFO_TYPE: 4727906Sgm89044 dca_rsactxfree(ctx); 4728906Sgm89044 break; 4729906Sgm89044 case DSA_MECH_INFO_TYPE: 4730906Sgm89044 dca_dsactxfree(ctx); 4731906Sgm89044 break; 4732906Sgm89044 default: 4733906Sgm89044 /* Should never reach here */ 4734906Sgm89044 cmn_err(CE_WARN, "dca_free_context_low: unexpected mech type " 4735906Sgm89044 "0x%llx\n", (unsigned long long)DCA_MECH_FROM_CTX(ctx)); 4736906Sgm89044 error = CRYPTO_MECHANISM_INVALID; 4737906Sgm89044 } 4738906Sgm89044 4739906Sgm89044 return (error); 4740906Sgm89044 } 4741906Sgm89044 4742906Sgm89044 4743906Sgm89044 /* Free any unfreed private context. It is called in detach. */ 4744906Sgm89044 static void 4745906Sgm89044 dca_free_context_list(dca_t *dca) 4746906Sgm89044 { 4747906Sgm89044 dca_listnode_t *node; 4748906Sgm89044 crypto_ctx_t ctx; 4749906Sgm89044 4750906Sgm89044 (void) memset(&ctx, 0, sizeof (ctx)); 4751906Sgm89044 ctx.cc_provider = dca; 4752906Sgm89044 4753906Sgm89044 while ((node = dca_delist2(&dca->dca_ctx_list, 4754906Sgm89044 &dca->dca_ctx_list_lock)) != NULL) { 4755906Sgm89044 ctx.cc_provider_private = node; 4756906Sgm89044 (void) dca_free_context_low(&ctx); 4757906Sgm89044 } 4758906Sgm89044 } 4759906Sgm89044 4760906Sgm89044 static int 4761906Sgm89044 ext_info_sym(crypto_provider_handle_t prov, 4762906Sgm89044 crypto_provider_ext_info_t *ext_info, crypto_req_handle_t cfreq) 4763906Sgm89044 { 4764906Sgm89044 return (ext_info_base(prov, ext_info, cfreq, IDENT_SYM)); 4765906Sgm89044 } 4766906Sgm89044 4767906Sgm89044 static int 4768906Sgm89044 ext_info_asym(crypto_provider_handle_t prov, 4769906Sgm89044 crypto_provider_ext_info_t *ext_info, crypto_req_handle_t cfreq) 4770906Sgm89044 { 4771906Sgm89044 int rv; 4772906Sgm89044 4773906Sgm89044 rv = ext_info_base(prov, ext_info, cfreq, IDENT_ASYM); 4774906Sgm89044 /* The asymmetric cipher slot supports random */ 4775906Sgm89044 ext_info->ei_flags |= CRYPTO_EXTF_RNG; 4776906Sgm89044 4777906Sgm89044 return (rv); 4778906Sgm89044 } 4779906Sgm89044 4780906Sgm89044 /* ARGSUSED */ 4781906Sgm89044 static int 4782906Sgm89044 ext_info_base(crypto_provider_handle_t prov, 4783906Sgm89044 crypto_provider_ext_info_t *ext_info, crypto_req_handle_t cfreq, char *id) 4784906Sgm89044 { 4785906Sgm89044 dca_t *dca = (dca_t *)prov; 4786906Sgm89044 int len; 4787906Sgm89044 4788906Sgm89044 /* Label */ 4789906Sgm89044 (void) sprintf((char *)ext_info->ei_label, "%s/%d %s", 4790906Sgm89044 ddi_driver_name(dca->dca_dip), ddi_get_instance(dca->dca_dip), id); 4791906Sgm89044 len = strlen((char *)ext_info->ei_label); 4792906Sgm89044 (void) memset(ext_info->ei_label + len, ' ', 4793906Sgm89044 CRYPTO_EXT_SIZE_LABEL - len); 4794906Sgm89044 4795906Sgm89044 /* Manufacturer ID */ 4796906Sgm89044 (void) sprintf((char *)ext_info->ei_manufacturerID, "%s", 4797906Sgm89044 DCA_MANUFACTURER_ID); 4798906Sgm89044 len = strlen((char *)ext_info->ei_manufacturerID); 4799906Sgm89044 (void) memset(ext_info->ei_manufacturerID + len, ' ', 4800906Sgm89044 CRYPTO_EXT_SIZE_MANUF - len); 4801906Sgm89044 4802906Sgm89044 /* Model */ 4803906Sgm89044 (void) sprintf((char *)ext_info->ei_model, dca->dca_model); 4804906Sgm89044 4805906Sgm89044 DBG(dca, DWARN, "kCF MODEL: %s", (char *)ext_info->ei_model); 4806906Sgm89044 4807906Sgm89044 len = strlen((char *)ext_info->ei_model); 4808906Sgm89044 (void) memset(ext_info->ei_model + len, ' ', 4809906Sgm89044 CRYPTO_EXT_SIZE_MODEL - len); 4810906Sgm89044 4811906Sgm89044 /* Serial Number. Blank for Deimos */ 4812906Sgm89044 (void) memset(ext_info->ei_serial_number, ' ', CRYPTO_EXT_SIZE_SERIAL); 4813906Sgm89044 4814906Sgm89044 ext_info->ei_flags = CRYPTO_EXTF_WRITE_PROTECTED; 4815906Sgm89044 4816906Sgm89044 ext_info->ei_max_session_count = CRYPTO_UNAVAILABLE_INFO; 4817906Sgm89044 ext_info->ei_max_pin_len = CRYPTO_UNAVAILABLE_INFO; 4818906Sgm89044 ext_info->ei_min_pin_len = CRYPTO_UNAVAILABLE_INFO; 4819906Sgm89044 ext_info->ei_total_public_memory = CRYPTO_UNAVAILABLE_INFO; 4820906Sgm89044 ext_info->ei_free_public_memory = CRYPTO_UNAVAILABLE_INFO; 4821906Sgm89044 ext_info->ei_total_private_memory = CRYPTO_UNAVAILABLE_INFO; 4822906Sgm89044 ext_info->ei_free_private_memory = CRYPTO_UNAVAILABLE_INFO; 4823906Sgm89044 ext_info->ei_hardware_version.cv_major = 0; 4824906Sgm89044 ext_info->ei_hardware_version.cv_minor = 0; 4825906Sgm89044 ext_info->ei_firmware_version.cv_major = 0; 4826906Sgm89044 ext_info->ei_firmware_version.cv_minor = 0; 4827906Sgm89044 4828906Sgm89044 /* Time. No need to be supplied for token without a clock */ 4829906Sgm89044 ext_info->ei_time[0] = '\000'; 4830906Sgm89044 4831906Sgm89044 return (CRYPTO_SUCCESS); 4832906Sgm89044 } 4833906Sgm89044 4834906Sgm89044 static void 4835906Sgm89044 dca_fma_init(dca_t *dca) 4836906Sgm89044 { 4837906Sgm89044 ddi_iblock_cookie_t fm_ibc; 4838906Sgm89044 int fm_capabilities = DDI_FM_EREPORT_CAPABLE | 4839906Sgm89044 DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE | 4840906Sgm89044 DDI_FM_ERRCB_CAPABLE; 4841906Sgm89044 4842906Sgm89044 /* Read FMA capabilities from dca.conf file (if present) */ 4843906Sgm89044 dca->fm_capabilities = ddi_getprop(DDI_DEV_T_ANY, dca->dca_dip, 4844906Sgm89044 DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "fm-capable", 4845906Sgm89044 fm_capabilities); 4846906Sgm89044 4847906Sgm89044 DBG(dca, DWARN, "dca->fm_capabilities = 0x%x", dca->fm_capabilities); 4848906Sgm89044 4849906Sgm89044 /* Only register with IO Fault Services if we have some capability */ 4850906Sgm89044 if (dca->fm_capabilities) { 4851906Sgm89044 dca_regsattr.devacc_attr_access = DDI_FLAGERR_ACC; 4852906Sgm89044 dca_devattr.devacc_attr_access = DDI_FLAGERR_ACC; 4853906Sgm89044 dca_dmaattr.dma_attr_flags = DDI_DMA_FLAGERR; 4854906Sgm89044 4855906Sgm89044 /* Register capabilities with IO Fault Services */ 4856906Sgm89044 ddi_fm_init(dca->dca_dip, &dca->fm_capabilities, &fm_ibc); 4857906Sgm89044 DBG(dca, DWARN, "fm_capable() = 0x%x", 4858906Sgm89044 ddi_fm_capable(dca->dca_dip)); 4859906Sgm89044 4860906Sgm89044 /* 4861906Sgm89044 * Initialize pci ereport capabilities if ereport capable 4862906Sgm89044 */ 48631865Sdilpreet if (DDI_FM_EREPORT_CAP(dca->fm_capabilities) || 48641865Sdilpreet DDI_FM_ERRCB_CAP(dca->fm_capabilities)) 4865906Sgm89044 pci_ereport_setup(dca->dca_dip); 4866906Sgm89044 4867906Sgm89044 /* 4868906Sgm89044 * Initialize callback mutex and register error callback if 4869906Sgm89044 * error callback capable. 4870906Sgm89044 */ 4871906Sgm89044 if (DDI_FM_ERRCB_CAP(dca->fm_capabilities)) { 4872906Sgm89044 ddi_fm_handler_register(dca->dca_dip, dca_fm_error_cb, 4873906Sgm89044 (void *)dca); 4874906Sgm89044 } 4875906Sgm89044 } else { 4876906Sgm89044 /* 4877906Sgm89044 * These fields have to be cleared of FMA if there are no 4878906Sgm89044 * FMA capabilities at runtime. 4879906Sgm89044 */ 4880906Sgm89044 dca_regsattr.devacc_attr_access = DDI_DEFAULT_ACC; 4881906Sgm89044 dca_devattr.devacc_attr_access = DDI_DEFAULT_ACC; 4882906Sgm89044 dca_dmaattr.dma_attr_flags = 0; 4883906Sgm89044 } 4884906Sgm89044 } 4885906Sgm89044 4886906Sgm89044 4887906Sgm89044 static void 4888906Sgm89044 dca_fma_fini(dca_t *dca) 4889906Sgm89044 { 4890906Sgm89044 /* Only unregister FMA capabilities if we registered some */ 4891906Sgm89044 if (dca->fm_capabilities) { 4892906Sgm89044 4893906Sgm89044 /* 4894906Sgm89044 * Release any resources allocated by pci_ereport_setup() 4895906Sgm89044 */ 48961865Sdilpreet if (DDI_FM_EREPORT_CAP(dca->fm_capabilities) || 48971865Sdilpreet DDI_FM_ERRCB_CAP(dca->fm_capabilities)) { 4898906Sgm89044 pci_ereport_teardown(dca->dca_dip); 4899906Sgm89044 } 4900906Sgm89044 4901906Sgm89044 /* 4902906Sgm89044 * Free callback mutex and un-register error callback if 4903906Sgm89044 * error callback capable. 4904906Sgm89044 */ 4905906Sgm89044 if (DDI_FM_ERRCB_CAP(dca->fm_capabilities)) { 4906906Sgm89044 ddi_fm_handler_unregister(dca->dca_dip); 4907906Sgm89044 } 4908906Sgm89044 4909906Sgm89044 /* Unregister from IO Fault Services */ 4910906Sgm89044 ddi_fm_fini(dca->dca_dip); 4911906Sgm89044 DBG(dca, DWARN, "fm_capable() = 0x%x", 4912906Sgm89044 ddi_fm_capable(dca->dca_dip)); 4913906Sgm89044 } 4914906Sgm89044 } 4915906Sgm89044 4916906Sgm89044 4917906Sgm89044 /* 4918906Sgm89044 * The IO fault service error handling callback function 4919906Sgm89044 */ 49201865Sdilpreet /*ARGSUSED*/ 4921906Sgm89044 static int 4922906Sgm89044 dca_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) 4923906Sgm89044 { 4924906Sgm89044 dca_t *dca = (dca_t *)impl_data; 49251865Sdilpreet 49261865Sdilpreet pci_ereport_post(dip, err, NULL); 49271865Sdilpreet if (err->fme_status == DDI_FM_FATAL) { 4928906Sgm89044 dca_failure(dca, DDI_DATAPATH_FAULT, 4929906Sgm89044 DCA_FM_ECLASS_NONE, dca_ena(0), CRYPTO_DEVICE_ERROR, 4930906Sgm89044 "fault PCI in FMA callback."); 4931906Sgm89044 } 49321865Sdilpreet return (err->fme_status); 4933906Sgm89044 } 4934906Sgm89044 4935906Sgm89044 4936906Sgm89044 static int 4937906Sgm89044 dca_check_acc_handle(dca_t *dca, ddi_acc_handle_t handle, 4938906Sgm89044 dca_fma_eclass_t eclass_index) 4939906Sgm89044 { 4940906Sgm89044 ddi_fm_error_t de; 4941906Sgm89044 int version = 0; 49421865Sdilpreet 49431865Sdilpreet ddi_fm_acc_err_get(handle, &de, version); 49441865Sdilpreet if (de.fme_status != DDI_FM_OK) { 49451865Sdilpreet dca_failure(dca, DDI_DATAPATH_FAULT, 49461865Sdilpreet eclass_index, fm_ena_increment(de.fme_ena), 49471865Sdilpreet CRYPTO_DEVICE_ERROR, ""); 49481865Sdilpreet return (DDI_FAILURE); 4949906Sgm89044 } 4950906Sgm89044 4951906Sgm89044 return (DDI_SUCCESS); 4952906Sgm89044 } 4953906Sgm89044 4954906Sgm89044 int 4955906Sgm89044 dca_check_dma_handle(dca_t *dca, ddi_dma_handle_t handle, 4956906Sgm89044 dca_fma_eclass_t eclass_index) 4957906Sgm89044 { 4958906Sgm89044 ddi_fm_error_t de; 4959906Sgm89044 int version = 0; 49601865Sdilpreet 49611865Sdilpreet ddi_fm_dma_err_get(handle, &de, version); 49621865Sdilpreet if (de.fme_status != DDI_FM_OK) { 49631865Sdilpreet dca_failure(dca, DDI_DATAPATH_FAULT, 49641865Sdilpreet eclass_index, fm_ena_increment(de.fme_ena), 49651865Sdilpreet CRYPTO_DEVICE_ERROR, ""); 49661865Sdilpreet return (DDI_FAILURE); 4967906Sgm89044 } 4968906Sgm89044 return (DDI_SUCCESS); 4969906Sgm89044 } 4970906Sgm89044 4971906Sgm89044 static uint64_t 4972906Sgm89044 dca_ena(uint64_t ena) 4973906Sgm89044 { 4974906Sgm89044 if (ena == 0) 4975906Sgm89044 ena = fm_ena_generate(0, FM_ENA_FMT1); 4976906Sgm89044 else 4977906Sgm89044 ena = fm_ena_increment(ena); 4978906Sgm89044 return (ena); 4979906Sgm89044 } 4980906Sgm89044 4981906Sgm89044 static char * 4982906Sgm89044 dca_fma_eclass_string(char *model, dca_fma_eclass_t index) 4983906Sgm89044 { 4984906Sgm89044 if (strstr(model, "500")) 4985906Sgm89044 return (dca_fma_eclass_sca500[index]); 4986906Sgm89044 else 4987906Sgm89044 return (dca_fma_eclass_sca1000[index]); 4988906Sgm89044 } 4989