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
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.
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
34 #include <sys/ib/mgt/ibmf/ibmf_saa_impl.h>
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
45 #define IBMF_SAA_SET_CLIENT_SIGNATURE(clientp) { \
46 (clientp)->saa_client_sig = (void *)0xACEDFACE; \
49 #define IBMF_SAA_VERIFY_CLIENT_SIGNATURE(clientp) \
50 (((clientp) != NULL && (clientp)->saa_client_sig == \
51 (void *)0xACEDFACE) ? B_TRUE: B_FALSE)
53 #define IBMF_SAA_CLEAR_CLIENT_SIGNATURE(clientp) { \
54 (clientp)->saa_client_sig = 0; \
57 /* Global Sa_access State Pointer */
58 extern saa_state_t
*saa_statep
;
59 extern int ibmf_trace_level
;
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
76 * ibmf_sa_session_open():
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.
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.
90 * This interface blocks allocating memory, but not waiting for any packet
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)
101 * ibmf_sa_handle - pointer to ibmf_saa_handle to be used in future calls
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
112 * IBMF_TRANSPORT_FAILURE - failure with underlying transport framework
113 * IBMF_INVALID_ARG - ibmf_saa_handle arg was NULL
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.
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.
135 ibmf_sa_session_open(ib_guid_t port_guid
, ib_smkey_t sm_key
,
136 ibmf_saa_subnet_event_args_t
*event_args
, uint_t ibmf_version
,
137 uint_t flags
, ibmf_saa_handle_t
*ibmf_saa_handle
)
139 saa_port_t
*saa_portp
= NULL
;
140 int status
= IBMF_SUCCESS
;
141 saa_client_data_t
*saa_client
= NULL
;
143 IBMF_TRACE_0(DPRINT_L4
, "ibmf_sa_session_open() enter\n");
145 if (ibmf_version
!= IBMF_VERSION
) {
147 IBMF_TRACE_0(DPRINT_L1
, "ibmf_sa_session_open: Bad Version\n");
149 status
= IBMF_BAD_VERSION
;
153 if (ibmf_saa_handle
== NULL
) {
155 IBMF_TRACE_0(DPRINT_L1
,
156 "ibmf_sa_session_open: invalid argument, null pointer\n");
158 status
= IBMF_INVALID_ARG
;
162 IBMF_TRACE_2(DPRINT_L3
,
163 "ibmf_sa_session_open: %s, guid = %016"PRIx64
", prefix = %016"PRIx64
"\n",
168 * Find a valid entry matching the port guid
169 * Refcount is immediately incremented
172 /* acquire list mutex (and keep it locked until after creation) */
173 mutex_enter(&saa_statep
->saa_port_list_mutex
);
175 saa_portp
= saa_statep
->saa_port_list
;
176 while (saa_portp
!= NULL
) {
178 if (saa_portp
->saa_pt_port_guid
== port_guid
&&
179 ibmf_saa_is_valid(saa_portp
, B_TRUE
) == B_TRUE
) {
183 saa_portp
= saa_portp
->next
;
186 if (saa_portp
!= NULL
) {
188 IBMF_TRACE_1(DPRINT_L3
, "ibmf_sa_session_open(): %s\n",
191 /* release list mutex */
192 mutex_exit(&saa_statep
->saa_port_list_mutex
);
195 * now add client to existing port
196 * (will wait till end of ibmf registering)
197 * Note that the state may have changed in the meantime...
199 status
= ibmf_saa_impl_add_client(saa_portp
);
201 if (status
!= IBMF_SUCCESS
) {
203 IBMF_TRACE_2(DPRINT_L1
,
204 "ibmf_sa_session_open: %s, status = %d\n",
205 "ibmf_saa_impl_add_client()"" failed",
212 /* create minimal port entry, non blocking */
213 status
= ibmf_saa_impl_create_port(port_guid
, &saa_portp
);
215 if (status
!= IBMF_SUCCESS
) {
217 /* release list mutex */
218 mutex_exit(&saa_statep
->saa_port_list_mutex
);
220 IBMF_TRACE_2(DPRINT_L1
,
221 "ibmf_sa_session_open: %s, status = %d\n",
222 "ibmf_saa_impl_create_port()"" failed",
229 saa_portp
->next
= saa_statep
->saa_port_list
;
230 saa_statep
->saa_port_list
= saa_portp
;
233 * release the list mutex since we now have the minimum amount
234 * of port data initialized to prevent subsequent clients from
235 * continuing with registration (they will cv_wait on registe-
236 * -ring state). We don't want to hold the list mutex since
237 * other ports may need it and since we're about to make calls
238 * to functions which may block.
240 * We do not need the port registering mutex since clients will
241 * not proceed while saa_pt_state ==
242 * IBMF_SAA_PORT_STATE_REGISTERING.
244 mutex_exit(&saa_statep
->saa_port_list_mutex
);
246 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(saa_portp
->saa_pt_kstatp
))
248 status
= ibmf_saa_impl_init_kstats(saa_portp
);
250 if (status
!= IBMF_SUCCESS
) {
252 IBMF_TRACE_2(DPRINT_L1
,
253 "ibmf_sa_session_open: %s, status = %d\n",
254 "could not initialize kstats",
257 ibmf_saa_impl_register_failed(saa_portp
);
262 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*saa_portp
))
264 status
= ibmf_saa_impl_register_port(saa_portp
);
266 if (status
!= IBMF_SUCCESS
) {
268 IBMF_TRACE_2(DPRINT_L1
,
269 "ibmf_sa_session_open: %s, ibmf_status = %d\n",
270 "ibmf_saa_impl_register_port failed",
273 ibmf_saa_impl_register_failed(saa_portp
);
276 * Note: we don't update kstats as this entry
277 * will eventually go away...
283 IBMF_TRACE_1(DPRINT_L3
,
284 "ibmf_sa_session_open: %s, prefix = %016"PRIx64
"\n",
285 "successfully initialized port");
287 /* mark port as registered */
288 mutex_enter(&saa_portp
->saa_pt_mutex
);
290 /* incremement reference count to account for cpi */
291 saa_portp
->saa_pt_reference_count
++;
293 saa_portp
->saa_pt_state
= IBMF_SAA_PORT_STATE_READY
;
295 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*saa_portp
))
298 cv_broadcast(&saa_portp
->saa_pt_ibmf_reg_cv
);
300 mutex_exit(&saa_portp
->saa_pt_mutex
);
302 IBMF_TRACE_1(DPRINT_L3
, "ibmf_sa_session_open: %s\n",
303 "port is up. Sending classportinfo request");
305 ibmf_saa_impl_get_classportinfo(saa_portp
);
308 mutex_enter(&saa_portp
->saa_pt_kstat_mutex
);
310 IBMF_SAA_ADD32_KSTATS(saa_portp
, clients_registered
, 1);
312 mutex_exit(&saa_portp
->saa_pt_kstat_mutex
);
314 /* create new client structure */
315 saa_client
= kmem_zalloc(sizeof (saa_client_data_t
), KM_SLEEP
);
317 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*saa_client
))
319 IBMF_TRACE_2(DPRINT_L3
,
320 "ibmf_sa_session_open: clientp = %p, subnetp = %p\n",
324 saa_client
->saa_client_port
= saa_portp
;
325 mutex_init(&saa_client
->saa_client_mutex
, NULL
, MUTEX_DRIVER
,
327 cv_init(&saa_client
->saa_client_state_cv
, NULL
, CV_DRIVER
, NULL
);
328 cv_init(&saa_client
->saa_client_event_cb_cv
, NULL
, CV_DRIVER
, NULL
);
330 IBMF_SAA_SET_CLIENT_SIGNATURE(saa_client
);
332 saa_client
->saa_client_state
= SAA_CLIENT_STATE_ACTIVE
;
333 saa_client
->saa_client_sm_key
= sm_key
;
335 *ibmf_saa_handle
= (ibmf_saa_handle_t
)saa_client
;
337 /* if client is interested in subnet event notifications */
338 if (event_args
!= NULL
) {
339 ibmf_saa_add_event_subscriber(saa_client
, event_args
);
342 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*saa_client
))
346 /* purge invalid entries */
347 ibmf_saa_impl_purge();
354 * ibmf_sa_session_close()
356 * Unregister a consumer of the SA_Access interface
358 * This interface blocks.
364 * IBMF_SUCCESS - unregistration succeeded
365 * IBMF_FAILURE - unregistration failed for unknown reasons
367 * All outstanding callbacks will be canceled before this function returns.
372 ibmf_sa_session_close(ibmf_saa_handle_t
*ibmf_saa_handle
, uint_t flags
)
374 saa_client_data_t
*client_data
= NULL
;
375 saa_port_t
*saa_portp
= NULL
;
376 int status
= IBMF_SUCCESS
;
377 saa_client_data_t
*curr_clientp
, *prev_clientp
;
380 IBMF_TRACE_0(DPRINT_L4
, "ibmf_sa_session_close() enter\n");
382 if (ibmf_saa_handle
== NULL
) {
384 IBMF_TRACE_1(DPRINT_L1
, "ibmf_sa_session_close: %s\n",
385 "invalid argument, NULL pointer argument");
387 status
= IBMF_INVALID_ARG
;
391 /* ibmf_saa_handle is pointer to the client data structure */
392 client_data
= (saa_client_data_t
*)*ibmf_saa_handle
;
394 /* sanity check to make sure nothing happened to handle */
395 if (IBMF_SAA_VERIFY_CLIENT_SIGNATURE(client_data
) == B_FALSE
) {
397 IBMF_TRACE_1(DPRINT_L1
, "ibmf_sa_session_close: %s\n",
400 status
= IBMF_BAD_HANDLE
;
404 saa_portp
= client_data
->saa_client_port
;
406 IBMF_TRACE_1(DPRINT_L3
, "ibmf_sa_session_close: saa_portp = %p\n",
409 mutex_enter(&saa_portp
->saa_pt_mutex
);
411 port_state
= saa_portp
->saa_pt_state
;
413 mutex_exit(&saa_portp
->saa_pt_mutex
);
416 * if there are pending async transactions, wait for them to finish
417 * note that we wait only once, not loop....
418 * note we test the state outside saa_pt_mutex
420 mutex_enter(&client_data
->saa_client_mutex
);
422 if ((client_data
->saa_client_num_pending_trans
> 0) &&
423 (port_state
== IBMF_SAA_PORT_STATE_READY
)) {
425 IBMF_TRACE_2(DPRINT_L3
,
426 "ibmf_sa_session_close: %s, num_pending_trans = %d\n",
427 "waiting for async callbacks",
428 client_data
->saa_client_num_pending_trans
);
430 client_data
->saa_client_state
= SAA_CLIENT_STATE_WAITING
;
433 * we rely on IBMF calling the callback in all cases,
434 * callback signals cv
436 cv_wait(&client_data
->saa_client_state_cv
,
437 &client_data
->saa_client_mutex
);
439 IBMF_TRACE_1(DPRINT_L3
, "ibmf_sa_session_close: %s\n",
443 /* mark state as closed so no more event callbacks will be generated */
444 client_data
->saa_client_state
= SAA_CLIENT_STATE_CLOSED
;
447 * if there are pending subnet event callbacks wait for them to finish
449 if (client_data
->saa_client_event_cb_num_active
> 0) {
451 IBMF_TRACE_2(DPRINT_L3
,
452 "ibmf_sa_session_close: %s, num_active_cb = %d\n",
453 "waiting for event callbacks",
454 client_data
->saa_client_event_cb_num_active
);
456 cv_wait(&client_data
->saa_client_event_cb_cv
,
457 &client_data
->saa_client_mutex
);
460 mutex_exit(&client_data
->saa_client_mutex
);
462 mutex_enter(&saa_portp
->saa_pt_kstat_mutex
);
464 IBMF_SAA_SUB32_KSTATS(saa_portp
, clients_registered
, 1);
466 mutex_exit(&saa_portp
->saa_pt_kstat_mutex
);
469 * if client was subscribed for events then remove the callback from the
470 * list, and possibly unsubscribe from the SA
472 if (client_data
->saa_client_event_cb
!= NULL
) {
474 /* remove the client from the port's list of clients */
475 mutex_enter(&saa_portp
->saa_pt_event_sub_mutex
);
477 curr_clientp
= saa_portp
->saa_pt_event_sub_client_list
;
479 while (curr_clientp
!= NULL
) {
481 if (curr_clientp
== client_data
) {
486 prev_clientp
= curr_clientp
;
487 curr_clientp
= curr_clientp
->next
;
490 /* should have found the client */
491 ASSERT(curr_clientp
!= NULL
);
493 if (curr_clientp
== NULL
) {
495 IBMF_TRACE_2(DPRINT_L1
,
496 "ibmf_sa_session_close: %s. ref_count = %d\n",
497 "could not find client in list",
501 if (prev_clientp
== NULL
) {
503 saa_portp
->saa_pt_event_sub_client_list
=
507 prev_clientp
->next
= curr_clientp
->next
;
509 IBMF_TRACE_1(DPRINT_L3
,
510 "ibmf_sa_session_close: %s\n",
511 "Removed client from event subscriber list");
515 mutex_exit(&saa_portp
->saa_pt_event_sub_mutex
);
519 /* decrementing refcount is last thing we do on port entry */
520 mutex_enter(&saa_portp
->saa_pt_mutex
);
522 ASSERT(saa_portp
->saa_pt_reference_count
> 0);
523 saa_portp
->saa_pt_reference_count
--;
525 IBMF_TRACE_1(DPRINT_L3
, "ibmf_sa_session_close: ref_count = %d\n",
526 saa_portp
->saa_pt_reference_count
);
528 mutex_exit(&saa_portp
->saa_pt_mutex
);
530 IBMF_TRACE_2(DPRINT_L3
, "ibmf_sa_session_close: %s, clientp = %p\n",
531 "freeing client memory", *ibmf_saa_handle
);
533 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*client_data
))
536 mutex_destroy(&client_data
->saa_client_mutex
);
538 cv_destroy(&client_data
->saa_client_state_cv
);
539 cv_destroy(&client_data
->saa_client_event_cb_cv
);
541 IBMF_SAA_CLEAR_CLIENT_SIGNATURE(client_data
);
543 kmem_free(*ibmf_saa_handle
, sizeof (saa_client_data_t
));
545 *ibmf_saa_handle
= NULL
;
548 /* purge invalid entries */
549 ibmf_saa_impl_purge();
557 * Retrieve records from the SA given an AttributeID, ComponentMask,
560 * This interface blocks if the callback parameter is NULL.
563 * ibmf_saa_handle - handle returned from ibmf_sa_session_open()
564 * access_args - structure containing various parameters for the query
568 * length - size of buffer returned
569 * result - pointer to buffer of records returned in response.
570 * Buffer is host-endian, unpacked and can be cast to one
571 * of the record types in sa_recs.h
573 * IBMF_SUCCESS - query succeeded
574 * IBMF_BAD_HANDLE - sa session handle is invalid
575 * IBMF_BAD_PORT_STATE - port in incorrect state
576 * IBMF_INVALID_ARG - one of the pointer parameters was NULL
577 * IBMF_NO_RESOURCES - ibmf could not allocate ib resources or SA returned
579 * IBMF_TRANS_TIMEOUT - transaction timed out
580 * IBMF_TRANS_FAILURE - transaction failure
581 * IBMF_NO_MEMORY - ibmf could not allocate memory
582 * IBMF_REQ_INVALID - send and recv buffer the same for a sequenced
583 * transaction or the SA returned an ERR_REQ_INVALID
584 * IBMF_NO_RECORDS - no records matched query
585 * IBMF_TOO_MANY_RECORDS- SA returned SA_ERR_TOO_MANY_RECORDS
586 * IBMF_INVALID_GID - SA returned SA_INVALID_GID
587 * IBMF_INSUFF_COMPS - SA returned SA_ERR_INSUFFICIENT_COMPS
588 * IBMF_UNSUPP_METHOD - SA returned MAD_STATUS_UNSUPP_METHOD
589 * IBMF_UNSUPP_METHOD_ATTR - SA returned MAD_STATUS_UNSUPP_METHOD_ATTR
590 * IBMF_INVALID_FIELD - SA returned MAD_STATUS_INVALID_FIELD
592 * Upon successful completion, result points to a buffer containing the records.
593 * length is the size in bytes of the buffer returned in result. If there are
594 * no records or the call failed the length is 0.
596 * The consumer is responsible for freeing the memory associated with result.
600 ibmf_sa_access(ibmf_saa_handle_t ibmf_saa_handle
,
601 ibmf_saa_access_args_t
*access_args
, uint_t flags
, size_t *length
,
604 int res
= IBMF_SUCCESS
;
606 saa_impl_trans_info_t
*trans_info
;
607 saa_client_data_t
*clientp
;
608 saa_port_t
*saa_portp
;
610 IBMF_TRACE_3(DPRINT_L3
,
611 "ibmf_sa_access_start() enter. attr_id = 0x%x, access_type ="" 0x%x, comp_mask = %016"PRIx64
"\n",
612 access_args
->sq_attr_id
,
613 access_args
->sq_access_type
,
614 access_args
->sq_component_mask
);
616 if ((access_args
== NULL
) || (length
== NULL
) || (result
== NULL
)) {
618 IBMF_TRACE_1(DPRINT_L1
, "ibmf_sa_access: %s\n",
619 "invalid argument, NULL pointer argument");
621 res
= IBMF_INVALID_ARG
;
625 /* sanity check to make sure nothing happened to handle */
626 if (IBMF_SAA_VERIFY_CLIENT_SIGNATURE(
627 (saa_client_data_t
*)ibmf_saa_handle
) == B_FALSE
) {
629 IBMF_TRACE_1(DPRINT_L1
, "ibmf_sa_access: %s\n", "bad handle");
631 res
= IBMF_BAD_HANDLE
;
635 if (access_args
->sq_callback
== NULL
) {
637 trans_info
= kmem_zalloc(sizeof (saa_impl_trans_info_t
),
640 trans_info
= kmem_zalloc(sizeof (saa_impl_trans_info_t
),
642 if (trans_info
== NULL
) {
644 IBMF_TRACE_1(DPRINT_L1
, "ibmf_sa_access: %s\n",
645 "could not allocate memory for trans_info");
647 res
= IBMF_NO_MEMORY
;
652 clientp
= (saa_client_data_t
*)ibmf_saa_handle
;
653 saa_portp
= clientp
->saa_client_port
;
655 trans_info
->si_trans_client_data
= clientp
;
656 trans_info
->si_trans_port
= saa_portp
;
659 * method is get_multi if attribute is multipath; otherwise method is
660 * based on query type
662 if (access_args
->sq_attr_id
== SA_MULTIPATHRECORD_ATTRID
) {
664 if (access_args
->sq_access_type
!= IBMF_SAA_RETRIEVE
) {
666 IBMF_TRACE_2(DPRINT_L1
,
667 "ibmf_sa_access: %s, access_type = 0x%x\n",
668 "access_type for multi-path"" records must be IBMF_SAA_RETRIEVE",
669 access_args
->sq_access_type
);
671 kmem_free(trans_info
, sizeof (saa_impl_trans_info_t
));
673 res
= IBMF_REQ_INVALID
;
677 trans_info
->si_trans_method
= SA_SUBN_ADM_GET_MULTI
;
678 } else if (access_args
->sq_attr_id
== SA_TRACERECORD_ATTRID
) {
680 if (access_args
->sq_access_type
!= IBMF_SAA_RETRIEVE
) {
682 IBMF_TRACE_2(DPRINT_L1
,
683 "ibmf_sa_access: %s, access_type = 0x%x\n",
684 "access_type for trace"" records must be IBMF_SAA_RETRIEVE",
685 access_args
->sq_access_type
);
687 kmem_free(trans_info
, sizeof (saa_impl_trans_info_t
));
689 res
= IBMF_REQ_INVALID
;
693 trans_info
->si_trans_method
= SA_SUBN_ADM_GET_TRACE_TABLE
;
696 switch (access_args
->sq_access_type
) {
698 case IBMF_SAA_RETRIEVE
:
699 trans_info
->si_trans_method
=
700 SA_SUBN_ADM_GET_TABLE
;
702 case IBMF_SAA_UPDATE
:
703 trans_info
->si_trans_method
= SA_SUBN_ADM_SET
;
705 case IBMF_SAA_DELETE
:
706 trans_info
->si_trans_method
=
711 IBMF_TRACE_2(DPRINT_L1
,
712 "ibmf_sa_access: %s, access_type = 0x%x\n",
713 "unknown access_type",
714 access_args
->sq_access_type
);
716 kmem_free(trans_info
,
717 sizeof (saa_impl_trans_info_t
));
719 res
= IBMF_REQ_INVALID
;
724 trans_info
->si_trans_attr_id
= access_args
->sq_attr_id
;
725 trans_info
->si_trans_component_mask
= access_args
->sq_component_mask
;
726 trans_info
->si_trans_template
= access_args
->sq_template
;
727 trans_info
->si_trans_template_length
= access_args
->sq_template_length
;
728 trans_info
->si_trans_callback
= access_args
->sq_callback
;
729 trans_info
->si_trans_callback_arg
= access_args
->sq_callback_arg
;
731 mutex_enter(&saa_portp
->saa_pt_kstat_mutex
);
733 IBMF_SAA_ADD32_KSTATS(saa_portp
, outstanding_requests
, 1);
734 IBMF_SAA_ADD32_KSTATS(saa_portp
, total_requests
, 1);
736 mutex_exit(&saa_portp
->saa_pt_kstat_mutex
);
738 res
= ibmf_saa_impl_send_request(trans_info
);
739 if (res
!= IBMF_SUCCESS
) {
741 IBMF_TRACE_2(DPRINT_L1
,
742 "ibmf_sa_access: %s, ibmf_status = %d\n",
743 "ibmf_saa_impl_send_request() failed",
749 kmem_free(trans_info
, sizeof (saa_impl_trans_info_t
));
751 mutex_enter(&saa_portp
->saa_pt_kstat_mutex
);
753 IBMF_SAA_SUB32_KSTATS(saa_portp
, outstanding_requests
, 1);
754 IBMF_SAA_ADD32_KSTATS(saa_portp
, failed_requests
, 1);
756 if (res
== IBMF_TRANS_TIMEOUT
)
757 IBMF_SAA_ADD32_KSTATS(saa_portp
, requests_timedout
,
760 mutex_exit(&saa_portp
->saa_pt_kstat_mutex
);
766 * if async call don't do anything as callback will take care of
767 * everything; for sync call, copy parameters back to client and free
768 * trans_info structure
770 if (access_args
->sq_callback
== NULL
) {
771 *length
= trans_info
->si_trans_length
;
772 *result
= trans_info
->si_trans_result
;
773 res
= trans_info
->si_trans_status
;
775 mutex_enter(&saa_portp
->saa_pt_kstat_mutex
);
777 IBMF_SAA_SUB32_KSTATS(saa_portp
, outstanding_requests
, 1);
779 if (res
!= IBMF_SUCCESS
)
780 IBMF_SAA_ADD32_KSTATS(saa_portp
, failed_requests
,
783 if (res
== IBMF_TRANS_TIMEOUT
)
784 IBMF_SAA_ADD32_KSTATS(saa_portp
, requests_timedout
,
787 mutex_exit(&saa_portp
->saa_pt_kstat_mutex
);
789 kmem_free(trans_info
, sizeof (saa_impl_trans_info_t
));
794 if (res
!= IBMF_SUCCESS
) {
801 IBMF_TRACE_1(DPRINT_L3
, "ibmf_sa_access() exit: result = 0x%x\n", res
);
808 * Ease of use functions so that the consumer doesn't
809 * have to do the overhead of calling ibmf_sa_access for
810 * commonly used queries
814 * ibmf_saa_gid_to_pathrecords
815 * Given a source gid and a destination gid, return paths
818 * This interface blocks.
821 * ibmf_saa_handle - handle returned from ibmf_sa_session_open()
822 * sgid - source gid of path
823 * dgid - destination gid of path
824 * p_key - partition of path. This value may be wildcarded with
826 * mtu - preferred MTU of the path. This argument may be
827 * wildcarded with IBMF_SAA_MTU_WC.
828 * reversible - if B_TRUE, ibmf will query only reversible paths
829 * see Infiniband Specification table 171
830 * num_paths - maximum number of paths to return
831 * num_paths should be checked for the actual number of
836 * num_paths - actual number of paths returned
837 * length - size of buffer returned
838 * result - pointer to buffer of path records returned in response
841 * Error codes are the same as ibmf_sa_access() return values
843 * Upon successful completion, result points to a buffer containing the records.
844 * length is the size in bytes of the buffer returned in result. If there are
845 * no records or the call failed the length is 0.
847 * The consumer is responsible for freeing the memory associated with result.
851 ibmf_saa_gid_to_pathrecords(ibmf_saa_handle_t ibmf_saa_handle
, ib_gid_t sgid
,
852 ib_gid_t dgid
, ib_pkey_t p_key
, ib_mtu_t mtu
, boolean_t reversible
,
853 uint8_t *num_paths
, uint_t flags
, size_t *length
, sa_path_record_t
**result
)
855 sa_path_record_t path_record
;
858 ibmf_saa_access_args_t access_args
;
860 IBMF_TRACE_0(DPRINT_L4
, "ibmf_saa_gid_to_pathrecords() enter\n");
863 * check num_paths pointer here since we dereference before calling
866 if (num_paths
== NULL
) {
868 IBMF_TRACE_1(DPRINT_L1
, "ibmf_saa_gid_to_pathrecords: %s\n",
869 "invalid argument, NULL pointer argument");
871 IBMF_TRACE_0(DPRINT_L4
,
872 "ibmf_saa_gid_to_pathrecords() exit\n");
879 return (IBMF_INVALID_ARG
);
882 /* check valid handle; in non-debug system ibmf_sa_access() will fail */
883 ASSERT(ibmf_saa_handle
!= NULL
);
885 ASSERT(length
!= NULL
);
886 ASSERT(result
!= NULL
);
891 comp_mask
= SA_PR_COMPMASK_SGID
| SA_PR_COMPMASK_DGID
|
892 SA_PR_COMPMASK_NUMBPATH
;
894 bzero(&path_record
, sizeof (sa_path_record_t
));
896 path_record
.SGID
= sgid
;
897 path_record
.DGID
= dgid
;
898 path_record
.NumbPath
= *num_paths
;
900 if (reversible
== B_TRUE
) {
901 path_record
.Reversible
= 1;
902 comp_mask
|= SA_PR_COMPMASK_REVERSIBLE
;
905 if (p_key
!= IBMF_SAA_PKEY_WC
) {
907 path_record
.P_Key
= p_key
;
908 comp_mask
|= SA_PR_COMPMASK_PKEY
;
912 * gid_to_pathrecords specifies greater than or equal to MTU. Path
913 * records can only do strictly greater. Set the mtu value to one
914 * less than the mtu parameter. If it's the lowest value possible (256)
915 * don't do anything and any path mtu will be allowed.
917 if ((mtu
!= IBMF_SAA_MTU_WC
) && (mtu
> IB_MTU_256
)) {
919 path_record
.MtuSelector
= SA_PR_MTU_SEL_GREATER
;
920 path_record
.Mtu
= (mtu
- 1);
922 comp_mask
|= SA_PR_COMPMASK_MTUSELECTOR
| SA_PR_COMPMASK_MTU
;
925 access_args
.sq_attr_id
= SA_PATHRECORD_ATTRID
;
926 access_args
.sq_access_type
= IBMF_SAA_RETRIEVE
;
927 access_args
.sq_component_mask
= comp_mask
;
928 access_args
.sq_template
= &path_record
;
929 access_args
.sq_callback
= NULL
;
930 access_args
.sq_callback_arg
= NULL
;
932 res
= ibmf_sa_access(ibmf_saa_handle
, &access_args
, 0, length
,
934 if (res
!= IBMF_SUCCESS
) {
936 IBMF_TRACE_2(DPRINT_L2
,
937 "ibmf_saa_gid_to_pathrecords: %s, ibmf_status = %d\n",
938 "ibmf_sa_access() failed",
942 *num_paths
= *length
/ sizeof (sa_path_record_t
);
944 IBMF_TRACE_1(DPRINT_L3
,
945 "ibmf_saa_gid_to_pathrecords() exit: result = 0x%x\n",
952 * ibmf_saa_paths_from_gid
953 * Given a source GID, return a path from the source gid
954 * to every other port on the subnet. It is assumed that the
955 * subnet is fully connected. Only one path per port on the subnet
958 * This interface blocks.
961 * ibmf_saa_handle - handle returned from ibmf_sa_session_open()
962 * sgid - source gid of path
963 * pkey - paritition of path. This value may be wildcarded with
965 * reversible - if B_TRUE, ibmf will query only reversible paths;
966 * see Infiniband Specification table 171
970 * num_paths - number of paths returned
971 * length - size of buffer returned
972 * result - pointer to buffer of path records returned in response
975 * Error codes are the same as ibmf_sa_access() return values
977 * Upon successful completion, result points to a buffer containing the records.
978 * and num_records is the number of path records returned. length is the size
979 * in bytes of the buffer returned in result. If there are no records or the
980 * call failed the length is 0.
982 * The consumer is responsible for freeing the memory associated with result.
986 ibmf_saa_paths_from_gid(ibmf_saa_handle_t ibmf_saa_handle
, ib_gid_t sgid
,
987 ib_pkey_t p_key
, boolean_t reversible
, uint_t flags
, uint_t
*num_paths
,
988 size_t *length
, sa_path_record_t
**result
)
990 sa_path_record_t path_record
;
993 ibmf_saa_access_args_t access_args
;
995 IBMF_TRACE_0(DPRINT_L4
, "ibmf_saa_paths_from_gid() enter\n");
997 /* check valid handle; in non-debug system ibmf_sa_access() will fail */
998 ASSERT(ibmf_saa_handle
!= NULL
);
1000 ASSERT(length
!= NULL
);
1001 ASSERT(result
!= NULL
);
1003 comp_mask
= SA_PR_COMPMASK_SGID
| SA_PR_COMPMASK_NUMBPATH
;
1005 bzero(&path_record
, sizeof (sa_path_record_t
));
1007 path_record
.SGID
= sgid
;
1008 path_record
.NumbPath
= 1;
1010 if (reversible
== B_TRUE
) {
1011 path_record
.Reversible
= 1;
1012 comp_mask
|= SA_PR_COMPMASK_REVERSIBLE
;
1015 if (p_key
!= IBMF_SAA_PKEY_WC
) {
1017 path_record
.P_Key
= p_key
;
1018 comp_mask
|= SA_PR_COMPMASK_PKEY
;
1021 access_args
.sq_attr_id
= SA_PATHRECORD_ATTRID
;
1022 access_args
.sq_access_type
= IBMF_SAA_RETRIEVE
;
1023 access_args
.sq_component_mask
= comp_mask
;
1024 access_args
.sq_template
= &path_record
;
1025 access_args
.sq_callback
= NULL
;
1026 access_args
.sq_callback_arg
= NULL
;
1028 res
= ibmf_sa_access(ibmf_saa_handle
, &access_args
, 0, length
,
1030 if (res
!= IBMF_SUCCESS
) {
1032 IBMF_TRACE_2(DPRINT_L2
,
1033 "ibmf_saa_gid_to_pathrecords: %s, ibmf_status = %d\n",
1034 "ibmf_sa_access() failed",
1038 *num_paths
= *length
/ sizeof (sa_path_record_t
);
1040 IBMF_TRACE_1(DPRINT_L3
,
1041 "ibmf_saa_paths_from_gid() exit: result = 0x%x\n", res
);
1047 * ibmf_saa_name_to_service_record:
1048 * Given a service name, return the service records associated
1051 * This interface blocks.
1054 * ibmf_saa_handle - handle returned from ibmf_sa_session_open()
1055 * name - service name, a null terminated string
1056 * p_key - partition that the service is requested on. This
1057 * value may be wildcarded with IBMF_SAA_PKEY_WC.
1061 * num_records - number of service records returned
1062 * length - size of buffer returned
1063 * result - pointer to buffer of service records returned in
1066 * Error codes are the same as ibmf_sa_access() return values
1068 * Upon successful completion, result points to a buffer containing the records.
1069 * and num_records is the number of service records returned. length is the
1070 * size in bytes of the buffer returned in result. If there are no records or
1071 * the call failed the length is 0.
1073 * The consumer is responsible for freeing the memory associated with result.
1077 ibmf_saa_name_to_service_record(ibmf_saa_handle_t ibmf_saa_handle
,
1078 char *service_name
, ib_pkey_t p_key
, uint_t flags
,
1079 uint_t
*num_records
, size_t *length
, sa_service_record_t
**result
)
1081 sa_service_record_t service_record
;
1083 ibmf_saa_access_args_t access_args
;
1085 IBMF_TRACE_0(DPRINT_L4
, "ibmf_saa_name_to_service_record() enter\n");
1087 /* check valid handle; in non-debug system ibmf_sa_access() will fail */
1088 ASSERT(ibmf_saa_handle
!= NULL
);
1090 ASSERT(num_records
!= NULL
);
1091 ASSERT(length
!= NULL
);
1092 ASSERT(result
!= NULL
);
1094 bzero((void *)&service_record
, sizeof (sa_service_record_t
));
1096 if (strlen(service_name
) >= IB_SVC_NAME_LEN
) {
1098 IBMF_TRACE_2(DPRINT_L1
,
1099 "ibmf_saa_gid_to_pathrecords: %s, service_name = %s\n",
1100 "service name too long",
1103 IBMF_TRACE_0(DPRINT_L4
,
1104 "ibmf_saa_name_to_service_record() exit\n");
1110 return (IBMF_REQ_INVALID
);
1113 /* copy IB_SVC_NAME_LEN bytes, leaving room at end for null char */
1114 (void) strncpy((char *)(service_record
.ServiceName
), service_name
,
1117 if (p_key
!= IBMF_SAA_PKEY_WC
) {
1118 service_record
.ServiceP_Key
= p_key
;
1119 access_args
.sq_component_mask
= SA_SR_COMPMASK_NAME
|
1120 SA_SR_COMPMASK_PKEY
;
1122 access_args
.sq_component_mask
= SA_SR_COMPMASK_NAME
;
1124 access_args
.sq_attr_id
= SA_SERVICERECORD_ATTRID
;
1125 access_args
.sq_access_type
= IBMF_SAA_RETRIEVE
;
1126 access_args
.sq_template
= &service_record
;
1127 access_args
.sq_callback
= NULL
;
1128 access_args
.sq_callback_arg
= NULL
;
1130 res
= ibmf_sa_access(ibmf_saa_handle
, &access_args
, 0, length
,
1132 if (res
!= IBMF_SUCCESS
) {
1134 IBMF_TRACE_2(DPRINT_L2
,
1135 "ibmf_saa_name_to_service_record: %s, ibmf_status = %d\n",
1136 "ibmf_sa_access() failed",
1140 *num_records
= *length
/ sizeof (sa_service_record_t
);
1142 IBMF_TRACE_1(DPRINT_L3
,
1143 "ibmf_saa_name_to_service_record() exit: result = 0x%x\n",
1150 * ibmf_saa_id_to_service_record:
1151 * Given a service id, return the service records associated
1154 * This interface blocks.
1157 * ibmf_saa_handle - handle returned from ibmf_sa_session_open()
1159 * p_key - partition that the service is requested on. This
1160 * value may be wildcarded with IBMF_SAA_PKEY_WC.
1164 * num_records - number of service records returned
1165 * length - size of buffer returned
1166 * result - pointer to buffer of service records returned in
1170 * Error codes are the same as ibmf_sa_access() return values
1172 * Upon successful completion, result points to a buffer containing the records.
1173 * and num_records is the number of service records returned. length is the
1174 * size in bytes of the buffer returned in result. If there are no records or
1175 * the call failed the length is 0.
1177 * The consumer is responsible for freeing the memory associated with result.
1181 ibmf_saa_id_to_service_record(ibmf_saa_handle_t ibmf_saa_handle
,
1182 ib_svc_id_t service_id
, ib_pkey_t p_key
, uint_t flags
, uint_t
*num_records
,
1183 size_t *length
, sa_service_record_t
**result
)
1185 sa_service_record_t service_record
;
1187 ibmf_saa_access_args_t access_args
;
1189 IBMF_TRACE_0(DPRINT_L4
, "ibmf_saa_id_to_service_record() enter\n");
1191 /* check valid handle; in non-debug system ibmf_sa_access() will fail */
1192 ASSERT(ibmf_saa_handle
!= NULL
);
1194 ASSERT(num_records
!= NULL
);
1195 ASSERT(length
!= NULL
);
1196 ASSERT(result
!= NULL
);
1198 bzero((void *)&service_record
, sizeof (sa_service_record_t
));
1200 service_record
.ServiceID
= service_id
;
1202 if (p_key
!= IBMF_SAA_PKEY_WC
) {
1203 service_record
.ServiceP_Key
= p_key
;
1204 access_args
.sq_component_mask
= SA_SR_COMPMASK_ID
|
1205 SA_SR_COMPMASK_PKEY
;
1207 access_args
.sq_component_mask
= SA_SR_COMPMASK_ID
;
1209 access_args
.sq_attr_id
= SA_SERVICERECORD_ATTRID
;
1210 access_args
.sq_access_type
= IBMF_SAA_RETRIEVE
;
1211 access_args
.sq_template
= &service_record
;
1212 access_args
.sq_callback
= NULL
;
1213 access_args
.sq_callback_arg
= NULL
;
1215 res
= ibmf_sa_access(ibmf_saa_handle
, &access_args
, 0, length
,
1217 if (res
!= IBMF_SUCCESS
) {
1219 IBMF_TRACE_2(DPRINT_L2
,
1220 "ibmf_saa_id_to_service_record: %s, ibmf_status = %d\n",
1221 "ibmf_sa_access() failed",
1225 *num_records
= *length
/ sizeof (sa_service_record_t
);
1227 IBMF_TRACE_1(DPRINT_L3
,
1228 "ibmf_saa_id_to_service_record() exit: result = 0x%x\n",
1235 * ibmf_saa_update_service_record
1236 * Given a pointer to a service record, either insert or delete it
1238 * This interface blocks.
1241 * ibmf_saa_handle - handle returned from ibmf_sa_session_open()
1242 * service_record - service record is to be inserted or deleted. To
1243 * delete a service record the GID, ID, P_Key, and
1244 * Service Key must match what is in the SA.
1245 * access_type - indicates whether this is an insertion or deletion.
1246 * valid values are IBMF_SAA_UPDATE or IBMF_SAA_DELETE
1253 * Error codes are the same as ibmf_sa_access() return values
1257 ibmf_saa_update_service_record(ibmf_saa_handle_t ibmf_saa_handle
,
1258 sa_service_record_t
*service_record
, ibmf_saa_access_type_t access_type
,
1265 ibmf_saa_access_args_t access_args
;
1267 IBMF_TRACE_0(DPRINT_L4
, "ibmf_saa_update_service_record() enter\n");
1269 /* check valid handle; in non-debug system ibmf_sa_access() will fail */
1270 ASSERT(ibmf_saa_handle
!= NULL
);
1272 if ((access_type
!= IBMF_SAA_UPDATE
) &&
1273 (access_type
!= IBMF_SAA_DELETE
)) {
1275 IBMF_TRACE_2(DPRINT_L1
,
1276 "ibmf_saa_update_service_record: %s, access_type = 0x%x\n",
1277 "invalid query type",
1280 return (IBMF_REQ_INVALID
);
1284 * call ibmf_sa_access with the following special parameters:
1285 * attrid : service_record
1286 * component_mask : RID fields of service record (GID, ID, and P_key)
1289 comp_mask
= SA_SR_COMPMASK_ID
| SA_SR_COMPMASK_GID
|
1290 SA_SR_COMPMASK_PKEY
| SA_SR_COMPMASK_KEY
;
1292 access_args
.sq_attr_id
= SA_SERVICERECORD_ATTRID
;
1293 access_args
.sq_access_type
= access_type
;
1294 access_args
.sq_component_mask
= comp_mask
;
1295 access_args
.sq_template
= service_record
;
1296 access_args
.sq_callback
= NULL
;
1297 access_args
.sq_callback_arg
= NULL
;
1299 res
= ibmf_sa_access(ibmf_saa_handle
, &access_args
, 0, &length
,
1302 /* if a valid add request, response buffer should be one service rec */
1303 if (res
== IBMF_SUCCESS
&& length
> 0) {
1305 if (length
> sizeof (sa_service_record_t
)) {
1307 IBMF_TRACE_1(DPRINT_L1
,
1308 "ibmf_saa_update_service_record: %s\n",
1309 "SA returned more than one record");
1312 kmem_free(result
, length
);
1315 IBMF_TRACE_1(DPRINT_L3
,
1316 "ibmf_saa_update_service_record() exit: result = 0x%x\n",