static void ni_rcv_get_port_info(IN osm_sm_t * sm, IN osm_node_t * node, IN const osm_madw_t * madw) { osm_madw_context_t context; osm_physp_t *physp; ib_node_info_t *ni; unsigned port; ib_api_status_t status; int mlnx_epi_supported = 0; ni = ib_smp_get_payload_ptr(osm_madw_get_smp_ptr(madw)); port = ib_node_info_get_local_port_num(ni); if (sm->p_subn->opt.fdr10) mlnx_epi_supported = is_mlnx_ext_port_info_supported(ni->device_id); physp = osm_node_get_physp_ptr(node, port); if (!physp) { OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR OD1E: " "Failed to find physp for port %d of Node GUID 0x%" PRIx64 "\n", port, cl_ntoh64(osm_node_get_node_guid(node))); return; } context.pi_context.node_guid = osm_node_get_node_guid(node); context.pi_context.port_guid = osm_physp_get_port_guid(physp); context.pi_context.set_method = FALSE; context.pi_context.light_sweep = FALSE; context.pi_context.active_transition = FALSE; context.pi_context.client_rereg = FALSE; status = osm_req_get(sm, osm_physp_get_dr_path_ptr(physp), IB_MAD_ATTR_PORT_INFO, cl_hton32(port), TRUE, 0, CL_DISP_MSGID_NONE, &context); if (status != IB_SUCCESS) OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR OD02: " "Failure initiating PortInfo request (%s)\n", ib_get_err_str(status)); if (mlnx_epi_supported) { status = osm_req_get(sm, osm_physp_get_dr_path_ptr(physp), IB_MAD_ATTR_MLNX_EXTENDED_PORT_INFO, cl_hton32(port), TRUE, 0, CL_DISP_MSGID_NONE, &context); if (status != IB_SUCCESS) OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D0B: " "Failure initiating MLNX ExtPortInfo request (%s)\n", ib_get_err_str(status)); } }
static void state_mgr_get_sw_info(IN cl_map_item_t * p_object, IN void *context) { osm_node_t *p_node; osm_dr_path_t *p_dr_path; osm_madw_context_t mad_context; osm_switch_t *const p_sw = (osm_switch_t *) p_object; osm_sm_t *sm = context; ib_api_status_t status; OSM_LOG_ENTER(sm->p_log); p_node = p_sw->p_node; p_dr_path = osm_physp_get_dr_path_ptr(osm_node_get_physp_ptr(p_node, 0)); memset(&mad_context, 0, sizeof(mad_context)); mad_context.si_context.node_guid = osm_node_get_node_guid(p_node); mad_context.si_context.set_method = FALSE; mad_context.si_context.light_sweep = TRUE; status = osm_req_get(sm, p_dr_path, IB_MAD_ATTR_SWITCH_INFO, 0, OSM_MSG_LIGHT_SWEEP_FAIL, &mad_context); if (status != IB_SUCCESS) OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3304: " "Request for SwitchInfo failed (%s)\n", ib_get_err_str(status)); OSM_LOG_EXIT(sm->p_log); }
static void query_sm_info(cl_map_item_t * item, void *cxt) { osm_madw_context_t context; osm_remote_sm_t *r_sm = cl_item_obj(item, r_sm, map_item); osm_sm_t *sm = cxt; ib_api_status_t ret; osm_port_t *p_port; p_port= osm_get_port_by_guid(sm->p_subn, r_sm->smi.guid); if (p_port == NULL) { OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3340: " "No port object on given sm object\n"); return; } context.smi_context.port_guid = r_sm->smi.guid; context.smi_context.set_method = FALSE; context.smi_context.light_sweep = TRUE; ret = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_port->p_physp), IB_MAD_ATTR_SM_INFO, 0, CL_DISP_MSGID_NONE, &context); if (ret != IB_SUCCESS) OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3314: " "Failure requesting SMInfo (%s)\n", ib_get_err_str(ret)); }
static void ni_rcv_process_switch(IN osm_sm_t * sm, IN osm_node_t * p_node, IN const osm_madw_t * p_madw) { ib_api_status_t status = IB_SUCCESS; osm_physp_t *p_physp; osm_madw_context_t context; osm_dr_path_t *path; ib_smp_t *p_smp; OSM_LOG_ENTER(sm->p_log); p_smp = osm_madw_get_smp_ptr(p_madw); p_physp = osm_node_get_physp_ptr(p_node, 0); /* update DR path of already initialized switch port 0 */ path = osm_physp_get_dr_path_ptr(p_physp); osm_dr_path_init(path, p_smp->hop_count, p_smp->initial_path); context.si_context.node_guid = osm_node_get_node_guid(p_node); context.si_context.set_method = FALSE; context.si_context.light_sweep = FALSE; context.si_context.lft_top_change = FALSE; /* Request a SwitchInfo attribute */ status = osm_req_get(sm, path, IB_MAD_ATTR_SWITCH_INFO, 0, TRUE, 0, CL_DISP_MSGID_NONE, &context); if (status != IB_SUCCESS) /* continue despite error */ OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D06: " "Failure initiating SwitchInfo request (%s)\n", ib_get_err_str(status)); OSM_LOG_EXIT(sm->p_log); }
/********************************************************************** Initiates a thorough sweep of the subnet. Used when there is suspicion that something on the subnet has changed. **********************************************************************/ static ib_api_status_t state_mgr_sweep_hop_0(IN osm_sm_t * sm) { ib_api_status_t status; osm_dr_path_t dr_path; osm_bind_handle_t h_bind; uint8_t path_array[IB_SUBNET_PATH_HOPS_MAX]; OSM_LOG_ENTER(sm->p_log); memset(path_array, 0, sizeof(path_array)); /* * First, get the bind handle. */ h_bind = osm_sm_mad_ctrl_get_bind_handle(&sm->mad_ctrl); if (h_bind != OSM_BIND_INVALID_HANDLE) { OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, "INITIATING HEAVY SWEEP"); /* * Start the sweep by clearing the port counts, then * get our own NodeInfo at 0 hops. */ CL_PLOCK_ACQUIRE(sm->p_lock); cl_qmap_apply_func(&sm->p_subn->node_guid_tbl, state_mgr_reset_node_count, sm); cl_qmap_apply_func(&sm->p_subn->port_guid_tbl, state_mgr_reset_port_count, sm); cl_qmap_apply_func(&sm->p_subn->sw_guid_tbl, state_mgr_reset_switch_count, sm); /* Set the in_sweep_hop_0 flag in subn to be TRUE. * This will indicate the sweeping not to continue beyond the * the current node. * This is relevant for the case of SM on switch, since in the * switch info we need to signal somehow not to continue * the sweeping. */ sm->p_subn->in_sweep_hop_0 = TRUE; CL_PLOCK_RELEASE(sm->p_lock); osm_dr_path_init(&dr_path, h_bind, 0, path_array); status = osm_req_get(sm, &dr_path, IB_MAD_ATTR_NODE_INFO, 0, CL_DISP_MSGID_NONE, NULL); if (status != IB_SUCCESS) OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3305: " "Request for NodeInfo failed (%s)\n", ib_get_err_str(status)); } else { OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "No bound ports. Deferring sweep...\n"); status = IB_INVALID_STATE; } OSM_LOG_EXIT(sm->p_log); return status; }
/********************************************************************** The plock must be held before calling this function. **********************************************************************/ static void pi_rcv_process_switch_port0(IN osm_sm_t * sm, IN osm_node_t * p_node, IN osm_physp_t * p_physp, IN ib_port_info_t * p_pi) { ib_api_status_t status; osm_madw_context_t context; uint8_t port, num_ports; OSM_LOG_ENTER(sm->p_log); if (p_physp->need_update) sm->p_subn->ignore_existing_lfts = TRUE; pi_rcv_check_and_fix_lid(sm->p_log, p_pi, p_physp); /* Update the PortInfo attribute */ osm_physp_set_port_info(p_physp, p_pi, sm); /* Determine if base switch port 0 */ if (p_node->sw && !ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info)) /* PortState is not used on BSP0 but just in case it is DOWN */ p_physp->port_info = *p_pi; /* Now, query PortInfo for the switch external ports */ num_ports = osm_node_get_num_physp(p_node); context.pi_context.node_guid = osm_node_get_node_guid(p_node); context.pi_context.port_guid = osm_physp_get_port_guid(p_physp); context.pi_context.set_method = FALSE; context.pi_context.light_sweep = FALSE; context.pi_context.active_transition = FALSE; context.pi_context.client_rereg = FALSE; for (port = 1; port < num_ports; port++) { status = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_physp), IB_MAD_ATTR_PORT_INFO, cl_hton32(port), FALSE, ib_port_info_get_m_key(&p_physp->port_info), CL_DISP_MSGID_NONE, &context); if (status != IB_SUCCESS) OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F16: " "Failure initiating PortInfo request (%s)\n", ib_get_err_str(status)); } pi_rcv_process_endport(sm, p_physp, p_pi); OSM_LOG_EXIT(sm->p_log); }
static void sm_state_mgr_send_master_sm_info_req(osm_sm_t * sm) { osm_madw_context_t context; const osm_port_t *p_port; ib_api_status_t status; OSM_LOG_ENTER(sm->p_log); memset(&context, 0, sizeof(context)); if (sm->p_subn->sm_state == IB_SMINFO_STATE_STANDBY) { /* * We are in STANDBY state - this means we need to poll the * master SM (according to master_guid). * Send a query of SubnGet(SMInfo) to the subn * master_sm_base_lid object. */ p_port = osm_get_port_by_guid(sm->p_subn, sm->master_sm_guid); } else { /* * We are not in STANDBY - this means we are in MASTER state - * so we need to poll the SM that is saved in p_polling_sm * under sm. * Send a query of SubnGet(SMInfo) to that SM. */ p_port = sm->p_polling_sm->p_port; } if (p_port == NULL) { OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3203: " "No port object for GUID 0x%016" PRIx64 "\n", cl_ntoh64(sm->master_sm_guid)); goto Exit; } context.smi_context.port_guid = p_port->guid; context.smi_context.set_method = FALSE; status = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_port->p_physp), IB_MAD_ATTR_SM_INFO, 0, CL_DISP_MSGID_NONE, &context); if (status != IB_SUCCESS) OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3204: " "Failure requesting SMInfo (%s)\n", ib_get_err_str(status)); Exit: OSM_LOG_EXIT(sm->p_log); }
/********************************************************************** Initiate a remote port info request for the given physical port **********************************************************************/ static void state_mgr_get_remote_port_info(IN osm_sm_t * sm, IN osm_physp_t * p_physp) { osm_dr_path_t *p_dr_path; osm_dr_path_t rem_node_dr_path; osm_madw_context_t mad_context; ib_api_status_t status; OSM_LOG_ENTER(sm->p_log); /* generate a dr path leaving on the physp to the remote node */ p_dr_path = osm_physp_get_dr_path_ptr(p_physp); memcpy(&rem_node_dr_path, p_dr_path, sizeof(osm_dr_path_t)); if (osm_dr_path_extend(&rem_node_dr_path, osm_physp_get_port_num(p_physp))) { OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 332D: " "DR path with hop count %d couldn't be extended " "so skipping PortInfo query\n", p_dr_path->hop_count); goto Exit; } memset(&mad_context, 0, sizeof(mad_context)); mad_context.pi_context.node_guid = osm_node_get_node_guid(osm_physp_get_node_ptr(p_physp)); mad_context.pi_context.port_guid = p_physp->port_guid; mad_context.pi_context.set_method = FALSE; mad_context.pi_context.light_sweep = TRUE; mad_context.pi_context.active_transition = FALSE; /* note that with some negative logic - if the query failed it means * that there is no point in going to heavy sweep */ status = osm_req_get(sm, &rem_node_dr_path, IB_MAD_ATTR_PORT_INFO, 0, CL_DISP_MSGID_NONE, &mad_context); if (status != IB_SUCCESS) OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 332E: " "Request for PortInfo failed (%s)\n", ib_get_err_str(status)); Exit: OSM_LOG_EXIT(sm->p_log); }
static void state_mgr_update_node_desc(IN cl_map_item_t * obj, IN void *context) { osm_madw_context_t mad_context; osm_node_t *p_node = (osm_node_t *) obj; osm_sm_t *sm = context; osm_physp_t *p_physp = NULL; unsigned i, num_ports; ib_api_status_t status; OSM_LOG_ENTER(sm->p_log); CL_ASSERT(p_node); OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "Updating NodeDesc for 0x%016" PRIx64 "\n", cl_ntoh64(osm_node_get_node_guid(p_node))); /* get a physp to request from. */ num_ports = osm_node_get_num_physp(p_node); for (i = 0; i < num_ports; i++) if ((p_physp = osm_node_get_physp_ptr(p_node, i))) break; if (!p_physp) { OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 331C: " "Failed to find any valid physical port object.\n"); goto exit; } mad_context.nd_context.node_guid = osm_node_get_node_guid(p_node); status = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_physp), IB_MAD_ATTR_NODE_DESC, 0, CL_DISP_MSGID_NONE, &mad_context); if (status != IB_SUCCESS) OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 331B: Failure initiating NodeDescription request " "(%s)\n", ib_get_err_str(status)); exit: OSM_LOG_EXIT(sm->p_log); }
/********************************************************************** The plock must be held before calling this function. **********************************************************************/ static void si_rcv_get_fwd_tbl(IN osm_sm_t * sm, IN osm_switch_t * p_sw) { osm_madw_context_t context; osm_dr_path_t *p_dr_path; osm_physp_t *p_physp; osm_node_t *p_node; uint32_t block_id_ho; uint32_t max_block_id_ho; ib_api_status_t status = IB_SUCCESS; OSM_LOG_ENTER(sm->p_log); CL_ASSERT(p_sw); p_node = p_sw->p_node; CL_ASSERT(osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH); context.lft_context.node_guid = osm_node_get_node_guid(p_node); context.lft_context.set_method = FALSE; max_block_id_ho = osm_switch_get_max_block_id_in_use(p_sw); p_physp = osm_node_get_physp_ptr(p_node, 0); p_dr_path = osm_physp_get_dr_path_ptr(p_physp); for (block_id_ho = 0; block_id_ho <= max_block_id_ho; block_id_ho++) { OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "Retrieving FT block %u\n", block_id_ho); status = osm_req_get(sm, p_dr_path, IB_MAD_ATTR_LIN_FWD_TBL, cl_hton32(block_id_ho), CL_DISP_MSGID_NONE, &context); if (status != IB_SUCCESS) /* continue the loop despite the error */ OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3603: " "Failure initiating PortInfo request (%s)\n", ib_get_err_str(status)); } OSM_LOG_EXIT(sm->p_log); }
/********************************************************************** The plock must be held before calling this function. **********************************************************************/ void osm_req_get_node_desc(IN osm_sm_t * sm, osm_physp_t * p_physp) { ib_api_status_t status = IB_SUCCESS; osm_madw_context_t context; OSM_LOG_ENTER(sm->p_log); context.nd_context.node_guid = osm_node_get_node_guid(osm_physp_get_node_ptr(p_physp)); status = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_physp), IB_MAD_ATTR_NODE_DESC, 0, TRUE, 0, CL_DISP_MSGID_NONE, &context); if (status != IB_SUCCESS) OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D03: " "Failure initiating NodeDescription request (%s)\n", ib_get_err_str(status)); OSM_LOG_EXIT(sm->p_log); }
static void requery_dup_node_info(IN osm_sm_t * sm, osm_physp_t * p_physp, unsigned count) { osm_madw_context_t context; osm_dr_path_t path; cl_status_t status; if (!p_physp->p_remote_physp) { OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D0D: " "DR path couldn't be extended due to NULL remote physp\n"); return; } path = *osm_physp_get_dr_path_ptr(p_physp->p_remote_physp); if (osm_dr_path_extend(&path, p_physp->p_remote_physp->port_num)) { OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D08: " "DR path with hop count %d couldn't be extended\n", path.hop_count); return; } context.ni_context.node_guid = p_physp->p_remote_physp->p_node->node_info.port_guid; context.ni_context.port_num = p_physp->p_remote_physp->port_num; context.ni_context.dup_node_guid = p_physp->p_node->node_info.node_guid; context.ni_context.dup_port_num = p_physp->port_num; context.ni_context.dup_count = count; status = osm_req_get(sm, &path, IB_MAD_ATTR_NODE_INFO, 0, TRUE, 0, CL_DISP_MSGID_NONE, &context); if (status != IB_SUCCESS) OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D02: " "Failure initiating NodeInfo request (%s)\n", ib_get_err_str(status)); }
static void __osm_pi_rcv_process_endport(IN osm_sm_t * sm, IN osm_physp_t * const p_physp, IN const ib_port_info_t * const p_pi) { osm_madw_context_t context; ib_api_status_t status; ib_net64_t port_guid; uint8_t rate, mtu; cl_qmap_t *p_sm_tbl; osm_remote_sm_t *p_sm; OSM_LOG_ENTER(sm->p_log); port_guid = osm_physp_get_port_guid(p_physp); /* HACK extended port 0 should be handled too! */ if (osm_physp_get_port_num(p_physp) != 0) { /* track the minimal endport MTU and rate */ mtu = ib_port_info_get_mtu_cap(p_pi); if (mtu < sm->p_subn->min_ca_mtu) { OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, "Setting endport minimal MTU to:%u defined by port:0x%" PRIx64 "\n", mtu, cl_ntoh64(port_guid)); sm->p_subn->min_ca_mtu = mtu; } rate = ib_port_info_compute_rate(p_pi); if (rate < sm->p_subn->min_ca_rate) { OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, "Setting endport minimal rate to:%u defined by port:0x%" PRIx64 "\n", rate, cl_ntoh64(port_guid)); sm->p_subn->min_ca_rate = rate; } } if (port_guid == sm->p_subn->sm_port_guid) { /* We received the PortInfo for our own port. */ if (!(p_pi->capability_mask & IB_PORT_CAP_IS_SM)) /* Set the IS_SM bit to indicate our port hosts an SM. */ __osm_pi_rcv_set_sm(sm, p_physp); } else { p_sm_tbl = &sm->p_subn->sm_guid_tbl; if (p_pi->capability_mask & IB_PORT_CAP_IS_SM) { /* * Before querying the SM - we want to make sure we * clean its state, so if the querying fails we * recognize that this SM is not active. */ p_sm = (osm_remote_sm_t *) cl_qmap_get(p_sm_tbl, port_guid); if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl)) /* clean it up */ p_sm->smi.pri_state = 0xF0 & p_sm->smi.pri_state; if (sm->p_subn->opt.ignore_other_sm) OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, "Ignoring SM on port 0x%" PRIx64 "\n", cl_ntoh64(port_guid)); else { OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, "Detected another SM. Requesting SMInfo" "\n\t\t\t\tPort 0x%" PRIx64 "\n", cl_ntoh64(port_guid)); /* This port indicates it's an SM and it's not our own port. Acquire the SMInfo Attribute. */ memset(&context, 0, sizeof(context)); context.smi_context.set_method = FALSE; context.smi_context.port_guid = port_guid; status = osm_req_get(sm, osm_physp_get_dr_path_ptr (p_physp), IB_MAD_ATTR_SM_INFO, 0, CL_DISP_MSGID_NONE, &context); if (status != IB_SUCCESS) OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F05: " "Failure requesting SMInfo (%s)\n", ib_get_err_str(status)); } } else { p_sm = (osm_remote_sm_t *) cl_qmap_remove(p_sm_tbl, port_guid); if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl)) free(p_sm); } } OSM_LOG_EXIT(sm->p_log); }
/********************************************************************** The plock must be held before calling this function. **********************************************************************/ static void pi_rcv_process_switch_ext_port(IN osm_sm_t * sm, IN osm_node_t * p_node, IN osm_physp_t * p_physp, IN ib_port_info_t * p_pi) { ib_api_status_t status = IB_SUCCESS; osm_madw_context_t context; osm_physp_t *p_remote_physp, *physp0; osm_node_t *p_remote_node; ib_net64_t m_key; unsigned data_vls; uint8_t port_num; uint8_t remote_port_num; osm_dr_path_t path; int mlnx_epi_supported = 0; OSM_LOG_ENTER(sm->p_log); /* Check the state of the physical port. If there appears to be something on the other end of the wire, then ask for NodeInfo. Ignore the switch management port. */ port_num = osm_physp_get_port_num(p_physp); if (sm->p_subn->opt.fdr10) mlnx_epi_supported = is_mlnx_ext_port_info_supported( ib_node_info_get_vendor_id(&p_node->node_info), p_node->node_info.device_id); /* if in_sweep_hop_0 is TRUE, then this means the SM is on the switch, and we got switchInfo of our local switch. Do not continue probing through the switch. */ switch (ib_port_info_get_port_state(p_pi)) { case IB_LINK_DOWN: p_remote_physp = osm_physp_get_remote(p_physp); if (p_remote_physp) { p_remote_node = osm_physp_get_node_ptr(p_remote_physp); remote_port_num = osm_physp_get_port_num(p_remote_physp); OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, "Unlinking local node 0x%" PRIx64 ", port %u" "\n\t\t\t\tand remote node 0x%" PRIx64 ", port %u\n", cl_ntoh64(osm_node_get_node_guid (p_node)), port_num, cl_ntoh64(osm_node_get_node_guid (p_remote_node)), remote_port_num); if (sm->ucast_mgr.cache_valid) osm_ucast_cache_add_link(&sm->ucast_mgr, p_physp, p_remote_physp); osm_node_unlink(p_node, (uint8_t) port_num, p_remote_node, (uint8_t) remote_port_num); } break; case IB_LINK_INIT: case IB_LINK_ARMED: case IB_LINK_ACTIVE: physp0 = osm_node_get_physp_ptr(p_node, 0); if (mlnx_epi_supported) { m_key = ib_port_info_get_m_key(&physp0->port_info); context.pi_context.node_guid = osm_node_get_node_guid(p_node); context.pi_context.port_guid = osm_physp_get_port_guid(p_physp); context.pi_context.set_method = FALSE; context.pi_context.light_sweep = FALSE; context.pi_context.active_transition = FALSE; context.pi_context.client_rereg = FALSE; status = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_physp), IB_MAD_ATTR_MLNX_EXTENDED_PORT_INFO, cl_hton32(port_num), FALSE, m_key, CL_DISP_MSGID_NONE, &context); if (status != IB_SUCCESS) OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F11: " "Failure initiating MLNX ExtPortInfo request (%s)\n", ib_get_err_str(status)); } if (sm->p_subn->in_sweep_hop_0 == FALSE) { /* To avoid looping forever, only probe the port if it is NOT the port that responded to the SMP. Request node info from the other end of this link: 1) Copy the current path from the parent node. 2) Extend the path to the next hop thru this port. 3) Request node info with the new path */ if (p_pi->local_port_num != osm_physp_get_port_num(p_physp)) { path = *osm_physp_get_dr_path_ptr(p_physp); if (osm_dr_path_extend(&path, osm_physp_get_port_num (p_physp))) { OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F08: " "DR path with hop count %d couldn't be extended\n", path.hop_count); break; } memset(&context, 0, sizeof(context)); context.ni_context.node_guid = osm_node_get_node_guid(p_node); context.ni_context.port_num = osm_physp_get_port_num(p_physp); status = osm_req_get(sm, &path, IB_MAD_ATTR_NODE_INFO, 0, TRUE, 0, CL_DISP_MSGID_NONE, &context); if (status != IB_SUCCESS) OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F02: " "Failure initiating NodeInfo request (%s)\n", ib_get_err_str(status)); } else OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "Skipping SMP responder port %u\n", p_pi->local_port_num); } break; default: OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F03: " "Unknown link state = %u, port = %u\n", ib_port_info_get_port_state(p_pi), p_pi->local_port_num); break; } if (ib_port_info_get_port_state(p_pi) > IB_LINK_INIT && p_node->sw && !ib_switch_info_get_state_change(&p_node->sw->switch_info) && p_node->sw->need_update == 1) p_node->sw->need_update = 0; if (p_physp->need_update) sm->p_subn->ignore_existing_lfts = TRUE; /* Update the PortInfo attribute. */ osm_physp_set_port_info(p_physp, p_pi, sm); if (ib_port_info_get_port_state(p_pi) == IB_LINK_DOWN) goto Exit; p_remote_physp = osm_physp_get_remote(p_physp); if (p_remote_physp) { p_remote_node = osm_physp_get_node_ptr(p_remote_physp); if (p_remote_node->sw) { data_vls = 1U << (ib_port_info_get_vl_cap(p_pi) - 1); if (data_vls > 1U << (sm->p_subn->opt.max_op_vls - 1)) data_vls = 1U << (sm->p_subn->opt.max_op_vls - 1); if (data_vls >= IB_MAX_NUM_VLS) data_vls = IB_MAX_NUM_VLS - 1; if ((uint8_t)data_vls < sm->p_subn->min_sw_data_vls) { OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, "Setting switch port minimal data VLs " "to:%u defined by node:0x%" PRIx64 ", port:%u\n", data_vls, cl_ntoh64(osm_node_get_node_guid(p_node)), port_num); sm->p_subn->min_sw_data_vls = data_vls; } } } Exit: OSM_LOG_EXIT(sm->p_log); }
/********************************************************************** The plock must be held before calling this function. **********************************************************************/ static void si_rcv_get_mcast_fwd_tbl(IN osm_sm_t * sm, IN osm_switch_t * p_sw) { osm_madw_context_t context; osm_dr_path_t *p_dr_path; osm_physp_t *p_physp; osm_node_t *p_node; osm_mcast_tbl_t *p_tbl; uint32_t block_id_ho; uint32_t max_block_id_ho; uint32_t position; uint32_t max_position; uint32_t attr_mod_ho; ib_api_status_t status = IB_SUCCESS; OSM_LOG_ENTER(sm->p_log); CL_ASSERT(p_sw); p_node = p_sw->p_node; CL_ASSERT(osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH); if (osm_switch_get_mcast_fwd_tbl_size(p_sw) == 0) { OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "Multicast not supported by switch 0x%016" PRIx64 "\n", cl_ntoh64(osm_node_get_node_guid(p_node))); goto Exit; } context.mft_context.node_guid = osm_node_get_node_guid(p_node); context.mft_context.set_method = FALSE; p_tbl = osm_switch_get_mcast_tbl_ptr(p_sw); max_block_id_ho = osm_mcast_tbl_get_max_block(p_tbl); if (max_block_id_ho > IB_MCAST_MAX_BLOCK_ID) { OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3609: " "Out-of-range mcast block size = %u on switch 0x%016" PRIx64 "\n", max_block_id_ho, cl_ntoh64(osm_node_get_node_guid(p_node))); goto Exit; } max_position = osm_mcast_tbl_get_max_position(p_tbl); CL_ASSERT(max_position <= IB_MCAST_POSITION_MAX); OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "Max MFT block = %u, Max position = %u\n", max_block_id_ho, max_position); p_physp = osm_node_get_physp_ptr(p_node, 0); p_dr_path = osm_physp_get_dr_path_ptr(p_physp); for (block_id_ho = 0; block_id_ho <= max_block_id_ho; block_id_ho++) { OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "Retrieving MFT block %u\n", block_id_ho); for (position = 0; position <= max_position; position++) { OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "Retrieving MFT position %u\n", position); attr_mod_ho = block_id_ho | position << IB_MCAST_POSITION_SHIFT; status = osm_req_get(sm, p_dr_path, IB_MAD_ATTR_MCAST_FWD_TBL, cl_hton32(attr_mod_ho), CL_DISP_MSGID_NONE, &context); if (status != IB_SUCCESS) /* continue the loop despite the error */ OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3607: " "Failure initiating PortInfo request (%s)\n", ib_get_err_str(status)); } } Exit: OSM_LOG_EXIT(sm->p_log); }
/********************************************************************** Sweeps the node 1 hop away. This sets off a "chain reaction" that causes discovery of the subnet. Used when there is suspicion that something on the subnet has changed. **********************************************************************/ static ib_api_status_t state_mgr_sweep_hop_1(IN osm_sm_t * sm) { ib_api_status_t status = IB_SUCCESS; osm_bind_handle_t h_bind; osm_madw_context_t context; osm_node_t *p_node; osm_port_t *p_port; osm_physp_t *p_physp; osm_dr_path_t *p_dr_path; osm_dr_path_t hop_1_path; ib_net64_t port_guid; uint8_t port_num; uint8_t path_array[IB_SUBNET_PATH_HOPS_MAX]; uint8_t num_ports; osm_physp_t *p_ext_physp; OSM_LOG_ENTER(sm->p_log); /* * First, get our own port and node objects. */ port_guid = sm->p_subn->sm_port_guid; CL_ASSERT(port_guid); /* Set the in_sweep_hop_0 flag in subn to be FALSE. * This will indicate the sweeping to continue beyond the * the current node. * This is relevant for the case of SM on switch, since in the * switch info we need to signal that the sweeping should * continue through the switch. */ sm->p_subn->in_sweep_hop_0 = FALSE; p_port = osm_get_port_by_guid(sm->p_subn, port_guid); if (!p_port) { OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3310: " "No SM port object\n"); status = IB_ERROR; goto Exit; } p_node = p_port->p_node; CL_ASSERT(p_node); port_num = ib_node_info_get_local_port_num(&p_node->node_info); OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "Probing hop 1 on local port %u\n", port_num); p_physp = osm_node_get_physp_ptr(p_node, port_num); CL_ASSERT(p_physp); p_dr_path = osm_physp_get_dr_path_ptr(p_physp); h_bind = osm_dr_path_get_bind_handle(p_dr_path); CL_ASSERT(h_bind != OSM_BIND_INVALID_HANDLE); memset(path_array, 0, sizeof(path_array)); /* the hop_1 operations depend on the type of our node. * Currently - legal nodes that can host SM are SW and CA */ switch (osm_node_get_type(p_node)) { case IB_NODE_TYPE_CA: case IB_NODE_TYPE_ROUTER: memset(&context, 0, sizeof(context)); context.ni_context.node_guid = osm_node_get_node_guid(p_node); context.ni_context.port_num = port_num; path_array[1] = port_num; osm_dr_path_init(&hop_1_path, h_bind, 1, path_array); status = osm_req_get(sm, &hop_1_path, IB_MAD_ATTR_NODE_INFO, 0, CL_DISP_MSGID_NONE, &context); if (status != IB_SUCCESS) OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3311: " "Request for NodeInfo failed (%s)\n", ib_get_err_str(status)); break; case IB_NODE_TYPE_SWITCH: /* Need to go over all the ports of the switch, and send a * node_info from them. This doesn't include the port 0 of the * switch, which hosts the SM. * Note: We'll send another switchInfo on port 0, since if no * ports are connected, we still want to get some response, and * have the subnet come up. */ num_ports = osm_node_get_num_physp(p_node); for (port_num = 1; port_num < num_ports; port_num++) { /* go through the port only if the port is not DOWN */ p_ext_physp = osm_node_get_physp_ptr(p_node, port_num); if (p_ext_physp && ib_port_info_get_port_state (&(p_ext_physp->port_info)) > IB_LINK_DOWN) { memset(&context, 0, sizeof(context)); context.ni_context.node_guid = osm_node_get_node_guid(p_node); context.ni_context.port_num = port_num; path_array[1] = port_num; osm_dr_path_init(&hop_1_path, h_bind, 1, path_array); status = osm_req_get(sm, &hop_1_path, IB_MAD_ATTR_NODE_INFO, 0, CL_DISP_MSGID_NONE, &context); if (status != IB_SUCCESS) OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3312: " "Request for NodeInfo failed (%s)\n", ib_get_err_str(status)); } } break; default: OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3313: Unknown node type %d (%s)\n", osm_node_get_type(p_node), p_node->print_desc); } Exit: OSM_LOG_EXIT(sm->p_log); return status; }
static void get_pkey_table(IN osm_log_t * p_log, IN osm_sm_t * sm, IN osm_node_t * p_node, IN osm_physp_t * p_physp) { osm_madw_context_t context; ib_api_status_t status; osm_dr_path_t path; osm_physp_t *physp0; ib_net64_t m_key; uint8_t port_num; uint16_t block_num, max_blocks; uint32_t attr_mod_ho; OSM_LOG_ENTER(p_log); path = *osm_physp_get_dr_path_ptr(p_physp); context.pkey_context.node_guid = osm_node_get_node_guid(p_node); context.pkey_context.port_guid = osm_physp_get_port_guid(p_physp); context.pkey_context.set_method = FALSE; port_num = p_physp->port_num; if (!p_node->sw || port_num == 0) /* The maximum blocks is defined by the node info partition cap for CA, router, and switch management ports. */ max_blocks = (cl_ntoh16(p_node->node_info.partition_cap) + IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1) / IB_NUM_PKEY_ELEMENTS_IN_BLOCK; else { /* This is a switch, and not a management port. The maximum blocks is defined in the switch info partition enforcement cap. */ /* Check for IBM eHCA firmware defect in reporting partition enforcement cap */ if (cl_ntoh32(ib_node_info_get_vendor_id(&p_node->node_info)) == IBM_VENDOR_ID) p_node->sw->switch_info.enforce_cap = 0; /* Bail out if this is a switch with no partition enforcement capability */ if (cl_ntoh16(p_node->sw->switch_info.enforce_cap) == 0) goto Exit; max_blocks = (cl_ntoh16(p_node->sw->switch_info.enforce_cap) + IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1) / IB_NUM_PKEY_ELEMENTS_IN_BLOCK; } p_physp->pkeys.rcv_blocks_cnt = max_blocks; for (block_num = 0; block_num < max_blocks; block_num++) { if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH || osm_physp_get_port_num(p_physp) == 0) { attr_mod_ho = block_num; m_key = ib_port_info_get_m_key(&p_physp->port_info); } else { attr_mod_ho = block_num | (port_num << 16); physp0 = osm_node_get_physp_ptr(p_node, 0); m_key = ib_port_info_get_m_key(&physp0->port_info); } status = osm_req_get(sm, &path, IB_MAD_ATTR_P_KEY_TABLE, cl_hton32(attr_mod_ho), FALSE, m_key, CL_DISP_MSGID_NONE, &context); if (status != IB_SUCCESS) { OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0F12: " "Failure initiating PKeyTable request (%s)\n", ib_get_err_str(status)); goto Exit; } } Exit: OSM_LOG_EXIT(p_log); }
/********************************************************************** The plock must be held before calling this function. **********************************************************************/ static void __osm_pi_rcv_process_switch_port(IN osm_sm_t * sm, IN osm_node_t * const p_node, IN osm_physp_t * const p_physp, IN ib_port_info_t * const p_pi) { ib_api_status_t status = IB_SUCCESS; osm_madw_context_t context; osm_physp_t *p_remote_physp; osm_node_t *p_remote_node; uint8_t port_num; uint8_t remote_port_num; osm_dr_path_t path; OSM_LOG_ENTER(sm->p_log); /* Check the state of the physical port. If there appears to be something on the other end of the wire, then ask for NodeInfo. Ignore the switch management port. */ port_num = osm_physp_get_port_num(p_physp); /* if in_sweep_hop_0 is TRUE, then this means the SM is on the switch, and we got switchInfo of our local switch. Do not continue probing through the switch. */ if (port_num != 0 && sm->p_subn->in_sweep_hop_0 == FALSE) { switch (ib_port_info_get_port_state(p_pi)) { case IB_LINK_DOWN: p_remote_physp = osm_physp_get_remote(p_physp); if (p_remote_physp) { p_remote_node = osm_physp_get_node_ptr(p_remote_physp); remote_port_num = osm_physp_get_port_num(p_remote_physp); OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, "Unlinking local node 0x%" PRIx64 ", port %u" "\n\t\t\t\tand remote node 0x%" PRIx64 ", port %u\n", cl_ntoh64(osm_node_get_node_guid (p_node)), port_num, cl_ntoh64(osm_node_get_node_guid (p_remote_node)), remote_port_num); if (sm->ucast_mgr.cache_valid) osm_ucast_cache_add_link(&sm->ucast_mgr, p_physp, p_remote_physp); osm_node_unlink(p_node, (uint8_t) port_num, p_remote_node, (uint8_t) remote_port_num); } break; case IB_LINK_INIT: case IB_LINK_ARMED: case IB_LINK_ACTIVE: /* To avoid looping forever, only probe the port if it is NOT the port that responded to the SMP. Request node info from the other end of this link: 1) Copy the current path from the parent node. 2) Extend the path to the next hop thru this port. 3) Request node info with the new path */ if (p_pi->local_port_num != osm_physp_get_port_num(p_physp)) { path = *osm_physp_get_dr_path_ptr(p_physp); osm_dr_path_extend(&path, osm_physp_get_port_num (p_physp)); memset(&context, 0, sizeof(context)); context.ni_context.node_guid = osm_node_get_node_guid(p_node); context.ni_context.port_num = osm_physp_get_port_num(p_physp); status = osm_req_get(sm, &path, IB_MAD_ATTR_NODE_INFO, 0, CL_DISP_MSGID_NONE, &context); if (status != IB_SUCCESS) OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F02: " "Failure initiating NodeInfo request (%s)\n", ib_get_err_str(status)); } else OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "Skipping SMP responder port %u\n", p_pi->local_port_num); break; default: OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F03: " "Unknown link state = %u, port = %u\n", ib_port_info_get_port_state(p_pi), p_pi->local_port_num); break; } } if (ib_port_info_get_port_state(p_pi) > IB_LINK_INIT && p_node->sw && p_node->sw->need_update == 1) p_node->sw->need_update = 0; if (p_physp->need_update) sm->p_subn->ignore_existing_lfts = TRUE; if (port_num == 0) pi_rcv_check_and_fix_lid(sm->p_log, p_pi, p_physp); /* Update the PortInfo attribute. */ osm_physp_set_port_info(p_physp, p_pi); if (port_num == 0) { /* Determine if base switch port 0 */ if (p_node->sw && !ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info)) /* PortState is not used on BSP0 but just in case it is DOWN */ p_physp->port_info = *p_pi; __osm_pi_rcv_process_endport(sm, p_physp, p_pi); } OSM_LOG_EXIT(sm->p_log); }
static void pi_rcv_process_endport(IN osm_sm_t * sm, IN osm_physp_t * p_physp, IN const ib_port_info_t * p_pi) { osm_madw_context_t context; ib_api_status_t status; ib_net64_t port_guid; int extended; uint8_t rate, mtu, mpb; unsigned data_vls; cl_qmap_t *p_sm_tbl; osm_remote_sm_t *p_sm; OSM_LOG_ENTER(sm->p_log); port_guid = osm_physp_get_port_guid(p_physp); /* HACK extended port 0 should be handled too! */ if (osm_physp_get_port_num(p_physp) != 0 && ib_port_info_get_port_state(p_pi) != IB_LINK_DOWN) { /* track the minimal endport MTU, rate, and operational VLs */ mtu = ib_port_info_get_mtu_cap(p_pi); if (mtu < sm->p_subn->min_ca_mtu) { OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, "Setting endport minimal MTU to:%u defined by port:0x%" PRIx64 "\n", mtu, cl_ntoh64(port_guid)); sm->p_subn->min_ca_mtu = mtu; } extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS; rate = ib_port_info_compute_rate(p_pi, extended); if (ib_path_compare_rates(rate, sm->p_subn->min_ca_rate) < 0) { OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, "Setting endport minimal rate to:%u defined by port:0x%" PRIx64 "\n", rate, cl_ntoh64(port_guid)); sm->p_subn->min_ca_rate = rate; } data_vls = 1U << (ib_port_info_get_vl_cap(p_pi) - 1); if (data_vls > 1U << (sm->p_subn->opt.max_op_vls - 1)) data_vls = 1U << (sm->p_subn->opt.max_op_vls - 1); if (data_vls >= IB_MAX_NUM_VLS) data_vls = IB_MAX_NUM_VLS - 1; if ((uint8_t)data_vls < sm->p_subn->min_data_vls) { OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, "Setting endport minimal data VLs to:%u defined by port:0x%" PRIx64 "\n", data_vls, cl_ntoh64(port_guid)); sm->p_subn->min_data_vls = data_vls; } } /* Check M_Key vs M_Key protect, can we control the port ? */ mpb = ib_port_info_get_mpb(p_pi); if (mpb > 0 && p_pi->m_key == 0) { OSM_LOG(sm->p_log, OSM_LOG_INFO, "Port 0x%" PRIx64 " has unknown M_Key, protection level %u\n", cl_ntoh64(port_guid), mpb); } if (port_guid != sm->p_subn->sm_port_guid) { p_sm_tbl = &sm->p_subn->sm_guid_tbl; if (p_pi->capability_mask & IB_PORT_CAP_IS_SM) { /* * Before querying the SM - we want to make sure we * clean its state, so if the querying fails we * recognize that this SM is not active. */ p_sm = (osm_remote_sm_t *) cl_qmap_get(p_sm_tbl, port_guid); if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl)) /* clean it up */ p_sm->smi.pri_state = 0xF0 & p_sm->smi.pri_state; if (sm->p_subn->opt.ignore_other_sm) OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, "Ignoring SM on port 0x%" PRIx64 "\n", cl_ntoh64(port_guid)); else { OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, "Detected another SM. Requesting SMInfo " "from port 0x%" PRIx64 "\n", cl_ntoh64(port_guid)); /* This port indicates it's an SM and it's not our own port. Acquire the SMInfo Attribute. */ memset(&context, 0, sizeof(context)); context.smi_context.set_method = FALSE; context.smi_context.port_guid = port_guid; status = osm_req_get(sm, osm_physp_get_dr_path_ptr (p_physp), IB_MAD_ATTR_SM_INFO, 0, FALSE, ib_port_info_get_m_key(&p_physp->port_info), CL_DISP_MSGID_NONE, &context); if (status != IB_SUCCESS) OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F05: " "Failure requesting SMInfo (%s) " "from port 0x%" PRIx64 "\n", ib_get_err_str(status), cl_ntoh64(port_guid)); } } else { p_sm = (osm_remote_sm_t *) cl_qmap_remove(p_sm_tbl, port_guid); if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl)) free(p_sm); } } OSM_LOG_EXIT(sm->p_log); }