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_sender.h> 42219820Sjeff#include <vendor/osm_vendor_mlx_transport.h> 43219820Sjeff#include <vendor/osm_vendor_mlx_svc.h> 44219820Sjeff#include <vendor/osm_pkt_randomizer.h> 45219820Sjeff 46219820Sjeffstatic ib_api_status_t 47219820Sjeff__osmv_rmpp_send_segment(IN osm_bind_handle_t h_bind, 48219820Sjeff IN osmv_txn_ctx_t * p_txn, IN uint32_t seg_num); 49219820Sjeff 50219820Sjeff/****d* OSM Vendor/osmv_simple_send_madw 51219820Sjeff * NAME 52219820Sjeff * osmv_simple_send_madw 53219820Sjeff * 54219820Sjeff * DESCRIPTION 55219820Sjeff * Send a single MAD (256 bytes). 56219820Sjeff * 57219820Sjeff * If this MAD requires a response, set the timeout event. 58219820Sjeff * The function call returns when the MAD's send completion is received. 59219820Sjeff * 60219820Sjeff */ 61219820Sjeff 62219820Sjeffib_api_status_t 63219820Sjeffosmv_simple_send_madw(IN osm_bind_handle_t h_bind, 64219820Sjeff IN osm_madw_t * const p_madw, 65219820Sjeff IN osmv_txn_ctx_t * p_txn, IN boolean_t is_retry) 66219820Sjeff{ 67219820Sjeff ib_api_status_t ret; 68219820Sjeff osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 69219820Sjeff osm_mad_addr_t *p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw); 70219820Sjeff uint8_t mad_buf[MAD_BLOCK_SIZE]; 71219820Sjeff ib_mad_t *p_mad = (ib_mad_t *) mad_buf; 72219820Sjeff uint64_t key = 0; 73219820Sjeff 74219820Sjeff OSM_LOG_ENTER(p_bo->p_vendor->p_log); 75219820Sjeff 76219820Sjeff CL_ASSERT(p_madw->mad_size <= MAD_BLOCK_SIZE); 77219820Sjeff 78219820Sjeff memset(p_mad, 0, MAD_BLOCK_SIZE); 79219820Sjeff memcpy(p_mad, osm_madw_get_mad_ptr(p_madw), p_madw->mad_size); 80219820Sjeff 81219820Sjeff if (NULL != p_txn) { 82219820Sjeff /* Push a fake txn id to the MAD */ 83219820Sjeff key = osmv_txn_get_key(p_txn); 84219820Sjeff p_mad->trans_id = cl_hton64(key); 85219820Sjeff } 86219820Sjeff 87219820Sjeff /* 88219820Sjeff Add call for packet drop randomizer. 89219820Sjeff This is a testing feature. If run_randomizer flag is set to TRUE, 90219820Sjeff the randomizer will be called, and randomally will drop 91219820Sjeff a packet. This is used for simulating unstable fabric. 92219820Sjeff */ 93219820Sjeff if (p_bo->p_vendor->run_randomizer == TRUE) { 94219820Sjeff /* Try the randomizer */ 95219820Sjeff if (osm_pkt_randomizer_mad_drop(p_bo->p_vendor->p_log, 96219820Sjeff p_bo->p_vendor-> 97219820Sjeff p_pkt_randomizer, 98219820Sjeff p_mad) == TRUE) { 99219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 100219820Sjeff "The MAD will not be sent. \n"); 101219820Sjeff ret = IB_SUCCESS; 102219820Sjeff } else { 103219820Sjeff ret = 104219820Sjeff osmv_transport_mad_send(h_bind, p_mad, p_mad_addr); 105219820Sjeff } 106219820Sjeff } else { 107219820Sjeff ret = osmv_transport_mad_send(h_bind, p_mad, p_mad_addr); 108219820Sjeff } 109219820Sjeff 110219820Sjeff if ((IB_SUCCESS == ret) && (NULL != p_txn) && (!is_retry)) { 111219820Sjeff /* Set the timeout for receiving the response MAD */ 112219820Sjeff ret = osmv_txn_set_timeout_ev(h_bind, key, 113219820Sjeff p_bo->p_vendor->resp_timeout); 114219820Sjeff } 115219820Sjeff 116219820Sjeff OSM_LOG_EXIT(p_bo->p_vendor->p_log); 117219820Sjeff return ret; 118219820Sjeff} 119219820Sjeff 120219820Sjeff/***** OSM Vendor/osmv_rmpp_send_madw 121219820Sjeff * NAME 122219820Sjeff * osmv_rmpp_send_madw 123219820Sjeff * 124219820Sjeff * DESCRIPTION 125219820Sjeff * Send a single message (MAD wrapper of arbitrary length). 126219820Sjeff * Follow the RMPP semantics 127219820Sjeff * (segmentation, send window, timeouts etc). 128219820Sjeff * 129219820Sjeff * The function call returns either when the whole message 130219820Sjeff * has been acknowledged, or upon error. 131219820Sjeff * 132219820Sjeff * ASSUMPTIONS 133219820Sjeff * The RMPP sender context is set up 134219820Sjeff */ 135219820Sjeff 136219820Sjeffib_api_status_t 137219820Sjeffosmv_rmpp_send_madw(IN osm_bind_handle_t h_bind, 138219820Sjeff IN osm_madw_t * const p_madw, 139219820Sjeff IN osmv_txn_ctx_t * p_txn, IN boolean_t is_rmpp_ds) 140219820Sjeff{ 141219820Sjeff ib_api_status_t ret = IB_SUCCESS; 142219820Sjeff uint32_t i, total_segs; 143219820Sjeff 144219820Sjeff osmv_rmpp_send_ctx_t *p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn); 145219820Sjeff osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 146219820Sjeff 147219820Sjeff OSM_LOG_ENTER(p_bo->p_vendor->p_log); 148219820Sjeff 149219820Sjeff total_segs = osmv_rmpp_send_ctx_get_num_segs(p_send_ctx); 150219820Sjeff CL_ASSERT(total_segs >= 1); 151219820Sjeff 152219820Sjeff /* In the double-sided transfer, wait for ACK 0 */ 153219820Sjeff 154219820Sjeff for (;;) { 155219820Sjeff 156219820Sjeff if (p_send_ctx->window_first > total_segs) { 157219820Sjeff 158219820Sjeff /* Every segment is acknowledged */ 159219820Sjeff break; 160219820Sjeff } 161219820Sjeff 162219820Sjeff /* Send the next burst. */ 163219820Sjeff for (i = p_send_ctx->window_first; i <= p_send_ctx->window_last; 164219820Sjeff i++) { 165219820Sjeff 166219820Sjeff /* Send a segment and setup a timeout timer */ 167219820Sjeff ret = __osmv_rmpp_send_segment(h_bind, p_txn, i); 168219820Sjeff if (IB_SUCCESS != ret) { 169219820Sjeff goto send_done; 170219820Sjeff } 171219820Sjeff } 172219820Sjeff 173219820Sjeff /* Set the Response Timeout for the ACK on the last DATA segment */ 174219820Sjeff ret = osmv_txn_set_timeout_ev(h_bind, osmv_txn_get_key(p_txn), 175219820Sjeff p_bo->p_vendor->resp_timeout); 176219820Sjeff if (IB_SUCCESS != ret) { 177219820Sjeff goto send_done; 178219820Sjeff } 179219820Sjeff 180219820Sjeff /* Going to sleep. Let the others access the transaction DB */ 181219820Sjeff osmv_txn_unlock(p_bo); 182219820Sjeff 183219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 184219820Sjeff "RMPP Sender thread (madw=%p) going to sleep ...\n", 185219820Sjeff p_madw); 186219820Sjeff 187219820Sjeff /* Await the next event to happen */ 188219820Sjeff cl_event_wait_on(&p_send_ctx->event, 189219820Sjeff EVENT_NO_TIMEOUT, TRUE /* interruptible */ ); 190219820Sjeff 191219820Sjeff /* Got a signal from the MAD dispatcher/timeout handler */ 192219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 193219820Sjeff "RMPP Sender thread (madw=%p) waking up on a signal ...\n", 194219820Sjeff p_madw); 195219820Sjeff 196219820Sjeff /* Let's see what changed... Make this atomic - re-acquire the lock. */ 197219820Sjeff osmv_txn_lock(p_bo); 198219820Sjeff 199219820Sjeff if (TRUE == p_bo->is_closing) { 200219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 201219820Sjeff "osmv_rmpp_send_madw: ERR 6601: " 202219820Sjeff "The bind handle %p is being closed. " 203219820Sjeff "Stopping the RMPP Send of MADW %p\n", 204219820Sjeff h_bind, p_madw); 205219820Sjeff 206219820Sjeff ret = IB_TIMEOUT; 207219820Sjeff return IB_INTERRUPTED; 208219820Sjeff } 209219820Sjeff 210219820Sjeff /* STOP? ABORT? TIMEOUT? */ 211219820Sjeff if (IB_SUCCESS != p_send_ctx->status) { 212219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 213219820Sjeff "osmv_rmpp_send_madw: ERR 6602: " 214219820Sjeff "An error (%s) happened during the RMPP send of %p. Bailing out.\n", 215219820Sjeff ib_get_err_str(p_send_ctx->status), p_madw); 216219820Sjeff ret = p_send_ctx->status; 217219820Sjeff goto send_done; 218219820Sjeff } 219219820Sjeff } 220219820Sjeff 221219820Sjeff if (TRUE == is_rmpp_ds) { 222219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 223219820Sjeff "Double-sided RMPP - switching to be the receiver.\n"); 224219820Sjeff 225219820Sjeff ret = osmv_txn_init_rmpp_receiver(h_bind, p_txn, FALSE 226219820Sjeff /*Send was initiated by me */ 227219820Sjeff ); 228219820Sjeff 229219820Sjeff if (IB_SUCCESS == ret) { 230219820Sjeff /* Send ACK on the 0 segment */ 231219820Sjeff ret = __osmv_rmpp_send_segment(h_bind, p_txn, 0); 232219820Sjeff } 233219820Sjeff } 234219820Sjeff 235219820Sjeffsend_done: 236219820Sjeff OSM_LOG_EXIT(p_bo->p_vendor->p_log); 237219820Sjeff return ret; 238219820Sjeff} 239219820Sjeff 240219820Sjeff/* 241219820Sjeff * NAME osmv_rmpp_send_ack 242219820Sjeff * 243219820Sjeff * DESCRIPTION 244219820Sjeff * 245219820Sjeff */ 246219820Sjeff 247219820Sjeffib_api_status_t 248219820Sjeffosmv_rmpp_send_ack(IN osm_bind_handle_t h_bind, 249219820Sjeff IN const ib_mad_t * p_req_mad, 250219820Sjeff IN uint32_t seg_num, 251219820Sjeff IN uint32_t nwl, IN const osm_mad_addr_t * p_mad_addr) 252219820Sjeff{ 253219820Sjeff uint8_t resp_mad[MAD_BLOCK_SIZE]; 254219820Sjeff ib_rmpp_mad_t *p_resp_mad = (ib_rmpp_mad_t *) resp_mad; 255219820Sjeff 256219820Sjeff#ifdef OSMV_RANDOM_DROP 257219820Sjeff if (TRUE == osmv_random_drop()) { 258219820Sjeff osm_log(((osmv_bind_obj_t *) h_bind)->p_vendor->p_log, 259219820Sjeff OSM_LOG_DEBUG, 260219820Sjeff "Error injection - dropping the RMPP ACK\n"); 261219820Sjeff return IB_SUCCESS; 262219820Sjeff } 263219820Sjeff#endif 264219820Sjeff 265219820Sjeff memcpy(p_resp_mad, p_req_mad, MAD_BLOCK_SIZE); 266219820Sjeff 267219820Sjeff p_resp_mad->common_hdr.method = osmv_invert_method(p_req_mad->method); 268219820Sjeff p_resp_mad->rmpp_type = IB_RMPP_TYPE_ACK; 269219820Sjeff p_resp_mad->seg_num = cl_hton32(seg_num); 270219820Sjeff p_resp_mad->paylen_newwin = cl_hton32(nwl); 271219820Sjeff p_resp_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; 272219820Sjeff 273219820Sjeff return osmv_transport_mad_send(h_bind, p_resp_mad, p_mad_addr); 274219820Sjeff} 275219820Sjeff 276219820Sjeff/* 277219820Sjeff * NAME osmv_rmpp_send_nak 278219820Sjeff * 279219820Sjeff * DESCRIPTION Send the RMPP ABORT or STOP packet 280219820Sjeff */ 281219820Sjeff 282219820Sjeffib_api_status_t 283219820Sjeffosmv_rmpp_send_nak(IN osm_bind_handle_t h_bind, 284219820Sjeff IN const ib_mad_t * p_req_mad, 285219820Sjeff IN const osm_mad_addr_t * p_mad_addr, 286219820Sjeff IN uint8_t nak_type, IN uint8_t status) 287219820Sjeff{ 288219820Sjeff uint8_t resp_mad[MAD_BLOCK_SIZE]; 289219820Sjeff ib_rmpp_mad_t *p_resp_mad = (ib_rmpp_mad_t *) resp_mad; 290219820Sjeff 291219820Sjeff memcpy(p_resp_mad, p_req_mad, MAD_BLOCK_SIZE); 292219820Sjeff 293219820Sjeff p_resp_mad->common_hdr.method = osmv_invert_method(p_req_mad->method); 294219820Sjeff p_resp_mad->rmpp_type = nak_type; 295219820Sjeff p_resp_mad->rmpp_status = status; 296219820Sjeff 297219820Sjeff return osmv_transport_mad_send(h_bind, p_resp_mad, p_mad_addr); 298219820Sjeff} 299219820Sjeff 300219820Sjeff/* 301219820Sjeff * NAME __osmv_rmpp_send_segment 302219820Sjeff * 303219820Sjeff * DESCRIPTION Build a MAD for a specific segment and send it 304219820Sjeff */ 305219820Sjeff 306219820Sjeffstatic ib_api_status_t 307219820Sjeff__osmv_rmpp_send_segment(IN osm_bind_handle_t h_bind, 308219820Sjeff IN osmv_txn_ctx_t * p_txn, IN uint32_t seg_num) 309219820Sjeff{ 310219820Sjeff ib_api_status_t ret; 311219820Sjeff osmv_rmpp_send_ctx_t *p_send_ctx; 312219820Sjeff uint8_t mad_buf[MAD_BLOCK_SIZE]; 313219820Sjeff ib_mad_t *p_mad = (ib_mad_t *) mad_buf; 314219820Sjeff osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 315219820Sjeff osm_mad_addr_t *p_mad_addr = 316219820Sjeff osm_madw_get_mad_addr_ptr(osmv_txn_get_madw(p_txn)); 317219820Sjeff uint32_t timeout = p_bo->p_vendor->resp_timeout; 318219820Sjeff uint64_t key; 319219820Sjeff 320219820Sjeff OSM_LOG_ENTER(p_bo->p_vendor->p_log); 321219820Sjeff 322219820Sjeff#ifdef OSMV_RANDOM_DROP 323219820Sjeff if (TRUE == osmv_random_drop()) { 324219820Sjeff 325219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 326219820Sjeff "Error injection - simulating the RMPP segment drop\n"); 327219820Sjeff return IB_SUCCESS; 328219820Sjeff } 329219820Sjeff#endif 330219820Sjeff 331219820Sjeff p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn); 332219820Sjeff key = osmv_txn_get_key(p_txn); 333219820Sjeff 334219820Sjeff if (0 != seg_num) { 335219820Sjeff ret = 336219820Sjeff osmv_rmpp_send_ctx_get_seg(p_send_ctx, seg_num, timeout, 337219820Sjeff p_mad); 338219820Sjeff CL_ASSERT(IB_SUCCESS == ret); 339219820Sjeff 340219820Sjeff /* Put the segment to the wire ! */ 341219820Sjeff p_mad->trans_id = cl_hton64(key); 342219820Sjeff 343219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 344219820Sjeff "Sending RMPP segment #%d, on-wire TID=0x%llX\n", 345219820Sjeff seg_num, p_mad->trans_id); 346219820Sjeff 347219820Sjeff /* 348219820Sjeff Add call for packet drop randomizer. 349219820Sjeff This is a testing feature. If run_randomizer flag is set to TRUE, 350219820Sjeff the randomizer will be called, and randomally will drop 351219820Sjeff a packet. This is used for simulating unstable fabric. 352219820Sjeff */ 353219820Sjeff if (p_bo->p_vendor->run_randomizer == TRUE) { 354219820Sjeff /* Try the randomizer */ 355219820Sjeff if (osm_pkt_randomizer_mad_drop(p_bo->p_vendor->p_log, 356219820Sjeff p_bo->p_vendor-> 357219820Sjeff p_pkt_randomizer, 358219820Sjeff p_mad) == TRUE) { 359219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 360219820Sjeff "The MAD will not be sent. \n"); 361219820Sjeff ret = IB_SUCCESS; 362219820Sjeff } else { 363219820Sjeff ret = 364219820Sjeff osmv_transport_mad_send((osm_bind_handle_t) 365219820Sjeff p_bo, p_mad, 366219820Sjeff p_mad_addr); 367219820Sjeff } 368219820Sjeff } else { 369219820Sjeff ret = 370219820Sjeff osmv_transport_mad_send((osm_bind_handle_t) p_bo, 371219820Sjeff p_mad, p_mad_addr); 372219820Sjeff } 373219820Sjeff } else { 374219820Sjeff /* This is an ACK for double-sided handshake. Give it a special treatment. */ 375219820Sjeff 376219820Sjeff /* It doesn't really matter which data to put. Only the header matters. */ 377219820Sjeff ret = osmv_rmpp_send_ctx_get_seg(p_send_ctx, 1, timeout, p_mad); 378219820Sjeff CL_ASSERT(IB_SUCCESS == ret); 379219820Sjeff 380219820Sjeff p_mad->trans_id = cl_hton64(key); 381219820Sjeff ret = 382219820Sjeff osmv_rmpp_send_ack((osm_bind_handle_t) p_bo, p_mad, 383219820Sjeff 0 /* segnum */ , 384219820Sjeff OSMV_RMPP_RECV_WIN /* NWL */ , 385219820Sjeff p_mad_addr); 386219820Sjeff } 387219820Sjeff 388219820Sjeff OSM_LOG_EXIT(p_bo->p_vendor->p_log); 389219820Sjeff return ret; 390219820Sjeff} 391