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 */
50 typedef 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 */
71 static 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 
162 Exit:
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 */
180 static 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  *****************************************************************************/
220 static 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 
290 Exit:
291 	OSM_LOG_EXIT(p_vend->p_log);
292 	return (status);
293 }
294 
295 osm_bind_handle_t
296 osmv_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 
372 Exit:
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  */
387 typedef 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 */
418 static 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 
542 Exit:
543 	OSM_LOG_EXIT(p_log);
544 	return status;
545 }
546 
547 /*
548  * Query the SA based on the user's request.
549  */
550 ib_api_status_t
551 osmv_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