xref: /illumos-gate/usr/src/uts/common/io/ib/mgt/ibmf/ibmf_impl.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * This file implements the client interfaces of the IBMF.
31  */
32 
33 #include <sys/ib/mgt/ibmf/ibmf_impl.h>
34 #include <sys/ib/mgt/ib_mad.h>
35 
36 extern ibmf_state_t *ibmf_statep;
37 
38 /* global settable */
39 int	ibmf_send_wqes_per_port = IBMF_MAX_SQ_WRE;
40 int	ibmf_recv_wqes_per_port = IBMF_MAX_RQ_WRE;
41 int	ibmf_send_wqes_posted_per_qp = IBMF_MAX_POSTED_SQ_PER_QP;
42 int	ibmf_recv_wqes_posted_per_qp = IBMF_MAX_POSTED_RQ_PER_QP;
43 
44 int	ibmf_taskq_max_tasks = 1024;
45 
46 int	ibmf_trace_level = DPRINT_L0;
47 
48 #define	IBMF_MAD_CL_HDR_OFF_1	0
49 #define	IBMF_MAD_CL_HDR_OFF_2	12
50 #define	IBMF_MAD_CL_HDR_SZ_1	40
51 #define	IBMF_MAD_CL_HDR_SZ_2	20
52 #define	IBMF_MAD_CL_HDR_SZ_3	0
53 #define	IBMF_MAD_CL_HDR_SZ_4	4
54 
55 #define	IBMF_VALID_CLIENT_TYPE(client_type)		\
56 	((client_type) == SUBN_AGENT ||			\
57 	(client_type) == SUBN_MANAGER ||		\
58 	(client_type) == SUBN_ADM_AGENT ||		\
59 	(client_type) == SUBN_ADM_MANAGER ||		\
60 	(client_type) == PERF_AGENT ||			\
61 	(client_type) == PERF_MANAGER ||		\
62 	(client_type) == BM_AGENT ||			\
63 	(client_type) == BM_MANAGER ||			\
64 	(client_type) == DEV_MGT_AGENT ||		\
65 	(client_type) == DEV_MGT_MANAGER ||		\
66 	(client_type) == COMM_MGT_MANAGER_AGENT ||	\
67 	(client_type) == SNMP_MANAGER_AGENT ||		\
68 	(client_type) == VENDOR_09_MANAGER_AGENT ||	\
69 	(client_type) == VENDOR_0A_MANAGER_AGENT ||	\
70 	(client_type) == VENDOR_0B_MANAGER_AGENT ||	\
71 	(client_type) == VENDOR_0C_MANAGER_AGENT ||	\
72 	(client_type) == VENDOR_0D_MANAGER_AGENT ||	\
73 	(client_type) == VENDOR_0E_MANAGER_AGENT ||	\
74 	(client_type) == VENDOR_0F_MANAGER_AGENT ||	\
75 	(client_type) == VENDOR_30_MANAGER_AGENT ||	\
76 	(client_type) == VENDOR_31_MANAGER_AGENT ||	\
77 	(client_type) == VENDOR_32_MANAGER_AGENT ||	\
78 	(client_type) == VENDOR_33_MANAGER_AGENT ||	\
79 	(client_type) == VENDOR_34_MANAGER_AGENT ||	\
80 	(client_type) == VENDOR_35_MANAGER_AGENT ||	\
81 	(client_type) == VENDOR_36_MANAGER_AGENT ||	\
82 	(client_type) == VENDOR_37_MANAGER_AGENT ||	\
83 	(client_type) == VENDOR_38_MANAGER_AGENT ||	\
84 	(client_type) == VENDOR_39_MANAGER_AGENT ||	\
85 	(client_type) == VENDOR_3A_MANAGER_AGENT ||	\
86 	(client_type) == VENDOR_3B_MANAGER_AGENT ||	\
87 	(client_type) == VENDOR_3C_MANAGER_AGENT ||	\
88 	(client_type) == VENDOR_3D_MANAGER_AGENT ||	\
89 	(client_type) == VENDOR_3E_MANAGER_AGENT ||	\
90 	(client_type) == VENDOR_3F_MANAGER_AGENT ||	\
91 	(client_type) == VENDOR_40_MANAGER_AGENT ||	\
92 	(client_type) == VENDOR_41_MANAGER_AGENT ||	\
93 	(client_type) == VENDOR_42_MANAGER_AGENT ||	\
94 	(client_type) == VENDOR_43_MANAGER_AGENT ||	\
95 	(client_type) == VENDOR_44_MANAGER_AGENT ||	\
96 	(client_type) == VENDOR_45_MANAGER_AGENT ||	\
97 	(client_type) == VENDOR_46_MANAGER_AGENT ||	\
98 	(client_type) == VENDOR_47_MANAGER_AGENT ||	\
99 	(client_type) == VENDOR_48_MANAGER_AGENT ||	\
100 	(client_type) == VENDOR_49_MANAGER_AGENT ||	\
101 	(client_type) == VENDOR_4A_MANAGER_AGENT ||	\
102 	(client_type) == VENDOR_4B_MANAGER_AGENT ||	\
103 	(client_type) == VENDOR_4C_MANAGER_AGENT ||	\
104 	(client_type) == VENDOR_4D_MANAGER_AGENT ||	\
105 	(client_type) == VENDOR_4E_MANAGER_AGENT ||	\
106 	(client_type) == VENDOR_4F_MANAGER_AGENT ||	\
107 	(client_type) == APPLICATION_10_MANAGER_AGENT || \
108 	(client_type) == APPLICATION_11_MANAGER_AGENT || \
109 	(client_type) == APPLICATION_12_MANAGER_AGENT || \
110 	(client_type) == APPLICATION_13_MANAGER_AGENT || \
111 	(client_type) == APPLICATION_14_MANAGER_AGENT || \
112 	(client_type) == APPLICATION_15_MANAGER_AGENT || \
113 	(client_type) == APPLICATION_16_MANAGER_AGENT || \
114 	(client_type) == APPLICATION_17_MANAGER_AGENT || \
115 	(client_type) == APPLICATION_18_MANAGER_AGENT || \
116 	(client_type) == APPLICATION_19_MANAGER_AGENT || \
117 	(client_type) == APPLICATION_1A_MANAGER_AGENT || \
118 	(client_type) == APPLICATION_1B_MANAGER_AGENT || \
119 	(client_type) == APPLICATION_1C_MANAGER_AGENT || \
120 	(client_type) == APPLICATION_1D_MANAGER_AGENT || \
121 	(client_type) == APPLICATION_1E_MANAGER_AGENT || \
122 	(client_type) == APPLICATION_1F_MANAGER_AGENT || \
123 	(client_type) == APPLICATION_20_MANAGER_AGENT || \
124 	(client_type) == APPLICATION_21_MANAGER_AGENT || \
125 	(client_type) == APPLICATION_22_MANAGER_AGENT || \
126 	(client_type) == APPLICATION_23_MANAGER_AGENT || \
127 	(client_type) == APPLICATION_24_MANAGER_AGENT || \
128 	(client_type) == APPLICATION_25_MANAGER_AGENT || \
129 	(client_type) == APPLICATION_26_MANAGER_AGENT || \
130 	(client_type) == APPLICATION_27_MANAGER_AGENT || \
131 	(client_type) == APPLICATION_28_MANAGER_AGENT || \
132 	(client_type) == APPLICATION_29_MANAGER_AGENT || \
133 	(client_type) == APPLICATION_2A_MANAGER_AGENT || \
134 	(client_type) == APPLICATION_2B_MANAGER_AGENT || \
135 	(client_type) == APPLICATION_2C_MANAGER_AGENT || \
136 	(client_type) == APPLICATION_2D_MANAGER_AGENT || \
137 	(client_type) == APPLICATION_2E_MANAGER_AGENT || \
138 	(client_type) == APPLICATION_2F_MANAGER_AGENT || \
139 	(client_type) == UNIVERSAL_CLASS)
140 
141 static ibmf_ci_t *ibmf_i_lookup_ci(ib_guid_t ci_guid);
142 static int ibmf_i_init_ci(ibmf_register_info_t *client_infop,
143     ibmf_ci_t *cip);
144 static void ibmf_i_uninit_ci(ibmf_ci_t *cip);
145 static void ibmf_i_init_ci_done(ibmf_ci_t *cip);
146 static void ibmf_i_uninit_ci_done(ibmf_ci_t *cip);
147 static int ibmf_i_init_qp(ibmf_ci_t *ibmf_cip, ibmf_qp_t *qpp);
148 static void ibmf_i_uninit_qp(ibmf_ci_t *ibmf_cip, ibmf_qp_t *qpp);
149 static int ibmf_i_init_cqs(ibmf_ci_t *cip);
150 static void ibmf_i_fini_cqs(ibmf_ci_t *cip);
151 static void ibmf_i_init_qplist(ibmf_ci_t *ibmf_cip);
152 static void ibmf_i_fini_qplist(ibmf_ci_t *ibmf_cip);
153 static int ibmf_i_lookup_client_by_info(ibmf_ci_t *ibmf_cip,
154     ibmf_register_info_t *ir_client, ibmf_client_t **clientpp);
155 
156 /*
157  * ibmf_init():
158  *	Initializes module state and registers with the IBT framework.
159  * 	Returns 0 if initialization was successful, else returns non-zero.
160  */
161 int
162 ibmf_init(void)
163 {
164 	ibt_status_t 	status;
165 	ibt_clnt_hdl_t 	ibmf_ibt_handle;
166 
167 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_init_start,
168 	    IBMF_TNF_TRACE, "", "ibmf_init() enter\n");
169 
170 	/* setup the IBT module information */
171 	ibmf_statep->ibmf_ibt_modinfo.mi_ibt_version = IBTI_V1;
172 	ibmf_statep->ibmf_ibt_modinfo.mi_clnt_class = IBT_IBMA;
173 	ibmf_statep->ibmf_ibt_modinfo.mi_async_handler
174 	    = ibmf_ibt_async_handler;
175 	ibmf_statep->ibmf_ibt_modinfo.mi_reserved = NULL;
176 	ibmf_statep->ibmf_ibt_modinfo.mi_clnt_name = "ibmf";
177 
178 	/* setup a connection to IB transport layer (IBTF) */
179 	status = ibt_attach(&ibmf_statep->ibmf_ibt_modinfo, (void *)NULL,
180 	    (void *)NULL, (void *)&ibmf_ibt_handle);
181 	if (status != IBT_SUCCESS) {
182 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_init_err,
183 		    IBMF_TNF_ERROR, "", "%s, status = %d\n", tnf_string, msg,
184 		    "ibt attach failed", tnf_uint, status, status);
185 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_init_end,
186 		    IBMF_TNF_TRACE, "", "ibmf_init() exit\n");
187 		return (1);
188 	}
189 
190 	/* initialize the IBMF state context */
191 	ibmf_statep->ibmf_ibt_handle = ibmf_ibt_handle;
192 	ibmf_statep->ibmf_ci_list = (ibmf_ci_t *)NULL;
193 	ibmf_statep->ibmf_ci_list_tail = (ibmf_ci_t *)NULL;
194 	mutex_init(&ibmf_statep->ibmf_mutex, NULL, MUTEX_DRIVER, NULL);
195 	ibmf_statep->ibmf_cq_handler = ibmf_i_mad_completions;
196 
197 	ibmf_statep->ibmf_taskq = taskq_create("ibmf_taskq", IBMF_TASKQ_1THREAD,
198 	    MINCLSYSPRI, 1, ibmf_taskq_max_tasks, TASKQ_PREPOPULATE);
199 
200 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_init_end,
201 	    IBMF_TNF_TRACE, "", "ibmf_init() exit\n");
202 
203 	return (0);
204 }
205 
206 /*
207  * ibmf_fini():
208  *	Cleans up module state resources and unregisters from IBT framework.
209  */
210 int
211 ibmf_fini(void)
212 {
213 	ibmf_ci_t	*cip;
214 	ibmf_ci_t	*tcip;
215 	ibt_status_t	status;
216 
217 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_fini_start,
218 	    IBMF_TNF_TRACE, "", "ibmf_fini() enter\n");
219 
220 	ASSERT(MUTEX_NOT_HELD(&ibmf_statep->ibmf_mutex));
221 
222 	mutex_enter(&ibmf_statep->ibmf_mutex);
223 
224 	/* free all the Channel Interface (CI) context structures */
225 	cip = ibmf_statep->ibmf_ci_list;
226 	tcip = NULL;
227 	while (cip != (ibmf_ci_t *)NULL) {
228 
229 		mutex_enter(&cip->ci_mutex);
230 		ASSERT((cip->ci_state == IBMF_CI_STATE_PRESENT && cip->ci_ref ==
231 		    0) || (cip->ci_state == IBMF_CI_STATE_GONE));
232 		ASSERT(cip->ci_init_state == IBMF_CI_INIT_HCA_LINKED);
233 		ASSERT(cip->ci_qp_list == NULL && cip->ci_qp_list_tail == NULL);
234 		if (tcip != (ibmf_ci_t *)NULL)
235 			tcip->ci_next = cip->ci_next;
236 		if (ibmf_statep->ibmf_ci_list_tail == cip)
237 			ibmf_statep->ibmf_ci_list_tail = NULL;
238 		if (ibmf_statep->ibmf_ci_list == cip)
239 			ibmf_statep->ibmf_ci_list = cip->ci_next;
240 		tcip = cip->ci_next;
241 		mutex_exit(&cip->ci_mutex);
242 		/* free up the ci structure */
243 		if (cip->ci_port_kstatp != NULL) {
244 			kstat_delete(cip->ci_port_kstatp);
245 		}
246 		mutex_destroy(&cip->ci_mutex);
247 		mutex_destroy(&cip->ci_clients_mutex);
248 		mutex_destroy(&cip->ci_wqe_mutex);
249 		cv_destroy(&cip->ci_state_cv);
250 		cv_destroy(&cip->ci_wqes_cv);
251 		kmem_free((void *) cip, sizeof (ibmf_ci_t));
252 		cip = tcip;
253 	}
254 
255 	ASSERT(ibmf_statep->ibmf_ci_list == NULL);
256 	ASSERT(ibmf_statep->ibmf_ci_list_tail == NULL);
257 
258 	taskq_destroy(ibmf_statep->ibmf_taskq);
259 
260 	mutex_exit(&ibmf_statep->ibmf_mutex);
261 
262 	/* detach from IBTF */
263 	status = ibt_detach(ibmf_statep->ibmf_ibt_handle);
264 	if (status != IBT_SUCCESS) {
265 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_fini_err,
266 		    IBMF_TNF_ERROR, "", "%s, status = %d\n", tnf_string, msg,
267 		    "ibt detach error", tnf_uint, status, status);
268 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_fini_end,
269 		    IBMF_TNF_TRACE, "", "ibmf_fini() exit\n");
270 		return (1);
271 	}
272 
273 	mutex_destroy(&ibmf_statep->ibmf_mutex);
274 
275 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_fini_end,
276 	    IBMF_TNF_TRACE, "", "ibmf_fini() exit\n");
277 
278 	return (0);
279 }
280 
281 /*
282  * ibmf_i_validate_class_mask():
283  *	Checks client type value in client information structure.
284  */
285 int
286 ibmf_i_validate_class_mask(ibmf_register_info_t	*client_infop)
287 {
288 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
289 	    ibmf_i_validate_class_mask_start, IBMF_TNF_TRACE, "",
290 	    "ibmf_i_validate_class_mask() enter, client_infop = %p\n",
291 	    tnf_opaque, client_infop, client_infop);
292 
293 	if (IBMF_VALID_CLIENT_TYPE(client_infop->ir_client_class) == B_FALSE) {
294 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
295 		    ibmf_i_validate_class_mask_err, IBMF_TNF_ERROR, "",
296 		    "%s, class = %x\n", tnf_string, msg,
297 		    "invalid class", tnf_uint, class,
298 		    client_infop->ir_client_class);
299 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
300 		    ibmf_i_validate_class_mask_end, IBMF_TNF_TRACE, "",
301 		    "ibmf_i_validate_class_mask() exit\n");
302 		return (IBMF_BAD_CLASS);
303 	}
304 
305 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_validate_class_mask_end,
306 	    IBMF_TNF_TRACE, "", "ibmf_i_validate_class_mask() exit\n");
307 	return (IBMF_SUCCESS);
308 }
309 
310 /*
311  * ibmf_i_validate_ci_guid_and_port():
312  *	Checks validity of port number and HCA GUID at client
313  *	registration time.
314  */
315 int
316 ibmf_i_validate_ci_guid_and_port(ib_guid_t hca_guid, uint8_t port_num)
317 {
318 	ibt_status_t	status;
319 	ibt_hca_attr_t	hca_attrs;
320 
321 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
322 	    ibmf_i_validate_ci_guid_and_port_start, IBMF_TNF_TRACE, "",
323 	    "ibmf_i_validate_ci_guid_and_port() enter, hca_guid = %x, "
324 	    "port_num = %d\n", tnf_opaque, hca_guid, hca_guid,
325 	    tnf_uint, port_num, port_num);
326 
327 	/* check for incorrect port number specification */
328 	if (port_num == 0) {
329 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, 1,
330 		    ibmf_i_validate_ci_guid_and_port_err, IBMF_TNF_ERROR, "",
331 		    "%s\n", tnf_string, msg, "port num is 0");
332 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
333 		    ibmf_i_validate_ci_guid_and_port_end, IBMF_TNF_TRACE, "",
334 		    "ibmf_i_validate_ci_guid_and_port() exit\n");
335 		return (IBMF_BAD_PORT);
336 	}
337 
338 	/* call IB transport layer for HCA attributes */
339 	status = ibt_query_hca_byguid(hca_guid, &hca_attrs);
340 	if (status != IBT_SUCCESS) {
341 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
342 		    ibmf_i_validate_ci_guid_and_port_err,
343 		    IBMF_TNF_ERROR, "", "%s, status = %d\n", tnf_string, msg,
344 		    "query_hca_guid failed", tnf_uint, status, status);
345 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
346 		    ibmf_i_validate_ci_guid_and_port_end, IBMF_TNF_TRACE, "",
347 		    "ibmf_i_validate_ci_guid_and_port() exit\n");
348 		return (IBMF_BAD_NODE);
349 	}
350 
351 	/* check if the specified port number is within the HCAs range */
352 	if (port_num > hca_attrs.hca_nports) {
353 		IBMF_TRACE_3(IBMF_TNF_NODEBUG, 1,
354 		    ibmf_i_validate_ci_guid_and_port_err, IBMF_TNF_ERROR, "",
355 		    "%s, num = %d, hca_ports = %d\n",
356 		    tnf_string, msg, "port num > valid ports",
357 		    tnf_uint, num, port_num, tnf_uint, hca_nports,
358 		    hca_attrs.hca_nports);
359 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
360 		    ibmf_i_validate_ci_guid_and_port_end, IBMF_TNF_TRACE, "",
361 		    "ibmf_i_validate_ci_guid_and_port() exit\n");
362 		return (IBMF_BAD_PORT);
363 	}
364 
365 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
366 	    ibmf_i_validate_ci_guid_and_port_end, IBMF_TNF_TRACE, "",
367 	    "ibmf_i_validate_ci_guid_and_port() exit\n");
368 	return (IBMF_SUCCESS);
369 }
370 
371 /*
372  * ibmf_i_lookup_ci():
373  * 	Lookup the ci and return if found. If the CI is not found, returns
374  * 	NULL.
375  */
376 static ibmf_ci_t *
377 ibmf_i_lookup_ci(ib_guid_t ci_guid)
378 {
379 	ibmf_ci_t	*cip = NULL;
380 
381 	ASSERT(MUTEX_NOT_HELD(&ibmf_statep->ibmf_mutex));
382 
383 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_lookup_ci_start,
384 	    IBMF_TNF_TRACE, "", "ibmf_i_lookup_ci(): enter, guid = 0x%x\n",
385 	    tnf_uint64, guid, ci_guid);
386 
387 	/* walk the CI list looking for one that matches the provided GUID */
388 	mutex_enter(&ibmf_statep->ibmf_mutex);
389 	cip = ibmf_statep->ibmf_ci_list;
390 	while (cip != (ibmf_ci_t *)NULL) {
391 		if (ci_guid == cip->ci_node_guid) {
392 			/* found it in our list */
393 			break;
394 		}
395 		cip = cip->ci_next;
396 	}
397 	mutex_exit(&ibmf_statep->ibmf_mutex);
398 
399 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_lookup_ci_end,
400 	    IBMF_TNF_TRACE, "", "ibmf_i_lookup_ci() exit\n");
401 
402 	return (cip);
403 }
404 
405 /*
406  * ibmf_i_get_ci():
407  *	Get the CI structure based on the HCA GUID from a list if it exists.
408  *	If the CI structure does not exist, and the HCA GUID is valid,
409  *	create a new CI structure and add it to the list.
410  */
411 int
412 ibmf_i_get_ci(ibmf_register_info_t *client_infop, ibmf_ci_t **cipp)
413 {
414 	ibmf_ci_t 		*cip;
415 	ibt_status_t		status;
416 	boolean_t		invalid = B_FALSE;
417 	ibt_hca_attr_t		hca_attrs;
418 	ibmf_port_kstat_t	*ksp;
419 
420 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_get_ci_start,
421 	    IBMF_TNF_TRACE, "", "ibmf_i_get_ci() enter, clinfop = %p\n",
422 	    tnf_opaque, client_infop, client_infop);
423 
424 	/* look for a CI context with a matching GUID */
425 	cip = ibmf_i_lookup_ci(client_infop->ir_ci_guid);
426 
427 	if (cip == NULL) {
428 
429 		/*
430 		 * attempt to create the ci. First, verify the ci exists.
431 		 * If it exists, allocate ci memory and insert in the ci list.
432 		 * It is possible that some other thread raced with us
433 		 * and inserted created ci while we are blocked in
434 		 * allocating memory. Check for that case and if that is indeed
435 		 * the case, free up what we allocated and try to get a
436 		 * reference count on the ci that the other thread added.
437 		 */
438 		status = ibt_query_hca_byguid(client_infop->ir_ci_guid,
439 		    &hca_attrs);
440 		if (status == IBT_SUCCESS) {
441 
442 			ibmf_ci_t *tcip;
443 			char buf[128];
444 
445 			/* allocate memory for the CI structure */
446 			cip = (ibmf_ci_t *)kmem_zalloc(sizeof (ibmf_ci_t),
447 			    KM_SLEEP);
448 
449 			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cip))
450 
451 			mutex_init(&cip->ci_mutex, NULL, MUTEX_DRIVER, NULL);
452 			mutex_init(&cip->ci_clients_mutex, NULL, MUTEX_DRIVER,
453 			    NULL);
454 			mutex_init(&cip->ci_wqe_mutex, NULL, MUTEX_DRIVER,
455 			    NULL);
456 			cv_init(&cip->ci_state_cv, NULL, CV_DRIVER, NULL);
457 			cv_init(&cip->ci_wqes_cv, NULL, CV_DRIVER, NULL);
458 
459 			(void) sprintf(buf, "r%08X",
460 			    (uint32_t)client_infop->ir_ci_guid);
461 			mutex_enter(&cip->ci_mutex);
462 
463 			cip->ci_state = IBMF_CI_STATE_PRESENT;
464 			cip->ci_node_guid = client_infop->ir_ci_guid;
465 
466 			/* set up per CI kstats */
467 			(void) sprintf(buf, "ibmf_%016" PRIx64 "_%d_stat",
468 			    client_infop->ir_ci_guid,
469 			    client_infop->ir_port_num);
470 			if ((cip->ci_port_kstatp = kstat_create("ibmf", 0, buf,
471 			    "misc", KSTAT_TYPE_NAMED,
472 			    sizeof (ibmf_port_kstat_t) / sizeof (kstat_named_t),
473 			    KSTAT_FLAG_WRITABLE)) == NULL) {
474 				mutex_exit(&cip->ci_mutex);
475 				mutex_destroy(&cip->ci_mutex);
476 				mutex_destroy(&cip->ci_clients_mutex);
477 				mutex_destroy(&cip->ci_wqe_mutex);
478 				cv_destroy(&cip->ci_state_cv);
479 				cv_destroy(&cip->ci_wqes_cv);
480 				kmem_free((void *)cip, sizeof (ibmf_ci_t));
481 				IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
482 				    ibmf_i_get_ci_err, IBMF_TNF_ERROR, "",
483 				    "%s\n", tnf_string, msg,
484 				    "kstat create failed");
485 				IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
486 				    ibmf_i_get_ci_end, IBMF_TNF_TRACE, "",
487 				    "ibmf_i_get_ci() exit\n");
488 				return (IBMF_NO_RESOURCES);
489 			}
490 			ksp = (ibmf_port_kstat_t *)cip->ci_port_kstatp->ks_data;
491 			kstat_named_init(&ksp->clients_registered,
492 			    "clients_registered", KSTAT_DATA_UINT32);
493 			kstat_named_init(&ksp->client_regs_failed,
494 			    "client_registrations_failed", KSTAT_DATA_UINT32);
495 			kstat_named_init(&ksp->send_wqes_alloced,
496 			    "send_wqes_allocated", KSTAT_DATA_UINT32);
497 			kstat_named_init(&ksp->recv_wqes_alloced,
498 			    "receive_wqes_allocated", KSTAT_DATA_UINT32);
499 			kstat_named_init(&ksp->swqe_allocs_failed,
500 			    "send_wqe_allocs_failed", KSTAT_DATA_UINT32);
501 			kstat_named_init(&ksp->rwqe_allocs_failed,
502 			    "recv_wqe_allocs_failed", KSTAT_DATA_UINT32);
503 			kstat_install(cip->ci_port_kstatp);
504 
505 			mutex_exit(&cip->ci_mutex);
506 
507 			mutex_enter(&ibmf_statep->ibmf_mutex);
508 
509 			tcip = ibmf_statep->ibmf_ci_list;
510 			while (tcip != (ibmf_ci_t *)NULL) {
511 				if (client_infop->ir_ci_guid ==
512 				    tcip->ci_node_guid) {
513 					/* found it in our list */
514 					break;
515 				}
516 				tcip = tcip->ci_next;
517 			}
518 
519 			/* if the ci isn't on the list, add it */
520 			if (tcip == NULL) {
521 				cip->ci_next = NULL;
522 
523 				_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*cip))
524 
525 				if (ibmf_statep->ibmf_ci_list_tail != NULL)
526 					ibmf_statep->ibmf_ci_list_tail->
527 					    ci_next = cip;
528 				if (ibmf_statep->ibmf_ci_list == NULL)
529 					ibmf_statep->ibmf_ci_list = cip;
530 				ibmf_statep->ibmf_ci_list_tail = cip;
531 
532 				mutex_enter(&cip->ci_mutex);
533 				cip->ci_init_state |= IBMF_CI_INIT_HCA_LINKED;
534 				mutex_exit(&cip->ci_mutex);
535 
536 			} else {
537 				/* free cip and set it to the one on the list */
538 				kstat_delete(cip->ci_port_kstatp);
539 				mutex_destroy(&cip->ci_mutex);
540 				mutex_destroy(&cip->ci_clients_mutex);
541 				mutex_destroy(&cip->ci_wqe_mutex);
542 				cv_destroy(&cip->ci_state_cv);
543 				cv_destroy(&cip->ci_wqes_cv);
544 				kmem_free((void *)cip, sizeof (ibmf_ci_t));
545 
546 				_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*cip))
547 
548 				cip = tcip;
549 			}
550 			mutex_exit(&ibmf_statep->ibmf_mutex);
551 		} else {
552 			/* we didn't find it and the CI doesn't exist */
553 			IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L1,
554 			    ibmf_i_get_ci_err, IBMF_TNF_ERROR, "", "%s\n",
555 			    tnf_string, msg, "GUID doesn't exist");
556 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
557 			    ibmf_i_get_ci_end, IBMF_TNF_TRACE, "",
558 			    "ibmf_i_get_ci() exit\n");
559 			return (IBMF_TRANSPORT_FAILURE);
560 		}
561 	}
562 
563 	ASSERT(cip != NULL);
564 
565 	/*
566 	 * We now have a CI context structure, either found it on the list,
567 	 * or created it.
568 	 * We now proceed to intialize the CI context.
569 	 */
570 	for (;;) {
571 		mutex_enter(&cip->ci_mutex);
572 
573 		/* CI is INITED & no state change in progress; we are all set */
574 		if (cip->ci_state == IBMF_CI_STATE_INITED && (cip->
575 		    ci_state_flags & (IBMF_CI_STATE_INVALIDATING |
576 		    IBMF_CI_STATE_UNINITING)) == 0) {
577 
578 			cip->ci_ref++;
579 			mutex_exit(&cip->ci_mutex);
580 
581 			break;
582 		}
583 
584 		/* CI is PRESENT; transition it to INITED */
585 		if (cip->ci_state == IBMF_CI_STATE_PRESENT && (cip->
586 		    ci_state_flags & (IBMF_CI_STATE_INVALIDATING |
587 		    IBMF_CI_STATE_INITING)) == 0) {
588 
589 			/* mark state as initing and init the ci */
590 			cip->ci_state_flags |= IBMF_CI_STATE_INITING;
591 			mutex_exit(&cip->ci_mutex);
592 
593 			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cip))
594 
595 			if (ibmf_i_init_ci(client_infop, cip) != IBMF_SUCCESS) {
596 				invalid = B_TRUE;
597 				break;
598 			}
599 
600 			_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*cip))
601 
602 			continue;
603 		}
604 
605 		/*
606 		 * If CI is GONE and no validation is in progress, we should
607 		 * return failure. Also, if CI is INITED but in the process of
608 		 * being made GONE (ie., a hot remove in progress), return
609 		 * failure.
610 		 */
611 		if ((cip->ci_state == IBMF_CI_STATE_GONE && (cip->
612 		    ci_state_flags & IBMF_CI_STATE_VALIDATING) == 0) ||
613 		    (cip->ci_state == IBMF_CI_STATE_INITED && (cip->
614 		    ci_state_flags & IBMF_CI_STATE_INVALIDATING) != 0)) {
615 
616 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
617 			    ibmf_i_get_ci_err, IBMF_TNF_ERROR, "",
618 			    "ci_state = %x, ci_state_flags = %x\n",
619 			    tnf_opaque, cip->ci_state, cip->ci_state,
620 			    tnf_opaque, cip->ci_state_flags,
621 			    cip->ci_state_flags);
622 
623 			invalid = B_TRUE;
624 			mutex_exit(&cip->ci_mutex);
625 
626 			break;
627 		}
628 
629 		/* a state change in progress; block waiting for state change */
630 		if (cip->ci_state_flags & IBMF_CI_STATE_VALIDATING)
631 			cip->ci_state_flags |= IBMF_CI_STATE_VALIDATE_WAIT;
632 		else if (cip->ci_state_flags & IBMF_CI_STATE_INITING)
633 			cip->ci_state_flags |= IBMF_CI_STATE_INIT_WAIT;
634 		else if (cip->ci_state_flags & IBMF_CI_STATE_UNINITING)
635 			cip->ci_state_flags |= IBMF_CI_STATE_UNINIT_WAIT;
636 
637 		cv_wait(&cip->ci_state_cv, &cip->ci_mutex);
638 
639 		mutex_exit(&cip->ci_mutex);
640 	}
641 
642 	if (invalid == B_TRUE) {
643 		IBMF_TRACE_0(IBMF_TNF_NODEBUG, DPRINT_L2, ibmf_i_get_ci_err,
644 		    IBMF_TNF_ERROR, "", "ibmf_i_get_ci() error\n");
645 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_get_ci_end,
646 		    IBMF_TNF_TRACE, "", "ibmf_i_get_ci() exit\n");
647 		return (IBMF_FAILURE);
648 	}
649 
650 	if (cip != NULL) {
651 		*cipp = cip;
652 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_get_ci_end,
653 		    IBMF_TNF_TRACE, "", "ibmf_i_get_ci() exit\n");
654 		return (IBMF_SUCCESS);
655 	} else {
656 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_get_ci_end,
657 		    IBMF_TNF_TRACE, "", "ibmf_i_get_ci() exit\n");
658 		return (IBMF_FAILURE);
659 	}
660 }
661 
662 /*
663  * ibmf_i_release_ci():
664  *	Drop the reference count for the CI.
665  */
666 void
667 ibmf_i_release_ci(ibmf_ci_t *cip)
668 {
669 	uint_t ref;
670 
671 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_release_ci_start,
672 	    IBMF_TNF_TRACE, "", "ibmf_i_release_ci() enter, cip = %p\n",
673 	    tnf_opaque, cip, cip);
674 
675 	ASSERT(MUTEX_NOT_HELD(&cip->ci_mutex));
676 
677 	mutex_enter(&cip->ci_mutex);
678 	ref = cip->ci_ref--;
679 	if (ref == 1) {
680 		ASSERT(cip->ci_state == IBMF_CI_STATE_INITED);
681 		cip->ci_state_flags |= IBMF_CI_STATE_UNINITING;
682 	}
683 	mutex_exit(&cip->ci_mutex);
684 
685 	if (ref == 1) {
686 		ibmf_i_uninit_ci(cip);
687 	}
688 
689 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_release_ci_end,
690 	    IBMF_TNF_TRACE, "", "ibmf_i_release_ci() exit\n");
691 }
692 
693 /*
694  * ibmf_i_init_ci():
695  *	Initialize the CI structure by setting up the HCA, allocating
696  *	protection domains, completion queues, a pool of WQEs.
697  */
698 /* ARGSUSED */
699 static int
700 ibmf_i_init_ci(ibmf_register_info_t *client_infop, ibmf_ci_t *cip)
701 {
702 	ibt_pd_hdl_t		pd;
703 	ibt_status_t		status;
704 	ib_guid_t		ci_guid;
705 	ibt_hca_attr_t		hca_attrs;
706 	ibt_hca_hdl_t		hca_handle;
707 	ibt_pd_flags_t		pd_flags = IBT_PD_NO_FLAGS;
708 	boolean_t		error = B_FALSE;
709 	int			ibmfstatus = IBMF_SUCCESS;
710 	char			errmsg[128];
711 
712 	_NOTE(ASSUMING_PROTECTED(*cip))
713 
714 	ASSERT(MUTEX_NOT_HELD(&ibmf_statep->ibmf_mutex));
715 	ASSERT(MUTEX_NOT_HELD(&cip->ci_mutex));
716 
717 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_ci_start,
718 	    IBMF_TNF_TRACE, "", "ibmf_i_init_ci() enter, cip = %p\n",
719 	    tnf_opaque, ibmf_ci, cip);
720 
721 	mutex_enter(&cip->ci_mutex);
722 	ci_guid = cip->ci_node_guid;
723 	ASSERT(cip->ci_state == IBMF_CI_STATE_PRESENT);
724 	ASSERT((cip->ci_state_flags & IBMF_CI_STATE_INITING) != 0);
725 	mutex_exit(&cip->ci_mutex);
726 
727 	/* set up a connection to the HCA specified by the GUID */
728 	status = ibt_open_hca(ibmf_statep->ibmf_ibt_handle, ci_guid,
729 	    &hca_handle);
730 	ASSERT(status != IBT_HCA_IN_USE);
731 	if (status != IBT_SUCCESS) {
732 		ibmf_i_init_ci_done(cip);
733 		(void) sprintf(errmsg, "ibt open hca failed, status = 0x%x",
734 		    status);
735 		error = B_TRUE;
736 		ibmfstatus = IBMF_TRANSPORT_FAILURE;
737 		goto bail;
738 	}
739 
740 	/* get the HCA attributes */
741 	status = ibt_query_hca(hca_handle, &hca_attrs);
742 	if (status != IBT_SUCCESS) {
743 		(void) ibt_close_hca(hca_handle);
744 		ibmf_i_init_ci_done(cip);
745 		(void) sprintf(errmsg, "ibt query hca failed, status = 0x%x",
746 		    status);
747 		error = B_TRUE;
748 		ibmfstatus = IBMF_TRANSPORT_FAILURE;
749 		goto bail;
750 	}
751 
752 	/* allocate a Protection Domain */
753 	status = ibt_alloc_pd(hca_handle, pd_flags, &pd);
754 	if (status != IBT_SUCCESS) {
755 		(void) ibt_close_hca(hca_handle);
756 		ibmf_i_init_ci_done(cip);
757 		(void) sprintf(errmsg, "alloc PD failed, status = 0x%x",
758 		    status);
759 		error = B_TRUE;
760 		ibmfstatus = IBMF_TRANSPORT_FAILURE;
761 		goto bail;
762 	}
763 
764 	/* init the ci */
765 	mutex_enter(&cip->ci_mutex);
766 	cip->ci_nports = hca_attrs.hca_nports;
767 	cip->ci_vendor_id = hca_attrs.hca_vendor_id;
768 	cip->ci_device_id = hca_attrs.hca_device_id;
769 	cip->ci_ci_handle = hca_handle;
770 	cip->ci_pd = pd;
771 	cip->ci_init_state |= IBMF_CI_INIT_HCA_INITED;
772 	mutex_exit(&cip->ci_mutex);
773 
774 	/* initialize cqs */
775 	if (ibmf_i_init_cqs(cip) != IBMF_SUCCESS) {
776 		(void) ibt_free_pd(cip->ci_ci_handle, cip->ci_pd);
777 		mutex_enter(&cip->ci_mutex);
778 		cip->ci_init_state &= ~IBMF_CI_INIT_HCA_INITED;
779 		mutex_exit(&cip->ci_mutex);
780 		(void) ibt_close_hca(cip->ci_ci_handle);
781 		ibmf_i_init_ci_done(cip);
782 		(void) sprintf(errmsg, "init CQs failed");
783 		error = B_TRUE;
784 		ibmfstatus = IBMF_FAILURE;
785 		goto bail;
786 	}
787 
788 	/* initialize wqes */
789 	if (ibmf_i_init_wqes(cip) != IBMF_SUCCESS) {
790 		ibmf_i_fini_cqs(cip);
791 		(void) ibt_free_pd(cip->ci_ci_handle, cip->ci_pd);
792 		mutex_enter(&cip->ci_mutex);
793 		cip->ci_init_state &= ~IBMF_CI_INIT_HCA_INITED;
794 		mutex_exit(&cip->ci_mutex);
795 		(void) ibt_close_hca(cip->ci_ci_handle);
796 		ibmf_i_init_ci_done(cip);
797 		(void) sprintf(errmsg, "init WQEs failed");
798 		error = B_TRUE;
799 		ibmfstatus = IBMF_FAILURE;
800 		goto bail;
801 	}
802 
803 	/* initialize the UD destination structure pool */
804 	ibmf_i_init_ud_dest(cip);
805 
806 	/* initialize the QP list */
807 	ibmf_i_init_qplist(cip);
808 
809 	/* initialize condition variable, state, and enable CQ notification */
810 	cip->ci_init_state |= IBMF_CI_INIT_MUTEX_CV_INITED;
811 	(void) ibt_enable_cq_notify(cip->ci_cq_handle, IBT_NEXT_COMPLETION);
812 	(void) ibt_enable_cq_notify(cip->ci_alt_cq_handle, IBT_NEXT_COMPLETION);
813 
814 	/* set state to INITED */
815 	mutex_enter(&cip->ci_mutex);
816 	cip->ci_state = IBMF_CI_STATE_INITED;
817 	mutex_exit(&cip->ci_mutex);
818 
819 	/* wake up waiters blocked on an initialization done event */
820 	ibmf_i_init_ci_done(cip);
821 
822 bail:
823 	if (error) {
824 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_i_init_ci_err,
825 		    IBMF_TNF_ERROR, "", "%s, status = %d\n", tnf_string, msg,
826 		    errmsg, tnf_uint, ibmfstatus, ibmfstatus);
827 	}
828 
829 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_ci_end,
830 	    IBMF_TNF_TRACE, "", "ibmf_i_init_ci() exit, cip = %p\n",
831 	    tnf_opaque, ibmf_ci, cip);
832 
833 	return (ibmfstatus);
834 }
835 
836 /*
837  * ibmf_i_uninit_ci():
838  *	Free up the resources allocated when initalizing the CI structure.
839  */
840 static void
841 ibmf_i_uninit_ci(ibmf_ci_t *cip)
842 {
843 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_uninit_ci_start,
844 	    IBMF_TNF_TRACE, "", "ibmf_i_uninit_ci() enter, cip = %p\n",
845 	    tnf_opaque, cip, cip);
846 
847 	ASSERT(MUTEX_HELD(&cip->ci_mutex) == 0);
848 
849 	/* clean up the QP list */
850 	ibmf_i_fini_qplist(cip);
851 
852 	/* empty completions directly */
853 	ibmf_i_mad_completions(cip->ci_cq_handle, (void*)cip);
854 	ibmf_i_mad_completions(cip->ci_alt_cq_handle, (void*)cip);
855 
856 	mutex_enter(&cip->ci_mutex);
857 	if (cip->ci_init_state & IBMF_CI_INIT_MUTEX_CV_INITED) {
858 		cip->ci_init_state &= ~IBMF_CI_INIT_MUTEX_CV_INITED;
859 	}
860 	mutex_exit(&cip->ci_mutex);
861 
862 	/* clean up the UD destination structure pool */
863 	ibmf_i_fini_ud_dest(cip);
864 
865 	/* clean up any WQE caches */
866 	ibmf_i_fini_wqes(cip);
867 
868 	/* free up the completion queues */
869 	ibmf_i_fini_cqs(cip);
870 
871 	/* free up the protection domain */
872 	(void) ibt_free_pd(cip->ci_ci_handle, cip->ci_pd);
873 
874 	/* close the HCA connection */
875 	(void) ibt_close_hca(cip->ci_ci_handle);
876 
877 	/* set state down to PRESENT */
878 	mutex_enter(&cip->ci_mutex);
879 	cip->ci_init_state &= ~IBMF_CI_INIT_HCA_INITED;
880 	cip->ci_state = IBMF_CI_STATE_PRESENT;
881 	mutex_exit(&cip->ci_mutex);
882 
883 	/* wake up waiters blocked on an un-initialization done event */
884 	ibmf_i_uninit_ci_done(cip);
885 
886 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_uninit_ci_end,
887 	    IBMF_TNF_TRACE, "", "ibmf_i_uninit_ci() exit\n");
888 }
889 
890 /*
891  * ibmf_i_init_ci_done():
892  *	Mark CI initialization as "done", and wake up any waiters.
893  */
894 static void
895 ibmf_i_init_ci_done(ibmf_ci_t *cip)
896 {
897 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_ci_done_start,
898 	    IBMF_TNF_TRACE, "", "ibmf_i_init_ci_done() enter, cip = %p\n",
899 	    tnf_opaque, cip, cip);
900 
901 	mutex_enter(&cip->ci_mutex);
902 	cip->ci_state_flags &= ~IBMF_CI_STATE_INITING;
903 	if (cip->ci_state_flags & IBMF_CI_STATE_INIT_WAIT) {
904 		cip->ci_state_flags &= ~IBMF_CI_STATE_INIT_WAIT;
905 		cv_broadcast(&cip->ci_state_cv);
906 	}
907 	mutex_exit(&cip->ci_mutex);
908 
909 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_ci_done_end,
910 	    IBMF_TNF_TRACE, "", "ibmf_i_init_ci_done() exit\n");
911 }
912 
913 /*
914  * ibmf_i_uninit_ci_done():
915  *	Mark CI uninitialization as "done", and wake up any waiters.
916  */
917 static void
918 ibmf_i_uninit_ci_done(ibmf_ci_t *cip)
919 {
920 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_uninit_ci_done_start,
921 	    IBMF_TNF_TRACE, "", "ibmf_i_uninit_ci_done() enter, cip = %p\n",
922 	    tnf_opaque, cip, cip);
923 
924 	mutex_enter(&cip->ci_mutex);
925 	cip->ci_state_flags &= ~IBMF_CI_STATE_UNINITING;
926 	if (cip->ci_state_flags & IBMF_CI_STATE_UNINIT_WAIT) {
927 		cip->ci_state_flags &= ~IBMF_CI_STATE_UNINIT_WAIT;
928 		cv_broadcast(&cip->ci_state_cv);
929 	}
930 	mutex_exit(&cip->ci_mutex);
931 
932 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_uninit_ci_done_end,
933 	    IBMF_TNF_TRACE, "", "ibmf_i_uninit_ci_done() exit\n");
934 }
935 
936 /*
937  * ibmf_i_init_cqs():
938  *	Allocate a completion queue and set the CQ handler.
939  */
940 static int
941 ibmf_i_init_cqs(ibmf_ci_t *cip)
942 {
943 	ibt_status_t		status;
944 	ibt_cq_attr_t		cq_attrs;
945 	ibt_cq_hdl_t		cq_handle;
946 	uint32_t		num_entries;
947 
948 	ASSERT(MUTEX_NOT_HELD(&cip->ci_mutex));
949 
950 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_cqs_start,
951 	    IBMF_TNF_TRACE, "", "ibmf_i_init_cqs() enter, cip = %p\n",
952 	    tnf_opaque, cip, cip);
953 
954 	/*
955 	 * Allocate completion queue handle.
956 	 * The CQ size should be a 2^n - 1 value to avoid excess CQ allocation
957 	 * as done by some HCAs when the CQ size is specified as a 2^n
958 	 * quantity.
959 	 */
960 	cq_attrs.cq_size = (cip->ci_nports * (ibmf_send_wqes_posted_per_qp +
961 	    ibmf_recv_wqes_posted_per_qp)) - 1;
962 
963 	cq_attrs.cq_sched = NULL;
964 	cq_attrs.cq_flags = 0;
965 
966 	/* Get the CQ handle for the special QPs */
967 	status = ibt_alloc_cq(cip->ci_ci_handle, &cq_attrs,
968 	    &cq_handle, &num_entries);
969 	if (status != IBT_SUCCESS) {
970 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_i_init_cqs_err,
971 		    IBMF_TNF_ERROR, "", "%s, status = %d\n", tnf_string, msg,
972 		    "ibt_alloc_cq failed", tnf_uint, ibt_status, status);
973 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_cqs_end,
974 		    IBMF_TNF_TRACE, "", "ibmf_i_init_cqs() exit\n");
975 		return (IBMF_TRANSPORT_FAILURE);
976 	}
977 	ibt_set_cq_handler(cq_handle, ibmf_statep->ibmf_cq_handler, cip);
978 	cip->ci_cq_handle = cq_handle;
979 
980 	/* Get the CQ handle for the alternate QPs */
981 	status = ibt_alloc_cq(cip->ci_ci_handle, &cq_attrs,
982 	    &cq_handle, &num_entries);
983 	if (status != IBT_SUCCESS) {
984 		(void) ibt_free_cq(cip->ci_cq_handle);
985 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_i_init_cqs_err,
986 		    IBMF_TNF_ERROR, "", "%s, status = %d\n", tnf_string, msg,
987 		    "ibt_alloc_cq failed", tnf_uint, ibt_status, status);
988 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_cqs_end,
989 		    IBMF_TNF_TRACE, "", "ibmf_i_init_cqs() exit\n");
990 		return (IBMF_TRANSPORT_FAILURE);
991 	}
992 	ibt_set_cq_handler(cq_handle, ibmf_statep->ibmf_cq_handler, cip);
993 	cip->ci_alt_cq_handle = cq_handle;
994 
995 	/* set state to CQ INITED */
996 	mutex_enter(&cip->ci_mutex);
997 	cip->ci_init_state |= IBMF_CI_INIT_CQ_INITED;
998 	mutex_exit(&cip->ci_mutex);
999 
1000 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_cqs_end,
1001 	    IBMF_TNF_TRACE, "", "ibmf_i_init_cqs() exit\n");
1002 
1003 	return (IBMF_SUCCESS);
1004 }
1005 
1006 /*
1007  * ibmf_i_fini_cqs():
1008  *	Free up the completion queue
1009  */
1010 static void
1011 ibmf_i_fini_cqs(ibmf_ci_t *cip)
1012 {
1013 	ibt_status_t	status;
1014 	uint_t		ci_init_state;
1015 
1016 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_fini_cqs_start,
1017 	    IBMF_TNF_TRACE, "", "ibmf_i_fini_cqs() enter, cip = %p\n",
1018 	    tnf_opaque, cip, cip);
1019 
1020 	mutex_enter(&cip->ci_mutex);
1021 	ci_init_state = cip->ci_init_state;
1022 	cip->ci_init_state &= ~IBMF_CI_INIT_CQ_INITED;
1023 	mutex_exit(&cip->ci_mutex);
1024 
1025 	if (ci_init_state & IBMF_CI_INIT_CQ_INITED) {
1026 		status = ibt_free_cq(cip->ci_alt_cq_handle);
1027 		if (status != IBT_SUCCESS) {
1028 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L3,
1029 			    ibmf_i_fini_cqs_err, IBMF_TNF_ERROR, "",
1030 			    "%s, status = %d\n", tnf_string, msg,
1031 			    "ibt free cqs failed", tnf_uint, status, status);
1032 		}
1033 
1034 		status = ibt_free_cq(cip->ci_cq_handle);
1035 		if (status != IBT_SUCCESS) {
1036 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L3,
1037 			    ibmf_i_fini_cqs_err, IBMF_TNF_ERROR, "",
1038 			    "%s, status = %d\n", tnf_string, msg,
1039 			    "ibt free cqs failed", tnf_uint, status, status);
1040 		}
1041 	}
1042 
1043 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_fini_cqs_end,
1044 	    IBMF_TNF_TRACE, "", "ibmf_i_fini_cqs() exit");
1045 }
1046 
1047 /*
1048  * ibmf_i_init_qplist():
1049  *	Set the QP list inited state flag
1050  */
1051 static void
1052 ibmf_i_init_qplist(ibmf_ci_t *ibmf_cip)
1053 {
1054 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_qplist_start,
1055 	    IBMF_TNF_TRACE, "", "ibmf_i_init_qplist() enter, cip = %p\n",
1056 	    tnf_opaque, cip, ibmf_cip);
1057 
1058 	mutex_enter(&ibmf_cip->ci_mutex);
1059 	ASSERT((ibmf_cip->ci_init_state & IBMF_CI_INIT_QP_LIST_INITED) == 0);
1060 	ASSERT(ibmf_cip->ci_qp_list == NULL && ibmf_cip->ci_qp_list_tail ==
1061 	    NULL);
1062 	cv_init(&ibmf_cip->ci_qp_cv, NULL, CV_DRIVER, NULL);
1063 	ibmf_cip->ci_init_state |= IBMF_CI_INIT_QP_LIST_INITED;
1064 	mutex_exit(&ibmf_cip->ci_mutex);
1065 
1066 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_qplist_end,
1067 	    IBMF_TNF_TRACE, "", "ibmf_i_init_qplist() exit\n");
1068 }
1069 
1070 /*
1071  * ibmf_i_fini_qplist():
1072  *	Clean up the QP list
1073  */
1074 static void
1075 ibmf_i_fini_qplist(ibmf_ci_t *ibmf_cip)
1076 {
1077 	ibmf_qp_t *qpp;
1078 	ibmf_alt_qp_t *altqpp;
1079 	ibt_status_t status;
1080 
1081 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_fini_qplist_start,
1082 	    IBMF_TNF_TRACE, "", "ibmf_i_fini_qplist() enter, cip = %p\n",
1083 	    tnf_opaque, cip, ibmf_cip);
1084 
1085 	mutex_enter(&ibmf_cip->ci_mutex);
1086 
1087 	if ((ibmf_cip->ci_init_state & IBMF_CI_INIT_QP_LIST_INITED) != 0) {
1088 
1089 		/* walk through the qp list and free the memory */
1090 		qpp = ibmf_cip->ci_qp_list;
1091 		while (qpp != NULL) {
1092 			/* Remove qpp from the list */
1093 			ibmf_cip->ci_qp_list = qpp->iq_next;
1094 
1095 			ASSERT(qpp->iq_qp_ref == 0);
1096 			ASSERT(qpp->iq_flags == IBMF_QP_FLAGS_INVALID);
1097 			mutex_exit(&ibmf_cip->ci_mutex);
1098 			if (qpp->iq_qp_handle != NULL) {
1099 				/* Flush the special QP */
1100 				status = ibt_flush_qp(qpp->iq_qp_handle);
1101 				if (status != IBT_SUCCESS) {
1102 					IBMF_TRACE_2(IBMF_TNF_NODEBUG,
1103 					    DPRINT_L1, ibmf_i_fini_qplist_err,
1104 					    IBMF_TNF_ERROR, "",
1105 					    "%s, status = %d\n", tnf_string,
1106 					    msg, "ibt_flush_qp returned error",
1107 					    tnf_int, status, status);
1108 				}
1109 
1110 				/* Grab the ci_mutex mutex before waiting */
1111 				mutex_enter(&ibmf_cip->ci_mutex);
1112 
1113 				/* Wait if WQEs for special QPs are alloced */
1114 				while (ibmf_cip->ci_wqes_alloced != 0) {
1115 					cv_wait(&ibmf_cip->ci_wqes_cv,
1116 					    &ibmf_cip->ci_mutex);
1117 				}
1118 
1119 				mutex_exit(&ibmf_cip->ci_mutex);
1120 
1121 				/* Free the special QP */
1122 				status = ibt_free_qp(qpp->iq_qp_handle);
1123 				if (status != IBT_SUCCESS) {
1124 					IBMF_TRACE_2(IBMF_TNF_NODEBUG,
1125 					    DPRINT_L1, ibmf_i_fini_qplist_err,
1126 					    IBMF_TNF_ERROR, "",
1127 					    "%s, status = %d\n", tnf_string,
1128 					    msg, "ibt_free_qp returned error",
1129 					    tnf_int, status, status);
1130 				}
1131 			}
1132 			mutex_destroy(&qpp->iq_mutex);
1133 			kmem_free((void *)qpp, sizeof (ibmf_qp_t));
1134 
1135 			/* Grab the mutex again before accessing the QP list */
1136 			mutex_enter(&ibmf_cip->ci_mutex);
1137 			qpp = ibmf_cip->ci_qp_list;
1138 		}
1139 
1140 		cv_destroy(&ibmf_cip->ci_qp_cv);
1141 
1142 		ibmf_cip->ci_qp_list = ibmf_cip->ci_qp_list_tail = NULL;
1143 		ibmf_cip->ci_init_state &=  ~IBMF_CI_INIT_QP_LIST_INITED;
1144 
1145 		altqpp = ibmf_cip->ci_alt_qp_list;
1146 		while (altqpp != NULL) {
1147 			/* Remove altqpp from the list */
1148 			ibmf_cip->ci_alt_qp_list = altqpp->isq_next;
1149 			mutex_exit(&ibmf_cip->ci_mutex);
1150 
1151 			if (altqpp->isq_qp_handle != NULL) {
1152 				/* Flush the special QP */
1153 				status = ibt_flush_qp(altqpp->isq_qp_handle);
1154 				if (status != IBT_SUCCESS) {
1155 					IBMF_TRACE_2(IBMF_TNF_NODEBUG,
1156 					    DPRINT_L1, ibmf_i_fini_qplist_err,
1157 					    IBMF_TNF_ERROR, "",
1158 					    "%s, status = %d\n", tnf_string,
1159 					    msg, "ibt_flush_qp returned error",
1160 					    tnf_int, status, status);
1161 				}
1162 
1163 				/* Free the special QP */
1164 				status = ibt_free_qp(altqpp->isq_qp_handle);
1165 				if (status != IBT_SUCCESS) {
1166 					IBMF_TRACE_2(IBMF_TNF_NODEBUG,
1167 					    DPRINT_L1, ibmf_i_fini_qplist_err,
1168 					    IBMF_TNF_ERROR, "",
1169 					    "%s, status = %d\n", tnf_string,
1170 					    msg, "ibt_free_qp returned error",
1171 					    tnf_int, status, status);
1172 				}
1173 			}
1174 			mutex_destroy(&altqpp->isq_mutex);
1175 			kmem_free((void *)altqpp, sizeof (ibmf_alt_qp_t));
1176 
1177 			/* Grab the mutex again before accessing the QP list */
1178 			mutex_enter(&ibmf_cip->ci_mutex);
1179 			altqpp = ibmf_cip->ci_alt_qp_list;
1180 		}
1181 	}
1182 
1183 	mutex_exit(&ibmf_cip->ci_mutex);
1184 
1185 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_fini_qplist_end,
1186 	    IBMF_TNF_TRACE, "", "ibmf_i_fini_qplist() exit\n");
1187 }
1188 
1189 /*
1190  * ibmf_i_alloc_client():
1191  *	Allocate and initialize the client structure.
1192  */
1193 int
1194 ibmf_i_alloc_client(ibmf_register_info_t *client_infop, uint_t flags,
1195     ibmf_client_t **clientpp)
1196 {
1197 	ibmf_client_t		*ibmf_clientp;
1198 	char			buf[128];
1199 	ibmf_kstat_t		*ksp;
1200 
1201 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_alloc_client_start,
1202 	    IBMF_TNF_TRACE, "", "ibmf_i_alloc_client() enter, "
1203 	    "client_infop = %p\n", tnf_opaque, client_infop, client_infop);
1204 
1205 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ibmf_clientp))
1206 
1207 	/* allocate memory for ibmf_client and initialize it */
1208 	ibmf_clientp = kmem_zalloc(sizeof (ibmf_client_t), KM_SLEEP);
1209 	mutex_init(&ibmf_clientp->ic_mutex, NULL, MUTEX_DRIVER, NULL);
1210 	mutex_init(&ibmf_clientp->ic_msg_mutex, NULL, MUTEX_DRIVER, NULL);
1211 	mutex_init(&ibmf_clientp->ic_kstat_mutex, NULL, MUTEX_DRIVER, NULL);
1212 	cv_init(&ibmf_clientp->ic_recv_cb_teardown_cv, NULL, CV_DRIVER, NULL);
1213 
1214 	(void) sprintf(buf, "s%08X_0x%08X",
1215 	    (uint32_t)client_infop->ir_ci_guid, client_infop->ir_client_class);
1216 
1217 	/* create a taskq to handle send completions based on reg flags */
1218 	if ((flags & IBMF_REG_FLAG_NO_OFFLOAD) == 0) {
1219 		if (flags & IBMF_REG_FLAG_SINGLE_OFFLOAD)
1220 			ibmf_clientp->ic_send_taskq = taskq_create(buf,
1221 			    IBMF_TASKQ_1THREAD, MINCLSYSPRI, 1,
1222 			    ibmf_taskq_max_tasks, TASKQ_PREPOPULATE);
1223 		else
1224 			ibmf_clientp->ic_send_taskq = taskq_create(buf,
1225 			    IBMF_TASKQ_NTHREADS, MINCLSYSPRI, 1,
1226 			    ibmf_taskq_max_tasks,
1227 			    TASKQ_DYNAMIC | TASKQ_PREPOPULATE);
1228 		if (ibmf_clientp->ic_send_taskq == NULL) {
1229 			cv_destroy(&ibmf_clientp->ic_recv_cb_teardown_cv);
1230 			mutex_destroy(&ibmf_clientp->ic_mutex);
1231 			mutex_destroy(&ibmf_clientp->ic_msg_mutex);
1232 			mutex_destroy(&ibmf_clientp->ic_kstat_mutex);
1233 			kmem_free((void *)ibmf_clientp, sizeof (ibmf_client_t));
1234 			IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1235 			    ibmf_i_alloc_client_err, IBMF_TNF_ERROR, "", "%s\n",
1236 			    tnf_string, msg, buf);
1237 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1238 			    ibmf_i_alloc_client_end, IBMF_TNF_TRACE, "",
1239 			    "ibmf_i_alloc_client() exit\n");
1240 			return (IBMF_NO_RESOURCES);
1241 		}
1242 	}
1243 	ibmf_clientp->ic_init_state_class |= IBMF_CI_INIT_SEND_TASKQ_DONE;
1244 
1245 	(void) sprintf(buf, "r%08X_0x%08X",
1246 	    (uint32_t)client_infop->ir_ci_guid, client_infop->ir_client_class);
1247 
1248 	/* create a taskq to handle receive completions on reg flags */
1249 	if ((flags & IBMF_REG_FLAG_NO_OFFLOAD) == 0) {
1250 		if (flags & IBMF_REG_FLAG_SINGLE_OFFLOAD)
1251 			ibmf_clientp->ic_recv_taskq = taskq_create(buf,
1252 			    IBMF_TASKQ_1THREAD, MINCLSYSPRI, 1,
1253 			    ibmf_taskq_max_tasks, TASKQ_PREPOPULATE);
1254 		else
1255 			ibmf_clientp->ic_recv_taskq = taskq_create(buf,
1256 			    IBMF_TASKQ_NTHREADS, MINCLSYSPRI, 1,
1257 			    ibmf_taskq_max_tasks,
1258 			    TASKQ_DYNAMIC | TASKQ_PREPOPULATE);
1259 		if (ibmf_clientp->ic_recv_taskq == NULL) {
1260 			cv_destroy(&ibmf_clientp->ic_recv_cb_teardown_cv);
1261 			mutex_destroy(&ibmf_clientp->ic_mutex);
1262 			mutex_destroy(&ibmf_clientp->ic_msg_mutex);
1263 			mutex_destroy(&ibmf_clientp->ic_kstat_mutex);
1264 			taskq_destroy(ibmf_clientp->ic_send_taskq);
1265 			kmem_free((void *)ibmf_clientp, sizeof (ibmf_client_t));
1266 			IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1267 			    ibmf_i_alloc_client_err, IBMF_TNF_ERROR, "", "%s\n",
1268 			    tnf_string, msg, buf);
1269 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1270 			    ibmf_i_alloc_client_end, IBMF_TNF_TRACE, "",
1271 			    "ibmf_i_alloc_client() exit\n");
1272 			return (IBMF_NO_RESOURCES);
1273 		}
1274 	}
1275 	ibmf_clientp->ic_init_state_class |= IBMF_CI_INIT_RECV_TASKQ_DONE;
1276 	ibmf_clientp->ic_client_info.ci_guid = client_infop->ir_ci_guid;
1277 	ibmf_clientp->ic_client_info.port_num = client_infop->ir_port_num;
1278 
1279 	/* Get the base LID */
1280 	(void) ibt_get_port_state_byguid(ibmf_clientp->ic_client_info.ci_guid,
1281 	    ibmf_clientp->ic_client_info.port_num, NULL,
1282 	    &ibmf_clientp->ic_base_lid);
1283 
1284 	ibmf_clientp->ic_client_info.client_class =
1285 	    client_infop->ir_client_class;
1286 
1287 	/* set up the per client ibmf kstats */
1288 	(void) sprintf(buf, "ibmf_%016" PRIx64 "_%d_%X_stat",
1289 	    client_infop->ir_ci_guid, client_infop->ir_port_num,
1290 	    client_infop->ir_client_class);
1291 	if ((ibmf_clientp->ic_kstatp = kstat_create("ibmf", 0, buf, "misc",
1292 	    KSTAT_TYPE_NAMED, sizeof (ibmf_kstat_t) / sizeof (kstat_named_t),
1293 	    KSTAT_FLAG_WRITABLE)) == NULL) {
1294 		cv_destroy(&ibmf_clientp->ic_recv_cb_teardown_cv);
1295 		mutex_destroy(&ibmf_clientp->ic_mutex);
1296 		mutex_destroy(&ibmf_clientp->ic_msg_mutex);
1297 		mutex_destroy(&ibmf_clientp->ic_kstat_mutex);
1298 		if ((flags & IBMF_REG_FLAG_NO_OFFLOAD) == 0) {
1299 			taskq_destroy(ibmf_clientp->ic_send_taskq);
1300 			taskq_destroy(ibmf_clientp->ic_recv_taskq);
1301 		}
1302 		kmem_free((void *)ibmf_clientp, sizeof (ibmf_client_t));
1303 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1304 		    ibmf_i_alloc_client_err, IBMF_TNF_ERROR, "", "%s\n",
1305 		    tnf_string, msg, "kstat creation failed");
1306 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1307 		    ibmf_i_alloc_client_end, IBMF_TNF_TRACE, "",
1308 		    "ibmf_i_alloc_client() exit\n");
1309 		return (IBMF_NO_RESOURCES);
1310 	}
1311 	ksp = (ibmf_kstat_t *)ibmf_clientp->ic_kstatp->ks_data;
1312 	kstat_named_init(&ksp->msgs_alloced, "messages_allocated",
1313 	    KSTAT_DATA_UINT32);
1314 	kstat_named_init(&ksp->msgs_active, "messages_active",
1315 	    KSTAT_DATA_UINT32);
1316 	kstat_named_init(&ksp->msgs_sent, "messages_sent", KSTAT_DATA_UINT32);
1317 	kstat_named_init(&ksp->msgs_received, "messages_received",
1318 	    KSTAT_DATA_UINT32);
1319 	kstat_named_init(&ksp->sends_active, "sends_active", KSTAT_DATA_UINT32);
1320 	kstat_named_init(&ksp->recvs_active, "receives_active",
1321 	    KSTAT_DATA_UINT32);
1322 	kstat_named_init(&ksp->ud_dests_alloced, "ud_dests_allocated",
1323 	    KSTAT_DATA_UINT32);
1324 	kstat_named_init(&ksp->alt_qps_alloced, "alt_qps_allocated",
1325 	    KSTAT_DATA_UINT32);
1326 	kstat_named_init(&ksp->send_cb_active, "send_callbacks_active",
1327 	    KSTAT_DATA_UINT32);
1328 	kstat_named_init(&ksp->recv_cb_active, "receive_callbacks_active",
1329 	    KSTAT_DATA_UINT32);
1330 	kstat_named_init(&ksp->recv_bufs_alloced, "receive_bufs_allocated",
1331 	    KSTAT_DATA_UINT32);
1332 	kstat_named_init(&ksp->msg_allocs_failed, "msg_allocs_failed",
1333 	    KSTAT_DATA_UINT32);
1334 	kstat_named_init(&ksp->uddest_allocs_failed, "uddest_allocs_failed",
1335 	    KSTAT_DATA_UINT32);
1336 	kstat_named_init(&ksp->alt_qp_allocs_failed, "alt_qp_allocs_failed",
1337 	    KSTAT_DATA_UINT32);
1338 	kstat_named_init(&ksp->send_pkt_failed, "send_pkt_failed",
1339 	    KSTAT_DATA_UINT32);
1340 	kstat_named_init(&ksp->rmpp_errors, "rmpp_errors",
1341 	    KSTAT_DATA_UINT32);
1342 
1343 	kstat_install(ibmf_clientp->ic_kstatp);
1344 
1345 	*clientpp = ibmf_clientp;
1346 
1347 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*ibmf_clientp))
1348 
1349 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_alloc_client_end,
1350 	    IBMF_TNF_TRACE, "", "ibmf_i_alloc_client() exit\n");
1351 
1352 	return (IBMF_SUCCESS);
1353 }
1354 
1355 /*
1356  * ibmf_i_free_client():
1357  *	Free up the client structure and release resources
1358  */
1359 void
1360 ibmf_i_free_client(ibmf_client_t *clientp)
1361 {
1362 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_free_client_start,
1363 	    IBMF_TNF_TRACE, "", "ibmf_i_free_client() enter, clientp = %p\n",
1364 	    tnf_opaque, clientp, clientp);
1365 
1366 	/* delete the general ibmf kstats */
1367 	if (clientp->ic_kstatp != NULL) {
1368 		kstat_delete(clientp->ic_kstatp);
1369 		clientp->ic_kstatp = NULL;
1370 	}
1371 
1372 	/* release references and destroy the resources */
1373 	if (clientp->ic_init_state_class & IBMF_CI_INIT_SEND_TASKQ_DONE) {
1374 		if ((clientp->ic_reg_flags & IBMF_REG_FLAG_NO_OFFLOAD) == 0) {
1375 			taskq_destroy(clientp->ic_send_taskq);
1376 		}
1377 		clientp->ic_init_state_class &= ~IBMF_CI_INIT_SEND_TASKQ_DONE;
1378 	}
1379 
1380 	if (clientp->ic_init_state_class & IBMF_CI_INIT_RECV_TASKQ_DONE) {
1381 		if ((clientp->ic_reg_flags & IBMF_REG_FLAG_NO_OFFLOAD) == 0) {
1382 			taskq_destroy(clientp->ic_recv_taskq);
1383 		}
1384 		clientp->ic_init_state_class &= ~IBMF_CI_INIT_RECV_TASKQ_DONE;
1385 	}
1386 
1387 	mutex_destroy(&clientp->ic_mutex);
1388 	mutex_destroy(&clientp->ic_msg_mutex);
1389 	mutex_destroy(&clientp->ic_kstat_mutex);
1390 	cv_destroy(&clientp->ic_recv_cb_teardown_cv);
1391 	kmem_free((void *)clientp, sizeof (ibmf_client_t));
1392 
1393 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_free_client_end,
1394 	    IBMF_TNF_TRACE, "", "ibmf_i_free_client() exit\n");
1395 }
1396 
1397 /*
1398  * ibmf_i_validate_classes_and_port():
1399  *	Validate the class type and get the client structure
1400  */
1401 int
1402 ibmf_i_validate_classes_and_port(ibmf_ci_t *ibmf_cip,
1403     ibmf_register_info_t *client_infop)
1404 {
1405 	ibmf_client_t		*ibmf_clientp;
1406 	int			status;
1407 
1408 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
1409 	    ibmf_i_validate_classes_and_port_start, IBMF_TNF_TRACE, "",
1410 	    "ibmf_i_validate_classes_and_port() enter, cip = %p, "
1411 	    "clientp = %p\n", tnf_opaque, cip, ibmf_cip,
1412 	    tnf_opaque, client_infop, client_infop);
1413 
1414 	/*
1415 	 * the Solaris implementation of IBMF does not support
1416 	 * the UNIVERSAL_CLASS
1417 	 */
1418 	if (client_infop->ir_client_class == UNIVERSAL_CLASS) {
1419 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1420 		    ibmf_i_validate_classes_and_port_err, IBMF_TNF_ERROR, "",
1421 		    "%s\n", tnf_string, msg,
1422 		    "UNIVERSAL class is not supported");
1423 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1424 		    ibmf_i_validate_classes_and_port_end, IBMF_TNF_TRACE, "",
1425 		    "ibmf_i_validate_classes_and_port() exit\n");
1426 		return (IBMF_NOT_SUPPORTED);
1427 	}
1428 
1429 	/*
1430 	 * Check if the client context already exists on the list
1431 	 * maintained in the CI context. If it is, then the client class
1432 	 * has already been registered for.
1433 	 */
1434 	status = ibmf_i_lookup_client_by_info(ibmf_cip, client_infop,
1435 	    &ibmf_clientp);
1436 	if (status != IBMF_SUCCESS) {
1437 		/* client class has not been previously registered for */
1438 		status = IBMF_SUCCESS;
1439 	} else {
1440 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1441 		    ibmf_i_validate_classes_and_port_err, IBMF_TNF_ERROR, "",
1442 		    "client already registered, class = 0x%X\n",
1443 		    tnf_uint, class, client_infop->ir_client_class);
1444 		status = IBMF_PORT_IN_USE;
1445 	}
1446 
1447 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1448 	    ibmf_i_validate_classes_and_port_end, IBMF_TNF_TRACE, "",
1449 	    "ibmf_i_validate_classes_and_port() exit\n");
1450 	return (status);
1451 }
1452 
1453 /*
1454  * ibmf_i_lookup_client_by_info():
1455  *	Get the client structure from the list
1456  */
1457 static int
1458 ibmf_i_lookup_client_by_info(ibmf_ci_t *ibmf_cip,
1459     ibmf_register_info_t *ir_client, ibmf_client_t **clientpp)
1460 {
1461 	ibmf_client_t *clientp;
1462 
1463 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
1464 	    ibmf_i_lookup_client_by_info_start, IBMF_TNF_TRACE, "",
1465 	    "ibmf_i_lookup_client_by_info() enter, cip = %p, clientinfo = %p\n",
1466 	    tnf_opaque, cip, ibmf_cip, tnf_opaque, clientinfo, ir_client);
1467 
1468 	ASSERT(MUTEX_NOT_HELD(&ibmf_cip->ci_clients_mutex));
1469 
1470 	/*
1471 	 * walk the CI's client list searching for one with the specified class
1472 	 */
1473 	mutex_enter(&ibmf_cip->ci_clients_mutex);
1474 	clientp = ibmf_cip->ci_clients;
1475 	while (clientp != NULL) {
1476 		ibmf_client_info_t *tmp = &clientp->ic_client_info;
1477 		if (tmp->client_class == ir_client->ir_client_class &&
1478 		    ir_client->ir_client_class != UNIVERSAL_CLASS &&
1479 		    tmp->ci_guid == ir_client->ir_ci_guid &&
1480 		    tmp->port_num == ir_client->ir_port_num) {
1481 			/* found our match */
1482 			break;
1483 		}
1484 		clientp = clientp->ic_next;
1485 	}
1486 	mutex_exit(&ibmf_cip->ci_clients_mutex);
1487 
1488 	if (clientp != NULL) {
1489 		*clientpp = clientp;
1490 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
1491 		    ibmf_i_lookup_client_by_info_end, IBMF_TNF_TRACE, "",
1492 		    "ibmf_i_lookup_client_by_info(): clientp = %p\n",
1493 		    tnf_opaque, clientp, clientp);
1494 		return (IBMF_SUCCESS);
1495 	} else {
1496 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1497 		    ibmf_i_lookup_client_by_info_end, IBMF_TNF_TRACE, "",
1498 		    "ibmf_i_lookup_client_by_info() exit\n");
1499 		return (IBMF_FAILURE);
1500 	}
1501 }
1502 
1503 /*
1504  * ibmf_i_add_client():
1505  *	Add a new client to the client list
1506  */
1507 void
1508 ibmf_i_add_client(ibmf_ci_t *ibmf_cip, ibmf_client_t *ibmf_clientp)
1509 {
1510 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_add_start,
1511 	    IBMF_TNF_TRACE, "",
1512 	    "ibmf_i_add_client() enter, cip = %p, clientp = %p\n",
1513 	    tnf_opaque, ibmf_ci, ibmf_cip, tnf_opaque, client, ibmf_clientp);
1514 
1515 	ASSERT(MUTEX_NOT_HELD(&ibmf_cip->ci_clients_mutex));
1516 
1517 	mutex_enter(&ibmf_cip->ci_clients_mutex);
1518 	ibmf_clientp->ic_next = NULL;
1519 	ibmf_clientp->ic_prev = ibmf_cip->ci_clients_last;
1520 	if (ibmf_cip->ci_clients == NULL) {
1521 		ibmf_cip->ci_clients = ibmf_clientp;
1522 	}
1523 	if (ibmf_cip->ci_clients_last) {
1524 		ibmf_cip->ci_clients_last->ic_next = ibmf_clientp;
1525 	}
1526 	ibmf_cip->ci_clients_last = ibmf_clientp;
1527 	mutex_exit(&ibmf_cip->ci_clients_mutex);
1528 
1529 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_add_end,
1530 	    IBMF_TNF_TRACE, "", "ibmf_i_add_client() exit\n");
1531 }
1532 
1533 /*
1534  * ibmf_i_delete_client():
1535  *	Delete a client from the client list
1536  */
1537 void
1538 ibmf_i_delete_client(ibmf_ci_t *ibmf_cip, ibmf_client_t *ibmf_clientp)
1539 {
1540 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_delete_client_start,
1541 	    IBMF_TNF_TRACE, "", "ibmf_i_delete_client() enter, "
1542 	    "ibmf_i_delete_client() enter, cip = %p, clientp = %p\n",
1543 	    tnf_opaque, ibmf_ci, ibmf_cip, tnf_opaque, client, ibmf_clientp);
1544 
1545 	ASSERT(MUTEX_NOT_HELD(&ibmf_cip->ci_clients_mutex));
1546 
1547 	mutex_enter(&ibmf_cip->ci_clients_mutex);
1548 	if (ibmf_clientp->ic_next)
1549 		ibmf_clientp->ic_next->ic_prev = ibmf_clientp->ic_prev;
1550 
1551 	if (ibmf_clientp->ic_prev)
1552 		ibmf_clientp->ic_prev->ic_next = ibmf_clientp->ic_next;
1553 
1554 	if (ibmf_cip->ci_clients == ibmf_clientp) {
1555 		ibmf_cip->ci_clients = ibmf_clientp->ic_next;
1556 	}
1557 	if (ibmf_cip->ci_clients_last == ibmf_clientp) {
1558 		ibmf_cip->ci_clients_last = ibmf_clientp->ic_prev;
1559 	}
1560 	mutex_exit(&ibmf_cip->ci_clients_mutex);
1561 
1562 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_delete_client_end,
1563 	    IBMF_TNF_TRACE, "", "ibmf_i_delete_client() exit\n");
1564 }
1565 
1566 /*
1567  * ibmf_i_get_qp():
1568  *	Get the QP structure based on the client class
1569  */
1570 int
1571 ibmf_i_get_qp(ibmf_ci_t *ibmf_cip, uint_t port_num, ibmf_client_type_t class,
1572     ibmf_qp_t **qppp)
1573 {
1574 	ibmf_qp_t		*qpp;
1575 	int			qp_num, status = IBMF_SUCCESS;
1576 
1577 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_get_qp_start,
1578 	    IBMF_TNF_TRACE, "", "ibmf_i_get_qp() enter, cip = %p, "
1579 	    "port = %d, class = %x\n", tnf_opaque, ibmf_ci, ibmf_cip,
1580 	    tnf_int, port, port_num, tnf_opaque, class, class);
1581 
1582 	ASSERT(MUTEX_NOT_HELD(&ibmf_cip->ci_mutex));
1583 
1584 	mutex_enter(&ibmf_cip->ci_mutex);
1585 
1586 	/*
1587 	 * walk through the list of qps on this ci, looking for one that
1588 	 * corresponds to the type and class the caller is interested in.
1589 	 * If it is not there, we need allocate it from the transport. Since
1590 	 * qp0 & qp1 can only be allocated once, we maintain a reference count
1591 	 * and call the transport for allocation iff the ref count is 0.
1592 	 */
1593 	qp_num = (class == SUBN_AGENT || class == SUBN_MANAGER) ? 0 : 1;
1594 
1595 	qpp = ibmf_cip->ci_qp_list;
1596 	while (qpp != NULL) {
1597 		if (port_num == qpp->iq_port_num && qp_num == qpp->iq_qp_num)
1598 			break;
1599 		qpp = qpp->iq_next;
1600 	}
1601 
1602 	if (qpp == NULL) {
1603 		/*
1604 		 * allocate qp and add it the qp list; recheck to
1605 		 * catch races
1606 		 */
1607 		ibmf_qp_t *tqpp;
1608 
1609 		mutex_exit(&ibmf_cip->ci_mutex);
1610 
1611 		tqpp = (ibmf_qp_t *)kmem_zalloc(sizeof (ibmf_qp_t), KM_SLEEP);
1612 
1613 		/* check the list under lock */
1614 		mutex_enter(&ibmf_cip->ci_mutex);
1615 
1616 		qpp = ibmf_cip->ci_qp_list;
1617 		while (qpp != NULL) {
1618 			if (port_num == qpp->iq_port_num && qp_num ==
1619 			    qpp->iq_qp_num)
1620 				break;
1621 			qpp = qpp->iq_next;
1622 		}
1623 
1624 		if (qpp != NULL) {
1625 			/* some one raced past us and added to the list */
1626 			kmem_free((void *)tqpp, sizeof (ibmf_qp_t));
1627 		} else {
1628 			/* add this to the qp list */
1629 			qpp = tqpp;
1630 			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*qpp))
1631 			qpp->iq_next = NULL;
1632 			if (ibmf_cip->ci_qp_list == NULL)
1633 				ibmf_cip->ci_qp_list = qpp;
1634 			if (ibmf_cip->ci_qp_list_tail != NULL)
1635 				ibmf_cip->ci_qp_list_tail->iq_next = qpp;
1636 			ibmf_cip->ci_qp_list_tail = qpp;
1637 			qpp->iq_port_num = port_num;
1638 			qpp->iq_qp_num = qp_num;
1639 			qpp->iq_flags = IBMF_QP_FLAGS_INVALID;
1640 			mutex_init(&qpp->iq_mutex, NULL, MUTEX_DRIVER, NULL);
1641 		}
1642 	}
1643 
1644 	/* we now have a QP context */
1645 	for (;;) {
1646 		if (qpp->iq_flags == IBMF_QP_FLAGS_INITING) {
1647 
1648 			/* block till qp is in VALID state */
1649 			cv_wait(&ibmf_cip->ci_qp_cv, &ibmf_cip->ci_mutex);
1650 			continue;
1651 
1652 		}
1653 
1654 		if (qpp->iq_flags == IBMF_QP_FLAGS_UNINITING) {
1655 
1656 			/* block till qp is in INVALID state */
1657 			cv_wait(&ibmf_cip->ci_qp_cv, &ibmf_cip->ci_mutex);
1658 			continue;
1659 		}
1660 
1661 		if (qpp->iq_flags == IBMF_QP_FLAGS_INVALID) {
1662 			if ((status = ibmf_i_init_qp(ibmf_cip, qpp)) !=
1663 			    IBMF_SUCCESS) {
1664 				ibmf_qp_t *tqpp;
1665 
1666 				/*
1667 				 * Remove the QP context from the CI's list.
1668 				 * Only initialized QPs should be on the list.
1669 				 * We know that this QP is on the list, so
1670 				 * the list is not empty.
1671 				 */
1672 				tqpp = ibmf_cip->ci_qp_list;
1673 				if (tqpp == qpp) {
1674 					/* Only QP context on the list */
1675 					ibmf_cip->ci_qp_list = NULL;
1676 					ibmf_cip->ci_qp_list_tail = NULL;
1677 				}
1678 
1679 				/* Find the QP context before the last one */
1680 				if (tqpp != qpp) {
1681 					while (tqpp->iq_next != qpp) {
1682 						tqpp = tqpp->iq_next;
1683 					}
1684 
1685 					/*
1686 					 * We are at the second last element of
1687 					 * the list. Readjust the tail pointer.
1688 					 * Remove the last element from the
1689 					 * list.
1690 					 */
1691 					tqpp->iq_next = NULL;
1692 					ibmf_cip->ci_qp_list_tail = tqpp;
1693 				}
1694 
1695 				/* Free up the QP context */
1696 				kmem_free((void *)qpp, sizeof (ibmf_qp_t));
1697 
1698 				break;
1699 			}
1700 			continue;
1701 		}
1702 
1703 		if (qpp->iq_flags == IBMF_QP_FLAGS_INITED) {
1704 			qpp->iq_qp_ref++;
1705 			break;
1706 		}
1707 	}
1708 
1709 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*qpp))
1710 
1711 	mutex_exit(&ibmf_cip->ci_mutex);
1712 
1713 	if (status == IBMF_SUCCESS) {
1714 		*qppp = qpp;
1715 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_get_qp_end,
1716 		    IBMF_TNF_TRACE, "", "ibmf_i_get_qp() exit "
1717 		    "qp_handle = %p\n", tnf_opaque, qp_handle, qpp);
1718 		return (IBMF_SUCCESS);
1719 	} else {
1720 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_i_get_qp_err,
1721 		    IBMF_TNF_ERROR, "", "%s\n", tnf_string, msg,
1722 		    "ibmf_i_get_qp(): qp_not found");
1723 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_get_qp_end,
1724 		    IBMF_TNF_TRACE, "", "ibmf_i_get_qp() exit\n");
1725 		return (status);
1726 	}
1727 }
1728 
1729 /*
1730  * ibmf_i_release_qp():
1731  *	Drop the reference count on the QP structure
1732  */
1733 void
1734 ibmf_i_release_qp(ibmf_ci_t *ibmf_cip, ibmf_qp_t **qppp)
1735 {
1736 	ibmf_qp_t	*qpp;
1737 
1738 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_release_qp_start,
1739 	    IBMF_TNF_TRACE, "", "ibmf_i_release_qp() enter, cip = %p, "
1740 	    "qpp = %p\n", tnf_opaque, cip, ibmf_cip, tnf_opaque, qpp, *qppp);
1741 
1742 	ASSERT(MUTEX_NOT_HELD(&ibmf_cip->ci_mutex));
1743 
1744 	mutex_enter(&ibmf_cip->ci_mutex);
1745 	qpp = *qppp;
1746 	qpp->iq_qp_ref--;
1747 	if (qpp->iq_qp_ref == 0)
1748 		ibmf_i_uninit_qp(ibmf_cip, qpp);
1749 	mutex_exit(&ibmf_cip->ci_mutex);
1750 
1751 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_release_qp_end,
1752 	    IBMF_TNF_TRACE, "", "ibmf_i_release_qp() exit\n");
1753 }
1754 
1755 /*
1756  * ibmf_i_init_qp():
1757  *	Set up the QP context, request a QP from the IBT framework
1758  *	and initialize it
1759  */
1760 static int
1761 ibmf_i_init_qp(ibmf_ci_t *ibmf_cip, ibmf_qp_t *qpp)
1762 {
1763 	ibt_sqp_type_t		qp_type;
1764 	ibt_qp_alloc_attr_t	qp_attrs;
1765 	ibt_qp_hdl_t		qp_handle;
1766 	ibt_qp_info_t		qp_modify_attr;
1767 	ibt_status_t		ibt_status;
1768 	int			i, status;
1769 
1770 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_qp_start,
1771 	    IBMF_TNF_TRACE, "", "ibmf_i_init_qp() enter, cip = %p, "
1772 	    "port = %d, qp = %d\n", tnf_opaque, ibmf_ci, ibmf_cip, tnf_int,
1773 	    port, qpp->iq_port_num, tnf_int, num, qpp->iq_qp_num);
1774 
1775 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(qpp->iq_qp_handle))
1776 
1777 	ASSERT(MUTEX_HELD(&ibmf_cip->ci_mutex));
1778 
1779 	qpp->iq_flags = IBMF_QP_FLAGS_INITING;
1780 	mutex_exit(&ibmf_cip->ci_mutex);
1781 	if (qpp->iq_qp_handle) {	/* closed but not yet freed */
1782 		ibt_status = ibt_free_qp(qpp->iq_qp_handle);
1783 		if (ibt_status != IBT_SUCCESS) {
1784 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
1785 			    ibmf_i_init_qp_err, IBMF_TNF_ERROR, "",
1786 			    "%s, status = %d\n", tnf_string, msg,
1787 			    "ibt_free_qp returned error",
1788 			    tnf_uint, ibt_status, ibt_status);
1789 		}
1790 		qpp->iq_qp_handle = NULL;
1791 	}
1792 	ASSERT(qpp->iq_qp_num == 0 || qpp->iq_qp_num == 1);
1793 	if (qpp->iq_qp_num == 0)
1794 		qp_type = IBT_SMI_SQP;
1795 	else
1796 		qp_type = IBT_GSI_SQP;
1797 	qp_attrs.qp_scq_hdl = ibmf_cip->ci_cq_handle;
1798 	qp_attrs.qp_rcq_hdl = ibmf_cip->ci_cq_handle;
1799 	qp_attrs.qp_pd_hdl = ibmf_cip->ci_pd;
1800 	qp_attrs.qp_sizes.cs_sq_sgl = 1;
1801 	qp_attrs.qp_sizes.cs_rq_sgl = IBMF_MAX_RQ_WR_SGL_ELEMENTS;
1802 	qp_attrs.qp_sizes.cs_sq = ibmf_send_wqes_posted_per_qp;
1803 	qp_attrs.qp_sizes.cs_rq = ibmf_recv_wqes_posted_per_qp;
1804 	qp_attrs.qp_flags = IBT_ALL_SIGNALED;
1805 	qp_attrs.qp_alloc_flags = IBT_QP_NO_FLAGS;
1806 
1807 	/* call the IB transport to allocate a special QP */
1808 	ibt_status = ibt_alloc_special_qp(ibmf_cip->ci_ci_handle,
1809 	    qpp->iq_port_num, qp_type, &qp_attrs, NULL, &qp_handle);
1810 	if (ibt_status != IBT_SUCCESS) {
1811 		mutex_enter(&ibmf_cip->ci_mutex);
1812 		qpp->iq_flags = IBMF_QP_FLAGS_INVALID;
1813 		cv_broadcast(&ibmf_cip->ci_qp_cv);
1814 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_i_init_qp_err,
1815 		    IBMF_TNF_ERROR, "", "ibmf_i_init_qp() error status = %d\n",
1816 		    tnf_uint, ibt_status, ibt_status);
1817 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_qp_end,
1818 		    IBMF_TNF_TRACE, "", "ibmf_i_init_qp() exit\n");
1819 		return (IBMF_TRANSPORT_FAILURE);
1820 	}
1821 
1822 	/* initialize qpp */
1823 	qpp->iq_qp_handle = qp_handle;
1824 	qp_modify_attr.qp_trans = IBT_UD_SRV;
1825 	qp_modify_attr.qp_flags = IBT_CEP_NO_FLAGS;
1826 
1827 	/* get the pkey index for the specified pkey */
1828 	if (ibmf_i_get_pkeyix(ibmf_cip->ci_ci_handle, IBMF_P_KEY_DEF_LIMITED,
1829 	    qpp->iq_port_num, &qp_modify_attr.qp_transport.ud.ud_pkey_ix) !=
1830 	    IBMF_SUCCESS) {
1831 		ibt_status = ibt_free_qp(qpp->iq_qp_handle);
1832 		if (ibt_status != IBT_SUCCESS) {
1833 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
1834 			    ibmf_i_init_qp_err, IBMF_TNF_ERROR, "",
1835 			    "%s, status = %d\n", tnf_string, msg,
1836 			    "ibt_free_qp returned error",
1837 			    tnf_uint, ibt_status, ibt_status);
1838 		}
1839 		mutex_enter(&ibmf_cip->ci_mutex);
1840 		qpp->iq_flags = IBMF_QP_FLAGS_INVALID;
1841 		cv_broadcast(&ibmf_cip->ci_qp_cv);
1842 		IBMF_TRACE_0(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_i_init_qp_err,
1843 		    IBMF_TNF_ERROR, "", "ibmf_init_qp(): failed to get "
1844 		    "pkey index\n");
1845 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_qp_end,
1846 		    IBMF_TNF_TRACE, "", "ibmf_i_init_qp() exit\n");
1847 		return (IBMF_FAILURE);
1848 	}
1849 	qp_modify_attr.qp_transport.ud.ud_sq_psn = 0;
1850 	qp_modify_attr.qp_transport.ud.ud_port = qpp->iq_port_num;
1851 	qp_modify_attr.qp_transport.ud.ud_qkey = IBMF_MGMT_Q_KEY;
1852 
1853 	/* call the IB transport to initialize the QP */
1854 	ibt_status = ibt_initialize_qp(qp_handle, &qp_modify_attr);
1855 	if (ibt_status != IBT_SUCCESS) {
1856 		ibt_status = ibt_free_qp(qpp->iq_qp_handle);
1857 		if (ibt_status != IBT_SUCCESS) {
1858 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
1859 			    ibmf_i_init_qp_err, IBMF_TNF_ERROR, "",
1860 			    "%s, status = %d\n", tnf_string, msg,
1861 			    "ibt_free_qp returned error",
1862 			    tnf_uint, ibt_status, ibt_status);
1863 		}
1864 		mutex_enter(&ibmf_cip->ci_mutex);
1865 		qpp->iq_flags = IBMF_QP_FLAGS_INVALID;
1866 		cv_broadcast(&ibmf_cip->ci_qp_cv);
1867 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_i_init_qp_err,
1868 		    IBMF_TNF_ERROR, "", "ibmf_init_qp(): error status = %d\n",
1869 		    tnf_uint, ibt_status, ibt_status);
1870 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_qp_end,
1871 		    IBMF_TNF_TRACE, "", "ibmf_i_init_qp() exit\n");
1872 		return (IBMF_TRANSPORT_FAILURE);
1873 	}
1874 
1875 	/* post receive wqes to the RQ to handle unsolicited inbound packets  */
1876 	for (i = 0; i < ibmf_recv_wqes_per_port; i++) {
1877 		status =  ibmf_i_post_recv_buffer(ibmf_cip, qpp,
1878 		    B_TRUE, IBMF_QP_HANDLE_DEFAULT);
1879 		if (status != IBMF_SUCCESS) {
1880 			IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L1,
1881 			    ibmf_i_init_qp, IBMF_TNF_TRACE, "",
1882 			    "%s\n", tnf_string, msg, "ibmf_i_init_qp(): "
1883 			    "ibmf_i_post_recv_buffer() failed");
1884 		}
1885 	}
1886 	mutex_enter(&ibmf_cip->ci_mutex);
1887 
1888 	/* set the state and signal blockers */
1889 	qpp->iq_flags = IBMF_QP_FLAGS_INITED;
1890 	cv_broadcast(&ibmf_cip->ci_qp_cv);
1891 
1892 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_qp_end,
1893 	    IBMF_TNF_TRACE, "", "ibmf_i_init_qp() exit\n");
1894 	return (IBMF_SUCCESS);
1895 }
1896 
1897 /*
1898  * ibmf_i_uninit_qp():
1899  *	Invalidate the QP context
1900  */
1901 static void
1902 ibmf_i_uninit_qp(ibmf_ci_t *ibmf_cip, ibmf_qp_t *qpp)
1903 {
1904 	ibt_status_t		status;
1905 
1906 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_uninit_qp_start,
1907 	    IBMF_TNF_TRACE, "", "ibmf_i_uninit_qp() enter, cip = %p "
1908 	    "qpp = %p\n", tnf_opaque, cip, ibmf_cip, tnf_opaque, qpp, qpp);
1909 
1910 	ASSERT(MUTEX_HELD(&ibmf_cip->ci_mutex));
1911 
1912 	/* mark the state as uniniting */
1913 	ASSERT(qpp->iq_qp_ref == 0);
1914 	qpp->iq_flags = IBMF_QP_FLAGS_UNINITING;
1915 	mutex_exit(&ibmf_cip->ci_mutex);
1916 
1917 	/* note: we ignore error values from ibt_flush_qp */
1918 	status = ibt_flush_qp(qpp->iq_qp_handle);
1919 	if (status != IBT_SUCCESS) {
1920 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L2,
1921 		    ibmf_i_uninit_qp_err, IBMF_TNF_ERROR, "",
1922 		    "ibmf_i_uninit_qp(): %s, status = %d\n", tnf_string, msg,
1923 		    "ibt_flush_qp returned error", tnf_int, status, status);
1924 	}
1925 
1926 	/* mark state as INVALID and signal any blockers */
1927 	mutex_enter(&ibmf_cip->ci_mutex);
1928 	qpp->iq_flags = IBMF_QP_FLAGS_INVALID;
1929 	cv_broadcast(&ibmf_cip->ci_qp_cv);
1930 
1931 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_uninit_qp_end,
1932 	    IBMF_TNF_TRACE, "", "ibmf_i_uninit_qp() exit\n");
1933 }
1934 
1935 /*
1936  * ibmf_i_alloc_msg():
1937  *	Allocate and set up a message context
1938  */
1939 int
1940 ibmf_i_alloc_msg(ibmf_client_t *clientp, ibmf_msg_impl_t **msgp, int km_flags)
1941 {
1942 	ibmf_msg_impl_t *msgimplp;
1943 
1944 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4,
1945 	    ibmf_i_alloc_msg_start, IBMF_TNF_TRACE, "",
1946 	    "ibmf_i_alloc_msg() enter, clientp = %p, msg = %p, "
1947 	    " kmflags = %d\n", tnf_opaque, clientp, clientp, tnf_opaque, msg,
1948 	    *msgp, tnf_int, km_flags, km_flags);
1949 
1950 	/* allocate the message context */
1951 	msgimplp = (ibmf_msg_impl_t *)kmem_zalloc(sizeof (ibmf_msg_impl_t),
1952 	    km_flags);
1953 	if (msgimplp != NULL) {
1954 
1955 		ibmf_ud_dest_t	*ibmf_ud_dest;
1956 
1957 		if (km_flags == KM_SLEEP) {
1958 			ibmf_i_pop_ud_dest_thread(clientp->ic_myci);
1959 		}
1960 
1961 		/* get a UD dest structure from the pool */
1962 		ibmf_ud_dest = ibmf_i_get_ud_dest(clientp->ic_myci);
1963 		if (ibmf_ud_dest == NULL) {
1964 			kmem_free(msgimplp, sizeof (ibmf_msg_impl_t));
1965 			IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1966 			    ibmf_i_alloc_msg_err, IBMF_TNF_ERROR, "",
1967 			    "ibmf_i_alloc_msg(): %s\n",
1968 			    tnf_string, msg, "No ud_dest available");
1969 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1970 			    ibmf_i_alloc_msg_end, IBMF_TNF_TRACE, "",
1971 			    "ibmf_i_alloc_msg() exit\n");
1972 			return (IBMF_NO_RESOURCES);
1973 		}
1974 		msgimplp->im_ibmf_ud_dest = ibmf_ud_dest;
1975 		msgimplp->im_ud_dest = &ibmf_ud_dest->ud_dest;
1976 
1977 	} else {
1978 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1979 		    ibmf_i_alloc_msg_err, IBMF_TNF_ERROR, "",
1980 		    "ibmf_i_alloc_msg(): %s\n",
1981 		    tnf_string, msg, "kmem_xalloc failed");
1982 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_alloc_msg_end,
1983 		    IBMF_TNF_TRACE, "", "ibmf_i_alloc_msg() exit\n");
1984 		return (IBMF_NO_RESOURCES);
1985 	}
1986 
1987 	*msgp = msgimplp;
1988 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_alloc_msg_end,
1989 	    IBMF_TNF_TRACE, "", "ibmf_i_alloc_msg() exit\n");
1990 	return (IBMF_SUCCESS);
1991 }
1992 
1993 /*
1994  * ibmf_i_free_msg():
1995  *	frees up all buffers allocated by IBMF for
1996  * 	this message context, and then frees up the context
1997  */
1998 void
1999 ibmf_i_free_msg(ibmf_msg_impl_t *msgimplp)
2000 {
2001 	ibmf_msg_bufs_t *msgbufp = &msgimplp->im_msgbufs_recv;
2002 	ibmf_client_t *clientp = (ibmf_client_t *)msgimplp->im_client;
2003 	uint32_t	cl_hdr_sz, cl_hdr_off;
2004 
2005 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
2006 	    ibmf_i_free_msg_start, IBMF_TNF_TRACE, "",
2007 	    "ibmf_i_free_msg() enter, msg = %p\n", tnf_opaque, msg, msgimplp);
2008 
2009 	/* free up the UD destination resource */
2010 	if (msgimplp->im_ibmf_ud_dest != NULL) {
2011 		ibmf_i_free_ud_dest(clientp, msgimplp);
2012 		ibmf_i_clean_ud_dest_list(clientp->ic_myci, B_FALSE);
2013 	}
2014 
2015 	/* free up the receive buffer if allocated previously */
2016 	if (msgbufp->im_bufs_mad_hdr != NULL) {
2017 		ibmf_i_mgt_class_to_hdr_sz_off(
2018 		    msgbufp->im_bufs_mad_hdr->MgmtClass,
2019 		    &cl_hdr_sz, &cl_hdr_off);
2020 		kmem_free(msgbufp->im_bufs_mad_hdr, sizeof (ib_mad_hdr_t) +
2021 		    cl_hdr_off + msgbufp->im_bufs_cl_hdr_len +
2022 		    msgbufp->im_bufs_cl_data_len);
2023 		mutex_enter(&clientp->ic_kstat_mutex);
2024 		IBMF_SUB32_KSTATS(clientp, recv_bufs_alloced, 1);
2025 		mutex_exit(&clientp->ic_kstat_mutex);
2026 	}
2027 
2028 	/* destroy the message mutex */
2029 	mutex_destroy(&msgimplp->im_mutex);
2030 
2031 	/* free the message context */
2032 	kmem_free(msgimplp, sizeof (ibmf_msg_impl_t));
2033 
2034 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_free_msg_end,
2035 	    IBMF_TNF_TRACE, "", "ibmf_i_free_msg() exit\n");
2036 }
2037 
2038 /*
2039  * ibmf_i_msg_transport():
2040  *	Send a message posted by the IBMF client using the RMPP protocol
2041  *	if specified
2042  */
2043 int
2044 ibmf_i_msg_transport(ibmf_client_t *clientp, ibmf_qp_handle_t ibmf_qp_handle,
2045     ibmf_msg_impl_t *msgimplp, int blocking)
2046 {
2047 	ib_mad_hdr_t	*madhdrp;
2048 	ibmf_msg_bufs_t *msgbufp, *smsgbufp;
2049 	uint32_t	cl_hdr_sz, cl_hdr_off;
2050 	boolean_t	isDS = 0; /* double sided (sequenced) transaction */
2051 	boolean_t	error = B_FALSE;
2052 	int		status = IBMF_SUCCESS;
2053 	uint_t		refcnt;
2054 	char		errmsg[128];
2055 	timeout_id_t	msg_rp_unset_id, msg_tr_unset_id;
2056 
2057 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_msg_transport_start,
2058 	    IBMF_TNF_TRACE, "", "ibmf_i_msg_transport(): clientp = 0x%p, "
2059 	    "qphdl = 0x%p, msgp = 0x%p, block = %d\n",
2060 	    tnf_opaque, clientp, clientp, tnf_opaque, qphdl, ibmf_qp_handle,
2061 	    tnf_opaque, msg, msgimplp, tnf_uint, block, blocking);
2062 
2063 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msgimplp, *msgbufp))
2064 
2065 	mutex_enter(&msgimplp->im_mutex);
2066 
2067 	madhdrp = msgimplp->im_msgbufs_send.im_bufs_mad_hdr;
2068 	msgbufp = &msgimplp->im_msgbufs_recv;
2069 	smsgbufp = &msgimplp->im_msgbufs_send;
2070 
2071 	/*
2072 	 * check if transp_op_flags specify that the transaction is
2073 	 * a single packet, then the size of the message header + data
2074 	 * does not exceed 256 bytes
2075 	 */
2076 	if ((msgimplp->im_transp_op_flags & IBMF_MSG_TRANS_FLAG_RMPP) == 0) {
2077 		ibmf_i_mgt_class_to_hdr_sz_off(
2078 		    smsgbufp->im_bufs_mad_hdr->MgmtClass,
2079 		    &cl_hdr_sz, &cl_hdr_off);
2080 
2081 		if ((sizeof (ib_mad_hdr_t) + cl_hdr_off +
2082 		    smsgbufp->im_bufs_cl_hdr_len +
2083 		    smsgbufp->im_bufs_cl_data_len) > IBMF_MAD_SIZE) {
2084 			mutex_exit(&msgimplp->im_mutex);
2085 			(void) sprintf(errmsg,
2086 			    "Non-RMPP message size is too large");
2087 			error = B_TRUE;
2088 			status = IBMF_BAD_SIZE;
2089 			goto bail;
2090 		}
2091 	}
2092 
2093 	/* more message context initialization */
2094 	msgimplp->im_qp_hdl 	= ibmf_qp_handle;
2095 	msgimplp->im_tid	= b2h64(madhdrp->TransactionID);
2096 	msgimplp->im_mgt_class 	= madhdrp->MgmtClass;
2097 	msgimplp->im_unsolicited = B_FALSE;
2098 	msgimplp->im_trans_state_flags = IBMF_TRANS_STATE_FLAG_UNINIT;
2099 	msgimplp->im_rmpp_ctx.rmpp_state = IBMF_RMPP_STATE_UNDEFINED;
2100 	msgimplp->im_rmpp_ctx.rmpp_respt = IBMF_RMPP_DEFAULT_RRESPT;
2101 	msgimplp->im_rmpp_ctx.rmpp_retry_cnt = 0;
2102 	IBMF_MSG_INCR_REFCNT(msgimplp);
2103 	if (msgimplp->im_retrans.retrans_retries == 0)
2104 		msgimplp->im_retrans.retrans_retries = IBMF_RETRANS_DEF_RETRIES;
2105 	if (msgimplp->im_retrans.retrans_rtv == 0)
2106 		msgimplp->im_retrans.retrans_rtv = IBMF_RETRANS_DEF_RTV;
2107 	if (msgimplp->im_retrans.retrans_rttv == 0)
2108 		msgimplp->im_retrans.retrans_rttv = IBMF_RETRANS_DEF_RTTV;
2109 
2110 	IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_msg_transport,
2111 	    IBMF_TNF_TRACE, "", "ibmf_i_msg_transport(): %s, msgp = 0x%p, "
2112 	    "class = 0x%x, method = 0x%x, attributeID = 0x%x\n",
2113 	    tnf_string, msg, "Added message", tnf_opaque, msgimplp,
2114 	    msgimplp, tnf_opaque, class, msgimplp->im_mgt_class, tnf_opaque,
2115 	    method, madhdrp->R_Method, tnf_opaque, attrib_id,
2116 	    b2h16(madhdrp->AttributeID));
2117 
2118 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_msg_transport,
2119 	    IBMF_TNF_TRACE, "", "ibmf_i_msg_transport(): msgp = 0x%p, "
2120 	    "TID = 0x%p, transp_op_flags = 0x%x\n",
2121 	    tnf_opaque, msgimplp, msgimplp, tnf_opaque, tid, msgimplp->im_tid,
2122 	    tnf_uint, transp_op_flags, msgimplp->im_transp_op_flags);
2123 
2124 	/*
2125 	 * Do not allow reuse of a message where the receive buffers are
2126 	 * being used as send buffers if this is a sequenced transaction
2127 	 */
2128 	if ((madhdrp == msgbufp->im_bufs_mad_hdr) &&
2129 	    (msgimplp->im_transp_op_flags & IBMF_MSG_TRANS_FLAG_SEQ)) {
2130 		IBMF_MSG_DECR_REFCNT(msgimplp);
2131 		mutex_exit(&msgimplp->im_mutex);
2132 		(void) sprintf(errmsg,
2133 		    "Send and Recv buffers are the same for sequenced"
2134 		    " transaction");
2135 		error = B_TRUE;
2136 		status = IBMF_REQ_INVALID;
2137 		goto bail;
2138 	}
2139 
2140 	/* set transaction flags */
2141 	if (msgimplp->im_transp_op_flags & IBMF_MSG_TRANS_FLAG_SEQ)
2142 		msgimplp->im_flags |= IBMF_MSG_FLAGS_SEQUENCED;
2143 
2144 	if (msgimplp->im_transp_op_flags & IBMF_MSG_TRANS_FLAG_RMPP)
2145 		msgimplp->im_flags |= IBMF_MSG_FLAGS_SEND_RMPP;
2146 	else
2147 		msgimplp->im_flags |= IBMF_MSG_FLAGS_NOT_RMPP;
2148 
2149 	/* free recv buffers if this is a reused message */
2150 	if ((msgbufp->im_bufs_mad_hdr != NULL) &&
2151 	    (msgimplp->im_transp_op_flags & IBMF_MSG_TRANS_FLAG_SEQ)) {
2152 
2153 		IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_msg_transport,
2154 		    IBMF_TNF_TRACE, "", "ibmf_i_msg_transport(): %s, "
2155 		    "msgp = 0x%p, mad_hdrp = 0x%p\n", tnf_string, msg,
2156 		    "Freeing recv buffer for reused message",
2157 		    tnf_opaque, msgimplp, msgimplp,
2158 		    tnf_opaque, mad_hdr, msgbufp->im_bufs_mad_hdr);
2159 
2160 		ibmf_i_mgt_class_to_hdr_sz_off(
2161 		    msgbufp->im_bufs_mad_hdr->MgmtClass,
2162 		    &cl_hdr_sz, &cl_hdr_off);
2163 
2164 		kmem_free(msgbufp->im_bufs_mad_hdr, sizeof (ib_mad_hdr_t) +
2165 		    cl_hdr_off + msgbufp->im_bufs_cl_hdr_len +
2166 		    msgbufp->im_bufs_cl_data_len);
2167 
2168 		msgbufp->im_bufs_mad_hdr = NULL;
2169 		msgbufp->im_bufs_cl_hdr = NULL;
2170 		msgbufp->im_bufs_cl_hdr_len = 0;
2171 		msgbufp->im_bufs_cl_data = NULL;
2172 		msgbufp->im_bufs_cl_data_len = 0;
2173 	}
2174 
2175 	mutex_exit(&msgimplp->im_mutex);
2176 
2177 	/* initialize (and possibly allocate) the address handle */
2178 	status = ibmf_i_alloc_ud_dest(clientp, msgimplp,
2179 	    &msgimplp->im_ud_dest, blocking);
2180 	if (status != IBMF_SUCCESS) {
2181 		(void) sprintf(errmsg, "ibmf_i_alloc_ud_dest() failed");
2182 		error = B_TRUE;
2183 		goto bail;
2184 	}
2185 
2186 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msgimplp, *msgbufp))
2187 
2188 	/* add the message to the client context's message list */
2189 	ibmf_i_client_add_msg(clientp, msgimplp);
2190 
2191 	mutex_enter(&msgimplp->im_mutex);
2192 
2193 	/* no one should have touched our state */
2194 	ASSERT(msgimplp->im_trans_state_flags == IBMF_TRANS_STATE_FLAG_UNINIT);
2195 
2196 	/* transition out of uninit state */
2197 	msgimplp->im_trans_state_flags = IBMF_TRANS_STATE_FLAG_INIT;
2198 
2199 	IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_msg_transport,
2200 	    IBMF_TNF_TRACE, "", "ibmf_i_msg_transport(): msgp = 0x%p, "
2201 	    "local_lid = 0x%x, remote_lid = 0x%x, remote_qpn = 0x%x, "
2202 	    "block = %d\n", tnf_opaque, msgp, msgimplp,
2203 	    tnf_uint, local_lid, msgimplp->im_local_addr.ia_local_lid,
2204 	    tnf_uint, remote_lid, msgimplp->im_local_addr.ia_remote_lid,
2205 	    tnf_uint, remote_qpn, msgimplp->im_local_addr.ia_remote_qno,
2206 	    tnf_uint, blocking, blocking);
2207 
2208 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_msg_transport,
2209 	    IBMF_TNF_TRACE, "", "ibmf_i_msg_transport(): "
2210 	    "unsetting timer %p %d\n", tnf_opaque, msgimplp, msgimplp,
2211 	    tnf_opaque, timeout_id, msgimplp->im_rp_timeout_id);
2212 
2213 	ASSERT(msgimplp->im_rp_timeout_id == 0);
2214 	ASSERT(msgimplp->im_tr_timeout_id == 0);
2215 
2216 	if ((msgimplp->im_transp_op_flags & IBMF_MSG_TRANS_FLAG_RMPP) == 0) {
2217 
2218 		/* Non-RMPP transaction */
2219 
2220 		status = ibmf_i_send_single_pkt(clientp, ibmf_qp_handle,
2221 		    msgimplp, blocking);
2222 		if (status != IBMF_SUCCESS) {
2223 			IBMF_MSG_DECR_REFCNT(msgimplp);
2224 			mutex_exit(&msgimplp->im_mutex);
2225 			ibmf_i_client_rem_msg(clientp, msgimplp, &refcnt);
2226 			(void) sprintf(errmsg, "Single packet send failed");
2227 			error = B_TRUE;
2228 			goto bail;
2229 		}
2230 
2231 	} else if (msgimplp->im_transp_op_flags & IBMF_MSG_TRANS_FLAG_RMPP) {
2232 
2233 		/* RMPP transaction */
2234 
2235 		/* check if client supports RMPP traffic */
2236 		if ((clientp->ic_reg_flags & IBMF_REG_FLAG_RMPP) == 0) {
2237 			IBMF_MSG_DECR_REFCNT(msgimplp);
2238 			mutex_exit(&msgimplp->im_mutex);
2239 			ibmf_i_client_rem_msg(clientp, msgimplp, &refcnt);
2240 			(void) sprintf(errmsg, "Class does not support RMPP");
2241 			error = B_TRUE;
2242 			status = IBMF_BAD_RMPP_OPT;
2243 			goto bail;
2244 		}
2245 
2246 		/* for non-special QPs, check if QP supports RMPP traffic */
2247 		if (ibmf_qp_handle != IBMF_QP_HANDLE_DEFAULT &&
2248 		    (((ibmf_alt_qp_t *)ibmf_qp_handle)->isq_supports_rmpp ==
2249 		    B_FALSE)) {
2250 			IBMF_MSG_DECR_REFCNT(msgimplp);
2251 			mutex_exit(&msgimplp->im_mutex);
2252 			ibmf_i_client_rem_msg(clientp, msgimplp, &refcnt);
2253 			(void) sprintf(errmsg, "QP does not support RMPP");
2254 			error = B_TRUE;
2255 			status = IBMF_BAD_RMPP_OPT;
2256 			goto bail;
2257 		}
2258 
2259 		/* check if transaction is "double sided" (send and receive) */
2260 		if (msgimplp->im_transp_op_flags & IBMF_MSG_TRANS_FLAG_SEQ)
2261 			isDS = 1;
2262 
2263 		status = ibmf_i_send_rmpp_pkts(clientp, ibmf_qp_handle,
2264 		    msgimplp, isDS, blocking);
2265 		if (status != IBMF_SUCCESS) {
2266 			IBMF_MSG_DECR_REFCNT(msgimplp);
2267 			mutex_exit(&msgimplp->im_mutex);
2268 			ibmf_i_client_rem_msg(clientp, msgimplp, &refcnt);
2269 			(void) sprintf(errmsg, "RMPP packets send failed");
2270 			error = B_TRUE;
2271 			goto bail;
2272 		}
2273 	}
2274 
2275 	/*
2276 	 * decrement the reference count so notify_client() can remove the
2277 	 * message when it's ready
2278 	 */
2279 	IBMF_MSG_DECR_REFCNT(msgimplp);
2280 
2281 	/* check if the transaction is a blocking transaction */
2282 	if (blocking && ((msgimplp->im_trans_state_flags &
2283 	    IBMF_TRANS_STATE_FLAG_SIGNALED) == 0)) {
2284 
2285 		/* indicate that the tranaction is waiting */
2286 		msgimplp->im_trans_state_flags |= IBMF_TRANS_STATE_FLAG_WAIT;
2287 
2288 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_msg_transport,
2289 		    IBMF_TNF_TRACE, "",
2290 		    "ibmf_i_msg_transport(): %s, msgp = 0x%p\n",
2291 		    tnf_string, msg, "blocking for completion",
2292 		    tnf_opaque, msgimplp, msgimplp);
2293 
2294 		/* wait for transaction completion */
2295 		cv_wait(&msgimplp->im_trans_cv, &msgimplp->im_mutex);
2296 
2297 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_msg_transport,
2298 		    IBMF_TNF_TRACE, "",
2299 		    "ibmf_i_msg_transport(): %s, msgp = 0x%p\n",
2300 		    tnf_string, msg, "unblocking for completion",
2301 		    tnf_opaque, msgimplp, msgimplp);
2302 
2303 		/* clean up flags */
2304 		msgimplp->im_trans_state_flags &= ~IBMF_TRANS_STATE_FLAG_WAIT;
2305 		msgimplp->im_flags &= ~IBMF_MSG_FLAGS_BUSY;
2306 
2307 		if (msgimplp->im_msg_status != IBMF_SUCCESS) {
2308 
2309 			IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
2310 			    ibmf_i_msg_transport_err, IBMF_TNF_ERROR, "",
2311 			    "ibmf_i_msg_transport(): msg_status = %d\n",
2312 			    tnf_uint, msgstatus, msgimplp->im_msg_status);
2313 
2314 			status = msgimplp->im_msg_status;
2315 		}
2316 	} else if (blocking && (msgimplp->im_trans_state_flags &
2317 	    IBMF_TRANS_STATE_FLAG_SIGNALED)) {
2318 		msgimplp->im_flags &= ~IBMF_MSG_FLAGS_BUSY;
2319 
2320 		if (msgimplp->im_msg_status != IBMF_SUCCESS) {
2321 			IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
2322 			    ibmf_i_msg_transport_err, IBMF_TNF_ERROR, "",
2323 			    "ibmf_i_msg_transport(): msg_status = %d\n",
2324 			    tnf_uint, msgstatus, msgimplp->im_msg_status);
2325 			status = msgimplp->im_msg_status;
2326 		}
2327 	}
2328 
2329 	msg_rp_unset_id = msg_tr_unset_id = 0;
2330 	msg_rp_unset_id = msgimplp->im_rp_unset_timeout_id;
2331 	msg_tr_unset_id = msgimplp->im_tr_unset_timeout_id;
2332 	msgimplp->im_rp_unset_timeout_id = 0;
2333 	msgimplp->im_tr_unset_timeout_id = 0;
2334 
2335 	mutex_exit(&msgimplp->im_mutex);
2336 
2337 	/* Unset the timers */
2338 	if (msg_rp_unset_id != 0) {
2339 		(void) untimeout(msg_rp_unset_id);
2340 	}
2341 
2342 	if (msg_tr_unset_id != 0) {
2343 		(void) untimeout(msg_tr_unset_id);
2344 	}
2345 
2346 	/* increment kstats of the number of sent messages */
2347 	mutex_enter(&clientp->ic_kstat_mutex);
2348 	IBMF_ADD32_KSTATS(clientp, msgs_sent, 1);
2349 	mutex_exit(&clientp->ic_kstat_mutex);
2350 
2351 bail:
2352 	if (error) {
2353 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2354 		    ibmf_i_msg_transport_err, IBMF_TNF_ERROR, "",
2355 		    "ibmf_i_msg_transport(): %s, msgp = 0x%p\n",
2356 		    tnf_string, msg, errmsg, tnf_opaque, msgimplp, msgimplp);
2357 	}
2358 
2359 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,	ibmf_i_msg_transport_end,
2360 	    IBMF_TNF_TRACE, "", "ibmf_i_msg_transport() exit, status = %d\n",
2361 	    tnf_uint, status, status);
2362 
2363 	return (status);
2364 }
2365 
2366 /*
2367  * ibmf_i_init_msg():
2368  *	Initialize the message fields
2369  */
2370 void
2371 ibmf_i_init_msg(ibmf_msg_impl_t *msgimplp, ibmf_msg_cb_t trans_cb,
2372     void *trans_cb_arg, ibmf_retrans_t *retrans, boolean_t block)
2373 {
2374 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_msg_start,
2375 	    IBMF_TNF_TRACE, "", "ibmf_i_init_msg() enter\n");
2376 
2377 	_NOTE(ASSUMING_PROTECTED(msgimplp->im_trans_cb,
2378 	    msgimplp->im_trans_cb_arg))
2379 
2380 	if (block == B_TRUE)
2381 		msgimplp->im_msg_flags |= IBMF_MSG_FLAGS_BLOCKING;
2382 	msgimplp->im_trans_cb = trans_cb;
2383 	msgimplp->im_trans_cb_arg = trans_cb_arg;
2384 
2385 	if (retrans != NULL) {
2386 		bcopy((void *)retrans, (void *)&msgimplp->im_retrans,
2387 		    sizeof (ibmf_retrans_t));
2388 	}
2389 
2390 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_msg_end,
2391 	    IBMF_TNF_TRACE, "", "ibmf_i_init_msg() exit\n");
2392 }
2393 
2394 /*
2395  * ibmf_i_alloc_qp():
2396  *	Allocate a QP context for the alternate QPs
2397  */
2398 int
2399 ibmf_i_alloc_qp(ibmf_client_t *clientp, ib_pkey_t p_key, ib_qkey_t q_key,
2400     uint_t flags, ibmf_qp_handle_t *ibmf_qp_handlep)
2401 {
2402 	ibmf_ci_t		*ibmf_cip = clientp->ic_myci;
2403 	ibt_qp_alloc_attr_t	qp_attrs;
2404 	ibt_qp_info_t		qp_modify_attr;
2405 	ibmf_alt_qp_t		*qp_ctx;
2406 	uint16_t		pkey_ix;
2407 	ibt_status_t		ibt_status;
2408 	int			i, blocking;
2409 	boolean_t		error = B_FALSE;
2410 	int			status = IBMF_SUCCESS;
2411 	char			errmsg[128];
2412 
2413 
2414 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4,
2415 	    ibmf_i_alloc_qp_start, IBMF_TNF_TRACE, "",
2416 	    "ibmf_i_alloc_qp() enter, clientp = %p, pkey = %x, qkey = %x \n",
2417 	    tnf_opaque, clientp, clientp, tnf_uint, p_key, p_key,
2418 	    tnf_uint, q_key, q_key);
2419 
2420 	/*
2421 	 * get the pkey index associated with this pkey if present in table
2422 	 */
2423 	if (ibmf_i_get_pkeyix(clientp->ic_ci_handle, p_key,
2424 	    clientp->ic_client_info.port_num, &pkey_ix) != IBMF_SUCCESS) {
2425 		(void) sprintf(errmsg, "pkey not in table, pkey = %x", p_key);
2426 		error = B_TRUE;
2427 		status = IBMF_FAILURE;
2428 		goto bail;
2429 	}
2430 
2431 	/* allocate QP context memory */
2432 	qp_ctx = (ibmf_alt_qp_t *)kmem_zalloc(sizeof (ibmf_alt_qp_t),
2433 	    (flags & IBMF_ALLOC_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
2434 	if (qp_ctx == NULL) {
2435 		(void) sprintf(errmsg, "failed to kmem_zalloc qp ctx");
2436 		error = B_TRUE;
2437 		status = IBMF_NO_RESOURCES;
2438 		goto bail;
2439 	}
2440 
2441 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*qp_ctx));
2442 
2443 	/* setup the qp attrs for the alloc call */
2444 	qp_attrs.qp_scq_hdl = ibmf_cip->ci_alt_cq_handle;
2445 	qp_attrs.qp_rcq_hdl = ibmf_cip->ci_alt_cq_handle;
2446 	qp_attrs.qp_pd_hdl = ibmf_cip->ci_pd;
2447 	qp_attrs.qp_sizes.cs_sq_sgl = IBMF_MAX_SQ_WR_SGL_ELEMENTS;
2448 	qp_attrs.qp_sizes.cs_rq_sgl = IBMF_MAX_RQ_WR_SGL_ELEMENTS;
2449 	qp_attrs.qp_sizes.cs_sq = ibmf_send_wqes_posted_per_qp;
2450 	qp_attrs.qp_sizes.cs_rq = ibmf_recv_wqes_posted_per_qp;
2451 	qp_attrs.qp_flags = IBT_ALL_SIGNALED;
2452 	qp_attrs.qp_alloc_flags = IBT_QP_NO_FLAGS;
2453 
2454 	/* request IBT for a qp with the desired attributes */
2455 	ibt_status = ibt_alloc_qp(clientp->ic_ci_handle, IBT_UD_RQP,
2456 	    &qp_attrs, &qp_ctx->isq_qp_sizes, &qp_ctx->isq_qpn,
2457 	    &qp_ctx->isq_qp_handle);
2458 	if (ibt_status != IBT_SUCCESS) {
2459 		kmem_free(qp_ctx, sizeof (ibmf_alt_qp_t));
2460 		(void) sprintf(errmsg, "failed to alloc qp, status = %d",
2461 		    ibt_status);
2462 		error = B_TRUE;
2463 		status = IBMF_NO_RESOURCES;
2464 		goto bail;
2465 	}
2466 
2467 	qp_modify_attr.qp_trans = IBT_UD_SRV;
2468 	qp_modify_attr.qp_flags = IBT_CEP_NO_FLAGS;
2469 	qp_modify_attr.qp_transport.ud.ud_qkey = q_key;
2470 	qp_modify_attr.qp_transport.ud.ud_sq_psn = 0;
2471 	qp_modify_attr.qp_transport.ud.ud_pkey_ix = pkey_ix;
2472 	qp_modify_attr.qp_transport.ud.ud_port =
2473 	    clientp->ic_client_info.port_num;
2474 
2475 	/* Set up the client handle in the QP context */
2476 	qp_ctx->isq_client_hdl = clientp;
2477 
2478 	/* call the IB transport to initialize the QP */
2479 	ibt_status = ibt_initialize_qp(qp_ctx->isq_qp_handle, &qp_modify_attr);
2480 	if (ibt_status != IBT_SUCCESS) {
2481 		(void) ibt_free_qp(qp_ctx->isq_qp_handle);
2482 		kmem_free(qp_ctx, sizeof (ibmf_alt_qp_t));
2483 		(void) sprintf(errmsg, "failed to initialize qp, status = %d",
2484 		    ibt_status);
2485 		error = B_TRUE;
2486 		status = IBMF_NO_RESOURCES;
2487 		goto bail;
2488 	}
2489 
2490 	/* Set up the WQE caches */
2491 	status = ibmf_i_init_altqp_wqes(qp_ctx);
2492 	if (status != IBMF_SUCCESS) {
2493 		(void) ibt_free_qp(qp_ctx->isq_qp_handle);
2494 		kmem_free(qp_ctx, sizeof (ibmf_alt_qp_t));
2495 		(void) sprintf(errmsg, "failed to init wqe caches, status = %d",
2496 		    status);
2497 		error = B_TRUE;
2498 		goto bail;
2499 	}
2500 
2501 	qp_ctx->isq_next = NULL;
2502 	qp_ctx->isq_pkey = p_key;
2503 	qp_ctx->isq_qkey = q_key;
2504 	qp_ctx->isq_port_num = clientp->ic_client_info.port_num;
2505 	mutex_init(&qp_ctx->isq_mutex, NULL, MUTEX_DRIVER, NULL);
2506 	mutex_init(&qp_ctx->isq_wqe_mutex, NULL, MUTEX_DRIVER, NULL);
2507 	cv_init(&qp_ctx->isq_recv_cb_teardown_cv, NULL, CV_DRIVER, NULL);
2508 	cv_init(&qp_ctx->isq_sqd_cv, NULL, CV_DRIVER, NULL);
2509 	cv_init(&qp_ctx->isq_wqes_cv, NULL, CV_DRIVER, NULL);
2510 
2511 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*qp_ctx));
2512 
2513 	/* add alt qp to the list in CI context */
2514 	mutex_enter(&ibmf_cip->ci_mutex);
2515 	if (ibmf_cip->ci_alt_qp_list == NULL) {
2516 		ibmf_cip->ci_alt_qp_list = qp_ctx;
2517 	} else {
2518 		ibmf_alt_qp_t *qpp;
2519 
2520 		qpp = ibmf_cip->ci_alt_qp_list;
2521 		while (qpp->isq_next != NULL) {
2522 			qpp = qpp->isq_next;
2523 		}
2524 		qpp->isq_next = qp_ctx;
2525 	}
2526 	mutex_exit(&ibmf_cip->ci_mutex);
2527 
2528 	*ibmf_qp_handlep = (ibmf_qp_handle_t)qp_ctx;
2529 
2530 	if (flags & IBMF_ALLOC_SLEEP)
2531 		blocking = 1;
2532 	else
2533 		blocking = 0;
2534 
2535 	/* post the max number of buffers to RQ */
2536 	for (i = 0; i < ibmf_recv_wqes_per_port; i++) {
2537 		status = ibmf_i_post_recv_buffer(ibmf_cip, clientp->ic_qp,
2538 		    blocking, *ibmf_qp_handlep);
2539 		if (status != IBMF_SUCCESS) {
2540 			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
2541 			    ibmf_i_alloc_qp, IBMF_TNF_TRACE, "",
2542 			    "ibmf_i_alloc_qp(): %s, status = %d\n",
2543 			    tnf_string, msg, "ibmf_i_post_recv_buffer() failed",
2544 			    tnf_int, status, status);
2545 		}
2546 	}
2547 
2548 	mutex_enter(&clientp->ic_kstat_mutex);
2549 	IBMF_ADD32_KSTATS(clientp, alt_qps_alloced, 1);
2550 	mutex_exit(&clientp->ic_kstat_mutex);
2551 
2552 bail:
2553 	if (error) {
2554 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
2555 		    ibmf_i_alloc_qp_err, IBMF_TNF_TRACE, "",
2556 		    "ibmf_i_alloc_qp(): %s\n", tnf_string, msg, errmsg);
2557 	}
2558 
2559 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_alloc_qp_end,
2560 	    IBMF_TNF_TRACE, "", "ibmf_i_alloc_qp() exit, qp = %p\n",
2561 	    tnf_opaque, qp_handlep, *ibmf_qp_handlep);
2562 	return (status);
2563 }
2564 
2565 /*
2566  * ibmf_i_free_qp():
2567  *	Free an alternate QP context
2568  */
2569 /* ARGSUSED */
2570 int
2571 ibmf_i_free_qp(ibmf_qp_handle_t ibmf_qp_handle, uint_t flags)
2572 {
2573 	ibmf_alt_qp_t		*qp_ctx = (ibmf_alt_qp_t *)ibmf_qp_handle;
2574 	ibmf_client_t		*clientp = qp_ctx->isq_client_hdl;
2575 	ibmf_ci_t		*ibmf_cip = qp_ctx->isq_client_hdl->ic_myci;
2576 	ibmf_alt_qp_t		*qpp, *pqpp;
2577 	ibt_status_t		ibt_status;
2578 
2579 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
2580 	    ibmf_i_free_qp_start, IBMF_TNF_TRACE, "",
2581 	    "ibmf_i_free_qp() enter, qp_hdl = %p, flags = %x\n",
2582 	    tnf_opaque, qp_hdl, ibmf_qp_handle, tnf_uint, flags, flags);
2583 
2584 	/* remove qp from the list in CI context */
2585 
2586 	mutex_enter(&ibmf_cip->ci_mutex);
2587 	qpp = ibmf_cip->ci_alt_qp_list;
2588 	ASSERT(qpp != NULL);
2589 	if (qpp == qp_ctx) {
2590 		ibmf_cip->ci_alt_qp_list = qpp->isq_next;
2591 	} else {
2592 		while (qpp != NULL) {
2593 			if (qpp == qp_ctx)
2594 				break;
2595 			pqpp = qpp;
2596 			qpp = qpp->isq_next;
2597 		}
2598 		ASSERT(qpp != NULL);
2599 		pqpp->isq_next = qpp->isq_next;
2600 	}
2601 
2602 	mutex_exit(&ibmf_cip->ci_mutex);
2603 
2604 	/* flush the WQEs in the QP queues */
2605 	ibt_status = ibt_flush_qp(qp_ctx->isq_qp_handle);
2606 	if (ibt_status != IBT_SUCCESS) {
2607 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2608 		    ibmf_i_free_qp_err, IBMF_TNF_TRACE, "",
2609 		    "ibmf_i_free_qp(): %s, status = %d\n",
2610 		    tnf_string, msg, "failed to close qp",
2611 		    tnf_uint, ibt_status, ibt_status);
2612 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_free_qp_end,
2613 		    IBMF_TNF_TRACE, "", "ibmf_i_free_qp() exit\n");
2614 		return (IBMF_TRANSPORT_FAILURE);
2615 	}
2616 
2617 	/* Call the MAD completion handler */
2618 	ibmf_i_mad_completions(ibmf_cip->ci_alt_cq_handle, (void*)ibmf_cip);
2619 
2620 	/* Wait here for all WQE owned by this QP to get freed */
2621 	mutex_enter(&qpp->isq_mutex);
2622 	while (qpp->isq_wqes_alloced != 0) {
2623 		cv_wait(&qpp->isq_wqes_cv, &qpp->isq_mutex);
2624 	}
2625 	mutex_exit(&qpp->isq_mutex);
2626 
2627 	cv_destroy(&qp_ctx->isq_recv_cb_teardown_cv);
2628 	cv_destroy(&qp_ctx->isq_sqd_cv);
2629 	cv_destroy(&qp_ctx->isq_wqes_cv);
2630 
2631 	/* call the IB transport to free the QP */
2632 	ibt_status = ibt_free_qp(qp_ctx->isq_qp_handle);
2633 	if (ibt_status != IBT_SUCCESS) {
2634 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2635 		    ibmf_i_free_qp_err, IBMF_TNF_TRACE, "",
2636 		    "ibmf_i_free_qp(): %s, status = %d\n",
2637 		    tnf_string, msg, "failed to free qp",
2638 		    tnf_uint, ibt_status, ibt_status);
2639 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_free_qp_end,
2640 		    IBMF_TNF_TRACE, "", "ibmf_i_free_qp() exit\n");
2641 		return (IBMF_TRANSPORT_FAILURE);
2642 	}
2643 
2644 	/* Clean up the WQE caches */
2645 	ibmf_i_fini_altqp_wqes(qp_ctx);
2646 	mutex_destroy(&qp_ctx->isq_wqe_mutex);
2647 	mutex_destroy(&qp_ctx->isq_mutex);
2648 
2649 	mutex_enter(&clientp->ic_kstat_mutex);
2650 	IBMF_SUB32_KSTATS(clientp, alt_qps_alloced, 1);
2651 	mutex_exit(&clientp->ic_kstat_mutex);
2652 
2653 	kmem_free(qp_ctx, sizeof (ibmf_alt_qp_t));
2654 
2655 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_free_qp_end,
2656 	    IBMF_TNF_TRACE, "", "ibmf_i_free_qp() exit\n");
2657 
2658 	return (IBMF_SUCCESS);
2659 }
2660 
2661 /*
2662  * ibmf_i_query_qp():
2663  *	Query an alternate QP context
2664  */
2665 /* ARGSUSED */
2666 int
2667 ibmf_i_query_qp(ibmf_qp_handle_t ibmf_qp_handle, uint_t flags,
2668     uint_t *qp_nump, ib_pkey_t *p_keyp, ib_qkey_t *q_keyp, uint8_t *portnump)
2669 {
2670 	ibt_qp_query_attr_t	qp_query;
2671 	ibmf_alt_qp_t		*qp_ctx = (ibmf_alt_qp_t *)ibmf_qp_handle;
2672 	uint16_t		pkey_ix;
2673 	ibt_status_t		ibt_status;
2674 
2675 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
2676 	    ibmf_i_free_qp_start, IBMF_TNF_TRACE, "",
2677 	    "ibmf_i_free_qp() enter, qp_hdl = %p, flags = %x\n",
2678 	    tnf_opaque, qp_hdl, ibmf_qp_handle, tnf_uint, flags, flags);
2679 
2680 	ibt_status = ibt_query_qp(qp_ctx->isq_qp_handle, &qp_query);
2681 	if (ibt_status != IBT_SUCCESS) {
2682 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2683 		    ibmf_i_query_qp_err, IBMF_TNF_TRACE, "",
2684 		    "ibmf_i_query_qp(): %s, status = %d\n",
2685 		    tnf_string, msg, "failed to query qp",
2686 		    tnf_uint, ibt_status, ibt_status);
2687 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_query_qp_end,
2688 		    IBMF_TNF_TRACE, "", "ibmf_i_query_qp() exit\n");
2689 		return (IBMF_TRANSPORT_FAILURE);
2690 	}
2691 
2692 	/* move the desired attributes into the locations provided */
2693 	*qp_nump = qp_query.qp_qpn;
2694 	*q_keyp = qp_query.qp_info.qp_transport.ud.ud_qkey;
2695 	*portnump = qp_query.qp_info.qp_transport.ud.ud_port;
2696 
2697 	pkey_ix = qp_query.qp_info.qp_transport.ud.ud_pkey_ix;
2698 
2699 	/* get the pkey based on the pkey_ix */
2700 	ibt_status = ibt_index2pkey(qp_ctx->isq_client_hdl->ic_ci_handle,
2701 	    *portnump, pkey_ix, p_keyp);
2702 	if (ibt_status != IBT_SUCCESS) {
2703 		IBMF_TRACE_3(IBMF_TNF_NODEBUG, DPRINT_L1,
2704 		    ibmf_i_query_qp_err, IBMF_TNF_TRACE, "",
2705 		    "ibmf_i_query_qp(): %s, pkey_ix = %d, status = %d\n",
2706 		    tnf_string, msg, "failed to get pkey from index",
2707 		    tnf_uint, pkey_ix, pkey_ix,
2708 		    tnf_uint, ibt_status, ibt_status);
2709 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_query_qp_end,
2710 		    IBMF_TNF_TRACE, "", "ibmf_i_query_qp() exit\n");
2711 		return (IBMF_TRANSPORT_FAILURE);
2712 	}
2713 
2714 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_query_qp_end,
2715 	    IBMF_TNF_TRACE, "", "ibmf_i_query_qp() exit, qp_num = 0x%x, "
2716 	    "pkey = 0x%x, qkey = 0x%x, portnum = %d\n",
2717 	    tnf_uint, qp_num, *qp_nump, tnf_uint, pkey, *p_keyp,
2718 	    tnf_uint, qkey, *q_keyp, tnf_uint, portnum, *portnump);
2719 
2720 	return (IBMF_SUCCESS);
2721 }
2722 
2723 /*
2724  * ibmf_i_modify_qp():
2725  *	Modify an alternate QP context
2726  */
2727 /* ARGSUSED */
2728 int
2729 ibmf_i_modify_qp(ibmf_qp_handle_t ibmf_qp_handle, ib_pkey_t p_key,
2730     ib_qkey_t q_key, uint_t flags)
2731 {
2732 	ibmf_alt_qp_t		*qp_ctx = (ibmf_alt_qp_t *)ibmf_qp_handle;
2733 	ibmf_client_t		*clientp = qp_ctx->isq_client_hdl;
2734 	ibmf_ci_t		*ibmf_cip = clientp->ic_myci;
2735 	ibmf_alt_qp_t		*qpp;
2736 	ibt_qp_info_t		qp_mod;
2737 	ibt_cep_modify_flags_t	qp_mod_flags;
2738 	ibt_queue_sizes_t	actual_sz;
2739 	uint16_t		pkey_ix;
2740 	ibt_status_t		ibt_status;
2741 
2742 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4,
2743 	    ibmf_i_modify_qp_start, IBMF_TNF_TRACE, "",
2744 	    "ibmf_i_modify_qp() enter, qp_hdl = %p, flags = %x, pkey = 0x%x, "
2745 	    "qkey = 0x%x\n", tnf_opaque, qp_hdl, ibmf_qp_handle,
2746 	    tnf_uint, flags, flags, tnf_uint, p_key, p_key,
2747 	    tnf_uint, q_key, q_key);
2748 
2749 	/*
2750 	 * get the pkey index associated with this pkey if present in table
2751 	 */
2752 	if (ibmf_i_get_pkeyix(clientp->ic_ci_handle, p_key,
2753 	    clientp->ic_client_info.port_num, &pkey_ix) != IBMF_SUCCESS) {
2754 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2755 		    ibmf_i_modify_qp_err, IBMF_TNF_TRACE, "",
2756 		    "ibmf_i_modify_qp(): %s, pkey = %x\n",
2757 		    tnf_string, msg, "pkey not in table",
2758 		    tnf_uint, pkey, p_key);
2759 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_modify_qp_end,
2760 		    IBMF_TNF_TRACE, "", "ibmf_i_modify_qp() exit\n");
2761 		return (IBMF_FAILURE);
2762 	}
2763 
2764 	/* Find the QP context in the CI QP context list */
2765 	mutex_enter(&ibmf_cip->ci_mutex);
2766 	qpp = ibmf_cip->ci_alt_qp_list;
2767 	while (qpp != NULL) {
2768 		if (qpp == qp_ctx) {
2769 			break;
2770 		}
2771 		qpp = qpp->isq_next;
2772 	}
2773 
2774 	if (qpp == NULL) {
2775 		mutex_exit(&ibmf_cip->ci_mutex);
2776 
2777 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
2778 		    ibmf_i_modify_qp_err, IBMF_TNF_TRACE, "",
2779 		    "ibmf_i_modify_qp(): %s\n",
2780 		    tnf_string, msg, "QP not in altqp list");
2781 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_modify_qp_end,
2782 		    IBMF_TNF_TRACE, "", "ibmf_i_modify_qp() exit\n");
2783 		return (IBMF_BAD_QP_HANDLE);
2784 
2785 	} else {
2786 
2787 		mutex_enter(&qp_ctx->isq_mutex);
2788 	}
2789 
2790 	mutex_exit(&ibmf_cip->ci_mutex);
2791 
2792 	/*
2793 	 * Transition the QP to SQD state
2794 	 */
2795 	bzero(&qp_mod, sizeof (ibt_qp_info_t));
2796 	qp_mod.qp_trans = IBT_UD_SRV;
2797 	qp_mod.qp_state = IBT_STATE_SQD;
2798 	qp_mod_flags = IBT_CEP_SET_STATE | IBT_CEP_SET_SQD_EVENT;
2799 	ibt_status = ibt_modify_qp(qp_ctx->isq_qp_handle, qp_mod_flags,
2800 	    &qp_mod, &actual_sz);
2801 	if (ibt_status != IBT_SUCCESS) {
2802 		mutex_exit(&qp_ctx->isq_mutex);
2803 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2804 		    ibmf_i_modify_qp_err, IBMF_TNF_TRACE, "",
2805 		    "ibmf_i_modify_qp(): %s, qp_hdl = %p\n",
2806 		    tnf_string, msg, "QP transition RTS to SQD failed",
2807 		    tnf_opaque, qp_handle, qp_ctx->isq_qp_handle);
2808 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_modify_qp_end,
2809 		    IBMF_TNF_TRACE, "", "ibmf_i_modify_qp() exit\n");
2810 		return (IBMF_TRANSPORT_FAILURE);
2811 	}
2812 
2813 	/*
2814 	 * Wait for an event indicating that the QP is in SQD state
2815 	 */
2816 	cv_wait(&qp_ctx->isq_sqd_cv, &qp_ctx->isq_mutex);
2817 
2818 	/* Setup QP modification information for transition to RTS state */
2819 	bzero(&qp_mod, sizeof (ibt_qp_info_t));
2820 	qp_mod.qp_trans = IBT_UD_SRV;
2821 	qp_mod.qp_state = IBT_STATE_RTS;
2822 	qp_mod.qp_current_state = IBT_STATE_SQD;
2823 	qp_mod.qp_transport.ud.ud_pkey_ix = pkey_ix;
2824 	qp_mod.qp_transport.ud.ud_qkey = q_key;
2825 	qp_mod_flags = IBT_CEP_SET_STATE | IBT_CEP_SET_PKEY_IX |
2826 	    IBT_CEP_SET_QKEY;
2827 
2828 	/*
2829 	 * transition the QP back to RTS state to allow
2830 	 * modification of the pkey and qkey
2831 	 */
2832 
2833 	ibt_status = ibt_modify_qp(qp_ctx->isq_qp_handle, qp_mod_flags,
2834 	    &qp_mod, &actual_sz);
2835 	if (ibt_status != IBT_SUCCESS) {
2836 		mutex_exit(&qp_ctx->isq_mutex);
2837 		IBMF_TRACE_3(IBMF_TNF_NODEBUG, DPRINT_L1,
2838 		    ibmf_i_modify_qp_err, IBMF_TNF_TRACE, "",
2839 		    "ibmf_i_modify_qp(): %s, qp_hdl = %p, status = %d\n",
2840 		    tnf_string, msg, "QP transition SQD to RTS failed",
2841 		    tnf_opaque, qp_handle, qp_ctx->isq_qp_handle,
2842 		    tnf_uint, ibt_status, ibt_status);
2843 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_modify_qp_end,
2844 		    IBMF_TNF_TRACE, "", "ibmf_i_modify_qp() exit\n");
2845 		return (IBMF_TRANSPORT_FAILURE);
2846 	}
2847 
2848 	qp_ctx->isq_pkey = p_key;
2849 	qp_ctx->isq_qkey = q_key;
2850 	mutex_exit(&qp_ctx->isq_mutex);
2851 
2852 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_modify_qp_end,
2853 	    IBMF_TNF_TRACE, "", "ibmf_i_modify_qp() exit\n");
2854 	return (IBMF_SUCCESS);
2855 }
2856 
2857 /*
2858  * ibmf_i_post_recv_buffer():
2859  *	Post a WQE to the RQ of the specified QP
2860  */
2861 int
2862 ibmf_i_post_recv_buffer(ibmf_ci_t *cip, ibmf_qp_t *qpp, boolean_t block,
2863     ibmf_qp_handle_t ibmf_qp_handle)
2864 {
2865 	int			ret;
2866 	ibt_wr_ds_t		*sgl;
2867 	ibt_status_t		status;
2868 	ibmf_recv_wqe_t		*recv_wqep;
2869 	ibt_qp_hdl_t		ibt_qp_handle;
2870 	struct kmem_cache	*kmem_cachep;
2871 	ibmf_alt_qp_t		*altqp;
2872 
2873 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4,
2874 	    ibmf_i_post_recv_buffer_start, IBMF_TNF_TRACE, "",
2875 	    "ibmf_i_post_recv_buffer() enter, cip = %p, qpp = %p, "
2876 	    "qp_hdl = %p, block = %d\n", tnf_opaque, cip, cip,
2877 	    tnf_opaque, qpp, qpp, tnf_opaque, qp_hdl, ibmf_qp_handle,
2878 	    tnf_uint, block, block);
2879 
2880 	/*
2881 	 * if we haven't hit the max wqes per qp, attempt to allocate a recv
2882 	 * wqe and post it to the recv queue.
2883 	 * It is possible for more than one thread to get through this
2884 	 * check below and post wqes that could push us above the
2885 	 * ibmf_recv_wqes_posted_per_qp. We catch that case when the recv
2886 	 * completion is signaled.
2887 	 */
2888 	ASSERT(MUTEX_NOT_HELD(&cip->ci_mutex));
2889 
2890 	/* Get the WQE kmem cache pointer based on the QP type */
2891 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT)
2892 		kmem_cachep = cip->ci_recv_wqes_cache;
2893 	else {
2894 		altqp = (ibmf_alt_qp_t *)ibmf_qp_handle;
2895 		kmem_cachep = altqp->isq_recv_wqes_cache;
2896 	}
2897 
2898 	/* allocate a receive WQE from the receive WQE kmem cache */
2899 	recv_wqep = kmem_cache_alloc(kmem_cachep,
2900 	    (block == B_TRUE ? KM_SLEEP : KM_NOSLEEP));
2901 	if (recv_wqep == NULL) {
2902 		/*
2903 		 * Attempt to extend the cache and then retry the
2904 		 * kmem_cache_alloc()
2905 		 */
2906 		if (ibmf_i_extend_wqe_cache(cip, ibmf_qp_handle, block) ==
2907 		    IBMF_NO_RESOURCES) {
2908 			mutex_enter(&cip->ci_mutex);
2909 			IBMF_ADD32_PORT_KSTATS(cip, rwqe_allocs_failed, 1);
2910 			mutex_exit(&cip->ci_mutex);
2911 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2912 			    ibmf_i_post_recv_buffer_err, IBMF_TNF_ERROR, "",
2913 			    "ibmf_i_post_recv_buffer(): %s, status = %d\n",
2914 			    tnf_string, msg, "alloc recv_wqe failed",
2915 			    tnf_int, ibmf_status, IBMF_NO_RESOURCES);
2916 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
2917 			    ibmf_i_post_recv_buffer_end, IBMF_TNF_TRACE, "",
2918 			    "ibmf_i_post_recv_buffer() exit\n");
2919 			return (IBMF_NO_RESOURCES);
2920 		} else {
2921 			recv_wqep = kmem_cache_alloc(kmem_cachep,
2922 			    (block == B_TRUE ? KM_SLEEP : KM_NOSLEEP));
2923 			if (recv_wqep == NULL) {
2924 				/* Allocation failed again. Give up here. */
2925 				mutex_enter(&cip->ci_mutex);
2926 				IBMF_ADD32_PORT_KSTATS(cip, rwqe_allocs_failed,
2927 				    1);
2928 				mutex_exit(&cip->ci_mutex);
2929 				IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2930 				    ibmf_i_post_recv_buffer_err,
2931 				    IBMF_TNF_ERROR, "",
2932 				    "ibmf_i_post_recv_buffer(): %s, "
2933 				    "status = %d\n",
2934 				    tnf_string, msg, "alloc recv_wqe failed",
2935 				    tnf_int, ibmf_status, IBMF_NO_RESOURCES);
2936 				IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
2937 				    ibmf_i_post_recv_buffer_end,
2938 				    IBMF_TNF_TRACE, "",
2939 				    "ibmf_i_post_recv_buffer() exit\n");
2940 				return (IBMF_NO_RESOURCES);
2941 			}
2942 		}
2943 	}
2944 
2945 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*recv_wqep))
2946 
2947 	/*
2948 	 * if the qp handle provided in ibmf_send_pkt() or
2949 	 * ibmf_setup_recv_cb() is not the default qp handle
2950 	 * for this client, then the wqe must be queued on this qp,
2951 	 * else use the default qp handle set up during ibmf_register()
2952 	 */
2953 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
2954 		ibt_qp_handle = qpp->iq_qp_handle;
2955 	} else {
2956 		ibt_qp_handle =
2957 		    ((ibmf_alt_qp_t *)ibmf_qp_handle)->isq_qp_handle;
2958 	}
2959 
2960 	/* allocate memory for the scatter-gather list */
2961 	sgl = kmem_zalloc(IBMF_MAX_RQ_WR_SGL_ELEMENTS * sizeof (ibt_wr_ds_t),
2962 	    (block == B_TRUE) ? KM_SLEEP : KM_NOSLEEP);
2963 	if (sgl == NULL) {
2964 		kmem_cache_free(kmem_cachep, recv_wqep);
2965 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
2966 		    ibmf_i_post_recv_buffer_err, IBMF_TNF_ERROR, "",
2967 		    "ibmf_i_post_recv_buffer(): %s\n",
2968 		    tnf_string, msg, "failed to kmem_zalloc qp ctx");
2969 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
2970 		    ibmf_i_post_recv_buffer_end, IBMF_TNF_TRACE, "",
2971 		    "ibmf_i_post_recv_buffer() exit\n");
2972 		return (IBMF_NO_RESOURCES);
2973 	}
2974 
2975 	/* initialize it */
2976 	ibmf_i_init_recv_wqe(qpp, sgl, recv_wqep, ibt_qp_handle,
2977 	    ibmf_qp_handle);
2978 
2979 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*recv_wqep))
2980 
2981 	/* and post it */
2982 	status = ibt_post_recv(recv_wqep->recv_qp_handle, &recv_wqep->recv_wr,
2983 	    1, NULL);
2984 
2985 	ret = ibmf_i_ibt_to_ibmf_status(status);
2986 	if (ret != IBMF_SUCCESS) {
2987 		kmem_free(sgl, IBMF_MAX_RQ_WR_SGL_ELEMENTS *
2988 		    sizeof (ibt_wr_ds_t));
2989 		kmem_cache_free(kmem_cachep, recv_wqep);
2990 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2991 		    ibmf_i_post_recv_buffer_err, IBMF_TNF_ERROR, "",
2992 		    "ibmf_i_post_recv_buffer(): %s, status = %d\n",
2993 		    tnf_string, msg, "ibt_post_recv failed",
2994 		    tnf_uint, ibt_status, status);
2995 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
2996 		    ibmf_i_post_recv_buffer_end, IBMF_TNF_TRACE, "",
2997 		    "ibmf_i_post_recv_buffer() exit\n");
2998 		return (ret);
2999 	}
3000 
3001 	mutex_enter(&cip->ci_mutex);
3002 	IBMF_ADD32_PORT_KSTATS(cip, recv_wqes_alloced, 1);
3003 	mutex_exit(&cip->ci_mutex);
3004 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
3005 		mutex_enter(&qpp->iq_mutex);
3006 		qpp->iq_rwqes_posted++;
3007 		mutex_exit(&qpp->iq_mutex);
3008 		mutex_enter(&cip->ci_mutex);
3009 		cip->ci_wqes_alloced++;
3010 		mutex_exit(&cip->ci_mutex);
3011 	} else {
3012 		mutex_enter(&altqp->isq_mutex);
3013 		altqp->isq_wqes_alloced++;
3014 		altqp->isq_rwqes_posted++;
3015 		mutex_exit(&altqp->isq_mutex);
3016 	}
3017 
3018 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_post_recv_buffer_end,
3019 	    IBMF_TNF_TRACE, "", "ibmf_i_post_recv_buffer() exit\n");
3020 
3021 	return (ret);
3022 }
3023 
3024 /*
3025  * ibmf_i_mgt_class_to_hdr_sz_off():
3026  *	Determine class header offser and size for management classes
3027  */
3028 void
3029 ibmf_i_mgt_class_to_hdr_sz_off(uint32_t mgt_class, uint32_t *szp,
3030     uint32_t *offp)
3031 {
3032 	uint32_t	hdr_sz = 0, hdr_off = 0;
3033 
3034 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
3035 	    ibmf_i_mgt_class_to_hdr_sz_off_start, IBMF_TNF_TRACE, "",
3036 	    "ibmf_i_mgt_class_to_hdr_sz_off(): mgt_class = 0x%x\n",
3037 	    tnf_uint, mgt_class, mgt_class);
3038 
3039 	switch (mgt_class) {
3040 	case MAD_MGMT_CLASS_SUBN_LID_ROUTED :
3041 	case MAD_MGMT_CLASS_SUBN_DIRECT_ROUTE :
3042 	case MAD_MGMT_CLASS_PERF :
3043 	case MAD_MGMT_CLASS_BM :
3044 	case MAD_MGMT_CLASS_DEV_MGT :
3045 	case MAD_MGMT_CLASS_SNMP :
3046 		hdr_sz = IBMF_MAD_CL_HDR_SZ_1;
3047 		hdr_off = IBMF_MAD_CL_HDR_OFF_1;
3048 		break;
3049 	case MAD_MGMT_CLASS_SUBN_ADM :
3050 		hdr_sz = IBMF_MAD_CL_HDR_SZ_2;
3051 		hdr_off = IBMF_MAD_CL_HDR_OFF_2;
3052 		break;
3053 	}
3054 
3055 	if (((mgt_class >= MAD_MGMT_CLASS_VENDOR_START) &&
3056 	    (mgt_class <= MAD_MGMT_CLASS_VENDOR_END)) ||
3057 	    ((mgt_class >= MAD_MGMT_CLASS_APPLICATION_START) &&
3058 	    (mgt_class <= MAD_MGMT_CLASS_APPLICATION_END))) {
3059 		hdr_sz = IBMF_MAD_CL_HDR_SZ_3;
3060 		hdr_off = IBMF_MAD_CL_HDR_OFF_1;
3061 	}
3062 
3063 	if ((mgt_class >= MAD_MGMT_CLASS_VENDOR2_START) &&
3064 	    (mgt_class <= MAD_MGMT_CLASS_VENDOR2_END)) {
3065 		hdr_sz = IBMF_MAD_CL_HDR_SZ_4;
3066 		hdr_off = IBMF_MAD_CL_HDR_OFF_2;
3067 	}
3068 
3069 	*szp = hdr_sz;
3070 	*offp = hdr_off;
3071 
3072 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
3073 	    ibmf_i_mgt_class_to_hdr_sz_off_end, IBMF_TNF_TRACE, "",
3074 	    "ibmf_i_mgt_class_to_hdr_sz_off() exit,hdr_sz = %d, hdr_off = %d\n",
3075 	    tnf_uint, hdr_sz, hdr_sz, tnf_uint, hdr_off, hdr_off);
3076 }
3077 
3078 /*
3079  * ibmf_i_lookup_client_by_mgmt_class():
3080  *	Lookup the client context based on the management class of
3081  *	the incoming packet
3082  */
3083 int
3084 ibmf_i_lookup_client_by_mgmt_class(ibmf_ci_t *ibmf_cip, int port_num,
3085     ibmf_client_type_t class, ibmf_client_t **clientpp)
3086 {
3087 	ibmf_client_t 		*clientp;
3088 	ibmf_client_info_t	*client_infop;
3089 
3090 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4,
3091 	    ibmf_i_lookup_client_by_mgmt_class_start, IBMF_TNF_TRACE, "",
3092 	    "ibmf_i_lookup_client_by_mgmt_class() enter, cip = %p, "
3093 	    "port_num = %d, class = 0x%x\n", tnf_opaque, cip, ibmf_cip,
3094 	    tnf_int, port, port_num, tnf_opaque, class, class);
3095 
3096 	ASSERT(MUTEX_NOT_HELD(&ibmf_cip->ci_clients_mutex));
3097 
3098 	mutex_enter(&ibmf_cip->ci_clients_mutex);
3099 
3100 	clientp = ibmf_cip->ci_clients;
3101 
3102 	/* walk client context list looking for class/portnum match */
3103 	while (clientp != NULL) {
3104 		client_infop = &clientp->ic_client_info;
3105 		if (class == client_infop->client_class &&
3106 		    port_num == client_infop->port_num) {
3107 			/* found our match */
3108 			break;
3109 		}
3110 		clientp = clientp->ic_next;
3111 	}
3112 
3113 	mutex_exit(&ibmf_cip->ci_clients_mutex);
3114 
3115 	if (clientp != NULL) {
3116 		*clientpp = clientp;
3117 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
3118 		    ibmf_i_lookup_client_by_mgmt_class_end, IBMF_TNF_TRACE, "",
3119 		    "ibmf_i_lookup_client_by_mgmt_class() exit, clp = %p\n",
3120 		    tnf_opaque, clientp, clientp);
3121 		return (IBMF_SUCCESS);
3122 	} else {
3123 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3124 		    ibmf_i_lookup_client_by_mgmt_class_end, IBMF_TNF_TRACE, "",
3125 		    "ibmf_i_lookup_client_by_mgmt_class() failure exit\n");
3126 		return (IBMF_FAILURE);
3127 	}
3128 }
3129 
3130 /*
3131  * ibmf_i_get_pkeyix():
3132  *	Get the pkey index of the pkey in the pkey table of the specified
3133  *	port. Take into account the partition membership.
3134  */
3135 int
3136 ibmf_i_get_pkeyix(ibt_hca_hdl_t hca_handle, ib_pkey_t pkey, uint8_t port,
3137     ib_pkey_t *pkeyixp)
3138 {
3139 	ib_pkey_t		tpkey;
3140 	ibt_status_t		ibt_status;
3141 
3142 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_get_pkeyix_start,
3143 	    IBMF_TNF_TRACE, "", "ibmf_i_get_pkeyix() enter, hcahdl = %p, "
3144 	    "pkey = 0x%x, port = %d\n", tnf_opaque, hcahdl, hca_handle,
3145 	    tnf_int, pkey, pkey, tnf_int, port, port);
3146 
3147 	/*
3148 	 * If the client specifies the FULL membership pkey and the
3149 	 * pkey is not in the table, this function should fail.
3150 	 */
3151 	if (pkey & IBMF_PKEY_MEMBERSHIP_MASK) {
3152 		ibt_status = ibt_pkey2index(hca_handle, port,
3153 		    pkey, pkeyixp);
3154 		if (ibt_status != IBT_SUCCESS) {
3155 			IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
3156 			    ibmf_i_get_pkeyix_err, IBMF_TNF_ERROR, "",
3157 			    "ibmf_i_get_pkeyix() error status = %d\n",
3158 			    tnf_uint, ibt_status, ibt_status);
3159 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3160 			    ibmf_i_get_pkeyix_end, IBMF_TNF_TRACE, "",
3161 			    "ibmf_i_get_pkeyix() exit\n");
3162 			return (IBMF_TRANSPORT_FAILURE);
3163 		}
3164 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_get_pkeyix_end,
3165 		    IBMF_TNF_TRACE, "", "ibmf_i_get_pkeyix() exit\n");
3166 		return (IBMF_SUCCESS);
3167 	}
3168 
3169 	/*
3170 	 * Limited member pkey processing
3171 	 * Check if this limited member pkey is in the pkey table
3172 	 */
3173 	ibt_status = ibt_pkey2index(hca_handle, port, pkey, pkeyixp);
3174 	if (ibt_status == IBT_SUCCESS) {
3175 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3176 		    ibmf_i_get_pkeyix_end, IBMF_TNF_TRACE, "",
3177 		    "ibmf_i_get_pkeyix() exit\n");
3178 		return (IBMF_SUCCESS);
3179 	}
3180 
3181 	/*
3182 	 * Could not find the limited member version of the pkey.
3183 	 * Now check if the full member version of the pkey is in the
3184 	 * pkey table. If not, fail the call.
3185 	 */
3186 	tpkey = pkey | IBMF_PKEY_MEMBERSHIP_MASK;
3187 	ibt_status = ibt_pkey2index(hca_handle, port, tpkey, pkeyixp);
3188 	if (ibt_status != IBT_SUCCESS) {
3189 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
3190 		    ibmf_i_get_pkeyix_err, IBMF_TNF_ERROR, "",
3191 		    "ibmf_i_get_pkeyix() error status = %d\n",
3192 		    tnf_uint, ibt_status, ibt_status);
3193 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3194 		    ibmf_i_get_pkeyix_end, IBMF_TNF_TRACE, "",
3195 		    "ibmf_i_get_pkeyix() exit\n");
3196 		return (IBMF_TRANSPORT_FAILURE);
3197 	}
3198 
3199 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_get_pkeyix_end,
3200 	    IBMF_TNF_TRACE, "", "ibmf_i_get_pkeyix(): pkey_ix = %d\n",
3201 	    tnf_int, pkeyix, *pkeyixp);
3202 	return (IBMF_SUCCESS);
3203 }
3204 
3205 /*
3206  * ibmf_i_pkey_ix_to_key():
3207  *	Figure out pkey from pkey index
3208  */
3209 int
3210 ibmf_i_pkey_ix_to_key(ibmf_ci_t *cip, uint_t port_num, uint_t pkey_ix,
3211     ib_pkey_t *pkeyp)
3212 {
3213 	ibt_status_t		ibt_status;
3214 
3215 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_pkey_ix_to_key_start,
3216 	    IBMF_TNF_TRACE, "", "ibmf_i_pkey_ix_to_key() enter\n");
3217 
3218 	ibt_status = ibt_index2pkey(cip->ci_ci_handle, port_num, pkey_ix,
3219 	    pkeyp);
3220 	if (ibt_status != IBT_SUCCESS) {
3221 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
3222 		    ibmf_i_pkey_ix_to_key, IBMF_TNF_TRACE, "",
3223 		    "ibmf_i_pkey_ix_to_key(): ibt_index2pkey failed for "
3224 		    " pkey index %d \n", tnf_uint, pkey_ix, pkey_ix);
3225 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3226 		    ibmf_i_pkey_ix_to_key_end,
3227 		    IBMF_TNF_TRACE, "", "ibmf_i_pkey_ix_to_key() exit\n");
3228 		return (IBMF_TRANSPORT_FAILURE);
3229 	}
3230 
3231 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_pkey_ix_to_key_end,
3232 	    IBMF_TNF_TRACE, "", "ibmf_i_pkey_ix_to_key() exit\n");
3233 
3234 	return (IBMF_SUCCESS);
3235 }
3236 
3237 /*
3238  * ibmf_i_ibt_to_ibmf_status():
3239  *	Map IBT return code to IBMF return code
3240  */
3241 int
3242 ibmf_i_ibt_to_ibmf_status(ibt_status_t ibt_status)
3243 {
3244 	int ibmf_status;
3245 
3246 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_ibt_to_ibmf_status_start,
3247 	    IBMF_TNF_TRACE, "", "ibmf_i_ibt_to_ibmf_status() enter, "
3248 	    "status = %d\n", tnf_uint, ibt_status, ibt_status);
3249 
3250 	switch (ibt_status) {
3251 
3252 	case IBT_SUCCESS:
3253 		ibmf_status = IBMF_SUCCESS;
3254 		break;
3255 
3256 	case IBT_INSUFF_KERNEL_RESOURCE:
3257 	case IBT_INSUFF_RESOURCE:
3258 	case IBT_QP_FULL:
3259 		ibmf_status = IBMF_NO_RESOURCES;
3260 		break;
3261 
3262 	case IBT_HCA_IN_USE:
3263 	case IBT_QP_IN_USE:
3264 	case IBT_CQ_BUSY:
3265 	case IBT_PD_IN_USE:
3266 	case IBT_MR_IN_USE:
3267 		ibmf_status = IBMF_BUSY;
3268 		break;
3269 
3270 	default:
3271 		ibmf_status = IBMF_FAILURE;
3272 		break;
3273 	}
3274 
3275 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_ibt_to_ibmf_status_end,
3276 	    IBMF_TNF_TRACE, "", "ibmf_i_ibt_to_ibmf_status() exit, "
3277 	    "ibt_status = %d, ibmf_status = %d\n", tnf_uint, ibt_status,
3278 	    ibt_status, tnf_int, ibmf_status, ibmf_status);
3279 
3280 	return (ibmf_status);
3281 }
3282 
3283 /*
3284  * ibmf_i_ibt_wc_to_ibmf_status():
3285  *	Map work completion code to IBMF return code
3286  */
3287 int
3288 ibmf_i_ibt_wc_to_ibmf_status(ibt_wc_status_t ibt_wc_status)
3289 {
3290 	int ibmf_status;
3291 
3292 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
3293 	    ibmf_i_ibt_wc_to_ibmf_status_start, IBMF_TNF_TRACE, "",
3294 	    "ibmf_i_ibt_to_ibmf_status() enter, status = %d\n",
3295 	    tnf_uint, ibt_wc_status, ibt_wc_status);
3296 
3297 	switch (ibt_wc_status) {
3298 
3299 	case IBT_WC_SUCCESS:
3300 		ibmf_status = IBMF_SUCCESS;
3301 		break;
3302 
3303 	default:
3304 		ibmf_status = IBMF_FAILURE;
3305 		break;
3306 	}
3307 
3308 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
3309 	    ibmf_i_ibt_wc_to_ibmf_status_end, IBMF_TNF_TRACE, "",
3310 	    "ibmf_i_ibt_to_ibmf_status() exit, wc_status = %d, "
3311 	    "ibmf_status = %d\n", tnf_uint, ibt_wc_status,
3312 	    ibt_wc_status, tnf_int, ibmf_status, ibmf_status);
3313 
3314 	return (ibmf_status);
3315 }
3316 
3317 /*
3318  * ibmf_i_is_ibmf_handle_valid():
3319  *	Validate the ibmf handle
3320  */
3321 int
3322 ibmf_i_is_ibmf_handle_valid(ibmf_handle_t ibmf_handle)
3323 {
3324 	ibmf_ci_t	*cip;
3325 	ibmf_client_t	*clp, *clientp = (ibmf_client_t *)ibmf_handle;
3326 
3327 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3328 	    ibmf_i_is_ibmf_handle_valid_start, IBMF_TNF_TRACE, "",
3329 	    "ibmf_i_is_ibmf_handle_valid() enter\n");
3330 
3331 	mutex_enter(&ibmf_statep->ibmf_mutex);
3332 
3333 	cip = ibmf_statep->ibmf_ci_list;
3334 
3335 	/* iterate through all the channel interace contexts */
3336 	while (cip != NULL) {
3337 
3338 		mutex_enter(&cip->ci_clients_mutex);
3339 
3340 		clp = cip->ci_clients;
3341 
3342 		/* search all registration contexts for this ci */
3343 		while (clp != NULL) {
3344 			if (clp == clientp)
3345 				break;
3346 			clp = clp->ic_next;
3347 		}
3348 
3349 		mutex_exit(&cip->ci_clients_mutex);
3350 
3351 		if (clp == clientp) {
3352 			/* ci found */
3353 			break;
3354 		} else {
3355 			/* ci not found, move onto next ci */
3356 			cip = cip->ci_next;
3357 		}
3358 	}
3359 
3360 	mutex_exit(&ibmf_statep->ibmf_mutex);
3361 
3362 	if (cip != NULL) {
3363 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3364 		    ibmf_i_is_ibmf_handle_valid_end, IBMF_TNF_TRACE, "",
3365 		    "ibmf_i_is_ibmf_handle_valid() exit\n");
3366 		return (IBMF_SUCCESS);
3367 	} else {
3368 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3369 		    ibmf_i_is_ibmf_handle_valid_end, IBMF_TNF_TRACE, "",
3370 		    "ibmf_i_is_ibmf_handle_valid() failure exit\n");
3371 		return (IBMF_FAILURE);
3372 	}
3373 }
3374 
3375 /*
3376  * ibmf_i_is_qp_handle_valid():
3377  *	Validate the QP handle
3378  */
3379 int
3380 ibmf_i_is_qp_handle_valid(ibmf_handle_t ibmf_handle,
3381     ibmf_qp_handle_t ibmf_qp_handle)
3382 {
3383 	ibmf_client_t	*clientp = (ibmf_client_t *)ibmf_handle;
3384 	ibmf_alt_qp_t	*alt_qp, *qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
3385 	ibmf_ci_t	*cip = clientp->ic_myci;
3386 
3387 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3388 	    ibmf_i_is_qp_handle_valid_start, IBMF_TNF_TRACE, "",
3389 	    "ibmf_i_is_qp_handle_valid() enter\n");
3390 
3391 	/* the default qp handle is always valid */
3392 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT)
3393 		return (IBMF_SUCCESS);
3394 
3395 	mutex_enter(&cip->ci_mutex);
3396 
3397 	alt_qp = cip->ci_alt_qp_list;
3398 
3399 	while (alt_qp != NULL) {
3400 		if (alt_qp == qpp) {
3401 			/* qp handle found */
3402 			break;
3403 		} else {
3404 			/* qp handle not found, get next qp on list */
3405 			alt_qp = alt_qp->isq_next;
3406 		}
3407 	}
3408 
3409 	mutex_exit(&cip->ci_mutex);
3410 
3411 	if (alt_qp != NULL) {
3412 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3413 		    ibmf_i_is_qp_handle_valid_end, IBMF_TNF_TRACE, "",
3414 		    "ibmf_i_is_qp_handle_valid() exit\n");
3415 		return (IBMF_SUCCESS);
3416 	} else {
3417 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3418 		    ibmf_i_is_qp_handle_valid_end, IBMF_TNF_TRACE, "",
3419 		    "ibmf_i_is_qp_handle_valid() failure exit\n");
3420 		return (IBMF_FAILURE);
3421 	}
3422 }
3423 
3424 void
3425 ibmf_dprintf(int l, const char *fmt, ...)
3426 {
3427 	va_list ap;
3428 
3429 	if ((l) > ibmf_trace_level) {
3430 
3431 		return;
3432 	}
3433 
3434 	va_start(ap, fmt);
3435 	(void) vprintf(fmt, ap);
3436 	va_end(ap);
3437 }
3438 
3439 /*
3440  * ibmf_setup_term_ctx():
3441  * Sets up a message context that is the duplicate of the one
3442  * passed in the regmsgimplp argument. The duplicate message context
3443  * is not visible to the client. It is managed internally by ibmf
3444  * to process the RMPP receiver termination flow logic for the
3445  * transaction while the client is notified of the completion of the
3446  * same transaction (i.e. all the solicited data has been received).
3447  */
3448 int
3449 ibmf_setup_term_ctx(ibmf_client_t *clientp, ibmf_msg_impl_t *regmsgimplp)
3450 {
3451 	ibmf_msg_impl_t	*msgimplp;
3452 	size_t		offset;
3453 	uint32_t	cl_hdr_sz, cl_hdr_off;
3454 	int		status;
3455 
3456 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3457 	    ibmf_setup_term_ctx_start, IBMF_TNF_TRACE, "",
3458 	    "ibmf_setup_term_ctx() enter\n");
3459 
3460 	/*
3461 	 * Allocate the termination message context
3462 	 */
3463 	msgimplp = (ibmf_msg_impl_t *)kmem_zalloc(sizeof (ibmf_msg_impl_t),
3464 	    KM_NOSLEEP);
3465 	if (msgimplp == NULL) {
3466 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
3467 		    ibmf_setup_term_ctx_error, IBMF_TNF_ERROR, "",
3468 		    "ibmf_setup_term_ctx(): %s\n", tnf_string, msg,
3469 		    "message mem allocation failure");
3470 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3471 		    ibmf_setup_term_ctx_end, IBMF_TNF_TRACE, "",
3472 		    "ibmf_setup_term_ctx() exit\n");
3473 		return (IBMF_NO_RESOURCES);
3474 	}
3475 
3476 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msgimplp))
3477 
3478 	/* Copy the message context to the termination message structure */
3479 	*msgimplp = *regmsgimplp;
3480 
3481 	/* Initialize the message mutex */
3482 	mutex_init(&msgimplp->im_mutex, NULL, MUTEX_DRIVER, NULL);
3483 
3484 	/*
3485 	 * Allocate enough memory for the MAD header only.
3486 	 */
3487 	msgimplp->im_msgbufs_recv.im_bufs_mad_hdr =
3488 	    (ib_mad_hdr_t *)kmem_zalloc(IBMF_MAD_SIZE, KM_NOSLEEP);
3489 	if (msgimplp->im_msgbufs_recv.im_bufs_mad_hdr == NULL) {
3490 		kmem_free(msgimplp, sizeof (ibmf_msg_impl_t));
3491 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
3492 		    ibmf_setup_term_ctx_error, IBMF_TNF_ERROR, "",
3493 		    "ibmf_setup_term_ctx(): %s\n", tnf_string, msg,
3494 		    "recv buf mem allocation failure");
3495 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3496 		    ibmf_setup_term_ctx_end, IBMF_TNF_TRACE, "",
3497 		    "ibmf_setup_term_ctx() exit\n");
3498 		return (IBMF_NO_RESOURCES);
3499 	}
3500 
3501 	/* Copy over just the MAD header contents */
3502 	bcopy((const void *)regmsgimplp->im_msgbufs_recv.im_bufs_mad_hdr,
3503 	    (void *)msgimplp->im_msgbufs_recv.im_bufs_mad_hdr,
3504 	    sizeof (ib_mad_hdr_t));
3505 
3506 	offset = sizeof (ib_mad_hdr_t);
3507 	ibmf_i_mgt_class_to_hdr_sz_off(
3508 	    regmsgimplp->im_msgbufs_recv.im_bufs_mad_hdr->MgmtClass,
3509 	    &cl_hdr_sz, &cl_hdr_off);
3510 	offset += cl_hdr_off;
3511 
3512 	/*
3513 	 * Copy the management class header
3514 	 */
3515 	msgimplp->im_msgbufs_recv.im_bufs_cl_hdr =
3516 	    (uchar_t *)msgimplp->im_msgbufs_recv.im_bufs_mad_hdr + offset;
3517 	msgimplp->im_msgbufs_recv.im_bufs_cl_hdr_len =
3518 	    regmsgimplp->im_msgbufs_recv.im_bufs_cl_hdr_len;
3519 	bcopy((void *)regmsgimplp->im_msgbufs_recv.im_bufs_cl_hdr,
3520 	    (void *)msgimplp->im_msgbufs_recv.im_bufs_cl_hdr,
3521 	    regmsgimplp->im_msgbufs_recv.im_bufs_cl_hdr_len);
3522 
3523 	/*
3524 	 * Clear the termination message timers copied from the regular message
3525 	 * since ibmf_i_set_timer() expects them to be cleared.
3526 	 */
3527 	msgimplp->im_rp_timeout_id = 0;
3528 	msgimplp->im_tr_timeout_id = 0;
3529 
3530 	/* Mark this message as being in a receiver RMPP mode */
3531 	msgimplp->im_flags |= IBMF_MSG_FLAGS_RECV_RMPP;
3532 
3533 	/* Mark this message as being a "termination flow" message */
3534 	msgimplp->im_flags |= IBMF_MSG_FLAGS_TERMINATION;
3535 
3536 	/*
3537 	 * Clear the IBMF_MSG_FLAGS_SET_TERMINATION copied over from the regular
3538 	 * message.
3539 	 */
3540 	msgimplp->im_flags &= ~IBMF_MSG_FLAGS_SET_TERMINATION;
3541 
3542 	/*
3543 	 * Clear the trans_state RECV_DONE and DONE flags so that the
3544 	 * protocol continues with the termination message context.
3545 	 */
3546 	msgimplp->im_trans_state_flags &= ~IBMF_TRANS_STATE_FLAG_RECV_DONE;
3547 	msgimplp->im_trans_state_flags &= ~IBMF_TRANS_STATE_FLAG_DONE;
3548 
3549 	/* Clear out references to the old UD dest handles */
3550 	msgimplp->im_ibmf_ud_dest = NULL;
3551 	msgimplp->im_ud_dest = NULL;
3552 
3553 	/*
3554 	 * Request new UD dest resources for the termination phase.
3555 	 * The old UD dest resources are freed when the IBMF client
3556 	 * calls ibmf_free_msg(), so they cannot be relied on to exist
3557 	 * when the RMPP termination loop completes.
3558 	 */
3559 	status = ibmf_i_alloc_ud_dest(clientp, msgimplp, &msgimplp->im_ud_dest,
3560 	    B_FALSE);
3561 	if (status != IBMF_SUCCESS) {
3562 		kmem_free(msgimplp, sizeof (ibmf_msg_impl_t));
3563 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
3564 		    ibmf_setup_term_ctx_err, IBMF_TNF_ERROR, "",
3565 		    "ibmf_setup_term_ctx(): %s, status = %d\n",
3566 		    tnf_string, msg, "UD destination resource allocation"
3567 		    " failed", tnf_int, ibmf_status, status);
3568 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3569 		    ibmf_setup_term_ctx_end, IBMF_TNF_TRACE, "",
3570 		    "ibmf_setup_term_ctx() exit\n");
3571 		return (status);
3572 	}
3573 
3574 	/*
3575 	 * Add the message to the termination client list by virtue of
3576 	 * having the IBMF_MSG_FLAGS_TERMINATION "im_flags" flag set.
3577 	 */
3578 	ibmf_i_client_add_msg(clientp, msgimplp);
3579 
3580 	/*
3581 	 * Increase the "allocted messages" count so that the client
3582 	 * does not unregister before this message has been freed.
3583 	 * This is necessary because we want the client context to
3584 	 * be around when the receive timeout expires for this termination
3585 	 * loop, otherwise the code will access freed memory and crash.
3586 	 */
3587 	mutex_enter(&clientp->ic_mutex);
3588 	clientp->ic_msgs_alloced++;
3589 	mutex_exit(&clientp->ic_mutex);
3590 
3591 	mutex_enter(&msgimplp->im_mutex);
3592 	/* Set the response timer for the termination message. */
3593 	ibmf_i_set_timer(ibmf_i_recv_timeout, msgimplp, IBMF_RESP_TIMER);
3594 	mutex_exit(&msgimplp->im_mutex);
3595 
3596 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_setup_term_ctx_end,
3597 	    IBMF_TNF_TRACE, "", "ibmf_setup_term_ctx() exit\n");
3598 
3599 	return (IBMF_SUCCESS);
3600 }
3601