1/* 2 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. 3 * Copyright (c) 2002-2005 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_node_t. 39 * This object represents an Infiniband Node. 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 <stdlib.h> 48#include <iba/ib_types.h> 49#include <opensm/osm_node.h> 50#include <opensm/osm_madw.h> 51 52/********************************************************************** 53 **********************************************************************/ 54void 55osm_node_init_physp(IN osm_node_t * const p_node, 56 IN const osm_madw_t * const p_madw) 57{ 58 ib_net64_t port_guid; 59 ib_smp_t *p_smp; 60 ib_node_info_t *p_ni; 61 uint8_t port_num; 62 63 p_smp = osm_madw_get_smp_ptr(p_madw); 64 65 p_ni = (ib_node_info_t *) ib_smp_get_payload_ptr(p_smp); 66 port_guid = p_ni->port_guid; 67 port_num = ib_node_info_get_local_port_num(p_ni); 68 69 CL_ASSERT(port_num < p_node->physp_tbl_size); 70 71 osm_physp_init(&p_node->physp_table[port_num], 72 port_guid, port_num, p_node, 73 osm_madw_get_bind_handle(p_madw), 74 p_smp->hop_count, p_smp->initial_path); 75} 76 77/********************************************************************** 78 **********************************************************************/ 79static void node_init_physp0(IN osm_node_t * const p_node, 80 IN const osm_madw_t * const p_madw) 81{ 82 ib_smp_t *p_smp; 83 ib_node_info_t *p_ni; 84 85 p_smp = osm_madw_get_smp_ptr(p_madw); 86 p_ni = (ib_node_info_t *) ib_smp_get_payload_ptr(p_smp); 87 88 osm_physp_init(&p_node->physp_table[0], 89 p_ni->port_guid, 0, p_node, 90 osm_madw_get_bind_handle(p_madw), 91 p_smp->hop_count, p_smp->initial_path); 92} 93 94/********************************************************************** 95 **********************************************************************/ 96osm_node_t *osm_node_new(IN const osm_madw_t * const p_madw) 97{ 98 osm_node_t *p_node; 99 ib_smp_t *p_smp; 100 ib_node_info_t *p_ni; 101 uint8_t i; 102 uint32_t size; 103 104 p_smp = osm_madw_get_smp_ptr(p_madw); 105 p_ni = (ib_node_info_t *) ib_smp_get_payload_ptr(p_smp); 106 107 /* 108 The node object already contains one physical port object. 109 Therefore, subtract 1 from the number of physical ports 110 used by the switch. This is not done for CA's since they 111 need to occupy 1 more physp than they physically have since 112 we still reserve room for a "port 0". 113 */ 114 size = p_ni->num_ports; 115 116 p_node = malloc(sizeof(*p_node) + sizeof(osm_physp_t) * size); 117 if (!p_node) 118 return NULL; 119 120 memset(p_node, 0, sizeof(*p_node) + sizeof(osm_physp_t) * size); 121 p_node->node_info = *p_ni; 122 p_node->physp_tbl_size = size + 1; 123 124 /* 125 Construct Physical Port objects owned by this Node. 126 Then, initialize the Physical Port through with we 127 discovered this port. 128 For switches, all ports have the same GUID. 129 For CAs and routers, each port has a different GUID, so we only 130 know the GUID for the port that responded to our 131 Get(NodeInfo). 132 */ 133 for (i = 0; i < p_node->physp_tbl_size; i++) 134 osm_physp_construct(&p_node->physp_table[i]); 135 136 osm_node_init_physp(p_node, p_madw); 137 if (p_ni->node_type == IB_NODE_TYPE_SWITCH) 138 node_init_physp0(p_node, p_madw); 139 p_node->print_desc = strdup(OSM_NODE_DESC_UNKNOWN); 140 141 return (p_node); 142} 143 144/********************************************************************** 145 **********************************************************************/ 146static void osm_node_destroy(IN osm_node_t * p_node) 147{ 148 uint16_t i; 149 150 /* 151 Cleanup all physports 152 */ 153 for (i = 0; i < p_node->physp_tbl_size; i++) 154 osm_physp_destroy(&p_node->physp_table[i]); 155 156 /* cleanup printable node_desc field */ 157 if (p_node->print_desc) { 158 free(p_node->print_desc); 159 } 160} 161 162/********************************************************************** 163 **********************************************************************/ 164void osm_node_delete(IN OUT osm_node_t ** const p_node) 165{ 166 CL_ASSERT(p_node && *p_node); 167 osm_node_destroy(*p_node); 168 free(*p_node); 169 *p_node = NULL; 170} 171 172/********************************************************************** 173 **********************************************************************/ 174void 175osm_node_link(IN osm_node_t * const p_node, 176 IN const uint8_t port_num, 177 IN osm_node_t * const p_remote_node, 178 IN const uint8_t remote_port_num) 179{ 180 osm_physp_t *p_physp; 181 osm_physp_t *p_remote_physp; 182 183 CL_ASSERT(port_num < p_node->physp_tbl_size); 184 CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size); 185 186 p_physp = osm_node_get_physp_ptr(p_node, port_num); 187 p_remote_physp = osm_node_get_physp_ptr(p_remote_node, remote_port_num); 188 189 if (p_physp->p_remote_physp) 190 p_physp->p_remote_physp->p_remote_physp = NULL; 191 if (p_remote_physp->p_remote_physp) 192 p_remote_physp->p_remote_physp->p_remote_physp = NULL; 193 194 osm_physp_link(p_physp, p_remote_physp); 195} 196 197/********************************************************************** 198 **********************************************************************/ 199void 200osm_node_unlink(IN osm_node_t * const p_node, 201 IN const uint8_t port_num, 202 IN osm_node_t * const p_remote_node, 203 IN const uint8_t remote_port_num) 204{ 205 osm_physp_t *p_physp; 206 osm_physp_t *p_remote_physp; 207 208 CL_ASSERT(port_num < p_node->physp_tbl_size); 209 CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size); 210 211 if (osm_node_link_exists(p_node, port_num, 212 p_remote_node, remote_port_num)) { 213 214 p_physp = osm_node_get_physp_ptr(p_node, port_num); 215 p_remote_physp = 216 osm_node_get_physp_ptr(p_remote_node, remote_port_num); 217 218 osm_physp_unlink(p_physp, p_remote_physp); 219 } 220} 221 222/********************************************************************** 223 **********************************************************************/ 224boolean_t 225osm_node_link_exists(IN osm_node_t * const p_node, 226 IN const uint8_t port_num, 227 IN osm_node_t * const p_remote_node, 228 IN const uint8_t remote_port_num) 229{ 230 osm_physp_t *p_physp; 231 osm_physp_t *p_remote_physp; 232 233 CL_ASSERT(port_num < p_node->physp_tbl_size); 234 CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size); 235 236 p_physp = osm_node_get_physp_ptr(p_node, port_num); 237 p_remote_physp = osm_node_get_physp_ptr(p_remote_node, remote_port_num); 238 239 return (osm_physp_link_exists(p_physp, p_remote_physp)); 240} 241 242/********************************************************************** 243 **********************************************************************/ 244boolean_t 245osm_node_link_has_valid_ports(IN osm_node_t * const p_node, 246 IN const uint8_t port_num, 247 IN osm_node_t * const p_remote_node, 248 IN const uint8_t remote_port_num) 249{ 250 osm_physp_t *p_physp; 251 osm_physp_t *p_remote_physp; 252 253 CL_ASSERT(port_num < p_node->physp_tbl_size); 254 CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size); 255 256 p_physp = osm_node_get_physp_ptr(p_node, port_num); 257 p_remote_physp = osm_node_get_physp_ptr(p_remote_node, remote_port_num); 258 259 return (p_physp && p_remote_physp); 260} 261 262/********************************************************************** 263 **********************************************************************/ 264boolean_t 265osm_node_has_any_link(IN osm_node_t * const p_node, IN const uint8_t port_num) 266{ 267 osm_physp_t *p_physp; 268 CL_ASSERT(port_num < p_node->physp_tbl_size); 269 p_physp = osm_node_get_physp_ptr(p_node, port_num); 270 return (osm_physp_has_any_link(p_physp)); 271} 272 273/********************************************************************** 274 **********************************************************************/ 275osm_node_t *osm_node_get_remote_node(IN osm_node_t * const p_node, 276 IN const uint8_t port_num, 277 OUT uint8_t * p_remote_port_num) 278{ 279 osm_physp_t *p_physp; 280 osm_physp_t *p_remote_physp; 281 282 p_physp = osm_node_get_physp_ptr(p_node, port_num); 283 284 if (!p_physp || !osm_physp_has_any_link(p_physp)) 285 return (NULL); 286 287 p_remote_physp = osm_physp_get_remote(p_physp); 288 if (p_remote_port_num) 289 *p_remote_port_num = osm_physp_get_port_num(p_remote_physp); 290 291 return (osm_physp_get_node_ptr(p_remote_physp)); 292} 293 294/********************************************************************** 295 The lock must be held before calling this function. 296**********************************************************************/ 297ib_net16_t 298osm_node_get_remote_base_lid(IN osm_node_t * const p_node, 299 IN const uint32_t port_num) 300{ 301 osm_physp_t *p_physp; 302 osm_physp_t *p_remote_physp; 303 CL_ASSERT(port_num < p_node->physp_tbl_size); 304 305 p_physp = osm_node_get_physp_ptr(p_node, port_num); 306 if (p_physp) { 307 p_remote_physp = osm_physp_get_remote(p_physp); 308 return (osm_physp_get_base_lid(p_remote_physp)); 309 } 310 311 return (0); 312} 313