diff options
author | Sean Hefty <sean.hefty@intel.com> | 2006-10-04 14:37:25 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2006-10-10 15:50:38 -0400 |
commit | 82a9c16a10521a0ceadbd27a549f6e8d5e70e0ab (patch) | |
tree | 317ca9b4ed1f378dd61cf644aa469e836f904c20 /drivers/infiniband | |
parent | 8575329d4f8596519d86830f622d2c30601f3ef3 (diff) |
IB/cm: Send DREP in response to unmatched DREQ
Currently a DREP is only sent in response to a DREQ if a connection
has been found matching the DREQ, and it is in the proper state. Once
a DREP is sent, the local connection moves into timewait. Duplicate
DREQs received while in this state result in re-sending the DREP.
However, it's likely that the local connection will enter and exit
timewait before the remote side times out a lost DREP and resends a DREQ.
To handle this, we send a DREP in response to a DREQ, even if a local
connection is not found. This avoids maintaining disconnected
id's in timewait states for excessively long times, just to handle a
lost DREP.
Signed-off-by: Sean Hefty <sean.hefty@intel.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/core/cm.c | 30 |
1 files changed, 29 insertions, 1 deletions
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 470c482f2887..25b1018a476c 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c | |||
@@ -1902,6 +1902,32 @@ out: spin_unlock_irqrestore(&cm_id_priv->lock, flags); | |||
1902 | } | 1902 | } |
1903 | EXPORT_SYMBOL(ib_send_cm_drep); | 1903 | EXPORT_SYMBOL(ib_send_cm_drep); |
1904 | 1904 | ||
1905 | static int cm_issue_drep(struct cm_port *port, | ||
1906 | struct ib_mad_recv_wc *mad_recv_wc) | ||
1907 | { | ||
1908 | struct ib_mad_send_buf *msg = NULL; | ||
1909 | struct cm_dreq_msg *dreq_msg; | ||
1910 | struct cm_drep_msg *drep_msg; | ||
1911 | int ret; | ||
1912 | |||
1913 | ret = cm_alloc_response_msg(port, mad_recv_wc, &msg); | ||
1914 | if (ret) | ||
1915 | return ret; | ||
1916 | |||
1917 | dreq_msg = (struct cm_dreq_msg *) mad_recv_wc->recv_buf.mad; | ||
1918 | drep_msg = (struct cm_drep_msg *) msg->mad; | ||
1919 | |||
1920 | cm_format_mad_hdr(&drep_msg->hdr, CM_DREP_ATTR_ID, dreq_msg->hdr.tid); | ||
1921 | drep_msg->remote_comm_id = dreq_msg->local_comm_id; | ||
1922 | drep_msg->local_comm_id = dreq_msg->remote_comm_id; | ||
1923 | |||
1924 | ret = ib_post_send_mad(msg, NULL); | ||
1925 | if (ret) | ||
1926 | cm_free_msg(msg); | ||
1927 | |||
1928 | return ret; | ||
1929 | } | ||
1930 | |||
1905 | static int cm_dreq_handler(struct cm_work *work) | 1931 | static int cm_dreq_handler(struct cm_work *work) |
1906 | { | 1932 | { |
1907 | struct cm_id_private *cm_id_priv; | 1933 | struct cm_id_private *cm_id_priv; |
@@ -1913,8 +1939,10 @@ static int cm_dreq_handler(struct cm_work *work) | |||
1913 | dreq_msg = (struct cm_dreq_msg *)work->mad_recv_wc->recv_buf.mad; | 1939 | dreq_msg = (struct cm_dreq_msg *)work->mad_recv_wc->recv_buf.mad; |
1914 | cm_id_priv = cm_acquire_id(dreq_msg->remote_comm_id, | 1940 | cm_id_priv = cm_acquire_id(dreq_msg->remote_comm_id, |
1915 | dreq_msg->local_comm_id); | 1941 | dreq_msg->local_comm_id); |
1916 | if (!cm_id_priv) | 1942 | if (!cm_id_priv) { |
1943 | cm_issue_drep(work->port, work->mad_recv_wc); | ||
1917 | return -EINVAL; | 1944 | return -EINVAL; |
1945 | } | ||
1918 | 1946 | ||
1919 | work->cm_event.private_data = &dreq_msg->private_data; | 1947 | work->cm_event.private_data = &dreq_msg->private_data; |
1920 | 1948 | ||