1/*
2 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5 *
6 * This software is available to you under a choice of one of two
7 * licenses.  You may choose to be licensed under the terms of the GNU
8 * General Public License (GPL) Version 2, available from the file
9 * COPYING in the main directory of this source tree, or the
10 * OpenIB.org BSD license below:
11 *
12 *     Redistribution and use in source and binary forms, with or
13 *     without modification, are permitted provided that the following
14 *     conditions are met:
15 *
16 *      - Redistributions of source code must retain the above
17 *        copyright notice, this list of conditions and the following
18 *        disclaimer.
19 *
20 *      - Redistributions in binary form must reproduce the above
21 *        copyright notice, this list of conditions and the following
22 *        disclaimer in the documentation and/or other materials
23 *        provided with the distribution.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 * SOFTWARE.
33 *
34 */
35
36/*
37 * Abstract:
38 *    Implementation of osm_req_t.
39 * This object represents the generic attribute requester.
40 * This object is part of the opensm family of objects.
41 *
42 */
43
44/*
45  Next available error code: 0x300
46*/
47
48#if HAVE_CONFIG_H
49#  include <config.h>
50#endif				/* HAVE_CONFIG_H */
51
52#ifdef OSM_VENDOR_INTF_AL
53
54#include <stdlib.h>
55#include <string.h>
56#include <complib/cl_qlist.h>
57#include <complib/cl_thread.h>
58#include <complib/cl_math.h>
59#include <complib/cl_debug.h>
60#include <iba/ib_types.h>
61#include <opensm/osm_madw.h>
62#include <opensm/osm_log.h>
63#include <opensm/osm_mad_pool.h>
64#include <vendor/osm_vendor_api.h>
65
66/****s* OpenSM: Vendor AL/osm_al_bind_info_t
67 * NAME
68 *   osm_al_bind_info_t
69 *
70 * DESCRIPTION
71 *    Structure containing bind information.
72 *
73 * SYNOPSIS
74 */
75typedef struct _osm_al_bind_info {
76	osm_vendor_t *p_vend;
77	void *client_context;
78	ib_qp_handle_t h_qp;
79	ib_mad_svc_handle_t h_svc;
80	uint8_t port_num;
81	ib_pool_key_t pool_key;
82	osm_vend_mad_recv_callback_t rcv_callback;
83	osm_vend_mad_send_err_callback_t send_err_callback;
84	osm_mad_pool_t *p_osm_pool;
85	ib_av_handle_t h_dr_av;
86
87} osm_al_bind_info_t;
88/*
89 * FIELDS
90 * p_vend
91 *    Pointer to the vendor object.
92 *
93 * client_context
94 *    User's context passed during osm_bind
95 *
96 * h_qp
97 *    Handle the QP for this bind.
98 *
99 * h_qp_svc
100 *    Handle the QP mad service for this bind.
101 *
102 * port_num
103 *    Port number (within the HCA) of the bound port.
104 *
105 * pool_key
106 *    Pool key returned by all for this QP.
107 *
108 * h_dr_av
109 *    Address vector handle used for all directed route SMPs.
110 *
111 * SEE ALSO
112 *********/
113
114/**********************************************************************
115 **********************************************************************/
116inline static ib_api_status_t
117__osm_al_convert_wcs(IN ib_wc_status_t const wc_status)
118{
119	switch (wc_status) {
120	case IB_WCS_SUCCESS:
121		return (IB_SUCCESS);
122
123	case IB_WCS_TIMEOUT_RETRY_ERR:
124		return (IB_TIMEOUT);
125
126	default:
127		return (IB_ERROR);
128	}
129}
130
131/**********************************************************************
132 **********************************************************************/
133static void __osm_al_ca_err_callback(IN ib_async_event_rec_t * p_async_rec)
134{
135	osm_vendor_t *p_vend = (osm_vendor_t *) p_async_rec->context;
136	OSM_LOG_ENTER(p_vend->p_log);
137
138	osm_log(p_vend->p_log, OSM_LOG_ERROR,
139		"__osm_al_ca_err_callback: ERR 3B01: "
140		"Event on channel adapter (%s).\n",
141		ib_get_async_event_str(p_async_rec->code));
142
143	OSM_LOG_EXIT(p_vend->p_log);
144}
145
146/**********************************************************************
147 **********************************************************************/
148static void __osm_al_ca_destroy_callback(IN void *context)
149{
150	osm_al_bind_info_t *p_bind = (osm_al_bind_info_t *) context;
151	osm_vendor_t *p_vend = p_bind->p_vend;
152	OSM_LOG_ENTER(p_vend->p_log);
153
154	osm_log(p_vend->p_log, OSM_LOG_INFO,
155		"__osm_al_ca_destroy_callback: "
156		"Closing local channel adapter.\n");
157
158	OSM_LOG_EXIT(p_vend->p_log);
159}
160
161/**********************************************************************
162 **********************************************************************/
163static void __osm_al_err_callback(IN ib_async_event_rec_t * p_async_rec)
164{
165	osm_al_bind_info_t *p_bind =
166	    (osm_al_bind_info_t *) p_async_rec->context;
167	osm_vendor_t *p_vend = p_bind->p_vend;
168	OSM_LOG_ENTER(p_vend->p_log);
169
170	osm_log(p_vend->p_log, OSM_LOG_ERROR,
171		"__osm_al_err_callback: ERR 3B02: "
172		"Error on QP (%s).\n",
173		ib_get_async_event_str(p_async_rec->code));
174
175	OSM_LOG_EXIT(p_vend->p_log);
176}
177
178/**********************************************************************
179 **********************************************************************/
180static void
181__osm_al_send_callback(IN void *mad_svc_context, IN ib_mad_element_t * p_elem)
182{
183	osm_al_bind_info_t *const p_bind =
184	    (osm_al_bind_info_t *) mad_svc_context;
185	osm_vendor_t *const p_vend = p_bind->p_vend;
186	osm_madw_t *const p_madw = (osm_madw_t *) p_elem->context1;
187	osm_vend_wrap_t *const p_vw = osm_madw_get_vend_ptr(p_madw);
188	ib_mad_t *p_mad;
189
190	OSM_LOG_ENTER(p_vend->p_log);
191
192	CL_ASSERT(p_vw);
193	CL_ASSERT(p_vw->h_av);
194
195	/*
196	   Destroy the address vector as necessary.
197	 */
198	if (p_vw->h_av != p_bind->h_dr_av) {
199		if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) {
200			osm_log(p_vend->p_log, OSM_LOG_DEBUG,
201				"__osm_al_send_callback: "
202				"Destroying av handle %p.\n", p_vw->h_av);
203		}
204
205		ib_destroy_av(p_vw->h_av);
206	}
207
208	p_mad = ib_get_mad_buf(p_elem);
209
210	if (p_elem->resp_expected) {
211		/*
212		   If the send was unsuccessful, notify the user
213		   for MADs that were expecting a response.
214		   A NULL mad wrapper parameter is the user's clue
215		   that the transaction turned sour.
216
217		   Otherwise, do nothing for successful sends when a
218		   reponse is expected.  The mad will be returned to the
219		   pool later.
220		 */
221		p_madw->status = __osm_al_convert_wcs(p_elem->status);
222		if (p_elem->status != IB_WCS_SUCCESS) {
223			osm_log(p_vend->p_log, OSM_LOG_DEBUG,
224				"__osm_al_send_callback: "
225				"MAD completed with work queue error: %s.\n",
226				ib_get_wc_status_str(p_elem->status));
227			/*
228			   Return any wrappers to the pool that may have been
229			   pre-emptively allocated to handle a receive.
230			 */
231			if (p_vw->p_resp_madw) {
232				osm_mad_pool_put(p_bind->p_osm_pool,
233						 p_vw->p_resp_madw);
234				p_vw->p_resp_madw = NULL;
235			}
236
237			p_bind->send_err_callback(p_bind->client_context,
238						  p_madw);
239		}
240	} else {
241		osm_log(p_vend->p_log, OSM_LOG_DEBUG,
242			"__osm_al_send_callback: "
243			"Returning MAD to pool, TID = 0x%" PRIx64 ".\n",
244			cl_ntoh64(p_mad->trans_id));
245		osm_mad_pool_put(p_bind->p_osm_pool, p_madw);
246		goto Exit;
247	}
248
249Exit:
250	OSM_LOG_EXIT(p_vend->p_log);
251}
252
253/**********************************************************************
254 **********************************************************************/
255static void
256__osm_al_rcv_callback(IN void *mad_svc_context, IN ib_mad_element_t * p_elem)
257{
258	osm_al_bind_info_t *const p_bind =
259	    (osm_al_bind_info_t *) mad_svc_context;
260	osm_vendor_t *const p_vend = p_bind->p_vend;
261	osm_madw_t *p_old_madw;
262	osm_madw_t *p_new_madw;
263	osm_vend_wrap_t *p_old_vw;
264	osm_vend_wrap_t *p_new_vw;
265	ib_mad_t *p_new_mad;
266	osm_mad_addr_t mad_addr;
267
268	OSM_LOG_ENTER(p_vend->p_log);
269
270	CL_ASSERT(p_elem->context1 == NULL);
271	CL_ASSERT(p_elem->context2 == NULL);
272
273	p_new_mad = ib_get_mad_buf(p_elem);
274
275	/*
276	   In preperation for initializing the new mad wrapper,
277	   Initialize the mad_addr structure for the received wire MAD.
278	 */
279	mad_addr.dest_lid = p_elem->remote_lid;
280	mad_addr.path_bits = p_elem->path_bits;
281
282	/* TO DO - figure out which #define to use for the 2.5 Gb rate... */
283	mad_addr.static_rate = 0;
284
285	if (p_new_mad->mgmt_class == IB_MCLASS_SUBN_LID ||
286	    p_new_mad->mgmt_class == IB_MCLASS_SUBN_DIR) {
287		mad_addr.addr_type.smi.source_lid = p_elem->remote_lid;
288	} else {
289		mad_addr.addr_type.gsi.remote_qp = p_elem->remote_qp;
290		mad_addr.addr_type.gsi.remote_qkey = p_elem->remote_qkey;
291		mad_addr.addr_type.gsi.pkey_ix = p_elem->pkey_index;
292		mad_addr.addr_type.gsi.service_level = p_elem->remote_sl;
293		mad_addr.addr_type.gsi.global_route = FALSE;
294	}
295
296	/*
297	   If this MAD is a response to a previous request,
298	   then grab our pre-allocated MAD wrapper.
299	   Otherwise, allocate a new MAD wrapper.
300	 */
301	if (ib_mad_is_response(p_new_mad)) {
302		CL_ASSERT(p_elem->send_context1 != NULL);
303		CL_ASSERT(p_elem->send_context2 == NULL);
304
305		p_old_madw = (osm_madw_t *) p_elem->send_context1;
306		p_old_vw = osm_madw_get_vend_ptr(p_old_madw);
307		p_new_madw = p_old_vw->p_resp_madw;
308
309		CL_ASSERT(p_new_madw);
310
311		osm_madw_init(p_new_madw, p_bind, p_elem->size, &mad_addr);
312		osm_madw_set_mad(p_new_madw, p_new_mad);
313	} else {
314		CL_ASSERT(p_elem->send_context1 == NULL);
315		CL_ASSERT(p_elem->send_context2 == NULL);
316
317		p_new_madw = osm_mad_pool_get_wrapper(p_bind->p_osm_pool,
318						      p_bind, p_elem->size,
319						      p_new_mad, &mad_addr);
320	}
321
322	CL_ASSERT(p_new_madw);
323	p_new_vw = osm_madw_get_vend_ptr(p_new_madw);
324
325	p_new_vw->h_bind = p_bind;
326	p_new_vw->size = p_elem->size;
327	p_new_vw->p_elem = p_elem;
328	p_new_vw->h_av = 0;
329	p_new_vw->p_resp_madw = NULL;
330
331	osm_log(p_vend->p_log, OSM_LOG_DEBUG,
332		"__osm_al_rcv_callback: "
333		"Calling receive callback function %p.\n",
334		p_bind->rcv_callback);
335
336	p_bind->rcv_callback(p_new_madw, p_bind->client_context,
337			     p_elem->send_context1);
338
339	OSM_LOG_EXIT(p_vend->p_log);
340}
341
342/**********************************************************************
343 **********************************************************************/
344ib_api_status_t
345osm_vendor_init(IN osm_vendor_t * const p_vend,
346		IN osm_log_t * const p_log, IN const uint32_t timeout)
347{
348	ib_api_status_t status;
349	OSM_LOG_ENTER(p_log);
350
351	p_vend->p_log = p_log;
352
353	/*
354	   Open our instance of AL.
355	 */
356	status = ib_open_al(&p_vend->h_al);
357	if (status != IB_SUCCESS) {
358		osm_log(p_vend->p_log, OSM_LOG_ERROR,
359			"osm_vendor_init: ERR 3B03: "
360			"Error opening AL (%s).\n", ib_get_err_str(status));
361
362		goto Exit;
363	}
364
365	p_vend->timeout = timeout;
366
367Exit:
368	OSM_LOG_EXIT(p_log);
369	return (status);
370}
371
372/**********************************************************************
373 **********************************************************************/
374osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log,
375			     IN const uint32_t timeout)
376{
377	ib_api_status_t status;
378	osm_vendor_t *p_vend;
379
380	OSM_LOG_ENTER(p_log);
381
382	p_vend = malloc(sizeof(*p_vend));
383	if (p_vend == NULL) {
384		osm_log(p_vend->p_log, OSM_LOG_ERROR,
385			"osm_vendor_new: ERR 3B04: "
386			"Unable to allocate vendor object.\n");
387		goto Exit;
388	}
389
390	memset(p_vend, 0, sizeof(*p_vend));
391
392	status = osm_vendor_init(p_vend, p_log, timeout);
393	if (status != IB_SUCCESS) {
394		free(p_vend);
395		p_vend = NULL;
396	}
397
398Exit:
399	OSM_LOG_EXIT(p_log);
400	return (p_vend);
401}
402
403/**********************************************************************
404 **********************************************************************/
405void osm_vendor_delete(IN osm_vendor_t ** const pp_vend)
406{
407	/* TO DO - fill this in */
408	ib_close_al((*pp_vend)->h_al);
409	free(*pp_vend);
410	*pp_vend = NULL;
411}
412
413/**********************************************************************
414 **********************************************************************/
415static ib_api_status_t
416__osm_ca_info_init(IN osm_vendor_t * const p_vend,
417		   IN osm_ca_info_t * const p_ca_info,
418		   IN const ib_net64_t ca_guid)
419{
420	ib_api_status_t status;
421
422	OSM_LOG_ENTER(p_vend->p_log);
423
424	p_ca_info->guid = ca_guid;
425
426	if (osm_log_is_active(p_vend->p_log, OSM_LOG_VERBOSE)) {
427		osm_log(p_vend->p_log, OSM_LOG_VERBOSE,
428			"__osm_ca_info_init: "
429			"Querying CA 0x%" PRIx64 ".\n", cl_ntoh64(ca_guid));
430	}
431
432	status = ib_query_ca_by_guid(p_vend->h_al, ca_guid, NULL,
433				     &p_ca_info->attr_size);
434	if ((status != IB_INSUFFICIENT_MEMORY) && (status != IB_SUCCESS)) {
435		osm_log(p_vend->p_log, OSM_LOG_ERROR,
436			"__osm_ca_info_init: ERR 3B05: "
437			"Unexpected status getting CA attributes (%s).\n",
438			ib_get_err_str(status));
439		goto Exit;
440	}
441
442	CL_ASSERT(p_ca_info->attr_size);
443
444	p_ca_info->p_attr = malloc(p_ca_info->attr_size);
445	if (p_ca_info->p_attr == NULL) {
446		osm_log(p_vend->p_log, OSM_LOG_ERROR,
447			"__osm_ca_info_init: ERR 3B06: "
448			"Unable to allocate attribute storage.\n");
449		goto Exit;
450	}
451
452	status = ib_query_ca_by_guid(p_vend->h_al, ca_guid, p_ca_info->p_attr,
453				     &p_ca_info->attr_size);
454	if (status != IB_SUCCESS) {
455		osm_log(p_vend->p_log, OSM_LOG_ERROR,
456			"__osm_ca_info_init: ERR 3B07: "
457			"Unexpected status getting CA attributes (%s).\n",
458			ib_get_err_str(status));
459		goto Exit;
460	}
461
462Exit:
463	OSM_LOG_EXIT(p_vend->p_log);
464	return (status);
465}
466
467/**********************************************************************
468 **********************************************************************/
469void
470osm_ca_info_destroy(IN osm_vendor_t * const p_vend,
471		    IN osm_ca_info_t * const p_ca_info)
472{
473	OSM_LOG_ENTER(p_vend->p_log);
474
475	if (p_ca_info->p_attr)
476		free(p_ca_info->p_attr);
477
478	free(p_ca_info);
479
480	OSM_LOG_EXIT(p_vend->p_log);
481}
482
483/**********************************************************************
484 **********************************************************************/
485osm_ca_info_t *osm_ca_info_new(IN osm_vendor_t * const p_vend,
486			       IN const ib_net64_t ca_guid)
487{
488	ib_api_status_t status;
489	osm_ca_info_t *p_ca_info;
490
491	OSM_LOG_ENTER(p_vend->p_log);
492
493	CL_ASSERT(ca_guid);
494
495	p_ca_info = malloc(sizeof(*p_ca_info));
496	if (p_ca_info == NULL)
497		goto Exit;
498
499	memset(p_ca_info, 0, sizeof(*p_ca_info));
500
501	status = __osm_ca_info_init(p_vend, p_ca_info, ca_guid);
502	if (status != IB_SUCCESS) {
503		osm_ca_info_destroy(p_vend, p_ca_info);
504		p_ca_info = NULL;
505		goto Exit;
506	}
507
508Exit:
509	OSM_LOG_EXIT(p_vend->p_log);
510	return (p_ca_info);
511}
512
513/**********************************************************************
514 **********************************************************************/
515static ib_api_status_t
516__osm_vendor_get_ca_guids(IN osm_vendor_t * const p_vend,
517			  IN ib_net64_t ** const p_guids,
518			  IN uintn_t * const p_num_guids)
519{
520	ib_api_status_t status;
521
522	OSM_LOG_ENTER(p_vend->p_log);
523
524	CL_ASSERT(p_guids);
525	CL_ASSERT(p_num_guids);
526
527	status = ib_get_ca_guids(p_vend->h_al, NULL, p_num_guids);
528	if ((status != IB_INSUFFICIENT_MEMORY) && (status != IB_SUCCESS)) {
529		osm_log(p_vend->p_log, OSM_LOG_ERROR,
530			"__osm_vendor_get_ca_guids: ERR 3B08: "
531			"Unexpected status getting CA GUID array (%s).\n",
532			ib_get_err_str(status));
533		goto Exit;
534	}
535
536	if (*p_num_guids == 0) {
537		osm_log(p_vend->p_log, OSM_LOG_ERROR,
538			"__osm_vendor_get_ca_guids: ERR 3B09: "
539			"No available channel adapters.\n");
540		status = IB_INSUFFICIENT_RESOURCES;
541		goto Exit;
542	}
543
544	*p_guids = malloc(*p_num_guids * sizeof(**p_guids));
545	if (*p_guids == NULL) {
546		osm_log(p_vend->p_log, OSM_LOG_ERROR,
547			"__osm_vendor_get_ca_guids: ERR 3B10: "
548			"Unable to allocate CA GUID array.\n");
549		goto Exit;
550	}
551
552	status = ib_get_ca_guids(p_vend->h_al, *p_guids, p_num_guids);
553	CL_ASSERT(*p_num_guids);
554
555	if (osm_log_is_active(p_vend->p_log, OSM_LOG_VERBOSE)) {
556		osm_log(p_vend->p_log, OSM_LOG_VERBOSE,
557			"__osm_vendor_get_ca_guids: "
558			"Detected %u local channel adapters.\n", *p_num_guids);
559	}
560
561Exit:
562	OSM_LOG_EXIT(p_vend->p_log);
563	return (status);
564}
565
566/****f* OpenSM: CA Info/osm_ca_info_get_pi_ptr
567 * NAME
568 * osm_ca_info_get_pi_ptr
569 *
570 * DESCRIPTION
571 * Returns a pointer to the port attribute of the specified port
572 * owned by this CA.
573 *
574 * SYNOPSIS
575 */
576static ib_port_attr_t *__osm_ca_info_get_port_attr_ptr(IN const osm_ca_info_t *
577						       const p_ca_info,
578						       IN const uint8_t index)
579{
580	return (&p_ca_info->p_attr->p_port_attr[index]);
581}
582
583/*
584 * PARAMETERS
585 * p_ca_info
586 *    [in] Pointer to a CA Info object.
587 *
588 * index
589 *    [in] Port "index" for which to retrieve the port attribute.
590 *    The index is the offset into the ca's internal array
591 *    of port attributes.
592 *
593 * RETURN VALUE
594 * Returns a pointer to the port attribute of the specified port
595 * owned by this CA.
596 *
597 * NOTES
598 *
599 * SEE ALSO
600 *********/
601
602/**********************************************************************
603 **********************************************************************/
604ib_api_status_t
605osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend,
606			     IN ib_port_attr_t * const p_attr_array,
607			     IN uint32_t * const p_num_ports)
608{
609	ib_api_status_t status;
610
611	uint32_t ca;
612	uintn_t ca_count;
613	uint32_t port_count = 0;
614	uint8_t port_num;
615	uint32_t total_ports = 0;
616	ib_net64_t *p_ca_guid = NULL;
617	osm_ca_info_t *p_ca_info;
618
619	OSM_LOG_ENTER(p_vend->p_log);
620
621	CL_ASSERT(p_vend);
622	CL_ASSERT(p_vend->p_ca_info == NULL);
623
624	/*
625	   1) Determine the number of CA's
626	   2) Allocate an array big enough to hold the ca info objects.
627	   3) Call again to retrieve the guids.
628	 */
629	status = __osm_vendor_get_ca_guids(p_vend, &p_ca_guid, &ca_count);
630
631	p_vend->p_ca_info = malloc(ca_count * sizeof(*p_vend->p_ca_info));
632	if (p_vend->p_ca_info == NULL) {
633		osm_log(p_vend->p_log, OSM_LOG_ERROR,
634			"osm_vendor_get_all_port_attr: ERR 3B11: "
635			"Unable to allocate CA information array.\n");
636		goto Exit;
637	}
638
639	memset(p_vend->p_ca_info, 0, ca_count * sizeof(*p_vend->p_ca_info));
640	p_vend->ca_count = ca_count;
641
642	/*
643	   For each CA, retrieve the port info attributes
644	 */
645	for (ca = 0; ca < ca_count; ca++) {
646		p_ca_info = &p_vend->p_ca_info[ca];
647
648		status = __osm_ca_info_init(p_vend, p_ca_info, p_ca_guid[ca]);
649
650		if (status != IB_SUCCESS) {
651			osm_log(p_vend->p_log, OSM_LOG_ERROR,
652				"osm_vendor_get_all_port_attr: ERR 3B12: "
653				"Unable to initialize CA Info object (%s).\n",
654				ib_get_err_str(status));
655		}
656
657		total_ports += osm_ca_info_get_num_ports(p_ca_info);
658	}
659
660	/*
661	   If the user supplied enough storage, return the port guids,
662	   otherwise, return the appropriate error.
663	 */
664	if (*p_num_ports >= total_ports) {
665		for (ca = 0; ca < ca_count; ca++) {
666			uint32_t num_ports;
667
668			p_ca_info = &p_vend->p_ca_info[ca];
669
670			num_ports = osm_ca_info_get_num_ports(p_ca_info);
671
672			for (port_num = 0; port_num < num_ports; port_num++) {
673				p_attr_array[port_count] =
674				    *__osm_ca_info_get_port_attr_ptr(p_ca_info,
675								     port_num);
676				port_count++;
677			}
678		}
679	} else {
680		status = IB_INSUFFICIENT_MEMORY;
681	}
682
683	*p_num_ports = total_ports;
684
685Exit:
686	if (p_ca_guid)
687		free(p_ca_guid);
688
689	OSM_LOG_EXIT(p_vend->p_log);
690	return (status);
691}
692
693/**********************************************************************
694 **********************************************************************/
695ib_net64_t
696osm_vendor_get_ca_guid(IN osm_vendor_t * const p_vend,
697		       IN const ib_net64_t port_guid)
698{
699	uint8_t index;
700	uint8_t num_ports;
701	uint32_t num_guids = 0;
702	osm_ca_info_t *p_ca_info;
703	uint32_t ca;
704
705	OSM_LOG_ENTER(p_vend->p_log);
706
707	CL_ASSERT(port_guid);
708	/*
709	   First, locate the HCA that owns this port.
710	 */
711	if (p_vend->p_ca_info == NULL) {
712		/*
713		   Initialize the osm_ca_info_t array which allows
714		   us to match port GUID to CA.
715		 */
716		osm_vendor_get_all_port_attr(p_vend, NULL, &num_guids);
717	}
718
719	CL_ASSERT(p_vend->p_ca_info);
720	CL_ASSERT(p_vend->ca_count);
721
722	for (ca = 0; ca < p_vend->ca_count; ca++) {
723		p_ca_info = &p_vend->p_ca_info[ca];
724
725		num_ports = osm_ca_info_get_num_ports(p_ca_info);
726		CL_ASSERT(num_ports);
727
728		for (index = 0; index < num_ports; index++) {
729			if (port_guid ==
730			    osm_ca_info_get_port_guid(p_ca_info, index)) {
731				OSM_LOG_EXIT(p_vend->p_log);
732				return (osm_ca_info_get_ca_guid(p_ca_info));
733			}
734		}
735	}
736
737	/*
738	   No local CA owns this guid!
739	 */
740	osm_log(p_vend->p_log, OSM_LOG_ERROR,
741		"osm_vendor_get_ca_guid: ERR 3B13: "
742		"Unable to determine CA guid.\n");
743
744	OSM_LOG_EXIT(p_vend->p_log);
745	return (0);
746}
747
748/**********************************************************************
749 **********************************************************************/
750uint8_t
751osm_vendor_get_port_num(IN osm_vendor_t * const p_vend,
752			IN const ib_net64_t port_guid)
753{
754	uint8_t index;
755	uint8_t num_ports;
756	uint32_t num_guids = 0;
757	osm_ca_info_t *p_ca_info;
758	uint32_t ca;
759
760	OSM_LOG_ENTER(p_vend->p_log);
761
762	CL_ASSERT(port_guid);
763	/*
764	   First, locate the HCA that owns this port.
765	 */
766	if (p_vend->p_ca_info == NULL) {
767		/*
768		   Initialize the osm_ca_info_t array which allows
769		   us to match port GUID to CA.
770		 */
771		osm_vendor_get_all_port_attr(p_vend, NULL, &num_guids);
772	}
773
774	CL_ASSERT(p_vend->p_ca_info);
775	CL_ASSERT(p_vend->ca_count);
776
777	for (ca = 0; ca < p_vend->ca_count; ca++) {
778		p_ca_info = &p_vend->p_ca_info[ca];
779
780		num_ports = osm_ca_info_get_num_ports(p_ca_info);
781		CL_ASSERT(num_ports);
782
783		for (index = 0; index < num_ports; index++) {
784			if (port_guid ==
785			    osm_ca_info_get_port_guid(p_ca_info, index)) {
786				OSM_LOG_EXIT(p_vend->p_log);
787				return (osm_ca_info_get_port_num
788					(p_ca_info, index));
789			}
790		}
791	}
792
793	/*
794	   No local CA owns this guid!
795	 */
796	osm_log(p_vend->p_log, OSM_LOG_ERROR,
797		"osm_vendor_get_port_num: ERR 3B30: "
798		"Unable to determine CA guid.\n");
799
800	OSM_LOG_EXIT(p_vend->p_log);
801	return (0);
802}
803
804/**********************************************************************
805 **********************************************************************/
806static ib_api_status_t
807__osm_vendor_open_ca(IN osm_vendor_t * const p_vend,
808		     IN const ib_net64_t port_guid)
809{
810	ib_net64_t ca_guid;
811	ib_api_status_t status;
812
813	OSM_LOG_ENTER(p_vend->p_log);
814
815	ca_guid = osm_vendor_get_ca_guid(p_vend, port_guid);
816	if (ca_guid == 0) {
817		osm_log(p_vend->p_log, OSM_LOG_ERROR,
818			"__osm_vendor_open_ca: ERR 3B31: "
819			"Bad port GUID value 0x%" PRIx64 ".\n",
820			cl_ntoh64(port_guid));
821		status = IB_ERROR;
822		goto Exit;
823	}
824
825	osm_log(p_vend->p_log, OSM_LOG_VERBOSE,
826		"__osm_vendor_open_ca: "
827		"Opening HCA 0x%" PRIx64 ".\n", cl_ntoh64(ca_guid));
828
829	status = ib_open_ca(p_vend->h_al,
830			    ca_guid,
831			    __osm_al_ca_err_callback, p_vend, &p_vend->h_ca);
832
833	if (status != IB_SUCCESS) {
834		osm_log(p_vend->p_log, OSM_LOG_ERROR,
835			"__osm_vendor_open_ca: ERR 3B15: "
836			"Unable to open CA (%s).\n", ib_get_err_str(status));
837		goto Exit;
838	}
839
840	CL_ASSERT(p_vend->h_ca);
841
842	status = ib_alloc_pd(p_vend->h_ca, IB_PDT_ALIAS, p_vend, &p_vend->h_pd);
843
844	if (status != IB_SUCCESS) {
845		ib_close_ca(p_vend->h_ca, __osm_al_ca_destroy_callback);
846		osm_log(p_vend->p_log, OSM_LOG_ERROR,
847			"__osm_vendor_open_ca: ERR 3B16: "
848			"Unable to allocate protection domain (%s).\n",
849			ib_get_err_str(status));
850		goto Exit;
851	}
852
853	CL_ASSERT(p_vend->h_pd);
854
855Exit:
856	OSM_LOG_EXIT(p_vend->p_log);
857	return (status);
858}
859
860/**********************************************************************
861 **********************************************************************/
862static void
863__osm_vendor_init_av(IN const osm_al_bind_info_t * p_bind,
864		     IN ib_av_attr_t * p_av)
865{
866	memset(p_av, 0, sizeof(*p_av));
867	p_av->port_num = p_bind->port_num;
868	p_av->dlid = IB_LID_PERMISSIVE;
869}
870
871/**********************************************************************
872 **********************************************************************/
873osm_bind_handle_t
874osm_vendor_bind(IN osm_vendor_t * const p_vend,
875		IN osm_bind_info_t * const p_user_bind,
876		IN osm_mad_pool_t * const p_mad_pool,
877		IN osm_vend_mad_recv_callback_t mad_recv_callback,
878		IN osm_vend_mad_send_err_callback_t send_err_callback,
879		IN void *context)
880{
881	ib_net64_t port_guid;
882	osm_al_bind_info_t *p_bind = 0;
883	ib_api_status_t status;
884	ib_qp_create_t qp_create;
885	ib_mad_svc_t mad_svc;
886	ib_av_attr_t av;
887
888	OSM_LOG_ENTER(p_vend->p_log);
889
890	CL_ASSERT(p_user_bind);
891	CL_ASSERT(p_mad_pool);
892	CL_ASSERT(mad_recv_callback);
893	CL_ASSERT(send_err_callback);
894
895	port_guid = p_user_bind->port_guid;
896
897	osm_log(p_vend->p_log, OSM_LOG_INFO,
898		"osm_vendor_bind: "
899		"Binding to port 0x%" PRIx64 ".\n", cl_ntoh64(port_guid));
900
901	if (p_vend->h_ca == 0) {
902		osm_log(p_vend->p_log, OSM_LOG_DEBUG,
903			"osm_vendor_bind: "
904			"Opening CA that owns port 0x%" PRIx64 ".\n",
905			port_guid);
906
907		status = __osm_vendor_open_ca(p_vend, port_guid);
908		if (status != IB_SUCCESS) {
909			osm_log(p_vend->p_log, OSM_LOG_ERROR,
910				"osm_vendor_bind: ERR 3B17: "
911				"Unable to Open CA (%s).\n",
912				ib_get_err_str(status));
913			goto Exit;
914		}
915	}
916
917	p_bind = malloc(sizeof(*p_bind));
918	if (p_bind == NULL) {
919		osm_log(p_vend->p_log, OSM_LOG_ERROR,
920			"osm_vendor_bind: ERR 3B18: "
921			"Unable to allocate internal bind object.\n");
922		goto Exit;
923	}
924
925	memset(p_bind, 0, sizeof(*p_bind));
926	p_bind->p_vend = p_vend;
927	p_bind->client_context = context;
928	p_bind->port_num = osm_vendor_get_port_num(p_vend, port_guid);
929	p_bind->rcv_callback = mad_recv_callback;
930	p_bind->send_err_callback = send_err_callback;
931	p_bind->p_osm_pool = p_mad_pool;
932
933	CL_ASSERT(p_bind->port_num);
934
935	/*
936	   Get the proper QP.
937	 */
938	memset(&qp_create, 0, sizeof(qp_create));
939
940	switch (p_user_bind->mad_class) {
941	case IB_MCLASS_SUBN_LID:
942	case IB_MCLASS_SUBN_DIR:
943		qp_create.qp_type = IB_QPT_QP0_ALIAS;
944		break;
945
946	case IB_MCLASS_SUBN_ADM:
947	default:
948		qp_create.qp_type = IB_QPT_QP1_ALIAS;
949		break;
950	}
951
952	qp_create.sq_depth = p_user_bind->send_q_size;
953	qp_create.rq_depth = p_user_bind->recv_q_size;
954	qp_create.sq_sge = OSM_AL_SQ_SGE;
955	qp_create.rq_sge = OSM_AL_RQ_SGE;
956
957	status = ib_get_spl_qp(p_vend->h_pd,
958			       port_guid,
959			       &qp_create,
960			       p_bind,
961			       __osm_al_err_callback,
962			       &p_bind->pool_key, &p_bind->h_qp);
963
964	if (status != IB_SUCCESS) {
965		free(p_bind);
966		osm_log(p_vend->p_log, OSM_LOG_ERROR,
967			"osm_vendor_bind: ERR 3B19: "
968			"Unable to get QP handle (%s).\n",
969			ib_get_err_str(status));
970		goto Exit;
971	}
972
973	CL_ASSERT(p_bind->h_qp);
974	CL_ASSERT(p_bind->pool_key);
975
976	memset(&mad_svc, 0, sizeof(mad_svc));
977
978	mad_svc.mad_svc_context = p_bind;
979	mad_svc.pfn_mad_send_cb = __osm_al_send_callback;
980	mad_svc.pfn_mad_recv_cb = __osm_al_rcv_callback;
981	mad_svc.mgmt_class = p_user_bind->mad_class;
982	mad_svc.mgmt_version = p_user_bind->class_version;
983	mad_svc.support_unsol = p_user_bind->is_responder;
984	mad_svc.method_array[IB_MAD_METHOD_GET] = TRUE;
985	mad_svc.method_array[IB_MAD_METHOD_SET] = TRUE;
986	mad_svc.method_array[IB_MAD_METHOD_DELETE] = TRUE;
987	mad_svc.method_array[IB_MAD_METHOD_TRAP] = TRUE;
988	mad_svc.method_array[IB_MAD_METHOD_GETTABLE] = TRUE;
989
990	status = ib_reg_mad_svc(p_bind->h_qp, &mad_svc, &p_bind->h_svc);
991
992	if (status != IB_SUCCESS) {
993		free(p_bind);
994		osm_log(p_vend->p_log, OSM_LOG_ERROR,
995			"osm_vendor_bind: ERR 3B21: "
996			"Unable to register QP0 MAD service (%s).\n",
997			ib_get_err_str(status));
998		goto Exit;
999	}
1000
1001	__osm_vendor_init_av(p_bind, &av);
1002
1003	status = ib_create_av(p_vend->h_pd, &av, &p_bind->h_dr_av);
1004	if (status != IB_SUCCESS) {
1005		osm_log(p_vend->p_log, OSM_LOG_ERROR,
1006			"osm_vendor_bind: ERR 3B22: "
1007			"Unable to create address vector (%s).\n",
1008			ib_get_err_str(status));
1009
1010		goto Exit;
1011	}
1012
1013	if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) {
1014		osm_log(p_vend->p_log, OSM_LOG_DEBUG,
1015			"osm_vendor_bind: "
1016			"Allocating av handle %p.\n", p_bind->h_dr_av);
1017	}
1018
1019Exit:
1020	OSM_LOG_EXIT(p_vend->p_log);
1021	return ((osm_bind_handle_t) p_bind);
1022}
1023
1024/**********************************************************************
1025 **********************************************************************/
1026ib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind,
1027			 IN const uint32_t mad_size,
1028			 IN osm_vend_wrap_t * const p_vw)
1029{
1030	ib_mad_t *p_mad;
1031	osm_al_bind_info_t *p_bind = (osm_al_bind_info_t *) h_bind;
1032	osm_vendor_t *p_vend = p_bind->p_vend;
1033	ib_api_status_t status;
1034
1035	OSM_LOG_ENTER(p_vend->p_log);
1036
1037	CL_ASSERT(p_vw);
1038
1039	p_vw->size = mad_size;
1040	p_vw->h_bind = h_bind;
1041
1042	/*
1043	   Retrieve a MAD element from the pool and give the user direct
1044	   access to its buffer.
1045	 */
1046	status = ib_get_mad(p_bind->pool_key, mad_size, &p_vw->p_elem);
1047	if (status != IB_SUCCESS) {
1048		osm_log(p_vend->p_log, OSM_LOG_ERROR,
1049			"osm_vendor_get: ERR 3B25: "
1050			"Unable to acquire MAD (%s).\n",
1051			ib_get_err_str(status));
1052
1053		p_mad = NULL;
1054		goto Exit;
1055	}
1056
1057	CL_ASSERT(p_vw->p_elem);
1058	p_mad = ib_get_mad_buf(p_vw->p_elem);
1059
1060	if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) {
1061		osm_log(p_vend->p_log, OSM_LOG_DEBUG,
1062			"osm_vendor_get: "
1063			"Acquired MAD %p, size = %u.\n", p_mad, mad_size);
1064	}
1065
1066Exit:
1067	OSM_LOG_EXIT(p_vend->p_log);
1068	return (p_mad);
1069}
1070
1071/**********************************************************************
1072 **********************************************************************/
1073void
1074osm_vendor_put(IN osm_bind_handle_t h_bind, IN osm_vend_wrap_t * const p_vw)
1075{
1076	osm_al_bind_info_t *p_bind = (osm_al_bind_info_t *) h_bind;
1077	osm_vendor_t *p_vend = p_bind->p_vend;
1078	ib_api_status_t status;
1079
1080	OSM_LOG_ENTER(p_vend->p_log);
1081
1082	CL_ASSERT(p_vw);
1083	CL_ASSERT(p_vw->p_elem);
1084	CL_ASSERT(p_vw->h_bind == h_bind);
1085
1086	if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) {
1087		osm_log(p_vend->p_log, OSM_LOG_DEBUG,
1088			"osm_vendor_put: "
1089			"Retiring MAD %p.\n", ib_get_mad_buf(p_vw->p_elem));
1090	}
1091
1092	status = ib_put_mad(p_vw->p_elem);
1093	if (status != IB_SUCCESS) {
1094		osm_log(p_vend->p_log, OSM_LOG_ERROR,
1095			"osm_vendor_put: ERR 3B26: "
1096			"Unable to retire MAD (%s).\n", ib_get_err_str(status));
1097	}
1098
1099	OSM_LOG_EXIT(p_vend->p_log);
1100}
1101
1102/**********************************************************************
1103 **********************************************************************/
1104ib_api_status_t
1105osm_vendor_send(IN osm_bind_handle_t h_bind,
1106		IN osm_madw_t * const p_madw, IN boolean_t const resp_expected)
1107{
1108	osm_al_bind_info_t *const p_bind = h_bind;
1109	osm_vendor_t *const p_vend = p_bind->p_vend;
1110	osm_vend_wrap_t *const p_vw = osm_madw_get_vend_ptr(p_madw);
1111	osm_mad_addr_t *const p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw);
1112	ib_mad_t *const p_mad = osm_madw_get_mad_ptr(p_madw);
1113	ib_api_status_t status;
1114	ib_mad_element_t *p_elem;
1115	ib_av_attr_t av;
1116
1117	OSM_LOG_ENTER(p_vend->p_log);
1118
1119	CL_ASSERT(p_vw->h_bind == h_bind);
1120	CL_ASSERT(p_vw->p_elem);
1121
1122	p_elem = p_vw->p_elem;
1123
1124	/*
1125	   If a response is expected to this MAD, then preallocate
1126	   a mad wrapper to contain the wire MAD received in the
1127	   response.  Allocating a wrapper here allows for easier
1128	   failure paths than after we already received the wire mad.
1129	 */
1130	if (resp_expected) {
1131		p_vw->p_resp_madw =
1132		    osm_mad_pool_get_wrapper_raw(p_bind->p_osm_pool);
1133		if (p_vw->p_resp_madw == NULL) {
1134			osm_log(p_vend->p_log, OSM_LOG_ERROR,
1135				"osm_vendor_send: ERR 3B27: "
1136				"Unable to allocate MAD wrapper.\n");
1137			status = IB_INSUFFICIENT_RESOURCES;
1138			goto Exit;
1139		}
1140	} else
1141		p_vw->p_resp_madw = NULL;
1142
1143	/*
1144	   For all sends other than directed route SM MADs,
1145	   acquire an address vector for the destination.
1146	 */
1147	if (p_mad->mgmt_class != IB_MCLASS_SUBN_DIR) {
1148		memset(&av, 0, sizeof(av));
1149		av.port_num = p_bind->port_num;
1150		av.dlid = p_mad_addr->dest_lid;
1151		av.static_rate = p_mad_addr->static_rate;
1152		av.path_bits = p_mad_addr->path_bits;
1153
1154		if ((p_mad->mgmt_class != IB_MCLASS_SUBN_LID) &&
1155		    (p_mad->mgmt_class != IB_MCLASS_SUBN_DIR)) {
1156			av.sl = p_mad_addr->addr_type.gsi.service_level;
1157
1158			if (p_mad_addr->addr_type.gsi.global_route) {
1159				av.grh_valid = TRUE;
1160				/* ANIL */
1161				/* av.grh = p_mad_addr->addr_type.gsi.grh_info; */
1162			}
1163		}
1164
1165		if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) {
1166			osm_log(p_vend->p_log, OSM_LOG_DEBUG,
1167				"osm_vendor_send: "
1168				"av.port_num 0x%X, "
1169				"av.dlid 0x%X, "
1170				"av.static_rate   %d, "
1171				"av.path_bits %d.\n",
1172				av.port_num, cl_ntoh16(av.dlid),
1173				av.static_rate, av.path_bits);
1174		}
1175
1176		status = ib_create_av(p_vend->h_pd, &av, &p_vw->h_av);
1177		if (status != IB_SUCCESS) {
1178			osm_log(p_vend->p_log, OSM_LOG_ERROR,
1179				"osm_vendor_send: ERR 3B28: "
1180				"Unable to create address vector (%s).\n",
1181				ib_get_err_str(status));
1182
1183			if (p_vw->p_resp_madw)
1184				osm_mad_pool_put(p_bind->p_osm_pool,
1185						 p_vw->p_resp_madw);
1186			goto Exit;
1187		}
1188
1189		if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) {
1190			osm_log(p_vend->p_log, OSM_LOG_DEBUG,
1191				"osm_vendor_send: "
1192				"Allocating av handle %p.\n", p_vw->h_av);
1193		}
1194	} else {
1195		p_vw->h_av = p_bind->h_dr_av;
1196	}
1197
1198	p_elem->h_av = p_vw->h_av;
1199
1200	p_elem->context1 = p_madw;
1201	p_elem->context2 = NULL;
1202
1203	p_elem->immediate_data = 0;
1204	p_elem->p_grh = NULL;
1205	p_elem->resp_expected = resp_expected;
1206	p_elem->retry_cnt = OSM_DEFAULT_RETRY_COUNT;
1207
1208	p_elem->send_opt = IB_SEND_OPT_SIGNALED;
1209	p_elem->timeout_ms = p_vend->timeout;
1210
1211	/* Completion information. */
1212	p_elem->status = 0;	/* Not trusting AL */
1213
1214	if ((p_mad->mgmt_class == IB_MCLASS_SUBN_LID) ||
1215	    (p_mad->mgmt_class == IB_MCLASS_SUBN_DIR)) {
1216		p_elem->remote_qp = 0;
1217		p_elem->remote_qkey = 0;
1218	} else {
1219		p_elem->remote_qp = p_mad_addr->addr_type.gsi.remote_qp;
1220		p_elem->remote_qkey = p_mad_addr->addr_type.gsi.remote_qkey;
1221		osm_log(p_vend->p_log, OSM_LOG_DEBUG,
1222			"osm_vendor_send: "
1223			"remote qp = 0x%X, remote qkey = 0x%X.\n",
1224			cl_ntoh32(p_elem->remote_qp),
1225			cl_ntoh32(p_elem->remote_qkey));
1226	}
1227
1228	status = ib_send_mad(p_bind->h_svc, p_elem, NULL);
1229	if (status != IB_SUCCESS) {
1230		osm_log(p_vend->p_log, OSM_LOG_ERROR,
1231			"osm_vendor_send: ERR 3B29: "
1232			"Send failed (%s).\n", ib_get_err_str(status));
1233		if (p_vw->p_resp_madw)
1234			osm_mad_pool_put(p_bind->p_osm_pool, p_vw->p_resp_madw);
1235		goto Exit;
1236	}
1237
1238Exit:
1239	OSM_LOG_EXIT(p_vend->p_log);
1240	return (status);
1241}
1242
1243/**********************************************************************
1244 **********************************************************************/
1245ib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind)
1246{
1247	osm_al_bind_info_t *p_bind = (osm_al_bind_info_t *) h_bind;
1248	osm_vendor_t *p_vend = p_bind->p_vend;
1249	ib_av_attr_t av;
1250	ib_api_status_t status;
1251
1252	OSM_LOG_ENTER(p_vend->p_log);
1253
1254	/*
1255	   The only thing we need to do is refresh the directed
1256	   route address vector.
1257	 */
1258	__osm_vendor_init_av(p_bind, &av);
1259
1260	status = ib_destroy_av(p_bind->h_dr_av);
1261	if (status != IB_SUCCESS) {
1262		osm_log(p_vend->p_log, OSM_LOG_ERROR,
1263			"osm_vendor_local_lid_change: ERR 3B32: "
1264			"Unable to destroy address vector (%s).\n",
1265			ib_get_err_str(status));
1266
1267		goto Exit;
1268	}
1269
1270	status = ib_create_av(p_vend->h_pd, &av, &p_bind->h_dr_av);
1271	if (status != IB_SUCCESS) {
1272		osm_log(p_vend->p_log, OSM_LOG_ERROR,
1273			"osm_vendor_local_lid_change: ERR 3B33: "
1274			"Unable to create address vector (%s).\n",
1275			ib_get_err_str(status));
1276
1277		goto Exit;
1278	}
1279
1280Exit:
1281	OSM_LOG_EXIT(p_vend->p_log);
1282	return (status);
1283}
1284
1285/**********************************************************************
1286 **********************************************************************/
1287void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val)
1288{
1289	osm_al_bind_info_t *p_bind = (osm_al_bind_info_t *) h_bind;
1290	osm_vendor_t *p_vend = p_bind->p_vend;
1291	ib_api_status_t status;
1292	ib_port_attr_mod_t attr_mod;
1293
1294	OSM_LOG_ENTER(p_vend->p_log);
1295
1296	memset(&attr_mod, 0, sizeof(attr_mod));
1297
1298	attr_mod.cap.sm = is_sm_val;
1299
1300	status = ib_modify_ca(p_vend->h_ca, p_bind->port_num,
1301			      IB_CA_MOD_IS_SM, &attr_mod);
1302
1303	if (status != IB_SUCCESS) {
1304		osm_log(p_vend->p_log, OSM_LOG_ERROR,
1305			"osm_vendor_set_sm: ERR 3B34: "
1306			"Unable set 'IS_SM' bit to:%u in port attributes (%s).\n",
1307			is_sm_val, ib_get_err_str(status));
1308	}
1309
1310	OSM_LOG_EXIT(p_vend->p_log);
1311}
1312
1313/**********************************************************************
1314 **********************************************************************/
1315void osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level)
1316{
1317
1318}
1319
1320#endif				/* OSM_VENDOR_INTF_AL */
1321