ibcm_sm.c revision 015f8fff605f2fbd5fd0072e555576297804d57b
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* These routines implement the CM state machine (both ACTIVE and PASSIVE)
*
* Points to Note :
*
* o CM uses one ibcm_hca_info_t entry per HCA to store all the
* connection state data belonging to that HCA in the AVL trees, etc.,
*
* o There is one state structure per RC, referenced from three AVL trees
* ie. the HCA active AVL tree, and the HCA passive AVL tree and HCA
* passive comid tree
*
* o SIDR state structures are stored in a linked list
*
* o The term statep generally refers to RC, until explicitly mentioned
* in the notes below
*
* o Any thread that may access statep increments the ref_cnt. This ensures
* that statep is not deleted when it is still being accessed and modified
* by other threads
*
* o Any thread that may want to search the AVL tree(s) holds the hca state
* the lock held is writer lock.
*
* o Incrementing and Decrementing the ref_cnt can happen only after acquiring
* statep mutex
*
* o Deleting a statep can happen only by acquiring the hca state writer lock
* and statep mutex and if ref_cnt is zero.
*
* o Statep mutexes are used to decrease the hca state table lock holding
* times. thus increasing more number of threads that can access hca
* global data structures
*
* o Statep mutexes cannot be hold for long time. They are primarily used to
* check the state of statep, change it and exit the lock. Other threads
* checking this statep find statep's new state, and may exit without
* further processing (as the statep->state has changed).
*
* o Statep mutex must be held while setting and unsetting the timer id
* values and during untimeout
*
* Re-stating, the overall purpose of these various locks are:
* - Minimize the time state table locks are held
* so multiple readers can traverse data structures in parallel
* - Minimize the time statep mutex held, so other threads entering the same
* statep mutex are not held for long
*
* The CM state machine logic ensures that the statep is valid and exists
* when timeout callback (ibcm_timeout_cb) is called. This is ensured by
* cancelling timeouts on state changes, where appropriate
*
*
* The timeout processing is handled in the context in which the
* timeout callback is invoked.
*
* The CM STATE MACHINE logic flow:
*
* On an incoming MAD:-
*
* IBMF -> ibcm_process_incoming_mad
* Verify and branch to one of the below connection state routines.
* The callback arg from ibmf has the pointer to ibcm_hca_info_t
*
* 1. INCOMING REQ MAD
*
* Acquire hca state table WRITER lock
* Do lookup in passive AVL tree by remote qpn and remote hca guid
*
* If (new lookup)
*
* create new statep, initialize key fields
* obtain new local com id, insert into hca state AVL tree
* release hca state table WRITER lock
*
* Initialize remaining fields
* If invalid service id,
* send a REJ reply,
* decr ref_cnt holding state mutex
* If existing peer conn, check guids, and break the tie
* Call the cep state transition function
* Check and handle for any incoming REJ's during REQ RCVD state
*
* else if (existing lookup)
*
* increment refcnt holding state mutex
* release hca state table WRITER lock
*
* re-acquire the statep mutex
* resend the mad
* else if established
* handle the stale detection
* else
* drop the mad (no processing required)
* decr statep->ref_cnt, release state mutex
*
*
* 2. INCOMING REP MAD
*
* Acquire hca state READER lock
* Do lookup in hca state tree by local com id
* Release hca state table READER lock
*
* if lookup does not exist
* return
*
* if look up exists
* incr statep->ref_cnt holding state mutex
*
* acquire the statep lock
* if (state == ESTABLISHED or REJ SENt or MRA REP SENT)
* resend the MAD
* release state mutex, cancel req sent timer
* decrement ref_cnt holding the statep lock
* return
*
* if (state == REQ_SENT or REP_WAIT)
* first, change state to REP_RCVD
* release statep lock
* cancel timers
* lookup in the passive tree by remote qpn and remote hca guid
* if entry already exists
* handle the stale detection
* else
* add to the passive tree
*
* Initialize fields of statep
* Call the qp state transition function
* Acquire the state mutex
* decrement the ref cnt
* release the statep lock
*
* 3. INCOMING MRA
*
* Acquire hca state table READER lock
* Do lookup in active hca state tree by local com id
* Release hca state table READER lock
*
* If lookup does not exist
* return
*
* if look up exists
* incr statep->ref_cnt holding state mutex
*
* acquire state mutex
* if (state is REQ_SENT or REP_SENT)
* change state to REP WAIT or MRA REP RCVD
* release state mutex
* cancel the current timer
*
* reacquire state mutex
* if (state is REP_WAIT or MRA_REP_RCVD)
* set new timer, using service timeout for the first timeout
* decr ref cnt, release state mutex
*
* 4. INCOMING RTU
*
* Acquire hca state table READER lock
* Do lookup in active hca state tree by local com id
* Release hca state table READER lock
*
* If lookup does not exist
* return
*
* if look up exists
* incr statep->ref_cnt holding state mutex
*
* acquire statep mutex
* if (state == REP_SENT or MRA REP RCVD))
* change state to ESTABLISHED
* release statep mutex
* cancel timer
*
* Change QP state
*
* acquire the statep mutex
* decrement the ref count
* release statep mutex
*
* 5. INCOMING REJ
*
* Acquire hca state table READER lock
* Do lookup in active hca state tree by local com id
* Release hca state table READER lock
*
* If lookup does not exist
* return
*
* if look up exists
* incr statep->ref_cnt holding state mutex
*
* if (state == REQ RCVD or REP RCVD MRA_SENT or MRA_REP_SNET)
* set statep->delete = true
* decrement the ref_cnt
* release statep mutex;
*
* else if (state == REQ_SENT or REP SENT or MRA REP Rcvd)
* state = IBCM_STATE_DELETE
* Cancel running timers
* decrement the ref_cnt
* release state mutex
* Call the client QP handler
* delete the state data
*
* 6. INCOMING DREQ
*
* Acquire hca state table READER lock
* Do lookup in active hca state tree by local com id
* Release hca state table READER lock
*
* If lookup does not exist
* return
*
* if look up exists
* incr statep->ref_cnt holding state mutex
*
* acquire state mutex
* if (state is ESTABLISHED/DREQ SENT/TIMEWAIT)
* if state is ESTABLISHED/DREQ SENT,
* change state to DREQ RECVD
* start timers
*
* send DREP reply
* decr ref_cnt
* release state mutex
*
* 7. Incoming DREP
*
* Acquire hca state table READER lock
* Do lookup in active hca state tree by local com id
* Release hca state table READER lock
*
* If lookup does not exist
* return
*
* if look up exists
* incr statep->ref_cnt holding state mutex
*
* acquire state mutex
* if state is DREQ_SENT
* change state to DREP_RCVD
* cancel timer
* change state to TIMEWAIT
* set timewait timer
* decr ref_cnt
* release state mutex
*
* 8. Timeout handler
*
*
* acquire the statep mutex
*
* if (set state != stored_state)
* The thread that changed the state is responsible for any cleanup
* decrement ref cnt
* release statep mutex
* return
* else if (statep's state == REJ SENT)
* change state to DELETE
* decrement ref cnt
* release statep mutex
* delete statep
* return
* else if (state == TIME WAIT)
* do the time wait state processing
* decrement ref cnt
* change state to DELETE
* release statep mutex
* delete statep, and also QP
* else if (remaining retry cnt > 0)
* resend the mad
* decrement ref cnt
* release statep mutex
* else if (state == rep sent or req sent or mra rep rcvd or rep wait)
* (retry counter expired)
* change state to REJ SENT (No one shall delete in REJ SENT)
* decrement the ref_cnt
* release the statep mutex
* Post REJ MAD
* cv_signal anyone blocking
* Invoke client handler
* else if state == DREQ_SENT
* change state to TIME WAIT
* decrement the ref cnt
* set a timer for time wait time
* release the statep mutex
*
*
* SIDR processing
*
* 9. INCOMING SIDR_REQ MAD
*
* Do lookup in SIDR LIST based on LID, GID, grh_exists and req_id
* increment ud_statep->ud_ref_cnt
*
* If (new lookup)
*
* validate service id, and the create new statep,
* initialize key fields
* do a lookup based on service id
* if service_id_lookup returns exists
* set sidr_status to QPN_VALID
* else
* set sidr_status to SID_INVALID
* post SIDR_REP mad
* decr ud_statep->ud_ref_cnt, release ud_state_mutex
*
* else if (existing lookup)
*
* if (ud_statep->ud_state is SIDR_REP_SENT)
* resend the mad
*
* decr ud_statep->ud_ref_cnt, release ud_state_mutex
*
*
* 10. INCOMING SIDR_REP MAD
*
* Do lookup in SIDR LIST based on LID, GID, grh_exists and req_id
* increment ud_statep->ud_ref_cnt
*
* if look up doesn't exists
* return
*
* if (state == SIDR_REQ_SENT)
* first, change state to SIDR_REP_RCVD
* release statep lock
* cancel timers
* cv_signal anyone blocking
* release the statep lock
* extract return args
* destroy the statep
*
* 11. Timeout handler
*
* (for states SIDR_REQ_SENT/SIDR_REP_SENT)
*
* acquire the statep mutex
*
* if (statep's state == SIDR_REP_SENT SENT)
* change state to DELETE
* decrement ref cnt
* release statep mutex
* delete statep
* return
* else if (remaining retry cnt > 0 and state is SIDR_REQ_SENT)
* resend the mad
* decrement ref cnt
* release statep mutex
* else if (state == SIDR_REQ_SENT)
* (retry counter expired)
* change state to DELETE
* decrement the ref_cnt
* the statep mutex
* cv_signal anyone blocking
* Invoke client handler
* delete statep
*/
/* Function prototypes */
static void ibcm_set_primary_adds_vect(ibcm_state_data_t *,
ibt_adds_vect_t *, ibcm_req_msg_t *);
static void ibcm_set_alt_adds_vect(ibcm_state_data_t *,
ibt_adds_vect_t *, ibcm_req_msg_t *);
ibt_cep_path_t *, ibcm_req_msg_t *);
ibt_cep_path_t *, ibcm_req_msg_t *);
ibcm_req_msg_t *, ibcm_rep_msg_t *);
ib_time_t, ibcm_rep_msg_t *);
static void ibcm_sidr_rep_ud_handler(ibcm_ud_state_data_t *,
static void ibcm_handler_conn_fail(ibcm_state_data_t *,
static void ibcm_post_drep_mad(ibcm_state_data_t *);
static void ibcm_ud_timeout_client_cb(
/* limit the number of taskq threads to handle received MADs. */
int ibcm_recv_tasks = 0;
int ibcm_max_recv_tasks = 24;
int ibcm_recv_timeouts = 0;
/*
* Tunable MAX MRA Service Timeout value in MicroSECONDS.
* 0 - Tunable parameter not used.
*
* Ex: 60000000 - Max MRA Service Delay is 60 Seconds.
*/
#ifdef DEBUG
static void print_modify_qp(char *prefix,
#endif
/* Warlock annotations */
/*
* ibcm_process_incoming_mad:
* The CM callback that is invoked by IBMF, when a valid CM MAD arrives
* on any of the registered ibmf handles by CM.
*
* It is assumed that the incoming MAD (except for incoming REQ) belongs
* to a connection on the HCA, on which the MAD is received.
* The IBMF callback arg specifies ibcm_hca_info_t
*
* NOTE: IBMF always invokes ibcm_recv_cb() in a taskq. CM does some memory
* allocations and invoke ibcm_sm_funcs_tbl[i]() in the same taskq.
*
* INPUTS:
* ibmf_handle - IBMF Handle
* args - from IBMF. Is a ptr to ibcm_hca_info_t
* status - Callback status. Is mostly IBMF_SUCCESS
* madbuf - IBMF allocated MAD buffer (CM should free it)
* madaddr - IBMF MAD's address
* grhvalid - If GRH is valid or not
*
* RETURN VALUES: NONE
*/
void
void *args)
{
int ibmf_status;
/* Noticed that IBMF always calls with IBMF_SUCCESS, but still check */
/* IBMF allocates Input MAD, so free it here */
"ibmf_free_msg failed %d", ibmf_status);
return;
}
/* Get the HCA entry pointer */
#ifdef DEBUG
if (ibcm_test_mode > 1)
#endif
/* Increment hca ref cnt, if HCA is in attached state, else fail */
"hca not in attach state");
/* IBMF allocates Input MAD, and ibcm free's it */
"ibmf_free_msg failed %d", ibmf_status);
return;
}
/* allocate memory for internal MAD address buffer */
/* initialize cm_mad_addr field(s) */
"ibmf_free_msg failed %d", ibmf_status);
return;
}
"CM recv GID GUID %llX sender GID GUID %llX",
}
/* Save IBMF handle and ibmf qp related information */
/* IBMF does not initialize ia_p_key for non-QP1's */
else
"arrived from limited PKEY %x",
/* Retrieve the method and Attr-Id from generic mad header */
"unsupported ibcm class version %x",
"ibmf_free_msg failed %d", ibmf_status);
return;
}
#ifdef DEBUG
#endif
/*
* The following are valid combination of Method type
* and attribute id in the received MAD :-
* o ClassPortInfo with Get method
* o CM messages with Send method
*/
if ((attr_id == MAD_ATTR_ID_CLASSPORTINFO) &&
((method == MAD_METHOD_GET) ||
(method == MAD_METHOD_GET_RESPONSE))) {
if (method == MAD_METHOD_GET)
else if (method == MAD_METHOD_GET_RESPONSE)
} else if ((attr_id >= IBCM_ATTR_BASE_ID) &&
(method == MAD_METHOD_SEND)) {
/* Call the CM process connection state function */
} else {
/*
* Any other combination of method and attribute are invalid,
* hence drop the MAD
*/
}
/* decrement the hcap access reference count */
/* ASSERT(NO_LOCKS_HELD); */
/* free up ibmf msgp */
"ibmf_free_msg failed %d", ibmf_status);
}
/*
* Structure to carry the arguments from ibcm_recv_cb() to
* ibcm_recv_incoming_mad() via taskq_dispatch
*/
typedef struct ibcm_taskq_args_s {
void *tq_args;
#define IBCM_RECV_MAX 128
int ibcm_recv_total;
int ibcm_recv_queued;
static int
{
return (0);
if (++ibcm_get >= IBCM_RECV_MAX)
ibcm_get = 0;
return (1);
}
static int
{
int next;
if (next >= IBCM_RECV_MAX)
next = 0;
return (1);
} else {
return (0);
}
}
void
{
int ibmf_status;
"ibmf_free_msg failed %d", ibmf_status);
}
/*
* Processing done in taskq thread.
*
* Calls ibcm_process_incoming_mad with all function arguments extracted
* from args. Afterwards, check for queued requests.
*/
static void
ibcm_recv_task(void *args)
{
" via taskq");
/* process queued entries before giving up this thread */
}
}
static void
ibcm_recv_timeout_cb(void *args)
{
int rv = 1;
if (ibcm_recv_tasks == 0) {
TQ_NOQUEUE | TQ_NOSLEEP) == 0) {
if (--ibcm_recv_tasks == 0) {
} else {
}
}
} else {
/*
* one or more taskq threads are running now
* so just try to enqueue this one.
*/
}
if (rv == 0)
}
/*
* Dispatch to taskq if we're not using many, else just queue it
* and have the taskq thread pick it up. Return 0 if we're dropping it.
*/
static int
{
int rv;
return (rv);
} else {
ibcm_recv_tasks++; /* dispatch this one to a taskq thread */
if (--ibcm_recv_tasks > 0)
else /* don't enqueue if no threads are running */
rv = 0;
return (rv);
}
if (--ibcm_recv_tasks == 0) {
/* try the dispatch again, after a tick */
} else {
}
return (rv);
} else {
return (1);
}
}
}
/*
* ibcm_recv_cb:
* The CM callback that is invoked by IBMF, when a valid CM MAD arrives
* on any of the registered ibmf handles by CM.
*
* INPUTS:
* ibmf_handle - IBMF Handle
* msgp - IBMF msg containing the MAD (allocated by IBMF)
* args - Ptr to ibcm_hca_info_t
*
* RETURN VALUES: NONE
*/
void
{
}
/*
* ibcm_process_req_msg:
* PASSIVE SIDE CM
* Called from ibcm_process_incoming_mad on reception of a REQ message
*
* Description:
* If it a new REQ (not duplicate)
* creates a new state structure in passive connection mode
* populate state structure fields
* inserts state structure in hca active and passive trees
* validates service id
* calls QP state transition function
* stores the response MAD in state structure for future re-sends
* initializes timers as required
* If a duplicate REQ, action depends upon current state in the state
* structure
*
* INPUTS:
* hcap - HCA entry ptr
* input_madp - CM MAD that is input to this function
* cm_mad_addr - Address information for the MAD
*
* RETURN VALUE:
* NONE
*/
void
{
/*
* Lookup for an existing state structure or create a new state struct
* If there is no entry, the lookup function also allocates a new
* state structure and inserts in the table, initializes remote qpn
* and hca guid from REQ
*/
/* allocate the local_comid before proceeding */
return;
}
/* allocate ibcm_state_data_t before grabbing the WRITER lock */
/* NOTE that only a writer lock is held here */
if (state_lookup_status == IBCM_LOOKUP_NEW) {
/* seeing the REQ request for the first time */
/* Release the state table lock */
" created", statep);
/* if ibmf msg allocation fails, delete the statep */
/* HCA res cnt decremented via ibcm_delete_state_data */
return;
}
/* Allocate dreq_msg buf to be used during teardown. */
"statep 0x%p: Failed to allocate dreq_msg", statep);
/* HCA res cnt decremented via ibcm_delete_state_data */
return;
}
/* initialize some "statep" fields */
/*
* get the remote_ack_delay, etc.
*/
/*
* get the req_max_cm_retries
*/
/* Approximate pkt life time for now */
/* Passive side timer is set to LocalCMRespTime in REQ */
"active cep timeout(usec) = %u",
/*
* Initialize the stale clock. Any other REQ
* messages on this statep are considered as duplicate
* if they arrive within stale clock
* ibcm_adj_btime is used to offset for retry REQ's
* arriving just after expected retry clock
*/
/* Increment the hca's resource count */
"statep 0x%p cm_qp_entry alloc failed", statep);
/*
* Not much choice. CM MADs cannot go on QP1, not even
* REJ. Hence delete state data and go away silently.
* The remote will timeout after repeated attempts
*/
return;
}
if (comid_lookup_status == IBCM_LOOKUP_EXISTS) {
"dup comid %x stale_statep 0x%p statep 0x%p",
/* Send a REJ with duplicate com id */
IBT_CM_FAILURE_REQ, NULL, 0);
/*
* Don't free the ibmf msg, if stale_statep is not in
* ESTABLISHED state, because probability is very less.
* ibmf msg shall be deleted along with statep
*/
/*
* if stale_statep is in established state, process
* stale connection handling on stale_statep
*/
/* Cancel pending ibt_set_alt_path */
/* The above call releases the state mutex */
(void) ibcm_alloc_out_msg(stale_statep->
/*
* Spec says, post DREQ MAD on the stale
* channel. This moves channel into timewait
*/
} else {
/* Set it back to original state. */
}
}
return;
}
/* If unknown service type, just post a REJ */
0x3;
(trans != IBT_RD_SRV)) {
"statep 0x%p invalid transport type %x", statep,
trans);
/* Send a REJ with invalid transport type */
IBT_CM_FAILURE_REQ, NULL, 0);
return;
}
/* Validate the gids, lids and service id */
req_msgp);
if (svc_gid_check == IBCM_FAILURE) {
"gid or sid invalid for statep 0x%p", statep);
/* REJ posted from ibcm_verify_req_gids_and_svcid */
return;
}
/* Call the QP state transition processing function */
/* If defer, return holding the statep ref cnt */
if (response == IBCM_DEFER) {
"statep %0xp client returned DEFER response",
statep);
return;
}
/* statep ref cnt decremented in the func below */
return;
} else {
}
if (state_lookup_status == IBCM_LOOKUP_EXISTS) {
/*
* There is an existing state structure entry
* with the same active comid
* states
* Any other state implies the active has already received
* out of the fabric, hence no resend is required
*/
/* decrementing ref cnt and returning from below */
"statep 0x%p being retired, REMOTE_QPN %x",
statep, remote_qpn);
/*
* OK, this is reuse of the QPN on the active side
* that was not connected last time. This REQ is
* considered NEW. We delete the statep here,
* then start over from the top.
*/
if (timer_val)
goto new_req;
/*
* The statep is stale in the following cases :-
* 1) if incoming REQ's comid's doesn't match with what is
* stored in statep
* 2) incoming REQ's local comid matches with statep's
* remote comid, but the REQ is for a new connection.
* This is verified that by comparing the current time
* with stale clock in statep
*/
} else {
/* This is a stale connection on passive side */
"stale detected statep %p state %x",
"cur_time 0x%llX stale_clock 0x%llX", cur_time,
/* Cancel pending ibt_set_alt_path */
/* The above call releases the state mutex */
(void) ibcm_alloc_out_msg(
/*
* Spec says, post DREQ MAD on the stale
* channel. This moves channel into timewait
*/
else {
}
} else {
/*
* If not in established state, the CM
* protocol would timeout and delete the
* statep that is stale, eventually
*/
}
/* Post a REJ MAD to the incoming REQ's sender */
}
}
}
/*
* ibcm_handle_cep_req_response:
* Processes the response from ibcm_cep_state_req. Called holding a
* statep ref cnt. The statep ref cnt is decremented before returning.
*/
void
{
if (response == IBCM_SEND_REP)
else {
}
}
/*
* ibcm_process_rep_msg:
* ACTIVE SIDE CM
* Called from ibcm_process_incoming_mad on reception of a REP message
*
* INPUTS:
* hcap - HCA entry pointer
* input_madp - CM MAD that is input to this function
* cm_mad_addr - Address information for the MAD
*
* RETURN VALUE: NONE
*/
void
{
/* Lookup for an existing state structure */
/* lookup message holding a reader lock */
if (lookup_status == IBCM_LOOKUP_FAIL) {
return;
}
/* if transaction id is not as expected, drop the REP mad */
"An REP MAD with tid expected 0x%llX tid found 0x%llX ",
return;
}
/* grab mutex first */
/*
* There is a state structure entry with active comid
* First, handle the re-send cases
* The resend routines below release the state mutex
*/
/* change state */
/* cancel the REQ timer */
} else {
}
/* Initialize the remote destination QPN for further MADs */
sizeof (ib_guid_t));
"passive cid = %x passive qpn = %x", statep,
/* Handle stale connection detection on active side */
&stale_qpn);
/*
* Check for other side reusing QPN that was attempted
* to be used, but somehow we sent a REJ.
*/
if ((stale_lookup_status == IBCM_LOOKUP_EXISTS) &&
"statep 0x%p being retired, REMOTE_QPN %x",
/*
* OK, this is reuse of the QPN on the active side
* that was not connected last time. This REQ is
* considered NEW. We delete the statep here,
* then start over from the top.
*/
if (timer_val)
/* OK to continue now */
} else
/*
* lookup exists implies that there is already an entry with
*/
if ((stale_lookup_status == IBCM_LOOKUP_EXISTS) ||
"statep 0x%p stale detected "
"qpn_lkup %d comid_lkup %d", statep,
/* Disassociate statep and QP */
else
/* Send a REJ with stale reason for statep */
IBT_CM_FAILURE_REP, NULL, 0);
/* Now let's handle the logic for stale connections */
/* If in established state, stale_statep is stale */
if (stale_lookup_status == IBCM_LOOKUP_EXISTS) {
"state_qpn 0x%p stale QPN detected "
/* change state to DREQ sent */
/* above call releases state mutex */
(void) ibcm_alloc_out_msg(
&stale_qpn->state_mutex);
} else {
&stale_qpn->state_mutex);
}
}
}
if (stale_comid_lookup_status == IBCM_LOOKUP_EXISTS) {
"state_comid 0x%p stale COMID detected "
"state %X", stale_comid,
stale_comid->state);
if (!((stale_lookup_status ==
(stale_qpn == stale_comid)) &&
(stale_comid->state ==
/* change state to DREQ sent */
stale_comid->state =
/* above call releases state mutex */
(void) ibcm_alloc_out_msg(
} else {
stale_comid->state =
}
}
}
return;
}
/*
* No need to handle out of memory conditions as we called
* ibcm_lookup_msg() with IBT_CHAN_BLOCKING flags.
*/
/* Initialize the remote ack delay */
" passive hca_ack_delay= %x ", statep,
if (response == IBCM_DEFER) {
"statep 0x%p client returned DEFER response",
statep);
return;
}
return;
} else {
#ifdef DEBUG
if (ibcm_test_mode > 0)
"REP re-send from passive for statep 0x%p"
else
"Unexpected REP for statep 0x%p in "
#endif
}
/* decrement ref count and return for LOOKUP_EXISTS */
}
/*
* ibcm_handle_cep_req_response:
* Processes the response from ibcm_cep_state_rep. Called holding a
* statep ref cnt. The statep ref cnt is decremented before returning.
*/
void
{
/* wait until the send completion callback is invoked for REQ post */
if (response == IBCM_SEND_RTU) {
/* if connection aborted, return */
return;
}
/*
* Call client handler with cm event IBT_CM_EVENT_CONN_EST to
* indicate RTU posted
*/
} else {
}
}
/*
* ibcm_return_open_data:
* Initializes the ibt_open_rc_channel return data. The statep ref cnt is
* decremented before returning.
*/
static void
{
/* signal waiting CV - blocking in ibt_open_channel() */
/* decrement ref count and return for LOOKUP_EXISTS */
}
/*
* ibcm_process_mra_msg:
* Called from ibcm_process_incoming_mad on reception of a MRA message
*
* Cancels existing timer, and sets a new timer based on timeout
* value from MRA message. The remaining retry count of statep is
* not changed, and timer value for the remaining retry timers is
* also not changed
*
* INPUTS:
* hcap - HCA entry pointer
* input_madp - CM MAD that is input to this function
* cm_mad_addr - Address information for the MAD
*
* RETURN VALUE: NONE
*/
void
{
/* Lookup for an existing state structure (as a READER) */
/* if state doesn't exist just return */
if (state_lookup_status != IBCM_LOOKUP_EXISTS) {
return;
}
"MRA MAD with tid expected 0x%llX tid found 0x%llX "
"com id 0x%x arrived", statep,
return;
}
/*
* (to validate MRA message received)?
*/
if ((mra_msg != IBT_CM_MRA_TYPE_REQ) &&
(mra_msg != IBT_CM_MRA_TYPE_REP) &&
(mra_msg != IBT_CM_MRA_TYPE_LAP)) {
return;
}
} else { /* statep->state == IBCM_STATE_LAP_SENT */
}
/* cancel the timer */
/*
* If tunable MAX MRA Service Timeout parameter is set, then
* verify whether the requested timer value exceeds the MAX
* value and reset the timer value to the MAX value.
*/
if (ibcm_mra_service_timeout_max &&
"Unexpected MRA Service Timeout value (%ld), Max "
"allowed is (%ld)", service_timeout,
}
/*
* Invoke client handler to pass the MRA private data
*/
/* Client cannot return private data */
}
/*
* Must re-check state, as an RTU could have come
* after the above mutex_exit and mutex_enter below
*/
/*
* The timeout interval is changed only for the first
* retry. The later retries use the timeout from
* statep->timer_value
*/
}
} else {
#ifdef DEBUG
if (ibcm_test_mode > 0)
"Unexpected mra for statep 0x%p in state %d",
#endif
}
}
/*
* ibcm_process_rtu_msg:
* Called from ibcm_process_incoming_mad on reception of a RTU message
*
* Changes connection state to established if in REP SENT state
*
* INPUTS:
* hcap - HCA entry pointer
* input_madp - CM MAD that is input to this function
* cm_mad_addr - Address information for the MAD
*
* RETURN VALUE: NONE
*/
void
{
/* Lookup for an existing state structure - using a reader lock */
/* if state doesn't exist just return */
if (status != IBCM_LOOKUP_EXISTS) {
return;
}
"An RTU MAD with tid expected 0x%llX tid found 0x%llX "
"com id 0x%x arrived", statep,
return;
}
/* transient until ibt_modify_qp succeeds to RTS */
} else {
#ifdef DEBUG
if ((ibcm_test_mode > 0) &&
"Unexpected rtu for statep 0x%p in state %d",
#endif
}
}
/*
* ibcm_process_rej_msg:
* Called from ibcm_process_incoming_mad on reception of a REJ message.
*
* INPUTS:
* hcap - HCA entry pointer
* input_madp - CM MAD that is input to this function
* cm_mad_addr - Address information for the MAD
*
* RETURN VALUE: NONE
*/
/* ARGSUSED */
void
{
/* Lookup for an existing state structure */
sizeof (ib_guid_t));
"hca guid in REJ's ARI = %llX", remote_hca_guid);
} else
/* if state doesn't exist just return */
if (state_lookup_status != IBCM_LOOKUP_EXISTS) {
"local com id %x remote com id %x reason %d",
/* Do NOT respond with invalid comid REJ */
return;
}
statep);
if (ibcm_enable_trace & 2)
if (timer_val != 0) {
} else {
}
/*
* Call the QP state transition processing function
* NOTE: Input MAD is the REJ received, there is no output MAD
*/
/* signal waiting CV - blocking in ibt_open_channel() */
min(
} else {
}
/* Now delete the statep */
"REJ in established state", statep);
/* wait until client is informed CONN EST event */
/*
* Call the QP state transition processing function
* NOTE: Input MAD is the REJ received, there is no output MAD
*/
/*
* Start the timewait state timer, as connection is in
* established state
*/
/*
* For passive side CM set it to remote_ack_delay
* For active side CM add the pkt_life_time * 2
*/
/* statep->mode == IBCM_ACTIVE_MODE) */
statep->remaining_retry_cnt = 0;
} else {
#ifdef DEBUG
if ((ibcm_test_mode > 0) &&
"Unexpected rej for statep 0x%p in state %d",
#endif
}
}
/*
* ibcm_process_dreq_msg:
*
* INPUTS:
* hcap - HCA entry pointer
* input_madp - CM MAD that is input to this function
* cm_mad_addr - Address information for the MAD
*
* RETURN VALUE: NONE
*/
/*ARGSUSED*/
void
{
/* Lookup for an existing state structure */
if (state_lookup_status != IBCM_LOOKUP_EXISTS) {
/* implies a bogus message */
return;
}
/*
* Local QPN check is necessary. There could be a DREQ from
* a remote stale connection processing with the same com id, but
* not intended for this statep
*/
"statep->local_qpn = %x qpn in dreq = %x"
"statep->remote_comid = %x local comid in dreq = %x",
return;
}
/*
* If another thread is processing a copy of this same DREQ,
* bail out here.
*/
return;
}
case IBCM_STATE_ESTABLISHED:
case IBCM_STATE_DREQ_SENT:
case IBCM_STATE_TIMEWAIT:
break;
default:
/* All other states ignore DREQ */
return;
}
/*
* If drep msg wasn't really required, it shall be deleted finally
* when statep goes away
*/
"statep 0x%p ibcm_alloc_out_msg failed", statep);
statep->drep_in_progress = 0;
return;
}
}
statep->drep_in_progress = 0;
return;
}
/*
* Need to generate drep, as time wait can be reached either by an
* outgoing dreq or an incoming dreq
*/
ibcm_close_done(statep, 0);
if (timer_val != 0) {
/* Cancel the timer set for DREP reception */
}
} else { /* In ESTABLISHED State */
/* The above function releases the state mutex */
/* wait until client knows CONN EST event */
&statep->state_mutex);
/* Move CEP to error state */
(void) ibcm_cep_to_error_state(statep);
}
statep->drep_in_progress = 0;
priv_data = &(((ibcm_drep_msg_t *)
if (statep->close_ret_status)
}
/*
* if close_nocb_state is IBCM_FAIL, then cm_handler is NULL
* if close_nocb_state is IBCM_BLOCK, client cannot go away
*/
if (cb_status == IBT_CM_DEFER) {
" statep 0x%p client returned DEFER "
"response", statep);
return;
}
}
/* Signal for cm proceed api */
/* Signal for close with no callbacks */
/* Signal any waiting close channel thread */
statep->drep_in_progress = 0;
return;
}
/* Release statep mutex before posting the MAD */
/* ref cnt decremented in ibcm_post_drep_complete */
} else {
#ifdef DEBUG
if ((ibcm_test_mode > 0) &&
"Unexpected dreq for statep 0x%p in state %d",
#endif
statep->drep_in_progress = 0;
}
}
/*
* ibcm_handle_cep_dreq_response:
* Processes the response from client handler for an incoming DREQ.
* The statep ref cnt is decremented before returning.
*/
void
{
&(((ibcm_drep_msg_t *)
}
/*
* ibcm_post_dreq_mad:
* Posts a DREQ MAD
* Post DREQ now for TIMEWAIT state and DREQ_RCVD
*
* INPUTS:
* statep - state pointer
*
* RETURN VALUE:
* NONE
*/
void
ibcm_post_dreq_mad(void *vstatep)
{
/* Fill in the DREQ message */
/* wait until client knows CONN EST event */
(void) ibcm_cep_to_error_state(statep);
0));
/* post the first DREQ via timeout callback */
/* client cannot specify more than 16 retries */
}
}
/*
* ibcm_post_drep_mad:
* Posts a DREP MAD
* Post DREP now for TIMEWAIT state and DREQ_RCVD
*
* INPUTS:
* statep - state pointer
*
* RETURN VALUE:
* NONE
*/
static void
{
/* Fill up DREP fields */
/* Post the DREP MAD now. */
statep);
}
/*
* ibcm_process_drep_msg:
*
* INPUTS:
* hcap - HCA entry pointer
* input_madp - CM MAD that is input to this function
* cm_mad_addr - Address information for the MAD
*
* RETURN VALUE: NONE
*/
/* ARGSUSED */
void
{
/* Lookup for an existing state structure */
if (state_lookup_status != IBCM_LOOKUP_EXISTS) {
return;
}
/* if transaction id is not as expected, drop the DREP mad */
"DREP with tid expected 0x%llX tid found 0x%llX", statep,
return;
}
"statep 0x%p Unexpected DREP received for a stale "
"DREQ sent", statep);
/* allow free qp, if close channel with NOCALLBACKS didn't */
}
/* if close_nocb_state is IBCM_FAIL, then cm_handler is NULL */
event.cm_priv_data_len = 0;
} else {
}
}
/* copy the private to close channel, if specified */
(*statep->close_ret_priv_data_len > 0)) {
}
if (statep->close_ret_status)
/* signal waiting CV - blocking in ibt_close_channel() */
/* signal any blocked close channels with no callbacks */
/* Set the timer wait state timer */
ibcm_close_done(statep, 0);
statep->remaining_retry_cnt = 0;
/*
* For passive side CM set it to remote_ack_delay
* For active side CM add the pkt_life_time * 2
*/
}
/* start TIMEWAIT processing */
}
/* There is no processing required for other states */
}
/*
* Following are the routines used to resend various CM MADs as a response to
* incoming MADs
*/
void
{
/* don't care, if timer is running or not. Timer may be from LAP */
}
/* ref cnt is decremented in ibcm_post_rtu_complete */
}
void
{
/* It's a too fast of a REQ or REP */
if (timer_val == 0)
return;
if (ibcm_enable_trace & 2)
}
/* return, holding the state mutex */
}
void
{
/* REP timer that is set by ibcm_post_rep_mad */
if (timer_val != 0) {
/* Re-start REP timeout */
/* for nonblocking REP post */
}
}
/*
* else, timer is not yet set by ibcm_post_rep_mad. This is too fast
* of a REQ being re-transmitted.
*/
}
void
{
return;
/* Exit the statep mutex, before sending the MAD */
/* Always resend the response MAD to the original reply destination */
statep);
/* return, holding the state mutex */
}
/*
* ibcm_post_rej_mad:
* Posts a REJ MAD and starts timer
*
* INPUTS:
* statep - state pointer
* which_msg - which message is being MRAed
* reject_reason - Rejection reason See Section 12.6.7.2 rev1.0a IB Spec
* addl_rej_info - Additional rej Information
* arej_info_len - Additional rej Info length
*
* RETURN VALUE:
* NONE
* Notes
* There is no need to hold the statep->mutex and call ibcm_post_rej_mad
* REJ can be posted either in IBCM_STATE_REQ_RCVD or IBCM_STATE_REP_RCVD
* In these states, there is no timer active, and an incoming REJ shall
* not modify the state or cancel timers
* An incoming REJ doesn't affect statep in state = IBCM_STATE_REJ_SENT/BUSY
*/
void
{
/* Message printed if connection gets REJed */
/* Initialize rej_msg fields */
/* signal any waiting close channels with blocking or no callbacks */
if (ibcm_enable_trace & 2)
statep);
}
/*
* ibcm_build_n_post_rej_mad:
* Builds and posts a REJ MAD for "reject_reason"
* Doesn't set a timer, and doesn't need statep
*
* INPUTS:
* input_madp - Incoming MAD
* remote_comid - Local comid in the message being rejected
* cm_mad_addr - Address information for the MAD to be posted
*
* RETURN VALUE:
* NONE
*/
static void
{
MAD_METHOD_SEND) != IBT_SUCCESS) {
"ibcm_alloc_out_msg failed");
return;
}
/* Initialize rej_msg fields */
rej_msg->rej_local_comm_id = 0;
}
}
/* posts a REJ for an incoming REQ with unsupported class version */
static void
{
MAD_METHOD_SEND) != IBT_SUCCESS) {
"ibcm_alloc_out_msg failed");
return;
}
/* Initialize rej_msg fields */
rej_msg->rej_local_comm_id = 0;
}
}
/*
* ibcm_post_rep_mad:
* Posts a REP MAD and starts timer
*
* INPUTS:
* statep - state pointer
*
* RETURN VALUE:
* NONE
*/
void
{
/*
* All other REP fields, other that the 2 below, are filled in
* the ibcm_cep_state_req() function.
*/
/*
* Changing state and attempt to delete the mra msg must be done
* together holding the state_mutex
*/
/* Now, attempt to delete the mra_msg, if there is one allocated */
}
/* Now post a REJ MAD, rej reason consumer abort */
NULL, 0);
} else {
}
&mra_msg);
return;
statep);
}
/*
* ibcm_post_rtu_mad:
* From active side post RTU MAD
*
* INPUTS:
* statep - state pointer
*
* RETURN VALUE: NONE
*
* NOTE: No timer set after posting RTU
*/
{
/* Now, attempt to delete the mra_msg, if there is one allocated */
}
/* Now post a REJ MAD */
NULL, 0);
} else {
}
&mra_msg);
return (IBCM_FAILURE);
statep);
return (IBCM_SUCCESS);
}
/*
* ibcm_process_abort:
* Processes abort, if client requested abort connection attempt
*
* INPUTS:
* statep - pointer to ibcm_state_data_t is passed
*
* RETURN VALUES: None
*/
void
{
/* move CEP to error state, before calling client handler */
(void) ibcm_cep_to_error_state(statep);
/* Now disassociate the link between statep and qp */
else {
}
}
/*
* Unblock an ibt_open_rc_channel called in a blocking mode, though
* it is an unlikely scenario
*/
/* REJ came first, and then client aborted connection */
}
if (ibcm_enable_trace != 0)
}
/*
* ibcm_timeout_cb:
* Called when the timer expires
*
* INPUTS:
* arg - ibcm_state_data_t is passed
*
* RETURN VALUES: NONE
*/
void
ibcm_timeout_cb(void *arg)
{
/*
* The blocking operations are handled in a separate thread.
* All other non-blocking operations, including ibmf non-blocking
* posts are done from timeout context
*/
return;
}
/* Processing depends upon current state */
/* Deallocate the CM state structure */
return;
/* TIME_WAIT timer expired, so cleanup */
if (statep->recycle_arg) {
struct ibcm_taskq_recycle_arg_s *recycle_arg;
/* if possible, do not slow down calling recycle func */
return;
}
}
return;
} else if (statep->remaining_retry_cnt > 0) {
"attr-id= 0x%x, retries remaining = 0x%x", statep,
/*
* REP could be resent, either because of timeout or an
* incoming REQ. Any other MAD below can be resent, because
* of timeout only, hence send_mad_flag manipulation not
* required for those cases.
* If REP is already being retransmitted, then just set the
* timer and return. Else post REP in non-blocking mode
*/
return;
}
/*
* Set REP busy flag, so any incoming REQ's will not
* initiate new REP transmissions
*/
== 0);
}
/* Post REQ MAD in non-blocking mode */
if (stored_state == IBCM_STATE_REQ_SENT) {
/* Post REQ MAD in non-blocking mode */
} else if (stored_state == IBCM_STATE_REP_WAIT) {
/* Post REP MAD in non-blocking mode */
} else if (stored_state == IBCM_STATE_REP_SENT) {
/* Post REP MAD in non-blocking mode */
} else if (stored_state == IBCM_STATE_MRA_REP_RCVD) {
/* Post DREQ MAD in non-blocking mode */
} else if (stored_state == IBCM_STATE_DREQ_SENT) {
if (statep->remaining_retry_cnt ==
else {
statep->cm_retries++;
ibcm_close_done(statep, 0);
}
/* post LAP MAD in non-blocking mode */
} else if (stored_ap_state == IBCM_AP_STATE_LAP_SENT) {
/* post LAP MAD in non-blocking mode */
} else if (stored_ap_state == IBCM_AP_STATE_MRA_LAP_RCVD) {
}
return;
/*
* MAX retries reached, send a REJ to the remote,
* and close the connection
*/
"max retries done for statep 0x%p", statep);
(void) ibcm_cep_to_error_state(statep);
/* Disassociate statep from QP */
/*
* statep is in REJ SENT state, the only way to get deleted is
* the timeout callback that is set after posting REJ
* The thread processing is required where cm handler is
* specified
*/
/* Attach the statep to timeout list */
} else {
/*
* statep->open_return_data is set for blocking
* No handler specified, hence signal blocked
* ibt_open_rc_channel from here
*/
}
&local_hca_guid, sizeof (ib_guid_t));
}
"LAP timed out", statep);
/*
* This state setting ensures that the processing of DREQ is
* sequentialized, once this ap_state is set. If statep is
* attached to timeout list, it cannot be re-attached as long
* as in this state
*/
/* Attach statep to timeout list - thread handling */
/*
* statep->ap_return_data is initialized for blocking in
* ibt_set_alt_path(), signal the waiting CV
*/
}
/*
* The logic below is necessary, for a race situation between
* ibt_close_rc_channel with no callbacks option and CM's
* internal stale connection handling on the same connection
*/
}
/*
* If cm handler is specified, then invoke handler for
* the DREQ timeout
*/
return;
}
} else {
#ifdef DEBUG
if (ibcm_test_mode > 0)
"Unexpected unhandled timeout for statep 0x%p "
#endif
}
}
/*
* Following are set of ibmf send callback routines that are used when posting
* various CM MADs in non-blocking post mode
*/
/*ARGSUSED*/
void
{
/* signal any waiting threads for REQ MAD to become available */
}
/*ARGSUSED*/
void
void *args)
{
}
/*ARGSUSED*/
void
{
}
/*ARGSUSED*/
void
void *args)
{
/* No new timeout is set for resending a REP MAD for an incoming REQ */
}
/*ARGSUSED*/
void
void *args)
{
}
/*ARGSUSED*/
void
void *args)
{
&mra_msg);
}
}
/*ARGSUSED*/
void
{
}
/*ARGSUSED*/
void
{
}
/*ARGSUSED*/
void
void *args)
{
}
/*ARGSUSED*/
void
void *args)
{
statep->remaining_retry_cnt = 0;
}
}
/*ARGSUSED*/
void
void *args)
{
}
/*ARGSUSED*/
void
void *args)
{
/* As long as one APR mad in transit, no retransmits are allowed */
/* unblock any DREQ threads and close channels */
}
/*ARGSUSED*/
void
void *args)
{
ibcm_flow_dec(0, "APR_RESEND");
}
/*ARGSUSED*/
void
void *args)
{
/*
* For passive side CM set it to remote_ack_delay
* For active side CM add the pkt_life_time * 2
*/
statep->remaining_retry_cnt = 0;
}
}
/*ARGSUSED*/
void
void *args)
{
ibcm_flow_dec(0, "SIDR_REP");
}
/*ARGSUSED*/
void
void *args)
{
ibcm_flow_dec(0, "SIDR_REQ");
}
/*
* ibcm_process_dreq_timeout:
* Called when the timer expires on DREP
*
* INPUTS:
* arg - ibcm_state_data_t is passed
*
* RETURN VALUES: NONE
*/
void
{
/* Max retries reached, move to the time wait state */
ibcm_close_done(statep, 0);
/* Set the TIME_WAIT state timer value */
}
if (statep->close_ret_status)
/* signal waiting CVs - blocking in ibt_close_channel() */
*statep->close_ret_priv_data_len = 0;
/* unblock any close channel with no callbacks option */
}
/*
* ibcm_add_tlist:
* Adds the given RC statep to timeout list
*
* INPUTS:
* arg - ibcm_state_data_t is passed
*
* RETURN VALUES: NONE
*/
void
{
if (ibcm_timeout_list_hdr == NULL) {
} else {
}
"attached state = %p to timeout list", statep);
}
void
ibcm_run_tlist_thread(void)
{
}
/*
* ibcm_add_ud_tlist:
* Adds the given UD statep to timeout list
*
* INPUTS:
* arg - ibcm_ud_state_data_t is passed
*
* RETURN VALUES: NONE
*/
void
{
if (ibcm_ud_timeout_list_hdr == NULL) {
} else {
}
"attached state = %p to ud timeout list", ud_statep);
}
/*
* ibcm_process_tlist:
* Thread that processes all the RC and UD statep's from
* the appropriate lists
*
* INPUTS:
* NONE
*
* RETURN VALUES: NONE
*/
void
{
"ibcm_process_tlist");
for (;;) {
/* The thread needs to exit */
break;
}
/* First, handle pending RC statep's, followed by UD's */
if (ibcm_timeout_list_hdr != NULL) {
if (ibcm_timeout_list_hdr == NULL)
"scheduling state = %p", statep);
} else if (ibcm_ud_timeout_list_hdr != NULL) {
if (ibcm_ud_timeout_list_hdr == NULL)
"ud scheduling state = %p", ud_statep);
} else {
}
}
#ifndef __lock_lint
#endif
}
/*
* ibcm_timeout_client_cb:
* Called from timeout thread processing
* Primary purpose is to call client handler
*
* INPUTS:
* arg - ibcm_state_data_t is passed
*
* RETURN VALUES: NONE
*/
void
{
struct ibcm_taskq_recycle_arg_s *recycle_arg;
(void) ibcm_process_rc_recycle(recycle_arg);
return;
}
return;
}
/* Else, it must be in TIMEOUT state, do the necessary processing */
void *data;
event.cm_priv_data_len = 0;
/*
* cm handler cannot be non-NULL, as that check is
* already made in ibcm_timeout_cb
*/
return;
}
data = ((ibcm_rej_msg_t *)
} else {
(statep->timedout_state ==
}
/*
* Invoke the CM handler w/ event IBT_CM_EVENT_TIMEOUT
* This callback happens for only active non blocking or
* passive client
*/
/* signal the blocked ibt_open_rc_channel */
/*
* statep->open_return_data is set for blocking
* signal the blocked ibt_open_rc_channel
*/
}
sizeof (ib_guid_t));
/*
* statep->ap_return_data is initialized for blocking in
* ibt_set_alt_path(), signal the waiting CV
*/
}
} else {
"Unexpected else path statep %p state %d ap_state %d",
}
}
/*
* ibcm_ud_timeout_client_cb:
* Called from UD timeout thread processing
* Primary purpose is to call client handler
*
* INPUTS:
* arg - ibcm_ud_state_data_t is passed
*
* RETURN VALUES: NONE
*/
void
{
return;
} else
/* Fill in ibt_cm_ud_event_t */
/* Delete UD state data now, finally done with it */
}
/*
* ibcm_process_sidr_req_msg:
* This call processes an incoming SIDR REQ
*
* INPUTS:
* hcap - HCA entry pointer
* input_madp - Incoming CM SIDR REQ MAD
* cm_mad_addr - Address information for the MAD to be posted
*
* RETURN VALUE:
* NONE
*/
void
{
/* Figure out LID, GID, RequestId for svc_id lookup */
else
/*
* Lookup for an existing state structure
* - if lookup fails it creates a new ud_state struct
* No need to hold a lock across the call to ibcm_find_sidr_entry() as
* the list lock is held in that function to find the matching entry.
*/
if (state_lookup_status == IBCM_LOOKUP_NEW) {
/* Increment hca's resource count */
/*
* Allocate CM MAD for a response
* This MAD is deallocated on state structure delete
* and re-used for all outgoing MADs for this connection.
* If MAD allocation fails, delete the ud statep
*/
IBT_SUCCESS) {
return;
}
/* Lookup for service */
/*
* No need to hold the ud state mutex, as no other thread
* modifies ud statep in IBCM_STATE_SIDR_REQ_RCVD state
*/
/* find the "bind" entry that enables this port */
while (tmp_bindp) {
gid.gid_prefix ==
/* a really good match */
if (pkey ==
/* absolute best */
break;
/* port match => a good match */
}
}
}
}
}
/* Not much choice. CM MADs cannot go on QP1 */
return;
}
/*
* Don't have a record of Service ID in CM's
* So, send out Service ID not supported SIDR REP msg
*/
} else {
/* Call Client's UD handler */
}
if (cm_status == IBCM_DEFER) {
"ud_statep 0x%p client returned DEFER response",
return;
}
} else {
}
}
/*
* ibcm_process_sidr_rep_msg:
* This call processes an incoming SIDR REP
*
* INPUTS:
* hcap - HCA entry pointer
* input_madp - incoming CM SIDR REP MAD
* cm_mad_addr - Address information for the MAD to be posted
*
* RETURN VALUE:
* NONE
*/
void
{
else
/*
* Lookup for an existing state structure.
* No need to hold a lock as ibcm_find_sidr_entry() holds the
* list lock to find the matching entry.
*/
if (status != IBCM_LOOKUP_EXISTS) {
"No matching ud_statep for SIDR REP");
return;
}
"ud_statep 0x%p. A SIDR REP MAD with tid expected 0x%llX "
"tid found 0x%llX req_id %x arrived", ud_statep,
return;
}
/*
* We need to check service ID received against the one sent?
* If they don't match just return.
*/
"ud_statep -0x%p svcids do not match %llx %llx",
return;
}
ud_statep->ud_timerid = 0;
/* Cancel timer set after sending SIDR REQ */
/*
* Call Client's UD handler
*/
/*
* ud_statep->ud_return_data is initialized for blocking in
* ibt_ud_get_dqpn(). Initialize its fields and
* signal the blocking call in ibt_ud_get_dqpn().
*/
/* get rep_qpn and rep_status */
/* Copy the SIDR private data */
(len > 0)) {
len);
}
/* get status first */
}
}
/* Delete UD state data now, finally done with it */
} else {
}
}
/*
* ibcm_post_sidr_rep_mad:
* This call posts a SIDR REP MAD
*
* INPUTS:
* ud_statep - pointer to ibcm_ud_state_data_t
* status - Status information
*
* RETURN VALUE: NONE
*/
void
{
/*
* Initialize SIDR REP message. (Other fields were
* already filled up in ibcm_sidr_req_ud_handler()
*/
/* post the SIDR REP MAD */
/*
* Hold the statep lock, as a SIDR REQ may come in after setting state
* but before timeout. This can result in a dangling timeout ie.,
* the incoming SIDR REQ would be unable to cancel this timeout
*/
}
/*
* ibcm_sidr_timeout_cb:
* Called when the timer expires on SIDR request
*
* INPUTS:
* arg - ibcm_ud_state_data_t with all the info
*
* RETURN VALUE: NONE
*/
void
ibcm_sidr_timeout_cb(void *arg)
{
/* Processing depends upon current state */
/* Deallocate the CM state structure */
} else if ((ud_statep->ud_remaining_retry_cnt > 0) &&
"ud_statep = %p, retries remaining = 0x%x",
/* Post mad in non blocking mode */
/* This is on SIDR REQ Sender side processing */
/* set state to IBCM_STATE_DELETE */
/*
* retry counter expired, clean up
*
* IBT_CM_SREP_TIMEOUT.
*/
}
/* Invoke the client handler in a separate thread */
/* UD state data is delete in timeout thread */
return;
}
/* Delete UD state data now, finally done with it */
} else {
#ifdef DEBUG
if (ibcm_test_mode > 0)
"Nop timeout for ud_statep 0x%p in ud_state %d",
#endif
}
}
/*
* ibcm_resend_srep_mad:
* Called on a duplicate incoming SIDR REQ on server side
* Posts the stored MAD from ud state structure using ud_stored_reply_addr
* Cancels any running timer, and then re-starts the timer
* This routine must be called with state structure table lock held
*
* INPUTS:
* ud_statep - ibcm_ud_state_data_t
*
* RETURN VALUE: NONE
*/
void
{
return;
/* for nonblocking SIDR REP Post */
/* Cancel currently running timer */
if (ud_statep->ud_timerid != 0) {
ud_statep->ud_timerid = 0;
} else {
}
/* Always resend the response MAD to the original reply destination */
}
/*
* ibcm_build_reply_mad_addr:
* Forms the reply MAD address based on "incoming mad addr" that is
* supplied as an arg.
*
* Swaps the source and destination gids in ib_grh_t
*
* INPUTS:
* inp_mad_addr: Address information in the incoming MAD
* out_mad_addr: Derived address for the reply MAD
* The reply MAD address is derived based
* address information of incoming CM MAD
* RETURN VALUE: NONE
*/
void
{
/* Swap the GIDs in the GRH */
/* swap the SGID and DGID */
}
/*
* and pkey
*/
}
/*
* ibcm_post_rc_mad
* Posts a CM MAD associated with a RC statep
*
* INPUTS:
* statep : RC statep associated with the post
* msgp : CM MAD to be posted
* post_cb : non-NULL callback address implies non-blocking post
* args : Args to ibmf send callback
*
* RETURN VALUE: based on ibmf_send_mad
*/
void
{
args);
/* Call ibmf callback directly */
}
/*
* ibcm_post_ud_mad
* Posts a CM MAD associated with a UD statep
*
* INPUTS:
* ud_statep : UD statep associated with the post
* msgp : CM MAD to be posted
* post_cb : non-NULL callback address implies non-blocking post
* args : Args to ibmf send callback
*
* RETURN VALUE: based on ibmf_send_mad
*/
void
{
ud_post_cb, args);
/* Call ibmf callback directly */
}
/*
* ibcm_post_mad:
* Posts CM MAD using IBMF in blocking mode
*
* INPUTS:
* msgp : CM MAD to be posted
* cm_mad_addr : Address information for the MAD to be posted
* post_cb : non-NULL callback address implies non-blocking post
* args : Args to ibmf send callback
*
* RETURN VALUE: based on ibmf_send_mad
*/
{
int post_status;
"sl = %x, grh_exists = %x",
/* Copy local addressing info */
if (post_cb)
if (post_status != IBMF_SUCCESS) {
/* Analyze the reason for failure */
return (ibcm_ibmf_analyze_error(post_status));
}
return (IBT_SUCCESS);
}
/*
* ibcm_process_get_classport_info:
* Get classportinfo
*
* INPUTS:
* hcap - HCA entry pointer
* input_madp - Input MAD pointer
* cm_mad_addr - Address information for the MAD to be posted
*
* RETURN VALUE: NONE
*/
static void
{
"ibcm_alloc_out_msg failed");
return;
}
/* copy the transaction id from input get mad */
}
/*
* ibcm_decode_classport_info:
* Decode classportinfo
*
* INPUTS:
* hcap - HCA entry pointer
* cm_mad_addr - Address information for the MAD to be posted
* input_madp - Input MAD pointer
*
* RETURN VALUE: NONE
*/
static void
{
/* Print various fields of received classportinfo in debuf buf */
}
/*
* ibcm_handler_conn_fail:
* Helper function used to call client handler for Conn fail event
*
* INPUTS:
* statep: The connection state pointer
* rej_type: Message being rejected
* rej_reason: Reason why CM is sending the REJ message
* client_data: Private data returned by the client for REJ
* client_data_len: Length of above client's private data.
*
* RETURN VALUE: Client Handler's return status
*/
static void
{
/* Invoke CM handler w/ event passed as arg */
event.cm_priv_data_len = 0;
}
if (ibcm_enable_trace != 0)
}
/*
* QP State transition functions here
*
* The brief description of these functions :
* Validate QP related attributes in the messages
* Change QP state
* Set QP attributes (modify QP)
* Fill up the response MADs
*/
/*
* ibcm_set_primary_adds_vect:
* Helper function used to fill up ibt_adds_vect_t PRIMARY PATH
* (called from ibcm_cep_state_*() functions)
*
* INPUTS:
* statep : The connection state pointer
* adds_vectp : The ibt_adds_vect_t ptr that is being filled up
* msgp : CM REQ message that is the source of information
*
* RETURN VALUE: NONE
*/
static void
{
/* first setup the srvl, srate, dlid and dgid */
} else {
}
/* next copy off the GRH info if it exists */
} else {
}
}
/*
* ibcm_set_alt_adds_vect:
* Helper function used to fill up ibt_adds_vect_t ALTERNATE PATH
* (called from ibcm_cep_state_*() functions)
*
* INPUTS:
* statep : The connection state pointer
* adds_vectp : The ibt_adds_vect_t ptr that is being filled up
* msgp : CM REQ message that is the source of information
*
* RETURN VALUE: NONE
*/
static void
{
/* first setup the srvl, srate, dlid and dgid */
} else {
}
/* next copy off the GRH info if it exists */
} else {
}
}
/*
* ibcm_set_primary_cep_path:
* Helper function used to fill up ibt_cep_path_t PRIMARY PATH
* (called from ibcm_cep_state_*() functions)
*
* INPUTS:
* statep : The connection state pointer
* adds_vectp : The ibt_cep_path_t ptr that is being filled up
* msgp : CM REQ message that is the source of information
*
* RETURN VALUE: NONE
*/
static ibt_status_t
{
/* validate the PKEY in REQ for prim port */
if (status != IBT_SUCCESS) {
"statep 0x%p pkey %x prim_port %d ", statep,
"statep 0x%p Invalid PKEY on prim_port, status %d ",
return (status);
}
return (IBT_SUCCESS);
}
/*
* ibcm_set_alt_cep_path:
* Helper function used to fill up ibt_cep_path_t ALTERNATE PATH
* (called from ibcm_cep_state_*() functions)
*
* INPUTS:
* statep : The connection state pointer
* adds_vectp : The ibt_cep_path_t ptr that is being filled up
* msgp : CM REQ message that is the source of information
*
* RETURN VALUE: NONE
*/
static ibt_status_t
{
/* no alternate path specified */
return (IBT_SUCCESS);
}
/* validate the PKEY in REQ for alt port */
if (status != IBT_SUCCESS) {
"statep 0x%p pkey %x alt_port %d ", statep,
"statep 0x%p Invalid PKEY on alt_port, status %d ",
return (status);
}
return (IBT_SUCCESS);
}
/*
* ibcm_compare_prim_alt_paths:
* Helper function used to find if primary and alternate paths are
* identical
* (called from ibcm_cep_state_req)
*
* INPUTS:
* req: Pointer to ibt_cm_req_rcv_t, filled before invoking
* the function
*
* RETURN VALUE: NONE
*/
static boolean_t
{
return (B_TRUE);
}
return (B_FALSE);
}
/*
* ibcm_invoke_qp_modify:
* Helper function used to call ibt_modify_qp()
* called from ibcm_cep_state_req()/ibcm_cep_state_rep()
*
* Sets state to RTR as well.
*
*
* INPUTS:
* statep: The connection state pointer
* req_msgp: The CM REQ message
*
* RETURN VALUE:
* IBT_SUCCESS - call succeeded
*/
static ibt_status_t
{
/*
* If alternate path is present in REQ message then
* OR in IBT_CEP_SET_ALT_PATH, if APM supported on hca
*/
/* default value of rep_failover is ACCEPT */
else {
" Alt Path specified in REQ, but not supported");
}
}
/* If transport type is RD OR in IBC_CEP_SET_QKEY */
if (trans == IBT_RD_SRV) {
}
/* Start filling up ibt_qp_info_t. */
switch (trans) {
case IBT_RC_SRV:
/* Setting PSN on RQ */
/* RDMA resources taken from negotiated REP values */
} else { /* Passive side CM */
/* Setting PSN on SQ and RQ */
/* RDMA resources taken from negotiated REP values */
}
/* XXX, Oh!, ibtl doesn't have interface for setting this */
return (status);
return (status);
break;
case IBT_RD_SRV:
} else {
}
break;
case IBT_UC_SRV:
} else {
}
return (status);
return (status);
break;
default:
"unknown svc_type = %x", trans);
break;
}
/* Call modify_qp */
if (status == IBT_SUCCESS)
else
#ifdef DEBUG
}
#endif
return (status);
}
/*
* ibcm_verify_req_gids_and_svcid
* Validation of LIDs, GIDs and SVC ID
*
* INPUTS:
* statep - state pointer
* cm_req_msgp - REQ message pointer
*
* RETURN VALUE: IBCM_SUCCESS/IBCM_FAILURE
*
*/
{
/* Verify LID and GID of primary port */
"PRIM passive lid %x", statep,
/* Verify GID validity, if specified */
}
if (status != IBT_SUCCESS) {
"ibtl_cm_get_hca_port() primary port failed = %d", statep,
status);
/* we will search for an acceptable GID to this port */
} else if (port.hp_base_lid !=
"primary port lid invalid (%x, %x, %x)", statep,
} else {
"statep 0x%p prim_port_path_bits %d ",
/* Verify LID and GID of alternate port. Post REJ if invalid */
/* Need a bcopy, as alt port gid is unaligned in req message */
sizeof (ib_gid_t));
/* Verify GID validity, if specified */
"ibcm_verify_req_gids: ibtl_cm_get_hca_port"
" statep 0x%p alternate port failed = %d",
} else if (port.hp_base_lid !=
"ibcm_verify_req_gids: statep 0x%p "
"alternate port lid invalid (%x, %x, %x)",
} else { /* Alt LID and GID are valid */
"statep 0x%p alt_port_num %d "
"alt_rc_hca_guid 0x%llX", statep,
"statep 0x%p alt_port_path_bits %d ",
}
}
}
/*
* Note: When we return SUCCESS, the reader lock won't get dropped
* until after the cm_handler is called from ibcm_cep_state_req().
*/
"ibcm_find_svc_entry found svc_infop %p", svc_infop);
/*
* Send REJ with reject reason "invalid service id" for the
* the following cases :-
* Service id is invalid
*/
"statep 0x%p svc_id %llX svc_infop NULL", statep,
/* Send a REJ with invalid SID reason */
return (IBCM_FAILURE);
}
/* Send a REJ with invalid SID reason */
return (IBCM_FAILURE);
}
/*
* Check if ServiceID is in RDMA IP CM SID range, if yes, we parse
* the REQ's Private Data and verify for it's goodness.
*/
" RDMA CM IP REQ Priv Data is NULL");
/* Send a REJ with CONSUMER REJ */
IBT_CM_FAILURE_REQ, NULL, 0);
return (IBCM_FAILURE);
}
/* RDMA IP CM Layer Rejects this */
} else {
/*
* Validate whether ip_addr specified are non-NULL.
*
* NOTE:
* RDMA ULP which is servicing this SID, should validate
* REJ related to ibt_ari_ip_reason_t of
* IBT_ARI_IP_SRC_ADDR, IBT_ARI_IP_DST_ADDR and
* IBT_ARI_IP_UNKNOWN_ADDR.
*/
"ibcm_verify_req_gids_and_svcid: "
"Invalid NULL V4 SrcIp specified");
"ibcm_verify_req_gids_and_svcid: "
"Invalid NULL V4 DstIp specified");
}
"ibcm_verify_req_gids_and_svcid: "
"Invalid NULL V6 SrcIp specified");
} else if (IN6_IS_ADDR_UNSPECIFIED(
"ibcm_verify_req_gids_and_svcid: "
"Invalid NULL V6 DstIp specified");
}
}
/* TBD: IBT_ARI_IP_UNKNOWN_ADDR */
}
if (rdma_rej_mad == B_TRUE) {
sizeof (ibt_ari_ip_t));
/* Send a REJ with CONSUMER REJ */
sizeof (ibt_ari_con_t));
return (IBCM_FAILURE);
}
}
/* find the best "bind" entry that enables this port */
while (tmp_bindp) {
gid.gid_prefix ==
/* gid match => really good match */
/* absolute best match */
break;
/* port match => a good match */
}
}
}
"ibcm_verify_req_gids_and_svcid: statep 0x%p "
"no binding found", statep);
return (IBCM_FAILURE);
}
/* copy the GID in case we need it in REJ below */
if (reject_reason == IBT_CM_SUCCESS)
/*
* If the service id is valid, but gid in REQ is invalid,
* then send a REJ with invalid gid
* For Invalid primary gid, the ARI field is filled with
* with gid from svcinfo
* registered in ARI.
*/
if (reject_reason != IBT_CM_SUCCESS) {
switch (reject_reason) {
case IBT_CM_PRIM_GID :
case IBT_CM_ALT_GID :
break;
case IBT_CM_PRIM_LID :
case IBT_CM_ALT_LID :
break;
}
return (IBCM_FAILURE);
}
return (IBCM_SUCCESS);
}
/*
* ibcm_cep_state_req:
* QP state transition function called for an incoming REQ on passive side
* LIDs and GIDs should be maintained and validated by the client handler
*
* INPUTS:
* statep - state pointer
* cm_req_msgp - REQ message pointer
* reject_reason - Rejection reason See Section 12.6.7.2 rev1.0a IB Spec
* arej_info_len - Additional Rejection reason info length
*
* RETURN VALUE: IBCM_SEND_REP/IBCM_SEND_REJ
*/
{
/* client handler should be valid */
/* Fill in ibt_cm_event_t */
/* Account for CM and other software delays */
"Avail resp time %d (usec)", statep,
} else {
"REQ rem_resp_time < local sw delay 0x%x", statep,
}
/* Initialize req.req_prim_addr */
/* Initialize req.req_alternate_path if they exist */
/* Verify, alt path is not same as primary */
/* XXX New REJ code needed */
" Alt and prim paths are same", statep);
return (IBCM_SEND_REJ);
}
}
#ifdef NO_EEC_SUPPORT_YET
#endif
/* cm_req_msgp->req_private_data to event.cm_event.cm_priv_data */
/*
* Allocate priv_data of size IBT_MAX_PRIV_DATA_SZ
*/
/* Fill in the default values from REQ, that client can modify */
/* Invoke the client handler */
if (cb_status == IBT_CM_DEFER) {
/*
* unblock any blocked cm proceed api calls. Do not access
* statep after cv_signal
*/
return (IBCM_DEFER);
}
/* fail any blocked cm proceed api call - client bug */
status =
return (status);
}
/*
* ibcm_process_cep_req_cm_hdlr:
* Processes the response from client handler for an incoming REQ.
*/
{
#ifdef NO_EEC_SUPPORT_YET
#endif
if (cb_status == IBT_CM_DEFAULT)
/* verify status */
if (cb_status == IBT_CM_ACCEPT) {
} else if (cb_status == IBT_CM_REJECT) {
} else if (cb_status == IBT_CM_REDIRECT_PORT) {
} else if (cb_status == IBT_CM_REDIRECT) {
} else if (cb_status == IBT_CM_NO_CHANNEL) {
} else if (cb_status == IBT_CM_NO_RESOURCE) {
} else {
}
/* client handler gave CM ok */
if (cb_status == IBT_CM_ACCEPT) {
/*
* Check first if ret_args make sense. If not, bailout
* here rather than going along and panicing later.
*/
if (IBCM_INVALID_CHANNEL(channel)) {
"statep 0x%p server's QP handle is NULL", statep);
}
if ((*reject_reason == IBT_CM_SUCCESS) &&
(old_statep != NULL)) {
"statep 0x%p Channel being re-used on passive side",
statep);
}
if (old_statep != NULL)
if (*reject_reason != IBT_CM_SUCCESS) {
return (IBCM_SEND_REJ);
}
if (status != IBT_SUCCESS) {
return (IBCM_SEND_REJ);
}
"statep %p qp is not RC channel on server", statep);
NULL, 0);
return (IBCM_SEND_REJ);
}
"qp state != INIT on server");
NULL, 0);
return (IBCM_SEND_REJ);
}
/* Init to Init, if required */
"chan 0x%p chan port %d", channel,
"chan 0x%p d path port %d", channel,
if (status != IBT_SUCCESS) {
"ibcm_process_cep_req_cm_hdlr: "
"chan 0x%p ibt_modify_qp() = %d", channel,
status);
IBT_CM_CI_FAILURE, NULL, 0);
return (IBCM_SEND_REJ);
} else {
"ibcm_process_cep_req_cm_hdlr: "
"chan 0x%p ibt_modify_qp() = %d", channel,
status);
}
}
/* fill in the REP msg based on ret_args from client */
/* IBT_CM_FLOW_CONTROL is always set by default. */
/*
* Check out whether SRQ is associated with this channel.
* If yes, then set the appropriate bit.
*/
}
sizeof (ib_guid_t));
/* Transition QP from Init to RTR state */
IBT_SUCCESS) {
"statep 0x%p ibcm_invoke_qp_modify failed because "
"of invalid data", statep);
return (IBCM_SEND_REJ);
}
/*
* Link statep and channel, once CM determines it is
* post REP definitely.
*/
/*
* Fill up the REP fields from ret_args
* failover status, from ret_args
*
* Fill up local QPN and EECN from ret_args->channel
*/
/* fill in REP msg bytes Qkey, Starting PSN, 12-15, and 16-19 */
case IBT_RD_SRV:
break;
case IBT_RC_SRV:
break;
case IBT_UC_SRV:
break;
}
#ifdef NO_EEC_SUPPORT_YET
&eec_attrs);
if (status == IBT_SUCCESS) {
}
}
#endif
/* figure out Target ACK delay */
/* Copy PrivateData from priv_data */
if (clnt_info->priv_data_len != 0) {
}
return (IBCM_SEND_REP);
}
/* REJ message */
/* if priv_data_len != 0 use priv_data to copy back to rej_priv_data */
if (clnt_info->priv_data_len != 0) {
}
if (cb_status == IBT_CM_REDIRECT_PORT) {
} else if (cb_status == IBT_CM_REDIRECT) {
*arej_len = sizeof (ibcm_classportinfo_msg_t);
} else if (cb_status == IBT_CM_REJECT) {
/* Fill up the REJ fields, from ret_args */
/*
* RDMA IP REQ was passed up to the ULP, the ULP decided to do
* a "normal" consumer REJ, by the returning IBT_CM_REJECT in
* the cm handler.
* CM has to do some extra stuff too, it has to
* a) return REJ code 28 (consumer) and b) put 0x1 in the first
* byte of the ARI data, to indicate that this is a RDMA aware
* ULP that is doing a consumer reject. The ULP should have
* put its consumer specific data into ibt_arej_info_t(9s) at
* byte 1 of the rej_ari[] array.
*/
}
}
return (IBCM_SEND_REJ);
}
/*
* ibcm_cep_state_rep:
* QP state transition function called for an incoming REP on active side
*
* INPUTS:
* statep - state pointer
* cm_rep_msg - REP message pointer
* reject_reason - Rejection reason See Section 12.6.7.2 rev1.0a IB Spec
*
* RETURN VALUE:
*/
{
/* Check first if client handler is valid */
/* initialize fields in ibt_cm_event_t */
"rep_service_time %d", statep,
/*
* Allocate priv_data of size IBT_MAX_PRIV_DATA_SZ
*/
/* invoke the CM handler */
if (cb_status == IBT_CM_DEFER) {
/* unblock any blocked cm proceed api calls */
return (IBCM_DEFER);
}
}
/* fail any blocked cm proceed api calls - client bug */
rval =
return (rval);
}
/*
* ibcm_process_cep_rep_cm_hdlr:
* Processes the response from client handler for an incoming REP.
*/
{
if (cb_status == IBT_CM_DEFAULT)
if (cb_status == IBT_CM_REJECT) {
} else if (cb_status == IBT_CM_REDIRECT_PORT) {
} else if (cb_status == IBT_CM_REDIRECT) {
} else if (cb_status == IBT_CM_NO_RESOURCE) {
} else if (cb_status != IBT_CM_ACCEPT) {
"0x%p, Client handler returned unexpected value %d",
} else
/* We come here if status is ACCEPT or CM handler is NULL */
if (cb_status == IBT_CM_ACCEPT) {
" passive hca_ack_delay(ib_time) = 0x%x, ", statep,
" rnr_retry_cnt = 0x%x", statep,
/* Call IBTL CM's qp modify function from Init to RTR */
cm_rep_msgp) != IBT_SUCCESS) {
"statep %p, ibcm_invoke_qp_modify to RTR failed",
statep);
/*
* Call modify qp function from RTR to RTS
* RDMA initiator depth on active is same as negotiated
* passive REP's responder resources
*/
!= IBT_SUCCESS) {
"statep %p ibcm_invoke_rtu_qp_modify to RTS failed",
statep);
(void) ibcm_cep_to_error_state(statep);
}
if (*reject_reason == IBT_CM_NO_RESC) {
/* Disassociate statep and QP */
return (IBCM_SEND_REJ); /* send REJ */
}
if (clnt_info->priv_data_len != 0) {
rtu_msgp = (ibcm_rtu_msg_t *)
}
return (rval);
}
/* Fill up the REJ fields, from ret_args */
/* if priv_len != 0 use priv_data to copy back to rej_priv_data */
if (clnt_info->priv_data_len != 0)
*arej_len =
if (*arej_len != 0) /* asserts that clnt_info->reply_event != 0 */
/* Disassociate statep and QP */
/* callback client, to enable client to do resource cleanup */
return (rval);
}
/*
* ibcm_invoke_rtu_qp_modify:
* Helper function to modify QP for RTU only called from
* ibcm_cep_state_rtu() and ibcm_cep_send_rtu()
*
* INPUTS:
* statep - connection state pointer
*
* RETURN VALUE:
*/
static ibt_status_t
{
/* Start filling up ibt_qp_info_t. */
case IBT_RC_SRV:
} else {
}
/* failover was accepted */
}
break;
/* XXX RD? */
case IBT_UC_SRV:
break;
default:
break;
}
/* Call modify_qp */
if (status == IBT_SUCCESS)
else
#ifdef DEBUG
}
#endif
return (status);
}
/*
* ibcm_cep_state_rtu:
* QP state transition function called for an incoming RTU
* on passive side.
*
* INPUTS:
* statep - connection state pointer
* cm_rtu_msg - RTU message pointer
*
*/
void
{
/* RDMA initiator depth taken from negotiated REP values */
if (status != IBT_SUCCESS) {
(void) ibcm_cep_to_error_state(statep);
/*
* Disassociate statep and QP, as there is a
* QP associated with this statep.
*/
IBT_CM_FAILURE_UNKNOWN, NULL, 0);
/*
* resource cleanup. No private data can be returned here
*/
/* unblock any pending DREQ threads */
return;
}
/* invoke the CM handler */
if (cm_rtu_msgp != NULL) {
}
NULL, 0);
if (ibcm_enable_trace & 4)
/* unblock any pending DREQ threads */
}
/*
* ibcm_cep_send_rtu:
* QP state transition function called for an outgoing RTU
* on active side.
*
* INPUTS:
* statep - connection state pointer
*
* RETURN VALUE:
*/
void
{
/* invoke the CM handler */
if (statep->cm_handler) {
event.cm_priv_data_len = 0;
} else {
}
if (ibcm_enable_trace & 4)
/* unblock any pending DREQ threads */
}
/*
* ibcm_cep_to_error_state:
* CEP state transition function. Changes state to IBT_STATE_ERROR
*
* INPUTS:
* statep - connection state pointer
*
* RETURN VALUE:
* IBT_SUCCESS - if able to change state otherwise failure
*/
{
/* For now, set it to RC type */
/* Call modify_qp to move to ERROR state */
if (status == IBT_SUCCESS)
else
}
#ifdef NO_EEC_SUPPORT_YET
/* Call modify_eec */
"ibtl_cm_modify_eec() returned = %x", status);
}
#endif
return (status);
}
/*
* ibcm_cep_state_rej:
* QP state transition function called for an incoming REJ
*
* INPUTS:
* statep - connection state pointer
* rej_msgp - REJ message pointer
* rej_state - State where REJ processing began
*
* RETURN VALUE:
*/
void
{
if ((rej_state == IBCM_STATE_REP_SENT) ||
(rej_state == IBCM_STATE_MRA_REP_RCVD)) {
"ibcm_cep_to_error_state returned %d", statep,
status);
}
/* Disassociate state structure and CM */
/* invoke the CM handler */
if (statep->cm_handler) {
/*
* copy rej_msgp->rej_private_data to
* event.cm_event.cm_priv_data
*/
}
sizeof (ibt_arej_info_t));
if (ibcm_enable_trace != 0)
}
/* Used to initialize client args with addl rej information from REJ MAD */
static void
{
(rej_reason != IBT_CM_CONSUMER))
return;
switch (rej_reason) {
case IBT_CM_PRIM_GID:
case IBT_CM_ALT_GID:
case IBT_CM_PORT_REDIRECT:
break;
sizeof (ib_gid_t));
break;
case IBT_CM_PRIM_LID:
case IBT_CM_ALT_LID:
break;
sizeof (ib_lid_t));
break;
case IBT_CM_INVALID_PRIM_SL:
case IBT_CM_INVALID_ALT_SL:
if (ari_len < 1)
break;
/* take the first 4 bits */
break;
case IBT_CM_INVALID_PRIM_TC:
case IBT_CM_INVALID_ALT_TC:
if (ari_len < 1)
break;
/* take the first byte */
break;
case IBT_CM_INVALID_PRIM_HOP:
case IBT_CM_INVALID_ALT_HOP:
if (ari_len < 1)
break;
/* take the first byte */
break;
case IBT_CM_INVALID_PRIM_RATE:
case IBT_CM_INVALID_ALT_RATE:
if (ari_len < 1)
break;
/* take the first 6 bits */
break;
case IBT_CM_REDIRECT_CM:
if (ari_len < sizeof (ibcm_classportinfo_msg_t))
break;
break;
case IBT_CM_INVALID_MTU:
if (ari_len < 1)
break;
/* take the first 4 bits */
break;
case IBT_CM_CONSUMER:
if (ari_len == 0)
break;
if (ari_len > IBT_CM_ADDL_REJ_LEN)
break;
case IBT_CM_INVALID_PRIM_FLOW:
case IBT_CM_INVALID_ALT_FLOW:
break;
/* take the first 20 bits */
break;
default:
break;
}
}
/* Used to copy classportinfo to MAD from client initialized args */
static void
{
clp->RedirectLID);
}
/* Used to initialize classportinfo to be returned to clients, from MAD */
static void
{
}
/*
* ibcm_cep_state_rej_est:
* QP state transition function called for an incoming REJ
* on active side in established state
*
* INPUTS:
* statep - connection state pointer
*
* RETURN VALUE:
*/
void
{
/* Disassociate state structure and CM */
/* invoke the CM handler */
if (statep->cm_handler) {
event.cm_priv_data_len = 0;
}
}
/*
* ibcm_sidr_req_ud_handler:
* Invoke Client's UD handler For SIDR_REQ msg
*
* INPUTS:
* ud_statep - ud_state pointer
* sidr_reqp - SIDR_REQ message pointer
*
* RETURN VALUE: IBCM_SEND_REP/IBCM_SEND_REJ
*/
static ibcm_status_t
{
/* Check first if UD client handler is valid */
/* Fill in ibt_cm_ud_event_t */
&(sidr_reqp->sidr_req_private_data[0]);
/* Invoke the client handler */
if (cb_status == IBT_CM_DEFER) {
/* unblock any blocked cm ud proceed api calls */
return (IBCM_DEFER);
}
/* fail any blocked ud cm proceed api calls - client bug */
/* do the query qp as soon as possible, after return from cm handler */
if (cb_status == IBT_CM_ACCEPT) {
if (retval != IBT_SUCCESS) {
"Failed to retrieve QPN from the channel: %d",
retval);
return (IBCM_SEND_SIDR_REP);
return (IBCM_SEND_SIDR_REP);
}
}
return (IBCM_SEND_SIDR_REP);
}
/*ARGSUSED*/
void
{
if (cb_status == IBT_CM_DEFAULT)
if (cb_status == IBT_CM_ACCEPT)
else if ((cb_status == IBT_CM_REJECT) ||
(cb_status == IBT_CM_NO_RESOURCE))
else if (cb_status == IBT_CM_NO_CHANNEL)
else if (cb_status == IBT_CM_REDIRECT)
else *sidr_status = IBT_CM_SREP_REJ;
if (*sidr_status != IBT_CM_SREP_CHAN_VALID) {
"ud_handler return a failure: %d", cb_status);
if (*sidr_status == IBT_CM_SREP_REDIRECT) {
/*
* typecasting to ibcm_classportinfo_msg_t is ok, as addl info
* begins at offset 24 in sidr rep
*/
}
return;
}
}
/*
* ibcm_sidr_rep_ud_handler:
* Invoke Client's UD handler For SIDR_REP msg
*
* INPUTS:
* ud_statep - ud_state pointer
* sidr_rep_msgp - SIDR_REQ message pointer
*
*/
static void
{
/* Check first if UD client handler is valid */
"cm_handler NULL");
return;
}
/* Fill in ibt_cm_ud_event_t */
/*
* typecasting to ibcm_classportinfo_msg_t is ok, as addl info
* begins at offset 24 in sidr rep
*/
sizeof (ibt_redirect_info_t));
}
/* Invoke the client handler - inform only, so ignore retval */
}
/*
* ibcm_process_lap_msg:
* This call processes an incoming LAP message
*
* INPUTS:
* hcap - HCA entry pointer
* input_madp - incoming CM LAP MAD
* cm_mad_addr - Address information for the MAD
*
* RETURN VALUE: NONE
*/
/* ARGSUSED */
void
{
" com id %x", state_lookup_status,
if (state_lookup_status != IBCM_LOOKUP_EXISTS) {
/* Post a REJ message ? - but spec doesn't state so */
return;
}
/* There is an existing state structure entry with active comid */
else {
if (ibcm_alloc_out_msg(
IBT_SUCCESS) {
return;
}
}
apr_msg = (ibcm_apr_msg_t *)
" statep 0x%p apr status %d", statep,
if (clnt_response == IBCM_DEFER) {
"client returned DEFER response");
return;
}
/* fail any blocked cm proceed api calls - client bug */
return;
}
} /* drop the LAP MAD in any other state */
}
/*
* ibcm_post_stored_apr_mad:
* Builds and posts an APR MAD from the stored APR MAD
*
* INPUTS:
* statep - pointer to ibcm_state_data_t
* input_madp - pointer to incoming lap mad
*
* RETURN VALUE:
* NONE
*
* This function is called holding the state mutex, and returns
* holding the state mutex
*/
static void
{
/* Need to make a copy, else an incoming new LAP may modify lapr_msg */
"ibcm_alloc_out_msg failed");
return;
}
/* ibcm_free_out_msg done in ibcm_post_stored_apr_complete */
}
/*
* ibcm_cep_state_lap:
* This call processes an incoming LAP message for cep state
* transition and invoking cm handler
*
* INPUTS:
* statep - pointer to ibcm_state_data_t
* lap_msg - lap msg received
* apr_msg - apr msg to be sent
*
* RETURN VALUE: NONE
*/
{
/* If APM is not supported, return error */
return (IBCM_SEND_APR);
}
return (IBCM_SEND_APR);
}
/* Fill up the event */
if (cb_status == IBT_CM_DEFER) {
/* unblock any blocked cm proceed api calls */
return (IBCM_DEFER);
}
clnt_info.priv_data_len = 0;
apr_msg);
return (IBCM_SEND_APR);
}
/*
* ibcm_fill_adds_from_lap:
* Fills the address vector (part of event structure passed to
* client) from the LAP message
*
* INPUTS:
* adds - Address vector to be filled-in
* lap_msg - LAP message used to fill the address vector
*
* RETURN VALUE: NONE
*/
static void
{
if (mode == IBCM_PASSIVE_MODE) {
} else {
}
/* next copy off the GRH info if it exists */
} else {
}
}
/*
* ibcm_process_cep_lap_cm_hdlr:
* Processes the cm handler response for an incoming LAP.
*/
void
{
if (cb_status == IBT_CM_DEFAULT)
/* verify status */
apr_msg->apr_addl_info_len = 0;
if (cb_status == IBT_CM_ACCEPT) {
} else if (cb_status == IBT_CM_REJECT) {
} else if (cb_status == IBT_CM_REDIRECT) {
/* copy redirect info to APR */
} else if (cb_status == IBT_CM_NO_RESOURCE) {
} else {
}
/* copy private data to outgoing apr, specified via priv_data */
if (cb_status != IBT_CM_ACCEPT)
return;
return;
}
/* Fill up input args for ibt_modify_qp */
/* do RTS=>RTS or SQD=>SQD. The next line is needed for RTS=>RTS. */
" ibtl_cm_get_hca_port failed status %d", status);
return;
}
"gid = (%llx, %llx), port_num = %d", statep,
/* The pkey is same as the primary path */
if (status != IBT_SUCCESS) {
return;
}
": rearming APM", statep);
}
NULL);
if (status != IBT_SUCCESS) {
} else
#ifdef DEBUG
#endif
if (status != IBT_SUCCESS) {
" ibt_modify_qp() returned = %d", status);
return;
}
}
/*
* ibcm_post_apr_mad:
* Posts a APR MAD and starts timer
*
* INPUTS:
* statep - state pointer
*
* RETURN VALUE: NONE
*/
void
{
statep);
}
/*
* ibcm_process_apr_msg:
* This call processes an incoming APR message
*
* INPUTS:
* hcap - HCA entry pointer
* input_madp - incoming CM SIDR REP MAD
* cm_mad_addr - Address information for the MAD to be posted
*
* RETURN VALUE: NONE
*/
/*ARGSUSED*/
void
{
if (state_lookup_status != IBCM_LOOKUP_EXISTS) {
return;
}
/* if transaction id is not as expected, drop the APR mad */
": rcv'd APR MAD with comid 0x%x",
"tid expected 0x%llX tid found 0x%llX",
return;
}
return;
}
/* cancel the LAP timer */
} else {
}
/* unblock any DREQ threads and close channels */
/* wake up blocking ibt_set_alt_path */
}
static void
{
switch (ap_status) {
case IBT_CM_AP_REDIRECT:
if (ari_len < sizeof (ibcm_classportinfo_msg_t))
break;
break;
case IBT_CM_AP_RLID_REJECTED:
break;
sizeof (ib_lid_t));
break;
case IBT_CM_AP_RGID_REJECTED:
break;
sizeof (ib_gid_t));
break;
case IBT_CM_AP_FLOW_REJECTED:
break;
/* take the first 20 bits */
break;
if (ari_len < 1)
break;
/* take the first byte */
break;
case IBT_CM_AP_HOP_REJECTED:
if (ari_len < 1)
break;
/* take the first byte */
break;
case IBT_CM_AP_RATE_REJECTED:
if (ari_len < 1)
break;
/* take the first 6 bits */
break;
case IBT_CM_AP_SL_REJECTED:
if (ari_len < 1)
break;
/* take the first 4 bits */
break;
default:
break;
}
}
/*
* ibcm_cep_state_apr:
* This call processes an incoming APR message
*
* INPUTS:
* statep - pointer to ibcm_state_data_t
* lap_msg - lap msg sent earlier
* apr_msg - apr msg received
*
* RETURN VALUE: NONE
*/
void
{
if (ap_status == IBT_CM_AP_LOADED)
/* copy the private data */
/* initialize the ap status */
if (status == IBCM_FAILURE) {
} else {
}
/* do a cv signal for a blocking ibt_set_alt_path */
} else { /* Non blocking call */
/* Fill up the event */
if (status == IBCM_FAILURE) {
} else {
}
/* initialize the ap status */
}
}
/*
* ibcm_set_qp_from_apr:
* This call sets QP's alt path info based on APR message contents
*
* INPUTS:
* statep - pointer to ibcm_state_data_t
* lap_msg - lap msg sent earlier
*
* RETURN VALUE: ibcm_status_t
*/
static ibcm_status_t
{
if (status != IBT_SUCCESS ||
return (IBCM_FAILURE);
}
/* Fill up input args for ibt_modify_qp */
/* do RTS=>RTS or SQD=>SQD. The next line is needed for RTS=>RTS. */
/* Fill up input args for ibt_modify_qp */
"ibtl_cm_get_hca_port failed status = %d", status);
" ibtl_cm_get_hca_port sgid guid %llX",
" ibtl_cm_get_hca_port sgid prefix %llX ",
return (IBCM_FAILURE);
}
"gid = %llx:%llx, port_num = %d",
/* The pkey is same as the primary path */
if (status != IBT_SUCCESS) {
"ibt_pkey2index_byguid failed %d", status);
return (IBCM_FAILURE);
}
/* Need to rearm */
"rearming APM", statep);
}
NULL);
if (status != IBT_SUCCESS)
else
#ifdef DEBUG
#endif
if (status != IBT_SUCCESS) {
" ibt_modify_qp() failed, status = %d", status);
return (IBCM_FAILURE);
}
return (IBCM_SUCCESS);
}
/*
* ibcm_sync_lapr_idle:
*
* until the operation is complete
*
* INPUTS:
* statep Pointer to ibcm_state_data_t
*
* RETURN VALUE: NONE
*
* This function is called holding state mutex
* This function returns, releasing the state mutex
*/
void
{
/* wait till ap_state becomes IBCM_AP_STATE_IDLE */
/* fail the client's ibt_set_alt_path */
/* blocking ibt_set_alt_path */
"blocked wait");
}
/* Cancel the timeout */
if (timer_val != 0)
/* Non blocking ibt_set_alt_path */
/* Fill up the event */
event.cm_priv_data_len = 0;
/* Call the cm handler */
"non-blocked wait");
}
}
#ifdef DEBUG
/*
* Debug function used to print all the modify qp attributes.
* Useful to manually verify the modify qp parameters are as
* expected
*/
static void
{
"rc_rdma_ra_in %d rc_rdma_ra_out %d",
"port %d path bits %d dlid %X",
"pkey index %d cep_timeout %d",
"srvl %d flow label %d tclass %d",
"hop %d srate %d sgid_ix %d send_grh %d",
"dgid prefix %llX dgid guid %llX",
"sgid prefix %llX sgid guid %llX",
"port %d path bits %d dlid %X",
"pkey index %d cep_timeout %d",
"srvl %d flow label %d tclass %d",
"hop %d srate %d sgid_ix %d send_grh %d",
"dgid prefix %llX dgid guid %llX",
gid_guid);
"sgid prefix %llX sgid guid %llX",
gid_guid);
}
#endif