1/* 2 * Copyright (c) 2006-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_gir_rcv_t. 39 * This object represents the GUIDInfoRecord 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_passivelock.h> 51#include <complib/cl_debug.h> 52#include <complib/cl_qlist.h> 53#include <vendor/osm_vendor_api.h> 54#include <opensm/osm_port.h> 55#include <opensm/osm_node.h> 56#include <opensm/osm_helper.h> 57#include <opensm/osm_pkey.h> 58#include <opensm/osm_sa.h> 59 60typedef struct osm_gir_item { 61 cl_list_item_t list_item; 62 ib_guidinfo_record_t rec; 63} osm_gir_item_t; 64 65typedef struct osm_gir_search_ctxt { 66 const ib_guidinfo_record_t *p_rcvd_rec; 67 ib_net64_t comp_mask; 68 cl_qlist_t *p_list; 69 osm_sa_t *sa; 70 const osm_physp_t *p_req_physp; 71} osm_gir_search_ctxt_t; 72 73/********************************************************************** 74 **********************************************************************/ 75static ib_api_status_t 76__osm_gir_rcv_new_gir(IN osm_sa_t * sa, 77 IN const osm_node_t * const p_node, 78 IN cl_qlist_t * const p_list, 79 IN ib_net64_t const match_port_guid, 80 IN ib_net16_t const match_lid, 81 IN const osm_physp_t * const p_req_physp, 82 IN uint8_t const block_num) 83{ 84 osm_gir_item_t *p_rec_item; 85 ib_api_status_t status = IB_SUCCESS; 86 87 OSM_LOG_ENTER(sa->p_log); 88 89 p_rec_item = malloc(sizeof(*p_rec_item)); 90 if (p_rec_item == NULL) { 91 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 5102: " 92 "rec_item alloc failed\n"); 93 status = IB_INSUFFICIENT_RESOURCES; 94 goto Exit; 95 } 96 97 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 98 "New GUIDInfoRecord: lid %u, block num %d\n", 99 cl_ntoh16(match_lid), block_num); 100 101 memset(p_rec_item, 0, sizeof(*p_rec_item)); 102 103 p_rec_item->rec.lid = match_lid; 104 p_rec_item->rec.block_num = block_num; 105 if (!block_num) 106 p_rec_item->rec.guid_info.guid[0] = 107 osm_physp_get_port_guid(p_req_physp); 108 109 cl_qlist_insert_tail(p_list, &p_rec_item->list_item); 110 111Exit: 112 OSM_LOG_EXIT(sa->p_log); 113 return (status); 114} 115 116/********************************************************************** 117 **********************************************************************/ 118static void 119__osm_sa_gir_create_gir(IN osm_sa_t * sa, 120 IN osm_node_t * const p_node, 121 IN cl_qlist_t * const p_list, 122 IN ib_net64_t const match_port_guid, 123 IN ib_net16_t const match_lid, 124 IN const osm_physp_t * const p_req_physp, 125 IN uint8_t const match_block_num) 126{ 127 const osm_physp_t *p_physp; 128 uint8_t port_num; 129 uint8_t num_ports; 130 uint16_t match_lid_ho; 131 ib_net16_t base_lid_ho; 132 ib_net16_t max_lid_ho; 133 uint8_t lmc; 134 ib_net64_t port_guid; 135 uint8_t block_num, start_block_num, end_block_num, num_blocks; 136 137 OSM_LOG_ENTER(sa->p_log); 138 139 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 140 "Looking for GUIDRecord with LID: %u GUID:0x%016" 141 PRIx64 "\n", cl_ntoh16(match_lid), cl_ntoh64(match_port_guid)); 142 143 /* 144 For switches, do not return the GUIDInfo record(s) 145 for each port on the switch, just for port 0. 146 */ 147 if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH) 148 num_ports = 1; 149 else 150 num_ports = osm_node_get_num_physp(p_node); 151 152 for (port_num = 0; port_num < num_ports; port_num++) { 153 p_physp = osm_node_get_physp_ptr(p_node, port_num); 154 if (!p_physp) 155 continue; 156 157 /* Check to see if the found p_physp and the requester physp 158 share a pkey. If not, continue */ 159 if (!osm_physp_share_pkey(sa->p_log, p_physp, p_req_physp)) 160 continue; 161 162 port_guid = osm_physp_get_port_guid(p_physp); 163 164 if (match_port_guid && (port_guid != match_port_guid)) 165 continue; 166 167 /* 168 Note: the following check is a temporary workaround 169 Since 1. GUIDCap should never be 0 on ports where this applies 170 and 2. GUIDCap should not be used on ports where it doesn't apply 171 So this should really be a check for whether the port is a 172 switch external port or not! 173 */ 174 if (p_physp->port_info.guid_cap == 0) 175 continue; 176 177 num_blocks = p_physp->port_info.guid_cap / 8; 178 if (p_physp->port_info.guid_cap % 8) 179 num_blocks++; 180 if (match_block_num == 255) { 181 start_block_num = 0; 182 end_block_num = num_blocks - 1; 183 } else { 184 if (match_block_num >= num_blocks) 185 continue; 186 end_block_num = start_block_num = match_block_num; 187 } 188 189 base_lid_ho = cl_ntoh16(osm_physp_get_base_lid(p_physp)); 190 match_lid_ho = cl_ntoh16(match_lid); 191 if (match_lid_ho) { 192 lmc = osm_physp_get_lmc(p_physp); 193 max_lid_ho = (uint16_t) (base_lid_ho + (1 << lmc) - 1); 194 195 /* 196 We validate that the lid belongs to this node. 197 */ 198 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 199 "Comparing LID: %u <= %u <= %u\n", 200 base_lid_ho, match_lid_ho, max_lid_ho); 201 202 if (match_lid_ho < base_lid_ho 203 || match_lid_ho > max_lid_ho) 204 continue; 205 } 206 207 for (block_num = start_block_num; block_num <= end_block_num; 208 block_num++) 209 __osm_gir_rcv_new_gir(sa, p_node, p_list, port_guid, 210 cl_ntoh16(base_lid_ho), p_physp, 211 block_num); 212 213 } 214 215 OSM_LOG_EXIT(sa->p_log); 216} 217 218/********************************************************************** 219 **********************************************************************/ 220static void 221__osm_sa_gir_by_comp_mask_cb(IN cl_map_item_t * const p_map_item, 222 IN void *context) 223{ 224 const osm_gir_search_ctxt_t *const p_ctxt = 225 (osm_gir_search_ctxt_t *) context; 226 osm_node_t *const p_node = (osm_node_t *) p_map_item; 227 const ib_guidinfo_record_t *const p_rcvd_rec = p_ctxt->p_rcvd_rec; 228 const osm_physp_t *const p_req_physp = p_ctxt->p_req_physp; 229 osm_sa_t *sa = p_ctxt->sa; 230 const ib_guid_info_t *p_comp_gi; 231 ib_net64_t const comp_mask = p_ctxt->comp_mask; 232 ib_net64_t match_port_guid = 0; 233 ib_net16_t match_lid = 0; 234 uint8_t match_block_num = 255; 235 236 OSM_LOG_ENTER(p_ctxt->sa->p_log); 237 238 if (comp_mask & IB_GIR_COMPMASK_LID) 239 match_lid = p_rcvd_rec->lid; 240 241 if (comp_mask & IB_GIR_COMPMASK_BLOCKNUM) 242 match_block_num = p_rcvd_rec->block_num; 243 244 p_comp_gi = &p_rcvd_rec->guid_info; 245 /* Different rule for block 0 v. other blocks */ 246 if (comp_mask & IB_GIR_COMPMASK_GID0) { 247 if (!p_rcvd_rec->block_num) 248 match_port_guid = osm_physp_get_port_guid(p_req_physp); 249 if (p_comp_gi->guid[0] != match_port_guid) 250 goto Exit; 251 } 252 253 if (comp_mask & IB_GIR_COMPMASK_GID1) { 254 if (p_comp_gi->guid[1] != 0) 255 goto Exit; 256 } 257 258 if (comp_mask & IB_GIR_COMPMASK_GID2) { 259 if (p_comp_gi->guid[2] != 0) 260 goto Exit; 261 } 262 263 if (comp_mask & IB_GIR_COMPMASK_GID3) { 264 if (p_comp_gi->guid[3] != 0) 265 goto Exit; 266 } 267 268 if (comp_mask & IB_GIR_COMPMASK_GID4) { 269 if (p_comp_gi->guid[4] != 0) 270 goto Exit; 271 } 272 273 if (comp_mask & IB_GIR_COMPMASK_GID5) { 274 if (p_comp_gi->guid[5] != 0) 275 goto Exit; 276 } 277 278 if (comp_mask & IB_GIR_COMPMASK_GID6) { 279 if (p_comp_gi->guid[6] != 0) 280 goto Exit; 281 } 282 283 if (comp_mask & IB_GIR_COMPMASK_GID7) { 284 if (p_comp_gi->guid[7] != 0) 285 goto Exit; 286 } 287 288 __osm_sa_gir_create_gir(sa, p_node, p_ctxt->p_list, 289 match_port_guid, match_lid, p_req_physp, 290 match_block_num); 291 292Exit: 293 OSM_LOG_EXIT(p_ctxt->sa->p_log); 294} 295 296/********************************************************************** 297 **********************************************************************/ 298void osm_gir_rcv_process(IN void *ctx, IN void *data) 299{ 300 osm_sa_t *sa = ctx; 301 osm_madw_t *p_madw = data; 302 const ib_sa_mad_t *p_rcvd_mad; 303 const ib_guidinfo_record_t *p_rcvd_rec; 304 cl_qlist_t rec_list; 305 osm_gir_search_ctxt_t context; 306 osm_physp_t *p_req_physp; 307 308 CL_ASSERT(sa); 309 310 OSM_LOG_ENTER(sa->p_log); 311 312 CL_ASSERT(p_madw); 313 314 p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw); 315 p_rcvd_rec = 316 (ib_guidinfo_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); 317 318 CL_ASSERT(p_rcvd_mad->attr_id == IB_MAD_ATTR_GUIDINFO_RECORD); 319 320 /* we only support SubnAdmGet and SubnAdmGetTable methods */ 321 if (p_rcvd_mad->method != IB_MAD_METHOD_GET && 322 p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) { 323 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 5105: " 324 "Unsupported Method (%s)\n", 325 ib_get_sa_method_str(p_rcvd_mad->method)); 326 osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); 327 goto Exit; 328 } 329 330 /* update the requester physical port. */ 331 p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, 332 osm_madw_get_mad_addr_ptr 333 (p_madw)); 334 if (p_req_physp == NULL) { 335 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 5104: " 336 "Cannot find requester physical port\n"); 337 goto Exit; 338 } 339 340 if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) 341 osm_dump_guidinfo_record(sa->p_log, p_rcvd_rec, OSM_LOG_DEBUG); 342 343 cl_qlist_init(&rec_list); 344 345 context.p_rcvd_rec = p_rcvd_rec; 346 context.p_list = &rec_list; 347 context.comp_mask = p_rcvd_mad->comp_mask; 348 context.sa = sa; 349 context.p_req_physp = p_req_physp; 350 351 cl_plock_acquire(sa->p_lock); 352 353 cl_qmap_apply_func(&sa->p_subn->node_guid_tbl, 354 __osm_sa_gir_by_comp_mask_cb, &context); 355 356 cl_plock_release(sa->p_lock); 357 358 osm_sa_respond(sa, p_madw, sizeof(ib_guidinfo_record_t), &rec_list); 359 360Exit: 361 OSM_LOG_EXIT(sa->p_log); 362} 363