1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. 3219820Sjeff * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. 4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5219820Sjeff * 6219820Sjeff * This software is available to you under a choice of one of two 7219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 8219820Sjeff * General Public License (GPL) Version 2, available from the file 9219820Sjeff * COPYING in the main directory of this source tree, or the 10219820Sjeff * OpenIB.org BSD license below: 11219820Sjeff * 12219820Sjeff * Redistribution and use in source and binary forms, with or 13219820Sjeff * without modification, are permitted provided that the following 14219820Sjeff * conditions are met: 15219820Sjeff * 16219820Sjeff * - Redistributions of source code must retain the above 17219820Sjeff * copyright notice, this list of conditions and the following 18219820Sjeff * disclaimer. 19219820Sjeff * 20219820Sjeff * - Redistributions in binary form must reproduce the above 21219820Sjeff * copyright notice, this list of conditions and the following 22219820Sjeff * disclaimer in the documentation and/or other materials 23219820Sjeff * provided with the distribution. 24219820Sjeff * 25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32219820Sjeff * SOFTWARE. 33219820Sjeff * 34219820Sjeff */ 35219820Sjeff 36219820Sjeff#if HAVE_CONFIG_H 37219820Sjeff# include <config.h> 38219820Sjeff#endif /* HAVE_CONFIG_H */ 39219820Sjeff 40219820Sjeff#include <string.h> 41219820Sjeff#include <vendor/osm_vendor_mlx.h> 42219820Sjeff#include <vendor/osm_vendor_mlx_defs.h> 43219820Sjeff#include <vendor/osm_vendor_mlx_svc.h> 44219820Sjeff#include <vendor/osm_vendor_mlx_transport.h> 45219820Sjeff#include <vendor/osm_vendor_mlx_sender.h> 46219820Sjeff#include <vendor/osm_pkt_randomizer.h> 47219820Sjeff 48219820Sjefftypedef enum _osmv_disp_route { 49219820Sjeff 50219820Sjeff OSMV_ROUTE_DROP, 51219820Sjeff OSMV_ROUTE_SIMPLE, 52219820Sjeff OSMV_ROUTE_RMPP, 53219820Sjeff 54219820Sjeff} osmv_disp_route_t; 55219820Sjeff 56219820Sjeff/** 57219820Sjeff * FORWARD REFERENCES TO PRIVATE FUNCTIONS 58219820Sjeff */ 59219820Sjeff 60219820Sjeffstatic osmv_disp_route_t 61219820Sjeff__osmv_dispatch_route(IN osm_bind_handle_t h_bind, 62219820Sjeff IN const ib_mad_t * p_mad, OUT osmv_txn_ctx_t ** pp_txn); 63219820Sjeff 64219820Sjeffstatic void 65219820Sjeff__osmv_dispatch_simple_mad(IN osm_bind_handle_t h_bind, 66219820Sjeff IN const ib_mad_t * p_mad, 67219820Sjeff IN osmv_txn_ctx_t * p_txn, 68219820Sjeff IN const osm_mad_addr_t * p_mad_addr); 69219820Sjeff 70219820Sjeffstatic void 71219820Sjeff__osmv_dispatch_rmpp_mad(IN osm_bind_handle_t h_bind, 72219820Sjeff IN const ib_mad_t * p_mad, 73219820Sjeff IN osmv_txn_ctx_t * p_txn, 74219820Sjeff IN const osm_mad_addr_t * p_mad_addr); 75219820Sjeff 76219820Sjeffstatic void 77219820Sjeff__osmv_dispatch_rmpp_snd(IN osm_bind_handle_t h_bind, 78219820Sjeff IN const ib_mad_t * p_mad, 79219820Sjeff IN osmv_txn_ctx_t * p_txn, 80219820Sjeff IN const osm_mad_addr_t * p_mad_addr); 81219820Sjeff 82219820Sjeffstatic ib_api_status_t 83219820Sjeff__osmv_dispatch_rmpp_rcv(IN osm_bind_handle_t h_bind, 84219820Sjeff IN const ib_mad_t * p_mad, 85219820Sjeff IN osmv_txn_ctx_t * p_txn, 86219820Sjeff IN const osm_mad_addr_t * p_mad_addr); 87219820Sjeff 88219820Sjeffstatic ib_api_status_t 89219820Sjeff__osmv_dispatch_accept_seg(IN osm_bind_handle_t h_bind, 90219820Sjeff IN osmv_txn_ctx_t * p_txn, 91219820Sjeff IN const ib_mad_t * p_mad); 92219820Sjeffstatic void 93219820Sjeff__osmv_dispatch_send_ack(IN osm_bind_handle_t h_bind, 94219820Sjeff IN const ib_mad_t * p_req_mad, 95219820Sjeff IN osmv_txn_ctx_t * p_txn, 96219820Sjeff IN const osm_mad_addr_t * p_mad_addr); 97219820Sjeff 98219820Sjeff/* 99219820Sjeff * NAME 100219820Sjeff * osmv_dispatch_mad 101219820Sjeff * 102219820Sjeff * DESCRIPTION 103219820Sjeff * Lower-level MAD dispatcher. 104219820Sjeff * Implements a switch between the following MAD consumers: 105219820Sjeff * (1) Non-RMPP consumer (DATA) 106219820Sjeff * (2) RMPP receiver (DATA/ABORT/STOP) 107219820Sjeff * (3) RMPP sender (ACK/ABORT/STOP) 108219820Sjeff * 109219820Sjeff * PARAMETERS 110219820Sjeff * h_bind The bind handle 111219820Sjeff * p_mad_buf The 256 byte buffer of individual MAD 112219820Sjeff * p_mad_addr The MAD originator's address 113219820Sjeff */ 114219820Sjeff 115219820Sjeffib_api_status_t 116219820Sjeffosmv_dispatch_mad(IN osm_bind_handle_t h_bind, 117219820Sjeff IN const void *p_mad_buf, 118219820Sjeff IN const osm_mad_addr_t * p_mad_addr) 119219820Sjeff{ 120219820Sjeff ib_api_status_t ret = IB_SUCCESS; 121219820Sjeff const ib_mad_t *p_mad = (ib_mad_t *) p_mad_buf; 122219820Sjeff osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 123219820Sjeff osmv_txn_ctx_t *p_txn = NULL; 124219820Sjeff osm_log_t *p_log = p_bo->p_vendor->p_log; 125219820Sjeff 126219820Sjeff OSM_LOG_ENTER(p_bo->p_vendor->p_log); 127219820Sjeff 128219820Sjeff CL_ASSERT(NULL != h_bind && NULL != p_mad && NULL != p_mad_addr); 129219820Sjeff 130219820Sjeff osmv_txn_lock(p_bo); 131219820Sjeff 132219820Sjeff if (TRUE == p_bo->is_closing) { 133219820Sjeff 134219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 135219820Sjeff "The bind handle %p is being closed. " 136219820Sjeff "The MAD will not be dispatched.\n", p_bo); 137219820Sjeff 138219820Sjeff ret = IB_INTERRUPTED; 139219820Sjeff goto dispatch_mad_done; 140219820Sjeff } 141219820Sjeff 142219820Sjeff /* 143219820Sjeff Add call for packet drop randomizer. 144219820Sjeff This is a testing feature. If run_randomizer flag is set to TRUE, 145219820Sjeff the randomizer will be called, and randomally will drop 146219820Sjeff a packet. This is used for simulating unstable fabric. 147219820Sjeff */ 148219820Sjeff if (p_bo->p_vendor->run_randomizer == TRUE) { 149219820Sjeff /* Try the randomizer */ 150219820Sjeff if (osm_pkt_randomizer_mad_drop(p_bo->p_vendor->p_log, 151219820Sjeff p_bo->p_vendor-> 152219820Sjeff p_pkt_randomizer, 153219820Sjeff p_mad) == TRUE) { 154219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 155219820Sjeff "The MAD will not be dispatched.\n"); 156219820Sjeff goto dispatch_mad_done; 157219820Sjeff } 158219820Sjeff } 159219820Sjeff 160219820Sjeff switch (__osmv_dispatch_route(h_bind, p_mad, &p_txn)) { 161219820Sjeff 162219820Sjeff case OSMV_ROUTE_DROP: 163219820Sjeff break; /* Do nothing */ 164219820Sjeff 165219820Sjeff case OSMV_ROUTE_SIMPLE: 166219820Sjeff __osmv_dispatch_simple_mad(h_bind, p_mad, p_txn, p_mad_addr); 167219820Sjeff break; 168219820Sjeff 169219820Sjeff case OSMV_ROUTE_RMPP: 170219820Sjeff __osmv_dispatch_rmpp_mad(h_bind, p_mad, p_txn, p_mad_addr); 171219820Sjeff break; 172219820Sjeff 173219820Sjeff default: 174219820Sjeff CL_ASSERT(FALSE); 175219820Sjeff } 176219820Sjeff 177219820Sjeffdispatch_mad_done: 178219820Sjeff osmv_txn_unlock(p_bo); 179219820Sjeff 180219820Sjeff OSM_LOG_EXIT(p_log); 181219820Sjeff return ret; 182219820Sjeff} 183219820Sjeff 184219820Sjeff/* 185219820Sjeff * NAME __osmv_dispatch_route() 186219820Sjeff * 187219820Sjeff * DESCRIPTION Decide which way to handle the received MAD: simple txn/RMPP/drop 188219820Sjeff */ 189219820Sjeff 190219820Sjeffstatic osmv_disp_route_t 191219820Sjeff__osmv_dispatch_route(IN osm_bind_handle_t h_bind, 192219820Sjeff IN const ib_mad_t * p_mad, OUT osmv_txn_ctx_t ** pp_txn) 193219820Sjeff{ 194219820Sjeff ib_api_status_t ret; 195219820Sjeff osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 196219820Sjeff boolean_t is_resp = osmv_mad_is_response(p_mad); 197219820Sjeff boolean_t is_txn; 198219820Sjeff uint64_t key = cl_ntoh64(p_mad->trans_id); 199219820Sjeff 200219820Sjeff CL_ASSERT(NULL != pp_txn); 201219820Sjeff 202219820Sjeff ret = osmv_txn_lookup(h_bind, key, pp_txn); 203219820Sjeff is_txn = (IB_SUCCESS == ret); 204219820Sjeff 205219820Sjeff if (FALSE == is_txn && TRUE == is_resp) { 206219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 207219820Sjeff "Received a response to a non-started/aged-out transaction (tid=0x%llX). " 208219820Sjeff "Dropping the MAD.\n", key); 209219820Sjeff return OSMV_ROUTE_DROP; 210219820Sjeff } 211219820Sjeff 212219820Sjeff if (TRUE == osmv_mad_is_rmpp(p_mad)) { 213219820Sjeff /* An RMPP transaction. The filtering is more delicate there */ 214219820Sjeff return OSMV_ROUTE_RMPP; 215219820Sjeff } 216219820Sjeff 217219820Sjeff if (TRUE == is_txn && FALSE == is_resp) { 218219820Sjeff /* Does this MAD try to start a transaction with duplicate tid? */ 219219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 220219820Sjeff "Duplicate TID 0x%llX received (not a response). " 221219820Sjeff "Dropping the MAD.\n", key); 222219820Sjeff 223219820Sjeff return OSMV_ROUTE_DROP; 224219820Sjeff } 225219820Sjeff 226219820Sjeff return OSMV_ROUTE_SIMPLE; 227219820Sjeff} 228219820Sjeff 229219820Sjeff/* 230219820Sjeff * NAME __osmv_dispatch_simple_mad() 231219820Sjeff * 232219820Sjeff * DESCRIPTION Handle a MAD that is part of non-RMPP transfer 233219820Sjeff */ 234219820Sjeff 235219820Sjeffstatic void 236219820Sjeff__osmv_dispatch_simple_mad(IN osm_bind_handle_t h_bind, 237219820Sjeff IN const ib_mad_t * p_mad, 238219820Sjeff IN osmv_txn_ctx_t * p_txn, 239219820Sjeff IN const osm_mad_addr_t * p_mad_addr) 240219820Sjeff{ 241219820Sjeff osm_madw_t *p_madw; 242219820Sjeff ib_mad_t *p_mad_buf; 243219820Sjeff osm_madw_t *p_req_madw = NULL; 244219820Sjeff osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 245219820Sjeff 246219820Sjeff OSM_LOG_ENTER(p_bo->p_vendor->p_log); 247219820Sjeff 248219820Sjeff /* Build the MAD wrapper to be returned to the user. 249219820Sjeff * The actual storage for the MAD is allocated there. 250219820Sjeff */ 251219820Sjeff p_madw = 252219820Sjeff osm_mad_pool_get(p_bo->p_osm_pool, h_bind, MAD_BLOCK_SIZE, 253219820Sjeff p_mad_addr); 254219820Sjeff 255219820Sjeff if (NULL == p_madw) { 256219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 257219820Sjeff "__osmv_dispatch_simple_mad: ERR 6501: " 258219820Sjeff "Out Of Memory - could not allocate a buffer of size %d\n", 259219820Sjeff MAD_BLOCK_SIZE); 260219820Sjeff 261219820Sjeff goto dispatch_simple_mad_done; 262219820Sjeff } 263219820Sjeff 264219820Sjeff p_mad_buf = osm_madw_get_mad_ptr(p_madw); 265219820Sjeff /* Copy the payload to the MAD buffer */ 266219820Sjeff memcpy((void *)p_mad_buf, (void *)p_mad, MAD_BLOCK_SIZE); 267219820Sjeff 268219820Sjeff if (NULL != p_txn) { 269219820Sjeff /* This is a RESPONSE MAD. Pair it with the REQUEST MAD, pass upstream */ 270219820Sjeff p_req_madw = p_txn->p_madw; 271219820Sjeff CL_ASSERT(NULL != p_req_madw); 272219820Sjeff 273219820Sjeff p_mad_buf->trans_id = cl_hton64(osmv_txn_get_tid(p_txn)); 274219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 275219820Sjeff "Restoring the original TID to 0x%llX\n", 276219820Sjeff cl_ntoh64(p_mad_buf->trans_id)); 277219820Sjeff 278219820Sjeff /* Reply matched, transaction complete */ 279219820Sjeff osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), FALSE); 280219820Sjeff } else { 281219820Sjeff /* This is a REQUEST MAD. Don't create a context, pass upstream */ 282219820Sjeff } 283219820Sjeff 284219820Sjeff /* Do the job ! */ 285219820Sjeff p_bo->recv_cb(p_madw, p_bo->cb_context, p_req_madw); 286219820Sjeff 287219820Sjeffdispatch_simple_mad_done: 288219820Sjeff OSM_LOG_EXIT(p_bo->p_vendor->p_log); 289219820Sjeff} 290219820Sjeff 291219820Sjeff/* 292219820Sjeff * NAME __osmv_dispatch_rmpp_mad() 293219820Sjeff * 294219820Sjeff * DESCRIPTION Handle a MAD that is part of RMPP transfer 295219820Sjeff */ 296219820Sjeff 297219820Sjeffstatic void 298219820Sjeff__osmv_dispatch_rmpp_mad(IN osm_bind_handle_t h_bind, 299219820Sjeff IN const ib_mad_t * p_mad, 300219820Sjeff IN osmv_txn_ctx_t * p_txn, 301219820Sjeff IN const osm_mad_addr_t * p_mad_addr) 302219820Sjeff{ 303219820Sjeff ib_api_status_t status = IB_SUCCESS; 304219820Sjeff uint64_t key = cl_ntoh64(p_mad->trans_id); 305219820Sjeff boolean_t is_init_by_peer = FALSE; 306219820Sjeff osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 307219820Sjeff osm_madw_t *p_madw; 308219820Sjeff 309219820Sjeff OSM_LOG_ENTER(p_bo->p_vendor->p_log); 310219820Sjeff 311219820Sjeff if (NULL == p_txn) { 312219820Sjeff if (FALSE == osmv_rmpp_is_data(p_mad) 313219820Sjeff || FALSE == osmv_rmpp_is_first(p_mad)) { 314219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 315219820Sjeff "The MAD does not match any transaction " 316219820Sjeff "and does not start a sender-initiated RMPP transfer.\n"); 317219820Sjeff goto dispatch_rmpp_mad_done; 318219820Sjeff } 319219820Sjeff 320219820Sjeff /* IB Spec 13.6.2.2. This is a Sender Initiated Transfer. 321219820Sjeff My peer is the requester and RMPP Sender. I am the RMPP Receiver. 322219820Sjeff */ 323219820Sjeff status = osmv_txn_init(h_bind, /*tid==key */ key, key, &p_txn); 324219820Sjeff if (IB_SUCCESS != status) { 325219820Sjeff goto dispatch_rmpp_mad_done; 326219820Sjeff } 327219820Sjeff 328219820Sjeff is_init_by_peer = TRUE; 329219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 330219820Sjeff "A new sender-initiated transfer (TID=0x%llX) started\n", 331219820Sjeff key); 332219820Sjeff } 333219820Sjeff 334219820Sjeff if (OSMV_TXN_RMPP_NONE == osmv_txn_get_rmpp_state(p_txn)) { 335219820Sjeff /* Case 1: Fall through from above. 336219820Sjeff * Case 2: When the transaction was initiated by me 337219820Sjeff * (a single request MAD), there was an uncertainty 338219820Sjeff * whether the reply will be RMPP. Now it's resolved, 339219820Sjeff * since the reply is RMPP! 340219820Sjeff */ 341219820Sjeff status = 342219820Sjeff osmv_txn_init_rmpp_receiver(h_bind, p_txn, is_init_by_peer); 343219820Sjeff if (IB_SUCCESS != status) { 344219820Sjeff goto dispatch_rmpp_mad_done; 345219820Sjeff } 346219820Sjeff } 347219820Sjeff 348219820Sjeff switch (osmv_txn_get_rmpp_state(p_txn)) { 349219820Sjeff 350219820Sjeff case OSMV_TXN_RMPP_RECEIVER: 351219820Sjeff status = 352219820Sjeff __osmv_dispatch_rmpp_rcv(h_bind, p_mad, p_txn, p_mad_addr); 353219820Sjeff if (IB_SUCCESS != status) { 354219820Sjeff if (FALSE == osmv_txn_is_rmpp_init_by_peer(p_txn)) { 355219820Sjeff /* This is a requester, still waiting for the reply. Apply the callback */ 356219820Sjeff /* update the status of the p_madw */ 357219820Sjeff p_madw = osmv_txn_get_madw(p_txn); 358219820Sjeff p_madw->status = status; 359219820Sjeff p_bo->send_err_cb(p_bo->cb_context, p_madw); 360219820Sjeff } 361219820Sjeff 362219820Sjeff /* ABORT/STOP/LOCAL ERROR */ 363219820Sjeff osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), FALSE); 364219820Sjeff } 365219820Sjeff break; 366219820Sjeff 367219820Sjeff case OSMV_TXN_RMPP_SENDER: 368219820Sjeff __osmv_dispatch_rmpp_snd(h_bind, p_mad, p_txn, p_mad_addr); 369219820Sjeff /* If an error happens here, it's the sender thread to cleanup the txn */ 370219820Sjeff break; 371219820Sjeff 372219820Sjeff default: 373219820Sjeff CL_ASSERT(FALSE); 374219820Sjeff } 375219820Sjeff 376219820Sjeffdispatch_rmpp_mad_done: 377219820Sjeff OSM_LOG_EXIT(p_bo->p_vendor->p_log); 378219820Sjeff} 379219820Sjeff 380219820Sjeff/* 381219820Sjeff * NAME __osmv_dispatch_rmpp_snd() 382219820Sjeff * 383219820Sjeff * DESCRIPTION MAD handling by an RMPP sender (ACK/ABORT/STOP) 384219820Sjeff */ 385219820Sjeff 386219820Sjeffstatic void 387219820Sjeff__osmv_dispatch_rmpp_snd(IN osm_bind_handle_t h_bind, 388219820Sjeff IN const ib_mad_t * p_mad, 389219820Sjeff IN osmv_txn_ctx_t * p_txn, 390219820Sjeff IN const osm_mad_addr_t * p_mad_addr) 391219820Sjeff{ 392219820Sjeff osmv_rmpp_send_ctx_t *p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn); 393219820Sjeff 394219820Sjeff uint32_t old_wl = p_send_ctx->window_last; 395219820Sjeff uint32_t total_segs = osmv_rmpp_send_ctx_get_num_segs(p_send_ctx); 396219820Sjeff uint32_t seg_num = cl_ntoh32(((ib_rmpp_mad_t *) p_mad)->seg_num); 397219820Sjeff uint32_t new_wl = cl_ntoh32(((ib_rmpp_mad_t *) p_mad)->paylen_newwin); 398219820Sjeff osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 399219820Sjeff 400219820Sjeff OSM_LOG_ENTER(p_bo->p_vendor->p_log); 401219820Sjeff 402219820Sjeff if (TRUE == osmv_rmpp_is_abort_stop(p_mad)) { 403219820Sjeff 404219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 405219820Sjeff "__osmv_dispatch_rmpp_snd: ERR 6502: " 406219820Sjeff "The remote side sent an ABORT/STOP indication.\n"); 407219820Sjeff osmv_rmpp_snd_error(p_send_ctx, IB_REMOTE_ERROR); 408219820Sjeff goto dispatch_rmpp_snd_done; 409219820Sjeff } 410219820Sjeff 411219820Sjeff if (FALSE == osmv_rmpp_is_ack(p_mad)) { 412219820Sjeff 413219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 414219820Sjeff "Not supposed to receive DATA packets --> dropping the MAD\n"); 415219820Sjeff goto dispatch_rmpp_snd_done; 416219820Sjeff } 417219820Sjeff 418219820Sjeff /* Continue processing the ACK */ 419219820Sjeff if (seg_num > old_wl) { 420219820Sjeff 421219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 422219820Sjeff "__osmv_dispatch_rmpp_snd: ERR 6503: " 423219820Sjeff "ACK received for a non-sent segment %d\n", seg_num); 424219820Sjeff 425219820Sjeff osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr, 426219820Sjeff IB_RMPP_TYPE_ABORT, IB_RMPP_STATUS_S2B); 427219820Sjeff 428219820Sjeff osmv_rmpp_snd_error(p_send_ctx, IB_REMOTE_ERROR); 429219820Sjeff goto dispatch_rmpp_snd_done; 430219820Sjeff } 431219820Sjeff 432219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 433219820Sjeff "__osmv_dispatch_rmpp_snd: " 434219820Sjeff "New WL = %u Old WL = %u Total Segs = %u\n", 435219820Sjeff new_wl, old_wl, total_segs); 436219820Sjeff 437219820Sjeff if (new_wl < old_wl) { 438219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 439219820Sjeff "__osmv_dispatch_rmpp_snd: ERR 6508: " 440219820Sjeff "The receiver requests a smaller WL (%d) than before (%d)\n", 441219820Sjeff new_wl, old_wl); 442219820Sjeff 443219820Sjeff osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr, 444219820Sjeff IB_RMPP_TYPE_ABORT, IB_RMPP_STATUS_W2S); 445219820Sjeff 446219820Sjeff osmv_rmpp_snd_error(p_send_ctx, IB_REMOTE_ERROR); 447219820Sjeff goto dispatch_rmpp_snd_done; 448219820Sjeff } 449219820Sjeff 450219820Sjeff /* Update the sender's window, and optionally wake up the sender thread 451219820Sjeff * Note! A single ACK can acknowledge a whole range of segments: [WF..SEG_NUM] 452219820Sjeff */ 453219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 454219820Sjeff "ACK for seg_num #%d accepted.\n", seg_num); 455219820Sjeff 456219820Sjeff if (seg_num == old_wl) { 457219820Sjeff 458219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 459219820Sjeff "The send window [%d:%d] is totally acknowledged.\n", 460219820Sjeff p_send_ctx->window_first, old_wl); 461219820Sjeff 462219820Sjeff p_send_ctx->window_first = seg_num + 1; 463219820Sjeff p_send_ctx->window_last = 464219820Sjeff (new_wl < total_segs) ? new_wl : total_segs; 465219820Sjeff 466219820Sjeff /* Remove the response timeout event for the window */ 467219820Sjeff osmv_txn_remove_timeout_ev(h_bind, osmv_txn_get_key(p_txn)); 468219820Sjeff 469219820Sjeff /* Wake up the sending thread */ 470219820Sjeff cl_event_signal(&p_send_ctx->event); 471219820Sjeff } 472219820Sjeff 473219820Sjeffdispatch_rmpp_snd_done: 474219820Sjeff OSM_LOG_EXIT(p_bo->p_vendor->p_log); 475219820Sjeff} 476219820Sjeff 477219820Sjeff/* 478219820Sjeff * NAME __osmv_dispatch_rmpp_rcv() 479219820Sjeff * 480219820Sjeff * DESCRIPTION MAD handling by an RMPP receiver (DATA/ABORT/STOP) 481219820Sjeff */ 482219820Sjeff 483219820Sjeffstatic ib_api_status_t 484219820Sjeff__osmv_dispatch_rmpp_rcv(IN osm_bind_handle_t h_bind, 485219820Sjeff IN const ib_mad_t * p_mad, 486219820Sjeff IN osmv_txn_ctx_t * p_txn, 487219820Sjeff IN const osm_mad_addr_t * p_mad_addr) 488219820Sjeff{ 489219820Sjeff ib_api_status_t status = IB_SUCCESS; 490219820Sjeff osmv_rmpp_recv_ctx_t *p_recv_ctx = osmv_txn_get_rmpp_recv_ctx(p_txn); 491219820Sjeff osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 492219820Sjeff boolean_t is_last1 = FALSE, is_last2 = FALSE; 493219820Sjeff osm_madw_t *p_new_madw = NULL, *p_req_madw = NULL; 494219820Sjeff ib_mad_t *p_mad_buf; 495219820Sjeff uint32_t size = 0; 496219820Sjeff uint64_t key = osmv_txn_get_key(p_txn); 497219820Sjeff uint64_t tid = osmv_txn_get_tid(p_txn); 498219820Sjeff 499219820Sjeff OSM_LOG_ENTER(p_bo->p_vendor->p_log); 500219820Sjeff 501219820Sjeff if (TRUE == osmv_rmpp_is_ack(p_mad)) { 502219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 503219820Sjeff "Not supposed to receive ACK's --> dropping the MAD\n"); 504219820Sjeff 505219820Sjeff goto dispatch_rmpp_rcv_done; 506219820Sjeff } 507219820Sjeff 508219820Sjeff if (TRUE == osmv_rmpp_is_abort_stop(p_mad)) { 509219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 510219820Sjeff "__osmv_dispatch_rmpp_rcv: ERR 6504: " 511219820Sjeff "The Remote Side stopped sending\n"); 512219820Sjeff 513219820Sjeff status = IB_REMOTE_ERROR; 514219820Sjeff goto dispatch_rmpp_rcv_done; 515219820Sjeff } 516219820Sjeff 517219820Sjeff status = __osmv_dispatch_accept_seg(h_bind, p_txn, p_mad); 518219820Sjeff switch (status) { 519219820Sjeff 520219820Sjeff case IB_SUCCESS: 521219820Sjeff 522219820Sjeff /* Check wheter this is the legal last MAD */ 523219820Sjeff /* Criteria #1: the received MAD is marked last */ 524219820Sjeff is_last1 = osmv_rmpp_is_last(p_mad); 525219820Sjeff 526219820Sjeff /* Criteria #2: the total accumulated length hits the advertised one */ 527219820Sjeff is_last2 = is_last1; 528219820Sjeff 529219820Sjeff size = osmv_rmpp_recv_ctx_get_byte_num_from_first(p_recv_ctx); 530219820Sjeff if (size > 0) { 531219820Sjeff is_last2 = 532219820Sjeff (osmv_rmpp_recv_ctx_get_cur_byte_num(p_recv_ctx) >= 533219820Sjeff size); 534219820Sjeff } 535219820Sjeff 536219820Sjeff if (is_last1 != is_last2) { 537219820Sjeff 538219820Sjeff osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr, 539219820Sjeff IB_RMPP_TYPE_ABORT, 540219820Sjeff IB_RMPP_STATUS_BAD_LEN); 541219820Sjeff 542219820Sjeff status = IB_ERROR; 543219820Sjeff goto dispatch_rmpp_rcv_done; 544219820Sjeff } 545219820Sjeff 546219820Sjeff /* TBD Consider an optimization - sending an ACK 547219820Sjeff * only for the last segment in the window 548219820Sjeff */ 549219820Sjeff __osmv_dispatch_send_ack(h_bind, p_mad, p_txn, p_mad_addr); 550219820Sjeff break; 551219820Sjeff 552219820Sjeff case IB_INSUFFICIENT_RESOURCES: 553219820Sjeff /* An out-of-order segment received. Send the ACK anyway */ 554219820Sjeff __osmv_dispatch_send_ack(h_bind, p_mad, p_txn, p_mad_addr); 555219820Sjeff status = IB_SUCCESS; 556219820Sjeff goto dispatch_rmpp_rcv_done; 557219820Sjeff 558219820Sjeff case IB_INSUFFICIENT_MEMORY: 559219820Sjeff osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr, 560219820Sjeff IB_RMPP_TYPE_STOP, IB_RMPP_STATUS_RESX); 561219820Sjeff goto dispatch_rmpp_rcv_done; 562219820Sjeff 563219820Sjeff default: 564219820Sjeff /* Illegal return code */ 565219820Sjeff CL_ASSERT(FALSE); 566219820Sjeff } 567219820Sjeff 568219820Sjeff if (TRUE != is_last1) { 569219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 570219820Sjeff "RMPP MADW assembly continues, TID=0x%llX\n", tid); 571219820Sjeff goto dispatch_rmpp_rcv_done; 572219820Sjeff } 573219820Sjeff 574219820Sjeff /* This is the last packet. */ 575219820Sjeff if (0 == size) { 576219820Sjeff /* The total size was not advertised in the first packet */ 577219820Sjeff size = osmv_rmpp_recv_ctx_get_byte_num_from_last(p_recv_ctx); 578219820Sjeff } 579219820Sjeff 580219820Sjeff /* 581219820Sjeff NOTE: the received mad might not be >= 256 bytes. 582219820Sjeff some MADs might contain several SA records but still be 583219820Sjeff less then a full MAD. 584219820Sjeff We have to use RMPP to send them over since on a regular 585219820Sjeff "simple" MAD there is no way to know how many records were sent 586219820Sjeff */ 587219820Sjeff 588219820Sjeff /* Build the MAD wrapper to be returned to the user. 589219820Sjeff * The actual storage for the MAD is allocated there. 590219820Sjeff */ 591219820Sjeff p_new_madw = 592219820Sjeff osm_mad_pool_get(p_bo->p_osm_pool, h_bind, size, p_mad_addr); 593219820Sjeff if (NULL == p_new_madw) { 594219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 595219820Sjeff "__osmv_dispatch_rmpp_rcv: ERR 6506: " 596219820Sjeff "Out Of Memory - could not allocate %d bytes for the MADW\n", 597219820Sjeff size); 598219820Sjeff 599219820Sjeff status = IB_INSUFFICIENT_MEMORY; 600219820Sjeff goto dispatch_rmpp_rcv_done; 601219820Sjeff } 602219820Sjeff 603219820Sjeff p_req_madw = osmv_txn_get_madw(p_txn); 604219820Sjeff p_mad_buf = osm_madw_get_mad_ptr(p_new_madw); 605219820Sjeff status = osmv_rmpp_recv_ctx_reassemble_arbt_mad(p_recv_ctx, size, 606219820Sjeff (uint8_t *) p_mad_buf); 607219820Sjeff if (IB_SUCCESS != status) { 608219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 609219820Sjeff "__osmv_dispatch_rmpp_rcv: ERR 6507: " 610219820Sjeff "Internal error - could not reassemble the result MAD\n"); 611219820Sjeff goto dispatch_rmpp_rcv_done; /* What can happen here? */ 612219820Sjeff } 613219820Sjeff 614219820Sjeff /* The MAD is assembled, we are about to apply the callback. 615219820Sjeff * Delete the transaction context, unless the transaction is double sided */ 616219820Sjeff if (FALSE == osmv_txn_is_rmpp_init_by_peer(p_txn) 617219820Sjeff || FALSE == osmv_mad_is_multi_resp(p_mad)) { 618219820Sjeff 619219820Sjeff osmv_txn_done(h_bind, key, FALSE); 620219820Sjeff } 621219820Sjeff 622219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 623219820Sjeff "RMPP MADW %p assembly complete, TID=0x%llX\n", p_new_madw, 624219820Sjeff tid); 625219820Sjeff 626219820Sjeff p_mad_buf->trans_id = cl_hton64(tid); 627219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 628219820Sjeff "Restoring the original TID to 0x%llX\n", 629219820Sjeff cl_ntoh64(p_mad_buf->trans_id)); 630219820Sjeff 631219820Sjeff /* Finally, do the job! */ 632219820Sjeff p_bo->recv_cb(p_new_madw, p_bo->cb_context, p_req_madw); 633219820Sjeff 634219820Sjeffdispatch_rmpp_rcv_done: 635219820Sjeff OSM_LOG_EXIT(p_bo->p_vendor->p_log); 636219820Sjeff return status; 637219820Sjeff} 638219820Sjeff 639219820Sjeff/* 640219820Sjeff * NAME __osmv_dispatch_accept_seg() 641219820Sjeff * 642219820Sjeff * DESCRIPTION Store a DATA segment at the RMPP receiver side, 643219820Sjeff * if one is received in order. 644219820Sjeff */ 645219820Sjeff 646219820Sjeffstatic ib_api_status_t 647219820Sjeff__osmv_dispatch_accept_seg(IN osm_bind_handle_t h_bind, 648219820Sjeff IN osmv_txn_ctx_t * p_txn, IN const ib_mad_t * p_mad) 649219820Sjeff{ 650219820Sjeff ib_api_status_t ret = IB_SUCCESS; 651219820Sjeff uint32_t seg_num = cl_ntoh32(((ib_rmpp_mad_t *) p_mad)->seg_num); 652219820Sjeff osmv_rmpp_recv_ctx_t *p_recv_ctx = osmv_txn_get_rmpp_recv_ctx(p_txn); 653219820Sjeff osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 654219820Sjeff uint64_t tid = osmv_txn_get_tid(p_txn); 655219820Sjeff 656219820Sjeff OSM_LOG_ENTER(p_bo->p_vendor->p_log); 657219820Sjeff 658219820Sjeff if (seg_num != p_recv_ctx->expected_seg) { 659219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 660219820Sjeff "TID 0x%llX: can't accept this segment (%d) - " 661219820Sjeff "this is a Go-Back-N implementation\n", tid, seg_num); 662219820Sjeff return IB_INSUFFICIENT_RESOURCES; 663219820Sjeff } 664219820Sjeff 665219820Sjeff /* Store the packet's copy in the reassembly list. 666219820Sjeff * Promote the expected segment counter. 667219820Sjeff */ 668219820Sjeff ret = osmv_rmpp_recv_ctx_store_mad_seg(p_recv_ctx, (uint8_t *) p_mad); 669219820Sjeff if (IB_SUCCESS != ret) { 670219820Sjeff return ret; 671219820Sjeff } 672219820Sjeff 673219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 674219820Sjeff "TID 0x%llX: segment %d accepted\n", tid, seg_num); 675219820Sjeff p_recv_ctx->expected_seg = seg_num + 1; 676219820Sjeff 677219820Sjeff OSM_LOG_EXIT(p_bo->p_vendor->p_log); 678219820Sjeff return IB_SUCCESS; 679219820Sjeff} 680219820Sjeff 681219820Sjeff/* 682219820Sjeff * NAME __osmv_dispatch_send_ack() 683219820Sjeff * 684219820Sjeff * DESCRIPTION 685219820Sjeff * 686219820Sjeff * ISSUES 687219820Sjeff * Consider sending the ACK from an async thread 688219820Sjeff * if problems with the receiving side processing arise. 689219820Sjeff */ 690219820Sjeff 691219820Sjeffstatic void 692219820Sjeff__osmv_dispatch_send_ack(IN osm_bind_handle_t h_bind, 693219820Sjeff IN const ib_mad_t * p_req_mad, 694219820Sjeff IN osmv_txn_ctx_t * p_txn, 695219820Sjeff IN const osm_mad_addr_t * p_mad_addr) 696219820Sjeff{ 697219820Sjeff osmv_rmpp_recv_ctx_t *p_recv_ctx = osmv_txn_get_rmpp_recv_ctx(p_txn); 698219820Sjeff 699219820Sjeff /* ACK the segment # that was accepted */ 700219820Sjeff uint32_t seg_num = cl_ntoh32(((ib_rmpp_mad_t *) p_req_mad)->seg_num); 701219820Sjeff 702219820Sjeff /* NOTE! The receiver can publish the New Window Last (NWL) value 703219820Sjeff * that is greater than the total number of segments to be sent. 704219820Sjeff * It's the sender's responsibility to compute the correct number 705219820Sjeff * of segments to send in the next burst. 706219820Sjeff */ 707219820Sjeff uint32_t nwl = p_recv_ctx->expected_seg + OSMV_RMPP_RECV_WIN - 1; 708219820Sjeff 709219820Sjeff osmv_rmpp_send_ack(h_bind, p_req_mad, seg_num, nwl, p_mad_addr); 710219820Sjeff} 711