#ifndef _AL_CM_CEP_H_\r
#define _AL_CM_CEP_H_\r
\r
-\r
#include <iba/ib_al.h>\r
#include "al_common.h"\r
\r
+#ifdef CL_KERNEL\r
+#include <iba/ib_cm_ifc.h>\r
+#endif\r
\r
#define CEP_EVENT_TIMEOUT 0x80000000\r
#define CEP_EVENT_RECV 0x40000000\r
* event notification.\r
*********/\r
\r
+#ifdef CL_KERNEL\r
+ib_api_status_t\r
+kal_alloc_cep(\r
+ IN ib_al_handle_t h_al,\r
+ IN OUT net32_t* const p_cid );\r
+\r
+ib_api_status_t\r
+kal_config_cep(\r
+ IN ib_al_handle_t h_al,\r
+ IN net32_t cid,\r
+ IN al_pfn_cep_cb_t pfn_cb,\r
+ IN void* context,\r
+ IN ib_pfn_destroy_cb_t pfn_destroy_cb );\r
+#endif\r
+\r
/* Destruction is asynchronous. */\r
void\r
al_destroy_cep(\r
IN ib_cep_listen_t* const p_listen_info );\r
\r
\r
+#ifdef CL_KERNEL\r
+ib_api_status_t\r
+kal_cep_pre_req(\r
+ IN ib_al_handle_t h_al,\r
+ IN net32_t cid,\r
+ IN const iba_cm_req* const p_cm_req,\r
+ IN OUT ib_qp_mod_t* const p_init );\r
+#endif\r
+\r
ib_api_status_t\r
al_cep_pre_req(\r
IN ib_al_handle_t h_al,\r
IN OUT net32_t* const p_cid,\r
OUT ib_qp_mod_t* const p_init );\r
\r
+#ifdef CL_KERNEL\r
ib_api_status_t\r
-al_cep_pre_rep_ex(\r
+kal_cep_pre_rep(\r
IN ib_al_handle_t h_al,\r
IN net32_t cid,\r
- IN al_pfn_cep_cb_t pfn_cb,\r
- IN void* context,\r
- IN ib_pfn_destroy_cb_t pfn_destroy_cb OPTIONAL,\r
- IN const ib_cm_rep_t* const p_cm_rep,\r
- IN OUT net32_t* const p_cid,\r
- OUT ib_qp_mod_t* const p_init );\r
+ IN const iba_cm_rep* const p_cm_rep,\r
+ IN OUT ib_qp_mod_t* const p_init );\r
+\r
+void\r
+kal_destroy_cep(\r
+ IN ib_al_handle_t h_al,\r
+ IN net32_t cid );\r
+#endif\r
\r
ib_api_status_t\r
al_cep_send_rep(\r
IN ib_al_handle_t h_al,\r
IN net32_t cid );\r
\r
+#ifdef CL_KERNEL\r
+void\r
+kal_cep_format_event(\r
+ IN ib_al_handle_t h_al,\r
+ IN net32_t cid,\r
+ IN ib_mad_element_t *p_mad,\r
+ IN OUT iba_cm_event *p_event);\r
+\r
+ib_api_status_t\r
+al_cep_get_init_attr(\r
+ IN ib_al_handle_t h_al,\r
+ IN net32_t cid,\r
+ OUT ib_qp_mod_t* const p_init );\r
+#endif\r
\r
ib_api_status_t\r
al_cep_get_rtr_attr(\r
\r
\r
#ifdef CL_KERNEL\r
+void cm_get_interface(iba_cm_interface *p_ifc);\r
\r
NTSTATUS\r
al_cep_queue_irp(\r
\r
/* Match on the transaction ID, ignoring internally generated sends. */\r
AL_EXIT( AL_DBG_MAD_SVC );\r
- if( (p_recv_hdr->trans_id == h_send->mad_wr.client_tid) &&\r
+ if( al_get_user_tid(p_recv_hdr->trans_id) ==\r
+ al_get_user_tid(h_send->mad_wr.client_tid) &&\r
!__is_internal_send( h_mad_svc->svc_type, h_send->p_send_mad ) )\r
{\r
return h_send;\r
#endif /* CL_KERNEL */\r
\r
\r
-typedef ib_api_status_t\r
-(*ib_pfn_modify_qp_t)(\r
- IN const ib_qp_handle_t h_qp,\r
- IN const ib_qp_mod_t* const p_qp_mod,\r
- IN OUT ci_umv_buf_t* const p_umv_buf );\r
-\r
-typedef ib_api_status_t\r
-(*ib_pfn_post_send_t)(\r
- IN const ib_qp_handle_t h_qp,\r
- IN ib_send_wr_t* const p_send_wr,\r
- IN ib_send_wr_t **pp_send_failure OPTIONAL );\r
-\r
-typedef ib_api_status_t\r
-(*ib_pfn_post_recv_t)(\r
- IN const ib_qp_handle_t h_qp,\r
- IN ib_recv_wr_t* const p_recv_wr,\r
- IN ib_recv_wr_t **p_recv_failure OPTIONAL );\r
-\r
-typedef ib_api_status_t\r
-(*ib_pfn_init_dgrm_svc_t)(\r
- IN const ib_qp_handle_t h_qp,\r
- IN const ib_dgrm_info_t* const p_dgrm_info );\r
-\r
-typedef ib_api_status_t\r
-(*ib_pfn_reg_mad_svc_t)(\r
- IN const ib_qp_handle_t h_qp,\r
- IN const ib_mad_svc_t* const p_mad_svc,\r
- OUT ib_mad_svc_handle_t* const ph_mad_svc );\r
-\r
-typedef ib_api_status_t\r
-(*ib_pfn_dereg_mad_svc_t)(\r
- IN const ib_mad_svc_handle_t h_mad_svc );\r
-\r
-typedef void\r
-(*ib_pfn_queue_mad_t)(\r
- IN const ib_qp_handle_t h_qp,\r
- IN al_mad_wr_t* const p_mad_wr );\r
-\r
-typedef void\r
-(*ib_pfn_resume_mad_t)(\r
- IN const ib_qp_handle_t h_qp );\r
-\r
-typedef ib_api_status_t\r
-(*ib_pfn_join_mcast_t)(\r
- IN const ib_qp_handle_t h_qp,\r
- IN const ib_mcast_req_t* const p_mcast_req );\r
-\r
-typedef ib_api_status_t\r
-(*ib_pfn_leave_mcast_t)(\r
- IN const ib_mcast_handle_t h_mcast );\r
-\r
-\r
/*\r
* Queue pair information required by the access layer. This structure\r
* is referenced by a user's QP handle.\r
* handle.\r
*/\r
ib_qp_handle_t h_ud_send_qp;\r
- ib_pfn_post_send_t pfn_ud_post_send;\r
+ ib_api_status_t\r
+ (*pfn_ud_post_send)(\r
+ IN const ib_qp_handle_t h_qp,\r
+ IN ib_send_wr_t* const p_send_wr,\r
+ IN ib_send_wr_t **pp_send_failure OPTIONAL );\r
\r
ib_cq_handle_t h_recv_cq;\r
ib_cq_handle_t h_send_cq;\r
\r
ib_pfn_event_cb_t pfn_event_cb;\r
\r
- ib_pfn_modify_qp_t pfn_modify_qp;\r
- ib_pfn_post_recv_t pfn_post_recv;\r
- ib_pfn_post_send_t pfn_post_send;\r
- ib_pfn_reg_mad_svc_t pfn_reg_mad_svc;\r
- ib_pfn_dereg_mad_svc_t pfn_dereg_mad_svc;\r
- ib_pfn_queue_mad_t pfn_queue_mad;\r
- ib_pfn_resume_mad_t pfn_resume_mad;\r
- ib_pfn_init_dgrm_svc_t pfn_init_dgrm_svc;\r
- ib_pfn_join_mcast_t pfn_join_mcast;\r
+ ib_api_status_t\r
+ (*pfn_modify_qp)(\r
+ IN const ib_qp_handle_t h_qp,\r
+ IN const ib_qp_mod_t* const p_qp_mod,\r
+ IN OUT ci_umv_buf_t* const p_umv_buf );\r
+ ib_api_status_t\r
+ (*pfn_post_recv)(\r
+ IN const ib_qp_handle_t h_qp,\r
+ IN ib_recv_wr_t* const p_recv_wr,\r
+ IN ib_recv_wr_t **p_recv_failure OPTIONAL );\r
+ ib_api_status_t\r
+ (*pfn_post_send)(\r
+ IN const ib_qp_handle_t h_qp,\r
+ IN ib_send_wr_t* const p_send_wr,\r
+ IN ib_send_wr_t **pp_send_failure OPTIONAL );\r
+ ib_api_status_t\r
+ (*pfn_reg_mad_svc)(\r
+ IN const ib_qp_handle_t h_qp,\r
+ IN const ib_mad_svc_t* const p_mad_svc,\r
+ OUT ib_mad_svc_handle_t* const ph_mad_svc );\r
+ ib_api_status_t\r
+ (*pfn_dereg_mad_svc)(\r
+ IN const ib_mad_svc_handle_t h_mad_svc );\r
+ void\r
+ (*pfn_queue_mad)(\r
+ IN const ib_qp_handle_t h_qp,\r
+ IN al_mad_wr_t* const p_mad_wr );\r
+ void\r
+ (*pfn_resume_mad)(\r
+ IN const ib_qp_handle_t h_qp );\r
+ ib_api_status_t\r
+ (*pfn_init_dgrm_svc)(\r
+ IN const ib_qp_handle_t h_qp,\r
+ IN const ib_dgrm_info_t* const p_dgrm_info );\r
+ ib_api_status_t\r
+ (*pfn_join_mcast)(\r
+ IN const ib_qp_handle_t h_qp,\r
+ IN const ib_mcast_req_t* const p_mcast_req );\r
\r
#ifdef CL_KERNEL\r
ndi_qp_csq_t *p_irp_queue;\r
\r
SOURCES= ibal.rc \\r
al_ci_ca.c \\r
+ al_cm.c \\r
al_cm_cep.c \\r
al_dev.c \\r
al_ioc_pnp.c \\r
--- /dev/null
+/*\r
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+#include <iba/ib_cm_ifc.h>\r
+#include "al_cm_cep.h"\r
+#include "al_mgr.h"\r
+#include "al_proxy.h"\r
+#include "al_cm_conn.h"\r
+#include "al_cm_sidr.h"\r
+\r
+typedef struct _iba_cm_id_priv\r
+{\r
+ iba_cm_id id;\r
+ KEVENT destroy_event; \r
+\r
+} iba_cm_id_priv;\r
+\r
+static iba_cm_id*\r
+cm_alloc_id(NTSTATUS (*callback)(iba_cm_id *p_id, iba_cm_event *p_event),\r
+ void *context)\r
+{\r
+ iba_cm_id_priv *id;\r
+\r
+ id = ExAllocatePoolWithTag(NonPagedPool, sizeof(iba_cm_id_priv), 'mcbi');\r
+ if (id == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ KeInitializeEvent(&id->destroy_event, NotificationEvent, FALSE);\r
+ id->id.callback = callback;\r
+ id->id.context = context;\r
+ return &id->id;\r
+}\r
+\r
+static void\r
+cm_free_id(iba_cm_id *id)\r
+{\r
+ ExFreePool(CONTAINING_RECORD(id, iba_cm_id_priv, id));\r
+}\r
+\r
+static void\r
+cm_destroy_handler(void *context)\r
+{\r
+ iba_cm_id_priv *id = context;\r
+ KeSetEvent(&id->destroy_event, 0, FALSE);\r
+}\r
+\r
+static void\r
+cm_cep_handler(const ib_al_handle_t h_al, const net32_t cid)\r
+{\r
+ void *context;\r
+ net32_t new_cid;\r
+ ib_mad_element_t *mad;\r
+ iba_cm_id *id, *listen_id;\r
+ iba_cm_event event;\r
+ NTSTATUS status;\r
+\r
+ while (al_cep_poll(h_al, cid, &context, &new_cid, &mad) == IB_SUCCESS) {\r
+\r
+ if (new_cid == AL_INVALID_CID) {\r
+ id = (iba_cm_id *) context;\r
+ } else {\r
+ listen_id = (iba_cm_id *) context;\r
+\r
+ id = cm_alloc_id(listen_id->callback, listen_id);\r
+ if (id == NULL) {\r
+ kal_destroy_cep(h_al, new_cid);\r
+ ib_put_mad(mad);\r
+ continue;\r
+ }\r
+\r
+ kal_config_cep(h_al, new_cid, cm_cep_handler, id, cm_destroy_handler);\r
+ id->cid = new_cid;\r
+ }\r
+\r
+ kal_cep_format_event(h_al, id->cid, mad, &event);\r
+ status = id->callback(id, &event);\r
+ if (!NT_SUCCESS(status)) {\r
+ kal_config_cep(h_al, new_cid, NULL, NULL, NULL);\r
+ kal_destroy_cep(h_al, id->cid);\r
+ cm_free_id(id);\r
+ }\r
+ ib_put_mad(mad);\r
+ }\r
+}\r
+\r
+static NTSTATUS\r
+cm_create_id(NTSTATUS (*callback)(iba_cm_id *p_id, iba_cm_event *p_event),\r
+ void *context, iba_cm_id **pp_id)\r
+{\r
+ iba_cm_id *id;\r
+ ib_api_status_t ib_status;\r
+\r
+ id = cm_alloc_id(callback, context);\r
+ if (id == NULL) {\r
+ return STATUS_NO_MEMORY;\r
+ }\r
+\r
+ ib_status = kal_alloc_cep(gh_al, &id->cid);\r
+ if (ib_status != IB_SUCCESS) {\r
+ cm_free_id(id);\r
+ return ib_to_ntstatus(ib_status);\r
+ }\r
+\r
+ kal_config_cep(gh_al, id->cid, cm_cep_handler, id, cm_destroy_handler);\r
+ *pp_id = id;\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+static void\r
+cm_destroy_id(iba_cm_id *p_id)\r
+{\r
+ iba_cm_id_priv *id;\r
+\r
+ id = CONTAINING_RECORD(p_id, iba_cm_id_priv, id);\r
+ kal_destroy_cep(gh_al, p_id->cid);\r
+ KeWaitForSingleObject(&id->destroy_event, Executive, KernelMode, FALSE, NULL);\r
+ cm_free_id(p_id);\r
+}\r
+\r
+static NTSTATUS\r
+cm_listen(iba_cm_id *p_id, net64_t service_id, void *p_compare_buf,\r
+ uint8_t compare_len, uint8_t compare_offset)\r
+{\r
+ ib_cep_listen_t info;\r
+ ib_api_status_t ib_status;\r
+\r
+ info.svc_id = service_id;\r
+ info.port_guid = IB_ALL_PORTS;\r
+ info.p_cmp_buf = p_compare_buf;\r
+ info.cmp_len = compare_len;\r
+ info.cmp_offset = compare_offset;\r
+ \r
+ ib_status = al_cep_listen(gh_al, p_id->cid, &info);\r
+ return ib_to_ntstatus(ib_status);\r
+}\r
+\r
+static NTSTATUS\r
+cm_send_req(iba_cm_id *p_id, iba_cm_req *p_req)\r
+{\r
+ ib_qp_mod_t attr;\r
+ ib_api_status_t ib_status;\r
+ \r
+ attr.state.rtr.rnr_nak_timeout = 0;\r
+ ib_status = kal_cep_pre_req(gh_al, p_id->cid, p_req, &attr);\r
+ if (ib_status != IB_SUCCESS) {\r
+ return ib_to_ntstatus(ib_status);\r
+ }\r
+\r
+ ib_status = al_cep_send_req(gh_al, p_id->cid);\r
+ return ib_to_ntstatus(ib_status);\r
+}\r
+\r
+static NTSTATUS\r
+cm_send_rep(iba_cm_id *p_id, iba_cm_rep *p_rep)\r
+{\r
+ ib_qp_mod_t attr;\r
+ ib_api_status_t ib_status;\r
+\r
+ ib_status = kal_cep_pre_rep(gh_al, p_id->cid, p_rep, &attr);\r
+ if (ib_status != IB_SUCCESS) {\r
+ return ib_to_ntstatus(ib_status);\r
+ }\r
+\r
+ ib_status = al_cep_send_rep(gh_al, p_id->cid);\r
+ return ib_to_ntstatus(ib_status);\r
+}\r
+\r
+static NTSTATUS\r
+cm_send_rtu(iba_cm_id *p_id, void *p_pdata, uint8_t pdata_len)\r
+{\r
+ ib_api_status_t ib_status;\r
+\r
+ ib_status = al_cep_rtu(gh_al, p_id->cid, p_pdata, pdata_len);\r
+ return ib_to_ntstatus(ib_status);\r
+}\r
+\r
+static NTSTATUS\r
+cm_send_dreq(iba_cm_id *p_id, void *p_pdata, uint8_t pdata_len)\r
+{\r
+ ib_api_status_t ib_status;\r
+\r
+ ib_status = al_cep_dreq(gh_al, p_id->cid, p_pdata, pdata_len);\r
+ return ib_to_ntstatus(ib_status);\r
+}\r
+\r
+static NTSTATUS\r
+cm_send_drep(iba_cm_id *p_id, void *p_pdata, uint8_t pdata_len)\r
+{\r
+ ib_api_status_t ib_status;\r
+\r
+ ib_status = al_cep_drep(gh_al, p_id->cid, p_pdata, pdata_len);\r
+ return ib_to_ntstatus(ib_status);\r
+}\r
+\r
+static NTSTATUS\r
+cm_send_rej(iba_cm_id *p_id, ib_rej_status_t status,\r
+ void *p_ari, uint8_t ari_len,\r
+ void *p_pdata, uint8_t pdata_len)\r
+{\r
+ ib_api_status_t ib_status;\r
+\r
+ ib_status = al_cep_rej(gh_al, p_id->cid, status, p_ari, ari_len,\r
+ p_pdata, pdata_len);\r
+ return ib_to_ntstatus(ib_status);\r
+}\r
+\r
+static NTSTATUS\r
+cm_send_mra(iba_cm_id *p_id, uint8_t service_timeout,\r
+ void *p_pdata, uint8_t pdata_len)\r
+{\r
+ ib_cm_mra_t mra;\r
+ ib_api_status_t ib_status;\r
+\r
+ mra.svc_timeout = service_timeout;\r
+ mra.p_mra_pdata = p_pdata;\r
+ mra.mra_length = pdata_len;\r
+\r
+ ib_status = al_cep_mra(gh_al, p_id->cid, &mra);\r
+ return ib_to_ntstatus(ib_status);\r
+}\r
+\r
+static NTSTATUS\r
+cm_send_lap(iba_cm_id *p_id, iba_cm_lap *p_lap)\r
+{\r
+ ib_cm_lap_t lap;\r
+ ib_api_status_t ib_status;\r
+\r
+ RtlZeroMemory(&lap, sizeof lap);\r
+ lap.p_lap_pdata = p_lap->p_pdata;\r
+ lap.lap_length = p_lap->pdata_len;\r
+ lap.remote_resp_timeout = p_lap->remote_resp_timeout;\r
+ lap.p_alt_path = p_lap->p_alt_path;\r
+\r
+ ib_status = al_cep_lap(gh_al, p_id->cid, &lap);\r
+ return ib_to_ntstatus(ib_status);\r
+}\r
+\r
+static NTSTATUS\r
+cm_send_apr(iba_cm_id *p_id, iba_cm_apr *p_apr)\r
+{\r
+ ib_cm_apr_t apr;\r
+ ib_qp_mod_t attr;\r
+ ib_api_status_t ib_status;\r
+\r
+ RtlZeroMemory(&apr, sizeof apr);\r
+ apr.p_apr_pdata = p_apr->p_pdata;\r
+ apr.apr_length = p_apr->pdata_len;\r
+ apr.apr_status = p_apr->status;\r
+ apr.info_length = p_apr->info_length;\r
+ apr.p_info = p_apr->p_info;\r
+\r
+ ib_status = al_cep_pre_apr(gh_al, p_id->cid, &apr, &attr);\r
+ if (ib_status != IB_SUCCESS) {\r
+ return ib_to_ntstatus(ib_status);\r
+ }\r
+\r
+ ib_status = al_cep_send_apr(gh_al, p_id->cid);\r
+ return ib_to_ntstatus(ib_status);\r
+}\r
+\r
+static NTSTATUS\r
+cm_send_sidr_req(iba_cm_id *p_id, iba_cm_sidr_req *p_req)\r
+{\r
+ UNUSED_PARAM(p_id);\r
+ UNUSED_PARAM(p_req);\r
+\r
+ return STATUS_NOT_SUPPORTED;\r
+}\r
+\r
+static NTSTATUS\r
+cm_send_sidr_rep(iba_cm_id *p_id, iba_cm_sidr_rep *p_rep)\r
+{\r
+ UNUSED_PARAM(p_id);\r
+ UNUSED_PARAM(p_rep);\r
+\r
+ return STATUS_NOT_SUPPORTED;\r
+}\r
+\r
+static NTSTATUS\r
+cm_get_qp_attr(iba_cm_id *p_id, ib_qp_state_t state, ib_qp_mod_t *p_attr)\r
+{\r
+ ib_api_status_t ib_status;\r
+\r
+ switch (state) {\r
+ case IB_QPS_INIT:\r
+ ib_status = al_cep_get_init_attr(gh_al, p_id->cid, p_attr);\r
+ break;\r
+ case IB_QPS_RTR:\r
+ ib_status = al_cep_get_rtr_attr(gh_al, p_id->cid, p_attr);\r
+ break;\r
+ case IB_QPS_RTS:\r
+ ib_status = al_cep_get_rts_attr(gh_al, p_id->cid, p_attr);\r
+ break;\r
+ default:\r
+ return STATUS_INVALID_PARAMETER;\r
+ }\r
+\r
+ return ib_to_ntstatus(ib_status);\r
+}\r
+\r
+static NTSTATUS\r
+cm_migrate(iba_cm_id *p_id)\r
+{\r
+ ib_api_status_t ib_status;\r
+\r
+ ib_status = al_cep_migrate(gh_al, p_id->cid);\r
+ return ib_to_ntstatus(ib_status);\r
+}\r
+\r
+static NTSTATUS\r
+cm_establish(iba_cm_id *p_id)\r
+{\r
+ ib_api_status_t ib_status;\r
+\r
+ ib_status = al_cep_established(gh_al, p_id->cid);\r
+ return ib_to_ntstatus(ib_status);\r
+}\r
+\r
+void cm_get_interface(iba_cm_interface *p_ifc)\r
+{\r
+ p_ifc->create_id = cm_create_id;\r
+ p_ifc->destroy_id = cm_destroy_id;\r
+ p_ifc->listen = cm_listen;\r
+ p_ifc->send_req = cm_send_req;\r
+ p_ifc->send_rep = cm_send_rep;\r
+ p_ifc->send_rtu = cm_send_rtu;\r
+ p_ifc->send_dreq = cm_send_dreq;\r
+ p_ifc->send_drep = cm_send_drep;\r
+ p_ifc->send_rej = cm_send_rej;\r
+ p_ifc->send_mra = cm_send_mra;\r
+ p_ifc->send_lap = cm_send_lap;\r
+ p_ifc->send_apr = cm_send_apr;\r
+ p_ifc->send_sidr_req = cm_send_sidr_req;\r
+ p_ifc->send_sidr_rep = cm_send_sidr_rep;\r
+ p_ifc->get_qp_attr = cm_get_qp_attr;\r
+ p_ifc->migrate = cm_migrate;\r
+ p_ifc->established = cm_establish;\r
+}\r
#include <complib/cl_rbmap.h>\r
#include <complib/cl_qmap.h>\r
#include <complib/cl_spinlock.h>\r
+#include <iba/ib_cm_ifc.h>\r
#include "al_common.h"\r
#include "al_cm_cep.h"\r
#include "al_cm_conn.h"\r
ib_mad_svc_handle_t h_mad_svc;\r
ib_mad_element_t *p_send_mad;\r
\r
- /* Number of outstanding MADs. Delays destruction of CEP destruction. */\r
atomic32_t ref_cnt;\r
\r
/* MAD transaction ID to use when sending MADs. */\r
} mads;\r
\r
/*\r
- * NDI stuff\r
+ * NDI stuff - TODO: manage above core kernel CM code\r
*/\r
\r
/* IRP list head */\r
\r
KeAcquireInStackQueuedSpinLockAtDpcLevel( &gp_cep_mgr->lock, &hdl );\r
\r
- if( conn_req_get_qp_type( p_req ) > IB_QPT_UNRELIABLE_CONN )\r
+ if( conn_req_get_qp_type( p_req ) > IB_QPT_UNRELIABLE_CONN ||\r
+ conn_req_get_lcl_qpn( p_req ) == 0 )\r
{\r
/* Reserved value. Reject. */\r
AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid transport type received.\n") );\r
return IB_INVALID_STATE;\r
}\r
\r
+ // TODO: Remove - manage above core kernel CM code\r
/* NDI connection request case */\r
if ( p_cep->state == CEP_STATE_LISTEN &&\r
(p_cep->sid & ~0x0ffffffI64) == IB_REQ_CM_RDMA_SID_PREFIX )\r
cl_spinlock_release( &h_al->obj.lock );\r
}\r
\r
+ib_api_status_t\r
+kal_alloc_cep(\r
+ IN ib_al_handle_t h_al,\r
+ IN OUT net32_t* const p_cid )\r
+{\r
+ kcep_t *p_cep;\r
+ KLOCK_QUEUE_HANDLE hdl;\r
+ ib_api_status_t status = IB_SUCCESS;\r
+\r
+ KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl );\r
+ p_cep = __create_cep();\r
+ KeReleaseInStackQueuedSpinLock( &hdl );\r
+\r
+ if( p_cep )\r
+ {\r
+ __bind_cep(p_cep, h_al, NULL, NULL);\r
+ *p_cid = p_cep->cid;\r
+ }\r
+ else\r
+ {\r
+ status = IB_INSUFFICIENT_MEMORY;\r
+ }\r
+\r
+ return status;\r
+}\r
+\r
+ib_api_status_t\r
+kal_config_cep(\r
+ IN ib_al_handle_t h_al,\r
+ IN net32_t cid,\r
+ IN al_pfn_cep_cb_t pfn_cb,\r
+ IN void* context,\r
+ IN ib_pfn_destroy_cb_t pfn_destroy_cb )\r
+{\r
+ kcep_t *p_cep;\r
+ KLOCK_QUEUE_HANDLE hdl;\r
+ ib_api_status_t status = IB_SUCCESS;\r
+\r
+ KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl );\r
+ p_cep = __lookup_cep( h_al, cid );\r
+ if (!p_cep )\r
+ {\r
+ status = IB_INVALID_PARAMETER;\r
+ goto out;\r
+ }\r
+\r
+ p_cep->pfn_cb = pfn_cb;\r
+ p_cep->context = context;\r
+ p_cep->pfn_destroy_cb = pfn_destroy_cb;\r
+\r
+out:\r
+ KeReleaseInStackQueuedSpinLock( &hdl );\r
+ return status;\r
+}\r
\r
static inline void\r
__unbind_cep(\r
sizeof(p_cep->local_ca_guid), NULL, 0 );\r
break;\r
\r
- case CEP_STATE_ESTABLISHED:\r
- case CEP_STATE_LAP_RCVD:\r
case CEP_STATE_LAP_SENT:\r
case CEP_STATE_LAP_MRA_RCVD:\r
+ ib_cancel_mad( p_cep->h_mad_svc, p_cep->p_send_mad );\r
+ /* fall through */\r
+ case CEP_STATE_ESTABLISHED:\r
+ case CEP_STATE_LAP_RCVD:\r
case CEP_STATE_LAP_MRA_SENT:\r
case CEP_STATE_PRE_APR:\r
case CEP_STATE_PRE_APR_MRA_SENT:\r
/* Fall through. */\r
\r
case CEP_STATE_DREQ_SENT:\r
+ ib_cancel_mad( p_cep->h_mad_svc, p_cep->p_send_mad );\r
p_cep->state = CEP_STATE_DREQ_DESTROY;\r
- AL_EXIT( AL_DBG_CM );\r
- return cl_atomic_dec( &p_cep->ref_cnt );\r
+ goto out;\r
\r
case CEP_STATE_DREQ_RCVD:\r
/* Send the DREP. */\r
case CEP_STATE_TIMEWAIT:\r
/* Already in timewait - so all is good. */\r
p_cep->state = CEP_STATE_DESTROY;\r
- AL_EXIT( AL_DBG_CM );\r
- return cl_atomic_dec( &p_cep->ref_cnt );\r
+ goto out;\r
}\r
\r
p_cep->state = CEP_STATE_DESTROY;\r
__insert_timewait( p_cep );\r
\r
+out:\r
AL_EXIT( AL_DBG_CM );\r
return cl_atomic_dec( &p_cep->ref_cnt );\r
}\r
IN ib_pfn_destroy_cb_t pfn_destroy_cb,\r
IN OUT net32_t* const p_cid )\r
{\r
- kcep_t *p_cep;\r
- KLOCK_QUEUE_HANDLE hdl;\r
+ ib_api_status_t status;\r
\r
AL_ENTER( AL_DBG_CM );\r
+ CL_ASSERT( h_al );\r
\r
- CL_ASSERT( p_cid );\r
-\r
- KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl );\r
- if( *p_cid != AL_INVALID_CID )\r
+ status = kal_alloc_cep(h_al, p_cid);\r
+ if ( status == IB_SUCCESS )\r
{\r
- KeReleaseInStackQueuedSpinLock( &hdl );\r
- return IB_RESOURCE_BUSY;\r
- }\r
- p_cep = __create_cep();\r
- if( !p_cep )\r
- {\r
- KeReleaseInStackQueuedSpinLock( &hdl );\r
- AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Failed to allocate CEP.\n") );\r
- return IB_INSUFFICIENT_MEMORY;\r
+ kal_config_cep(h_al, *p_cid, pfn_cb, context, pfn_destroy_cb);\r
}\r
\r
- __bind_cep( p_cep, h_al, pfn_cb, context );\r
-\r
- p_cep->pfn_destroy_cb = pfn_destroy_cb;\r
- *p_cid = p_cep->cid;\r
-\r
- KeReleaseInStackQueuedSpinLock( &hdl );\r
-\r
- AL_PRINT(TRACE_LEVEL_INFORMATION ,AL_DBG_CM ,\r
- ("Created CEP with cid %d, h_al %p, context %p \n", \r
- p_cep->cid, h_al, p_cep->context ));\r
-\r
AL_EXIT( AL_DBG_CM );\r
- return IB_SUCCESS;\r
+ return status;\r
}\r
\r
\r
\r
KeReleaseInStackQueuedSpinLock( &hdl );\r
\r
- /*\r
- * Done waiting. Release the reference so the timewait timer callback\r
- * can finish cleaning up.\r
- */\r
if( !ref_cnt && pfn_destroy_cb )\r
pfn_destroy_cb( context );\r
\r
AL_EXIT( AL_DBG_CM );\r
}\r
\r
+void\r
+kal_destroy_cep(\r
+ IN ib_al_handle_t h_al,\r
+ IN net32_t cid )\r
+{\r
+ al_destroy_cep(h_al, &cid, FALSE);\r
+}\r
+\r
\r
ib_api_status_t\r
al_cep_listen(\r
\r
static ib_api_status_t\r
__format_req(\r
+ IN cep_agent_t* const p_port_cep,\r
IN kcep_t* const p_cep,\r
- IN const ib_cm_req_t* const p_cm_req )\r
+ IN const iba_cm_req* const p_cm_req )\r
{\r
ib_api_status_t status;\r
mad_cm_req_t* p_req;\r
\r
p_req = (mad_cm_req_t*)p_cep->p_mad->p_mad_buf;\r
\r
- ci_ca_lock_attr( p_cm_req->h_qp->obj.p_ci_ca );\r
+ ci_ca_lock_attr( p_port_cep->h_ca->obj.p_ci_ca );\r
/*\r
* Store the local CA's ack timeout for use when computing\r
* the local ACK timeout.\r
*/\r
p_cep->local_ack_delay =\r
- p_cm_req->h_qp->obj.p_ci_ca->p_pnp_attr->local_ack_delay;\r
- ci_ca_unlock_attr( p_cm_req->h_qp->obj.p_ci_ca );\r
+ p_port_cep->h_ca->obj.p_ci_ca->p_pnp_attr->local_ack_delay;\r
+ ci_ca_unlock_attr( p_port_cep->h_ca->obj.p_ci_ca );\r
\r
/* Format the primary path. */\r
__format_req_path( p_cm_req->p_primary_path,\r
\r
/* Set the local communication in the REQ. */\r
p_req->local_comm_id = p_cep->local_comm_id;\r
- p_req->sid = p_cm_req->svc_id;\r
- p_req->local_ca_guid = p_cm_req->h_qp->obj.p_ci_ca->verbs.guid;\r
+ p_req->sid = p_cm_req->service_id;\r
+ p_req->local_ca_guid = p_port_cep->h_ca->obj.p_ci_ca->verbs.guid;\r
\r
conn_req_set_lcl_qpn( p_cep->local_qpn, p_req );\r
conn_req_set_resp_res( p_cm_req->resp_res, p_req );\r
conn_req_set_init_depth( p_cm_req->init_depth, p_req );\r
conn_req_set_remote_resp_timeout( p_cm_req->remote_resp_timeout, p_req );\r
- conn_req_set_qp_type( p_cm_req->h_qp->type, p_req );\r
+ conn_req_set_qp_type( p_cm_req->qp_type, p_req );\r
conn_req_set_flow_ctrl( p_cm_req->flow_ctrl, p_req );\r
- conn_req_set_starting_psn( p_cep->rq_psn, p_req );\r
+ conn_req_set_starting_psn( p_cm_req->starting_psn, p_req );\r
\r
conn_req_set_lcl_resp_timeout( p_cm_req->local_resp_timeout, p_req );\r
conn_req_set_retry_cnt( p_cm_req->retry_cnt, p_req );\r
\r
conn_req_set_max_cm_retries( p_cm_req->max_cm_retries, p_req );\r
status = conn_req_set_pdata(\r
- p_cm_req->p_req_pdata, p_cm_req->req_length, p_req );\r
+ p_cm_req->p_pdata, p_cm_req->pdata_len, p_req );\r
\r
conn_req_clr_rsvd_fields( p_req );\r
\r
static ib_api_status_t\r
__save_user_req(\r
IN kcep_t* const p_cep,\r
- IN const ib_cm_req_t* const p_cm_req,\r
+ IN const iba_cm_req* const p_cm_req,\r
+ IN uint8_t rnr_nak_timeout,\r
OUT cep_agent_t** const pp_port_cep )\r
{\r
cep_agent_t *p_port_cep;\r
return IB_INVALID_SETTING;\r
}\r
\r
- p_cep->sid = p_cm_req->svc_id;\r
-\r
+ p_cep->sid = p_cm_req->service_id;\r
p_cep->idx_primary = 0;\r
-\r
- p_cep->p2p = (p_cm_req->pfn_cm_req_cb != NULL);\r
-\r
- if( p_cm_req->p_compare_buffer )\r
- {\r
- if( !p_cm_req->compare_length ||\r
- (p_cm_req->compare_offset + p_cm_req->compare_length) >\r
- IB_REQ_PDATA_SIZE )\r
- {\r
- AL_EXIT( AL_DBG_CM );\r
- return IB_INVALID_SETTING;\r
- }\r
- p_cep->p_cmp_buf = cl_malloc( p_cm_req->compare_length );\r
- if( !p_cep->p_cmp_buf )\r
- {\r
- AL_EXIT( AL_DBG_CM );\r
- return IB_INSUFFICIENT_MEMORY;\r
- }\r
-\r
- cl_memcpy( p_cep->p_cmp_buf,\r
- p_cm_req->p_compare_buffer, p_cm_req->compare_length );\r
-\r
- p_cep->cmp_len = p_cm_req->compare_length;\r
- p_cep->cmp_offset = p_cm_req->compare_offset;\r
- }\r
- else\r
- {\r
- p_cep->p_cmp_buf = NULL;\r
- p_cep->cmp_len = 0;\r
- p_cep->cmp_offset = 0;\r
- }\r
+ p_cep->p2p = FALSE;\r
+ p_cep->p_cmp_buf = NULL;\r
+ p_cep->cmp_len = 0;\r
+ p_cep->cmp_offset = 0;\r
p_cep->was_active = TRUE;\r
\r
/* Validate the primary path. */\r
\r
p_cep->av[0].attr.conn.seq_err_retry_cnt = p_cm_req->retry_cnt;\r
\r
- /* Make sure the paths will work on the desired QP. */\r
- if( p_port_cep->h_ca->obj.p_ci_ca->verbs.guid !=\r
- p_cm_req->h_qp->obj.p_ci_ca->verbs.guid )\r
- {\r
- AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
- ("Primary path not realizable on given QP.\n") );\r
- return IB_INVALID_SETTING;\r
- }\r
-\r
p_cep->local_ca_guid = p_port_cep->h_ca->obj.p_ci_ca->verbs.guid;\r
\r
*pp_port_cep = p_port_cep;\r
p_cep->remote_comm_id = 0;\r
\r
/* Cache the local QPN. */\r
- p_cep->local_qpn = p_cm_req->h_qp->num;\r
+ p_cep->local_qpn = p_cm_req->qpn;\r
p_cep->remote_ca_guid = 0;\r
p_cep->remote_qpn = 0;\r
\r
*/\r
p_cep->timewait_time.QuadPart = 0;\r
\r
- p_cep->rq_psn = p_cep->local_qpn;\r
+ p_cep->rq_psn = p_cm_req->starting_psn;\r
\r
- p_cep->rnr_nak_timeout = p_cm_req->rnr_nak_timeout;\r
+ p_cep->rnr_nak_timeout = rnr_nak_timeout;\r
\r
AL_EXIT( AL_DBG_CM );\r
return IB_SUCCESS;\r
\r
\r
ib_api_status_t\r
-al_cep_pre_req(\r
+kal_cep_pre_req(\r
IN ib_al_handle_t h_al,\r
IN net32_t cid,\r
- IN const ib_cm_req_t* const p_cm_req,\r
- OUT ib_qp_mod_t* const p_init )\r
+ IN const iba_cm_req* const p_cm_req,\r
+ IN OUT ib_qp_mod_t* const p_init )\r
{\r
ib_api_status_t status;\r
kcep_t *p_cep;\r
CL_ASSERT( p_cm_req );\r
CL_ASSERT( p_init );\r
\r
- /* TODO: Code P2P support. */\r
- if( p_cm_req->pfn_cm_req_cb )\r
- {\r
- AL_EXIT( AL_DBG_CM );\r
- return IB_UNSUPPORTED;\r
- }\r
-\r
KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl );\r
p_cep = __lookup_cep( h_al, cid );\r
if( !p_cep )\r
p_cep->p_mad = NULL;\r
/* Fall through. */\r
case CEP_STATE_IDLE:\r
- status = __save_user_req( p_cep, p_cm_req, &p_port_cep );\r
+ status = __save_user_req( p_cep, p_cm_req,\r
+ p_init->state.rtr.rnr_nak_timeout, &p_port_cep );\r
if( status != IB_SUCCESS )\r
break;\r
\r
if( status != IB_SUCCESS )\r
break;\r
\r
- status = __format_req( p_cep, p_cm_req );\r
+ status = __format_req( p_port_cep, p_cep, p_cm_req );\r
if( status != IB_SUCCESS )\r
{\r
AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid pdata length.\n") );\r
return status;\r
}\r
\r
+ib_api_status_t\r
+al_cep_pre_req(\r
+ IN ib_al_handle_t h_al,\r
+ IN net32_t cid,\r
+ IN const ib_cm_req_t* const p_cm_req,\r
+ OUT ib_qp_mod_t* const p_init )\r
+{\r
+ iba_cm_req req;\r
+ \r
+ RtlZeroMemory(&req, sizeof req);\r
+ req.service_id = p_cm_req->svc_id;\r
+\r
+ req.p_primary_path = p_cm_req->p_primary_path;\r
+ req.p_alt_path = p_cm_req->p_alt_path;\r
+\r
+ req.qpn = p_cm_req->h_qp->num;\r
+ req.qp_type = p_cm_req->qp_type;\r
+ req.starting_psn = req.qpn;\r
+\r
+ req.p_pdata = (void *) p_cm_req->p_req_pdata;\r
+ req.pdata_len = p_cm_req->req_length;\r
+\r
+ req.max_cm_retries = p_cm_req->max_cm_retries;\r
+ req.resp_res = p_cm_req->resp_res;\r
+ req.init_depth = p_cm_req->init_depth;\r
+ req.remote_resp_timeout = p_cm_req->remote_resp_timeout;\r
+ req.flow_ctrl = (uint8_t) p_cm_req->flow_ctrl;\r
+ req.local_resp_timeout = p_cm_req->local_resp_timeout;\r
+ req.rnr_retry_cnt = p_cm_req->rnr_retry_cnt;\r
+ req.retry_cnt = p_cm_req->retry_cnt;\r
+ req.srq = (uint8_t) (p_cm_req->h_qp->h_srq != NULL);\r
+\r
+ p_init->state.rtr.rnr_nak_timeout = p_cm_req->rnr_nak_timeout;\r
+\r
+ return kal_cep_pre_req(h_al, cid, &req, p_init);\r
+}\r
\r
ib_api_status_t\r
al_cep_send_req(\r
\r
static void\r
__save_user_rep(\r
+ IN cep_agent_t* const p_port_cep,\r
IN kcep_t* const p_cep,\r
- IN const ib_cm_rep_t* const p_cm_rep )\r
+ IN const iba_cm_rep* const p_cm_rep,\r
+ IN uint8_t rnr_nak_timeout )\r
{\r
AL_ENTER( AL_DBG_CM );\r
\r
- /* Cache the local QPN. */\r
- p_cep->local_qpn = p_cm_rep->h_qp->num;\r
- p_cep->rq_psn = p_cep->local_qpn;\r
+ p_cep->local_qpn = p_cm_rep->qpn;\r
+ p_cep->rq_psn = p_cm_rep->starting_psn;\r
p_cep->init_depth = p_cm_rep->init_depth;\r
\r
- ci_ca_lock_attr( p_cm_rep->h_qp->obj.p_ci_ca );\r
+ ci_ca_lock_attr( p_port_cep->h_ca->obj.p_ci_ca );\r
/* Check the CA's responder resource max and trim if necessary. */\r
- if( (p_cm_rep->h_qp->obj.p_ci_ca->p_pnp_attr->max_qp_resp_res <\r
- p_cep->resp_res) )\r
+ if( p_port_cep->h_ca->obj.p_ci_ca->p_pnp_attr->max_qp_resp_res <\r
+ p_cep->resp_res )\r
{\r
/*\r
* The CA cannot handle the requested responder resources.\r
* Set the response to the CA's maximum.\r
*/\r
p_cep->resp_res = \r
- p_cm_rep->h_qp->obj.p_ci_ca->p_pnp_attr->max_qp_resp_res;\r
+ p_port_cep->h_ca->obj.p_ci_ca->p_pnp_attr->max_qp_resp_res;\r
}\r
- ci_ca_unlock_attr( p_cm_rep->h_qp->obj.p_ci_ca );\r
+ ci_ca_unlock_attr( p_port_cep->h_ca->obj.p_ci_ca );\r
\r
- p_cep->rnr_nak_timeout = p_cm_rep->rnr_nak_timeout;\r
+ p_cep->rnr_nak_timeout = rnr_nak_timeout;\r
\r
AL_EXIT( AL_DBG_CM );\r
}\r
\r
static ib_api_status_t\r
__format_rep(\r
+ IN cep_agent_t* const p_port_cep,\r
IN kcep_t* const p_cep,\r
- IN const ib_cm_rep_t* const p_cm_rep )\r
+ IN const iba_cm_rep* const p_cm_rep )\r
{\r
ib_api_status_t status;\r
mad_cm_rep_t *p_rep;\r
\r
p_rep->resp_resources = p_cep->resp_res;\r
\r
- ci_ca_lock_attr( p_cm_rep->h_qp->obj.p_ci_ca );\r
+ ci_ca_lock_attr( p_port_cep->h_ca->obj.p_ci_ca );\r
conn_rep_set_target_ack_delay(\r
- p_cm_rep->h_qp->obj.p_ci_ca->p_pnp_attr->local_ack_delay, p_rep );\r
- ci_ca_unlock_attr( p_cm_rep->h_qp->obj.p_ci_ca );\r
+ p_port_cep->h_ca->obj.p_ci_ca->p_pnp_attr->local_ack_delay, p_rep );\r
+ ci_ca_unlock_attr( p_port_cep->h_ca->obj.p_ci_ca );\r
\r
p_rep->initiator_depth = p_cep->init_depth;\r
\r
p_rep->local_ca_guid = p_cep->local_ca_guid;\r
\r
status = conn_rep_set_pdata(\r
- p_cm_rep->p_rep_pdata, p_cm_rep->rep_length, p_rep );\r
+ p_cm_rep->p_pdata, p_cm_rep->pdata_len, p_rep );\r
\r
conn_rep_clr_rsvd_fields( p_rep );\r
\r
\r
\r
\r
-ib_api_status_t\r
+static ib_api_status_t\r
__al_cep_pre_rep(\r
IN kcep_t *p_cep,\r
- IN void* context,\r
- IN const ib_cm_rep_t* const p_cm_rep,\r
+ IN const iba_cm_rep* const p_cm_rep,\r
OUT ib_qp_mod_t* const p_init )\r
{\r
ib_api_status_t status;\r
if( status != IB_SUCCESS )\r
break;\r
\r
- __save_user_rep( p_cep, p_cm_rep );\r
+ __save_user_rep( p_port_cep, p_cep, p_cm_rep,\r
+ p_init->state.rtr.rnr_nak_timeout );\r
\r
- status = __format_rep( p_cep, p_cm_rep );\r
+ status = __format_rep( p_port_cep, p_cep, p_cm_rep );\r
if( status != IB_SUCCESS )\r
{\r
ib_put_mad( p_cep->p_mad );\r
p_cep->av[p_cep->idx_primary].pkey_index;\r
p_init->state.init.access_ctrl = IB_AC_LOCAL_WRITE;\r
\r
- p_cep->context = context;\r
-\r
/* Just OR in the PREP bit into the state. */\r
p_cep->state |= CEP_STATE_PREP;\r
break;\r
IN OUT net32_t* const p_cid,\r
OUT ib_qp_mod_t* const p_init )\r
{\r
- ib_api_status_t status;\r
kcep_t *p_cep;\r
+ iba_cm_rep rep;\r
KLOCK_QUEUE_HANDLE hdl;\r
+ ib_api_status_t status;\r
\r
- AL_ENTER( AL_DBG_CM );\r
+ RtlZeroMemory(&rep, sizeof rep);\r
+ rep.qpn = p_cm_rep->h_qp->num;\r
+ rep.starting_psn = rep.qpn;\r
\r
- CL_ASSERT( h_al );\r
- CL_ASSERT( p_cm_rep );\r
- CL_ASSERT( p_init );\r
+ rep.p_pdata = (void *) p_cm_rep->p_rep_pdata;\r
+ rep.pdata_len = p_cm_rep->rep_length;\r
\r
- KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl );\r
- if( *p_cid != AL_INVALID_CID )\r
- {\r
- KeReleaseInStackQueuedSpinLock( &hdl );\r
- AL_EXIT( AL_DBG_CM );\r
- return IB_RESOURCE_BUSY;\r
- }\r
+ rep.failover_accepted = p_cm_rep->failover_accepted;\r
+ rep.init_depth = p_cm_rep->init_depth;\r
+ rep.flow_ctrl = (uint8_t) p_cm_rep->flow_ctrl;\r
+ rep.rnr_retry_cnt = p_cm_rep->rnr_retry_cnt;\r
+ rep.srq = (uint8_t) (p_cm_rep->h_qp->h_srq != NULL);\r
\r
+ p_init->state.rtr.rnr_nak_timeout = p_cm_rep->rnr_nak_timeout;\r
+\r
+ KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl );\r
p_cep = __lookup_cep( h_al, cid );\r
- if( !p_cep )\r
+ if (!p_cep )\r
{\r
- KeReleaseInStackQueuedSpinLock( &hdl );\r
- AL_EXIT( AL_DBG_CM );\r
- return IB_INVALID_HANDLE;\r
+ status = IB_INVALID_HANDLE;\r
+ goto out;\r
}\r
\r
- status = __al_cep_pre_rep( p_cep, context, p_cm_rep, p_init );\r
-\r
- if( status == IB_SUCCESS )\r
+ rep.resp_res = p_cep->resp_res;\r
+ status = __al_cep_pre_rep( p_cep, &rep, p_init );\r
+ if ( status == IB_SUCCESS )\r
{\r
+ p_cep->context = context;\r
p_cep->pfn_destroy_cb = pfn_destroy_cb;\r
*p_cid = cid;\r
}\r
\r
+out:\r
KeReleaseInStackQueuedSpinLock( &hdl );\r
- AL_EXIT( AL_DBG_CM );\r
return status;\r
}\r
\r
\r
ib_api_status_t\r
-al_cep_pre_rep_ex(\r
+kal_cep_pre_rep(\r
IN ib_al_handle_t h_al,\r
IN net32_t cid,\r
- IN al_pfn_cep_cb_t pfn_cb,\r
- IN void* context,\r
- IN ib_pfn_destroy_cb_t pfn_destroy_cb,\r
- IN const ib_cm_rep_t* const p_cm_rep,\r
- IN OUT net32_t* const p_cid,\r
+ IN const iba_cm_rep* const p_cm_rep,\r
OUT ib_qp_mod_t* const p_init )\r
{\r
ib_api_status_t status;\r
CL_ASSERT( p_init );\r
\r
KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl );\r
- if( *p_cid != AL_INVALID_CID )\r
- {\r
- KeReleaseInStackQueuedSpinLock( &hdl );\r
- AL_EXIT( AL_DBG_CM );\r
- return IB_RESOURCE_BUSY;\r
- }\r
-\r
p_cep = __lookup_cep( h_al, cid );\r
if( !p_cep )\r
{\r
- KeReleaseInStackQueuedSpinLock( &hdl );\r
- AL_EXIT( AL_DBG_CM );\r
- return IB_INVALID_HANDLE;\r
+ status = IB_INVALID_HANDLE;\r
+ goto out;\r
}\r
\r
- status = __al_cep_pre_rep( p_cep, context, p_cm_rep, p_init );\r
-\r
- if( status == IB_SUCCESS )\r
- {\r
- p_cep->pfn_cb = pfn_cb;\r
- p_cep->pfn_destroy_cb = pfn_destroy_cb;\r
- *p_cid = cid;\r
- }\r
+ status = __al_cep_pre_rep( p_cep, p_cm_rep, p_init );\r
\r
+out:\r
KeReleaseInStackQueuedSpinLock( &hdl );\r
AL_EXIT( AL_DBG_CM );\r
return status;\r
p_cep = __lookup_cep( h_al, cid );\r
if( !p_cep )\r
{\r
- KeReleaseInStackQueuedSpinLock( &hdl );\r
- AL_EXIT( AL_DBG_CM );\r
- return IB_INVALID_HANDLE;\r
+ status = IB_INVALID_HANDLE;\r
+ goto out;\r
}\r
\r
switch( p_cep->state )\r
p_port_cep = __get_cep_agent( p_cep );\r
if( !p_port_cep )\r
{\r
+ // Why call ib_put_mad() here but not below?\r
ib_put_mad( p_cep->p_mad );\r
+ // Why call __remove_cep() below but not here?\r
p_cep->state = CEP_STATE_IDLE;\r
status = IB_INSUFFICIENT_RESOURCES;\r
}\r
("Invalid state: %d\n", p_cep->state) );\r
status = IB_INVALID_STATE;\r
}\r
+out:\r
KeReleaseInStackQueuedSpinLock( &hdl );\r
AL_EXIT( AL_DBG_CM );\r
return status;\r
return status;\r
}\r
\r
+static void\r
+__format_path(ib_path_rec_t *p_path, req_path_info_t *p_info,\r
+ ib_net16_t pkey, uint8_t mtu)\r
+{\r
+ p_path->resv0 = 0;\r
+ p_path->dgid = p_info->local_gid;\r
+ p_path->sgid = p_info->remote_gid;\r
+ p_path->dlid = p_info->local_lid;\r
+ p_path->slid = p_info->remote_lid;\r
+ ib_path_rec_set_hop_flow_raw(p_path, p_info->hop_limit, \r
+ conn_req_path_get_flow_lbl(p_info), 0);\r
+ p_path->tclass = p_info->traffic_class;\r
+ p_path->num_path = 0;\r
+ p_path->pkey = pkey;\r
+ p_path->sl = conn_req_path_get_svc_lvl(p_info);\r
+ p_path->mtu = mtu;\r
+ p_path->rate = conn_req_path_get_pkt_rate(p_info);\r
+ p_path->pkt_life = conn_req_path_get_lcl_ack_timeout(p_info);\r
+ p_path->preference = 0;\r
+ p_path->resv1 = 0;\r
+ p_path->resv2 = 0;\r
+}\r
+\r
+static void\r
+__format_event_req(kcep_t *p_cep, mad_cm_req_t *p_mad, iba_cm_req_event *p_req)\r
+{\r
+ p_req->local_ca_guid = p_cep->local_ca_guid;\r
+ p_req->remote_ca_guid = p_cep->remote_ca_guid;\r
+ p_req->pkey_index = p_cep->av[0].pkey_index;\r
+ p_req->port_num = p_cep->av[0].attr.port_num;\r
+ p_req->req.service_id = p_mad->sid;\r
+\r
+ p_req->req.qpn = conn_req_get_lcl_qpn(p_mad);\r
+ p_req->req.qp_type = conn_req_get_qp_type(p_mad);\r
+ p_req->req.starting_psn = conn_req_get_starting_psn(p_mad);\r
+\r
+ p_req->req.p_pdata = p_mad->pdata;\r
+ p_req->req.pdata_len = IB_REQ_PDATA_SIZE;\r
+\r
+ p_req->req.max_cm_retries = conn_req_get_max_cm_retries(p_mad);\r
+ p_req->req.resp_res = conn_req_get_init_depth(p_mad);\r
+ p_req->req.init_depth = conn_req_get_resp_res(p_mad);\r
+ p_req->req.remote_resp_timeout = conn_req_get_resp_timeout(p_mad);\r
+ p_req->req.flow_ctrl = (uint8_t) conn_req_get_flow_ctrl(p_mad);\r
+ p_req->req.local_resp_timeout = conn_req_get_lcl_resp_timeout(p_mad);\r
+ p_req->req.rnr_retry_cnt = conn_req_get_rnr_retry_cnt(p_mad);\r
+ p_req->req.retry_cnt = conn_req_get_retry_cnt(p_mad);\r
+ p_req->req.srq = 0; // TODO: fix mad_cm_req_t\r
+\r
+ // We can re-use the MAD buffer if we're careful to read out the data\r
+ // that we need before it's overwritten.\r
+ p_req->req.p_primary_path = (ib_path_rec_t *) p_mad;\r
+ __format_path(p_req->req.p_primary_path, &p_mad->primary_path,\r
+ p_mad->pkey, conn_req_get_mtu(p_mad));\r
+\r
+ if (p_mad->alternate_path.remote_lid != 0) {\r
+ p_req->req.p_alt_path = p_req->req.p_primary_path + 1;\r
+ __format_path(p_req->req.p_alt_path, &p_mad->alternate_path,\r
+ p_req->req.p_primary_path->pkey,\r
+ p_req->req.p_primary_path->mtu);\r
+ } else {\r
+ p_req->req.p_alt_path = NULL;\r
+ }\r
+}\r
+\r
+static void\r
+__format_event_rep(mad_cm_rep_t *p_mad, iba_cm_rep_event *p_rep)\r
+{\r
+ p_rep->ca_guid = p_mad->local_ca_guid;\r
+ p_rep->target_ack_delay = conn_rep_get_target_ack_delay(p_mad);\r
+ p_rep->rep.qpn = conn_rep_get_lcl_qpn(p_mad);\r
+ p_rep->rep.starting_psn = conn_rep_get_starting_psn(p_mad);\r
+\r
+ p_rep->rep.p_pdata = p_mad->pdata;\r
+ p_rep->rep.pdata_len = IB_REP_PDATA_SIZE;\r
+\r
+ p_rep->rep.failover_accepted = conn_rep_get_failover(p_mad);\r
+ p_rep->rep.resp_res = p_mad->initiator_depth;\r
+ p_rep->rep.init_depth = p_mad->resp_resources;\r
+ p_rep->rep.flow_ctrl = (uint8_t) conn_rep_get_e2e_flow_ctl(p_mad);\r
+ p_rep->rep.rnr_retry_cnt = conn_rep_get_rnr_retry_cnt(p_mad);\r
+}\r
+\r
+static void\r
+__format_event_rej(mad_cm_rej_t *p_mad, iba_cm_rej_event *p_rej)\r
+{\r
+ p_rej->ari = p_mad->ari;\r
+ p_rej->p_pdata = p_mad->pdata;\r
+ p_rej->reason = p_mad->reason;\r
+ p_rej->ari_length = conn_rej_get_ari_len(p_mad);\r
+ p_rej->pdata_len = IB_MRA_PDATA_SIZE;\r
+}\r
+\r
+static void\r
+__format_event_mra(mad_cm_mra_t *p_mad, iba_cm_mra_event *p_mra)\r
+{\r
+ p_mra->p_pdata = p_mad->pdata;\r
+ p_mra->pdata_len = IB_MRA_PDATA_SIZE;\r
+ p_mra->service_timeout = conn_mra_get_svc_timeout(p_mad);\r
+}\r
+\r
+static void\r
+__format_event_pdata(kcep_t *p_cep, iba_cm_pdata *p_pdata)\r
+{\r
+ p_pdata->p_pdata = p_cep->pdata;\r
+ p_pdata->pdata_len = p_cep->psize;\r
+}\r
+\r
+/*\r
+ * Called after polling a MAD from a CEP to parse the received CM message\r
+ * into readable event data.\r
+ */\r
+void\r
+kal_cep_format_event(\r
+ IN ib_al_handle_t h_al,\r
+ IN net32_t cid,\r
+ IN ib_mad_element_t *p_mad,\r
+ IN OUT iba_cm_event *p_event)\r
+{\r
+ KLOCK_QUEUE_HANDLE hdl;\r
+ kcep_t *p_cep;\r
+ \r
+ KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl );\r
+ p_cep = __lookup_cep( h_al, cid );\r
+ KeReleaseInStackQueuedSpinLock( &hdl );\r
+\r
+ switch (p_mad->p_mad_buf->attr_id) {\r
+ case CM_REQ_ATTR_ID:\r
+ if (p_mad->status == IB_SUCCESS) {\r
+ p_event->type = iba_cm_req_received;\r
+ __format_event_req(p_cep, (mad_cm_req_t*) p_mad->p_mad_buf, &p_event->data.req);\r
+ } else {\r
+ p_event->type = iba_cm_req_error;\r
+ }\r
+ break;\r
+ case CM_REP_ATTR_ID:\r
+ if (p_mad->status == IB_SUCCESS) {\r
+ p_event->type = iba_cm_rep_received;\r
+ __format_event_rep((mad_cm_rep_t*) p_mad->p_mad_buf, &p_event->data.rep);\r
+ } else {\r
+ p_event->type = iba_cm_rep_error;\r
+ }\r
+ break;\r
+ case CM_RTU_ATTR_ID:\r
+ p_event->type = iba_cm_rtu_received;\r
+ __format_event_pdata(p_cep, &p_event->data.rtu);\r
+ break;\r
+ case CM_DREQ_ATTR_ID:\r
+ if (p_mad->status == IB_SUCCESS) {\r
+ p_event->type = iba_cm_dreq_received;\r
+ __format_event_pdata(p_cep, &p_event->data.dreq);\r
+ } else {\r
+ p_event->type = iba_cm_dreq_error;\r
+ }\r
+ break;\r
+ case CM_DREP_ATTR_ID:\r
+ p_event->type = iba_cm_drep_received;\r
+ __format_event_pdata(p_cep, &p_event->data.drep);\r
+ break;\r
+ case CM_REJ_ATTR_ID:\r
+ p_event->type = iba_cm_rej_received;\r
+ __format_event_rej((mad_cm_rej_t*) p_mad->p_mad_buf, &p_event->data.rej);\r
+ break;\r
+ case CM_MRA_ATTR_ID:\r
+ p_event->type = iba_cm_mra_received;\r
+ __format_event_mra((mad_cm_mra_t*) p_mad->p_mad_buf, &p_event->data.mra);\r
+ break;\r
+ case CM_LAP_ATTR_ID:\r
+ if (p_mad->status == IB_SUCCESS) {\r
+ p_event->type = iba_cm_lap_received;\r
+ // TODO: format lap event\r
+ } else {\r
+ p_event->type = iba_cm_lap_error;\r
+ }\r
+ break;\r
+ case CM_APR_ATTR_ID:\r
+ p_event->type = iba_cm_apr_received;;\r
+ // TODO: format apr event\r
+ break;\r
+ case CM_SIDR_REQ_ATTR_ID:\r
+ if (p_mad->status == IB_SUCCESS) {\r
+ p_event->type = iba_cm_sidr_req_received;\r
+ // TODO: format sidr req event\r
+ } else {\r
+ p_event->type = iba_cm_sidr_req_error;\r
+ }\r
+ break;\r
+ case CM_SIDR_REP_ATTR_ID:\r
+ p_event->type = iba_cm_sidr_rep_received;\r
+ // TODO: format sidr rep event\r
+ break;\r
+ default:\r
+ CL_ASSERT(0);\r
+ }\r
+}\r
+\r
+\r
+ib_api_status_t\r
+al_cep_get_init_attr(\r
+ IN ib_al_handle_t h_al,\r
+ IN net32_t cid,\r
+ OUT ib_qp_mod_t* const p_init )\r
+{\r
+ ib_api_status_t status;\r
+ kcep_t *p_cep;\r
+ KLOCK_QUEUE_HANDLE hdl;\r
+\r
+ AL_ENTER( AL_DBG_CM );\r
+\r
+ KeAcquireInStackQueuedSpinLock( &gp_cep_mgr->lock, &hdl );\r
+ p_cep = __lookup_cep( h_al, cid );\r
+ if( !p_cep )\r
+ {\r
+ status = IB_INVALID_HANDLE;\r
+ goto out;\r
+ }\r
+\r
+ switch( p_cep->state )\r
+ {\r
+ case CEP_STATE_PRE_REQ:\r
+ case CEP_STATE_REQ_RCVD:\r
+ case CEP_STATE_PRE_REP:\r
+ case CEP_STATE_REQ_SENT:\r
+ case CEP_STATE_REQ_MRA_RCVD:\r
+ case CEP_STATE_REQ_MRA_SENT:\r
+ case CEP_STATE_PRE_REP_MRA_SENT:\r
+ case CEP_STATE_REP_RCVD:\r
+ case CEP_STATE_REP_SENT:\r
+ case CEP_STATE_REP_MRA_RCVD:\r
+ case CEP_STATE_REP_MRA_SENT:\r
+ case CEP_STATE_ESTABLISHED:\r
+ /* Format the INIT qp modify attributes. */\r
+ cl_memclr(p_init, sizeof(ib_qp_mod_t));\r
+ p_init->req_state = IB_QPS_INIT;\r
+ p_init->state.init.primary_port =\r
+ p_cep->av[p_cep->idx_primary].attr.port_num;\r
+ p_init->state.init.pkey_index =\r
+ p_cep->av[p_cep->idx_primary].pkey_index;\r
+ p_init->state.init.access_ctrl = IB_AC_LOCAL_WRITE;\r
+ if ( p_cep->resp_res )\r
+ {\r
+ p_init->state.init.access_ctrl |= IB_AC_RDMA_READ |\r
+ IB_AC_RDMA_WRITE |\r
+ IB_AC_ATOMIC;\r
+ }\r
+ status = IB_SUCCESS;\r
+ break;\r
+ default:\r
+ status = IB_INVALID_STATE;\r
+ break;\r
+ }\r
+\r
+out:\r
+ KeReleaseInStackQueuedSpinLock( &hdl );\r
+ AL_EXIT( AL_DBG_CM );\r
+ return status;\r
+}\r
\r
ib_api_status_t\r
al_cep_get_rtr_attr(\r
\r
switch( p_cep->state )\r
{\r
+ case CEP_STATE_REQ_RCVD:\r
+ case CEP_STATE_REQ_MRA_SENT:\r
case CEP_STATE_PRE_REP:\r
case CEP_STATE_PRE_REP_MRA_SENT:\r
case CEP_STATE_REP_SENT:\r
__ndi_fill_cm_rep(\r
IN ib_qp_handle_t const h_qp,\r
IN ual_ndi_rep_cm_ioctl_in_t *p_rep,\r
- OUT ib_cm_rep_t *p_cm_rep)\r
+ OUT iba_cm_rep *p_cm_rep)\r
{\r
AL_ENTER( AL_DBG_NDI );\r
\r
- memset( p_cm_rep, 0, sizeof(ib_cm_rep_t) );\r
+ memset( p_cm_rep, 0, sizeof(iba_cm_rep) );\r
\r
- p_cm_rep->p_rep_pdata = p_rep->pdata;\r
- p_cm_rep->rep_length = sizeof(p_rep->pdata);\r
+ p_cm_rep->p_pdata = p_rep->pdata;\r
+ p_cm_rep->pdata_len = sizeof(p_rep->pdata);\r
\r
- p_cm_rep->qp_type = IB_QPT_RELIABLE_CONN;\r
- p_cm_rep->h_qp = h_qp;\r
+ p_cm_rep->qpn = h_qp->num;\r
\r
- p_cm_rep->access_ctrl = IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE;\r
p_cm_rep->init_depth = p_rep->init_depth;\r
- p_cm_rep->target_ack_delay = 10;\r
p_cm_rep->failover_accepted = IB_FAILOVER_ACCEPT_UNSUPPORTED;\r
p_cm_rep->flow_ctrl = TRUE; /* HCAs must support end-to-end flow control. */\r
- p_cm_rep->rnr_nak_timeout = QP_ATTRIB_RNR_NAK_TIMEOUT;\r
p_cm_rep->rnr_retry_cnt = QP_ATTRIB_RNR_RETRY;\r
\r
AL_EXIT( AL_DBG_NDI );\r
IN PIRP p_irp )\r
{\r
IO_STACK_LOCATION *p_io_stack;\r
- ib_cm_rep_t cm_rep;\r
+ iba_cm_rep cm_rep;\r
ib_qp_mod_t qp_mod;\r
ib_api_status_t status;\r
ual_ndi_rep_cm_ioctl_in_t *p_rep = \r
\r
/* Format ib_cm_req_t structure */\r
__ndi_fill_cm_rep( h_qp, p_rep, &cm_rep );\r
+ qp_mod.state.rtr.rnr_nak_timeout = QP_ATTRIB_RNR_NAK_TIMEOUT;\r
\r
ref_al_obj( &h_qp->obj ); /* Take CEP reference. */\r
\r
/* prepare Passive CEP for connection */\r
- status = al_cep_pre_rep_ex(\r
- qp_get_al( h_qp ), p_rep->cid, __ndi_cm_handler, h_qp, deref_al_obj,\r
- &cm_rep, &((al_conn_qp_t*)h_qp)->cid, &qp_mod );\r
+ status = kal_config_cep(qp_get_al( h_qp ), p_rep->cid, __ndi_cm_handler,\r
+ h_qp, deref_al_obj);\r
+ if ( status == IB_SUCCESS )\r
+ {\r
+ status = kal_cep_pre_rep(qp_get_al( h_qp ), p_rep->cid,\r
+ &cm_rep, &qp_mod );\r
+ }\r
if( status != IB_SUCCESS )\r
{\r
IoFreeWorkItem( p_irp->Tail.Overlay.DriverContext[1] );\r
al_destroy_cep( qp_get_al( h_qp ), &p_rep->cid, FALSE );\r
deref_al_obj( &h_qp->obj ); /* Release CEP reference. */\r
AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
- ("al_cep_pre_rep_ex returned %s.\n", ib_get_err_str( status )) );\r
+ ("kal_cep_pre_rep returned %s.\n", ib_get_err_str( status )) );\r
switch (status)\r
{\r
case IB_INVALID_HANDLE:\r
return ib_to_ntstatus( status );\r
}\r
}\r
+ else\r
+ {\r
+ ((al_conn_qp_t*)h_qp)->cid = p_rep->cid;\r
+ }\r
\r
AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_NDI,\r
("Prepared Passive CEP with cid %d, h_al %p, context %p\n",\r
/* Create an address vector for the SA. */\r
av_attr.port_num = p_sa_req_svc->port_num;\r
av_attr.sl = p_sa_req_svc->sm_sl;\r
- av_attr.dlid = 1;\r
+ av_attr.dlid = cl_hton16(1);\r
av_attr.grh_valid = FALSE;\r
av_attr.static_rate = IB_PATH_RECORD_RATE_10_GBS;\r
av_attr.path_bits = 0;\r
#include "complib/cl_memory.h"\r
#include <initguid.h>\r
#include "iba/ib_ci_ifc.h"\r
+#include "iba/ib_cm_ifc.h"\r
+#include "al_cm_cep.h"\r
\r
\r
/* Interface names are generated by IoRegisterDeviceInterface. */\r
static UNICODE_STRING al_ifc_name;\r
static UNICODE_STRING ci_ifc_name;\r
+static UNICODE_STRING cm_ifc_name;\r
\r
KEVENT g_ControlEvent;\r
ULONG g_bfi_InstanceCount;\r
IN DEVICE_OBJECT* const p_dev_obj,\r
IN IO_STACK_LOCATION* const p_io_stack );\r
\r
+static NTSTATUS\r
+__query_cm_ifc(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IO_STACK_LOCATION* const p_io_stack );\r
+\r
static NTSTATUS\r
fdo_query_interface(\r
IN DEVICE_OBJECT* const p_dev_obj,\r
#pragma alloc_text (PAGE, fdo_query_bus_relations)\r
#pragma alloc_text (PAGE, __query_al_ifc)\r
#pragma alloc_text (PAGE, __query_ci_ifc)\r
+#pragma alloc_text (PAGE, __query_cm_ifc)\r
#pragma alloc_text (PAGE, __get_relations)\r
#pragma alloc_text (PAGE, fdo_query_interface)\r
#pragma alloc_text (PAGE_PNP, __fdo_query_power)\r
{\r
BUS_PRINT( BUS_DBG_ERROR, \r
("Failed to create ControlDeviceObject, status %x.\n",status) );\r
- goto bail;\r
+ goto err1;\r
}\r
IoDeleteSymbolicLink( &dos_name );\r
status = IoCreateSymbolicLink( &dos_name, &dev_name );\r
if( !NT_SUCCESS(status) )\r
{\r
- IoDeleteDevice( p_dev_obj );\r
BUS_PRINT( BUS_DBG_ERROR,\r
("Failed to create symlink for dos name.\n") );\r
- goto bail;\r
+ goto err2;\r
}\r
}\r
else {\r
{\r
BUS_PRINT( BUS_DBG_ERROR, \r
("Failed to create bus root FDO device.\n") );\r
- goto bail;\r
+ goto err1;\r
}\r
}\r
\r
p_next_do = IoAttachDeviceToDeviceStack( p_dev_obj, p_pdo );\r
if( !p_next_do )\r
{\r
- IoDeleteDevice( p_dev_obj );\r
BUS_PRINT( BUS_DBG_ERROR, ("IoAttachToDeviceStack failed.\n") );\r
status = STATUS_NO_SUCH_DEVICE;\r
- goto bail;\r
+ goto err2;\r
}\r
\r
cl_init_pnp_po_ext( p_dev_obj, p_next_do, p_pdo, bus_globals.dbg_lvl,\r
&al_ifc_name );\r
if( !NT_SUCCESS( status ) )\r
{\r
- IoDetachDevice( p_ext->cl_ext.p_next_do );\r
- IoDeleteDevice( p_dev_obj );\r
BUS_PRINT( BUS_DBG_ERROR, \r
("IoRegisterDeviceInterface for upper interface returned %08x\n",\r
status) );\r
status = STATUS_NO_SUCH_DEVICE;\r
- goto bail;\r
+ goto err3;\r
}\r
\r
/* Register the lower (CI) interface (the one used by HCA VPDs). */\r
&ci_ifc_name );\r
if( !NT_SUCCESS( status ) )\r
{\r
- IoDetachDevice( p_ext->cl_ext.p_next_do );\r
- IoDeleteDevice( p_dev_obj );\r
BUS_PRINT( BUS_DBG_ERROR, \r
("IoRegisterDeviceInterface for lower interface returned %08x\n",\r
status) );\r
status = STATUS_NO_SUCH_DEVICE;\r
- goto bail;\r
+ goto err3;\r
+ }\r
+\r
+ status = IoRegisterDeviceInterface( p_pdo, &GUID_INFINIBAND_INTERFACE_CM, NULL,\r
+ &cm_ifc_name );\r
+ if( !NT_SUCCESS( status ) )\r
+ {\r
+ BUS_PRINT( BUS_DBG_ERROR, \r
+ ("IoRegisterDeviceInterface for cm interface returned %08x\n",\r
+ status) );\r
+ status = STATUS_NO_SUCH_DEVICE;\r
+ goto err3;\r
}\r
\r
adxit:\r
BUS_EXIT( BUS_DBG_PNP );\r
return STATUS_SUCCESS;\r
\r
-bail:\r
+err3:\r
+ IoDetachDevice( p_ext->cl_ext.p_next_do );\r
+err2:\r
+ IoDeleteDevice( p_dev_obj );\r
+err1:\r
BUS_PRINT( BUS_DBG_PNP, ("%s exit status 0x%x\n", p_bfi->whoami,status) );\r
ic = free_bfi(p_bfi);\r
/* if last Bus filter, then cleanup */\r
\r
status = IoSetDeviceInterfaceState( &ci_ifc_name, TRUE );\r
ASSERT( NT_SUCCESS( status ) );\r
+\r
+ status = IoSetDeviceInterfaceState( &cm_ifc_name, TRUE );\r
+ ASSERT( NT_SUCCESS( status ) );\r
}\r
\r
BUS_PRINT(BUS_DBG_PNP,\r
ASSERT( NT_SUCCESS( status ) );\r
status = IoSetDeviceInterfaceState( &ci_ifc_name, FALSE );\r
ASSERT( NT_SUCCESS( status ) );\r
+ status = IoSetDeviceInterfaceState( &cm_ifc_name, FALSE );\r
+ ASSERT( NT_SUCCESS( status ) );\r
\r
/* Release the memory allocated for the interface symbolic names. */\r
+ RtlFreeUnicodeString( &cm_ifc_name );\r
RtlFreeUnicodeString( &ci_ifc_name );\r
RtlFreeUnicodeString( &al_ifc_name );\r
\r
}\r
\r
\r
+static NTSTATUS\r
+__query_cm_ifc(\r
+ IN DEVICE_OBJECT* const p_dev_obj,\r
+ IN IO_STACK_LOCATION* const p_io_stack )\r
+{\r
+ INFINIBAND_INTERFACE_CM *p_ifc;\r
+\r
+ BUS_ENTER( BUS_DBG_PNP );\r
+\r
+ if( p_io_stack->Parameters.QueryInterface.Version != IbaCmVersion(1, 0) )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_PNP, ("Incorrect interface version (%d)\n",\r
+ p_io_stack->Parameters.QueryInterface.Version ) );\r
+ return STATUS_NOT_SUPPORTED;\r
+ }\r
+\r
+ if( p_io_stack->Parameters.QueryInterface.Size < sizeof(INFINIBAND_INTERFACE_CM) )\r
+ {\r
+ BUS_TRACE_EXIT( BUS_DBG_PNP, \r
+ ("Buffer too small (%d given, %d required).\n",\r
+ p_io_stack->Parameters.QueryInterface.Size, sizeof(INFINIBAND_INTERFACE_CM)) );\r
+ return STATUS_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ /* Copy the interface. */\r
+ p_ifc = (INFINIBAND_INTERFACE_CM*)p_io_stack->Parameters.QueryInterface.Interface;\r
+\r
+ p_ifc->InterfaceHeader.Size = sizeof(INFINIBAND_INTERFACE_CM);\r
+ p_ifc->InterfaceHeader.Version = IbaCmVersion(1, 0);\r
+ p_ifc->InterfaceHeader.Context = p_dev_obj;\r
+ p_ifc->InterfaceHeader.InterfaceReference = al_ref_ifc;\r
+ p_ifc->InterfaceHeader.InterfaceDereference = al_deref_ifc;\r
+ cm_get_interface(&p_ifc->CM);\r
+\r
+ /* take the reference before returning. */\r
+ al_ref_ifc( p_dev_obj );\r
+ BUS_EXIT( BUS_DBG_PNP );\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+\r
static NTSTATUS\r
fdo_query_interface(\r
IN DEVICE_OBJECT* const p_dev_obj,\r
{\r
status = __query_ci_ifc( p_dev_obj, p_io_stack );\r
}\r
+ else if( IsEqualGUID( p_io_stack->Parameters.QueryInterface.InterfaceType,\r
+ &GUID_INFINIBAND_INTERFACE_CM ) )\r
+ {\r
+ status = __query_cm_ifc( p_dev_obj, p_io_stack );\r
+ }\r
else\r
{\r
status = p_irp->IoStatus.Status;\r
static LIST_ENTRY ProvList;\r
static KGUARDED_MUTEX Lock;\r
\r
-static EVT_WDF_DRIVER_DEVICE_ADD WmIbDeviceAdd;\r
-static EVT_WDF_OBJECT_CONTEXT_CLEANUP WmIbDeviceCleanup;\r
-static EVT_WDF_DEVICE_D0_ENTRY WmPowerD0Entry;\r
static EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL WmIoDeviceControl;\r
static EVT_WDF_IO_QUEUE_IO_READ WmIoRead;\r
static EVT_WDF_IO_QUEUE_IO_WRITE WmIoWrite;\r
NTSTATUS status;\r
\r
dev = WmIbDeviceGetContext(Device);\r
+ RtlZeroMemory(dev, sizeof *dev);\r
+ dev->Ref = 1;\r
+ KeInitializeEvent(&dev->Event, NotificationEvent, FALSE);\r
+\r
status = WdfFdoQueryForInterface(Device, &GUID_RDMA_INTERFACE_VERBS,\r
(PINTERFACE) &dev->VerbsInterface,\r
sizeof(dev->VerbsInterface), VerbsVersion(2, 0),\r
return STATUS_SUCCESS;\r
}\r
\r
-static NTSTATUS WmIbDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)\r
-{\r
- WDF_OBJECT_ATTRIBUTES attr;\r
- WDF_PNPPOWER_EVENT_CALLBACKS power;\r
- WDFDEVICE dev;\r
- WM_IB_DEVICE *pdev;\r
- NTSTATUS status;\r
-\r
- WdfFdoInitSetFilter(DeviceInit);\r
-\r
- WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, WM_IB_DEVICE);\r
- attr.EvtCleanupCallback = WmIbDeviceCleanup;\r
-\r
- WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&power);\r
- power.EvtDeviceD0Entry = WmPowerD0Entry;\r
- WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &power);\r
-\r
- status = WdfDeviceCreate(&DeviceInit, &attr, &dev);\r
- if (!NT_SUCCESS(status)) {\r
- return status;\r
- }\r
-\r
- pdev = WmIbDeviceGetContext(dev);\r
- RtlZeroMemory(pdev, sizeof *pdev);\r
- pdev->Ref = 1;\r
- KeInitializeEvent(&pdev->Event, NotificationEvent, FALSE);\r
-\r
- return STATUS_SUCCESS;\r
-}\r
-\r
-static VOID WmIbDeviceCleanup(WDFDEVICE Device)\r
+static NTSTATUS WmPowerD0Exit(WDFDEVICE Device, WDF_POWER_DEVICE_STATE TargetState)\r
{\r
WM_PROVIDER *prov;\r
WM_IB_DEVICE *pdev;\r
BOOLEAN destroy;\r
WDFDEVICE ctrldev;\r
\r
- pdev = (WmIbDeviceGetContext(Device));\r
+ pdev = WmIbDeviceGetContext(Device);\r
\r
KeAcquireGuardedMutex(&Lock);\r
RemoveEntryList(&pdev->Entry);\r
if (destroy) {\r
WdfObjectDelete(ctrldev);\r
}\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+static NTSTATUS WmIbDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)\r
+{\r
+ WDF_OBJECT_ATTRIBUTES attr;\r
+ WDF_PNPPOWER_EVENT_CALLBACKS power;\r
+ WDFDEVICE dev;\r
+ NTSTATUS status;\r
+\r
+ WdfFdoInitSetFilter(DeviceInit);\r
+\r
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, WM_IB_DEVICE);\r
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&power);\r
+ power.EvtDeviceD0Entry = WmPowerD0Entry;\r
+ power.EvtDeviceD0Exit = WmPowerD0Exit;\r
+ WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &power);\r
+\r
+ status = WdfDeviceCreate(&DeviceInit, &attr, &dev);\r
+ if (!NT_SUCCESS(status)) {\r
+ return status;\r
+ }\r
+\r
+ return STATUS_SUCCESS;\r
}\r
\r
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)\r
!endif\r
\r
DLLENTRY = DllMain\r
-USE_MSVCRT=1\r
+USE_MSVCRT = 1\r
\r
SOURCES = \\r
winmad.rc \\r
wv_cq.c \\r
wv_pd.c \\r
wv_srq.c \\r
- wv_qp.c\r
+ wv_qp.c \\r
+ wv_ep.c\r
\r
INCLUDES = ..;..\..\..\inc;..\..\..\inc\kernel;..\..\..\inc\user;..\..\..\etc\kernel;\r
\r
\r
[Version]\r
Signature = "$WINDOWS NT$"\r
-Class=InfiniBandController\r
+Class = InfiniBandController\r
ClassGUID = {58517E00-D3CF-40c9-A679-CEE5752F4491}\r
Provider = %OFA%\r
DriverVer = 05/20/2008\r
WvCqPut(pCq);\r
}\r
\r
-static void WvCqCompleteRequests(WDFQUEUE Queue, NTSTATUS ReqStatus)\r
-{\r
- WDFREQUEST request;\r
- NTSTATUS status;\r
-\r
- WdfObjectAcquireLock(Queue);\r
- status = WdfIoQueueRetrieveNextRequest(Queue, &request);\r
-\r
- while (NT_SUCCESS(status)) {\r
- WdfRequestComplete(request, ReqStatus);\r
- status = WdfIoQueueRetrieveNextRequest(Queue, &request);\r
- }\r
- WdfObjectReleaseLock(Queue);\r
-}\r
-\r
static void WvCqEventHandler(ib_event_rec_t *pEvent)\r
{\r
WV_COMPLETION_QUEUE *cq = pEvent->context;\r
- WvCqCompleteRequests(cq->Queue, STATUS_UNEXPECTED_IO_ERROR);\r
- WvCqCompleteRequests(cq->ErrorQueue, STATUS_UNEXPECTED_IO_ERROR);\r
+ WvFlushQueue(cq->Queue, STATUS_UNEXPECTED_IO_ERROR);\r
+ WvFlushQueue(cq->ErrorQueue, STATUS_UNEXPECTED_IO_ERROR);\r
}\r
\r
static void WvCqHandler(void *Context)\r
{\r
WV_COMPLETION_QUEUE *cq = Context;\r
\r
- WvCqCompleteRequests(cq->Queue, STATUS_SUCCESS);\r
+ WvFlushQueue(cq->Queue, STATUS_SUCCESS);\r
}\r
\r
static NTSTATUS WvCqAlloc(WV_DEVICE *pDevice, UINT32 *pSize,\r
goto out;\r
}\r
\r
- WvCqCompleteRequests(cq->Queue, STATUS_CANCELLED);\r
- WvCqCompleteRequests(cq->ErrorQueue, STATUS_CANCELLED);\r
+ WvFlushQueue(cq->Queue, STATUS_CANCELLED);\r
+ WvFlushQueue(cq->ErrorQueue, STATUS_CANCELLED);\r
WvCqRelease(cq);\r
\r
out:\r
static LIST_ENTRY DevList;\r
static LIST_ENTRY ProvList;\r
static KGUARDED_MUTEX Lock;\r
+ULONG RandomSeed;\r
+\r
+INFINIBAND_INTERFACE_CM IbCmInterface;\r
\r
static EVT_WDF_DRIVER_DEVICE_ADD WvRdmaDeviceAdd;\r
static EVT_WDF_OBJECT_CONTEXT_CLEANUP WvRdmaDeviceCleanup;\r
}\r
}\r
\r
+\r
+void WvCompleteRequests(WDFQUEUE Queue, NTSTATUS ReqStatus)\r
+{\r
+ WDFREQUEST request;\r
+ NTSTATUS status;\r
+\r
+ status = WdfIoQueueRetrieveNextRequest(Queue, &request);\r
+\r
+ while (NT_SUCCESS(status)) {\r
+ WdfRequestComplete(request, ReqStatus);\r
+ status = WdfIoQueueRetrieveNextRequest(Queue, &request);\r
+ }\r
+}\r
+\r
+void WvFlushQueue(WDFQUEUE Queue, NTSTATUS ReqStatus)\r
+{\r
+ WdfObjectAcquireLock(Queue);\r
+ WvCompleteRequests(Queue, ReqStatus);\r
+ WdfObjectReleaseLock(Queue);\r
+}\r
+\r
+void WvCompleteRequestsWithInformation(WDFQUEUE Queue, NTSTATUS ReqStatus)\r
+{\r
+ WDFREQUEST request;\r
+ NTSTATUS status;\r
+ UINT8 *out;\r
+ size_t outlen;\r
+\r
+ status = WdfIoQueueRetrieveNextRequest(Queue, &request);\r
+\r
+ while (NT_SUCCESS(status)) {\r
+ outlen = 0;\r
+ WdfRequestRetrieveOutputBuffer(request, 0, &out, &outlen);\r
+ WdfRequestCompleteWithInformation(request, ReqStatus, outlen);\r
+ status = WdfIoQueueRetrieveNextRequest(Queue, &request);\r
+ }\r
+}\r
+\r
static void WvGuidQuery(WDFREQUEST Request)\r
{\r
WV_IO_GUID_LIST *list;\r
case WV_IOCTL_QP_CANCEL:\r
WvQpCancel(prov, Request);\r
break;\r
- case WV_IOCTL_ADDRESS_QUERY:\r
- //WvAddressQuery(prov, Request);\r
- WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
- break;\r
case WV_IOCTL_EP_CREATE:\r
- //WvEpCreate(prov, Request);\r
- WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
+ WvEpCreate(prov, Request);\r
break;\r
case WV_IOCTL_EP_DESTROY:\r
- //WvEpDestroy(prov, Request);\r
- WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
+ WvEpDestroy(prov, Request);\r
+ break;\r
+ case WV_IOCTL_EP_MODIFY:\r
+ WvEpModify(prov, Request);\r
break;\r
case WV_IOCTL_EP_BIND:\r
- //WvEpBind(prov, Request);\r
- WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
+ WvEpBind(prov, Request);\r
break;\r
case WV_IOCTL_EP_REJECT:\r
- //WvEpReject(prov, Request);\r
- WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
+ WvEpReject(prov, Request);\r
break;\r
case WV_IOCTL_EP_CONNECT:\r
- //WvEpConnect(prov, Request);\r
- WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
+ WvEpConnect(prov, Request);\r
break;\r
case WV_IOCTL_EP_ACCEPT:\r
- //WvEpAccept(prov, Request);\r
- WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
+ WvEpAccept(prov, Request);\r
break;\r
case WV_IOCTL_EP_DISCONNECT:\r
- //WvEpDisconnect(prov, Request);\r
- WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
+ WvEpDisconnect(prov, Request);\r
break;\r
case WV_IOCTL_EP_DISCONNECT_NOTIFY:\r
- //WvEpDisconnectNotify(prov, Request);\r
- WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
+ WvEpDisconnectNotify(prov, Request);\r
break;\r
case WV_IOCTL_EP_QUERY:\r
- //WvEpQuery(prov, Request);\r
- WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
+ WvEpQuery(prov, Request);\r
break;\r
case WV_IOCTL_EP_LOOKUP:\r
- //WvEpLookup(prov, Request);\r
- WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
+ WvEpLookup(prov, Request);\r
break;\r
case WV_IOCTL_EP_MULTICAST_JOIN:\r
- //WvEpMulticastJoin(prov, Request);\r
- WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
+ WvEpMulticastJoin(prov, Request);\r
break;\r
case WV_IOCTL_EP_MULTICAST_LEAVE:\r
- //WvEpMulticastLeave(prov, Request);\r
- WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
+ WvEpMulticastLeave(prov, Request);\r
break;\r
case WV_IOCTL_EP_CANCEL:\r
- //WvEpCancel(prov, Request);\r
- WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
+ WvEpCancel(prov, Request);\r
break;\r
- case WV_IOCTL_LISTEN:\r
- //WvListen(prov, Request);\r
- WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
+ case WV_IOCTL_EP_LISTEN:\r
+ WvEpListen(prov, Request);\r
break;\r
- case WV_IOCTL_LISTEN_DESTROY:\r
- //WvListenDestroy(prov, Request);\r
- WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
- break;\r
- case WV_IOCTL_LISTEN_GET_REQUEST:\r
- //WvListenGetRequest(prov, Request);\r
- WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
- break;\r
- case WV_IOCTL_LISTEN_CANCEL:\r
- //WvListenCancel(prov, Request);\r
- WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
+ case WV_IOCTL_EP_GET_REQUEST:\r
+ WvEpGetRequest(prov, Request);\r
break;\r
default:\r
WdfRequestComplete(Request, STATUS_PROCEDURE_NOT_FOUND);\r
WDFFILEOBJECT FileObject)\r
{\r
WV_PROVIDER *prov = WvProviderGetContext(FileObject);\r
- UNREFERENCED_PARAMETER(Device);\r
\r
- WvProviderInit(prov);\r
+ WvProviderInit(Device, prov);\r
KeAcquireGuardedMutex(&Lock);\r
InsertHeadList(&ProvList, &prov->Entry);\r
KeReleaseGuardedMutex(&Lock);\r
\r
if (create) {\r
WvCreateControlDevice(WdfGetDriver());\r
+ status = WdfFdoQueryForInterface(Device, &GUID_INFINIBAND_INTERFACE_CM,\r
+ (PINTERFACE) &IbCmInterface,\r
+ sizeof(IbCmInterface),\r
+ IbaCmVersion(1, 0), NULL);\r
}\r
\r
- return STATUS_SUCCESS;\r
+ return status;\r
}\r
\r
static NTSTATUS WvRdmaDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)\r
KeWaitForSingleObject(&pdev->Event, Executive, KernelMode, FALSE, NULL);\r
}\r
\r
- pdev->Interface.InterfaceHeader.\r
- InterfaceDereference(pdev->Interface.InterfaceHeader.Context);\r
+ if (IbCmInterface.CM.create_id != NULL) {\r
+ IbCmInterface.InterfaceHeader.InterfaceDereference(IbCmInterface.\r
+ InterfaceHeader.Context);\r
+ }\r
+\r
+ pdev->Interface.InterfaceHeader.InterfaceDereference(pdev->Interface.\r
+ InterfaceHeader.Context);\r
\r
if (destroy) {\r
WdfObjectDelete(ctrldev);\r
InitializeListHead(&DevList);\r
InitializeListHead(&ProvList);\r
KeInitializeGuardedMutex(&Lock);\r
+ RandomSeed = (ULONG) (ULONG_PTR) DriverObject;\r
\r
WDF_DRIVER_CONFIG_INIT(&config, WvRdmaDeviceAdd);\r
status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,\r
\r
#include <iba\ib_types.h>\r
#include <iba\ib_ci.h>\r
+#include <iba\ib_cm_ifc.h>\r
#include <rdma\verbs.h>\r
#include "wv_ioctl.h"\r
\r
#if WINVER <= _WIN32_WINNT_WINXP\r
-#define KGUARDED_MUTEX FAST_MUTEX\r
+#define KGUARDED_MUTEX FAST_MUTEX\r
#define KeInitializeGuardedMutex ExInitializeFastMutex\r
-#define KeAcquireGuardedMutex ExAcquireFastMutex\r
-#define KeReleaseGuardedMutex ExReleaseFastMutex\r
+#define KeAcquireGuardedMutex ExAcquireFastMutex\r
+#define KeReleaseGuardedMutex ExReleaseFastMutex\r
#endif\r
\r
-extern WDFDEVICE ControlDevice;\r
+extern WDFDEVICE ControlDevice;\r
+extern INFINIBAND_INTERFACE_CM IbCmInterface;\r
+extern ULONG RandomSeed;\r
\r
typedef struct _WV_RDMA_DEVICE\r
{\r
pVerbsData->status = 0;\r
}\r
\r
+void WvCompleteRequests(WDFQUEUE Queue, NTSTATUS ReqStatus);\r
+void WvFlushQueue(WDFQUEUE Queue, NTSTATUS ReqStatus);\r
+void WvCompleteRequestsWithInformation(WDFQUEUE Queue, NTSTATUS ReqStatus);\r
+\r
#endif // _WV_DRIVER_H_\r
--- /dev/null
+/*\r
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+#include <ntifs.h>\r
+#include <iba/ib_rdma_cm.h>\r
+\r
+#include "wv_ep.h"\r
+#include "wv_qp.h"\r
+#include "wv_ioctl.h"\r
+#include "wv_driver.h"\r
+\r
+#define WV_AF_INET 2\r
+#define WV_AF_INET6 23\r
+\r
+static void WvEpGet(WV_ENDPOINT *pEndpoint)\r
+{\r
+ InterlockedIncrement(&pEndpoint->Ref);\r
+}\r
+\r
+static void WvEpPut(WV_ENDPOINT *pEndpoint)\r
+{\r
+ if (InterlockedDecrement(&pEndpoint->Ref) == 0) {\r
+ KeSetEvent(&pEndpoint->Event, 0, FALSE);\r
+ }\r
+}\r
+\r
+WV_ENDPOINT *WvEpAcquire(WV_PROVIDER *pProvider, UINT64 Id)\r
+{\r
+ WV_ENDPOINT *ep;\r
+\r
+ KeAcquireGuardedMutex(&pProvider->Lock);\r
+ WvProviderDisableRemove(pProvider);\r
+ ep = IndexListAt(&pProvider->EpIndex, (SIZE_T) Id);\r
+ if (ep != NULL) {\r
+ WvEpGet(ep);\r
+ } else {\r
+ ep = NULL;\r
+ WvProviderEnableRemove(pProvider);\r
+ }\r
+ KeReleaseGuardedMutex(&pProvider->Lock);\r
+\r
+ return ep;\r
+}\r
+\r
+void WvEpRelease(WV_ENDPOINT *pEndpoint)\r
+{\r
+ WvProviderEnableRemove(pEndpoint->pProvider);\r
+ WvEpPut(pEndpoint);\r
+}\r
+\r
+static NTSTATUS WvEpAllocate(WV_PROVIDER *pProvider, UINT16 EpType,\r
+ WV_ENDPOINT **ppEndpoint)\r
+{\r
+ WV_ENDPOINT *ep;\r
+ NTSTATUS status;\r
+ WDF_IO_QUEUE_CONFIG config;\r
+\r
+ ep = ExAllocatePoolWithTag(NonPagedPool, sizeof(WV_ENDPOINT), 'pevw');\r
+ if (ep == NULL) {\r
+ return STATUS_NO_MEMORY;\r
+ }\r
+\r
+ RtlZeroMemory(ep, sizeof(WV_ENDPOINT));\r
+ ep->Ref = 1;\r
+ ep->pProvider = pProvider;\r
+ ep->EpType = EpType;\r
+ KeInitializeEvent(&ep->Event, NotificationEvent, FALSE);\r
+ InitializeListHead(&ep->Entry);\r
+\r
+ WDF_IO_QUEUE_CONFIG_INIT(&config, WdfIoQueueDispatchManual);\r
+ status = WdfIoQueueCreate(ControlDevice, &config,\r
+ WDF_NO_OBJECT_ATTRIBUTES, &ep->Queue);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto err;\r
+ }\r
+\r
+ *ppEndpoint = ep;\r
+ return STATUS_SUCCESS;\r
+\r
+err:\r
+ ExFreePool(ep);\r
+ return status;\r
+}\r
+\r
+void WvEpCreate(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+{\r
+ UINT64 *pId;\r
+ UINT64 *type;\r
+ WV_ENDPOINT *ep;\r
+ NTSTATUS status;\r
+\r
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &type, NULL);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto err1;\r
+ }\r
+ status = WdfRequestRetrieveOutputBuffer(Request, sizeof(UINT64), &pId, NULL);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto err1;\r
+ }\r
+\r
+ status = WvEpAllocate(pProvider, (UINT16) *type, &ep);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto err1;\r
+ }\r
+\r
+ KeAcquireGuardedMutex(&pProvider->Lock);\r
+ *pId = IndexListInsertHead(&pProvider->EpIndex, ep);\r
+ if (*pId == 0) {\r
+ status = STATUS_NO_MEMORY;\r
+ goto err2;\r
+ }\r
+ KeReleaseGuardedMutex(&pProvider->Lock);\r
+\r
+ WdfRequestCompleteWithInformation(Request, status, sizeof(UINT64));\r
+ return;\r
+\r
+err2:\r
+ KeReleaseGuardedMutex(&pProvider->Lock);\r
+ WvEpFree(ep);\r
+err1:\r
+ WdfRequestComplete(Request, status);\r
+}\r
+\r
+void WvEpDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+{\r
+ WV_ENDPOINT *ep;\r
+ UINT64 *id;\r
+ NTSTATUS status;\r
+\r
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto out;\r
+ }\r
+\r
+ KeAcquireGuardedMutex(&pProvider->Lock);\r
+ WvProviderDisableRemove(pProvider);\r
+ ep = IndexListAt(&pProvider->EpIndex, (SIZE_T) *id);\r
+ if (ep == NULL) {\r
+ status = STATUS_NOT_FOUND;\r
+ } else if (ep->Ref > 1) {\r
+ status = STATUS_ACCESS_DENIED;\r
+ } else {\r
+ IndexListRemove(&pProvider->EpIndex, (SIZE_T) *id);\r
+ status = STATUS_SUCCESS;\r
+ }\r
+ KeReleaseGuardedMutex(&pProvider->Lock);\r
+\r
+ if (NT_SUCCESS(status)) {\r
+ WvEpFree(ep);\r
+ }\r
+ WvProviderEnableRemove(pProvider);\r
+out:\r
+ WdfRequestComplete(Request, status);\r
+}\r
+\r
+void WvEpFree(WV_ENDPOINT *pEndpoint)\r
+{\r
+ if (pEndpoint->pIbCmId != NULL) {\r
+ IbCmInterface.CM.destroy_id(pEndpoint->pIbCmId);\r
+ }\r
+\r
+ if (InterlockedDecrement(&pEndpoint->Ref) > 0) {\r
+ KeWaitForSingleObject(&pEndpoint->Event, Executive, KernelMode, FALSE, NULL);\r
+ }\r
+\r
+ WdfIoQueuePurgeSynchronously(pEndpoint->Queue);\r
+ WdfObjectDelete(pEndpoint->Queue);\r
+ ExFreePool(pEndpoint);\r
+}\r
+\r
+void WvEpQuery(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+{\r
+ UINT64 *id;\r
+ WV_IO_EP_ATTRIBUTES *pattr;\r
+ WV_ENDPOINT *ep;\r
+ size_t len = 0;\r
+ NTSTATUS status;\r
+\r
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto complete;\r
+ }\r
+ status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_EP_ATTRIBUTES),\r
+ &pattr, NULL);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto complete;\r
+ }\r
+\r
+ ep = WvEpAcquire(pProvider, *id);\r
+ if (ep == NULL) {\r
+ status = STATUS_NOT_FOUND;\r
+ goto complete;\r
+ }\r
+\r
+ *pattr = ep->Attributes;\r
+ WvEpRelease(ep);\r
+ len = sizeof(WV_IO_EP_ATTRIBUTES);\r
+\r
+complete:\r
+ WdfRequestCompleteWithInformation(Request, status, len);\r
+}\r
+\r
+void WvEpModify(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+{\r
+ WV_IO_ID *pId;\r
+ size_t inlen;\r
+ WV_ENDPOINT *ep;\r
+ NTSTATUS status;\r
+\r
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &pId, &inlen);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto complete;\r
+ }\r
+\r
+ if (pId->Data != WV_IO_EP_OPTION_ROUTE) {\r
+ status = STATUS_INVALID_PARAMETER;\r
+ goto complete;\r
+ }\r
+\r
+ if (inlen < sizeof(WV_IO_ID) + sizeof(ib_path_rec_t)) {\r
+ status = STATUS_BUFFER_TOO_SMALL;\r
+ goto complete;\r
+ }\r
+\r
+ ep = WvEpAcquire(pProvider, pId->Id);\r
+ if (ep == NULL) {\r
+ status = STATUS_NOT_FOUND;\r
+ goto complete;\r
+ }\r
+\r
+ WdfObjectAcquireLock(ep->Queue);\r
+ if (ep->State != WvEpAddressBound) {\r
+ status = STATUS_NOT_SUPPORTED;\r
+ goto release;\r
+ }\r
+\r
+ RtlCopyMemory(&ep->Route, pId + 1, sizeof ep->Route);\r
+ ep->State = WvEpRouteResolved;\r
+\r
+release:\r
+ WdfObjectReleaseLock(ep->Queue);\r
+ WvEpRelease(ep);\r
+complete:\r
+ WdfRequestComplete(Request, status);\r
+}\r
+\r
+void WvEpBind(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+{\r
+ WV_IO_EP_BIND *pattr;\r
+ WV_ENDPOINT *ep;\r
+ size_t len = 0;\r
+ NTSTATUS status;\r
+\r
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_BIND),\r
+ &pattr, NULL);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto complete;\r
+ }\r
+ status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_EP_BIND),\r
+ &pattr, NULL);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto complete;\r
+ }\r
+\r
+ ep = WvEpAcquire(pProvider, pattr->Id);\r
+ if (ep == NULL) {\r
+ status = STATUS_NOT_FOUND;\r
+ goto complete;\r
+ }\r
+\r
+ WdfObjectAcquireLock(ep->Queue);\r
+ if (ep->State != WvEpIdle) {\r
+ status = STATUS_NOT_SUPPORTED;\r
+ goto release;\r
+ }\r
+\r
+ ep->Attributes.LocalAddress = pattr->Address;\r
+ ep->Attributes.Device = pattr->Device;\r
+ len = sizeof(WV_IO_EP_BIND);\r
+ ep->State = WvEpAddressBound;\r
+\r
+release:\r
+ WdfObjectReleaseLock(ep->Queue);\r
+ WvEpRelease(ep);\r
+complete:\r
+ WdfRequestCompleteWithInformation(Request, status, len);\r
+}\r
+\r
+static UINT64 WvGetServiceId(UINT16 EpType, WV_IO_SOCKADDR_DATA *pAddress)\r
+{\r
+ return RtlUlonglongByteSwap(((UINT64)EpType << 16) +\r
+ RtlUshortByteSwap(pAddress->SockAddr.In.SinPort));\r
+}\r
+\r
+static int WvAnyAddress(WV_IO_SOCKADDR_DATA *pAddress)\r
+{\r
+ if (pAddress->SockAddr.Sa.SaFamily == WV_AF_INET) {\r
+ return (pAddress->SockAddr.In.SinAddr == 0) ||\r
+ ((pAddress->SockAddr.In.SinAddr & 0xff) == 0x7f);\r
+ } else {\r
+ return (RtlCompareMemoryUlong(pAddress->SockAddr.In6.Sin6Addr, 16, 0) == 16);\r
+ }\r
+}\r
+\r
+static void WvFormatCmaHeader(IB_CMA_HEADER *pHeader,\r
+ WV_IO_SOCKADDR_DATA *pLocalAddress,\r
+ WV_IO_SOCKADDR_DATA *pPeerAddress)\r
+{\r
+ pHeader->CmaVersion = IB_CMA_VERSION;\r
+ if (pLocalAddress->SockAddr.Sa.SaFamily == WV_AF_INET) {\r
+ pHeader->IpVersion = 4 << 4;\r
+ pHeader->SrcAddress.Ip4.Address = pLocalAddress->SockAddr.In.SinAddr;\r
+ pHeader->DstAddress.Ip4.Address = pPeerAddress->SockAddr.In.SinAddr;\r
+ pHeader->Port = pLocalAddress->SockAddr.In.SinPort;\r
+ } else {\r
+ pHeader->IpVersion = 6 << 4;\r
+ RtlCopyMemory(pHeader->SrcAddress.Ip6Address,\r
+ pLocalAddress->SockAddr.In6.Sin6Addr, 16);\r
+ RtlCopyMemory(pHeader->DstAddress.Ip6Address,\r
+ pPeerAddress->SockAddr.In6.Sin6Addr, 16);\r
+ pHeader->Port = pLocalAddress->SockAddr.In6.Sin6Port;\r
+ }\r
+}\r
+\r
+static void WvEpSaveReply(WV_ENDPOINT *pEndpoint, iba_cm_rep_event *pReply)\r
+{\r
+ UINT8 len;\r
+\r
+ len = sizeof(pEndpoint->Attributes.Param.Connect.Data);\r
+ RtlCopyMemory(pEndpoint->Attributes.Param.Connect.Data, pReply->rep.p_pdata, len);\r
+ pEndpoint->Attributes.Param.Connect.DataLength = len;\r
+ pEndpoint->Attributes.Param.Connect.InitiatorDepth = pReply->rep.resp_res;\r
+ pEndpoint->Attributes.Param.Connect.ResponderResources = pReply->rep.init_depth;\r
+ pEndpoint->Attributes.Param.Connect.RnrRetryCount = pReply->rep.rnr_retry_cnt;\r
+}\r
+\r
+static NTSTATUS WvEpIbCmHandler(iba_cm_id *pId, iba_cm_event *pEvent)\r
+{\r
+ WV_ENDPOINT *ep;\r
+\r
+ ep = pId->context;\r
+ switch (pEvent->type) {\r
+ case iba_cm_req_error:\r
+ case iba_cm_rep_error:\r
+ case iba_cm_dreq_error:\r
+ WdfObjectAcquireLock(ep->Queue);\r
+ ep->State = WvEpDisconnected;\r
+ WvCompleteRequests(ep->Queue, STATUS_IO_TIMEOUT);\r
+ WdfObjectReleaseLock(ep->Queue);\r
+ break;\r
+ case iba_cm_rep_received:\r
+ WdfObjectAcquireLock(ep->Queue);\r
+ if (ep->State == WvEpActiveConnect) {\r
+ WvEpSaveReply(ep, &pEvent->data.rep);\r
+ WvCompleteRequests(ep->Queue, STATUS_SUCCESS);\r
+ }\r
+ WdfObjectReleaseLock(ep->Queue);\r
+ break;\r
+ case iba_cm_rtu_received:\r
+ WdfObjectAcquireLock(ep->Queue);\r
+ if (ep->State == WvEpPassiveConnect) {\r
+ WvCompleteRequestsWithInformation(ep->Queue, STATUS_SUCCESS);\r
+ ep->State = WvEpConnected;\r
+ }\r
+ WdfObjectReleaseLock(ep->Queue);\r
+ break;\r
+ case iba_cm_dreq_received:\r
+ WdfObjectAcquireLock(ep->Queue);\r
+ if (ep->State == WvEpConnected) {\r
+ ep->State = WvEpPassiveDisconnect;\r
+ } else {\r
+ ep->State = WvEpDisconnected;\r
+ IbCmInterface.CM.send_drep(pId, NULL, 0);\r
+ }\r
+ WvCompleteRequests(ep->Queue, STATUS_CONNECTION_DISCONNECTED);\r
+ WdfObjectReleaseLock(ep->Queue);\r
+ break;\r
+ case iba_cm_drep_received:\r
+ WdfObjectAcquireLock(ep->Queue);\r
+ ep->State = WvEpDisconnected;\r
+ WvCompleteRequests(ep->Queue, STATUS_CONNECTION_DISCONNECTED);\r
+ WdfObjectReleaseLock(ep->Queue);\r
+ break;\r
+ case iba_cm_rej_received:\r
+ WdfObjectAcquireLock(ep->Queue);\r
+ ep->State = WvEpDisconnected;\r
+ WvCompleteRequests(ep->Queue, STATUS_REQUEST_NOT_ACCEPTED);\r
+ WdfObjectReleaseLock(ep->Queue);\r
+ break;\r
+ case iba_cm_mra_received:\r
+ break;\r
+ default:\r
+ WdfObjectAcquireLock(ep->Queue);\r
+ ep->State = WvEpDisconnected;\r
+ WvCompleteRequests(ep->Queue, STATUS_NOT_IMPLEMENTED);\r
+ WdfObjectReleaseLock(ep->Queue);\r
+ break;\r
+ }\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+void WvEpConnect(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+{\r
+ WV_IO_EP_CONNECT *pattr;\r
+ WV_ENDPOINT *ep;\r
+ WV_QUEUE_PAIR *qp;\r
+ iba_cm_req req;\r
+ NTSTATUS status;\r
+ UINT8 data[IB_REQ_PDATA_SIZE];\r
+\r
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_CONNECT),\r
+ &pattr, NULL);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto complete;\r
+ }\r
+\r
+ if (pattr->Param.DataLength > sizeof(pattr->Param.Data)) {\r
+ status = STATUS_INVALID_BUFFER_SIZE;\r
+ goto complete;\r
+ }\r
+\r
+ ep = WvEpAcquire(pProvider, pattr->Id);\r
+ if (ep == NULL) {\r
+ status = STATUS_NOT_FOUND;\r
+ goto complete;\r
+ }\r
+\r
+ qp = WvQpAcquire(pProvider, pattr->QpId);\r
+ if (qp == NULL) {\r
+ status = STATUS_NOT_FOUND;\r
+ goto release;\r
+ }\r
+\r
+ ep->Attributes.PeerAddress = pattr->PeerAddress;\r
+ WvFormatCmaHeader((IB_CMA_HEADER *) data, &ep->Attributes.LocalAddress,\r
+ &ep->Attributes.PeerAddress);\r
+\r
+ req.service_id = WvGetServiceId(ep->EpType, &ep->Attributes.PeerAddress);\r
+ req.p_primary_path = &ep->Route;\r
+ req.p_alt_path = NULL;\r
+ req.qpn = qp->Qpn;\r
+ req.qp_type = IB_QPT_RELIABLE_CONN;\r
+ req.starting_psn = (net32_t) RtlRandomEx(&RandomSeed);\r
+ req.p_pdata = data;\r
+ RtlCopyMemory(data + sizeof(IB_CMA_HEADER), pattr->Param.Data,\r
+ pattr->Param.DataLength);\r
+ req.pdata_len = sizeof(IB_CMA_HEADER) + pattr->Param.DataLength;\r
+ req.max_cm_retries = IB_CMA_MAX_CM_RETRIES;\r
+ req.resp_res = (UINT8) pattr->Param.ResponderResources;\r
+ req.init_depth = (UINT8) pattr->Param.InitiatorDepth;\r
+ req.remote_resp_timeout = IB_CMA_CM_RESPONSE_TIMEOUT;\r
+ req.flow_ctrl = 1;\r
+ req.local_resp_timeout = IB_CMA_CM_RESPONSE_TIMEOUT;\r
+ req.rnr_retry_cnt = pattr->Param.RnrRetryCount;\r
+ req.retry_cnt = pattr->Param.RetryCount;\r
+ req.srq = (qp->pSrq != NULL);\r
+\r
+ WvQpRelease(qp);\r
+ RtlCopyMemory(&ep->Attributes.Param.Connect, &pattr->Param,\r
+ sizeof(pattr->Param));\r
+\r
+ WdfObjectAcquireLock(ep->Queue);\r
+ if (ep->State != WvEpRouteResolved) {\r
+ status = STATUS_NOT_SUPPORTED;\r
+ goto release;\r
+ }\r
+\r
+ status = IbCmInterface.CM.create_id(WvEpIbCmHandler, ep, &ep->pIbCmId);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto release;\r
+ }\r
+\r
+ ep->State = WvEpActiveConnect;\r
+ status = WdfRequestForwardToIoQueue(Request, ep->Queue);\r
+ if (NT_SUCCESS(status)) {\r
+ status = IbCmInterface.CM.send_req(ep->pIbCmId, &req);\r
+ }\r
+\r
+ if (!NT_SUCCESS(status)) {\r
+ ep->State = WvEpDisconnected;\r
+ }\r
+release:\r
+ WdfObjectReleaseLock(ep->Queue);\r
+ WvEpRelease(ep);\r
+complete:\r
+ if (!NT_SUCCESS(status)) {\r
+ WdfRequestComplete(Request, status);\r
+ }\r
+}\r
+\r
+static NTSTATUS WvEpModifyQpRtr(WV_ENDPOINT *pEndpoint, WV_QUEUE_PAIR *pQp,\r
+ UINT64 ResponderResources, UINT32 Psn,\r
+ UINT8 *pVerbsData, UINT32 VerbsSize)\r
+{\r
+ ib_qp_mod_t attr;\r
+ ib_api_status_t ib_status;\r
+ NTSTATUS status;\r
+\r
+ status =IbCmInterface.CM.get_qp_attr(pEndpoint->pIbCmId, IB_QPS_INIT, &attr);\r
+ if (!NT_SUCCESS(status)) {\r
+ return status;\r
+ }\r
+ \r
+ ib_status = pQp->pVerbs->ndi_modify_qp(pQp->hVerbsQp, &attr, NULL,\r
+ VerbsSize, pVerbsData);\r
+ if (ib_status != IB_SUCCESS) {\r
+ return STATUS_UNSUCCESSFUL;\r
+ }\r
+\r
+ status = IbCmInterface.CM.get_qp_attr(pEndpoint->pIbCmId, IB_QPS_RTR, &attr);\r
+ if (!NT_SUCCESS(status)) {\r
+ return status;\r
+ }\r
+ \r
+ if (pEndpoint->State == WvEpPassiveConnect) {\r
+ attr.state.rtr.resp_res = (UINT8) ResponderResources;\r
+ attr.state.rtr.rq_psn = Psn;\r
+ }\r
+\r
+ ib_status = pQp->pVerbs->ndi_modify_qp(pQp->hVerbsQp, &attr, NULL,\r
+ VerbsSize, pVerbsData);\r
+ if (ib_status != IB_SUCCESS) {\r
+ return STATUS_UNSUCCESSFUL;\r
+ }\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+static NTSTATUS WvEpModifyQpRts(WV_ENDPOINT *pEndpoint, WV_QUEUE_PAIR *pQp,\r
+ UINT64 InitiatorDepth,\r
+ UINT8 *pVerbsData, UINT32 VerbsSize)\r
+{\r
+ ib_qp_mod_t attr;\r
+ ib_api_status_t ib_status;\r
+ NTSTATUS status;\r
+\r
+ status = IbCmInterface.CM.get_qp_attr(pEndpoint->pIbCmId, IB_QPS_RTS, &attr);\r
+ if (!NT_SUCCESS(status)) {\r
+ return status;\r
+ }\r
+ \r
+ if (pEndpoint->State == WvEpPassiveConnect) {\r
+ attr.state.rts.init_depth = (UINT8) InitiatorDepth;\r
+ }\r
+\r
+ ib_status = pQp->pVerbs->ndi_modify_qp(pQp->hVerbsQp, &attr, NULL,\r
+ VerbsSize, pVerbsData);\r
+ if (ib_status != IB_SUCCESS) {\r
+ return STATUS_UNSUCCESSFUL;\r
+ }\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+static NTSTATUS WvEpAcceptActive(WDFREQUEST Request, UINT8 *pVerbsData, size_t VerbsSize,\r
+ WV_ENDPOINT *pEndpoint, WV_IO_EP_ACCEPT *pAttr)\r
+{\r
+ WV_QUEUE_PAIR *qp;\r
+ NTSTATUS status;\r
+\r
+ qp = WvQpAcquire(pEndpoint->pProvider, pAttr->QpId);\r
+ if (qp == NULL) {\r
+ return STATUS_NOT_FOUND;\r
+ }\r
+\r
+ status = WvEpModifyQpRtr(pEndpoint, qp, 0, 0, pVerbsData, VerbsSize);\r
+ if (NT_SUCCESS(status)) {\r
+ status = WvEpModifyQpRts(pEndpoint, qp, 0, pVerbsData, VerbsSize);\r
+ }\r
+\r
+ WvQpRelease(qp);\r
+\r
+ WdfObjectAcquireLock(pEndpoint->Queue);\r
+ if (pEndpoint->State != WvEpActiveConnect) {\r
+ status = STATUS_NOT_SUPPORTED;\r
+ goto release;\r
+ }\r
+\r
+ pEndpoint->State = WvEpConnected;\r
+ status = IbCmInterface.CM.send_rtu(pEndpoint->pIbCmId, pAttr->Param.Data,\r
+ pAttr->Param.DataLength);\r
+ if (NT_SUCCESS(status)) {\r
+ WdfRequestComplete(Request, STATUS_SUCCESS);\r
+ } else {\r
+ pEndpoint->State = WvEpDisconnected;\r
+ }\r
+\r
+release:\r
+ WdfObjectReleaseLock(pEndpoint->Queue);\r
+ return status;\r
+}\r
+\r
+static NTSTATUS WvEpAcceptPassive(WDFREQUEST Request, UINT8 *pVerbsData, size_t VerbsSize,\r
+ WV_ENDPOINT *pEndpoint, WV_IO_EP_ACCEPT *pAttr)\r
+{\r
+ WV_QUEUE_PAIR *qp;\r
+ iba_cm_rep rep;\r
+ NTSTATUS status;\r
+\r
+ qp = WvQpAcquire(pEndpoint->pProvider, pAttr->QpId);\r
+ if (qp == NULL) {\r
+ return STATUS_NOT_FOUND;\r
+ }\r
+\r
+ rep.qpn = qp->Qpn;\r
+ rep.starting_psn = (net32_t) RtlRandomEx(&RandomSeed);\r
+ rep.p_pdata = pAttr->Param.Data;\r
+ rep.pdata_len = pAttr->Param.DataLength;\r
+ rep.failover_accepted = IB_FAILOVER_ACCEPT_UNSUPPORTED;\r
+ rep.resp_res = (UINT8) pAttr->Param.ResponderResources;\r
+ rep.init_depth = (UINT8) pAttr->Param.InitiatorDepth;\r
+ rep.flow_ctrl = 1;\r
+ rep.rnr_retry_cnt = pAttr->Param.RnrRetryCount;\r
+ rep.srq = (qp->pSrq != NULL);\r
+\r
+ status = WvEpModifyQpRtr(pEndpoint, qp, pAttr->Param.ResponderResources,\r
+ rep.starting_psn, pVerbsData, VerbsSize);\r
+ if (NT_SUCCESS(status)) {\r
+ status = WvEpModifyQpRts(pEndpoint, qp, pAttr->Param.InitiatorDepth,\r
+ pVerbsData, VerbsSize);\r
+ }\r
+\r
+ WvQpRelease(qp);\r
+\r
+ if (!NT_SUCCESS(status)) {\r
+ goto out;\r
+ }\r
+\r
+ WdfObjectAcquireLock(pEndpoint->Queue);\r
+ if (pEndpoint->State != WvEpPassiveConnect) {\r
+ status = STATUS_NOT_SUPPORTED;\r
+ goto release;\r
+ }\r
+\r
+ status = IbCmInterface.CM.send_rep(pEndpoint->pIbCmId, &rep);\r
+ if (NT_SUCCESS(status)) {\r
+ status = WdfRequestForwardToIoQueue(Request, pEndpoint->Queue);\r
+ }\r
+ \r
+ if (!NT_SUCCESS(status)) {\r
+ pEndpoint->State = WvEpDisconnected;\r
+ }\r
+\r
+release:\r
+ WdfObjectReleaseLock(pEndpoint->Queue);\r
+out:\r
+ return status;\r
+}\r
+\r
+void WvEpAccept(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+{\r
+ WV_IO_EP_ACCEPT *pattr;\r
+ WV_ENDPOINT *ep;\r
+ NTSTATUS status;\r
+ UINT8 *out;\r
+ size_t outlen;\r
+\r
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_ACCEPT),\r
+ &pattr, NULL);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto complete;\r
+ }\r
+\r
+ status = WdfRequestRetrieveOutputBuffer(Request, 0, &out, &outlen);\r
+ if (!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) {\r
+ goto complete;\r
+ }\r
+\r
+ if (pattr->Param.DataLength > sizeof(pattr->Param.Data)) {\r
+ status = STATUS_INVALID_BUFFER_SIZE;\r
+ goto complete;\r
+ }\r
+\r
+ ep = WvEpAcquire(pProvider, pattr->Id);\r
+ if (ep == NULL) {\r
+ status = STATUS_NOT_FOUND;\r
+ goto complete;\r
+ }\r
+\r
+ switch (ep->State) {\r
+ case WvEpActiveConnect:\r
+ status = WvEpAcceptActive(Request, out, outlen, ep, pattr);\r
+ break;\r
+ case WvEpPassiveConnect:\r
+ status = WvEpAcceptPassive(Request, out, outlen, ep, pattr);\r
+ break;\r
+ default:\r
+ status = STATUS_NOT_SUPPORTED;\r
+ break;\r
+ }\r
+\r
+ WvEpRelease(ep);\r
+complete:\r
+ if (!NT_SUCCESS(status)) {\r
+ WdfRequestComplete(Request, status);\r
+ }\r
+}\r
+\r
+void WvEpReject(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+{\r
+ WV_IO_ID *id;\r
+ WV_ENDPOINT *ep;\r
+ NTSTATUS status;\r
+ size_t len;\r
+\r
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &id, &len);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto complete;\r
+ }\r
+\r
+ ep = WvEpAcquire(pProvider, id->Id);\r
+ if (ep == NULL) {\r
+ status = STATUS_NOT_FOUND;\r
+ goto complete;\r
+ }\r
+\r
+ WdfObjectAcquireLock(ep->Queue);\r
+ if (ep->State != WvEpActiveConnect && ep->State != WvEpPassiveConnect) {\r
+ status = STATUS_NOT_SUPPORTED;\r
+ goto release;\r
+ }\r
+\r
+ ep->State = WvEpDisconnected;\r
+ status = IbCmInterface.CM.send_rej(ep->pIbCmId, IB_REJ_USER_DEFINED,\r
+ NULL, 0, id + 1, len - sizeof(WV_IO_ID));\r
+\r
+release:\r
+ WdfObjectReleaseLock(ep->Queue);\r
+ WvEpRelease(ep);\r
+complete:\r
+ WdfRequestComplete(Request, status);\r
+}\r
+\r
+void WvEpDisconnect(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+{\r
+ UINT64 *id;\r
+ WV_ENDPOINT *ep;\r
+ NTSTATUS status;\r
+\r
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto complete;\r
+ }\r
+\r
+ ep = WvEpAcquire(pProvider, *id);\r
+ if (ep == NULL) {\r
+ status = STATUS_NOT_FOUND;\r
+ goto complete;\r
+ }\r
+\r
+ WdfObjectAcquireLock(ep->Queue);\r
+ switch (ep->State) {\r
+ case WvEpConnected:\r
+ ep->State = WvEpActiveDisconnect;\r
+ status = IbCmInterface.CM.send_dreq(ep->pIbCmId, NULL, 0);\r
+ break;\r
+ case WvEpPassiveDisconnect:\r
+ ep->State = WvEpDisconnected;\r
+ IbCmInterface.CM.send_drep(ep->pIbCmId, NULL, 0);\r
+ status = STATUS_SUCCESS;\r
+ break;\r
+ default:\r
+ status = STATUS_NOT_SUPPORTED;\r
+ break;\r
+ }\r
+\r
+ WdfObjectReleaseLock(ep->Queue);\r
+ WvEpRelease(ep);\r
+complete:\r
+ WdfRequestComplete(Request, status);\r
+}\r
+\r
+void WvEpDisconnectNotify(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+{\r
+ UINT64 *id;\r
+ WV_ENDPOINT *ep;\r
+ NTSTATUS status;\r
+\r
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto complete;\r
+ }\r
+\r
+ ep = WvEpAcquire(pProvider, *id);\r
+ if (ep == NULL) {\r
+ status = STATUS_NOT_FOUND;\r
+ goto complete;\r
+ }\r
+\r
+ WdfObjectAcquireLock(ep->Queue);\r
+ switch (ep->State) {\r
+ case WvEpConnected:\r
+ case WvEpActiveDisconnect:\r
+ status = WdfRequestForwardToIoQueue(Request, ep->Queue);\r
+ break;\r
+ case WvEpPassiveDisconnect:\r
+ case WvEpDisconnected:\r
+ status = STATUS_CONNECTION_DISCONNECTED;\r
+ break;\r
+ default:\r
+ status = STATUS_NOT_SUPPORTED;\r
+ break;\r
+ }\r
+ WdfObjectReleaseLock(ep->Queue);\r
+\r
+ WvEpRelease(ep);\r
+complete:\r
+ if (!NT_SUCCESS(status)) {\r
+ WdfRequestComplete(Request, status);\r
+ }\r
+}\r
+\r
+static NTSTATUS WvEpIbListenHandler(iba_cm_id *pId, iba_cm_event *pEvent)\r
+{\r
+ WV_ENDPOINT *listen, *ep;\r
+ WDFREQUEST request;\r
+ NTSTATUS status;\r
+ IB_CMA_HEADER *hdr;\r
+\r
+ listen = ((iba_cm_id *) pId->context)->context;\r
+\r
+ WdfObjectAcquireLock(listen->Queue);\r
+ status = WdfIoQueueRetrieveNextRequest(listen->Queue, &request);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto release;\r
+ }\r
+\r
+ ep = CONTAINING_RECORD(RemoveHeadList(&listen->Entry), WV_ENDPOINT, Entry);\r
+ ep->pIbCmId = pId;\r
+ pId->callback = WvEpIbCmHandler;\r
+ pId->context = ep;\r
+\r
+ hdr = pEvent->data.req.req.p_pdata;\r
+ if (hdr->IpVersion == 4) {\r
+ ep->Attributes.LocalAddress.SockAddr.In.SinFamily = WV_AF_INET;\r
+ ep->Attributes.LocalAddress.SockAddr.In.SinAddr = hdr->DstAddress.Ip4.Address;\r
+ ep->Attributes.PeerAddress.SockAddr.In.SinFamily = WV_AF_INET;\r
+ ep->Attributes.PeerAddress.SockAddr.In.SinAddr = hdr->SrcAddress.Ip4.Address;\r
+ } else {\r
+ ep->Attributes.LocalAddress.SockAddr.In6.Sin6Family = WV_AF_INET6; \r
+ RtlCopyMemory(ep->Attributes.LocalAddress.SockAddr.In6.Sin6Addr,\r
+ hdr->DstAddress.Ip6Address, 16);\r
+ ep->Attributes.PeerAddress.SockAddr.In6.Sin6Family = WV_AF_INET6;\r
+ RtlCopyMemory(ep->Attributes.PeerAddress.SockAddr.In6.Sin6Addr,\r
+ hdr->SrcAddress.Ip6Address, 16);\r
+ }\r
+ ep->Attributes.Device.DeviceGuid = pEvent->data.req.local_ca_guid;\r
+ ep->Attributes.Device.Pkey = pEvent->data.req.req.p_primary_path->pkey;\r
+ ep->Attributes.Device.PortNumber = pEvent->data.req.port_num;\r
+ ep->Attributes.Param.Connect.ResponderResources = pEvent->data.req.req.resp_res;\r
+ ep->Attributes.Param.Connect.InitiatorDepth = pEvent->data.req.req.init_depth;\r
+ ep->Attributes.Param.Connect.RetryCount = pEvent->data.req.req.retry_cnt;\r
+ ep->Attributes.Param.Connect.RnrRetryCount = pEvent->data.req.req.rnr_retry_cnt;\r
+ ep->Attributes.Param.Connect.DataLength = sizeof(ep->Attributes.Param.Connect.Data);\r
+ RtlCopyMemory(ep->Attributes.Param.Connect.Data, hdr + 1,\r
+ sizeof(ep->Attributes.Param.Connect.Data));\r
+ ep->Route = *pEvent->data.req.req.p_primary_path;\r
+\r
+ ep->State = WvEpPassiveConnect;\r
+ WvEpPut(ep);\r
+\r
+ WdfRequestComplete(request, STATUS_SUCCESS);\r
+release:\r
+ WdfObjectReleaseLock(listen->Queue);\r
+ return status;\r
+}\r
+\r
+void WvEpListen(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+{\r
+ WV_ENDPOINT *ep;\r
+ WV_IO_EP_LISTEN *pattr;\r
+ NTSTATUS status;\r
+ void *buf;\r
+ UINT8 offset, len;\r
+ UINT64 sid;\r
+\r
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_LISTEN),\r
+ &pattr, NULL);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto complete;\r
+ }\r
+\r
+ ep = WvEpAcquire(pProvider, pattr->Id);\r
+ if (ep == NULL) {\r
+ status = STATUS_NOT_FOUND;\r
+ goto complete;\r
+ }\r
+\r
+ if (WvAnyAddress(&ep->Attributes.LocalAddress)) {\r
+ buf = NULL;\r
+ offset = 0;\r
+ len = 0;\r
+ } else {\r
+ if (ep->Attributes.LocalAddress.SockAddr.Sa.SaFamily == WV_AF_INET) {\r
+ buf = &ep->Attributes.LocalAddress.SockAddr.In.SinAddr;\r
+ len = sizeof ep->Attributes.LocalAddress.SockAddr.In.SinAddr;\r
+ offset = FIELD_OFFSET(IB_CMA_HEADER, DstAddress.Ip4.Address);\r
+ } else {\r
+ buf = ep->Attributes.LocalAddress.SockAddr.In6.Sin6Addr;\r
+ len = sizeof ep->Attributes.LocalAddress.SockAddr.In6.Sin6Addr;\r
+ offset = FIELD_OFFSET(IB_CMA_HEADER, DstAddress.Ip6Address);\r
+ }\r
+ }\r
+\r
+ WdfObjectAcquireLock(ep->Queue);\r
+ if (ep->State != WvEpAddressBound) {\r
+ status = STATUS_NOT_SUPPORTED;\r
+ goto release;\r
+ }\r
+\r
+ status = IbCmInterface.CM.create_id(WvEpIbListenHandler, ep, &ep->pIbCmId);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto release;\r
+ }\r
+\r
+ ep->Attributes.Param.Backlog = pattr->Backlog;\r
+ ep->State = WvEpListening;\r
+ sid = WvGetServiceId(ep->EpType, &ep->Attributes.LocalAddress);\r
+ status = IbCmInterface.CM.listen(ep->pIbCmId, sid, buf, len, offset);\r
+\r
+release:\r
+ WdfObjectReleaseLock(ep->Queue);\r
+ WvEpRelease(ep);\r
+complete:\r
+ WdfRequestComplete(Request, status);\r
+}\r
+\r
+void WvEpGetRequest(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+{\r
+ WV_ENDPOINT *listen, *ep;\r
+ WV_IO_EP_GET_REQUEST *req;\r
+ NTSTATUS status;\r
+\r
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_GET_REQUEST),\r
+ &req, NULL);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto complete;\r
+ }\r
+\r
+ listen = WvEpAcquire(pProvider, req->Id);\r
+ if (listen == NULL) {\r
+ status = STATUS_NOT_FOUND;\r
+ goto complete;\r
+ }\r
+\r
+ if (listen->State != WvEpListening) {\r
+ status = STATUS_NOT_SUPPORTED;\r
+ goto release1;\r
+ }\r
+\r
+ ep = WvEpAcquire(pProvider, req->EpId);\r
+ if (ep == NULL) {\r
+ status = STATUS_NOT_FOUND;\r
+ goto release1;\r
+ }\r
+\r
+ WdfObjectAcquireLock(ep->Queue);\r
+ if (ep->State == WvEpIdle) {\r
+ ep->State = WvEpQueued;\r
+ } else {\r
+ status = STATUS_CONNECTION_IN_USE;\r
+ }\r
+ WdfObjectReleaseLock(ep->Queue);\r
+\r
+ if (!NT_SUCCESS(status)) {\r
+ goto release2;\r
+ }\r
+\r
+ WdfObjectAcquireLock(listen->Queue);\r
+ status = WdfRequestForwardToIoQueue(Request, listen->Queue);\r
+ if (NT_SUCCESS(status)) {\r
+ InsertTailList(&listen->Entry, &ep->Entry);\r
+ WvEpGet(ep);\r
+ }\r
+ WdfObjectReleaseLock(listen->Queue);\r
+\r
+release2:\r
+ WvEpRelease(ep);\r
+release1:\r
+ WvEpRelease(listen);\r
+complete:\r
+ if (!NT_SUCCESS(status)) {\r
+ WdfRequestComplete(Request, status);\r
+ }\r
+}\r
+\r
+void WvEpLookup(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+{\r
+ UNUSED_PARAM(pProvider);\r
+ WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
+}\r
+\r
+void WvEpMulticastJoin(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+{\r
+ UNUSED_PARAM(pProvider);\r
+ WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
+}\r
+\r
+void WvEpMulticastLeave(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+{\r
+ UNUSED_PARAM(pProvider);\r
+ WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
+}\r
+\r
+//\r
+// Note that the framework may have already canceled outstanding requests.\r
+//\r
+void WvEpCancelListen(WV_ENDPOINT *pListen)\r
+{\r
+ WV_ENDPOINT *ep;\r
+ WDFREQUEST request;\r
+ NTSTATUS status;\r
+\r
+ WdfObjectAcquireLock(pListen->Queue);\r
+ status = WdfIoQueueRetrieveNextRequest(pListen->Queue, &request);\r
+\r
+ while (NT_SUCCESS(status)) {\r
+ WdfRequestComplete(request, STATUS_CANCELLED);\r
+ status = WdfIoQueueRetrieveNextRequest(pListen->Queue, &request);\r
+ }\r
+\r
+ while (!IsListEmpty(&pListen->Entry)) {\r
+ ep = CONTAINING_RECORD(RemoveHeadList(&pListen->Entry), WV_ENDPOINT, Entry);\r
+ ep->State = WvEpIdle;\r
+ WvEpPut(ep);\r
+ }\r
+\r
+ WdfObjectReleaseLock(pListen->Queue);\r
+}\r
+\r
+void WvEpCancel(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
+{\r
+ UINT64 *id;\r
+ WV_ENDPOINT *ep;\r
+ NTSTATUS status;\r
+\r
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
+ if (!NT_SUCCESS(status)) {\r
+ goto out;\r
+ }\r
+\r
+ ep = WvEpAcquire(pProvider, *id);\r
+ if (ep == NULL) {\r
+ status = STATUS_NOT_FOUND;\r
+ goto out;\r
+ }\r
+\r
+ if (ep->State == WvEpListening) {\r
+ WvEpCancelListen(ep);\r
+ } else {\r
+ WvFlushQueue(ep->Queue, STATUS_CANCELLED);\r
+ }\r
+ WvEpRelease(ep);\r
+\r
+out:\r
+ WdfRequestComplete(Request, status);\r
+}\r
#ifndef _WV_EP_H_\r
#define _WV_EP_H_\r
\r
+#include <ntddk.h>\r
#include <wdm.h>\r
+\r
#include <iba\ib_types.h>\r
#include <iba\ib_ci.h>\r
#include "wv_provider.h"\r
+#include "wv_ioctl.h"\r
\r
-typedef struct _WV_CONNECT_ENDPOINT\r
+typedef enum _WV_ENDPOINT_STATE\r
{\r
- WV_PROVIDER *pProvider;\r
- UINT64 Id;\r
- LONG nRef;\r
+ WvEpIdle,\r
+ WvEpAddressBound,\r
+ WvEpListening,\r
+ WvEpQueued,\r
+ WvEpRouteResolved,\r
+ WvEpPassiveConnect,\r
+ WvEpActiveConnect,\r
+ WvEpConnected,\r
+ WvEpActiveDisconnect,\r
+ WvEpPassiveDisconnect,\r
+ WvEpDisconnected\r
\r
-} WV_CONNECT_ENDPOINT;\r
+} WV_ENDPOINT_STATE;\r
\r
-typedef struct _WV_DATAGRAM_ENDPOINT\r
+typedef struct _WV_ENDPOINT\r
{\r
- WV_PROVIDER *pProvider;\r
- UINT64 Id;\r
- LONG m_nRef;\r
+ WV_PROVIDER *pProvider;\r
+ LIST_ENTRY Entry;\r
+ WV_ENDPOINT_STATE State;\r
+\r
+ iba_cm_id *pIbCmId;\r
+ WV_IO_EP_ATTRIBUTES Attributes;\r
+ ib_path_rec_t Route;\r
+\r
+ UINT16 EpType;\r
+ KEVENT Event;\r
+ LONG Ref;\r
+ WDFQUEUE Queue;\r
+\r
+} WV_ENDPOINT;\r
+\r
+void WvEpCreate(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
+void WvEpDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
+void WvEpFree(WV_ENDPOINT *pEndpoint);\r
+void WvEpCancelListen(WV_ENDPOINT *pEndpoint);\r
+\r
+void WvEpQuery(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
+void WvEpModify(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
+void WvEpBind(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
+void WvEpCancel(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
+\r
+void WvEpConnect(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
+void WvEpAccept(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
+void WvEpReject(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
+void WvEpDisconnect(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
+void WvEpDisconnectNotify(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
+\r
+void WvEpListen(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
+void WvEpGetRequest(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
\r
-} WV_DATAGRAM_ENDPOINT;\r
+void WvEpLookup(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
+void WvEpMulticastJoin(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
+void WvEpMulticastLeave(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
\r
#endif // _WV_EP_H_\r
#include "wv_srq.h"\r
#include "wv_cq.h"\r
#include "wv_qp.h"\r
+#include "wv_ep.h"\r
\r
void WvProviderGet(WV_PROVIDER *pProvider)\r
{\r
}\r
}\r
\r
-void WvProviderInit(WV_PROVIDER *pProvider)\r
+void WvProviderInit(WDFDEVICE Device, WV_PROVIDER *pProvider)\r
{\r
IndexListInit(&pProvider->DevIndex);\r
IndexListInit(&pProvider->CqIndex);\r
IndexListInit(&pProvider->QpIndex);\r
IndexListInit(&pProvider->MwIndex);\r
IndexListInit(&pProvider->AhIndex);\r
+ IndexListInit(&pProvider->EpIndex);\r
\r
KeInitializeGuardedMutex(&pProvider->Lock);\r
pProvider->Ref = 1;\r
WV_QUEUE_PAIR *qp;\r
WV_MEMORY_WINDOW *mw;\r
WV_ADDRESS_HANDLE *ah;\r
+ WV_ENDPOINT *ep;\r
+ SIZE_T i;\r
\r
+ IndexListForEach(&pProvider->EpIndex, i) {\r
+ ep = (WV_ENDPOINT *) IndexListAt(&pProvider->EpIndex, i);\r
+ if (ep->State == WvEpListening) {\r
+ WvEpCancelListen(ep);\r
+ }\r
+ }\r
+ while ((ep = IndexListRemoveHead(&pProvider->EpIndex)) != NULL) {\r
+ RemoveEntryList(&ep->Entry);\r
+ WvEpFree(ep);\r
+ }\r
while ((ah = IndexListRemoveHead(&pProvider->AhIndex)) != NULL) {\r
RemoveEntryList(&ah->Entry);\r
WvAhFree(ah);\r
KeWaitForSingleObject(&pProvider->Event, Executive, KernelMode, FALSE, NULL);\r
}\r
\r
+ IndexListDestroy(&pProvider->EpIndex);\r
IndexListDestroy(&pProvider->AhIndex);\r
IndexListDestroy(&pProvider->MwIndex);\r
IndexListDestroy(&pProvider->QpIndex);\r
INDEX_LIST QpIndex;\r
INDEX_LIST MwIndex;\r
INDEX_LIST AhIndex;\r
+ INDEX_LIST EpIndex;\r
\r
KGUARDED_MUTEX Lock;\r
LONG Ref;\r
\r
void WvProviderGet(WV_PROVIDER *pProvider);\r
void WvProviderPut(WV_PROVIDER *pProvider);\r
-void WvProviderInit(WV_PROVIDER *pProvider);\r
+void WvProviderInit(WDFDEVICE Device, WV_PROVIDER *pProvider);\r
void WvProviderCleanup(WV_PROVIDER *pProvider);\r
\r
void WvProviderRemoveHandler(WV_PROVIDER *pProvider, WV_RDMA_DEVICE *pDevice);\r
goto err3;\r
}\r
\r
+ qp->Qpn = ib_attr.num;\r
KeAcquireGuardedMutex(&pProvider->Lock);\r
outattr->Id.Id = IndexListInsertHead(&pProvider->QpIndex, qp);\r
if (outattr->Id.Id == 0) {\r
WV_SHARED_RECEIVE_QUEUE *pSrq;\r
ci_interface_t *pVerbs;\r
ib_qp_handle_t hVerbsQp;\r
+ UINT32 Qpn;\r
LIST_ENTRY Entry;\r
LIST_ENTRY McList;\r
\r
void WvQpFree(WV_QUEUE_PAIR *pQp);\r
void WvQpRemoveHandler(WV_QUEUE_PAIR *pQp);\r
\r
+WV_QUEUE_PAIR *WvQpAcquire(WV_PROVIDER *pProvider, UINT64 Id);\r
+void WvQpRelease(WV_QUEUE_PAIR *pQp);\r
+\r
void WvQpModify(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
void WvQpQuery(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
void WvQpAttach(WV_PROVIDER *pProvider, WDFREQUEST Request);\r
pVerbsAttr->srq_limit = pAttr->SrqLimit;\r
}\r
\r
-static void WvSrqCompleteRequests(WV_SHARED_RECEIVE_QUEUE *pSrq, NTSTATUS ReqStatus)\r
-{\r
- WDFREQUEST request;\r
- NTSTATUS status;\r
-\r
- WdfObjectAcquireLock(pSrq->Queue);\r
- status = WdfIoQueueRetrieveNextRequest(pSrq->Queue, &request);\r
-\r
- while (NT_SUCCESS(status)) {\r
- WdfRequestComplete(request, ReqStatus);\r
- status = WdfIoQueueRetrieveNextRequest(pSrq->Queue, &request);\r
- }\r
- WdfObjectReleaseLock(pSrq->Queue);\r
-}\r
-\r
static void WvSrqEventHandler(ib_event_rec_t *pEvent)\r
{\r
+ WV_SHARED_RECEIVE_QUEUE *srq = pEvent->context;\r
+\r
switch (pEvent->type) {\r
case IB_AE_SRQ_LIMIT_REACHED:\r
- WvSrqCompleteRequests(pEvent->context, STATUS_ALERTED);\r
+ WvFlushQueue(srq->Queue, STATUS_ALERTED);\r
break;\r
case IB_AE_SRQ_QP_LAST_WQE_REACHED:\r
- WvSrqCompleteRequests(pEvent->context, STATUS_NOTIFY_CLEANUP);\r
+ WvFlushQueue(srq->Queue, STATUS_NOTIFY_CLEANUP);\r
break;\r
default:\r
- WvSrqCompleteRequests(pEvent->context, STATUS_UNEXPECTED_IO_ERROR);\r
+ WvFlushQueue(srq->Queue, STATUS_UNEXPECTED_IO_ERROR);\r
break;\r
}\r
}\r
goto out;\r
}\r
\r
- WvSrqCompleteRequests(srq, STATUS_CANCELLED);\r
+ WvFlushQueue(srq->Queue, STATUS_CANCELLED);\r
WvSrqRelease(srq);\r
\r
out:\r
!endif\r
\r
DLLENTRY = DllMain\r
-USE_NTDLL = 1\r
+USE_MSVCRT = 1\r
\r
SOURCES = \\r
winverbs.rc \\r
wv_cq.cpp \\r
wv_device.cpp \\r
wv_ep.cpp \\r
- wv_listen.cpp \\r
wv_pd.cpp \\r
wv_provider.cpp \\r
wv_qp.cpp \\r
\r
TARGETLIBS = \\r
$(SDK_LIB_PATH)\kernel32.lib \\r
- $(SDK_LIB_PATH)\uuid.lib\r
+ $(SDK_LIB_PATH)\uuid.lib \\r
+ $(SDK_LIB_PATH)\ws2_32.lib\r
DWORD bytes;\r
HRESULT hr;\r
\r
- if (m_Id != NULL) {\r
+ if (m_Id != 0) {\r
m_pVerbs->pre_destroy_cq(m_hVerbsCq);\r
hr = WvDeviceIoControl(m_hFile, WV_IOCTL_CQ_DESTROY, &m_Id, sizeof m_Id,\r
NULL, 0, &bytes, NULL) ?\r
}\r
\r
STDMETHODIMP CWVDevice::\r
-FindGidIndex(UINT8 PortNumber, WV_GID *pGid, UINT16 *pIndex)\r
+FindGid(UINT8 PortNumber, WV_GID *pGid, DWORD *pIndex)\r
{\r
WV_GID gid;\r
DWORD index;\r
for (index = 0; true; index++) {\r
hr = QueryGid(PortNumber, index, &gid);\r
if (FAILED(hr)) {\r
- break;\r
+ return hr;\r
}\r
\r
- if (RtlCompareMemory(pGid, &gid, sizeof(gid)) == sizeof(gid)) {\r
+ if (RtlEqualMemory(pGid, &gid, sizeof(gid))) {\r
*pIndex = (UINT16) index;\r
- break;\r
+ return WV_SUCCESS;\r
}\r
}\r
\r
- return hr;\r
+ return WV_INVALID_ADDRESS;\r
}\r
\r
STDMETHODIMP CWVDevice::\r
return hr;\r
}\r
\r
+STDMETHODIMP CWVDevice::\r
+FindPkey(UINT8 PortNumber, NET16 Pkey, DWORD *pIndex)\r
+{\r
+ NET16 key;\r
+ DWORD index;\r
+ HRESULT hr;\r
+\r
+ for (index = 0; true; index++) {\r
+ hr = QueryPkey(PortNumber, index, &key);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+\r
+ if (Pkey == key) {\r
+ *pIndex = (UINT16) index;\r
+ return WV_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return WV_INVALID_ADDRESS;\r
+}\r
+\r
STDMETHODIMP CWVDevice::\r
CreateCompletionQueue(SIZE_T *pEntries, IWVCompletionQueue** ppCq)\r
{\r
STDMETHODIMP Query(WV_DEVICE_ATTRIBUTES* pAttributes);\r
STDMETHODIMP QueryPort(UINT8 PortNumber, WV_PORT_ATTRIBUTES* pAttributes);\r
STDMETHODIMP QueryGid(UINT8 PortNumber, DWORD Index, WV_GID* pGid);\r
+ STDMETHODIMP FindGid(UINT8 PortNumber, WV_GID *pGid, DWORD *pIndex);\r
STDMETHODIMP QueryPkey(UINT8 PortNumber, DWORD Index, NET16* pPkey);\r
+ STDMETHODIMP FindPkey(UINT8 PortNumber, NET16 Pkey, DWORD *pIndex);\r
STDMETHODIMP CreateCompletionQueue(SIZE_T *pEntries, IWVCompletionQueue** ppCq);\r
STDMETHODIMP AllocateProtectionDomain(IWVProtectionDomain** ppPd);\r
STDMETHODIMP Notify(UINT8 PortNumber, OVERLAPPED* pOverlapped, DWORD* pFlags);\r
*ppDevice = NULL;\r
return hr;\r
}\r
- STDMETHODIMP FindGidIndex(UINT8 PortNumber, WV_GID *pGid, UINT16 *pIndex);\r
\r
CWVProvider *m_pProvider;\r
uvp_interface_t m_Verbs;\r
#include "wv_memory.h"\r
#include "wv_ep.h"\r
#include "wv_ioctl.h"\r
+#include "wv_qp.h"\r
+\r
+static void WvIoConvertConnParam(WV_IO_CONNECT_PARAM *pIoParam,\r
+ WV_CONNECT_PARAM *pParam)\r
+{\r
+ pIoParam->DataLength = (UINT8) pParam->DataLength;\r
+ pIoParam->ResponderResources = pParam->ResponderResources;\r
+ pIoParam->InitiatorDepth = pParam->InitiatorDepth;\r
+ pIoParam->RetryCount = pParam->RetryCount;\r
+ pIoParam->RnrRetryCount = pParam->RnrRetryCount;\r
+ RtlZeroMemory(pIoParam->Reserved, sizeof pIoParam->Reserved);\r
+ RtlCopyMemory(pIoParam->Data, pParam->Data, pParam->DataLength);\r
+}\r
\r
CWVConnectEndpoint::CWVConnectEndpoint(CWVProvider *pProvider)\r
{\r
pProvider->AddRef();\r
m_pProvider = pProvider;\r
m_hFile = pProvider->m_hFile;\r
+ m_Socket = INVALID_SOCKET;\r
+}\r
+\r
+STDMETHODIMP CWVConnectEndpoint::\r
+Allocate(void)\r
+{\r
+ UINT64 EpType;\r
+ DWORD bytes;\r
+ HRESULT hr;\r
+\r
+ EpType = WV_IO_EP_TYPE_CONNECT;\r
+ if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_CREATE, &EpType, sizeof EpType,\r
+ &m_Id, sizeof m_Id, &bytes, NULL)) {\r
+ hr = WV_SUCCESS;\r
+ } else {\r
+ hr = HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
+\r
+ return hr;\r
}\r
\r
CWVConnectEndpoint::~CWVConnectEndpoint()\r
{\r
+ DWORD bytes;\r
+\r
+ if (m_Id != 0) {\r
+ WvDeviceIoControl(m_hFile, WV_IOCTL_EP_DESTROY, &m_Id, sizeof m_Id,\r
+ NULL, 0, &bytes, NULL);\r
+ }\r
+\r
+ if (m_Socket != INVALID_SOCKET) {\r
+ closesocket(m_Socket);\r
+ }\r
m_pProvider->Release();\r
}\r
\r
}\r
\r
STDMETHODIMP CWVConnectEndpoint::\r
-BindAddress(const struct sockaddr* pAddress)\r
+Modify(DWORD Option, const VOID* pOptionData, SIZE_T OptionLength)\r
{\r
- UNREFERENCED_PARAMETER(pAddress);\r
+ WV_IO_ID *pId;\r
+ DWORD bytes;\r
+ HRESULT hr;\r
+ CWVBuffer buf;\r
+\r
+ bytes = sizeof WV_IO_ID + OptionLength;\r
+ pId = (WV_IO_ID *) buf.Get(bytes);\r
+ if (pId == NULL) {\r
+ return WV_NO_MEMORY;\r
+ }\r
\r
- return E_NOTIMPL;\r
+ pId->Id = m_Id;\r
+ pId->Data = Option;\r
+ RtlCopyMemory(pId + 1, pOptionData, OptionLength);\r
+\r
+ if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_MODIFY, pId, bytes,\r
+ NULL, 0, &bytes, NULL)) {\r
+ hr = WV_SUCCESS;\r
+ } else {\r
+ hr = HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
+\r
+ buf.Put();\r
+ return hr;\r
}\r
\r
STDMETHODIMP CWVConnectEndpoint::\r
-Reject(const VOID* pPrivateData, SIZE_T PrivateDataLength)\r
+BindAddress(SOCKADDR* pAddress)\r
{\r
- UNREFERENCED_PARAMETER(pPrivateData);\r
- UNREFERENCED_PARAMETER(PrivateDataLength);\r
+ WV_IO_EP_BIND attr;\r
+ BOOLEAN any;\r
+ DWORD bytes;\r
+ HRESULT hr;\r
+\r
+ if (pAddress->sa_family == AF_INET) {\r
+ any = (((SOCKADDR_IN *) pAddress)->sin_addr.S_un.S_addr == INADDR_ANY);\r
+ bytes = sizeof(SOCKADDR_IN);\r
+ } else {\r
+ any = IN6ADDR_ISANY((SOCKADDR_IN6 *) pAddress);\r
+ bytes = sizeof(SOCKADDR_IN6);\r
+ }\r
\r
- return E_NOTIMPL;\r
+ if (any) {\r
+ RtlZeroMemory(&attr.Device, sizeof attr.Device);\r
+ } else {\r
+ hr = m_pProvider->TranslateAddress(pAddress, (WV_DEVICE_ADDRESS *) &attr.Device);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+ }\r
+\r
+ m_Socket = socket(pAddress->sa_family, SOCK_STREAM, IPPROTO_TCP);\r
+ if (m_Socket == INVALID_SOCKET) {\r
+ return WSAGetLastError();\r
+ }\r
+\r
+ hr = bind(m_Socket, pAddress, bytes);\r
+ if (FAILED(hr)) {\r
+ goto err;\r
+ }\r
+\r
+ attr.Id = m_Id;\r
+ RtlCopyMemory(&attr.Address, pAddress, bytes);\r
+\r
+ if (!WvDeviceIoControl(m_hFile, WV_IOCTL_EP_BIND, &attr, sizeof attr,\r
+ &attr, sizeof attr, &bytes, NULL)) {\r
+ hr = HRESULT_FROM_WIN32(GetLastError());\r
+ goto err;\r
+ }\r
+\r
+ return WV_SUCCESS;\r
+\r
+err:\r
+ closesocket(m_Socket);\r
+ m_Socket = INVALID_SOCKET;\r
+ return hr;\r
}\r
\r
STDMETHODIMP CWVConnectEndpoint::\r
-Connect(IWVConnectQueuePair* pQp, WV_CONNECT_PARAM* pParam, OVERLAPPED* pOverlapped)\r
+Listen(SIZE_T Backlog)\r
{\r
- UNREFERENCED_PARAMETER(pQp);\r
- UNREFERENCED_PARAMETER(pParam);\r
- UNREFERENCED_PARAMETER(pOverlapped);\r
+ WV_IO_EP_LISTEN attr;\r
+ DWORD bytes;\r
+ HRESULT hr;\r
+\r
+ attr.Id = m_Id;\r
+ attr.Backlog = Backlog;\r
+\r
+ if (!WvDeviceIoControl(m_hFile, WV_IOCTL_EP_LISTEN, &attr, sizeof attr,\r
+ &attr, sizeof attr, &bytes, NULL)) {\r
+ hr = HRESULT_FROM_WIN32(GetLastError());\r
+ } else {\r
+ hr = WV_SUCCESS;\r
+ }\r
\r
- return E_NOTIMPL;\r
+ return hr;\r
+}\r
+\r
+STDMETHODIMP CWVConnectEndpoint::\r
+Reject(const VOID* pUserData, SIZE_T UserDataLength)\r
+{\r
+ WV_IO_ID *pId;\r
+ DWORD bytes;\r
+ HRESULT hr;\r
+ CWVBuffer buf;\r
+\r
+ bytes = sizeof WV_IO_ID + UserDataLength;\r
+ pId = (WV_IO_ID *) buf.Get(bytes);\r
+ if (pId == NULL) {\r
+ return WV_NO_MEMORY;\r
+ }\r
+\r
+ pId->Id = m_Id;\r
+ RtlCopyMemory(pId + 1, pUserData, UserDataLength);\r
+\r
+ if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_REJECT, pId, bytes,\r
+ NULL, 0, &bytes, NULL)) {\r
+ hr = WV_SUCCESS;\r
+ } else {\r
+ hr = HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
+\r
+ buf.Put();\r
+ return hr;\r
+}\r
+\r
+STDMETHODIMP CWVConnectEndpoint::\r
+GetRequest(IWVConnectEndpoint* pEndpoint, OVERLAPPED* pOverlapped)\r
+{\r
+ WV_IO_EP_GET_REQUEST req;\r
+ DWORD bytes;\r
+ HRESULT hr;\r
+\r
+ req.Id = m_Id;\r
+ req.EpId = ((CWVConnectEndpoint *) pEndpoint)->m_Id;\r
+ if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_GET_REQUEST,\r
+ &req, sizeof req, NULL, 0, &bytes, pOverlapped)) {\r
+ hr = WV_SUCCESS;\r
+ } else {\r
+ hr = HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
+\r
+ return hr;\r
+}\r
+\r
+STDMETHODIMP CWVConnectEndpoint::\r
+Connect(IWVConnectQueuePair* pQp, const SOCKADDR* pAddress,\r
+ WV_CONNECT_PARAM* pParam, OVERLAPPED* pOverlapped)\r
+{\r
+ WV_IO_EP_CONNECT attr;\r
+ DWORD bytes;\r
+ HRESULT hr;\r
+\r
+ attr.Id = m_Id;\r
+ attr.QpId = ((CWVConnectQueuePair *) pQp)->m_Id;\r
+\r
+ if (pAddress->sa_family == AF_INET) {\r
+ RtlCopyMemory(&attr.PeerAddress, pAddress, sizeof(SOCKADDR_IN));\r
+ } else {\r
+ RtlCopyMemory(&attr.PeerAddress, pAddress, sizeof(SOCKADDR_IN6));\r
+ }\r
+ WvIoConvertConnParam(&attr.Param, pParam);\r
+\r
+ if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_CONNECT, &attr, sizeof attr,\r
+ NULL, 0, &bytes, pOverlapped)) {\r
+ hr = WV_SUCCESS;\r
+ } else {\r
+ hr = HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
+\r
+ return hr;\r
}\r
\r
STDMETHODIMP CWVConnectEndpoint::\r
Accept(IWVConnectQueuePair* pQp, WV_CONNECT_PARAM* pParam, OVERLAPPED* pOverlapped)\r
{\r
- UNREFERENCED_PARAMETER(pQp);\r
- UNREFERENCED_PARAMETER(pParam);\r
- UNREFERENCED_PARAMETER(pOverlapped);\r
+ CWVConnectQueuePair *qp = (CWVConnectQueuePair *) pQp;\r
+ WV_IO_EP_ACCEPT attr;\r
+ DWORD bytes;\r
+ HRESULT hr;\r
+ void *pout;\r
+ DWORD size;\r
+\r
+ attr.Id = m_Id;\r
+ attr.QpId = qp->m_Id;\r
+ qp->m_pVerbs->nd_modify_qp(qp->m_hVerbsQp, &pout, &size);\r
+ WvIoConvertConnParam(&attr.Param, pParam);\r
+\r
+ if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_ACCEPT, &attr, sizeof attr,\r
+ pout, size, &bytes, pOverlapped)) {\r
+ hr = WV_SUCCESS;\r
+ } else {\r
+ hr = HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
\r
- return E_NOTIMPL;\r
+ return hr;\r
}\r
\r
STDMETHODIMP CWVConnectEndpoint::\r
-Disconnect(OVERLAPPED* pOverlapped)\r
+Disconnect(void)\r
{\r
- UNREFERENCED_PARAMETER(pOverlapped);\r
+ DWORD bytes;\r
+ HRESULT hr;\r
+\r
+ if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_DISCONNECT,\r
+ &m_Id, sizeof m_Id, NULL, 0, &bytes, NULL)) {\r
+ hr = WV_SUCCESS;\r
+ } else {\r
+ hr = HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
\r
- return E_NOTIMPL;\r
+ return hr;\r
}\r
\r
STDMETHODIMP CWVConnectEndpoint::\r
NotifyDisconnect(OVERLAPPED* pOverlapped)\r
{\r
- UNREFERENCED_PARAMETER(pOverlapped);\r
+ DWORD bytes;\r
+ HRESULT hr;\r
+\r
+ if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_DISCONNECT_NOTIFY,\r
+ &m_Id, sizeof m_Id, NULL, 0, &bytes, pOverlapped)) {\r
+ hr = WV_SUCCESS;\r
+ } else {\r
+ hr = HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
\r
- return E_NOTIMPL;\r
+ return hr;\r
}\r
\r
STDMETHODIMP CWVConnectEndpoint::\r
Query(WV_CONNECT_ATTRIBUTES* pAttributes)\r
{\r
- UNREFERENCED_PARAMETER(pAttributes);\r
+ WV_IO_EP_ATTRIBUTES attr;\r
+ DWORD bytes;\r
+ HRESULT hr;\r
\r
- return E_NOTIMPL;\r
+ if (!WvDeviceIoControl(m_hFile, WV_IOCTL_EP_QUERY, &m_Id, sizeof m_Id,\r
+ &attr, sizeof attr, &bytes, NULL)) {\r
+ return HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
+\r
+ RtlCopyMemory(&pAttributes->LocalAddress, &attr.LocalAddress,\r
+ sizeof pAttributes->LocalAddress);\r
+ RtlCopyMemory(&pAttributes->PeerAddress, &attr.PeerAddress,\r
+ sizeof pAttributes->PeerAddress);\r
+ RtlCopyMemory(&pAttributes->Device, &attr.Device, sizeof pAttributes->Device);\r
+ pAttributes->Param.DataLength = attr.Param.Connect.DataLength;\r
+ pAttributes->Param.ResponderResources = (SIZE_T) attr.Param.Connect.ResponderResources;\r
+ pAttributes->Param.InitiatorDepth = (SIZE_T) attr.Param.Connect.InitiatorDepth;\r
+ pAttributes->Param.RetryCount = attr.Param.Connect.RetryCount;\r
+ pAttributes->Param.RnrRetryCount = attr.Param.Connect.RnrRetryCount;\r
+ RtlCopyMemory(pAttributes->Param.Data, attr.Param.Connect.Data, attr.Param.Connect.DataLength);\r
+\r
+ return WV_SUCCESS;\r
}\r
\r
\r
m_pProvider = pProvider;\r
m_hFile = pProvider->m_hFile;\r
}\r
+ \r
+STDMETHODIMP CWVDatagramEndpoint::\r
+Allocate(void)\r
+{\r
+ UINT64 EpType;\r
+ DWORD bytes;\r
+ HRESULT hr;\r
+\r
+ EpType = WV_IO_EP_TYPE_DATAGRAM;\r
+ if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_CREATE, &EpType, sizeof EpType,\r
+ &m_Id, sizeof m_Id, &bytes, NULL)) {\r
+ hr = WV_SUCCESS;\r
+ } else {\r
+ hr = HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
+\r
+ return hr;\r
+}\r
\r
CWVDatagramEndpoint::~CWVDatagramEndpoint()\r
{\r
+ DWORD bytes;\r
+\r
+ if (m_Id != 0) {\r
+ WvDeviceIoControl(m_hFile, WV_IOCTL_EP_DESTROY, &m_Id, sizeof m_Id,\r
+ NULL, 0, &bytes, NULL);\r
+ }\r
m_pProvider->Release();\r
}\r
\r
}\r
\r
STDMETHODIMP CWVDatagramEndpoint::\r
-BindAddress(const struct sockaddr* pAddress)\r
+Modify(DWORD Option, const VOID* pOptionData, SIZE_T OptionLength)\r
+{\r
+ UNREFERENCED_PARAMETER(Option);\r
+ UNREFERENCED_PARAMETER(pOptionData);\r
+ UNREFERENCED_PARAMETER(OptionLength);\r
+\r
+ return E_NOTIMPL;\r
+}\r
+\r
+STDMETHODIMP CWVDatagramEndpoint::\r
+BindAddress(SOCKADDR* pAddress)\r
{\r
UNREFERENCED_PARAMETER(pAddress);\r
\r
}\r
\r
STDMETHODIMP CWVDatagramEndpoint::\r
-Reject(const VOID* pPrivateData, SIZE_T PrivateDataLength)\r
+Listen(SIZE_T Backlog)\r
{\r
- UNREFERENCED_PARAMETER(pPrivateData);\r
- UNREFERENCED_PARAMETER(PrivateDataLength);\r
+ UNREFERENCED_PARAMETER(Backlog);\r
+\r
+ return E_NOTIMPL;\r
+}\r
+\r
+STDMETHODIMP CWVDatagramEndpoint::\r
+Reject(const VOID* pUserData, SIZE_T UserDataLength)\r
+{\r
+ UNREFERENCED_PARAMETER(pUserData);\r
+ UNREFERENCED_PARAMETER(UserDataLength);\r
+\r
+ return E_NOTIMPL;\r
+}\r
+\r
+STDMETHODIMP CWVDatagramEndpoint::\r
+GetRequest(IWVDatagramEndpoint* pEndpoint, OVERLAPPED* pOverlapped)\r
+{\r
+ UNREFERENCED_PARAMETER(pEndpoint);\r
+ UNREFERENCED_PARAMETER(pOverlapped);\r
\r
return E_NOTIMPL;\r
}\r
\r
STDMETHODIMP CWVDatagramEndpoint::\r
-Lookup(const struct sockaddr* pAddress, const VOID* pPrivateData,\r
- SIZE_T PrivateDataLength, OVERLAPPED* pOverlapped)\r
+Lookup(const SOCKADDR* pAddress, const VOID* pUserData,\r
+ SIZE_T UserDataLength, OVERLAPPED* pOverlapped)\r
{\r
UNREFERENCED_PARAMETER(pAddress);\r
- UNREFERENCED_PARAMETER(pPrivateData);\r
- UNREFERENCED_PARAMETER(PrivateDataLength);\r
+ UNREFERENCED_PARAMETER(pUserData);\r
+ UNREFERENCED_PARAMETER(UserDataLength);\r
UNREFERENCED_PARAMETER(pOverlapped);\r
\r
return E_NOTIMPL;\r
}\r
\r
STDMETHODIMP CWVDatagramEndpoint::\r
-JoinMulticast(const struct sockaddr* pAddress, OVERLAPPED* pOverlapped)\r
+JoinMulticast(const SOCKADDR* pAddress, OVERLAPPED* pOverlapped)\r
{\r
UNREFERENCED_PARAMETER(pAddress);\r
UNREFERENCED_PARAMETER(pOverlapped);\r
}\r
\r
STDMETHODIMP CWVDatagramEndpoint::\r
-LeaveMulticast(const struct sockaddr* pAddress, OVERLAPPED* pOverlapped)\r
+LeaveMulticast(const SOCKADDR* pAddress, OVERLAPPED* pOverlapped)\r
{\r
UNREFERENCED_PARAMETER(pAddress);\r
UNREFERENCED_PARAMETER(pOverlapped);\r
DWORD *pNumberOfBytesTransferred, BOOL bWait);\r
\r
// IWVEndpoint methods\r
- STDMETHODIMP BindAddress(const struct sockaddr* pAddress);\r
- STDMETHODIMP Reject(const VOID* pPrivateData, SIZE_T PrivateDataLength);\r
+ STDMETHODIMP Modify(DWORD Option, const VOID* pOptionData, SIZE_T OptionLength);\r
+ STDMETHODIMP BindAddress(SOCKADDR* pAddress);\r
+ STDMETHODIMP Listen(SIZE_T Backlog);\r
+ STDMETHODIMP Reject(const VOID* pUserData, SIZE_T UserDataLength);\r
\r
// IWVConnectEndpoint methods\r
- STDMETHODIMP Connect(IWVConnectQueuePair* pQp, WV_CONNECT_PARAM* pParam,\r
- OVERLAPPED* pOverlapped);\r
+ STDMETHODIMP GetRequest(IWVConnectEndpoint* pEndpoint, OVERLAPPED* pOverlapped);\r
+ STDMETHODIMP Connect(IWVConnectQueuePair* pQp, const SOCKADDR* pAddress,\r
+ WV_CONNECT_PARAM* pParam, OVERLAPPED* pOverlapped);\r
STDMETHODIMP Accept(IWVConnectQueuePair* pQp, WV_CONNECT_PARAM* pParam,\r
OVERLAPPED* pOverlapped);\r
- STDMETHODIMP Disconnect(OVERLAPPED* pOverlapped);\r
+ STDMETHODIMP Disconnect();\r
STDMETHODIMP NotifyDisconnect(OVERLAPPED* pOverlapped);\r
STDMETHODIMP Query(WV_CONNECT_ATTRIBUTES* pAttributes);\r
\r
goto err2;\r
}\r
\r
+ hr = ep->Allocate();\r
+ if (FAILED(hr)) {\r
+ goto err2;\r
+ }\r
+\r
*ppConnectEndpoint = ep;\r
return WV_SUCCESS;\r
\r
}\r
\r
CWVProvider *m_pProvider;\r
+\r
+protected:\r
+ SOCKET m_Socket;\r
+\r
+ STDMETHODIMP Allocate();\r
};\r
\r
class CWVDatagramEndpoint : IWVDatagramEndpoint, public CWVBase\r
DWORD *pNumberOfBytesTransferred, BOOL bWait);\r
\r
// IWVEndpoint methods\r
- STDMETHODIMP BindAddress(const struct sockaddr* pAddress);\r
- STDMETHODIMP Reject(const VOID* pPrivateData, SIZE_T PrivateDataLength);\r
+ STDMETHODIMP Modify(DWORD Option, const VOID* pOptionData, SIZE_T OptionLength);\r
+ STDMETHODIMP BindAddress(SOCKADDR* pAddress);\r
+ STDMETHODIMP Listen(SIZE_T Backlog);\r
+ STDMETHODIMP Reject(const VOID* pUserData, SIZE_T UserDataLength);\r
\r
// IWVDatagramEndpoint methods\r
- STDMETHODIMP Lookup(const struct sockaddr* pAddress, const VOID* pPrivateData,\r
- SIZE_T PrivateDataLength, OVERLAPPED* pOverlapped);\r
+ STDMETHODIMP GetRequest(IWVDatagramEndpoint* pEndpoint, OVERLAPPED* pOverlapped);\r
+ STDMETHODIMP Lookup(const SOCKADDR* pAddress, const VOID* pUserData,\r
+ SIZE_T UserDataLength, OVERLAPPED* pOverlapped);\r
STDMETHODIMP Accept(WV_DATAGRAM_PARAM* pParam, OVERLAPPED* pOverlapped);\r
- STDMETHODIMP JoinMulticast(const struct sockaddr* pAddress,\r
+ STDMETHODIMP JoinMulticast(const SOCKADDR* pAddress,\r
OVERLAPPED* pOverlapped);\r
- STDMETHODIMP LeaveMulticast(const struct sockaddr* pAddress,\r
+ STDMETHODIMP LeaveMulticast(const SOCKADDR* pAddress,\r
OVERLAPPED* pOverlapped);\r
STDMETHODIMP Query(WV_DATAGRAM_ATTRIBUTES* pAttributes);\r
\r
goto err2;\r
}\r
\r
+ hr = ep->Allocate();\r
+ if (FAILED(hr)) {\r
+ goto err2;\r
+ }\r
+\r
*ppDatagramEndpoint = ep;\r
return WV_SUCCESS;\r
\r
}\r
\r
CWVProvider *m_pProvider;\r
+\r
+protected:\r
+ STDMETHODIMP Allocate();\r
};\r
\r
#endif // _WV_EP_H_\r
#include "wv_memory.h"\r
#include "wv_listen.h"\r
#include "wv_ioctl.h"\r
+#include "wv_ep.h"\r
\r
CWVListen::CWVListen(CWVProvider *pProvider)\r
{\r
pProvider->AddRef();\r
m_pProvider = pProvider;\r
m_hFile = pProvider->m_hFile;\r
+ m_Socket = INVALID_SOCKET;\r
}\r
\r
CWVListen::~CWVListen()\r
{\r
+ DWORD bytes;\r
+\r
+ if (m_Id != 0) {\r
+ WvDeviceIoControl(m_hFile, WV_IOCTL_EP_DESTROY, &m_Id, sizeof m_Id,\r
+ NULL, 0, &bytes, NULL);\r
+ }\r
+\r
+ if (m_Socket != INVALID_SOCKET) {\r
+ closesocket(m_Socket);\r
+ }\r
m_pProvider->Release();\r
}\r
\r
{\r
DWORD bytes;\r
\r
- return WvDeviceIoControl(m_hFile, WV_IOCTL_LISTEN_CANCEL, &m_Id, sizeof m_Id,\r
+ return WvDeviceIoControl(m_hFile, WV_IOCTL_EP_CANCEL, &m_Id, sizeof m_Id,\r
NULL, 0, &bytes, NULL) ?\r
WV_SUCCESS : HRESULT_FROM_WIN32(GetLastError());\r
}\r
}\r
\r
STDMETHODIMP CWVListen::\r
-Listen(const struct sockaddr* pAddress, SIZE_T Backlog)\r
+Allocate(UINT64 EpType)\r
+{\r
+ DWORD bytes;\r
+ HRESULT hr;\r
+\r
+ if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_CREATE, &EpType, sizeof EpType,\r
+ &m_Id, sizeof m_Id, &bytes, NULL)) {\r
+ hr = WV_SUCCESS;\r
+ } else {\r
+ hr = HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
+\r
+ return hr;\r
+}\r
+\r
+STDMETHODIMP CWVListen::\r
+Bind(SOCKADDR* pAddress, WV_EP_TYPE EpType)\r
+{\r
+ WV_IO_EP_BIND attr;\r
+ BOOLEAN any;\r
+ DWORD bytes;\r
+ HRESULT hr;\r
+\r
+ if (pAddress->sa_family == AF_INET) {\r
+ any = (((SOCKADDR_IN *) pAddress)->sin_addr.S_un.S_addr == INADDR_ANY);\r
+ bytes = sizeof(SOCKADDR_IN);\r
+ } else {\r
+ any = IN6ADDR_ISANY((SOCKADDR_IN6 *) pAddress);\r
+ bytes = sizeof(SOCKADDR_IN6);\r
+ }\r
+\r
+ if (any == FALSE) {\r
+ hr = m_pProvider->TranslateAddress(pAddress,\r
+ (WV_DEVICE_ADDRESS *) &attr.Device);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+ }\r
+\r
+ m_Socket = (EpType == WvEpTypeConnect) ?\r
+ socket(pAddress->sa_family, SOCK_STREAM, IPPROTO_TCP) :\r
+ socket(pAddress->sa_family, SOCK_DGRAM, IPPROTO_UDP);\r
+ if (m_Socket == INVALID_SOCKET) {\r
+ return WSAGetLastError();\r
+ }\r
+\r
+ hr = bind(m_Socket, pAddress, bytes);\r
+ if (FAILED(hr)) {\r
+ goto err;\r
+ }\r
+\r
+ attr.Id = m_Id;\r
+ RtlCopyMemory(&attr.Address, pAddress, bytes);\r
+\r
+ if (!WvDeviceIoControl(m_hFile, WV_IOCTL_EP_BIND, &attr, sizeof attr,\r
+ &attr, sizeof attr, &bytes, NULL)) {\r
+ hr = HRESULT_FROM_WIN32(GetLastError());\r
+ goto err;\r
+ }\r
+\r
+ return WV_SUCCESS;\r
+\r
+err:\r
+ closesocket(m_Socket);\r
+ m_Socket = INVALID_SOCKET;\r
+ return hr;\r
+}\r
+\r
+STDMETHODIMP CWVListen::\r
+Listen(SOCKADDR* pAddress, WV_EP_TYPE EpType, SIZE_T Backlog)\r
{\r
- UNREFERENCED_PARAMETER(pAddress);\r
- UNREFERENCED_PARAMETER(Backlog);\r
+ WV_IO_EP_LISTEN attr;\r
+ BOOLEAN any;\r
+ DWORD bytes;\r
+ HRESULT hr;\r
+\r
+ hr = Allocate((UINT64) EpType);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+\r
+ hr = Bind(pAddress, EpType);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+\r
+ attr.Id = m_Id;\r
+ attr.Backlog = Backlog;\r
+\r
+ if (!WvDeviceIoControl(m_hFile, WV_IOCTL_EP_LISTEN, &attr, sizeof attr,\r
+ &attr, sizeof attr, &bytes, NULL)) {\r
+ hr = HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
\r
- return E_NOTIMPL;\r
+ return hr;\r
}\r
\r
STDMETHODIMP CWVListen::\r
GetRequest(IWVEndpoint* pEndpoint, OVERLAPPED* pOverlapped)\r
{\r
- UNREFERENCED_PARAMETER(pEndpoint);\r
- UNREFERENCED_PARAMETER(pOverlapped);\r
+ WV_IO_EP_GET_REQUEST req;\r
+ DWORD bytes;\r
+ HRESULT hr;\r
\r
- return E_NOTIMPL;\r
+ req.Id = m_Id;\r
+ req.EpId = ((CWVBase *) pEndpoint)->m_Id;\r
+\r
+ if (WvDeviceIoControl(m_hFile, WV_IOCTL_EP_GET_REQUEST,\r
+ &req, sizeof req, NULL, 0, &bytes, NULL)) {\r
+ hr = WV_SUCCESS;\r
+ } else {\r
+ hr = HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
+\r
+ return hr;\r
+}\r
+\r
+STDMETHODIMP CWVListen::\r
+Query(WV_LISTEN_ATTRIBUTES* pAttributes)\r
+{\r
+ WV_IO_EP_ATTRIBUTES attr;\r
+ DWORD bytes;\r
+ HRESULT hr;\r
+\r
+ if (!WvDeviceIoControl(m_hFile, WV_IOCTL_EP_QUERY, &m_Id, sizeof m_Id,\r
+ &attr, sizeof attr, &bytes, NULL)) {\r
+ return HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
+\r
+ RtlCopyMemory(&pAttributes->LocalAddress, &attr.LocalAddress,\r
+ sizeof pAttributes->LocalAddress);\r
+ RtlCopyMemory(&pAttributes->Device, &attr.Device, sizeof pAttributes->Device);\r
+ pAttributes->Backlog = attr.Param.Backlog;\r
+\r
+ return WV_SUCCESS;\r
}\r
\r
// IWVListen methods\r
STDMETHODIMP GetRequest(IWVEndpoint* pEndpoint, OVERLAPPED* pOverlapped);\r
+ STDMETHODIMP Query(WV_LISTEN_ATTRIBUTES* pAttributes);\r
\r
- STDMETHODIMP Listen(const struct sockaddr* pAddress, SIZE_T Backlog);\r
+ STDMETHODIMP Listen(SOCKADDR* pAddress, WV_EP_TYPE EndpointType, SIZE_T Backlog);\r
\r
CWVListen(CWVProvider *pProvider);\r
~CWVListen();\r
void Delete() {delete this;}\r
static STDMETHODIMP\r
- CreateInstance(CWVProvider *pProvider, const struct sockaddr* pAddress,\r
- SIZE_T Backlog, IWVListen** ppListen)\r
+ CreateInstance(CWVProvider *pProvider, SOCKADDR* pAddress,\r
+ WV_EP_TYPE EpType, SIZE_T Backlog, IWVListen** ppListen)\r
{\r
HRESULT hr;\r
CWVListen *listener;\r
goto err2;\r
}\r
\r
- hr = listener->Listen(pAddress, Backlog);\r
+ hr = listener->Listen(pAddress, EpType, Backlog);\r
if (FAILED(hr)) {\r
goto err2;\r
}\r
}\r
\r
CWVProvider *m_pProvider;\r
+\r
+protected:\r
+ SOCKET m_Socket;\r
+ STDMETHODIMP Allocate(UINT64 EpType);\r
+ STDMETHODIMP Bind(SOCKADDR* pAddress, WV_EP_TYPE EpType);\r
};\r
\r
#endif // _WV_LISTEN_H_
\ No newline at end of file
DWORD bytes;\r
HRESULT hr;\r
\r
- if (m_Id != NULL) {\r
+ if (m_Id != 0) {\r
m_pVerbs->pre_deallocate_pd(m_hVerbsPd);\r
- hr = WvDeviceIoControl(m_hFile, WV_IOCTL_PD_ALLOCATE, &m_Id, sizeof m_Id,\r
+ hr = WvDeviceIoControl(m_hFile, WV_IOCTL_PD_DEALLOCATE, &m_Id, sizeof m_Id,\r
NULL, 0, &bytes, NULL) ?\r
WV_SUCCESS : HRESULT_FROM_WIN32(GetLastError());\r
m_pVerbs->post_deallocate_pd(m_hVerbsPd, (ib_api_status_t) hr);\r
DWORD bytes;\r
HRESULT hr;\r
\r
- if (m_Id != NULL) {\r
+ if (m_Id != 0) {\r
m_pVerbs->pre_destroy_mw(m_hVerbsMw);\r
hr = WvDeviceIoControl(m_hFile, WV_IOCTL_MW_DEALLOCATE,\r
&m_Id, sizeof m_Id, NULL, 0, &bytes, NULL) ?\r
HRESULT hr;\r
ib_api_status_t stat;\r
\r
- if (m_Id != NULL) {\r
+ if (m_Id != 0) {\r
stat = m_pVerbs->pre_destroy_av(m_hVerbsAh);\r
if (stat != IB_VERBS_PROCESSING_DONE) {\r
hr = WvDeviceIoControl(m_hFile, WV_IOCTL_AH_DESTROY,\r
STDMETHODIMP CWVAddressHandle::\r
ConvertAv(ib_av_attr_t *pVerbsAv, WV_ADDRESS_VECTOR *pAv)\r
{\r
+ DWORD index;\r
HRESULT hr;\r
\r
pVerbsAv->grh_valid = pAv->Route.Valid;\r
if (pVerbsAv->grh_valid) {\r
- hr = m_pPd->m_pDevice->FindGidIndex(pAv->PortNumber, &pAv->Route.SGid,\r
- &pVerbsAv->grh.resv1);\r
+ hr = m_pPd->m_pDevice->FindGid(pAv->PortNumber, &pAv->Route.SGid, &index);\r
if (FAILED(hr)) {\r
return hr;\r
}\r
\r
+ pVerbsAv->grh.resv1 = (UINT16) index;\r
pVerbsAv->grh.ver_class_flow =\r
_byteswap_ulong(_byteswap_ulong(pAv->Route.FlowLabel) |\r
(pAv->Route.TrafficClass << 20));\r
*/\r
\r
#include <iba\ib_al.h>\r
+#include <iba\ib_at_ioctl.h>\r
\r
#include "wv_memory.h"\r
#include "wv_provider.h"\r
#include "wv_device.h"\r
#include "wv_ep.h"\r
-#include "wv_listen.h"\r
#include "wv_ioctl.h"\r
\r
CWVProvider::CWVProvider()\r
CWVProvider::~CWVProvider()\r
{\r
CloseHandle(m_hFile);\r
- InterlockedDecrement(&WvRef);\r
+ if (InterlockedDecrement(&WvRef) == 0) {\r
+ WSACleanup();\r
+ }\r
}\r
\r
STDMETHODIMP CWVProvider::\r
}\r
\r
STDMETHODIMP CWVProvider::\r
-QueryAddressList(WV_ADDRESS_LIST* pAddressList, SIZE_T* pBufferSize)\r
+TranslateAddress(SOCKADDR* pAddress, WV_DEVICE_ADDRESS* pDeviceAddress)\r
{\r
- UNREFERENCED_PARAMETER(pAddressList);\r
- UNREFERENCED_PARAMETER(pBufferSize);\r
+ HANDLE hIbat;\r
+ IOCTL_IBAT_IP_TO_PORT_IN addr;\r
+ IBAT_PORT_RECORD port;\r
+ DWORD bytes;\r
+ HRESULT hr;\r
+\r
+ hIbat = CreateFileW(IBAT_WIN32_NAME, GENERIC_READ | GENERIC_WRITE,\r
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,\r
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\r
+ if (hIbat == INVALID_HANDLE_VALUE) {\r
+ return HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
+\r
+ addr.Version = IBAT_IOCTL_VERSION;\r
+ if (pAddress->sa_family == AF_INET) {\r
+ addr.Address.IpVersion = 4;\r
+ RtlCopyMemory(addr.Address.Address + 12,\r
+ &((SOCKADDR_IN *)pAddress)->sin_addr, 4);\r
+ } else {\r
+ addr.Address.IpVersion = 6;\r
+ RtlCopyMemory(addr.Address.Address,\r
+ &((SOCKADDR_IN6 *)pAddress)->sin6_addr, 16);\r
+ }\r
+\r
+ if (DeviceIoControl(hIbat, IOCTL_IBAT_IP_TO_PORT,\r
+ &addr, sizeof addr, &port, sizeof port, &bytes, NULL)) {\r
+ hr = WV_SUCCESS;\r
+ pDeviceAddress->DeviceGuid = port.CaGuid;\r
+ pDeviceAddress->Pkey = port.PKey;\r
+ pDeviceAddress->PortNumber = port.PortNum;\r
+ } else {\r
+ hr = HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
\r
- return E_NOTIMPL;\r
+ CloseHandle(hIbat);\r
+ return hr;\r
}\r
\r
STDMETHODIMP CWVProvider::\r
{\r
return CWVDatagramEndpoint::CreateInstance(this, ppDatagramEndpoint);\r
}\r
-\r
-STDMETHODIMP CWVProvider::\r
-CreateListen(const struct sockaddr* pAddress, SIZE_T Backlog, IWVListen** ppListen)\r
-{\r
- return CWVListen::CreateInstance(this, pAddress, Backlog, ppListen);\r
-}\r
STDMETHODIMP_(HANDLE) GetFileHandle();\r
STDMETHODIMP QueryDeviceList(NET64* pGuidList, SIZE_T* pBufferSize);\r
STDMETHODIMP QueryDevice(NET64 Guid, WV_DEVICE_ATTRIBUTES* pAttributes);\r
- STDMETHODIMP QueryAddressList(WV_ADDRESS_LIST* pAddressList, SIZE_T* pBufferSize);\r
+ STDMETHODIMP TranslateAddress(SOCKADDR* pAddress,\r
+ WV_DEVICE_ADDRESS* pDeviceAddress);\r
\r
STDMETHODIMP OpenDevice(NET64 Guid, IWVDevice** ppDevice);\r
\r
STDMETHODIMP CreateConnectEndpoint(IWVConnectEndpoint** ppConnectEndpoint);\r
STDMETHODIMP CreateDatagramEndpoint(IWVDatagramEndpoint** ppDatagramEndpoint);\r
- STDMETHODIMP CreateListen(const struct sockaddr* pAddress,\r
- SIZE_T backlog, IWVListen** ppListen);\r
\r
CWVProvider();\r
~CWVProvider();\r
void Delete() {delete this;}\r
static STDMETHODIMP CreateInstance(IWVProvider** ppProvider)\r
{\r
+ WSADATA wsadata;\r
HRESULT hr;\r
CWVProvider *wv;\r
\r
+ if (WvRef == 0) {\r
+ hr = WSAStartup(MAKEWORD(2, 2), &wsadata);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+ }\r
+\r
wv = new CWVProvider;\r
if (wv == NULL) {\r
hr = WV_NO_MEMORY;\r
\r
pIoAttr->AccessFlags = (UINT8) pAttr->AccessFlags;\r
pIoAttr->QpFlags = (UINT8) pAttr->QpFlags;\r
+ RtlZeroMemory(pIoAttr->Reserved, sizeof pIoAttr->Reserved);\r
}\r
\r
CWVQueuePair::CWVQueuePair(CWVProtectionDomain *pPd)\r
DWORD bytes;\r
HRESULT hr;\r
\r
- if (m_Id != NULL) {\r
+ if (m_Id != 0) {\r
m_pVerbs->pre_destroy_qp(m_hVerbsQp);\r
hr = WvDeviceIoControl(m_hFile, WV_IOCTL_QP_DESTROY, &m_Id, sizeof m_Id,\r
NULL, 0, &bytes, NULL) ?\r
pattr->MaxSge = attr.max_sge;\r
pattr->MaxWr = attr.max_wr;\r
pattr->SrqLimit = attr.srq_limit;\r
+ pattr->Reserved = 0;\r
RtlCopyMemory(pattr + 1, (void *) (ULONG_PTR) verbsData.p_inout_buf,\r
verbsData.input_size);\r
\r
DWORD bytes;\r
HRESULT hr;\r
\r
- if (m_Id != NULL) {\r
+ if (m_Id != 0) {\r
m_pVerbs->pre_destroy_srq(m_hVerbsSrq);\r
hr = WvDeviceIoControl(m_hFile, WV_IOCTL_SRQ_DESTROY, &m_Id, sizeof m_Id,\r
NULL, 0, &bytes, NULL) ?\r
\r
pattr->Id.Id = m_Id;\r
pattr->Id.VerbInfo = verbsData.command;\r
+ pattr->Reserved = 0;\r
RtlCopyMemory(pattr + 1, (void *) (ULONG_PTR) verbsData.p_inout_buf,\r
verbsData.input_size);\r
\r
pattr->Id.VerbInfo = verbsData.command;\r
pattr->MaxWr = attr.max_wr;\r
pattr->SrqLimit = attr.srq_limit;\r
+ pattr->Reserved = 0;\r
RtlCopyMemory(pattr + 1, (void *) (ULONG_PTR) verbsData.p_inout_buf,\r
verbsData.input_size);\r
\r
WV_IO_FUNCTION_QP_ATTACH,\r
WV_IO_FUNCTION_QP_DETACH,\r
WV_IO_FUNCTION_QP_CANCEL,\r
- WV_IO_FUNCTION_ADDRESS_QUERY,\r
WV_IO_FUNCTION_EP_CREATE,\r
WV_IO_FUNCTION_EP_DESTROY,\r
+ WV_IO_FUNCTION_EP_MODIFY,\r
WV_IO_FUNCTION_EP_BIND,\r
WV_IO_FUNCTION_EP_REJECT,\r
WV_IO_FUNCTION_EP_CONNECT,\r
WV_IO_FUNCTION_EP_MULTICAST_JOIN,\r
WV_IO_FUNCTION_EP_MULTICAST_LEAVE,\r
WV_IO_FUNCTION_EP_CANCEL,\r
- WV_IO_FUNCTION_LISTEN,\r
- WV_IO_FUNCTION_LISTEN_DESTROY,\r
- WV_IO_FUNCTION_LISTEN_GET_REQUEST,\r
- WV_IO_FUNCTION_LISTEN_CANCEL,\r
+ WV_IO_FUNCTION_EP_LISTEN,\r
+ WV_IO_FUNCTION_EP_GET_REQUEST,\r
WV_IO_FUNCTION_MAX\r
};\r
\r
#define WV_IOCTL_QP_QUERY WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
WV_IO_FUNCTION_QP_QUERY)\r
\r
-// WV_IO_QP_ATTRIBUTES / none\r
+// WV_IO_QP_ATTRIBUTES / verbs specific\r
#define WV_IOCTL_QP_MODIFY WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
WV_IO_FUNCTION_QP_MODIFY)\r
\r
#define WV_IOCTL_QP_CANCEL WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
WV_IO_FUNCTION_QP_CANCEL)\r
\r
-// TODO\r
-#define WV_IOCTL_ADDRESS_QUERY WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
- WV_IO_FUNCTION_ADDRESS_QUERY)\r
+// UINT64 EpType / UINT64 Id\r
#define WV_IOCTL_EP_CREATE WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
WV_IO_FUNCTION_EP_CREATE)\r
+\r
+// UINT64 Id / none\r
#define WV_IOCTL_EP_DESTROY WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
WV_IO_FUNCTION_EP_DESTROY)\r
+\r
+// WV_IO_ID + UINT8[] / none\r
+#define WV_IOCTL_EP_MODIFY WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
+ WV_IO_FUNCTION_EP_MODIFY)\r
+\r
+// WV_IO_EP_BIND / WV_IO_EP_BIND\r
#define WV_IOCTL_EP_BIND WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
WV_IO_FUNCTION_EP_BIND)\r
+\r
+// WV_IO_ID + UINT8[] / none\r
#define WV_IOCTL_EP_REJECT WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
WV_IO_FUNCTION_EP_REJECT)\r
+\r
+// WV_IO_EP_CONNECT / none\r
#define WV_IOCTL_EP_CONNECT WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
WV_IO_FUNCTION_EP_CONNECT)\r
+\r
+// WV_IO_EP_ACCEPT / verbs specific\r
#define WV_IOCTL_EP_ACCEPT WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
WV_IO_FUNCTION_EP_ACCEPT)\r
+\r
+// UINT64 Id / none\r
#define WV_IOCTL_EP_DISCONNECT WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
WV_IO_FUNCTION_EP_DISCONNECT)\r
+\r
+// UINT64 Id / none\r
#define WV_IOCTL_EP_DISCONNECT_NOTIFY WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
WV_IO_FUNCTION_EP_DISCONNECT_NOTIFY)\r
+\r
+// UINT64 Id / WV_IO_EP_ATTRIBUTES\r
#define WV_IOCTL_EP_QUERY WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
WV_IO_FUNCTION_EP_QUERY)\r
+\r
+// TODO\r
#define WV_IOCTL_EP_LOOKUP WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
WV_IO_FUNCTION_EP_LOOKUP)\r
+\r
+// TODO\r
#define WV_IOCTL_EP_MULTICAST_JOIN WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
WV_IO_FUNCTION_EP_MULTICAST_JOIN)\r
+\r
+// TODO\r
#define WV_IOCTL_EP_MULTICAST_LEAVE WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
WV_IO_FUNCTION_EP_MULTICAST_LEAVE)\r
+\r
+// UINT64 Id / none\r
#define WV_IOCTL_EP_CANCEL WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
WV_IO_FUNCTION_EP_CANCEL)\r
-#define WV_IOCTL_LISTEN WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
- WV_IO_FUNCTION_LISTEN)\r
-#define WV_IOCTL_LISTEN_DESTROY WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
- WV_IO_FUNCTION_LISTEN_DESTROY)\r
-#define WV_IOCTL_LISTEN_GET_REQUEST WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
- WV_IO_FUNCTION_LISTEN_GET_REQUEST)\r
-#define WV_IOCTL_LISTEN_CANCEL WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
- WV_IO_FUNCTION_LISTEN_CANCEL)\r
+\r
+// WV_IO_EP_LISTEN / none\r
+#define WV_IOCTL_EP_LISTEN WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
+ WV_IO_FUNCTION_EP_LISTEN)\r
+\r
+// WV_IO_EP_GET_REQUEST / none\r
+#define WV_IOCTL_EP_GET_REQUEST WV_IOCTL(WV_IO_FUNCTION_BASE + \\r
+ WV_IO_FUNCTION_EP_GET_REQUEST)\r
\r
#define WV_IOCTL_MIN WV_IO_FUNCTION_BASE + WV_IO_FUNCTION_MIN\r
#define WV_IOCTL_MAX WV_IO_FUNCTION_BASE + WV_IO_FUNCTION_MAX\r
\r
} WV_IO_QP_MULTICAST;\r
\r
-// TODO:\r
-//WV_IO_ADDRESS_QUERY\r
-//WV_IO_EP_CREATE\r
-//WV_IO_EP_BIND\r
-//WV_IO_EP_REJECT\r
-//WV_IO_EP_CONNECT\r
-//WV_IO_EP_ACCEPT\r
-//WV_IO_EP_DISCONNECT\r
-//WV_IO_EP_DISCONNECT_NOTIFY\r
-//WV_IO_EP_QUERY\r
-//WV_IO_EP_LOOKUP\r
-//WV_IO_EP_MULTICAST_JOIN\r
-//WV_IO_EP_MULTICAST_LEAVE\r
-//WV_IO_LISTEN\r
-//WV_IO_LISTEN_GET_REQUEST\r
+// Windows kernel does not define sockaddr* pre-Vista\r
+typedef struct _WV_IO_SOCKADDR\r
+{\r
+ UINT16 SaFamily;\r
+ UINT8 SaData[14];\r
+\r
+} WV_IO_SOCKADDR;\r
+\r
+typedef struct _WV_IO_SOCKADDR_IN\r
+{\r
+ UINT16 SinFamily;\r
+ UINT16 SinPort;\r
+ UINT32 SinAddr;\r
+ UINT8 SinZero[8];\r
+\r
+} WV_IO_SOCKADDR_IN;\r
+\r
+typedef struct _WV_IO_SOCKADDR_IN6\r
+{\r
+ UINT16 Sin6Family;\r
+ UINT16 Sin6Port;\r
+ UINT32 Sin6FlowInfo;\r
+ UINT8 Sin6Addr[16];\r
+ UINT32 Sin6ScopeId;\r
+\r
+} WV_IO_SOCKADDR_IN6;\r
+\r
+typedef struct _WV_IO_SOCKADDR_DATA\r
+{\r
+ union\r
+ {\r
+ WV_IO_SOCKADDR Sa;\r
+ WV_IO_SOCKADDR_IN In;\r
+ WV_IO_SOCKADDR_IN6 In6;\r
+\r
+ } SockAddr;\r
+\r
+ UINT32 Reserved;\r
+\r
+} WV_IO_SOCKADDR_DATA;\r
+\r
+typedef struct _WV_IO_DEVICE_ADDRESS\r
+{\r
+ NET64 DeviceGuid;\r
+ NET16 Pkey;\r
+ UINT8 PortNumber;\r
+ UINT8 Reserved[5];\r
+\r
+} WV_IO_DEVICE_ADDRESS;\r
+\r
+typedef struct _WV_IO_EP_BIND\r
+{\r
+ UINT64 Id;\r
+ WV_IO_SOCKADDR_DATA Address;\r
+ WV_IO_DEVICE_ADDRESS Device;\r
+\r
+} WV_IO_EP_BIND;\r
+\r
+#define WV_IO_EP_OPTION_ROUTE 0x00000001\r
+\r
+#define WV_IO_EP_TYPE_CONNECT 0x0106\r
+#define WV_IO_EP_TYPE_DATAGRAM 0x0111\r
+\r
+typedef struct _WV_IO_EP_LISTEN\r
+{\r
+ UINT64 Id;\r
+ UINT64 Backlog;\r
+\r
+} WV_IO_EP_LISTEN;\r
+\r
+typedef struct _WV_IO_EP_GET_REQUEST\r
+{\r
+ UINT64 Id;\r
+ UINT64 EpId;\r
+\r
+} WV_IO_EP_GET_REQUEST;\r
+\r
+typedef struct _WV_IO_CONNECT_PARAM\r
+{\r
+ UINT64 ResponderResources;\r
+ UINT64 InitiatorDepth;\r
+ UINT8 RetryCount;\r
+ UINT8 RnrRetryCount;\r
+ UINT8 DataLength;\r
+ UINT8 Reserved[5];\r
+ UINT8 Data[56];\r
+\r
+} WV_IO_CONNECT_PARAM;\r
+\r
+typedef struct _WV_IO_EP_CONNECT\r
+{\r
+ UINT64 Id;\r
+ UINT64 QpId;\r
+ WV_IO_SOCKADDR_DATA PeerAddress;\r
+ WV_IO_CONNECT_PARAM Param;\r
+\r
+} WV_IO_EP_CONNECT;\r
+\r
+typedef struct _WV_IO_EP_ACCEPT\r
+{\r
+ UINT64 Id;\r
+ UINT64 QpId;\r
+ WV_IO_CONNECT_PARAM Param;\r
+\r
+} WV_IO_EP_ACCEPT;\r
+\r
+typedef struct _WV_IO_EP_ATTRIBUTES\r
+{\r
+ WV_IO_SOCKADDR_DATA LocalAddress;\r
+ WV_IO_SOCKADDR_DATA PeerAddress;\r
+ WV_IO_DEVICE_ADDRESS Device;\r
+\r
+ union {\r
+ WV_IO_CONNECT_PARAM Connect;\r
+ UINT64 Backlog;\r
+\r
+ } Param;\r
+\r
+\r
+} WV_IO_EP_ATTRIBUTES;\r
\r
#endif // _WV_IOCTL_H_\r
\r
HCA_ENTER(HCA_DBG_QP);\r
\r
+ if (buf_size < sizeof(resp.qp_state)) {\r
+ status = IB_INVALID_PARAMETER;\r
+ goto out;\r
+ }\r
+\r
/* imitate umv_buf */\r
umv_buf.command = TRUE; /* special case for NDI. Usually it's TRUE */\r
umv_buf.input_size = 0;\r
*p_outbuf = resp.qp_state;\r
}\r
\r
+out:\r
HCA_EXIT(HCA_DBG_QP);\r
return status;\r
}\r
\r
HCA_ENTER(HCA_DBG_QP);\r
\r
+ if (buf_size < sizeof(resp.qp_state)) {\r
+ status = IB_INVALID_PARAMETER;\r
+ goto out;\r
+ }\r
+\r
/* imitate umv_buf */\r
umv_buf.command = TRUE; /* special case for NDI. Usually it's TRUE */\r
umv_buf.input_size = 0;\r
*p_outbuf = resp.qp_state;\r
}\r
\r
+out:\r
HCA_EXIT(HCA_DBG_QP);\r
return status;\r
}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+#ifndef _ib_cm_ifc_h_\r
+#define _ib_cm_ifc_h_\r
+\r
+#include <initguid.h>\r
+#include <iba/ib_al_ifc.h>\r
+#include <iba/ib_types.h>\r
+#include <iba/ib_al.h>\r
+\r
+struct _iba_cm_event;\r
+\r
+typedef struct _iba_cm_id\r
+{\r
+ void *context;\r
+ NTSTATUS (*callback)(struct _iba_cm_id *p_id, struct _iba_cm_event *p_event);\r
+ net32_t cid;\r
+\r
+} iba_cm_id;\r
+\r
+typedef struct _iba_cm_req\r
+{\r
+ ib_net64_t service_id;\r
+\r
+ ib_path_rec_t *p_primary_path;\r
+ ib_path_rec_t *p_alt_path;\r
+\r
+ net32_t qpn;\r
+ ib_qp_type_t qp_type;\r
+ net32_t starting_psn;\r
+\r
+ void *p_pdata;\r
+ uint8_t pdata_len;\r
+\r
+ uint8_t max_cm_retries;\r
+ uint8_t resp_res;\r
+ uint8_t init_depth;\r
+ uint8_t remote_resp_timeout;\r
+ uint8_t flow_ctrl;\r
+ uint8_t local_resp_timeout;\r
+ uint8_t rnr_retry_cnt;\r
+ uint8_t retry_cnt;\r
+ uint8_t srq;\r
+\r
+} iba_cm_req;\r
+\r
+typedef struct _iba_cm_req_event\r
+{\r
+ iba_cm_req req;\r
+ net64_t local_ca_guid;\r
+ net64_t remote_ca_guid;\r
+ uint16_t pkey_index;\r
+ uint8_t port_num;\r
+\r
+} iba_cm_req_event;\r
+\r
+typedef struct _iba_cm_rep\r
+{\r
+ net32_t qpn;\r
+ net32_t starting_psn;\r
+\r
+ void *p_pdata;\r
+ uint8_t pdata_len;\r
+\r
+ ib_cm_failover_t failover_accepted;\r
+ uint8_t resp_res;\r
+ uint8_t init_depth;\r
+ uint8_t flow_ctrl;\r
+ uint8_t rnr_retry_cnt;\r
+ uint8_t srq;\r
+\r
+} iba_cm_rep;\r
+\r
+typedef struct _iba_cm_rep_event\r
+{\r
+ iba_cm_rep rep;\r
+ net64_t ca_guid;\r
+ uint8_t target_ack_delay;\r
+\r
+} iba_cm_rep_event;\r
+\r
+typedef struct _iba_cm_pdata\r
+{\r
+ void *p_pdata;\r
+ uint8_t pdata_len;\r
+\r
+} iba_cm_pdata;\r
+typedef iba_cm_pdata iba_cm_rtu_event;\r
+typedef iba_cm_pdata iba_cm_dreq_event;\r
+typedef iba_cm_pdata iba_cm_drep_event;\r
+\r
+typedef struct _iba_cm_rej_event\r
+{\r
+ void *ari;\r
+ void *p_pdata;\r
+ ib_rej_status_t reason;\r
+ uint8_t ari_length;\r
+ uint8_t pdata_len;\r
+ \r
+} iba_cm_rej_event;\r
+\r
+typedef struct _iba_cm_mra_event\r
+{\r
+ void *p_pdata;\r
+ uint8_t pdata_len;\r
+ uint8_t service_timeout;\r
+\r
+} iba_cm_mra_event;\r
+\r
+typedef struct _iba_cm_lap\r
+{\r
+ ib_path_rec_t *p_alt_path;\r
+ void *p_pdata;\r
+ uint8_t pdata_len;\r
+ uint8_t remote_resp_timeout;\r
+\r
+} iba_cm_lap;\r
+typedef iba_cm_lap iba_cm_lap_event;\r
+\r
+typedef struct _iba_cm_apr\r
+{\r
+ void *p_pdata;\r
+ ib_apr_info_t *p_info;\r
+ uint8_t pdata_len;\r
+ uint8_t info_length;\r
+ ib_apr_status_t status;\r
+\r
+} iba_cm_apr;\r
+typedef iba_cm_apr iba_cm_apr_event;\r
+\r
+typedef struct _iba_cm_sidr_req\r
+{\r
+ ib_net64_t service_id;\r
+ ib_path_rec_t *p_path;\r
+ void *p_pdata;\r
+ uint8_t pdata_len;\r
+ uint8_t max_cm_retries;\r
+ uint32_t timeout;\r
+\r
+} iba_cm_sidr_req;\r
+\r
+typedef struct _iba_cm_sidr_req_event\r
+{\r
+ iba_cm_sidr_req sidr_req;\r
+ net64_t ca_guid;\r
+ uint16_t pkey_index;\r
+ uint8_t port_num;\r
+\r
+} iba_cm_sidr_req_event;\r
+\r
+typedef struct _iba_cm_sidr_rep\r
+{\r
+ net32_t qpn;\r
+ net32_t qkey;\r
+ void *p_pdata;\r
+ void *p_info;\r
+ uint8_t pdata_len;\r
+ uint8_t info_len;\r
+ ib_sidr_status_t status;\r
+\r
+} iba_cm_sidr_rep;\r
+typedef iba_cm_sidr_rep iba_cm_sidr_rep_event;\r
+\r
+typedef enum _iba_cm_event_type\r
+{\r
+ iba_cm_req_error,\r
+ iba_cm_req_received,\r
+ iba_cm_rep_error,\r
+ iba_cm_rep_received,\r
+ iba_cm_rtu_received,\r
+ iba_cm_dreq_error,\r
+ iba_cm_dreq_received,\r
+ iba_cm_drep_received,\r
+ iba_cm_rej_received,\r
+ iba_cm_mra_received,\r
+ iba_cm_lap_error,\r
+ iba_cm_lap_received,\r
+ iba_cm_apr_received,\r
+ iba_cm_sidr_req_error,\r
+ iba_cm_sidr_req_received,\r
+ iba_cm_sidr_rep_received\r
+\r
+} iba_cm_event_type;\r
+\r
+typedef struct _iba_cm_event\r
+{\r
+ iba_cm_event_type type;\r
+ union\r
+ {\r
+ iba_cm_req_event req;\r
+ iba_cm_rep_event rep;\r
+ iba_cm_rtu_event rtu;\r
+ iba_cm_dreq_event dreq;\r
+ iba_cm_drep_event drep;\r
+ iba_cm_rej_event rej;\r
+ iba_cm_mra_event mra;\r
+ iba_cm_lap_event lap;\r
+ iba_cm_apr_event apr;\r
+ iba_cm_sidr_req_event sidr_req;\r
+ iba_cm_sidr_rep_event sidr_rep;\r
+\r
+ } data;\r
+\r
+} iba_cm_event;\r
+\r
+typedef struct _iba_cm_interface\r
+{\r
+ NTSTATUS (*create_id)(NTSTATUS (*callback)(iba_cm_id *p_id,\r
+ iba_cm_event *p_event),\r
+ void *context, iba_cm_id **pp_id);\r
+ void (*destroy_id)(iba_cm_id *p_id);\r
+\r
+ NTSTATUS (*listen)(iba_cm_id *p_id, net64_t service_id, void *p_compare_buf,\r
+ uint8_t compare_len, uint8_t compare_offset);\r
+\r
+ NTSTATUS (*send_req)(iba_cm_id *p_id, iba_cm_req *p_req);\r
+ NTSTATUS (*send_rep)(iba_cm_id *p_id, iba_cm_rep *p_rep);\r
+ NTSTATUS (*send_rtu)(iba_cm_id *p_id, void *p_pdata, uint8_t pdata_len);\r
+\r
+ NTSTATUS (*send_dreq)(iba_cm_id *p_id, void *p_pdata, uint8_t pdata_len);\r
+ NTSTATUS (*send_drep)(iba_cm_id *p_id, void *p_pdata, uint8_t pdata_len);\r
+\r
+ NTSTATUS (*send_rej)(iba_cm_id *p_id, ib_rej_status_t status,\r
+ void *p_ari, uint8_t ari_len,\r
+ void *p_pdata, uint8_t pdata_len);\r
+ NTSTATUS (*send_mra)(iba_cm_id *p_id, uint8_t service_timeout,\r
+ void *p_pdata, uint8_t pdata_len);\r
+\r
+ NTSTATUS (*send_lap)(iba_cm_id *p_id, iba_cm_lap *p_lap);\r
+ NTSTATUS (*send_apr)(iba_cm_id *p_id, iba_cm_apr *p_apr);\r
+\r
+ NTSTATUS (*send_sidr_req)(iba_cm_id *p_id, iba_cm_sidr_req *p_req);\r
+ NTSTATUS (*send_sidr_rep)(iba_cm_id *p_id, iba_cm_sidr_rep *p_rep);\r
+\r
+ NTSTATUS (*get_qp_attr)(iba_cm_id *p_id, ib_qp_state_t state,\r
+ ib_qp_mod_t *p_attr);\r
+\r
+ NTSTATUS (*migrate)(iba_cm_id *p_id);\r
+ NTSTATUS (*established)(iba_cm_id *p_id);\r
+\r
+} iba_cm_interface;\r
+\r
+static inline USHORT IbaCmVersion(UINT8 Major, UINT8 Minor)\r
+{\r
+ return ((USHORT) Major << 8) | ((USHORT) Minor);\r
+}\r
+\r
+static inline UINT8 IbaCmVersionMajor(USHORT Version)\r
+{\r
+ return (UINT8) (Version >> 8);\r
+}\r
+\r
+static inline UINT8 IbaCmVersionMinor(USHORT Version)\r
+{\r
+ return (UINT8) Version;\r
+}\r
+\r
+// {EACC1466-BB2D-4478-B5BE-40EDF7EE08AB}\r
+DEFINE_GUID(GUID_INFINIBAND_INTERFACE_CM, 0xeacc1466, 0xbb2d, 0x4478,\r
+ 0xb5, 0xbe, 0x40, 0xed, 0xf7, 0xee, 0x8, 0xab);\r
+\r
+typedef struct _INFINIBAND_INTERFACE_CM\r
+{\r
+ INTERFACE InterfaceHeader;\r
+ iba_cm_interface CM;\r
+\r
+} INFINIBAND_INTERFACE_CM;\r
+\r
+#endif // _ib_cm_ifc_h_
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+#pragma once\r
+\r
+#ifndef _IB_RDMA_CM_H_\r
+#define _IB_RDMA_CM_H_\r
+\r
+#include <ntddk.h>\r
+\r
+#define IB_CMA_VERSION 0x00\r
+\r
+#define IB_CMA_SERVICE_ID 0x0000000001000000\r
+#define IB_CMA_SERVICE_ID_MASK 0xFFFFFFFFFF000000\r
+#define IB_CMA_CM_RESPONSE_TIMEOUT 20\r
+#define IB_CMA_MAX_CM_RETRIES 15\r
+\r
+typedef union _IB_CMA_IP_ADDRESS\r
+{\r
+ UINT8 Ip6Address[16];\r
+ struct {\r
+ UINT32 Pad[3];\r
+ UINT32 Address;\r
+\r
+ } Ip4;\r
+\r
+} IB_CMA_IP_ADDRESS;\r
+\r
+typedef struct _IB_CMA_HEADER\r
+{\r
+ UINT8 CmaVersion;\r
+ UINT8 IpVersion; // IP Version: 7:4\r
+ UINT16 Port;\r
+ IB_CMA_IP_ADDRESS SrcAddress;\r
+ IB_CMA_IP_ADDRESS DstAddress;\r
+\r
+} IB_CMA_HEADER;\r
+\r
+#endif // _IB_RDMA_CM_H_
\ No newline at end of file
#include <initguid.h>\r
\r
#include <winsock2.h>\r
+#include <ws2tcpip.h>\r
#include <unknwn.h>\r
#include <rdma\wvstatus.h>\r
\r
\r
} WV_PORT_ATTRIBUTES;\r
\r
-typedef struct _WV_ADDRESS\r
+typedef struct _WV_DEVICE_ADDRESS\r
{\r
- SOCKET_ADDRESS Address;\r
- NET64 DeviceGuid;\r
- NET16 Pkey;\r
- UINT8 PortNumber;\r
-\r
-} WV_ADDRESS;\r
-\r
-typedef struct _WV_ADDRESS_LIST\r
-{\r
- SIZE_T Count;\r
- WV_ADDRESS Address[1];\r
+ NET64 DeviceGuid;\r
+ NET16 Pkey;\r
+ UINT8 PortNumber;\r
\r
-} WV_ADDRESS_LIST;\r
+} WV_DEVICE_ADDRESS;\r
\r
// Port notification flags\r
#define WV_EVENT_ERROR 0x00000001\r
\r
#define WV_CM_UDP_QKEY 0x01234567\r
\r
-#pragma warning(push)\r
-#pragma warning(disable: 4200)\r
typedef struct _WV_CONNECT_PARAM\r
{\r
SIZE_T DataLength;\r
UINT8 RetryCount; // Ignored when accepting\r
UINT8 RnrRetryCount;\r
UINT8 Reserved[2];\r
- UINT8 Data[];\r
+ UINT8 Data[56];\r
\r
} WV_CONNECT_PARAM;\r
\r
WV_ADDRESS_VECTOR AddressVector;\r
NET32 Qpn;\r
NET32 Qkey;\r
- UINT8 Data[];\r
+ UINT8 Data[56];\r
\r
} WV_DATAGRAM_PARAM;\r
-#pragma warning(pop)\r
+\r
+typedef union _WV_SOCKADDR\r
+{\r
+ SOCKADDR Sa;\r
+ SOCKADDR_IN Sin;\r
+ SOCKADDR_IN6 Sin6;\r
+\r
+} WV_SOCKADDR;\r
\r
typedef struct _WV_CONNECT_ATTRIBUTES\r
{\r
- WV_ADDRESS LocalAddress;\r
- SOCKET_ADDRESS PeerAddress;\r
+ WV_SOCKADDR LocalAddress;\r
+ WV_SOCKADDR PeerAddress;\r
+ WV_DEVICE_ADDRESS Device;\r
WV_CONNECT_PARAM Param;\r
\r
} WV_CONNECT_ATTRIBUTES;\r
\r
typedef struct _WV_DATAGRAM_ATTRIBUTES\r
{\r
- WV_ADDRESS LocalAddress;\r
- SOCKET_ADDRESS PeerAddress; // Specify when querying\r
+ WV_SOCKADDR LocalAddress;\r
+ WV_SOCKADDR PeerAddress; // Specify when querying\r
+ WV_DEVICE_ADDRESS Device;\r
WV_DATAGRAM_PARAM Param;\r
\r
} WV_DATAGRAM_ATTRIBUTES;\r
\r
+// Endpoint options\r
+#define WV_EP_OPTION_ROUTE 0x00000001\r
+\r
#undef INTERFACE\r
#define INTERFACE IWVOverlapped\r
// {64687592-aa67-4b55-bc4b-e189bdd2fc4f}\r
) PURE;\r
\r
// IWVEndpoint methods\r
+ STDMETHOD(Modify)(\r
+ THIS_\r
+ __in DWORD Option,\r
+ __in_bcount_opt(OptionLength) const VOID* pOptionData,\r
+ __in SIZE_T OptionLength\r
+ ) PURE;\r
+\r
STDMETHOD(BindAddress)(\r
THIS_\r
- __in const struct sockaddr* pAddress\r
+ __in SOCKADDR* pAddress\r
+ ) PURE;\r
+\r
+ STDMETHOD(Listen)(\r
+ THIS_\r
+ __in SIZE_T Backlog\r
) PURE;\r
\r
STDMETHOD(Reject)(\r
THIS_\r
- __in_bcount_opt(PrivateDataLength) const VOID* pPrivateData,\r
- __in SIZE_T PrivateDataLength\r
+ __in_bcount_opt(UserDataLength) const VOID* pUserData,\r
+ __in SIZE_T UserDataLength\r
) PURE;\r
};\r
\r
) PURE;\r
\r
// IWVEndpoint methods\r
+ __override STDMETHOD(Modify)(\r
+ THIS_\r
+ __in DWORD Option,\r
+ __in_bcount_opt(OptionLength) const VOID* pOptionData,\r
+ __in SIZE_T OptionLength\r
+ ) PURE;\r
+\r
__override STDMETHOD(BindAddress)(\r
THIS_\r
- __in const struct sockaddr* pAddress\r
+ __in SOCKADDR* pAddress\r
+ ) PURE;\r
+\r
+ __override STDMETHOD(Listen)(\r
+ THIS_\r
+ __in SIZE_T Backlog\r
) PURE;\r
\r
__override STDMETHOD(Reject)(\r
THIS_\r
- __in_bcount_opt(PrivateDataLength) const VOID* pPrivateData,\r
- __in SIZE_T PrivateDataLength\r
+ __in_bcount_opt(UserDataLength) const VOID* pUserData,\r
+ __in SIZE_T UserDataLength\r
) PURE;\r
\r
// IWVConnectEndpoint methods\r
+ STDMETHOD(GetRequest)(\r
+ THIS_\r
+ __in IWVConnectEndpoint* pEndpoint,\r
+ __in_opt OVERLAPPED* pOverlapped\r
+ ) PURE;\r
+\r
STDMETHOD(Connect)(\r
THIS_\r
__in IWVConnectQueuePair* pQp,\r
+ __in const SOCKADDR* pAddress,\r
__in WV_CONNECT_PARAM* pParam,\r
__in_opt OVERLAPPED* pOverlapped\r
) PURE;\r
) PURE;\r
\r
STDMETHOD(Disconnect)(\r
- THIS_\r
- __in_opt OVERLAPPED* pOverlapped\r
+ THIS\r
) PURE;\r
\r
STDMETHOD(NotifyDisconnect)(\r
) PURE;\r
\r
// IWVEndpoint methods\r
+ __override STDMETHOD(Modify)(\r
+ THIS_\r
+ __in DWORD Option,\r
+ __in_bcount_opt(OptionLength) const VOID* pOptionData,\r
+ __in SIZE_T OptionLength\r
+ ) PURE;\r
+\r
__override STDMETHOD(BindAddress)(\r
THIS_\r
- __in const struct sockaddr* pAddress\r
+ __in SOCKADDR* pAddress\r
+ ) PURE;\r
+\r
+ __override STDMETHOD(Listen)(\r
+ THIS_\r
+ __in SIZE_T Backlog\r
) PURE;\r
\r
__override STDMETHOD(Reject)(\r
THIS_\r
- __in_bcount_opt(PrivateDataLength) const VOID* pPrivateData,\r
- __in SIZE_T PrivateDataLength\r
+ __in_bcount_opt(UserDataLength) const VOID* pUserData,\r
+ __in SIZE_T UserDataLength\r
) PURE;\r
\r
// IWVDatagramEndpoint methods\r
+ STDMETHOD(GetRequest)(\r
+ THIS_\r
+ __in IWVDatagramEndpoint* pEndpoint,\r
+ __in_opt OVERLAPPED* pOverlapped\r
+ ) PURE;\r
+\r
STDMETHOD(Lookup)(\r
THIS_\r
- __in const struct sockaddr* pAddress,\r
- __in_bcount_opt(PrivateDataLength) const VOID* pPrivateData,\r
- __in SIZE_T PrivateDataLength,\r
+ __in const SOCKADDR* pAddress,\r
+ __in_bcount_opt(UserDataLength) const VOID* pUserData,\r
+ __in SIZE_T UserDataLength,\r
__in_opt OVERLAPPED* pOverlapped\r
) PURE;\r
\r
\r
STDMETHOD(JoinMulticast)(\r
THIS_\r
- __in const struct sockaddr* pAddress,\r
+ __in const SOCKADDR* pAddress,\r
__in_opt OVERLAPPED* pOverlapped\r
) PURE;\r
\r
STDMETHOD(LeaveMulticast)(\r
THIS_\r
- __in const struct sockaddr* pAddress,\r
+ __in const SOCKADDR* pAddress,\r
__in_opt OVERLAPPED* pOverlapped\r
) PURE;\r
\r
};\r
\r
\r
-#undef INTERFACE\r
-#define INTERFACE IWVListen\r
-// {5b839fd4-7410-441f-a2d9-5d75b1d8599b}\r
-DEFINE_GUID(IID_IWVListen, 0x5b839fd4, 0x7410, 0x441f,\r
- 0xa2, 0xd9, 0x5d, 0x75, 0xb1, 0xd8, 0x59, 0x9b);\r
-\r
-DECLARE_INTERFACE_(IWVListen, IWVOverlapped)\r
-{\r
- // IUnknown methods\r
- __override STDMETHOD(QueryInterface)(\r
- THIS_\r
- REFIID riid,\r
- LPVOID FAR* ppvObj\r
- ) PURE;\r
-\r
- __override STDMETHOD_(ULONG,AddRef)(\r
- THIS\r
- ) PURE;\r
-\r
- __override STDMETHOD_(ULONG,Release)(\r
- THIS\r
- ) PURE;\r
-\r
- // IWVOverlapped methods\r
- __override STDMETHOD(CancelOverlappedRequests)(\r
- THIS\r
- ) PURE;\r
-\r
- __override STDMETHOD(GetOverlappedResult)(\r
- THIS_\r
- __inout_opt OVERLAPPED *pOverlapped,\r
- __out DWORD *pNumberOfBytesTransferred,\r
- __in BOOL bWait\r
- ) PURE;\r
-\r
- // IWVListen methods\r
- STDMETHOD(GetRequest)(\r
- THIS_\r
- __in IWVEndpoint* pEndpoint,\r
- __in_opt OVERLAPPED* pOverlapped\r
- ) PURE;\r
-};\r
-\r
-\r
#undef INTERFACE\r
#define INTERFACE IWVDevice\r
// {244af78c-b1ac-40e4-9896-271d58d591b8}\r
__out WV_GID* pGid\r
) PURE;\r
\r
+ STDMETHOD(FindGid)(\r
+ THIS_\r
+ __in UINT8 PortNumber,\r
+ __in WV_GID* pGid,\r
+ __out DWORD* pIndex\r
+ ) PURE;\r
+\r
STDMETHOD(QueryPkey)(\r
THIS_\r
__in UINT8 PortNumber,\r
__out NET16* pPkey\r
) PURE;\r
\r
+ STDMETHOD(FindPkey)(\r
+ THIS_\r
+ __in UINT8 PortNumber,\r
+ __in NET16 Pkey,\r
+ __out DWORD* pIndex\r
+ ) PURE;\r
+\r
STDMETHOD(CreateCompletionQueue)(\r
THIS_\r
__inout SIZE_T *pEntries,\r
\r
#undef INTERFACE\r
#define INTERFACE IWVProvider\r
-// {6901010c-17af-4894-a1dc-794d3611f262}\r
-DEFINE_GUID(IID_IWVProvider, 0x6901010c, 0x17af, 0x4894,\r
- 0xa1, 0xdc, 0x79, 0x4d, 0x36, 0x11, 0xf2, 0x62);\r
+// {060E95D6-EC54-43b2-83FC-B578FD037259}\r
+DEFINE_GUID(IID_IWVProvider, 0x60e95d6, 0xec54, 0x43b2,\r
+ 0x83, 0xfc, 0xb5, 0x78, 0xfd, 0x3, 0x72, 0x59);\r
\r
DECLARE_INTERFACE_(IWVProvider, IUnknown)\r
{\r
__out WV_DEVICE_ATTRIBUTES* pAttributes\r
) PURE;\r
\r
- STDMETHOD(QueryAddressList)(\r
+ STDMETHOD(TranslateAddress)(\r
THIS_\r
- __inout_bcount_part_opt(*pBufferSize, *pBufferSize) WV_ADDRESS_LIST* pAddressList,\r
- __inout SIZE_T* pBufferSize\r
+ __in SOCKADDR* pAddress,\r
+ __out WV_DEVICE_ADDRESS* pDeviceAddress\r
) PURE;\r
\r
STDMETHOD(OpenDevice)(\r
THIS_\r
__deref_out IWVDatagramEndpoint** ppDatagramEndpoint\r
) PURE;\r
-\r
- STDMETHOD(CreateListen)(\r
- THIS_\r
- __in const struct sockaddr* pAddress,\r
- __in SIZE_T Backlog,\r
- __deref_out IWVListen** ppListen\r
- ) PURE;\r
};\r
\r
__declspec(dllexport) HRESULT WvGetObject(REFIID riid, LPVOID FAR* ppvObj);\r
SOURCES = \\r
wv_main.cpp \\r
wv_device.cpp \\r
- wv_listen.cpp \\r
wv_connect.cpp \\r
wv_datagram.cpp \\r
wv_pd.cpp \\r
cout << "<interface> is one of the following:" << endl;\r
cout << "\t" << "provider" << endl;\r
cout << "\t" << "device" << endl;\r
- cout << "\t" << "listen" << endl;\r
cout << "\t" << "connect" << endl;\r
cout << "\t" << "datagram" << endl;\r
cout << "\t" << "pd" << endl;\r
hr = ProviderTest(argc - 1, &argv[1]);\r
} else if (strcmp("device", argv[1]) == 0) {\r
hr = DeviceTest(argc - 1, &argv[1]);\r
- } else if (strcmp("listen", argv[1]) == 0) {\r
- hr = ListenTest(argc - 1, &argv[1]);\r
} else if (strcmp("connect", argv[1]) == 0) {\r
hr = ConnectTest(argc - 1, &argv[1]);\r
} else if (strcmp("datagram", argv[1]) == 0) {\r
DIRS=\\r
- coinstaller \\r
- wsdinstall \\r
- vstat \\r
- nsc \\r
- perftests \\r
+ coinstaller \\r
+ wsdinstall \\r
+ vstat \\r
+ nsc \\r
+ perftests \\r
+ infiniband_diags \\r
part_man\r
wsd \\r
qlgcvnic \\r
libibverbs \\r
+ libibumad \\r
+ libibmad \\r
nd\r
!endif\r
\r
DLLENTRY = DllMain\r
-USE_NTDLL = 1\r
+USE_MSVCRT=1\r
\r
SOURCES = \\r
ibverbs.rc \\r
uint8_t event_port_index;\r
};\r
\r
+__declspec(dllexport)\r
+IWVProvider *ibv_get_winverbs(void)\r
+{\r
+ HRESULT hr;\r
+\r
+ if (prov == NULL) {\r
+ hr = WvGetObject(IID_IWVProvider, (LPVOID*) &prov);\r
+ if (FAILED(hr)) {\r
+ return NULL;\r
+ }\r
+ }\r
+\r
+ prov->AddRef();\r
+ return prov;\r
+}\r
+\r
__declspec(dllexport)\r
struct ibv_device **ibv_get_device_list(int *num)\r
{\r
vchan->count--;\r
vchan->cq[cq->channel_index] = vchan->cq[vchan->count];\r
vchan->event[cq->channel_index] = vchan->event[vchan->count];\r
+ vchan->cq[cq->channel_index]->channel_index = cq->channel_index;\r
LeaveCriticalSection(&vchan->lock);\r
}\r
\r
--- /dev/null
+Sean Hefty <sean.hefty@intel.com>\r
--- /dev/null
+Copyright (c) 2008 Intel Corporation. All rights reserved.\r
+\r
+This software is available to you under the OpenFabrics.org BSD license\r
+below:\r
+\r
+ Redistribution and use in source and binary forms, with or\r
+ without modification, are permitted provided that the following\r
+ conditions are met:\r
+\r
+ - Redistributions of source code must retain the above\r
+ copyright notice, this list of conditions and the following\r
+ disclaimer.\r
+\r
+ - Redistributions in binary form must reproduce the above\r
+ copyright notice, this list of conditions and the following\r
+ disclaimer in the documentation and/or other materials\r
+ provided with the distribution.\r
+\r
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV\r
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+SOFTWARE.\r
--- /dev/null
+DIRS = \\r
+ src \\r
+ examples\r
--- /dev/null
+TARGETNAME = rdma_cmatose\r
+TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR)\r
+TARGETTYPE = PROGRAM\r
+\r
+UMTYPE = console\r
+UMENTRY = main\r
+\r
+USE_MSVCRT = 1\r
+USE_STL = 1\r
+USE_NATIVE_EH = 1\r
+USE_IOSTREAM = 1\r
+\r
+SOURCES = cmatose.c\r
+ \r
+INCLUDES = ..;..\..\include;..\..\..\..\inc;..\..\..\..\inc\user;..\..\..\libibverbs\include;\r
+\r
+TARGETLIBS = \\r
+ $(SDK_LIB_PATH)\kernel32.lib \\r
+ $(SDK_LIB_PATH)\advapi32.lib \\r
+ $(SDK_LIB_PATH)\user32.lib \\r
+ $(SDK_LIB_PATH)\ole32.lib \\r
+ $(SDK_LIB_PATH)\ws2_32.lib \\r
+!if $(FREEBUILD)\r
+ $(TARGETPATH)\*\libibverbs.lib \\r
+ $(TARGETPATH)\*\librdmacm.lib\r
+!else\r
+ $(TARGETPATH)\*\libibverbsd.lib \\r
+ $(TARGETPATH)\*\librdmacmd.lib\r
+!endif\r
+\r
--- /dev/null
+/*\r
+ * Copyright (c) 2005-2009 Intel Corporation. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <ws2tcpip.h>\r
+#include <winsock2.h>\r
+#include <time.h>\r
+\r
+#include "..\..\..\..\etc\user\getopt.c"\r
+#include <rdma/rdma_cma.h>\r
+\r
+struct cmatest_node {\r
+ int id;\r
+ struct rdma_cm_id *cma_id;\r
+ int connected;\r
+ struct ibv_pd *pd;\r
+ struct ibv_cq *cq;\r
+ struct ibv_mr *mr;\r
+ void *mem;\r
+};\r
+\r
+struct cmatest {\r
+ struct rdma_event_channel *channel;\r
+ struct cmatest_node *nodes;\r
+ int conn_index;\r
+ int connects_left;\r
+ int disconnects_left;\r
+\r
+ struct sockaddr_in dst_in;\r
+ struct sockaddr *dst_addr;\r
+ struct sockaddr_in src_in;\r
+ struct sockaddr *src_addr;\r
+};\r
+\r
+static struct cmatest test;\r
+static int connections = 1;\r
+static int message_size = 100;\r
+static int message_count = 10;\r
+static uint16_t port = 7471;\r
+static uint8_t set_tos = 0;\r
+static uint8_t tos;\r
+static uint8_t migrate = 0;\r
+static char *dst_addr;\r
+static char *src_addr;\r
+\r
+static int create_message(struct cmatest_node *node)\r
+{\r
+ if (!message_size)\r
+ message_count = 0;\r
+\r
+ if (!message_count)\r
+ return 0;\r
+\r
+ node->mem = malloc(message_size);\r
+ if (!node->mem) {\r
+ printf("failed message allocation\n");\r
+ return -1;\r
+ }\r
+ node->mr = ibv_reg_mr(node->pd, node->mem, message_size,\r
+ IBV_ACCESS_LOCAL_WRITE);\r
+ if (!node->mr) {\r
+ printf("failed to reg MR\n");\r
+ goto err;\r
+ }\r
+ return 0;\r
+err:\r
+ free(node->mem);\r
+ return -1;\r
+}\r
+\r
+static int init_node(struct cmatest_node *node)\r
+{\r
+ struct ibv_qp_init_attr init_qp_attr;\r
+ int cqe, ret;\r
+\r
+ node->pd = ibv_alloc_pd(node->cma_id->verbs);\r
+ if (!node->pd) {\r
+ ret = -1;\r
+ printf("cmatose: unable to allocate PD\n");\r
+ goto out;\r
+ }\r
+\r
+ cqe = message_count ? message_count * 2 : 2;\r
+ node->cq = ibv_create_cq(node->cma_id->verbs, cqe, node, 0, 0);\r
+ if (!node->cq) {\r
+ ret = -1;\r
+ printf("cmatose: unable to create CQ\n");\r
+ goto out;\r
+ }\r
+\r
+ memset(&init_qp_attr, 0, sizeof init_qp_attr);\r
+ init_qp_attr.cap.max_send_wr = message_count ? message_count : 1;\r
+ init_qp_attr.cap.max_recv_wr = message_count ? message_count : 1;\r
+ init_qp_attr.cap.max_send_sge = 1;\r
+ init_qp_attr.cap.max_recv_sge = 1;\r
+ init_qp_attr.qp_context = node;\r
+ init_qp_attr.sq_sig_all = 1;\r
+ init_qp_attr.qp_type = IBV_QPT_RC;\r
+ init_qp_attr.send_cq = node->cq;\r
+ init_qp_attr.recv_cq = node->cq;\r
+ ret = rdma_create_qp(node->cma_id, node->pd, &init_qp_attr);\r
+ if (ret) {\r
+ printf("cmatose: unable to create QP: 0x%x\n", ret);\r
+ goto out;\r
+ }\r
+\r
+ ret = create_message(node);\r
+ if (ret) {\r
+ printf("cmatose: failed to create messages: 0x%x\n", ret);\r
+ goto out;\r
+ }\r
+out:\r
+ return ret;\r
+}\r
+\r
+static int post_recvs(struct cmatest_node *node)\r
+{\r
+ struct ibv_recv_wr recv_wr, *recv_failure;\r
+ struct ibv_sge sge;\r
+ int i, ret = 0;\r
+\r
+ if (!message_count)\r
+ return 0;\r
+\r
+ recv_wr.next = NULL;\r
+ recv_wr.sg_list = &sge;\r
+ recv_wr.num_sge = 1;\r
+ recv_wr.wr_id = (uintptr_t) node;\r
+\r
+ sge.length = message_size;\r
+ sge.lkey = node->mr->lkey;\r
+ sge.addr = (uintptr_t) node->mem;\r
+\r
+ for (i = 0; i < message_count && !ret; i++ ) {\r
+ ret = ibv_post_recv(node->cma_id->qp, &recv_wr, &recv_failure);\r
+ if (ret) {\r
+ printf("failed to post receives: 0x%x\n", ret);\r
+ break;\r
+ }\r
+ }\r
+ return ret;\r
+}\r
+\r
+static int post_sends(struct cmatest_node *node)\r
+{\r
+ struct ibv_send_wr send_wr, *bad_send_wr;\r
+ struct ibv_sge sge;\r
+ int i, ret = 0;\r
+\r
+ if (!node->connected || !message_count)\r
+ return 0;\r
+\r
+ send_wr.next = NULL;\r
+ send_wr.sg_list = &sge;\r
+ send_wr.num_sge = 1;\r
+ send_wr.opcode = IBV_WR_SEND;\r
+ send_wr.send_flags = 0;\r
+ send_wr.wr_id = (ULONG_PTR) node;\r
+\r
+ sge.length = message_size;\r
+ sge.lkey = node->mr->lkey;\r
+ sge.addr = (uintptr_t) node->mem;\r
+\r
+ for (i = 0; i < message_count && !ret; i++) {\r
+ ret = ibv_post_send(node->cma_id->qp, &send_wr, &bad_send_wr);\r
+ if (ret) \r
+ printf("failed to post sends: 0x%x\n", ret);\r
+ }\r
+ return ret;\r
+}\r
+\r
+static void connect_error(void)\r
+{\r
+ test.disconnects_left--;\r
+ test.connects_left--;\r
+}\r
+\r
+static int addr_handler(struct cmatest_node *node)\r
+{\r
+ int ret;\r
+\r
+ if (set_tos) {\r
+ ret = rdma_set_option(node->cma_id, RDMA_OPTION_ID,\r
+ RDMA_OPTION_ID_TOS, &tos, sizeof tos);\r
+ if (ret)\r
+ printf("cmatose: set TOS option failed: 0x%x\n", ret);\r
+ }\r
+\r
+ ret = rdma_resolve_route(node->cma_id, 2000);\r
+ if (ret) {\r
+ printf("cmatose: resolve route failed: 0x%x\n", ret);\r
+ connect_error();\r
+ }\r
+ return ret;\r
+}\r
+\r
+static int route_handler(struct cmatest_node *node)\r
+{\r
+ struct rdma_conn_param conn_param;\r
+ int ret;\r
+\r
+ ret = init_node(node);\r
+ if (ret)\r
+ goto err;\r
+\r
+ ret = post_recvs(node);\r
+ if (ret)\r
+ goto err;\r
+\r
+ memset(&conn_param, 0, sizeof conn_param);\r
+ conn_param.responder_resources = 1;\r
+ conn_param.initiator_depth = 1;\r
+ conn_param.retry_count = 5;\r
+ ret = rdma_connect(node->cma_id, &conn_param);\r
+ if (ret) {\r
+ printf("cmatose: failure connecting: 0x%x\n", ret);\r
+ goto err;\r
+ }\r
+ return 0;\r
+err:\r
+ connect_error();\r
+ return ret;\r
+}\r
+\r
+static int connect_handler(struct rdma_cm_id *cma_id)\r
+{\r
+ struct cmatest_node *node;\r
+ struct rdma_conn_param conn_param;\r
+ int ret;\r
+\r
+ if (test.conn_index == connections) {\r
+ ret = -1;\r
+ goto err1;\r
+ }\r
+ node = &test.nodes[test.conn_index++];\r
+\r
+ node->cma_id = cma_id;\r
+ cma_id->context = node;\r
+\r
+ ret = init_node(node);\r
+ if (ret)\r
+ goto err2;\r
+\r
+ ret = post_recvs(node);\r
+ if (ret)\r
+ goto err2;\r
+\r
+ memset(&conn_param, 0, sizeof conn_param);\r
+ conn_param.responder_resources = 1;\r
+ conn_param.initiator_depth = 1;\r
+ ret = rdma_accept(node->cma_id, &conn_param);\r
+ if (ret) {\r
+ printf("cmatose: failure accepting: 0x%x\n", ret);\r
+ goto err2;\r
+ }\r
+ return 0;\r
+\r
+err2:\r
+ node->cma_id = NULL;\r
+ connect_error();\r
+err1:\r
+ printf("cmatose: failing connection request\n");\r
+ rdma_reject(cma_id, NULL, 0);\r
+ return ret;\r
+}\r
+\r
+static int cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)\r
+{\r
+ int ret = 0;\r
+\r
+ switch (event->event) {\r
+ case RDMA_CM_EVENT_ADDR_RESOLVED:\r
+ ret = addr_handler(cma_id->context);\r
+ break;\r
+ case RDMA_CM_EVENT_ROUTE_RESOLVED:\r
+ ret = route_handler(cma_id->context);\r
+ break;\r
+ case RDMA_CM_EVENT_CONNECT_REQUEST:\r
+ ret = connect_handler(cma_id);\r
+ break;\r
+ case RDMA_CM_EVENT_ESTABLISHED:\r
+ ((struct cmatest_node *) cma_id->context)->connected = 1;\r
+ test.connects_left--;\r
+ break;\r
+ case RDMA_CM_EVENT_ADDR_ERROR:\r
+ case RDMA_CM_EVENT_ROUTE_ERROR:\r
+ case RDMA_CM_EVENT_CONNECT_ERROR:\r
+ case RDMA_CM_EVENT_UNREACHABLE:\r
+ case RDMA_CM_EVENT_REJECTED:\r
+ printf("cmatose: event: %s, error: 0x%x\n",\r
+ rdma_event_str(event->event), event->status);\r
+ connect_error();\r
+ break;\r
+ case RDMA_CM_EVENT_DISCONNECTED:\r
+ rdma_disconnect(cma_id);\r
+ test.disconnects_left--;\r
+ break;\r
+ case RDMA_CM_EVENT_DEVICE_REMOVAL:\r
+ /* Cleanup will occur after test completes. */\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ return ret;\r
+}\r
+\r
+static void destroy_node(struct cmatest_node *node)\r
+{\r
+ if (!node->cma_id)\r
+ return;\r
+\r
+ if (node->cma_id->qp)\r
+ rdma_destroy_qp(node->cma_id);\r
+\r
+ if (node->cq)\r
+ ibv_destroy_cq(node->cq);\r
+\r
+ if (node->mem) {\r
+ ibv_dereg_mr(node->mr);\r
+ free(node->mem);\r
+ }\r
+\r
+ if (node->pd)\r
+ ibv_dealloc_pd(node->pd);\r
+\r
+ /* Destroy the RDMA ID after all device resources */\r
+ rdma_destroy_id(node->cma_id);\r
+}\r
+\r
+static int alloc_nodes(void)\r
+{\r
+ int ret, i;\r
+\r
+ test.nodes = malloc(sizeof *test.nodes * connections);\r
+ if (!test.nodes) {\r
+ printf("cmatose: unable to allocate memory for test nodes\n");\r
+ return -1;\r
+ }\r
+ memset(test.nodes, 0, sizeof *test.nodes * connections);\r
+\r
+ for (i = 0; i < connections; i++) {\r
+ test.nodes[i].id = i;\r
+ if (dst_addr) {\r
+ ret = rdma_create_id(test.channel,\r
+ &test.nodes[i].cma_id,\r
+ &test.nodes[i], RDMA_PS_TCP);\r
+ if (ret)\r
+ goto err;\r
+ }\r
+ }\r
+ return 0;\r
+err:\r
+ while (--i >= 0)\r
+ rdma_destroy_id(test.nodes[i].cma_id);\r
+ free(test.nodes);\r
+ return ret;\r
+}\r
+\r
+static void destroy_nodes(void)\r
+{\r
+ int i;\r
+\r
+ for (i = 0; i < connections; i++)\r
+ destroy_node(&test.nodes[i]);\r
+ free(test.nodes);\r
+}\r
+\r
+static int poll_cqs(void)\r
+{\r
+ struct ibv_wc wc[8];\r
+ int done, i, ret;\r
+\r
+ for (i = 0; i < connections; i++) {\r
+ if (!test.nodes[i].connected)\r
+ continue;\r
+\r
+ for (done = 0; done < message_count; done += ret) {\r
+ ret = ibv_poll_cq(test.nodes[i].cq, 8, wc);\r
+ if (ret < 0) {\r
+ printf("cmatose: failed polling CQ: 0x%x\n", ret);\r
+ return ret;\r
+ }\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+\r
+static int connect_events(void)\r
+{\r
+ struct rdma_cm_event *event;\r
+ int err = 0, ret = 0;\r
+\r
+ while (test.connects_left && !err) {\r
+ err = rdma_get_cm_event(test.channel, &event);\r
+ if (!err) {\r
+ cma_handler(event->id, event);\r
+ rdma_ack_cm_event(event);\r
+ } else {\r
+ printf("cmatose: failure in rdma_get_cm_event in connect events\n");\r
+ ret = err;\r
+ }\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+static int disconnect_events(void)\r
+{\r
+ struct rdma_cm_event *event;\r
+ int err = 0, ret = 0;\r
+\r
+ while (test.disconnects_left && !err) {\r
+ err = rdma_get_cm_event(test.channel, &event);\r
+ if (!err) {\r
+ cma_handler(event->id, event);\r
+ rdma_ack_cm_event(event);\r
+ } else {\r
+ printf("cmatose: failure in rdma_get_cm_event in disconnect events\n");\r
+ ret = err;\r
+ }\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+static int migrate_channel(struct rdma_cm_id *listen_id)\r
+{\r
+ struct rdma_event_channel *channel;\r
+ int i, ret;\r
+\r
+ printf("migrating to new event channel\n");\r
+\r
+ channel = rdma_create_event_channel();\r
+ if (!channel) {\r
+ printf("cmatose: failed to create event channel\n");\r
+ return -1;\r
+ }\r
+\r
+ ret = 0;\r
+ if (listen_id)\r
+ ret = rdma_migrate_id(listen_id, channel);\r
+\r
+ for (i = 0; i < connections && !ret; i++)\r
+ ret = rdma_migrate_id(test.nodes[i].cma_id, channel);\r
+\r
+ if (!ret) {\r
+ rdma_destroy_event_channel(test.channel);\r
+ test.channel = channel;\r
+ } else\r
+ printf("cmatose: failure migrating to channel: 0x%x\n", ret);\r
+\r
+ return ret;\r
+}\r
+\r
+static int get_addr(char *dst, struct sockaddr_in *addr)\r
+{\r
+ struct addrinfo *res;\r
+ int ret;\r
+\r
+ ret = getaddrinfo(dst, NULL, NULL, &res);\r
+ if (ret) {\r
+ printf("getaddrinfo failed - invalid hostname or IP address\n");\r
+ return ret;\r
+ }\r
+\r
+ if (res->ai_family != PF_INET) {\r
+ ret = -1;\r
+ goto out;\r
+ }\r
+\r
+ *addr = *(struct sockaddr_in *) res->ai_addr;\r
+out:\r
+ freeaddrinfo(res);\r
+ return ret;\r
+}\r
+\r
+static int run_server(void)\r
+{\r
+ struct rdma_cm_id *listen_id;\r
+ int i, ret;\r
+\r
+ printf("cmatose: starting server\n");\r
+ ret = rdma_create_id(test.channel, &listen_id, &test, RDMA_PS_TCP);\r
+ if (ret) {\r
+ printf("cmatose: listen request failed\n");\r
+ return ret;\r
+ }\r
+\r
+ if (src_addr) {\r
+ ret = get_addr(src_addr, &test.src_in);\r
+ if (ret)\r
+ goto out;\r
+ } else\r
+ test.src_in.sin_family = PF_INET;\r
+\r
+ test.src_in.sin_port = port;\r
+ ret = rdma_bind_addr(listen_id, test.src_addr);\r
+ if (ret) {\r
+ printf("cmatose: bind address failed: 0x%x\n", ret);\r
+ goto out;\r
+ }\r
+\r
+ ret = rdma_listen(listen_id, 0);\r
+ if (ret) {\r
+ printf("cmatose: failure trying to listen: 0x%x\n", ret);\r
+ goto out;\r
+ }\r
+\r
+ ret = connect_events();\r
+ if (ret)\r
+ goto out;\r
+\r
+ if (message_count) {\r
+ printf("initiating data transfers\n");\r
+ for (i = 0; i < connections; i++) {\r
+ ret = post_sends(&test.nodes[i]);\r
+ if (ret)\r
+ goto out;\r
+ }\r
+\r
+ printf("completing sends\n");\r
+ ret = poll_cqs();\r
+ if (ret)\r
+ goto out;\r
+\r
+ printf("receiving data transfers\n");\r
+ ret = poll_cqs();\r
+ if (ret)\r
+ goto out;\r
+ printf("data transfers complete\n");\r
+\r
+ }\r
+\r
+ if (migrate) {\r
+ ret = migrate_channel(listen_id);\r
+ if (ret)\r
+ goto out;\r
+ }\r
+\r
+ printf("cmatose: disconnecting\n");\r
+ for (i = 0; i < connections; i++) {\r
+ if (!test.nodes[i].connected)\r
+ continue;\r
+\r
+ test.nodes[i].connected = 0;\r
+ rdma_disconnect(test.nodes[i].cma_id);\r
+ }\r
+\r
+ ret = disconnect_events();\r
+\r
+ printf("disconnected\n");\r
+\r
+out:\r
+ rdma_destroy_id(listen_id);\r
+ return ret;\r
+}\r
+\r
+static int run_client(void)\r
+{\r
+ int i, ret, ret2;\r
+\r
+ printf("cmatose: starting client\n");\r
+ if (src_addr) {\r
+ ret = get_addr(src_addr, &test.src_in);\r
+ if (ret)\r
+ return ret;\r
+ }\r
+\r
+ ret = get_addr(dst_addr, &test.dst_in);\r
+ if (ret)\r
+ return ret;\r
+\r
+ test.dst_in.sin_port = port;\r
+\r
+ printf("cmatose: connecting\n");\r
+ for (i = 0; i < connections; i++) {\r
+ ret = rdma_resolve_addr(test.nodes[i].cma_id,\r
+ src_addr ? test.src_addr : NULL,\r
+ test.dst_addr, 2000);\r
+ if (ret) {\r
+ printf("cmatose: failure getting addr: 0x%x\n", ret);\r
+ connect_error();\r
+ return ret;\r
+ }\r
+ }\r
+\r
+ ret = connect_events();\r
+ if (ret)\r
+ goto disc;\r
+\r
+ if (message_count) {\r
+ printf("receiving data transfers\n");\r
+ ret = poll_cqs();\r
+ if (ret)\r
+ goto disc;\r
+\r
+ printf("sending replies\n");\r
+ for (i = 0; i < connections; i++) {\r
+ ret = post_sends(&test.nodes[i]);\r
+ if (ret)\r
+ goto disc;\r
+ }\r
+\r
+ printf("data transfers complete\n");\r
+ }\r
+\r
+ ret = 0;\r
+\r
+ if (migrate) {\r
+ ret = migrate_channel(NULL);\r
+ if (ret)\r
+ goto out;\r
+ }\r
+disc:\r
+ ret2 = disconnect_events();\r
+ if (ret2)\r
+ ret = ret2;\r
+out:\r
+ return ret;\r
+}\r
+\r
+int main(int argc, char **argv)\r
+{\r
+ int op, ret;\r
+\r
+ while ((op = getopt(argc, argv, "s:b:c:C:S:t:p:m")) != -1) {\r
+ switch (op) {\r
+ case 's':\r
+ dst_addr = optarg;\r
+ break;\r
+ case 'b':\r
+ src_addr = optarg;\r
+ break;\r
+ case 'c':\r
+ connections = atoi(optarg);\r
+ break;\r
+ case 'C':\r
+ message_count = atoi(optarg);\r
+ break;\r
+ case 'S':\r
+ message_size = atoi(optarg);\r
+ break;\r
+ case 't':\r
+ set_tos = 1;\r
+ tos = (uint8_t) atoi(optarg);\r
+ break;\r
+ case 'p':\r
+ port = (uint16_t) atoi(optarg);\r
+ break;\r
+ case 'm':\r
+ migrate = 1;\r
+ break;\r
+ default:\r
+ printf("usage: %s\n", argv[0]);\r
+ printf("\t[-s server_address]\n");\r
+ printf("\t[-b bind_address]\n");\r
+ printf("\t[-c connections]\n");\r
+ printf("\t[-C message_count]\n");\r
+ printf("\t[-S message_size]\n");\r
+ printf("\t[-t type_of_service]\n");\r
+ printf("\t[-p port_number]\n");\r
+ printf("\t[-m(igrate)]\n");\r
+ exit(1);\r
+ }\r
+ }\r
+\r
+ test.dst_addr = (struct sockaddr *) &test.dst_in;\r
+ test.src_addr = (struct sockaddr *) &test.src_in;\r
+ test.connects_left = connections;\r
+ test.disconnects_left = connections;\r
+\r
+ test.channel = rdma_create_event_channel();\r
+ if (!test.channel) {\r
+ printf("failed to create event channel\n");\r
+ exit(1);\r
+ }\r
+\r
+ if (alloc_nodes())\r
+ exit(1);\r
+\r
+ if (dst_addr)\r
+ ret = run_client();\r
+ else\r
+ ret = run_server();\r
+\r
+ printf("test complete\n");\r
+ destroy_nodes();\r
+ rdma_destroy_event_channel(test.channel);\r
+\r
+ printf("return status 0x%x\n", ret);\r
+ return ret;\r
+}\r
--- /dev/null
+#\r
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source\r
+# file to this component. This file merely indirects to the real make file\r
+# that is shared by all the driver components of the OpenIB Windows project.\r
+#\r
+\r
+!INCLUDE ..\..\..\..\inc\openib.def\r
--- /dev/null
+DIRS = \\r
+ cmatose\r
--- /dev/null
+/*\r
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.\r
+ * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved.\r
+ * Copyright (c) 2009 Intel Corp. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <ws2tcpip.h>\r
+#include <winsock2.h>\r
+#include <time.h>\r
+\r
+#include "..\..\..\..\etc\user\getopt.c"\r
+#include <rdma/rdma_cma.h>\r
+\r
+#include <rdma/rdma_cma.h>\r
+\r
+static int debug = 0;\r
+#define DEBUG_LOG if (debug) printf\r
+\r
+/*\r
+ * rping "ping/pong" loop:\r
+ * client sends source rkey/addr/len\r
+ * server receives source rkey/add/len\r
+ * server rdma reads "ping" data from source\r
+ * server sends "go ahead" on rdma read completion\r
+ * client sends sink rkey/addr/len\r
+ * server receives sink rkey/addr/len\r
+ * server rdma writes "pong" data to sink\r
+ * server sends "go ahead" on rdma write completion\r
+ * <repeat loop>\r
+ */\r
+\r
+/*\r
+ * These states are used to signal events between the completion handler\r
+ * and the main client or server thread.\r
+ *\r
+ * Once CONNECTED, they cycle through RDMA_READ_ADV, RDMA_WRITE_ADV, \r
+ * and RDMA_WRITE_COMPLETE for each ping.\r
+ */\r
+enum test_state {\r
+ IDLE = 1,\r
+ CONNECT_REQUEST,\r
+ ADDR_RESOLVED,\r
+ ROUTE_RESOLVED,\r
+ CONNECTED,\r
+ RDMA_READ_ADV,\r
+ RDMA_READ_COMPLETE,\r
+ RDMA_WRITE_ADV,\r
+ RDMA_WRITE_COMPLETE,\r
+ RDMA_ERROR\r
+};\r
+\r
+struct rping_rdma_info {\r
+ uint64_t buf;\r
+ uint32_t rkey;\r
+ uint32_t size;\r
+};\r
+\r
+#define RPING_SQ_DEPTH 16\r
+\r
+#define RPING_MSG_FMT "rdma-ping-%d: "\r
+#define RPING_MIN_BUFSIZE 16\r
+\r
+/*\r
+ * Control block struct.\r
+ */\r
+struct rping_cb {\r
+ int server; /* 0 iff client */\r
+ pthread_t cqthread;\r
+ struct ibv_comp_channel *channel;\r
+ struct ibv_cq *cq;\r
+ struct ibv_pd *pd;\r
+ struct ibv_qp *qp;\r
+\r
+ struct ibv_recv_wr rq_wr; /* recv work request record */\r
+ struct ibv_sge recv_sgl; /* recv single SGE */\r
+ struct rping_rdma_info recv_buf;/* malloc'd buffer */\r
+ struct ibv_mr *recv_mr; /* MR associated with this buffer */\r
+\r
+ struct ibv_send_wr sq_wr; /* send work request record */\r
+ struct ibv_sge send_sgl;\r
+ struct rping_rdma_info send_buf;/* single send buf */\r
+ struct ibv_mr *send_mr;\r
+\r
+ struct ibv_send_wr rdma_sq_wr; /* rdma work request record */\r
+ struct ibv_sge rdma_sgl; /* rdma single SGE */\r
+ char *rdma_buf; /* used as rdma sink */\r
+ struct ibv_mr *rdma_mr;\r
+\r
+ uint32_t remote_rkey; /* remote guys RKEY */\r
+ uint64_t remote_addr; /* remote guys TO */\r
+ uint32_t remote_len; /* remote guys LEN */\r
+\r
+ char *start_buf; /* rdma read src */\r
+ struct ibv_mr *start_mr;\r
+\r
+ enum test_state state; /* used for cond/signalling */\r
+ sem_t sem;\r
+\r
+ struct sockaddr_in sin;\r
+ uint16_t port; /* dst port in NBO */\r
+ int verbose; /* verbose logging */\r
+ int count; /* ping count */\r
+ int size; /* ping data size */\r
+ int validate; /* validate ping data */\r
+\r
+ /* CM stuff */\r
+ pthread_t cmthread;\r
+ struct rdma_event_channel *cm_channel;\r
+ struct rdma_cm_id *cm_id; /* connection on client side,*/\r
+ /* listener on service side. */\r
+ struct rdma_cm_id *child_cm_id; /* connection on server side */\r
+};\r
+\r
+static int rping_cma_event_handler(struct rdma_cm_id *cma_id,\r
+ struct rdma_cm_event *event)\r
+{\r
+ int ret = 0;\r
+ struct rping_cb *cb = cma_id->context;\r
+\r
+ DEBUG_LOG("cma_event type %s cma_id %p (%s)\n",\r
+ rdma_event_str(event->event), cma_id,\r
+ (cma_id == cb->cm_id) ? "parent" : "child");\r
+\r
+ switch (event->event) {\r
+ case RDMA_CM_EVENT_ADDR_RESOLVED:\r
+ cb->state = ADDR_RESOLVED;\r
+ ret = rdma_resolve_route(cma_id, 2000);\r
+ if (ret) {\r
+ cb->state = RDMA_ERROR;\r
+ fprintf(stderr, "rdma_resolve_route error %d\n", ret);\r
+ sem_post(&cb->sem);\r
+ }\r
+ break;\r
+\r
+ case RDMA_CM_EVENT_ROUTE_RESOLVED:\r
+ cb->state = ROUTE_RESOLVED;\r
+ sem_post(&cb->sem);\r
+ break;\r
+\r
+ case RDMA_CM_EVENT_CONNECT_REQUEST:\r
+ cb->state = CONNECT_REQUEST;\r
+ cb->child_cm_id = cma_id;\r
+ DEBUG_LOG("child cma %p\n", cb->child_cm_id);\r
+ sem_post(&cb->sem);\r
+ break;\r
+\r
+ case RDMA_CM_EVENT_ESTABLISHED:\r
+ DEBUG_LOG("ESTABLISHED\n");\r
+\r
+ /*\r
+ * Server will wake up when first RECV completes.\r
+ */\r
+ if (!cb->server) {\r
+ cb->state = CONNECTED;\r
+ }\r
+ sem_post(&cb->sem);\r
+ break;\r
+\r
+ case RDMA_CM_EVENT_ADDR_ERROR:\r
+ case RDMA_CM_EVENT_ROUTE_ERROR:\r
+ case RDMA_CM_EVENT_CONNECT_ERROR:\r
+ case RDMA_CM_EVENT_UNREACHABLE:\r
+ case RDMA_CM_EVENT_REJECTED:\r
+ fprintf(stderr, "cma event %s, error %d\n",\r
+ rdma_event_str(event->event), event->status);\r
+ sem_post(&cb->sem);\r
+ ret = -1;\r
+ break;\r
+\r
+ case RDMA_CM_EVENT_DISCONNECTED:\r
+ fprintf(stderr, "%s DISCONNECT EVENT...\n",\r
+ cb->server ? "server" : "client");\r
+ sem_post(&cb->sem);\r
+ break;\r
+\r
+ case RDMA_CM_EVENT_DEVICE_REMOVAL:\r
+ fprintf(stderr, "cma detected device removal!!!!\n");\r
+ ret = -1;\r
+ break;\r
+\r
+ default:\r
+ fprintf(stderr, "unhandled event: %s, ignoring\n",\r
+ rdma_event_str(event->event));\r
+ break;\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+static int server_recv(struct rping_cb *cb, struct ibv_wc *wc)\r
+{\r
+ if (wc->byte_len != sizeof(cb->recv_buf)) {\r
+ fprintf(stderr, "Received bogus data, size %d\n", wc->byte_len);\r
+ return -1;\r
+ }\r
+\r
+ cb->remote_rkey = ntohl(cb->recv_buf.rkey);\r
+ cb->remote_addr = ntohll(cb->recv_buf.buf);\r
+ cb->remote_len = ntohl(cb->recv_buf.size);\r
+ DEBUG_LOG("Received rkey %x addr %" PRIx64 " len %d from peer\n",\r
+ cb->remote_rkey, cb->remote_addr, cb->remote_len);\r
+\r
+ if (cb->state <= CONNECTED || cb->state == RDMA_WRITE_COMPLETE)\r
+ cb->state = RDMA_READ_ADV;\r
+ else\r
+ cb->state = RDMA_WRITE_ADV;\r
+\r
+ return 0;\r
+}\r
+\r
+static int client_recv(struct rping_cb *cb, struct ibv_wc *wc)\r
+{\r
+ if (wc->byte_len != sizeof(cb->recv_buf)) {\r
+ fprintf(stderr, "Received bogus data, size %d\n", wc->byte_len);\r
+ return -1;\r
+ }\r
+\r
+ if (cb->state == RDMA_READ_ADV)\r
+ cb->state = RDMA_WRITE_ADV;\r
+ else\r
+ cb->state = RDMA_WRITE_COMPLETE;\r
+\r
+ return 0;\r
+}\r
+\r
+static int rping_cq_event_handler(struct rping_cb *cb)\r
+{\r
+ struct ibv_wc wc;\r
+ struct ibv_recv_wr *bad_wr;\r
+ int ret;\r
+\r
+ while ((ret = ibv_poll_cq(cb->cq, 1, &wc)) == 1) {\r
+ ret = 0;\r
+\r
+ if (wc.status) {\r
+ fprintf(stderr, "cq completion failed status %d\n",\r
+ wc.status);\r
+ if (wc.status != IBV_WC_WR_FLUSH_ERR)\r
+ ret = -1;\r
+ goto error;\r
+ }\r
+\r
+ switch (wc.opcode) {\r
+ case IBV_WC_SEND:\r
+ DEBUG_LOG("send completion\n");\r
+ break;\r
+\r
+ case IBV_WC_RDMA_WRITE:\r
+ DEBUG_LOG("rdma write completion\n");\r
+ cb->state = RDMA_WRITE_COMPLETE;\r
+ sem_post(&cb->sem);\r
+ break;\r
+\r
+ case IBV_WC_RDMA_READ:\r
+ DEBUG_LOG("rdma read completion\n");\r
+ cb->state = RDMA_READ_COMPLETE;\r
+ sem_post(&cb->sem);\r
+ break;\r
+\r
+ case IBV_WC_RECV:\r
+ DEBUG_LOG("recv completion\n");\r
+ ret = cb->server ? server_recv(cb, &wc) :\r
+ client_recv(cb, &wc);\r
+ if (ret) {\r
+ fprintf(stderr, "recv wc error: %d\n", ret);\r
+ goto error;\r
+ }\r
+\r
+ ret = ibv_post_recv(cb->qp, &cb->rq_wr, &bad_wr);\r
+ if (ret) {\r
+ fprintf(stderr, "post recv error: %d\n", ret);\r
+ goto error;\r
+ }\r
+ sem_post(&cb->sem);\r
+ break;\r
+\r
+ default:\r
+ DEBUG_LOG("unknown!!!!! completion\n");\r
+ ret = -1;\r
+ goto error;\r
+ }\r
+ }\r
+ if (ret) {\r
+ fprintf(stderr, "poll error %d\n", ret);\r
+ goto error;\r
+ }\r
+ return 0;\r
+\r
+error:\r
+ cb->state = RDMA_ERROR;\r
+ sem_post(&cb->sem);\r
+ return ret;\r
+}\r
+\r
+static int rping_accept(struct rping_cb *cb)\r
+{\r
+ struct rdma_conn_param conn_param;\r
+ int ret;\r
+\r
+ DEBUG_LOG("accepting client connection request\n");\r
+\r
+ memset(&conn_param, 0, sizeof conn_param);\r
+ conn_param.responder_resources = 1;\r
+ conn_param.initiator_depth = 1;\r
+\r
+ ret = rdma_accept(cb->child_cm_id, &conn_param);\r
+ if (ret) {\r
+ fprintf(stderr, "rdma_accept error: %d\n", ret);\r
+ return ret;\r
+ }\r
+\r
+ sem_wait(&cb->sem);\r
+ if (cb->state == RDMA_ERROR) {\r
+ fprintf(stderr, "wait for CONNECTED state %d\n", cb->state);\r
+ return -1;\r
+ }\r
+ return 0;\r
+}\r
+\r
+static void rping_setup_wr(struct rping_cb *cb)\r
+{\r
+ cb->recv_sgl.addr = (uint64_t) (unsigned long) &cb->recv_buf;\r
+ cb->recv_sgl.length = sizeof cb->recv_buf;\r
+ cb->recv_sgl.lkey = cb->recv_mr->lkey;\r
+ cb->rq_wr.sg_list = &cb->recv_sgl;\r
+ cb->rq_wr.num_sge = 1;\r
+\r
+ cb->send_sgl.addr = (uint64_t) (unsigned long) &cb->send_buf;\r
+ cb->send_sgl.length = sizeof cb->send_buf;\r
+ cb->send_sgl.lkey = cb->send_mr->lkey;\r
+\r
+ cb->sq_wr.opcode = IBV_WR_SEND;\r
+ cb->sq_wr.send_flags = IBV_SEND_SIGNALED;\r
+ cb->sq_wr.sg_list = &cb->send_sgl;\r
+ cb->sq_wr.num_sge = 1;\r
+\r
+ cb->rdma_sgl.addr = (uint64_t) (unsigned long) cb->rdma_buf;\r
+ cb->rdma_sgl.lkey = cb->rdma_mr->lkey;\r
+ cb->rdma_sq_wr.send_flags = IBV_SEND_SIGNALED;\r
+ cb->rdma_sq_wr.sg_list = &cb->rdma_sgl;\r
+ cb->rdma_sq_wr.num_sge = 1;\r
+}\r
+\r
+static int rping_setup_buffers(struct rping_cb *cb)\r
+{\r
+ int ret;\r
+\r
+ DEBUG_LOG("rping_setup_buffers called on cb %p\n", cb);\r
+\r
+ cb->recv_mr = ibv_reg_mr(cb->pd, &cb->recv_buf, sizeof cb->recv_buf,\r
+ IBV_ACCESS_LOCAL_WRITE);\r
+ if (!cb->recv_mr) {\r
+ fprintf(stderr, "recv_buf reg_mr failed\n");\r
+ return errno;\r
+ }\r
+\r
+ cb->send_mr = ibv_reg_mr(cb->pd, &cb->send_buf, sizeof cb->send_buf, 0);\r
+ if (!cb->send_mr) {\r
+ fprintf(stderr, "send_buf reg_mr failed\n");\r
+ ret = errno;\r
+ goto err1;\r
+ }\r
+\r
+ cb->rdma_buf = malloc(cb->size);\r
+ if (!cb->rdma_buf) {\r
+ fprintf(stderr, "rdma_buf malloc failed\n");\r
+ ret = -ENOMEM;\r
+ goto err2;\r
+ }\r
+\r
+ cb->rdma_mr = ibv_reg_mr(cb->pd, cb->rdma_buf, cb->size,\r
+ IBV_ACCESS_LOCAL_WRITE |\r
+ IBV_ACCESS_REMOTE_READ |\r
+ IBV_ACCESS_REMOTE_WRITE);\r
+ if (!cb->rdma_mr) {\r
+ fprintf(stderr, "rdma_buf reg_mr failed\n");\r
+ ret = errno;\r
+ goto err3;\r
+ }\r
+\r
+ if (!cb->server) {\r
+ cb->start_buf = malloc(cb->size);\r
+ if (!cb->start_buf) {\r
+ fprintf(stderr, "start_buf malloc failed\n");\r
+ ret = -ENOMEM;\r
+ goto err4;\r
+ }\r
+\r
+ cb->start_mr = ibv_reg_mr(cb->pd, cb->start_buf, cb->size,\r
+ IBV_ACCESS_LOCAL_WRITE | \r
+ IBV_ACCESS_REMOTE_READ |\r
+ IBV_ACCESS_REMOTE_WRITE);\r
+ if (!cb->start_mr) {\r
+ fprintf(stderr, "start_buf reg_mr failed\n");\r
+ ret = errno;\r
+ goto err5;\r
+ }\r
+ }\r
+\r
+ rping_setup_wr(cb);\r
+ DEBUG_LOG("allocated & registered buffers...\n");\r
+ return 0;\r
+\r
+err5:\r
+ free(cb->start_buf);\r
+err4:\r
+ ibv_dereg_mr(cb->rdma_mr);\r
+err3:\r
+ free(cb->rdma_buf);\r
+err2:\r
+ ibv_dereg_mr(cb->send_mr);\r
+err1:\r
+ ibv_dereg_mr(cb->recv_mr);\r
+ return ret;\r
+}\r
+\r
+static void rping_free_buffers(struct rping_cb *cb)\r
+{\r
+ DEBUG_LOG("rping_free_buffers called on cb %p\n", cb);\r
+ ibv_dereg_mr(cb->recv_mr);\r
+ ibv_dereg_mr(cb->send_mr);\r
+ ibv_dereg_mr(cb->rdma_mr);\r
+ free(cb->rdma_buf);\r
+ if (!cb->server) {\r
+ ibv_dereg_mr(cb->start_mr);\r
+ free(cb->start_buf);\r
+ }\r
+}\r
+\r
+static int rping_create_qp(struct rping_cb *cb)\r
+{\r
+ struct ibv_qp_init_attr init_attr;\r
+ int ret;\r
+\r
+ memset(&init_attr, 0, sizeof(init_attr));\r
+ init_attr.cap.max_send_wr = RPING_SQ_DEPTH;\r
+ init_attr.cap.max_recv_wr = 2;\r
+ init_attr.cap.max_recv_sge = 1;\r
+ init_attr.cap.max_send_sge = 1;\r
+ init_attr.qp_type = IBV_QPT_RC;\r
+ init_attr.send_cq = cb->cq;\r
+ init_attr.recv_cq = cb->cq;\r
+\r
+ if (cb->server) {\r
+ ret = rdma_create_qp(cb->child_cm_id, cb->pd, &init_attr);\r
+ if (!ret)\r
+ cb->qp = cb->child_cm_id->qp;\r
+ } else {\r
+ ret = rdma_create_qp(cb->cm_id, cb->pd, &init_attr);\r
+ if (!ret)\r
+ cb->qp = cb->cm_id->qp;\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+static void rping_free_qp(struct rping_cb *cb)\r
+{\r
+ ibv_destroy_qp(cb->qp);\r
+ ibv_destroy_cq(cb->cq);\r
+ ibv_destroy_comp_channel(cb->channel);\r
+ ibv_dealloc_pd(cb->pd);\r
+}\r
+\r
+static int rping_setup_qp(struct rping_cb *cb, struct rdma_cm_id *cm_id)\r
+{\r
+ int ret;\r
+\r
+ cb->pd = ibv_alloc_pd(cm_id->verbs);\r
+ if (!cb->pd) {\r
+ fprintf(stderr, "ibv_alloc_pd failed\n");\r
+ return errno;\r
+ }\r
+ DEBUG_LOG("created pd %p\n", cb->pd);\r
+\r
+ cb->channel = ibv_create_comp_channel(cm_id->verbs);\r
+ if (!cb->channel) {\r
+ fprintf(stderr, "ibv_create_comp_channel failed\n");\r
+ ret = errno;\r
+ goto err1;\r
+ }\r
+ DEBUG_LOG("created channel %p\n", cb->channel);\r
+\r
+ cb->cq = ibv_create_cq(cm_id->verbs, RPING_SQ_DEPTH * 2, cb,\r
+ cb->channel, 0);\r
+ if (!cb->cq) {\r
+ fprintf(stderr, "ibv_create_cq failed\n");\r
+ ret = errno;\r
+ goto err2;\r
+ }\r
+ DEBUG_LOG("created cq %p\n", cb->cq);\r
+\r
+ ret = ibv_req_notify_cq(cb->cq, 0);\r
+ if (ret) {\r
+ fprintf(stderr, "ibv_create_cq failed\n");\r
+ ret = errno;\r
+ goto err3;\r
+ }\r
+\r
+ ret = rping_create_qp(cb);\r
+ if (ret) {\r
+ fprintf(stderr, "rping_create_qp failed: %d\n", ret);\r
+ goto err3;\r
+ }\r
+ DEBUG_LOG("created qp %p\n", cb->qp);\r
+ return 0;\r
+\r
+err3:\r
+ ibv_destroy_cq(cb->cq);\r
+err2:\r
+ ibv_destroy_comp_channel(cb->channel);\r
+err1:\r
+ ibv_dealloc_pd(cb->pd);\r
+ return ret;\r
+}\r
+\r
+static void *cm_thread(void *arg)\r
+{\r
+ struct rping_cb *cb = arg;\r
+ struct rdma_cm_event *event;\r
+ int ret;\r
+\r
+ while (1) {\r
+ ret = rdma_get_cm_event(cb->cm_channel, &event);\r
+ if (ret) {\r
+ fprintf(stderr, "rdma_get_cm_event err %d\n", ret);\r
+ exit(ret);\r
+ }\r
+ ret = rping_cma_event_handler(event->id, event);\r
+ rdma_ack_cm_event(event);\r
+ if (ret)\r
+ exit(ret);\r
+ }\r
+}\r
+\r
+static void *cq_thread(void *arg)\r
+{\r
+ struct rping_cb *cb = arg;\r
+ struct ibv_cq *ev_cq;\r
+ void *ev_ctx;\r
+ int ret;\r
+ \r
+ DEBUG_LOG("cq_thread started.\n");\r
+\r
+ while (1) { \r
+ pthread_testcancel();\r
+\r
+ ret = ibv_get_cq_event(cb->channel, &ev_cq, &ev_ctx);\r
+ if (ret) {\r
+ fprintf(stderr, "Failed to get cq event!\n");\r
+ pthread_exit(NULL);\r
+ }\r
+ if (ev_cq != cb->cq) {\r
+ fprintf(stderr, "Unknown CQ!\n");\r
+ pthread_exit(NULL);\r
+ }\r
+ ret = ibv_req_notify_cq(cb->cq, 0);\r
+ if (ret) {\r
+ fprintf(stderr, "Failed to set notify!\n");\r
+ pthread_exit(NULL);\r
+ }\r
+ ret = rping_cq_event_handler(cb);\r
+ ibv_ack_cq_events(cb->cq, 1);\r
+ if (ret)\r
+ pthread_exit(NULL);\r
+ }\r
+}\r
+\r
+static void rping_format_send(struct rping_cb *cb, char *buf, struct ibv_mr *mr)\r
+{\r
+ struct rping_rdma_info *info = &cb->send_buf;\r
+\r
+ info->buf = htonll((uint64_t) (unsigned long) buf);\r
+ info->rkey = htonl(mr->rkey);\r
+ info->size = htonl(cb->size);\r
+\r
+ DEBUG_LOG("RDMA addr %" PRIx64" rkey %x len %d\n",\r
+ ntohll(info->buf), ntohl(info->rkey), ntohl(info->size));\r
+}\r
+\r
+static int rping_test_server(struct rping_cb *cb)\r
+{\r
+ struct ibv_send_wr *bad_wr;\r
+ int ret;\r
+\r
+ while (1) {\r
+ /* Wait for client's Start STAG/TO/Len */\r
+ sem_wait(&cb->sem);\r
+ if (cb->state != RDMA_READ_ADV) {\r
+ fprintf(stderr, "wait for RDMA_READ_ADV state %d\n",\r
+ cb->state);\r
+ ret = -1;\r
+ break;\r
+ }\r
+\r
+ DEBUG_LOG("server received sink adv\n");\r
+\r
+ /* Issue RDMA Read. */\r
+ cb->rdma_sq_wr.opcode = IBV_WR_RDMA_READ;\r
+ cb->rdma_sq_wr.wr.rdma.rkey = cb->remote_rkey;\r
+ cb->rdma_sq_wr.wr.rdma.remote_addr = cb->remote_addr;\r
+ cb->rdma_sq_wr.sg_list->length = cb->remote_len;\r
+\r
+ ret = ibv_post_send(cb->qp, &cb->rdma_sq_wr, &bad_wr);\r
+ if (ret) {\r
+ fprintf(stderr, "post send error %d\n", ret);\r
+ break;\r
+ }\r
+ DEBUG_LOG("server posted rdma read req \n");\r
+\r
+ /* Wait for read completion */\r
+ sem_wait(&cb->sem);\r
+ if (cb->state != RDMA_READ_COMPLETE) {\r
+ fprintf(stderr, "wait for RDMA_READ_COMPLETE state %d\n",\r
+ cb->state);\r
+ ret = -1;\r
+ break;\r
+ }\r
+ DEBUG_LOG("server received read complete\n");\r
+\r
+ /* Display data in recv buf */\r
+ if (cb->verbose)\r
+ printf("server ping data: %s\n", cb->rdma_buf);\r
+\r
+ /* Tell client to continue */\r
+ ret = ibv_post_send(cb->qp, &cb->sq_wr, &bad_wr);\r
+ if (ret) {\r
+ fprintf(stderr, "post send error %d\n", ret);\r
+ break;\r
+ }\r
+ DEBUG_LOG("server posted go ahead\n");\r
+\r
+ /* Wait for client's RDMA STAG/TO/Len */\r
+ sem_wait(&cb->sem);\r
+ if (cb->state != RDMA_WRITE_ADV) {\r
+ fprintf(stderr, "wait for RDMA_WRITE_ADV state %d\n",\r
+ cb->state);\r
+ ret = -1;\r
+ break;\r
+ }\r
+ DEBUG_LOG("server received sink adv\n");\r
+\r
+ /* RDMA Write echo data */\r
+ cb->rdma_sq_wr.opcode = IBV_WR_RDMA_WRITE;\r
+ cb->rdma_sq_wr.wr.rdma.rkey = cb->remote_rkey;\r
+ cb->rdma_sq_wr.wr.rdma.remote_addr = cb->remote_addr;\r
+ cb->rdma_sq_wr.sg_list->length = strlen(cb->rdma_buf) + 1;\r
+ DEBUG_LOG("rdma write from lkey %x laddr %" PRIx64 " len %d\n",\r
+ cb->rdma_sq_wr.sg_list->lkey,\r
+ cb->rdma_sq_wr.sg_list->addr,\r
+ cb->rdma_sq_wr.sg_list->length);\r
+\r
+ ret = ibv_post_send(cb->qp, &cb->rdma_sq_wr, &bad_wr);\r
+ if (ret) {\r
+ fprintf(stderr, "post send error %d\n", ret);\r
+ break;\r
+ }\r
+\r
+ /* Wait for completion */\r
+ ret = sem_wait(&cb->sem);\r
+ if (cb->state != RDMA_WRITE_COMPLETE) {\r
+ fprintf(stderr, "wait for RDMA_WRITE_COMPLETE state %d\n",\r
+ cb->state);\r
+ ret = -1;\r
+ break;\r
+ }\r
+ DEBUG_LOG("server rdma write complete \n");\r
+\r
+ /* Tell client to begin again */\r
+ ret = ibv_post_send(cb->qp, &cb->sq_wr, &bad_wr);\r
+ if (ret) {\r
+ fprintf(stderr, "post send error %d\n", ret);\r
+ break;\r
+ }\r
+ DEBUG_LOG("server posted go ahead\n");\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+static int rping_bind_server(struct rping_cb *cb)\r
+{\r
+ int ret;\r
+\r
+ cb->sin.sin_port = cb->port;\r
+ ret = rdma_bind_addr(cb->cm_id, (struct sockaddr *) &cb->sin);\r
+ if (ret) {\r
+ fprintf(stderr, "rdma_bind_addr error %d\n", ret);\r
+ return ret;\r
+ }\r
+ DEBUG_LOG("rdma_bind_addr successful\n");\r
+\r
+ DEBUG_LOG("rdma_listen\n");\r
+ ret = rdma_listen(cb->cm_id, 3);\r
+ if (ret) {\r
+ fprintf(stderr, "rdma_listen failed: %d\n", ret);\r
+ return ret;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+static struct rping_cb *clone_cb(struct rping_cb *listening_cb)\r
+{\r
+ struct rping_cb *cb = malloc(sizeof *cb);\r
+ if (!cb)\r
+ return NULL;\r
+ *cb = *listening_cb;\r
+ cb->child_cm_id->context = cb;\r
+ return cb;\r
+}\r
+\r
+static void free_cb(struct rping_cb *cb)\r
+{\r
+ free(cb);\r
+}\r
+\r
+static int rping_run_server(struct rping_cb *cb)\r
+{\r
+ struct ibv_recv_wr *bad_wr;\r
+ int ret;\r
+\r
+ ret = rping_bind_server(cb);\r
+ if (ret)\r
+ return ret;\r
+\r
+ sem_wait(&cb->sem);\r
+ if (cb->state != CONNECT_REQUEST) {\r
+ fprintf(stderr, "wait for CONNECT_REQUEST state %d\n",\r
+ cb->state);\r
+ return -1;\r
+ }\r
+\r
+ ret = rping_setup_qp(cb, cb->child_cm_id);\r
+ if (ret) {\r
+ fprintf(stderr, "setup_qp failed: %d\n", ret);\r
+ return ret;\r
+ }\r
+\r
+ ret = rping_setup_buffers(cb);\r
+ if (ret) {\r
+ fprintf(stderr, "rping_setup_buffers failed: %d\n", ret);\r
+ goto err1;\r
+ }\r
+\r
+ ret = ibv_post_recv(cb->qp, &cb->rq_wr, &bad_wr);\r
+ if (ret) {\r
+ fprintf(stderr, "ibv_post_recv failed: %d\n", ret);\r
+ goto err2;\r
+ }\r
+\r
+ pthread_create(&cb->cqthread, NULL, cq_thread, cb);\r
+\r
+ ret = rping_accept(cb);\r
+ if (ret) {\r
+ fprintf(stderr, "connect error %d\n", ret);\r
+ goto err2;\r
+ }\r
+\r
+ rping_test_server(cb);\r
+ rdma_disconnect(cb->child_cm_id);\r
+ rdma_destroy_id(cb->child_cm_id);\r
+err2:\r
+ rping_free_buffers(cb);\r
+err1:\r
+ rping_free_qp(cb);\r
+\r
+ return ret;\r
+}\r
+\r
+static int rping_test_client(struct rping_cb *cb)\r
+{\r
+ int ping, start, cc, i, ret = 0;\r
+ struct ibv_send_wr *bad_wr;\r
+ unsigned char c;\r
+\r
+ start = 65;\r
+ for (ping = 0; !cb->count || ping < cb->count; ping++) {\r
+ cb->state = RDMA_READ_ADV;\r
+\r
+ /* Put some ascii text in the buffer. */\r
+ cc = sprintf(cb->start_buf, RPING_MSG_FMT, ping);\r
+ for (i = cc, c = start; i < cb->size; i++) {\r
+ cb->start_buf[i] = c;\r
+ c++;\r
+ if (c > 122)\r
+ c = 65;\r
+ }\r
+ start++;\r
+ if (start > 122)\r
+ start = 65;\r
+ cb->start_buf[cb->size - 1] = 0;\r
+\r
+ rping_format_send(cb, cb->start_buf, cb->start_mr);\r
+ ret = ibv_post_send(cb->qp, &cb->sq_wr, &bad_wr);\r
+ if (ret) {\r
+ fprintf(stderr, "post send error %d\n", ret);\r
+ break;\r
+ }\r
+\r
+ /* Wait for server to ACK */\r
+ sem_wait(&cb->sem);\r
+ if (cb->state != RDMA_WRITE_ADV) {\r
+ fprintf(stderr, "wait for RDMA_WRITE_ADV state %d\n",\r
+ cb->state);\r
+ ret = -1;\r
+ break;\r
+ }\r
+\r
+ rping_format_send(cb, cb->rdma_buf, cb->rdma_mr);\r
+ ret = ibv_post_send(cb->qp, &cb->sq_wr, &bad_wr);\r
+ if (ret) {\r
+ fprintf(stderr, "post send error %d\n", ret);\r
+ break;\r
+ }\r
+\r
+ /* Wait for the server to say the RDMA Write is complete. */\r
+ sem_wait(&cb->sem);\r
+ if (cb->state != RDMA_WRITE_COMPLETE) {\r
+ fprintf(stderr, "wait for RDMA_WRITE_COMPLETE state %d\n",\r
+ cb->state);\r
+ ret = -1;\r
+ break;\r
+ }\r
+\r
+ if (cb->validate)\r
+ if (memcmp(cb->start_buf, cb->rdma_buf, cb->size)) {\r
+ fprintf(stderr, "data mismatch!\n");\r
+ ret = -1;\r
+ break;\r
+ }\r
+\r
+ if (cb->verbose)\r
+ printf("ping data: %s\n", cb->rdma_buf);\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+static int rping_connect_client(struct rping_cb *cb)\r
+{\r
+ struct rdma_conn_param conn_param;\r
+ int ret;\r
+\r
+ memset(&conn_param, 0, sizeof conn_param);\r
+ conn_param.responder_resources = 1;\r
+ conn_param.initiator_depth = 1;\r
+ conn_param.retry_count = 10;\r
+\r
+ ret = rdma_connect(cb->cm_id, &conn_param);\r
+ if (ret) {\r
+ fprintf(stderr, "rdma_connect error %d\n", ret);\r
+ return ret;\r
+ }\r
+\r
+ sem_wait(&cb->sem);\r
+ if (cb->state != CONNECTED) {\r
+ fprintf(stderr, "wait for CONNECTED state %d\n", cb->state);\r
+ return -1;\r
+ }\r
+\r
+ DEBUG_LOG("rmda_connect successful\n");\r
+ return 0;\r
+}\r
+\r
+static int rping_bind_client(struct rping_cb *cb)\r
+{\r
+ int ret;\r
+\r
+ cb->sin.sin_port = cb->port;\r
+ ret = rdma_resolve_addr(cb->cm_id, NULL, (struct sockaddr *) &cb->sin, 2000);\r
+ if (ret) {\r
+ fprintf(stderr, "rdma_resolve_addr error %d\n", ret);\r
+ return ret;\r
+ }\r
+\r
+ sem_wait(&cb->sem);\r
+ if (cb->state != ROUTE_RESOLVED) {\r
+ fprintf(stderr, "waiting for addr/route resolution state %d\n",\r
+ cb->state);\r
+ return -1;\r
+ }\r
+\r
+ DEBUG_LOG("rdma_resolve_addr - rdma_resolve_route successful\n");\r
+ return 0;\r
+}\r
+\r
+static int rping_run_client(struct rping_cb *cb)\r
+{\r
+ struct ibv_recv_wr *bad_wr;\r
+ int ret;\r
+\r
+ ret = rping_bind_client(cb);\r
+ if (ret)\r
+ return ret;\r
+\r
+ ret = rping_setup_qp(cb, cb->cm_id);\r
+ if (ret) {\r
+ fprintf(stderr, "setup_qp failed: %d\n", ret);\r
+ return ret;\r
+ }\r
+\r
+ ret = rping_setup_buffers(cb);\r
+ if (ret) {\r
+ fprintf(stderr, "rping_setup_buffers failed: %d\n", ret);\r
+ goto err1;\r
+ }\r
+\r
+ ret = ibv_post_recv(cb->qp, &cb->rq_wr, &bad_wr);\r
+ if (ret) {\r
+ fprintf(stderr, "ibv_post_recv failed: %d\n", ret);\r
+ goto err2;\r
+ }\r
+\r
+ pthread_create(&cb->cqthread, NULL, cq_thread, cb);\r
+\r
+ ret = rping_connect_client(cb);\r
+ if (ret) {\r
+ fprintf(stderr, "connect error %d\n", ret);\r
+ goto err2;\r
+ }\r
+\r
+ rping_test_client(cb);\r
+ rdma_disconnect(cb->cm_id);\r
+err2:\r
+ rping_free_buffers(cb);\r
+err1:\r
+ rping_free_qp(cb);\r
+\r
+ return ret;\r
+}\r
+\r
+static int get_addr(char *dst, struct sockaddr_in *addr)\r
+{\r
+ struct addrinfo *res;\r
+ int ret;\r
+\r
+ ret = getaddrinfo(dst, NULL, NULL, &res);\r
+ if (ret) {\r
+ printf("getaddrinfo failed - invalid hostname or IP address\n");\r
+ return ret;\r
+ }\r
+\r
+ if (res->ai_family != PF_INET) {\r
+ ret = -1;\r
+ goto out;\r
+ }\r
+\r
+ *addr = *(struct sockaddr_in *) res->ai_addr;\r
+out:\r
+ freeaddrinfo(res);\r
+ return ret;\r
+}\r
+\r
+static void usage()\r
+{\r
+ printf("rdma_rping -s [-vVd] [-S size] [-C count] [-a addr] [-p port]\n");\r
+ printf("rdma_rping -c [-vVd] [-S size] [-C count] -a addr [-p port]\n");\r
+ printf("\t-c\t\tclient side\n");\r
+ printf("\t-s\t\tserver side\n");\r
+ printf("\t-v\t\tdisplay ping data to stdout\n");\r
+ printf("\t-V\t\tvalidate ping data\n");\r
+ printf("\t-d\t\tdebug printfs\n");\r
+ printf("\t-S size \tping data size\n");\r
+ printf("\t-C count\tping count times\n");\r
+ printf("\t-a addr\t\taddress\n");\r
+ printf("\t-p port\t\tport\n");\r
+}\r
+\r
+int main(int argc, char *argv[])\r
+{\r
+ struct rping_cb *cb;\r
+ int op;\r
+ int ret = 0;\r
+\r
+ cb = malloc(sizeof(*cb));\r
+ if (!cb)\r
+ return -ENOMEM;\r
+\r
+ memset(cb, 0, sizeof(*cb));\r
+ cb->server = -1;\r
+ cb->state = IDLE;\r
+ cb->size = 64;\r
+ cb->sin.sin_family = PF_INET;\r
+ cb->port = htons(7174);\r
+ sem_init(&cb->sem, 0, 0);\r
+\r
+ opterr = 0;\r
+ while ((op=getopt(argc, argv, "a:Pp:C:S:t:scvVd")) != -1) {\r
+ switch (op) {\r
+ case 'a':\r
+ ret = get_addr(optarg, &cb->sin);\r
+ break;\r
+ case 'p':\r
+ cb->port = htons(atoi(optarg));\r
+ DEBUG_LOG("port %d\n", (int) atoi(optarg));\r
+ break;\r
+ case 's':\r
+ cb->server = 1;\r
+ DEBUG_LOG("server\n");\r
+ break;\r
+ case 'c':\r
+ cb->server = 0;\r
+ DEBUG_LOG("client\n");\r
+ break;\r
+ case 'S':\r
+ cb->size = atoi(optarg);\r
+ if (cb->size < RPING_MIN_BUFSIZE) {\r
+ fprintf(stderr, "Invalid size (minimum is %d) " RPING_MIN_BUFSIZE);\r
+ ret = EINVAL;\r
+ } else\r
+ DEBUG_LOG("size %d\n", (int) atoi(optarg));\r
+ break;\r
+ case 'C':\r
+ cb->count = atoi(optarg);\r
+ if (cb->count < 0) {\r
+ fprintf(stderr, "Invalid count %d\n", cb->count);\r
+ ret = EINVAL;\r
+ } else\r
+ DEBUG_LOG("count %d\n", (int) cb->count);\r
+ break;\r
+ case 'v':\r
+ cb->verbose++;\r
+ DEBUG_LOG("verbose\n");\r
+ break;\r
+ case 'V':\r
+ cb->validate++;\r
+ DEBUG_LOG("validate data\n");\r
+ break;\r
+ case 'd':\r
+ debug++;\r
+ break;\r
+ default:\r
+ usage();\r
+ ret = EINVAL;\r
+ goto out;\r
+ }\r
+ }\r
+ if (ret)\r
+ goto out;\r
+\r
+ if (cb->server == -1) {\r
+ usage();\r
+ ret = EINVAL;\r
+ goto out;\r
+ }\r
+\r
+ cb->cm_channel = rdma_create_event_channel();\r
+ if (!cb->cm_channel) {\r
+ ret = errno;\r
+ fprintf(stderr, "rdma_create_event_channel error %d\n", ret);\r
+ goto out;\r
+ }\r
+\r
+ ret = rdma_create_id(cb->cm_channel, &cb->cm_id, cb, RDMA_PS_TCP);\r
+ if (ret) {\r
+ ret = errno;\r
+ fprintf(stderr, "rdma_create_id error %d\n", ret);\r
+ goto out2;\r
+ }\r
+ DEBUG_LOG("created cm_id %p\n", cb->cm_id);\r
+\r
+ pthread_create(&cb->cmthread, NULL, cm_thread, cb);\r
+\r
+ if (cb->server)\r
+ ret = rping_run_server(cb);\r
+ else\r
+ ret = rping_run_client(cb);\r
+\r
+ DEBUG_LOG("destroy cm_id %p\n", cb->cm_id);\r
+ rdma_destroy_id(cb->cm_id);\r
+out2:\r
+ rdma_destroy_event_channel(cb->cm_channel);\r
+out:\r
+ free(cb);\r
+ return ret;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2005-2009 Intel Corporation. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenFabrics.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+#pragma once\r
+\r
+#if !defined(RDMA_CMA_H)\r
+#define RDMA_CMA_H\r
+\r
+#include <windows.h>\r
+#include <infiniband\verbs.h>\r
+#include <rdma\winverbs.h>\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/*\r
+ * Interfaces based on librdmacm 1.0.8.\r
+ */\r
+\r
+typedef unsigned __int8 uint8_t;\r
+typedef unsigned __int16 uint16_t;\r
+typedef unsigned __int32 uint32_t;\r
+typedef unsigned __int64 uint64_t;\r
+\r
+/*\r
+ * Upon receiving a device removal event, users must destroy the associated\r
+ * RDMA identifier and release all resources allocated with the device.\r
+ */\r
+enum rdma_cm_event_type\r
+{\r
+ RDMA_CM_EVENT_ADDR_RESOLVED,\r
+ RDMA_CM_EVENT_ADDR_ERROR,\r
+ RDMA_CM_EVENT_ROUTE_RESOLVED,\r
+ RDMA_CM_EVENT_ROUTE_ERROR,\r
+ RDMA_CM_EVENT_CONNECT_REQUEST,\r
+ RDMA_CM_EVENT_CONNECT_RESPONSE,\r
+ RDMA_CM_EVENT_CONNECT_ERROR,\r
+ RDMA_CM_EVENT_UNREACHABLE,\r
+ RDMA_CM_EVENT_REJECTED,\r
+ RDMA_CM_EVENT_ESTABLISHED,\r
+ RDMA_CM_EVENT_DISCONNECTED,\r
+ RDMA_CM_EVENT_DEVICE_REMOVAL,\r
+ RDMA_CM_EVENT_MULTICAST_JOIN,\r
+ RDMA_CM_EVENT_MULTICAST_ERROR,\r
+ RDMA_CM_EVENT_ADDR_CHANGE,\r
+ RDMA_CM_EVENT_TIMEWAIT_EXIT\r
+};\r
+\r
+enum rdma_port_space\r
+{\r
+ RDMA_PS_IPOIB = 0x0002,\r
+ RDMA_PS_TCP = 0x0106,\r
+ RDMA_PS_UDP = 0x0111,\r
+};\r
+\r
+/*\r
+ * Global qkey value for UDP QPs and multicast groups created via the \r
+ * RDMA CM.\r
+ */\r
+#define RDMA_UDP_QKEY 0x01234567\r
+\r
+struct ib_addr\r
+{\r
+ union ibv_gid sgid;\r
+ union ibv_gid dgid;\r
+ uint16_t pkey;\r
+};\r
+\r
+struct rdma_addr\r
+{\r
+ struct sockaddr src_addr;\r
+ uint8_t src_pad[sizeof(SOCKADDR_IN6) -\r
+ sizeof(struct sockaddr)];\r
+ struct sockaddr dst_addr;\r
+ uint8_t dst_pad[sizeof(SOCKADDR_IN6) -\r
+ sizeof(struct sockaddr)];\r
+ union\r
+ {\r
+ struct ib_addr ibaddr;\r
+ } addr;\r
+};\r
+\r
+struct ibv_sa_path_rec\r
+{\r
+ uint8_t data[64];\r
+};\r
+\r
+struct rdma_route\r
+{\r
+ struct rdma_addr addr;\r
+ struct ibv_sa_path_rec *path_rec;\r
+ int num_paths;\r
+};\r
+\r
+struct rdma_event_channel\r
+{\r
+ uint32_t timeout;\r
+};\r
+\r
+struct rdma_cm_id\r
+{\r
+ struct ibv_context *verbs;\r
+ struct rdma_event_channel *channel;\r
+ void *context;\r
+ struct ibv_qp *qp;\r
+ struct rdma_route route;\r
+ enum rdma_port_space ps;\r
+ uint8_t port_num;\r
+\r
+ union {\r
+ IWVConnectEndpoint *connect;\r
+ IWVDatagramEndpoint *datagram;\r
+ } ep;\r
+ OVERLAPPED overlap;\r
+ uint32_t events_completed;\r
+};\r
+\r
+struct rdma_conn_param\r
+{\r
+ const void *private_data;\r
+ uint8_t private_data_len;\r
+ uint8_t responder_resources;\r
+ uint8_t initiator_depth;\r
+ uint8_t flow_control;\r
+ uint8_t retry_count; /* ignored when accepting */\r
+ uint8_t rnr_retry_count;\r
+ /* Fields below ignored if a QP is created on the rdma_cm_id. */\r
+ uint8_t srq;\r
+ uint32_t qp_num;\r
+};\r
+\r
+struct rdma_ud_param\r
+{\r
+ const void *private_data;\r
+ uint8_t private_data_len;\r
+ struct ibv_ah_attr ah_attr;\r
+ uint32_t qp_num;\r
+ uint32_t qkey;\r
+};\r
+\r
+struct rdma_cm_event\r
+{\r
+ struct rdma_cm_id *id;\r
+ struct rdma_cm_id *listen_id;\r
+ enum rdma_cm_event_type event;\r
+ int status;\r
+ union\r
+ {\r
+ struct rdma_conn_param conn;\r
+ struct rdma_ud_param ud;\r
+\r
+ } param;\r
+};\r
+\r
+/**\r
+ * rdma_create_event_channel - Open a channel used to report communication events.\r
+ * Description:\r
+ * Asynchronous events are reported to users through event channels. Each\r
+ * event channel maps to a file descriptor.\r
+ * Notes:\r
+ * All created event channels must be destroyed by calling\r
+ * rdma_destroy_event_channel. Users should call rdma_get_cm_event to\r
+ * retrieve events on an event channel.\r
+ * See also:\r
+ * rdma_get_cm_event, rdma_destroy_event_channel\r
+ */\r
+__declspec(dllexport)\r
+struct rdma_event_channel *rdma_create_event_channel(void);\r
+\r
+/**\r
+ * rdma_destroy_event_channel - Close an event communication channel.\r
+ * @channel: The communication channel to destroy.\r
+ * Description:\r
+ * Release all resources associated with an event channel and closes the\r
+ * associated file descriptor.\r
+ * Notes:\r
+ * All rdma_cm_id's associated with the event channel must be destroyed,\r
+ * and all returned events must be acked before calling this function.\r
+ * See also:\r
+ * rdma_create_event_channel, rdma_get_cm_event, rdma_ack_cm_event\r
+ */\r
+__declspec(dllexport)\r
+void rdma_destroy_event_channel(struct rdma_event_channel *channel);\r
+\r
+/**\r
+ * rdma_create_id - Allocate a communication identifier.\r
+ * @channel: The communication channel that events associated with the\r
+ * allocated rdma_cm_id will be reported on.\r
+ * @id: A reference where the allocated communication identifier will be\r
+ * returned.\r
+ * @context: User specified context associated with the rdma_cm_id.\r
+ * @ps: RDMA port space.\r
+ * Description:\r
+ * Creates an identifier that is used to track communication information.\r
+ * Notes:\r
+ * Rdma_cm_id's are conceptually equivalent to a socket for RDMA\r
+ * communication. The difference is that RDMA communication requires\r
+ * explicitly binding to a specified RDMA device before communication\r
+ * can occur, and most operations are asynchronous in nature. Communication\r
+ * events on an rdma_cm_id are reported through the associated event\r
+ * channel. Users must release the rdma_cm_id by calling rdma_destroy_id.\r
+ * See also:\r
+ * rdma_create_event_channel, rdma_destroy_id, rdma_get_devices,\r
+ * rdma_bind_addr, rdma_resolve_addr, rdma_connect, rdma_listen,\r
+ */\r
+__declspec(dllexport)\r
+int rdma_create_id(struct rdma_event_channel *channel,\r
+ struct rdma_cm_id **id, void *context,\r
+ enum rdma_port_space ps);\r
+\r
+/**\r
+ * rdma_destroy_id - Release a communication identifier.\r
+ * @id: The communication identifier to destroy.\r
+ * Description:\r
+ * Destroys the specified rdma_cm_id and cancels any outstanding\r
+ * asynchronous operation.\r
+ * Notes:\r
+ * Users must free any associated QP with the rdma_cm_id before\r
+ * calling this routine and ack an related events.\r
+ * See also:\r
+ * rdma_create_id, rdma_destroy_qp, rdma_ack_cm_event\r
+ */\r
+__declspec(dllexport)\r
+int rdma_destroy_id(struct rdma_cm_id *id);\r
+\r
+/**\r
+ * rdma_bind_addr - Bind an RDMA identifier to a source address.\r
+ * @id: RDMA identifier.\r
+ * @addr: Local address information. Wildcard values are permitted.\r
+ * Description:\r
+ * Associates a source address with an rdma_cm_id. The address may be\r
+ * wildcarded. If binding to a specific local address, the rdma_cm_id\r
+ * will also be bound to a local RDMA device.\r
+ * Notes:\r
+ * Typically, this routine is called before calling rdma_listen to bind\r
+ * to a specific port number, but it may also be called on the active side\r
+ * of a connection before calling rdma_resolve_addr to bind to a specific\r
+ * address.\r
+ * See also:\r
+ * rdma_create_id, rdma_listen, rdma_resolve_addr, rdma_create_qp\r
+ */\r
+__declspec(dllexport)\r
+int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr);\r
+\r
+/**\r
+ * rdma_resolve_addr - Resolve destination and optional source addresses.\r
+ * @id: RDMA identifier.\r
+ * @src_addr: Source address information. This parameter may be NULL.\r
+ * @dst_addr: Destination address information.\r
+ * @timeout_ms: Time to wait for resolution to complete.\r
+ * Description:\r
+ * Resolve destination and optional source addresses from IP addresses\r
+ * to an RDMA address. If successful, the specified rdma_cm_id will\r
+ * be bound to a local device.\r
+ * Notes:\r
+ * This call is used to map a given destination IP address to a usable RDMA\r
+ * address. If a source address is given, the rdma_cm_id is bound to that\r
+ * address, the same as if rdma_bind_addr were called. If no source\r
+ * address is given, and the rdma_cm_id has not yet been bound to a device,\r
+ * then the rdma_cm_id will be bound to a source address based on the\r
+ * local routing tables. After this call, the rdma_cm_id will be bound to\r
+ * an RDMA device. This call is typically made from the active side of a\r
+ * connection before calling rdma_resolve_route and rdma_connect.\r
+ * See also:\r
+ * rdma_create_id, rdma_resolve_route, rdma_connect, rdma_create_qp,\r
+ * rdma_get_cm_event, rdma_bind_addr\r
+ */\r
+__declspec(dllexport)\r
+int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,\r
+ struct sockaddr *dst_addr, int timeout_ms);\r
+\r
+/**\r
+ * rdma_resolve_route - Resolve the route information needed to establish a connection.\r
+ * @id: RDMA identifier.\r
+ * @timeout_ms: Time to wait for resolution to complete.\r
+ * Description:\r
+ * Resolves an RDMA route to the destination address in order to establish\r
+ * a connection. The destination address must have already been resolved\r
+ * by calling rdma_resolve_addr.\r
+ * Notes:\r
+ * This is called on the client side of a connection after calling\r
+ * rdma_resolve_addr, but before calling rdma_connect.\r
+ * See also:\r
+ * rdma_resolve_addr, rdma_connect, rdma_get_cm_event\r
+ */\r
+__declspec(dllexport)\r
+int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms);\r
+\r
+/**\r
+ * rdma_create_qp - Allocate a QP.\r
+ * @id: RDMA identifier.\r
+ * @pd: protection domain for the QP.\r
+ * @qp_init_attr: initial QP attributes.\r
+ * Description:\r
+ * Allocate a QP associated with the specified rdma_cm_id and transition it\r
+ * for sending and receiving.\r
+ * Notes:\r
+ * The rdma_cm_id must be bound to a local RDMA device before calling this\r
+ * function, and the protection domain must be for that same device.\r
+ * QPs allocated to an rdma_cm_id are automatically transitioned by the\r
+ * librdmacm through their states. After being allocated, the QP will be\r
+ * ready to handle posting of receives. If the QP is unconnected, it will\r
+ * be ready to post sends.\r
+ * See also:\r
+ * rdma_bind_addr, rdma_resolve_addr, rdma_destroy_qp, ibv_create_qp,\r
+ * ibv_modify_qp\r
+ */\r
+__declspec(dllexport)\r
+int rdma_create_qp(struct rdma_cm_id *id, struct ibv_pd *pd,\r
+ struct ibv_qp_init_attr *qp_init_attr);\r
+\r
+/**\r
+ * rdma_destroy_qp - Deallocate a QP.\r
+ * @id: RDMA identifier.\r
+ * Description:\r
+ * Destroy a QP allocated on the rdma_cm_id.\r
+ * Notes:\r
+ * Users must destroy any QP associated with an rdma_cm_id before\r
+ * destroying the ID.\r
+ * See also:\r
+ * rdma_create_qp, rdma_destroy_id, ibv_destroy_qp\r
+ */\r
+__declspec(dllexport)\r
+void rdma_destroy_qp(struct rdma_cm_id *id);\r
+\r
+/**\r
+ * rdma_connect - Initiate an active connection request.\r
+ * @id: RDMA identifier.\r
+ * @conn_param: connection parameters.\r
+ * Description:\r
+ * For a connected rdma_cm_id, this call initiates a connection request\r
+ * to a remote destination. For an unconnected rdma_cm_id, it initiates\r
+ * a lookup of the remote QP providing the datagram service.\r
+ * Notes:\r
+ * Users must have resolved a route to the destination address\r
+ * by having called rdma_resolve_route before calling this routine.\r
+ * See also:\r
+ * rdma_resolve_route, rdma_disconnect, rdma_listen, rdma_get_cm_event\r
+ */\r
+__declspec(dllexport)\r
+int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param);\r
+\r
+/**\r
+ * rdma_listen - Listen for incoming connection requests.\r
+ * @id: RDMA identifier.\r
+ * @backlog: backlog of incoming connection requests.\r
+ * Description:\r
+ * Initiates a listen for incoming connection requests or datagram service\r
+ * lookup. The listen will be restricted to the locally bound source\r
+ * address.\r
+ * Notes:\r
+ * Users must have bound the rdma_cm_id to a local address by calling\r
+ * rdma_bind_addr before calling this routine. If the rdma_cm_id is\r
+ * bound to a specific IP address, the listen will be restricted to that\r
+ * address and the associated RDMA device. If the rdma_cm_id is bound\r
+ * to an RDMA port number only, the listen will occur across all RDMA\r
+ * devices.\r
+ * See also:\r
+ * rdma_bind_addr, rdma_connect, rdma_accept, rdma_reject, rdma_get_cm_event\r
+ */\r
+__declspec(dllexport)\r
+int rdma_listen(struct rdma_cm_id *id, int backlog);\r
+\r
+/**\r
+ * rdma_accept - Called to accept a connection request.\r
+ * @id: Connection identifier associated with the request.\r
+ * @conn_param: Information needed to establish the connection.\r
+ * Description:\r
+ * Called from the listening side to accept a connection or datagram\r
+ * service lookup request.\r
+ * Notes:\r
+ * Unlike the socket accept routine, rdma_accept is not called on a\r
+ * listening rdma_cm_id. Instead, after calling rdma_listen, the user\r
+ * waits for a connection request event to occur. Connection request\r
+ * events give the user a newly created rdma_cm_id, similar to a new\r
+ * socket, but the rdma_cm_id is bound to a specific RDMA device.\r
+ * rdma_accept is called on the new rdma_cm_id.\r
+ * See also:\r
+ * rdma_listen, rdma_reject, rdma_get_cm_event\r
+ */\r
+__declspec(dllexport)\r
+int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param);\r
+\r
+/**\r
+ * rdma_reject - Called to reject a connection request.\r
+ * @id: Connection identifier associated with the request.\r
+ * @private_data: Optional private data to send with the reject message.\r
+ * @private_data_len: Size of the private_data to send, in bytes.\r
+ * Description:\r
+ * Called from the listening side to reject a connection or datagram\r
+ * service lookup request.\r
+ * Notes:\r
+ * After receiving a connection request event, a user may call rdma_reject\r
+ * to reject the request. If the underlying RDMA transport supports\r
+ * private data in the reject message, the specified data will be passed to\r
+ * the remote side.\r
+ * See also:\r
+ * rdma_listen, rdma_accept, rdma_get_cm_event\r
+ */\r
+__declspec(dllexport)\r
+int rdma_reject(struct rdma_cm_id *id, const void *private_data,\r
+ uint8_t private_data_len);\r
+\r
+/**\r
+ * rdma_notify - Notifies the librdmacm of an asynchronous event.\r
+ * @id: RDMA identifier.\r
+ * @event: Asynchronous event.\r
+ * Description:\r
+ * Used to notify the librdmacm of asynchronous events that have occurred\r
+ * on a QP associated with the rdma_cm_id.\r
+ * Notes:\r
+ * Asynchronous events that occur on a QP are reported through the user's\r
+ * device event handler. This routine is used to notify the librdmacm of\r
+ * communication events. In most cases, use of this routine is not\r
+ * necessary, however if connection establishment is done out of band\r
+ * (such as done through Infiniband), it's possible to receive data on a\r
+ * QP that is not yet considered connected. This routine forces the\r
+ * connection into an established state in this case in order to handle\r
+ * the rare situation where the connection never forms on its own.\r
+ * Events that should be reported to the CM are: IB_EVENT_COMM_EST.\r
+ * See also:\r
+ * rdma_connect, rdma_accept, rdma_listen\r
+ */\r
+__declspec(dllexport)\r
+int rdma_notify(struct rdma_cm_id *id, enum ibv_event_type event);\r
+\r
+/**\r
+ * rdma_disconnect - This function disconnects a connection.\r
+ * @id: RDMA identifier.\r
+ * Description:\r
+ * Disconnects a connection and transitions any associated QP to the\r
+ * error state.\r
+ * See also:\r
+ * rdma_connect, rdma_listen, rdma_accept\r
+ */\r
+__declspec(dllexport)\r
+int rdma_disconnect(struct rdma_cm_id *id);\r
+\r
+/**\r
+ * rdma_join_multicast - Joins a multicast group.\r
+ * @id: Communication identifier associated with the request.\r
+ * @addr: Multicast address identifying the group to join.\r
+ * @context: User-defined context associated with the join request.\r
+ * Description:\r
+ * Joins a multicast group and attaches an associated QP to the group.\r
+ * Notes:\r
+ * Before joining a multicast group, the rdma_cm_id must be bound to\r
+ * an RDMA device by calling rdma_bind_addr or rdma_resolve_addr. Use of\r
+ * rdma_resolve_addr requires the local routing tables to resolve the\r
+ * multicast address to an RDMA device. The user must call\r
+ * rdma_leave_multicast to leave the multicast group and release any\r
+ * multicast resources. The context is returned to the user through\r
+ * the private_data field in the rdma_cm_event.\r
+ * See also:\r
+ * rdma_leave_multicast, rdma_bind_addr, rdma_resolve_addr, rdma_create_qp\r
+ */\r
+__declspec(dllexport)\r
+int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,\r
+ void *context);\r
+\r
+/**\r
+ * rdma_leave_multicast - Leaves a multicast group.\r
+ * @id: Communication identifier associated with the request.\r
+ * @addr: Multicast address identifying the group to leave.\r
+ * Description:\r
+ * Leaves a multicast group and detaches an associated QP from the group.\r
+ * Notes:\r
+ * Calling this function before a group has been fully joined results in\r
+ * canceling the join operation. Users should be aware that messages\r
+ * received from the multicast group may stilled be queued for\r
+ * completion processing immediately after leaving a multicast group.\r
+ * Destroying an rdma_cm_id will automatically leave all multicast groups.\r
+ * See also:\r
+ * rdma_join_multicast, rdma_destroy_qp\r
+ */\r
+__declspec(dllexport)\r
+int rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr);\r
+\r
+/**\r
+ * rdma_get_cm_event - Retrieves the next pending communication event.\r
+ * @channel: Event channel to check for events.\r
+ * @event: Allocated information about the next communication event.\r
+ * Description:\r
+ * Retrieves a communication event. If no events are pending, by default,\r
+ * the call will block until an event is received.\r
+ * Notes:\r
+ * The default synchronous behavior of this routine can be changed by\r
+ * modifying the file descriptor associated with the given channel. All\r
+ * events that are reported must be acknowledged by calling rdma_ack_cm_event.\r
+ * Destruction of an rdma_cm_id will block until related events have been\r
+ * acknowledged.\r
+ * See also:\r
+ * rdma_ack_cm_event, rdma_create_event_channel, rdma_event_str\r
+ */\r
+__declspec(dllexport)\r
+int rdma_get_cm_event(struct rdma_event_channel *channel,\r
+ struct rdma_cm_event **event);\r
+\r
+/**\r
+ * rdma_ack_cm_event - Free a communication event.\r
+ * @event: Event to be released.\r
+ * Description:\r
+ * All events which are allocated by rdma_get_cm_event must be released,\r
+ * there should be a one-to-one correspondence between successful gets\r
+ * and acks.\r
+ * See also:\r
+ * rdma_get_cm_event, rdma_destroy_id\r
+ */\r
+__declspec(dllexport)\r
+int rdma_ack_cm_event(struct rdma_cm_event *event);\r
+\r
+static uint16_t rdma_get_src_port(struct rdma_cm_id *id)\r
+{\r
+ return id->route.addr.src_addr.sa_family == PF_INET6 ?\r
+ ((struct sockaddr_in6 *) &id->route.addr.src_addr)->sin6_port :\r
+ ((struct sockaddr_in *) &id->route.addr.src_addr)->sin_port;\r
+}\r
+\r
+static uint16_t rdma_get_dst_port(struct rdma_cm_id *id)\r
+{\r
+ return id->route.addr.dst_addr.sa_family == PF_INET6 ?\r
+ ((struct sockaddr_in6 *) &id->route.addr.dst_addr)->sin6_port :\r
+ ((struct sockaddr_in *) &id->route.addr.dst_addr)->sin_port;\r
+}\r
+\r
+static struct sockaddr *rdma_get_local_addr(struct rdma_cm_id *id)\r
+{\r
+ return &id->route.addr.src_addr;\r
+}\r
+\r
+static struct sockaddr *rdma_get_peer_addr(struct rdma_cm_id *id)\r
+{\r
+ return &id->route.addr.dst_addr;\r
+}\r
+\r
+/**\r
+ * rdma_get_devices - Get list of RDMA devices currently available.\r
+ * @num_devices: If non-NULL, set to the number of devices returned.\r
+ * Description:\r
+ * Return a NULL-terminated array of opened RDMA devices. Callers can use\r
+ * this routine to allocate resources on specific RDMA devices that will be\r
+ * shared across multiple rdma_cm_id's.\r
+ * Notes:\r
+ * The returned array must be released by calling rdma_free_devices. Devices\r
+ * remain opened while the librdmacm is loaded.\r
+ * See also:\r
+ * rdma_free_devices\r
+ */\r
+__declspec(dllexport)\r
+struct ibv_context **rdma_get_devices(int *num_devices);\r
+\r
+/**\r
+ * rdma_free_devices - Frees the list of devices returned by rdma_get_devices.\r
+ * @list: List of devices returned from rdma_get_devices.\r
+ * Description:\r
+ * Frees the device array returned by rdma_get_devices.\r
+ * See also:\r
+ * rdma_get_devices\r
+ */\r
+__declspec(dllexport)\r
+void rdma_free_devices(struct ibv_context **list);\r
+\r
+/**\r
+ * rdma_event_str - Returns a string representation of an rdma cm event.\r
+ * @event: Asynchronous event.\r
+ * Description:\r
+ * Returns a string representation of an asynchronous event.\r
+ * See also:\r
+ * rdma_get_cm_event\r
+ */\r
+__declspec(dllexport)\r
+const char *rdma_event_str(enum rdma_cm_event_type event);\r
+\r
+/* Option levels */\r
+enum\r
+{\r
+ RDMA_OPTION_ID = 0\r
+};\r
+\r
+/* Option details */\r
+enum\r
+{\r
+ RDMA_OPTION_ID_TOS = 0 /* uint8_t: RFC 2474 */\r
+};\r
+\r
+/**\r
+ * rdma_set_option - Set options for an rdma_cm_id.\r
+ * @id: Communication identifier to set option for.\r
+ * @level: Protocol level of the option to set.\r
+ * @optname: Name of the option to set.\r
+ * @optval: Reference to the option data.\r
+ * @optlen: The size of the %optval buffer.\r
+ */\r
+__declspec(dllexport)\r
+int rdma_set_option(struct rdma_cm_id *id, int level, int optname,\r
+ void *optval, size_t optlen);\r
+\r
+/**\r
+ * rdma_migrate_id - Move an rdma_cm_id to a new event channel.\r
+ * @id: Communication identifier to migrate.\r
+ * @channel: New event channel for rdma_cm_id events.\r
+ */\r
+__declspec(dllexport)\r
+int rdma_migrate_id(struct rdma_cm_id *id, struct rdma_event_channel *channel);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* RDMA_CMA_H */\r
--- /dev/null
+!if $(FREEBUILD)\r
+TARGETNAME = librdmacm\r
+!else\r
+TARGETNAME = librdmacmd\r
+!endif\r
+\r
+TARGETPATH = ..\..\..\bin\user\obj$(BUILD_ALT_DIR)\r
+TARGETTYPE = DYNLINK\r
+\r
+!if $(_NT_TOOLS_VERSION) == 0x700\r
+DLLDEF = $O\cma_exports.def\r
+!else\r
+DLLDEF = $(OBJ_PATH)\$O\cma_exports.def\r
+!endif\r
+\r
+DLLENTRY = DllMain\r
+USE_MSVCRT = 1\r
+\r
+SOURCES = \\r
+ cma.rc \\r
+ cma_main.cpp \\r
+ cma.cpp\r
+\r
+INCLUDES = ..\include;..\..\..\inc;..\..\..\inc\user;..\..\libibverbs\include\r
+\r
+USER_C_FLAGS = $(USER_C_FLAGS) -DEXPORT_CMA_SYMBOLS\r
+\r
+TARGETLIBS = \\r
+ $(SDK_LIB_PATH)\kernel32.lib \\r
+ $(SDK_LIB_PATH)\uuid.lib \\r
+ $(SDK_LIB_PATH)\ws2_32.lib \\r
+ $(SDK_LIB_PATH)\iphlpapi.lib \\r
+ $(TARGETPATH)\*\ibat.lib \\r
+!if $(FREEBUILD)\r
+ $(TARGETPATH)\*\libibverbs.lib \\r
+ $(TARGETPATH)\*\winverbs.lib\r
+!else\r
+ $(TARGETPATH)\*\libibverbsd.lib \\r
+ $(TARGETPATH)\*\winverbsd.lib\r
+!endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2005-2009 Intel Corporation. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+#include <windows.h>\r
+#include <winsock2.h>\r
+#include <stdio.h>\r
+#include <iphlpapi.h>\r
+\r
+#include <rdma/rdma_cma.h>\r
+#include <infiniband/verbs.h>\r
+#include <iba/ibat.h>\r
+#include "cma.h"\r
+\r
+IWVProvider *prov;\r
+__declspec(dllexport)\r
+IWVProvider *ibv_get_winverbs(void);\r
+\r
+enum cma_state\r
+{\r
+ cma_idle,\r
+ cma_listening,\r
+ cma_get_request,\r
+ cma_addr_resolve,\r
+ cma_route_resolve,\r
+ cma_passive_connect,\r
+ cma_active_connect,\r
+ cma_active_accept,\r
+ cma_accepting,\r
+ cma_connected,\r
+ cma_active_disconnect,\r
+ cma_passive_disconnect,\r
+ cma_disconnected\r
+};\r
+\r
+#define CMA_DEFAULT_BACKLOG 16\r
+\r
+struct cma_id_private\r
+{\r
+ struct rdma_cm_id id;\r
+ enum cma_state state;\r
+ int channel_index;\r
+ struct cma_device *cma_dev;\r
+ int backlog;\r
+ int index;\r
+ struct rdma_cm_id **req_list;\r
+};\r
+\r
+struct cma_event_channel\r
+{\r
+ struct rdma_event_channel channel;\r
+ CRITICAL_SECTION lock;\r
+ struct cma_id_private *id[MAXIMUM_WAIT_OBJECTS];\r
+ HANDLE event[MAXIMUM_WAIT_OBJECTS];\r
+ int count;\r
+};\r
+\r
+struct cma_device\r
+{\r
+ struct ibv_context *verbs;\r
+ uint64_t guid;\r
+ int port_cnt;\r
+ uint8_t max_initiator_depth;\r
+ uint8_t max_responder_resources;\r
+};\r
+\r
+struct cma_event {\r
+ struct rdma_cm_event event;\r
+ uint8_t private_data[56];\r
+ struct cma_id_private *id_priv;\r
+};\r
+\r
+static struct cma_device *cma_dev_array;\r
+static int cma_dev_cnt;\r
+\r
+static void ucma_cleanup(void)\r
+{\r
+ if (cma_dev_cnt > 0) {\r
+ while (cma_dev_cnt > 0) {\r
+ ibv_close_device(cma_dev_array[--cma_dev_cnt].verbs);\r
+ }\r
+ delete cma_dev_array;\r
+ cma_dev_cnt = 0;\r
+ }\r
+ if (prov != NULL) {\r
+ prov->Release();\r
+ prov = NULL;\r
+ }\r
+}\r
+\r
+static int ucma_init(void)\r
+{\r
+ struct ibv_device **dev_list = NULL;\r
+ struct cma_device *cma_dev;\r
+ struct ibv_device_attr attr;\r
+ int i, ret;\r
+\r
+ EnterCriticalSection(&lock);\r
+ if (cma_dev_cnt > 0) {\r
+ goto out;\r
+ }\r
+\r
+ prov = ibv_get_winverbs();\r
+ if (prov == NULL) {\r
+ ret = -1;\r
+ goto err;\r
+ }\r
+\r
+ dev_list = ibv_get_device_list(&cma_dev_cnt);\r
+ if (dev_list == NULL) {\r
+ ret = -1;\r
+ goto err;\r
+ }\r
+\r
+ cma_dev_array = new struct cma_device[cma_dev_cnt];\r
+ if (cma_dev_array == NULL) {\r
+ ret = -1;\r
+ goto err;\r
+ }\r
+\r
+ for (i = 0; dev_list[i]; ++i) {\r
+ cma_dev = &cma_dev_array[i];\r
+\r
+ cma_dev->guid = ibv_get_device_guid(dev_list[i]);\r
+ cma_dev->verbs = ibv_open_device(dev_list[i]);\r
+ if (cma_dev->verbs == NULL) {\r
+ ret = -1;\r
+ goto err;\r
+ }\r
+\r
+ ret = ibv_query_device(cma_dev->verbs, &attr);\r
+ if (ret) {\r
+ goto err;\r
+ }\r
+\r
+ cma_dev->port_cnt = attr.phys_port_cnt;\r
+ cma_dev->max_initiator_depth = (uint8_t) attr.max_qp_init_rd_atom;\r
+ cma_dev->max_responder_resources = (uint8_t) attr.max_qp_rd_atom;\r
+ }\r
+ ibv_free_device_list(dev_list);\r
+out:\r
+ LeaveCriticalSection(&lock);\r
+ return 0;\r
+\r
+err:\r
+ ucma_cleanup();\r
+ LeaveCriticalSection(&lock);\r
+ if (dev_list) {\r
+ ibv_free_device_list(dev_list);\r
+ }\r
+ return ret;\r
+}\r
+\r
+__declspec(dllexport)\r
+struct ibv_context **rdma_get_devices(int *num_devices)\r
+{\r
+ struct ibv_context **devs = NULL;\r
+ int i;\r
+\r
+ if (!cma_dev_cnt && ucma_init()) {\r
+ goto out;\r
+ }\r
+\r
+ devs = new struct ibv_context *[cma_dev_cnt + 1];\r
+ if (devs == NULL) {\r
+ goto out;\r
+ }\r
+\r
+ for (i = 0; i < cma_dev_cnt; i++) {\r
+ devs[i] = cma_dev_array[i].verbs;\r
+ }\r
+ devs[i] = NULL;\r
+out:\r
+ if (num_devices != NULL) {\r
+ *num_devices = devs ? cma_dev_cnt : 0;\r
+ }\r
+ return devs;\r
+}\r
+\r
+__declspec(dllexport)\r
+void rdma_free_devices(struct ibv_context **list)\r
+{\r
+ delete list;\r
+}\r
+\r
+__declspec(dllexport)\r
+struct rdma_event_channel *rdma_create_event_channel(void)\r
+{\r
+ struct cma_event_channel *chan;\r
+\r
+ if (!cma_dev_cnt && ucma_init()) {\r
+ return NULL;\r
+ }\r
+\r
+ chan = new struct cma_event_channel;\r
+ if (chan == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ InitializeCriticalSection(&chan->lock);\r
+ chan->count = 0;\r
+ chan->channel.timeout = INFINITE;\r
+\r
+ return &chan->channel;\r
+}\r
+\r
+__declspec(dllexport)\r
+void rdma_destroy_event_channel(struct rdma_event_channel *channel)\r
+{\r
+ struct cma_event_channel *chan;\r
+\r
+ chan = CONTAINING_RECORD(channel, struct cma_event_channel, channel);\r
+ DeleteCriticalSection(&chan->lock); \r
+ delete chan;\r
+}\r
+\r
+static int cma_event_channel_insert_id(struct rdma_event_channel *channel,\r
+ struct cma_id_private *id_priv)\r
+{\r
+ struct cma_event_channel *chan;\r
+ int ret = 0;\r
+\r
+ chan = CONTAINING_RECORD(channel, struct cma_event_channel, channel);\r
+\r
+ EnterCriticalSection(&chan->lock);\r
+ if (chan->count == MAXIMUM_WAIT_OBJECTS) {\r
+ ret = -1;\r
+ goto out;\r
+ }\r
+\r
+ chan->id[chan->count] = id_priv;\r
+ chan->event[chan->count] = id_priv->id.overlap.hEvent;\r
+ id_priv->channel_index = chan->count++;\r
+out:\r
+ LeaveCriticalSection(&chan->lock);\r
+ return ret;\r
+}\r
+\r
+/*\r
+ * TODO: we cannot call cma_event_channel_remove_id() while another\r
+ * thread is calling rdma_get_event(). If this is needed, then we\r
+ * need to halt the rdma_get_event() thread, modify the event list,\r
+ * then restart the rdma_get_event() thread.\r
+ */\r
+static void cma_event_channel_remove_id(struct rdma_event_channel *channel,\r
+ struct cma_id_private *id_priv)\r
+{\r
+ struct cma_event_channel *chan;\r
+\r
+ chan = CONTAINING_RECORD(channel, struct cma_event_channel, channel);\r
+\r
+ EnterCriticalSection(&chan->lock);\r
+ chan->count--;\r
+ chan->id[id_priv->channel_index] = chan->id[chan->count];\r
+ chan->event[id_priv->channel_index] = chan->event[chan->count];\r
+ chan->id[id_priv->channel_index]->channel_index = id_priv->channel_index;\r
+ LeaveCriticalSection(&chan->lock);\r
+}\r
+\r
+__declspec(dllexport)\r
+int rdma_create_id(struct rdma_event_channel *channel,\r
+ struct rdma_cm_id **id, void *context,\r
+ enum rdma_port_space ps)\r
+{\r
+ struct cma_id_private *id_priv;\r
+ HRESULT hr;\r
+\r
+ hr = cma_dev_cnt ? 0 : ucma_init();\r
+ if (hr) {\r
+ return hr;\r
+ }\r
+\r
+ id_priv = new struct cma_id_private;\r
+ if (id_priv == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ RtlZeroMemory(id_priv, sizeof(struct cma_id_private));\r
+ id_priv->id.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);\r
+ if (id_priv->id.overlap.hEvent == NULL) {\r
+ goto err1;\r
+ }\r
+\r
+ id_priv->id.context = context;\r
+ id_priv->id.channel = channel;\r
+ id_priv->id.ps = ps;\r
+\r
+ if (ps == RDMA_PS_TCP) {\r
+ hr = prov->CreateConnectEndpoint(&id_priv->id.ep.connect);\r
+ } else {\r
+ hr = prov->CreateDatagramEndpoint(&id_priv->id.ep.datagram);\r
+ }\r
+ if (FAILED(hr)) {\r
+ goto err2;\r
+ }\r
+\r
+ hr = cma_event_channel_insert_id(channel, id_priv);\r
+ if (FAILED(hr)) {\r
+ goto err3;\r
+ }\r
+\r
+ *id = &id_priv->id;\r
+ return 0;\r
+\r
+err3:\r
+ if (ps == RDMA_PS_TCP) {\r
+ id_priv->id.ep.connect->Release();\r
+ } else {\r
+ id_priv->id.ep.datagram->Release();\r
+ }\r
+err2:\r
+ CloseHandle(id_priv->id.overlap.hEvent);\r
+err1:\r
+ delete id_priv;\r
+ return -1;\r
+}\r
+\r
+static void ucma_destroy_listen(struct cma_id_private *id_priv)\r
+{\r
+ while (--id_priv->backlog >= 0) {\r
+ if (id_priv->req_list[id_priv->backlog] != NULL) {\r
+ rdma_destroy_id(id_priv->req_list[id_priv->backlog]);\r
+ }\r
+ }\r
+\r
+ delete id_priv->req_list;\r
+}\r
+\r
+__declspec(dllexport)\r
+int rdma_destroy_id(struct rdma_cm_id *id)\r
+{\r
+ struct cma_id_private *id_priv;\r
+\r
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
+ if (id->ps == RDMA_PS_TCP) {\r
+ id->ep.connect->CancelOverlappedRequests();\r
+ } else {\r
+ id->ep.datagram->CancelOverlappedRequests();\r
+ }\r
+\r
+ cma_event_channel_remove_id(id->channel, id_priv);\r
+\r
+ if (id_priv->backlog > 0) {\r
+ ucma_destroy_listen(id_priv);\r
+ }\r
+\r
+ if (id_priv->id.ps == RDMA_PS_TCP) {\r
+ id_priv->id.ep.connect->Release();\r
+ } else {\r
+ id_priv->id.ep.datagram->Release();\r
+ }\r
+\r
+ delete id_priv;\r
+ return 0;\r
+}\r
+\r
+static int ucma_addrlen(struct sockaddr *addr)\r
+{\r
+ if (addr->sa_family == PF_INET) {\r
+ return sizeof(struct sockaddr_in);\r
+ } else {\r
+ return sizeof(struct sockaddr_in6);\r
+ }\r
+}\r
+\r
+static int ucma_get_device(struct cma_id_private *id_priv, uint64_t guid)\r
+{\r
+ struct cma_device *cma_dev;\r
+ int i;\r
+\r
+ for (i = 0; i < cma_dev_cnt; i++) {\r
+ cma_dev = &cma_dev_array[i];\r
+ if (cma_dev->guid == guid) {\r
+ id_priv->cma_dev = cma_dev;\r
+ id_priv->id.verbs = cma_dev->verbs;\r
+ return 0;\r
+ }\r
+ }\r
+ return -1;\r
+}\r
+\r
+static int ucma_query_connect(struct rdma_cm_id *id, struct rdma_conn_param *param)\r
+{\r
+ struct cma_id_private *id_priv;\r
+ WV_CONNECT_ATTRIBUTES attr;\r
+ HRESULT hr;\r
+\r
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
+ hr = id->ep.connect->Query(&attr);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+\r
+ RtlCopyMemory(&id->route.addr.src_addr, &attr.LocalAddress,\r
+ sizeof attr.LocalAddress);\r
+ RtlCopyMemory(&id->route.addr.dst_addr, &attr.PeerAddress,\r
+ sizeof attr.PeerAddress);\r
+\r
+ if (param != NULL) {\r
+ RtlCopyMemory((void *) param->private_data, attr.Param.Data,\r
+ attr.Param.DataLength);\r
+ param->private_data_len = (uint8_t) attr.Param.DataLength;\r
+ param->responder_resources = (uint8_t) attr.Param.ResponderResources;\r
+ param->initiator_depth = (uint8_t) attr.Param.InitiatorDepth;\r
+ param->flow_control = 1;\r
+ param->retry_count = attr.Param.RetryCount;\r
+ param->rnr_retry_count = attr.Param.RnrRetryCount;\r
+ }\r
+\r
+ if (id_priv->cma_dev == NULL && attr.Device.DeviceGuid != 0) {\r
+ hr = ucma_get_device(id_priv, attr.Device.DeviceGuid);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+\r
+ id->route.addr.addr.ibaddr.pkey = attr.Device.Pkey;\r
+ id_priv->id.port_num = attr.Device.PortNumber;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+static int ucma_query_datagram(struct rdma_cm_id *id, struct rdma_ud_param *param)\r
+{\r
+ struct cma_id_private *id_priv;\r
+ WV_DATAGRAM_ATTRIBUTES attr;\r
+ HRESULT hr;\r
+\r
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
+ hr = id->ep.datagram->Query(&attr);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+\r
+ RtlCopyMemory(&id->route.addr.src_addr, &attr.LocalAddress,\r
+ sizeof attr.LocalAddress);\r
+ RtlCopyMemory(&id->route.addr.dst_addr, &attr.PeerAddress,\r
+ sizeof attr.PeerAddress);\r
+\r
+ if (param != NULL) {\r
+ RtlCopyMemory((void *) param->private_data, attr.Param.Data,\r
+ attr.Param.DataLength);\r
+ param->private_data_len = (uint8_t) attr.Param.DataLength;\r
+ // ucma_convert_av(&attr.Param.AddressVector, param->ah_attr)\r
+ param->qp_num = attr.Param.Qpn;\r
+ param->qkey = attr.Param.Qkey;\r
+ }\r
+\r
+ if (id_priv->cma_dev == NULL && attr.Device.DeviceGuid != 0) {\r
+ hr = ucma_get_device(id_priv, attr.Device.DeviceGuid);\r
+ if (FAILED(hr))\r
+ return hr;\r
+ id->route.addr.addr.ibaddr.pkey = attr.Device.Pkey;\r
+ id_priv->id.port_num = attr.Device.PortNumber;\r
+ }\r
+ return 0;\r
+}\r
+\r
+__declspec(dllexport)\r
+int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)\r
+{\r
+ HRESULT hr;\r
+\r
+ if (id->ps == RDMA_PS_TCP) {\r
+ hr = id->ep.connect->BindAddress(addr);\r
+ if (SUCCEEDED(hr)) {\r
+ hr = ucma_query_connect(id, NULL);\r
+ }\r
+ } else {\r
+ hr = id->ep.datagram->BindAddress(addr);\r
+ if (SUCCEEDED(hr)) {\r
+ hr = ucma_query_datagram(id, NULL);\r
+ }\r
+ }\r
+\r
+ return hr;\r
+}\r
+\r
+__declspec(dllexport)\r
+int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,\r
+ struct sockaddr *dst_addr, int timeout_ms)\r
+{\r
+ struct cma_id_private *id_priv;\r
+ WV_SOCKADDR addr;\r
+ SOCKET s;\r
+ DWORD size;\r
+ HRESULT hr;\r
+\r
+ if (src_addr == NULL) {\r
+ if (id->ps == RDMA_PS_TCP) {\r
+ s = socket(dst_addr->sa_family, SOCK_STREAM, IPPROTO_TCP);\r
+ } else {\r
+ s = socket(dst_addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);\r
+ }\r
+ if (s == INVALID_SOCKET) {\r
+ return WSAGetLastError();\r
+ }\r
+\r
+ hr = WSAIoctl(s, SIO_ROUTING_INTERFACE_QUERY, dst_addr, ucma_addrlen(dst_addr),\r
+ &addr, sizeof addr, &size, NULL, NULL);\r
+ closesocket(s);\r
+ if (FAILED(hr)) {\r
+ return WSAGetLastError();\r
+ }\r
+ src_addr = &addr.Sa;\r
+ }\r
+\r
+ hr = rdma_bind_addr(id, src_addr);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+\r
+ RtlCopyMemory(&id->route.addr.dst_addr, dst_addr, ucma_addrlen(dst_addr));\r
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
+ id_priv->state = cma_addr_resolve;\r
+ SetEvent(id->overlap.hEvent);\r
+ return 0;\r
+}\r
+\r
+__declspec(dllexport)\r
+int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)\r
+{\r
+ struct cma_id_private *id_priv;\r
+ IBAT_PATH_BLOB path;\r
+ HRESULT hr;\r
+\r
+ hr = IBAT::Resolve(&id->route.addr.src_addr, &id->route.addr.dst_addr, &path);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+\r
+ hr = (id->ps == RDMA_PS_TCP) ?\r
+ id->ep.connect->Modify(WV_EP_OPTION_ROUTE, &path, sizeof path) :\r
+ id->ep.datagram->Modify(WV_EP_OPTION_ROUTE, &path, sizeof path);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+\r
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
+ id_priv->state = cma_route_resolve;\r
+ SetEvent(id->overlap.hEvent);\r
+ return 0;\r
+}\r
+\r
+static int ucma_modify_qp_init(struct cma_id_private *id_priv, struct ibv_qp *qp)\r
+{\r
+ struct ibv_qp_attr qp_attr;\r
+ DWORD index;\r
+ HRESULT hr;\r
+\r
+ RtlZeroMemory(&qp_attr, sizeof qp_attr);\r
+ qp_attr.qp_state = IBV_QPS_INIT;\r
+ qp_attr.port_num = id_priv->id.port_num;\r
+ hr = qp->context->cmd_if->FindPkey(id_priv->id.port_num,\r
+ id_priv->id.route.addr.addr.ibaddr.pkey,\r
+ &index);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+\r
+ qp_attr.pkey_index = (uint16_t) index;\r
+ return ibv_modify_qp(qp, &qp_attr, (enum ibv_qp_attr_mask)\r
+ (IBV_QP_STATE | IBV_QP_PKEY_INDEX | IBV_QP_PORT));\r
+}\r
+\r
+static int ucma_init_ud_qp(struct cma_id_private *id_priv, struct ibv_qp *qp)\r
+{\r
+ struct ibv_qp_attr qp_attr;\r
+ int qp_attr_mask, ret;\r
+\r
+ ret = ucma_modify_qp_init(id_priv, qp);\r
+ if (ret) {\r
+ return ret;\r
+ }\r
+\r
+ qp_attr.qp_state = IBV_QPS_RTR;\r
+ ret = ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE);\r
+ if (ret) {\r
+ return ret;\r
+ }\r
+\r
+ qp_attr.qp_state = IBV_QPS_RTS;\r
+ qp_attr.sq_psn = 0;\r
+ return ibv_modify_qp(qp, &qp_attr, (enum ibv_qp_attr_mask)\r
+ (IBV_QP_STATE | IBV_QP_SQ_PSN));\r
+}\r
+\r
+__declspec(dllexport)\r
+int rdma_create_qp(struct rdma_cm_id *id, struct ibv_pd *pd,\r
+ struct ibv_qp_init_attr *qp_init_attr)\r
+{\r
+ struct cma_id_private *id_priv;\r
+ struct ibv_qp *qp;\r
+ int ret;\r
+\r
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
+ if (id->verbs != pd->context) {\r
+ return -1;\r
+ }\r
+\r
+ qp = ibv_create_qp(pd, qp_init_attr);\r
+ if (!qp) {\r
+ return -1;\r
+ }\r
+\r
+ if (id->ps == RDMA_PS_TCP) {\r
+ ret = ucma_modify_qp_init(id_priv, qp);\r
+ } else {\r
+ ret = ucma_init_ud_qp(id_priv, qp);\r
+ }\r
+ if (ret) {\r
+ goto err;\r
+ }\r
+\r
+ id->qp = qp;\r
+ return 0;\r
+err:\r
+ ibv_destroy_qp(qp);\r
+ return ret;\r
+}\r
+\r
+__declspec(dllexport)\r
+void rdma_destroy_qp(struct rdma_cm_id *id)\r
+{\r
+ ibv_destroy_qp(id->qp);\r
+}\r
+\r
+static int ucma_valid_param(struct cma_id_private *id_priv,\r
+ struct rdma_conn_param *conn_param)\r
+{\r
+ if (id_priv->id.ps != RDMA_PS_TCP) {\r
+ return 0;\r
+ }\r
+\r
+ if ((conn_param->responder_resources > id_priv->cma_dev->max_responder_resources) ||\r
+ (conn_param->initiator_depth > id_priv->cma_dev->max_initiator_depth)) {\r
+ return -1;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+__declspec(dllexport)\r
+int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)\r
+{\r
+ struct cma_id_private *id_priv;\r
+ WV_CONNECT_PARAM attr;\r
+ HRESULT hr;\r
+ \r
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
+ hr = ucma_valid_param(id_priv, conn_param);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+\r
+ RtlZeroMemory(&attr, sizeof attr);\r
+ attr.ResponderResources = conn_param->responder_resources;\r
+ attr.InitiatorDepth = conn_param->initiator_depth;\r
+ attr.RetryCount = conn_param->retry_count;\r
+ attr.RnrRetryCount = conn_param->rnr_retry_count;\r
+ if ((attr.DataLength = conn_param->private_data_len)) {\r
+ RtlCopyMemory(attr.Data, conn_param->private_data, attr.DataLength);\r
+ }\r
+\r
+ id_priv->state = cma_active_connect;\r
+ hr = id->ep.connect->Connect(id->qp->conn_handle, &id->route.addr.dst_addr,\r
+ &attr, &id->overlap);\r
+ if (FAILED(hr) && hr != WV_IO_PENDING) {\r
+ id_priv->state = cma_route_resolve;\r
+ return hr;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+static int ucma_get_request(struct cma_id_private *listen, int index)\r
+{\r
+ struct cma_id_private *id_priv;\r
+ HRESULT hr;\r
+\r
+ hr = rdma_create_id(listen->id.channel, &listen->req_list[index],\r
+ listen, listen->id.ps);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+\r
+ id_priv = CONTAINING_RECORD(listen->req_list[index], struct cma_id_private, id);\r
+ id_priv->index = index;\r
+ id_priv->state = cma_get_request;\r
+\r
+ if (listen->id.ps == RDMA_PS_TCP) {\r
+ hr = listen->id.ep.connect->GetRequest(id_priv->id.ep.connect,\r
+ &id_priv->id.overlap);\r
+ } else {\r
+ hr = listen->id.ep.datagram->GetRequest(id_priv->id.ep.datagram,\r
+ &id_priv->id.overlap);\r
+ }\r
+\r
+ return (FAILED(hr) && hr != WV_IO_PENDING) ? hr : 0;\r
+}\r
+\r
+__declspec(dllexport)\r
+int rdma_listen(struct rdma_cm_id *id, int backlog)\r
+{\r
+ struct cma_id_private *id_priv, *req_id;\r
+ HRESULT hr;\r
+ int i;\r
+\r
+ if (backlog <= 0 || backlog > CMA_DEFAULT_BACKLOG) {\r
+ backlog = CMA_DEFAULT_BACKLOG;\r
+ }\r
+\r
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
+ id_priv->req_list = new struct rdma_cm_id*[backlog];\r
+ if (id_priv->req_list == NULL) {\r
+ return -1;\r
+ }\r
+\r
+ RtlZeroMemory(id_priv->req_list, sizeof(struct rdma_cm_id *) * backlog);\r
+ id_priv->backlog = backlog;\r
+\r
+ id_priv->state = cma_listening;\r
+ hr = (id->ps == RDMA_PS_TCP) ?\r
+ id->ep.connect->Listen(backlog) : id->ep.datagram->Listen(backlog);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+\r
+ for (i = 0; i < backlog; i++) {\r
+ hr = ucma_get_request(id_priv, i);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+__declspec(dllexport)\r
+int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)\r
+{\r
+ struct cma_id_private *id_priv;\r
+ WV_CONNECT_PARAM attr;\r
+ HRESULT hr;\r
+\r
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
+ hr = ucma_valid_param(id_priv, conn_param);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+\r
+ RtlZeroMemory(&attr, sizeof attr);\r
+ attr.ResponderResources = conn_param->responder_resources;\r
+ attr.InitiatorDepth = conn_param->initiator_depth;\r
+ attr.RetryCount = conn_param->retry_count;\r
+ attr.RnrRetryCount = conn_param->rnr_retry_count;\r
+ if ((attr.DataLength = conn_param->private_data_len)) {\r
+ RtlCopyMemory(attr.Data, conn_param->private_data, attr.DataLength);\r
+ }\r
+\r
+ id_priv->state = cma_accepting;\r
+ hr = id->ep.connect->Accept(id->qp->conn_handle, &attr, &id->overlap);\r
+ if (FAILED(hr) && hr != WV_IO_PENDING) {\r
+ id_priv->state = cma_disconnected;\r
+ return hr;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+__declspec(dllexport)\r
+int rdma_reject(struct rdma_cm_id *id, const void *private_data,\r
+ uint8_t private_data_len)\r
+{\r
+ struct cma_id_private *id_priv;\r
+ HRESULT hr;\r
+\r
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
+ id_priv->state = cma_disconnected;\r
+ hr = id->ep.connect->Reject(private_data, private_data_len);\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+ return 0;\r
+}\r
+\r
+__declspec(dllexport)\r
+int rdma_notify(struct rdma_cm_id *id, enum ibv_event_type event)\r
+{\r
+ return 0;\r
+}\r
+\r
+__declspec(dllexport)\r
+int rdma_disconnect(struct rdma_cm_id *id)\r
+{\r
+ struct cma_id_private *id_priv;\r
+ HRESULT hr;\r
+\r
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
+ if (id_priv->state == cma_connected) {\r
+ id_priv->state = cma_active_disconnect;\r
+ } else {\r
+ id_priv->state = cma_disconnected;\r
+ }\r
+ hr = id->ep.connect->Disconnect();\r
+ if (FAILED(hr)) {\r
+ return hr;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+__declspec(dllexport)\r
+int rdma_ack_cm_event(struct rdma_cm_event *event)\r
+{\r
+ struct cma_event *evt;\r
+\r
+ evt = CONTAINING_RECORD(event, struct cma_event, event);\r
+ delete evt;\r
+ return 0;\r
+}\r
+\r
+static int ucma_process_conn_req(struct cma_event *event)\r
+{\r
+ struct cma_id_private *listen;\r
+ HRESULT hr = 0;\r
+\r
+ listen = (struct cma_id_private *) event->id_priv->id.context;\r
+\r
+ if (SUCCEEDED(event->event.status)) {\r
+ event->event.status = ucma_query_connect(&event->id_priv->id,\r
+ &event->event.param.conn);\r
+ }\r
+\r
+ if (SUCCEEDED(event->event.status)) {\r
+ event->event.event = RDMA_CM_EVENT_CONNECT_REQUEST;\r
+ event->id_priv->state = cma_passive_connect;\r
+\r
+ listen->req_list[event->id_priv->index] = NULL;\r
+ ucma_get_request(listen, event->id_priv->index);\r
+ } else {\r
+ hr = listen->id.ep.connect->GetRequest(event->id_priv->id.ep.connect,\r
+ &event->id_priv->id.overlap);\r
+ if (hr == WV_IO_PENDING) {\r
+ hr = 0;\r
+ }\r
+ }\r
+\r
+ return hr;\r
+}\r
+\r
+static int ucma_process_conn_resp(struct cma_event *event)\r
+{\r
+ struct rdma_cm_id *id;\r
+ WV_CONNECT_PARAM attr;\r
+ HRESULT hr;\r
+\r
+ if (FAILED(event->event.status)) {\r
+ goto err;\r
+ }\r
+\r
+ RtlZeroMemory(&attr, sizeof(attr));\r
+ event->id_priv->state = cma_accepting;\r
+\r
+ id = &event->id_priv->id;\r
+ hr = id->ep.connect->Accept(id->qp->conn_handle, &attr, &id->overlap);\r
+ if (FAILED(hr) && hr != WV_IO_PENDING) {\r
+ event->event.status = hr;\r
+ goto err;\r
+ }\r
+\r
+ return WV_IO_PENDING;\r
+\r
+err:\r
+ event->event.event = RDMA_CM_EVENT_CONNECT_ERROR;\r
+ event->id_priv->state = cma_disconnected;\r
+ return 0;\r
+}\r
+\r
+static void ucma_process_establish(struct cma_event *event)\r
+{\r
+ if (SUCCEEDED(event->event.status)) {\r
+ event->event.event = RDMA_CM_EVENT_ESTABLISHED;\r
+ event->id_priv->state = cma_connected;\r
+\r
+ event->id_priv->id.ep.connect->NotifyDisconnect(&event->id_priv->id.overlap);\r
+ } else {\r
+ event->event.event = RDMA_CM_EVENT_CONNECT_ERROR;\r
+ event->id_priv->state = cma_disconnected;\r
+ }\r
+}\r
+\r
+static int ucma_process_event(struct cma_event *event)\r
+{\r
+ WV_CONNECT_ATTRIBUTES attr;\r
+ HRESULT hr = 0;\r
+\r
+ switch (event->id_priv->state) {\r
+ case cma_get_request:\r
+ hr = ucma_process_conn_req(event);\r
+ break;\r
+ case cma_addr_resolve:\r
+ event->event.event = RDMA_CM_EVENT_ADDR_RESOLVED;\r
+ break;\r
+ case cma_route_resolve:\r
+ event->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;\r
+ break;\r
+ case cma_active_connect:\r
+ hr = ucma_process_conn_resp(event);\r
+ break;\r
+ case cma_accepting:\r
+ ucma_process_establish(event);\r
+ break;\r
+ case cma_connected:\r
+ event->event.event = RDMA_CM_EVENT_DISCONNECTED;\r
+ event->id_priv->state = cma_passive_disconnect;\r
+ break;\r
+ case cma_active_disconnect:\r
+ event->event.event = RDMA_CM_EVENT_DISCONNECTED;\r
+ event->id_priv->state = cma_disconnected;\r
+ break;\r
+ default:\r
+ return -1;\r
+ }\r
+\r
+ return hr;\r
+}\r
+\r
+__declspec(dllexport)\r
+int rdma_get_cm_event(struct rdma_event_channel *channel,\r
+ struct rdma_cm_event **event)\r
+{\r
+ struct cma_event_channel *chan;\r
+ struct cma_event *evt;\r
+ struct cma_id_private *id_priv;\r
+ struct rdma_cm_id *id;\r
+ DWORD bytes;\r
+ HRESULT hr;\r
+\r
+ evt = new struct cma_event;\r
+ if (evt == NULL) {\r
+ return -1;\r
+ }\r
+\r
+ do {\r
+ RtlZeroMemory(evt, sizeof(struct cma_event));\r
+\r
+ chan = CONTAINING_RECORD(channel, struct cma_event_channel, channel);\r
+ hr = WaitForMultipleObjects(chan->count, chan->event, FALSE,\r
+ chan->channel.timeout);\r
+ if (hr == WAIT_TIMEOUT) {\r
+ return hr;\r
+ } else if (hr == WAIT_FAILED) {\r
+ return HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
+\r
+ EnterCriticalSection(&chan->lock);\r
+ evt->id_priv = chan->id[hr];\r
+ LeaveCriticalSection(&chan->lock);\r
+\r
+ id = &evt->id_priv->id;\r
+ evt->event.id = id;\r
+ evt->event.param.conn.private_data = evt->private_data;\r
+ if (id->ep.connect->GetOverlappedResult(&id->overlap, &bytes, FALSE) == 0) {\r
+ evt->event.status = HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
+\r
+ hr = ucma_process_event(evt);\r
+ } while (FAILED(hr));\r
+ \r
+ *event = &evt->event;\r
+ return 0;\r
+}\r
+\r
+\r
+__declspec(dllexport)\r
+int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,\r
+ void *context)\r
+{\r
+ return WV_NOT_SUPPORTED;\r
+}\r
+\r
+__declspec(dllexport)\r
+int rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr)\r
+{\r
+ return WV_NOT_SUPPORTED;\r
+}\r
+\r
+__declspec(dllexport)\r
+const char *rdma_event_str(enum rdma_cm_event_type event)\r
+{\r
+ switch (event) {\r
+ case RDMA_CM_EVENT_ADDR_RESOLVED:\r
+ return "RDMA_CM_EVENT_ADDR_RESOLVED";\r
+ case RDMA_CM_EVENT_ADDR_ERROR:\r
+ return "RDMA_CM_EVENT_ADDR_ERROR";\r
+ case RDMA_CM_EVENT_ROUTE_RESOLVED:\r
+ return "RDMA_CM_EVENT_ROUTE_RESOLVED";\r
+ case RDMA_CM_EVENT_ROUTE_ERROR:\r
+ return "RDMA_CM_EVENT_ROUTE_ERROR";\r
+ case RDMA_CM_EVENT_CONNECT_REQUEST:\r
+ return "RDMA_CM_EVENT_CONNECT_REQUEST";\r
+ case RDMA_CM_EVENT_CONNECT_RESPONSE:\r
+ return "RDMA_CM_EVENT_CONNECT_RESPONSE";\r
+ case RDMA_CM_EVENT_CONNECT_ERROR:\r
+ return "RDMA_CM_EVENT_CONNECT_ERROR";\r
+ case RDMA_CM_EVENT_UNREACHABLE:\r
+ return "RDMA_CM_EVENT_UNREACHABLE";\r
+ case RDMA_CM_EVENT_REJECTED:\r
+ return "RDMA_CM_EVENT_REJECTED";\r
+ case RDMA_CM_EVENT_ESTABLISHED:\r
+ return "RDMA_CM_EVENT_ESTABLISHED";\r
+ case RDMA_CM_EVENT_DISCONNECTED:\r
+ return "RDMA_CM_EVENT_DISCONNECTED";\r
+ case RDMA_CM_EVENT_DEVICE_REMOVAL:\r
+ return "RDMA_CM_EVENT_DEVICE_REMOVAL";\r
+ case RDMA_CM_EVENT_MULTICAST_JOIN:\r
+ return "RDMA_CM_EVENT_MULTICAST_JOIN";\r
+ case RDMA_CM_EVENT_MULTICAST_ERROR:\r
+ return "RDMA_CM_EVENT_MULTICAST_ERROR";\r
+ case RDMA_CM_EVENT_ADDR_CHANGE:\r
+ return "RDMA_CM_EVENT_ADDR_CHANGE";\r
+ case RDMA_CM_EVENT_TIMEWAIT_EXIT:\r
+ return "RDMA_CM_EVENT_TIMEWAIT_EXIT";\r
+ default:\r
+ return "UNKNOWN EVENT";\r
+ }\r
+}\r
+\r
+__declspec(dllexport)\r
+int rdma_set_option(struct rdma_cm_id *id, int level, int optname,\r
+ void *optval, size_t optlen)\r
+{\r
+ return WV_NOT_SUPPORTED;\r
+}\r
+\r
+__declspec(dllexport)\r
+int rdma_migrate_id(struct rdma_cm_id *id, struct rdma_event_channel *channel)\r
+{\r
+ struct cma_id_private *id_priv;\r
+\r
+ id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
+ cma_event_channel_remove_id(id->channel, id_priv);\r
+ /*\r
+ * TODO: To support calling this routine while processing events on the old\r
+ * channel, we need to wait for all old events to be acknowledged.\r
+ */\r
+ id->channel = channel;\r
+ cma_event_channel_insert_id(channel, id_priv);\r
+\r
+ return 0;\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.\r
+ * Copyright (c) 2008-2009 Intel Corp. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+#ifndef CMA_H\r
+#define CMA_H\r
+\r
+extern CRITICAL_SECTION lock;\r
+\r
+__inline void* __cdecl operator new(size_t size)\r
+{\r
+ return HeapAlloc(GetProcessHeap(), 0, size);\r
+}\r
+\r
+__inline void __cdecl operator delete(void *pObj)\r
+{\r
+ HeapFree(GetProcessHeap(), 0, pObj);\r
+}\r
+\r
+#endif /* CMA_H */\r
--- /dev/null
+/*\r
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+\r
+#include <oib_ver.h>\r
+\r
+#define VER_FILETYPE VFT_DLL\r
+#define VER_FILESUBTYPE VFT2_UNKNOWN\r
+\r
+#ifdef _DEBUG_\r
+#define VER_FILEDESCRIPTION_STR "LibRdmaCm (Debug)"\r
+#define VER_INTERNALNAME_STR "librdmacmd.dll"\r
+#define VER_ORIGINALFILENAME_STR "librdmacmd.dll"\r
+#else\r
+#define VER_FILEDESCRIPTION_STR "LibRdmaCm"\r
+#define VER_INTERNALNAME_STR "librdmacm.dll"\r
+#define VER_ORIGINALFILENAME_STR "librdmacm.dll"\r
+#endif\r
+\r
+#include <common.ver>\r
--- /dev/null
+/*\r
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+LIBRARY LIBRDMACM.DLL\r
+\r
+EXPORTS\r
+ DllCanUnloadNow PRIVATE\r
+ DllGetClassObject PRIVATE\r
--- /dev/null
+#if DBG\r
+LIBRARY librdmacmd.dll\r
+#else\r
+LIBRARY librdmacm.dll\r
+#endif\r
+\r
+#ifndef _WIN64\r
+EXPORTS\r
+rdma_create_event_channel\r
+rdma_destroy_event_channel\r
+rdma_create_id\r
+rdma_destroy_id\r
+rdma_bind_addr\r
+rdma_resolve_addr\r
+rdma_resolve_route\r
+rdma_create_qp\r
+rdma_destroy_qp\r
+rdma_connect\r
+rdma_listen\r
+rdma_accept\r
+rdma_reject\r
+rdma_notify\r
+rdma_disconnect\r
+rdma_join_multicast\r
+rdma_leave_multicast\r
+rdma_get_cm_event\r
+rdma_ack_cm_event\r
+rdma_get_devices\r
+rdma_free_devices\r
+rdma_event_str\r
+rdma_set_option\r
+rdma_migrate_id\r
+#endif\r
--- /dev/null
+/*\r
+ * Copyright (c) 2008-2009 Intel Corporation. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+#include <windows.h>\r
+#include "cma.h"\r
+\r
+CRITICAL_SECTION lock;\r
+\r
+BOOLEAN WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)\r
+{\r
+ UNREFERENCED_PARAMETER(hInstance);\r
+ UNREFERENCED_PARAMETER(dwReason);\r
+ UNREFERENCED_PARAMETER(lpReserved);\r
+\r
+ InitializeCriticalSection(&lock);\r
+\r
+ return TRUE;\r
+}\r
--- /dev/null
+#\r
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source\r
+# file to this component. This file merely indirects to the real make file\r
+# that is shared by all the driver components of the OpenIB Windows project.\r
+#\r
+\r
+!INCLUDE ..\..\..\inc\openib.def\r