#include <sys/systm.h>
#include <sys/sunndi.h>
#include <sys/sunmdi.h>
#include <sys/ib/ibtl/impl/ibtl.h>
#include <sys/ib/ibtl/impl/ibtl_ibnex.h>
static char ibtl_ibnex[] = "ibtl_ibnex";
ibtl_ibnex_callback_t ibtl_ibnex_callback_routine = NULL;
ibt_status_t
ibtl_ibnex_get_hca_info(ib_guid_t hca_guid, int flag, char **buffer,
size_t *bufsiz, void (*callback)(dev_info_t *, char **))
{
char *node_name;
char *ret_apid;
nvlist_t *nvl;
ibtl_hca_t *ibt_hca;
ibtl_clnt_t *clntp;
dev_info_t *child;
dev_info_t *parent;
ibtl_hca_devinfo_t *hca_devp;
IBTF_DPRINTF_L3(ibtl_ibnex, "ibtl_ibnex_get_hca_info: "
"GUID 0x%llX, flag = 0x%x", hca_guid, flag);
*buffer = NULL;
*bufsiz = 0;
if (flag != IBTL_IBNEX_LIST_CLNTS_FLAG &&
flag != IBTL_IBNEX_UNCFG_CLNTS_FLAG) {
return (IBT_INVALID_PARAM);
}
mutex_enter(&ibtl_clnt_list_mutex);
if ((hca_devp = ibtl_get_hcadevinfo(hca_guid)) == NULL) {
mutex_exit(&ibtl_clnt_list_mutex);
IBTF_DPRINTF_L2(ibtl_ibnex, "ibtl_ibnex_get_hca_info: "
"HCA Not Found, Invalid HCA GUID 0x%llX", hca_guid);
return (IBT_HCA_INVALID);
}
ibt_hca = hca_devp->hd_clnt_list;
(void) nvlist_alloc(&nvl, 0, KM_SLEEP);
ret_apid = kmem_alloc(IBTL_IBNEX_APID_LEN, KM_SLEEP);
while (ibt_hca != NULL) {
clntp = ibt_hca->ha_clnt_devp;
child = clntp->clnt_dip;
IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_get_hca_info: "
"Client = %s", clntp->clnt_modinfop->mi_clnt_name);
if (flag == IBTL_IBNEX_LIST_CLNTS_FLAG) {
(void) nvlist_add_string(nvl, "Client",
clntp->clnt_modinfop->mi_clnt_name);
if (clntp->clnt_hca_list == NULL) {
(void) nvlist_add_string(nvl, "Alt_HCA", "no");
(void) nvlist_add_string(nvl, "ApID", "-");
ibt_hca = ibt_hca->ha_clnt_link;
continue;
}
if (clntp->clnt_hca_list->ha_hca_link == NULL)
(void) nvlist_add_string(nvl, "Alt_HCA", "no");
else
(void) nvlist_add_string(nvl, "Alt_HCA", "yes");
if (child == NULL) {
(void) nvlist_add_string(nvl, "ApID", "-");
ibt_hca = ibt_hca->ha_clnt_link;
continue;
}
parent = ddi_get_parent(child);
if (parent == NULL ||
ddi_get_parent_data(child) == NULL) {
(void) nvlist_add_string(nvl, "ApID", "-");
ibt_hca = ibt_hca->ha_clnt_link;
continue;
}
node_name = ddi_node_name(child);
if ((strcmp(ddi_node_name(parent), "ib") == 0) ||
((hca_devp->hd_hca_dip == parent) &&
(strncmp(node_name, IBNEX_IBPORT_CNAME, 6) == 0))) {
ASSERT(callback != NULL);
callback(child, &ret_apid);
(void) nvlist_add_string(nvl, "ApID", ret_apid);
} else {
(void) nvlist_add_string(nvl, "ApID", "-");
}
} else if (flag == IBTL_IBNEX_UNCFG_CLNTS_FLAG) {
char path[MAXPATHLEN];
if (child == NULL) {
IBTF_DPRINTF_L4(ibtl_ibnex,
"ibtl_ibnex_get_hca_info: No dip exists");
ibt_hca = ibt_hca->ha_clnt_link;
continue;
}
if (clntp->clnt_hca_list->ha_hca_link) {
IBTF_DPRINTF_L4(ibtl_ibnex,
"ibtl_ibnex_get_hca_info: Alt HCA exists");
ibt_hca = ibt_hca->ha_clnt_link;
continue;
}
parent = ddi_get_parent(child);
if (parent == NULL ||
ddi_get_parent_data(child) == NULL) {
IBTF_DPRINTF_L4(ibtl_ibnex,
"ibtl_ibnex_get_hca_info: no parent");
ibt_hca = ibt_hca->ha_clnt_link;
continue;
}
node_name = ddi_node_name(child);
if ((strcmp(ddi_node_name(parent), "ib") == 0) ||
((hca_devp->hd_hca_dip == parent) &&
(strncmp(node_name, IBNEX_IBPORT_CNAME, 6) == 0))) {
ASSERT(callback != NULL);
callback(child, &ret_apid);
(void) nvlist_add_string(nvl, "ApID", ret_apid);
(void) strcpy(path, "/devices");
(void) ddi_pathname(child, path + strlen(path));
IBTF_DPRINTF_L4(ibtl_ibnex,
"ibtl_ibnex_get_hca_info: "
"device path = %s", path);
if (nvlist_add_string(nvl, "devpath", path)) {
IBTF_DPRINTF_L2(ibtl_ibnex,
"ibtl_ibnex_get_hca_info: "
"failed to fill in path %s", path);
mutex_exit(&ibtl_clnt_list_mutex);
nvlist_free(nvl);
kmem_free(ret_apid,
IBTL_IBNEX_APID_LEN);
return (ibt_get_module_failure(
IBT_FAILURE_IBTL, 0));
}
}
}
ibt_hca = ibt_hca->ha_clnt_link;
}
mutex_exit(&ibtl_clnt_list_mutex);
kmem_free(ret_apid, IBTL_IBNEX_APID_LEN);
if (nvlist_pack(nvl, buffer, bufsiz, NV_ENCODE_NATIVE, KM_SLEEP)) {
IBTF_DPRINTF_L2(ibtl_ibnex, "ibtl_ibnex_get_hca_info: "
"nvlist_pack failed");
nvlist_free(nvl);
return (ibt_get_module_failure(IBT_FAILURE_IBTL, 0));
}
IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_get_hca_info: size = %x",
*bufsiz);
nvlist_free(nvl);
return (IBT_SUCCESS);
}
void
ibtl_ibnex_register_callback(ibtl_ibnex_callback_t ibnex_cb)
{
IBTF_DPRINTF_L5(ibtl_ibnex, "ibtl_ibnex_register_callback:");
mutex_enter(&ibtl_clnt_list_mutex);
ibtl_ibnex_callback_routine = ibnex_cb;
mutex_exit(&ibtl_clnt_list_mutex);
}
void
ibtl_ibnex_unregister_callback()
{
IBTF_DPRINTF_L5(ibtl_ibnex, "ibtl_ibnex_unregister_callback: ibnex cb");
mutex_enter(&ibtl_clnt_list_mutex);
ibtl_ibnex_callback_routine = NULL;
mutex_exit(&ibtl_clnt_list_mutex);
}
ib_guid_t
ibtl_ibnex_hcadip2guid(dev_info_t *hca_dip)
{
ib_guid_t hca_guid = 0LL;
ibtl_hca_devinfo_t *hca_devp;
mutex_enter(&ibtl_clnt_list_mutex);
hca_devp = ibtl_hca_list;
while (hca_devp) {
if (hca_devp->hd_hca_dip == hca_dip) {
hca_guid = hca_devp->hd_hca_attr->hca_node_guid;
break;
}
hca_devp = hca_devp->hd_hca_dev_link;
}
mutex_exit(&ibtl_clnt_list_mutex);
IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_hcadip_guid: hca_guid 0x%llX",
hca_guid);
return (hca_guid);
}
dev_info_t *
ibtl_ibnex_hcaguid2dip(ib_guid_t hca_guid)
{
dev_info_t *dip = NULL;
ibtl_hca_devinfo_t *hca_devp;
IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_hcaguid2dip:");
mutex_enter(&ibtl_clnt_list_mutex);
hca_devp = ibtl_hca_list;
while (hca_devp) {
if (hca_devp->hd_hca_attr->hca_node_guid == hca_guid) {
dip = hca_devp->hd_hca_dip;
break;
}
hca_devp = hca_devp->hd_hca_dev_link;
}
mutex_exit(&ibtl_clnt_list_mutex);
return (dip);
}
ibt_status_t
ibtl_ibnex_get_hca_verbose_data(ib_guid_t hca_guid, char **buffer,
size_t *bufsiz)
{
char path[IBTL_IBNEX_STR_LEN];
char tmp[MAXPATHLEN];
uint_t ii;
ibt_hca_portinfo_t *pinfop;
ibtl_hca_devinfo_t *hca_devp;
IBTF_DPRINTF_L3(ibtl_ibnex, "ibtl_ibnex_get_hca_verbose_data: "
"HCA GUID 0x%llX", hca_guid);
*buffer = NULL;
*bufsiz = 0;
mutex_enter(&ibtl_clnt_list_mutex);
if ((hca_devp = ibtl_get_hcadevinfo(hca_guid)) == NULL) {
mutex_exit(&ibtl_clnt_list_mutex);
IBTF_DPRINTF_L2(ibtl_ibnex, "ibtl_ibnex_get_hca_verbose_data: "
"HCA Not Found, Invalid HCA GUID");
return (IBT_HCA_INVALID);
}
(void) snprintf(tmp, MAXPATHLEN, "VID: 0x%x, PID: 0x%x, #ports: 0x%x",
hca_devp->hd_hca_attr->hca_vendor_id,
hca_devp->hd_hca_attr->hca_device_id,
hca_devp->hd_hca_attr->hca_nports);
pinfop = hca_devp->hd_portinfop;
for (ii = 0; ii < hca_devp->hd_hca_attr->hca_nports; ii++) {
(void) snprintf(path, IBTL_IBNEX_STR_LEN,
", port%d GUID: 0x%llX", ii + 1,
(longlong_t)pinfop[ii].p_sgid_tbl->gid_guid);
(void) strcat(tmp, path);
}
mutex_exit(&ibtl_clnt_list_mutex);
*bufsiz = strlen(tmp);
*buffer = kmem_alloc(*bufsiz, KM_SLEEP);
(void) strncpy(*buffer, tmp, *bufsiz);
IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_get_hca_verbose_data: "
"data = %s, size = 0x%x", *buffer, *bufsiz);
return (IBT_SUCCESS);
}
ibt_status_t
ibt_reprobe_dev(dev_info_t *dip)
{
ibt_status_t rv;
ibtl_ibnex_cb_args_t cb_args;
if (dip == NULL)
return (IBT_NOT_SUPPORTED);
if (strcmp(ddi_node_name(ddi_get_parent(dip)), "ib") != 0)
return (IBT_NOT_SUPPORTED);
if (strncmp(ddi_node_name(dip), IBNEX_IBPORT_CNAME, 6) == 0)
return (IBT_NOT_SUPPORTED);
cb_args.cb_flag = IBTL_IBNEX_REPROBE_DEV_REQ;
cb_args.cb_dip = dip;
mutex_enter(&ibtl_clnt_list_mutex);
if (ibtl_ibnex_callback_routine) {
rv = (*ibtl_ibnex_callback_routine)(&cb_args);
mutex_exit(&ibtl_clnt_list_mutex);
return (rv);
}
mutex_exit(&ibtl_clnt_list_mutex);
IBTF_DPRINTF_L2("ibtl", "ibt_reprobe_dev: ibnex not registered!!");
return (IBT_ILLEGAL_OP);
}
ibt_status_t
ibtl_ibnex_valid_hca_parent(dev_info_t *pdip)
{
ibtl_hca_devinfo_t *hca_devp;
IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_valid_hca_parent: pdip %p",
pdip);
if (strncmp(ddi_node_name(pdip), "ib", 2) == 0 ||
strncmp(ddi_node_name(pdip), "eibnx", 5) == 0) {
return (IBT_SUCCESS);
} else {
mutex_enter(&ibtl_clnt_list_mutex);
hca_devp = ibtl_hca_list;
while (hca_devp) {
if (hca_devp->hd_hca_dip == pdip) {
mutex_exit(&ibtl_clnt_list_mutex);
return (IBT_SUCCESS);
}
hca_devp = hca_devp->hd_hca_dev_link;
}
mutex_exit(&ibtl_clnt_list_mutex);
return (IBT_NO_HCAS_AVAILABLE);
}
}
ibt_status_t
ibtl_ibnex_phci_register(dev_info_t *hca_dip)
{
if (mdi_phci_register(MDI_HCI_CLASS_IB, hca_dip, 0) !=
MDI_SUCCESS) {
return (IBT_FAILURE);
}
return (IBT_SUCCESS);
}
ibt_status_t
ibtl_ibnex_phci_unregister(dev_info_t *hca_dip)
{
mdi_pathinfo_t *pip = NULL;
dev_info_t *vdip = 0;
vdip = mdi_devi_get_vdip(hca_dip);
ndi_devi_enter(vdip);
ndi_devi_enter(hca_dip);
while (pip = mdi_get_next_client_path(hca_dip, NULL)) {
if (mdi_pi_free(pip, 0) == MDI_SUCCESS) {
continue;
}
ndi_devi_exit(hca_dip);
ndi_devi_exit(vdip);
IBTF_DPRINTF_L1(ibtl_ibnex, "ibtl_ibnex_phci_unregister: "
"mdi_pi_free failed");
return (IBT_FAILURE);
}
ndi_devi_exit(hca_dip);
ndi_devi_exit(vdip);
if (mdi_phci_unregister(hca_dip, 0) != MDI_SUCCESS) {
IBTF_DPRINTF_L1(ibtl_ibnex, "ibtl_ibnex_phci_unregister: PHCI "
"unregister failed");
return (IBT_FAILURE);
}
return (IBT_SUCCESS);
}
ibt_status_t
ibtl_ibnex_query_hca_byguid(ib_guid_t hca_guid, ibt_hca_attr_t *hca_attrs,
char *driver_name, size_t driver_name_size, int *driver_instance,
char *hca_device_path)
{
ibtl_hca_devinfo_t *hca_devp;
IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_query_hca_byguid("
"hca_guid = 0x%llx, hca_attrs = 0x%p, driver_name = 0x%p, "
"driver_name_size = 0x%d, driver_instancep = 0x%p)", hca_guid,
hca_attrs, driver_name, (int)driver_name_size, driver_instance);
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);
}
if (strlcpy(driver_name,
ddi_driver_name(hca_devp->hd_hca_dip), driver_name_size) >=
driver_name_size) {
mutex_exit(&ibtl_clnt_list_mutex);
return (IBT_INSUFF_KERNEL_RESOURCE);
}
(void) ddi_pathname(hca_devp->hd_hca_dip, hca_device_path);
*driver_instance = ddi_get_instance(hca_devp->hd_hca_dip);
bcopy(hca_devp->hd_hca_attr, hca_attrs, sizeof (ibt_hca_attr_t));
mutex_exit(&ibtl_clnt_list_mutex);
return (IBT_SUCCESS);
}