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
ibmf_saa_subscribe_events(saa_port_t * saa_portp,boolean_t subscribe,boolean_t unseq_unsubscribe)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
ibmf_saa_send_informinfo(saa_port_t * saa_portp,uint32_t producer_type,boolean_t subscribe,boolean_t unseq_unsubscribe)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
ibmf_saa_informinfo_cb(void * arg,size_t length,char * buffer,int status,uint32_t producer_type)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
ibmf_saa_notify_event_client_task(void * args)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
ibmf_saa_process_subnet_event(saa_port_t * saa_portp,ib_mad_notice_t * notice)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
ibmf_saa_notify_event_clients(saa_port_t * saa_portp,ibmf_saa_event_details_t * event_details,ibmf_saa_subnet_event_t subnet_event,saa_client_data_t * registering_client)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 == 0) {
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
ibmf_saa_report_cb(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)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
ibmf_saa_add_event_subscriber(saa_client_data_t * client,ibmf_saa_subnet_event_args_t * event_args)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