/* * dapls_ib_reject_connection * * Perform necessary steps to reject a connection * * Input: * cr_handle * * Output: * none * * Returns: * DAT_SUCCESS * DAT_INSUFFICIENT_RESOURCES * DAT_INVALID_PARAMETER * */ DAT_RETURN dapls_ib_reject_connection(IN ib_cm_handle_t cm_handle, IN int reject_reason, IN DAPL_SP *sp_ptr) { dapl_cr_reject_t args; int retval; args.crr_reason = reject_reason; args.crr_bkl_cookie = (uint64_t)cm_handle; args.crr_sp_hkey = sp_ptr->cm_srvc_handle->sv_sp_hkey; dapl_dbg_log(DAPL_DBG_TYPE_CM, "dapls_ib_reject: fd %d, sp_hkey %016llx, bkl_index 0x%llx\n", sp_ptr->header.owner_ia->hca_ptr->ib_hca_handle->ia_fd, args.crr_sp_hkey, args.crr_bkl_cookie); retval = ioctl(sp_ptr->header.owner_ia->hca_ptr->ib_hca_handle->ia_fd, DAPL_CR_REJECT, &args); if (retval != 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "dapls_ib_reject: reject failed %s\n", strerror(errno)); return (dapls_convert_error(errno, retval)); } return (DAT_SUCCESS); }
/* ARGSUSED */ DAT_RETURN dapls_ib_disconnect(IN DAPL_EP *ep_ptr, IN DAT_CLOSE_FLAGS close_flags) { dapl_ep_disconnect_t args; struct sockaddr *s; char addr_buf[64]; int retval; if (ep_ptr->qp_handle == NULL) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "dapls_ib_disconnect: qp_handle == NULL\n"); return (DAT_INVALID_PARAMETER); } args.epd_hkey = ep_ptr->qp_handle->ep_hkey; retval = ioctl(ep_ptr->header.owner_ia->hca_ptr->ib_hca_handle->ia_fd, DAPL_EP_DISCONNECT, &args); /* no reason for disconnect to fail so transition the state */ ep_ptr->qp_state = IBT_STATE_ERROR; if (retval != 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "dapls_ib_disconnect: disconnect failed %s\n", strerror(errno)); return (dapls_convert_error(errno, retval)); } s = (struct sockaddr *)ep_ptr->param.remote_ia_address_ptr; dapl_dbg_log(DAPL_DBG_TYPE_CM, "dapls_ib_disconnect: disconnected from %s, conn_qual %016llu\n", dapls_inet_ntop(s, addr_buf, 64), ep_ptr->param.remote_port_qual); return (DAT_SUCCESS); }
/* * dapls_ib_handoff_connection * * handoff connection to a different qualifier * * Input: * cr_ptr * cr_handoff * * Output: * none * * Returns: * DAT_SUCCESS * DAT_INSUFFICIENT_RESOURCES * DAT_INVALID_PARAMETER * */ DAT_RETURN dapls_ib_handoff_connection(IN DAPL_CR *cr_ptr, IN DAT_CONN_QUAL cr_handoff) { dapl_cr_handoff_t args; int retval; dapl_dbg_log(DAPL_DBG_TYPE_CM, "dapls_ib_handoff: fd %d, sp_hkey %016llx, " "bkl_index 0x%llx conn_qual %llu\n", cr_ptr->header.owner_ia->hca_ptr->ib_hca_handle->ia_fd, cr_ptr->sp_ptr->cm_srvc_handle->sv_sp_hkey, (uint64_t)cr_ptr->ib_cm_handle, cr_handoff); args.crh_bkl_cookie = (uint64_t)cr_ptr->ib_cm_handle; args.crh_sp_hkey = cr_ptr->sp_ptr->cm_srvc_handle->sv_sp_hkey; args.crh_conn_qual = cr_handoff; retval = ioctl(cr_ptr->header.owner_ia->hca_ptr->ib_hca_handle->ia_fd, DAPL_CR_HANDOFF, &args); if (retval != 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "dapls_ib_handoff: failed %s\n", strerror(errno)); return (dapls_convert_error(errno, retval)); } return (DAT_SUCCESS); }
/* * dapls_create_gid_map() * * Read /usr/local/etc/ibhosts to obtain host names and GIDs. * Create a table containing IP addresses and GIDs which can * be used for lookups. * * This implementation is a simple method providing name services * when more advanced mechanisms do not exist. The proper way * to obtain these mappings is to use a name service such as is * provided by IPoIB on InfiniBand. * * Input: * device_name Name of device as reported by the provider * * Output: * none * * Returns: * char * to string number */ DAT_RETURN dapli_ns_create_gid_map(void) { FILE *f; ib_gid_t gid; char hostname[128]; int rc; struct addrinfo *addr; struct sockaddr_in *si; DAPL_GID_MAP gmt; f = fopen(MAP_FILE, "r"); if (f == NULL) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ERROR: Must have file <%s> " "for IP/GID mappings\n", MAP_FILE); return (DAT_ERROR(DAT_INTERNAL_ERROR, 0)); } rc = fscanf(f, "%s " F64x " " F64x, hostname, &gid.gid_prefix, &gid.gid_guid); while (rc != EOF) { rc = dapls_osd_getaddrinfo(hostname, &addr); if (rc != 0) { /* * hostname not registered in DNS, * provide a dummy value */ dapl_dbg_log(DAPL_DBG_TYPE_ERR, "WARNING: <%s> not registered in " "DNS, using dummy IP value\n", hostname); gmt.ip_address = 0x01020304; } else { /* * Load into the ip/gid mapping table */ si = (struct sockaddr_in *)addr->ai_addr; if (AF_INET == addr->ai_addr->sa_family) { gmt.ip_address = si->sin_addr.s_addr; } else { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "WARNING: <%s> Address family " "not supported, using dummy " "IP value\n", hostname); gmt.ip_address = 0x01020304; } dapls_osd_freeaddrinfo(addr); } gmt.gid.gid_prefix = gid.gid_prefix; gmt.gid.gid_guid = gid.gid_guid; dapli_ns_add_address(&gmt); rc = fscanf(f, "%s " F64x " " F64x, hostname, &gid.gid_prefix, &gid.gid_guid); } (void) fclose(f); return (DAT_SUCCESS); }
/* * dapl_ib_setup_conn_listener * * Have the CM set up a connection listener. * * Input: * ibm_hca_handle HCA handle * qp_handle QP handle * * Output: * none * * Returns: * DAT_SUCCESS * DAT_INSUFFICIENT_RESOURCES * DAT_INVALID_PARAMETER * */ DAT_RETURN dapls_ib_setup_conn_listener(IN DAPL_IA *ia_ptr, IN DAT_UINT64 ServiceID, IN DAPL_SP *sp_ptr) { ib_hca_handle_t hca_hdl = ia_ptr->hca_ptr->ib_hca_handle; struct dapls_ib_cm_srvc_handle *srvc_hdl; dapl_service_register_t args; struct sockaddr *s; char addr_buf[64]; DAPL_EVD *evd_p = (DAPL_EVD *)sp_ptr->evd_handle; int retval; if (hca_hdl == NULL) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "setup_conn_listener: hca_handle == NULL\n"); return (DAT_INVALID_PARAMETER); } if (evd_p == NULL) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "setup_conn_listener: evd_p == NULL\n"); return (DAT_INVALID_PARAMETER); } srvc_hdl = (struct dapls_ib_cm_srvc_handle *) dapl_os_alloc(sizeof (*srvc_hdl)); if (srvc_hdl == NULL) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "setup_conn_listener: srvc_handle == NULL\n"); return (DAT_INSUFFICIENT_RESOURCES); } args.sr_sid = ServiceID; args.sr_evd_hkey = evd_p->ib_cq_handle->evd_hkey; args.sr_sp_cookie = (uintptr_t)sp_ptr; retval = ioctl(hca_hdl->ia_fd, DAPL_SERVICE_REGISTER, &args); if (retval != 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "setup_conn_listener: register failed %s\n", strerror(errno)); dapl_os_free(srvc_hdl, sizeof (*srvc_hdl)); return (dapls_convert_error(errno, retval)); } srvc_hdl->sv_sp_hkey = args.sr_sp_hkey; sp_ptr->cm_srvc_handle = srvc_hdl; sp_ptr->conn_qual = args.sr_retsid; s = (struct sockaddr *)&ia_ptr->hca_ptr->hca_address; dapl_dbg_log(DAPL_DBG_TYPE_CM, "setup_conn_listener: listening on ia_address %s, " "conn_qual %016llu\n\n", dapls_inet_ntop(s, addr_buf, 64), sp_ptr->conn_qual); return (DAT_SUCCESS); }
/* * dapl_ep_recv_query * * uDAPL Version 1.2, 6.6.11 * * Destroy an instance of the Endpoint * * Input: * ep_handle * * Output: * none * * Returns: * DAT_SUCCESS * DAT_INVALID_PARAMETER * DAT_INVALID_HANDLE * DAT_MODEL_NOT_SUPPORTED */ DAT_RETURN DAT_API dapl_ep_recv_query(IN DAT_EP_HANDLE ep_handle, OUT DAT_COUNT * nbufs_allocate, OUT DAT_COUNT * bufs_alloc_span) { DAPL_EP *ep_ptr; DAT_RETURN dat_status; dat_status = DAT_SUCCESS; dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_ep_recv_query (%p, %p, %p)\n", ep_handle, nbufs_allocate, bufs_alloc_span); ep_ptr = (DAPL_EP *) ep_handle; /* * Verify parameter & state */ if (DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); goto bail; } dat_status = DAT_ERROR(DAT_NOT_IMPLEMENTED, DAT_NO_SUBTYPE); bail: return dat_status; }
DAT_RETURN dapl_cr_query( IN DAT_CR_HANDLE cr_handle, IN DAT_CR_PARAM_MASK cr_param_mask, OUT DAT_CR_PARAM *cr_param) { DAPL_CR *cr_ptr; DAT_RETURN dat_status; dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_cr_query (%p, %x, %p)\n", cr_handle, cr_param_mask, cr_param); dat_status = DAT_SUCCESS; if (DAPL_BAD_HANDLE(cr_handle, DAPL_MAGIC_CR)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CR); goto bail; } if (NULL == cr_param) { dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); goto bail; } cr_ptr = (DAPL_CR *) cr_handle; /* since the arguments are easily accessible, ignore the mask */ (void) dapl_os_memcpy(cr_param, &cr_ptr->param, sizeof (DAT_CR_PARAM)); bail: return (dat_status); }
static int dapls_ns_subnet_match_v6(int s, DAPL_IA *ia_ptr, struct sockaddr_in6 *addr) { struct lifreq lifreq; struct sockaddr_in6 netmask_sock; uchar_t *netmask, *local_addr, *dest_addr; int i, retval; (void) dapl_os_strcpy(lifreq.lifr_name, ia_ptr->hca_ptr->name); retval = ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifreq); if (retval < 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_subnet_match_v6: cannot get netmask: %s\n", strerror(errno)); return (-1); } (void) dapl_os_memcpy(&netmask_sock, &lifreq.lifr_addr, sizeof (netmask_sock)); /* * we need to get the interface address here because the * address in ia_ptr->hca_ptr->hca_address might not * necessarily be an IPv6 address. */ retval = ioctl(s, SIOCGLIFADDR, (caddr_t)&lifreq); if (retval < 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_subnet_match_v6: cannot get local addr: %s\n", strerror(errno)); return (-1); } netmask = (uchar_t *)&netmask_sock.sin6_addr; local_addr = (uchar_t *)&((struct sockaddr_in6 *)&lifreq.lifr_addr)-> sin6_addr; dest_addr = (uchar_t *)&addr->sin6_addr; for (i = 0; i < sizeof (addr->sin6_addr); i++) { if (((local_addr[i] ^ dest_addr[i]) & netmask[i]) != 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_subnet_match_v6: subnets do not match\n"); return (-1); } } return (0); }
static int dapls_ns_subnet_match_v4(int s, DAPL_IA *ia_ptr, struct sockaddr_in *addr) { struct lifreq lifreq; int retval; uint32_t netmask, netaddr, netaddr_dest; (void) dapl_os_strcpy(lifreq.lifr_name, ia_ptr->hca_ptr->name); retval = ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifreq); if (retval < 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_subnet_match_v4: cannot get netmask: %s\n", strerror(errno)); return (-1); } netmask = ((struct sockaddr_in *)&lifreq.lifr_addr)-> sin_addr.s_addr; /* * we need to get the interface address here because the * address in ia_ptr->hca_ptr->hca_address might not * necessarily be an IPv4 address. */ retval = ioctl(s, SIOCGLIFADDR, (caddr_t)&lifreq); if (retval < 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_subnet_match_v4: cannot get local addr: %s\n", strerror(errno)); return (-1); } netaddr = ((struct sockaddr_in *)&lifreq.lifr_addr)-> sin_addr.s_addr & netmask; netaddr_dest = addr->sin_addr.s_addr & netmask; if (netaddr != netaddr_dest) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_subnet_match_v4: netaddrs don't match: " "local %x, remote %x\n", netaddr, netaddr_dest); return (-1); } return (0); }
/* * dapl_ep_query * * DAPL Requirements Version xxx, 6.5.5 * * Provide the consumer parameters, including attributes and status of * the Endpoint. * * Input: * ep_handle * ep_param_mask * * Output: * ep_param * * Returns: * DAT_SUCCESS * DAT_INVALID_PARAMETER */ DAT_RETURN DAT_API dapl_ep_query(IN DAT_EP_HANDLE ep_handle, IN DAT_EP_PARAM_MASK ep_param_mask, OUT DAT_EP_PARAM * ep_param) { DAPL_EP *ep_ptr; DAT_RETURN dat_status; dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_ep_query (%p, %x, %p)\n", ep_handle, ep_param_mask, ep_param); dat_status = DAT_SUCCESS; ep_ptr = (DAPL_EP *) ep_handle; /* * Verify parameter & state */ if (DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); goto bail; } if (ep_param == NULL) { dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); goto bail; } /* * Fill in according to user request * * N.B. Just slam all values into the user structure, there * is nothing to be gained by checking for each bit. */ if (ep_param_mask & DAT_EP_FIELD_ALL) { /* only attempt to get remote IA address if consumer requested it */ if (ep_param_mask & DAT_EP_FIELD_REMOTE_IA_ADDRESS_PTR) { if (ep_ptr->param.ep_state == DAT_EP_STATE_CONNECTED) { /* obtain the remote IP address */ dat_status = dapls_ib_cm_remote_addr((DAT_HANDLE) ep_handle, &ep_ptr-> remote_ia_address); } ep_ptr->param.remote_ia_address_ptr = (DAT_IA_ADDRESS_PTR) & ep_ptr->remote_ia_address; } *ep_param = ep_ptr->param; dats_get_ia_handle(ep_ptr->param.ia_handle, &ep_param->ia_handle); } bail: return dat_status; }
static int dapls_ns_send_packet_v6(int s, struct sockaddr_in6 *addr) { if (sendto(s, NULL, 0, MSG_DONTROUTE, (struct sockaddr *)addr, sizeof (*addr)) < 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_send_packet_v6: failed: %s\n", strerror(errno)); return (-1); } return (0); }
/* * dapls_ib_accept_connection * * Perform necessary steps to accept a connection * * Input: * cr_handle * ep_handle * private_data_size * private_data * * Output: * none * * Returns: * DAT_SUCCESS * DAT_INSUFFICIENT_RESOURCES * DAT_INVALID_PARAMETER * */ DAT_RETURN dapls_ib_accept_connection(IN DAT_CR_HANDLE cr_handle, IN DAT_EP_HANDLE ep_handle, IN DAPL_PRIVATE *prd_ptr) { DAPL_EP *ep_p = (DAPL_EP *)ep_handle; DAPL_CR *cr_p = (DAPL_CR *)cr_handle; dapl_cr_accept_t args; int retval; /* check if ep is valid */ if (ep_p->qp_handle == NULL) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "dapls_ib_accept: qp_handle == NULL\n"); return (DAT_INVALID_PARAMETER); } dapl_dbg_log(DAPL_DBG_TYPE_CM, "dapls_ib_accept: fd %d, sp_hkey %016llx, " "bkl_index 0x%llx, ep_hkey %016llx\n", cr_p->header.owner_ia->hca_ptr->ib_hca_handle->ia_fd, cr_p->sp_ptr->cm_srvc_handle->sv_sp_hkey, (uint64_t)cr_p->ib_cm_handle, ep_p->qp_handle->ep_hkey); args.cra_bkl_cookie = (uint64_t)cr_p->ib_cm_handle; args.cra_sp_hkey = cr_p->sp_ptr->cm_srvc_handle->sv_sp_hkey; args.cra_ep_hkey = ep_p->qp_handle->ep_hkey; args.cra_priv_sz = IB_MAX_REP_PDATA_SIZE; bcopy(prd_ptr, args.cra_priv, IB_MAX_REP_PDATA_SIZE); retval = ioctl(cr_p->header.owner_ia->hca_ptr->ib_hca_handle->ia_fd, DAPL_CR_ACCEPT, &args); if (retval != 0) { ep_p->qp_state = IBT_STATE_ERROR; dapl_dbg_log(DAPL_DBG_TYPE_ERR, "dapls_ib_accept: accept failed %s\n", strerror(errno)); return (dapls_convert_error(errno, retval)); } return (DAT_SUCCESS); }
/* * dapli_stup_dummy_addr * * Set up a dummy local address for the HCA. Things are not going * to work too well if this happens. * We call this routine if: * - remote host adapter name is not in DNS * - IPoIB implementation is not correctly set up * - Similar nonsense. * * Input: * hca_ptr * rhost_name Name of remote adapter * * Output: * none * * Returns: * none */ void dapli_setup_dummy_addr(IN DAPL_HCA * hca_ptr, IN char *rhost_name) { struct sockaddr_in *si; /* Not registered in DNS, provide a dummy value */ dapl_dbg_log(DAPL_DBG_TYPE_WARN, "WARNING: <%s> not registered in DNS, using dummy IP value\n", rhost_name); si = (struct sockaddr_in *)&hca_ptr->hca_address; hca_ptr->hca_address.sin6_family = AF_INET; si->sin_addr.s_addr = 0x01020304; }
/* * dapl_ib_remove_conn_listener * * Have the CM remove a connection listener. * * Input: * ia_handle IA handle * ServiceID IB Channel Service ID * * Output: * none * * Returns: * DAT_SUCCESS * DAT_INVALID_PARAMETER * */ DAT_RETURN dapls_ib_remove_conn_listener(IN DAPL_IA *ia_ptr, IN DAPL_SP *sp_ptr) { ib_hca_handle_t hca_hdl = ia_ptr->hca_ptr->ib_hca_handle; struct dapls_ib_cm_srvc_handle *srvc_hdl; dapl_service_deregister_t args; struct sockaddr *s; char addr_buf[64]; int retval; if (hca_hdl == NULL) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "remove_conn_listener: hca_handle == NULL\n"); return (DAT_INVALID_PARAMETER); } srvc_hdl = (struct dapls_ib_cm_srvc_handle *)sp_ptr-> cm_srvc_handle; args.sdr_sp_hkey = srvc_hdl->sv_sp_hkey; retval = ioctl(hca_hdl->ia_fd, DAPL_SERVICE_DEREGISTER, &args); if (retval != 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "remove_conn_listener: deregister failed %s\n", strerror(errno)); return (dapls_convert_error(errno, retval)); } dapl_os_free(srvc_hdl, sizeof (*srvc_hdl)); sp_ptr->cm_srvc_handle = NULL; s = (struct sockaddr *)&ia_ptr->hca_ptr->hca_address; dapl_dbg_log(DAPL_DBG_TYPE_CM, "remove_conn_listener: successful, ia_address %s, " "conn_qual %016llu\n\n", dapls_inet_ntop(s, addr_buf, 64), sp_ptr->conn_qual); return (DAT_SUCCESS); }
/* * dapl_cno_free * * DAPL Requirements Version xxx, 6.3.2.2 * * Destroy a consumer notification object instance * * Input: * cno_handle * * Output: * none * * Returns: * DAT_SUCCESS * DAT_INVALID_HANDLE * DAT_INVALID_STATE */ DAT_RETURN dapl_cno_free( IN DAT_CNO_HANDLE cno_handle) /* cno_handle */ { DAPL_CNO *cno_ptr; DAT_RETURN dat_status; dat_status = DAT_SUCCESS; cno_ptr = (DAPL_CNO *)cno_handle; if (DAPL_BAD_HANDLE(cno_handle, DAPL_MAGIC_CNO)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CNO); goto bail; } if (cno_ptr->cno_ref_count != 0 || cno_ptr->cno_waiters != 0) { dat_status = DAT_ERROR(DAT_INVALID_STATE, DAT_INVALID_STATE_CNO_IN_USE); goto bail; } dapl_os_lock(&cno_ptr->header.lock); if (!dapl_llist_is_empty(&cno_ptr->evd_list_head)) { dapl_dbg_log(DAPL_DBG_TYPE_UTIL, "cno_free: evd list not empty!\n"); dapl_os_unlock(&cno_ptr->header.lock); dat_status = DAT_ERROR(DAT_INVALID_STATE, DAT_INVALID_STATE_CNO_IN_USE); goto bail; } dapl_os_unlock(&cno_ptr->header.lock); dat_status = dapls_ib_cno_free(cno_ptr); if (dat_status != DAT_SUCCESS) { goto bail; } dapl_ia_unlink_cno(cno_ptr->header.owner_ia, cno_ptr); dapl_cno_dealloc(cno_ptr); bail: return (dat_status); }
/* * dapl_sp_remove_cr * * Remove the CR from the PSP. Done prior to freeing the CR resource. * * Input: * sp_ptr * cr_ptr * * Output: * none * * Returns: * void * */ void dapl_sp_remove_cr( IN DAPL_SP *sp_ptr, IN DAPL_CR *cr_ptr) { dapl_os_lock(&sp_ptr->header.lock); if (dapl_llist_is_empty(&sp_ptr->cr_list_head)) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "***dapl_sp_remove_cr: removing from empty queue! sp %p\n", sp_ptr); dapl_os_unlock(&sp_ptr->header.lock); return; } (void) dapl_llist_remove_entry(&sp_ptr->cr_list_head, &cr_ptr->header.ia_list_entry); sp_ptr->cr_list_count--; dapl_os_unlock(&sp_ptr->header.lock); }
/* * dapl_pz_query * * DAPL Requirements Version xxx, 6.6.2.1 * * Return the ia associated with the protection zone pz * * Input: * pz_handle * pz_param_mask * * Output: * pz_param * * Returns: * DAT_SUCCESS * DAT_INVALID_HANDLE * DAT_INVALID_PARAMETER */ DAT_RETURN dapl_pz_query( IN DAT_PZ_HANDLE pz_handle, IN DAT_PZ_PARAM_MASK pz_param_mask, OUT DAT_PZ_PARAM *pz_param) { DAPL_PZ *pz; DAT_RETURN dat_status; dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_pz_query (%p, %x, %p)\n", pz_handle, pz_param_mask, pz_param); dat_status = DAT_SUCCESS; if (DAPL_BAD_HANDLE(pz_handle, DAPL_MAGIC_PZ)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_PZ); goto bail; } if (NULL == pz_param) { dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); goto bail; } if (pz_param_mask & ~DAT_PZ_FIELD_ALL) { dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); goto bail; } pz = (DAPL_PZ *) pz_handle; /* Since the DAT_PZ_ARGS values are easily accessible, */ /* don't bother checking the DAT_PZ_ARGS_MASK value */ pz_param->ia_handle = (DAT_IA_HANDLE) pz->header.owner_ia; bail: return (dat_status); }
/* * dapl_srq_query * * DAPL Requirements Version 1.2, 6.5.6 * * Return SRQ parameters to the consumer * * Input: * srq_handle * srq_param_mask * * Output: * srq_param * * Returns: * DAT_SUCCESS * DAT_INVALID_HANDLE * DAT_INVALID_PARAMETER */ DAT_RETURN DAT_API dapl_srq_query(IN DAT_SRQ_HANDLE srq_handle, IN DAT_SRQ_PARAM_MASK srq_param_mask, OUT DAT_SRQ_PARAM * srq_param) { DAPL_SRQ *srq_ptr; DAT_RETURN dat_status; dat_status = DAT_SUCCESS; dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_srq_query (%p, %x, %p)\n", srq_handle, srq_param_mask, srq_param); if (DAPL_BAD_HANDLE(srq_handle, DAPL_MAGIC_SRQ)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_SRQ); goto bail; } if (srq_param == NULL) { dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); goto bail; } srq_ptr = (DAPL_SRQ *) srq_handle; /* * XXX Need to calculate available_dto_count and outstanding_dto_count */ srq_ptr->param.available_dto_count = DAT_VALUE_UNKNOWN; srq_ptr->param.outstanding_dto_count = DAT_VALUE_UNKNOWN; *srq_param = srq_ptr->param; dats_get_ia_handle(srq_ptr->header.owner_ia, &srq_param->ia_handle); bail: return dat_status; }
DAT_RETURN dapls_ib_connect(IN DAT_EP_HANDLE ep_handle, IN DAT_IA_ADDRESS_PTR remote_ia_address, IN DAT_CONN_QUAL remote_conn_qual, IN DAT_COUNT prd_size, IN DAPL_PRIVATE *prd_ptr, IN DAT_TIMEOUT timeout) { dapl_ep_connect_t args; DAPL_EP *ep_p = (DAPL_EP *)ep_handle; struct sockaddr *s; char addr_buf[64]; ib_gid_t dgid; int retval; struct sockaddr_in6 *v6addr; struct sockaddr_in *v4addr; dapl_ia_addr_t *sap; s = (struct sockaddr *)remote_ia_address; dapl_dbg_log(DAPL_DBG_TYPE_CM, "dapls_ib_connect: ep 0x%p\n" " addr %s, conn_qual %016llu, ep_hkey %016llx\n" " prd_size %d, timeout 0x%x\n", ep_p, dapls_inet_ntop(s, addr_buf, 64), remote_conn_qual, ep_p->qp_handle->ep_hkey, prd_size, timeout); if (ep_p->qp_handle == NULL) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "dapls_ib_connect: ep 0x%p, addr %s, conn_qual %016llu, " "qp_handle == NULL\n", ep_p, dapls_inet_ntop(s, addr_buf, 64), remote_conn_qual); return (DAT_INVALID_PARAMETER); } if (timeout == DAT_TIMEOUT_INFINITE) { args.epc_timeout = 0; } else { args.epc_timeout = timeout; } /* resolve remote address to dgid */ retval = dapls_ns_lookup_address(ep_p->header.owner_ia, remote_ia_address, timeout, &dgid); if (retval == DAT_SUCCESS) { args.epc_dgid = dgid; } else if ((retval & DAT_SUBTYPE_MASK) == DAT_INVALID_ADDRESS_UNREACHABLE) { /* let the kernel driver look up the dgid from ATS */ args.epc_dgid.gid_guid = 0ULL; args.epc_dgid.gid_prefix = 0ULL; } else { return (retval); } args.epc_sid = remote_conn_qual; args.epc_hkey = ep_p->qp_handle->ep_hkey; sap = (dapl_ia_addr_t *)&args.epc_raddr_sadata; /* * filled in the remote_ia_address for consistent though * not necessary when dapls_ns_lookup_address has resolved the dgid */ switch (s->sa_family) { case AF_INET: /* LINTED: E_BAD_PTR_CAST_ALIGN */ v4addr = (struct sockaddr_in *)s; sap->iad_v4pad[0] = 0; sap->iad_v4pad[1] = 0; sap->iad_v4pad[2] = 0; sap->iad_v4 = v4addr->sin_addr; break; case AF_INET6: /* LINTED: E_BAD_PTR_CAST_ALIGN */ v6addr = (struct sockaddr_in6 *)s; sap->iad_v6 = v6addr->sin6_addr; break; } /* establish the hello message */ (void) dapl_os_memzero((void *)&prd_ptr->hello_msg, sizeof (DAPL_HELLO_MSG)); /* on ATS leave the msg blank to avoid confusion to 3rd parties */ if ((args.epc_dgid.gid_guid | args.epc_dgid.gid_prefix)) { prd_ptr->hello_msg.hi_checksum = DAPL_CHECKSUM; prd_ptr->hello_msg.hi_clen = prd_size; prd_ptr->hello_msg.hi_mid = 0; prd_ptr->hello_msg.hi_vers = DAPL_HELLO_MSG_VERS; /* fill in local address */ s = (struct sockaddr *) &ep_p->header.owner_ia->hca_ptr->hca_address; prd_ptr->hello_msg.hi_ipv = (uint8_t)s->sa_family; switch (s->sa_family) { case AF_INET: /* LINTED: E_BAD_PTR_CAST_ALIGN */ v4addr = (struct sockaddr_in *)s; prd_ptr->hello_msg.hi_port = v4addr->sin_port; prd_ptr->hello_msg.hi_v4ipaddr = v4addr->sin_addr; break; case AF_INET6: /* LINTED: E_BAD_PTR_CAST_ALIGN */ v6addr = (struct sockaddr_in6 *)s; prd_ptr->hello_msg.hi_port = v6addr->sin6_port; prd_ptr->hello_msg.hi_v6ipaddr = v6addr->sin6_addr; break; default: break; /* fall through */ } } if (prd_size > 0) { (void) dapl_os_memcpy((void *)&args.epc_priv[0], (void *)prd_ptr, sizeof (DAPL_PRIVATE)); } else { (void) dapl_os_memcpy((void *) &args.epc_priv[DAPL_CONSUMER_MAX_PRIVATE_DATA_SIZE], (void *)&prd_ptr->hello_msg, sizeof (DAPL_HELLO_MSG)); } args.epc_priv_sz = sizeof (DAPL_PRIVATE); retval = ioctl(ep_p->header.owner_ia->hca_ptr->ib_hca_handle->ia_fd, DAPL_EP_CONNECT, &args); if (retval != 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "dapls_ib_connect: connect failed %s, retval %d\n\n", strerror(errno), retval); return (dapls_convert_error(errno, retval)); } dapl_dbg_log(DAPL_DBG_TYPE_CM, "dapls_ib_connect: connected to %s\n\n", dapls_inet_ntop(s, addr_buf, 64)); return (DAT_SUCCESS); }
DAT_RETURN DAT_API dapl_evd_create(IN DAT_IA_HANDLE ia_handle, IN DAT_COUNT evd_min_qlen, IN DAT_CNO_HANDLE cno_handle, IN DAT_EVD_FLAGS evd_flags, OUT DAT_EVD_HANDLE * evd_handle) { DAPL_IA *ia_ptr; DAPL_EVD *evd_ptr; DAPL_CNO *cno_ptr; DAT_RETURN dat_status; DAT_PROVIDER_ATTR provider_attr; int i; int j; int flag_mask[6]; dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_evd_create (%p, %d, %p, 0x%x, %p)\n", ia_handle, evd_min_qlen, cno_handle, evd_flags, evd_handle); ia_ptr = (DAPL_IA *) ia_handle; cno_ptr = (DAPL_CNO *) cno_handle; evd_ptr = NULL; *evd_handle = NULL; dat_status = DAT_SUCCESS; if (DAPL_BAD_HANDLE(ia_handle, DAPL_MAGIC_IA)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); goto bail; } DAPL_CNTR(ia_ptr, DCNT_IA_EVD_CREATE); if (evd_min_qlen <= 0) { dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); goto bail; } if (evd_min_qlen > ia_ptr->hca_ptr->ia_attr.max_evd_qlen) { dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_TEVD); goto bail; } if (cno_handle != DAT_HANDLE_NULL && DAPL_BAD_HANDLE(cno_handle, DAPL_MAGIC_CNO)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CNO); goto bail; } /* * Check the merging attributes to ensure the combination of * flags requested is supported. */ dapl_ia_query(ia_handle, NULL, 0, NULL, DAT_PROVIDER_FIELD_ALL, &provider_attr); /* Set up an array of flags to compare against; the EVD bits are * a sparse array that need to be mapped to the merging flags */ flag_mask[0] = DAT_EVD_SOFTWARE_FLAG; flag_mask[1] = DAT_EVD_CR_FLAG; flag_mask[2] = DAT_EVD_DTO_FLAG; flag_mask[3] = DAT_EVD_CONNECTION_FLAG; flag_mask[4] = DAT_EVD_RMR_BIND_FLAG; flag_mask[5] = DAT_EVD_ASYNC_FLAG; for (i = 0; i < 6; i++) { if (flag_mask[i] & evd_flags) { for (j = 0; j < 6; j++) { if (flag_mask[j] & evd_flags) { if (provider_attr. evd_stream_merging_supported[i][j] == DAT_FALSE) { dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); goto bail; } } } /* end for j */ } } /* end for i */ dat_status = dapls_evd_internal_create(ia_ptr, cno_ptr, evd_min_qlen, evd_flags, &evd_ptr); if (dat_status != DAT_SUCCESS) { goto bail; } evd_ptr->evd_state = DAPL_EVD_STATE_OPEN; *evd_handle = (DAT_EVD_HANDLE) evd_ptr; bail: if (dat_status != DAT_SUCCESS) { if (evd_ptr) { dapl_evd_free(evd_ptr); } } dapl_dbg_log(DAPL_DBG_TYPE_RTN, "dapl_evd_create () returns 0x%x\n", dat_status); return dat_status; }
DAT_RETURN DAT_API dapl_evd_resize(IN DAT_EVD_HANDLE evd_handle, IN DAT_COUNT evd_qlen) { DAPL_IA *ia_ptr; DAPL_EVD *evd_ptr; DAT_COUNT pend_cnt; DAT_RETURN dat_status; dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_evd_resize (%p, %d)\n", evd_handle, evd_qlen); if (DAPL_BAD_HANDLE(evd_handle, DAPL_MAGIC_EVD)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE1); goto bail; } evd_ptr = (DAPL_EVD *) evd_handle; ia_ptr = evd_ptr->header.owner_ia; if (evd_qlen == evd_ptr->qlen) { dat_status = DAT_SUCCESS; goto bail; } if (evd_qlen > ia_ptr->hca_ptr->ia_attr.max_evd_qlen) { dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); goto bail; } dapl_os_lock(&evd_ptr->header.lock); /* Don't try to resize if we are actively waiting */ if (evd_ptr->evd_state == DAPL_EVD_STATE_WAITED) { dapl_os_unlock(&evd_ptr->header.lock); dat_status = DAT_ERROR(DAT_INVALID_STATE, 0); goto bail; } pend_cnt = dapls_rbuf_count(&evd_ptr->pending_event_queue); if (pend_cnt > evd_qlen) { dapl_os_unlock(&evd_ptr->header.lock); dat_status = DAT_ERROR(DAT_INVALID_STATE, 0); goto bail; } if (evd_ptr->ib_cq_handle) { dat_status = dapls_ib_cq_resize(evd_ptr->header.owner_ia, evd_ptr, &evd_qlen); if (dat_status != DAT_SUCCESS) { dapl_os_unlock(&evd_ptr->header.lock); goto bail; } } dat_status = dapls_evd_event_realloc(evd_ptr, evd_qlen); if (dat_status != DAT_SUCCESS) { dapl_os_unlock(&evd_ptr->header.lock); goto bail; } dapl_os_unlock(&evd_ptr->header.lock); bail: return dat_status; }
void dapl_evd_connection_callback( IN ib_cm_handle_t ib_cm_handle, IN const ib_cm_events_t ib_cm_event, IN const void *private_data_ptr, IN const void *context) { DAPL_EP *ep_ptr; DAPL_EVD *evd_ptr; DAPL_PRIVATE *prd_ptr; DAT_EVENT_NUMBER event_type; dapl_dbg_log( DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, "--> dapl_evd_connection_callback: ctxt: %p event: %x" " cm_handle %p\n", context, ib_cm_event, ib_cm_handle); /* * Determine the type of handle passed back to us in the context * and sort out key parameters. */ dapl_os_assert(((DAPL_HEADER *)context)->magic == DAPL_MAGIC_EP || ((DAPL_HEADER *)context)->magic == DAPL_MAGIC_EP_EXIT); /* * Active side of the connection, context is an EP and * PSP is irrelevant. */ ep_ptr = (DAPL_EP *)context; evd_ptr = (DAPL_EVD *)ep_ptr->param.connect_evd_handle; prd_ptr = (DAPL_PRIVATE *)private_data_ptr; switch (ib_cm_event) { case IB_CME_CONNECTED: { /* * If we don't have an EP at this point we are very screwed * up */ DAT_RETURN dat_status; if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECT_PENDING) { /* * If someone pulled the plug on the connection, just * exit */ break; } dapls_ib_connected(ep_ptr); ep_ptr->param.ep_state = DAT_EP_STATE_CONNECTED; ep_ptr->cm_handle = ib_cm_handle; /* copy in the private data */ (void) dapl_os_memcpy(ep_ptr->private_data, prd_ptr->private_data, IB_MAX_REQ_PDATA_SIZE); dat_status = dapls_evd_post_connection_event( evd_ptr, DAT_CONNECTION_EVENT_ESTABLISHED, (DAT_HANDLE) ep_ptr, IB_MAX_REQ_PDATA_SIZE, ep_ptr->private_data); if (dat_status != DAT_SUCCESS) { (void) dapls_ib_disconnect(ep_ptr, DAT_CLOSE_ABRUPT_FLAG); ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECT_PENDING; } /* * If we received any premature DTO completions and * post them to the recv evd now. * there is a race here - if events arrive after we change * the ep state to connected and before we process premature * events */ dapls_evd_post_premature_events(ep_ptr); break; } case IB_CME_DISCONNECTED: case IB_CME_DISCONNECTED_ON_LINK_DOWN: { /* * EP is now fully disconnected; initiate any post processing * to reset the underlying QP and get the EP ready for * another connection */ if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED) { /* DTO error caused this */ event_type = DAT_CONNECTION_EVENT_BROKEN; } else { ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; dapls_ib_disconnect_clean(ep_ptr, DAT_TRUE, ib_cm_event); event_type = DAT_CONNECTION_EVENT_DISCONNECTED; } /* If the EP has been freed, the evd_ptr will be NULL */ if (evd_ptr != NULL) { (void) dapls_evd_post_connection_event( evd_ptr, event_type, (DAT_HANDLE) ep_ptr, 0, 0); } /* * If the user has done an ep_free of the EP, we have been * waiting for the disconnect event; just clean it up now. */ if (ep_ptr->header.magic == DAPL_MAGIC_EP_EXIT) { (void) dapl_ep_free(ep_ptr); } break; } case IB_CME_DESTINATION_REJECT_PRIVATE_DATA: { ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; dapls_ib_disconnect_clean(ep_ptr, DAT_TRUE, ib_cm_event); (void) dapls_evd_post_connection_event( evd_ptr, DAT_CONNECTION_EVENT_PEER_REJECTED, (DAT_HANDLE) ep_ptr, 0, 0); break; } case IB_CME_DESTINATION_UNREACHABLE: { ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; dapls_ib_disconnect_clean(ep_ptr, DAT_TRUE, ib_cm_event); (void) dapls_evd_post_connection_event( evd_ptr, DAT_CONNECTION_EVENT_UNREACHABLE, (DAT_HANDLE) ep_ptr, 0, 0); break; } case IB_CME_DESTINATION_REJECT: case IB_CME_TOO_MANY_CONNECTION_REQUESTS: case IB_CME_LOCAL_FAILURE: { ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; dapls_ib_disconnect_clean(ep_ptr, DAT_TRUE, ib_cm_event); (void) dapls_evd_post_connection_event( evd_ptr, DAT_CONNECTION_EVENT_NON_PEER_REJECTED, (DAT_HANDLE) ep_ptr, 0, 0); break; } case IB_CME_TIMED_OUT: { ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; dapls_ib_disconnect_clean(ep_ptr, DAT_TRUE, ib_cm_event); (void) dapls_evd_post_connection_event( evd_ptr, DAT_CONNECTION_EVENT_TIMED_OUT, (DAT_HANDLE) ep_ptr, 0, 0); break; } case IB_CME_CONNECTION_REQUEST_PENDING: case IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA: default: { dapl_os_assert(0); /* shouldn't happen */ break; } } dapl_dbg_log(DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, "dapl_evd_connection_callback () returns\n"); }
/* * dapl_psp_create * * uDAPL: User Direct Access Program Library Version 1.1, 6.4.1.1 * * Create a persistent Public Service Point that can recieve multiple * requests for connections and generate multiple connection request * instances that wil be delivered to the specified Event Dispatcher * in a notification event. * * Input: * ia_handle * conn_qual * evd_handle * psp_flags * * Output: * psp_handle * * Returns: * DAT_SUCCESS * DAT_INSUFFICIENT_RESOURCES * DAT_INVALID_PARAMETER * DAT_CONN_QUAL_IN_USE * DAT_MODEL_NOT_SUPPORTED */ DAT_RETURN dapl_psp_create( IN DAT_IA_HANDLE ia_handle, IN DAT_CONN_QUAL conn_qual, IN DAT_EVD_HANDLE evd_handle, IN DAT_PSP_FLAGS psp_flags, OUT DAT_PSP_HANDLE *psp_handle) { DAPL_IA *ia_ptr; DAPL_SP *sp_ptr; DAPL_EVD *evd_ptr; DAT_BOOLEAN sp_found; DAT_RETURN dat_status; ia_ptr = (DAPL_IA *)ia_handle; dat_status = DAT_SUCCESS; if (DAPL_BAD_HANDLE(ia_ptr, DAPL_MAGIC_IA)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); goto bail; } if (DAPL_BAD_HANDLE(evd_handle, DAPL_MAGIC_EVD)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CR); goto bail; } if (psp_handle == NULL) { dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG5); goto bail; } /* check for invalid psp flags */ if ((psp_flags != DAT_PSP_CONSUMER_FLAG) && (psp_flags != DAT_PSP_PROVIDER_FLAG)) { dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); goto bail; } evd_ptr = (DAPL_EVD *)evd_handle; if (!(evd_ptr->evd_flags & DAT_EVD_CR_FLAG)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CR); goto bail; } /* * check for connection qualifier eq 0 * in IB this is called Null Service ID, use of it in CM is invalid. * in tcp/udp, port number 0 is reserved. */ if (!conn_qual) { dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); goto bail; } /* * See if we have a quiescent listener to use for this PSP, else * create one and set it listening */ sp_ptr = dapls_ia_sp_search(ia_ptr, conn_qual, DAT_TRUE); sp_found = DAT_TRUE; if (sp_ptr == NULL) { /* Allocate PSP */ sp_found = DAT_FALSE; sp_ptr = dapls_sp_alloc(ia_ptr, DAT_TRUE); if (sp_ptr == NULL) { dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); goto bail; } } else if (sp_ptr->listening == DAT_TRUE) { dat_status = DAT_ERROR(DAT_CONN_QUAL_IN_USE, 0); goto bail; } /* * Fill out the args for a PSP */ sp_ptr->ia_handle = ia_handle; sp_ptr->conn_qual = conn_qual; sp_ptr->evd_handle = evd_handle; sp_ptr->psp_flags = psp_flags; sp_ptr->ep_handle = NULL; /* * Take a reference on the EVD handle */ (void) dapl_os_atomic_inc(&((DAPL_EVD *)evd_handle)->evd_ref_count); /* * Set up a listener for a connection. Connections can arrive * even before this call returns! */ sp_ptr->state = DAPL_SP_STATE_PSP_LISTENING; sp_ptr->listening = DAT_TRUE; /* * If this is a new sp we need to add it to the IA queue, and set up * a conn_listener. */ if (sp_found == DAT_FALSE) { /* Link it onto the IA */ dapl_ia_link_psp(ia_ptr, sp_ptr); dat_status = dapls_ib_setup_conn_listener(ia_ptr, conn_qual, sp_ptr); if (dat_status != DAT_SUCCESS) { /* * Have a problem setting up the connection, something * wrong! The psp_free decrements the EVD refcount for * us; we don't * need to do that. * But we want to set the listener bits to false, * as we know that call failed. */ sp_ptr->state = DAPL_SP_STATE_FREE; sp_ptr->listening = DAT_FALSE; (void) dapl_psp_free((DAT_PSP_HANDLE) sp_ptr); dapl_dbg_log(DAPL_DBG_TYPE_CM, "--> dapl_psp_create setup_conn_listener failed: " "%x\n", dat_status); goto bail; } } /* * Return handle to the user */ *psp_handle = (DAT_PSP_HANDLE)sp_ptr; bail: return (dat_status); }
/* * dapl_ep_connect * * DAPL Requirements Version xxx, 6.5.7 * * Request a connection be established between the local Endpoint * and a remote Endpoint. This operation is used by the active/client * side of a connection * * Input: * ep_handle * remote_ia_address * remote_conn_qual * timeout * private_data_size * privaet_data * qos * connect_flags * * Output: * None * * Returns: * DAT_SUCCESS * DAT_INSUFFICIENT_RESOUCRES * DAT_INVALID_PARAMETER * DAT_MODLE_NOT_SUPPORTED */ DAT_RETURN dapl_ep_connect( IN DAT_EP_HANDLE ep_handle, IN DAT_IA_ADDRESS_PTR remote_ia_address, IN DAT_CONN_QUAL remote_conn_qual, IN DAT_TIMEOUT timeout, IN DAT_COUNT private_data_size, IN const DAT_PVOID private_data, IN DAT_QOS qos, IN DAT_CONNECT_FLAGS connect_flags) { DAPL_EP *ep_ptr; DAPL_PRIVATE prd; DAPL_EP alloc_ep; DAT_RETURN dat_status; dapl_dbg_log(DAPL_DBG_TYPE_API | DAPL_DBG_TYPE_CM, "dapl_ep_connect (%p, {%u.%u.%u.%u}, %X, %d, %d, %p, %x, %x)\n", ep_handle, remote_ia_address->sa_data[2], remote_ia_address->sa_data[3], remote_ia_address->sa_data[4], remote_ia_address->sa_data[5], remote_conn_qual, timeout, private_data_size, private_data, qos, connect_flags); dat_status = DAT_SUCCESS; ep_ptr = (DAPL_EP *) ep_handle; /* * Verify parameter & state. The connection handle must be good * at this point. */ if (DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); goto bail; } if (DAPL_BAD_HANDLE(ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CONN); goto bail; } /* * If the endpoint needs a QP, associated the QP with it. * This needs to be done carefully, in order to: * * Avoid allocating under a lock. * * Not step on data structures being altered by * routines with which we are racing. * So we: * * Confirm that a new QP is needed and is not forbidden by the * current state. * * Allocate it into a separate EP. * * Take the EP lock. * * Reconfirm that the EP is in a state where it needs a QP. * * Assign the QP and release the lock. */ if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) { if (ep_ptr->param.pz_handle == NULL || DAPL_BAD_HANDLE(ep_ptr->param.pz_handle, DAPL_MAGIC_PZ)) { dat_status = DAT_ERROR(DAT_INVALID_STATE, DAT_INVALID_STATE_EP_NOTREADY); goto bail; } alloc_ep = *ep_ptr; dat_status = dapls_ib_qp_alloc(ep_ptr->header.owner_ia, &alloc_ep, ep_ptr); if (dat_status != DAT_SUCCESS) { dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); goto bail; } dapl_os_lock(&ep_ptr->header.lock); /* * PZ shouldn't have changed since we're only racing with * dapl_cr_accept() */ if (ep_ptr->qp_state != DAPL_QP_STATE_UNATTACHED) { /* Bail, cleaning up. */ dapl_os_unlock(&ep_ptr->header.lock); dat_status = dapls_ib_qp_free(ep_ptr->header.owner_ia, &alloc_ep); if (dat_status != DAT_SUCCESS) { dapl_dbg_log(DAPL_DBG_TYPE_WARN, "ep_connect: ib_qp_free failed with %x\n", dat_status); } dat_status = DAT_ERROR(DAT_INVALID_STATE, dapls_ep_state_subtype(ep_ptr)); goto bail; } ep_ptr->qp_handle = alloc_ep.qp_handle; ep_ptr->qpn = alloc_ep.qpn; ep_ptr->qp_state = alloc_ep.qp_state; dapl_os_unlock(&ep_ptr->header.lock); } /* * We do state checks and transitions under lock. * The only code we're racing against is dapl_cr_accept. */ dapl_os_lock(&ep_ptr->header.lock); /* * Verify the attributes of the EP handle before we connect it. Test * all of the handles to make sure they are currently valid. * Specifically: * pz_handle required * recv_evd_handle optional, but must be valid * request_evd_handle optional, but must be valid * connect_evd_handle required */ if (ep_ptr->param.pz_handle == NULL || DAPL_BAD_HANDLE(ep_ptr->param.pz_handle, DAPL_MAGIC_PZ) || ep_ptr->param.connect_evd_handle == NULL || DAPL_BAD_HANDLE(ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD) || !(((DAPL_EVD *)ep_ptr->param.connect_evd_handle)->evd_flags & DAT_EVD_CONNECTION_FLAG) || (ep_ptr->param.recv_evd_handle != DAT_HANDLE_NULL && (DAPL_BAD_HANDLE(ep_ptr->param.recv_evd_handle, DAPL_MAGIC_EVD))) || (ep_ptr->param.request_evd_handle != DAT_HANDLE_NULL && (DAPL_BAD_HANDLE(ep_ptr->param.request_evd_handle, DAPL_MAGIC_EVD)))) { dapl_os_unlock(&ep_ptr->header.lock); dat_status = DAT_ERROR(DAT_INVALID_STATE, DAT_INVALID_STATE_EP_NOTREADY); goto bail; } /* * Check both the EP state and the QP state: if we don't have a QP * we need to attach one now. */ if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) { dat_status = dapls_ib_qp_alloc(ep_ptr->header.owner_ia, ep_ptr, ep_ptr); if (dat_status != DAT_SUCCESS) { dapl_os_unlock(&ep_ptr->header.lock); dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_TEP); goto bail; } } if (ep_ptr->param.ep_state != DAT_EP_STATE_UNCONNECTED) { dapl_os_unlock(&ep_ptr->header.lock); dat_status = DAT_ERROR(DAT_INVALID_STATE, dapls_ep_state_subtype(ep_ptr)); goto bail; } if (qos != DAT_QOS_BEST_EFFORT || connect_flags != DAT_CONNECT_DEFAULT_FLAG) { /* * At this point we only support one QOS level */ dapl_os_unlock(&ep_ptr->header.lock); dat_status = DAT_ERROR(DAT_MODEL_NOT_SUPPORTED, 0); goto bail; } /* * Verify the private data size doesn't exceed the max */ if (private_data_size > DAPL_CONSUMER_MAX_PRIVATE_DATA_SIZE) { dapl_os_unlock(&ep_ptr->header.lock); dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG5); goto bail; } /* * transition the state before requesting a connection to avoid * race conditions */ ep_ptr->param.ep_state = DAT_EP_STATE_ACTIVE_CONNECTION_PENDING; /* * At this point we're committed, and done with the endpoint * except for the connect, so we can drop the lock. */ dapl_os_unlock(&ep_ptr->header.lock); /* * fill in the private data */ (void) dapl_os_memzero(&prd, sizeof (DAPL_PRIVATE)); if (private_data_size > 0) (void) dapl_os_memcpy(prd.private_data, private_data, private_data_size); /* Copy the connection qualifiers */ (void) dapl_os_memcpy(ep_ptr->param.remote_ia_address_ptr, remote_ia_address, sizeof (DAT_SOCK_ADDR6)); ep_ptr->param.remote_port_qual = remote_conn_qual; dat_status = dapls_ib_connect(ep_handle, remote_ia_address, remote_conn_qual, private_data_size, &prd, timeout); if (dat_status != DAT_SUCCESS) { DAPL_EVD *evd_ptr; if (dat_status == DAT_ERROR(DAT_INVALID_ADDRESS, DAT_INVALID_ADDRESS_UNREACHABLE)) { /* Unreachable IP address */ evd_ptr = (DAPL_EVD *)ep_ptr->param.connect_evd_handle; if (evd_ptr != NULL) { (void) dapls_evd_post_connection_event(evd_ptr, DAT_CONNECTION_EVENT_UNREACHABLE, (DAT_HANDLE) ep_ptr, 0, 0); } ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; dat_status = DAT_SUCCESS; } else if (dat_status == DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ADDRESS_UNREACHABLE)) { /* Non-existant connection qualifier */ evd_ptr = (DAPL_EVD *)ep_ptr->param.connect_evd_handle; if (evd_ptr != NULL) { (void) dapls_evd_post_connection_event(evd_ptr, DAT_CONNECTION_EVENT_NON_PEER_REJECTED, (DAT_HANDLE) ep_ptr, 0, 0); } ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; dat_status = DAT_SUCCESS; } else { ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED; } } bail: dapl_dbg_log(DAPL_DBG_TYPE_RTN | DAPL_DBG_TYPE_CM, "dapl_ep_connect () returns 0x%x\n", dat_status); return (dat_status); }
/* * dapl_cr_accept * * DAPL Requirements Version xxx, 6.4.2.1 * * Establish a connection between active remote side requesting Endpoint * and passic side local Endpoint. * * Input: * cr_handle * ep_handle * private_data_size * private_data * * Output: * none * * Returns: * DAT_SUCCESS * DAT_INVALID_PARAMETER * DAT_INVALID_ATTRIBUTE */ DAT_RETURN dapl_cr_accept( IN DAT_CR_HANDLE cr_handle, IN DAT_EP_HANDLE ep_handle, IN DAT_COUNT private_data_size, IN const DAT_PVOID private_data) { DAPL_EP *ep_ptr; DAT_RETURN dat_status; DAPL_PRIVATE prd; DAPL_CR *cr_ptr; DAT_EP_STATE entry_ep_state; DAT_EP_HANDLE entry_ep_handle; dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_cr_accept(%p, %p, %d, %p)\n", cr_handle, ep_handle, private_data_size, private_data); if (DAPL_BAD_HANDLE(cr_handle, DAPL_MAGIC_CR)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CR); goto bail; } cr_ptr = (DAPL_CR *) cr_handle; /* * Return an error if we have an ep_handle and the CR already has an * EP, indicating this is an RSP connection or PSP_PROVIDER_FLAG was * specified. */ if (ep_handle != NULL && (DAPL_BAD_HANDLE(ep_handle, DAPL_MAGIC_EP) || cr_ptr->param.local_ep_handle != NULL)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); goto bail; } if ((0 != private_data_size) && (NULL == private_data)) { dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); goto bail; } /* * Verify the private data size doesn't exceed the max */ if (private_data_size > DAPL_CONSUMER_MAX_PRIVATE_DATA_SIZE) { dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); goto bail; } /* * ep_handle is NULL if the user specified DAT_PSP_PROVIDER_FLAG * OR this is an RSP connection; retrieve it from the cr. */ if (ep_handle == NULL) { ep_handle = cr_ptr->param.local_ep_handle; if ((((DAPL_EP *) ep_handle)->param.ep_state != DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING) && (((DAPL_EP *)ep_handle)->param.ep_state != DAT_EP_STATE_PASSIVE_CONNECTION_PENDING)) { return (DAT_INVALID_STATE); } } else { /* ensure this EP isn't connected or in use */ if (((DAPL_EP *)ep_handle)->param.ep_state != DAT_EP_STATE_UNCONNECTED) { return (DAT_INVALID_STATE); } } ep_ptr = (DAPL_EP *) ep_handle; /* * Verify the attributes of the EP handle before we connect it. Test * all of the handles to make sure they are currently valid. * Specifically: * pz_handle required * recv_evd_handle optional, but must be valid * request_evd_handle optional, but must be valid * connect_evd_handle required * We do all verification and state change under lock, at which * point the EP state should protect us from most races. */ dapl_os_lock(&ep_ptr->header.lock); if ((ep_ptr->param.pz_handle == NULL) || DAPL_BAD_HANDLE(ep_ptr->param.pz_handle, DAPL_MAGIC_PZ) || (ep_ptr->param.connect_evd_handle == NULL) || DAPL_BAD_HANDLE(ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD) || !(((DAPL_EVD *)ep_ptr->param.connect_evd_handle)->evd_flags & DAT_EVD_CONNECTION_FLAG) || (ep_ptr->param.recv_evd_handle != DAT_HANDLE_NULL && (DAPL_BAD_HANDLE(ep_ptr->param.recv_evd_handle, DAPL_MAGIC_EVD))) || (ep_ptr->param.request_evd_handle != DAT_HANDLE_NULL && (DAPL_BAD_HANDLE(ep_ptr->param.request_evd_handle, DAPL_MAGIC_EVD)))) { dapl_os_unlock(&ep_ptr->header.lock); dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); goto bail; } if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) { /* * If we are lazy attaching the QP then we may need to * hook it up here. Typically, we run this code only for * DAT_PSP_PROVIDER_FLAG */ dat_status = dapls_ib_qp_alloc(cr_ptr->header.owner_ia, ep_ptr, ep_ptr); if (dat_status != DAT_SUCCESS) { /* This is not a great error code, but spec allows */ dapl_os_unlock(&ep_ptr->header.lock); dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); goto bail; } } entry_ep_state = ep_ptr->param.ep_state; entry_ep_handle = cr_ptr->param.local_ep_handle; ep_ptr->param.ep_state = DAT_EP_STATE_COMPLETION_PENDING; ep_ptr->cm_handle = cr_ptr->ib_cm_handle; ep_ptr->cr_ptr = cr_ptr; ep_ptr->param.remote_ia_address_ptr = cr_ptr->param. remote_ia_address_ptr; cr_ptr->param.local_ep_handle = ep_handle; /* * private data */ (void) dapl_os_memcpy(prd.private_data, private_data, private_data_size); (void) dapl_os_memzero(prd.private_data + private_data_size, sizeof (DAPL_PRIVATE) - private_data_size); dapl_os_unlock(&ep_ptr->header.lock); dat_status = dapls_ib_accept_connection(cr_handle, ep_handle, &prd); /* * If the provider failed, unwind the damage so we are back at * the initial state. */ if (dat_status != DAT_SUCCESS) { ep_ptr->param.ep_state = entry_ep_state; cr_ptr->param.local_ep_handle = entry_ep_handle; } else { /* * Make this CR invalid. We need to hang on to it until * the connection terminates, but it's destroyed from * the app point of view. */ cr_ptr->header.magic = DAPL_MAGIC_CR_DESTROYED; } bail: return (dat_status); }
DAT_RETURN dapl_evd_dequeue( IN DAT_EVD_HANDLE evd_handle, OUT DAT_EVENT *event) { DAPL_EVD *evd_ptr; DAT_EVENT *local_event; DAT_RETURN dat_status; dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_evd_dequeue (%p, %p)\n", evd_handle, event); evd_ptr = (DAPL_EVD *)evd_handle; dat_status = DAT_SUCCESS; if (DAPL_BAD_HANDLE(evd_handle, DAPL_MAGIC_EVD)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, 0); goto bail; } if (event == NULL) { dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); goto bail; } /* * We need to dequeue under lock, as the IB OS Access API * restricts us from having multiple threads in CQ poll, and the * DAPL 1.1 API allows multiple threads in dat_evd_dequeue() */ dapl_os_lock(&evd_ptr->header.lock); /* * Make sure there are no other waiters and the evd is active. * Currently this means only the OPEN state is allowed. */ if (evd_ptr->evd_state != DAPL_EVD_STATE_OPEN || evd_ptr->catastrophic_overflow) { dapl_os_unlock(&evd_ptr->header.lock); dat_status = DAT_ERROR(DAT_INVALID_STATE, 0); goto bail; } /* * Try the EVD rbuf first; poll from the CQ only if that's empty. * This keeps events in order if dat_evd_wait() has copied events * from CQ to EVD. */ if (evd_ptr->pending_event_queue.head != evd_ptr->pending_event_queue.tail) { local_event = (DAT_EVENT *) dapls_rbuf_remove(&evd_ptr->pending_event_queue); if (local_event != NULL) { *event = *local_event; dat_status = dapls_rbuf_add(&evd_ptr->free_event_queue, local_event); } else { /* should never happen */ dat_status = DAT_ERROR(DAT_INTERNAL_ERROR, 0); } } else if (evd_ptr->ib_cq_handle == IB_INVALID_HANDLE) { dat_status = DAT_ERROR(DAT_QUEUE_EMPTY, 0); } else if ((evd_ptr->evd_flags & (DAT_EVD_CONNECTION_FLAG | DAT_EVD_CR_FLAG | DAT_EVD_ASYNC_FLAG)) == 0) { /* * No need to drop into kernel, just check the CQ. */ dat_status = dapls_evd_cq_poll_to_event(evd_ptr, event); } else { /* poll for events with threshold and timeout both 0 */ evd_ptr->threshold = 0; dapl_os_unlock(&evd_ptr->header.lock); dat_status = dapls_evd_copy_events(evd_ptr, 0); if (dat_status != DAT_SUCCESS) { dat_status = DAT_ERROR(DAT_QUEUE_EMPTY, 0); goto bail; } dapl_os_lock(&evd_ptr->header.lock); local_event = (DAT_EVENT *)dapls_rbuf_remove( &evd_ptr->pending_event_queue); if (local_event != NULL) { *event = *local_event; dat_status = dapls_rbuf_add(&evd_ptr->free_event_queue, local_event); } else { /* still didn't find anything */ dat_status = DAT_ERROR(DAT_QUEUE_EMPTY, 0); } } dapl_os_unlock(&evd_ptr->header.lock); bail: dapl_dbg_log(DAPL_DBG_TYPE_RTN, "dapl_evd_dequeue () returns 0x%x\n", dat_status); return (dat_status); }
/* * dapls_ib_reinit_ep * * Move the QP to INIT state again. * * Input: * ep_ptr DAPL_EP * * Output: * none * * Returns: * void * */ void dapls_ib_reinit_ep(IN DAPL_EP *ep_ptr) { dapl_ep_reinit_t reinit_args; ib_hca_handle_t hca_hndl; ib_qp_handle_t qp_p; char addr_buf[64]; int retval; hca_hndl = ep_ptr->header.owner_ia->hca_ptr->ib_hca_handle; qp_p = ep_ptr->qp_handle; if (qp_p == NULL) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "dapls_ib_reinit: qp_handle == NULL\n"); return; } /* * Do all the work request cleanup processing right away * no one should really be doing any operation on this * qp (we are not threadsafe)... */ dapls_tavor_wrid_cleanup(ep_ptr, qp_p); reinit_args.epri_hkey = qp_p->ep_hkey; if (ioctl(hca_hndl->ia_fd, DAPL_EP_REINIT, &reinit_args) != 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "dapls_ib_reinit: reinit failed %s\n", strerror(errno)); return; } qp_p->qp_sq_lastwqeaddr = NULL; qp_p->qp_rq_lastwqeaddr = NULL; /* * Setup data structure for work request processing */ retval = dapls_tavor_wrid_init(qp_p); if (retval != DAT_SUCCESS) { /* * we failed to create data structures for work request * processing. Lets unmap and leave, the qp will get * cleaned when ep gets destroyed - the ep is unusable * in this state. */ if (munmap((void *)qp_p->qp_addr, qp_p->qp_map_len) < 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "qp_free: munmap failed(%d)\n", errno); } qp_p->qp_addr = NULL; dapl_dbg_log(DAPL_DBG_TYPE_CM, "dapls_ib_reinit: wrid_init failed %d\n", retval); return; } /* we have a new ep and it is in the init state */ ep_ptr->qp_state = IBT_STATE_INIT; dapl_dbg_log(DAPL_DBG_TYPE_CM, "dapls_ib_reinit: successful, ia_address %s, conn_qual %016llu\n", dapls_inet_ntop((struct sockaddr *)ep_ptr->param. remote_ia_address_ptr, addr_buf, 64), ep_ptr->param.remote_port_qual); }
/* * dapli_get_sp_ep * * Passive side of a connection is now fully established. Clean * up resources and obtain the EP pointer associated with a CR in * the SP * * Input: * ib_cm_handle, * sp_ptr * connection_event * * Output: * none * * Returns * ep_ptr * */ DAPL_EP *dapli_get_sp_ep(IN dp_ib_cm_handle_t ib_cm_handle, IN DAPL_SP * sp_ptr, IN DAT_EVENT_NUMBER dat_event_num) { DAPL_CR *cr_ptr; DAPL_EP *ep_ptr; /* * acquire the lock, we may be racing with other threads here */ dapl_os_lock(&sp_ptr->header.lock); /* Verify under lock that the SP is still valid */ if (sp_ptr->header.magic == DAPL_MAGIC_INVALID) { dapl_os_unlock(&sp_ptr->header.lock); return NULL; } /* * There are potentially multiple connections in progress. Need to * go through the list and find the one we are interested * in. There is no guarantee of order. dapl_sp_search_cr * leaves the CR on the SP queue. */ cr_ptr = dapl_sp_search_cr(sp_ptr, ib_cm_handle); if (cr_ptr == NULL) { dapl_os_unlock(&sp_ptr->header.lock); return NULL; } ep_ptr = (DAPL_EP *) cr_ptr->param.local_ep_handle; /* Quick check to ensure our EP is still valid */ if ((DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP))) { ep_ptr = NULL; } /* The CR record is discarded in all except for the CONNECTED case, * as it will have no further relevance. */ if (dat_event_num != DAT_CONNECTION_EVENT_ESTABLISHED) { /* Remove the CR from the queue */ dapl_sp_remove_cr(sp_ptr, cr_ptr); if (ep_ptr != NULL) { ep_ptr->cr_ptr = NULL; } /* * If this SP has been removed from service, free it * up after the last CR is removed */ if (sp_ptr->listening != DAT_TRUE && sp_ptr->cr_list_count == 0 && sp_ptr->state != DAPL_SP_STATE_FREE && sp_ptr->state != DAPL_SP_STATE_RSP_LISTENING) { dapl_dbg_log(DAPL_DBG_TYPE_CM, "--> dapli_get_sp_ep! disconnect dump sp: %p \n", sp_ptr); /* Decrement the ref count on the EVD */ if (sp_ptr->evd_handle) { dapl_os_atomic_dec(& ((DAPL_EVD *) sp_ptr-> evd_handle)->evd_ref_count); sp_ptr->evd_handle = NULL; } sp_ptr->state = DAPL_SP_STATE_FREE; dapl_os_unlock(&sp_ptr->header.lock); (void)dapls_ib_remove_conn_listener(sp_ptr->header. owner_ia, sp_ptr); dapls_ia_unlink_sp((DAPL_IA *) sp_ptr->header.owner_ia, sp_ptr); dapls_sp_free_sp(sp_ptr); dapls_cr_free(cr_ptr); goto skip_unlock; } dapl_os_unlock(&sp_ptr->header.lock); /* free memory outside of the lock */ dapls_cr_free(cr_ptr); } else { dapl_os_unlock(&sp_ptr->header.lock); } skip_unlock: return ep_ptr; }
/* * dapls_cr_callback * * The callback function registered with verbs for passive side of * connection requests. The interface is specified by cm_api.h * * * Input: * ib_cm_handle, Handle to CM * ib_cm_event Specific CM event * instant_data Private data with DAT ADDRESS header * context SP pointer * * Output: * None * */ void dapls_cr_callback(IN dp_ib_cm_handle_t ib_cm_handle, IN const ib_cm_events_t ib_cm_event, IN const void *private_data_ptr, IN const int private_data_size, IN const void *context) { DAPL_EP *ep_ptr; DAPL_EVD *evd_ptr; DAPL_SP *sp_ptr; DAPL_PRIVATE *prd_ptr; DAT_EVENT_NUMBER dat_event_num; DAT_RETURN dat_status; dapl_dbg_log(DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK, "--> dapl_cr_callback! context: %p event: %x cm_handle %p\n", context, ib_cm_event, (void *)ib_cm_handle); /* * Passive side of the connection, context is a SP and * we need to look up the EP. */ sp_ptr = (DAPL_SP *) context; /* * The context pointer could have been cleaned up in a racing * CM callback, check to see if we should just exit here */ if (sp_ptr->header.magic == DAPL_MAGIC_INVALID) { return; } dapl_os_assert(sp_ptr->header.magic == DAPL_MAGIC_PSP || sp_ptr->header.magic == DAPL_MAGIC_RSP); /* Obtain the event number from the provider layer */ dat_event_num = dapls_ib_get_dat_event(ib_cm_event, DAT_FALSE); /* * CONNECT_REQUEST events create an event on the PSP * EVD, which will trigger connection processing. The * sequence is: * CONNECT_REQUEST Event to SP * CONNECTED Event to EP * DISCONNECT Event to EP * * Obtain the EP if required and set an event up on the correct * EVD. */ if (dat_event_num == DAT_CONNECTION_REQUEST_EVENT) { ep_ptr = NULL; evd_ptr = sp_ptr->evd_handle; } else { /* see if there is an EP connected with this CM handle */ ep_ptr = dapli_get_sp_ep(ib_cm_handle, sp_ptr, dat_event_num); /* if we lost a race with the CM just exit. */ if (ep_ptr == NULL) { return; } evd_ptr = (DAPL_EVD *) ep_ptr->param.connect_evd_handle; /* if something has happened to our EVD, bail. */ if (evd_ptr == NULL) { return; } } prd_ptr = (DAPL_PRIVATE *) private_data_ptr; dat_status = DAT_INTERNAL_ERROR; /* init to ERR */ switch (dat_event_num) { case DAT_CONNECTION_REQUEST_EVENT: { /* * Requests arriving on a disabled SP are immediatly rejected */ dapl_os_lock(&sp_ptr->header.lock); if (sp_ptr->listening == DAT_FALSE) { dapl_os_unlock(&sp_ptr->header.lock); dapl_log(DAPL_DBG_TYPE_CM_WARN, " cr_callback: CR event on non-listening SP\n"); (void)dapls_ib_reject_connection(ib_cm_handle, DAT_CONNECTION_EVENT_UNREACHABLE, 0, NULL); return; } if (sp_ptr->header.handle_type == DAT_HANDLE_TYPE_RSP) { /* * RSP connections only allow a single connection. Close * it down NOW so we reject any further connections. */ sp_ptr->listening = DAT_FALSE; } dapl_os_unlock(&sp_ptr->header.lock); /* * Only occurs on the passive side of a connection * dapli_connection_request will post the connection * event if appropriate. */ dat_status = dapli_connection_request(ib_cm_handle, sp_ptr, prd_ptr, private_data_size, evd_ptr); /* Set evd_ptr = NULL so we don't generate an event below */ evd_ptr = NULL; break; } case DAT_CONNECTION_EVENT_ESTABLISHED: { /* This is just a notification the connection is now * established, there isn't any private data to deal with. * * Update the EP state and cache a copy of the cm handle, * then let the user know we are ready to go. */ dapl_os_lock(&ep_ptr->header.lock); if (ep_ptr->header.magic != DAPL_MAGIC_EP || ep_ptr->param.ep_state != DAT_EP_STATE_COMPLETION_PENDING) { /* If someone pulled the plug on the EP or connection, * just exit */ dapl_os_unlock(&ep_ptr->header.lock); dat_status = DAT_SUCCESS; /* Set evd_ptr = NULL so we don't generate an event below */ evd_ptr = NULL; break; } ep_ptr->param.ep_state = DAT_EP_STATE_CONNECTED; dapl_os_unlock(&ep_ptr->header.lock); break; } case DAT_CONNECTION_EVENT_DISCONNECTED: { /* * EP is now fully disconnected; initiate any post processing * to reset the underlying QP and get the EP ready for * another connection */ dapl_os_lock(&ep_ptr->header.lock); if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED) { /* The disconnect has already occurred, we are now * cleaned up and ready to exit */ dapl_os_unlock(&ep_ptr->header.lock); return; } ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE, ib_cm_event); dapl_os_unlock(&ep_ptr->header.lock); break; } case DAT_CONNECTION_EVENT_NON_PEER_REJECTED: case DAT_CONNECTION_EVENT_PEER_REJECTED: case DAT_CONNECTION_EVENT_UNREACHABLE: { /* * After posting an accept the requesting node has * stopped talking. */ dapl_os_lock(&ep_ptr->header.lock); ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE, ib_cm_event); dapl_os_unlock(&ep_ptr->header.lock); break; } case DAT_CONNECTION_EVENT_BROKEN: { dapl_os_lock(&ep_ptr->header.lock); ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE, ib_cm_event); dapl_os_unlock(&ep_ptr->header.lock); break; } default: { evd_ptr = NULL; dapl_os_assert(0); /* shouldn't happen */ break; } } if (evd_ptr != NULL) { dat_status = dapls_evd_post_connection_event(evd_ptr, dat_event_num, (DAT_HANDLE) ep_ptr, 0, NULL); } if (dat_status != DAT_SUCCESS) { /* The event post failed; take appropriate action. */ (void)dapls_ib_reject_connection(ib_cm_handle, DAT_CONNECTION_EVENT_BROKEN, 0, NULL); return; } }
/* * dapl_rsp_create * * uDAPL: User Direct Access Program Library Version 1.1, 6.4.3.4.1 * * Create a Resereved Service Point with the specified Endpoint * that generates at most one Connection Request that is * delivered to the specified Event Dispatcher in a notification * event * * Input: * ia_handle * conn_qual * ep_handle * evd_handle * * Output: * rsp_handle * * Returns: * DAT_SUCCESS * DAT_INSUFFICIENT_RESOURCES * DAT_INVALID_PARAMETER * DAT_INVALID_STATE * DAT_CONN_QUAL_IN_USE */ DAT_RETURN dapl_rsp_create( IN DAT_IA_HANDLE ia_handle, IN DAT_CONN_QUAL conn_qual, IN DAT_EP_HANDLE ep_handle, IN DAT_EVD_HANDLE evd_handle, OUT DAT_RSP_HANDLE *rsp_handle) { DAPL_IA *ia_ptr; DAPL_SP *sp_ptr; DAPL_EVD *evd_ptr; DAPL_EP *ep_ptr; DAT_BOOLEAN sp_found; DAT_RETURN dat_status; dat_status = DAT_SUCCESS; ia_ptr = (DAPL_IA *)ia_handle; dapl_dbg_log(DAPL_DBG_TYPE_CM, ">>> dapl_rsp_free conn_qual: %x EP: %p\n", conn_qual, ep_handle); if (DAPL_BAD_HANDLE(ia_ptr, DAPL_MAGIC_IA)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_IA); goto bail; } if (DAPL_BAD_HANDLE(ep_handle, DAPL_MAGIC_EP)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); goto bail; } if (DAPL_BAD_HANDLE(evd_handle, DAPL_MAGIC_EVD)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CR); goto bail; } if (rsp_handle == NULL) { dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG5); goto bail; } ep_ptr = (DAPL_EP *) ep_handle; if (ep_ptr->param.ep_state != DAT_EP_STATE_UNCONNECTED) { dat_status = DAT_ERROR(DAT_INVALID_STATE, dapls_ep_state_subtype(ep_ptr)); goto bail; } evd_ptr = (DAPL_EVD *)evd_handle; if (!(evd_ptr->evd_flags & DAT_EVD_CR_FLAG)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CR); goto bail; } sp_ptr = dapls_ia_sp_search(ia_ptr, conn_qual, DAT_FALSE); sp_found = DAT_TRUE; if (sp_ptr == NULL) { sp_found = DAT_FALSE; /* Allocate RSP */ sp_ptr = dapls_sp_alloc(ia_ptr, DAT_FALSE); if (sp_ptr == NULL) { dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); goto bail; } } /* * Fill out the RSP args */ sp_ptr->ia_handle = ia_handle; sp_ptr->conn_qual = conn_qual; sp_ptr->evd_handle = evd_handle; sp_ptr->psp_flags = 0; sp_ptr->ep_handle = ep_handle; /* * Take a reference on the EVD handle */ (void) dapl_os_atomic_inc(&((DAPL_EVD *)evd_handle)->evd_ref_count); /* * Update the EP state indicating the provider now owns it */ ep_ptr->param.ep_state = DAT_EP_STATE_RESERVED; /* * Set up a listener for a connection. Connections can arrive * even before this call returns! */ sp_ptr->state = DAPL_SP_STATE_RSP_LISTENING; sp_ptr->listening = DAT_TRUE; if (sp_found == DAT_FALSE) { /* Link it onto the IA */ dapl_ia_link_rsp(ia_ptr, sp_ptr); dat_status = dapls_ib_setup_conn_listener(ia_ptr, conn_qual, sp_ptr); if (dat_status != DAT_SUCCESS) { /* * Have a problem setting up the connection, something * wrong! * rsp_free will decrement the EVD refcount. Set * listening to * false to avoid tearing down the * conn_listener which didn't * get set up. */ sp_ptr->listening = DAT_FALSE; (void) dapl_rsp_free((DAT_RSP_HANDLE) sp_ptr); dapl_dbg_log(DAPL_DBG_TYPE_CM, "--> dapl_rsp_create setup_conn_listener failed: " "%x\n", dat_status); goto bail; } } /* * Return handle to the user */ *rsp_handle = (DAT_RSP_HANDLE)sp_ptr; bail: return (dat_status); }