2 * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
6 * This software is available to you under a choice of one of two
7 * licenses. You may choose to be licensed under the terms of the GNU
8 * General Public License (GPL) Version 2, available from the file
9 * COPYING in the main directory of this source tree, or the
10 * OpenIB.org BSD license below:
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
20 * - Redistributions in binary form must reproduce the above
21 * copyright notice, this list of conditions and the following
22 * disclaimer in the documentation and/or other materials
23 * provided with the distribution.
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38 #endif /* HAVE_CONFIG_H */
41 #include <vendor/osm_vendor_mlx.h>
42 #include <vendor/osm_vendor_mlx_defs.h>
43 #include <vendor/osm_vendor_mlx_svc.h>
44 #include <vendor/osm_vendor_mlx_transport.h>
45 #include <vendor/osm_vendor_mlx_sender.h>
46 #include <vendor/osm_pkt_randomizer.h>
48 typedef enum _osmv_disp_route {
57 * FORWARD REFERENCES TO PRIVATE FUNCTIONS
60 static osmv_disp_route_t
61 __osmv_dispatch_route(IN osm_bind_handle_t h_bind,
62 IN const ib_mad_t * p_mad, OUT osmv_txn_ctx_t ** pp_txn);
65 __osmv_dispatch_simple_mad(IN osm_bind_handle_t h_bind,
66 IN const ib_mad_t * p_mad,
67 IN osmv_txn_ctx_t * p_txn,
68 IN const osm_mad_addr_t * p_mad_addr);
71 __osmv_dispatch_rmpp_mad(IN osm_bind_handle_t h_bind,
72 IN const ib_mad_t * p_mad,
73 IN osmv_txn_ctx_t * p_txn,
74 IN const osm_mad_addr_t * p_mad_addr);
77 __osmv_dispatch_rmpp_snd(IN osm_bind_handle_t h_bind,
78 IN const ib_mad_t * p_mad,
79 IN osmv_txn_ctx_t * p_txn,
80 IN const osm_mad_addr_t * p_mad_addr);
82 static ib_api_status_t
83 __osmv_dispatch_rmpp_rcv(IN osm_bind_handle_t h_bind,
84 IN const ib_mad_t * p_mad,
85 IN osmv_txn_ctx_t * p_txn,
86 IN const osm_mad_addr_t * p_mad_addr);
88 static ib_api_status_t
89 __osmv_dispatch_accept_seg(IN osm_bind_handle_t h_bind,
90 IN osmv_txn_ctx_t * p_txn,
91 IN const ib_mad_t * p_mad);
93 __osmv_dispatch_send_ack(IN osm_bind_handle_t h_bind,
94 IN const ib_mad_t * p_req_mad,
95 IN osmv_txn_ctx_t * p_txn,
96 IN const osm_mad_addr_t * p_mad_addr);
103 * Lower-level MAD dispatcher.
104 * Implements a switch between the following MAD consumers:
105 * (1) Non-RMPP consumer (DATA)
106 * (2) RMPP receiver (DATA/ABORT/STOP)
107 * (3) RMPP sender (ACK/ABORT/STOP)
110 * h_bind The bind handle
111 * p_mad_buf The 256 byte buffer of individual MAD
112 * p_mad_addr The MAD originator's address
116 osmv_dispatch_mad(IN osm_bind_handle_t h_bind,
117 IN const void *p_mad_buf,
118 IN const osm_mad_addr_t * p_mad_addr)
120 ib_api_status_t ret = IB_SUCCESS;
121 const ib_mad_t *p_mad = (ib_mad_t *) p_mad_buf;
122 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
123 osmv_txn_ctx_t *p_txn = NULL;
124 osm_log_t *p_log = p_bo->p_vendor->p_log;
126 OSM_LOG_ENTER(p_bo->p_vendor->p_log);
128 CL_ASSERT(NULL != h_bind && NULL != p_mad && NULL != p_mad_addr);
132 if (TRUE == p_bo->is_closing) {
134 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
135 "The bind handle %p is being closed. "
136 "The MAD will not be dispatched.\n", p_bo);
138 ret = IB_INTERRUPTED;
139 goto dispatch_mad_done;
143 Add call for packet drop randomizer.
144 This is a testing feature. If run_randomizer flag is set to TRUE,
145 the randomizer will be called, and randomally will drop
146 a packet. This is used for simulating unstable fabric.
148 if (p_bo->p_vendor->run_randomizer == TRUE) {
149 /* Try the randomizer */
150 if (osm_pkt_randomizer_mad_drop(p_bo->p_vendor->p_log,
154 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
155 "The MAD will not be dispatched.\n");
156 goto dispatch_mad_done;
160 switch (__osmv_dispatch_route(h_bind, p_mad, &p_txn)) {
162 case OSMV_ROUTE_DROP:
163 break; /* Do nothing */
165 case OSMV_ROUTE_SIMPLE:
166 __osmv_dispatch_simple_mad(h_bind, p_mad, p_txn, p_mad_addr);
169 case OSMV_ROUTE_RMPP:
170 __osmv_dispatch_rmpp_mad(h_bind, p_mad, p_txn, p_mad_addr);
178 osmv_txn_unlock(p_bo);
185 * NAME __osmv_dispatch_route()
187 * DESCRIPTION Decide which way to handle the received MAD: simple txn/RMPP/drop
190 static osmv_disp_route_t
191 __osmv_dispatch_route(IN osm_bind_handle_t h_bind,
192 IN const ib_mad_t * p_mad, OUT osmv_txn_ctx_t ** pp_txn)
195 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
196 boolean_t is_resp = osmv_mad_is_response(p_mad);
198 uint64_t key = cl_ntoh64(p_mad->trans_id);
200 CL_ASSERT(NULL != pp_txn);
202 ret = osmv_txn_lookup(h_bind, key, pp_txn);
203 is_txn = (IB_SUCCESS == ret);
205 if (FALSE == is_txn && TRUE == is_resp) {
206 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
207 "Received a response to a non-started/aged-out transaction (tid=0x%llX). "
208 "Dropping the MAD.\n", key);
209 return OSMV_ROUTE_DROP;
212 if (TRUE == osmv_mad_is_rmpp(p_mad)) {
213 /* An RMPP transaction. The filtering is more delicate there */
214 return OSMV_ROUTE_RMPP;
217 if (TRUE == is_txn && FALSE == is_resp) {
218 /* Does this MAD try to start a transaction with duplicate tid? */
219 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
220 "Duplicate TID 0x%llX received (not a response). "
221 "Dropping the MAD.\n", key);
223 return OSMV_ROUTE_DROP;
226 return OSMV_ROUTE_SIMPLE;
230 * NAME __osmv_dispatch_simple_mad()
232 * DESCRIPTION Handle a MAD that is part of non-RMPP transfer
236 __osmv_dispatch_simple_mad(IN osm_bind_handle_t h_bind,
237 IN const ib_mad_t * p_mad,
238 IN osmv_txn_ctx_t * p_txn,
239 IN const osm_mad_addr_t * p_mad_addr)
243 osm_madw_t *p_req_madw = NULL;
244 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
246 OSM_LOG_ENTER(p_bo->p_vendor->p_log);
248 /* Build the MAD wrapper to be returned to the user.
249 * The actual storage for the MAD is allocated there.
252 osm_mad_pool_get(p_bo->p_osm_pool, h_bind, MAD_BLOCK_SIZE,
255 if (NULL == p_madw) {
256 osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
257 "__osmv_dispatch_simple_mad: ERR 6501: "
258 "Out Of Memory - could not allocate a buffer of size %d\n",
261 goto dispatch_simple_mad_done;
264 p_mad_buf = osm_madw_get_mad_ptr(p_madw);
265 /* Copy the payload to the MAD buffer */
266 memcpy((void *)p_mad_buf, (void *)p_mad, MAD_BLOCK_SIZE);
269 /* This is a RESPONSE MAD. Pair it with the REQUEST MAD, pass upstream */
270 p_req_madw = p_txn->p_madw;
271 CL_ASSERT(NULL != p_req_madw);
273 p_mad_buf->trans_id = cl_hton64(osmv_txn_get_tid(p_txn));
274 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
275 "Restoring the original TID to 0x%llX\n",
276 cl_ntoh64(p_mad_buf->trans_id));
278 /* Reply matched, transaction complete */
279 osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), FALSE);
281 /* This is a REQUEST MAD. Don't create a context, pass upstream */
285 p_bo->recv_cb(p_madw, p_bo->cb_context, p_req_madw);
287 dispatch_simple_mad_done:
288 OSM_LOG_EXIT(p_bo->p_vendor->p_log);
292 * NAME __osmv_dispatch_rmpp_mad()
294 * DESCRIPTION Handle a MAD that is part of RMPP transfer
298 __osmv_dispatch_rmpp_mad(IN osm_bind_handle_t h_bind,
299 IN const ib_mad_t * p_mad,
300 IN osmv_txn_ctx_t * p_txn,
301 IN const osm_mad_addr_t * p_mad_addr)
303 ib_api_status_t status = IB_SUCCESS;
304 uint64_t key = cl_ntoh64(p_mad->trans_id);
305 boolean_t is_init_by_peer = FALSE;
306 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
309 OSM_LOG_ENTER(p_bo->p_vendor->p_log);
312 if (FALSE == osmv_rmpp_is_data(p_mad)
313 || FALSE == osmv_rmpp_is_first(p_mad)) {
314 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
315 "The MAD does not match any transaction "
316 "and does not start a sender-initiated RMPP transfer.\n");
317 goto dispatch_rmpp_mad_done;
320 /* IB Spec 13.6.2.2. This is a Sender Initiated Transfer.
321 My peer is the requester and RMPP Sender. I am the RMPP Receiver.
323 status = osmv_txn_init(h_bind, /*tid==key */ key, key, &p_txn);
324 if (IB_SUCCESS != status) {
325 goto dispatch_rmpp_mad_done;
328 is_init_by_peer = TRUE;
329 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
330 "A new sender-initiated transfer (TID=0x%llX) started\n",
334 if (OSMV_TXN_RMPP_NONE == osmv_txn_get_rmpp_state(p_txn)) {
335 /* Case 1: Fall through from above.
336 * Case 2: When the transaction was initiated by me
337 * (a single request MAD), there was an uncertainty
338 * whether the reply will be RMPP. Now it's resolved,
339 * since the reply is RMPP!
342 osmv_txn_init_rmpp_receiver(h_bind, p_txn, is_init_by_peer);
343 if (IB_SUCCESS != status) {
344 goto dispatch_rmpp_mad_done;
348 switch (osmv_txn_get_rmpp_state(p_txn)) {
350 case OSMV_TXN_RMPP_RECEIVER:
352 __osmv_dispatch_rmpp_rcv(h_bind, p_mad, p_txn, p_mad_addr);
353 if (IB_SUCCESS != status) {
354 if (FALSE == osmv_txn_is_rmpp_init_by_peer(p_txn)) {
355 /* This is a requester, still waiting for the reply. Apply the callback */
356 /* update the status of the p_madw */
357 p_madw = osmv_txn_get_madw(p_txn);
358 p_madw->status = status;
359 p_bo->send_err_cb(p_bo->cb_context, p_madw);
362 /* ABORT/STOP/LOCAL ERROR */
363 osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), FALSE);
367 case OSMV_TXN_RMPP_SENDER:
368 __osmv_dispatch_rmpp_snd(h_bind, p_mad, p_txn, p_mad_addr);
369 /* If an error happens here, it's the sender thread to cleanup the txn */
376 dispatch_rmpp_mad_done:
377 OSM_LOG_EXIT(p_bo->p_vendor->p_log);
381 * NAME __osmv_dispatch_rmpp_snd()
383 * DESCRIPTION MAD handling by an RMPP sender (ACK/ABORT/STOP)
387 __osmv_dispatch_rmpp_snd(IN osm_bind_handle_t h_bind,
388 IN const ib_mad_t * p_mad,
389 IN osmv_txn_ctx_t * p_txn,
390 IN const osm_mad_addr_t * p_mad_addr)
392 osmv_rmpp_send_ctx_t *p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn);
394 uint32_t old_wl = p_send_ctx->window_last;
395 uint32_t total_segs = osmv_rmpp_send_ctx_get_num_segs(p_send_ctx);
396 uint32_t seg_num = cl_ntoh32(((ib_rmpp_mad_t *) p_mad)->seg_num);
397 uint32_t new_wl = cl_ntoh32(((ib_rmpp_mad_t *) p_mad)->paylen_newwin);
398 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
400 OSM_LOG_ENTER(p_bo->p_vendor->p_log);
402 if (TRUE == osmv_rmpp_is_abort_stop(p_mad)) {
404 osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
405 "__osmv_dispatch_rmpp_snd: ERR 6502: "
406 "The remote side sent an ABORT/STOP indication.\n");
407 osmv_rmpp_snd_error(p_send_ctx, IB_REMOTE_ERROR);
408 goto dispatch_rmpp_snd_done;
411 if (FALSE == osmv_rmpp_is_ack(p_mad)) {
413 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
414 "Not supposed to receive DATA packets --> dropping the MAD\n");
415 goto dispatch_rmpp_snd_done;
418 /* Continue processing the ACK */
419 if (seg_num > old_wl) {
421 osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
422 "__osmv_dispatch_rmpp_snd: ERR 6503: "
423 "ACK received for a non-sent segment %d\n", seg_num);
425 osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr,
426 IB_RMPP_TYPE_ABORT, IB_RMPP_STATUS_S2B);
428 osmv_rmpp_snd_error(p_send_ctx, IB_REMOTE_ERROR);
429 goto dispatch_rmpp_snd_done;
432 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
433 "__osmv_dispatch_rmpp_snd: "
434 "New WL = %u Old WL = %u Total Segs = %u\n",
435 new_wl, old_wl, total_segs);
437 if (new_wl < old_wl) {
438 osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
439 "__osmv_dispatch_rmpp_snd: ERR 6508: "
440 "The receiver requests a smaller WL (%d) than before (%d)\n",
443 osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr,
444 IB_RMPP_TYPE_ABORT, IB_RMPP_STATUS_W2S);
446 osmv_rmpp_snd_error(p_send_ctx, IB_REMOTE_ERROR);
447 goto dispatch_rmpp_snd_done;
450 /* Update the sender's window, and optionally wake up the sender thread
451 * Note! A single ACK can acknowledge a whole range of segments: [WF..SEG_NUM]
453 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
454 "ACK for seg_num #%d accepted.\n", seg_num);
456 if (seg_num == old_wl) {
458 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
459 "The send window [%d:%d] is totally acknowledged.\n",
460 p_send_ctx->window_first, old_wl);
462 p_send_ctx->window_first = seg_num + 1;
463 p_send_ctx->window_last =
464 (new_wl < total_segs) ? new_wl : total_segs;
466 /* Remove the response timeout event for the window */
467 osmv_txn_remove_timeout_ev(h_bind, osmv_txn_get_key(p_txn));
469 /* Wake up the sending thread */
470 cl_event_signal(&p_send_ctx->event);
473 dispatch_rmpp_snd_done:
474 OSM_LOG_EXIT(p_bo->p_vendor->p_log);
478 * NAME __osmv_dispatch_rmpp_rcv()
480 * DESCRIPTION MAD handling by an RMPP receiver (DATA/ABORT/STOP)
483 static ib_api_status_t
484 __osmv_dispatch_rmpp_rcv(IN osm_bind_handle_t h_bind,
485 IN const ib_mad_t * p_mad,
486 IN osmv_txn_ctx_t * p_txn,
487 IN const osm_mad_addr_t * p_mad_addr)
489 ib_api_status_t status = IB_SUCCESS;
490 osmv_rmpp_recv_ctx_t *p_recv_ctx = osmv_txn_get_rmpp_recv_ctx(p_txn);
491 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
492 boolean_t is_last1 = FALSE, is_last2 = FALSE;
493 osm_madw_t *p_new_madw = NULL, *p_req_madw = NULL;
496 uint64_t key = osmv_txn_get_key(p_txn);
497 uint64_t tid = osmv_txn_get_tid(p_txn);
499 OSM_LOG_ENTER(p_bo->p_vendor->p_log);
501 if (TRUE == osmv_rmpp_is_ack(p_mad)) {
502 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
503 "Not supposed to receive ACK's --> dropping the MAD\n");
505 goto dispatch_rmpp_rcv_done;
508 if (TRUE == osmv_rmpp_is_abort_stop(p_mad)) {
509 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
510 "__osmv_dispatch_rmpp_rcv: ERR 6504: "
511 "The Remote Side stopped sending\n");
513 status = IB_REMOTE_ERROR;
514 goto dispatch_rmpp_rcv_done;
517 status = __osmv_dispatch_accept_seg(h_bind, p_txn, p_mad);
522 /* Check wheter this is the legal last MAD */
523 /* Criteria #1: the received MAD is marked last */
524 is_last1 = osmv_rmpp_is_last(p_mad);
526 /* Criteria #2: the total accumulated length hits the advertised one */
529 size = osmv_rmpp_recv_ctx_get_byte_num_from_first(p_recv_ctx);
532 (osmv_rmpp_recv_ctx_get_cur_byte_num(p_recv_ctx) >=
536 if (is_last1 != is_last2) {
538 osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr,
540 IB_RMPP_STATUS_BAD_LEN);
543 goto dispatch_rmpp_rcv_done;
546 /* TBD Consider an optimization - sending an ACK
547 * only for the last segment in the window
549 __osmv_dispatch_send_ack(h_bind, p_mad, p_txn, p_mad_addr);
552 case IB_INSUFFICIENT_RESOURCES:
553 /* An out-of-order segment received. Send the ACK anyway */
554 __osmv_dispatch_send_ack(h_bind, p_mad, p_txn, p_mad_addr);
556 goto dispatch_rmpp_rcv_done;
558 case IB_INSUFFICIENT_MEMORY:
559 osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr,
560 IB_RMPP_TYPE_STOP, IB_RMPP_STATUS_RESX);
561 goto dispatch_rmpp_rcv_done;
564 /* Illegal return code */
568 if (TRUE != is_last1) {
569 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
570 "RMPP MADW assembly continues, TID=0x%llX\n", tid);
571 goto dispatch_rmpp_rcv_done;
574 /* This is the last packet. */
576 /* The total size was not advertised in the first packet */
577 size = osmv_rmpp_recv_ctx_get_byte_num_from_last(p_recv_ctx);
581 NOTE: the received mad might not be >= 256 bytes.
582 some MADs might contain several SA records but still be
583 less then a full MAD.
584 We have to use RMPP to send them over since on a regular
585 "simple" MAD there is no way to know how many records were sent
588 /* Build the MAD wrapper to be returned to the user.
589 * The actual storage for the MAD is allocated there.
592 osm_mad_pool_get(p_bo->p_osm_pool, h_bind, size, p_mad_addr);
593 if (NULL == p_new_madw) {
594 osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
595 "__osmv_dispatch_rmpp_rcv: ERR 6506: "
596 "Out Of Memory - could not allocate %d bytes for the MADW\n",
599 status = IB_INSUFFICIENT_MEMORY;
600 goto dispatch_rmpp_rcv_done;
603 p_req_madw = osmv_txn_get_madw(p_txn);
604 p_mad_buf = osm_madw_get_mad_ptr(p_new_madw);
605 status = osmv_rmpp_recv_ctx_reassemble_arbt_mad(p_recv_ctx, size,
606 (uint8_t *) p_mad_buf);
607 if (IB_SUCCESS != status) {
608 osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
609 "__osmv_dispatch_rmpp_rcv: ERR 6507: "
610 "Internal error - could not reassemble the result MAD\n");
611 goto dispatch_rmpp_rcv_done; /* What can happen here? */
614 /* The MAD is assembled, we are about to apply the callback.
615 * Delete the transaction context, unless the transaction is double sided */
616 if (FALSE == osmv_txn_is_rmpp_init_by_peer(p_txn)
617 || FALSE == osmv_mad_is_multi_resp(p_mad)) {
619 osmv_txn_done(h_bind, key, FALSE);
622 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
623 "RMPP MADW %p assembly complete, TID=0x%llX\n", p_new_madw,
626 p_mad_buf->trans_id = cl_hton64(tid);
627 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
628 "Restoring the original TID to 0x%llX\n",
629 cl_ntoh64(p_mad_buf->trans_id));
631 /* Finally, do the job! */
632 p_bo->recv_cb(p_new_madw, p_bo->cb_context, p_req_madw);
634 dispatch_rmpp_rcv_done:
635 OSM_LOG_EXIT(p_bo->p_vendor->p_log);
640 * NAME __osmv_dispatch_accept_seg()
642 * DESCRIPTION Store a DATA segment at the RMPP receiver side,
643 * if one is received in order.
646 static ib_api_status_t
647 __osmv_dispatch_accept_seg(IN osm_bind_handle_t h_bind,
648 IN osmv_txn_ctx_t * p_txn, IN const ib_mad_t * p_mad)
650 ib_api_status_t ret = IB_SUCCESS;
651 uint32_t seg_num = cl_ntoh32(((ib_rmpp_mad_t *) p_mad)->seg_num);
652 osmv_rmpp_recv_ctx_t *p_recv_ctx = osmv_txn_get_rmpp_recv_ctx(p_txn);
653 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
654 uint64_t tid = osmv_txn_get_tid(p_txn);
656 OSM_LOG_ENTER(p_bo->p_vendor->p_log);
658 if (seg_num != p_recv_ctx->expected_seg) {
659 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
660 "TID 0x%llX: can't accept this segment (%d) - "
661 "this is a Go-Back-N implementation\n", tid, seg_num);
662 return IB_INSUFFICIENT_RESOURCES;
665 /* Store the packet's copy in the reassembly list.
666 * Promote the expected segment counter.
668 ret = osmv_rmpp_recv_ctx_store_mad_seg(p_recv_ctx, (uint8_t *) p_mad);
669 if (IB_SUCCESS != ret) {
673 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
674 "TID 0x%llX: segment %d accepted\n", tid, seg_num);
675 p_recv_ctx->expected_seg = seg_num + 1;
677 OSM_LOG_EXIT(p_bo->p_vendor->p_log);
682 * NAME __osmv_dispatch_send_ack()
687 * Consider sending the ACK from an async thread
688 * if problems with the receiving side processing arise.
692 __osmv_dispatch_send_ack(IN osm_bind_handle_t h_bind,
693 IN const ib_mad_t * p_req_mad,
694 IN osmv_txn_ctx_t * p_txn,
695 IN const osm_mad_addr_t * p_mad_addr)
697 osmv_rmpp_recv_ctx_t *p_recv_ctx = osmv_txn_get_rmpp_recv_ctx(p_txn);
699 /* ACK the segment # that was accepted */
700 uint32_t seg_num = cl_ntoh32(((ib_rmpp_mad_t *) p_req_mad)->seg_num);
702 /* NOTE! The receiver can publish the New Window Last (NWL) value
703 * that is greater than the total number of segments to be sent.
704 * It's the sender's responsibility to compute the correct number
705 * of segments to send in the next burst.
707 uint32_t nwl = p_recv_ctx->expected_seg + OSMV_RMPP_RECV_WIN - 1;
709 osmv_rmpp_send_ack(h_bind, p_req_mad, seg_num, nwl, p_mad_addr);