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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * This file implements the callback handler logic common to send and receive
31 #include <sys/ib/mgt/ibmf/ibmf_impl.h>
33 extern int ibmf_trace_level
;
34 extern ibmf_state_t
*ibmf_statep
;
35 extern void ibmf_saa_impl_ibt_async_handler(ibt_async_code_t code
,
36 ibt_async_event_t
*event
);
38 static void ibmf_i_process_completion(ibmf_ci_t
*cip
, ibt_wc_t
*wcp
);
39 static void ibmf_i_callback_clients(ib_guid_t hca_guid
,
40 ibmf_async_event_t evt
);
43 * ibmf_ibt_async_handler():
44 * This function handles asynchronous events detected by the
49 ibmf_ibt_async_handler(void *clnt_private
, ibt_hca_hdl_t hca_hdl
,
50 ibt_async_code_t code
, ibt_async_event_t
*event
)
54 IBMF_TRACE_3(DPRINT_L3
,
55 "ibmf_ibt_async_handler: Code %x HCA GUID %016"PRIx64
" Port %d\n",
56 code
, event
->ev_hca_guid
, event
->ev_port
);
59 * let ibmf_saa know events first hand
61 ibmf_saa_impl_ibt_async_handler(code
, event
);
64 * call client callbacks and then fail if ANY client remains.
66 if (code
== IBT_HCA_DETACH_EVENT
) {
68 ibmf_i_callback_clients(event
->ev_hca_guid
, IBMF_CI_OFFLINE
);
70 mutex_enter(&ibmf_statep
->ibmf_mutex
);
71 cip
= ibmf_statep
->ibmf_ci_list
;
74 mutex_enter(&cip
->ci_mutex
);
76 if (cip
->ci_node_guid
== event
->ev_hca_guid
) {
78 mutex_exit(&cip
->ci_mutex
);
82 mutex_exit(&cip
->ci_mutex
);
88 * found the right ci, check
89 * if any clients are still registered
90 * (Note that if we found the ci, chances are that
91 * it was not released).
93 mutex_enter(&cip
->ci_clients_mutex
);
95 if (cip
->ci_clients
!= NULL
) {
97 IBMF_TRACE_1(DPRINT_L1
,
98 "%s, returning failure\n",
99 "ibmf_ibt_async_handler: Found "
100 "clients still registered.");
102 mutex_exit(&cip
->ci_clients_mutex
);
104 mutex_exit(&ibmf_statep
->ibmf_mutex
);
105 } else if (code
== IBT_EVENT_SQD
) {
107 ibt_qp_hdl_t qphdl
= (ibt_qp_hdl_t
)event
->ev_chan_hdl
;
108 ibmf_alt_qp_t
*altqpp
;
109 boolean_t found
= B_FALSE
;
111 mutex_enter(&ibmf_statep
->ibmf_mutex
);
113 cip
= ibmf_statep
->ibmf_ci_list
;
116 * An SQD event is received. We match the QP handle provided
117 * with all the alternate QP handles maintained on the lists
118 * of all the CI contexts. If a match is found, we wake
119 * up the thread waiting in ibmf_modify_qp().
121 while (cip
!= NULL
) {
122 mutex_enter(&cip
->ci_mutex
);
123 altqpp
= cip
->ci_alt_qp_list
;
124 while (altqpp
!= NULL
) {
125 if (altqpp
->isq_qp_handle
== qphdl
) {
126 mutex_enter(&altqpp
->isq_mutex
);
127 cv_signal(&altqpp
->isq_sqd_cv
);
128 mutex_exit(&altqpp
->isq_mutex
);
132 altqpp
= altqpp
->isq_next
;
134 mutex_exit(&cip
->ci_mutex
);
141 mutex_exit(&ibmf_statep
->ibmf_mutex
);
144 IBMF_TRACE_1(DPRINT_L1
, "%s, ignoring event\n",
145 "ibmf_ibt_async_handler: SQD "
146 "event for unknown QP received");
149 IBMF_TRACE_0(DPRINT_L3
, "ibmf_ibt_async_handler: exit.\n");
153 * ibmf_i_callback_clients():
154 * Finds the ci given in parameter.
155 * Calls the client callbacks with the event given in parameter.
156 * Note that client callbacks are called with all ibmf mutexes unlocked.
159 ibmf_i_callback_clients(ib_guid_t hca_guid
, ibmf_async_event_t evt
)
162 ibmf_client_t
*clientp
;
165 ibmf_async_event_cb_t
*cb_array
= NULL
;
166 void **cb_args_array
= NULL
;
167 ibmf_handle_t
*client_array
= NULL
;
170 IBMF_TRACE_0(DPRINT_L3
, "ibmf_i_callback_clients() enter\n");
173 mutex_enter(&ibmf_statep
->ibmf_mutex
);
174 cip
= ibmf_statep
->ibmf_ci_list
;
176 while (cip
!= NULL
) {
177 mutex_enter(&cip
->ci_mutex
);
179 if (cip
->ci_node_guid
== hca_guid
) {
180 mutex_exit(&cip
->ci_mutex
);
184 mutex_exit(&cip
->ci_mutex
);
190 IBMF_TRACE_1(DPRINT_L1
,
191 "ibmf_i_callback_clients: ci = %016"PRIx64
"NOT found.\n",
194 mutex_exit(&ibmf_statep
->ibmf_mutex
);
198 /* found the right ci, count clients */
199 mutex_enter(&cip
->ci_clients_mutex
);
201 /* empty counting loop */
202 for (clientp
= cip
->ci_clients
, nclients
= 0; clientp
!= NULL
;
203 clientp
= clientp
->ic_next
, nclients
++)
206 IBMF_TRACE_2(DPRINT_L3
,
207 "ibmf_i_callback_clients: found %d clients, on ci = %016"PRIx64
"\n",
210 /* no clients? bail */
213 mutex_exit(&cip
->ci_clients_mutex
);
214 mutex_exit(&ibmf_statep
->ibmf_mutex
);
218 /* allocate callback, args, and client arrays */
220 cb_array
= kmem_zalloc(
221 nclients
* sizeof (ibmf_async_event_cb_t
), KM_NOSLEEP
);
223 cb_args_array
= kmem_zalloc(
224 nclients
* sizeof (void*), KM_NOSLEEP
);
226 client_array
= kmem_zalloc(
227 nclients
* sizeof (ibmf_handle_t
), KM_NOSLEEP
);
229 if (cb_array
== NULL
|| cb_args_array
== NULL
||
230 client_array
== NULL
) {
232 IBMF_TRACE_1(DPRINT_L1
, "ibmf_i_callback_clients: %s\n",
233 "could not allocate memory for callback arrays");
235 mutex_exit(&cip
->ci_clients_mutex
);
236 mutex_exit(&ibmf_statep
->ibmf_mutex
);
240 /* build callback list */
242 for (clientp
= cip
->ci_clients
, iclient
= 0;
244 clientp
= clientp
->ic_next
, iclient
++) {
246 cb_array
[iclient
] = clientp
->ic_async_cb
;
247 cb_args_array
[iclient
] = clientp
->ic_async_cb_arg
;
248 client_array
[iclient
] = (ibmf_handle_t
)clientp
;
251 mutex_exit(&cip
->ci_clients_mutex
);
252 mutex_exit(&ibmf_statep
->ibmf_mutex
);
255 * All mutex unlocked, call back clients
257 for (iclient
= 0; iclient
< nclients
; iclient
++) {
259 IBMF_TRACE_4(DPRINT_L3
,
260 "ibmf_i_callback_clients: client %d, handle = %016"PRIx64
","
261 " callback = %016"PRIx64
", args = %016"PRIx64
"\n", iclient
,
262 client_array
[iclient
], cb_array
[iclient
],
263 cb_args_array
[iclient
]);
265 if (cb_array
[iclient
] != NULL
)
266 cb_array
[iclient
](client_array
[iclient
],
267 cb_args_array
[iclient
], evt
);
272 if (cb_array
!= NULL
)
273 kmem_free(cb_array
, nclients
* sizeof (ibmf_async_event_cb_t
));
275 if (cb_args_array
!= NULL
)
276 kmem_free(cb_args_array
, nclients
* sizeof (void*));
278 if (client_array
!= NULL
)
279 kmem_free(client_array
, nclients
* sizeof (ibmf_handle_t
));
281 IBMF_TRACE_0(DPRINT_L3
, "ibmf_i_callback_clients: exit.\n");
285 * ibmf_i_mad_completions():
286 * Check for a completion entry on the specified CQ and process it
289 ibmf_i_mad_completions(ibt_cq_hdl_t cq_handle
, void *arg
)
295 IBMF_TRACE_1(DPRINT_L4
,
296 "ibmf_i_mad_completions() enter, cq_hdl = %p\n", cq_handle
);
300 ASSERT(ibmf_cip
!= NULL
);
303 * Pull a completion and process it
306 status
= ibt_poll_cq(cq_handle
, &cqe
, 1, NULL
);
307 ASSERT(status
!= IBT_CQ_HDL_INVALID
&&
308 status
!= IBT_HCA_HDL_INVALID
);
310 * Check if the status is IBT_SUCCESS or IBT_CQ_EMPTY
311 * either which can return from ibt_poll_cq(). In other
312 * cases, log the status for the further investigation.
314 if (status
!= IBT_SUCCESS
) {
315 if (status
!= IBT_CQ_EMPTY
) {
316 cmn_err(CE_NOTE
, "!ibmf_i_mad_completions got "
317 "an error status (0x%x) from ibt_poll_cq.",
323 /* process the completion */
324 ibmf_i_process_completion(ibmf_cip
, &cqe
);
327 (void) ibt_enable_cq_notify(cq_handle
, IBT_NEXT_COMPLETION
);
330 * Look for more completions just in case some came in before
331 * we were able to reenable CQ notification
334 status
= ibt_poll_cq(cq_handle
, &cqe
, 1, NULL
);
335 ASSERT(status
!= IBT_CQ_HDL_INVALID
&&
336 status
!= IBT_HCA_HDL_INVALID
);
338 * Check if the status is IBT_SUCCESS or IBT_CQ_EMPTY
339 * either which can return from ibt_poll_cq(). In other
340 * cases, log the status for the further investigation.
342 if (status
!= IBT_SUCCESS
) {
343 if (status
!= IBT_CQ_EMPTY
) {
344 cmn_err(CE_NOTE
, "!ibmf_i_mad_completions got "
345 "an error status (0x%x) from ibt_poll_cq.",
351 /* process the completion */
352 ibmf_i_process_completion(ibmf_cip
, &cqe
);
357 * ibmf_i_process_completion():
358 * Process the send or receive completion
361 ibmf_i_process_completion(ibmf_ci_t
*cip
, ibt_wc_t
*wcp
)
363 IBMF_TRACE_2(DPRINT_L4
,
364 "ibmf_i_process_completion() enter, cip = %p, wcp = %p\n", cip
,
367 if (IBMF_IS_RECV_WR_ID(wcp
->wc_id
) == B_TRUE
) {
368 /* completion from a receive queue */
369 ibmf_i_handle_recv_completion(cip
, wcp
);
371 /* completion from a send queue */
372 ibmf_i_handle_send_completion(cip
, wcp
);
377 static int ibmf_i_dump_mad_size
= 0x40;
378 static int ibmf_i_dump_wcp_enable
= 0;
382 ibmf_i_dump_wcp(ibmf_ci_t
*cip
, ibt_wc_t
*wcp
, ibmf_recv_wqe_t
*recv_wqep
)
385 char buf
[256], *sptr
;
388 if (ibmf_i_dump_wcp_enable
== 0)
391 printf("wcp: sender lid %x port num %x path bits %x qp %x sl %x\n",
392 wcp
->wc_slid
, recv_wqep
->recv_port_num
, wcp
->wc_path_bits
,
393 wcp
->wc_qpn
, wcp
->wc_sl
);
395 ptr
= (uchar_t
*)((uintptr_t)recv_wqep
->recv_mem
+
399 /* first print multiples of 16bytes */
400 for (i
= ibmf_i_dump_mad_size
; i
>= 16; i
-= 16) {
401 for (sptr
= buf
, j
= 0; j
< 16; j
++) {
402 (void) sprintf(sptr
, "%02x ", *ptr
++);
403 sptr
+= 3; /* 2 digits + space */
409 for (sptr
= buf
, j
= 0; j
< i
; j
++) {
410 (void) sprintf(sptr
, "%02x ", *ptr
++);
411 sptr
+= 3; /* 2 digits + space */