1/*
2 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2006 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_trap_rcv_t.
39 * This object represents the Trap Receiver object.
40 * This object is part of the opensm family of objects.
41 */
42
43#if HAVE_CONFIG_H
44#  include <config.h>
45#endif				/* HAVE_CONFIG_H */
46
47#include <string.h>
48#include <iba/ib_types.h>
49#include <complib/cl_qmap.h>
50#include <complib/cl_debug.h>
51#include <opensm/osm_madw.h>
52#include <opensm/osm_log.h>
53#include <opensm/osm_node.h>
54#include <opensm/osm_helper.h>
55#include <opensm/osm_subnet.h>
56#include <opensm/osm_inform.h>
57#include <opensm/osm_opensm.h>
58
59extern void osm_req_get_node_desc(IN osm_sm_t * sm, osm_physp_t *p_physp);
60
61/**********************************************************************
62 *
63 * TRAP HANDLING:
64 *
65 * Assuming traps can be caused by bad hardware we should provide
66 * a mechanism for filtering their propagation into the actual logic
67 * of OpenSM such that it is not overloaded by them.
68 *
69 * We will provide a trap filtering mechanism with "Aging" capability.
70 * This mechanism will track incoming traps, clasify them by their
71 * source and content and provide back their age.
72 *
73 * A timer running in the background will toggle a timer counter
74 * that should be referenced by the aging algorithm.
75 * To provide an efficient handling of aging. We also track all traps
76 * in a sorted list by their aging.
77 *
78 * The generic Aging Tracker mechanism is implemented in the
79 * cl_aging_tracker object.
80 *
81 **********************************************************************/
82
83typedef struct osm_trap_agingracker_context {
84	osm_log_t *p_log;
85	osm_physp_t *p_physp;
86} osm_trap_aging_tracker_context_t;
87
88/**********************************************************************
89 **********************************************************************/
90static osm_physp_t *get_physp_by_lid_and_num(IN osm_sm_t * sm,
91					     IN uint16_t lid, IN uint8_t num)
92{
93	cl_ptr_vector_t *p_vec = &(sm->p_subn->port_lid_tbl);
94	osm_port_t *p_port;
95
96	if (lid > cl_ptr_vector_get_size(p_vec))
97		return NULL;
98
99	p_port = (osm_port_t *) cl_ptr_vector_get(p_vec, lid);
100	if (!p_port)
101		return NULL;
102
103	if (osm_node_get_num_physp(p_port->p_node) < num)
104		return NULL;
105
106	return osm_node_get_physp_ptr(p_port->p_node, num);
107}
108
109/**********************************************************************
110 **********************************************************************/
111uint64_t
112osm_trap_rcv_aging_tracker_callback(IN uint64_t key,
113				    IN uint32_t num_regs, IN void *context)
114{
115	osm_sm_t *sm = context;
116	uint16_t lid;
117	uint8_t port_num;
118	osm_physp_t *p_physp;
119
120	OSM_LOG_ENTER(sm->p_log);
121
122	if (osm_exit_flag)
123		/* We got an exit flag - do nothing */
124		return 0;
125
126	lid = cl_ntoh16((uint16_t) ((key & 0x0000FFFF00000000ULL) >> 32));
127	port_num = (uint8_t) ((key & 0x00FF000000000000ULL) >> 48);
128
129	p_physp = get_physp_by_lid_and_num(sm, lid, port_num);
130	if (!p_physp)
131		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
132			"Cannot find port num:%u with lid:%u\n",
133			port_num, lid);
134	/* make sure the physp is still valid */
135	/* If the health port was false - set it to true */
136	else if (!osm_physp_is_healthy(p_physp)) {
137		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
138			"Clearing health bit of port num:%u with lid:%u\n",
139			port_num, lid);
140
141		/* Clear its health bit */
142		osm_physp_set_health(p_physp, TRUE);
143	}
144
145	OSM_LOG_EXIT(sm->p_log);
146
147	/* We want to remove the event from the tracker - so
148	   need to return zero. */
149	return 0;
150}
151
152/**********************************************************************
153 * CRC calculation for notice identification
154 **********************************************************************/
155
156#define CRC32_POLYNOMIAL   0xEDB88320L
157
158/* calculate the crc for a given buffer */
159static uint32_t __osm_trap_calc_crc32(void *buffer, uint32_t count)
160{
161	uint32_t temp1, temp2;
162	uint32_t crc = -1L;
163	unsigned char *p = (unsigned char *)buffer;
164	/* pre - calculated table for faster crc calculation */
165	static uint32_t crc_table[256];
166	static boolean_t first = TRUE;
167	int i, j;
168
169	/* if we need to initialize the lookup table */
170	if (first) {
171		/* calc the CRC table */
172		for (i = 0; i <= 255; i++) {
173			crc = i;
174			for (j = 8; j > 0; j--)
175				if (crc & 1)
176					crc = (crc >> 1) ^ CRC32_POLYNOMIAL;
177				else
178					crc >>= 1;
179			crc_table[i] = crc;
180		}
181		first = FALSE;
182	}
183
184	crc = -1L;
185	/* do the calculation */
186	while (count-- != 0) {
187		temp1 = (crc >> 8) & 0x00FFFFFFL;
188		temp2 = crc_table[((int)crc ^ *p++) & 0xFF];
189		crc = temp1 ^ temp2;
190	}
191	return crc;
192}
193
194/********************************************************************
195 ********************************************************************/
196
197/* The key is created in the following manner:
198   port_num  lid   crc
199   \______/ \___/ \___/
200     16b     16b   32b
201*/
202static void
203__osm_trap_get_key(IN uint16_t lid,
204		   IN uint8_t port_num,
205		   IN ib_mad_notice_attr_t * p_ntci, OUT uint64_t * trap_key)
206{
207	uint32_t crc = 0;
208
209	CL_ASSERT(trap_key);
210
211	crc = __osm_trap_calc_crc32(p_ntci, sizeof(ib_mad_notice_attr_t));
212	*trap_key = ((uint64_t) port_num << 48) | ((uint64_t) lid << 32) | crc;
213}
214
215/**********************************************************************
216 **********************************************************************/
217static int __print_num_received(IN uint32_t num_received)
218{
219	uint32_t i;
220
221	/* Series is 10, 20, 50, 100, 200, 500, ... */
222	i = num_received;
223	while (i >= 10) {
224		if (i % 10)
225			break;
226		i = i / 10;
227	}
228
229	if (i == 1 || i == 2 || i == 5)
230		return 1;
231	else
232		return 0;
233}
234
235static int disable_port(osm_sm_t *sm, osm_physp_t *p)
236{
237	uint8_t payload[IB_SMP_DATA_SIZE];
238	osm_madw_context_t context;
239	ib_port_info_t *pi = (ib_port_info_t *)payload;
240	int ret;
241
242	/* select the nearest port to master opensm */
243	if (p->p_remote_physp &&
244	    p->dr_path.hop_count > p->p_remote_physp->dr_path.hop_count)
245		p = p->p_remote_physp;
246
247	/* If trap 131, might want to disable peer port if available */
248	/* but peer port has been observed not to respond to SM requests */
249
250	OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3810: "
251		"Disabling physical port 0x%016" PRIx64 " num:%u\n",
252		cl_ntoh64(osm_physp_get_port_guid(p)), p->port_num);
253
254	memcpy(payload, &p->port_info, sizeof(ib_port_info_t));
255
256	/* Set port to disabled/down */
257	ib_port_info_set_port_state(pi, IB_LINK_DOWN);
258	ib_port_info_set_port_phys_state(IB_PORT_PHYS_STATE_DISABLED, pi);
259
260	/* Issue set of PortInfo */
261	context.pi_context.node_guid = osm_node_get_node_guid(p->p_node);
262	context.pi_context.port_guid = osm_physp_get_port_guid(p);
263	context.pi_context.set_method = TRUE;
264	context.pi_context.light_sweep = FALSE;
265	context.pi_context.active_transition = FALSE;
266
267	ret = osm_req_set(sm, osm_physp_get_dr_path_ptr(p),
268			  payload, sizeof(payload), IB_MAD_ATTR_PORT_INFO,
269			  cl_hton32(osm_physp_get_port_num(p)),
270			  CL_DISP_MSGID_NONE, &context);
271	if (ret)
272		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3811: "
273			"Request to set PortInfo failed\n");
274
275	return ret;
276}
277
278/**********************************************************************
279 **********************************************************************/
280static void
281__osm_trap_rcv_process_request(IN osm_sm_t * sm,
282			       IN const osm_madw_t * const p_madw)
283{
284	uint8_t payload[sizeof(ib_mad_notice_attr_t)];
285	ib_smp_t *p_smp;
286	ib_mad_notice_attr_t *p_ntci = (ib_mad_notice_attr_t *) payload;
287	ib_api_status_t status;
288	osm_madw_t tmp_madw;	/* we need a copy to last after repress */
289	uint64_t trap_key;
290	uint32_t num_received;
291	osm_physp_t *p_physp;
292	cl_ptr_vector_t *p_tbl;
293	osm_port_t *p_port;
294	ib_net16_t source_lid = 0;
295	boolean_t is_gsi = TRUE;
296	uint8_t port_num = 0;
297	boolean_t physp_change_trap = FALSE;
298	uint64_t event_wheel_timeout = OSM_DEFAULT_TRAP_SUPRESSION_TIMEOUT;
299	boolean_t run_heavy_sweep = FALSE;
300
301	OSM_LOG_ENTER(sm->p_log);
302
303	CL_ASSERT(p_madw);
304
305	if (osm_exit_flag)
306		/*
307		   We got an exit flag - do nothing
308		   Otherwise we start a sweep on the trap 144 caused by
309		   cleaning up SM Cap bit...
310		 */
311		goto Exit;
312
313	/* update the is_gsi flag according to the mgmt_class field */
314	if (p_madw->p_mad->mgmt_class == IB_MCLASS_SUBN_LID ||
315	    p_madw->p_mad->mgmt_class == IB_MCLASS_SUBN_DIR)
316		is_gsi = FALSE;
317
318	/* No real need to grab the lock for this function. */
319	memset(payload, 0, sizeof(payload));
320	memset(&tmp_madw, 0, sizeof(tmp_madw));
321
322	p_smp = osm_madw_get_smp_ptr(p_madw);
323
324	if (p_smp->method != IB_MAD_METHOD_TRAP) {
325		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3801: "
326			"Unsupported method 0x%X\n", p_smp->method);
327		goto Exit;
328	}
329
330	/*
331	 * The NOTICE Attribute is part of the SMP CLASS attributes
332	 * As such the actual attribute data resides inside the SMP
333	 * payload.
334	 */
335
336	memcpy(payload, &(p_smp->data), IB_SMP_DATA_SIZE);
337	memcpy(&tmp_madw, p_madw, sizeof(tmp_madw));
338
339	if (is_gsi == FALSE) {
340		/* We are in smi flow */
341		/*
342		 * When we received a TRAP with dlid = 0 - it means it
343		 * came from our own node. So we need to fix it.
344		 */
345
346		if (p_madw->mad_addr.addr_type.smi.source_lid == 0) {
347			/* Check if the sm_base_lid is 0. If yes - this means
348			   that the local lid wasn't configured yet. Don't send
349			   a response to the trap. */
350			if (sm->p_subn->sm_base_lid == 0) {
351				OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
352					"Received SLID=0 Trap with local LID=0. Ignoring MAD\n");
353				goto Exit;
354			}
355			OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
356				"Received SLID=0 Trap. Using local LID:%u instead\n",
357				cl_ntoh16(sm->p_subn->sm_base_lid));
358			tmp_madw.mad_addr.addr_type.smi.source_lid =
359			    sm->p_subn->sm_base_lid;
360		}
361
362		source_lid = tmp_madw.mad_addr.addr_type.smi.source_lid;
363
364		/* Print some info about the incoming Trap */
365		if (ib_notice_is_generic(p_ntci)) {
366			if ((p_ntci->g_or_v.generic.trap_num == CL_HTON16(129))
367			    || (p_ntci->g_or_v.generic.trap_num ==
368				CL_HTON16(130))
369			    || (p_ntci->g_or_v.generic.trap_num ==
370				CL_HTON16(131)))
371				OSM_LOG(sm->p_log, OSM_LOG_ERROR,
372					"Received Generic Notice type:%u "
373					"num:%u (%s) Producer:%u (%s) "
374					"from LID:%u Port %d TID:0x%016"
375					PRIx64 "\n", ib_notice_get_type(p_ntci),
376					cl_ntoh16(p_ntci->g_or_v.generic.
377						  trap_num),
378					ib_get_trap_str(p_ntci->g_or_v.generic.
379							trap_num),
380					cl_ntoh32(ib_notice_get_prod_type
381						  (p_ntci)),
382					ib_get_producer_type_str
383					(ib_notice_get_prod_type(p_ntci)),
384					cl_hton16(source_lid),
385					p_ntci->data_details.ntc_129_131.
386					port_num, cl_ntoh64(p_smp->trans_id));
387			else
388				OSM_LOG(sm->p_log, OSM_LOG_ERROR,
389					"Received Generic Notice type:%u "
390					"num:%u (%s) Producer:%u (%s) "
391					"from LID:%u TID:0x%016" PRIx64
392					"\n", ib_notice_get_type(p_ntci),
393					cl_ntoh16(p_ntci->g_or_v.generic.
394						  trap_num),
395					ib_get_trap_str(p_ntci->g_or_v.generic.
396							trap_num),
397					cl_ntoh32(ib_notice_get_prod_type
398						  (p_ntci)),
399					ib_get_producer_type_str
400					(ib_notice_get_prod_type(p_ntci)),
401					cl_hton16(source_lid),
402					cl_ntoh64(p_smp->trans_id));
403		} else
404			OSM_LOG(sm->p_log, OSM_LOG_ERROR,
405				"Received Vendor Notice type:%u vend:0x%06X "
406				"dev:%u from LID:%u TID:0x%016" PRIx64 "\n",
407				ib_notice_get_type(p_ntci),
408				cl_ntoh32(ib_notice_get_vend_id(p_ntci)),
409				cl_ntoh16(p_ntci->g_or_v.vend.dev_id),
410				cl_ntoh16(source_lid),
411				cl_ntoh64(p_smp->trans_id));
412	}
413
414	osm_dump_notice(sm->p_log, p_ntci, OSM_LOG_VERBOSE);
415
416	p_physp = osm_get_physp_by_mad_addr(sm->p_log,
417					    sm->p_subn, &tmp_madw.mad_addr);
418	if (p_physp)
419		p_smp->m_key = p_physp->port_info.m_key;
420	else
421		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3809: "
422			"Failed to find source physical port for trap\n");
423
424	status = osm_resp_send(sm, &tmp_madw, 0, payload);
425	if (status != IB_SUCCESS) {
426		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3802: "
427			"Error sending response (%s)\n",
428			ib_get_err_str(status));
429		goto Exit;
430	}
431
432	/*
433	 * We would like to filter out recurring Traps so we track them by
434	 * their source lid and content. If the same trap was already
435	 * received within the aging time window more than 10 times,
436	 * we simply ignore it. This is done only if we are in smi mode
437	 */
438
439	if (is_gsi == FALSE) {
440		if (ib_notice_is_generic(p_ntci) &&
441		    ((p_ntci->g_or_v.generic.trap_num == CL_HTON16(129)) ||
442		     (p_ntci->g_or_v.generic.trap_num == CL_HTON16(130)) ||
443		     (p_ntci->g_or_v.generic.trap_num == CL_HTON16(131)))) {
444			/* If this is a trap 129, 130, or 131 - then this is a
445			 * trap signaling a change on a physical port.
446			 * Mark the physp_change_trap flag as TRUE.
447			 */
448			physp_change_trap = TRUE;
449			/* The source_lid should be based on the source_lid from the trap */
450			source_lid = p_ntci->data_details.ntc_129_131.lid;
451		}
452
453		/* If physp_change_trap is TRUE - the key will include the port number.
454		   If not - the port_number in the key will be zero. */
455		if (physp_change_trap == TRUE) {
456			port_num = p_ntci->data_details.ntc_129_131.port_num;
457			__osm_trap_get_key(source_lid, port_num, p_ntci,
458					   &trap_key);
459		} else
460			__osm_trap_get_key(source_lid, 0, p_ntci, &trap_key);
461
462		/* try to find it in the aging tracker */
463		num_received =
464		    cl_event_wheel_num_regs(&sm->trap_aging_tracker,
465					    trap_key);
466
467		/* Now we know how many times it provided this trap */
468		if (num_received > 10) {
469			if (__print_num_received(num_received))
470				OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3804: "
471					"Received trap %u times consecutively\n",
472					num_received);
473			/*
474			 * If the trap provides info about a bad port
475			 * we mark it as unhealthy.
476			 */
477			if (physp_change_trap == TRUE) {
478				/* get the port */
479				p_physp = get_physp_by_lid_and_num(sm,
480								   cl_ntoh16
481								   (p_ntci->
482								    data_details.
483								    ntc_129_131.
484								    lid),
485								   port_num);
486
487				if (!p_physp)
488					OSM_LOG(sm->p_log, OSM_LOG_ERROR,
489						"ERR 3805: "
490						"Failed to find physical port by lid:%u num:%u\n",
491						cl_ntoh16(p_ntci->data_details.
492							  ntc_129_131.lid),
493						p_ntci->data_details.
494						ntc_129_131.port_num);
495				else {
496					/* When babbling port policy option is enabled and
497					   Threshold for disabling a "babbling" port is exceeded */
498					if (sm->p_subn->opt.
499					    babbling_port_policy
500					    && num_received >= 250
501					    && disable_port(sm, p_physp) == 0)
502						goto Exit;
503
504					OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
505						"Marking unhealthy physical port by lid:%u num:%u\n",
506						cl_ntoh16(p_ntci->data_details.
507							  ntc_129_131.lid),
508						p_ntci->data_details.
509						ntc_129_131.port_num);
510					/* check if the current state of the p_physp is healthy. If
511					   it is - then this is a first change of state. Run a heavy sweep.
512					   if it is not - no need to mark it again - just restart the timer. */
513					if (osm_physp_is_healthy(p_physp)) {
514						osm_physp_set_health(p_physp,
515								     FALSE);
516						/* Make sure we sweep again - force a heavy sweep. */
517						/* The sweep should be done only after the re-registration, or
518						   else we'll be losing track of the timer. */
519						run_heavy_sweep = TRUE;
520					}
521					/* If we are marking the port as unhealthy - we want to
522					   keep this for a longer period of time than the
523					   OSM_DEFAULT_TRAP_SUPRESSION_TIMEOUT. Use the
524					   OSM_DEFAULT_UNHEALTHY_TIMEOUT */
525					event_wheel_timeout =
526					    OSM_DEFAULT_UNHEALTHY_TIMEOUT;
527				}
528			}
529		}
530
531		/* restart the aging anyway */
532		/* If physp_change_trap is TRUE - then use a callback to unset the
533		   healthy bit. If not - no need to use a callback. */
534		if (physp_change_trap == TRUE)
535			cl_event_wheel_reg(&sm->trap_aging_tracker, trap_key, cl_get_time_stamp() + event_wheel_timeout, osm_trap_rcv_aging_tracker_callback,	/* no callback */
536					   sm	/* no context */ );
537		else
538			cl_event_wheel_reg(&sm->trap_aging_tracker, trap_key, cl_get_time_stamp() + event_wheel_timeout, NULL,	/* no callback */
539					   NULL	/* no context */ );
540
541		/* If was already registered do nothing more */
542		if (num_received > 10 && run_heavy_sweep == FALSE) {
543			if (__print_num_received(num_received))
544				OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
545					"Continuously received this trap %u times. Ignoring\n",
546					num_received);
547			goto Exit;
548		}
549	}
550
551	/* Check for node description update. IB Spec v1.2.1 pg 823 */
552	if ((p_ntci->data_details.ntc_144.local_changes & TRAP_144_MASK_OTHER_LOCAL_CHANGES) &&
553		(p_ntci->data_details.ntc_144.change_flgs & TRAP_144_MASK_NODE_DESCRIPTION_CHANGE)
554		) {
555		OSM_LOG(sm->p_log, OSM_LOG_INFO, "Trap 144 Node description update\n");
556
557		if (p_physp) {
558			CL_PLOCK_ACQUIRE(sm->p_lock);
559			osm_req_get_node_desc(sm, p_physp);
560			CL_PLOCK_RELEASE(sm->p_lock);
561		} else {
562			OSM_LOG(sm->p_log, OSM_LOG_ERROR,
563				"ERR 3812: No physical port found for "
564				"trap 144: \"node description update\"\n");
565		}
566	}
567
568	/* do a sweep if we received a trap */
569	if (sm->p_subn->opt.sweep_on_trap) {
570		/* if this is trap number 128 or run_heavy_sweep is TRUE - update the
571		   force_single_heavy_sweep flag of the subnet.
572		   Sweep also on traps 144/145 - these traps signal a change of a certain
573		   port capability/system image guid.
574		   TODO: In the future we can change this to just getting PortInfo on
575		   this port instead of sweeping the entire subnet. */
576		if (ib_notice_is_generic(p_ntci) &&
577		    ((cl_ntoh16(p_ntci->g_or_v.generic.trap_num) == 128) ||
578		     (cl_ntoh16(p_ntci->g_or_v.generic.trap_num) == 144) ||
579		     (cl_ntoh16(p_ntci->g_or_v.generic.trap_num) == 145) ||
580		     run_heavy_sweep)) {
581			OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
582				"Forcing heavy sweep. Received trap:%u\n",
583				cl_ntoh16(p_ntci->g_or_v.generic.trap_num));
584
585			sm->p_subn->force_heavy_sweep = TRUE;
586		}
587		osm_sm_signal(sm, OSM_SIGNAL_SWEEP);
588	}
589
590	/* If we reached here due to trap 129/130/131 - do not need to do
591	   the notice report. Just goto exit. We know this is the case
592	   if physp_change_trap is TRUE. */
593	if (physp_change_trap == TRUE)
594		goto Exit;
595
596	/* Add a call to osm_report_notice */
597	/* We are going to report the notice - so need to fix the IssuerGID
598	   accordingly. See IBA 1.2 p.739 or IBA 1.1 p.653 for details. */
599	if (is_gsi) {
600		if (!tmp_madw.mad_addr.addr_type.gsi.global_route) {
601			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3806: "
602				"Received gsi trap with global_route FALSE. "
603				"Cannot update issuer_gid!\n");
604			goto Exit;
605		}
606		memcpy(&(p_ntci->issuer_gid),
607		       &(tmp_madw.mad_addr.addr_type.gsi.grh_info.src_gid),
608		       sizeof(ib_gid_t));
609	} else {
610		/* Need to use the IssuerLID */
611		p_tbl = &sm->p_subn->port_lid_tbl;
612
613		CL_ASSERT(cl_ptr_vector_get_size(p_tbl) < 0x10000);
614
615		if ((uint16_t) cl_ptr_vector_get_size(p_tbl) <=
616		    cl_ntoh16(source_lid)) {
617			/*  the source lid is out of range */
618			OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
619				"source lid is out of range:%u\n",
620				cl_ntoh16(source_lid));
621
622			goto Exit;
623		}
624		p_port = cl_ptr_vector_get(p_tbl, cl_ntoh16(source_lid));
625		if (p_port == 0) {
626			/* We have the lid - but no corresponding port */
627			OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
628				"Cannot find port corresponding to lid:%u\n",
629				cl_ntoh16(source_lid));
630
631			goto Exit;
632		}
633
634		p_ntci->issuer_gid.unicast.prefix =
635		    sm->p_subn->opt.subnet_prefix;
636		p_ntci->issuer_gid.unicast.interface_id = p_port->guid;
637	}
638
639	/* we need a lock here as the InformInfo DB must be stable */
640	CL_PLOCK_ACQUIRE(sm->p_lock);
641	status = osm_report_notice(sm->p_log, sm->p_subn, p_ntci);
642	CL_PLOCK_RELEASE(sm->p_lock);
643	if (status != IB_SUCCESS) {
644		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3803: "
645			"Error sending trap reports (%s)\n",
646			ib_get_err_str(status));
647		goto Exit;
648	}
649
650Exit:
651	OSM_LOG_EXIT(sm->p_log);
652}
653
654#if 0
655/**********************************************************************
656 CURRENTLY WE ARE NOT CREATING TRAPS - SO THIS CALL IS AN ERROR
657**********************************************************************/
658static void
659__osm_trap_rcv_process_sm(IN osm_sm_t * sm,
660			  IN const osm_remote_sm_t * const p_sm)
661{
662	/* const ib_sm_info_t*        p_smi; */
663
664	OSM_LOG_ENTER(sm->p_log);
665
666	OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3807: "
667		"This function is not supported yet\n");
668
669	OSM_LOG_EXIT(sm->p_log);
670}
671#endif
672
673/**********************************************************************
674 CURRENTLY WE ARE NOT CREATING TRAPS - SO THIS CALL IN AN ERROR
675**********************************************************************/
676static void
677__osm_trap_rcv_process_response(IN osm_sm_t * sm,
678				IN const osm_madw_t * const p_madw)
679{
680
681	OSM_LOG_ENTER(sm->p_log);
682
683	OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3808: "
684		"This function is not supported yet\n");
685
686	OSM_LOG_EXIT(sm->p_log);
687}
688
689/**********************************************************************
690 **********************************************************************/
691void osm_trap_rcv_process(IN void *context, IN void *data)
692{
693	osm_sm_t *sm = context;
694	osm_madw_t *p_madw = data;
695	ib_smp_t *p_smp;
696
697	OSM_LOG_ENTER(sm->p_log);
698
699	CL_ASSERT(p_madw);
700
701	p_smp = osm_madw_get_smp_ptr(p_madw);
702
703	/*
704	   Determine if this is a request for our own Trap
705	   or if this is a response to our request for another
706	   SM's Trap.
707	 */
708	if (ib_smp_is_response(p_smp))
709		__osm_trap_rcv_process_response(sm, p_madw);
710	else
711		__osm_trap_rcv_process_request(sm, p_madw);
712
713	OSM_LOG_EXIT(sm->p_log);
714}
715