home *** CD-ROM | disk | FTP | other *** search
/ ftp.parl.clemson.edu / 2015-02-07.ftp.parl.clemson.edu.tar / ftp.parl.clemson.edu / pub / pvfs2 / orangefs-2.8.3-20110323.tar.gz / orangefs-2.8.3-20110323.tar / orangefs / src / io / bmi / bmi_ib / vapi.c < prev   
C/C++ Source or Header  |  2008-02-22  |  34KB  |  1,058 lines

  1. /*
  2.  * VAPI-specific functions.
  3.  *
  4.  * Copyright (C) 2003-6 Pete Wyckoff <pw@osc.edu>
  5.  *
  6.  * See COPYING in top-level directory.
  7.  */
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <stdarg.h>
  11. #include <unistd.h>
  12. #include <fcntl.h>
  13. #include <netinet/in.h>  /* htonl */
  14. #define __PINT_REQPROTO_ENCODE_FUNCS_C  /* include definitions */
  15. #include <src/io/bmi/bmi-method-support.h>   /* struct bmi_method_addr */
  16. #include <src/common/misc/pvfs2-internal.h>
  17. #include <src/io/bmi/bmi-byteswap.h>  /* bmitoh64 */
  18.  
  19. #include "pvfs2-config.h" /* HAVE_IB_WRAP_COMMON_H configure symbol */
  20.  
  21. #include <dlfcn.h>        /* look in mosal for syms */
  22.  
  23. /* otherwise undefined things in mtl_log.h */
  24. #define MAX_TRACE 0
  25. #define MAX_DEBUG 0
  26. #define MAX_ERROR 0
  27.  
  28. #include <vapi.h>
  29. #include <vapi_common.h>
  30. #ifdef HAVE_IB_WRAP_COMMON_H
  31. #include <wrap_common.h>  /* reinit_mosal externs */
  32. #endif
  33.  
  34. #include "ib.h"
  35.  
  36. /*
  37.  * VAPI-private device-wide state.
  38.  */
  39. struct vapi_device_priv {
  40.     VAPI_hca_hndl_t nic_handle;  /* NIC reference */
  41.     VAPI_cq_hndl_t nic_cq;  /* single completion queue for all QPs */
  42.     VAPI_pd_hndl_t nic_pd;  /* single protection domain for all memory/QP */
  43.     IB_lid_t nic_lid;  /* my lid */
  44.  
  45.     /*
  46.      * Temp array for filling scatter/gather lists to pass to IB functions,
  47.      * allocated once at start to max size defined as reported by the qp.
  48.      */
  49.     VAPI_sg_lst_entry_t *sg_tmp_array;
  50.     unsigned int sg_max_len;
  51.  
  52.     /*
  53.      * Maximum number of outstanding work requests in the NIC, same for both
  54.      * SQ and RQ.  Used to decide when to use a SIGNALED completion on a send
  55.      * to avoid WQE buildup.
  56.      */
  57.     unsigned int max_outstanding_wr;
  58.  
  59.     /* async events */
  60.     EVAPI_async_handler_hndl_t nic_async_event_handler;
  61.     int async_event_pipe[2];
  62.  
  63.     /* completion channel events */
  64.     EVAPI_compl_handler_hndl_t nic_cq_event_handler;
  65.     int cq_event_pipe[2];
  66. };
  67.  
  68. /*
  69.  * Per-connection state.
  70.  */
  71. struct vapi_connection_priv {
  72.     /* ib local params */
  73.     VAPI_qp_hndl_t qp;
  74.     VAPI_qp_num_t qp_num;
  75.     VAPI_mr_hndl_t eager_send_mr;
  76.     VAPI_mr_hndl_t eager_recv_mr;
  77.     VAPI_lkey_t eager_send_lkey;  /* for post_sr */
  78.     VAPI_lkey_t eager_recv_lkey;  /* for post_rr */
  79.     unsigned int num_unsignaled_wr;  /* keep track of outstanding WRs */
  80.     /* ib remote params */
  81.     IB_lid_t remote_lid;
  82.     VAPI_qp_num_t remote_qp_num;
  83. };
  84.  
  85. /* constants used to initialize infiniband device */
  86. static const int VAPI_PORT = 1;
  87. static const unsigned int VAPI_NUM_CQ_ENTRIES = 1024;
  88. static const int VAPI_MTU = MTU1024;  /* default mtu, 1k best on mellanox */
  89.  
  90. static int exchange_data(int sock, int is_server, void *xin, void *xout,
  91.                          size_t len);
  92. static void verify_prop_caps(VAPI_qp_cap_t *cap);
  93. static void init_connection_modify_qp(VAPI_qp_hndl_t qp,
  94.   VAPI_qp_num_t remote_qp_num, int remote_lid);
  95. static void vapi_post_rr(const ib_connection_t *c, struct buf_head *bh);
  96. static void __attribute__((noreturn,format(printf,2,3)))
  97.   error_verrno(int ecode, const char *fmt, ...);
  98. int vapi_ib_initialize(void);
  99. static void vapi_ib_finalize(void);
  100.  
  101. /*
  102.  * Build new conneciton and do the QP bringup dance.
  103.  */
  104. static int vapi_new_connection(ib_connection_t *c, int sock, int is_server)
  105. {
  106.     struct vapi_connection_priv *vc;
  107.     struct vapi_device_priv *vd = ib_device->priv;
  108.     int i, ret;
  109.     VAPI_mr_t mr, mr_out;
  110.     VAPI_qp_init_attr_t qp_init_attr;
  111.     VAPI_qp_prop_t prop;
  112.     /* for connection handshake with peer */
  113.     struct {
  114.     IB_lid_t lid;
  115.     VAPI_qp_num_t qp_num;
  116.     } ch_in, ch_out;
  117.  
  118.     vc = bmi_ib_malloc(sizeof(*vc));
  119.     c->priv = vc;
  120.  
  121.     /* register memory region, recv */
  122.     mr.type = VAPI_MR;
  123.     mr.start = int64_from_ptr(c->eager_recv_buf_contig);
  124.     mr.size = ib_device->eager_buf_num * ib_device->eager_buf_size;
  125.     mr.pd_hndl = vd->nic_pd;
  126.     mr.acl = VAPI_EN_LOCAL_WRITE | VAPI_EN_REMOTE_WRITE;
  127.     ret = VAPI_register_mr(vd->nic_handle, &mr, &vc->eager_recv_mr, &mr_out);
  128.     if (ret < 0)
  129.     error_verrno(ret, "%s: register_mr eager recv", __func__);
  130.     vc->eager_recv_lkey = mr_out.l_key;
  131.  
  132.     /* register memory region, send */
  133.     mr.type = VAPI_MR;
  134.     mr.start = int64_from_ptr(c->eager_send_buf_contig);
  135.     mr.size = ib_device->eager_buf_num * ib_device->eager_buf_size;
  136.     mr.pd_hndl = vd->nic_pd;
  137.     mr.acl = VAPI_EN_LOCAL_WRITE;
  138.     ret = VAPI_register_mr(vd->nic_handle, &mr, &vc->eager_send_mr, &mr_out);
  139.     if (ret < 0)
  140.     error_verrno(ret, "%s: register_mr bounce", __func__);
  141.     vc->eager_send_lkey = mr_out.l_key;
  142.  
  143.     /* common qp properites */
  144.     qp_init_attr.cap.max_oust_wr_sq = 5000;  /* outstanding WQEs */
  145.     qp_init_attr.cap.max_oust_wr_rq = 5000;
  146.     qp_init_attr.cap.max_sg_size_sq = 20;  /* scatter/gather entries */
  147.     qp_init_attr.cap.max_sg_size_rq = 20;
  148.     qp_init_attr.pd_hndl            = vd->nic_pd;
  149.     qp_init_attr.rdd_hndl           = 0;
  150.     /* wire both send and recv to the same CQ */
  151.     qp_init_attr.sq_cq_hndl         = vd->nic_cq;
  152.     qp_init_attr.rq_cq_hndl         = vd->nic_cq;
  153.     /* only generate completion queue entries if requested */
  154.     qp_init_attr.sq_sig_type        = VAPI_SIGNAL_REQ_WR;
  155.     qp_init_attr.rq_sig_type        = VAPI_SIGNAL_REQ_WR;
  156.     qp_init_attr.ts_type            = VAPI_TS_RC;
  157.  
  158.     /* build main qp */
  159.     ret = VAPI_create_qp(vd->nic_handle, &qp_init_attr, &vc->qp, &prop);
  160.     if (ret < 0)
  161.     error_verrno(ret, "%s: create QP", __func__);
  162.     vc->qp_num = prop.qp_num;
  163.     verify_prop_caps(&prop.cap);
  164.  
  165.     /* initialize for post_sr */
  166.     vc->num_unsignaled_wr = 0;
  167.  
  168.     /* share connection information across TCP */
  169.     /* sanity check sizes of things (actually only 24 bits in qp_num) */
  170.     bmi_ib_assert(sizeof(ch_in.lid) == sizeof(uint16_t),
  171.           "%s: connection_handshake.lid size %d expecting %d",
  172.           __func__, (int) sizeof(ch_in.lid), (int) sizeof(u_int16_t));
  173.     bmi_ib_assert(sizeof(ch_in.qp_num) == sizeof(uint32_t),
  174.           "%s: connection_handshake.qp_num size %d expecting %d",
  175.           __func__, (int) sizeof(ch_in.qp_num), (int) sizeof(uint32_t));
  176.  
  177.     /* convert all to network order and back */
  178.     ch_out.lid = htobmi16(vd->nic_lid);
  179.     ch_out.qp_num = htobmi32(vc->qp_num);
  180.  
  181.     ret = exchange_data(sock, is_server, &ch_in, &ch_out, sizeof(ch_in));
  182.     if (ret)
  183.     goto out;
  184.  
  185.     vc->remote_lid = bmitoh16(ch_in.lid);
  186.     vc->remote_qp_num = bmitoh32(ch_in.qp_num);
  187.  
  188.     /* bring the two QPs up to RTR */
  189.     init_connection_modify_qp(vc->qp, vc->remote_qp_num, vc->remote_lid);
  190.  
  191.     /* post initial RRs */
  192.     for (i=0; i<ib_device->eager_buf_num; i++)
  193.     vapi_post_rr(c, &c->eager_recv_buf_head_contig[i]);
  194.  
  195.     /* final sychronize to ensure both sides have posted RRs */
  196.     ret = exchange_data(sock, is_server, &ret, &ret, sizeof(ret));
  197.  
  198.   out:
  199.     return ret;
  200. }
  201.  
  202. /*
  203.  * Exchange information: server reads first, then writes; client opposite.
  204.  */
  205. static int exchange_data(int sock, int is_server, void *xin, void *xout,
  206.                          size_t len)
  207. {
  208.     int i;
  209.     int ret;
  210.  
  211.     for (i=0; i<2; i++) {
  212.     if (i ^ is_server) {
  213.         ret = read_full(sock, xin, len);
  214.         if (ret < 0) {
  215.         warning_errno("%s: read", __func__);
  216.         goto out;
  217.         }
  218.         if (ret != (int) len) {
  219.         ret = 1;
  220.         warning("%s: partial read, %d/%d bytes", __func__, ret,
  221.                                                 (int) len);
  222.         goto out;
  223.         }
  224.     } else {
  225.         ret = write_full(sock, xout, len);
  226.         if (ret < 0) {
  227.         warning_errno("%s: write", __func__);
  228.         goto out;
  229.         }
  230.     }
  231.     }
  232.  
  233.     ret = 0;
  234.  
  235.   out:
  236.     return ret;
  237. }
  238.  
  239. /*
  240.  * If not set, set them.  Otherwise verify that none of our assumed global
  241.  * limits are different for this new connection.
  242.  */
  243. static void verify_prop_caps(VAPI_qp_cap_t *cap)
  244. {
  245.     struct vapi_device_priv *vd = ib_device->priv;
  246.  
  247.     if (vd->sg_max_len == 0) {
  248.     vd->sg_max_len = cap->max_sg_size_sq;
  249.     if (cap->max_sg_size_rq < vd->sg_max_len)
  250.         vd->sg_max_len = cap->max_sg_size_rq;
  251.     vd->sg_tmp_array = bmi_ib_malloc(vd->sg_max_len *
  252.                      sizeof(*vd->sg_tmp_array));
  253.     } else {
  254.     if (cap->max_sg_size_sq < vd->sg_max_len)
  255.         error(
  256.           "%s: new connection has smaller send scatter/gather array size,"
  257.           " %d vs %d", __func__, cap->max_sg_size_sq, vd->sg_max_len);
  258.     if (cap->max_sg_size_rq < vd->sg_max_len)
  259.         error(
  260.           "%s: new connection has smaller recv scatter/gather array size,"
  261.           " %d vs %d", __func__, cap->max_sg_size_rq, vd->sg_max_len);
  262.     }
  263.  
  264.     if (vd->max_outstanding_wr == 0) {
  265.     vd->max_outstanding_wr = cap->max_oust_wr_sq;
  266.     } else {
  267.     if (cap->max_oust_wr_sq < vd->max_outstanding_wr)
  268.         error(
  269.           "%s: new connection has smaller max_oust_wr_sq size, %d vs %d",
  270.           __func__, cap->max_oust_wr_sq, vd->max_outstanding_wr);
  271.     }
  272. }
  273.  
  274. /*
  275.  * Perform the many steps required to bring up both sides of an IB connection.
  276.  */
  277. static void init_connection_modify_qp(VAPI_qp_hndl_t qp,
  278.                                       VAPI_qp_num_t remote_qp_num,
  279.                       int remote_lid)
  280. {
  281.     struct vapi_device_priv *vd = ib_device->priv;
  282.     int ret;
  283.     VAPI_qp_attr_t attr;
  284.     VAPI_qp_attr_mask_t mask;
  285.     VAPI_qp_cap_t cap;
  286.  
  287.     /* see HCA/vip/qpm/qp_xition.h for important settings */
  288.     /* transition qp to init */
  289.     QP_ATTR_MASK_CLR_ALL(mask);
  290.     QP_ATTR_MASK_SET(mask,
  291.        QP_ATTR_QP_STATE
  292.      | QP_ATTR_REMOTE_ATOMIC_FLAGS
  293.      | QP_ATTR_PKEY_IX
  294.      | QP_ATTR_PORT);
  295.     attr.qp_state = VAPI_INIT;
  296.     attr.remote_atomic_flags = VAPI_EN_REM_WRITE;
  297.     attr.pkey_ix = 0;
  298.     attr.port = VAPI_PORT;
  299.     ret = VAPI_modify_qp(vd->nic_handle, qp, &attr, &mask, &cap);
  300.     if (ret < 0)
  301.     error_verrno(ret, "%s: VAPI_modify_qp RST -> INIT", __func__);
  302.  
  303.     /* transition qp to ready-to-receive */
  304.     QP_ATTR_MASK_CLR_ALL(mask);
  305.     QP_ATTR_MASK_SET(mask,
  306.        QP_ATTR_QP_STATE
  307.      | QP_ATTR_QP_OUS_RD_ATOM
  308.      | QP_ATTR_AV
  309.      | QP_ATTR_PATH_MTU
  310.      | QP_ATTR_RQ_PSN
  311.      | QP_ATTR_DEST_QP_NUM
  312.      | QP_ATTR_MIN_RNR_TIMER);
  313.     attr.qp_state = VAPI_RTR;
  314.     attr.qp_ous_rd_atom = 0;
  315.     memset(&attr.av, 0, sizeof(attr.av));
  316.     attr.av.dlid = remote_lid;
  317.     attr.path_mtu = VAPI_MTU;
  318.     attr.rq_psn = 0;
  319.     attr.dest_qp_num = remote_qp_num;
  320.     attr.min_rnr_timer = IB_RNR_NAK_TIMER_491_52;
  321.     ret = VAPI_modify_qp(vd->nic_handle, qp, &attr, &mask, &cap);
  322.     if (ret < 0)
  323.     error_verrno(ret, "%s: VAPI_modify_qp INIT -> RTR", __func__);
  324.  
  325.     /* transition qp to ready-to-send */
  326.     QP_ATTR_MASK_CLR_ALL(mask);
  327.     QP_ATTR_MASK_SET(mask,
  328.        QP_ATTR_QP_STATE
  329.      | QP_ATTR_SQ_PSN
  330.      | QP_ATTR_OUS_DST_RD_ATOM
  331.      | QP_ATTR_TIMEOUT
  332.      | QP_ATTR_RETRY_COUNT
  333.      | QP_ATTR_RNR_RETRY
  334.      );
  335.     attr.qp_state = VAPI_RTS;
  336.     attr.sq_psn = 0;
  337.     attr.ous_dst_rd_atom = 0;
  338.     attr.timeout = 26;  /* 4.096us * 2^26 = 5 min */
  339.     attr.retry_count = 20;
  340.     attr.rnr_retry = 20;
  341.     ret = VAPI_modify_qp(vd->nic_handle, qp, &attr, &mask, &cap);
  342.     if (ret < 0)
  343.     error_verrno(ret, "%s: VAPI_modify_qp RTR -> RTS", __func__);
  344. }
  345.  
  346. /*
  347.  * Close the QP associated with this connection.  Used to wait for drain to
  348.  * finish, but many seconds pass before the adapter tells us about it via an
  349.  * asynch event.  Perhaps there is a way to do it via polling.
  350.  */
  351. static void vapi_drain_qp(ib_connection_t *c)
  352. {
  353.     struct vapi_connection_priv *vc = c->priv;
  354.     struct vapi_device_priv *vd = ib_device->priv;
  355.     VAPI_qp_hndl_t qp = vc->qp;
  356.     int ret;
  357.     /* int trips; */
  358.     VAPI_qp_attr_t attr;
  359.     VAPI_qp_attr_mask_t mask;
  360.     VAPI_qp_cap_t cap;
  361.  
  362.     /* transition to drain */
  363.     QP_ATTR_MASK_CLR_ALL(mask);
  364.     QP_ATTR_MASK_SET(mask,
  365.        QP_ATTR_QP_STATE);
  366.      /* | QP_ATTR_EN_SQD_ASYN_NOTIF); */
  367.     attr.qp_state = VAPI_SQD;
  368.     /* attr.en_sqd_asyn_notif = 1; */
  369.     ret = VAPI_modify_qp(vd->nic_handle, qp, &attr, &mask, &cap);
  370.     if (ret < 0)
  371.     error_verrno(ret, "%s: VAPI_modify_qp RTS -> SQD", __func__);
  372. }
  373.  
  374. /*
  375.  * At an explicit BYE message, or at finalize time, shut down a connection.
  376.  * If descriptors are posted, defer and clean up the connection structures
  377.  * later.
  378.  */
  379. static void vapi_close_connection(ib_connection_t *c)
  380. {
  381.     int ret;
  382.     struct vapi_connection_priv *vc = c->priv;
  383.     struct vapi_device_priv *vd = ib_device->priv;
  384.  
  385.     ret = VAPI_destroy_qp(vd->nic_handle, vc->qp);
  386.     if (ret < 0)
  387.     error_verrno(ret, "%s: VAPI_destroy_qp", __func__);
  388.     ret = VAPI_deregister_mr(vd->nic_handle, vc->eager_send_mr);
  389.     if (ret < 0)
  390.     error_verrno(ret, "%s: VAPI_deregister_mr eager send", __func__);
  391.     ret = VAPI_deregister_mr(vd->nic_handle, vc->eager_recv_mr);
  392.     if (ret < 0)
  393.     error_verrno(ret, "%s: VAPI_deregister_mr eager recv", __func__);
  394.  
  395.     free(vc);
  396. }
  397.  
  398. /*
  399.  * VAPI interface to post sends.  Not RDMA, just SEND.
  400.  * Called for an eager send, rts send, or cts send.
  401.  */
  402. static void vapi_post_sr(const struct buf_head *bh, u_int32_t len)
  403. {
  404.     VAPI_sg_lst_entry_t sg;
  405.     VAPI_sr_desc_t sr;
  406.     int ret;
  407.     ib_connection_t *c = bh->c;
  408.     struct vapi_connection_priv *vc = c->priv;
  409.     struct vapi_device_priv *vd = ib_device->priv;
  410.  
  411.     debug(2, "%s: %s bh %d len %u wr %d/%d", __func__, c->peername, bh->num,
  412.       len, vc->num_unsignaled_wr, vd->max_outstanding_wr);
  413.     sg.addr = int64_from_ptr(bh->buf);
  414.     sg.len = len;
  415.     sg.lkey = vc->eager_send_lkey;
  416.  
  417.     memset(&sr, 0, sizeof(sr));
  418.     sr.opcode = VAPI_SEND;
  419.     sr.id = int64_from_ptr(bh);
  420.     sr.comp_type = VAPI_SIGNALED;
  421. /* no unsignaled anymore, see openib.c
  422.     if (++vc->num_unsignaled_wr + 100 == vd->max_outstanding_wr) {
  423.     vc->num_unsignaled_wr = 0;
  424.     } else
  425.     sr.comp_type = VAPI_UNSIGNALED;
  426.  */
  427.     sr.sg_lst_p = &sg;
  428.     sr.sg_lst_len = 1;
  429.     ret = VAPI_post_sr(vd->nic_handle, vc->qp, &sr);
  430.     if (ret < 0)
  431.     error_verrno(ret, "%s: VAPI_post_sr", __func__);
  432. }
  433.  
  434. /*
  435.  * Post one of the eager recv bufs for this connection.
  436.  */
  437. static void vapi_post_rr(const ib_connection_t *c, struct buf_head *bh)
  438. {
  439.     VAPI_sg_lst_entry_t sg;
  440.     VAPI_rr_desc_t rr;
  441.     int ret;
  442.     struct vapi_connection_priv *vc = c->priv;
  443.     struct vapi_device_priv *vd = ib_device->priv;
  444.  
  445.     debug(2, "%s: %s bh %d", __func__, c->peername, bh->num);
  446.     sg.addr = int64_from_ptr(bh->buf);
  447.     sg.len = ib_device->eager_buf_size;
  448.     sg.lkey = vc->eager_recv_lkey;
  449.  
  450.     memset(&rr, 0, sizeof(rr));
  451.     rr.opcode = VAPI_RECEIVE;
  452.     rr.id = int64_from_ptr(bh);
  453.     rr.sg_lst_p = &sg;
  454.     rr.sg_lst_len = 1;
  455.     ret = VAPI_post_rr(vd->nic_handle, vc->qp, &rr);
  456.     if (ret < 0)
  457.     error_verrno(ret, "%s: VAPI_post_rr", __func__);
  458. }
  459.  
  460. /*
  461.  * Called only in response to receipt of a CTS on the sender.  RDMA write
  462.  * the big data to the other side.  A bit messy since an RDMA write may
  463.  * not scatter to the receiver, but can gather from the sender, and we may
  464.  * have a non-trivial buflist on both sides.  The mh_cts variable length
  465.  * fields must be decoded as we go.
  466.  */
  467. static void vapi_post_sr_rdmaw(struct ib_work *sq, msg_header_cts_t *mh_cts,
  468.                                void *mh_cts_buf)
  469. {
  470.     VAPI_sr_desc_t sr;
  471.     int done;
  472.     ib_connection_t *c = sq->c;
  473.     struct vapi_connection_priv *vc = c->priv;
  474.     struct vapi_device_priv *vd = ib_device->priv;
  475.  
  476.     int send_index = 0, recv_index = 0;    /* working entry in buflist */
  477.     int send_offset = 0;  /* byte offset in working send entry */
  478.     u_int64_t *recv_bufp = (u_int64_t *) mh_cts_buf;
  479.     u_int32_t *recv_lenp = (u_int32_t *)(recv_bufp + mh_cts->buflist_num);
  480.     u_int32_t *recv_rkey = (u_int32_t *)(recv_lenp + mh_cts->buflist_num);
  481.     u_int32_t recv_bytes_needed = 0;
  482.  
  483.     debug(2, "%s: sq %p totlen %d", __func__, sq, (int) sq->buflist.tot_len);
  484.  
  485. #if MEMCACHE_BOUNCEBUF
  486.     if (reg_send_buflist.num == 0) {
  487.     reg_send_buflist.num = 1;
  488.     reg_send_buflist.buf.recv = ®_send_buflist_buf;
  489.     reg_send_buflist.len = ®_send_buflist_len;
  490.     reg_send_buflist.tot_len = reg_send_buflist_len;
  491.     reg_send_buflist_buf = bmi_ib_malloc(reg_send_buflist_len);
  492.     memcache_register(ib_device->memcache, ®_send_buflist);
  493.     }
  494.     if (sq->buflist.tot_len > reg_send_buflist_len)
  495.     error("%s: send prereg buflist too small, need %lld", __func__,
  496.       lld(sq->buflist.tot_len));
  497.     memcpy_from_buflist(&sq->buflist, reg_send_buflist_buf);
  498.  
  499.     ib_buflist_t save_buflist = sq->buflist;
  500.     sq->buflist = reg_send_buflist;
  501.  
  502. #else
  503. #if !MEMCACHE_EARLY_REG
  504.     memcache_register(ib_device->memcache, &sq->buflist);
  505. #endif
  506. #endif
  507.  
  508.     /* constant things for every send */
  509.     memset(&sr, 0, sizeof(sr));
  510.     sr.opcode = VAPI_RDMA_WRITE;
  511.     sr.comp_type = VAPI_UNSIGNALED;
  512.     sr.sg_lst_p = vd->sg_tmp_array;
  513.  
  514.     done = 0;
  515.     while (!done) {
  516.     int ret;
  517.  
  518.     if (recv_bytes_needed == 0) {
  519.         /* new one, fresh numbers */
  520.         sr.remote_addr = bmitoh64(recv_bufp[recv_index]);
  521.         recv_bytes_needed = bmitoh32(recv_lenp[recv_index]);
  522.     } else {
  523.         /* continuing into unfinished remote receive index */
  524.         sr.remote_addr +=
  525.         bmitoh32(recv_lenp[recv_index]) - recv_bytes_needed;
  526.     }
  527.  
  528.     sr.r_key = bmitoh32(recv_rkey[recv_index]);
  529.     sr.sg_lst_len = 0;
  530.  
  531.     debug(4, "%s: chunk to %s remote addr %llx rkey %x",
  532.       __func__, c->peername, llu(sr.remote_addr), sr.r_key);
  533.  
  534.     /*
  535.      * Driven by recv elements.  Sizes have already been checked.
  536.      */
  537.     while (recv_bytes_needed > 0 && sr.sg_lst_len < vd->sg_max_len) {
  538.         /* consume from send buflist to fill this one receive */
  539.         u_int32_t send_bytes_offered
  540.           = sq->buflist.len[send_index] - send_offset;
  541.         u_int32_t this_bytes = send_bytes_offered;
  542.         if (this_bytes > recv_bytes_needed)
  543.         this_bytes = recv_bytes_needed;
  544.  
  545.         vd->sg_tmp_array[sr.sg_lst_len].addr =
  546.           int64_from_ptr(sq->buflist.buf.send[send_index])
  547.           + send_offset;
  548.         vd->sg_tmp_array[sr.sg_lst_len].len = this_bytes;
  549.         vd->sg_tmp_array[sr.sg_lst_len].lkey =
  550.           sq->buflist.memcache[send_index]->memkeys.lkey;
  551.  
  552.         debug(4, "%s: chunk %d local addr %llx len %d lkey %x",
  553.           __func__, sr.sg_lst_len,
  554.           llu(vd->sg_tmp_array[sr.sg_lst_len].addr),
  555.           vd->sg_tmp_array[sr.sg_lst_len].len,
  556.           vd->sg_tmp_array[sr.sg_lst_len].lkey);
  557.  
  558.         ++sr.sg_lst_len;
  559.         send_offset += this_bytes;
  560.         if (send_offset == sq->buflist.len[send_index]) {
  561.         ++send_index;
  562.         send_offset = 0;
  563.         if (send_index == sq->buflist.num) {
  564.             done = 1;
  565.             break;  /* short send */
  566.         }
  567.         }
  568.         recv_bytes_needed -= this_bytes;
  569.     }
  570.  
  571.     /* done with the one we were just working on, is this the last recv? */
  572.     if (recv_bytes_needed == 0) {
  573.         ++recv_index;
  574.         if (recv_index == (int)mh_cts->buflist_num)
  575.         done = 1;
  576.     }
  577.  
  578.     /* either filled the recv or exhausted the send */
  579.     if (done) {
  580.         sr.id = int64_from_ptr(sq);    /* used to match in completion */
  581.         sr.comp_type = VAPI_SIGNALED;  /* completion drives the unpin */
  582.     } else {
  583.         sr.id = 0;
  584.         sr.comp_type = VAPI_UNSIGNALED;
  585.     }
  586.     ret = VAPI_post_sr(vd->nic_handle, vc->qp, &sr);
  587.     if (ret < 0)
  588.         error_verrno(ret, "%s: VAPI_post_sr", __func__);
  589.     }
  590. #if MEMCACHE_BOUNCEBUF
  591.     sq->buflist = save_buflist;
  592. #endif
  593. }
  594.  
  595. /*
  596.  * Get one entry from completion queue, return 1 if found something, 0
  597.  * if CQ empty.  Die if some error.
  598.  */
  599. static int vapi_check_cq(struct bmi_ib_wc *wc)
  600. {
  601.     int ret;
  602.     VAPI_wc_desc_t desc;
  603.     struct vapi_device_priv *vd = ib_device->priv;
  604.     
  605.     ret = VAPI_poll_cq(vd->nic_handle, vd->nic_cq, &desc);
  606.     if (ret < 0) {
  607.     if (ret == VAPI_CQ_EMPTY)
  608.         return 0;
  609.     error_verrno(ret, "%s: VAPI_poll_cq", __func__);
  610.     }
  611.  
  612.     /* convert to generic form */
  613.     wc->id = desc.id;
  614.     wc->status = desc.status;
  615.     wc->byte_len = desc.byte_len;
  616.     if (desc.opcode == VAPI_CQE_SQ_SEND_DATA)
  617.     wc->opcode = BMI_IB_OP_SEND;
  618.     else if (desc.opcode == VAPI_CQE_RQ_SEND_DATA)
  619.     wc->opcode = BMI_IB_OP_RECV;
  620.     else if (desc.opcode == VAPI_CQE_SQ_RDMA_WRITE)
  621.     wc->opcode = BMI_IB_OP_RDMA_WRITE;
  622.     else
  623.     error("%s: unknown opcode %d", __func__, desc.opcode);
  624.     return 1;
  625. }
  626.  
  627. static void vapi_prepare_cq_block(int *cq_fd, int *async_fd)
  628. {
  629.     struct vapi_device_priv *vd = ib_device->priv;
  630.     int ret;
  631.  
  632.     /* ask for the next notfication */
  633.     ret = VAPI_req_comp_notif(vd->nic_handle, vd->nic_cq, VAPI_NEXT_COMP);
  634.     if (ret < 0)
  635.     error_verrno(ret, "%s: VAPI_req_comp_notif", __func__);
  636.  
  637.     /* return the fd that can be fed to poll() */
  638.     *cq_fd = vd->cq_event_pipe[0];
  639.     *async_fd = vd->async_event_pipe[0];
  640. }
  641.  
  642. /*
  643.  * Read an event that tells us there is some action on the CQ.  In
  644.  * reality, just read the int from the pipe that connects us to the
  645.  * event handler thread.
  646.  */
  647. static void vapi_ack_cq_completion_event(void)
  648. {
  649.     struct vapi_device_priv *vd = ib_device->priv;
  650.     int i, ret;
  651.  
  652.     ret = read(vd->cq_event_pipe[0], &i, sizeof(i));
  653.     if (ret != sizeof(i))
  654.     error_errno("%s: read cq event pipe", __func__);
  655. }
  656.  
  657. /*
  658.  * Return string form of work completion status field.
  659.  */
  660. static const char *vapi_wc_status_string(int status)
  661. {
  662.     return VAPI_wc_status_sym(status);
  663. }
  664.  
  665. #define CASE(e)  case e: s = #e; break
  666. static const char *vapi_port_state_string(IB_port_state_t state)
  667. {
  668.     const char *s = "(UNKNOWN)";
  669.  
  670.     switch (state) {
  671.     CASE(PORT_NOP);
  672.     CASE(PORT_DOWN);
  673.     CASE(PORT_INITIALIZE);
  674.     CASE(PORT_ARMED);
  675.     CASE(PORT_ACTIVE);
  676.     }
  677.     return s;
  678. }
  679. #undef CASE
  680.  
  681.  
  682. /*
  683.  * Memory registration and deregistration.  Used both by sender and
  684.  * receiver, vary if lkey or rkey = 0.
  685.  */
  686. static int vapi_mem_register(memcache_entry_t *c)
  687. {
  688.     struct vapi_device_priv *vd = ib_device->priv;
  689.     VAPI_mrw_t mrw, mrw_out;
  690.     VAPI_mr_hndl_t mrh;
  691.     int ret;
  692.  
  693.     /* always turn on local write and write even if just BMI_SEND */
  694.     mrw.acl = VAPI_EN_LOCAL_WRITE | VAPI_EN_REMOTE_WRITE;
  695.     mrw.type = VAPI_MR;
  696.     mrw.pd_hndl = vd->nic_pd;
  697.     mrw.start = int64_from_ptr(c->buf);
  698.     mrw.size = c->len;
  699.     ret = VAPI_register_mr(vd->nic_handle, &mrw, &mrh, &mrw_out);
  700.     if (ret < 0)
  701.     error_verrno(ret, "%s: VAPI_register_mr", __func__);
  702.     c->memkeys.mrh = mrh;  /* store in 64-bit int */
  703.     c->memkeys.lkey = mrw_out.l_key;
  704.     c->memkeys.rkey = mrw_out.r_key;
  705.     debug(4, "%s: buf %p len %lld", __func__, c->buf, lld(c->len));
  706.     return 0;
  707. }
  708.  
  709. static void vapi_mem_deregister(memcache_entry_t *c)
  710. {
  711.     struct vapi_device_priv *vd = ib_device->priv;
  712.     VAPI_mr_hndl_t mrh;
  713.     int ret;
  714.     
  715.     mrh = c->memkeys.mrh;  /* retrieve 32-bit from 64-bit int */
  716.     ret = VAPI_deregister_mr(vd->nic_handle, mrh);
  717.     if (ret < 0)
  718.     error_verrno(ret, "%s: VAPI_deregister_mr", __func__);
  719.     debug(4, "%s: buf %p len %lld lkey %x rkey %x", __func__,
  720.       c->buf, lld(c->len), c->memkeys.lkey, c->memkeys.rkey);
  721. }
  722.  
  723. /*
  724.  * Format vapi-specific error code.
  725.  */
  726. static void __attribute__((noreturn,format(printf,2,3)))
  727. error_verrno(int ecode, const char *fmt, ...)
  728. {
  729.     char s[2048];
  730.     va_list ap;
  731.  
  732.     va_start(ap, fmt);
  733.     vsprintf(s, fmt, ap);
  734.     va_end(ap);
  735.     gossip_err("Error: %s: %s\n", s, VAPI_strerror(ecode));  /* adds a dot */
  736.     exit(1);
  737. }
  738.  
  739. /*
  740.  * Catch errors from IB.  This is invoked in its own thread created
  741.  * by libvapi.  Just ship the event down an fd and read it later when
  742.  * we want to get it, like the OpenIB model.
  743.  */
  744. static void
  745. async_event_handler(VAPI_hca_hndl_t nic_handle_in __attribute__((unused)),
  746.   VAPI_event_record_t *e, void *private_data __attribute__((unused)) )
  747. {
  748.     struct vapi_device_priv *vd = ib_device->priv;
  749.     int ret;
  750.  
  751.     ret = write(vd->async_event_pipe[1], e, sizeof(*e));
  752.     if (ret != sizeof(*e))
  753.     error_errno("%s: write async event pipe", __func__);
  754. }
  755.  
  756. /*
  757.  * To deal with blocking completion events.  Just write down a pipe
  758.  * that something is ready to go; signaling to poll that an event is
  759.  * ready.
  760.  */
  761. static void cq_event_handler(VAPI_hca_hndl_t hca __attribute__((unused)),
  762.                              VAPI_cq_hndl_t cq __attribute__((unused)),
  763.                      void *private_data __attribute__((unused)))
  764. {
  765.     struct vapi_device_priv *vd = ib_device->priv;
  766.     int i = 0, ret;
  767.  
  768.     ret = write(vd->cq_event_pipe[1], &i, sizeof(i));
  769.     if (ret != sizeof(i))
  770.     error_errno("%s: write cq event pipe", __func__);
  771. }
  772.  
  773. #ifdef HAVE_IB_WRAP_COMMON_H
  774. extern int mosal_fd;
  775. #endif
  776.  
  777. /*
  778.  * Hack to work around fork in daemon mode which confuses kernel
  779.  * state.  I wish they did not have an _init constructor function in
  780.  * libmosal.so.  It calls into MOSAL_user_lib_init().
  781.  * This just breaks its saved state and reinitializes.  (task->mm
  782.  * changes due to fork after init, hash lookup on that fails.)
  783.  *
  784.  * Seems to work even in the case of a non-backgrounded server too,
  785.  * fortunately.
  786.  *
  787.  * Note that even with shared libraries you do not have protection
  788.  * against wandering headers.  The thca distributions have in the
  789.  * past been eager to change critical #defines like VAPI_CQ_EMPTY
  790.  * so libpvfs2.so is more or less tied to the vapi.h against which
  791.  * it was compiled.
  792.  */
  793. static void reinit_mosal(void)
  794. {
  795.     void *dlh;
  796.     int (*mosal_ioctl_open)(void);
  797.     int (*mosal_ioctl_close)(void);
  798.  
  799.     dlh = dlopen("libmosal.so", RTLD_LAZY);
  800.     if (!dlh)
  801.     error("%s: cannot open libmosal shared library", __func__);
  802.  
  803. #ifdef HAVE_IB_WRAP_COMMON_H
  804.     {
  805.     /*
  806.      * What's happening here is we probe the internals of the mosal library
  807.      * to get it to return a structure that has the current fd and state
  808.      * of the connection to /dev/mosal.  We close it, reset the state, and
  809.      * force it to reinitialize itself.  Icky, but effective.  Only necessary
  810.      * for older thca distributions that install the needed header and
  811.      * have this symbol in the library.
  812.      *
  813.      * Else fall through to the easier method.
  814.      */
  815.     call_result_t (*_dev_mosal_init_lib)(t_lib_descriptor **pp_t_lib);
  816.     const char *errmsg;
  817.  
  818.     _dev_mosal_init_lib = dlsym(dlh, "_dev_mosal_init_lib");
  819.     errmsg = dlerror();
  820.     if (errmsg == NULL) {
  821.     t_lib_descriptor *desc;
  822.     int ret;
  823.  
  824.     ret = (*_dev_mosal_init_lib)(&desc);
  825.     debug(2, "%s: mosal init ret %d, desc %p", __func__, ret, desc);
  826.     debug(2, "%s: desc->fd %d", __func__, desc->os_lib_desc_st.fd);
  827.     close(desc->os_lib_desc_st.fd);
  828.     /* both these state items protect against a reinit */
  829.     desc->state = 0;
  830.     mosal_fd = -1;
  831.     MOSAL_user_lib_init();
  832.     return;
  833.     }
  834.     }
  835. #endif
  836.  
  837.     /*
  838.      * Recent thca distros and the 2.6 openib tree do not seem to permit
  839.      * any way to "trick" the library as above, but there's no need for
  840.      * the hack now that they export a "finalize" function to undo the init.
  841.      */
  842.     mosal_ioctl_open = dlsym(dlh, "mosal_ioctl_open");
  843.     if (dlerror())
  844.     error("%s: mosal_ioctl_open not found in libmosal", __func__);
  845.     mosal_ioctl_close = dlsym(dlh, "mosal_ioctl_close");
  846.     if (dlerror())
  847.     error("%s: mosal_ioctl_close not found in libmosal", __func__);
  848.  
  849.     (*mosal_ioctl_close)();
  850.     (*mosal_ioctl_open)();
  851. }
  852.  
  853. /*
  854.  * Just catch and report the events, do not try to do anything with
  855.  * them.
  856.  */
  857. static int vapi_check_async_events(void)
  858. {
  859.     struct vapi_device_priv *vd = ib_device->priv;
  860.     int ret;
  861.     VAPI_event_record_t ev;
  862.  
  863.     ret = read(vd->async_event_pipe[0], &ev, sizeof(ev));
  864.     if (ret < 0) {
  865.     if (errno == EAGAIN)
  866.         return 0;
  867.     error_errno("%s: read async event pipe", __func__);
  868.     }
  869.     warning("%s: %s", __func__, VAPI_event_record_sym(ev.type));
  870.     return 1;
  871. }
  872.  
  873. /*
  874.  * VAPI-specific startup.
  875.  */
  876. int vapi_ib_initialize(void)
  877. {
  878.     int ret, flags;
  879.     u_int32_t num_hcas;
  880.     VAPI_hca_id_t hca_ids[10];
  881.     VAPI_hca_port_t nic_port_props;
  882.     VAPI_hca_vendor_t vendor_cap;
  883.     VAPI_hca_cap_t hca_cap;
  884.     VAPI_cqe_num_t cqe_num, cqe_num_out;
  885.     struct vapi_device_priv *vd;
  886.  
  887.     reinit_mosal();
  888.  
  889.     /* look for exactly one and take it */
  890.     ret = EVAPI_list_hcas(sizeof(hca_ids)/sizeof(hca_ids[0]), &num_hcas,
  891.                           hca_ids);
  892.     if (ret < 0)
  893.     error_verrno(ret, "%s: EVAPI_list_hcas", __func__);
  894.     if (num_hcas == 0) {
  895.     warning("%s: no hcas detected", __func__);
  896.     return -ENODEV;
  897.     }
  898.     if (num_hcas > 1)
  899.     warning("%s: found %d HCAs, choosing the first", __func__, num_hcas);
  900.  
  901.     vd = bmi_ib_malloc(sizeof(*vd));
  902.     ib_device->priv = vd;
  903.  
  904.     /* set the function pointers for vapi */
  905.     ib_device->func.new_connection = vapi_new_connection;
  906.     ib_device->func.close_connection = vapi_close_connection;
  907.     ib_device->func.drain_qp = vapi_drain_qp;
  908.     ib_device->func.ib_initialize = vapi_ib_initialize;
  909.     ib_device->func.ib_finalize = vapi_ib_finalize;
  910.     ib_device->func.post_sr = vapi_post_sr;
  911.     ib_device->func.post_rr = vapi_post_rr;
  912.     ib_device->func.post_sr_rdmaw = vapi_post_sr_rdmaw;
  913.     ib_device->func.check_cq = vapi_check_cq;
  914.     ib_device->func.prepare_cq_block = vapi_prepare_cq_block;
  915.     ib_device->func.ack_cq_completion_event = vapi_ack_cq_completion_event;
  916.     ib_device->func.wc_status_string = vapi_wc_status_string;
  917.     ib_device->func.mem_register = vapi_mem_register;
  918.     ib_device->func.mem_deregister = vapi_mem_deregister;
  919.     ib_device->func.check_async_events = vapi_check_async_events;
  920.  
  921.     /*
  922.      * Apparently VAPI_open_hca() is a once-per-machine sort of thing, and
  923.      * users are not expected to call it.  It returns EBUSY every time.
  924.      * This call initializes the per-process user resources and starts up
  925.      * all the threads.  Discard const char* for silly mellanox prototype;
  926.      * it really is treated as constant.
  927.      */
  928.     ret = EVAPI_get_hca_hndl(hca_ids[0], &vd->nic_handle);
  929.     if (ret < 0)
  930.     error("%s: could not get HCA handle", __func__);
  931.  
  932.     /* connect an asynchronous event handler to look for weirdness */
  933.     ret = EVAPI_set_async_event_handler(vd->nic_handle, async_event_handler, 0,
  934.                                         &vd->nic_async_event_handler);
  935.     if (ret < 0)
  936.     error_verrno(ret, "%s: EVAPI_set_async_event_handler", __func__);
  937.  
  938.     /* get the lid and verify port state */
  939.     /* ignore different-width-prototype warning here, cannot pass u8 */
  940.     ret = VAPI_query_hca_port_prop(vd->nic_handle, VAPI_PORT, &nic_port_props);
  941.     if (ret < 0)
  942.     error_verrno(ret, "%s: VAPI_query_hca_port_prop", __func__);
  943.     vd->nic_lid = nic_port_props.lid;
  944.  
  945.     if (nic_port_props.state != PORT_ACTIVE)
  946.     error("%s: port state is %s but should be ACTIVE; check subnet manager",
  947.           __func__, vapi_port_state_string(nic_port_props.state));
  948.  
  949.     /* build a protection domain */
  950.     ret = VAPI_alloc_pd(vd->nic_handle, &vd->nic_pd);
  951.     if (ret < 0)
  952.     error_verrno(ret, "%s: VAPI_create_pd", __func__);
  953.     /* ulong in 2.6, uint32 in 2.4 */
  954.     debug(2, "%s: built pd %lx", __func__, (unsigned long) vd->nic_pd);
  955.  
  956.     /* see how many cq entries we are allowed to have */
  957.     memset(&hca_cap, 0, sizeof(hca_cap));
  958.     ret = VAPI_query_hca_cap(vd->nic_handle, &vendor_cap, &hca_cap);
  959.     if (ret < 0)
  960.     error_verrno(ret, "%s: VAPI_query_hca_cap", __func__);
  961.  
  962.     debug(0, "%s: max %d completion queue entries", __func__,
  963.       hca_cap.max_num_cq);
  964.     cqe_num = VAPI_NUM_CQ_ENTRIES;
  965.     if (hca_cap.max_num_cq < cqe_num) {
  966.     cqe_num = hca_cap.max_num_cq;
  967.     warning("%s: hardly enough completion queue entries %d, hoping for %d",
  968.       __func__, hca_cap.max_num_cq, cqe_num);
  969.     }
  970.  
  971.     /* build a CQ (ignore actual number returned) */
  972.     debug(0, "%s: asking for %d completion queue entries", __func__, cqe_num);
  973.     ret = VAPI_create_cq(vd->nic_handle, cqe_num, &vd->nic_cq, &cqe_num_out);
  974.     if (ret < 0)
  975.     error_verrno(ret, "%s: VAPI_create_cq ret %d", __func__, ret);
  976.  
  977.     /* create completion "channel" */
  978.     ret = pipe(vd->cq_event_pipe);
  979.     if (ret < 0)
  980.     error_errno("%s: pipe", __func__);
  981.     flags = fcntl(vd->cq_event_pipe[0], F_GETFL);
  982.     if (flags < 0)
  983.     error_errno("%s: get cq pipe flags", __func__);
  984.     if (fcntl(vd->cq_event_pipe[0], F_SETFL, flags | O_NONBLOCK) < 0)
  985.     error_errno("%s: set cq pipe nonblocking", __func__);
  986.  
  987.     /* register handler for the cq */
  988.     ret = EVAPI_set_comp_eventh(vd->nic_handle, vd->nic_cq, cq_event_handler,
  989.                                 NULL, &vd->nic_cq_event_handler);
  990.     if (ret < 0)
  991.     error_verrno(ret, "%s: EVAPI_set_comp_eventh", __func__);
  992.  
  993.     /* build a pipe to queue up async events, and set it to non-blocking
  994.      * on the receive side */
  995.     ret = pipe(vd->async_event_pipe);
  996.     if (ret < 0)
  997.     error_errno("%s: pipe", __func__);
  998.     flags = fcntl(vd->async_event_pipe[0], F_GETFL);
  999.     if (flags < 0)
  1000.     error_errno("%s: get async pipe flags", __func__);
  1001.     if (fcntl(vd->async_event_pipe[0], F_SETFL, flags | O_NONBLOCK) < 0)
  1002.     error_errno("%s: set async pipe nonblocking", __func__);
  1003.  
  1004.     /* will be set on first connection */
  1005.     vd->sg_tmp_array = NULL;
  1006.     vd->sg_max_len = 0;
  1007.     vd->max_outstanding_wr = 0;
  1008.  
  1009.     return 0;
  1010. }
  1011.  
  1012. /*
  1013.  * VAPI shutdown.
  1014.  */
  1015. static void vapi_ib_finalize(void)
  1016. {
  1017.     int ret;
  1018.     struct vapi_device_priv *vd = ib_device->priv;
  1019.  
  1020.     if (vd->sg_tmp_array)
  1021.     free(vd->sg_tmp_array);
  1022.     ret = EVAPI_clear_comp_eventh(vd->nic_handle, vd->nic_cq_event_handler);
  1023.     if (ret < 0)
  1024.     error_verrno(ret, "%s: EVAPI_clear_comp_eventh", __func__);
  1025.  
  1026.     close(vd->cq_event_pipe[0]);
  1027.     close(vd->cq_event_pipe[1]);
  1028.  
  1029.     ret = VAPI_destroy_cq(vd->nic_handle, vd->nic_cq);
  1030.     if (ret < 0)
  1031.     error_verrno(ret, "%s: VAPI_destroy_cq", __func__);
  1032.  
  1033.     ret = VAPI_dealloc_pd(vd->nic_handle, vd->nic_pd);
  1034.     if (ret < 0)
  1035.     error_verrno(ret, "%s: VAPI_dealloc_pd", __func__);
  1036.     ret = EVAPI_clear_async_event_handler(vd->nic_handle,
  1037.                                           vd->nic_async_event_handler);
  1038.     if (ret < 0)
  1039.     error_verrno(ret, "%s: EVAPI_clear_async_event_handler", __func__);
  1040.     ret = EVAPI_release_hca_hndl(vd->nic_handle);
  1041.  
  1042.     close(vd->async_event_pipe[0]);
  1043.     close(vd->async_event_pipe[1]);
  1044.  
  1045.     if (ret < 0)
  1046.     error_verrno(ret, "%s: EVAPI_release_hca_hndl", __func__);
  1047.     ret = VAPI_close_hca(vd->nic_handle);
  1048.     /*
  1049.      * Buggy vapi always returns EBUSY, just like for the open
  1050.     if (ret < 0)
  1051.     error_verrno(ret, "%s: VAPI_close_hca", __func__);
  1052.      */
  1053.  
  1054.     free(vd);
  1055.     ib_device->priv = NULL;
  1056. }
  1057.  
  1058.