1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3219820Sjeff * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5219820Sjeff *
6219820Sjeff * This software is available to you under a choice of one of two
7219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
8219820Sjeff * General Public License (GPL) Version 2, available from the file
9219820Sjeff * COPYING in the main directory of this source tree, or the
10219820Sjeff * OpenIB.org BSD license below:
11219820Sjeff *
12219820Sjeff *     Redistribution and use in source and binary forms, with or
13219820Sjeff *     without modification, are permitted provided that the following
14219820Sjeff *     conditions are met:
15219820Sjeff *
16219820Sjeff *      - Redistributions of source code must retain the above
17219820Sjeff *        copyright notice, this list of conditions and the following
18219820Sjeff *        disclaimer.
19219820Sjeff *
20219820Sjeff *      - Redistributions in binary form must reproduce the above
21219820Sjeff *        copyright notice, this list of conditions and the following
22219820Sjeff *        disclaimer in the documentation and/or other materials
23219820Sjeff *        provided with the distribution.
24219820Sjeff *
25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32219820Sjeff * SOFTWARE.
33219820Sjeff *
34219820Sjeff */
35219820Sjeff
36219820Sjeff/*
37219820Sjeff * Abstract:
38219820Sjeff *    Implementation of osm_node_t.
39219820Sjeff * This object represents an Infiniband Node.
40219820Sjeff * This object is part of the opensm family of objects.
41219820Sjeff */
42219820Sjeff
43219820Sjeff#if HAVE_CONFIG_H
44219820Sjeff#  include <config.h>
45219820Sjeff#endif				/* HAVE_CONFIG_H */
46219820Sjeff
47219820Sjeff#include <stdlib.h>
48219820Sjeff#include <iba/ib_types.h>
49219820Sjeff#include <opensm/osm_node.h>
50219820Sjeff#include <opensm/osm_madw.h>
51219820Sjeff
52219820Sjeff/**********************************************************************
53219820Sjeff **********************************************************************/
54219820Sjeffvoid
55219820Sjeffosm_node_init_physp(IN osm_node_t * const p_node,
56219820Sjeff		    IN const osm_madw_t * const p_madw)
57219820Sjeff{
58219820Sjeff	ib_net64_t port_guid;
59219820Sjeff	ib_smp_t *p_smp;
60219820Sjeff	ib_node_info_t *p_ni;
61219820Sjeff	uint8_t port_num;
62219820Sjeff
63219820Sjeff	p_smp = osm_madw_get_smp_ptr(p_madw);
64219820Sjeff
65219820Sjeff	p_ni = (ib_node_info_t *) ib_smp_get_payload_ptr(p_smp);
66219820Sjeff	port_guid = p_ni->port_guid;
67219820Sjeff	port_num = ib_node_info_get_local_port_num(p_ni);
68219820Sjeff
69219820Sjeff	CL_ASSERT(port_num < p_node->physp_tbl_size);
70219820Sjeff
71219820Sjeff	osm_physp_init(&p_node->physp_table[port_num],
72219820Sjeff		       port_guid, port_num, p_node,
73219820Sjeff		       osm_madw_get_bind_handle(p_madw),
74219820Sjeff		       p_smp->hop_count, p_smp->initial_path);
75219820Sjeff}
76219820Sjeff
77219820Sjeff/**********************************************************************
78219820Sjeff **********************************************************************/
79219820Sjeffstatic void node_init_physp0(IN osm_node_t * const p_node,
80219820Sjeff			     IN const osm_madw_t * const p_madw)
81219820Sjeff{
82219820Sjeff	ib_smp_t *p_smp;
83219820Sjeff	ib_node_info_t *p_ni;
84219820Sjeff
85219820Sjeff	p_smp = osm_madw_get_smp_ptr(p_madw);
86219820Sjeff	p_ni = (ib_node_info_t *) ib_smp_get_payload_ptr(p_smp);
87219820Sjeff
88219820Sjeff	osm_physp_init(&p_node->physp_table[0],
89219820Sjeff		       p_ni->port_guid, 0, p_node,
90219820Sjeff		       osm_madw_get_bind_handle(p_madw),
91219820Sjeff		       p_smp->hop_count, p_smp->initial_path);
92219820Sjeff}
93219820Sjeff
94219820Sjeff/**********************************************************************
95219820Sjeff **********************************************************************/
96219820Sjeffosm_node_t *osm_node_new(IN const osm_madw_t * const p_madw)
97219820Sjeff{
98219820Sjeff	osm_node_t *p_node;
99219820Sjeff	ib_smp_t *p_smp;
100219820Sjeff	ib_node_info_t *p_ni;
101219820Sjeff	uint8_t i;
102219820Sjeff	uint32_t size;
103219820Sjeff
104219820Sjeff	p_smp = osm_madw_get_smp_ptr(p_madw);
105219820Sjeff	p_ni = (ib_node_info_t *) ib_smp_get_payload_ptr(p_smp);
106219820Sjeff
107219820Sjeff	/*
108219820Sjeff	   The node object already contains one physical port object.
109219820Sjeff	   Therefore, subtract 1 from the number of physical ports
110219820Sjeff	   used by the switch.  This is not done for CA's since they
111219820Sjeff	   need to occupy 1 more physp than they physically have since
112219820Sjeff	   we still reserve room for a "port 0".
113219820Sjeff	 */
114219820Sjeff	size = p_ni->num_ports;
115219820Sjeff
116219820Sjeff	p_node = malloc(sizeof(*p_node) + sizeof(osm_physp_t) * size);
117219820Sjeff	if (!p_node)
118219820Sjeff		return NULL;
119219820Sjeff
120219820Sjeff	memset(p_node, 0, sizeof(*p_node) + sizeof(osm_physp_t) * size);
121219820Sjeff	p_node->node_info = *p_ni;
122219820Sjeff	p_node->physp_tbl_size = size + 1;
123219820Sjeff
124219820Sjeff	/*
125219820Sjeff	   Construct Physical Port objects owned by this Node.
126219820Sjeff	   Then, initialize the Physical Port through with we
127219820Sjeff	   discovered this port.
128219820Sjeff	   For switches, all ports have the same GUID.
129219820Sjeff	   For CAs and routers, each port has a different GUID, so we only
130219820Sjeff	   know the GUID for the port that responded to our
131219820Sjeff	   Get(NodeInfo).
132219820Sjeff	 */
133219820Sjeff	for (i = 0; i < p_node->physp_tbl_size; i++)
134219820Sjeff		osm_physp_construct(&p_node->physp_table[i]);
135219820Sjeff
136219820Sjeff	osm_node_init_physp(p_node, p_madw);
137219820Sjeff	if (p_ni->node_type == IB_NODE_TYPE_SWITCH)
138219820Sjeff		node_init_physp0(p_node, p_madw);
139219820Sjeff	p_node->print_desc = strdup(OSM_NODE_DESC_UNKNOWN);
140219820Sjeff
141219820Sjeff	return (p_node);
142219820Sjeff}
143219820Sjeff
144219820Sjeff/**********************************************************************
145219820Sjeff **********************************************************************/
146219820Sjeffstatic void osm_node_destroy(IN osm_node_t * p_node)
147219820Sjeff{
148219820Sjeff	uint16_t i;
149219820Sjeff
150219820Sjeff	/*
151219820Sjeff	   Cleanup all physports
152219820Sjeff	 */
153219820Sjeff	for (i = 0; i < p_node->physp_tbl_size; i++)
154219820Sjeff		osm_physp_destroy(&p_node->physp_table[i]);
155219820Sjeff
156219820Sjeff	/* cleanup printable node_desc field */
157219820Sjeff	if (p_node->print_desc) {
158219820Sjeff		free(p_node->print_desc);
159219820Sjeff	}
160219820Sjeff}
161219820Sjeff
162219820Sjeff/**********************************************************************
163219820Sjeff **********************************************************************/
164219820Sjeffvoid osm_node_delete(IN OUT osm_node_t ** const p_node)
165219820Sjeff{
166219820Sjeff	CL_ASSERT(p_node && *p_node);
167219820Sjeff	osm_node_destroy(*p_node);
168219820Sjeff	free(*p_node);
169219820Sjeff	*p_node = NULL;
170219820Sjeff}
171219820Sjeff
172219820Sjeff/**********************************************************************
173219820Sjeff **********************************************************************/
174219820Sjeffvoid
175219820Sjeffosm_node_link(IN osm_node_t * const p_node,
176219820Sjeff	      IN const uint8_t port_num,
177219820Sjeff	      IN osm_node_t * const p_remote_node,
178219820Sjeff	      IN const uint8_t remote_port_num)
179219820Sjeff{
180219820Sjeff	osm_physp_t *p_physp;
181219820Sjeff	osm_physp_t *p_remote_physp;
182219820Sjeff
183219820Sjeff	CL_ASSERT(port_num < p_node->physp_tbl_size);
184219820Sjeff	CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size);
185219820Sjeff
186219820Sjeff	p_physp = osm_node_get_physp_ptr(p_node, port_num);
187219820Sjeff	p_remote_physp = osm_node_get_physp_ptr(p_remote_node, remote_port_num);
188219820Sjeff
189219820Sjeff	if (p_physp->p_remote_physp)
190219820Sjeff		p_physp->p_remote_physp->p_remote_physp = NULL;
191219820Sjeff	if (p_remote_physp->p_remote_physp)
192219820Sjeff		p_remote_physp->p_remote_physp->p_remote_physp = NULL;
193219820Sjeff
194219820Sjeff	osm_physp_link(p_physp, p_remote_physp);
195219820Sjeff}
196219820Sjeff
197219820Sjeff/**********************************************************************
198219820Sjeff **********************************************************************/
199219820Sjeffvoid
200219820Sjeffosm_node_unlink(IN osm_node_t * const p_node,
201219820Sjeff		IN const uint8_t port_num,
202219820Sjeff		IN osm_node_t * const p_remote_node,
203219820Sjeff		IN const uint8_t remote_port_num)
204219820Sjeff{
205219820Sjeff	osm_physp_t *p_physp;
206219820Sjeff	osm_physp_t *p_remote_physp;
207219820Sjeff
208219820Sjeff	CL_ASSERT(port_num < p_node->physp_tbl_size);
209219820Sjeff	CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size);
210219820Sjeff
211219820Sjeff	if (osm_node_link_exists(p_node, port_num,
212219820Sjeff				 p_remote_node, remote_port_num)) {
213219820Sjeff
214219820Sjeff		p_physp = osm_node_get_physp_ptr(p_node, port_num);
215219820Sjeff		p_remote_physp =
216219820Sjeff		    osm_node_get_physp_ptr(p_remote_node, remote_port_num);
217219820Sjeff
218219820Sjeff		osm_physp_unlink(p_physp, p_remote_physp);
219219820Sjeff	}
220219820Sjeff}
221219820Sjeff
222219820Sjeff/**********************************************************************
223219820Sjeff **********************************************************************/
224219820Sjeffboolean_t
225219820Sjeffosm_node_link_exists(IN osm_node_t * const p_node,
226219820Sjeff		     IN const uint8_t port_num,
227219820Sjeff		     IN osm_node_t * const p_remote_node,
228219820Sjeff		     IN const uint8_t remote_port_num)
229219820Sjeff{
230219820Sjeff	osm_physp_t *p_physp;
231219820Sjeff	osm_physp_t *p_remote_physp;
232219820Sjeff
233219820Sjeff	CL_ASSERT(port_num < p_node->physp_tbl_size);
234219820Sjeff	CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size);
235219820Sjeff
236219820Sjeff	p_physp = osm_node_get_physp_ptr(p_node, port_num);
237219820Sjeff	p_remote_physp = osm_node_get_physp_ptr(p_remote_node, remote_port_num);
238219820Sjeff
239219820Sjeff	return (osm_physp_link_exists(p_physp, p_remote_physp));
240219820Sjeff}
241219820Sjeff
242219820Sjeff/**********************************************************************
243219820Sjeff **********************************************************************/
244219820Sjeffboolean_t
245219820Sjeffosm_node_link_has_valid_ports(IN osm_node_t * const p_node,
246219820Sjeff			      IN const uint8_t port_num,
247219820Sjeff			      IN osm_node_t * const p_remote_node,
248219820Sjeff			      IN const uint8_t remote_port_num)
249219820Sjeff{
250219820Sjeff	osm_physp_t *p_physp;
251219820Sjeff	osm_physp_t *p_remote_physp;
252219820Sjeff
253219820Sjeff	CL_ASSERT(port_num < p_node->physp_tbl_size);
254219820Sjeff	CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size);
255219820Sjeff
256219820Sjeff	p_physp = osm_node_get_physp_ptr(p_node, port_num);
257219820Sjeff	p_remote_physp = osm_node_get_physp_ptr(p_remote_node, remote_port_num);
258219820Sjeff
259219820Sjeff	return (p_physp && p_remote_physp);
260219820Sjeff}
261219820Sjeff
262219820Sjeff/**********************************************************************
263219820Sjeff **********************************************************************/
264219820Sjeffboolean_t
265219820Sjeffosm_node_has_any_link(IN osm_node_t * const p_node, IN const uint8_t port_num)
266219820Sjeff{
267219820Sjeff	osm_physp_t *p_physp;
268219820Sjeff	CL_ASSERT(port_num < p_node->physp_tbl_size);
269219820Sjeff	p_physp = osm_node_get_physp_ptr(p_node, port_num);
270219820Sjeff	return (osm_physp_has_any_link(p_physp));
271219820Sjeff}
272219820Sjeff
273219820Sjeff/**********************************************************************
274219820Sjeff **********************************************************************/
275219820Sjeffosm_node_t *osm_node_get_remote_node(IN osm_node_t * const p_node,
276219820Sjeff				     IN const uint8_t port_num,
277219820Sjeff				     OUT uint8_t * p_remote_port_num)
278219820Sjeff{
279219820Sjeff	osm_physp_t *p_physp;
280219820Sjeff	osm_physp_t *p_remote_physp;
281219820Sjeff
282219820Sjeff	p_physp = osm_node_get_physp_ptr(p_node, port_num);
283219820Sjeff
284219820Sjeff	if (!p_physp || !osm_physp_has_any_link(p_physp))
285219820Sjeff		return (NULL);
286219820Sjeff
287219820Sjeff	p_remote_physp = osm_physp_get_remote(p_physp);
288219820Sjeff	if (p_remote_port_num)
289219820Sjeff		*p_remote_port_num = osm_physp_get_port_num(p_remote_physp);
290219820Sjeff
291219820Sjeff	return (osm_physp_get_node_ptr(p_remote_physp));
292219820Sjeff}
293219820Sjeff
294219820Sjeff/**********************************************************************
295219820Sjeff The lock must be held before calling this function.
296219820Sjeff**********************************************************************/
297219820Sjeffib_net16_t
298219820Sjeffosm_node_get_remote_base_lid(IN osm_node_t * const p_node,
299219820Sjeff			     IN const uint32_t port_num)
300219820Sjeff{
301219820Sjeff	osm_physp_t *p_physp;
302219820Sjeff	osm_physp_t *p_remote_physp;
303219820Sjeff	CL_ASSERT(port_num < p_node->physp_tbl_size);
304219820Sjeff
305219820Sjeff	p_physp = osm_node_get_physp_ptr(p_node, port_num);
306219820Sjeff	if (p_physp) {
307219820Sjeff		p_remote_physp = osm_physp_get_remote(p_physp);
308219820Sjeff		return (osm_physp_get_base_lid(p_remote_physp));
309219820Sjeff	}
310219820Sjeff
311219820Sjeff	return (0);
312219820Sjeff}
313