#include <sys/ib/mgt/ibmf/ibmf_saa_impl.h>
#include <sys/ib/mgt/ibmf/ibmf_saa_utils.h>
extern saa_state_t *saa_statep;
extern int ibmf_trace_level;
static void
ibmf_saa_informinfo_cb(void *arg, size_t length, char *buffer,
int status, uint32_t producer_type);
static int
ibmf_saa_send_informinfo(saa_port_t *saa_portp, uint32_t producer_type,
boolean_t subscribe, boolean_t unseq_unsubscribe);
static void
ibmf_saa_notify_event_client_task(void *args);
static void
ibmf_saa_process_subnet_event(saa_port_t *saa_portp, ib_mad_notice_t *notice);
void
ibmf_saa_subscribe_events(saa_port_t *saa_portp, boolean_t subscribe,
boolean_t unseq_unsubscribe)
{
int res;
ibmf_saa_event_details_t event_details;
boolean_t notify_clients = B_FALSE;
uint8_t success_mask;
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_saa_subscribe_events_start, IBMF_TNF_TRACE, "",
"ibmf_saa_subscribe_events() enter\n");
ASSERT((subscribe == B_FALSE) || (unseq_unsubscribe == B_FALSE));
mutex_enter(&saa_portp->saa_pt_event_sub_mutex);
success_mask = saa_portp->saa_pt_event_sub_success_mask;
saa_portp->saa_pt_event_sub_arrive_mask = 0;
saa_portp->saa_pt_event_sub_success_mask = 0;
mutex_exit(&saa_portp->saa_pt_event_sub_mutex);
if ((success_mask & IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SM) ||
(subscribe == B_TRUE))
res = ibmf_saa_send_informinfo(saa_portp,
MAD_INFORMINFO_NODETYPE_SUBNET_MANAGEMENT, subscribe,
unseq_unsubscribe);
if ((success_mask & IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_CA) ||
(subscribe == B_TRUE))
res |= ibmf_saa_send_informinfo(saa_portp,
MAD_INFORMINFO_NODETYPE_CA, subscribe, unseq_unsubscribe);
if ((success_mask & IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SWITCH) ||
(subscribe == B_TRUE))
res |= ibmf_saa_send_informinfo(saa_portp,
MAD_INFORMINFO_NODETYPE_SWITCH, subscribe,
unseq_unsubscribe);
if ((success_mask & IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_ROUTER) ||
(subscribe == B_TRUE))
res |= ibmf_saa_send_informinfo(saa_portp,
MAD_INFORMINFO_NODETYPE_ROUTER, subscribe,
unseq_unsubscribe);
if ((res == 0) && (subscribe == B_TRUE)) {
IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_saa_subscribe_events_err, IBMF_TNF_ERROR, "",
"ibmf_saa_subscribe_events: %s\n", tnf_string, msg,
"Could not subscribe for any of the four producer types");
mutex_enter(&saa_portp->saa_pt_event_sub_mutex);
ASSERT(saa_portp->saa_pt_event_sub_arrive_mask ==
IBMF_SAA_PORT_EVENT_SUB_ALL_ARRIVE);
ASSERT(saa_portp->saa_pt_event_sub_success_mask == 0);
if (saa_portp->saa_pt_event_sub_last_success_mask !=
saa_portp->saa_pt_event_sub_success_mask)
notify_clients = B_TRUE;
saa_portp->saa_pt_event_sub_last_success_mask =
saa_portp->saa_pt_event_sub_arrive_mask = 0;
mutex_exit(&saa_portp->saa_pt_event_sub_mutex);
mutex_enter(&saa_portp->saa_pt_mutex);
ASSERT(saa_portp->saa_pt_reference_count > 0);
saa_portp->saa_pt_reference_count--;
mutex_exit(&saa_portp->saa_pt_mutex);
}
if (unseq_unsubscribe == B_TRUE) {
mutex_enter(&saa_portp->saa_pt_mutex);
ASSERT(saa_portp->saa_pt_reference_count > 0);
saa_portp->saa_pt_reference_count--;
mutex_exit(&saa_portp->saa_pt_mutex);
}
if (notify_clients == B_TRUE) {
bzero(&event_details, sizeof (ibmf_saa_event_details_t));
ibmf_saa_notify_event_clients(saa_portp, &event_details,
IBMF_SAA_EVENT_SUBSCRIBER_STATUS_CHG, NULL);
}
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_subscribe_events_end,
IBMF_TNF_TRACE, "", "ibmf_saa_subscribe_events() exit\n");
}
static int
ibmf_saa_send_informinfo(saa_port_t *saa_portp, uint32_t producer_type,
boolean_t subscribe, boolean_t unseq_unsubscribe)
{
ib_mad_informinfo_t inform_info;
saa_impl_trans_info_t *trans_info;
int res;
uint8_t producer_type_mask;
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_saa_send_informinfo_start, IBMF_TNF_TRACE, "",
"ibmf_saa_send_informinfo() enter\n");
IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_saa_send_informinfo,
IBMF_TNF_TRACE, "", "ibmf_saa_send_informinfo: %s, producer_type ="
"%x, subscribe = %x, unseq_unsubscribe = %x\n",
tnf_string, msg, "Sending informinfo request",
tnf_opaque, producer_type, producer_type,
tnf_int, subscribe, subscribe,
tnf_int, unseq_unsubscribe, unseq_unsubscribe);
bzero(&inform_info, sizeof (ib_mad_informinfo_t));
inform_info.LIDRangeBegin = MAD_INFORMINFO_ALL_ENDPORTS_RANGE;
inform_info.IsGeneric = MAD_INFORMINFO_FORWARD_GENERIC;
if (subscribe == B_TRUE)
inform_info.Subscribe = MAD_INFORMINFO_SUBSCRIBE;
else {
inform_info.Subscribe = MAD_INFORMINFO_UNSUBSCRIBE;
inform_info.QPN = saa_portp->saa_pt_qpn;
}
inform_info.Type = MAD_INFORMINFO_TRAP_TYPE_FORWARD_ALL;
inform_info.TrapNumber_DeviceID =
MAD_INFORMINFO_TRAP_NUMBER_FORWARD_ALL;
inform_info.ProducerType_VendorID = producer_type;
trans_info = kmem_zalloc(sizeof (saa_impl_trans_info_t), KM_SLEEP);
trans_info->si_trans_client_data = NULL;
trans_info->si_trans_port = saa_portp;
trans_info->si_trans_method = SA_SUBN_ADM_SET;
trans_info->si_trans_attr_id = SA_INFORMINFO_ATTRID;
trans_info->si_trans_component_mask = 0;
trans_info->si_trans_template = &inform_info;
trans_info->si_trans_template_length = sizeof (ib_mad_informinfo_t);
trans_info->si_trans_unseq_unsubscribe = unseq_unsubscribe;
if (unseq_unsubscribe == B_FALSE) {
trans_info->si_trans_sub_callback =
ibmf_saa_informinfo_cb;
trans_info->si_trans_callback_arg = saa_portp;
if (subscribe == B_TRUE) {
trans_info->si_trans_sub_producer_type = producer_type;
}
}
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_saa_send_informinfo, IBMF_TNF_ERROR, "",
"ibmf_saa_send_informinfo: %s, ibmf_status = %d\n",
tnf_string, msg, "ibmf_saa_impl_send_request() failed",
tnf_int, ibmf_status, res);
res = 0;
} else {
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_saa_send_informinfo, IBMF_TNF_TRACE, "",
"ibmf_saa_send_informinfo: %s\n", tnf_string, msg,
"Request sent successfully");
res = 1;
if (unseq_unsubscribe == B_FALSE) {
goto bail;
}
}
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);
mutex_exit(&saa_portp->saa_pt_kstat_mutex);
if ((res == 0) && (subscribe == B_TRUE)) {
mutex_enter(&saa_portp->saa_pt_event_sub_mutex);
saa_portp->saa_pt_event_sub_arrive_mask = 0;
saa_portp->saa_pt_event_sub_success_mask = 0;
switch (producer_type) {
case MAD_INFORMINFO_NODETYPE_CA:
producer_type_mask =
IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_CA;
break;
case MAD_INFORMINFO_NODETYPE_SWITCH:
producer_type_mask =
IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SWITCH;
break;
case MAD_INFORMINFO_NODETYPE_ROUTER:
producer_type_mask =
IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_ROUTER;
break;
case MAD_INFORMINFO_NODETYPE_SUBNET_MANAGEMENT:
producer_type_mask =
IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SM;
break;
default:
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_saa_send_informinfo, IBMF_TNF_ERROR,
"", "ibmf_saa_send_informinfo: %s, "
"producer_type = 0x%x\n",
tnf_string, msg, "Unknown producer type",
tnf_opaque, producer_type, producer_type);
ASSERT(0);
producer_type_mask = 0;
break;
}
saa_portp->saa_pt_event_sub_arrive_mask |= producer_type_mask;
mutex_exit(&saa_portp->saa_pt_event_sub_mutex);
}
bail:
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_saa_send_informinfo_end, IBMF_TNF_TRACE, "",
"ibmf_saa_send_informinfo() exit: result = 0x%x\n",
tnf_opaque, result, res);
return (res);
}
static void
ibmf_saa_informinfo_cb(void *arg, size_t length, char *buffer,
int status, uint32_t producer_type)
{
saa_port_t *saa_portp;
uint8_t producer_type_mask;
boolean_t notify_clients;
uint8_t event_status_mask;
ibmf_saa_event_details_t event_details;
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_saa_informinfo_cb_start,
IBMF_TNF_TRACE, "", "ibmf_saa_informinfo_cb() enter: producer_type "
"= 0x%x, status = %d\n", tnf_opaque, producer_type, producer_type,
tnf_int, status, status);
saa_portp = (saa_port_t *)arg;
notify_clients = B_FALSE;
if (producer_type == 0) {
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_saa_informinfo_cb, IBMF_TNF_TRACE, "",
"ibmf_saa_informinfo_cb(): %s",
tnf_string, msg, "handling unsubscribe");
if (buffer != NULL)
kmem_free(buffer, length);
goto bail;
}
switch (producer_type) {
case MAD_INFORMINFO_NODETYPE_CA:
producer_type_mask =
IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_CA;
break;
case MAD_INFORMINFO_NODETYPE_SWITCH:
producer_type_mask =
IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SWITCH;
break;
case MAD_INFORMINFO_NODETYPE_ROUTER:
producer_type_mask =
IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_ROUTER;
break;
case MAD_INFORMINFO_NODETYPE_SUBNET_MANAGEMENT:
producer_type_mask =
IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SM;
break;
default:
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_saa_send_informinfo_cb, IBMF_TNF_ERROR,
"", "ibmf_saa_informinfo_cb: %s, "
"producer_type = 0x%x\n",
tnf_string, msg, "Unknown producer type",
tnf_opaque, producer_type, producer_type);
producer_type_mask = 0;
break;
}
mutex_enter(&saa_portp->saa_pt_event_sub_mutex);
if (saa_portp->saa_pt_event_sub_arrive_mask & producer_type_mask) {
mutex_exit(&saa_portp->saa_pt_event_sub_mutex);
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
ibmf_saa_informinfo_cb, IBMF_TNF_TRACE, "",
"ibmf_saa_informinfo_cb(): %s, prod_type_mask = 0x%x",
tnf_string, msg, "Received duplicate response",
tnf_opaque, producer_type_mask, producer_type_mask);
if (buffer != NULL)
kmem_free(buffer, length);
goto bail;
}
saa_portp->saa_pt_event_sub_arrive_mask |= producer_type_mask;
if ((status != IBMF_SUCCESS) || (buffer == NULL)) {
IBMF_TRACE_4(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_saa_informinfo_cb, IBMF_TNF_ERROR, "",
"ibmf_saa_informinfo_cb: %s, status = %d,"
" buffer = 0x%p, length = %d\n",
tnf_string, msg, "could not get informinfo resp",
tnf_int, status, status, tnf_opaque, buffer, buffer,
tnf_uint, length, length);
} else if (buffer != NULL) {
kmem_free(buffer, length);
saa_portp->saa_pt_event_sub_success_mask |= producer_type_mask;
}
if (saa_portp->saa_pt_event_sub_arrive_mask ==
IBMF_SAA_PORT_EVENT_SUB_ALL_ARRIVE) {
IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_saa_informinfo_cb, IBMF_TNF_TRACE, "",
"ibmf_saa_informinfo_cb(): %s, success mask = 0x%x,"
" last success mask = 0x%x\n",
tnf_string, msg, "all informinfo responses have arrived",
tnf_opaque, success_mask,
saa_portp->saa_pt_event_sub_success_mask,
tnf_opaque, last_success_mask,
saa_portp->saa_pt_event_sub_last_success_mask);
mutex_enter(&saa_portp->saa_pt_mutex);
ASSERT(saa_portp->saa_pt_reference_count > 0);
saa_portp->saa_pt_reference_count--;
mutex_exit(&saa_portp->saa_pt_mutex);
if (saa_portp->saa_pt_event_sub_last_success_mask !=
saa_portp->saa_pt_event_sub_success_mask) {
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2,
ibmf_saa_informinfo_cb, IBMF_TNF_TRACE, "",
"ibmf_saa_informinfo_cb(): %s\n",
tnf_string, msg,
"success mask different - notifying clients");
event_status_mask =
saa_portp->saa_pt_event_sub_last_success_mask =
saa_portp->saa_pt_event_sub_success_mask;
notify_clients = B_TRUE;
}
}
mutex_exit(&saa_portp->saa_pt_event_sub_mutex);
if (notify_clients == B_TRUE) {
bzero(&event_details, sizeof (ibmf_saa_event_details_t));
event_details.ie_producer_event_status_mask =
event_status_mask;
ibmf_saa_notify_event_clients(saa_portp, &event_details,
IBMF_SAA_EVENT_SUBSCRIBER_STATUS_CHG, NULL);
}
bail:
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_saa_informinfo_cb_end,
IBMF_TNF_TRACE, "", "ibmf_saa_informinfo_cb() exit\n");
}
static void
ibmf_saa_notify_event_client_task(void *args)
{
ibmf_saa_event_taskq_args_t *event_taskq_args;
saa_client_data_t *client;
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_saa_notify_event_client_task_start,
IBMF_TNF_TRACE, "", "ibmf_saa_notify_event_client_task() enter\n");
event_taskq_args = (ibmf_saa_event_taskq_args_t *)args;
client = event_taskq_args->et_client;
(event_taskq_args->et_callback)((ibmf_saa_handle_t)client,
event_taskq_args->et_subnet_event,
event_taskq_args->et_event_details,
event_taskq_args->et_callback_arg);
kmem_free(event_taskq_args->et_event_details,
sizeof (ibmf_saa_event_details_t));
kmem_free(event_taskq_args, sizeof (ibmf_saa_event_taskq_args_t));
mutex_enter(&client->saa_client_mutex);
client->saa_client_event_cb_num_active--;
if (client->saa_client_event_cb_num_active == 0) {
cv_signal(&client->saa_client_event_cb_cv);
}
mutex_exit(&client->saa_client_mutex);
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_saa_notify_event_client_task_end,
IBMF_TNF_TRACE, "", "ibmf_saa_notify_event_client_task() exit\n");
}
static void
ibmf_saa_process_subnet_event(saa_port_t *saa_portp, ib_mad_notice_t *notice)
{
ibmf_saa_event_details_t event_details;
sm_trap_64_t trap_data_details;
sm_trap_144_t cap_mask_trap_data_details;
sm_trap_145_t sys_img_trap_data_details;
ibmf_saa_subnet_event_t subnet_event;
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_saa_process_subnet_event_start,
IBMF_TNF_TRACE, "", "ibmf_saa_process_subnet_event() enter: "
"trap_number = 0x%x\n",
tnf_opaque, trap_number, notice->TrapNumber_DeviceID);
bzero(&event_details, sizeof (ibmf_saa_event_details_t));
switch (notice->TrapNumber_DeviceID) {
case SM_GID_IN_SERVICE_TRAP:
ibmf_saa_gid_trap_parse_buffer(notice->DataDetails,
&trap_data_details);
event_details.ie_gid = trap_data_details.GIDADDR;
subnet_event = IBMF_SAA_EVENT_GID_AVAILABLE;
break;
case SM_GID_OUT_OF_SERVICE_TRAP:
ibmf_saa_gid_trap_parse_buffer(notice->DataDetails,
&trap_data_details);
event_details.ie_gid = trap_data_details.GIDADDR;
subnet_event = IBMF_SAA_EVENT_GID_UNAVAILABLE;
break;
case SM_MGID_CREATED_TRAP:
ibmf_saa_gid_trap_parse_buffer(notice->DataDetails,
&trap_data_details);
event_details.ie_gid = trap_data_details.GIDADDR;
subnet_event = IBMF_SAA_EVENT_MCG_CREATED;
break;
case SM_MGID_DESTROYED_TRAP:
ibmf_saa_gid_trap_parse_buffer(notice->DataDetails,
&trap_data_details);
event_details.ie_gid = trap_data_details.GIDADDR;
subnet_event = IBMF_SAA_EVENT_MCG_DELETED;
break;
case SM_CAP_MASK_CHANGED_TRAP:
ibmf_saa_capmask_chg_trap_parse_buffer(
notice->DataDetails, &cap_mask_trap_data_details);
event_details.ie_lid =
cap_mask_trap_data_details.LIDADDR;
event_details.ie_capability_mask =
cap_mask_trap_data_details.CAPABILITYMASK;
subnet_event = IBMF_SAA_EVENT_CAP_MASK_CHG;
break;
case SM_SYS_IMG_GUID_CHANGED_TRAP:
ibmf_saa_sysimg_guid_chg_trap_parse_buffer(
notice->DataDetails, &sys_img_trap_data_details);
event_details.ie_lid =
sys_img_trap_data_details.LIDADDR;
event_details.ie_sysimg_guid =
sys_img_trap_data_details.SYSTEMIMAGEGUID;
subnet_event = IBMF_SAA_EVENT_SYS_IMG_GUID_CHG;
break;
default:
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_saa_process_subnet_event_end,
IBMF_TNF_TRACE, "",
"ibmf_saa_process_subnet_event() exit: %s\n",
tnf_string, msg,
"not one of the six ibmf_saa subnet events");
return;
}
ibmf_saa_notify_event_clients(saa_portp, &event_details, subnet_event,
NULL);
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_saa_process_subnet_event_end,
IBMF_TNF_TRACE, "", "ibmf_saa_process_subnet_event() exit\n");
}
void
ibmf_saa_notify_event_clients(saa_port_t *saa_portp,
ibmf_saa_event_details_t *event_details,
ibmf_saa_subnet_event_t subnet_event, saa_client_data_t *registering_client)
{
saa_client_data_t *client;
ibmf_saa_event_taskq_args_t *event_taskq_args;
int status;
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_saa_notify_event_clients_start,
IBMF_TNF_TRACE, "", "ibmf_saa_notify_event_clients() enter\n");
mutex_enter(&saa_portp->saa_pt_event_sub_mutex);
if (registering_client != NULL)
client = registering_client;
else
client = saa_portp->saa_pt_event_sub_client_list;
while (client != NULL) {
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*event_taskq_args))
event_taskq_args = kmem_zalloc(
sizeof (ibmf_saa_event_taskq_args_t), KM_NOSLEEP);
if (event_taskq_args == NULL) {
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_saa_notify_event_clients_err, IBMF_TNF_ERROR,
"", "ibmf_saa_notify_event_clients: %s, client = "
"0x%x\n", tnf_string, msg,
"could not allocate memory for taskq args",
tnf_opaque, client, client);
if (registering_client == NULL)
client = client->next;
else
client = NULL;
continue;
}
event_taskq_args->et_event_details = kmem_zalloc(
sizeof (ibmf_saa_event_details_t), KM_NOSLEEP);
if (event_taskq_args->et_event_details == NULL) {
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_saa_notify_event_clients_err, IBMF_TNF_ERROR,
"", "ibmf_saa_notify_event_clients: %s, client = "
"0x%x\n", tnf_string, msg,
"could not allocate memory for taskq event details",
tnf_opaque, client, client);
kmem_free(event_taskq_args,
sizeof (ibmf_saa_event_taskq_args_t));
client =
(registering_client == NULL) ? client->next: NULL;
continue;
}
mutex_enter(&client->saa_client_mutex);
if (client->saa_client_state != SAA_CLIENT_STATE_ACTIVE) {
IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L2,
ibmf_saa_notify_event_clients, IBMF_TNF_TRACE,
"", "ibmf_saa_notify_event_clients: %s, client = "
"0x%x, state = 0x%x\n", tnf_string, msg,
"client state not active",
tnf_opaque, client, client,
tnf_opaque, state, client->saa_client_state);
mutex_exit(&client->saa_client_mutex);
kmem_free(event_taskq_args->et_event_details,
sizeof (ibmf_saa_event_details_t));
kmem_free(event_taskq_args,
sizeof (ibmf_saa_event_taskq_args_t));
client =
(registering_client == NULL) ? client->next: NULL;
continue;
}
client->saa_client_event_cb_num_active++;
mutex_exit(&client->saa_client_mutex);
event_taskq_args->et_client = client;
event_taskq_args->et_subnet_event = subnet_event;
bcopy(event_details, event_taskq_args->et_event_details,
sizeof (ibmf_saa_event_details_t));
event_taskq_args->et_callback = client->saa_client_event_cb;
event_taskq_args->et_callback_arg =
client->saa_client_event_cb_arg;
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*event_taskq_args))
status = taskq_dispatch(saa_statep->saa_event_taskq,
ibmf_saa_notify_event_client_task, event_taskq_args,
KM_NOSLEEP);
if (status == TASKQID_INVALID) {
IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
ibmf_saa_notify_event_clients_err, IBMF_TNF_ERROR,
"", "ibmf_saa_notify_event_clients: %s, client = "
"0x%x\n",
tnf_string, msg, "Could not dispatch event taskq",
tnf_opaque, client, client);
kmem_free(event_taskq_args->et_event_details,
sizeof (ibmf_saa_event_details_t));
kmem_free(event_taskq_args,
sizeof (ibmf_saa_event_taskq_args_t));
mutex_enter(&client->saa_client_mutex);
client->saa_client_event_cb_num_active--;
if (client->saa_client_event_cb_num_active == 0) {
cv_signal(&client->saa_client_event_cb_cv);
}
mutex_exit(&client->saa_client_mutex);
} else {
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_saa_notify_event_clients_err, IBMF_TNF_ERROR,
"", "ibmf_saa_notify_event_clients: %s, client = "
"0x%x\n",
tnf_string, msg, "Dispatched task to notify client",
tnf_opaque, client, client);
}
client = (registering_client == NULL) ? client->next: NULL;
}
mutex_exit(&saa_portp->saa_pt_event_sub_mutex);
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_saa_notify_event_clients_end,
IBMF_TNF_TRACE, "", "ibmf_saa_notify_event_clients() exit\n");
}
void
ibmf_saa_report_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
void *args)
{
ib_mad_hdr_t *req_mad_hdr, *resp_mad_hdr;
saa_port_t *saa_portp, *saa_port_list_entry;
ibmf_retrans_t ibmf_retrans;
int ibmf_status;
ib_mad_notice_t *notice_report;
saa_impl_trans_info_t *trans_info;
boolean_t port_valid;
uint16_t mad_status;
uint16_t attr_id;
boolean_t response_sent = B_FALSE;
size_t length;
int status;
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_saa_report_cb_start,
IBMF_TNF_TRACE, "", "ibmf_saa_report_cb() enter\n");
_NOTE(ASSUMING_PROTECTED(*msgp))
saa_portp = (saa_port_t *)args;
port_valid = B_FALSE;
mutex_enter(&saa_statep->saa_port_list_mutex);
saa_port_list_entry = saa_statep->saa_port_list;
while (saa_port_list_entry != NULL) {
if (saa_port_list_entry == saa_portp) {
port_valid = ibmf_saa_is_valid(saa_portp, B_FALSE);
break;
}
saa_port_list_entry = saa_port_list_entry->next;
}
mutex_exit(&saa_statep->saa_port_list_mutex);
if (port_valid == B_FALSE) {
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
ibmf_saa_report_cb, IBMF_TNF_TRACE, "",
"ibmf_saa_report_cb: %s, saa_port = 0x%p\n",
tnf_string, msg, "port no longer valid",
tnf_opaque, saa_portp, saa_portp);
goto bail;
}
req_mad_hdr = msgp->im_msgbufs_recv.im_bufs_mad_hdr;
if ((msgp->im_msg_status != IBMF_SUCCESS) ||
(req_mad_hdr == NULL) ||
((mad_status = b2h16(req_mad_hdr->Status)) != SA_STATUS_NO_ERROR)) {
IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L1,
ibmf_saa_report_cb, IBMF_TNF_TRACE, "",
"ibmf_saa_report_cb: %s, msg_status = 0x%x,"
" req_mad_hdr = 0x%p, mad_status = 0x%x\n",
tnf_string, msg, "Bad ibmf status",
tnf_opaque, msg_status, msgp->im_msg_status,
tnf_opaque, req_mad_hdr, req_mad_hdr,
tnf_opaque, mad_status,
(req_mad_hdr == NULL ? 0 : mad_status));
goto bail;
}
if (req_mad_hdr->ClassVersion != SAA_MAD_CLASS_VERSION) {
IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L1,
ibmf_saa_report_cb, IBMF_TNF_TRACE, "",
"ibmf_saa_report_cb: %s, msg_class_ver = 0x%x,"
" ibmf_saa_class_ver = 0x%x\n",
tnf_string, msg, "Bad class version",
tnf_opaque, msg_class_ver, req_mad_hdr->ClassVersion,
tnf_opaque, ibmf_saa_class_ver, SAA_MAD_CLASS_VERSION);
goto bail;
}
if (((attr_id = b2h16(req_mad_hdr->AttributeID)) != SA_NOTICE_ATTRID) ||
(req_mad_hdr->R_Method != SA_SUBN_ADM_REPORT)) {
IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L2,
ibmf_saa_report_cb, IBMF_TNF_TRACE, "",
"ibmf_saa_report_cb: %s, attr_id = 0x%x, "
"method = 0x%x\n",
tnf_string, msg, "Unsolicited message not notice report",
tnf_opaque, attr_id, attr_id,
tnf_opaque, method, req_mad_hdr->R_Method);
goto bail;
}
status = ibmf_saa_utils_unpack_payload(
msgp->im_msgbufs_recv.im_bufs_cl_data,
msgp->im_msgbufs_recv.im_bufs_cl_data_len, SA_NOTICE_ATTRID,
(void **)¬ice_report, &length, 0, B_TRUE, KM_NOSLEEP);
if (status != IBMF_SUCCESS) {
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
ibmf_saa_report_cb, IBMF_TNF_TRACE, "",
"ibmf_saa_report_cb: %s, status = %d",
tnf_string, msg, "Could not unpack data",
tnf_int, status, status);
goto bail;
}
ASSERT(length == sizeof (ib_mad_notice_t));
ibmf_saa_process_subnet_event(saa_portp, notice_report);
kmem_free(notice_report, length);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*resp_mad_hdr))
resp_mad_hdr = kmem_zalloc(sizeof (ib_mad_hdr_t), KM_SLEEP);
bcopy(req_mad_hdr, resp_mad_hdr, sizeof (ib_mad_hdr_t));
resp_mad_hdr->R_Method = SA_SUBN_ADM_REPORT_RESP;
msgp->im_msgbufs_send.im_bufs_mad_hdr = resp_mad_hdr;
msgp->im_msgbufs_send.im_bufs_cl_hdr = kmem_zalloc(
msgp->im_msgbufs_recv.im_bufs_cl_hdr_len, KM_SLEEP);
msgp->im_msgbufs_send.im_bufs_cl_hdr_len =
msgp->im_msgbufs_recv.im_bufs_cl_hdr_len;
msgp->im_msgbufs_send.im_bufs_cl_data = NULL;
msgp->im_msgbufs_send.im_bufs_cl_data_len = 0;
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_saa_report_cb_err, IBMF_TNF_TRACE, "",
"ibmf_saa_report_cb: %s",
tnf_string, msg, "could not allocate trans_info structure");
goto bail;
}
trans_info->si_trans_port = saa_portp;
mutex_enter(&saa_portp->saa_pt_mutex);
bcopy(&saa_portp->saa_pt_ibmf_retrans, &ibmf_retrans,
sizeof (ibmf_retrans_t));
saa_portp->saa_pt_num_outstanding_trans++;
mutex_exit(&saa_portp->saa_pt_mutex);
ASSERT(ibmf_handle == saa_portp->saa_pt_ibmf_handle);
ibmf_status = ibmf_msg_transport(ibmf_handle,
saa_portp->saa_pt_qp_handle, msgp, &ibmf_retrans, ibmf_saa_async_cb,
trans_info, 0);
if (ibmf_status != IBMF_SUCCESS) {
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L1,
ibmf_saa_report_cb, IBMF_TNF_TRACE, "",
"ibmf_saa_report_cb: %s, msg_status = 0x%x\n",
tnf_string, msg, "Could not send report response",
tnf_int, ibmf_status, ibmf_status);
mutex_enter(&saa_portp->saa_pt_mutex);
ASSERT(saa_portp->saa_pt_num_outstanding_trans > 0);
saa_portp->saa_pt_num_outstanding_trans--;
mutex_exit(&saa_portp->saa_pt_mutex);
kmem_free(trans_info, sizeof (saa_impl_trans_info_t));
} else {
IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_saa_report_cb, IBMF_TNF_TRACE, "",
"ibmf_saa_report_cb: %s\n",
tnf_string, msg, "Asynchronous Report response sent");
response_sent = B_TRUE;
}
bail:
if (response_sent == B_FALSE) {
ibmf_status = ibmf_free_msg(ibmf_handle, &msgp);
ASSERT(ibmf_status == IBMF_SUCCESS);
}
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_saa_informinfo_cb_end, IBMF_TNF_TRACE, "",
"ibmf_saa_report_cb() exit\n");
}
void
ibmf_saa_add_event_subscriber(saa_client_data_t *client,
ibmf_saa_subnet_event_args_t *event_args)
{
saa_port_t *saa_portp;
boolean_t first_client;
uint8_t producer_status_mask;
ibmf_saa_event_details_t event_details;
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_saa_add_event_subscriber_start, IBMF_TNF_TRACE, "",
"ibmf_saa_add_event_subscriber() enter\n");
ASSERT(event_args != NULL);
if (event_args->is_event_callback == NULL)
return;
saa_portp = client->saa_client_port;
client->saa_client_event_cb = event_args->is_event_callback;
client->saa_client_event_cb_arg = event_args->is_event_callback_arg;
mutex_enter(&saa_portp->saa_pt_event_sub_mutex);
IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
ibmf_sa_session_open, IBMF_TNF_TRACE, "",
"ibmf_saa_add_event_subscriber: %s, client = 0x%x\n",
tnf_string, msg, "Adding client to event subscriber list",
tnf_opaque, client, client);
if (saa_portp->saa_pt_event_sub_client_list == NULL)
first_client = B_TRUE;
else {
first_client = B_FALSE;
producer_status_mask =
saa_portp->saa_pt_event_sub_last_success_mask;
}
client->next = saa_portp->saa_pt_event_sub_client_list;
saa_portp->saa_pt_event_sub_client_list = client;
mutex_exit(&saa_portp->saa_pt_event_sub_mutex);
if (first_client == B_TRUE) {
mutex_enter(&saa_portp->saa_pt_mutex);
saa_portp->saa_pt_reference_count++;
mutex_exit(&saa_portp->saa_pt_mutex);
ibmf_saa_subscribe_events(saa_portp, B_TRUE, B_FALSE);
} else if (producer_status_mask != IBMF_SAA_PORT_EVENT_SUB_ALL_ARRIVE) {
bzero(&event_details, sizeof (ibmf_saa_event_details_t));
event_details.ie_producer_event_status_mask =
producer_status_mask;
ibmf_saa_notify_event_clients(saa_portp, &event_details,
IBMF_SAA_EVENT_SUBSCRIBER_STATUS_CHG, client);
}
IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
ibmf_saa_add_event_subscriber_end, IBMF_TNF_TRACE, "",
"ibmf_saa_add_event_subscriber() exit\n");
}