ibcm_ti.c revision 9d3d2ed09c8e9ba0b2ba44fdd1dd300b2c3f9e8e
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* These routines implement the Communication Manager's interfaces to IBTL.
*/
/* CM rc recycle task args structure definition */
typedef struct ibcm_taskq_recycle_arg_s {
void *arg;
static void ibcm_process_abort_via_taskq(void *args);
static void ibcm_process_async_join_mcg(void *tq_arg);
/* Address Record management definitions */
#define IBCM_DAPL_ATS_NAME "DAPL Address Translation Service"
#define IBCM_DAPL_ATS_SID 0x10000CE100415453ULL
#define IBCM_DAPL_ATS_NBYTES 16
#ifdef DEBUG
#endif
/*
* Typically, clients initialize these args in one api call, and use in
* another api
*/
/*
* ibt_open_rc_channel()
* ibt_open_rc_channel opens a communication channel on the specified
* channel to the specified service. For connection service type qp's
* the CM initiates the CEP to establish the connection and transitions
* attributes as necessary.
* The implementation of this function assumes that alt path is different
* from primary path. It is assumed that the Path functions ensure that.
*
* RETURN VALUES:
* IBT_SUCCESS on success (or respective failure on error)
*/
{
/* all fields that are related to REQ MAD formation */
ib_qkey_t local_qkey = 0;
ib_eecn_t local_eecn = 0;
ib_eecn_t remote_eecn = 0;
uint32_t starting_psn = 0;
/* CM path related fields */
/* Other misc local args */
if (IBCM_INVALID_CHANNEL(channel)) {
return (IBT_CHAN_HDL_INVALID);
}
/* cm handler should always be specified */
"CM handler is not be specified", channel);
return (IBT_INVALID_PARAM);
}
if (mode == IBT_NONBLOCKING) {
" ret_args should be NULL when called in "
"non-blocking mode", channel);
return (IBT_INVALID_PARAM);
}
} else if (mode == IBT_BLOCKING) {
" ret_args should be Non-NULL when called in "
"blocking mode", channel);
return (IBT_INVALID_PARAM);
}
" private data length is too large", channel);
return (IBT_INVALID_PARAM);
}
if ((ret_args->rc_priv_data_len > 0) &&
" rc_priv_data_len > 0, but rc_priv_data NULL",
channel);
return (IBT_INVALID_PARAM);
}
} else { /* any other mode is not valid for ibt_open_rc_channel */
return (IBT_INVALID_PARAM);
}
/*
* XXX: no support yet for ibt_chan_open_flags_t - IBT_OCHAN_DUP
*/
if (flags & IBT_OCHAN_DUP) {
return (IBT_INVALID_PARAM);
}
if ((flags & IBT_OCHAN_REDIRECTED) &&
(flags & IBT_OCHAN_PORT_REDIRECTED)) {
"Illegal to specify IBT_OCHAN_REDIRECTED and "
"IBT_OCHAN_PORT_REDIRECTED flags together", channel);
return (IBT_INVALID_PARAM);
}
if (((flags & IBT_OCHAN_REDIRECTED) &&
((flags & IBT_OCHAN_PORT_REDIRECTED) &&
"Redirect flag specified, but respective arg is NULL",
channel);
return (IBT_INVALID_PARAM);
}
if ((flags & IBT_OCHAN_REDIRECTED) &&
"Either rdi_dlid or rdi_gid must be specified for"
" IBT_OCHAN_REDIRECTED", channel);
return (IBT_INVALID_PARAM);
}
/* primary dlid and hca_port_num should never be zero */
"Primary Path's information is not valid", channel);
return (IBT_INVALID_PARAM);
}
/* validate SID */
"ERROR: Service ID in path information is 0", channel);
return (IBT_INVALID_PARAM);
}
/* validate rnr_retry_cnt (enum has more than 3 bits) */
"ERROR: oc_path_rnr_retry_cnt(%d) is out of range",
return (IBT_INVALID_PARAM);
}
/*
* Ensure that client is not re-using a QP that is still associated
* with a statep
*/
"Channel being re-used on active side", channel);
return (IBT_CHAN_IN_USE);
}
/* Get GUID from Channel */
/* validate QP's hca guid with that from primary path */
"GUID from Channel and primary path don't match", channel);
"Channel GUID %llX primary path GUID %llX", channel,
return (IBT_CHAN_HDL_INVALID);
}
if (status != IBT_SUCCESS) {
return (status);
}
/* If client specified "no port change on QP" */
"chan port %d and path port %d does not match", channel,
return (IBT_INVALID_PARAM);
}
"Invalid Channel type: Applicable only to RC Channel",
channel);
return (IBT_CHAN_SRV_TYPE_INVALID);
}
/* Check if QP is in INIT state or not */
"QP is not in INIT state %x", channel,
return (IBT_CHAN_STATE_INVALID);
}
#ifdef NO_EEC_SUPPORT_YET
if (flags & IBT_OCHAN_RDC_EXISTS) {
if (status != IBT_SUCCESS) {
return (status);
}
}
#endif
/* If no HCA found return failure */
"hcap is NULL. Probably hca is not in active state",
channel);
return (IBT_CHAN_HDL_INVALID);
}
return (IBT_INVALID_PARAM);
}
"Huge Primary Pkt lt %d", channel,
return (IBT_PATH_PKT_LT_TOO_HIGH);
}
if (status != IBT_SUCCESS) {
return (status);
}
/* Validate P_KEY Index */
if (status != IBT_SUCCESS) {
"Invalid Primary PKeyIx %x", channel,
return (status);
}
!= IBT_SUCCESS)) {
"ibmf reg or callback setup failed during re-initialize",
channel);
return (status);
}
/* check first if alternate path exists or not as it is OPTIONAL */
"Huge Alt Pkt lt %d", channel,
return (IBT_PATH_PKT_LT_TOO_HIGH);
}
if (port_no != alt_port_no) {
if (status != IBT_SUCCESS) {
"chan 0x%p alt_port_num %d inactive %d",
return (status);
}
}
}
/*
* only pkey needs to be zero'ed, because all other fields are set in
* in ibcm_init_reply_addr. But, let's bzero the complete struct for
* any future modifications.
*/
/* Initialize the MAD destination address in stored_reply_addr */
return (status);
}
/* Initialize the pkey for CM MAD communication */
#ifdef DEBUG
#endif
/* Retrieve an ibmf qp for sending CM MADs */
"unable to allocate ibmf qp for CM MADs", channel);
return (IBT_INSUFF_RESOURCE);
}
" Unable to allocate comid", channel);
return (IBT_INSUFF_KERNEL_RESOURCE);
}
/* allocate an IBMF mad buffer */
MAD_METHOD_SEND)) != IBT_SUCCESS) {
"chan 0x%p ibcm_alloc_out_msg failed", channel);
return (status);
}
/* Init to Init, if QP's port does not match with path information */
"chan 0x%p chan port %d", channel,
/* For now, set it to RC type */
if (status != IBT_SUCCESS) {
return (status);
} else
}
/* allocate ibcm_state_data_t before grabbing the WRITER lock */
/* CM should be seeing this for the first time */
/* Increment the hca's resource count */
/* Once a resource created on hca, no need to hold the acc cnt */
/* Save "statep" as channel's CM private data. */
/* Start filling in the REQ MAD */
/* Bytes 32-35 are req_local_qpn and req_off_resp_resources */
/* Bytes 36-39 are req_local_eec_no and req_off_initiator_depth */
if (flags & IBT_OCHAN_REMOTE_CM_TM)
else
/*
* Bytes 40-43 - remote_eecn, remote_cm_resp_time, tran_type,
* IBT_CM_FLOW_CONTROL is always set by default.
*/
if (flags & IBT_OCHAN_LOCAL_CM_TM)
else
/* save retry count */
if (flags & IBT_OCHAN_STARTING_PSN)
if (local_cm_resp_time > 0x1f)
local_cm_resp_time = 0x1f;
/* Bytes 44-47 are req_starting_psn, local_cm_resp_time and retry_cnt */
"Prim Pkt lt (IB time) 0x%x", channel,
/* Pkey - bytes 48-49 */
if (flags & IBT_OCHAN_CM_RETRY)
else
/*
* Check whether SRQ is associated with this Channel, if yes, then
* set the SRQ Exists bit in the REQ.
*/
}
#ifdef NO_EEC_SUPPORT_YET
if (flags & IBT_OCHAN_RDC_EXISTS)
#endif
/* Initialize the "primary" port stuff next - bytes 52-95 */
/* Bytes 88-91 - primary_flowlbl, and primary_srate */
"active hca_ack_delay (usec) %d", channel,
"Sent primary cep timeout (IB Time) %d", channel,
"prim GID %llX:%llX", channel,
/* Initialize the "alternate" port stuff - optional */
/*
* doing all this as req_alt_r/l_port_gid is at offset
* 100, 116 which is not divisible by 8
*/
sizeof (ib_gid_t));
sizeof (ib_gid_t));
/* Bytes 132-135 - alternate_flow_label, and alternate srate */
(((alternate_grh == B_TRUE) ?
"alt_dlid %x ", channel,
"alt GID %llX:%llX", channel,
}
/* return_data is filled up in the state machine code */
}
/* initialize some statep fields here */
/* Initialize statep->stored_reply_addr */
/* Initialize stored reply addr fields */
/*
* hence available in the args of ibt_open_rc_channel
*/
/* Store the source path bits for primary and alt paths */
0));
if (mode == IBT_BLOCKING) {
}
/*
* In the case that open_channel() fails because of a
* REJ or timeout, change retval to IBT_CM_FAILURE
*/
}
/* decrement the ref-count before leaving here */
return (status);
}
/*
* ibcm_init_reply_addr:
*
* The brief description of functionality below.
*
* For IBT_OCHAN_PORT_REDIRECTED (ie., port redirected case):
* Build CM path from chan_args->oc_cm_cep_path
* Set CM pkt lt (ie.,life time) to chan_args->oc_cm_pkt_lt
*
* For IBT_OCHAN_REDIRECTED (ie., port and CM redirected case):
* If Redirect LID is specified,
* If Redirect GID is not specified or specified to be on the same
* subnet, then
* Build CM path from chan_args->oc_cm_redirect_info
* Set CM pkt lt to subnet timeout
* Else (ie., GID specified, but on a different subnet)
* Do a path lookup to build CM Path and set CM pkt lt
*
*/
static ibt_status_t
{
/*
* In the future, these values can be set based on framework policy
* decisions ensuring reachability.
*/
if (flags & IBT_OCHAN_PORT_REDIRECTED) {
"IBT_OCHAN_PORT_REDIRECTED specified");
if (status != IBT_SUCCESS) {
"CM PKeyIx %x port_num %x",
return (status);
}
} else if (flags & IBT_OCHAN_REDIRECTED) {
"IBT_OCHAN_REDIRECTED specified");
"ERROR: Re-direct GID value NOT Provided.");
return (IBT_INVALID_PARAM);
}
/* As per spec definition 1.1, it's always IB_GSI_QKEY */
/*
* if LID is non-zero in classportinfo then use classportinfo
* fields to form CM MAD destination address.
*/
if (redirect_info->rdi_dlid != 0) {
"Query Ports Failed: %d", status);
return (status);
} else if (port_infop->p_subnet_timeout >
"large subnet timeout %x port_no %x",
return (IBT_PATH_PKT_LT_TOO_HIGH);
} else {
"subnet timeout %x port_no %x",
*cm_pkt_lt =
}
/* Classportinfo doesn't have hoplimit field */
return (IBT_SUCCESS);
} else {
/*
* If GID is specified, and LID is zero in classportinfo
* do a path lookup using specified GID, Pkey,
* in classportinfo
*/
/*
* use reply_addr below, as sender_gid in reply_addr
* may have been set above based on some policy decision
* for originating end point for CM MADs above
*/
return (status);
/* Initialize cm_adds */
}
} else { /* cm_pkey initialized in ibt_open_rc_channel */
}
return (IBT_SUCCESS);
}
/*
* ibt_prime_close_rc_channel()
* It allocates resources required for close channel operation, so
* ibt_close_rc_channel can be called from interrupt routine.
*
* INPUTS:
* channel The address of an ibt_channel_t struct that
* specifies the channel to open.
*
* RETURN VALUES:
* IBT_SUCCESS on success(or respective failure on error)
*
* Clients are typically expected to call this function in established state
*/
{
/* validate channel, first */
if (IBCM_INVALID_CHANNEL(channel)) {
"invalid channel", channel);
return (IBT_CHAN_HDL_INVALID);
}
"Invalid Channel type: Applicable only to RC Channel",
channel);
return (IBT_CHAN_SRV_TYPE_INVALID);
}
/* get the statep */
/*
* This can happen, if the statep is already gone by a DREQ from
* the remote side
*/
"statep NULL", channel);
return (IBT_SUCCESS);
}
return (IBT_CHAN_STATE_INVALID);
}
/* clients could pre-allocate dreq mad, even before connection est */
if (status != IBT_SUCCESS) {
"ibcm_alloc_out_msg failed ", channel);
return (status);
}
/* If this message isn't seen then ibt_prime_close_rc_channel failed */
channel);
return (IBT_SUCCESS);
}
/*
* ibt_close_rc_channel()
* It closes an established channel.
*
* RETURN VALUES:
* IBT_SUCCESS on success(or respective failure on error)
*/
{
/* validate channel, first */
if (IBCM_INVALID_CHANNEL(channel)) {
"invalid channel", channel);
return (IBT_CHAN_HDL_INVALID);
}
"Invalid Channel type: Applicable only to RC Channel",
channel);
return (IBT_CHAN_SRV_TYPE_INVALID);
}
if (mode == IBT_BLOCKING) {
/* valid only for BLOCKING MODE */
if ((ret_priv_data_len_p != NULL) &&
" private data len %d is too large", channel,
return (IBT_INVALID_PARAM);
}
return (IBT_INVALID_PARAM);
}
/* get the statep */
"statep NULL", channel);
if (ibtl_cm_is_chan_closing(channel) ||
if (ret_status)
/* No private data to return to the client */
if (ret_priv_data_len_p != NULL)
*ret_priv_data_len_p = 0;
return (IBT_SUCCESS);
}
return (IBT_CHAN_STATE_INVALID);
}
/* HCA must have been in active state. If not, it's a client bug */
if (!IBCM_ACCESS_HCA_OK(hcap)) {
return (IBT_CHAN_HDL_INVALID);
}
}
/* Do TRANSIENT_DREQ check after TRANSIENT_ESTABLISHED check */
/* If state is in pre-established states, abort the connection est */
/* No DREP private data possible */
if (ret_priv_data_len_p != NULL)
*ret_priv_data_len_p = 0;
/*
* If waiting for a response mad, then cancel the timer,
* and delete the connection
*/
"chan 0x%p connection aborted in state %x", channel,
if (mode == IBT_NONBLOCKING) {
if (taskq_dispatch(ibcm_taskq,
TQ_NOSLEEP) == 0) {
return (IBT_INSUFF_KERNEL_RESOURCE);
} /* if taskq_dispatch succeeds */
/* Cancel the timer */
} else {
/* Cancel the timer */
(void) taskq_dispatch(ibcm_taskq,
TQ_SLEEP);
}
/* cancel the currently running timer */
if (timer_val != 0)
/* wait until cm handler returns for BLOCKING cases */
if ((mode == IBT_BLOCKING) ||
(mode == IBT_NOCALLBACKS)) {
&statep->state_mutex);
}
if (ret_status)
/*
* It would ideal to post a REJ MAD, but that would
* be non-conformance to spec. Hence, delete the state
* data. Assuming that happens quickly, any retransmits
* from the remote are replied by CM with reject
* reason " no valid com id". That would stop remote
* sending any more MADs.
*/
return (IBT_SUCCESS);
/* if CM busy in cm handler, wait until cm handler returns */
/* take control of statep */
"chan 0x%p connection aborted in state = %x",
/*
* wait until state machine modifies qp state to error,
* including disassociating statep and QP
*/
&statep->state_mutex);
/* a sanity setting */
if (mode == IBT_NOCALLBACKS)
/*
* In rare situations, connection attempt could be
* terminated for some other reason, before abort is
* processed, but CM still returns ret_status as abort
*/
if (ret_status)
/*
* REJ MAD is posted by the CM state machine for this
* case, hence state structure is deleted in the
* state machine processing.
*/
return (IBT_SUCCESS);
/* State already in timewait, so no return priv data */
/* The teardown has already been done */
if (ret_status)
return (IBT_SUCCESS);
/*
* Either the remote or local client has already
* initiated the teardown. IBCM_STATE_DREP_RCVD is
* possible, if CM initiated teardown without client's
* knowledge, for stale handling, etc.,
*/
if (mode == IBT_NOCALLBACKS) {
/* enable free qp after return */
} else while (statep->close_nocb_state ==
&statep->state_mutex);
if (ret_status)
} else if (mode == IBT_BLOCKING) {
/* wait until state is moved to timewait */
&statep->state_mutex);
}
/* ret_status is set in state machine code */
return (IBT_SUCCESS);
if ((mode == IBT_BLOCKING) ||
(mode == IBT_NOCALLBACKS)) {
/*
* wait until cm handler invocation and
* disassociation between statep and channel
* is complete
*/
&statep->state_mutex);
}
if (ret_status)
return (IBT_SUCCESS);
} else {
return (IBT_CM_FAILURE);
}
}
if (mode == IBT_NOCALLBACKS) {
"NOCALLBACKS on in statep = %p", statep);
}
goto lost_race;
}
/*
* release state mutex
*/
goto lost_race;
}
if ((status = ibcm_alloc_out_msg(
MAD_METHOD_SEND)) != IBT_SUCCESS) {
"chan 0x%p ibcm_alloc_out_msg failed ", channel);
statep->close_flow = 0;
return (status);
}
} else
"DREQ MAD already allocated in statep %p", statep);
} else {
}
if (mode == IBT_BLOCKING) {
/* wait for DREP */
&statep->state_mutex);
"done blocking", channel);
}
/* If this message isn't seen then ibt_close_rc_channel failed */
channel);
return (IBT_SUCCESS);
}
{
if (IBCM_INVALID_CHANNEL(rc_chan)) {
return (IBT_CHAN_HDL_INVALID);
}
/* check qp state */
if (retval != IBT_SUCCESS)
return (retval);
return (IBT_CHAN_SRV_TYPE_INVALID);
return (IBT_CHAN_STATE_INVALID);
KM_SLEEP);
/*
* If non-blocking ie., func specified and channel has not yet completed
* the timewait, then schedule the work for later
*/
return (IBT_SUCCESS);
}
/*
* if blocking ie., func specified, and channel has not yet completed
* the timewait, then block until the channel completes the timewait
*/
if (func) { /* NON BLOCKING case. Taskq for QP state change */
return (IBT_SUCCESS);
} else /* BLOCKING case */
return (ibcm_process_rc_recycle_ret(ibcm_tq_recycle_arg));
}
void
{
(void) ibcm_process_rc_recycle_ret(recycle_arg);
}
static ibt_status_t
{
/* QP must have been in error state */
if (ibt_status != IBT_SUCCESS)
"chanp %p ibt_query_qp() = %d",
else {
/* perform the QP state change from ERROR to RESET */
/* Call modify_qp to move to RESET state */
if (ibt_status != IBT_SUCCESS)
"chanp %p ibt_modify_qp() = %d for ERROR to RESET",
}
if (ibt_status == IBT_SUCCESS) {
/* set flags for all mandatory args from RESET to INIT */
/* Always use the existing pkey */
/* Call modify_qp to move to INIT state */
if (ibt_status != IBT_SUCCESS)
"chanp %p ibt_modify_qp() = %d for RESET to INIT",
}
/* Change the QP CM state to indicate QP being re-used */
if (ibt_status == IBT_SUCCESS)
/* Call func, if defined */
if (ibcm_tq_recycle_arg->func)
return (ibt_status);
}
static void
ibcm_process_abort_via_taskq(void *args)
{
}
/*
* Local UD CM Handler's private data, used during ibt_request_ud_dest() in
* Non-Blocking mode operations.
*/
typedef struct ibcm_local_handler_s {
void *actual_cm_private;
/*
* Local UD CM Handler, used when ibt_alloc_ud_dest() is issued in
* NON-Blocking mode.
*
* Out here, we update the UD Destination handle with
* the obtained DQPN and QKey (from SIDR REP) and invokes actual client
* handler that was specified by the client.
*/
static ibt_cm_status_t
{
case IBT_CM_UD_EVENT_SIDR_REP:
/* Update QPN & QKey from event into destination handle. */
}
/* Invoke the client handler - inform only, so ignore retval */
(void) handler_priv->actual_cm_handler(
len);
/* Free memory allocated for local handler's private data. */
if (handler_priv != NULL)
break;
default:
break;
}
return (IBT_CM_ACCEPT);
}
/* Validate the input UD destination attributes. */
static ibt_status_t
{
/* cm handler must always be specified */
"CM handler is not specified ");
return (IBT_INVALID_PARAM);
}
if (mode == IBT_NONBLOCKING) {
"ret_args should be NULL when called in "
"non-blocking mode");
return (IBT_INVALID_PARAM);
}
} else if (mode == IBT_BLOCKING) {
"ret_args should be Non-NULL when called in "
"blocking mode");
return (IBT_INVALID_PARAM);
}
} else {
"invalid mode %x specified ", mode);
return (IBT_INVALID_PARAM);
}
"ServiceID must be specified. ");
return (IBT_INVALID_PARAM);
}
"Address Info NULL");
return (IBT_INVALID_PARAM);
}
/* Validate SGID */
return (IBT_INVALID_PARAM);
}
/* Validate DGID */
return (IBT_INVALID_PARAM);
}
return (IBT_SUCCESS);
}
/* Perform SIDR to retrieve DQPN and QKey. */
static ibt_status_t
{
/* Retrieve HCA GUID value from the available SGID info. */
"ibtl_cm_get_hca_port failed: %d", retval);
return (retval);
}
/* Lookup the HCA info for this GUID */
return (IBT_HCA_INVALID);
}
/* Return failure if the HCA device or Port is not operational */
/* Device Port is not in good state, don't use it. */
"port specified or port not active");
return (retval);
}
if (retval != IBT_SUCCESS) {
"Failed to convert index2pkey: %d", retval);
return (retval);
}
/* Allocate a new request id */
"no req id available");
return (IBT_INSUFF_KERNEL_RESOURCE);
}
!= IBT_SUCCESS)) {
"ibmf reg or callback setup failed during re-initialize");
return (retval);
}
/* find the ibmf QP to post the SIDR REQ */
NULL) {
" failed");
return (IBT_INSUFF_RESOURCE);
}
!= IBT_SUCCESS) {
" failed");
return (retval);
}
/* do various allocations needed here */
/* Increment hca's resource count */
/* After a resource created on hca, no need to hold the acc cnt */
/* Initialize some ud_statep fields */
/* set remaining retry cnt */
/*
* Get UD handler and corresponding args which is pass it back
* as first argument for the handler.
*/
if (mode == IBT_BLOCKING)
else
/* Initialize the fields of ud_statep->ud_stored_reply_addr */
/* needs to be derived based on the base LID and path bits */
/*
* This may be enchanced later, to use a remote qno based on past
* redirect rej mad responses. This would be the place to specify
* appropriate remote qno
*/
/* Initialize the SIDR REQ message fields */
}
/* Send out the SIDR REQ message */
/* Wait for SIDR_REP */
if (mode == IBT_BLOCKING) {
}
} else {
}
}
return (retval);
}
/*
* Function:
* ibt_request_ud_dest
* Input:
* ud_dest A previously allocated UD destination handle.
* mode This function can execute in blocking or non blocking
* modes.
* attr UD destination attributes to be modified.
* Output:
* ud_ret_args If the function is called in blocking mode, ud_ret_args
* should be a pointer to an ibt_ud_returns_t struct.
* Returns:
* IBT_SUCCESS
* Description:
* Modify a previously allocated UD destination handle based on the
* results of doing the SIDR protocol.
*/
{
if (retval != IBT_SUCCESS) {
return (retval);
}
/* Allocate an Address handle. */
if (retval != IBT_SUCCESS) {
"Address Handle Modification failed: %d", retval);
return (retval);
}
if (mode == IBT_NONBLOCKING) {
/*
* In NON-BLOCKING mode, and we need to update the destination
* handle with the DQPN and QKey that are obtained from
* SIDR REP, hook-up our own handler, so that we can catch
* the event, and we ourselves call the actual client's
* ud_cm_handler, in our handler.
*/
/* Allocate memory for local handler's private data. */
}
/* In order to get DQPN and Destination QKey, perform SIDR */
if (retval != IBT_SUCCESS) {
"Failed to get DQPN: %d", retval);
/* Free memory allocated for local handler's private data. */
if (local_handler_priv != NULL)
sizeof (*local_handler_priv));
return (retval);
}
/*
* Fill in the dqpn and dqkey as obtained from ud_ret_args,
* values will be valid only on BLOCKING mode.
*/
if (mode == IBT_BLOCKING) {
}
return (retval);
}
/*
* Function:
* ibt_ud_get_dqpn
* Input:
* attr A pointer to an ibt_ud_dest_attr_t struct that are
* required for SIDR REQ message. Not specified attributes
* should be set to "NULL" or "0".
* ud_sid, ud_addr and ud_pkt_lt must be specified.
* mode This function can execute in blocking or non blocking
* modes.
* Output:
* returns If the function is called in blocking mode, returns
* should be a pointer to an ibt_ud_returns_t struct.
* Return:
* IBT_SUCCESS on success or respective failure on error.
* Description:
* Finds the destination QPN at the specified destination that the
* specified service can be reached on. The IBTF CM initiates the
* service ID resolution protocol (SIDR) to determine a destination QPN.
*
* NOTE: SIDR_REQ is initiated from active side.
*/
{
if (retval != IBT_SUCCESS) {
return (retval);
}
}
/*
* ibt_cm_delay:
* A client CM handler function can call this function
* to extend its response time to a CM event.
* INPUTS:
* flags Indicates what CM message processing is being delayed
* by the CM handler, valid values are:
* IBT_CM_DELAY_REQ
* IBT_CM_DELAY_REP
* IBT_CM_DELAY_LAP
* cm_session_id The session ID that was passed to client srv_handler
* by the CM
* service_time The extended service time
* priv_data Vendor specific data to be sent in the CM generated
* MRA message. Should be NULL if not specified.
* len The number of bytes of data specified by priv_data.
*
* RETURN VALUES:
* IBT_SUCCESS on success (or respective failure on error)
*/
{
/*
* Make sure channel is associated with a statep
*/
return (IBT_INVALID_PARAM);
}
/* Allocate an ibmf msg for mra, if not allocated yet */
if ((status = ibcm_alloc_out_msg(
MAD_METHOD_SEND)) != IBT_SUCCESS) {
return (status);
}
}
/* fill in rest of MRA's fields - Message MRAed and Service Timeout */
if (flags == IBT_CM_DELAY_REQ) {
} else if (flags == IBT_CM_DELAY_REP) {
} else if (flags == IBT_CM_DELAY_LAP) {
}
} else {
return (IBT_CHAN_STATE_INVALID);
}
} else {
return (IBT_CHAN_STATE_INVALID);
}
/* service time is usecs, stale_clock is nsecs */
/* post the MRA mad in blocking mode, as no timers involved */
statep);
/* If this message isn't seen then ibt_cm_delay failed */
return (IBT_SUCCESS);
}
/*
* ibt_register_service()
* Register a service with the IBCM
*
* INPUTS:
* ibt_hdl The IBT client handle returned to the client
* on an ibt_attach() call.
*
* srv The address of a ibt_srv_desc_t that describes
* the service, containing the following:
*
* sd_ud_handler The Service CM UD event Handler.
* sd_flags Service flags (peer-to-peer, or not).
*
* sid This tells CM if the service is local (sid is 0) or
* wellknown (sid is the starting service id of the range).
*
* num_sids The number of contiguous service-ids to reserve.
*
* srv_hdl The address of a service identification handle, used
* to deregister a service, and to bind GIDs to.
*
* ret_sid The address to store the Service ID return value.
* If num_sids > 1, ret_sid is the first Service ID
* in the range.
*
* ibt_register_service() returns:
* IBT_SUCCESS - added a service successfully.
* IBT_INVALID_PARAM - invalid input parameter.
* IBT_CM_FAILURE - failed to add the service.
* IBT_CM_SERVICE_EXISTS - service already exists.
* IBT_INSUFF_KERNEL_RESOURCE - ran out of local service ids (should
* never happen).
*/
{
if (num_sids <= 0) {
"Invalid number of service-ids specified (%d)", num_sids);
return (IBT_INVALID_PARAM);
}
if (sid == 0) {
return (IBT_INVALID_PARAM);
if (sid == 0)
return (IBT_INSUFF_KERNEL_RESOURCE);
/* Make sure that the ServiceId specified is not of LOCAL AGN type. */
"Invalid non-LOCAL SID specified: 0x%llX",
(longlong_t)sid);
return (IBT_INVALID_PARAM);
}
return (IBT_CM_SERVICE_EXISTS);
}
/*
* 'sid' and 'num_sids' are filled in ibcm_create_svc_entry()
*/
/* If this message isn't seen, then ibt_register_service failed. */
return (IBT_SUCCESS);
}
static ibt_status_t
{
int rval;
int retry;
if (rval != IBMF_TRANS_TIMEOUT) {
break;
}
"ibmf_saa_update_service_record timed out"
" SID = %llX, rval = %d, saa_type = %d",
}
if (rval != IBMF_SUCCESS) {
"ibmf_saa_update_service_record() : Failed - %d", rval);
return (ibcm_ibmf_analyze_error(rval));
} else
return (IBT_SUCCESS);
}
static void
{
void *results_p;
uint_t i;
/* Call in SA Access retrieve routine to get Service Records. */
&results_p);
if (retval != IBT_SUCCESS) {
"SA Access Failure");
return;
}
if (num_found)
"Found %d matching Service Records.", num_found);
/* Validate the returned number of records. */
/* Remove all the records. */
for (i = 0; i < num_found; i++) {
srv_resp = (sa_service_record_t *)
i * sizeof (sa_service_record_t));
/*
* Found some matching records, but check out whether
* this Record is really stale or just happens to match
* the current session records. If yes, don't remove it.
*/
/* This record is NOT STALE. */
"This is not Stale, it's an active record");
continue;
}
"Removing Stale Rec: %s, %llX",
/*
* Remove the Service Record Entry from SA.
*
* Get ServiceID info from Response Buf, other
* attributes are already filled-in.
*/
}
/* Deallocate the memory for results_p. */
}
}
/*
* ibt_bind_service()
* Register a service with the IBCM
*
* INPUTS:
* srv_hdl The service id handle returned to the client
* on an ibt_service_register() call.
*
* gid The GID to which to bind the service.
*
* srv_bind The address of a ibt_srv_bind_t that describes
* the service record. This should be NULL if there
* is to be no service record. This contains:
*
* sb_lease Lease period
* sb_pkey Partition
* sb_name pointer to ASCII string Service Name,
* NULL terminated.
* sb_key[] Key to secure the service record.
* sb_data Service Data structure (64-byte)
*
* cm_private First argument of Service handler.
*
* sb_hdl_p The address of a service bind handle, used
* to undo the service binding.
*
* ibt_bind_service() returns:
* IBT_SUCCESS - added a service successfully.
* IBT_INVALID_PARAM - invalid input parameter.
* IBT_CM_FAILURE - failed to add the service.
* IBT_CM_SERVICE_EXISTS - service already exists.
*/
{
/* Call ibtl_cm_get_hca_port to get the port number and the HCA GUID. */
"ibtl_cm_get_hca_port failed: %d", status);
return (status);
}
return (IBT_HCA_BUSY_DETACHING);
}
if (saa_handle == NULL) {
"saa_handle is NULL");
return (IBT_HCA_PORT_NOT_ACTIVE);
}
"P_Key must not be 0");
return (IBT_INVALID_PARAM);
}
"Service Name is too long");
return (IBT_INVALID_PARAM);
} else
if (status != IBT_SUCCESS) {
"P_Key 0x%x not found in P_Key_Table",
return (status);
}
}
/* assume success - allocate before locking */
"failed: GID %llx:%llx and PKEY %x is "
return (IBT_CM_SERVICE_EXISTS);
}
}
}
/* no entry found */
/*
* Find out whether we have any stale Local Service records
* matching the current attributes. If yes, we shall try to
* remove them from SA using the current request's ServiceKey.
*
* We will perform this operation only for Local Services, as
* it is handled by SA automatically for WellKnown Services.
*
* Ofcourse, clients can specify NOT to do this clean-up by
* setting IBT_SBIND_NO_CLEANUP flag (srv_bind->sb_flag).
*/
}
/* Handle endianess for service data. */
/* insert srv record into the SA */
"ibmf_saa_write_service_record, SvcId = %llX",
(longlong_t)sid);
if (status != IBT_SUCCESS) {
" ibcm_write_service_record fails %d, "
/*
* Bind failed while bind SID other than
* first in the sid_range. So we need
* to unbind those, which are passed.
*
* Need to increment svc count to
* compensate for ibt_unbind_service().
*/
(void) ibt_unbind_service(srv_hdl,
sbindp);
} else {
/*
* Bind failed for the first SID or the
* only SID in question, then no need
* to unbind, just free memory and
* return error.
*/
break;
}
}
}
return (status);
}
}
}
/* If this message isn't seen then ibt_bind_service failed */
return (IBT_SUCCESS);
}
{
/* If there is a service on hca, respective hcap cannot go away */
break;
}
}
"service binding not found: srv_hdl %p, srv_bind %p",
return (IBT_INVALID_PARAM);
}
/* get the default SGID of the port */
!= IBT_SUCCESS) {
"ibtl_cm_get_hca_port failed: %d", status);
/* we're done, but there may be stale service records */
goto done;
}
if (saa_handle == NULL) {
"saa_handle is NULL");
/* we're done, but there may be stale service records */
goto done;
}
/* Fill in fields of srv_rec */
"ibcm_write_service_record rval = %d, SID %llx",
if (rval != IBT_SUCCESS) {
/* this is not considered a reason to fail */
"ibcm_write_service_record fails %d, "
}
sid++;
}
}
done:
/* If this message isn't seen then ibt_unbind_service failed */
return (IBT_SUCCESS);
}
/*
* Simply pull off each binding from the list and unbind it.
* If any of the unbind calls fail, we fail.
*/
{
/* this compare keeps the loop from being infinite */
if (status != IBT_SUCCESS)
return (status);
break;
}
return (IBT_SUCCESS);
}
/*
* ibt_deregister_service()
* Deregister a service with the IBCM
*
* INPUTS:
* ibt_hdl The IBT client handle returned to the client
* on an ibt_attach() call.
*
* srv_hdl The address of a service identification handle, used
* to de-register a service.
* RETURN VALUES:
* IBT_SUCCESS on success (or respective failure on error)
*/
{
" srv_hdl %p still has bindings", srv_hdl);
return (IBT_CM_SERVICE_BUSY);
}
#ifdef __lock_lint
#endif
"srv_hdl %p not found", srv_hdl);
return (IBT_INVALID_PARAM);
}
while (svcp->svc_ref_cnt != 0)
/* If this message isn't seen then ibt_deregister_service failed */
return (IBT_SUCCESS);
}
ibcm_ar_init(void)
{
/* remove this special SID from the pool of available SIDs */
return (IBCM_FAILURE);
}
return (IBCM_SUCCESS);
}
ibcm_ar_fini(void)
{
return (IBCM_SUCCESS);
}
return (IBCM_FAILURE);
}
/*
* Return to the caller:
* IBT_SUCCESS Found a perfect match.
* *arpp is set to the record.
* IBT_INCONSISTENT_AR Found a record that's inconsistent.
* found no record with same data.
*/
static ibt_status_t
{
int i;
tmp = ibcm_ar_list;
for (i = 0; i < IBCM_DAPL_ATS_NBYTES; i++)
return (IBT_INCONSISTENT_AR);
return (IBT_SUCCESS);
} else {
/* if all the data bytes match, we have inconsistency */
for (i = 0; i < IBCM_DAPL_ATS_NBYTES; i++)
break;
if (i == IBCM_DAPL_ATS_NBYTES)
return (IBT_INCONSISTENT_AR);
/* try next address record */
}
}
return (IBT_AR_NOT_REGISTERED);
}
{
char *s;
/*
* If P_Key is 0, but GID is not, this query is invalid.
* If GID is 0, but P_Key is not, this query is invalid.
*/
return (IBT_INVALID_PARAM);
}
/* assume success, so these might be needed */
if (status == IBT_INCONSISTENT_AR) {
"address record is inconsistent with a known one");
return (IBT_INCONSISTENT_AR);
} else if (status == IBT_SUCCESS) {
found->ar_waiters++;
found->ar_waiters--;
}
if (found->ar_waiters == 0) {
}
return (ibt_get_module_failure(IBT_FAILURE_IBCM, 0));
}
return (IBT_SUCCESS);
} else {
}
new->ar_waiters = 0;
ibcm_ar_list = new;
!= IBT_SUCCESS ||
if (s1 == IBT_HCA_PORT_NOT_ACTIVE) {
s = "PORT DOWN";
} else if (s1 != IBT_SUCCESS)
s = "GID not found";
else if (s2 != IBT_SUCCESS)
s = "PKEY not found";
else
s = "CM could not find its HCA entry";
s, status);
return (status);
}
/* create service record */
/* insert service record into the SA */
if (saa_handle != NULL)
else
if (status != IBT_SUCCESS) {
linkp = &ibcm_ar_list;
break;
}
}
if (new->ar_waiters > 0) {
} else {
}
"IBMF_SAA failed to write address record");
} else { /* SUCCESS */
uint8_t *b;
" data %d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9],
b[10], b[11], b[12], b[13], b[14], b[15]);
if (new->ar_waiters > 0)
/* do not call ibcm_dec_hca_acc_cnt(hcap) until deregister */
}
return (status);
}
{
/*
* If P_Key is 0, but GID is not, this query is invalid.
* If GID is 0, but P_Key is not, this query is invalid.
*/
return (IBT_INVALID_PARAM);
}
"address record not found");
return (IBT_AR_NOT_REGISTERED);
}
break;
}
"address record found, but not for this client");
return (IBT_AR_NOT_REGISTERED);
}
/* last entry was removed */
/* wait if this service record is being rewritten */
/* remove service record */
if (status != IBT_SUCCESS)
"IBMF_SAA failed to delete address record");
linkp = &ibcm_ar_list;
}
} else {
/* add service record back in for the waiters */
if (status == IBT_SUCCESS)
else {
"IBMF_SAA failed to write address record");
}
}
}
return (status);
}
{
void *results_p;
uint64_t component_mask = 0;
int num_rec;
int i;
/*
* If P_Key is 0, but GID is not, this query is invalid.
* If GID is 0, but P_Key is not, this query is invalid.
*/
return (IBT_INVALID_PARAM);
}
return (IBT_INVALID_PARAM);
}
}
/* Is ServiceData Specified. */
for (i = 0; i < IBCM_DAPL_ATS_NBYTES; i++) {
/* components */
break;
}
}
/* Service Name */
"Perform SA Access: Mask: 0x%X", component_mask);
/*
* Call in SA Access retrieve routine to get Service Records.
*
* SA Access framework allocated memory for the "results_p".
* Make sure to deallocate once we are done with the results_p.
* The size of the buffer allocated will be as returned in
* "length" field.
*/
&results_p);
if (retval != IBT_SUCCESS) {
return (retval);
}
"Found %d Service Records.", num_rec);
/* Validate the returned number of records. */
uint8_t *b;
/* Just return info from the first service record. */
/* The Service GID and Service ID */
" data %d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9],
b[10], b[11], b[12], b[13], b[14], b[15]);
/* Deallocate the memory for results_p. */
if (num_rec > 1)
else
} else {
"ibmf_sa_access found 0 matching records");
}
return (retval);
}
/* mark all ATS service records associated with the port */
static void
{
/* even if it's busy, we mark it for rewrite */
}
}
}
/* rewrite all ATS service records */
static int
ibcm_rewrite_ar(void)
{
int did_something = 0;
"rewriting ar @ %p", tmp);
did_something = 1;
if (rval != IBT_SUCCESS)
"ibcm_write_service_record failed: "
"status = %d", rval);
/* if it got marked again, then we want to rewrite */
/* in case there was a waiter... */
goto check_for_work;
}
}
return (did_something);
}
static void
{
return;
}
if (saa_handle == NULL) {
"saa_handle is NULL");
return;
}
/* insert srv record into the SA */
"ibcm_write_service_record, SvcId = %llX, "
if (rval != IBT_SUCCESS) {
" ibcm_write_service_record fails %d sid %llX",
}
}
}
/*
* This task does not return until all of them have been rewritten.
*/
void
{
static int task_is_running = 0;
if (sbp->sbind_pkey != 0 &&
/* even if it's busy, we mark it for rewrite */
}
}
}
if (task_is_running) {
/* let the other task thread finish the work */
return;
}
task_is_running = 1;
(void) ibcm_rewrite_ar();
/* if it got marked again, we want to rewrite */
if (sbp->sbind_rewrite_state ==
/* in case there was a waiter... */
goto check_for_work;
}
}
}
/*
* If there were no service records to write, and we failed to
* have to rewrite any more ATS service records, then we're done.
*/
if (ibcm_rewrite_ar() != 0)
goto check_for_work;
task_is_running = 0;
}
/*
* Function:
* ibt_cm_proceed
*
* Verifies the arguments and dispatches the cm state machine processing
* via taskq
*/
{
/* validate session_id and status */
return (IBT_INVALID_PARAM);
}
/* If priv data len specified, then priv_data cannot be NULL */
return (IBT_INVALID_PARAM);
if (event == IBT_CM_EVENT_REQ_RCV) {
else if (priv_data_len > IBT_REP_PRIV_DATA_SZ)
} else if (event == IBT_CM_EVENT_REP_RCV) {
else if (priv_data_len > IBT_RTU_PRIV_DATA_SZ)
} else if (event == IBT_CM_EVENT_LAP_RCV) {
else if (priv_data_len > IBT_APR_PRIV_DATA_SZ)
} else if (event == IBT_CM_EVENT_CONN_CLOSED) {
else if (priv_data_len > IBT_DREP_PRIV_DATA_SZ)
} else {
}
/* if there is an error, print an error message and return */
if (proceed_error != IBCM_PROCEED_INVALID_NONE) {
return (IBT_INVALID_PARAM);
} else if (proceed_error == IBCM_PROCEED_INVALID_PRIV_SZ) {
return (IBT_INVALID_PARAM);
} else if (proceed_error == IBCM_PROCEED_INVALID_EVENT) {
return (IBT_INVALID_PARAM);
} else {
"IBT_CM_EVENT_LAP_RCV not supported",
/* UNTIL HCA DRIVER ENABLES AP SUPPORT, FAIL THE CALL */
return (IBT_APM_NOT_SUPPORTED);
}
}
/* wait until client's CM handler returns DEFER status back to CM */
}
"client returned non-DEFER status from cm handler",
return (IBT_CHAN_STATE_INVALID);
}
/* the state machine processing is done in a separate thread */
/* proceed_targs is freed in ibcm_proceed_via_taskq */
KM_SLEEP);
sizeof (ibt_cm_proceed_reply_t));
return (IBT_SUCCESS);
}
/*
* Function:
* ibcm_proceed_via_taskq
*
* Called from taskq, dispatched by ibt_cm_proceed
* Completes the cm state processing for ibt_cm_proceed
*/
void
ibcm_proceed_via_taskq(void *targs)
{
response =
arej_len);
response =
} else {
}
}
/*
* Function:
* ibt_cm_ud_proceed
*
* Verifies the arguments and dispatches the cm state machine processing
* via taskq
*/
{
/* validate session_id and status */
return (IBT_INVALID_PARAM);
}
/* If priv data len specified, then priv_data cannot be NULL */
return (IBT_INVALID_PARAM);
return (IBT_INVALID_PARAM);
/* retrieve qpn and qkey from ud channel */
/* validate event and statep's state */
if (status == IBT_CM_ACCEPT) {
if ((retval != IBT_SUCCESS) ||
"Failed to retrieve QPN from the channel: %d",
retval);
return (IBT_INVALID_PARAM);
}
}
"specified");
return (IBT_INVALID_PARAM);
}
/* wait until client's CM handler returns DEFER status back to CM */
" of client's ud cm handler");
}
"returned non-DEFER status from cm handler");
return (IBT_INVALID_PARAM);
}
/* the state machine processing is done in a separate thread */
/* proceed_targs is freed in ibcm_proceed_via_taskq */
KM_SLEEP);
if (status == IBT_CM_ACCEPT) {
}
/* copy redirect info based on status */
if (status == IBT_CM_REDIRECT)
sizeof (ibt_redirect_info_t));
return (IBT_SUCCESS);
}
/*
* Function:
* ibcm_ud_proceed_via_taskq
*
* Called from taskq, dispatched by ibt_cm_ud_proceed
* Completes the cm state processing for ibt_cm_ud_proceed
*/
void
ibcm_ud_proceed_via_taskq(void *targs)
{
/* validate event and statep's state */
/* decr the statep ref cnt incremented in ibcm_process_sidr_req_msg */
}
/*
* Function:
* ibt_set_alt_path
* Input:
* channel Channel handle returned from ibt_alloc_rc_channel(9F).
*
* mode Execute in blocking or non blocking mode.
*
* alt_path A pointer to an ibt_alt_path_info_t as returned from an
* ibt_get_alt_path(9F) call that specifies the new
* alternate path.
*
* priv_data A pointer to a buffer specified by caller for the
* private data in the outgoing CM Load Alternate Path
* (LAP) message sent to the remote host. This can be NULL
* if no private data is available to communicate to the
* remote node.
*
* priv_data_len Length of valid data in priv_data, this should be less
* than or equal to IBT_LAP_PRIV_DATA_SZ.
*
* Output:
* ret_args If called in blocking mode, points to a return argument
* structure of type ibt_ap_returns_t.
*
* Returns:
* IBT_SUCCESS on Success else appropriate error.
* Description:
* Load the specified alternate path. Causes the CM to send an LAP message
* to the remote node.
* Can only be called on a previously opened RC channel.
*/
{
/* validate channel */
if (IBCM_INVALID_CHANNEL(channel)) {
return (IBT_CHAN_HDL_INVALID);
}
"Invalid Channel type: Applicable only to RC Channel");
return (IBT_CHAN_SRV_TYPE_INVALID);
}
if (mode == IBT_NONBLOCKING) {
"ret_args should be NULL when called in "
"non-blocking mode");
return (IBT_INVALID_PARAM);
}
} else if (mode == IBT_BLOCKING) {
"ret_args should be Non-NULL when called in "
"blocking mode");
return (IBT_INVALID_PARAM);
}
"expected private data length is too large");
return (IBT_INVALID_PARAM);
}
if ((ret_args->ap_priv_data_len > 0) &&
"apr_priv_data_len > 0, but apr_priv_data NULL");
return (IBT_INVALID_PARAM);
}
} else { /* any other mode is not valid for ibt_set_alt_path */
"invalid mode %x specified", mode);
return (IBT_INVALID_PARAM);
}
return (IBT_INVALID_PARAM);
/* get the statep */
return (IBT_CM_FAILURE);
}
/* HCA must have been in active state. If not, it's a client bug */
if (!IBCM_ACCESS_HCA_OK(hcap))
/* Check Alternate port */
&base_lid);
if (status != IBT_SUCCESS) {
"ibt_get_port_state_byguid status %d ", status);
return (status);
}
!= IBT_SUCCESS)) {
"ibmf reg or callback setup failed during re-initialize");
return (status);
}
ibcm_lapr_enter(); /* limit how many run simultaneously */
/* Allocate MAD for LAP */
MAD_METHOD_SEND)) != IBT_SUCCESS) {
"chan 0x%p ibcm_alloc_out_msg failed", channel);
return (status);
}
/* Check state */
return (IBT_CHAN_STATE_INVALID);
} else {
/* Set to LAP Sent state */
}
/* No more failure returns below */
/* Allocate MAD for LAP */
/* Fill in remote port gid */
/* Fill in local port gid */
/* alternate_flow_label, and alternate srate, alternate traffic class */
/* Alternate hop limit, service level */
}
/* only rc_alt_pkt_lt and ap_return_data fields are initialized */
/* return_data is filled up in the state machine code */
0));
/* Send LAP */
statep);
if (mode == IBT_BLOCKING) {
/* wait for APR */
&statep->state_mutex);
}
/*
* In the case that ibt_set_alt_path fails,
* change retval to IBT_CM_FAILURE
*/
}
/* decrement the ref-count before leaving here */
/* If this message isn't seen then ibt_set_alt_path failed */
return (status);
}
#ifdef DEBUG
/*
* ibcm_query_classport_info:
* Query classportinfo
*
* INPUTS:
* channel - Channel that is associated with a statep
*
* RETURN VALUE: NONE
* This function is currently used to generate a valid get method classport
* info, and test CM functionality. There is no ibtl client interface to
* generate a classportinfo. It is possible that CM may use classportinfo
* from other nodes in the future, and most of the code below could be re-used.
*/
void
{
/* validate channel, first */
if (IBCM_INVALID_CHANNEL(channel)) {
"invalid channel (%p)", channel);
return;
}
/* get the statep */
/*
* This can happen, if the statep is already gone by a DREQ from
* the remote side
*/
"statep NULL");
return;
}
"Get method MAD posted ", channel);
}
static void
{
}
#endif
typedef struct ibcm_join_mcg_tqarg_s {
void *arg;
/*
* Function:
* ibt_join_mcg
* Input:
* rgid The request GID that defines the HCA port from which a
* contact to SA Access is performed to add the specified
* endport GID ((mcg_attr->mc_pgid) to a multicast group.
* If mcg_attr->mc_pgid is null, then this (rgid) will be
* treated as endport GID that is to be added to the
* multicast group.
*
* mcg_attr A pointer to an ibt_mcg_attr_t structure that defines
* the attributes of the desired multicast group to be
* created or joined.
*
* func NULL or a pointer to a function to call when
* ibt_join_mcg() completes. If 'func' is not NULL then
* ibt_join_mcg() will return as soon as possible after
* 'func' is then called when the process completes.
*
* arg Argument to the 'func'.
*
* Output:
* mcg_info_p A pointer to the ibt_mcg_info_t structure, allocated
* by the caller, where the attributes of the created or
* joined multicast group are copied.
* Returns:
* IBT_SUCCESS
* IBT_INVALID_PARAM
* IBT_MCG_RECORDS_NOT_FOUND
* IBT_INSUFF_RESOURCE
* Description:
* Join a multicast group. The first full member "join" causes the MCG
* to be created.
*/
{
return (IBT_INVALID_PARAM);
}
return (IBT_INVALID_PARAM);
}
if (mcg_attr->mc_join_state == 0) {
return (IBT_INVALID_PARAM);
}
if (mcg_info_p == NULL) {
return (IBT_INVALID_PARAM);
}
"Unable to allocate memory for local usage.");
return (IBT_INSUFF_KERNEL_RESOURCE);
}
mcg_tq, TQ_NOSLEEP) == 0) {
"Dispatch the TaskQ");
return (IBT_INSUFF_KERNEL_RESOURCE);
} else
return (IBT_SUCCESS);
} else { /* Blocking */
return (ibcm_process_join_mcg(mcg_tq));
}
}
static void
{
(void) ibcm_process_join_mcg(tq_arg);
}
static ibt_status_t
ibcm_process_join_mcg(void *taskq_arg)
{
uint64_t component_mask = 0;
if (retval != IBT_SUCCESS) {
"port info from specified RGID: status = %d", retval);
goto ibcm_join_mcg_exit1;
}
"Request GID is Port GID");
} else {
}
/* If client has specified MGID, use it else SA will assign one. */
}
/* Is MTU specified. */
}
/* Is RATE specified. */
}
/* Is Packet Life Time specified. */
}
}
}
}
/* Get SA Access Handle. */
goto ibcm_join_mcg_exit1;
}
if (saa_handle == NULL) {
goto ibcm_join_mcg_exit;
}
&hca_port);
if (retval != IBT_SUCCESS) {
"to get PortInfo of specified PGID: status = %d",
retval);
goto ibcm_join_mcg_exit1;
}
}
/* Contact SA Access */
(void **)&mcg_resp);
if (retval != IBT_SUCCESS) {
"SA Access Failed");
goto ibcm_join_mcg_exit;
}
"Found %d MCMember Records", num_records);
/* Validate the returned number of records. */
/* Update the return values. */
if (retval != IBT_SUCCESS) {
"Pkey2Index Conversion failed<%d>", retval);
mcg_info_p->mc_pkey_ix = 0;
}
/* Deallocate the memory allocated by SA for mcg_resp. */
} else {
"MCG RECORDS NOT FOUND");
}
return (retval);
}
/*
* Function:
* ibt_leave_mcg
* Input:
* rgid The request GID that defines the HCA port upon which
* to send the request to the Subnet Administrator, to
* remove the specified port (port_gid) from the multicast
* group. If 'port_gid' is the Reserved GID (i.e.
* port_gid.gid_prefix = 0 and port_gid.gid_guid = 0),
* then the end-port associated with 'rgid' is removed
* from the multicast group.
*
* mc_gid A multicast group GID as returned from ibt_join_mcg()
* call. This is optional, if not specified (i.e.
* mc_gid.gid_prefix has 0xFF in its upper 8 bits to
* identify this as being a multicast GID), then the
* port is removed from all the multicast groups of
* which it is a member.
*
* port_gid This is optional, if not the Reserved GID (gid_prefix
* and gid_guid not equal to 0), then this specifies the
* endport GID of the multicast group member being deleted
* from the group. If it is the Reserved GID (gid_prefix
* and gid_guid equal to 0) then the member endport GID is
* determined from 'rgid'.
*
* mc_join_state The Join State attribute used when the group was joined
* using ibt_join_mcg(). This Join State component must
* contains at least one bit set to 1 in the same position
* as that used during ibt_join_mcg(). i.e. the logical
* AND of the two JoinState components is not all zeros.
* This Join State component must not have some bits set
* which are not set using ibt_join_mcg().
* Output:
* None.
* Returns:
* IBT_SUCCESS
* IBT_INVALID_PARAM
* IBT_MC_GROUP_INVALID
* IBT_INSUFF_RESOURCE
* Description:
* The port associated with the port GID shall be removed from the
* multicast group specified by MGID (mc_gid) or from all the multicast
* groups of which it is a member if the MGID (mc_gid) is not specified.
*
* The last full member to leave causes the destruction of the Multicast
* Group.
*/
{
uint64_t component_mask = 0;
int sa_retval;
void *results_p;
return (IBT_INVALID_PARAM);
}
/* Validate MGID */
return (IBT_MC_MGID_INVALID);
}
} else {
}
/* Join State */
if (retval != IBT_SUCCESS) {
"from specified RGID : status = %d", retval);
return (retval);
}
/* Get SA Access Handle. */
"NO HCA found");
return (IBT_HCA_BUSY_DETACHING);
}
if (saa_handle == NULL) {
return (IBT_HCA_PORT_NOT_ACTIVE);
}
/* Contact SA Access */
&results_p);
if (sa_retval != IBMF_SUCCESS) {
(void) ibcm_ibmf_analyze_error(sa_retval);
}
return (retval);
}
/*
* Function:
* ibt_query_mcg
* Input:
* rgid The request GID that defines the HCA port upon which
* to send the request to the Subnet Administrator, to
* retrieve Multicast Records matching attributes as
* specified through 'mcg_attr' argument.
*
* mcg_attr NULL or a pointer to an ibt_mcg_attr_t structure that
* specifies MCG attributes that are to be matched.
* Attributes that are not required can be wild carded
* by specifying as '0'.
*
* mcgs_max_num The maximum number of matching multicast groups to
* return. If zero, then all available matching multicast
* groups are returned.
* Output:
* mcgs_info_p The address of an ibt_mcg_info_t pointer, where
* multicast group information is returned. The actual
* number of entries filled in the array is returned in
* entries_p.
*
* entries_p The number of ibt_mcg_attr_t entries returned.
* Returns:
* IBT_SUCCESS
* IBT_INVALID_PARAM
* IBT_MCG_RECORDS_NOT_FOUND
* Description:
* Request information on multicast groups that match the parameters
* specified in mcg_attr. Information on each multicast group is returned
* to the caller in the form of an array of ibt_mcg_info_t.
* ibt_query_mcg() allocates the memory for this array and returns a
* pointer to the array (mcgs_p) and the number of entries in the array
* (entries_p). This memory should be freed by the client using
* ibt_free_mcg_info().
*/
{
uint64_t component_mask = 0;
void *results_p;
"entries_p or mcgs_info_p is NULL");
return (IBT_INVALID_PARAM);
}
return (IBT_INVALID_PARAM);
}
}
/* Is Q_Key specified. */
}
/* Is P_Key specified. */
}
/* Is MGID specified. */
}
/* Is MTU specified. */
}
}
/* Is RATE specified. */
}
/* Is Packet Life Time specified. */
}
}
}
}
}
if (mcg_attr->mc_join_state) {
}
}
}
if (retval != IBT_SUCCESS) {
"from specified RGID : status = %d", retval);
return (retval);
}
/* Get SA Access Handle. */
return (IBT_HCA_BUSY_DETACHING);
}
if (saa_handle == NULL) {
return (IBT_HCA_PORT_NOT_ACTIVE);
}
/* Contact SA Access */
&results_p);
if (retval != IBT_SUCCESS) {
return (retval);
}
/* Validate the returned number of records. */
uint_t i;
/*
* If mcgs_max_num is zero, then return all records else
* return only requested number of records
*/
/* we are interested in only mcgs_max_num records */
}
/*
* The SGID returned in "mcg_info_p" buffer should be PortGID,
* (mcg_attr->mc_pgid), if 'mcg_attr->mc_pgid' was specified,
* else RequestGID (rgid) should be returned.
*/
/* Get sgid_ix and port number of 'port_gid' */
if (retval != IBT_SUCCESS) {
"Failed to Get Portinfo for PortGID :"
"status = %d", retval);
return (retval);
}
} else {
/*
* The sgid_ix and port number related to RequestGID
* are already obtained at the beginning.
*/
}
/*
* Allocate memory for return buffer, to be freed in
* ibt_free_mcg_info().
*/
KM_SLEEP);
*mcgs_info_p = mcg_infop;
*entries_p = num_records;
/* Update the return values. */
for (i = 0; i < num_records; i++) {
results_p + i * sizeof (sa_mcmember_record_t));
"Pkey2Index Conversion failed");
mcg_infop[i].mc_pkey_ix = 0;
}
}
/*
* Deallocate the memory allocated by SA for results_p.
*/
} else {
*entries_p = 0;
}
return (retval);
}
/*
* ibt_free_mcg_info()
* Free the memory allocated by successful ibt_query_mcg()
*
* mcgs_info Pointer returned by ibt_query_mcg().
*
* entries The number of ibt_mcg_info_t entries to free.
*/
void
{
else
"ERROR: NULL buf pointer or length specified.");
}
/*
* Function:
* ibt_gid_to_node_info()
* Input:
* gid Identifies the IB Node and port for which to obtain
* Node information.
* Output:
* node_info_p A pointer to an ibt_node_info_t structure (allocated
* by the caller) in which to return the node information.
* Returns:
* IBT_SUCCESS
* IBT_INVALID_PARAM
* IBT_NODE_RECORDS_NOT_FOUND
* IBT_NO_HCAS_AVAILABLE
* Description:
* Retrieve Node Information for the specified GID.
*/
{
int i, j;
void *res_p;
return (IBT_INVALID_PARAM);
}
if (node_info_p == NULL) {
"Return Buf (node_info_p) is NULL.");
return (IBT_INVALID_PARAM);
}
/*
* If 'gid' is on local node, then get node lid (i.e. base lid of the
* associated port) info via ibtl_cm_get_hca_port() call.
*/
return (IBT_NO_HCAS_AVAILABLE);
}
num_ports = 1;
num_hcas = 1;
local_node = B_TRUE;
"LID = 0x%X", node_lid);
} else {
/* Get the number of HCAs and their GUIDs */
"returned %d hcas", num_hcas);
if (num_hcas == 0) {
"NO HCA's Found on this system");
return (IBT_NO_HCAS_AVAILABLE);
}
}
for (i = 0; i < num_hcas; i++) {
if (local_node == B_FALSE) {
"HCA(%llX) info not found", guid_array[i]);
continue;
}
}
for (j = 0; j < num_ports; j++) {
if (local_node == B_TRUE)
else
port = j + 1;
/* Get SA Access Handle. */
if (saa_handle == NULL) {
"Port %d of HCA (%llX) is NOT ACTIVE",
continue;
}
if (local_node == B_FALSE) {
int sa_ret;
/*
* Check whether 'gid' and this port has same
* subnet prefix. If not, then there is no use
* in searching from this port.
*/
"ibt_gid_to_node_info:Sn_Prefix of "
"GID(%llX) and Port's(%llX) differ",
continue;
}
/*
* First Get Path Records for the specified DGID
* from this port (SGID). From Path Records,
* note down DLID, then use this DLID as Input
* attribute to get NodeRecords from SA Access.
*/
npaths = 1;
&path);
if (sa_ret != IBMF_SUCCESS) {
"ibt_gid_to_node_info: "
"ibmf_saa_gid_to_pathrecords() "
"returned error: %d ", sa_ret);
retval =
continue;
"ibt_gid_to_node_info: failed (%d) "
"to get path records for the DGID "
"0x%llX from SGID 0x%llX", sa_ret,
continue;
}
"Remote Node: LID = 0x%X", node_lid);
/* Free SA_Access memory for path record. */
}
/* Retrieve Node Records from SA Access. */
if (retval == IBT_NODE_RECORDS_NOT_FOUND) {
"failed (%d) to get Node records", retval);
continue;
} else if (retval != IBT_SUCCESS) {
"failed (%d) to get Node records", retval);
goto gid_to_ni_exit;
}
/* Validate the returned number of records. */
*node_info_p))
*node_info_p))
/*
* Deallocate the memory allocated by SA for
* 'nr_resp'.
*/
goto gid_to_ni_exit;
} else {
"Node Records NOT found - PortGUID %016llX",
}
}
if (local_node == B_TRUE)
break;
}
if (guid_array)
return (retval);
}
static ibt_status_t
{
if (retval != IBT_SUCCESS) {
return (retval);
}
/* Validate the returned number of records. */
/* Got it, done!. */
return (IBT_SUCCESS);
} else {
return (IBT_NODE_RECORDS_NOT_FOUND);
}
}
/*
* Function:
* ibt_get_companion_port_gids()
* Description:
* Get list of GID's available on a companion port(s) of the specified
* GID or list of GIDs available on a specified Node GUID/SystemImage GUID.
*/
{
void *res_p;
int sa_ret;
int i, j;
int multi_hca_loop = 0;
(sysimg_guid == 0)) {
"Null Input attribute specified.");
return (IBT_INVALID_PARAM);
}
"num_gids_p or gids_p is NULL");
return (IBT_INVALID_PARAM);
}
*num_gids_p = 0;
/* Get the number of HCAs and their GUIDs */
"NO HCA's Found on this system");
return (IBT_NO_HCAS_AVAILABLE);
}
"ibt_get_hca_list() returned %d hcas", num_hcas);
/*
* If 'gid' is on local node, then get node lid (i.e. base lid of the
* associated port) info via ibtl_cm_get_hca_port() call.
*/
"Invalid GID<->HCAGUID combination specified.");
goto get_comp_pgid_exit;
}
local_node = B_TRUE;
"Local Node: HCA (0x%llX)", h_guid);
} else if (h_guid) { /* Is specified HCA GUID - local? */
for (i = 0; i < num_hcas; i++) {
if (h_guid == guid_array[i]) {
break;
}
}
} else if (sysimg_guid) { /* Is specified SystemImage GUID - local? */
for (i = 0; i < num_hcas; i++) {
if (ret != IBT_SUCCESS) {
"ibt_get_companion_port_gids: HCA(%llX) "
"info not found", guid_array[i]);
continue;
}
if ((hca_guid != 0) &&
"ibt_get_companion_port_gids: "
"Invalid SysImg<->HCA GUID "
"combination specified.");
goto get_comp_pgid_exit;
}
break;
}
}
}
goto get_comp_pgid_exit;
}
/* We will be here, if request is for remote node */
for (i = 0; i < num_hcas; i++) {
int multism;
int multi_sm_loop = 0;
uint_t k = 0, l;
"HCA(%llX) info not found", guid_array[i]);
continue;
}
/* 1 - MultiSM, 0 - Single SM */
for (j = 0; j < hcap->hca_num_ports; j++) {
"Port %d, HCA %llX, MultiSM= %d, Loop=%d",
/* Get SA Access Handle. */
if (saa_handle == NULL) {
"ibt_get_companion_port_gids: "
"Port (%d) - NOT ACTIVE", port);
continue;
}
/*
* Check whether 'gid' and this port has same subnet
* prefix. If not, then there is no use in searching
* from this port.
*/
(multi_sm_loop == 0) &&
"ibt_get_companion_port_gids: SnPrefix of "
"GID(%llX) and Port SN_Pfx(%llX) differ",
continue;
}
/*
* If HCA GUID or System Image GUID is specified, then
* we can achieve our goal sooner!.
*/
if ((h_guid == 0) && (sysimg_guid == 0)) {
/* So only GID info is provided. */
/*
* First Get Path Records for the specified DGID
* from this port (SGID). From Path Records,
* note down DLID, then use this DLID as Input
* attribute to get NodeRecords.
*/
npaths = 1;
&path);
if (sa_ret != IBMF_SUCCESS) {
"ibt_get_companion_port_gids: "
"ibmf_saa_gid_to_pathrecords() "
"returned error: %d ", sa_ret);
retval =
goto get_comp_pgid_exit;
"ibt_get_companion_port_gids: "
"failed (%d) to get path records "
"for the DGID (0x%llX) from SGID "
continue;
}
"ibt_get_companion_port_gids: "
/* Free SA_Access memory for path record. */
"ibt_get_companion_port_gids: SAA Call: "
"based on LID ");
if (retval == IBT_NODE_RECORDS_NOT_FOUND) {
"ibt_get_companion_port_gids: "
"failed (%d) to get Node records",
retval);
continue;
} else if (retval != IBT_SUCCESS) {
"ibt_get_companion_port_gids: "
"failed (%d) to get Node records",
retval);
goto get_comp_pgid_exit;
}
/* Note down HCA GUID info. */
"ibt_get_companion_port_gids: "
"Remote HCA GUID: 0x%llX", h_guid);
}
if (h_guid != 0) {
}
if (sysimg_guid != 0) {
}
"SAA Call: CMASK= 0x%llX", c_mask);
if (retval == IBT_NODE_RECORDS_NOT_FOUND) {
"ibt_get_companion_port_gids: "
"failed (%d) to get Node records", retval);
continue;
} else if (retval != IBT_SUCCESS) {
"ibt_get_companion_port_gids: Error: (%d) "
"while getting Node records", retval);
goto get_comp_pgid_exit;
}
/* We will be here, only if we found some NodeRec */
count++;
}
} else {
}
if (count != 0) {
if (multi_sm_loop == 1) {
count += k;
k * sizeof (ib_gid_t));
k * sizeof (ib_gid_t));
}
} else {
}
*num_gids_p = count;
"ibt_get_companion_port_gids: "
"PortGID %llX", pg);
gidp[k].gid_prefix =
"ibt_get_companion_pgids: "
"GID[%d] = %llX:%llX", k,
gidp[k].gid_prefix,
k++;
if (k == count)
break;
}
}
goto get_comp_pgid_exit;
} else {
"ibt_get_companion_port_gids: "
"Companion PortGIDs not available");
}
/* Deallocate the memory for 'res_p'. */
/*
* If we are on MultiSM setup, then we need to lookout
* from that subnet port too.
*/
if (multism) {
/* break if already searched both the subnet */
if (multi_sm_loop == 1)
break;
port = (j == 0) ? 1 : 0;
multi_sm_loop = 1;
goto get_comp_for_multism;
} else {
break;
}
}
/*
* We may be on dual HCA with dual SM configured system. And
* the input attr GID was visible from second HCA. So in order
* to get the companion portgid we need to re-look from the
* first HCA ports.
*/
(multi_hca_loop != 1)) {
multi_hca_loop = 1;
goto get_comp_for_multihca;
}
}
if (guid_array)
}
return (retval);
}
/* Routines for warlock */
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static ibt_cm_status_t
{
/*
* Let warlock see that ibcm_local_handler_s::actual_cm_handler
* points to this routine.
*/
"dummy_ud.ud_cm_handler %p", p.actual_cm_handler,
/*
* Call all routines that the client's callback routine could call.
*/
return (IBT_CM_ACCEPT);
}
/* ARGSUSED */
static ibt_cm_status_t
{
/*
* Call all routines that the client's callback routine could call.
*/
return (IBT_CM_ACCEPT);
}