ib_api_status_t osmv_txn_init_rmpp_sender(IN osm_bind_handle_t h_bind, IN osmv_txn_ctx_t * p_txn, IN osm_madw_t * p_madw) { ib_api_status_t st; CL_ASSERT(p_txn); /* Double-Sided RMPP Direction Switch */ osmv_txn_remove_timeout_ev(h_bind, osmv_txn_get_key(p_txn)); p_txn->rmpp_txfr.rmpp_state = OSMV_TXN_RMPP_SENDER; p_txn->rmpp_txfr.p_rmpp_send_ctx = malloc(sizeof(osmv_rmpp_send_ctx_t)); if (!p_txn->rmpp_txfr.p_rmpp_send_ctx) { return IB_INSUFFICIENT_MEMORY; } memset(p_txn->rmpp_txfr.p_rmpp_send_ctx, 0, sizeof(osmv_rmpp_send_ctx_t)); st = osmv_rmpp_send_ctx_init(p_txn->rmpp_txfr.p_rmpp_send_ctx, (void *)p_madw->p_mad, p_madw->mad_size, p_txn->p_log); return st; }
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; }
static void __osmv_dispatch_simple_mad(IN osm_bind_handle_t h_bind, IN const ib_mad_t * p_mad, IN osmv_txn_ctx_t * p_txn, IN const osm_mad_addr_t * p_mad_addr) { osm_madw_t *p_madw; ib_mad_t *p_mad_buf; osm_madw_t *p_req_madw = NULL; osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; OSM_LOG_ENTER(p_bo->p_vendor->p_log); /* Build the MAD wrapper to be returned to the user. * The actual storage for the MAD is allocated there. */ p_madw = osm_mad_pool_get(p_bo->p_osm_pool, h_bind, MAD_BLOCK_SIZE, p_mad_addr); if (NULL == p_madw) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, "__osmv_dispatch_simple_mad: ERR 6501: " "Out Of Memory - could not allocate a buffer of size %d\n", MAD_BLOCK_SIZE); goto dispatch_simple_mad_done; } p_mad_buf = osm_madw_get_mad_ptr(p_madw); /* Copy the payload to the MAD buffer */ memcpy((void *)p_mad_buf, (void *)p_mad, MAD_BLOCK_SIZE); if (NULL != p_txn) { /* This is a RESPONSE MAD. Pair it with the REQUEST MAD, pass upstream */ p_req_madw = p_txn->p_madw; CL_ASSERT(NULL != p_req_madw); p_mad_buf->trans_id = cl_hton64(osmv_txn_get_tid(p_txn)); osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "Restoring the original TID to 0x%" PRIx64 "\n", cl_ntoh64(p_mad_buf->trans_id)); /* Reply matched, transaction complete */ osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), FALSE); } else { /* This is a REQUEST MAD. Don't create a context, pass upstream */ } /* Do the job ! */ p_bo->recv_cb(p_madw, p_bo->cb_context, p_req_madw); dispatch_simple_mad_done: OSM_LOG_EXIT(p_bo->p_vendor->p_log); }
ib_api_status_t osmv_txn_init_rmpp_receiver(IN osm_bind_handle_t h_bind, IN osmv_txn_ctx_t * p_txn, IN boolean_t is_init_by_peer) { ib_api_status_t st; osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; uint64_t key = osmv_txn_get_key(p_txn); CL_ASSERT(p_txn); /* Double-Sided RMPP Direction Switch */ osmv_txn_remove_timeout_ev(h_bind, key); /* Set the Transaction Timeout value */ st = osmv_txn_set_timeout_ev(h_bind, key, p_bo->p_vendor->ttime_timeout); if (IB_SUCCESS != st) { return st; } p_txn->rmpp_txfr.rmpp_state = OSMV_TXN_RMPP_RECEIVER; p_txn->rmpp_txfr.is_rmpp_init_by_peer = is_init_by_peer; p_txn->rmpp_txfr.p_rmpp_recv_ctx = malloc(sizeof(osmv_rmpp_recv_ctx_t)); if (!p_txn->rmpp_txfr.p_rmpp_recv_ctx) { osmv_txn_remove_timeout_ev(h_bind, key); return IB_INSUFFICIENT_MEMORY; } memset(p_txn->rmpp_txfr.p_rmpp_recv_ctx, 0, sizeof(osmv_rmpp_recv_ctx_t)); st = osmv_rmpp_recv_ctx_init(p_txn->rmpp_txfr.p_rmpp_recv_ctx, p_txn->p_log); return st; }
void __osmv_txn_all_done(osm_bind_handle_t h_bind) { osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; cl_map_item_t *p_item; cl_map_obj_t *p_obj; osmv_txn_ctx_t *p_txn; OSM_LOG_ENTER(p_bo->p_vendor->p_log); p_item = cl_qmap_head(p_bo->txn_mgr.p_txn_map); while (p_item != cl_qmap_end(p_bo->txn_mgr.p_txn_map)) { p_obj = PARENT_STRUCT(p_item, cl_map_obj_t, item); p_txn = (osmv_txn_ctx_t *) cl_qmap_obj(p_obj); osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), FALSE); free(p_obj); /* assuming osmv_txn_done has removed the txn from the map */ p_item = cl_qmap_head(p_bo->txn_mgr.p_txn_map); } OSM_LOG_EXIT(p_bo->p_vendor->p_log); }
ib_api_status_t __osmv_txnmgr_insert_txn(IN osmv_txn_mgr_t * p_tx_mgr, IN osmv_txn_ctx_t * p_txn, IN uint64_t key) { cl_map_obj_t *p_obj = NULL; cl_map_item_t *p_item; uint64_t tmp_key; CL_ASSERT(p_tx_mgr); CL_ASSERT(p_txn); key = osmv_txn_get_key(p_txn); p_obj = malloc(sizeof(cl_map_obj_t)); if (NULL == p_obj) return IB_INSUFFICIENT_MEMORY; osm_log(p_tx_mgr->p_log, OSM_LOG_DEBUG, "__osmv_txnmgr_insert_txn: " "Inserting key: 0x%llX to map ptr:%p\n", key, p_tx_mgr->p_txn_map); memset(p_obj, 0, sizeof(cl_map_obj_t)); cl_qmap_set_obj(p_obj, p_txn); /* assuming lookup with this key was made and the result was IB_NOT_FOUND */ cl_qmap_insert(p_tx_mgr->p_txn_map, key, &p_obj->item); p_item = cl_qmap_head(p_tx_mgr->p_txn_map); while (p_item != cl_qmap_end(p_tx_mgr->p_txn_map)) { tmp_key = cl_qmap_key(p_item); osm_log(p_tx_mgr->p_log, OSM_LOG_DEBUG, "__osmv_txnmgr_insert_txn: " "Found key 0x%llX \n", tmp_key); p_item = cl_qmap_next(p_item); } return IB_SUCCESS; }
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; }
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; }
static ib_api_status_t __osmv_dispatch_rmpp_rcv(IN osm_bind_handle_t h_bind, IN const ib_mad_t * p_mad, IN osmv_txn_ctx_t * p_txn, IN const osm_mad_addr_t * p_mad_addr) { ib_api_status_t status = IB_SUCCESS; osmv_rmpp_recv_ctx_t *p_recv_ctx = osmv_txn_get_rmpp_recv_ctx(p_txn); osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; boolean_t is_last1 = FALSE, is_last2 = FALSE; osm_madw_t *p_new_madw = NULL, *p_req_madw = NULL; ib_mad_t *p_mad_buf; uint32_t size = 0; uint64_t key = osmv_txn_get_key(p_txn); uint64_t tid = osmv_txn_get_tid(p_txn); OSM_LOG_ENTER(p_bo->p_vendor->p_log); if (TRUE == osmv_rmpp_is_ack(p_mad)) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "Not supposed to receive ACK's --> dropping the MAD\n"); goto dispatch_rmpp_rcv_done; } if (TRUE == osmv_rmpp_is_abort_stop(p_mad)) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "__osmv_dispatch_rmpp_rcv: ERR 6504: " "The Remote Side stopped sending\n"); status = IB_REMOTE_ERROR; goto dispatch_rmpp_rcv_done; } status = __osmv_dispatch_accept_seg(h_bind, p_txn, p_mad); switch (status) { case IB_SUCCESS: /* Check wheter this is the legal last MAD */ /* Criteria #1: the received MAD is marked last */ is_last1 = osmv_rmpp_is_last(p_mad); /* Criteria #2: the total accumulated length hits the advertised one */ is_last2 = is_last1; size = osmv_rmpp_recv_ctx_get_byte_num_from_first(p_recv_ctx); if (size > 0) { is_last2 = (osmv_rmpp_recv_ctx_get_cur_byte_num(p_recv_ctx) >= size); } if (is_last1 != is_last2) { osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr, IB_RMPP_TYPE_ABORT, IB_RMPP_STATUS_BAD_LEN); status = IB_ERROR; goto dispatch_rmpp_rcv_done; } /* TBD Consider an optimization - sending an ACK * only for the last segment in the window */ __osmv_dispatch_send_ack(h_bind, p_mad, p_txn, p_mad_addr); break; case IB_INSUFFICIENT_RESOURCES: /* An out-of-order segment received. Send the ACK anyway */ __osmv_dispatch_send_ack(h_bind, p_mad, p_txn, p_mad_addr); status = IB_SUCCESS; goto dispatch_rmpp_rcv_done; case IB_INSUFFICIENT_MEMORY: osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr, IB_RMPP_TYPE_STOP, IB_RMPP_STATUS_RESX); goto dispatch_rmpp_rcv_done; default: /* Illegal return code */ CL_ASSERT(FALSE); } if (TRUE != is_last1) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "RMPP MADW assembly continues, TID=0x%" PRIx64 "\n", tid); goto dispatch_rmpp_rcv_done; } /* This is the last packet. */ if (0 == size) { /* The total size was not advertised in the first packet */ size = osmv_rmpp_recv_ctx_get_byte_num_from_last(p_recv_ctx); } /* NOTE: the received mad might not be >= 256 bytes. some MADs might contain several SA records but still be less then a full MAD. We have to use RMPP to send them over since on a regular "simple" MAD there is no way to know how many records were sent */ /* Build the MAD wrapper to be returned to the user. * The actual storage for the MAD is allocated there. */ p_new_madw = osm_mad_pool_get(p_bo->p_osm_pool, h_bind, size, p_mad_addr); if (NULL == p_new_madw) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, "__osmv_dispatch_rmpp_rcv: ERR 6506: " "Out Of Memory - could not allocate %d bytes for the MADW\n", size); status = IB_INSUFFICIENT_MEMORY; goto dispatch_rmpp_rcv_done; } p_req_madw = osmv_txn_get_madw(p_txn); p_mad_buf = osm_madw_get_mad_ptr(p_new_madw); status = osmv_rmpp_recv_ctx_reassemble_arbt_mad(p_recv_ctx, size, (uint8_t *) p_mad_buf); if (IB_SUCCESS != status) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, "__osmv_dispatch_rmpp_rcv: ERR 6507: " "Internal error - could not reassemble the result MAD\n"); goto dispatch_rmpp_rcv_done; /* What can happen here? */ } /* The MAD is assembled, we are about to apply the callback. * Delete the transaction context, unless the transaction is double sided */ if (FALSE == osmv_txn_is_rmpp_init_by_peer(p_txn) || FALSE == osmv_mad_is_multi_resp(p_mad)) { osmv_txn_done(h_bind, key, FALSE); } osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "RMPP MADW %p assembly complete, TID=0x%" PRIx64 "\n", p_new_madw, tid); p_mad_buf->trans_id = cl_hton64(tid); osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "Restoring the original TID to 0x%" PRIx64 "\n", cl_ntoh64(p_mad_buf->trans_id)); /* Finally, do the job! */ p_bo->recv_cb(p_new_madw, p_bo->cb_context, p_req_madw); dispatch_rmpp_rcv_done: OSM_LOG_EXIT(p_bo->p_vendor->p_log); return status; }
static void __osmv_dispatch_rmpp_snd(IN osm_bind_handle_t h_bind, IN const ib_mad_t * p_mad, IN osmv_txn_ctx_t * p_txn, IN const osm_mad_addr_t * p_mad_addr) { osmv_rmpp_send_ctx_t *p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn); uint32_t old_wl = p_send_ctx->window_last; uint32_t total_segs = osmv_rmpp_send_ctx_get_num_segs(p_send_ctx); uint32_t seg_num = cl_ntoh32(((ib_rmpp_mad_t *) p_mad)->seg_num); uint32_t new_wl = cl_ntoh32(((ib_rmpp_mad_t *) p_mad)->paylen_newwin); osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; OSM_LOG_ENTER(p_bo->p_vendor->p_log); if (TRUE == osmv_rmpp_is_abort_stop(p_mad)) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, "__osmv_dispatch_rmpp_snd: ERR 6502: " "The remote side sent an ABORT/STOP indication.\n"); osmv_rmpp_snd_error(p_send_ctx, IB_REMOTE_ERROR); goto dispatch_rmpp_snd_done; } if (FALSE == osmv_rmpp_is_ack(p_mad)) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "Not supposed to receive DATA packets --> dropping the MAD\n"); goto dispatch_rmpp_snd_done; } /* Continue processing the ACK */ if (seg_num > old_wl) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, "__osmv_dispatch_rmpp_snd: ERR 6503: " "ACK received for a non-sent segment %d\n", seg_num); osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr, IB_RMPP_TYPE_ABORT, IB_RMPP_STATUS_S2B); osmv_rmpp_snd_error(p_send_ctx, IB_REMOTE_ERROR); goto dispatch_rmpp_snd_done; } osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "__osmv_dispatch_rmpp_snd: " "New WL = %u Old WL = %u Total Segs = %u\n", new_wl, old_wl, total_segs); if (new_wl < old_wl) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, "__osmv_dispatch_rmpp_snd: ERR 6508: " "The receiver requests a smaller WL (%d) than before (%d)\n", new_wl, old_wl); osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr, IB_RMPP_TYPE_ABORT, IB_RMPP_STATUS_W2S); osmv_rmpp_snd_error(p_send_ctx, IB_REMOTE_ERROR); goto dispatch_rmpp_snd_done; } /* Update the sender's window, and optionally wake up the sender thread * Note! A single ACK can acknowledge a whole range of segments: [WF..SEG_NUM] */ osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "ACK for seg_num #%d accepted.\n", seg_num); if (seg_num == old_wl) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "The send window [%d:%d] is totally acknowledged.\n", p_send_ctx->window_first, old_wl); p_send_ctx->window_first = seg_num + 1; p_send_ctx->window_last = (new_wl < total_segs) ? new_wl : total_segs; /* Remove the response timeout event for the window */ osmv_txn_remove_timeout_ev(h_bind, osmv_txn_get_key(p_txn)); /* Wake up the sending thread */ cl_event_signal(&p_send_ctx->event); } dispatch_rmpp_snd_done: OSM_LOG_EXIT(p_bo->p_vendor->p_log); }
static void __osmv_dispatch_rmpp_mad(IN osm_bind_handle_t h_bind, IN const ib_mad_t * p_mad, IN osmv_txn_ctx_t * p_txn, IN const osm_mad_addr_t * p_mad_addr) { ib_api_status_t status = IB_SUCCESS; uint64_t key = cl_ntoh64(p_mad->trans_id); boolean_t is_init_by_peer = FALSE; osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; osm_madw_t *p_madw; OSM_LOG_ENTER(p_bo->p_vendor->p_log); if (NULL == p_txn) { if (FALSE == osmv_rmpp_is_data(p_mad) || FALSE == osmv_rmpp_is_first(p_mad)) { osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "The MAD does not match any transaction " "and does not start a sender-initiated RMPP transfer.\n"); goto dispatch_rmpp_mad_done; } /* IB Spec 13.6.2.2. This is a Sender Initiated Transfer. My peer is the requester and RMPP Sender. I am the RMPP Receiver. */ status = osmv_txn_init(h_bind, /*tid==key */ key, key, &p_txn); if (IB_SUCCESS != status) { goto dispatch_rmpp_mad_done; } is_init_by_peer = TRUE; osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, "A new sender-initiated transfer (TID=0x%" PRIx64 ") started\n", key); } if (OSMV_TXN_RMPP_NONE == osmv_txn_get_rmpp_state(p_txn)) { /* Case 1: Fall through from above. * Case 2: When the transaction was initiated by me * (a single request MAD), there was an uncertainty * whether the reply will be RMPP. Now it's resolved, * since the reply is RMPP! */ status = osmv_txn_init_rmpp_receiver(h_bind, p_txn, is_init_by_peer); if (IB_SUCCESS != status) { goto dispatch_rmpp_mad_done; } } switch (osmv_txn_get_rmpp_state(p_txn)) { case OSMV_TXN_RMPP_RECEIVER: status = __osmv_dispatch_rmpp_rcv(h_bind, p_mad, p_txn, p_mad_addr); if (IB_SUCCESS != status) { if (FALSE == osmv_txn_is_rmpp_init_by_peer(p_txn)) { /* This is a requester, still waiting for the reply. Apply the callback */ /* update the status of the p_madw */ p_madw = osmv_txn_get_madw(p_txn); p_madw->status = status; p_bo->send_err_cb(p_bo->cb_context, p_madw); } /* ABORT/STOP/LOCAL ERROR */ osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), FALSE); } break; case OSMV_TXN_RMPP_SENDER: __osmv_dispatch_rmpp_snd(h_bind, p_mad, p_txn, p_mad_addr); /* If an error happens here, it's the sender thread to cleanup the txn */ break; default: CL_ASSERT(FALSE); } dispatch_rmpp_mad_done: OSM_LOG_EXIT(p_bo->p_vendor->p_log); }