1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2008 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/* 37219820Sjeff * Abstract: 38219820Sjeff * Implementation of osm_vendor_t (for umad). 39219820Sjeff * This object represents the OpenIB vendor layer. 40219820Sjeff * This object is part of the opensm family of objects. 41219820Sjeff * 42219820Sjeff * Environment: 43219820Sjeff * Linux User Mode 44219820Sjeff * 45219820Sjeff */ 46219820Sjeff 47219820Sjeff#if HAVE_CONFIG_H 48219820Sjeff# include <config.h> 49219820Sjeff#endif /* HAVE_CONFIG_H */ 50219820Sjeff 51219820Sjeff#ifdef OSM_VENDOR_INTF_OPENIB 52219820Sjeff 53219820Sjeff#include <unistd.h> 54219820Sjeff#include <stdlib.h> 55219820Sjeff#include <fcntl.h> 56219820Sjeff#include <errno.h> 57219820Sjeff 58219820Sjeff#include <iba/ib_types.h> 59219820Sjeff#include <complib/cl_qlist.h> 60219820Sjeff#include <complib/cl_math.h> 61219820Sjeff#include <complib/cl_debug.h> 62219820Sjeff#include <opensm/osm_madw.h> 63219820Sjeff#include <opensm/osm_log.h> 64219820Sjeff#include <opensm/osm_mad_pool.h> 65219820Sjeff#include <opensm/osm_helper.h> 66219820Sjeff#include <vendor/osm_vendor_api.h> 67219820Sjeff 68219820Sjeff/****s* OpenSM: Vendor UMAD/osm_umad_bind_info_t 69219820Sjeff * NAME 70219820Sjeff * osm_umad_bind_info_t 71219820Sjeff * 72219820Sjeff * DESCRIPTION 73219820Sjeff * Structure containing bind information. 74219820Sjeff * 75219820Sjeff * SYNOPSIS 76219820Sjeff */ 77219820Sjefftypedef struct _osm_umad_bind_info { 78219820Sjeff osm_vendor_t *p_vend; 79219820Sjeff void *client_context; 80219820Sjeff osm_mad_pool_t *p_mad_pool; 81219820Sjeff osm_vend_mad_recv_callback_t mad_recv_callback; 82219820Sjeff osm_vend_mad_send_err_callback_t send_err_callback; 83219820Sjeff ib_net64_t port_guid; 84219820Sjeff int port_id; 85219820Sjeff int agent_id; 86219820Sjeff int agent_id1; /* SMI requires two agents */ 87219820Sjeff} osm_umad_bind_info_t; 88219820Sjeff 89219820Sjefftypedef struct _umad_receiver { 90219820Sjeff pthread_t tid; 91219820Sjeff osm_vendor_t *p_vend; 92219820Sjeff osm_log_t *p_log; 93219820Sjeff} umad_receiver_t; 94219820Sjeff 95219820Sjeffstatic void osm_vendor_close_port(osm_vendor_t * const p_vend); 96219820Sjeff 97219820Sjeffstatic void clear_madw(osm_vendor_t * p_vend) 98219820Sjeff{ 99219820Sjeff umad_match_t *m, *e, *old_m; 100219820Sjeff ib_net64_t old_tid; 101219820Sjeff 102219820Sjeff OSM_LOG_ENTER(p_vend->p_log); 103219820Sjeff pthread_mutex_lock(&p_vend->match_tbl_mutex); 104219820Sjeff for (m = p_vend->mtbl.tbl, e = m + p_vend->mtbl.max; m < e; m++) { 105219820Sjeff if (m->tid) { 106219820Sjeff old_m = m; 107219820Sjeff old_tid = m->tid; 108219820Sjeff m->tid = 0; 109219820Sjeff osm_mad_pool_put(((osm_umad_bind_info_t 110219820Sjeff *) ((osm_madw_t *) m->v)->h_bind)-> 111219820Sjeff p_mad_pool, m->v); 112219820Sjeff pthread_mutex_unlock(&p_vend->match_tbl_mutex); 113219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5401: " 114219820Sjeff "evicting entry %p (tid was 0x%" PRIx64 ")\n", 115219820Sjeff old_m, old_tid); 116219820Sjeff goto Exit; 117219820Sjeff } 118219820Sjeff } 119219820Sjeff pthread_mutex_unlock(&p_vend->match_tbl_mutex); 120219820Sjeff 121219820SjeffExit: 122219820Sjeff OSM_LOG_EXIT(p_vend->p_log); 123219820Sjeff} 124219820Sjeff 125219820Sjeffstatic osm_madw_t *get_madw(osm_vendor_t * p_vend, ib_net64_t * tid) 126219820Sjeff{ 127219820Sjeff umad_match_t *m, *e; 128219820Sjeff ib_net64_t mtid = (*tid & CL_HTON64(0x00000000ffffffffllu)); 129219820Sjeff osm_madw_t *res; 130219820Sjeff 131219820Sjeff /* 132219820Sjeff * Since mtid == 0 is the empty key, we should not 133219820Sjeff * waste time looking for it 134219820Sjeff */ 135219820Sjeff if (mtid == 0) 136219820Sjeff return 0; 137219820Sjeff 138219820Sjeff pthread_mutex_lock(&p_vend->match_tbl_mutex); 139219820Sjeff for (m = p_vend->mtbl.tbl, e = m + p_vend->mtbl.max; m < e; m++) { 140219820Sjeff if (m->tid == mtid) { 141219820Sjeff m->tid = 0; 142219820Sjeff *tid = mtid; 143219820Sjeff res = m->v; 144219820Sjeff pthread_mutex_unlock(&p_vend->match_tbl_mutex); 145219820Sjeff return res; 146219820Sjeff } 147219820Sjeff } 148219820Sjeff 149219820Sjeff pthread_mutex_unlock(&p_vend->match_tbl_mutex); 150219820Sjeff return 0; 151219820Sjeff} 152219820Sjeff 153219820Sjeffstatic void 154219820Sjeffput_madw(osm_vendor_t * p_vend, osm_madw_t * p_madw, ib_net64_t tid) 155219820Sjeff{ 156219820Sjeff umad_match_t *m, *e, *old_lru, *lru = 0; 157219820Sjeff osm_madw_t *p_req_madw; 158219820Sjeff osm_umad_bind_info_t *p_bind; 159219820Sjeff ib_net64_t old_tid; 160219820Sjeff uint32_t oldest = ~0; 161219820Sjeff 162219820Sjeff pthread_mutex_lock(&p_vend->match_tbl_mutex); 163219820Sjeff for (m = p_vend->mtbl.tbl, e = m + p_vend->mtbl.max; m < e; m++) { 164219820Sjeff if (m->tid == 0) { 165219820Sjeff m->tid = tid; 166219820Sjeff m->v = p_madw; 167219820Sjeff m->version = 168219820Sjeff cl_atomic_inc((atomic32_t *) & p_vend->mtbl. 169219820Sjeff last_version); 170219820Sjeff pthread_mutex_unlock(&p_vend->match_tbl_mutex); 171219820Sjeff return; 172219820Sjeff } 173219820Sjeff if (oldest > m->version) { 174219820Sjeff oldest = m->version; 175219820Sjeff lru = m; 176219820Sjeff } 177219820Sjeff } 178219820Sjeff 179219820Sjeff old_lru = lru; 180219820Sjeff old_tid = lru->tid; 181219820Sjeff p_req_madw = old_lru->v; 182219820Sjeff p_bind = p_req_madw->h_bind; 183219820Sjeff p_req_madw->status = IB_CANCELED; 184219820Sjeff pthread_mutex_lock(&p_vend->cb_mutex); 185219820Sjeff (*p_bind->send_err_callback) (p_bind->client_context, p_req_madw); 186219820Sjeff pthread_mutex_unlock(&p_vend->cb_mutex); 187219820Sjeff lru->tid = tid; 188219820Sjeff lru->v = p_madw; 189219820Sjeff lru->version = 190219820Sjeff cl_atomic_inc((atomic32_t *) & p_vend->mtbl.last_version); 191219820Sjeff pthread_mutex_unlock(&p_vend->match_tbl_mutex); 192219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5402: " 193219820Sjeff "evicting entry %p (tid was 0x%" PRIx64 ")\n", old_lru, 194219820Sjeff cl_ntoh64(old_tid)); 195219820Sjeff} 196219820Sjeff 197219820Sjeffstatic void 198219820Sjeffib_mad_addr_conv(ib_user_mad_t * umad, osm_mad_addr_t * osm_mad_addr, 199219820Sjeff int is_smi) 200219820Sjeff{ 201219820Sjeff ib_mad_addr_t *ib_mad_addr = umad_get_mad_addr(umad); 202219820Sjeff osm_mad_addr->dest_lid = ib_mad_addr->lid; 203219820Sjeff osm_mad_addr->path_bits = ib_mad_addr->path_bits; 204219820Sjeff osm_mad_addr->static_rate = 0; 205219820Sjeff 206219820Sjeff if (is_smi) { 207219820Sjeff osm_mad_addr->addr_type.smi.source_lid = osm_mad_addr->dest_lid; 208219820Sjeff osm_mad_addr->addr_type.smi.port_num = 255; /* not used */ 209219820Sjeff return; 210219820Sjeff } 211219820Sjeff 212219820Sjeff osm_mad_addr->addr_type.gsi.remote_qp = ib_mad_addr->qpn; 213219820Sjeff osm_mad_addr->addr_type.gsi.remote_qkey = ib_mad_addr->qkey; 214219820Sjeff osm_mad_addr->addr_type.gsi.pkey_ix = umad_get_pkey(umad); 215219820Sjeff osm_mad_addr->addr_type.gsi.service_level = ib_mad_addr->sl; 216219820Sjeff osm_mad_addr->addr_type.gsi.global_route = 0; /* FIXME: handle GRH */ 217219820Sjeff memset(&osm_mad_addr->addr_type.gsi.grh_info, 0, 218219820Sjeff sizeof osm_mad_addr->addr_type.gsi.grh_info); 219219820Sjeff} 220219820Sjeff 221219820Sjeffstatic void *swap_mad_bufs(osm_madw_t * p_madw, void *umad) 222219820Sjeff{ 223219820Sjeff void *old; 224219820Sjeff 225219820Sjeff old = p_madw->vend_wrap.umad; 226219820Sjeff p_madw->vend_wrap.umad = umad; 227219820Sjeff p_madw->p_mad = umad_get_mad(umad); 228219820Sjeff 229219820Sjeff return old; 230219820Sjeff} 231219820Sjeff 232219820Sjeffstatic void unlock_mutex(void *arg) 233219820Sjeff{ 234219820Sjeff pthread_mutex_unlock(arg); 235219820Sjeff} 236219820Sjeff 237219820Sjeffstatic void *umad_receiver(void *p_ptr) 238219820Sjeff{ 239219820Sjeff umad_receiver_t *const p_ur = (umad_receiver_t *) p_ptr; 240219820Sjeff osm_vendor_t *p_vend = p_ur->p_vend; 241219820Sjeff osm_umad_bind_info_t *p_bind; 242219820Sjeff ib_mad_addr_t *ib_mad_addr; 243219820Sjeff osm_mad_addr_t osm_addr; 244219820Sjeff osm_madw_t *p_madw, *p_req_madw; 245219820Sjeff ib_mad_t *mad; 246219820Sjeff void *umad = 0; 247219820Sjeff int mad_agent, length; 248219820Sjeff 249219820Sjeff OSM_LOG_ENTER(p_ur->p_log); 250219820Sjeff 251219820Sjeff for (;;) { 252219820Sjeff if (!umad && 253219820Sjeff !(umad = umad_alloc(1, umad_size() + MAD_BLOCK_SIZE))) { 254219820Sjeff OSM_LOG(p_ur->p_log, OSM_LOG_ERROR, "ERR 5403: " 255219820Sjeff "can't alloc MAD sized umad\n"); 256219820Sjeff break; 257219820Sjeff } 258219820Sjeff 259219820Sjeff length = MAD_BLOCK_SIZE; 260219820Sjeff if ((mad_agent = umad_recv(p_vend->umad_port_id, umad, 261219820Sjeff &length, -1)) < 0) { 262219820Sjeff if (length <= MAD_BLOCK_SIZE) { 263219820Sjeff OSM_LOG(p_ur->p_log, OSM_LOG_ERROR, "ERR 5404: " 264219820Sjeff "recv error on MAD sized umad (%m)\n"); 265219820Sjeff continue; 266219820Sjeff } else { 267219820Sjeff umad_free(umad); 268219820Sjeff /* Need a larger buffer for RMPP */ 269219820Sjeff umad = umad_alloc(1, umad_size() + length); 270219820Sjeff if (!umad) { 271219820Sjeff OSM_LOG(p_ur->p_log, OSM_LOG_ERROR, 272219820Sjeff "ERR 5405: " 273219820Sjeff "can't alloc umad length %d\n", 274219820Sjeff length); 275219820Sjeff continue; 276219820Sjeff } 277219820Sjeff 278219820Sjeff if ((mad_agent = umad_recv(p_vend->umad_port_id, 279219820Sjeff umad, &length, 280219820Sjeff -1)) < 0) { 281219820Sjeff OSM_LOG(p_ur->p_log, OSM_LOG_ERROR, 282219820Sjeff "ERR 5406: " 283219820Sjeff "recv error on umad length %d (%m)\n", 284219820Sjeff length); 285219820Sjeff continue; 286219820Sjeff } 287219820Sjeff } 288219820Sjeff } 289219820Sjeff 290219820Sjeff if (mad_agent >= UMAD_CA_MAX_AGENTS || 291219820Sjeff !(p_bind = p_vend->agents[mad_agent])) { 292219820Sjeff OSM_LOG(p_ur->p_log, OSM_LOG_ERROR, "ERR 5407: " 293219820Sjeff "invalid mad agent %d - dropping\n", mad_agent); 294219820Sjeff continue; 295219820Sjeff } 296219820Sjeff 297219820Sjeff mad = (ib_mad_t *) umad_get_mad(umad); 298219820Sjeff ib_mad_addr = umad_get_mad_addr(umad); 299219820Sjeff 300219820Sjeff ib_mad_addr_conv(umad, &osm_addr, 301219820Sjeff mad->mgmt_class == IB_MCLASS_SUBN_LID || 302219820Sjeff mad->mgmt_class == IB_MCLASS_SUBN_DIR); 303219820Sjeff 304219820Sjeff if (!(p_madw = osm_mad_pool_get(p_bind->p_mad_pool, 305219820Sjeff (osm_bind_handle_t) p_bind, 306219820Sjeff MAX(length, MAD_BLOCK_SIZE), 307219820Sjeff &osm_addr))) { 308219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5408: " 309219820Sjeff "request for a new madw failed -- dropping packet\n"); 310219820Sjeff continue; 311219820Sjeff } 312219820Sjeff 313219820Sjeff /* Need to fix up MAD size if short RMPP packet */ 314219820Sjeff if (length < MAD_BLOCK_SIZE) 315219820Sjeff p_madw->mad_size = length; 316219820Sjeff 317219820Sjeff /* 318219820Sjeff * Avoid copying by swapping mad buf pointers. 319219820Sjeff * Do not use umad after this line of code. 320219820Sjeff */ 321219820Sjeff umad = swap_mad_bufs(p_madw, umad); 322219820Sjeff 323219820Sjeff /* if status != 0 then we are handling recv timeout on send */ 324219820Sjeff if (umad_status(p_madw->vend_wrap.umad)) { 325219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5409: " 326219820Sjeff "send completed with error" 327219820Sjeff " (method=0x%X attr=0x%X trans_id=0x%" PRIx64 328219820Sjeff ") -- dropping\n", 329219820Sjeff mad->method, cl_ntoh16(mad->attr_id), 330219820Sjeff cl_ntoh64(mad->trans_id)); 331219820Sjeff if (mad->mgmt_class != IB_MCLASS_SUBN_DIR) { 332219820Sjeff /* LID routed */ 333219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, 334219820Sjeff "ERR 5410: class 0x%x LID 0x%x\n", 335219820Sjeff mad->mgmt_class, 336219820Sjeff cl_ntoh16(ib_mad_addr->lid)); 337219820Sjeff } else { 338219820Sjeff ib_smp_t *smp; 339219820Sjeff 340219820Sjeff /* Direct routed SMP */ 341219820Sjeff smp = (ib_smp_t *) mad; 342219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, 343219820Sjeff "ERR 5411: DR SMP Hop Ptr: 0x%X\n", 344219820Sjeff smp->hop_ptr); 345219820Sjeff osm_dump_smp_dr_path(p_vend->p_log, smp, 346219820Sjeff OSM_LOG_ERROR); 347219820Sjeff } 348219820Sjeff 349219820Sjeff if (!(p_req_madw = get_madw(p_vend, &mad->trans_id))) { 350219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, 351219820Sjeff "ERR 5412: " 352219820Sjeff "Failed to obtain request madw for timed out MAD" 353219820Sjeff "(method=0x%X attr=0x%X tid=0x%"PRIx64") -- dropping\n", 354219820Sjeff mad->method, cl_ntoh16(mad->attr_id), 355219820Sjeff cl_ntoh64(mad->trans_id)); 356219820Sjeff } else { 357219820Sjeff p_req_madw->status = IB_TIMEOUT; 358219820Sjeff /* cb frees req_madw */ 359219820Sjeff pthread_mutex_lock(&p_vend->cb_mutex); 360219820Sjeff pthread_cleanup_push(unlock_mutex, 361219820Sjeff &p_vend->cb_mutex); 362219820Sjeff (*p_bind->send_err_callback) (p_bind-> 363219820Sjeff client_context, 364219820Sjeff p_req_madw); 365219820Sjeff pthread_cleanup_pop(1); 366219820Sjeff } 367219820Sjeff 368219820Sjeff osm_mad_pool_put(p_bind->p_mad_pool, p_madw); 369219820Sjeff continue; 370219820Sjeff } 371219820Sjeff 372219820Sjeff p_req_madw = 0; 373219820Sjeff if (ib_mad_is_response(mad) && 374219820Sjeff !(p_req_madw = get_madw(p_vend, &mad->trans_id))) { 375219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5413: " 376219820Sjeff "Failed to obtain request madw for received MAD" 377219820Sjeff "(method=0x%X attr=0x%X tid=0x%"PRIx64") -- dropping\n", 378219820Sjeff mad->method, cl_ntoh16((mad)->attr_id), 379219820Sjeff cl_ntoh64(mad->trans_id)); 380219820Sjeff osm_mad_pool_put(p_bind->p_mad_pool, p_madw); 381219820Sjeff continue; 382219820Sjeff } 383219820Sjeff#ifndef VENDOR_RMPP_SUPPORT 384219820Sjeff if ((mad->mgmt_class != IB_MCLASS_SUBN_DIR) && 385219820Sjeff (mad->mgmt_class != IB_MCLASS_SUBN_LID) && 386219820Sjeff (ib_rmpp_is_flag_set((ib_rmpp_mad_t *) mad, 387219820Sjeff IB_RMPP_FLAG_ACTIVE))) { 388219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5414: " 389219820Sjeff "class 0x%x method 0x%x RMPP version %d type " 390219820Sjeff "%d flags 0x%x received -- dropping\n", 391219820Sjeff mad->mgmt_class, mad->method, 392219820Sjeff ((ib_rmpp_mad_t *) mad)->rmpp_version, 393219820Sjeff ((ib_rmpp_mad_t *) mad)->rmpp_type, 394219820Sjeff ((ib_rmpp_mad_t *) mad)->rmpp_flags); 395219820Sjeff osm_mad_pool_put(p_bind->p_mad_pool, p_madw); 396219820Sjeff continue; 397219820Sjeff } 398219820Sjeff#endif 399219820Sjeff 400219820Sjeff /* call the CB */ 401219820Sjeff pthread_mutex_lock(&p_vend->cb_mutex); 402219820Sjeff pthread_cleanup_push(unlock_mutex, &p_vend->cb_mutex); 403219820Sjeff (*p_bind->mad_recv_callback) (p_madw, p_bind->client_context, 404219820Sjeff p_req_madw); 405219820Sjeff pthread_cleanup_pop(1); 406219820Sjeff } 407219820Sjeff 408219820Sjeff OSM_LOG_EXIT(p_vend->p_log); 409219820Sjeff return NULL; 410219820Sjeff} 411219820Sjeff 412219820Sjeffstatic int umad_receiver_start(osm_vendor_t * p_vend) 413219820Sjeff{ 414219820Sjeff umad_receiver_t *p_ur = p_vend->receiver; 415219820Sjeff 416219820Sjeff p_ur->p_vend = p_vend; 417219820Sjeff p_ur->p_log = p_vend->p_log; 418219820Sjeff 419219820Sjeff if (pthread_create(&p_ur->tid, NULL, umad_receiver, p_ur) < 0) 420219820Sjeff return -1; 421219820Sjeff 422219820Sjeff return 0; 423219820Sjeff} 424219820Sjeff 425219820Sjeffstatic void umad_receiver_stop(umad_receiver_t * p_ur) 426219820Sjeff{ 427219820Sjeff pthread_cancel(p_ur->tid); 428219820Sjeff pthread_join(p_ur->tid, NULL); 429219820Sjeff p_ur->tid = 0; 430219820Sjeff p_ur->p_vend = NULL; 431219820Sjeff p_ur->p_log = NULL; 432219820Sjeff} 433219820Sjeff 434219820Sjeff/********************************************************************** 435219820Sjeff **********************************************************************/ 436219820Sjeffib_api_status_t 437219820Sjeffosm_vendor_init(IN osm_vendor_t * const p_vend, 438219820Sjeff IN osm_log_t * const p_log, IN const uint32_t timeout) 439219820Sjeff{ 440219820Sjeff char *max = NULL; 441219820Sjeff int r, n_cas; 442219820Sjeff 443219820Sjeff OSM_LOG_ENTER(p_log); 444219820Sjeff 445219820Sjeff p_vend->p_log = p_log; 446219820Sjeff p_vend->timeout = timeout; 447219820Sjeff p_vend->max_retries = OSM_DEFAULT_RETRY_COUNT; 448219820Sjeff pthread_mutex_init(&p_vend->cb_mutex, NULL); 449219820Sjeff pthread_mutex_init(&p_vend->match_tbl_mutex, NULL); 450219820Sjeff p_vend->umad_port_id = -1; 451219820Sjeff p_vend->issmfd = -1; 452219820Sjeff 453219820Sjeff /* 454219820Sjeff * Open our instance of UMAD. 455219820Sjeff */ 456219820Sjeff if ((r = umad_init()) < 0) { 457219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, 458219820Sjeff "ERR 5415: Error opening UMAD\n"); 459219820Sjeff } 460219820Sjeff 461219820Sjeff if ((n_cas = umad_get_cas_names(p_vend->ca_names, 462219820Sjeff OSM_UMAD_MAX_CAS)) < 0) { 463219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, 464219820Sjeff "ERR 5416: umad_get_cas_names failed\n"); 465219820Sjeff r = n_cas; 466219820Sjeff goto Exit; 467219820Sjeff } 468219820Sjeff 469219820Sjeff p_vend->ca_count = n_cas; 470219820Sjeff p_vend->mtbl.max = DEFAULT_OSM_UMAD_MAX_PENDING; 471219820Sjeff 472219820Sjeff if ((max = getenv("OSM_UMAD_MAX_PENDING")) != NULL) { 473219820Sjeff int tmp = strtol(max, NULL, 0); 474219820Sjeff if (tmp > 0) 475219820Sjeff p_vend->mtbl.max = tmp; 476219820Sjeff else 477219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "Error:" 478219820Sjeff "OSM_UMAD_MAX_PENDING=%d is invalid", 479219820Sjeff tmp); 480219820Sjeff } 481219820Sjeff 482219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_INFO, "%d pending umads specified\n", 483219820Sjeff p_vend->mtbl.max); 484219820Sjeff 485219820Sjeff p_vend->mtbl.tbl = calloc(p_vend->mtbl.max, sizeof(*(p_vend->mtbl.tbl))); 486219820Sjeff if (!p_vend->mtbl.tbl) { 487219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "Error:" 488219820Sjeff "failed to allocate vendor match table\n"); 489219820Sjeff r = IB_INSUFFICIENT_MEMORY; 490219820Sjeff goto Exit; 491219820Sjeff } 492219820Sjeff 493219820SjeffExit: 494219820Sjeff OSM_LOG_EXIT(p_log); 495219820Sjeff return (r); 496219820Sjeff} 497219820Sjeff 498219820Sjeff/********************************************************************** 499219820Sjeff **********************************************************************/ 500219820Sjeffosm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log, 501219820Sjeff IN const uint32_t timeout) 502219820Sjeff{ 503219820Sjeff osm_vendor_t *p_vend = NULL; 504219820Sjeff 505219820Sjeff OSM_LOG_ENTER(p_log); 506219820Sjeff 507219820Sjeff if (!timeout) { 508219820Sjeff OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 5433: " 509219820Sjeff "transaction timeout cannot be 0\n"); 510219820Sjeff goto Exit; 511219820Sjeff } 512219820Sjeff 513219820Sjeff p_vend = malloc(sizeof(*p_vend)); 514219820Sjeff if (p_vend == NULL) { 515219820Sjeff OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 5417: " 516219820Sjeff "Unable to allocate vendor object\n"); 517219820Sjeff goto Exit; 518219820Sjeff } 519219820Sjeff 520219820Sjeff memset(p_vend, 0, sizeof(*p_vend)); 521219820Sjeff 522219820Sjeff if (osm_vendor_init(p_vend, p_log, timeout) < 0) { 523219820Sjeff free(p_vend); 524219820Sjeff p_vend = NULL; 525219820Sjeff } 526219820Sjeff 527219820SjeffExit: 528219820Sjeff OSM_LOG_EXIT(p_log); 529219820Sjeff return (p_vend); 530219820Sjeff} 531219820Sjeff 532219820Sjeff/********************************************************************** 533219820Sjeff **********************************************************************/ 534219820Sjeffvoid osm_vendor_delete(IN osm_vendor_t ** const pp_vend) 535219820Sjeff{ 536219820Sjeff osm_vendor_close_port(*pp_vend); 537219820Sjeff 538219820Sjeff clear_madw(*pp_vend); 539219820Sjeff /* make sure all ports are closed */ 540219820Sjeff umad_done(); 541219820Sjeff 542219820Sjeff pthread_mutex_destroy(&(*pp_vend)->cb_mutex); 543219820Sjeff pthread_mutex_destroy(&(*pp_vend)->match_tbl_mutex); 544219820Sjeff free((*pp_vend)->mtbl.tbl); 545219820Sjeff free(*pp_vend); 546219820Sjeff *pp_vend = NULL; 547219820Sjeff} 548219820Sjeff 549219820Sjeff/********************************************************************** 550219820Sjeff **********************************************************************/ 551219820Sjeffib_api_status_t 552219820Sjeffosm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend, 553219820Sjeff IN ib_port_attr_t * const p_attr_array, 554219820Sjeff IN uint32_t * const p_num_ports) 555219820Sjeff{ 556219820Sjeff umad_ca_t ca; 557219820Sjeff ib_port_attr_t *attr = p_attr_array; 558219820Sjeff unsigned done = 0; 559219820Sjeff int r, i, j; 560219820Sjeff 561219820Sjeff OSM_LOG_ENTER(p_vend->p_log); 562219820Sjeff 563219820Sjeff CL_ASSERT(p_vend && p_num_ports); 564219820Sjeff 565219820Sjeff if (!*p_num_ports) { 566219820Sjeff r = IB_INVALID_PARAMETER; 567219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5418: " 568219820Sjeff "Ports in should be > 0\n"); 569219820Sjeff goto Exit; 570219820Sjeff } 571219820Sjeff 572219820Sjeff if (!p_attr_array) { 573219820Sjeff r = IB_INSUFFICIENT_MEMORY; 574219820Sjeff *p_num_ports = 0; 575219820Sjeff goto Exit; 576219820Sjeff } 577219820Sjeff 578219820Sjeff for (i = 0; i < p_vend->ca_count && !done; i++) { 579219820Sjeff /* 580219820Sjeff * For each CA, retrieve the port guids 581219820Sjeff */ 582219820Sjeff if (umad_get_ca(p_vend->ca_names[i], &ca) == 0) { 583219820Sjeff if (ca.node_type < 1 || ca.node_type > 3) 584219820Sjeff continue; 585219820Sjeff for (j = 0; j <= ca.numports; j++) { 586219820Sjeff if (!ca.ports[j]) 587219820Sjeff continue; 588219820Sjeff attr->port_guid = ca.ports[j]->port_guid; 589219820Sjeff attr->lid = ca.ports[j]->base_lid; 590219820Sjeff attr->port_num = ca.ports[j]->portnum; 591219820Sjeff attr->sm_lid = ca.ports[j]->sm_lid; 592219820Sjeff attr->link_state = ca.ports[j]->state; 593219820Sjeff attr++; 594219820Sjeff if (attr - p_attr_array > *p_num_ports) { 595219820Sjeff done = 1; 596219820Sjeff break; 597219820Sjeff } 598219820Sjeff } 599219820Sjeff umad_release_ca(&ca); 600219820Sjeff } 601219820Sjeff } 602219820Sjeff 603219820Sjeff *p_num_ports = attr - p_attr_array; 604219820Sjeff r = 0; 605219820Sjeff 606219820SjeffExit: 607219820Sjeff OSM_LOG_EXIT(p_vend->p_log); 608219820Sjeff return r; 609219820Sjeff} 610219820Sjeff 611219820Sjeff/********************************************************************** 612219820Sjeff **********************************************************************/ 613219820Sjeffstatic int 614219820Sjeffosm_vendor_open_port(IN osm_vendor_t * const p_vend, 615219820Sjeff IN const ib_net64_t port_guid) 616219820Sjeff{ 617219820Sjeff ib_net64_t portguids[OSM_UMAD_MAX_PORTS_PER_CA + 1]; 618219820Sjeff umad_ca_t umad_ca; 619219820Sjeff int i = 0, umad_port_id = -1; 620219820Sjeff char *name; 621219820Sjeff int ca, r; 622219820Sjeff 623219820Sjeff CL_ASSERT(p_vend); 624219820Sjeff 625219820Sjeff OSM_LOG_ENTER(p_vend->p_log); 626219820Sjeff 627219820Sjeff if (p_vend->umad_port_id >= 0) { 628219820Sjeff umad_port_id = p_vend->umad_port_id; 629219820Sjeff goto Exit; 630219820Sjeff } 631219820Sjeff 632219820Sjeff if (!port_guid) { 633219820Sjeff name = NULL; 634219820Sjeff i = 0; 635219820Sjeff goto _found; 636219820Sjeff } 637219820Sjeff 638219820Sjeff for (ca = 0; ca < p_vend->ca_count; ca++) { 639219820Sjeff if ((r = umad_get_ca_portguids(p_vend->ca_names[ca], 640219820Sjeff portguids, 641219820Sjeff OSM_UMAD_MAX_CAS)) < 0) { 642219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5421: " 643219820Sjeff "Unable to get CA %s port guids (%s)\n", 644219820Sjeff p_vend->ca_names[ca], strerror(r)); 645219820Sjeff goto Exit; 646219820Sjeff } 647219820Sjeff for (i = 0; i < r; i++) 648219820Sjeff if (port_guid == portguids[i]) { 649219820Sjeff name = p_vend->ca_names[ca]; 650219820Sjeff goto _found; 651219820Sjeff } 652219820Sjeff } 653219820Sjeff 654219820Sjeff /* 655219820Sjeff * No local CA owns this guid! 656219820Sjeff */ 657219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5422: " 658219820Sjeff "Unable to find requested CA guid 0x%" PRIx64 "\n", 659219820Sjeff cl_ntoh64(port_guid)); 660219820Sjeff goto Exit; 661219820Sjeff 662219820Sjeff_found: 663219820Sjeff /* Validate that node is an IB node type (not iWARP) */ 664219820Sjeff if (umad_get_ca(name, &umad_ca) < 0) { 665219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542A: " 666219820Sjeff "umad_get_ca() failed\n"); 667219820Sjeff goto Exit; 668219820Sjeff } 669219820Sjeff 670219820Sjeff if (umad_ca.node_type < 1 || umad_ca.node_type > 3) { 671219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542D: " 672219820Sjeff "Type %d of node \'%s\' is not an IB node type\n", 673219820Sjeff umad_ca.node_type, umad_ca.ca_name); 674219820Sjeff fprintf(stderr, 675219820Sjeff "Type %d of node \'%s\' is not an IB node type\n", 676219820Sjeff umad_ca.node_type, umad_ca.ca_name); 677219820Sjeff umad_release_ca(&umad_ca); 678219820Sjeff goto Exit; 679219820Sjeff } 680219820Sjeff umad_release_ca(&umad_ca); 681219820Sjeff 682219820Sjeff /* Port found, try to open it */ 683219820Sjeff if (umad_get_port(name, i, &p_vend->umad_port) < 0) { 684219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542B: " 685219820Sjeff "umad_get_port() failed\n"); 686219820Sjeff goto Exit; 687219820Sjeff } 688219820Sjeff 689219820Sjeff if ((umad_port_id = umad_open_port(p_vend->umad_port.ca_name, 690219820Sjeff p_vend->umad_port.portnum)) < 0) { 691219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542C: " 692219820Sjeff "umad_open_port() failed\n"); 693219820Sjeff goto Exit; 694219820Sjeff } 695219820Sjeff 696219820Sjeff p_vend->umad_port_id = umad_port_id; 697219820Sjeff 698219820Sjeff /* start receiver thread */ 699219820Sjeff if (!(p_vend->receiver = calloc(1, sizeof(umad_receiver_t)))) { 700219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5423: " 701219820Sjeff "Unable to alloc receiver struct\n"); 702219820Sjeff umad_close_port(umad_port_id); 703219820Sjeff umad_release_port(&p_vend->umad_port); 704219820Sjeff p_vend->umad_port.port_guid = 0; 705219820Sjeff p_vend->umad_port_id = umad_port_id = -1; 706219820Sjeff goto Exit; 707219820Sjeff } 708219820Sjeff if (umad_receiver_start(p_vend) != 0) { 709219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5420: " 710219820Sjeff "umad_receiver_init failed\n"); 711219820Sjeff umad_close_port(umad_port_id); 712219820Sjeff umad_release_port(&p_vend->umad_port); 713219820Sjeff p_vend->umad_port.port_guid = 0; 714219820Sjeff p_vend->umad_port_id = umad_port_id = -1; 715219820Sjeff } 716219820Sjeff 717219820SjeffExit: 718219820Sjeff OSM_LOG_EXIT(p_vend->p_log); 719219820Sjeff return umad_port_id; 720219820Sjeff} 721219820Sjeff 722219820Sjeffstatic void osm_vendor_close_port(osm_vendor_t * const p_vend) 723219820Sjeff{ 724219820Sjeff umad_receiver_t *p_ur; 725219820Sjeff int i; 726219820Sjeff 727219820Sjeff p_ur = p_vend->receiver; 728219820Sjeff p_vend->receiver = NULL; 729219820Sjeff if (p_ur) { 730219820Sjeff umad_receiver_stop(p_ur); 731219820Sjeff free(p_ur); 732219820Sjeff } 733219820Sjeff 734219820Sjeff if (p_vend->umad_port_id >= 0) { 735219820Sjeff for (i = 0; i < UMAD_CA_MAX_AGENTS; i++) 736219820Sjeff if (p_vend->agents[i]) 737219820Sjeff umad_unregister(p_vend->umad_port_id, i); 738219820Sjeff umad_close_port(p_vend->umad_port_id); 739219820Sjeff umad_release_port(&p_vend->umad_port); 740219820Sjeff p_vend->umad_port.port_guid = 0; 741219820Sjeff p_vend->umad_port_id = -1; 742219820Sjeff } 743219820Sjeff} 744219820Sjeff 745219820Sjeffstatic int set_bit(int nr, void *method_mask) 746219820Sjeff{ 747219820Sjeff long mask, *addr = method_mask; 748219820Sjeff int retval; 749219820Sjeff 750219820Sjeff addr += nr / (8 * sizeof(long)); 751219820Sjeff mask = 1L << (nr % (8 * sizeof(long))); 752219820Sjeff retval = (mask & *addr) != 0; 753219820Sjeff *addr |= mask; 754219820Sjeff return retval; 755219820Sjeff} 756219820Sjeff 757219820Sjeff/********************************************************************** 758219820Sjeff **********************************************************************/ 759219820Sjeffosm_bind_handle_t 760219820Sjeffosm_vendor_bind(IN osm_vendor_t * const p_vend, 761219820Sjeff IN osm_bind_info_t * const p_user_bind, 762219820Sjeff IN osm_mad_pool_t * const p_mad_pool, 763219820Sjeff IN osm_vend_mad_recv_callback_t mad_recv_callback, 764219820Sjeff IN osm_vend_mad_send_err_callback_t send_err_callback, 765219820Sjeff IN void *context) 766219820Sjeff{ 767219820Sjeff ib_net64_t port_guid; 768219820Sjeff osm_umad_bind_info_t *p_bind = 0; 769219820Sjeff long method_mask[16 / sizeof(long)]; 770219820Sjeff int umad_port_id; 771219820Sjeff uint8_t rmpp_version; 772219820Sjeff 773219820Sjeff OSM_LOG_ENTER(p_vend->p_log); 774219820Sjeff 775219820Sjeff CL_ASSERT(p_user_bind); 776219820Sjeff CL_ASSERT(p_mad_pool); 777219820Sjeff CL_ASSERT(mad_recv_callback); 778219820Sjeff CL_ASSERT(send_err_callback); 779219820Sjeff 780219820Sjeff port_guid = p_user_bind->port_guid; 781219820Sjeff 782219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_INFO, 783219820Sjeff "Binding to port 0x%" PRIx64 "\n", cl_ntoh64(port_guid)); 784219820Sjeff 785219820Sjeff if ((umad_port_id = osm_vendor_open_port(p_vend, port_guid)) < 0) { 786219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5424: " 787219820Sjeff "Unable to open port 0x%" PRIx64 "\n", 788219820Sjeff cl_ntoh64(port_guid)); 789219820Sjeff goto Exit; 790219820Sjeff } 791219820Sjeff 792219820Sjeff if (umad_get_issm_path(p_vend->umad_port.ca_name, 793219820Sjeff p_vend->umad_port.portnum, 794219820Sjeff p_vend->issm_path, 795219820Sjeff sizeof(p_vend->issm_path)) < 0) { 796219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542E: " 797219820Sjeff "Cannot resolve issm path for port %s:%u\n", 798219820Sjeff p_vend->umad_port.ca_name, p_vend->umad_port.portnum); 799219820Sjeff goto Exit; 800219820Sjeff } 801219820Sjeff 802219820Sjeff if (!(p_bind = malloc(sizeof(*p_bind)))) { 803219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5425: " 804219820Sjeff "Unable to allocate internal bind object\n"); 805219820Sjeff goto Exit; 806219820Sjeff } 807219820Sjeff 808219820Sjeff memset(p_bind, 0, sizeof(*p_bind)); 809219820Sjeff p_bind->p_vend = p_vend; 810219820Sjeff p_bind->port_id = umad_port_id; 811219820Sjeff p_bind->client_context = context; 812219820Sjeff p_bind->mad_recv_callback = mad_recv_callback; 813219820Sjeff p_bind->send_err_callback = send_err_callback; 814219820Sjeff p_bind->p_mad_pool = p_mad_pool; 815219820Sjeff p_bind->port_guid = port_guid; 816219820Sjeff 817219820Sjeff memset(method_mask, 0, sizeof method_mask); 818219820Sjeff if (p_user_bind->is_responder) { 819219820Sjeff set_bit(IB_MAD_METHOD_GET, &method_mask); 820219820Sjeff set_bit(IB_MAD_METHOD_SET, &method_mask); 821219820Sjeff if (p_user_bind->mad_class == IB_MCLASS_SUBN_ADM) { 822219820Sjeff set_bit(IB_MAD_METHOD_GETTABLE, &method_mask); 823219820Sjeff set_bit(IB_MAD_METHOD_DELETE, &method_mask); 824219820Sjeff#ifdef DUAL_SIDED_RMPP 825219820Sjeff set_bit(IB_MAD_METHOD_GETMULTI, &method_mask); 826219820Sjeff#endif 827219820Sjeff /* Add in IB_MAD_METHOD_GETTRACETABLE */ 828219820Sjeff /* when supported by OpenSM */ 829219820Sjeff } 830219820Sjeff } 831219820Sjeff if (p_user_bind->is_report_processor) 832219820Sjeff set_bit(IB_MAD_METHOD_REPORT, &method_mask); 833219820Sjeff if (p_user_bind->is_trap_processor) { 834219820Sjeff set_bit(IB_MAD_METHOD_TRAP, &method_mask); 835219820Sjeff set_bit(IB_MAD_METHOD_TRAP_REPRESS, &method_mask); 836219820Sjeff } 837219820Sjeff#ifndef VENDOR_RMPP_SUPPORT 838219820Sjeff rmpp_version = 0; 839219820Sjeff#else 840219820Sjeff /* If SA class, set rmpp_version */ 841219820Sjeff if (p_user_bind->mad_class == IB_MCLASS_SUBN_ADM) 842219820Sjeff rmpp_version = 1; 843219820Sjeff else 844219820Sjeff rmpp_version = 0; 845219820Sjeff#endif 846219820Sjeff 847219820Sjeff if ((p_bind->agent_id = umad_register(p_vend->umad_port_id, 848219820Sjeff p_user_bind->mad_class, 849219820Sjeff p_user_bind->class_version, 850219820Sjeff rmpp_version, method_mask)) < 0) { 851219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5426: " 852219820Sjeff "Unable to register class %u version %u\n", 853219820Sjeff p_user_bind->mad_class, p_user_bind->class_version); 854219820Sjeff free(p_bind); 855219820Sjeff p_bind = 0; 856219820Sjeff goto Exit; 857219820Sjeff } 858219820Sjeff 859219820Sjeff if (p_bind->agent_id >= UMAD_CA_MAX_AGENTS || 860219820Sjeff p_vend->agents[p_bind->agent_id]) { 861219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5427: " 862219820Sjeff "bad agent id %u or duplicate agent for class %u vers %u\n", 863219820Sjeff p_bind->agent_id, p_user_bind->mad_class, 864219820Sjeff p_user_bind->class_version); 865219820Sjeff free(p_bind); 866219820Sjeff p_bind = 0; 867219820Sjeff goto Exit; 868219820Sjeff } 869219820Sjeff 870219820Sjeff p_vend->agents[p_bind->agent_id] = p_bind; 871219820Sjeff 872219820Sjeff /* If Subn Directed Route class, register Subn LID routed class */ 873219820Sjeff if (p_user_bind->mad_class == IB_MCLASS_SUBN_DIR) { 874219820Sjeff if ((p_bind->agent_id1 = umad_register(p_vend->umad_port_id, 875219820Sjeff IB_MCLASS_SUBN_LID, 876219820Sjeff p_user_bind-> 877219820Sjeff class_version, 0, 878219820Sjeff method_mask)) < 0) { 879219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5428: " 880219820Sjeff "Unable to register class 1 version %u\n", 881219820Sjeff p_user_bind->class_version); 882219820Sjeff free(p_bind); 883219820Sjeff p_bind = 0; 884219820Sjeff goto Exit; 885219820Sjeff } 886219820Sjeff 887219820Sjeff if (p_bind->agent_id1 >= UMAD_CA_MAX_AGENTS || 888219820Sjeff p_vend->agents[p_bind->agent_id1]) { 889219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5429: " 890219820Sjeff "bad agent id %u or duplicate agent for class 1 vers %u\n", 891219820Sjeff p_bind->agent_id1, p_user_bind->class_version); 892219820Sjeff free(p_bind); 893219820Sjeff p_bind = 0; 894219820Sjeff goto Exit; 895219820Sjeff } 896219820Sjeff 897219820Sjeff p_vend->agents[p_bind->agent_id1] = p_bind; 898219820Sjeff } 899219820Sjeff 900219820SjeffExit: 901219820Sjeff OSM_LOG_EXIT(p_vend->p_log); 902219820Sjeff return ((osm_bind_handle_t) p_bind); 903219820Sjeff} 904219820Sjeff 905219820Sjeff/********************************************************************** 906219820Sjeff **********************************************************************/ 907219820Sjeffstatic void 908219820Sjeff__osm_vendor_recv_dummy_cb(IN osm_madw_t * p_madw, 909219820Sjeff IN void *bind_context, IN osm_madw_t * p_req_madw) 910219820Sjeff{ 911219820Sjeff#ifdef _DEBUG_ 912219820Sjeff fprintf(stderr, 913219820Sjeff "__osm_vendor_recv_dummy_cb: Ignoring received MAD after osm_vendor_unbind\n"); 914219820Sjeff#endif 915219820Sjeff} 916219820Sjeff 917219820Sjeff/********************************************************************** 918219820Sjeff **********************************************************************/ 919219820Sjeffstatic void 920219820Sjeff__osm_vendor_send_err_dummy_cb(IN void *bind_context, 921219820Sjeff IN osm_madw_t * p_req_madw) 922219820Sjeff{ 923219820Sjeff#ifdef _DEBUG_ 924219820Sjeff fprintf(stderr, 925219820Sjeff "__osm_vendor_send_err_dummy_cb: Ignoring send error after osm_vendor_unbind\n"); 926219820Sjeff#endif 927219820Sjeff} 928219820Sjeff 929219820Sjeff/********************************************************************** 930219820Sjeff **********************************************************************/ 931219820Sjeffvoid osm_vendor_unbind(IN osm_bind_handle_t h_bind) 932219820Sjeff{ 933219820Sjeff osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind; 934219820Sjeff osm_vendor_t *p_vend = p_bind->p_vend; 935219820Sjeff 936219820Sjeff OSM_LOG_ENTER(p_vend->p_log); 937219820Sjeff 938219820Sjeff pthread_mutex_lock(&p_vend->cb_mutex); 939219820Sjeff p_bind->mad_recv_callback = __osm_vendor_recv_dummy_cb; 940219820Sjeff p_bind->send_err_callback = __osm_vendor_send_err_dummy_cb; 941219820Sjeff pthread_mutex_unlock(&p_vend->cb_mutex); 942219820Sjeff 943219820Sjeff OSM_LOG_EXIT(p_vend->p_log); 944219820Sjeff} 945219820Sjeff 946219820Sjeff/********************************************************************** 947219820Sjeff **********************************************************************/ 948219820Sjeffib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind, 949219820Sjeff IN const uint32_t mad_size, 950219820Sjeff IN osm_vend_wrap_t * const p_vw) 951219820Sjeff{ 952219820Sjeff osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind; 953219820Sjeff osm_vendor_t *p_vend = p_bind->p_vend; 954219820Sjeff 955219820Sjeff OSM_LOG_ENTER(p_vend->p_log); 956219820Sjeff 957219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG, 958219820Sjeff "Acquiring UMAD for p_madw = %p, size = %u\n", p_vw, mad_size); 959219820Sjeff CL_ASSERT(p_vw); 960219820Sjeff p_vw->size = mad_size; 961219820Sjeff p_vw->umad = umad_alloc(1, mad_size + umad_size()); 962219820Sjeff 963219820Sjeff /* track locally */ 964219820Sjeff p_vw->h_bind = h_bind; 965219820Sjeff 966219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG, 967219820Sjeff "Acquired UMAD %p, size = %u\n", p_vw->umad, p_vw->size); 968219820Sjeff 969219820Sjeff OSM_LOG_EXIT(p_vend->p_log); 970219820Sjeff return umad_get_mad(p_vw->umad); 971219820Sjeff} 972219820Sjeff 973219820Sjeff/********************************************************************** 974219820Sjeff **********************************************************************/ 975219820Sjeffvoid 976219820Sjeffosm_vendor_put(IN osm_bind_handle_t h_bind, IN osm_vend_wrap_t * const p_vw) 977219820Sjeff{ 978219820Sjeff osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind; 979219820Sjeff osm_vendor_t *p_vend = p_bind->p_vend; 980219820Sjeff osm_madw_t *p_madw; 981219820Sjeff 982219820Sjeff OSM_LOG_ENTER(p_vend->p_log); 983219820Sjeff 984219820Sjeff CL_ASSERT(p_vw); 985219820Sjeff 986219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG, "Retiring UMAD %p\n", p_vw->umad); 987219820Sjeff 988219820Sjeff /* 989219820Sjeff * We moved the removal of the transaction to immediately after 990219820Sjeff * it was looked up. 991219820Sjeff */ 992219820Sjeff 993219820Sjeff /* free the mad but the wrapper is part of the madw object */ 994219820Sjeff umad_free(p_vw->umad); 995219820Sjeff p_vw->umad = 0; 996219820Sjeff p_madw = PARENT_STRUCT(p_vw, osm_madw_t, vend_wrap); 997219820Sjeff p_madw->p_mad = NULL; 998219820Sjeff 999219820Sjeff OSM_LOG_EXIT(p_vend->p_log); 1000219820Sjeff} 1001219820Sjeff 1002219820Sjeff/********************************************************************** 1003219820Sjeff **********************************************************************/ 1004219820Sjeffib_api_status_t 1005219820Sjeffosm_vendor_send(IN osm_bind_handle_t h_bind, 1006219820Sjeff IN osm_madw_t * const p_madw, IN boolean_t const resp_expected) 1007219820Sjeff{ 1008219820Sjeff osm_umad_bind_info_t *const p_bind = h_bind; 1009219820Sjeff osm_vendor_t *const p_vend = p_bind->p_vend; 1010219820Sjeff osm_vend_wrap_t *const p_vw = osm_madw_get_vend_ptr(p_madw); 1011219820Sjeff osm_mad_addr_t *const p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw); 1012219820Sjeff ib_mad_t *const p_mad = osm_madw_get_mad_ptr(p_madw); 1013219820Sjeff ib_sa_mad_t *const p_sa = (ib_sa_mad_t *) p_mad; 1014219820Sjeff int ret = -1; 1015219820Sjeff int is_rmpp = 0; 1016219820Sjeff uint32_t sent_mad_size; 1017219820Sjeff#ifndef VENDOR_RMPP_SUPPORT 1018219820Sjeff uint32_t paylen = 0; 1019219820Sjeff#endif 1020219820Sjeff 1021219820Sjeff OSM_LOG_ENTER(p_vend->p_log); 1022219820Sjeff 1023219820Sjeff CL_ASSERT(p_vw->h_bind == h_bind); 1024219820Sjeff CL_ASSERT(p_mad == umad_get_mad(p_vw->umad)); 1025219820Sjeff 1026219820Sjeff if (p_mad->mgmt_class == IB_MCLASS_SUBN_DIR) { 1027219820Sjeff umad_set_addr_net(p_vw->umad, 0xffff, 0, 0, 0); 1028219820Sjeff umad_set_grh(p_vw->umad, 0); 1029219820Sjeff goto Resp; 1030219820Sjeff } 1031219820Sjeff if (p_mad->mgmt_class == IB_MCLASS_SUBN_LID) { 1032219820Sjeff umad_set_addr_net(p_vw->umad, p_mad_addr->dest_lid, 0, 0, 0); 1033219820Sjeff umad_set_grh(p_vw->umad, 0); 1034219820Sjeff goto Resp; 1035219820Sjeff } 1036219820Sjeff /* GSI classes */ 1037219820Sjeff umad_set_addr_net(p_vw->umad, p_mad_addr->dest_lid, 1038219820Sjeff p_mad_addr->addr_type.gsi.remote_qp, 1039219820Sjeff p_mad_addr->addr_type.gsi.service_level, 1040219820Sjeff IB_QP1_WELL_KNOWN_Q_KEY); 1041219820Sjeff umad_set_grh(p_vw->umad, 0); /* FIXME: GRH support */ 1042219820Sjeff umad_set_pkey(p_vw->umad, p_mad_addr->addr_type.gsi.pkey_ix); 1043219820Sjeff if (ib_class_is_rmpp(p_mad->mgmt_class)) { /* RMPP GSI classes FIXME: no GRH */ 1044219820Sjeff if (!ib_rmpp_is_flag_set((ib_rmpp_mad_t *) p_sa, 1045219820Sjeff IB_RMPP_FLAG_ACTIVE)) { 1046219820Sjeff /* Clear RMPP header when RMPP not ACTIVE */ 1047219820Sjeff p_sa->rmpp_version = 0; 1048219820Sjeff p_sa->rmpp_type = 0; 1049219820Sjeff p_sa->rmpp_flags = 0; 1050219820Sjeff p_sa->rmpp_status = 0; 1051219820Sjeff#ifdef VENDOR_RMPP_SUPPORT 1052219820Sjeff } else 1053219820Sjeff is_rmpp = 1; 1054219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_VERBOSE, "RMPP %d length %d\n", 1055219820Sjeff ib_rmpp_is_flag_set((ib_rmpp_mad_t *) p_sa, 1056219820Sjeff IB_RMPP_FLAG_ACTIVE), 1057219820Sjeff p_madw->mad_size); 1058219820Sjeff#else 1059219820Sjeff } else { 1060219820Sjeff p_sa->rmpp_version = 1; 1061219820Sjeff p_sa->seg_num = cl_ntoh32(1); /* first DATA is seg 1 */ 1062219820Sjeff p_sa->rmpp_flags |= (uint8_t) 0x70; /* RRespTime of 14 (high 5 bits) */ 1063219820Sjeff p_sa->rmpp_status = 0; 1064219820Sjeff paylen = p_madw->mad_size - IB_SA_MAD_HDR_SIZE; 1065219820Sjeff paylen += (IB_SA_MAD_HDR_SIZE - MAD_RMPP_HDR_SIZE); 1066219820Sjeff p_sa->paylen_newwin = cl_ntoh32(paylen); 1067219820Sjeff } 1068219820Sjeff#endif 1069219820Sjeff } 1070219820Sjeff 1071219820SjeffResp: 1072219820Sjeff if (resp_expected) 1073219820Sjeff put_madw(p_vend, p_madw, p_mad->trans_id); 1074219820Sjeff 1075219820Sjeff#ifdef VENDOR_RMPP_SUPPORT 1076219820Sjeff sent_mad_size = p_madw->mad_size; 1077219820Sjeff#else 1078219820Sjeff sent_mad_size = is_rmpp ? p_madw->mad_size - IB_SA_MAD_HDR_SIZE : 1079219820Sjeff p_madw->mad_size; 1080219820Sjeff#endif 1081219820Sjeff if ((ret = umad_send(p_bind->port_id, p_bind->agent_id, p_vw->umad, 1082219820Sjeff sent_mad_size, 1083219820Sjeff resp_expected ? p_vend->timeout : 0, 1084219820Sjeff p_vend->max_retries)) < 0) { 1085219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5430: " 1086219820Sjeff "Send p_madw = %p of size %d failed %d (%m)\n", 1087219820Sjeff p_madw, sent_mad_size, ret); 1088219820Sjeff if (resp_expected) { 1089219820Sjeff get_madw(p_vend, &p_mad->trans_id); /* remove from aging table */ 1090219820Sjeff p_madw->status = IB_ERROR; 1091219820Sjeff pthread_mutex_lock(&p_vend->cb_mutex); 1092219820Sjeff (*p_bind->send_err_callback) (p_bind->client_context, p_madw); /* cb frees madw */ 1093219820Sjeff pthread_mutex_unlock(&p_vend->cb_mutex); 1094219820Sjeff } else 1095219820Sjeff osm_mad_pool_put(p_bind->p_mad_pool, p_madw); 1096219820Sjeff goto Exit; 1097219820Sjeff } 1098219820Sjeff 1099219820Sjeff if (!resp_expected) 1100219820Sjeff osm_mad_pool_put(p_bind->p_mad_pool, p_madw); 1101219820Sjeff 1102219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG, "Completed sending %s p_madw = %p\n", 1103219820Sjeff resp_expected ? "request" : "response or unsolicited", p_madw); 1104219820SjeffExit: 1105219820Sjeff OSM_LOG_EXIT(p_vend->p_log); 1106219820Sjeff return (ret); 1107219820Sjeff} 1108219820Sjeff 1109219820Sjeff/********************************************************************** 1110219820Sjeff **********************************************************************/ 1111219820Sjeffib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind) 1112219820Sjeff{ 1113219820Sjeff osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind; 1114219820Sjeff osm_vendor_t *p_vend = p_bind->p_vend; 1115219820Sjeff 1116219820Sjeff OSM_LOG_ENTER(p_vend->p_log); 1117219820Sjeff ; 1118219820Sjeff OSM_LOG_EXIT(p_vend->p_log); 1119219820Sjeff return (0); 1120219820Sjeff} 1121219820Sjeff 1122219820Sjeff/********************************************************************** 1123219820Sjeff **********************************************************************/ 1124219820Sjeffvoid osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val) 1125219820Sjeff{ 1126219820Sjeff osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind; 1127219820Sjeff osm_vendor_t *p_vend = p_bind->p_vend; 1128219820Sjeff 1129219820Sjeff OSM_LOG_ENTER(p_vend->p_log); 1130219820Sjeff if (TRUE == is_sm_val) { 1131219820Sjeff p_vend->issmfd = open(p_vend->issm_path, O_NONBLOCK); 1132219820Sjeff if (p_vend->issmfd < 0) { 1133219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5431: " 1134219820Sjeff "setting IS_SM capmask: cannot open file " 1135219820Sjeff "\'%s\': %s\n", 1136219820Sjeff p_vend->issm_path, strerror(errno)); 1137219820Sjeff p_vend->issmfd = -1; 1138219820Sjeff } 1139219820Sjeff } else if (p_vend->issmfd != -1) { 1140219820Sjeff if (0 != close(p_vend->issmfd)) 1141219820Sjeff OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5432: " 1142219820Sjeff "clearing IS_SM capmask: cannot close: %s\n", 1143219820Sjeff strerror(errno)); 1144219820Sjeff p_vend->issmfd = -1; 1145219820Sjeff } 1146219820Sjeff OSM_LOG_EXIT(p_vend->p_log); 1147219820Sjeff} 1148219820Sjeff 1149219820Sjeffvoid osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level) 1150219820Sjeff{ 1151219820Sjeff umad_debug(level); 1152219820Sjeff} 1153219820Sjeff 1154219820Sjeff#endif /* OSM_VENDOR_INTF_OPENIB */ 1155