boolean_t
osm_pkt_randomizer_mad_drop(IN osm_log_t * p_log,
			    IN osm_pkt_randomizer_t * p_pkt_randomizer,
			    IN const ib_mad_t * p_mad)
{
	const ib_smp_t *p_smp;
	boolean_t res = FALSE;
	osm_dr_path_t dr_path;

	OSM_LOG_ENTER(p_log);

	p_smp = (ib_smp_t *) p_mad;

	if (p_smp->mgmt_class != IB_MCLASS_SUBN_DIR)
		/* This is a lid route mad. Don't drop it */
		goto Exit;

	osm_dr_path_init(&dr_path, 0,	/* The h_bind is not really important for us to save */
			 p_smp->hop_count, p_smp->initial_path);

	if (__osm_pkt_randomizer_process_path
	    (p_log, p_pkt_randomizer, &dr_path)) {
		/* the mad should be dropped o */
		OSM_LOG(p_log, OSM_LOG_VERBOSE,
			"mad TID: 0x%" PRIx64 " is being dropped\n",
			cl_ntoh64(p_smp->trans_id));
		res = TRUE;
	}

Exit:
	OSM_LOG_EXIT(p_log);
	return res;
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
/**********************************************************************
 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;
}
Ejemplo n.º 4
0
/**********************************************************************
 The plock must be held before calling this function.
**********************************************************************/
static void ni_rcv_process_existing_ca_or_router(IN osm_sm_t * sm,
						 IN osm_node_t * p_node,
						 IN const osm_madw_t * p_madw)
{
	ib_node_info_t *p_ni;
	ib_smp_t *p_smp;
	osm_port_t *p_port;
	osm_port_t *p_port_check;
	uint8_t port_num;
	osm_dr_path_t *p_dr_path;
	osm_alias_guid_t *p_alias_guid, *p_alias_guid_check;

	OSM_LOG_ENTER(sm->p_log);

	p_smp = osm_madw_get_smp_ptr(p_madw);
	p_ni = ib_smp_get_payload_ptr(p_smp);
	port_num = ib_node_info_get_local_port_num(p_ni);

	/*
	   Determine if we have encountered this node through a
	   previously undiscovered port.  If so, build the new
	   port object.
	 */
	p_port = osm_get_port_by_guid(sm->p_subn, p_ni->port_guid);
	if (!p_port) {
		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
			"Creating new port object with GUID 0x%" PRIx64 "\n",
			cl_ntoh64(p_ni->port_guid));

		osm_node_init_physp(p_node, port_num, p_madw);

		p_port = osm_port_new(p_ni, p_node);
		if (PF(p_port == NULL)) {
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D04: "
				"Unable to create new port object\n");
			goto Exit;
		}

		/*
		   Add the new port object to the database.
		 */
		p_port_check =
		    (osm_port_t *) cl_qmap_insert(&sm->p_subn->port_guid_tbl,
						  p_ni->port_guid,
						  &p_port->map_item);
		if (PF(p_port_check != p_port)) {
			/*
			   We should never be here!
			   Somehow, this port GUID already exists in the table.
			 */
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D12: "
				"Port 0x%" PRIx64 " already in the database!\n",
				cl_ntoh64(p_ni->port_guid));

			osm_port_delete(&p_port);
			goto Exit;
		}

		p_alias_guid = osm_alias_guid_new(p_ni->port_guid,
						  p_port);
		if (PF(!p_alias_guid)) {
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D11: "
				"alias guid memory allocation failed"
				" for port GUID 0x%" PRIx64 "\n",
				cl_ntoh64(p_ni->port_guid));
			goto alias_done;
		}

		/* insert into alias guid table */
		p_alias_guid_check =
			(osm_alias_guid_t *) cl_qmap_insert(&sm->p_subn->alias_port_guid_tbl,
							    p_alias_guid->alias_guid,
							    &p_alias_guid->map_item);
		if (p_alias_guid_check != p_alias_guid) {
			/* alias GUID is a duplicate */
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D13: "
				"Duplicate alias port GUID 0x%" PRIx64 "\n",
				cl_ntoh64(p_ni->port_guid));
			osm_alias_guid_delete(&p_alias_guid);
			osm_port_delete(&p_port);
			goto Exit;
		}

alias_done:
		/* If we are a master, then this means the port is new on the subnet.
		   Mark it as new - need to send trap 64 for these ports.
		   The condition that we are master is true, since if we are in discovering
		   state (meaning we woke up from standby or we are just initializing),
		   then these ports may be new to us, but are not new on the subnet.
		   If we are master, then the subnet as we know it is the updated one,
		   and any new ports we encounter should cause trap 64. C14-72.1.1 */
		if (sm->p_subn->sm_state == IB_SMINFO_STATE_MASTER)
			p_port->is_new = 1;

	} else {
		osm_physp_t *p_physp = osm_node_get_physp_ptr(p_node, port_num);

		if (PF(p_physp == NULL)) {
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D1C: "
				"No physical port found for node GUID 0x%"
				PRIx64 " port %u. Might be duplicate port GUID\n",
				cl_ntoh64(p_node->node_info.node_guid),
				port_num);
			goto Exit;
		}

		/*
		   Update the DR Path to the port,
		   in case the old one is no longer available.
		 */
		p_dr_path = osm_physp_get_dr_path_ptr(p_physp);

		osm_dr_path_init(p_dr_path, p_smp->hop_count,
				 p_smp->initial_path);
	}

	ni_rcv_get_port_info(sm, p_node, p_madw);

Exit:
	OSM_LOG_EXIT(sm->p_log);
}
Ejemplo n.º 5
0
/**********************************************************************
 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;
}
Ejemplo n.º 6
0
void osm_pi_rcv_process(IN void *context, IN void *data)
{
	osm_sm_t *sm = context;
	osm_madw_t *p_madw = data;
	ib_port_info_t *p_pi;
	ib_smp_t *p_smp;
	osm_port_t *p_port;
	osm_physp_t *p_physp;
	osm_dr_path_t *p_dr_path;
	osm_node_t *p_node;
	osm_pi_context_t *p_context;
	ib_net64_t port_guid, node_guid;
	uint8_t port_num;

	CL_ASSERT(sm);

	OSM_LOG_ENTER(sm->p_log);

	CL_ASSERT(p_madw);

	p_smp = osm_madw_get_smp_ptr(p_madw);
	p_context = osm_madw_get_pi_context_ptr(p_madw);
	p_pi = ib_smp_get_payload_ptr(p_smp);

	CL_ASSERT(p_smp->attr_id == IB_MAD_ATTR_PORT_INFO);

	/*
	 * Attribute modifier has already been validated upon MAD receive,
	 * which means that port_num has to be valid - it originated from
	 * the request attribute modifier.
	 */
	port_num = (uint8_t) cl_ntoh32(p_smp->attr_mod);

	port_guid = p_context->port_guid;
	node_guid = p_context->node_guid;

	osm_dump_port_info_v2(sm->p_log, node_guid, port_guid, port_num, p_pi,
			      FILE_ID, OSM_LOG_DEBUG);

	/* On receipt of client reregister, clear the reregister bit so
	   reregistering won't be sent again and again */
	if (p_context->set_method &&
	    (ib_port_info_get_client_rereg(p_pi) || p_context->client_rereg)) {
		OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
			"Client reregister received on response\n");
		ib_port_info_set_client_rereg(p_pi, 0);
		p_context->client_rereg = FALSE;
	}

	/*
	   we might get a response during a light sweep looking for a change in
	   the status of a remote port that did not respond in earlier sweeps.
	   So if the context of the Get was light_sweep - we do not need to
	   do anything with the response - just flag that we need a heavy sweep
	 */
	if (p_context->light_sweep == TRUE) {
		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
			"Got light sweep response from remote port of parent node "
			"GUID 0x%" PRIx64 " port 0x%016" PRIx64
			", Commencing heavy sweep\n",
			cl_ntoh64(node_guid), cl_ntoh64(port_guid));
		sm->p_subn->force_heavy_sweep = TRUE;
		sm->p_subn->ignore_existing_lfts = TRUE;
		goto Exit;
	}

	CL_PLOCK_EXCL_ACQUIRE(sm->p_lock);
	p_port = osm_get_port_by_guid(sm->p_subn, port_guid);
	if (PF(!p_port)) {
		CL_PLOCK_RELEASE(sm->p_lock);
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F06: "
			"No port object for port with GUID 0x%" PRIx64
			"\n\t\t\t\tfor parent node GUID 0x%" PRIx64
			", TID 0x%" PRIx64 "\n",
			cl_ntoh64(port_guid),
			cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id));
		goto Exit;
	}

	p_node = p_port->p_node;
	CL_ASSERT(p_node);

	if (PF(p_pi->local_port_num > p_node->node_info.num_ports)) {
		CL_PLOCK_RELEASE(sm->p_lock);
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F15: "
			"Received PortInfo for port GUID 0x%" PRIx64 " is "
			"non-compliant and is being ignored since the "
			"local port num %u > num ports %u\n",
			cl_ntoh64(port_guid), p_pi->local_port_num,
			p_node->node_info.num_ports);
		goto Exit;
	}

	/*
	   If we were setting the PortInfo, then receiving
	   this attribute was not part of sweeping the subnet.
	   In this case, just update the PortInfo attribute.

	   In an unfortunate blunder, the IB spec defines the
	   return method for Set() as a GetResp().  Thus, we can't
	   use the method (what would have been SetResp()) to determine
	   our course of action.  So, we have to carry this extra
	   boolean around to determine if we were doing Get() or Set().
	 */
	if (p_context->set_method)
		pi_rcv_process_set(sm, p_node, port_num, p_madw);
	else {

		/*
		   This PortInfo arrived because we did a Get() method,
		   most likely due to a subnet sweep in progress.
		 */
		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
			"Discovered port num %u with GUID 0x%" PRIx64
			" for parent node GUID 0x%" PRIx64
			", TID 0x%" PRIx64 "\n",
			port_num, cl_ntoh64(port_guid),
			cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id));

		p_physp = osm_node_get_physp_ptr(p_node, port_num);

		CL_ASSERT(p_physp);

		/* Update the directed route path to this port
		   in case the old path is no longer usable. */
		p_dr_path = osm_physp_get_dr_path_ptr(p_physp);
		osm_dr_path_init(p_dr_path, p_smp->hop_count,
				 p_smp->initial_path);

		p_physp->need_update = osm_pi_rcv_update_self(sm, p_physp, p_pi);

		switch (osm_node_get_type(p_node)) {
		case IB_NODE_TYPE_CA:
		case IB_NODE_TYPE_ROUTER:
			if (!p_node->physp_discovered[port_num]) {
				p_port->discovery_count++;
				p_node->physp_discovered[port_num] = 1;
			}
			p_physp->need_update = osm_pi_rcv_update_neighbor(p_physp);
			pi_rcv_process_ca_or_router_port(sm, p_node, p_physp,
							 p_pi);
			break;
		case IB_NODE_TYPE_SWITCH:
			if (!p_node->physp_discovered[port_num]) {
				p_port->discovery_count++;
				p_node->physp_discovered[port_num] = 1;
			}
			if (port_num == 0)
				pi_rcv_process_switch_port0(sm, p_node,
							    p_physp, p_pi);
			else
				pi_rcv_process_switch_ext_port(sm, p_node,
							       p_physp, p_pi);
			break;
		default:
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F07: "
				"Unknown node type %u with GUID 0x%" PRIx64
				"\n", osm_node_get_type(p_node),
				cl_ntoh64(node_guid));
			break;
		}

		/*
		   Get the tables on the physp.
		 */
		if (p_physp->need_update || (p_node->sw &&
					     p_node->sw->need_update))
			pi_rcv_get_pkey_slvl_vla_tables(sm, p_node, p_physp);

	}

	CL_PLOCK_RELEASE(sm->p_lock);

Exit:
	/*
	   Release the lock before jumping here!!
	 */
	OSM_LOG_EXIT(sm->p_log);
}
Ejemplo n.º 7
0
void osm_pi_rcv_process(IN void *context, IN void *data)
{
	osm_sm_t *sm = context;
	osm_madw_t *p_madw = data;
	ib_port_info_t *p_pi;
	ib_smp_t *p_smp;
	osm_port_t *p_port;
	osm_physp_t *p_physp;
	osm_dr_path_t *p_dr_path;
	osm_node_t *p_node;
	osm_pi_context_t *p_context;
	ib_net64_t port_guid;
	ib_net64_t node_guid;
	uint8_t port_num;

	OSM_LOG_ENTER(sm->p_log);

	CL_ASSERT(sm);
	CL_ASSERT(p_madw);

	p_smp = osm_madw_get_smp_ptr(p_madw);
	p_context = osm_madw_get_pi_context_ptr(p_madw);
	p_pi = (ib_port_info_t *) ib_smp_get_payload_ptr(p_smp);

	CL_ASSERT(p_smp->attr_id == IB_MAD_ATTR_PORT_INFO);

	port_num = (uint8_t) cl_ntoh32(p_smp->attr_mod);

	port_guid = p_context->port_guid;
	node_guid = p_context->node_guid;

	osm_dump_port_info(sm->p_log,
			   node_guid, port_guid, port_num, p_pi, OSM_LOG_DEBUG);

	/* On receipt of client reregister, clear the reregister bit so
	   reregistering won't be sent again and again */
	if (ib_port_info_get_client_rereg(p_pi)) {
		OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
			"Client reregister received on response\n");
		ib_port_info_set_client_rereg(p_pi, 0);
	}

	/*
	   we might get a response during a light sweep looking for a change in
	   the status of a remote port that did not respond in earlier sweeps.
	   So if the context of the Get was light_sweep - we do not need to
	   do anything with the response - just flag that we need a heavy sweep
	 */
	if (p_context->light_sweep == TRUE) {
		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
			"Got light sweep response from remote port of parent node "
			"GUID 0x%" PRIx64 " port 0x%016" PRIx64
			", Commencing heavy sweep\n",
			cl_ntoh64(node_guid), cl_ntoh64(port_guid));
		sm->p_subn->force_heavy_sweep = TRUE;
		sm->p_subn->ignore_existing_lfts = TRUE;
		goto Exit;
	}

	CL_PLOCK_EXCL_ACQUIRE(sm->p_lock);
	p_port = osm_get_port_by_guid(sm->p_subn, port_guid);
	if (!p_port) {
		CL_PLOCK_RELEASE(sm->p_lock);
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F06: "
			"No port object for port with GUID 0x%" PRIx64
			"\n\t\t\t\tfor parent node GUID 0x%" PRIx64
			", TID 0x%" PRIx64 "\n",
			cl_ntoh64(port_guid),
			cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id));
		goto Exit;
	}

	p_node = p_port->p_node;
	CL_ASSERT(p_node);

	/*
	   If we were setting the PortInfo, then receiving
	   this attribute was not part of sweeping the subnet.
	   In this case, just update the PortInfo attribute.

	   In an unfortunate blunder, the IB spec defines the
	   return method for Set() as a GetResp().  Thus, we can't
	   use the method (what would have been SetResp()) to determine
	   our course of action.  So, we have to carry this extra
	   boolean around to determine if we were doing Get() or Set().
	 */
	if (p_context->set_method)
		osm_pi_rcv_process_set(sm, p_node, port_num, p_madw);
	else {
		p_port->discovery_count++;

		/*
		   This PortInfo arrived because we did a Get() method,
		   most likely due to a subnet sweep in progress.
		 */
		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
			"Discovered port num %u with GUID 0x%" PRIx64
			" for parent node GUID 0x%" PRIx64
			", TID 0x%" PRIx64 "\n",
			port_num, cl_ntoh64(port_guid),
			cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id));

		p_physp = osm_node_get_physp_ptr(p_node, port_num);

		/*
		   Determine if we encountered a new Physical Port.
		   If so, initialize the new Physical Port then
		   continue processing as normal.
		 */
		if (!p_physp) {
			OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
				"Initializing port number %u\n", port_num);
			p_physp = &p_node->physp_table[port_num];
			osm_physp_init(p_physp,
				       port_guid,
				       port_num,
				       p_node,
				       osm_madw_get_bind_handle(p_madw),
				       p_smp->hop_count, p_smp->initial_path);
		} else {
			/*
			   Update the directed route path to this port
			   in case the old path is no longer usable.
			 */
			p_dr_path = osm_physp_get_dr_path_ptr(p_physp);
			osm_dr_path_init(p_dr_path,
					 osm_madw_get_bind_handle(p_madw),
					 p_smp->hop_count, p_smp->initial_path);
		}

		/* if port just inited or reached INIT state (external reset)
		   request update for port related tables */
		p_physp->need_update =
		    (ib_port_info_get_port_state(p_pi) == IB_LINK_INIT ||
		     p_physp->need_update > 1) ? 1 : 0;

		switch (osm_node_get_type(p_node)) {
		case IB_NODE_TYPE_CA:
		case IB_NODE_TYPE_ROUTER:
			__osm_pi_rcv_process_ca_or_router_port(sm,
							       p_node, p_physp,
							       p_pi);
			break;
		case IB_NODE_TYPE_SWITCH:
			__osm_pi_rcv_process_switch_port(sm,
							 p_node, p_physp, p_pi);
			break;
		default:
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F07: "
				"Unknown node type %u with GUID 0x%" PRIx64
				"\n", osm_node_get_type(p_node),
				cl_ntoh64(node_guid));
			break;
		}

		/*
		   Get the tables on the physp.
		 */
		if (p_physp->need_update || sm->p_subn->need_update)
			__osm_pi_rcv_get_pkey_slvl_vla_tables(sm, p_node,
							      p_physp);

	}

	CL_PLOCK_RELEASE(sm->p_lock);

Exit:
	/*
	   Release the lock before jumping here!!
	 */
	OSM_LOG_EXIT(sm->p_log);
}