ibmf_saa_impl.c revision 76c04273c82e93b83f826e73f096a3ece549a8f9
/*
* 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.
*/
/* Global sa_access State Pointer */
extern int ibmf_trace_level;
extern int ibmf_taskq_max_tasks;
static int
static int
static int
int status);
ibmf_msg_t *msgp);
/*
* ibmf_saa_impl_init:
* Allocates memory for the ibmf_saa state structure and initializes the taskq.
* Called from the modules init() routine.
*
* Input Arguments
* none
*
* Output Arguments
* none
*
* Returns
* IBMF_NO_RESOURCES if taskq could not be created.
* IBMF_SUCCESS on success
*
*/
int
{
int res;
/* CONSTCOND */
/* create taskq for notifying event subscribers */
"ibmf_saa_event_taskq", IBMF_TASKQ_NTHREADS,
goto bail;
}
NULL);
res = IBMF_SUCCESS;
bail:
return (res);
}
/*
* ibmf_saa_impl_fini:
* If there are no registered clients, cleans up all memory associated with the
* state, including each of the port list entries.
* Called from the modules fini() routine.
*
* Input Arguments
* none
*
* Output Arguments
* none
*
* Returns
* EBUSY if there are outstanding transactions or registered clients
* 0 if cleanup was sucessfull
*
*/
int
{
int ret = 0;
/* make sure there are no registered clients */
if (saa_portp->saa_pt_reference_count > 0) {
"cannot unload ibmf_saa. Client on port still"
goto bail;
}
/* make sure there are no outstanding transactions */
if (saa_portp->saa_pt_num_outstanding_trans > 0) {
"ibmf_saa_impl_fini: %s, port = %016" PRIx64
", num transactions = %d\n",
" Outstanding transactions on port.",
goto bail;
}
}
*saa_portp))
/*
* no more clients nor pending transaction:
* unregister ibmf and destroy port entries
*/
/* unregister from ibmf */
!= IBMF_SUCCESS) {
goto bail;
}
} else
}
bail:
return (ret);
}
/*
* ibmf_saa_is_valid
* Returns true the entry is valid.
*
* Input Arguments
* saa_portp pointer to state structure
* add_ref if B_TRUE ref count is incremented on a valid portp
*
* Output Arguments
* none
*
* Returns
* B_TRUE if entry was in a valid state, B_FALSE otherwise
*/
{
/*
* increment reference count here to ensure that
* entry does not get purged behind our backs
*/
}
return (is_valid);
}
/*
* ibmf_saa_must_purge
* Determines if we can purge a portp (remove it from the list) based on the
* state and number of clients
*
* Input Arguments
* saa_portp pointer to state structure
*
* Output Arguments
* none
*
* Returns
* B_TRUE if the entry can be removed, B_FALSE otherwise
*/
static int
{
int must_purge = B_FALSE;
saa_portp->saa_pt_reference_count == 0) {
must_purge = B_TRUE;
}
return (must_purge);
}
/*
* ibmf_saa_impl_purge:
* Removes invalid port state entries from the list
*
* Input Arguments
* none
*
* Output Arguments
* none
*
* Returns
* void
*/
void
{
/* unlink entry */
} else {
}
/* destroy entry */
} else {
}
}
}
/*
* saa_impl_add_client:
* Adds a client for a particular portp. Reference count has been incremented
* before this call. It is decremented by saa_impl_add_client() if the call
* fails.
*
* Input Arguments
* none
*
* Output Arguments
* none
*
* Returns
* IBMF_BUSY if there are already too many clients registered,
* IBMF_BAD_PORT_STATE if the port is invalid (generally because a previous
* client failed during registration for this port)
* IBMF_SUCCESS otherwise
*/
int
{
int status = IBMF_SUCCESS;
/*
* check that we don't exceed max clients
*/
if (saa_portp->saa_pt_reference_count >
"ibmf_saa_impl_add_client: %s, num_reg_clients %d\n",
goto bail;
}
"ibmf_saa_impl_add_client: num_registered_clients %d\n",
/*
* wait until anyone who is currently registering
* this port with ibmf is done
*/
"ibmf_saa_impl_add_client: %s\n",
" for them to finish");
}
/*
* if port isn't ready here, fail.
*/
"", "ibmf_saa_impl_add_client: %s\n",
" removing client.");
goto bail;
}
bail:
if (status != IBMF_SUCCESS) {
clients_reg_failed, 1);
/* decrementing refcount is last thing we do on entry */
}
"ibmf_saa_impl_add_client() exit\n");
return (status);
}
/*
* ibmf_saa_impl_create_port()
* Create port entry with mimimal inits because
* we're holding the list mutex: NO BLOCKING CALLS HERE, please.
*
* Initialize port state to "registering", so that clients accessing
* same port concurrently will wait for the end of the ibmf registration.
* Note: this thread will access port members without locking mutex.
*
* Input Arguments
* pt_guid guid of port
*
* Output Arguments
* saa_portpp pointer to new saa_portp structure
*
* Returns
* IBMF_NO_MEMORY if memory could not be allocated
* IBMF_SUCCESS otherwise
*/
int
{
int status = IBMF_SUCCESS;
/* create & initialize new port */
"ibmf_saa_impl_create_port: %s\n",
"new port");
goto bail;
}
/* tell everyone that kstats are not initialized */
/*
* set up mutexe and state variable to indicate to
* other clients that were currently in the process of
* setting up the port data. This will prevent a subsequent
* client from trying to to register with ibmf before the
* port data has been initialized.
*/
/* create other mutexes */
NULL);
/*
* clients assume all arrive; set mask to this so we only notify
* if something failed
*/
/*
* set port_guid now so any immediately subsequent clients
* registering on this port, guid will know we're already here
*/
/* set sa_uptime now in case we never receive anything from SA */
/* Set new pointer in caller's */
*saa_portpp = saa_portp;
bail:
return (status);
}
/*
* ibmf_saa_impl_invalidate_port:
* invalidates port entry (assumes exist) and deletes kstat object
* kstat object is destroyed in order to allow creating port entry
* even if this entry is not purged
*/
static void
{
}
/*
* ibmf_saa_impl_destroy_port:
* Frees the resources associated with an saa_portp structure. Assumes the
* saa_portp exists
*
* Input Arguments
* saa_portp pointer to saa_portp structure
*
* Output Arguments
* none
*
* Returns
* void
*/
static void
{
/* uninit synchronization variables used for registration */
}
/*
* ibmf_saa_impl_init_kstats:
* Create kstats structure. Should be called when memory is alloced for a new
* port entry.
*/
int
{
char buf[128];
/* set up kstats structure */
sizeof (ibmf_saa_kstat_t) / sizeof (kstat_named_t),
return (IBMF_NO_RESOURCES);
"clients_registered", KSTAT_DATA_UINT32);
"clients_reg_failed", KSTAT_DATA_UINT32);
"outstanding_requests", KSTAT_DATA_UINT32);
"total_requests", KSTAT_DATA_UINT32);
"failed_requests", KSTAT_DATA_UINT32);
"requests_timedout", KSTAT_DATA_UINT32);
return (IBMF_SUCCESS);
}
/*
* ibmf_saa_impl_uninit_kstats:
* Free kstats context. Should be called when port is either destroyed
* or invalidated.
*/
static void
{
}
}
/*
* ibmf_saa_impl_register_failed:
* invalidate entry and kick waiters
*/
void
{
/* decrementing refcount is last thing we do on entry */
}
static int
{
int status;
int unreg_status;
if (setup_async_cb_only == 0) {
/* allocate a qp through ibmf */
if (status != IBMF_SUCCESS) {
"ibmf_saa_impl_setup_qp_async_cb: %s, "
"ibmf_status = %d\n",
return (status);
}
qp_alloced = B_TRUE;
/*
* query the queue pair number; we will need it to unsubscribe
* from notice reports
*/
if (status != IBMF_SUCCESS) {
"ibmf_saa_impl_setup_qp_async_cb: %s, "
"ibmf_status = %d\n",
"Cannot query alt qp to get qp num",
goto bail;
}
}
/*
* core ibmf is taking advantage of the fact that saa_portp is our
* callback arg. If this changes, the code in ibmf_recv would need to
* change as well
*/
if (status != IBMF_SUCCESS) {
"ibmf_saa_impl_setup_qp_async_cb: %s, ibmf_status = %d\n",
goto bail;
}
return (IBMF_SUCCESS);
bail:
if (qp_alloced == B_TRUE) {
/* free alternate qp */
&saa_portp->saa_pt_qp_handle, 0);
if (unreg_status != IBMF_SUCCESS) {
"ibmf_saa_impl_setup_qp_async_cb: %s, ibmf_status ="
"Cannot free alternate queue pair with ibmf",
}
}
return (status);
}
/*
* ibmf_saa_impl_register_port:
*/
int
{
int status = IBMF_SUCCESS;
int unreg_status = IBMF_SUCCESS;
int ibt_status = IBT_SUCCESS;
uint_t port_count = 0;
"ibmf_saa_impl_register_port() enter\n");
/* get the HCA list */
if (hca_count == 0) {
"ibmf_saa_impl_register_port: %s\n",
goto bail;
}
/* lookup requested port guid in hca list */
0 /* all ports */, &port_info_list,
&port_count, &port_size);
if (ibt_status != IBT_SUCCESS) {
break;
}
/* get port guid associated with hca guid, port num */
continue;
continue;
IBMF_TNF_TRACE, "",
"ibmf_saa_impl_register_port: %s, hca_guid = %016"
", number = %d\n",
/*
* we're here? then we found our port:
* fill in ibmf registration info
* and address parameters from the portinfo
*/
break;
}
if (iport != port_count)
break; /* found our port */
}
"ibmf_saa_impl_register_port: %s, port_guid %016"
PRIx64 "\n",
}
if (status != IBMF_SUCCESS) {
goto bail;
}
/*
* Now we found the port we searched for,
* and open an ibmf session on that port.
*/
"ibmf_saa_impl_register_port: %s, port_guid = %016" PRIx64
if (status != IBMF_SUCCESS) {
"ibmf_saa_impl_register_port: %s, ibmf_status = %d\n",
goto bail;
}
return (IBMF_SUCCESS);
bail:
/* unregister from ibmf */
&saa_portp->saa_pt_ibmf_handle, 0);
if (unreg_status != IBMF_SUCCESS) {
"ibmf_saa_impl_register_port: %s, ibmf_status ="
"Cannot unregister from ibmf",
}
}
return (status);
}
/*
* ibmf_saa_impl_getclassportinfo:
*/
void
{
int res;
/*
* allocate memory for trans_info; send_request's callback will free up
* memory since request is asynchronous
*/
if (trans_info == NULL) {
/* cpi transaction is handled as a client, decrement refcount */
"Could not allocate memory for classportinfo trans_info");
"ibmf_saa_impl_get_classportinfo() exiting\n");
return;
}
/* no specific client associated with this transaction */
if (res != IBMF_SUCCESS) {
"ibmf_saa_impl_get_classportinfo: %s, res = 0x%x\n",
/* cpi transaction is handled as a client, decrement refcount */
}
}
/*
* ibmf_saa_impl_get_cpi_cb:
*
* Called when the asynchronous getportinfo request receives its response.
* Checks the status. If success, updates the times in the port's
* ibmf_retrans structure that is used in ibmf_msg_transport calls. If failure,
* just use default values.
*
* Input Arguments
* arg user-specified pointer (points to the current port data)
* length length of payload returned (should be size of classportinfo_t)
* buffer pointer to classportinfo returned (should not be null)
* status status of sa access request
*
* Output Arguments
* none
*
* Returns void
*/
static void
{
int resp_time_value;
/*
* access port entry: note that it may have become invalid
* but we hold a ref count for cpi and the interactions on
* the entry are harmless
*/
/* process response */
"ibmf_saa_impl_get_cpi_cb: %s, status = %d, buffer = "
"could not get classportinfo. Check node and path to sm"
/*
* IB spec (C13-13) indicates 20 can be used as default or
* intial value for classportinfo->resptimeout value
*/
resp_time_value = 20;
sa_cap_mask = 0xFFFF;
/*
* Because some subnet managers might not provide sane
* value for "resp_time_value", we limit it here. In
* case this limit is too restrictive (very large fabric),
*/
if (resp_time_value > ibmf_saa_max_resp_time) {
"exceeded.", ibmf_saa_max_resp_time);
"resp_time value from %d to %d.",
}
"ibmf_saa_impl_get_cpi_cb: %s, timeout = 0x%x,"
" cap_mask = 0x%x\n",
}
/*
* using IB spec calculation from 13.4.6.2
* use bit shifting for 2^x.
*/
/*
* cpi transaction is handled as a client,
* decrement refcount; make sure it's the last
* thing we do on this entry
*/
"ibmf_saa_impl_get_cpi_cb: %s, subnet_timeout = 0x%x, "
"resp_time_value = 0x%x\n",
}
/*
* ibmf_saa_impl_send_request:
* Sends a request to the sa. Can be used for both classportinfo and record
* requests. Will set up all data structures for using the multi-packet
* protocol, create the mad, and send it. Returns SA_SUCCESS if msg transport
* worked, meaning succesful send for the async case and a succesful send and
* recv for the sync case.
*/
int
{
void *ibmf_callback_arg;
int ibmf_status = IBMF_SUCCESS;
int retry_count;
/*
* don't send on invalid entry
* Note that there is a window where it could become
* invalid after this test is done, but we'd rely on ibmf errors...
*/
IBMF_TNF_ERROR, "",
"ibmf_saa_impl_send_request: %s, hca_guid = %016"
", number = %d\n",
goto bail;
}
/* check whether SA supports this attribute */
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_saa_impl_send_request: %s, ibmf_status = %d\n",
goto bail;
}
/* make only non-blocking calls if this is an async request */
sleep_flag = B_TRUE;
} else {
ibmf_callback_arg = (void *)trans_info;
}
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_saa_impl_send_request: %s, ibmf_status = %d\n",
goto bail;
}
/*
* increment the number of outstanding transaction so
* ibmf_close_sa_session() will wait. classportinfo requests
* don't have associated clients so check for valid clientp
*/
if (client_data != NULL) {
}
/*
* make the call to msg_transport. If synchronous and success,
* check that the response mad isn't status busy. If so, repeat the
* call
*/
retry_count = 0;
/*
* set the send time here. We only set this once at the beginning of
* the transaction. Retrying because of busys or mastersmlid changes
* does not change the original send time. It is meant to be an
* absolute time out value and will only be used if there are other
* problems (i.e. a buggy SA)
*/
for (;;) {
if (ibmf_callback != NULL)
break;
/*
* stop here for non-sequenced transactions since they wouldn't
* receive a timeout or busy response
*/
if (!(transport_flags & IBMF_MSG_TRANS_FLAG_SEQ))
break;
/*
* if the transaction timed out and this was a synchronous
* request there's a possiblity we were talking to the wrong
* master smlid or that the SA has stopped responding on the
* redirected desination (if redirect is active).
* Check this and retry if necessary.
*/
if ((ibmf_status == IBMF_TRANS_TIMEOUT) &&
(sleep_flag == B_TRUE)) {
if (sa_is_redirected == B_TRUE) {
} else {
}
}
/*
* if the transaction timed out (and retrying with a new SM LID
* didn't help) check how long it's been since we received an SA
* packet. If it hasn't been max_wait_time then retry the
* request.
*/
if ((ibmf_status == IBMF_TRANS_TIMEOUT) &&
(sleep_flag == B_TRUE)) {
}
if (ibmf_status != IBMF_SUCCESS)
break;
break;
/* sync transaction with status SUCCESS should have response */
if ((mad_status != MAD_STATUS_BUSY) &&
break;
if (mad_status == MAD_STATUS_REDIRECT_REQUIRED) {
"ibmf_saa_impl_send_request: %s, retry_count %d\n",
"response returned redirect status",
/* update address info and copy it into msgp */
} else {
"ibmf_saa_impl_send_request: %s, retry_count %d\n",
}
retry_count++;
/*
* since this is a blocking call, sleep for some time
* to allow SA to transition from busy state (if busy)
*/
if (mad_status == MAD_STATUS_BUSY)
IBMF_SAA_BUSY_RETRY_SLEEP_SECS * 1000000));
}
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_saa_impl_send_request: %s, ibmf_status = %d\n",
if (client_data != NULL) {
if ((client_data->saa_client_num_pending_trans == 0) &&
}
} else if (sleep_flag == B_TRUE) {
"ibmf_saa_impl_send_request: %s\n",
/* fill in response values and free the message */
if (client_data != NULL) {
if ((client_data->saa_client_num_pending_trans == 0) &&
}
} else {
"ibmf_saa_impl_send_request: %s\n",
}
bail:
return (ibmf_status);
}
/*
* ibmf_saa_impl_init_msg:
* Allocates an ibmf message and fills out the header fields and formatted data
* fields. Also sets up the correct transport_flags and retrans argument for
* the message transport call based on the request information.
*
* Input Arguments
* trans_info saa_trans_info structure passed to send_request
* sleep_flag B_TRUE if init_msg can sleep in function calls
*
* Output Arguments
* msgp ibmf message that should be given to msg_transport
* transport_flagsp transport flags that should be given to msg_transport
* ibmf_retrans_t retrans parameter that should be given to msg_transport
*
* Returns
* ibmf_status
*/
static int
{
int ibmf_status;
int ibmf_sleep_flag, km_sleep_flag;
int free_res;
if (sleep_flag == B_TRUE) {
} else {
}
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_saa_impl_init_msg: %s, ibmf_status = %d\n",
goto bail;
}
/* create a template (SA MAD) */
"ibmf_saa_impl_init_msg: %s\n",
&ibmf_msg);
goto bail;
}
*req_mad))
/* attribute modifier is all Fs since RIDs are no longer used */
"ibmf_saa_impl_init_msg: %s, class = 0x%x, method = 0x%x,"
if (client_data != NULL)
/*
* pack data for IB wire format; req_mad will have different pointers to
* sa header and payload, mad_hdr will be the same
*/
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_saa_impl_init_msg: %s, ibmf_status = %d\n",
&ibmf_msg);
goto bail;
}
if (attr_id == SA_MULTIPATHRECORD_ATTRID) {
payload_length = sizeof (sa_multipath_record_t) +
} else {
/* trace record template is a path record */
if (payload_length == 0) {
"ibmf_saa_impl_init_msg: %s, length = %d\n",
"Unknown attribute. Using user-defined length.",
}
}
/* transport type depends on method */
switch (method) {
case SA_SUBN_ADM_GET:
case SA_SUBN_ADM_DELETE:
case SA_SUBN_ADM_GET_TABLE:
break;
case SA_SUBN_ADM_SET:
/* unsubscribes can be sequenced or unsequenced */
transport_flags = 0;
} else {
}
break;
case SA_SUBN_ADM_GET_MULTI:
break;
default :
goto bail;
}
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_saa_impl_init_msg: %s, ibmf_status ="
"ibmf_saa_utils_pack_payload() failed",
&ibmf_msg);
goto bail;
}
"ibmf_saa_impl_init_msg: %s, attr_id = 0x%x, length ="
/* non-RMPP transactions have template size limit */
if (((transport_flags & IBMF_MSG_TRANS_FLAG_RMPP) == 0) &&
+ sizeof (ib_mad_hdr_t)) > IBMF_MAD_SIZE)) {
"Template too large to fit in single packet");
&ibmf_msg);
goto bail;
}
}
sizeof (ibmf_retrans_t));
/* copy local addressing information to message */
sizeof (ibmf_addr_info_t));
/* copy global addressing information to message if in use */
sizeof (ibmf_global_addr_info_t));
} else {
ibmf_msg->im_msg_flags = 0;
}
bail:
return (ibmf_status);
}
/*
* ibmf_saa_impl_new_smlid_retry:
*
* It's possible for the MasterSMLID to change while ibmf_saa is running. The
* MasterSMLID is set when we first register with ibmf_saa. If a request
* timesout, this function should be called to check whether the SM LID changed.
* If so, it will call msg_transport again with the request.
*
* msgp, ibmf_callback, ibmf_callback_arg, and transport flags should be the
* same values passed to the original ibmf_msg_transport that timedout. The
* ibmf_retrans parameter will be re-retrieved from the saa_portp structure.
*
* If the lid did not change then this function returns IBMF_TRANS_TIMEOUT.
* That way, callers can simply return the result of this function.
*
* Input Arguments
* saa_portp pointer to saa_port structure
* msgp ibmf message that timedout
* ibmf_callback callback that should be called by msg_transport
* ibmf_callback_arg args for ibmf_callback
* transport_flags flags for ibmf_msg_transport
*
* Output Arguments
* none
*
* Returns
* IBMF_SUCCESS if lid changed and request was resent successfully,
* IBMF_TRANS_TIMEOUT if lid did not change,
* same values as ibmf_msg_transport() if lid changed but request could not be
* resent.
*/
static int
{
int subnet_timeout;
int ibmf_status;
/* first query the portinfo to see if the lid changed */
if (ibt_status != IBT_SUCCESS) {
"ibmf_saa_impl_new_smlid_retry: %s, ibmf_status ="
"ibt_query_hca_ports_byguid() failed",
goto bail;
}
/* if master smlid is different than the remote lid we sent to */
"ibmf_saa_impl_new_smlid_retry: %s, new_lid 0x%x,"
"master smlid has changed. retrying msg_transport",
/* update the master sm lid value in ibmf_saa */
/* new tid needed */
sizeof (ibmf_retrans_t));
/* place upper bound on subnet timeout in case of faulty SM */
/* increment the reference count to account for the cpi call */
/* update the remote lid for this particular message */
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_saa_impl_new_smlid_retry: %s, ibmf_status = "
"ibmf_msg_transport() failed",
}
goto bail;
}
"ibmf_saa_impl_new_smlid_retry: %s, master_smlid = 0x%x\n",
"master smlid did not change. returning failure",
/* mark status as timeout since that was original failure */
bail:
return (ibmf_status);
}
/*
* ibmf_saa_impl_revert_to_qp1()
*
* The SA that we had contact with via redirect may fail to respond. If this
* occurs SA should revert back to qp1 and the SMLID set in the port.
* msg_transport for the message that timed out will be retried with
* these new parameters.
*
* msgp, ibmf_callback, ibmf_callback_arg, and transport flags should be the
* same values passed to the original ibmf_msg_transport that timedout. The
* ibmf_retrans parameter will be re-retrieved from the saa_portp structure.
*
* Input Arguments
* saa_portp pointer to saa_port structure
* msgp ibmf message that timedout
* ibmf_callback callback that should be called by msg_transport
* ibmf_callback_arg args for ibmf_callback
* transport_flags flags for ibmf_msg_transport
*
* Output Arguments
* none
*
* Returns
* none
*/
static int
{
int subnet_timeout;
int ibmf_status;
/* first query the portinfo to see if the lid changed */
if (ibt_status != IBT_SUCCESS) {
"ibmf_saa_impl_revert_to_qp1: %s, ibmf_status ="
"ibt_query_hca_ports_byguid() failed",
goto bail;
}
/* update the address info in ibmf_saa */
/* new tid needed */
sizeof (ibmf_retrans_t));
/* place upper bound on subnet timeout in case of faulty SM */
/* increment the reference count to account for the cpi call */
/* update the address info for this particular message */
sizeof (ibmf_addr_info_t));
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_saa_impl_revert_to_qp1: %s, ibmf_status = "
"ibmf_msg_transport() failed",
}
bail:
return (ibmf_status);
}
/*
* ibmf_saa_impl_async_event_cb:
* ibmf event callback, argument to ibmf_register
* ibmf_handle is unused
*/
/* ARGSUSED */
static void
void *clnt_private,
{
"ibmf_saa_impl_async_event_cb: Handling event type 0x%x\n",
switch (event_type) {
case IBMF_CI_OFFLINE:
break;
default:
break;
}
}
/*
* ibmf_saa_impl_ibt_async_handler:
* MUST NOT BE STATIC (referred from within IBMF)
*/
void
{
"ibmf_saa_impl_ibt_async_handler: Handling event code 0x%x\n",
switch (code) {
case IBT_EVENT_PORT_UP:
break;
case IBT_ERROR_PORT_DOWN:
break;
case IBT_PORT_CHANGE_EVENT:
break;
case IBT_CLNT_REREG_EVENT:
break;
default:
break;
}
}
/*
* ibmf_saa_impl_port_chg:
*/
static void
{
int port_num;
/* Get classportinfo of corresponding entry */
/*
* increment reference count to account for cpi and
* informinfos. All 4 informinfo's sent are treated as
* one port client reference
*/
if (is_ready)
if (is_ready)
break; /* normally, only 1 port entry */
}
}
/* first query the portinfo to see if the lid changed */
if (ibt_status != IBT_SUCCESS) {
"ibmf_saa_impl_port_chg: %s, ibmf_status ="
"ibt_query_hca_ports_byguid() failed",
goto bail;
}
/* update the Master SM Lid value in ibmf_saa */
}
/* update the Master SM SL value in ibmf_saa */
}
/* update the Subnet timeout value in ibmf_saa */
}
/* get the classportinfo again */
}
bail:
}
/*
* ibmf_saa_impl_client_rereg:
*/
static void
{
/* Get classportinfo of corresponding entry */
/*
* increment reference count to account for cpi and
* informinfos. All 4 informinfo's sent are treated as
* one port client reference
*/
if (is_ready)
if (is_ready)
break; /* normally, only 1 port entry */
}
}
/* verify whether master sm lid changed */
/* first query the portinfo to see if the lid changed */
if (ibt_status != IBT_SUCCESS) {
"ibmf_saa_impl_client_rereg: %s, ibmf_status ="
"ibt_query_hca_ports_byguid() failed",
goto bail;
}
/* check whether we need to subscribe for events */
/* update the master smlid */
/* update the master sm lid value in ibmf_saa */
/* if we're not subscribed for events, dec reference count */
if (event_subs == B_FALSE)
"ibmf_saa_impl_client_rereg: %s, master_sm_lid = 0x%x\n",
"port is up. Sending classportinfo request",
/* get the classportinfo again */
/*
* resubscribe to events if there are subscribers since SA may
* have removed our subscription records when the port went down
*/
if (event_subs == B_TRUE)
}
bail:
}
/*
* ibmf_saa_impl_port_up:
*/
static void
{
int is_ready;
/* Get classportinfo of corresponding entry */
/*
* increment reference count to account for cpi and
* informinfos. All 4 informinfo's sent are treated as
* one port client reference
*/
break; /* normally, only 1 port entry */
}
}
/* verify whether master sm lid changed */
/* first query the portinfo to see if the lid changed */
if (ibt_status != IBT_SUCCESS) {
"ibmf_saa_impl_port_up: %s, ibmf_status ="
"ibt_query_hca_ports_byguid() failed",
goto bail;
}
/* check whether we need to subscribe for events */
/* update the master smlid */
/* update the master sm lid value in ibmf_saa */
/* if we're not subscribed for events, dec reference count */
if (event_subs == B_FALSE)
"ibmf_saa_impl_port_up: %s, master_sm_lid = 0x%x\n",
"port is up. Sending classportinfo request",
/* get the classportinfo again */
/*
* resubscribe to events if there are subscribers since SA may
* have removed our subscription records when the port went down
*/
if (event_subs == B_TRUE)
}
bail:
}
/*
* ibmf_saa_impl_port_down:
*/
static void
{
}
/*
* ibmf_saa_impl_hca_detach:
* find entry, unregister if there are no clients
* have to unregister since ibmf needs to close the hca and will only do this if
* no clients are registered
*/
static void
{
/* find this entry */
if (saa_portp == saa_removed)
break;
}
"ibmf_saa_impl_hca_detach: %s, entry %016"
PRIx64 "\n",
"Port entry NOT found",
goto bail;
}
/* if there are clients expecting Reports(), unsusbscribe */
/* fail if outstanding transactions */
if (saa_portp->saa_pt_num_outstanding_trans > 0) {
"ibmf_saa_impl_fini: %s, port = %016" PRIx64
", num transactions = %d\n",
" Outstanding transactions on port.",
goto bail;
}
/*
* increment reference count by one to account for unsubscribe requests
* that are about to be sent. All four informinfo's are treated as one
* port client reference. The count will be decremented by
* subscribe_events() before the call returns.
*/
if (must_unsub == B_TRUE)
/*
* try and unsubscribe from SA. Generate synchronous, unsequenced
* unsubscribe requests.
*/
if (must_unsub == B_TRUE)
/* warning if registered clients */
if (saa_portp->saa_pt_reference_count > 0) {
"ibmf_saa_impl_hca_detach: %s, port %016"
PRIx64 "\n",
"Detaching HCA for port with clients still"
}
/* synchronize on end of registration */
"ibmf_saa_impl_hca_detach: %s\n",
" for them to finish");
}
/* unregister from ibmf */
must_unreg = B_TRUE;
} else
if (must_unreg == B_TRUE) {
(void) ibmf_saa_impl_init_kstats(saa_portp);
if (must_unsub == B_TRUE)
if (must_unsub == B_TRUE) {
B_FALSE);
}
}
}
bail:
}
/* ARGSUSED */
void
{
int status;
void *result;
int ibmf_status;
(sa_is_redirected == B_TRUE)) {
/*
* We should retry the request using SM_LID and QP1 if we
* have been using redirect up until now
*/
/*
* If revert_to_qp1 returns success msg was resent.
* Otherwise msg could not be resent. Continue normally
*/
if (ibmf_status == IBMF_SUCCESS)
goto bail;
/*
* if smlid_retry() returns success sm lid changed and msg
* was resent. Otherwise, lid did not change or msg could not
* be resent. Continue normally.
*/
if (ibmf_status == IBMF_SUCCESS)
goto bail;
/*
* check whether we've received anything from the SA in a while.
* If we have, this function will retry and return success. If
* we haven't continue normally so that we return a timeout to
* the client
*/
if (ibmf_status == IBMF_SUCCESS)
goto bail;
}
/*
* If SA returned success but mad status is busy, retry a few times.
* If SA returned success but mad status says redirect is required,
* update the address info and retry the request to the new SA address
*/
MAD_STATUS_BUSY) &&
"ibmf_saa_async_cb: %s, retry_count = %d\n",
"async response returned busy status",
sizeof (ibmf_retrans_t));
/*
* if retry is successful, quit here since async_cb will
* get called again; otherwise, let this function call
* handle the cleanup
*/
if (ibmf_status == IBMF_SUCCESS)
goto bail;
"ibmf_saa_async_cb: "
"async response returned redirect status\n");
/* update address info and copy it into msgp */
/* retry with new address info */
sizeof (ibmf_retrans_t));
/*
* if retry is successful, quit here since async_cb will
* get called again; otherwise, let this function call
* handle the cleanup
*/
if (ibmf_status == IBMF_SUCCESS)
goto bail;
}
}
else
if (status != IBMF_SUCCESS)
if (status == IBMF_TRANS_TIMEOUT)
"Calling ibmf_saa client's callback");
/*
* there are three classes or trans_info users: ibmf_saa clients and
* classportinfo requests; informinfo subscribe requests, and report
* responses. For the first two, call the correct callback. For report
* responses there's no need to notify anyone.
*/
/* ibmf_saa client or classportinfo request */
/* informinfo subscribe request */
}
"Returned from callback");
if (client_data != NULL) {
if ((client_data->saa_client_num_pending_trans == 0) &&
}
bail:
}
/*
* ibmf_saa_check_sa_and_retry:
*
* If a particular transaction times out, we don't want to give up if we know
* the SA is responding. Check the time since we last received a response. If
* it's less than ibmf_saa_max_wait_time retry the request.
*
* msgp, ibmf_callback, ibmf_callback_arg, and transport flags should be the
* same values passed to the original ibmf_msg_transport that timed out. The
* ibmf_retrans parameter will be re-retrieved from the saa_portp structure.
*
* If max_wait_time seconds have passed, this function returns IBMF_TIMEOUT.
* That way, callers can simply return the result of this function.
*
* Input Arguments
* saa_portp pointer to saa_port structure
* msgp ibmf message that timedout
* ibmf_callback callback that should be called by msg_transport
* ibmf_callback_arg args for ibmf_callback
* transport_flags flags for ibmf_msg_transport
*
* Output Arguments
* none
*
* Returns
* IBMF_SUCCESS if we've recently received data from the SA and request was
* resent.
* IBMF_TRANS_TIMEOUT if no data has been received from the SA in max_wait_time
* same values as ibmf_msg_transport() if data has been received but request
* could not be resent.
*/
static int
{
int ibmf_status;
do {
/* if nothing received from SA since we sent */
/*
* check if it's been a very long time since this
* particular transaction was sent
*/
"ibmf_saa_check_sa_and_retry: %s, msgp = "
"Nothing received for this transaction",
break;
}
/*
* check time since we received something,
* and make sure that it hasn't been an extra long
* time for this particular transaction
*/
"ibmf_saa_check_sa_and_retry: %s, msgp = "
/*
* something received in WAIT_TIME_IN_SECS;
* resend request
*/
/* new tid needed */
&ibmf_retrans, sizeof (ibmf_retrans_t));
if (ibmf_status == IBMF_SUCCESS)
goto bail;
"ibmf_saa_check_sa_and_retry: %s, ibmf_status = "
"ibmf_msg_transport() failed",
} else {
"ibmf_saa_check_sa_and_retry: %s, msgp = "
"Nothing received. Timing out",
break;
}
} while (ibmf_status == IBMF_TRANS_TIMEOUT);
bail:
return (ibmf_status);
}
/*
* ibmf_saa_impl_prepare_response:
*/
static void
{
*length = 0;
"ibmf_saa_impl_prepare_response: %s, msg_status = %d\n",
goto exit;
}
/*
* this was an unsequenced transaction (from an unsubscribe for
* following a CI_OFFLINE event)
*/
"ibmf_saa_impl_prepare_response: %s\n",
goto exit;
}
/* convert mad packet status to IBMF status */
switch (mad_status) {
break;
break;
case SA_STATUS_ERR_NO_RECORDS:
break;
break;
break;
break;
case MAD_STATUS_UNSUPP_METHOD:
break;
break;
case MAD_STATUS_INVALID_FIELD:
break;
default:
break;
}
"ibmf_saa_impl_prepare_response: %s, mad_status = %x\n",
goto exit;
}
"ibmf_saa_impl_prepare_response: attr_id = 0x%x, method = "
"0x%x\n",
/*
* ignore any data from deleteresp since there's no way to know whether
* real data was returned; also ignore data if this was a Report
* response
*/
if (method == SA_SUBN_ADM_DELETE_RESP) {
"impf_saa_impl_prepare_response: %s\n",
"DeleteResp or NoticeResp returned. "
"Ignoring response data");
*status = IBMF_SUCCESS;
*length = 0;
goto exit;
}
if (attr_id == SA_MULTIPATHRECORD_ATTRID) {
/*
* getmulti is only for requests; attribute should not
* be returned from SA
*/
"", "ibmf_saa_impl_prepare_response: %s\n",
goto exit;
}
/* if we are supposed to ignore data, stop here */
if (ignore_data == B_TRUE) {
*status = IBMF_SUCCESS;
goto exit;
}
/* unpack the sa header to get the attribute offset */
if (*status != IBMF_SUCCESS) {
goto exit;
}
/*
* unpack data payload; if unpack function doesn't return success
* (because it could not allocate memory) forward this status to waiting
* client
*/
if (*status == IBMF_SUCCESS) {
IBMF_TNF_TRACE, "",
"ibmf_saa_impl_prepare_response: attr_id = "
"0x%x, attr_offset = %d, packed_payload_len = %d, "
"unpacked_payload_len = %d\n",
} else {
"attr_id = 0x%x, attr_offset = %d, packed_payload_len = %d,"
"status = %d\n",
}
exit:
}
/*
* ibmf_saa_impl_check_sa_support:
* Checks the capability mask (returned from the SA classportinfo response) to
* determine whether the sa supports the specified attribute ID.
*
* Input Arguments
* cap_mask 16-bit capability mask returned in SA's classportinfo
* attr_id attribute ID of current request
*
* Returns
* IBMF_NOT_SUPPORTED if capability mask indicates SA does not support attribute
* IBMF_SUCCESS otherwise
*/
static int
{
"ibmf_saa_impl_check_sa_support: cap_mask = 0x%x, "
switch (attr_id) {
case SA_SMINFORECORD_ATTRID:
case SA_LINKRECORD_ATTRID:
case SA_GUIDINFORECORD_ATTRID:
case SA_TRACERECORD_ATTRID:
if ((cap_mask &
SA_CAPMASK_OPT_RECORDS_SUPPORTED) == 0) {
IBMF_TNF_ERROR, "",
"ibmf_saa_impl_check_sa_support: %s, "
"SA does not support optional records",
}
break;
if ((cap_mask & SA_CAPMASK_MULTIPATH_SUPPORTED) == 0) {
IBMF_TNF_ERROR, "",
"ibmf_saa_impl_check_sa_support: %s, "
"SA does not support multipath records",
}
break;
case SA_MCMEMBERRECORD_ATTRID:
if ((cap_mask & SA_CAPMASK_UD_MCAST_SUPPORTED) == 0) {
IBMF_TNF_ERROR, "",
"ibmf_saa_impl_check_sa_support: %s, "
"SA does not support ud multicast",
}
break;
default:
break;
} /* switch */
"ibmf_saa_impl_check_sa_support() exiting, attr_supported = %d\n",
if (attr_supported == B_FALSE)
return (IBMF_UNSUPP_METHOD_ATTR);
else
return (IBMF_SUCCESS);
}
/*
* ibmf_saa_impl_get_attr_id_length:
*
* Returns the host size of the specified sa record. Returns 0 for unknown
* attributes. multipath record size is a dynamic value given as a parameter
* specified with the ibmf_sa_access() call.
*/
static uint_t
{
/* this function should not be used for multipath record */
switch (attr_id) {
case SA_CLASSPORTINFO_ATTRID:
attr_length = sizeof (ib_mad_classportinfo_t);
break;
case SA_NOTICE_ATTRID:
attr_length = sizeof (ib_mad_notice_t);
break;
case SA_INFORMINFO_ATTRID:
attr_length = sizeof (ib_mad_informinfo_t);
break;
case SA_NODERECORD_ATTRID:
attr_length = sizeof (sa_node_record_t);
break;
case SA_PORTINFORECORD_ATTRID:
attr_length = sizeof (sa_portinfo_record_t);
break;
case SA_SLTOVLRECORD_ATTRID:
attr_length = sizeof (sa_SLtoVLmapping_record_t);
break;
attr_length = sizeof (sa_switchinfo_record_t);
break;
attr_length = sizeof (sa_linearft_record_t);
break;
attr_length = sizeof (sa_randomft_record_t);
break;
attr_length = sizeof (sa_multicastft_record_t);
break;
case SA_SMINFORECORD_ATTRID:
attr_length = sizeof (sa_sminfo_record_t);
break;
attr_length = sizeof (sa_informinfo_record_t);
break;
case SA_LINKRECORD_ATTRID:
attr_length = sizeof (sa_link_record_t);
break;
case SA_GUIDINFORECORD_ATTRID:
attr_length = sizeof (sa_guidinfo_record_t);
break;
case SA_SERVICERECORD_ATTRID:
attr_length = sizeof (sa_service_record_t);
break;
attr_length = sizeof (sa_pkey_table_record_t);
break;
case SA_PATHRECORD_ATTRID:
attr_length = sizeof (sa_path_record_t);
break;
case SA_VLARBRECORD_ATTRID:
attr_length = sizeof (sa_VLarb_table_record_t);
break;
case SA_MCMEMBERRECORD_ATTRID:
attr_length = sizeof (sa_mcmember_record_t);
break;
case SA_TRACERECORD_ATTRID:
attr_length = sizeof (sa_trace_record_t);
break;
attr_length = sizeof (sa_service_assn_record_t);
break;
default:
/* should only get the above type of packets */
attr_length = 0;
break;
}
" attr_id: 0x%x size %d\n",
return (attr_length);
}
/*
* ibmf_saa_impl_free_msg:
* Takes a completed message and free memory associated with the message,
* including the individual fields of the im_msgbufs_send.
* ibmf_free_msg, called at the end of this function, takes a pointer to the
* message pointer so that it can set the message pointer to NULL. This
* function takes just the message pointer so the msgp will not be NULL after
* this function returns.
*
* Input Arguments
* ibmf_hdl ibmf handle used in ibmf_msg_alloc
* msgp pointer to ibmf_msg_t to free
*
* Returns
* void
*/
static void
{
int res;
sizeof (ib_mad_hdr_t));
}
/*
* ibmf_saa_impl_get_port_guid:
*/
static int
{
return (IBMF_BAD_PORT_STATE);
}
if (ibt_portinfop->p_sgid_tbl_sz == 0) {
"portinfo sgid table size is 0. Exiting.\n");
return (IBMF_TRANSPORT_FAILURE);
}
return (IBMF_SUCCESS);
}
/*
* ibmf_saa_impl_set_transaction_params:
*/
static void
{
IBMF_TNF_TRACE, "",
"ibmf_saa_impl_set_transaction_params() enter\n");
/*
* For the first transaction (generally getting the
* classportinfo) have ibmf pick our timeouts. It should be using the
* default IB spec values.
* Once we get the classportinfo we'll update the correct response time
* value (rtv) and round-trip time (rttv). ibmf should always calculate
* trans_to since it depends on the particular transaction's number of
* packets.
*/
/*
* Assume that the SA supports all optional records. If it
* does not, the request will get returned with ERR_NOT_SUPP. When
* the classportinfo response comes back we will update the cap mask
* to prevent unnecessary unsupported requests.
*/
/*
* fill out addr information for MADs that will be sent
* to SA on this port
*/
/* place upper bound on subnet timeout in case of faulty SM */
IBMF_TNF_TRACE, "",
"ibmf_saa_impl_set_transaction_params: local_lid = 0x%x, "
"sm_lid = 0x%x, sm_sl = 0x%x, sn_timeout = 0x%x\n",
IBMF_TNF_TRACE, "",
"ibmf_saa_impl_set_transaction_params() exit\n");
}
/*
* ibmf_saa_impl_update_sa_address_info
*/
static void
{
void *result;
int rv;
IBMF_TNF_TRACE, "",
"ibmf_saa_impl_update_sa_address_info() enter\n");
/*
* decode the respons of msgp as a classportinfo attribute
*/
if (rv != IBMF_SUCCESS) {
return;
}
if (attr_id != MAD_ATTR_ID_CLASSPORTINFO) {
return;
}
if (rv != IBMF_SUCCESS) {
return;
}
/*
* Use the classportinfo contents to update the SA address info
*/
if (ibt_status != IBT_SUCCESS) {
"", "ibmf_saa_impl_update_sa_address_info: "
"Could not query hca port",
return;
}
/*
* Fill in global address info parameters
*
* NOTE: The HopLimit value is not specified through the
* contents of ClassPortInfo. It may be possible to find
* out the proper value to use even for SA beeing redirected
* to another subnet. But we do only support redirect within
* our local subnet
*/
gaddrp->ig_hop_limit = 0;
} else {
}
/*
* Update the address info of msgp with the new address parameters
*/
sizeof (ibmf_addr_info_t));
} else {
msgp->im_msg_flags = 0;
}
}
/*
* ibmf_saa_impl_ibmf_unreg:
*/
static int
{
int ibmf_status;
/* teardown async cb */
saa_portp->saa_pt_qp_handle, 0);
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_saa_impl_ibmf_unreg: %s, ibmf_status = %d\n",
goto bail;
}
/* free qp */
&saa_portp->saa_pt_qp_handle, 0);
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_saa_impl_ibmf_unreg: %s, ibmf_status = %d\n",
goto bail;
}
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_saa_impl_ibmf_unreg: %s, ibmf_status = %d\n",
(void) ibmf_saa_impl_setup_qp_async_cb(saa_portp, 0);
}
bail:
return (ibmf_status);
}