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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * hermon_agents.c 29 * Hermon 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 Hermon 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/hermon/hermon.h> 43 #include <sys/ib/mgt/ibmf/ibmf.h> 44 #include <sys/disp.h> 45 46 static void hermon_agent_request_cb(ibmf_handle_t ibmf_handle, 47 ibmf_msg_t *msgp, void *args); 48 static void hermon_agent_handle_req(void *cb_args); 49 static void hermon_agent_response_cb(ibmf_handle_t ibmf_handle, 50 ibmf_msg_t *msgp, void *args); 51 static int hermon_agent_list_init(hermon_state_t *state); 52 static void hermon_agent_list_fini(hermon_state_t *state); 53 static int hermon_agent_register_all(hermon_state_t *state); 54 static int hermon_agent_unregister_all(hermon_state_t *state, int num_reg); 55 static void hermon_agent_mad_resp_handling(hermon_state_t *state, 56 ibmf_msg_t *msgp, uint_t port); 57 58 /* 59 * hermon_agent_handlers_init() 60 * Context: Only called from attach() and/or detach() path contexts 61 */ 62 int 63 hermon_agent_handlers_init(hermon_state_t *state) 64 { 65 int status; 66 char *rsrc_name; 67 68 /* Determine if we need to register any agents with the IBMF */ 69 if ((state->hs_cfg_profile->cp_qp0_agents_in_fw) && 70 (state->hs_cfg_profile->cp_qp1_agents_in_fw)) { 71 return (DDI_SUCCESS); 72 } 73 74 /* 75 * Build a unique name for the Hermon task queue from the Hermon driver 76 * instance number and HERMON_TASKQ_NAME 77 */ 78 rsrc_name = (char *)kmem_zalloc(HERMON_RSRC_NAME_MAXLEN, KM_SLEEP); 79 HERMON_RSRC_NAME(rsrc_name, HERMON_TASKQ_NAME); 80 81 /* Initialize the Hermon IB management agent list */ 82 status = hermon_agent_list_init(state); 83 if (status != DDI_SUCCESS) { 84 goto agentsinit_fail; 85 } 86 87 /* 88 * Initialize the agent handling task queue. Note: We set the task 89 * queue priority to the minimum system priority. At this point this 90 * is considered acceptable because MADs are unreliable datagrams 91 * and could get lost (in general) anyway. 92 */ 93 state->hs_taskq_agents = ddi_taskq_create(state->hs_dip, 94 rsrc_name, HERMON_TASKQ_NTHREADS, TASKQ_DEFAULTPRI, 0); 95 if (state->hs_taskq_agents == NULL) { 96 hermon_agent_list_fini(state); 97 goto agentsinit_fail; 98 } 99 100 /* Now attempt to register all of the agents with the IBMF */ 101 status = hermon_agent_register_all(state); 102 if (status != DDI_SUCCESS) { 103 ddi_taskq_destroy(state->hs_taskq_agents); 104 hermon_agent_list_fini(state); 105 goto agentsinit_fail; 106 } 107 108 kmem_free(rsrc_name, HERMON_RSRC_NAME_MAXLEN); 109 return (DDI_SUCCESS); 110 111 agentsinit_fail: 112 kmem_free(rsrc_name, HERMON_RSRC_NAME_MAXLEN); 113 return (status); 114 } 115 116 117 /* 118 * hermon_agent_handlers_fini() 119 * Context: Only called from detach() path context 120 */ 121 int 122 hermon_agent_handlers_fini(hermon_state_t *state) 123 { 124 int status; 125 126 /* Determine if we need to unregister any agents from the IBMF */ 127 if ((state->hs_cfg_profile->cp_qp0_agents_in_fw) && 128 (state->hs_cfg_profile->cp_qp1_agents_in_fw)) { 129 return (DDI_SUCCESS); 130 } 131 132 /* Now attempt to unregister all of the agents from the IBMF */ 133 status = hermon_agent_unregister_all(state, state->hs_num_agents); 134 if (status != DDI_SUCCESS) { 135 return (DDI_FAILURE); 136 } 137 138 /* 139 * Destroy the task queue. The task queue destroy is guaranteed to 140 * wait until any scheduled tasks have completed. We are able to 141 * guarantee that no _new_ tasks will be added the task queue while 142 * we are in the ddi_taskq_destroy() call because we have 143 * (at this point) successfully unregistered from IBMF (in 144 * hermon_agent_unregister_all() above). 145 */ 146 ddi_taskq_destroy(state->hs_taskq_agents); 147 148 /* Teardown the Hermon IB management agent list */ 149 hermon_agent_list_fini(state); 150 151 return (DDI_SUCCESS); 152 } 153 154 155 /* 156 * hermon_agent_request_cb() 157 * Context: Called from the IBMF context 158 */ 159 static void 160 hermon_agent_request_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, 161 void *args) 162 { 163 hermon_agent_handler_arg_t *cb_args; 164 hermon_agent_list_t *curr; 165 hermon_state_t *state; 166 int status; 167 168 curr = (hermon_agent_list_t *)args; 169 state = curr->agl_state; 170 171 /* 172 * Allocate space to hold the callback args (for passing to the 173 * task queue). Note: If we are unable to allocate space for the 174 * the callback args here, then we just return. But we must ensure 175 * that we call ibmf_free_msg() to free up the message. 176 */ 177 cb_args = (hermon_agent_handler_arg_t *)kmem_zalloc( 178 sizeof (hermon_agent_handler_arg_t), KM_NOSLEEP); 179 if (cb_args == NULL) { 180 (void) ibmf_free_msg(ibmf_handle, &msgp); 181 return; 182 } 183 184 /* Fill in the callback args */ 185 cb_args->ahd_ibmfhdl = ibmf_handle; 186 cb_args->ahd_ibmfmsg = msgp; 187 cb_args->ahd_agentlist = args; 188 189 /* 190 * Dispatch the message to the task queue. Note: Just like above, 191 * if this request fails for any reason then make sure to free up 192 * the IBMF message and then return 193 */ 194 status = ddi_taskq_dispatch(state->hs_taskq_agents, 195 hermon_agent_handle_req, cb_args, DDI_NOSLEEP); 196 if (status == DDI_FAILURE) { 197 kmem_free(cb_args, sizeof (hermon_agent_handler_arg_t)); 198 (void) ibmf_free_msg(ibmf_handle, &msgp); 199 } 200 } 201 202 /* 203 * hermon_get_smlid() 204 * Simple helper function for hermon_agent_handle_req() below. 205 * Get the portinfo and extract the smlid. 206 */ 207 static ib_lid_t 208 hermon_get_smlid(hermon_state_t *state, uint_t port) 209 { 210 sm_portinfo_t portinfo; 211 int status; 212 213 status = hermon_getportinfo_cmd_post(state, port, 214 HERMON_SLEEPFLAG_FOR_CONTEXT(), &portinfo); 215 if (status != HERMON_CMD_SUCCESS) { 216 cmn_err(CE_CONT, "Hermon: GetPortInfo (port %02d) command " 217 "failed: %08x\n", port, status); 218 return (0); 219 } 220 return (portinfo.MasterSMLID); 221 } 222 223 /* 224 * hermon_get_port_change_flags() 225 * Helper function to determine the changes in the incoming MAD's portinfo 226 * for the Port Change event. 227 */ 228 static ibt_port_change_t 229 hermon_port_change_flags(sm_portinfo_t *curpinfo, sm_portinfo_t *madpinfo) 230 { 231 int SMDisabled, ReregSuppd; 232 ibt_port_change_t flags = 0; 233 234 SMDisabled = curpinfo->CapabilityMask & SM_CAP_MASK_IS_SM_DISABLED; 235 ReregSuppd = curpinfo->CapabilityMask & SM_CAP_MASK_IS_CLNT_REREG_SUPPD; 236 237 if (curpinfo->MasterSMLID != madpinfo->MasterSMLID) { 238 flags |= IBT_PORT_CHANGE_SM_LID; 239 } 240 if (curpinfo->MasterSMSL != madpinfo->MasterSMSL) { 241 flags |= IBT_PORT_CHANGE_SM_SL; 242 } 243 if (curpinfo->SubnetTimeOut != madpinfo->SubnetTimeOut) { 244 flags |= IBT_PORT_CHANGE_SUB_TIMEOUT; 245 } 246 if ((madpinfo->CapabilityMask & SM_CAP_MASK_IS_SM_DISABLED) 247 ^ SMDisabled) { 248 flags |= IBT_PORT_CHANGE_SM_FLAG; 249 } 250 if ((madpinfo->CapabilityMask & SM_CAP_MASK_IS_CLNT_REREG_SUPPD) 251 ^ ReregSuppd) { 252 flags |= IBT_PORT_CHANGE_REREG; 253 } 254 return (flags); 255 } 256 257 int 258 hermon_set_port_capability(hermon_state_t *state, uint8_t port, 259 sm_portinfo_t *portinfo, ibt_port_change_t flags) 260 { 261 uint32_t capmask; 262 int status; 263 hermon_hw_set_port_t set_port; 264 265 bzero(&set_port, sizeof (set_port)); 266 267 /* Validate that specified port number is legal */ 268 if (!hermon_portnum_is_valid(state, port)) { 269 return (IBT_HCA_PORT_INVALID); 270 } 271 272 /* 273 * Convert InfiniBand-defined port capability flags to the format 274 * specified by the IBTF. Specifically, we modify the capability 275 * mask based on the specified values. 276 */ 277 capmask = portinfo->CapabilityMask; 278 279 if (flags & IBT_PORT_CHANGE_SM_FLAG) 280 capmask ^= SM_CAP_MASK_IS_SM; 281 282 if (flags & IBT_PORT_CHANGE_REREG) 283 capmask ^= SM_CAP_MASK_IS_CLNT_REREG_SUPPD; 284 set_port.cap_mask = capmask; 285 286 /* 287 * Use the Hermon SET_PORT command to update the capability mask and 288 * (possibly) reset the QKey violation counter for the specified port. 289 * Note: In general, this operation shouldn't fail. If it does, then 290 * it is an indication that something (probably in HW, but maybe in 291 * SW) has gone seriously wrong. 292 */ 293 status = hermon_set_port_cmd_post(state, &set_port, port, 294 HERMON_SLEEPFLAG_FOR_CONTEXT()); 295 if (status != HERMON_CMD_SUCCESS) { 296 HERMON_WARNING(state, "failed to modify port capabilities"); 297 cmn_err(CE_CONT, "Hermon: SET_IB (port %02d) command failed: " 298 "%08x\n", port, status); 299 return (DDI_FAILURE); 300 } 301 302 return (DDI_SUCCESS); 303 } 304 305 /* 306 * hermon_agent_handle_req() 307 * Context: Called with priority of taskQ thread 308 */ 309 static void 310 hermon_agent_handle_req(void *cb_args) 311 { 312 hermon_agent_handler_arg_t *agent_args; 313 hermon_agent_list_t *curr; 314 ibc_async_event_t event; 315 ibt_async_code_t type, code; 316 sm_portinfo_t curpinfo, tmadpinfo; 317 sm_portinfo_t *madpinfop; 318 hermon_state_t *state; 319 ibmf_handle_t ibmf_handle; 320 ibmf_msg_t *msgp; 321 ibmf_msg_bufs_t *recv_msgbufp; 322 ibmf_msg_bufs_t *send_msgbufp; 323 ib_mad_hdr_t *madhdrp; 324 ibmf_retrans_t retrans; 325 uint_t port; 326 int status; 327 328 /* Extract the necessary info from the callback args parameter */ 329 agent_args = (hermon_agent_handler_arg_t *)cb_args; 330 ibmf_handle = agent_args->ahd_ibmfhdl; 331 msgp = agent_args->ahd_ibmfmsg; 332 curr = agent_args->ahd_agentlist; 333 state = curr->agl_state; 334 port = curr->agl_port; 335 336 /* 337 * Set the message send buffer pointers to the message receive buffer 338 * pointers to reuse the IBMF provided buffers for the sender 339 * information. 340 */ 341 recv_msgbufp = &msgp->im_msgbufs_recv; 342 send_msgbufp = &msgp->im_msgbufs_send; 343 bcopy(recv_msgbufp, send_msgbufp, sizeof (ibmf_msg_bufs_t)); 344 345 /* 346 * Check if the incoming packet is a special "Hermon Trap" MAD. If it 347 * is, then do the special handling. If it isn't, then simply pass it 348 * on to the firmware and forward the response back to the IBMF. 349 * 350 * Note: Hermon has a unique method for handling internally generated 351 * Traps. All internally detected/generated Trap messages are 352 * automatically received by the IBMF (as receive completions on QP0), 353 * which (because all Hermon Trap MADs have SLID == 0) detects it as a 354 * special "Hermon Trap" and forwards it here to the driver's SMA. 355 * It is then our responsibility here to fill in the Trap MAD's DLID 356 * for forwarding to the real Master SM (as programmed in the port's 357 * PortInfo.MasterSMLID field.) 358 */ 359 if (HERMON_IS_SPECIAL_TRAP_MAD(msgp)) { 360 msgp->im_local_addr.ia_remote_lid = 361 hermon_get_smlid(state, port); 362 } else { 363 int isSMSet, isReregSuppd; 364 uint_t attr_id, method, mgmt_class; 365 366 madhdrp = recv_msgbufp->im_bufs_mad_hdr; 367 method = madhdrp->R_Method; 368 attr_id = b2h16(madhdrp->AttributeID); 369 mgmt_class = madhdrp->MgmtClass; 370 371 /* 372 * Is this a Subnet Manager MAD with SET method ? If so 373 * we will have to get the current portinfo to generate 374 * events based on what has changed in portinfo. 375 */ 376 isSMSet = (((mgmt_class == MAD_MGMT_CLASS_SUBN_LID_ROUTED)|| 377 (mgmt_class == MAD_MGMT_CLASS_SUBN_DIRECT_ROUTE)) && 378 (method == MAD_METHOD_SET)); 379 380 /* 381 * Get the current portinfo to compare with the portinfo 382 * received in the MAD for PortChange event. 383 */ 384 if (isSMSet && (attr_id == SM_PORTINFO_ATTRID) || 385 (attr_id == SM_PKEY_TABLE_ATTRID) || 386 (attr_id == SM_GUIDINFO_ATTRID)) { 387 madpinfop = recv_msgbufp->im_bufs_cl_data; 388 tmadpinfo = *madpinfop; 389 HERMON_GETPORTINFO_SWAP(&tmadpinfo); 390 status = hermon_getportinfo_cmd_post(state, port, 391 HERMON_SLEEPFLAG_FOR_CONTEXT(), &curpinfo); 392 if (status != HERMON_CMD_SUCCESS) { 393 cmn_err(CE_CONT, "Hermon: GetPortInfo " 394 "(port %02d) command failed: %08x\n", port, 395 status); 396 goto hermon_agent_handle_req_skip_response; 397 } 398 } 399 400 /* 401 * Post the command to the firmware (using the MAD_IFC 402 * command). Note: We also reuse the command that was passed 403 * in. We pass the pointer to the original MAD payload as if 404 * it were both the source of the incoming MAD as well as the 405 * destination for the response. This is acceptable and saves 406 * us the step of one additional copy. Note: If this command 407 * fails for any reason other than HERMON_CMD_BAD_PKT, it 408 * probably indicates a serious problem. 409 */ 410 status = hermon_mad_ifc_cmd_post(state, port, 411 HERMON_CMD_SLEEP_NOSPIN, 412 (uint32_t *)recv_msgbufp->im_bufs_mad_hdr, 413 (uint32_t *)send_msgbufp->im_bufs_mad_hdr); 414 if (status != HERMON_CMD_SUCCESS) { 415 if ((status != HERMON_CMD_BAD_PKT) && 416 (status != HERMON_CMD_INSUFF_RSRC)) { 417 cmn_err(CE_CONT, "Hermon: MAD_IFC (port %02d) " 418 "command failed: %08x\n", port, status); 419 } 420 421 /* finish cleanup */ 422 goto hermon_agent_handle_req_skip_response; 423 } 424 425 if (isSMSet) { 426 event.ev_port_flags = 0; 427 type = 0; 428 event.ev_port = (uint8_t)port; 429 430 switch (attr_id) { 431 case SM_PORTINFO_ATTRID: 432 /* 433 * This is a SM SET method with portinfo 434 * attribute. If ClientRereg bit was set in 435 * the MADs portinfo this is a REREG event 436 * (see section 14.4.11 in IB Spec 1.2.1). Else 437 * compare the current (before MAD_IFC command) 438 * portinfo with the portinfo in the MAD and 439 * signal PORT_CHANGE event with the proper 440 * ev_port_flags. 441 * 442 */ 443 isReregSuppd = curpinfo.CapabilityMask & 444 SM_CAP_MASK_IS_CLNT_REREG_SUPPD; 445 446 madpinfop = recv_msgbufp->im_bufs_cl_data; 447 if (tmadpinfo.ClientRereg && isReregSuppd) { 448 type |= IBT_CLNT_REREG_EVENT; 449 } 450 451 type |= IBT_PORT_CHANGE_EVENT; 452 event.ev_port_flags = hermon_port_change_flags( 453 &curpinfo, &tmadpinfo); 454 if (event.ev_port_flags & 455 (IBT_PORT_CHANGE_REREG | 456 IBT_PORT_CHANGE_SM_FLAG)) { 457 if (hermon_set_port_capability(state, 458 port, &curpinfo, 459 event.ev_port_flags) 460 != DDI_SUCCESS) { 461 cmn_err(CE_CONT, "HERMON: Port " 462 "%d capability reset " 463 "failed\n", port); 464 } 465 } 466 467 /* 468 * If we have a SMLID change event but 469 * capability mask doesn't have Rereg support 470 * bit set, we have to do the Rereg part too. 471 */ 472 if ((event.ev_port_flags & 473 IBT_PORT_CHANGE_SM_LID) && !isReregSuppd) 474 type |= IBT_CLNT_REREG_EVENT; 475 break; 476 case SM_PKEY_TABLE_ATTRID: 477 type |= IBT_PORT_CHANGE_EVENT; 478 event.ev_port_flags = IBT_PORT_CHANGE_PKEY; 479 break; 480 case SM_GUIDINFO_ATTRID: 481 type |= IBT_PORT_CHANGE_EVENT; 482 event.ev_port_flags = IBT_PORT_CHANGE_SGID; 483 break; 484 default: 485 break; 486 487 } 488 489 /* 490 * NOTE: here we call ibc_async_handler directly without 491 * using the HERMON_DO_IBTF_ASYNC_CALLB, since hermon 492 * can not be unloaded till ibmf_unregiter is done and 493 * this thread (hs_taskq_agents) will be destroyed 494 * before ibmf_uregister is called. 495 * 496 * The hermon event queue based hs_in_evcallb flag 497 * assumes that we will pick one event after another 498 * and dispatch them sequentially. If we use 499 * HERMON_DO_IBTF_ASYNC_CALLB, we will break this 500 * assumption make hs_in_evcallb inconsistent. 501 */ 502 while (type != 0) { 503 if (type & IBT_PORT_CHANGE_EVENT) { 504 code = IBT_PORT_CHANGE_EVENT; 505 type &= ~IBT_PORT_CHANGE_EVENT; 506 } else { 507 code = IBT_CLNT_REREG_EVENT; 508 type = 0; 509 } 510 ibc_async_handler(state->hs_ibtfpriv, code, 511 &event); 512 } 513 } 514 } 515 516 /* 517 * If incoming MAD was "TrapRepress", then no response is necessary. 518 * Free the IBMF message and return. 519 */ 520 if (HERMON_IS_TRAP_REPRESS_MAD(msgp)) { 521 goto hermon_agent_handle_req_skip_response; 522 } 523 524 /* 525 * Modify the response MAD as necessary (for any special cases). 526 * Specifically, if this MAD was a directed route MAD, then some 527 * additional packet manipulation may be necessary because the Hermon 528 * firmware does not do all the required steps to respond to the 529 * MAD. 530 */ 531 hermon_agent_mad_resp_handling(state, msgp, port); 532 533 /* 534 * Send response (or forwarded "Trap" MAD) back to IBMF. We use the 535 * "response callback" to indicate when it is appropriate (later) to 536 * free the IBMF msg. 537 */ 538 status = ibmf_msg_transport(ibmf_handle, IBMF_QP_HANDLE_DEFAULT, 539 msgp, &retrans, hermon_agent_response_cb, state, 0); 540 if (status != IBMF_SUCCESS) { 541 goto hermon_agent_handle_req_skip_response; 542 } 543 544 /* Free up the callback args parameter */ 545 kmem_free(agent_args, sizeof (hermon_agent_handler_arg_t)); 546 return; 547 548 hermon_agent_handle_req_skip_response: 549 /* Free up the ibmf message */ 550 (void) ibmf_free_msg(ibmf_handle, &msgp); 551 552 /* Free up the callback args parameter */ 553 kmem_free(agent_args, sizeof (hermon_agent_handler_arg_t)); 554 } 555 556 557 /* 558 * hermon_agent_response_cb() 559 * Context: Called from the IBMF context 560 */ 561 /* ARGSUSED */ 562 static void 563 hermon_agent_response_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, 564 void *args) 565 { 566 /* 567 * It is the responsibility of each IBMF callback recipient to free 568 * the packets that it has been given. Now that we are in the 569 * response callback, we can be assured that it is safe to do so. 570 */ 571 (void) ibmf_free_msg(ibmf_handle, &msgp); 572 } 573 574 575 /* 576 * hermon_agent_list_init() 577 * Context: Only called from attach() path context 578 */ 579 static int 580 hermon_agent_list_init(hermon_state_t *state) 581 { 582 hermon_agent_list_t *curr; 583 uint_t num_ports, num_agents, num_agents_per_port; 584 uint_t num_sma_agents = 0; 585 uint_t num_pma_agents = 0; 586 uint_t num_bma_agents = 0; 587 uint_t do_qp0, do_qp1; 588 int i, j, indx; 589 590 /* 591 * Calculate the number of registered agents for each port 592 * (SMA, PMA, and BMA) and determine whether or not to register 593 * a given agent with the IBMF (or whether to let the Hermon firmware 594 * handle it) 595 */ 596 num_ports = state->hs_cfg_profile->cp_num_ports; 597 num_agents = 0; 598 num_agents_per_port = 0; 599 do_qp0 = state->hs_cfg_profile->cp_qp0_agents_in_fw; 600 do_qp1 = state->hs_cfg_profile->cp_qp1_agents_in_fw; 601 if (do_qp0 == 0) { 602 num_agents += (num_ports * HERMON_NUM_QP0_AGENTS_PER_PORT); 603 num_agents_per_port += HERMON_NUM_QP0_AGENTS_PER_PORT; 604 num_sma_agents = num_ports; 605 } 606 if (do_qp1 == 0) { 607 num_agents += (num_ports * HERMON_NUM_QP1_AGENTS_PER_PORT); 608 num_agents_per_port += HERMON_NUM_QP1_AGENTS_PER_PORT; 609 num_pma_agents = num_ports; 610 /* 611 * The following line is commented out because the Hermon 612 * firmware does not currently support a BMA. If it did, 613 * then we would want to register the agent with the IBMF. 614 * (We would also need to have HERMON_NUM_QP1_AGENTS_PER_PORT 615 * set to 2, instead of 1.) 616 * 617 * num_bma_agents = num_ports; 618 */ 619 } 620 621 state->hs_num_agents = num_agents; 622 623 /* 624 * Allocate the memory for all of the agent list entries 625 */ 626 state->hs_agents = (hermon_agent_list_t *)kmem_zalloc(num_agents * 627 sizeof (hermon_agent_list_t), KM_SLEEP); 628 if (state->hs_agents == NULL) { 629 return (DDI_FAILURE); 630 } 631 632 /* 633 * Fill in each of the agent list entries with the agent's 634 * MgmtClass, port number, and Hermon softstate pointer 635 */ 636 indx = 0; 637 for (i = 0; i < num_agents_per_port; i++) { 638 for (j = 0; j < num_ports; j++) { 639 curr = &state->hs_agents[indx]; 640 curr->agl_state = state; 641 curr->agl_port = j + 1; 642 643 if ((do_qp0 == 0) && num_sma_agents) { 644 curr->agl_mgmtclass = SUBN_AGENT; 645 num_sma_agents--; 646 indx++; 647 } else if ((do_qp1 == 0) && (num_pma_agents)) { 648 curr->agl_mgmtclass = PERF_AGENT; 649 num_pma_agents--; 650 indx++; 651 } else if ((do_qp1 == 0) && (num_bma_agents)) { 652 curr->agl_mgmtclass = BM_AGENT; 653 num_bma_agents--; 654 indx++; 655 } 656 } 657 } 658 659 return (DDI_SUCCESS); 660 } 661 662 663 /* 664 * hermon_agent_list_fini() 665 * Context: Only called from attach() and/or detach() path contexts 666 */ 667 static void 668 hermon_agent_list_fini(hermon_state_t *state) 669 { 670 /* Free up the memory for the agent list entries */ 671 kmem_free(state->hs_agents, 672 state->hs_num_agents * sizeof (hermon_agent_list_t)); 673 } 674 675 676 /* 677 * hermon_agent_register_all() 678 * Context: Only called from attach() path context 679 */ 680 static int 681 hermon_agent_register_all(hermon_state_t *state) 682 { 683 hermon_agent_list_t *curr; 684 ibmf_register_info_t ibmf_reg; 685 ibmf_impl_caps_t impl_caps; 686 ib_guid_t nodeguid; 687 int i, status, num_registered; 688 689 /* Get the Hermon NodeGUID from the softstate */ 690 nodeguid = state->hs_ibtfinfo.hca_attr->hca_node_guid; 691 692 /* 693 * Register each of the agents with the IBMF (and add callbacks for 694 * each to the hermon_agent_request_cb() routine). Note: If we 695 * fail somewhere along the line here, we attempt to cleanup as much 696 * of the mess as we can and then jump to hermon_agent_unregister_all() 697 * to cleanup the rest. 698 */ 699 num_registered = 0; 700 701 if (state->hs_num_agents == 0) { 702 return (DDI_SUCCESS); 703 } 704 705 for (i = 0; i < state->hs_num_agents; i++) { 706 /* Register each agent with the IBMF */ 707 curr = &state->hs_agents[i]; 708 ibmf_reg.ir_ci_guid = nodeguid; 709 ibmf_reg.ir_port_num = curr->agl_port; 710 ibmf_reg.ir_client_class = curr->agl_mgmtclass; 711 712 status = ibmf_register(&ibmf_reg, IBMF_VERSION, 0, 713 NULL, NULL, &curr->agl_ibmfhdl, &impl_caps); 714 if (status != IBMF_SUCCESS) { 715 goto agents_reg_fail; 716 } 717 718 /* Setup callbacks with the IBMF */ 719 status = ibmf_setup_async_cb(curr->agl_ibmfhdl, 720 IBMF_QP_HANDLE_DEFAULT, hermon_agent_request_cb, curr, 0); 721 if (status != IBMF_SUCCESS) { 722 (void) ibmf_unregister(&curr->agl_ibmfhdl, 0); 723 goto agents_reg_fail; 724 } 725 num_registered++; 726 } 727 728 return (DDI_SUCCESS); 729 730 agents_reg_fail: 731 (void) hermon_agent_unregister_all(state, num_registered); 732 return (DDI_FAILURE); 733 } 734 735 736 /* 737 * hermon_agent_unregister_all() 738 * Context: Only called from detach() path context 739 */ 740 static int 741 hermon_agent_unregister_all(hermon_state_t *state, int num_reg) 742 { 743 hermon_agent_list_t *curr; 744 int i, status; 745 746 if (num_reg == 0) { 747 return (DDI_SUCCESS); 748 } 749 750 /* 751 * For each registered agent in the agent list, teardown the 752 * callbacks from the IBMF and unregister. 753 */ 754 for (i = 0; i < num_reg; i++) { 755 curr = &state->hs_agents[i]; 756 757 /* Teardown the IBMF callback */ 758 status = ibmf_tear_down_async_cb(curr->agl_ibmfhdl, 759 IBMF_QP_HANDLE_DEFAULT, 0); 760 if (status != IBMF_SUCCESS) { 761 return (DDI_FAILURE); 762 } 763 764 /* Unregister the agent from the IBMF */ 765 status = ibmf_unregister(&curr->agl_ibmfhdl, 0); 766 if (status != IBMF_SUCCESS) { 767 return (DDI_FAILURE); 768 } 769 } 770 771 return (DDI_SUCCESS); 772 } 773 774 775 /* 776 * hermon_agent_mad_resp_handling() 777 * Context: Called with priority of taskQ thread 778 */ 779 /* ARGSUSED */ 780 static void 781 hermon_agent_mad_resp_handling(hermon_state_t *state, ibmf_msg_t *msgp, 782 uint_t port) 783 { 784 ib_mad_hdr_t *rmadhdrp = msgp->im_msgbufs_recv.im_bufs_mad_hdr; 785 ib_mad_hdr_t *smadhdrp = msgp->im_msgbufs_send.im_bufs_mad_hdr; 786 uint_t hop_count, hop_point; 787 uchar_t *resp, *ret_path; 788 789 resp = (uchar_t *)msgp->im_msgbufs_send.im_bufs_cl_data; 790 791 /* 792 * Handle directed route MADs as a special case. Hermon firmware 793 * does not update the "direction" bit, "hop pointer", "Return 794 * Path" or, in fact, any of the "directed route" parameters. So 795 * the responsibility falls on Hermon driver software to inspect the 796 * MADs and update those fields as appropriate (see section 14.2.2 797 * of the IBA specification, rev 1.1) 798 */ 799 if (HERMON_MAD_IS_DR(rmadhdrp)) { 800 /* 801 * Set the "Direction" bit to one. This indicates that this 802 * is now directed route response 803 */ 804 HERMON_DRMAD_SET_DIRECTION(rmadhdrp); 805 806 /* Extract the "hop pointer" and "hop count" from the MAD */ 807 hop_count = HERMON_DRMAD_GET_HOPCOUNT(rmadhdrp); 808 hop_point = HERMON_DRMAD_GET_HOPPOINTER(rmadhdrp); 809 810 /* Append the port we came in on to the "Return Path" */ 811 if ((hop_count != 0) && ((hop_point == hop_count) || 812 (hop_point == hop_count + 1))) { 813 ret_path = &resp[HERMON_DRMAD_RETURN_PATH_OFFSET]; 814 ret_path[hop_point] = (uchar_t)port; 815 } 816 817 /* Then increment the "hop pointer" in the MAD */ 818 hop_point++; 819 HERMON_DRMAD_SET_HOPPOINTER(smadhdrp, (uint8_t)hop_point); 820 } 821 }