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 */
58extern saa_state_t *saa_statep;
59extern 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 */
134int
135ibmf_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
362bail:
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 */
391int
392ibmf_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
587bail:
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 */
642int
643ibmf_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
857bail:
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 */
917int
918ibmf_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 */
1059int
1060ibmf_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 */
1155int
1156ibmf_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 */
1265int
1266ibmf_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 */
1345int
1346ibmf_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