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