#include "dapl.h"
#include "dapl_provider.h"
#include "dapl_evd_util.h"
#include "dapl_hca_util.h"
#include "dapl_ia_util.h"
#include "dapl_adapter_util.h"
#include <sys/systeminfo.h>
#include <libdevinfo.h>
#if defined(IBHOSTS_NAMING)
void dapli_assign_hca_ip_address(
DAPL_HCA *hca_ptr,
char *device_name);
#endif
static void dapli_hca_cleanup(DAPL_HCA *hca_ptr, DAT_BOOLEAN dec_ref);
static boolean_t
dapl_ro_disallowed(void)
{
static const char * const non_ro_capable_platforms[] = {
"i86pc",
"i86xpv",
"SUNW,Sun-Fire-V215",
"SUNW,Sun-Fire-V245",
"SUNW,Sun-Fire-V445",
"SUNW,Sun-Fire-T1000",
"SUNW,Sun-Fire-T200",
"SUNW,Sun-Blade-T6300",
"SUNW,Sun-Blade-T6320",
"SUNW,SPARC-Enterprise-T1000",
"SUNW,SPARC-Enterprise-T2000",
"SUNW,SPARC-Enterprise-T5120",
"SUNW,SPARC-Enterprise-T5220",
NULL
};
char platform[256 + 1];
register int i;
register const char *cp;
int ret;
di_node_t root_node, node;
boolean_t ro_disallowed;
static const char *ro_disallowed_property =
"pci-relaxed-ordering-disallowed";
int bool;
int *boolp = &bool;
ret = sysinfo(SI_PLATFORM, platform, sizeof (platform));
if ((ret != -1) && (ret <= sizeof (platform))) {
for (i = 0; (cp = non_ro_capable_platforms[i]) != NULL; ++i) {
if (strcmp(platform, cp) == 0)
return (B_TRUE);
}
}
if ((root_node = di_init("/", DINFOSUBTREE | DINFOPROP)) == DI_NODE_NIL)
return (B_FALSE);
node = di_drv_first_node("daplt", root_node);
if (node != DI_NODE_NIL) {
ret = di_prop_lookup_ints(DDI_DEV_T_ANY, node,
ro_disallowed_property, &boolp);
switch (ret) {
case 0:
case 1:
ro_disallowed = B_TRUE;
break;
default:
ro_disallowed = B_FALSE;
break;
}
}
else
ro_disallowed = B_FALSE;
di_fini(root_node);
return (ro_disallowed);
}
DAT_RETURN
dapl_ia_open(
IN const DAT_NAME_PTR name,
IN DAT_COUNT async_evd_qlen,
INOUT DAT_EVD_HANDLE *async_evd_handle_ptr,
OUT DAT_IA_HANDLE *ia_handle_ptr,
IN boolean_t ro_aware_client)
{
DAT_RETURN dat_status;
DAT_PROVIDER *provider;
DAPL_HCA *hca_ptr;
DAPL_IA *ia_ptr;
DAPL_EVD *evd_ptr;
boolean_t ro_disallowed;
dat_status = DAT_SUCCESS;
hca_ptr = NULL;
ia_ptr = NULL;
dapl_dbg_log(DAPL_DBG_TYPE_API,
"dapl_ia_open(%s, %d, %p, %p, %d)\n",
name,
async_evd_qlen,
async_evd_handle_ptr,
ia_handle_ptr,
ro_aware_client);
dat_status = dapl_provider_list_search(name, &provider);
if (DAT_SUCCESS != dat_status) {
dapl_dbg_log(DAPL_DBG_TYPE_API,
"dapl_ia_open: dapl_provider_list_search(\"%s\") returned "
"%d\n",
name,
dat_status);
dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG1);
goto bail;
}
if (ia_handle_ptr == NULL) {
dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4);
goto bail;
}
if (async_evd_handle_ptr == NULL) {
dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3);
goto bail;
}
*ia_handle_ptr = DAT_HANDLE_NULL;
hca_ptr = (DAPL_HCA *)provider->extension;
dapl_os_lock(&hca_ptr->lock);
if (hca_ptr->ib_hca_handle == IB_INVALID_HANDLE) {
dat_status = dapls_ib_open_hca(hca_ptr,
&hca_ptr->ib_hca_handle);
if (dat_status != DAT_SUCCESS) {
dapl_dbg_log(DAPL_DBG_TYPE_ERR,
"dapls_ib_open_hca failed %d\n", dat_status);
dapl_os_unlock(&hca_ptr->lock);
goto bail;
}
dat_status = dapls_ib_cqd_create(hca_ptr);
if (dat_status != DAT_SUCCESS) {
dapl_dbg_log(DAPL_DBG_TYPE_ERR,
"ERR: Cannot allocate CQD: err %x\n", dat_status);
dapli_hca_cleanup(hca_ptr, DAT_FALSE);
dapl_os_unlock(&hca_ptr->lock);
goto bail;
}
#ifdef IBHOSTS_NAMING
dapli_assign_hca_ip_address(hca_ptr, name);
#endif
dat_status = dapls_ib_query_hca(hca_ptr,
&hca_ptr->ia_attr,
NULL,
&hca_ptr->hca_address, NULL);
if (dat_status != DAT_SUCCESS) {
dapli_hca_cleanup(hca_ptr, DAT_FALSE);
dapl_os_unlock(&hca_ptr->lock);
goto bail;
}
}
if (hca_ptr->hermon_resize_cq != 0) {
ro_disallowed = dapl_ro_disallowed();
if (! ro_aware_client && ! ro_disallowed) {
dapl_dbg_log(DAPL_DBG_TYPE_API,
"dapl_ia_open: failing ro_disallowed %d "
"ro_aware_client %d \n",
ro_disallowed, ro_aware_client);
dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
DAT_INVALID_RO_COOKIE);
dapli_hca_cleanup(hca_ptr, DAT_FALSE);
dapl_os_unlock(&hca_ptr->lock);
goto bail;
}
} else {
ro_disallowed = B_TRUE;
}
dapl_os_atomic_inc(&hca_ptr->handle_ref_count);
dapl_os_unlock(&hca_ptr->lock);
ia_ptr = dapl_ia_alloc(provider, hca_ptr);
if (!ia_ptr) {
dapl_os_lock(&hca_ptr->lock);
dapli_hca_cleanup(hca_ptr, DAT_TRUE);
dapl_os_unlock(&hca_ptr->lock);
dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
DAT_RESOURCE_MEMORY);
goto bail;
}
if (ro_disallowed)
ia_ptr->dapl_flags |= DAPL_DISABLE_RO;
evd_ptr = (DAPL_EVD *) *async_evd_handle_ptr;
if (evd_ptr) {
if (DAPL_BAD_HANDLE(evd_ptr, DAPL_MAGIC_EVD) ||
! (evd_ptr->evd_flags & DAT_EVD_ASYNC_FLAG)) {
dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
DAT_INVALID_HANDLE_EVD_ASYNC);
goto bail;
}
if (evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle !=
hca_ptr->ib_hca_handle) {
dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
DAT_INVALID_HANDLE_EVD_ASYNC);
goto bail;
}
ia_ptr->cleanup_async_error_evd = DAT_FALSE;
ia_ptr->async_error_evd = evd_ptr;
} else {
if (async_evd_qlen <= 0) {
dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
DAT_INVALID_ARG2);
goto bail;
}
dat_status = dapls_evd_internal_create(ia_ptr,
NULL,
async_evd_qlen,
DAT_EVD_ASYNC_FLAG,
&evd_ptr);
if (dat_status != DAT_SUCCESS) {
goto bail;
}
dapl_os_atomic_inc(&evd_ptr->evd_ref_count);
dapl_os_lock(&hca_ptr->lock);
if (hca_ptr->async_evd != (DAPL_EVD *) 0) {
#if 0
dapl_os_atomic_dec(&evd_ptr->evd_ref_count);
dapl_evd_free(evd_ptr);
dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
DAT_INVALID_ARG4);
goto bail;
#endif
dapl_os_unlock(&hca_ptr->lock);
} else {
hca_ptr->async_evd = evd_ptr;
dapl_os_unlock(&hca_ptr->lock);
dat_status = dapls_ia_setup_callbacks(ia_ptr, evd_ptr);
if (dat_status != DAT_SUCCESS) {
ia_ptr->cleanup_async_error_evd = DAT_TRUE;
ia_ptr->async_error_evd = evd_ptr;
goto bail;
}
}
ia_ptr->cleanup_async_error_evd = DAT_TRUE;
ia_ptr->async_error_evd = evd_ptr;
}
dat_status = DAT_SUCCESS;
*ia_handle_ptr = ia_ptr;
*async_evd_handle_ptr = evd_ptr;
bail:
if (dat_status != DAT_SUCCESS) {
if (ia_ptr) {
(void) dapl_ia_close(ia_ptr, DAT_CLOSE_ABRUPT_FLAG);
}
}
dapl_dbg_log(DAPL_DBG_TYPE_RTN,
"dapl_ia_open () returns 0x%x\n",
dat_status);
return (dat_status);
}
void
dapli_hca_cleanup(
DAPL_HCA *hca_ptr,
DAT_BOOLEAN dec_ref)
{
(void) dapls_ib_close_hca(hca_ptr->ib_hca_handle);
hca_ptr->ib_hca_handle = IB_INVALID_HANDLE;
if (dec_ref == DAT_TRUE) {
dapl_os_atomic_dec(&hca_ptr->handle_ref_count);
}
}
#if defined(IBHOSTS_NAMING)
char *dapli_get_adapter_num(
char *device_name);
void dapli_setup_dummy_addr(
IN DAPL_HCA *hca_ptr,
IN char *hca_name);
void
dapli_assign_hca_ip_address(
DAPL_HCA *hca_ptr,
char *device_name)
{
char *adapter_num;
#define NAMELEN 128
struct addrinfo *addr;
char hostname[NAMELEN];
char *str;
int rc;
rc = gethostname(hostname, NAMELEN);
for (str = hostname; *str && *str != '.'; ) {
str++;
}
if (*str == '.') {
*str = '\0';
}
dapl_os_strcat(hostname, "-ib");
adapter_num = dapli_get_adapter_num(device_name);
dapl_os_strcat(hostname, adapter_num);
rc = dapls_osd_getaddrinfo(hostname, &addr);
if (rc != 0) {
dapli_setup_dummy_addr(hca_ptr, hostname);
} else {
(void) dapl_os_memcpy((void *)&hca_ptr->hca_address,
(void *)(addr->ai_addr), sizeof (DAT_SOCK_ADDR6));
}
}
void
dapli_setup_dummy_addr(
IN DAPL_HCA *hca_ptr,
IN char *rhost_name)
{
struct sockaddr_in *si;
dapl_dbg_log(DAPL_DBG_TYPE_ERR, "WARNING: <%s> not registered in DNS,"
" using dummy IP value\n", rhost_name);
si = (struct sockaddr_in *)&hca_ptr->hca_address;
si->sin_family = AF_INET;
si->sin_addr.s_addr = 0x01020304;
}
char *
dapli_get_adapter_num(
char *device_name)
{
static char *zero = "0";
char *p;
for (p = device_name; *p; p++) {
if (isdigit(*p)) {
return (p);
}
}
return (zero);
}
#endif