Exemple #1
0
Test(vc_management_auto, vc_lookup_by_id)
{
	int ret;
	struct gnix_vc *vc[2], *vc_chk;
	struct gnix_fid_ep *ep_priv;

	ep_priv = container_of(ep[0], struct gnix_fid_ep, ep_fid);

	ret = _gnix_vc_alloc(ep_priv, gnix_addr[0], &vc[0]);
	cr_assert_eq(ret, FI_SUCCESS);

	ret = _gnix_vc_alloc(ep_priv, gnix_addr[1], &vc[1]);
	cr_assert_eq(ret, FI_SUCCESS);

	vc_chk = __gnix_nic_elem_by_rem_id(ep_priv->nic, vc[0]->vc_id);
	cr_assert_eq(vc_chk, vc[0]);

	vc_chk = __gnix_nic_elem_by_rem_id(ep_priv->nic, vc[1]->vc_id);
	cr_assert_eq(vc_chk, vc[1]);

	ret = _gnix_vc_destroy(vc[0]);
	cr_assert_eq(ret, FI_SUCCESS);

	ret = _gnix_vc_destroy(vc[1]);
	cr_assert_eq(ret, FI_SUCCESS);

}
Exemple #2
0
Test(vc_management_auto, vc_alloc_simple)
{
	int ret;
	struct gnix_vc *vc[2];
	struct gnix_fid_ep *ep_priv;

	ep_priv = container_of(ep[0], struct gnix_fid_ep, ep_fid);

	ret = _gnix_vc_alloc(ep_priv, gnix_addr[0], &vc[0]);
	cr_assert_eq(ret, FI_SUCCESS);

	ret = _gnix_vc_alloc(ep_priv, gnix_addr[1], &vc[1]);
	cr_assert_eq(ret, FI_SUCCESS);

	/*
	 * vc_id's have to be different since the
	 * vc's were allocated using the same ep.
	 */
	cr_assert_neq(vc[0]->vc_id, vc[1]->vc_id);

	ret = _gnix_vc_destroy(vc[0]);
	cr_assert_eq(ret, FI_SUCCESS);

	ret = _gnix_vc_destroy(vc[1]);
	cr_assert_eq(ret, FI_SUCCESS);
}
Exemple #3
0
static int gnix_ep_control(fid_t fid, int command, void *arg)
{
	int i, ret = FI_SUCCESS;
	struct gnix_fid_ep *ep;
	struct gnix_fid_domain *dom;
	struct gnix_vc *vc;

	ep = container_of(fid, struct gnix_fid_ep, ep_fid);

	switch (command) {
	/*
	 * for FI_EP_RDM, post wc datagrams now
	 */
	case FI_ENABLE:
		if (ep->type == FI_EP_RDM) {
			dom = ep->domain;
			for (i = 0; i < dom->fabric->n_wc_dgrams; i++) {
				assert(ep->recv_cq != NULL);
				ret = _gnix_vc_alloc(ep, FI_ADDR_UNSPEC, &vc);
				if (ret != FI_SUCCESS) {
					GNIX_WARN(FI_LOG_EP_CTRL,
				     "_gnix_vc_alloc call returned %d\n", ret);
					goto err;
				}
				ret = _gnix_vc_accept(vc);
				if (ret != FI_SUCCESS) {
					GNIX_WARN(FI_LOG_EP_CTRL,
						"_gnix_vc_accept returned %d\n",
						ret);
					_gnix_vc_destroy(vc);
					goto err;
				} else {
					fastlock_acquire(&ep->vc_list_lock);
					dlist_insert_tail(&vc->entry,
						       &ep->wc_vc_list);
					fastlock_release(&ep->vc_list_lock);
				}
			}
		}
		break;

	case FI_GETFIDFLAG:
	case FI_SETFIDFLAG:
	case FI_ALIAS:
	default:
		return -FI_ENOSYS;
	}

err:
	return ret;
}
Exemple #4
0
static int gnix_ep_close(fid_t fid)
{
	int ret = FI_SUCCESS;
	struct gnix_fid_ep *ep;
	struct gnix_fid_domain *domain;
	struct gnix_nic *nic;
	struct gnix_vc *vc;
	struct gnix_fid_av *av;
	struct gnix_cm_nic *cm_nic;
	struct dlist_entry *p, *head;


	GNIX_TRACE(FI_LOG_EP_CTRL, "\n");

	ep = container_of(fid, struct gnix_fid_ep, ep_fid.fid);
	/* TODO: lots more stuff to do here */

	if (ep->send_cq) {
		_gnix_cq_poll_nic_rem(ep->send_cq, ep->nic);
		atomic_dec(&ep->send_cq->ref_cnt);
	}

	if (ep->recv_cq) {
		_gnix_cq_poll_nic_rem(ep->recv_cq, ep->nic);
		atomic_dec(&ep->recv_cq->ref_cnt);
	}

	if (ep->send_cntr) {
		_gnix_cntr_poll_nic_rem(ep->send_cntr, ep->nic);
		atomic_dec(&ep->send_cntr->ref_cnt);
	}

	if (ep->recv_cntr) {
		_gnix_cntr_poll_nic_rem(ep->recv_cntr, ep->nic);
		atomic_dec(&ep->recv_cntr->ref_cnt);
	}

	if (ep->read_cntr) {
		_gnix_cntr_poll_nic_rem(ep->read_cntr, ep->nic);
		atomic_dec(&ep->read_cntr->ref_cnt);
	}

	if (ep->write_cntr) {
		_gnix_cntr_poll_nic_rem(ep->write_cntr, ep->nic);
		atomic_dec(&ep->write_cntr->ref_cnt);
	}

	domain = ep->domain;
	assert(domain != NULL);
	atomic_dec(&domain->ref_cnt);

	cm_nic = ep->cm_nic;
	assert(cm_nic != NULL);
	_gnix_cm_nic_free(cm_nic);

	nic = ep->nic;
	assert(nic != NULL);

	av = ep->av;
	if (av != NULL)
		atomic_dec(&av->ref_cnt);

	/*
	 * destroy any vc's being used by this EP.
	 */

	head = &ep->wc_vc_list;
	for (p = head->next; p != head; p = p->next) {
		vc = container_of(p, struct gnix_vc, entry);
		dlist_remove(&vc->entry);
		if (vc->conn_state == GNIX_VC_CONNECTED) {
			ret = _gnix_vc_disconnect(vc);
			if (ret != FI_SUCCESS) {
				GNIX_WARN(FI_LOG_EP_CTRL,
				    "_gnix_vc_disconnect returned %d\n",
				     ret);
				goto err;
			}
		}
		ret = _gnix_vc_destroy(vc);
		if (ret != FI_SUCCESS) {
			GNIX_WARN(FI_LOG_EP_CTRL,
			    "_gnix_vc_destroy returned %d\n",
			     ret);
			goto err;
		}
	}

	/*
	 * clean up any vc hash table or vector
	 */

	if (ep->type == FI_EP_RDM) {
		if (ep->vc_ht != NULL) {
			_gnix_ht_destroy(ep->vc_ht);
			free(ep->vc_ht);
			ep->vc_ht = NULL;
		}
	}

	ret = _gnix_nic_free(nic);
	if (ret != FI_SUCCESS) {
		GNIX_WARN(FI_LOG_EP_CTRL,
		    "_gnix_vc_destroy call returned %d\n",
		     ret);
		goto err;
	}

	ep->nic = NULL;

	/*
	 * Free fab_reqs
	 */
	if (atomic_get(&ep->active_fab_reqs) != 0) {
		/* Should we just assert here? */
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "Active requests while closing an endpoint.");
	}
	__fr_freelist_destroy(ep);

	free(ep);

err:
	return ret;
}
DIRECT_FN STATIC int gnix_accept(struct fid_ep *ep, const void *param,
				 size_t paramlen)
{
	int ret;
	struct gnix_vc *vc;
	struct gnix_fid_ep *ep_priv;
	struct gnix_pep_sock_conn *conn;
	struct gnix_pep_sock_connresp resp;
	struct fi_eq_cm_entry eq_entry, *eqe_ptr;
	struct gnix_mbox *mbox = NULL;
	struct gnix_av_addr_entry av_entry;

	if (!ep || (paramlen && !param) || paramlen > GNIX_CM_DATA_MAX_SIZE)
		return -FI_EINVAL;

	ep_priv = container_of(ep, struct gnix_fid_ep, ep_fid.fid);

	COND_ACQUIRE(ep_priv->requires_lock, &ep_priv->vc_lock);

	/* Look up and unpack the connection request used to create this EP. */
	conn = (struct gnix_pep_sock_conn *)ep_priv->info->handle;
	if (!conn || conn->fid.fclass != FI_CLASS_CONNREQ) {
		ret = -FI_EINVAL;
		goto err_unlock;
	}

	/* Create new VC without CM data. */
	av_entry.gnix_addr = ep_priv->dest_addr.gnix_addr;
	av_entry.cm_nic_cdm_id = ep_priv->dest_addr.cm_nic_cdm_id;
	ret = _gnix_vc_alloc(ep_priv, &av_entry, &vc);
	if (ret != FI_SUCCESS) {
		GNIX_WARN(FI_LOG_EP_CTRL, "Failed to create VC: %d\n", ret);
		goto err_unlock;
	}
	ep_priv->vc = vc;
	ep_priv->vc->peer_caps = conn->req.peer_caps;
	ep_priv->vc->peer_id = conn->req.vc_id;

	ret = _gnix_mbox_alloc(vc->ep->nic->mbox_hndl, &mbox);
	if (ret != FI_SUCCESS) {
		GNIX_WARN(FI_LOG_EP_DATA, "_gnix_mbox_alloc returned %s\n",
			  fi_strerror(-ret));
		goto err_mbox_alloc;
	}
	vc->smsg_mbox = mbox;

	/* Initialize the GNI connection. */
	ret = _gnix_vc_smsg_init(vc, conn->req.vc_id,
				 &conn->req.vc_mbox_attr,
				 &conn->req.cq_irq_mdh);
	if (ret != FI_SUCCESS) {
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "_gnix_vc_smsg_init returned %s\n",
			  fi_strerror(-ret));
		goto err_smsg_init;
	}

	vc->conn_state = GNIX_VC_CONNECTED;

	/* Send ACK with VC attrs to allow peer to initialize GNI connection. */
	resp.cmd = GNIX_PEP_SOCK_RESP_ACCEPT;

	resp.vc_id = vc->vc_id;
	resp.vc_mbox_attr.msg_type = GNI_SMSG_TYPE_MBOX_AUTO_RETRANSMIT;
	resp.vc_mbox_attr.msg_buffer = mbox->base;
	resp.vc_mbox_attr.buff_size =  vc->ep->nic->mem_per_mbox;
	resp.vc_mbox_attr.mem_hndl = *mbox->memory_handle;
	resp.vc_mbox_attr.mbox_offset = (uint64_t)mbox->offset;
	resp.vc_mbox_attr.mbox_maxcredit =
			ep_priv->domain->params.mbox_maxcredit;
	resp.vc_mbox_attr.msg_maxsize =
			ep_priv->domain->params.mbox_msg_maxsize;
	resp.cq_irq_mdh = ep_priv->nic->irq_mem_hndl;
	resp.peer_caps = ep_priv->caps;

	resp.cm_data_len = paramlen;
	if (paramlen) {
		eqe_ptr = (struct fi_eq_cm_entry *)resp.eqe_buf;
		memcpy(eqe_ptr->data, param, paramlen);
	}

	ret = write(conn->sock_fd, &resp, sizeof(resp));
	if (ret != sizeof(resp)) {
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "Failed to send resp, errno: %d\n",
			  errno);
		ret = -FI_EIO;
		goto err_write;
	}

	/* Notify user that this side is connected. */
	eq_entry.fid = &ep_priv->ep_fid.fid;

	ret = fi_eq_write(&ep_priv->eq->eq_fid, FI_CONNECTED, &eq_entry,
			  sizeof(eq_entry), 0);
	if (ret != sizeof(eq_entry)) {
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "fi_eq_write failed, err: %d\n", ret);
		goto err_eq_write;
	}

	/* Free the connection request. */
	free(conn);

	ep_priv->conn_state = GNIX_EP_CONNECTED;

	COND_RELEASE(ep_priv->requires_lock, &ep_priv->vc_lock);

	GNIX_DEBUG(FI_LOG_EP_CTRL, "Sent conn accept: %p\n", ep_priv);

	return FI_SUCCESS;

err_eq_write:
err_write:
err_smsg_init:
	_gnix_mbox_free(ep_priv->vc->smsg_mbox);
	ep_priv->vc->smsg_mbox = NULL;
err_mbox_alloc:
	_gnix_vc_destroy(ep_priv->vc);
	ep_priv->vc = NULL;
err_unlock:
	COND_RELEASE(ep_priv->requires_lock, &ep_priv->vc_lock);

	return ret;
}
DIRECT_FN STATIC int gnix_connect(struct fid_ep *ep, const void *addr,
				  const void *param, size_t paramlen)
{
	int ret;
	struct gnix_fid_ep *ep_priv;
	struct sockaddr_in saddr;
	struct gnix_pep_sock_connreq req;
	struct fi_eq_cm_entry *eqe_ptr;
	struct gnix_vc *vc;
	struct gnix_mbox *mbox = NULL;
	struct gnix_av_addr_entry av_entry;

	if (!ep || !addr || (paramlen && !param) ||
	    paramlen > GNIX_CM_DATA_MAX_SIZE)
		return -FI_EINVAL;

	ep_priv = container_of(ep, struct gnix_fid_ep, ep_fid.fid);

	COND_ACQUIRE(ep_priv->requires_lock, &ep_priv->vc_lock);

	if (ep_priv->conn_state != GNIX_EP_UNCONNECTED) {
		ret = -FI_EINVAL;
		goto err_unlock;
	}

	ret = _gnix_pe_to_ip(addr, &saddr);
	if (ret != FI_SUCCESS) {
		GNIX_INFO(FI_LOG_EP_CTRL,
			  "Failed to translate gnix_ep_name to IP\n");
		goto err_unlock;
	}

	/* Create new VC without CM data. */
	av_entry.gnix_addr = ep_priv->dest_addr.gnix_addr;
	av_entry.cm_nic_cdm_id = ep_priv->dest_addr.cm_nic_cdm_id;
	ret = _gnix_vc_alloc(ep_priv, &av_entry, &vc);
	if (ret != FI_SUCCESS) {
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "Failed to create VC:: %d\n",
			  ret);
		goto err_unlock;
	}
	ep_priv->vc = vc;

	ret = _gnix_mbox_alloc(vc->ep->nic->mbox_hndl, &mbox);
	if (ret != FI_SUCCESS) {
		GNIX_WARN(FI_LOG_EP_DATA,
			  "_gnix_mbox_alloc returned %s\n",
			  fi_strerror(-ret));
		goto err_mbox_alloc;
	}
	vc->smsg_mbox = mbox;

	ep_priv->conn_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (ep_priv->conn_fd < 0) {
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "Failed to create connect socket, errno: %d\n",
			  errno);
		ret = -FI_ENOSPC;
		goto err_socket;
	}

	/* Currently blocks until connected. */
	ret = connect(ep_priv->conn_fd, (struct sockaddr *)&saddr,
		      sizeof(saddr));
	if (ret) {
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "Failed to connect, errno: %d\n",
			  errno);
		ret = -FI_EIO;
		goto err_connect;
	}

	req.info = *ep_priv->info;

	/* Note addrs are swapped. */
	memcpy(&req.dest_addr, (void *)&ep_priv->src_addr,
	       sizeof(req.dest_addr));
	memcpy(&ep_priv->dest_addr, addr, sizeof(ep_priv->dest_addr));
	memcpy(&req.src_addr, addr, sizeof(req.src_addr));

	if (ep_priv->info->tx_attr)
		req.tx_attr = *ep_priv->info->tx_attr;
	if (ep_priv->info->rx_attr)
		req.rx_attr = *ep_priv->info->rx_attr;
	if (ep_priv->info->ep_attr)
		req.ep_attr = *ep_priv->info->ep_attr;
	if (ep_priv->info->domain_attr)
		req.domain_attr = *ep_priv->info->domain_attr;
	if (ep_priv->info->fabric_attr)
		req.fabric_attr = *ep_priv->info->fabric_attr;

	req.fabric_attr.fabric = NULL;
	req.domain_attr.domain = NULL;

	req.vc_id = vc->vc_id;
	req.vc_mbox_attr.msg_type = GNI_SMSG_TYPE_MBOX_AUTO_RETRANSMIT;
	req.vc_mbox_attr.msg_buffer = mbox->base;
	req.vc_mbox_attr.buff_size =  vc->ep->nic->mem_per_mbox;
	req.vc_mbox_attr.mem_hndl = *mbox->memory_handle;
	req.vc_mbox_attr.mbox_offset = (uint64_t)mbox->offset;
	req.vc_mbox_attr.mbox_maxcredit =
			ep_priv->domain->params.mbox_maxcredit;
	req.vc_mbox_attr.msg_maxsize = ep_priv->domain->params.mbox_msg_maxsize;
	req.cq_irq_mdh = ep_priv->nic->irq_mem_hndl;
	req.peer_caps = ep_priv->caps;

	req.cm_data_len = paramlen;
	if (paramlen) {
		eqe_ptr = (struct fi_eq_cm_entry *)req.eqe_buf;
		memcpy(eqe_ptr->data, param, paramlen);
	}

	ret = write(ep_priv->conn_fd, &req, sizeof(req));
	if (ret != sizeof(req)) {
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "Failed to send req, errno: %d\n",
			  errno);
		ret = -FI_EIO;
		goto err_write;
	}
	/* set fd to non-blocking now since we can't block within the eq
	 * progress system
	 */
	fi_fd_nonblock(ep_priv->conn_fd);

	ep_priv->conn_state = GNIX_EP_CONNECTING;

	COND_RELEASE(ep_priv->requires_lock, &ep_priv->vc_lock);

	GNIX_DEBUG(FI_LOG_EP_CTRL, "Sent conn req: %p, %s\n",
		   ep_priv, inet_ntoa(saddr.sin_addr));

	return FI_SUCCESS;

err_write:
err_connect:
	close(ep_priv->conn_fd);
	ep_priv->conn_fd = -1;
err_socket:
	_gnix_mbox_free(ep_priv->vc->smsg_mbox);
	ep_priv->vc->smsg_mbox = NULL;
err_mbox_alloc:
	_gnix_vc_destroy(ep_priv->vc);
	ep_priv->vc = NULL;
err_unlock:
	COND_RELEASE(ep_priv->requires_lock, &ep_priv->vc_lock);

	return ret;
}
/* Process a connection response on an FI_EP_MSG. */
static int __gnix_ep_connresp(struct gnix_fid_ep *ep,
			      struct gnix_pep_sock_connresp *resp)
{
	int ret = FI_SUCCESS;
	struct fi_eq_cm_entry *eq_entry;
	int eqe_size;

	switch (resp->cmd) {
	case GNIX_PEP_SOCK_RESP_ACCEPT:
		ep->vc->peer_caps = resp->peer_caps;
		ep->vc->peer_id = resp->vc_id;

		/* Initialize the GNI connection. */
		ret = _gnix_vc_smsg_init(ep->vc, resp->vc_id,
					 &resp->vc_mbox_attr,
					 &resp->cq_irq_mdh);
		if (ret != FI_SUCCESS) {
			GNIX_WARN(FI_LOG_EP_CTRL,
				  "_gnix_vc_smsg_init returned %s\n",
				  fi_strerror(-ret));
			return ret;
		}

		ep->vc->conn_state = GNIX_VC_CONNECTED;
		ep->conn_state = GNIX_EP_CONNECTED;

		/* Notify user that this side is connected. */
		eq_entry = (struct fi_eq_cm_entry *)resp->eqe_buf;
		eq_entry->fid = &ep->ep_fid.fid;

		eqe_size = sizeof(*eq_entry) + resp->cm_data_len;
		ret = fi_eq_write(&ep->eq->eq_fid, FI_CONNECTED, eq_entry,
				  eqe_size, 0);
		if (ret != eqe_size) {
			GNIX_WARN(FI_LOG_EP_CTRL,
				  "fi_eq_write failed, err: %d\n", ret);
			return ret;
		}

		GNIX_DEBUG(FI_LOG_EP_CTRL, "Received conn accept: %p\n", ep);

		break;
	case GNIX_PEP_SOCK_RESP_REJECT:
		/* Undo the connect and generate a failure EQE. */
		close(ep->conn_fd);
		ep->conn_fd = -1;

		_gnix_mbox_free(ep->vc->smsg_mbox);
		ep->vc->smsg_mbox = NULL;

		_gnix_vc_destroy(ep->vc);
		ep->vc = NULL;

		ep->conn_state = GNIX_EP_UNCONNECTED;

		/* Generate EQE. */
		eq_entry = (struct fi_eq_cm_entry *)resp->eqe_buf;
		eq_entry->fid = &ep->ep_fid.fid;

		eq_entry = (struct fi_eq_cm_entry *)resp->eqe_buf;
		ret = _gnix_eq_write_error(ep->eq, &ep->ep_fid.fid, NULL, 0,
					   FI_ECONNREFUSED, FI_ECONNREFUSED,
					   &eq_entry->data, resp->cm_data_len);
		if (ret != FI_SUCCESS) {
			GNIX_WARN(FI_LOG_EP_CTRL,
				  "fi_eq_write failed, err: %d\n", ret);
			return ret;
		}

		GNIX_DEBUG(FI_LOG_EP_CTRL, "Conn rejected: %p\n", ep);

		break;
	default:
		GNIX_INFO(FI_LOG_EP_CTRL, "Invalid response command: %d\n",
			  resp->cmd);
		return -FI_EINVAL;
	}

	return FI_SUCCESS;
}
Exemple #8
0
static int __gnix_vc_hndl_conn_req(struct gnix_cm_nic *cm_nic,
				   char *msg_buffer,
				   struct gnix_address src_cm_nic_addr)
{
	int ret = FI_SUCCESS;
	gni_return_t __attribute__((unused)) status;
	struct gnix_fid_ep *ep = NULL;
	gnix_ht_key_t *key_ptr;
	struct gnix_av_addr_entry entry;
	struct gnix_address src_addr, target_addr;
	struct gnix_vc *vc = NULL;
	struct gnix_vc *vc_try = NULL;
	struct gnix_work_req *work_req;
	int src_vc_id;
	gni_smsg_attr_t src_smsg_attr;
	uint64_t src_vc_ptr;
	struct wq_hndl_conn_req *data = NULL;

	ssize_t __attribute__((unused)) len;

	GNIX_TRACE(FI_LOG_EP_CTRL, "\n");

	/*
	 * unpack the message
	 */

	__gnix_vc_unpack_conn_req(msg_buffer,
				  &target_addr,
				  &src_addr,
				  &src_vc_id,
				  &src_vc_ptr,
				  &src_smsg_attr);


	GNIX_DEBUG(FI_LOG_EP_CTRL,
		"conn req rx: (From Aries addr 0x%x Id %d to Aries 0x%x Id %d src vc 0x%lx )\n",
		 src_addr.device_addr,
		 src_addr.cdm_id,
		 target_addr.device_addr,
		 target_addr.cdm_id,
		 src_vc_ptr);

	/*
	 * lookup the ep from the addr_to_ep_ht using the target_addr
	 * in the datagram
	 */

	key_ptr = (gnix_ht_key_t *)&target_addr;

	ep = (struct gnix_fid_ep *)_gnix_ht_lookup(cm_nic->addr_to_ep_ht,
						   *key_ptr);
	if (ep == NULL) {
		GNIX_WARN(FI_LOG_EP_DATA,
			  "_gnix_ht_lookup addr_to_ep failed\n");
		ret = -FI_ENOENT;
		goto err;
	}

	/*
	 * look to see if there is a VC already for the
	 * address of the connecting EP.
	 */

	key_ptr = (gnix_ht_key_t *)&src_addr;

	fastlock_acquire(&ep->vc_ht_lock);
	vc = (struct gnix_vc *)_gnix_ht_lookup(ep->vc_ht,
					       *key_ptr);

	/*
 	 * if there is no corresponding vc in the hash,
 	 * or there is an entry and its not in connecting state
 	 * go down the conn req ack route.
 	 */

	if ((vc == NULL)  ||
	    (vc->conn_state == GNIX_VC_CONN_NONE)) {
		if (vc == NULL) {
			entry.gnix_addr = src_addr;
			entry.cm_nic_cdm_id = src_cm_nic_addr.cdm_id;
			ret = _gnix_vc_alloc(ep,
					     &entry,
					     &vc_try);
			if (ret != FI_SUCCESS) {
				GNIX_WARN(FI_LOG_EP_CTRL,
					  "_gnix_vc_alloc returned %s\n",
					  fi_strerror(-ret));
				goto err;
			}

			vc_try->conn_state = GNIX_VC_CONNECTING;
			ret = _gnix_ht_insert(ep->vc_ht,
					      *key_ptr,
					      vc_try);
			if (likely(ret == FI_SUCCESS)) {
				vc = vc_try;
				vc->modes |= GNIX_VC_MODE_IN_HT;
			} else if (ret == -FI_ENOSPC) {
				_gnix_vc_destroy(vc_try);
			} else {
				GNIX_WARN(FI_LOG_EP_DATA,
				  "_gnix_ht_insert returned %s\n",
				   fi_strerror(-ret));
				goto err;
			}
		} else
			vc->conn_state = GNIX_VC_CONNECTING;

		/*
		 * prepare a work request to
		 * initiate an request response
		 */

		work_req = calloc(1, sizeof(*work_req));
		if (work_req == NULL) {
			ret = -FI_ENOMEM;
			goto err;
		}

		data = calloc(1, sizeof(struct wq_hndl_conn_req));
		if (data == NULL) {
			ret = -FI_ENOMEM;
			goto err;
		}
		memcpy(&data->src_smsg_attr,
		       &src_smsg_attr,
		       sizeof(src_smsg_attr));
		data->vc = vc;
		data->src_vc_id = src_vc_id;
		data->src_vc_ptr = src_vc_ptr;

		work_req->progress_fn = __gnix_vc_conn_ack_prog_fn;
		work_req->data = data;
		work_req->completer_fn = __gnix_vc_conn_ack_comp_fn;
		work_req->completer_data = data;

		/*
		 * add the work request to the tail of the
		 * cm_nic's work queue, progress the cm_nic.
		 */


		fastlock_acquire(&cm_nic->wq_lock);
		dlist_insert_before(&work_req->list, &cm_nic->cm_nic_wq);
		fastlock_release(&cm_nic->wq_lock);

		fastlock_release(&ep->vc_ht_lock);

		_gnix_vc_schedule(vc);
		ret = _gnix_cm_nic_progress(cm_nic);
		if (ret != FI_SUCCESS)
			GNIX_WARN(FI_LOG_EP_CTRL,
				"_gnix_cm_nic_progress returned %s\n",
				fi_strerror(-ret));

	} else {

		/*
		 * we can only be in connecting state if we
		 * reach here.  We have all the informatinon,
		 * and the other side will get the information
		 * at some point, so go ahead and build SMSG connection.
		 */
		if (vc->conn_state != GNIX_VC_CONNECTING) {
			GNIX_WARN(FI_LOG_EP_CTRL,
				 "vc %p not in connecting state nor in cm wq\n",
				  vc, vc->conn_state);
			ret = -FI_EINVAL;
			goto err;
		}

		ret = __gnix_vc_smsg_init(vc, src_vc_id,
					  &src_smsg_attr);
		if (ret != FI_SUCCESS) {
			GNIX_WARN(FI_LOG_EP_CTRL,
				  "_gnix_vc_smsg_init returned %s\n",
				  fi_strerror(-ret));
			goto err;
		}

		vc->conn_state = GNIX_VC_CONNECTED;
		GNIX_DEBUG(FI_LOG_EP_CTRL, "moving vc %p state to connected\n",
			vc);

		fastlock_release(&ep->vc_ht_lock);

		ret = _gnix_vc_schedule(vc);
		ret = _gnix_cm_nic_progress(cm_nic);
		if (ret != FI_SUCCESS)
			GNIX_WARN(FI_LOG_EP_CTRL,
				"_gnix_cm_nic_progress returned %s\n",
				fi_strerror(-ret));
	}
err:
	return ret;
}
Exemple #9
0
static void __gnix_vc_destroy_ht_entry(void *val)
{
	struct gnix_vc *vc = (struct gnix_vc *) val;

	_gnix_vc_destroy(vc);
}