1/*
2 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2011 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5 * Copyright (c) 2013 Oracle and/or its affiliates. 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/*
38 * Abstract:
39 *    Implementation of osm_pir_rcv_t.
40 * This object represents the PortInfoRecord Receiver object.
41 * This object is part of the opensm family of objects.
42 */
43
44#if HAVE_CONFIG_H
45#  include <config.h>
46#endif				/* HAVE_CONFIG_H */
47
48#include <string.h>
49#include <iba/ib_types.h>
50#include <complib/cl_qmap.h>
51#include <complib/cl_passivelock.h>
52#include <complib/cl_debug.h>
53#include <complib/cl_qlist.h>
54#include <opensm/osm_file_ids.h>
55#define FILE_ID OSM_FILE_SA_PORTINFO_RECORD_C
56#include <vendor/osm_vendor_api.h>
57#include <opensm/osm_port.h>
58#include <opensm/osm_node.h>
59#include <opensm/osm_switch.h>
60#include <opensm/osm_helper.h>
61#include <opensm/osm_pkey.h>
62#include <opensm/osm_sa.h>
63
64#define SA_PIR_RESP_SIZE SA_ITEM_RESP_SIZE(port_rec)
65
66typedef struct osm_pir_search_ctxt {
67	const ib_portinfo_record_t *p_rcvd_rec;
68	ib_net64_t comp_mask;
69	cl_qlist_t *p_list;
70	osm_sa_t *sa;
71	const osm_physp_t *p_req_physp;
72	boolean_t is_enhanced_comp_mask;
73} osm_pir_search_ctxt_t;
74
75static ib_api_status_t pir_rcv_new_pir(IN osm_sa_t * sa,
76				       IN const osm_physp_t * p_physp,
77				       IN osm_pir_search_ctxt_t * p_ctxt,
78				       IN ib_net16_t const lid)
79{
80	osm_sa_item_t *p_rec_item;
81	ib_port_info_t *p_pi;
82	osm_physp_t *p_physp0;
83	ib_api_status_t status = IB_SUCCESS;
84
85	OSM_LOG_ENTER(sa->p_log);
86
87	p_rec_item = malloc(SA_PIR_RESP_SIZE);
88	if (p_rec_item == NULL) {
89		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2102: "
90			"rec_item alloc failed\n");
91		status = IB_INSUFFICIENT_RESOURCES;
92		goto Exit;
93	}
94
95	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
96		"New PortInfoRecord: port 0x%016" PRIx64
97		", lid %u, port %u\n",
98		cl_ntoh64(osm_physp_get_port_guid(p_physp)),
99		cl_ntoh16(lid), osm_physp_get_port_num(p_physp));
100
101	memset(p_rec_item, 0, SA_PIR_RESP_SIZE);
102
103	p_rec_item->resp.port_rec.lid = lid;
104	p_rec_item->resp.port_rec.port_info = p_physp->port_info;
105	if (p_ctxt->comp_mask & IB_PIR_COMPMASK_OPTIONS)
106		p_rec_item->resp.port_rec.options = p_ctxt->p_rcvd_rec->options;
107	if ((p_ctxt->comp_mask & IB_PIR_COMPMASK_OPTIONS) == 0 ||
108	    (p_ctxt->p_rcvd_rec->options & 0x80) == 0) {
109		/* Does requested port have an extended link speed active ? */
110		if (osm_node_get_type(p_physp->p_node) ==
111		    IB_NODE_TYPE_SWITCH) {
112			p_physp0 = osm_node_get_physp_ptr(p_physp->p_node, 0);
113			p_pi = &p_physp0->port_info;
114		} else
115			p_pi = (ib_port_info_t *) &p_physp->port_info;
116		if ((p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS) > 0) {
117			if (ib_port_info_get_link_speed_ext_active(&p_physp->port_info)) {
118				/* Add QDR bits to original link speed components */
119				p_pi = &p_rec_item->resp.port_rec.port_info;
120				ib_port_info_set_link_speed_enabled(p_pi,
121								    ib_port_info_get_link_speed_enabled(p_pi) | IB_LINK_SPEED_ACTIVE_10);
122				p_pi->state_info1 =
123				    (uint8_t) ((p_pi->state_info1 & IB_PORT_STATE_MASK) |
124					       (ib_port_info_get_link_speed_sup(p_pi) | IB_LINK_SPEED_ACTIVE_10) << IB_PORT_LINK_SPEED_SHIFT);
125				p_pi->link_speed =
126				    (uint8_t) ((p_pi->link_speed & IB_PORT_LINK_SPEED_ENABLED_MASK) |
127					       (ib_port_info_get_link_speed_active(p_pi) | IB_LINK_SPEED_ACTIVE_10) << IB_PORT_LINK_SPEED_SHIFT);
128			}
129		}
130	}
131	p_rec_item->resp.port_rec.port_num = osm_physp_get_port_num(p_physp);
132
133	cl_qlist_insert_tail(p_ctxt->p_list, &p_rec_item->list_item);
134
135Exit:
136	OSM_LOG_EXIT(sa->p_log);
137	return status;
138}
139
140static void sa_pir_create(IN osm_sa_t * sa, IN const osm_physp_t * p_physp,
141			  IN osm_pir_search_ctxt_t * p_ctxt)
142{
143	uint8_t lmc;
144	uint16_t max_lid_ho;
145	uint16_t base_lid_ho;
146	uint16_t match_lid_ho;
147	osm_physp_t *p_node_physp;
148
149	OSM_LOG_ENTER(sa->p_log);
150
151	if (p_physp->p_node->sw) {
152		p_node_physp = osm_node_get_physp_ptr(p_physp->p_node, 0);
153		base_lid_ho = cl_ntoh16(osm_physp_get_base_lid(p_node_physp));
154		lmc =
155		    osm_switch_sp0_is_lmc_capable(p_physp->p_node->sw,
156						  sa->p_subn) ?
157		    osm_physp_get_lmc(p_node_physp) : 0;
158	} else {
159		lmc = osm_physp_get_lmc(p_physp);
160		base_lid_ho = cl_ntoh16(osm_physp_get_base_lid(p_physp));
161	}
162	max_lid_ho = (uint16_t) (base_lid_ho + (1 << lmc) - 1);
163
164	if (p_ctxt->comp_mask & IB_PIR_COMPMASK_LID) {
165		match_lid_ho = cl_ntoh16(p_ctxt->p_rcvd_rec->lid);
166
167		/*
168		   We validate that the lid belongs to this node.
169		 */
170		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
171			"Comparing LID: %u <= %u <= %u\n",
172			base_lid_ho, match_lid_ho, max_lid_ho);
173
174		if (match_lid_ho < base_lid_ho || match_lid_ho > max_lid_ho)
175			goto Exit;
176	}
177
178	pir_rcv_new_pir(sa, p_physp, p_ctxt, cl_hton16(base_lid_ho));
179
180Exit:
181	OSM_LOG_EXIT(sa->p_log);
182}
183
184static void sa_pir_check_physp(IN osm_sa_t * sa, IN const osm_physp_t * p_physp,
185			       osm_pir_search_ctxt_t * p_ctxt)
186{
187	const ib_portinfo_record_t *p_rcvd_rec;
188	ib_net64_t comp_mask;
189	const ib_port_info_t *p_comp_pi;
190	const ib_port_info_t *p_pi;
191	const osm_physp_t * p_physp0;
192	ib_net32_t cap_mask;
193
194	OSM_LOG_ENTER(sa->p_log);
195
196	p_rcvd_rec = p_ctxt->p_rcvd_rec;
197	comp_mask = p_ctxt->comp_mask;
198	p_comp_pi = &p_rcvd_rec->port_info;
199	p_pi = &p_physp->port_info;
200
201	osm_dump_port_info_v2(sa->p_log, osm_node_get_node_guid(p_physp->p_node),
202			      p_physp->port_guid, p_physp->port_num,
203			      &p_physp->port_info, FILE_ID, OSM_LOG_DEBUG);
204
205	/* We have to re-check the base_lid, since if the given
206	   base_lid in p_pi is zero - we are comparing on all ports. */
207	if (comp_mask & IB_PIR_COMPMASK_BASELID) {
208		if (p_comp_pi->base_lid != p_pi->base_lid)
209			goto Exit;
210	}
211	if (comp_mask & IB_PIR_COMPMASK_MKEY) {
212		if (p_comp_pi->m_key != p_pi->m_key)
213			goto Exit;
214	}
215	if (comp_mask & IB_PIR_COMPMASK_GIDPRE) {
216		if (p_comp_pi->subnet_prefix != p_pi->subnet_prefix)
217			goto Exit;
218	}
219	if (comp_mask & IB_PIR_COMPMASK_SMLID) {
220		if (p_comp_pi->master_sm_base_lid != p_pi->master_sm_base_lid)
221			goto Exit;
222	}
223
224	/* IBTA 1.2 errata provides support for bitwise compare if the bit 31
225	   of the attribute modifier of the Get/GetTable is set */
226	if (comp_mask & IB_PIR_COMPMASK_CAPMASK) {
227		if (p_ctxt->is_enhanced_comp_mask) {
228			if ((p_comp_pi->capability_mask & p_pi->
229			     capability_mask) != p_comp_pi->capability_mask)
230				goto Exit;
231		} else {
232			if (p_comp_pi->capability_mask != p_pi->capability_mask)
233				goto Exit;
234		}
235	}
236
237	if (comp_mask & IB_PIR_COMPMASK_DIAGCODE) {
238		if (p_comp_pi->diag_code != p_pi->diag_code)
239			goto Exit;
240	}
241	if (comp_mask & IB_PIR_COMPMASK_MKEYLEASEPRD) {
242		if (p_comp_pi->m_key_lease_period != p_pi->m_key_lease_period)
243			goto Exit;
244	}
245	if (comp_mask & IB_PIR_COMPMASK_LOCALPORTNUM) {
246		if (p_comp_pi->local_port_num != p_pi->local_port_num)
247			goto Exit;
248	}
249	if (comp_mask & IB_PIR_COMPMASK_LNKWIDTHSUPPORT) {
250		if (p_comp_pi->link_width_supported !=
251		    p_pi->link_width_supported)
252			goto Exit;
253	}
254	if (comp_mask & IB_PIR_COMPMASK_LNKWIDTHACTIVE) {
255		if (p_comp_pi->link_width_active != p_pi->link_width_active)
256			goto Exit;
257	}
258	if (comp_mask & IB_PIR_COMPMASK_LINKWIDTHENABLED) {
259		if (p_comp_pi->link_width_enabled != p_pi->link_width_enabled)
260			goto Exit;
261	}
262	if (comp_mask & IB_PIR_COMPMASK_LNKSPEEDSUPPORT) {
263		if (ib_port_info_get_link_speed_sup(p_comp_pi) !=
264		    ib_port_info_get_link_speed_sup(p_pi))
265			goto Exit;
266	}
267	if (comp_mask & IB_PIR_COMPMASK_PORTSTATE) {
268		if (ib_port_info_get_port_state(p_comp_pi) !=
269		    ib_port_info_get_port_state(p_pi))
270			goto Exit;
271	}
272	if (comp_mask & IB_PIR_COMPMASK_PORTPHYSTATE) {
273		if (ib_port_info_get_port_phys_state(p_comp_pi) !=
274		    ib_port_info_get_port_phys_state(p_pi))
275			goto Exit;
276	}
277	if (comp_mask & IB_PIR_COMPMASK_LINKDWNDFLTSTATE) {
278		if (ib_port_info_get_link_down_def_state(p_comp_pi) !=
279		    ib_port_info_get_link_down_def_state(p_pi))
280			goto Exit;
281	}
282	if (comp_mask & IB_PIR_COMPMASK_MKEYPROTBITS) {
283		if (ib_port_info_get_mpb(p_comp_pi) !=
284		    ib_port_info_get_mpb(p_pi))
285			goto Exit;
286	}
287	if (comp_mask & IB_PIR_COMPMASK_LMC) {
288		if (ib_port_info_get_lmc(p_comp_pi) !=
289		    ib_port_info_get_lmc(p_pi))
290			goto Exit;
291	}
292	if (comp_mask & IB_PIR_COMPMASK_LINKSPEEDACTIVE) {
293		if (ib_port_info_get_link_speed_active(p_comp_pi) !=
294		    ib_port_info_get_link_speed_active(p_pi))
295			goto Exit;
296	}
297	if (comp_mask & IB_PIR_COMPMASK_LINKSPEEDENABLE) {
298		if (ib_port_info_get_link_speed_enabled(p_comp_pi) !=
299		    ib_port_info_get_link_speed_enabled(p_pi))
300			goto Exit;
301	}
302	if (comp_mask & IB_PIR_COMPMASK_NEIGHBORMTU) {
303		if (ib_port_info_get_neighbor_mtu(p_comp_pi) !=
304		    ib_port_info_get_neighbor_mtu(p_pi))
305			goto Exit;
306	}
307	if (comp_mask & IB_PIR_COMPMASK_MASTERSMSL) {
308		if (ib_port_info_get_master_smsl(p_comp_pi) !=
309		    ib_port_info_get_master_smsl(p_pi))
310			goto Exit;
311	}
312	if (comp_mask & IB_PIR_COMPMASK_VLCAP) {
313		if (ib_port_info_get_vl_cap(p_comp_pi) !=
314		    ib_port_info_get_vl_cap(p_pi))
315			goto Exit;
316	}
317	if (comp_mask & IB_PIR_COMPMASK_INITTYPE) {
318		if (ib_port_info_get_init_type(p_comp_pi) !=
319		    ib_port_info_get_init_type(p_pi))
320			goto Exit;
321	}
322	if (comp_mask & IB_PIR_COMPMASK_VLHIGHLIMIT) {
323		if (p_comp_pi->vl_high_limit != p_pi->vl_high_limit)
324			goto Exit;
325	}
326	if (comp_mask & IB_PIR_COMPMASK_VLARBHIGHCAP) {
327		if (p_comp_pi->vl_arb_high_cap != p_pi->vl_arb_high_cap)
328			goto Exit;
329	}
330	if (comp_mask & IB_PIR_COMPMASK_VLARBLOWCAP) {
331		if (p_comp_pi->vl_arb_low_cap != p_pi->vl_arb_low_cap)
332			goto Exit;
333	}
334	if (comp_mask & IB_PIR_COMPMASK_MTUCAP) {
335		if (ib_port_info_get_mtu_cap(p_comp_pi) !=
336		    ib_port_info_get_mtu_cap(p_pi))
337			goto Exit;
338	}
339	if (comp_mask & IB_PIR_COMPMASK_VLSTALLCNT) {
340		if (ib_port_info_get_vl_stall_count(p_comp_pi) !=
341		    ib_port_info_get_vl_stall_count(p_pi))
342			goto Exit;
343	}
344	if (comp_mask & IB_PIR_COMPMASK_HOQLIFE) {
345		if ((p_comp_pi->vl_stall_life & 0x1F) !=
346		    (p_pi->vl_stall_life & 0x1F))
347			goto Exit;
348	}
349	if (comp_mask & IB_PIR_COMPMASK_OPVLS) {
350		if ((p_comp_pi->vl_enforce & 0xF0) != (p_pi->vl_enforce & 0xF0))
351			goto Exit;
352	}
353	if (comp_mask & IB_PIR_COMPMASK_PARENFIN) {
354		if ((p_comp_pi->vl_enforce & 0x08) != (p_pi->vl_enforce & 0x08))
355			goto Exit;
356	}
357	if (comp_mask & IB_PIR_COMPMASK_PARENFOUT) {
358		if ((p_comp_pi->vl_enforce & 0x04) != (p_pi->vl_enforce & 0x04))
359			goto Exit;
360	}
361	if (comp_mask & IB_PIR_COMPMASK_FILTERRAWIN) {
362		if ((p_comp_pi->vl_enforce & 0x02) != (p_pi->vl_enforce & 0x02))
363			goto Exit;
364	}
365	if (comp_mask & IB_PIR_COMPMASK_FILTERRAWOUT) {
366		if ((p_comp_pi->vl_enforce & 0x01) != (p_pi->vl_enforce & 0x01))
367			goto Exit;
368	}
369	if (comp_mask & IB_PIR_COMPMASK_MKEYVIO) {
370		if (p_comp_pi->m_key_violations != p_pi->m_key_violations)
371			goto Exit;
372	}
373	if (comp_mask & IB_PIR_COMPMASK_PKEYVIO) {
374		if (p_comp_pi->p_key_violations != p_pi->p_key_violations)
375			goto Exit;
376	}
377	if (comp_mask & IB_PIR_COMPMASK_QKEYVIO) {
378		if (p_comp_pi->q_key_violations != p_pi->q_key_violations)
379			goto Exit;
380	}
381	if (comp_mask & IB_PIR_COMPMASK_GUIDCAP) {
382		if (p_comp_pi->guid_cap != p_pi->guid_cap)
383			goto Exit;
384	}
385	if (comp_mask & IB_PIR_COMPMASK_SUBNTO) {
386		if (ib_port_info_get_timeout(p_comp_pi) !=
387		    ib_port_info_get_timeout(p_pi))
388			goto Exit;
389	}
390	if (comp_mask & IB_PIR_COMPMASK_RESPTIME) {
391		if ((p_comp_pi->resp_time_value & 0x1F) !=
392		    (p_pi->resp_time_value & 0x1F))
393			goto Exit;
394	}
395	if (comp_mask & IB_PIR_COMPMASK_LOCALPHYERR) {
396		if (ib_port_info_get_local_phy_err_thd(p_comp_pi) !=
397		    ib_port_info_get_local_phy_err_thd(p_pi))
398			goto Exit;
399	}
400	if (comp_mask & IB_PIR_COMPMASK_OVERRUNERR) {
401		if (ib_port_info_get_overrun_err_thd(p_comp_pi) !=
402		    ib_port_info_get_overrun_err_thd(p_pi))
403			goto Exit;
404	}
405
406	/* IBTA 1.2 errata provides support for bitwise compare if the bit 31
407	   of the attribute modifier of the Get/GetTable is set */
408	if (comp_mask & IB_PIR_COMPMASK_CAPMASK2) {
409		if (p_ctxt->is_enhanced_comp_mask) {
410			if ((cl_ntoh16(p_comp_pi->capability_mask2) &
411			     cl_ntoh16(p_pi->capability_mask2)) !=
412			     cl_ntoh16(p_comp_pi->capability_mask2))
413				goto Exit;
414		} else {
415			if (cl_ntoh16(p_comp_pi->capability_mask2) !=
416			    cl_ntoh16(p_pi->capability_mask2))
417				goto Exit;
418		}
419	}
420	if (osm_node_get_type(p_physp->p_node) == IB_NODE_TYPE_SWITCH) {
421		p_physp0 = osm_node_get_physp_ptr(p_physp->p_node, 0);
422		cap_mask = p_physp0->port_info.capability_mask;
423	} else
424		cap_mask = p_pi->capability_mask;
425	if (comp_mask & IB_PIR_COMPMASK_LINKSPDEXTACT) {
426		if (((cap_mask & IB_PORT_CAP_HAS_EXT_SPEEDS) > 0) &&
427		    (ib_port_info_get_link_speed_ext_active(p_comp_pi) !=
428		     ib_port_info_get_link_speed_ext_active(p_pi)))
429			goto Exit;
430	}
431	if (comp_mask & IB_PIR_COMPMASK_LINKSPDEXTSUPP) {
432		if (((cap_mask & IB_PORT_CAP_HAS_EXT_SPEEDS) > 0) &&
433		    (ib_port_info_get_link_speed_ext_sup(p_comp_pi) !=
434		     ib_port_info_get_link_speed_ext_sup(p_pi)))
435			goto Exit;
436	}
437	if (comp_mask & IB_PIR_COMPMASK_LINKSPDEXTENAB) {
438		if (((cap_mask & IB_PORT_CAP_HAS_EXT_SPEEDS) > 0) &&
439		    (ib_port_info_get_link_speed_ext_enabled(p_comp_pi) !=
440		     ib_port_info_get_link_speed_ext_enabled(p_pi)))
441			goto Exit;
442	}
443	sa_pir_create(sa, p_physp, p_ctxt);
444
445Exit:
446	OSM_LOG_EXIT(sa->p_log);
447}
448
449static void sa_pir_by_comp_mask(IN osm_sa_t * sa, IN osm_node_t * p_node,
450				osm_pir_search_ctxt_t * p_ctxt)
451{
452	const ib_portinfo_record_t *p_rcvd_rec;
453	ib_net64_t comp_mask;
454	const osm_physp_t *p_physp;
455	uint8_t port_num;
456	uint8_t num_ports;
457	const osm_physp_t *p_req_physp;
458
459	OSM_LOG_ENTER(sa->p_log);
460
461	p_rcvd_rec = p_ctxt->p_rcvd_rec;
462	comp_mask = p_ctxt->comp_mask;
463	p_req_physp = p_ctxt->p_req_physp;
464
465	num_ports = osm_node_get_num_physp(p_node);
466
467	if (comp_mask & IB_PIR_COMPMASK_PORTNUM) {
468		if (p_rcvd_rec->port_num < num_ports) {
469			p_physp =
470			    osm_node_get_physp_ptr(p_node,
471						   p_rcvd_rec->port_num);
472			/* Check that the p_physp is valid, and that the
473			   p_physp and the p_req_physp share a pkey. */
474			if (p_physp &&
475			    osm_physp_share_pkey(sa->p_log, p_req_physp, p_physp,
476						 sa->p_subn->opt.allow_both_pkeys))
477				sa_pir_check_physp(sa, p_physp, p_ctxt);
478		}
479	} else {
480		for (port_num = 0; port_num < num_ports; port_num++) {
481			p_physp = osm_node_get_physp_ptr(p_node, port_num);
482			if (!p_physp)
483				continue;
484
485			/* if the requester and the p_physp don't share a pkey -
486			   continue */
487			if (!osm_physp_share_pkey(sa->p_log, p_req_physp, p_physp,
488						  sa->p_subn->opt.allow_both_pkeys))
489				continue;
490
491			sa_pir_check_physp(sa, p_physp, p_ctxt);
492		}
493	}
494
495	OSM_LOG_EXIT(sa->p_log);
496}
497
498static void sa_pir_by_comp_mask_cb(IN cl_map_item_t * p_map_item, IN void *cxt)
499{
500	osm_node_t *p_node = (osm_node_t *) p_map_item;
501	osm_pir_search_ctxt_t *p_ctxt = cxt;
502
503	sa_pir_by_comp_mask(p_ctxt->sa, p_node, p_ctxt);
504}
505
506void osm_pir_rcv_process(IN void *ctx, IN void *data)
507{
508	osm_sa_t *sa = ctx;
509	osm_madw_t *p_madw = data;
510	const ib_sa_mad_t *p_rcvd_mad;
511	const ib_portinfo_record_t *p_rcvd_rec;
512	const osm_port_t *p_port = NULL;
513	cl_qlist_t rec_list;
514	osm_pir_search_ctxt_t context;
515	ib_net64_t comp_mask;
516	osm_physp_t *p_req_physp;
517
518	CL_ASSERT(sa);
519
520	OSM_LOG_ENTER(sa->p_log);
521
522	CL_ASSERT(p_madw);
523
524	p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw);
525	p_rcvd_rec =
526	    (ib_portinfo_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad);
527	comp_mask = p_rcvd_mad->comp_mask;
528
529	CL_ASSERT(p_rcvd_mad->attr_id == IB_MAD_ATTR_PORTINFO_RECORD);
530
531	/* we only support SubnAdmGet and SubnAdmGetTable methods */
532	if (p_rcvd_mad->method != IB_MAD_METHOD_GET &&
533	    p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) {
534		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2105: "
535			"Unsupported Method (%s) for PortInfoRecord request\n",
536			ib_get_sa_method_str(p_rcvd_mad->method));
537		osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
538		goto Exit;
539	}
540
541	cl_plock_acquire(sa->p_lock);
542
543	/* update the requester physical port */
544	p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
545						osm_madw_get_mad_addr_ptr
546						(p_madw));
547	if (p_req_physp == NULL) {
548		cl_plock_release(sa->p_lock);
549		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2104: "
550			"Cannot find requester physical port\n");
551		goto Exit;
552	}
553
554	if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) {
555		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
556			"Requester port GUID 0x%" PRIx64 "\n",
557			cl_ntoh64(osm_physp_get_port_guid(p_req_physp)));
558		osm_dump_portinfo_record_v2(sa->p_log, p_rcvd_rec, FILE_ID, OSM_LOG_DEBUG);
559	}
560
561	cl_qlist_init(&rec_list);
562
563	context.p_rcvd_rec = p_rcvd_rec;
564	context.p_list = &rec_list;
565	context.comp_mask = p_rcvd_mad->comp_mask;
566	context.sa = sa;
567	context.p_req_physp = p_req_physp;
568	context.is_enhanced_comp_mask =
569	    cl_ntoh32(p_rcvd_mad->attr_mod) & (1 << 31);
570
571	/*
572	   If the user specified a LID, it obviously narrows our
573	   work load, since we don't have to search every port
574	 */
575	if (comp_mask & (IB_PIR_COMPMASK_LID | IB_PIR_COMPMASK_BASELID)) {
576		p_port = osm_get_port_by_lid(sa->p_subn, p_rcvd_rec->lid);
577		if (p_port)
578			sa_pir_by_comp_mask(sa, p_port->p_node, &context);
579		else
580			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2109: "
581				"No port found with requested LID %u\n",
582				cl_ntoh16(p_rcvd_rec->lid));
583	} else
584		cl_qmap_apply_func(&sa->p_subn->node_guid_tbl,
585				   sa_pir_by_comp_mask_cb, &context);
586
587	cl_plock_release(sa->p_lock);
588
589	/*
590	   p922 - The M_Key returned shall be zero, except in the case of a
591	   trusted request.
592	   Note: In the mad controller we check that the SM_Key received on
593	   the mad is valid. Meaning - is either zero or equal to the local
594	   sm_key.
595	 */
596	if (!p_rcvd_mad->sm_key) {
597		osm_sa_item_t *item;
598		for (item = (osm_sa_item_t *) cl_qlist_head(&rec_list);
599		     item != (osm_sa_item_t *) cl_qlist_end(&rec_list);
600		     item = (osm_sa_item_t *) cl_qlist_next(&item->list_item))
601			item->resp.port_rec.port_info.m_key = 0;
602	}
603
604	osm_sa_respond(sa, p_madw, sizeof(ib_portinfo_record_t), &rec_list);
605
606Exit:
607	OSM_LOG_EXIT(sa->p_log);
608}
609