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