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