static int __gnix_auth_key_initialize(
	uint8_t *auth_key,
	size_t auth_key_size,
	struct gnix_auth_key_attr *attr)
{
	struct gnix_auth_key *info = NULL;
	int ret = FI_SUCCESS;

	info = _gnix_auth_key_lookup(auth_key, auth_key_size);

	if (info) {
		GNIX_WARN(FI_LOG_FABRIC, "authorization key is already "
			"initialized, auth_key=%d auth_key_size=%d\n",
			auth_key, auth_key_size);
		return -FI_ENOSPC; /* already initialized*/
	}

	info = _gnix_auth_key_alloc();
	if (!info)
		return -FI_ENOMEM;

	if (attr)
		info->attr = *attr;
	else {
		info->attr.user_key_limit =
			gnix_default_user_registration_limit;
		info->attr.prov_key_limit =
			gnix_default_prov_registration_limit;
	}

	ret = _gnix_auth_key_insert(auth_key, auth_key_size, info);
	if (ret) {
		GNIX_INFO(FI_LOG_FABRIC, "failed to insert authorization key"
			", key=%p len=%d ret=%d\n",
			auth_key, auth_key_size, ret);
		_gnix_auth_key_free(info);
		info = NULL;
	}

	return ret;
}
static int __gnix_auth_key_get_val(
	uint8_t *auth_key,
	size_t auth_key_size,
	gnix_auth_key_opt_t opt,
	void *val)
{
	struct gnix_auth_key *info;

	if (!val)
		return -FI_EINVAL;

	info = _gnix_auth_key_lookup(auth_key, auth_key_size);

	switch (opt) {
	case GNIX_USER_KEY_LIMIT:
		*(int *)val = (info) ?
			info->attr.user_key_limit :
			gnix_default_user_registration_limit;
		break;
	case GNIX_PROV_KEY_LIMIT:
		*(int *)val = (info) ?
			info->attr.prov_key_limit :
			gnix_default_prov_registration_limit;
		break;
	case GNIX_TOTAL_KEYS_NEEDED:
		*(uint32_t *)val = ((info) ?
			(info->attr.user_key_limit +
			info->attr.prov_key_limit) :
			(gnix_default_user_registration_limit +
			 gnix_default_prov_registration_limit));
	break;
	default:
		GNIX_WARN(FI_LOG_FABRIC, ("Invalid fab_ops_val\n"));
		return -FI_EINVAL;
	}

	return FI_SUCCESS;
}
/**
 * Create a slab from a handle and append to the slab list.
 *
 * @param[in] handle	Handle to the allocator being used.
 *
 * @return FI_SUCCESS	On successful slab creation.
 *
 * @return -FI_ENOMEM	if failure to allocate memory for slab or bitmap.
 * @return [Unspec]	if failure in alloc_bitmap. Will return error code from
 * alloc_bitmap.
 * @return [Unspec]	if failure in GNI_MemRegister. Converts gni_return_t
 * status code to FI_ERRNO value.
 */
static int __create_slab(struct gnix_mbox_alloc_handle *handle)
{
	struct gnix_slab *slab;
	gni_return_t status;
	char error_buf[256];
	char *error;
	size_t total_size;
	int ret;
	int vmdh_index = -1;
	int flags = GNI_MEM_READWRITE;
	struct gnix_auth_key *info;

	GNIX_TRACE(FI_LOG_EP_CTRL, "\n");

	slab = calloc(1, sizeof(*slab));
	if (!slab) {
		error = strerror_r(errno, error_buf, sizeof(error_buf));
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "Error allocating slab: %s\n",
			  error);
		ret = -FI_ENOMEM;
		goto err_slab_calloc;
	}

	total_size = handle->page_size * __page_count(handle);
	GNIX_DEBUG(FI_LOG_EP_CTRL, "total_size requested for mmap: %zu.\n",
		   total_size);

	slab->used = calloc(1, sizeof(*(slab->used)));
	if (!slab->used) {
		error = strerror_r(errno, error_buf, sizeof(error_buf));
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "Error allocating bitmap: %s\n",
			  error);
		ret = -FI_ENOMEM;
		goto err_bitmap_calloc;
	}

	slab->base = mmap(0, total_size, (PROT_READ | PROT_WRITE), MAP_SHARED,
			  handle->fd, handle->last_offset);
	if (slab->base == MAP_FAILED) {
		error = strerror_r(errno, error_buf, sizeof(error_buf));
		GNIX_WARN(FI_LOG_EP_CTRL, "%s\n", error);
		ret = -FI_ENOMEM;
		goto err_mmap;
	}

	ret = _gnix_alloc_bitmap(slab->used, __mbox_count(handle), NULL);
	if (ret) {
		GNIX_WARN(FI_LOG_EP_CTRL, "Error allocating bitmap.\n");
		goto err_alloc_bitmap;
	}

	COND_ACQUIRE(handle->nic_handle->requires_lock, &handle->nic_handle->lock);
	if (handle->nic_handle->using_vmdh) {
		info = _gnix_auth_key_lookup(GNIX_PROV_DEFAULT_AUTH_KEY,
				GNIX_PROV_DEFAULT_AUTH_KEYLEN);
		assert(info);

		if (!handle->nic_handle->mdd_resources_set) {
			/* check to see if the ptag registration limit was set
			 * yet or not -- becomes read-only after success */
			_gnix_auth_key_enable(info);

			status = GNI_SetMddResources(
				handle->nic_handle->gni_nic_hndl,
				(info->attr.prov_key_limit +
				 info->attr.user_key_limit));
			assert(status == GNI_RC_SUCCESS);

			handle->nic_handle->mdd_resources_set = 1;
		}

		vmdh_index = _gnix_get_next_reserved_key(info);
		if (vmdh_index <= 0) {
			GNIX_FATAL(FI_LOG_DOMAIN,
				"failed to get reserved key for mbox "
				"registration, rc=%d\n",
				vmdh_index);
		}
		flags |= GNI_MEM_USE_VMDH;
	}

	status = GNI_MemRegister(handle->nic_handle->gni_nic_hndl,
				 (uint64_t) slab->base, total_size,
				 handle->cq_handle,
				 flags, vmdh_index,
				 &slab->memory_handle);
	COND_RELEASE(handle->nic_handle->requires_lock, &handle->nic_handle->lock);
	if (status != GNI_RC_SUCCESS) {
		GNIX_WARN(FI_LOG_EP_CTRL, "GNI_MemRegister failed: %s\n",
			  gni_err_str[status]);
		ret = gnixu_to_fi_errno(status);
		goto err_memregister;
	}

	slab->allocator = handle;

	gnix_slist_insert_tail(&slab->list_entry, &handle->slab_list);

	handle->last_offset += total_size;

	return ret;

err_memregister:
	_gnix_free_bitmap(slab->used);
err_alloc_bitmap:
	munmap(slab->base, total_size);
err_mmap:
	free(slab->used);
err_bitmap_calloc:
	free(slab);
err_slab_calloc:
	return ret;
}
static int __gnix_auth_key_set_val(
	uint8_t *auth_key,
	size_t auth_key_size,
	gnix_auth_key_opt_t opt,
	void *val)
{
	struct gnix_auth_key *info;
	int v;
	int ret;

	if (!val)
		return -FI_EINVAL;

	info = _gnix_auth_key_lookup(auth_key, auth_key_size);

	if (!info) {
		ret = __gnix_auth_key_initialize(auth_key, auth_key_size, NULL);
		assert(ret == FI_SUCCESS);

		info = _gnix_auth_key_lookup(auth_key, auth_key_size);
		assert(info);
	}

	/* if the limits have already been set, and the user is
	 * trying to modify it, kick it back */
	if (opt == GNIX_USER_KEY_LIMIT || opt == GNIX_PROV_KEY_LIMIT) {
		fastlock_acquire(&info->lock);
		if (info->enabled) {
			fastlock_release(&info->lock);
			GNIX_INFO(FI_LOG_FABRIC, "authorization key already "
				"enabled and cannot be modified\n");
			return -FI_EAGAIN;
		}
	}

	switch (opt) {
	case GNIX_USER_KEY_LIMIT:
		v = *(int *) val;
		if (v >= GNIX_MAX_SCALABLE_REGISTRATIONS) {
			GNIX_ERR(FI_LOG_FABRIC,
				"User is requesting more registrations than is present on node\n");
			ret = -FI_EINVAL;
		} else
			info->attr.user_key_limit = v;
		fastlock_release(&info->lock);
		break;
	case GNIX_PROV_KEY_LIMIT:
		v = *(int *) val;
		if (v >= GNIX_MAX_SCALABLE_REGISTRATIONS) {
			GNIX_ERR(FI_LOG_FABRIC,
				"User is requesting more registrations than is present on node\n");
			ret = -FI_EINVAL;
		}
		info->attr.prov_key_limit = v;
		fastlock_release(&info->lock);
		break;
	case GNIX_TOTAL_KEYS_NEEDED:
		GNIX_WARN(FI_LOG_FABRIC,
			"GNIX_TOTAL_KEYS_NEEDED is not a definable value.\n");
		return -FI_EOPNOTSUPP;
	default:
		GNIX_WARN(FI_LOG_FABRIC, ("Invalid fab_ops_val\n"));
		return -FI_EINVAL;
	}

	return ret;
}