xref: /illumos-gate/usr/src/uts/common/io/ib/mgt/ibmf/ibmf_saa_events.c (revision fc8ae2ec4282de7ec96f48e11078345f3dc0ac3d)
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 **)&notice_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