/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * ibtl_hca.c * * This file contains Transport API functions related to * Host Channel Adapter (HCA) Verbs. */ #include static char ibtf_hca[] = "ibtl_hca"; /* Prototype declarations. */ static ibt_status_t ibtl_query_hca_ports(ibtl_hca_devinfo_t *hca_devp, uint8_t port, ibt_hca_portinfo_t **port_info_p, uint_t *ports_p, uint_t *size_p, int use_cache); /* * Function: * ibt_open_hca * Input: * ibt_hdl - IBT Client Handle * hca_guid - HCA's node GUID. * Output: * hca_hdl_p - IBT HCA Handle. * Returns: * IBT_SUCCESS * IBT_HCA_IN_USE * IBT_HCA_INVALID * Description: * Open a HCA. HCA can only be opened/closed once. This routine allocates * and returns a unique IBT Client HCA handle. Clients passes this * handle on its subsequent references to this device. Once opened by a * client, a specific HCA cannot be opened again until after it is closed. * The IBT_HCA_IN_USE error is returned if client tries to open multiple * times. In this case, previously allocated IBT HCA handle is returned to * the client. Opening the HCA prepares the HCA for use by the client. */ ibt_status_t ibt_open_hca(ibt_clnt_hdl_t ibt_hdl, ib_guid_t hca_guid, ibt_hca_hdl_t *hca_hdl_p) { ibtl_hca_t *hca_infop; ibtl_hca_devinfo_t *hca_devp; /* HCA Dev Info */ IBTF_DPRINTF_L3(ibtf_hca, "ibt_open_hca(%p, %llX)", ibt_hdl, hca_guid); /* * Get HCA Device Info Structure, referenced by HCA GUID. */ mutex_enter(&ibtl_clnt_list_mutex); hca_devp = ibtl_get_hcadevinfo(hca_guid); if (hca_devp == NULL) { /* * If we are here, then the requested HCA device is not present. * Return the status as Invalid HCA GUID. */ mutex_exit(&ibtl_clnt_list_mutex); IBTF_DPRINTF_L2(ibtf_hca, "ibt_open_hca: " "HCA Device Not Found: Invalid HCA GUID"); *hca_hdl_p = NULL; return (IBT_HCA_INVALID); } /* * Check whether open is allowed for this dip */ if (ibt_hdl->clnt_dip) { if (ddi_get_parent(ibt_hdl->clnt_dip) == hca_devp->hd_hca_dip) { if (hca_guid != hca_devp->hd_hca_attr->hca_node_guid) { mutex_exit(&ibtl_clnt_list_mutex); return (IBT_FAILURE); } } } if (hca_devp->hd_state != IBTL_HCA_DEV_ATTACHED) { /* * If we are here, then the requested HCA device has detached, * or is in the process of detaching. */ mutex_exit(&ibtl_clnt_list_mutex); IBTF_DPRINTF_L2(ibtf_hca, "ibt_open_hca: " "HCA is busy trying to detach"); *hca_hdl_p = NULL; return (IBT_HCA_BUSY_DETACHING); } /* * Yes, we found a HCA Device registered with IBTF, which matches with * the requested HCA_GUID. * * Check out whether this client has already opened this HCA device, * if yes return the status as IBT_HCA_IN_USE. */ hca_infop = hca_devp->hd_clnt_list; while (hca_infop != NULL) { if (ibt_hdl == hca_infop->ha_clnt_devp) { IBTF_DPRINTF_L3(ibtf_hca, "ibt_open_hca: Already Open"); if (hca_infop->ha_flags & IBTL_HA_CLOSING) { mutex_exit(&ibtl_clnt_list_mutex); *hca_hdl_p = NULL; return (IBT_HCA_BUSY_CLOSING); } mutex_exit(&ibtl_clnt_list_mutex); /* Already Opened. Return back old HCA Handle. */ *hca_hdl_p = hca_infop; return (IBT_HCA_IN_USE); } hca_infop = hca_infop->ha_clnt_link; } /* Create a new HCA Info entity. */ hca_infop = kmem_zalloc(sizeof (ibtl_hca_t), KM_SLEEP); /* Update the HCA Info entity */ hca_infop->ha_hca_devp = hca_devp; /* HCA Device Info */ hca_infop->ha_clnt_devp = ibt_hdl; /* Client Info */ /* Update the HCA List, to keep track about the clients using it. */ hca_infop->ha_clnt_link = hca_devp->hd_clnt_list; hca_devp->hd_clnt_list = hca_infop; /* Update the client's list to depict that it uses this HCA device. */ hca_infop->ha_hca_link = ibt_hdl->clnt_hca_list; ibt_hdl->clnt_hca_list = hca_infop; mutex_exit(&ibtl_clnt_list_mutex); /* * Return back the address of ibtl_hca_t structure as an opaque * IBT HCA handle for the clients, to be used in future calls. */ *hca_hdl_p = hca_infop; return (IBT_SUCCESS); } static char *ibtl_close_error_fmt = "IBT CLOSE HCA failed: %d '%s' " "resources not yet freed by client '%s'\n"; #define IBTL_CLOSE_RESOURCE_CHECK(counter, resource_type) \ if ((cntr = atomic_add_32_nv(&(counter), 0)) != 0) { \ cmn_err(CE_CONT, ibtl_close_error_fmt, \ cntr, resource_type, \ hca_hdl->ha_clnt_devp->clnt_modinfop->mi_clnt_name); \ } \ error |= cntr /* * Function: * ibt_close_hca * Input: * hca_hdl - The HCA handle as returned during its open. * Output: * none * Returns: * IBT_SUCCESS * IBT_HCA_HDL_INVALID * IBT_HCA_RESOURCES_NOT_FREED * Description: * Close a HCA. */ ibt_status_t ibt_close_hca(ibt_hca_hdl_t hca_hdl) { ibtl_hca_devinfo_t *hca_devp, *tmp_devp; ibtl_hca_t **hcapp; ibtl_clnt_t *clntp = hca_hdl->ha_clnt_devp; uint32_t cntr, error; IBTF_DPRINTF_L3(ibtf_hca, "ibt_close_hca(%p)", hca_hdl); /* * Verify the Input HCA Handle, if fake return error as * invalid HCA Handle. */ mutex_enter(&ibtl_clnt_list_mutex); hca_devp = hca_hdl->ha_hca_devp; tmp_devp = ibtl_hca_list; for (; tmp_devp != NULL; tmp_devp = tmp_devp->hd_hca_dev_link) if (tmp_devp == hca_devp) break; if (tmp_devp == NULL) { mutex_exit(&ibtl_clnt_list_mutex); IBTF_DPRINTF_L2(ibtf_hca, "ibt_close_hca: " "Unable to find this on global HCA list"); return (IBT_HCA_HDL_INVALID); } /* Make sure resources have been freed. */ error = 0; IBTL_CLOSE_RESOURCE_CHECK(hca_hdl->ha_qp_cnt, "QP/Channel"); IBTL_CLOSE_RESOURCE_CHECK(hca_hdl->ha_eec_cnt, "EEC"); IBTL_CLOSE_RESOURCE_CHECK(hca_hdl->ha_cq_cnt, "CQ"); IBTL_CLOSE_RESOURCE_CHECK(hca_hdl->ha_pd_cnt, "Protection Domain"); IBTL_CLOSE_RESOURCE_CHECK(hca_hdl->ha_ah_cnt, "AH"); IBTL_CLOSE_RESOURCE_CHECK(hca_hdl->ha_mr_cnt, "Memory Region"); IBTL_CLOSE_RESOURCE_CHECK(hca_hdl->ha_mw_cnt, "Memory Window"); IBTL_CLOSE_RESOURCE_CHECK(hca_hdl->ha_qpn_cnt, "QPN"); IBTL_CLOSE_RESOURCE_CHECK(hca_hdl->ha_srq_cnt, "SRQ"); IBTL_CLOSE_RESOURCE_CHECK(hca_hdl->ha_fmr_pool_cnt, "FMR Pool"); if (error) { mutex_exit(&ibtl_clnt_list_mutex); return (IBT_HCA_RESOURCES_NOT_FREED); } /* we are now committed to closing the HCA */ hca_hdl->ha_flags |= IBTL_HA_CLOSING; while (hca_hdl->ha_qpn_cnt > 0) cv_wait(&ibtl_close_hca_cv, &ibtl_clnt_list_mutex); /* * Remove this HCA Device entry form Client's current list of HCA * Device Instances being used by it. */ hcapp = &clntp->clnt_hca_list; for (; *hcapp != NULL; hcapp = &(*hcapp)->ha_hca_link) if (*hcapp == hca_hdl) break; if (*hcapp == NULL) { IBTF_DPRINTF_L2(ibtf_hca, "ibt_close_hca: " "Unable to find this HCA on client list"); mutex_exit(&ibtl_clnt_list_mutex); return (IBT_HCA_HDL_INVALID); } /* hcapp now points to a link that points to us */ *hcapp = hca_hdl->ha_hca_link; /* remove us */ /* * Remove this Client's entry from this HCA Device's Clients list. */ hcapp = &hca_devp->hd_clnt_list; for (; *hcapp != NULL; hcapp = &(*hcapp)->ha_clnt_link) if (*hcapp == hca_hdl) break; if (*hcapp == NULL) { mutex_exit(&ibtl_clnt_list_mutex); IBTF_DPRINTF_L2(ibtf_hca, "ibt_close_hca: " "Unable to find this HCA on the client's HCA list"); return (IBT_HCA_HDL_INVALID); } /* hcapp now points to a link that points to us */ *hcapp = hca_hdl->ha_clnt_link; /* remove us */ mutex_exit(&ibtl_clnt_list_mutex); /* Free memory for this HCA Handle */ ibtl_free_hca_async_check(hca_hdl); return (IBT_SUCCESS); } void ibtl_close_hca_check(ibt_hca_hdl_t hca_hdl) { IBTF_DPRINTF_L3(ibtf_hca, "ibtl_close_hca_check(%p)", hca_hdl); mutex_enter(&ibtl_clnt_list_mutex); if ((--hca_hdl->ha_qpn_cnt == 0) && (hca_hdl->ha_flags & IBTL_HA_CLOSING)) { cv_signal(&ibtl_close_hca_cv); } mutex_exit(&ibtl_clnt_list_mutex); } /* * Function: * ibt_get_hca_list * Input: * hca_list_p - Address of pointer updated here. * Output: * hca_list_p - Points to an array of ib_guid_t's allocated here. * Returns: * The actual number of valid ib_guid_t's returned. * Description: * If hca_list_p is not NULL then the memory for the array of GUIDs is * allocated here and should be freed by the caller using * ibt_free_hca_list(). If hca_list_p is NULL then no memory is allocated * by ibt_get_hca_list and only the number of HCAs in a system is returned. */ uint_t ibt_get_hca_list(ib_guid_t **hca_list_p) { uint_t hca_count = 0; ibtl_hca_devinfo_t *hca_devp; ib_guid_t *hca_listp; IBTF_DPRINTF_L3(ibtf_hca, "ibt_get_hca_list(%p)", hca_list_p); mutex_enter(&ibtl_clnt_list_mutex); hca_devp = ibtl_hca_list; while (hca_devp != NULL) { hca_count++; hca_devp = hca_devp->hd_hca_dev_link; } if (hca_count == 0) IBTF_DPRINTF_L2(ibtf_hca, "ibt_get_hca_list: " "HCA device not found"); if ((hca_count == 0) || (hca_list_p == NULL)) { mutex_exit(&ibtl_clnt_list_mutex); return (hca_count); } hca_listp = kmem_alloc(hca_count * sizeof (ib_guid_t), KM_SLEEP); *hca_list_p = hca_listp; hca_devp = ibtl_hca_list; while (hca_devp != NULL) { /* Traverse Global HCA List & retrieve HCA Node GUIDs. */ *hca_listp++ = hca_devp->hd_hca_attr->hca_node_guid; hca_devp = hca_devp->hd_hca_dev_link; } mutex_exit(&ibtl_clnt_list_mutex); IBTF_DPRINTF_L3(ibtf_hca, "ibt_get_hca_list: " "Returned <%d> entries @0x%p", hca_count, *hca_list_p); return (hca_count); } /* * Function: * ibt_free_hca_list * Input: * hca_list - The address of an ib_guid_t pointer. * entries - The number of ib_guid_t entries to be freed. * Output: * none. * Returns: * none. * Description: * The memory allocated in ibt_get_hca_list() is freed in this function. */ void ibt_free_hca_list(ib_guid_t *hca_list, uint_t entries) { IBTF_DPRINTF_L3(ibtf_hca, "ibt_free_hca_list: " "Free <%d> entries from 0x%p", entries, hca_list); if ((hca_list != NULL) && (entries > 0)) kmem_free(hca_list, entries * sizeof (ib_guid_t)); } /* * ibtl_portinfo_locked() is called when the portinfo cache is being * updated. If this port's info update is in progress, we return 0 * immediately and have the c * unless it's already in progress (distinguished by return value). * When done updating the portinfo, they call ibtl_portinfo_unlock(). */ static int ibtl_portinfo_locked(ibtl_hca_devinfo_t *hca_devp, uint8_t port) { ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex)); for (;;) { if (hca_devp->hd_portinfo_locked_port == 0) { hca_devp->hd_portinfo_locked_port = port; return (1); /* not busy, so OK to initiate update */ } else if (hca_devp->hd_portinfo_locked_port == port) { IBTF_DPRINTF_L3(ibtf_hca, "ibtl_portinfo_locked: " "HCA %p port %d is already locked", hca_devp, port); hca_devp->hd_portinfo_waiters = 1; cv_wait(&hca_devp->hd_portinfo_cv, &ibtl_clnt_list_mutex); return (0); /* it's now done, so no need to initiate */ } else { /* need to wait for other port before we try again */ hca_devp->hd_portinfo_waiters = 1; cv_wait(&hca_devp->hd_portinfo_cv, &ibtl_clnt_list_mutex); } } } static void ibtl_portinfo_unlock(ibtl_hca_devinfo_t *hca_devp, uint8_t port) { ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex)); ASSERT(hca_devp->hd_portinfo_locked_port == port); hca_devp->hd_portinfo_locked_port = 0; if (hca_devp->hd_portinfo_waiters) { hca_devp->hd_portinfo_waiters = 0; cv_broadcast(&hca_devp->hd_portinfo_cv); IBTF_DPRINTF_L3(ibtf_hca, "ibtl_portinfo_unlock: " "waking up waiters for port %d info on HCA %p", port, hca_devp); } } /* * Function: * ibt_get_port_state * Input: * hca_devp - The HCA Dev Info pointer. * port - Port number to query. * Output: * sgid_p - Returned sgid[0], NULL implies no return value. * base_lid_p - Returned base_lid, NULL implies no return value. * Returns: * IBT_SUCCESS * IBT_HCA_PORT_INVALID * Description: * Returns HCA port attributes for one of the HCA ports. */ static ibt_status_t ibtl_get_port_state(ibtl_hca_devinfo_t *hca_devp, uint8_t port, ib_gid_t *sgid_p, ib_lid_t *base_lid_p) { ibt_hca_portinfo_t *portinfop; ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex)); if ((port < 1) || (port > hca_devp->hd_hca_attr->hca_nports)) { IBTF_DPRINTF_L2(ibtf_hca, "ibtl_get_port_state: " "invalid port %d, nports = %d", port, hca_devp->hd_hca_attr->hca_nports); return (IBT_HCA_PORT_INVALID); } portinfop = hca_devp->hd_portinfop + port - 1; if (portinfop->p_linkstate != IBT_PORT_ACTIVE) ibtl_reinit_hca_portinfo(hca_devp, port); if (sgid_p) *sgid_p = portinfop->p_sgid_tbl[0]; if (base_lid_p) *base_lid_p = portinfop->p_base_lid; if (portinfop->p_linkstate != IBT_PORT_ACTIVE) { IBTF_DPRINTF_L2(ibtf_hca, "ibtl_get_port_state: " "port %d, port_state %d, base_lid %d", port, portinfop->p_linkstate, portinfop->p_base_lid); return (IBT_HCA_PORT_NOT_ACTIVE); } IBTF_DPRINTF_L3(ibtf_hca, "ibtl_get_port_state: " "port %d, port_state %d, base_lid %d", port, portinfop->p_linkstate, portinfop->p_base_lid); return (IBT_SUCCESS); } /* * Function: * ibt_get_port_state * Input: * hca_hdl - The HCA handle. * port - Port number to query. * Output: * sgid_p - Returned sgid[0], NULL implies no return value. * base_lid_p - Returned base_lid, NULL implies no return value. * Returns: * IBT_SUCCESS * IBT_HCA_PORT_INVALID * Description: * Returns HCA port attributes for one of the HCA ports. */ ibt_status_t ibt_get_port_state(ibt_hca_hdl_t hca_hdl, uint8_t port, ib_gid_t *sgid_p, ib_lid_t *base_lid_p) { ibt_status_t retval; IBTF_DPRINTF_L3(ibtf_hca, "ibt_get_port_state(%p, %d, %p, %p)", hca_hdl, port, sgid_p, base_lid_p); mutex_enter(&ibtl_clnt_list_mutex); retval = ibtl_get_port_state(hca_hdl->ha_hca_devp, port, sgid_p, base_lid_p); mutex_exit(&ibtl_clnt_list_mutex); return (retval); } /* * Function: * ibt_get_port_state_byguid * Input: * hca_guid - The HCA node GUID. * port - Port number to query. * Output: * sgid_p - Returned sgid[0], NULL implies no return value. * base_lid_p - Returned base_lid, NULL implies no return value. * Returns: * IBT_SUCCESS * IBT_HCA_PORT_INVALID * IBT_HCA_INVALID * Description: * Returns HCA port attributes for one of the HCA ports. */ ibt_status_t ibt_get_port_state_byguid(ib_guid_t hca_guid, uint8_t port, ib_gid_t *sgid_p, ib_lid_t *base_lid_p) { ibtl_hca_devinfo_t *hca_devp; /* HCA Dev Info */ ibt_status_t retval; IBTF_DPRINTF_L3(ibtf_hca, "ibt_get_port_state_byguid(%llx, %d, %p, " "%p)", (longlong_t)hca_guid, port, sgid_p, base_lid_p); mutex_enter(&ibtl_clnt_list_mutex); hca_devp = ibtl_get_hcadevinfo(hca_guid); if (hca_devp == NULL) retval = IBT_HCA_INVALID; else retval = ibtl_get_port_state(hca_devp, port, sgid_p, base_lid_p); mutex_exit(&ibtl_clnt_list_mutex); return (retval); } /* * Function: * ibt_query_hca_byguid * Input: * hca_guid - The HCA node GUID. * Output: * hca_attrs - A pointer to a ibt_hca_attr_t allocated by the caller, * into which the HCA Attributes are copied. * Returns: * IBT_SUCCESS * IBT_INVALID_PARAM * IBT_HCA_INVALID * Description: * Returns the static attributes of the specified HCA. */ ibt_status_t ibt_query_hca_byguid(ib_guid_t hca_guid, ibt_hca_attr_t *hca_attrs) { ibtl_hca_devinfo_t *hca_devp; /* HCA Dev Info. */ IBTF_DPRINTF_L3(ibtf_hca, "ibt_query_hca_byguid(%llX)", hca_guid); mutex_enter(&ibtl_clnt_list_mutex); /* Get HCA Dev Info Structure, referenced by HCA GUID. */ hca_devp = ibtl_get_hcadevinfo(hca_guid); if (hca_devp == NULL) { /* * If we are here, then the requested HCA device is not present. */ mutex_exit(&ibtl_clnt_list_mutex); IBTF_DPRINTF_L2(ibtf_hca, "ibt_query_hca_byguid: " "Device Not Found"); return (IBT_HCA_INVALID); } /* Return back the static HCA attributes */ bcopy(hca_devp->hd_hca_attr, hca_attrs, sizeof (ibt_hca_attr_t)); mutex_exit(&ibtl_clnt_list_mutex); return (IBT_SUCCESS); } /* * Function: * ibt_query_hca * Input: * hca_hdl - The HCA handle. * Output: * hca_attrs - A pointer to a ibt_hca_attr_t allocated by the caller, * into which the HCA Attributes are copied. * Returns: * IBT_SUCCESS * * Description: * Returns the static attributes of the specified HCA. */ ibt_status_t ibt_query_hca(ibt_hca_hdl_t hca_hdl, ibt_hca_attr_t *hca_attrs) { IBTF_DPRINTF_L3(ibtf_hca, "ibt_query_hca(%p)", hca_hdl); /* Return back the static HCA attributes */ bcopy(hca_hdl->ha_hca_devp->hd_hca_attr, hca_attrs, sizeof (ibt_hca_attr_t)); return (IBT_SUCCESS); } #define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) /* * Function: * ibt_query_hca_ports * Input: * hca_hdl - The HCA handle. * port - Port number. If "0", then query ALL Ports. * Output: * port_info_p - The address of a pointer to a ibt_hca_portinfo_t struct. * ports_p - The number of hca ports on the specified HCA. * size_p - Size of the memory allocated by IBTL to get portinfo, * to be freed by calling ibt_free_portinfo(). * Returns: * IBT_SUCCESS * IBT_HCA_HDL_INVALID * IBT_HCA_INVALID * Description: * Returns HCA port attributes for either "one", or "all" of the HCA ports. */ ibt_status_t ibt_query_hca_ports(ibt_hca_hdl_t hca_hdl, uint8_t port, ibt_hca_portinfo_t **port_info_p, uint_t *ports_p, uint_t *size_p) { ibt_status_t retval; IBTF_DPRINTF_L3(ibtf_hca, "ibt_query_hca_ports(%p, %d)", hca_hdl, port); mutex_enter(&ibtl_clnt_list_mutex); retval = ibtl_query_hca_ports(hca_hdl->ha_hca_devp, port, port_info_p, ports_p, size_p, 0); mutex_exit(&ibtl_clnt_list_mutex); return (retval); } /* * Function: * ibt_query_hca_ports_byguid * Input: * hca_guid - The HCA node GUID. * port - Port number. If "0", then query ALL Ports. * Output: * port_info_p - The address of a pointer to a ibt_hca_portinfo_t struct. * ports_p - The number of hca ports on the specified HCA. * size_p - Size of the memory allocated by IBTL to get portinfo, * to be freed by calling ibt_free_portinfo(). * Returns: * IBT_SUCCESS * IBT_HCA_HDL_INVALID * IBT_HCA_INVALID * Description: * Returns HCA port attributes for either "one", or "all" of the HCA ports. */ ibt_status_t ibt_query_hca_ports_byguid(ib_guid_t hca_guid, uint8_t port, ibt_hca_portinfo_t **port_info_p, uint_t *ports_p, uint_t *size_p) { ibtl_hca_devinfo_t *hca_devp; /* HCA Dev Info */ ibt_status_t retval; mutex_enter(&ibtl_clnt_list_mutex); hca_devp = ibtl_get_hcadevinfo(hca_guid); if (hca_devp == NULL) { /* * If we are here, then the requested HCA device is not present. * Return the status as Invalid HCA GUID. */ *ports_p = *size_p = 0; *port_info_p = NULL; mutex_exit(&ibtl_clnt_list_mutex); IBTF_DPRINTF_L2(ibtf_hca, "ibt_query_hca_ports_byguid: " "HCA Device Not Found. "); return (IBT_HCA_INVALID); } retval = ibtl_query_hca_ports(hca_devp, port, port_info_p, ports_p, size_p, 0); mutex_exit(&ibtl_clnt_list_mutex); return (retval); } /* * Define the above function for CM's use that uses the cached copy. */ ibt_status_t ibtl_cm_query_hca_ports_byguid(ib_guid_t hca_guid, uint8_t port, ibt_hca_portinfo_t **port_info_p, uint_t *ports_p, uint_t *size_p) { ibtl_hca_devinfo_t *hca_devp; /* HCA Dev Info */ ibt_status_t retval; mutex_enter(&ibtl_clnt_list_mutex); hca_devp = ibtl_get_hcadevinfo(hca_guid); if (hca_devp == NULL) { /* * If we are here, then the requested HCA device is not present. * Return the status as Invalid HCA GUID. */ *ports_p = *size_p = 0; *port_info_p = NULL; mutex_exit(&ibtl_clnt_list_mutex); IBTF_DPRINTF_L2(ibtf_hca, "ibt_query_hca_ports_byguid: " "HCA Device Not Found. "); return (IBT_HCA_INVALID); } retval = ibtl_query_hca_ports(hca_devp, port, port_info_p, ports_p, size_p, 1); mutex_exit(&ibtl_clnt_list_mutex); return (retval); } /* * ibtl_query_one_port - fill in portinfo for one port. */ static ibt_status_t ibtl_query_one_port(ibtl_hca_devinfo_t *hca_devp, uint8_t port, ibt_hca_portinfo_t **port_info_p, uint_t *ports_p, uint_t *size_p, int use_cache) { ibt_hca_portinfo_t *sp1; /* src */ ibt_hca_portinfo_t *p1; /* dst */ caddr_t p2; uint_t len; uint_t sgid_tbl_len, pkey_tbl_len; ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex)); IBTF_DPRINTF_L3(ibtf_hca, "ibtl_query_one_port(%p, %d)", hca_devp, port); if (port > hca_devp->hd_hca_attr->hca_nports) { IBTF_DPRINTF_L2(ibtf_hca, "ibtl_query_one_port: " "invalid port %d", port); return (IBT_HCA_PORT_INVALID); } /* If the PORT_UP event is not supported, we need to query */ sp1 = hca_devp->hd_portinfop + port - 1; if (use_cache == 0) ibtl_reinit_hca_portinfo(hca_devp, port); *ports_p = 1; /* * Calculate how much memory we need for one port, and allocate it. */ sgid_tbl_len = ROUNDUP(sp1->p_sgid_tbl_sz * sizeof (ib_gid_t), _LONG_LONG_ALIGNMENT); pkey_tbl_len = ROUNDUP(sp1->p_pkey_tbl_sz * sizeof (ib_pkey_t), _LONG_LONG_ALIGNMENT); len = sizeof (ibt_hca_portinfo_t) + sgid_tbl_len + pkey_tbl_len; *size_p = len; p1 = kmem_zalloc(len, KM_SLEEP); *port_info_p = p1; bcopy(sp1, p1, sizeof (ibt_hca_portinfo_t)); /* initialize the p_pkey_tbl & p_sgid_tbl pointers. */ p2 = (caddr_t)(p1 + 1); /* pkeys follow the struct ibt_hca_portinfo_s */ bcopy(sp1->p_pkey_tbl, p2, pkey_tbl_len); p1->p_pkey_tbl = (ib_pkey_t *)p2; p2 += pkey_tbl_len; /* sgids follow the pkeys */ bcopy(sp1->p_sgid_tbl, p2, sgid_tbl_len); p1->p_sgid_tbl = (ib_gid_t *)p2; return (IBT_SUCCESS); } /* * ibtl_query_hca_ports - worker routine to get port_info for clients. */ static ibt_status_t ibtl_query_hca_ports(ibtl_hca_devinfo_t *hca_devp, uint8_t port, ibt_hca_portinfo_t **port_info_p, uint_t *ports_p, uint_t *size_p, int use_cache) { ibt_hca_portinfo_t *sp1; /* src */ ibt_hca_portinfo_t *p1; /* dst */ uint_t i, nports; caddr_t p2; uint_t len; uint_t sgid_tbl_len, pkey_tbl_len; ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex)); /* * If user has specified the port num, then query only that port, * else query all ports. */ if (port) return (ibtl_query_one_port(hca_devp, port, port_info_p, ports_p, size_p, use_cache)); IBTF_DPRINTF_L3(ibtf_hca, "ibtl_query_hca_ports(%p, ALL)", hca_devp); nports = hca_devp->hd_hca_attr->hca_nports; *ports_p = nports; /* If the PORT_UP event is not supported, we need to query */ if (use_cache == 0) for (i = 0; i < nports; i++) ibtl_reinit_hca_portinfo(hca_devp, i + 1); sp1 = hca_devp->hd_portinfop; /* * Calculate how much memory we need for all ports, and allocate it. */ sgid_tbl_len = ROUNDUP(sp1->p_sgid_tbl_sz * sizeof (ib_gid_t), _LONG_LONG_ALIGNMENT); pkey_tbl_len = ROUNDUP(sp1->p_pkey_tbl_sz * sizeof (ib_pkey_t), _LONG_LONG_ALIGNMENT); len = (sizeof (ibt_hca_portinfo_t) + sgid_tbl_len + pkey_tbl_len) * nports; *size_p = len; ASSERT(len == hca_devp->hd_portinfo_len); p1 = kmem_zalloc(len, KM_SLEEP); *port_info_p = p1; bcopy(sp1, p1, len); /* start with an exact copy of our cache */ p2 = (caddr_t)(p1 + nports); /* For each port, update the p_pkey_tbl & p_sgid_tbl ptrs. */ for (i = 0; i < nports; i++) { p1->p_pkey_tbl = (ib_pkey_t *)p2; p2 += pkey_tbl_len; p1->p_sgid_tbl = (ib_gid_t *)p2; p2 += sgid_tbl_len; p1++; } return (IBT_SUCCESS); } /* * Search for a Full pkey. Use the pkey at index 0 if not found. */ static void ibtl_set_default_pkey_ix(ibt_hca_portinfo_t *p1) { uint16_t pkey_ix; for (pkey_ix = 0; pkey_ix < p1->p_pkey_tbl_sz; pkey_ix++) { if ((p1->p_pkey_tbl[pkey_ix] & 0x8000) && (p1->p_pkey_tbl[pkey_ix] != IB_PKEY_INVALID_FULL)) { p1->p_def_pkey_ix = pkey_ix; IBTF_DPRINTF_L3(ibtf_hca, "ibtl_set_default_pkey_ix: portinfop %p, " "FULL PKEY 0x%x found, pkey_ix is %d", p1, p1->p_pkey_tbl[pkey_ix], pkey_ix); return; } } IBTF_DPRINTF_L2(ibtf_hca, "ibtl_set_default_pkey_ix: portinfop %p: failed " "to find a default PKEY in the table, using PKey 0x%x", p1, p1->p_pkey_tbl[0]); p1->p_def_pkey_ix = 0; } /* * ibtl_reinit_hca_portinfo - update the portinfo cache for use by IBTL. * * We have the HCA driver fill in a temporary portinfo, then we bcopy * it into our cache while holding the appropriate lock. */ void ibtl_reinit_hca_portinfo(ibtl_hca_devinfo_t *hca_devp, uint8_t port) { ibt_status_t status; ibt_hca_portinfo_t *p1, *sp1; ibt_port_state_t old_linkstate; uint_t len, sgid_tbl_len, pkey_tbl_len; ib_pkey_t *saved_pkey_tbl; ib_gid_t *saved_sgid_tbl; ib_sn_prefix_t sn_pfx = 0; uint_t multiSM; int i; IBTF_DPRINTF_L3(ibtf_hca, "ibtl_reinit_hca_portinfo(%p, %d)", hca_devp, port); ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex)); ASSERT(port != 0); if (ibtl_portinfo_locked(hca_devp, port)) { /* we got the lock, so we need to do the portinfo update */ /* invalidate fast_gid_cache */ ibtl_fast_gid_cache_valid = B_FALSE; p1 = hca_devp->hd_portinfop + port - 1; sgid_tbl_len = ROUNDUP(p1->p_sgid_tbl_sz * sizeof (ib_gid_t), _LONG_LONG_ALIGNMENT); pkey_tbl_len = ROUNDUP(p1->p_pkey_tbl_sz * sizeof (ib_pkey_t), _LONG_LONG_ALIGNMENT); len = sizeof (ibt_hca_portinfo_t) + sgid_tbl_len + pkey_tbl_len; /* update was NOT in progress, so we do it here */ mutex_exit(&ibtl_clnt_list_mutex); IBTF_DPRINTF_L3(ibtf_hca, "ibtl_reinit_hca_portinfo(%p, %d): " "calling ibc_query_hca_ports", hca_devp, port); sp1 = kmem_zalloc(len, KM_SLEEP); sp1->p_pkey_tbl = (ib_pkey_t *)(sp1 + 1); sp1->p_sgid_tbl = (ib_gid_t *)((caddr_t)sp1->p_pkey_tbl + pkey_tbl_len); status = IBTL_HDIP2CIHCAOPS_P(hca_devp)->ibc_query_hca_ports( IBTL_HDIP2CIHCA(hca_devp), port, sp1); mutex_enter(&ibtl_clnt_list_mutex); if (status != IBT_SUCCESS) { IBTF_DPRINTF_L2(ibtf_hca, "ibtl_reinit_hca_portinfo(%p, %d): " "ibc_query_hca_ports() failed: status = %d", hca_devp, port, status); } else { old_linkstate = p1->p_linkstate; bcopy(sp1->p_pkey_tbl, p1->p_pkey_tbl, pkey_tbl_len); bcopy(sp1->p_sgid_tbl, p1->p_sgid_tbl, sgid_tbl_len); saved_pkey_tbl = p1->p_pkey_tbl; saved_sgid_tbl = p1->p_sgid_tbl; bcopy(sp1, p1, sizeof (ibt_hca_portinfo_t)); p1->p_pkey_tbl = saved_pkey_tbl; p1->p_sgid_tbl = saved_sgid_tbl; if (p1->p_linkstate == IBT_PORT_ACTIVE) { ibtl_set_default_pkey_ix(p1); if (p1->p_linkstate != old_linkstate) IBTF_DPRINTF_L2(ibtf_hca, "ibtl_reinit_hca_portinfo(%p, %d): " "PORT UP", hca_devp, port); } else { if (p1->p_linkstate != IBT_PORT_ARM) p1->p_base_lid = 0; if (p1->p_linkstate != old_linkstate) IBTF_DPRINTF_L2(ibtf_hca, "ibtl_reinit_hca_portinfo(%p, %d): " "PORT DOWN", hca_devp, port); } } kmem_free(sp1, len); /* Set multism bit accordingly. */ multiSM = 0; p1 = hca_devp->hd_portinfop; for (i = 0; i < hca_devp->hd_hca_attr->hca_nports; i++) { if (p1->p_linkstate == IBT_PORT_ACTIVE) { if (sn_pfx == 0) { sn_pfx = p1->p_sgid_tbl[0].gid_prefix; } else if (sn_pfx != p1->p_sgid_tbl[0].gid_prefix) { multiSM = 1; IBTF_DPRINTF_L3(ibtf_hca, "ibtl_reinit_hca_portinfo: " "MULTI SM, Port1 SnPfx=0x%llX, " "Port2 SnPfx=0x%llX", sn_pfx, p1->p_sgid_tbl[0].gid_prefix); } } p1++; } hca_devp->hd_multism = multiSM; ibtl_portinfo_unlock(hca_devp, port); } } /* * ibtl_init_hca_portinfo - fill in the portinfo cache for use by IBTL. */ ibt_status_t ibtl_init_hca_portinfo(ibtl_hca_devinfo_t *hca_devp) { ibt_hca_portinfo_t *p1; ibt_status_t retval; uint_t i, nports; caddr_t p2; uint_t len; uint_t sgid_tbl_len, pkey_tbl_len; uint_t sgid_tbl_sz, pkey_tbl_sz; ib_sn_prefix_t sn_pfx = 0; uint_t multiSM; IBTF_DPRINTF_L2(ibtf_hca, "ibtl_init_hca_portinfo(%p)", hca_devp); ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex)); nports = hca_devp->hd_hca_attr->hca_nports; /* * Calculate how much memory we need for all ports, and allocate it. */ pkey_tbl_sz = IBTL_HDIP2PKEYTBLSZ(hca_devp); sgid_tbl_sz = IBTL_HDIP2SGIDTBLSZ(hca_devp); pkey_tbl_len = ROUNDUP(pkey_tbl_sz * sizeof (ib_pkey_t), _LONG_LONG_ALIGNMENT); sgid_tbl_len = ROUNDUP(sgid_tbl_sz * sizeof (ib_gid_t), _LONG_LONG_ALIGNMENT); len = (sizeof (ibt_hca_portinfo_t) + sgid_tbl_len + pkey_tbl_len) * nports; p1 = kmem_zalloc(len, KM_SLEEP); p2 = (caddr_t)(p1 + nports); hca_devp->hd_portinfop = p1; hca_devp->hd_portinfo_len = len; /* For each port initialize the p_pkey_tbl & p_sgid_tbl ptrs. */ for (i = 0; i < nports; i++) { p1->p_pkey_tbl_sz = pkey_tbl_sz; p1->p_sgid_tbl_sz = sgid_tbl_sz; p1->p_pkey_tbl = (ib_pkey_t *)p2; p2 += pkey_tbl_len; p1->p_sgid_tbl = (ib_gid_t *)p2; p2 += sgid_tbl_len; p1++; } p1 = hca_devp->hd_portinfop; mutex_exit(&ibtl_clnt_list_mutex); /* re-direct the call to CI's call */ retval = IBTL_HDIP2CIHCAOPS_P(hca_devp)->ibc_query_hca_ports( IBTL_HDIP2CIHCA(hca_devp), 0, p1); mutex_enter(&ibtl_clnt_list_mutex); if (retval != IBT_SUCCESS) { IBTF_DPRINTF_L2(ibtf_hca, "ibtl_init_hca_portinfo(%p): " "ibc_query_hca_ports() failed: status = %d", hca_devp, retval); kmem_free(hca_devp->hd_portinfop, len); hca_devp->hd_portinfop = NULL; hca_devp->hd_portinfo_len = 0; return (retval); } p1 = hca_devp->hd_portinfop; multiSM = 0; for (i = 0; i < nports; i++) { if (p1->p_linkstate == IBT_PORT_ACTIVE) { ibtl_set_default_pkey_ix(p1); if (sn_pfx == 0) { sn_pfx = p1->p_sgid_tbl[0].gid_prefix; } else if (p1->p_sgid_tbl[0].gid_prefix != sn_pfx) { multiSM = 1; IBTF_DPRINTF_L3(ibtf_hca, "ibtl_init_hca_portinfo: MULTI SM, " "Port1 SnPfx=0x%llX, Port2 SnPfx=0x%llX", sn_pfx, p1->p_sgid_tbl[0].gid_prefix); } } else { if (p1->p_linkstate != IBT_PORT_ARM) p1->p_base_lid = 0; } p1++; } hca_devp->hd_multism = multiSM; return (IBT_SUCCESS); } /* * Function: * ibt_modify_system_image * Input: * hca_hdl - The HCA handle. * sys_guid - The New system image GUID. * Description: * Modify specified HCA's system image GUID. */ ibt_status_t ibt_modify_system_image(ibt_hca_hdl_t hca_hdl, ib_guid_t sys_guid) { ibt_status_t retval; IBTF_DPRINTF_L3(ibtf_hca, "ibt_modify_system_image(%p, %llX)", hca_hdl, sys_guid); mutex_enter(&ibtl_clnt_list_mutex); /* Get HCA Dev Info Structure, referenced by HCA GUID. */ /* re-direct the call to CI's call */ retval = IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_modify_system_image( IBTL_HCA2CIHCA(hca_hdl), sys_guid); mutex_exit(&ibtl_clnt_list_mutex); return (retval); } /* * Function: * ibt_modify_system_image_byguid * * Input: * hca_guid - The HCA Node GUID. * sys_guid - The New system image GUID. * Description: * Modify specified HCA's system image GUID. */ ibt_status_t ibt_modify_system_image_byguid(ib_guid_t hca_guid, ib_guid_t sys_guid) { ibtl_hca_devinfo_t *hca_devp; /* HCA Dev Info. */ ibt_status_t retval; IBTF_DPRINTF_L3(ibtf_hca, "ibt_modify_system_image_byguid(%llX, %llX)", hca_guid, sys_guid); mutex_enter(&ibtl_clnt_list_mutex); /* Get HCA Dev Info Structure, referenced by HCA GUID. */ hca_devp = ibtl_get_hcadevinfo(hca_guid); if (hca_devp == NULL) { /* * If we are here, then the requested HCA device is not present. */ mutex_exit(&ibtl_clnt_list_mutex); return (IBT_HCA_INVALID); } /* re-direct the call to CI's call */ retval = IBTL_HDIP2CIHCAOPS_P(hca_devp)->ibc_modify_system_image( IBTL_HDIP2CIHCA(hca_devp), sys_guid); mutex_exit(&ibtl_clnt_list_mutex); return (retval); } /* * Function: * ibt_modify_port_byguid * Input: * hca_guid - The HCA Guid. * cmds - A pointer to an array of ibt_port_modify_t cmds. The * pmod_port field specifies the port to modify (all ports if 0) * and the pmod_flags field specifies which attribute to reset. * num_cmds - The number of commands in the cmds array. * Output: * none. * Returns: * IBT_SUCCESS * IBT_HCA_HDL_INVALID * IBT_HCA_CNTR_INVALID * IBT_HCA_CNTR_VAL_INVALID * Description: * Reset the specified port, or all ports attribute(s). */ ibt_status_t ibt_modify_port_byguid(ib_guid_t hca_guid, uint8_t port, ibt_port_modify_flags_t flags, uint8_t init_type) { ibtl_hca_devinfo_t *hca_devp; /* HCA Dev Info. */ ibt_status_t retval; IBTF_DPRINTF_L3(ibtf_hca, "ibt_modify_port_byguid(%llX, %d, %X, %X)", hca_guid, port, flags, init_type); mutex_enter(&ibtl_clnt_list_mutex); /* Get HCA Dev Info Structure, referenced by HCA GUID. */ hca_devp = ibtl_get_hcadevinfo(hca_guid); if (hca_devp == NULL) { /* * If we are here, then the requested HCA device is not present. */ mutex_exit(&ibtl_clnt_list_mutex); return (IBT_HCA_INVALID); } /* re-direct the call to CI's call */ retval = IBTL_HDIP2CIHCAOPS_P(hca_devp)->ibc_modify_ports( IBTL_HDIP2CIHCA(hca_devp), port, flags, init_type); mutex_exit(&ibtl_clnt_list_mutex); return (retval); } /* * Function: * ibt_modify_port * Input: * hca_hdl - The HCA handle. * cmds - A pointer to an array of ibt_port_modify_t cmds. The * pmod_port field specifies the port to modify (all ports if 0) * and the pmod_flags field specifies which attribute to reset. * num_cmds - The number of commands in the cmds array. * Output: * none. * Returns: * IBT_SUCCESS * IBT_HCA_HDL_INVALID * IBT_HCA_CNTR_INVALID * IBT_HCA_CNTR_VAL_INVALID * Description: * Reset the specified port, or all ports attribute(s). */ ibt_status_t ibt_modify_port(ibt_hca_hdl_t hca_hdl, uint8_t port, ibt_port_modify_flags_t flags, uint8_t init_type) { ibt_status_t retval; IBTF_DPRINTF_L3(ibtf_hca, "ibt_modify_port(%p, %d, %X, %X)", hca_hdl, port, flags, init_type); mutex_enter(&ibtl_clnt_list_mutex); /* re-direct the call to CI's call */ retval = IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_modify_ports( IBTL_HCA2CIHCA(hca_hdl), port, flags, init_type); mutex_exit(&ibtl_clnt_list_mutex); return (retval); } /* * Function: * ibt_free_portinfo * Input: * port_info - The address of an array to a ibt_hca_portinfo_t struct. * size - Memory Size as returned from ibt_query_hca_ports(). * Output: * none * Returns: * none * Description: * Frees the memory allocated for a specified ibt_hca_portinfo_t struct. */ void ibt_free_portinfo(ibt_hca_portinfo_t *port_info, uint_t size) { IBTF_DPRINTF_L3(ibtf_hca, "ibt_free_portinfo(%p, %d)", port_info, size); if ((port_info == NULL) || (size == 0)) { IBTF_DPRINTF_L2(ibtf_hca, "ibt_free_portinfo: NULL Pointer"); } else { kmem_free(port_info, size); } } /* * Function: * ibt_get_hcadevinfo * Input: * hca_guid - The HCA's node GUID. * Output: * none. * Returns: * Pointer to HCA Device Info structure whose HCA GUID is requested or NULL * Description: * Get a pointer to HCA Device Info Structure for the requested HCA GUID. * If no matching HCA GUID Device info is found, NULL is returned. */ ibtl_hca_devinfo_t * ibtl_get_hcadevinfo(ib_guid_t hca_guid) { ibtl_hca_devinfo_t *hca_devp; /* HCA Dev Info */ IBTF_DPRINTF_L3(ibtf_hca, "ibtl_get_hcadevinfo(%llX)", hca_guid); ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex)); hca_devp = ibtl_hca_list; /* * Check whether a HCA device with requested Node GUID is available. * This is done, by searching the global HCA devinfo list and * comparing the Node GUID from the device attribute info. */ while (hca_devp != NULL) { if (hca_devp->hd_hca_attr->hca_node_guid == hca_guid) { /* Match Found. */ break; } hca_devp = hca_devp->hd_hca_dev_link; } return (hca_devp); } /* * Function: * ibtl_pkey2index * Input: * hca_devp - The IBTL HCA Device Info. * port_num - The HCA port number. * pkey - The input PKey value, whose index we are interested in. * Output: * pkey_ix - The PKey index returned for the specified PKey. * Returns: * IBT_SUCCESS/IBT_HCA_PORT_INVALID/IBT_INVALID_PARAM * Description: * Returns the PKey Index for the specified PKey, the device as specified * by IBT HCA Handle. */ static ibt_status_t ibtl_pkey2index(ibtl_hca_devinfo_t *hca_devp, uint8_t port_num, ib_pkey_t pkey, uint16_t *pkey_ix) { ibt_hca_portinfo_t *port_infop; uint_t ports; uint_t i; IBTF_DPRINTF_L3(ibtf_hca, "ibtl_pkey2index(%p, %d, %d)", hca_devp, port_num, pkey); ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex)); if ((pkey == IB_PKEY_INVALID_FULL) || (pkey == IB_PKEY_INVALID_LIMITED)) return (IBT_INVALID_PARAM); ports = hca_devp->hd_hca_attr->hca_nports; if ((port_num == 0) || (port_num > ports)) { IBTF_DPRINTF_L2(ibtf_hca, "ibtl_pkey2index: " "Invalid port_num %d, range is (1 to %d)", port_num, ports); return (IBT_HCA_PORT_INVALID); } port_infop = hca_devp->hd_portinfop + port_num - 1; for (i = 0; i < port_infop->p_pkey_tbl_sz; i++) { if (pkey == port_infop->p_pkey_tbl[i]) { *pkey_ix = i; return (IBT_SUCCESS); } } return (IBT_INVALID_PARAM); } /* * Function: * ibtl_index2pkey * Input: * hca_devp - The IBTL HCA Device Info. * port_num - The HCA port * pkey_ix - The input PKey index, whose PKey we are interested in. * Output: * pkey - The returned PKey value. * Returns: * IBT_SUCCESS/IBT_PKEY_IX_ILLEGAL/IBT_PKEY_IX_INVALID/IBT_HCA_PORT_INVALID * Description: * Returns the PKey value for the specified PKey index, the device as * specified by IBT HCA Handle. */ static ibt_status_t ibtl_index2pkey(ibtl_hca_devinfo_t *hca_devp, uint8_t port_num, uint16_t pkey_ix, ib_pkey_t *pkey) { ibt_hca_portinfo_t *port_infop; uint_t ports; IBTF_DPRINTF_L3(ibtf_hca, "ibtl_index2pkey(%p, %d, %d)", hca_devp, port_num, pkey_ix); ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex)); ports = hca_devp->hd_hca_attr->hca_nports; if ((port_num == 0) || (port_num > ports)) { IBTF_DPRINTF_L2(ibtf_hca, "ibtl_index2pkey: " "Invalid port_num %d, range is (1 to %d)", port_num, ports); return (IBT_HCA_PORT_INVALID); } port_infop = hca_devp->hd_portinfop + port_num - 1; if (pkey_ix >= port_infop->p_pkey_tbl_sz) { IBTF_DPRINTF_L2(ibtf_hca, "ibtl_index2pkey: " "pkey index %d out of range (0, %d)", pkey_ix, port_infop->p_pkey_tbl_sz - 1); return (IBT_PKEY_IX_ILLEGAL); } *pkey = port_infop->p_pkey_tbl[pkey_ix]; if ((*pkey == IB_PKEY_INVALID_FULL) || (*pkey == IB_PKEY_INVALID_LIMITED)) return (IBT_PKEY_IX_INVALID); return (IBT_SUCCESS); } /* * Function: * ibt_pkey2index * Input: * hca_hdl - The IBT HCA handle. * port_num - The HCA port number. * pkey - The input PKey value, whose index we are interested in. * Output: * pkey_ix - The PKey index returned for the specified PKey. * Returns: * IBT_SUCCESS/IBT_HCA_PORT_INVALID/IBT_INVALID_PARAM * Description: * Returns the PKey Index for the specified PKey, the device as specified * by IBT HCA Handle. */ ibt_status_t ibt_pkey2index(ibt_hca_hdl_t hca_hdl, uint8_t port_num, ib_pkey_t pkey, uint16_t *pkey_ix) { ibt_status_t retval; IBTF_DPRINTF_L3(ibtf_hca, "ibt_pkey2index(%p, %d, %d)", hca_hdl, port_num, pkey); mutex_enter(&ibtl_clnt_list_mutex); retval = ibtl_pkey2index(hca_hdl->ha_hca_devp, port_num, pkey, pkey_ix); mutex_exit(&ibtl_clnt_list_mutex); return (retval); } /* * Function: * ibt_pkey2index_byguid * Input: * hca_guid - The HCA's node GUID. * port_num - The HCA port number. * pkey - The input PKey value, whose index we are interested in. * Output: * pkey_ix - The PKey Index returned for the specified PKey. * Returns: * IBT_SUCCESS/IBT_HCA_PORT_INVALID/IBT_INVALID_PARAM/IBT_HCA_INVALID * Description: * Returns the PKey Index for the specified PKey, the device as specified * by HCA GUID Info. */ ibt_status_t ibt_pkey2index_byguid(ib_guid_t hca_guid, uint8_t port_num, ib_pkey_t pkey, uint16_t *pkey_ix) { ibt_status_t retval; ibtl_hca_devinfo_t *hca_devp; /* HCA Dev Info */ IBTF_DPRINTF_L3(ibtf_hca, "ibt_pkey2index_byguid(%llX, %d, %d)", hca_guid, port_num, pkey); mutex_enter(&ibtl_clnt_list_mutex); hca_devp = ibtl_get_hcadevinfo(hca_guid); if (hca_devp == NULL) { IBTF_DPRINTF_L2(ibtf_hca, "ibt_pkey2index_byguid: " "Invalid HCA GUID 0x%llx", hca_guid); mutex_exit(&ibtl_clnt_list_mutex); return (IBT_HCA_INVALID); } retval = ibtl_pkey2index(hca_devp, port_num, pkey, pkey_ix); mutex_exit(&ibtl_clnt_list_mutex); return (retval); } /* * Function: * ibt_index2pkey * Input: * hca_hdl - The IBT HCA handle. * port_num - The HCA port * pkey_ix - The input PKey index, whose PKey we are interested in. * Output: * pkey - The returned PKey value. * Returns: * IBT_SUCCESS/IBT_PKEY_IX_ILLEGAL/IBT_PKEY_IX_INVALID/IBT_HCA_PORT_INVALID * Description: * Returns the PKey value for the specified PKey index, the device as * specified by IBT HCA Handle. */ ibt_status_t ibt_index2pkey(ibt_hca_hdl_t hca_hdl, uint8_t port_num, uint16_t pkey_ix, ib_pkey_t *pkey) { ibt_status_t retval; IBTF_DPRINTF_L3(ibtf_hca, "ibt_index2pkey(%p, %d, %d)", hca_hdl, port_num, pkey_ix); mutex_enter(&ibtl_clnt_list_mutex); retval = ibtl_index2pkey(hca_hdl->ha_hca_devp, port_num, pkey_ix, pkey); mutex_exit(&ibtl_clnt_list_mutex); return (retval); } /* * Function: * ibt_index2pkey_byguid * Input: * hca_guid - The HCA's node GUID. * port_num - The HCA port * pkey_ix - The input PKey index, whose PKey we are interested in. * Output: * pkey - The returned PKey value, for the specified index. * Returns: * IBT_SUCCESS/IBT_PKEY_IX_ILLEGAL/IBT_PKEY_IX_INVALID/ * IBT_HCA_PORT_INVALID/IBT_HCA_INVALID * Description: * Returns the PKey Index for the specified PKey, the device as specified * by HCA GUID Info. */ ibt_status_t ibt_index2pkey_byguid(ib_guid_t hca_guid, uint8_t port_num, uint16_t pkey_ix, ib_pkey_t *pkey) { ibt_status_t retval; ibtl_hca_devinfo_t *hca_devp; /* HCA Dev Info */ IBTF_DPRINTF_L3(ibtf_hca, "ibt_index2pkey_byguid(%llX, %d, %d)", hca_guid, port_num, pkey_ix); mutex_enter(&ibtl_clnt_list_mutex); hca_devp = ibtl_get_hcadevinfo(hca_guid); if (hca_devp == NULL) { IBTF_DPRINTF_L2(ibtf_hca, "ibt_index2pkey_byguid: " "Invalid HCA GUID 0x%llx", hca_guid); mutex_exit(&ibtl_clnt_list_mutex); return (IBT_HCA_INVALID); } retval = ibtl_index2pkey(hca_devp, port_num, pkey_ix, pkey); mutex_exit(&ibtl_clnt_list_mutex); return (retval); } _NOTE(SCHEME_PROTECTS_DATA("client managed", ibtl_hca_s::ha_clnt_private)) /* * Function: * ibt_set_hca_private * Input: * hca_hdl The ibt_hca_hdl_t of the opened HCA. * clnt_private The client private data. * Output: * none. * Returns: * none * Description: * Sets the client private data. */ void ibt_set_hca_private(ibt_hca_hdl_t hca_hdl, void *clnt_private) { hca_hdl->ha_clnt_private = clnt_private; } /* * Function: * ibt_get_hca_private * Input: * hca_hdl The ibt_hca_hdl_t of the opened HCA. * Output: * none * Returns: * The client private data. * Description: * Retrieves the private data from a specified HCA. */ void * ibt_get_hca_private(ibt_hca_hdl_t hca_hdl) { return (hca_hdl->ha_clnt_private); } /* * Function: * ibt_hca_handle_to_guid * Input: * hca HCA Handle. * Output: * none. * Returns: * hca_guid Returned HCA GUID on which the specified Channel is * allocated. Valid if it is non-NULL on return. * Description: * A helper function to retrieve HCA GUID for the specified handle. */ ib_guid_t ibt_hca_handle_to_guid(ibt_hca_hdl_t hca) { IBTF_DPRINTF_L3(ibtf_hca, "ibt_hca_handle_to_guid(%p)", hca); return (IBTL_HCA2HCAGUID(hca)); } /* * Function: * ibt_hca_guid_to_handle * Input: * ibt_hdl The handle returned to the client by the IBTF from * an ibt_attach() call. * hca_guid HCA GUID * Output: * hca_hdl Returned ibt_hca_hdl_t. * Returns: * IBT_SUCCESS * IBT_HCA_INVALID * Description: * A helper function to retrieve a hca handle from a HCA GUID. */ ibt_status_t ibt_hca_guid_to_handle(ibt_clnt_hdl_t ibt_hdl, ib_guid_t hca_guid, ibt_hca_hdl_t *hca_hdl) { ibtl_hca_t *hca_infop; ibtl_hca_devinfo_t *hca_devp; /* HCA Dev Info */ ibt_status_t rval = IBT_HCA_INVALID; IBTF_DPRINTF_L3(ibtf_hca, "ibt_hca_guid_to_handle(%p, %llX)", ibt_hdl, hca_guid); mutex_enter(&ibtl_clnt_list_mutex); /* * Get HCA Device Info Structure, referenced by HCA GUID. */ hca_devp = ibtl_get_hcadevinfo(hca_guid); if (hca_devp == NULL) { /* * If we are here, then the requested HCA device is not present. * Return the status as Invalid HCA GUID. */ mutex_exit(&ibtl_clnt_list_mutex); IBTF_DPRINTF_L2(ibtf_hca, "ibt_hca_guid_to_handle: " "HCA Device Not Found: Invalid HCA GUID"); *hca_hdl = NULL; return (rval); } /* * Yes, we found a HCA Device registered with IBTF, which matches with * the requested HCA_GUID. */ hca_infop = hca_devp->hd_clnt_list; while (hca_infop != NULL) { if (ibt_hdl == hca_infop->ha_clnt_devp) { rval = IBT_SUCCESS; break; } hca_infop = hca_infop->ha_clnt_link; } mutex_exit(&ibtl_clnt_list_mutex); *hca_hdl = hca_infop; return (rval); }