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_sa_mad_ctrl_t. 39 * This object is part of the SA object. 40 */ 41 42#if HAVE_CONFIG_H 43# include <config.h> 44#endif /* HAVE_CONFIG_H */ 45 46#include <string.h> 47#include <complib/cl_debug.h> 48#include <iba/ib_types.h> 49#include <vendor/osm_vendor_api.h> 50#include <opensm/osm_sa_mad_ctrl.h> 51#include <opensm/osm_msgdef.h> 52#include <opensm/osm_helper.h> 53#include <opensm/osm_sa.h> 54 55/****f* opensm: SA/__osm_sa_mad_ctrl_disp_done_callback 56 * NAME 57 * __osm_sa_mad_ctrl_disp_done_callback 58 * 59 * DESCRIPTION 60 * This function is the Dispatcher callback that indicates 61 * a received MAD has been processed by the recipient. 62 * 63 * SYNOPSIS 64 */ 65static void 66__osm_sa_mad_ctrl_disp_done_callback(IN void *context, IN void *p_data) 67{ 68 osm_sa_mad_ctrl_t *const p_ctrl = (osm_sa_mad_ctrl_t *) context; 69 osm_madw_t *const p_madw = (osm_madw_t *) p_data; 70 71 OSM_LOG_ENTER(p_ctrl->p_log); 72 73 CL_ASSERT(p_madw); 74 /* 75 Return the MAD & wrapper to the pool. 76 */ 77 osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); 78 OSM_LOG_EXIT(p_ctrl->p_log); 79} 80 81/************/ 82 83/****f* opensm: SA/__osm_sa_mad_ctrl_process 84 * NAME 85 * __osm_sa_mad_ctrl_process 86 * 87 * DESCRIPTION 88 * This function handles known methods for received MADs. 89 * 90 * SYNOPSIS 91 */ 92static void 93__osm_sa_mad_ctrl_process(IN osm_sa_mad_ctrl_t * const p_ctrl, 94 IN osm_madw_t * p_madw) 95{ 96 ib_sa_mad_t *p_sa_mad; 97 cl_status_t status; 98 cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE; 99 uint64_t last_dispatched_msg_queue_time_msec; 100 uint32_t num_messages; 101 102 OSM_LOG_ENTER(p_ctrl->p_log); 103 104 /* 105 If the dispatcher is showing us that it is overloaded 106 there is no point in placing the request in. We should instead provide 107 immediate response - IB_RESOURCE_BUSY 108 But how do we know? 109 The dispatcher reports back the number of outstanding messages and the 110 time the last message stayed in the queue. 111 HACK: Actually, we cannot send a mad from within the receive callback; 112 thus - we will just drop it. 113 */ 114 cl_disp_get_queue_status(p_ctrl->h_disp, 115 &num_messages, 116 &last_dispatched_msg_queue_time_msec); 117 if ((num_messages > 1) && 118 (p_ctrl->p_subn->opt.max_msg_fifo_timeout) && 119 (last_dispatched_msg_queue_time_msec > 120 p_ctrl->p_subn->opt.max_msg_fifo_timeout)) { 121 OSM_LOG(p_ctrl->p_log, OSM_LOG_INFO, 122 /* "Responding BUSY status since the dispatcher is already" */ 123 "Dropping MAD since the dispatcher is already" 124 " overloaded with %u messages and queue time of:" 125 "%" PRIu64 "[msec]\n", 126 num_messages, last_dispatched_msg_queue_time_msec); 127 128 /* send a busy response */ 129 /* osm_sa_send_error(p_ctrl->p_resp, p_madw, IB_RESOURCE_BUSY); */ 130 131 /* return the request to the pool */ 132 osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); 133 134 goto Exit; 135 } 136 137 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); 138 139 /* 140 Note that attr_id (like the rest of the MAD) is in 141 network byte order. 142 */ 143 switch (p_sa_mad->attr_id) { 144 case IB_MAD_ATTR_CLASS_PORT_INFO: 145 msg_id = OSM_MSG_MAD_CLASS_PORT_INFO; 146 break; 147 148 case IB_MAD_ATTR_NODE_RECORD: 149 msg_id = OSM_MSG_MAD_NODE_RECORD; 150 break; 151 152 case IB_MAD_ATTR_PORTINFO_RECORD: 153 msg_id = OSM_MSG_MAD_PORTINFO_RECORD; 154 break; 155 156 case IB_MAD_ATTR_LINK_RECORD: 157 msg_id = OSM_MSG_MAD_LINK_RECORD; 158 break; 159 160 case IB_MAD_ATTR_SMINFO_RECORD: 161 msg_id = OSM_MSG_MAD_SMINFO_RECORD; 162 break; 163 164 case IB_MAD_ATTR_SERVICE_RECORD: 165 msg_id = OSM_MSG_MAD_SERVICE_RECORD; 166 break; 167 168 case IB_MAD_ATTR_PATH_RECORD: 169 msg_id = OSM_MSG_MAD_PATH_RECORD; 170 break; 171 172 case IB_MAD_ATTR_MCMEMBER_RECORD: 173 msg_id = OSM_MSG_MAD_MCMEMBER_RECORD; 174 break; 175 176 case IB_MAD_ATTR_INFORM_INFO: 177 msg_id = OSM_MSG_MAD_INFORM_INFO; 178 break; 179 180 case IB_MAD_ATTR_VLARB_RECORD: 181 msg_id = OSM_MSG_MAD_VL_ARB_RECORD; 182 break; 183 184 case IB_MAD_ATTR_SLVL_RECORD: 185 msg_id = OSM_MSG_MAD_SLVL_TBL_RECORD; 186 break; 187 188 case IB_MAD_ATTR_PKEY_TBL_RECORD: 189 msg_id = OSM_MSG_MAD_PKEY_TBL_RECORD; 190 break; 191 192 case IB_MAD_ATTR_LFT_RECORD: 193 msg_id = OSM_MSG_MAD_LFT_RECORD; 194 break; 195 196 case IB_MAD_ATTR_GUIDINFO_RECORD: 197 msg_id = OSM_MSG_MAD_GUIDINFO_RECORD; 198 break; 199 200 case IB_MAD_ATTR_INFORM_INFO_RECORD: 201 msg_id = OSM_MSG_MAD_INFORM_INFO_RECORD; 202 break; 203 204 case IB_MAD_ATTR_SWITCH_INFO_RECORD: 205 msg_id = OSM_MSG_MAD_SWITCH_INFO_RECORD; 206 break; 207 208 case IB_MAD_ATTR_MFT_RECORD: 209 msg_id = OSM_MSG_MAD_MFT_RECORD; 210 break; 211 212#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) 213 case IB_MAD_ATTR_MULTIPATH_RECORD: 214 msg_id = OSM_MSG_MAD_MULTIPATH_RECORD; 215 break; 216#endif 217 218 default: 219 OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A01: " 220 "Unsupported attribute = 0x%X\n", 221 cl_ntoh16(p_sa_mad->attr_id)); 222 osm_dump_sa_mad(p_ctrl->p_log, p_sa_mad, OSM_LOG_ERROR); 223 } 224 225 if (msg_id != CL_DISP_MSGID_NONE) { 226 /* 227 Post this MAD to the dispatcher for asynchronous 228 processing by the appropriate controller. 229 */ 230 231 OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, 232 "Posting Dispatcher message %s\n", 233 osm_get_disp_msg_str(msg_id)); 234 235 status = cl_disp_post(p_ctrl->h_disp, 236 msg_id, 237 p_madw, 238 __osm_sa_mad_ctrl_disp_done_callback, 239 p_ctrl); 240 241 if (status != CL_SUCCESS) { 242 OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A02: " 243 "Dispatcher post message failed (%s) for attribute = 0x%X\n", 244 CL_STATUS_MSG(status), 245 cl_ntoh16(p_sa_mad->attr_id)); 246 247 osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); 248 goto Exit; 249 } 250 } else { 251 /* 252 There is an unknown MAD attribute type for which there is 253 no recipient. Simply retire the MAD here. 254 */ 255 cl_atomic_inc(&p_ctrl->p_stats->sa_mads_rcvd_unknown); 256 osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); 257 } 258 259Exit: 260 OSM_LOG_EXIT(p_ctrl->p_log); 261} 262 263/* 264 * PARAMETERS 265 * 266 * RETURN VALUES 267 * 268 * NOTES 269 * 270 * SEE ALSO 271 *********/ 272 273/****f* opensm: SA/__osm_sa_mad_ctrl_rcv_callback 274 * NAME 275 * __osm_sa_mad_ctrl_rcv_callback 276 * 277 * DESCRIPTION 278 * This is the callback from the transport layer for received MADs. 279 * 280 * SYNOPSIS 281 */ 282static void 283__osm_sa_mad_ctrl_rcv_callback(IN osm_madw_t * p_madw, 284 IN void *bind_context, 285 IN osm_madw_t * p_req_madw) 286{ 287 osm_sa_mad_ctrl_t *p_ctrl = (osm_sa_mad_ctrl_t *) bind_context; 288 ib_sa_mad_t *p_sa_mad; 289 290 OSM_LOG_ENTER(p_ctrl->p_log); 291 292 CL_ASSERT(p_madw); 293 294 /* 295 A MAD was received from the wire, possibly in response to a request. 296 */ 297 cl_atomic_inc(&p_ctrl->p_stats->sa_mads_rcvd); 298 299 OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, 300 "%u SA MADs received\n", p_ctrl->p_stats->sa_mads_rcvd); 301 302 /* 303 * C15-0.1.3 requires not responding to any MAD if the SM is 304 * not in active state! 305 * We will not respond if the sm_state is not MASTER, or if the 306 * first_time_master_sweep flag (of the subnet) is TRUE - this 307 * flag indicates that the master still didn't finish its first 308 * sweep, so the subnet is not up and stable yet. 309 */ 310 if (p_ctrl->p_subn->sm_state != IB_SMINFO_STATE_MASTER) { 311 cl_atomic_inc(&p_ctrl->p_stats->sa_mads_ignored); 312 OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE, 313 "Received SA MAD while SM not MASTER. MAD ignored\n"); 314 osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); 315 goto Exit; 316 } 317 if (p_ctrl->p_subn->first_time_master_sweep == TRUE) { 318 cl_atomic_inc(&p_ctrl->p_stats->sa_mads_ignored); 319 OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE, 320 "Received SA MAD while SM in first sweep. MAD ignored\n"); 321 osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); 322 goto Exit; 323 } 324 325 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); 326 327 if (osm_log_is_active(p_ctrl->p_log, OSM_LOG_FRAMES)) 328 osm_dump_sa_mad(p_ctrl->p_log, p_sa_mad, OSM_LOG_FRAMES); 329 330 /* 331 * C15-0.1.5 - Table 185: SA Header - p884 332 * SM_key should be either 0 or match the current SM_Key 333 * otherwise discard the MAD. 334 */ 335 if ((p_sa_mad->sm_key != 0) && 336 (p_sa_mad->sm_key != p_ctrl->p_subn->opt.sa_key)) { 337 OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A04: " 338 "Non-Zero SA MAD SM_Key: 0x%" PRIx64 " != SM_Key: 0x%" 339 PRIx64 "; MAD ignored\n", cl_ntoh64(p_sa_mad->sm_key), 340 cl_ntoh64(p_ctrl->p_subn->opt.sa_key) 341 ); 342 osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); 343 goto Exit; 344 } 345 346 switch (p_sa_mad->method) { 347 case IB_MAD_METHOD_REPORT_RESP: 348 /* we do not really do anything with report represses - 349 just retire the transaction */ 350 OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, 351 "Received Report Repress. Retiring the transaction\n"); 352 353 if (p_req_madw) 354 osm_mad_pool_put(p_ctrl->p_mad_pool, p_req_madw); 355 osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); 356 357 break; 358 359 case IB_MAD_METHOD_GET: 360 case IB_MAD_METHOD_GETTABLE: 361#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) 362 case IB_MAD_METHOD_GETMULTI: 363#endif 364 case IB_MAD_METHOD_SET: 365 case IB_MAD_METHOD_DELETE: 366 __osm_sa_mad_ctrl_process(p_ctrl, p_madw); 367 break; 368 369 default: 370 cl_atomic_inc(&p_ctrl->p_stats->sa_mads_rcvd_unknown); 371 OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A05: " 372 "Unsupported method = 0x%X\n", p_sa_mad->method); 373 osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); 374 goto Exit; 375 } 376 377Exit: 378 OSM_LOG_EXIT(p_ctrl->p_log); 379} 380 381/* 382 * PARAMETERS 383 * 384 * RETURN VALUES 385 * 386 * NOTES 387 * 388 * SEE ALSO 389 *********/ 390 391/****f* opensm: SA/__osm_sa_mad_ctrl_send_err_callback 392 * NAME 393 * __osm_sa_mad_ctrl_send_err_callback 394 * 395 * DESCRIPTION 396 * This is the callback from the transport layer for send errors 397 * on MADs that were expecting a response. 398 * 399 * SYNOPSIS 400 */ 401static void 402__osm_sa_mad_ctrl_send_err_callback(IN void *bind_context, 403 IN osm_madw_t * p_madw) 404{ 405 osm_sa_mad_ctrl_t *p_ctrl = (osm_sa_mad_ctrl_t *) bind_context; 406 cl_status_t status; 407 408 OSM_LOG_ENTER(p_ctrl->p_log); 409 410 OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A06: " 411 "MAD transaction completed in error\n"); 412 413 /* 414 We should never be here since the SA never originates a request. 415 Unless we generated a Report(Notice) 416 */ 417 418 CL_ASSERT(p_madw); 419 420 /* 421 An error occurred. No response was received to a request MAD. 422 Retire the original request MAD. 423 */ 424 425 osm_dump_sa_mad(p_ctrl->p_log, osm_madw_get_sa_mad_ptr(p_madw), 426 OSM_LOG_ERROR); 427 428 /* __osm_sm_mad_ctrl_update_wire_stats( p_ctrl ); */ 429 430 if (osm_madw_get_err_msg(p_madw) != CL_DISP_MSGID_NONE) { 431 OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, 432 "Posting Dispatcher message %s\n", 433 osm_get_disp_msg_str(osm_madw_get_err_msg(p_madw))); 434 435 status = cl_disp_post(p_ctrl->h_disp, 436 osm_madw_get_err_msg(p_madw), 437 p_madw, 438 __osm_sa_mad_ctrl_disp_done_callback, 439 p_ctrl); 440 if (status != CL_SUCCESS) { 441 OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A07: " 442 "Dispatcher post message failed (%s)\n", 443 CL_STATUS_MSG(status)); 444 } 445 } else { 446 /* 447 No error message was provided, just retire the MAD. 448 */ 449 osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); 450 } 451 452 OSM_LOG_EXIT(p_ctrl->p_log); 453} 454 455/* 456 * PARAMETERS 457 * 458 * RETURN VALUES 459 * 460 * NOTES 461 * 462 * SEE ALSO 463 *********/ 464 465/********************************************************************** 466 **********************************************************************/ 467void osm_sa_mad_ctrl_construct(IN osm_sa_mad_ctrl_t * const p_ctrl) 468{ 469 CL_ASSERT(p_ctrl); 470 memset(p_ctrl, 0, sizeof(*p_ctrl)); 471 p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; 472} 473 474/********************************************************************** 475 **********************************************************************/ 476void osm_sa_mad_ctrl_destroy(IN osm_sa_mad_ctrl_t * const p_ctrl) 477{ 478 CL_ASSERT(p_ctrl); 479 cl_disp_unregister(p_ctrl->h_disp); 480} 481 482/********************************************************************** 483 **********************************************************************/ 484ib_api_status_t 485osm_sa_mad_ctrl_init(IN osm_sa_mad_ctrl_t * const p_ctrl, 486 IN osm_sa_t * sa, 487 IN osm_mad_pool_t * const p_mad_pool, 488 IN osm_vendor_t * const p_vendor, 489 IN osm_subn_t * const p_subn, 490 IN osm_log_t * const p_log, 491 IN osm_stats_t * const p_stats, 492 IN cl_dispatcher_t * const p_disp) 493{ 494 ib_api_status_t status = IB_SUCCESS; 495 496 OSM_LOG_ENTER(p_log); 497 498 osm_sa_mad_ctrl_construct(p_ctrl); 499 500 p_ctrl->sa = sa; 501 p_ctrl->p_log = p_log; 502 p_ctrl->p_disp = p_disp; 503 p_ctrl->p_mad_pool = p_mad_pool; 504 p_ctrl->p_vendor = p_vendor; 505 p_ctrl->p_stats = p_stats; 506 p_ctrl->p_subn = p_subn; 507 508 p_ctrl->h_disp = cl_disp_register(p_disp, 509 CL_DISP_MSGID_NONE, NULL, p_ctrl); 510 511 if (p_ctrl->h_disp == CL_DISP_INVALID_HANDLE) { 512 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 1A08: " 513 "Dispatcher registration failed\n"); 514 status = IB_INSUFFICIENT_RESOURCES; 515 goto Exit; 516 } 517 518Exit: 519 OSM_LOG_EXIT(p_log); 520 return (status); 521} 522 523/********************************************************************** 524 **********************************************************************/ 525ib_api_status_t 526osm_sa_mad_ctrl_bind(IN osm_sa_mad_ctrl_t * const p_ctrl, 527 IN const ib_net64_t port_guid) 528{ 529 osm_bind_info_t bind_info; 530 ib_api_status_t status = IB_SUCCESS; 531 532 OSM_LOG_ENTER(p_ctrl->p_log); 533 534 if (p_ctrl->h_bind != OSM_BIND_INVALID_HANDLE) { 535 OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A09: " 536 "Multiple binds not allowed\n"); 537 status = IB_ERROR; 538 goto Exit; 539 } 540 541 bind_info.class_version = 2; 542 bind_info.is_responder = TRUE; 543 bind_info.is_report_processor = FALSE; 544 bind_info.is_trap_processor = FALSE; 545 bind_info.mad_class = IB_MCLASS_SUBN_ADM; 546 bind_info.port_guid = port_guid; 547 bind_info.recv_q_size = OSM_SM_DEFAULT_QP1_RCV_SIZE; 548 bind_info.send_q_size = OSM_SM_DEFAULT_QP1_SEND_SIZE; 549 550 OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE, 551 "Binding to port GUID 0x%" PRIx64 "\n", cl_ntoh64(port_guid)); 552 553 p_ctrl->h_bind = osm_vendor_bind(p_ctrl->p_vendor, 554 &bind_info, 555 p_ctrl->p_mad_pool, 556 __osm_sa_mad_ctrl_rcv_callback, 557 __osm_sa_mad_ctrl_send_err_callback, 558 p_ctrl); 559 560 if (p_ctrl->h_bind == OSM_BIND_INVALID_HANDLE) { 561 status = IB_ERROR; 562 OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A10: " 563 "Vendor specific bind failed (%s)\n", 564 ib_get_err_str(status)); 565 goto Exit; 566 } 567 568Exit: 569 OSM_LOG_EXIT(p_ctrl->p_log); 570 return (status); 571} 572 573/********************************************************************** 574 **********************************************************************/ 575ib_api_status_t osm_sa_mad_ctrl_unbind(IN osm_sa_mad_ctrl_t * const p_ctrl) 576{ 577 ib_api_status_t status = IB_SUCCESS; 578 579 OSM_LOG_ENTER(p_ctrl->p_log); 580 581 if (p_ctrl->h_bind == OSM_BIND_INVALID_HANDLE) { 582 OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A11: " 583 "No previous bind\n"); 584 status = IB_ERROR; 585 goto Exit; 586 } 587 588 osm_vendor_unbind(p_ctrl->h_bind); 589Exit: 590 OSM_LOG_EXIT(p_ctrl->p_log); 591 return (status); 592} 593