1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * tavor_agents.c 29 * Tavor InfiniBand Management Agent (SMA, PMA, BMA) routines 30 * 31 * Implements all the routines necessary for initializing, handling, 32 * and (later) tearing down all the infrastructure necessary for Tavor 33 * MAD processing. 34 */ 35 36 #include <sys/types.h> 37 #include <sys/conf.h> 38 #include <sys/ddi.h> 39 #include <sys/sunddi.h> 40 #include <sys/modctl.h> 41 42 #include <sys/ib/adapters/tavor/tavor.h> 43 #include <sys/ib/mgt/ibmf/ibmf.h> 44 #include <sys/disp.h> 45 46 static void tavor_agent_request_cb(ibmf_handle_t ibmf_handle, 47 ibmf_msg_t *msgp, void *args); 48 static void tavor_agent_handle_req(void *cb_args); 49 static void tavor_agent_response_cb(ibmf_handle_t ibmf_handle, 50 ibmf_msg_t *msgp, void *args); 51 static int tavor_agent_list_init(tavor_state_t *state); 52 static void tavor_agent_list_fini(tavor_state_t *state); 53 static int tavor_agent_register_all(tavor_state_t *state); 54 static int tavor_agent_unregister_all(tavor_state_t *state, int num_reg); 55 static void tavor_agent_mad_resp_handling(tavor_state_t *state, 56 ibmf_msg_t *msgp, uint_t port); 57 58 /* 59 * tavor_agent_handlers_init() 60 * Context: Only called from attach() and/or detach() path contexts 61 */ 62 int 63 tavor_agent_handlers_init(tavor_state_t *state) 64 { 65 int status; 66 char *errormsg, *rsrc_name; 67 68 TAVOR_TNF_ENTER(tavor_agent_handlers_init); 69 70 /* Determine if we need to register any agents with the IBMF */ 71 if ((state->ts_cfg_profile->cp_qp0_agents_in_fw) && 72 (state->ts_cfg_profile->cp_qp1_agents_in_fw)) { 73 TAVOR_TNF_EXIT(tavor_agent_handlers_init); 74 return (DDI_SUCCESS); 75 } 76 77 /* 78 * Build a unique name for the Tavor task queue from the Tavor driver 79 * instance number and TAVOR_TASKQ_NAME 80 */ 81 rsrc_name = (char *)kmem_zalloc(TAVOR_RSRC_NAME_MAXLEN, KM_SLEEP); 82 TAVOR_RSRC_NAME(rsrc_name, TAVOR_TASKQ_NAME); 83 84 /* Initialize the Tavor IB management agent list */ 85 status = tavor_agent_list_init(state); 86 if (status != DDI_SUCCESS) { 87 /* Set "status" and "errormsg" and goto failure */ 88 TAVOR_TNF_FAIL(DDI_FAILURE, "failed agent list init"); 89 goto agentsinit_fail; 90 } 91 92 /* 93 * Initialize the agent handling task queue. Note: We set the task 94 * queue priority to the minimum system priority. At this point this 95 * is considered acceptable because MADs are unreliable datagrams 96 * and could get lost (in general) anyway. 97 */ 98 state->ts_taskq_agents = ddi_taskq_create(state->ts_dip, 99 rsrc_name, TAVOR_TASKQ_NTHREADS, TASKQ_DEFAULTPRI, 0); 100 if (state->ts_taskq_agents == NULL) { 101 tavor_agent_list_fini(state); 102 /* Set "status" and "errormsg" and goto failure */ 103 TAVOR_TNF_FAIL(DDI_FAILURE, "failed task queue"); 104 goto agentsinit_fail; 105 } 106 107 /* Now attempt to register all of the agents with the IBMF */ 108 status = tavor_agent_register_all(state); 109 if (status != DDI_SUCCESS) { 110 ddi_taskq_destroy(state->ts_taskq_agents); 111 tavor_agent_list_fini(state); 112 /* Set "status" and "errormsg" and goto failure */ 113 TAVOR_TNF_FAIL(DDI_FAILURE, "failed IBMF register"); 114 goto agentsinit_fail; 115 } 116 117 kmem_free(rsrc_name, TAVOR_RSRC_NAME_MAXLEN); 118 TAVOR_TNF_EXIT(tavor_agent_handlers_init); 119 return (DDI_SUCCESS); 120 121 agentsinit_fail: 122 kmem_free(rsrc_name, TAVOR_RSRC_NAME_MAXLEN); 123 TNF_PROBE_1(tavor_agent_handlers_init_fail, TAVOR_TNF_ERROR, "", 124 tnf_string, msg, errormsg); 125 TAVOR_TNF_EXIT(tavor_agent_handlers_init); 126 return (status); 127 } 128 129 130 /* 131 * tavor_agent_handlers_fini() 132 * Context: Only called from detach() path context 133 */ 134 int 135 tavor_agent_handlers_fini(tavor_state_t *state) 136 { 137 int status; 138 139 TAVOR_TNF_ENTER(tavor_agent_handlers_fini); 140 141 /* Determine if we need to unregister any agents from the IBMF */ 142 if ((state->ts_cfg_profile->cp_qp0_agents_in_fw) && 143 (state->ts_cfg_profile->cp_qp1_agents_in_fw)) { 144 TAVOR_TNF_EXIT(tavor_agent_handlers_fini); 145 return (DDI_SUCCESS); 146 } 147 148 /* Now attempt to unregister all of the agents from the IBMF */ 149 status = tavor_agent_unregister_all(state, state->ts_num_agents); 150 if (status != DDI_SUCCESS) { 151 TNF_PROBE_0(tavor_agent_handlers_fini_unreg_fail, 152 TAVOR_TNF_ERROR, ""); 153 TAVOR_TNF_EXIT(tavor_agent_handlers_fini); 154 return (DDI_FAILURE); 155 } 156 157 /* 158 * Destroy the task queue. The task queue destroy is guaranteed to 159 * wait until any scheduled tasks have completed. We are able to 160 * guarantee that no _new_ tasks will be added the task queue while 161 * we are in the ddi_taskq_destroy() call because we have 162 * (at this point) successfully unregistered from IBMF (in 163 * tavor_agent_unregister_all() above). 164 */ 165 ddi_taskq_destroy(state->ts_taskq_agents); 166 167 /* Teardown the Tavor IB management agent list */ 168 tavor_agent_list_fini(state); 169 170 TAVOR_TNF_EXIT(tavor_agent_handlers_fini); 171 return (DDI_SUCCESS); 172 } 173 174 175 /* 176 * tavor_agent_request_cb() 177 * Context: Called from the IBMF context 178 */ 179 static void 180 tavor_agent_request_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, 181 void *args) 182 { 183 tavor_agent_handler_arg_t *cb_args; 184 tavor_agent_list_t *curr; 185 tavor_state_t *state; 186 int status; 187 int ibmf_status; 188 189 TAVOR_TNF_ENTER(tavor_agent_request_cb); 190 191 curr = (tavor_agent_list_t *)args; 192 state = curr->agl_state; 193 194 /* 195 * Allocate space to hold the callback args (for passing to the 196 * task queue). Note: If we are unable to allocate space for the 197 * the callback args here, then we just return. But we must ensure 198 * that we call ibmf_free_msg() to free up the message. 199 */ 200 cb_args = (tavor_agent_handler_arg_t *)kmem_zalloc( 201 sizeof (tavor_agent_handler_arg_t), KM_NOSLEEP); 202 if (cb_args == NULL) { 203 ibmf_status = ibmf_free_msg(ibmf_handle, &msgp); 204 if (ibmf_status != IBMF_SUCCESS) { 205 TNF_PROBE_1(tavor_agent_request_cb_ibmf_free_msg_fail, 206 TAVOR_TNF_ERROR, "", tnf_uint, ibmf_status, 207 ibmf_status); 208 } 209 TNF_PROBE_0(tavor_agent_request_cb_kma_fail, 210 TAVOR_TNF_ERROR, ""); 211 TAVOR_TNF_EXIT(tavor_agent_request_cb); 212 return; 213 } 214 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cb_args)) 215 216 /* Fill in the callback args */ 217 cb_args->ahd_ibmfhdl = ibmf_handle; 218 cb_args->ahd_ibmfmsg = msgp; 219 cb_args->ahd_agentlist = args; 220 221 /* 222 * Dispatch the message to the task queue. Note: Just like above, 223 * if this request fails for any reason then make sure to free up 224 * the IBMF message and then return 225 */ 226 status = ddi_taskq_dispatch(state->ts_taskq_agents, 227 tavor_agent_handle_req, cb_args, DDI_NOSLEEP); 228 if (status == DDI_FAILURE) { 229 kmem_free(cb_args, sizeof (tavor_agent_handler_arg_t)); 230 ibmf_status = ibmf_free_msg(ibmf_handle, &msgp); 231 if (ibmf_status != IBMF_SUCCESS) { 232 TNF_PROBE_1(tavor_agent_request_cb_ibmf_free_msg_fail, 233 TAVOR_TNF_ERROR, "", tnf_uint, ibmf_status, 234 ibmf_status); 235 } 236 TNF_PROBE_0(tavor_agent_request_cb_taskq_fail, 237 TAVOR_TNF_ERROR, ""); 238 } 239 TAVOR_TNF_EXIT(tavor_agent_request_cb); 240 } 241 242 /* 243 * tavor_agent_handle_req() 244 * Context: Called with priority of taskQ thread 245 */ 246 static void 247 tavor_agent_handle_req(void *cb_args) 248 { 249 tavor_agent_handler_arg_t *agent_args; 250 tavor_agent_list_t *curr; 251 tavor_state_t *state; 252 ibmf_handle_t ibmf_handle; 253 ibmf_msg_t *msgp; 254 ibmf_msg_bufs_t *recv_msgbufp; 255 ibmf_msg_bufs_t *send_msgbufp; 256 ibmf_retrans_t retrans; 257 uint_t port; 258 int status; 259 260 TAVOR_TNF_ENTER(tavor_agent_handle_req); 261 262 /* Extract the necessary info from the callback args parameter */ 263 agent_args = (tavor_agent_handler_arg_t *)cb_args; 264 ibmf_handle = agent_args->ahd_ibmfhdl; 265 msgp = agent_args->ahd_ibmfmsg; 266 curr = agent_args->ahd_agentlist; 267 state = curr->agl_state; 268 port = curr->agl_port; 269 270 /* 271 * Set the message send buffer pointers to the message receive buffer 272 * pointers to reuse the IBMF provided buffers for the sender 273 * information. 274 */ 275 recv_msgbufp = &msgp->im_msgbufs_recv; 276 send_msgbufp = &msgp->im_msgbufs_send; 277 bcopy(recv_msgbufp, send_msgbufp, sizeof (ibmf_msg_bufs_t)); 278 279 /* 280 * Check if the incoming packet is a special "Tavor Trap" MAD. If it 281 * is, then do the special handling. If it isn't, then simply pass it 282 * on to the firmware and forward the response back to the IBMF. 283 * 284 * Note: Tavor has a unique method for handling internally generated 285 * Traps. All internally detected/generated Trap messages are 286 * automatically received by the IBMF (as receive completions on QP0), 287 * which (because all Tavor Trap MADs have SLID == 0) detects it as a 288 * special "Tavor Trap" and forwards it here to the driver's SMA. 289 * It is then our responsibility here to fill in the Trap MAD's DLID 290 * for forwarding to the real Master SM (as programmed in the port's 291 * PortInfo.MasterSMLID field.) 292 */ 293 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(msgp->im_local_addr)) 294 if (TAVOR_IS_SPECIAL_TRAP_MAD(msgp)) { 295 msgp->im_local_addr.ia_remote_lid = 296 TAVOR_PORT_MASTERSMLID_GET(state, port - 1); 297 } else { 298 /* 299 * Post the command to the firmware (using the MAD_IFC 300 * command). Note: We also reuse the command that was passed 301 * in. We pass the pointer to the original MAD payload as if 302 * it were both the source of the incoming MAD as well as the 303 * destination for the response. This is acceptable and saves 304 * us the step of one additional copy. Note: If this command 305 * fails for any reason other than TAVOR_CMD_BAD_PKT, it 306 * probably indicates a serious problem. 307 */ 308 status = tavor_mad_ifc_cmd_post(state, port, 309 TAVOR_CMD_SLEEP_NOSPIN, 310 (uint32_t *)recv_msgbufp->im_bufs_mad_hdr, 311 (uint32_t *)send_msgbufp->im_bufs_mad_hdr); 312 if (status != TAVOR_CMD_SUCCESS) { 313 if ((status != TAVOR_CMD_BAD_PKT) && 314 (status != TAVOR_CMD_INSUFF_RSRC)) { 315 cmn_err(CE_CONT, "Tavor: MAD_IFC (port %02d) " 316 "command failed: %08x\n", port, status); 317 TNF_PROBE_1(tavor_agent_handle_req_madifc_fail, 318 TAVOR_TNF_ERROR, "", tnf_uint, cmd_status, 319 status); 320 } 321 322 /* finish cleanup */ 323 goto tavor_agent_handle_req_skip_response; 324 } 325 } 326 327 /* 328 * If incoming MAD was "TrapRepress", then no response is necessary. 329 * Free the IBMF message and return. 330 */ 331 if (TAVOR_IS_TRAP_REPRESS_MAD(msgp)) { 332 goto tavor_agent_handle_req_skip_response; 333 } 334 335 /* 336 * Modify the response MAD as necessary (for any special cases). 337 * Specifically, if this MAD was a directed route MAD, then some 338 * additional packet manipulation may be necessary because the Tavor 339 * firmware does not do all the required steps to respond to the 340 * MAD. 341 */ 342 tavor_agent_mad_resp_handling(state, msgp, port); 343 344 /* 345 * Send response (or forwarded "Trap" MAD) back to IBMF. We use the 346 * "response callback" to indicate when it is appropriate (later) to 347 * free the IBMF msg. 348 */ 349 status = ibmf_msg_transport(ibmf_handle, IBMF_QP_HANDLE_DEFAULT, 350 msgp, &retrans, tavor_agent_response_cb, state, 0); 351 if (status != IBMF_SUCCESS) { 352 TNF_PROBE_1(tavor_ibmf_send_msg_fail, TAVOR_TNF_ERROR, "", 353 tnf_uint, ibmf_status, status); 354 goto tavor_agent_handle_req_skip_response; 355 } 356 357 /* Free up the callback args parameter */ 358 kmem_free(agent_args, sizeof (tavor_agent_handler_arg_t)); 359 TAVOR_TNF_EXIT(tavor_agent_handle_req); 360 return; 361 362 tavor_agent_handle_req_skip_response: 363 /* Free up the ibmf message */ 364 status = ibmf_free_msg(ibmf_handle, &msgp); 365 if (status != IBMF_SUCCESS) { 366 TNF_PROBE_1(tavor_agent_handle_req_ibmf_free_msg_fail, 367 TAVOR_TNF_ERROR, "", tnf_uint, ibmf_status, 368 status); 369 } 370 /* Free up the callback args parameter */ 371 kmem_free(agent_args, sizeof (tavor_agent_handler_arg_t)); 372 TAVOR_TNF_EXIT(tavor_agent_handle_req); 373 } 374 375 376 /* 377 * tavor_agent_response_cb() 378 * Context: Called from the IBMF context 379 */ 380 /* ARGSUSED */ 381 static void 382 tavor_agent_response_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, 383 void *args) 384 { 385 int status; 386 387 TAVOR_TNF_ENTER(tavor_agent_response_cb); 388 389 /* 390 * It is the responsibility of each IBMF callback recipient to free 391 * the packets that it has been given. Now that we are in the 392 * response callback, we can be assured that it is safe to do so. 393 */ 394 status = ibmf_free_msg(ibmf_handle, &msgp); 395 if (status != IBMF_SUCCESS) { 396 TNF_PROBE_1(tavor_agent_response_cb_ibmf_free_msg_fail, 397 TAVOR_TNF_ERROR, "", tnf_uint, ibmf_status, status); 398 } 399 400 TAVOR_TNF_EXIT(tavor_agent_response_cb); 401 } 402 403 404 /* 405 * tavor_agent_list_init() 406 * Context: Only called from attach() path context 407 */ 408 static int 409 tavor_agent_list_init(tavor_state_t *state) 410 { 411 tavor_agent_list_t *curr; 412 uint_t num_ports, num_agents, num_agents_per_port; 413 uint_t num_sma_agents = 0; 414 uint_t num_pma_agents = 0; 415 uint_t num_bma_agents = 0; 416 uint_t do_qp0, do_qp1; 417 int i, j, indx; 418 419 TAVOR_TNF_ENTER(tavor_agent_list_init); 420 421 /* 422 * Calculate the number of registered agents for each port 423 * (SMA, PMA, and BMA) and determine whether or not to register 424 * a given agent with the IBMF (or whether to let the Tavor firmware 425 * handle it) 426 */ 427 num_ports = state->ts_cfg_profile->cp_num_ports; 428 num_agents = 0; 429 num_agents_per_port = 0; 430 do_qp0 = state->ts_cfg_profile->cp_qp0_agents_in_fw; 431 do_qp1 = state->ts_cfg_profile->cp_qp1_agents_in_fw; 432 if (do_qp0 == 0) { 433 num_agents += (num_ports * TAVOR_NUM_QP0_AGENTS_PER_PORT); 434 num_agents_per_port += TAVOR_NUM_QP0_AGENTS_PER_PORT; 435 num_sma_agents = num_ports; 436 } 437 if (do_qp1 == 0) { 438 num_agents += (num_ports * TAVOR_NUM_QP1_AGENTS_PER_PORT); 439 num_agents_per_port += TAVOR_NUM_QP1_AGENTS_PER_PORT; 440 num_pma_agents = num_ports; 441 /* 442 * The following line is commented out because the Tavor 443 * firmware does not currently support a BMA. If it did, 444 * then we would want to register the agent with the IBMF. 445 * (We would also need to have TAVOR_NUM_QP1_AGENTS_PER_PORT 446 * set to 2, instead of 1.) 447 * 448 * num_bma_agents = num_ports; 449 */ 450 } 451 452 state->ts_num_agents = num_agents; 453 454 /* 455 * Allocate the memory for all of the agent list entries 456 */ 457 state->ts_agents = (tavor_agent_list_t *)kmem_zalloc(num_agents * 458 sizeof (tavor_agent_list_t), KM_SLEEP); 459 if (state->ts_agents == NULL) { 460 TNF_PROBE_0(tavor_agent_list_init_kma_fail, 461 TAVOR_TNF_ERROR, ""); 462 TAVOR_TNF_EXIT(tavor_agent_list_init); 463 return (DDI_FAILURE); 464 } 465 466 /* 467 * Fill in each of the agent list entries with the agent's 468 * MgmtClass, port number, and Tavor softstate pointer 469 */ 470 indx = 0; 471 for (i = 0; i < num_agents_per_port; i++) { 472 for (j = 0; j < num_ports; j++) { 473 curr = &state->ts_agents[indx]; 474 curr->agl_state = state; 475 curr->agl_port = j + 1; 476 477 if ((do_qp0 == 0) && num_sma_agents) { 478 curr->agl_mgmtclass = SUBN_AGENT; 479 num_sma_agents--; 480 indx++; 481 } else if ((do_qp1 == 0) && (num_pma_agents)) { 482 curr->agl_mgmtclass = PERF_AGENT; 483 num_pma_agents--; 484 indx++; 485 } else if ((do_qp1 == 0) && (num_bma_agents)) { 486 curr->agl_mgmtclass = BM_AGENT; 487 num_bma_agents--; 488 indx++; 489 } 490 } 491 } 492 493 TAVOR_TNF_EXIT(tavor_agent_list_init); 494 return (DDI_SUCCESS); 495 } 496 497 498 /* 499 * tavor_agent_list_fini() 500 * Context: Only called from attach() and/or detach() path contexts 501 */ 502 static void 503 tavor_agent_list_fini(tavor_state_t *state) 504 { 505 TAVOR_TNF_ENTER(tavor_agent_list_fini); 506 507 /* Free up the memory for the agent list entries */ 508 kmem_free(state->ts_agents, 509 state->ts_num_agents * sizeof (tavor_agent_list_t)); 510 511 TAVOR_TNF_EXIT(tavor_agent_list_fini); 512 } 513 514 515 /* 516 * tavor_agent_register_all() 517 * Context: Only called from attach() path context 518 */ 519 static int 520 tavor_agent_register_all(tavor_state_t *state) 521 { 522 tavor_agent_list_t *curr; 523 ibmf_register_info_t ibmf_reg; 524 ibmf_impl_caps_t impl_caps; 525 ib_guid_t nodeguid; 526 int i, status, num_registered; 527 528 TAVOR_TNF_ENTER(tavor_agent_register_all); 529 530 /* Get the Tavor NodeGUID from the softstate */ 531 nodeguid = state->ts_ibtfinfo.hca_attr->hca_node_guid; 532 533 /* 534 * Register each of the agents with the IBMF (and add callbacks for 535 * each to the tavor_agent_request_cb() routine). Note: If we 536 * fail somewhere along the line here, we attempt to cleanup as much 537 * of the mess as we can and then jump to tavor_agent_unregister_all() 538 * to cleanup the rest. 539 */ 540 num_registered = 0; 541 for (i = 0; i < state->ts_num_agents; i++) { 542 543 /* Register each agent with the IBMF */ 544 curr = &state->ts_agents[i]; 545 ibmf_reg.ir_ci_guid = nodeguid; 546 ibmf_reg.ir_port_num = curr->agl_port; 547 ibmf_reg.ir_client_class = curr->agl_mgmtclass; 548 status = ibmf_register(&ibmf_reg, IBMF_VERSION, 0, 549 NULL, NULL, &curr->agl_ibmfhdl, &impl_caps); 550 if (status != IBMF_SUCCESS) { 551 TNF_PROBE_0(tavor_agent_register_all_ibmf_reg_fail, 552 TAVOR_TNF_ERROR, ""); 553 goto agents_reg_fail; 554 } 555 556 /* Setup callbacks with the IBMF */ 557 status = ibmf_setup_async_cb(curr->agl_ibmfhdl, 558 IBMF_QP_HANDLE_DEFAULT, tavor_agent_request_cb, curr, 0); 559 if (status != IBMF_SUCCESS) { 560 (void) ibmf_unregister(&curr->agl_ibmfhdl, 0); 561 TNF_PROBE_0(tavor_agent_register_all_ibmf_cb_fail, 562 TAVOR_TNF_ERROR, ""); 563 goto agents_reg_fail; 564 } 565 num_registered++; 566 } 567 568 TAVOR_TNF_EXIT(tavor_agent_register_all); 569 return (DDI_SUCCESS); 570 571 agents_reg_fail: 572 (void) tavor_agent_unregister_all(state, num_registered); 573 TAVOR_TNF_EXIT(tavor_agent_register_all); 574 return (DDI_FAILURE); 575 } 576 577 578 /* 579 * tavor_agent_unregister_all() 580 * Context: Only called from detach() path context 581 */ 582 static int 583 tavor_agent_unregister_all(tavor_state_t *state, int num_reg) 584 { 585 tavor_agent_list_t *curr; 586 int i, status; 587 588 TAVOR_TNF_ENTER(tavor_agent_unregister_all); 589 590 /* 591 * For each registered agent in the agent list, teardown the 592 * callbacks from the IBMF and unregister. 593 */ 594 for (i = 0; i < num_reg; i++) { 595 curr = &state->ts_agents[i]; 596 597 /* Teardown the IBMF callback */ 598 status = ibmf_tear_down_async_cb(curr->agl_ibmfhdl, 599 IBMF_QP_HANDLE_DEFAULT, 0); 600 if (status != IBMF_SUCCESS) { 601 TNF_PROBE_0(tavor_agents_unreg_teardown_cb_fail, 602 TAVOR_TNF_ERROR, ""); 603 TAVOR_TNF_EXIT(tavor_agent_unregister_all); 604 return (DDI_FAILURE); 605 } 606 607 /* Unregister the agent from the IBMF */ 608 status = ibmf_unregister(&curr->agl_ibmfhdl, 0); 609 if (status != IBMF_SUCCESS) { 610 TNF_PROBE_0(tavor_agents_unreg_ibmf_fail, 611 TAVOR_TNF_ERROR, ""); 612 TAVOR_TNF_EXIT(tavor_agent_unregister_all); 613 return (DDI_FAILURE); 614 } 615 } 616 617 TAVOR_TNF_EXIT(tavor_agent_unregister_all); 618 return (DDI_SUCCESS); 619 } 620 621 622 /* 623 * tavor_agent_mad_resp_handling() 624 * Context: Called with priority of taskQ thread 625 */ 626 /* ARGSUSED */ 627 static void 628 tavor_agent_mad_resp_handling(tavor_state_t *state, ibmf_msg_t *msgp, 629 uint_t port) 630 { 631 ib_mad_hdr_t *rmadhdrp = msgp->im_msgbufs_recv.im_bufs_mad_hdr; 632 ib_mad_hdr_t *smadhdrp = msgp->im_msgbufs_send.im_bufs_mad_hdr; 633 uint_t hop_count, hop_point; 634 uchar_t *resp, *ret_path; 635 636 resp = (uchar_t *)msgp->im_msgbufs_send.im_bufs_cl_data; 637 638 /* 639 * Handle directed route MADs as a special case. Tavor firmware 640 * does not update the "direction" bit, "hop pointer", "Return 641 * Path" or, in fact, any of the "directed route" parameters. So 642 * the responsibility falls on Tavor driver software to inspect the 643 * MADs and update those fields as appropriate (see section 14.2.2 644 * of the IBA specification, rev 1.1) 645 */ 646 if (TAVOR_MAD_IS_DR(rmadhdrp)) { 647 648 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*((sm_dr_mad_hdr_t *)rmadhdrp))) 649 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*((sm_dr_mad_hdr_t *)smadhdrp))) 650 651 /* 652 * Set the "Direction" bit to one. This indicates that this 653 * is now directed route response 654 */ 655 TAVOR_DRMAD_SET_DIRECTION(rmadhdrp); 656 657 /* Extract the "hop pointer" and "hop count" from the MAD */ 658 hop_count = TAVOR_DRMAD_GET_HOPCOUNT(rmadhdrp); 659 hop_point = TAVOR_DRMAD_GET_HOPPOINTER(rmadhdrp); 660 661 /* Append the port we came in on to the "Return Path" */ 662 if ((hop_count != 0) && ((hop_point == hop_count) || 663 (hop_point == hop_count + 1))) { 664 ret_path = &resp[TAVOR_DRMAD_RETURN_PATH_OFFSET]; 665 ret_path[hop_point] = port; 666 } 667 668 /* Then increment the "hop pointer" in the MAD */ 669 hop_point++; 670 TAVOR_DRMAD_SET_HOPPOINTER(smadhdrp, hop_point); 671 } 672 } 673