1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * ibmf_saa.c
31  *
32  */
33 
34 #include <sys/ib/mgt/ibmf/ibmf_saa_impl.h>
35 
36 /*
37  * As a primitive error checking scheme, the first 4 bytes of the client state
38  * have a well-known pattern.  We write this pattern during session_open, make
39  * sure all subsequent calls still have this pattern in the client state, and
40  * clear the pattern on session_close.  Clients could still run into trouble
41  * providing a bad handle since we don't check a known list of handles.  But
42  * this mechanism will protect against making ibmf_saa calls after the session
43  * has been closed.
44  */
45 #define	IBMF_SAA_SET_CLIENT_SIGNATURE(clientp) {		\
46 		(clientp)->saa_client_sig = (void *)0xACEDFACE;	\
47 }
48 
49 #define	IBMF_SAA_VERIFY_CLIENT_SIGNATURE(clientp) 		\
50 	(((clientp) != NULL && (clientp)->saa_client_sig ==	\
51 	    (void *)0xACEDFACE) ? B_TRUE: B_FALSE)
52 
53 #define	IBMF_SAA_CLEAR_CLIENT_SIGNATURE(clientp) {		\
54 		(clientp)->saa_client_sig = 0;			\
55 }
56 
57 /* Global Sa_access State Pointer */
58 extern saa_state_t *saa_statep;
59 extern int ibmf_trace_level;
60 
61 /*
62  * Locking scheme:
63  * ibmf_saa maintains a linked list of port entries.  Each element of the list
64  * contains information about a certain port.  There may be multiple clients
65  * associated with each of these entries.  The list is synchronized with a state
66  * port_list_mutex.  Each of the entries has their own individual mutex.  When
67  * adding a new port entry to the mutex the client, with the list mutex,  marks
68  * the port as registering, adds the port, and releases the list mutex.
69  * Subsequent clients aquire the list mutex, find the port, acquire the port
70  * mutex, release the list mutex, and wait if the port is marked as registering.
71  * Clients should never try to acquire the list mutex when they have a port
72  * mutex.
73  */
74 
75 /*
76  * ibmf_sa_session_open():
77  *
78  * Before using the ibmf_saa interface, consumers should register with the
79  * ibmf_saa interface by calling ibmf_sa_session_open(). Upon a successful
80  * registration, a handle is returned for use in subsequent interaction with the
81  * ibmf_saa interface; this handle is also provided as an argument to subnet
82  * event notification function.
83  *
84  * Consumers can register to be notified of subnet events such as GID
85  * being available/unavailable.  Clients which provide a non-NULL event args
86  * structure will have the is_event_callback function called when an event is
87  * received or there is a failure in subscribing for events.  This callback may
88  * be generated before the ibmf_sa_session_open() call returns.
89  *
90  * This interface blocks allocating memory, but not waiting for any packet
91  * responses.
92  *
93  * Arguments:
94  * port_guid            - GUID of the port.
95  * event_args		- subnet event registration details
96  * sm_key               - only filled in if the consumer is an SM
97  * ibmf_version         - version of the interface (IBMF_VERSION)
98  * flags                - unused
99  *
100  * Output Arguments:
101  * ibmf_sa_handle	- pointer to ibmf_saa_handle to be used in future calls
102  *
103  * Return values:
104  * IBMF_SUCCESS         - registration succeeded
105  * IBMF_BAD_PORT	- registration failed; active port not found
106  * IBMF_BAD_PORT_STATE  - registration failed; port found but not active or
107  * 			previous registration failed
108  * IBMF_NO_MEMORY	- registration failed; could not allocate memory
109  * IBMF_NO_RESOURCES    - registration failed due to a resource issue
110  * IBMF_BUSY            - registration failed; too many clients registered
111  *                      for this port
112  * IBMF_TRANSPORT_FAILURE - failure with underlying transport framework
113  * IBMF_INVALID_ARG     - ibmf_saa_handle arg was NULL
114  *
115  * The ibmf_saa module maintains a linked list of ports which it knows about.
116  * For each port, a reference count is kept.  When the first client for a
117  * port registers with ibmf_saa, ibmf_saa registers with ibmf.
118  * The reference count checking must be serialized to
119  * ensure that only one client modifies the reference count at a time.
120  * When a client determines that it is responsible for registering it
121  * sets the state field to "registering" in the port.  Clients registering with
122  * sa_acess will cv_wait on this field before modifying the reference count.
123  * Unregistering clients do not need to wait on this field since no one else
124  * will be registering while they are completing (the port's ref count will
125  * be greater than 0).
126  * If ibmf registration fails, the entry is set to "invalid"; we decrement
127  * the reference count that we just incremented.
128  *
129  * WARNING: after decrementing the reference count, NO further access to
130  * the entry should be performed in the same thread, because invalid entries
131  *  with ref counts of 0 are purged.
132  */
133 /* ARGSUSED */
134 int
135 ibmf_sa_session_open(ib_guid_t port_guid, ib_smkey_t sm_key,
136     ibmf_saa_subnet_event_args_t *event_args, uint_t ibmf_version,
137     uint_t flags, ibmf_saa_handle_t *ibmf_saa_handle)
138 {
139 	saa_port_t			*saa_portp	= NULL;
140 	int				status		= IBMF_SUCCESS;
141 	saa_client_data_t		*saa_client	= NULL;
142 
143 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
144 	    ibmf_sa_session_open_start, IBMF_TNF_TRACE, "",
145 	    "ibmf_sa_session_open() enter\n");
146 
147 	if (ibmf_version != IBMF_VERSION) {
148 
149 		IBMF_TRACE_0(IBMF_TNF_NODEBUG, DPRINT_L1,
150 		    ibmf_sa_session_open_err, IBMF_TNF_ERROR, "",
151 		    "ibmf_sa_session_open: Bad Version\n");
152 
153 		status = IBMF_BAD_VERSION;
154 		goto bail;
155 	}
156 
157 	if (ibmf_saa_handle == NULL) {
158 
159 		IBMF_TRACE_0(IBMF_TNF_NODEBUG, DPRINT_L1,
160 		    ibmf_sa_session_open_err, IBMF_TNF_ERROR, "",
161 		    "ibmf_sa_session_open: invalid argument, null pointer\n");
162 
163 		status = IBMF_INVALID_ARG;
164 		goto bail;
165 	}
166 
167 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
168 	    ibmf_sa_session_open, IBMF_TNF_TRACE, "",
169 	    "ibmf_sa_session_open: %s, guid = %016" PRIx64 ", prefix = %016"
170 	    PRIx64 "\n", tnf_string, msg, "opening session",
171 	    tnf_opaque, guid, port_guid);
172 
173 	/*
174 	 * Find a valid entry matching the port guid
175 	 * Refcount is immediately incremented
176 	 */
177 
178 	/* acquire list mutex (and keep it locked until after creation) */
179 	mutex_enter(&saa_statep->saa_port_list_mutex);
180 
181 	saa_portp = saa_statep->saa_port_list;
182 	while (saa_portp != NULL) {
183 
184 		if (saa_portp->saa_pt_port_guid == port_guid &&
185 		    ibmf_saa_is_valid(saa_portp, B_TRUE) == B_TRUE) {
186 
187 			break;
188 		}
189 		saa_portp = saa_portp->next;
190 	}
191 
192 	if (saa_portp != NULL) {
193 
194 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
195 		    ibmf_sa_session_open, IBMF_TNF_TRACE, "",
196 		    "ibmf_sa_session_open(): %s\n",
197 		    tnf_string, msg, "port exists\n");
198 
199 		/* release list mutex */
200 		mutex_exit(&saa_statep->saa_port_list_mutex);
201 
202 		/*
203 		 * now add client to existing port
204 		 * (will wait till end of ibmf registering)
205 		 * Note that the state may have changed in the meantime...
206 		 */
207 		status = ibmf_saa_impl_add_client(saa_portp);
208 
209 		if (status != IBMF_SUCCESS) {
210 
211 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
212 			    ibmf_sa_session_open_err, IBMF_TNF_ERROR, "",
213 			    "ibmf_sa_session_open: %s, status = %d\n",
214 			    tnf_string, msg, "ibmf_saa_impl_add_client()"
215 			    " failed", tnf_int, status, status);
216 
217 			goto bail;
218 		}
219 	} else {
220 
221 		/* create minimal port entry, non blocking */
222 		status = ibmf_saa_impl_create_port(port_guid, &saa_portp);
223 
224 		if (status != IBMF_SUCCESS) {
225 
226 			/* release list mutex */
227 			mutex_exit(&saa_statep->saa_port_list_mutex);
228 
229 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
230 			    ibmf_sa_session_open_err, IBMF_TNF_ERROR, "",
231 			    "ibmf_sa_session_open: %s, status = %d\n",
232 			    tnf_string, msg, "ibmf_saa_impl_create_port()"
233 			    " failed", tnf_int, status, status);
234 
235 			goto bail;
236 		}
237 
238 		/* link to list */
239 		saa_portp->next = saa_statep->saa_port_list;
240 		saa_statep->saa_port_list = saa_portp;
241 
242 		/*
243 		 * release the list mutex since we now have the minimum amount
244 		 * of port data initialized to prevent subsequent clients from
245 		 * continuing with registration (they will cv_wait on registe-
246 		 * -ring state).  We don't want to hold the list mutex since
247 		 * other ports may need it and since we're about to make calls
248 		 * to functions which may block.
249 		 *
250 		 * We do not need the port registering mutex since clients will
251 		 * not proceed while saa_pt_state ==
252 		 * IBMF_SAA_PORT_STATE_REGISTERING.
253 		 */
254 		mutex_exit(&saa_statep->saa_port_list_mutex);
255 
256 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(saa_portp->saa_pt_kstatp))
257 
258 		status = ibmf_saa_impl_init_kstats(saa_portp);
259 
260 		if (status != IBMF_SUCCESS) {
261 
262 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
263 			    ibmf_sa_session_open_err, IBMF_TNF_ERROR, "",
264 			    "ibmf_sa_session_open: %s, status = %d\n",
265 			    tnf_string, msg, "could not initialize kstats",
266 			    tnf_int, status, status);
267 
268 			ibmf_saa_impl_register_failed(saa_portp);
269 
270 			goto bail;
271 		}
272 
273 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*saa_portp))
274 
275 		status = ibmf_saa_impl_register_port(saa_portp);
276 
277 		if (status != IBMF_SUCCESS) {
278 
279 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
280 			    ibmf_sa_session_open_err, IBMF_TNF_ERROR, "",
281 			    "ibmf_sa_session_open: %s, ibmf_status = %d\n",
282 			    tnf_string, msg,
283 			    "ibmf_saa_impl_register_port failed",
284 			    tnf_int, ibmf_status, status);
285 
286 			ibmf_saa_impl_register_failed(saa_portp);
287 
288 			/*
289 			 * Note: we don't update kstats as this entry
290 			 * will eventually go away...
291 			 */
292 			goto bail;
293 
294 		}
295 
296 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
297 		    ibmf_sa_session_open, IBMF_TNF_TRACE, "",
298 		    "ibmf_sa_session_open: %s, prefix = %016" PRIx64
299 		    "\n", tnf_string, msg, "successfully initialized port");
300 
301 		/* mark port as registered */
302 		mutex_enter(&saa_portp->saa_pt_mutex);
303 
304 		/* incremement reference count to account for cpi */
305 		saa_portp->saa_pt_reference_count++;
306 
307 		saa_portp->saa_pt_state = IBMF_SAA_PORT_STATE_READY;
308 
309 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*saa_portp))
310 
311 		/* kick waiters  */
312 		cv_broadcast(&saa_portp->saa_pt_ibmf_reg_cv);
313 
314 		mutex_exit(&saa_portp->saa_pt_mutex);
315 
316 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
317 		    ibmf_sa_session_open, IBMF_TNF_TRACE, "",
318 		    "ibmf_sa_session_open: %s\n", tnf_string, msg,
319 		    "port is up.  Sending classportinfo request");
320 
321 		ibmf_saa_impl_get_classportinfo(saa_portp);
322 	}
323 
324 	mutex_enter(&saa_portp->saa_pt_kstat_mutex);
325 
326 	IBMF_SAA_ADD32_KSTATS(saa_portp, clients_registered, 1);
327 
328 	mutex_exit(&saa_portp->saa_pt_kstat_mutex);
329 
330 	/* create new client structure */
331 	saa_client = kmem_zalloc(sizeof (saa_client_data_t), KM_SLEEP);
332 
333 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*saa_client))
334 
335 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
336 	    ibmf_sa_session_open, IBMF_TNF_TRACE, "",
337 	    "ibmf_sa_session_open: clientp = %p, subnetp = %p\n",
338 	    tnf_opaque, clientp, saa_client,
339 	    tnf_opaque, subnetp, saa_portp);
340 
341 	saa_client->saa_client_port = saa_portp;
342 	mutex_init(&saa_client->saa_client_mutex, NULL, MUTEX_DRIVER,
343 	    NULL);
344 	cv_init(&saa_client->saa_client_state_cv, NULL, CV_DRIVER, NULL);
345 	cv_init(&saa_client->saa_client_event_cb_cv, NULL, CV_DRIVER, NULL);
346 
347 	IBMF_SAA_SET_CLIENT_SIGNATURE(saa_client);
348 
349 	saa_client->saa_client_state  = SAA_CLIENT_STATE_ACTIVE;
350 	saa_client->saa_client_sm_key = sm_key;
351 
352 	*ibmf_saa_handle = (ibmf_saa_handle_t)saa_client;
353 
354 	/* if client is interested in subnet event notifications */
355 	if (event_args != NULL) {
356 		ibmf_saa_add_event_subscriber(saa_client, event_args);
357 	}
358 
359 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*saa_client))
360 
361 
362 bail:
363 	/* purge invalid entries */
364 	ibmf_saa_impl_purge();
365 
366 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_sa_session_open_end,
367 	    IBMF_TNF_TRACE, "", "ibmf_sa_session_open() exit\n");
368 
369 	return (status);
370 }
371 
372 
373 /*
374  * ibmf_sa_session_close()
375  *
376  * Unregister a consumer of the SA_Access interface
377  *
378  * This interface blocks.
379  *
380  * Arguments:
381  *	SA_Access handle
382  *
383  * Return values:
384  *	IBMF_SUCCESS        - unregistration succeeded
385  *      IBMF_FAILURE        - unregistration failed for unknown reasons
386  *
387  * All outstanding callbacks will be canceled before this function returns.
388  *
389  */
390 /* ARGSUSED */
391 int
392 ibmf_sa_session_close(ibmf_saa_handle_t *ibmf_saa_handle, uint_t flags)
393 {
394 	saa_client_data_t	*client_data	= NULL;
395 	saa_port_t		*saa_portp	= NULL;
396 	int			status		= IBMF_SUCCESS;
397 	saa_client_data_t	*curr_clientp, *prev_clientp;
398 	uint8_t			port_state;
399 
400 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
401 	    ibmf_sa_session_close_start, IBMF_TNF_TRACE, "",
402 	    "ibmf_sa_session_close() enter\n");
403 
404 	if (ibmf_saa_handle == NULL) {
405 
406 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
407 		    ibmf_sa_session_close_err, IBMF_TNF_ERROR, "",
408 		    "ibmf_sa_session_close: %s\n",
409 		    tnf_string, msg, "invalid argument, NULL pointer argument");
410 
411 		status = IBMF_INVALID_ARG;
412 		goto bail;
413 	}
414 
415 	/* ibmf_saa_handle is pointer to the client data structure */
416 	client_data = (saa_client_data_t *)*ibmf_saa_handle;
417 
418 	/* sanity check to make sure nothing happened to handle */
419 	if (IBMF_SAA_VERIFY_CLIENT_SIGNATURE(client_data) == B_FALSE) {
420 
421 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
422 		    ibmf_sa_session_close_err, IBMF_TNF_ERROR, "",
423 		    "ibmf_sa_session_close: %s\n",
424 		    tnf_string, msg, "bad handle");
425 
426 		status = IBMF_BAD_HANDLE;
427 		goto bail;
428 	}
429 
430 	saa_portp = client_data->saa_client_port;
431 
432 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
433 	    ibmf_sa_session_close, IBMF_TNF_TRACE,
434 	    "", "ibmf_sa_session_close: saa_portp = %p\n",
435 	    tnf_opaque, saa_portp, saa_portp);
436 
437 	mutex_enter(&saa_portp->saa_pt_mutex);
438 
439 	port_state = saa_portp->saa_pt_state;
440 
441 	mutex_exit(&saa_portp->saa_pt_mutex);
442 
443 	/*
444 	 * if there are pending async transactions, wait for them to finish
445 	 * note that we wait only once, not loop....
446 	 * note we test the state outside saa_pt_mutex
447 	 */
448 	mutex_enter(&client_data->saa_client_mutex);
449 
450 	if ((client_data->saa_client_num_pending_trans > 0) &&
451 	    (port_state == IBMF_SAA_PORT_STATE_READY)) {
452 
453 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
454 		    ibmf_sa_session_close, IBMF_TNF_TRACE,
455 		    "", "ibmf_sa_session_close: %s, num_pending_trans = %d\n",
456 		    tnf_string, msg, "waiting for async callbacks",
457 		    tnf_uint, num_pending_trans,
458 		    client_data->saa_client_num_pending_trans);
459 
460 		client_data->saa_client_state = SAA_CLIENT_STATE_WAITING;
461 
462 		/*
463 		 * we rely on IBMF calling the callback in all cases,
464 		 * callback signals cv
465 		 */
466 		cv_wait(&client_data->saa_client_state_cv,
467 		    &client_data->saa_client_mutex);
468 
469 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_sa_session_close,
470 		    IBMF_TNF_TRACE, "", "ibmf_sa_session_close: %s\n",
471 		    tnf_string, msg, "done waiting");
472 	}
473 
474 	/* mark state as closed so no more event callbacks will be generated */
475 	client_data->saa_client_state = SAA_CLIENT_STATE_CLOSED;
476 
477 	/*
478 	 * if there are pending subnet event callbacks wait for them to finish
479 	 */
480 	if (client_data->saa_client_event_cb_num_active > 0) {
481 
482 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
483 		    ibmf_sa_session_close, IBMF_TNF_TRACE,
484 		    "", "ibmf_sa_session_close: %s, num_active_cb = %d\n",
485 		    tnf_string, msg, "waiting for event callbacks",
486 		    tnf_uint, num_active_cb,
487 		    client_data->saa_client_event_cb_num_active);
488 
489 		cv_wait(&client_data->saa_client_event_cb_cv,
490 		    &client_data->saa_client_mutex);
491 	}
492 
493 	mutex_exit(&client_data->saa_client_mutex);
494 
495 	mutex_enter(&saa_portp->saa_pt_kstat_mutex);
496 
497 	IBMF_SAA_SUB32_KSTATS(saa_portp, clients_registered, 1);
498 
499 	mutex_exit(&saa_portp->saa_pt_kstat_mutex);
500 
501 	/*
502 	 * if client was subscribed for events then remove the callback from the
503 	 * list, and possibly unsubscribe from the SA
504 	 */
505 	if (client_data->saa_client_event_cb != NULL) {
506 
507 		/* remove the client from the port's list of clients */
508 		mutex_enter(&saa_portp->saa_pt_event_sub_mutex);
509 
510 		curr_clientp = saa_portp->saa_pt_event_sub_client_list;
511 		prev_clientp = NULL;
512 		while (curr_clientp != NULL) {
513 
514 			if (curr_clientp == client_data) {
515 
516 				break;
517 			}
518 
519 			prev_clientp = curr_clientp;
520 			curr_clientp = curr_clientp->next;
521 		}
522 
523 		/* should have found the client */
524 		ASSERT(curr_clientp != NULL);
525 
526 		if (curr_clientp == NULL) {
527 
528 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
529 			    ibmf_sa_session_close, IBMF_TNF_ERROR, "",
530 			    "ibmf_sa_session_close: %s.  ref_count = %d\n",
531 			    tnf_string, msg, "could not find client in list",
532 			    tnf_opaque, client, client_data);
533 		} else {
534 
535 			if (prev_clientp == NULL) {
536 
537 				saa_portp->saa_pt_event_sub_client_list =
538 				    curr_clientp->next;
539 
540 			} else
541 				prev_clientp->next = curr_clientp->next;
542 
543 			IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
544 			    ibmf_sa_session_close, IBMF_TNF_TRACE, "",
545 			    "ibmf_sa_session_close: %s\n", tnf_string, msg,
546 			    "Removed client from event subscriber list");
547 		}
548 
549 
550 		mutex_exit(&saa_portp->saa_pt_event_sub_mutex);
551 
552 	}
553 
554 	/* decrementing refcount is last thing we do on port entry */
555 	mutex_enter(&saa_portp->saa_pt_mutex);
556 
557 	ASSERT(saa_portp->saa_pt_reference_count > 0);
558 	saa_portp->saa_pt_reference_count--;
559 
560 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_sa_session_close,
561 	    IBMF_TNF_TRACE, "",
562 	    "ibmf_sa_session_close: ref_count = %d\n",
563 	    tnf_uint, port_ref_count,
564 	    saa_portp->saa_pt_reference_count);
565 
566 	mutex_exit(&saa_portp->saa_pt_mutex);
567 
568 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
569 	    ibmf_sa_session_close, IBMF_TNF_TRACE, "",
570 	    "ibmf_sa_session_close: %s, clientp = %p\n", tnf_string, msg,
571 	    "freeing client memory", tnf_opaque, clientp, *ibmf_saa_handle);
572 
573 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*client_data))
574 
575 	/* destroy client */
576 	mutex_destroy(&client_data->saa_client_mutex);
577 
578 	cv_destroy(&client_data->saa_client_state_cv);
579 	cv_destroy(&client_data->saa_client_event_cb_cv);
580 
581 	IBMF_SAA_CLEAR_CLIENT_SIGNATURE(client_data);
582 
583 	kmem_free(*ibmf_saa_handle, sizeof (saa_client_data_t));
584 
585 	*ibmf_saa_handle = NULL;
586 
587 bail:
588 	/* purge invalid entries */
589 	ibmf_saa_impl_purge();
590 
591 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_sa_session_close_end,
592 	    IBMF_TNF_TRACE, "", "ibmf_sa_session_close() exit\n");
593 
594 	return (status);
595 }
596 
597 /*
598  * ibmf_sa_access
599  *
600  * Retrieve records from the SA given an AttributeID, ComponentMask,
601  * and a template
602  *
603  * This interface blocks if the callback parameter is NULL.
604  *
605  * Input Arguments:
606  * ibmf_saa_handle	- handle returned from ibmf_sa_session_open()
607  * access_args 		- structure containing various parameters for the query
608  * flags 		- unsused
609  *
610  * Output Arguments:
611  * length		- size of buffer returned
612  * result		- pointer to buffer of records returned in response.
613  *			  Buffer is host-endian, unpacked and can be cast to one
614  *			  of the record types in sa_recs.h
615  * Return values:
616  * IBMF_SUCCESS 	- query succeeded
617  * IBMF_BAD_HANDLE	- sa session handle is invalid
618  * IBMF_BAD_PORT_STATE	- port in incorrect state
619  * IBMF_INVALID_ARG	- one of the pointer parameters was NULL
620  * IBMF_NO_RESOURCES	- ibmf could not allocate ib resources or SA returned
621  *			  ERR_NO_RESOURCES
622  * IBMF_TRANS_TIMEOUT	- transaction timed out
623  * IBMF_TRANS_FAILURE	- transaction failure
624  * IBMF_NO_MEMORY	- ibmf could not allocate memory
625  * IBMF_REQ_INVALID	- send and recv buffer the same for a sequenced
626  *			  transaction or the SA returned an ERR_REQ_INVALID
627  * IBMF_NO_RECORDS	- no records matched query
628  * IBMF_TOO_MANY_RECORDS- SA returned SA_ERR_TOO_MANY_RECORDS
629  * IBMF_INVALID_GID	- SA returned SA_INVALID_GID
630  * IBMF_INSUFF_COMPS	- SA returned SA_ERR_INSUFFICIENT_COMPS
631  * IBMF_UNSUPP_METHOD	- SA returned MAD_STATUS_UNSUPP_METHOD
632  * IBMF_UNSUPP_METHOD_ATTR - SA returned MAD_STATUS_UNSUPP_METHOD_ATTR
633  * IBMF_INVALID_FIELD	- SA returned MAD_STATUS_INVALID_FIELD
634  *
635  * Upon successful completion, result points to a buffer containing the records.
636  * length is the size in bytes of the buffer returned in result.  If there are
637  * no records or the call failed the length is 0.
638  *
639  * The consumer is responsible for freeing the memory associated with result.
640  */
641 /* ARGSUSED */
642 int
643 ibmf_sa_access(ibmf_saa_handle_t ibmf_saa_handle,
644     ibmf_saa_access_args_t *access_args, uint_t flags, size_t *length,
645     void **result)
646 {
647 	int			res = IBMF_SUCCESS;
648 
649 	saa_impl_trans_info_t	*trans_info;
650 	saa_client_data_t	*clientp;
651 	saa_port_t		*saa_portp;
652 
653 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3,
654 	    ibmf_sa_access_start, IBMF_TNF_TRACE, "",
655 	    "ibmf_sa_access_start() enter. attr_id = 0x%x, access_type ="
656 	    " 0x%x, comp_mask = %016" PRIx64 "\n",
657 	    tnf_opaque, attr_id, access_args->sq_attr_id,
658 	    tnf_opaque, access_type, access_args->sq_access_type,
659 	    tnf_opaque, comp_mask, access_args->sq_component_mask);
660 
661 	if ((access_args == NULL) || (length == NULL) || (result == NULL)) {
662 
663 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
664 		    ibmf_sa_access_err, IBMF_TNF_ERROR, "",
665 		    "ibmf_sa_access: %s\n",
666 		    tnf_string, msg, "invalid argument, NULL pointer argument");
667 
668 		res = IBMF_INVALID_ARG;
669 		goto bail;
670 	}
671 
672 	/* sanity check to make sure nothing happened to handle */
673 	if (IBMF_SAA_VERIFY_CLIENT_SIGNATURE(
674 	    (saa_client_data_t *)ibmf_saa_handle) == B_FALSE) {
675 
676 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
677 		    ibmf_sa_access_err, IBMF_TNF_ERROR, "",
678 		    "ibmf_sa_access: %s\n",
679 		    tnf_string, msg, "bad handle");
680 
681 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
682 		    ibmf_sa_access_end, IBMF_TNF_TRACE,
683 		    "", "ibmf_sa_access() exit\n");
684 
685 		res = IBMF_BAD_HANDLE;
686 		goto bail;
687 	}
688 
689 	if (access_args->sq_callback == NULL) {
690 
691 		trans_info = kmem_zalloc(sizeof (saa_impl_trans_info_t),
692 		    KM_SLEEP);
693 	} else {
694 		trans_info = kmem_zalloc(sizeof (saa_impl_trans_info_t),
695 		    KM_NOSLEEP);
696 		if (trans_info == NULL) {
697 
698 			IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
699 			    ibmf_sa_access_err, IBMF_TNF_ERROR, "",
700 			    "ibmf_sa_access: %s\n", tnf_string, msg,
701 			    "could not allocate memory for trans_info");
702 
703 			res = IBMF_NO_MEMORY;
704 			goto bail;
705 		}
706 	}
707 
708 	clientp = (saa_client_data_t *)ibmf_saa_handle;
709 	saa_portp = clientp->saa_client_port;
710 
711 	trans_info->si_trans_client_data = clientp;
712 	trans_info->si_trans_port = saa_portp;
713 
714 	/*
715 	 * method is get_multi if attribute is multipath; otherwise method is
716 	 * based on query type
717 	 */
718 	if (access_args->sq_attr_id == SA_MULTIPATHRECORD_ATTRID) {
719 
720 		if (access_args->sq_access_type != IBMF_SAA_RETRIEVE) {
721 
722 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
723 			    ibmf_sa_access_err, IBMF_TNF_ERROR, "",
724 			    "ibmf_sa_access: %s, access_type = 0x%x\n",
725 			    tnf_string, msg, "access_type for multi-path"
726 			    " records must be IBMF_SAA_RETRIEVE",
727 			    tnf_opaque, access_type,
728 			    access_args->sq_access_type);
729 
730 			kmem_free(trans_info, sizeof (saa_impl_trans_info_t));
731 
732 			res = IBMF_REQ_INVALID;
733 			goto bail;
734 		}
735 
736 		trans_info->si_trans_method = SA_SUBN_ADM_GET_MULTI;
737 	} else if (access_args->sq_attr_id == SA_TRACERECORD_ATTRID) {
738 
739 		if (access_args->sq_access_type != IBMF_SAA_RETRIEVE) {
740 
741 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
742 			    ibmf_sa_access_err, IBMF_TNF_ERROR, "",
743 			    "ibmf_sa_access: %s, access_type = 0x%x\n",
744 			    tnf_string, msg, "access_type for trace"
745 			    " records must be IBMF_SAA_RETRIEVE",
746 			    tnf_opaque, access_type,
747 			    access_args->sq_access_type);
748 
749 			kmem_free(trans_info, sizeof (saa_impl_trans_info_t));
750 
751 			res = IBMF_REQ_INVALID;
752 			goto bail;
753 		}
754 
755 		trans_info->si_trans_method = SA_SUBN_ADM_GET_TRACE_TABLE;
756 	} else {
757 
758 		switch (access_args->sq_access_type) {
759 
760 			case IBMF_SAA_RETRIEVE:
761 				trans_info->si_trans_method =
762 				    SA_SUBN_ADM_GET_TABLE;
763 				break;
764 			case IBMF_SAA_UPDATE:
765 				trans_info->si_trans_method = SA_SUBN_ADM_SET;
766 				break;
767 			case IBMF_SAA_DELETE:
768 				trans_info->si_trans_method =
769 				    SA_SUBN_ADM_DELETE;
770 				break;
771 			default:
772 
773 				IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
774 				    ibmf_sa_access_err, IBMF_TNF_ERROR, "",
775 				    "ibmf_sa_access: %s, access_type = 0x%x\n",
776 				    tnf_string, msg, "unknown access_type",
777 				    tnf_opaque, access_type,
778 				    access_args->sq_access_type);
779 
780 				kmem_free(trans_info,
781 				    sizeof (saa_impl_trans_info_t));
782 
783 				res = IBMF_REQ_INVALID;
784 				goto bail;
785 		}
786 	}
787 
788 	trans_info->si_trans_attr_id = access_args->sq_attr_id;
789 	trans_info->si_trans_component_mask = access_args->sq_component_mask;
790 	trans_info->si_trans_template = access_args->sq_template;
791 	trans_info->si_trans_template_length = access_args->sq_template_length;
792 	trans_info->si_trans_callback = access_args->sq_callback;
793 	trans_info->si_trans_callback_arg = access_args->sq_callback_arg;
794 
795 	mutex_enter(&saa_portp->saa_pt_kstat_mutex);
796 
797 	IBMF_SAA_ADD32_KSTATS(saa_portp, outstanding_requests, 1);
798 	IBMF_SAA_ADD32_KSTATS(saa_portp, total_requests, 1);
799 
800 	mutex_exit(&saa_portp->saa_pt_kstat_mutex);
801 
802 	res = ibmf_saa_impl_send_request(trans_info);
803 	if (res != IBMF_SUCCESS) {
804 
805 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
806 		    ibmf_sa_access_err, IBMF_TNF_ERROR, "",
807 		    "ibmf_sa_access: %s, ibmf_status = %d\n",
808 		    tnf_string, msg, "ibmf_saa_impl_send_request() failed",
809 		    tnf_int, ibmf_status, res);
810 
811 		*length = 0;
812 		*result = NULL;
813 
814 		kmem_free(trans_info, sizeof (saa_impl_trans_info_t));
815 
816 		mutex_enter(&saa_portp->saa_pt_kstat_mutex);
817 
818 		IBMF_SAA_SUB32_KSTATS(saa_portp, outstanding_requests, 1);
819 		IBMF_SAA_ADD32_KSTATS(saa_portp, failed_requests, 1);
820 
821 		if (res == IBMF_TRANS_TIMEOUT)
822 			IBMF_SAA_ADD32_KSTATS(saa_portp, requests_timedout,
823 			    1);
824 
825 		mutex_exit(&saa_portp->saa_pt_kstat_mutex);
826 
827 		goto bail;
828 	}
829 
830 	/*
831 	 * if async call don't do anything as callback will take care of
832 	 * everything; for sync call, copy parameters back to client and free
833 	 * trans_info structure
834 	 */
835 	if (access_args->sq_callback == NULL) {
836 		*length = trans_info->si_trans_length;
837 		*result = trans_info->si_trans_result;
838 		res = trans_info->si_trans_status;
839 
840 		mutex_enter(&saa_portp->saa_pt_kstat_mutex);
841 
842 		IBMF_SAA_SUB32_KSTATS(saa_portp, outstanding_requests, 1);
843 
844 		if (res != IBMF_SUCCESS)
845 			IBMF_SAA_ADD32_KSTATS(saa_portp, failed_requests,
846 			    1);
847 
848 		if (res == IBMF_TRANS_TIMEOUT)
849 			IBMF_SAA_ADD32_KSTATS(saa_portp, requests_timedout,
850 			    1);
851 
852 		mutex_exit(&saa_portp->saa_pt_kstat_mutex);
853 
854 		kmem_free(trans_info, sizeof (saa_impl_trans_info_t));
855 	}
856 
857 bail:
858 
859 	if (res != IBMF_SUCCESS) {
860 		if (length != NULL)
861 			*length = 0;
862 		if (result != NULL)
863 			*result = NULL;
864 	}
865 
866 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_sa_access, IBMF_TNF_TRACE,
867 	    "", "ibmf_sa_access() exit: result = 0x%x\n",
868 	    tnf_opaque, result, res);
869 
870 	return (res);
871 }
872 
873 /*
874  * Helper Functions.
875  *	Ease of use functions so that the consumer doesn't
876  * 	have to do the overhead of calling ibmf_sa_access for
877  *	commonly used queries
878  */
879 
880 /*
881  * ibmf_saa_gid_to_pathrecords
882  * 	Given a source gid and a destination gid, return paths
883  *	between the gids.
884  *
885  * This interface blocks.
886  *
887  * Input Arguments:
888  * ibmf_saa_handle	- handle returned from ibmf_sa_session_open()
889  * sgid 		- source gid of path
890  * dgid			- destination gid of path
891  * p_key		- partition of path.  This value may be wildcarded with
892  *			  IBMF_SAA_PKEY_WC.
893  * mtu 			- preferred MTU of the path.  This argument may be
894  *			  wildcarded with IBMF_SAA_MTU_WC.
895  * reversible		- if B_TRUE, ibmf will query only reversible paths
896  *			  see Infiniband Specification table 171
897  * num_paths		- maximum number of paths to return
898  *			  num_paths should be checked for the actual number of
899  *			  records returned.
900  * flags		- unused
901  *
902  * Output Arguments:
903  * num_paths		- actual number of paths returned
904  * length		- size of buffer returned
905  * result		- pointer to buffer of path records returned in response
906  *
907  * Return values:
908  * Error codes are the same as ibmf_sa_access() return values
909  *
910  * Upon successful completion, result points to a buffer containing the records.
911  * length is the size in bytes of the buffer returned in result.  If there are
912  * no records or the call failed the length is 0.
913  *
914  * The consumer is responsible for freeing the memory associated with result.
915  */
916 /* ARGSUSED */
917 int
918 ibmf_saa_gid_to_pathrecords(ibmf_saa_handle_t ibmf_saa_handle, ib_gid_t sgid,
919     ib_gid_t dgid, ib_pkey_t p_key, ib_mtu_t mtu, boolean_t reversible,
920     uint8_t *num_paths, uint_t flags, size_t *length, sa_path_record_t **result)
921 {
922 	sa_path_record_t	path_record;
923 	uint64_t		comp_mask;
924 	int			res;
925 	ibmf_saa_access_args_t	access_args;
926 
927 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
928 	    ibmf_saa_gid_to_pathrecords_start, IBMF_TNF_TRACE, "",
929 	    "ibmf_saa_gid_to_pathrecords() enter\n");
930 
931 	/*
932 	 * check num_paths pointer here since we dereference before calling
933 	 * ibmf_sa_access
934 	 */
935 	if (num_paths == NULL) {
936 
937 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
938 		    ibmf_saa_gid_to_pathrecords_err, IBMF_TNF_ERROR, "",
939 		    "ibmf_saa_gid_to_pathrecords: %s\n",
940 		    tnf_string, msg, "invalid argument, NULL pointer argument");
941 
942 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
943 		    ibmf_saa_gid_to_pathrecords_end, IBMF_TNF_TRACE,
944 		    "", "ibmf_saa_gid_to_pathrecords() exit\n");
945 
946 		if (length != NULL)
947 			*length = 0;
948 		if (result != NULL)
949 			*result = NULL;
950 
951 		return (IBMF_INVALID_ARG);
952 	}
953 
954 	/* check valid handle; in non-debug system ibmf_sa_access() will fail */
955 	ASSERT(ibmf_saa_handle != NULL);
956 
957 	ASSERT(length != NULL);
958 	ASSERT(result != NULL);
959 
960 	*length = 0;
961 	*result = NULL;
962 
963 	comp_mask = SA_PR_COMPMASK_SGID | SA_PR_COMPMASK_DGID |
964 	    SA_PR_COMPMASK_NUMBPATH;
965 
966 	bzero(&path_record, sizeof (sa_path_record_t));
967 
968 	path_record.SGID = sgid;
969 	path_record.DGID = dgid;
970 	path_record.NumbPath = *num_paths;
971 
972 	if (reversible == B_TRUE) {
973 		path_record.Reversible = 1;
974 		comp_mask |= SA_PR_COMPMASK_REVERSIBLE;
975 	}
976 
977 	if (p_key != IBMF_SAA_PKEY_WC) {
978 
979 		path_record.P_Key = p_key;
980 		comp_mask |= SA_PR_COMPMASK_PKEY;
981 	}
982 
983 	/*
984 	 * gid_to_pathrecords specifies greater than or equal to MTU.  Path
985 	 * records can only do strictly greater.  Set the mtu value to one
986 	 * less than the mtu parameter.  If it's the lowest value possible (256)
987 	 * don't do anything and any path mtu will be allowed.
988 	 */
989 	if ((mtu != IBMF_SAA_MTU_WC) && (mtu > IB_MTU_256)) {
990 
991 		path_record.MtuSelector = SA_PR_MTU_SEL_GREATER;
992 		path_record.Mtu = (mtu - 1);
993 
994 		comp_mask |= SA_PR_COMPMASK_MTUSELECTOR | SA_PR_COMPMASK_MTU;
995 	}
996 
997 	access_args.sq_attr_id = SA_PATHRECORD_ATTRID;
998 	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
999 	access_args.sq_component_mask = comp_mask;
1000 	access_args.sq_template = &path_record;
1001 	access_args.sq_callback = NULL;
1002 	access_args.sq_callback_arg = NULL;
1003 
1004 	res = ibmf_sa_access(ibmf_saa_handle, &access_args, 0, length,
1005 	    (void **)result);
1006 	if (res != IBMF_SUCCESS) {
1007 
1008 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
1009 		    ibmf_saa_gid_to_pathrecords, IBMF_TNF_TRACE, "",
1010 		    "ibmf_saa_gid_to_pathrecords: %s, ibmf_status = %d\n",
1011 		    tnf_string, msg, "ibmf_sa_access() failed",
1012 		    tnf_int, ibmf_status, res);
1013 	}
1014 
1015 	*num_paths = *length / sizeof (sa_path_record_t);
1016 
1017 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1018 	    ibmf_saa_gid_to_pathrecords_end, IBMF_TNF_TRACE, "",
1019 	    "ibmf_saa_gid_to_pathrecords() exit: result = 0x%x\n",
1020 	    tnf_opaque, result, res);
1021 
1022 	return (res);
1023 }
1024 
1025 /*
1026  * ibmf_saa_paths_from_gid
1027  *      Given a source GID, return a path from the source gid
1028  *	to every other port on the subnet.  It is assumed that the
1029  *	subnet is fully connected.  Only one path per port on the subnet
1030  *	is returned.
1031  *
1032  * This interface blocks.
1033  *
1034  * Input Arguments:
1035  * ibmf_saa_handle	- handle returned from ibmf_sa_session_open()
1036  * sgid 		- source gid of path
1037  * pkey			- paritition of path.  This value may be wildcarded with
1038  *			  IBMF_SAA_PKEY_WC.
1039  * reversible		- if B_TRUE, ibmf will query only reversible paths;
1040  *			  see Infiniband Specification table 171
1041  * flags		- unused
1042  *
1043  * Output Arguments:
1044  * num_paths		- number of paths returned
1045  * length		- size of buffer returned
1046  * result		- pointer to buffer of path records returned in response
1047  *
1048  * Return values:
1049  * Error codes are the same as ibmf_sa_access() return values
1050  *
1051  * Upon successful completion, result points to a buffer containing the records.
1052  * and num_records is the number of path records returned.  length is the size
1053  * in bytes of the buffer returned in result.  If there are no records or the
1054  * call failed the length is 0.
1055  *
1056  * The consumer is responsible for freeing the memory associated with result.
1057  */
1058 /* ARGSUSED */
1059 int
1060 ibmf_saa_paths_from_gid(ibmf_saa_handle_t ibmf_saa_handle, ib_gid_t sgid,
1061     ib_pkey_t p_key, boolean_t reversible, uint_t flags, uint_t *num_paths,
1062     size_t *length, sa_path_record_t **result)
1063 {
1064 	sa_path_record_t	path_record;
1065 	uint64_t		comp_mask;
1066 	int			res;
1067 	ibmf_saa_access_args_t	access_args;
1068 
1069 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1070 	    ibmf_saa_paths_from_gid_start, IBMF_TNF_TRACE, "",
1071 	    "ibmf_saa_paths_from_gid() enter\n");
1072 
1073 	/* check valid handle; in non-debug system ibmf_sa_access() will fail */
1074 	ASSERT(ibmf_saa_handle != NULL);
1075 
1076 	ASSERT(length != NULL);
1077 	ASSERT(result != NULL);
1078 
1079 	comp_mask = SA_PR_COMPMASK_SGID | SA_PR_COMPMASK_NUMBPATH;
1080 
1081 	bzero(&path_record, sizeof (sa_path_record_t));
1082 
1083 	path_record.SGID = sgid;
1084 	path_record.NumbPath = 1;
1085 
1086 	if (reversible == B_TRUE) {
1087 		path_record.Reversible = 1;
1088 		comp_mask |= SA_PR_COMPMASK_REVERSIBLE;
1089 	}
1090 
1091 	if (p_key != IBMF_SAA_PKEY_WC) {
1092 
1093 		path_record.P_Key = p_key;
1094 		comp_mask |= SA_PR_COMPMASK_PKEY;
1095 	}
1096 
1097 	access_args.sq_attr_id = SA_PATHRECORD_ATTRID;
1098 	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
1099 	access_args.sq_component_mask = comp_mask;
1100 	access_args.sq_template = &path_record;
1101 	access_args.sq_callback = NULL;
1102 	access_args.sq_callback_arg = NULL;
1103 
1104 	res = ibmf_sa_access(ibmf_saa_handle, &access_args, 0, length,
1105 	    (void **)result);
1106 	if (res != IBMF_SUCCESS) {
1107 
1108 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
1109 		    ibmf_saa_gid_to_pathrecords, IBMF_TNF_TRACE, "",
1110 		    "ibmf_saa_gid_to_pathrecords: %s, ibmf_status = %d\n",
1111 		    tnf_string, msg, "ibmf_sa_access() failed",
1112 		    tnf_int, ibmf_status, res);
1113 	}
1114 
1115 	*num_paths = *length / sizeof (sa_path_record_t);
1116 
1117 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1118 	    ibmf_saa_paths_from_gid_end, IBMF_TNF_TRACE, "",
1119 	    "ibmf_saa_paths_from_gid() exit: result = 0x%x\n",
1120 	    tnf_opaque, result, res);
1121 
1122 	return (res);
1123 }
1124 
1125 /*
1126  * ibmf_saa_name_to_service_record:
1127  *	Given a service name, return the service records associated
1128  *	with it.
1129  *
1130  * This interface blocks.
1131  *
1132  * Input Arguments:
1133  * ibmf_saa_handle	- handle returned from ibmf_sa_session_open()
1134  * name			- service name, a null terminated string
1135  * p_key		- partition that the service is requested on.  This
1136  *			  value may be wildcarded with IBMF_SAA_PKEY_WC.
1137  * flags		- unused
1138  *
1139  * Output Arguments:
1140  * num_records		- number of service records returned
1141  * length		- size of buffer returned
1142  * result		- pointer to buffer of service records returned in
1143  *			  response
1144  * Return values:
1145  * Error codes are the same as ibmf_sa_access() return values
1146  *
1147  * Upon successful completion, result points to a buffer containing the records.
1148  * and num_records is the number of service records returned.  length is the
1149  * size in bytes of the buffer returned in result.  If there are no records or
1150  * the call failed the length is 0.
1151  *
1152  * The consumer is responsible for freeing the memory associated with result.
1153  */
1154 /* ARGSUSED */
1155 int
1156 ibmf_saa_name_to_service_record(ibmf_saa_handle_t ibmf_saa_handle,
1157     char *service_name, ib_pkey_t p_key, uint_t flags,
1158     uint_t *num_records, size_t *length, sa_service_record_t **result)
1159 {
1160 	sa_service_record_t	service_record;
1161 	int			res;
1162 	ibmf_saa_access_args_t	access_args;
1163 
1164 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1165 	    ibmf_saa_name_to_service_record_start, IBMF_TNF_TRACE, "",
1166 	    "ibmf_saa_name_to_service_record() enter\n");
1167 
1168 	/* check valid handle; in non-debug system ibmf_sa_access() will fail */
1169 	ASSERT(ibmf_saa_handle != NULL);
1170 
1171 	ASSERT(num_records != NULL);
1172 	ASSERT(length != NULL);
1173 	ASSERT(result != NULL);
1174 
1175 	bzero((void *)&service_record, sizeof (sa_service_record_t));
1176 
1177 	if (strlen(service_name) >= IB_SVC_NAME_LEN) {
1178 
1179 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
1180 		    ibmf_saa_name_to_service_record_err, IBMF_TNF_ERROR, "",
1181 		    "ibmf_saa_gid_to_pathrecords: %s, service_name = %s\n",
1182 		    tnf_string, msg, "service name too long",
1183 		    tnf_string, service_name, service_name);
1184 
1185 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1186 		    ibmf_saa_name_to_service_record_end, IBMF_TNF_TRACE, "",
1187 		    "ibmf_saa_name_to_service_record() exit\n");
1188 
1189 		*num_records = 0;
1190 		*length = 0;
1191 		*result = NULL;
1192 
1193 		return (IBMF_REQ_INVALID);
1194 	}
1195 
1196 	/* copy IB_SVC_NAME_LEN bytes, leaving room at end for null char */
1197 	(void) strncpy((char *)(service_record.ServiceName), service_name,
1198 	    IB_SVC_NAME_LEN-1);
1199 
1200 	if (p_key != IBMF_SAA_PKEY_WC) {
1201 		service_record.ServiceP_Key = p_key;
1202 		access_args.sq_component_mask = SA_SR_COMPMASK_NAME |
1203 		    SA_SR_COMPMASK_PKEY;
1204 	} else
1205 		access_args.sq_component_mask = SA_SR_COMPMASK_NAME;
1206 
1207 	access_args.sq_attr_id = SA_SERVICERECORD_ATTRID;
1208 	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
1209 	access_args.sq_template = &service_record;
1210 	access_args.sq_callback = NULL;
1211 	access_args.sq_callback_arg = NULL;
1212 
1213 	res = ibmf_sa_access(ibmf_saa_handle, &access_args, 0, length,
1214 	    (void *)result);
1215 	if (res != IBMF_SUCCESS) {
1216 
1217 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
1218 		    ibmf_saa_name_to_service_record, IBMF_TNF_TRACE, "",
1219 		    "ibmf_saa_name_to_service_record: %s, ibmf_status = %d\n",
1220 		    tnf_string, msg, "ibmf_sa_access() failed",
1221 		    tnf_int, ibmf_status, res);
1222 	}
1223 
1224 	*num_records = *length / sizeof (sa_service_record_t);
1225 
1226 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1227 	    ibmf_saa_name_to_service_record_end, IBMF_TNF_TRACE, "",
1228 	    "ibmf_saa_name_to_service_record() exit: result = 0x%x\n",
1229 	    tnf_opaque, result, res);
1230 
1231 	return (res);
1232 }
1233 
1234 /*
1235  * ibmf_saa_id_to_service_record:
1236  *      Given a service id, return the service records associated
1237  *      with it.
1238  *
1239  * This interface blocks.
1240  *
1241  * Input Arguments:
1242  * ibmf_saa_handle	- handle returned from ibmf_sa_session_open()
1243  * id			- service id
1244  * p_key		- partition that the service is requested on.  This
1245  *			  value may be wildcarded with IBMF_SAA_PKEY_WC.
1246  * flags		- unused
1247  *
1248  * Output Arguments:
1249  * num_records		- number of service records returned
1250  * length		- size of buffer returned
1251  * result		- pointer to buffer of service records returned in
1252  *			  response
1253  *
1254  * Return values:
1255  * Error codes are the same as ibmf_sa_access() return values
1256  *
1257  * Upon successful completion, result points to a buffer containing the records.
1258  * and num_records is the number of service records returned.  length is the
1259  * size in bytes of the buffer returned in result.  If there are no records or
1260  * the call failed the length is 0.
1261  *
1262  * The consumer is responsible for freeing the memory associated with result.
1263  */
1264 /* ARGSUSED */
1265 int
1266 ibmf_saa_id_to_service_record(ibmf_saa_handle_t ibmf_saa_handle,
1267     ib_svc_id_t service_id, ib_pkey_t p_key, uint_t flags, uint_t *num_records,
1268     size_t *length, sa_service_record_t **result)
1269 {
1270 	sa_service_record_t	service_record;
1271 	int	res;
1272 	ibmf_saa_access_args_t	access_args;
1273 
1274 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1275 	    ibmf_saa_id_to_service_record_start, IBMF_TNF_TRACE, "",
1276 	    "ibmf_saa_id_to_service_record() enter\n");
1277 
1278 	/* check valid handle; in non-debug system ibmf_sa_access() will fail */
1279 	ASSERT(ibmf_saa_handle != NULL);
1280 
1281 	ASSERT(num_records != NULL);
1282 	ASSERT(length != NULL);
1283 	ASSERT(result != NULL);
1284 
1285 	bzero((void *)&service_record, sizeof (sa_service_record_t));
1286 
1287 	service_record.ServiceID = service_id;
1288 
1289 	if (p_key != IBMF_SAA_PKEY_WC) {
1290 		service_record.ServiceP_Key = p_key;
1291 		access_args.sq_component_mask = SA_SR_COMPMASK_ID |
1292 		    SA_SR_COMPMASK_PKEY;
1293 	} else
1294 		access_args.sq_component_mask = SA_SR_COMPMASK_ID;
1295 
1296 	access_args.sq_attr_id = SA_SERVICERECORD_ATTRID;
1297 	access_args.sq_access_type = IBMF_SAA_RETRIEVE;
1298 	access_args.sq_template = &service_record;
1299 	access_args.sq_callback = NULL;
1300 	access_args.sq_callback_arg = NULL;
1301 
1302 	res = ibmf_sa_access(ibmf_saa_handle, &access_args, 0, length,
1303 	    (void **)result);
1304 	if (res != IBMF_SUCCESS) {
1305 
1306 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L2,
1307 		    ibmf_saa_id_to_service_record, IBMF_TNF_TRACE, "",
1308 		    "ibmf_saa_id_to_service_record: %s, ibmf_status = %d\n",
1309 		    tnf_string, msg, "ibmf_sa_access() failed",
1310 		    tnf_int, ibmf_status, res);
1311 	}
1312 
1313 	*num_records = *length / sizeof (sa_service_record_t);
1314 
1315 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1316 	    ibmf_saa_id_to_service_record_end, IBMF_TNF_TRACE, "",
1317 	    "ibmf_saa_id_to_service_record() exit: result = 0x%x\n",
1318 	    tnf_opaque, result, res);
1319 
1320 	return (res);
1321 }
1322 
1323 /*
1324  * ibmf_saa_update_service_record
1325  *	Given a pointer to a service record, either insert or delete it
1326  *
1327  * This interface blocks.
1328  *
1329  * Input Arguments:
1330  * ibmf_saa_handle	- handle returned from ibmf_sa_session_open()
1331  * service_record	- service record is to be inserted or deleted.  To
1332  *			  delete a service record the GID, ID, P_Key, and
1333  *			  Service Key must match what is in the SA.
1334  * access_type		- indicates whether this is an insertion or deletion.
1335  *			  valid values are IBMF_SAA_UPDATE or IBMF_SAA_DELETE
1336  * flags		- unused
1337  *
1338  * Output Arguments
1339  * none
1340  *
1341  * Return values:
1342  * Error codes are the same as ibmf_sa_access() return values
1343  */
1344 /* ARGSUSED */
1345 int
1346 ibmf_saa_update_service_record(ibmf_saa_handle_t ibmf_saa_handle,
1347     sa_service_record_t *service_record, ibmf_saa_access_type_t access_type,
1348     uint_t flags)
1349 {
1350 	size_t			length;
1351 	void			*result;
1352 	int			res;
1353 	uint64_t		comp_mask;
1354 	ibmf_saa_access_args_t	access_args;
1355 
1356 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1357 	    ibmf_saa_update_service_record_start, IBMF_TNF_TRACE, "",
1358 	    "ibmf_saa_update_service_record() enter\n");
1359 
1360 	/* check valid handle; in non-debug system ibmf_sa_access() will fail */
1361 	ASSERT(ibmf_saa_handle != NULL);
1362 
1363 	if ((access_type != IBMF_SAA_UPDATE) &&
1364 	    (access_type != IBMF_SAA_DELETE)) {
1365 
1366 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
1367 		    ibmf_saa_update_service_record_err, IBMF_TNF_ERROR, "",
1368 		    "ibmf_saa_update_service_record: %s, access_type = 0x%x\n",
1369 		    tnf_string, msg, "invalid query type",
1370 		    tnf_opaque, access_type, access_type);
1371 
1372 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1373 		    ibmf_saa_update_service_record_end, IBMF_TNF_TRACE, "",
1374 		    "ibmf_saa_update_service_record() exit\n");
1375 
1376 		return (IBMF_REQ_INVALID);
1377 	}
1378 
1379 	/*
1380 	 * call ibmf_sa_access with the following special parameters:
1381 	 * attrid : service_record
1382 	 * component_mask : RID fields of service record (GID, ID, and P_key)
1383 	 *		    and service key
1384 	 */
1385 	comp_mask =  SA_SR_COMPMASK_ID | SA_SR_COMPMASK_GID |
1386 	    SA_SR_COMPMASK_PKEY | SA_SR_COMPMASK_KEY;
1387 
1388 	access_args.sq_attr_id = SA_SERVICERECORD_ATTRID;
1389 	access_args.sq_access_type = access_type;
1390 	access_args.sq_component_mask = comp_mask;
1391 	access_args.sq_template = service_record;
1392 	access_args.sq_callback = NULL;
1393 	access_args.sq_callback_arg = NULL;
1394 
1395 	res = ibmf_sa_access(ibmf_saa_handle, &access_args, 0, &length,
1396 	    &result);
1397 
1398 	/* if a valid add request, response buffer should be one service rec */
1399 	if (res == IBMF_SUCCESS && length > 0) {
1400 
1401 		if (length > sizeof (sa_service_record_t)) {
1402 
1403 			IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L1,
1404 			    ibmf_saa_update_service_record, IBMF_TNF_TRACE, "",
1405 			    "ibmf_saa_update_service_record: %s\n",
1406 			    tnf_string, msg,
1407 			    "SA returned more than one record");
1408 		}
1409 
1410 		kmem_free(result, length);
1411 	}
1412 
1413 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1414 	    ibmf_saa_update_service_record_end, IBMF_TNF_TRACE, "",
1415 	    "ibmf_saa_update_service_record() exit: result = 0x%x\n",
1416 	    tnf_opaque, result, res);
1417 
1418 	return (res);
1419 }
1420