1 /* 2 * Copyright (c) 2004-2008 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. 5 * 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: 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * - Redistributions of source code must retain the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer. 19 * 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. 24 * 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 32 * SOFTWARE. 33 * 34 */ 35 36 #if HAVE_CONFIG_H 37 # include <config.h> 38 #endif /* HAVE_CONFIG_H */ 39 40 #include <string.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> 47 48 typedef enum _osmv_disp_route { 49 50 OSMV_ROUTE_DROP, 51 OSMV_ROUTE_SIMPLE, 52 OSMV_ROUTE_RMPP, 53 54 } osmv_disp_route_t; 55 56 /** 57 * FORWARD REFERENCES TO PRIVATE FUNCTIONS 58 */ 59 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); 63 64 static void 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); 69 70 static void 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); 75 76 static void 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); 81 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); 87 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); 92 static void 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); 97 98 /* 99 * NAME 100 * osmv_dispatch_mad 101 * 102 * DESCRIPTION 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) 108 * 109 * PARAMETERS 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 113 */ 114 115 ib_api_status_t 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) 119 { 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; 125 126 OSM_LOG_ENTER(p_bo->p_vendor->p_log); 127 128 CL_ASSERT(NULL != h_bind && NULL != p_mad && NULL != p_mad_addr); 129 130 osmv_txn_lock(p_bo); 131 132 if (TRUE == p_bo->is_closing) { 133 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); 137 138 ret = IB_INTERRUPTED; 139 goto dispatch_mad_done; 140 } 141 142 /* 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. 147 */ 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, 151 p_bo->p_vendor-> 152 p_pkt_randomizer, 153 p_mad) == TRUE) { 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; 157 } 158 } 159 160 switch (__osmv_dispatch_route(h_bind, p_mad, &p_txn)) { 161 162 case OSMV_ROUTE_DROP: 163 break; /* Do nothing */ 164 165 case OSMV_ROUTE_SIMPLE: 166 __osmv_dispatch_simple_mad(h_bind, p_mad, p_txn, p_mad_addr); 167 break; 168 169 case OSMV_ROUTE_RMPP: 170 __osmv_dispatch_rmpp_mad(h_bind, p_mad, p_txn, p_mad_addr); 171 break; 172 173 default: 174 CL_ASSERT(FALSE); 175 } 176 177 dispatch_mad_done: 178 osmv_txn_unlock(p_bo); 179 180 OSM_LOG_EXIT(p_log); 181 return ret; 182 } 183 184 /* 185 * NAME __osmv_dispatch_route() 186 * 187 * DESCRIPTION Decide which way to handle the received MAD: simple txn/RMPP/drop 188 */ 189 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) 193 { 194 ib_api_status_t ret; 195 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 196 boolean_t is_resp = ib_mad_is_response(p_mad); 197 boolean_t is_txn; 198 uint64_t key = cl_ntoh64(p_mad->trans_id); 199 200 CL_ASSERT(NULL != pp_txn); 201 202 ret = osmv_txn_lookup(h_bind, key, pp_txn); 203 is_txn = (IB_SUCCESS == ret); 204 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%" PRIx64 "). " 208 "Dropping the MAD.\n", key); 209 return OSMV_ROUTE_DROP; 210 } 211 212 if (TRUE == osmv_mad_is_rmpp(p_mad)) { 213 /* An RMPP transaction. The filtering is more delicate there */ 214 return OSMV_ROUTE_RMPP; 215 } 216 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%" PRIx64 " received (not a response). " 221 "Dropping the MAD.\n", key); 222 223 return OSMV_ROUTE_DROP; 224 } 225 226 return OSMV_ROUTE_SIMPLE; 227 } 228 229 /* 230 * NAME __osmv_dispatch_simple_mad() 231 * 232 * DESCRIPTION Handle a MAD that is part of non-RMPP transfer 233 */ 234 235 static void 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) 240 { 241 osm_madw_t *p_madw; 242 ib_mad_t *p_mad_buf; 243 osm_madw_t *p_req_madw = NULL; 244 osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 245 246 OSM_LOG_ENTER(p_bo->p_vendor->p_log); 247 248 /* Build the MAD wrapper to be returned to the user. 249 * The actual storage for the MAD is allocated there. 250 */ 251 p_madw = 252 osm_mad_pool_get(p_bo->p_osm_pool, h_bind, MAD_BLOCK_SIZE, 253 p_mad_addr); 254 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", 259 MAD_BLOCK_SIZE); 260 261 goto dispatch_simple_mad_done; 262 } 263 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); 267 268 if (NULL != p_txn) { 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); 272 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%" PRIx64 "\n", 276 cl_ntoh64(p_mad_buf->trans_id)); 277 278 /* Reply matched, transaction complete */ 279 osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), FALSE); 280 } else { 281 /* This is a REQUEST MAD. Don't create a context, pass upstream */ 282 } 283 284 /* Do the job ! */ 285 p_bo->recv_cb(p_madw, p_bo->cb_context, p_req_madw); 286 287 dispatch_simple_mad_done: 288 OSM_LOG_EXIT(p_bo->p_vendor->p_log); 289 } 290 291 /* 292 * NAME __osmv_dispatch_rmpp_mad() 293 * 294 * DESCRIPTION Handle a MAD that is part of RMPP transfer 295 */ 296 297 static void 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) 302 { 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; 307 osm_madw_t *p_madw; 308 309 OSM_LOG_ENTER(p_bo->p_vendor->p_log); 310 311 if (NULL == p_txn) { 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; 318 } 319 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. 322 */ 323 status = osmv_txn_init(h_bind, /*tid==key */ key, key, &p_txn); 324 if (IB_SUCCESS != status) { 325 goto dispatch_rmpp_mad_done; 326 } 327 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%" PRIx64 ") started\n", 331 key); 332 } 333 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! 340 */ 341 status = 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; 345 } 346 } 347 348 switch (osmv_txn_get_rmpp_state(p_txn)) { 349 350 case OSMV_TXN_RMPP_RECEIVER: 351 status = 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); 360 } 361 362 /* ABORT/STOP/LOCAL ERROR */ 363 osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), FALSE); 364 } 365 break; 366 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 */ 370 break; 371 372 default: 373 CL_ASSERT(FALSE); 374 } 375 376 dispatch_rmpp_mad_done: 377 OSM_LOG_EXIT(p_bo->p_vendor->p_log); 378 } 379 380 /* 381 * NAME __osmv_dispatch_rmpp_snd() 382 * 383 * DESCRIPTION MAD handling by an RMPP sender (ACK/ABORT/STOP) 384 */ 385 386 static void 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) 391 { 392 osmv_rmpp_send_ctx_t *p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn); 393 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; 399 400 OSM_LOG_ENTER(p_bo->p_vendor->p_log); 401 402 if (TRUE == osmv_rmpp_is_abort_stop(p_mad)) { 403 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; 409 } 410 411 if (FALSE == osmv_rmpp_is_ack(p_mad)) { 412 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; 416 } 417 418 /* Continue processing the ACK */ 419 if (seg_num > old_wl) { 420 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); 424 425 osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr, 426 IB_RMPP_TYPE_ABORT, IB_RMPP_STATUS_S2B); 427 428 osmv_rmpp_snd_error(p_send_ctx, IB_REMOTE_ERROR); 429 goto dispatch_rmpp_snd_done; 430 } 431 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); 436 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", 441 new_wl, old_wl); 442 443 osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr, 444 IB_RMPP_TYPE_ABORT, IB_RMPP_STATUS_W2S); 445 446 osmv_rmpp_snd_error(p_send_ctx, IB_REMOTE_ERROR); 447 goto dispatch_rmpp_snd_done; 448 } 449 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] 452 */ 453 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 454 "ACK for seg_num #%d accepted.\n", seg_num); 455 456 if (seg_num == old_wl) { 457 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); 461 462 p_send_ctx->window_first = seg_num + 1; 463 p_send_ctx->window_last = 464 (new_wl < total_segs) ? new_wl : total_segs; 465 466 /* Remove the response timeout event for the window */ 467 osmv_txn_remove_timeout_ev(h_bind, osmv_txn_get_key(p_txn)); 468 469 /* Wake up the sending thread */ 470 cl_event_signal(&p_send_ctx->event); 471 } 472 473 dispatch_rmpp_snd_done: 474 OSM_LOG_EXIT(p_bo->p_vendor->p_log); 475 } 476 477 /* 478 * NAME __osmv_dispatch_rmpp_rcv() 479 * 480 * DESCRIPTION MAD handling by an RMPP receiver (DATA/ABORT/STOP) 481 */ 482 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) 488 { 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; 494 ib_mad_t *p_mad_buf; 495 uint32_t size = 0; 496 uint64_t key = osmv_txn_get_key(p_txn); 497 uint64_t tid = osmv_txn_get_tid(p_txn); 498 499 OSM_LOG_ENTER(p_bo->p_vendor->p_log); 500 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"); 504 505 goto dispatch_rmpp_rcv_done; 506 } 507 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"); 512 513 status = IB_REMOTE_ERROR; 514 goto dispatch_rmpp_rcv_done; 515 } 516 517 status = __osmv_dispatch_accept_seg(h_bind, p_txn, p_mad); 518 switch (status) { 519 520 case IB_SUCCESS: 521 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); 525 526 /* Criteria #2: the total accumulated length hits the advertised one */ 527 is_last2 = is_last1; 528 529 size = osmv_rmpp_recv_ctx_get_byte_num_from_first(p_recv_ctx); 530 if (size > 0) { 531 is_last2 = 532 (osmv_rmpp_recv_ctx_get_cur_byte_num(p_recv_ctx) >= 533 size); 534 } 535 536 if (is_last1 != is_last2) { 537 538 osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr, 539 IB_RMPP_TYPE_ABORT, 540 IB_RMPP_STATUS_BAD_LEN); 541 542 status = IB_ERROR; 543 goto dispatch_rmpp_rcv_done; 544 } 545 546 /* TBD Consider an optimization - sending an ACK 547 * only for the last segment in the window 548 */ 549 __osmv_dispatch_send_ack(h_bind, p_mad, p_txn, p_mad_addr); 550 break; 551 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); 555 status = IB_SUCCESS; 556 goto dispatch_rmpp_rcv_done; 557 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; 562 563 default: 564 /* Illegal return code */ 565 CL_ASSERT(FALSE); 566 } 567 568 if (TRUE != is_last1) { 569 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 570 "RMPP MADW assembly continues, TID=0x%" PRIx64 "\n", tid); 571 goto dispatch_rmpp_rcv_done; 572 } 573 574 /* This is the last packet. */ 575 if (0 == size) { 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); 578 } 579 580 /* 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 586 */ 587 588 /* Build the MAD wrapper to be returned to the user. 589 * The actual storage for the MAD is allocated there. 590 */ 591 p_new_madw = 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", 597 size); 598 599 status = IB_INSUFFICIENT_MEMORY; 600 goto dispatch_rmpp_rcv_done; 601 } 602 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? */ 612 } 613 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)) { 618 619 osmv_txn_done(h_bind, key, FALSE); 620 } 621 622 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 623 "RMPP MADW %p assembly complete, TID=0x%" PRIx64 "\n", p_new_madw, 624 tid); 625 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%" PRIx64 "\n", 629 cl_ntoh64(p_mad_buf->trans_id)); 630 631 /* Finally, do the job! */ 632 p_bo->recv_cb(p_new_madw, p_bo->cb_context, p_req_madw); 633 634 dispatch_rmpp_rcv_done: 635 OSM_LOG_EXIT(p_bo->p_vendor->p_log); 636 return status; 637 } 638 639 /* 640 * NAME __osmv_dispatch_accept_seg() 641 * 642 * DESCRIPTION Store a DATA segment at the RMPP receiver side, 643 * if one is received in order. 644 */ 645 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) 649 { 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); 655 656 OSM_LOG_ENTER(p_bo->p_vendor->p_log); 657 658 if (seg_num != p_recv_ctx->expected_seg) { 659 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 660 "TID 0x%" PRIx64 ": can't accept this segment (%d) - " 661 "this is a Go-Back-N implementation\n", tid, seg_num); 662 return IB_INSUFFICIENT_RESOURCES; 663 } 664 665 /* Store the packet's copy in the reassembly list. 666 * Promote the expected segment counter. 667 */ 668 ret = osmv_rmpp_recv_ctx_store_mad_seg(p_recv_ctx, (uint8_t *) p_mad); 669 if (IB_SUCCESS != ret) { 670 return ret; 671 } 672 673 osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 674 "TID 0x%" PRIx64 ": segment %d accepted\n", tid, seg_num); 675 p_recv_ctx->expected_seg = seg_num + 1; 676 677 OSM_LOG_EXIT(p_bo->p_vendor->p_log); 678 return IB_SUCCESS; 679 } 680 681 /* 682 * NAME __osmv_dispatch_send_ack() 683 * 684 * DESCRIPTION 685 * 686 * ISSUES 687 * Consider sending the ACK from an async thread 688 * if problems with the receiving side processing arise. 689 */ 690 691 static void 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) 696 { 697 osmv_rmpp_recv_ctx_t *p_recv_ctx = osmv_txn_get_rmpp_recv_ctx(p_txn); 698 699 /* ACK the segment # that was accepted */ 700 uint32_t seg_num = cl_ntoh32(((ib_rmpp_mad_t *) p_req_mad)->seg_num); 701 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. 706 */ 707 uint32_t nwl = p_recv_ctx->expected_seg + OSMV_RMPP_RECV_WIN - 1; 708 709 osmv_rmpp_send_ack(h_bind, p_req_mad, seg_num, nwl, p_mad_addr); 710 } 711