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