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