xref: /illumos-gate/usr/src/uts/common/io/ib/mgt/ibmf/ibmf_impl.c (revision d01412971af32f806ad2e91e40c00b485e893b2c)
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 	bzero(&msgimplp->im_rmpp_ctx, sizeof (ibmf_rmpp_ctx_t));
2100 	msgimplp->im_rmpp_ctx.rmpp_state = IBMF_RMPP_STATE_UNDEFINED;
2101 	msgimplp->im_rmpp_ctx.rmpp_respt = IBMF_RMPP_DEFAULT_RRESPT;
2102 	msgimplp->im_rmpp_ctx.rmpp_retry_cnt = 0;
2103 	msgimplp->im_ref_count = 0;
2104 	msgimplp->im_pending_send_compls = 0;
2105 	IBMF_MSG_INCR_REFCNT(msgimplp);
2106 	if (msgimplp->im_retrans.retrans_retries == 0)
2107 		msgimplp->im_retrans.retrans_retries = IBMF_RETRANS_DEF_RETRIES;
2108 	if (msgimplp->im_retrans.retrans_rtv == 0)
2109 		msgimplp->im_retrans.retrans_rtv = IBMF_RETRANS_DEF_RTV;
2110 	if (msgimplp->im_retrans.retrans_rttv == 0)
2111 		msgimplp->im_retrans.retrans_rttv = IBMF_RETRANS_DEF_RTTV;
2112 
2113 	IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_msg_transport,
2114 	    IBMF_TNF_TRACE, "", "ibmf_i_msg_transport(): %s, msgp = 0x%p, "
2115 	    "class = 0x%x, method = 0x%x, attributeID = 0x%x\n",
2116 	    tnf_string, msg, "Added message", tnf_opaque, msgimplp,
2117 	    msgimplp, tnf_opaque, class, msgimplp->im_mgt_class, tnf_opaque,
2118 	    method, madhdrp->R_Method, tnf_opaque, attrib_id,
2119 	    b2h16(madhdrp->AttributeID));
2120 
2121 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_msg_transport,
2122 	    IBMF_TNF_TRACE, "", "ibmf_i_msg_transport(): msgp = 0x%p, "
2123 	    "TID = 0x%p, transp_op_flags = 0x%x\n",
2124 	    tnf_opaque, msgimplp, msgimplp, tnf_opaque, tid, msgimplp->im_tid,
2125 	    tnf_uint, transp_op_flags, msgimplp->im_transp_op_flags);
2126 
2127 	/*
2128 	 * Do not allow reuse of a message where the receive buffers are
2129 	 * being used as send buffers if this is a sequenced transaction
2130 	 */
2131 	if ((madhdrp == msgbufp->im_bufs_mad_hdr) &&
2132 	    (msgimplp->im_transp_op_flags & IBMF_MSG_TRANS_FLAG_SEQ)) {
2133 		IBMF_MSG_DECR_REFCNT(msgimplp);
2134 		mutex_exit(&msgimplp->im_mutex);
2135 		(void) sprintf(errmsg,
2136 		    "Send and Recv buffers are the same for sequenced"
2137 		    " transaction");
2138 		error = B_TRUE;
2139 		status = IBMF_REQ_INVALID;
2140 		goto bail;
2141 	}
2142 
2143 	/* set transaction flags */
2144 	if (msgimplp->im_transp_op_flags & IBMF_MSG_TRANS_FLAG_SEQ)
2145 		msgimplp->im_flags |= IBMF_MSG_FLAGS_SEQUENCED;
2146 
2147 	if (msgimplp->im_transp_op_flags & IBMF_MSG_TRANS_FLAG_RMPP)
2148 		msgimplp->im_flags |= IBMF_MSG_FLAGS_SEND_RMPP;
2149 	else
2150 		msgimplp->im_flags |= IBMF_MSG_FLAGS_NOT_RMPP;
2151 
2152 	/* free recv buffers if this is a reused message */
2153 	if ((msgbufp->im_bufs_mad_hdr != NULL) &&
2154 	    (msgimplp->im_transp_op_flags & IBMF_MSG_TRANS_FLAG_SEQ)) {
2155 
2156 		IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_msg_transport,
2157 		    IBMF_TNF_TRACE, "", "ibmf_i_msg_transport(): %s, "
2158 		    "msgp = 0x%p, mad_hdrp = 0x%p\n", tnf_string, msg,
2159 		    "Freeing recv buffer for reused message",
2160 		    tnf_opaque, msgimplp, msgimplp,
2161 		    tnf_opaque, mad_hdr, msgbufp->im_bufs_mad_hdr);
2162 
2163 		ibmf_i_mgt_class_to_hdr_sz_off(
2164 		    msgbufp->im_bufs_mad_hdr->MgmtClass,
2165 		    &cl_hdr_sz, &cl_hdr_off);
2166 
2167 		kmem_free(msgbufp->im_bufs_mad_hdr, sizeof (ib_mad_hdr_t) +
2168 		    cl_hdr_off + msgbufp->im_bufs_cl_hdr_len +
2169 		    msgbufp->im_bufs_cl_data_len);
2170 
2171 		msgbufp->im_bufs_mad_hdr = NULL;
2172 		msgbufp->im_bufs_cl_hdr = NULL;
2173 		msgbufp->im_bufs_cl_hdr_len = 0;
2174 		msgbufp->im_bufs_cl_data = NULL;
2175 		msgbufp->im_bufs_cl_data_len = 0;
2176 	}
2177 
2178 	mutex_exit(&msgimplp->im_mutex);
2179 
2180 	/* initialize (and possibly allocate) the address handle */
2181 	status = ibmf_i_alloc_ud_dest(clientp, msgimplp,
2182 	    &msgimplp->im_ud_dest, blocking);
2183 	if (status != IBMF_SUCCESS) {
2184 		(void) sprintf(errmsg, "ibmf_i_alloc_ud_dest() failed");
2185 		error = B_TRUE;
2186 		goto bail;
2187 	}
2188 
2189 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msgimplp, *msgbufp))
2190 
2191 	/* add the message to the client context's message list */
2192 	ibmf_i_client_add_msg(clientp, msgimplp);
2193 
2194 	mutex_enter(&msgimplp->im_mutex);
2195 
2196 	/* no one should have touched our state */
2197 	ASSERT(msgimplp->im_trans_state_flags == IBMF_TRANS_STATE_FLAG_UNINIT);
2198 
2199 	/* transition out of uninit state */
2200 	msgimplp->im_trans_state_flags = IBMF_TRANS_STATE_FLAG_INIT;
2201 
2202 	IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_msg_transport,
2203 	    IBMF_TNF_TRACE, "", "ibmf_i_msg_transport(): msgp = 0x%p, "
2204 	    "local_lid = 0x%x, remote_lid = 0x%x, remote_qpn = 0x%x, "
2205 	    "block = %d\n", tnf_opaque, msgp, msgimplp,
2206 	    tnf_uint, local_lid, msgimplp->im_local_addr.ia_local_lid,
2207 	    tnf_uint, remote_lid, msgimplp->im_local_addr.ia_remote_lid,
2208 	    tnf_uint, remote_qpn, msgimplp->im_local_addr.ia_remote_qno,
2209 	    tnf_uint, blocking, blocking);
2210 
2211 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_msg_transport,
2212 	    IBMF_TNF_TRACE, "", "ibmf_i_msg_transport(): "
2213 	    "unsetting timer %p %d\n", tnf_opaque, msgimplp, msgimplp,
2214 	    tnf_opaque, timeout_id, msgimplp->im_rp_timeout_id);
2215 
2216 	ASSERT(msgimplp->im_rp_timeout_id == 0);
2217 	ASSERT(msgimplp->im_tr_timeout_id == 0);
2218 
2219 	if ((msgimplp->im_transp_op_flags & IBMF_MSG_TRANS_FLAG_RMPP) == 0) {
2220 
2221 		/* Non-RMPP transaction */
2222 
2223 		status = ibmf_i_send_single_pkt(clientp, ibmf_qp_handle,
2224 		    msgimplp, blocking);
2225 		if (status != IBMF_SUCCESS) {
2226 			IBMF_MSG_DECR_REFCNT(msgimplp);
2227 			mutex_exit(&msgimplp->im_mutex);
2228 			ibmf_i_client_rem_msg(clientp, msgimplp, &refcnt);
2229 			(void) sprintf(errmsg, "Single packet send failed");
2230 			error = B_TRUE;
2231 			goto bail;
2232 		}
2233 
2234 	} else if (msgimplp->im_transp_op_flags & IBMF_MSG_TRANS_FLAG_RMPP) {
2235 
2236 		/* RMPP transaction */
2237 
2238 		/* check if client supports RMPP traffic */
2239 		if ((clientp->ic_reg_flags & IBMF_REG_FLAG_RMPP) == 0) {
2240 			IBMF_MSG_DECR_REFCNT(msgimplp);
2241 			mutex_exit(&msgimplp->im_mutex);
2242 			ibmf_i_client_rem_msg(clientp, msgimplp, &refcnt);
2243 			(void) sprintf(errmsg, "Class does not support RMPP");
2244 			error = B_TRUE;
2245 			status = IBMF_BAD_RMPP_OPT;
2246 			goto bail;
2247 		}
2248 
2249 		/* for non-special QPs, check if QP supports RMPP traffic */
2250 		if (ibmf_qp_handle != IBMF_QP_HANDLE_DEFAULT &&
2251 		    (((ibmf_alt_qp_t *)ibmf_qp_handle)->isq_supports_rmpp ==
2252 		    B_FALSE)) {
2253 			IBMF_MSG_DECR_REFCNT(msgimplp);
2254 			mutex_exit(&msgimplp->im_mutex);
2255 			ibmf_i_client_rem_msg(clientp, msgimplp, &refcnt);
2256 			(void) sprintf(errmsg, "QP does not support RMPP");
2257 			error = B_TRUE;
2258 			status = IBMF_BAD_RMPP_OPT;
2259 			goto bail;
2260 		}
2261 
2262 		/* check if transaction is "double sided" (send and receive) */
2263 		if (msgimplp->im_transp_op_flags & IBMF_MSG_TRANS_FLAG_SEQ)
2264 			isDS = 1;
2265 
2266 		status = ibmf_i_send_rmpp_pkts(clientp, ibmf_qp_handle,
2267 		    msgimplp, isDS, blocking);
2268 		if (status != IBMF_SUCCESS) {
2269 			IBMF_MSG_DECR_REFCNT(msgimplp);
2270 			mutex_exit(&msgimplp->im_mutex);
2271 			ibmf_i_client_rem_msg(clientp, msgimplp, &refcnt);
2272 			(void) sprintf(errmsg, "RMPP packets send failed");
2273 			error = B_TRUE;
2274 			goto bail;
2275 		}
2276 	}
2277 
2278 	/*
2279 	 * decrement the reference count so notify_client() can remove the
2280 	 * message when it's ready
2281 	 */
2282 	IBMF_MSG_DECR_REFCNT(msgimplp);
2283 
2284 	/* check if the transaction is a blocking transaction */
2285 	if (blocking && ((msgimplp->im_trans_state_flags &
2286 	    IBMF_TRANS_STATE_FLAG_SIGNALED) == 0)) {
2287 
2288 		/* indicate that the tranaction is waiting */
2289 		msgimplp->im_trans_state_flags |= IBMF_TRANS_STATE_FLAG_WAIT;
2290 
2291 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_msg_transport,
2292 		    IBMF_TNF_TRACE, "",
2293 		    "ibmf_i_msg_transport(): %s, msgp = 0x%p\n",
2294 		    tnf_string, msg, "blocking for completion",
2295 		    tnf_opaque, msgimplp, msgimplp);
2296 
2297 		/* wait for transaction completion */
2298 		cv_wait(&msgimplp->im_trans_cv, &msgimplp->im_mutex);
2299 
2300 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_msg_transport,
2301 		    IBMF_TNF_TRACE, "",
2302 		    "ibmf_i_msg_transport(): %s, msgp = 0x%p\n",
2303 		    tnf_string, msg, "unblocking for completion",
2304 		    tnf_opaque, msgimplp, msgimplp);
2305 
2306 		/* clean up flags */
2307 		msgimplp->im_trans_state_flags &= ~IBMF_TRANS_STATE_FLAG_WAIT;
2308 		msgimplp->im_flags &= ~IBMF_MSG_FLAGS_BUSY;
2309 
2310 		if (msgimplp->im_msg_status != IBMF_SUCCESS) {
2311 
2312 			IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
2313 			    ibmf_i_msg_transport_err, IBMF_TNF_ERROR, "",
2314 			    "ibmf_i_msg_transport(): msg_status = %d\n",
2315 			    tnf_uint, msgstatus, msgimplp->im_msg_status);
2316 
2317 			status = msgimplp->im_msg_status;
2318 		}
2319 	} else if (blocking && (msgimplp->im_trans_state_flags &
2320 	    IBMF_TRANS_STATE_FLAG_SIGNALED)) {
2321 		msgimplp->im_flags &= ~IBMF_MSG_FLAGS_BUSY;
2322 
2323 		if (msgimplp->im_msg_status != IBMF_SUCCESS) {
2324 			IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
2325 			    ibmf_i_msg_transport_err, IBMF_TNF_ERROR, "",
2326 			    "ibmf_i_msg_transport(): msg_status = %d\n",
2327 			    tnf_uint, msgstatus, msgimplp->im_msg_status);
2328 			status = msgimplp->im_msg_status;
2329 		}
2330 	}
2331 
2332 	msg_rp_unset_id = msg_tr_unset_id = 0;
2333 	msg_rp_unset_id = msgimplp->im_rp_unset_timeout_id;
2334 	msg_tr_unset_id = msgimplp->im_tr_unset_timeout_id;
2335 	msgimplp->im_rp_unset_timeout_id = 0;
2336 	msgimplp->im_tr_unset_timeout_id = 0;
2337 
2338 	mutex_exit(&msgimplp->im_mutex);
2339 
2340 	/* Unset the timers */
2341 	if (msg_rp_unset_id != 0) {
2342 		(void) untimeout(msg_rp_unset_id);
2343 	}
2344 
2345 	if (msg_tr_unset_id != 0) {
2346 		(void) untimeout(msg_tr_unset_id);
2347 	}
2348 
2349 	/* increment kstats of the number of sent messages */
2350 	mutex_enter(&clientp->ic_kstat_mutex);
2351 	IBMF_ADD32_KSTATS(clientp, msgs_sent, 1);
2352 	mutex_exit(&clientp->ic_kstat_mutex);
2353 
2354 bail:
2355 	if (error) {
2356 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2357 		    ibmf_i_msg_transport_err, IBMF_TNF_ERROR, "",
2358 		    "ibmf_i_msg_transport(): %s, msgp = 0x%p\n",
2359 		    tnf_string, msg, errmsg, tnf_opaque, msgimplp, msgimplp);
2360 	}
2361 
2362 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,	ibmf_i_msg_transport_end,
2363 	    IBMF_TNF_TRACE, "", "ibmf_i_msg_transport() exit, status = %d\n",
2364 	    tnf_uint, status, status);
2365 
2366 	return (status);
2367 }
2368 
2369 /*
2370  * ibmf_i_init_msg():
2371  *	Initialize the message fields
2372  */
2373 void
2374 ibmf_i_init_msg(ibmf_msg_impl_t *msgimplp, ibmf_msg_cb_t trans_cb,
2375     void *trans_cb_arg, ibmf_retrans_t *retrans, boolean_t block)
2376 {
2377 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_msg_start,
2378 	    IBMF_TNF_TRACE, "", "ibmf_i_init_msg() enter\n");
2379 
2380 	_NOTE(ASSUMING_PROTECTED(msgimplp->im_trans_cb,
2381 	    msgimplp->im_trans_cb_arg))
2382 
2383 	if (block == B_TRUE)
2384 		msgimplp->im_msg_flags |= IBMF_MSG_FLAGS_BLOCKING;
2385 	msgimplp->im_trans_cb = trans_cb;
2386 	msgimplp->im_trans_cb_arg = trans_cb_arg;
2387 
2388 	bzero(&msgimplp->im_retrans, sizeof (ibmf_retrans_t));
2389 	if (retrans != NULL) {
2390 		bcopy((void *)retrans, (void *)&msgimplp->im_retrans,
2391 		    sizeof (ibmf_retrans_t));
2392 	}
2393 
2394 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_init_msg_end,
2395 	    IBMF_TNF_TRACE, "", "ibmf_i_init_msg() exit\n");
2396 }
2397 
2398 /*
2399  * ibmf_i_alloc_qp():
2400  *	Allocate a QP context for the alternate QPs
2401  */
2402 int
2403 ibmf_i_alloc_qp(ibmf_client_t *clientp, ib_pkey_t p_key, ib_qkey_t q_key,
2404     uint_t flags, ibmf_qp_handle_t *ibmf_qp_handlep)
2405 {
2406 	ibmf_ci_t		*ibmf_cip = clientp->ic_myci;
2407 	ibt_qp_alloc_attr_t	qp_attrs;
2408 	ibt_qp_info_t		qp_modify_attr;
2409 	ibmf_alt_qp_t		*qp_ctx;
2410 	uint16_t		pkey_ix;
2411 	ibt_status_t		ibt_status;
2412 	int			i, blocking;
2413 	boolean_t		error = B_FALSE;
2414 	int			status = IBMF_SUCCESS;
2415 	char			errmsg[128];
2416 
2417 
2418 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4,
2419 	    ibmf_i_alloc_qp_start, IBMF_TNF_TRACE, "",
2420 	    "ibmf_i_alloc_qp() enter, clientp = %p, pkey = %x, qkey = %x \n",
2421 	    tnf_opaque, clientp, clientp, tnf_uint, p_key, p_key,
2422 	    tnf_uint, q_key, q_key);
2423 
2424 	/*
2425 	 * get the pkey index associated with this pkey if present in table
2426 	 */
2427 	if (ibmf_i_get_pkeyix(clientp->ic_ci_handle, p_key,
2428 	    clientp->ic_client_info.port_num, &pkey_ix) != IBMF_SUCCESS) {
2429 		(void) sprintf(errmsg, "pkey not in table, pkey = %x", p_key);
2430 		error = B_TRUE;
2431 		status = IBMF_FAILURE;
2432 		goto bail;
2433 	}
2434 
2435 	/* allocate QP context memory */
2436 	qp_ctx = (ibmf_alt_qp_t *)kmem_zalloc(sizeof (ibmf_alt_qp_t),
2437 	    (flags & IBMF_ALLOC_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
2438 	if (qp_ctx == NULL) {
2439 		(void) sprintf(errmsg, "failed to kmem_zalloc qp ctx");
2440 		error = B_TRUE;
2441 		status = IBMF_NO_RESOURCES;
2442 		goto bail;
2443 	}
2444 
2445 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*qp_ctx));
2446 
2447 	/* setup the qp attrs for the alloc call */
2448 	qp_attrs.qp_scq_hdl = ibmf_cip->ci_alt_cq_handle;
2449 	qp_attrs.qp_rcq_hdl = ibmf_cip->ci_alt_cq_handle;
2450 	qp_attrs.qp_pd_hdl = ibmf_cip->ci_pd;
2451 	qp_attrs.qp_sizes.cs_sq_sgl = IBMF_MAX_SQ_WR_SGL_ELEMENTS;
2452 	qp_attrs.qp_sizes.cs_rq_sgl = IBMF_MAX_RQ_WR_SGL_ELEMENTS;
2453 	qp_attrs.qp_sizes.cs_sq = ibmf_send_wqes_posted_per_qp;
2454 	qp_attrs.qp_sizes.cs_rq = ibmf_recv_wqes_posted_per_qp;
2455 	qp_attrs.qp_flags = IBT_ALL_SIGNALED;
2456 	qp_attrs.qp_alloc_flags = IBT_QP_NO_FLAGS;
2457 
2458 	/* request IBT for a qp with the desired attributes */
2459 	ibt_status = ibt_alloc_qp(clientp->ic_ci_handle, IBT_UD_RQP,
2460 	    &qp_attrs, &qp_ctx->isq_qp_sizes, &qp_ctx->isq_qpn,
2461 	    &qp_ctx->isq_qp_handle);
2462 	if (ibt_status != IBT_SUCCESS) {
2463 		kmem_free(qp_ctx, sizeof (ibmf_alt_qp_t));
2464 		(void) sprintf(errmsg, "failed to alloc qp, status = %d",
2465 		    ibt_status);
2466 		error = B_TRUE;
2467 		status = IBMF_NO_RESOURCES;
2468 		goto bail;
2469 	}
2470 
2471 	qp_modify_attr.qp_trans = IBT_UD_SRV;
2472 	qp_modify_attr.qp_flags = IBT_CEP_NO_FLAGS;
2473 	qp_modify_attr.qp_transport.ud.ud_qkey = q_key;
2474 	qp_modify_attr.qp_transport.ud.ud_sq_psn = 0;
2475 	qp_modify_attr.qp_transport.ud.ud_pkey_ix = pkey_ix;
2476 	qp_modify_attr.qp_transport.ud.ud_port =
2477 	    clientp->ic_client_info.port_num;
2478 
2479 	/* Set up the client handle in the QP context */
2480 	qp_ctx->isq_client_hdl = clientp;
2481 
2482 	/* call the IB transport to initialize the QP */
2483 	ibt_status = ibt_initialize_qp(qp_ctx->isq_qp_handle, &qp_modify_attr);
2484 	if (ibt_status != IBT_SUCCESS) {
2485 		(void) ibt_free_qp(qp_ctx->isq_qp_handle);
2486 		kmem_free(qp_ctx, sizeof (ibmf_alt_qp_t));
2487 		(void) sprintf(errmsg, "failed to initialize qp, status = %d",
2488 		    ibt_status);
2489 		error = B_TRUE;
2490 		status = IBMF_NO_RESOURCES;
2491 		goto bail;
2492 	}
2493 
2494 	/* Set up the WQE caches */
2495 	status = ibmf_i_init_altqp_wqes(qp_ctx);
2496 	if (status != IBMF_SUCCESS) {
2497 		(void) ibt_free_qp(qp_ctx->isq_qp_handle);
2498 		kmem_free(qp_ctx, sizeof (ibmf_alt_qp_t));
2499 		(void) sprintf(errmsg, "failed to init wqe caches, status = %d",
2500 		    status);
2501 		error = B_TRUE;
2502 		goto bail;
2503 	}
2504 
2505 	qp_ctx->isq_next = NULL;
2506 	qp_ctx->isq_pkey = p_key;
2507 	qp_ctx->isq_qkey = q_key;
2508 	qp_ctx->isq_port_num = clientp->ic_client_info.port_num;
2509 	mutex_init(&qp_ctx->isq_mutex, NULL, MUTEX_DRIVER, NULL);
2510 	mutex_init(&qp_ctx->isq_wqe_mutex, NULL, MUTEX_DRIVER, NULL);
2511 	cv_init(&qp_ctx->isq_recv_cb_teardown_cv, NULL, CV_DRIVER, NULL);
2512 	cv_init(&qp_ctx->isq_sqd_cv, NULL, CV_DRIVER, NULL);
2513 	cv_init(&qp_ctx->isq_wqes_cv, NULL, CV_DRIVER, NULL);
2514 
2515 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*qp_ctx));
2516 
2517 	/* add alt qp to the list in CI context */
2518 	mutex_enter(&ibmf_cip->ci_mutex);
2519 	if (ibmf_cip->ci_alt_qp_list == NULL) {
2520 		ibmf_cip->ci_alt_qp_list = qp_ctx;
2521 	} else {
2522 		ibmf_alt_qp_t *qpp;
2523 
2524 		qpp = ibmf_cip->ci_alt_qp_list;
2525 		while (qpp->isq_next != NULL) {
2526 			qpp = qpp->isq_next;
2527 		}
2528 		qpp->isq_next = qp_ctx;
2529 	}
2530 	mutex_exit(&ibmf_cip->ci_mutex);
2531 
2532 	*ibmf_qp_handlep = (ibmf_qp_handle_t)qp_ctx;
2533 
2534 	if (flags & IBMF_ALLOC_SLEEP)
2535 		blocking = 1;
2536 	else
2537 		blocking = 0;
2538 
2539 	/* post the max number of buffers to RQ */
2540 	for (i = 0; i < ibmf_recv_wqes_per_port; i++) {
2541 		status = ibmf_i_post_recv_buffer(ibmf_cip, clientp->ic_qp,
2542 		    blocking, *ibmf_qp_handlep);
2543 		if (status != IBMF_SUCCESS) {
2544 			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
2545 			    ibmf_i_alloc_qp, IBMF_TNF_TRACE, "",
2546 			    "ibmf_i_alloc_qp(): %s, status = %d\n",
2547 			    tnf_string, msg, "ibmf_i_post_recv_buffer() failed",
2548 			    tnf_int, status, status);
2549 		}
2550 	}
2551 
2552 	mutex_enter(&clientp->ic_kstat_mutex);
2553 	IBMF_ADD32_KSTATS(clientp, alt_qps_alloced, 1);
2554 	mutex_exit(&clientp->ic_kstat_mutex);
2555 
2556 bail:
2557 	if (error) {
2558 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
2559 		    ibmf_i_alloc_qp_err, IBMF_TNF_TRACE, "",
2560 		    "ibmf_i_alloc_qp(): %s\n", tnf_string, msg, errmsg);
2561 	}
2562 
2563 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_alloc_qp_end,
2564 	    IBMF_TNF_TRACE, "", "ibmf_i_alloc_qp() exit, qp = %p\n",
2565 	    tnf_opaque, qp_handlep, *ibmf_qp_handlep);
2566 	return (status);
2567 }
2568 
2569 /*
2570  * ibmf_i_free_qp():
2571  *	Free an alternate QP context
2572  */
2573 /* ARGSUSED */
2574 int
2575 ibmf_i_free_qp(ibmf_qp_handle_t ibmf_qp_handle, uint_t flags)
2576 {
2577 	ibmf_alt_qp_t		*qp_ctx = (ibmf_alt_qp_t *)ibmf_qp_handle;
2578 	ibmf_client_t		*clientp = qp_ctx->isq_client_hdl;
2579 	ibmf_ci_t		*ibmf_cip = qp_ctx->isq_client_hdl->ic_myci;
2580 	ibmf_alt_qp_t		*qpp, *pqpp;
2581 	ibt_status_t		ibt_status;
2582 
2583 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
2584 	    ibmf_i_free_qp_start, IBMF_TNF_TRACE, "",
2585 	    "ibmf_i_free_qp() enter, qp_hdl = %p, flags = %x\n",
2586 	    tnf_opaque, qp_hdl, ibmf_qp_handle, tnf_uint, flags, flags);
2587 
2588 	/* remove qp from the list in CI context */
2589 
2590 	mutex_enter(&ibmf_cip->ci_mutex);
2591 	qpp = ibmf_cip->ci_alt_qp_list;
2592 	ASSERT(qpp != NULL);
2593 	if (qpp == qp_ctx) {
2594 		ibmf_cip->ci_alt_qp_list = qpp->isq_next;
2595 	} else {
2596 		while (qpp != NULL) {
2597 			if (qpp == qp_ctx)
2598 				break;
2599 			pqpp = qpp;
2600 			qpp = qpp->isq_next;
2601 		}
2602 		ASSERT(qpp != NULL);
2603 		pqpp->isq_next = qpp->isq_next;
2604 	}
2605 
2606 	mutex_exit(&ibmf_cip->ci_mutex);
2607 
2608 	/* flush the WQEs in the QP queues */
2609 	ibt_status = ibt_flush_qp(qp_ctx->isq_qp_handle);
2610 	if (ibt_status != IBT_SUCCESS) {
2611 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2612 		    ibmf_i_free_qp_err, IBMF_TNF_TRACE, "",
2613 		    "ibmf_i_free_qp(): %s, status = %d\n",
2614 		    tnf_string, msg, "failed to close qp",
2615 		    tnf_uint, ibt_status, ibt_status);
2616 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_free_qp_end,
2617 		    IBMF_TNF_TRACE, "", "ibmf_i_free_qp() exit\n");
2618 		return (IBMF_TRANSPORT_FAILURE);
2619 	}
2620 
2621 	/* Call the MAD completion handler */
2622 	ibmf_i_mad_completions(ibmf_cip->ci_alt_cq_handle, (void*)ibmf_cip);
2623 
2624 	/* Wait here for all WQE owned by this QP to get freed */
2625 	mutex_enter(&qpp->isq_mutex);
2626 	while (qpp->isq_wqes_alloced != 0) {
2627 		cv_wait(&qpp->isq_wqes_cv, &qpp->isq_mutex);
2628 	}
2629 	mutex_exit(&qpp->isq_mutex);
2630 
2631 	cv_destroy(&qp_ctx->isq_recv_cb_teardown_cv);
2632 	cv_destroy(&qp_ctx->isq_sqd_cv);
2633 	cv_destroy(&qp_ctx->isq_wqes_cv);
2634 
2635 	/* call the IB transport to free the QP */
2636 	ibt_status = ibt_free_qp(qp_ctx->isq_qp_handle);
2637 	if (ibt_status != IBT_SUCCESS) {
2638 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2639 		    ibmf_i_free_qp_err, IBMF_TNF_TRACE, "",
2640 		    "ibmf_i_free_qp(): %s, status = %d\n",
2641 		    tnf_string, msg, "failed to free qp",
2642 		    tnf_uint, ibt_status, ibt_status);
2643 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_free_qp_end,
2644 		    IBMF_TNF_TRACE, "", "ibmf_i_free_qp() exit\n");
2645 		return (IBMF_TRANSPORT_FAILURE);
2646 	}
2647 
2648 	/* Clean up the WQE caches */
2649 	ibmf_i_fini_altqp_wqes(qp_ctx);
2650 	mutex_destroy(&qp_ctx->isq_wqe_mutex);
2651 	mutex_destroy(&qp_ctx->isq_mutex);
2652 
2653 	mutex_enter(&clientp->ic_kstat_mutex);
2654 	IBMF_SUB32_KSTATS(clientp, alt_qps_alloced, 1);
2655 	mutex_exit(&clientp->ic_kstat_mutex);
2656 
2657 	kmem_free(qp_ctx, sizeof (ibmf_alt_qp_t));
2658 
2659 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_free_qp_end,
2660 	    IBMF_TNF_TRACE, "", "ibmf_i_free_qp() exit\n");
2661 
2662 	return (IBMF_SUCCESS);
2663 }
2664 
2665 /*
2666  * ibmf_i_query_qp():
2667  *	Query an alternate QP context
2668  */
2669 /* ARGSUSED */
2670 int
2671 ibmf_i_query_qp(ibmf_qp_handle_t ibmf_qp_handle, uint_t flags,
2672     uint_t *qp_nump, ib_pkey_t *p_keyp, ib_qkey_t *q_keyp, uint8_t *portnump)
2673 {
2674 	ibt_qp_query_attr_t	qp_query;
2675 	ibmf_alt_qp_t		*qp_ctx = (ibmf_alt_qp_t *)ibmf_qp_handle;
2676 	uint16_t		pkey_ix;
2677 	ibt_status_t		ibt_status;
2678 
2679 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
2680 	    ibmf_i_free_qp_start, IBMF_TNF_TRACE, "",
2681 	    "ibmf_i_free_qp() enter, qp_hdl = %p, flags = %x\n",
2682 	    tnf_opaque, qp_hdl, ibmf_qp_handle, tnf_uint, flags, flags);
2683 
2684 	ibt_status = ibt_query_qp(qp_ctx->isq_qp_handle, &qp_query);
2685 	if (ibt_status != IBT_SUCCESS) {
2686 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2687 		    ibmf_i_query_qp_err, IBMF_TNF_TRACE, "",
2688 		    "ibmf_i_query_qp(): %s, status = %d\n",
2689 		    tnf_string, msg, "failed to query qp",
2690 		    tnf_uint, ibt_status, ibt_status);
2691 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_query_qp_end,
2692 		    IBMF_TNF_TRACE, "", "ibmf_i_query_qp() exit\n");
2693 		return (IBMF_TRANSPORT_FAILURE);
2694 	}
2695 
2696 	/* move the desired attributes into the locations provided */
2697 	*qp_nump = qp_query.qp_qpn;
2698 	*q_keyp = qp_query.qp_info.qp_transport.ud.ud_qkey;
2699 	*portnump = qp_query.qp_info.qp_transport.ud.ud_port;
2700 
2701 	pkey_ix = qp_query.qp_info.qp_transport.ud.ud_pkey_ix;
2702 
2703 	/* get the pkey based on the pkey_ix */
2704 	ibt_status = ibt_index2pkey(qp_ctx->isq_client_hdl->ic_ci_handle,
2705 	    *portnump, pkey_ix, p_keyp);
2706 	if (ibt_status != IBT_SUCCESS) {
2707 		IBMF_TRACE_3(IBMF_TNF_NODEBUG, DPRINT_L1,
2708 		    ibmf_i_query_qp_err, IBMF_TNF_TRACE, "",
2709 		    "ibmf_i_query_qp(): %s, pkey_ix = %d, status = %d\n",
2710 		    tnf_string, msg, "failed to get pkey from index",
2711 		    tnf_uint, pkey_ix, pkey_ix,
2712 		    tnf_uint, ibt_status, ibt_status);
2713 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_query_qp_end,
2714 		    IBMF_TNF_TRACE, "", "ibmf_i_query_qp() exit\n");
2715 		return (IBMF_TRANSPORT_FAILURE);
2716 	}
2717 
2718 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_query_qp_end,
2719 	    IBMF_TNF_TRACE, "", "ibmf_i_query_qp() exit, qp_num = 0x%x, "
2720 	    "pkey = 0x%x, qkey = 0x%x, portnum = %d\n",
2721 	    tnf_uint, qp_num, *qp_nump, tnf_uint, pkey, *p_keyp,
2722 	    tnf_uint, qkey, *q_keyp, tnf_uint, portnum, *portnump);
2723 
2724 	return (IBMF_SUCCESS);
2725 }
2726 
2727 /*
2728  * ibmf_i_modify_qp():
2729  *	Modify an alternate QP context
2730  */
2731 /* ARGSUSED */
2732 int
2733 ibmf_i_modify_qp(ibmf_qp_handle_t ibmf_qp_handle, ib_pkey_t p_key,
2734     ib_qkey_t q_key, uint_t flags)
2735 {
2736 	ibmf_alt_qp_t		*qp_ctx = (ibmf_alt_qp_t *)ibmf_qp_handle;
2737 	ibmf_client_t		*clientp = qp_ctx->isq_client_hdl;
2738 	ibmf_ci_t		*ibmf_cip = clientp->ic_myci;
2739 	ibmf_alt_qp_t		*qpp;
2740 	ibt_qp_info_t		qp_mod;
2741 	ibt_cep_modify_flags_t	qp_mod_flags;
2742 	ibt_queue_sizes_t	actual_sz;
2743 	uint16_t		pkey_ix;
2744 	ibt_status_t		ibt_status;
2745 
2746 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4,
2747 	    ibmf_i_modify_qp_start, IBMF_TNF_TRACE, "",
2748 	    "ibmf_i_modify_qp() enter, qp_hdl = %p, flags = %x, pkey = 0x%x, "
2749 	    "qkey = 0x%x\n", tnf_opaque, qp_hdl, ibmf_qp_handle,
2750 	    tnf_uint, flags, flags, tnf_uint, p_key, p_key,
2751 	    tnf_uint, q_key, q_key);
2752 
2753 	/*
2754 	 * get the pkey index associated with this pkey if present in table
2755 	 */
2756 	if (ibmf_i_get_pkeyix(clientp->ic_ci_handle, p_key,
2757 	    clientp->ic_client_info.port_num, &pkey_ix) != IBMF_SUCCESS) {
2758 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2759 		    ibmf_i_modify_qp_err, IBMF_TNF_TRACE, "",
2760 		    "ibmf_i_modify_qp(): %s, pkey = %x\n",
2761 		    tnf_string, msg, "pkey not in table",
2762 		    tnf_uint, pkey, p_key);
2763 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_modify_qp_end,
2764 		    IBMF_TNF_TRACE, "", "ibmf_i_modify_qp() exit\n");
2765 		return (IBMF_FAILURE);
2766 	}
2767 
2768 	/* Find the QP context in the CI QP context list */
2769 	mutex_enter(&ibmf_cip->ci_mutex);
2770 	qpp = ibmf_cip->ci_alt_qp_list;
2771 	while (qpp != NULL) {
2772 		if (qpp == qp_ctx) {
2773 			break;
2774 		}
2775 		qpp = qpp->isq_next;
2776 	}
2777 
2778 	if (qpp == NULL) {
2779 		mutex_exit(&ibmf_cip->ci_mutex);
2780 
2781 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
2782 		    ibmf_i_modify_qp_err, IBMF_TNF_TRACE, "",
2783 		    "ibmf_i_modify_qp(): %s\n",
2784 		    tnf_string, msg, "QP not in altqp list");
2785 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_modify_qp_end,
2786 		    IBMF_TNF_TRACE, "", "ibmf_i_modify_qp() exit\n");
2787 		return (IBMF_BAD_QP_HANDLE);
2788 
2789 	} else {
2790 
2791 		mutex_enter(&qp_ctx->isq_mutex);
2792 	}
2793 
2794 	mutex_exit(&ibmf_cip->ci_mutex);
2795 
2796 	/*
2797 	 * Transition the QP to SQD state
2798 	 */
2799 	bzero(&qp_mod, sizeof (ibt_qp_info_t));
2800 	qp_mod.qp_trans = IBT_UD_SRV;
2801 	qp_mod.qp_state = IBT_STATE_SQD;
2802 	qp_mod_flags = IBT_CEP_SET_STATE | IBT_CEP_SET_SQD_EVENT;
2803 	ibt_status = ibt_modify_qp(qp_ctx->isq_qp_handle, qp_mod_flags,
2804 	    &qp_mod, &actual_sz);
2805 	if (ibt_status != IBT_SUCCESS) {
2806 		mutex_exit(&qp_ctx->isq_mutex);
2807 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2808 		    ibmf_i_modify_qp_err, IBMF_TNF_TRACE, "",
2809 		    "ibmf_i_modify_qp(): %s, qp_hdl = %p\n",
2810 		    tnf_string, msg, "QP transition RTS to SQD failed",
2811 		    tnf_opaque, qp_handle, qp_ctx->isq_qp_handle);
2812 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_modify_qp_end,
2813 		    IBMF_TNF_TRACE, "", "ibmf_i_modify_qp() exit\n");
2814 		return (IBMF_TRANSPORT_FAILURE);
2815 	}
2816 
2817 	/*
2818 	 * Wait for an event indicating that the QP is in SQD state
2819 	 */
2820 	cv_wait(&qp_ctx->isq_sqd_cv, &qp_ctx->isq_mutex);
2821 
2822 	/* Setup QP modification information for transition to RTS state */
2823 	bzero(&qp_mod, sizeof (ibt_qp_info_t));
2824 	qp_mod.qp_trans = IBT_UD_SRV;
2825 	qp_mod.qp_state = IBT_STATE_RTS;
2826 	qp_mod.qp_current_state = IBT_STATE_SQD;
2827 	qp_mod.qp_transport.ud.ud_pkey_ix = pkey_ix;
2828 	qp_mod.qp_transport.ud.ud_qkey = q_key;
2829 	qp_mod_flags = IBT_CEP_SET_STATE | IBT_CEP_SET_PKEY_IX |
2830 	    IBT_CEP_SET_QKEY;
2831 
2832 	/*
2833 	 * transition the QP back to RTS state to allow
2834 	 * modification of the pkey and qkey
2835 	 */
2836 
2837 	ibt_status = ibt_modify_qp(qp_ctx->isq_qp_handle, qp_mod_flags,
2838 	    &qp_mod, &actual_sz);
2839 	if (ibt_status != IBT_SUCCESS) {
2840 		mutex_exit(&qp_ctx->isq_mutex);
2841 		IBMF_TRACE_3(IBMF_TNF_NODEBUG, DPRINT_L1,
2842 		    ibmf_i_modify_qp_err, IBMF_TNF_TRACE, "",
2843 		    "ibmf_i_modify_qp(): %s, qp_hdl = %p, status = %d\n",
2844 		    tnf_string, msg, "QP transition SQD to RTS failed",
2845 		    tnf_opaque, qp_handle, qp_ctx->isq_qp_handle,
2846 		    tnf_uint, ibt_status, ibt_status);
2847 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_modify_qp_end,
2848 		    IBMF_TNF_TRACE, "", "ibmf_i_modify_qp() exit\n");
2849 		return (IBMF_TRANSPORT_FAILURE);
2850 	}
2851 
2852 	qp_ctx->isq_pkey = p_key;
2853 	qp_ctx->isq_qkey = q_key;
2854 	mutex_exit(&qp_ctx->isq_mutex);
2855 
2856 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_modify_qp_end,
2857 	    IBMF_TNF_TRACE, "", "ibmf_i_modify_qp() exit\n");
2858 	return (IBMF_SUCCESS);
2859 }
2860 
2861 /*
2862  * ibmf_i_post_recv_buffer():
2863  *	Post a WQE to the RQ of the specified QP
2864  */
2865 int
2866 ibmf_i_post_recv_buffer(ibmf_ci_t *cip, ibmf_qp_t *qpp, boolean_t block,
2867     ibmf_qp_handle_t ibmf_qp_handle)
2868 {
2869 	int			ret;
2870 	ibt_wr_ds_t		*sgl;
2871 	ibt_status_t		status;
2872 	ibmf_recv_wqe_t		*recv_wqep;
2873 	ibt_qp_hdl_t		ibt_qp_handle;
2874 	struct kmem_cache	*kmem_cachep;
2875 	ibmf_alt_qp_t		*altqp;
2876 
2877 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4,
2878 	    ibmf_i_post_recv_buffer_start, IBMF_TNF_TRACE, "",
2879 	    "ibmf_i_post_recv_buffer() enter, cip = %p, qpp = %p, "
2880 	    "qp_hdl = %p, block = %d\n", tnf_opaque, cip, cip,
2881 	    tnf_opaque, qpp, qpp, tnf_opaque, qp_hdl, ibmf_qp_handle,
2882 	    tnf_uint, block, block);
2883 
2884 	/*
2885 	 * if we haven't hit the max wqes per qp, attempt to allocate a recv
2886 	 * wqe and post it to the recv queue.
2887 	 * It is possible for more than one thread to get through this
2888 	 * check below and post wqes that could push us above the
2889 	 * ibmf_recv_wqes_posted_per_qp. We catch that case when the recv
2890 	 * completion is signaled.
2891 	 */
2892 	ASSERT(MUTEX_NOT_HELD(&cip->ci_mutex));
2893 
2894 	/* Get the WQE kmem cache pointer based on the QP type */
2895 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT)
2896 		kmem_cachep = cip->ci_recv_wqes_cache;
2897 	else {
2898 		altqp = (ibmf_alt_qp_t *)ibmf_qp_handle;
2899 		kmem_cachep = altqp->isq_recv_wqes_cache;
2900 	}
2901 
2902 	/* allocate a receive WQE from the receive WQE kmem cache */
2903 	recv_wqep = kmem_cache_alloc(kmem_cachep,
2904 	    (block == B_TRUE ? KM_SLEEP : KM_NOSLEEP));
2905 	if (recv_wqep == NULL) {
2906 		/*
2907 		 * Attempt to extend the cache and then retry the
2908 		 * kmem_cache_alloc()
2909 		 */
2910 		if (ibmf_i_extend_wqe_cache(cip, ibmf_qp_handle, block) ==
2911 		    IBMF_NO_RESOURCES) {
2912 			mutex_enter(&cip->ci_mutex);
2913 			IBMF_ADD32_PORT_KSTATS(cip, rwqe_allocs_failed, 1);
2914 			mutex_exit(&cip->ci_mutex);
2915 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2916 			    ibmf_i_post_recv_buffer_err, IBMF_TNF_ERROR, "",
2917 			    "ibmf_i_post_recv_buffer(): %s, status = %d\n",
2918 			    tnf_string, msg, "alloc recv_wqe failed",
2919 			    tnf_int, ibmf_status, IBMF_NO_RESOURCES);
2920 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
2921 			    ibmf_i_post_recv_buffer_end, IBMF_TNF_TRACE, "",
2922 			    "ibmf_i_post_recv_buffer() exit\n");
2923 			return (IBMF_NO_RESOURCES);
2924 		} else {
2925 			recv_wqep = kmem_cache_alloc(kmem_cachep,
2926 			    (block == B_TRUE ? KM_SLEEP : KM_NOSLEEP));
2927 			if (recv_wqep == NULL) {
2928 				/* Allocation failed again. Give up here. */
2929 				mutex_enter(&cip->ci_mutex);
2930 				IBMF_ADD32_PORT_KSTATS(cip, rwqe_allocs_failed,
2931 				    1);
2932 				mutex_exit(&cip->ci_mutex);
2933 				IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2934 				    ibmf_i_post_recv_buffer_err,
2935 				    IBMF_TNF_ERROR, "",
2936 				    "ibmf_i_post_recv_buffer(): %s, "
2937 				    "status = %d\n",
2938 				    tnf_string, msg, "alloc recv_wqe failed",
2939 				    tnf_int, ibmf_status, IBMF_NO_RESOURCES);
2940 				IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
2941 				    ibmf_i_post_recv_buffer_end,
2942 				    IBMF_TNF_TRACE, "",
2943 				    "ibmf_i_post_recv_buffer() exit\n");
2944 				return (IBMF_NO_RESOURCES);
2945 			}
2946 		}
2947 	}
2948 
2949 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*recv_wqep))
2950 
2951 	/*
2952 	 * if the qp handle provided in ibmf_send_pkt() or
2953 	 * ibmf_setup_recv_cb() is not the default qp handle
2954 	 * for this client, then the wqe must be queued on this qp,
2955 	 * else use the default qp handle set up during ibmf_register()
2956 	 */
2957 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
2958 		ibt_qp_handle = qpp->iq_qp_handle;
2959 	} else {
2960 		ibt_qp_handle =
2961 		    ((ibmf_alt_qp_t *)ibmf_qp_handle)->isq_qp_handle;
2962 	}
2963 
2964 	/* allocate memory for the scatter-gather list */
2965 	sgl = kmem_zalloc(IBMF_MAX_RQ_WR_SGL_ELEMENTS * sizeof (ibt_wr_ds_t),
2966 	    (block == B_TRUE) ? KM_SLEEP : KM_NOSLEEP);
2967 	if (sgl == NULL) {
2968 		kmem_cache_free(kmem_cachep, recv_wqep);
2969 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
2970 		    ibmf_i_post_recv_buffer_err, IBMF_TNF_ERROR, "",
2971 		    "ibmf_i_post_recv_buffer(): %s\n",
2972 		    tnf_string, msg, "failed to kmem_zalloc qp ctx");
2973 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
2974 		    ibmf_i_post_recv_buffer_end, IBMF_TNF_TRACE, "",
2975 		    "ibmf_i_post_recv_buffer() exit\n");
2976 		return (IBMF_NO_RESOURCES);
2977 	}
2978 
2979 	/* initialize it */
2980 	ibmf_i_init_recv_wqe(qpp, sgl, recv_wqep, ibt_qp_handle,
2981 	    ibmf_qp_handle);
2982 
2983 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*recv_wqep))
2984 
2985 	/* and post it */
2986 	status = ibt_post_recv(recv_wqep->recv_qp_handle, &recv_wqep->recv_wr,
2987 	    1, NULL);
2988 
2989 	ret = ibmf_i_ibt_to_ibmf_status(status);
2990 	if (ret != IBMF_SUCCESS) {
2991 		kmem_free(sgl, IBMF_MAX_RQ_WR_SGL_ELEMENTS *
2992 		    sizeof (ibt_wr_ds_t));
2993 		kmem_cache_free(kmem_cachep, recv_wqep);
2994 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2995 		    ibmf_i_post_recv_buffer_err, IBMF_TNF_ERROR, "",
2996 		    "ibmf_i_post_recv_buffer(): %s, status = %d\n",
2997 		    tnf_string, msg, "ibt_post_recv failed",
2998 		    tnf_uint, ibt_status, status);
2999 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3000 		    ibmf_i_post_recv_buffer_end, IBMF_TNF_TRACE, "",
3001 		    "ibmf_i_post_recv_buffer() exit\n");
3002 		return (ret);
3003 	}
3004 
3005 	mutex_enter(&cip->ci_mutex);
3006 	IBMF_ADD32_PORT_KSTATS(cip, recv_wqes_alloced, 1);
3007 	mutex_exit(&cip->ci_mutex);
3008 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
3009 		mutex_enter(&qpp->iq_mutex);
3010 		qpp->iq_rwqes_posted++;
3011 		mutex_exit(&qpp->iq_mutex);
3012 		mutex_enter(&cip->ci_mutex);
3013 		cip->ci_wqes_alloced++;
3014 		mutex_exit(&cip->ci_mutex);
3015 	} else {
3016 		mutex_enter(&altqp->isq_mutex);
3017 		altqp->isq_wqes_alloced++;
3018 		altqp->isq_rwqes_posted++;
3019 		mutex_exit(&altqp->isq_mutex);
3020 	}
3021 
3022 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_post_recv_buffer_end,
3023 	    IBMF_TNF_TRACE, "", "ibmf_i_post_recv_buffer() exit\n");
3024 
3025 	return (ret);
3026 }
3027 
3028 /*
3029  * ibmf_i_mgt_class_to_hdr_sz_off():
3030  *	Determine class header offser and size for management classes
3031  */
3032 void
3033 ibmf_i_mgt_class_to_hdr_sz_off(uint32_t mgt_class, uint32_t *szp,
3034     uint32_t *offp)
3035 {
3036 	uint32_t	hdr_sz = 0, hdr_off = 0;
3037 
3038 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
3039 	    ibmf_i_mgt_class_to_hdr_sz_off_start, IBMF_TNF_TRACE, "",
3040 	    "ibmf_i_mgt_class_to_hdr_sz_off(): mgt_class = 0x%x\n",
3041 	    tnf_uint, mgt_class, mgt_class);
3042 
3043 	switch (mgt_class) {
3044 	case MAD_MGMT_CLASS_SUBN_LID_ROUTED :
3045 	case MAD_MGMT_CLASS_SUBN_DIRECT_ROUTE :
3046 	case MAD_MGMT_CLASS_PERF :
3047 	case MAD_MGMT_CLASS_BM :
3048 	case MAD_MGMT_CLASS_DEV_MGT :
3049 	case MAD_MGMT_CLASS_SNMP :
3050 		hdr_sz = IBMF_MAD_CL_HDR_SZ_1;
3051 		hdr_off = IBMF_MAD_CL_HDR_OFF_1;
3052 		break;
3053 	case MAD_MGMT_CLASS_SUBN_ADM :
3054 		hdr_sz = IBMF_MAD_CL_HDR_SZ_2;
3055 		hdr_off = IBMF_MAD_CL_HDR_OFF_2;
3056 		break;
3057 	}
3058 
3059 	if (((mgt_class >= MAD_MGMT_CLASS_VENDOR_START) &&
3060 	    (mgt_class <= MAD_MGMT_CLASS_VENDOR_END)) ||
3061 	    ((mgt_class >= MAD_MGMT_CLASS_APPLICATION_START) &&
3062 	    (mgt_class <= MAD_MGMT_CLASS_APPLICATION_END))) {
3063 		hdr_sz = IBMF_MAD_CL_HDR_SZ_3;
3064 		hdr_off = IBMF_MAD_CL_HDR_OFF_1;
3065 	}
3066 
3067 	if ((mgt_class >= MAD_MGMT_CLASS_VENDOR2_START) &&
3068 	    (mgt_class <= MAD_MGMT_CLASS_VENDOR2_END)) {
3069 		hdr_sz = IBMF_MAD_CL_HDR_SZ_4;
3070 		hdr_off = IBMF_MAD_CL_HDR_OFF_2;
3071 	}
3072 
3073 	*szp = hdr_sz;
3074 	*offp = hdr_off;
3075 
3076 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
3077 	    ibmf_i_mgt_class_to_hdr_sz_off_end, IBMF_TNF_TRACE, "",
3078 	    "ibmf_i_mgt_class_to_hdr_sz_off() exit,hdr_sz = %d, hdr_off = %d\n",
3079 	    tnf_uint, hdr_sz, hdr_sz, tnf_uint, hdr_off, hdr_off);
3080 }
3081 
3082 /*
3083  * ibmf_i_lookup_client_by_mgmt_class():
3084  *	Lookup the client context based on the management class of
3085  *	the incoming packet
3086  */
3087 int
3088 ibmf_i_lookup_client_by_mgmt_class(ibmf_ci_t *ibmf_cip, int port_num,
3089     ibmf_client_type_t class, ibmf_client_t **clientpp)
3090 {
3091 	ibmf_client_t 		*clientp;
3092 	ibmf_client_info_t	*client_infop;
3093 
3094 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4,
3095 	    ibmf_i_lookup_client_by_mgmt_class_start, IBMF_TNF_TRACE, "",
3096 	    "ibmf_i_lookup_client_by_mgmt_class() enter, cip = %p, "
3097 	    "port_num = %d, class = 0x%x\n", tnf_opaque, cip, ibmf_cip,
3098 	    tnf_int, port, port_num, tnf_opaque, class, class);
3099 
3100 	ASSERT(MUTEX_NOT_HELD(&ibmf_cip->ci_clients_mutex));
3101 
3102 	mutex_enter(&ibmf_cip->ci_clients_mutex);
3103 
3104 	clientp = ibmf_cip->ci_clients;
3105 
3106 	/* walk client context list looking for class/portnum match */
3107 	while (clientp != NULL) {
3108 		client_infop = &clientp->ic_client_info;
3109 		if (class == client_infop->client_class &&
3110 		    port_num == client_infop->port_num) {
3111 			/* found our match */
3112 			break;
3113 		}
3114 		clientp = clientp->ic_next;
3115 	}
3116 
3117 	mutex_exit(&ibmf_cip->ci_clients_mutex);
3118 
3119 	if (clientp != NULL) {
3120 		*clientpp = clientp;
3121 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
3122 		    ibmf_i_lookup_client_by_mgmt_class_end, IBMF_TNF_TRACE, "",
3123 		    "ibmf_i_lookup_client_by_mgmt_class() exit, clp = %p\n",
3124 		    tnf_opaque, clientp, clientp);
3125 		return (IBMF_SUCCESS);
3126 	} else {
3127 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3128 		    ibmf_i_lookup_client_by_mgmt_class_end, IBMF_TNF_TRACE, "",
3129 		    "ibmf_i_lookup_client_by_mgmt_class() failure exit\n");
3130 		return (IBMF_FAILURE);
3131 	}
3132 }
3133 
3134 /*
3135  * ibmf_i_get_pkeyix():
3136  *	Get the pkey index of the pkey in the pkey table of the specified
3137  *	port. Take into account the partition membership.
3138  */
3139 int
3140 ibmf_i_get_pkeyix(ibt_hca_hdl_t hca_handle, ib_pkey_t pkey, uint8_t port,
3141     ib_pkey_t *pkeyixp)
3142 {
3143 	ib_pkey_t		tpkey;
3144 	ibt_status_t		ibt_status;
3145 
3146 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_get_pkeyix_start,
3147 	    IBMF_TNF_TRACE, "", "ibmf_i_get_pkeyix() enter, hcahdl = %p, "
3148 	    "pkey = 0x%x, port = %d\n", tnf_opaque, hcahdl, hca_handle,
3149 	    tnf_int, pkey, pkey, tnf_int, port, port);
3150 
3151 	/*
3152 	 * If the client specifies the FULL membership pkey and the
3153 	 * pkey is not in the table, this function should fail.
3154 	 */
3155 	if (pkey & IBMF_PKEY_MEMBERSHIP_MASK) {
3156 		ibt_status = ibt_pkey2index(hca_handle, port,
3157 		    pkey, pkeyixp);
3158 		if (ibt_status != IBT_SUCCESS) {
3159 			IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
3160 			    ibmf_i_get_pkeyix_err, IBMF_TNF_ERROR, "",
3161 			    "ibmf_i_get_pkeyix() error status = %d\n",
3162 			    tnf_uint, ibt_status, ibt_status);
3163 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3164 			    ibmf_i_get_pkeyix_end, IBMF_TNF_TRACE, "",
3165 			    "ibmf_i_get_pkeyix() exit\n");
3166 			return (IBMF_TRANSPORT_FAILURE);
3167 		}
3168 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_get_pkeyix_end,
3169 		    IBMF_TNF_TRACE, "", "ibmf_i_get_pkeyix() exit\n");
3170 		return (IBMF_SUCCESS);
3171 	}
3172 
3173 	/*
3174 	 * Limited member pkey processing
3175 	 * Check if this limited member pkey is in the pkey table
3176 	 */
3177 	ibt_status = ibt_pkey2index(hca_handle, port, pkey, pkeyixp);
3178 	if (ibt_status == IBT_SUCCESS) {
3179 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3180 		    ibmf_i_get_pkeyix_end, IBMF_TNF_TRACE, "",
3181 		    "ibmf_i_get_pkeyix() exit\n");
3182 		return (IBMF_SUCCESS);
3183 	}
3184 
3185 	/*
3186 	 * Could not find the limited member version of the pkey.
3187 	 * Now check if the full member version of the pkey is in the
3188 	 * pkey table. If not, fail the call.
3189 	 */
3190 	tpkey = pkey | IBMF_PKEY_MEMBERSHIP_MASK;
3191 	ibt_status = ibt_pkey2index(hca_handle, port, tpkey, pkeyixp);
3192 	if (ibt_status != IBT_SUCCESS) {
3193 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
3194 		    ibmf_i_get_pkeyix_err, IBMF_TNF_ERROR, "",
3195 		    "ibmf_i_get_pkeyix() error status = %d\n",
3196 		    tnf_uint, ibt_status, ibt_status);
3197 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3198 		    ibmf_i_get_pkeyix_end, IBMF_TNF_TRACE, "",
3199 		    "ibmf_i_get_pkeyix() exit\n");
3200 		return (IBMF_TRANSPORT_FAILURE);
3201 	}
3202 
3203 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_get_pkeyix_end,
3204 	    IBMF_TNF_TRACE, "", "ibmf_i_get_pkeyix(): pkey_ix = %d\n",
3205 	    tnf_int, pkeyix, *pkeyixp);
3206 	return (IBMF_SUCCESS);
3207 }
3208 
3209 /*
3210  * ibmf_i_pkey_ix_to_key():
3211  *	Figure out pkey from pkey index
3212  */
3213 int
3214 ibmf_i_pkey_ix_to_key(ibmf_ci_t *cip, uint_t port_num, uint_t pkey_ix,
3215     ib_pkey_t *pkeyp)
3216 {
3217 	ibt_status_t		ibt_status;
3218 
3219 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_pkey_ix_to_key_start,
3220 	    IBMF_TNF_TRACE, "", "ibmf_i_pkey_ix_to_key() enter\n");
3221 
3222 	ibt_status = ibt_index2pkey(cip->ci_ci_handle, port_num, pkey_ix,
3223 	    pkeyp);
3224 	if (ibt_status != IBT_SUCCESS) {
3225 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
3226 		    ibmf_i_pkey_ix_to_key, IBMF_TNF_TRACE, "",
3227 		    "ibmf_i_pkey_ix_to_key(): ibt_index2pkey failed for "
3228 		    " pkey index %d \n", tnf_uint, pkey_ix, pkey_ix);
3229 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3230 		    ibmf_i_pkey_ix_to_key_end,
3231 		    IBMF_TNF_TRACE, "", "ibmf_i_pkey_ix_to_key() exit\n");
3232 		return (IBMF_TRANSPORT_FAILURE);
3233 	}
3234 
3235 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_pkey_ix_to_key_end,
3236 	    IBMF_TNF_TRACE, "", "ibmf_i_pkey_ix_to_key() exit\n");
3237 
3238 	return (IBMF_SUCCESS);
3239 }
3240 
3241 /*
3242  * ibmf_i_ibt_to_ibmf_status():
3243  *	Map IBT return code to IBMF return code
3244  */
3245 int
3246 ibmf_i_ibt_to_ibmf_status(ibt_status_t ibt_status)
3247 {
3248 	int ibmf_status;
3249 
3250 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_ibt_to_ibmf_status_start,
3251 	    IBMF_TNF_TRACE, "", "ibmf_i_ibt_to_ibmf_status() enter, "
3252 	    "status = %d\n", tnf_uint, ibt_status, ibt_status);
3253 
3254 	switch (ibt_status) {
3255 
3256 	case IBT_SUCCESS:
3257 		ibmf_status = IBMF_SUCCESS;
3258 		break;
3259 
3260 	case IBT_INSUFF_KERNEL_RESOURCE:
3261 	case IBT_INSUFF_RESOURCE:
3262 	case IBT_QP_FULL:
3263 		ibmf_status = IBMF_NO_RESOURCES;
3264 		break;
3265 
3266 	case IBT_HCA_IN_USE:
3267 	case IBT_QP_IN_USE:
3268 	case IBT_CQ_BUSY:
3269 	case IBT_PD_IN_USE:
3270 	case IBT_MR_IN_USE:
3271 		ibmf_status = IBMF_BUSY;
3272 		break;
3273 
3274 	default:
3275 		ibmf_status = IBMF_FAILURE;
3276 		break;
3277 	}
3278 
3279 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_ibt_to_ibmf_status_end,
3280 	    IBMF_TNF_TRACE, "", "ibmf_i_ibt_to_ibmf_status() exit, "
3281 	    "ibt_status = %d, ibmf_status = %d\n", tnf_uint, ibt_status,
3282 	    ibt_status, tnf_int, ibmf_status, ibmf_status);
3283 
3284 	return (ibmf_status);
3285 }
3286 
3287 /*
3288  * ibmf_i_ibt_wc_to_ibmf_status():
3289  *	Map work completion code to IBMF return code
3290  */
3291 int
3292 ibmf_i_ibt_wc_to_ibmf_status(ibt_wc_status_t ibt_wc_status)
3293 {
3294 	int ibmf_status;
3295 
3296 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
3297 	    ibmf_i_ibt_wc_to_ibmf_status_start, IBMF_TNF_TRACE, "",
3298 	    "ibmf_i_ibt_to_ibmf_status() enter, status = %d\n",
3299 	    tnf_uint, ibt_wc_status, ibt_wc_status);
3300 
3301 	switch (ibt_wc_status) {
3302 
3303 	case IBT_WC_SUCCESS:
3304 		ibmf_status = IBMF_SUCCESS;
3305 		break;
3306 
3307 	default:
3308 		ibmf_status = IBMF_FAILURE;
3309 		break;
3310 	}
3311 
3312 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
3313 	    ibmf_i_ibt_wc_to_ibmf_status_end, IBMF_TNF_TRACE, "",
3314 	    "ibmf_i_ibt_to_ibmf_status() exit, wc_status = %d, "
3315 	    "ibmf_status = %d\n", tnf_uint, ibt_wc_status,
3316 	    ibt_wc_status, tnf_int, ibmf_status, ibmf_status);
3317 
3318 	return (ibmf_status);
3319 }
3320 
3321 /*
3322  * ibmf_i_is_ibmf_handle_valid():
3323  *	Validate the ibmf handle
3324  */
3325 int
3326 ibmf_i_is_ibmf_handle_valid(ibmf_handle_t ibmf_handle)
3327 {
3328 	ibmf_ci_t	*cip;
3329 	ibmf_client_t	*clp, *clientp = (ibmf_client_t *)ibmf_handle;
3330 
3331 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3332 	    ibmf_i_is_ibmf_handle_valid_start, IBMF_TNF_TRACE, "",
3333 	    "ibmf_i_is_ibmf_handle_valid() enter\n");
3334 
3335 	mutex_enter(&ibmf_statep->ibmf_mutex);
3336 
3337 	cip = ibmf_statep->ibmf_ci_list;
3338 
3339 	/* iterate through all the channel interace contexts */
3340 	while (cip != NULL) {
3341 
3342 		mutex_enter(&cip->ci_clients_mutex);
3343 
3344 		clp = cip->ci_clients;
3345 
3346 		/* search all registration contexts for this ci */
3347 		while (clp != NULL) {
3348 			if (clp == clientp)
3349 				break;
3350 			clp = clp->ic_next;
3351 		}
3352 
3353 		mutex_exit(&cip->ci_clients_mutex);
3354 
3355 		if (clp == clientp) {
3356 			/* ci found */
3357 			break;
3358 		} else {
3359 			/* ci not found, move onto next ci */
3360 			cip = cip->ci_next;
3361 		}
3362 	}
3363 
3364 	mutex_exit(&ibmf_statep->ibmf_mutex);
3365 
3366 	if (cip != NULL) {
3367 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3368 		    ibmf_i_is_ibmf_handle_valid_end, IBMF_TNF_TRACE, "",
3369 		    "ibmf_i_is_ibmf_handle_valid() exit\n");
3370 		return (IBMF_SUCCESS);
3371 	} else {
3372 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3373 		    ibmf_i_is_ibmf_handle_valid_end, IBMF_TNF_TRACE, "",
3374 		    "ibmf_i_is_ibmf_handle_valid() failure exit\n");
3375 		return (IBMF_FAILURE);
3376 	}
3377 }
3378 
3379 /*
3380  * ibmf_i_is_qp_handle_valid():
3381  *	Validate the QP handle
3382  */
3383 int
3384 ibmf_i_is_qp_handle_valid(ibmf_handle_t ibmf_handle,
3385     ibmf_qp_handle_t ibmf_qp_handle)
3386 {
3387 	ibmf_client_t	*clientp = (ibmf_client_t *)ibmf_handle;
3388 	ibmf_alt_qp_t	*alt_qp, *qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
3389 	ibmf_ci_t	*cip = clientp->ic_myci;
3390 
3391 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3392 	    ibmf_i_is_qp_handle_valid_start, IBMF_TNF_TRACE, "",
3393 	    "ibmf_i_is_qp_handle_valid() enter\n");
3394 
3395 	/* the default qp handle is always valid */
3396 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT)
3397 		return (IBMF_SUCCESS);
3398 
3399 	mutex_enter(&cip->ci_mutex);
3400 
3401 	alt_qp = cip->ci_alt_qp_list;
3402 
3403 	while (alt_qp != NULL) {
3404 		if (alt_qp == qpp) {
3405 			/* qp handle found */
3406 			break;
3407 		} else {
3408 			/* qp handle not found, get next qp on list */
3409 			alt_qp = alt_qp->isq_next;
3410 		}
3411 	}
3412 
3413 	mutex_exit(&cip->ci_mutex);
3414 
3415 	if (alt_qp != NULL) {
3416 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3417 		    ibmf_i_is_qp_handle_valid_end, IBMF_TNF_TRACE, "",
3418 		    "ibmf_i_is_qp_handle_valid() exit\n");
3419 		return (IBMF_SUCCESS);
3420 	} else {
3421 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3422 		    ibmf_i_is_qp_handle_valid_end, IBMF_TNF_TRACE, "",
3423 		    "ibmf_i_is_qp_handle_valid() failure exit\n");
3424 		return (IBMF_FAILURE);
3425 	}
3426 }
3427 
3428 void
3429 ibmf_dprintf(int l, const char *fmt, ...)
3430 {
3431 	va_list ap;
3432 
3433 	if ((l) > ibmf_trace_level) {
3434 
3435 		return;
3436 	}
3437 
3438 	va_start(ap, fmt);
3439 	(void) vprintf(fmt, ap);
3440 	va_end(ap);
3441 }
3442 
3443 /*
3444  * ibmf_setup_term_ctx():
3445  * Sets up a message context that is the duplicate of the one
3446  * passed in the regmsgimplp argument. The duplicate message context
3447  * is not visible to the client. It is managed internally by ibmf
3448  * to process the RMPP receiver termination flow logic for the
3449  * transaction while the client is notified of the completion of the
3450  * same transaction (i.e. all the solicited data has been received).
3451  */
3452 int
3453 ibmf_setup_term_ctx(ibmf_client_t *clientp, ibmf_msg_impl_t *regmsgimplp)
3454 {
3455 	ibmf_msg_impl_t	*msgimplp;
3456 	size_t		offset;
3457 	uint32_t	cl_hdr_sz, cl_hdr_off;
3458 	int		status;
3459 
3460 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3461 	    ibmf_setup_term_ctx_start, IBMF_TNF_TRACE, "",
3462 	    "ibmf_setup_term_ctx() enter\n");
3463 
3464 	/*
3465 	 * Allocate the termination message context
3466 	 */
3467 	msgimplp = (ibmf_msg_impl_t *)kmem_zalloc(sizeof (ibmf_msg_impl_t),
3468 	    KM_NOSLEEP);
3469 	if (msgimplp == NULL) {
3470 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
3471 		    ibmf_setup_term_ctx_error, IBMF_TNF_ERROR, "",
3472 		    "ibmf_setup_term_ctx(): %s\n", tnf_string, msg,
3473 		    "message mem allocation failure");
3474 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3475 		    ibmf_setup_term_ctx_end, IBMF_TNF_TRACE, "",
3476 		    "ibmf_setup_term_ctx() exit\n");
3477 		return (IBMF_NO_RESOURCES);
3478 	}
3479 
3480 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msgimplp))
3481 
3482 	/* Copy the message context to the termination message structure */
3483 	*msgimplp = *regmsgimplp;
3484 
3485 	/* Initialize the message mutex */
3486 	mutex_init(&msgimplp->im_mutex, NULL, MUTEX_DRIVER, NULL);
3487 
3488 	/*
3489 	 * Allocate enough memory for the MAD header only.
3490 	 */
3491 	msgimplp->im_msgbufs_recv.im_bufs_mad_hdr =
3492 	    (ib_mad_hdr_t *)kmem_zalloc(IBMF_MAD_SIZE, KM_NOSLEEP);
3493 	if (msgimplp->im_msgbufs_recv.im_bufs_mad_hdr == NULL) {
3494 		kmem_free(msgimplp, sizeof (ibmf_msg_impl_t));
3495 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
3496 		    ibmf_setup_term_ctx_error, IBMF_TNF_ERROR, "",
3497 		    "ibmf_setup_term_ctx(): %s\n", tnf_string, msg,
3498 		    "recv buf mem allocation failure");
3499 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3500 		    ibmf_setup_term_ctx_end, IBMF_TNF_TRACE, "",
3501 		    "ibmf_setup_term_ctx() exit\n");
3502 		return (IBMF_NO_RESOURCES);
3503 	}
3504 
3505 	/* Copy over just the MAD header contents */
3506 	bcopy((const void *)regmsgimplp->im_msgbufs_recv.im_bufs_mad_hdr,
3507 	    (void *)msgimplp->im_msgbufs_recv.im_bufs_mad_hdr,
3508 	    sizeof (ib_mad_hdr_t));
3509 
3510 	offset = sizeof (ib_mad_hdr_t);
3511 	ibmf_i_mgt_class_to_hdr_sz_off(
3512 	    regmsgimplp->im_msgbufs_recv.im_bufs_mad_hdr->MgmtClass,
3513 	    &cl_hdr_sz, &cl_hdr_off);
3514 	offset += cl_hdr_off;
3515 
3516 	/*
3517 	 * Copy the management class header
3518 	 */
3519 	msgimplp->im_msgbufs_recv.im_bufs_cl_hdr =
3520 	    (uchar_t *)msgimplp->im_msgbufs_recv.im_bufs_mad_hdr + offset;
3521 	msgimplp->im_msgbufs_recv.im_bufs_cl_hdr_len =
3522 	    regmsgimplp->im_msgbufs_recv.im_bufs_cl_hdr_len;
3523 	bcopy((void *)regmsgimplp->im_msgbufs_recv.im_bufs_cl_hdr,
3524 	    (void *)msgimplp->im_msgbufs_recv.im_bufs_cl_hdr,
3525 	    regmsgimplp->im_msgbufs_recv.im_bufs_cl_hdr_len);
3526 
3527 	/*
3528 	 * Clear the termination message timers copied from the regular message
3529 	 * since ibmf_i_set_timer() expects them to be cleared.
3530 	 */
3531 	msgimplp->im_rp_timeout_id = 0;
3532 	msgimplp->im_tr_timeout_id = 0;
3533 
3534 	/* Mark this message as being in a receiver RMPP mode */
3535 	msgimplp->im_flags |= IBMF_MSG_FLAGS_RECV_RMPP;
3536 
3537 	/* Mark this message as being a "termination flow" message */
3538 	msgimplp->im_flags |= IBMF_MSG_FLAGS_TERMINATION;
3539 
3540 	/*
3541 	 * Clear the IBMF_MSG_FLAGS_SET_TERMINATION copied over from the regular
3542 	 * message.
3543 	 */
3544 	msgimplp->im_flags &= ~IBMF_MSG_FLAGS_SET_TERMINATION;
3545 
3546 	/*
3547 	 * Clear the trans_state RECV_DONE and DONE flags so that the
3548 	 * protocol continues with the termination message context.
3549 	 */
3550 	msgimplp->im_trans_state_flags &= ~IBMF_TRANS_STATE_FLAG_RECV_DONE;
3551 	msgimplp->im_trans_state_flags &= ~IBMF_TRANS_STATE_FLAG_DONE;
3552 
3553 	/* Clear out references to the old UD dest handles */
3554 	msgimplp->im_ibmf_ud_dest = NULL;
3555 	msgimplp->im_ud_dest = NULL;
3556 
3557 	/*
3558 	 * Request new UD dest resources for the termination phase.
3559 	 * The old UD dest resources are freed when the IBMF client
3560 	 * calls ibmf_free_msg(), so they cannot be relied on to exist
3561 	 * when the RMPP termination loop completes.
3562 	 */
3563 	status = ibmf_i_alloc_ud_dest(clientp, msgimplp, &msgimplp->im_ud_dest,
3564 	    B_FALSE);
3565 	if (status != IBMF_SUCCESS) {
3566 		kmem_free(msgimplp, sizeof (ibmf_msg_impl_t));
3567 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
3568 		    ibmf_setup_term_ctx_err, IBMF_TNF_ERROR, "",
3569 		    "ibmf_setup_term_ctx(): %s, status = %d\n",
3570 		    tnf_string, msg, "UD destination resource allocation"
3571 		    " failed", tnf_int, ibmf_status, status);
3572 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3573 		    ibmf_setup_term_ctx_end, IBMF_TNF_TRACE, "",
3574 		    "ibmf_setup_term_ctx() exit\n");
3575 		return (status);
3576 	}
3577 
3578 	/*
3579 	 * Add the message to the termination client list by virtue of
3580 	 * having the IBMF_MSG_FLAGS_TERMINATION "im_flags" flag set.
3581 	 */
3582 	ibmf_i_client_add_msg(clientp, msgimplp);
3583 
3584 	/*
3585 	 * Increase the "allocted messages" count so that the client
3586 	 * does not unregister before this message has been freed.
3587 	 * This is necessary because we want the client context to
3588 	 * be around when the receive timeout expires for this termination
3589 	 * loop, otherwise the code will access freed memory and crash.
3590 	 */
3591 	mutex_enter(&clientp->ic_mutex);
3592 	clientp->ic_msgs_alloced++;
3593 	mutex_exit(&clientp->ic_mutex);
3594 
3595 	mutex_enter(&msgimplp->im_mutex);
3596 	/* Set the response timer for the termination message. */
3597 	ibmf_i_set_timer(ibmf_i_recv_timeout, msgimplp, IBMF_RESP_TIMER);
3598 	mutex_exit(&msgimplp->im_mutex);
3599 
3600 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_setup_term_ctx_end,
3601 	    IBMF_TNF_TRACE, "", "ibmf_setup_term_ctx() exit\n");
3602 
3603 	return (IBMF_SUCCESS);
3604 }
3605