#include <sys/ib/ibtl/impl/ibtl.h>
static char ibtf_hca[] = "ibtl_hca";
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_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;
IBTF_DPRINTF_L3(ibtf_hca, "ibt_open_hca(%p, %llX)", ibt_hdl, hca_guid);
mutex_enter(&ibtl_clnt_list_mutex);
hca_devp = ibtl_get_hcadevinfo(hca_guid);
if (hca_devp == NULL) {
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);
}
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) {
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);
}
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);
*hca_hdl_p = hca_infop;
return (IBT_HCA_IN_USE);
}
hca_infop = hca_infop->ha_clnt_link;
}
hca_infop = kmem_zalloc(sizeof (ibtl_hca_t), KM_SLEEP);
hca_infop->ha_hca_devp = hca_devp;
hca_infop->ha_clnt_devp = ibt_hdl;
hca_infop->ha_clnt_link = hca_devp->hd_clnt_list;
hca_devp->hd_clnt_list = hca_infop;
hca_infop->ha_hca_link = ibt_hdl->clnt_hca_list;
ibt_hdl->clnt_hca_list = hca_infop;
mutex_exit(&ibtl_clnt_list_mutex);
*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
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);
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);
}
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);
}
hca_hdl->ha_flags |= IBTL_HA_CLOSING;
while (hca_hdl->ha_qpn_cnt > 0)
cv_wait(&ibtl_close_hca_cv, &ibtl_clnt_list_mutex);
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 = hca_hdl->ha_hca_link;
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 = hca_hdl->ha_clnt_link;
mutex_exit(&ibtl_clnt_list_mutex);
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);
}
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) {
*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);
}
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));
}
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);
} 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);
} else {
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);
}
}
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);
}
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);
}
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;
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);
}
ibt_status_t
ibt_query_hca_byguid(ib_guid_t hca_guid, ibt_hca_attr_t *hca_attrs)
{
ibtl_hca_devinfo_t *hca_devp;
IBTF_DPRINTF_L3(ibtf_hca, "ibt_query_hca_byguid(%llX)", hca_guid);
mutex_enter(&ibtl_clnt_list_mutex);
hca_devp = ibtl_get_hcadevinfo(hca_guid);
if (hca_devp == NULL) {
mutex_exit(&ibtl_clnt_list_mutex);
IBTF_DPRINTF_L2(ibtf_hca, "ibt_query_hca_byguid: "
"Device Not Found");
return (IBT_HCA_INVALID);
}
bcopy(hca_devp->hd_hca_attr, hca_attrs, sizeof (ibt_hca_attr_t));
mutex_exit(&ibtl_clnt_list_mutex);
return (IBT_SUCCESS);
}
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);
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))
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);
}
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;
ibt_status_t retval;
mutex_enter(&ibtl_clnt_list_mutex);
hca_devp = ibtl_get_hcadevinfo(hca_guid);
if (hca_devp == NULL) {
*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);
}
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;
ibt_status_t retval;
mutex_enter(&ibtl_clnt_list_mutex);
hca_devp = ibtl_get_hcadevinfo(hca_guid);
if (hca_devp == NULL) {
*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);
}
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;
ibt_hca_portinfo_t *p1;
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);
}
sp1 = hca_devp->hd_portinfop + port - 1;
if (use_cache == 0)
ibtl_reinit_hca_portinfo(hca_devp, port);
*ports_p = 1;
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));
p2 = (caddr_t)(p1 + 1);
bcopy(sp1->p_pkey_tbl, p2, pkey_tbl_len);
p1->p_pkey_tbl = (ib_pkey_t *)p2;
p2 += pkey_tbl_len;
bcopy(sp1->p_sgid_tbl, p2, sgid_tbl_len);
p1->p_sgid_tbl = (ib_gid_t *)p2;
return (IBT_SUCCESS);
}
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;
ibt_hca_portinfo_t *p1;
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 (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 (use_cache == 0)
for (i = 0; i < nports; i++)
ibtl_reinit_hca_portinfo(hca_devp, i + 1);
sp1 = hca_devp->hd_portinfop;
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);
p2 = (caddr_t)(p1 + nports);
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);
}
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;
}
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)) {
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;
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);
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);
}
}
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;
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 (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);
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);
}
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);
retval = IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_modify_system_image(
IBTL_HCA2CIHCA(hca_hdl), sys_guid);
mutex_exit(&ibtl_clnt_list_mutex);
return (retval);
}
ibt_status_t
ibt_modify_system_image_byguid(ib_guid_t hca_guid, ib_guid_t sys_guid)
{
ibtl_hca_devinfo_t *hca_devp;
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);
hca_devp = ibtl_get_hcadevinfo(hca_guid);
if (hca_devp == NULL) {
mutex_exit(&ibtl_clnt_list_mutex);
return (IBT_HCA_INVALID);
}
retval = IBTL_HDIP2CIHCAOPS_P(hca_devp)->ibc_modify_system_image(
IBTL_HDIP2CIHCA(hca_devp), sys_guid);
mutex_exit(&ibtl_clnt_list_mutex);
return (retval);
}
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;
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);
hca_devp = ibtl_get_hcadevinfo(hca_guid);
if (hca_devp == NULL) {
mutex_exit(&ibtl_clnt_list_mutex);
return (IBT_HCA_INVALID);
}
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);
}
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);
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);
}
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);
}
}
ibtl_hca_devinfo_t *
ibtl_get_hcadevinfo(ib_guid_t hca_guid)
{
ibtl_hca_devinfo_t *hca_devp;
IBTF_DPRINTF_L3(ibtf_hca, "ibtl_get_hcadevinfo(%llX)", hca_guid);
ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex));
hca_devp = ibtl_hca_list;
while (hca_devp != NULL) {
if (hca_devp->hd_hca_attr->hca_node_guid == hca_guid) {
break;
}
hca_devp = hca_devp->hd_hca_dev_link;
}
return (hca_devp);
}
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);
}
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);
}
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);
}
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;
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);
}
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);
}
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;
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))
void
ibt_set_hca_private(ibt_hca_hdl_t hca_hdl, void *clnt_private)
{
hca_hdl->ha_clnt_private = clnt_private;
}
void *
ibt_get_hca_private(ibt_hca_hdl_t hca_hdl)
{
return (hca_hdl->ha_clnt_private);
}
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));
}
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;
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);
hca_devp = ibtl_get_hcadevinfo(hca_guid);
if (hca_devp == NULL) {
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);
}
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);
}