static void __osm_vendor_internal_unbind(osm_bind_handle_t h_bind) { osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; osm_log_t *p_log = p_bo->p_vendor->p_log; OSM_LOG_ENTER(p_log); /* "notifying" all that from now on no new sends can be done */ p_bo->txn_mgr.p_event_wheel->closing = TRUE; osmv_txn_lock(p_bo); /* the is_closing is set under lock we we know we only need to check for it after obtaining the lock */ p_bo->is_closing = TRUE; /* notifying all sleeping rmpp sends to exit */ osmv_txn_abort_rmpp_txns(h_bind); /* unlock the bo to allow for any residual mads to be dispatched */ osmv_txn_unlock(p_bo); osm_log(p_log, OSM_LOG_DEBUG, "__osm_vendor_internal_unbind: destroying transport mgr.. \n"); /* wait for the receiver thread to exit */ osmv_transport_done(h_bind); /* lock to avoid any collissions while we cleanup the structs */ osmv_txn_lock(p_bo); osm_log(p_log, OSM_LOG_DEBUG, "__osm_vendor_internal_unbind: destroying txn mgr.. \n"); osmv_txnmgr_done(h_bind); osm_log(p_log, OSM_LOG_DEBUG, "__osm_vendor_internal_unbind: destroying bind lock.. \n"); osmv_txn_unlock(p_bo); /* we intentionally let the p_bo and its lock leak - as we did not implement a way to track active bind handles provided to the client - and the client might use them cl_spinlock_destroy(&p_bo->lock); free(p_bo); */ OSM_LOG_EXIT(p_log); }
ib_api_status_t osmv_rmpp_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_rmpp_ds) { ib_api_status_t ret = IB_SUCCESS; uint32_t i, total_segs; osmv_rmpp_send_ctx_t *p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn); osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; OSM_LOG_ENTER(p_bo->p_vendor->p_log); total_segs = osmv_rmpp_send_ctx_get_num_segs(p_send_ctx); CL_ASSERT(total_segs >= 1); /* In the double-sided transfer, wait for ACK 0 */ for (;;) { if (p_send_ctx->window_first > total_segs) { /* Every segment is acknowledged */ break; } /* Send the next burst. */ for (i = p_send_ctx->window_first; i <= p_send_ctx->window_last; i++) { /* Send a segment and setup a timeout timer */ ret = __osmv_rmpp_send_segment(h_bind, p_txn, i); if (IB_SUCCESS != ret) { goto send_done; } } /* Set the Response Timeout for the ACK on the last DATA segment */ ret = osmv_txn_set_timeout_ev(h_bind, osmv_txn_get_key(p_txn), p_bo->p_vendor->resp_timeout); if (IB_SUCCESS != ret) { goto send_done; } /* Going to sleep. Let the others access the transaction DB */ osmv_txn_unlock(p_bo); osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "RMPP Sender thread (madw=%p) going to sleep ...\n", p_madw); /* Await the next event to happen */ cl_event_wait_on(&p_send_ctx->event, EVENT_NO_TIMEOUT, TRUE /* interruptible */ ); /* Got a signal from the MAD dispatcher/timeout handler */ osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "RMPP Sender thread (madw=%p) waking up on a signal ...\n", p_madw); /* Let's see what changed... Make this atomic - re-acquire the lock. */ osmv_txn_lock(p_bo); if (TRUE == p_bo->is_closing) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, "osmv_rmpp_send_madw: ERR 6601: " "The bind handle %p is being closed. " "Stopping the RMPP Send of MADW %p\n", h_bind, p_madw); ret = IB_TIMEOUT; return IB_INTERRUPTED; } /* STOP? ABORT? TIMEOUT? */ if (IB_SUCCESS != p_send_ctx->status) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, "osmv_rmpp_send_madw: ERR 6602: " "An error (%s) happened during the RMPP send of %p. Bailing out.\n", ib_get_err_str(p_send_ctx->status), p_madw); ret = p_send_ctx->status; goto send_done; } } if (TRUE == is_rmpp_ds) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "Double-sided RMPP - switching to be the receiver.\n"); ret = osmv_txn_init_rmpp_receiver(h_bind, p_txn, FALSE /*Send was initiated by me */ ); if (IB_SUCCESS == ret) { /* Send ACK on the 0 segment */ ret = __osmv_rmpp_send_segment(h_bind, p_txn, 0); } } send_done: OSM_LOG_EXIT(p_bo->p_vendor->p_log); return ret; }
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; }
ib_api_status_t osmv_dispatch_mad(IN osm_bind_handle_t h_bind, IN const void *p_mad_buf, IN const osm_mad_addr_t * p_mad_addr) { ib_api_status_t ret = IB_SUCCESS; const ib_mad_t *p_mad = (ib_mad_t *) p_mad_buf; osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; osmv_txn_ctx_t *p_txn = NULL; osm_log_t *p_log = p_bo->p_vendor->p_log; OSM_LOG_ENTER(p_bo->p_vendor->p_log); CL_ASSERT(NULL != h_bind && NULL != p_mad && NULL != p_mad_addr); osmv_txn_lock(p_bo); if (TRUE == p_bo->is_closing) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "The bind handle %p is being closed. " "The MAD will not be dispatched.\n", p_bo); ret = IB_INTERRUPTED; goto dispatch_mad_done; } /* 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 dispatched.\n"); goto dispatch_mad_done; } } switch (__osmv_dispatch_route(h_bind, p_mad, &p_txn)) { case OSMV_ROUTE_DROP: break; /* Do nothing */ case OSMV_ROUTE_SIMPLE: __osmv_dispatch_simple_mad(h_bind, p_mad, p_txn, p_mad_addr); break; case OSMV_ROUTE_RMPP: __osmv_dispatch_rmpp_mad(h_bind, p_mad, p_txn, p_mad_addr); break; default: CL_ASSERT(FALSE); } dispatch_mad_done: osmv_txn_unlock(p_bo); OSM_LOG_EXIT(p_log); return ret; }