/*
* 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
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
*
* contains internal functions of IB CM module.
*
* TBD:
* 1. HCA CATASTROPHIC/RECOVERED not handled yet
*/
/* function prototypes */
static ibcm_status_t ibcm_init(void);
static ibcm_status_t ibcm_fini(void);
/* Routines to initialize and destroy CM global locks and CVs */
static void ibcm_init_locks(void);
static void ibcm_fini_locks(void);
/* Routines that initialize/teardown CM's global hca structures */
static void ibcm_init_hcas();
static ibcm_status_t ibcm_fini_hcas();
static void ibcm_init_classportinfo();
static void ibcm_stop_timeout_thread();
static void ibcm_hca_attach(ib_guid_t);
/* Routines that initialize the HCA's port related fields */
static void ibcm_rc_flow_control_init(void);
static void ibcm_rc_flow_control_fini(void);
/*
* Routines that check if hca's avl trees and sidr lists are free of any
* active client resources ie., RC or UD state structures in certain states
*/
/* Add a new hca structure to CM's global hca list */
static void ibcm_comm_est_handler(ibt_async_event_t *);
void ibcm_async_handler(void *, ibt_hca_hdl_t,
/* Global variables */
/*
* Initial state is INIT. All hca dr's return success immediately in this
* state, without adding or deleting any hca's to CM.
*/
/* mutex and cv to manage hca's reference and resource count(s) */
/* mutex and cv to sa session open */
/* serialize sm notice callbacks */
/* mutex for CM's qp list management */
/*
* Flow control logic for open_rc_channel uses the following.
*/
struct ibcm_open_s {
} ibcm_open;
/*
* Flow control logic for SA access and close_rc_channel calls follows.
*/
typedef struct ibcm_flow1_s {
} ibcm_flow1_t;
typedef struct ibcm_flow_s {
/* statistics */
} ibcm_flow_t;
/* NONBLOCKING close requests are queued */
struct ibcm_close_s {
} ibcm_close;
NULL,
"IBCM"
};
/* IBCM's list of HCAs registered with it */
/* Array of CM state call table functions */
};
/* the following globals are CM tunables */
/*
* This delay accounts for time involved in various activities as follows :
*
* IBMF delays for posting the MADs in non-blocking mode
* IBMF delays for receiving the MADs and delivering to CM
* CM delays in processing the MADs before invoking client handlers,
* Any other delays associated with HCA driver in processing the MADs and
* other subsystems that CM may invoke (ex : SA, HCA driver)
*/
/* approx boot time */
/*
* The information in ibcm_clpinfo is kept in wireformat and is setup at
* init time, and used read-only after that
*/
char *event_str[] = {
"NEVER SEE THIS ",
"SESSION_ID ",
"CHAN_HDL ",
"LOCAL_COMID/HCA/PORT ",
"LOCAL_QPN ",
"REMOTE_COMID/HCA ",
"REMOTE_QPN ",
"BASE_TIME ",
"INCOMING_REQ ",
"INCOMING_REP ",
"INCOMING_RTU ",
"INCOMING_COMEST ",
"INCOMING_MRA ",
"INCOMING_REJ ",
"INCOMING_LAP ",
"INCOMING_APR ",
"INCOMING_DREQ ",
"INCOMING_DREP ",
"OUTGOING_REQ ",
"OUTGOING_REP ",
"OUTGOING_RTU ",
"OUTGOING_LAP ",
"OUTGOING_APR ",
"OUTGOING_MRA ",
"OUTGOING_REJ ",
"OUTGOING_DREQ ",
"OUTGOING_DREP ",
"REQ_POST_COMPLETE ",
"REP_POST_COMPLETE ",
"RTU_POST_COMPLETE ",
"MRA_POST_COMPLETE ",
"REJ_POST_COMPLETE ",
"LAP_POST_COMPLETE ",
"APR_POST_COMPLETE ",
"DREQ_POST_COMPLETE ",
"DREP_POST_COMPLETE ",
"TIMEOUT_REP ",
"CALLED_REQ_RCVD_EVENT ",
"RET_REQ_RCVD_EVENT ",
"CALLED_REP_RCVD_EVENT ",
"RET_REP_RCVD_EVENT ",
"CALLED_CONN_EST_EVENT ",
"RET_CONN_EST_EVENT ",
"CALLED_CONN_FAIL_EVENT ",
"RET_CONN_FAIL_EVENT ",
"CALLED_CONN_CLOSE_EVENT ",
"RET_CONN_CLOSE_EVENT ",
"INIT_INIT ",
"INIT_INIT_FAIL ",
"INIT_RTR ",
"INIT_RTR_FAIL ",
"RTR_RTS ",
"RTR_RTS_FAIL ",
"RTS_RTS ",
"RTS_RTS_FAIL ",
"TO_ERROR ",
"ERROR_FAIL ",
"SET_ALT ",
"SET_ALT_FAIL ",
"STALE_DETECT ",
"OUTGOING_REQ_RETRY ",
"OUTGOING_REP_RETRY ",
"OUTGOING_LAP_RETRY ",
"OUTGOING_MRA_RETRY ",
"OUTGOING_DREQ_RETRY ",
"NEVER SEE THIS "
};
#ifdef DEBUG
int ibcm_test_mode = 0; /* set to 1, if running tests */
#endif
/* Module Driver Info */
"IB Communication Manager"
};
/* Module Linkage */
};
int
_init(void)
{
int rval;
if (status != IBCM_SUCCESS) {
return (EINVAL);
}
if (rval != 0) {
rval);
(void) ibcm_fini();
}
return (rval);
}
int
{
}
int
_fini(void)
{
int status;
if (ibcm_fini() != IBCM_SUCCESS)
return (EBUSY);
status);
return (status);
}
return (status);
}
/* Initializes all global mutex and CV in cm module */
static void
{
/* Verify CM MAD sizes */
#ifdef DEBUG
if (ibcm_test_mode > 1) {
sizeof (ibcm_req_msg_t));
sizeof (ibcm_rep_msg_t));
sizeof (ibcm_rtu_msg_t));
sizeof (ibcm_mra_msg_t));
sizeof (ibcm_rej_msg_t));
sizeof (ibcm_lap_msg_t));
sizeof (ibcm_apr_msg_t));
sizeof (ibcm_dreq_msg_t));
sizeof (ibcm_drep_msg_t));
sizeof (ibcm_sidr_req_msg_t));
sizeof (ibcm_sidr_rep_msg_t));
}
#endif
/* Create all global locks within cm module */
sizeof (ibcm_svc_info_t),
}
/* Destroys all global mutex and CV in cm module */
static void
{
/* Destroy all global locks within cm module */
}
/* Initialize CM's classport info */
static void
{
/* For now, CM supports same capabilities at all ports */
/* Bits 0-7 are all 0 for Communication Mgmt Class */
/* For now, CM has the same respvalue at all ports */
/* For now, redirect fields are set to 0 */
/* Trap fields are not applicable to CM, hence set to 0 */
}
/*
* ibcm_init():
* - call ibt_attach()
* - create AVL trees
* - Attach HCA handlers that are already present before
* CM got loaded.
*
* Arguments: NONE
*
* Return values:
* IBCM_SUCCESS - success
*/
static ibcm_status_t
ibcm_init(void)
{
kthread_t *t;
if (ibcm_init_ids() != IBCM_SUCCESS) {
"fatal error: vmem_create() failed");
return (IBCM_FAILURE);
}
if (ibcm_ar_init() != IBCM_SUCCESS) {
"fatal error: ibcm_ar_init() failed");
return (IBCM_FAILURE);
}
/* Start the timeout list processing thread */
ibcm_timeout_thread_did = t->t_did;
/*
* NOTE : if ibt_attach is done after ibcm_init_hcas, then some
* HCA DR events may be lost. CM could call re-init hca list
* again, but it is more complicated. Some HCA's DR's lost may
* be HCA detach, which makes hca list re-syncing and locking more
* complex
*/
if (status != IBT_SUCCESS) {
status);
(void) ibcm_ar_fini();
return (IBCM_FAILURE);
}
/*
* This callback will be used by IBTL to get the Node record for a
* given LID via the speccified HCA and port.
*/
/* Unblock any waiting HCA DR asyncs in CM */
return (IBCM_SUCCESS);
}
/* Allocates and initializes the "per hca" global data in CM */
static void
{
int i;
/* Get the number of HCAs */
"returned %d hcas", num_hcas);
for (i = 0; i < num_hcas; i++)
if (num_hcas)
}
/*
* ibcm_fini():
* - Deregister w/ ibt
* - Cleanup IBCM HCA listp
* - Destroy mutexes
*
* Arguments: NONE
*
* Return values:
* IBCM_SUCCESS - success
*/
static ibcm_status_t
ibcm_fini(void)
{
/*
* CM assumes that the all general clients got rid of all the
* established connections and service registrations, completed all
* pending SIDR operations before a call to ibcm_fini()
*/
if (ibcm_ar_fini() != IBCM_SUCCESS) {
return (IBCM_FAILURE);
}
/* cleanup the svcinfo list */
"ibcm_svc_avl_tree is not empty");
return (IBCM_FAILURE);
}
if (ibcm_fini_hcas() != IBCM_SUCCESS) {
"some hca's still have client resources");
/* First, re-initialize the hcas */
/* and then enable the HCA asyncs */
if (ibcm_ar_init() != IBCM_SUCCESS) {
}
return (IBCM_FAILURE);
}
/* Release any pending asyncs on ibcm_global_hca_lock */
/*
* Detach from IBTL. Waits until all pending asyncs are complete.
*/
/* if detach fails, CM didn't free up some resources, so assert */
if (status != IBT_SUCCESS)
status);
return (IBCM_SUCCESS);
}
/* This routine exit's the ibcm timeout thread */
static void
{
/* Stop the timeout list processing thread */
/* Wake up, if the timeout thread is on a cv_wait */
}
/* Attempts to release all the hca's associated with CM */
static ibcm_status_t
{
return (IBCM_FAILURE);
}
}
return (IBCM_SUCCESS);
}
/*
* ibcm_hca_attach():
* Called as an asynchronous event to notify CM of an attach of HCA.
* Here ibcm_hca_info_t is initialized and all fields are
* filled in along with SA Access handles and IBMA handles.
* Also called from ibcm_init to initialize ibcm_hca_info_t's for each
* hca's
*
* Arguments: (WILL CHANGE BASED ON ASYNC EVENT CODE)
* hca_guid - HCA's guid
*
* Return values: NONE
*/
static void
{
int i;
if (status != IBT_SUCCESS) {
"ibt_query_hca_byguid failed = %d", status);
return;
}
return;
return;
}
/* Store the static hca attribute data */
/* loop thru nports and initialize IBMF handles */
for (i = 0; i < hcap->hca_num_ports; i++) {
if (status != IBT_SUCCESS) {
"port_num %d state DOWN", i + 1);
}
"ibcm_hca_init_port failed %d port_num %d",
status, i+1);
}
/* create the "active" CM AVL tree */
sizeof (ibcm_state_data_t),
/* create the "passive" CM AVL tree */
sizeof (ibcm_state_data_t),
/* create the "passive comid" CM AVL tree */
sizeof (ibcm_state_data_t),
/*
* Mark the state of the HCA to "attach" only at the end
* Now CM starts accepting incoming MADs and client API calls
*/
}
/*
* ibcm_hca_detach():
* Called as an asynchronous event to notify CM of a detach of HCA.
* Here ibcm_hca_info_t is freed up and all fields that
* were initialized earlier are cleaned up
*
* Arguments: (WILL CHANGE BASED ON ASYNC EVENT CODE)
* hca_guid - HCA's guid
*
* Return values:
* IBCM_SUCCESS - able to detach HCA
* IBCM_FAILURE - failed to detach HCA
*/
static ibcm_status_t
{
int port_index, i;
/*
* Declare hca is going away to all CM clients. Wait until the
* access count becomes zero.
*/
/* wait on response CV */
absolute_time = ddi_get_lbolt() +
while (hcap->hca_acc_cnt > 0)
absolute_time) == -1)
break;
if (hcap->hca_acc_cnt != 0) {
/* We got a timeout */
" to timeout on hca_acc_cnt %u, \n Some CM Clients are "
"still active, looks like we need to wait some more time "
return (IBCM_FAILURE);
}
/*
* First make sure, there are no active users of ibma handles,
* and then de-register handles.
*/
/* make sure that there are no "Service"s registered w/ this HCA. */
if (hcap->hca_svc_cnt != 0) {
return (IBCM_FAILURE);
}
"There are active SIDR operations");
return (IBCM_FAILURE);
}
"There are active RC connections");
return (IBCM_FAILURE);
}
/*
* Now, wait until all rc and sidr stateps go away
* All these stateps must be short lived ones, waiting to be cleaned
* up after some timeout value, based on the current state.
*/
while (hcap->hca_res_cnt > 0)
/* Re-assert the while loop step above */
/*
* Unregister all ports from IBMA
* If there is a failure, re-initialize any free'd ibma handles. This
* is required to receive the incoming mads
*/
IBCM_SUCCESS) {
"Failed to free IBMA Handle for port_num %d",
port_index + 1);
break;
}
}
/* If detach fails, re-initialize ibma handles for incoming mads */
if (status != IBCM_SUCCESS) {
for (i = 0; i < port_index; i++) {
"Failed to re-allocate IBMA Handles for"
}
return (IBCM_FAILURE);
}
return (IBCM_SUCCESS);
}
/* Checks, if there are any active sidr state entries in the specified hca */
static ibcm_status_t
{
"usp = %p not in transient state = %d", usp,
return (IBCM_FAILURE);
} else {
}
}
return (IBCM_SUCCESS);
}
/* Checks, if there are any active rc state entries, in the specified hca */
static ibcm_status_t
{
/*
* Both the trees ie., active and passive must reference to all
* statep's, so let's use one
*/
"sp = %p not in transient state = %d", sp,
return (IBCM_FAILURE);
} else {
}
}
return (IBCM_SUCCESS);
}
/* Adds a new entry into CM's global hca list, if hca_guid is not there yet */
static ibcm_hca_info_t *
{
hcaguid);
/*
* Check if this hca_guid already in the list
* If yes, then ignore this and return NULL
*/
/* search for this HCA */
/* already exists */
"hcap %p guid 0x%llX, entry already exists !!",
return (NULL);
}
}
/* Allocate storage for the new HCA entry found */
/* initialize RW lock */
/* initialize SIDR list lock */
/* Insert "hcap" into the global HCA list maintained by CM */
return (hcap);
}
/* deletes the given ibcm_hca_info_t from CM's global hca list */
void
{
/* ibcm_hca_global_lock is held */
"deleting hcap %p hcaguid %llX", hcap,
if (prevp) {
} else {
}
sizeof (ibcm_port_info_t));
return;
}
}
}
/*
* ibcm_find_hca_entry:
* Given a HCA's GUID find out ibcm_hca_info_t entry for that HCA
* If entry exists and in HCA ATTACH state, then hca's ref cnt is
* incremented and entry returned. Else NULL returned.
*
* All functions that use ibcm_find_hca_entry and get a non-NULL
* return values must call ibcm_dec_hca_acc_cnt to decrement the
* respective hca ref cnt. There shouldn't be any usage of
* ibcm_hca_info_t * returned from ibcm_find_hca_entry,
* after decrementing the hca_acc_cnt
*
* INPUTS:
* hca_guid - HCA's guid
*
* RETURN VALUE:
* hcap - if a match is found, else NULL
*/
{
/* search for this HCA */
break;
}
/* if no hcap for the hca_guid, return NULL */
return (NULL);
}
/* return hcap, only if it valid to use */
++(hcap->hca_acc_cnt);
"found hcap = 0x%p hca_acc_cnt %u", hcap,
hcap->hca_acc_cnt);
return (hcap);
} else {
"found hcap = 0x%p not in active state", hcap);
return (NULL);
}
}
/*
* Searches for ibcm_hca_info_t entry based on hca_guid, but doesn't increment
* the hca's reference count. This function is used, where the calling context
* is attempting to delete hcap itself and hence acc_cnt cannot be incremented
* OR assumes that valid hcap must be available in ibcm's global hca list.
*/
{
/* search for this HCA */
break;
}
" hca_guid 0x%llX", hca_guid);
else
" hca_guid 0x%llX", hca_guid);
return (hcap);
}
/* increment the hca's temporary reference count */
{
++(hcap->hca_acc_cnt);
return (IBCM_SUCCESS);
} else {
"hcap INACTIVE 0x%p acc_cnt = %d ", hcap,
hcap->hca_acc_cnt);
return (IBCM_FAILURE);
}
}
/* decrement the hca's ref count, and wake up any waiting threads */
void
{
--(hcap->hca_acc_cnt);
(hcap->hca_acc_cnt == 0)) {
"cv_broadcast for hcap = 0x%p", hcap);
}
}
/* increment the hca's resource count */
void
{
++(hcap->hca_res_cnt);
}
/* decrement the hca's resource count, and wake up any waiting threads */
void
{
--(hcap->hca_res_cnt);
(hcap->hca_res_cnt == 0)) {
"cv_broadcast for hcap = 0x%p", hcap);
}
}
/* increment the hca's service count */
void
{
++(hcap->hca_svc_cnt);
}
/* decrement the hca's service count */
void
{
--(hcap->hca_svc_cnt);
}
/*
* The following code manages three classes of requests that CM makes to
* The main issue is that the fabric can become very busy, and the CM
* protocols rely on responses being made based on a predefined timeout
* value. By managing how many simultaneous sessions are allowed, there
* is observed extremely high reliability of CM protocol succeeding when
* it should.
*
* thread blocks until there are less than some number of threads doing
* similar requests.
*
* allowing the thread to return immediately to its caller in the
* case where the "mode" is IBT_NONBLOCKING. This is the mode used
*/
static int
{
}
void
{
int run;
} else {
/*
* If we remove what tail pointed to, we need
* to reassign tail (it is never NULL).
* tail points to head for the empty list.
*/
}
run = 0;
}
if (run)
}
}
/* dtrace */
void
{
if (delta > 1000000)
}
void
{
statep);
}
void
{
int run;
} else {
if (run)
}
}
ibcm_open_dequeue(void)
{
/*
* If we remove what tail pointed to, we need
* to reassign tail (it is never NULL).
* tail points to head for the empty list.
*/
return (statep);
}
void
ibcm_check_for_opens(void)
{
if (ibcm_ok_to_start(&ibcm_open)) {
statep = ibcm_open_dequeue();
} else {
break;
}
}
}
static void
{
/* stats */
}
static void
{
ibcm_open.exit_deferred = 0;
ibcm_open.in_progress = 0;
}
static void
{
}
static ibcm_flow1_t *
{
ibcm_flow1_t *f;
if (f) { /* most likely code path */
f = f->link;
return (f);
}
/* There was no flow1 list element ready for another waiter */
if (f) {
f = f->link;
return (f);
}
} else {
}
return (flow1);
}
static void
{
} else {
} else
}
}
static void
{
}
}
}
void
ibcm_flow_inc(void)
{
}
}
static void
{
if (delta > 4000000LL) {
}
}
void
{
int flow_exit = 0;
int run = 0;
if (ibcm_dtrace)
if (ibcm_open.exit_deferred) {
flow_exit = 1;
}
}
if (flow_exit)
if (run)
}
void
{
}
void
{
}
}
void
ibcm_close_enter(void)
{
}
void
ibcm_close_exit(void)
{
int flow_exit;
flow_exit = 1;
else {
flow_exit = 0;
}
if (flow_exit)
}
/*
* This function needs to be called twice to finish our flow
* control accounting when closing down a connection. One
* call has send_done set to 1, while the other has it set to 0.
* Because of retries, this could get called more than once
* with either 0 or 1, but additional calls have no effect.
*/
void
{
int flow_exit;
if (send_done)
else
statep->close_flow = 0;
flow_exit = 1;
else {
flow_exit = 0;
}
if (flow_exit)
}
}
void
ibcm_lapr_enter(void)
{
}
void
ibcm_lapr_exit(void)
{
}
void
{
}
void
{
}
static void
void *callback_arg)
{
switch (saa_event_code) {
break;
break;
break;
break;
return; /* no change */
}
else
break;
default:
return;
}
/* don't send the event if we're tearing down */
return;
}
}
void
{
int num_failed_sgids;
if (sm_notice_handler == NULL) {
return;
}
/* for each port, if service is not available, make a call */
num_failed_sgids = 0;
if (!(portp->port_event_status &
portp++;
}
}
if (num_failed_sgids != 0) {
if (!(portp->port_event_status &
portp++;
}
}
}
if (num_failed_sgids != 0) {
}
}
/* The following is run from a taskq because we've seen the stack overflow. */
static void
{
int status;
"ibmf_sa_session_open failed for port guid %llX "
} else {
"registered sa_hdl 0x%p for port guid %llX",
}
}
void
{
return;
if (portp->port_saa_open_in_progress) {
return;
}
if (saa_handle != NULL) {
return;
}
/* The assumption is that we're getting event notifications */
if (ibt_status != IBT_SUCCESS) {
"ibt_get_port_state_byguid failed for guid %llX "
return;
}
/* if the port is UP, try sa_session_open */
}
{
return (NULL);
while (portp->port_saa_open_in_progress) {
}
if (saa_handle != NULL) {
return (saa_handle);
}
if (ibt_status != IBT_SUCCESS) {
"ibt_get_port_state_byguid failed for guid %llX "
return (NULL);
}
/* if the port is UP, try sa_session_open */
while (portp->port_saa_open_in_progress) {
}
return (saa_handle);
}
/*
* ibcm_hca_init_port():
* - Register port with IBMA
*
* Arguments:
* hcap - HCA's guid
* port_index - port number minus 1
*
* Return values:
* IBCM_SUCCESS - success
*/
{
int status;
/* Register with IBMF */
/*
* register with management framework
*/
if (status != IBMF_SUCCESS) {
"ibmf_register failed for port_num %x, "
return (ibcm_ibmf_analyze_error(status));
}
/*
* Register the read callback with IBMF.
* Since we just did an ibmf_register, handle is
* valid and ibcm_recv_cb() is valid so we can
* safely assert for success of ibmf_setup_recv_cb()
*
* Depending on the "state" of the HCA,
* CM may drop incoming packets
*/
"IBMF hdl[%x] = 0x%p", port_index,
/* Attempt to get the saa_handle for this port */
}
return (IBT_SUCCESS);
}
/*
* useful, to re attempt to initialize port ibma handles from elsewhere in
* cm code
*/
{
return (status);
}
/*
* ibcm_hca_fini_port():
* - Deregister port with IBMA
*
* Arguments:
* hcap - HCA's guid
* port_index - port number minus 1
*
* Return values:
* IBCM_SUCCESS - success
*/
static ibcm_status_t
{
int ibmf_status;
"ibmf_sa_session_close IBMF SAA hdl %p",
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_sa_session_close of port %d returned %x",
return (IBCM_FAILURE);
}
}
"ibmf_unregister IBMF Hdl %p",
/* clean-up all the ibmf qp's allocated on this port */
if (ibcm_status != IBCM_SUCCESS) {
"ibcm_free_allqps failed for port_num %d",
port_index + 1);
return (IBCM_FAILURE);
}
/* Tear down the receive callback */
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_tear_down_async_cb failed %d port_num %d",
return (IBCM_FAILURE);
}
/* Now, unregister with IBMF */
"ibmf_unregister of port_num %x returned %x",
if (ibmf_status == IBMF_SUCCESS)
else {
"ibmf_unregister failed %d port_num %d",
return (IBCM_FAILURE);
}
}
return (IBCM_SUCCESS);
}
/*
* ibcm_comm_est_handler():
* Check if the given channel is in ESTABLISHED state or not
*
* Arguments:
* eventp - A pointer to an ibt_async_event_t struct
*
* Return values: NONE
*/
static void
{
/* Both QP and EEC handles can't be NULL */
"both QP and EEC handles are NULL");
return;
}
return;
}
if (timer_val) {
} else
/* CM doesn't have RTU message here */
} else {
"Channel already in ESTABLISHED state");
} else {
/* An unexpected behavior from remote */
}
}
}
/*
* ibcm_async_handler():
* CM's Async Handler
* (Handles ATTACH, DETACH, COM_EST events)
*
* Arguments:
* eventp - A pointer to an ibt_async_event_t struct
*
* Return values: None
*
* NOTE : CM assumes that all HCA DR events are delivered sequentially
* i.e., until ibcm_async_handler completes for a given HCA DR, framework
* shall not invoke ibcm_async_handler with another DR event for the same
* HCA
*/
/* ARGSUSED */
void
{
"clnt_hdl = %p, code = 0x%x, eventp = 0x%p",
/* If fini is going to complete successfully, then return */
if (ibcm_finit_state != IBCM_FINIT_IDLE) {
/*
* This finit state implies one of the following:
* Init either didn't start or didn't complete OR
* Fini is about to return SUCCESS and release the global lock.
* In all these cases, it is safe to ignore the async.
*/
"as either init didn't complete or fini about to succeed",
code);
return;
}
switch (code) {
case IBT_PORT_CHANGE_EVENT:
break;
/* FALLTHROUGH */
case IBT_CLNT_REREG_EVENT:
case IBT_EVENT_PORT_UP:
(void) taskq_dispatch(ibcm_taskq,
return;
case IBT_HCA_ATTACH_EVENT:
/* eventp->ev_hcaguid is the HCA GUID of interest */
break;
case IBT_HCA_DETACH_EVENT:
/* eventp->ev_hca_guid is the HCA GUID of interest */
NULL) {
break;
}
(void) ibcm_hca_detach(hcap);
break;
case IBT_EVENT_COM_EST_QP:
/* eventp->ev_qp_hdl is the ibt_qp_hdl_t of interest */
case IBT_EVENT_COM_EST_EEC:
/* eventp->ev_eec_hdl is the ibt_eec_hdl_t of interest */
break;
default:
break;
}
}