1/*
2 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2005,2008 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5 * Copyright (c) 2009,2010 HNR Consulting. All rights reserved.
6 *
7 * This software is available to you under a choice of one of two
8 * licenses.  You may choose to be licensed under the terms of the GNU
9 * General Public License (GPL) Version 2, available from the file
10 * COPYING in the main directory of this source tree, or the
11 * OpenIB.org BSD license below:
12 *
13 *     Redistribution and use in source and binary forms, with or
14 *     without modification, are permitted provided that the following
15 *     conditions are met:
16 *
17 *      - Redistributions of source code must retain the above
18 *        copyright notice, this list of conditions and the following
19 *        disclaimer.
20 *
21 *      - Redistributions in binary form must reproduce the above
22 *        copyright notice, this list of conditions and the following
23 *        disclaimer in the documentation and/or other materials
24 *        provided with the distribution.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 * SOFTWARE.
34 *
35 */
36
37#if HAVE_CONFIG_H
38#  include <config.h>
39#endif				/* HAVE_CONFIG_H */
40
41#include <stdlib.h>
42#include <string.h>
43#include <complib/cl_debug.h>
44#include <complib/cl_timer.h>
45#include <complib/cl_event.h>
46#include <vendor/osm_vendor_api.h>
47#include <vendor/osm_vendor_sa_api.h>
48
49/* this struct is the internal rep of the bind handle */
50typedef struct _osmv_sa_bind_info {
51	osm_bind_handle_t h_bind;
52	osm_log_t *p_log;
53	osm_vendor_t *p_vendor;
54	osm_mad_pool_t *p_mad_pool;
55	uint64_t port_guid;
56	cl_event_t sync_event;
57	uint64_t last_lids_update_sec;
58	uint16_t lid;
59	uint16_t sm_lid;
60} osmv_sa_bind_info_t;
61
62/*
63  Call back on new mad received:
64
65  We basically only need to set the context of the query.
66  Or report an error.
67
68  A pointer to the actual context of the request (a copy of the oriignal
69  request structure) is attached as the p_madw->context.ni_context.node_guid
70*/
71static void
72__osmv_sa_mad_rcv_cb(IN osm_madw_t * p_madw,
73		     IN void *bind_context, IN osm_madw_t * p_req_madw)
74{
75	osmv_sa_bind_info_t *p_bind = (osmv_sa_bind_info_t *) bind_context;
76	osmv_query_req_t *p_query_req_copy = NULL;
77	osmv_query_res_t query_res;
78	ib_sa_mad_t *p_sa_mad;
79	ib_net16_t mad_status;
80
81	OSM_LOG_ENTER(p_bind->p_log);
82
83	if (!p_req_madw) {
84		OSM_LOG(p_bind->p_log, OSM_LOG_DEBUG,
85			"Ignoring a non-response mad\n");
86		osm_mad_pool_put(p_bind->p_mad_pool, p_madw);
87		goto Exit;
88	}
89
90	/* obtain the sent context */
91	p_query_req_copy =
92	    (osmv_query_req_t *) (p_req_madw->context.arb_context.context1);
93
94	/* provide the context of the original request in the result */
95	query_res.query_context = p_query_req_copy->query_context;
96
97	/* provide the resulting madw */
98	query_res.p_result_madw = p_madw;
99
100	/* update the req fields */
101	p_sa_mad = (ib_sa_mad_t *) p_madw->p_mad;
102
103	/* if we got a remote error track it in the status */
104	mad_status = (ib_net16_t) (p_sa_mad->status & IB_SMP_STATUS_MASK);
105	if (mad_status != IB_SUCCESS) {
106		OSM_LOG(p_bind->p_log, OSM_LOG_ERROR, "ERR 0501: "
107			"Remote error:0x%04X\n", cl_ntoh16(mad_status));
108		query_res.status = IB_REMOTE_ERROR;
109	} else
110		query_res.status = IB_SUCCESS;
111
112	/* what if we have got back an empty mad ? */
113	if (!p_madw->mad_size) {
114		OSM_LOG(p_bind->p_log, OSM_LOG_ERROR, "ERR 0502: "
115			"Got an empty mad\n");
116		query_res.status = IB_ERROR;
117	}
118
119	if (IB_SUCCESS == mad_status) {
120
121		/* if we are in not in a method response of an rmpp nature we must get only 1 */
122		/* HACK: in the future we might need to be smarter for other methods... */
123		if (p_sa_mad->method != IB_MAD_METHOD_GETTABLE_RESP) {
124			query_res.result_cnt = 1;
125		} else {
126#ifndef VENDOR_RMPP_SUPPORT
127			if (mad_status != IB_SUCCESS)
128				query_res.result_cnt = 0;
129			else
130				query_res.result_cnt = 1;
131#else
132			/* we used the offset value to calculate the number of
133			   records in here */
134			if (ib_get_attr_size(p_sa_mad->attr_offset) == 0) {
135				query_res.result_cnt = 0;
136				OSM_LOG(p_bind->p_log, OSM_LOG_DEBUG,
137					"Count = 0\n");
138			}
139			else {
140				query_res.result_cnt =
141					(p_madw->mad_size - IB_SA_MAD_HDR_SIZE) /
142					ib_get_attr_size(p_sa_mad->attr_offset);
143				OSM_LOG(p_bind->p_log, OSM_LOG_DEBUG,
144					"Count = %u = %zu / %u (%zu)\n",
145					query_res.result_cnt,
146					p_madw->mad_size - IB_SA_MAD_HDR_SIZE,
147					ib_get_attr_size(p_sa_mad->attr_offset),
148					(p_madw->mad_size - IB_SA_MAD_HDR_SIZE) %
149					ib_get_attr_size(p_sa_mad->attr_offset));
150			}
151#endif
152		}
153	}
154
155	query_res.query_type = p_query_req_copy->query_type;
156
157	p_query_req_copy->pfn_query_cb(&query_res);
158
159	if ((p_query_req_copy->flags & OSM_SA_FLAGS_SYNC) == OSM_SA_FLAGS_SYNC)
160		cl_event_signal(&p_bind->sync_event);
161
162Exit:
163
164	/* free the copied query request if found */
165	if (p_query_req_copy)
166		free(p_query_req_copy);
167
168	/* put back the request madw */
169	if (p_req_madw)
170		osm_mad_pool_put(p_bind->p_mad_pool, p_req_madw);
171
172	OSM_LOG_EXIT(p_bind->p_log);
173}
174
175/*
176  Send Error Callback:
177
178  Only report the error and get rid of the mad wrapper
179*/
180static void __osmv_sa_mad_err_cb(IN void *bind_context, IN osm_madw_t * p_madw)
181{
182	osmv_sa_bind_info_t *p_bind = (osmv_sa_bind_info_t *) bind_context;
183	osmv_query_req_t *p_query_req_copy = NULL;
184	osmv_query_res_t query_res;
185
186	OSM_LOG_ENTER(p_bind->p_log);
187
188	/* Obtain the sent context etc */
189	p_query_req_copy =
190	    (osmv_query_req_t *) (p_madw->context.arb_context.context1);
191
192	/* provide the context of the original request in the result */
193	query_res.query_context = p_query_req_copy->query_context;
194
195	query_res.p_result_madw = p_madw;
196
197	query_res.status = IB_TIMEOUT;
198	query_res.result_cnt = 0;
199	query_res.p_result_madw->status = IB_TIMEOUT;
200	p_madw->status = IB_TIMEOUT;
201	query_res.query_type = p_query_req_copy->query_type;
202
203	p_query_req_copy->pfn_query_cb(&query_res);
204
205	if ((p_query_req_copy->flags & OSM_SA_FLAGS_SYNC) == OSM_SA_FLAGS_SYNC)
206		cl_event_signal(&p_bind->sync_event);
207
208	free(p_query_req_copy);
209	OSM_LOG_EXIT(p_bind->p_log);
210}
211
212/*****************************************************************************
213 This routine needs to be invoked on every send - since the SM LID and Local
214 lid might change. To do that without any major perfoermance impact we cache
215 the results and time they were obtained. Refresh only twice a minute.
216 To avoid the need to use statics and risk a race - we require the refresh time
217 to be stored in the context of the results. Also this coveres cases were
218 we query for multiple guids.
219 *****************************************************************************/
220static ib_api_status_t
221__osmv_get_lid_and_sm_lid_by_port_guid(IN osm_vendor_t * const p_vend,
222				       IN ib_net64_t port_guid,
223				       IN OUT uint64_t * p_lids_update_time_sec,
224				       OUT uint16_t * lid,
225				       OUT uint16_t * sm_lid)
226{
227
228	ib_api_status_t status;
229	ib_port_attr_t *p_attr_array;
230	uint32_t num_ports;
231	uint32_t port_num;
232
233	OSM_LOG_ENTER(p_vend->p_log);
234
235	/* use prevous values if current time is close enough to previous query */
236	if (cl_get_time_stamp_sec() <= *p_lids_update_time_sec + 30) {
237		OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG,
238			"Using previously stored lid:0x%04x sm_lid:0x%04x\n",
239			*lid, *sm_lid);
240		status = IB_SUCCESS;
241		goto Exit;
242	}
243
244	/* obtain the number of available ports */
245	num_ports = 0;
246	status = osm_vendor_get_all_port_attr(p_vend, NULL, &num_ports);
247	if (status != IB_INSUFFICIENT_MEMORY) {
248		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 0503: "
249			"Expected to get the IB_INSUFFICIENT_MEMORY but got: %s\n",
250			ib_get_err_str(status));
251		status = IB_ERROR;
252		goto Exit;
253	}
254
255	OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG,
256		"Found total of %u ports. Looking for guid:0x%016" PRIx64 "\n",
257		num_ports, cl_ntoh64(port_guid));
258
259	/* allocate the attributes */
260	p_attr_array =
261	    (ib_port_attr_t *) malloc(sizeof(ib_port_attr_t) * num_ports);
262
263	/* obtain the attributes */
264	status = osm_vendor_get_all_port_attr(p_vend, p_attr_array, &num_ports);
265	if (status != IB_SUCCESS) {
266		OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 0504: "
267			"Failed to get port attributes (error: %s)\n",
268			ib_get_err_str(status));
269		free(p_attr_array);
270		goto Exit;
271	}
272
273	status = IB_ERROR;
274	/* find the port requested in the list */
275	for (port_num = 0; (port_num < num_ports) && (status == IB_ERROR);
276	     port_num++) {
277		if (p_attr_array[port_num].port_guid == port_guid) {
278			*lid = p_attr_array[port_num].lid;
279			*sm_lid = p_attr_array[port_num].sm_lid;
280			*p_lids_update_time_sec = cl_get_time_stamp_sec();
281			status = IB_SUCCESS;
282			OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG,
283				"Found guid:0x%016" PRIx64 " with idx:%d\n",
284				cl_ntoh64(port_guid), port_num);
285		}
286	}
287
288	free(p_attr_array);
289
290Exit:
291	OSM_LOG_EXIT(p_vend->p_log);
292	return (status);
293}
294
295osm_bind_handle_t
296osmv_bind_sa(IN osm_vendor_t * const p_vend,
297	     IN osm_mad_pool_t * const p_mad_pool, IN ib_net64_t port_guid)
298{
299	osm_bind_info_t bind_info;
300	osm_log_t *p_log = p_vend->p_log;
301	ib_api_status_t status = IB_SUCCESS;
302	osmv_sa_bind_info_t *p_sa_bind_info;
303	cl_status_t cl_status;
304
305	OSM_LOG_ENTER(p_log);
306
307	OSM_LOG(p_log, OSM_LOG_DEBUG,
308		"Binding to port 0x%" PRIx64 "\n", cl_ntoh64(port_guid));
309
310	bind_info.port_guid = port_guid;
311	bind_info.mad_class = IB_MCLASS_SUBN_ADM;
312	bind_info.class_version = 2;
313	bind_info.is_responder = FALSE;
314	bind_info.is_trap_processor = FALSE;
315	bind_info.is_report_processor = FALSE;
316	bind_info.send_q_size = 256;
317	bind_info.recv_q_size = 256;
318
319	/* allocate the new sa bind info */
320	p_sa_bind_info =
321	    (osmv_sa_bind_info_t *) malloc(sizeof(osmv_sa_bind_info_t));
322	if (!p_sa_bind_info) {
323		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0505: "
324			"Failed to allocate new bind structure\n");
325		p_sa_bind_info = OSM_BIND_INVALID_HANDLE;
326		goto Exit;
327	}
328
329	/* store some important context */
330	p_sa_bind_info->p_log = p_log;
331	p_sa_bind_info->port_guid = port_guid;
332	p_sa_bind_info->p_mad_pool = p_mad_pool;
333	p_sa_bind_info->p_vendor = p_vend;
334	p_sa_bind_info->last_lids_update_sec = 0;
335
336	/* Bind to the lower level */
337	p_sa_bind_info->h_bind = osm_vendor_bind(p_vend, &bind_info, p_mad_pool, __osmv_sa_mad_rcv_cb, __osmv_sa_mad_err_cb, p_sa_bind_info);	/* context provided to CBs */
338
339	if (p_sa_bind_info->h_bind == OSM_BIND_INVALID_HANDLE) {
340		free(p_sa_bind_info);
341		p_sa_bind_info = OSM_BIND_INVALID_HANDLE;
342		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0506: "
343			"Failed to bind to vendor GSI\n");
344		goto Exit;
345	}
346
347	/* obtain the sm_lid from the vendor */
348	status =
349	    __osmv_get_lid_and_sm_lid_by_port_guid(p_vend, port_guid,
350						   &p_sa_bind_info->
351						   last_lids_update_sec,
352						   &p_sa_bind_info->lid,
353						   &p_sa_bind_info->sm_lid);
354	if (status != IB_SUCCESS) {
355		free(p_sa_bind_info);
356		p_sa_bind_info = OSM_BIND_INVALID_HANDLE;
357		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0507: "
358			"Failed to obtain the SM lid\n");
359		goto Exit;
360	}
361
362	/* initialize the sync_event */
363	cl_event_construct(&p_sa_bind_info->sync_event);
364	cl_status = cl_event_init(&p_sa_bind_info->sync_event, TRUE);
365	if (cl_status != CL_SUCCESS) {
366		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0508: "
367			"cl_init_event failed: %s\n", ib_get_err_str(cl_status));
368		free(p_sa_bind_info);
369		p_sa_bind_info = OSM_BIND_INVALID_HANDLE;
370	}
371
372Exit:
373	OSM_LOG_EXIT(p_log);
374	return (p_sa_bind_info);
375}
376
377/****t* OSM Vendor SA Client/osmv_sa_mad_data
378 * NAME
379 *    osmv_sa_mad_data
380 *
381 * DESCRIPTION
382 * Extra fields required to perform a mad query
383 *  This struct is passed to the actual send method
384 *
385 * SYNOPSIS
386 */
387typedef struct _osmv_sa_mad_data {
388	/* MAD data. */
389	uint8_t method;
390	ib_net16_t attr_id;
391	ib_net16_t attr_offset;
392	ib_net32_t attr_mod;
393	ib_net64_t comp_mask;
394	void *p_attr;
395} osmv_sa_mad_data_t;
396/*
397 * method
398 *    The method of the mad to be sent
399 *
400 *  attr_id
401 *     Attribute ID
402 *
403 *  attr_offset
404 *     Offset as defined by RMPP
405 *
406 *  attr_mod
407 *     Attribute modifier
408 *
409 *  comp_mask
410 *     The component mask of the query
411 *
412 *  p_attr
413 *     A pointer to the record of the attribute to be sent.
414 *
415 *****/
416
417/* Send a MAD out on the GSI interface */
418static ib_api_status_t
419__osmv_send_sa_req(IN osmv_sa_bind_info_t * p_bind,
420		   IN const osmv_sa_mad_data_t * const p_sa_mad_data,
421		   IN const osmv_query_req_t * const p_query_req)
422{
423	ib_api_status_t status;
424	ib_mad_t *p_mad_hdr;
425	ib_sa_mad_t *p_sa_mad;
426	osm_madw_t *p_madw;
427	osm_log_t *p_log = p_bind->p_log;
428	static atomic32_t trans_id;
429	boolean_t sync;
430	osmv_query_req_t *p_query_req_copy;
431	uint32_t sa_size;
432
433	OSM_LOG_ENTER(p_log);
434
435	/*
436	   since the sm_lid might change we obtain it every send
437	   (actually it is cached in the bind object and refreshed
438	   every 30sec by this proc)
439	 */
440	status =
441	    __osmv_get_lid_and_sm_lid_by_port_guid(p_bind->p_vendor,
442						   p_bind->port_guid,
443						   &p_bind->
444						   last_lids_update_sec,
445						   &p_bind->lid,
446						   &p_bind->sm_lid);
447	if (status != IB_SUCCESS) {
448		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0509: "
449			"Failed to obtain the SM lid\n");
450		goto Exit;
451	}
452
453	/* Get a MAD wrapper for the send */
454	p_madw = osm_mad_pool_get(p_bind->p_mad_pool,
455				  p_bind->h_bind, MAD_BLOCK_SIZE, NULL);
456
457	if (p_madw == NULL) {
458		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0510: "
459			"Unable to acquire MAD\n");
460		status = IB_INSUFFICIENT_RESOURCES;
461		goto Exit;
462	}
463
464	/* Initialize the Sent MAD: */
465
466	/* Initialize the MAD buffer for the send operation. */
467	p_mad_hdr = osm_madw_get_mad_ptr(p_madw);
468	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
469
470	/* Get a new transaction Id */
471	cl_atomic_inc(&trans_id);
472
473	/* Cleanup the MAD from any residue */
474	memset(p_sa_mad, 0, MAD_BLOCK_SIZE);
475
476	/* Initialize the standard MAD header. */
477	ib_mad_init_new(p_mad_hdr,	/* mad pointer */
478			IB_MCLASS_SUBN_ADM,	/* class */
479			(uint8_t) 2,	/* version */
480			p_sa_mad_data->method,	/* method */
481			cl_hton64((uint64_t) trans_id),	/* tid */
482			p_sa_mad_data->attr_id,	/* attr id */
483			p_sa_mad_data->attr_mod	/* attr mod */);
484
485	/* Set the query information. */
486	p_sa_mad->sm_key = p_query_req->sm_key;
487	p_sa_mad->attr_offset = 0;
488	p_sa_mad->comp_mask = p_sa_mad_data->comp_mask;
489	if (p_sa_mad->comp_mask) {
490		p_sa_mad_data->attr_offset ? (sa_size = ib_get_attr_size(p_sa_mad_data->attr_offset)) : (sa_size = IB_SA_DATA_SIZE);
491		memcpy(p_sa_mad->data, p_sa_mad_data->p_attr, sa_size);
492	}
493
494	/*
495	   Provide the address to send to
496	 */
497	/* Patch to handle IBAL - host order , where it should take destination lid in network order */
498#ifdef OSM_VENDOR_INTF_AL
499	p_madw->mad_addr.dest_lid = p_bind->sm_lid;
500#else
501	p_madw->mad_addr.dest_lid = cl_hton16(p_bind->sm_lid);
502#endif
503	p_madw->mad_addr.addr_type.smi.source_lid = cl_hton16(p_bind->lid);
504	p_madw->mad_addr.addr_type.gsi.remote_qp = CL_HTON32(1);
505	p_madw->resp_expected = TRUE;
506	p_madw->fail_msg = CL_DISP_MSGID_NONE;
507
508	/*
509	   Provide MAD context such that the call back will know what to do.
510	   We have to keep the entire request structure so we know the CB.
511	   Since we can not rely on the client to keep it around until
512	   the response - we duplicate it and will later dispose it (in CB).
513	   To store on the MADW we cast it into what opensm has:
514	   p_madw->context.arb_context.context1
515	 */
516	p_query_req_copy = malloc(sizeof(*p_query_req_copy));
517	if (!p_query_req_copy) {
518		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0511: "
519			"Unable to acquire memory for query copy\n");
520		osm_mad_pool_put(p_bind->p_mad_pool, p_madw);
521		status = IB_INSUFFICIENT_RESOURCES;
522		goto Exit;
523	}
524	*p_query_req_copy = *p_query_req;
525	p_madw->context.arb_context.context1 = p_query_req_copy;
526
527	/* we can support async as well as sync calls */
528	sync = ((p_query_req->flags & OSM_SA_FLAGS_SYNC) == OSM_SA_FLAGS_SYNC);
529
530	/* send the mad asynchronously */
531	status = osm_vendor_send(osm_madw_get_bind_handle(p_madw),
532				 p_madw, p_madw->resp_expected);
533
534	/* if synchronous - wait on the event */
535	if (sync) {
536		OSM_LOG(p_log, OSM_LOG_DEBUG, "Waiting for async event\n");
537		cl_event_wait_on(&p_bind->sync_event, EVENT_NO_TIMEOUT, FALSE);
538		cl_event_reset(&p_bind->sync_event);
539		status = p_madw->status;
540	}
541
542Exit:
543	OSM_LOG_EXIT(p_log);
544	return status;
545}
546
547/*
548 * Query the SA based on the user's request.
549 */
550ib_api_status_t
551osmv_query_sa(IN osm_bind_handle_t h_bind,
552	      IN const osmv_query_req_t * const p_query_req)
553{
554	union {
555		ib_service_record_t svc_rec;
556		ib_node_record_t node_rec;
557		ib_portinfo_record_t port_info;
558		ib_path_rec_t path_rec;
559#ifdef DUAL_SIDED_RMPP
560		ib_multipath_rec_t multipath_rec;
561#endif
562		ib_class_port_info_t class_port_info;
563	} u;
564	osmv_sa_mad_data_t sa_mad_data;
565	osmv_sa_bind_info_t *p_bind = (osmv_sa_bind_info_t *) h_bind;
566	osmv_user_query_t *p_user_query;
567#ifdef DUAL_SIDED_RMPP
568	osmv_multipath_req_t *p_mpr_req;
569	int i, j;
570#endif
571	osm_log_t *p_log = p_bind->p_log;
572	ib_api_status_t status;
573
574	OSM_LOG_ENTER(p_log);
575
576	/* Set the request information. */
577	sa_mad_data.method = IB_MAD_METHOD_GETTABLE;
578	sa_mad_data.attr_mod = 0;
579	sa_mad_data.attr_offset = 0;
580
581	/* Set the MAD attributes and component mask correctly. */
582	switch (p_query_req->query_type) {
583
584	case OSMV_QUERY_USER_DEFINED:
585		OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 USER_DEFINED\n");
586		p_user_query = (osmv_user_query_t *) p_query_req->p_query_input;
587		if (p_user_query->method)
588			sa_mad_data.method = p_user_query->method;
589#ifdef DUAL_SIDED_RMPP
590		if (sa_mad_data.method == IB_MAD_METHOD_GETMULTI ||
591		    sa_mad_data.method == IB_MAD_METHOD_GETTRACETABLE)
592			sa_mad_data.attr_offset = p_user_query->attr_offset;
593#endif
594		sa_mad_data.attr_id = p_user_query->attr_id;
595		sa_mad_data.attr_mod = p_user_query->attr_mod;
596		sa_mad_data.comp_mask = p_user_query->comp_mask;
597		sa_mad_data.p_attr = p_user_query->p_attr;
598		break;
599
600	case OSMV_QUERY_ALL_SVC_RECS:
601		OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 SVC_REC_BY_NAME\n");
602		sa_mad_data.attr_id = IB_MAD_ATTR_SERVICE_RECORD;
603		sa_mad_data.comp_mask = 0;
604		sa_mad_data.p_attr = &u.svc_rec;
605		break;
606
607	case OSMV_QUERY_SVC_REC_BY_NAME:
608		OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 SVC_REC_BY_NAME\n");
609		sa_mad_data.method = IB_MAD_METHOD_GET;
610		sa_mad_data.attr_id = IB_MAD_ATTR_SERVICE_RECORD;
611		sa_mad_data.comp_mask = IB_SR_COMPMASK_SNAME;
612		sa_mad_data.p_attr = &u.svc_rec;
613		memcpy(u.svc_rec.service_name, p_query_req->p_query_input,
614		       sizeof(ib_svc_name_t));
615		break;
616
617	case OSMV_QUERY_SVC_REC_BY_ID:
618		OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 SVC_REC_BY_ID\n");
619		sa_mad_data.attr_id = IB_MAD_ATTR_SERVICE_RECORD;
620		sa_mad_data.comp_mask = IB_SR_COMPMASK_SID;
621		sa_mad_data.p_attr = &u.svc_rec;
622		u.svc_rec.service_id =
623		    *(ib_net64_t *) (p_query_req->p_query_input);
624		break;
625
626	case OSMV_QUERY_CLASS_PORT_INFO:
627		OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 CLASS_PORT_INFO\n");
628		sa_mad_data.method = IB_MAD_METHOD_GET;
629		sa_mad_data.attr_id = IB_MAD_ATTR_CLASS_PORT_INFO;
630		sa_mad_data.comp_mask = 0;
631		sa_mad_data.p_attr = &u.class_port_info;
632		break;
633
634	case OSMV_QUERY_NODE_REC_BY_NODE_GUID:
635		OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 NODE_REC_BY_NODE_GUID\n");
636		sa_mad_data.attr_id = IB_MAD_ATTR_NODE_RECORD;
637		sa_mad_data.comp_mask = IB_NR_COMPMASK_NODEGUID;
638		sa_mad_data.p_attr = &u.node_rec;
639		u.node_rec.node_info.node_guid =
640		    *(ib_net64_t *) (p_query_req->p_query_input);
641		break;
642
643	case OSMV_QUERY_PORT_REC_BY_LID:
644		OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 PORT_REC_BY_LID\n");
645		sa_mad_data.attr_id = IB_MAD_ATTR_PORTINFO_RECORD;
646		sa_mad_data.comp_mask = IB_PIR_COMPMASK_LID;
647		sa_mad_data.p_attr = &u.port_info;
648		u.port_info.lid = *(ib_net16_t *) (p_query_req->p_query_input);
649		break;
650
651	case OSMV_QUERY_PORT_REC_BY_LID_AND_NUM:
652		sa_mad_data.method = IB_MAD_METHOD_GET;
653		p_user_query = (osmv_user_query_t *) p_query_req->p_query_input;
654		OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 PORT_REC_BY_LID_AND_NUM\n");
655		sa_mad_data.attr_id = IB_MAD_ATTR_PORTINFO_RECORD;
656		sa_mad_data.comp_mask =
657		    IB_PIR_COMPMASK_LID | IB_PIR_COMPMASK_PORTNUM;
658		sa_mad_data.p_attr = p_user_query->p_attr;
659		break;
660
661	case OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK:
662		sa_mad_data.method = IB_MAD_METHOD_GET;
663		p_user_query = (osmv_user_query_t *) p_query_req->p_query_input;
664		OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK\n");
665		sa_mad_data.attr_id = IB_MAD_ATTR_VLARB_RECORD;
666		sa_mad_data.comp_mask =
667		    IB_VLA_COMPMASK_LID | IB_VLA_COMPMASK_OUT_PORT |
668		    IB_VLA_COMPMASK_BLOCK;
669		sa_mad_data.p_attr = p_user_query->p_attr;
670		break;
671
672	case OSMV_QUERY_SLVL_BY_LID_AND_PORTS:
673		sa_mad_data.method = IB_MAD_METHOD_GET;
674		p_user_query = (osmv_user_query_t *) p_query_req->p_query_input;
675		OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK\n");
676		sa_mad_data.attr_id = IB_MAD_ATTR_SLVL_RECORD;
677		sa_mad_data.comp_mask =
678		    IB_SLVL_COMPMASK_LID | IB_SLVL_COMPMASK_OUT_PORT |
679		    IB_SLVL_COMPMASK_IN_PORT;
680		sa_mad_data.p_attr = p_user_query->p_attr;
681		break;
682
683	case OSMV_QUERY_PATH_REC_BY_PORT_GUIDS:
684		OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 PATH_REC_BY_PORT_GUIDS\n");
685		memset(&u.path_rec, 0, sizeof(ib_path_rec_t));
686		sa_mad_data.attr_id = IB_MAD_ATTR_PATH_RECORD;
687		sa_mad_data.comp_mask =
688		    (IB_PR_COMPMASK_DGID | IB_PR_COMPMASK_SGID | IB_PR_COMPMASK_NUMBPATH);
689		u.path_rec.num_path = 0x7f;
690		sa_mad_data.p_attr = &u.path_rec;
691		ib_gid_set_default(&u.path_rec.dgid,
692				   ((osmv_guid_pair_t *) (p_query_req->
693							  p_query_input))->
694				   dest_guid);
695		ib_gid_set_default(&u.path_rec.sgid,
696				   ((osmv_guid_pair_t *) (p_query_req->
697							  p_query_input))->
698				   src_guid);
699		break;
700
701	case OSMV_QUERY_PATH_REC_BY_GIDS:
702		OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 PATH_REC_BY_GIDS\n");
703		memset(&u.path_rec, 0, sizeof(ib_path_rec_t));
704		sa_mad_data.attr_id = IB_MAD_ATTR_PATH_RECORD;
705		sa_mad_data.comp_mask =
706		    (IB_PR_COMPMASK_DGID | IB_PR_COMPMASK_SGID | IB_PR_COMPMASK_NUMBPATH);
707		u.path_rec.num_path = 0x7f;
708		sa_mad_data.p_attr = &u.path_rec;
709		memcpy(&u.path_rec.dgid,
710		       &((osmv_gid_pair_t *) (p_query_req->p_query_input))->
711		       dest_gid, sizeof(ib_gid_t));
712		memcpy(&u.path_rec.sgid,
713		       &((osmv_gid_pair_t *) (p_query_req->p_query_input))->
714		       src_gid, sizeof(ib_gid_t));
715		break;
716
717	case OSMV_QUERY_PATH_REC_BY_LIDS:
718		OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 PATH_REC_BY_LIDS\n");
719		memset(&u.path_rec, 0, sizeof(ib_path_rec_t));
720		sa_mad_data.method = IB_MAD_METHOD_GET;
721		sa_mad_data.attr_id = IB_MAD_ATTR_PATH_RECORD;
722		sa_mad_data.comp_mask =
723		    (IB_PR_COMPMASK_DLID | IB_PR_COMPMASK_SLID);
724		sa_mad_data.p_attr = &u.path_rec;
725		u.path_rec.dlid =
726		    ((osmv_lid_pair_t *) (p_query_req->p_query_input))->
727		    dest_lid;
728		u.path_rec.slid =
729		    ((osmv_lid_pair_t *) (p_query_req->p_query_input))->src_lid;
730		break;
731
732	case OSMV_QUERY_UD_MULTICAST_SET:
733		sa_mad_data.method = IB_MAD_METHOD_SET;
734		p_user_query = (osmv_user_query_t *) p_query_req->p_query_input;
735		OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 OSMV_QUERY_UD_MULTICAST_SET\n");
736		sa_mad_data.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD;
737		sa_mad_data.comp_mask = p_user_query->comp_mask;
738		sa_mad_data.p_attr = p_user_query->p_attr;
739		break;
740
741	case OSMV_QUERY_UD_MULTICAST_DELETE:
742		sa_mad_data.method = IB_MAD_METHOD_DELETE;
743		p_user_query = (osmv_user_query_t *) p_query_req->p_query_input;
744		OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 OSMV_QUERY_UD_MULTICAST_DELETE\n");
745		sa_mad_data.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD;
746		sa_mad_data.comp_mask = p_user_query->comp_mask;
747		sa_mad_data.p_attr = p_user_query->p_attr;
748		break;
749
750#ifdef DUAL_SIDED_RMPP
751	case OSMV_QUERY_MULTIPATH_REC:
752		OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 MULTIPATH_REC\n");
753		/* Validate sgid/dgid counts against SA client limit */
754		p_mpr_req = (osmv_multipath_req_t *) p_query_req->p_query_input;
755		if (p_mpr_req->sgid_count + p_mpr_req->dgid_count >
756		    IB_MULTIPATH_MAX_GIDS) {
757			OSM_LOG(p_log, OSM_LOG_ERROR, "DBG:001 MULTIPATH_REC "
758				"SGID count %d DGID count %d max count %d\n",
759				p_mpr_req->sgid_count, p_mpr_req->dgid_count,
760				IB_MULTIPATH_MAX_GIDS);
761			CL_ASSERT(0);
762			return IB_ERROR;
763		}
764		memset(&u.multipath_rec, 0, sizeof(ib_multipath_rec_t));
765		sa_mad_data.method = IB_MAD_METHOD_GETMULTI;
766		sa_mad_data.attr_id = IB_MAD_ATTR_MULTIPATH_RECORD;
767		sa_mad_data.attr_offset =
768		    ib_get_attr_offset(sizeof(ib_multipath_rec_t));
769		sa_mad_data.p_attr = &u.multipath_rec;
770		sa_mad_data.comp_mask = p_mpr_req->comp_mask;
771		u.multipath_rec.num_path = p_mpr_req->num_path;
772		if (p_mpr_req->reversible)
773			u.multipath_rec.num_path |= 0x80;
774		else
775			u.multipath_rec.num_path &= ~0x80;
776		u.multipath_rec.pkey = p_mpr_req->pkey;
777		ib_multipath_rec_set_sl(&u.multipath_rec, p_mpr_req->sl);
778		ib_multipath_rec_set_qos_class(&u.multipath_rec, 0);
779		u.multipath_rec.independence = p_mpr_req->independence;
780		u.multipath_rec.sgid_count = p_mpr_req->sgid_count;
781		u.multipath_rec.dgid_count = p_mpr_req->dgid_count;
782		j = 0;
783		for (i = 0; i < p_mpr_req->sgid_count; i++, j++)
784			u.multipath_rec.gids[j] = p_mpr_req->gids[j];
785		for (i = 0; i < p_mpr_req->dgid_count; i++, j++)
786			u.multipath_rec.gids[j] = p_mpr_req->gids[j];
787		break;
788#endif
789
790	default:
791		OSM_LOG(p_log, OSM_LOG_ERROR, "DBG:001 UNKNOWN\n");
792		CL_ASSERT(0);
793		return IB_ERROR;
794	}
795
796	status = __osmv_send_sa_req(h_bind, &sa_mad_data, p_query_req);
797
798	OSM_LOG_EXIT(p_log);
799	return status;
800}
801