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 215 /* Fill in the callback args */ 216 cb_args->ahd_ibmfhdl = ibmf_handle; 217 cb_args->ahd_ibmfmsg = msgp; 218 cb_args->ahd_agentlist = args; 219 220 /* 221 * Dispatch the message to the task queue. Note: Just like above, 222 * if this request fails for any reason then make sure to free up 223 * the IBMF message and then return 224 */ 225 status = ddi_taskq_dispatch(state->ts_taskq_agents, 226 tavor_agent_handle_req, cb_args, DDI_NOSLEEP); 227 if (status == DDI_FAILURE) { 228 kmem_free(cb_args, sizeof (tavor_agent_handler_arg_t)); 229 ibmf_status = ibmf_free_msg(ibmf_handle, &msgp); 230 if (ibmf_status != IBMF_SUCCESS) { 231 TNF_PROBE_1(tavor_agent_request_cb_ibmf_free_msg_fail, 232 TAVOR_TNF_ERROR, "", tnf_uint, ibmf_status, 233 ibmf_status); 234 } 235 TNF_PROBE_0(tavor_agent_request_cb_taskq_fail, 236 TAVOR_TNF_ERROR, ""); 237 } 238 TAVOR_TNF_EXIT(tavor_agent_request_cb); 239 } 240 241 /* 242 * tavor_agent_handle_req() 243 * Context: Called with priority of taskQ thread 244 */ 245 static void 246 tavor_agent_handle_req(void *cb_args) 247 { 248 tavor_agent_handler_arg_t *agent_args; 249 tavor_agent_list_t *curr; 250 tavor_state_t *state; 251 ibmf_handle_t ibmf_handle; 252 ibmf_msg_t *msgp; 253 ibmf_msg_bufs_t *recv_msgbufp; 254 ibmf_msg_bufs_t *send_msgbufp; 255 ibmf_retrans_t retrans; 256 uint_t port; 257 int status; 258 259 TAVOR_TNF_ENTER(tavor_agent_handle_req); 260 261 /* Extract the necessary info from the callback args parameter */ 262 agent_args = (tavor_agent_handler_arg_t *)cb_args; 263 ibmf_handle = agent_args->ahd_ibmfhdl; 264 msgp = agent_args->ahd_ibmfmsg; 265 curr = agent_args->ahd_agentlist; 266 state = curr->agl_state; 267 port = curr->agl_port; 268 269 /* 270 * Set the message send buffer pointers to the message receive buffer 271 * pointers to reuse the IBMF provided buffers for the sender 272 * information. 273 */ 274 recv_msgbufp = &msgp->im_msgbufs_recv; 275 send_msgbufp = &msgp->im_msgbufs_send; 276 bcopy(recv_msgbufp, send_msgbufp, sizeof (ibmf_msg_bufs_t)); 277 278 /* 279 * Check if the incoming packet is a special "Tavor Trap" MAD. If it 280 * is, then do the special handling. If it isn't, then simply pass it 281 * on to the firmware and forward the response back to the IBMF. 282 * 283 * Note: Tavor has a unique method for handling internally generated 284 * Traps. All internally detected/generated Trap messages are 285 * automatically received by the IBMF (as receive completions on QP0), 286 * which (because all Tavor Trap MADs have SLID == 0) detects it as a 287 * special "Tavor Trap" and forwards it here to the driver's SMA. 288 * It is then our responsibility here to fill in the Trap MAD's DLID 289 * for forwarding to the real Master SM (as programmed in the port's 290 * PortInfo.MasterSMLID field.) 291 */ 292 if (TAVOR_IS_SPECIAL_TRAP_MAD(msgp)) { 293 msgp->im_local_addr.ia_remote_lid = 294 TAVOR_PORT_MASTERSMLID_GET(state, port - 1); 295 } else { 296 /* 297 * Post the command to the firmware (using the MAD_IFC 298 * command). Note: We also reuse the command that was passed 299 * in. We pass the pointer to the original MAD payload as if 300 * it were both the source of the incoming MAD as well as the 301 * destination for the response. This is acceptable and saves 302 * us the step of one additional copy. Note: If this command 303 * fails for any reason other than TAVOR_CMD_BAD_PKT, it 304 * probably indicates a serious problem. 305 */ 306 status = tavor_mad_ifc_cmd_post(state, port, 307 TAVOR_CMD_SLEEP_NOSPIN, 308 (uint32_t *)recv_msgbufp->im_bufs_mad_hdr, 309 (uint32_t *)send_msgbufp->im_bufs_mad_hdr); 310 if (status != TAVOR_CMD_SUCCESS) { 311 if ((status != TAVOR_CMD_BAD_PKT) && 312 (status != TAVOR_CMD_INSUFF_RSRC)) { 313 cmn_err(CE_CONT, "Tavor: MAD_IFC (port %02d) " 314 "command failed: %08x\n", port, status); 315 TNF_PROBE_1(tavor_agent_handle_req_madifc_fail, 316 TAVOR_TNF_ERROR, "", tnf_uint, cmd_status, 317 status); 318 } 319 320 /* finish cleanup */ 321 goto tavor_agent_handle_req_skip_response; 322 } 323 } 324 325 /* 326 * If incoming MAD was "TrapRepress", then no response is necessary. 327 * Free the IBMF message and return. 328 */ 329 if (TAVOR_IS_TRAP_REPRESS_MAD(msgp)) { 330 goto tavor_agent_handle_req_skip_response; 331 } 332 333 /* 334 * Modify the response MAD as necessary (for any special cases). 335 * Specifically, if this MAD was a directed route MAD, then some 336 * additional packet manipulation may be necessary because the Tavor 337 * firmware does not do all the required steps to respond to the 338 * MAD. 339 */ 340 tavor_agent_mad_resp_handling(state, msgp, port); 341 342 /* 343 * Send response (or forwarded "Trap" MAD) back to IBMF. We use the 344 * "response callback" to indicate when it is appropriate (later) to 345 * free the IBMF msg. 346 */ 347 status = ibmf_msg_transport(ibmf_handle, IBMF_QP_HANDLE_DEFAULT, 348 msgp, &retrans, tavor_agent_response_cb, state, 0); 349 if (status != IBMF_SUCCESS) { 350 TNF_PROBE_1(tavor_ibmf_send_msg_fail, TAVOR_TNF_ERROR, "", 351 tnf_uint, ibmf_status, status); 352 goto tavor_agent_handle_req_skip_response; 353 } 354 355 /* Free up the callback args parameter */ 356 kmem_free(agent_args, sizeof (tavor_agent_handler_arg_t)); 357 TAVOR_TNF_EXIT(tavor_agent_handle_req); 358 return; 359 360 tavor_agent_handle_req_skip_response: 361 /* Free up the ibmf message */ 362 status = ibmf_free_msg(ibmf_handle, &msgp); 363 if (status != IBMF_SUCCESS) { 364 TNF_PROBE_1(tavor_agent_handle_req_ibmf_free_msg_fail, 365 TAVOR_TNF_ERROR, "", tnf_uint, ibmf_status, 366 status); 367 } 368 /* Free up the callback args parameter */ 369 kmem_free(agent_args, sizeof (tavor_agent_handler_arg_t)); 370 TAVOR_TNF_EXIT(tavor_agent_handle_req); 371 } 372 373 374 /* 375 * tavor_agent_response_cb() 376 * Context: Called from the IBMF context 377 */ 378 /* ARGSUSED */ 379 static void 380 tavor_agent_response_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, 381 void *args) 382 { 383 int status; 384 385 TAVOR_TNF_ENTER(tavor_agent_response_cb); 386 387 /* 388 * It is the responsibility of each IBMF callback recipient to free 389 * the packets that it has been given. Now that we are in the 390 * response callback, we can be assured that it is safe to do so. 391 */ 392 status = ibmf_free_msg(ibmf_handle, &msgp); 393 if (status != IBMF_SUCCESS) { 394 TNF_PROBE_1(tavor_agent_response_cb_ibmf_free_msg_fail, 395 TAVOR_TNF_ERROR, "", tnf_uint, ibmf_status, status); 396 } 397 398 TAVOR_TNF_EXIT(tavor_agent_response_cb); 399 } 400 401 402 /* 403 * tavor_agent_list_init() 404 * Context: Only called from attach() path context 405 */ 406 static int 407 tavor_agent_list_init(tavor_state_t *state) 408 { 409 tavor_agent_list_t *curr; 410 uint_t num_ports, num_agents, num_agents_per_port; 411 uint_t num_sma_agents = 0; 412 uint_t num_pma_agents = 0; 413 uint_t num_bma_agents = 0; 414 uint_t do_qp0, do_qp1; 415 int i, j, indx; 416 417 TAVOR_TNF_ENTER(tavor_agent_list_init); 418 419 /* 420 * Calculate the number of registered agents for each port 421 * (SMA, PMA, and BMA) and determine whether or not to register 422 * a given agent with the IBMF (or whether to let the Tavor firmware 423 * handle it) 424 */ 425 num_ports = state->ts_cfg_profile->cp_num_ports; 426 num_agents = 0; 427 num_agents_per_port = 0; 428 do_qp0 = state->ts_cfg_profile->cp_qp0_agents_in_fw; 429 do_qp1 = state->ts_cfg_profile->cp_qp1_agents_in_fw; 430 if (do_qp0 == 0) { 431 num_agents += (num_ports * TAVOR_NUM_QP0_AGENTS_PER_PORT); 432 num_agents_per_port += TAVOR_NUM_QP0_AGENTS_PER_PORT; 433 num_sma_agents = num_ports; 434 } 435 if (do_qp1 == 0) { 436 num_agents += (num_ports * TAVOR_NUM_QP1_AGENTS_PER_PORT); 437 num_agents_per_port += TAVOR_NUM_QP1_AGENTS_PER_PORT; 438 num_pma_agents = num_ports; 439 /* 440 * The following line is commented out because the Tavor 441 * firmware does not currently support a BMA. If it did, 442 * then we would want to register the agent with the IBMF. 443 * (We would also need to have TAVOR_NUM_QP1_AGENTS_PER_PORT 444 * set to 2, instead of 1.) 445 * 446 * num_bma_agents = num_ports; 447 */ 448 } 449 450 state->ts_num_agents = num_agents; 451 452 /* 453 * Allocate the memory for all of the agent list entries 454 */ 455 state->ts_agents = (tavor_agent_list_t *)kmem_zalloc(num_agents * 456 sizeof (tavor_agent_list_t), KM_SLEEP); 457 if (state->ts_agents == NULL) { 458 TNF_PROBE_0(tavor_agent_list_init_kma_fail, 459 TAVOR_TNF_ERROR, ""); 460 TAVOR_TNF_EXIT(tavor_agent_list_init); 461 return (DDI_FAILURE); 462 } 463 464 /* 465 * Fill in each of the agent list entries with the agent's 466 * MgmtClass, port number, and Tavor softstate pointer 467 */ 468 indx = 0; 469 for (i = 0; i < num_agents_per_port; i++) { 470 for (j = 0; j < num_ports; j++) { 471 curr = &state->ts_agents[indx]; 472 curr->agl_state = state; 473 curr->agl_port = j + 1; 474 475 if ((do_qp0 == 0) && num_sma_agents) { 476 curr->agl_mgmtclass = SUBN_AGENT; 477 num_sma_agents--; 478 indx++; 479 } else if ((do_qp1 == 0) && (num_pma_agents)) { 480 curr->agl_mgmtclass = PERF_AGENT; 481 num_pma_agents--; 482 indx++; 483 } else if ((do_qp1 == 0) && (num_bma_agents)) { 484 curr->agl_mgmtclass = BM_AGENT; 485 num_bma_agents--; 486 indx++; 487 } 488 } 489 } 490 491 TAVOR_TNF_EXIT(tavor_agent_list_init); 492 return (DDI_SUCCESS); 493 } 494 495 496 /* 497 * tavor_agent_list_fini() 498 * Context: Only called from attach() and/or detach() path contexts 499 */ 500 static void 501 tavor_agent_list_fini(tavor_state_t *state) 502 { 503 TAVOR_TNF_ENTER(tavor_agent_list_fini); 504 505 /* Free up the memory for the agent list entries */ 506 kmem_free(state->ts_agents, 507 state->ts_num_agents * sizeof (tavor_agent_list_t)); 508 509 TAVOR_TNF_EXIT(tavor_agent_list_fini); 510 } 511 512 513 /* 514 * tavor_agent_register_all() 515 * Context: Only called from attach() path context 516 */ 517 static int 518 tavor_agent_register_all(tavor_state_t *state) 519 { 520 tavor_agent_list_t *curr; 521 ibmf_register_info_t ibmf_reg; 522 ibmf_impl_caps_t impl_caps; 523 ib_guid_t nodeguid; 524 int i, status, num_registered; 525 526 TAVOR_TNF_ENTER(tavor_agent_register_all); 527 528 /* Get the Tavor NodeGUID from the softstate */ 529 nodeguid = state->ts_ibtfinfo.hca_attr->hca_node_guid; 530 531 /* 532 * Register each of the agents with the IBMF (and add callbacks for 533 * each to the tavor_agent_request_cb() routine). Note: If we 534 * fail somewhere along the line here, we attempt to cleanup as much 535 * of the mess as we can and then jump to tavor_agent_unregister_all() 536 * to cleanup the rest. 537 */ 538 num_registered = 0; 539 for (i = 0; i < state->ts_num_agents; i++) { 540 541 /* Register each agent with the IBMF */ 542 curr = &state->ts_agents[i]; 543 ibmf_reg.ir_ci_guid = nodeguid; 544 ibmf_reg.ir_port_num = curr->agl_port; 545 ibmf_reg.ir_client_class = curr->agl_mgmtclass; 546 status = ibmf_register(&ibmf_reg, IBMF_VERSION, 0, 547 NULL, NULL, &curr->agl_ibmfhdl, &impl_caps); 548 if (status != IBMF_SUCCESS) { 549 TNF_PROBE_0(tavor_agent_register_all_ibmf_reg_fail, 550 TAVOR_TNF_ERROR, ""); 551 goto agents_reg_fail; 552 } 553 554 /* Setup callbacks with the IBMF */ 555 status = ibmf_setup_async_cb(curr->agl_ibmfhdl, 556 IBMF_QP_HANDLE_DEFAULT, tavor_agent_request_cb, curr, 0); 557 if (status != IBMF_SUCCESS) { 558 (void) ibmf_unregister(&curr->agl_ibmfhdl, 0); 559 TNF_PROBE_0(tavor_agent_register_all_ibmf_cb_fail, 560 TAVOR_TNF_ERROR, ""); 561 goto agents_reg_fail; 562 } 563 num_registered++; 564 } 565 566 TAVOR_TNF_EXIT(tavor_agent_register_all); 567 return (DDI_SUCCESS); 568 569 agents_reg_fail: 570 (void) tavor_agent_unregister_all(state, num_registered); 571 TAVOR_TNF_EXIT(tavor_agent_register_all); 572 return (DDI_FAILURE); 573 } 574 575 576 /* 577 * tavor_agent_unregister_all() 578 * Context: Only called from detach() path context 579 */ 580 static int 581 tavor_agent_unregister_all(tavor_state_t *state, int num_reg) 582 { 583 tavor_agent_list_t *curr; 584 int i, status; 585 586 TAVOR_TNF_ENTER(tavor_agent_unregister_all); 587 588 /* 589 * For each registered agent in the agent list, teardown the 590 * callbacks from the IBMF and unregister. 591 */ 592 for (i = 0; i < num_reg; i++) { 593 curr = &state->ts_agents[i]; 594 595 /* Teardown the IBMF callback */ 596 status = ibmf_tear_down_async_cb(curr->agl_ibmfhdl, 597 IBMF_QP_HANDLE_DEFAULT, 0); 598 if (status != IBMF_SUCCESS) { 599 TNF_PROBE_0(tavor_agents_unreg_teardown_cb_fail, 600 TAVOR_TNF_ERROR, ""); 601 TAVOR_TNF_EXIT(tavor_agent_unregister_all); 602 return (DDI_FAILURE); 603 } 604 605 /* Unregister the agent from the IBMF */ 606 status = ibmf_unregister(&curr->agl_ibmfhdl, 0); 607 if (status != IBMF_SUCCESS) { 608 TNF_PROBE_0(tavor_agents_unreg_ibmf_fail, 609 TAVOR_TNF_ERROR, ""); 610 TAVOR_TNF_EXIT(tavor_agent_unregister_all); 611 return (DDI_FAILURE); 612 } 613 } 614 615 TAVOR_TNF_EXIT(tavor_agent_unregister_all); 616 return (DDI_SUCCESS); 617 } 618 619 620 /* 621 * tavor_agent_mad_resp_handling() 622 * Context: Called with priority of taskQ thread 623 */ 624 /* ARGSUSED */ 625 static void 626 tavor_agent_mad_resp_handling(tavor_state_t *state, ibmf_msg_t *msgp, 627 uint_t port) 628 { 629 ib_mad_hdr_t *rmadhdrp = msgp->im_msgbufs_recv.im_bufs_mad_hdr; 630 ib_mad_hdr_t *smadhdrp = msgp->im_msgbufs_send.im_bufs_mad_hdr; 631 uint_t hop_count, hop_point; 632 uchar_t *resp, *ret_path; 633 634 resp = (uchar_t *)msgp->im_msgbufs_send.im_bufs_cl_data; 635 636 /* 637 * Handle directed route MADs as a special case. Tavor firmware 638 * does not update the "direction" bit, "hop pointer", "Return 639 * Path" or, in fact, any of the "directed route" parameters. So 640 * the responsibility falls on Tavor driver software to inspect the 641 * MADs and update those fields as appropriate (see section 14.2.2 642 * of the IBA specification, rev 1.1) 643 */ 644 if (TAVOR_MAD_IS_DR(rmadhdrp)) { 645 /* 646 * Set the "Direction" bit to one. This indicates that this 647 * is now directed route response 648 */ 649 TAVOR_DRMAD_SET_DIRECTION(rmadhdrp); 650 651 /* Extract the "hop pointer" and "hop count" from the MAD */ 652 hop_count = TAVOR_DRMAD_GET_HOPCOUNT(rmadhdrp); 653 hop_point = TAVOR_DRMAD_GET_HOPPOINTER(rmadhdrp); 654 655 /* Append the port we came in on to the "Return Path" */ 656 if ((hop_count != 0) && ((hop_point == hop_count) || 657 (hop_point == hop_count + 1))) { 658 ret_path = &resp[TAVOR_DRMAD_RETURN_PATH_OFFSET]; 659 ret_path[hop_point] = port; 660 } 661 662 /* Then increment the "hop pointer" in the MAD */ 663 hop_point++; 664 TAVOR_DRMAD_SET_HOPPOINTER(smadhdrp, hop_point); 665 } 666 }