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