/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* This file implements the client interfaces of the IBMF.
*/
#include <sys/ib/mgt/ibmf/ibmf_impl.h>
#define IBMF_SET_CLIENT_SIGNATURE(clientp) { \
(clientp)->ic_client_sig = (void *)0xf00DdEaD; \
}
#define IBMF_VERIFY_CLIENT_SIGNATURE(clientp) \
(((clientp) != NULL && (clientp)->ic_client_sig == \
(void *)0xf00DdEaD) ? B_TRUE: B_FALSE)
#define IBMF_INVALID_PKEY(pkey) (((pkey) & 0x7FFF) == 0)
#define QP1 1
extern ibmf_state_t *ibmf_statep;
extern int ibmf_trace_level;
/* ARGSUSED */
int
ibmf_register(ibmf_register_info_t *client_infop, uint_t ibmf_version,
uint_t flags, ibmf_async_event_cb_t client_cb, void *client_cb_args,
ibmf_handle_t *ibmf_handlep, ibmf_impl_caps_t *ibmf_impl_features)
{
ibmf_ci_t *ibmf_cip;
ibmf_qp_t *ibmf_qpp;
ibmf_client_t *ibmf_clientp;
boolean_t error = B_FALSE;
int status = IBMF_SUCCESS;
char errmsg[128];
IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_register_start,
IBMF_TNF_TRACE, "", "ibmf_register() enter, client_infop = %p "
" ibmf_version = %d, flags = 0x%x, ibmf_impl_featuresp = %p\n",
tnf_opaque, client_infop, client_infop,
tnf_uint, ibmf_version, ibmf_version, tnf_uint, flags, flags,
tnf_opaque, ibmf_impl_features, ibmf_impl_features);
/* validate client_infop and ibmf_handlep */
if ((client_infop == NULL) || (ibmf_handlep == NULL) ||
(ibmf_impl_features == NULL)) {
(void) sprintf(errmsg,
"invalid argument, NULL pointer argument");
error = B_TRUE;
status = IBMF_INVALID_ARG;
goto bail;
}
/* check IBMF version */
if (ibmf_version != IBMF_VERSION) {
(void) sprintf(errmsg, "Bad version");
error = B_TRUE;
status = IBMF_BAD_VERSION;
goto bail;
}
/* check flags validity */
if ((flags & IBMF_REG_FLAG_NO_OFFLOAD) &&
(flags & IBMF_REG_FLAG_SINGLE_OFFLOAD)) {
(void) sprintf(errmsg, "Bad flags");
error = B_TRUE;
status = IBMF_BAD_FLAGS;
goto bail;
}
/* check client mask and size */
status = ibmf_i_validate_class_mask(client_infop);
if (status != IBMF_SUCCESS) {
(void) sprintf(errmsg, "invalid class");
error = B_TRUE;
goto bail;
}
/*
* verify the node identified by ir_ci_guid exists and that the
* port ir_port_num is valid.
*/
status = ibmf_i_validate_ci_guid_and_port(client_infop->ir_ci_guid,
client_infop->ir_port_num);
if (status != IBMF_SUCCESS) {
(void) sprintf(errmsg, "guid/port validation failed");
error = B_TRUE;
goto bail;
}
/* get the ci */
status = ibmf_i_get_ci(client_infop, &ibmf_cip);
if (status != IBMF_SUCCESS) {
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_register_error, IBMF_TNF_ERROR, "",
"ibmf_register(): %s, guid = 0x%p\n",
tnf_string, msg, "unable to get ci",
tnf_ulonglong, guid, client_infop->ir_ci_guid);
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_register_end,
IBMF_TNF_TRACE, "", "ibmf_register() exit\n");
return (status);
}
/*
* check if classes and port are already registered for.
*/
status = ibmf_i_validate_classes_and_port(ibmf_cip, client_infop);
if (status != IBMF_SUCCESS) {
mutex_enter(&ibmf_cip->ci_mutex);
IBMF_ADD32_PORT_KSTATS(ibmf_cip, client_regs_failed, 1);
mutex_exit(&ibmf_cip->ci_mutex);
/* release ci */
ibmf_i_release_ci(ibmf_cip);
(void) sprintf(errmsg,
"class and port already registered for or unsupported");
error = B_TRUE;
goto bail;
}
/*
* the class is valid, get qp and alloc the client
*/
/* obtain the qp corresponding to the port and classes */
status = ibmf_i_get_qp(ibmf_cip, client_infop->ir_port_num,
client_infop->ir_client_class, &ibmf_qpp);
if (status != IBMF_SUCCESS) {
mutex_enter(&ibmf_cip->ci_mutex);
IBMF_ADD32_PORT_KSTATS(ibmf_cip, client_regs_failed, 1);
mutex_exit(&ibmf_cip->ci_mutex);
ibmf_i_release_ci(ibmf_cip);
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_register_error, IBMF_TNF_ERROR, "",
"ibmf_register(): %s, class = 0x%x\n",
tnf_string, msg, "can't get qp",
tnf_int, class, client_infop->ir_client_class);
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_register_end,
IBMF_TNF_TRACE, "", "ibmf_register() exit\n");
return (status);
}
/* alloc the client */
status = ibmf_i_alloc_client(client_infop, flags, &ibmf_clientp);
if (status != IBMF_SUCCESS) {
mutex_enter(&ibmf_cip->ci_mutex);
IBMF_ADD32_PORT_KSTATS(ibmf_cip, client_regs_failed, 1);
mutex_exit(&ibmf_cip->ci_mutex);
ibmf_i_release_ci(ibmf_cip);
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_register_error, IBMF_TNF_ERROR, "",
"ibmf_register(): %s, class = 0x%x\n",
tnf_string, msg, "can't alloc client",
tnf_int, class, client_infop->ir_client_class);
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_register_end,
IBMF_TNF_TRACE, "", "ibmf_register() exit\n");
return (status);
}
ASSERT(ibmf_clientp != NULL);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ibmf_clientp))
/* initialize the IBMF client context */
ibmf_clientp->ic_myci = ibmf_cip;
ibmf_clientp->ic_qp = ibmf_qpp;
ibmf_clientp->ic_ci_handle = ibmf_cip->ci_ci_handle;
ibmf_clientp->ic_reg_flags = flags;
ibmf_clientp->ic_async_cb = client_cb;
ibmf_clientp->ic_async_cb_arg = client_cb_args;
IBMF_SET_CLIENT_SIGNATURE(ibmf_clientp);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*ibmf_clientp))
/* add the client to the list of clients */
ibmf_i_add_client(ibmf_cip, ibmf_clientp);
/* increment kstats for number of registered clients */
mutex_enter(&ibmf_cip->ci_mutex);
IBMF_ADD32_PORT_KSTATS(ibmf_cip, clients_registered, 1);
mutex_exit(&ibmf_cip->ci_mutex);
/* Setup ibmf_handlep -- handle is last allocated clientp */
*ibmf_handlep = (ibmf_handle_t)ibmf_clientp;
*ibmf_impl_features = 0;
bail:
if (error) {
IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_register_error, IBMF_TNF_ERROR, "",
"ibmf_register(): %s\n", tnf_string, msg, errmsg);
}
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_register_end,
IBMF_TNF_TRACE, "", "ibmf_register() exit, ibmf_handle = %p\n",
tnf_opaque, ibmf_handle, *ibmf_handlep);
return (status);
}
/* ARGSUSED */
int
ibmf_unregister(ibmf_handle_t *ibmf_handlep, uint_t flags)
{
ibmf_ci_t *cip;
ibmf_client_t *clientp;
boolean_t error = B_FALSE;
int status = IBMF_SUCCESS;
char errmsg[128];
int secs;
clientp = (ibmf_client_t *)*ibmf_handlep;
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_unregister_start,
IBMF_TNF_TRACE, "", "ibmf_unregister() enter, "
"ibmf_handlep = %p, flags = 0x%x\n",
tnf_opaque, ibmf_handle, *ibmf_handlep, tnf_uint, flags, flags);
/* check for null ibmf_handlep */
if (ibmf_handlep == NULL) {
(void) sprintf(errmsg,
"invalid argument, NULL pointer argument");
error = B_TRUE;
status = IBMF_INVALID_ARG;
goto bail;
}
/* validate ibmf_handlep */
if (ibmf_i_is_ibmf_handle_valid(*ibmf_handlep) != IBMF_SUCCESS) {
(void) sprintf(errmsg, "bad ibmf registration handle");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
/* check signature */
if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
(void) sprintf(errmsg, "bad client signature");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
/*
* Verify the client does not have a receive callback registered.
* If there are messages, give some time for the messages to be
* cleaned up.
*/
secs = 60;
mutex_enter(&clientp->ic_mutex);
while (clientp->ic_recv_cb == NULL && clientp->ic_msgs_alloced != 0 &&
secs > 0) {
mutex_exit(&clientp->ic_mutex);
delay(drv_usectohz(1000000)); /* one second delay */
secs--;
mutex_enter(&clientp->ic_mutex);
}
if (clientp->ic_recv_cb != NULL || clientp->ic_msgs_alloced != 0) {
IBMF_TRACE_4(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_unregister_err, IBMF_TNF_ERROR, "",
"ibmf_unregister(): %s, flags = 0x%x, recv_cb = 0x%p, "
"msgs_alloced = %d\n",
tnf_string, msg, "busy with resources", tnf_uint, ic_flags,
clientp->ic_flags, tnf_opaque, recv_cb, clientp->ic_recv_cb,
tnf_uint, msgs_allocd, clientp->ic_msgs_alloced);
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_unregister_end,
IBMF_TNF_TRACE, "", "ibmf_unregister() exit\n");
mutex_exit(&clientp->ic_mutex);
return (IBMF_BUSY);
}
mutex_exit(&clientp->ic_mutex);
cip = clientp->ic_myci;
/* remove the client from the list of clients */
ibmf_i_delete_client(cip, clientp);
/* release the reference to the qp */
ibmf_i_release_qp(cip, &clientp->ic_qp);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*clientp))
/* and free the client structure */
ibmf_i_free_client(clientp);
/* release the ci; this may delete & free the ci structure */
ibmf_i_release_ci(cip);
/* decrement kstats for number of registered clients */
mutex_enter(&cip->ci_mutex);
IBMF_SUB32_PORT_KSTATS(cip, clients_registered, 1);
mutex_exit(&cip->ci_mutex);
*ibmf_handlep = NULL;
bail:
if (error) {
IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_unregister_err, IBMF_TNF_ERROR, "",
"ibmf_unregister(): %s\n", tnf_string, msg, errmsg);
}
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_unregister_end,
IBMF_TNF_TRACE, "", "ibmf_unregister() exit\n");
return (status);
}
/* ARGSUSED */
int
ibmf_setup_async_cb(ibmf_handle_t ibmf_handle, ibmf_qp_handle_t ibmf_qp_handle,
ibmf_msg_cb_t async_msg_cb, void *async_msg_cb_args, uint_t flags)
{
ibmf_client_t *clientp;
boolean_t error = B_FALSE;
int status = IBMF_SUCCESS;
char errmsg[128];
clientp = (ibmf_client_t *)ibmf_handle;
IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_setup_async_cb_start,
IBMF_TNF_TRACE, "", "ibmf_setup_async_cb() enter, "
"ibmf_handlep = %p, cb = 0x%p, cb_args = 0x%p, flags = 0x%x\n",
tnf_opaque, ibmf_handle, ibmf_handle, tnf_opaque, cb,
async_msg_cb, tnf_opaque, cb_args, async_msg_cb_args,
tnf_uint, flags, flags);
/* check for null ibmf_handlep */
if (ibmf_handle == NULL) {
(void) sprintf(errmsg,
"invalid argument, NULL pointer argument");
error = B_TRUE;
status = IBMF_INVALID_ARG;
goto bail;
}
/* validate ibmf_handle */
if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
(void) sprintf(errmsg, "bad ibmf registration handle");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
/* validate ibmf_qp_handle */
if (ibmf_i_is_qp_handle_valid(ibmf_handle, ibmf_qp_handle) !=
IBMF_SUCCESS) {
(void) sprintf(errmsg, "bad qp handle");
error = B_TRUE;
status = IBMF_BAD_QP_HANDLE;
goto bail;
}
/* check signature */
if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
(void) sprintf(errmsg, "bad signature");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
ASSERT(clientp->ic_myci != NULL);
/* store the registered callback in the appropriate context */
if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
/*
* if using the default QP handle, store the callback in
* the client context
*/
mutex_enter(&clientp->ic_mutex);
/* check if the callback has already been registered */
if (clientp->ic_recv_cb != NULL) {
mutex_exit(&clientp->ic_mutex);
(void) sprintf(errmsg, "cb already exists");
error = B_TRUE;
status = IBMF_CB_REGISTERED;
goto bail;
}
clientp->ic_recv_cb = async_msg_cb;
clientp->ic_recv_cb_arg = async_msg_cb_args;
mutex_exit(&clientp->ic_mutex);
} else {
ibmf_alt_qp_t *qp_ctxp = (ibmf_alt_qp_t *)ibmf_qp_handle;
/*
* if using an alternate QP handle, store the callback in
* the alternate QP context because there can be more than
* one alternate QP associated with a client
*/
mutex_enter(&qp_ctxp->isq_mutex);
/* check if the callback has already been registered */
if (qp_ctxp->isq_recv_cb != NULL) {
mutex_exit(&qp_ctxp->isq_mutex);
(void) sprintf(errmsg, "cb already exists");
error = B_TRUE;
status = IBMF_CB_REGISTERED;
goto bail;
}
qp_ctxp->isq_recv_cb = async_msg_cb;
qp_ctxp->isq_recv_cb_arg = async_msg_cb_args;
mutex_exit(&qp_ctxp->isq_mutex);
}
bail:
if (error) {
IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_setup_async_cb_err, IBMF_TNF_ERROR, "",
"ibmf_setup_async_cb(): %s\n", tnf_string, msg, errmsg);
}
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_setup_async_cb_end,
IBMF_TNF_TRACE, "", "ibmf_setup_async_cb() exit\n");
return (status);
}
/* ARGSUSED */
int
ibmf_tear_down_async_cb(ibmf_handle_t ibmf_handle,
ibmf_qp_handle_t ibmf_qp_handle, uint_t flags)
{
ibmf_client_t *clientp;
boolean_t error = B_FALSE;
int status = IBMF_SUCCESS;
char errmsg[128];
clientp = (ibmf_client_t *)ibmf_handle;
IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_tear_down_async_cb_start,
IBMF_TNF_TRACE, "", "ibmf_tear_down_async_cb() enter, "
"ibmf_handlep = %p, ibmf_qp_handle = %p, flags = 0x%x\n",
tnf_opaque, ibmf_handle, ibmf_handle,
tnf_opaque, ibmf_qp_handle, ibmf_qp_handle, tnf_uint, flags, flags);
/* check for null ibmf_handlep */
if (ibmf_handle == NULL) {
(void) sprintf(errmsg,
"invalid argument, NULL pointer argument");
error = B_TRUE;
status = IBMF_INVALID_ARG;
goto bail;
}
/* validate ibmf_handle */
if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
(void) sprintf(errmsg, "bad ibmf registration handle");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
/* validate ibmf_qp_handle */
if (ibmf_i_is_qp_handle_valid(ibmf_handle, ibmf_qp_handle) !=
IBMF_SUCCESS) {
(void) sprintf(errmsg, "bad qp handle");
error = B_TRUE;
status = IBMF_BAD_QP_HANDLE;
goto bail;
}
/* check signature */
if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
(void) sprintf(errmsg, "bad signature");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
ASSERT(clientp->ic_myci != NULL);
/* remove the registered callback from the appropriate context */
if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
mutex_enter(&clientp->ic_mutex);
/* check if callback has not been registered */
if (clientp->ic_recv_cb == NULL) {
mutex_exit(&clientp->ic_mutex);
(void) sprintf(errmsg, "no cb exists");
error = B_TRUE;
status = IBMF_CB_NOT_REGISTERED;
goto bail;
}
/*
* if an unsolicited MAD just arrived for this
* client, wait for it to be processed
*/
while (clientp->ic_flags & IBMF_CLIENT_RECV_CB_ACTIVE) {
clientp->ic_flags |= IBMF_CLIENT_TEAR_DOWN_CB;
cv_wait(&clientp->ic_recv_cb_teardown_cv,
&clientp->ic_mutex);
clientp->ic_flags &= ~IBMF_CLIENT_TEAR_DOWN_CB;
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(clientp->ic_recv_cb,
clientp->ic_recv_cb_arg))
/*
* if using the default QP handle, remove the callback from
* the client context
*/
clientp->ic_recv_cb = NULL;
clientp->ic_recv_cb_arg = NULL;
ASSERT((clientp->ic_flags & IBMF_CLIENT_RECV_CB_ACTIVE) == 0);
mutex_exit(&clientp->ic_mutex);
} else {
ibmf_alt_qp_t *qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
mutex_enter(&qpp->isq_mutex);
/* check if callback has not been registered */
if (qpp->isq_recv_cb == NULL) {
mutex_exit(&qpp->isq_mutex);
(void) sprintf(errmsg, "no cb exists");
error = B_TRUE;
status = IBMF_CB_NOT_REGISTERED;
goto bail;
}
/*
* if an unsolicited MAD just arrived for this
* client on the alternate QP, wait for it to be processed
*/
while (qpp->isq_flags & IBMF_CLIENT_RECV_CB_ACTIVE) {
qpp->isq_flags |= IBMF_CLIENT_TEAR_DOWN_CB;
cv_wait(&qpp->isq_recv_cb_teardown_cv,
&qpp->isq_mutex);
qpp->isq_flags &= ~IBMF_CLIENT_TEAR_DOWN_CB;
}
/*
* if using an alternate QP handle, remove the callback from
* the alternate QP context
*/
qpp->isq_recv_cb = NULL;
qpp->isq_recv_cb_arg = NULL;
ASSERT((qpp->isq_flags & IBMF_CLIENT_RECV_CB_ACTIVE) == 0);
mutex_exit(&qpp->isq_mutex);
}
bail:
if (error) {
IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_tear_down_async_cb_err, IBMF_TNF_ERROR, "",
"ibmf_tear_down_async_cb(): %s\n", tnf_string, msg, errmsg);
}
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_tear_down_async_cb_end,
IBMF_TNF_TRACE, "", "ibmf_tear_down_async_cb() exit\n");
return (status);
}
int
ibmf_alloc_msg(ibmf_handle_t ibmf_handle, int flag, ibmf_msg_t **ibmf_msgpp)
{
ibmf_msg_impl_t *ibmf_msg_impl;
ibmf_client_t *clientp;
int km_flags;
boolean_t error = B_FALSE;
int status = IBMF_SUCCESS;
char errmsg[128];
clientp = (ibmf_client_t *)ibmf_handle;
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_alloc_msg_start,
IBMF_TNF_TRACE, "", "ibmf_alloc_msg() enter, "
"ibmf_handle = %p, flags = 0x%x\n",
tnf_opaque, ibmf_handle, ibmf_handle, tnf_uint, flag, flag);
/* check for null ibmf_handle and ibmf_msgpp */
if ((ibmf_handle == NULL) || (ibmf_msgpp == NULL)) {
(void) sprintf(errmsg,
"invalid argument, NULL pointer argument");
error = B_TRUE;
status = IBMF_INVALID_ARG;
goto bail;
}
/* validate ibmf_handle */
if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
(void) sprintf(errmsg, "bad ibmf registration handle");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
/* check signature */
if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
(void) sprintf(errmsg, "bad signature");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
/* validate flag */
if (flag != IBMF_ALLOC_SLEEP && flag != IBMF_ALLOC_NOSLEEP) {
(void) sprintf(errmsg, "invalid flags, flags = 0x%x", flag);
error = B_TRUE;
status = IBMF_BAD_FLAGS;
goto bail;
}
/* set flags for kmem allocaton */
km_flags = (flag == IBMF_ALLOC_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ibmf_msg_impl))
/* call the internal function to allocate the IBMF message context */
status = ibmf_i_alloc_msg(clientp, &ibmf_msg_impl, km_flags);
if (status != IBMF_SUCCESS) {
mutex_enter(&clientp->ic_kstat_mutex);
IBMF_ADD32_KSTATS(clientp, msg_allocs_failed, 1);
mutex_exit(&clientp->ic_kstat_mutex);
(void) sprintf(errmsg, "message allocation failure");
error = B_TRUE;
goto bail;
}
/* increment counter and kstats for number of allocated messages */
mutex_enter(&clientp->ic_mutex);
clientp->ic_msgs_alloced++;
mutex_exit(&clientp->ic_mutex);
mutex_enter(&clientp->ic_kstat_mutex);
IBMF_ADD32_KSTATS(clientp, msgs_alloced, 1);
mutex_exit(&clientp->ic_kstat_mutex);
/* initialize the msg */
ibmf_msg_impl->im_client = clientp;
cv_init(&ibmf_msg_impl->im_trans_cv, NULL, CV_DRIVER, NULL);
mutex_init(&ibmf_msg_impl->im_mutex, NULL, MUTEX_DRIVER, NULL);
*ibmf_msgpp = (ibmf_msg_t *)ibmf_msg_impl;
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*ibmf_msg_impl))
bail:
if (error) {
IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_alloc_msg_err, IBMF_TNF_ERROR, "",
"ibmf_alloc_msg(): %s\n", tnf_string, msg, errmsg);
}
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_alloc_msg_end,
IBMF_TNF_TRACE, "", "ibmf_alloc_msg() exit\n");
return (status);
}
int
ibmf_free_msg(ibmf_handle_t ibmf_handle, ibmf_msg_t **ibmf_msgpp)
{
ibmf_client_t *clientp;
ibmf_msg_impl_t *ibmf_msg_impl;
boolean_t error = B_FALSE;
int status = IBMF_SUCCESS;
char errmsg[128];
timeout_id_t msg_rp_set_id, msg_tr_set_id;
timeout_id_t msg_rp_unset_id, msg_tr_unset_id;
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_free_msg_start,
IBMF_TNF_TRACE, "", "ibmf_free_msg() enter, " "ibmf_handle = %p\n",
tnf_opaque, ibmf_handle, ibmf_handle);
/* check for null ibmf_handle and ibmf_msgpp */
if ((ibmf_handle == NULL) || (ibmf_msgpp == NULL)) {
(void) sprintf(errmsg,
"invalid argument, NULL pointer argument");
error = B_TRUE;
status = IBMF_INVALID_ARG;
goto bail;
}
/* validate ibmf_handle */
if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
(void) sprintf(errmsg, "bad ibmf registration handle");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
ibmf_msg_impl = (ibmf_msg_impl_t *)*ibmf_msgpp;
/* check for null message pointer */
if (ibmf_msg_impl == NULL) {
(void) sprintf(errmsg, "null message");
error = B_TRUE;
status = IBMF_FAILURE;
goto bail;
}
mutex_enter(&ibmf_msg_impl->im_mutex);
/* check if message context flags indicate a busy message */
if (ibmf_msg_impl->im_flags & IBMF_MSG_FLAGS_BUSY) {
mutex_exit(&ibmf_msg_impl->im_mutex);
(void) sprintf(errmsg, "message in use");
error = B_TRUE;
status = IBMF_BUSY;
goto bail;
}
ASSERT((ibmf_msg_impl->im_flags & IBMF_MSG_FLAGS_ON_LIST) == 0);
/* Initialize the timer ID holders */
msg_rp_set_id = msg_tr_set_id = 0;
msg_rp_unset_id = msg_tr_unset_id = 0;
/* Clear any timers that are still set */
if (ibmf_msg_impl->im_rp_timeout_id != 0) {
msg_rp_set_id = ibmf_msg_impl->im_rp_timeout_id;
ibmf_msg_impl->im_rp_timeout_id = 0;
}
if (ibmf_msg_impl->im_tr_timeout_id != 0) {
msg_tr_set_id = ibmf_msg_impl->im_tr_timeout_id;
ibmf_msg_impl->im_tr_timeout_id = 0;
}
if (ibmf_msg_impl->im_rp_unset_timeout_id != 0) {
msg_rp_unset_id = ibmf_msg_impl->im_rp_unset_timeout_id;
ibmf_msg_impl->im_rp_unset_timeout_id = 0;
}
if (ibmf_msg_impl->im_tr_unset_timeout_id != 0) {
msg_tr_unset_id = ibmf_msg_impl->im_tr_unset_timeout_id;
ibmf_msg_impl->im_tr_unset_timeout_id = 0;
}
/* mark the message context flags to indicate a freed message */
ibmf_msg_impl->im_flags |= IBMF_MSG_FLAGS_FREE;
mutex_exit(&ibmf_msg_impl->im_mutex);
/* cast pointer to client context */
clientp = (ibmf_client_t *)ibmf_handle;
/* check signature */
if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
(void) sprintf(errmsg, "bad signature");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
/* Clear the timers */
if (msg_rp_unset_id != 0) {
(void) untimeout(msg_rp_unset_id);
}
if (msg_tr_unset_id != 0) {
(void) untimeout(msg_tr_unset_id);
}
if (msg_rp_set_id != 0) {
(void) untimeout(msg_rp_set_id);
}
if (msg_tr_set_id != 0) {
(void) untimeout(msg_tr_set_id);
}
/* destroy the condition variables */
cv_destroy(&ibmf_msg_impl->im_trans_cv);
/* decrement counter and kstats for number of allocated messages */
mutex_enter(&clientp->ic_mutex);
clientp->ic_msgs_alloced--;
mutex_exit(&clientp->ic_mutex);
mutex_enter(&clientp->ic_kstat_mutex);
IBMF_SUB32_KSTATS(clientp, msgs_alloced, 1);
mutex_exit(&clientp->ic_kstat_mutex);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ibmf_msg_impl,
ibmf_msg_impl->im_msgbufs_recv,
ibmf_msg_impl->im_msgbufs_send))
/* call the internal function to free the message context */
ibmf_i_free_msg(ibmf_msg_impl);
*ibmf_msgpp = NULL;
bail:
if (error) {
IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_free_msg_err, IBMF_TNF_ERROR, "",
"ibmf_free_msg(): %s\n", tnf_string, msg, errmsg);
}
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_free_msg_end,
IBMF_TNF_TRACE, "", "ibmf_free_msg() exit\n");
return (status);
}
/* ARGSUSED */
int
ibmf_msg_transport(ibmf_handle_t ibmf_handle, ibmf_qp_handle_t ibmf_qp_handle,
ibmf_msg_t *msgp, ibmf_retrans_t *retrans, ibmf_msg_cb_t msg_cb,
void *msg_cb_args, uint_t flags)
{
ibmf_client_t *clientp;
ibmf_msg_impl_t *msgimplp;
boolean_t blocking, loopback, error = B_FALSE;
int status = IBMF_SUCCESS;
sm_dr_mad_hdr_t *dr_hdr;
char errmsg[128];
IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_msg_transport_start,
IBMF_TNF_TRACE, "", "ibmf_msg_transport() enter, "
"ibmf_handlep = %p, ibmf_qp_handle = %p, flags = 0x%x "
"msgp = 0x%p, retrans = 0x%p\n",
tnf_opaque, ibmf_handle, ibmf_handle,
tnf_opaque, ibmf_qp_handle, ibmf_qp_handle, tnf_uint, flags, flags,
tnf_opaque, msgp, msgp, tnf_opaque, retrans, retrans);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msgp,*msgimplp))
/* check for null ibmf_handle and msgp */
if ((ibmf_handle == NULL) || (msgp == NULL)) {
(void) sprintf(errmsg,
"invalid argument, NULL pointer argument");
error = B_TRUE;
status = IBMF_INVALID_ARG;
goto bail;
}
/* validate ibmf_handle */
if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
(void) sprintf(errmsg, "bad ibmf registration handle");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
/* validate ibmf_qp_handle */
if (ibmf_i_is_qp_handle_valid(ibmf_handle, ibmf_qp_handle) !=
IBMF_SUCCESS) {
(void) sprintf(errmsg, "bad qp handle");
error = B_TRUE;
status = IBMF_BAD_QP_HANDLE;
goto bail;
}
clientp = (ibmf_client_t *)ibmf_handle;
/* check signature */
if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
(void) sprintf(errmsg, "bad signature");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
/*
* Check the validity of the pkey and qkey in the posted packet
* For special QPs do the check for QP1 only
* For the alternate qps, the pkey and qkey should match the
* pkey and qkey maintained in the ibmf cached qp context
*/
if ((ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) &&
((clientp->ic_client_info.client_class != SUBN_AGENT) &&
(clientp->ic_client_info.client_class != SUBN_ADM_AGENT) &&
(clientp->ic_client_info.client_class != SUBN_MANAGER))) {
if ((msgp->im_local_addr.ia_p_key != IBMF_P_KEY_DEF_FULL) &&
(msgp->im_local_addr.ia_p_key != IBMF_P_KEY_DEF_LIMITED)) {
(void) sprintf(errmsg,
"PKey in packet not default PKey");
error = B_TRUE;
status = IBMF_BAD_QP_HANDLE;
goto bail;
}
if (msgp->im_local_addr.ia_q_key != IBMF_MGMT_Q_KEY) {
(void) sprintf(errmsg, "QKey in packet not Mgt QKey");
error = B_TRUE;
status = IBMF_BAD_QP_HANDLE;
goto bail;
}
} else if (ibmf_qp_handle != IBMF_QP_HANDLE_DEFAULT) {
ibmf_alt_qp_t *qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
/* alternate QP context */
mutex_enter(&qpp->isq_mutex);
if (msgp->im_local_addr.ia_p_key != qpp->isq_pkey) {
mutex_exit(&qpp->isq_mutex);
(void) sprintf(errmsg, "PKey in packet does not match "
"PKey in the QP context");
error = B_TRUE;
status = IBMF_BAD_QP_HANDLE;
goto bail;
}
if (msgp->im_local_addr.ia_q_key != qpp->isq_qkey) {
mutex_exit(&qpp->isq_mutex);
(void) sprintf(errmsg, "QKey in packet does not match "
"QKey in the QP context");
error = B_TRUE;
status = IBMF_BAD_QP_HANDLE;
goto bail;
}
mutex_exit(&qpp->isq_mutex);
}
msgimplp = (ibmf_msg_impl_t *)msgp;
ASSERT(msgimplp->im_client != NULL);
ASSERT(msgimplp->im_client == clientp);
msgimplp->im_transp_op_flags = flags;
mutex_enter(&msgimplp->im_mutex);
if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
if (msgimplp->im_msgbufs_send.im_bufs_mad_hdr == NULL) {
mutex_exit(&msgimplp->im_mutex);
(void) sprintf(errmsg, "Send buffer MAD header data "
"not provided for special QP");
error = B_TRUE;
status = IBMF_BAD_SIZE;
goto bail;
}
} else {
ibmf_alt_qp_t *qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
mutex_enter(&qpp->isq_mutex);
if (((qpp->isq_flags & IBMF_RAW_ONLY) == 0) &&
(msgimplp->im_msgbufs_send.im_bufs_mad_hdr == NULL)) {
mutex_exit(&qpp->isq_mutex);
mutex_exit(&msgimplp->im_mutex);
(void) sprintf(errmsg, "Send buffer MAD header data "
"not provided for alternate QP");
error = B_TRUE;
status = IBMF_BAD_SIZE;
goto bail;
}
mutex_exit(&qpp->isq_mutex);
}
/* check if client has freed the message by calling ibmf_free_msg() */
if (msgimplp->im_flags & IBMF_MSG_FLAGS_FREE) {
mutex_exit(&msgimplp->im_mutex);
(void) sprintf(errmsg, "Message is being freed");
error = B_TRUE;
status = IBMF_BUSY;
goto bail;
}
/*
* check if the message is already in use in an
* ibmf_msg_transport() call
*/
if (msgimplp->im_flags & IBMF_MSG_FLAGS_BUSY) {
mutex_exit(&msgimplp->im_mutex);
(void) sprintf(errmsg,
"Message is being processed by an other thread");
error = B_TRUE;
status = IBMF_BUSY;
goto bail;
}
msgimplp->im_flags = IBMF_MSG_FLAGS_BUSY;
mutex_exit(&msgimplp->im_mutex);
/* check for the Directed Route SMP loopback case */
loopback = B_FALSE;
dr_hdr = (sm_dr_mad_hdr_t *)msgimplp->im_msgbufs_send.im_bufs_mad_hdr;
if ((dr_hdr->MgmtClass == MAD_MGMT_CLASS_SUBN_DIRECT_ROUTE) &&
(dr_hdr->HopCount == 0)) {
loopback = B_TRUE;
}
/* check for and perform DR loopback on tavor */
status = ibmf_i_check_for_loopback(msgimplp, msg_cb, msg_cb_args,
retrans, &loopback);
if (status != IBMF_SUCCESS) {
(void) sprintf(errmsg, "dr_loopback_check failed");
error = B_TRUE;
mutex_enter(&msgimplp->im_mutex);
msgimplp->im_flags &= ~IBMF_MSG_FLAGS_BUSY;
mutex_exit(&msgimplp->im_mutex);
goto bail;
}
if (loopback == B_TRUE) {
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_msg_transport_end, IBMF_TNF_TRACE, "",
"ibmf_msg_transport() exit, dr_loopback ok\n");
return (IBMF_SUCCESS);
}
if (msg_cb == NULL) {
blocking = B_TRUE;
} else {
blocking = B_FALSE;
}
/* initialize the message context */
ibmf_i_init_msg(msgimplp, msg_cb, msg_cb_args, retrans, blocking);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msgp,*msgimplp))
/* call the internal function to transport the message */
status = ibmf_i_msg_transport(clientp, ibmf_qp_handle, msgimplp,
blocking);
if (status != IBMF_SUCCESS) {
(void) sprintf(errmsg, "message transport failed");
error = B_TRUE;
mutex_enter(&msgimplp->im_mutex);
msgimplp->im_flags &= ~IBMF_MSG_FLAGS_BUSY;
mutex_exit(&msgimplp->im_mutex);
goto bail;
}
bail:
if (error) {
IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_msg_transport_err, IBMF_TNF_ERROR, "",
"ibmf_msg_transport(): %s\n", tnf_string, msg, errmsg);
}
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_msg_transport_end,
IBMF_TNF_TRACE, "", "ibmf_msg_transport() exit\n");
return (status);
}
/* ARGSUSED */
int
ibmf_alloc_qp(ibmf_handle_t ibmf_handle, ib_pkey_t p_key, ib_qkey_t q_key,
uint_t flags, ibmf_qp_handle_t *ibmf_qp_handlep)
{
ibmf_client_t *clientp = (ibmf_client_t *)ibmf_handle;
uint_t alloc_flags;
ibmf_alt_qp_t *qp_ctx;
boolean_t error = B_FALSE;
int status = IBMF_SUCCESS;
char errmsg[128];
IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_alloc_qp_start,
IBMF_TNF_TRACE, "", "ibmf_alloc_qp() enter, "
"ibmf_handlep = %p, p_key = 0x%x, q_key = 0x%x\n",
tnf_opaque, ibmf_handle, ibmf_handle,
tnf_uint, pkey, p_key, tnf_uint, qkey, q_key);
/* check for null ibmf_handle and ibmf_qp_handle */
if ((ibmf_handle == NULL) || (ibmf_qp_handlep == NULL)) {
(void) sprintf(errmsg,
"invalid argument, NULL pointer argument");
error = B_TRUE;
status = IBMF_INVALID_ARG;
goto bail;
}
/* validate ibmf_handle */
if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
(void) sprintf(errmsg, "bad ibmf registration handle");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
/* check signature */
if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
(void) sprintf(errmsg, "bad signature");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
/* validate PKey */
if (IBMF_INVALID_PKEY(p_key)) {
(void) sprintf(errmsg, "invalid value in p_key argument");
error = B_TRUE;
status = IBMF_INVALID_ARG;
goto bail;
}
if (((flags & IBMF_ALT_QP_MAD_NO_RMPP) == 0) &&
((flags & IBMF_ALT_QP_MAD_RMPP) == 0) &&
((flags & IBMF_ALT_QP_RAW_ONLY) == 0)) {
(void) sprintf(errmsg, "invalid flags combination");
error = B_TRUE;
status = IBMF_BAD_FLAGS;
goto bail;
}
alloc_flags = IBMF_ALLOC_SLEEP;
/* call the internal function to allocate the alternate QP context */
status = ibmf_i_alloc_qp(clientp, p_key, q_key, alloc_flags,
ibmf_qp_handlep);
if (status != IBMF_SUCCESS) {
mutex_enter(&clientp->ic_kstat_mutex);
IBMF_ADD32_KSTATS(clientp, alt_qp_allocs_failed, 1);
mutex_exit(&clientp->ic_kstat_mutex);
(void) sprintf(errmsg, "unable to allocate QP");
error = B_TRUE;
status = IBMF_NO_RESOURCES;
goto bail;
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*qp_ctx))
qp_ctx = (ibmf_alt_qp_t *)*ibmf_qp_handlep;
/* initialize the alternate qp context */
if (flags & IBMF_ALT_QP_MAD_NO_RMPP)
qp_ctx->isq_flags |= IBMF_MAD_ONLY;
if (flags & IBMF_ALT_QP_RAW_ONLY)
qp_ctx->isq_flags |= IBMF_RAW_ONLY;
if (flags & IBMF_ALT_QP_MAD_RMPP)
qp_ctx->isq_supports_rmpp = B_TRUE;
else
qp_ctx->isq_supports_rmpp = B_FALSE;
bail:
if (error) {
IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_alloc_qp_err, IBMF_TNF_ERROR, "",
"ibmf_alloc_qp(): %s\n", tnf_string, msg, errmsg);
}
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_alloc_qp_end,
IBMF_TNF_TRACE, "", "ibmf_alloc_qp() exit\n");
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*qp_ctx))
return (status);
}
/* ARGSUSED */
int
ibmf_query_qp(ibmf_handle_t ibmf_handle, ibmf_qp_handle_t ibmf_qp_handle,
uint_t *qp_num, ib_pkey_t *p_key, ib_qkey_t *q_key, uint8_t *portnum,
uint_t flags)
{
ibmf_client_t *clientp = (ibmf_client_t *)ibmf_handle;
ibmf_alt_qp_t *qp_ctx = (ibmf_alt_qp_t *)ibmf_qp_handle;
uint_t query_flags;
boolean_t error = B_FALSE;
int status = IBMF_SUCCESS;
char errmsg[128];
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_query_qp_start,
IBMF_TNF_TRACE, "", "ibmf_query_qp() enter, "
"ibmf_handlep = %p, ibmf_qp_handle = %p\n",
tnf_opaque, ibmf_handle, ibmf_handle,
tnf_opaque, ibmf_qp_handle, ibmf_qp_handle);
/* check for null args */
if ((ibmf_handle == NULL) || (ibmf_qp_handle == NULL) ||
(qp_num == NULL) || (p_key == NULL) || (q_key == NULL) ||
(portnum == NULL)) {
(void) sprintf(errmsg,
"invalid argument, NULL pointer argument");
error = B_TRUE;
status = IBMF_INVALID_ARG;
goto bail;
}
/* validate ibmf_handle */
if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
(void) sprintf(errmsg, "bad ibmf registration handle");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
/* validate ibmf_qp_handle */
if (ibmf_i_is_qp_handle_valid(ibmf_handle, ibmf_qp_handle) !=
IBMF_SUCCESS) {
(void) sprintf(errmsg, "bad qp handle");
error = B_TRUE;
status = IBMF_BAD_QP_HANDLE;
goto bail;
}
/* validate ibmf_qp_handle */
if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
(void) sprintf(errmsg, "bad qp handle (default)");
error = B_TRUE;
status = IBMF_BAD_QP_HANDLE;
goto bail;
}
/* check signature */
if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
(void) sprintf(errmsg, "bad client signature");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
/* validate client context handle */
if (qp_ctx->isq_client_hdl != clientp) {
(void) sprintf(errmsg, "bad QP handle");
error = B_TRUE;
status = IBMF_BAD_QP_HANDLE;
goto bail;
}
query_flags = IBMF_ALLOC_NOSLEEP;
/* call the internal function to query the alternate qp */
status = ibmf_i_query_qp(ibmf_qp_handle, query_flags, qp_num, p_key,
q_key, portnum);
if (status != IBMF_SUCCESS) {
(void) sprintf(errmsg, "unable to query QP");
error = B_TRUE;
goto bail;
}
bail:
if (error) {
IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_query_qp_err, IBMF_TNF_ERROR, "",
"ibmf_query_qp(): %s\n", tnf_string, msg, errmsg);
}
IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_query_qp_end,
IBMF_TNF_TRACE, "", "ibmf_query_qp() exit, qp = %d, "
"pkey = 0x%x, qkey = 0x%x\n", tnf_uint, qp_num, *qp_num,
tnf_uint, pkey, *p_key, tnf_uint, qkey, *q_key);
return (status);
}
/* ARGSUSED */
int
ibmf_modify_qp(ibmf_handle_t ibmf_handle, ibmf_qp_handle_t ibmf_qp_handle,
ib_pkey_t p_key, ib_qkey_t q_key, uint_t flags)
{
ibmf_client_t *clientp = (ibmf_client_t *)ibmf_handle;
ibmf_alt_qp_t *qp_ctx = (ibmf_alt_qp_t *)ibmf_qp_handle;
uint_t modify_flags;
boolean_t error = B_FALSE;
int status = IBMF_SUCCESS;
char errmsg[128];
IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_modify_qp_start,
IBMF_TNF_TRACE, "", "ibmf_modify_qp() enter, "
"ibmf_handlep = %p, ibmf_qp_handle = %p, pkey = 0x%x, "
"qkey = 0x%x\n", tnf_opaque, ibmf_handle, ibmf_handle,
tnf_opaque, ibmf_qp_handle, ibmf_qp_handle,
tnf_uint, p_key, p_key, tnf_uint, q_key, q_key);
/* check for null args */
if ((ibmf_handle == NULL) || (ibmf_qp_handle == NULL)) {
(void) sprintf(errmsg,
"invalid argument, NULL pointer argument");
error = B_TRUE;
status = IBMF_INVALID_ARG;
goto bail;
}
/* validate ibmf_handle */
if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
(void) sprintf(errmsg, "bad ibmf registration handle");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
/* validate ibmf_qp_handle */
if (ibmf_i_is_qp_handle_valid(ibmf_handle, ibmf_qp_handle) !=
IBMF_SUCCESS) {
(void) sprintf(errmsg, "bad qp handle");
error = B_TRUE;
status = IBMF_BAD_QP_HANDLE;
goto bail;
}
/* validate ibmf_qp_handle */
if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
(void) sprintf(errmsg, "bad qp handle (default)");
error = B_TRUE;
status = IBMF_BAD_QP_HANDLE;
goto bail;
}
/* check signature */
if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
(void) sprintf(errmsg, "bad client signature");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
/* validate PKey */
if (IBMF_INVALID_PKEY(p_key)) {
(void) sprintf(errmsg, "invalid value in p_key argument");
error = B_TRUE;
status = IBMF_INVALID_ARG;
goto bail;
}
if (qp_ctx->isq_client_hdl != clientp) {
(void) sprintf(errmsg, "bad QP handle");
error = B_TRUE;
status = IBMF_BAD_QP_HANDLE;
goto bail;
}
modify_flags = IBMF_ALLOC_SLEEP;
/* call the internal function to modify the qp */
status = ibmf_i_modify_qp(ibmf_qp_handle, p_key, q_key, modify_flags);
if (status != IBMF_SUCCESS) {
(void) sprintf(errmsg, "unable to modify QP");
error = B_TRUE;
goto bail;
}
bail:
if (error) {
IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_modify_qp_err, IBMF_TNF_ERROR, "",
"ibmf_modify_qp(): %s\n", tnf_string, msg, errmsg);
}
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_modify_qp_end,
IBMF_TNF_TRACE, "", "ibmf_modify_qp() exit\n");
return (status);
}
/* ARGSUSED */
int
ibmf_free_qp(ibmf_handle_t ibmf_handle, ibmf_qp_handle_t *ibmf_qp_handle,
uint_t flags)
{
ibmf_client_t *clientp = (ibmf_client_t *)ibmf_handle;
ibmf_alt_qp_t *qp_ctx = (ibmf_alt_qp_t *)*ibmf_qp_handle;
uint_t modify_flags;
boolean_t error = B_FALSE;
int status = IBMF_SUCCESS;
char errmsg[128];
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_free_qp_start,
IBMF_TNF_TRACE, "", "ibmf_free_qp() enter, "
"ibmf_handlep = %p, ibmf_qp_handle = %p\n",
tnf_opaque, ibmf_handle, ibmf_handle,
tnf_opaque, ibmf_qp_handle, *ibmf_qp_handle);
/* check for null args */
if ((ibmf_handle == NULL) || (ibmf_qp_handle == NULL)) {
(void) sprintf(errmsg,
"invalid argument, NULL pointer argument");
error = B_TRUE;
status = IBMF_INVALID_ARG;
goto bail;
}
/* validate ibmf_handle */
if (ibmf_i_is_ibmf_handle_valid(ibmf_handle) != IBMF_SUCCESS) {
(void) sprintf(errmsg, "bad ibmf registration handle");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
/* validate ibmf_qp_handle */
if (ibmf_i_is_qp_handle_valid(ibmf_handle, *ibmf_qp_handle) !=
IBMF_SUCCESS) {
(void) sprintf(errmsg, "bad qp handle");
error = B_TRUE;
status = IBMF_BAD_QP_HANDLE;
goto bail;
}
/* validate ibmf_qp_handle */
if (*ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
(void) sprintf(errmsg, "bad qp handle (default)");
error = B_TRUE;
status = IBMF_BAD_QP_HANDLE;
goto bail;
}
/* check signature */
if (IBMF_VERIFY_CLIENT_SIGNATURE(clientp) == B_FALSE) {
(void) sprintf(errmsg, "bad client signature");
error = B_TRUE;
status = IBMF_BAD_HANDLE;
goto bail;
}
/* validate client context handle */
if (qp_ctx->isq_client_hdl != clientp) {
(void) sprintf(errmsg, "bad QP handle");
error = B_TRUE;
status = IBMF_BAD_QP_HANDLE;
goto bail;
}
mutex_enter(&qp_ctx->isq_mutex);
if (qp_ctx->isq_recv_cb != NULL) {
mutex_exit(&qp_ctx->isq_mutex);
(void) sprintf(errmsg, "QP busy, callback active");
error = B_TRUE;
status = IBMF_BUSY;
goto bail;
}
mutex_exit(&qp_ctx->isq_mutex);
modify_flags = IBMF_ALLOC_SLEEP;
status = ibmf_i_free_qp(*ibmf_qp_handle, modify_flags);
if (status != IBMF_SUCCESS) {
(void) sprintf(errmsg, "unable to free QP");
error = B_TRUE;
goto bail;
}
*ibmf_qp_handle = NULL;
bail:
if (error) {
IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_free_qp_err, IBMF_TNF_ERROR, "",
"ibmf_free_qp(): %s\n", tnf_string, msg, errmsg);
}
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_free_qp_end,
IBMF_TNF_TRACE, "", "ibmf_free_qp() exit\n");
return (status);
}