ibmf_saa.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* 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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* ibmf_saa.c
*
*/
#include <sys/ib/mgt/ibmf/ibmf_saa_impl.h>
/*
* As a primitive error checking scheme, the first 4 bytes of the client state
* have a well-known pattern. We write this pattern during session_open, make
* sure all subsequent calls still have this pattern in the client state, and
* clear the pattern on session_close. Clients could still run into trouble
* providing a bad handle since we don't check a known list of handles. But
* this mechanism will protect against making ibmf_saa calls after the session
* has been closed.
*/
#define IBMF_SAA_SET_CLIENT_SIGNATURE(clientp) { \
(clientp)->saa_client_sig = (void *)0xACEDFACE; \
}
#define IBMF_SAA_VERIFY_CLIENT_SIGNATURE(clientp) \
(((clientp) != NULL && (clientp)->saa_client_sig == \
(void *)0xACEDFACE) ? B_TRUE: B_FALSE)
#define IBMF_SAA_CLEAR_CLIENT_SIGNATURE(clientp) { \
(clientp)->saa_client_sig = 0; \
}
/* Global Sa_access State Pointer */
extern saa_state_t *saa_statep;
extern int ibmf_trace_level;
/*
* Locking scheme:
* ibmf_saa maintains a linked list of port entries. Each element of the list
* contains information about a certain port. There may be multiple clients
* associated with each of these entries. The list is synchronized with a state
* port_list_mutex. Each of the entries has their own individual mutex. When
* adding a new port entry to the mutex the client, with the list mutex, marks
* the port as registering, adds the port, and releases the list mutex.
* Subsequent clients aquire the list mutex, find the port, acquire the port
* mutex, release the list mutex, and wait if the port is marked as registering.
* Clients should never try to acquire the list mutex when they have a port
* mutex.
*/
/*
* ibmf_sa_session_open():
*
* Before using the ibmf_saa interface, consumers should register with the
* ibmf_saa interface by calling ibmf_sa_session_open(). Upon a successful
* registration, a handle is returned for use in subsequent interaction with the
* ibmf_saa interface; this handle is also provided as an argument to subnet
* event notification function.
*
* Consumers can register to be notified of subnet events such as GID
* being available/unavailable. Clients which provide a non-NULL event args
* structure will have the is_event_callback function called when an event is
* received or there is a failure in subscribing for events. This callback may
* be generated before the ibmf_sa_session_open() call returns.
*
* This interface blocks allocating memory, but not waiting for any packet
* responses.
*
* Arguments:
* port_guid - GUID of the port.
* event_args - subnet event registration details
* sm_key - only filled in if the consumer is an SM
* ibmf_version - version of the interface (IBMF_VERSION)
* flags - unused
*
* Output Arguments:
* ibmf_sa_handle - pointer to ibmf_saa_handle to be used in future calls
*
* Return values:
* IBMF_SUCCESS - registration succeeded
* IBMF_BAD_PORT - registration failed; active port not found
* IBMF_BAD_PORT_STATE - registration failed; port found but not active or
* previous registration failed
* IBMF_NO_MEMORY - registration failed; could not allocate memory
* IBMF_NO_RESOURCES - registration failed due to a resource issue
* IBMF_BUSY - registration failed; too many clients registered
* for this port
* IBMF_TRANSPORT_FAILURE - failure with underlying transport framework
* IBMF_INVALID_ARG - ibmf_saa_handle arg was NULL
*
* The ibmf_saa module maintains a linked list of ports which it knows about.
* For each port, a reference count is kept. When the first client for a
* port registers with ibmf_saa, ibmf_saa registers with ibmf.
* The reference count checking must be serialized to
* ensure that only one client modifies the reference count at a time.
* When a client determines that it is responsible for registering it
* sets the state field to "registering" in the port. Clients registering with
* sa_acess will cv_wait on this field before modifying the reference count.
* Unregistering clients do not need to wait on this field since no one else
* will be registering while they are completing (the port's ref count will
* be greater than 0).
* If ibmf registration fails, the entry is set to "invalid"; we decrement
* the reference count that we just incremented.
*
* WARNING: after decrementing the reference count, NO further access to
* the entry should be performed in the same thread, because invalid entries
* with ref counts of 0 are purged.
*/
/* ARGSUSED */
int
ibmf_sa_session_open(ib_guid_t port_guid, ib_smkey_t sm_key,
ibmf_saa_subnet_event_args_t *event_args, uint_t ibmf_version,
uint_t flags, ibmf_saa_handle_t *ibmf_saa_handle)
{
saa_port_t *saa_portp = NULL;
int status = IBMF_SUCCESS;
saa_client_data_t *saa_client = NULL;
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_sa_session_open_start, IBMF_TNF_TRACE, "",
"ibmf_sa_session_open() enter\n");
if (ibmf_version != IBMF_VERSION) {
IBMF_TRACE_0(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_sa_session_open_err, IBMF_TNF_ERROR, "",
"ibmf_sa_session_open: Bad Version\n");
status = IBMF_BAD_VERSION;
goto bail;
}
if (ibmf_saa_handle == NULL) {
IBMF_TRACE_0(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_sa_session_open_err, IBMF_TNF_ERROR, "",
"ibmf_sa_session_open: invalid argument, null pointer\n");
status = IBMF_INVALID_ARG;
goto bail;
}
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_sa_session_open, IBMF_TNF_TRACE, "",
"ibmf_sa_session_open: %s, guid = %016" PRIx64 ", prefix = %016"
PRIx64 "\n", tnf_string, msg, "opening session",
tnf_opaque, guid, port_guid);
/*
* Find a valid entry matching the port guid
* Refcount is immediately incremented
*/
/* acquire list mutex (and keep it locked until after creation) */
mutex_enter(&saa_statep->saa_port_list_mutex);
saa_portp = saa_statep->saa_port_list;
while (saa_portp != NULL) {
if (saa_portp->saa_pt_port_guid == port_guid &&
ibmf_saa_is_valid(saa_portp, B_TRUE) == B_TRUE) {
break;
}
saa_portp = saa_portp->next;
}
if (saa_portp != NULL) {
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_sa_session_open, IBMF_TNF_TRACE, "",
"ibmf_sa_session_open(): %s\n",
tnf_string, msg, "port exists\n");
/* release list mutex */
mutex_exit(&saa_statep->saa_port_list_mutex);
/*
* now add client to existing port
* (will wait till end of ibmf registering)
* Note that the state may have changed in the meantime...
*/
status = ibmf_saa_impl_add_client(saa_portp);
if (status != IBMF_SUCCESS) {
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_sa_session_open_err, IBMF_TNF_ERROR, "",
"ibmf_sa_session_open: %s, status = %d\n",
tnf_string, msg, "ibmf_saa_impl_add_client()"
" failed", tnf_int, status, status);
goto bail;
}
} else {
/* create minimal port entry, non blocking */
status = ibmf_saa_impl_create_port(port_guid, &saa_portp);
if (status != IBMF_SUCCESS) {
/* release list mutex */
mutex_exit(&saa_statep->saa_port_list_mutex);
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_sa_session_open_err, IBMF_TNF_ERROR, "",
"ibmf_sa_session_open: %s, status = %d\n",
tnf_string, msg, "ibmf_saa_impl_create_port()"
" failed", tnf_int, status, status);
goto bail;
}
/* link to list */
saa_portp->next = saa_statep->saa_port_list;
saa_statep->saa_port_list = saa_portp;
/*
* release the list mutex since we now have the minimum amount
* of port data initialized to prevent subsequent clients from
* continuing with registration (they will cv_wait on registe-
* -ring state). We don't want to hold the list mutex since
* other ports may need it and since we're about to make calls
* to functions which may block.
*
* We do not need the port registering mutex since clients will
* not proceed while saa_pt_state ==
* IBMF_SAA_PORT_STATE_REGISTERING.
*/
mutex_exit(&saa_statep->saa_port_list_mutex);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(saa_portp->saa_pt_kstatp))
status = ibmf_saa_impl_init_kstats(saa_portp);
if (status != IBMF_SUCCESS) {
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_sa_session_open_err, IBMF_TNF_ERROR, "",
"ibmf_sa_session_open: %s, status = %d\n",
tnf_string, msg, "could not initialize kstats",
tnf_int, status, status);
ibmf_saa_impl_register_failed(saa_portp);
goto bail;
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*saa_portp))
status = ibmf_saa_impl_register_port(saa_portp);
if (status != IBMF_SUCCESS) {
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_sa_session_open_err, IBMF_TNF_ERROR, "",
"ibmf_sa_session_open: %s, ibmf_status = %d\n",
tnf_string, msg,
"ibmf_saa_impl_register_port failed",
tnf_int, ibmf_status, status);
ibmf_saa_impl_register_failed(saa_portp);
/*
* Note: we don't update kstats as this entry
* will eventually go away...
*/
goto bail;
}
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_sa_session_open, IBMF_TNF_TRACE, "",
"ibmf_sa_session_open: %s, prefix = %016" PRIx64
"\n", tnf_string, msg, "successfully initialized port");
/* mark port as registered */
mutex_enter(&saa_portp->saa_pt_mutex);
/* incremement reference count to account for cpi */
saa_portp->saa_pt_reference_count++;
saa_portp->saa_pt_state = IBMF_SAA_PORT_STATE_READY;
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*saa_portp))
/* kick waiters */
cv_broadcast(&saa_portp->saa_pt_ibmf_reg_cv);
mutex_exit(&saa_portp->saa_pt_mutex);
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_sa_session_open, IBMF_TNF_TRACE, "",
"ibmf_sa_session_open: %s\n", tnf_string, msg,
"port is up. Sending classportinfo request");
ibmf_saa_impl_get_classportinfo(saa_portp);
}
mutex_enter(&saa_portp->saa_pt_kstat_mutex);
IBMF_SAA_ADD32_KSTATS(saa_portp, clients_registered, 1);
mutex_exit(&saa_portp->saa_pt_kstat_mutex);
/* create new client structure */
saa_client = kmem_zalloc(sizeof (saa_client_data_t), KM_SLEEP);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*saa_client))
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_sa_session_open, IBMF_TNF_TRACE, "",
"ibmf_sa_session_open: clientp = %p, subnetp = %p\n",
tnf_opaque, clientp, saa_client,
tnf_opaque, subnetp, saa_portp);
saa_client->saa_client_port = saa_portp;
mutex_init(&saa_client->saa_client_mutex, NULL, MUTEX_DRIVER,
NULL);
cv_init(&saa_client->saa_client_state_cv, NULL, CV_DRIVER, NULL);
cv_init(&saa_client->saa_client_event_cb_cv, NULL, CV_DRIVER, NULL);
IBMF_SAA_SET_CLIENT_SIGNATURE(saa_client);
saa_client->saa_client_state = SAA_CLIENT_STATE_ACTIVE;
saa_client->saa_client_sm_key = sm_key;
*ibmf_saa_handle = (ibmf_saa_handle_t)saa_client;
/* if client is interested in subnet event notifications */
if (event_args != NULL) {
ibmf_saa_add_event_subscriber(saa_client, event_args);
}
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*saa_client))
bail:
/* purge invalid entries */
ibmf_saa_impl_purge();
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_sa_session_open_end,
IBMF_TNF_TRACE, "", "ibmf_sa_session_open() exit\n");
return (status);
}
/*
* ibmf_sa_session_close()
*
* Unregister a consumer of the SA_Access interface
*
* This interface blocks.
*
* Arguments:
* SA_Access handle
*
* Return values:
* IBMF_SUCCESS - unregistration succeeded
* IBMF_FAILURE - unregistration failed for unknown reasons
*
* All outstanding callbacks will be canceled before this function returns.
*
*/
/* ARGSUSED */
int
ibmf_sa_session_close(ibmf_saa_handle_t *ibmf_saa_handle, uint_t flags)
{
saa_client_data_t *client_data = NULL;
saa_port_t *saa_portp = NULL;
int status = IBMF_SUCCESS;
saa_client_data_t *curr_clientp, *prev_clientp;
uint8_t port_state;
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_sa_session_close_start, IBMF_TNF_TRACE, "",
"ibmf_sa_session_close() enter\n");
if (ibmf_saa_handle == NULL) {
IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_sa_session_close_err, IBMF_TNF_ERROR, "",
"ibmf_sa_session_close: %s\n",
tnf_string, msg, "invalid argument, NULL pointer argument");
status = IBMF_INVALID_ARG;
goto bail;
}
/* ibmf_saa_handle is pointer to the client data structure */
client_data = (saa_client_data_t *)*ibmf_saa_handle;
/* sanity check to make sure nothing happened to handle */
if (IBMF_SAA_VERIFY_CLIENT_SIGNATURE(client_data) == B_FALSE) {
IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_sa_session_close_err, IBMF_TNF_ERROR, "",
"ibmf_sa_session_close: %s\n",
tnf_string, msg, "bad handle");
status = IBMF_BAD_HANDLE;
goto bail;
}
saa_portp = client_data->saa_client_port;
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_sa_session_close, IBMF_TNF_TRACE,
"", "ibmf_sa_session_close: saa_portp = %p\n",
tnf_opaque, saa_portp, saa_portp);
mutex_enter(&saa_portp->saa_pt_mutex);
port_state = saa_portp->saa_pt_state;
mutex_exit(&saa_portp->saa_pt_mutex);
/*
* if there are pending async transactions, wait for them to finish
* note that we wait only once, not loop....
* note we test the state outside saa_pt_mutex
*/
mutex_enter(&client_data->saa_client_mutex);
if ((client_data->saa_client_num_pending_trans > 0) &&
(port_state == IBMF_SAA_PORT_STATE_READY)) {
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_sa_session_close, IBMF_TNF_TRACE,
"", "ibmf_sa_session_close: %s, num_pending_trans = %d\n",
tnf_string, msg, "waiting for async callbacks",
tnf_uint, num_pending_trans,
client_data->saa_client_num_pending_trans);
client_data->saa_client_state = SAA_CLIENT_STATE_WAITING;
/*
* we rely on IBMF calling the callback in all cases,
* callback signals cv
*/
cv_wait(&client_data->saa_client_state_cv,
&client_data->saa_client_mutex);
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_sa_session_close,
IBMF_TNF_TRACE, "", "ibmf_sa_session_close: %s\n",
tnf_string, msg, "done waiting");
}
/* mark state as closed so no more event callbacks will be generated */
client_data->saa_client_state = SAA_CLIENT_STATE_CLOSED;
/*
* if there are pending subnet event callbacks wait for them to finish
*/
if (client_data->saa_client_event_cb_num_active > 0) {
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_sa_session_close, IBMF_TNF_TRACE,
"", "ibmf_sa_session_close: %s, num_active_cb = %d\n",
tnf_string, msg, "waiting for event callbacks",
tnf_uint, num_active_cb,
client_data->saa_client_event_cb_num_active);
cv_wait(&client_data->saa_client_event_cb_cv,
&client_data->saa_client_mutex);
}
mutex_exit(&client_data->saa_client_mutex);
mutex_enter(&saa_portp->saa_pt_kstat_mutex);
IBMF_SAA_SUB32_KSTATS(saa_portp, clients_registered, 1);
mutex_exit(&saa_portp->saa_pt_kstat_mutex);
/*
* if client was subscribed for events then remove the callback from the
* list, and possibly unsubscribe from the SA
*/
if (client_data->saa_client_event_cb != NULL) {
/* remove the client from the port's list of clients */
mutex_enter(&saa_portp->saa_pt_event_sub_mutex);
curr_clientp = saa_portp->saa_pt_event_sub_client_list;
prev_clientp = NULL;
while (curr_clientp != NULL) {
if (curr_clientp == client_data) {
break;
}
prev_clientp = curr_clientp;
curr_clientp = curr_clientp->next;
}
/* should have found the client */
ASSERT(curr_clientp != NULL);
if (curr_clientp == NULL) {
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_sa_session_close, IBMF_TNF_ERROR, "",
"ibmf_sa_session_close: %s. ref_count = %d\n",
tnf_string, msg, "could not find client in list",
tnf_opaque, client, client_data);
} else {
if (prev_clientp == NULL) {
saa_portp->saa_pt_event_sub_client_list =
curr_clientp->next;
} else
prev_clientp->next = curr_clientp->next;
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_sa_session_close, IBMF_TNF_TRACE, "",
"ibmf_sa_session_close: %s\n", tnf_string, msg,
"Removed client from event subscriber list");
}
mutex_exit(&saa_portp->saa_pt_event_sub_mutex);
}
/* decrementing refcount is last thing we do on port entry */
mutex_enter(&saa_portp->saa_pt_mutex);
ASSERT(saa_portp->saa_pt_reference_count > 0);
saa_portp->saa_pt_reference_count--;
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_sa_session_close,
IBMF_TNF_TRACE, "",
"ibmf_sa_session_close: ref_count = %d\n",
tnf_uint, port_ref_count,
saa_portp->saa_pt_reference_count);
mutex_exit(&saa_portp->saa_pt_mutex);
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_sa_session_close, IBMF_TNF_TRACE, "",
"ibmf_sa_session_close: %s, clientp = %p\n", tnf_string, msg,
"freeing client memory", tnf_opaque, clientp, *ibmf_saa_handle);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*client_data))
/* destroy client */
mutex_destroy(&client_data->saa_client_mutex);
cv_destroy(&client_data->saa_client_state_cv);
cv_destroy(&client_data->saa_client_event_cb_cv);
IBMF_SAA_CLEAR_CLIENT_SIGNATURE(client_data);
kmem_free(*ibmf_saa_handle, sizeof (saa_client_data_t));
*ibmf_saa_handle = NULL;
bail:
/* purge invalid entries */
ibmf_saa_impl_purge();
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_sa_session_close_end,
IBMF_TNF_TRACE, "", "ibmf_sa_session_close() exit\n");
return (status);
}
/*
* ibmf_sa_access
*
* Retrieve records from the SA given an AttributeID, ComponentMask,
* and a template
*
* This interface blocks if the callback parameter is NULL.
*
* Input Arguments:
* ibmf_saa_handle - handle returned from ibmf_sa_session_open()
* access_args - structure containing various parameters for the query
* flags - unsused
*
* Output Arguments:
* length - size of buffer returned
* result - pointer to buffer of records returned in response.
* Buffer is host-endian, unpacked and can be cast to one
* of the record types in sa_recs.h
* Return values:
* IBMF_SUCCESS - query succeeded
* IBMF_BAD_HANDLE - sa session handle is invalid
* IBMF_BAD_PORT_STATE - port in incorrect state
* IBMF_INVALID_ARG - one of the pointer parameters was NULL
* IBMF_NO_RESOURCES - ibmf could not allocate ib resources or SA returned
* ERR_NO_RESOURCES
* IBMF_TRANS_TIMEOUT - transaction timed out
* IBMF_TRANS_FAILURE - transaction failure
* IBMF_NO_MEMORY - ibmf could not allocate memory
* IBMF_REQ_INVALID - send and recv buffer the same for a sequenced
* transaction or the SA returned an ERR_REQ_INVALID
* IBMF_NO_RECORDS - no records matched query
* IBMF_TOO_MANY_RECORDS- SA returned SA_ERR_TOO_MANY_RECORDS
* IBMF_INVALID_GID - SA returned SA_INVALID_GID
* IBMF_INSUFF_COMPS - SA returned SA_ERR_INSUFFICIENT_COMPS
* IBMF_UNSUPP_METHOD - SA returned MAD_STATUS_UNSUPP_METHOD
* IBMF_UNSUPP_METHOD_ATTR - SA returned MAD_STATUS_UNSUPP_METHOD_ATTR
* IBMF_INVALID_FIELD - SA returned MAD_STATUS_INVALID_FIELD
*
* Upon successful completion, result points to a buffer containing the records.
* length is the size in bytes of the buffer returned in result. If there are
* no records or the call failed the length is 0.
*
* The consumer is responsible for freeing the memory associated with result.
*/
/* ARGSUSED */
int
ibmf_sa_access(ibmf_saa_handle_t ibmf_saa_handle,
ibmf_saa_access_args_t *access_args, uint_t flags, size_t *length,
void **result)
{
int res = IBMF_SUCCESS;
saa_impl_trans_info_t *trans_info;
saa_client_data_t *clientp;
saa_port_t *saa_portp;
IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_sa_access_start, IBMF_TNF_TRACE, "",
"ibmf_sa_access_start() enter. attr_id = 0x%x, access_type ="
" 0x%x, comp_mask = %016" PRIx64 "\n",
tnf_opaque, attr_id, access_args->sq_attr_id,
tnf_opaque, access_type, access_args->sq_access_type,
tnf_opaque, comp_mask, access_args->sq_component_mask);
if ((access_args == NULL) || (length == NULL) || (result == NULL)) {
IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_sa_access_err, IBMF_TNF_ERROR, "",
"ibmf_sa_access: %s\n",
tnf_string, msg, "invalid argument, NULL pointer argument");
res = IBMF_INVALID_ARG;
goto bail;
}
/* sanity check to make sure nothing happened to handle */
if (IBMF_SAA_VERIFY_CLIENT_SIGNATURE(
(saa_client_data_t *)ibmf_saa_handle) == B_FALSE) {
IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_sa_access_err, IBMF_TNF_ERROR, "",
"ibmf_sa_access: %s\n",
tnf_string, msg, "bad handle");
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_sa_access_end, IBMF_TNF_TRACE,
"", "ibmf_sa_access() exit\n");
res = IBMF_BAD_HANDLE;
goto bail;
}
if (access_args->sq_callback == NULL) {
trans_info = kmem_zalloc(sizeof (saa_impl_trans_info_t),
KM_SLEEP);
} else {
trans_info = kmem_zalloc(sizeof (saa_impl_trans_info_t),
KM_NOSLEEP);
if (trans_info == NULL) {
IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_sa_access_err, IBMF_TNF_ERROR, "",
"ibmf_sa_access: %s\n", tnf_string, msg,
"could not allocate memory for trans_info");
res = IBMF_NO_MEMORY;
goto bail;
}
}
clientp = (saa_client_data_t *)ibmf_saa_handle;
saa_portp = clientp->saa_client_port;
trans_info->si_trans_client_data = clientp;
trans_info->si_trans_port = saa_portp;
/*
* method is get_multi if attribute is multipath; otherwise method is
* based on query type
*/
if (access_args->sq_attr_id == SA_MULTIPATHRECORD_ATTRID) {
if (access_args->sq_access_type != IBMF_SAA_RETRIEVE) {
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_sa_access_err, IBMF_TNF_ERROR, "",
"ibmf_sa_access: %s, access_type = 0x%x\n",
tnf_string, msg, "access_type for multi-path"
" records must be IBMF_SAA_RETRIEVE",
tnf_opaque, access_type,
access_args->sq_access_type);
kmem_free(trans_info, sizeof (saa_impl_trans_info_t));
res = IBMF_REQ_INVALID;
goto bail;
}
trans_info->si_trans_method = SA_SUBN_ADM_GET_MULTI;
} else if (access_args->sq_attr_id == SA_TRACERECORD_ATTRID) {
if (access_args->sq_access_type != IBMF_SAA_RETRIEVE) {
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_sa_access_err, IBMF_TNF_ERROR, "",
"ibmf_sa_access: %s, access_type = 0x%x\n",
tnf_string, msg, "access_type for trace"
" records must be IBMF_SAA_RETRIEVE",
tnf_opaque, access_type,
access_args->sq_access_type);
kmem_free(trans_info, sizeof (saa_impl_trans_info_t));
res = IBMF_REQ_INVALID;
goto bail;
}
trans_info->si_trans_method = SA_SUBN_ADM_GET_TRACE_TABLE;
} else {
switch (access_args->sq_access_type) {
case IBMF_SAA_RETRIEVE:
trans_info->si_trans_method =
SA_SUBN_ADM_GET_TABLE;
break;
case IBMF_SAA_UPDATE:
trans_info->si_trans_method = SA_SUBN_ADM_SET;
break;
case IBMF_SAA_DELETE:
trans_info->si_trans_method =
SA_SUBN_ADM_DELETE;
break;
default:
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_sa_access_err, IBMF_TNF_ERROR, "",
"ibmf_sa_access: %s, access_type = 0x%x\n",
tnf_string, msg, "unknown access_type",
tnf_opaque, access_type,
access_args->sq_access_type);
kmem_free(trans_info,
sizeof (saa_impl_trans_info_t));
res = IBMF_REQ_INVALID;
goto bail;
}
}
trans_info->si_trans_attr_id = access_args->sq_attr_id;
trans_info->si_trans_component_mask = access_args->sq_component_mask;
trans_info->si_trans_template = access_args->sq_template;
trans_info->si_trans_template_length = access_args->sq_template_length;
trans_info->si_trans_callback = access_args->sq_callback;
trans_info->si_trans_callback_arg = access_args->sq_callback_arg;
mutex_enter(&saa_portp->saa_pt_kstat_mutex);
IBMF_SAA_ADD32_KSTATS(saa_portp, outstanding_requests, 1);
IBMF_SAA_ADD32_KSTATS(saa_portp, total_requests, 1);
mutex_exit(&saa_portp->saa_pt_kstat_mutex);
res = ibmf_saa_impl_send_request(trans_info);
if (res != IBMF_SUCCESS) {
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_sa_access_err, IBMF_TNF_ERROR, "",
"ibmf_sa_access: %s, ibmf_status = %d\n",
tnf_string, msg, "ibmf_saa_impl_send_request() failed",
tnf_int, ibmf_status, res);
*length = 0;
*result = NULL;
kmem_free(trans_info, sizeof (saa_impl_trans_info_t));
mutex_enter(&saa_portp->saa_pt_kstat_mutex);
IBMF_SAA_SUB32_KSTATS(saa_portp, outstanding_requests, 1);
IBMF_SAA_ADD32_KSTATS(saa_portp, failed_requests, 1);
if (res == IBMF_TRANS_TIMEOUT)
IBMF_SAA_ADD32_KSTATS(saa_portp, requests_timedout,
1);
mutex_exit(&saa_portp->saa_pt_kstat_mutex);
goto bail;
}
/*
* if async call don't do anything as callback will take care of
* everything; for sync call, copy parameters back to client and free
* trans_info structure
*/
if (access_args->sq_callback == NULL) {
*length = trans_info->si_trans_length;
*result = trans_info->si_trans_result;
res = trans_info->si_trans_status;
mutex_enter(&saa_portp->saa_pt_kstat_mutex);
IBMF_SAA_SUB32_KSTATS(saa_portp, outstanding_requests, 1);
if (res != IBMF_SUCCESS)
IBMF_SAA_ADD32_KSTATS(saa_portp, failed_requests,
1);
if (res == IBMF_TRANS_TIMEOUT)
IBMF_SAA_ADD32_KSTATS(saa_portp, requests_timedout,
1);
mutex_exit(&saa_portp->saa_pt_kstat_mutex);
kmem_free(trans_info, sizeof (saa_impl_trans_info_t));
}
bail:
if (res != IBMF_SUCCESS) {
if (length != NULL)
*length = 0;
if (result != NULL)
*result = NULL;
}
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_sa_access, IBMF_TNF_TRACE,
"", "ibmf_sa_access() exit: result = 0x%x\n",
tnf_opaque, result, res);
return (res);
}
/*
* Helper Functions.
* Ease of use functions so that the consumer doesn't
* have to do the overhead of calling ibmf_sa_access for
* commonly used queries
*/
/*
* ibmf_saa_gid_to_pathrecords
* Given a source gid and a destination gid, return paths
* between the gids.
*
* This interface blocks.
*
* Input Arguments:
* ibmf_saa_handle - handle returned from ibmf_sa_session_open()
* sgid - source gid of path
* dgid - destination gid of path
* p_key - partition of path. This value may be wildcarded with
* IBMF_SAA_PKEY_WC.
* mtu - preferred MTU of the path. This argument may be
* wildcarded with IBMF_SAA_MTU_WC.
* reversible - if B_TRUE, ibmf will query only reversible paths
* see Infiniband Specification table 171
* num_paths - maximum number of paths to return
* num_paths should be checked for the actual number of
* records returned.
* flags - unused
*
* Output Arguments:
* num_paths - actual number of paths returned
* length - size of buffer returned
* result - pointer to buffer of path records returned in response
*
* Return values:
* Error codes are the same as ibmf_sa_access() return values
*
* Upon successful completion, result points to a buffer containing the records.
* length is the size in bytes of the buffer returned in result. If there are
* no records or the call failed the length is 0.
*
* The consumer is responsible for freeing the memory associated with result.
*/
/* ARGSUSED */
int
ibmf_saa_gid_to_pathrecords(ibmf_saa_handle_t ibmf_saa_handle, ib_gid_t sgid,
ib_gid_t dgid, ib_pkey_t p_key, ib_mtu_t mtu, boolean_t reversible,
uint8_t *num_paths, uint_t flags, size_t *length, sa_path_record_t **result)
{
sa_path_record_t path_record;
uint64_t comp_mask;
int res;
ibmf_saa_access_args_t access_args;
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_saa_gid_to_pathrecords_start, IBMF_TNF_TRACE, "",
"ibmf_saa_gid_to_pathrecords() enter\n");
/*
* check num_paths pointer here since we dereference before calling
* ibmf_sa_access
*/
if (num_paths == NULL) {
IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_saa_gid_to_pathrecords_err, IBMF_TNF_ERROR, "",
"ibmf_saa_gid_to_pathrecords: %s\n",
tnf_string, msg, "invalid argument, NULL pointer argument");
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_saa_gid_to_pathrecords_end, IBMF_TNF_TRACE,
"", "ibmf_saa_gid_to_pathrecords() exit\n");
if (length != NULL)
*length = 0;
if (result != NULL)
*result = NULL;
return (IBMF_INVALID_ARG);
}
/* check valid handle; in non-debug system ibmf_sa_access() will fail */
ASSERT(ibmf_saa_handle != NULL);
ASSERT(length != NULL);
ASSERT(result != NULL);
*length = 0;
*result = NULL;
comp_mask = SA_PR_COMPMASK_SGID | SA_PR_COMPMASK_DGID |
SA_PR_COMPMASK_NUMBPATH;
bzero(&path_record, sizeof (sa_path_record_t));
path_record.SGID = sgid;
path_record.DGID = dgid;
path_record.NumbPath = *num_paths;
if (reversible == B_TRUE) {
path_record.Reversible = 1;
comp_mask |= SA_PR_COMPMASK_REVERSIBLE;
}
if (p_key != IBMF_SAA_PKEY_WC) {
path_record.P_Key = p_key;
comp_mask |= SA_PR_COMPMASK_PKEY;
}
/*
* gid_to_pathrecords specifies greater than or equal to MTU. Path
* records can only do strictly greater. Set the mtu value to one
* less than the mtu parameter. If it's the lowest value possible (256)
* don't do anything and any path mtu will be allowed.
*/
if ((mtu != IBMF_SAA_MTU_WC) && (mtu > IB_MTU_256)) {
path_record.MtuSelector = SA_PR_MTU_SEL_GREATER;
path_record.Mtu = (mtu - 1);
comp_mask |= SA_PR_COMPMASK_MTUSELECTOR | SA_PR_COMPMASK_MTU;
}
access_args.sq_attr_id = SA_PATHRECORD_ATTRID;
access_args.sq_access_type = IBMF_SAA_RETRIEVE;
access_args.sq_component_mask = comp_mask;
access_args.sq_template = &path_record;
access_args.sq_callback = NULL;
access_args.sq_callback_arg = NULL;
res = ibmf_sa_access(ibmf_saa_handle, &access_args, 0, length,
(void **)result);
if (res != IBMF_SUCCESS) {
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
ibmf_saa_gid_to_pathrecords, IBMF_TNF_TRACE, "",
"ibmf_saa_gid_to_pathrecords: %s, ibmf_status = %d\n",
tnf_string, msg, "ibmf_sa_access() failed",
tnf_int, ibmf_status, res);
}
*num_paths = *length / sizeof (sa_path_record_t);
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_saa_gid_to_pathrecords_end, IBMF_TNF_TRACE, "",
"ibmf_saa_gid_to_pathrecords() exit: result = 0x%x\n",
tnf_opaque, result, res);
return (res);
}
/*
* ibmf_saa_paths_from_gid
* Given a source GID, return a path from the source gid
* to every other port on the subnet. It is assumed that the
* subnet is fully connected. Only one path per port on the subnet
* is returned.
*
* This interface blocks.
*
* Input Arguments:
* ibmf_saa_handle - handle returned from ibmf_sa_session_open()
* sgid - source gid of path
* pkey - paritition of path. This value may be wildcarded with
* IBMF_SAA_PKEY_WC.
* reversible - if B_TRUE, ibmf will query only reversible paths;
* see Infiniband Specification table 171
* flags - unused
*
* Output Arguments:
* num_paths - number of paths returned
* length - size of buffer returned
* result - pointer to buffer of path records returned in response
*
* Return values:
* Error codes are the same as ibmf_sa_access() return values
*
* Upon successful completion, result points to a buffer containing the records.
* and num_records is the number of path records returned. length is the size
* in bytes of the buffer returned in result. If there are no records or the
* call failed the length is 0.
*
* The consumer is responsible for freeing the memory associated with result.
*/
/* ARGSUSED */
int
ibmf_saa_paths_from_gid(ibmf_saa_handle_t ibmf_saa_handle, ib_gid_t sgid,
ib_pkey_t p_key, boolean_t reversible, uint_t flags, uint_t *num_paths,
size_t *length, sa_path_record_t **result)
{
sa_path_record_t path_record;
uint64_t comp_mask;
int res;
ibmf_saa_access_args_t access_args;
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_saa_paths_from_gid_start, IBMF_TNF_TRACE, "",
"ibmf_saa_paths_from_gid() enter\n");
/* check valid handle; in non-debug system ibmf_sa_access() will fail */
ASSERT(ibmf_saa_handle != NULL);
ASSERT(length != NULL);
ASSERT(result != NULL);
comp_mask = SA_PR_COMPMASK_SGID | SA_PR_COMPMASK_NUMBPATH;
bzero(&path_record, sizeof (sa_path_record_t));
path_record.SGID = sgid;
path_record.NumbPath = 1;
if (reversible == B_TRUE) {
path_record.Reversible = 1;
comp_mask |= SA_PR_COMPMASK_REVERSIBLE;
}
if (p_key != IBMF_SAA_PKEY_WC) {
path_record.P_Key = p_key;
comp_mask |= SA_PR_COMPMASK_PKEY;
}
access_args.sq_attr_id = SA_PATHRECORD_ATTRID;
access_args.sq_access_type = IBMF_SAA_RETRIEVE;
access_args.sq_component_mask = comp_mask;
access_args.sq_template = &path_record;
access_args.sq_callback = NULL;
access_args.sq_callback_arg = NULL;
res = ibmf_sa_access(ibmf_saa_handle, &access_args, 0, length,
(void **)result);
if (res != IBMF_SUCCESS) {
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
ibmf_saa_gid_to_pathrecords, IBMF_TNF_TRACE, "",
"ibmf_saa_gid_to_pathrecords: %s, ibmf_status = %d\n",
tnf_string, msg, "ibmf_sa_access() failed",
tnf_int, ibmf_status, res);
}
*num_paths = *length / sizeof (sa_path_record_t);
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_saa_paths_from_gid_end, IBMF_TNF_TRACE, "",
"ibmf_saa_paths_from_gid() exit: result = 0x%x\n",
tnf_opaque, result, res);
return (res);
}
/*
* ibmf_saa_name_to_service_record:
* Given a service name, return the service records associated
* with it.
*
* This interface blocks.
*
* Input Arguments:
* ibmf_saa_handle - handle returned from ibmf_sa_session_open()
* name - service name, a null terminated string
* p_key - partition that the service is requested on. This
* value may be wildcarded with IBMF_SAA_PKEY_WC.
* flags - unused
*
* Output Arguments:
* num_records - number of service records returned
* length - size of buffer returned
* result - pointer to buffer of service records returned in
* response
* Return values:
* Error codes are the same as ibmf_sa_access() return values
*
* Upon successful completion, result points to a buffer containing the records.
* and num_records is the number of service records returned. length is the
* size in bytes of the buffer returned in result. If there are no records or
* the call failed the length is 0.
*
* The consumer is responsible for freeing the memory associated with result.
*/
/* ARGSUSED */
int
ibmf_saa_name_to_service_record(ibmf_saa_handle_t ibmf_saa_handle,
char *service_name, ib_pkey_t p_key, uint_t flags,
uint_t *num_records, size_t *length, sa_service_record_t **result)
{
sa_service_record_t service_record;
int res;
ibmf_saa_access_args_t access_args;
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_saa_name_to_service_record_start, IBMF_TNF_TRACE, "",
"ibmf_saa_name_to_service_record() enter\n");
/* check valid handle; in non-debug system ibmf_sa_access() will fail */
ASSERT(ibmf_saa_handle != NULL);
ASSERT(num_records != NULL);
ASSERT(length != NULL);
ASSERT(result != NULL);
bzero((void *)&service_record, sizeof (sa_service_record_t));
if (strlen(service_name) >= IB_SVC_NAME_LEN) {
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_saa_name_to_service_record_err, IBMF_TNF_ERROR, "",
"ibmf_saa_gid_to_pathrecords: %s, service_name = %s\n",
tnf_string, msg, "service name too long",
tnf_string, service_name, service_name);
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_saa_name_to_service_record_end, IBMF_TNF_TRACE, "",
"ibmf_saa_name_to_service_record() exit\n");
*num_records = 0;
*length = 0;
*result = NULL;
return (IBMF_REQ_INVALID);
}
/* copy IB_SVC_NAME_LEN bytes, leaving room at end for null char */
(void) strncpy((char *)(service_record.ServiceName), service_name,
IB_SVC_NAME_LEN-1);
if (p_key != IBMF_SAA_PKEY_WC) {
service_record.ServiceP_Key = p_key;
access_args.sq_component_mask = SA_SR_COMPMASK_NAME |
SA_SR_COMPMASK_PKEY;
} else
access_args.sq_component_mask = SA_SR_COMPMASK_NAME;
access_args.sq_attr_id = SA_SERVICERECORD_ATTRID;
access_args.sq_access_type = IBMF_SAA_RETRIEVE;
access_args.sq_template = &service_record;
access_args.sq_callback = NULL;
access_args.sq_callback_arg = NULL;
res = ibmf_sa_access(ibmf_saa_handle, &access_args, 0, length,
(void *)result);
if (res != IBMF_SUCCESS) {
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
ibmf_saa_name_to_service_record, IBMF_TNF_TRACE, "",
"ibmf_saa_name_to_service_record: %s, ibmf_status = %d\n",
tnf_string, msg, "ibmf_sa_access() failed",
tnf_int, ibmf_status, res);
}
*num_records = *length / sizeof (sa_service_record_t);
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_saa_name_to_service_record_end, IBMF_TNF_TRACE, "",
"ibmf_saa_name_to_service_record() exit: result = 0x%x\n",
tnf_opaque, result, res);
return (res);
}
/*
* ibmf_saa_id_to_service_record:
* Given a service id, return the service records associated
* with it.
*
* This interface blocks.
*
* Input Arguments:
* ibmf_saa_handle - handle returned from ibmf_sa_session_open()
* id - service id
* p_key - partition that the service is requested on. This
* value may be wildcarded with IBMF_SAA_PKEY_WC.
* flags - unused
*
* Output Arguments:
* num_records - number of service records returned
* length - size of buffer returned
* result - pointer to buffer of service records returned in
* response
*
* Return values:
* Error codes are the same as ibmf_sa_access() return values
*
* Upon successful completion, result points to a buffer containing the records.
* and num_records is the number of service records returned. length is the
* size in bytes of the buffer returned in result. If there are no records or
* the call failed the length is 0.
*
* The consumer is responsible for freeing the memory associated with result.
*/
/* ARGSUSED */
int
ibmf_saa_id_to_service_record(ibmf_saa_handle_t ibmf_saa_handle,
ib_svc_id_t service_id, ib_pkey_t p_key, uint_t flags, uint_t *num_records,
size_t *length, sa_service_record_t **result)
{
sa_service_record_t service_record;
int res;
ibmf_saa_access_args_t access_args;
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_saa_id_to_service_record_start, IBMF_TNF_TRACE, "",
"ibmf_saa_id_to_service_record() enter\n");
/* check valid handle; in non-debug system ibmf_sa_access() will fail */
ASSERT(ibmf_saa_handle != NULL);
ASSERT(num_records != NULL);
ASSERT(length != NULL);
ASSERT(result != NULL);
bzero((void *)&service_record, sizeof (sa_service_record_t));
service_record.ServiceID = service_id;
if (p_key != IBMF_SAA_PKEY_WC) {
service_record.ServiceP_Key = p_key;
access_args.sq_component_mask = SA_SR_COMPMASK_ID |
SA_SR_COMPMASK_PKEY;
} else
access_args.sq_component_mask = SA_SR_COMPMASK_ID;
access_args.sq_attr_id = SA_SERVICERECORD_ATTRID;
access_args.sq_access_type = IBMF_SAA_RETRIEVE;
access_args.sq_template = &service_record;
access_args.sq_callback = NULL;
access_args.sq_callback_arg = NULL;
res = ibmf_sa_access(ibmf_saa_handle, &access_args, 0, length,
(void **)result);
if (res != IBMF_SUCCESS) {
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
ibmf_saa_id_to_service_record, IBMF_TNF_TRACE, "",
"ibmf_saa_id_to_service_record: %s, ibmf_status = %d\n",
tnf_string, msg, "ibmf_sa_access() failed",
tnf_int, ibmf_status, res);
}
*num_records = *length / sizeof (sa_service_record_t);
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_saa_id_to_service_record_end, IBMF_TNF_TRACE, "",
"ibmf_saa_id_to_service_record() exit: result = 0x%x\n",
tnf_opaque, result, res);
return (res);
}
/*
* ibmf_saa_update_service_record
* Given a pointer to a service record, either insert or delete it
*
* This interface blocks.
*
* Input Arguments:
* ibmf_saa_handle - handle returned from ibmf_sa_session_open()
* service_record - service record is to be inserted or deleted. To
* delete a service record the GID, ID, P_Key, and
* Service Key must match what is in the SA.
* access_type - indicates whether this is an insertion or deletion.
* valid values are IBMF_SAA_UPDATE or IBMF_SAA_DELETE
* flags - unused
*
* Output Arguments
* none
*
* Return values:
* Error codes are the same as ibmf_sa_access() return values
*/
/* ARGSUSED */
int
ibmf_saa_update_service_record(ibmf_saa_handle_t ibmf_saa_handle,
sa_service_record_t *service_record, ibmf_saa_access_type_t access_type,
uint_t flags)
{
size_t length;
void *result;
int res;
uint64_t comp_mask;
ibmf_saa_access_args_t access_args;
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_saa_update_service_record_start, IBMF_TNF_TRACE, "",
"ibmf_saa_update_service_record() enter\n");
/* check valid handle; in non-debug system ibmf_sa_access() will fail */
ASSERT(ibmf_saa_handle != NULL);
if ((access_type != IBMF_SAA_UPDATE) &&
(access_type != IBMF_SAA_DELETE)) {
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_saa_update_service_record_err, IBMF_TNF_ERROR, "",
"ibmf_saa_update_service_record: %s, access_type = 0x%x\n",
tnf_string, msg, "invalid query type",
tnf_opaque, access_type, access_type);
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_saa_update_service_record_end, IBMF_TNF_TRACE, "",
"ibmf_saa_update_service_record() exit\n");
return (IBMF_REQ_INVALID);
}
/*
* call ibmf_sa_access with the following special parameters:
* attrid : service_record
* component_mask : RID fields of service record (GID, ID, and P_key)
* and service key
*/
comp_mask = SA_SR_COMPMASK_ID | SA_SR_COMPMASK_GID |
SA_SR_COMPMASK_PKEY | SA_SR_COMPMASK_KEY;
access_args.sq_attr_id = SA_SERVICERECORD_ATTRID;
access_args.sq_access_type = access_type;
access_args.sq_component_mask = comp_mask;
access_args.sq_template = service_record;
access_args.sq_callback = NULL;
access_args.sq_callback_arg = NULL;
res = ibmf_sa_access(ibmf_saa_handle, &access_args, 0, &length,
&result);
/* if a valid add request, response buffer should be one service rec */
if (res == IBMF_SUCCESS && length > 0) {
if (length > sizeof (sa_service_record_t)) {
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L1,
ibmf_saa_update_service_record, IBMF_TNF_TRACE, "",
"ibmf_saa_update_service_record: %s\n",
tnf_string, msg,
"SA returned more than one record");
}
kmem_free(result, length);
}
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_saa_update_service_record_end, IBMF_TNF_TRACE, "",
"ibmf_saa_update_service_record() exit: result = 0x%x\n",
tnf_opaque, result, res);
return (res);
}