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