xref: /titanic_51/usr/src/uts/common/io/ib/mgt/ibmf/ibmf_saa_impl.c (revision 8e55d2638713a256e1e595d733e9ea6900834744)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/ib/mgt/ibmf/ibmf_saa_impl.h>
27 #include <sys/ib/mgt/ibmf/ibmf_saa_utils.h>
28 
29 /* Global sa_access State Pointer */
30 saa_state_t *saa_statep;
31 _NOTE(READ_ONLY_DATA(saa_statep))
32 
33 extern	int	ibmf_trace_level;
34 
35 extern	int	ibmf_taskq_max_tasks;
36 
37 static int
38 ibmf_saa_impl_new_smlid_retry(saa_port_t *saa_portp, ibmf_msg_t *msgp,
39     ibmf_msg_cb_t ibmf_callback, void *ibmf_callback_arg, int transport_flags);
40 static int
41 ibmf_saa_impl_revert_to_qp1(saa_port_t *saa_portp, ibmf_msg_t *msgp,
42     ibmf_msg_cb_t ibmf_callback, void *ibmf_callback_args, int transport_flags);
43 static int
44 ibmf_saa_check_sa_and_retry(saa_port_t *saa_portp, ibmf_msg_t *msgp,
45     ibmf_msg_cb_t ibmf_callback, void *ibmf_callback_arg,
46     hrtime_t trans_send_time, int transport_flags);
47 static int ibmf_saa_impl_init_msg(saa_impl_trans_info_t *trans_info,
48     boolean_t sleep_flag, ibmf_msg_t **msgp, uint32_t *transport_flagsp,
49     ibmf_retrans_t *ibmf_retransp);
50 static int ibmf_saa_must_purge(saa_port_t *saa_portp);
51 static void ibmf_saa_impl_invalidate_port(saa_port_t *saa_portp);
52 static void ibmf_saa_impl_destroy_port(saa_port_t *saa_portp);
53 static void ibmf_saa_impl_uninit_kstats(saa_port_t *saa_portp);
54 static void ibmf_saa_impl_get_cpi_cb(void *arg, size_t length, char *buffer,
55     int status);
56 static void ibmf_saa_impl_async_event_cb(ibmf_handle_t ibmf_handle,
57     void *clnt_private, ibmf_async_event_t event_type);
58 static void ibmf_saa_impl_port_up(ib_guid_t ci_guid, uint8_t port_num);
59 static void ibmf_saa_impl_port_down(ib_guid_t ci_guid, uint8_t port_num);
60 static void ibmf_saa_impl_port_chg(ibt_async_event_t *event);
61 static void ibmf_saa_impl_client_rereg(ib_guid_t ci_guid, uint8_t port_num);
62 static void ibmf_saa_impl_hca_detach(saa_port_t *saa_removed);
63 static void ibmf_saa_impl_prepare_response(ibmf_handle_t ibmf_handle,
64     ibmf_msg_t *msgp, boolean_t ignore_data, int *status, void **result,
65     size_t *length, boolean_t sleep_flag);
66 static int ibmf_saa_impl_check_sa_support(uint16_t cap_mask, uint16_t attr_id);
67 static uint_t ibmf_saa_impl_get_attr_id_length(uint16_t attr_id);
68 static void ibmf_saa_impl_free_msg(ibmf_handle_t ibmf_hdl, ibmf_msg_t *msgp);
69 static int ibmf_saa_impl_get_port_guid(ibt_hca_portinfo_t *ibt_portinfop,
70     ib_guid_t *guid_ret);
71 static void ibmf_saa_impl_set_transaction_params(saa_port_t *saa_portp,
72     ibt_hca_portinfo_t *portinfop);
73 static void ibmf_saa_impl_update_sa_address_info(saa_port_t *saa_portp,
74     ibmf_msg_t *msgp);
75 static int ibmf_saa_impl_ibmf_unreg(saa_port_t *saa_portp);
76 
77 int	ibmf_saa_max_wait_time = IBMF_SAA_MAX_WAIT_TIME_IN_SECS;
78 int	ibmf_saa_trans_wait_time = IBMF_SAA_TRANS_WAIT_TIME_IN_SECS;
79 int	ibmf_saa_max_resp_time = IBMF_SAA_MAX_RESP_TIME;
80 int	ibmf_saa_max_subnet_timeout = IBMF_SAA_MAX_SUBNET_TIMEOUT;
81 int	ibmf_saa_retrans_retries = IBMF_SAA_RETRANS_RETRIES;
82 
83 /*
84  * ibmf_saa_impl_init:
85  * Allocates memory for the ibmf_saa state structure and initializes the taskq.
86  * Called from the modules init() routine.
87  *
88  * Input Arguments
89  * none
90  *
91  * Output Arguments
92  * none
93  *
94  * Returns
95  * IBMF_NO_RESOURCES if taskq could not be created.
96  * IBMF_SUCCESS on success
97  *
98  */
99 int
100 ibmf_saa_impl_init()
101 {
102 	int		res;
103 
104 	/* CONSTCOND */
105 	ASSERT(NO_COMPETING_THREADS);
106 
107 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_init_start,
108 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_init() enter\n");
109 
110 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*saa_statep))
111 
112 	saa_statep = kmem_zalloc(sizeof (saa_state_t), KM_SLEEP);
113 
114 	/* create taskq for notifying event subscribers */
115 	saa_statep->saa_event_taskq = taskq_create(
116 	    "ibmf_saa_event_taskq", IBMF_TASKQ_NTHREADS,
117 	    MINCLSYSPRI, 1, ibmf_taskq_max_tasks, TASKQ_DYNAMIC |
118 	    TASKQ_PREPOPULATE);
119 	if (saa_statep->saa_event_taskq == NULL) {
120 
121 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L4,
122 		    ibmf_saa_impl_init_end_err,
123 		    IBMF_TNF_TRACE, "", "ibmf_saa_impl_init(): %s\n",
124 		    tnf_string, msg, "event taskq create failed");
125 
126 		kmem_free(saa_statep, sizeof (saa_state_t));
127 
128 		res = IBMF_NO_RESOURCES;
129 
130 		goto bail;
131 	}
132 
133 	mutex_init(&saa_statep->saa_port_list_mutex, NULL, MUTEX_DRIVER,
134 	    NULL);
135 
136 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*saa_statep))
137 
138 	res = IBMF_SUCCESS;
139 bail:
140 
141 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_saa_impl_init_end,
142 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_init() exit: status = %d\n",
143 	    tnf_int, res, res);
144 
145 	return (res);
146 }
147 
148 /*
149  * ibmf_saa_impl_fini:
150  * If there are no registered clients, cleans up all memory associated with the
151  * state, including each of the port list entries.
152  * Called from the modules fini() routine.
153  *
154  * Input Arguments
155  * none
156  *
157  * Output Arguments
158  * none
159  *
160  * Returns
161  * EBUSY if there are outstanding transactions or registered clients
162  * 0 if cleanup was sucessfull
163  *
164  */
165 int
166 ibmf_saa_impl_fini()
167 {
168 	int		ret = 0;
169 	saa_port_t	*saa_portp;
170 	saa_port_t	*next;
171 
172 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_fini_start,
173 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_fini() enter\n");
174 
175 	/* make sure there are no registered clients */
176 	mutex_enter(&saa_statep->saa_port_list_mutex);
177 
178 	saa_portp = saa_statep->saa_port_list;
179 	while (saa_portp != NULL) {
180 
181 		mutex_enter(&saa_portp->saa_pt_mutex);
182 
183 		if (saa_portp->saa_pt_reference_count > 0) {
184 
185 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
186 			    ibmf_saa_impl_fini_err, IBMF_TNF_ERROR, "",
187 			    "ibmf_saa_impl_fini: %s, port %016" PRIx64 "\n",
188 			    tnf_string, msg,
189 			    "cannot unload ibmf_saa. Client on port still"
190 			    " registered", tnf_opaque, port,
191 			    saa_portp->saa_pt_port_guid);
192 
193 			mutex_exit(&saa_portp->saa_pt_mutex);
194 
195 			mutex_exit(&saa_statep->saa_port_list_mutex);
196 
197 			ret = EBUSY;
198 			goto bail;
199 		}
200 
201 		/* make sure there are no outstanding transactions */
202 
203 		if (saa_portp->saa_pt_num_outstanding_trans > 0) {
204 
205 			IBMF_TRACE_3(IBMF_TNF_NODEBUG, DPRINT_L1,
206 			    ibmf_saa_impl_fini_err, IBMF_TNF_ERROR, "",
207 			    "ibmf_saa_impl_fini: %s, port = %016" PRIx64
208 			    ", num transactions = %d\n",
209 			    tnf_string, msg, "Cannot unload ibmf_saa."
210 			    "  Outstanding transactions on port.",
211 			    tnf_opaque, port,
212 			    saa_portp->saa_pt_port_guid,
213 			    tnf_uint, outstanding_transactions,
214 			    saa_portp->saa_pt_num_outstanding_trans);
215 
216 			mutex_exit(&saa_portp->saa_pt_mutex);
217 
218 			mutex_exit(&saa_statep->saa_port_list_mutex);
219 
220 			ret = EBUSY;
221 			goto bail;
222 		}
223 
224 		mutex_exit(&saa_portp->saa_pt_mutex);
225 
226 		saa_portp = saa_portp->next;
227 	}
228 
229 	mutex_exit(&saa_statep->saa_port_list_mutex);
230 
231 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(saa_statep->saa_port_list,
232 	    *saa_portp))
233 
234 	/*
235 	 * no more clients nor pending transaction:
236 	 * unregister ibmf and destroy port entries
237 	 */
238 	while (saa_statep->saa_port_list != NULL) {
239 
240 		saa_portp = saa_statep->saa_port_list;
241 		next = saa_portp->next;
242 
243 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
244 		    ibmf_saa_impl_fini, IBMF_TNF_TRACE, "",
245 		    "ibmf_saa_impl_fini: %s, prefix = %016" PRIx64 "\n",
246 		    tnf_string, msg, "deinitializing port",
247 		    tnf_opaque, port_guid, saa_portp->saa_pt_port_guid);
248 
249 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*saa_portp))
250 
251 		mutex_enter(&saa_portp->saa_pt_mutex);
252 
253 		/* unregister from ibmf */
254 		if (saa_portp->saa_pt_state == IBMF_SAA_PORT_STATE_READY) {
255 
256 			mutex_exit(&saa_portp->saa_pt_mutex);
257 
258 			if (ibmf_saa_impl_ibmf_unreg(saa_portp)
259 			    != IBMF_SUCCESS) {
260 				ret = EBUSY;
261 				goto bail;
262 			}
263 		} else
264 			mutex_exit(&saa_portp->saa_pt_mutex);
265 
266 		ibmf_saa_impl_destroy_port(saa_portp);
267 
268 		saa_statep->saa_port_list = next;
269 	}
270 
271 	taskq_destroy(saa_statep->saa_event_taskq);
272 
273 	mutex_destroy(&saa_statep->saa_port_list_mutex);
274 
275 	kmem_free(saa_statep, sizeof (saa_state_t));
276 
277 bail:
278 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_fini_end,
279 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_fini() exit\n");
280 
281 	return (ret);
282 }
283 
284 /*
285  * ibmf_saa_is_valid
286  * Returns true the entry is valid.
287  *
288  * Input Arguments
289  * saa_portp		pointer to state structure
290  * add_ref 		if B_TRUE ref count is incremented on a valid portp
291  *
292  * Output Arguments
293  * none
294  *
295  * Returns
296  * B_TRUE if entry was in a valid state, B_FALSE otherwise
297  */
298 boolean_t
299 ibmf_saa_is_valid(saa_port_t *saa_portp, int add_ref)
300 {
301 	boolean_t is_valid = B_TRUE;
302 
303 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_is_valid_start,
304 	    IBMF_TNF_TRACE, "", "ibmf_saa_is_valid() enter\n");
305 
306 	mutex_enter(&saa_portp->saa_pt_mutex);
307 
308 	if (saa_portp->saa_pt_state == IBMF_SAA_PORT_STATE_INVALID ||
309 	    saa_portp->saa_pt_state == IBMF_SAA_PORT_STATE_PURGING) {
310 
311 		is_valid = B_FALSE;
312 
313 	} else if (add_ref == B_TRUE) {
314 		/*
315 		 * increment reference count here to ensure that
316 		 * entry does not get purged behind our backs
317 		 */
318 		saa_portp->saa_pt_reference_count++;
319 	}
320 	mutex_exit(&saa_portp->saa_pt_mutex);
321 
322 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_is_valid_end,
323 	    IBMF_TNF_TRACE, "", "ibmf_saa_is_valid() exit\n");
324 
325 	return (is_valid);
326 }
327 
328 /*
329  * ibmf_saa_must_purge
330  * Determines if we can purge a portp (remove it from the list) based on the
331  * state and number of clients
332  *
333  * Input Arguments
334  * saa_portp		pointer to state structure
335  *
336  * Output Arguments
337  * none
338  *
339  * Returns
340  * B_TRUE if the entry can be removed, B_FALSE otherwise
341  */
342 static int
343 ibmf_saa_must_purge(saa_port_t *saa_portp)
344 {
345 	int must_purge = B_FALSE;
346 
347 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_must_purge_start,
348 	    IBMF_TNF_TRACE, "", "ibmf_saa_must_purge() enter\n");
349 
350 	mutex_enter(&saa_portp->saa_pt_mutex);
351 
352 	if (saa_portp->saa_pt_state == IBMF_SAA_PORT_STATE_INVALID &&
353 	    saa_portp->saa_pt_reference_count == 0) {
354 
355 		saa_portp->saa_pt_state = IBMF_SAA_PORT_STATE_PURGING;
356 		must_purge = B_TRUE;
357 	}
358 
359 	mutex_exit(&saa_portp->saa_pt_mutex);
360 
361 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_must_purge_end,
362 	    IBMF_TNF_TRACE, "", "ibmf_saa_must_purge() exit\n");
363 
364 	return (must_purge);
365 }
366 
367 
368 /*
369  * ibmf_saa_impl_purge:
370  * Removes invalid port state entries from the list
371  *
372  * Input Arguments
373  * none
374  *
375  * Output Arguments
376  * none
377  *
378  * Returns
379  * void
380  */
381 void
382 ibmf_saa_impl_purge()
383 {
384 	saa_port_t *cur_portp  = NULL;
385 	saa_port_t *prev_portp = NULL;
386 	saa_port_t *rem_portp  = NULL;
387 
388 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_purge_start,
389 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_purge() enter\n");
390 
391 	mutex_enter(&saa_statep->saa_port_list_mutex);
392 
393 	cur_portp = saa_statep->saa_port_list;
394 	prev_portp = cur_portp;
395 
396 	while (cur_portp != NULL) {
397 
398 		if (ibmf_saa_must_purge(cur_portp) == B_TRUE) {
399 
400 			rem_portp = cur_portp;
401 
402 			/* unlink entry */
403 			if (cur_portp == saa_statep->saa_port_list) {
404 
405 				saa_statep->saa_port_list = cur_portp->next;
406 				cur_portp = saa_statep->saa_port_list;
407 				prev_portp = cur_portp;
408 
409 			} else {
410 
411 				prev_portp->next = cur_portp->next;
412 				cur_portp = cur_portp->next;
413 			}
414 
415 			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rem_portp))
416 
417 			/* destroy entry */
418 			ASSERT(rem_portp != NULL);
419 			ibmf_saa_impl_destroy_port(rem_portp);
420 
421 		} else {
422 
423 			prev_portp = cur_portp;
424 			cur_portp = cur_portp->next;
425 		}
426 	}
427 
428 	mutex_exit(&saa_statep->saa_port_list_mutex);
429 
430 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_purge_end,
431 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_purge() exit\n");
432 }
433 
434 /*
435  * saa_impl_add_client:
436  * Adds a client for a particular portp.  Reference count has been incremented
437  * before this call.  It is decremented by saa_impl_add_client() if the call
438  * fails.
439  *
440  * Input Arguments
441  * none
442  *
443  * Output Arguments
444  * none
445  *
446  * Returns
447  * IBMF_BUSY if there are already too many clients registered,
448  * IBMF_BAD_PORT_STATE if the port is invalid (generally because a previous
449  * client failed during registration for this port)
450  * IBMF_SUCCESS otherwise
451  */
452 int
453 ibmf_saa_impl_add_client(saa_port_t *saa_portp)
454 {
455 	int status = IBMF_SUCCESS;
456 
457 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_add_client_start,
458 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_add_client() enter\n");
459 
460 	mutex_enter(&saa_portp->saa_pt_mutex);
461 
462 	/*
463 	 * check that we don't exceed max clients
464 	 */
465 	if (saa_portp->saa_pt_reference_count >
466 	    SAA_MAX_CLIENTS_PER_PORT) {
467 
468 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
469 		    ibmf_saa_impl_add_client_err, IBMF_TNF_ERROR, "",
470 		    "ibmf_saa_impl_add_client: %s, num_reg_clients %d\n",
471 		    tnf_string, msg, "too many clients registered for"
472 		    " port", tnf_uint, num_reg_clients,
473 		    saa_portp->saa_pt_reference_count);
474 
475 		status = IBMF_BUSY;
476 		goto bail;
477 	}
478 
479 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
480 	    ibmf_saa_impl_add_client, IBMF_TNF_TRACE, "",
481 	    "ibmf_saa_impl_add_client: num_registered_clients %d\n",
482 	    tnf_uint, num_registered_clients,
483 	    saa_portp->saa_pt_reference_count);
484 
485 	/*
486 	 * wait until anyone who is currently registering
487 	 * this port with ibmf is done
488 	 */
489 	while (saa_portp->saa_pt_state == IBMF_SAA_PORT_STATE_REGISTERING) {
490 
491 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
492 		    ibmf_saa_impl_add_client, IBMF_TNF_TRACE, "",
493 		    "ibmf_saa_impl_add_client: %s\n",
494 		    tnf_string, msg, "someone is registering. waiting"
495 		    " for them to finish");
496 
497 		cv_wait(&saa_portp->saa_pt_ibmf_reg_cv,
498 		    &saa_portp->saa_pt_mutex);
499 
500 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
501 		    ibmf_saa_impl_add_client,
502 		    IBMF_TNF_TRACE, "", "ibmf_saa_impl_add_client: %s\n",
503 		    tnf_string, msg, "done waiting");
504 	}
505 
506 	/*
507 	 * if port isn't ready here, fail.
508 	 */
509 	if (saa_portp->saa_pt_state != IBMF_SAA_PORT_STATE_READY) {
510 
511 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
512 		    ibmf_saa_impl_add_client_err, IBMF_TNF_ERROR,
513 		    "", "ibmf_saa_impl_add_client: %s\n",
514 		    tnf_string, msg, "port state not ready,"
515 		    " removing client.");
516 
517 		status = IBMF_BAD_PORT_STATE;
518 		goto bail;
519 	}
520 
521 bail:
522 	mutex_exit(&saa_portp->saa_pt_mutex);
523 
524 	if (status != IBMF_SUCCESS) {
525 
526 		mutex_enter(&saa_portp->saa_pt_kstat_mutex);
527 
528 		IBMF_SAA_ADD32_KSTATS(saa_portp,
529 		    clients_reg_failed, 1);
530 
531 		mutex_exit(&saa_portp->saa_pt_kstat_mutex);
532 
533 		/* decrementing refcount is last thing we do on entry */
534 
535 		mutex_enter(&saa_portp->saa_pt_mutex);
536 
537 		ASSERT(saa_portp->saa_pt_reference_count > 0);
538 		saa_portp->saa_pt_reference_count--;
539 
540 		mutex_exit(&saa_portp->saa_pt_mutex);
541 	}
542 
543 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
544 	    ibmf_saa_impl_add_client_end, IBMF_TNF_TRACE, "",
545 	    "ibmf_saa_impl_add_client() exit\n");
546 
547 	return (status);
548 }
549 
550 /*
551  * ibmf_saa_impl_create_port()
552  * Create port entry with mimimal inits because
553  * we're holding the list mutex: NO BLOCKING CALLS HERE, please.
554  *
555  * Initialize port state to "registering", so that clients accessing
556  * same port concurrently will wait for the end of the ibmf registration.
557  * Note: this thread will access port members without locking mutex.
558  *
559  * Input Arguments
560  * pt_guid		guid of port
561  *
562  * Output Arguments
563  * saa_portpp		pointer to new saa_portp structure
564  *
565  * Returns
566  * IBMF_NO_MEMORY if memory could not be allocated
567  * IBMF_SUCCESS otherwise
568  */
569 int
570 ibmf_saa_impl_create_port(ib_guid_t pt_guid, saa_port_t **saa_portpp)
571 {
572 	int		status		= IBMF_SUCCESS;
573 	saa_port_t	*saa_portp	= NULL;
574 
575 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_saa_impl_create_port_start,
576 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_create_port:"
577 	    " guid %016" PRIx64 "\n",
578 	    tnf_opaque, port_guid, pt_guid);
579 
580 	ASSERT(MUTEX_HELD(&saa_statep->saa_port_list_mutex));
581 
582 	/* create & initialize new port */
583 	saa_portp = kmem_zalloc(sizeof (saa_port_t), KM_NOSLEEP);
584 
585 	if (saa_portp == NULL) {
586 
587 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
588 		    ibmf_sa_session_open_err, IBMF_TNF_ERROR, "",
589 		    "ibmf_saa_impl_create_port: %s\n",
590 		    tnf_string, msg, "could not allocate memory for "
591 		    "new port");
592 
593 		status = IBMF_NO_MEMORY;
594 		goto bail;
595 	}
596 
597 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_sa_session_open,
598 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_create_port: %s\n",
599 	    tnf_string, msg, "first client registering, initializing");
600 
601 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*saa_portp))
602 
603 	/* tell everyone that kstats are not initialized */
604 	saa_portp->saa_pt_kstatp = NULL;
605 
606 	/*
607 	 * set up mutexe and state variable to indicate to
608 	 * other clients that were currently in the process of
609 	 * setting up the port data.  This will prevent a subsequent
610 	 * client from trying to to register with ibmf before the
611 	 * port data has been initialized.
612 	 */
613 	mutex_init(&saa_portp->saa_pt_mutex, NULL, MUTEX_DRIVER, NULL);
614 	cv_init(&saa_portp->saa_pt_ibmf_reg_cv, NULL, CV_DRIVER, NULL);
615 
616 	saa_portp->saa_pt_state = IBMF_SAA_PORT_STATE_REGISTERING;
617 
618 	/* create other mutexes */
619 	mutex_init(&saa_portp->saa_pt_kstat_mutex, NULL, MUTEX_DRIVER, NULL);
620 
621 	mutex_init(&saa_portp->saa_pt_event_sub_mutex, NULL, MUTEX_DRIVER,
622 	    NULL);
623 
624 	/*
625 	 * clients assume all arrive; set mask to this so we only notify
626 	 * if something failed
627 	 */
628 	saa_portp->saa_pt_event_sub_last_success_mask =
629 	    IBMF_SAA_PORT_EVENT_SUB_ALL_ARRIVE;
630 
631 	/*
632 	 * set port_guid now so any immediately subsequent clients
633 	 * registering on this port, guid will know we're already here
634 	 */
635 	saa_portp->saa_pt_port_guid = pt_guid;
636 	saa_portp->saa_pt_reference_count = 1;
637 	saa_portp->saa_pt_current_tid = pt_guid << 32;
638 
639 	saa_portp->saa_pt_redirect_active = B_FALSE;
640 
641 	/* set sa_uptime now in case we never receive anything from SA */
642 	saa_portp->saa_pt_sa_uptime = gethrtime();
643 
644 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*saa_portp))
645 
646 	/* Set new pointer in caller's */
647 	*saa_portpp = saa_portp;
648 
649 bail:
650 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_create_port_end,
651 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_create_port() exit\n");
652 
653 	return (status);
654 }
655 
656 /*
657  * ibmf_saa_impl_invalidate_port:
658  * invalidates port entry (assumes exist) and deletes kstat object
659  * kstat object is destroyed in order to allow creating port entry
660  * even if this entry is not purged
661  */
662 static void
663 ibmf_saa_impl_invalidate_port(saa_port_t *saa_portp)
664 {
665 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
666 	    ibmf_saa_impl_invalidate_port_start,
667 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_invalidate_port() enter\n");
668 
669 	ASSERT(saa_portp != NULL);
670 	ASSERT(MUTEX_HELD(&saa_portp->saa_pt_mutex));
671 
672 	saa_portp->saa_pt_state = IBMF_SAA_PORT_STATE_INVALID;
673 	ibmf_saa_impl_uninit_kstats(saa_portp);
674 
675 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
676 	    ibmf_saa_impl_invalidate_port_end,
677 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_invalidate_port() exit\n");
678 }
679 
680 /*
681  * ibmf_saa_impl_destroy_port:
682  * Frees the resources associated with an saa_portp structure.  Assumes the
683  * saa_portp exists
684  *
685  * Input Arguments
686  * saa_portp		pointer to saa_portp structure
687  *
688  * Output Arguments
689  * none
690  *
691  * Returns
692  * void
693  */
694 static void
695 ibmf_saa_impl_destroy_port(saa_port_t *saa_portp)
696 {
697 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_destroy_start,
698 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_destroy() enter\n");
699 
700 	ASSERT(saa_portp != NULL);
701 
702 	_NOTE(ASSUMING_PROTECTED(*saa_portp))
703 
704 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
705 	    ibmf_saa_impl_destroy, IBMF_TNF_TRACE, "",
706 	    "ibmf_saa_impl_destroy(): destroying port_guid %016" PRIx64 "\n",
707 	    tnf_opaque, port_guid, saa_portp->saa_pt_port_guid);
708 
709 	ibmf_saa_impl_uninit_kstats(saa_portp);
710 
711 	/* uninit synchronization variables used for registration */
712 	mutex_destroy(&saa_portp->saa_pt_mutex);
713 	cv_destroy(&saa_portp->saa_pt_ibmf_reg_cv);
714 
715 	mutex_destroy(&saa_portp->saa_pt_event_sub_mutex);
716 	mutex_destroy(&saa_portp->saa_pt_kstat_mutex);
717 
718 	kmem_free(saa_portp, sizeof (saa_port_t));
719 
720 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_destroy_end,
721 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_destroy() exit\n");
722 }
723 
724 /*
725  * ibmf_saa_impl_init_kstats:
726  * Create kstats structure.  Should be called when memory is alloced for a new
727  * port entry.
728  */
729 int
730 ibmf_saa_impl_init_kstats(saa_port_t *saa_portp)
731 {
732 	char			buf[128];
733 	ibmf_saa_kstat_t	*ksp;
734 
735 	_NOTE(ASSUMING_PROTECTED(saa_portp->saa_pt_kstatp))
736 
737 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
738 	    ibmf_saa_impl_init_kstats_start,
739 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_init_kstats() enter\n");
740 
741 	/* set up kstats structure */
742 	(void) sprintf(buf, "ibmf_saa_%016" PRIx64 "_stat",
743 	    saa_portp->saa_pt_port_guid);
744 
745 	saa_portp->saa_pt_kstatp = kstat_create("ibmf_saa",
746 	    0, buf, "misc", KSTAT_TYPE_NAMED,
747 	    sizeof (ibmf_saa_kstat_t) / sizeof (kstat_named_t),
748 	    KSTAT_FLAG_WRITABLE);
749 
750 	if (saa_portp->saa_pt_kstatp == NULL)
751 		return (IBMF_NO_RESOURCES);
752 
753 	ksp = (ibmf_saa_kstat_t *)saa_portp->saa_pt_kstatp->ks_data;
754 
755 	kstat_named_init(&ksp->clients_registered,
756 	    "clients_registered", KSTAT_DATA_UINT32);
757 
758 	kstat_named_init(&ksp->clients_reg_failed,
759 	    "clients_reg_failed", KSTAT_DATA_UINT32);
760 
761 	kstat_named_init(&ksp->outstanding_requests,
762 	    "outstanding_requests", KSTAT_DATA_UINT32);
763 
764 	kstat_named_init(&ksp->total_requests,
765 	    "total_requests", KSTAT_DATA_UINT32);
766 
767 	kstat_named_init(&ksp->failed_requests,
768 	    "failed_requests", KSTAT_DATA_UINT32);
769 
770 	kstat_named_init(&ksp->requests_timedout,
771 	    "requests_timedout", KSTAT_DATA_UINT32);
772 
773 	kstat_install(saa_portp->saa_pt_kstatp);
774 
775 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
776 	    ibmf_saa_impl_init_kstats_end,
777 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_init_kstats() exit\n");
778 
779 	return (IBMF_SUCCESS);
780 }
781 
782 /*
783  * ibmf_saa_impl_uninit_kstats:
784  * Free kstats context.  Should be called when port is either destroyed
785  * or invalidated.
786  */
787 static void
788 ibmf_saa_impl_uninit_kstats(saa_port_t *saa_portp)
789 {
790 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
791 	    ibmf_saa_impl_uninit_kstats_start,
792 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_uninit_kstats() enter\n");
793 
794 	mutex_enter(&saa_portp->saa_pt_kstat_mutex);
795 
796 	if (saa_portp->saa_pt_kstatp != NULL) {
797 		kstat_delete(saa_portp->saa_pt_kstatp);
798 	}
799 	saa_portp->saa_pt_kstatp = NULL;
800 
801 	mutex_exit(&saa_portp->saa_pt_kstat_mutex);
802 
803 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
804 	    ibmf_saa_impl_uninit_kstats_end,
805 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_uninit_kstats() exit\n");
806 }
807 
808 /*
809  * ibmf_saa_impl_register_failed:
810  * invalidate entry and kick waiters
811  */
812 void
813 ibmf_saa_impl_register_failed(saa_port_t *saa_portp)
814 {
815 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
816 	    ibmf_saa_impl_register_failed_start,
817 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_register_failed() enter\n");
818 
819 	mutex_enter(&saa_portp->saa_pt_mutex);
820 
821 	ibmf_saa_impl_invalidate_port(saa_portp);
822 
823 	cv_broadcast(&saa_portp->saa_pt_ibmf_reg_cv);
824 
825 	/* decrementing refcount is last thing we do on entry */
826 
827 	ASSERT(saa_portp->saa_pt_reference_count > 0);
828 	saa_portp->saa_pt_reference_count--;
829 
830 	mutex_exit(&saa_portp->saa_pt_mutex);
831 
832 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
833 	    ibmf_saa_impl_register_failed_end,
834 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_register_failed() exit\n");
835 }
836 
837 static int
838 ibmf_saa_impl_setup_qp_async_cb(saa_port_t *saa_portp, int setup_async_cb_only)
839 {
840 	int		status;
841 	int		unreg_status;
842 	ib_pkey_t	p_key;
843 	ib_qkey_t	q_key;
844 	uint8_t		portnum;
845 	boolean_t	qp_alloced = B_FALSE;
846 
847 	if (setup_async_cb_only == 0) {
848 
849 		/* allocate a qp through ibmf */
850 		status = ibmf_alloc_qp(saa_portp->saa_pt_ibmf_handle,
851 		    IB_PKEY_DEFAULT_LIMITED, IB_GSI_QKEY,
852 		    IBMF_ALT_QP_MAD_RMPP, &saa_portp->saa_pt_qp_handle);
853 
854 		if (status != IBMF_SUCCESS) {
855 
856 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
857 			    ibmf_saa_impl_setup_qp_async_cb, IBMF_TNF_ERROR, "",
858 			    "ibmf_saa_impl_setup_qp_async_cb: %s, "
859 			    "ibmf_status = %d\n",
860 			    tnf_string, msg, "Cannot alloc qp with ibmf",
861 			    tnf_int, status, status);
862 
863 			return (status);
864 		}
865 
866 		qp_alloced = B_TRUE;
867 
868 		/*
869 		 * query the queue pair number; we will need it to unsubscribe
870 		 * from notice reports
871 		 */
872 		status = ibmf_query_qp(saa_portp->saa_pt_ibmf_handle,
873 		    saa_portp->saa_pt_qp_handle, &saa_portp->saa_pt_qpn,
874 		    &p_key, &q_key, &portnum, 0);
875 
876 		if (status != IBMF_SUCCESS) {
877 
878 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
879 			    ibmf_saa_impl_setup_qp_async_cb, IBMF_TNF_ERROR, "",
880 			    "ibmf_saa_impl_setup_qp_async_cb: %s, "
881 			    "ibmf_status = %d\n",
882 			    tnf_string, msg,
883 			    "Cannot query alt qp to get qp num",
884 			    tnf_int, status, status);
885 
886 			goto bail;
887 		}
888 	}
889 
890 	/*
891 	 * core ibmf is taking advantage of the fact that saa_portp is our
892 	 * callback arg. If this changes, the code in ibmf_recv would need to
893 	 * change as well
894 	 */
895 	status = ibmf_setup_async_cb(saa_portp->saa_pt_ibmf_handle,
896 	    saa_portp->saa_pt_qp_handle, ibmf_saa_report_cb, saa_portp, 0);
897 	if (status != IBMF_SUCCESS) {
898 
899 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
900 		    ibmf_saa_impl_setup_qp_async_cb, IBMF_TNF_ERROR, "",
901 		    "ibmf_saa_impl_setup_qp_async_cb: %s, ibmf_status = %d\n",
902 		    tnf_string, msg, "Cannot register async cb with ibmf",
903 		    tnf_int, status, status);
904 
905 		goto bail;
906 	}
907 
908 	return (IBMF_SUCCESS);
909 
910 bail:
911 	if (qp_alloced == B_TRUE) {
912 		/* free alternate qp */
913 		unreg_status = ibmf_free_qp(saa_portp->saa_pt_ibmf_handle,
914 		    &saa_portp->saa_pt_qp_handle, 0);
915 		if (unreg_status != IBMF_SUCCESS) {
916 
917 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
918 			    ibmf_saa_impl_setup_qp_async_cb, IBMF_TNF_ERROR, "",
919 			    "ibmf_saa_impl_setup_qp_async_cb: %s, ibmf_status ="
920 			    " %d\n", tnf_string, msg,
921 			    "Cannot free alternate queue pair with ibmf",
922 			    tnf_int, unreg_status, unreg_status);
923 		}
924 	}
925 
926 	return (status);
927 }
928 
929 /*
930  * ibmf_saa_impl_register_port:
931  */
932 int
933 ibmf_saa_impl_register_port(
934 	saa_port_t *saa_portp)
935 {
936 	uint_t		hca_count	= 0;
937 	ib_guid_t	*hca_list 	= NULL;
938 	int		status 		= IBMF_SUCCESS;
939 	int		unreg_status 	= IBMF_SUCCESS;
940 	int		ibt_status	= IBT_SUCCESS;
941 	ibt_hca_portinfo_t *port_info_list = NULL;
942 	uint_t		port_count	= 0;
943 	uint_t		port_size	= 0;
944 	int		ihca, iport;
945 	ib_guid_t	port_guid;
946 	boolean_t	ibmf_reg = B_FALSE;
947 
948 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
949 	    ibmf_saa_impl_register_port_start, IBMF_TNF_TRACE, "",
950 	    "ibmf_saa_impl_register_port() enter\n");
951 
952 	ASSERT(saa_portp != NULL);
953 
954 	_NOTE(ASSUMING_PROTECTED(*saa_portp))
955 
956 	/* get the HCA list */
957 
958 	hca_count = ibt_get_hca_list(&hca_list);
959 
960 	if (hca_count == 0) {
961 
962 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
963 		    ibmf_saa_impl_register_port, IBMF_TNF_ERROR, "",
964 		    "ibmf_saa_impl_register_port: %s\n",
965 		    tnf_string, msg, "cannot register port (no HCAs).\n");
966 
967 		status = IBMF_BAD_PORT;
968 		goto bail;
969 	}
970 
971 	/* lookup requested port guid in hca list */
972 	for (ihca = 0; ihca != hca_count; ihca++) {
973 
974 		ibt_status = ibt_query_hca_ports_byguid(hca_list[ihca],
975 		    0 /* all ports */, &port_info_list,
976 		    &port_count, &port_size);
977 
978 		if (ibt_status != IBT_SUCCESS) {
979 
980 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
981 			    ibmf_saa_impl_register_port, IBMF_TNF_ERROR, "",
982 			    "ibmf_saa_impl_register_port: %s, %016" PRIx64 "\n",
983 			    tnf_string, msg, "Could not query hca.  Exiting.",
984 			    tnf_opaque, guid, hca_list[ihca]);
985 
986 			status = IBMF_TRANSPORT_FAILURE;
987 			break;
988 		}
989 
990 		for (iport = 0; iport < port_count; iport++) {
991 
992 			/* get port guid associated with hca guid, port num */
993 			if (ibmf_saa_impl_get_port_guid(
994 			    port_info_list + iport, &port_guid) != IBMF_SUCCESS)
995 				continue;
996 
997 			if (saa_portp->saa_pt_port_guid != port_guid)
998 				continue;
999 
1000 			IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L3,
1001 			    ibmf_saa_impl_register_port,
1002 			    IBMF_TNF_TRACE, "",
1003 			    "ibmf_saa_impl_register_port: %s, hca_guid = %016"
1004 			    PRIx64 ", port_guid = %016" PRIx64
1005 			    ", number = %d\n",
1006 			    tnf_string, msg, "found port",
1007 			    tnf_opaque, hca_guid, hca_list[ihca],
1008 			    tnf_opaque, port_guid, port_guid,
1009 			    tnf_uint,   port, iport + 1);
1010 
1011 			/*
1012 			 * we're here? then we found our port:
1013 			 * fill in ibmf registration info
1014 			 * and address parameters from the portinfo
1015 			 */
1016 
1017 			saa_portp->saa_pt_ibmf_reginfo.ir_ci_guid
1018 			    = hca_list[ihca];
1019 			saa_portp->saa_pt_ibmf_reginfo.ir_port_num = iport+1;
1020 			saa_portp->saa_pt_ibmf_reginfo.ir_client_class
1021 			    = SUBN_ADM_MANAGER;
1022 
1023 			saa_portp->saa_pt_node_guid = hca_list[ihca];
1024 			saa_portp->saa_pt_port_num = iport + 1;
1025 
1026 			ibmf_saa_impl_set_transaction_params(
1027 			    saa_portp, port_info_list + iport);
1028 			break;
1029 		}
1030 
1031 		ibt_free_portinfo(port_info_list, port_size);
1032 
1033 		if (iport != port_count)
1034 			break;	/* found our port */
1035 	}
1036 
1037 	ibt_free_hca_list(hca_list, hca_count);
1038 
1039 	if (ihca == hca_count) {
1040 
1041 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
1042 		    ibmf_saa_impl_register_port, IBMF_TNF_ERROR, "",
1043 		    "ibmf_saa_impl_register_port: %s, port_guid %016"
1044 		    PRIx64 "\n",
1045 		    tnf_string, msg, "Could not find port,  exiting",
1046 		    tnf_opaque, port_guid, saa_portp->saa_pt_port_guid);
1047 
1048 		status = IBMF_BAD_PORT;
1049 	}
1050 
1051 	if (status != IBMF_SUCCESS) {
1052 
1053 		goto bail;
1054 	}
1055 
1056 	/*
1057 	 * Now we found the port we searched for,
1058 	 * and open an ibmf session on that port.
1059 	 */
1060 
1061 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3,
1062 	    ibmf_saa_impl_register_port, IBMF_TNF_TRACE, "",
1063 	    "ibmf_saa_impl_register_port: %s, port_guid = %016" PRIx64
1064 	    ", port = %d\n", tnf_string, msg, "Registering with ibmf",
1065 	    tnf_opaque, port_guid, saa_portp->saa_pt_ibmf_reginfo.ir_ci_guid,
1066 	    tnf_uint, port, saa_portp->saa_pt_ibmf_reginfo.ir_port_num);
1067 
1068 	status = ibmf_register(&saa_portp->saa_pt_ibmf_reginfo,
1069 	    IBMF_VERSION, IBMF_REG_FLAG_RMPP,
1070 	    ibmf_saa_impl_async_event_cb, saa_portp,
1071 	    &saa_portp->saa_pt_ibmf_handle,
1072 	    &saa_portp->saa_pt_ibmf_impl_features);
1073 
1074 	if (status != IBMF_SUCCESS) {
1075 
1076 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
1077 		    ibmf_saa_impl_register_port, IBMF_TNF_ERROR, "",
1078 		    "ibmf_saa_impl_register_port: %s, ibmf_status = %d\n",
1079 		    tnf_string, msg, "Could not register with ibmf",
1080 		    tnf_int, status, status);
1081 
1082 		goto bail;
1083 	}
1084 
1085 	ibmf_reg = B_TRUE;
1086 
1087 	if (ibmf_saa_impl_setup_qp_async_cb(saa_portp, 0) == IBMF_SUCCESS)
1088 		return (IBMF_SUCCESS);
1089 
1090 bail:
1091 	if (ibmf_reg == B_TRUE) {
1092 		/* unregister from ibmf */
1093 		unreg_status = ibmf_unregister(
1094 		    &saa_portp->saa_pt_ibmf_handle, 0);
1095 
1096 		if (unreg_status != IBMF_SUCCESS) {
1097 
1098 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
1099 			    ibmf_saa_impl_register_port, IBMF_TNF_ERROR, "",
1100 			    "ibmf_saa_impl_register_port: %s, ibmf_status ="
1101 			    " %d\n", tnf_string, msg,
1102 			    "Cannot unregister from ibmf",
1103 			    tnf_int, unreg_status, unreg_status);
1104 		}
1105 	}
1106 
1107 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_register_port_end,
1108 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_register_port() exit\n");
1109 
1110 	return (status);
1111 }
1112 
1113 /*
1114  * ibmf_saa_impl_getclassportinfo:
1115  */
1116 void
1117 ibmf_saa_impl_get_classportinfo(saa_port_t *saa_portp)
1118 {
1119 	int			res;
1120 	saa_impl_trans_info_t	*trans_info;
1121 
1122 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1123 	    ibmf_saa_impl_get_classportinfo_start,
1124 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_get_classportinfo() enter\n");
1125 
1126 	/*
1127 	 * allocate memory for trans_info; send_request's callback will free up
1128 	 * memory since request is asynchronous
1129 	 */
1130 	trans_info = kmem_zalloc(sizeof (saa_impl_trans_info_t), KM_NOSLEEP);
1131 	if (trans_info == NULL) {
1132 
1133 		mutex_enter(&saa_portp->saa_pt_mutex);
1134 
1135 		/* cpi transaction is handled as a client, decrement refcount */
1136 		ASSERT(saa_portp->saa_pt_reference_count > 0);
1137 		saa_portp->saa_pt_reference_count--;
1138 
1139 		mutex_exit(&saa_portp->saa_pt_mutex);
1140 
1141 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1142 		    ibmf_saa_impl_get_classportinfo_err, IBMF_TNF_ERROR, "",
1143 		    "ibmf_saa_impl_get_classportinfo: %s\n", tnf_string, msg,
1144 		    "Could not allocate memory for classportinfo trans_info");
1145 
1146 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1147 		    ibmf_saa_impl_get_classportinfo_end, IBMF_TNF_TRACE, "",
1148 		    "ibmf_saa_impl_get_classportinfo() exiting\n");
1149 
1150 		return;
1151 	}
1152 
1153 	/* no specific client associated with this transaction */
1154 	trans_info->si_trans_client_data = NULL;
1155 	trans_info->si_trans_port	 = saa_portp;
1156 	trans_info->si_trans_method	 = SA_SUBN_ADM_GET;
1157 	trans_info->si_trans_attr_id	 = MAD_ATTR_ID_CLASSPORTINFO;
1158 
1159 	trans_info->si_trans_callback = ibmf_saa_impl_get_cpi_cb;
1160 	trans_info->si_trans_callback_arg = saa_portp;
1161 
1162 	mutex_enter(&saa_portp->saa_pt_kstat_mutex);
1163 
1164 	IBMF_SAA_ADD32_KSTATS(saa_portp, outstanding_requests, 1);
1165 	IBMF_SAA_ADD32_KSTATS(saa_portp, total_requests, 1);
1166 
1167 	mutex_exit(&saa_portp->saa_pt_kstat_mutex);
1168 
1169 	res = ibmf_saa_impl_send_request(trans_info);
1170 
1171 	if (res != IBMF_SUCCESS) {
1172 
1173 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
1174 		    ibmf_saa_impl_get_classportinfo_err, IBMF_TNF_TRACE, "",
1175 		    "ibmf_saa_impl_get_classportinfo: %s, res = 0x%x\n",
1176 		    tnf_string, msg, "ibmf_saa_impl_send_request failed",
1177 		    tnf_opaque, res, res);
1178 
1179 		mutex_enter(&saa_portp->saa_pt_kstat_mutex);
1180 
1181 		IBMF_SAA_SUB32_KSTATS(saa_portp, outstanding_requests, 1);
1182 		IBMF_SAA_ADD32_KSTATS(saa_portp, failed_requests, 1);
1183 
1184 		mutex_exit(&saa_portp->saa_pt_kstat_mutex);
1185 
1186 		mutex_enter(&saa_portp->saa_pt_mutex);
1187 
1188 		/* cpi transaction is handled as a client, decrement refcount */
1189 		ASSERT(saa_portp->saa_pt_reference_count > 0);
1190 		saa_portp->saa_pt_reference_count--;
1191 
1192 		mutex_exit(&saa_portp->saa_pt_mutex);
1193 
1194 	}
1195 
1196 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1197 	    ibmf_saa_impl_get_classportinfo_end,
1198 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_get_classportinfo() exit\n");
1199 }
1200 
1201 /*
1202  * ibmf_saa_impl_get_cpi_cb:
1203  *
1204  * Called when the asynchronous getportinfo request receives its response.
1205  * Checks the status.  If success, updates the times in the port's
1206  * ibmf_retrans structure that is used in ibmf_msg_transport calls.  If failure,
1207  * just use default values.
1208  *
1209  * Input Arguments
1210  * arg		user-specified pointer (points to the current port data)
1211  * length	length of payload returned (should be size of classportinfo_t)
1212  * buffer	pointer to classportinfo returned (should not be null)
1213  * status	status of sa access request
1214  *
1215  * Output Arguments
1216  * none
1217  *
1218  * Returns void
1219  */
1220 static void
1221 ibmf_saa_impl_get_cpi_cb(void *arg, size_t length, char *buffer, int status)
1222 {
1223 	saa_port_t		*saa_portp;
1224 	uint64_t		base_time, resp_timeout, rttv_timeout;
1225 	ib_mad_classportinfo_t	*classportinfo;
1226 	int			resp_time_value;
1227 	uint16_t		sa_cap_mask;
1228 
1229 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_get_cpi_cb_start,
1230 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_get_cpi_cb() enter\n");
1231 
1232 	/*
1233 	 * access port entry: note that it may have become invalid
1234 	 * but we hold a ref count for cpi and the interactions on
1235 	 * the entry are harmless
1236 	 */
1237 	saa_portp = (saa_port_t *)arg;
1238 
1239 	/* process response */
1240 
1241 	if ((status != IBMF_SUCCESS) || (buffer == NULL)) {
1242 
1243 		IBMF_TRACE_4(IBMF_TNF_NODEBUG, DPRINT_L1,
1244 		    ibmf_saa_impl_get_cpi_cb, IBMF_TNF_ERROR, "",
1245 		    "ibmf_saa_impl_get_cpi_cb: %s, status = %d, buffer = "
1246 		    " 0x%p, length = %d\n", tnf_string, msg,
1247 		    "could not get classportinfo.  Check node and path to sm"
1248 		    " lid", tnf_int, status, status,
1249 		    tnf_opaque, buffer, buffer, tnf_uint, length, length);
1250 
1251 		/*
1252 		 * IB spec (C13-13) indicates 20 can be used as default or
1253 		 * intial value for classportinfo->resptimeout value
1254 		 */
1255 		resp_time_value = 20;
1256 
1257 		sa_cap_mask = 0xFFFF;
1258 
1259 	} else if (buffer != NULL) {
1260 
1261 		classportinfo = (ib_mad_classportinfo_t *)buffer;
1262 
1263 		resp_time_value = classportinfo->RespTimeValue & 0x1f;
1264 
1265 		/*
1266 		 * Because some subnet managers might not provide sane
1267 		 * value for "resp_time_value", we limit it here.  In
1268 		 * case this limit is too restrictive (very large fabric),
1269 		 * we allow the limit to be raised (/etc/system).
1270 		 */
1271 		if (resp_time_value > ibmf_saa_max_resp_time) {
1272 			cmn_err(CE_CONT, "!ibmf_saa_max_resp_time (%d) "
1273 			    "exceeded.", ibmf_saa_max_resp_time);
1274 			cmn_err(CE_CONT, "!Reducing subnet administrator "
1275 			    "resp_time value from %d to %d.",
1276 			    resp_time_value, ibmf_saa_max_resp_time);
1277 			resp_time_value = ibmf_saa_max_resp_time;
1278 		}
1279 
1280 		sa_cap_mask = classportinfo->CapabilityMask;
1281 
1282 		IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3,
1283 		    ibmf_saa_impl_get_cpi_cb, IBMF_TNF_TRACE, "",
1284 		    "ibmf_saa_impl_get_cpi_cb: %s, timeout = 0x%x,"
1285 		    " cap_mask = 0x%x\n",
1286 		    tnf_string, msg, "got classportinfo",
1287 		    tnf_opaque, timeout, resp_time_value,
1288 		    tnf_opaque, cap_mask, sa_cap_mask);
1289 
1290 		kmem_free(buffer, length);
1291 	}
1292 
1293 	/*
1294 	 * using IB spec calculation from 13.4.6.2
1295 	 * use bit shifting for 2^x.
1296 	 */
1297 	base_time = (1 << resp_time_value);
1298 
1299 	resp_timeout = (4 * base_time * 1000 + 96 * base_time) / 1000;
1300 
1301 	mutex_enter(&saa_portp->saa_pt_mutex);
1302 
1303 	base_time = 2 * (1 << saa_portp->saa_pt_timeout);
1304 
1305 	rttv_timeout = (4 * base_time * 1000 + 96 * base_time) / 1000;
1306 
1307 	saa_portp->saa_pt_ibmf_retrans.retrans_rtv = resp_timeout;
1308 	saa_portp->saa_pt_ibmf_retrans.retrans_rttv = rttv_timeout;
1309 	saa_portp->saa_pt_sa_cap_mask = sa_cap_mask;
1310 
1311 	/*
1312 	 * cpi transaction is handled as a client,
1313 	 * decrement refcount; make sure it's the last
1314 	 * thing we do on this entry
1315 	 */
1316 	ASSERT(saa_portp->saa_pt_reference_count > 0);
1317 	saa_portp->saa_pt_reference_count--;
1318 
1319 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3,
1320 	    ibmf_saa_impl_get_cpi_cb, IBMF_TNF_TRACE, "",
1321 	    "ibmf_saa_impl_get_cpi_cb: %s, subnet_timeout = 0x%x, "
1322 	    "resp_time_value = 0x%x\n",
1323 	    tnf_string, msg, "updated resp timeout",
1324 	    tnf_opaque, subnet_timeout, saa_portp->saa_pt_timeout,
1325 	    tnf_opaque, resp_time_value, resp_time_value);
1326 
1327 	mutex_exit(&saa_portp->saa_pt_mutex);
1328 
1329 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_get_cpi_cb_end,
1330 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_get_cpi_cb() exit\n");
1331 }
1332 
1333 /*
1334  * ibmf_saa_impl_send_request:
1335  * Sends a request to the sa.  Can be used for both classportinfo and record
1336  * requests.  Will set up all data structures for using the multi-packet
1337  * protocol, create the mad, and send it.  Returns SA_SUCCESS if msg transport
1338  * worked, meaning succesful send for the async case and a succesful send and
1339  * recv for the sync case.
1340  */
1341 int
1342 ibmf_saa_impl_send_request(saa_impl_trans_info_t *trans_info)
1343 {
1344 	uint16_t 		attr_id;
1345 	saa_client_data_t	*client_data;
1346 	saa_port_t		*saa_portp;
1347 	uint32_t		transport_flags;
1348 	ibmf_msg_cb_t		ibmf_callback;
1349 	void			*ibmf_callback_arg;
1350 	ibmf_msg_t		*msgp;
1351 	ibmf_retrans_t		ibmf_retrans;
1352 	uint16_t		sa_cap_mask;
1353 	boolean_t		sleep_flag;
1354 	int			ibmf_status = IBMF_SUCCESS;
1355 	int			retry_count;
1356 	uint16_t		mad_status;
1357 	boolean_t		sa_is_redirected = B_FALSE;
1358 
1359 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1360 	    ibmf_saa_impl_send_request_start,
1361 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_send_request() enter\n");
1362 
1363 	attr_id = trans_info->si_trans_attr_id;
1364 	client_data = trans_info->si_trans_client_data;
1365 	saa_portp   = trans_info->si_trans_port;
1366 
1367 	/*
1368 	 * don't send on invalid entry
1369 	 * Note that there is a window where it could become
1370 	 * invalid after this test is done, but we'd rely on ibmf errors...
1371 	 */
1372 	if (ibmf_saa_is_valid(saa_portp, B_FALSE) == B_FALSE) {
1373 
1374 		IBMF_TRACE_4(IBMF_TNF_NODEBUG, DPRINT_L1,
1375 		    ibmf_saa_impl_send_request,
1376 		    IBMF_TNF_ERROR, "",
1377 		    "ibmf_saa_impl_send_request: %s, hca_guid = %016"
1378 		    PRIx64 ", port_guid = %016" PRIx64
1379 		    ", number = %d\n",
1380 		    tnf_string, msg, "sending on invalid port",
1381 		    tnf_opaque, hca_guid,
1382 		    saa_portp->saa_pt_ibmf_reginfo.ir_ci_guid,
1383 		    tnf_opaque, port_guid,
1384 		    saa_portp->saa_pt_port_guid,
1385 		    tnf_uint,   port,
1386 		    saa_portp->saa_pt_ibmf_reginfo.ir_port_num);
1387 
1388 		ibmf_status = IBMF_REQ_INVALID;
1389 		goto bail;
1390 	}
1391 
1392 	/* check whether SA supports this attribute */
1393 	mutex_enter(&saa_portp->saa_pt_mutex);
1394 
1395 	sa_cap_mask = saa_portp->saa_pt_sa_cap_mask;
1396 	sa_is_redirected = saa_portp->saa_pt_redirect_active;
1397 
1398 	mutex_exit(&saa_portp->saa_pt_mutex);
1399 
1400 	ibmf_status = ibmf_saa_impl_check_sa_support(sa_cap_mask, attr_id);
1401 
1402 	if (ibmf_status != IBMF_SUCCESS) {
1403 
1404 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
1405 		    ibmf_saa_impl_send_request_err, IBMF_TNF_ERROR, "",
1406 		    "ibmf_saa_impl_send_request: %s, ibmf_status = %d\n",
1407 		    tnf_string, msg, "SA does not support attribute",
1408 		    tnf_int, ibmf_status, ibmf_status);
1409 
1410 		goto bail;
1411 	}
1412 
1413 	/* make only non-blocking calls if this is an async request */
1414 	if ((trans_info->si_trans_callback == NULL) &&
1415 	    (trans_info->si_trans_sub_callback == NULL)) {
1416 		ibmf_callback = NULL;
1417 		ibmf_callback_arg = NULL;
1418 		sleep_flag = B_TRUE;
1419 	} else {
1420 		ibmf_callback = ibmf_saa_async_cb;
1421 		ibmf_callback_arg = (void *)trans_info;
1422 		sleep_flag = B_FALSE;
1423 	}
1424 
1425 	ibmf_status = ibmf_saa_impl_init_msg(trans_info, sleep_flag, &msgp,
1426 	    &transport_flags, &ibmf_retrans);
1427 	if (ibmf_status != IBMF_SUCCESS) {
1428 
1429 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
1430 		    ibmf_saa_impl_send_request_err, IBMF_TNF_ERROR, "",
1431 		    "ibmf_saa_impl_send_request: %s, ibmf_status = %d\n",
1432 		    tnf_string, msg, "init_msg() failed",
1433 		    tnf_int, ibmf_status, ibmf_status);
1434 
1435 		goto bail;
1436 	}
1437 
1438 	mutex_enter(&saa_portp->saa_pt_mutex);
1439 
1440 	saa_portp->saa_pt_num_outstanding_trans++;
1441 
1442 	mutex_exit(&saa_portp->saa_pt_mutex);
1443 
1444 	/*
1445 	 * increment the number of outstanding transaction so
1446 	 * ibmf_close_sa_session() will wait.  classportinfo requests
1447 	 * don't have associated clients so check for valid clientp
1448 	 */
1449 	if (client_data != NULL) {
1450 
1451 		mutex_enter(&client_data->saa_client_mutex);
1452 
1453 		client_data->saa_client_num_pending_trans++;
1454 
1455 		mutex_exit(&client_data->saa_client_mutex);
1456 	}
1457 
1458 	/*
1459 	 * make the call to msg_transport.  If synchronous and success,
1460 	 * check that the response mad isn't status busy.  If so, repeat the
1461 	 * call
1462 	 */
1463 	retry_count = 0;
1464 
1465 	/*
1466 	 * set the send time here. We only set this once at the beginning of
1467 	 * the transaction.  Retrying because of busys or mastersmlid changes
1468 	 * does not change the original send time.  It is meant to be an
1469 	 * absolute time out value and will only be used if there are other
1470 	 * problems (i.e. a buggy SA)
1471 	 */
1472 	trans_info->si_trans_send_time = gethrtime();
1473 
1474 	for (;;) {
1475 
1476 		ibmf_status = ibmf_msg_transport(saa_portp->saa_pt_ibmf_handle,
1477 		    saa_portp->saa_pt_qp_handle, msgp, &ibmf_retrans,
1478 		    ibmf_callback, ibmf_callback_arg, transport_flags);
1479 
1480 		if (ibmf_callback != NULL)
1481 			break;
1482 
1483 		/*
1484 		 * stop here for non-sequenced transactions since they wouldn't
1485 		 * receive a timeout or busy response
1486 		 */
1487 		if (!(transport_flags & IBMF_MSG_TRANS_FLAG_SEQ))
1488 			break;
1489 
1490 		/*
1491 		 * if the transaction timed out and this was a synchronous
1492 		 * request there's a possiblity we were talking to the wrong
1493 		 * master smlid or that the SA has stopped responding on the
1494 		 * redirected desination (if redirect is active).
1495 		 * Check this and retry if necessary.
1496 		 */
1497 		if ((ibmf_status == IBMF_TRANS_TIMEOUT) &&
1498 		    (sleep_flag == B_TRUE)) {
1499 			if (sa_is_redirected == B_TRUE) {
1500 				ibmf_status = ibmf_saa_impl_revert_to_qp1(
1501 				    saa_portp, msgp, ibmf_callback,
1502 				    ibmf_callback_arg, transport_flags);
1503 			} else {
1504 				ibmf_status = ibmf_saa_impl_new_smlid_retry(
1505 				    saa_portp, msgp, ibmf_callback,
1506 				    ibmf_callback_arg, transport_flags);
1507 			}
1508 		}
1509 
1510 		/*
1511 		 * if the transaction timed out (and retrying with a new SM LID
1512 		 * didn't help) check how long it's been since we received an SA
1513 		 * packet.  If it hasn't been max_wait_time then retry the
1514 		 * request.
1515 		 */
1516 		if ((ibmf_status == IBMF_TRANS_TIMEOUT) &&
1517 		    (sleep_flag == B_TRUE)) {
1518 
1519 			ibmf_status = ibmf_saa_check_sa_and_retry(
1520 			    saa_portp, msgp, ibmf_callback, ibmf_callback_arg,
1521 			    trans_info->si_trans_send_time, transport_flags);
1522 		}
1523 
1524 		if (ibmf_status != IBMF_SUCCESS)
1525 			break;
1526 
1527 		if (retry_count >= IBMF_SAA_MAX_BUSY_RETRY_COUNT)
1528 			break;
1529 
1530 		/* sync transaction with status SUCCESS should have response */
1531 		ASSERT(msgp->im_msgbufs_recv.im_bufs_mad_hdr != NULL);
1532 
1533 		mad_status = b2h16(msgp->im_msgbufs_recv.
1534 		    im_bufs_mad_hdr->Status);
1535 
1536 		if ((mad_status != MAD_STATUS_BUSY) &&
1537 		    (mad_status != MAD_STATUS_REDIRECT_REQUIRED))
1538 			break;
1539 
1540 		if (mad_status == MAD_STATUS_REDIRECT_REQUIRED) {
1541 
1542 			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
1543 			    ibmf_saa_impl_send_request, IBMF_TNF_TRACE, "",
1544 			    "ibmf_saa_impl_send_request: %s, retry_count %d\n",
1545 			    tnf_string, msg,
1546 			    "response returned redirect status",
1547 			    tnf_int, retry_count, retry_count);
1548 
1549 			/* update address info and copy it into msgp */
1550 			ibmf_saa_impl_update_sa_address_info(saa_portp, msgp);
1551 		} else {
1552 			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
1553 			    ibmf_saa_impl_send_request, IBMF_TNF_TRACE, "",
1554 			    "ibmf_saa_impl_send_request: %s, retry_count %d\n",
1555 			    tnf_string, msg, "response returned busy status",
1556 			    tnf_int, retry_count, retry_count);
1557 		}
1558 
1559 		retry_count++;
1560 
1561 		/*
1562 		 * since this is a blocking call, sleep for some time
1563 		 * to allow SA to transition from busy state (if busy)
1564 		 */
1565 		if (mad_status == MAD_STATUS_BUSY)
1566 			delay(drv_usectohz(
1567 			    IBMF_SAA_BUSY_RETRY_SLEEP_SECS * 1000000));
1568 	}
1569 
1570 	if (ibmf_status != IBMF_SUCCESS) {
1571 
1572 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
1573 		    ibmf_saa_impl_send_request, IBMF_TNF_TRACE, "",
1574 		    "ibmf_saa_impl_send_request: %s, ibmf_status = %d\n",
1575 		    tnf_string, msg, "ibmf_msg_transport() failed",
1576 		    tnf_int, ibmf_status, ibmf_status);
1577 
1578 		ibmf_saa_impl_free_msg(saa_portp->saa_pt_ibmf_handle, msgp);
1579 
1580 		mutex_enter(&saa_portp->saa_pt_mutex);
1581 
1582 		ASSERT(saa_portp->saa_pt_num_outstanding_trans > 0);
1583 		saa_portp->saa_pt_num_outstanding_trans--;
1584 
1585 		mutex_exit(&saa_portp->saa_pt_mutex);
1586 
1587 		if (client_data != NULL) {
1588 
1589 			mutex_enter(&client_data->saa_client_mutex);
1590 
1591 			ASSERT(client_data->saa_client_num_pending_trans > 0);
1592 			client_data->saa_client_num_pending_trans--;
1593 
1594 			if ((client_data->saa_client_num_pending_trans == 0) &&
1595 			    (client_data->saa_client_state ==
1596 			    SAA_CLIENT_STATE_WAITING))
1597 				cv_signal(&client_data->saa_client_state_cv);
1598 
1599 			mutex_exit(&client_data->saa_client_mutex);
1600 		}
1601 
1602 	} else if (sleep_flag == B_TRUE) {
1603 
1604 		mutex_enter(&saa_portp->saa_pt_mutex);
1605 
1606 		ASSERT(saa_portp->saa_pt_num_outstanding_trans > 0);
1607 		saa_portp->saa_pt_num_outstanding_trans--;
1608 
1609 		mutex_exit(&saa_portp->saa_pt_mutex);
1610 
1611 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1612 		    ibmf_saa_impl_send_request, IBMF_TNF_TRACE, "",
1613 		    "ibmf_saa_impl_send_request: %s\n",
1614 		    tnf_string, msg, "Message sent and received successfully");
1615 
1616 		/* fill in response values and free the message */
1617 		ibmf_saa_impl_prepare_response(saa_portp->saa_pt_ibmf_handle,
1618 		    msgp, B_FALSE, &trans_info->si_trans_status,
1619 		    &trans_info->si_trans_result,
1620 		    &trans_info->si_trans_length, sleep_flag);
1621 
1622 		if (client_data != NULL) {
1623 			mutex_enter(&client_data->saa_client_mutex);
1624 
1625 			ASSERT(client_data->saa_client_num_pending_trans > 0);
1626 			client_data->saa_client_num_pending_trans--;
1627 
1628 			if ((client_data->saa_client_num_pending_trans == 0) &&
1629 			    (client_data->saa_client_state ==
1630 			    SAA_CLIENT_STATE_WAITING))
1631 				cv_signal(&client_data->saa_client_state_cv);
1632 
1633 			mutex_exit(&client_data->saa_client_mutex);
1634 		}
1635 	} else {
1636 
1637 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1638 		    ibmf_saa_impl_send_request, IBMF_TNF_TRACE, "",
1639 		    "ibmf_saa_impl_send_request: %s\n",
1640 		    tnf_string, msg, "Message sent successfully");
1641 	}
1642 
1643 bail:
1644 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1645 	    ibmf_saa_impl_send_request_end,
1646 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_send_request() exiting"
1647 	    " ibmf_status = %d\n", tnf_int, result, ibmf_status);
1648 
1649 	return (ibmf_status);
1650 }
1651 
1652 /*
1653  * ibmf_saa_impl_init_msg:
1654  * Allocates an ibmf message and fills out the header fields and formatted data
1655  * fields.  Also sets up the correct transport_flags and retrans argument for
1656  * the message transport call based on the request information.
1657  *
1658  * Input Arguments
1659  * trans_info		saa_trans_info structure passed to send_request
1660  * sleep_flag		B_TRUE if init_msg can sleep in function calls
1661  *
1662  * Output Arguments
1663  * msgp			ibmf message that should be given to msg_transport
1664  * transport_flagsp	transport flags that should be given to msg_transport
1665  * ibmf_retrans_t	retrans parameter that should be given to msg_transport
1666  *
1667  * Returns
1668  * ibmf_status
1669  */
1670 static int
1671 ibmf_saa_impl_init_msg(saa_impl_trans_info_t *trans_info, boolean_t sleep_flag,
1672     ibmf_msg_t **msgp, uint32_t *transport_flagsp,
1673     ibmf_retrans_t *ibmf_retransp)
1674 {
1675 	int			ibmf_status;
1676 	ibmf_msg_bufs_t		*req_mad;
1677 	ib_mad_hdr_t		*mad_hdr;
1678 	int			ibmf_sleep_flag, km_sleep_flag;
1679 	int 			free_res;
1680 	ib_sa_hdr_t		sa_hdr;
1681 	ibmf_msg_t		*ibmf_msg;
1682 	uint16_t 		attr_id, pack_attr_id;
1683 	uint8_t			method;
1684 	saa_client_data_t	*client_data;
1685 	saa_port_t		*saa_portp;
1686 	sa_multipath_record_t	*multipath_template;
1687 	size_t			payload_length;
1688 	uint32_t		transport_flags;
1689 
1690 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1691 	    ibmf_saa_impl_init_msg_start,
1692 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_init_msg() entering\n");
1693 
1694 	attr_id = trans_info->si_trans_attr_id;
1695 	method = trans_info->si_trans_method;
1696 	client_data = trans_info->si_trans_client_data;
1697 	saa_portp   = trans_info->si_trans_port;
1698 
1699 	if (sleep_flag == B_TRUE) {
1700 		ibmf_sleep_flag = IBMF_ALLOC_SLEEP;
1701 		km_sleep_flag = KM_SLEEP;
1702 	} else {
1703 		ibmf_sleep_flag = IBMF_ALLOC_NOSLEEP;
1704 		km_sleep_flag = KM_NOSLEEP;
1705 	}
1706 
1707 	ibmf_status = ibmf_alloc_msg(saa_portp->saa_pt_ibmf_handle,
1708 	    ibmf_sleep_flag, &ibmf_msg);
1709 	if (ibmf_status != IBMF_SUCCESS) {
1710 
1711 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
1712 		    ibmf_saa_impl_init_msg_err, IBMF_TNF_ERROR, "",
1713 		    "ibmf_saa_impl_init_msg: %s, ibmf_status = %d\n",
1714 		    tnf_string, msg, "Cannot allocate msg_buf.",
1715 		    tnf_int, ibmf_status, ibmf_status);
1716 
1717 		goto bail;
1718 	}
1719 
1720 	req_mad = &ibmf_msg->im_msgbufs_send;
1721 
1722 	/* create a template (SA MAD) */
1723 	mad_hdr = kmem_zalloc(sizeof (ib_mad_hdr_t), km_sleep_flag);
1724 
1725 	if (mad_hdr == NULL) {
1726 
1727 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1728 		    ibmf_saa_impl_init_msg_err, IBMF_TNF_ERROR, "",
1729 		    "ibmf_saa_impl_init_msg: %s\n",
1730 		    tnf_string, msg, "Cannot allocate mad header.");
1731 
1732 		free_res = ibmf_free_msg(saa_portp->saa_pt_ibmf_handle,
1733 		    &ibmf_msg);
1734 		ASSERT(free_res == IBMF_SUCCESS);
1735 
1736 		ibmf_status = IBMF_NO_MEMORY;
1737 		goto bail;
1738 	}
1739 
1740 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mad_hdr,
1741 	    *req_mad))
1742 
1743 	bzero(mad_hdr, sizeof (ib_mad_hdr_t));
1744 	mad_hdr->BaseVersion = SAA_MAD_BASE_VERSION;
1745 	mad_hdr->MgmtClass = MAD_MGMT_CLASS_SUBN_ADM;
1746 	mad_hdr->ClassVersion = SAA_MAD_CLASS_VERSION;
1747 	mad_hdr->R_Method = method;
1748 	mad_hdr->AttributeID = h2b16(attr_id);
1749 
1750 	/* attribute modifier is all Fs since RIDs are no longer used */
1751 	mad_hdr->AttributeModifier = h2b32(0xffffffff);
1752 
1753 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L3,
1754 	    ibmf_saa_impl_init_msg, IBMF_TNF_TRACE, "",
1755 	    "ibmf_saa_impl_init_msg: %s, class = 0x%x, method = 0x%x,"
1756 	    " attr_id = 0x%x\n", tnf_string, msg, "Sending MAD",
1757 	    tnf_opaque, class, mad_hdr->MgmtClass,
1758 	    tnf_opaque, method, mad_hdr->R_Method,
1759 	    tnf_opaque, attr_id, attr_id);
1760 
1761 	bzero(&sa_hdr, sizeof (ib_sa_hdr_t));
1762 	sa_hdr.ComponentMask = trans_info->si_trans_component_mask;
1763 
1764 	if (client_data != NULL)
1765 		sa_hdr.SM_KEY = client_data->saa_client_sm_key;
1766 
1767 	/*
1768 	 * pack data for IB wire format; req_mad will have different pointers to
1769 	 * sa header and payload, mad_hdr will be the same
1770 	 */
1771 	req_mad->im_bufs_mad_hdr = mad_hdr;
1772 
1773 	ibmf_status = ibmf_saa_utils_pack_sa_hdr(&sa_hdr,
1774 	    &req_mad->im_bufs_cl_hdr, &req_mad->im_bufs_cl_hdr_len,
1775 	    km_sleep_flag);
1776 
1777 	if (ibmf_status != IBMF_SUCCESS) {
1778 
1779 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
1780 		    ibmf_saa_impl_init_msg, IBMF_TNF_ERROR, "",
1781 		    "ibmf_saa_impl_init_msg: %s, ibmf_status = %d\n",
1782 		    tnf_string, msg, "ibmf_saa_utils_pack_sa_hdr() failed",
1783 		    tnf_int, ibmf_status, ibmf_status);
1784 
1785 		kmem_free(mad_hdr, sizeof (ib_mad_hdr_t));
1786 
1787 		free_res = ibmf_free_msg(saa_portp->saa_pt_ibmf_handle,
1788 		    &ibmf_msg);
1789 		ASSERT(free_res == IBMF_SUCCESS);
1790 
1791 		goto bail;
1792 	}
1793 
1794 	if (attr_id == SA_MULTIPATHRECORD_ATTRID) {
1795 
1796 		multipath_template =
1797 		    (sa_multipath_record_t *)trans_info->si_trans_template;
1798 
1799 		payload_length = sizeof (sa_multipath_record_t) +
1800 		    ((multipath_template->SGIDCount +
1801 		    multipath_template->DGIDCount) * sizeof (ib_gid_t));
1802 
1803 		pack_attr_id = attr_id;
1804 	} else {
1805 
1806 		/* trace record template is a path record */
1807 		pack_attr_id = (attr_id == SA_TRACERECORD_ATTRID) ?
1808 		    SA_PATHRECORD_ATTRID : attr_id;
1809 
1810 		payload_length = ibmf_saa_impl_get_attr_id_length(pack_attr_id);
1811 
1812 		if (payload_length == 0) {
1813 			payload_length = trans_info->si_trans_template_length;
1814 
1815 			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
1816 			    ibmf_saa_impl_init_msg, IBMF_TNF_TRACE, "",
1817 			    "ibmf_saa_impl_init_msg: %s, length = %d\n",
1818 			    tnf_string, msg,
1819 			    "Unknown attribute.  Using user-defined length.",
1820 			    tnf_uint, length, payload_length)
1821 		}
1822 	}
1823 
1824 	/* transport type depends on method */
1825 	switch (method) {
1826 
1827 		case SA_SUBN_ADM_GET:
1828 		case SA_SUBN_ADM_DELETE:
1829 		case SA_SUBN_ADM_GET_TABLE:
1830 		case SA_SUBN_ADM_GET_TRACE_TABLE:
1831 			transport_flags = IBMF_MSG_TRANS_FLAG_SEQ;
1832 			break;
1833 		case SA_SUBN_ADM_SET:
1834 			/* unsubscribes can be sequenced or unsequenced */
1835 			if (trans_info->si_trans_unseq_unsubscribe == B_TRUE) {
1836 				transport_flags = 0;
1837 			} else {
1838 				transport_flags = IBMF_MSG_TRANS_FLAG_SEQ;
1839 			}
1840 			break;
1841 		case SA_SUBN_ADM_GET_MULTI:
1842 			transport_flags = IBMF_MSG_TRANS_FLAG_SEQ |
1843 			    IBMF_MSG_TRANS_FLAG_RMPP;
1844 			break;
1845 		default :
1846 			ibmf_status = IBMF_UNSUPP_METHOD;
1847 			goto bail;
1848 	}
1849 
1850 	trans_info->si_trans_transport_flags = transport_flags;
1851 
1852 	if (trans_info->si_trans_template != NULL) {
1853 
1854 		ibmf_status = ibmf_saa_utils_pack_payload(
1855 		    trans_info->si_trans_template, payload_length, pack_attr_id,
1856 		    &req_mad->im_bufs_cl_data, &req_mad->im_bufs_cl_data_len,
1857 		    km_sleep_flag);
1858 		if (ibmf_status != IBMF_SUCCESS) {
1859 
1860 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
1861 			    ibmf_saa_impl_init_msg_err, IBMF_TNF_ERROR, "",
1862 			    "ibmf_saa_impl_init_msg: %s, ibmf_status ="
1863 			    " %d\n", tnf_string, msg,
1864 			    "ibmf_saa_utils_pack_payload() failed",
1865 			    tnf_int, ibmf_status, ibmf_status);
1866 
1867 			kmem_free(mad_hdr, sizeof (ib_mad_hdr_t));
1868 
1869 			kmem_free(req_mad->im_bufs_cl_hdr,
1870 			    req_mad->im_bufs_cl_hdr_len);
1871 
1872 			free_res = ibmf_free_msg(saa_portp->saa_pt_ibmf_handle,
1873 			    &ibmf_msg);
1874 			ASSERT(free_res == IBMF_SUCCESS);
1875 
1876 			goto bail;
1877 		}
1878 
1879 		IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3,
1880 		    ibmf_saa_impl_init_msg, IBMF_TNF_TRACE, "",
1881 		    "ibmf_saa_impl_init_msg: %s, attr_id = 0x%x, length ="
1882 		    " %d\n", tnf_string, msg, "Packed payload successfully",
1883 		    tnf_opaque, attr_id, attr_id,
1884 		    tnf_uint, length, req_mad->im_bufs_cl_data_len);
1885 
1886 		/* non-RMPP transactions have template size limit */
1887 		if (((transport_flags & IBMF_MSG_TRANS_FLAG_RMPP) == 0) &&
1888 		    ((req_mad->im_bufs_cl_data_len + req_mad->im_bufs_cl_hdr_len
1889 		    + sizeof (ib_mad_hdr_t)) > IBMF_MAD_SIZE)) {
1890 
1891 			IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
1892 			    ibmf_saa_impl_init_msg_err, IBMF_TNF_ERROR, "",
1893 			    "ibmf_saa_impl_init_msg: %s\n", tnf_string, msg,
1894 			    "Template too large to fit in single packet");
1895 
1896 			kmem_free(mad_hdr, sizeof (ib_mad_hdr_t));
1897 
1898 			kmem_free(req_mad->im_bufs_cl_hdr,
1899 			    req_mad->im_bufs_cl_hdr_len);
1900 
1901 			kmem_free(req_mad->im_bufs_cl_data,
1902 			    req_mad->im_bufs_cl_data_len);
1903 
1904 			free_res = ibmf_free_msg(saa_portp->saa_pt_ibmf_handle,
1905 			    &ibmf_msg);
1906 			ASSERT(free_res == IBMF_SUCCESS);
1907 
1908 			ibmf_status = IBMF_REQ_INVALID;
1909 			goto bail;
1910 		}
1911 	}
1912 
1913 	mutex_enter(&saa_portp->saa_pt_mutex);
1914 
1915 	mad_hdr->TransactionID = h2b64(saa_portp->saa_pt_current_tid++);
1916 
1917 	bcopy(&saa_portp->saa_pt_ibmf_retrans, ibmf_retransp,
1918 	    sizeof (ibmf_retrans_t));
1919 
1920 	/* copy local addressing information to message */
1921 	bcopy(&saa_portp->saa_pt_ibmf_addr_info, &ibmf_msg->im_local_addr,
1922 	    sizeof (ibmf_addr_info_t));
1923 
1924 	/* copy global addressing information to message if in use */
1925 	if (saa_portp->saa_pt_ibmf_msg_flags & IBMF_MSG_FLAGS_GLOBAL_ADDRESS) {
1926 
1927 		ibmf_msg->im_msg_flags = IBMF_MSG_FLAGS_GLOBAL_ADDRESS;
1928 
1929 		bcopy(&saa_portp->saa_pt_ibmf_global_addr,
1930 		    &ibmf_msg->im_global_addr,
1931 		    sizeof (ibmf_global_addr_info_t));
1932 	} else {
1933 		ibmf_msg->im_msg_flags = 0;
1934 	}
1935 
1936 	mutex_exit(&saa_portp->saa_pt_mutex);
1937 
1938 	*msgp = ibmf_msg;
1939 	*transport_flagsp = transport_flags;
1940 bail:
1941 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1942 	    ibmf_saa_impl_init_msg_end,
1943 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_init_msg() exiting"
1944 	    " ibmf_status = %d\n", tnf_int, result, ibmf_status);
1945 
1946 	return (ibmf_status);
1947 
1948 }
1949 
1950 /*
1951  * ibmf_saa_impl_new_smlid_retry:
1952  *
1953  * It's possible for the MasterSMLID to change while ibmf_saa is running.  The
1954  * MasterSMLID is set when we first register with ibmf_saa.  If a request
1955  * timesout, this function should be called to check whether the SM LID changed.
1956  * If so, it will call msg_transport again with the request.
1957  *
1958  * msgp, ibmf_callback, ibmf_callback_arg, and transport flags should be the
1959  * same values passed to the original ibmf_msg_transport that timedout.  The
1960  * ibmf_retrans parameter will be re-retrieved from the saa_portp structure.
1961  *
1962  * If the lid did not change then this function returns IBMF_TRANS_TIMEOUT.
1963  * That way, callers can simply return the result of this function.
1964  *
1965  * Input Arguments
1966  * saa_portp		pointer to saa_port structure
1967  * msgp			ibmf message that timedout
1968  * ibmf_callback	callback that should be called by msg_transport
1969  * ibmf_callback_arg	args for ibmf_callback
1970  * transport_flags	flags for ibmf_msg_transport
1971  *
1972  * Output Arguments
1973  * none
1974  *
1975  * Returns
1976  * IBMF_SUCCESS if lid changed and request was resent successfully,
1977  * IBMF_TRANS_TIMEOUT if lid did not change,
1978  * same values as ibmf_msg_transport() if lid changed but request could not be
1979  * resent.
1980  */
1981 static int
1982 ibmf_saa_impl_new_smlid_retry(saa_port_t *saa_portp, ibmf_msg_t *msgp,
1983     ibmf_msg_cb_t ibmf_callback, void *ibmf_callback_arg, int transport_flags)
1984 {
1985 	ibt_hca_portinfo_t	*ibt_portinfop;
1986 	ib_lid_t		master_sm_lid;
1987 	int			subnet_timeout;
1988 	uint_t			nports, size;
1989 	ibmf_retrans_t		ibmf_retrans;
1990 	int			ibmf_status;
1991 	ibt_status_t		ibt_status;
1992 
1993 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1994 	    ibmf_saa_impl_new_smlid_retry_start,
1995 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_new_smlid_retry() enter\n");
1996 
1997 	_NOTE(ASSUMING_PROTECTED(*msgp))
1998 	_NOTE(ASSUMING_PROTECTED(*msgp->im_msgbufs_send.im_bufs_mad_hdr))
1999 
2000 	/* first query the portinfo to see if the lid changed */
2001 	ibt_status = ibt_query_hca_ports_byguid(saa_portp->saa_pt_node_guid,
2002 	    saa_portp->saa_pt_port_num, &ibt_portinfop, &nports, &size);
2003 
2004 	if (ibt_status != IBT_SUCCESS)  {
2005 
2006 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2007 		    ibmf_saa_impl_new_smlid_retry_err, IBMF_TNF_ERROR, "",
2008 		    "ibmf_saa_impl_new_smlid_retry: %s, ibmf_status ="
2009 		    " %d\n", tnf_string, msg,
2010 		    "ibt_query_hca_ports_byguid() failed",
2011 		    tnf_int, ibt_status, ibt_status);
2012 
2013 		ibmf_status = IBMF_TRANSPORT_FAILURE;
2014 
2015 		goto bail;
2016 	}
2017 
2018 	master_sm_lid = ibt_portinfop->p_sm_lid;
2019 	subnet_timeout = ibt_portinfop->p_subnet_timeout;
2020 
2021 	ibt_free_portinfo(ibt_portinfop, size);
2022 
2023 	/* if master smlid is different than the remote lid we sent to */
2024 	if (master_sm_lid != msgp->im_local_addr.ia_remote_lid) {
2025 
2026 		IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L2,
2027 		    ibmf_saa_impl_new_smlid_retry, IBMF_TNF_TRACE, "",
2028 		    "ibmf_saa_impl_new_smlid_retry: %s, new_lid 0x%x,"
2029 		    " old_lid 0x%x\n", tnf_string, msg,
2030 		    "master smlid has changed.  retrying msg_transport",
2031 		    tnf_opaque, new_lid, master_sm_lid,
2032 		    tnf_opaque, old_lid, msgp->im_local_addr.ia_remote_lid);
2033 
2034 		mutex_enter(&saa_portp->saa_pt_mutex);
2035 
2036 		/* update the master sm lid value in ibmf_saa */
2037 		saa_portp->saa_pt_ibmf_addr_info.ia_remote_lid =
2038 		    master_sm_lid;
2039 
2040 		/* new tid needed */
2041 		msgp->im_msgbufs_send.im_bufs_mad_hdr->TransactionID =
2042 		    h2b64(saa_portp->saa_pt_current_tid++);
2043 
2044 		bcopy(&saa_portp->saa_pt_ibmf_retrans, &ibmf_retrans,
2045 		    sizeof (ibmf_retrans_t));
2046 
2047 		/* update the subnet timeout since this may be a new sm/sa */
2048 		saa_portp->saa_pt_timeout = subnet_timeout;
2049 
2050 		/* place upper bound on subnet timeout in case of faulty SM */
2051 		if (saa_portp->saa_pt_timeout > ibmf_saa_max_subnet_timeout)
2052 			saa_portp->saa_pt_timeout = ibmf_saa_max_subnet_timeout;
2053 
2054 		/* increment the reference count to account for the cpi call */
2055 		saa_portp->saa_pt_reference_count++;
2056 
2057 		mutex_exit(&saa_portp->saa_pt_mutex);
2058 
2059 		/* update the remote lid for this particular message */
2060 		msgp->im_local_addr.ia_remote_lid = master_sm_lid;
2061 
2062 		/* get the classportinfo again since this may be a new sm/sa */
2063 		ibmf_saa_impl_get_classportinfo(saa_portp);
2064 
2065 		ibmf_status = ibmf_msg_transport(saa_portp->saa_pt_ibmf_handle,
2066 		    saa_portp->saa_pt_qp_handle, msgp, &ibmf_retrans,
2067 		    ibmf_callback, ibmf_callback_arg, transport_flags);
2068 
2069 		if (ibmf_status != IBMF_SUCCESS) {
2070 
2071 			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
2072 			    ibmf_saa_impl_new_smlid_retry, IBMF_TNF_TRACE, "",
2073 			    "ibmf_saa_impl_new_smlid_retry: %s, ibmf_status = "
2074 			    "%d\n", tnf_string, msg,
2075 			    "ibmf_msg_transport() failed",
2076 			    tnf_int, ibmf_status, ibmf_status);
2077 		}
2078 
2079 		goto bail;
2080 	}
2081 
2082 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
2083 	    ibmf_saa_impl_new_smlid_retry, IBMF_TNF_TRACE, "",
2084 	    "ibmf_saa_impl_new_smlid_retry: %s, master_smlid = 0x%x\n",
2085 	    tnf_string, msg,
2086 	    "master smlid did not change.  returning failure",
2087 	    tnf_opaque, master_smlid, master_sm_lid);
2088 
2089 	/* mark status as timeout since that was original failure */
2090 	ibmf_status = IBMF_TRANS_TIMEOUT;
2091 
2092 bail:
2093 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
2094 	    ibmf_saa_impl_new_smlid_retry_end,
2095 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_new_smlid_retry() exiting"
2096 	    " ibmf_status = %d\n", tnf_int, result, ibmf_status);
2097 
2098 	return (ibmf_status);
2099 }
2100 
2101 /*
2102  * ibmf_saa_impl_revert_to_qp1()
2103  *
2104  * The SA that we had contact with via redirect may fail to respond. If this
2105  * occurs SA should revert back to qp1 and the SMLID set in the port.
2106  * msg_transport for the message that timed out will be retried with
2107  * these new parameters.
2108  *
2109  * msgp, ibmf_callback, ibmf_callback_arg, and transport flags should be the
2110  * same values passed to the original ibmf_msg_transport that timedout.  The
2111  * ibmf_retrans parameter will be re-retrieved from the saa_portp structure.
2112  *
2113  * Input Arguments
2114  * saa_portp		pointer to saa_port structure
2115  * msgp			ibmf message that timedout
2116  * ibmf_callback	callback that should be called by msg_transport
2117  * ibmf_callback_arg	args for ibmf_callback
2118  * transport_flags	flags for ibmf_msg_transport
2119  *
2120  * Output Arguments
2121  * none
2122  *
2123  * Returns
2124  * none
2125  */
2126 static int
2127 ibmf_saa_impl_revert_to_qp1(saa_port_t *saa_portp, ibmf_msg_t *msgp,
2128     ibmf_msg_cb_t ibmf_callback, void *ibmf_callback_args, int transport_flags)
2129 {
2130 	ibt_hca_portinfo_t	*ibt_portinfop;
2131 	ib_lid_t		master_sm_lid, base_lid;
2132 	uint8_t			sm_sl;
2133 	int			subnet_timeout;
2134 	uint_t			nports, size;
2135 	ibmf_retrans_t		ibmf_retrans;
2136 	int			ibmf_status;
2137 	ibt_status_t		ibt_status;
2138 
2139 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
2140 	    ibmf_saa_impl_revert_to_qp1_start,
2141 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_revert_to_qp1() enter\n");
2142 
2143 	_NOTE(ASSUMING_PROTECTED(*msgp))
2144 	_NOTE(ASSUMING_PROTECTED(*msgp->im_msgbufs_send.im_bufs_mad_hdr))
2145 
2146 	/* first query the portinfo to see if the lid changed */
2147 	ibt_status = ibt_query_hca_ports_byguid(saa_portp->saa_pt_node_guid,
2148 	    saa_portp->saa_pt_port_num, &ibt_portinfop, &nports, &size);
2149 
2150 	if (ibt_status != IBT_SUCCESS)  {
2151 
2152 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2153 		    ibmf_saa_impl_revert_to_qp1_err, IBMF_TNF_ERROR, "",
2154 		    "ibmf_saa_impl_revert_to_qp1: %s, ibmf_status ="
2155 		    " %d\n", tnf_string, msg,
2156 		    "ibt_query_hca_ports_byguid() failed",
2157 		    tnf_int, ibt_status, ibt_status);
2158 
2159 		ibmf_status = IBMF_TRANSPORT_FAILURE;
2160 
2161 		goto bail;
2162 	}
2163 
2164 	master_sm_lid = ibt_portinfop->p_sm_lid;
2165 	base_lid = ibt_portinfop->p_base_lid;
2166 	sm_sl = ibt_portinfop->p_sm_sl;
2167 	subnet_timeout = ibt_portinfop->p_subnet_timeout;
2168 
2169 	ibt_free_portinfo(ibt_portinfop, size);
2170 
2171 
2172 	mutex_enter(&saa_portp->saa_pt_mutex);
2173 
2174 	saa_portp->saa_pt_redirect_active = B_FALSE;
2175 
2176 	/* update the address info in ibmf_saa */
2177 	saa_portp->saa_pt_ibmf_addr_info.ia_local_lid = base_lid;
2178 	saa_portp->saa_pt_ibmf_addr_info.ia_remote_lid = master_sm_lid;
2179 	saa_portp->saa_pt_ibmf_addr_info.ia_service_level = sm_sl;
2180 	saa_portp->saa_pt_ibmf_addr_info.ia_remote_qno = 1;
2181 	saa_portp->saa_pt_ibmf_addr_info.ia_p_key = IB_PKEY_DEFAULT_LIMITED;
2182 	saa_portp->saa_pt_ibmf_addr_info.ia_q_key = IB_GSI_QKEY;
2183 	saa_portp->saa_pt_ibmf_msg_flags = 0;
2184 
2185 	/* new tid needed */
2186 	msgp->im_msgbufs_send.im_bufs_mad_hdr->TransactionID =
2187 	    h2b64(saa_portp->saa_pt_current_tid++);
2188 
2189 	bcopy(&saa_portp->saa_pt_ibmf_retrans, &ibmf_retrans,
2190 	    sizeof (ibmf_retrans_t));
2191 
2192 	/* update the subnet timeout since this may be a new sm/sa */
2193 	saa_portp->saa_pt_timeout = subnet_timeout;
2194 
2195 	/* place upper bound on subnet timeout in case of faulty SM */
2196 	if (saa_portp->saa_pt_timeout > ibmf_saa_max_subnet_timeout)
2197 		saa_portp->saa_pt_timeout = ibmf_saa_max_subnet_timeout;
2198 
2199 	/* increment the reference count to account for the cpi call */
2200 	saa_portp->saa_pt_reference_count++;
2201 
2202 	mutex_exit(&saa_portp->saa_pt_mutex);
2203 
2204 	/* update the address info for this particular message */
2205 	bcopy(&saa_portp->saa_pt_ibmf_addr_info, &msgp->im_local_addr,
2206 	    sizeof (ibmf_addr_info_t));
2207 	msgp->im_msg_flags = 0; /* No GRH */
2208 
2209 	/* get the classportinfo again since this may be a new sm/sa */
2210 	ibmf_saa_impl_get_classportinfo(saa_portp);
2211 
2212 	ibmf_status = ibmf_msg_transport(saa_portp->saa_pt_ibmf_handle,
2213 	    saa_portp->saa_pt_qp_handle, msgp, &ibmf_retrans,
2214 	    ibmf_callback, ibmf_callback_args, transport_flags);
2215 
2216 	if (ibmf_status != IBMF_SUCCESS) {
2217 
2218 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
2219 		    ibmf_saa_impl_revert_to_qp1, IBMF_TNF_TRACE, "",
2220 		    "ibmf_saa_impl_revert_to_qp1: %s, ibmf_status = "
2221 		    "%d\n", tnf_string, msg,
2222 		    "ibmf_msg_transport() failed",
2223 		    tnf_int, ibmf_status, ibmf_status);
2224 	}
2225 
2226 bail:
2227 
2228 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
2229 	    ibmf_saa_impl_revert_to_qp1_end,
2230 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_revert_to_qp1() exiting"
2231 	    " ibmf_status = %d\n", tnf_int, result, ibmf_status);
2232 
2233 	return (ibmf_status);
2234 }
2235 
2236 /*
2237  * ibmf_saa_impl_async_event_cb:
2238  *	ibmf event callback, argument to ibmf_register
2239  *	ibmf_handle is unused
2240  */
2241 /*  ARGSUSED */
2242 static void
2243 ibmf_saa_impl_async_event_cb(
2244 	ibmf_handle_t		ibmf_handle,
2245 	void			*clnt_private,
2246 	ibmf_async_event_t	event_type)
2247 {
2248 	saa_port_t		*saa_portp;
2249 
2250 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
2251 	    ibmf_saa_impl_async_event_cb_start, IBMF_TNF_TRACE, "",
2252 	    "ibmf_saa_impl_async_event_cb: Handling event type 0x%x\n",
2253 	    tnf_opaque, event_type, event_type);
2254 
2255 	saa_portp = (saa_port_t *)clnt_private;
2256 	ASSERT(saa_portp != NULL);
2257 
2258 	switch (event_type) {
2259 
2260 	case IBMF_CI_OFFLINE:
2261 		ibmf_saa_impl_hca_detach(saa_portp);
2262 		break;
2263 	default:
2264 		break;
2265 	}
2266 
2267 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L3,
2268 	    ibmf_saa_impl_async_event_cb_end,
2269 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_async_event_cb() exit\n");
2270 }
2271 
2272 
2273 /*
2274  * ibmf_saa_impl_ibt_async_handler:
2275  * MUST NOT BE STATIC (referred from within IBMF)
2276  */
2277 void
2278 ibmf_saa_impl_ibt_async_handler(ibt_async_code_t code, ibt_async_event_t *event)
2279 {
2280 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
2281 	    ibmf_saa_impl_ibt_async_handler_start, IBMF_TNF_TRACE, "",
2282 	    "ibmf_saa_impl_ibt_async_handler: Handling event code 0x%x\n",
2283 	    tnf_opaque, code, code);
2284 
2285 	switch (code) {
2286 
2287 	case IBT_EVENT_PORT_UP:
2288 		ibmf_saa_impl_port_up(event->ev_hca_guid, event->ev_port);
2289 		break;
2290 	case IBT_ERROR_PORT_DOWN:
2291 		ibmf_saa_impl_port_down(event->ev_hca_guid, event->ev_port);
2292 		break;
2293 	case IBT_PORT_CHANGE_EVENT:
2294 		ibmf_saa_impl_port_chg(event);
2295 		break;
2296 	case IBT_CLNT_REREG_EVENT:
2297 		ibmf_saa_impl_client_rereg(event->ev_hca_guid, event->ev_port);
2298 		break;
2299 	default:
2300 		break;
2301 	}
2302 
2303 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_async_handler_end,
2304 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_ibt_async_handler() exit\n");
2305 }
2306 
2307 /*
2308  * ibmf_saa_impl_port_chg:
2309  */
2310 static void
2311 ibmf_saa_impl_port_chg(ibt_async_event_t *event)
2312 {
2313 	saa_port_t		*saa_portp	= NULL;
2314 	boolean_t		is_ready = B_FALSE;
2315 	ibt_hca_portinfo_t	*ibt_portinfop;
2316 	uint_t			nports, size;
2317 	ibt_status_t		ibt_status;
2318 	ib_guid_t		ci_guid;
2319 	int			port_num;
2320 
2321 	ci_guid = event->ev_hca_guid;
2322 	port_num = event->ev_port;
2323 
2324 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_saa_impl_port_chg_start,
2325 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_port_chg: Handling port chg"
2326 	    " guid %016" PRIx64 " port %d\n",
2327 	    tnf_opaque, hca_guid, ci_guid, tnf_uint, port, port_num);
2328 
2329 	/* Get classportinfo of corresponding entry */
2330 	mutex_enter(&saa_statep->saa_port_list_mutex);
2331 
2332 	saa_portp = saa_statep->saa_port_list;
2333 	while (saa_portp != NULL) {
2334 		if (saa_portp->saa_pt_ibmf_reginfo.ir_ci_guid == ci_guid &&
2335 		    saa_portp->saa_pt_ibmf_reginfo.ir_port_num == port_num) {
2336 			mutex_enter(&saa_portp->saa_pt_mutex);
2337 
2338 			is_ready = (saa_portp->saa_pt_state
2339 			    == IBMF_SAA_PORT_STATE_READY) ? B_TRUE : B_FALSE;
2340 
2341 			/*
2342 			 * increment reference count to account for cpi and
2343 			 * informinfos.  All 4 informinfo's sent are treated as
2344 			 * one port client reference
2345 			 */
2346 			if (is_ready)
2347 				saa_portp->saa_pt_reference_count ++;
2348 
2349 			mutex_exit(&saa_portp->saa_pt_mutex);
2350 
2351 			if (is_ready)
2352 				break; /* normally, only 1 port entry */
2353 		}
2354 		saa_portp = saa_portp->next;
2355 	}
2356 
2357 	mutex_exit(&saa_statep->saa_port_list_mutex);
2358 
2359 	if (saa_portp != NULL) {
2360 		/* first query the portinfo to see if the lid changed */
2361 		ibt_status = ibt_query_hca_ports_byguid(ci_guid, port_num,
2362 		    &ibt_portinfop, &nports, &size);
2363 
2364 		if (ibt_status != IBT_SUCCESS) {
2365 
2366 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2367 			    ibmf_saa_impl_port_chg_err, IBMF_TNF_ERROR, "",
2368 			    "ibmf_saa_impl_port_chg: %s, ibmf_status ="
2369 			    " %d\n", tnf_string, msg,
2370 			    "ibt_query_hca_ports_byguid() failed",
2371 			    tnf_int, ibt_status, ibt_status);
2372 
2373 			goto bail;
2374 		}
2375 
2376 		mutex_enter(&saa_portp->saa_pt_mutex);
2377 		if (event->ev_port_flags & IBT_PORT_CHANGE_SM_LID) {
2378 			/* update the Master SM Lid value in ibmf_saa */
2379 			saa_portp->saa_pt_ibmf_addr_info.ia_remote_lid =
2380 			    ibt_portinfop->p_sm_lid;
2381 		}
2382 		if (event->ev_port_flags & IBT_PORT_CHANGE_SM_SL) {
2383 			/* update the Master SM SL value in ibmf_saa */
2384 			saa_portp->saa_pt_ibmf_addr_info.ia_service_level =
2385 			    ibt_portinfop->p_sm_sl;
2386 		}
2387 		if (event->ev_port_flags & IBT_PORT_CHANGE_SUB_TIMEOUT) {
2388 			/* update the Subnet timeout value in ibmf_saa */
2389 			saa_portp->saa_pt_timeout =
2390 			    ibt_portinfop->p_subnet_timeout;
2391 		}
2392 		mutex_exit(&saa_portp->saa_pt_mutex);
2393 
2394 		ibt_free_portinfo(ibt_portinfop, size);
2395 
2396 		/* get the classportinfo again */
2397 		ibmf_saa_impl_get_classportinfo(saa_portp);
2398 	}
2399 bail:
2400 
2401 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_port_chg_end,
2402 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_port_chg() exit\n");
2403 }
2404 /*
2405  * ibmf_saa_impl_client_rereg:
2406  */
2407 static void
2408 ibmf_saa_impl_client_rereg(ib_guid_t ci_guid, uint8_t port_num)
2409 {
2410 	saa_port_t		*saa_portp	= NULL;
2411 	boolean_t		is_ready = B_FALSE;
2412 	ibt_hca_portinfo_t	*ibt_portinfop;
2413 	ib_lid_t		master_sm_lid;
2414 	uint_t			nports, size;
2415 	ibt_status_t		ibt_status;
2416 	boolean_t		event_subs = B_FALSE;
2417 
2418 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_saa_impl_port_rereg_start,
2419 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_client_rereg: Handling clnt "
2420 	    "rereg guid %016" PRIx64 " port %d\n",
2421 	    tnf_opaque, hca_guid, ci_guid, tnf_uint, port, port_num);
2422 
2423 	/* Get classportinfo of corresponding entry */
2424 	mutex_enter(&saa_statep->saa_port_list_mutex);
2425 
2426 	saa_portp = saa_statep->saa_port_list;
2427 	while (saa_portp != NULL) {
2428 
2429 		if (saa_portp->saa_pt_ibmf_reginfo.ir_ci_guid == ci_guid &&
2430 		    saa_portp->saa_pt_ibmf_reginfo.ir_port_num == port_num) {
2431 
2432 			mutex_enter(&saa_portp->saa_pt_mutex);
2433 
2434 			is_ready = (saa_portp->saa_pt_state
2435 			    == IBMF_SAA_PORT_STATE_READY) ? B_TRUE : B_FALSE;
2436 
2437 			/*
2438 			 * increment reference count to account for cpi and
2439 			 * informinfos.  All 4 informinfo's sent are treated as
2440 			 * one port client reference
2441 			 */
2442 			if (is_ready)
2443 				saa_portp->saa_pt_reference_count += 2;
2444 
2445 			mutex_exit(&saa_portp->saa_pt_mutex);
2446 
2447 			if (is_ready)
2448 				break; /* normally, only 1 port entry */
2449 		}
2450 		saa_portp = saa_portp->next;
2451 	}
2452 
2453 	mutex_exit(&saa_statep->saa_port_list_mutex);
2454 
2455 	if (saa_portp != NULL && is_ready == B_TRUE) {
2456 
2457 		/* verify whether master sm lid changed */
2458 
2459 		/* first query the portinfo to see if the lid changed */
2460 		ibt_status = ibt_query_hca_ports_byguid(ci_guid, port_num,
2461 		    &ibt_portinfop, &nports, &size);
2462 
2463 		if (ibt_status != IBT_SUCCESS) {
2464 
2465 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2466 			    ibmf_saa_impl_port_rereg_err, IBMF_TNF_ERROR, "",
2467 			    "ibmf_saa_impl_client_rereg: %s, ibmf_status ="
2468 			    " %d\n", tnf_string, msg,
2469 			    "ibt_query_hca_ports_byguid() failed",
2470 			    tnf_int, ibt_status, ibt_status);
2471 
2472 			goto bail;
2473 		}
2474 
2475 		master_sm_lid = ibt_portinfop->p_sm_lid;
2476 
2477 		ibt_free_portinfo(ibt_portinfop, size);
2478 
2479 		/* check whether we need to subscribe for events */
2480 		mutex_enter(&saa_portp->saa_pt_event_sub_mutex);
2481 
2482 		event_subs = (saa_portp->saa_pt_event_sub_client_list != NULL) ?
2483 		    B_TRUE : B_FALSE;
2484 
2485 		mutex_exit(&saa_portp->saa_pt_event_sub_mutex);
2486 
2487 		/* update the master smlid */
2488 		mutex_enter(&saa_portp->saa_pt_mutex);
2489 
2490 		/* update the master sm lid value in ibmf_saa */
2491 		saa_portp->saa_pt_ibmf_addr_info.ia_remote_lid =
2492 		    master_sm_lid;
2493 
2494 		/* if we're not subscribed for events, dec reference count */
2495 		if (event_subs == B_FALSE)
2496 			saa_portp->saa_pt_reference_count--;
2497 
2498 		mutex_exit(&saa_portp->saa_pt_mutex);
2499 
2500 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
2501 		    ibmf_saa_impl_port_rereg, IBMF_TNF_TRACE, "",
2502 		    "ibmf_saa_impl_client_rereg: %s, master_sm_lid = 0x%x\n",
2503 		    tnf_string, msg,
2504 		    "port is up.  Sending classportinfo request",
2505 		    tnf_opaque, master_sm_lid, master_sm_lid);
2506 
2507 		/* get the classportinfo again */
2508 		ibmf_saa_impl_get_classportinfo(saa_portp);
2509 
2510 		/*
2511 		 * resubscribe to events if there are subscribers since SA may
2512 		 * have removed our subscription records when the port went down
2513 		 */
2514 		if (event_subs == B_TRUE)
2515 			ibmf_saa_subscribe_events(saa_portp, B_TRUE, B_FALSE);
2516 	}
2517 
2518 bail:
2519 
2520 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_port_rereg_end,
2521 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_client_rereg() exit\n");
2522 }
2523 /*
2524  * ibmf_saa_impl_port_up:
2525  */
2526 static void
2527 ibmf_saa_impl_port_up(ib_guid_t ci_guid, uint8_t port_num)
2528 {
2529 	saa_port_t		*saa_portp	= NULL;
2530 	int			is_ready;
2531 	ibt_hca_portinfo_t	*ibt_portinfop;
2532 	ib_lid_t		master_sm_lid;
2533 	uint_t			nports, size;
2534 	ibt_status_t		ibt_status;
2535 	boolean_t		event_subs = B_FALSE;
2536 
2537 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_saa_impl_port_up_start,
2538 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_port_up: Handling port up"
2539 	    " guid %016" PRIx64 " port %d\n",
2540 	    tnf_opaque, hca_guid, ci_guid, tnf_uint, port, port_num);
2541 
2542 	/* Get classportinfo of corresponding entry */
2543 	mutex_enter(&saa_statep->saa_port_list_mutex);
2544 
2545 	saa_portp = saa_statep->saa_port_list;
2546 	while (saa_portp != NULL) {
2547 
2548 		if (saa_portp->saa_pt_ibmf_reginfo.ir_ci_guid == ci_guid &&
2549 		    saa_portp->saa_pt_ibmf_reginfo.ir_port_num == port_num) {
2550 
2551 			mutex_enter(&saa_portp->saa_pt_mutex);
2552 
2553 			is_ready = (saa_portp->saa_pt_state
2554 			    == IBMF_SAA_PORT_STATE_READY) ? B_TRUE : B_FALSE;
2555 
2556 			/*
2557 			 * increment reference count to account for cpi and
2558 			 * informinfos.  All 4 informinfo's sent are treated as
2559 			 * one port client reference
2560 			 */
2561 			if (is_ready == B_TRUE)
2562 				saa_portp->saa_pt_reference_count += 2;
2563 
2564 			mutex_exit(&saa_portp->saa_pt_mutex);
2565 
2566 			if (is_ready == B_TRUE)
2567 				break; /* normally, only 1 port entry */
2568 		}
2569 		saa_portp = saa_portp->next;
2570 	}
2571 
2572 	mutex_exit(&saa_statep->saa_port_list_mutex);
2573 
2574 	if (saa_portp != NULL && is_ready == B_TRUE) {
2575 
2576 		/* verify whether master sm lid changed */
2577 
2578 		/* first query the portinfo to see if the lid changed */
2579 		ibt_status = ibt_query_hca_ports_byguid(ci_guid, port_num,
2580 		    &ibt_portinfop, &nports, &size);
2581 
2582 		if (ibt_status != IBT_SUCCESS) {
2583 
2584 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2585 			    ibmf_saa_impl_port_up_err, IBMF_TNF_ERROR, "",
2586 			    "ibmf_saa_impl_port_up: %s, ibmf_status ="
2587 			    " %d\n", tnf_string, msg,
2588 			    "ibt_query_hca_ports_byguid() failed",
2589 			    tnf_int, ibt_status, ibt_status);
2590 
2591 			goto bail;
2592 		}
2593 
2594 		master_sm_lid = ibt_portinfop->p_sm_lid;
2595 
2596 		ibt_free_portinfo(ibt_portinfop, size);
2597 
2598 		/* check whether we need to subscribe for events */
2599 		mutex_enter(&saa_portp->saa_pt_event_sub_mutex);
2600 
2601 		event_subs = (saa_portp->saa_pt_event_sub_client_list != NULL) ?
2602 		    B_TRUE : B_FALSE;
2603 
2604 		mutex_exit(&saa_portp->saa_pt_event_sub_mutex);
2605 
2606 		/* update the master smlid */
2607 		mutex_enter(&saa_portp->saa_pt_mutex);
2608 
2609 		/* update the master sm lid value in ibmf_saa */
2610 		saa_portp->saa_pt_ibmf_addr_info.ia_remote_lid =
2611 		    master_sm_lid;
2612 
2613 		/* if we're not subscribed for events, dec reference count */
2614 		if (event_subs == B_FALSE)
2615 			saa_portp->saa_pt_reference_count--;
2616 
2617 		mutex_exit(&saa_portp->saa_pt_mutex);
2618 
2619 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
2620 		    ibmf_saa_impl_port_up, IBMF_TNF_TRACE, "",
2621 		    "ibmf_saa_impl_port_up: %s, master_sm_lid = 0x%x\n",
2622 		    tnf_string, msg,
2623 		    "port is up.  Sending classportinfo request",
2624 		    tnf_opaque, master_sm_lid, master_sm_lid);
2625 
2626 		/* get the classportinfo again */
2627 		ibmf_saa_impl_get_classportinfo(saa_portp);
2628 
2629 		/*
2630 		 * resubscribe to events if there are subscribers since SA may
2631 		 * have removed our subscription records when the port went down
2632 		 */
2633 		if (event_subs == B_TRUE)
2634 			ibmf_saa_subscribe_events(saa_portp, B_TRUE, B_FALSE);
2635 	}
2636 
2637 bail:
2638 
2639 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_port_up_end,
2640 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_port_up() exit\n");
2641 }
2642 
2643 /*
2644  * ibmf_saa_impl_port_down:
2645  */
2646 static void
2647 ibmf_saa_impl_port_down(ib_guid_t ci_guid, uint8_t port_num)
2648 {
2649 
2650 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_saa_impl_port_down_start,
2651 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_port_down: Handling port down"
2652 	    " guid %016" PRIx64 " port %d\n",
2653 	    tnf_opaque, hca_guid, ci_guid, tnf_uint, port, port_num);
2654 
2655 
2656 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_port_down_end,
2657 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_port_down() exit\n");
2658 }
2659 
2660 /*
2661  * ibmf_saa_impl_hca_detach:
2662  * find entry, unregister if there are no clients
2663  * have to unregister since ibmf needs to close the hca and will only do this if
2664  * no clients are registered
2665  */
2666 static void
2667 ibmf_saa_impl_hca_detach(saa_port_t *saa_removed)
2668 {
2669 	saa_port_t 	*saa_portp;
2670 	boolean_t	must_unreg, must_unsub;
2671 
2672 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_saa_impl_hca_detach_start,
2673 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_hca_detach: Detaching"
2674 	    " entry %016" PRIx64 "\n", tnf_opaque, entry, saa_removed);
2675 
2676 	/* find this entry */
2677 	mutex_enter(&saa_statep->saa_port_list_mutex);
2678 
2679 	saa_portp = saa_statep->saa_port_list;
2680 	while (saa_portp != NULL) {
2681 
2682 		if (saa_portp == saa_removed)
2683 			break;
2684 
2685 		saa_portp = saa_portp->next;
2686 	}
2687 	mutex_exit(&saa_statep->saa_port_list_mutex);
2688 
2689 	ASSERT(saa_portp != NULL);
2690 
2691 	if (saa_portp == NULL) {
2692 
2693 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L1,
2694 		    ibmf_saa_impl_hca_detach, IBMF_TNF_TRACE, "",
2695 		    "ibmf_saa_impl_hca_detach: %s, entry %016"
2696 		    PRIx64 "\n",
2697 		    tnf_string, msg,
2698 		    "Port entry NOT found",
2699 		    tnf_opaque, entryp, saa_removed);
2700 
2701 		goto bail;
2702 	}
2703 
2704 	/* if there are clients expecting Reports(), unsusbscribe */
2705 	mutex_enter(&saa_portp->saa_pt_event_sub_mutex);
2706 
2707 	must_unsub = (saa_portp->saa_pt_event_sub_client_list != NULL) ?
2708 	    B_TRUE : B_FALSE;
2709 
2710 	mutex_exit(&saa_portp->saa_pt_event_sub_mutex);
2711 
2712 	/* fail if outstanding transactions */
2713 	mutex_enter(&saa_portp->saa_pt_mutex);
2714 
2715 	if (saa_portp->saa_pt_num_outstanding_trans > 0) {
2716 
2717 		IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L1,
2718 		    ibmf_saa_impl_fini_err, IBMF_TNF_TRACE, "",
2719 		    "ibmf_saa_impl_fini: %s, port = %016" PRIx64
2720 		    ", num transactions = %d\n",
2721 		    tnf_string, msg, "Detaching HCA."
2722 		    "  Outstanding transactions on port.",
2723 		    tnf_opaque, port,
2724 		    saa_portp->saa_pt_port_guid,
2725 		    tnf_uint, outstanding_transactions,
2726 		    saa_portp->saa_pt_num_outstanding_trans);
2727 
2728 		mutex_exit(&saa_portp->saa_pt_mutex);
2729 
2730 		goto bail;
2731 	}
2732 
2733 
2734 	/*
2735 	 * increment reference count by one to account for unsubscribe requests
2736 	 * that are about to be sent.  All four informinfo's are treated as one
2737 	 * port client reference.  The count will be decremented by
2738 	 * subscribe_events() before the call returns.
2739 	 */
2740 	if (must_unsub == B_TRUE)
2741 		saa_portp->saa_pt_reference_count++;
2742 
2743 	mutex_exit(&saa_portp->saa_pt_mutex);
2744 
2745 	/*
2746 	 * try and unsubscribe from SA.  Generate synchronous, unsequenced
2747 	 * unsubscribe requests.
2748 	 */
2749 	if (must_unsub == B_TRUE)
2750 		ibmf_saa_subscribe_events(saa_portp, B_FALSE, B_TRUE);
2751 
2752 	/* warning if registered clients */
2753 	mutex_enter(&saa_portp->saa_pt_mutex);
2754 
2755 	if (saa_portp->saa_pt_reference_count > 0) {
2756 
2757 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L1,
2758 		    ibmf_saa_impl_hca_detach, IBMF_TNF_TRACE, "",
2759 		    "ibmf_saa_impl_hca_detach: %s, port %016"
2760 		    PRIx64 "\n",
2761 		    tnf_string, msg,
2762 		    "Detaching HCA for port with clients still"
2763 		    " registered", tnf_opaque, port,
2764 		    saa_portp->saa_pt_port_guid);
2765 	}
2766 
2767 	/* synchronize on end of registration */
2768 	while (saa_portp->saa_pt_state == IBMF_SAA_PORT_STATE_REGISTERING) {
2769 
2770 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L1,
2771 		    ibmf_saa_impl_hca_detach, IBMF_TNF_TRACE, "",
2772 		    "ibmf_saa_impl_hca_detach: %s\n",
2773 		    tnf_string, msg, "someone is registering. waiting"
2774 		    " for them to finish");
2775 
2776 		cv_wait(&saa_portp->saa_pt_ibmf_reg_cv,
2777 		    &saa_portp->saa_pt_mutex);
2778 
2779 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L1,
2780 		    ibmf_saa_impl_hca_detach,
2781 		    IBMF_TNF_TRACE, "", "ibmf_saa_impl_hca_detach: %s\n",
2782 		    tnf_string, msg, "done waiting");
2783 	}
2784 
2785 	/* unregister from ibmf */
2786 	if (saa_portp->saa_pt_state == IBMF_SAA_PORT_STATE_READY) {
2787 		must_unreg = B_TRUE;
2788 	} else
2789 		must_unreg = B_FALSE;
2790 
2791 	ibmf_saa_impl_invalidate_port(saa_portp);
2792 
2793 	mutex_exit(&saa_portp->saa_pt_mutex);
2794 
2795 	if (must_unreg == B_TRUE) {
2796 		if (ibmf_saa_impl_ibmf_unreg(saa_portp) != IBMF_SUCCESS) {
2797 			mutex_enter(&saa_portp->saa_pt_mutex);
2798 			mutex_enter(&saa_portp->saa_pt_kstat_mutex);
2799 			(void) ibmf_saa_impl_init_kstats(saa_portp);
2800 			mutex_exit(&saa_portp->saa_pt_kstat_mutex);
2801 			saa_portp->saa_pt_state = IBMF_SAA_PORT_STATE_READY;
2802 			if (must_unsub == B_TRUE)
2803 				saa_portp->saa_pt_reference_count++;
2804 			mutex_exit(&saa_portp->saa_pt_mutex);
2805 
2806 			if (must_unsub == B_TRUE) {
2807 				ibmf_saa_subscribe_events(saa_portp, B_TRUE,
2808 				    B_FALSE);
2809 			}
2810 		}
2811 	}
2812 bail:
2813 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_saa_impl_hca_detach_end,
2814 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_hca_detach() exit\n");
2815 }
2816 
2817 /* ARGSUSED */
2818 void
2819 ibmf_saa_async_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
2820 {
2821 	saa_impl_trans_info_t	*trans_info;
2822 	int			status;
2823 	size_t			length;
2824 	void			*result;
2825 	saa_port_t		*saa_portp;
2826 	saa_client_data_t	*client_data;
2827 	int			ibmf_status;
2828 	boolean_t		ignore_data;
2829 	ibmf_retrans_t		ibmf_retrans;
2830 	boolean_t		sa_is_redirected = B_FALSE;
2831 
2832 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_async_cb_start,
2833 	    IBMF_TNF_TRACE, "", "ibmf_saa_async_cb() enter\n");
2834 
2835 	trans_info = (saa_impl_trans_info_t *)args;
2836 
2837 	client_data = trans_info->si_trans_client_data;
2838 	saa_portp   = trans_info->si_trans_port;
2839 
2840 	mutex_enter(&saa_portp->saa_pt_mutex);
2841 	sa_is_redirected = saa_portp->saa_pt_redirect_active;
2842 	mutex_exit(&saa_portp->saa_pt_mutex);
2843 
2844 	if ((msgp->im_msg_status == IBMF_TRANS_TIMEOUT) &&
2845 	    (sa_is_redirected == B_TRUE)) {
2846 
2847 		/*
2848 		 * We should retry the request using SM_LID and QP1 if we
2849 		 * have been using redirect up until now
2850 		 */
2851 		ibmf_status = ibmf_saa_impl_revert_to_qp1(
2852 		    saa_portp, msgp, ibmf_saa_async_cb, args,
2853 		    trans_info->si_trans_transport_flags);
2854 
2855 		/*
2856 		 * If revert_to_qp1 returns success msg was resent.
2857 		 * Otherwise msg could not be resent. Continue normally
2858 		 */
2859 		if (ibmf_status == IBMF_SUCCESS)
2860 			goto bail;
2861 
2862 	} else if (msgp->im_msg_status == IBMF_TRANS_TIMEOUT) {
2863 
2864 
2865 		ibmf_status = ibmf_saa_impl_new_smlid_retry(saa_portp, msgp,
2866 		    ibmf_saa_async_cb, args,
2867 		    trans_info->si_trans_transport_flags);
2868 
2869 		/*
2870 		 * if smlid_retry() returns success sm lid changed and msg
2871 		 * was resent.  Otherwise, lid did not change or msg could not
2872 		 * be resent.  Continue normally.
2873 		 */
2874 		if (ibmf_status == IBMF_SUCCESS)
2875 			goto bail;
2876 
2877 		/*
2878 		 * check whether we've received anything from the SA in a while.
2879 		 * If we have, this function will retry and return success.  If
2880 		 * we haven't continue normally so that we return a timeout to
2881 		 * the client
2882 		 */
2883 		ibmf_status = ibmf_saa_check_sa_and_retry(
2884 		    saa_portp, msgp, ibmf_saa_async_cb, args,
2885 		    trans_info->si_trans_send_time,
2886 		    trans_info->si_trans_transport_flags);
2887 
2888 		if (ibmf_status == IBMF_SUCCESS)
2889 			goto bail;
2890 	}
2891 
2892 	/*
2893 	 * If SA returned success but mad status is busy, retry a few times.
2894 	 * If SA returned success but mad status says redirect is required,
2895 	 * update the address info and retry the request to the new SA address
2896 	 */
2897 	if (msgp->im_msg_status == IBMF_SUCCESS) {
2898 
2899 		ASSERT(msgp->im_msgbufs_recv.im_bufs_mad_hdr != NULL);
2900 
2901 		if ((b2h16(msgp->im_msgbufs_recv.im_bufs_mad_hdr->Status) ==
2902 		    MAD_STATUS_BUSY) &&
2903 		    (trans_info->si_trans_retry_busy_count <
2904 		    IBMF_SAA_MAX_BUSY_RETRY_COUNT)) {
2905 
2906 			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
2907 			    ibmf_saa_async_cb, IBMF_TNF_TRACE, "",
2908 			    "ibmf_saa_async_cb: %s, retry_count = %d\n",
2909 			    tnf_string, msg,
2910 			    "async response returned busy status",
2911 			    tnf_int, retry_count,
2912 			    trans_info->si_trans_retry_busy_count);
2913 
2914 			trans_info->si_trans_retry_busy_count++;
2915 
2916 			bcopy(&saa_portp->saa_pt_ibmf_retrans, &ibmf_retrans,
2917 			    sizeof (ibmf_retrans_t));
2918 
2919 			ibmf_status = ibmf_msg_transport(
2920 			    saa_portp->saa_pt_ibmf_handle,
2921 			    saa_portp->saa_pt_qp_handle, msgp, &ibmf_retrans,
2922 			    ibmf_saa_async_cb, args,
2923 			    trans_info->si_trans_transport_flags);
2924 
2925 			/*
2926 			 * if retry is successful, quit here since async_cb will
2927 			 * get called again; otherwise, let this function call
2928 			 * handle the cleanup
2929 			 */
2930 			if (ibmf_status == IBMF_SUCCESS)
2931 				goto bail;
2932 		} else if (b2h16(msgp->im_msgbufs_recv.im_bufs_mad_hdr->Status)
2933 		    == MAD_STATUS_REDIRECT_REQUIRED) {
2934 
2935 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L2,
2936 			    ibmf_saa_async_cb, IBMF_TNF_TRACE, "",
2937 			    "ibmf_saa_async_cb: "
2938 			    "async response returned redirect status\n");
2939 
2940 			/* update address info and copy it into msgp */
2941 			ibmf_saa_impl_update_sa_address_info(saa_portp, msgp);
2942 
2943 			/* retry with new address info */
2944 			bcopy(&saa_portp->saa_pt_ibmf_retrans, &ibmf_retrans,
2945 			    sizeof (ibmf_retrans_t));
2946 
2947 			ibmf_status = ibmf_msg_transport(
2948 			    saa_portp->saa_pt_ibmf_handle,
2949 			    saa_portp->saa_pt_qp_handle, msgp, &ibmf_retrans,
2950 			    ibmf_saa_async_cb, args,
2951 			    trans_info->si_trans_transport_flags);
2952 
2953 			/*
2954 			 * if retry is successful, quit here since async_cb will
2955 			 * get called again; otherwise, let this function call
2956 			 * handle the cleanup
2957 			 */
2958 			if (ibmf_status == IBMF_SUCCESS)
2959 				goto bail;
2960 		}
2961 	}
2962 
2963 	mutex_enter(&saa_portp->saa_pt_mutex);
2964 
2965 	ASSERT(saa_portp->saa_pt_num_outstanding_trans > 0);
2966 	saa_portp->saa_pt_num_outstanding_trans--;
2967 
2968 	mutex_exit(&saa_portp->saa_pt_mutex);
2969 
2970 	if ((trans_info->si_trans_callback == NULL) &&
2971 	    (trans_info->si_trans_sub_callback == NULL))
2972 		ignore_data = B_TRUE;
2973 	else
2974 		ignore_data = B_FALSE;
2975 
2976 	ibmf_saa_impl_prepare_response(ibmf_handle, msgp, ignore_data, &status,
2977 	    &result, &length, B_FALSE);
2978 
2979 	mutex_enter(&saa_portp->saa_pt_kstat_mutex);
2980 
2981 	IBMF_SAA_SUB32_KSTATS(saa_portp, outstanding_requests, 1);
2982 
2983 	if (status != IBMF_SUCCESS)
2984 		IBMF_SAA_ADD32_KSTATS(saa_portp, failed_requests, 1);
2985 
2986 	if (status == IBMF_TRANS_TIMEOUT)
2987 		IBMF_SAA_ADD32_KSTATS(saa_portp, requests_timedout, 1);
2988 
2989 	mutex_exit(&saa_portp->saa_pt_kstat_mutex);
2990 
2991 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
2992 	    ibmf_saa_async_cb, IBMF_TNF_TRACE, "",
2993 	    "ibmf_saa_async_cb: %s\n", tnf_string, msg,
2994 	    "Calling ibmf_saa client's callback");
2995 
2996 	/*
2997 	 * there are three classes or trans_info users: ibmf_saa clients and
2998 	 * classportinfo requests; informinfo subscribe requests, and report
2999 	 * responses.  For the first two, call the correct callback.  For report
3000 	 * responses there's no need to notify anyone.
3001 	 */
3002 	if (trans_info->si_trans_callback != NULL) {
3003 		/* ibmf_saa client or classportinfo request */
3004 		trans_info->si_trans_callback(trans_info->si_trans_callback_arg,
3005 		    length, result, status);
3006 	} else if (trans_info->si_trans_sub_callback != NULL) {
3007 		/* informinfo subscribe request */
3008 		trans_info->si_trans_sub_callback(
3009 		    trans_info->si_trans_callback_arg, length, result, status,
3010 		    trans_info->si_trans_sub_producer_type);
3011 	}
3012 
3013 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
3014 	    ibmf_saa_async_cb, IBMF_TNF_TRACE, "",
3015 	    "ibmf_saa_async_cb: %s\n", tnf_string, msg,
3016 	    "Returned from callback");
3017 
3018 	if (client_data != NULL) {
3019 		mutex_enter(&client_data->saa_client_mutex);
3020 
3021 		ASSERT(client_data->saa_client_num_pending_trans > 0);
3022 		client_data->saa_client_num_pending_trans--;
3023 
3024 		if ((client_data->saa_client_num_pending_trans == 0) &&
3025 		    (client_data->saa_client_state == SAA_CLIENT_STATE_WAITING))
3026 			cv_signal(&client_data->saa_client_state_cv);
3027 
3028 		mutex_exit(&client_data->saa_client_mutex);
3029 	}
3030 
3031 	kmem_free(trans_info, sizeof (saa_impl_trans_info_t));
3032 
3033 bail:
3034 
3035 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_async_cb_end,
3036 	    IBMF_TNF_TRACE, "", "ibmf_saa_async_cb() exit\n");
3037 }
3038 
3039 /*
3040  * ibmf_saa_check_sa_and_retry:
3041  *
3042  * If a particular transaction times out, we don't want to give up if we know
3043  * the SA is responding.  Check the time since we last received a response. If
3044  * it's less than ibmf_saa_max_wait_time retry the request.
3045  *
3046  * msgp, ibmf_callback, ibmf_callback_arg, and transport flags should be the
3047  * same values passed to the original ibmf_msg_transport that timed out.  The
3048  * ibmf_retrans parameter will be re-retrieved from the saa_portp structure.
3049  *
3050  * If max_wait_time seconds have passed, this function returns IBMF_TIMEOUT.
3051  * That way, callers can simply return the result of this function.
3052  *
3053  * Input Arguments
3054  * saa_portp		pointer to saa_port structure
3055  * msgp			ibmf message that timedout
3056  * ibmf_callback	callback that should be called by msg_transport
3057  * ibmf_callback_arg	args for ibmf_callback
3058  * transport_flags	flags for ibmf_msg_transport
3059  *
3060  * Output Arguments
3061  * none
3062  *
3063  * Returns
3064  * IBMF_SUCCESS if we've recently received data from the SA and request was
3065  * resent.
3066  * IBMF_TRANS_TIMEOUT if no data has been received from the SA in max_wait_time
3067  * same values as ibmf_msg_transport() if data has been received but request
3068  * could not be resent.
3069  */
3070 static int
3071 ibmf_saa_check_sa_and_retry(saa_port_t *saa_portp, ibmf_msg_t *msgp,
3072     ibmf_msg_cb_t ibmf_callback, void *ibmf_callback_arg,
3073     hrtime_t trans_send_time, int transport_flags)
3074 {
3075 	hrtime_t		curr_time, sa_uptime;
3076 	ibmf_retrans_t		ibmf_retrans;
3077 	int			ibmf_status;
3078 
3079 	do {
3080 
3081 		mutex_enter(&saa_portp->saa_pt_mutex);
3082 
3083 		sa_uptime = saa_portp->saa_pt_sa_uptime;
3084 
3085 		/* if nothing received from SA since we sent */
3086 		curr_time = gethrtime();
3087 
3088 		/*
3089 		 * check if it's been a very long time since this
3090 		 * particular transaction was sent
3091 		 */
3092 		if (((curr_time - trans_send_time) / 1000000000) >
3093 		    ibmf_saa_trans_wait_time) {
3094 
3095 			mutex_exit(&saa_portp->saa_pt_mutex);
3096 
3097 			IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L1,
3098 			    ibmf_saa_check_sa_and_retry_err, IBMF_TNF_ERROR, "",
3099 			    "ibmf_saa_check_sa_and_retry: %s, msgp = "
3100 			    "%p sa_uptime = %" PRIu64 ", trans send time = %"
3101 			    PRIu64 ", curr_time = %" PRIu64 "\n",
3102 			    tnf_string, msg,
3103 			    "Nothing received for this transaction",
3104 			    tnf_opaque, msgp, msgp,
3105 			    tnf_long, sa_uptime, sa_uptime,
3106 			    tnf_long, trans_send_time, trans_send_time,
3107 			    tnf_long, curr_time, curr_time);
3108 
3109 			ibmf_status = IBMF_TRANS_TIMEOUT;
3110 
3111 			break;
3112 		}
3113 
3114 		/*
3115 		 * check time since we received something,
3116 		 * and make sure that it hasn't been an extra long
3117 		 * time for this particular transaction
3118 		 */
3119 		if (((curr_time - sa_uptime) / 1000000000) <
3120 		    ibmf_saa_max_wait_time) {
3121 
3122 			IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L2,
3123 			    ibmf_saa_check_sa_and_retry, IBMF_TNF_TRACE, "",
3124 			    "ibmf_saa_check_sa_and_retry: %s, msgp = "
3125 			    "%p sa_uptime = %" PRIu64 " trans_send_time = %"
3126 			    PRIu64 " curr_time = %" PRIu64 "\n",
3127 			    tnf_string, msg, "Something received.  Retrying",
3128 			    tnf_opaque, msgp, msgp,
3129 			    tnf_long, sa_uptime, sa_uptime,
3130 			    tnf_long, trans_send_time, trans_send_time,
3131 			    tnf_long, curr_time, curr_time);
3132 
3133 			/*
3134 			 * something received in WAIT_TIME_IN_SECS;
3135 			 * resend request
3136 			 */
3137 
3138 			/* new tid needed */
3139 			msgp->im_msgbufs_send.im_bufs_mad_hdr->TransactionID =
3140 			    h2b64(saa_portp->saa_pt_current_tid++);
3141 
3142 			/*
3143 			 * We are going to retry the access to the SM but
3144 			 * Master SMLID could have changed due to a port change
3145 			 * event. So update the remote_lid of the message with
3146 			 * the SMLID from saa_portp for this port before the
3147 			 * retry.
3148 			 */
3149 			msgp->im_local_addr.ia_remote_lid =
3150 			    saa_portp->saa_pt_ibmf_addr_info.ia_remote_lid;
3151 
3152 			bcopy(&saa_portp->saa_pt_ibmf_retrans,
3153 			    &ibmf_retrans, sizeof (ibmf_retrans_t));
3154 
3155 			mutex_exit(&saa_portp->saa_pt_mutex);
3156 
3157 			ibmf_status = ibmf_msg_transport(
3158 			    saa_portp->saa_pt_ibmf_handle,
3159 			    saa_portp->saa_pt_qp_handle, msgp,
3160 			    &ibmf_retrans, ibmf_callback, ibmf_callback_arg,
3161 			    transport_flags);
3162 
3163 			if (ibmf_status == IBMF_SUCCESS)
3164 				goto bail;
3165 
3166 			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
3167 			    ibmf_saa_check_sa_and_retry, IBMF_TNF_TRACE, "",
3168 			    "ibmf_saa_check_sa_and_retry: %s, ibmf_status = "
3169 			    "%d\n", tnf_string, msg,
3170 			    "ibmf_msg_transport() failed",
3171 			    tnf_int, ibmf_status, ibmf_status);
3172 		} else {
3173 
3174 			mutex_exit(&saa_portp->saa_pt_mutex);
3175 
3176 			IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L1,
3177 			    ibmf_saa_check_sa_and_retry_err, IBMF_TNF_ERROR, "",
3178 			    "ibmf_saa_check_sa_and_retry: %s, msgp = "
3179 			    "%p sa_uptime = %" PRIu64 " curr_time = %"
3180 			    PRIu64 "\n", tnf_string, msg,
3181 			    "Nothing received.  Timing out",
3182 			    tnf_opaque, msgp, msgp,
3183 			    tnf_long, sa_uptime, sa_uptime,
3184 			    tnf_long, curr_time, curr_time);
3185 
3186 			ibmf_status = IBMF_TRANS_TIMEOUT;
3187 
3188 			break;
3189 		}
3190 	} while (ibmf_status == IBMF_TRANS_TIMEOUT);
3191 
3192 bail:
3193 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
3194 	    ibmf_saa_check_sa_and_retry_end,
3195 	    IBMF_TNF_TRACE, "", "ibmf_saa_check_sa_and_retry() exiting"
3196 	    " ibmf_status = %d\n", tnf_int, result, ibmf_status);
3197 
3198 	return (ibmf_status);
3199 }
3200 
3201 
3202 /*
3203  * ibmf_saa_impl_prepare_response:
3204  */
3205 static void
3206 ibmf_saa_impl_prepare_response(ibmf_handle_t ibmf_handle,
3207     ibmf_msg_t *msgp, boolean_t ignore_data, int *status, void **result,
3208     size_t *length, boolean_t sleep_flag)
3209 {
3210 	ibmf_msg_bufs_t	*resp_buf;
3211 	uint16_t	attr_id;
3212 	uint8_t		method;
3213 	boolean_t	is_get_resp;
3214 	uint16_t	mad_status;
3215 	uint16_t	attr_offset;
3216 	ib_sa_hdr_t	*sa_hdr;
3217 
3218 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3219 	    ibmf_saa_impl_prepare_response_start,
3220 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_prepare_response() enter\n");
3221 
3222 	_NOTE(ASSUMING_PROTECTED(*msgp))
3223 
3224 	*result = NULL;
3225 	*length = 0;
3226 	sa_hdr = NULL;
3227 
3228 	resp_buf = &msgp->im_msgbufs_recv;
3229 
3230 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*resp_buf))
3231 
3232 	if (msgp->im_msg_status != IBMF_SUCCESS) {
3233 
3234 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
3235 		    ibmf_saa_impl_prepare_response, IBMF_TNF_TRACE, "",
3236 		    "ibmf_saa_impl_prepare_response: %s, msg_status = %d\n",
3237 		    tnf_string, msg, "Bad ibmf status",
3238 		    tnf_int, msg_status, msgp->im_msg_status);
3239 
3240 		*status = msgp->im_msg_status;
3241 
3242 		goto exit;
3243 	}
3244 
3245 	if (resp_buf->im_bufs_mad_hdr == NULL) {
3246 
3247 		/*
3248 		 * this was an unsequenced transaction (from an unsubscribe for
3249 		 * following a CI_OFFLINE event)
3250 		 */
3251 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
3252 		    ibmf_saa_impl_prepare_response, IBMF_TNF_TRACE, "",
3253 		    "ibmf_saa_impl_prepare_response: %s\n",
3254 		    tnf_string, msg, "Unsequenced transaction callback");
3255 
3256 		goto exit;
3257 	}
3258 
3259 	if ((mad_status = b2h16(resp_buf->im_bufs_mad_hdr->Status)) !=
3260 	    MAD_STATUS_NO_INVALID_FIELDS) {
3261 
3262 		/* convert mad packet status to IBMF status */
3263 		switch (mad_status) {
3264 
3265 			case SA_STATUS_ERR_NO_RESOURCES:
3266 				*status = IBMF_NO_RESOURCES;
3267 				break;
3268 			case SA_STATUS_ERR_REQ_INVALID:
3269 				*status = IBMF_REQ_INVALID;
3270 				break;
3271 			case SA_STATUS_ERR_NO_RECORDS:
3272 				*status = IBMF_NO_RECORDS;
3273 				break;
3274 			case SA_STATUS_ERR_TOO_MANY_RECORDS:
3275 				*status = IBMF_TOO_MANY_RECORDS;
3276 				break;
3277 			case SA_STATUS_ERR_REQ_INVALID_GID:
3278 				*status = IBMF_INVALID_GID;
3279 				break;
3280 			case SA_STATUS_ERR_REQ_INSUFFICIENT_COMPONENTS:
3281 				*status = IBMF_INSUFF_COMPS;
3282 				break;
3283 			case MAD_STATUS_UNSUPP_METHOD:
3284 				*status = IBMF_UNSUPP_METHOD;
3285 				break;
3286 			case MAD_STATUS_UNSUPP_METHOD_ATTR:
3287 				*status = IBMF_UNSUPP_METHOD_ATTR;
3288 				break;
3289 			case MAD_STATUS_INVALID_FIELD:
3290 				*status = IBMF_INVALID_FIELD;
3291 				break;
3292 			default:
3293 				*status = IBMF_REQ_INVALID;
3294 				break;
3295 		}
3296 
3297 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
3298 		    ibmf_saa_impl_prepare_response, IBMF_TNF_TRACE, "",
3299 		    "ibmf_saa_impl_prepare_response: %s, mad_status = %x\n",
3300 		    tnf_string, msg, "Bad MAD status",
3301 		    tnf_int, mad_status, mad_status);
3302 
3303 		goto exit;
3304 	}
3305 
3306 	attr_id = b2h16(resp_buf->im_bufs_mad_hdr->AttributeID);
3307 	method = resp_buf->im_bufs_mad_hdr->R_Method;
3308 
3309 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
3310 	    ibmf_saa_impl_prepare_response, IBMF_TNF_TRACE, "",
3311 	    "ibmf_saa_impl_prepare_response: attr_id = 0x%x, method = "
3312 	    "0x%x\n",
3313 	    tnf_opaque, attr_id, attr_id,
3314 	    tnf_opaque, method, method);
3315 
3316 	/*
3317 	 * ignore any data from deleteresp since there's no way to know whether
3318 	 * real data was returned; also ignore data if this was a Report
3319 	 * response
3320 	 */
3321 	if (method == SA_SUBN_ADM_DELETE_RESP) {
3322 
3323 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
3324 		    ibmf_saa_impl_prepare_response, IBMF_TNF_TRACE, "",
3325 		    "impf_saa_impl_prepare_response: %s\n",
3326 		    tnf_string, msg,
3327 		    "DeleteResp or NoticeResp returned.  "
3328 		    "Ignoring response data");
3329 
3330 		*status = IBMF_SUCCESS;
3331 
3332 		*length = 0;
3333 		*result = NULL;
3334 
3335 		goto exit;
3336 	}
3337 
3338 	if (attr_id == SA_MULTIPATHRECORD_ATTRID) {
3339 
3340 		/*
3341 		 * getmulti is only for requests; attribute should not
3342 		 * be returned from SA
3343 		 */
3344 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
3345 		    ibmf_saa_impl_prepare_response_err, IBMF_TNF_ERROR,
3346 		    "", "ibmf_saa_impl_prepare_response: %s\n",
3347 		    tnf_string, msg, "SA returned getmulti record");
3348 
3349 		*status = IBMF_REQ_INVALID;
3350 
3351 		goto exit;
3352 	}
3353 
3354 	/* if we are supposed to ignore data, stop here */
3355 	if (ignore_data == B_TRUE) {
3356 
3357 		*status = IBMF_SUCCESS;
3358 
3359 		goto exit;
3360 	}
3361 
3362 	is_get_resp = resp_buf->im_bufs_mad_hdr->R_Method ==
3363 	    SA_SUBN_ADM_GET_RESP ? B_TRUE: B_FALSE;
3364 
3365 	/* unpack the sa header to get the attribute offset */
3366 	*status = ibmf_saa_utils_unpack_sa_hdr(resp_buf->im_bufs_cl_hdr,
3367 	    resp_buf->im_bufs_cl_hdr_len, &sa_hdr, sleep_flag);
3368 	if (*status != IBMF_SUCCESS) {
3369 
3370 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L1,
3371 		    ibmf_saa_impl_prepare_response_err,
3372 		    IBMF_TNF_TRACE, "", "ibmf_saa_impl_prepare_response: %s,"
3373 		    " ibmf_status = %d\n", tnf_string, msg,
3374 		    "Could not unpack sa hdr", tnf_int, ibmf_status, *status);
3375 
3376 		goto exit;
3377 	}
3378 
3379 	attr_offset = sa_hdr->AttributeOffset;
3380 
3381 	/*
3382 	 * unpack data payload; if unpack function doesn't return success
3383 	 * (because it could not allocate memory) forward this status to waiting
3384 	 * client
3385 	 */
3386 	*status = ibmf_saa_utils_unpack_payload(resp_buf->im_bufs_cl_data,
3387 	    resp_buf->im_bufs_cl_data_len, attr_id, result, length,
3388 	    attr_offset, is_get_resp, sleep_flag);
3389 	if (*status == IBMF_SUCCESS) {
3390 
3391 		IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L3,
3392 		    ibmf_saa_impl_prepare_response,
3393 		    IBMF_TNF_TRACE, "",
3394 		    "ibmf_saa_impl_prepare_response: attr_id = "
3395 		    "0x%x, attr_offset = %d, packed_payload_len = %d, "
3396 		    "unpacked_payload_len = %d\n",
3397 		    tnf_opaque, attr_id, attr_id,
3398 		    tnf_opaque, attr_offset, attr_offset,
3399 		    tnf_opaque, packed_payload_len,
3400 		    resp_buf->im_bufs_cl_data_len,
3401 		    tnf_opaque, unpacked_payload_len, *length);
3402 	} else {
3403 
3404 		IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L1,
3405 		    ibmf_saa_impl_prepare_response_err,
3406 		    IBMF_TNF_TRACE, "", "ibmf_saa_impl_prepare_response: %s,"
3407 		    "attr_id = 0x%x, attr_offset = %d, packed_payload_len = %d,"
3408 		    "status = %d\n",
3409 		    tnf_string, msg, "Could not unpack payload",
3410 		    tnf_opaque, attr_id, attr_id,
3411 		    tnf_int, attr_offset, attr_offset,
3412 		    tnf_int, packed_payload_len,
3413 		    resp_buf->im_bufs_cl_data_len,
3414 		    tnf_int, status, *status);
3415 	}
3416 exit:
3417 	if (sa_hdr != NULL)
3418 		kmem_free(sa_hdr, sizeof (ib_sa_hdr_t));
3419 
3420 	ibmf_saa_impl_free_msg(ibmf_handle, msgp);
3421 
3422 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
3423 	    ibmf_saa_impl_prepare_response_end,
3424 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_prepare_response() exit,"
3425 	    " status = 0x%d\n", tnf_int, status, *status);
3426 }
3427 
3428 
3429 /*
3430  * ibmf_saa_impl_check_sa_support:
3431  * Checks the capability mask (returned from the SA classportinfo response) to
3432  * determine whether the sa supports the specified attribute ID.
3433  *
3434  * Input Arguments
3435  * cap_mask	16-bit capability mask returned in SA's classportinfo
3436  * attr_id	attribute ID of current request
3437  *
3438  * Returns
3439  * IBMF_NOT_SUPPORTED if capability mask indicates SA does not support attribute
3440  * IBMF_SUCCESS otherwise
3441  */
3442 static int
3443 ibmf_saa_impl_check_sa_support(uint16_t cap_mask, uint16_t attr_id)
3444 {
3445 	boolean_t	attr_supported = B_TRUE;
3446 
3447 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
3448 	    ibmf_saa_impl_check_sa_support, IBMF_TNF_TRACE, "",
3449 	    "ibmf_saa_impl_check_sa_support: cap_mask = 0x%x, "
3450 	    "attr_id = 0x%x\n", tnf_opaque, cap_mask, cap_mask,
3451 	    tnf_opaque, attr_id, attr_id);
3452 
3453 	switch (attr_id) {
3454 
3455 		case SA_SWITCHINFORECORD_ATTRID:
3456 		case SA_LINEARFDBRECORD_ATTRID:
3457 		case SA_RANDOMFDBRECORD_ATTRID:
3458 		case SA_MULTICASTFDBRECORD_ATTRID:
3459 		case SA_SMINFORECORD_ATTRID:
3460 		case SA_INFORMINFORECORD_ATTRID:
3461 		case SA_LINKRECORD_ATTRID:
3462 		case SA_GUIDINFORECORD_ATTRID:
3463 		case SA_TRACERECORD_ATTRID:
3464 		case SA_SERVICEASSNRECORD_ATTRID:
3465 
3466 			if ((cap_mask &
3467 			    SA_CAPMASK_OPT_RECORDS_SUPPORTED) == 0) {
3468 
3469 				IBMF_TRACE_3(IBMF_TNF_NODEBUG, DPRINT_L1,
3470 				    ibmf_saa_impl_check_sa_support,
3471 				    IBMF_TNF_ERROR, "",
3472 				    "ibmf_saa_impl_check_sa_support: %s, "
3473 				    "cap_mask = 0x%x\n", tnf_string, msg,
3474 				    "SA does not support optional records",
3475 				    tnf_opaque, cap_mask, cap_mask,
3476 				    tnf_opaque, attr_id, attr_id);
3477 
3478 				attr_supported = B_FALSE;
3479 			}
3480 			break;
3481 
3482 		case SA_MULTIPATHRECORD_ATTRID:
3483 
3484 			if ((cap_mask & SA_CAPMASK_MULTIPATH_SUPPORTED) == 0) {
3485 
3486 				IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
3487 				    ibmf_saa_impl_check_sa_support,
3488 				    IBMF_TNF_ERROR, "",
3489 				    "ibmf_saa_impl_check_sa_support: %s, "
3490 				    "cap_mask = 0x%x\n", tnf_string, msg,
3491 				    "SA does not support multipath records",
3492 				    tnf_opaque, cap_mask, cap_mask);
3493 
3494 				attr_supported = B_FALSE;
3495 			}
3496 			break;
3497 
3498 		case SA_MCMEMBERRECORD_ATTRID:
3499 
3500 			if ((cap_mask & SA_CAPMASK_UD_MCAST_SUPPORTED) == 0) {
3501 
3502 				IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
3503 				    ibmf_saa_impl_check_sa_support,
3504 				    IBMF_TNF_ERROR, "",
3505 				    "ibmf_saa_impl_check_sa_support: %s, "
3506 				    "cap_mask = 0x%x\n", tnf_string, msg,
3507 				    "SA does not support ud multicast",
3508 				    tnf_opaque, cap_mask, cap_mask);
3509 
3510 				attr_supported = B_FALSE;
3511 			}
3512 			break;
3513 
3514 		default:
3515 			break;
3516 	} /* switch */
3517 
3518 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
3519 	    ibmf_saa_impl_check_sa_support_end, IBMF_TNF_TRACE, "",
3520 	    "ibmf_saa_impl_check_sa_support() exiting, attr_supported = %d\n",
3521 	    tnf_opaque, attr_supported, attr_supported);
3522 
3523 	if (attr_supported == B_FALSE)
3524 		return (IBMF_UNSUPP_METHOD_ATTR);
3525 	else
3526 		return (IBMF_SUCCESS);
3527 }
3528 
3529 /*
3530  * ibmf_saa_impl_get_attr_id_length:
3531  *
3532  * Returns the host size of the specified sa record.  Returns 0 for unknown
3533  * attributes.  multipath record size is a dynamic value given as a parameter
3534  * specified with the ibmf_sa_access() call.
3535  */
3536 static uint_t
3537 ibmf_saa_impl_get_attr_id_length(uint16_t attr_id)
3538 {
3539 	uint_t	attr_length;
3540 
3541 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3542 	    ibmf_saa_impl_get_attr_id_length_start,
3543 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_get_attr_id_length() enter\n");
3544 
3545 	/* this function should not be used for multipath record */
3546 	ASSERT(attr_id != SA_MULTIPATHRECORD_ATTRID);
3547 
3548 	switch (attr_id) {
3549 		case SA_CLASSPORTINFO_ATTRID:
3550 			attr_length = sizeof (ib_mad_classportinfo_t);
3551 			break;
3552 		case SA_NOTICE_ATTRID:
3553 			attr_length = sizeof (ib_mad_notice_t);
3554 			break;
3555 		case SA_INFORMINFO_ATTRID:
3556 			attr_length = sizeof (ib_mad_informinfo_t);
3557 			break;
3558 		case SA_NODERECORD_ATTRID:
3559 			attr_length = sizeof (sa_node_record_t);
3560 			break;
3561 		case SA_PORTINFORECORD_ATTRID:
3562 			attr_length = sizeof (sa_portinfo_record_t);
3563 			break;
3564 		case SA_SLTOVLRECORD_ATTRID:
3565 			attr_length = sizeof (sa_SLtoVLmapping_record_t);
3566 			break;
3567 		case SA_SWITCHINFORECORD_ATTRID:
3568 			attr_length = sizeof (sa_switchinfo_record_t);
3569 			break;
3570 		case SA_LINEARFDBRECORD_ATTRID:
3571 			attr_length = sizeof (sa_linearft_record_t);
3572 			break;
3573 		case SA_RANDOMFDBRECORD_ATTRID:
3574 			attr_length = sizeof (sa_randomft_record_t);
3575 			break;
3576 		case SA_MULTICASTFDBRECORD_ATTRID:
3577 			attr_length = sizeof (sa_multicastft_record_t);
3578 			break;
3579 		case SA_SMINFORECORD_ATTRID:
3580 			attr_length = sizeof (sa_sminfo_record_t);
3581 			break;
3582 		case SA_INFORMINFORECORD_ATTRID:
3583 			attr_length = sizeof (sa_informinfo_record_t);
3584 			break;
3585 		case SA_LINKRECORD_ATTRID:
3586 			attr_length = sizeof (sa_link_record_t);
3587 			break;
3588 		case SA_GUIDINFORECORD_ATTRID:
3589 			attr_length = sizeof (sa_guidinfo_record_t);
3590 			break;
3591 		case SA_SERVICERECORD_ATTRID:
3592 			attr_length = sizeof (sa_service_record_t);
3593 			break;
3594 		case SA_PARTITIONRECORD_ATTRID:
3595 			attr_length = sizeof (sa_pkey_table_record_t);
3596 			break;
3597 		case SA_PATHRECORD_ATTRID:
3598 			attr_length = sizeof (sa_path_record_t);
3599 			break;
3600 		case SA_VLARBRECORD_ATTRID:
3601 			attr_length = sizeof (sa_VLarb_table_record_t);
3602 			break;
3603 		case SA_MCMEMBERRECORD_ATTRID:
3604 			attr_length = sizeof (sa_mcmember_record_t);
3605 			break;
3606 		case SA_TRACERECORD_ATTRID:
3607 			attr_length = sizeof (sa_trace_record_t);
3608 			break;
3609 		case SA_SERVICEASSNRECORD_ATTRID:
3610 			attr_length = sizeof (sa_service_assn_record_t);
3611 			break;
3612 		default:
3613 			/* should only get the above type of packets */
3614 			attr_length = 0;
3615 			break;
3616 	}
3617 
3618 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
3619 	    ibmf_saa_impl_get_attr_id_length_end,
3620 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_get_attr_id_length():"
3621 	    " attr_id: 0x%x size %d\n",
3622 	    tnf_opaque, attr_id, attr_id, tnf_uint, attr_length, attr_length);
3623 
3624 	return (attr_length);
3625 }
3626 
3627 /*
3628  * ibmf_saa_impl_free_msg:
3629  * Takes a completed message and free memory associated with the message,
3630  * including the individual fields of the im_msgbufs_send.
3631  * ibmf_free_msg, called at the end of this function, takes a pointer to the
3632  * message pointer so that it can set the message pointer to NULL.  This
3633  * function takes just the message pointer so the msgp will not be NULL after
3634  * this function returns.
3635  *
3636  * Input Arguments
3637  * ibmf_hdl	ibmf handle used in ibmf_msg_alloc
3638  * msgp		pointer to ibmf_msg_t to free
3639  *
3640  * Returns
3641  * void
3642  */
3643 static void
3644 ibmf_saa_impl_free_msg(ibmf_handle_t ibmf_hdl, ibmf_msg_t *msgp)
3645 {
3646 	int	res;
3647 
3648 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
3649 	    ibmf_saa_impl_free_msg_start,
3650 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_free_msg() enter: msg %p\n",
3651 	    tnf_opaque, msg, msgp);
3652 
3653 	ASSERT(msgp != NULL);
3654 
3655 	kmem_free(msgp->im_msgbufs_send.im_bufs_mad_hdr,
3656 	    sizeof (ib_mad_hdr_t));
3657 
3658 	kmem_free(msgp->im_msgbufs_send.im_bufs_cl_hdr,
3659 	    msgp->im_msgbufs_send.im_bufs_cl_hdr_len);
3660 
3661 	if (msgp->im_msgbufs_send.im_bufs_cl_data_len > 0)
3662 		kmem_free(msgp->im_msgbufs_send.im_bufs_cl_data,
3663 		    msgp->im_msgbufs_send.im_bufs_cl_data_len);
3664 
3665 	res = ibmf_free_msg(ibmf_hdl, &msgp);
3666 	ASSERT(res == IBMF_SUCCESS);
3667 
3668 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3669 	    ibmf_saa_impl_free_msg_end,
3670 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_free_msg() exit\n");
3671 }
3672 
3673 /*
3674  * ibmf_saa_impl_get_port_guid:
3675  */
3676 static int
3677 ibmf_saa_impl_get_port_guid(ibt_hca_portinfo_t *ibt_portinfop,
3678     ib_guid_t *guid_ret)
3679 {
3680 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3681 	    ibmf_saa_impl_get_port_guid_start,
3682 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_get_port_guid() enter\n");
3683 
3684 	if (ibt_portinfop->p_linkstate != IBT_PORT_ACTIVE) {
3685 
3686 		return (IBMF_BAD_PORT_STATE);
3687 	}
3688 
3689 	if (ibt_portinfop->p_sgid_tbl_sz == 0) {
3690 
3691 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L2,
3692 		    ibmf_saa_impl_get_port_guid_end, IBMF_TNF_TRACE, "",
3693 		    "ibmf_saa_impl_get_port_guid: %s\n", tnf_string, msg,
3694 		    "portinfo sgid table size is 0. Exiting.\n");
3695 
3696 		return (IBMF_TRANSPORT_FAILURE);
3697 	}
3698 
3699 	*guid_ret = ibt_portinfop->p_sgid_tbl[0].gid_guid;
3700 
3701 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
3702 	    ibmf_saa_impl_get_port_guid_end, IBMF_TNF_TRACE, "",
3703 	    "ibmf_saa_impl_get_port_guid: Returning port_guid %016" PRIx64 "\n",
3704 	    tnf_opaque, port_guid, *guid_ret);
3705 
3706 	return (IBMF_SUCCESS);
3707 }
3708 
3709 /*
3710  * ibmf_saa_impl_set_transaction_params:
3711  */
3712 static void
3713 ibmf_saa_impl_set_transaction_params(saa_port_t *saa_portp,
3714     ibt_hca_portinfo_t *portinfop)
3715 {
3716 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3717 	    ibmf_saa_impl_set_transaction_params_start,
3718 	    IBMF_TNF_TRACE, "",
3719 	    "ibmf_saa_impl_set_transaction_params() enter\n");
3720 
3721 	_NOTE(ASSUMING_PROTECTED(*saa_portp))
3722 
3723 	saa_portp->saa_pt_ibmf_retrans.retrans_retries =
3724 	    ibmf_saa_retrans_retries;
3725 	/*
3726 	 * For the first transaction (generally getting the
3727 	 * classportinfo) have ibmf pick our timeouts.  It should be using the
3728 	 * default IB spec values.
3729 	 * Once we get the classportinfo we'll update the correct response time
3730 	 * value (rtv) and round-trip time (rttv).  ibmf should always calculate
3731 	 * trans_to since it depends on the particular transaction's number of
3732 	 * packets.
3733 	 */
3734 	saa_portp->saa_pt_ibmf_retrans.retrans_rtv = 0;
3735 	saa_portp->saa_pt_ibmf_retrans.retrans_rttv = 0;
3736 	saa_portp->saa_pt_ibmf_retrans.retrans_trans_to = 0;
3737 
3738 	/*
3739 	 * Assume that the SA supports all optional records. If it
3740 	 * does not, the request will get returned with ERR_NOT_SUPP.  When
3741 	 * the classportinfo response comes back we will update the cap mask
3742 	 * to prevent unnecessary unsupported requests.
3743 	 */
3744 	saa_portp->saa_pt_sa_cap_mask = 0xFFFF;
3745 
3746 	saa_portp->saa_pt_ibmf_msg_flags = 0;
3747 	saa_portp->saa_pt_ibmf_addr_info.ia_remote_qno 	= 1;
3748 	saa_portp->saa_pt_ibmf_addr_info.ia_p_key 	=
3749 	    IB_PKEY_DEFAULT_LIMITED;
3750 	saa_portp->saa_pt_ibmf_addr_info.ia_q_key 	= IB_GSI_QKEY;
3751 
3752 	/*
3753 	 * fill out addr information for MADs that will be sent
3754 	 * to SA on this port
3755 	 */
3756 	saa_portp->saa_pt_ibmf_addr_info.ia_local_lid 	= portinfop->p_base_lid;
3757 	saa_portp->saa_pt_ibmf_addr_info.ia_remote_lid 	= portinfop->p_sm_lid;
3758 	saa_portp->saa_pt_ibmf_addr_info.ia_service_level = portinfop->p_sm_sl;
3759 
3760 	/* place upper bound on subnet timeout in case of faulty SM */
3761 	saa_portp->saa_pt_timeout = portinfop->p_subnet_timeout;
3762 
3763 	if (saa_portp->saa_pt_timeout > ibmf_saa_max_subnet_timeout)
3764 		saa_portp->saa_pt_timeout = ibmf_saa_max_subnet_timeout;
3765 
3766 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L3,
3767 	    ibmf_saa_impl_set_transaction_params,
3768 	    IBMF_TNF_TRACE, "",
3769 	    "ibmf_saa_impl_set_transaction_params: local_lid = 0x%x, "
3770 	    "sm_lid = 0x%x, sm_sl = 0x%x, sn_timeout = 0x%x\n",
3771 	    tnf_opaque, local_lid, portinfop->p_base_lid,
3772 	    tnf_opaque, sm_lid, portinfop->p_sm_lid,
3773 	    tnf_opaque, sm_sl, portinfop->p_sm_sl,
3774 	    tnf_opaque, subnet_timeout, portinfop->p_subnet_timeout);
3775 
3776 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3777 	    ibmf_saa_impl_set_transaction_params_end,
3778 	    IBMF_TNF_TRACE, "",
3779 	    "ibmf_saa_impl_set_transaction_params() exit\n");
3780 }
3781 
3782 
3783 /*
3784  * ibmf_saa_impl_update_sa_address_info
3785  */
3786 static void
3787 ibmf_saa_impl_update_sa_address_info(saa_port_t *saa_portp, ibmf_msg_t *msgp)
3788 {
3789 	void			*result;
3790 	ib_sa_hdr_t		*sa_hdr;
3791 	int			rv;
3792 	size_t			length;
3793 	uint16_t		attr_id;
3794 	ib_mad_classportinfo_t	*cpi;
3795 	ibmf_global_addr_info_t	*gaddrp = &saa_portp->saa_pt_ibmf_global_addr;
3796 	ibt_hca_portinfo_t	*ibt_pinfo;
3797 	uint_t			nports, size;
3798 	ibt_status_t		ibt_status;
3799 
3800 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3801 	    ibmf_saa_impl_update_sa_address_info,
3802 	    IBMF_TNF_TRACE, "",
3803 	    "ibmf_saa_impl_update_sa_address_info() enter\n");
3804 
3805 	/*
3806 	 * decode the respons of msgp as a classportinfo attribute
3807 	 */
3808 	rv = ibmf_saa_utils_unpack_sa_hdr(msgp->im_msgbufs_recv.im_bufs_cl_hdr,
3809 	    msgp->im_msgbufs_recv.im_bufs_cl_hdr_len, &sa_hdr, KM_NOSLEEP);
3810 	if (rv != IBMF_SUCCESS) {
3811 
3812 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L1,
3813 		    ibmf_saa_impl_update_sa_address_err,
3814 		    IBMF_TNF_TRACE, "", "ibmf_saa_impl_update_sa_address_info: "
3815 		    "%s, ibmf_status = %d\n", tnf_string, msg,
3816 		    "Could not unpack sa hdr", tnf_int, ibmf_status, rv);
3817 
3818 		return;
3819 	}
3820 
3821 	attr_id = b2h16(msgp->im_msgbufs_recv.im_bufs_mad_hdr->AttributeID);
3822 	if (attr_id != MAD_ATTR_ID_CLASSPORTINFO) {
3823 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L1,
3824 		    ibmf_saa_impl_update_sa_address_info_err,
3825 		    IBMF_TNF_TRACE, "", "ibmf_saa_impl_update_sa_address_info: "
3826 		    "%s, attrID = %x\n", tnf_string, msg,
3827 		    "Wrong attribute ID", tnf_int, ibmf_status, attr_id);
3828 
3829 		kmem_free(sa_hdr, sizeof (ib_sa_hdr_t));
3830 		return;
3831 	}
3832 	rv = ibmf_saa_utils_unpack_payload(
3833 	    msgp->im_msgbufs_recv.im_bufs_cl_data,
3834 	    msgp->im_msgbufs_recv.im_bufs_cl_data_len, attr_id, &result,
3835 	    &length, sa_hdr->AttributeOffset, B_TRUE, KM_NOSLEEP);
3836 	if (rv != IBMF_SUCCESS) {
3837 
3838 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L1,
3839 		    ibmf_saa_impl_update_sa_address_err,
3840 		    IBMF_TNF_TRACE, "", "ibmf_saa_impl_update_sa_address_info: "
3841 		    "%s, ibmf_status = %d\n", tnf_string, msg,
3842 		    "Could not unpack payload", tnf_int, ibmf_status, rv);
3843 
3844 		kmem_free(sa_hdr, sizeof (ib_sa_hdr_t));
3845 		return;
3846 	}
3847 
3848 	kmem_free(sa_hdr, sizeof (ib_sa_hdr_t));
3849 
3850 	/*
3851 	 * Use the classportinfo contents to update the SA address info
3852 	 */
3853 	cpi = (ib_mad_classportinfo_t *)result;
3854 	mutex_enter(&saa_portp->saa_pt_mutex);
3855 	saa_portp->saa_pt_ibmf_addr_info.ia_remote_lid	= cpi->RedirectLID;
3856 	saa_portp->saa_pt_ibmf_addr_info.ia_remote_qno 	= cpi->RedirectQP;
3857 	saa_portp->saa_pt_ibmf_addr_info.ia_p_key 	= cpi->RedirectP_Key;
3858 	saa_portp->saa_pt_ibmf_addr_info.ia_q_key 	= cpi->RedirectQ_Key;
3859 	saa_portp->saa_pt_ibmf_addr_info.ia_service_level = cpi->RedirectSL;
3860 
3861 	saa_portp->saa_pt_redirect_active = B_TRUE;
3862 
3863 	if ((cpi->RedirectGID_hi != 0) || (cpi->RedirectGID_lo != 0)) {
3864 
3865 		mutex_exit(&saa_portp->saa_pt_mutex);
3866 		ibt_status = ibt_query_hca_ports_byguid(
3867 		    saa_portp->saa_pt_node_guid, saa_portp->saa_pt_port_num,
3868 		    &ibt_pinfo, &nports, &size);
3869 		if (ibt_status != IBT_SUCCESS) {
3870 
3871 			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L1,
3872 			    ibmf_saa_impl_update_sa_address_err, IBMF_TNF_TRACE,
3873 			    "", "ibmf_saa_impl_update_sa_address_info: "
3874 			    "%s, ibt_status = %d\n", tnf_string, msg,
3875 			    "Could not query hca port",
3876 			    tnf_int, ibt_status, ibt_status);
3877 
3878 			kmem_free(result, length);
3879 			return;
3880 		}
3881 
3882 		mutex_enter(&saa_portp->saa_pt_mutex);
3883 		/*
3884 		 * Fill in global address info parameters
3885 		 *
3886 		 * NOTE: The HopLimit value is not specified through the
3887 		 * contents of ClassPortInfo. It may be possible to find
3888 		 * out the proper value to use even for SA beeing redirected
3889 		 * to another subnet. But we do only support redirect within
3890 		 * our local subnet
3891 		 */
3892 		gaddrp->ig_sender_gid.gid_prefix =
3893 		    ibt_pinfo->p_sgid_tbl[0].gid_prefix;
3894 		gaddrp->ig_sender_gid.gid_guid = saa_portp->saa_pt_port_guid;
3895 		gaddrp->ig_recver_gid.gid_prefix = cpi->RedirectGID_hi;
3896 		gaddrp->ig_recver_gid.gid_guid = cpi->RedirectGID_lo;
3897 		gaddrp->ig_flow_label = cpi->RedirectFL;
3898 		gaddrp->ig_tclass = cpi->RedirectTC;
3899 		gaddrp->ig_hop_limit = 0;
3900 
3901 		saa_portp->saa_pt_ibmf_msg_flags =
3902 		    IBMF_MSG_FLAGS_GLOBAL_ADDRESS;
3903 
3904 		mutex_exit(&saa_portp->saa_pt_mutex);
3905 		ibt_free_portinfo(ibt_pinfo, size);
3906 	} else {
3907 		saa_portp->saa_pt_ibmf_msg_flags = 0;
3908 		mutex_exit(&saa_portp->saa_pt_mutex);
3909 	}
3910 	kmem_free(result, length);
3911 
3912 	/*
3913 	 * Update the address info of msgp with the new address parameters
3914 	 */
3915 	mutex_enter(&saa_portp->saa_pt_mutex);
3916 	bcopy(&saa_portp->saa_pt_ibmf_addr_info, &msgp->im_local_addr,
3917 	    sizeof (ibmf_addr_info_t));
3918 	if (saa_portp->saa_pt_ibmf_msg_flags & IBMF_MSG_FLAGS_GLOBAL_ADDRESS) {
3919 
3920 		msgp->im_msg_flags = IBMF_MSG_FLAGS_GLOBAL_ADDRESS;
3921 
3922 		bcopy(&saa_portp->saa_pt_ibmf_global_addr,
3923 		    &msgp->im_global_addr, sizeof (ibmf_global_addr_info_t));
3924 	} else {
3925 		msgp->im_msg_flags = 0;
3926 	}
3927 	mutex_exit(&saa_portp->saa_pt_mutex);
3928 }
3929 
3930 /*
3931  * ibmf_saa_impl_ibmf_unreg:
3932  */
3933 static int
3934 ibmf_saa_impl_ibmf_unreg(saa_port_t *saa_portp)
3935 {
3936 	int	ibmf_status;
3937 
3938 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_ibmf_unreg_start,
3939 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_ibmf_unreg() enter\n");
3940 
3941 	/* teardown async cb */
3942 	ibmf_status = ibmf_tear_down_async_cb(saa_portp->saa_pt_ibmf_handle,
3943 	    saa_portp->saa_pt_qp_handle, 0);
3944 	if (ibmf_status != IBMF_SUCCESS) {
3945 
3946 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L1,
3947 		    ibmf_saa_impl_ibmf_unreg, IBMF_TNF_TRACE, "",
3948 		    "ibmf_saa_impl_ibmf_unreg: %s, ibmf_status = %d\n",
3949 		    tnf_string, msg, "Could not tear down async cb",
3950 		    tnf_int, ibmf_status, ibmf_status);
3951 
3952 		goto bail;
3953 	}
3954 
3955 	/* free qp */
3956 	ibmf_status = ibmf_free_qp(saa_portp->saa_pt_ibmf_handle,
3957 	    &saa_portp->saa_pt_qp_handle, 0);
3958 
3959 	if (ibmf_status != IBMF_SUCCESS) {
3960 
3961 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L1,
3962 		    ibmf_saa_impl_ibmf_unreg, IBMF_TNF_TRACE, "",
3963 		    "ibmf_saa_impl_ibmf_unreg: %s, ibmf_status = %d\n",
3964 		    tnf_string, msg, "Could not free queue pair",
3965 		    tnf_int, ibmf_status, ibmf_status);
3966 
3967 		(void) ibmf_saa_impl_setup_qp_async_cb(saa_portp, 1);
3968 		goto bail;
3969 	}
3970 
3971 	ibmf_status = ibmf_unregister(&saa_portp->saa_pt_ibmf_handle, 0);
3972 
3973 	if (ibmf_status != IBMF_SUCCESS) {
3974 
3975 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L1,
3976 		    ibmf_saa_impl_ibmf_unreg, IBMF_TNF_TRACE, "",
3977 		    "ibmf_saa_impl_ibmf_unreg: %s, ibmf_status = %d\n",
3978 		    tnf_string, msg, "ibmf_unregister() failed",
3979 		    tnf_int, ibmf_status, ibmf_status);
3980 
3981 		(void) ibmf_saa_impl_setup_qp_async_cb(saa_portp, 0);
3982 	}
3983 
3984 bail:
3985 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_saa_impl_ibmf_unreg_end,
3986 	    IBMF_TNF_TRACE, "", "ibmf_saa_impl_ibmf_unreg() exit\n");
3987 
3988 	return (ibmf_status);
3989 }
3990