/*
* 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
* 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
*/
/*
*/
/*
* This file implements the client interfaces of the IBMF.
*/
extern ibmf_state_t *ibmf_statep;
/* global settable */
#define IBMF_MAD_CL_HDR_OFF_1 0
#define IBMF_MAD_CL_HDR_SZ_3 0
((client_type) == SUBN_AGENT || \
(client_type) == SUBN_MANAGER || \
(client_type) == SUBN_ADM_AGENT || \
(client_type) == SUBN_ADM_MANAGER || \
(client_type) == PERF_AGENT || \
(client_type) == PERF_MANAGER || \
(client_type) == BM_AGENT || \
(client_type) == BM_MANAGER || \
(client_type) == DEV_MGT_AGENT || \
(client_type) == DEV_MGT_MANAGER || \
(client_type) == COMM_MGT_MANAGER_AGENT || \
(client_type) == SNMP_MANAGER_AGENT || \
(client_type) == VENDOR_09_MANAGER_AGENT || \
(client_type) == VENDOR_0A_MANAGER_AGENT || \
(client_type) == VENDOR_0B_MANAGER_AGENT || \
(client_type) == VENDOR_0C_MANAGER_AGENT || \
(client_type) == VENDOR_0D_MANAGER_AGENT || \
(client_type) == VENDOR_0E_MANAGER_AGENT || \
(client_type) == VENDOR_0F_MANAGER_AGENT || \
(client_type) == VENDOR_30_MANAGER_AGENT || \
(client_type) == VENDOR_31_MANAGER_AGENT || \
(client_type) == VENDOR_32_MANAGER_AGENT || \
(client_type) == VENDOR_33_MANAGER_AGENT || \
(client_type) == VENDOR_34_MANAGER_AGENT || \
(client_type) == VENDOR_35_MANAGER_AGENT || \
(client_type) == VENDOR_36_MANAGER_AGENT || \
(client_type) == VENDOR_37_MANAGER_AGENT || \
(client_type) == VENDOR_38_MANAGER_AGENT || \
(client_type) == VENDOR_39_MANAGER_AGENT || \
(client_type) == VENDOR_3A_MANAGER_AGENT || \
(client_type) == VENDOR_3B_MANAGER_AGENT || \
(client_type) == VENDOR_3C_MANAGER_AGENT || \
(client_type) == VENDOR_3D_MANAGER_AGENT || \
(client_type) == VENDOR_3E_MANAGER_AGENT || \
(client_type) == VENDOR_3F_MANAGER_AGENT || \
(client_type) == VENDOR_40_MANAGER_AGENT || \
(client_type) == VENDOR_41_MANAGER_AGENT || \
(client_type) == VENDOR_42_MANAGER_AGENT || \
(client_type) == VENDOR_43_MANAGER_AGENT || \
(client_type) == VENDOR_44_MANAGER_AGENT || \
(client_type) == VENDOR_45_MANAGER_AGENT || \
(client_type) == VENDOR_46_MANAGER_AGENT || \
(client_type) == VENDOR_47_MANAGER_AGENT || \
(client_type) == VENDOR_48_MANAGER_AGENT || \
(client_type) == VENDOR_49_MANAGER_AGENT || \
(client_type) == VENDOR_4A_MANAGER_AGENT || \
(client_type) == VENDOR_4B_MANAGER_AGENT || \
(client_type) == VENDOR_4C_MANAGER_AGENT || \
(client_type) == VENDOR_4D_MANAGER_AGENT || \
(client_type) == VENDOR_4E_MANAGER_AGENT || \
(client_type) == VENDOR_4F_MANAGER_AGENT || \
(client_type) == APPLICATION_10_MANAGER_AGENT || \
(client_type) == APPLICATION_11_MANAGER_AGENT || \
(client_type) == APPLICATION_12_MANAGER_AGENT || \
(client_type) == APPLICATION_13_MANAGER_AGENT || \
(client_type) == APPLICATION_14_MANAGER_AGENT || \
(client_type) == APPLICATION_15_MANAGER_AGENT || \
(client_type) == APPLICATION_16_MANAGER_AGENT || \
(client_type) == APPLICATION_17_MANAGER_AGENT || \
(client_type) == APPLICATION_18_MANAGER_AGENT || \
(client_type) == APPLICATION_19_MANAGER_AGENT || \
(client_type) == APPLICATION_1A_MANAGER_AGENT || \
(client_type) == APPLICATION_1B_MANAGER_AGENT || \
(client_type) == APPLICATION_1C_MANAGER_AGENT || \
(client_type) == APPLICATION_1D_MANAGER_AGENT || \
(client_type) == APPLICATION_1E_MANAGER_AGENT || \
(client_type) == APPLICATION_1F_MANAGER_AGENT || \
(client_type) == APPLICATION_20_MANAGER_AGENT || \
(client_type) == APPLICATION_21_MANAGER_AGENT || \
(client_type) == APPLICATION_22_MANAGER_AGENT || \
(client_type) == APPLICATION_23_MANAGER_AGENT || \
(client_type) == APPLICATION_24_MANAGER_AGENT || \
(client_type) == APPLICATION_25_MANAGER_AGENT || \
(client_type) == APPLICATION_26_MANAGER_AGENT || \
(client_type) == APPLICATION_27_MANAGER_AGENT || \
(client_type) == APPLICATION_28_MANAGER_AGENT || \
(client_type) == APPLICATION_29_MANAGER_AGENT || \
(client_type) == APPLICATION_2A_MANAGER_AGENT || \
(client_type) == APPLICATION_2B_MANAGER_AGENT || \
(client_type) == APPLICATION_2C_MANAGER_AGENT || \
(client_type) == APPLICATION_2D_MANAGER_AGENT || \
(client_type) == APPLICATION_2E_MANAGER_AGENT || \
(client_type) == APPLICATION_2F_MANAGER_AGENT || \
(client_type) == UNIVERSAL_CLASS)
/*
* ibmf_init():
* Initializes module state and registers with the IBT framework.
* Returns 0 if initialization was successful, else returns non-zero.
*/
int
ibmf_init(void)
{
/* setup the IBT module information */
/* setup a connection to IB transport layer (IBTF) */
(void *)NULL, (void *)&ibmf_ibt_handle);
if (status != IBT_SUCCESS) {
return (1);
}
/* initialize the IBMF state context */
return (0);
}
/*
* ibmf_fini():
* Cleans up module state resources and unregisters from IBT framework.
*/
int
ibmf_fini(void)
{
/* free all the Channel Interface (CI) context structures */
/* free up the ci structure */
}
}
/* detach from IBTF */
if (status != IBT_SUCCESS) {
return (1);
}
return (0);
}
/*
* ibmf_i_validate_class_mask():
* Checks client type value in client information structure.
*/
int
{
"ibmf_i_validate_class_mask() enter, client_infop = %p\n",
"ibmf_i_validate_class_mask() exit\n");
return (IBMF_BAD_CLASS);
}
return (IBMF_SUCCESS);
}
/*
* ibmf_i_validate_ci_guid_and_port():
* Checks validity of port number and HCA GUID at client
* registration time.
*/
int
{
"ibmf_i_validate_ci_guid_and_port() enter, hca_guid = %x, "
/* check for incorrect port number specification */
if (port_num == 0) {
"ibmf_i_validate_ci_guid_and_port() exit\n");
return (IBMF_BAD_PORT);
}
/* call IB transport layer for HCA attributes */
if (status != IBT_SUCCESS) {
"ibmf_i_validate_ci_guid_and_port() exit\n");
return (IBMF_BAD_NODE);
}
/* check if the specified port number is within the HCAs range */
"%s, num = %d, hca_ports = %d\n",
"ibmf_i_validate_ci_guid_and_port() exit\n");
return (IBMF_BAD_PORT);
}
"ibmf_i_validate_ci_guid_and_port() exit\n");
return (IBMF_SUCCESS);
}
/*
* ibmf_i_lookup_ci():
* Lookup the ci and return if found. If the CI is not found, returns
* NULL.
*/
static ibmf_ci_t *
{
/* walk the CI list looking for one that matches the provided GUID */
/* found it in our list */
break;
}
}
return (cip);
}
/*
* ibmf_i_get_ci():
* Get the CI structure based on the HCA GUID from a list if it exists.
* If the CI structure does not exist, and the HCA GUID is valid,
* create a new CI structure and add it to the list.
*/
int
{
/* look for a CI context with a matching GUID */
/*
* attempt to create the ci. First, verify the ci exists.
* If it exists, allocate ci memory and insert in the ci list.
* It is possible that some other thread raced with us
* and inserted created ci while we are blocked in
* allocating memory. Check for that case and if that is indeed
* the case, free up what we allocated and try to get a
* reference count on the ci that the other thread added.
*/
&hca_attrs);
if (status == IBT_SUCCESS) {
/* allocate memory for the CI structure */
KM_SLEEP);
NULL);
NULL);
/* set up per CI kstats */
"misc", KSTAT_TYPE_NAMED,
sizeof (ibmf_port_kstat_t) / sizeof (kstat_named_t),
KSTAT_FLAG_WRITABLE)) == NULL) {
"kstat create failed");
"ibmf_i_get_ci() exit\n");
return (IBMF_NO_RESOURCES);
}
"clients_registered", KSTAT_DATA_UINT32);
"client_registrations_failed", KSTAT_DATA_UINT32);
"send_wqes_allocated", KSTAT_DATA_UINT32);
"receive_wqes_allocated", KSTAT_DATA_UINT32);
"send_wqe_allocs_failed", KSTAT_DATA_UINT32);
"recv_wqe_allocs_failed", KSTAT_DATA_UINT32);
if (client_infop->ir_ci_guid ==
tcip->ci_node_guid) {
/* found it in our list */
break;
}
}
/* if the ci isn't on the list, add it */
} else {
/* free cip and set it to the one on the list */
}
} else {
/* we didn't find it and the CI doesn't exist */
"ibmf_i_get_ci() exit\n");
return (IBMF_TRANSPORT_FAILURE);
}
}
/*
* We now have a CI context structure, either found it on the list,
* or created it.
* We now proceed to intialize the CI context.
*/
for (;;) {
/* CI is INITED & no state change in progress; we are all set */
IBMF_CI_STATE_UNINITING)) == 0) {
break;
}
/* CI is PRESENT; transition it to INITED */
IBMF_CI_STATE_INITING)) == 0) {
/* mark state as initing and init the ci */
break;
}
continue;
}
/*
* If CI is GONE and no validation is in progress, we should
* return failure. Also, if CI is INITED but in the process of
* being made GONE (ie., a hot remove in progress), return
* failure.
*/
ci_state_flags & IBMF_CI_STATE_VALIDATING) == 0) ||
ci_state_flags & IBMF_CI_STATE_INVALIDATING) != 0)) {
"ci_state = %x, ci_state_flags = %x\n",
break;
}
/* a state change in progress; block waiting for state change */
}
return (IBMF_FAILURE);
}
return (IBMF_SUCCESS);
} else {
return (IBMF_FAILURE);
}
}
/*
* ibmf_i_release_ci():
* Drop the reference count for the CI.
*/
void
{
if (ref == 1) {
}
if (ref == 1) {
}
}
/*
* ibmf_i_init_ci():
* Initialize the CI structure by setting up the HCA, allocating
* protection domains, completion queues, a pool of WQEs.
*/
/* ARGSUSED */
static int
{
/* set up a connection to the HCA specified by the GUID */
&hca_handle);
if (status != IBT_SUCCESS) {
status);
goto bail;
}
/* get the HCA attributes */
if (status != IBT_SUCCESS) {
(void) ibt_close_hca(hca_handle);
status);
goto bail;
}
/* allocate a Protection Domain */
if (status != IBT_SUCCESS) {
(void) ibt_close_hca(hca_handle);
status);
goto bail;
}
/* init the ci */
/* initialize cqs */
goto bail;
}
/* initialize wqes */
goto bail;
}
/* initialize the UD destination structure pool */
/* initialize the QP list */
/* initialize condition variable, state, and enable CQ notification */
/* set state to INITED */
/* wake up waiters blocked on an initialization done event */
bail:
if (error) {
}
return (ibmfstatus);
}
/*
* ibmf_i_uninit_ci():
* Free up the resources allocated when initializing the CI structure.
*/
static void
{
/* clean up the QP list */
/* empty completions directly */
}
/* clean up the UD destination structure pool */
/* clean up any WQE caches */
/* free up the completion queues */
/* free up the protection domain */
/* close the HCA connection */
/* set state down to PRESENT */
/* wake up waiters blocked on an un-initialization done event */
}
/*
* ibmf_i_init_ci_done():
* Mark CI initialization as "done", and wake up any waiters.
*/
static void
{
}
}
/*
* ibmf_i_uninit_ci_done():
* Mark CI uninitialization as "done", and wake up any waiters.
*/
static void
{
}
}
/*
* ibmf_i_init_cqs():
* Allocate a completion queue and set the CQ handler.
*/
static int
{
/*
* Allocate completion queue handle.
* The CQ size should be a 2^n - 1 value to avoid excess CQ allocation
* as done by some HCAs when the CQ size is specified as a 2^n
* quantity.
*/
ibmf_recv_wqes_posted_per_qp)) - 1;
/* Get the CQ handle for the special QPs */
&cq_handle, &num_entries);
if (status != IBT_SUCCESS) {
return (IBMF_TRANSPORT_FAILURE);
}
/* Get the CQ handle for the alternate QPs */
&cq_handle, &num_entries);
if (status != IBT_SUCCESS) {
return (IBMF_TRANSPORT_FAILURE);
}
/* set state to CQ INITED */
return (IBMF_SUCCESS);
}
/*
* ibmf_i_fini_cqs():
* Free up the completion queue
*/
static void
{
if (ci_init_state & IBMF_CI_INIT_CQ_INITED) {
if (status != IBT_SUCCESS) {
}
if (status != IBT_SUCCESS) {
}
}
}
/*
* ibmf_i_init_qplist():
* Set the QP list inited state flag
*/
static void
{
NULL);
}
/*
* ibmf_i_fini_qplist():
* Clean up the QP list
*/
static void
{
/* walk through the qp list and free the memory */
/* Remove qpp from the list */
/* Flush the special QP */
if (status != IBT_SUCCESS) {
IBMF_TNF_ERROR, "",
"%s, status = %d\n", tnf_string,
msg, "ibt_flush_qp returned error",
}
/* Grab the ci_mutex mutex before waiting */
/* Wait if WQEs for special QPs are alloced */
while (ibmf_cip->ci_wqes_alloced != 0) {
}
/* Free the special QP */
if (status != IBT_SUCCESS) {
IBMF_TNF_ERROR, "",
"%s, status = %d\n", tnf_string,
msg, "ibt_free_qp returned error",
}
}
/* Grab the mutex again before accessing the QP list */
}
/* Remove altqpp from the list */
/* Flush the special QP */
if (status != IBT_SUCCESS) {
IBMF_TNF_ERROR, "",
"%s, status = %d\n", tnf_string,
msg, "ibt_flush_qp returned error",
}
/* Free the special QP */
if (status != IBT_SUCCESS) {
IBMF_TNF_ERROR, "",
"%s, status = %d\n", tnf_string,
msg, "ibt_free_qp returned error",
}
}
/* Grab the mutex again before accessing the QP list */
}
}
}
/*
* ibmf_i_alloc_client():
* Allocate and initialize the client structure.
*/
int
{
/* allocate memory for ibmf_client and initialize it */
/* create a taskq to handle send completions based on reg flags */
if ((flags & IBMF_REG_FLAG_NO_OFFLOAD) == 0) {
else
"ibmf_i_alloc_client() exit\n");
return (IBMF_NO_RESOURCES);
}
}
/* create a taskq to handle receive completions on reg flags */
if ((flags & IBMF_REG_FLAG_NO_OFFLOAD) == 0) {
else
"ibmf_i_alloc_client() exit\n");
return (IBMF_NO_RESOURCES);
}
}
/* Get the base LID */
/* set up the per client ibmf kstats */
KSTAT_FLAG_WRITABLE)) == NULL) {
if ((flags & IBMF_REG_FLAG_NO_OFFLOAD) == 0) {
}
"ibmf_i_alloc_client() exit\n");
return (IBMF_NO_RESOURCES);
}
*clientpp = ibmf_clientp;
return (IBMF_SUCCESS);
}
/*
* ibmf_i_free_client():
* Free up the client structure and release resources
*/
void
{
/* delete the general ibmf kstats */
}
/* release references and destroy the resources */
}
}
}
}
}
/*
* ibmf_i_validate_classes_and_port():
* Validate the class type and get the client structure
*/
int
{
int status;
"ibmf_i_validate_classes_and_port() enter, cip = %p, "
/*
* the Solaris implementation of IBMF does not support
* the UNIVERSAL_CLASS
*/
"UNIVERSAL class is not supported");
"ibmf_i_validate_classes_and_port() exit\n");
return (IBMF_NOT_SUPPORTED);
}
/*
* Check if the client context already exists on the list
* maintained in the CI context. If it is, then the client class
* has already been registered for.
*/
&ibmf_clientp);
if (status != IBMF_SUCCESS) {
/* client class has not been previously registered for */
} else {
"client already registered, class = 0x%X\n",
}
"ibmf_i_validate_classes_and_port() exit\n");
return (status);
}
/*
* ibmf_i_lookup_client_by_info():
* Get the client structure from the list
*/
static int
{
"ibmf_i_lookup_client_by_info() enter, cip = %p, clientinfo = %p\n",
/*
* walk the CI's client list searching for one with the specified class
*/
/* found our match */
break;
}
}
"ibmf_i_lookup_client_by_info(): clientp = %p\n",
return (IBMF_SUCCESS);
} else {
"ibmf_i_lookup_client_by_info() exit\n");
return (IBMF_FAILURE);
}
}
/*
* ibmf_i_add_client():
* Add a new client to the client list
*/
void
{
IBMF_TNF_TRACE, "",
"ibmf_i_add_client() enter, cip = %p, clientp = %p\n",
}
if (ibmf_cip->ci_clients_last) {
}
}
/*
* ibmf_i_delete_client():
* Delete a client from the client list
*/
void
{
"ibmf_i_delete_client() enter, cip = %p, clientp = %p\n",
if (ibmf_clientp->ic_next)
if (ibmf_clientp->ic_prev)
}
}
}
/*
* ibmf_i_get_qp():
* Get the QP structure based on the client class
*/
int
{
/*
* walk through the list of qps on this ci, looking for one that
* corresponds to the type and class the caller is interested in.
* If it is not there, we need allocate it from the transport. Since
* qp0 & qp1 can only be allocated once, we maintain a reference count
* and call the transport for allocation iff the ref count is 0.
*/
break;
}
/*
* allocate qp and add it the qp list; recheck to
* catch races
*/
/* check the list under lock */
break;
}
/* some one raced past us and added to the list */
} else {
/* add this to the qp list */
}
}
/* we now have a QP context */
for (;;) {
/* block till qp is in VALID state */
continue;
}
/* block till qp is in INVALID state */
continue;
}
IBMF_SUCCESS) {
/*
* Remove the QP context from the CI's list.
* Only initialized QPs should be on the list.
* We know that this QP is on the list, so
* the list is not empty.
*/
/* Only QP context on the list */
}
/* Find the QP context before the last one */
}
/*
* We are at the second last element of
* the list. Readjust the tail pointer.
* Remove the last element from the
* list.
*/
}
/* Free up the QP context */
break;
}
continue;
}
break;
}
}
if (status == IBMF_SUCCESS) {
return (IBMF_SUCCESS);
} else {
"ibmf_i_get_qp(): qp_not found");
return (status);
}
}
/*
* ibmf_i_release_qp():
* Drop the reference count on the QP structure
*/
void
{
}
/*
* ibmf_i_init_qp():
* Set up the QP context, request a QP from the IBT framework
* and initialize it
*/
static int
{
int i, status;
if (ibt_status != IBT_SUCCESS) {
"ibt_free_qp returned error",
}
}
else
/* call the IB transport to allocate a special QP */
if (ibt_status != IBT_SUCCESS) {
return (IBMF_TRANSPORT_FAILURE);
}
/* initialize qpp */
/* get the pkey index for the specified pkey */
IBMF_SUCCESS) {
if (ibt_status != IBT_SUCCESS) {
"ibt_free_qp returned error",
}
"pkey index\n");
return (IBMF_FAILURE);
}
/* call the IB transport to initialize the QP */
if (ibt_status != IBT_SUCCESS) {
if (ibt_status != IBT_SUCCESS) {
"ibt_free_qp returned error",
}
return (IBMF_TRANSPORT_FAILURE);
}
/* post receive wqes to the RQ to handle unsolicited inbound packets */
for (i = 0; i < ibmf_recv_wqes_per_port; i++) {
if (status != IBMF_SUCCESS) {
"ibmf_i_post_recv_buffer() failed");
}
}
/* set the state and signal blockers */
return (IBMF_SUCCESS);
}
/*
* ibmf_i_uninit_qp():
* Invalidate the QP context
*/
static void
{
/* mark the state as uniniting */
/* note: we ignore error values from ibt_flush_qp */
if (status != IBT_SUCCESS) {
}
/* mark state as INVALID and signal any blockers */
}
/*
* ibmf_i_alloc_msg():
* Allocate and set up a message context
*/
int
{
"ibmf_i_alloc_msg() enter, clientp = %p, msg = %p, "
/* allocate the message context */
km_flags);
}
} else {
"ibmf_i_alloc_msg(): %s\n",
return (IBMF_NO_RESOURCES);
}
return (IBMF_SUCCESS);
}
/*
* ibmf_i_free_msg():
* frees up all buffers allocated by IBMF for
* this message context, and then frees up the context
*/
void
{
/* free up the UD destination resource */
}
/* free up the receive buffer if allocated previously */
&cl_hdr_sz, &cl_hdr_off);
}
/* destroy the message mutex */
/* free the message context */
}
/*
* ibmf_i_msg_transport():
* Send a message posted by the IBMF client using the RMPP protocol
* if specified
*/
int
{
"qphdl = 0x%p, msgp = 0x%p, block = %d\n",
/*
* check if transp_op_flags specify that the transaction is
* a single packet, then the size of the message header + data
* does not exceed 256 bytes
*/
&cl_hdr_sz, &cl_hdr_off);
if ((sizeof (ib_mad_hdr_t) + cl_hdr_off +
"Non-RMPP message size is too large");
goto bail;
}
}
/* more message context initialization */
msgimplp->im_ref_count = 0;
"class = 0x%x, method = 0x%x, attributeID = 0x%x\n",
"TID = 0x%p, transp_op_flags = 0x%x\n",
/*
* Do not allow reuse of a message where the receive buffers are
* being used as send buffers if this is a sequenced transaction
*/
"Send and Recv buffers are the same for sequenced"
" transaction");
goto bail;
}
/* set transaction flags */
else
/* free recv buffers if this is a reused message */
"Freeing recv buffer for reused message",
&cl_hdr_sz, &cl_hdr_off);
msgbufp->im_bufs_cl_hdr_len = 0;
msgbufp->im_bufs_cl_data_len = 0;
}
/* initialize (and possibly allocate) the address handle */
if (status != IBMF_SUCCESS) {
goto bail;
}
/* add the message to the client context's message list */
/* no one should have touched our state */
/* transition out of uninit state */
"local_lid = 0x%x, remote_lid = 0x%x, remote_qpn = 0x%x, "
/* Non-RMPP transaction */
if (status != IBMF_SUCCESS) {
goto bail;
}
/* RMPP transaction */
/* check if client supports RMPP traffic */
goto bail;
}
/* for non-special QPs, check if QP supports RMPP traffic */
if (ibmf_qp_handle != IBMF_QP_HANDLE_DEFAULT &&
B_FALSE)) {
goto bail;
}
/* check if transaction is "double sided" (send and receive) */
isDS = 1;
if (status != IBMF_SUCCESS) {
goto bail;
}
}
/*
* decrement the reference count so notify_client() can remove the
* message when it's ready
*/
/* check if the transaction is a blocking transaction */
IBMF_TRANS_STATE_FLAG_SIGNALED) == 0)) {
/* indicate that the tranaction is waiting */
IBMF_TNF_TRACE, "",
"ibmf_i_msg_transport(): %s, msgp = 0x%p\n",
/* wait for transaction completion */
IBMF_TNF_TRACE, "",
"ibmf_i_msg_transport(): %s, msgp = 0x%p\n",
/* clean up flags */
"ibmf_i_msg_transport(): msg_status = %d\n",
}
"ibmf_i_msg_transport(): msg_status = %d\n",
}
}
msg_rp_unset_id = msg_tr_unset_id = 0;
/* Unset 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);
}
/* increment kstats of the number of sent messages */
bail:
if (error) {
"ibmf_i_msg_transport(): %s, msgp = 0x%p\n",
}
return (status);
}
/*
* ibmf_i_init_msg():
* Initialize the message fields
*/
void
{
sizeof (ibmf_retrans_t));
}
}
/*
* ibmf_i_alloc_qp():
* Allocate a QP context for the alternate QPs
*/
int
{
int i, blocking;
"ibmf_i_alloc_qp() enter, clientp = %p, pkey = %x, qkey = %x \n",
/*
* get the pkey index associated with this pkey if present in table
*/
goto bail;
}
/* allocate QP context memory */
goto bail;
}
/* setup the qp attrs for the alloc call */
/* request IBT for a qp with the desired attributes */
&qp_ctx->isq_qp_handle);
if (ibt_status != IBT_SUCCESS) {
goto bail;
}
/* Set up the client handle in the QP context */
/* call the IB transport to initialize the QP */
if (ibt_status != IBT_SUCCESS) {
goto bail;
}
/* Set up the WQE caches */
if (status != IBMF_SUCCESS) {
status);
goto bail;
}
/* add alt qp to the list in CI context */
} else {
}
}
if (flags & IBMF_ALLOC_SLEEP)
blocking = 1;
else
blocking = 0;
/* post the max number of buffers to RQ */
for (i = 0; i < ibmf_recv_wqes_per_port; i++) {
if (status != IBMF_SUCCESS) {
"ibmf_i_alloc_qp(): %s, status = %d\n",
}
}
bail:
if (error) {
}
return (status);
}
/*
* ibmf_i_free_qp():
* Free an alternate QP context
*/
/* ARGSUSED */
int
{
"ibmf_i_free_qp() enter, qp_hdl = %p, flags = %x\n",
/* remove qp from the list in CI context */
} else {
break;
}
}
/* flush the WQEs in the QP queues */
if (ibt_status != IBT_SUCCESS) {
"ibmf_i_free_qp(): %s, status = %d\n",
return (IBMF_TRANSPORT_FAILURE);
}
/* Call the MAD completion handler */
/* Wait here for all WQE owned by this QP to get freed */
while (qpp->isq_wqes_alloced != 0) {
}
/* call the IB transport to free the QP */
if (ibt_status != IBT_SUCCESS) {
"ibmf_i_free_qp(): %s, status = %d\n",
return (IBMF_TRANSPORT_FAILURE);
}
/* Clean up the WQE caches */
return (IBMF_SUCCESS);
}
/*
* ibmf_i_query_qp():
* Query an alternate QP context
*/
/* ARGSUSED */
int
{
"ibmf_i_free_qp() enter, qp_hdl = %p, flags = %x\n",
if (ibt_status != IBT_SUCCESS) {
"ibmf_i_query_qp(): %s, status = %d\n",
return (IBMF_TRANSPORT_FAILURE);
}
/* move the desired attributes into the locations provided */
/* get the pkey based on the pkey_ix */
if (ibt_status != IBT_SUCCESS) {
"ibmf_i_query_qp(): %s, pkey_ix = %d, status = %d\n",
return (IBMF_TRANSPORT_FAILURE);
}
"pkey = 0x%x, qkey = 0x%x, portnum = %d\n",
return (IBMF_SUCCESS);
}
/*
* ibmf_i_modify_qp():
* Modify an alternate QP context
*/
/* ARGSUSED */
int
{
"ibmf_i_modify_qp() enter, qp_hdl = %p, flags = %x, pkey = 0x%x, "
/*
* get the pkey index associated with this pkey if present in table
*/
"ibmf_i_modify_qp(): %s, pkey = %x\n",
return (IBMF_FAILURE);
}
/* Find the QP context in the CI QP context list */
break;
}
}
"ibmf_i_modify_qp(): %s\n",
return (IBMF_BAD_QP_HANDLE);
} else {
}
/*
* Transition the QP to SQD state
*/
if (ibt_status != IBT_SUCCESS) {
"ibmf_i_modify_qp(): %s, qp_hdl = %p\n",
return (IBMF_TRANSPORT_FAILURE);
}
/*
* Wait for an event indicating that the QP is in SQD state
*/
/* Setup QP modification information for transition to RTS state */
/*
* transition the QP back to RTS state to allow
* modification of the pkey and qkey
*/
if (ibt_status != IBT_SUCCESS) {
"ibmf_i_modify_qp(): %s, qp_hdl = %p, status = %d\n",
return (IBMF_TRANSPORT_FAILURE);
}
return (IBMF_SUCCESS);
}
/*
* ibmf_i_post_recv_buffer():
* Post a WQE to the RQ of the specified QP
*/
int
{
int ret;
"ibmf_i_post_recv_buffer() enter, cip = %p, qpp = %p, "
/*
* if we haven't hit the max wqes per qp, attempt to allocate a recv
* wqe and post it to the recv queue.
* It is possible for more than one thread to get through this
* check below and post wqes that could push us above the
* ibmf_recv_wqes_posted_per_qp. We catch that case when the recv
* completion is signaled.
*/
/* Get the WQE kmem cache pointer based on the QP type */
if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT)
else {
}
/* allocate a receive WQE from the receive WQE kmem cache */
/*
* Attempt to extend the cache and then retry the
* kmem_cache_alloc()
*/
"ibmf_i_post_recv_buffer(): %s, status = %d\n",
"ibmf_i_post_recv_buffer() exit\n");
return (IBMF_NO_RESOURCES);
} else {
/* Allocation failed again. Give up here. */
1);
IBMF_TNF_ERROR, "",
"ibmf_i_post_recv_buffer(): %s, "
"status = %d\n",
IBMF_TNF_TRACE, "",
"ibmf_i_post_recv_buffer() exit\n");
return (IBMF_NO_RESOURCES);
}
}
}
/*
* if the qp handle provided in ibmf_send_pkt() or
* ibmf_setup_recv_cb() is not the default qp handle
* for this client, then the wqe must be queued on this qp,
* else use the default qp handle set up during ibmf_register()
*/
if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
} else {
}
/* allocate memory for the scatter-gather list */
"ibmf_i_post_recv_buffer(): %s\n",
"ibmf_i_post_recv_buffer() exit\n");
return (IBMF_NO_RESOURCES);
}
/* initialize it */
/* and post it */
1, NULL);
if (ret != IBMF_SUCCESS) {
sizeof (ibt_wr_ds_t));
"ibmf_i_post_recv_buffer(): %s, status = %d\n",
"ibmf_i_post_recv_buffer() exit\n");
return (ret);
}
if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
qpp->iq_rwqes_posted++;
cip->ci_wqes_alloced++;
} else {
}
return (ret);
}
/*
* ibmf_i_mgt_class_to_hdr_sz_off():
* Determine class header offser and size for management classes
*/
void
{
"ibmf_i_mgt_class_to_hdr_sz_off(): mgt_class = 0x%x\n",
switch (mgt_class) {
case MAD_MGMT_CLASS_PERF :
case MAD_MGMT_CLASS_BM :
case MAD_MGMT_CLASS_DEV_MGT :
case MAD_MGMT_CLASS_SNMP :
case MAD_MGMT_CLASS_COMM_MGT:
break;
case MAD_MGMT_CLASS_SUBN_ADM :
break;
default:
if (((mgt_class >= MAD_MGMT_CLASS_VENDOR_START) &&
(mgt_class <= MAD_MGMT_CLASS_VENDOR_END)) ||
(mgt_class <= MAD_MGMT_CLASS_APPLICATION_END))) {
} else if ((mgt_class >= MAD_MGMT_CLASS_VENDOR2_START) &&
(mgt_class <= MAD_MGMT_CLASS_VENDOR2_END)) {
} else {
IBMF_TNF_TRACE, "",
"ibmf_i_mgt_class_to_hdr_sz_off():"
"got illegal management class = 0x%x\n",
}
break;
}
"ibmf_i_mgt_class_to_hdr_sz_off() exit,hdr_sz = %d, hdr_off = %d\n",
}
/*
* ibmf_i_lookup_client_by_mgmt_class():
* Lookup the client context based on the management class of
* the incoming packet
*/
int
{
"ibmf_i_lookup_client_by_mgmt_class() enter, cip = %p, "
/* found our match */
break;
}
}
"ibmf_i_lookup_client_by_mgmt_class() exit, clp = %p\n",
return (IBMF_SUCCESS);
} else {
"ibmf_i_lookup_client_by_mgmt_class() failure exit\n");
return (IBMF_FAILURE);
}
}
/*
* ibmf_i_get_pkeyix():
* Get the pkey index of the pkey in the pkey table of the specified
* port. Take into account the partition membership.
*/
int
{
/*
* If the client specifies the FULL membership pkey and the
* pkey is not in the table, this function should fail.
*/
if (pkey & IBMF_PKEY_MEMBERSHIP_MASK) {
if (ibt_status != IBT_SUCCESS) {
"ibmf_i_get_pkeyix() error status = %d\n",
"ibmf_i_get_pkeyix() exit\n");
return (IBMF_TRANSPORT_FAILURE);
}
return (IBMF_SUCCESS);
}
/*
* Limited member pkey processing
* Check if this limited member pkey is in the pkey table
*/
if (ibt_status == IBT_SUCCESS) {
"ibmf_i_get_pkeyix() exit\n");
return (IBMF_SUCCESS);
}
/*
* Could not find the limited member version of the pkey.
* Now check if the full member version of the pkey is in the
* pkey table. If not, fail the call.
*/
if (ibt_status != IBT_SUCCESS) {
"ibmf_i_get_pkeyix() error status = %d\n",
"ibmf_i_get_pkeyix() exit\n");
return (IBMF_TRANSPORT_FAILURE);
}
return (IBMF_SUCCESS);
}
/*
* ibmf_i_pkey_ix_to_key():
* Figure out pkey from pkey index
*/
int
{
pkeyp);
if (ibt_status != IBT_SUCCESS) {
"ibmf_i_pkey_ix_to_key(): ibt_index2pkey failed for "
return (IBMF_TRANSPORT_FAILURE);
}
return (IBMF_SUCCESS);
}
/*
* ibmf_i_ibt_to_ibmf_status():
* Map IBT return code to IBMF return code
*/
int
{
int ibmf_status;
switch (ibt_status) {
case IBT_SUCCESS:
break;
case IBT_INSUFF_RESOURCE:
case IBT_QP_FULL:
break;
case IBT_HCA_IN_USE:
case IBT_QP_IN_USE:
case IBT_CQ_BUSY:
case IBT_PD_IN_USE:
case IBT_MR_IN_USE:
break;
default:
break;
}
return (ibmf_status);
}
/*
* ibmf_i_ibt_wc_to_ibmf_status():
* Map work completion code to IBMF return code
*/
int
{
int ibmf_status;
"ibmf_i_ibt_to_ibmf_status() enter, status = %d\n",
switch (ibt_wc_status) {
case IBT_WC_SUCCESS:
break;
default:
break;
}
"ibmf_i_ibt_to_ibmf_status() exit, wc_status = %d, "
return (ibmf_status);
}
/*
* ibmf_i_is_ibmf_handle_valid():
* Validate the ibmf handle
*/
int
{
"ibmf_i_is_ibmf_handle_valid() enter\n");
/* iterate through all the channel interace contexts */
/* search all registration contexts for this ci */
break;
}
/* ci found */
break;
} else {
/* ci not found, move onto next ci */
}
}
"ibmf_i_is_ibmf_handle_valid() exit\n");
return (IBMF_SUCCESS);
} else {
"ibmf_i_is_ibmf_handle_valid() failure exit\n");
return (IBMF_FAILURE);
}
}
/*
* ibmf_i_is_qp_handle_valid():
* Validate the QP handle
*/
int
{
"ibmf_i_is_qp_handle_valid() enter\n");
/* the default qp handle is always valid */
if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT)
return (IBMF_SUCCESS);
/* qp handle found */
break;
} else {
/* qp handle not found, get next qp on list */
}
}
"ibmf_i_is_qp_handle_valid() exit\n");
return (IBMF_SUCCESS);
} else {
"ibmf_i_is_qp_handle_valid() failure exit\n");
return (IBMF_FAILURE);
}
}
void
{
if ((l) > ibmf_trace_level) {
return;
}
}
/*
* ibmf_setup_term_ctx():
* Sets up a message context that is the duplicate of the one
* passed in the regmsgimplp argument. The duplicate message context
* is not visible to the client. It is managed internally by ibmf
* to process the RMPP receiver termination flow logic for the
* transaction while the client is notified of the completion of the
* same transaction (i.e. all the solicited data has been received).
*/
int
{
int status;
"ibmf_setup_term_ctx() enter\n");
/*
* Allocate the termination message context
*/
"message mem allocation failure");
"ibmf_setup_term_ctx() exit\n");
return (IBMF_NO_RESOURCES);
}
/* Copy the message context to the termination message structure */
*msgimplp = *regmsgimplp;
/* Initialize the message mutex */
/*
* Allocate enough memory for the MAD header only.
*/
"recv buf mem allocation failure");
"ibmf_setup_term_ctx() exit\n");
return (IBMF_NO_RESOURCES);
}
/* Copy over just the MAD header contents */
sizeof (ib_mad_hdr_t));
offset = sizeof (ib_mad_hdr_t);
&cl_hdr_sz, &cl_hdr_off);
offset += cl_hdr_off;
/*
* Copy the management class header
*/
/*
* Clear the termination message timers copied from the regular message
* since ibmf_i_set_timer() expects them to be cleared.
*/
msgimplp->im_rp_timeout_id = 0;
msgimplp->im_tr_timeout_id = 0;
/* Mark this message as being in a receiver RMPP mode */
/* Mark this message as being a "termination flow" message */
/*
* Clear the IBMF_MSG_FLAGS_SET_TERMINATION copied over from the regular
* message.
*/
/*
* Clear the trans_state RECV_DONE and DONE flags so that the
* protocol continues with the termination message context.
*/
/* Clear out references to the old UD dest handles */
/*
* Request new UD dest resources for the termination phase.
* The old UD dest resources are freed when the IBMF client
* calls ibmf_free_msg(), so they cannot be relied on to exist
* when the RMPP termination loop completes.
*/
B_FALSE);
if (status != IBMF_SUCCESS) {
"ibmf_setup_term_ctx(): %s, status = %d\n",
"ibmf_setup_term_ctx() exit\n");
return (status);
}
/*
* Add the message to the termination client list by virtue of
* having the IBMF_MSG_FLAGS_TERMINATION "im_flags" flag set.
*/
/*
* Increase the "allocted messages" count so that the client
* does not unregister before this message has been freed.
* This is necessary because we want the client context to
* be around when the receive timeout expires for this termination
* loop, otherwise the code will access freed memory and crash.
*/
/* Set the response timer for the termination message. */
return (IBMF_SUCCESS);
}