xref: /illumos-gate/usr/src/uts/common/io/ib/mgt/ibmf/ibmf.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
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 /*
23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
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_ADM_AGENT) &&
905 	    (clientp->ic_client_info.client_class != SUBN_MANAGER))) {
906 
907 		if ((msgp->im_local_addr.ia_p_key != IBMF_P_KEY_DEF_FULL) &&
908 		    (msgp->im_local_addr.ia_p_key != IBMF_P_KEY_DEF_LIMITED)) {
909 			(void) sprintf(errmsg,
910 			    "PKey in packet not default PKey");
911 			error = B_TRUE;
912 			status = IBMF_BAD_QP_HANDLE;
913 			goto bail;
914 		}
915 
916 		if (msgp->im_local_addr.ia_q_key != IBMF_MGMT_Q_KEY) {
917 			(void) sprintf(errmsg, "QKey in packet not Mgt QKey");
918 			error = B_TRUE;
919 			status = IBMF_BAD_QP_HANDLE;
920 			goto bail;
921 		}
922 	} else if (ibmf_qp_handle != IBMF_QP_HANDLE_DEFAULT) {
923 		ibmf_alt_qp_t *qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
924 
925 		/* alternate QP context */
926 
927 		mutex_enter(&qpp->isq_mutex);
928 
929 		if (msgp->im_local_addr.ia_p_key != qpp->isq_pkey) {
930 			mutex_exit(&qpp->isq_mutex);
931 			(void) sprintf(errmsg, "PKey in packet does not match "
932 			    "PKey in the QP context");
933 			error = B_TRUE;
934 			status = IBMF_BAD_QP_HANDLE;
935 			goto bail;
936 		}
937 
938 		if (msgp->im_local_addr.ia_q_key != qpp->isq_qkey) {
939 			mutex_exit(&qpp->isq_mutex);
940 			(void) sprintf(errmsg, "QKey in packet does not match "
941 			    "QKey in the QP context");
942 			error = B_TRUE;
943 			status = IBMF_BAD_QP_HANDLE;
944 			goto bail;
945 		}
946 
947 		mutex_exit(&qpp->isq_mutex);
948 	}
949 
950 	msgimplp = (ibmf_msg_impl_t *)msgp;
951 
952 	ASSERT(msgimplp->im_client != NULL);
953 	ASSERT(msgimplp->im_client == clientp);
954 
955 	msgimplp->im_transp_op_flags = flags;
956 
957 	mutex_enter(&msgimplp->im_mutex);
958 
959 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
960 		if (msgimplp->im_msgbufs_send.im_bufs_mad_hdr == NULL) {
961 			mutex_exit(&msgimplp->im_mutex);
962 			(void) sprintf(errmsg, "Send buffer MAD header data "
963 			    "not provided for special QP");
964 			error = B_TRUE;
965 			status = IBMF_BAD_SIZE;
966 			goto bail;
967 		}
968 	} else {
969 		ibmf_alt_qp_t *qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
970 
971 		mutex_enter(&qpp->isq_mutex);
972 
973 		if (((qpp->isq_flags & IBMF_RAW_ONLY) == 0) &&
974 		    (msgimplp->im_msgbufs_send.im_bufs_mad_hdr == NULL)) {
975 			mutex_exit(&qpp->isq_mutex);
976 			mutex_exit(&msgimplp->im_mutex);
977 			(void) sprintf(errmsg, "Send buffer MAD header data "
978 			    "not provided for alternate QP");
979 			error = B_TRUE;
980 			status = IBMF_BAD_SIZE;
981 			goto bail;
982 		}
983 		mutex_exit(&qpp->isq_mutex);
984 	}
985 
986 	/* check if client has freed the message by calling ibmf_free_msg() */
987 	if (msgimplp->im_flags & IBMF_MSG_FLAGS_FREE) {
988 		mutex_exit(&msgimplp->im_mutex);
989 		(void) sprintf(errmsg, "Message is being freed");
990 		error = B_TRUE;
991 		status = IBMF_BUSY;
992 		goto bail;
993 	}
994 
995 	/*
996 	 * check if the message is already in use in an
997 	 * ibmf_msg_transport() call
998 	 */
999 	if (msgimplp->im_flags & IBMF_MSG_FLAGS_BUSY) {
1000 		mutex_exit(&msgimplp->im_mutex);
1001 		(void) sprintf(errmsg,
1002 		    "Message is being processed by an other thread");
1003 		error = B_TRUE;
1004 		status = IBMF_BUSY;
1005 		goto bail;
1006 	}
1007 
1008 	msgimplp->im_flags = IBMF_MSG_FLAGS_BUSY;
1009 
1010 	mutex_exit(&msgimplp->im_mutex);
1011 
1012 	/* check for the Directed Route SMP loopback case */
1013 	loopback = B_FALSE;
1014 	dr_hdr = (sm_dr_mad_hdr_t *)msgimplp->im_msgbufs_send.im_bufs_mad_hdr;
1015 	if ((dr_hdr->MgmtClass == MAD_MGMT_CLASS_SUBN_DIRECT_ROUTE) &&
1016 	    (dr_hdr->HopCount == 0)) {
1017 		loopback = B_TRUE;
1018 	}
1019 
1020 	/* check for and perform DR loopback on tavor */
1021 	status = ibmf_i_check_for_loopback(msgimplp, msg_cb, msg_cb_args,
1022 	    retrans, &loopback);
1023 	if (status != IBMF_SUCCESS) {
1024 		(void) sprintf(errmsg, "dr_loopback_check failed");
1025 		error = B_TRUE;
1026 		mutex_enter(&msgimplp->im_mutex);
1027 		msgimplp->im_flags &= ~IBMF_MSG_FLAGS_BUSY;
1028 		mutex_exit(&msgimplp->im_mutex);
1029 		goto bail;
1030 	}
1031 	if (loopback == B_TRUE) {
1032 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1033 		    ibmf_msg_transport_end, IBMF_TNF_TRACE, "",
1034 		    "ibmf_msg_transport() exit, dr_loopback ok\n");
1035 		return (IBMF_SUCCESS);
1036 	}
1037 
1038 	if (msg_cb == NULL) {
1039 		blocking = B_TRUE;
1040 	} else {
1041 		blocking = B_FALSE;
1042 	}
1043 
1044 	/* initialize the message context */
1045 	ibmf_i_init_msg(msgimplp, msg_cb, msg_cb_args, retrans, blocking);
1046 
1047 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msgp,*msgimplp))
1048 
1049 	/* call the internal function to transport the message */
1050 	status = ibmf_i_msg_transport(clientp, ibmf_qp_handle, msgimplp,
1051 	    blocking);
1052 	if (status != IBMF_SUCCESS) {
1053 		(void) sprintf(errmsg, "message transport failed");
1054 		error = B_TRUE;
1055 		mutex_enter(&msgimplp->im_mutex);
1056 		msgimplp->im_flags &= ~IBMF_MSG_FLAGS_BUSY;
1057 		mutex_exit(&msgimplp->im_mutex);
1058 		goto bail;
1059 	}
1060 
1061 bail:
1062 	if (error) {
1063 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1064 		    ibmf_msg_transport_err, IBMF_TNF_ERROR, "",
1065 		    "ibmf_msg_transport(): %s\n", tnf_string, msg, errmsg);
1066 	}
1067 
1068 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_msg_transport_end,
1069 	    IBMF_TNF_TRACE, "", "ibmf_msg_transport() exit\n");
1070 
1071 	return (status);
1072 }
1073 
1074 
1075 /* ARGSUSED */
1076 int
1077 ibmf_alloc_qp(ibmf_handle_t ibmf_handle, ib_pkey_t p_key, ib_qkey_t q_key,
1078     uint_t flags, ibmf_qp_handle_t *ibmf_qp_handlep)
1079 {
1080 	ibmf_client_t	*clientp = (ibmf_client_t *)ibmf_handle;
1081 	uint_t		alloc_flags;
1082 	ibmf_alt_qp_t	*qp_ctx;
1083 	boolean_t	error = B_FALSE;
1084 	int		status = IBMF_SUCCESS;
1085 	char		errmsg[128];
1086 
1087 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_alloc_qp_start,
1088 	    IBMF_TNF_TRACE, "", "ibmf_alloc_qp() enter, "
1089 	    "ibmf_handlep = %p, p_key = 0x%x, q_key = 0x%x\n",
1090 	    tnf_opaque, ibmf_handle, ibmf_handle,
1091 	    tnf_uint, pkey, p_key, tnf_uint, qkey, q_key);
1092 
1093 	/* check for null ibmf_handle and ibmf_qp_handle */
1094 	if ((ibmf_handle == NULL) || (ibmf_qp_handlep == NULL)) {
1095 		(void) sprintf(errmsg,
1096 		    "invalid argument, NULL pointer argument");
1097 		error = B_TRUE;
1098 		status = IBMF_INVALID_ARG;
1099 		goto bail;
1100 	}
1101 
1102 	/* validate ibmf_handle */
1103 	if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
1104 		(void) sprintf(errmsg, "bad ibmf registration handle");
1105 		error = B_TRUE;
1106 		status = IBMF_BAD_HANDLE;
1107 		goto bail;
1108 	}
1109 
1110 	/* check signature */
1111 	if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
1112 		(void) sprintf(errmsg, "bad signature");
1113 		error = B_TRUE;
1114 		status = IBMF_BAD_HANDLE;
1115 		goto bail;
1116 	}
1117 
1118 	/* validate PKey */
1119 	if (IBMF_INVALID_PKEY(p_key)) {
1120 		(void) sprintf(errmsg, "invalid value in p_key argument");
1121 		error = B_TRUE;
1122 		status = IBMF_INVALID_ARG;
1123 		goto bail;
1124 	}
1125 
1126 	if (((flags & IBMF_ALT_QP_MAD_NO_RMPP) == 0) &&
1127 	    ((flags & IBMF_ALT_QP_MAD_RMPP) == 0) &&
1128 	    ((flags & IBMF_ALT_QP_RAW_ONLY) == 0)) {
1129 		(void) sprintf(errmsg, "invalid flags combination");
1130 		error = B_TRUE;
1131 		status = IBMF_BAD_FLAGS;
1132 		goto bail;
1133 	}
1134 
1135 	alloc_flags = IBMF_ALLOC_SLEEP;
1136 
1137 	/* call the internal function to allocate the alternate QP context */
1138 	status = ibmf_i_alloc_qp(clientp, p_key, q_key, alloc_flags,
1139 	    ibmf_qp_handlep);
1140 	if (status != IBMF_SUCCESS) {
1141 		mutex_enter(&clientp->ic_kstat_mutex);
1142 		IBMF_ADD32_KSTATS(clientp, alt_qp_allocs_failed, 1);
1143 		mutex_exit(&clientp->ic_kstat_mutex);
1144 		(void) sprintf(errmsg, "unable to allocate QP");
1145 		error = B_TRUE;
1146 		status = IBMF_NO_RESOURCES;
1147 		goto bail;
1148 	}
1149 
1150 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*qp_ctx))
1151 
1152 	qp_ctx = (ibmf_alt_qp_t *)*ibmf_qp_handlep;
1153 
1154 	/* initialize the alternate qp context */
1155 	if (flags & IBMF_ALT_QP_MAD_NO_RMPP)
1156 		qp_ctx->isq_flags |= IBMF_MAD_ONLY;
1157 
1158 	if (flags & IBMF_ALT_QP_RAW_ONLY)
1159 		qp_ctx->isq_flags |= IBMF_RAW_ONLY;
1160 
1161 	if (flags & IBMF_ALT_QP_MAD_RMPP)
1162 		qp_ctx->isq_supports_rmpp = B_TRUE;
1163 	else
1164 		qp_ctx->isq_supports_rmpp = B_FALSE;
1165 
1166 bail:
1167 	if (error) {
1168 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1169 		    ibmf_alloc_qp_err, IBMF_TNF_ERROR, "",
1170 		    "ibmf_alloc_qp(): %s\n", tnf_string, msg, errmsg);
1171 	}
1172 
1173 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_alloc_qp_end,
1174 	    IBMF_TNF_TRACE, "", "ibmf_alloc_qp() exit\n");
1175 
1176 
1177 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*qp_ctx))
1178 
1179 	return (status);
1180 }
1181 
1182 
1183 /* ARGSUSED */
1184 int
1185 ibmf_query_qp(ibmf_handle_t ibmf_handle, ibmf_qp_handle_t ibmf_qp_handle,
1186     uint_t *qp_num, ib_pkey_t *p_key, ib_qkey_t *q_key, uint8_t *portnum,
1187     uint_t flags)
1188 {
1189 	ibmf_client_t	*clientp = (ibmf_client_t *)ibmf_handle;
1190 	ibmf_alt_qp_t *qp_ctx = (ibmf_alt_qp_t *)ibmf_qp_handle;
1191 	uint_t		query_flags;
1192 	boolean_t	error = B_FALSE;
1193 	int		status = IBMF_SUCCESS;
1194 	char		errmsg[128];
1195 
1196 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_query_qp_start,
1197 	    IBMF_TNF_TRACE, "", "ibmf_query_qp() enter, "
1198 	    "ibmf_handlep = %p, ibmf_qp_handle = %p\n",
1199 	    tnf_opaque, ibmf_handle, ibmf_handle,
1200 	    tnf_opaque, ibmf_qp_handle, ibmf_qp_handle);
1201 
1202 	/* check for null args */
1203 	if ((ibmf_handle == NULL) || (ibmf_qp_handle == NULL) ||
1204 	    (qp_num == NULL) || (p_key == NULL) || (q_key == NULL) ||
1205 	    (portnum == NULL)) {
1206 		(void) sprintf(errmsg,
1207 		    "invalid argument, NULL pointer argument");
1208 		error = B_TRUE;
1209 		status = IBMF_INVALID_ARG;
1210 		goto bail;
1211 	}
1212 
1213 	/* validate ibmf_handle */
1214 	if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
1215 		(void) sprintf(errmsg, "bad ibmf registration handle");
1216 		error = B_TRUE;
1217 		status = IBMF_BAD_HANDLE;
1218 		goto bail;
1219 	}
1220 
1221 	/* validate ibmf_qp_handle */
1222 	if (ibmf_i_is_qp_handle_valid(ibmf_handle, ibmf_qp_handle) !=
1223 	    IBMF_SUCCESS) {
1224 		(void) sprintf(errmsg, "bad qp handle");
1225 		error = B_TRUE;
1226 		status = IBMF_BAD_QP_HANDLE;
1227 		goto bail;
1228 	}
1229 
1230 	/* validate ibmf_qp_handle */
1231 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
1232 		(void) sprintf(errmsg, "bad qp handle (default)");
1233 		error = B_TRUE;
1234 		status = IBMF_BAD_QP_HANDLE;
1235 		goto bail;
1236 	}
1237 
1238 	/* check signature */
1239 	if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
1240 		(void) sprintf(errmsg, "bad client signature");
1241 		error = B_TRUE;
1242 		status = IBMF_BAD_HANDLE;
1243 		goto bail;
1244 	}
1245 
1246 	/* validate client context handle */
1247 	if (qp_ctx->isq_client_hdl != clientp) {
1248 		(void) sprintf(errmsg, "bad QP handle");
1249 		error = B_TRUE;
1250 		status = IBMF_BAD_QP_HANDLE;
1251 		goto bail;
1252 	}
1253 
1254 	query_flags = IBMF_ALLOC_NOSLEEP;
1255 
1256 	/* call the internal function to query the alternate qp */
1257 	status = ibmf_i_query_qp(ibmf_qp_handle, query_flags, qp_num, p_key,
1258 	    q_key, portnum);
1259 	if (status != IBMF_SUCCESS) {
1260 		(void) sprintf(errmsg, "unable to query QP");
1261 		error = B_TRUE;
1262 		goto bail;
1263 	}
1264 
1265 bail:
1266 	if (error) {
1267 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1268 		    ibmf_query_qp_err, IBMF_TNF_ERROR, "",
1269 		    "ibmf_query_qp(): %s\n", tnf_string, msg, errmsg);
1270 	}
1271 
1272 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_query_qp_end,
1273 	    IBMF_TNF_TRACE, "", "ibmf_query_qp() exit, qp = %d, "
1274 	    "pkey = 0x%x, qkey = 0x%x\n", tnf_uint, qp_num, *qp_num,
1275 	    tnf_uint, pkey, *p_key, tnf_uint, qkey, *q_key);
1276 
1277 	return (status);
1278 }
1279 
1280 
1281 /* ARGSUSED */
1282 int
1283 ibmf_modify_qp(ibmf_handle_t ibmf_handle, ibmf_qp_handle_t ibmf_qp_handle,
1284     ib_pkey_t p_key, ib_qkey_t q_key, uint_t flags)
1285 {
1286 	ibmf_client_t	*clientp = (ibmf_client_t *)ibmf_handle;
1287 	ibmf_alt_qp_t *qp_ctx = (ibmf_alt_qp_t *)ibmf_qp_handle;
1288 	uint_t		modify_flags;
1289 	boolean_t	error = B_FALSE;
1290 	int		status = IBMF_SUCCESS;
1291 	char		errmsg[128];
1292 
1293 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_modify_qp_start,
1294 	    IBMF_TNF_TRACE, "", "ibmf_modify_qp() enter, "
1295 	    "ibmf_handlep = %p, ibmf_qp_handle = %p, pkey = 0x%x, "
1296 	    "qkey = 0x%x\n", tnf_opaque, ibmf_handle, ibmf_handle,
1297 	    tnf_opaque, ibmf_qp_handle, ibmf_qp_handle,
1298 	    tnf_uint, p_key, p_key, tnf_uint, q_key, q_key);
1299 
1300 	/* check for null args */
1301 	if ((ibmf_handle == NULL) || (ibmf_qp_handle == NULL)) {
1302 		(void) sprintf(errmsg,
1303 		    "invalid argument, NULL pointer argument");
1304 		error = B_TRUE;
1305 		status = IBMF_INVALID_ARG;
1306 		goto bail;
1307 	}
1308 
1309 	/* validate ibmf_handle */
1310 	if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
1311 		(void) sprintf(errmsg, "bad ibmf registration handle");
1312 		error = B_TRUE;
1313 		status = IBMF_BAD_HANDLE;
1314 		goto bail;
1315 	}
1316 
1317 	/* validate ibmf_qp_handle */
1318 	if (ibmf_i_is_qp_handle_valid(ibmf_handle, ibmf_qp_handle) !=
1319 	    IBMF_SUCCESS) {
1320 		(void) sprintf(errmsg, "bad qp handle");
1321 		error = B_TRUE;
1322 		status = IBMF_BAD_QP_HANDLE;
1323 		goto bail;
1324 	}
1325 
1326 	/* validate ibmf_qp_handle */
1327 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
1328 		(void) sprintf(errmsg, "bad qp handle (default)");
1329 		error = B_TRUE;
1330 		status = IBMF_BAD_QP_HANDLE;
1331 		goto bail;
1332 	}
1333 
1334 	/* check signature */
1335 	if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
1336 		(void) sprintf(errmsg, "bad client signature");
1337 		error = B_TRUE;
1338 		status = IBMF_BAD_HANDLE;
1339 		goto bail;
1340 	}
1341 
1342 	/* validate PKey */
1343 	if (IBMF_INVALID_PKEY(p_key)) {
1344 		(void) sprintf(errmsg, "invalid value in p_key argument");
1345 		error = B_TRUE;
1346 		status = IBMF_INVALID_ARG;
1347 		goto bail;
1348 	}
1349 
1350 	if (qp_ctx->isq_client_hdl != clientp) {
1351 		(void) sprintf(errmsg, "bad QP handle");
1352 		error = B_TRUE;
1353 		status = IBMF_BAD_QP_HANDLE;
1354 		goto bail;
1355 	}
1356 
1357 	modify_flags = IBMF_ALLOC_SLEEP;
1358 
1359 	/* call the internal function to modify the qp */
1360 	status = ibmf_i_modify_qp(ibmf_qp_handle, p_key, q_key, modify_flags);
1361 	if (status != IBMF_SUCCESS) {
1362 		(void) sprintf(errmsg, "unable to modify QP");
1363 		error = B_TRUE;
1364 		goto bail;
1365 	}
1366 
1367 bail:
1368 	if (error) {
1369 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1370 		    ibmf_modify_qp_err, IBMF_TNF_ERROR, "",
1371 		    "ibmf_modify_qp(): %s\n", tnf_string, msg, errmsg);
1372 	}
1373 
1374 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_modify_qp_end,
1375 	    IBMF_TNF_TRACE, "", "ibmf_modify_qp() exit\n");
1376 
1377 	return (status);
1378 }
1379 
1380 /* ARGSUSED */
1381 int
1382 ibmf_free_qp(ibmf_handle_t ibmf_handle, ibmf_qp_handle_t *ibmf_qp_handle,
1383     uint_t flags)
1384 {
1385 	ibmf_client_t	*clientp = (ibmf_client_t *)ibmf_handle;
1386 	ibmf_alt_qp_t	*qp_ctx = (ibmf_alt_qp_t *)*ibmf_qp_handle;
1387 	uint_t		modify_flags;
1388 	boolean_t	error = B_FALSE;
1389 	int		status = IBMF_SUCCESS;
1390 	char		errmsg[128];
1391 
1392 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_free_qp_start,
1393 	    IBMF_TNF_TRACE, "", "ibmf_free_qp() enter, "
1394 	    "ibmf_handlep = %p, ibmf_qp_handle = %p\n",
1395 	    tnf_opaque, ibmf_handle, ibmf_handle,
1396 	    tnf_opaque, ibmf_qp_handle, *ibmf_qp_handle);
1397 
1398 	/* check for null args */
1399 	if ((ibmf_handle == NULL) || (ibmf_qp_handle == NULL)) {
1400 		(void) sprintf(errmsg,
1401 		    "invalid argument, NULL pointer argument");
1402 		error = B_TRUE;
1403 		status = IBMF_INVALID_ARG;
1404 		goto bail;
1405 	}
1406 
1407 	/* validate ibmf_handle */
1408 	if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
1409 		(void) sprintf(errmsg, "bad ibmf registration handle");
1410 		error = B_TRUE;
1411 		status = IBMF_BAD_HANDLE;
1412 		goto bail;
1413 	}
1414 
1415 	/* validate ibmf_qp_handle */
1416 	if (ibmf_i_is_qp_handle_valid(ibmf_handle, *ibmf_qp_handle) !=
1417 	    IBMF_SUCCESS) {
1418 		(void) sprintf(errmsg, "bad qp handle");
1419 		error = B_TRUE;
1420 		status = IBMF_BAD_QP_HANDLE;
1421 		goto bail;
1422 	}
1423 
1424 	/* validate ibmf_qp_handle */
1425 	if (*ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
1426 		(void) sprintf(errmsg, "bad qp handle (default)");
1427 		error = B_TRUE;
1428 		status = IBMF_BAD_QP_HANDLE;
1429 		goto bail;
1430 	}
1431 
1432 	/* check signature */
1433 	if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
1434 		(void) sprintf(errmsg, "bad client signature");
1435 		error = B_TRUE;
1436 		status = IBMF_BAD_HANDLE;
1437 		goto bail;
1438 	}
1439 
1440 	/* validate client context handle */
1441 	if (qp_ctx->isq_client_hdl != clientp) {
1442 		(void) sprintf(errmsg, "bad QP handle");
1443 		error = B_TRUE;
1444 		status = IBMF_BAD_QP_HANDLE;
1445 		goto bail;
1446 	}
1447 
1448 	mutex_enter(&qp_ctx->isq_mutex);
1449 
1450 	if (qp_ctx->isq_recv_cb != NULL) {
1451 		mutex_exit(&qp_ctx->isq_mutex);
1452 		(void) sprintf(errmsg, "QP busy, callback active");
1453 		error = B_TRUE;
1454 		status = IBMF_BUSY;
1455 		goto bail;
1456 	}
1457 
1458 	mutex_exit(&qp_ctx->isq_mutex);
1459 
1460 	modify_flags = IBMF_ALLOC_SLEEP;
1461 
1462 	status = ibmf_i_free_qp(*ibmf_qp_handle, modify_flags);
1463 	if (status != IBMF_SUCCESS) {
1464 		(void) sprintf(errmsg, "unable to free QP");
1465 		error = B_TRUE;
1466 		goto bail;
1467 	}
1468 
1469 	*ibmf_qp_handle = NULL;
1470 
1471 bail:
1472 	if (error) {
1473 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1474 		    ibmf_free_qp_err, IBMF_TNF_ERROR, "",
1475 		    "ibmf_free_qp(): %s\n", tnf_string, msg, errmsg);
1476 	}
1477 
1478 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_free_qp_end,
1479 	    IBMF_TNF_TRACE, "", "ibmf_free_qp() exit\n");
1480 
1481 	return (status);
1482 }
1483