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 }