/********************************************************************** Actually Send a MAD MADs are buffers of type: struct ib_mad - so they are limited by size. This is for internal use by osm_vendor_send and the transaction mgr retry too. **********************************************************************/ ib_api_status_t osm_ts_send_mad(IN osm_ts_bind_info_t * p_bind, IN osm_madw_t * const p_madw) { osm_vendor_t *const p_vend = p_bind->p_vend; osm_mad_addr_t *const p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw); ib_mad_t *const p_mad = osm_madw_get_mad_ptr(p_madw); struct ib_mad ts_mad; int ret; ib_api_status_t status; OSM_LOG_ENTER(p_vend->p_log); /* * Copy the MAD over to the sent mad */ memcpy(&ts_mad, p_mad, 256); /* * For all sends other than directed route SM MADs, * acquire an address vector for the destination. */ if (p_mad->mgmt_class != IB_MCLASS_SUBN_DIR) { __osm_ts_conv_osm_addr_to_ts_addr(p_mad_addr, p_mad->mgmt_class == IB_MCLASS_SUBN_LID, &ts_mad); } else { /* is a directed route - we need to construct a permissive address */ /* we do not need port number since it is part of the mad_hndl */ ts_mad.dlid = IB_LID_PERMISSIVE; ts_mad.slid = IB_LID_PERMISSIVE; } if ((p_mad->mgmt_class == IB_MCLASS_SUBN_DIR) || (p_mad->mgmt_class == IB_MCLASS_SUBN_LID)) { ts_mad.sqpn = 0; ts_mad.dqpn = 0; } else { ts_mad.sqpn = 1; ts_mad.dqpn = 1; } ts_mad.port = p_bind->port_num; /* send it */ ret = write(p_bind->ul_dev_fd, &ts_mad, sizeof(ts_mad)); if (ret != sizeof(ts_mad)) { osm_log(p_vend->p_log, OSM_LOG_ERROR, "osm_ts_send_mad: ERR 5026: " "Error sending mad (%d).\n", ret); status = IB_ERROR; goto Exit; } status = IB_SUCCESS; Exit: OSM_LOG_EXIT(p_vend->p_log); return (status); }
ib_api_status_t osmv_simple_send_madw(IN osm_bind_handle_t h_bind, IN osm_madw_t * const p_madw, IN osmv_txn_ctx_t * p_txn, IN boolean_t is_retry) { ib_api_status_t ret; osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; osm_mad_addr_t *p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw); uint8_t mad_buf[MAD_BLOCK_SIZE]; ib_mad_t *p_mad = (ib_mad_t *) mad_buf; uint64_t key = 0; OSM_LOG_ENTER(p_bo->p_vendor->p_log); CL_ASSERT(p_madw->mad_size <= MAD_BLOCK_SIZE); memset(p_mad, 0, MAD_BLOCK_SIZE); memcpy(p_mad, osm_madw_get_mad_ptr(p_madw), p_madw->mad_size); if (NULL != p_txn) { /* Push a fake txn id to the MAD */ key = osmv_txn_get_key(p_txn); p_mad->trans_id = cl_hton64(key); } /* Add call for packet drop randomizer. This is a testing feature. If run_randomizer flag is set to TRUE, the randomizer will be called, and randomally will drop a packet. This is used for simulating unstable fabric. */ if (p_bo->p_vendor->run_randomizer == TRUE) { /* Try the randomizer */ if (osm_pkt_randomizer_mad_drop(p_bo->p_vendor->p_log, p_bo->p_vendor-> p_pkt_randomizer, p_mad) == TRUE) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "The MAD will not be sent. \n"); ret = IB_SUCCESS; } else { ret = osmv_transport_mad_send(h_bind, p_mad, p_mad_addr); } } else { ret = osmv_transport_mad_send(h_bind, p_mad, p_mad_addr); } if ((IB_SUCCESS == ret) && (NULL != p_txn) && (!is_retry)) { /* Set the timeout for receiving the response MAD */ ret = osmv_txn_set_timeout_ev(h_bind, key, p_bo->p_vendor->resp_timeout); } OSM_LOG_EXIT(p_bo->p_vendor->p_log); return ret; }
void osm_mpr_rcv_process(IN void *context, IN void *data) { osm_sa_t *sa = context; osm_madw_t *p_madw = data; const ib_multipath_rec_t *p_mpr; ib_sa_mad_t *p_sa_mad; osm_port_t *requester_port; osm_alias_guid_t *pp_alias_guids[IB_MULTIPATH_MAX_GIDS]; cl_qlist_t pr_list; ib_net16_t sa_status; int nsrc, ndest; uint8_t rate, mtu; OSM_LOG_ENTER(sa->p_log); CL_ASSERT(p_madw); p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); p_mpr = (ib_multipath_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_MULTIPATH_RECORD); if ((p_sa_mad->rmpp_flags & IB_RMPP_FLAG_ACTIVE) != IB_RMPP_FLAG_ACTIVE) { OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4510: " "Invalid request since RMPP_FLAG_ACTIVE is not set\n"); osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); goto Exit; } /* we only support SubnAdmGetMulti method */ if (p_sa_mad->method != IB_MAD_METHOD_GETMULTI) { OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4513: " "Unsupported Method (%s)\n", ib_get_sa_method_str(p_sa_mad->method)); osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); goto Exit; } /* update the requester physical port */ requester_port = osm_get_port_by_mad_addr(sa->p_log, sa->p_subn, osm_madw_get_mad_addr_ptr (p_madw)); if (requester_port == NULL) { OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4517: " "Cannot find requester physical port\n"); goto Exit; } if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) { OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Requester port GUID 0x%" PRIx64 "\n", cl_ntoh64(osm_port_get_guid(requester_port))); osm_dump_multipath_record_v2(sa->p_log, p_mpr, FILE_ID, OSM_LOG_DEBUG); } /* Make sure required components (S/DGIDCount) are supplied */ if (!(p_sa_mad->comp_mask & IB_MPR_COMPMASK_SGIDCOUNT) || !(p_sa_mad->comp_mask & IB_MPR_COMPMASK_DGIDCOUNT)) { osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INSUF_COMPS); goto Exit; } /* Validate rate if supplied */ if ((p_sa_mad->comp_mask & IB_MPR_COMPMASK_RATESELEC) && (p_sa_mad->comp_mask & IB_MPR_COMPMASK_RATE)) { rate = ib_multipath_rec_rate(p_mpr); if (!ib_rate_is_valid(rate)) { osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); goto Exit; } } /* Validate MTU if supplied */ if ((p_sa_mad->comp_mask & IB_MPR_COMPMASK_MTUSELEC) && (p_sa_mad->comp_mask & IB_MPR_COMPMASK_MTU)) { mtu = ib_multipath_rec_mtu(p_mpr); if (!ib_mtu_is_valid(mtu)) { osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); goto Exit; } } /* Make sure either none or both ServiceID parameters are supplied */ if ((p_sa_mad->comp_mask & IB_MPR_COMPMASK_SERVICEID) != 0 && (p_sa_mad->comp_mask & IB_MPR_COMPMASK_SERVICEID) != IB_MPR_COMPMASK_SERVICEID) { osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INSUF_COMPS); goto Exit; } cl_qlist_init(&pr_list); /* Most SA functions (including this one) are read-only on the subnet object, so we grab the lock non-exclusively. */ cl_plock_acquire(sa->p_lock); sa_status = mpr_rcv_get_end_points(sa, p_madw, pp_alias_guids, &nsrc, &ndest); if (sa_status != IB_SA_MAD_STATUS_SUCCESS || !nsrc || !ndest) { if (sa_status == IB_SA_MAD_STATUS_SUCCESS && (!nsrc || !ndest)) OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4512: " "mpr_rcv_get_end_points failed, # GIDs found; " "src %d; dest %d)\n", nsrc, ndest); cl_plock_release(sa->p_lock); if (sa_status == IB_SA_MAD_STATUS_SUCCESS) osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); else osm_sa_send_error(sa, p_madw, sa_status); goto Exit; } /* APM request */ if (nsrc == 2 && ndest == 2 && (p_mpr->num_path & 0x7F) == 2) mpr_rcv_get_apm_paths(sa, p_mpr, requester_port, pp_alias_guids, p_sa_mad->comp_mask, &pr_list); else mpr_rcv_process_pairs(sa, p_mpr, requester_port, pp_alias_guids, nsrc, ndest, p_sa_mad->comp_mask, &pr_list); cl_plock_release(sa->p_lock); /* o15-0.2.7: If MultiPath is supported, then SA shall respond to a SubnAdmGetMulti() containing a valid MultiPathRecord attribute with a set of zero or more PathRecords satisfying the constraints indicated in the MultiPathRecord received. The PathRecord Attribute ID shall be used in the response. */ p_sa_mad->attr_id = IB_MAD_ATTR_PATH_RECORD; osm_sa_respond(sa, p_madw, sizeof(ib_path_rec_t), &pr_list); Exit: OSM_LOG_EXIT(sa->p_log); }
void osm_slvl_rec_rcv_process(IN void *ctx, IN void *data) { osm_sa_t *sa = ctx; osm_madw_t *p_madw = data; const ib_sa_mad_t *p_rcvd_mad; const ib_slvl_table_record_t *p_rcvd_rec; const osm_port_t *p_port = NULL; cl_qlist_t rec_list; osm_slvl_search_ctxt_t context; ib_api_status_t status = IB_SUCCESS; ib_net64_t comp_mask; osm_physp_t *p_req_physp; CL_ASSERT(sa); OSM_LOG_ENTER(sa->p_log); CL_ASSERT(p_madw); p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw); p_rcvd_rec = (ib_slvl_table_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); comp_mask = p_rcvd_mad->comp_mask; CL_ASSERT(p_rcvd_mad->attr_id == IB_MAD_ATTR_SLVL_RECORD); /* we only support SubnAdmGet and SubnAdmGetTable methods */ if (p_rcvd_mad->method != IB_MAD_METHOD_GET && p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) { OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2604: " "Unsupported Method (%s)\n", ib_get_sa_method_str(p_rcvd_mad->method)); osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); goto Exit; } /* update the requester physical port. */ p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, osm_madw_get_mad_addr_ptr (p_madw)); if (p_req_physp == NULL) { OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2603: " "Cannot find requester physical port\n"); goto Exit; } cl_qlist_init(&rec_list); context.p_rcvd_rec = p_rcvd_rec; context.p_list = &rec_list; context.comp_mask = p_rcvd_mad->comp_mask; context.sa = sa; context.in_port_num = p_rcvd_rec->in_port_num; context.p_req_physp = p_req_physp; cl_plock_acquire(sa->p_lock); OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Got Query Lid:%u(%02X), In-Port:0x%02X(%02X), Out-Port:0x%02X(%02X)\n", cl_ntoh16(p_rcvd_rec->lid), (comp_mask & IB_SLVL_COMPMASK_LID) != 0, p_rcvd_rec->in_port_num, (comp_mask & IB_SLVL_COMPMASK_IN_PORT) != 0, p_rcvd_rec->out_port_num, (comp_mask & IB_SLVL_COMPMASK_OUT_PORT) != 0); /* If the user specified a LID, it obviously narrows our work load, since we don't have to search every port */ if (comp_mask & IB_SLVL_COMPMASK_LID) { status = osm_get_port_by_base_lid(sa->p_subn, p_rcvd_rec->lid, &p_port); if ((status != IB_SUCCESS) || (p_port == NULL)) { status = IB_NOT_FOUND; OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2608: " "No port found with LID %u\n", cl_ntoh16(p_rcvd_rec->lid)); } } if (status == IB_SUCCESS) { /* if we have a unique port - no need for a port search */ if (p_port) /* this does the loop on all the port phys ports */ __osm_sa_slvl_by_comp_mask(sa, p_port, &context); else cl_qmap_apply_func(&sa->p_subn->port_guid_tbl, __osm_sa_slvl_by_comp_mask_cb, &context); } cl_plock_release(sa->p_lock); osm_sa_respond(sa, p_madw, sizeof(ib_slvl_table_record_t), &rec_list); Exit: OSM_LOG_EXIT(sa->p_log); }
static ib_api_status_t __osmv_rmpp_send_segment(IN osm_bind_handle_t h_bind, IN osmv_txn_ctx_t * p_txn, IN uint32_t seg_num) { ib_api_status_t ret; osmv_rmpp_send_ctx_t *p_send_ctx; uint8_t mad_buf[MAD_BLOCK_SIZE]; ib_mad_t *p_mad = (ib_mad_t *) mad_buf; osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; osm_mad_addr_t *p_mad_addr = osm_madw_get_mad_addr_ptr(osmv_txn_get_madw(p_txn)); uint32_t timeout = p_bo->p_vendor->resp_timeout; uint64_t key; OSM_LOG_ENTER(p_bo->p_vendor->p_log); #ifdef OSMV_RANDOM_DROP if (TRUE == osmv_random_drop()) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "Error injection - simulating the RMPP segment drop\n"); return IB_SUCCESS; } #endif p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn); key = osmv_txn_get_key(p_txn); if (0 != seg_num) { ret = osmv_rmpp_send_ctx_get_seg(p_send_ctx, seg_num, timeout, p_mad); CL_ASSERT(IB_SUCCESS == ret); /* Put the segment to the wire ! */ p_mad->trans_id = cl_hton64(key); osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "Sending RMPP segment #%d, on-wire TID=0x%llX\n", seg_num, p_mad->trans_id); /* Add call for packet drop randomizer. This is a testing feature. If run_randomizer flag is set to TRUE, the randomizer will be called, and randomally will drop a packet. This is used for simulating unstable fabric. */ if (p_bo->p_vendor->run_randomizer == TRUE) { /* Try the randomizer */ if (osm_pkt_randomizer_mad_drop(p_bo->p_vendor->p_log, p_bo->p_vendor-> p_pkt_randomizer, p_mad) == TRUE) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "The MAD will not be sent. \n"); ret = IB_SUCCESS; } else { ret = osmv_transport_mad_send((osm_bind_handle_t) p_bo, p_mad, p_mad_addr); } } else { ret = osmv_transport_mad_send((osm_bind_handle_t) p_bo, p_mad, p_mad_addr); } } else { /* This is an ACK for double-sided handshake. Give it a special treatment. */ /* It doesn't really matter which data to put. Only the header matters. */ ret = osmv_rmpp_send_ctx_get_seg(p_send_ctx, 1, timeout, p_mad); CL_ASSERT(IB_SUCCESS == ret); p_mad->trans_id = cl_hton64(key); ret = osmv_rmpp_send_ack((osm_bind_handle_t) p_bo, p_mad, 0 /* segnum */ , OSMV_RMPP_RECV_WIN /* NWL */ , p_mad_addr); } OSM_LOG_EXIT(p_bo->p_vendor->p_log); return ret; }
/********************************************************************** Received a Get(InformInfoRecord) or GetTable(InformInfoRecord) MAD **********************************************************************/ static void osm_infr_rcv_process_get_method(IN osm_sa_t * sa, IN osm_madw_t * const p_madw) { char gid_str[INET6_ADDRSTRLEN]; ib_sa_mad_t *p_rcvd_mad; const ib_inform_info_record_t *p_rcvd_rec; cl_qlist_t rec_list; osm_iir_search_ctxt_t context; osm_physp_t *p_req_physp; osm_iir_item_t *item; OSM_LOG_ENTER(sa->p_log); CL_ASSERT(p_madw); p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw); p_rcvd_rec = (ib_inform_info_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); /* update the requester physical port. */ p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, osm_madw_get_mad_addr_ptr (p_madw)); if (p_req_physp == NULL) { OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4309: " "Cannot find requester physical port\n"); goto Exit; } if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) osm_dump_inform_info_record(sa->p_log, p_rcvd_rec, OSM_LOG_DEBUG); cl_qlist_init(&rec_list); context.p_rcvd_rec = p_rcvd_rec; context.p_list = &rec_list; context.comp_mask = p_rcvd_mad->comp_mask; context.subscriber_gid = p_rcvd_rec->subscriber_gid; context.subscriber_enum = p_rcvd_rec->subscriber_enum; context.sa = sa; context.p_req_physp = p_req_physp; OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Query Subscriber GID:%s(%02X) Enum:0x%X(%02X)\n", inet_ntop(AF_INET6, p_rcvd_rec->subscriber_gid.raw, gid_str, sizeof gid_str), (p_rcvd_mad->comp_mask & IB_IIR_COMPMASK_SUBSCRIBERGID) != 0, cl_ntoh16(p_rcvd_rec->subscriber_enum), (p_rcvd_mad->comp_mask & IB_IIR_COMPMASK_ENUM) != 0); cl_plock_acquire(sa->p_lock); cl_qlist_apply_func(&sa->p_subn->sa_infr_list, __osm_sa_inform_info_rec_by_comp_mask_cb, &context); cl_plock_release(sa->p_lock); /* clear reserved and pad fields in InformInfoRecord */ for (item = (osm_iir_item_t *) cl_qlist_head(&rec_list); item != (osm_iir_item_t *) cl_qlist_end(&rec_list); item = (osm_iir_item_t *)cl_qlist_next(&item->list_item)) { memset(item->rec.reserved, 0, sizeof(item->rec.reserved)); memset(item->rec.pad, 0, sizeof(item->rec.pad)); } osm_sa_respond(sa, p_madw, sizeof(ib_inform_info_record_t), &rec_list); Exit: OSM_LOG_EXIT(sa->p_log); }
static uint64_t __osmv_txn_timeout_cb(IN uint64_t key, IN uint32_t num_regs, IN void *cb_context) { osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) cb_context; uint64_t ret = 0; osmv_txn_ctx_t *p_txn; osmv_rmpp_send_ctx_t *p_send_ctx; osm_madw_t *p_madw = NULL; ib_mad_t *p_mad; osm_mad_addr_t *p_mad_addr; boolean_t invoke_err_cb = FALSE; OSM_LOG_ENTER(p_bo->p_vendor->p_log); /* Don't try to acquire a lock on the Bind Object - * it's taken by the mechanism that drives the timeout based events! * (Recall the special constructor that the Event Wheel is applied with) */ if (p_bo->is_closing) { goto txn_done; } ret = osmv_txn_lookup(p_bo, key, &p_txn); if (IB_NOT_FOUND == ret) { /* Prevent a race - the transaction is already destroyed */ goto txn_done; } p_madw = p_txn->p_madw; switch (osmv_txn_get_rmpp_state(p_txn)) { case OSMV_TXN_RMPP_NONE: if (num_regs <= OSMV_MAX_RETRANSMIT) { /* We still did not exceed the limit of retransmissions. * Set the next timeout's value. */ osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "__osmv_txn_timeout_cb: " "The transaction request (tid=0x%llX) timed out %d times. " "Retrying the send.\n", osmv_txn_get_tid(p_txn), num_regs); /* resend this mad */ ret = osmv_simple_send_madw((osm_bind_handle_t *) p_bo, p_madw, p_txn, TRUE); if (ret != IB_SUCCESS) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, "__osmv_txn_timeout_cb: " "Fail to send retry for transaction request (tid=0x%llX).\n", osmv_txn_get_tid(p_txn)); osmv_txn_done((osm_bind_handle_t) p_bo, key, TRUE /*in timeout callback */ ); /* This is a requester. Always apply the callback */ invoke_err_cb = TRUE; } else { uint64_t next_timeout_ms; next_timeout_ms = p_bo->p_vendor->resp_timeout * (num_regs + 1) * (num_regs + 1); /* when do we need to timeout again */ ret = cl_get_time_stamp() + (uint64_t) (1000 * next_timeout_ms); osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "__osmv_txn_timeout_cb: " "Retry request timout in : %lu [msec].\n", next_timeout_ms); } } else { osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, "__osmv_txn_timeout_cb: ERR 6702: " "The transaction request (tid=0x%llX) timed out (after %d retries). " "Invoking the error callback.\n", osmv_txn_get_tid(p_txn), num_regs); osmv_txn_done((osm_bind_handle_t) p_bo, key, TRUE /*in timeout callback */ ); /* This is a requester. Always apply the callback */ invoke_err_cb = TRUE; } break; case OSMV_TXN_RMPP_SENDER: osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "RMPP sender (tid=0x%llX) did not receive ACK " "on every segment in the current send window.\n", osmv_txn_get_tid(p_txn)); p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn); if (num_regs <= OSMV_MAX_RETRANSMIT) { /* We still did not exceed the limit of retransmissions. * Set the next timeout's value. */ ret = cl_get_time_stamp() + 1000 * p_bo->p_vendor->resp_timeout; } else { p_send_ctx->status = IB_TIMEOUT; p_mad = osm_madw_get_mad_ptr(p_madw); p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw); /* Send an ABORT to the other side */ osmv_rmpp_send_nak((osm_bind_handle_t) p_bo, p_mad, p_mad_addr, IB_RMPP_TYPE_ABORT, IB_RMPP_STATUS_T2L); } /* Wake the RMPP sender thread up */ cl_event_signal(&p_send_ctx->event); break; case OSMV_TXN_RMPP_RECEIVER: osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "Transaction timeout on an RMPP receiver (tid=0x%llX). " "Dropping the transaction.\n", osmv_txn_get_tid(p_txn)); osmv_txn_done((osm_bind_handle_t) p_bo, key, TRUE /*in timeout callback */ ); if (FALSE == osmv_txn_is_rmpp_init_by_peer(p_txn)) { /* This is a requester, still waiting for the reply. Apply the callback */ invoke_err_cb = TRUE; } break; default: CL_ASSERT(FALSE); } if (TRUE == invoke_err_cb) { CL_ASSERT(NULL != p_madw); /* update the status in the p_madw */ p_madw->status = IB_TIMEOUT; p_bo->send_err_cb(p_bo->cb_context, p_madw); /* no re-registration */ ret = 0; } txn_done: OSM_LOG_EXIT(p_bo->p_vendor->p_log); return ret; }
void osm_pkey_rec_rcv_process(IN void *ctx, IN void *data) { osm_sa_t *sa = ctx; osm_madw_t *p_madw = data; const ib_sa_mad_t *p_rcvd_mad; const ib_pkey_table_record_t *p_rcvd_rec; const osm_port_t *p_port = NULL; const ib_pkey_table_t *p_pkey; cl_qlist_t rec_list; osm_pkey_search_ctxt_t context; ib_api_status_t status = IB_SUCCESS; ib_net64_t comp_mask; osm_physp_t *p_req_physp; CL_ASSERT(sa); OSM_LOG_ENTER(sa->p_log); CL_ASSERT(p_madw); p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw); p_rcvd_rec = (ib_pkey_table_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); comp_mask = p_rcvd_mad->comp_mask; CL_ASSERT(p_rcvd_mad->attr_id == IB_MAD_ATTR_PKEY_TBL_RECORD); /* we only support SubnAdmGet and SubnAdmGetTable methods */ if (p_rcvd_mad->method != IB_MAD_METHOD_GET && p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) { OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4605: " "Unsupported Method (%s)\n", ib_get_sa_method_str(p_rcvd_mad->method)); osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); goto Exit; } /* p922 - P_KeyTableRecords shall only be provided in response to trusted requests. Check that the requester is a trusted one. */ if (p_rcvd_mad->sm_key != sa->p_subn->opt.sa_key) { /* This is not a trusted requester! */ OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4608: " "Request from non-trusted requester: " "Given SM_Key:0x%016" PRIx64 "\n", cl_ntoh64(p_rcvd_mad->sm_key)); osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); goto Exit; } /* update the requester physical port. */ p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, osm_madw_get_mad_addr_ptr (p_madw)); if (p_req_physp == NULL) { OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4604: " "Cannot find requester physical port\n"); goto Exit; } p_pkey = (ib_pkey_table_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); cl_qlist_init(&rec_list); context.p_rcvd_rec = p_rcvd_rec; context.p_list = &rec_list; context.comp_mask = p_rcvd_mad->comp_mask; context.sa = sa; context.block_num = p_rcvd_rec->block_num; context.p_req_physp = p_req_physp; OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Got Query Lid:%u(%02X), Block:0x%02X(%02X), Port:0x%02X(%02X)\n", cl_ntoh16(p_rcvd_rec->lid), (comp_mask & IB_PKEY_COMPMASK_LID) != 0, p_rcvd_rec->port_num, (comp_mask & IB_PKEY_COMPMASK_PORT) != 0, p_rcvd_rec->block_num, (comp_mask & IB_PKEY_COMPMASK_BLOCK) != 0); cl_plock_acquire(sa->p_lock); /* If the user specified a LID, it obviously narrows our work load, since we don't have to search every port */ if (comp_mask & IB_PKEY_COMPMASK_LID) { status = osm_get_port_by_base_lid(sa->p_subn, p_rcvd_rec->lid, &p_port); if (status != IB_SUCCESS || p_port == NULL) { status = IB_NOT_FOUND; OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 460B: " "No port found with LID %u\n", cl_ntoh16(p_rcvd_rec->lid)); } } if (status == IB_SUCCESS) { /* if we got a unique port - no need for a port search */ if (p_port) /* this does the loop on all the port phys ports */ __osm_sa_pkey_by_comp_mask(sa, p_port, &context); else cl_qmap_apply_func(&sa->p_subn->port_guid_tbl, __osm_sa_pkey_by_comp_mask_cb, &context); } cl_plock_release(sa->p_lock); osm_sa_respond(sa, p_madw, sizeof(ib_pkey_table_record_t), &rec_list); Exit: OSM_LOG_EXIT(sa->p_log); }
void osm_lftr_rcv_process(IN void *ctx, IN void *data) { osm_sa_t *sa = ctx; osm_madw_t *p_madw = data; const ib_sa_mad_t *p_rcvd_mad; const ib_lft_record_t *p_rcvd_rec; cl_qlist_t rec_list; osm_lftr_search_ctxt_t context; osm_physp_t *p_req_physp; CL_ASSERT(sa); OSM_LOG_ENTER(sa->p_log); CL_ASSERT(p_madw); p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw); p_rcvd_rec = (ib_lft_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); CL_ASSERT(p_rcvd_mad->attr_id == IB_MAD_ATTR_LFT_RECORD); /* we only support SubnAdmGet and SubnAdmGetTable methods */ if (p_rcvd_mad->method != IB_MAD_METHOD_GET && p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) { OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4408: " "Unsupported Method (%s)\n", ib_get_sa_method_str(p_rcvd_mad->method)); osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); goto Exit; } /* update the requester physical port */ p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, osm_madw_get_mad_addr_ptr (p_madw)); if (p_req_physp == NULL) { OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4407: " "Cannot find requester physical port\n"); goto Exit; } OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Requester port GUID 0x%" PRIx64 "\n", cl_ntoh64(osm_physp_get_port_guid(p_req_physp))); cl_qlist_init(&rec_list); context.p_rcvd_rec = p_rcvd_rec; context.p_list = &rec_list; context.comp_mask = p_rcvd_mad->comp_mask; context.sa = sa; context.p_req_physp = p_req_physp; cl_plock_acquire(sa->p_lock); /* Go over all switches */ cl_qmap_apply_func(&sa->p_subn->sw_guid_tbl, lftr_rcv_by_comp_mask, &context); cl_plock_release(sa->p_lock); osm_sa_respond(sa, p_madw, sizeof(ib_lft_record_t), &rec_list); Exit: OSM_LOG_EXIT(sa->p_log); }
ib_api_status_t osm_vendor_send(IN osm_bind_handle_t h_bind, IN osm_madw_t * const p_madw, IN boolean_t const resp_expected) { osm_al_bind_info_t *const p_bind = h_bind; osm_vendor_t *const p_vend = p_bind->p_vend; osm_vend_wrap_t *const p_vw = osm_madw_get_vend_ptr(p_madw); osm_mad_addr_t *const p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw); ib_mad_t *const p_mad = osm_madw_get_mad_ptr(p_madw); ib_api_status_t status; ib_mad_element_t *p_elem; ib_av_attr_t av; OSM_LOG_ENTER(p_vend->p_log); CL_ASSERT(p_vw->h_bind == h_bind); CL_ASSERT(p_vw->p_elem); p_elem = p_vw->p_elem; /* If a response is expected to this MAD, then preallocate a mad wrapper to contain the wire MAD received in the response. Allocating a wrapper here allows for easier failure paths than after we already received the wire mad. */ if (resp_expected) { p_vw->p_resp_madw = osm_mad_pool_get_wrapper_raw(p_bind->p_osm_pool); if (p_vw->p_resp_madw == NULL) { osm_log(p_vend->p_log, OSM_LOG_ERROR, "osm_vendor_send: ERR 3B27: " "Unable to allocate MAD wrapper.\n"); status = IB_INSUFFICIENT_RESOURCES; goto Exit; } } else p_vw->p_resp_madw = NULL; /* For all sends other than directed route SM MADs, acquire an address vector for the destination. */ if (p_mad->mgmt_class != IB_MCLASS_SUBN_DIR) { memset(&av, 0, sizeof(av)); av.port_num = p_bind->port_num; av.dlid = p_mad_addr->dest_lid; av.static_rate = p_mad_addr->static_rate; av.path_bits = p_mad_addr->path_bits; if ((p_mad->mgmt_class != IB_MCLASS_SUBN_LID) && (p_mad->mgmt_class != IB_MCLASS_SUBN_DIR)) { av.sl = p_mad_addr->addr_type.gsi.service_level; if (p_mad_addr->addr_type.gsi.global_route) { av.grh_valid = TRUE; /* ANIL */ /* av.grh = p_mad_addr->addr_type.gsi.grh_info; */ } } if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { osm_log(p_vend->p_log, OSM_LOG_DEBUG, "osm_vendor_send: " "av.port_num 0x%X, " "av.dlid 0x%X, " "av.static_rate %d, " "av.path_bits %d.\n", av.port_num, cl_ntoh16(av.dlid), av.static_rate, av.path_bits); } status = ib_create_av(p_vend->h_pd, &av, &p_vw->h_av); if (status != IB_SUCCESS) { osm_log(p_vend->p_log, OSM_LOG_ERROR, "osm_vendor_send: ERR 3B28: " "Unable to create address vector (%s).\n", ib_get_err_str(status)); if (p_vw->p_resp_madw) osm_mad_pool_put(p_bind->p_osm_pool, p_vw->p_resp_madw); goto Exit; } if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { osm_log(p_vend->p_log, OSM_LOG_DEBUG, "osm_vendor_send: " "Allocating av handle %p.\n", p_vw->h_av); } } else { p_vw->h_av = p_bind->h_dr_av; } p_elem->h_av = p_vw->h_av; p_elem->context1 = p_madw; p_elem->context2 = NULL; p_elem->immediate_data = 0; p_elem->p_grh = NULL; p_elem->resp_expected = resp_expected; p_elem->retry_cnt = OSM_DEFAULT_RETRY_COUNT; p_elem->send_opt = IB_SEND_OPT_SIGNALED; p_elem->timeout_ms = p_vend->timeout; /* Completion information. */ p_elem->status = 0; /* Not trusting AL */ if ((p_mad->mgmt_class == IB_MCLASS_SUBN_LID) || (p_mad->mgmt_class == IB_MCLASS_SUBN_DIR)) { p_elem->remote_qp = 0; p_elem->remote_qkey = 0; } else { p_elem->remote_qp = p_mad_addr->addr_type.gsi.remote_qp; p_elem->remote_qkey = p_mad_addr->addr_type.gsi.remote_qkey; osm_log(p_vend->p_log, OSM_LOG_DEBUG, "osm_vendor_send: " "remote qp = 0x%X, remote qkey = 0x%X.\n", cl_ntoh32(p_elem->remote_qp), cl_ntoh32(p_elem->remote_qkey)); } status = ib_send_mad(p_bind->h_svc, p_elem, NULL); if (status != IB_SUCCESS) { osm_log(p_vend->p_log, OSM_LOG_ERROR, "osm_vendor_send: ERR 3B29: " "Send failed (%s).\n", ib_get_err_str(status)); if (p_vw->p_resp_madw) osm_mad_pool_put(p_bind->p_osm_pool, p_vw->p_resp_madw); goto Exit; } Exit: OSM_LOG_EXIT(p_vend->p_log); return (status); }
ib_api_status_t osm_vendor_send(IN osm_bind_handle_t h_bind, IN osm_madw_t * const p_madw, IN boolean_t const resp_expected) { ib_api_status_t ret = IB_SUCCESS; osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; boolean_t is_rmpp = FALSE, is_rmpp_ds = FALSE; osmv_txn_ctx_t *p_txn = NULL; ib_mad_t *p_mad; osm_log_t *p_log = p_bo->p_vendor->p_log; osm_mad_pool_t *p_mad_pool = p_bo->p_osm_pool; OSM_LOG_ENTER(p_log); if (NULL == h_bind || NULL == p_madw || NULL == (p_mad = osm_madw_get_mad_ptr(p_madw)) || NULL == osm_madw_get_mad_addr_ptr(p_madw)) { return IB_INVALID_PARAMETER; } is_rmpp = (p_madw->mad_size > MAD_BLOCK_SIZE || osmv_mad_is_rmpp(p_mad)); /* is this rmpp double sided? This means we expect a response that can be an rmpp or not */ is_rmpp_ds = (TRUE == is_rmpp && TRUE == resp_expected); /* Make our operations with the send context atomic */ osmv_txn_lock(p_bo); if (TRUE == p_bo->is_closing) { osm_log(p_log, OSM_LOG_ERROR, "osm_vendor_send: ERR 7310: " "The handle %p is being unbound, cannot send.\n", h_bind); ret = IB_INTERRUPTED; /* When closing p_bo could be detroyed or is going to , thus could not refer to it */ goto send_done; } if (TRUE == resp_expected || TRUE == is_rmpp) { /* We must run under a transaction framework. * Get the transaction object (old or new) */ ret = __osmv_get_send_txn(h_bind, p_madw, is_rmpp, resp_expected, &p_txn); if (IB_SUCCESS != ret) { goto send_done; } } if (TRUE == is_rmpp) { /* Do the job - RMPP! * The call returns as all the packets are ACK'ed/upon error * The txn lock will be released each time the function sleeps * and re-acquired when it wakes up */ ret = osmv_rmpp_send_madw(h_bind, p_madw, p_txn, is_rmpp_ds); } else { /* Do the job - single MAD! * The call returns as soon as the MAD is put on the wire */ ret = osmv_simple_send_madw(h_bind, p_madw, p_txn, FALSE); } if (IB_SUCCESS == ret) { if ((TRUE == is_rmpp) && (FALSE == is_rmpp_ds)) { /* For double-sided sends, the txn continues to live */ osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), FALSE /*not in callback */ ); } if (FALSE == resp_expected) { osm_mad_pool_put(p_mad_pool, p_madw); } } else if (IB_INTERRUPTED != ret) { if (NULL != p_txn) { osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), FALSE /*not in callback */ ); } osm_log(p_log, OSM_LOG_ERROR, "osm_vendor_send: ERR 7311: failed to send MADW %p\n", p_madw); if (TRUE == resp_expected) { /* Change the status on the p_madw */ p_madw->status = ret; /* Only the requester expects the error callback */ p_bo->send_err_cb(p_bo->cb_context, p_madw); } else { /* put back the mad - it is useless ... */ osm_mad_pool_put(p_mad_pool, p_madw); } } else { /* the transaction was aborted due to p_bo exit */ osm_mad_pool_put(p_mad_pool, p_madw); goto aborted; } send_done: osmv_txn_unlock(p_bo); aborted: OSM_LOG_EXIT(p_log); return ret; }
void osm_smir_rcv_process(IN void *ctx, IN void *data) { osm_sa_t *sa = ctx; osm_madw_t *p_madw = data; const ib_sa_mad_t *sad_mad; const ib_sminfo_record_t *p_rcvd_rec; const osm_port_t *p_port = NULL; const ib_sm_info_t *p_smi; cl_qlist_t rec_list; osm_smir_search_ctxt_t context; ib_api_status_t status = IB_SUCCESS; ib_net64_t comp_mask; ib_net64_t port_guid; osm_physp_t *p_req_physp; osm_port_t *local_port; osm_remote_sm_t *p_rem_sm; cl_qmap_t *p_sm_guid_tbl; uint8_t pri_state; CL_ASSERT(sa); OSM_LOG_ENTER(sa->p_log); CL_ASSERT(p_madw); sad_mad = osm_madw_get_sa_mad_ptr(p_madw); p_rcvd_rec = (ib_sminfo_record_t *) ib_sa_mad_get_payload_ptr(sad_mad); comp_mask = sad_mad->comp_mask; CL_ASSERT(sad_mad->attr_id == IB_MAD_ATTR_SMINFO_RECORD); /* we only support SubnAdmGet and SubnAdmGetTable methods */ if (sad_mad->method != IB_MAD_METHOD_GET && sad_mad->method != IB_MAD_METHOD_GETTABLE) { OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2804: " "Unsupported Method (%s)\n", ib_get_sa_method_str(sad_mad->method)); osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); goto Exit; } /* update the requester physical port */ p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, osm_madw_get_mad_addr_ptr (p_madw)); if (p_req_physp == NULL) { OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2803: " "Cannot find requester physical port\n"); goto Exit; } if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) { OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Requester port GUID 0x%" PRIx64 "\n", cl_ntoh64(osm_physp_get_port_guid(p_req_physp))); osm_dump_sm_info_record_v2(sa->p_log, p_rcvd_rec, FILE_ID, OSM_LOG_DEBUG); } p_smi = &p_rcvd_rec->sm_info; cl_qlist_init(&rec_list); context.p_rcvd_rec = p_rcvd_rec; context.p_list = &rec_list; context.comp_mask = sad_mad->comp_mask; context.sa = sa; context.p_req_physp = p_req_physp; cl_plock_acquire(sa->p_lock); /* If the user specified a LID, it obviously narrows our work load, since we don't have to search every port */ if (comp_mask & IB_SMIR_COMPMASK_LID) { p_port = osm_get_port_by_lid(sa->p_subn, p_rcvd_rec->lid); if (!p_port) { status = IB_NOT_FOUND; OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2806: " "No port found with LID %u\n", cl_ntoh16(p_rcvd_rec->lid)); } } if (status == IB_SUCCESS) { /* Handle our own SM first */ local_port = osm_get_port_by_guid(sa->p_subn, sa->p_subn->sm_port_guid); if (!local_port) { cl_plock_release(sa->p_lock); OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2809: " "No port found with GUID 0x%016" PRIx64 "\n", cl_ntoh64(sa->p_subn->sm_port_guid)); goto Exit; } if (!p_port || local_port == p_port) { if (FALSE == osm_physp_share_pkey(sa->p_log, p_req_physp, local_port->p_physp, sa->p_subn->opt.allow_both_pkeys)) { cl_plock_release(sa->p_lock); OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2805: " "Cannot get SMInfo record due to pkey violation\n"); goto Exit; } /* Check that other search components specified match */ if ((comp_mask & IB_SMIR_COMPMASK_GUID) && sa->p_subn->sm_port_guid != p_smi->guid) goto Remotes; if ((comp_mask & IB_SMIR_COMPMASK_PRIORITY) && sa->p_subn->opt.sm_priority != ib_sminfo_get_priority(p_smi)) goto Remotes; if ((comp_mask & IB_SMIR_COMPMASK_SMSTATE) && sa->p_subn->sm_state != ib_sminfo_get_state(p_smi)) goto Remotes; /* Now, add local SMInfo to list */ pri_state = sa->p_subn->sm_state & 0x0F; pri_state |= (sa->p_subn->opt.sm_priority & 0x0F) << 4; smir_rcv_new_smir(sa, local_port, context.p_list, sa->p_subn->sm_port_guid, cl_ntoh32(sa->p_subn->p_osm->stats. qp0_mads_sent), pri_state, p_req_physp); } Remotes: if (p_port && p_port != local_port) { /* Find remote SM corresponding to p_port */ port_guid = osm_port_get_guid(p_port); p_sm_guid_tbl = &sa->p_subn->sm_guid_tbl; p_rem_sm = (osm_remote_sm_t *) cl_qmap_get(p_sm_guid_tbl, port_guid); if (p_rem_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_guid_tbl)) sa_smir_by_comp_mask(sa, p_rem_sm, &context); else OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 280A: " "No remote SM for GUID 0x%016" PRIx64 "\n", cl_ntoh64(port_guid)); } else { /* Go over all other known (remote) SMs */ cl_qmap_apply_func(&sa->p_subn->sm_guid_tbl, sa_smir_by_comp_mask_cb, &context); } } cl_plock_release(sa->p_lock); osm_sa_respond(sa, p_madw, sizeof(ib_sminfo_record_t), &rec_list); Exit: OSM_LOG_EXIT(sa->p_log); }
void osm_lr_rcv_process(IN void *context, IN void *data) { osm_sa_t *sa = context; osm_madw_t *p_madw = data; const ib_link_record_t *p_lr; const ib_sa_mad_t *p_sa_mad; const osm_port_t *p_src_port; const osm_port_t *p_dest_port; cl_qlist_t lr_list; ib_net16_t status; osm_physp_t *p_req_physp; OSM_LOG_ENTER(sa->p_log); CL_ASSERT(p_madw); p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); p_lr = ib_sa_mad_get_payload_ptr(p_sa_mad); CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_LINK_RECORD); /* we only support SubnAdmGet and SubnAdmGetTable methods */ if (p_sa_mad->method != IB_MAD_METHOD_GET && p_sa_mad->method != IB_MAD_METHOD_GETTABLE) { OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1804: " "Unsupported Method (%s)\n", ib_get_sa_method_str(p_sa_mad->method)); osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); goto Exit; } /* update the requester physical port */ p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, osm_madw_get_mad_addr_ptr (p_madw)); if (p_req_physp == NULL) { OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1805: " "Cannot find requester physical port\n"); goto Exit; } if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) { OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Requester port GUID 0x%" PRIx64 "\n", cl_ntoh64(osm_physp_get_port_guid(p_req_physp))); osm_dump_link_record_v2(sa->p_log, p_lr, FILE_ID, OSM_LOG_DEBUG); } cl_qlist_init(&lr_list); /* Most SA functions (including this one) are read-only on the subnet object, so we grab the lock non-exclusively. */ cl_plock_acquire(sa->p_lock); status = lr_rcv_get_end_points(sa, p_madw, &p_src_port, &p_dest_port); if (status == IB_SA_MAD_STATUS_SUCCESS) lr_rcv_get_port_links(sa, p_lr, p_src_port, p_dest_port, p_sa_mad->comp_mask, &lr_list, p_req_physp); cl_plock_release(sa->p_lock); osm_sa_respond(sa, p_madw, sizeof(ib_link_record_t), &lr_list); Exit: OSM_LOG_EXIT(sa->p_log); }