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