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