tavor_agents.c revision 9517:b4839b0aa7a4
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
46static void tavor_agent_request_cb(ibmf_handle_t ibmf_handle,
47    ibmf_msg_t *msgp, void *args);
48static void tavor_agent_handle_req(void *cb_args);
49static void tavor_agent_response_cb(ibmf_handle_t ibmf_handle,
50    ibmf_msg_t *msgp, void *args);
51static int tavor_agent_list_init(tavor_state_t *state);
52static void tavor_agent_list_fini(tavor_state_t *state);
53static int tavor_agent_register_all(tavor_state_t *state);
54static int tavor_agent_unregister_all(tavor_state_t *state, int num_reg);
55static 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 */
62int
63tavor_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
121agentsinit_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 */
134int
135tavor_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 */
179static void
180tavor_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 */
246static void
247tavor_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
362tavor_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 */
381static void
382tavor_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 */
408static int
409tavor_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 */
502static void
503tavor_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 */
519static int
520tavor_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
571agents_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 */
582static int
583tavor_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 */
627static void
628tavor_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}
673