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 #include <sys/ib/mgt/ibmf/ibmf_saa_impl.h> 28 #include <sys/ib/mgt/ibmf/ibmf_saa_utils.h> 29 30 extern saa_state_t *saa_statep; 31 extern int ibmf_trace_level; 32 33 static void 34 ibmf_saa_informinfo_cb(void *arg, size_t length, char *buffer, 35 int status, uint32_t producer_type); 36 37 static int 38 ibmf_saa_send_informinfo(saa_port_t *saa_portp, uint32_t producer_type, 39 boolean_t subscribe, boolean_t unseq_unsubscribe); 40 41 static void 42 ibmf_saa_notify_event_client_task(void *args); 43 44 static void 45 ibmf_saa_process_subnet_event(saa_port_t *saa_portp, ib_mad_notice_t *notice); 46 47 /* 48 * ibmf_saa_subscribe_events: 49 * Subscribe or unsubscribe to subnet events for a certain port. 50 * ibmf_saa_subscribe_events() will send an InformInfo request for each of the 51 * four notice producer types. 52 * 53 * Subscribes generally occur when the first client for a port opens a session 54 * and when a port with registered ibmf_saa clients transitions to active. 55 * Subscribes are done as asynchronous, sequenced transactions. 56 * 57 * ibmf_saa sends unsubscribe requests when the last client for a port 58 * unregisters and when an CI_OFFLINE message is received from ibtf (via ibmf). 59 * For the first case, the unsubscribe is done as an asynchronous, sequenced 60 * transaction. For the second case, the request is asynchronous, unsequenced. 61 * This means that the unsubscribes will not be retried. Because the port is 62 * going away we cannot wait for responses. Unsubscribes are not required 63 * anyway as the SA will remove subscription records from ports it determines to 64 * be down. 65 * 66 * For subscribe requests, clients are notified that the request failed through 67 * the event notification mechanism. For unsubscribe requests, clients are not 68 * notified if the request fails. Therefore, this function returns void. 69 * 70 * Input Arguments 71 * saa_portp pointer to port state structure 72 * subscribe B_TRUE if request is a Subscribe, B_FALSE if unsubscribe 73 * unseq_unsubscribe B_TRUE if unsubscribe request should be unsequenced 74 * (called from CI_OFFLINE event handler) 75 * B_FALSE if sequenced (wait for response) or for all 76 * subscribe requests 77 * 78 * Output Arguments 79 * none 80 * 81 * Returns 82 * void 83 */ 84 void 85 ibmf_saa_subscribe_events(saa_port_t *saa_portp, boolean_t subscribe, 86 boolean_t unseq_unsubscribe) 87 { 88 int res; 89 ibmf_saa_event_details_t event_details; 90 boolean_t notify_clients = B_FALSE; 91 uint8_t success_mask; 92 93 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, 94 ibmf_saa_subscribe_events_start, IBMF_TNF_TRACE, "", 95 "ibmf_saa_subscribe_events() enter\n"); 96 97 /* subscribes should always be sychronous */ 98 ASSERT((subscribe == B_FALSE) || (unseq_unsubscribe == B_FALSE)); 99 100 /* 101 * reset the arrive and success masks to indicate no responses have come 102 * back; technically only used for subscriptions but reset the values 103 * anyway 104 */ 105 mutex_enter(&saa_portp->saa_pt_event_sub_mutex); 106 107 success_mask = saa_portp->saa_pt_event_sub_success_mask; 108 109 saa_portp->saa_pt_event_sub_arrive_mask = 0; 110 saa_portp->saa_pt_event_sub_success_mask = 0; 111 112 mutex_exit(&saa_portp->saa_pt_event_sub_mutex); 113 114 /* 115 * now subscribe/unsubscribe for each of the notice producer types; 116 * send_informinfo returns 1 on success, 0 on failure. If the "or" of 117 * all four results is 0 then none of the informinfo's succeed and we 118 * should notify the client. If it's not 0, then informinfo_cb will be 119 * called at least once, taking care of notifying the clients that there 120 * was a failure. 121 * For each producer type, send the request only if it's a subscribe or 122 * if it's an unsubscribe for a subscribe which succeeded 123 */ 124 125 /* 126 * subscribe for all traps generated by the SM; 127 * gid in service/out of service, mgid created/deleted, etc. 128 */ 129 if ((success_mask & IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SM) || 130 (subscribe == B_TRUE)) 131 res = ibmf_saa_send_informinfo(saa_portp, 132 MAD_INFORMINFO_NODETYPE_SUBNET_MANAGEMENT, subscribe, 133 unseq_unsubscribe); 134 135 /* subscribe for all traps generated by a CA */ 136 if ((success_mask & IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_CA) || 137 (subscribe == B_TRUE)) 138 res |= ibmf_saa_send_informinfo(saa_portp, 139 MAD_INFORMINFO_NODETYPE_CA, subscribe, unseq_unsubscribe); 140 141 /* subscribe for all traps generated by a switch */ 142 if ((success_mask & IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SWITCH) || 143 (subscribe == B_TRUE)) 144 res |= ibmf_saa_send_informinfo(saa_portp, 145 MAD_INFORMINFO_NODETYPE_SWITCH, subscribe, 146 unseq_unsubscribe); 147 148 /* subscribe for all traps generated by a router */ 149 if ((success_mask & IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_ROUTER) || 150 (subscribe == B_TRUE)) 151 res |= ibmf_saa_send_informinfo(saa_portp, 152 MAD_INFORMINFO_NODETYPE_ROUTER, subscribe, 153 unseq_unsubscribe); 154 155 /* if none of the subscribe requests succeeded notify the clients */ 156 if ((res == 0) && (subscribe == B_TRUE)) { 157 158 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1, 159 ibmf_saa_subscribe_events_err, IBMF_TNF_ERROR, "", 160 "ibmf_saa_subscribe_events: %s\n", tnf_string, msg, 161 "Could not subscribe for any of the four producer types"); 162 163 mutex_enter(&saa_portp->saa_pt_event_sub_mutex); 164 165 /* all events should have "arrived" */ 166 ASSERT(saa_portp->saa_pt_event_sub_arrive_mask == 167 IBMF_SAA_PORT_EVENT_SUB_ALL_ARRIVE); 168 169 /* status mask should be 0 since all failed */ 170 ASSERT(saa_portp->saa_pt_event_sub_success_mask == 0); 171 172 /* notify clients if success mask changed */ 173 if (saa_portp->saa_pt_event_sub_last_success_mask != 174 saa_portp->saa_pt_event_sub_success_mask) 175 notify_clients = B_TRUE; 176 177 /* update last mask for next set of subscription requests */ 178 saa_portp->saa_pt_event_sub_last_success_mask = 179 saa_portp->saa_pt_event_sub_arrive_mask = 0; 180 181 mutex_exit(&saa_portp->saa_pt_event_sub_mutex); 182 183 mutex_enter(&saa_portp->saa_pt_mutex); 184 185 /* 186 * Sending the four InformInfos is treated as one port client 187 * reference. Now that all have returned decrement the 188 * reference count. 189 */ 190 ASSERT(saa_portp->saa_pt_reference_count > 0); 191 saa_portp->saa_pt_reference_count--; 192 193 mutex_exit(&saa_portp->saa_pt_mutex); 194 } 195 196 /* 197 * for unsequenced unsubscribes, decrement the reference count here 198 * since no callbacks will ever do it 199 */ 200 if (unseq_unsubscribe == B_TRUE) { 201 202 mutex_enter(&saa_portp->saa_pt_mutex); 203 204 /* 205 * Sending the four InformInfos is treated as one port client 206 * reference. Now that all have returned decrement the 207 * reference count. 208 */ 209 ASSERT(saa_portp->saa_pt_reference_count > 0); 210 saa_portp->saa_pt_reference_count--; 211 212 mutex_exit(&saa_portp->saa_pt_mutex); 213 } 214 215 if (notify_clients == B_TRUE) { 216 217 bzero(&event_details, sizeof (ibmf_saa_event_details_t)); 218 219 ibmf_saa_notify_event_clients(saa_portp, &event_details, 220 IBMF_SAA_EVENT_SUBSCRIBER_STATUS_CHG, NULL); 221 } 222 223 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_subscribe_events_end, 224 IBMF_TNF_TRACE, "", "ibmf_saa_subscribe_events() exit\n"); 225 } 226 227 /* 228 * ibmf_saa_send_informinfo: 229 * 230 * Sends an InformInfo request to the SA. There are two types of request, 231 * Subscribes and Unsubscribes. This function is called from 232 * ibmf_saa_subscribe_events. See that function's comment for usage of 233 * subscribe, unseq_unsubscribe booleans. 234 * 235 * This function generates a standard ibmf_saa transaction and sends using 236 * ibmf_saa_impl_send_request(). For asynchronous callbacks, the function 237 * ibmf_saa_informinfo_cb() will be called. 238 * 239 * This function blocks allocating resources, but not waiting for response 240 * packets. 241 * 242 * Input Arguments 243 * saa_portp pointer to port data 244 * producer_type InformInfo producer type to subscribe for 245 * subscribe B_TRUE if subscribe request, B_FALSE if unsubscribe 246 * unseq_unsubscribe B_TRUE if unsubscribe request should be unsequenced 247 * (called from CI_OFFLINE event handler) 248 * B_FALSE if sequenced (wait for response) or for all 249 * subscribe requests 250 * 251 * Output Arguments 252 * none 253 * 254 * Returns 255 * 1 if the transaction succeeded, 0 if it failed 256 */ 257 static int 258 ibmf_saa_send_informinfo(saa_port_t *saa_portp, uint32_t producer_type, 259 boolean_t subscribe, boolean_t unseq_unsubscribe) 260 { 261 ib_mad_informinfo_t inform_info; 262 saa_impl_trans_info_t *trans_info; 263 int res; 264 uint8_t producer_type_mask; 265 266 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, 267 ibmf_saa_send_informinfo_start, IBMF_TNF_TRACE, "", 268 "ibmf_saa_send_informinfo() enter\n"); 269 270 IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_saa_send_informinfo, 271 IBMF_TNF_TRACE, "", "ibmf_saa_send_informinfo: %s, producer_type =" 272 "%x, subscribe = %x, unseq_unsubscribe = %x\n", 273 tnf_string, msg, "Sending informinfo request", 274 tnf_opaque, producer_type, producer_type, 275 tnf_int, subscribe, subscribe, 276 tnf_int, unseq_unsubscribe, unseq_unsubscribe); 277 278 bzero(&inform_info, sizeof (ib_mad_informinfo_t)); 279 280 /* initialize inform_info packet */ 281 inform_info.LIDRangeBegin = MAD_INFORMINFO_ALL_ENDPORTS_RANGE; 282 inform_info.IsGeneric = MAD_INFORMINFO_FORWARD_GENERIC; 283 284 if (subscribe == B_TRUE) 285 inform_info.Subscribe = MAD_INFORMINFO_SUBSCRIBE; 286 else { 287 inform_info.Subscribe = MAD_INFORMINFO_UNSUBSCRIBE; 288 inform_info.QPN = saa_portp->saa_pt_qpn; 289 } 290 291 inform_info.Type = MAD_INFORMINFO_TRAP_TYPE_FORWARD_ALL; 292 inform_info.TrapNumber_DeviceID = 293 MAD_INFORMINFO_TRAP_NUMBER_FORWARD_ALL; 294 inform_info.ProducerType_VendorID = producer_type; 295 296 trans_info = kmem_zalloc(sizeof (saa_impl_trans_info_t), KM_SLEEP); 297 298 /* no specific client associated with this transaction */ 299 trans_info->si_trans_client_data = NULL; 300 trans_info->si_trans_port = saa_portp; 301 trans_info->si_trans_method = SA_SUBN_ADM_SET; 302 trans_info->si_trans_attr_id = SA_INFORMINFO_ATTRID; 303 trans_info->si_trans_component_mask = 0; 304 trans_info->si_trans_template = &inform_info; 305 trans_info->si_trans_template_length = sizeof (ib_mad_informinfo_t); 306 trans_info->si_trans_unseq_unsubscribe = unseq_unsubscribe; 307 308 /* 309 * if this isn't an unsequenced unsubscribe (the only synchronous 310 * request) then set up the callback 311 */ 312 if (unseq_unsubscribe == B_FALSE) { 313 trans_info->si_trans_sub_callback = 314 ibmf_saa_informinfo_cb; 315 trans_info->si_trans_callback_arg = saa_portp; 316 317 /* 318 * if this is a subscribe, set the producer type so we can know 319 * which one's failed 320 */ 321 if (subscribe == B_TRUE) { 322 trans_info->si_trans_sub_producer_type = producer_type; 323 } 324 } 325 326 mutex_enter(&saa_portp->saa_pt_kstat_mutex); 327 328 IBMF_SAA_ADD32_KSTATS(saa_portp, outstanding_requests, 1); 329 IBMF_SAA_ADD32_KSTATS(saa_portp, total_requests, 1); 330 331 mutex_exit(&saa_portp->saa_pt_kstat_mutex); 332 333 res = ibmf_saa_impl_send_request(trans_info); 334 if (res != IBMF_SUCCESS) { 335 336 IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, 337 ibmf_saa_send_informinfo, IBMF_TNF_ERROR, "", 338 "ibmf_saa_send_informinfo: %s, ibmf_status = %d\n", 339 tnf_string, msg, "ibmf_saa_impl_send_request() failed", 340 tnf_int, ibmf_status, res); 341 342 res = 0; 343 344 } else { 345 346 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, 347 ibmf_saa_send_informinfo, IBMF_TNF_TRACE, "", 348 "ibmf_saa_send_informinfo: %s\n", tnf_string, msg, 349 "Request sent successfully"); 350 351 res = 1; 352 353 /* 354 * if this was an asynchronous transaction (not the unsequenced 355 * unsubscribe case) return here. 356 * The callback will clean up everything. 357 */ 358 if (unseq_unsubscribe == B_FALSE) { 359 360 goto bail; 361 } 362 } 363 364 kmem_free(trans_info, sizeof (saa_impl_trans_info_t)); 365 366 mutex_enter(&saa_portp->saa_pt_kstat_mutex); 367 368 IBMF_SAA_SUB32_KSTATS(saa_portp, outstanding_requests, 1); 369 IBMF_SAA_ADD32_KSTATS(saa_portp, failed_requests, 1); 370 371 mutex_exit(&saa_portp->saa_pt_kstat_mutex); 372 373 /* 374 * if subscribe transaction failed, update status mask 375 * to indicate "response" 376 */ 377 if ((res == 0) && (subscribe == B_TRUE)) { 378 379 mutex_enter(&saa_portp->saa_pt_event_sub_mutex); 380 381 saa_portp->saa_pt_event_sub_arrive_mask = 0; 382 saa_portp->saa_pt_event_sub_success_mask = 0; 383 384 switch (producer_type) { 385 386 case MAD_INFORMINFO_NODETYPE_CA: 387 producer_type_mask = 388 IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_CA; 389 break; 390 case MAD_INFORMINFO_NODETYPE_SWITCH: 391 producer_type_mask = 392 IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SWITCH; 393 break; 394 case MAD_INFORMINFO_NODETYPE_ROUTER: 395 producer_type_mask = 396 IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_ROUTER; 397 break; 398 case MAD_INFORMINFO_NODETYPE_SUBNET_MANAGEMENT: 399 producer_type_mask = 400 IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SM; 401 break; 402 default: 403 IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, 404 ibmf_saa_send_informinfo, IBMF_TNF_ERROR, 405 "", "ibmf_saa_send_informinfo: %s, " 406 "producer_type = 0x%x\n", 407 tnf_string, msg, "Unknown producer type", 408 tnf_opaque, producer_type, producer_type); 409 410 ASSERT(0); 411 producer_type_mask = 0; 412 break; 413 } 414 415 saa_portp->saa_pt_event_sub_arrive_mask |= producer_type_mask; 416 417 mutex_exit(&saa_portp->saa_pt_event_sub_mutex); 418 } 419 420 bail: 421 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, 422 ibmf_saa_send_informinfo_end, IBMF_TNF_TRACE, "", 423 "ibmf_saa_send_informinfo() exit: result = 0x%x\n", 424 tnf_opaque, result, res); 425 426 return (res); 427 } 428 429 /* 430 * ibmf_saa_informinfo_cb: 431 * 432 * Called when the asynchronous informinfo request receives its response. 433 * Checks the status (whether the ibmf_saa was able to subscribe with the SA for 434 * events) and updates the status mask for the specific producer. If all four 435 * producer types have arrived then the event clients are notified if there has 436 * been a change in the status. 437 * 438 * Input Arguments 439 * arg user-specified pointer (points to the current port data) 440 * length length of payload returned (should be size of informinfo_rec) 441 * buffer pointer to informinfo response returned (should not be null) 442 * status status of sa access request 443 * producer_type for subscriptions, indicates the notice producer type that was 444 * requested; ignored for unsubscribes 445 * 446 * Output Arguments 447 * none 448 * 449 * Returns void 450 */ 451 static void 452 ibmf_saa_informinfo_cb(void *arg, size_t length, char *buffer, 453 int status, uint32_t producer_type) 454 { 455 saa_port_t *saa_portp; 456 uint8_t producer_type_mask; 457 boolean_t notify_clients; 458 uint8_t event_status_mask; 459 ibmf_saa_event_details_t event_details; 460 461 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_saa_informinfo_cb_start, 462 IBMF_TNF_TRACE, "", "ibmf_saa_informinfo_cb() enter: producer_type " 463 "= 0x%x, status = %d\n", tnf_opaque, producer_type, producer_type, 464 tnf_int, status, status); 465 466 saa_portp = (saa_port_t *)arg; 467 468 notify_clients = B_FALSE; 469 470 /* if producer type is 0 this was an unsubscribe */ 471 if (producer_type == 0) { 472 473 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, 474 ibmf_saa_informinfo_cb, IBMF_TNF_TRACE, "", 475 "ibmf_saa_informinfo_cb(): %s", 476 tnf_string, msg, "handling unsubscribe"); 477 478 if (buffer != NULL) 479 kmem_free(buffer, length); 480 481 goto bail; 482 } 483 484 /* determine which event it was */ 485 switch (producer_type) { 486 487 case MAD_INFORMINFO_NODETYPE_CA: 488 producer_type_mask = 489 IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_CA; 490 break; 491 case MAD_INFORMINFO_NODETYPE_SWITCH: 492 producer_type_mask = 493 IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SWITCH; 494 break; 495 case MAD_INFORMINFO_NODETYPE_ROUTER: 496 producer_type_mask = 497 IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_ROUTER; 498 break; 499 case MAD_INFORMINFO_NODETYPE_SUBNET_MANAGEMENT: 500 producer_type_mask = 501 IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SM; 502 break; 503 504 default: 505 IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, 506 ibmf_saa_send_informinfo_cb, IBMF_TNF_ERROR, 507 "", "ibmf_saa_informinfo_cb: %s, " 508 "producer_type = 0x%x\n", 509 tnf_string, msg, "Unknown producer type", 510 tnf_opaque, producer_type, producer_type); 511 512 producer_type_mask = 0; 513 break; 514 } 515 516 mutex_enter(&saa_portp->saa_pt_event_sub_mutex); 517 518 if (saa_portp->saa_pt_event_sub_arrive_mask & producer_type_mask) { 519 520 mutex_exit(&saa_portp->saa_pt_event_sub_mutex); 521 522 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2, 523 ibmf_saa_informinfo_cb, IBMF_TNF_TRACE, "", 524 "ibmf_saa_informinfo_cb(): %s, prod_type_mask = 0x%x", 525 tnf_string, msg, "Received duplicate response", 526 tnf_opaque, producer_type_mask, producer_type_mask); 527 528 if (buffer != NULL) 529 kmem_free(buffer, length); 530 531 goto bail; 532 } 533 534 saa_portp->saa_pt_event_sub_arrive_mask |= producer_type_mask; 535 536 /* process response */ 537 if ((status != IBMF_SUCCESS) || (buffer == NULL)) { 538 539 IBMF_TRACE_4(IBMF_TNF_NODEBUG, DPRINT_L1, 540 ibmf_saa_informinfo_cb, IBMF_TNF_ERROR, "", 541 "ibmf_saa_informinfo_cb: %s, status = %d," 542 " buffer = 0x%p, length = %d\n", 543 tnf_string, msg, "could not get informinfo resp", 544 tnf_int, status, status, tnf_opaque, buffer, buffer, 545 tnf_uint, length, length); 546 547 } else if (buffer != NULL) { 548 549 kmem_free(buffer, length); 550 saa_portp->saa_pt_event_sub_success_mask |= producer_type_mask; 551 } 552 553 /* if all four InformInfo responses have arrived */ 554 if (saa_portp->saa_pt_event_sub_arrive_mask == 555 IBMF_SAA_PORT_EVENT_SUB_ALL_ARRIVE) { 556 557 IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3, 558 ibmf_saa_informinfo_cb, IBMF_TNF_TRACE, "", 559 "ibmf_saa_informinfo_cb(): %s, success mask = 0x%x," 560 " last success mask = 0x%x\n", 561 tnf_string, msg, "all informinfo responses have arrived", 562 tnf_opaque, success_mask, 563 saa_portp->saa_pt_event_sub_success_mask, 564 tnf_opaque, last_success_mask, 565 saa_portp->saa_pt_event_sub_last_success_mask); 566 567 mutex_enter(&saa_portp->saa_pt_mutex); 568 569 /* 570 * Sending the four InformInfos is treated as one port client 571 * reference. Now that all have returned decrement the 572 * reference count. 573 */ 574 ASSERT(saa_portp->saa_pt_reference_count > 0); 575 saa_portp->saa_pt_reference_count--; 576 577 mutex_exit(&saa_portp->saa_pt_mutex); 578 579 if (saa_portp->saa_pt_event_sub_last_success_mask != 580 saa_portp->saa_pt_event_sub_success_mask) { 581 582 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L2, 583 ibmf_saa_informinfo_cb, IBMF_TNF_TRACE, "", 584 "ibmf_saa_informinfo_cb(): %s\n", 585 tnf_string, msg, 586 "success mask different - notifying clients"); 587 588 /* 589 * save status mask to give to clients and update last 590 * mask for next set of subscription requests 591 */ 592 event_status_mask = 593 saa_portp->saa_pt_event_sub_last_success_mask = 594 saa_portp->saa_pt_event_sub_success_mask; 595 596 notify_clients = B_TRUE; 597 } 598 } 599 600 mutex_exit(&saa_portp->saa_pt_event_sub_mutex); 601 602 if (notify_clients == B_TRUE) { 603 604 bzero(&event_details, sizeof (ibmf_saa_event_details_t)); 605 606 event_details.ie_producer_event_status_mask = 607 event_status_mask; 608 609 ibmf_saa_notify_event_clients(saa_portp, &event_details, 610 IBMF_SAA_EVENT_SUBSCRIBER_STATUS_CHG, NULL); 611 } 612 613 bail: 614 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, 615 ibmf_saa_informinfo_cb_end, 616 IBMF_TNF_TRACE, "", "ibmf_saa_informinfo_cb() exit\n"); 617 } 618 619 /* 620 * ibmf_saa_notify_event_client_task 621 * 622 * Calls the event notification callback for a registered saa client. Called 623 * from ibmf_saa_notify_event_clients() for each client that has registered for 624 * events. ibmf_saa_notify_event_clients() will dispatch this task on the 625 * saa_event_taskq so the client's callback can be invoked directly. 626 * 627 * Input Arguments 628 * args pointer to ibmf_saa_event_taskq_args_t 629 * this function will free memory associated with args 630 * 631 * Output Arguments 632 * none 633 * 634 * Returns 635 * void 636 */ 637 static void 638 ibmf_saa_notify_event_client_task(void *args) 639 { 640 ibmf_saa_event_taskq_args_t *event_taskq_args; 641 saa_client_data_t *client; 642 643 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L3, 644 ibmf_saa_notify_event_client_task_start, 645 IBMF_TNF_TRACE, "", "ibmf_saa_notify_event_client_task() enter\n"); 646 647 event_taskq_args = (ibmf_saa_event_taskq_args_t *)args; 648 649 client = event_taskq_args->et_client; 650 651 /* call client's callback (client pointer is ibmf_saa_handle) */ 652 (event_taskq_args->et_callback)((ibmf_saa_handle_t)client, 653 event_taskq_args->et_subnet_event, 654 event_taskq_args->et_event_details, 655 event_taskq_args->et_callback_arg); 656 657 kmem_free(event_taskq_args->et_event_details, 658 sizeof (ibmf_saa_event_details_t)); 659 660 kmem_free(event_taskq_args, sizeof (ibmf_saa_event_taskq_args_t)); 661 662 /* decrement the callback count and signal a waiting client */ 663 mutex_enter(&client->saa_client_mutex); 664 665 client->saa_client_event_cb_num_active--; 666 667 if (client->saa_client_event_cb_num_active == 0) { 668 669 cv_signal(&client->saa_client_event_cb_cv); 670 671 } 672 673 mutex_exit(&client->saa_client_mutex); 674 675 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L3, 676 ibmf_saa_notify_event_client_task_end, 677 IBMF_TNF_TRACE, "", "ibmf_saa_notify_event_client_task() exit\n"); 678 } 679 680 /* 681 * ibmf_saa_process_subnet_event: 682 * 683 * Called when the ibmf_saa is notified of a forwarded notice. Converts the 684 * notice into an ibmf_saa_event_details structure and calls 685 * ibmf_saa_notify_event_clients() which will notify each interested client. 686 * 687 * Input Arguments 688 * saa_portp pointer to saa_port data 689 * notice notice that was forwarded from SA 690 * 691 * Output Arguments 692 * none 693 * 694 * Returns 695 * void 696 */ 697 static void 698 ibmf_saa_process_subnet_event(saa_port_t *saa_portp, ib_mad_notice_t *notice) 699 { 700 ibmf_saa_event_details_t event_details; 701 sm_trap_64_t trap_data_details; 702 sm_trap_144_t cap_mask_trap_data_details; 703 sm_trap_145_t sys_img_trap_data_details; 704 ibmf_saa_subnet_event_t subnet_event; 705 706 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, 707 ibmf_saa_process_subnet_event_start, 708 IBMF_TNF_TRACE, "", "ibmf_saa_process_subnet_event() enter: " 709 "trap_number = 0x%x\n", 710 tnf_opaque, trap_number, notice->TrapNumber_DeviceID); 711 712 bzero(&event_details, sizeof (ibmf_saa_event_details_t)); 713 714 /* 715 * fill in the appropriate fields of event_details depending on 716 * the trap number 717 */ 718 switch (notice->TrapNumber_DeviceID) { 719 720 case SM_GID_IN_SERVICE_TRAP: 721 722 ibmf_saa_gid_trap_parse_buffer(notice->DataDetails, 723 &trap_data_details); 724 725 event_details.ie_gid = trap_data_details.GIDADDR; 726 727 subnet_event = IBMF_SAA_EVENT_GID_AVAILABLE; 728 break; 729 730 731 case SM_GID_OUT_OF_SERVICE_TRAP: 732 733 ibmf_saa_gid_trap_parse_buffer(notice->DataDetails, 734 &trap_data_details); 735 736 event_details.ie_gid = trap_data_details.GIDADDR; 737 738 subnet_event = IBMF_SAA_EVENT_GID_UNAVAILABLE; 739 break; 740 741 case SM_MGID_CREATED_TRAP: 742 743 ibmf_saa_gid_trap_parse_buffer(notice->DataDetails, 744 &trap_data_details); 745 746 event_details.ie_gid = trap_data_details.GIDADDR; 747 748 subnet_event = IBMF_SAA_EVENT_MCG_CREATED; 749 break; 750 751 case SM_MGID_DESTROYED_TRAP: 752 753 ibmf_saa_gid_trap_parse_buffer(notice->DataDetails, 754 &trap_data_details); 755 756 event_details.ie_gid = trap_data_details.GIDADDR; 757 758 subnet_event = IBMF_SAA_EVENT_MCG_DELETED; 759 break; 760 761 case SM_CAP_MASK_CHANGED_TRAP: 762 763 ibmf_saa_capmask_chg_trap_parse_buffer( 764 notice->DataDetails, &cap_mask_trap_data_details); 765 766 event_details.ie_lid = 767 cap_mask_trap_data_details.LIDADDR; 768 event_details.ie_capability_mask = 769 cap_mask_trap_data_details.CAPABILITYMASK; 770 771 subnet_event = IBMF_SAA_EVENT_CAP_MASK_CHG; 772 break; 773 774 case SM_SYS_IMG_GUID_CHANGED_TRAP: 775 776 ibmf_saa_sysimg_guid_chg_trap_parse_buffer( 777 notice->DataDetails, &sys_img_trap_data_details); 778 779 event_details.ie_lid = 780 sys_img_trap_data_details.LIDADDR; 781 event_details.ie_sysimg_guid = 782 sys_img_trap_data_details.SYSTEMIMAGEGUID; 783 784 subnet_event = IBMF_SAA_EVENT_SYS_IMG_GUID_CHG; 785 break; 786 787 default: 788 /* 789 * do nothing if it's not one of the traps we care about 790 */ 791 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, 792 ibmf_saa_process_subnet_event_end, 793 IBMF_TNF_TRACE, "", 794 "ibmf_saa_process_subnet_event() exit: %s\n", 795 tnf_string, msg, 796 "not one of the six ibmf_saa subnet events"); 797 798 return; 799 } 800 801 ibmf_saa_notify_event_clients(saa_portp, &event_details, subnet_event, 802 NULL); 803 804 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, 805 ibmf_saa_process_subnet_event_end, 806 IBMF_TNF_TRACE, "", "ibmf_saa_process_subnet_event() exit\n"); 807 } 808 809 /* 810 * ibmf_saa_notify_event_clients: 811 * 812 * Called when a trap for one of the six saa subnet events arrives or there is a 813 * change in the status of event subscriptions. Searches the list of clients 814 * with callbacks and dispatches a taskq thread to notify the client that the 815 * event occured. 816 * 817 * If some subscription request fails and a subsequent client registers for 818 * events that client needs to know that it may not receive all events. To 819 * facilitate this, notify_event_clients() takes an optional parameter which 820 * specifies a specific client. If registering_client is non-NULL only this 821 * client is notified. If the parameter is NULL, all clients in the list are 822 * notified. 823 * 824 * Input Arguments 825 * saa_portp pointer to saa_port data 826 * event_details pointer to ibmf_saa_event_details_t for this event 827 * subnet_event type of event that occured 828 * registering_client pointer to client_data_t if notification should go to a 829 * specific client; NULL if notification should go to all 830 * clients which subscribed for events 831 * 832 * Output Arguments 833 * none 834 * 835 * Returns 836 * none 837 */ 838 void 839 ibmf_saa_notify_event_clients(saa_port_t *saa_portp, 840 ibmf_saa_event_details_t *event_details, 841 ibmf_saa_subnet_event_t subnet_event, saa_client_data_t *registering_client) 842 { 843 saa_client_data_t *client; 844 ibmf_saa_event_taskq_args_t *event_taskq_args; 845 int status; 846 847 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, 848 ibmf_saa_notify_event_clients_start, 849 IBMF_TNF_TRACE, "", "ibmf_saa_notify_event_clients() enter\n"); 850 851 mutex_enter(&saa_portp->saa_pt_event_sub_mutex); 852 853 if (registering_client != NULL) 854 client = registering_client; 855 else 856 client = saa_portp->saa_pt_event_sub_client_list; 857 858 while (client != NULL) { 859 860 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*event_taskq_args)) 861 862 event_taskq_args = kmem_zalloc( 863 sizeof (ibmf_saa_event_taskq_args_t), KM_NOSLEEP); 864 if (event_taskq_args == NULL) { 865 866 IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, 867 ibmf_saa_notify_event_clients_err, IBMF_TNF_ERROR, 868 "", "ibmf_saa_notify_event_clients: %s, client = " 869 "0x%x\n", tnf_string, msg, 870 "could not allocate memory for taskq args", 871 tnf_opaque, client, client); 872 873 /* 874 * if a particular client was not specified continue 875 * processing the client list 876 */ 877 if (registering_client == NULL) 878 client = client->next; 879 else 880 client = NULL; 881 882 continue; 883 } 884 885 /* 886 * each task needs its own pointer, the task will free 887 * up this memory 888 */ 889 event_taskq_args->et_event_details = kmem_zalloc( 890 sizeof (ibmf_saa_event_details_t), KM_NOSLEEP); 891 if (event_taskq_args->et_event_details == NULL) { 892 893 IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, 894 ibmf_saa_notify_event_clients_err, IBMF_TNF_ERROR, 895 "", "ibmf_saa_notify_event_clients: %s, client = " 896 "0x%x\n", tnf_string, msg, 897 "could not allocate memory for taskq event details", 898 tnf_opaque, client, client); 899 900 kmem_free(event_taskq_args, 901 sizeof (ibmf_saa_event_taskq_args_t)); 902 903 /* 904 * if a particular client was not specified continue 905 * processing the client list 906 */ 907 client = 908 (registering_client == NULL) ? client->next: NULL; 909 910 continue; 911 } 912 913 mutex_enter(&client->saa_client_mutex); 914 915 /* 916 * don't generate callbacks if client is not active 917 * (it's probably closing the session) 918 */ 919 if (client->saa_client_state != SAA_CLIENT_STATE_ACTIVE) { 920 921 IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L2, 922 ibmf_saa_notify_event_clients, IBMF_TNF_TRACE, 923 "", "ibmf_saa_notify_event_clients: %s, client = " 924 "0x%x, state = 0x%x\n", tnf_string, msg, 925 "client state not active", 926 tnf_opaque, client, client, 927 tnf_opaque, state, client->saa_client_state); 928 929 mutex_exit(&client->saa_client_mutex); 930 931 kmem_free(event_taskq_args->et_event_details, 932 sizeof (ibmf_saa_event_details_t)); 933 934 kmem_free(event_taskq_args, 935 sizeof (ibmf_saa_event_taskq_args_t)); 936 937 /* 938 * if a particular client was not specified continue 939 * processing the client list 940 */ 941 client = 942 (registering_client == NULL) ? client->next: NULL; 943 944 continue; 945 } 946 947 /* 948 * increment the callback count so the client cannot close the 949 * session while callbacks are active 950 */ 951 client->saa_client_event_cb_num_active++; 952 953 mutex_exit(&client->saa_client_mutex); 954 955 event_taskq_args->et_client = client; 956 event_taskq_args->et_subnet_event = subnet_event; 957 958 bcopy(event_details, event_taskq_args->et_event_details, 959 sizeof (ibmf_saa_event_details_t)); 960 961 event_taskq_args->et_callback = client->saa_client_event_cb; 962 event_taskq_args->et_callback_arg = 963 client->saa_client_event_cb_arg; 964 965 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*event_taskq_args)) 966 967 /* dispatch taskq thread to notify client */ 968 status = taskq_dispatch(saa_statep->saa_event_taskq, 969 ibmf_saa_notify_event_client_task, event_taskq_args, 970 KM_NOSLEEP); 971 if (status == TASKQID_INVALID) { 972 973 IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, 974 ibmf_saa_notify_event_clients_err, IBMF_TNF_ERROR, 975 "", "ibmf_saa_notify_event_clients: %s, client = " 976 "0x%x\n", 977 tnf_string, msg, "Could not dispatch event taskq", 978 tnf_opaque, client, client); 979 980 kmem_free(event_taskq_args->et_event_details, 981 sizeof (ibmf_saa_event_details_t)); 982 983 kmem_free(event_taskq_args, 984 sizeof (ibmf_saa_event_taskq_args_t)); 985 986 /* 987 * decrement the callback count and signal a waiting 988 * client 989 */ 990 mutex_enter(&client->saa_client_mutex); 991 992 client->saa_client_event_cb_num_active--; 993 994 if (client->saa_client_event_cb_num_active == 0) { 995 996 cv_signal(&client->saa_client_event_cb_cv); 997 998 } 999 1000 mutex_exit(&client->saa_client_mutex); 1001 1002 } else { 1003 1004 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, 1005 ibmf_saa_notify_event_clients_err, IBMF_TNF_ERROR, 1006 "", "ibmf_saa_notify_event_clients: %s, client = " 1007 "0x%x\n", 1008 tnf_string, msg, "Dispatched task to notify client", 1009 tnf_opaque, client, client); 1010 } 1011 1012 1013 /* 1014 * if a particular client was not specified continue processing 1015 * the client list 1016 */ 1017 client = (registering_client == NULL) ? client->next: NULL; 1018 } 1019 1020 mutex_exit(&saa_portp->saa_pt_event_sub_mutex); 1021 1022 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, 1023 ibmf_saa_notify_event_clients_end, 1024 IBMF_TNF_TRACE, "", "ibmf_saa_notify_event_clients() exit\n"); 1025 } 1026 1027 /* 1028 * ibmf_saa_report_cb: 1029 * 1030 * Called when a forwarded notice Report is received by ibmf_saa from the SA. 1031 * Converts the Report into an ib_mad_notice_t and calls 1032 * ibmf_saa_notify_event_clients() which will notify each subscribed ibmf_saa 1033 * client. Also sends a response to the report to acknowledge to the SA that 1034 * this port is still up. 1035 * 1036 * This is the registered async callback with ibmf. Only Reports should come 1037 * through this interface as all other transactions with ibmf_saa are sequenced 1038 * (ibmf_saa makes the initial request). 1039 * 1040 * This function cannot block since it is called from an ibmf callback. 1041 * 1042 * Input Arguments 1043 * ibmf_handle ibmf handle 1044 * msgp pointer to ibmf_msg_t 1045 * args pointer to saa_port data 1046 * 1047 * Output Arguments 1048 * none 1049 * 1050 * Returns 1051 * none 1052 */ 1053 void 1054 ibmf_saa_report_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, 1055 void *args) 1056 { 1057 ib_mad_hdr_t *req_mad_hdr, *resp_mad_hdr; 1058 saa_port_t *saa_portp, *saa_port_list_entry; 1059 ibmf_retrans_t ibmf_retrans; 1060 int ibmf_status; 1061 ib_mad_notice_t *notice_report; 1062 saa_impl_trans_info_t *trans_info; 1063 boolean_t port_valid; 1064 uint16_t mad_status; 1065 uint16_t attr_id; 1066 boolean_t response_sent = B_FALSE; 1067 size_t length; 1068 int status; 1069 1070 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, 1071 ibmf_saa_report_cb_start, 1072 IBMF_TNF_TRACE, "", "ibmf_saa_report_cb() enter\n"); 1073 1074 _NOTE(ASSUMING_PROTECTED(*msgp)) 1075 1076 saa_portp = (saa_port_t *)args; 1077 1078 port_valid = B_FALSE; 1079 1080 /* check whether this portp is still valid */ 1081 mutex_enter(&saa_statep->saa_port_list_mutex); 1082 1083 saa_port_list_entry = saa_statep->saa_port_list; 1084 while (saa_port_list_entry != NULL) { 1085 1086 if (saa_port_list_entry == saa_portp) { 1087 1088 port_valid = ibmf_saa_is_valid(saa_portp, B_FALSE); 1089 1090 break; 1091 } 1092 saa_port_list_entry = saa_port_list_entry->next; 1093 } 1094 1095 mutex_exit(&saa_statep->saa_port_list_mutex); 1096 1097 if (port_valid == B_FALSE) { 1098 1099 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2, 1100 ibmf_saa_report_cb, IBMF_TNF_TRACE, "", 1101 "ibmf_saa_report_cb: %s, saa_port = 0x%p\n", 1102 tnf_string, msg, "port no longer valid", 1103 tnf_opaque, saa_portp, saa_portp); 1104 1105 goto bail; 1106 } 1107 1108 req_mad_hdr = msgp->im_msgbufs_recv.im_bufs_mad_hdr; 1109 1110 /* drop packet if status is bad */ 1111 if ((msgp->im_msg_status != IBMF_SUCCESS) || 1112 (req_mad_hdr == NULL) || 1113 ((mad_status = b2h16(req_mad_hdr->Status)) != SA_STATUS_NO_ERROR)) { 1114 1115 IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L1, 1116 ibmf_saa_report_cb, IBMF_TNF_TRACE, "", 1117 "ibmf_saa_report_cb: %s, msg_status = 0x%x," 1118 " req_mad_hdr = 0x%p, mad_status = 0x%x\n", 1119 tnf_string, msg, "Bad ibmf status", 1120 tnf_opaque, msg_status, msgp->im_msg_status, 1121 tnf_opaque, req_mad_hdr, req_mad_hdr, 1122 tnf_opaque, mad_status, 1123 (req_mad_hdr == NULL ? 0 : mad_status)); 1124 1125 goto bail; 1126 } 1127 1128 /* drop packet if class version is not correct */ 1129 if (req_mad_hdr->ClassVersion != SAA_MAD_CLASS_VERSION) { 1130 1131 IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L1, 1132 ibmf_saa_report_cb, IBMF_TNF_TRACE, "", 1133 "ibmf_saa_report_cb: %s, msg_class_ver = 0x%x," 1134 " ibmf_saa_class_ver = 0x%x\n", 1135 tnf_string, msg, "Bad class version", 1136 tnf_opaque, msg_class_ver, req_mad_hdr->ClassVersion, 1137 tnf_opaque, ibmf_saa_class_ver, SAA_MAD_CLASS_VERSION); 1138 1139 goto bail; 1140 } 1141 1142 1143 /* 1144 * only care about notice reports(); should not get any other type 1145 * of method or attribute 1146 */ 1147 if (((attr_id = b2h16(req_mad_hdr->AttributeID)) != SA_NOTICE_ATTRID) || 1148 (req_mad_hdr->R_Method != SA_SUBN_ADM_REPORT)) { 1149 1150 IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L2, 1151 ibmf_saa_report_cb, IBMF_TNF_TRACE, "", 1152 "ibmf_saa_report_cb: %s, attr_id = 0x%x, " 1153 "method = 0x%x\n", 1154 tnf_string, msg, "Unsolicited message not notice report", 1155 tnf_opaque, attr_id, attr_id, 1156 tnf_opaque, method, req_mad_hdr->R_Method); 1157 1158 goto bail; 1159 } 1160 1161 /* 1162 * unpack the data into a ib_mad_notice_t; the data details are left 1163 * as packed data and will be unpacked by process_subnet_event() 1164 * is_get_resp parameter is set to B_TRUE since cl_data_len will 1165 * probably be set to 200 bytes by ibmf (it's not an RMPP trans) 1166 */ 1167 status = ibmf_saa_utils_unpack_payload( 1168 msgp->im_msgbufs_recv.im_bufs_cl_data, 1169 msgp->im_msgbufs_recv.im_bufs_cl_data_len, SA_NOTICE_ATTRID, 1170 (void **)¬ice_report, &length, 0, B_TRUE, KM_NOSLEEP); 1171 if (status != IBMF_SUCCESS) { 1172 1173 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2, 1174 ibmf_saa_report_cb, IBMF_TNF_TRACE, "", 1175 "ibmf_saa_report_cb: %s, status = %d", 1176 tnf_string, msg, "Could not unpack data", 1177 tnf_int, status, status); 1178 1179 goto bail; 1180 } 1181 1182 ASSERT(length == sizeof (ib_mad_notice_t)); 1183 1184 ibmf_saa_process_subnet_event(saa_portp, notice_report); 1185 1186 kmem_free(notice_report, length); 1187 1188 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*resp_mad_hdr)) 1189 1190 /* send ReportResp */ 1191 resp_mad_hdr = kmem_zalloc(sizeof (ib_mad_hdr_t), KM_SLEEP); 1192 1193 bcopy(req_mad_hdr, resp_mad_hdr, sizeof (ib_mad_hdr_t)); 1194 1195 resp_mad_hdr->R_Method = SA_SUBN_ADM_REPORT_RESP; 1196 1197 msgp->im_msgbufs_send.im_bufs_mad_hdr = resp_mad_hdr; 1198 msgp->im_msgbufs_send.im_bufs_cl_hdr = kmem_zalloc( 1199 msgp->im_msgbufs_recv.im_bufs_cl_hdr_len, KM_SLEEP); 1200 msgp->im_msgbufs_send.im_bufs_cl_hdr_len = 1201 msgp->im_msgbufs_recv.im_bufs_cl_hdr_len; 1202 1203 /* only headers are needed */ 1204 msgp->im_msgbufs_send.im_bufs_cl_data = NULL; 1205 msgp->im_msgbufs_send.im_bufs_cl_data_len = 0; 1206 1207 /* 1208 * report_cb cannot block because it's in the context of an ibmf 1209 * callback. So the response needs to be sent asynchronously. 1210 * ibmf_saa_async_cb is an appropriate callback to use for the response. 1211 * Set up a trans_info structure as saa_async_cb expects. But don't use 1212 * ibmf_saa_impl_send_request() to send the response since that function 1213 * does unncessary steps in this case (like allocating a new ibmf msg). 1214 * Only the si_trans_port field needs to be filled in. 1215 */ 1216 trans_info = kmem_zalloc(sizeof (saa_impl_trans_info_t), KM_NOSLEEP); 1217 if (trans_info == NULL) { 1218 1219 IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1, 1220 ibmf_saa_report_cb_err, IBMF_TNF_TRACE, "", 1221 "ibmf_saa_report_cb: %s", 1222 tnf_string, msg, "could not allocate trans_info structure"); 1223 1224 goto bail; 1225 } 1226 1227 trans_info->si_trans_port = saa_portp; 1228 1229 mutex_enter(&saa_portp->saa_pt_mutex); 1230 1231 bcopy(&saa_portp->saa_pt_ibmf_retrans, &ibmf_retrans, 1232 sizeof (ibmf_retrans_t)); 1233 1234 saa_portp->saa_pt_num_outstanding_trans++; 1235 1236 mutex_exit(&saa_portp->saa_pt_mutex); 1237 1238 ASSERT(ibmf_handle == saa_portp->saa_pt_ibmf_handle); 1239 1240 ibmf_status = ibmf_msg_transport(ibmf_handle, 1241 saa_portp->saa_pt_qp_handle, msgp, &ibmf_retrans, ibmf_saa_async_cb, 1242 trans_info, 0); 1243 if (ibmf_status != IBMF_SUCCESS) { 1244 1245 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L1, 1246 ibmf_saa_report_cb, IBMF_TNF_TRACE, "", 1247 "ibmf_saa_report_cb: %s, msg_status = 0x%x\n", 1248 tnf_string, msg, "Could not send report response", 1249 tnf_int, ibmf_status, ibmf_status); 1250 1251 mutex_enter(&saa_portp->saa_pt_mutex); 1252 1253 ASSERT(saa_portp->saa_pt_num_outstanding_trans > 0); 1254 saa_portp->saa_pt_num_outstanding_trans--; 1255 1256 mutex_exit(&saa_portp->saa_pt_mutex); 1257 1258 kmem_free(trans_info, sizeof (saa_impl_trans_info_t)); 1259 1260 } else { 1261 1262 IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, 1263 ibmf_saa_report_cb, IBMF_TNF_TRACE, "", 1264 "ibmf_saa_report_cb: %s\n", 1265 tnf_string, msg, "Asynchronous Report response sent"); 1266 1267 response_sent = B_TRUE; 1268 } 1269 1270 bail: 1271 if (response_sent == B_FALSE) { 1272 ibmf_status = ibmf_free_msg(ibmf_handle, &msgp); 1273 ASSERT(ibmf_status == IBMF_SUCCESS); 1274 } 1275 1276 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, 1277 ibmf_saa_informinfo_cb_end, IBMF_TNF_TRACE, "", 1278 "ibmf_saa_report_cb() exit\n"); 1279 } 1280 1281 /* 1282 * ibmf_saa_add_event_subscriber: 1283 * 1284 * Adds an interested client to the list of subscribers for events for a port. 1285 * If it's the first client, generates the subscription requests. 1286 * This function must only be called if event_args is not null 1287 * 1288 * Input Arguments 1289 * 1290 * client pointer to client data (client->saa_port should be set) 1291 * event_args pointer to event_args passed in from client (non-NULL) 1292 * 1293 * Output Arguments 1294 * none 1295 * 1296 * Returns 1297 * void 1298 */ 1299 void 1300 ibmf_saa_add_event_subscriber(saa_client_data_t *client, 1301 ibmf_saa_subnet_event_args_t *event_args) 1302 { 1303 saa_port_t *saa_portp; 1304 boolean_t first_client; 1305 uint8_t producer_status_mask; 1306 ibmf_saa_event_details_t event_details; 1307 1308 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, 1309 ibmf_saa_add_event_subscriber_start, IBMF_TNF_TRACE, "", 1310 "ibmf_saa_add_event_subscriber() enter\n"); 1311 1312 /* event_args should be checked before calling this function */ 1313 ASSERT(event_args != NULL); 1314 1315 /* don't add client if no callback function is specified */ 1316 if (event_args->is_event_callback == NULL) 1317 return; 1318 1319 saa_portp = client->saa_client_port; 1320 1321 client->saa_client_event_cb = event_args->is_event_callback; 1322 client->saa_client_event_cb_arg = event_args->is_event_callback_arg; 1323 1324 /* 1325 * insert this client onto the list; this list is used when a 1326 * Report arrives to call each client's callback 1327 */ 1328 mutex_enter(&saa_portp->saa_pt_event_sub_mutex); 1329 1330 IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, 1331 ibmf_sa_session_open, IBMF_TNF_TRACE, "", 1332 "ibmf_saa_add_event_subscriber: %s, client = 0x%x\n", 1333 tnf_string, msg, "Adding client to event subscriber list", 1334 tnf_opaque, client, client); 1335 1336 if (saa_portp->saa_pt_event_sub_client_list == NULL) 1337 first_client = B_TRUE; 1338 else { 1339 first_client = B_FALSE; 1340 producer_status_mask = 1341 saa_portp->saa_pt_event_sub_last_success_mask; 1342 } 1343 1344 client->next = saa_portp->saa_pt_event_sub_client_list; 1345 saa_portp->saa_pt_event_sub_client_list = client; 1346 1347 mutex_exit(&saa_portp->saa_pt_event_sub_mutex); 1348 1349 if (first_client == B_TRUE) { 1350 1351 /* 1352 * increment the reference count by one to account for 1353 * the subscription requests. All four InformInfo's are 1354 * sent as one port client reference. 1355 */ 1356 mutex_enter(&saa_portp->saa_pt_mutex); 1357 1358 saa_portp->saa_pt_reference_count++; 1359 1360 mutex_exit(&saa_portp->saa_pt_mutex); 1361 1362 /* subscribe for subnet events */ 1363 ibmf_saa_subscribe_events(saa_portp, B_TRUE, B_FALSE); 1364 1365 } else if (producer_status_mask != IBMF_SAA_PORT_EVENT_SUB_ALL_ARRIVE) { 1366 1367 /* 1368 * if this is not the first client and the producer status mask 1369 * is not all success, generate a callback to indicate to the 1370 * client that not all events will be forwarded 1371 */ 1372 bzero(&event_details, sizeof (ibmf_saa_event_details_t)); 1373 1374 event_details.ie_producer_event_status_mask = 1375 producer_status_mask; 1376 1377 ibmf_saa_notify_event_clients(saa_portp, &event_details, 1378 IBMF_SAA_EVENT_SUBSCRIBER_STATUS_CHG, client); 1379 } 1380 1381 IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, 1382 ibmf_saa_add_event_subscriber_end, IBMF_TNF_TRACE, "", 1383 "ibmf_saa_add_event_subscriber() exit\n"); 1384 } 1385