1219820Sjeff/* 2219820Sjeff * Copyright (c) 2006-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_gir_rcv_t. 39219820Sjeff * This object represents the GUIDInfoRecord Receiver object. 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 <string.h> 48219820Sjeff#include <iba/ib_types.h> 49219820Sjeff#include <complib/cl_qmap.h> 50219820Sjeff#include <complib/cl_passivelock.h> 51219820Sjeff#include <complib/cl_debug.h> 52219820Sjeff#include <complib/cl_qlist.h> 53219820Sjeff#include <vendor/osm_vendor_api.h> 54219820Sjeff#include <opensm/osm_port.h> 55219820Sjeff#include <opensm/osm_node.h> 56219820Sjeff#include <opensm/osm_helper.h> 57219820Sjeff#include <opensm/osm_pkey.h> 58219820Sjeff#include <opensm/osm_sa.h> 59219820Sjeff 60219820Sjefftypedef struct osm_gir_item { 61219820Sjeff cl_list_item_t list_item; 62219820Sjeff ib_guidinfo_record_t rec; 63219820Sjeff} osm_gir_item_t; 64219820Sjeff 65219820Sjefftypedef struct osm_gir_search_ctxt { 66219820Sjeff const ib_guidinfo_record_t *p_rcvd_rec; 67219820Sjeff ib_net64_t comp_mask; 68219820Sjeff cl_qlist_t *p_list; 69219820Sjeff osm_sa_t *sa; 70219820Sjeff const osm_physp_t *p_req_physp; 71219820Sjeff} osm_gir_search_ctxt_t; 72219820Sjeff 73219820Sjeff/********************************************************************** 74219820Sjeff **********************************************************************/ 75219820Sjeffstatic ib_api_status_t 76219820Sjeff__osm_gir_rcv_new_gir(IN osm_sa_t * sa, 77219820Sjeff IN const osm_node_t * const p_node, 78219820Sjeff IN cl_qlist_t * const p_list, 79219820Sjeff IN ib_net64_t const match_port_guid, 80219820Sjeff IN ib_net16_t const match_lid, 81219820Sjeff IN const osm_physp_t * const p_req_physp, 82219820Sjeff IN uint8_t const block_num) 83219820Sjeff{ 84219820Sjeff osm_gir_item_t *p_rec_item; 85219820Sjeff ib_api_status_t status = IB_SUCCESS; 86219820Sjeff 87219820Sjeff OSM_LOG_ENTER(sa->p_log); 88219820Sjeff 89219820Sjeff p_rec_item = malloc(sizeof(*p_rec_item)); 90219820Sjeff if (p_rec_item == NULL) { 91219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 5102: " 92219820Sjeff "rec_item alloc failed\n"); 93219820Sjeff status = IB_INSUFFICIENT_RESOURCES; 94219820Sjeff goto Exit; 95219820Sjeff } 96219820Sjeff 97219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 98219820Sjeff "New GUIDInfoRecord: lid %u, block num %d\n", 99219820Sjeff cl_ntoh16(match_lid), block_num); 100219820Sjeff 101219820Sjeff memset(p_rec_item, 0, sizeof(*p_rec_item)); 102219820Sjeff 103219820Sjeff p_rec_item->rec.lid = match_lid; 104219820Sjeff p_rec_item->rec.block_num = block_num; 105219820Sjeff if (!block_num) 106219820Sjeff p_rec_item->rec.guid_info.guid[0] = 107219820Sjeff osm_physp_get_port_guid(p_req_physp); 108219820Sjeff 109219820Sjeff cl_qlist_insert_tail(p_list, &p_rec_item->list_item); 110219820Sjeff 111219820SjeffExit: 112219820Sjeff OSM_LOG_EXIT(sa->p_log); 113219820Sjeff return (status); 114219820Sjeff} 115219820Sjeff 116219820Sjeff/********************************************************************** 117219820Sjeff **********************************************************************/ 118219820Sjeffstatic void 119219820Sjeff__osm_sa_gir_create_gir(IN osm_sa_t * sa, 120219820Sjeff IN osm_node_t * const p_node, 121219820Sjeff IN cl_qlist_t * const p_list, 122219820Sjeff IN ib_net64_t const match_port_guid, 123219820Sjeff IN ib_net16_t const match_lid, 124219820Sjeff IN const osm_physp_t * const p_req_physp, 125219820Sjeff IN uint8_t const match_block_num) 126219820Sjeff{ 127219820Sjeff const osm_physp_t *p_physp; 128219820Sjeff uint8_t port_num; 129219820Sjeff uint8_t num_ports; 130219820Sjeff uint16_t match_lid_ho; 131219820Sjeff ib_net16_t base_lid_ho; 132219820Sjeff ib_net16_t max_lid_ho; 133219820Sjeff uint8_t lmc; 134219820Sjeff ib_net64_t port_guid; 135219820Sjeff uint8_t block_num, start_block_num, end_block_num, num_blocks; 136219820Sjeff 137219820Sjeff OSM_LOG_ENTER(sa->p_log); 138219820Sjeff 139219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 140219820Sjeff "Looking for GUIDRecord with LID: %u GUID:0x%016" 141219820Sjeff PRIx64 "\n", cl_ntoh16(match_lid), cl_ntoh64(match_port_guid)); 142219820Sjeff 143219820Sjeff /* 144219820Sjeff For switches, do not return the GUIDInfo record(s) 145219820Sjeff for each port on the switch, just for port 0. 146219820Sjeff */ 147219820Sjeff if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH) 148219820Sjeff num_ports = 1; 149219820Sjeff else 150219820Sjeff num_ports = osm_node_get_num_physp(p_node); 151219820Sjeff 152219820Sjeff for (port_num = 0; port_num < num_ports; port_num++) { 153219820Sjeff p_physp = osm_node_get_physp_ptr(p_node, port_num); 154219820Sjeff if (!p_physp) 155219820Sjeff continue; 156219820Sjeff 157219820Sjeff /* Check to see if the found p_physp and the requester physp 158219820Sjeff share a pkey. If not, continue */ 159219820Sjeff if (!osm_physp_share_pkey(sa->p_log, p_physp, p_req_physp)) 160219820Sjeff continue; 161219820Sjeff 162219820Sjeff port_guid = osm_physp_get_port_guid(p_physp); 163219820Sjeff 164219820Sjeff if (match_port_guid && (port_guid != match_port_guid)) 165219820Sjeff continue; 166219820Sjeff 167219820Sjeff /* 168219820Sjeff Note: the following check is a temporary workaround 169219820Sjeff Since 1. GUIDCap should never be 0 on ports where this applies 170219820Sjeff and 2. GUIDCap should not be used on ports where it doesn't apply 171219820Sjeff So this should really be a check for whether the port is a 172219820Sjeff switch external port or not! 173219820Sjeff */ 174219820Sjeff if (p_physp->port_info.guid_cap == 0) 175219820Sjeff continue; 176219820Sjeff 177219820Sjeff num_blocks = p_physp->port_info.guid_cap / 8; 178219820Sjeff if (p_physp->port_info.guid_cap % 8) 179219820Sjeff num_blocks++; 180219820Sjeff if (match_block_num == 255) { 181219820Sjeff start_block_num = 0; 182219820Sjeff end_block_num = num_blocks - 1; 183219820Sjeff } else { 184219820Sjeff if (match_block_num >= num_blocks) 185219820Sjeff continue; 186219820Sjeff end_block_num = start_block_num = match_block_num; 187219820Sjeff } 188219820Sjeff 189219820Sjeff base_lid_ho = cl_ntoh16(osm_physp_get_base_lid(p_physp)); 190219820Sjeff match_lid_ho = cl_ntoh16(match_lid); 191219820Sjeff if (match_lid_ho) { 192219820Sjeff lmc = osm_physp_get_lmc(p_physp); 193219820Sjeff max_lid_ho = (uint16_t) (base_lid_ho + (1 << lmc) - 1); 194219820Sjeff 195219820Sjeff /* 196219820Sjeff We validate that the lid belongs to this node. 197219820Sjeff */ 198219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 199219820Sjeff "Comparing LID: %u <= %u <= %u\n", 200219820Sjeff base_lid_ho, match_lid_ho, max_lid_ho); 201219820Sjeff 202219820Sjeff if (match_lid_ho < base_lid_ho 203219820Sjeff || match_lid_ho > max_lid_ho) 204219820Sjeff continue; 205219820Sjeff } 206219820Sjeff 207219820Sjeff for (block_num = start_block_num; block_num <= end_block_num; 208219820Sjeff block_num++) 209219820Sjeff __osm_gir_rcv_new_gir(sa, p_node, p_list, port_guid, 210219820Sjeff cl_ntoh16(base_lid_ho), p_physp, 211219820Sjeff block_num); 212219820Sjeff 213219820Sjeff } 214219820Sjeff 215219820Sjeff OSM_LOG_EXIT(sa->p_log); 216219820Sjeff} 217219820Sjeff 218219820Sjeff/********************************************************************** 219219820Sjeff **********************************************************************/ 220219820Sjeffstatic void 221219820Sjeff__osm_sa_gir_by_comp_mask_cb(IN cl_map_item_t * const p_map_item, 222219820Sjeff IN void *context) 223219820Sjeff{ 224219820Sjeff const osm_gir_search_ctxt_t *const p_ctxt = 225219820Sjeff (osm_gir_search_ctxt_t *) context; 226219820Sjeff osm_node_t *const p_node = (osm_node_t *) p_map_item; 227219820Sjeff const ib_guidinfo_record_t *const p_rcvd_rec = p_ctxt->p_rcvd_rec; 228219820Sjeff const osm_physp_t *const p_req_physp = p_ctxt->p_req_physp; 229219820Sjeff osm_sa_t *sa = p_ctxt->sa; 230219820Sjeff const ib_guid_info_t *p_comp_gi; 231219820Sjeff ib_net64_t const comp_mask = p_ctxt->comp_mask; 232219820Sjeff ib_net64_t match_port_guid = 0; 233219820Sjeff ib_net16_t match_lid = 0; 234219820Sjeff uint8_t match_block_num = 255; 235219820Sjeff 236219820Sjeff OSM_LOG_ENTER(p_ctxt->sa->p_log); 237219820Sjeff 238219820Sjeff if (comp_mask & IB_GIR_COMPMASK_LID) 239219820Sjeff match_lid = p_rcvd_rec->lid; 240219820Sjeff 241219820Sjeff if (comp_mask & IB_GIR_COMPMASK_BLOCKNUM) 242219820Sjeff match_block_num = p_rcvd_rec->block_num; 243219820Sjeff 244219820Sjeff p_comp_gi = &p_rcvd_rec->guid_info; 245219820Sjeff /* Different rule for block 0 v. other blocks */ 246219820Sjeff if (comp_mask & IB_GIR_COMPMASK_GID0) { 247219820Sjeff if (!p_rcvd_rec->block_num) 248219820Sjeff match_port_guid = osm_physp_get_port_guid(p_req_physp); 249219820Sjeff if (p_comp_gi->guid[0] != match_port_guid) 250219820Sjeff goto Exit; 251219820Sjeff } 252219820Sjeff 253219820Sjeff if (comp_mask & IB_GIR_COMPMASK_GID1) { 254219820Sjeff if (p_comp_gi->guid[1] != 0) 255219820Sjeff goto Exit; 256219820Sjeff } 257219820Sjeff 258219820Sjeff if (comp_mask & IB_GIR_COMPMASK_GID2) { 259219820Sjeff if (p_comp_gi->guid[2] != 0) 260219820Sjeff goto Exit; 261219820Sjeff } 262219820Sjeff 263219820Sjeff if (comp_mask & IB_GIR_COMPMASK_GID3) { 264219820Sjeff if (p_comp_gi->guid[3] != 0) 265219820Sjeff goto Exit; 266219820Sjeff } 267219820Sjeff 268219820Sjeff if (comp_mask & IB_GIR_COMPMASK_GID4) { 269219820Sjeff if (p_comp_gi->guid[4] != 0) 270219820Sjeff goto Exit; 271219820Sjeff } 272219820Sjeff 273219820Sjeff if (comp_mask & IB_GIR_COMPMASK_GID5) { 274219820Sjeff if (p_comp_gi->guid[5] != 0) 275219820Sjeff goto Exit; 276219820Sjeff } 277219820Sjeff 278219820Sjeff if (comp_mask & IB_GIR_COMPMASK_GID6) { 279219820Sjeff if (p_comp_gi->guid[6] != 0) 280219820Sjeff goto Exit; 281219820Sjeff } 282219820Sjeff 283219820Sjeff if (comp_mask & IB_GIR_COMPMASK_GID7) { 284219820Sjeff if (p_comp_gi->guid[7] != 0) 285219820Sjeff goto Exit; 286219820Sjeff } 287219820Sjeff 288219820Sjeff __osm_sa_gir_create_gir(sa, p_node, p_ctxt->p_list, 289219820Sjeff match_port_guid, match_lid, p_req_physp, 290219820Sjeff match_block_num); 291219820Sjeff 292219820SjeffExit: 293219820Sjeff OSM_LOG_EXIT(p_ctxt->sa->p_log); 294219820Sjeff} 295219820Sjeff 296219820Sjeff/********************************************************************** 297219820Sjeff **********************************************************************/ 298219820Sjeffvoid osm_gir_rcv_process(IN void *ctx, IN void *data) 299219820Sjeff{ 300219820Sjeff osm_sa_t *sa = ctx; 301219820Sjeff osm_madw_t *p_madw = data; 302219820Sjeff const ib_sa_mad_t *p_rcvd_mad; 303219820Sjeff const ib_guidinfo_record_t *p_rcvd_rec; 304219820Sjeff cl_qlist_t rec_list; 305219820Sjeff osm_gir_search_ctxt_t context; 306219820Sjeff osm_physp_t *p_req_physp; 307219820Sjeff 308219820Sjeff CL_ASSERT(sa); 309219820Sjeff 310219820Sjeff OSM_LOG_ENTER(sa->p_log); 311219820Sjeff 312219820Sjeff CL_ASSERT(p_madw); 313219820Sjeff 314219820Sjeff p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw); 315219820Sjeff p_rcvd_rec = 316219820Sjeff (ib_guidinfo_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); 317219820Sjeff 318219820Sjeff CL_ASSERT(p_rcvd_mad->attr_id == IB_MAD_ATTR_GUIDINFO_RECORD); 319219820Sjeff 320219820Sjeff /* we only support SubnAdmGet and SubnAdmGetTable methods */ 321219820Sjeff if (p_rcvd_mad->method != IB_MAD_METHOD_GET && 322219820Sjeff p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) { 323219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 5105: " 324219820Sjeff "Unsupported Method (%s)\n", 325219820Sjeff ib_get_sa_method_str(p_rcvd_mad->method)); 326219820Sjeff osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); 327219820Sjeff goto Exit; 328219820Sjeff } 329219820Sjeff 330219820Sjeff /* update the requester physical port. */ 331219820Sjeff p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, 332219820Sjeff osm_madw_get_mad_addr_ptr 333219820Sjeff (p_madw)); 334219820Sjeff if (p_req_physp == NULL) { 335219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 5104: " 336219820Sjeff "Cannot find requester physical port\n"); 337219820Sjeff goto Exit; 338219820Sjeff } 339219820Sjeff 340219820Sjeff if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) 341219820Sjeff osm_dump_guidinfo_record(sa->p_log, p_rcvd_rec, OSM_LOG_DEBUG); 342219820Sjeff 343219820Sjeff cl_qlist_init(&rec_list); 344219820Sjeff 345219820Sjeff context.p_rcvd_rec = p_rcvd_rec; 346219820Sjeff context.p_list = &rec_list; 347219820Sjeff context.comp_mask = p_rcvd_mad->comp_mask; 348219820Sjeff context.sa = sa; 349219820Sjeff context.p_req_physp = p_req_physp; 350219820Sjeff 351219820Sjeff cl_plock_acquire(sa->p_lock); 352219820Sjeff 353219820Sjeff cl_qmap_apply_func(&sa->p_subn->node_guid_tbl, 354219820Sjeff __osm_sa_gir_by_comp_mask_cb, &context); 355219820Sjeff 356219820Sjeff cl_plock_release(sa->p_lock); 357219820Sjeff 358219820Sjeff osm_sa_respond(sa, p_madw, sizeof(ib_guidinfo_record_t), &rec_list); 359219820Sjeff 360219820SjeffExit: 361219820Sjeff OSM_LOG_EXIT(sa->p_log); 362219820Sjeff} 363