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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * This file implements the callback handler logic common to send and receive
28 * handling in IBMF.
29 */
30
31 #include <sys/ib/mgt/ibmf/ibmf_impl.h>
32
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);
37
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);
41
42 /*
43 * ibmf_ibt_async_handler():
44 * This function handles asynchronous events detected by the
45 * IBT framework.
46 */
47 /* ARGSUSED */
48 void
ibmf_ibt_async_handler(void * clnt_private,ibt_hca_hdl_t hca_hdl,ibt_async_code_t code,ibt_async_event_t * event)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)
51 {
52 ibmf_ci_t *cip;
53
54 IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_ibt_async_handler_start,
55 IBMF_TNF_TRACE, "",
56 "ibmf_ibt_async_handler: Code %x HCA GUID %016" PRIx64 " Port %d\n",
57 tnf_uint, code, code, tnf_opaque, hca_guid, event->ev_hca_guid,
58 tnf_uint, port, event->ev_port);
59
60 /*
61 * let ibmf_saa know events first hand
62 */
63 ibmf_saa_impl_ibt_async_handler(code, event);
64
65 /*
66 * call client callbacks and then fail if ANY client remains.
67 */
68 if (code == IBT_HCA_DETACH_EVENT) {
69
70 ibmf_i_callback_clients(event->ev_hca_guid, IBMF_CI_OFFLINE);
71
72 mutex_enter(&ibmf_statep->ibmf_mutex);
73 cip = ibmf_statep->ibmf_ci_list;
74
75 while (cip != NULL) {
76 mutex_enter(&cip->ci_mutex);
77
78 if (cip->ci_node_guid == event->ev_hca_guid) {
79
80 mutex_exit(&cip->ci_mutex);
81 break;
82 }
83
84 mutex_exit(&cip->ci_mutex);
85 cip = cip->ci_next;
86 }
87
88 if (cip != NULL) {
89 /*
90 * found the right ci, check
91 * if any clients are still registered
92 * (Note that if we found the ci, chances are that
93 * it was not released).
94 */
95 mutex_enter(&cip->ci_clients_mutex);
96
97 if (cip->ci_clients != NULL) {
98
99 IBMF_TRACE_1(IBMF_TNF_NODEBUG,
100 DPRINT_L1, ibmf_ibt_async_handler_err,
101 IBMF_TNF_TRACE, "",
102 "%s, returning failure\n",
103 tnf_string, msg,
104 "ibmf_ibt_async_handler: Found "
105 "clients still registered.");
106 }
107 mutex_exit(&cip->ci_clients_mutex);
108 }
109 mutex_exit(&ibmf_statep->ibmf_mutex);
110 } else if (code == IBT_EVENT_SQD) {
111 ibmf_ci_t *cip;
112 ibt_qp_hdl_t qphdl = (ibt_qp_hdl_t)event->ev_chan_hdl;
113 ibmf_alt_qp_t *altqpp;
114 boolean_t found = B_FALSE;
115
116 mutex_enter(&ibmf_statep->ibmf_mutex);
117
118 cip = ibmf_statep->ibmf_ci_list;
119
120 /*
121 * An SQD event is received. We match the QP handle provided
122 * with all the alternate QP handles maintained on the lists
123 * of all the CI contexts. If a match is found, we wake
124 * up the thread waiting in ibmf_modify_qp().
125 */
126 while (cip != NULL) {
127 mutex_enter(&cip->ci_mutex);
128 altqpp = cip->ci_alt_qp_list;
129 while (altqpp != NULL) {
130 if (altqpp->isq_qp_handle == qphdl) {
131 mutex_enter(&altqpp->isq_mutex);
132 cv_signal(&altqpp->isq_sqd_cv);
133 mutex_exit(&altqpp->isq_mutex);
134 found = B_TRUE;
135 break;
136 }
137 altqpp = altqpp->isq_next;
138 }
139 mutex_exit(&cip->ci_mutex);
140
141 if (found)
142 break;
143 cip = cip->ci_next;
144 }
145
146 mutex_exit(&ibmf_statep->ibmf_mutex);
147
148 if (!found)
149 IBMF_TRACE_1(IBMF_TNF_NODEBUG,
150 DPRINT_L1, ibmf_ibt_async_handler_err,
151 IBMF_TNF_TRACE, "", "%s, ignoring event\n",
152 tnf_string, msg, "ibmf_ibt_async_handler: SQD "
153 "event for unknown QP received");
154 }
155
156 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_ibt_async_handler_end,
157 IBMF_TNF_TRACE, "", "ibmf_ibt_async_handler: exit.\n");
158 }
159
160 /*
161 * ibmf_i_callback_clients():
162 * Finds the ci given in parameter.
163 * Calls the client callbacks with the event given in parameter.
164 * Note that client callbacks are called with all ibmf mutexes unlocked.
165 */
166 static void
ibmf_i_callback_clients(ib_guid_t hca_guid,ibmf_async_event_t evt)167 ibmf_i_callback_clients(ib_guid_t hca_guid, ibmf_async_event_t evt)
168 {
169 ibmf_ci_t *cip;
170 ibmf_client_t *clientp;
171
172 int nclients = 0;
173 ibmf_async_event_cb_t *cb_array = NULL;
174 void **cb_args_array = NULL;
175 ibmf_handle_t *client_array = NULL;
176 int iclient;
177
178 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_callback_clients_start,
179 IBMF_TNF_TRACE, "", "ibmf_i_callback_clients() enter\n");
180
181 /* find ci */
182 mutex_enter(&ibmf_statep->ibmf_mutex);
183 cip = ibmf_statep->ibmf_ci_list;
184
185 while (cip != NULL) {
186 mutex_enter(&cip->ci_mutex);
187
188 if (cip->ci_node_guid == hca_guid) {
189 mutex_exit(&cip->ci_mutex);
190 break;
191 }
192
193 mutex_exit(&cip->ci_mutex);
194 cip = cip->ci_next;
195 }
196
197 if (cip == NULL) {
198
199 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
200 ibmf_i_callback_clients, IBMF_TNF_TRACE, "",
201 "ibmf_i_callback_clients: "
202 "ci = %016" PRIx64 "NOT found.\n",
203 tnf_opaque, hca_guid, hca_guid);
204
205 mutex_exit(&ibmf_statep->ibmf_mutex);
206 goto bail;
207 }
208
209 /* found the right ci, count clients */
210 mutex_enter(&cip->ci_clients_mutex);
211
212 /* empty counting loop */
213 for (clientp = cip->ci_clients, nclients = 0; clientp != NULL;
214 clientp = clientp->ic_next, nclients++)
215 ;
216
217 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
218 ibmf_i_callback_clients, IBMF_TNF_TRACE, "",
219 "ibmf_i_callback_clients: found %d clients, "
220 "on ci = %016" PRIx64 "\n",
221 tnf_int, nclients, nclients,
222 tnf_opaque, hca_guid, hca_guid);
223
224 /* no clients? bail */
225 if (nclients == 0) {
226
227 mutex_exit(&cip->ci_clients_mutex);
228 mutex_exit(&ibmf_statep->ibmf_mutex);
229 goto bail;
230 }
231
232 /* allocate callback, args, and client arrays */
233
234 cb_array = kmem_zalloc(
235 nclients * sizeof (ibmf_async_event_cb_t), KM_NOSLEEP);
236
237 cb_args_array = kmem_zalloc(
238 nclients * sizeof (void*), KM_NOSLEEP);
239
240 client_array = kmem_zalloc(
241 nclients * sizeof (ibmf_handle_t), KM_NOSLEEP);
242
243 if (cb_array == NULL || cb_args_array == NULL ||
244 client_array == NULL) {
245
246 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
247 ibmf_i_callback_clients_err, IBMF_TNF_ERROR, "",
248 "ibmf_i_callback_clients: %s\n",
249 tnf_string, msg, "could not allocate memory for "
250 "callback arrays");
251
252 mutex_exit(&cip->ci_clients_mutex);
253 mutex_exit(&ibmf_statep->ibmf_mutex);
254 goto bail;
255 }
256
257 /* build callback list */
258
259 for (clientp = cip->ci_clients, iclient = 0;
260 clientp != NULL;
261 clientp = clientp->ic_next, iclient++) {
262
263 cb_array[iclient] = clientp->ic_async_cb;
264 cb_args_array[iclient] = clientp->ic_async_cb_arg;
265 client_array[iclient] = (ibmf_handle_t)clientp;
266 }
267
268 mutex_exit(&cip->ci_clients_mutex);
269 mutex_exit(&ibmf_statep->ibmf_mutex);
270
271 /*
272 * All mutex unlocked, call back clients
273 */
274 for (iclient = 0; iclient < nclients; iclient++) {
275
276 IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L3,
277 ibmf_i_callback_clients, IBMF_TNF_TRACE, "",
278 "ibmf_i_callback_clients: client %d"
279 ", handle = %016" PRIx64
280 ", callback = %016" PRIx64 ", args = %016" PRIx64 "\n",
281 tnf_int, iclient, iclient,
282 tnf_opaque, handle, client_array[iclient],
283 tnf_opaque, cb_ptr, cb_array[iclient],
284 tnf_opaque, args_ptr, cb_args_array[iclient]);
285
286 if (cb_array[iclient] != NULL)
287 cb_array[iclient](client_array[iclient],
288 cb_args_array[iclient], evt);
289 }
290
291 bail:
292
293 if (cb_array != NULL)
294 kmem_free(cb_array, nclients * sizeof (ibmf_async_event_cb_t));
295
296 if (cb_args_array != NULL)
297 kmem_free(cb_args_array, nclients * sizeof (void*));
298
299 if (client_array != NULL)
300 kmem_free(client_array, nclients * sizeof (ibmf_handle_t));
301
302 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_callback_clients_end,
303 IBMF_TNF_TRACE, "", "ibmf_i_callback_clients: exit.\n");
304 }
305
306 /*
307 * ibmf_i_mad_completions():
308 * Check for a completion entry on the specified CQ and process it
309 */
310 void
ibmf_i_mad_completions(ibt_cq_hdl_t cq_handle,void * arg)311 ibmf_i_mad_completions(ibt_cq_hdl_t cq_handle, void *arg)
312 {
313 ibt_wc_t cqe;
314 ibt_status_t status;
315 ibmf_ci_t *ibmf_cip;
316
317 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
318 ibmf_i_mad_completions_start, IBMF_TNF_TRACE, "",
319 "ibmf_i_mad_completions() enter, cq_hdl = %p\n",
320 tnf_opaque, cq_handle, cq_handle);
321
322 ibmf_cip = arg;
323
324 ASSERT(ibmf_cip != NULL);
325
326 /*
327 * Pull a completion and process it
328 */
329 for (;;) {
330 status = ibt_poll_cq(cq_handle, &cqe, 1, NULL);
331 ASSERT(status != IBT_CQ_HDL_INVALID &&
332 status != IBT_HCA_HDL_INVALID);
333 /*
334 * Check if the status is IBT_SUCCESS or IBT_CQ_EMPTY
335 * either which can return from ibt_poll_cq(). In other
336 * cases, log the status for the further investigation.
337 */
338 if (status != IBT_SUCCESS) {
339 if (status != IBT_CQ_EMPTY) {
340 cmn_err(CE_NOTE, "!ibmf_i_mad_completions got "
341 "an error status (0x%x) from ibt_poll_cq.",
342 status);
343 }
344 break;
345 }
346
347 /* process the completion */
348 ibmf_i_process_completion(ibmf_cip, &cqe);
349 }
350
351 (void) ibt_enable_cq_notify(cq_handle, IBT_NEXT_COMPLETION);
352
353 /*
354 * Look for more completions just in case some came in before
355 * we were able to reenable CQ notification
356 */
357 for (;;) {
358 status = ibt_poll_cq(cq_handle, &cqe, 1, NULL);
359 ASSERT(status != IBT_CQ_HDL_INVALID &&
360 status != IBT_HCA_HDL_INVALID);
361 /*
362 * Check if the status is IBT_SUCCESS or IBT_CQ_EMPTY
363 * either which can return from ibt_poll_cq(). In other
364 * cases, log the status for the further investigation.
365 */
366 if (status != IBT_SUCCESS) {
367 if (status != IBT_CQ_EMPTY) {
368 cmn_err(CE_NOTE, "!ibmf_i_mad_completions got "
369 "an error status (0x%x) from ibt_poll_cq.",
370 status);
371 }
372 break;
373 }
374
375 /* process the completion */
376 ibmf_i_process_completion(ibmf_cip, &cqe);
377 }
378
379 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_mad_completions_end,
380 IBMF_TNF_TRACE, "", "ibmf_i_mad_completions() exit\n");
381 }
382
383 /*
384 * ibmf_i_process_completion():
385 * Process the send or receive completion
386 */
387 static void
ibmf_i_process_completion(ibmf_ci_t * cip,ibt_wc_t * wcp)388 ibmf_i_process_completion(ibmf_ci_t *cip, ibt_wc_t *wcp)
389 {
390 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
391 ibmf_i_process_completion_start, IBMF_TNF_TRACE, "",
392 "ibmf_i_process_completion() enter, cip = %p, wcp = %p\n",
393 tnf_opaque, cip, cip, tnf_opaque, wcp, wcp);
394
395 if (IBMF_IS_RECV_WR_ID(wcp->wc_id) == B_TRUE) {
396 /* completion from a receive queue */
397 ibmf_i_handle_recv_completion(cip, wcp);
398 } else {
399 /* completion from a send queue */
400 ibmf_i_handle_send_completion(cip, wcp);
401 }
402
403 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_process_completion_end,
404 IBMF_TNF_TRACE, "", "ibmf_i_process_completion() exit\n");
405 }
406
407 #ifdef DEBUG
408 static int ibmf_i_dump_mad_size = 0x40;
409 static int ibmf_i_dump_wcp_enable = 0;
410
411 /* ARGSUSED */
412 void
ibmf_i_dump_wcp(ibmf_ci_t * cip,ibt_wc_t * wcp,ibmf_recv_wqe_t * recv_wqep)413 ibmf_i_dump_wcp(ibmf_ci_t *cip, ibt_wc_t *wcp, ibmf_recv_wqe_t *recv_wqep)
414 {
415 uchar_t *ptr;
416 char buf[256], *sptr;
417 int i, j;
418
419 if (ibmf_i_dump_wcp_enable == 0)
420 return;
421
422 printf("wcp: sender lid %x port num %x path bits %x qp %x sl %x\n",
423 wcp->wc_slid, recv_wqep->recv_port_num, wcp->wc_path_bits,
424 wcp->wc_qpn, wcp->wc_sl);
425
426 ptr = (uchar_t *)((uintptr_t)recv_wqep->recv_mem +
427 sizeof (ib_grh_t));
428
429 printf("mad:\n");
430 /* first print multiples of 16bytes */
431 for (i = ibmf_i_dump_mad_size; i >= 16; i -= 16) {
432 for (sptr = buf, j = 0; j < 16; j++) {
433 (void) sprintf(sptr, "%02x ", *ptr++);
434 sptr += 3; /* 2 digits + space */
435 }
436 printf("%s\n", buf);
437 }
438 /* print the rest */
439 if (i < 16) {
440 for (sptr = buf, j = 0; j < i; j++) {
441 (void) sprintf(sptr, "%02x ", *ptr++);
442 sptr += 3; /* 2 digits + space */
443 }
444 printf("%s\n", buf);
445 }
446 }
447 #endif /* DEBUG */
448