15115240jeff/*
2c187222hselasky * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
35115240jeff * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
45115240jeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5c187222hselasky * Copyright (c) 2009 HNR Consulting. All rights reserved.
6c187222hselasky * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved.
75115240jeff *
85115240jeff * This software is available to you under a choice of one of two
95115240jeff * licenses.  You may choose to be licensed under the terms of the GNU
105115240jeff * General Public License (GPL) Version 2, available from the file
115115240jeff * COPYING in the main directory of this source tree, or the
125115240jeff * OpenIB.org BSD license below:
135115240jeff *
145115240jeff *     Redistribution and use in source and binary forms, with or
155115240jeff *     without modification, are permitted provided that the following
165115240jeff *     conditions are met:
175115240jeff *
185115240jeff *      - Redistributions of source code must retain the above
195115240jeff *        copyright notice, this list of conditions and the following
205115240jeff *        disclaimer.
215115240jeff *
225115240jeff *      - Redistributions in binary form must reproduce the above
235115240jeff *        copyright notice, this list of conditions and the following
245115240jeff *        disclaimer in the documentation and/or other materials
255115240jeff *        provided with the distribution.
265115240jeff *
275115240jeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
285115240jeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
295115240jeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
305115240jeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
315115240jeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
325115240jeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
335115240jeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
345115240jeff * SOFTWARE.
355115240jeff *
365115240jeff */
375115240jeff
385115240jeff/*
395115240jeff * Abstract:
405115240jeff *    Implementation of osm_vendor_t (for umad).
415115240jeff * This object represents the OpenIB vendor layer.
425115240jeff * This object is part of the opensm family of objects.
435115240jeff *
445115240jeff * Environment:
455115240jeff *    Linux User Mode
465115240jeff *
475115240jeff */
485115240jeff
495115240jeff#if HAVE_CONFIG_H
505115240jeff#  include <config.h>
515115240jeff#endif				/* HAVE_CONFIG_H */
525115240jeff
535115240jeff#ifdef OSM_VENDOR_INTF_OPENIB
545115240jeff
555115240jeff#include <unistd.h>
565115240jeff#include <stdlib.h>
575115240jeff#include <fcntl.h>
585115240jeff#include <errno.h>
595115240jeff
605115240jeff#include <iba/ib_types.h>
615115240jeff#include <complib/cl_qlist.h>
625115240jeff#include <complib/cl_math.h>
635115240jeff#include <complib/cl_debug.h>
64c187222hselasky#include <opensm/osm_file_ids.h>
65c187222hselasky#define FILE_ID OSM_FILE_VENDOR_IBUMAD_C
665115240jeff#include <opensm/osm_madw.h>
675115240jeff#include <opensm/osm_log.h>
685115240jeff#include <opensm/osm_mad_pool.h>
695115240jeff#include <opensm/osm_helper.h>
705115240jeff#include <vendor/osm_vendor_api.h>
715115240jeff
725115240jeff/****s* OpenSM: Vendor UMAD/osm_umad_bind_info_t
735115240jeff * NAME
745115240jeff *   osm_umad_bind_info_t
755115240jeff *
765115240jeff * DESCRIPTION
775115240jeff *    Structure containing bind information.
785115240jeff *
795115240jeff * SYNOPSIS
805115240jeff */
815115240jefftypedef struct _osm_umad_bind_info {
825115240jeff	osm_vendor_t *p_vend;
835115240jeff	void *client_context;
845115240jeff	osm_mad_pool_t *p_mad_pool;
855115240jeff	osm_vend_mad_recv_callback_t mad_recv_callback;
865115240jeff	osm_vend_mad_send_err_callback_t send_err_callback;
875115240jeff	ib_net64_t port_guid;
885115240jeff	int port_id;
895115240jeff	int agent_id;
905115240jeff	int agent_id1;		/* SMI requires two agents */
91c187222hselasky	int timeout;
92c187222hselasky	int max_retries;
935115240jeff} osm_umad_bind_info_t;
945115240jeff
955115240jefftypedef struct _umad_receiver {
965115240jeff	pthread_t tid;
975115240jeff	osm_vendor_t *p_vend;
985115240jeff	osm_log_t *p_log;
995115240jeff} umad_receiver_t;
1005115240jeff
1015115240jeffstatic void osm_vendor_close_port(osm_vendor_t * const p_vend);
1025115240jeff
103c187222hselaskystatic void log_send_error(osm_vendor_t * const p_vend, osm_madw_t *p_madw)
104c187222hselasky{
105c187222hselasky	if (p_madw->p_mad->mgmt_class != IB_MCLASS_SUBN_DIR) {
106c187222hselasky		/* LID routed */
107c187222hselasky		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5410: "
108c187222hselasky			"Send completed with error (%s) -- dropping\n"
109c187222hselasky			"\t\t\tClass 0x%x, Method 0x%X, Attr 0x%X, "
110c187222hselasky			"TID 0x%" PRIx64 ", LID %u\n",
111c187222hselasky			ib_get_err_str(p_madw->status),
112c187222hselasky			p_madw->p_mad->mgmt_class, p_madw->p_mad->method,
113c187222hselasky			cl_ntoh16(p_madw->p_mad->attr_id),
114c187222hselasky			cl_ntoh64(p_madw->p_mad->trans_id),
115c187222hselasky			cl_ntoh16(p_madw->mad_addr.dest_lid));
116c187222hselasky	} else {
117c187222hselasky		ib_smp_t *p_smp;
118c187222hselasky
119c187222hselasky		/* Direct routed SMP */
120c187222hselasky		p_smp = osm_madw_get_smp_ptr(p_madw);
121c187222hselasky		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5411: "
122c187222hselasky			"DR SMP Send completed with error (%s) -- dropping\n"
123c187222hselasky			"\t\t\tMethod 0x%X, Attr 0x%X, TID 0x%" PRIx64 "\n",
124c187222hselasky			ib_get_err_str(p_madw->status),
125c187222hselasky			p_madw->p_mad->method,
126c187222hselasky			cl_ntoh16(p_madw->p_mad->attr_id),
127c187222hselasky			cl_ntoh64(p_madw->p_mad->trans_id));
128c187222hselasky		osm_dump_smp_dr_path(p_vend->p_log, p_smp, OSM_LOG_ERROR);
129c187222hselasky	}
130c187222hselasky}
131c187222hselasky
1325115240jeffstatic void clear_madw(osm_vendor_t * p_vend)
1335115240jeff{
1345115240jeff	umad_match_t *m, *e, *old_m;
1355115240jeff	ib_net64_t old_tid;
136c187222hselasky	uint8_t old_mgmt_class;
1375115240jeff
1385115240jeff	OSM_LOG_ENTER(p_vend->p_log);
1395115240jeff	pthread_mutex_lock(&p_vend->match_tbl_mutex);
1405115240jeff	for (m = p_vend->mtbl.tbl, e = m + p_vend->mtbl.max; m < e; m++) {
1415115240jeff		if (m->tid) {
1425115240jeff			old_m = m;
1435115240jeff			old_tid = m->tid;
144c187222hselasky			old_mgmt_class = m->mgmt_class;
1455115240jeff			m->tid = 0;
1465115240jeff			osm_mad_pool_put(((osm_umad_bind_info_t
1475115240jeff					   *) ((osm_madw_t *) m->v)->h_bind)->
1485115240jeff					 p_mad_pool, m->v);
1495115240jeff			pthread_mutex_unlock(&p_vend->match_tbl_mutex);
1505115240jeff			OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5401: "
151c187222hselasky				"evicting entry %p (tid was 0x%" PRIx64
152c187222hselasky				" mgmt class 0x%x)\n",
153c187222hselasky				old_m, cl_ntoh64(old_tid), old_mgmt_class);
1545115240jeff			goto Exit;
1555115240jeff		}
1565115240jeff	}
1575115240jeff	pthread_mutex_unlock(&p_vend->match_tbl_mutex);
1585115240jeff
1595115240jeffExit:
1605115240jeff	OSM_LOG_EXIT(p_vend->p_log);
1615115240jeff}
1625115240jeff
163c187222hselaskystatic osm_madw_t *get_madw(osm_vendor_t * p_vend, ib_net64_t * tid,
164c187222hselasky			    uint8_t mgmt_class)
1655115240jeff{
1665115240jeff	umad_match_t *m, *e;
167c187222hselasky	ib_net64_t mtid = (*tid & CL_HTON64(0x00000000ffffffffULL));
1685115240jeff	osm_madw_t *res;
1695115240jeff
1705115240jeff	/*
1715115240jeff	 * Since mtid == 0 is the empty key, we should not
1725115240jeff	 * waste time looking for it
1735115240jeff	 */
174c187222hselasky	if (mtid == 0 || mgmt_class == 0)
1755115240jeff		return 0;
1765115240jeff
1775115240jeff	pthread_mutex_lock(&p_vend->match_tbl_mutex);
1785115240jeff	for (m = p_vend->mtbl.tbl, e = m + p_vend->mtbl.max; m < e; m++) {
179c187222hselasky		if (m->tid == mtid && m->mgmt_class == mgmt_class) {
1805115240jeff			m->tid = 0;
181c187222hselasky			m->mgmt_class = 0;
1825115240jeff			*tid = mtid;
1835115240jeff			res = m->v;
1845115240jeff			pthread_mutex_unlock(&p_vend->match_tbl_mutex);
1855115240jeff			return res;
1865115240jeff		}
1875115240jeff	}
1885115240jeff
1895115240jeff	pthread_mutex_unlock(&p_vend->match_tbl_mutex);
1905115240jeff	return 0;
1915115240jeff}
1925115240jeff
193c187222hselasky/*
194c187222hselasky * If match table full, evict LRU (least recently used) transaction.
195c187222hselasky * Maintain 2 LRUs: one for SMPs, and one for others (GS).
196c187222hselasky * Evict LRU GS transaction if one is available and only evict LRU SMP
197c187222hselasky * transaction if no other choice.
198c187222hselasky */
1995115240jeffstatic void
200c187222hselaskyput_madw(osm_vendor_t * p_vend, osm_madw_t * p_madw, ib_net64_t tid,
201c187222hselasky	 uint8_t mgmt_class)
2025115240jeff{
203c187222hselasky	umad_match_t *m, *e, *old_lru, *lru = 0, *lru_smp = 0;
2045115240jeff	osm_madw_t *p_req_madw;
2055115240jeff	osm_umad_bind_info_t *p_bind;
2065115240jeff	ib_net64_t old_tid;
207c187222hselasky	uint32_t oldest = ~0, oldest_smp = ~0;
208c187222hselasky	uint8_t old_mgmt_class;
2095115240jeff
2105115240jeff	pthread_mutex_lock(&p_vend->match_tbl_mutex);
2115115240jeff	for (m = p_vend->mtbl.tbl, e = m + p_vend->mtbl.max; m < e; m++) {
212c187222hselasky		if (m->tid == 0 && m->mgmt_class == 0) {
2135115240jeff			m->tid = tid;
214c187222hselasky			m->mgmt_class = mgmt_class;
2155115240jeff			m->v = p_madw;
2165115240jeff			m->version =
2175115240jeff			    cl_atomic_inc((atomic32_t *) & p_vend->mtbl.
2185115240jeff					  last_version);
2195115240jeff			pthread_mutex_unlock(&p_vend->match_tbl_mutex);
2205115240jeff			return;
2215115240jeff		}
222c187222hselasky		if (m->mgmt_class == IB_MCLASS_SUBN_DIR ||
223c187222hselasky		    m->mgmt_class == IB_MCLASS_SUBN_LID) {
224c187222hselasky			if (oldest_smp >= m->version) {
225c187222hselasky				oldest_smp = m->version;
226c187222hselasky				lru_smp = m;
227c187222hselasky			}
228c187222hselasky		} else {
229c187222hselasky			if (oldest >= m->version) {
230c187222hselasky				oldest = m->version;
231c187222hselasky				lru = m;
232c187222hselasky			}
2335115240jeff		}
2345115240jeff	}
2355115240jeff
236c187222hselasky	if (oldest != ~0) {
237c187222hselasky		old_lru = lru;
238c187222hselasky		old_tid = lru->tid;
239c187222hselasky		old_mgmt_class = lru->mgmt_class;
240c187222hselasky	} else {
241c187222hselasky		CL_ASSERT(oldest_smp != ~0);
242c187222hselasky		old_lru = lru_smp;
243c187222hselasky		old_tid = lru_smp->tid;
244c187222hselasky		old_mgmt_class = lru_smp->mgmt_class;
245c187222hselasky	}
2465115240jeff	p_req_madw = old_lru->v;
2475115240jeff	p_bind = p_req_madw->h_bind;
2485115240jeff	p_req_madw->status = IB_CANCELED;
249c187222hselasky	log_send_error(p_vend, p_req_madw);
2505115240jeff	pthread_mutex_lock(&p_vend->cb_mutex);
2515115240jeff	(*p_bind->send_err_callback) (p_bind->client_context, p_req_madw);
2525115240jeff	pthread_mutex_unlock(&p_vend->cb_mutex);
253c187222hselasky	if (mgmt_class == IB_MCLASS_SUBN_DIR ||
254c187222hselasky	    mgmt_class == IB_MCLASS_SUBN_LID) {
255c187222hselasky		lru_smp->tid = tid;
256c187222hselasky		lru_smp->mgmt_class = mgmt_class;
257c187222hselasky		lru_smp->v = p_madw;
258c187222hselasky		lru_smp->version =
259c187222hselasky		    cl_atomic_inc((atomic32_t *) & p_vend->mtbl.last_version);
260c187222hselasky	} else {
261c187222hselasky		lru->tid = tid;
262c187222hselasky		lru->mgmt_class = mgmt_class;
263c187222hselasky		lru->v = p_madw;
264c187222hselasky		lru->version =
265c187222hselasky		    cl_atomic_inc((atomic32_t *) & p_vend->mtbl.last_version);
266c187222hselasky	}
2675115240jeff	pthread_mutex_unlock(&p_vend->match_tbl_mutex);
2685115240jeff	OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5402: "
269c187222hselasky		"evicting entry %p (tid was 0x%" PRIx64
270c187222hselasky		" mgmt class 0x%x)\n", old_lru,
271c187222hselasky		cl_ntoh64(old_tid), old_mgmt_class);
2725115240jeff}
2735115240jeff
2745115240jeffstatic void
2755115240jeffib_mad_addr_conv(ib_user_mad_t * umad, osm_mad_addr_t * osm_mad_addr,
2765115240jeff		 int is_smi)
2775115240jeff{
2785115240jeff	ib_mad_addr_t *ib_mad_addr = umad_get_mad_addr(umad);
279c187222hselasky
280c187222hselasky	memset(osm_mad_addr, 0, sizeof(osm_mad_addr_t));
2815115240jeff	osm_mad_addr->dest_lid = ib_mad_addr->lid;
2825115240jeff	osm_mad_addr->path_bits = ib_mad_addr->path_bits;
2835115240jeff
2845115240jeff	if (is_smi) {
2855115240jeff		osm_mad_addr->addr_type.smi.source_lid = osm_mad_addr->dest_lid;
2865115240jeff		osm_mad_addr->addr_type.smi.port_num = 255;	/* not used */
2875115240jeff		return;
2885115240jeff	}
2895115240jeff
2905115240jeff	osm_mad_addr->addr_type.gsi.remote_qp = ib_mad_addr->qpn;
2915115240jeff	osm_mad_addr->addr_type.gsi.remote_qkey = ib_mad_addr->qkey;
2925115240jeff	osm_mad_addr->addr_type.gsi.pkey_ix = umad_get_pkey(umad);
2935115240jeff	osm_mad_addr->addr_type.gsi.service_level = ib_mad_addr->sl;
294c187222hselasky	if (ib_mad_addr->grh_present) {
295c187222hselasky		osm_mad_addr->addr_type.gsi.global_route = 1;
296c187222hselasky		osm_mad_addr->addr_type.gsi.grh_info.hop_limit = ib_mad_addr->hop_limit;
297c187222hselasky		osm_mad_addr->addr_type.gsi.grh_info.ver_class_flow =
298c187222hselasky			ib_grh_set_ver_class_flow(6,	/* GRH version */
299c187222hselasky						  ib_mad_addr->traffic_class,
300c187222hselasky						  ib_mad_addr->flow_label);
301c187222hselasky		memcpy(&osm_mad_addr->addr_type.gsi.grh_info.dest_gid,
302c187222hselasky		       &ib_mad_addr->gid, 16);
303c187222hselasky	}
3045115240jeff}
3055115240jeff
3065115240jeffstatic void *swap_mad_bufs(osm_madw_t * p_madw, void *umad)
3075115240jeff{
3085115240jeff	void *old;
3095115240jeff
3105115240jeff	old = p_madw->vend_wrap.umad;
3115115240jeff	p_madw->vend_wrap.umad = umad;
3125115240jeff	p_madw->p_mad = umad_get_mad(umad);
3135115240jeff
3145115240jeff	return old;
3155115240jeff}
3165115240jeff
3175115240jeffstatic void unlock_mutex(void *arg)
3185115240jeff{
3195115240jeff	pthread_mutex_unlock(arg);
3205115240jeff}
3215115240jeff
3225115240jeffstatic void *umad_receiver(void *p_ptr)
3235115240jeff{
3245115240jeff	umad_receiver_t *const p_ur = (umad_receiver_t *) p_ptr;
3255115240jeff	osm_vendor_t *p_vend = p_ur->p_vend;
3265115240jeff	osm_umad_bind_info_t *p_bind;
3275115240jeff	osm_mad_addr_t osm_addr;
3285115240jeff	osm_madw_t *p_madw, *p_req_madw;
329c187222hselasky	ib_mad_t *p_mad, *p_req_mad;
3305115240jeff	void *umad = 0;
3315115240jeff	int mad_agent, length;
3325115240jeff
3335115240jeff	OSM_LOG_ENTER(p_ur->p_log);
3345115240jeff
3355115240jeff	for (;;) {
3365115240jeff		if (!umad &&
3375115240jeff		    !(umad = umad_alloc(1, umad_size() + MAD_BLOCK_SIZE))) {
3385115240jeff			OSM_LOG(p_ur->p_log, OSM_LOG_ERROR, "ERR 5403: "
3395115240jeff				"can't alloc MAD sized umad\n");
3405115240jeff			break;
3415115240jeff		}
3425115240jeff
3435115240jeff		length = MAD_BLOCK_SIZE;
3445115240jeff		if ((mad_agent = umad_recv(p_vend->umad_port_id, umad,
3455115240jeff					   &length, -1)) < 0) {
3465115240jeff			if (length <= MAD_BLOCK_SIZE) {
3475115240jeff				OSM_LOG(p_ur->p_log, OSM_LOG_ERROR, "ERR 5404: "
3485115240jeff					"recv error on MAD sized umad (%m)\n");
3495115240jeff				continue;
3505115240jeff			} else {
3515115240jeff				umad_free(umad);
3525115240jeff				/* Need a larger buffer for RMPP */
3535115240jeff				umad = umad_alloc(1, umad_size() + length);
3545115240jeff				if (!umad) {
3555115240jeff					OSM_LOG(p_ur->p_log, OSM_LOG_ERROR,
3565115240jeff						"ERR 5405: "
3575115240jeff						"can't alloc umad length %d\n",
3585115240jeff						length);
3595115240jeff					continue;
3605115240jeff				}
3615115240jeff
3625115240jeff				if ((mad_agent = umad_recv(p_vend->umad_port_id,
3635115240jeff							   umad, &length,
3645115240jeff							   -1)) < 0) {
3655115240jeff					OSM_LOG(p_ur->p_log, OSM_LOG_ERROR,
3665115240jeff						"ERR 5406: "
3675115240jeff						"recv error on umad length %d (%m)\n",
3685115240jeff						length);
3695115240jeff					continue;
3705115240jeff				}
3715115240jeff			}
3725115240jeff		}
3735115240jeff
374c187222hselasky		if (mad_agent >= OSM_UMAD_MAX_AGENTS ||
3755115240jeff		    !(p_bind = p_vend->agents[mad_agent])) {
3765115240jeff			OSM_LOG(p_ur->p_log, OSM_LOG_ERROR, "ERR 5407: "
3775115240jeff				"invalid mad agent %d - dropping\n", mad_agent);
3785115240jeff			continue;
3795115240jeff		}
3805115240jeff
381c187222hselasky		p_mad = (ib_mad_t *) umad_get_mad(umad);
3825115240jeff
3835115240jeff		ib_mad_addr_conv(umad, &osm_addr,
384c187222hselasky				 p_mad->mgmt_class == IB_MCLASS_SUBN_LID ||
385c187222hselasky				 p_mad->mgmt_class == IB_MCLASS_SUBN_DIR);
3865115240jeff
3875115240jeff		if (!(p_madw = osm_mad_pool_get(p_bind->p_mad_pool,
3885115240jeff						(osm_bind_handle_t) p_bind,
3895115240jeff						MAX(length, MAD_BLOCK_SIZE),
3905115240jeff						&osm_addr))) {
3915115240jeff			OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5408: "
3925115240jeff				"request for a new madw failed -- dropping packet\n");
3935115240jeff			continue;
3945115240jeff		}
3955115240jeff
3965115240jeff		/* Need to fix up MAD size if short RMPP packet */
3975115240jeff		if (length < MAD_BLOCK_SIZE)
3985115240jeff			p_madw->mad_size = length;
3995115240jeff
4005115240jeff		/*
4015115240jeff		 * Avoid copying by swapping mad buf pointers.
4025115240jeff		 * Do not use umad after this line of code.
4035115240jeff		 */
4045115240jeff		umad = swap_mad_bufs(p_madw, umad);
4055115240jeff
4065115240jeff		/* if status != 0 then we are handling recv timeout on send */
4075115240jeff		if (umad_status(p_madw->vend_wrap.umad)) {
408c187222hselasky			if (!(p_req_madw = get_madw(p_vend, &p_mad->trans_id,
409c187222hselasky						    p_mad->mgmt_class))) {
4105115240jeff				OSM_LOG(p_vend->p_log, OSM_LOG_ERROR,
4115115240jeff					"ERR 5412: "
4125115240jeff					"Failed to obtain request madw for timed out MAD"
413c187222hselasky					" (class=0x%X method=0x%X attr=0x%X tid=0x%"PRIx64") -- dropping\n",
414c187222hselasky					p_mad->mgmt_class, p_mad->method,
415c187222hselasky					cl_ntoh16(p_mad->attr_id),
416c187222hselasky					cl_ntoh64(p_mad->trans_id));
4175115240jeff			} else {
4185115240jeff				p_req_madw->status = IB_TIMEOUT;
419c187222hselasky				log_send_error(p_vend, p_req_madw);
4205115240jeff				/* cb frees req_madw */
4215115240jeff				pthread_mutex_lock(&p_vend->cb_mutex);
4225115240jeff				pthread_cleanup_push(unlock_mutex,
4235115240jeff						     &p_vend->cb_mutex);
4245115240jeff				(*p_bind->send_err_callback) (p_bind->
4255115240jeff							      client_context,
4265115240jeff							      p_req_madw);
4275115240jeff				pthread_cleanup_pop(1);
4285115240jeff			}
4295115240jeff
4305115240jeff			osm_mad_pool_put(p_bind->p_mad_pool, p_madw);
4315115240jeff			continue;
4325115240jeff		}
4335115240jeff
4345115240jeff		p_req_madw = 0;
435c187222hselasky		if (ib_mad_is_response(p_mad)) {
436c187222hselasky			p_req_madw = get_madw(p_vend, &p_mad->trans_id,
437c187222hselasky					      p_mad->mgmt_class);
438c187222hselasky			if (PF(!p_req_madw)) {
439c187222hselasky				OSM_LOG(p_vend->p_log, OSM_LOG_ERROR,
440c187222hselasky					"ERR 5413: Failed to obtain request "
441c187222hselasky					"madw for received MAD "
442c187222hselasky					"(class=0x%X method=0x%X attr=0x%X "
443c187222hselasky					"tid=0x%"PRIx64") -- dropping\n",
444c187222hselasky					p_mad->mgmt_class, p_mad->method,
445c187222hselasky					cl_ntoh16(p_mad->attr_id),
446c187222hselasky					cl_ntoh64(p_mad->trans_id));
447c187222hselasky				osm_mad_pool_put(p_bind->p_mad_pool, p_madw);
448c187222hselasky				continue;
449c187222hselasky			}
450c187222hselasky
451c187222hselasky			/*
452c187222hselasky			 * Check that request MAD was really a request,
453c187222hselasky			 * and make sure that attribute ID, attribute
454c187222hselasky			 * modifier and transaction ID are the same in
455c187222hselasky			 * request and response.
456c187222hselasky			 *
457c187222hselasky			 * Exception for o15-0.2-1.11:
458c187222hselasky			 * SA response to a SubnAdmGetMulti() containing a
459c187222hselasky			 * MultiPathRecord shall have PathRecord attribute ID.
460c187222hselasky			 */
461c187222hselasky			p_req_mad = osm_madw_get_mad_ptr(p_req_madw);
462c187222hselasky			if (PF(ib_mad_is_response(p_req_mad) ||
463c187222hselasky			       (p_mad->attr_id != p_req_mad->attr_id &&
464c187222hselasky                                !(p_mad->mgmt_class == IB_MCLASS_SUBN_ADM &&
465c187222hselasky                                  p_req_mad->attr_id ==
466c187222hselasky					IB_MAD_ATTR_MULTIPATH_RECORD &&
467c187222hselasky                                  p_mad->attr_id == IB_MAD_ATTR_PATH_RECORD)) ||
468c187222hselasky			       p_mad->attr_mod != p_req_mad->attr_mod ||
469c187222hselasky			       p_mad->trans_id != p_req_mad->trans_id)) {
470c187222hselasky				OSM_LOG(p_vend->p_log, OSM_LOG_ERROR,
471c187222hselasky					"ERR 541A: "
472c187222hselasky					"Response MAD validation failed "
473c187222hselasky					"(request attr=0x%X modif=0x%X "
474c187222hselasky					"tid=0x%"PRIx64", "
475c187222hselasky					"response attr=0x%X modif=0x%X "
476c187222hselasky					"tid=0x%"PRIx64") -- dropping\n",
477c187222hselasky					cl_ntoh16(p_req_mad->attr_id),
478c187222hselasky					cl_ntoh32(p_req_mad->attr_mod),
479c187222hselasky					cl_ntoh64(p_req_mad->trans_id),
480c187222hselasky					cl_ntoh16(p_mad->attr_id),
481c187222hselasky					cl_ntoh32(p_mad->attr_mod),
482c187222hselasky					cl_ntoh64(p_mad->trans_id));
483c187222hselasky				osm_mad_pool_put(p_bind->p_mad_pool, p_madw);
484c187222hselasky				continue;
485c187222hselasky			}
4865115240jeff		}
487c187222hselasky
4885115240jeff#ifndef VENDOR_RMPP_SUPPORT
489c187222hselasky		if ((p_mad->mgmt_class != IB_MCLASS_SUBN_DIR) &&
490c187222hselasky		    (p_mad->mgmt_class != IB_MCLASS_SUBN_LID) &&
491c187222hselasky		    (ib_rmpp_is_flag_set((ib_rmpp_mad_t *) p_mad,
4925115240jeff					 IB_RMPP_FLAG_ACTIVE))) {
4935115240jeff			OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5414: "
4945115240jeff				"class 0x%x method 0x%x RMPP version %d type "
4955115240jeff				"%d flags 0x%x received -- dropping\n",
496c187222hselasky				p_mad->mgmt_class, p_mad->method,
497c187222hselasky				((ib_rmpp_mad_t *) p_mad)->rmpp_version,
498c187222hselasky				((ib_rmpp_mad_t *) p_mad)->rmpp_type,
499c187222hselasky				((ib_rmpp_mad_t *) p_mad)->rmpp_flags);
5005115240jeff			osm_mad_pool_put(p_bind->p_mad_pool, p_madw);
5015115240jeff			continue;
5025115240jeff		}
5035115240jeff#endif
5045115240jeff
5055115240jeff		/* call the CB */
5065115240jeff		pthread_mutex_lock(&p_vend->cb_mutex);
5075115240jeff		pthread_cleanup_push(unlock_mutex, &p_vend->cb_mutex);
5085115240jeff		(*p_bind->mad_recv_callback) (p_madw, p_bind->client_context,
5095115240jeff					      p_req_madw);
5105115240jeff		pthread_cleanup_pop(1);
5115115240jeff	}
5125115240jeff
5135115240jeff	OSM_LOG_EXIT(p_vend->p_log);
5145115240jeff	return NULL;
5155115240jeff}
5165115240jeff
5175115240jeffstatic int umad_receiver_start(osm_vendor_t * p_vend)
5185115240jeff{
5195115240jeff	umad_receiver_t *p_ur = p_vend->receiver;
5205115240jeff
5215115240jeff	p_ur->p_vend = p_vend;
5225115240jeff	p_ur->p_log = p_vend->p_log;
5235115240jeff
524c187222hselasky	if (pthread_create(&p_ur->tid, NULL, umad_receiver, p_ur) != 0)
5255115240jeff		return -1;
5265115240jeff
5275115240jeff	return 0;
5285115240jeff}
5295115240jeff
5305115240jeffstatic void umad_receiver_stop(umad_receiver_t * p_ur)
5315115240jeff{
5325115240jeff	pthread_cancel(p_ur->tid);
5335115240jeff	pthread_join(p_ur->tid, NULL);
5345115240jeff	p_ur->tid = 0;
5355115240jeff	p_ur->p_vend = NULL;
5365115240jeff	p_ur->p_log = NULL;
5375115240jeff}
5385115240jeff
5395115240jeffib_api_status_t
5405115240jeffosm_vendor_init(IN osm_vendor_t * const p_vend,
5415115240jeff		IN osm_log_t * const p_log, IN const uint32_t timeout)
5425115240jeff{
5435115240jeff	char *max = NULL;
5445115240jeff	int r, n_cas;
5455115240jeff
5465115240jeff	OSM_LOG_ENTER(p_log);
5475115240jeff
5485115240jeff	p_vend->p_log = p_log;
5495115240jeff	p_vend->timeout = timeout;
5505115240jeff	p_vend->max_retries = OSM_DEFAULT_RETRY_COUNT;
5515115240jeff	pthread_mutex_init(&p_vend->cb_mutex, NULL);
5525115240jeff	pthread_mutex_init(&p_vend->match_tbl_mutex, NULL);
5535115240jeff	p_vend->umad_port_id = -1;
5545115240jeff	p_vend->issmfd = -1;
5555115240jeff
5565115240jeff	/*
5575115240jeff	 * Open our instance of UMAD.
5585115240jeff	 */
5595115240jeff	if ((r = umad_init()) < 0) {
5605115240jeff		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR,
5615115240jeff			"ERR 5415: Error opening UMAD\n");
5625115240jeff	}
5635115240jeff
5645115240jeff	if ((n_cas = umad_get_cas_names(p_vend->ca_names,
5655115240jeff					OSM_UMAD_MAX_CAS)) < 0) {
5665115240jeff		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR,
5675115240jeff			"ERR 5416: umad_get_cas_names failed\n");
5685115240jeff		r = n_cas;
5695115240jeff		goto Exit;
5705115240jeff	}
5715115240jeff
5725115240jeff	p_vend->ca_count = n_cas;
5735115240jeff	p_vend->mtbl.max = DEFAULT_OSM_UMAD_MAX_PENDING;
5745115240jeff
5755115240jeff	if ((max = getenv("OSM_UMAD_MAX_PENDING")) != NULL) {
5765115240jeff		int tmp = strtol(max, NULL, 0);
5775115240jeff		if (tmp > 0)
5785115240jeff			p_vend->mtbl.max = tmp;
5795115240jeff		else
5805115240jeff			OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "Error:"
581c187222hselasky				"OSM_UMAD_MAX_PENDING=%d is invalid\n",
5825115240jeff				tmp);
5835115240jeff	}
5845115240jeff
5855115240jeff	OSM_LOG(p_vend->p_log, OSM_LOG_INFO, "%d pending umads specified\n",
5865115240jeff		p_vend->mtbl.max);
5875115240jeff
5885115240jeff	p_vend->mtbl.tbl = calloc(p_vend->mtbl.max, sizeof(*(p_vend->mtbl.tbl)));
5895115240jeff	if (!p_vend->mtbl.tbl) {
5905115240jeff		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "Error:"
5915115240jeff			"failed to allocate vendor match table\n");
5925115240jeff		r = IB_INSUFFICIENT_MEMORY;
5935115240jeff		goto Exit;
5945115240jeff	}
5955115240jeff
5965115240jeffExit:
5975115240jeff	OSM_LOG_EXIT(p_log);
5985115240jeff	return (r);
5995115240jeff}
6005115240jeff
6015115240jeffosm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log,
6025115240jeff			     IN const uint32_t timeout)
6035115240jeff{
6045115240jeff	osm_vendor_t *p_vend = NULL;
6055115240jeff
6065115240jeff	OSM_LOG_ENTER(p_log);
6075115240jeff
6085115240jeff	if (!timeout) {
6095115240jeff		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 5433: "
6105115240jeff			"transaction timeout cannot be 0\n");
6115115240jeff		goto Exit;
6125115240jeff	}
6135115240jeff
6145115240jeff	p_vend = malloc(sizeof(*p_vend));
6155115240jeff	if (p_vend == NULL) {
6165115240jeff		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 5417: "
6175115240jeff			"Unable to allocate vendor object\n");
6185115240jeff		goto Exit;
6195115240jeff	}
6205115240jeff
6215115240jeff	memset(p_vend, 0, sizeof(*p_vend));
6225115240jeff
623c187222hselasky	if (osm_vendor_init(p_vend, p_log, timeout) != IB_SUCCESS) {
6245115240jeff		free(p_vend);
6255115240jeff		p_vend = NULL;
6265115240jeff	}
6275115240jeff
6285115240jeffExit:
6295115240jeff	OSM_LOG_EXIT(p_log);
6305115240jeff	return (p_vend);
6315115240jeff}
6325115240jeff
6335115240jeffvoid osm_vendor_delete(IN osm_vendor_t ** const pp_vend)
6345115240jeff{
6355115240jeff	osm_vendor_close_port(*pp_vend);
6365115240jeff
6375115240jeff	clear_madw(*pp_vend);
6385115240jeff	/* make sure all ports are closed */
6395115240jeff	umad_done();
6405115240jeff
6415115240jeff	pthread_mutex_destroy(&(*pp_vend)->cb_mutex);
6425115240jeff	pthread_mutex_destroy(&(*pp_vend)->match_tbl_mutex);
6435115240jeff	free((*pp_vend)->mtbl.tbl);
6445115240jeff	free(*pp_vend);
6455115240jeff	*pp_vend = NULL;
6465115240jeff}
6475115240jeff
6485115240jeffib_api_status_t
6495115240jeffosm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend,
6505115240jeff			     IN ib_port_attr_t * const p_attr_array,
6515115240jeff			     IN uint32_t * const p_num_ports)
6525115240jeff{
6535115240jeff	umad_ca_t ca;
6545115240jeff	ib_port_attr_t *attr = p_attr_array;
6555115240jeff	unsigned done = 0;
656c187222hselasky	int r = 0, i, j, k;
6575115240jeff
6585115240jeff	OSM_LOG_ENTER(p_vend->p_log);
6595115240jeff
6605115240jeff	CL_ASSERT(p_vend && p_num_ports);
6615115240jeff
6625115240jeff	if (!*p_num_ports) {
6635115240jeff		r = IB_INVALID_PARAMETER;
6645115240jeff		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5418: "
6655115240jeff			"Ports in should be > 0\n");
6665115240jeff		goto Exit;
6675115240jeff	}
6685115240jeff
6695115240jeff	if (!p_attr_array) {
6705115240jeff		r = IB_INSUFFICIENT_MEMORY;
6715115240jeff		*p_num_ports = 0;
6725115240jeff		goto Exit;
6735115240jeff	}
6745115240jeff
6755115240jeff	for (i = 0; i < p_vend->ca_count && !done; i++) {
676c187222hselasky		/* For each CA, retrieve the port attributes */
6775115240jeff		if (umad_get_ca(p_vend->ca_names[i], &ca) == 0) {
6785115240jeff			if (ca.node_type < 1 || ca.node_type > 3)
6795115240jeff				continue;
6805115240jeff			for (j = 0; j <= ca.numports; j++) {
6815115240jeff				if (!ca.ports[j])
6825115240jeff					continue;
6835115240jeff				attr->port_guid = ca.ports[j]->port_guid;
6845115240jeff				attr->lid = ca.ports[j]->base_lid;
6855115240jeff				attr->port_num = ca.ports[j]->portnum;
6865115240jeff				attr->sm_lid = ca.ports[j]->sm_lid;
687c187222hselasky				attr->sm_sl = ca.ports[j]->sm_sl;
6885115240jeff				attr->link_state = ca.ports[j]->state;
689c187222hselasky				if (attr->num_pkeys && attr->p_pkey_table) {
690c187222hselasky					if (attr->num_pkeys > ca.ports[j]->pkeys_size)
691c187222hselasky						attr->num_pkeys = ca.ports[j]->pkeys_size;
692c187222hselasky					for (k = 0; k < attr->num_pkeys; k++)
693c187222hselasky						attr->p_pkey_table[k] =
694c187222hselasky							cl_hton16(ca.ports[j]->pkeys[k]);
695c187222hselasky				}
696c187222hselasky				attr->num_pkeys = ca.ports[j]->pkeys_size;
697c187222hselasky				if (attr->num_gids && attr->p_gid_table) {
698c187222hselasky					attr->p_gid_table[0].unicast.prefix = cl_hton64(ca.ports[j]->gid_prefix);
699c187222hselasky					attr->p_gid_table[0].unicast.interface_id = cl_hton64(ca.ports[j]->port_guid);
700c187222hselasky					attr->num_gids = 1;
701c187222hselasky				}
7025115240jeff				attr++;
7035115240jeff				if (attr - p_attr_array > *p_num_ports) {
7045115240jeff					done = 1;
7055115240jeff					break;
7065115240jeff				}
7075115240jeff			}
7085115240jeff			umad_release_ca(&ca);
7095115240jeff		}
7105115240jeff	}
7115115240jeff
7125115240jeff	*p_num_ports = attr - p_attr_array;
7135115240jeff
7145115240jeffExit:
7155115240jeff	OSM_LOG_EXIT(p_vend->p_log);
7165115240jeff	return r;
7175115240jeff}
7185115240jeff
7195115240jeffstatic int
7205115240jeffosm_vendor_open_port(IN osm_vendor_t * const p_vend,
7215115240jeff		     IN const ib_net64_t port_guid)
7225115240jeff{
7235115240jeff	ib_net64_t portguids[OSM_UMAD_MAX_PORTS_PER_CA + 1];
7245115240jeff	umad_ca_t umad_ca;
7255115240jeff	int i = 0, umad_port_id = -1;
7265115240jeff	char *name;
7275115240jeff	int ca, r;
7285115240jeff
7295115240jeff	CL_ASSERT(p_vend);
7305115240jeff
7315115240jeff	OSM_LOG_ENTER(p_vend->p_log);
7325115240jeff
7335115240jeff	if (p_vend->umad_port_id >= 0) {
7345115240jeff		umad_port_id = p_vend->umad_port_id;
7355115240jeff		goto Exit;
7365115240jeff	}
7375115240jeff
7385115240jeff	if (!port_guid) {
7395115240jeff		name = NULL;
7405115240jeff		i = 0;
7415115240jeff		goto _found;
7425115240jeff	}
7435115240jeff
7445115240jeff	for (ca = 0; ca < p_vend->ca_count; ca++) {
745c187222hselasky		if ((r = umad_get_ca_portguids(p_vend->ca_names[ca], portguids,
746c187222hselasky					       OSM_UMAD_MAX_PORTS_PER_CA + 1)) < 0) {
747c187222hselasky#ifdef __WIN__
748c187222hselasky			OSM_LOG(p_vend->p_log, OSM_LOG_VERBOSE,
749c187222hselasky#else
7505115240jeff			OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5421: "
751c187222hselasky#endif
7525115240jeff				"Unable to get CA %s port guids (%s)\n",
7535115240jeff				p_vend->ca_names[ca], strerror(r));
754c187222hselasky			continue;
7555115240jeff		}
7565115240jeff		for (i = 0; i < r; i++)
7575115240jeff			if (port_guid == portguids[i]) {
7585115240jeff				name = p_vend->ca_names[ca];
7595115240jeff				goto _found;
7605115240jeff			}
7615115240jeff	}
7625115240jeff
7635115240jeff	/*
7645115240jeff	 * No local CA owns this guid!
7655115240jeff	 */
7665115240jeff	OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5422: "
7675115240jeff		"Unable to find requested CA guid 0x%" PRIx64 "\n",
7685115240jeff		cl_ntoh64(port_guid));
7695115240jeff	goto Exit;
7705115240jeff
7715115240jeff_found:
7725115240jeff	/* Validate that node is an IB node type (not iWARP) */
7735115240jeff	if (umad_get_ca(name, &umad_ca) < 0) {
7745115240jeff		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542A: "
7755115240jeff			"umad_get_ca() failed\n");
7765115240jeff		goto Exit;
7775115240jeff	}
7785115240jeff
7795115240jeff	if (umad_ca.node_type < 1 || umad_ca.node_type > 3) {
7805115240jeff		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542D: "
7815115240jeff			"Type %d of node \'%s\' is not an IB node type\n",
7825115240jeff			umad_ca.node_type, umad_ca.ca_name);
7835115240jeff		fprintf(stderr,
7845115240jeff			"Type %d of node \'%s\' is not an IB node type\n",
7855115240jeff			umad_ca.node_type, umad_ca.ca_name);
7865115240jeff		umad_release_ca(&umad_ca);
7875115240jeff		goto Exit;
7885115240jeff	}
7895115240jeff	umad_release_ca(&umad_ca);
7905115240jeff
7915115240jeff	/* Port found, try to open it */
7925115240jeff	if (umad_get_port(name, i, &p_vend->umad_port) < 0) {
7935115240jeff		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542B: "
7945115240jeff			"umad_get_port() failed\n");
7955115240jeff		goto Exit;
7965115240jeff	}
7975115240jeff
7985115240jeff	if ((umad_port_id = umad_open_port(p_vend->umad_port.ca_name,
7995115240jeff					   p_vend->umad_port.portnum)) < 0) {
8005115240jeff		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542C: "
8015115240jeff			"umad_open_port() failed\n");
8025115240jeff		goto Exit;
8035115240jeff	}
8045115240jeff
8055115240jeff	p_vend->umad_port_id = umad_port_id;
8065115240jeff
8075115240jeff	/* start receiver thread */
8085115240jeff	if (!(p_vend->receiver = calloc(1, sizeof(umad_receiver_t)))) {
8095115240jeff		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5423: "
8105115240jeff			"Unable to alloc receiver struct\n");
8115115240jeff		umad_close_port(umad_port_id);
8125115240jeff		umad_release_port(&p_vend->umad_port);
8135115240jeff		p_vend->umad_port.port_guid = 0;
8145115240jeff		p_vend->umad_port_id = umad_port_id = -1;
8155115240jeff		goto Exit;
8165115240jeff	}
8175115240jeff	if (umad_receiver_start(p_vend) != 0) {
8185115240jeff		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5420: "
8195115240jeff			"umad_receiver_init failed\n");
8205115240jeff		umad_close_port(umad_port_id);
8215115240jeff		umad_release_port(&p_vend->umad_port);
8225115240jeff		p_vend->umad_port.port_guid = 0;
8235115240jeff		p_vend->umad_port_id = umad_port_id = -1;
8245115240jeff	}
8255115240jeff
8265115240jeffExit:
8275115240jeff	OSM_LOG_EXIT(p_vend->p_log);
8285115240jeff	return umad_port_id;
8295115240jeff}
8305115240jeff
8315115240jeffstatic void osm_vendor_close_port(osm_vendor_t * const p_vend)
8325115240jeff{
8335115240jeff	umad_receiver_t *p_ur;
8345115240jeff	int i;
8355115240jeff
8365115240jeff	p_ur = p_vend->receiver;
8375115240jeff	p_vend->receiver = NULL;
8385115240jeff	if (p_ur) {
8395115240jeff		umad_receiver_stop(p_ur);
8405115240jeff		free(p_ur);
8415115240jeff	}
8425115240jeff
8435115240jeff	if (p_vend->umad_port_id >= 0) {
844c187222hselasky		for (i = 0; i < OSM_UMAD_MAX_AGENTS; i++)
8455115240jeff			if (p_vend->agents[i])
8465115240jeff				umad_unregister(p_vend->umad_port_id, i);
8475115240jeff		umad_close_port(p_vend->umad_port_id);
8485115240jeff		umad_release_port(&p_vend->umad_port);
8495115240jeff		p_vend->umad_port.port_guid = 0;
8505115240jeff		p_vend->umad_port_id = -1;
8515115240jeff	}
8525115240jeff}
8535115240jeff
8545115240jeffstatic int set_bit(int nr, void *method_mask)
8555115240jeff{
8565115240jeff	long mask, *addr = method_mask;
8575115240jeff	int retval;
8585115240jeff
8595115240jeff	addr += nr / (8 * sizeof(long));
8605115240jeff	mask = 1L << (nr % (8 * sizeof(long)));
8615115240jeff	retval = (mask & *addr) != 0;
8625115240jeff	*addr |= mask;
8635115240jeff	return retval;
8645115240jeff}
8655115240jeff
8665115240jeffosm_bind_handle_t
8675115240jeffosm_vendor_bind(IN osm_vendor_t * const p_vend,
8685115240jeff		IN osm_bind_info_t * const p_user_bind,
8695115240jeff		IN osm_mad_pool_t * const p_mad_pool,
8705115240jeff		IN osm_vend_mad_recv_callback_t mad_recv_callback,
8715115240jeff		IN osm_vend_mad_send_err_callback_t send_err_callback,
8725115240jeff		IN void *context)
8735115240jeff{
8745115240jeff	ib_net64_t port_guid;
8755115240jeff	osm_umad_bind_info_t *p_bind = 0;
8765115240jeff	long method_mask[16 / sizeof(long)];
8775115240jeff	int umad_port_id;
8785115240jeff	uint8_t rmpp_version;
8795115240jeff
8805115240jeff	OSM_LOG_ENTER(p_vend->p_log);
8815115240jeff
8825115240jeff	CL_ASSERT(p_user_bind);
8835115240jeff	CL_ASSERT(p_mad_pool);
8845115240jeff	CL_ASSERT(mad_recv_callback);
8855115240jeff	CL_ASSERT(send_err_callback);
8865115240jeff
8875115240jeff	port_guid = p_user_bind->port_guid;
8885115240jeff
8895115240jeff	OSM_LOG(p_vend->p_log, OSM_LOG_INFO,
890c187222hselasky		"Mgmt class 0x%02x binding to port GUID 0x%" PRIx64 "\n",
891c187222hselasky		p_user_bind->mad_class, cl_ntoh64(port_guid));
8925115240jeff
8935115240jeff	if ((umad_port_id = osm_vendor_open_port(p_vend, port_guid)) < 0) {
8945115240jeff		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5424: "
8955115240jeff			"Unable to open port 0x%" PRIx64 "\n",
8965115240jeff			cl_ntoh64(port_guid));
8975115240jeff		goto Exit;
8985115240jeff	}
8995115240jeff
9005115240jeff	if (umad_get_issm_path(p_vend->umad_port.ca_name,
9015115240jeff			       p_vend->umad_port.portnum,
9025115240jeff			       p_vend->issm_path,
9035115240jeff			       sizeof(p_vend->issm_path)) < 0) {
9045115240jeff		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542E: "
9055115240jeff			"Cannot resolve issm path for port %s:%u\n",
9065115240jeff			p_vend->umad_port.ca_name, p_vend->umad_port.portnum);
9075115240jeff		goto Exit;
9085115240jeff	}
9095115240jeff
9105115240jeff	if (!(p_bind = malloc(sizeof(*p_bind)))) {
9115115240jeff		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5425: "
9125115240jeff			"Unable to allocate internal bind object\n");
9135115240jeff		goto Exit;
9145115240jeff	}
9155115240jeff
9165115240jeff	memset(p_bind, 0, sizeof(*p_bind));
9175115240jeff	p_bind->p_vend = p_vend;
9185115240jeff	p_bind->port_id = umad_port_id;
9195115240jeff	p_bind->client_context = context;
9205115240jeff	p_bind->mad_recv_callback = mad_recv_callback;
9215115240jeff	p_bind->send_err_callback = send_err_callback;
9225115240jeff	p_bind->p_mad_pool = p_mad_pool;
9235115240jeff	p_bind->port_guid = port_guid;
924c187222hselasky	p_bind->timeout = p_user_bind->timeout ? p_user_bind->timeout :
925c187222hselasky			  p_vend->timeout;
926c187222hselasky	p_bind->max_retries = p_user_bind->retries ? p_user_bind->retries :
927c187222hselasky			      p_vend->max_retries;
9285115240jeff
9295115240jeff	memset(method_mask, 0, sizeof method_mask);
9305115240jeff	if (p_user_bind->is_responder) {
9315115240jeff		set_bit(IB_MAD_METHOD_GET, &method_mask);
9325115240jeff		set_bit(IB_MAD_METHOD_SET, &method_mask);
9335115240jeff		if (p_user_bind->mad_class == IB_MCLASS_SUBN_ADM) {
9345115240jeff			set_bit(IB_MAD_METHOD_GETTABLE, &method_mask);
9355115240jeff			set_bit(IB_MAD_METHOD_DELETE, &method_mask);
9365115240jeff#ifdef DUAL_SIDED_RMPP
9375115240jeff			set_bit(IB_MAD_METHOD_GETMULTI, &method_mask);
9385115240jeff#endif
9395115240jeff			/* Add in IB_MAD_METHOD_GETTRACETABLE */
9405115240jeff			/* when supported by OpenSM */
9415115240jeff		}
9425115240jeff	}
9435115240jeff	if (p_user_bind->is_report_processor)
9445115240jeff		set_bit(IB_MAD_METHOD_REPORT, &method_mask);
9455115240jeff	if (p_user_bind->is_trap_processor) {
9465115240jeff		set_bit(IB_MAD_METHOD_TRAP, &method_mask);
9475115240jeff		set_bit(IB_MAD_METHOD_TRAP_REPRESS, &method_mask);
9485115240jeff	}
9495115240jeff#ifndef VENDOR_RMPP_SUPPORT
9505115240jeff	rmpp_version = 0;
9515115240jeff#else
9525115240jeff	/* If SA class, set rmpp_version */
9535115240jeff	if (p_user_bind->mad_class == IB_MCLASS_SUBN_ADM)
9545115240jeff		rmpp_version = 1;
9555115240jeff	else
9565115240jeff		rmpp_version = 0;
9575115240jeff#endif
9585115240jeff
9595115240jeff	if ((p_bind->agent_id = umad_register(p_vend->umad_port_id,
9605115240jeff					      p_user_bind->mad_class,
9615115240jeff					      p_user_bind->class_version,
9625115240jeff					      rmpp_version, method_mask)) < 0) {
9635115240jeff		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5426: "
9645115240jeff			"Unable to register class %u version %u\n",
9655115240jeff			p_user_bind->mad_class, p_user_bind->class_version);
9665115240jeff		free(p_bind);
9675115240jeff		p_bind = 0;
9685115240jeff		goto Exit;
9695115240jeff	}
9705115240jeff
971c187222hselasky	if (p_bind->agent_id >= OSM_UMAD_MAX_AGENTS ||
9725115240jeff	    p_vend->agents[p_bind->agent_id]) {
9735115240jeff		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5427: "
9745115240jeff			"bad agent id %u or duplicate agent for class %u vers %u\n",
9755115240jeff			p_bind->agent_id, p_user_bind->mad_class,
9765115240jeff			p_user_bind->class_version);
9775115240jeff		free(p_bind);
9785115240jeff		p_bind = 0;
9795115240jeff		goto Exit;
9805115240jeff	}
9815115240jeff
9825115240jeff	p_vend->agents[p_bind->agent_id] = p_bind;
9835115240jeff
9845115240jeff	/* If Subn Directed Route class, register Subn LID routed class */
9855115240jeff	if (p_user_bind->mad_class == IB_MCLASS_SUBN_DIR) {
9865115240jeff		if ((p_bind->agent_id1 = umad_register(p_vend->umad_port_id,
9875115240jeff						       IB_MCLASS_SUBN_LID,
9885115240jeff						       p_user_bind->
9895115240jeff						       class_version, 0,
9905115240jeff						       method_mask)) < 0) {
9915115240jeff			OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5428: "
9925115240jeff				"Unable to register class 1 version %u\n",
9935115240jeff				p_user_bind->class_version);
9945115240jeff			free(p_bind);
9955115240jeff			p_bind = 0;
9965115240jeff			goto Exit;
9975115240jeff		}
9985115240jeff
999c187222hselasky		if (p_bind->agent_id1 >= OSM_UMAD_MAX_AGENTS ||
10005115240jeff		    p_vend->agents[p_bind->agent_id1]) {
10015115240jeff			OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5429: "
10025115240jeff				"bad agent id %u or duplicate agent for class 1 vers %u\n",
10035115240jeff				p_bind->agent_id1, p_user_bind->class_version);
10045115240jeff			free(p_bind);
10055115240jeff			p_bind = 0;
10065115240jeff			goto Exit;
10075115240jeff		}
10085115240jeff
10095115240jeff		p_vend->agents[p_bind->agent_id1] = p_bind;
10105115240jeff	}
10115115240jeff
10125115240jeffExit:
10135115240jeff	OSM_LOG_EXIT(p_vend->p_log);
10145115240jeff	return ((osm_bind_handle_t) p_bind);
10155115240jeff}
10165115240jeff
10175115240jeffstatic void
10185115240jeff__osm_vendor_recv_dummy_cb(IN osm_madw_t * p_madw,
10195115240jeff			   IN void *bind_context, IN osm_madw_t * p_req_madw)
10205115240jeff{
10215115240jeff#ifdef _DEBUG_
10225115240jeff	fprintf(stderr,
10235115240jeff		"__osm_vendor_recv_dummy_cb: Ignoring received MAD after osm_vendor_unbind\n");
10245115240jeff#endif
10255115240jeff}
10265115240jeff
10275115240jeffstatic void
10285115240jeff__osm_vendor_send_err_dummy_cb(IN void *bind_context,
10295115240jeff			       IN osm_madw_t * p_req_madw)
10305115240jeff{
10315115240jeff#ifdef _DEBUG_
10325115240jeff	fprintf(stderr,
10335115240jeff		"__osm_vendor_send_err_dummy_cb: Ignoring send error after osm_vendor_unbind\n");
10345115240jeff#endif
10355115240jeff}
10365115240jeff
10375115240jeffvoid osm_vendor_unbind(IN osm_bind_handle_t h_bind)
10385115240jeff{
10395115240jeff	osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind;
10405115240jeff	osm_vendor_t *p_vend = p_bind->p_vend;
10415115240jeff
10425115240jeff	OSM_LOG_ENTER(p_vend->p_log);
10435115240jeff
10445115240jeff	pthread_mutex_lock(&p_vend->cb_mutex);
10455115240jeff	p_bind->mad_recv_callback = __osm_vendor_recv_dummy_cb;
10465115240jeff	p_bind->send_err_callback = __osm_vendor_send_err_dummy_cb;
10475115240jeff	pthread_mutex_unlock(&p_vend->cb_mutex);
10485115240jeff
10495115240jeff	OSM_LOG_EXIT(p_vend->p_log);
10505115240jeff}
10515115240jeff
10525115240jeffib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind,
10535115240jeff			 IN const uint32_t mad_size,
10545115240jeff			 IN osm_vend_wrap_t * const p_vw)
10555115240jeff{
10565115240jeff	osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind;
10575115240jeff	osm_vendor_t *p_vend = p_bind->p_vend;
10585115240jeff
10595115240jeff	OSM_LOG_ENTER(p_vend->p_log);
10605115240jeff
10615115240jeff	OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG,
10625115240jeff		"Acquiring UMAD for p_madw = %p, size = %u\n", p_vw, mad_size);
10635115240jeff	CL_ASSERT(p_vw);
10645115240jeff	p_vw->size = mad_size;
10655115240jeff	p_vw->umad = umad_alloc(1, mad_size + umad_size());
10665115240jeff
10675115240jeff	/* track locally */
10685115240jeff	p_vw->h_bind = h_bind;
10695115240jeff
10705115240jeff	OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG,
10715115240jeff		"Acquired UMAD %p, size = %u\n", p_vw->umad, p_vw->size);
10725115240jeff
10735115240jeff	OSM_LOG_EXIT(p_vend->p_log);
1074c187222hselasky	return (p_vw->umad ? umad_get_mad(p_vw->umad) : NULL);
10755115240jeff}
10765115240jeff
10775115240jeffvoid
10785115240jeffosm_vendor_put(IN osm_bind_handle_t h_bind, IN osm_vend_wrap_t * const p_vw)
10795115240jeff{
10805115240jeff	osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind;
10815115240jeff	osm_vendor_t *p_vend = p_bind->p_vend;
10825115240jeff	osm_madw_t *p_madw;
10835115240jeff
10845115240jeff	OSM_LOG_ENTER(p_vend->p_log);
10855115240jeff
10865115240jeff	CL_ASSERT(p_vw);
10875115240jeff
10885115240jeff	OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG, "Retiring UMAD %p\n", p_vw->umad);
10895115240jeff
10905115240jeff	/*
10915115240jeff	 * We moved the removal of the transaction to immediately after
10925115240jeff	 * it was looked up.
10935115240jeff	 */
10945115240jeff
10955115240jeff	/* free the mad but the wrapper is part of the madw object */
10965115240jeff	umad_free(p_vw->umad);
10975115240jeff	p_vw->umad = 0;
10985115240jeff	p_madw = PARENT_STRUCT(p_vw, osm_madw_t, vend_wrap);
10995115240jeff	p_madw->p_mad = NULL;
11005115240jeff
11015115240jeff	OSM_LOG_EXIT(p_vend->p_log);
11025115240jeff}
11035115240jeff
11045115240jeffib_api_status_t
11055115240jeffosm_vendor_send(IN osm_bind_handle_t h_bind,
11065115240jeff		IN osm_madw_t * const p_madw, IN boolean_t const resp_expected)
11075115240jeff{
11085115240jeff	osm_umad_bind_info_t *const p_bind = h_bind;
11095115240jeff	osm_vendor_t *const p_vend = p_bind->p_vend;
11105115240jeff	osm_vend_wrap_t *const p_vw = osm_madw_get_vend_ptr(p_madw);
11115115240jeff	osm_mad_addr_t *const p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw);
11125115240jeff	ib_mad_t *const p_mad = osm_madw_get_mad_ptr(p_madw);
11135115240jeff	ib_sa_mad_t *const p_sa = (ib_sa_mad_t *) p_mad;
1114c187222hselasky	ib_mad_addr_t mad_addr;
11155115240jeff	int ret = -1;
1116c187222hselasky	int __attribute__((__unused__)) is_rmpp = 0;
11175115240jeff	uint32_t sent_mad_size;
1118c187222hselasky	uint64_t tid;
11195115240jeff#ifndef VENDOR_RMPP_SUPPORT
11205115240jeff	uint32_t paylen = 0;
11215115240jeff#endif
11225115240jeff
11235115240jeff	OSM_LOG_ENTER(p_vend->p_log);
11245115240jeff
11255115240jeff	CL_ASSERT(p_vw->h_bind == h_bind);
11265115240jeff	CL_ASSERT(p_mad == umad_get_mad(p_vw->umad));
11275115240jeff
11285115240jeff	if (p_mad->mgmt_class == IB_MCLASS_SUBN_DIR) {
11295115240jeff		umad_set_addr_net(p_vw->umad, 0xffff, 0, 0, 0);
1130c187222hselasky		umad_set_grh(p_vw->umad, NULL);
11315115240jeff		goto Resp;
11325115240jeff	}
11335115240jeff	if (p_mad->mgmt_class == IB_MCLASS_SUBN_LID) {
11345115240jeff		umad_set_addr_net(p_vw->umad, p_mad_addr->dest_lid, 0, 0, 0);
1135c187222hselasky		umad_set_grh(p_vw->umad, NULL);
11365115240jeff		goto Resp;
11375115240jeff	}
1138c187222hselasky	/* GS classes */
11395115240jeff	umad_set_addr_net(p_vw->umad, p_mad_addr->dest_lid,
11405115240jeff			  p_mad_addr->addr_type.gsi.remote_qp,
11415115240jeff			  p_mad_addr->addr_type.gsi.service_level,
11425115240jeff			  IB_QP1_WELL_KNOWN_Q_KEY);
1143c187222hselasky	if (p_mad_addr->addr_type.gsi.global_route) {
1144c187222hselasky		mad_addr.grh_present = 1;
1145c187222hselasky		mad_addr.gid_index = 0;
1146c187222hselasky		mad_addr.hop_limit = p_mad_addr->addr_type.gsi.grh_info.hop_limit;
1147c187222hselasky		ib_grh_get_ver_class_flow(p_mad_addr->addr_type.gsi.grh_info.ver_class_flow,
1148c187222hselasky					  NULL, &mad_addr.traffic_class,
1149c187222hselasky					  &mad_addr.flow_label);
1150c187222hselasky		memcpy(&mad_addr.gid, &p_mad_addr->addr_type.gsi.grh_info.dest_gid, 16);
1151c187222hselasky		umad_set_grh(p_vw->umad, &mad_addr);
1152c187222hselasky	} else
1153c187222hselasky		umad_set_grh(p_vw->umad, NULL);
11545115240jeff	umad_set_pkey(p_vw->umad, p_mad_addr->addr_type.gsi.pkey_ix);
1155c187222hselasky	if (ib_class_is_rmpp(p_mad->mgmt_class)) {	/* RMPP GS classes */
11565115240jeff		if (!ib_rmpp_is_flag_set((ib_rmpp_mad_t *) p_sa,
11575115240jeff					 IB_RMPP_FLAG_ACTIVE)) {
11585115240jeff			/* Clear RMPP header when RMPP not ACTIVE */
11595115240jeff			p_sa->rmpp_version = 0;
11605115240jeff			p_sa->rmpp_type = 0;
11615115240jeff			p_sa->rmpp_flags = 0;
11625115240jeff			p_sa->rmpp_status = 0;
11635115240jeff#ifdef VENDOR_RMPP_SUPPORT
11645115240jeff		} else
11655115240jeff			is_rmpp = 1;
1166c187222hselasky		OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG, "RMPP %d length %d\n",
11675115240jeff			ib_rmpp_is_flag_set((ib_rmpp_mad_t *) p_sa,
11685115240jeff					    IB_RMPP_FLAG_ACTIVE),
11695115240jeff			p_madw->mad_size);
11705115240jeff#else
11715115240jeff		} else {
11725115240jeff			p_sa->rmpp_version = 1;
11735115240jeff			p_sa->seg_num = cl_ntoh32(1);	/* first DATA is seg 1 */
11745115240jeff			p_sa->rmpp_flags |= (uint8_t) 0x70;	/* RRespTime of 14 (high 5 bits) */
11755115240jeff			p_sa->rmpp_status = 0;
11765115240jeff			paylen = p_madw->mad_size - IB_SA_MAD_HDR_SIZE;
11775115240jeff			paylen += (IB_SA_MAD_HDR_SIZE - MAD_RMPP_HDR_SIZE);
11785115240jeff			p_sa->paylen_newwin = cl_ntoh32(paylen);
11795115240jeff		}
11805115240jeff#endif
11815115240jeff	}
11825115240jeff
11835115240jeffResp:
11845115240jeff	if (resp_expected)
1185c187222hselasky		put_madw(p_vend, p_madw, p_mad->trans_id, p_mad->mgmt_class);
11865115240jeff
11875115240jeff#ifdef VENDOR_RMPP_SUPPORT
11885115240jeff	sent_mad_size = p_madw->mad_size;
11895115240jeff#else
11905115240jeff	sent_mad_size = is_rmpp ? p_madw->mad_size - IB_SA_MAD_HDR_SIZE :
11915115240jeff	    p_madw->mad_size;
11925115240jeff#endif
1193c187222hselasky	tid = cl_ntoh64(p_mad->trans_id);
11945115240jeff	if ((ret = umad_send(p_bind->port_id, p_bind->agent_id, p_vw->umad,
11955115240jeff			     sent_mad_size,
1196c187222hselasky			     resp_expected ? p_bind->timeout : 0,
1197c187222hselasky			     p_bind->max_retries)) < 0) {
11985115240jeff		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5430: "
1199c187222hselasky			"Send p_madw = %p of size %d, Class 0x%x, Method 0x%X, "
1200c187222hselasky			"Attr 0x%X, TID 0x%" PRIx64 " failed %d (%m)\n",
1201c187222hselasky			p_madw, sent_mad_size, p_mad->mgmt_class,
1202c187222hselasky			p_mad->method, cl_ntoh16(p_mad->attr_id), tid, ret);
12035115240jeff		if (resp_expected) {
1204c187222hselasky			get_madw(p_vend, &p_mad->trans_id,
1205c187222hselasky				 p_mad->mgmt_class);	/* remove from aging table */
12065115240jeff			p_madw->status = IB_ERROR;
12075115240jeff			pthread_mutex_lock(&p_vend->cb_mutex);
12085115240jeff			(*p_bind->send_err_callback) (p_bind->client_context, p_madw);	/* cb frees madw */
12095115240jeff			pthread_mutex_unlock(&p_vend->cb_mutex);
12105115240jeff		} else
12115115240jeff			osm_mad_pool_put(p_bind->p_mad_pool, p_madw);
12125115240jeff		goto Exit;
12135115240jeff	}
12145115240jeff
12155115240jeff	if (!resp_expected)
12165115240jeff		osm_mad_pool_put(p_bind->p_mad_pool, p_madw);
12175115240jeff
1218c187222hselasky	OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG, "Completed sending %s TID 0x%" PRIx64 "\n",
1219c187222hselasky		resp_expected ? "request" : "response or unsolicited", tid);
12205115240jeffExit:
12215115240jeff	OSM_LOG_EXIT(p_vend->p_log);
12225115240jeff	return (ret);
12235115240jeff}
12245115240jeff
12255115240jeffib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind)
12265115240jeff{
12275115240jeff	osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind;
12285115240jeff	osm_vendor_t *p_vend = p_bind->p_vend;
12295115240jeff
12305115240jeff	OSM_LOG_ENTER(p_vend->p_log);
12315115240jeff	;
12325115240jeff	OSM_LOG_EXIT(p_vend->p_log);
12335115240jeff	return (0);
12345115240jeff}
12355115240jeff
12365115240jeffvoid osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val)
12375115240jeff{
12385115240jeff	osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind;
12395115240jeff	osm_vendor_t *p_vend = p_bind->p_vend;
12405115240jeff
12415115240jeff	OSM_LOG_ENTER(p_vend->p_log);
12425115240jeff	if (TRUE == is_sm_val) {
12435115240jeff		p_vend->issmfd = open(p_vend->issm_path, O_NONBLOCK);
12445115240jeff		if (p_vend->issmfd < 0) {
12455115240jeff			OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5431: "
12465115240jeff				"setting IS_SM capmask: cannot open file "
12475115240jeff				"\'%s\': %s\n",
12485115240jeff				p_vend->issm_path, strerror(errno));
12495115240jeff			p_vend->issmfd = -1;
12505115240jeff		}
12515115240jeff	} else if (p_vend->issmfd != -1) {
12525115240jeff		if (0 != close(p_vend->issmfd))
12535115240jeff			OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5432: "
12545115240jeff				"clearing IS_SM capmask: cannot close: %s\n",
12555115240jeff				strerror(errno));
12565115240jeff		p_vend->issmfd = -1;
12575115240jeff	}
12585115240jeff	OSM_LOG_EXIT(p_vend->p_log);
12595115240jeff}
12605115240jeff
12615115240jeffvoid osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level)
12625115240jeff{
12635115240jeff	umad_debug(level);
12645115240jeff}
12655115240jeff
12665115240jeff#endif				/* OSM_VENDOR_INTF_OPENIB */
1267