1321936Shselasky/* 2321936Shselasky * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. 3321936Shselasky * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. 4321936Shselasky * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5321936Shselasky * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. 6321936Shselasky * 7321936Shselasky * This software is available to you under a choice of one of two 8321936Shselasky * licenses. You may choose to be licensed under the terms of the GNU 9321936Shselasky * General Public License (GPL) Version 2, available from the file 10321936Shselasky * COPYING in the main directory of this source tree, or the 11321936Shselasky * OpenIB.org BSD license below: 12321936Shselasky * 13321936Shselasky * Redistribution and use in source and binary forms, with or 14321936Shselasky * without modification, are permitted provided that the following 15321936Shselasky * conditions are met: 16321936Shselasky * 17321936Shselasky * - Redistributions of source code must retain the above 18321936Shselasky * copyright notice, this list of conditions and the following 19321936Shselasky * disclaimer. 20321936Shselasky * 21321936Shselasky * - Redistributions in binary form must reproduce the above 22321936Shselasky * copyright notice, this list of conditions and the following 23321936Shselasky * disclaimer in the documentation and/or other materials 24321936Shselasky * provided with the distribution. 25321936Shselasky * 26321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 30321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 31321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 32321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33321936Shselasky * SOFTWARE. 34321936Shselasky * 35321936Shselasky */ 36321936Shselasky 37321936Shselasky/* 38321936Shselasky * Abstract: 39321936Shselasky * Implementation of osm_vlarb_rec_rcv_t. 40321936Shselasky * This object represents the VLArbitrationRecord Receiver object. 41321936Shselasky * This object is part of the opensm family of objects. 42321936Shselasky */ 43321936Shselasky 44321936Shselasky#if HAVE_CONFIG_H 45321936Shselasky# include <config.h> 46321936Shselasky#endif /* HAVE_CONFIG_H */ 47321936Shselasky 48321936Shselasky#include <string.h> 49321936Shselasky#include <iba/ib_types.h> 50321936Shselasky#include <complib/cl_qmap.h> 51321936Shselasky#include <complib/cl_passivelock.h> 52321936Shselasky#include <complib/cl_debug.h> 53321936Shselasky#include <complib/cl_qlist.h> 54321936Shselasky#include <opensm/osm_file_ids.h> 55321936Shselasky#define FILE_ID OSM_FILE_SA_VLARB_RECORD_C 56321936Shselasky#include <vendor/osm_vendor_api.h> 57321936Shselasky#include <opensm/osm_port.h> 58321936Shselasky#include <opensm/osm_node.h> 59321936Shselasky#include <opensm/osm_helper.h> 60321936Shselasky#include <opensm/osm_pkey.h> 61321936Shselasky#include <opensm/osm_sa.h> 62321936Shselasky 63321936Shselasky#define SA_VLA_RESP_SIZE SA_ITEM_RESP_SIZE(vlarb_rec) 64321936Shselasky 65321936Shselaskytypedef struct osm_vl_arb_search_ctxt { 66321936Shselasky const ib_vl_arb_table_record_t *p_rcvd_rec; 67321936Shselasky ib_net64_t comp_mask; 68321936Shselasky uint8_t block_num; 69321936Shselasky cl_qlist_t *p_list; 70321936Shselasky osm_sa_t *sa; 71321936Shselasky const osm_physp_t *p_req_physp; 72321936Shselasky} osm_vl_arb_search_ctxt_t; 73321936Shselasky 74321936Shselaskystatic void sa_vl_arb_create(IN osm_sa_t * sa, IN osm_physp_t * p_physp, 75321936Shselasky IN osm_vl_arb_search_ctxt_t * p_ctxt, 76321936Shselasky IN uint8_t block) 77321936Shselasky{ 78321936Shselasky osm_sa_item_t *p_rec_item; 79321936Shselasky uint16_t lid; 80321936Shselasky 81321936Shselasky OSM_LOG_ENTER(sa->p_log); 82321936Shselasky 83321936Shselasky p_rec_item = malloc(SA_VLA_RESP_SIZE); 84321936Shselasky if (p_rec_item == NULL) { 85321936Shselasky OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2A02: " 86321936Shselasky "rec_item alloc failed\n"); 87321936Shselasky goto Exit; 88321936Shselasky } 89321936Shselasky 90321936Shselasky if (p_physp->p_node->node_info.node_type != IB_NODE_TYPE_SWITCH) 91321936Shselasky lid = p_physp->port_info.base_lid; 92321936Shselasky else 93321936Shselasky lid = osm_node_get_base_lid(p_physp->p_node, 0); 94321936Shselasky 95321936Shselasky OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 96321936Shselasky "New VLArbitration for: port 0x%016" PRIx64 97321936Shselasky ", lid %u, port %u Block:%u\n", 98321936Shselasky cl_ntoh64(osm_physp_get_port_guid(p_physp)), 99321936Shselasky cl_ntoh16(lid), osm_physp_get_port_num(p_physp), block); 100321936Shselasky 101321936Shselasky memset(p_rec_item, 0, SA_VLA_RESP_SIZE); 102321936Shselasky 103321936Shselasky p_rec_item->resp.vlarb_rec.lid = lid; 104321936Shselasky p_rec_item->resp.vlarb_rec.port_num = osm_physp_get_port_num(p_physp); 105321936Shselasky p_rec_item->resp.vlarb_rec.block_num = block; 106321936Shselasky p_rec_item->resp.vlarb_rec.vl_arb_tbl = *(osm_physp_get_vla_tbl(p_physp, block)); 107321936Shselasky 108321936Shselasky cl_qlist_insert_tail(p_ctxt->p_list, &p_rec_item->list_item); 109321936Shselasky 110321936ShselaskyExit: 111321936Shselasky OSM_LOG_EXIT(sa->p_log); 112321936Shselasky} 113321936Shselasky 114321936Shselaskystatic void sa_vl_arb_check_physp(IN osm_sa_t * sa, IN osm_physp_t * p_physp, 115321936Shselasky osm_vl_arb_search_ctxt_t * p_ctxt) 116321936Shselasky{ 117321936Shselasky ib_net64_t comp_mask = p_ctxt->comp_mask; 118321936Shselasky uint8_t block; 119321936Shselasky 120321936Shselasky OSM_LOG_ENTER(sa->p_log); 121321936Shselasky 122321936Shselasky /* we got here with the phys port - all that's left is to get the right block */ 123321936Shselasky for (block = 1; block <= 4; block++) { 124321936Shselasky if (!(comp_mask & IB_VLA_COMPMASK_BLOCK) 125321936Shselasky || block == p_ctxt->block_num) 126321936Shselasky sa_vl_arb_create(sa, p_physp, p_ctxt, block); 127321936Shselasky } 128321936Shselasky 129321936Shselasky OSM_LOG_EXIT(sa->p_log); 130321936Shselasky} 131321936Shselasky 132321936Shselaskystatic void sa_vl_arb_by_comp_mask(osm_sa_t * sa, IN const osm_port_t * p_port, 133321936Shselasky osm_vl_arb_search_ctxt_t * p_ctxt) 134321936Shselasky{ 135321936Shselasky const ib_vl_arb_table_record_t *p_rcvd_rec; 136321936Shselasky ib_net64_t comp_mask; 137321936Shselasky osm_physp_t *p_physp; 138321936Shselasky uint8_t port_num; 139321936Shselasky uint8_t num_ports; 140321936Shselasky const osm_physp_t *p_req_physp; 141321936Shselasky 142321936Shselasky OSM_LOG_ENTER(sa->p_log); 143321936Shselasky 144321936Shselasky p_rcvd_rec = p_ctxt->p_rcvd_rec; 145321936Shselasky comp_mask = p_ctxt->comp_mask; 146321936Shselasky port_num = p_rcvd_rec->port_num; 147321936Shselasky p_req_physp = p_ctxt->p_req_physp; 148321936Shselasky 149321936Shselasky /* if this is a switch port we can search all ports 150321936Shselasky otherwise we must be looking on port 0 */ 151321936Shselasky if (p_port->p_node->node_info.node_type != IB_NODE_TYPE_SWITCH) { 152321936Shselasky /* we put it in the comp mask and port num */ 153321936Shselasky port_num = p_port->p_physp->port_num; 154321936Shselasky OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 155321936Shselasky "Using Physical Default Port Number: 0x%X (for End Node)\n", 156321936Shselasky port_num); 157321936Shselasky comp_mask |= IB_VLA_COMPMASK_OUT_PORT; 158321936Shselasky } 159321936Shselasky 160321936Shselasky if (comp_mask & IB_VLA_COMPMASK_OUT_PORT) { 161321936Shselasky if (port_num < osm_node_get_num_physp(p_port->p_node)) { 162321936Shselasky p_physp = 163321936Shselasky osm_node_get_physp_ptr(p_port->p_node, port_num); 164321936Shselasky /* check that the p_physp is valid, and that the requester 165321936Shselasky and the p_physp share a pkey. */ 166321936Shselasky if (p_physp && 167321936Shselasky osm_physp_share_pkey(sa->p_log, p_req_physp, p_physp, 168321936Shselasky sa->p_subn->opt.allow_both_pkeys)) 169321936Shselasky sa_vl_arb_check_physp(sa, p_physp, p_ctxt); 170321936Shselasky } else { 171321936Shselasky OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2A03: " 172321936Shselasky "Given Physical Port Number: 0x%X is out of range should be < 0x%X\n", 173321936Shselasky port_num, 174321936Shselasky osm_node_get_num_physp(p_port->p_node)); 175321936Shselasky goto Exit; 176321936Shselasky } 177321936Shselasky } else { 178321936Shselasky num_ports = osm_node_get_num_physp(p_port->p_node); 179321936Shselasky for (port_num = 0; port_num < num_ports; port_num++) { 180321936Shselasky p_physp = 181321936Shselasky osm_node_get_physp_ptr(p_port->p_node, port_num); 182321936Shselasky if (!p_physp) 183321936Shselasky continue; 184321936Shselasky 185321936Shselasky /* if the requester and the p_physp don't share a pkey - 186321936Shselasky continue */ 187321936Shselasky if (!osm_physp_share_pkey(sa->p_log, p_req_physp, p_physp, 188321936Shselasky sa->p_subn->opt.allow_both_pkeys)) 189321936Shselasky continue; 190321936Shselasky 191321936Shselasky sa_vl_arb_check_physp(sa, p_physp, p_ctxt); 192321936Shselasky } 193321936Shselasky } 194321936ShselaskyExit: 195321936Shselasky OSM_LOG_EXIT(sa->p_log); 196321936Shselasky} 197321936Shselasky 198321936Shselaskystatic void sa_vl_arb_by_comp_mask_cb(IN cl_map_item_t * p_map_item, void *cxt) 199321936Shselasky{ 200321936Shselasky const osm_port_t *p_port = (osm_port_t *) p_map_item; 201321936Shselasky osm_vl_arb_search_ctxt_t *p_ctxt = cxt; 202321936Shselasky 203321936Shselasky sa_vl_arb_by_comp_mask(p_ctxt->sa, p_port, p_ctxt); 204321936Shselasky} 205321936Shselasky 206321936Shselaskyvoid osm_vlarb_rec_rcv_process(IN void *ctx, IN void *data) 207321936Shselasky{ 208321936Shselasky osm_sa_t *sa = ctx; 209321936Shselasky osm_madw_t *p_madw = data; 210321936Shselasky const ib_sa_mad_t *sad_mad; 211321936Shselasky const ib_vl_arb_table_record_t *p_rcvd_rec; 212321936Shselasky const osm_port_t *p_port = NULL; 213321936Shselasky cl_qlist_t rec_list; 214321936Shselasky osm_vl_arb_search_ctxt_t context; 215321936Shselasky ib_api_status_t status = IB_SUCCESS; 216321936Shselasky ib_net64_t comp_mask; 217321936Shselasky osm_physp_t *p_req_physp; 218321936Shselasky 219321936Shselasky CL_ASSERT(sa); 220321936Shselasky 221321936Shselasky OSM_LOG_ENTER(sa->p_log); 222321936Shselasky 223321936Shselasky CL_ASSERT(p_madw); 224321936Shselasky 225321936Shselasky sad_mad = osm_madw_get_sa_mad_ptr(p_madw); 226321936Shselasky p_rcvd_rec = 227321936Shselasky (ib_vl_arb_table_record_t *) ib_sa_mad_get_payload_ptr(sad_mad); 228321936Shselasky comp_mask = sad_mad->comp_mask; 229321936Shselasky 230321936Shselasky CL_ASSERT(sad_mad->attr_id == IB_MAD_ATTR_VLARB_RECORD); 231321936Shselasky 232321936Shselasky /* we only support SubnAdmGet and SubnAdmGetTable methods */ 233321936Shselasky if (sad_mad->method != IB_MAD_METHOD_GET && 234321936Shselasky sad_mad->method != IB_MAD_METHOD_GETTABLE) { 235321936Shselasky OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2A05: " 236321936Shselasky "Unsupported Method (%s) for a VLArbRecord request\n", 237321936Shselasky ib_get_sa_method_str(sad_mad->method)); 238321936Shselasky osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); 239321936Shselasky goto Exit; 240321936Shselasky } 241321936Shselasky 242321936Shselasky cl_plock_acquire(sa->p_lock); 243321936Shselasky 244321936Shselasky /* update the requester physical port */ 245321936Shselasky p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, 246321936Shselasky osm_madw_get_mad_addr_ptr 247321936Shselasky (p_madw)); 248321936Shselasky if (p_req_physp == NULL) { 249321936Shselasky cl_plock_release(sa->p_lock); 250321936Shselasky OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2A04: " 251321936Shselasky "Cannot find requester physical port\n"); 252321936Shselasky goto Exit; 253321936Shselasky } 254321936Shselasky OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 255321936Shselasky "Requester port GUID 0x%" PRIx64 "\n", 256321936Shselasky cl_ntoh64(osm_physp_get_port_guid(p_req_physp))); 257321936Shselasky 258321936Shselasky cl_qlist_init(&rec_list); 259321936Shselasky 260321936Shselasky context.p_rcvd_rec = p_rcvd_rec; 261321936Shselasky context.p_list = &rec_list; 262321936Shselasky context.comp_mask = sad_mad->comp_mask; 263321936Shselasky context.sa = sa; 264321936Shselasky context.block_num = p_rcvd_rec->block_num; 265321936Shselasky context.p_req_physp = p_req_physp; 266321936Shselasky 267321936Shselasky OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 268321936Shselasky "Got Query Lid:%u(%02X), Port:0x%02X(%02X), Block:0x%02X(%02X)\n", 269321936Shselasky cl_ntoh16(p_rcvd_rec->lid), 270321936Shselasky (comp_mask & IB_VLA_COMPMASK_LID) != 0, p_rcvd_rec->port_num, 271321936Shselasky (comp_mask & IB_VLA_COMPMASK_OUT_PORT) != 0, 272321936Shselasky p_rcvd_rec->block_num, 273321936Shselasky (comp_mask & IB_VLA_COMPMASK_BLOCK) != 0); 274321936Shselasky 275321936Shselasky /* 276321936Shselasky If the user specified a LID, it obviously narrows our 277321936Shselasky work load, since we don't have to search every port 278321936Shselasky */ 279321936Shselasky if (comp_mask & IB_VLA_COMPMASK_LID) { 280321936Shselasky p_port = osm_get_port_by_lid(sa->p_subn, p_rcvd_rec->lid); 281321936Shselasky if (!p_port) { 282321936Shselasky status = IB_NOT_FOUND; 283321936Shselasky OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2A09: " 284321936Shselasky "No port found with LID %u\n", 285321936Shselasky cl_ntoh16(p_rcvd_rec->lid)); 286321936Shselasky } 287321936Shselasky } 288321936Shselasky 289321936Shselasky if (status == IB_SUCCESS) { 290321936Shselasky /* if we got a unique port - no need for a port search */ 291321936Shselasky if (p_port) 292321936Shselasky /* this does the loop on all the port phys ports */ 293321936Shselasky sa_vl_arb_by_comp_mask(sa, p_port, &context); 294321936Shselasky else 295321936Shselasky cl_qmap_apply_func(&sa->p_subn->port_guid_tbl, 296321936Shselasky sa_vl_arb_by_comp_mask_cb, &context); 297321936Shselasky } 298321936Shselasky 299321936Shselasky cl_plock_release(sa->p_lock); 300321936Shselasky 301321936Shselasky osm_sa_respond(sa, p_madw, sizeof(ib_vl_arb_table_record_t), &rec_list); 302321936Shselasky 303321936ShselaskyExit: 304321936Shselasky OSM_LOG_EXIT(sa->p_log); 305321936Shselasky} 306