/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
extern saa_state_t *saa_statep;
extern int ibmf_trace_level;
static void
static int
static void
static void
/*
* ibmf_saa_subscribe_events:
* Subscribe or unsubscribe to subnet events for a certain port.
* ibmf_saa_subscribe_events() will send an InformInfo request for each of the
* four notice producer types.
*
* Subscribes generally occur when the first client for a port opens a session
* and when a port with registered ibmf_saa clients transitions to active.
* Subscribes are done as asynchronous, sequenced transactions.
*
* ibmf_saa sends unsubscribe requests when the last client for a port
* unregisters and when an CI_OFFLINE message is received from ibtf (via ibmf).
* For the first case, the unsubscribe is done as an asynchronous, sequenced
* transaction. For the second case, the request is asynchronous, unsequenced.
* This means that the unsubscribes will not be retried. Because the port is
* going away we cannot wait for responses. Unsubscribes are not required
* anyway as the SA will remove subscription records from ports it determines to
* be down.
*
* For subscribe requests, clients are notified that the request failed through
* the event notification mechanism. For unsubscribe requests, clients are not
* notified if the request fails. Therefore, this function returns void.
*
* Input Arguments
* saa_portp pointer to port state structure
* subscribe B_TRUE if request is a Subscribe, B_FALSE if unsubscribe
* unseq_unsubscribe B_TRUE if unsubscribe request should be unsequenced
* (called from CI_OFFLINE event handler)
* B_FALSE if sequenced (wait for response) or for all
* subscribe requests
*
* Output Arguments
* none
*
* Returns
* void
*/
void
{
int res;
"ibmf_saa_subscribe_events() enter\n");
/* subscribes should always be sychronous */
/*
* reset the arrive and success masks to indicate no responses have come
* back; technically only used for subscriptions but reset the values
* anyway
*/
/*
* now subscribe/unsubscribe for each of the notice producer types;
* send_informinfo returns 1 on success, 0 on failure. If the "or" of
* all four results is 0 then none of the informinfo's succeed and we
* should notify the client. If it's not 0, then informinfo_cb will be
* called at least once, taking care of notifying the clients that there
* was a failure.
* For each producer type, send the request only if it's a subscribe or
* if it's an unsubscribe for a subscribe which succeeded
*/
/*
* subscribe for all traps generated by the SM;
*/
/* subscribe for all traps generated by a CA */
/* subscribe for all traps generated by a switch */
/* subscribe for all traps generated by a router */
/* if none of the subscribe requests succeeded notify the clients */
"Could not subscribe for any of the four producer types");
/* all events should have "arrived" */
/* status mask should be 0 since all failed */
/* notify clients if success mask changed */
/* update last mask for next set of subscription requests */
/*
* Sending the four InformInfos is treated as one port client
* reference. Now that all have returned decrement the
* reference count.
*/
}
/*
* for unsequenced unsubscribes, decrement the reference count here
* since no callbacks will ever do it
*/
if (unseq_unsubscribe == B_TRUE) {
/*
* Sending the four InformInfos is treated as one port client
* reference. Now that all have returned decrement the
* reference count.
*/
}
if (notify_clients == B_TRUE) {
}
}
/*
* ibmf_saa_send_informinfo:
*
* Sends an InformInfo request to the SA. There are two types of request,
* Subscribes and Unsubscribes. This function is called from
* ibmf_saa_subscribe_events. See that function's comment for usage of
* subscribe, unseq_unsubscribe booleans.
*
* This function generates a standard ibmf_saa transaction and sends using
* ibmf_saa_impl_send_request(). For asynchronous callbacks, the function
* ibmf_saa_informinfo_cb() will be called.
*
* This function blocks allocating resources, but not waiting for response
* packets.
*
* Input Arguments
* saa_portp pointer to port data
* producer_type InformInfo producer type to subscribe for
* subscribe B_TRUE if subscribe request, B_FALSE if unsubscribe
* unseq_unsubscribe B_TRUE if unsubscribe request should be unsequenced
* (called from CI_OFFLINE event handler)
* B_FALSE if sequenced (wait for response) or for all
* subscribe requests
*
* Output Arguments
* none
*
* Returns
* 1 if the transaction succeeded, 0 if it failed
*/
static int
{
int res;
"ibmf_saa_send_informinfo() enter\n");
"%x, subscribe = %x, unseq_unsubscribe = %x\n",
/* initialize inform_info packet */
else {
}
/* no specific client associated with this transaction */
/*
* if this isn't an unsequenced unsubscribe (the only synchronous
* request) then set up the callback
*/
if (unseq_unsubscribe == B_FALSE) {
/*
* if this is a subscribe, set the producer type so we can know
* which one's failed
*/
}
}
if (res != IBMF_SUCCESS) {
"ibmf_saa_send_informinfo: %s, ibmf_status = %d\n",
res = 0;
} else {
"Request sent successfully");
res = 1;
/*
* if this was an asynchronous transaction (not the unsequenced
* unsubscribe case) return here.
* The callback will clean up everything.
*/
if (unseq_unsubscribe == B_FALSE) {
goto bail;
}
}
/*
* if subscribe transaction failed, update status mask
* to indicate "response"
*/
switch (producer_type) {
break;
break;
break;
break;
default:
"", "ibmf_saa_send_informinfo: %s, "
"producer_type = 0x%x\n",
ASSERT(0);
producer_type_mask = 0;
break;
}
}
bail:
"ibmf_saa_send_informinfo() exit: result = 0x%x\n",
return (res);
}
/*
* ibmf_saa_informinfo_cb:
*
* Called when the asynchronous informinfo request receives its response.
* Checks the status (whether the ibmf_saa was able to subscribe with the SA for
* events) and updates the status mask for the specific producer. If all four
* producer types have arrived then the event clients are notified if there has
* been a change in the status.
*
* Input Arguments
* arg user-specified pointer (points to the current port data)
* length length of payload returned (should be size of informinfo_rec)
* buffer pointer to informinfo response returned (should not be null)
* status status of sa access request
* producer_type for subscriptions, indicates the notice producer type that was
* requested; ignored for unsubscribes
*
* Output Arguments
* none
*
* Returns void
*/
static void
{
/* if producer type is 0 this was an unsubscribe */
if (producer_type == 0) {
"ibmf_saa_informinfo_cb(): %s",
goto bail;
}
/* determine which event it was */
switch (producer_type) {
break;
break;
break;
break;
default:
"", "ibmf_saa_informinfo_cb: %s, "
"producer_type = 0x%x\n",
producer_type_mask = 0;
break;
}
"ibmf_saa_informinfo_cb(): %s, prod_type_mask = 0x%x",
goto bail;
}
/* process response */
"ibmf_saa_informinfo_cb: %s, status = %d,"
" buffer = 0x%p, length = %d\n",
}
/* if all four InformInfo responses have arrived */
"ibmf_saa_informinfo_cb(): %s, success mask = 0x%x,"
" last success mask = 0x%x\n",
/*
* Sending the four InformInfos is treated as one port client
* reference. Now that all have returned decrement the
* reference count.
*/
"ibmf_saa_informinfo_cb(): %s\n",
"success mask different - notifying clients");
/*
* save status mask to give to clients and update last
* mask for next set of subscription requests
*/
}
}
if (notify_clients == B_TRUE) {
}
bail:
}
/*
* ibmf_saa_notify_event_client_task
*
* Calls the event notification callback for a registered saa client. Called
* from ibmf_saa_notify_event_clients() for each client that has registered for
* events. ibmf_saa_notify_event_clients() will dispatch this task on the
* saa_event_taskq so the client's callback can be invoked directly.
*
* Input Arguments
* args pointer to ibmf_saa_event_taskq_args_t
* this function will free memory associated with args
*
* Output Arguments
* none
*
* Returns
* void
*/
static void
{
/* call client's callback (client pointer is ibmf_saa_handle) */
sizeof (ibmf_saa_event_details_t));
/* decrement the callback count and signal a waiting client */
if (client->saa_client_event_cb_num_active == 0) {
}
}
/*
* ibmf_saa_process_subnet_event:
*
* Called when the ibmf_saa is notified of a forwarded notice. Converts the
* notice into an ibmf_saa_event_details structure and calls
* ibmf_saa_notify_event_clients() which will notify each interested client.
*
* Input Arguments
* saa_portp pointer to saa_port data
* notice notice that was forwarded from SA
*
* Output Arguments
* none
*
* Returns
* void
*/
static void
{
"trap_number = 0x%x\n",
/*
* fill in the appropriate fields of event_details depending on
* the trap number
*/
switch (notice->TrapNumber_DeviceID) {
case SM_GID_IN_SERVICE_TRAP:
break;
break;
case SM_MGID_CREATED_TRAP:
break;
case SM_MGID_DESTROYED_TRAP:
break;
case SM_CAP_MASK_CHANGED_TRAP:
break;
break;
default:
/*
* do nothing if it's not one of the traps we care about
*/
IBMF_TNF_TRACE, "",
"ibmf_saa_process_subnet_event() exit: %s\n",
"not one of the six ibmf_saa subnet events");
return;
}
NULL);
}
/*
* ibmf_saa_notify_event_clients:
*
* Called when a trap for one of the six saa subnet events arrives or there is a
* change in the status of event subscriptions. Searches the list of clients
* with callbacks and dispatches a taskq thread to notify the client that the
* event occured.
*
* If some subscription request fails and a subsequent client registers for
* events that client needs to know that it may not receive all events. To
* facilitate this, notify_event_clients() takes an optional parameter which
* specifies a specific client. If registering_client is non-NULL only this
* client is notified. If the parameter is NULL, all clients in the list are
* notified.
*
* Input Arguments
* saa_portp pointer to saa_port data
* event_details pointer to ibmf_saa_event_details_t for this event
* subnet_event type of event that occured
* registering_client pointer to client_data_t if notification should go to a
* specific client; NULL if notification should go to all
* clients which subscribed for events
*
* Output Arguments
* none
*
* Returns
* none
*/
void
{
int status;
if (registering_client != NULL)
else
sizeof (ibmf_saa_event_taskq_args_t), KM_NOSLEEP);
if (event_taskq_args == NULL) {
"", "ibmf_saa_notify_event_clients: %s, client = "
"could not allocate memory for taskq args",
/*
* if a particular client was not specified continue
* processing the client list
*/
if (registering_client == NULL)
else
continue;
}
/*
* each task needs its own pointer, the task will free
* up this memory
*/
sizeof (ibmf_saa_event_details_t), KM_NOSLEEP);
"", "ibmf_saa_notify_event_clients: %s, client = "
"could not allocate memory for taskq event details",
sizeof (ibmf_saa_event_taskq_args_t));
/*
* if a particular client was not specified continue
* processing the client list
*/
client =
continue;
}
/*
* don't generate callbacks if client is not active
* (it's probably closing the session)
*/
"", "ibmf_saa_notify_event_clients: %s, client = "
"client state not active",
sizeof (ibmf_saa_event_details_t));
sizeof (ibmf_saa_event_taskq_args_t));
/*
* if a particular client was not specified continue
* processing the client list
*/
client =
continue;
}
/*
* increment the callback count so the client cannot close the
* session while callbacks are active
*/
sizeof (ibmf_saa_event_details_t));
/* dispatch taskq thread to notify client */
if (status == 0) {
"", "ibmf_saa_notify_event_clients: %s, client = "
"0x%x\n",
sizeof (ibmf_saa_event_details_t));
sizeof (ibmf_saa_event_taskq_args_t));
/*
* decrement the callback count and signal a waiting
* client
*/
if (client->saa_client_event_cb_num_active == 0) {
}
} else {
"", "ibmf_saa_notify_event_clients: %s, client = "
"0x%x\n",
}
/*
* if a particular client was not specified continue processing
* the client list
*/
}
}
/*
* ibmf_saa_report_cb:
*
* Called when a forwarded notice Report is received by ibmf_saa from the SA.
* Converts the Report into an ib_mad_notice_t and calls
* ibmf_saa_notify_event_clients() which will notify each subscribed ibmf_saa
* client. Also sends a response to the report to acknowledge to the SA that
* this port is still up.
*
* This is the registered async callback with ibmf. Only Reports should come
* through this interface as all other transactions with ibmf_saa are sequenced
* (ibmf_saa makes the initial request).
*
* This function cannot block since it is called from an ibmf callback.
*
* Input Arguments
* ibmf_handle ibmf handle
* msgp pointer to ibmf_msg_t
* args pointer to saa_port data
*
* Output Arguments
* none
*
* Returns
* none
*/
void
void *args)
{
int ibmf_status;
int status;
/* check whether this portp is still valid */
while (saa_port_list_entry != NULL) {
if (saa_port_list_entry == saa_portp) {
break;
}
}
if (port_valid == B_FALSE) {
"ibmf_saa_report_cb: %s, saa_port = 0x%p\n",
goto bail;
}
/* drop packet if status is bad */
(req_mad_hdr == NULL) ||
"ibmf_saa_report_cb: %s, msg_status = 0x%x,"
" req_mad_hdr = 0x%p, mad_status = 0x%x\n",
goto bail;
}
/* drop packet if class version is not correct */
"ibmf_saa_report_cb: %s, msg_class_ver = 0x%x,"
" ibmf_saa_class_ver = 0x%x\n",
goto bail;
}
/*
* only care about notice reports(); should not get any other type
* of method or attribute
*/
"ibmf_saa_report_cb: %s, attr_id = 0x%x, "
"method = 0x%x\n",
goto bail;
}
/*
* unpack the data into a ib_mad_notice_t; the data details are left
* as packed data and will be unpacked by process_subnet_event()
* is_get_resp parameter is set to B_TRUE since cl_data_len will
* probably be set to 200 bytes by ibmf (it's not an RMPP trans)
*/
if (status != IBMF_SUCCESS) {
"ibmf_saa_report_cb: %s, status = %d",
goto bail;
}
/* send ReportResp */
/* only headers are needed */
/*
* report_cb cannot block because it's in the context of an ibmf
* callback. So the response needs to be sent asynchronously.
* ibmf_saa_async_cb is an appropriate callback to use for the response.
* Set up a trans_info structure as saa_async_cb expects. But don't use
* ibmf_saa_impl_send_request() to send the response since that function
* does unncessary steps in this case (like allocating a new ibmf msg).
* Only the si_trans_port field needs to be filled in.
*/
if (trans_info == NULL) {
"ibmf_saa_report_cb: %s",
goto bail;
}
sizeof (ibmf_retrans_t));
trans_info, 0);
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_saa_report_cb: %s, msg_status = 0x%x\n",
} else {
"ibmf_saa_report_cb: %s\n",
}
bail:
if (response_sent == B_FALSE) {
}
"ibmf_saa_report_cb() exit\n");
}
/*
* ibmf_saa_add_event_subscriber:
*
* Adds an interested client to the list of subscribers for events for a port.
* If it's the first client, generates the subscription requests.
* This function must only be called if event_args is not null
*
* Input Arguments
*
* client pointer to client data (client->saa_port should be set)
* event_args pointer to event_args passed in from client (non-NULL)
*
* Output Arguments
* none
*
* Returns
* void
*/
void
{
"ibmf_saa_add_event_subscriber() enter\n");
/* event_args should be checked before calling this function */
/* don't add client if no callback function is specified */
return;
/*
* insert this client onto the list; this list is used when a
* Report arrives to call each client's callback
*/
"ibmf_saa_add_event_subscriber: %s, client = 0x%x\n",
else {
}
if (first_client == B_TRUE) {
/*
* increment the reference count by one to account for
* the subscription requests. All four InformInfo's are
* sent as one port client reference.
*/
/* subscribe for subnet events */
} else if (producer_status_mask != IBMF_SAA_PORT_EVENT_SUB_ALL_ARRIVE) {
/*
* if this is not the first client and the producer status mask
* is not all success, generate a callback to indicate to the
* client that not all events will be forwarded
*/
}
"ibmf_saa_add_event_subscriber() exit\n");
}