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