[Pkg-ofed-commits] [libibverbs] 07/24: Imported Upstream version 1.1

Ana Beatriz Guerrero López ana at moszumanska.debian.org
Wed Jul 2 13:16:47 UTC 2014


This is an automated email from the git hooks/post-receive script.

ana pushed a commit to branch master
in repository libibverbs.

commit 9ebb4937ef31c839e2cc41a5539c7960eaa48c8f
Author: Ana Guerrero López <ana at ekaia.org>
Date:   Wed Jul 2 15:15:07 2014 +0200

    Imported Upstream version 1.1
---
 ChangeLog                     | 122 ++++--
 Makefile.am                   |  62 ++-
 Makefile.in                   | 149 +++++--
 README                        |  57 +--
 config.h.in                   |   6 +-
 config/compile                |   4 +-
 config/depcomp                |   9 +-
 config/install-sh             |   2 +-
 config/missing                |   9 +-
 configure                     | 356 +++++------------
 configure.in                  |  32 +-
 examples/asyncwatch.c         |   2 -
 examples/device_list.c        |   2 -
 examples/devinfo.c            |  12 +-
 examples/pingpong.c           |   2 -
 examples/pingpong.h           |   2 -
 examples/rc_pingpong.c        |  63 ++-
 examples/srq_pingpong.c       |  73 +++-
 examples/uc_pingpong.c        |  63 ++-
 examples/ud_pingpong.c        |  68 +++-
 include/infiniband/arch.h     |   2 -
 include/infiniband/driver.h   |  35 +-
 include/infiniband/kern-abi.h |   4 +-
 include/infiniband/marshall.h |  24 +-
 include/infiniband/opcode.h   |   2 -
 include/infiniband/sa.h       |   9 -
 include/infiniband/verbs.h    | 144 ++++++-
 libibverbs.spec               |  50 ++-
 libibverbs.spec.in            |  50 ++-
 man/ibv_alloc_pd.3            |  40 ++
 man/ibv_attach_mcast.3        |  53 +++
 man/ibv_create_ah.3           |  64 +++
 man/ibv_create_ah_from_wc.3   |  63 +++
 man/ibv_create_comp_channel.3 |  49 +++
 man/ibv_create_cq.3           |  57 +++
 man/ibv_create_qp.3           |  85 ++++
 man/ibv_create_srq.3          |  67 ++++
 man/ibv_fork_init.3           |  56 +++
 man/ibv_get_async_event.3     | 162 ++++++++
 man/ibv_get_cq_event.3        | 181 +++++++++
 man/ibv_get_device_guid.3     |  25 ++
 man/ibv_get_device_list.3     |  46 +++
 man/ibv_get_device_name.3     |  25 ++
 man/ibv_modify_qp.3           | 169 ++++++++
 man/ibv_modify_srq.3          |  63 +++
 man/ibv_open_device.3         |  43 ++
 man/ibv_poll_cq.3             |  77 ++++
 man/ibv_post_recv.3           |  70 ++++
 man/ibv_post_send.3           | 121 ++++++
 man/ibv_post_srq_recv.3       |  61 +++
 man/ibv_query_device.3        |  84 ++++
 man/ibv_query_gid.3           |  33 ++
 man/ibv_query_pkey.3          |  33 ++
 man/ibv_query_port.3          |  61 +++
 man/ibv_query_qp.3            |  88 +++++
 man/ibv_query_srq.3           |  44 +++
 man/ibv_rate_to_mult.3        |  46 +++
 man/ibv_rc_pingpong.1         |  12 +-
 man/ibv_reg_mr.3              |  77 ++++
 man/ibv_req_notify_cq.3       |  43 ++
 man/ibv_resize_cq.3           |  42 ++
 man/ibv_srq_pingpong.1        |  14 +-
 man/ibv_uc_pingpong.1         |  12 +-
 man/ibv_ud_pingpong.1         |  12 +-
 src/cmd.c                     |  50 ++-
 src/compat-1_0.c              | 898 ++++++++++++++++++++++++++++++++++++++++++
 src/device.c                  |  44 ++-
 src/ibverbs.h                 |  31 +-
 src/init.c                    | 467 +++++++++++++++-------
 src/libibverbs.map            |  21 +-
 src/marshall.c                |  24 +-
 src/memory.c                  | 533 +++++++++++++++++++------
 src/sysfs.c                   |  10 +-
 src/verbs.c                   | 242 +++++++++---
 74 files changed, 4962 insertions(+), 951 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 6e6db82..27ee956 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,3 @@
-2006-10-31  Roland Dreier  <rdreier at cisco.com>
-
-	* Release version 1.0.4.
-
 2006-10-30  Jack Morgenstein  <jackm at mellanox.co.il>
 	
 	* src/cmd.c (ibv_cmd_query_qp): Unmarshall sq_draining instead of
@@ -12,27 +8,18 @@
 
 2006-10-30  Roland Dreier  <rdreier at cisco.com>
 
-	* src/init.c (add_device): Fix two operator precedence bugs in the
-	same line: [] and ++ both bind tighter than *.
-	(find_sysfs_devs): Iterate through sysfs devices in reverse, since
-	we're pushing them onto another list.  Otherwise libibverbs will
-	report devices in the opposite order from how it used to.  This
-	should really be OK, but it's nicer not to change behavior in the
-	middle of a stable series.
+	* src/init.c (find_drivers): Make find_drivers() take a const
+	directory name, and tweak how we strip trailing /s so that we
+	don't have to modify the directory name passed in.  Constify
+	default_path too.
 
-2006-10-27  Roland Dreier  <rdreier at cisco.com>
+2006-10-25  Roland Dreier  <rdreier at cisco.com>
 
-	* src/init.c: Revise initialization order to fix static linking.
-	Using dlopen() on a device-specific driver from a statically
-	linked copy of libibverbs will crash, because the driver will
-	bring in dynamic copies of libibverbs and libdl that clash with
-	the copies already linked statically.
+	* src/init.c (init_drivers): Remove assignment to dev->driver now
+	that it is gone for good.
 
-	To fix this, we change the way we search for drivers: first we
-	find all uverbs devices and try the driver (if any) that is
-	linked in directly.  If all devices are handled by that driver,
-	then we don't proceed any further.  If not, then we try dynamic
-	loading of drivers and match them against any remaining devices.
+	* include/infiniband/verbs.h: Remove .driver member of struct
+	ibv_device, since it is never really used.
 
 2006-10-17  Roland Dreier  <rdreier at cisco.com>
 
@@ -70,12 +57,73 @@
 	ibv_cmd_modify_qp): Set reserved fields to 0 to avoid future
 	problems and also to make Valgrind a little quieter.
 
+	* src/init.c (init_drivers): Set node_type and transport_type
+	values of device being created.
+
+	* include/infiniband/verbs.h: Add ibv_node_type enum value
+	IBV_NODE_RNIC, and add enum ibv_transport_type.  Add node_type and
+	transport_type fields to struct ibv_device.
+
+2006-09-12  Roland Dreier  <rdreier at cisco.com>
+
+	* include/infiniband/verbs.h: Swap wr_id and next members of
+	struct ibv_send_wr and struct ibv_recv_wr.  This allows wr_id to
+	be naturally aligned without padding on 32-bit platforms.
+
+2006-08-23  Roland Dreier  <rdreier at cisco.com>
+
+	* include/infiniband/driver.h: Add a definition of the macro
+	IBV_CMD_RESIZE_CQ_HAS_RESP_PARAMS so that low-level driver plugins
+	can detect the changed signature of ibv_cmd_resize_cq().
+
+2006-08-23  Ralph Campbell  <ralph.campbell at qlogic.com>
+
+	* src/cmd.c (ibv_cmd_resize_cq): Add resp and resp_size parameters
+	so that the low-level driver in the kernel can return
+	device-specific information from the resize CQ operation.
+
+2006-07-26  Roland Dreier  <rdreier at cisco.com>
+
+	* src/verbs.c (ibv_reg_mr, ibv_dereg_mr): Add calls to
+	ibv_dontfork_range() and ibv_dofork_range() for memory regions
+	registered by library consumers.
+
+	* include/infiniband/verbs.h: Add declaration of ibv_fork_init().
+
+	* include/infiniband/driver.h: Add declarations of
+	ibv_dontfork_range() and ibv_dofork_range().
+
+	* src/memory.c: Rewrite to use a red-black tree instead of a
+	linked list.  Change from doing mlock()/munlock() to
+	madvise(..., MADV_DONTFORK) and madvise(..., MADV_DOFORK), and
+	change the name of the entry points to ibv_dontfork_range() and
+	ibv_dofork_range().  Add ibv_fork_init() for applications to
+	request fork-safe behavior.
+
+	* src/ibverbs.h: Kill off unused declarations.
+
+	* src/init.c (ibverbs_init): Get rid of call to ibv_init_mem_map().
+
+	* include/infiniband/verbs.h: Add addr and length field to struct
+	ibv_mr so that memory regions can be madvised().  This changes the
+	ABI, since the layout of struct ibv_mr is changed.
+
 2006-07-04  Roland Dreier  <rdreier at cisco.com>
 
 	* include/infiniband/arch.h: Fix typo in sparc mb()
 	implementation: the asm should just be empty -- the "sync"
 	instruction was mistakenly cut and pasted from the ppc version.
 
+2006-06-07  Sean Hefty     <sean.hefty at intel.com>
+
+	* src/verbs.c include/infiniband/verbs.h: Add new routines:
+	ibv_init_ah_from_wc() and ibv_create_ah_from_wc() to simplify UD QP
+	communication.
+
+	* src/marshall.c include/infiniband/marshall.h: Expose
+	ibv_copy_ah_attr_from_kern to retrieve ibv_ah_attr from kernel for
+	a UD QP.
+
 2006-06-01  Roland Dreier  <rdreier at cisco.com>
 
 	* src/device.c (ibv_get_device_list): Actually return a
@@ -83,9 +131,8 @@
 
 2006-05-31  Roland Dreier  <rdreier at cisco.com>
 
-	* src/init.c (find_drivers), src/device.c (ibv_open_device): Fix
-	memory leaks: the result of asprintf() needs to be freed when
-	we're done with it.
+	* src/init.c (find_drivers): Fix memory leak: the result of
+	asprintf() needs to be freed when we're done with it.
 
 	* examples/asyncwatch.c (event_name_str): Print human-readable
 	form of IBV_EVENT_CLIENT_REREGISTER.
@@ -94,6 +141,31 @@
 
 	* include/infiniband/verbs.h: Add IBV_EVENT_CLIENT_REREGISTER.
 
+2006-05-22  Roland Dreier  <rdreier at cisco.com>
+
+	* examples/devinfo.c (print_hca_cap): Read board_id attribute from
+	sysfs using ibv_read_sysfs_file() instead of libsysfs.
+
+	* src/cmd.c, src/marshall.c, src/sysfs.c: Include <string.h>,
+	since it is no longer implicitly included via <sysfs/libsysfs.h>.
+
+	* include/infiniband/driver.h, include/infiniband/verbs.h,
+	src/device.c, src/init.c, src/verbs.c: Remove dependency on
+	libsysfs by implementing what is required directly on top of
+	filesystem operations.
+
+	* include/infiniband/driver.h, src/init.c: Change name of driver
+	entry point to ibv_driver_init(), and update prototype to remove
+	libsysfs dependency.
+
+	* src/marshall.c, include/infiniband/marshall.h,
+	include/infiniband/sa.h: Remove deprecated ib_xxx symbols.
+
+	* Makefile.am: Bump SONAME to 2, since libibverbs 1.1 will be
+	ABI-incompatible with libibverbs 1.0.
+
+	* Create libibverbs 1.1 branch and bump version number to 1.1-pre1.
+
 2006-05-22  Michael S. Tsirkin  <mst at mellanox.co.il>
 
 	* include/infiniband/verbs.h: Remove trailing commas from
diff --git a/Makefile.am b/Makefile.am
index c89e73a..705b184 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,21 +1,15 @@
-# $Id: Makefile.am 7484 2006-05-24 21:12:21Z roland $
-
 INCLUDES = -I$(srcdir)/include
 
 lib_LTLIBRARIES = src/libibverbs.la
 
 AM_CFLAGS = -g -Wall -D_GNU_SOURCE
 
-src_libibverbs_la_CFLAGS = -g -Wall -D_GNU_SOURCE -DDRIVER_PATH=\"$(libdir)/infiniband\"
+src_libibverbs_la_CFLAGS = $(AM_CFLAGS) -DIBV_CONFIG_DIR=\"$(sysconfdir)/libibverbs.d\"
 
-if HAVE_LD_VERSION_SCRIPT
-    libibverbs_version_script = -Wl,--version-script=$(srcdir)/src/libibverbs.map
-else
-    libibverbs_version_script =
-endif
+libibverbs_version_script = @LIBIBVERBS_VERSION_SCRIPT@
 
-src_libibverbs_la_SOURCES = src/cmd.c src/device.c src/init.c src/marshall.c \
-			    src/memory.c src/sysfs.c src/verbs.c
+src_libibverbs_la_SOURCES = src/cmd.c src/compat-1_0.c src/device.c src/init.c \
+			    src/marshall.c src/memory.c src/sysfs.c src/verbs.c
 src_libibverbs_la_LDFLAGS = -version-info 1 -export-dynamic \
     $(libibverbs_version_script)
 src_libibverbs_la_DEPENDENCIES = $(srcdir)/src/libibverbs.map
@@ -44,9 +38,21 @@ libibverbsinclude_HEADERS = include/infiniband/arch.h include/infiniband/driver.
     include/infiniband/kern-abi.h include/infiniband/opcode.h include/infiniband/verbs.h \
     include/infiniband/sa-kern-abi.h include/infiniband/sa.h include/infiniband/marshall.h
 
-man_MANS = man/ibv_asyncwatch.1 man/ibv_devices.1 man/ibv_devinfo.1 \
+man_MANS = man/ibv_asyncwatch.1 man/ibv_devices.1 man/ibv_devinfo.1   \
     man/ibv_rc_pingpong.1 man/ibv_uc_pingpong.1 man/ibv_ud_pingpong.1 \
-    man/ibv_srq_pingpong.1
+    man/ibv_srq_pingpong.1 \
+    man/ibv_alloc_pd.3 man/ibv_attach_mcast.3 man/ibv_create_ah.3      \
+    man/ibv_create_ah_from_wc.3 man/ibv_create_comp_channel.3	       \
+    man/ibv_create_cq.3 man/ibv_create_qp.3 man/ibv_create_srq.3       \
+    man/ibv_fork_init.3 man/ibv_get_async_event.3		       \
+    man/ibv_get_cq_event.3 man/ibv_get_device_guid.3		       \
+    man/ibv_get_device_list.3 man/ibv_get_device_name.3		       \
+    man/ibv_modify_qp.3 man/ibv_modify_srq.3 man/ibv_open_device.3     \
+    man/ibv_poll_cq.3 man/ibv_post_recv.3 man/ibv_post_send.3	       \
+    man/ibv_post_srq_recv.3 man/ibv_query_device.3 man/ibv_query_gid.3 \
+    man/ibv_query_pkey.3 man/ibv_query_port.3 man/ibv_query_qp.3       \
+    man/ibv_query_srq.3 man/ibv_rate_to_mult.3 man/ibv_reg_mr.3	       \
+    man/ibv_req_notify_cq.3 man/ibv_resize_cq.3
 
 DEBIAN = debian/changelog debian/compat debian/control debian/copyright \
     debian/ibverbs-utils.install debian/libibverbs1.install \
@@ -61,3 +67,35 @@ EXTRA_DIST = include/infiniband/driver.h include/infiniband/kern-abi.h \
 
 dist-hook: libibverbs.spec
 	cp libibverbs.spec $(distdir)
+
+install-data-hook:
+	cd $(DESTDIR)$(mandir)/man3 && \
+	$(RM) ibv_ack_async_event.3 && \
+	$(RM) ibv_ack_cq_events.3 && \
+	$(RM) ibv_close_device.3 && \
+	$(RM) ibv_dealloc_pd.3 && \
+	$(RM) ibv_dereg_mr.3 && \
+	$(RM) ibv_destroy_ah.3 && \
+	$(RM) ibv_destroy_comp_channel.3 && \
+	$(RM) ibv_destroy_cq.3 && \
+	$(RM) ibv_destroy_qp.3 && \
+	$(RM) ibv_destroy_srq.3 && \
+	$(RM) ibv_detach_mcast.3 && \
+	$(RM) ibv_free_device_list.3 && \
+	$(RM) ibv_init_ah_from_wc.3 && \
+	$(RM) mult_to_ibv_rate.3 && \
+	$(LN_S) ibv_get_async_event.3 ibv_ack_async_event.3 && \
+	$(LN_S) ibv_get_cq_event.3 ibv_ack_cq_events.3 && \
+	$(LN_S) ibv_open_device.3 ibv_close_device.3 && \
+	$(LN_S) ibv_alloc_pd.3 ibv_dealloc_pd.3 && \
+	$(LN_S) ibv_reg_mr.3 ibv_dereg_mr.3 && \
+	$(LN_S) ibv_create_ah.3 ibv_destroy_ah.3 && \
+	$(LN_S) ibv_create_comp_channel.3 ibv_destroy_comp_channel.3 && \
+	$(LN_S) ibv_create_cq.3 ibv_destroy_cq.3 && \
+	$(LN_S) ibv_create_qp.3 ibv_destroy_qp.3 && \
+	$(LN_S) ibv_create_srq.3 ibv_destroy_srq.3 && \
+	$(LN_S) ibv_attach_mcast.3 ibv_detach_mcast.3 && \
+	$(LN_S) ibv_get_device_list.3 ibv_free_device_list.3 && \
+	$(LN_S) ibv_create_ah_from_wc.3 ibv_init_ah_from_wc.3 && \
+	$(LN_S) ibv_rate_to_mult.3 mult_to_ibv_rate.3
+
diff --git a/Makefile.in b/Makefile.in
index 2849407..3a09c9c 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -14,8 +14,6 @@
 
 @SET_MAKE@
 
-# $Id: Makefile.am 7484 2006-05-24 21:12:21Z roland $
-
 
 
 srcdir = @srcdir@
@@ -70,14 +68,16 @@ am__vpath_adj = case $$p in \
   esac;
 am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
 am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
-	"$(DESTDIR)$(man1dir)" "$(DESTDIR)$(libibverbsincludedir)"
+	"$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man3dir)" \
+	"$(DESTDIR)$(libibverbsincludedir)"
 libLTLIBRARIES_INSTALL = $(INSTALL)
 LTLIBRARIES = $(lib_LTLIBRARIES)
 src_libibverbs_la_LIBADD =
 am_src_libibverbs_la_OBJECTS = src_libibverbs_la-cmd.lo \
-	src_libibverbs_la-device.lo src_libibverbs_la-init.lo \
-	src_libibverbs_la-marshall.lo src_libibverbs_la-memory.lo \
-	src_libibverbs_la-sysfs.lo src_libibverbs_la-verbs.lo
+	src_libibverbs_la-compat-1_0.lo src_libibverbs_la-device.lo \
+	src_libibverbs_la-init.lo src_libibverbs_la-marshall.lo \
+	src_libibverbs_la-memory.lo src_libibverbs_la-sysfs.lo \
+	src_libibverbs_la-verbs.lo
 src_libibverbs_la_OBJECTS = $(am_src_libibverbs_la_OBJECTS)
 am__dirstamp = $(am__leading_dot)dirstamp
 binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
@@ -145,6 +145,7 @@ DIST_SOURCES = $(src_libibverbs_la_SOURCES) \
 	$(examples_ibv_uc_pingpong_SOURCES) \
 	$(examples_ibv_ud_pingpong_SOURCES)
 man1dir = $(mandir)/man1
+man3dir = $(mandir)/man3
 NROFF = nroff
 MANS = $(man_MANS)
 libibverbsincludeHEADERS_INSTALL = $(INSTALL_HEADER)
@@ -191,13 +192,12 @@ EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 F77 = @F77@
 FFLAGS = @FFLAGS@
-HAVE_LD_VERSION_SCRIPT_FALSE = @HAVE_LD_VERSION_SCRIPT_FALSE@
-HAVE_LD_VERSION_SCRIPT_TRUE = @HAVE_LD_VERSION_SCRIPT_TRUE@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
 INSTALL_SCRIPT = @INSTALL_SCRIPT@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
 LDFLAGS = @LDFLAGS@
+LIBIBVERBS_VERSION_SCRIPT = @LIBIBVERBS_VERSION_SCRIPT@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
@@ -264,11 +264,10 @@ target_alias = @target_alias@
 INCLUDES = -I$(srcdir)/include
 lib_LTLIBRARIES = src/libibverbs.la
 AM_CFLAGS = -g -Wall -D_GNU_SOURCE
-src_libibverbs_la_CFLAGS = -g -Wall -D_GNU_SOURCE -DDRIVER_PATH=\"$(libdir)/infiniband\"
- at HAVE_LD_VERSION_SCRIPT_FALSE@libibverbs_version_script = 
- at HAVE_LD_VERSION_SCRIPT_TRUE@libibverbs_version_script = -Wl,--version-script=$(srcdir)/src/libibverbs.map
-src_libibverbs_la_SOURCES = src/cmd.c src/device.c src/init.c src/marshall.c \
-			    src/memory.c src/sysfs.c src/verbs.c
+src_libibverbs_la_CFLAGS = $(AM_CFLAGS) -DIBV_CONFIG_DIR=\"$(sysconfdir)/libibverbs.d\"
+libibverbs_version_script = @LIBIBVERBS_VERSION_SCRIPT@
+src_libibverbs_la_SOURCES = src/cmd.c src/compat-1_0.c src/device.c src/init.c \
+			    src/marshall.c src/memory.c src/sysfs.c src/verbs.c
 
 src_libibverbs_la_LDFLAGS = -version-info 1 -export-dynamic \
     $(libibverbs_version_script)
@@ -293,9 +292,21 @@ libibverbsinclude_HEADERS = include/infiniband/arch.h include/infiniband/driver.
     include/infiniband/kern-abi.h include/infiniband/opcode.h include/infiniband/verbs.h \
     include/infiniband/sa-kern-abi.h include/infiniband/sa.h include/infiniband/marshall.h
 
-man_MANS = man/ibv_asyncwatch.1 man/ibv_devices.1 man/ibv_devinfo.1 \
+man_MANS = man/ibv_asyncwatch.1 man/ibv_devices.1 man/ibv_devinfo.1   \
     man/ibv_rc_pingpong.1 man/ibv_uc_pingpong.1 man/ibv_ud_pingpong.1 \
-    man/ibv_srq_pingpong.1
+    man/ibv_srq_pingpong.1 \
+    man/ibv_alloc_pd.3 man/ibv_attach_mcast.3 man/ibv_create_ah.3      \
+    man/ibv_create_ah_from_wc.3 man/ibv_create_comp_channel.3	       \
+    man/ibv_create_cq.3 man/ibv_create_qp.3 man/ibv_create_srq.3       \
+    man/ibv_fork_init.3 man/ibv_get_async_event.3		       \
+    man/ibv_get_cq_event.3 man/ibv_get_device_guid.3		       \
+    man/ibv_get_device_list.3 man/ibv_get_device_name.3		       \
+    man/ibv_modify_qp.3 man/ibv_modify_srq.3 man/ibv_open_device.3     \
+    man/ibv_poll_cq.3 man/ibv_post_recv.3 man/ibv_post_send.3	       \
+    man/ibv_post_srq_recv.3 man/ibv_query_device.3 man/ibv_query_gid.3 \
+    man/ibv_query_pkey.3 man/ibv_query_port.3 man/ibv_query_qp.3       \
+    man/ibv_query_srq.3 man/ibv_rate_to_mult.3 man/ibv_reg_mr.3	       \
+    man/ibv_req_notify_cq.3 man/ibv_resize_cq.3
 
 DEBIAN = debian/changelog debian/compat debian/control debian/copyright \
     debian/ibverbs-utils.install debian/libibverbs1.install \
@@ -462,6 +473,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/pingpong.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/rc_pingpong.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/src_libibverbs_la-cmd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/src_libibverbs_la-compat-1_0.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/src_libibverbs_la-device.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/src_libibverbs_la-init.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/src_libibverbs_la-marshall.Plo at am__quote@
@@ -500,6 +512,13 @@ src_libibverbs_la-cmd.lo: src/cmd.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libibverbs_la_CFLAGS) $(CFLAGS) -c -o src_libibverbs_la-cmd.lo `test -f 'src/cmd.c' || echo '$(srcdir)/'`src/cmd.c
 
+src_libibverbs_la-compat-1_0.lo: src/compat-1_0.c
+ at am__fastdepCC_TRUE@	if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libibverbs_la_CFLAGS) $(CFLAGS) -MT src_libibverbs_la-compat-1_0.lo -MD -MP -MF "$(DEPDIR)/src_libibverbs_la-compat-1_0.Tpo" -c -o src_libibverbs_la-compat-1_0.lo `test -f 'src/compat-1_0.c' || echo '$(srcdir)/'`src/compat-1_0.c; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/src_libibverbs_la-compat-1_0.Tpo" "$(DEPDIR)/src_libibverbs_la-compat-1_0.Plo"; else rm -f "$(DEPDIR)/src_libibverbs_la-compat-1_0.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='src/compat-1_0.c' object='src_libibverbs_la-compat-1_0.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libibverbs_la_CFLAGS) $(CFLAGS) -c -o src_libibverbs_la-compat-1_0.lo `test -f 'src/compat-1_0.c' || echo '$(srcdir)/'`src/compat-1_0.c
+
 src_libibverbs_la-device.lo: src/device.c
 @am__fastdepCC_TRUE@	if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libibverbs_la_CFLAGS) $(CFLAGS) -MT src_libibverbs_la-device.lo -MD -MP -MF "$(DEPDIR)/src_libibverbs_la-device.Tpo" -c -o src_libibverbs_la-device.lo `test -f 'src/device.c' || echo '$(srcdir)/'`src/device.c; \
 @am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/src_libibverbs_la-device.Tpo" "$(DEPDIR)/src_libibverbs_la-device.Plo"; else rm -f "$(DEPDIR)/src_libibverbs_la-device.Tpo"; exit 1; fi
@@ -709,6 +728,51 @@ uninstall-man1:
 	  echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \
 	  rm -f "$(DESTDIR)$(man1dir)/$$inst"; \
 	done
+install-man3: $(man3_MANS) $(man_MANS)
+	@$(NORMAL_INSTALL)
+	test -z "$(man3dir)" || $(mkdir_p) "$(DESTDIR)$(man3dir)"
+	@list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \
+	l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+	for i in $$l2; do \
+	  case "$$i" in \
+	    *.3*) list="$$list $$i" ;; \
+	  esac; \
+	done; \
+	for i in $$list; do \
+	  if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+	  else file=$$i; fi; \
+	  ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+	  case "$$ext" in \
+	    3*) ;; \
+	    *) ext='3' ;; \
+	  esac; \
+	  inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+	  inst=`echo $$inst | sed -e 's/^.*\///'`; \
+	  inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+	  echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \
+	  $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst"; \
+	done
+uninstall-man3:
+	@$(NORMAL_UNINSTALL)
+	@list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \
+	l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+	for i in $$l2; do \
+	  case "$$i" in \
+	    *.3*) list="$$list $$i" ;; \
+	  esac; \
+	done; \
+	for i in $$list; do \
+	  ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+	  case "$$ext" in \
+	    3*) ;; \
+	    *) ext='3' ;; \
+	  esac; \
+	  inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+	  inst=`echo $$inst | sed -e 's/^.*\///'`; \
+	  inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+	  echo " rm -f '$(DESTDIR)$(man3dir)/$$inst'"; \
+	  rm -f "$(DESTDIR)$(man3dir)/$$inst"; \
+	done
 install-libibverbsincludeHEADERS: $(libibverbsinclude_HEADERS)
 	@$(NORMAL_INSTALL)
 	test -z "$(libibverbsincludedir)" || $(mkdir_p) "$(DESTDIR)$(libibverbsincludedir)"
@@ -912,7 +976,7 @@ all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(MANS) $(HEADERS) \
 install-binPROGRAMS: install-libLTLIBRARIES
 
 installdirs:
-	for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(libibverbsincludedir)"; do \
+	for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(libibverbsincludedir)"; do \
 	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
 	done
 install: install-am
@@ -964,12 +1028,14 @@ info: info-am
 info-am:
 
 install-data-am: install-libibverbsincludeHEADERS install-man
+	@$(NORMAL_INSTALL)
+	$(MAKE) $(AM_MAKEFLAGS) install-data-hook
 
 install-exec-am: install-binPROGRAMS install-libLTLIBRARIES
 
 install-info: install-info-am
 
-install-man: install-man1
+install-man: install-man1 install-man3
 
 installcheck-am:
 
@@ -997,7 +1063,7 @@ uninstall-am: uninstall-binPROGRAMS uninstall-info-am \
 	uninstall-libLTLIBRARIES uninstall-libibverbsincludeHEADERS \
 	uninstall-man
 
-uninstall-man: uninstall-man1
+uninstall-man: uninstall-man1 uninstall-man3
 
 .PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \
 	clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
@@ -1007,20 +1073,51 @@ uninstall-man: uninstall-man1
 	distclean-libtool distclean-tags distcleancheck distdir \
 	distuninstallcheck dvi dvi-am html html-am info info-am \
 	install install-am install-binPROGRAMS install-data \
-	install-data-am install-exec install-exec-am install-info \
-	install-info-am install-libLTLIBRARIES \
+	install-data-am install-data-hook install-exec install-exec-am \
+	install-info install-info-am install-libLTLIBRARIES \
 	install-libibverbsincludeHEADERS install-man install-man1 \
-	install-strip installcheck installcheck-am installdirs \
-	maintainer-clean maintainer-clean-generic mostlyclean \
-	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
-	pdf pdf-am ps ps-am tags uninstall uninstall-am \
-	uninstall-binPROGRAMS uninstall-info-am \
+	install-man3 install-strip installcheck installcheck-am \
+	installdirs maintainer-clean maintainer-clean-generic \
+	mostlyclean mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+	uninstall-am uninstall-binPROGRAMS uninstall-info-am \
 	uninstall-libLTLIBRARIES uninstall-libibverbsincludeHEADERS \
-	uninstall-man uninstall-man1
+	uninstall-man uninstall-man1 uninstall-man3
 
 
 dist-hook: libibverbs.spec
 	cp libibverbs.spec $(distdir)
+
+install-data-hook:
+	cd $(DESTDIR)$(mandir)/man3 && \
+	$(RM) ibv_ack_async_event.3 && \
+	$(RM) ibv_ack_cq_events.3 && \
+	$(RM) ibv_close_device.3 && \
+	$(RM) ibv_dealloc_pd.3 && \
+	$(RM) ibv_dereg_mr.3 && \
+	$(RM) ibv_destroy_ah.3 && \
+	$(RM) ibv_destroy_comp_channel.3 && \
+	$(RM) ibv_destroy_cq.3 && \
+	$(RM) ibv_destroy_qp.3 && \
+	$(RM) ibv_destroy_srq.3 && \
+	$(RM) ibv_detach_mcast.3 && \
+	$(RM) ibv_free_device_list.3 && \
+	$(RM) ibv_init_ah_from_wc.3 && \
+	$(RM) mult_to_ibv_rate.3 && \
+	$(LN_S) ibv_get_async_event.3 ibv_ack_async_event.3 && \
+	$(LN_S) ibv_get_cq_event.3 ibv_ack_cq_events.3 && \
+	$(LN_S) ibv_open_device.3 ibv_close_device.3 && \
+	$(LN_S) ibv_alloc_pd.3 ibv_dealloc_pd.3 && \
+	$(LN_S) ibv_reg_mr.3 ibv_dereg_mr.3 && \
+	$(LN_S) ibv_create_ah.3 ibv_destroy_ah.3 && \
+	$(LN_S) ibv_create_comp_channel.3 ibv_destroy_comp_channel.3 && \
+	$(LN_S) ibv_create_cq.3 ibv_destroy_cq.3 && \
+	$(LN_S) ibv_create_qp.3 ibv_destroy_qp.3 && \
+	$(LN_S) ibv_create_srq.3 ibv_destroy_srq.3 && \
+	$(LN_S) ibv_attach_mcast.3 ibv_detach_mcast.3 && \
+	$(LN_S) ibv_get_device_list.3 ibv_free_device_list.3 && \
+	$(LN_S) ibv_create_ah_from_wc.3 ibv_init_ah_from_wc.3 && \
+	$(LN_S) ibv_rate_to_mult.3 mult_to_ibv_rate.3
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/README b/README
index 7b5780e..0b1b114 100644
--- a/README
+++ b/README
@@ -60,23 +60,6 @@ via the file /etc/security/limits.conf.  More configuration may be
 necessary if you are logging in via OpenSSH and your sshd is
 configured to use privilege separation.
 
-Static linking
---------------
-
-In almost all cases it is better to dynamically link libibverbs into
-an application.  However, if you are forced to use static linking for
-libibverbs, then you will also have to link a device-specific
-userspace driver (such as libmthca, libipathverbs, libehca, etc)
-statically into your application.  This is because of limitations on
-dynamically loading new modules into a static executable.
-
-In particular, a static application can only be linked against a
-single device-specific driver, which means that the application will
-only work with a single type of device.  This limitation will be
-removed in future libibverbs releases, but this will require a change
-to the libibverbs ABI, so it cannot be done as part of the libibverbs
-1.0 release series.
-
 Valgrind support
 ----------------
 
@@ -97,7 +80,7 @@ uninitialized" warnings.  This code adds trivial overhead to the
 critical performance path, so it is disabled by default.  The intent
 is that production users can use a "normal" build of libibverbs and
 developers can use the "valgrind debug" build by simply switching
-their LD_LIBRARY_PATH and/or OPENIB_DRIVER_PATH environment variables.
+their LD_LIBRARY_PATH environment variables.
 
 Libibverbs needs some header files from Valgrind in order to compile
 this support; it is important to use the header files from the same
@@ -113,8 +96,8 @@ will make the libibverbs build look for valgrind headers in
 Reporting bugs
 ==============
 
-Bugs should be reported to the OpenIB mailing list
-<openib-general at openib.org>.  In your bug report, please include:
+Bugs should be reported to the OpenFabrics mailing list
+<general at lists.openfabrics.org>.  In your bug report, please include:
 
  * Information about your system:
    - Linux distribution and version
@@ -135,8 +118,8 @@ Bugs should be reported to the OpenIB mailing list
 Submitting patches
 ==================
 
-Patches should also be submitted to the OpenIB mailing list
-<openib-general at openib.org>.  Please use unified diff form (the -u
+Patches should also be submitted to the OpenFabrics mailing list
+<general at lists.openfabrics.org>.  Please use unified diff form (the -u
 option to GNU diff), and include a good description of what your patch
 does and why it should be applied.  If your patch fixes a bug, please
 make sure to describe the bug and how your fix works.
@@ -151,40 +134,22 @@ necessary permissions to release your work.
 TODO
 ====
 
-1.0 series
-----------
-
- * Use the MADV_DONTFORK advice for madvise(2) to make applications
-   that use fork(2) work better.
-
 1.1 series
 ----------
 
-The libibverbs API and ABI are frozen for all releases in the 1.0
-series.  The following changes that break API or ABI are planned for
-the 1.1 release:
+The libibverbs API and ABI are frozen for all releases in the 1.1
+series.  Methods were added to struct ibv_context to implement the
+following features, so it should be possible to add them in a future
+release in the 1.1 series:
 
- * Implement memory window (MW) support.  This will break the
-   device driver ABI, because new methods will need to be added to
-   struct ibv_context_ops.
+ * Memory window (MW) support.
 
  * Implement the reregister memory region (MR) verb.  We will add an
    extension to the IB spec to allow the application to indicate that
    the region is only being extended, and that operations in progress
    should _not_ fail (contrary to the IB spec, which states that
    reregister must be implemented so that it behaves equivalently to a
-   deregister followed by a register).  This will break the device
-   driver ABI, because a new method will need to be added to struct
-   ibv_context_ops. 
-
- * Eliminate the dependency on libsysfs by implementing the required
-   sysfs handling directly.  This will break the API, because the dev
-   and ibdev members of struct ibv_device will be removed.  It will
-   also break the device driver ABI, because the signature of the
-   driver initialization function will change.  The driver
-   initialization function will be changed as part of this work; this
-   has the added benefit of allowing us to choose a better name than
-   "openib_driver_init."
+   deregister followed by a register).
 
 Other possibilities
 -------------------
diff --git a/config.h.in b/config.h.in
index 2e4427f..d47adb3 100644
--- a/config.h.in
+++ b/config.h.in
@@ -12,9 +12,6 @@
 /* Define to 1 if you have the `pthread' library (-lpthread). */
 #undef HAVE_LIBPTHREAD
 
-/* Define to 1 if you have the `sysfs' library (-lsysfs). */
-#undef HAVE_LIBSYSFS
-
 /* Define to 1 if you have the <memory.h> header file. */
 #undef HAVE_MEMORY_H
 
@@ -30,6 +27,9 @@
 /* Define to 1 if you have the <string.h> header file. */
 #undef HAVE_STRING_H
 
+/* assembler has .symver support */
+#undef HAVE_SYMVER_SUPPORT
+
 /* Define to 1 if you have the <sys/stat.h> header file. */
 #undef HAVE_SYS_STAT_H
 
diff --git a/config/compile b/config/compile
index ad57e2f..1b1d232 100755
--- a/config/compile
+++ b/config/compile
@@ -1,7 +1,7 @@
 #! /bin/sh
 # Wrapper for compilers which do not understand `-c -o'.
 
-scriptversion=2005-02-03.08
+scriptversion=2005-05-14.22
 
 # Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
 # Written by Tom Tromey <tromey at cygnus.com>.
@@ -18,7 +18,7 @@ scriptversion=2005-02-03.08
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
 # As a special exception to the GNU General Public License, if you
 # distribute this file as part of a program that contains a
diff --git a/config/depcomp b/config/depcomp
index ffcd540..04701da 100755
--- a/config/depcomp
+++ b/config/depcomp
@@ -1,7 +1,7 @@
 #! /bin/sh
 # depcomp - compile a program generating dependencies as side-effects
 
-scriptversion=2005-02-09.22
+scriptversion=2005-07-09.11
 
 # Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
 
@@ -17,8 +17,8 @@ scriptversion=2005-02-09.22
 
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
 
 # As a special exception to the GNU General Public License, if you
 # distribute this file as part of a program that contains a
@@ -467,7 +467,8 @@ cpp)
   done
 
   "$@" -E |
-    sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+    sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+       -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
     sed '$ s: \\$::' > "$tmpdepfile"
   rm -f "$depfile"
   echo "$object : \\" > "$depfile"
diff --git a/config/install-sh b/config/install-sh
index 1a83534..4d4a951 100755
--- a/config/install-sh
+++ b/config/install-sh
@@ -1,7 +1,7 @@
 #!/bin/sh
 # install - install a program, script, or datafile
 
-scriptversion=2005-02-02.21
+scriptversion=2005-05-14.22
 
 # This originates from X11R5 (mit/util/scripts/install.sh), which was
 # later released in X11R6 (xc/config/util/install.sh) with the
diff --git a/config/missing b/config/missing
index 09edd88..894e786 100755
--- a/config/missing
+++ b/config/missing
@@ -1,7 +1,7 @@
 #! /bin/sh
 # Common stub for a few missing GNU programs while installing.
 
-scriptversion=2005-02-08.22
+scriptversion=2005-06-08.21
 
 # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005
 #   Free Software Foundation, Inc.
@@ -19,8 +19,8 @@ scriptversion=2005-02-08.22
 
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
 
 # As a special exception to the GNU General Public License, if you
 # distribute this file as part of a program that contains a
@@ -297,6 +297,9 @@ WARNING: \`$1' is $msg.  You should only need it if
       # ... or it is derived from the source name (dir/f.texi becomes f.info)
       test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
     fi
+    # If the file does not exist, the user really needs makeinfo;
+    # let's fail without touching anything.
+    test -f $file || exit 1
     touch $file
     ;;
 
diff --git a/configure b/configure
index b650e34..eba17cd 100755
--- a/configure
+++ b/configure
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.59 for libibverbs 1.0.4.
+# Generated by GNU Autoconf 2.59 for libibverbs 1.1.
 #
-# Report bugs to <openib-general at openib.org>.
+# Report bugs to <general at lists.openfabrics.org>.
 #
 # Copyright (C) 2003 Free Software Foundation, Inc.
 # This configure script is free software; the Free Software Foundation
@@ -423,9 +423,9 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='libibverbs'
 PACKAGE_TARNAME='libibverbs'
-PACKAGE_VERSION='1.0.4'
-PACKAGE_STRING='libibverbs 1.0.4'
-PACKAGE_BUGREPORT='openib-general at openib.org'
+PACKAGE_VERSION='1.1'
+PACKAGE_STRING='libibverbs 1.1'
+PACKAGE_BUGREPORT='general at lists.openfabrics.org'
 
 ac_unique_file="src/ibverbs.h"
 # Factoring default headers for most tests.
@@ -465,7 +465,7 @@ ac_includes_default="\
 # include <unistd.h>
 #endif"
 
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INS [...]
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INS [...]
 ac_subst_files=''
 
 # Initialize some variables set by options.
@@ -954,7 +954,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures libibverbs 1.0.4 to adapt to many kinds of systems.
+\`configure' configures libibverbs 1.1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1020,7 +1020,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of libibverbs 1.0.4:";;
+     short | recursive ) echo "Configuration of libibverbs 1.1:";;
    esac
   cat <<\_ACEOF
 
@@ -1065,7 +1065,7 @@ Some influential environment variables:
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
 
-Report bugs to <openib-general at openib.org>.
+Report bugs to <general at lists.openfabrics.org>.
 _ACEOF
 fi
 
@@ -1161,7 +1161,7 @@ fi
 test -n "$ac_init_help" && exit 0
 if $ac_init_version; then
   cat <<\_ACEOF
-libibverbs configure 1.0.4
+libibverbs configure 1.1
 generated by GNU Autoconf 2.59
 
 Copyright (C) 2003 Free Software Foundation, Inc.
@@ -1175,7 +1175,7 @@ cat >&5 <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by libibverbs $as_me 1.0.4, which was
+It was created by libibverbs $as_me 1.1, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   $ $0 $@
@@ -1821,7 +1821,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE=libibverbs
- VERSION=1.0.4
+ VERSION=1.1
 
 
 cat >>confdefs.h <<_ACEOF
@@ -4455,9 +4455,9 @@ echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&
 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
     (
       cat <<\_ASBOX
-## ---------------------------------------- ##
-## Report this to openib-general at openib.org ##
-## ---------------------------------------- ##
+## -------------------------------------------- ##
+## Report this to general at lists.openfabrics.org ##
+## -------------------------------------------- ##
 _ASBOX
     ) |
       sed "s/^/$as_me: WARNING:     /" >&2
@@ -19475,6 +19475,17 @@ else
 fi
 
 
+echo "$as_me:$LINENO: checking whether ln -s works" >&5
+echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+  echo "$as_me:$LINENO: result: no, using $LN_S" >&5
+echo "${ECHO_T}no, using $LN_S" >&6
+fi
+
 
 
 echo "$as_me:$LINENO: checking for dlsym in -ldl" >&5
@@ -19633,230 +19644,6 @@ echo "$as_me: error: pthread_mutex_init() not found.  libibverbs requires libpth
 fi
 
 
-echo "$as_me:$LINENO: checking for sysfs_open_class in -lsysfs" >&5
-echo $ECHO_N "checking for sysfs_open_class in -lsysfs... $ECHO_C" >&6
-if test "${ac_cv_lib_sysfs_sysfs_open_class+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lsysfs  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-/* Override any gcc2 internal prototype to avoid an error.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-/* We use char because int might match the return type of a gcc2
-   builtin and then its argument prototype would still apply.  */
-char sysfs_open_class ();
-int
-main ()
-{
-sysfs_open_class ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
-  (eval $ac_link) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"
-			 || test ! -s conftest.err'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-	 { ac_try='test -s conftest$ac_exeext'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_lib_sysfs_sysfs_open_class=yes
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_lib_sysfs_sysfs_open_class=no
-fi
-rm -f conftest.err conftest.$ac_objext \
-      conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_sysfs_sysfs_open_class" >&5
-echo "${ECHO_T}$ac_cv_lib_sysfs_sysfs_open_class" >&6
-if test $ac_cv_lib_sysfs_sysfs_open_class = yes; then
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBSYSFS 1
-_ACEOF
-
-  LIBS="-lsysfs $LIBS"
-
-else
-  { { echo "$as_me:$LINENO: error: sysfs_open_class() not found.  libibverbs requires libsysfs." >&5
-echo "$as_me: error: sysfs_open_class() not found.  libibverbs requires libsysfs." >&2;}
-   { (exit 1); exit 1; }; }
-fi
-
-
-if test "${ac_cv_header_sysfs_libsysfs_h+set}" = set; then
-  echo "$as_me:$LINENO: checking for sysfs/libsysfs.h" >&5
-echo $ECHO_N "checking for sysfs/libsysfs.h... $ECHO_C" >&6
-if test "${ac_cv_header_sysfs_libsysfs_h+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-fi
-echo "$as_me:$LINENO: result: $ac_cv_header_sysfs_libsysfs_h" >&5
-echo "${ECHO_T}$ac_cv_header_sysfs_libsysfs_h" >&6
-else
-  # Is the header compilable?
-echo "$as_me:$LINENO: checking sysfs/libsysfs.h usability" >&5
-echo $ECHO_N "checking sysfs/libsysfs.h usability... $ECHO_C" >&6
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <sysfs/libsysfs.h>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
-  (eval $ac_compile) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"
-			 || test ! -s conftest.err'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-	 { ac_try='test -s conftest.$ac_objext'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_header_compiler=yes
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_header_compiler=no
-fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
-echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-echo "${ECHO_T}$ac_header_compiler" >&6
-
-# Is the header present?
-echo "$as_me:$LINENO: checking sysfs/libsysfs.h presence" >&5
-echo $ECHO_N "checking sysfs/libsysfs.h presence... $ECHO_C" >&6
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <sysfs/libsysfs.h>
-_ACEOF
-if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
-  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null; then
-  if test -s conftest.err; then
-    ac_cpp_err=$ac_c_preproc_warn_flag
-    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
-  else
-    ac_cpp_err=
-  fi
-else
-  ac_cpp_err=yes
-fi
-if test -z "$ac_cpp_err"; then
-  ac_header_preproc=yes
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  ac_header_preproc=no
-fi
-rm -f conftest.err conftest.$ac_ext
-echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-echo "${ECHO_T}$ac_header_preproc" >&6
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { echo "$as_me:$LINENO: WARNING: sysfs/libsysfs.h: accepted by the compiler, rejected by the preprocessor!" >&5
-echo "$as_me: WARNING: sysfs/libsysfs.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { echo "$as_me:$LINENO: WARNING: sysfs/libsysfs.h: proceeding with the compiler's result" >&5
-echo "$as_me: WARNING: sysfs/libsysfs.h: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { echo "$as_me:$LINENO: WARNING: sysfs/libsysfs.h: present but cannot be compiled" >&5
-echo "$as_me: WARNING: sysfs/libsysfs.h: present but cannot be compiled" >&2;}
-    { echo "$as_me:$LINENO: WARNING: sysfs/libsysfs.h:     check for missing prerequisite headers?" >&5
-echo "$as_me: WARNING: sysfs/libsysfs.h:     check for missing prerequisite headers?" >&2;}
-    { echo "$as_me:$LINENO: WARNING: sysfs/libsysfs.h: see the Autoconf documentation" >&5
-echo "$as_me: WARNING: sysfs/libsysfs.h: see the Autoconf documentation" >&2;}
-    { echo "$as_me:$LINENO: WARNING: sysfs/libsysfs.h:     section \"Present But Cannot Be Compiled\"" >&5
-echo "$as_me: WARNING: sysfs/libsysfs.h:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { echo "$as_me:$LINENO: WARNING: sysfs/libsysfs.h: proceeding with the preprocessor's result" >&5
-echo "$as_me: WARNING: sysfs/libsysfs.h: proceeding with the preprocessor's result" >&2;}
-    { echo "$as_me:$LINENO: WARNING: sysfs/libsysfs.h: in the future, the compiler will take precedence" >&5
-echo "$as_me: WARNING: sysfs/libsysfs.h: in the future, the compiler will take precedence" >&2;}
-    (
-      cat <<\_ASBOX
-## ---------------------------------------- ##
-## Report this to openib-general at openib.org ##
-## ---------------------------------------- ##
-_ASBOX
-    ) |
-      sed "s/^/$as_me: WARNING:     /" >&2
-    ;;
-esac
-echo "$as_me:$LINENO: checking for sysfs/libsysfs.h" >&5
-echo $ECHO_N "checking for sysfs/libsysfs.h... $ECHO_C" >&6
-if test "${ac_cv_header_sysfs_libsysfs_h+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  ac_cv_header_sysfs_libsysfs_h=$ac_header_preproc
-fi
-echo "$as_me:$LINENO: result: $ac_cv_header_sysfs_libsysfs_h" >&5
-echo "${ECHO_T}$ac_cv_header_sysfs_libsysfs_h" >&6
-
-fi
-if test $ac_cv_header_sysfs_libsysfs_h = yes; then
-  :
-else
-  { { echo "$as_me:$LINENO: error: <sysfs/libsysfs.h> not found.  libibverbs requires libsysfs." >&5
-echo "$as_me: error: <sysfs/libsysfs.h> not found.  libibverbs requires libsysfs." >&2;}
-   { (exit 1); exit 1; }; }
-fi
-
-
 echo "$as_me:$LINENO: checking for ANSI C header files" >&5
 echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
 if test "${ac_cv_header_stdc+set}" = set; then
@@ -20141,9 +19928,9 @@ echo "$as_me: WARNING: valgrind/memcheck.h: proceeding with the preprocessor's r
 echo "$as_me: WARNING: valgrind/memcheck.h: in the future, the compiler will take precedence" >&2;}
     (
       cat <<\_ASBOX
-## ---------------------------------------- ##
-## Report this to openib-general at openib.org ##
-## ---------------------------------------- ##
+## -------------------------------------------- ##
+## Report this to general at lists.openfabrics.org ##
+## -------------------------------------------- ##
 _ASBOX
     ) |
       sed "s/^/$as_me: WARNING:     /" >&2
@@ -20288,24 +20075,81 @@ if test "${ac_cv_version_script+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   if test -n "`$LD --help < /dev/null 2>/dev/null | grep version-script`"; then
-        ac_cv_version_script=yes
+	ac_cv_version_script=yes
     else
-        ac_cv_version_script=no
+	ac_cv_version_script=no
     fi
 fi
 echo "$as_me:$LINENO: result: $ac_cv_version_script" >&5
 echo "${ECHO_T}$ac_cv_version_script" >&6
 
+if test $ac_cv_version_script = yes; then
+    LIBIBVERBS_VERSION_SCRIPT='-Wl,--version-script=$(srcdir)/src/libibverbs.map'
+else
+    LIBIBVERBS_VERSION_SCRIPT=
+fi
 
 
-if test "$ac_cv_version_script" = "yes"; then
-  HAVE_LD_VERSION_SCRIPT_TRUE=
-  HAVE_LD_VERSION_SCRIPT_FALSE='#'
+echo "$as_me:$LINENO: checking for .symver assembler support" >&5
+echo $ECHO_N "checking for .symver assembler support... $ECHO_C" >&6
+if test "${ac_cv_asm_symver_support+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+asm("symbol:\n.symver symbol, api at ABI\n");
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_asm_symver_support=yes
 else
-  HAVE_LD_VERSION_SCRIPT_TRUE='#'
-  HAVE_LD_VERSION_SCRIPT_FALSE=
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_asm_symver_support=no
 fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_asm_symver_support" >&5
+echo "${ECHO_T}$ac_cv_asm_symver_support" >&6
+if test $ac_cv_asm_symver_support = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SYMVER_SUPPORT 1
+_ACEOF
 
+fi
 
                     ac_config_files="$ac_config_files Makefile libibverbs.spec"
 
@@ -20428,13 +20272,6 @@ echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
 Usually this means the macro was only invoked conditionally." >&2;}
    { (exit 1); exit 1; }; }
 fi
-if test -z "${HAVE_LD_VERSION_SCRIPT_TRUE}" && test -z "${HAVE_LD_VERSION_SCRIPT_FALSE}"; then
-  { { echo "$as_me:$LINENO: error: conditional \"HAVE_LD_VERSION_SCRIPT\" was never defined.
-Usually this means the macro was only invoked conditionally." >&5
-echo "$as_me: error: conditional \"HAVE_LD_VERSION_SCRIPT\" was never defined.
-Usually this means the macro was only invoked conditionally." >&2;}
-   { (exit 1); exit 1; }; }
-fi
 
 : ${CONFIG_STATUS=./config.status}
 ac_clean_files_save=$ac_clean_files
@@ -20706,7 +20543,7 @@ _ASBOX
 } >&5
 cat >&5 <<_CSEOF
 
-This file was extended by libibverbs $as_me 1.0.4, which was
+This file was extended by libibverbs $as_me 1.1, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -20769,7 +20606,7 @@ _ACEOF
 
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-libibverbs config.status 1.0.4
+libibverbs config.status 1.1
 configured by $0, generated by GNU Autoconf 2.59,
   with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
 
@@ -21034,8 +20871,7 @@ s, at F77@,$F77,;t t
 s, at FFLAGS@,$FFLAGS,;t t
 s, at ac_ct_F77@,$ac_ct_F77,;t t
 s, at LIBTOOL@,$LIBTOOL,;t t
-s, at HAVE_LD_VERSION_SCRIPT_TRUE@,$HAVE_LD_VERSION_SCRIPT_TRUE,;t t
-s, at HAVE_LD_VERSION_SCRIPT_FALSE@,$HAVE_LD_VERSION_SCRIPT_FALSE,;t t
+s, at LIBIBVERBS_VERSION_SCRIPT@,$LIBIBVERBS_VERSION_SCRIPT,;t t
 s, at LIBOBJS@,$LIBOBJS,;t t
 s, at LTLIBOBJS@,$LTLIBOBJS,;t t
 CEOF
diff --git a/configure.in b/configure.in
index 42a35c7..f2f889a 100644
--- a/configure.in
+++ b/configure.in
@@ -1,11 +1,11 @@
 dnl Process this file with autoconf to produce a configure script.
 
 AC_PREREQ(2.57)
-AC_INIT(libibverbs, 1.0.4, openib-general at openib.org)
+AC_INIT(libibverbs, 1.1, general at lists.openfabrics.org)
 AC_CONFIG_SRCDIR([src/ibverbs.h])
 AC_CONFIG_AUX_DIR(config)
 AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(libibverbs, 1.0.4)
+AM_INIT_AUTOMAKE(libibverbs, 1.1)
 
 AM_PROG_LIBTOOL
 
@@ -24,18 +24,15 @@ fi
 
 dnl Checks for programs
 AC_PROG_CC
+AC_PROG_LN_S
 
 dnl Checks for libraries
 AC_CHECK_LIB(dl, dlsym, [],
     AC_MSG_ERROR([dlsym() not found.  libibverbs requires libdl.]))
 AC_CHECK_LIB(pthread, pthread_mutex_init, [],
     AC_MSG_ERROR([pthread_mutex_init() not found.  libibverbs requires libpthread.]))
-AC_CHECK_LIB(sysfs, sysfs_open_class, [],
-    AC_MSG_ERROR([sysfs_open_class() not found.  libibverbs requires libsysfs.]))
 
 dnl Checks for header files.
-AC_CHECK_HEADER(sysfs/libsysfs.h, [],
-    AC_MSG_ERROR([<sysfs/libsysfs.h> not found.  libibverbs requires libsysfs.]))
 AC_HEADER_STDC
 AC_CHECK_HEADER(valgrind/memcheck.h, memcheck_ok=yes, memcheck_ok=no)
 
@@ -47,13 +44,26 @@ dnl Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
 
 AC_CACHE_CHECK(whether ld accepts --version-script, ac_cv_version_script,
-    if test -n "`$LD --help < /dev/null 2>/dev/null | grep version-script`"; then
-        ac_cv_version_script=yes
+    [if test -n "`$LD --help < /dev/null 2>/dev/null | grep version-script`"; then
+	ac_cv_version_script=yes
     else
-        ac_cv_version_script=no
-    fi)
+	ac_cv_version_script=no
+    fi])
 
-AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$ac_cv_version_script" = "yes")
+if test $ac_cv_version_script = yes; then
+    LIBIBVERBS_VERSION_SCRIPT='-Wl,--version-script=$(srcdir)/src/libibverbs.map'
+else
+    LIBIBVERBS_VERSION_SCRIPT=
+fi
+AC_SUBST(LIBIBVERBS_VERSION_SCRIPT)
+
+AC_CACHE_CHECK(for .symver assembler support, ac_cv_asm_symver_support,
+    [AC_TRY_COMPILE(, [asm("symbol:\n.symver symbol, api at ABI\n");],
+        ac_cv_asm_symver_support=yes,
+        ac_cv_asm_symver_support=no)])
+if test $ac_cv_asm_symver_support = yes; then
+    AC_DEFINE([HAVE_SYMVER_SUPPORT], 1, [assembler has .symver support])
+fi
 
 AC_CONFIG_FILES([Makefile libibverbs.spec])
 AC_OUTPUT
diff --git a/examples/asyncwatch.c b/examples/asyncwatch.c
index 18d3a53..16aee2c 100644
--- a/examples/asyncwatch.c
+++ b/examples/asyncwatch.c
@@ -28,8 +28,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: asyncwatch.c 7614 2006-05-31 23:06:39Z roland $
  */
 
 #if HAVE_CONFIG_H
diff --git a/examples/device_list.c b/examples/device_list.c
index 3c99bd7..b53d4b1 100644
--- a/examples/device_list.c
+++ b/examples/device_list.c
@@ -28,8 +28,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: device_list.c 7484 2006-05-24 21:12:21Z roland $
  */
 
 #if HAVE_CONFIG_H
diff --git a/examples/devinfo.c b/examples/devinfo.c
index 8ae7c28..28cf8d1 100644
--- a/examples/devinfo.c
+++ b/examples/devinfo.c
@@ -29,8 +29,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: devinfo.c 7484 2006-05-24 21:12:21Z roland $
  */
 
 #if HAVE_CONFIG_H
@@ -47,6 +45,7 @@
 #include <byteswap.h>
 
 #include <infiniband/verbs.h>
+#include <infiniband/driver.h>
 #include <infiniband/arch.h>
 
 static int verbose = 0;
@@ -169,7 +168,6 @@ static int print_hca_cap(struct ibv_device *ib_dev, uint8_t ib_port)
 	struct ibv_context *ctx;
 	struct ibv_device_attr device_attr;
 	struct ibv_port_attr port_attr;
-	struct sysfs_attribute *attr;
 	int rc = 0;
 	uint8_t port;
 	char buf[256];
@@ -194,11 +192,9 @@ static int print_hca_cap(struct ibv_device *ib_dev, uint8_t ib_port)
 	printf("\tvendor_id:\t\t\t0x%04x\n", device_attr.vendor_id);
 	printf("\tvendor_part_id:\t\t\t%d\n", device_attr.vendor_part_id);
 	printf("\thw_ver:\t\t\t\t0x%X\n", device_attr.hw_ver);
-	attr = sysfs_get_classdev_attr(ib_dev->ibdev, "board_id");
-	if (attr) {
-		printf("\tboard_id:\t\t\t%s", attr->value);
-		sysfs_close_attribute(attr);
-	}
+
+	if (ibv_read_sysfs_file(ib_dev->ibdev_path, "board_id", buf, sizeof buf) > 0)
+		printf("\tboard_id:\t\t\t%s\n", buf);
 
 	printf("\tphys_port_cnt:\t\t\t%d\n", device_attr.phys_port_cnt);
 
diff --git a/examples/pingpong.c b/examples/pingpong.c
index e60d29e..b916f59 100644
--- a/examples/pingpong.c
+++ b/examples/pingpong.c
@@ -28,8 +28,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id$
  */
 
 #include "pingpong.h"
diff --git a/examples/pingpong.h b/examples/pingpong.h
index eccd407..71d7c3f 100644
--- a/examples/pingpong.h
+++ b/examples/pingpong.h
@@ -28,8 +28,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id$
  */
 
 #ifndef IBV_PINGPONG_H
diff --git a/examples/rc_pingpong.c b/examples/rc_pingpong.c
index a3d71e1..82623db 100644
--- a/examples/rc_pingpong.c
+++ b/examples/rc_pingpong.c
@@ -28,8 +28,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: rc_pingpong.c 7484 2006-05-24 21:12:21Z roland $
  */
 
 #if HAVE_CONFIG_H
@@ -141,7 +139,9 @@ static struct pingpong_dest *pp_client_exch_dest(const char *servername, int por
 	int sockfd = -1;
 	struct pingpong_dest *rem_dest = NULL;
 
-	asprintf(&service, "%d", port);
+	if (asprintf(&service, "%d", port) < 0)
+		return NULL;
+
 	n = getaddrinfo(servername, service, &hints, &res);
 
 	if (n < 0) {
@@ -207,7 +207,9 @@ static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx,
 	int sockfd = -1, connfd;
 	struct pingpong_dest *rem_dest = NULL;
 
-	asprintf(&service, "%d", port);
+	if (asprintf(&service, "%d", port) < 0)
+		return NULL;
+
 	n = getaddrinfo(NULL, service, &hints, &res);
 
 	if (n < 0) {
@@ -324,7 +326,7 @@ static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size,
 
 	ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size, IBV_ACCESS_LOCAL_WRITE);
 	if (!ctx->mr) {
-		fprintf(stderr, "Couldn't allocate MR\n");
+		fprintf(stderr, "Couldn't register MR\n");
 		return NULL;
 	}
 
@@ -376,6 +378,46 @@ static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size,
 	return ctx;
 }
 
+int pp_close_ctx(struct pingpong_context *ctx)
+{
+	if (ibv_destroy_qp(ctx->qp)) {
+		fprintf(stderr, "Couldn't destroy QP\n");
+		return 1;
+	}
+
+	if (ibv_destroy_cq(ctx->cq)) {
+		fprintf(stderr, "Couldn't destroy CQ\n");
+		return 1;
+	}
+
+	if (ibv_dereg_mr(ctx->mr)) {
+		fprintf(stderr, "Couldn't deregister MR\n");
+		return 1;
+	}
+
+	if (ibv_dealloc_pd(ctx->pd)) {
+		fprintf(stderr, "Couldn't deallocate PD\n");
+		return 1;
+	}
+
+	if (ctx->channel) {
+		if (ibv_destroy_comp_channel(ctx->channel)) {
+			fprintf(stderr, "Couldn't destroy completion channel\n");
+			return 1;
+		}
+	}
+
+	if (ibv_close_device(ctx->context)) {
+		fprintf(stderr, "Couldn't release context\n");
+		return 1;
+	}
+
+	free(ctx->buf);
+	free(ctx);
+
+	return 0;
+}
+
 static int pp_post_recv(struct pingpong_context *ctx, int n)
 {
 	struct ibv_sge list = {
@@ -453,6 +495,7 @@ int main(int argc, char *argv[])
 	int                      use_event = 0;
 	int                      routs;
 	int                      rcnt, scnt;
+	int                      num_cq_events = 0;
 
 	srand48(getpid() * time(NULL));
 
@@ -624,6 +667,8 @@ int main(int argc, char *argv[])
 				return 1;
 			}
 
+			++num_cq_events;
+
 			if (ev_cq != ctx->cq) {
 				fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq);
 				return 1;
@@ -708,5 +753,13 @@ int main(int argc, char *argv[])
 		       iters, usec / 1000000., usec / iters);
 	}
 
+	ibv_ack_cq_events(ctx->cq, num_cq_events);
+
+	if (pp_close_ctx(ctx))
+		return 1;
+
+	ibv_free_device_list(dev_list);
+	free(rem_dest);
+
 	return 0;
 }
diff --git a/examples/srq_pingpong.c b/examples/srq_pingpong.c
index 2ab9b8d..6de3e95 100644
--- a/examples/srq_pingpong.c
+++ b/examples/srq_pingpong.c
@@ -28,8 +28,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: srq_pingpong.c 7484 2006-05-24 21:12:21Z roland $
  */
 
 #if HAVE_CONFIG_H
@@ -152,7 +150,9 @@ static struct pingpong_dest *pp_client_exch_dest(const char *servername, int por
 	int sockfd = -1;
 	struct pingpong_dest *rem_dest = NULL;
 
-	asprintf(&service, "%d", port);
+	if (asprintf(&service, "%d", port) < 0)
+		return NULL;
+
 	n = getaddrinfo(servername, service, &hints, &res);
 
 	if (n < 0) {
@@ -231,7 +231,9 @@ static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx,
 	int sockfd = -1, connfd;
 	struct pingpong_dest *rem_dest = NULL;
 
-	asprintf(&service, "%d", port);
+	if (asprintf(&service, "%d", port) < 0)
+		return NULL;
+
 	n = getaddrinfo(NULL, service, &hints, &res);
 
 	if (n < 0) {
@@ -360,7 +362,7 @@ static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size,
 
 	ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size, IBV_ACCESS_LOCAL_WRITE);
 	if (!ctx->mr) {
-		fprintf(stderr, "Couldn't allocate MR\n");
+		fprintf(stderr, "Couldn't register MR\n");
 		return NULL;
 	}
 
@@ -426,6 +428,55 @@ static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size,
 	return ctx;
 }
 
+int pp_close_ctx(struct pingpong_context *ctx, int num_qp)
+{
+	int i;
+
+	for (i = 0; i < num_qp; ++i) {
+		if (ibv_destroy_qp(ctx->qp[i])) {
+			fprintf(stderr, "Couldn't destroy QP[%d]\n", i);
+			return 1;
+		}
+	}
+
+	if (ibv_destroy_srq(ctx->srq)) {
+		fprintf(stderr, "Couldn't destroy SRQ\n");
+		return 1;
+	}
+
+	if (ibv_destroy_cq(ctx->cq)) {
+		fprintf(stderr, "Couldn't destroy CQ\n");
+		return 1;
+	}
+
+	if (ibv_dereg_mr(ctx->mr)) {
+		fprintf(stderr, "Couldn't deregister MR\n");
+		return 1;
+	}
+
+	if (ibv_dealloc_pd(ctx->pd)) {
+		fprintf(stderr, "Couldn't deallocate PD\n");
+		return 1;
+	}
+
+	if (ctx->channel) {
+		if (ibv_destroy_comp_channel(ctx->channel)) {
+			fprintf(stderr, "Couldn't destroy completion channel\n");
+			return 1;
+		}
+	}
+
+	if (ibv_close_device(ctx->context)) {
+		fprintf(stderr, "Couldn't release context\n");
+		return 1;
+	}
+
+	free(ctx->buf);
+	free(ctx);
+
+	return 0;
+}
+
 static int pp_post_recv(struct pingpong_context *ctx, int n)
 {
 	struct ibv_sge list = {
@@ -519,6 +570,7 @@ int main(int argc, char *argv[])
 	int                      rcnt, scnt;
 	int			 num_wc;
 	int                      i;
+	int                      num_cq_events = 0;
 
 	srand48(getpid() * time(NULL));
 
@@ -573,6 +625,7 @@ int main(int argc, char *argv[])
 				usage(argv[0]);
 				return 1;
 			}
+			break;
 
 		case 'q':
 			num_qp = strtol(optarg, NULL, 0);
@@ -712,6 +765,8 @@ int main(int argc, char *argv[])
 				return 1;
 			}
 
+			++num_cq_events;
+
 			if (ev_cq != ctx->cq) {
 				fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq);
 				return 1;
@@ -803,5 +858,13 @@ int main(int argc, char *argv[])
 		       iters, usec / 1000000., usec / iters);
 	}
 
+	ibv_ack_cq_events(ctx->cq, num_cq_events);
+
+	if (pp_close_ctx(ctx, num_qp))
+		return 1;
+
+	ibv_free_device_list(dev_list);
+	free(rem_dest);
+
 	return 0;
 }
diff --git a/examples/uc_pingpong.c b/examples/uc_pingpong.c
index 68d2b0a..1b2b1b4 100644
--- a/examples/uc_pingpong.c
+++ b/examples/uc_pingpong.c
@@ -28,8 +28,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: uc_pingpong.c 7484 2006-05-24 21:12:21Z roland $
  */
 
 #if HAVE_CONFIG_H
@@ -129,7 +127,9 @@ static struct pingpong_dest *pp_client_exch_dest(const char *servername, int por
 	int sockfd = -1;
 	struct pingpong_dest *rem_dest = NULL;
 
-	asprintf(&service, "%d", port);
+	if (asprintf(&service, "%d", port) < 0)
+		return NULL;
+
 	n = getaddrinfo(servername, service, &hints, &res);
 
 	if (n < 0) {
@@ -195,7 +195,9 @@ static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx,
 	int sockfd = -1, connfd;
 	struct pingpong_dest *rem_dest = NULL;
 
-	asprintf(&service, "%d", port);
+	if (asprintf(&service, "%d", port) < 0)
+		return NULL;
+
 	n = getaddrinfo(NULL, service, &hints, &res);
 
 	if (n < 0) {
@@ -312,7 +314,7 @@ static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size,
 
 	ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size, IBV_ACCESS_LOCAL_WRITE);
 	if (!ctx->mr) {
-		fprintf(stderr, "Couldn't allocate MR\n");
+		fprintf(stderr, "Couldn't register MR\n");
 		return NULL;
 	}
 
@@ -364,6 +366,46 @@ static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size,
 	return ctx;
 }
 
+int pp_close_ctx(struct pingpong_context *ctx)
+{
+	if (ibv_destroy_qp(ctx->qp)) {
+		fprintf(stderr, "Couldn't destroy QP\n");
+		return 1;
+	}
+
+	if (ibv_destroy_cq(ctx->cq)) {
+		fprintf(stderr, "Couldn't destroy CQ\n");
+		return 1;
+	}
+
+	if (ibv_dereg_mr(ctx->mr)) {
+		fprintf(stderr, "Couldn't deregister MR\n");
+		return 1;
+	}
+
+	if (ibv_dealloc_pd(ctx->pd)) {
+		fprintf(stderr, "Couldn't deallocate PD\n");
+		return 1;
+	}
+
+	if (ctx->channel) {
+		if (ibv_destroy_comp_channel(ctx->channel)) {
+			fprintf(stderr, "Couldn't destroy completion channel\n");
+			return 1;
+		}
+	}
+
+	if (ibv_close_device(ctx->context)) {
+		fprintf(stderr, "Couldn't release context\n");
+		return 1;
+	}
+
+	free(ctx->buf);
+	free(ctx);
+
+	return 0;
+}
+
 static int pp_post_recv(struct pingpong_context *ctx, int n)
 {
 	struct ibv_sge list = {
@@ -441,6 +483,7 @@ int main(int argc, char *argv[])
 	int                      use_event = 0;
 	int                      routs;
 	int                      rcnt, scnt;
+	int                      num_cq_events = 0;
 
 	srand48(getpid() * time(NULL));
 
@@ -612,6 +655,8 @@ int main(int argc, char *argv[])
 				return 1;
 			}
 
+			++num_cq_events;
+
 			if (ev_cq != ctx->cq) {
 				fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq);
 				return 1;
@@ -696,5 +741,13 @@ int main(int argc, char *argv[])
 		       iters, usec / 1000000., usec / iters);
 	}
 
+	ibv_ack_cq_events(ctx->cq, num_cq_events);
+
+	if (pp_close_ctx(ctx))
+		return 1;
+
+	ibv_free_device_list(dev_list);
+	free(rem_dest);
+
 	return 0;
 }
diff --git a/examples/ud_pingpong.c b/examples/ud_pingpong.c
index b45062f..d22ce8b 100644
--- a/examples/ud_pingpong.c
+++ b/examples/ud_pingpong.c
@@ -28,8 +28,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: ud_pingpong.c 7484 2006-05-24 21:12:21Z roland $
  */
 
 #if HAVE_CONFIG_H
@@ -130,7 +128,9 @@ static struct pingpong_dest *pp_client_exch_dest(const char *servername, int por
 	int sockfd = -1;
 	struct pingpong_dest *rem_dest = NULL;
 
-	asprintf(&service, "%d", port);
+	if (asprintf(&service, "%d", port) < 0)
+		return NULL;
+
 	n = getaddrinfo(servername, service, &hints, &res);
 
 	if (n < 0) {
@@ -196,7 +196,9 @@ static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx,
 	int sockfd = -1, connfd;
 	struct pingpong_dest *rem_dest = NULL;
 
-	asprintf(&service, "%d", port);
+	if (asprintf(&service, "%d", port) < 0)
+		return NULL;
+
 	n = getaddrinfo(NULL, service, &hints, &res);
 
 	if (n < 0) {
@@ -313,7 +315,7 @@ static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size,
 
 	ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size + 40, IBV_ACCESS_LOCAL_WRITE);
 	if (!ctx->mr) {
-		fprintf(stderr, "Couldn't allocate MR\n");
+		fprintf(stderr, "Couldn't register MR\n");
 		return NULL;
 	}
 
@@ -365,6 +367,51 @@ static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size,
 	return ctx;
 }
 
+int pp_close_ctx(struct pingpong_context *ctx)
+{
+	if (ibv_destroy_qp(ctx->qp)) {
+		fprintf(stderr, "Couldn't destroy QP\n");
+		return 1;
+	}
+
+	if (ibv_destroy_cq(ctx->cq)) {
+		fprintf(stderr, "Couldn't destroy CQ\n");
+		return 1;
+	}
+
+	if (ibv_dereg_mr(ctx->mr)) {
+		fprintf(stderr, "Couldn't deregister MR\n");
+		return 1;
+	}
+
+	if (ibv_destroy_ah(ctx->ah)) {
+		fprintf(stderr, "Couldn't destroy AH\n");
+		return 1;
+	}
+
+	if (ibv_dealloc_pd(ctx->pd)) {
+		fprintf(stderr, "Couldn't deallocate PD\n");
+		return 1;
+	}
+
+	if (ctx->channel) {
+		if (ibv_destroy_comp_channel(ctx->channel)) {
+			fprintf(stderr, "Couldn't destroy completion channel\n");
+			return 1;
+		}
+	}
+
+	if (ibv_close_device(ctx->context)) {
+		fprintf(stderr, "Couldn't release context\n");
+		return 1;
+	}
+
+	free(ctx->buf);
+	free(ctx);
+
+	return 0;
+}
+
 static int pp_post_recv(struct pingpong_context *ctx, int n)
 {
 	struct ibv_sge list = {
@@ -447,6 +494,7 @@ int main(int argc, char *argv[])
 	int                      use_event = 0;
 	int                      routs;
 	int                      rcnt, scnt;
+	int                      num_cq_events = 0;
 
 	srand48(getpid() * time(NULL));
 
@@ -610,6 +658,8 @@ int main(int argc, char *argv[])
 				return 1;
 			}
 
+			++num_cq_events;
+
 			if (ev_cq != ctx->cq) {
 				fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq);
 				return 1;
@@ -694,5 +744,13 @@ int main(int argc, char *argv[])
 		       iters, usec / 1000000., usec / iters);
 	}
 
+	ibv_ack_cq_events(ctx->cq, num_cq_events);
+
+	if (pp_close_ctx(ctx))
+		return 1;
+
+	ibv_free_device_list(dev_list);
+	free(rem_dest);
+
 	return 0;
 }
diff --git a/include/infiniband/arch.h b/include/infiniband/arch.h
index 310d93f..6a04287 100644
--- a/include/infiniband/arch.h
+++ b/include/infiniband/arch.h
@@ -28,8 +28,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: arch.h 9861 2006-10-17 23:07:44Z roland $
  */
 
 #ifndef INFINIBAND_ARCH_H
diff --git a/include/infiniband/driver.h b/include/infiniband/driver.h
index 0bfd26a..67a3bf8 100644
--- a/include/infiniband/driver.h
+++ b/include/infiniband/driver.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems, Inc.  All rights reserved.
  * Copyright (c) 2005 PathScale, Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -30,15 +30,11 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: driver.h 7484 2006-05-24 21:12:21Z roland $
  */
 
 #ifndef INFINIBAND_DRIVER_H
 #define INFINIBAND_DRIVER_H
 
-#include <sysfs/libsysfs.h>
-
 #include <infiniband/verbs.h>
 #include <infiniband/kern-abi.h>
 
@@ -51,20 +47,16 @@
 #endif /* __cplusplus */
 
 /*
- * Device-specific drivers should declare their device init function
- * as below (the name must be "openib_driver_init"):
- *
- * struct ibv_device *openib_driver_init(struct sysfs_class_device *);
- *
- * libibverbs will call each driver's openib_driver_init() function
- * once for each InfiniBand device.  If the device is one that the
- * driver can support, it should return a struct ibv_device * with the
- * ops member filled in.  If the driver does not support the device,
- * it should return NULL from openib_driver_init().
+ * Extension that low-level drivers should add to their .so filename
+ * (probably via libtool "-release" option).  For example a low-level
+ * driver named "libfoo" should build a plug-in named "libfoo-rdmav2.so".
  */
+#define IBV_DEVICE_LIBRARY_EXTENSION rdmav2
 
-typedef struct ibv_device *(*ibv_driver_init_func)(struct sysfs_class_device *);
+typedef struct ibv_device *(*ibv_driver_init_func)(const char *uverbs_sys_path,
+						   int abi_version);
 
+void ibv_register_driver(const char *name, ibv_driver_init_func init_func);
 int ibv_cmd_get_context(struct ibv_context *context, struct ibv_get_context *cmd,
 			size_t cmd_size, struct ibv_get_context_resp *resp,
 			size_t resp_size);
@@ -83,10 +75,12 @@ int ibv_cmd_alloc_pd(struct ibv_context *context, struct ibv_pd *pd,
 		     struct ibv_alloc_pd *cmd, size_t cmd_size,
 		     struct ibv_alloc_pd_resp *resp, size_t resp_size);
 int ibv_cmd_dealloc_pd(struct ibv_pd *pd);
+#define IBV_CMD_REG_MR_HAS_RESP_PARAMS
 int ibv_cmd_reg_mr(struct ibv_pd *pd, void *addr, size_t length,
 		   uint64_t hca_va, enum ibv_access_flags access,
 		   struct ibv_mr *mr, struct ibv_reg_mr *cmd,
-		   size_t cmd_size);
+		   size_t cmd_size,
+		   struct ibv_reg_mr_resp *resp, size_t resp_size);
 int ibv_cmd_dereg_mr(struct ibv_mr *mr);
 int ibv_cmd_create_cq(struct ibv_context *context, int cqe,
 		      struct ibv_comp_channel *channel,
@@ -95,8 +89,10 @@ int ibv_cmd_create_cq(struct ibv_context *context, int cqe,
 		      struct ibv_create_cq_resp *resp, size_t resp_size);
 int ibv_cmd_poll_cq(struct ibv_cq *cq, int ne, struct ibv_wc *wc);
 int ibv_cmd_req_notify_cq(struct ibv_cq *cq, int solicited_only);
+#define IBV_CMD_RESIZE_CQ_HAS_RESP_PARAMS
 int ibv_cmd_resize_cq(struct ibv_cq *cq, int cqe,
-		      struct ibv_resize_cq *cmd, size_t cmd_size);
+		      struct ibv_resize_cq *cmd, size_t cmd_size,
+		      struct ibv_resize_cq_resp *resp, size_t resp_size);
 int ibv_cmd_destroy_cq(struct ibv_cq *cq);
 
 int ibv_cmd_create_srq(struct ibv_pd *pd,
@@ -136,6 +132,9 @@ int ibv_cmd_destroy_ah(struct ibv_ah *ah);
 int ibv_cmd_attach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid);
 int ibv_cmd_detach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid);
 
+int ibv_dontfork_range(void *base, size_t size);
+int ibv_dofork_range(void *base, size_t size);
+
 /*
  * sysfs helper functions
  */
diff --git a/include/infiniband/kern-abi.h b/include/infiniband/kern-abi.h
index eb212ce..0db083a 100644
--- a/include/infiniband/kern-abi.h
+++ b/include/infiniband/kern-abi.h
@@ -30,8 +30,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: kern-abi.h 10009 2006-10-31 05:30:54Z roland $
  */
 
 #ifndef KERN_ABI_H
@@ -355,6 +353,8 @@ struct ibv_resize_cq {
 
 struct ibv_resize_cq_resp {
 	__u32 cqe;
+	__u32 reserved;
+	__u64 driver_data[0];
 };
 
 struct ibv_destroy_cq {
diff --git a/include/infiniband/marshall.h b/include/infiniband/marshall.h
index fe2bb1e..8be76c5 100644
--- a/include/infiniband/marshall.h
+++ b/include/infiniband/marshall.h
@@ -46,38 +46,20 @@
 #  define END_C_DECLS
 #endif /* __cplusplus */
 
-#if __GNUC__ >= 3
-#  define __attribute_deprecated	__attribute__((deprecated))
-#else
-#  define __attribute_deprecated
-#endif
-
 BEGIN_C_DECLS
 
 void ibv_copy_qp_attr_from_kern(struct ibv_qp_attr *dst,
 				struct ibv_kern_qp_attr *src);
 
+void ibv_copy_ah_attr_from_kern(struct ibv_ah_attr *dst,
+				struct ibv_kern_ah_attr *src);
+
 void ibv_copy_path_rec_from_kern(struct ibv_sa_path_rec *dst,
 				 struct ibv_kern_path_rec *src);
 
 void ibv_copy_path_rec_to_kern(struct ibv_kern_path_rec *dst,
 			       struct ibv_sa_path_rec *src);
 
-/*
- * Obsolete, deprecated names.  Will be removed in libibverbs 1.1.
- */
-
-void ib_copy_qp_attr_from_kern(struct ibv_qp_attr *dst,
-			       struct ibv_kern_qp_attr *src) __attribute_deprecated;
-
-void ib_copy_path_rec_from_kern(struct ib_sa_path_rec *dst,
-				struct ib_kern_path_rec *src) __attribute_deprecated;
-
-void ib_copy_path_rec_to_kern(struct ib_kern_path_rec *dst,
-			      struct ib_sa_path_rec *src) __attribute_deprecated;
-
 END_C_DECLS
 
-#undef __attribute_deprecated
-
 #endif /* INFINIBAND_MARSHALL_H */
diff --git a/include/infiniband/opcode.h b/include/infiniband/opcode.h
index c1e06fb..fd4bc96 100644
--- a/include/infiniband/opcode.h
+++ b/include/infiniband/opcode.h
@@ -28,8 +28,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: opcode.h 7484 2006-05-24 21:12:21Z roland $
  */
 
 #ifndef INFINIBAND_OPCODE_H
diff --git a/include/infiniband/sa.h b/include/infiniband/sa.h
index dc2f3b5..ec90f14 100644
--- a/include/infiniband/sa.h
+++ b/include/infiniband/sa.h
@@ -29,8 +29,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: sa.h 2616 2005-06-15 15:22:39Z halr $
  */
 
 #ifndef INFINIBAND_SA_H
@@ -38,13 +36,6 @@
 
 #include <infiniband/verbs.h>
 
-/*
- * Obsolete, deprecated names.  Will be removed in libibverbs 1.1.
- */
-#define ib_sa_path_rec		ibv_sa_path_rec
-#define ib_sa_mcmember_rec	ibv_sa_mcmember_rec
-#define ib_sa_service_rec	ibv_sa_service_rec
-
 struct ibv_sa_path_rec {
 	/* reserved */
 	/* reserved */
diff --git a/include/infiniband/verbs.h b/include/infiniband/verbs.h
index d725131..acc1b82 100644
--- a/include/infiniband/verbs.h
+++ b/include/infiniband/verbs.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2004 Intel Corporation.  All rights reserved.
- * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc.  All rights reserved.
  * Copyright (c) 2005 PathScale, Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -31,8 +31,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: verbs.h 7614 2006-05-31 23:06:39Z roland $
  */
 
 #ifndef INFINIBAND_VERBS_H
@@ -41,8 +39,6 @@
 #include <stdint.h>
 #include <pthread.h>
 
-#include <sysfs/libsysfs.h>
-
 #ifdef __cplusplus
 #  define BEGIN_C_DECLS extern "C" {
 #  define END_C_DECLS   }
@@ -68,9 +64,17 @@ union ibv_gid {
 };
 
 enum ibv_node_type {
-	IBV_NODE_CA 	= 1,
+	IBV_NODE_UNKNOWN	= -1,
+	IBV_NODE_CA 		= 1,
 	IBV_NODE_SWITCH,
-	IBV_NODE_ROUTER
+	IBV_NODE_ROUTER,
+	IBV_NODE_RNIC
+};
+
+enum ibv_transport_type {
+	IBV_TRANSPORT_UNKNOWN	= -1,
+	IBV_TRANSPORT_IB	= 0,
+	IBV_TRANSPORT_IWARP
 };
 
 enum ibv_device_cap_flags {
@@ -284,14 +288,34 @@ struct ibv_pd {
 	uint32_t		handle;
 };
 
+enum ibv_rereg_mr_flags {
+	IBV_REREG_MR_CHANGE_TRANSLATION	= (1 << 0),
+	IBV_REREG_MR_CHANGE_PD		= (1 << 1),
+	IBV_REREG_MR_CHANGE_ACCESS	= (1 << 2),
+	IBV_REREG_MR_KEEP_VALID		= (1 << 3)
+};
+
 struct ibv_mr {
 	struct ibv_context     *context;
 	struct ibv_pd	       *pd;
+	void		       *addr;
+	size_t			length;
 	uint32_t		handle;
 	uint32_t		lkey;
 	uint32_t		rkey;
 };
 
+enum ibv_mw_type {
+	IBV_MW_TYPE_1			= 1,
+	IBV_MW_TYPE_2			= 2
+};
+
+struct ibv_mw {
+	struct ibv_context     *context;
+	struct ibv_pd	       *pd;
+	uint32_t		rkey;
+};
+
 struct ibv_global_route {
 	union ibv_gid		dgid;
 	uint32_t		flow_label;
@@ -300,6 +324,15 @@ struct ibv_global_route {
 	uint8_t			traffic_class;
 };
 
+struct ibv_grh {
+	uint32_t		version_tclass_flow;
+	uint16_t		paylen;
+	uint8_t			next_hdr;
+	uint8_t			hop_limit;
+	union ibv_gid		sgid;
+	union ibv_gid		dgid;
+};
+
 enum ibv_rate {
 	IBV_RATE_MAX      = 0,
 	IBV_RATE_2_5_GBPS = 2,
@@ -469,8 +502,8 @@ struct ibv_sge {
 };
 
 struct ibv_send_wr {
-	struct ibv_send_wr     *next;
 	uint64_t		wr_id;
+	struct ibv_send_wr     *next;
 	struct ibv_sge	       *sg_list;
 	int			num_sge;
 	enum ibv_wr_opcode	opcode;
@@ -496,12 +529,21 @@ struct ibv_send_wr {
 };
 
 struct ibv_recv_wr {
-	struct ibv_recv_wr     *next;
 	uint64_t		wr_id;
+	struct ibv_recv_wr     *next;
 	struct ibv_sge	       *sg_list;
 	int			num_sge;
 };
 
+struct ibv_mw_bind {
+	uint64_t		wr_id;
+	struct ibv_mr	       *mr;
+	void		       *addr;
+	size_t			length;
+	enum ibv_send_flags	send_flags;
+	enum ibv_access_flags	mw_access_flags;
+};
+
 struct ibv_srq {
 	struct ibv_context     *context;
 	void		       *srq_context;
@@ -531,11 +573,14 @@ struct ibv_qp {
 };
 
 struct ibv_comp_channel {
+	struct ibv_context     *context;
 	int			fd;
+	int			refcnt;
 };
 
 struct ibv_cq {
 	struct ibv_context     *context;
+	struct ibv_comp_channel *channel;
 	void		       *cq_context;
 	uint32_t		handle;
 	int			cqe;
@@ -560,11 +605,23 @@ struct ibv_device_ops {
 	void			(*free_context)(struct ibv_context *context);
 };
 
+enum {
+	IBV_SYSFS_NAME_MAX	= 64,
+	IBV_SYSFS_PATH_MAX	= 256
+};
+
 struct ibv_device {
-	struct sysfs_class_device *dev;
-	struct sysfs_class_device *ibdev;
-	struct ibv_driver         *driver;
-	struct ibv_device_ops      ops;
+	struct ibv_device_ops	ops;
+	enum ibv_node_type	node_type;
+	enum ibv_transport_type	transport_type;
+	/* Name of underlying kernel IB device, eg "mthca0" */
+	char			name[IBV_SYSFS_NAME_MAX];
+	/* Name of uverbs device, eg "uverbs0" */
+	char			dev_name[IBV_SYSFS_NAME_MAX];
+	/* Path to infiniband_verbs class device in sysfs */
+	char			dev_path[IBV_SYSFS_PATH_MAX];
+	/* Path to infiniband class device in sysfs */
+	char			ibdev_path[IBV_SYSFS_PATH_MAX];
 };
 
 struct ibv_context_ops {
@@ -576,7 +633,16 @@ struct ibv_context_ops {
 	int			(*dealloc_pd)(struct ibv_pd *pd);
 	struct ibv_mr *		(*reg_mr)(struct ibv_pd *pd, void *addr, size_t length,
 					  enum ibv_access_flags access);
+	struct ibv_mr *		(*rereg_mr)(struct ibv_mr *mr,
+					    enum ibv_rereg_mr_flags flags,
+					    struct ibv_pd *pd, void *addr,
+					    size_t length,
+					    enum ibv_access_flags access);
 	int			(*dereg_mr)(struct ibv_mr *mr);
+	struct ibv_mw *		(*alloc_mw)(struct ibv_pd *pd, enum ibv_mw_type type);
+	int			(*bind_mw)(struct ibv_qp *qp, struct ibv_mw *mw,
+					   struct ibv_mw_bind *mw_bind);
+	int			(*dealloc_mw)(struct ibv_mw *mw);
 	struct ibv_cq *		(*create_cq)(struct ibv_context *context, int cqe,
 					     struct ibv_comp_channel *channel,
 					     int comp_vector);
@@ -613,15 +679,17 @@ struct ibv_context_ops {
 						uint16_t lid);
 	int			(*detach_mcast)(struct ibv_qp *qp, union ibv_gid *gid,
 						uint16_t lid);
+	void			(*async_event)(struct ibv_async_event *event);
 };
 
 struct ibv_context {
-	struct ibv_device         *device;
-	struct ibv_context_ops	   ops;
-	int                        cmd_fd;
-	int                        async_fd;
-	int                        num_comp_vectors;
-	void			  *abi_compat;
+	struct ibv_device      *device;
+	struct ibv_context_ops	ops;
+	int			cmd_fd;
+	int			async_fd;
+	int			num_comp_vectors;
+	pthread_mutex_t		mutex;
+	void		       *abi_compat;
 };
 
 /**
@@ -943,6 +1011,36 @@ static inline int ibv_post_recv(struct ibv_qp *qp, struct ibv_recv_wr *wr,
 struct ibv_ah *ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr);
 
 /**
+ * ibv_init_ah_from_wc - Initializes address handle attributes from a
+ *   work completion.
+ * @context: Device context on which the received message arrived.
+ * @port_num: Port on which the received message arrived.
+ * @wc: Work completion associated with the received message.
+ * @grh: References the received global route header.  This parameter is
+ *   ignored unless the work completion indicates that the GRH is valid.
+ * @ah_attr: Returned attributes that can be used when creating an address
+ *   handle for replying to the message.
+ */
+int ibv_init_ah_from_wc(struct ibv_context *context, uint8_t port_num,
+			struct ibv_wc *wc, struct ibv_grh *grh,
+			struct ibv_ah_attr *ah_attr);
+
+/**
+ * ibv_create_ah_from_wc - Creates an address handle associated with the
+ *   sender of the specified work completion.
+ * @pd: The protection domain associated with the address handle.
+ * @wc: Work completion information associated with a received message.
+ * @grh: References the received global route header.  This parameter is
+ *   ignored unless the work completion indicates that the GRH is valid.
+ * @port_num: The outbound port number to associate with the address.
+ *
+ * The address handle is used to reference a local or global destination
+ * in all UD QP post sends.
+ */
+struct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd *pd, struct ibv_wc *wc,
+				     struct ibv_grh *grh, uint8_t port_num);
+
+/**
  * ibv_destroy_ah - Destroy an address handle.
  */
 int ibv_destroy_ah(struct ibv_ah *ah);
@@ -968,6 +1066,14 @@ int ibv_attach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid);
  */
 int ibv_detach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid);
 
+/**
+ * ibv_fork_init - Prepare data structures so that fork() may be used
+ * safely.  If this function is not called or returns a non-zero
+ * status, then libibverbs data structures are not fork()-safe and the
+ * effect of an application calling fork() is undefined.
+ */
+int ibv_fork_init(void);
+
 END_C_DECLS
 
 #  undef __attribute_const
diff --git a/libibverbs.spec b/libibverbs.spec
index 5404cad..e00c81d 100644
--- a/libibverbs.spec
+++ b/libibverbs.spec
@@ -1,19 +1,15 @@
-# $Id: libibverbs.spec.in 7484 2006-05-24 21:12:21Z roland $
-
-%define ver      1.0.4
-
 Name: libibverbs
-Version: 1.0.4
+Version: 1.1
 Release: 1%{?dist}
-Summary: A library for direct userspace use of InfiniBand
+Summary: A library for direct userspace use of InfiniBand hardware
 
 Group: System Environment/Libraries
 License: GPL/BSD
-Url: http://openib.org/
-Source: http://openib.org/downloads/libibverbs-1.0.4.tar.gz
-BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-
-BuildRequires: %{_includedir}/sysfs/libsysfs.h
+Url: http://openfabrics.org/
+Source: http://openfabrics.org/downloads/libibverbs-1.1.tar.gz
+BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
 
 %description
 libibverbs is a library that allows userspace processes to use
@@ -27,10 +23,16 @@ also be installed.
 %package devel
 Summary: Development files for the libibverbs library
 Group: System Environment/Libraries
-Requires: %{name} = %{version}-%{release} %{_includedir}/sysfs/libsysfs.h
 
 %description devel
-Static libraries and header files for the libibverbs verbs library.
+Header files for the libibverbs library.
+
+%package devel-static
+Summary: Static development files for the libibverbs library
+Group: System Environment/Libraries
+
+%description devel-static
+Static libraries for the libibverbs library.
 
 %package utils
 Summary: Examples for the libibverbs library
@@ -42,7 +44,7 @@ Useful libibverbs1 example programs such as ibv_devinfo, which
 displays information about InfiniBand devices.
 
 %prep
-%setup -q -n %{name}-%{ver}
+%setup -q -n %{name}-1.1
 
 %build
 %configure
@@ -50,7 +52,7 @@ make %{?_smp_mflags}
 
 %install
 rm -rf $RPM_BUILD_ROOT
-%makeinstall
+make DESTDIR=%{buildroot} install
 # remove unpackaged files from the buildroot
 rm -f $RPM_BUILD_ROOT%{_libdir}/*.la
 
@@ -68,8 +70,12 @@ rm -rf $RPM_BUILD_ROOT
 %files devel
 %defattr(-,root,root,-)
 %{_libdir}/lib*.so
-%{_libdir}/*.a
 %{_includedir}/*
+%{_mandir}/man3/*
+
+%files devel-static
+%defattr(-,root,root,-)
+%{_libdir}/*.a
 
 %files utils
 %defattr(-,root,root,-)
@@ -77,6 +83,18 @@ rm -rf $RPM_BUILD_ROOT
 %{_mandir}/man1/*
 
 %changelog
+* Wed Apr 11 2007 Roland Dreier <rdreier at cisco.com> - 1.1-1
+- New upstream release
+
+* Mon May 22 2006 Roland Dreier <rdreier at cisco.com> - 1.1-0.1.rc2
+- New upstream release
+- Remove dependency on libsysfs, since it is no longer used
+- Put section 3 manpages in devel package.
+- Spec file cleanups: remove unused ver macro, improve BuildRoot, add
+  Requires for /sbin/ldconfig, split static libraries into
+  devel-static package, and don't use makeinstall any more (all
+  suggested by Doug Ledford <dledford at redhat.com>).
+
 * Thu May  4 2006 Roland Dreier <rdreier at cisco.com> - 1.0.4-1
 - New upstream release
 
diff --git a/libibverbs.spec.in b/libibverbs.spec.in
index 49dde73..40310e2 100644
--- a/libibverbs.spec.in
+++ b/libibverbs.spec.in
@@ -1,19 +1,15 @@
-# $Id: libibverbs.spec.in 7484 2006-05-24 21:12:21Z roland $
-
-%define ver      @VERSION@
-
 Name: libibverbs
-Version: 1.0.4
+Version: 1.1
 Release: 1%{?dist}
-Summary: A library for direct userspace use of InfiniBand
+Summary: A library for direct userspace use of InfiniBand hardware
 
 Group: System Environment/Libraries
 License: GPL/BSD
-Url: http://openib.org/
-Source: http://openib.org/downloads/libibverbs-1.0.4.tar.gz
-BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-
-BuildRequires: %{_includedir}/sysfs/libsysfs.h
+Url: http://openfabrics.org/
+Source: http://openfabrics.org/downloads/libibverbs-1.1.tar.gz
+BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
 
 %description
 libibverbs is a library that allows userspace processes to use
@@ -27,10 +23,16 @@ also be installed.
 %package devel
 Summary: Development files for the libibverbs library
 Group: System Environment/Libraries
-Requires: %{name} = %{version}-%{release} %{_includedir}/sysfs/libsysfs.h
 
 %description devel
-Static libraries and header files for the libibverbs verbs library.
+Header files for the libibverbs library.
+
+%package devel-static
+Summary: Static development files for the libibverbs library
+Group: System Environment/Libraries
+
+%description devel-static
+Static libraries for the libibverbs library.
 
 %package utils
 Summary: Examples for the libibverbs library
@@ -42,7 +44,7 @@ Useful libibverbs1 example programs such as ibv_devinfo, which
 displays information about InfiniBand devices.
 
 %prep
-%setup -q -n %{name}-%{ver}
+%setup -q -n %{name}- at VERSION@
 
 %build
 %configure
@@ -50,7 +52,7 @@ make %{?_smp_mflags}
 
 %install
 rm -rf $RPM_BUILD_ROOT
-%makeinstall
+make DESTDIR=%{buildroot} install
 # remove unpackaged files from the buildroot
 rm -f $RPM_BUILD_ROOT%{_libdir}/*.la
 
@@ -68,8 +70,12 @@ rm -rf $RPM_BUILD_ROOT
 %files devel
 %defattr(-,root,root,-)
 %{_libdir}/lib*.so
-%{_libdir}/*.a
 %{_includedir}/*
+%{_mandir}/man3/*
+
+%files devel-static
+%defattr(-,root,root,-)
+%{_libdir}/*.a
 
 %files utils
 %defattr(-,root,root,-)
@@ -77,6 +83,18 @@ rm -rf $RPM_BUILD_ROOT
 %{_mandir}/man1/*
 
 %changelog
+* Wed Apr 11 2007 Roland Dreier <rdreier at cisco.com> - 1.1-1
+- New upstream release
+
+* Mon May 22 2006 Roland Dreier <rdreier at cisco.com> - 1.1-0.1.rc2
+- New upstream release
+- Remove dependency on libsysfs, since it is no longer used
+- Put section 3 manpages in devel package.
+- Spec file cleanups: remove unused ver macro, improve BuildRoot, add
+  Requires for /sbin/ldconfig, split static libraries into
+  devel-static package, and don't use makeinstall any more (all
+  suggested by Doug Ledford <dledford at redhat.com>).
+
 * Thu May  4 2006 Roland Dreier <rdreier at cisco.com> - 1.0.4-1
 - New upstream release
 
diff --git a/man/ibv_alloc_pd.3 b/man/ibv_alloc_pd.3
new file mode 100644
index 0000000..017ab32
--- /dev/null
+++ b/man/ibv_alloc_pd.3
@@ -0,0 +1,40 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_ALLOC_PD 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_alloc_pd, ibv_dealloc_pd \- allocate or deallocate a protection domain (PDs)
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "struct ibv_pd *ibv_alloc_pd(struct ibv_context " "*context" );
+.nl
+.BI "int ibv_dealloc_pd(struct ibv_pd " "*pd" );
+.fi
+.SH "DESCRIPTION"
+.B ibv_alloc_pd()
+allocates a PD for the InfiniBand device context 
+.I context\fR.
+.PP
+.B ibv_dealloc_pd()
+deallocates the PD
+.I pd\fR.
+.SH "RETURN VALUE"
+.B ibv_alloc_pd()
+returns a pointer to the allocated PD, or NULL if the request fails.
+.PP
+.B ibv_dealloc_pd()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "NOTES"
+.B ibv_dealloc_pd()
+may fail if any other InfiniBand resource is still associated with the
+PD being freed.
+.SH "SEE ALSO"
+.BR ibv_reg_mr (3),
+.BR ibv_create_srq (3),
+.BR ibv_create_qp (3),
+.BR ibv_create_ah (3),
+.BR ibv_create_ah_from_wc (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_attach_mcast.3 b/man/ibv_attach_mcast.3
new file mode 100644
index 0000000..cb6ddf2
--- /dev/null
+++ b/man/ibv_attach_mcast.3
@@ -0,0 +1,53 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_ATTACH_MCAST 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_attach_mcast, ibv_detach_mcast \- attach and detach a queue pair
+(QPs) to/from a multicast group
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_attach_mcast(struct ibv_qp " "*qp" ", union ibv_gid " "*gid" ",
+.BI "                     uint16_t " "lid" ");
+.nl
+.BI "int ibv_detach_mcast(struct ibv_qp " "*qp" ", union ibv_gid " "*gid" ",
+.BI "                     uint16_t " "lid" ");
+.fi
+.SH "DESCRIPTION"
+.B ibv_attach_mcast()
+attaches the QP 
+.I qp
+to the multicast group having MGID
+.I gid
+and MLID 
+.I lid\fR.
+.PP
+.B ibv_detach_mcast()
+detaches the QP
+.I qp
+to the multicast group having MGID
+.I gid
+and MLID
+.I lid\fR.
+.SH "RETURN VALUE"
+.B ibv_attach_mcast()
+and
+.B ibv_detach_mcast()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "NOTES"
+Only QPs of Transport Service Type
+.BR IBV_QPT_UD
+may be attached to multicast groups.
+.PP
+If a QP is attached to the same multicast group multiple times, the QP will still receive a single copy of a multicast message.
+.PP
+In order to receive multicast messages, a join request for the
+multicast group must be sent to the subnet administrator (SA), so that
+the fabric's multicast routing is configured to deliver messages to
+the local port.
+.SH "SEE ALSO"
+.BR ibv_create_qp (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_create_ah.3 b/man/ibv_create_ah.3
new file mode 100644
index 0000000..85e4a71
--- /dev/null
+++ b/man/ibv_create_ah.3
@@ -0,0 +1,64 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_CREATE_AH 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_create_ah, ibv_destroy_ah \- create or destroy an address handle (AH)
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "struct ibv_ah *ibv_create_ah(struct ibv_pd " "*pd" ",
+.BI "                             struct ibv_ah_attr " "*attr" ");
+.nl
+.BI "int ibv_destroy_ah(struct ibv_ah " "*ah" ");
+.fi
+.SH "DESCRIPTION"
+.B ibv_create_ah()
+creates an address handle (AH) associated with the protection domain
+.I pd\fR.
+The argument
+.I attr
+is an ibv_ah_attr struct, as defined in <infiniband/verbs.h>.
+.PP
+.nf
+struct ibv_ah_attr {
+.in +8
+struct ibv_global_route grh;            /* Global Routing Header (GRH) attributes */
+uint16_t                dlid;           /* Destination LID */
+uint8_t                 sl;             /* Service Level */
+uint8_t                 src_path_bits;  /* Source path bits */
+uint8_t                 static_rate;    /* Maximum static rate */
+uint8_t                 is_global;      /* GRH attributes are valid */
+uint8_t                 port_num;       /* Physical port number */
+.in -8
+};
+.sp
+.nf
+struct ibv_global_route {
+.in +8
+union ibv_gid           dgid;           /* Destination GID or MGID */
+uint32_t                flow_label;     /* Flow label */
+uint8_t                 sgid_index;     /* Source GID index */
+uint8_t                 hop_limit;      /* Hop limit */
+uint8_t                 traffic_class;  /* Traffic class */
+.in -8
+};
+.fi
+.sp
+.PP
+.B ibv_destroy_ah()
+destroys the AH
+.I ah\fR.
+.SH "RETURN VALUE"
+.B ibv_create_ah()
+returns a pointer to the created AH, or NULL if the request fails.
+.PP
+.B ibv_destroy_ah()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "SEE ALSO"
+.BR ibv_alloc_pd (3),
+.BR ibv_init_ah_from_wc (3),
+.BR ibv_create_ah_from_wc (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_create_ah_from_wc.3 b/man/ibv_create_ah_from_wc.3
new file mode 100644
index 0000000..487f053
--- /dev/null
+++ b/man/ibv_create_ah_from_wc.3
@@ -0,0 +1,63 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_CREATE_AH_FROM_WC 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_init_ah_from_wc, ibv_create_ah_from_wc \- initialize or create an
+address handle (AH) from a work completion
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_init_ah_from_wc(struct ibv_context " "*context" ", uint8_t " "port_num" ,
+.BI "                        struct ibv_wc " "*wc" ", struct ibv_grh " "*grh" ,
+.BI "                        struct ibv_ah_attr " "*ah_attr" );
+.nl
+.BI "struct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd " "*pd" ,
+.BI "                                     struct ibv_wc " "*wc" ,
+.BI "                                     struct ibv_grh " "*grh" ,
+.BI "                                     uint8_t " "port_num" );
+.fi
+.SH "DESCRIPTION"
+.B ibv_init_ah_from_wc()
+initializes the address handle (AH) attribute structure
+.I ah_attr
+for the InfiniBand device context
+.I context
+using the port number
+.I port_num\fR,
+using attributes from the work completion
+.I wc
+and the Global Routing Header (GRH) structure
+.I grh\fR.
+.PP
+.B ibv_create_ah_from_wc()
+creates an AH associated with the protection domain
+.I pd
+using the port number
+.I port_num\fR,
+using attributes from the work completion
+.I wc
+and the Global Routing Header (GRH) structure
+.I grh\fR.
+.SH "RETURN VALUE"
+.B ibv_init_ah_from_wc()
+returns 0 on success, and \-1 on error.
+.PP
+.B ibv_create_ah_from_wc()
+returns a pointer to the created AH, or NULL if the request fails.
+.SH "NOTES"
+The filled structure
+.I ah_attr
+returned from
+.B ibv_init_ah_from_wc()
+can be used to create a new AH using
+.B ibv_create_ah()\fR.
+.SH "SEE ALSO"
+.BR ibv_open_device (3),
+.BR ibv_alloc_pd (3),
+.BR ibv_create_ah (3),
+.BR ibv_destroy_ah (3),
+.BR ibv_poll_cq (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_create_comp_channel.3 b/man/ibv_create_comp_channel.3
new file mode 100644
index 0000000..e0e1e68
--- /dev/null
+++ b/man/ibv_create_comp_channel.3
@@ -0,0 +1,49 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_CREATE_COMP_CHANNEL 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_create_comp_channel, ibv_destroy_comp_channel \- create or
+destroy a completion event channel
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "struct ibv_comp_channel *ibv_create_comp_channel(struct ibv_context
+.BI "                                                 " "*context" );
+.nl
+.BI "int ibv_destroy_comp_channel(struct ibv_comp_channel " "*channel" );
+.fi
+.SH "DESCRIPTION"
+.B ibv_create_comp_channel()
+creates a completion event channel for the InfiniBand device context
+.I context\fR.
+.PP
+.B ibv_destroy_comp_channel()
+destroys the completion event channel
+.I channel\fR.
+.SH "RETURN VALUE"
+.B ibv_create_comp_channel()
+returns a pointer to the created completion event channel, or NULL if the request fails.
+.PP
+.B ibv_destroy_comp_channel()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "NOTES"
+A "completion channel" is an abstraction introduced by libibverbs that
+does not exist in the InfiniBand Architecture verbs specification.  A
+completion channel is essentially file descriptor that is used to
+deliver completion notifications to a userspace process.  When a
+completion event is generated for a completion queue (CQ), the event
+is delivered via the completion channel attached to that CQ.  This may
+be useful to steer completion events to different threads by using
+multiple completion channels.
+.PP
+.B ibv_destroy_comp_channel()
+fails if any CQs are still associated with the completion event
+channel being destroyed.
+.SH "SEE ALSO"
+.BR ibv_open_device (3),
+.BR ibv_create_cq (3),
+.BR ibv_get_cq_event (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_create_cq.3 b/man/ibv_create_cq.3
new file mode 100644
index 0000000..c39fe83
--- /dev/null
+++ b/man/ibv_create_cq.3
@@ -0,0 +1,57 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_CREATE_CQ 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_create_cq, ibv_destroy_cq \- create or destroy a completion queue (CQ)
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "struct ibv_cq *ibv_create_cq(struct ibv_context " "*context" ", int " "cqe" ,
+.BI "                             void " "*cq_context" ,
+.BI "                             struct ibv_comp_channel " "*channel" ,
+.BI "                             int " "comp_vector" );
+.nl
+.BI "int ibv_destroy_cq(struct ibv_cq " "*cq" );
+.fi
+.SH "DESCRIPTION"
+.B ibv_create_cq()
+creates a completion queue (CQ) with at least
+.I cqe
+entries for the InfiniBand device context
+.I context\fR.
+The pointer
+.I cq_context
+will be used to set user context pointer of the CQ structure. The argument
+.I channel
+is optional; if not NULL, the completion channel
+.I channel
+will be used to return completion events.  The CQ will use the
+completion vector
+.I comp_vector
+for signaling completion events; it must be at least zero and less than
+.I context\fR->num_comp_vectors.
+.PP
+.B ibv_destroy_cq()
+destroys the CQ
+.I cq\fR.
+.SH "RETURN VALUE"
+.B ibv_create_cq()
+returns a pointer to the CQ, or NULL if the request fails.
+.PP
+.B ibv_destroy_cq()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "NOTES"
+.B ibv_create_cq()
+may create a CQ with size greater than or equal to the requested
+size. Check the cqe attribute in the returned CQ for the actual size.
+.PP
+.B ibv_destroy_cq()
+fails if any queue pair is still associated with this CQ.
+.SH "SEE ALSO"
+.BR ibv_resize_cq (3),
+.BR ibv_req_notify_cq (3),
+.BR ibv_create_qp (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_create_qp.3 b/man/ibv_create_qp.3
new file mode 100644
index 0000000..68a08b0
--- /dev/null
+++ b/man/ibv_create_qp.3
@@ -0,0 +1,85 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_CREATE_QP 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_create_qp, ibv_destroy_qp \- create or destroy a queue pair (QP)
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "struct ibv_qp *ibv_create_qp(struct ibv_pd " "*pd" ,
+.BI "                             struct ibv_qp_init_attr " "*qp_init_attr)" ;
+.nl
+.BI "int ibv_destroy_qp(struct ibv_qp " "*qp)" ;
+.fi
+.SH "DESCRIPTION"
+.B ibv_create_qp()
+creates a queue pair (QP) associated with the protection domain
+.I pd\fR.
+The argument
+.I qp_init_attr
+is an ibv_qp_init_attr struct, as defined in <infiniband/verbs.h>.
+.PP
+.nf
+struct ibv_qp_init_attr {
+.in +8
+void                   *qp_context;     /* Associated context of the QP */
+struct ibv_cq          *send_cq;        /* CQ to be associated with the Send Queue (SQ) */ 
+struct ibv_cq          *recv_cq;        /* CQ to be associated with the Receive Queue (RQ) */
+struct ibv_srq         *srq;            /* SRQ handle if QP is to be associated with an SRQ, otherwise NULL */
+struct ibv_qp_cap       cap;            /* QP capabilities */
+enum ibv_qp_type        qp_type;        /* QP Transport Service Type: IBV_QPT_RC, IBV_QPT_UC, or IBV_QPT_UD */
+int                     sq_sig_all;     /* If set, each Work Request (WR) submitted to the SQ generates a completion entry */
+.in -8
+};
+.sp
+.nf
+struct ibv_qp_cap {
+.in +8
+uint32_t                max_send_wr;    /* Requested max number of outstanding WRs in the SQ */
+uint32_t                max_recv_wr;    /* Requested max number of outstanding WRs in the RQ */
+uint32_t                max_send_sge;   /* Requested max number of scatter/gather (s/g) elements in a WR in the SQ */
+uint32_t                max_recv_sge;   /* Requested max number of s/g elements in a WR in the SQ */
+uint32_t                max_inline_data;/* Requested max number of data (bytes) that can be posted inline to the SQ, otherwise 0 */
+.in -8
+};
+.fi
+.PP
+The function
+.B ibv_create_qp()
+will update the
+.I qp_init_attr\fB\fR->cap
+struct with the actual \s-1QP\s0 values of the QP that was created;
+the values will be greater than or equal to the values requested.
+.PP
+.B ibv_destroy_qp()
+destroys the QP
+.I qp\fR.
+.SH "RETURN VALUE"
+.B ibv_create_qp()
+returns a pointer to the created QP, or NULL if the request fails.
+Check the QP number (\fBqp_num\fR) in the returned QP.
+.PP
+.B ibv_destroy_qp()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "NOTES"
+.B ibv_create_qp()
+will fail if a it is asked to create QP of a type other than
+.B IBV_QPT_RC
+or
+.B IBV_QPT_UD
+associated with an SRQ.
+.PP
+The attributes max_recv_wr and max_recv_sge are ignored by
+.B ibv_create_qp()
+if the QP is to be associated with an SRQ.
+.PP
+.B ibv_destroy_qp()
+fails if the QP is attached to a multicast group.
+.SH "SEE ALSO"
+.BR ibv_alloc_pd (3),
+.BR ibv_modify_qp (3),
+.BR ibv_query_qp (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_create_srq.3 b/man/ibv_create_srq.3
new file mode 100644
index 0000000..ff33736
--- /dev/null
+++ b/man/ibv_create_srq.3
@@ -0,0 +1,67 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_CREATE_SRQ 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_create_srq, ibv_destroy_srq \- create or destroy a shared receive queue (SRQ)
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "struct ibv_srq *ibv_create_srq(struct ibv_pd " "*pd" ", struct "
+.BI "                               ibv_srq_init_attr " "*srq_init_attr" );
+.nl
+.BI "int ibv_destroy_srq(struct ibv_srq " "*srq" );
+.fi
+.SH "DESCRIPTION"
+.B ibv_create_srq()
+creates a shared receive queue (SRQ) associated with the protection domain
+.I pd\fR.
+The argument
+.I srq_init_attr
+is an ibv_srq_init_attr struct, as defined in <infiniband/verbs.h>.
+.PP
+.nf
+struct ibv_srq_init_attr {
+.in +8
+void                   *srq_context;    /* Associated context of the SRQ */
+struct ibv_srq_attr     attr;           /* SRQ attributes */
+.in -8
+};
+.sp
+.nf
+struct ibv_srq_attr {
+.in +8
+uint32_t                max_wr;         /* Requested max number of outstanding work requests (WRs) in the SRQ */
+uint32_t                max_sge;        /* Requested max number of scatter elements per WR */
+uint32_t                srq_limit;      /* The limit value of the SRQ (irrelevant for ibv_create_srq) */
+.in -8
+};
+.fi
+.PP
+The function
+.B ibv_create_srq()
+will update the
+.I srq_init_attr
+struct with the original values of the SRQ that was created; the
+values of max_wr and max_sge will be greater than or equal to the
+values requested.
+.PP
+.B ibv_destroy_srq()
+destroys the SRQ
+.I srq\fR.
+.SH "RETURN VALUE"
+.B ibv_create_srq()
+returns a pointer to the created SRQ, or NULL if the request fails.
+.PP
+.B ibv_destroy_srq()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "NOTES"
+.B ibv_destroy_srq()
+fails if any queue pair is still associated with this SRQ.
+.SH "SEE ALSO"
+.BR ibv_alloc_pd (3),
+.BR ibv_modify_srq (3),
+.BR ibv_query_srq (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_fork_init.3 b/man/ibv_fork_init.3
new file mode 100644
index 0000000..d911c3f
--- /dev/null
+++ b/man/ibv_fork_init.3
@@ -0,0 +1,56 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_FORK_INIT 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_fork_init \- initialize libibverbs to support fork()
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_fork_init(void);
+.fi
+.SH "DESCRIPTION"
+.B ibv_fork_init()
+initializes libibverbs's data structures to handle
+.B fork()
+function calls correctly and avoid data corruption, whether
+.B fork()
+is called explicitly or implicitly (such as in
+.B system()\fR).
+.PP
+It is not necessary to use this function if all parent process threads
+are always blocked until all child processes end or change address
+spaces via an
+.B exec()
+operation.
+.SH "RETURN VALUE"
+.B ibv_fork_init()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "NOTES"
+.B ibv_fork_init()
+works on Linux kernels supporting the
+.BR MADV_DONTFORK
+flag for
+.B madvise()
+(2.6.17 and higher).
+.PP
+Setting the environment variable
+.BR RDMAV_FORK_SAFE
+or
+.BR IBV_FORK_SAFE
+has the same effect as calling
+.B ibv_fork_init()\fR.
+.PP
+Calling
+.B ibv_fork_init()
+will reduce performance due to an extra system call for every memory
+registration, and the additional memory allocated to track memory
+regions.  The precise performance impact depends on the workload and
+usually will not be significant.
+.SH "SEE ALSO"
+.BR fork (2),
+.BR system (3),
+.BR ibv_get_device_list (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_get_async_event.3 b/man/ibv_get_async_event.3
new file mode 100644
index 0000000..77e8be8
--- /dev/null
+++ b/man/ibv_get_async_event.3
@@ -0,0 +1,162 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_GET_ASYNC_EVENT 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_get_async_event, ibv_ack_async_event \- get or acknowledge asynchronous events
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_get_async_event(struct ibv_context " "*context" ,
+.BI "                        struct ibv_async_event " "*event" );
+.nl
+.BI "void ibv_ack_async_event(struct ibv_async_event " "*event" );
+.fi
+.SH "DESCRIPTION"
+.B ibv_get_async_event()
+waits for the next async event of the InfiniBand device context
+.I context
+and returns it through the pointer
+.I event\fR,
+which is an ibv_async_event struct, as defined in <infiniband/verbs.h>.
+.PP
+.nf
+struct ibv_async_event {
+.in +8
+union {
+.in +8
+struct ibv_cq  *cq;             /* CQ that got the event */
+struct ibv_qp  *qp;             /* QP that got the event */
+struct ibv_srq *srq;            /* SRQ that got the event */
+int             port_num;       /* port number that got the event */
+.in -8
+} element;
+enum ibv_event_type     event_type;     /* type of the event */
+.in -8
+};
+.fi
+.PP
+One member of the element union will be valid, depending on the
+event_type member of the structure.  event_type will be one of the
+following events:
+.PP
+.I QP events:
+.TP
+.B IBV_EVENT_QP_FATAL \fR Error occurred on a QP and it transitioned to error state
+.TP
+.B IBV_EVENT_QP_REQ_ERR \fR Invalid Request Local Work Queue Error
+.TP
+.B IBV_EVENT_QP_ACCESS_ERR \fR Local access violation error
+.TP
+.B IBV_EVENT_COMM_EST \fR Communication was established on a QP
+.TP
+.B IBV_EVENT_SQ_DRAINED \fR Send Queue was drained of outstanding messages in progress 
+.TP
+.B IBV_EVENT_PATH_MIG \fR A connection has migrated to the alternate path
+.TP
+.B IBV_EVENT_PATH_MIG_ERR \fR A connection failed to migrate to the alternate path
+.TP
+.B IBV_EVENT_QP_LAST_WQE_REACHED \fR Last WQE Reached on a QP associated with an SRQ
+.PP
+.I CQ events:
+.TP
+.B IBV_EVENT_CQ_ERR \fR CQ is in error (CQ overrun)
+.PP
+.I SRQ events:
+.TP
+.B IBV_EVENT_SRQ_ERR \fR Error occurred on an SRQ
+.TP
+.B IBV_EVENT_SRQ_LIMIT_REACHED \fR SRQ limit was reached
+.PP
+.I Port events:
+.TP
+.B IBV_EVENT_PORT_ACTIVE \fR Link became active on a port
+.TP
+.B IBV_EVENT_PORT_ERR \fR Link became unavailable on a port
+.TP
+.B IBV_EVENT_LID_CHANGE \fR LID was changed on a port
+.TP
+.B IBV_EVENT_PKEY_CHANGE \fR P_Key table was changed on a port
+.TP
+.B IBV_EVENT_SM_CHANGE \fR SM was changed on a port
+.TP
+.B IBV_EVENT_CLIENT_REREGISTER \fR SM sent a CLIENT_REREGISTER request to a port
+.PP
+.I CA events:
+.TP
+.B IBV_EVENT_DEVICE_FATAL \fR CA is in FATAL state
+.PP
+.B ibv_ack_async_event()
+acknowledge the async event
+.I event\fR.
+.SH "RETURN VALUE"
+.B ibv_get_async_event()
+returns 0 on success, and \-1 on error.
+.PP
+.B ibv_ack_async_event()
+returns no value.
+.SH "NOTES"
+All async events that
+.B ibv_get_async_event()
+returns must be acknowledged using
+.B ibv_ack_async_event()\fR.
+To avoid races, destroying an object (CQ, SRQ or QP) will wait for all
+affiliated events for the object to be acknowledged; this avoids an
+application retrieving an affiliated event after the corresponding
+object has already been destroyed.
+.PP
+.B ibv_get_async_event()
+is a blocking function.  If multiple threads call this function
+simultaneously, then when an async event occurs, only one thread will
+receive it, and it is not possible to predict which thread will
+receive it.
+.SH "EXAMPLES"
+The following code example demonstrates one possible way to work with async events in non-blocking mode.
+It performs the following steps:
+.PP
+1. Set the async events queue work mode to be non-blocked
+.br
+2. Poll the queue until it has an async event
+.br
+3. Get the async event and ack it
+.PP
+.nf
+/* change the blocking mode of the async event queue */
+flags = fcntl(ctx->async_fd, F_GETFL);
+rc = fcntl(ctx->async_fd, F_SETFL, flags | O_NONBLOCK);
+if (rc < 0) {
+        fprintf(stderr, "Failed to change file descriptor of async event queue\en");
+        return 1;
+}
+
+/*
+ * poll the queue until it has an event and sleep ms_timeout
+ * milliseconds between any iteration
+ */
+my_pollfd.fd      = ctx->async_fd;
+my_pollfd.events  = POLLIN;
+my_pollfd.revents = 0;
+
+do {
+        rc = poll(&my_pollfd, 1, ms_timeout);
+} while (rc == 0);
+if (rc < 0) {
+        fprintf(stderr, "poll failed\en");
+        return 1;
+}
+
+/* Get the async event */
+if (ibv_get_async_event(ctx, &async_event)) {
+        fprintf(stderr, "Failed to get async_event\en");
+        return 1;
+}
+
+/* Ack the event */
+ibv_ack_async_event(&async_event);
+
+.fi
+.SH "SEE ALSO"
+.BR ibv_open_device (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_get_cq_event.3 b/man/ibv_get_cq_event.3
new file mode 100644
index 0000000..695734b
--- /dev/null
+++ b/man/ibv_get_cq_event.3
@@ -0,0 +1,181 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_GET_CQ_EVENT 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_get_cq_event, ibv_ack_cq_events \- get and acknowledge completion queue (CQ) events
+
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_get_cq_event(struct ibv_comp_channel " "*channel" ,
+.BI "                     struct ibv_cq " "**cq" ", void " "**cq_context" );
+.nl
+.BI "void ibv_ack_cq_events(struct ibv_cq " "*cq" ", unsigned int " "nevents" );
+.fi
+
+.SH "DESCRIPTION"
+.B ibv_get_cq_event()
+waits for the next completion event in the completion event channel
+.I channel\fR.
+The argument
+.I cq
+is used to return the CQ that caused the event and
+.I cq_context
+is used to return the CQ's context.
+.PP
+.B ibv_ack_cq_events()
+acknowledges
+.I nevents
+events on the CQ
+.I cq\fR.
+
+.SH "RETURN VALUE"
+.B ibv_get_cq_event()
+returns 0 on success, and \-1 on error.
+.PP
+.B ibv_ack_cq_events()
+returns no value.
+.SH "NOTES"
+All completion events that
+.B ibv_get_cq_event()
+returns must be acknowledged using
+.B ibv_ack_cq_events()\fR.
+To avoid races, destroying a CQ will wait for all completion events to
+be acknowledged; this guarantees a one-to-one correspondence between
+acks and successful gets.
+.PP
+Calling
+.B ibv_ack_cq_events()
+may be relatively expensive in the datapath, since it must take a
+mutex.  Therefore it may be better to amortize this cost by
+keeping a count of the number of events needing acknowledgement and
+acking several completion events in one call to
+.B ibv_ack_cq_events()\fR.
+.SH "EXAMPLES"
+The following code example demonstrates one possible way to work with
+completion events. It performs the following steps:
+.PP
+Stage I: Preparation
+.br
+1. Creates a CQ
+.br
+2. Requests for notification upon a new (first) completion event
+.PP
+Stage II: Completion Handling Routine
+.br
+3. Wait for the completion event and ack it
+.br
+4. Request for notification upon the next completion event
+.br
+5. Empty the CQ
+.PP
+Note that an extra event may be triggered without having a
+corresponding completion entry in the CQ.  This occurs if a completion
+entry is added to the CQ between Step 4 and Step 5, and the CQ is then
+emptied (polled) in Step 5.
+.PP
+.nf
+cq = ibv_create_cq(ctx, 1, ev_ctx, channel, 0);
+if (!cq) {
+        fprintf(stderr, "Failed to create CQ\en");
+        return 1;
+}
+.PP
+/* Request notification before any completion can be created */
+if (ibv_req_notify_cq(cq, 0)) {
+        fprintf(stderr, "Couldn't request CQ notification\en");
+        return 1;
+}
+.PP
+\&.
+\&.
+\&.
+.PP
+/* Wait for the completion event */
+if (ibv_get_cq_event(channel, &ev_cq, &ev_ctx)) {
+        fprintf(stderr, "Failed to get cq_event\en");
+        return 1;
+}
+
+/* Ack the event */
+ibv_ack_cq_events(ev_cq, 1);
+.PP
+/* Request notification upon the next completion event */
+if (ibv_req_notify_cq(cq, 0)) {
+        fprintf(stderr, "Couldn't request CQ notification\en");
+        return 1;
+}
+.PP
+/* Empty the CQ: poll all of the completions from the CQ (if any exist) */
+do {
+        ne = ibv_poll_cq(cq, 1, &wc);
+        if (ne < 0) {
+                fprintf(stderr, "Failed to poll completions from the CQ\en");
+                return 1;
+        }
+.PP
+        if (wc.status != IBV_WC_SUCCESS) {
+                fprintf(stderr, "Completion with status 0x%x was found\en", wc.status);
+                return 1;
+        }
+} while (ne);
+.fi
+
+The following code example demonstrates one possible way to work with
+completion events in non-blocking mode.  It performs the following
+steps:
+.PP
+1. Set the completion event channel to be non-blocked
+.br
+2. Poll the channel until there it has a completion event
+.br
+3. Get the completion event and ack it
+.PP
+.nf
+/* change the blocking mode of the completion channel */
+flags = fcntl(channel->fd, F_GETFL);
+rc = fcntl(channel->fd, F_SETFL, flags | O_NONBLOCK);
+if (rc < 0) {
+	fprintf(stderr, "Failed to change file descriptor of completion event channel\en");
+	return 1;
+}
+
+
+/*
+ * poll the channel until it has an event and sleep ms_timeout
+ * milliseconds between any iteration
+ */
+my_pollfd.fd      = channel->fd;
+my_pollfd.events  = POLLIN;
+my_pollfd.revents = 0;
+
+do {
+	rc = poll(&my_pollfd, 1, ms_timeout);
+} while (rc == 0);
+if (rc < 0) {
+	fprintf(stderr, "poll failed\en");
+	return 1;
+}
+ev_cq = cq;
+
+/* Wait for the completion event */
+if (ibv_get_cq_event(channel, &ev_cq, &ev_ctx)) {
+        fprintf(stderr, "Failed to get cq_event\en");
+        return 1;
+}
+
+/* Ack the event */
+ibv_ack_cq_events(ev_cq, 1);
+
+.fi
+.SH "SEE ALSO"
+.BR ibv_create_comp_channel (3),
+.BR ibv_create_cq (3),
+.BR ibv_req_notify_cq (3),
+.BR ibv_poll_cq (3)
+
+.SH "AUTHORS"
+.TP
+Dotan Barak
+.RI < dotanb at mellanox.co.il >
diff --git a/man/ibv_get_device_guid.3 b/man/ibv_get_device_guid.3
new file mode 100644
index 0000000..03f444a
--- /dev/null
+++ b/man/ibv_get_device_guid.3
@@ -0,0 +1,25 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_GET_DEVICE_GUID 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_get_device_guid \- get an InfiniBand device's GUID
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "uint64_t ibv_get_device_guid(struct ibv_device " "*device" ");
+.fi
+.SH "DESCRIPTION"
+.B ibv_get_device_name()
+returns the Global Unique IDentifier (GUID) of the InfiniBand device
+.I device\fR.
+.SH "RETURN VALUE"
+.B ibv_get_device_guid()
+returns the GUID of the device in network byte order.
+.SH "SEE ALSO"
+.BR ibv_get_device_list (3),
+.BR ibv_get_device_name (3),
+.BR ibv_open_device (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_get_device_list.3 b/man/ibv_get_device_list.3
new file mode 100644
index 0000000..4dd8180
--- /dev/null
+++ b/man/ibv_get_device_list.3
@@ -0,0 +1,46 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_GET_DEVICE_LIST 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_get_device_list, ibv_free_device_list \- get and release list of available InfiniBand devices
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "struct ibv_device **ibv_get_device_list(int " "*num_devices" );
+.nl
+.BI "void ibv_free_device_list(struct ibv_device " "**list" );
+.fi
+.SH "DESCRIPTION"
+.B ibv_get_device_list()
+returns a NULL-terminated array of InfiniBand devices currently available.
+The argument
+.I num_devices
+is optional; if not NULL, it is set to the number of devices returned in the array.
+.PP
+.B ibv_free_device_list()
+frees the array of devices
+.I list
+returned by
+.B ibv_get_device_list()\fR.
+.SH "RETURN VALUE"
+.B ibv_get_device_list()
+returns the array of available InfiniBand devices, or NULL if the request fails.
+.PP
+.B ibv_free_device_list()
+returns no value.
+.SH "NOTES"
+Client code should open all the devices it intends to use with
+.B ibv_open_device()\fR before calling
+.B ibv_free_device_list()\fR.
+Once it frees the array with
+.B ibv_free_device_list()\fR,
+it will be able to use only the open devices; pointers to unopened devices will no longer be valid.
+.SH "SEE ALSO"
+.BR ibv_fork_init (3),
+.BR ibv_get_device_name (3),
+.BR ibv_get_device_guid (3),
+.BR ibv_open_device (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_get_device_name.3 b/man/ibv_get_device_name.3
new file mode 100644
index 0000000..c53f97d
--- /dev/null
+++ b/man/ibv_get_device_name.3
@@ -0,0 +1,25 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_GET_DEVICE_NAME 3  2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_get_device_name \- get an InfiniBand device's name
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "const char *ibv_get_device_name(struct ibv_device " "*device" ");
+.fi
+.SH "DESCRIPTION"
+.B ibv_get_device_name()
+returns a human-readable name associated with the InfiniBand device
+.I device\fR.
+.SH "RETURN VALUE"
+.B ibv_get_device_name()
+returns a pointer to the device name, or NULL if the request fails.
+.SH "SEE ALSO"
+.BR ibv_get_device_list (3),
+.BR ibv_get_device_guid (3),
+.BR ibv_open_device (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_modify_qp.3 b/man/ibv_modify_qp.3
new file mode 100644
index 0000000..a870744
--- /dev/null
+++ b/man/ibv_modify_qp.3
@@ -0,0 +1,169 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_MODIFY_QP 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_modify_qp \- modify the attributes of a queue pair (QP)
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_modify_qp(struct ibv_qp " "*qp" ", struct ibv_qp_attr " "*attr" ,
+.BI "                  enum ibv_qp_attr_mask " "attr_mask" );
+.fi
+.SH "DESCRIPTION"
+.B ibv_modify_qp()
+modifies the attributes of QP
+.I qp
+with the attributes in
+.I attr
+according to the mask
+.I attr_mask\fR.
+The argument \fIattr\fR is an ibv_qp_attr struct, as defined in <infiniband/verbs.h>.
+.PP
+.nf
+struct ibv_qp_attr {
+.in +8
+enum ibv_qp_state       qp_state;               /* Move the QP to this state */
+enum ibv_qp_state       cur_qp_state;           /* Assume this is the current QP state */
+enum ibv_mtu            path_mtu;               /* Path MTU (valid only for RC/UC QPs) */
+enum ibv_mig_state      path_mig_state;         /* Path migration state (valid if HCA supports APM) */
+uint32_t                qkey;                   /* Q_Key for the QP (valid only for UD QPs) */
+uint32_t                rq_psn;                 /* PSN for receive queue (valid only for RC/UC QPs) */
+uint32_t                sq_psn;                 /* PSN for send queue (valid only for RC/UC QPs) */
+uint32_t                dest_qp_num;            /* Destination QP number (valid only for RC/UC QPs) */
+int                     qp_access_flags;        /* Mask of enabled remote access operations (valid only for RC/UC QPs) */
+struct ibv_qp_cap       cap;                    /* QP capabilities (valid if HCA supports QP resizing) */
+struct ibv_ah_attr      ah_attr;                /* Primary path address vector (valid only for RC/UC QPs) */
+struct ibv_ah_attr      alt_ah_attr;            /* Alternate path address vector (valid only for RC/UC QPs) */
+uint16_t                pkey_index;             /* Primary P_Key index */
+uint16_t                alt_pkey_index;         /* Alternate P_Key index */
+uint8_t                 en_sqd_async_notify;    /* Enable SQD.drained async notification (Valid only if qp_state is SQD) */
+uint8_t                 sq_draining;            /* Is the QP draining? Irrelevant for ibv_modify_qp() */
+uint8_t                 max_rd_atomic;          /* Number of outstanding RDMA reads & atomic operations on the destination QP (valid only for RC QPs) */
+uint8_t                 max_dest_rd_atomic;     /* Number of responder resources for handling incoming RDMA reads & atomic operations (valid only for RC QPs) */
+uint8_t                 min_rnr_timer;          /* Minimum RNR NAK timer (valid only for RC QPs) */
+uint8_t                 port_num;               /* Primary port number */
+uint8_t                 timeout;                /* Local ack timeout for primary path (valid only for RC QPs) */
+uint8_t                 retry_cnt;              /* Retry count (valid only for RC QPs) */
+uint8_t                 rnr_retry;              /* RNR retry (valid only for RC QPs) */
+uint8_t                 alt_port_num;           /* Alternate port number */
+uint8_t                 alt_timeout;            /* Local ack timeout for alternate path (valid only for RC QPs) */
+.in -8
+};
+.fi
+.PP
+For details on struct ibv_qp_cap see the description of 
+.B ibv_create_qp()\fR.
+For details on struct ibv_ah_attr see the description of
+.B ibv_create_ah()\fR.
+.PP
+The argument
+.I attr_mask
+specifies the QP attributes to be modified.
+The argument is either 0 or the bitwise OR of one or more of the following flags:
+.PP
+.TP
+.B IBV_QP_STATE \fR Modify qp_state
+.TP
+.B IBV_QP_CUR_STATE \fR Set cur_qp_state
+.TP
+.B IBV_QP_EN_SQD_ASYNC_NOTIFY \fR Set en_sqd_async_notify
+.TP
+.B IBV_QP_ACCESS_FLAGS \fR Set qp_access_flags
+.TP
+.B IBV_QP_PKEY_INDEX \fR Set pkey_index
+.TP
+.B IBV_QP_PORT \fR Set port_num
+.TP
+.B IBV_QP_QKEY \fR Set qkey
+.TP
+.B IBV_QP_AV \fR Set ah_attr
+.TP
+.B IBV_QP_PATH_MTU \fR Set path_mtu
+.TP
+.B IBV_QP_TIMEOUT \fR Set timeout
+.TP
+.B IBV_QP_RETRY_CNT \fR Set retry_cnt
+.TP
+.B IBV_QP_RNR_RETRY \fR Set rnr_retry
+.TP
+.B IBV_QP_RQ_PSN \fR Set rq_psn
+.TP
+.B IBV_QP_MAX_QP_RD_ATOMIC \fR Set max_rd_atomic
+.TP
+.B IBV_QP_ALT_PATH \fR Set the alternative path via: alt_ah_attr, alt_pkey_index, alt_port_num, alt_timeout
+.TP
+.B IBV_QP_MIN_RNR_TIMER \fR Set min_rnr_timer
+.TP
+.B IBV_QP_SQ_PSN \fR Set sq_psn
+.TP
+.B IBV_QP_MAX_DEST_RD_ATOMIC \fR Set max_dest_rd_atomic
+.TP
+.B IBV_QP_PATH_MIG_STATE \fR Set path_mig_state
+.TP
+.B IBV_QP_CAP \fR Set cap
+.TP
+.B IBV_QP_DEST_QPN \fR Set dest_qp_num
+.SH "RETURN VALUE"
+.B ibv_modify_qp()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "NOTES"
+If any of the modify attributes or the modify mask are invalid, none
+of the attributes will be modified (including the QP state).
+.PP
+Not all devices support resizing QPs.  To check if a device supports it, check if the
+.B IBV_DEVICE_RESIZE_MAX_WR
+bit is set in the device capabilities flags.
+.PP
+Not all devices support alternate paths.  To check if a device supports it, check if the
+.B IBV_DEVICE_AUTO_PATH_MIG
+bit is set in the device capabilities flags.
+.PP
+The following tables indicate for each QP Transport Service Type, the
+minimum list of attributes that must be changed upon transitioning QP
+state from: Reset \-\-> Init \-\-> RTR \-\-> RTS.
+.PP
+.nf
+For QP Transport Service Type \fB IBV_QPT_UD\fR:
+.sp
+Next state     Required attributes
+\-\-\-\-\-\-\-\-\-\-     \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
+Init \fB          IBV_QP_STATE, IBV_QP_PKEY_INDEX, IBV_QP_PORT, \fR
+     \fB          IBV_QP_QKEY \fR
+RTR  \fB          None \fR
+RTS  \fB          IBV_QP_STATE, IBV_QP_SQ_PSN \fR
+.fi
+.PP
+.nf
+For QP Transport Service Type \fB IBV_QPT_UC\fR:
+.sp
+Next state     Required attributes
+\-\-\-\-\-\-\-\-\-\-     \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
+Init \fB          IBV_QP_STATE, IBV_QP_PKEY_INDEX, IBV_QP_PORT, \fR
+     \fB          IBV_QP_ACCESS_FLAGS \fR
+RTR  \fB          IBV_QP_STATE, IBV_QP_AV, IBV_QP_PATH_MTU, \fR
+     \fB          IBV_QP_DEST_QPN, IBV_QP_RQ_PSN \fR
+RTS  \fB          IBV_QP_STATE, IBV_QP_SQ_PSN \fR
+.fi
+.PP
+.nf
+For QP Transport Service Type \fB IBV_QPT_RC\fR:
+.sp
+Next state     Required attributes
+\-\-\-\-\-\-\-\-\-\-     \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
+Init \fB          IBV_QP_STATE, IBV_QP_PKEY_INDEX, IBV_QP_PORT, \fR
+     \fB          IBV_QP_ACCESS_FLAGS \fR
+RTR  \fB          IBV_QP_STATE, IBV_QP_AV, IBV_QP_PATH_MTU, \fR
+     \fB          IBV_QP_DEST_QPN, IBV_QP_RQ_PSN, \fR
+     \fB          IBV_QP_MAX_DEST_RD_ATOMIC, IBV_QP_MIN_RNR_TIMER \fR
+RTS  \fB          IBV_QP_STATE, IBV_QP_SQ_PSN, IBV_QP_MAX_QP_RD_ATOMIC, \fR
+     \fB          IBV_QP_RETRY_CNT, IBV_QP_RNR_RETRY, IBV_QP_TIMEOUT \fR
+.fi
+.SH "SEE ALSO"
+.BR ibv_create_qp (3),
+.BR ibv_destroy_qp (3),
+.BR ibv_query_qp (3),
+.BR ibv_create_ah (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_modify_srq.3 b/man/ibv_modify_srq.3
new file mode 100644
index 0000000..01375c9
--- /dev/null
+++ b/man/ibv_modify_srq.3
@@ -0,0 +1,63 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_MODIFY_SRQ 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_modify_srq \- modify attributes of a shared receive queue (SRQ)
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_modify_srq(struct ibv_srq " "*srq" ,
+.BI "                   struct ibv_srq_attr " "*srq_attr" ,
+.BI "                   enum ibv_srq_attr_mask " "srq_attr_mask" );
+.fi
+.SH "DESCRIPTION"
+.B ibv_modify_srq()
+modifies the attributes of SRQ
+.I srq
+with the attributes in
+.I srq_attr
+according to the mask
+.I srq_attr_mask\fR.
+The argument \fIsrq_attr\fR is an ibv_srq_attr struct, as defined in <infiniband/verbs.h>.
+.PP
+.nf
+struct ibv_srq_attr {
+.in +8
+uint32_t                max_wr;      /* maximum number of outstanding work requests (WRs) in the SRQ */
+uint32_t                max_sge;     /* number of scatter elements per WR (irrelevant for ibv_modify_srq) */
+uint32_t                srq_limit;   /* the limit value of the SRQ */
+.in -8
+};
+.fi
+.PP
+The argument
+.I srq_attr_mask
+specifies the SRQ attributes to be modified.
+The argument is either 0 or the bitwise OR of one or more of the following flags:
+.PP
+.TP
+.B IBV_SRQ_MAX_WR \fR Resize the SRQ
+.TP
+.B IBV_SRQ_LIMIT \fR Set the SRQ limit
+.SH "RETURN VALUE"
+.B ibv_modify_srq()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "NOTES"
+If any of the modify attributes is invalid, none of the attributes will be modified.
+.PP
+Not all devices support resizing SRQs.  To check if a device supports it, check if the
+.B IBV_DEVICE_SRQ_RESIZE
+bit is set in the device capabilities flags.
+.PP
+Modifying the srq_limit arms the SRQ to produce an
+.B IBV_EVENT_SRQ_LIMIT_REACHED
+"low watermark" asynchronous event once the number of WRs in the SRQ drops below srq_limit.
+.SH "SEE ALSO"
+.BR ibv_query_device (3),
+.BR ibv_create_srq (3),
+.BR ibv_destroy_srq (3),
+.BR ibv_query_srq (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_open_device.3 b/man/ibv_open_device.3
new file mode 100644
index 0000000..1858a42
--- /dev/null
+++ b/man/ibv_open_device.3
@@ -0,0 +1,43 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_OPEN_DEVICE 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_open_device, ibv_close_device \- open and close an InfiniBand device context
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "struct ibv_context *ibv_open_device(struct ibv_device " "*device" ");
+.nl
+.BI "int ibv_close_device(struct ibv_context " "*context" ");
+.fi
+.SH "DESCRIPTION"
+.B ibv_open_device()
+opens the device
+.I device
+and creates a context for further use.
+.PP
+.B ibv_close_device()
+closes the device context
+.I context\fR.
+.SH "RETURN VALUE"
+.B ibv_open_device()
+returns a pointer to the allocated device context, or NULL if the request fails.
+.PP
+.B ibv_close_device()
+returns 0 on success, \-1 on failure.
+.SH "NOTES"
+.B ibv_close_device()
+does not release all the resources allocated using context
+.I context\fR.
+To avoid resource leaks, the user should release all associated
+resources before closing a context.
+.SH "SEE ALSO"
+.BR ibv_get_device_list (3),
+.BR ibv_query_device (3),
+.BR ibv_query_port (3),
+.BR ibv_query_gid (3),
+.BR ibv_query_pkey (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_poll_cq.3 b/man/ibv_poll_cq.3
new file mode 100644
index 0000000..b634fc9
--- /dev/null
+++ b/man/ibv_poll_cq.3
@@ -0,0 +1,77 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_POLL_CQ 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_poll_cq \- poll a completion queue (CQ)
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_poll_cq(struct ibv_cq " "*cq" ", int " "num_entries" ,
+.BI "                struct ibv_wc " "*wc" );
+.fi
+.SH "DESCRIPTION"
+.B ibv_poll_cq()
+polls the CQ
+.I cq
+for work completions and returns the first
+.I num_entries
+(or all available completions if the CQ contains fewer than this number) in the array
+.I wc\fR.
+The argument
+.I wc
+is a pointer to an array of ibv_wc structs, as defined in <infiniband/verbs.h>.
+.PP
+.nf
+struct ibv_wc {
+.in +8
+uint64_t                wr_id;          /* ID of the completed Work Request (WR) */
+enum ibv_wc_status      status;         /* Status of the operation */
+enum ibv_wc_opcode      opcode;         /* Operation type specified in the completed WR */
+uint32_t                vendor_err;     /* Vendor error syndrome */
+uint32_t                byte_len;       /* Number of bytes transferred */
+uint32_t                imm_data;       /* Immediate data (in network byte order) */
+uint32_t                qp_num;         /* Local QP number of completed WR */
+uint32_t                src_qp;         /* Source QP number (remote QP number) of completed WR */
+enum ibv_wc_flags       wc_flags;       /* Flags of the completed WR */
+uint16_t                pkey_index;     /* P_Key index (valid only for GSI QPs) */
+uint16_t                slid;           /* Source LID */
+uint8_t                 sl;             /* Service Level */
+uint8_t                 dlid_path_bits; /* DLID path bits (not applicable for multicast messages) */
+.in -8
+};
+.sp
+.fi
+.PP
+The attribute wc_flags describes the properties of the work completion. 
+It is either 0 or the bitwise OR of one or more of the following flags:
+.PP
+.TP
+.B IBV_WC_GRH \fR      GRH is present
+.TP
+.B IBV_WC_WITH_IMM \fR Immediate data value is valid
+.PP
+Not all
+.I wc
+attributes are always valid. If the completion status is other than
+.B IBV_WC_SUCCESS\fR,
+only the following attributes are valid: wr_id, status, qp_num, and vendor_err.
+.SH "RETURN VALUE"
+On success, 
+.B ibv_poll_cq()
+returns a non-negative value equal to the number of completions
+found.  On failure, a negative value is returned.
+.SH "NOTES"
+.PP
+Each polled completion is removed from the CQ and cannot be returned to it.
+.PP
+The user should consume work completions at a rate that prevents CQ
+overrun from occurrence.  In case of a CQ overrun, the async event
+.B IBV_EVENT_CQ_ERR
+will be triggered, and the CQ cannot be used.
+.SH "SEE ALSO"
+.BR ibv_post_send (3),
+.BR ibv_post_recv (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_post_recv.3 b/man/ibv_post_recv.3
new file mode 100644
index 0000000..478b67a
--- /dev/null
+++ b/man/ibv_post_recv.3
@@ -0,0 +1,70 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_POST_RECV 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_post_recv \- post a list of work requests (WRs) to a receive queue
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_post_recv(struct ibv_qp " "*qp" ", struct ibv_recv_wr " "*wr" ,
+.BI "                  struct ibv_recv_wr " "**bad_wr" );
+.fi
+.SH "DESCRIPTION"
+.B ibv_post_recv()
+posts the linked list of work requests (WRs) starting with
+.I wr
+to the receive queue of the queue pair
+.I qp\fR.
+It stops processing WRs from this list at the first failure (that can
+be detected immediately while requests are being posted), and returns
+this failing WR through
+.I bad_wr\fR.
+.PP
+The argument
+.I wr
+is an ibv_recv_wr struct, as defined in <infiniband/verbs.h>.
+.PP
+.nf
+struct ibv_recv_wr {
+.in +8
+uint64_t                wr_id;     /* User defined WR ID */
+struct ibv_recv_wr     *next;      /* Pointer to next WR in list, NULL if last WR */
+struct ibv_sge         *sg_list;   /* Pointer to the s/g array */
+int                     num_sge;   /* Size of the s/g array */
+.in -8
+};
+.sp
+.nf
+struct ibv_sge {
+.in +8
+uint64_t                addr;      /* Start address of the local memory buffer */
+uint32_t                length;    /* Length of the buffer */
+uint32_t                lkey;      /* Key of the local Memory Region */
+.in -8
+};
+.fi
+
+.SH "RETURN VALUE"
+.B ibv_post_recv()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "NOTES"
+The buffers used by a WR can only be safely reused after WR the
+request is fully executed and a work completion has been retrieved
+from the corresponding completion queue (CQ).
+.PP
+If the QP
+.I qp
+is associated with a shared receive queue, you must use the function
+.B ibv_post_srq_recv()\fR,
+and not
+.B ibv_post_recv()\fR,
+since the QP's own receive queue will not be used.
+.SH "SEE ALSO"
+.BR ibv_create_qp (3),
+.BR ibv_post_send (3),
+.BR ibv_post_srq_recv (3),
+.BR ibv_poll_cq (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_post_send.3 b/man/ibv_post_send.3
new file mode 100644
index 0000000..d1b04fd
--- /dev/null
+++ b/man/ibv_post_send.3
@@ -0,0 +1,121 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_POST_SEND 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_post_send \- post a list of work requests (WRs) to a send queue
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_post_send(struct ibv_qp " "*qp" ", struct ibv_send_wr " "*wr" ,
+.BI "                  struct ibv_send_wr " "**bad_wr" );
+.fi
+.SH "DESCRIPTION"
+.B ibv_post_send()
+posts the linked list of work requests (WRs) starting with
+.I wr
+to the send queue of the queue pair
+.I qp\fR.
+It stops processing WRs from this list at the first failure (that can
+be detected immediately while requests are being posted), and returns
+this failing WR through
+.I bad_wr\fR.
+.PP
+The argument
+.I wr
+is an ibv_send_wr struct, as defined in <infiniband/verbs.h>.
+.PP
+.nf
+struct ibv_send_wr {
+.in +8
+uint64_t                wr_id;                  /* User defined WR ID */
+struct ibv_send_wr     *next;                   /* Pointer to next WR in list, NULL if last WR */
+struct ibv_sge         *sg_list;                /* Pointer to the s/g array */
+int                     num_sge;                /* Size of the s/g array */
+enum ibv_wr_opcode      opcode;                 /* Operation type */
+enum ibv_send_flags     send_flags;             /* Flags of the WR properties */
+uint32_t                imm_data;               /* Immediate data (in network byte order) */
+union {
+.in +8
+struct {
+.in +8
+uint64_t        remote_addr;    /* Start address of remote memory buffer */
+uint32_t        rkey;           /* Key of the remote Memory Region */
+.in -8
+} rdma;
+struct {
+.in +8
+uint64_t        remote_addr;    /* Start address of remote memory buffer */ 
+uint64_t        compare_add;    /* Compare operand */
+uint64_t        swap;           /* Swap operand */
+uint32_t        rkey;           /* Key of the remote Memory Region */
+.in -8
+} atomic;
+struct {
+.in +8
+struct ibv_ah  *ah;             /* Address handle (AH) for the remote node address */
+uint32_t        remote_qpn;     /* QP number of the destination QP */
+uint32_t        remote_qkey;    /* Q_Key number of the destination QP */
+.in -8
+} ud;
+.in -8
+} wr;
+.in -8
+};
+.sp
+.nf
+struct ibv_sge {
+.in +8
+uint64_t                addr;                   /* Start address of the local memory buffer */
+uint32_t                length;                 /* Length of the buffer */
+uint32_t                lkey;                   /* Key of the local Memory Region */
+.in -8
+};
+.fi
+.PP
+Each QP Transport Service Type supports a specific set of opcodes, as shown in the following table:
+.PP
+.nf
+OPCODE                      | IBV_QPT_UD | IBV_QPT_UC | IBV_QPT_RC
+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-
+IBV_WR_SEND                 |     X      |     X      |     X
+IBV_WR_SEND_WITH_IMM        |     X      |     X      |     X
+IBV_WR_RDMA_WRITE           |            |     X      |     X
+IBV_WR_RDMA_WRITE_WITH_IMM  |            |     X      |     X
+IBV_WR_RDMA_READ            |            |            |     X
+IBV_WR_ATOMIC_CMP_AND_SWP   |            |            |     X
+IBV_WR_ATOMIC_FETCH_AND_ADD |            |            |     X
+.fi
+.PP
+The attribute send_flags describes the properties of the \s-1WR\s0. It is either 0 or the bitwise \s-1OR\s0 of one or more of the following flags:
+.PP
+.TP
+.B IBV_SEND_FENCE \fR Set the fence indicator.  Valid only for QPs with Transport Service Type \fBIBV_QPT_RC
+.TP
+.B IBV_SEND_SIGNALED \fR Set the completion notification indicator.  Relevant only if QP was created with sq_sig_all=0
+.TP
+.B IBV_SEND_SOLICITED \fR Set the solicited event indicator.  Valid only for Send and RDMA Write with immediate
+.TP
+.B IBV_SEND_INLINE \fR Send data in given gather list as inline data
+in a send WQE.  Valid only for Send and RDMA Write.  The L_Key will not be checked.
+.SH "RETURN VALUE"
+.B ibv_post_send()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "NOTES"
+The user should not alter or destroy AHs associated with WRs until
+request is fully executed and a work completion has been retrieved
+from the corresponding completion queue (CQ) to avoid unexpected
+behavior.
+.PP
+The buffers used by a WR can only be safely reused after WR the
+request is fully executed and a work completion has been retrieved
+from the corresponding completion queue (CQ).
+.SH "SEE ALSO"
+.BR ibv_create_qp (3),
+.BR ibv_create_ah (3),
+.BR ibv_post_recv (3),
+.BR ibv_post_srq_recv (3),
+.BR ibv_poll_cq (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_post_srq_recv.3 b/man/ibv_post_srq_recv.3
new file mode 100644
index 0000000..c7e2302
--- /dev/null
+++ b/man/ibv_post_srq_recv.3
@@ -0,0 +1,61 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_POST_SRQ_RECV 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_post_srq_recv \- post a list of work requests (WRs) to a shared receive queue (SRQ)
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_post_srq_recv(struct ibv_srq " "*srq" ", struct ibv_recv_wr " "*wr" ,
+.BI "                      struct ibv_recv_wr " "**bad_wr" );
+.fi
+.SH "DESCRIPTION"
+.B ibv_post_srq_recv()
+posts the linked list of work requests (WRs) starting with
+.I wr
+to the shared receive queue (SRQ)
+.I srq\fR.
+It stops processing WRs from this list at the first failure (that can
+be detected immediately while requests are being posted), and returns
+this failing WR through
+.I bad_wr\fR.
+.PP
+The argument
+.I wr
+is an ibv_recv_wr struct, as defined in <infiniband/verbs.h>.
+.PP
+.nf
+struct ibv_recv_wr {
+.in +8
+uint64_t                wr_id;     /* User defined WR ID */
+struct ibv_recv_wr     *next;      /* Pointer to next WR in list, NULL if last WR */
+struct ibv_sge         *sg_list;   /* Pointer to the s/g array */
+int                     num_sge;   /* Size of the s/g array */
+.in -8
+};
+.sp
+.nf
+struct ibv_sge {
+.in +8
+uint64_t                addr;      /* Start address of the local memory buffer */
+uint32_t                length;    /* Length of the buffer */
+uint32_t                lkey;      /* Key of the local Memory Region */
+.in -8
+};
+.fi
+.SH "RETURN VALUE"
+.B ibv_post_srq_recv()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "NOTES"
+The buffers used by a WR can only be safely reused after WR the
+request is fully executed and a work completion has been retrieved
+from the corresponding completion queue (CQ).
+.SH "SEE ALSO"
+.BR ibv_create_qp (3),
+.BR ibv_post_send (3),
+.BR ibv_post_recv (3),
+.BR ibv_poll_cq (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_query_device.3 b/man/ibv_query_device.3
new file mode 100644
index 0000000..344f5b3
--- /dev/null
+++ b/man/ibv_query_device.3
@@ -0,0 +1,84 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_QUERY_DEVICE 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_query_device \- query an InfiniBand device's attributes
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_query_device(struct ibv_context " "*context",
+.BI "                     struct ibv_device_attr " "*device_attr" );
+.fi
+.SH "DESCRIPTION"
+.B ibv_query_device()
+returns the attributes of the device with context
+.I context\fR.
+The argument
+.I device_attr
+is a pointer to an ibv_device_attr struct, as defined in <infiniband/verbs.h>.
+.PP
+.nf
+struct ibv_device_attr {
+.in +8
+char                    fw_ver[64];             /* FW version */
+uint64_t                node_guid;              /* Node GUID */
+uint64_t                sys_image_guid;         /* System image GUID */
+uint64_t                max_mr_size;            /* Largest contiguous block that can be registered */
+uint64_t                page_size_cap;          /* Supported memory shift sizes */
+uint32_t                vendor_id;              /* Vendor ID, per IEEE */
+uint32_t                vendor_part_id;         /* Vendor supplied part ID */
+uint32_t                hw_ver;                 /* Hardware version */
+int                     max_qp;                 /* Maximum number of supported QPs */
+int                     max_qp_wr;              /* Maximum number of outstanding WR on any work queue */
+int                     device_cap_flags;       /* HCA capabilities mask */
+int                     max_sge;                /* Maximum number of s/g per WR for non-RD QPs */
+int                     max_sge_rd;             /* Maximum number of s/g per WR for RD QPs */
+int                     max_cq;                 /* Maximum number of supported CQs */
+int                     max_cqe;                /* Maximum number of CQE capacity per CQ */
+int                     max_mr;                 /* Maximum number of supported MRs */
+int                     max_pd;                 /* Maximum number of supported PDs */
+int                     max_qp_rd_atom;         /* Maximum number of RDMA Read & Atomic operations that can be outstanding per QP */
+int                     max_ee_rd_atom;         /* Maximum number of RDMA Read & Atomic operations that can be outstanding per EEC */
+int                     max_res_rd_atom;        /* Maximum number of resources used for RDMA Read & Atomic operations by this HCA as the Target */
+int                     max_qp_init_rd_atom;    /* Maximum depth per QP for initiation of RDMA Read & Atomic operations */ 
+int                     max_ee_init_rd_atom;    /* Maximum depth per EEC for initiation of RDMA Read & Atomic operations */
+enum ibv_atomic_cap     atomic_cap;             /* Atomic operations support level */
+int                     max_ee;                 /* Maximum number of supported EE contexts */
+int                     max_rdd;                /* Maximum number of supported RD domains */
+int                     max_mw;                 /* Maximum number of supported MWs */
+int                     max_raw_ipv6_qp;        /* Maximum number of supported raw IPv6 datagram QPs */
+int                     max_raw_ethy_qp;        /* Maximum number of supported Ethertype datagram QPs */
+int                     max_mcast_grp;          /* Maximum number of supported multicast groups */
+int                     max_mcast_qp_attach;    /* Maximum number of QPs per multicast group which can be attached */
+int                     max_total_mcast_qp_attach;/* Maximum number of QPs which can be attached to multicast groups */
+int                     max_ah;                 /* Maximum number of supported address handles */
+int                     max_fmr;                /* Maximum number of supported FMRs */
+int                     max_map_per_fmr;        /* Maximum number of (re)maps per FMR before an unmap operation in required */
+int                     max_srq;                /* Maximum number of supported SRQs */
+int                     max_srq_wr;             /* Maximum number of WRs per SRQ */
+int                     max_srq_sge;            /* Maximum number of s/g per SRQ */
+uint16_t                max_pkeys;              /* Maximum number of partitions */
+uint8_t                 local_ca_ack_delay;     /* Local CA ack delay */
+uint8_t                 phys_port_cnt;          /* Number of physical ports */
+.in -8
+};
+.fi
+.SH "RETURN VALUE"
+.B ibv_query_device()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "NOTES"
+The maximum values returned by this function are the upper limits of
+supported resources by the device.  However, it may not be possible to
+use these maximum values, since the actual number of any resource that
+can be created may be limited by the machine configuration, the amount
+of host memory, user permissions, and the amount of resources already
+in use by other users/processes.
+.SH "SEE ALSO"
+.BR ibv_open_device (3),
+.BR ibv_query_port (3),
+.BR ibv_query_pkey (3),
+.BR ibv_query_gid (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_query_gid.3 b/man/ibv_query_gid.3
new file mode 100644
index 0000000..df3ac10
--- /dev/null
+++ b/man/ibv_query_gid.3
@@ -0,0 +1,33 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_QUERY_GID 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_query_gid \- query an InfiniBand port's GID table
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_query_gid(struct ibv_context " "*context" ", uint8_t " "port_num" ,
+.BI "                  int " "index" ", union ibv_gid " "*gid" );
+.fi
+.SH "DESCRIPTION"
+.B ibv_query_gid()
+returns the GID value in entry
+.I index
+of port
+.I port_num
+for device context
+.I context
+through the pointer
+.I gid\fR.
+.SH "RETURN VALUE"
+.B ibv_query_gid()
+returns 0 on success, and \-1 on error.
+.SH "SEE ALSO"
+.BR ibv_open_device (3),
+.BR ibv_query_device (3),
+.BR ibv_query_port (3),
+.BR ibv_query_pkey (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_query_pkey.3 b/man/ibv_query_pkey.3
new file mode 100644
index 0000000..37c408d
--- /dev/null
+++ b/man/ibv_query_pkey.3
@@ -0,0 +1,33 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_QUERY_PKEY 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_query_pkey \- query an InfiniBand port's P_Key table
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_query_pkey(struct ibv_context " "*context" ", uint8_t " "port_num" ,
+.BI "                   int " "index" ", uint16_t " "*pkey" ");
+.fi
+.SH "DESCRIPTION"
+.B ibv_query_pkey()
+returns the P_Key value in entry
+.I index
+of port
+.I port_num
+for device context
+.I context
+through the pointer
+.I pkey\fR.
+.SH "RETURN VALUE"
+.B ibv_query_pkey()
+returns 0 on success, and -1 on error.
+.SH "SEE ALSO"
+.BR ibv_open_device (3),
+.BR ibv_query_device (3),
+.BR ibv_query_port (3),
+.BR ibv_query_gid (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_query_port.3 b/man/ibv_query_port.3
new file mode 100644
index 0000000..fd61eb9
--- /dev/null
+++ b/man/ibv_query_port.3
@@ -0,0 +1,61 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_QUERY_PORT 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_query_port \- query an InfiniBand port's attributes
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_query_port(struct ibv_context " "*context" ", uint8_t " "port_num" ,
+.BI "                   struct ibv_port_attr " "*port_attr" ");
+.fi
+.SH "DESCRIPTION"
+.B ibv_query_port()
+returns the attributes of port
+.I port_num
+for device context
+.I context
+through the pointer
+.I port_attr\fR.
+The argument
+.I port_attr
+is an ibv_port_attr struct, as defined in <infiniband/verbs.h>.
+.PP
+.nf
+struct ibv_port_attr {
+.in +8
+enum ibv_port_state     state;          /* Logical port state */
+enum ibv_mtu            max_mtu;        /* Max MTU supported by port */
+enum ibv_mtu            active_mtu;     /* Actual MTU */
+int                     gid_tbl_len;    /* Length of source GID table */
+uint32_t                port_cap_flags; /* Port capabilities */
+uint32_t                max_msg_sz;     /* Maximum message size */
+uint32_t                bad_pkey_cntr;  /* Bad P_Key counter */
+uint32_t                qkey_viol_cntr; /* Q_Key violation counter */
+uint16_t                pkey_tbl_len;   /* Length of partition table */
+uint16_t                lid;            /* Base port LID */
+uint16_t                sm_lid;         /* SM LID */
+uint8_t                 lmc;            /* LMC of LID */
+uint8_t                 max_vl_num;     /* Maximum number of VLs */
+uint8_t                 sm_sl;          /* SM service level */
+uint8_t                 subnet_timeout; /* Subnet propagation delay */
+uint8_t                 init_type_reply;/* Type of initialization performed by SM */
+uint8_t                 active_width;   /* Currently active link width */
+uint8_t                 active_speed;   /* Currently active link speed */
+uint8_t                 phys_state;     /* Physical port state */
+.in -8
+};
+.sp
+.fi
+.SH "RETURN VALUE"
+.B ibv_query_port()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "SEE ALSO"
+.BR ibv_create_qp (3),
+.BR ibv_destroy_qp (3),
+.BR ibv_query_qp (3),
+.BR ibv_create_ah (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_query_qp.3 b/man/ibv_query_qp.3
new file mode 100644
index 0000000..fd1f41d
--- /dev/null
+++ b/man/ibv_query_qp.3
@@ -0,0 +1,88 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_QUERY_QP 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_query_qp \- get the attributes of a queue pair (QP)
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_query_qp(struct ibv_qp " "*qp" ", struct ibv_qp_attr " "*attr" ,
+.BI "                 enum ibv_qp_attr_mask " "attr_mask" ,
+.BI "                 struct ibv_qp_init_attr " "*init_attr" );
+.fi
+.SH "DESCRIPTION"
+.B ibv_query_qp()
+gets the attributes specified in
+.I attr_mask
+for the QP
+.I qp
+and returns them through the pointers
+.I attr
+and
+.I init_attr\fR.
+The argument
+.I attr
+is an ibv_qp_attr struct, as defined in <infiniband/verbs.h>.
+.PP
+.nf
+struct ibv_qp_attr {
+.in +8
+enum ibv_qp_state       qp_state;            /* Current QP state */
+enum ibv_qp_state       cur_qp_state;        /* Current QP state - irrelevant for ibv_query_qp */
+enum ibv_mtu            path_mtu;            /* Path MTU (valid only for RC/UC QPs) */
+enum ibv_mig_state      path_mig_state;      /* Path migration state (valid if HCA supports APM) */
+uint32_t                qkey;                /* Q_Key of the QP (valid only for UD QPs) */
+uint32_t                rq_psn;              /* PSN for receive queue (valid only for RC/UC QPs) */
+uint32_t                sq_psn;              /* PSN for send queue (valid only for RC/UC QPs) */
+uint32_t                dest_qp_num;         /* Destination QP number (valid only for RC/UC QPs) */
+int                     qp_access_flags;     /* Mask of enabled remote access operations (valid only for RC/UC QPs) */
+struct ibv_qp_cap       cap;                 /* QP capabilities */
+struct ibv_ah_attr      ah_attr;             /* Primary path address vector (valid only for RC/UC QPs) */
+struct ibv_ah_attr      alt_ah_attr;         /* Alternate path address vector (valid only for RC/UC QPs) */
+uint16_t                pkey_index;          /* Primary P_Key index */
+uint16_t                alt_pkey_index;      /* Alternate P_Key index */
+uint8_t                 en_sqd_async_notify; /* Enable SQD.drained async notification - irrelevant for ibv_query_qp */
+uint8_t                 sq_draining;         /* Is the QP draining? (Valid only if qp_state is SQD) */
+uint8_t                 max_rd_atomic;       /* Number of outstanding RDMA reads & atomic operations on the destination QP (valid only for RC QPs) */
+uint8_t                 max_dest_rd_atomic;  /* Number of responder resources for handling incoming RDMA reads & atomic operations (valid only for RC QPs) */
+uint8_t                 min_rnr_timer;       /* Minimum RNR NAK timer (valid only for RC QPs) */
+uint8_t                 port_num;            /* Primary port number */
+uint8_t                 timeout;             /* Local ack timeout for primary path (valid only for RC QPs) */
+uint8_t                 retry_cnt;           /* Retry count (valid only for RC QPs) */
+uint8_t                 rnr_retry;           /* RNR retry (valid only for RC QPs) */
+uint8_t                 alt_port_num;        /* Alternate port number */
+uint8_t                 alt_timeout;         /* Local ack timeout for alternate path (valid only for RC QPs) */
+.in -8
+};
+.fi
+.PP
+For details on struct ibv_qp_cap see the description of
+.B ibv_create_qp()\fR.
+For details on struct ibv_ah_attr see the description of
+.B ibv_create_ah()\fR.
+.SH "RETURN VALUE"
+.B ibv_query_qp()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "NOTES"
+The argument
+.I attr_mask
+is a hint that specifies the minimum list of attributes to retrieve.
+Some InfiniBand devices may return extra attributes not requested, for
+example if the value can be returned cheaply.
+.PP
+Attribute values are valid if they have been set using
+.B ibv_modify_qp()\fR.
+The exact list of valid attributes depends on the QP state.
+.PP
+Multiple calls to
+.B ibv_query_qp()
+may yield some differences in the values returned for the following attributes: qp_state, path_mig_state, sq_draining, ah_attr (if APM is enabled).
+.SH "SEE ALSO"
+.BR ibv_create_qp (3),
+.BR ibv_destroy_qp (3),
+.BR ibv_modify_qp (3),
+.BR ibv_create_ah (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_query_srq.3 b/man/ibv_query_srq.3
new file mode 100644
index 0000000..56db4fa
--- /dev/null
+++ b/man/ibv_query_srq.3
@@ -0,0 +1,44 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_QUERY_SRQ 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_query_srq \- get the attributes of a shared receive queue (SRQ)
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_query_srq(struct ibv_srq " "*srq" ", struct ibv_srq_attr " "*srq_attr" );
+.fi
+.SH "DESCRIPTION"
+.B ibv_query_srq()
+gets the attributes of the SRQ
+.I srq
+and returns them through the pointer
+.I srq_attr\fR.
+The argument
+.I srq_attr
+is an ibv_srq_attr struct, as defined in <infiniband/verbs.h>.
+.PP
+.nf
+struct ibv_srq_attr {
+.in +8
+uint32_t                max_wr;         /* maximum number of outstanding work requests (WRs) in the SRQ */
+uint32_t                max_sge;        /* maximum number of scatter elements per WR */
+uint32_t                srq_limit;      /* the limit value of the SRQ */
+.in -8
+};
+.fi
+.SH "RETURN VALUE"
+.B ibv_query_srq()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "NOTES"
+If the value returned for srq_limit is 0, then the SRQ limit reached
+("low watermark") event is not (or no longer) armed, and no
+asynchronous events will be generated until the event is rearmed.
+.SH "SEE ALSO"
+.BR ibv_create_srq (3),
+.BR ibv_destroy_srq (3),
+.BR ibv_modify_srq (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_rate_to_mult.3 b/man/ibv_rate_to_mult.3
new file mode 100644
index 0000000..cf009bf
--- /dev/null
+++ b/man/ibv_rate_to_mult.3
@@ -0,0 +1,46 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_RATE_TO_MULT 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+.nf
+ibv_rate_to_mult \- convert IB rate enumeration to multiplier of 2.5 Gbit/sec
+.nl
+ibv_mult_to_rate \- convert multiplier of 2.5 Gbit/sec to an IB rate enumeration
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_rate_to_mult(enum ibv_rate " "rate" ");
+.nl
+.BI "enum ibv_rate mult_to_ibv_rate(int " "mult" ");
+.fi
+.SH "DESCRIPTION"
+.B ibv_rate_to_mult()
+converts the IB transmission rate enumeration
+.I rate
+to a multiple of 2.5 Gbit/sec (the base rate). For example, if
+.I rate
+is
+.BR IBV_RATE_5_GBPS\fR,
+the value 2 will be returned (5 Gbit/sec = 2 * 2.5 Gbit/sec).
+.PP
+.B mult_to_ibv_rate()
+converts the multiplier value (of 2.5 Gbit/sec)
+.I mult
+to an IB transmission rate enumeration. For example, if
+.I mult
+is 2, the rate enumeration
+.BR IBV_RATE_5_GBPS
+will be returned.
+.SH "RETURN VALUE"
+.B
+ibv_rate_to_mult()
+returns the multiplier of the base rate 2.5 Gbit/sec.
+.PP
+.B mult_to_ibv_rate()
+returns the enumeration representing the IB transmission rate.
+.SH "SEE ALSO"
+.BR ibv_query_port (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_rc_pingpong.1 b/man/ibv_rc_pingpong.1
index b9b2fdc..e83d635 100644
--- a/man/ibv_rc_pingpong.1
+++ b/man/ibv_rc_pingpong.1
@@ -23,22 +23,22 @@ connected (RC) transport.
 .TP
 \fB\-p\fR, \fB\-\-port\fR=\fIPORT\fR
 use TCP port \fIPORT\fR for initial synchronization (default 18515)
-
+.TP
 \fB\-d\fR, \fB\-\-ib\-dev\fR=\fIDEVICE\fR
 use IB device \fIDEVICE\fR (default first device found)
-
+.TP
 \fB\-i\fR, \fB\-\-ib\-port\fR=\fIPORT\fR
 use IB port \fIPORT\fR (default port 1)
-
+.TP
 \fB\-s\fR, \fB\-\-size\fR=\fISIZE\fR
 ping-pong messages of size \fISIZE\fR (default 4096)
-
+.TP
 \fB\-r\fR, \fB\-\-rx\-depth\fR=\fIDEPTH\fR
 post \fIDEPTH\fR receives at a time (default 1000)
-
+.TP
 \fB\-n\fR, \fB\-\-iters\fR=\fIITERS\fR
 perform \fIITERS\fR message exchanges (default 1000)
-
+.Tp
 \fB\-e\fR, \fB\-\-events\fR
 sleep while waiting for work completion events (default is to poll for
 completions)
diff --git a/man/ibv_reg_mr.3 b/man/ibv_reg_mr.3
new file mode 100644
index 0000000..bd2387b
--- /dev/null
+++ b/man/ibv_reg_mr.3
@@ -0,0 +1,77 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_REG_MR 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_reg_mr, ibv_dereg_mr \- register or deregister a memory region (MR)
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "struct ibv_mr *ibv_reg_mr(struct ibv_pd " "*pd" ", void " "*addr" ,
+.BI "                          size_t " "length" ,
+.BI "                          enum ibv_access_flags " "access" );
+.nl
+.BI "int ibv_dereg_mr(struct ibv_mr " "*mr" );
+.fi
+.SH "DESCRIPTION"
+.B ibv_reg_mr()
+registers a memory region (MR) associated with the protection domain
+.I pd\fR.
+The MR's starting address is
+.I addr
+and its size is
+.I length\fR.
+The argument
+.I access
+describes the desired memory protection attributes; it is either 0 or the bitwise OR of one or more of the following flags:
+.PP
+.TP
+.B IBV_ACCESS_LOCAL_WRITE \fR  Enable Local Write Access
+.TP
+.B IBV_ACCESS_REMOTE_WRITE \fR Enable Remote Write Access
+.TP
+.B IBV_ACCESS_REMOTE_READ\fR   Enable Remote Read Access
+.TP
+.B IBV_ACCESS_REMOTE_ATOMIC\fR Enable Remote Atomic Operation Access (if supported)
+.TP
+.B IBV_ACCESS_MW_BIND\fR       Enable Memory Window Binding
+.PP
+If
+.B IBV_ACCESS_REMOTE_WRITE
+or
+.B IBV_ACCESS_REMOTE_ATOMIC
+is set, then
+.B IBV_ACCESS_LOCAL_WRITE
+must be set too.
+.PP
+Local read access is always enabled for the MR.
+.PP
+.B ibv_dereg_mr()
+deregisters the MR
+.I mr\fR.
+.SH "RETURN VALUE"
+.B ibv_reg_mr()
+returns a pointer to the registered MR, or NULL if the request fails.
+The local key (\fBL_Key\fR) field
+.B lkey
+is used as the lkey field of struct ibv_sge when posting buffers with
+ibv_post_* verbs, and the the remote key (\fBR_Key\fR)
+field
+.B rkey
+is used by remote processes to perform Atomic and RDMA operations.  The remote process places this
+.B rkey
+as the rkey field of struct ibv_send_wr passed to the ibv_post_send function.
+.PP
+.B ibv_dereg_mr()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "NOTES"
+.B ibv_dereg_mr()
+fails if any memory window is still bound to this MR.
+.SH "SEE ALSO"
+.BR ibv_alloc_pd (3),
+.BR ibv_post_send (3),
+.BR ibv_post_recv (3),
+.BR ibv_post_srq_recv (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_req_notify_cq.3 b/man/ibv_req_notify_cq.3
new file mode 100644
index 0000000..eda5801
--- /dev/null
+++ b/man/ibv_req_notify_cq.3
@@ -0,0 +1,43 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_REQ_NOTIFY_CQ 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_req_notify_cq \- request completion notification on a completion queue (CQ)
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_req_notify_cq(struct ibv_cq " "*cq" ", int " "solicited_only" ");
+.SH "DESCRIPTION"
+.B ibv_req_notify_cq()
+requests a completion notification on the completion queue (CQ)
+.I cq\fR.
+.PP
+Upon the addition of a new CQ entry (CQE) to
+.I cq\fR,
+a completion event will be added to the completion channel associated
+with the CQ.
+If the argument
+.I solicited_only
+is zero, a completion event is generated for any new CQE.  If 
+.I solicited_only
+is non\-zero, an event is only generated for a new CQE with that is
+considered "solicited."  A CQE is solicited if it is a receive
+completion for a message with the Solicited Event header bit set, or
+if the status is not successful.  All other successful receive
+completions, or any successful send completion is unsolicited.
+.SH "RETURN VALUE"
+.B 
+ibv_req_notify_cq()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "NOTES"
+The request for notification is "one shot."  Only one completion event
+will be generated for each call to
+.B ibv_req_notify_cq()\fR.
+.SH "SEE ALSO"
+.BR ibv_create_comp_channel (3),
+.BR ibv_create_cq (3),
+.BR ibv_get_cq_event (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_resize_cq.3 b/man/ibv_resize_cq.3
new file mode 100644
index 0000000..0563f56
--- /dev/null
+++ b/man/ibv_resize_cq.3
@@ -0,0 +1,42 @@
+.\" -*- nroff -*-
+.\"
+.TH IBV_RESIZE_CQ 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_resize_cq \- resize a completion queue (CQ)
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_resize_cq(struct ibv_cq " "*cq" ", int " "cqe" ");
+.fi
+.SH "DESCRIPTION"
+.B ibv_resize_cq()
+resizes the completion queue (CQ)
+.I cq
+to have at least
+.I cqe
+entries.
+.I cqe
+must be at least the number of unpolled entries in the CQ
+.I cq\fR.
+If
+.I cqe
+is a valid value less than the current CQ size,
+.B ibv_resize_cq()
+may not do anything, since this function is only guaranteed to resize
+the CQ to a size at least as big as the requested size.
+.SH "RETURN VALUE"
+.B ibv_resize_cq()
+returns 0 on success, or the value of errno on failure (which indicates the failure reason).
+.SH "NOTES"
+.B ibv_resize_cq()
+may assign a CQ size greater than or equal to the requested size.
+The cqe member of
+.I cq
+will be updated to the actual size.
+.SH "SEE ALSO"
+.BR ibv_create_cq (3)
+.BR ibv_destroy_cq (3)
+.SH "AUTHORS"
+.TP
+Dotan Barak <dotanb at mellanox.co.il>
diff --git a/man/ibv_srq_pingpong.1 b/man/ibv_srq_pingpong.1
index 998282e..3624c6b 100644
--- a/man/ibv_srq_pingpong.1
+++ b/man/ibv_srq_pingpong.1
@@ -24,25 +24,25 @@ single shared receive queue (SRQ).
 .TP
 \fB\-p\fR, \fB\-\-port\fR=\fIPORT\fR
 use TCP port \fIPORT\fR for initial synchronization (default 18515)
-
+.TP
 \fB\-d\fR, \fB\-\-ib\-dev\fR=\fIDEVICE\fR
 use IB device \fIDEVICE\fR (default first device found)
-
+.TP
 \fB\-i\fR, \fB\-\-ib\-port\fR=\fIPORT\fR
 use IB port \fIPORT\fR (default port 1)
-
+.TP
 \fB\-s\fR, \fB\-\-size\fR=\fISIZE\fR
 ping-pong messages of size \fISIZE\fR (default 4096)
-
+.TP
 \fB\-q\fR, \fB\-\-num\-qp\fR=\fINUM\fR
 use \fINUM\fR queue pairs for test (default 16)
-
+.TP
 \fB\-r\fR, \fB\-\-rx\-depth\fR=\fIDEPTH\fR
 post \fIDEPTH\fR receives at a time (default 1000)
-
+.TP
 \fB\-n\fR, \fB\-\-iters\fR=\fIITERS\fR
 perform \fIITERS\fR message exchanges (default 1000)
-
+.TP
 \fB\-e\fR, \fB\-\-events\fR
 sleep while waiting for work completion events (default is to poll for
 completions)
diff --git a/man/ibv_uc_pingpong.1 b/man/ibv_uc_pingpong.1
index b02aaaa..6b535dc 100644
--- a/man/ibv_uc_pingpong.1
+++ b/man/ibv_uc_pingpong.1
@@ -23,22 +23,22 @@ connected (RC) transport.
 .TP
 \fB\-p\fR, \fB\-\-port\fR=\fIPORT\fR
 use TCP port \fIPORT\fR for initial synchronization (default 18515)
-
+.TP
 \fB\-d\fR, \fB\-\-ib\-dev\fR=\fIDEVICE\fR
 use IB device \fIDEVICE\fR (default first device found)
-
+.TP
 \fB\-i\fR, \fB\-\-ib\-port\fR=\fIPORT\fR
 use IB port \fIPORT\fR (default port 1)
-
+.TP
 \fB\-s\fR, \fB\-\-size\fR=\fISIZE\fR
 ping-pong messages of size \fISIZE\fR (default 4096)
-
+.TP
 \fB\-r\fR, \fB\-\-rx\-depth\fR=\fIDEPTH\fR
 post \fIDEPTH\fR receives at a time (default 1000)
-
+.TP
 \fB\-n\fR, \fB\-\-iters\fR=\fIITERS\fR
 perform \fIITERS\fR message exchanges (default 1000)
-
+.TP
 \fB\-e\fR, \fB\-\-events\fR
 sleep while waiting for work completion events (default is to poll for
 completions)
diff --git a/man/ibv_ud_pingpong.1 b/man/ibv_ud_pingpong.1
index 68c5b88..e5c0faa 100644
--- a/man/ibv_ud_pingpong.1
+++ b/man/ibv_ud_pingpong.1
@@ -23,22 +23,22 @@ datagram (UD) transport.
 .TP
 \fB\-p\fR, \fB\-\-port\fR=\fIPORT\fR
 use TCP port \fIPORT\fR for initial synchronization (default 18515)
-
+.TP
 \fB\-d\fR, \fB\-\-ib\-dev\fR=\fIDEVICE\fR
 use IB device \fIDEVICE\fR (default first device found)
-
+.TP
 \fB\-i\fR, \fB\-\-ib\-port\fR=\fIPORT\fR
 use IB port \fIPORT\fR (default port 1)
-
+.TP
 \fB\-s\fR, \fB\-\-size\fR=\fISIZE\fR
 ping-pong messages of size \fISIZE\fR (default 2048)
-
+.TP
 \fB\-r\fR, \fB\-\-rx\-depth\fR=\fIDEPTH\fR
 post \fIDEPTH\fR receives at a time (default 500)
-
+.TP
 \fB\-n\fR, \fB\-\-iters\fR=\fIITERS\fR
 perform \fIITERS\fR message exchanges (default 1000)
-
+.TP
 \fB\-e\fR, \fB\-\-events\fR
 sleep while waiting for work completion events (default is to poll for
 completions)
diff --git a/src/cmd.c b/src/cmd.c
index 5e5efe9..a0bfaad 100644
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 PathScale, Inc.  All rights reserved.
- * Copyright (c) 2006 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2006 Cisco Systems, Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -30,8 +30,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: cmd.c 10015 2006-10-31 15:52:42Z roland $
  */
 
 #if HAVE_CONFIG_H
@@ -43,6 +41,7 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <alloca.h>
+#include <string.h>
 
 #include "ibverbs.h"
 
@@ -76,7 +75,9 @@ static int ibv_cmd_get_context_v2(struct ibv_context *context,
 
 	context->async_fd         = resp->async_fd;
 	context->num_comp_vectors = 1;
+	t->channel.context        = context;
 	t->channel.fd		  = cq_fd;
+	t->channel.refcnt	  = 0;
 	context->abi_compat       = t;
 
 	return 0;
@@ -210,7 +211,8 @@ int ibv_cmd_alloc_pd(struct ibv_context *context, struct ibv_pd *pd,
 
 	VALGRIND_MAKE_MEM_DEFINED(resp, resp_size);
 
-	pd->handle = resp->pd_handle;
+	pd->handle  = resp->pd_handle;
+	pd->context = context;
 
 	return 0;
 }
@@ -231,11 +233,11 @@ int ibv_cmd_dealloc_pd(struct ibv_pd *pd)
 int ibv_cmd_reg_mr(struct ibv_pd *pd, void *addr, size_t length,
 		   uint64_t hca_va, enum ibv_access_flags access,
 		   struct ibv_mr *mr, struct ibv_reg_mr *cmd,
-		   size_t cmd_size)
+		   size_t cmd_size,
+		   struct ibv_reg_mr_resp *resp, size_t resp_size)
 {
-	struct ibv_reg_mr_resp resp;
 
-	IBV_INIT_CMD_RESP(cmd, cmd_size, REG_MR, &resp, sizeof resp);
+	IBV_INIT_CMD_RESP(cmd, cmd_size, REG_MR, resp, resp_size);
 
 	cmd->start 	  = (uintptr_t) addr;
 	cmd->length 	  = length;
@@ -248,9 +250,10 @@ int ibv_cmd_reg_mr(struct ibv_pd *pd, void *addr, size_t length,
 
 	VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp);
 
-	mr->handle  = resp.mr_handle;
-	mr->lkey    = resp.lkey;
-	mr->rkey    = resp.rkey;
+	mr->handle  = resp->mr_handle;
+	mr->lkey    = resp->lkey;
+	mr->rkey    = resp->rkey;
+	mr->context = pd->context;
 
 	return 0;
 }
@@ -290,8 +293,9 @@ static int ibv_cmd_create_cq_v2(struct ibv_context *context, int cqe,
 
 	VALGRIND_MAKE_MEM_DEFINED(resp, sizeof resp_size);
 
-	cq->handle = resp->cq_handle;
-	cq->cqe    = resp->cqe;
+	cq->handle  = resp->cq_handle;
+	cq->cqe     = resp->cqe;
+	cq->context = context;
 
 	return 0;
 }
@@ -318,8 +322,9 @@ int ibv_cmd_create_cq(struct ibv_context *context, int cqe,
 
 	VALGRIND_MAKE_MEM_DEFINED(resp, resp_size);
 
-	cq->handle = resp->cq_handle;
-	cq->cqe    = resp->cqe;
+	cq->handle  = resp->cq_handle;
+	cq->cqe     = resp->cqe;
+	cq->context = context;
 
 	return 0;
 }
@@ -386,20 +391,20 @@ int ibv_cmd_req_notify_cq(struct ibv_cq *ibcq, int solicited_only)
 }
 
 int ibv_cmd_resize_cq(struct ibv_cq *cq, int cqe,
-		      struct ibv_resize_cq *cmd, size_t cmd_size)
+		      struct ibv_resize_cq *cmd, size_t cmd_size,
+		      struct ibv_resize_cq_resp *resp, size_t resp_size)
 {
-	struct ibv_resize_cq_resp resp;
 
-	IBV_INIT_CMD_RESP(cmd, cmd_size, RESIZE_CQ, &resp, sizeof resp);
+	IBV_INIT_CMD_RESP(cmd, cmd_size, RESIZE_CQ, resp, resp_size);
 	cmd->cq_handle = cq->handle;
 	cmd->cqe       = cqe;
 
 	if (write(cq->context->cmd_fd, cmd, cmd_size) != cmd_size)
 		return errno;
 
-	VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp);
+	VALGRIND_MAKE_MEM_DEFINED(resp, resp_size);
 
-	cq->cqe = resp.cqe;
+	cq->cqe = resp->cqe;
 
 	return 0;
 }
@@ -459,7 +464,8 @@ int ibv_cmd_create_srq(struct ibv_pd *pd,
 
 	VALGRIND_MAKE_MEM_DEFINED(resp, resp_size);
 
-	srq->handle = resp->srq_handle;
+	srq->handle  = resp->srq_handle;
+	srq->context = pd->context;
 
 	if (abi_ver > 5) {
 		attr->attr.max_wr = resp->max_wr;
@@ -608,6 +614,7 @@ int ibv_cmd_create_qp(struct ibv_pd *pd,
 
 	qp->handle 		  = resp->qp_handle;
 	qp->qp_num 		  = resp->qpn;
+	qp->context		  = pd->context;
 
 	if (abi_ver > 3) {
 		attr->cap.max_recv_sge    = resp->max_recv_sge;
@@ -1026,7 +1033,8 @@ int ibv_cmd_create_ah(struct ibv_pd *pd, struct ibv_ah *ah,
 
 	VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp);
 
-	ah->handle = resp.handle;
+	ah->handle  = resp.handle;
+	ah->context = pd->context;
 
 	return 0;
 }
diff --git a/src/compat-1_0.c b/src/compat-1_0.c
new file mode 100644
index 0000000..459ade9
--- /dev/null
+++ b/src/compat-1_0.c
@@ -0,0 +1,898 @@
+/*
+ * Copyright (c) 2007 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <alloca.h>
+
+#include "ibverbs.h"
+
+struct ibv_pd_1_0 {
+	struct ibv_context_1_0 *context;
+	uint32_t		handle;
+
+	struct ibv_pd	       *real_pd;
+};
+
+struct ibv_mr_1_0 {
+	struct ibv_context_1_0 *context;
+	struct ibv_pd_1_0      *pd;
+	uint32_t		handle;
+	uint32_t		lkey;
+	uint32_t		rkey;
+
+	struct ibv_mr	       *real_mr;
+};
+
+struct ibv_srq_1_0 {
+	struct ibv_context_1_0 *context;
+	void		       *srq_context;
+	struct ibv_pd_1_0      *pd;
+	uint32_t		handle;
+
+	pthread_mutex_t		mutex;
+	pthread_cond_t		cond;
+	uint32_t		events_completed;
+
+	struct ibv_srq	       *real_srq;
+};
+
+struct ibv_qp_init_attr_1_0 {
+	void		       *qp_context;
+	struct ibv_cq_1_0      *send_cq;
+	struct ibv_cq_1_0      *recv_cq;
+	struct ibv_srq_1_0     *srq;
+	struct ibv_qp_cap	cap;
+	enum ibv_qp_type	qp_type;
+	int			sq_sig_all;
+};
+
+struct ibv_send_wr_1_0 {
+	struct ibv_send_wr_1_0 *next;
+	uint64_t		wr_id;
+	struct ibv_sge	       *sg_list;
+	int			num_sge;
+	enum ibv_wr_opcode	opcode;
+	enum ibv_send_flags	send_flags;
+	uint32_t		imm_data;	/* in network byte order */
+	union {
+		struct {
+			uint64_t	remote_addr;
+			uint32_t	rkey;
+		} rdma;
+		struct {
+			uint64_t	remote_addr;
+			uint64_t	compare_add;
+			uint64_t	swap;
+			uint32_t	rkey;
+		} atomic;
+		struct {
+			struct ibv_ah_1_0 *ah;
+			uint32_t	remote_qpn;
+			uint32_t	remote_qkey;
+		} ud;
+	} wr;
+};
+
+struct ibv_recv_wr_1_0 {
+	struct ibv_recv_wr_1_0 *next;
+	uint64_t		wr_id;
+	struct ibv_sge	       *sg_list;
+	int			num_sge;
+};
+
+struct ibv_qp_1_0 {
+	struct ibv_context_1_0 *context;
+	void		       *qp_context;
+	struct ibv_pd_1_0      *pd;
+	struct ibv_cq_1_0      *send_cq;
+	struct ibv_cq_1_0      *recv_cq;
+	struct ibv_srq_1_0     *srq;
+	uint32_t		handle;
+	uint32_t		qp_num;
+	enum ibv_qp_state       state;
+	enum ibv_qp_type	qp_type;
+
+	pthread_mutex_t		mutex;
+	pthread_cond_t		cond;
+	uint32_t		events_completed;
+
+	struct ibv_qp	       *real_qp;
+};
+
+struct ibv_cq_1_0 {
+	struct ibv_context_1_0 *context;
+	void		       *cq_context;
+	uint32_t		handle;
+	int			cqe;
+
+	pthread_mutex_t		mutex;
+	pthread_cond_t		cond;
+	uint32_t		comp_events_completed;
+	uint32_t		async_events_completed;
+
+	struct ibv_cq	       *real_cq;
+};
+
+struct ibv_ah_1_0 {
+	struct ibv_context_1_0 *context;
+	struct ibv_pd_1_0      *pd;
+	uint32_t		handle;
+
+	struct ibv_ah	       *real_ah;
+};
+
+struct ibv_device_1_0 {
+	void		       *obsolete_sysfs_dev;
+	void		       *obsolete_sysfs_ibdev;
+	struct ibv_device      *real_device; /* was obsolete driver member */
+	struct ibv_device_ops	ops;
+};
+
+struct ibv_context_ops_1_0 {
+	int			(*query_device)(struct ibv_context *context,
+					      struct ibv_device_attr *device_attr);
+	int			(*query_port)(struct ibv_context *context, uint8_t port_num,
+					      struct ibv_port_attr *port_attr);
+	struct ibv_pd *		(*alloc_pd)(struct ibv_context *context);
+	int			(*dealloc_pd)(struct ibv_pd *pd);
+	struct ibv_mr *		(*reg_mr)(struct ibv_pd *pd, void *addr, size_t length,
+					  enum ibv_access_flags access);
+	int			(*dereg_mr)(struct ibv_mr *mr);
+	struct ibv_cq *		(*create_cq)(struct ibv_context *context, int cqe,
+					     struct ibv_comp_channel *channel,
+					     int comp_vector);
+	int			(*poll_cq)(struct ibv_cq_1_0 *cq, int num_entries,
+					   struct ibv_wc *wc);
+	int			(*req_notify_cq)(struct ibv_cq_1_0 *cq,
+						 int solicited_only);
+	void			(*cq_event)(struct ibv_cq *cq);
+	int			(*resize_cq)(struct ibv_cq *cq, int cqe);
+	int			(*destroy_cq)(struct ibv_cq *cq);
+	struct ibv_srq *	(*create_srq)(struct ibv_pd *pd,
+					      struct ibv_srq_init_attr *srq_init_attr);
+	int			(*modify_srq)(struct ibv_srq *srq,
+					      struct ibv_srq_attr *srq_attr,
+					      enum ibv_srq_attr_mask srq_attr_mask);
+	int			(*query_srq)(struct ibv_srq *srq,
+					     struct ibv_srq_attr *srq_attr);
+	int			(*destroy_srq)(struct ibv_srq *srq);
+	int			(*post_srq_recv)(struct ibv_srq_1_0 *srq,
+						 struct ibv_recv_wr_1_0 *recv_wr,
+						 struct ibv_recv_wr_1_0 **bad_recv_wr);
+	struct ibv_qp *		(*create_qp)(struct ibv_pd *pd, struct ibv_qp_init_attr *attr);
+	int			(*query_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+					    enum ibv_qp_attr_mask attr_mask,
+					    struct ibv_qp_init_attr *init_attr);
+	int			(*modify_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+					     enum ibv_qp_attr_mask attr_mask);
+	int			(*destroy_qp)(struct ibv_qp *qp);
+	int			(*post_send)(struct ibv_qp_1_0 *qp,
+					     struct ibv_send_wr_1_0 *wr,
+					     struct ibv_send_wr_1_0 **bad_wr);
+	int			(*post_recv)(struct ibv_qp_1_0 *qp,
+					     struct ibv_recv_wr_1_0 *wr,
+					     struct ibv_recv_wr_1_0 **bad_wr);
+	struct ibv_ah *		(*create_ah)(struct ibv_pd *pd, struct ibv_ah_attr *attr);
+	int			(*destroy_ah)(struct ibv_ah *ah);
+	int			(*attach_mcast)(struct ibv_qp *qp, union ibv_gid *gid,
+						uint16_t lid);
+	int			(*detach_mcast)(struct ibv_qp *qp, union ibv_gid *gid,
+						uint16_t lid);
+};
+
+struct ibv_context_1_0 {
+	struct ibv_device_1_0	       *device;
+	struct ibv_context_ops_1_0	ops;
+	int				cmd_fd;
+	int				async_fd;
+	int				num_comp_vectors;
+
+	struct ibv_context	       *real_context; /* was abi_compat member */
+};
+
+struct ibv_device_1_0 **__ibv_get_device_list_1_0(int *num)
+{
+	struct ibv_device **real_list;
+	struct ibv_device_1_0 **l;
+	int i, n;
+
+	real_list = ibv_get_device_list(&n);
+	if (!real_list)
+		return NULL;
+
+	l = calloc(n + 2, sizeof (struct ibv_device_1_0 *));
+	if (!l)
+		return NULL;
+
+	l[0] = (void *) real_list;
+
+	for (i = 0; i < n; ++i) {
+		l[i + 1] = calloc(1, sizeof (struct ibv_device_1_0));
+		if (!l[i + 1])
+			goto fail;
+		l[i + 1]->real_device = real_list[i];
+	}
+
+	if (num)
+		*num = n;
+
+	return l + 1;
+
+fail:
+	for (i = 1; i <= n; ++i)
+		if (l[i])
+			free(l[i]);
+	ibv_free_device_list(real_list);
+	return NULL;
+}
+symver(__ibv_get_device_list_1_0, ibv_get_device_list, IBVERBS_1.0);
+
+void __ibv_free_device_list_1_0(struct ibv_device_1_0 **list)
+{
+	struct ibv_device_1_0 **l = list;
+
+	while (*l) {
+		free(*l);
+		++l;
+	}
+
+	ibv_free_device_list((void *) list[-1]);
+	free(list - 1);
+}
+symver(__ibv_free_device_list_1_0, ibv_free_device_list, IBVERBS_1.0);
+
+const char *__ibv_get_device_name_1_0(struct ibv_device_1_0 *device)
+{
+	return ibv_get_device_name(device->real_device);
+}
+symver(__ibv_get_device_name_1_0, ibv_get_device_name, IBVERBS_1.0);
+
+uint64_t __ibv_get_device_guid_1_0(struct ibv_device_1_0 *device)
+{
+	return ibv_get_device_guid(device->real_device);
+}
+symver(__ibv_get_device_guid_1_0, ibv_get_device_guid, IBVERBS_1.0);
+
+static int poll_cq_wrapper_1_0(struct ibv_cq_1_0 *cq, int num_entries,
+			       struct ibv_wc *wc)
+{
+	return cq->context->real_context->ops.poll_cq(cq->real_cq, num_entries, wc);
+}
+
+static int req_notify_cq_wrapper_1_0(struct ibv_cq_1_0 *cq, int sol_only)
+{
+	return cq->context->real_context->ops.req_notify_cq(cq->real_cq, sol_only);
+}
+
+static int post_srq_recv_wrapper_1_0(struct ibv_srq_1_0 *srq, struct ibv_recv_wr_1_0 *wr,
+				 struct ibv_recv_wr_1_0 **bad_wr)
+{
+	struct ibv_recv_wr_1_0 *w;
+	struct ibv_recv_wr *real_wr, *head_wr = NULL, *tail_wr = NULL, *real_bad_wr;
+	int ret;
+
+	for (w = wr; w; w = w->next) {
+		real_wr = alloca(sizeof *real_wr);
+		real_wr->wr_id   = w->wr_id;
+		real_wr->sg_list = w->sg_list;
+		real_wr->num_sge = w->num_sge;
+		real_wr->next    = NULL;
+		if (tail_wr)
+			tail_wr->next = real_wr;
+		else
+			head_wr = real_wr;
+
+		tail_wr = real_wr;
+	}
+
+	ret = srq->context->real_context->ops.post_srq_recv(srq->real_srq, head_wr,
+							    &real_bad_wr);
+
+	if (ret) {
+		for (real_wr = head_wr, w = wr;
+		     real_wr;
+		     real_wr = real_wr->next, w = w->next)
+			if (real_wr == real_bad_wr) {
+				*bad_wr = w;
+				break;
+			}
+	}
+
+	return ret;
+}
+
+static int post_send_wrapper_1_0(struct ibv_qp_1_0 *qp, struct ibv_send_wr_1_0 *wr,
+				 struct ibv_send_wr_1_0 **bad_wr)
+{
+	struct ibv_send_wr_1_0 *w;
+	struct ibv_send_wr *real_wr, *head_wr = NULL, *tail_wr = NULL, *real_bad_wr;
+	int is_ud = qp->qp_type == IBV_QPT_UD;
+	int ret;
+
+	for (w = wr; w; w = w->next) {
+		real_wr = alloca(sizeof *real_wr);
+		real_wr->wr_id = w->wr_id;
+		real_wr->next  = NULL;
+
+		memcpy(&real_wr->sg_list, &w->sg_list,
+		       sizeof *w - offsetof(struct ibv_send_wr, sg_list));
+
+		if (is_ud)
+			real_wr->wr.ud.ah = w->wr.ud.ah->real_ah;
+
+		if (tail_wr)
+			tail_wr->next = real_wr;
+		else
+			head_wr = real_wr;
+
+		tail_wr = real_wr;
+	}
+
+	ret = qp->context->real_context->ops.post_send(qp->real_qp, head_wr,
+						       &real_bad_wr);
+
+	if (ret) {
+		for (real_wr = head_wr, w = wr;
+		     real_wr;
+		     real_wr = real_wr->next, w = w->next)
+			if (real_wr == real_bad_wr) {
+				*bad_wr = w;
+				break;
+			}
+	}
+
+	return ret;
+}
+
+static int post_recv_wrapper_1_0(struct ibv_qp_1_0 *qp, struct ibv_recv_wr_1_0 *wr,
+				 struct ibv_recv_wr_1_0 **bad_wr)
+{
+	struct ibv_recv_wr_1_0 *w;
+	struct ibv_recv_wr *real_wr, *head_wr = NULL, *tail_wr = NULL, *real_bad_wr;
+	int ret;
+
+	for (w = wr; w; w = w->next) {
+		real_wr = alloca(sizeof *real_wr);
+		real_wr->wr_id   = w->wr_id;
+		real_wr->sg_list = w->sg_list;
+		real_wr->num_sge = w->num_sge;
+		real_wr->next    = NULL;
+		if (tail_wr)
+			tail_wr->next = real_wr;
+		else
+			head_wr = real_wr;
+
+		tail_wr = real_wr;
+	}
+
+	ret = qp->context->real_context->ops.post_recv(qp->real_qp, head_wr,
+						       &real_bad_wr);
+
+	if (ret) {
+		for (real_wr = head_wr, w = wr;
+		     real_wr;
+		     real_wr = real_wr->next, w = w->next)
+			if (real_wr == real_bad_wr) {
+				*bad_wr = w;
+				break;
+			}
+	}
+
+	return ret;
+}
+
+struct ibv_context_1_0 *__ibv_open_device_1_0(struct ibv_device_1_0 *device)
+{
+	struct ibv_context     *real_ctx;
+	struct ibv_context_1_0 *ctx;
+
+	ctx = malloc(sizeof *ctx);
+	if (!ctx)
+		return NULL;
+
+	real_ctx = ibv_open_device(device->real_device);
+	if (!real_ctx) {
+		free(ctx);
+		return NULL;
+	}
+
+	ctx->device       = device;
+	ctx->real_context = real_ctx;
+
+	ctx->ops.poll_cq       = poll_cq_wrapper_1_0;
+	ctx->ops.req_notify_cq = req_notify_cq_wrapper_1_0;
+	ctx->ops.post_send     = post_send_wrapper_1_0;
+	ctx->ops.post_recv     = post_recv_wrapper_1_0;
+	ctx->ops.post_srq_recv = post_srq_recv_wrapper_1_0;
+
+	return ctx;
+}
+symver(__ibv_open_device_1_0, ibv_open_device, IBVERBS_1.0);
+
+int __ibv_close_device_1_0(struct ibv_context_1_0 *context)
+{
+	int ret;
+
+	ret = ibv_close_device(context->real_context);
+	if (ret)
+		return ret;
+
+	free(context);
+	return 0;
+}
+symver(__ibv_close_device_1_0, ibv_close_device, IBVERBS_1.0);
+
+int __ibv_get_async_event_1_0(struct ibv_context_1_0 *context,
+			      struct ibv_async_event *event)
+{
+	int ret;
+
+	ret = ibv_get_async_event(context->real_context, event);
+	if (ret)
+		return ret;
+
+	switch (event->event_type) {
+	case IBV_EVENT_CQ_ERR:
+		event->element.cq = event->element.cq->cq_context;
+		break;
+
+	case IBV_EVENT_QP_FATAL:
+	case IBV_EVENT_QP_REQ_ERR:
+	case IBV_EVENT_QP_ACCESS_ERR:
+	case IBV_EVENT_COMM_EST:
+	case IBV_EVENT_SQ_DRAINED:
+	case IBV_EVENT_PATH_MIG:
+	case IBV_EVENT_PATH_MIG_ERR:
+	case IBV_EVENT_QP_LAST_WQE_REACHED:
+		event->element.qp = event->element.qp->qp_context;
+		break;
+
+	case IBV_EVENT_SRQ_ERR:
+	case IBV_EVENT_SRQ_LIMIT_REACHED:
+		event->element.srq = event->element.srq->srq_context;
+		break;
+
+	default:
+		break;
+	}
+
+	return ret;
+}
+symver(__ibv_get_async_event_1_0, ibv_get_async_event, IBVERBS_1.0);
+
+void __ibv_ack_async_event_1_0(struct ibv_async_event *event)
+{
+	struct ibv_async_event real_event = *event;
+
+	switch (event->event_type) {
+	case IBV_EVENT_CQ_ERR:
+		real_event.element.cq =
+			((struct ibv_cq_1_0 *) event->element.cq)->real_cq;
+		break;
+
+	case IBV_EVENT_QP_FATAL:
+	case IBV_EVENT_QP_REQ_ERR:
+	case IBV_EVENT_QP_ACCESS_ERR:
+	case IBV_EVENT_COMM_EST:
+	case IBV_EVENT_SQ_DRAINED:
+	case IBV_EVENT_PATH_MIG:
+	case IBV_EVENT_PATH_MIG_ERR:
+	case IBV_EVENT_QP_LAST_WQE_REACHED:
+		real_event.element.qp =
+			((struct ibv_qp_1_0 *) event->element.qp)->real_qp;
+		break;
+
+	case IBV_EVENT_SRQ_ERR:
+	case IBV_EVENT_SRQ_LIMIT_REACHED:
+		real_event.element.srq =
+			((struct ibv_srq_1_0 *) event->element.srq)->real_srq;
+		break;
+
+	default:
+		break;
+	}
+
+	ibv_ack_async_event(&real_event);
+}
+symver(__ibv_ack_async_event_1_0, ibv_ack_async_event, IBVERBS_1.0);
+
+int __ibv_query_device_1_0(struct ibv_context_1_0 *context,
+			   struct ibv_device_attr *device_attr)
+{
+	return ibv_query_device(context->real_context, device_attr);
+}
+symver(__ibv_query_device_1_0, ibv_query_device, IBVERBS_1.0);
+
+int __ibv_query_port_1_0(struct ibv_context_1_0 *context, uint8_t port_num,
+			 struct ibv_port_attr *port_attr)
+{
+	return ibv_query_port(context->real_context, port_num, port_attr);
+}
+symver(__ibv_query_port_1_0, ibv_query_port, IBVERBS_1.0);
+
+int __ibv_query_gid_1_0(struct ibv_context_1_0 *context, uint8_t port_num,
+			int index, union ibv_gid *gid)
+{
+	return ibv_query_gid(context->real_context, port_num, index, gid);
+}
+symver(__ibv_query_gid_1_0, ibv_query_gid, IBVERBS_1.0);
+
+int __ibv_query_pkey_1_0(struct ibv_context_1_0 *context, uint8_t port_num,
+			 int index, uint16_t *pkey)
+{
+	return ibv_query_pkey(context->real_context, port_num, index, pkey);
+}
+symver(__ibv_query_pkey_1_0, ibv_query_pkey, IBVERBS_1.0);
+
+struct ibv_pd_1_0 *__ibv_alloc_pd_1_0(struct ibv_context_1_0 *context)
+{
+	struct ibv_pd *real_pd;
+	struct ibv_pd_1_0 *pd;
+
+	pd = malloc(sizeof *pd);
+	if (!pd)
+		return NULL;
+
+	real_pd = ibv_alloc_pd(context->real_context);
+	if (!real_pd) {
+		free(pd);
+		return NULL;
+	}
+
+	pd->context = context;
+	pd->real_pd = real_pd;
+
+	return pd;
+}
+symver(__ibv_alloc_pd_1_0, ibv_alloc_pd, IBVERBS_1.0);
+
+int __ibv_dealloc_pd_1_0(struct ibv_pd_1_0 *pd)
+{
+	int ret;
+
+	ret = ibv_dealloc_pd(pd->real_pd);
+	if (ret)
+		return ret;
+
+	free(pd);
+	return 0;
+}
+symver(__ibv_dealloc_pd_1_0, ibv_dealloc_pd, IBVERBS_1.0);
+
+struct ibv_mr_1_0 *__ibv_reg_mr_1_0(struct ibv_pd_1_0 *pd, void *addr,
+				    size_t length, enum ibv_access_flags access)
+{
+	struct ibv_mr *real_mr;
+	struct ibv_mr_1_0 *mr;
+
+	mr = malloc(sizeof *mr);
+	if (!mr)
+		return NULL;
+
+	real_mr = ibv_reg_mr(pd->real_pd, addr, length, access);
+	if (!real_mr) {
+		free(mr);
+		return NULL;
+	}
+
+	mr->context = pd->context;
+	mr->pd      = pd;
+	mr->lkey    = real_mr->lkey;
+	mr->rkey    = real_mr->rkey;
+	mr->real_mr = real_mr;
+
+	return mr;
+}
+symver(__ibv_reg_mr_1_0, ibv_reg_mr, IBVERBS_1.0);
+
+int __ibv_dereg_mr_1_0(struct ibv_mr_1_0 *mr)
+{
+	int ret;
+
+	ret = ibv_dereg_mr(mr->real_mr);
+	if (ret)
+		return ret;
+
+	free(mr);
+	return 0;
+}
+symver(__ibv_dereg_mr_1_0, ibv_dereg_mr, IBVERBS_1.0);
+
+struct ibv_cq_1_0 *__ibv_create_cq_1_0(struct ibv_context_1_0 *context, int cqe,
+				       void *cq_context,
+				       struct ibv_comp_channel *channel,
+				       int comp_vector)
+{
+	struct ibv_cq *real_cq;
+	struct ibv_cq_1_0 *cq;
+
+	cq = malloc(sizeof *cq);
+	if (!cq)
+		return NULL;
+
+	real_cq = ibv_create_cq(context->real_context, cqe, cq_context,
+				channel, comp_vector);
+	if (!real_cq) {
+		free(cq);
+		return NULL;
+	}
+
+	cq->context    = context;
+	cq->cq_context = cq_context;
+	cq->cqe        = cqe;
+	cq->real_cq    = real_cq;
+
+	real_cq->cq_context = cq;
+
+	return cq;
+}
+symver(__ibv_create_cq_1_0, ibv_create_cq, IBVERBS_1.0);
+
+int __ibv_resize_cq_1_0(struct ibv_cq_1_0 *cq, int cqe)
+{
+	return ibv_resize_cq(cq->real_cq, cqe);
+}
+symver(__ibv_resize_cq_1_0, ibv_resize_cq, IBVERBS_1.0);
+
+int __ibv_destroy_cq_1_0(struct ibv_cq_1_0 *cq)
+{
+	int ret;
+
+	ret = ibv_destroy_cq(cq->real_cq);
+	if (ret)
+		return ret;
+
+	free(cq);
+	return 0;
+}
+symver(__ibv_destroy_cq_1_0, ibv_destroy_cq, IBVERBS_1.0);
+
+int __ibv_get_cq_event_1_0(struct ibv_comp_channel *channel,
+			   struct ibv_cq_1_0 **cq, void **cq_context)
+{
+	struct ibv_cq *real_cq;
+	void *cq_ptr;
+	int ret;
+
+	ret = ibv_get_cq_event(channel, &real_cq, &cq_ptr);
+	if (ret)
+		return ret;
+
+	*cq         = cq_ptr;
+	*cq_context = (*cq)->cq_context;
+
+	return 0;
+}
+symver(__ibv_get_cq_event_1_0, ibv_get_cq_event, IBVERBS_1.0);
+
+void __ibv_ack_cq_events_1_0(struct ibv_cq_1_0 *cq, unsigned int nevents)
+{
+	ibv_ack_cq_events(cq->real_cq, nevents);
+}
+symver(__ibv_ack_cq_events_1_0, ibv_ack_cq_events, IBVERBS_1.0);
+
+struct ibv_srq_1_0 *__ibv_create_srq_1_0(struct ibv_pd_1_0 *pd,
+					 struct ibv_srq_init_attr *srq_init_attr)
+{
+	struct ibv_srq *real_srq;
+	struct ibv_srq_1_0 *srq;
+
+	srq = malloc(sizeof *srq);
+	if (!srq)
+		return NULL;
+
+	real_srq = ibv_create_srq(pd->real_pd, srq_init_attr);
+	if (!real_srq) {
+		free(srq);
+		return NULL;
+	}
+
+	srq->context     = pd->context;
+	srq->srq_context = srq_init_attr->srq_context;
+	srq->pd          = pd;
+	srq->real_srq    = real_srq;
+
+	real_srq->srq_context = srq;
+
+	return srq;
+}
+symver(__ibv_create_srq_1_0, ibv_create_srq, IBVERBS_1.0);
+
+int __ibv_modify_srq_1_0(struct ibv_srq_1_0 *srq,
+			 struct ibv_srq_attr *srq_attr,
+			 enum ibv_srq_attr_mask srq_attr_mask)
+{
+	return ibv_modify_srq(srq->real_srq, srq_attr, srq_attr_mask);
+}
+symver(__ibv_modify_srq_1_0, ibv_modify_srq, IBVERBS_1.0);
+
+int __ibv_query_srq_1_0(struct ibv_srq_1_0 *srq, struct ibv_srq_attr *srq_attr)
+{
+	return ibv_query_srq(srq->real_srq, srq_attr);
+}
+symver(__ibv_query_srq_1_0, ibv_query_srq, IBVERBS_1.0);
+
+int __ibv_destroy_srq_1_0(struct ibv_srq_1_0 *srq)
+{
+	int ret;
+
+	ret = ibv_destroy_srq(srq->real_srq);
+	if (ret)
+		return ret;
+
+	free(srq);
+	return 0;
+}
+symver(__ibv_destroy_srq_1_0, ibv_destroy_srq, IBVERBS_1.0);
+
+struct ibv_qp_1_0 *__ibv_create_qp_1_0(struct ibv_pd_1_0 *pd,
+				       struct ibv_qp_init_attr_1_0 *qp_init_attr)
+{
+	struct ibv_qp *real_qp;
+	struct ibv_qp_1_0 *qp;
+	struct ibv_qp_init_attr real_init_attr;
+
+	qp = malloc(sizeof *qp);
+	if (!qp)
+		return NULL;
+
+	real_init_attr.qp_context = qp_init_attr->qp_context;
+	real_init_attr.send_cq    = qp_init_attr->send_cq->real_cq;
+	real_init_attr.recv_cq    = qp_init_attr->recv_cq->real_cq;
+	real_init_attr.srq        = qp_init_attr->srq ?
+		qp_init_attr->srq->real_srq : NULL;
+	real_init_attr.cap        = qp_init_attr->cap;
+	real_init_attr.qp_type    = qp_init_attr->qp_type;
+	real_init_attr.sq_sig_all = qp_init_attr->sq_sig_all;
+
+	real_qp = ibv_create_qp(pd->real_pd, &real_init_attr);
+	if (!real_qp) {
+		free(qp);
+		return NULL;
+	}
+
+	qp->context    = pd->context;
+	qp->qp_context = qp_init_attr->qp_context;
+	qp->pd         = pd;
+	qp->send_cq    = qp_init_attr->send_cq;
+	qp->recv_cq    = qp_init_attr->recv_cq;
+	qp->srq        = qp_init_attr->srq;
+	qp->qp_type    = qp_init_attr->qp_type;
+	qp->qp_num     = real_qp->qp_num;
+	qp->real_qp    = real_qp;
+
+	qp_init_attr->cap = real_init_attr.cap;
+
+	real_qp->qp_context = qp;
+
+	return qp;
+}
+symver(__ibv_create_qp_1_0, ibv_create_qp, IBVERBS_1.0);
+
+int __ibv_query_qp_1_0(struct ibv_qp_1_0 *qp, struct ibv_qp_attr *attr,
+		       enum ibv_qp_attr_mask attr_mask,
+		       struct ibv_qp_init_attr_1_0 *init_attr)
+{
+	struct ibv_qp_init_attr real_init_attr;
+	int ret;
+
+	ret = ibv_query_qp(qp->real_qp, attr, attr_mask, &real_init_attr);
+	if (ret)
+		return ret;
+
+	init_attr->qp_context = qp->qp_context;
+	init_attr->send_cq    = real_init_attr.send_cq->cq_context;
+	init_attr->recv_cq    = real_init_attr.recv_cq->cq_context;
+	init_attr->srq        = real_init_attr.srq->srq_context;
+	init_attr->qp_type    = real_init_attr.qp_type;
+	init_attr->cap        = real_init_attr.cap;
+	init_attr->sq_sig_all = real_init_attr.sq_sig_all;
+
+	return 0;
+}
+symver(__ibv_query_qp_1_0, ibv_query_qp, IBVERBS_1.0);
+
+int __ibv_modify_qp_1_0(struct ibv_qp_1_0 *qp, struct ibv_qp_attr *attr,
+			enum ibv_qp_attr_mask attr_mask)
+{
+	return ibv_modify_qp(qp->real_qp, attr, attr_mask);
+}
+symver(__ibv_modify_qp_1_0, ibv_modify_qp, IBVERBS_1.0);
+
+int __ibv_destroy_qp_1_0(struct ibv_qp_1_0 *qp)
+{
+	int ret;
+
+	ret = ibv_destroy_qp(qp->real_qp);
+	if (ret)
+		return ret;
+
+	free(qp);
+	return 0;
+}
+symver(__ibv_destroy_qp_1_0, ibv_destroy_qp, IBVERBS_1.0);
+
+struct ibv_ah_1_0 *__ibv_create_ah_1_0(struct ibv_pd_1_0 *pd,
+				       struct ibv_ah_attr *attr)
+{
+	struct ibv_ah *real_ah;
+	struct ibv_ah_1_0 *ah;
+
+	ah = malloc(sizeof *ah);
+	if (!ah)
+		return NULL;
+
+	real_ah = ibv_create_ah(pd->real_pd, attr);
+	if (!real_ah) {
+		free(ah);
+		return NULL;
+	}
+
+	ah->context = pd->context;
+	ah->pd      = pd;
+	ah->real_ah = real_ah;
+
+	return ah;
+}
+symver(__ibv_create_ah_1_0, ibv_create_ah, IBVERBS_1.0);
+
+int __ibv_destroy_ah_1_0(struct ibv_ah_1_0 *ah)
+{
+	int ret;
+
+	ret = ibv_destroy_ah(ah->real_ah);
+	if (ret)
+		return ret;
+
+	free(ah);
+	return 0;
+}
+symver(__ibv_destroy_ah_1_0, ibv_destroy_ah, IBVERBS_1.0);
+
+int __ibv_attach_mcast_1_0(struct ibv_qp_1_0 *qp, union ibv_gid *gid, uint16_t lid)
+{
+	return ibv_attach_mcast(qp->real_qp, gid, lid);
+}
+symver(__ibv_attach_mcast_1_0, ibv_attach_mcast, IBVERBS_1.0);
+
+int __ibv_detach_mcast_1_0(struct ibv_qp_1_0 *qp, union ibv_gid *gid, uint16_t lid)
+{
+	return ibv_detach_mcast(qp->real_qp, gid, lid);
+}
+symver(__ibv_detach_mcast_1_0, ibv_detach_mcast, IBVERBS_1.0);
diff --git a/src/device.c b/src/device.c
index 17b835f..3abc1eb 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -28,8 +29,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: device.c 7621 2006-06-01 23:16:18Z roland $
  */
 
 #if HAVE_CONFIG_H
@@ -53,7 +52,7 @@ static pthread_mutex_t device_list_lock = PTHREAD_MUTEX_INITIALIZER;
 static int num_devices;
 static struct ibv_device **device_list;
 
-struct ibv_device **ibv_get_device_list(int *num)
+struct ibv_device **__ibv_get_device_list(int *num)
 {
 	struct ibv_device **l;
 	int i;
@@ -64,9 +63,13 @@ struct ibv_device **ibv_get_device_list(int *num)
 		num_devices = ibverbs_init(&device_list);
 
 	l = calloc(num_devices + 1, sizeof (struct ibv_device *));
+	if (!l)
+		goto out;
+
 	for (i = 0; i < num_devices; ++i)
 		l[i] = device_list[i];
 
+out:
 	pthread_mutex_unlock(&device_list_lock);
 
 	if (num)
@@ -74,25 +77,28 @@ struct ibv_device **ibv_get_device_list(int *num)
 
 	return l;
 }
+default_symver(__ibv_get_device_list, ibv_get_device_list);
 
-void ibv_free_device_list(struct ibv_device **list)
+void __ibv_free_device_list(struct ibv_device **list)
 {
 	free(list);
 }
+default_symver(__ibv_free_device_list, ibv_free_device_list);
 
-const char *ibv_get_device_name(struct ibv_device *device)
+const char *__ibv_get_device_name(struct ibv_device *device)
 {
-	return device->ibdev->name;
+	return device->name;
 }
+default_symver(__ibv_get_device_name, ibv_get_device_name);
 
-uint64_t ibv_get_device_guid(struct ibv_device *device)
+uint64_t __ibv_get_device_guid(struct ibv_device *device)
 {
 	char attr[24];
 	uint64_t guid = 0;
 	uint16_t parts[4];
 	int i;
 
-	if (ibv_read_sysfs_file(device->ibdev->path, "node_guid",
+	if (ibv_read_sysfs_file(device->ibdev_path, "node_guid",
 				attr, sizeof attr) < 0)
 		return 0;
 
@@ -105,14 +111,16 @@ uint64_t ibv_get_device_guid(struct ibv_device *device)
 
 	return htonll(guid);
 }
+default_symver(__ibv_get_device_guid, ibv_get_device_guid);
 
-struct ibv_context *ibv_open_device(struct ibv_device *device)
+struct ibv_context *__ibv_open_device(struct ibv_device *device)
 {
 	char *devpath;
 	int cmd_fd;
 	struct ibv_context *context;
 
-	asprintf(&devpath, "/dev/infiniband/%s", device->dev->name);
+	if (asprintf(&devpath, "/dev/infiniband/%s", device->dev_name) < 0)
+		return NULL;
 
 	/*
 	 * We'll only be doing writes, but we need O_RDWR in case the
@@ -130,6 +138,7 @@ struct ibv_context *ibv_open_device(struct ibv_device *device)
 
 	context->device = device;
 	context->cmd_fd = cmd_fd;
+	pthread_mutex_init(&context->mutex, NULL);
 
 	return context;
 
@@ -138,8 +147,9 @@ err:
 
 	return NULL;
 }
+default_symver(__ibv_open_device, ibv_open_device);
 
-int ibv_close_device(struct ibv_context *context)
+int __ibv_close_device(struct ibv_context *context)
 {
 	int async_fd = context->async_fd;
 	int cmd_fd   = context->cmd_fd;
@@ -160,9 +170,10 @@ int ibv_close_device(struct ibv_context *context)
 
 	return 0;
 }
+default_symver(__ibv_close_device, ibv_close_device);
 
-int ibv_get_async_event(struct ibv_context *context,
-			struct ibv_async_event *event)
+int __ibv_get_async_event(struct ibv_context *context,
+			  struct ibv_async_event *event)
 {
 	struct ibv_kern_async_event ev;
 
@@ -197,10 +208,14 @@ int ibv_get_async_event(struct ibv_context *context,
 		break;
 	}
 
+	if (context->ops.async_event)
+		context->ops.async_event(event);
+
 	return 0;
 }
+default_symver(__ibv_get_async_event, ibv_get_async_event);
 
-void ibv_ack_async_event(struct ibv_async_event *event)
+void __ibv_ack_async_event(struct ibv_async_event *event)
 {
 	switch (event->event_type) {
 	case IBV_EVENT_CQ_ERR:
@@ -251,3 +266,4 @@ void ibv_ack_async_event(struct ibv_async_event *event)
 		return;
 	}
 }
+default_symver(__ibv_ack_async_event, ibv_ack_async_event);
diff --git a/src/ibverbs.h b/src/ibverbs.h
index ef69eba..b1d2c2b 100644
--- a/src/ibverbs.h
+++ b/src/ibverbs.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2007 Cisco Systems, Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -28,8 +29,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: ibverbs.h 9974 2006-10-27 23:46:16Z roland $
  */
 
 #ifndef IB_VERBS_H
@@ -58,18 +57,20 @@
 #define INIT		__attribute__((constructor))
 #define FINI		__attribute__((destructor))
 
-#define PFX		"libibverbs: "
+#define DEFAULT_ABI	"IBVERBS_1.1"
 
-struct ibv_sysfs_dev {
-	struct sysfs_class_device      *verbs_dev;
-	struct ibv_sysfs_dev	       *next;
-	int				have_driver;
-};
+#ifdef HAVE_SYMVER_SUPPORT
+#  define symver(name, api, ver) \
+	asm(".symver " #name "," #api "@" #ver)
+#  define default_symver(name, api) \
+	asm(".symver " #name "," #api "@@" DEFAULT_ABI)
+#else
+#  define symver(name, api, ver)
+#  define default_symver(name, api) \
+	extern __typeof(name) api __attribute__((alias(#name)))
+#endif /* HAVE_SYMVER_SUPPORT */
 
-struct ibv_driver {
-	ibv_driver_init_func	init_func;
-	struct ibv_driver      *next;
-};
+#define PFX		"libibverbs: "
 
 struct ibv_abi_compat_v2 {
 	struct ibv_comp_channel	channel;
@@ -78,11 +79,7 @@ struct ibv_abi_compat_v2 {
 
 extern HIDDEN int abi_ver;
 
-extern HIDDEN int ibverbs_init(struct ibv_device ***list);
-
-extern HIDDEN int ibv_init_mem_map(void);
-extern HIDDEN int ibv_lock_range(void *base, size_t size);
-extern HIDDEN int ibv_unlock_range(void *base, size_t size);
+HIDDEN int ibverbs_init(struct ibv_device ***list);
 
 #define IBV_INIT_CMD(cmd, size, opcode)					\
 	do {								\
diff --git a/src/init.c b/src/init.c
index 2fc6055..a17ae16 100644
--- a/src/init.c
+++ b/src/init.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2006 Cisco Systems, Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -28,8 +29,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: init.c 10005 2006-10-30 23:06:59Z roland $
  */
 
 #if HAVE_CONFIG_H
@@ -42,167 +41,354 @@
 #include <stdio.h>
 #include <dlfcn.h>
 #include <unistd.h>
+#include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <dirent.h>
 
 #include "ibverbs.h"
 
-#ifndef OPENIB_DRIVER_PATH_ENV
-#  define OPENIB_DRIVER_PATH_ENV "OPENIB_DRIVER_PATH"
-#endif
-
 HIDDEN int abi_ver;
 
-static const char default_path[] = DRIVER_PATH;
-static const char *user_path;
+struct ibv_sysfs_dev {
+	char		        sysfs_name[IBV_SYSFS_NAME_MAX];
+	char		        ibdev_name[IBV_SYSFS_NAME_MAX];
+	char		        sysfs_path[IBV_SYSFS_PATH_MAX];
+	char		        ibdev_path[IBV_SYSFS_PATH_MAX];
+	struct ibv_sysfs_dev   *next;
+	int			abi_ver;
+	int			have_driver;
+};
+
+struct ibv_driver_name {
+	char		       *name;
+	struct ibv_driver_name *next;
+};
+
+struct ibv_driver {
+	const char	       *name;
+	ibv_driver_init_func	init_func;
+	struct ibv_driver      *next;
+};
 
 static struct ibv_sysfs_dev *sysfs_dev_list;
-static struct ibv_driver *driver_list;
+static struct ibv_driver_name *driver_name_list;
+static struct ibv_driver *head_driver, *tail_driver;
 
 static void find_sysfs_devs(void)
 {
-	struct sysfs_class *cls;
-	struct dlist *verbs_dev_list;
-	struct sysfs_class_device *verbs_dev;
-	struct ibv_sysfs_dev *dev;
-
-	cls = sysfs_open_class("infiniband_verbs");
-	if (!cls) {
-		fprintf(stderr, PFX "Fatal: couldn't open sysfs class 'infiniband_verbs'.\n");
-		return;
-	}
+	char class_path[IBV_SYSFS_PATH_MAX];
+	DIR *class_dir;
+	struct dirent *dent;
+	struct ibv_sysfs_dev *sysfs_dev = NULL;
+	char value[8];
+
+	snprintf(class_path, sizeof class_path, "%s/class/infiniband_verbs",
+		 ibv_get_sysfs_path());
 
-	verbs_dev_list = sysfs_get_class_devices(cls);
-	if (!verbs_dev_list) {
-		fprintf(stderr, PFX "Fatal: no infiniband class devices found.\n");
+	class_dir = opendir(class_path);
+	if (!class_dir) {
+		fprintf(stderr, PFX "Fatal: couldn't open sysfs class "
+			"directory '%s'.\n", class_path);
 		return;
 	}
 
-	dlist_for_each_data_rev(verbs_dev_list, verbs_dev, struct sysfs_class_device) {
-		dev = malloc(sizeof *dev);
-		if (!dev) {
-			fprintf(stderr, PFX "Warning: couldn't allocate device for %s\n",
-				verbs_dev->name);
+	while ((dent = readdir(class_dir))) {
+		struct stat buf;
+
+		if (dent->d_name[0] == '.')
+			continue;
+
+		if (!sysfs_dev)
+			sysfs_dev = malloc(sizeof *sysfs_dev);
+		if (!sysfs_dev) {
+			fprintf(stderr, PFX "Warning: couldn't allocate sysfs dev "
+				"for '%s'.\n", dent->d_name);
+			continue;
+		}
+
+		snprintf(sysfs_dev->sysfs_path, sizeof sysfs_dev->sysfs_path,
+			 "%s/%s", class_path, dent->d_name);
+
+		if (stat(sysfs_dev->sysfs_path, &buf)) {
+			fprintf(stderr, PFX "Warning: couldn't stat '%s'.\n",
+				sysfs_dev->sysfs_path);
+			continue;
+		}
+
+		if (!S_ISDIR(buf.st_mode))
+			continue;
+
+		snprintf(sysfs_dev->sysfs_name, sizeof sysfs_dev->sysfs_name,
+			"%s", dent->d_name);
+
+		if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "ibdev",
+					sysfs_dev->ibdev_name,
+					sizeof sysfs_dev->ibdev_name) < 0) {
+			fprintf(stderr, PFX "Warning: no ibdev class attr for '%s'.\n",
+				dent->d_name);
+			free(sysfs_dev);
 			continue;
 		}
 
-		dev->verbs_dev   = verbs_dev;
-		dev->next        = sysfs_dev_list;
-		dev->have_driver = 0;
-		sysfs_dev_list   = dev;
+		snprintf(sysfs_dev->ibdev_path, sizeof sysfs_dev->ibdev_path,
+			 "%s/class/infiniband/%s", ibv_get_sysfs_path(),
+			 sysfs_dev->ibdev_name);
+
+		sysfs_dev->next        = sysfs_dev_list;
+		sysfs_dev->have_driver = 0;
+		if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "abi_version",
+					value, sizeof value) > 0)
+			sysfs_dev->abi_ver = strtol(value, NULL, 10);
+		else
+			sysfs_dev->abi_ver = 0;
+
+		sysfs_dev_list = sysfs_dev;
+		sysfs_dev      = NULL;
 	}
-}
 
-__attribute__((weak))
-struct ibv_device *openib_driver_init(struct sysfs_class_device *dev)
-{
-        return NULL;
+	if (sysfs_dev)
+		free(sysfs_dev);
+
+	closedir(class_dir);
 }
 
-static void load_driver(char *so_path)
+void ibv_register_driver(const char *name, ibv_driver_init_func init_func)
 {
-	void *dlhandle;
-	ibv_driver_init_func init_func;
 	struct ibv_driver *driver;
 
-	dlhandle = dlopen(so_path, RTLD_NOW);
-	if (!dlhandle) {
-		fprintf(stderr, PFX "Warning: couldn't load driver %s: %s\n",
-			so_path, dlerror());
+	driver = malloc(sizeof *driver);
+	if (!driver) {
+		fprintf(stderr, PFX "Warning: couldn't allocate driver for %s\n", name);
 		return;
 	}
 
-	dlerror();
-	init_func = dlsym(dlhandle, "openib_driver_init");
-	if (dlerror() != NULL || !init_func) {
-		dlclose(dlhandle);
+	driver->name      = name;
+	driver->init_func = init_func;
+	driver->next      = NULL;
+
+	if (tail_driver)
+		tail_driver->next = driver;
+	else
+		head_driver = driver;
+	tail_driver = driver;
+}
+
+static void load_driver(const char *name)
+{
+	char *so_name;
+	void *dlhandle;
+
+#define __IBV_QUOTE(x)	#x
+#define IBV_QUOTE(x)	__IBV_QUOTE(x)
+
+	if (asprintf(&so_name,
+		     "lib%s-" IBV_QUOTE(IBV_DEVICE_LIBRARY_EXTENSION) ".so",
+		     name) < 0) {
+		fprintf(stderr, PFX "Warning: couldn't load driver '%s'.\n",
+			name);
 		return;
 	}
 
-	driver = malloc(sizeof *driver);
-	if (!driver) {
-		fprintf(stderr, PFX "Warning: couldn't allocate driver for %s\n", so_path);
-		dlclose(dlhandle);
-		return;
+	dlhandle = dlopen(so_name, RTLD_NOW);
+	if (!dlhandle) {
+		fprintf(stderr, PFX "Warning: couldn't load driver '%s': %s\n",
+			name, dlerror());
+		goto out;
 	}
 
-	driver->init_func = init_func;
-	driver->next      = driver_list;
-	driver_list       = driver;
+out:
+	free(so_name);
 }
 
-static void find_drivers(const char *dir)
+static void load_drivers(void)
 {
-	size_t len = strlen(dir);
-	glob_t so_glob;
-	char *pat;
-	int ret;
-	int i;
+	struct ibv_driver_name *name, *next_name;
+	const char *env;
+	char *list, *env_name;
 
-	if (!len)
+	/*
+	 * Only use drivers passed in through the calling user's
+	 * environment if we're not running setuid.
+	 */
+	if (getuid() == geteuid()) {
+		if ((env = getenv("RDMAV_DRIVERS"))) {
+			list = strdupa(env);
+			while ((env_name = strsep(&list, ":;")))
+				load_driver(env_name);
+		} else if ((env = getenv("IBV_DRIVERS"))) {
+			list = strdupa(env);
+			while ((env_name = strsep(&list, ":;")))
+				load_driver(env_name);
+		}
+	}
+
+	for (name = driver_name_list, next_name = name ? name->next : NULL;
+	     name;
+	     name = next_name, next_name = name ? name->next : NULL) {
+		load_driver(name->name);
+		free(name->name);
+		free(name);
+	}
+}
+
+static void read_config_file(const char *path)
+{
+	FILE *conf;
+	char *line = NULL;
+	char *config;
+	char *field;
+	size_t buflen = 0;
+	ssize_t len;
+
+	conf = fopen(path, "r");
+	if (!conf) {
+		fprintf(stderr, PFX "Warning: couldn't read config file %s.\n",
+			path);
 		return;
+	}
+
+	while ((len = getline(&line, &buflen, conf)) != -1) {
+		config = line + strspn(line, "\t ");
+		if (config[0] == '\n' || config[0] == '#')
+			continue;
+
+		field = strsep(&config, "\n\t ");
+
+		if (strcmp(field, "driver") == 0) {
+			struct ibv_driver_name *driver_name;
 
-	while (len && dir[len - 1] == '/')
-		--len;
+			config += strspn(config, "\t ");
+			field = strsep(&config, "\n\t ");
 
-	asprintf(&pat, "%.*s/*.so", (int) len, dir);
+			driver_name = malloc(sizeof *driver_name);
+			if (!driver_name) {
+				fprintf(stderr, PFX "Warning: couldn't allocate "
+					"driver name '%s'.\n", field);
+				continue;
+			}
+
+			driver_name->name = strdup(field);
+			if (!driver_name->name) {
+				fprintf(stderr, PFX "Warning: couldn't allocate "
+					"driver name '%s'.\n", field);
+				free(driver_name);
+				continue;
+			}
+
+			driver_name->next = driver_name_list;
+			driver_name_list  = driver_name;
+		} else
+			fprintf(stderr, PFX "Warning: ignoring bad config directive "
+				"'%s' in file '%s'.\n", field, path);
+	}
 
-	ret = glob(pat, 0, NULL, &so_glob);
-	free(pat);
+	if (line)
+		free(line);
+	fclose(conf);
+}
 
-	if (ret) {
-		if (ret != GLOB_NOMATCH)
-			fprintf(stderr, PFX "Warning: couldn't search %s\n", pat);
+static void read_config(void)
+{
+	DIR *conf_dir;
+	struct dirent *dent;
+	char *path;
+
+	conf_dir = opendir(IBV_CONFIG_DIR);
+	if (!conf_dir) {
+		fprintf(stderr, PFX "Warning: couldn't open config directory '%s'.\n",
+			IBV_CONFIG_DIR);
 		return;
 	}
 
-	for (i = 0; i < so_glob.gl_pathc; ++i)
-		load_driver(so_glob.gl_pathv[i]);
+	while ((dent = readdir(conf_dir))) {
+		struct stat buf;
+
+		if (asprintf(&path, "%s/%s", IBV_CONFIG_DIR, dent->d_name) < 0) {
+			fprintf(stderr, PFX "Warning: couldn't read config file %s/%s.\n",
+				IBV_CONFIG_DIR, dent->d_name);
+			return;
+		}
+
+		if (stat(path, &buf)) {
+			fprintf(stderr, PFX "Warning: couldn't stat config file '%s'.\n",
+				path);
+			goto next;
+		}
+
+		if (!S_ISREG(buf.st_mode))
+			goto next;
+
+		read_config_file(path);
+	next:
+		free(path);
+	}
 
-	globfree(&so_glob);
+	closedir(conf_dir);
 }
 
-static struct ibv_device *try_driver(ibv_driver_init_func init_func,
-				     struct sysfs_class_device *verbs_dev)
+static struct ibv_device *try_driver(struct ibv_driver *driver,
+				     struct ibv_sysfs_dev *sysfs_dev)
 {
-	struct sysfs_class_device *ib_dev;
 	struct ibv_device *dev;
-	char ibdev_name[64];
+	char value[8];
+	enum ibv_node_type node_type;
 
-	if (ibv_read_sysfs_file(verbs_dev->path, "ibdev",
-				ibdev_name, sizeof ibdev_name) < 0) {
-		fprintf(stderr, PFX "Warning: no ibdev class attr for %s\n",
-			verbs_dev->name);
+	dev = driver->init_func(sysfs_dev->sysfs_path, sysfs_dev->abi_ver);
+	if (!dev)
 		return NULL;
-	}
 
-	ib_dev = sysfs_open_class_device("infiniband", ibdev_name);
-	if (!ib_dev) {
-		fprintf(stderr, PFX "Warning: no infiniband class device %s for %s\n",
-			ibdev_name, verbs_dev->name);
-		return NULL;
+	if (ibv_read_sysfs_file(sysfs_dev->ibdev_path, "node_type", value, sizeof value) < 0) {
+		fprintf(stderr, PFX "Warning: no node_type attr under %s.\n",
+			sysfs_dev->ibdev_path);
+			node_type = IBV_NODE_UNKNOWN;
+	} else {
+		node_type = strtol(value, NULL, 10);
+		if (node_type < IBV_NODE_CA || node_type > IBV_NODE_RNIC)
+			node_type = IBV_NODE_UNKNOWN;
 	}
 
-	dev = init_func(verbs_dev);
-	if (dev) {
-		dev->dev    = verbs_dev;
-		dev->ibdev  = ib_dev;
-		dev->driver = NULL;
+	switch (node_type) {
+	case IBV_NODE_CA:
+	case IBV_NODE_SWITCH:
+	case IBV_NODE_ROUTER:
+		dev->transport_type = IBV_TRANSPORT_IB;
+		break;
+	case IBV_NODE_RNIC:
+		dev->transport_type = IBV_TRANSPORT_IWARP;
+		break;
+	default:
+		dev->transport_type = IBV_TRANSPORT_UNKNOWN;
+		break;
 	}
 
+	strcpy(dev->dev_name,   sysfs_dev->sysfs_name);
+	strcpy(dev->dev_path,   sysfs_dev->sysfs_path);
+	strcpy(dev->name,       sysfs_dev->ibdev_name);
+	strcpy(dev->ibdev_path, sysfs_dev->ibdev_path);
+
 	return dev;
 }
 
-static int check_abi_version(void)
+static struct ibv_device *try_drivers(struct ibv_sysfs_dev *sysfs_dev)
 {
-	const char *path;
-	char value[8];
+	struct ibv_driver *driver;
+	struct ibv_device *dev;
 
-	path = ibv_get_sysfs_path();
-	if (!path) {
-		fprintf(stderr, PFX "Fatal: couldn't find sysfs mount.\n");
-		return -1;
+	for (driver = head_driver; driver; driver = driver->next) {
+		dev = try_driver(driver, sysfs_dev);
+		if (dev)
+			return dev;
 	}
 
+	return NULL;
+}
+
+static int check_abi_version(const char *path)
+{
+	char value[8];
+
 	if (ibv_read_sysfs_file(path, "class/infiniband_verbs/abi_version",
 				value, sizeof value) < 0) {
 		fprintf(stderr, PFX "Fatal: couldn't read uverbs ABI version.\n");
@@ -222,6 +408,21 @@ static int check_abi_version(void)
 	return 0;
 }
 
+static void check_memlock_limit(void)
+{
+	struct rlimit rlim;
+
+	if (getrlimit(RLIMIT_MEMLOCK, &rlim)) {
+		fprintf(stderr, PFX "Warning: getrlimit(RLIMIT_MEMLOCK) failed.");
+		return;
+	}
+
+	if (rlim.rlim_cur <= 32768)
+		fprintf(stderr, PFX "Warning: RLIMIT_MEMLOCK is %lu bytes.\n"
+			"    This will severely limit memory registrations.\n",
+			rlim.rlim_cur);
+}
+
 static void add_device(struct ibv_device *dev,
 		       struct ibv_device ***dev_list,
 		       int *num_devices,
@@ -242,38 +443,43 @@ static void add_device(struct ibv_device *dev,
 
 HIDDEN int ibverbs_init(struct ibv_device ***list)
 {
-	char *wr_path, *dir;
+	const char *sysfs_path;
 	struct ibv_sysfs_dev *sysfs_dev, *next_dev;
 	struct ibv_device *device;
-	struct ibv_driver *driver;
 	int num_devices = 0;
 	int list_size = 0;
-	int no_driver = 0;
 	int statically_linked = 0;
+	int no_driver = 0;
 
 	*list = NULL;
 
-	if (check_abi_version())
+	if (getenv("RDMAV_FORK_SAFE") || getenv("IBV_FORK_SAFE"))
+		if (ibv_fork_init())
+			fprintf(stderr, PFX "Warning: fork()-safety requested "
+				"but init failed\n");
+
+	sysfs_path = ibv_get_sysfs_path();
+	if (!sysfs_path) {
+		fprintf(stderr, PFX "Fatal: couldn't find sysfs mount.\n");
 		return 0;
+	}
 
-	if (ibv_init_mem_map())
+	if (check_abi_version(sysfs_path))
 		return 0;
 
+	check_memlock_limit();
+
+	read_config();
+
 	find_sysfs_devs();
 
-	/*
-	 * First check if a driver statically linked in can support
-	 * all the devices.  This is needed to avoid dlopen() in the
-	 * all-static case (which will break because we end up with
-	 * both a static and dynamic copy of libdl).
-	 */
 	for (sysfs_dev = sysfs_dev_list; sysfs_dev; sysfs_dev = sysfs_dev->next) {
-		device = try_driver(openib_driver_init, sysfs_dev->verbs_dev);
+		device = try_drivers(sysfs_dev);
 		if (device) {
 			add_device(device, list, &num_devices, &list_size);
 			sysfs_dev->have_driver = 1;
 		} else
-			++no_driver;
+			no_driver = 1;
 	}
 
 	if (!no_driver)
@@ -299,49 +505,30 @@ HIDDEN int ibverbs_init(struct ibv_device ***list)
 		dlclose(hand);
 	}
 
-	find_drivers(default_path);
-
-	/*
-	 * Only use path passed in through the calling user's
-	 * environment if we're not running SUID.
-	 */
-	if (getuid() == geteuid()) {
-		user_path = getenv(OPENIB_DRIVER_PATH_ENV);
-		if (user_path) {
-			wr_path = strdupa(user_path);
-			while ((dir = strsep(&wr_path, ";:")))
-				find_drivers(dir);
-		}
-	}
+	load_drivers();
 
 	for (sysfs_dev = sysfs_dev_list; sysfs_dev; sysfs_dev = sysfs_dev->next) {
 		if (sysfs_dev->have_driver)
 			continue;
-		for (driver = driver_list; driver; driver = driver->next) {
-			device = try_driver(driver->init_func, sysfs_dev->verbs_dev);
-			if (device) {
-				add_device(device, list, &num_devices, &list_size);
-				sysfs_dev->have_driver = 1;
-			}
+
+		device = try_drivers(sysfs_dev);
+		if (device) {
+			add_device(device, list, &num_devices, &list_size);
+			sysfs_dev->have_driver = 1;
 		}
 	}
 
 out:
-	for (sysfs_dev = sysfs_dev_list, next_dev = sysfs_dev->next;
+	for (sysfs_dev = sysfs_dev_list,
+		     next_dev = sysfs_dev ? sysfs_dev->next : NULL;
 	     sysfs_dev;
 	     sysfs_dev = next_dev, next_dev = sysfs_dev ? sysfs_dev->next : NULL) {
 		if (!sysfs_dev->have_driver) {
 			fprintf(stderr, PFX "Warning: no userspace device-specific "
-				" driver found for %s\n", sysfs_dev->verbs_dev->name);
+				"driver found for %s\n", sysfs_dev->sysfs_path);
 			if (statically_linked)
 				fprintf(stderr, "	When linking libibverbs statically, "
 					"driver must be statically linked too.\n");
-			else {
-				fprintf(stderr, "	driver search path: ");
-				if (user_path)
-					fprintf(stderr, "%s:", user_path);
-				fprintf(stderr, "%s\n", default_path);
-			}
 		}
 		free(sysfs_dev);
 	}
diff --git a/src/libibverbs.map b/src/libibverbs.map
index fba7026..3a346ed 100644
--- a/src/libibverbs.map
+++ b/src/libibverbs.map
@@ -72,8 +72,23 @@ IBVERBS_1.0 {
 		ibv_get_sysfs_path;
 		ibv_read_sysfs_file;
 
-		ib_copy_qp_attr_from_kern;
-		ib_copy_path_rec_from_kern;
-		ib_copy_path_rec_to_kern;
 	local: *;
 };
+
+IBVERBS_1.1 {
+	global:
+		ibv_get_device_list;
+		ibv_free_device_list;
+		ibv_get_device_name;
+		ibv_get_device_guid;
+		ibv_open_device;
+		ibv_close_device;
+
+		ibv_init_ah_from_wc;
+		ibv_create_ah_from_wc;
+		ibv_copy_ah_attr_from_kern;
+		ibv_fork_init;
+		ibv_dontfork_range;
+		ibv_dofork_range;
+		ibv_register_driver;
+} IBVERBS_1.0;
diff --git a/src/marshall.c b/src/marshall.c
index 1284f64..577b4b1 100644
--- a/src/marshall.c
+++ b/src/marshall.c
@@ -34,10 +34,12 @@
 #  include <config.h>
 #endif /* HAVE_CONFIG_H */
 
+#include <string.h>
+
 #include <infiniband/marshall.h>
 
-static void ibv_copy_ah_attr_from_kern(struct ibv_ah_attr *dst,
-				       struct ibv_kern_ah_attr *src)
+void ibv_copy_ah_attr_from_kern(struct ibv_ah_attr *dst,
+				struct ibv_kern_ah_attr *src)
 {
 	memcpy(dst->grh.dgid.raw, src->grh.dgid, sizeof dst->grh.dgid);
 	dst->grh.flow_label = src->grh.flow_label;
@@ -138,21 +140,3 @@ void ibv_copy_path_rec_to_kern(struct ibv_kern_path_rec *dst,
 	dst->preference		= src->preference;
 	dst->packet_life_time_selector = src->packet_life_time_selector;
 }
-
-void ib_copy_qp_attr_from_kern(struct ibv_qp_attr *dst,
-			       struct ibv_kern_qp_attr *src)
-{
-	return ibv_copy_qp_attr_from_kern(dst, src);
-}
-
-void ib_copy_path_rec_from_kern(struct ib_sa_path_rec *dst,
-				struct ib_kern_path_rec *src)
-{
-	return ibv_copy_path_rec_from_kern(dst, src);
-}
-
-void ib_copy_path_rec_to_kern(struct ib_kern_path_rec *dst,
-			      struct ib_sa_path_rec *src)
-{
-	return ibv_copy_path_rec_to_kern(dst, src);
-}
diff --git a/src/memory.c b/src/memory.c
index 27054a0..7f49683 100644
--- a/src/memory.c
+++ b/src/memory.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2006 Cisco Systems, Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -28,14 +29,13 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: memory.c 7484 2006-05-24 21:12:21Z roland $
  */
 
 #if HAVE_CONFIG_H
 #  include <config.h>
 #endif /* HAVE_CONFIG_H */
 
+#include <errno.h>
 #include <sys/mman.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -44,114 +44,427 @@
 #include "ibverbs.h"
 
 /*
- * We keep a linked list of page ranges that have been locked along with a
- * reference count to manage overlapping registrations, etc.
- *
- * Eventually we should turn this into an RB-tree or something similar
- * to avoid the O(n) cost of registering/unregistering memory.
+ * Most distro's headers don't have these yet.
  */
+#ifndef MADV_DONTFORK
+#define MADV_DONTFORK	10
+#endif
+
+#ifndef MADV_DOFORK
+#define MADV_DOFORK	11
+#endif
 
 struct ibv_mem_node {
-	struct ibv_mem_node *prev, *next;
-	uintptr_t            start, end;
-	int                  refcnt;
+	enum {
+		IBV_RED,
+		IBV_BLACK
+	}			color;
+	struct ibv_mem_node    *parent;
+	struct ibv_mem_node    *left, *right;
+	uintptr_t		start, end;
+	int			refcnt;
 };
 
-static struct {
-	struct ibv_mem_node *first;
-	pthread_mutex_t      mutex;
-	uintptr_t            page_size;
-} mem_map;
+static struct ibv_mem_node *mm_root;
+static pthread_mutex_t mm_mutex = PTHREAD_MUTEX_INITIALIZER;
+static int page_size;
+static int too_late;
 
-int ibv_init_mem_map(void)
+int ibv_fork_init(void)
 {
-	struct ibv_mem_node *node = NULL;
+	void *tmp;
+	int ret;
 
-	node = malloc(sizeof *node);
-	if (!node)
-		goto fail;
+	if (mm_root)
+		return 0;
 
-	node->prev   = node->next = NULL;
-	node->start  = 0;
-	node->end    = UINTPTR_MAX;
-	node->refcnt = 0;
+	if (too_late)
+		return EINVAL;
 
-	mem_map.first = node;
+	page_size = sysconf(_SC_PAGESIZE);
+	if (page_size < 0)
+		return errno;
 
-	mem_map.page_size = sysconf(_SC_PAGESIZE);
-	if (mem_map.page_size < 0)
-		goto fail;
+	if (posix_memalign(&tmp, page_size, page_size))
+		return ENOMEM;
 
-	if (pthread_mutex_init(&mem_map.mutex, NULL))
-		goto fail;
+	ret = madvise(tmp, page_size, MADV_DONTFORK) ||
+	      madvise(tmp, page_size, MADV_DOFORK);
 
-	return 0;
+	free(tmp);
+
+	if (ret)
+		return ENOSYS;
+
+	mm_root = malloc(sizeof *mm_root);
+	if (!mm_root)
+		return ENOMEM;
 
-fail:
-	if (node)
-		free(node);
+	mm_root->parent = NULL;
+	mm_root->left   = NULL;
+	mm_root->right  = NULL;
+	mm_root->color  = IBV_BLACK;
+	mm_root->start  = 0;
+	mm_root->end    = UINTPTR_MAX;
+	mm_root->refcnt = 0;
 
-	return -1;
+	return 0;
 }
 
-static struct ibv_mem_node *__mm_find_first(uintptr_t start, uintptr_t end)
+static struct ibv_mem_node *__mm_prev(struct ibv_mem_node *node)
 {
-	struct ibv_mem_node *node = mem_map.first;
+	if (node->left) {
+		node = node->left;
+		while (node->right)
+			node = node->right;
+	} else {
+		while (node->parent && node == node->parent->left)
+			node = node->parent;
+
+		node = node->parent;
+	}
 
-	while (node) {
-		if ((node->start <= start && node->end >= start) ||
-		    (node->start <= end   && node->end >= end))
-			break;
-		node = node->next;
+	return node;
+}
+
+static struct ibv_mem_node *__mm_next(struct ibv_mem_node *node)
+{
+	if (node->right) {
+		node = node->right;
+		while (node->left)
+			node = node->left;
+	} else {
+		while (node->parent && node == node->parent->right)
+			node = node->parent;
+
+		node = node->parent;
 	}
 
 	return node;
 }
 
-static struct ibv_mem_node *__mm_prev(struct ibv_mem_node *node)
+static void __mm_rotate_right(struct ibv_mem_node *node)
 {
-	return node->prev;
+	struct ibv_mem_node *tmp;
+
+	tmp = node->left;
+
+	node->left = tmp->right;
+	if (node->left)
+		node->left->parent = node;
+
+	if (node->parent) {
+		if (node->parent->right == node)
+			node->parent->right = tmp;
+		else
+			node->parent->left = tmp;
+	} else
+		mm_root = tmp;
+
+	tmp->parent = node->parent;
+
+	tmp->right = node;
+	node->parent = tmp;
 }
 
-static struct ibv_mem_node *__mm_next(struct ibv_mem_node *node)
+static void __mm_rotate_left(struct ibv_mem_node *node)
 {
-	return node->next;
+	struct ibv_mem_node *tmp;
+
+	tmp = node->right;
+
+	node->right = tmp->left;
+	if (node->right)
+		node->right->parent = node;
+
+	if (node->parent) {
+		if (node->parent->right == node)
+			node->parent->right = tmp;
+		else
+			node->parent->left = tmp;
+	} else
+		mm_root = tmp;
+
+	tmp->parent = node->parent;
+
+	tmp->left = node;
+	node->parent = tmp;
 }
 
-static void __mm_add(struct ibv_mem_node *node,
-		     struct ibv_mem_node *new)
+static int verify(struct ibv_mem_node *node)
 {
-	new->prev  = node;
-	new->next  = node->next;
-	node->next = new;
-	if (new->next)
-		new->next->prev = new;
+	int hl, hr;
+
+	if (!node)
+		return 1;
+
+	hl = verify(node->left);
+	hr = verify(node->left);
+
+	if (!hl || !hr)
+		return 0;
+	if (hl != hr)
+		return 0;
+
+	if (node->color == IBV_RED) {
+		if (node->left && node->left->color != IBV_BLACK)
+			return 0;
+		if (node->right && node->right->color != IBV_BLACK)
+			return 0;
+		return hl;
+	}
+
+	return hl + 1;
+}
+
+static void __mm_add_rebalance(struct ibv_mem_node *node)
+{
+	struct ibv_mem_node *parent, *gp, *uncle;
+
+	while (node->parent && node->parent->color == IBV_RED) {
+		parent = node->parent;
+		gp     = node->parent->parent;
+
+		if (parent == gp->left) {
+			uncle = gp->right;
+
+			if (uncle && uncle->color == IBV_RED) {
+				parent->color = IBV_BLACK;
+				uncle->color  = IBV_BLACK;
+				gp->color     = IBV_RED;
+
+				node = gp;
+			} else {
+				if (node == parent->right) {
+					__mm_rotate_left(parent);
+					node   = parent;
+					parent = node->parent;
+				}
+
+				parent->color = IBV_BLACK;
+				gp->color     = IBV_RED;
+
+				__mm_rotate_right(gp);
+			}
+		} else {
+			uncle = gp->left;
+
+			if (uncle && uncle->color == IBV_RED) {
+				parent->color = IBV_BLACK;
+				uncle->color  = IBV_BLACK;
+				gp->color     = IBV_RED;
+
+				node = gp;
+			} else {
+				if (node == parent->left) {
+					__mm_rotate_right(parent);
+					node   = parent;
+					parent = node->parent;
+				}
+
+				parent->color = IBV_BLACK;
+				gp->color     = IBV_RED;
+
+				__mm_rotate_left(gp);
+			}
+		}
+	}
+
+	mm_root->color = IBV_BLACK;
+}
+
+static void __mm_add(struct ibv_mem_node *new)
+{
+	struct ibv_mem_node *node, *parent = NULL;
+
+	node = mm_root;
+	while (node) {
+		parent = node;
+		if (node->start < new->start)
+			node = node->right;
+		else
+			node = node->left;
+	}
+
+	if (parent->start < new->start)
+		parent->right = new;
+	else
+		parent->left = new;
+
+	new->parent = parent;
+	new->left   = NULL;
+	new->right  = NULL;
+
+	new->color = IBV_RED;
+	__mm_add_rebalance(new);
 }
 
 static void __mm_remove(struct ibv_mem_node *node)
 {
-	/* Never have to remove the first node, so we can use prev */
-	node->prev->next = node->next;
-	if (node->next)
-		node->next->prev = node->prev;
+	struct ibv_mem_node *child, *parent, *sib, *tmp;
+	int nodecol;
+
+	if (node->left && node->right) {
+		tmp = node->left;
+		while (tmp->right)
+			tmp = tmp->right;
+
+		nodecol    = tmp->color;
+		child      = tmp->left;
+		tmp->color = node->color;
+
+		if (tmp->parent != node) {
+			parent        = tmp->parent;
+			parent->right = tmp->left;
+			if (tmp->left)
+				tmp->left->parent = parent;
+
+			tmp->left   	   = node->left;
+			node->left->parent = tmp;
+		} else
+			parent = tmp;
+
+		tmp->right          = node->right;
+		node->right->parent = tmp;
+
+		tmp->parent = node->parent;
+		if (node->parent) {
+			if (node->parent->left == node)
+				node->parent->left = tmp;
+			else
+				node->parent->right = tmp;
+		} else
+			mm_root = tmp;
+	} else {
+		nodecol = node->color;
+
+		child  = node->left ? node->left : node->right;
+		parent = node->parent;
+
+		if (child)
+			child->parent = parent;
+		if (parent) {
+			if (parent->left == node)
+				parent->left = child;
+			else
+				parent->right = child;
+		} else
+			mm_root = child;
+	}
+
+	free(node);
+
+	if (nodecol == IBV_RED)
+		return;
+
+	while ((!child || child->color == IBV_BLACK) && child != mm_root) {
+		if (parent->left == child) {
+			sib = parent->right;
+
+			if (sib->color == IBV_RED) {
+				parent->color = IBV_RED;
+				sib->color    = IBV_BLACK;
+				__mm_rotate_left(parent);
+				sib = parent->right;
+			}
+
+			if ((!sib->left  || sib->left->color  == IBV_BLACK) &&
+			    (!sib->right || sib->right->color == IBV_BLACK)) {
+				sib->color = IBV_RED;
+				child  = parent;
+				parent = child->parent;
+			} else {
+				if (!sib->right || sib->right->color == IBV_BLACK) {
+					if (sib->left)
+						sib->left->color = IBV_BLACK;
+					sib->color = IBV_RED;
+					__mm_rotate_right(sib);
+					sib = parent->right;
+				}
+
+				sib->color    = parent->color;
+				parent->color = IBV_BLACK;
+				if (sib->right)
+					sib->right->color = IBV_BLACK;
+				__mm_rotate_left(parent);
+				child = mm_root;
+				break;
+			}
+		} else {
+			sib = parent->left;
+
+			if (sib->color == IBV_RED) {
+				parent->color = IBV_RED;
+				sib->color    = IBV_BLACK;
+				__mm_rotate_right(parent);
+				sib = parent->left;
+			}
+
+			if ((!sib->left  || sib->left->color  == IBV_BLACK) &&
+			    (!sib->right || sib->right->color == IBV_BLACK)) {
+				sib->color = IBV_RED;
+				child  = parent;
+				parent = child->parent;
+			} else {
+				if (!sib->left || sib->left->color == IBV_BLACK) {
+					if (sib->right)
+						sib->right->color = IBV_BLACK;
+					sib->color = IBV_RED;
+					__mm_rotate_left(sib);
+					sib = parent->left;
+				}
+
+				sib->color    = parent->color;
+				parent->color = IBV_BLACK;
+				if (sib->left)
+					sib->left->color = IBV_BLACK;
+				__mm_rotate_right(parent);
+				child = mm_root;
+				break;
+			}
+		}
+	}
+
+	if (child)
+		child->color = IBV_BLACK;
 }
 
-int ibv_lock_range(void *base, size_t size)
+static struct ibv_mem_node *__mm_find_start(uintptr_t start, uintptr_t end)
+{
+	struct ibv_mem_node *node = mm_root;
+
+	while (node) {
+		if (node->start <= start && node->end >= start)
+			break;
+
+		if (node->start < start)
+			node = node->right;
+		else
+			node = node->left;
+	}
+
+	return node;
+}
+
+static int ibv_madvise_range(void *base, size_t size, int advice)
 {
 	uintptr_t start, end;
 	struct ibv_mem_node *node, *tmp;
+	int inc;
 	int ret = 0;
 
 	if (!size)
 		return 0;
 
-	start = (uintptr_t) base & ~(mem_map.page_size - 1);
-	end   = ((uintptr_t) (base + size + mem_map.page_size - 1) &
-		 ~(mem_map.page_size - 1)) - 1;
+	inc = advice == MADV_DONTFORK ? 1 : -1;
+
+	start = (uintptr_t) base & ~(page_size - 1);
+	end   = ((uintptr_t) (base + size + page_size - 1) &
+		 ~(page_size - 1)) - 1;
 
-	pthread_mutex_lock(&mem_map.mutex);
+	pthread_mutex_lock(&mm_mutex);
 
-	node = __mm_find_first(start, end);
+	node = __mm_find_start(start, end);
 
 	if (node->start < start) {
 		tmp = malloc(sizeof *tmp);
@@ -165,11 +478,19 @@ int ibv_lock_range(void *base, size_t size)
 		tmp->refcnt = node->refcnt;
 		node->end   = start - 1;
 
-		__mm_add(node, tmp);
+		__mm_add(tmp);
 		node = tmp;
+	} else {
+		tmp = __mm_prev(node);
+		if (tmp && tmp->refcnt == node->refcnt + inc) {
+			tmp->end = node->end;
+			tmp->refcnt = node->refcnt;
+			__mm_remove(node);
+			node = tmp;
+		}
 	}
 
-	while (node->start <= end) {
+	while (node && node->start <= end) {
 		if (node->end > end) {
 			tmp = malloc(sizeof *tmp);
 			if (!tmp) {
@@ -182,13 +503,16 @@ int ibv_lock_range(void *base, size_t size)
 			tmp->refcnt = node->refcnt;
 			node->end   = end;
 
-			__mm_add(node, tmp);
+			__mm_add(tmp);
 		}
 
+		node->refcnt += inc;
 
-		if (node->refcnt++ == 0) {
-			ret = mlock((void *) node->start,
-				    node->end - node->start + 1);
+		if ((inc == -1 && node->refcnt == 0) ||
+		    (inc ==  1 && node->refcnt == 1)) {
+			ret = madvise((void *) node->start,
+				      node->end - node->start + 1,
+				      advice);
 			if (ret)
 				goto out;
 		}
@@ -196,63 +520,36 @@ int ibv_lock_range(void *base, size_t size)
 		node = __mm_next(node);
 	}
 
+	if (node) {
+		tmp = __mm_prev(node);
+		if (tmp && node->refcnt == tmp->refcnt) {
+			tmp->end = node->end;
+			__mm_remove(node);
+		}
+	}
+
 out:
-	pthread_mutex_unlock(&mem_map.mutex);
+	pthread_mutex_unlock(&mm_mutex);
 
 	return ret;
 }
 
-int ibv_unlock_range(void *base, size_t size)
+int ibv_dontfork_range(void *base, size_t size)
 {
-	uintptr_t start, end;
-	struct ibv_mem_node *node, *tmp;
-	int ret = 0;
-
-	if (!size)
+	if (mm_root)
+		return ibv_madvise_range(base, size, MADV_DONTFORK);
+	else {
+		too_late = 1;
 		return 0;
-
-	start = (uintptr_t) base & ~(mem_map.page_size - 1);
-	end   = ((uintptr_t) (base + size + mem_map.page_size - 1) &
-		 ~(mem_map.page_size - 1)) - 1;
-
-	pthread_mutex_lock(&mem_map.mutex);
-
-	node = __mm_find_first(start, end);
-
-	if (node->start != start) {
-		ret = -1;
-		goto out;
-	}
-
-	while (node && node->end <= end) {
-		if (--node->refcnt == 0) {
-			ret = munlock((void *) node->start,
-				      node->end - node->start + 1);
-		}
-
-		if (__mm_prev(node) && node->refcnt == __mm_prev(node)->refcnt) {
-			__mm_prev(node)->end = node->end;
-			tmp = __mm_prev(node);
-			__mm_remove(node);
-			node = tmp;
-		}
-
-		node = __mm_next(node);
-	}
-
-	if (node && node->refcnt == __mm_prev(node)->refcnt) {
-		__mm_prev(node)->end = node->end;
-		tmp = __mm_prev(node);
-		__mm_remove(node);
 	}
+}
 
-	if (node->end != end) {
-		ret = -1;
-		goto out;
+int ibv_dofork_range(void *base, size_t size)
+{
+	if (mm_root)
+		return ibv_madvise_range(base, size, MADV_DOFORK);
+	else {
+		too_late = 1;
+		return 0;
 	}
-
-out:
-	pthread_mutex_unlock(&mem_map.mutex);
-
-	return ret;
 }
diff --git a/src/sysfs.c b/src/sysfs.c
index 52fbd5a..85aee39 100644
--- a/src/sysfs.c
+++ b/src/sysfs.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2006 Cisco Systems, Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -28,8 +28,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id$
  */
 
 #if HAVE_CONFIG_H
@@ -42,6 +40,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <string.h>
 
 #include "ibverbs.h"
 
@@ -64,7 +63,7 @@ const char *ibv_get_sysfs_path(void)
 	if (env) {
 		int len;
 
-		sysfs_path = strndup(env, 256);
+		sysfs_path = strndup(env, IBV_SYSFS_PATH_MAX);
 		len = strlen(sysfs_path);
 		while (len > 0 && sysfs_path[len - 1] == '/') {
 			--len;
@@ -83,7 +82,8 @@ int ibv_read_sysfs_file(const char *dir, const char *file,
 	int fd;
 	int len;
 
-	asprintf(&path, "%s/%s", dir, file);
+	if (asprintf(&path, "%s/%s", dir, file) < 0)
+		return -1;
 
 	fd = open(path, O_RDONLY);
 	if (fd < 0) {
diff --git a/src/verbs.c b/src/verbs.c
index 0af89c8..febf32a 100644
--- a/src/verbs.c
+++ b/src/verbs.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2006 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -29,8 +29,6 @@
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
- *
- * $Id: verbs.c 7484 2006-05-24 21:12:21Z roland $
  */
 
 #if HAVE_CONFIG_H
@@ -42,6 +40,7 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <string.h>
 
 #include "ibverbs.h"
 
@@ -77,20 +76,22 @@ enum ibv_rate mult_to_ibv_rate(int mult)
 	}
 }
 
-int ibv_query_device(struct ibv_context *context,
-		     struct ibv_device_attr *device_attr)
+int __ibv_query_device(struct ibv_context *context,
+		       struct ibv_device_attr *device_attr)
 {
 	return context->ops.query_device(context, device_attr);
 }
+default_symver(__ibv_query_device, ibv_query_device);
 
-int ibv_query_port(struct ibv_context *context, uint8_t port_num,
-		   struct ibv_port_attr *port_attr)
+int __ibv_query_port(struct ibv_context *context, uint8_t port_num,
+		     struct ibv_port_attr *port_attr)
 {
 	return context->ops.query_port(context, port_num, port_attr);
 }
+default_symver(__ibv_query_port, ibv_query_port);
 
-int ibv_query_gid(struct ibv_context *context, uint8_t port_num,
-		  int index, union ibv_gid *gid)
+int __ibv_query_gid(struct ibv_context *context, uint8_t port_num,
+		    int index, union ibv_gid *gid)
 {
 	char name[24];
 	char attr[41];
@@ -99,7 +100,7 @@ int ibv_query_gid(struct ibv_context *context, uint8_t port_num,
 
 	snprintf(name, sizeof name, "ports/%d/gids/%d", port_num, index);
 
-	if (ibv_read_sysfs_file(context->device->ibdev->path, name,
+	if (ibv_read_sysfs_file(context->device->ibdev_path, name,
 				attr, sizeof attr) < 0)
 		return -1;
 
@@ -112,9 +113,10 @@ int ibv_query_gid(struct ibv_context *context, uint8_t port_num,
 
 	return 0;
 }
+default_symver(__ibv_query_gid, ibv_query_gid);
 
-int ibv_query_pkey(struct ibv_context *context, uint8_t port_num,
-		   int index, uint16_t *pkey)
+int __ibv_query_pkey(struct ibv_context *context, uint8_t port_num,
+		     int index, uint16_t *pkey)
 {
 	char name[24];
 	char attr[8];
@@ -122,7 +124,7 @@ int ibv_query_pkey(struct ibv_context *context, uint8_t port_num,
 
 	snprintf(name, sizeof name, "ports/%d/pkeys/%d", port_num, index);
 
-	if (ibv_read_sysfs_file(context->device->ibdev->path, name,
+	if (ibv_read_sysfs_file(context->device->ibdev_path, name,
 				attr, sizeof attr) < 0)
 		return -1;
 
@@ -132,8 +134,9 @@ int ibv_query_pkey(struct ibv_context *context, uint8_t port_num,
 	*pkey = htons(val);
 	return 0;
 }
+default_symver(__ibv_query_pkey, ibv_query_pkey);
 
-struct ibv_pd *ibv_alloc_pd(struct ibv_context *context)
+struct ibv_pd *__ibv_alloc_pd(struct ibv_context *context)
 {
 	struct ibv_pd *pd;
 
@@ -143,30 +146,48 @@ struct ibv_pd *ibv_alloc_pd(struct ibv_context *context)
 
 	return pd;
 }
+default_symver(__ibv_alloc_pd, ibv_alloc_pd);
 
-int ibv_dealloc_pd(struct ibv_pd *pd)
+int __ibv_dealloc_pd(struct ibv_pd *pd)
 {
 	return pd->context->ops.dealloc_pd(pd);
 }
+default_symver(__ibv_dealloc_pd, ibv_dealloc_pd);
 
-struct ibv_mr *ibv_reg_mr(struct ibv_pd *pd, void *addr,
-			  size_t length, enum ibv_access_flags access)
+struct ibv_mr *__ibv_reg_mr(struct ibv_pd *pd, void *addr,
+			    size_t length, enum ibv_access_flags access)
 {
 	struct ibv_mr *mr;
 
+	if (ibv_dontfork_range(addr, length))
+		return NULL;
+
 	mr = pd->context->ops.reg_mr(pd, addr, length, access);
 	if (mr) {
 		mr->context = pd->context;
 		mr->pd      = pd;
-	}
+		mr->addr    = addr;
+		mr->length  = length;
+	} else
+		ibv_dofork_range(addr, length);
 
 	return mr;
 }
+default_symver(__ibv_reg_mr, ibv_reg_mr);
 
-int ibv_dereg_mr(struct ibv_mr *mr)
+int __ibv_dereg_mr(struct ibv_mr *mr)
 {
-	return mr->context->ops.dereg_mr(mr);
+	int ret;
+	void *addr	= mr->addr;
+	size_t length	= mr->length;
+
+	ret = mr->context->ops.dereg_mr(mr);
+	if (!ret)
+		ibv_dofork_range(addr, length);
+
+	return ret;
 }
+default_symver(__ibv_dereg_mr, ibv_dereg_mr);
 
 static struct ibv_comp_channel *ibv_create_comp_channel_v2(struct ibv_context *context)
 {
@@ -205,7 +226,9 @@ struct ibv_comp_channel *ibv_create_comp_channel(struct ibv_context *context)
 		return NULL;
 	}
 
-	channel->fd = resp.fd;
+	channel->context = context;
+	channel->fd      = resp.fd;
+	channel->refcnt  = 0;
 
 	return channel;
 }
@@ -219,23 +242,46 @@ static int ibv_destroy_comp_channel_v2(struct ibv_comp_channel *channel)
 
 int ibv_destroy_comp_channel(struct ibv_comp_channel *channel)
 {
-	if (abi_ver <= 2)
-		return ibv_destroy_comp_channel_v2(channel);
+	struct ibv_context *context;
+	int ret;
+
+	context = channel->context;
+	pthread_mutex_lock(&context->mutex);
+
+	if (channel->refcnt) {
+		ret = EBUSY;
+		goto out;
+	}
+
+	if (abi_ver <= 2) {
+		ret = ibv_destroy_comp_channel_v2(channel);
+		goto out;
+	}
 
 	close(channel->fd);
 	free(channel);
+	ret = 0;
 
-	return 0;
+out:
+	pthread_mutex_unlock(&context->mutex);
+
+	return ret;
 }
 
-struct ibv_cq *ibv_create_cq(struct ibv_context *context, int cqe, void *cq_context,
-			     struct ibv_comp_channel *channel, int comp_vector)
+struct ibv_cq *__ibv_create_cq(struct ibv_context *context, int cqe, void *cq_context,
+			       struct ibv_comp_channel *channel, int comp_vector)
 {
-	struct ibv_cq *cq = context->ops.create_cq(context, cqe, channel,
-						   comp_vector);
+	struct ibv_cq *cq;
+
+	pthread_mutex_lock(&context->mutex);
+
+	cq = context->ops.create_cq(context, cqe, channel, comp_vector);
 
 	if (cq) {
 		cq->context    	     	   = context;
+		cq->channel		   = channel;
+		if (channel)
+			++channel->refcnt;
 		cq->cq_context 	     	   = cq_context;
 		cq->comp_events_completed  = 0;
 		cq->async_events_completed = 0;
@@ -243,25 +289,43 @@ struct ibv_cq *ibv_create_cq(struct ibv_context *context, int cqe, void *cq_cont
 		pthread_cond_init(&cq->cond, NULL);
 	}
 
+	pthread_mutex_unlock(&context->mutex);
+
 	return cq;
 }
+default_symver(__ibv_create_cq, ibv_create_cq);
 
-int ibv_resize_cq(struct ibv_cq *cq, int cqe)
+int __ibv_resize_cq(struct ibv_cq *cq, int cqe)
 {
 	if (!cq->context->ops.resize_cq)
 		return ENOSYS;
 
 	return cq->context->ops.resize_cq(cq, cqe);
 }
+default_symver(__ibv_resize_cq, ibv_resize_cq);
 
-int ibv_destroy_cq(struct ibv_cq *cq)
+int __ibv_destroy_cq(struct ibv_cq *cq)
 {
-	return cq->context->ops.destroy_cq(cq);
-}
+	struct ibv_comp_channel *channel = cq->channel;
+	int ret;
+
+	if (channel)
+		pthread_mutex_lock(&channel->context->mutex);
+
+	ret = cq->context->ops.destroy_cq(cq);
 
+	if (channel) {
+		if (!ret)
+			--channel->refcnt;
+		pthread_mutex_unlock(&channel->context->mutex);
+	}
+
+	return ret;
+}
+default_symver(__ibv_destroy_cq, ibv_destroy_cq);
 
-int ibv_get_cq_event(struct ibv_comp_channel *channel,
-		     struct ibv_cq **cq, void **cq_context)
+int __ibv_get_cq_event(struct ibv_comp_channel *channel,
+		       struct ibv_cq **cq, void **cq_context)
 {
 	struct ibv_comp_event ev;
 
@@ -276,17 +340,19 @@ int ibv_get_cq_event(struct ibv_comp_channel *channel,
 
 	return 0;
 }
+default_symver(__ibv_get_cq_event, ibv_get_cq_event);
 
-void ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents)
+void __ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents)
 {
 	pthread_mutex_lock(&cq->mutex);
 	cq->comp_events_completed += nevents;
 	pthread_cond_signal(&cq->cond);
 	pthread_mutex_unlock(&cq->mutex);
 }
+default_symver(__ibv_ack_cq_events, ibv_ack_cq_events);
 
-struct ibv_srq *ibv_create_srq(struct ibv_pd *pd,
-			       struct ibv_srq_init_attr *srq_init_attr)
+struct ibv_srq *__ibv_create_srq(struct ibv_pd *pd,
+				 struct ibv_srq_init_attr *srq_init_attr)
 {
 	struct ibv_srq *srq;
 
@@ -305,26 +371,30 @@ struct ibv_srq *ibv_create_srq(struct ibv_pd *pd,
 
 	return srq;
 }
+default_symver(__ibv_create_srq, ibv_create_srq);
 
-int ibv_modify_srq(struct ibv_srq *srq,
-		   struct ibv_srq_attr *srq_attr,
-		   enum ibv_srq_attr_mask srq_attr_mask)
+int __ibv_modify_srq(struct ibv_srq *srq,
+		     struct ibv_srq_attr *srq_attr,
+		     enum ibv_srq_attr_mask srq_attr_mask)
 {
 	return srq->context->ops.modify_srq(srq, srq_attr, srq_attr_mask);
 }
+default_symver(__ibv_modify_srq, ibv_modify_srq);
 
-int ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr)
+int __ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr)
 {
 	return srq->context->ops.query_srq(srq, srq_attr);
 }
+default_symver(__ibv_query_srq, ibv_query_srq);
 
-int ibv_destroy_srq(struct ibv_srq *srq)
+int __ibv_destroy_srq(struct ibv_srq *srq)
 {
 	return srq->context->ops.destroy_srq(srq);
 }
+default_symver(__ibv_destroy_srq, ibv_destroy_srq);
 
-struct ibv_qp *ibv_create_qp(struct ibv_pd *pd,
-			     struct ibv_qp_init_attr *qp_init_attr)
+struct ibv_qp *__ibv_create_qp(struct ibv_pd *pd,
+			       struct ibv_qp_init_attr *qp_init_attr)
 {
 	struct ibv_qp *qp = pd->context->ops.create_qp(pd, qp_init_attr);
 
@@ -343,10 +413,11 @@ struct ibv_qp *ibv_create_qp(struct ibv_pd *pd,
 
 	return qp;
 }
+default_symver(__ibv_create_qp, ibv_create_qp);
 
-int ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
-		 enum ibv_qp_attr_mask attr_mask,
-		 struct ibv_qp_init_attr *init_attr)
+int __ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+		   enum ibv_qp_attr_mask attr_mask,
+		   struct ibv_qp_init_attr *init_attr)
 {
 	int ret;
 
@@ -359,9 +430,10 @@ int ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
 
 	return 0;
 }
+default_symver(__ibv_query_qp, ibv_query_qp);
 
-int ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
-		  enum ibv_qp_attr_mask attr_mask)
+int __ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+		    enum ibv_qp_attr_mask attr_mask)
 {
 	int ret;
 
@@ -374,13 +446,15 @@ int ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
 
 	return 0;
 }
+default_symver(__ibv_modify_qp, ibv_modify_qp);
 
-int ibv_destroy_qp(struct ibv_qp *qp)
+int __ibv_destroy_qp(struct ibv_qp *qp)
 {
 	return qp->context->ops.destroy_qp(qp);
 }
+default_symver(__ibv_destroy_qp, ibv_destroy_qp);
 
-struct ibv_ah *ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr)
+struct ibv_ah *__ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr)
 {
 	struct ibv_ah *ah = pd->context->ops.create_ah(pd, attr);
 
@@ -391,18 +465,78 @@ struct ibv_ah *ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr)
 
 	return ah;
 }
+default_symver(__ibv_create_ah, ibv_create_ah);
+
+static int ibv_find_gid_index(struct ibv_context *context, uint8_t port_num,
+			      union ibv_gid *gid)
+{
+	union ibv_gid sgid;
+	int i = 0, ret;
+
+	do {
+		ret = ibv_query_gid(context, port_num, i++, &sgid);
+	} while (!ret && memcmp(&sgid, gid, sizeof *gid));
+
+	return ret ? ret : i - 1;
+}
+
+int ibv_init_ah_from_wc(struct ibv_context *context, uint8_t port_num,
+			struct ibv_wc *wc, struct ibv_grh *grh,
+			struct ibv_ah_attr *ah_attr)
+{
+	uint32_t flow_class;
+	int ret;
+
+	memset(ah_attr, 0, sizeof *ah_attr);
+	ah_attr->dlid = wc->slid;
+	ah_attr->sl = wc->sl;
+	ah_attr->src_path_bits = wc->dlid_path_bits;
+	ah_attr->port_num = port_num;
+
+	if (wc->wc_flags & IBV_WC_GRH) {
+		ah_attr->is_global = 1;
+		ah_attr->grh.dgid = grh->sgid;
+
+		ret = ibv_find_gid_index(context, port_num, &grh->dgid);
+		if (ret < 0)
+			return ret;
+
+		ah_attr->grh.sgid_index = (uint8_t) ret;
+		flow_class = ntohl(grh->version_tclass_flow);
+		ah_attr->grh.flow_label = flow_class & 0xFFFFF;
+		ah_attr->grh.hop_limit = grh->hop_limit;
+		ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF;
+	}
+	return 0;
+}
+
+struct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd *pd, struct ibv_wc *wc,
+				     struct ibv_grh *grh, uint8_t port_num)
+{
+	struct ibv_ah_attr ah_attr;
+	int ret;
+
+	ret = ibv_init_ah_from_wc(pd->context, port_num, wc, grh, &ah_attr);
+	if (ret)
+		return NULL;
+
+	return ibv_create_ah(pd, &ah_attr);
+}
 
-int ibv_destroy_ah(struct ibv_ah *ah)
+int __ibv_destroy_ah(struct ibv_ah *ah)
 {
 	return ah->context->ops.destroy_ah(ah);
 }
+default_symver(__ibv_destroy_ah, ibv_destroy_ah);
 
-int ibv_attach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid)
+int __ibv_attach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid)
 {
 	return qp->context->ops.attach_mcast(qp, gid, lid);
 }
+default_symver(__ibv_attach_mcast, ibv_attach_mcast);
 
-int ibv_detach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid)
+int __ibv_detach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid)
 {
 	return qp->context->ops.detach_mcast(qp, gid, lid);
 }
+default_symver(__ibv_detach_mcast, ibv_detach_mcast);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ofed/libibverbs.git



More information about the Pkg-ofed-commits mailing list