1/* 2 * Copyright (c) 2004-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_vlarb_rec_rcv_t. 39 * This object represents the VLArbitrationRecord 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_vl_arb_item { 61 cl_list_item_t list_item; 62 ib_vl_arb_table_record_t rec; 63} osm_vl_arb_item_t; 64 65typedef struct osm_vl_arb_search_ctxt { 66 const ib_vl_arb_table_record_t *p_rcvd_rec; 67 ib_net64_t comp_mask; 68 uint8_t block_num; 69 cl_qlist_t *p_list; 70 osm_sa_t *sa; 71 const osm_physp_t *p_req_physp; 72} osm_vl_arb_search_ctxt_t; 73 74/********************************************************************** 75 **********************************************************************/ 76static void 77__osm_sa_vl_arb_create(IN osm_sa_t * sa, 78 IN osm_physp_t * const p_physp, 79 IN osm_vl_arb_search_ctxt_t * const p_ctxt, 80 IN uint8_t block) 81{ 82 osm_vl_arb_item_t *p_rec_item; 83 uint16_t lid; 84 ib_api_status_t status = IB_SUCCESS; 85 86 OSM_LOG_ENTER(sa->p_log); 87 88 p_rec_item = malloc(sizeof(*p_rec_item)); 89 if (p_rec_item == NULL) { 90 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2A02: " 91 "rec_item alloc failed\n"); 92 status = IB_INSUFFICIENT_RESOURCES; 93 goto Exit; 94 } 95 96 if (p_physp->p_node->node_info.node_type != IB_NODE_TYPE_SWITCH) 97 lid = p_physp->port_info.base_lid; 98 else 99 lid = osm_node_get_base_lid(p_physp->p_node, 0); 100 101 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 102 "New VLArbitration for: port 0x%016" PRIx64 103 ", lid %u, port %u Block:%u\n", 104 cl_ntoh64(osm_physp_get_port_guid(p_physp)), 105 cl_ntoh16(lid), osm_physp_get_port_num(p_physp), block); 106 107 memset(p_rec_item, 0, sizeof(*p_rec_item)); 108 109 p_rec_item->rec.lid = lid; 110 p_rec_item->rec.port_num = osm_physp_get_port_num(p_physp); 111 p_rec_item->rec.block_num = block; 112 p_rec_item->rec.vl_arb_tbl = *(osm_physp_get_vla_tbl(p_physp, block)); 113 114 cl_qlist_insert_tail(p_ctxt->p_list, &p_rec_item->list_item); 115 116Exit: 117 OSM_LOG_EXIT(sa->p_log); 118} 119 120/********************************************************************** 121 **********************************************************************/ 122static void 123__osm_sa_vl_arb_check_physp(IN osm_sa_t * sa, 124 IN osm_physp_t * const p_physp, 125 osm_vl_arb_search_ctxt_t * const p_ctxt) 126{ 127 ib_net64_t comp_mask = p_ctxt->comp_mask; 128 uint8_t block; 129 130 OSM_LOG_ENTER(sa->p_log); 131 132 /* we got here with the phys port - all that's left is to get the right block */ 133 for (block = 1; block <= 4; block++) { 134 if (!(comp_mask & IB_VLA_COMPMASK_BLOCK) 135 || block == p_ctxt->block_num) { 136 __osm_sa_vl_arb_create(sa, p_physp, p_ctxt, block); 137 } 138 } 139 140 OSM_LOG_EXIT(sa->p_log); 141} 142 143/********************************************************************** 144 **********************************************************************/ 145static void 146__osm_sa_vl_arb_by_comp_mask(IN osm_sa_t * sa, 147 IN const osm_port_t * const p_port, 148 osm_vl_arb_search_ctxt_t * const p_ctxt) 149{ 150 const ib_vl_arb_table_record_t *p_rcvd_rec; 151 ib_net64_t comp_mask; 152 osm_physp_t *p_physp; 153 uint8_t port_num; 154 uint8_t num_ports; 155 const osm_physp_t *p_req_physp; 156 157 OSM_LOG_ENTER(sa->p_log); 158 159 p_rcvd_rec = p_ctxt->p_rcvd_rec; 160 comp_mask = p_ctxt->comp_mask; 161 port_num = p_rcvd_rec->port_num; 162 p_req_physp = p_ctxt->p_req_physp; 163 164 /* if this is a switch port we can search all ports 165 otherwise we must be looking on port 0 */ 166 if (p_port->p_node->node_info.node_type != IB_NODE_TYPE_SWITCH) { 167 /* we put it in the comp mask and port num */ 168 port_num = p_port->p_physp->port_num; 169 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 170 "Using Physical Default Port Number: 0x%X (for End Node)\n", 171 port_num); 172 comp_mask |= IB_VLA_COMPMASK_OUT_PORT; 173 } 174 175 if (comp_mask & IB_VLA_COMPMASK_OUT_PORT) { 176 if (port_num < osm_node_get_num_physp(p_port->p_node)) { 177 p_physp = 178 osm_node_get_physp_ptr(p_port->p_node, port_num); 179 /* check that the p_physp is valid, and that the requester 180 and the p_physp share a pkey. */ 181 if (p_physp && 182 osm_physp_share_pkey(sa->p_log, p_req_physp, 183 p_physp)) 184 __osm_sa_vl_arb_check_physp(sa, p_physp, 185 p_ctxt); 186 } else { 187 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2A03: " 188 "Given Physical Port Number: 0x%X is out of range should be < 0x%X\n", 189 port_num, 190 osm_node_get_num_physp(p_port->p_node)); 191 goto Exit; 192 } 193 } else { 194 num_ports = osm_node_get_num_physp(p_port->p_node); 195 for (port_num = 0; port_num < num_ports; port_num++) { 196 p_physp = 197 osm_node_get_physp_ptr(p_port->p_node, port_num); 198 if (!p_physp) 199 continue; 200 201 /* if the requester and the p_physp don't share a pkey - 202 continue */ 203 if (!osm_physp_share_pkey 204 (sa->p_log, p_req_physp, p_physp)) 205 continue; 206 207 __osm_sa_vl_arb_check_physp(sa, p_physp, p_ctxt); 208 } 209 } 210Exit: 211 OSM_LOG_EXIT(sa->p_log); 212} 213 214/********************************************************************** 215 **********************************************************************/ 216static void 217__osm_sa_vl_arb_by_comp_mask_cb(IN cl_map_item_t * const p_map_item, 218 IN void *context) 219{ 220 const osm_port_t *const p_port = (osm_port_t *) p_map_item; 221 osm_vl_arb_search_ctxt_t *const p_ctxt = 222 (osm_vl_arb_search_ctxt_t *) context; 223 224 __osm_sa_vl_arb_by_comp_mask(p_ctxt->sa, p_port, p_ctxt); 225} 226 227/********************************************************************** 228 **********************************************************************/ 229void osm_vlarb_rec_rcv_process(IN void *ctx, IN void *data) 230{ 231 osm_sa_t *sa = ctx; 232 osm_madw_t *p_madw = data; 233 const ib_sa_mad_t *sad_mad; 234 const ib_vl_arb_table_record_t *p_rcvd_rec; 235 const osm_port_t *p_port = NULL; 236 const ib_vl_arb_table_t *p_vl_arb; 237 cl_qlist_t rec_list; 238 osm_vl_arb_search_ctxt_t context; 239 ib_api_status_t status = IB_SUCCESS; 240 ib_net64_t comp_mask; 241 osm_physp_t *p_req_physp; 242 243 CL_ASSERT(sa); 244 245 OSM_LOG_ENTER(sa->p_log); 246 247 CL_ASSERT(p_madw); 248 249 sad_mad = osm_madw_get_sa_mad_ptr(p_madw); 250 p_rcvd_rec = 251 (ib_vl_arb_table_record_t *) ib_sa_mad_get_payload_ptr(sad_mad); 252 comp_mask = sad_mad->comp_mask; 253 254 CL_ASSERT(sad_mad->attr_id == IB_MAD_ATTR_VLARB_RECORD); 255 256 /* we only support SubnAdmGet and SubnAdmGetTable methods */ 257 if (sad_mad->method != IB_MAD_METHOD_GET && 258 sad_mad->method != IB_MAD_METHOD_GETTABLE) { 259 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2A05: " 260 "Unsupported Method (%s)\n", 261 ib_get_sa_method_str(sad_mad->method)); 262 osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); 263 goto Exit; 264 } 265 266 /* update the requester physical port. */ 267 p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, 268 osm_madw_get_mad_addr_ptr 269 (p_madw)); 270 if (p_req_physp == NULL) { 271 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2A04: " 272 "Cannot find requester physical port\n"); 273 goto Exit; 274 } 275 276 p_vl_arb = (ib_vl_arb_table_t *) ib_sa_mad_get_payload_ptr(sad_mad); 277 278 cl_qlist_init(&rec_list); 279 280 context.p_rcvd_rec = p_rcvd_rec; 281 context.p_list = &rec_list; 282 context.comp_mask = sad_mad->comp_mask; 283 context.sa = sa; 284 context.block_num = p_rcvd_rec->block_num; 285 context.p_req_physp = p_req_physp; 286 287 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 288 "Got Query Lid:%u(%02X), Port:0x%02X(%02X), Block:0x%02X(%02X)\n", 289 cl_ntoh16(p_rcvd_rec->lid), 290 (comp_mask & IB_VLA_COMPMASK_LID) != 0, p_rcvd_rec->port_num, 291 (comp_mask & IB_VLA_COMPMASK_OUT_PORT) != 0, 292 p_rcvd_rec->block_num, 293 (comp_mask & IB_VLA_COMPMASK_BLOCK) != 0); 294 295 cl_plock_acquire(sa->p_lock); 296 297 /* 298 If the user specified a LID, it obviously narrows our 299 work load, since we don't have to search every port 300 */ 301 if (comp_mask & IB_VLA_COMPMASK_LID) { 302 status = 303 osm_get_port_by_base_lid(sa->p_subn, p_rcvd_rec->lid, 304 &p_port); 305 if ((status != IB_SUCCESS) || (p_port == NULL)) { 306 status = IB_NOT_FOUND; 307 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2A09: " 308 "No port found with LID %u\n", 309 cl_ntoh16(p_rcvd_rec->lid)); 310 } 311 } 312 313 if (status == IB_SUCCESS) { 314 /* if we got a unique port - no need for a port search */ 315 if (p_port) 316 /* this does the loop on all the port phys ports */ 317 __osm_sa_vl_arb_by_comp_mask(sa, p_port, &context); 318 else 319 cl_qmap_apply_func(&sa->p_subn->port_guid_tbl, 320 __osm_sa_vl_arb_by_comp_mask_cb, 321 &context); 322 } 323 324 cl_plock_release(sa->p_lock); 325 326 osm_sa_respond(sa, p_madw, sizeof(ib_vl_arb_table_record_t), &rec_list); 327 328Exit: 329 OSM_LOG_EXIT(sa->p_log); 330} 331