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