osm_sa_lft_record.c revision 321936
1321936Shselasky/* 2321936Shselasky * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. 3321936Shselasky * Copyright (c) 2002-2005,2008 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_lftr_rcv_t. 40321936Shselasky * This object represents the LinearForwardingTable 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_debug.h> 51321936Shselasky#include <complib/cl_qlist.h> 52321936Shselasky#include <opensm/osm_file_ids.h> 53321936Shselasky#define FILE_ID OSM_FILE_SA_LFT_RECORD_C 54321936Shselasky#include <vendor/osm_vendor_api.h> 55321936Shselasky#include <opensm/osm_switch.h> 56321936Shselasky#include <opensm/osm_helper.h> 57321936Shselasky#include <opensm/osm_pkey.h> 58321936Shselasky#include <opensm/osm_sa.h> 59321936Shselasky 60321936Shselasky#define SA_LFTR_RESP_SIZE SA_ITEM_RESP_SIZE(lft_rec) 61321936Shselasky 62321936Shselaskytypedef struct osm_lftr_search_ctxt { 63321936Shselasky const ib_lft_record_t *p_rcvd_rec; 64321936Shselasky ib_net64_t comp_mask; 65321936Shselasky cl_qlist_t *p_list; 66321936Shselasky osm_sa_t *sa; 67321936Shselasky const osm_physp_t *p_req_physp; 68321936Shselasky} osm_lftr_search_ctxt_t; 69321936Shselasky 70321936Shselaskystatic ib_api_status_t lftr_rcv_new_lftr(IN osm_sa_t * sa, 71321936Shselasky IN const osm_switch_t * p_sw, 72321936Shselasky IN cl_qlist_t * p_list, 73321936Shselasky IN ib_net16_t lid, IN uint16_t block) 74321936Shselasky{ 75321936Shselasky osm_sa_item_t *p_rec_item; 76321936Shselasky ib_api_status_t status = IB_SUCCESS; 77321936Shselasky 78321936Shselasky OSM_LOG_ENTER(sa->p_log); 79321936Shselasky 80321936Shselasky p_rec_item = malloc(SA_LFTR_RESP_SIZE); 81321936Shselasky if (p_rec_item == NULL) { 82321936Shselasky OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4402: " 83321936Shselasky "rec_item alloc failed\n"); 84321936Shselasky status = IB_INSUFFICIENT_RESOURCES; 85321936Shselasky goto Exit; 86321936Shselasky } 87321936Shselasky 88321936Shselasky OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 89321936Shselasky "New LinearForwardingTable: sw 0x%016" PRIx64 90321936Shselasky "\n\t\t\t\tblock 0x%02X lid %u\n", 91321936Shselasky cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)), 92321936Shselasky block, cl_ntoh16(lid)); 93321936Shselasky 94321936Shselasky memset(p_rec_item, 0, SA_LFTR_RESP_SIZE); 95321936Shselasky 96321936Shselasky p_rec_item->resp.lft_rec.lid = lid; 97321936Shselasky p_rec_item->resp.lft_rec.block_num = cl_hton16(block); 98321936Shselasky 99321936Shselasky /* copy the lft block */ 100321936Shselasky osm_switch_get_lft_block(p_sw, block, p_rec_item->resp.lft_rec.lft); 101321936Shselasky 102321936Shselasky cl_qlist_insert_tail(p_list, &p_rec_item->list_item); 103321936Shselasky 104321936ShselaskyExit: 105321936Shselasky OSM_LOG_EXIT(sa->p_log); 106321936Shselasky return status; 107321936Shselasky} 108321936Shselasky 109321936Shselaskystatic void lftr_rcv_by_comp_mask(IN cl_map_item_t * p_map_item, IN void *cxt) 110321936Shselasky{ 111321936Shselasky const osm_lftr_search_ctxt_t *p_ctxt = cxt; 112321936Shselasky const osm_switch_t *p_sw = (osm_switch_t *) p_map_item; 113321936Shselasky const ib_lft_record_t *const p_rcvd_rec = p_ctxt->p_rcvd_rec; 114321936Shselasky osm_sa_t *sa = p_ctxt->sa; 115321936Shselasky ib_net64_t const comp_mask = p_ctxt->comp_mask; 116321936Shselasky const osm_physp_t *const p_req_physp = p_ctxt->p_req_physp; 117321936Shselasky osm_port_t *p_port; 118321936Shselasky uint16_t min_lid_ho, max_lid_ho; 119321936Shselasky uint16_t min_block, max_block, block; 120321936Shselasky const osm_physp_t *p_physp; 121321936Shselasky 122321936Shselasky /* In switches, the port guid is the node guid. */ 123321936Shselasky p_port = osm_get_port_by_guid(sa->p_subn, 124321936Shselasky p_sw->p_node->node_info.port_guid); 125321936Shselasky if (!p_port) { 126321936Shselasky OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4405: " 127321936Shselasky "Failed to find Port by Node Guid:0x%016" PRIx64 128321936Shselasky "\n", cl_ntoh64(p_sw->p_node->node_info.node_guid)); 129321936Shselasky return; 130321936Shselasky } 131321936Shselasky 132321936Shselasky /* check that the requester physp and the current physp are under 133321936Shselasky the same partition. */ 134321936Shselasky p_physp = p_port->p_physp; 135321936Shselasky if (!p_physp) { 136321936Shselasky OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4406: " 137321936Shselasky "Failed to find default physical Port by Node Guid:0x%016" 138321936Shselasky PRIx64 "\n", 139321936Shselasky cl_ntoh64(p_sw->p_node->node_info.node_guid)); 140321936Shselasky return; 141321936Shselasky } 142321936Shselasky if (!osm_physp_share_pkey(sa->p_log, p_req_physp, 143321936Shselasky p_physp, sa->p_subn->opt.allow_both_pkeys)) 144321936Shselasky return; 145321936Shselasky 146321936Shselasky /* get the port 0 of the switch */ 147321936Shselasky osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho); 148321936Shselasky 149321936Shselasky /* compare the lids - if required */ 150321936Shselasky if (comp_mask & IB_LFTR_COMPMASK_LID) { 151321936Shselasky OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 152321936Shselasky "Comparing lid:%u to port lid range: %u .. %u\n", 153321936Shselasky cl_ntoh16(p_rcvd_rec->lid), min_lid_ho, max_lid_ho); 154321936Shselasky /* ok we are ready for range check */ 155321936Shselasky if (min_lid_ho > cl_ntoh16(p_rcvd_rec->lid) || 156321936Shselasky max_lid_ho < cl_ntoh16(p_rcvd_rec->lid)) 157321936Shselasky return; 158321936Shselasky } 159321936Shselasky 160321936Shselasky /* now we need to decide which blocks to output */ 161321936Shselasky max_block = osm_switch_get_max_block_id_in_use(p_sw); 162321936Shselasky if (comp_mask & IB_LFTR_COMPMASK_BLOCK) { 163321936Shselasky min_block = cl_ntoh16(p_rcvd_rec->block_num); 164321936Shselasky if (min_block > max_block) 165321936Shselasky return; 166321936Shselasky max_block = min_block; 167321936Shselasky } else /* use as many blocks as "in use" */ 168321936Shselasky min_block = 0; 169321936Shselasky 170321936Shselasky /* so we can add these blocks one by one ... */ 171321936Shselasky for (block = min_block; block <= max_block; block++) 172321936Shselasky lftr_rcv_new_lftr(sa, p_sw, p_ctxt->p_list, 173321936Shselasky osm_port_get_base_lid(p_port), block); 174321936Shselasky} 175321936Shselasky 176321936Shselaskyvoid osm_lftr_rcv_process(IN void *ctx, IN void *data) 177321936Shselasky{ 178321936Shselasky osm_sa_t *sa = ctx; 179321936Shselasky osm_madw_t *p_madw = data; 180321936Shselasky const ib_sa_mad_t *p_rcvd_mad; 181321936Shselasky const ib_lft_record_t *p_rcvd_rec; 182321936Shselasky cl_qlist_t rec_list; 183321936Shselasky osm_lftr_search_ctxt_t context; 184321936Shselasky osm_physp_t *p_req_physp; 185321936Shselasky 186321936Shselasky CL_ASSERT(sa); 187321936Shselasky 188321936Shselasky OSM_LOG_ENTER(sa->p_log); 189321936Shselasky 190321936Shselasky CL_ASSERT(p_madw); 191321936Shselasky 192321936Shselasky p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw); 193321936Shselasky p_rcvd_rec = (ib_lft_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); 194321936Shselasky 195321936Shselasky CL_ASSERT(p_rcvd_mad->attr_id == IB_MAD_ATTR_LFT_RECORD); 196321936Shselasky 197321936Shselasky /* we only support SubnAdmGet and SubnAdmGetTable methods */ 198321936Shselasky if (p_rcvd_mad->method != IB_MAD_METHOD_GET && 199321936Shselasky p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) { 200321936Shselasky OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4408: " 201321936Shselasky "Unsupported Method (%s) for LFTRecord request\n", 202321936Shselasky ib_get_sa_method_str(p_rcvd_mad->method)); 203321936Shselasky osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); 204321936Shselasky goto Exit; 205321936Shselasky } 206321936Shselasky 207321936Shselasky cl_plock_acquire(sa->p_lock); 208321936Shselasky 209321936Shselasky /* update the requester physical port */ 210321936Shselasky p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, 211321936Shselasky osm_madw_get_mad_addr_ptr 212321936Shselasky (p_madw)); 213321936Shselasky if (p_req_physp == NULL) { 214321936Shselasky cl_plock_release(sa->p_lock); 215321936Shselasky OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4407: " 216321936Shselasky "Cannot find requester physical port\n"); 217321936Shselasky goto Exit; 218321936Shselasky } 219321936Shselasky 220321936Shselasky OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 221321936Shselasky "Requester port GUID 0x%" PRIx64 "\n", 222321936Shselasky cl_ntoh64(osm_physp_get_port_guid(p_req_physp))); 223321936Shselasky 224321936Shselasky cl_qlist_init(&rec_list); 225321936Shselasky 226321936Shselasky context.p_rcvd_rec = p_rcvd_rec; 227321936Shselasky context.p_list = &rec_list; 228321936Shselasky context.comp_mask = p_rcvd_mad->comp_mask; 229321936Shselasky context.sa = sa; 230321936Shselasky context.p_req_physp = p_req_physp; 231321936Shselasky 232321936Shselasky /* Go over all switches */ 233321936Shselasky cl_qmap_apply_func(&sa->p_subn->sw_guid_tbl, lftr_rcv_by_comp_mask, 234321936Shselasky &context); 235321936Shselasky 236321936Shselasky cl_plock_release(sa->p_lock); 237321936Shselasky 238321936Shselasky osm_sa_respond(sa, p_madw, sizeof(ib_lft_record_t), &rec_list); 239321936Shselasky 240321936ShselaskyExit: 241321936Shselasky OSM_LOG_EXIT(sa->p_log); 242321936Shselasky} 243