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