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
Test(gnix_cancel, cancel_ep_send)
{
	int ret;
	struct gnix_fid_ep *gnix_ep;
	struct gnix_fab_req *req;
	struct fi_cq_err_entry buf;
	struct gnix_vc *vc;
	void *foobar_ptr = NULL;
	gnix_ht_key_t *key;

	/* simulate a posted request */
	gnix_ep = container_of(ep[0], struct gnix_fid_ep, ep_fid);
	req = _gnix_fr_alloc(gnix_ep);

	req->msg.send_info[0].send_addr = 0xdeadbeef;
	req->msg.cum_send_len = req->msg.send_info[0].send_len = 128;
	req->user_context = foobar_ptr;
	req->type = GNIX_FAB_RQ_SEND;

	/* allocate, store vc */
	ret = _gnix_vc_alloc(gnix_ep, NULL, &vc);
	cr_assert(ret == FI_SUCCESS, "_gnix_vc_alloc failed");

	key = (gnix_ht_key_t *)&gnix_ep->my_name.gnix_addr;
	ret = _gnix_ht_insert(gnix_ep->vc_ht, *key, vc);
	cr_assert(!ret);

	/* make a dummy request */
	fastlock_acquire(&vc->tx_queue_lock);
	dlist_insert_head(&req->dlist, &vc->tx_queue);
	fastlock_release(&vc->tx_queue_lock);

	/* cancel simulated request */
	ret = fi_cancel(&ep[0]->fid, foobar_ptr);
	cr_assert(ret == FI_SUCCESS, "fi_cancel failed");

	/* check for event */
	ret = fi_cq_readerr(msg_cq[0], &buf, FI_SEND);
	cr_assert(ret == 1, "did not find one error event");

	cr_assert(buf.buf == (void *) 0xdeadbeef, "buffer mismatch");
	cr_assert(buf.data == 0, "data mismatch");
	cr_assert(buf.err == FI_ECANCELED, "error code mismatch");
	cr_assert(buf.prov_errno == FI_ECANCELED, "prov error code mismatch");
	cr_assert(buf.len == 128, "length mismatch");
}
Exemple #5
0
Test(vc_management_auto, vc_connect)
{
	int ret;
	struct gnix_vc *vc_conn;
	struct gnix_fid_ep *ep_priv[2];
	gnix_ht_key_t key;
	enum gnix_vc_conn_state state;

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

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

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

	memcpy(&key, &gni_addr[1],
		sizeof(gnix_ht_key_t));

	ret = _gnix_ht_insert(ep_priv[0]->vc_ht, key, vc_conn);
	cr_assert_eq(ret, FI_SUCCESS);
	vc_conn->modes |= GNIX_VC_MODE_IN_HT;

	ret = _gnix_vc_connect(vc_conn);
	cr_assert_eq(ret, FI_SUCCESS);

	/*
	 * since we asked for FI_PROGRESS_AUTO for control
	 * we can just spin here.  add a yield in case the
	 * test is only being run on one cpu.
	 */

	state = GNIX_VC_CONN_NONE;
	while (state != GNIX_VC_CONNECTED) {
		pthread_yield();
		state = _gnix_vc_state(vc_conn);
	}

	ret = _gnix_vc_disconnect(vc_conn);
	cr_assert_eq(ret, FI_SUCCESS);

	/* VC is destroyed by the EP */
}
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;
}
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
/*
 * connect to self, since we use a lock here
 * the only case we need to deal with is one
 * vc connect request with the peer vc not yet
 * being set up
 */
static int __gnix_vc_connect_to_same_cm_nic(struct gnix_vc *vc)
{
	int ret = FI_SUCCESS;
	struct gnix_fid_domain *dom = NULL;
	struct gnix_fid_ep *ep = NULL;
	struct gnix_fid_ep *ep_peer = NULL;
	struct gnix_cm_nic *cm_nic = NULL;
	struct gnix_mbox *mbox = NULL, *mbox_peer = NULL;
	struct gnix_vc *vc_peer;
	gni_smsg_attr_t smsg_mbox_attr;
	gni_smsg_attr_t smsg_mbox_attr_peer;
	gnix_ht_key_t *key_ptr;
	struct gnix_av_addr_entry entry;

	GNIX_TRACE(FI_LOG_EP_CTRL, "\n");

	ep = vc->ep;
	if (ep == NULL)
		return -FI_EINVAL;

	cm_nic = ep->cm_nic;
	if (cm_nic == NULL) {
		ret = -FI_EINVAL;
		goto exit;
	}

	dom = ep->domain;
	if (dom == NULL) {
		ret = -FI_EINVAL;
		goto exit;
	}

	fastlock_acquire(&ep->vc_ht_lock);
	if ((vc->conn_state == GNIX_VC_CONNECTING) ||
	    (vc->conn_state == GNIX_VC_CONNECTED)) {
		fastlock_release(&ep->vc_ht_lock);
		return FI_SUCCESS;
	} else
		vc->conn_state = GNIX_VC_CONNECTING;

	fastlock_release(&ep->vc_ht_lock);

	GNIX_DEBUG(FI_LOG_EP_CTRL, "moving vc %p state to connecting\n", vc);


	if (vc->smsg_mbox == NULL) {
		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 exit;
		}
		vc->smsg_mbox = mbox;
	} else
		mbox = vc->smsg_mbox;

	smsg_mbox_attr.msg_type = GNI_SMSG_TYPE_MBOX_AUTO_RETRANSMIT;
	smsg_mbox_attr.msg_buffer = mbox->base;
	smsg_mbox_attr.buff_size =  vc->ep->nic->mem_per_mbox;
	smsg_mbox_attr.mem_hndl = *mbox->memory_handle;
	smsg_mbox_attr.mbox_offset = (uint64_t)mbox->offset;
	smsg_mbox_attr.mbox_maxcredit = dom->params.mbox_maxcredit;
	smsg_mbox_attr.msg_maxsize = dom->params.mbox_msg_maxsize;

	key_ptr = (gnix_ht_key_t *)&vc->peer_addr;
	ep_peer = (struct gnix_fid_ep *)_gnix_ht_lookup(cm_nic->addr_to_ep_ht,
						   *key_ptr);
	if (ep_peer == NULL) {
		GNIX_WARN(FI_LOG_EP_DATA,
			  "_gnix_ht_lookup addr_to_ep failed\n");
		ret = -FI_ENOENT;
		goto exit;
	}

	key_ptr = (gnix_ht_key_t *)&ep->my_name.gnix_addr;

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

	/*
	 * handle the special case of connecting to self
	 */

	if (vc_peer == vc) {
		ret = __gnix_vc_smsg_init(vc, vc->vc_id, &smsg_mbox_attr);
		if (ret != FI_SUCCESS) {
			GNIX_WARN(FI_LOG_EP_DATA,
				  "_gnix_vc_smsg_init returned %s\n",
				  fi_strerror(-ret));
			goto exit_w_lock;
		}
		vc->conn_state = GNIX_VC_CONNECTED;
		GNIX_DEBUG(FI_LOG_EP_CTRL, "moving vc %p state to connected\n",
			   vc);
		goto exit_w_lock;
	}

	if ((vc_peer != NULL) &&
	    (vc_peer->conn_state != GNIX_VC_CONN_NONE)) {
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "_gnix_vc_connect self, vc_peer in inconsistent state\n");
		ret = -FI_ENOSPC;
		goto exit_w_lock;
	}

	if (vc_peer == NULL) {
		entry.gnix_addr = ep->my_name.gnix_addr;
		entry.cm_nic_cdm_id = ep->my_name.cm_nic_cdm_id;
		ret = _gnix_vc_alloc(ep_peer,
				     &entry,
				     &vc_peer);
		if (ret != FI_SUCCESS) {
			GNIX_WARN(FI_LOG_EP_CTRL,
				"_gnix_vc_alloc returned %s\n",
				fi_strerror(-ret));
			goto exit_w_lock;
		}

		ret = _gnix_ht_insert(ep_peer->vc_ht,
				      *key_ptr,
				      vc_peer);
		if (ret != FI_SUCCESS) {
			GNIX_WARN(FI_LOG_EP_CTRL,
				  "_gnix_ht_insert returned %s\n",
				  fi_strerror(-ret));
			goto exit_w_lock;
		}
		vc_peer->modes |= GNIX_VC_MODE_IN_HT;
	}

	vc_peer->conn_state = GNIX_VC_CONNECTING;
	GNIX_DEBUG(FI_LOG_EP_CTRL, "moving vc %p state to connecting\n",
		   vc_peer);

	if (vc_peer->smsg_mbox == NULL) {
		ret = _gnix_mbox_alloc(vc_peer->ep->nic->mbox_hndl,
				       &mbox_peer);
		if (ret != FI_SUCCESS) {
			GNIX_WARN(FI_LOG_EP_DATA,
				  "_gnix_mbox_alloc returned %s\n",
				  fi_strerror(-ret));
			goto exit_w_lock;
		}
		vc_peer->smsg_mbox = mbox_peer;
	} else
		mbox_peer = vc_peer->smsg_mbox;

	smsg_mbox_attr_peer.msg_type = GNI_SMSG_TYPE_MBOX_AUTO_RETRANSMIT;
	smsg_mbox_attr_peer.msg_buffer = mbox_peer->base;
	smsg_mbox_attr_peer.buff_size =  vc_peer->ep->nic->mem_per_mbox;
	smsg_mbox_attr_peer.mem_hndl = *mbox_peer->memory_handle;
	smsg_mbox_attr_peer.mbox_offset = (uint64_t)mbox_peer->offset;
	smsg_mbox_attr_peer.mbox_maxcredit = dom->params.mbox_maxcredit;
	smsg_mbox_attr_peer.msg_maxsize = dom->params.mbox_msg_maxsize;

	ret = __gnix_vc_smsg_init(vc, vc_peer->vc_id, &smsg_mbox_attr_peer);
	if (ret != FI_SUCCESS) {
		GNIX_WARN(FI_LOG_EP_DATA,
			  "_gnix_vc_smsg_init returned %s\n",
			  fi_strerror(-ret));
		goto exit_w_lock;
	}

	ret = __gnix_vc_smsg_init(vc_peer, vc->vc_id, &smsg_mbox_attr);
	if (ret != FI_SUCCESS) {
		GNIX_WARN(FI_LOG_EP_DATA,
			  "_gnix_vc_smsg_init returned %s\n",
			  fi_strerror(-ret));
		goto exit_w_lock;
	}

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

exit_w_lock:
	fastlock_release(&ep_peer->vc_ht_lock);
exit:
	return ret;
}