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); }
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); }
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; }
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"); }
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; }
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; }
/* * 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; }