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