xref: /onnv-gate/usr/src/uts/common/crypto/io/dca.c (revision 11413:21d4b1442799)
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