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 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 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 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 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 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