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 }