static osmv_disp_route_t __osmv_dispatch_route(IN osm_bind_handle_t h_bind, IN const ib_mad_t * p_mad, OUT osmv_txn_ctx_t ** pp_txn) { ib_api_status_t ret; osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; boolean_t is_resp = ib_mad_is_response(p_mad); boolean_t is_txn; uint64_t key = cl_ntoh64(p_mad->trans_id); CL_ASSERT(NULL != pp_txn); ret = osmv_txn_lookup(h_bind, key, pp_txn); is_txn = (IB_SUCCESS == ret); if (FALSE == is_txn && TRUE == is_resp) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "Received a response to a non-started/aged-out transaction (tid=0x%" PRIx64 "). " "Dropping the MAD.\n", key); return OSMV_ROUTE_DROP; } if (TRUE == osmv_mad_is_rmpp(p_mad)) { /* An RMPP transaction. The filtering is more delicate there */ return OSMV_ROUTE_RMPP; } if (TRUE == is_txn && FALSE == is_resp) { /* Does this MAD try to start a transaction with duplicate tid? */ osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "Duplicate TID 0x%" PRIx64 " received (not a response). " "Dropping the MAD.\n", key); return OSMV_ROUTE_DROP; } return OSMV_ROUTE_SIMPLE; }
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; }
static ib_api_status_t __osmv_get_send_txn(IN osm_bind_handle_t h_bind, IN osm_madw_t * const p_madw, IN boolean_t is_rmpp, IN boolean_t resp_expected, OUT osmv_txn_ctx_t ** pp_txn) { ib_api_status_t ret; uint64_t tid, key; osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; ib_mad_t *p_mad = osm_madw_get_mad_ptr(p_madw); OSM_LOG_ENTER(p_bo->p_vendor->p_log); CL_ASSERT(NULL != pp_txn); key = tid = cl_ntoh64(p_mad->trans_id); if (TRUE == resp_expected) { /* Create a unique identifier at the requester side */ key = osmv_txn_uniq_key(tid); } /* We must run under a transaction framework */ ret = osmv_txn_lookup(h_bind, key, pp_txn); if (IB_NOT_FOUND == ret) { /* Generally, we start a new transaction */ ret = osmv_txn_init(h_bind, tid, key, pp_txn); if (IB_SUCCESS != ret) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, "__osmv_get_send_txn: ERR 7313: " "The transaction id=0x%" PRIx64 " failed to init.\n", tid); goto get_send_txn_done; } } else { CL_ASSERT(NULL != *pp_txn); /* The transaction context exists. * This is legal only if I am going to return an * (RMPP?) reply to an RMPP request sent by the other part * (double-sided RMPP transfer) */ if (FALSE == is_rmpp || FALSE == osmv_txn_is_rmpp_init_by_peer(*pp_txn)) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, "__osmv_get_send_txn: ERR 7314: " "The transaction id=0x%" PRIx64 " is not unique. Send failed.\n", tid); ret = IB_INVALID_SETTING; goto get_send_txn_done; } if (TRUE == resp_expected) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, "__osmv_get_send_txn: ERR 7315: " "The transaction id=0x%" PRIx64 " can't expect a response. Send failed.\n", tid); ret = IB_INVALID_PARAMETER; goto get_send_txn_done; } } if (TRUE == is_rmpp) { ret = osmv_txn_init_rmpp_sender(h_bind, *pp_txn, p_madw); if (IB_SUCCESS != ret) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, "__osmv_get_send_txn: ERR 7316: " "The transaction id=0x%" PRIx64 " failed to init the rmpp mad. Send failed.\n", tid); osmv_txn_done(h_bind, tid, FALSE); goto get_send_txn_done; } } /* Save a reference to the MAD in the txn context * We'll need to match it in two cases: * (1) When the response is returned, if I am the requester * (2) In RMPP retransmissions */ osmv_txn_set_madw(*pp_txn, p_madw); get_send_txn_done: OSM_LOG_EXIT(p_bo->p_vendor->p_log); return ret; }