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 <sys/ioctl.h> 41219820Sjeff#include <stdlib.h> 42219820Sjeff#include <stddef.h> 43219820Sjeff#include <sys/types.h> 44219820Sjeff#include <sys/stat.h> 45219820Sjeff#include <fcntl.h> 46219820Sjeff#include <errno.h> 47219820Sjeff 48219820Sjeff#include <vendor/osm_vendor_mlx.h> 49219820Sjeff#include <vendor/osm_vendor_mlx_transport.h> 50219820Sjeff#include <vendor/osm_vendor_mlx_transport_anafa.h> 51219820Sjeff#include <vendor/osm_vendor_mlx_svc.h> 52219820Sjeff#include <vendor/osm_vendor_mlx_sender.h> 53219820Sjeff#include <vendor/osm_pkt_randomizer.h> 54219820Sjeff#include <vendor/osm_ts_useraccess.h> 55219820Sjeff 56219820Sjeff/** 57219820Sjeff * FORWARD REFERENCES 58219820Sjeff */ 59219820Sjeffstatic ib_api_status_t 60219820Sjeff__osmv_get_send_txn(IN osm_bind_handle_t h_bind, 61219820Sjeff IN osm_madw_t * const p_madw, 62219820Sjeff IN boolean_t is_rmpp, 63219820Sjeff IN boolean_t resp_expected, OUT osmv_txn_ctx_t ** pp_txn); 64219820Sjeff 65219820Sjeffstatic void __osm_vendor_internal_unbind(osm_bind_handle_t h_bind); 66219820Sjeff 67219820Sjeff/* 68219820Sjeff * NAME osm_vendor_new 69219820Sjeff * 70219820Sjeff * DESCRIPTION Create and Initialize the osm_vendor_t Object 71219820Sjeff */ 72219820Sjeff 73219820Sjeffosm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log, 74219820Sjeff IN const uint32_t timeout) 75219820Sjeff{ 76219820Sjeff ib_api_status_t status; 77219820Sjeff osm_vendor_t *p_vend; 78219820Sjeff 79219820Sjeff OSM_LOG_ENTER(p_log); 80219820Sjeff 81219820Sjeff CL_ASSERT(p_log); 82219820Sjeff 83219820Sjeff p_vend = malloc(sizeof(*p_vend)); 84219820Sjeff if (p_vend != NULL) { 85219820Sjeff memset(p_vend, 0, sizeof(*p_vend)); 86219820Sjeff status = osm_vendor_init(p_vend, p_log, timeout); 87219820Sjeff if (status != IB_SUCCESS) { 88219820Sjeff osm_vendor_delete(&p_vend); 89219820Sjeff } 90219820Sjeff } else { 91219820Sjeff osm_log(p_vend->p_log, OSM_LOG_ERROR, 92219820Sjeff "osm_vendor_new: ERR 7401: " 93219820Sjeff "Fail to allocate vendor object.\n"); 94219820Sjeff } 95219820Sjeff 96219820Sjeff OSM_LOG_EXIT(p_log); 97219820Sjeff return (p_vend); 98219820Sjeff} 99219820Sjeff 100219820Sjeff/* 101219820Sjeff * NAME osm_vendor_delete 102219820Sjeff * 103219820Sjeff * DESCRIPTION Delete all the binds behind the vendor + free the vendor object 104219820Sjeff */ 105219820Sjeff 106219820Sjeffvoid osm_vendor_delete(IN osm_vendor_t ** const pp_vend) 107219820Sjeff{ 108219820Sjeff cl_list_item_t *p_item; 109219820Sjeff cl_list_obj_t *p_obj; 110219820Sjeff osm_bind_handle_t bind_h; 111219820Sjeff osm_log_t *p_log; 112219820Sjeff 113219820Sjeff OSM_LOG_ENTER((*pp_vend)->p_log); 114219820Sjeff p_log = (*pp_vend)->p_log; 115219820Sjeff 116219820Sjeff /* go over the bind handles , unbind them and remove from list */ 117219820Sjeff /* Note that if we reached here due to problem in the init, then 118219820Sjeff the bind_handles list is not initialized yet */ 119219820Sjeff if ((*pp_vend)->bind_handles.state == CL_INITIALIZED) { 120219820Sjeff p_item = cl_qlist_remove_head(&((*pp_vend)->bind_handles)); 121219820Sjeff while (p_item != cl_qlist_end(&((*pp_vend)->bind_handles))) { 122219820Sjeff 123219820Sjeff p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); 124219820Sjeff bind_h = (osm_bind_handle_t *) cl_qlist_obj(p_obj); 125219820Sjeff osm_log(p_log, OSM_LOG_DEBUG, 126219820Sjeff "osm_vendor_delete: unbinding bind_h:%p \n", 127219820Sjeff bind_h); 128219820Sjeff 129219820Sjeff __osm_vendor_internal_unbind(bind_h); 130219820Sjeff 131219820Sjeff free(p_obj); 132219820Sjeff /* removing from list */ 133219820Sjeff p_item = 134219820Sjeff cl_qlist_remove_head(&((*pp_vend)->bind_handles)); 135219820Sjeff } 136219820Sjeff } 137219820Sjeff 138219820Sjeff if (NULL != ((*pp_vend)->p_transport_info)) { 139219820Sjeff free((*pp_vend)->p_transport_info); 140219820Sjeff (*pp_vend)->p_transport_info = NULL; 141219820Sjeff } 142219820Sjeff 143219820Sjeff /* remove the packet randomizer object */ 144219820Sjeff if ((*pp_vend)->run_randomizer == TRUE) 145219820Sjeff osm_pkt_randomizer_destroy(&((*pp_vend)->p_pkt_randomizer), 146219820Sjeff p_log); 147219820Sjeff 148219820Sjeff free(*pp_vend); 149219820Sjeff *pp_vend = NULL; 150219820Sjeff 151219820Sjeff OSM_LOG_EXIT(p_log); 152219820Sjeff} 153219820Sjeff 154219820Sjeff/* 155219820Sjeff * NAME osm_vendor_init 156219820Sjeff * 157219820Sjeff * DESCRIPTION Initialize the vendor object 158219820Sjeff */ 159219820Sjeff 160219820Sjeffib_api_status_t 161219820Sjeffosm_vendor_init(IN osm_vendor_t * const p_vend, 162219820Sjeff IN osm_log_t * const p_log, IN const uint32_t timeout) 163219820Sjeff{ 164219820Sjeff ib_api_status_t status = IB_SUCCESS; 165219820Sjeff char device_file[16]; 166219820Sjeff int device_fd; 167219820Sjeff 168219820Sjeff OSM_LOG_ENTER(p_log); 169219820Sjeff 170219820Sjeff p_vend->p_log = p_log; 171219820Sjeff p_vend->resp_timeout = timeout; 172219820Sjeff p_vend->ttime_timeout = timeout * OSMV_TXN_TIMEOUT_FACTOR; 173219820Sjeff 174219820Sjeff p_vend->p_transport_info = (osmv_TOPSPIN_ANAFA_transport_info_t *) 175219820Sjeff malloc(sizeof(osmv_TOPSPIN_ANAFA_transport_info_t)); 176219820Sjeff if (!p_vend->p_transport_info) { 177219820Sjeff return IB_ERROR; 178219820Sjeff } 179219820Sjeff 180219820Sjeff memset(p_vend->p_transport_info, 0, 181219820Sjeff sizeof(osmv_TOPSPIN_ANAFA_transport_info_t)); 182219820Sjeff 183219820Sjeff /* update the run_randomizer flag */ 184219820Sjeff if (getenv("OSM_PKT_DROP_RATE") != NULL 185219820Sjeff && atol(getenv("OSM_PKT_DROP_RATE")) != 0) { 186219820Sjeff /* if the OSM_PKT_DROP_RATE global variable is defined 187219820Sjeff to a non-zero value - 188219820Sjeff then the randomizer should be called. 189219820Sjeff Need to create the packet randomizer object */ 190219820Sjeff p_vend->run_randomizer = TRUE; 191219820Sjeff status = 192219820Sjeff osm_pkt_randomizer_init(&(p_vend->p_pkt_randomizer), p_log); 193219820Sjeff if (status != IB_SUCCESS) 194219820Sjeff return status; 195219820Sjeff } else { 196219820Sjeff p_vend->run_randomizer = FALSE; 197219820Sjeff p_vend->p_pkt_randomizer = NULL; 198219820Sjeff } 199219820Sjeff 200219820Sjeff /* open TopSpin file device */ 201219820Sjeff sprintf(device_file, "/dev/ts_ua0"); 202219820Sjeff device_fd = open("/dev/ts_ua0", O_RDWR); 203219820Sjeff if (device_fd < 0) { 204219820Sjeff fprintf(stderr, "Fatal: Fail to open the file:%s(%d)\n", 205219820Sjeff device_file, errno); 206219820Sjeff return IB_ERROR; 207219820Sjeff } 208219820Sjeff 209219820Sjeff ((osmv_TOPSPIN_ANAFA_transport_info_t *) p_vend->p_transport_info)-> 210219820Sjeff device_fd = device_fd; 211219820Sjeff 212219820Sjeff cl_qlist_init(&p_vend->bind_handles); 213219820Sjeff 214219820Sjeff OSM_LOG_EXIT(p_log); 215219820Sjeff return (IB_SUCCESS); 216219820Sjeff} 217219820Sjeff 218219820Sjeff/* 219219820Sjeff * NAME osm_vendor_bind 220219820Sjeff * 221219820Sjeff * DESCRIPTION Create a new bind object under the vendor object 222219820Sjeff */ 223219820Sjeff 224219820Sjeffosm_bind_handle_t 225219820Sjeffosm_vendor_bind(IN osm_vendor_t * const p_vend, 226219820Sjeff IN osm_bind_info_t * const p_bind_info, 227219820Sjeff IN osm_mad_pool_t * const p_mad_pool, 228219820Sjeff IN osm_vend_mad_recv_callback_t mad_recv_callback, 229219820Sjeff IN osm_vend_mad_send_err_callback_t send_err_callback, 230219820Sjeff IN void *context) 231219820Sjeff{ 232219820Sjeff osmv_bind_obj_t *p_bo; 233219820Sjeff cl_status_t cl_st; 234219820Sjeff cl_list_obj_t *p_obj; 235219820Sjeff uint8_t hca_idx = 0; 236219820Sjeff 237219820Sjeff if (NULL == p_vend || NULL == p_bind_info || NULL == p_mad_pool 238219820Sjeff || NULL == mad_recv_callback || NULL == send_err_callback) { 239219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 240219820Sjeff "osm_vendor_bind: ERR 7402: " 241219820Sjeff "NULL parameter passed in: p_vend=%p p_bind_info=%p p_mad_pool=%p recv_cb=%p send_err_cb=%p\n", 242219820Sjeff p_vend, p_bind_info, p_mad_pool, mad_recv_callback, 243219820Sjeff send_err_callback); 244219820Sjeff 245219820Sjeff return OSM_BIND_INVALID_HANDLE; 246219820Sjeff } 247219820Sjeff 248219820Sjeff p_bo = malloc(sizeof(osmv_bind_obj_t)); 249219820Sjeff if (NULL == p_bo) { 250219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 251219820Sjeff "osm_vendor_bind: ERR 7403: " 252219820Sjeff "could not allocate the bind object\n"); 253219820Sjeff return OSM_BIND_INVALID_HANDLE; 254219820Sjeff } 255219820Sjeff 256219820Sjeff memset(p_bo, 0, sizeof(osmv_bind_obj_t)); 257219820Sjeff p_bo->p_vendor = p_vend; 258219820Sjeff p_bo->recv_cb = mad_recv_callback; 259219820Sjeff p_bo->send_err_cb = send_err_callback; 260219820Sjeff p_bo->cb_context = context; 261219820Sjeff p_bo->p_osm_pool = p_mad_pool; 262219820Sjeff p_bo->port_num = 1; /* anafa2 has one port */ 263219820Sjeff p_bo->hca_hndl = 0; /* only one ca on anafa system */ 264219820Sjeff 265219820Sjeff /* obtain the hca name and port num from the guid */ 266219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 267219820Sjeff "osm_vendor_bind: " 268219820Sjeff "Finding CA and Port that owns port guid 0x%" PRIx64 ".\n", 269219820Sjeff cl_ntoh64(p_bind_info->port_guid)); 270219820Sjeff 271219820Sjeff p_bo->is_closing = FALSE; 272219820Sjeff cl_spinlock_construct(&(p_bo->lock)); 273219820Sjeff cl_st = cl_spinlock_init(&(p_bo->lock)); 274219820Sjeff if (cl_st != CL_SUCCESS) { 275219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 276219820Sjeff "osm_vendor_bind: ERR 7405: " 277219820Sjeff "could not initialize the spinlock ...\n"); 278219820Sjeff free(p_bo); 279219820Sjeff return OSM_BIND_INVALID_HANDLE; 280219820Sjeff } 281219820Sjeff 282219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, 283219820Sjeff "osm_vendor_bind: osmv_txnmgr_init ... \n"); 284219820Sjeff if (osmv_txnmgr_init(&p_bo->txn_mgr, p_vend->p_log, &(p_bo->lock)) != 285219820Sjeff IB_SUCCESS) { 286219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 287219820Sjeff "osm_vendor_bind: ERR 7406: " 288219820Sjeff "osmv_txnmgr_init failed \n"); 289219820Sjeff cl_spinlock_destroy(&p_bo->lock); 290219820Sjeff free(p_bo); 291219820Sjeff return OSM_BIND_INVALID_HANDLE; 292219820Sjeff } 293219820Sjeff 294219820Sjeff /* Do the real job! (Transport-dependent) */ 295219820Sjeff if (IB_SUCCESS != 296219820Sjeff osmv_transport_init(p_bind_info, OSMV_ANAFA_ID, hca_idx, p_bo)) { 297219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 298219820Sjeff "osm_vendor_bind: ERR 7407: " 299219820Sjeff "osmv_transport_init failed \n"); 300219820Sjeff osmv_txnmgr_done((osm_bind_handle_t) p_bo); 301219820Sjeff cl_spinlock_destroy(&p_bo->lock); 302219820Sjeff free(p_bo); 303219820Sjeff return OSM_BIND_INVALID_HANDLE; 304219820Sjeff } 305219820Sjeff 306219820Sjeff /* insert bind handle into db */ 307219820Sjeff p_obj = malloc(sizeof(cl_list_obj_t)); 308219820Sjeff if (NULL == p_obj) { 309219820Sjeff 310219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 311219820Sjeff "osm_vendor_bind: ERR 7408: " 312219820Sjeff "osm_vendor_bind: could not allocate the list object\n"); 313219820Sjeff 314219820Sjeff osmv_transport_done(p_bo->p_transp_mgr); 315219820Sjeff osmv_txnmgr_done((osm_bind_handle_t) p_bo); 316219820Sjeff cl_spinlock_destroy(&p_bo->lock); 317219820Sjeff free(p_bo); 318219820Sjeff return OSM_BIND_INVALID_HANDLE; 319219820Sjeff } 320219820Sjeff if (p_obj) 321219820Sjeff memset(p_obj, 0, sizeof(cl_list_obj_t)); 322219820Sjeff cl_qlist_set_obj(p_obj, p_bo); 323219820Sjeff 324219820Sjeff cl_qlist_insert_head(&p_vend->bind_handles, &p_obj->list_item); 325219820Sjeff 326219820Sjeff return (osm_bind_handle_t) p_bo; 327219820Sjeff} 328219820Sjeff 329219820Sjeff/* 330219820Sjeff * NAME osm_vendor_unbind 331219820Sjeff * 332219820Sjeff * DESCRIPTION Destroy the bind object and remove it from the vendor's list 333219820Sjeff */ 334219820Sjeff 335219820Sjeffvoid osm_vendor_unbind(IN osm_bind_handle_t h_bind) 336219820Sjeff{ 337219820Sjeff osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 338219820Sjeff osm_log_t *p_log = p_bo->p_vendor->p_log; 339219820Sjeff cl_list_obj_t *p_obj; 340219820Sjeff cl_list_item_t *p_item, *p_item_tmp; 341219820Sjeff cl_qlist_t *const p_bh_list = 342219820Sjeff (cl_qlist_t * const)&p_bo->p_vendor->bind_handles; 343219820Sjeff 344219820Sjeff OSM_LOG_ENTER(p_log); 345219820Sjeff 346219820Sjeff /* go over all the items in the list and remove the specific item */ 347219820Sjeff p_item = cl_qlist_head(&p_bo->p_vendor->bind_handles); 348219820Sjeff while (p_item != cl_qlist_end(&p_bo->p_vendor->bind_handles)) { 349219820Sjeff p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); 350219820Sjeff if (cl_qlist_obj(p_obj) == h_bind) { 351219820Sjeff break; 352219820Sjeff } 353219820Sjeff p_item_tmp = cl_qlist_next(p_item); 354219820Sjeff p_item = p_item_tmp; 355219820Sjeff } 356219820Sjeff 357219820Sjeff CL_ASSERT(p_item != cl_qlist_end(p_bh_list)); 358219820Sjeff 359219820Sjeff cl_qlist_remove_item(p_bh_list, p_item); 360219820Sjeff free(p_obj); 361219820Sjeff 362219820Sjeff __osm_vendor_internal_unbind(h_bind); 363219820Sjeff 364219820Sjeff OSM_LOG_EXIT(p_bo->p_vendor->p_log); 365219820Sjeff} 366219820Sjeff 367219820Sjeff/* 368219820Sjeff * NAME osm_vendor_get 369219820Sjeff * 370219820Sjeff * DESCRIPTION Allocate the space for a new MAD 371219820Sjeff */ 372219820Sjeff 373219820Sjeffib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind, 374219820Sjeff IN const uint32_t mad_size, 375219820Sjeff IN osm_vend_wrap_t * const p_vw) 376219820Sjeff{ 377219820Sjeff ib_mad_t *p_mad; 378219820Sjeff osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 379219820Sjeff osm_vendor_t const *p_vend = p_bo->p_vendor; 380219820Sjeff uint32_t act_mad_size; 381219820Sjeff 382219820Sjeff OSM_LOG_ENTER(p_vend->p_log); 383219820Sjeff 384219820Sjeff CL_ASSERT(p_vw); 385219820Sjeff 386219820Sjeff if (mad_size < MAD_BLOCK_SIZE) { 387219820Sjeff /* Stupid, but the applications want that! */ 388219820Sjeff act_mad_size = MAD_BLOCK_SIZE; 389219820Sjeff } else { 390219820Sjeff act_mad_size = mad_size; 391219820Sjeff } 392219820Sjeff 393219820Sjeff /* allocate it */ 394219820Sjeff p_mad = (ib_mad_t *) malloc(act_mad_size); 395219820Sjeff if (p_mad == NULL) { 396219820Sjeff osm_log(p_vend->p_log, OSM_LOG_ERROR, 397219820Sjeff "osm_vendor_get: ERR 7409: " 398219820Sjeff "Error Obtaining MAD buffer.\n"); 399219820Sjeff goto Exit; 400219820Sjeff } 401219820Sjeff 402219820Sjeff memset(p_mad, 0, act_mad_size); 403219820Sjeff 404219820Sjeff if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) { 405219820Sjeff osm_log(p_vend->p_log, OSM_LOG_DEBUG, 406219820Sjeff "osm_vendor_get: " 407219820Sjeff "Allocated MAD %p, size = %u.\n", p_mad, act_mad_size); 408219820Sjeff } 409219820Sjeff p_vw->p_mad = p_mad; 410219820Sjeff 411219820SjeffExit: 412219820Sjeff OSM_LOG_EXIT(p_vend->p_log); 413219820Sjeff return (p_mad); 414219820Sjeff} 415219820Sjeff 416219820Sjeff/* 417219820Sjeff * NAME osm_vendor_send 418219820Sjeff * 419219820Sjeff * DESCRIPTION Send a MAD buffer (RMPP or simple send). 420219820Sjeff * 421219820Sjeff * Semantics: 422219820Sjeff * (1) The RMPP send completes when every segment 423219820Sjeff * is acknowledged (synchronous) 424219820Sjeff * (2) The simple send completes when the send completion 425219820Sjeff * is received (asynchronous) 426219820Sjeff */ 427219820Sjeff 428219820Sjeffib_api_status_t 429219820Sjeffosm_vendor_send(IN osm_bind_handle_t h_bind, 430219820Sjeff IN osm_madw_t * const p_madw, IN boolean_t const resp_expected) 431219820Sjeff{ 432219820Sjeff ib_api_status_t ret = IB_SUCCESS; 433219820Sjeff osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 434219820Sjeff boolean_t is_rmpp = FALSE, is_rmpp_ds = FALSE; 435219820Sjeff osmv_txn_ctx_t *p_txn = NULL; 436219820Sjeff ib_mad_t *p_mad; 437219820Sjeff 438219820Sjeff OSM_LOG_ENTER(p_bo->p_vendor->p_log); 439219820Sjeff 440219820Sjeff if (NULL == h_bind || NULL == p_madw || 441219820Sjeff NULL == (p_mad = osm_madw_get_mad_ptr(p_madw)) || 442219820Sjeff NULL == osm_madw_get_mad_addr_ptr(p_madw)) { 443219820Sjeff 444219820Sjeff return IB_INVALID_PARAMETER; 445219820Sjeff } 446219820Sjeff 447219820Sjeff is_rmpp = (p_madw->mad_size > MAD_BLOCK_SIZE 448219820Sjeff || osmv_mad_is_rmpp(p_mad)); 449219820Sjeff is_rmpp_ds = (TRUE == is_rmpp && TRUE == resp_expected); 450219820Sjeff 451219820Sjeff /* Make our operations with the send context atomic */ 452219820Sjeff osmv_txn_lock(p_bo); 453219820Sjeff 454219820Sjeff if (TRUE == p_bo->is_closing) { 455219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 456219820Sjeff "osm_vendor_send: ERR 7410: " 457219820Sjeff "The handle %p is being unbound, cannot send.\n", 458219820Sjeff h_bind); 459219820Sjeff ret = IB_INTERRUPTED; 460219820Sjeff goto send_done; 461219820Sjeff } 462219820Sjeff 463219820Sjeff if (TRUE == resp_expected || TRUE == is_rmpp) { 464219820Sjeff 465219820Sjeff /* We must run under a transaction framework. 466219820Sjeff * Get the transaction object (old or new) */ 467219820Sjeff ret = __osmv_get_send_txn(h_bind, p_madw, is_rmpp, 468219820Sjeff resp_expected, &p_txn); 469219820Sjeff if (IB_SUCCESS != ret) { 470219820Sjeff goto send_done; 471219820Sjeff } 472219820Sjeff } 473219820Sjeff 474219820Sjeff if (TRUE == is_rmpp) { 475219820Sjeff /* Do the job - RMPP! 476219820Sjeff * The call returns as all the packets are ACK'ed/upon error 477219820Sjeff * The txn lock will be released each time the function sleeps 478219820Sjeff * and re-acquired when it wakes up 479219820Sjeff */ 480219820Sjeff ret = osmv_rmpp_send_madw(h_bind, p_madw, p_txn, is_rmpp_ds); 481219820Sjeff } else { 482219820Sjeff 483219820Sjeff /* Do the job - single MAD! 484219820Sjeff * The call returns as soon as the MAD is put on the wire 485219820Sjeff */ 486219820Sjeff ret = osmv_simple_send_madw(h_bind, p_madw, p_txn, FALSE); /* anafa2 */ 487219820Sjeff } 488219820Sjeff 489219820Sjeff if (IB_SUCCESS == ret) { 490219820Sjeff 491219820Sjeff if ((TRUE == is_rmpp) && (FALSE == is_rmpp_ds)) { 492219820Sjeff /* For double-sided sends, the txn continues to live */ 493219820Sjeff osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), 494219820Sjeff FALSE /*not in callback */ ); 495219820Sjeff } 496219820Sjeff 497219820Sjeff if (FALSE == resp_expected) { 498219820Sjeff osm_mad_pool_put(p_bo->p_osm_pool, p_madw); 499219820Sjeff } 500219820Sjeff } else { 501219820Sjeff if (NULL != p_txn) { 502219820Sjeff osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), 503219820Sjeff FALSE /*not in callback */ ); 504219820Sjeff } 505219820Sjeff 506219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 507219820Sjeff "osm_vendor_send: ERR 7411: failed to send MADW %p\n", 508219820Sjeff p_madw); 509219820Sjeff 510219820Sjeff if (TRUE == resp_expected) { 511219820Sjeff /* Change the status on the p_madw */ 512219820Sjeff p_madw->status = ret; 513219820Sjeff /* Only the requester expects the error callback */ 514219820Sjeff p_bo->send_err_cb(p_bo->cb_context, p_madw); 515219820Sjeff } else { 516219820Sjeff /* put back the mad - it is useless ... */ 517219820Sjeff osm_mad_pool_put(p_bo->p_osm_pool, p_madw); 518219820Sjeff } 519219820Sjeff } 520219820Sjeff 521219820Sjeffsend_done: 522219820Sjeff 523219820Sjeff osmv_txn_unlock(p_bo); 524219820Sjeff 525219820Sjeff OSM_LOG_EXIT(p_bo->p_vendor->p_log); 526219820Sjeff return ret; 527219820Sjeff} 528219820Sjeff 529219820Sjeff/* 530219820Sjeff * NAME osm_vendor_put 531219820Sjeff * 532219820Sjeff * DESCRIPTION Free the MAD's memory 533219820Sjeff */ 534219820Sjeff 535219820Sjeffvoid 536219820Sjeffosm_vendor_put(IN osm_bind_handle_t h_bind, IN osm_vend_wrap_t * const p_vw) 537219820Sjeff{ 538219820Sjeff 539219820Sjeff osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 540219820Sjeff osm_vendor_t const *p_vend = p_bo->p_vendor; 541219820Sjeff 542219820Sjeff OSM_LOG_ENTER(p_vend->p_log); 543219820Sjeff 544219820Sjeff CL_ASSERT(p_vw); 545219820Sjeff CL_ASSERT(p_vw->p_mad); 546219820Sjeff 547219820Sjeff if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) { 548219820Sjeff osm_log(p_vend->p_log, OSM_LOG_DEBUG, 549219820Sjeff "osm_vendor_put: " "Retiring MAD %p.\n", p_vw->p_mad); 550219820Sjeff } 551219820Sjeff 552219820Sjeff free(p_vw->p_mad); 553219820Sjeff p_vw->p_mad = NULL; 554219820Sjeff 555219820Sjeff OSM_LOG_EXIT(p_vend->p_log); 556219820Sjeff} 557219820Sjeff 558219820Sjeff/* 559219820Sjeff * NAME osm_vendor_local_lid_change 560219820Sjeff * 561219820Sjeff * DESCRIPTION Notifies the vendor transport layer that the local address 562219820Sjeff * has changed. This allows the vendor layer to perform 563219820Sjeff * housekeeping functions such as address vector updates. 564219820Sjeff */ 565219820Sjeff 566219820Sjeffib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind) 567219820Sjeff{ 568219820Sjeff osm_vendor_t const *p_vend = ((osmv_bind_obj_t *) h_bind)->p_vendor; 569219820Sjeff OSM_LOG_ENTER(p_vend->p_log); 570219820Sjeff 571219820Sjeff osm_log(p_vend->p_log, OSM_LOG_DEBUG, 572219820Sjeff "osm_vendor_local_lid_change: " "Change of LID.\n"); 573219820Sjeff 574219820Sjeff OSM_LOG_EXIT(p_vend->p_log); 575219820Sjeff 576219820Sjeff return (IB_SUCCESS); 577219820Sjeff 578219820Sjeff} 579219820Sjeff 580219820Sjeff/* 581219820Sjeff * NAME osm_vendor_set_sm 582219820Sjeff * 583219820Sjeff * DESCRIPTION Modifies the port info for the bound port to set the "IS_SM" bit. 584219820Sjeff */ 585219820Sjeff 586219820Sjeffvoid osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val) 587219820Sjeff{ 588219820Sjeff osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 589219820Sjeff osm_vendor_t const *p_vend = p_bo->p_vendor; 590219820Sjeff osmv_TOPSPIN_ANAFA_transport_mgr_t *p_mgr; 591219820Sjeff int ioctl_ret; 592219820Sjeff osm_ts_set_port_info_ioctl port_info; 593219820Sjeff 594219820Sjeff OSM_LOG_ENTER(p_vend->p_log); 595219820Sjeff 596219820Sjeff port_info.port = 0; /* anafa has only 1 port */ 597219820Sjeff port_info.port_info.valid_fields = IB_PORT_IS_SM; 598219820Sjeff port_info.port_info.is_sm = is_sm_val; 599219820Sjeff 600219820Sjeff p_mgr = (osmv_TOPSPIN_ANAFA_transport_mgr_t *) p_bo->p_transp_mgr; 601219820Sjeff ioctl_ret = ioctl(p_mgr->device_fd, TS_IB_IOCSPORTINFO, &port_info); 602219820Sjeff 603219820Sjeff if (ioctl_ret < 0) { 604219820Sjeff osm_log(p_vend->p_log, OSM_LOG_ERROR, 605219820Sjeff "osm_vendor_set_sm: ERR 7412: " 606219820Sjeff "Unable set 'IS_SM' bit to:%u in port attributes (%d). errno=%d\n", 607219820Sjeff is_sm_val, ioctl_ret, errno); 608219820Sjeff } 609219820Sjeff 610219820Sjeff OSM_LOG_EXIT(p_vend->p_log); 611219820Sjeff} 612219820Sjeff 613219820Sjeff/* 614219820Sjeff * NAME __osm_vendor_internal_unbind 615219820Sjeff * 616219820Sjeff * DESCRIPTION Destroying a bind: 617219820Sjeff * (1) Wait for the completion of the sends in flight 618219820Sjeff * (2) Destroy the associated data structures 619219820Sjeff */ 620219820Sjeff 621219820Sjeffstatic void __osm_vendor_internal_unbind(osm_bind_handle_t h_bind) 622219820Sjeff{ 623219820Sjeff osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 624219820Sjeff osm_log_t *p_log = p_bo->p_vendor->p_log; 625219820Sjeff 626219820Sjeff OSM_LOG_ENTER(p_log); 627219820Sjeff 628219820Sjeff /* "notifying" all that from now on no new sends can be done */ 629219820Sjeff p_bo->txn_mgr.p_event_wheel->closing = TRUE; 630219820Sjeff 631219820Sjeff osmv_txn_lock(p_bo); 632219820Sjeff p_bo->is_closing = TRUE; 633219820Sjeff 634219820Sjeff /* notifying all sleeping rmpp sends to exit */ 635219820Sjeff osmv_txn_abort_rmpp_txns(h_bind); 636219820Sjeff 637219820Sjeff /* frees all data in bind handle */ 638219820Sjeff osm_log(p_log, OSM_LOG_DEBUG, 639219820Sjeff "__osm_vendor_internal_unbind: destroying transport mgr.. \n"); 640219820Sjeff osmv_txn_unlock(p_bo); 641219820Sjeff 642219820Sjeff osmv_transport_done(h_bind); 643219820Sjeff osm_log(p_log, OSM_LOG_DEBUG, 644219820Sjeff "__osm_vendor_internal_unbind: destroying txn mgr.. \n"); 645219820Sjeff osmv_txn_lock(p_bo); 646219820Sjeff osmv_txnmgr_done(h_bind); 647219820Sjeff osm_log(p_log, OSM_LOG_DEBUG, 648219820Sjeff "__osm_vendor_internal_unbind: destroying bind lock.. \n"); 649219820Sjeff 650219820Sjeff osmv_txn_unlock(p_bo); 651219820Sjeff /* 652219820Sjeff we intentionally let the p_bo and its lock leak - 653219820Sjeff as we did not implement a way to track active bind handles provided to 654219820Sjeff the client - and the client might use them 655219820Sjeff 656219820Sjeff cl_spinlock_destroy(&p_bo->lock); 657219820Sjeff free(p_bo); 658219820Sjeff */ 659219820Sjeff 660219820Sjeff OSM_LOG_EXIT(p_log); 661219820Sjeff} 662219820Sjeff 663219820Sjeff/* 664219820Sjeff * NAME __osmv_get_send_txn 665219820Sjeff * 666219820Sjeff * DESCRIPTION Return a transaction object that corresponds to this MAD. 667219820Sjeff * Optionally, create it, if the new request (query) is sent or received. 668219820Sjeff */ 669219820Sjeff 670219820Sjeffstatic ib_api_status_t 671219820Sjeff__osmv_get_send_txn(IN osm_bind_handle_t h_bind, 672219820Sjeff IN osm_madw_t * const p_madw, 673219820Sjeff IN boolean_t is_rmpp, 674219820Sjeff IN boolean_t resp_expected, OUT osmv_txn_ctx_t ** pp_txn) 675219820Sjeff{ 676219820Sjeff ib_api_status_t ret; 677219820Sjeff uint64_t tid, key; 678219820Sjeff osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; 679219820Sjeff ib_mad_t *p_mad = osm_madw_get_mad_ptr(p_madw); 680219820Sjeff 681219820Sjeff OSM_LOG_ENTER(p_bo->p_vendor->p_log); 682219820Sjeff CL_ASSERT(NULL != pp_txn); 683219820Sjeff 684219820Sjeff key = tid = cl_ntoh64(p_mad->trans_id); 685219820Sjeff if (TRUE == resp_expected) { 686219820Sjeff /* Create a unique identifier at the requester side */ 687219820Sjeff key = osmv_txn_uniq_key(tid); 688219820Sjeff } 689219820Sjeff 690219820Sjeff /* We must run under a transaction framework */ 691219820Sjeff ret = osmv_txn_lookup(h_bind, key, pp_txn); 692219820Sjeff if (IB_NOT_FOUND == ret) { 693219820Sjeff /* Generally, we start a new transaction */ 694219820Sjeff ret = osmv_txn_init(h_bind, tid, key, pp_txn); 695219820Sjeff if (IB_SUCCESS != ret) { 696219820Sjeff goto get_send_txn_done; 697219820Sjeff } 698219820Sjeff } else { 699219820Sjeff CL_ASSERT(NULL != *pp_txn); 700219820Sjeff /* The transaction context exists. 701219820Sjeff * This is legal only if I am going to return an 702219820Sjeff * (RMPP?) reply to an RMPP request sent by the other part 703219820Sjeff * (double-sided RMPP transfer) 704219820Sjeff */ 705219820Sjeff if (FALSE == is_rmpp 706219820Sjeff || FALSE == osmv_txn_is_rmpp_init_by_peer(*pp_txn)) { 707219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 708219820Sjeff "__osmv_get_send_txn: ERR 7413: " 709219820Sjeff "The transaction id=0x%llX is not unique. Send failed.\n", 710219820Sjeff tid); 711219820Sjeff 712219820Sjeff ret = IB_INVALID_SETTING; 713219820Sjeff goto get_send_txn_done; 714219820Sjeff } 715219820Sjeff 716219820Sjeff if (TRUE == resp_expected) { 717219820Sjeff osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, 718219820Sjeff "__osmv_get_send_txn: ERR 7414: " 719219820Sjeff "The transaction id=%llX can\'t expect a response. Send failed.\n", 720219820Sjeff tid); 721219820Sjeff 722219820Sjeff ret = IB_INVALID_PARAMETER; 723219820Sjeff goto get_send_txn_done; 724219820Sjeff } 725219820Sjeff } 726219820Sjeff 727219820Sjeff if (TRUE == is_rmpp) { 728219820Sjeff ret = osmv_txn_init_rmpp_sender(h_bind, *pp_txn, p_madw); 729219820Sjeff if (IB_SUCCESS != ret) { 730219820Sjeff osmv_txn_done(h_bind, tid, FALSE); 731219820Sjeff goto get_send_txn_done; 732219820Sjeff } 733219820Sjeff } 734219820Sjeff 735219820Sjeff /* Save a reference to the MAD in the txn context 736219820Sjeff * We'll need to match it in two cases: 737219820Sjeff * (1) When the response is returned, if I am the requester 738219820Sjeff * (2) In RMPP retransmissions 739219820Sjeff */ 740219820Sjeff osmv_txn_set_madw(*pp_txn, p_madw); 741219820Sjeff 742219820Sjeffget_send_txn_done: 743219820Sjeff OSM_LOG_EXIT(p_bo->p_vendor->p_log); 744219820Sjeff 745219820Sjeff return ret; 746219820Sjeff} 747219820Sjeff 748219820Sjeff/********************************************************************** 749219820Sjeff **********************************************************************/ 750219820Sjeffvoid osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level) 751219820Sjeff{ 752219820Sjeff 753219820Sjeff} 754