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