PSARC 2012/384 Fast IB node death detection
authorBoris Chiu <Boris.Chiu@Oracle.COM>
Thu, 17 Jan 2013 09:36:55 -0800
changeset 1125 47a52afcc302
parent 1124 08534bc6778b
child 1126 a7e552aeef46
PSARC 2012/384 Fast IB node death detection 16037511 Add support SM events to facilitate fast node death detection (userland)
components/open-fabrics/Makefile
components/open-fabrics/libibverbs/Makefile
components/open-fabrics/libibverbs/manpages/ibv_gid_reachable.3
components/open-fabrics/libibverbs/manpages/ibv_register_sm_events.3
components/open-fabrics/libibverbs/patches/base.patch
components/open-fabrics/open-fabrics.p5m
--- a/components/open-fabrics/Makefile	Wed Jan 16 12:43:19 2013 -0800
+++ b/components/open-fabrics/Makefile	Thu Jan 17 09:36:55 2013 -0800
@@ -18,7 +18,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
 #
 include ../../make-rules/shared-macros.mk
 include ../../make-rules/ips.mk
--- a/components/open-fabrics/libibverbs/Makefile	Wed Jan 16 12:43:19 2013 -0800
+++ b/components/open-fabrics/libibverbs/Makefile	Thu Jan 17 09:36:55 2013 -0800
@@ -18,7 +18,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
 #
 include ../../../make-rules/shared-macros.mk
 
@@ -36,7 +36,9 @@
 
 MAN3FILES =	ibv_alloc_shpd.3 \
 		ibv_reg_mr_relaxed.3 \
-		ibv_share_pd.3
+		ibv_share_pd.3 \
+		ibv_gid_reachable.3 \
+		ibv_register_sm_events.3
 
 include $(WS_TOP)/make-rules/shared-targets.mk
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/open-fabrics/libibverbs/manpages/ibv_gid_reachable.3	Thu Jan 17 09:36:55 2013 -0800
@@ -0,0 +1,93 @@
+'\" te
+.\" CDDL HEADER START
+.\"
+.\" The contents of this file are subject to the terms of the
+.\" Common Development and Distribution License (the "License").
+.\" You may not use this file except in compliance with the License.
+.\"
+.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+.\" or http://www.opensolaris.org/os/licensing.
+.\" See the License for the specific language governing permissions
+.\" and limitations under the License.
+.\"
+.\" When distributing Covered Code, include this CDDL HEADER in each
+.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+.\" If applicable, add the following below this CDDL HEADER, with the
+.\" fields enclosed by brackets "[]" replaced with your own identifying
+.\" information: Portions Copyright [yyyy] [name of copyright owner]
+.\"
+.\" CDDL HEADER END
+.\"
+.\" Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+.\"
+.\" -*- nroff -*-
+.\"
+.TH IBV_GID_REACHABLE 3 2012-08-08 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_gid_reachable \- will contact the SA to do a path record lookup from the
+device,port specified by 'context','port' to the remote 'gid_p'.  It finds the
+status of the remote GID (reachable or unreachable).
+.sp
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_gid_reachable(struct ibv_context *context, uint port,
+.BI "union ibv_gid *gid_p, int timeout)
+.if
+.TP
+.B gid_p
+A pointer to the gid to check
+.TP
+.B context
+A device context obtained from a call to ibv_open_device().
+This identifies the device to use in order to contact the
+remote 'gid_p'.
+.TP
+.B port
+Specifies the port on the device associated with 'context'.
+If '0' then the implementation will choose a port.
+.TP
+.B timeout
+It is currently set to '0' and reserved for future enhancement.
+ibv_gid_reachable() will block until a response
+(success, fail or no path found) is obtained.
+.sp
+.SH "DESCRIPTION"
+.B ibv_gid_reachable() will contact the SA from the device,port specified
+by 'context','port' to the remote 'gid_p'.
+It finds the status of the remote 'gid_p' (reachable or not).
+.sp
+.B ibv_gid_reachable()
+returns 0 on success, -1 on failure with errno set as follows:
+.sp
+.TP
+.in +10
+.B EINVAL \fR\fR\fR Invalid argument.
+.in -10
+.TP
+.in +10
+.B ENXIO \fR\fR\fR No Path Found
+.in -10
+.TP
+.in +10
+.B EIO \fR\fR\fR I/O Error
+.in -10
+.TP
+.in +10
+.B ENOMEM \fR\fR\fR Could not allocate kernel resource
+.in -10
+.in +23
+required to perform the lookup.
+.in -23
+.TP
+.in +10
+.B EINTR \fR\fR\fR Abort due to interrupted system call.
+.in -10
+.sp
+.SH "RETURN VALUE"
+.B ibv_gid_reachable()
+returns 0 on success, and \-1 on error.
+.sp
+.SH "NOTES"
+.TP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/open-fabrics/libibverbs/manpages/ibv_register_sm_events.3	Thu Jan 17 09:36:55 2013 -0800
@@ -0,0 +1,139 @@
+'\" te
+.\" CDDL HEADER START
+.\"
+.\" The contents of this file are subject to the terms of the
+.\" Common Development and Distribution License (the "License").
+.\" You may not use this file except in compliance with the License.
+.\"
+.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+.\" or http://www.opensolaris.org/os/licensing.
+.\" See the License for the specific language governing permissions
+.\" and limitations under the License.
+.\"
+.\" When distributing Covered Code, include this CDDL HEADER in each
+.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+.\" If applicable, add the following below this CDDL HEADER, with the
+.\" fields enclosed by brackets "[]" replaced with your own identifying
+.\" information: Portions Copyright [yyyy] [name of copyright owner]
+.\"
+.\" CDDL HEADER END
+.\"
+.\" Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+.\"
+.\" -*- nroff -*-
+.\"
+.TH IBV_REGISTER_SM_EVENTS 3 2012-08-08 libibverbs "Libibverbs Programmer's Manual"
+.SH "NAME"
+ibv_register_sm_events, ibv_unregister_sm_events \- registers or unregisters
+the specified subnet events for the specified GID(s).
+.sp
+.SH "SYNOPSIS"
+.nf
+.B #include <infiniband/verbs.h>
+.sp
+.BI "int ibv_register_sm_events(struct ibv_context *context,
+.BI "ibv_sm_event_type_t event, int gid_num, union ibv_gid *gids)
+.sp
+.BI "int ibv_unregister_sm_events(struct ibv_context *context,
+.BI "ibv_sm_event_type_t event, int gid_num, union ibv_gid *gids)
+.if
+.TP
+.B context:\fR Device context
+.TP
+.B event:\fR
+Logical OR of events to register for, valid values are:
+.TP
+.in +5
+.B IBV_SM_EVENT_MGID
+.in -5
+.in +15
+.B Request notification of Multicast GID events
+.in -15
+.TP
+.in +5
+.B IBV_SM_EVENT_UGID
+.in -5
+.in +15
+.B Request notification of Unicast GID events
+.in -15
+.TP
+.in +5
+.B IBV_SM_EVENT_UGID_ALL
+.in -5
+.in +15
+.B Request notification of ALL Unicast GID events
+.in -15
+.TP
+.in +5
+.B IBV_SM_EVENT_MGID_ALL
+.in -5
+.in +15
+.B Request notification of ALL Multicast GID events
+.in -15
+.TP
+.in +5
+.B IBV_SM_EVENT_ALL
+.in -5
+.in +15
+.B Request notification of ALL Multicast and Unicast GID events
+.in -15
+.TP
+.B gid_num:
+0 or the number of gids in the array of gids pointed to by gids.
+.TP
+.B gids:
+NULL, or an array of GIDS.
+.sp
+.SH "DESCRIPTION"
+.B ibv_register_sm_events()
+registers for the specified subnet events for the specified GID(s).
+ibv_unregister_sm_events() unregisters for the specified subnet events
+for the specified GID(s). These events are delivered on the async fd
+(see ibv_get_async_event(3)), from a previously opened device (see
+ibv_open_device()). It is only necessary to call ibv_register_sm_events()
+on a single device connected to each unique fabric, partition. For
+example, if a node has 4 HCAs attached to the same fabric, with all
+ports in the same partition, then it is only necessary to call
+ibv_register_sm_events() on one of them.
+.sp
+.TP
+.B The following ibv_event_type events can be passed to
+ibv_register_sm_events():
+.TP
+.in +5
+.B IBV_EVENT_MCG_CREATED
+.in -5
+.in +12
+An MCG specified by the new "gid" member of the ibv_async_event
+struct has been created. 
+.in -12
+.TP
+.in +5
+.B IBV_EVENT_MCG_DELETED
+.in -5
+.in +12
+The MCG specified by the "gid" member of the ibv_async_event struct
+has been deleted. 
+.in -12
+.TP
+.in +5
+.B IBV_EVENT_GID_AVAIL
+.in -5
+.in +12
+The GID specified by the "gid" member of the ibv_async_event struct
+is available on this subnet.
+.in -12
+.TP
+.in +5
+.B IBV_EVENT_GID_UNAVAIL
+.in -5
+.in +12
+The GID specified by the "gid" member of the ibv_async_event struct
+is no longer available on this subnet.
+.in -12
+.sp
+.SH "RETURN VALUE"
+.B ibv_register_sm_events(), ibv_unregister_sm_events()
+returns 0 on success, and \-1 on error.
+.SH "NOTES"
+.TP
--- a/components/open-fabrics/libibverbs/patches/base.patch	Wed Jan 16 12:43:19 2013 -0800
+++ b/components/open-fabrics/libibverbs/patches/base.patch	Thu Jan 17 09:36:55 2013 -0800
@@ -172,7 +172,7 @@
  .B ibv_get_device_guid()
 diff -r -u /tmp/846623/libibverbs-1.1.4/man/ibv_post_send.3 libibverbs-1.1.4/man/ibv_post_send.3
 --- /tmp/846623/libibverbs-1.1.4/man/ibv_post_send.3	Thu Mar 10 06:58:20 2011
-+++ libibverbs-1.1.4/man/ibv_post_send.3	Wed Oct 10 11:04:39 2012
++++ libibverbs-1.1.4/man/ibv_post_send.3	Tue Nov 13 10:04:25 2012
 @@ -91,14 +91,17 @@
  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
@@ -220,6 +220,32 @@
  .I context
  and returns it through the pointer
  .I event\fR,
[email protected]@ -29,6 +29,8 @@
+ 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 */
++uint32_t        xrc_qp_num;     /* XRC QP that got the event */
++union ibv_gid   gid;            /* list of guids that got the event */
+ .in -8
+ } element;
+ enum ibv_event_type     event_type;     /* type of the event */
[email protected]@ -86,6 +88,16 @@
+ .TP
+ .B IBV_EVENT_DEVICE_FATAL \fR CA is in FATAL state
+ .PP
++.I Subnet events:
++.TP
++.B IBV_SM_EVENT_MCG_CREATED \fR notification of MCG creation
++.TP
++.B IBV_SM_EVENT_MCG_DELETED \fR notification of MCG deletion
++.TP
++.B IBV_SM_EVENT_GID_AVAIL \fR notification of GID available events
++.TP
++.B IBV_SM_EVENT_GID_UNAVAIL \fR notification of GID unavailable events
++.PP
+ .B ibv_ack_async_event()
+ acknowledge the async event
+ .I event\fR.
 diff -r -u /tmp/846623/libibverbs-1.1.4/man/ibv_get_device_list.3 libibverbs-1.1.4/man/ibv_get_device_list.3
 --- /tmp/846623/libibverbs-1.1.4/man/ibv_get_device_list.3	Thu Mar 10 04:51:46 2011
 +++ libibverbs-1.1.4/man/ibv_get_device_list.3	Mon Mar 28 03:11:46 2011
@@ -277,15 +303,93 @@
 diff -r -u /tmp/846623/libibverbs-1.1.4/man/ibv_asyncwatch.1 libibverbs-1.1.4/man/ibv_asyncwatch.1
 --- /tmp/846623/libibverbs-1.1.4/man/ibv_asyncwatch.1	Thu Mar 10 04:51:46 2011
 +++ libibverbs-1.1.4/man/ibv_asyncwatch.1	Mon Mar 28 03:11:45 2011
[email protected]@ -8,7 +8,7 @@
[email protected]@ -1,16 +1,78 @@
+-.TH IBV_ASYNCWATCH 1 "August 30, 2005" "libibverbs" "USER COMMANDS"
++'\" te
++.TH IBV_ASYNCWATCH 1 "August 8, 2012" "libibverbs" "USER COMMANDS"
+ 
+ .SH NAME
+ ibv_asyncwatch \- display asynchronous events
  
+ .SH SYNOPSIS
+-.B ibv_asyncwatch
+-
++.sp
++.nf
++\fIibv_asyncwatch\fR [\-G | \-M] [\-s[<guid>]] [\-p port]
++\fIibv_asyncwactch\fR \-s
++\fIibv_asyncwatch\fR \-G \-s
++\fIibv_asyncwatch\fR \-M \-s
++\fIibv_asyncwatch\fR \-G [\-p port] \-s<guid1>,<guid2>,...
++\fIibv_asyncwatch\fR \-M [\-p port] \-s<mgid1>,<mgid2>,...
++.fi
++.sp
  .SH DESCRIPTION
  .PP
 -Display asynchronous events forwarded to userspace for an RDMA device.
 +Display asynchronous events forwarded to userspace for an InfiniBand device.
++SM events can be monitored using the '-s' option, which optionally
++takes a remote port GUID, or list of remote port GUIDS separated by ','.
++If '-s' is specified with no argument then all remote nodes reachable
++form device 0 are monitored, otherwise only the specified remote
++nodes are monitored. The following SM events are monitored using
++the '-s' option: 
  
- .SH AUTHORS
- .TP
+-.SH AUTHORS
+-.TP
+-Roland Dreier
+-.RI < [email protected] >
++    IBV_SM_EVENT_MCG_CREATED
++         An MCG specified by the "mgid" has been created
++         on this subnet.
++
++    IBV_SM_EVENT_MCG_DELETED
++         The MCG specified by the "mgid" has been deleted
++         on this subnet.
++
++    IBV_SM_EVENT_GID_AVAIL
++         The GID specified by the "guid" is available
++         on this subnet.
++
++    IBV_SM_EVENT_GID_UNAVAIL
++         The GID specified by the "guid" is no longer
++         available on this subnet.
++
++.SH OPTIONS
++.pp
++\-G               Monitor SM event for Unicast GIDs
++.sp
++.pp
++\-M               Monitor SM event for Multicast GIDs
++.pp
++\-s<GUID>         Takes as an optional argument a comma separated list of remote port GUIDs if \-G is specified or Multicast GIDs if \-M is specified.
++.sp
++.PP
++\-p <port>        use the specified ca_port.
++.sp
++.pp
++.SH EXAMPLES
++.PP
++To monitor event=IBV_SM_EVENT_ALL
++.sp
++ibv_asyncwatch -s
++.sp
++To monitor event=IBV_SM_EVENT_UGID_ALL
++.sp
++ibv_asyncwatch -G -s
++.sp
++To monitor event=IBV_SM_EVENT_MGID_ALL
++.sp
++ibv_asyncwatch -M -s
++.sp
++To monitor event=IBV_SM_EVENT_UGID
++.sp
++ibv_asyncwatch -G -s0x0021280001a0e4d9,0x0021280001a0e4da
++.sp
++To monitor event=IBV_SM_EVENT_MGID
++.sp
++ibv_asyncwatch -M -s0xff12:4001:ffff::c:2238
++.sp
 diff -r -u /tmp/846623/libibverbs-1.1.4/man/ibv_open_device.3 libibverbs-1.1.4/man/ibv_open_device.3
 --- /tmp/846623/libibverbs-1.1.4/man/ibv_open_device.3	Thu Mar 10 04:51:46 2011
 +++ libibverbs-1.1.4/man/ibv_open_device.3	Mon Mar 28 03:11:46 2011
@@ -473,7 +577,7 @@
  	char name[24];
  	char attr[8];
  	uint16_t val;
[email protected]@ -133,6 +151,7 @@
[email protected]@ -133,9 +151,142 @@
  
  	*pkey = htons(val);
  	return 0;
@@ -481,7 +585,142 @@
  }
  default_symver(__ibv_query_pkey, ibv_query_pkey);
  
[email protected]@ -148,6 +167,27 @@
++int ibv_register_sm_events(struct ibv_context *context,
++    ibv_sm_event_type_t event, uint_t gid_num, union ibv_gid *gids)
++{
++	struct ibv_reg_sm_event		*cmd;
++	int				rc, cmd_size, data_size;
++	void				*data_p;
++
++	if (((gid_num > 0) && (gids == NULL)) ||
++	   ((gid_num == 0) && (gids != NULL))) {
++		errno = EINVAL;
++		return (-1);
++	}
++
++	if ((event != IBV_SM_EVENT_UGID) && (event != IBV_SM_EVENT_UGID_ALL) &&
++	    (event != IBV_SM_EVENT_MGID) && (event != IBV_SM_EVENT_MGID_ALL) &&
++	    (event != IBV_SM_EVENT_ALL)) {
++		errno = EINVAL;
++		return (-1);
++	}
++
++	if (((event == IBV_SM_EVENT_UGID) || (event == IBV_SM_EVENT_MGID)) &&
++	    (gid_num == 0)) {
++		errno = EINVAL;
++		return (-1);
++	}
++
++	if (((event == IBV_SM_EVENT_UGID_ALL) ||
++	    (event == IBV_SM_EVENT_MGID_ALL) || (event == IBV_SM_EVENT_ALL)) &&
++	    (gid_num != 0)) {
++		errno = EINVAL;
++		return (-1);
++	}
++
++	data_size = gid_num * (sizeof (union ibv_gid));
++	cmd_size = (sizeof (struct ibv_reg_sm_event)) + data_size;
++	data_p = (void *)gids;
++	cmd  = alloca(cmd_size);
++	cmd->data_num = gid_num;
++
++	IBV_INIT_CMD(cmd, cmd_size, REG_SM_EVENT);
++
++	cmd->events = event;
++	if (gid_num > 0)
++		memcpy(cmd->driver_data, data_p, data_size);
++
++	rc = write(context->cmd_fd, cmd, cmd_size);
++	if (rc < 0) {
++		errno = -rc;
++		rc = -1;
++	}
++
++	return (rc);
++}
++
++int ibv_unregister_sm_events(struct ibv_context *context,
++    ibv_sm_event_type_t event, uint_t gid_num, union ibv_gid *gids)
++{
++	struct ibv_unreg_sm_event	*cmd;
++	int				rc, cmd_size, data_size;
++	void				*data_p;
++
++	if (((gid_num > 0) && (gids == NULL)) ||
++	   ((gid_num == 0) && (gids != NULL))) {
++		errno = EINVAL;
++		return (-1);
++	}
++
++	if ((event != IBV_SM_EVENT_UGID) && (event != IBV_SM_EVENT_UGID_ALL) &&
++	    (event != IBV_SM_EVENT_MGID) && (event != IBV_SM_EVENT_MGID_ALL) &&
++	    (event != IBV_SM_EVENT_ALL)) {
++		errno = EINVAL;
++		return (-1);
++	}
++
++	if (((event == IBV_SM_EVENT_UGID) || (event == IBV_SM_EVENT_MGID)) &&
++	    (gid_num == 0)) {
++		errno = EINVAL;
++		return (-1);
++	}
++
++	if (((event == IBV_SM_EVENT_UGID_ALL) ||
++	    (event == IBV_SM_EVENT_MGID_ALL) || (event == IBV_SM_EVENT_ALL)) &&
++	    (gid_num != 0)) {
++		errno = EINVAL;
++		return (-1);
++	}
++
++	data_size = gid_num*(sizeof (union ibv_gid));
++	cmd_size = (sizeof (struct ibv_unreg_sm_event)) + data_size;
++	data_p = (void *)gids;
++	cmd  = alloca(cmd_size);
++	cmd->data_num = gid_num;
++
++	IBV_INIT_CMD(cmd, cmd_size, UNREG_SM_EVENT);
++
++	cmd->events = event;
++	if (gid_num > 0)
++		memcpy(cmd->driver_data, data_p, data_size);
++
++	rc = write(context->cmd_fd, cmd, cmd_size);
++	if (rc < 0) {
++		errno = -rc;
++		rc = -1;
++	}
++
++	return (rc);
++}
++
++int ibv_gid_reachable(struct ibv_context *context,
++    uint_t port, union ibv_gid *gid_p, int timeout)
++{
++	struct ibv_gid_reachable	*cmd;
++	int				rc;
++
++	cmd = alloca((sizeof (struct ibv_gid_reachable)));
++	cmd->port_num = port;
++	cmd->timeout = timeout;
++
++	IBV_INIT_CMD(cmd, sizeof (struct ibv_gid_reachable),
++	    GID_REACHABLE);
++
++	memcpy(cmd->gid, gid_p, sizeof (*gid_p));
++
++	rc = write(context->cmd_fd, cmd, sizeof(struct ibv_gid_reachable));
++	if (rc < 0) {
++		errno = -rc;
++		rc = -1;
++	}
++
++	return (rc);
++}
++
+ struct ibv_pd *__ibv_alloc_pd(struct ibv_context *context)
+ {
+ 	struct ibv_pd *pd;
[email protected]@ -148,6 +299,27 @@
  }
  default_symver(__ibv_alloc_pd, ibv_alloc_pd);
  
@@ -509,7 +748,7 @@
  int __ibv_dealloc_pd(struct ibv_pd *pd)
  {
  	return pd->context->ops.dealloc_pd(pd);
[email protected]@ -175,6 +215,27 @@
[email protected]@ -175,6 +347,27 @@
  }
  default_symver(__ibv_reg_mr, ibv_reg_mr);
  
@@ -537,7 +776,7 @@
  int __ibv_dereg_mr(struct ibv_mr *mr)
  {
  	int ret;
[email protected]@ -189,6 +250,26 @@
[email protected]@ -189,6 +382,26 @@
  }
  default_symver(__ibv_dereg_mr, ibv_dereg_mr);
  
@@ -564,7 +803,7 @@
  static struct ibv_comp_channel *ibv_create_comp_channel_v2(struct ibv_context *context)
  {
  	struct ibv_abi_compat_v2 *t = context->abi_compat;
[email protected]@ -212,6 +293,10 @@
[email protected]@ -212,6 +425,10 @@
  	struct ibv_comp_channel            *channel;
  	struct ibv_create_comp_channel      cmd;
  	struct ibv_create_comp_channel_resp resp;
@@ -575,7 +814,7 @@
  
  	if (abi_ver <= 2)
  		return ibv_create_comp_channel_v2(context);
[email protected]@ -221,7 +306,23 @@
[email protected]@ -221,7 +438,23 @@
  		return NULL;
  
  	IBV_INIT_CMD_RESP(&cmd, sizeof cmd, CREATE_COMP_CHANNEL, &resp, sizeof resp);
@@ -599,7 +838,7 @@
  		free(channel);
  		return NULL;
  	}
[email protected]@ -228,6 +329,9 @@
[email protected]@ -228,6 +461,9 @@
  
  	VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp);
  
@@ -677,6 +916,22 @@
  	close(async_fd);
  	close(cmd_fd);
  	if (abi_ver <= 2)
[email protected]@ -214,6 +249,15 @@
+ 		case IBV_EVENT_SRQ_LIMIT_REACHED:
+ 			event->element.srq = (void *) (uintptr_t) ev.element;
+ 			break;
++		case IBV_EVENT_GID_AVAIL:
++		case IBV_EVENT_GID_UNAVAIL:
++		case IBV_EVENT_MCG_CREATED:
++		case IBV_EVENT_MCG_DELETED:
++			event->element.gid.global.subnet_prefix
++			    = ev.subnet_prefix;
++                        event->element.gid.global.interface_id
++			    = ev.interface_id;
++			break;
+ 		default:
+ 			event->element.port_num = ev.element;
+ 			break;
 diff -r -u /tmp/846623/libibverbs-1.1.4/src/ibverbs.h libibverbs-1.1.4/src/ibverbs.h
 --- /tmp/846623/libibverbs-1.1.4/src/ibverbs.h	Wed Sep 16 04:27:22 2009
 +++ libibverbs-1.1.4/src/ibverbs.h	Fri Feb 11 04:02:31 2011
@@ -697,9 +952,13 @@
 diff -r -u /tmp/846623/libibverbs-1.1.4/src/libibverbs.map libibverbs-1.1.4/src/libibverbs.map
 --- /tmp/846623/libibverbs-1.1.4/src/libibverbs.map	Thu Mar 10 06:58:21 2011
 +++ libibverbs-1.1.4/src/libibverbs.map	Mon Mar 28 13:44:44 2011
[email protected]@ -13,9 +13,14 @@
[email protected]@ -12,10 +12,18 @@
+ 		ibv_query_port;
  		ibv_query_gid;
  		ibv_query_pkey;
++		ibv_register_sm_events;
++		ibv_unregister_sm_events;
++		ibv__gid_reachable;
  		ibv_alloc_pd;
 +		ibv_alloc_shpd;
 +		ibv_share_pd;
@@ -712,7 +971,7 @@
  		ibv_create_comp_channel;
  		ibv_destroy_comp_channel;
  		ibv_create_cq;
[email protected]@ -41,9 +46,14 @@
[email protected]@ -41,9 +49,14 @@
  		ibv_cmd_query_gid;
  		ibv_cmd_query_pkey;
  		ibv_cmd_alloc_pd;
@@ -727,7 +986,7 @@
  		ibv_cmd_create_cq;
  		ibv_cmd_poll_cq;
  		ibv_cmd_req_notify_cq;
[email protected]@ -71,6 +81,7 @@
[email protected]@ -71,6 +84,7 @@
  		mult_to_ibv_rate;
  		ibv_get_sysfs_path;
  		ibv_read_sysfs_file;
@@ -1103,14 +1362,22 @@
 diff -r -u /tmp/846623/libibverbs-1.1.4/src/enum_strs.c libibverbs-1.1.4/src/enum_strs.c
 --- /tmp/846623/libibverbs-1.1.4/src/enum_strs.c	Wed Sep 16 04:27:22 2009
 +++ libibverbs-1.1.4/src/enum_strs.c	Tue Mar 20 16:27:45 2012
[email protected]@ -85,6 +85,7 @@
[email protected]@ -85,9 +85,14 @@
  		[IBV_EVENT_SRQ_LIMIT_REACHED]	= "SRQ limit reached",
  		[IBV_EVENT_QP_LAST_WQE_REACHED]	= "last WQE reached",
  		[IBV_EVENT_CLIENT_REREGISTER]	= "client reregistration",
 +		[IBV_EVENT_GID_CHANGE]		= "GID change",
++		[IBV_EVENT_MCG_CREATED]		= "MCG created",
++		[IBV_EVENT_MCG_DELETED]		= "MCG deleted",
++		[IBV_EVENT_GID_AVAIL]		= "GID available",
++		[IBV_EVENT_GID_UNAVAIL]		= "GID unavailable",
  	};
  
- 	if (event < IBV_EVENT_CQ_ERR || event > IBV_EVENT_CLIENT_REREGISTER)
+-	if (event < IBV_EVENT_CQ_ERR || event > IBV_EVENT_CLIENT_REREGISTER)
++	if (event < IBV_EVENT_CQ_ERR || event > IBV_EVENT_GID_UNAVAIL)
+ 		return "unknown";
+ 
+ 	return event_type_str[event];
 diff -r -u /tmp/846623/libibverbs-1.1.4/src/sysfs.c libibverbs-1.1.4/src/sysfs.c
 --- /tmp/846623/libibverbs-1.1.4/src/sysfs.c	Wed Sep 16 04:27:22 2009
 +++ libibverbs-1.1.4/src/sysfs.c	Fri Feb 11 04:02:33 2011
@@ -1277,7 +1544,7 @@
  
  /*
   * This file must be kept in sync with the kernel's version of
[email protected]@ -94,6 +98,11 @@
[email protected]@ -94,6 +98,14 @@
  	IB_USER_VERBS_CMD_QUERY_XRC_RCV_QP,
  	IB_USER_VERBS_CMD_REG_XRC_RCV_QP,
  	IB_USER_VERBS_CMD_UNREG_XRC_RCV_QP,
@@ -1285,11 +1552,23 @@
 +	IB_USER_VERBS_CMD_DEREG_MR_RELAXED,
 +	IB_USER_VERBS_CMD_FLUSH_RELAXED_MR,
 +	IB_USER_VERBS_CMD_ALLOC_SHPD,
-+	IB_USER_VERBS_CMD_SHARE_PD
++	IB_USER_VERBS_CMD_SHARE_PD,
++	IB_USER_VERBS_CMD_REG_SM_EVENT,
++	IB_USER_VERBS_CMD_UNREG_SM_EVENT,
++	IB_USER_VERBS_CMD_GID_REACHABLE
  };
  
  /*
[email protected]@ -160,6 +169,7 @@
[email protected]@ -111,6 +123,8 @@
+ 	__u64 element;
+ 	__u32 event_type;
+ 	__u32 reserved;
++	__u64 subnet_prefix;
++	__u64 interface_id;
+ };
+ 
+ struct ibv_comp_event {
[email protected]@ -160,6 +174,7 @@
  struct ibv_query_device_resp {
  	__u64 fw_ver;
  	__u64 node_guid;
@@ -1297,7 +1576,42 @@
  	__u64 sys_image_guid;
  	__u64 max_mr_size;
  	__u64 page_size_cap;
[email protected]@ -243,10 +253,57 @@
[email protected]@ -235,6 +250,34 @@
+ 	__u8  reserved[2];
+ };
+ 
++struct ibv_reg_sm_event {
++	__u32 command;
++	__u16 in_words;
++	__u16 out_words;
++	__u32 events;
++	__u32 data_num;
++	__u64 driver_data[0];
++};
++
++struct ibv_unreg_sm_event {
++	__u32 command;
++	__u16 in_words;
++	__u16 out_words;
++	__u32 events;
++	__u32 data_num;
++	__u64 driver_data[0];
++};
++
++struct ibv_gid_reachable {
++	__u32 command;
++	__u16 in_words;
++	__u16 out_words;
++	__u32 timeout;
++	__u8  port_num;
++	__u8  reserved[3];
++	__u8  gid[16];
++};
++
+ struct ibv_alloc_pd {
+ 	__u32 command;
+ 	__u16 in_words;
[email protected]@ -243,10 +286,57 @@
  	__u64 driver_data[0];
  };
  
@@ -1355,7 +1669,7 @@
  struct ibv_dealloc_pd {
  	__u32 command;
  	__u16 in_words;
[email protected]@ -280,6 +337,13 @@
[email protected]@ -280,6 +370,13 @@
  	__u32 mr_handle;
  };
  
@@ -1369,7 +1683,7 @@
  struct ibv_create_comp_channel {
  	__u32 command;
  	__u16 in_words;
[email protected]@ -304,10 +368,25 @@
[email protected]@ -304,10 +401,25 @@
  	__u64 driver_data[0];
  };
  
@@ -1395,7 +1709,7 @@
  
  struct ibv_kern_wc {
  	__u64  wr_id;
[email protected]@ -363,7 +442,11 @@
[email protected]@ -363,7 +475,11 @@
  struct ibv_resize_cq_resp {
  	__u32 cqe;
  	__u32 reserved;
@@ -1407,7 +1721,7 @@
  };
  
  struct ibv_destroy_cq {
[email protected]@ -460,6 +543,14 @@
[email protected]@ -460,6 +576,14 @@
  	__u64 driver_data[0];
  };
  
@@ -1422,7 +1736,7 @@
  struct ibv_create_qp_resp {
  	__u32 qp_handle;
  	__u32 qpn;
[email protected]@ -469,7 +560,20 @@
[email protected]@ -469,7 +593,20 @@
  	__u32 max_recv_sge;
  	__u32 max_inline_data;
  	__u32 reserved;
@@ -1443,7 +1757,7 @@
  
  struct ibv_qp_dest {
  	__u8  dgid[16];
[email protected]@ -817,12 +921,29 @@
[email protected]@ -817,12 +954,29 @@
  	__u64 driver_data[0];
  };
  
@@ -1473,7 +1787,7 @@
  
  struct ibv_modify_srq {
  	__u32 command;
[email protected]@ -946,6 +1067,11 @@
[email protected]@ -946,6 +1100,14 @@
  	IB_USER_VERBS_CMD_QUERY_XRC_RCV_QP_V2 = -1,
  	IB_USER_VERBS_CMD_REG_XRC_RCV_QP_V2 = -1,
  	IB_USER_VERBS_CMD_UNREG_XRC_RCV_QP_V2 = -1,
@@ -1482,6 +1796,9 @@
 +	IB_USER_VERBS_CMD_FLUSH_RELAXED_MR_V2 = -1,
 +  	IB_USER_VERBS_CMD_ALLOC_SHPD_V2 = -1,
 +  	IB_USER_VERBS_CMD_SHARE_PD_V2 = -1,
++	IB_USER_VERBS_CMD_REG_SM_EVENT_V2 = -1,
++	IB_USER_VERBS_CMD_UNREG_SM_EVENT_V2 = -1,
++	IB_USER_VERBS_CMD_GID_REACHABLE_V2 = -1,
  };
  
  struct ibv_destroy_cq_v1 {
@@ -1551,7 +1868,39 @@
  	uint64_t		sys_image_guid;
  	uint64_t		max_mr_size;
  	uint64_t		page_size_cap;
[email protected]@ -297,7 +301,8 @@
[email protected]@ -212,6 +216,10 @@
+ 	IBV_EVENT_QP_LAST_WQE_REACHED,
+ 	IBV_EVENT_CLIENT_REREGISTER,
+ 	IBV_EVENT_GID_CHANGE,
++	IBV_EVENT_MCG_CREATED,
++	IBV_EVENT_MCG_DELETED,
++	IBV_EVENT_GID_AVAIL,
++	IBV_EVENT_GID_UNAVAIL,
+ };
+ 
+ enum ibv_event_flags {
[email protected]@ -225,10 +233,20 @@
+ 		struct ibv_srq *srq;
+ 		int		port_num;
+ 		uint32_t	xrc_qp_num;
++		union ibv_gid	gid;
+ 	} element;
+ 	enum ibv_event_type	event_type;
+ };
+ 
++typedef enum ibv_sm_event_type_e {
++	IBV_SM_EVENT_MGID	= 1,
++	IBV_SM_EVENT_MGID_ALL	= 1 << 2,
++	IBV_SM_EVENT_UGID	= 1 << 3,
++	IBV_SM_EVENT_UGID_ALL	= 1 << 4,
++        IBV_SM_EVENT_ALL	= 1 << 5
++
++} ibv_sm_event_type_t;
++
+ enum ibv_wc_status {
+ 	IBV_WC_SUCCESS,
+ 	IBV_WC_LOC_LEN_ERR,
[email protected]@ -297,7 +315,8 @@
  	IBV_ACCESS_REMOTE_WRITE		= (1<<1),
  	IBV_ACCESS_REMOTE_READ		= (1<<2),
  	IBV_ACCESS_REMOTE_ATOMIC	= (1<<3),
@@ -1561,7 +1910,7 @@
  };
  
  struct ibv_pd {
[email protected]@ -305,6 +310,10 @@
[email protected]@ -305,6 +324,10 @@
  	uint32_t		handle;
  };
  
@@ -1572,7 +1921,7 @@
  enum ibv_rereg_mr_flags {
  	IBV_REREG_MR_CHANGE_TRANSLATION	= (1 << 0),
  	IBV_REREG_MR_CHANGE_PD		= (1 << 1),
[email protected]@ -425,6 +434,14 @@
[email protected]@ -425,6 +448,14 @@
  	uint32_t		max_inline_data;
  };
  
@@ -1587,7 +1936,7 @@
  struct ibv_qp_init_attr {
  	void		       *qp_context;
  	struct ibv_cq	       *send_cq;
[email protected]@ -743,6 +760,12 @@
[email protected]@ -743,6 +774,12 @@
  	int			(*detach_mcast)(struct ibv_qp *qp, const union ibv_gid *gid,
  						uint16_t lid);
  	void			(*async_event)(struct ibv_async_event *event);
@@ -1600,7 +1949,7 @@
  };
  
  struct ibv_context {
[email protected]@ -749,6 +772,13 @@
[email protected]@ -749,6 +786,13 @@
  	struct ibv_device      *device;
  	struct ibv_context_ops	ops;
  	int			cmd_fd;
@@ -1614,7 +1963,7 @@
  	int			async_fd;
  	int			num_comp_vectors;
  	pthread_mutex_t		mutex;
[email protected]@ -797,6 +827,11 @@
[email protected]@ -797,6 +841,11 @@
  uint64_t ibv_get_device_guid(struct ibv_device *device);
  
  /**
@@ -1626,7 +1975,31 @@
   * ibv_open_device - Initialize device for use
   */
  struct ibv_context *ibv_open_device(struct ibv_device *device);
[email protected]@ -858,6 +893,20 @@
[email protected]@ -853,11 +902,44 @@
+ 		   int index, uint16_t *pkey);
+ 
+ /**
++ * ibv_register_sm_events - Register subnet event for GID change
++ */
++int ibv_register_sm_events(struct ibv_context *context,
++    ibv_sm_event_type_t event, uint_t gid_num, union ibv_gid *gids);
++
++/**
++ * ibv_unregister_sm_events - Unregister subnet event for GID change
++ */
++int ibv_unregister_sm_events(struct ibv_context *context,
++    ibv_sm_event_type_t event, uint_t gid_num, union ibv_gid *gids);
++
++/**
++ * ibv_gid_reachable - To contact subnet agent for GID status; reachable or
++ * not reachable
++ */
++int ibv_gid_reachable(struct ibv_context *context,
++    uint port, union ibv_gid *gid_p, int timeout);
++
++/**
+  * ibv_alloc_pd - Allocate a protection domain
+  */
  struct ibv_pd *ibv_alloc_pd(struct ibv_context *context);
  
  /**
@@ -1647,7 +2020,7 @@
   * ibv_dealloc_pd - Free a protection domain
   */
  int ibv_dealloc_pd(struct ibv_pd *pd);
[email protected]@ -869,11 +918,27 @@
[email protected]@ -869,11 +951,27 @@
  			  size_t length, int access);
  
  /**
@@ -1795,10 +2168,16 @@
 diff -r -u /tmp/846623/libibverbs-1.1.4/examples/asyncwatch.c libibverbs-1.1.4/examples/asyncwatch.c
 --- /tmp/846623/libibverbs-1.1.4/examples/asyncwatch.c	Thu Mar 10 06:58:21 2011
 +++ libibverbs-1.1.4/examples/asyncwatch.c	Fri Feb 11 04:02:18 2011
[email protected]@ -35,8 +35,10 @@
[email protected]@ -35,11 +35,72 @@
  #endif /* HAVE_CONFIG_H */
  
  #include <stdio.h>
++#include <stdlib.h>
++#include <ctype.h>
++#include <getopt.h>
++#include <signal.h>
++#include <string.h>
++#include <strings.h>
 +#if !(defined(__SVR4) && defined(__sun))
  #include <endian.h>
  #include <byteswap.h>
@@ -1806,6 +2185,375 @@
  
  #include <infiniband/verbs.h>
  
++#define IS_PORT_EVENT(event)				\
++	((event == IBV_EVENT_PORT_ACTIVE) ||		\
++	(event == IBV_EVENT_PORT_ERR ) ||		\
++	(event == IBV_EVENT_LID_CHANGE) ||		\
++	(event == IBV_EVENT_PKEY_CHANGE) ||		\
++	(event == IBV_EVENT_SM_CHANGE) ||		\
++	(event == IBV_EVENT_GID_CHANGE) ||		\
++	(event == IBV_EVENT_CLIENT_REREGISTER))
++
++#define IS_SM_EVENT(event)				\
++	((event == IBV_EVENT_MCG_CREATED) ||		\
++	(event == IBV_EVENT_MCG_DELETED) ||		\
++	(event == IBV_EVENT_GID_AVAIL) ||		\
++	(event == IBV_EVENT_GID_UNAVAIL))
++
++#define IS_QP_EVENT(event)				\
++	((event == IBV_EVENT_CQ_ERR) ||			\
++	(event == IBV_EVENT_QP_FATAL) ||		\
++	(event == IBV_EVENT_QP_REQ_ERR) ||		\
++	(event == IBV_EVENT_COMM_EST) ||		\
++	(event == IBV_EVENT_SQ_DRAINED) ||		\
++	(event == IBV_EVENT_PATH_MIG) ||		\
++	(event == IBV_EVENT_PATH_MIG_ERR) ||		\
++	(event == IBV_EVENT_QP_LAST_WQE_REACHED) ||	\
++	(event == IBV_EVENT_QP_ACCESS_ERR))
++
++#define IS_CQ_EVENT(event)				\
++	(event == IBV_EVENT_CQ_ERR)
++
++#define IS_SRQ_EVENT(event)				\
++	((event == IBV_EVENT_SRQ_ERR) ||		\
++	(event == IBV_EVENT_SRQ_LIMIT_REACHED))
++
++#define IS_CA_EVENT(event)				\
++	(event == IBV_EVENT_DEVICE_FATAL)
++
++
++struct ibv_device	**dev_list;
++struct ibv_context	*context;
++struct ibv_async_event	event;
++union ibv_gid		*gids = NULL;
++uint_t			num_gids = 0;
++ibv_sm_event_type_t	events;
++
++static struct option long_options[] = {
++    {"sm",		0, 0, 's'},
++    {"GUID",		0, 0, 'G'},
++    {"MCG",		0, 0, 'M'},
++    {"port",		1, 0, 'p'},
++    {0, 0, 0, 0}
++};
++
++
+ static const char *event_name_str(enum ibv_event_type event_type)
+ {
+ 	switch (event_type) {
[email protected]@ -59,7 +120,14 @@
+ 		return "IBV_EVENT_CLIENT_REREGISTER";
+ 	case IBV_EVENT_GID_CHANGE:
+ 		return "IBV_EVENT_GID_CHANGE";
+-
++	case IBV_EVENT_MCG_CREATED:
++		return "IBV_EVENT_MCG_CREATED";
++	case IBV_EVENT_MCG_DELETED:
++		return "IBV_EVENT_MCG_DELETED";
++	case IBV_EVENT_GID_AVAIL:
++		return "IBV_EVENT_GID_AVAIL";
++	case IBV_EVENT_GID_UNAVAIL:
++		return "IBV_EVENT_GID_UNAVAIL";
+ 	case IBV_EVENT_CQ_ERR:
+ 	case IBV_EVENT_QP_FATAL:
+ 	case IBV_EVENT_QP_REQ_ERR:
[email protected]@ -76,15 +144,173 @@
+ 	}
+ }
+ 
+-int main(int argc, char *argv[])
++static void catch_signal(int sig_num)
+ {
+-	struct ibv_device **dev_list;
+-	struct ibv_context *context;
+-	struct ibv_async_event event;
++	ibv_unregister_sm_events(context, events, num_gids, gids);
++	if (gids)
++		free(gids);
++	ibv_close_device(context);
++	(void) ibv_free_device_list(dev_list);
++	exit (0);
++}
+ 
+-	/* Force line-buffering in case stdout is redirected */
+-	setvbuf(stdout, NULL, _IOLBF, 0);
++static void usage(const char *argv0)
++{
++	printf("Usage:\n");
++	printf("\n");
++	printf("Options:\n");
++	printf("[ -s, --sm<gid> ]\t\tsm event\n");
++	printf("[ -M, --M ]\t\t\tsm event for MGID (multicast)\n");
++	printf("[ -G, --G ]\t\t\tsm event for UGID (unicast)\n");
++	printf("[ -p, --port=<port> ]\t\t(default 1)\n");
++	printf("\nExamples;\n");
++	printf("ibv_asyncwatch -s\t\t# monitor event=IBV_SM_EVENT_ALL\n");
++	printf("ibv_asyncwatch -G -s\t\t# monitor event="
++	    "IBV_SM_EVENT_UGID_ALL\n");
++	printf("ibv_asyncwatch -M -s\t\t# monitor event="
++	    "IBV_SM_EVENT_MGID_ALL\n");
++	printf("ibv_asyncwatch -G -s0x0021280001a0e4d9,0x0021280001a0e4da\n");
++	printf("\t\t\t\t# monitor event=IBV_SM_EVENT_UGID\n");
++	printf("ibv_asyncwatch -M -s0xff12:4001:ffff::c:2238,");
++	printf("0xff12:ffff::38:220c\n");
++	printf("\t\t\t\t# monitor event=IBV_SM_EVENT_MGID\n");
++}
+ 
++
++uint_t get_gids(char *argptr, uint64_t subnet_prefix)
++{
++	char		*curr, *next;
++	char		*guid_str_p1, *guid_str_p2 = NULL;
++	int		i = 0;
++	int		data_num;
++
++	for (curr = argptr; curr; curr = next, i++) {
++		next = strchr(curr, ',');
++		if (next)
++			next++;
++        }
++	data_num = i;
++	if (data_num == 0)
++		return (0);
++
++	gids = (union ibv_gid *)calloc(data_num, sizeof (union ibv_gid));
++	guid_str_p1 = malloc(strlen(argptr));
++	strncpy(guid_str_p1, argptr, strlen(argptr));
++
++	i = 0;
++	guid_str_p2 = strtok(guid_str_p1, (const char *)",");
++	while (guid_str_p2 != NULL) {
++		gids[i].global.subnet_prefix = subnet_prefix;
++		gids[i].global.interface_id =
++		    htonll((uint64_t)strtoull(guid_str_p2, 0, 0));
++		i++;
++		guid_str_p2 = strtok(NULL, (const char *)",");
++	}
++	free (guid_str_p1);
++	return (data_num);
++}
++
++void process_one_mcg_gid(union ibv_gid *gid, char *mcg_str)
++{
++	char		*token, *token_p, half_token[3];
++	uint8_t		mcg_gid[16];
++	int		i, j = 0, num_data = -1;
++	char		*curr, *next;
++
++	/* find out how many two-byte data from command line input */
++	for (curr = mcg_str; curr; curr = next, num_data++) {
++		next = strchr(curr, ':');
++		if (next)
++			next++;
++        }
++
++	if (num_data > 8) {
++		fprintf(stderr, "Invalid MGID input format: %s\n", mcg_str);
++		exit (-1);
++	}
++
++	curr = mcg_str + 2;	/* Skip past 0x */
++	while ((token = strsep(&curr, ":")) != NULL && j < 15) {
++		if (strncmp(token, "\0", 1) == 0) {
++			/* We have :: in the input */
++			for (i = 0; i < 8 - num_data; i++) {
++				mcg_gid[j++] = 0;
++				mcg_gid[j++] = 0;
++			}
++		} else {
++			if (strlen(token) < 3) {
++				mcg_gid[j++] = 0;
++				mcg_gid[j++] =
++				    (uint8_t)strtoll(token, NULL, 16);
++			} else {
++				memset(half_token, 0, 3);
++				token_p = token;
++				if (strlen(token) == 3) {
++					strncpy(half_token, token, 1);
++					token_p += 1;
++				} else {
++					strncpy(half_token, token, 2);
++					token_p += 2;
++				}
++				mcg_gid[j++] = (uint8_t)strtol(half_token,
++				    NULL, 16);
++
++				mcg_gid[j++] = (uint8_t)strtol(token_p,
++				    NULL, 16);
++			}
++		}
++	}
++
++	memcpy(gid->raw, mcg_gid, 16);
++}
++
++uint_t get_mcgs(char *argptr, uint64_t subnet_prefix)
++{
++	char            *curr, *next;
++	char		*mcg_str_p1, *mcg_str_p2 = NULL;
++	int		i = 0;
++	int		data_num;
++
++	for (curr = argptr; curr; curr = next, i++) {
++		next = strchr(curr, ',');
++		if (next)
++			next++;
++        }
++	data_num = i;
++	if (data_num == 0)
++		return (0);
++
++	gids = (union ibv_gid *)calloc(data_num, sizeof (union ibv_gid));
++	mcg_str_p1 = malloc(strlen(argptr));
++	strncpy(mcg_str_p1, argptr, strlen(argptr));
++
++	i = 0;
++	mcg_str_p2 = strtok(mcg_str_p1, (const char *)",");
++	while (mcg_str_p2 != NULL) {
++		if (strncmp(mcg_str_p2, "0xff", 4) != 0) {
++			fprintf(stderr, "Invalid MGID input format: %s\n",
++			    mcg_str_p2);
++			exit (-1);
++		}
++		process_one_mcg_gid(&gids[i], mcg_str_p2);
++		i++;
++		mcg_str_p2 = strtok(NULL, (const char *)",");
++	}
++	free(mcg_str_p1);
++	return (data_num);
++}
++
++int main(int argc, char *argv[])
++{
++	int		c;
++	int		ret;
++	uint_t		port = 1;	/* default */
++	uint_t		do_sm_event_register = 0;
++	union ibv_gid	sgid;
++	uint64_t	subnet_prefix = 0ULL;
++	int		mcgflag = 0;
++	int		guidflag = 0;
++
+ 	dev_list = ibv_get_device_list(NULL);
+ 	if (!dev_list) {
+ 		perror("Failed to get IB devices list");
[email protected]@ -103,19 +329,111 @@
+ 		return 1;
+ 	}
+ 
+-	printf("%s: async event FD %d\n",
++	printf("\n%s: async event FD %d\n\n",
+ 	       ibv_get_device_name(*dev_list), context->async_fd);
+ 
++	ibv_query_gid(context, port, 0, &sgid);
++	subnet_prefix = sgid.global.subnet_prefix;
++
++	while ((c = getopt_long(argc, argv, "p:GMs::t:", long_options, NULL))
++	    != -1) {
++		switch(c) {
++			case 'G':
++				guidflag = 1;
++				break;
++			case 'M':
++				mcgflag = 1;
++				break;
++			case 's':
++				do_sm_event_register = 1;
++				if (mcgflag == 1)
++					num_gids =
++					    get_mcgs(optarg, subnet_prefix);
++				else
++					num_gids =
++					    get_gids(optarg, subnet_prefix);
++				break;
++			case 'p':
++				port = strtol(optarg, NULL, 0);
++				ibv_query_gid(context, port, 0, &sgid);
++				subnet_prefix = sgid.global.subnet_prefix;
++				break;
++			default:
++				usage(argv[0]);
++				return 1;
++		}
++	}
++
++	/* Force line-buffering in case stdout is redirected */
++	setvbuf(stdout, NULL, _IOLBF, 0);
++
++	if (num_gids) {
++		if (mcgflag)
++			events = IBV_SM_EVENT_MGID;
++		else
++			events = IBV_SM_EVENT_UGID;
++	} else {
++		if (mcgflag && guidflag)
++			events = IBV_SM_EVENT_ALL;
++		else if (mcgflag)
++			events = IBV_SM_EVENT_MGID_ALL;
++		else if (guidflag)
++			events = IBV_SM_EVENT_UGID_ALL;
++		else
++			events = IBV_SM_EVENT_ALL;
++	}
++
++	if (do_sm_event_register)
++		ret = ibv_register_sm_events(context, events, num_gids, gids);
++
++	(void) signal(SIGINT, catch_signal);
++
+ 	while (1) {
+ 		if (ibv_get_async_event(context, &event))
+ 			return 1;
+ 
+-		printf("  event_type %s (%d), port %d\n",
+-		       event_name_str(event.event_type),
+-		       event.event_type, event.element.port_num);
++		if (IS_PORT_EVENT(event.event_type))
++			printf("Event: %s (%d), port %d\n",
++			    event_name_str(event.event_type),
++			    event.event_type, event.element.port_num);
++		else if (IS_SM_EVENT(event.event_type))
++			printf("Event: %s (%d), gid " \
++			    "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"\
++			    "%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
++			    event_name_str(event.event_type), event.event_type,
++			    event.element.gid.raw[0], event.element.gid.raw[1],
++			    event.element.gid.raw[2], event.element.gid.raw[3],
++			    event.element.gid.raw[4], event.element.gid.raw[5],
++			    event.element.gid.raw[6], event.element.gid.raw[7],
++			    event.element.gid.raw[8], event.element.gid.raw[9],
++			    event.element.gid.raw[10],
++			    event.element.gid.raw[11],
++			    event.element.gid.raw[12],
++			    event.element.gid.raw[13],
++			    event.element.gid.raw[14],
++			    event.element.gid.raw[15]);
++		else if (IS_QP_EVENT(event.event_type))
++			printf("Event: %s (%d) QPN %d\n",
++			    event_name_str(event.event_type), event.event_type,
++			    event.element.qp->qp_num);
++		else if (IS_CQ_EVENT(event.event_type))
++			printf("Event: %s (%d) CQE %d\n",
++			    event_name_str(event.event_type), event.event_type,
++			    event.element.cq->cqe);
++		else if (IS_SRQ_EVENT(event.event_type))
++			printf("Event: %s (%d) SRQ %d\n",
++			    event_name_str(event.event_type), event.event_type,
++			    event.element.srq->handle);
++		else
++			printf("Event: %s (%d)\n",
++			    event_name_str(event.event_type), event.event_type);
+ 
+ 		ibv_ack_async_event(&event);
+-	}
+ 
++		if (event.event_type == IBV_EVENT_GID_AVAIL) {
++			ret = ibv_gid_reachable(context, port,
++			    &event.element.gid, 0);
++		}
++	}
+ 	return 0;
+ }
 diff -r -u /tmp/846623/libibverbs-1.1.4/examples/srq_pingpong.c libibverbs-1.1.4/examples/srq_pingpong.c
 --- /tmp/846623/libibverbs-1.1.4/examples/srq_pingpong.c	Thu Mar 10 06:58:21 2011
 +++ libibverbs-1.1.4/examples/srq_pingpong.c	Wed Jun  8 09:46:34 2011
--- a/components/open-fabrics/open-fabrics.p5m	Wed Jan 16 12:43:19 2013 -0800
+++ b/components/open-fabrics/open-fabrics.p5m	Thu Jan 17 09:36:55 2013 -0800
@@ -18,7 +18,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
 #
 <transform file path=usr.*/man/.+ -> default mangler.man.stability volatile>
 
@@ -321,6 +321,7 @@
 file path=usr/share/man/man3/ibv_get_device_guid.3 
 file path=usr/share/man/man3/ibv_get_device_list.3 
 file path=usr/share/man/man3/ibv_get_device_name.3 
+file path=usr/share/man/man3/ibv_gid_reachable.3
 file path=usr/share/man/man3/ibv_modify_qp.3 
 file path=usr/share/man/man3/ibv_modify_srq.3 
 file path=usr/share/man/man3/ibv_node_type_str.3 
@@ -339,6 +340,7 @@
 file path=usr/share/man/man3/ibv_rate_to_mult.3 
 file path=usr/share/man/man3/ibv_reg_mr.3 
 file path=usr/share/man/man3/ibv_reg_mr_relaxed.3 
+file path=usr/share/man/man3/ibv_register_sm_events.3
 file path=usr/share/man/man3/ibv_req_notify_cq.3 
 file path=usr/share/man/man3/ibv_resize_cq.3 
 file path=usr/share/man/man3/ibv_share_pd.3 
@@ -434,6 +436,7 @@
 link path=usr/share/man/man3/ibv_detach_mcast.3 target=ibv_attach_mcast.3 
 link path=usr/share/man/man3/ibv_free_device_list.3 target=ibv_get_device_list.3 
 link path=usr/share/man/man3/ibv_init_ah_from_wc.3 target=ibv_create_ah_from_wc.3 
+link path=usr/share/man/man3/ibv_unregister_sm_events.3 target=ibv_register_sm_events.3
 link path=usr/share/man/man3/mult_to_ibv_rate.3 target=ibv_rate_to_mult.3 
 license open-fabrics.license license='open-fabrics'