xref: /illumos-gate/usr/src/uts/common/io/ib/mgt/ibmf/ibmf.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * This file implements the client interfaces of the IBMF.
28  */
29 
30 #include <sys/ib/mgt/ibmf/ibmf_impl.h>
31 
32 #define	IBMF_SET_CLIENT_SIGNATURE(clientp) {			\
33 		(clientp)->ic_client_sig = (void *)0xf00DdEaD;	\
34 }
35 
36 #define	IBMF_VERIFY_CLIENT_SIGNATURE(clientp)			\
37 	(((clientp) != NULL && (clientp)->ic_client_sig ==	\
38 	    (void *)0xf00DdEaD) ? B_TRUE: B_FALSE)
39 
40 #define	IBMF_INVALID_PKEY(pkey)	(((pkey) & 0x7FFF) == 0)
41 #define	QP1 1
42 
43 extern ibmf_state_t *ibmf_statep;
44 extern int ibmf_trace_level;
45 
46 /* ARGSUSED */
47 int
48 ibmf_register(ibmf_register_info_t *client_infop, uint_t ibmf_version,
49     uint_t flags, ibmf_async_event_cb_t client_cb, void  *client_cb_args,
50     ibmf_handle_t *ibmf_handlep, ibmf_impl_caps_t *ibmf_impl_features)
51 {
52 	ibmf_ci_t	*ibmf_cip;
53 	ibmf_qp_t	*ibmf_qpp;
54 	ibmf_client_t	*ibmf_clientp;
55 	boolean_t	error = B_FALSE;
56 	int		status = IBMF_SUCCESS;
57 	char		errmsg[128];
58 
59 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_register_start,
60 	    IBMF_TNF_TRACE, "", "ibmf_register() enter, client_infop = %p "
61 	    " ibmf_version = %d, flags = 0x%x, ibmf_impl_featuresp = %p\n",
62 	    tnf_opaque, client_infop, client_infop,
63 	    tnf_uint, ibmf_version, ibmf_version, tnf_uint, flags, flags,
64 	    tnf_opaque, ibmf_impl_features, ibmf_impl_features);
65 
66 	/* validate client_infop and ibmf_handlep */
67 	if ((client_infop == NULL) || (ibmf_handlep == NULL) ||
68 	    (ibmf_impl_features == NULL)) {
69 		(void) sprintf(errmsg,
70 		    "invalid argument, NULL pointer argument");
71 		error = B_TRUE;
72 		status = IBMF_INVALID_ARG;
73 		goto bail;
74 	}
75 
76 	/* check IBMF version */
77 	if (ibmf_version != IBMF_VERSION) {
78 		(void) sprintf(errmsg, "Bad version");
79 		error = B_TRUE;
80 		status = IBMF_BAD_VERSION;
81 		goto bail;
82 	}
83 
84 	/* check flags validity */
85 	if ((flags & IBMF_REG_FLAG_NO_OFFLOAD) &&
86 	    (flags & IBMF_REG_FLAG_SINGLE_OFFLOAD)) {
87 		(void) sprintf(errmsg, "Bad flags");
88 		error = B_TRUE;
89 		status = IBMF_BAD_FLAGS;
90 		goto bail;
91 	}
92 
93 	/* check client mask and size */
94 	status = ibmf_i_validate_class_mask(client_infop);
95 	if (status != IBMF_SUCCESS) {
96 		(void) sprintf(errmsg, "invalid class");
97 		error = B_TRUE;
98 		goto bail;
99 	}
100 	/*
101 	 * verify the node identified by ir_ci_guid exists and that the
102 	 * port ir_port_num is valid.
103 	 */
104 	status = ibmf_i_validate_ci_guid_and_port(client_infop->ir_ci_guid,
105 	    client_infop->ir_port_num);
106 	if (status != IBMF_SUCCESS) {
107 		(void) sprintf(errmsg, "guid/port validation failed");
108 		error = B_TRUE;
109 		goto bail;
110 	}
111 
112 	/* get the ci */
113 	status = ibmf_i_get_ci(client_infop, &ibmf_cip);
114 	if (status != IBMF_SUCCESS) {
115 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
116 		    ibmf_register_error, IBMF_TNF_ERROR, "",
117 		    "ibmf_register(): %s, guid = 0x%p\n",
118 		    tnf_string, msg, "unable to get ci",
119 		    tnf_ulonglong, guid, client_infop->ir_ci_guid);
120 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_register_end,
121 		    IBMF_TNF_TRACE, "", "ibmf_register() exit\n");
122 		return (status);
123 	}
124 
125 	/*
126 	 * check if classes and port are already registered for.
127 	 */
128 	status = ibmf_i_validate_classes_and_port(ibmf_cip, client_infop);
129 	if (status != IBMF_SUCCESS) {
130 		mutex_enter(&ibmf_cip->ci_mutex);
131 		IBMF_ADD32_PORT_KSTATS(ibmf_cip, client_regs_failed, 1);
132 		mutex_exit(&ibmf_cip->ci_mutex);
133 		/* release ci */
134 		ibmf_i_release_ci(ibmf_cip);
135 		(void) sprintf(errmsg,
136 		    "class and port already registered for or unsupported");
137 		error = B_TRUE;
138 		goto bail;
139 	}
140 
141 	/*
142 	 * the class is valid, get qp and alloc the client
143 	 */
144 	/* obtain the qp corresponding to the port and classes */
145 	status = ibmf_i_get_qp(ibmf_cip, client_infop->ir_port_num,
146 	    client_infop->ir_client_class, &ibmf_qpp);
147 	if (status != IBMF_SUCCESS) {
148 		mutex_enter(&ibmf_cip->ci_mutex);
149 		IBMF_ADD32_PORT_KSTATS(ibmf_cip, client_regs_failed, 1);
150 		mutex_exit(&ibmf_cip->ci_mutex);
151 		ibmf_i_release_ci(ibmf_cip);
152 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
153 		    ibmf_register_error, IBMF_TNF_ERROR, "",
154 		    "ibmf_register(): %s, class = 0x%x\n",
155 		    tnf_string, msg, "can't get qp",
156 		    tnf_int, class, client_infop->ir_client_class);
157 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_register_end,
158 		    IBMF_TNF_TRACE, "", "ibmf_register() exit\n");
159 		return (status);
160 	}
161 
162 	/* alloc the client */
163 	status = ibmf_i_alloc_client(client_infop, flags, &ibmf_clientp);
164 	if (status != IBMF_SUCCESS) {
165 		mutex_enter(&ibmf_cip->ci_mutex);
166 		IBMF_ADD32_PORT_KSTATS(ibmf_cip, client_regs_failed, 1);
167 		mutex_exit(&ibmf_cip->ci_mutex);
168 		ibmf_i_release_ci(ibmf_cip);
169 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
170 		    ibmf_register_error, IBMF_TNF_ERROR, "",
171 		    "ibmf_register(): %s, class = 0x%x\n",
172 		    tnf_string, msg, "can't alloc client",
173 		    tnf_int, class, client_infop->ir_client_class);
174 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_register_end,
175 		    IBMF_TNF_TRACE, "", "ibmf_register() exit\n");
176 		return (status);
177 	}
178 
179 	ASSERT(ibmf_clientp != NULL);
180 
181 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ibmf_clientp))
182 
183 	/* initialize the IBMF client context */
184 	ibmf_clientp->ic_myci = ibmf_cip;
185 	ibmf_clientp->ic_qp = ibmf_qpp;
186 	ibmf_clientp->ic_ci_handle = ibmf_cip->ci_ci_handle;
187 
188 	ibmf_clientp->ic_reg_flags = flags;
189 
190 	ibmf_clientp->ic_async_cb = client_cb;
191 	ibmf_clientp->ic_async_cb_arg = client_cb_args;
192 
193 	IBMF_SET_CLIENT_SIGNATURE(ibmf_clientp);
194 
195 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*ibmf_clientp))
196 
197 	/* add the client to the list of clients */
198 	ibmf_i_add_client(ibmf_cip, ibmf_clientp);
199 
200 	/* increment kstats for number of registered clients */
201 	mutex_enter(&ibmf_cip->ci_mutex);
202 	IBMF_ADD32_PORT_KSTATS(ibmf_cip, clients_registered, 1);
203 	mutex_exit(&ibmf_cip->ci_mutex);
204 
205 	/* Setup ibmf_handlep -- handle is last allocated clientp */
206 	*ibmf_handlep = (ibmf_handle_t)ibmf_clientp;
207 	*ibmf_impl_features = 0;
208 
209 bail:
210 	if (error) {
211 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
212 		    ibmf_register_error, IBMF_TNF_ERROR, "",
213 		    "ibmf_register(): %s\n", tnf_string, msg, errmsg);
214 	}
215 
216 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_register_end,
217 	    IBMF_TNF_TRACE, "", "ibmf_register() exit, ibmf_handle = %p\n",
218 	    tnf_opaque, ibmf_handle, *ibmf_handlep);
219 
220 	return (status);
221 }
222 
223 /* ARGSUSED */
224 int
225 ibmf_unregister(ibmf_handle_t *ibmf_handlep, uint_t flags)
226 {
227 	ibmf_ci_t	*cip;
228 	ibmf_client_t	*clientp;
229 	boolean_t	error = B_FALSE;
230 	int		status = IBMF_SUCCESS;
231 	char		errmsg[128];
232 	int		secs;
233 
234 	clientp = (ibmf_client_t *)*ibmf_handlep;
235 
236 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_unregister_start,
237 	    IBMF_TNF_TRACE, "", "ibmf_unregister() enter, "
238 	    "ibmf_handlep = %p, flags = 0x%x\n",
239 	    tnf_opaque, ibmf_handle, *ibmf_handlep, tnf_uint, flags, flags);
240 
241 	/* check for null ibmf_handlep */
242 	if (ibmf_handlep == NULL) {
243 		(void) sprintf(errmsg,
244 		    "invalid argument, NULL pointer argument");
245 		error = B_TRUE;
246 		status = IBMF_INVALID_ARG;
247 		goto bail;
248 	}
249 
250 	/* validate ibmf_handlep */
251 	if (ibmf_i_is_ibmf_handle_valid(*ibmf_handlep) != IBMF_SUCCESS) {
252 		(void) sprintf(errmsg, "bad ibmf registration handle");
253 		error = B_TRUE;
254 		status = IBMF_BAD_HANDLE;
255 		goto bail;
256 	}
257 
258 	/* check signature */
259 	if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
260 		(void) sprintf(errmsg, "bad client signature");
261 		error = B_TRUE;
262 		status = IBMF_BAD_HANDLE;
263 		goto bail;
264 	}
265 
266 	/*
267 	 * Verify the client does not have a receive callback registered.
268 	 * If there are messages, give some time for the messages to be
269 	 * cleaned up.
270 	 */
271 	secs = 60;
272 	mutex_enter(&clientp->ic_mutex);
273 	while (clientp->ic_recv_cb == NULL && clientp->ic_msgs_alloced != 0 &&
274 	    secs > 0) {
275 		mutex_exit(&clientp->ic_mutex);
276 		delay(drv_usectohz(1000000)); /* one second delay */
277 		secs--;
278 		mutex_enter(&clientp->ic_mutex);
279 	}
280 
281 	if (clientp->ic_recv_cb != NULL || clientp->ic_msgs_alloced != 0) {
282 		IBMF_TRACE_4(IBMF_TNF_NODEBUG, DPRINT_L1,
283 		    ibmf_unregister_err, IBMF_TNF_ERROR, "",
284 		    "ibmf_unregister(): %s, flags = 0x%x, recv_cb = 0x%p, "
285 		    "msgs_alloced = %d\n",
286 		    tnf_string, msg, "busy with resources", tnf_uint, ic_flags,
287 		    clientp->ic_flags, tnf_opaque, recv_cb, clientp->ic_recv_cb,
288 		    tnf_uint, msgs_allocd, clientp->ic_msgs_alloced);
289 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_unregister_end,
290 		    IBMF_TNF_TRACE, "", "ibmf_unregister() exit\n");
291 		mutex_exit(&clientp->ic_mutex);
292 		return (IBMF_BUSY);
293 	}
294 
295 	mutex_exit(&clientp->ic_mutex);
296 
297 	cip = clientp->ic_myci;
298 
299 	/* remove the client from the list of clients */
300 	ibmf_i_delete_client(cip, clientp);
301 
302 	/* release the reference to the qp */
303 	ibmf_i_release_qp(cip, &clientp->ic_qp);
304 
305 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*clientp))
306 
307 	/* and free the client structure */
308 	ibmf_i_free_client(clientp);
309 
310 	/* release the ci; this may delete & free the ci structure */
311 	ibmf_i_release_ci(cip);
312 
313 	/* decrement kstats for number of registered clients */
314 	mutex_enter(&cip->ci_mutex);
315 	IBMF_SUB32_PORT_KSTATS(cip, clients_registered, 1);
316 	mutex_exit(&cip->ci_mutex);
317 
318 	*ibmf_handlep = NULL;
319 
320 bail:
321 	if (error) {
322 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
323 		    ibmf_unregister_err, IBMF_TNF_ERROR, "",
324 		    "ibmf_unregister(): %s\n", tnf_string, msg, errmsg);
325 	}
326 
327 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_unregister_end,
328 	    IBMF_TNF_TRACE, "", "ibmf_unregister() exit\n");
329 
330 	return (status);
331 }
332 
333 
334 /* ARGSUSED */
335 int
336 ibmf_setup_async_cb(ibmf_handle_t ibmf_handle, ibmf_qp_handle_t ibmf_qp_handle,
337     ibmf_msg_cb_t async_msg_cb, void *async_msg_cb_args, uint_t flags)
338 {
339 	ibmf_client_t	*clientp;
340 	boolean_t	error = B_FALSE;
341 	int		status = IBMF_SUCCESS;
342 	char		errmsg[128];
343 
344 	clientp = (ibmf_client_t *)ibmf_handle;
345 
346 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_setup_async_cb_start,
347 	    IBMF_TNF_TRACE, "", "ibmf_setup_async_cb() enter, "
348 	    "ibmf_handlep = %p, cb = 0x%p, cb_args = 0x%p, flags = 0x%x\n",
349 	    tnf_opaque, ibmf_handle, ibmf_handle, tnf_opaque, cb,
350 	    async_msg_cb, tnf_opaque, cb_args, async_msg_cb_args,
351 	    tnf_uint, flags, flags);
352 
353 	/* check for null ibmf_handlep */
354 	if (ibmf_handle == NULL) {
355 		(void) sprintf(errmsg,
356 		    "invalid argument, NULL pointer argument");
357 		error = B_TRUE;
358 		status = IBMF_INVALID_ARG;
359 		goto bail;
360 	}
361 
362 	/* validate ibmf_handle */
363 	if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
364 		(void) sprintf(errmsg, "bad ibmf registration handle");
365 		error = B_TRUE;
366 		status = IBMF_BAD_HANDLE;
367 		goto bail;
368 	}
369 
370 	/* validate ibmf_qp_handle */
371 	if (ibmf_i_is_qp_handle_valid(ibmf_handle, ibmf_qp_handle) !=
372 	    IBMF_SUCCESS) {
373 		(void) sprintf(errmsg, "bad qp handle");
374 		error = B_TRUE;
375 		status = IBMF_BAD_QP_HANDLE;
376 		goto bail;
377 	}
378 
379 	/* check signature */
380 	if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
381 		(void) sprintf(errmsg, "bad signature");
382 		error = B_TRUE;
383 		status = IBMF_BAD_HANDLE;
384 		goto bail;
385 	}
386 
387 	ASSERT(clientp->ic_myci != NULL);
388 
389 	/* store the registered callback in the appropriate context */
390 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
391 
392 		/*
393 		 * if using the default QP handle, store the callback in
394 		 * the client context
395 		 */
396 		mutex_enter(&clientp->ic_mutex);
397 
398 		/* check if the callback has already been registered */
399 		if (clientp->ic_recv_cb != NULL) {
400 			mutex_exit(&clientp->ic_mutex);
401 			(void) sprintf(errmsg, "cb already exists");
402 			error = B_TRUE;
403 			status = IBMF_CB_REGISTERED;
404 			goto bail;
405 		}
406 
407 		clientp->ic_recv_cb = async_msg_cb;
408 		clientp->ic_recv_cb_arg = async_msg_cb_args;
409 		mutex_exit(&clientp->ic_mutex);
410 
411 	} else {
412 		ibmf_alt_qp_t *qp_ctxp = (ibmf_alt_qp_t *)ibmf_qp_handle;
413 
414 		/*
415 		 * if using an alternate QP handle, store the callback in
416 		 * the alternate QP context because there can be more than
417 		 * one alternate QP associated with a client
418 		 */
419 		mutex_enter(&qp_ctxp->isq_mutex);
420 
421 		/* check if the callback has already been registered */
422 		if (qp_ctxp->isq_recv_cb != NULL) {
423 			mutex_exit(&qp_ctxp->isq_mutex);
424 			(void) sprintf(errmsg, "cb already exists");
425 			error = B_TRUE;
426 			status = IBMF_CB_REGISTERED;
427 			goto bail;
428 		}
429 
430 		qp_ctxp->isq_recv_cb = async_msg_cb;
431 		qp_ctxp->isq_recv_cb_arg = async_msg_cb_args;
432 
433 		mutex_exit(&qp_ctxp->isq_mutex);
434 	}
435 
436 bail:
437 	if (error) {
438 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
439 		    ibmf_setup_async_cb_err, IBMF_TNF_ERROR, "",
440 		    "ibmf_setup_async_cb(): %s\n", tnf_string, msg, errmsg);
441 	}
442 
443 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_setup_async_cb_end,
444 	    IBMF_TNF_TRACE, "", "ibmf_setup_async_cb() exit\n");
445 
446 	return (status);
447 }
448 
449 
450 /* ARGSUSED */
451 int
452 ibmf_tear_down_async_cb(ibmf_handle_t ibmf_handle,
453     ibmf_qp_handle_t ibmf_qp_handle, uint_t flags)
454 {
455 	ibmf_client_t	*clientp;
456 	boolean_t	error = B_FALSE;
457 	int		status = IBMF_SUCCESS;
458 	char		errmsg[128];
459 
460 	clientp = (ibmf_client_t *)ibmf_handle;
461 
462 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_tear_down_async_cb_start,
463 	    IBMF_TNF_TRACE, "", "ibmf_tear_down_async_cb() enter, "
464 	    "ibmf_handlep = %p, ibmf_qp_handle = %p, flags = 0x%x\n",
465 	    tnf_opaque, ibmf_handle, ibmf_handle,
466 	    tnf_opaque, ibmf_qp_handle, ibmf_qp_handle, tnf_uint, flags, flags);
467 
468 	/* check for null ibmf_handlep */
469 	if (ibmf_handle == NULL) {
470 		(void) sprintf(errmsg,
471 		    "invalid argument, NULL pointer argument");
472 		error = B_TRUE;
473 		status = IBMF_INVALID_ARG;
474 		goto bail;
475 	}
476 
477 	/* validate ibmf_handle */
478 	if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
479 		(void) sprintf(errmsg, "bad ibmf registration handle");
480 		error = B_TRUE;
481 		status = IBMF_BAD_HANDLE;
482 		goto bail;
483 	}
484 
485 	/* validate ibmf_qp_handle */
486 	if (ibmf_i_is_qp_handle_valid(ibmf_handle, ibmf_qp_handle) !=
487 	    IBMF_SUCCESS) {
488 		(void) sprintf(errmsg, "bad qp handle");
489 		error = B_TRUE;
490 		status = IBMF_BAD_QP_HANDLE;
491 		goto bail;
492 	}
493 
494 	/* check signature */
495 	if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
496 		(void) sprintf(errmsg, "bad signature");
497 		error = B_TRUE;
498 		status = IBMF_BAD_HANDLE;
499 		goto bail;
500 	}
501 
502 	ASSERT(clientp->ic_myci != NULL);
503 
504 	/* remove the registered callback from the appropriate context */
505 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
506 
507 		mutex_enter(&clientp->ic_mutex);
508 
509 		/* check if callback has not been registered */
510 		if (clientp->ic_recv_cb == NULL) {
511 			mutex_exit(&clientp->ic_mutex);
512 			(void) sprintf(errmsg, "no cb exists");
513 			error = B_TRUE;
514 			status = IBMF_CB_NOT_REGISTERED;
515 			goto bail;
516 		}
517 
518 		/*
519 		 * if an unsolicited MAD just arrived for this
520 		 * client, wait for it to be processed
521 		 */
522 		while (clientp->ic_flags & IBMF_CLIENT_RECV_CB_ACTIVE) {
523 			clientp->ic_flags |= IBMF_CLIENT_TEAR_DOWN_CB;
524 			cv_wait(&clientp->ic_recv_cb_teardown_cv,
525 			    &clientp->ic_mutex);
526 			clientp->ic_flags &= ~IBMF_CLIENT_TEAR_DOWN_CB;
527 		}
528 
529 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(clientp->ic_recv_cb,
530 		     clientp->ic_recv_cb_arg))
531 
532 		/*
533 		 * if using the default QP handle, remove the callback from
534 		 * the client context
535 		 */
536 		clientp->ic_recv_cb = NULL;
537 		clientp->ic_recv_cb_arg = NULL;
538 
539 		ASSERT((clientp->ic_flags & IBMF_CLIENT_RECV_CB_ACTIVE) == 0);
540 
541 		mutex_exit(&clientp->ic_mutex);
542 	} else {
543 		ibmf_alt_qp_t *qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
544 
545 		mutex_enter(&qpp->isq_mutex);
546 
547 		/* check if callback has not been registered */
548 		if (qpp->isq_recv_cb == NULL) {
549 			mutex_exit(&qpp->isq_mutex);
550 			(void) sprintf(errmsg, "no cb exists");
551 			error = B_TRUE;
552 			status = IBMF_CB_NOT_REGISTERED;
553 			goto bail;
554 		}
555 
556 		/*
557 		 * if an unsolicited MAD just arrived for this
558 		 * client on the alternate QP, wait for it to be processed
559 		 */
560 		while (qpp->isq_flags & IBMF_CLIENT_RECV_CB_ACTIVE) {
561 			qpp->isq_flags |= IBMF_CLIENT_TEAR_DOWN_CB;
562 			cv_wait(&qpp->isq_recv_cb_teardown_cv,
563 			    &qpp->isq_mutex);
564 			qpp->isq_flags &= ~IBMF_CLIENT_TEAR_DOWN_CB;
565 		}
566 
567 		/*
568 		 * if using an alternate QP handle, remove the callback from
569 		 * the alternate QP context
570 		 */
571 		qpp->isq_recv_cb = NULL;
572 		qpp->isq_recv_cb_arg = NULL;
573 
574 		ASSERT((qpp->isq_flags & IBMF_CLIENT_RECV_CB_ACTIVE) == 0);
575 
576 		mutex_exit(&qpp->isq_mutex);
577 	}
578 
579 bail:
580 	if (error) {
581 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
582 		    ibmf_tear_down_async_cb_err, IBMF_TNF_ERROR, "",
583 		    "ibmf_tear_down_async_cb(): %s\n", tnf_string, msg, errmsg);
584 	}
585 
586 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_tear_down_async_cb_end,
587 	    IBMF_TNF_TRACE, "", "ibmf_tear_down_async_cb() exit\n");
588 
589 	return (status);
590 }
591 
592 
593 int
594 ibmf_alloc_msg(ibmf_handle_t ibmf_handle, int flag, ibmf_msg_t **ibmf_msgpp)
595 {
596 	ibmf_msg_impl_t	*ibmf_msg_impl;
597 	ibmf_client_t	*clientp;
598 	int		km_flags;
599 	boolean_t	error = B_FALSE;
600 	int		status = IBMF_SUCCESS;
601 	char		errmsg[128];
602 
603 	clientp = (ibmf_client_t *)ibmf_handle;
604 
605 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_alloc_msg_start,
606 	    IBMF_TNF_TRACE, "", "ibmf_alloc_msg() enter, "
607 	    "ibmf_handle = %p, flags = 0x%x\n",
608 	    tnf_opaque, ibmf_handle, ibmf_handle, tnf_uint, flag, flag);
609 
610 	/* check for null ibmf_handle and ibmf_msgpp */
611 	if ((ibmf_handle == NULL) || (ibmf_msgpp == NULL)) {
612 		(void) sprintf(errmsg,
613 		    "invalid argument, NULL pointer argument");
614 		error = B_TRUE;
615 		status = IBMF_INVALID_ARG;
616 		goto bail;
617 	}
618 
619 	/* validate ibmf_handle */
620 	if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
621 		(void) sprintf(errmsg, "bad ibmf registration handle");
622 		error = B_TRUE;
623 		status = IBMF_BAD_HANDLE;
624 		goto bail;
625 	}
626 
627 	/* check signature */
628 	if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
629 		(void) sprintf(errmsg, "bad signature");
630 		error = B_TRUE;
631 		status = IBMF_BAD_HANDLE;
632 		goto bail;
633 	}
634 
635 	/* validate flag */
636 	if (flag != IBMF_ALLOC_SLEEP && flag != IBMF_ALLOC_NOSLEEP) {
637 		(void) sprintf(errmsg, "invalid flags, flags = 0x%x", flag);
638 		error = B_TRUE;
639 		status = IBMF_BAD_FLAGS;
640 		goto bail;
641 	}
642 
643 	/* set flags for kmem allocaton */
644 	km_flags = (flag == IBMF_ALLOC_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
645 
646 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ibmf_msg_impl))
647 
648 	/* call the internal function to allocate the IBMF message context */
649 	status = ibmf_i_alloc_msg(clientp, &ibmf_msg_impl, km_flags);
650 	if (status != IBMF_SUCCESS) {
651 		mutex_enter(&clientp->ic_kstat_mutex);
652 		IBMF_ADD32_KSTATS(clientp, msg_allocs_failed, 1);
653 		mutex_exit(&clientp->ic_kstat_mutex);
654 		(void) sprintf(errmsg, "message allocation failure");
655 		error = B_TRUE;
656 		goto bail;
657 	}
658 
659 	/* increment counter and kstats for number of allocated messages */
660 	mutex_enter(&clientp->ic_mutex);
661 	clientp->ic_msgs_alloced++;
662 	mutex_exit(&clientp->ic_mutex);
663 	mutex_enter(&clientp->ic_kstat_mutex);
664 	IBMF_ADD32_KSTATS(clientp, msgs_alloced, 1);
665 	mutex_exit(&clientp->ic_kstat_mutex);
666 
667 	/* initialize the msg */
668 	ibmf_msg_impl->im_client = clientp;
669 	cv_init(&ibmf_msg_impl->im_trans_cv, NULL, CV_DRIVER, NULL);
670 	mutex_init(&ibmf_msg_impl->im_mutex, NULL, MUTEX_DRIVER, NULL);
671 	*ibmf_msgpp = (ibmf_msg_t *)ibmf_msg_impl;
672 
673 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*ibmf_msg_impl))
674 
675 bail:
676 	if (error) {
677 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
678 		    ibmf_alloc_msg_err, IBMF_TNF_ERROR, "",
679 		    "ibmf_alloc_msg(): %s\n", tnf_string, msg, errmsg);
680 	}
681 
682 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_alloc_msg_end,
683 	    IBMF_TNF_TRACE, "", "ibmf_alloc_msg() exit\n");
684 
685 	return (status);
686 }
687 
688 
689 int
690 ibmf_free_msg(ibmf_handle_t ibmf_handle, ibmf_msg_t **ibmf_msgpp)
691 {
692 	ibmf_client_t	*clientp;
693 	ibmf_msg_impl_t	*ibmf_msg_impl;
694 	boolean_t	error = B_FALSE;
695 	int		status = IBMF_SUCCESS;
696 	char		errmsg[128];
697 	timeout_id_t	msg_rp_set_id, msg_tr_set_id;
698 	timeout_id_t	msg_rp_unset_id, msg_tr_unset_id;
699 
700 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_free_msg_start,
701 	    IBMF_TNF_TRACE, "", "ibmf_free_msg() enter, " "ibmf_handle = %p\n",
702 	    tnf_opaque, ibmf_handle, ibmf_handle);
703 
704 	/* check for null ibmf_handle and ibmf_msgpp */
705 	if ((ibmf_handle == NULL) || (ibmf_msgpp == NULL)) {
706 		(void) sprintf(errmsg,
707 		    "invalid argument, NULL pointer argument");
708 		error = B_TRUE;
709 		status = IBMF_INVALID_ARG;
710 		goto bail;
711 	}
712 
713 	/* validate ibmf_handle */
714 	if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
715 		(void) sprintf(errmsg, "bad ibmf registration handle");
716 		error = B_TRUE;
717 		status = IBMF_BAD_HANDLE;
718 		goto bail;
719 	}
720 
721 	ibmf_msg_impl = (ibmf_msg_impl_t *)*ibmf_msgpp;
722 
723 	/* check for null message pointer */
724 	if (ibmf_msg_impl == NULL) {
725 		(void) sprintf(errmsg, "null message");
726 		error = B_TRUE;
727 		status = IBMF_FAILURE;
728 		goto bail;
729 	}
730 
731 	mutex_enter(&ibmf_msg_impl->im_mutex);
732 
733 	/* check if message context flags indicate a busy message */
734 	if (ibmf_msg_impl->im_flags & IBMF_MSG_FLAGS_BUSY) {
735 		mutex_exit(&ibmf_msg_impl->im_mutex);
736 		(void) sprintf(errmsg, "message in use");
737 		error = B_TRUE;
738 		status = IBMF_BUSY;
739 		goto bail;
740 	}
741 
742 	ASSERT((ibmf_msg_impl->im_flags & IBMF_MSG_FLAGS_ON_LIST) == 0);
743 
744 	/* Initialize the timer ID holders */
745 	msg_rp_set_id = msg_tr_set_id = 0;
746 	msg_rp_unset_id = msg_tr_unset_id = 0;
747 
748 	/* Clear any timers that are still set */
749 
750 	if (ibmf_msg_impl->im_rp_timeout_id != 0) {
751 		msg_rp_set_id = ibmf_msg_impl->im_rp_timeout_id;
752 		ibmf_msg_impl->im_rp_timeout_id = 0;
753 	}
754 
755 	if (ibmf_msg_impl->im_tr_timeout_id != 0) {
756 		msg_tr_set_id = ibmf_msg_impl->im_tr_timeout_id;
757 		ibmf_msg_impl->im_tr_timeout_id = 0;
758 	}
759 
760 	if (ibmf_msg_impl->im_rp_unset_timeout_id != 0) {
761 		msg_rp_unset_id = ibmf_msg_impl->im_rp_unset_timeout_id;
762 		ibmf_msg_impl->im_rp_unset_timeout_id = 0;
763 	}
764 
765 	if (ibmf_msg_impl->im_tr_unset_timeout_id != 0) {
766 		msg_tr_unset_id = ibmf_msg_impl->im_tr_unset_timeout_id;
767 		ibmf_msg_impl->im_tr_unset_timeout_id = 0;
768 	}
769 
770 	/* mark the message context flags to indicate a freed message */
771 	ibmf_msg_impl->im_flags |= IBMF_MSG_FLAGS_FREE;
772 
773 	mutex_exit(&ibmf_msg_impl->im_mutex);
774 
775 	/* cast pointer to client context */
776 	clientp = (ibmf_client_t *)ibmf_handle;
777 
778 	/* check signature */
779 	if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
780 		(void) sprintf(errmsg, "bad signature");
781 		error = B_TRUE;
782 		status = IBMF_BAD_HANDLE;
783 		goto bail;
784 	}
785 
786 	/* Clear the timers */
787 	if (msg_rp_unset_id != 0) {
788 		(void) untimeout(msg_rp_unset_id);
789 	}
790 
791 	if (msg_tr_unset_id != 0) {
792 		(void) untimeout(msg_tr_unset_id);
793 	}
794 
795 	if (msg_rp_set_id != 0) {
796 		(void) untimeout(msg_rp_set_id);
797 	}
798 
799 	if (msg_tr_set_id != 0) {
800 		(void) untimeout(msg_tr_set_id);
801 	}
802 
803 	/* destroy the condition variables */
804 	cv_destroy(&ibmf_msg_impl->im_trans_cv);
805 
806 	/* decrement counter and kstats for number of allocated messages */
807 	mutex_enter(&clientp->ic_mutex);
808 	clientp->ic_msgs_alloced--;
809 	mutex_exit(&clientp->ic_mutex);
810 	mutex_enter(&clientp->ic_kstat_mutex);
811 	IBMF_SUB32_KSTATS(clientp, msgs_alloced, 1);
812 	mutex_exit(&clientp->ic_kstat_mutex);
813 
814 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ibmf_msg_impl,
815 	    ibmf_msg_impl->im_msgbufs_recv,
816 	    ibmf_msg_impl->im_msgbufs_send))
817 
818 	/* call the internal function to free the message context */
819 	ibmf_i_free_msg(ibmf_msg_impl);
820 
821 	*ibmf_msgpp = NULL;
822 
823 bail:
824 	if (error) {
825 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
826 		    ibmf_free_msg_err, IBMF_TNF_ERROR, "",
827 		    "ibmf_free_msg(): %s\n", tnf_string, msg, errmsg);
828 	}
829 
830 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_free_msg_end,
831 	    IBMF_TNF_TRACE, "", "ibmf_free_msg() exit\n");
832 
833 	return (status);
834 }
835 
836 
837 /* ARGSUSED */
838 int
839 ibmf_msg_transport(ibmf_handle_t ibmf_handle, ibmf_qp_handle_t ibmf_qp_handle,
840     ibmf_msg_t *msgp, ibmf_retrans_t *retrans, ibmf_msg_cb_t msg_cb,
841     void *msg_cb_args, uint_t flags)
842 {
843 	ibmf_client_t	*clientp;
844 	ibmf_msg_impl_t	*msgimplp;
845 	boolean_t	blocking, loopback, error = B_FALSE;
846 	int		status = IBMF_SUCCESS;
847 	sm_dr_mad_hdr_t	*dr_hdr;
848 	char		errmsg[128];
849 
850 	IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_msg_transport_start,
851 	    IBMF_TNF_TRACE, "", "ibmf_msg_transport() enter, "
852 	    "ibmf_handlep = %p, ibmf_qp_handle = %p, flags = 0x%x "
853 	    "msgp = 0x%p, retrans = 0x%p\n",
854 	    tnf_opaque, ibmf_handle, ibmf_handle,
855 	    tnf_opaque, ibmf_qp_handle, ibmf_qp_handle, tnf_uint, flags, flags,
856 	    tnf_opaque, msgp, msgp, tnf_opaque, retrans, retrans);
857 
858 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msgp,*msgimplp))
859 
860 	/* check for null ibmf_handle and msgp */
861 	if ((ibmf_handle == NULL) || (msgp == NULL)) {
862 		(void) sprintf(errmsg,
863 		    "invalid argument, NULL pointer argument");
864 		error = B_TRUE;
865 		status = IBMF_INVALID_ARG;
866 		goto bail;
867 	}
868 
869 	/* validate ibmf_handle */
870 	if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
871 		(void) sprintf(errmsg, "bad ibmf registration handle");
872 		error = B_TRUE;
873 		status = IBMF_BAD_HANDLE;
874 		goto bail;
875 	}
876 
877 	/* validate ibmf_qp_handle */
878 	if (ibmf_i_is_qp_handle_valid(ibmf_handle, ibmf_qp_handle) !=
879 	    IBMF_SUCCESS) {
880 		(void) sprintf(errmsg, "bad qp handle");
881 		error = B_TRUE;
882 		status = IBMF_BAD_QP_HANDLE;
883 		goto bail;
884 	}
885 
886 	clientp = (ibmf_client_t *)ibmf_handle;
887 
888 	/* check signature */
889 	if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
890 		(void) sprintf(errmsg, "bad signature");
891 		error = B_TRUE;
892 		status = IBMF_BAD_HANDLE;
893 		goto bail;
894 	}
895 
896 	/*
897 	 * Check the validity of the pkey and qkey in the posted packet
898 	 * For special QPs do the check for QP1 only
899 	 * For the alternate qps, the pkey and qkey should match the
900 	 * pkey and qkey maintained in the ibmf cached qp context
901 	 */
902 	if ((ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) &&
903 	    ((clientp->ic_client_info.client_class != SUBN_AGENT) &&
904 	    (clientp->ic_client_info.client_class != SUBN_MANAGER))) {
905 
906 		if ((msgp->im_local_addr.ia_p_key != IBMF_P_KEY_DEF_FULL) &&
907 		    (msgp->im_local_addr.ia_p_key != IBMF_P_KEY_DEF_LIMITED)) {
908 			(void) sprintf(errmsg,
909 			    "PKey in packet not default PKey");
910 			error = B_TRUE;
911 			status = IBMF_BAD_QP_HANDLE;
912 			goto bail;
913 		}
914 
915 		if (msgp->im_local_addr.ia_q_key != IBMF_MGMT_Q_KEY) {
916 			(void) sprintf(errmsg, "QKey in packet not Mgt QKey");
917 			error = B_TRUE;
918 			status = IBMF_BAD_QP_HANDLE;
919 			goto bail;
920 		}
921 	} else if (ibmf_qp_handle != IBMF_QP_HANDLE_DEFAULT) {
922 		ibmf_alt_qp_t *qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
923 
924 		/* alternate QP context */
925 
926 		mutex_enter(&qpp->isq_mutex);
927 
928 		if (msgp->im_local_addr.ia_p_key != qpp->isq_pkey) {
929 			mutex_exit(&qpp->isq_mutex);
930 			(void) sprintf(errmsg, "PKey in packet does not match "
931 			    "PKey in the QP context");
932 			error = B_TRUE;
933 			status = IBMF_BAD_QP_HANDLE;
934 			goto bail;
935 		}
936 
937 		if (msgp->im_local_addr.ia_q_key != qpp->isq_qkey) {
938 			mutex_exit(&qpp->isq_mutex);
939 			(void) sprintf(errmsg, "QKey in packet does not match "
940 			    "QKey in the QP context");
941 			error = B_TRUE;
942 			status = IBMF_BAD_QP_HANDLE;
943 			goto bail;
944 		}
945 
946 		mutex_exit(&qpp->isq_mutex);
947 	}
948 
949 	msgimplp = (ibmf_msg_impl_t *)msgp;
950 
951 	ASSERT(msgimplp->im_client != NULL);
952 	ASSERT(msgimplp->im_client == clientp);
953 
954 	msgimplp->im_transp_op_flags = flags;
955 
956 	mutex_enter(&msgimplp->im_mutex);
957 
958 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
959 		if (msgimplp->im_msgbufs_send.im_bufs_mad_hdr == NULL) {
960 			mutex_exit(&msgimplp->im_mutex);
961 			(void) sprintf(errmsg, "Send buffer MAD header data "
962 			    "not provided for special QP");
963 			error = B_TRUE;
964 			status = IBMF_BAD_SIZE;
965 			goto bail;
966 		}
967 	} else {
968 		ibmf_alt_qp_t *qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
969 
970 		mutex_enter(&qpp->isq_mutex);
971 
972 		if (((qpp->isq_flags & IBMF_RAW_ONLY) == 0) &&
973 		    (msgimplp->im_msgbufs_send.im_bufs_mad_hdr == NULL)) {
974 			mutex_exit(&qpp->isq_mutex);
975 			mutex_exit(&msgimplp->im_mutex);
976 			(void) sprintf(errmsg, "Send buffer MAD header data "
977 			    "not provided for alternate QP");
978 			error = B_TRUE;
979 			status = IBMF_BAD_SIZE;
980 			goto bail;
981 		}
982 		mutex_exit(&qpp->isq_mutex);
983 	}
984 
985 	/* check if client has freed the message by calling ibmf_free_msg() */
986 	if (msgimplp->im_flags & IBMF_MSG_FLAGS_FREE) {
987 		mutex_exit(&msgimplp->im_mutex);
988 		(void) sprintf(errmsg, "Message is being freed");
989 		error = B_TRUE;
990 		status = IBMF_BUSY;
991 		goto bail;
992 	}
993 
994 	/*
995 	 * check if the message is already in use in an
996 	 * ibmf_msg_transport() call
997 	 */
998 	if (msgimplp->im_flags & IBMF_MSG_FLAGS_BUSY) {
999 		mutex_exit(&msgimplp->im_mutex);
1000 		(void) sprintf(errmsg,
1001 		    "Message is being processed by an other thread");
1002 		error = B_TRUE;
1003 		status = IBMF_BUSY;
1004 		goto bail;
1005 	}
1006 
1007 	msgimplp->im_flags = IBMF_MSG_FLAGS_BUSY;
1008 
1009 	mutex_exit(&msgimplp->im_mutex);
1010 
1011 	/* check for the Directed Route SMP loopback case */
1012 	loopback = B_FALSE;
1013 	dr_hdr = (sm_dr_mad_hdr_t *)msgimplp->im_msgbufs_send.im_bufs_mad_hdr;
1014 	if ((dr_hdr->MgmtClass == MAD_MGMT_CLASS_SUBN_DIRECT_ROUTE) &&
1015 	    (dr_hdr->HopCount == 0)) {
1016 		loopback = B_TRUE;
1017 	}
1018 
1019 	/* check for and perform DR loopback on tavor */
1020 	status = ibmf_i_check_for_loopback(msgimplp, msg_cb, msg_cb_args,
1021 	    retrans, &loopback);
1022 	if (status != IBMF_SUCCESS) {
1023 		(void) sprintf(errmsg, "dr_loopback_check failed");
1024 		error = B_TRUE;
1025 		mutex_enter(&msgimplp->im_mutex);
1026 		msgimplp->im_flags &= ~IBMF_MSG_FLAGS_BUSY;
1027 		mutex_exit(&msgimplp->im_mutex);
1028 		goto bail;
1029 	}
1030 	if (loopback == B_TRUE) {
1031 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1032 		    ibmf_msg_transport_end, IBMF_TNF_TRACE, "",
1033 		    "ibmf_msg_transport() exit, dr_loopback ok\n");
1034 		return (IBMF_SUCCESS);
1035 	}
1036 
1037 	if (msg_cb == NULL) {
1038 		blocking = B_TRUE;
1039 	} else {
1040 		blocking = B_FALSE;
1041 	}
1042 
1043 	/* initialize the message context */
1044 	ibmf_i_init_msg(msgimplp, msg_cb, msg_cb_args, retrans, blocking);
1045 
1046 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msgp,*msgimplp))
1047 
1048 	/* call the internal function to transport the message */
1049 	status = ibmf_i_msg_transport(clientp, ibmf_qp_handle, msgimplp,
1050 	    blocking);
1051 	if (status != IBMF_SUCCESS) {
1052 		(void) sprintf(errmsg, "message transport failed");
1053 		error = B_TRUE;
1054 		mutex_enter(&msgimplp->im_mutex);
1055 		msgimplp->im_flags &= ~IBMF_MSG_FLAGS_BUSY;
1056 		mutex_exit(&msgimplp->im_mutex);
1057 		goto bail;
1058 	}
1059 
1060 bail:
1061 	if (error) {
1062 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1063 		    ibmf_msg_transport_err, IBMF_TNF_ERROR, "",
1064 		    "ibmf_msg_transport(): %s\n", tnf_string, msg, errmsg);
1065 	}
1066 
1067 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_msg_transport_end,
1068 	    IBMF_TNF_TRACE, "", "ibmf_msg_transport() exit\n");
1069 
1070 	return (status);
1071 }
1072 
1073 
1074 /* ARGSUSED */
1075 int
1076 ibmf_alloc_qp(ibmf_handle_t ibmf_handle, ib_pkey_t p_key, ib_qkey_t q_key,
1077     uint_t flags, ibmf_qp_handle_t *ibmf_qp_handlep)
1078 {
1079 	ibmf_client_t	*clientp = (ibmf_client_t *)ibmf_handle;
1080 	uint_t		alloc_flags;
1081 	ibmf_alt_qp_t	*qp_ctx;
1082 	boolean_t	error = B_FALSE;
1083 	int		status = IBMF_SUCCESS;
1084 	char		errmsg[128];
1085 
1086 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_alloc_qp_start,
1087 	    IBMF_TNF_TRACE, "", "ibmf_alloc_qp() enter, "
1088 	    "ibmf_handlep = %p, p_key = 0x%x, q_key = 0x%x\n",
1089 	    tnf_opaque, ibmf_handle, ibmf_handle,
1090 	    tnf_uint, pkey, p_key, tnf_uint, qkey, q_key);
1091 
1092 	/* check for null ibmf_handle and ibmf_qp_handle */
1093 	if ((ibmf_handle == NULL) || (ibmf_qp_handlep == NULL)) {
1094 		(void) sprintf(errmsg,
1095 		    "invalid argument, NULL pointer argument");
1096 		error = B_TRUE;
1097 		status = IBMF_INVALID_ARG;
1098 		goto bail;
1099 	}
1100 
1101 	/* validate ibmf_handle */
1102 	if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
1103 		(void) sprintf(errmsg, "bad ibmf registration handle");
1104 		error = B_TRUE;
1105 		status = IBMF_BAD_HANDLE;
1106 		goto bail;
1107 	}
1108 
1109 	/* check signature */
1110 	if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
1111 		(void) sprintf(errmsg, "bad signature");
1112 		error = B_TRUE;
1113 		status = IBMF_BAD_HANDLE;
1114 		goto bail;
1115 	}
1116 
1117 	/* validate PKey */
1118 	if (IBMF_INVALID_PKEY(p_key)) {
1119 		(void) sprintf(errmsg, "invalid value in p_key argument");
1120 		error = B_TRUE;
1121 		status = IBMF_INVALID_ARG;
1122 		goto bail;
1123 	}
1124 
1125 	if (((flags & IBMF_ALT_QP_MAD_NO_RMPP) == 0) &&
1126 	    ((flags & IBMF_ALT_QP_MAD_RMPP) == 0) &&
1127 	    ((flags & IBMF_ALT_QP_RAW_ONLY) == 0)) {
1128 		(void) sprintf(errmsg, "invalid flags combination");
1129 		error = B_TRUE;
1130 		status = IBMF_BAD_FLAGS;
1131 		goto bail;
1132 	}
1133 
1134 	alloc_flags = IBMF_ALLOC_SLEEP;
1135 
1136 	/* call the internal function to allocate the alternate QP context */
1137 	status = ibmf_i_alloc_qp(clientp, p_key, q_key, alloc_flags,
1138 	    ibmf_qp_handlep);
1139 	if (status != IBMF_SUCCESS) {
1140 		mutex_enter(&clientp->ic_kstat_mutex);
1141 		IBMF_ADD32_KSTATS(clientp, alt_qp_allocs_failed, 1);
1142 		mutex_exit(&clientp->ic_kstat_mutex);
1143 		(void) sprintf(errmsg, "unable to allocate QP");
1144 		error = B_TRUE;
1145 		status = IBMF_NO_RESOURCES;
1146 		goto bail;
1147 	}
1148 
1149 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*qp_ctx))
1150 
1151 	qp_ctx = (ibmf_alt_qp_t *)*ibmf_qp_handlep;
1152 
1153 	/* initialize the alternate qp context */
1154 	if (flags & IBMF_ALT_QP_MAD_NO_RMPP)
1155 		qp_ctx->isq_flags |= IBMF_MAD_ONLY;
1156 
1157 	if (flags & IBMF_ALT_QP_RAW_ONLY)
1158 		qp_ctx->isq_flags |= IBMF_RAW_ONLY;
1159 
1160 	if (flags & IBMF_ALT_QP_MAD_RMPP)
1161 		qp_ctx->isq_supports_rmpp = B_TRUE;
1162 	else
1163 		qp_ctx->isq_supports_rmpp = B_FALSE;
1164 
1165 bail:
1166 	if (error) {
1167 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1168 		    ibmf_alloc_qp_err, IBMF_TNF_ERROR, "",
1169 		    "ibmf_alloc_qp(): %s\n", tnf_string, msg, errmsg);
1170 	}
1171 
1172 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_alloc_qp_end,
1173 	    IBMF_TNF_TRACE, "", "ibmf_alloc_qp() exit\n");
1174 
1175 
1176 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*qp_ctx))
1177 
1178 	return (status);
1179 }
1180 
1181 
1182 /* ARGSUSED */
1183 int
1184 ibmf_query_qp(ibmf_handle_t ibmf_handle, ibmf_qp_handle_t ibmf_qp_handle,
1185     uint_t *qp_num, ib_pkey_t *p_key, ib_qkey_t *q_key, uint8_t *portnum,
1186     uint_t flags)
1187 {
1188 	ibmf_client_t	*clientp = (ibmf_client_t *)ibmf_handle;
1189 	ibmf_alt_qp_t *qp_ctx = (ibmf_alt_qp_t *)ibmf_qp_handle;
1190 	uint_t		query_flags;
1191 	boolean_t	error = B_FALSE;
1192 	int		status = IBMF_SUCCESS;
1193 	char		errmsg[128];
1194 
1195 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_query_qp_start,
1196 	    IBMF_TNF_TRACE, "", "ibmf_query_qp() enter, "
1197 	    "ibmf_handlep = %p, ibmf_qp_handle = %p\n",
1198 	    tnf_opaque, ibmf_handle, ibmf_handle,
1199 	    tnf_opaque, ibmf_qp_handle, ibmf_qp_handle);
1200 
1201 	/* check for null args */
1202 	if ((ibmf_handle == NULL) || (ibmf_qp_handle == NULL) ||
1203 	    (qp_num == NULL) || (p_key == NULL) || (q_key == NULL) ||
1204 	    (portnum == NULL)) {
1205 		(void) sprintf(errmsg,
1206 		    "invalid argument, NULL pointer argument");
1207 		error = B_TRUE;
1208 		status = IBMF_INVALID_ARG;
1209 		goto bail;
1210 	}
1211 
1212 	/* validate ibmf_handle */
1213 	if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
1214 		(void) sprintf(errmsg, "bad ibmf registration handle");
1215 		error = B_TRUE;
1216 		status = IBMF_BAD_HANDLE;
1217 		goto bail;
1218 	}
1219 
1220 	/* validate ibmf_qp_handle */
1221 	if (ibmf_i_is_qp_handle_valid(ibmf_handle, ibmf_qp_handle) !=
1222 	    IBMF_SUCCESS) {
1223 		(void) sprintf(errmsg, "bad qp handle");
1224 		error = B_TRUE;
1225 		status = IBMF_BAD_QP_HANDLE;
1226 		goto bail;
1227 	}
1228 
1229 	/* validate ibmf_qp_handle */
1230 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
1231 		(void) sprintf(errmsg, "bad qp handle (default)");
1232 		error = B_TRUE;
1233 		status = IBMF_BAD_QP_HANDLE;
1234 		goto bail;
1235 	}
1236 
1237 	/* check signature */
1238 	if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
1239 		(void) sprintf(errmsg, "bad client signature");
1240 		error = B_TRUE;
1241 		status = IBMF_BAD_HANDLE;
1242 		goto bail;
1243 	}
1244 
1245 	/* validate client context handle */
1246 	if (qp_ctx->isq_client_hdl != clientp) {
1247 		(void) sprintf(errmsg, "bad QP handle");
1248 		error = B_TRUE;
1249 		status = IBMF_BAD_QP_HANDLE;
1250 		goto bail;
1251 	}
1252 
1253 	query_flags = IBMF_ALLOC_NOSLEEP;
1254 
1255 	/* call the internal function to query the alternate qp */
1256 	status = ibmf_i_query_qp(ibmf_qp_handle, query_flags, qp_num, p_key,
1257 	    q_key, portnum);
1258 	if (status != IBMF_SUCCESS) {
1259 		(void) sprintf(errmsg, "unable to query QP");
1260 		error = B_TRUE;
1261 		goto bail;
1262 	}
1263 
1264 bail:
1265 	if (error) {
1266 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1267 		    ibmf_query_qp_err, IBMF_TNF_ERROR, "",
1268 		    "ibmf_query_qp(): %s\n", tnf_string, msg, errmsg);
1269 	}
1270 
1271 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_query_qp_end,
1272 	    IBMF_TNF_TRACE, "", "ibmf_query_qp() exit, qp = %d, "
1273 	    "pkey = 0x%x, qkey = 0x%x\n", tnf_uint, qp_num, *qp_num,
1274 	    tnf_uint, pkey, *p_key, tnf_uint, qkey, *q_key);
1275 
1276 	return (status);
1277 }
1278 
1279 
1280 /* ARGSUSED */
1281 int
1282 ibmf_modify_qp(ibmf_handle_t ibmf_handle, ibmf_qp_handle_t ibmf_qp_handle,
1283     ib_pkey_t p_key, ib_qkey_t q_key, uint_t flags)
1284 {
1285 	ibmf_client_t	*clientp = (ibmf_client_t *)ibmf_handle;
1286 	ibmf_alt_qp_t *qp_ctx = (ibmf_alt_qp_t *)ibmf_qp_handle;
1287 	uint_t		modify_flags;
1288 	boolean_t	error = B_FALSE;
1289 	int		status = IBMF_SUCCESS;
1290 	char		errmsg[128];
1291 
1292 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_modify_qp_start,
1293 	    IBMF_TNF_TRACE, "", "ibmf_modify_qp() enter, "
1294 	    "ibmf_handlep = %p, ibmf_qp_handle = %p, pkey = 0x%x, "
1295 	    "qkey = 0x%x\n", tnf_opaque, ibmf_handle, ibmf_handle,
1296 	    tnf_opaque, ibmf_qp_handle, ibmf_qp_handle,
1297 	    tnf_uint, p_key, p_key, tnf_uint, q_key, q_key);
1298 
1299 	/* check for null args */
1300 	if ((ibmf_handle == NULL) || (ibmf_qp_handle == NULL)) {
1301 		(void) sprintf(errmsg,
1302 		    "invalid argument, NULL pointer argument");
1303 		error = B_TRUE;
1304 		status = IBMF_INVALID_ARG;
1305 		goto bail;
1306 	}
1307 
1308 	/* validate ibmf_handle */
1309 	if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
1310 		(void) sprintf(errmsg, "bad ibmf registration handle");
1311 		error = B_TRUE;
1312 		status = IBMF_BAD_HANDLE;
1313 		goto bail;
1314 	}
1315 
1316 	/* validate ibmf_qp_handle */
1317 	if (ibmf_i_is_qp_handle_valid(ibmf_handle, ibmf_qp_handle) !=
1318 	    IBMF_SUCCESS) {
1319 		(void) sprintf(errmsg, "bad qp handle");
1320 		error = B_TRUE;
1321 		status = IBMF_BAD_QP_HANDLE;
1322 		goto bail;
1323 	}
1324 
1325 	/* validate ibmf_qp_handle */
1326 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
1327 		(void) sprintf(errmsg, "bad qp handle (default)");
1328 		error = B_TRUE;
1329 		status = IBMF_BAD_QP_HANDLE;
1330 		goto bail;
1331 	}
1332 
1333 	/* check signature */
1334 	if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
1335 		(void) sprintf(errmsg, "bad client signature");
1336 		error = B_TRUE;
1337 		status = IBMF_BAD_HANDLE;
1338 		goto bail;
1339 	}
1340 
1341 	/* validate PKey */
1342 	if (IBMF_INVALID_PKEY(p_key)) {
1343 		(void) sprintf(errmsg, "invalid value in p_key argument");
1344 		error = B_TRUE;
1345 		status = IBMF_INVALID_ARG;
1346 		goto bail;
1347 	}
1348 
1349 	if (qp_ctx->isq_client_hdl != clientp) {
1350 		(void) sprintf(errmsg, "bad QP handle");
1351 		error = B_TRUE;
1352 		status = IBMF_BAD_QP_HANDLE;
1353 		goto bail;
1354 	}
1355 
1356 	modify_flags = IBMF_ALLOC_SLEEP;
1357 
1358 	/* call the internal function to modify the qp */
1359 	status = ibmf_i_modify_qp(ibmf_qp_handle, p_key, q_key, modify_flags);
1360 	if (status != IBMF_SUCCESS) {
1361 		(void) sprintf(errmsg, "unable to modify QP");
1362 		error = B_TRUE;
1363 		goto bail;
1364 	}
1365 
1366 bail:
1367 	if (error) {
1368 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1369 		    ibmf_modify_qp_err, IBMF_TNF_ERROR, "",
1370 		    "ibmf_modify_qp(): %s\n", tnf_string, msg, errmsg);
1371 	}
1372 
1373 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_modify_qp_end,
1374 	    IBMF_TNF_TRACE, "", "ibmf_modify_qp() exit\n");
1375 
1376 	return (status);
1377 }
1378 
1379 /* ARGSUSED */
1380 int
1381 ibmf_free_qp(ibmf_handle_t ibmf_handle, ibmf_qp_handle_t *ibmf_qp_handle,
1382     uint_t flags)
1383 {
1384 	ibmf_client_t	*clientp = (ibmf_client_t *)ibmf_handle;
1385 	ibmf_alt_qp_t	*qp_ctx = (ibmf_alt_qp_t *)*ibmf_qp_handle;
1386 	uint_t		modify_flags;
1387 	boolean_t	error = B_FALSE;
1388 	int		status = IBMF_SUCCESS;
1389 	char		errmsg[128];
1390 
1391 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_free_qp_start,
1392 	    IBMF_TNF_TRACE, "", "ibmf_free_qp() enter, "
1393 	    "ibmf_handlep = %p, ibmf_qp_handle = %p\n",
1394 	    tnf_opaque, ibmf_handle, ibmf_handle,
1395 	    tnf_opaque, ibmf_qp_handle, *ibmf_qp_handle);
1396 
1397 	/* check for null args */
1398 	if ((ibmf_handle == NULL) || (ibmf_qp_handle == NULL)) {
1399 		(void) sprintf(errmsg,
1400 		    "invalid argument, NULL pointer argument");
1401 		error = B_TRUE;
1402 		status = IBMF_INVALID_ARG;
1403 		goto bail;
1404 	}
1405 
1406 	/* validate ibmf_handle */
1407 	if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
1408 		(void) sprintf(errmsg, "bad ibmf registration handle");
1409 		error = B_TRUE;
1410 		status = IBMF_BAD_HANDLE;
1411 		goto bail;
1412 	}
1413 
1414 	/* validate ibmf_qp_handle */
1415 	if (ibmf_i_is_qp_handle_valid(ibmf_handle, *ibmf_qp_handle) !=
1416 	    IBMF_SUCCESS) {
1417 		(void) sprintf(errmsg, "bad qp handle");
1418 		error = B_TRUE;
1419 		status = IBMF_BAD_QP_HANDLE;
1420 		goto bail;
1421 	}
1422 
1423 	/* validate ibmf_qp_handle */
1424 	if (*ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
1425 		(void) sprintf(errmsg, "bad qp handle (default)");
1426 		error = B_TRUE;
1427 		status = IBMF_BAD_QP_HANDLE;
1428 		goto bail;
1429 	}
1430 
1431 	/* check signature */
1432 	if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
1433 		(void) sprintf(errmsg, "bad client signature");
1434 		error = B_TRUE;
1435 		status = IBMF_BAD_HANDLE;
1436 		goto bail;
1437 	}
1438 
1439 	/* validate client context handle */
1440 	if (qp_ctx->isq_client_hdl != clientp) {
1441 		(void) sprintf(errmsg, "bad QP handle");
1442 		error = B_TRUE;
1443 		status = IBMF_BAD_QP_HANDLE;
1444 		goto bail;
1445 	}
1446 
1447 	mutex_enter(&qp_ctx->isq_mutex);
1448 
1449 	if (qp_ctx->isq_recv_cb != NULL) {
1450 		mutex_exit(&qp_ctx->isq_mutex);
1451 		(void) sprintf(errmsg, "QP busy, callback active");
1452 		error = B_TRUE;
1453 		status = IBMF_BUSY;
1454 		goto bail;
1455 	}
1456 
1457 	mutex_exit(&qp_ctx->isq_mutex);
1458 
1459 	modify_flags = IBMF_ALLOC_SLEEP;
1460 
1461 	status = ibmf_i_free_qp(*ibmf_qp_handle, modify_flags);
1462 	if (status != IBMF_SUCCESS) {
1463 		(void) sprintf(errmsg, "unable to free QP");
1464 		error = B_TRUE;
1465 		goto bail;
1466 	}
1467 
1468 	*ibmf_qp_handle = NULL;
1469 
1470 bail:
1471 	if (error) {
1472 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1473 		    ibmf_free_qp_err, IBMF_TNF_ERROR, "",
1474 		    "ibmf_free_qp(): %s\n", tnf_string, msg, errmsg);
1475 	}
1476 
1477 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_free_qp_end,
1478 	    IBMF_TNF_TRACE, "", "ibmf_free_qp() exit\n");
1479 
1480 	return (status);
1481 }
1482