Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / ib / mgt / ibmf / ibmf_saa.c
blob1e042247d0ef586357f5372dadfb95e3289fd8ec
1 /*
2 * CDDL HEADER START
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.
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]
20 * CDDL HEADER END
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * ibmf_saa.c
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
43 * has been closed.
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;
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.
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
91 * responses.
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
100 * Output Arguments:
101 * ibmf_sa_handle - pointer to ibmf_saa_handle to be used in future calls
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
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.
133 /* ARGSUSED */
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;
150 goto bail;
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;
159 goto bail;
162 IBMF_TRACE_2(DPRINT_L3,
163 "ibmf_sa_session_open: %s, guid = %016"PRIx64", prefix = %016"PRIx64"\n",
164 "opening session",
165 port_guid);
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) {
181 break;
183 saa_portp = saa_portp->next;
186 if (saa_portp != NULL) {
188 IBMF_TRACE_1(DPRINT_L3, "ibmf_sa_session_open(): %s\n",
189 "port exists\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",
206 status);
208 goto bail;
210 } else {
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",
223 status);
225 goto bail;
228 /* link to list */
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",
255 status);
257 ibmf_saa_impl_register_failed(saa_portp);
259 goto bail;
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",
271 status);
273 ibmf_saa_impl_register_failed(saa_portp);
276 * Note: we don't update kstats as this entry
277 * will eventually go away...
279 goto bail;
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))
297 /* kick waiters */
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",
321 saa_client,
322 saa_portp);
324 saa_client->saa_client_port = saa_portp;
325 mutex_init(&saa_client->saa_client_mutex, NULL, MUTEX_DRIVER,
326 NULL);
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))
345 bail:
346 /* purge invalid entries */
347 ibmf_saa_impl_purge();
349 return (status);
354 * ibmf_sa_session_close()
356 * Unregister a consumer of the SA_Access interface
358 * This interface blocks.
360 * Arguments:
361 * SA_Access handle
363 * Return values:
364 * IBMF_SUCCESS - unregistration succeeded
365 * IBMF_FAILURE - unregistration failed for unknown reasons
367 * All outstanding callbacks will be canceled before this function returns.
370 /* ARGSUSED */
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;
378 uint8_t port_state;
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;
388 goto bail;
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",
398 "bad handle");
400 status = IBMF_BAD_HANDLE;
401 goto bail;
404 saa_portp = client_data->saa_client_port;
406 IBMF_TRACE_1(DPRINT_L3, "ibmf_sa_session_close: saa_portp = %p\n",
407 saa_portp);
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",
440 "done waiting");
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;
478 prev_clientp = NULL;
479 while (curr_clientp != NULL) {
481 if (curr_clientp == client_data) {
483 break;
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",
498 client_data);
499 } else {
501 if (prev_clientp == NULL) {
503 saa_portp->saa_pt_event_sub_client_list =
504 curr_clientp->next;
506 } else
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))
535 /* destroy client */
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;
547 bail:
548 /* purge invalid entries */
549 ibmf_saa_impl_purge();
551 return (status);
555 * ibmf_sa_access
557 * Retrieve records from the SA given an AttributeID, ComponentMask,
558 * and a template
560 * This interface blocks if the callback parameter is NULL.
562 * Input Arguments:
563 * ibmf_saa_handle - handle returned from ibmf_sa_session_open()
564 * access_args - structure containing various parameters for the query
565 * flags - unsused
567 * Output Arguments:
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
572 * Return values:
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
578 * ERR_NO_RESOURCES
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.
598 /* ARGSUSED */
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,
602 void **result)
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;
622 goto bail;
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;
632 goto bail;
635 if (access_args->sq_callback == NULL) {
637 trans_info = kmem_zalloc(sizeof (saa_impl_trans_info_t),
638 KM_SLEEP);
639 } else {
640 trans_info = kmem_zalloc(sizeof (saa_impl_trans_info_t),
641 KM_NOSLEEP);
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;
648 goto bail;
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;
674 goto bail;
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;
690 goto bail;
693 trans_info->si_trans_method = SA_SUBN_ADM_GET_TRACE_TABLE;
694 } else {
696 switch (access_args->sq_access_type) {
698 case IBMF_SAA_RETRIEVE:
699 trans_info->si_trans_method =
700 SA_SUBN_ADM_GET_TABLE;
701 break;
702 case IBMF_SAA_UPDATE:
703 trans_info->si_trans_method = SA_SUBN_ADM_SET;
704 break;
705 case IBMF_SAA_DELETE:
706 trans_info->si_trans_method =
707 SA_SUBN_ADM_DELETE;
708 break;
709 default:
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;
720 goto bail;
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",
744 res);
746 *length = 0;
747 *result = NULL;
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);
762 goto bail;
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));
792 bail:
794 if (res != IBMF_SUCCESS) {
795 if (length != NULL)
796 *length = 0;
797 if (result != NULL)
798 *result = NULL;
801 IBMF_TRACE_1(DPRINT_L3, "ibmf_sa_access() exit: result = 0x%x\n", res);
803 return (res);
807 * Helper Functions.
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
816 * between the gids.
818 * This interface blocks.
820 * Input Arguments:
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
825 * IBMF_SAA_PKEY_WC.
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
832 * records returned.
833 * flags - unused
835 * Output Arguments:
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
840 * Return values:
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.
849 /* ARGSUSED */
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;
856 uint64_t comp_mask;
857 int res;
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
864 * ibmf_sa_access
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");
874 if (length != NULL)
875 *length = 0;
876 if (result != NULL)
877 *result = NULL;
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);
888 *length = 0;
889 *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,
933 (void **)result);
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",
939 res);
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",
946 res);
948 return (res);
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
956 * is returned.
958 * This interface blocks.
960 * Input Arguments:
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
964 * IBMF_SAA_PKEY_WC.
965 * reversible - if B_TRUE, ibmf will query only reversible paths;
966 * see Infiniband Specification table 171
967 * flags - unused
969 * Output Arguments:
970 * num_paths - number of paths returned
971 * length - size of buffer returned
972 * result - pointer to buffer of path records returned in response
974 * Return values:
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.
984 /* ARGSUSED */
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;
991 uint64_t comp_mask;
992 int res;
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,
1029 (void **)result);
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",
1035 res);
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);
1043 return (res);
1047 * ibmf_saa_name_to_service_record:
1048 * Given a service name, return the service records associated
1049 * with it.
1051 * This interface blocks.
1053 * Input Arguments:
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.
1058 * flags - unused
1060 * Output Arguments:
1061 * num_records - number of service records returned
1062 * length - size of buffer returned
1063 * result - pointer to buffer of service records returned in
1064 * response
1065 * Return values:
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.
1075 /* ARGSUSED */
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;
1082 int res;
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",
1101 service_name);
1103 IBMF_TRACE_0(DPRINT_L4,
1104 "ibmf_saa_name_to_service_record() exit\n");
1106 *num_records = 0;
1107 *length = 0;
1108 *result = NULL;
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,
1115 IB_SVC_NAME_LEN-1);
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;
1121 } else
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,
1131 (void *)result);
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",
1137 res);
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",
1144 res);
1146 return (res);
1150 * ibmf_saa_id_to_service_record:
1151 * Given a service id, return the service records associated
1152 * with it.
1154 * This interface blocks.
1156 * Input Arguments:
1157 * ibmf_saa_handle - handle returned from ibmf_sa_session_open()
1158 * id - service id
1159 * p_key - partition that the service is requested on. This
1160 * value may be wildcarded with IBMF_SAA_PKEY_WC.
1161 * flags - unused
1163 * Output Arguments:
1164 * num_records - number of service records returned
1165 * length - size of buffer returned
1166 * result - pointer to buffer of service records returned in
1167 * response
1169 * Return values:
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.
1179 /* ARGSUSED */
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;
1186 int res;
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;
1206 } else
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,
1216 (void **)result);
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",
1222 res);
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",
1229 res);
1231 return (res);
1235 * ibmf_saa_update_service_record
1236 * Given a pointer to a service record, either insert or delete it
1238 * This interface blocks.
1240 * Input Arguments:
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
1247 * flags - unused
1249 * Output Arguments
1250 * none
1252 * Return values:
1253 * Error codes are the same as ibmf_sa_access() return values
1255 /* ARGSUSED */
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,
1259 uint_t flags)
1261 size_t length;
1262 void *result;
1263 int res;
1264 uint64_t comp_mask;
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",
1278 access_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)
1287 * and service 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,
1300 &result);
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",
1317 res);
1319 return (res);