--- /dev/null
+From 2c14e0b50d8f29f1186c5ab5c11837d1520df598 Mon Sep 17 00:00:00 2001
+From: Vipul Pandya <vipul@chelsio.com>
+Date: Thu, 8 Nov 2012 12:57:40 +0530
+Subject: [PATCH 07/11] RDMA/cxgb4: abort connections when moving to ERROR state.
+
+If a FINI operation fails, then we need to ABORT instead
+of CLOSE. Also, if we ABORT due to unexpected STREAMING
+data, then wake up anybody blocked in FINI...
+
+Signed-off-by: Vipul Pandya <vipul@chelsio.com>
+---
+ drivers/infiniband/hw/cxgb4/cm.c | 1 +
+ drivers/infiniband/hw/cxgb4/qp.c | 1 +
+ 2 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
+index 40f9b17..cb4c071 100644
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -1439,6 +1439,7 @@ static int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
+ mutex_lock(&ep->com.mutex);
+ switch (ep->com.state) {
+ case ABORTING:
++ c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
+ __state_set(&ep->com, DEAD);
+ release = 1;
+ break;
+diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
+index 05bfe53..17ba4f8 100644
+--- a/drivers/infiniband/hw/cxgb4/qp.c
++++ b/drivers/infiniband/hw/cxgb4/qp.c
+@@ -1383,6 +1383,7 @@ err:
+ qhp->ep = NULL;
+ set_state(qhp, C4IW_QP_STATE_ERROR);
+ free = 1;
++ abort = 1;
+ wake_up(&qhp->wait);
+ BUG_ON(!ep);
+ flush_qp(qhp);
+--
+1.7.1
+
--- /dev/null
+From 12bd8166547ede591410c6420d4665be6bedc8fd Mon Sep 17 00:00:00 2001
+From: Vipul Pandya <vipul@chelsio.com>
+Date: Thu, 8 Nov 2012 13:08:45 +0530
+Subject: [PATCH 08/11] RDMA/cxgb4: Display streaming mode error only if detected in RTS.
+
+With later firmware, the chances of getting streaming mode data after
+we exit RTS is likely, so we don't need to warn for it. The only real
+case where we don't expect it is when the QP is in RTS.
+
+move QP to ERROR when streaming mode data received.
+
+Signed-off-by: Vipul Pandya <vipul@chelsio.com>
+---
+ drivers/infiniband/hw/cxgb4/cm.c | 26 ++++++++++++++------------
+ 1 files changed, 14 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
+index cb4c071..58896f0 100644
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -1404,19 +1404,21 @@ static int rx_data(struct c4iw_dev *dev, struct sk_buff *skb)
+ ep->rcv_seq += dlen;
+ process_mpa_request(ep, skb);
+ break;
++ case FPDU_MODE: {
++ struct c4iw_qp_attributes attrs;
++ BUG_ON(!ep->com.qp);
++ if (ep->com.qp->attr.state == C4IW_QP_STATE_RTS)
++ pr_err("%s Unexpected streaming data." \
++ " ep %p state %d tid %u status %d\n",
++ __func__, ep, state_read(&ep->com),
++ ep->hwtid, status);
++ attrs.next_state = C4IW_QP_STATE_ERROR;
++ c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
++ C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
++ c4iw_ep_disconnect (ep, 1, GFP_KERNEL);
++ break;
++ }
+ default:
+- pr_err("%s Unexpected streaming data." \
+- " ep %p state %d tid %u status %d\n",
+- __func__, ep, state_read(&ep->com), ep->hwtid, status);
+-
+- if (ep->com.qp) {
+- struct c4iw_qp_attributes attrs;
+-
+- attrs.next_state = C4IW_QP_STATE_ERROR;
+- c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
+- C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
+- }
+- c4iw_ep_disconnect (ep, 1, GFP_KERNEL);
+ break;
+ }
+ return 0;
+--
+1.7.1
+
--- /dev/null
+From f4d76e45f4b9438c8b8918f481ba617dfa9a37d3 Mon Sep 17 00:00:00 2001
+From: Vipul Pandya <vipul@chelsio.com>
+Date: Thu, 8 Nov 2012 13:57:21 +0530
+Subject: [PATCH 09/11] RDMA/cxgb4: keep qp referenced until TID released.
+
+The driver is currently releasing the last ref on the QP too early.
+This can cause bus errors due to HW still fetching WRs from the hw queue.
+The fix is to keep a qp ref until we release the HW TID.
+
+Signed-off-by: Vipul Pandya <vipul@chelsio.com>
+---
+ drivers/infiniband/hw/cxgb4/cm.c | 20 ++++++++++++++++----
+ drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 1 +
+ 2 files changed, 17 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
+index 58896f0..dbe79cf 100644
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -143,6 +143,18 @@ static void connect_reply_upcall(struct c4iw_ep *ep, int status);
+ static LIST_HEAD(timeout_list);
+ static spinlock_t timeout_lock;
+
++static void deref_qp(struct c4iw_ep *ep)
++{
++ c4iw_qp_rem_ref(&ep->com.qp->ibqp);
++ clear_bit(QP_REFERENCED, &ep->com.flags);
++}
++
++static void ref_qp(struct c4iw_ep *ep)
++{
++ set_bit(QP_REFERENCED, &ep->com.flags);
++ c4iw_qp_add_ref(&ep->com.qp->ibqp);
++}
++
+ static void start_ep_timer(struct c4iw_ep *ep)
+ {
+ PDBG("%s ep %p\n", __func__, ep);
+@@ -272,6 +284,8 @@ void _c4iw_free_ep(struct kref *kref)
+
+ ep = container_of(kref, struct c4iw_ep, com.kref);
+ PDBG("%s ep %p state %s\n", __func__, ep, states[state_read(&ep->com)]);
++ if (test_bit(QP_REFERENCED, &ep->com.flags))
++ deref_qp(ep);
+ if (test_bit(RELEASE_RESOURCES, &ep->com.flags)) {
+ cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, ep->hwtid);
+ dst_release(ep->dst);
+@@ -864,7 +878,6 @@ static void close_complete_upcall(struct c4iw_ep *ep)
+ ep->com.cm_id->event_handler(ep->com.cm_id, &event);
+ ep->com.cm_id->rem_ref(ep->com.cm_id);
+ ep->com.cm_id = NULL;
+- ep->com.qp = NULL;
+ set_bit(CLOSE_UPCALL, &ep->com.history);
+ }
+ }
+@@ -907,7 +920,6 @@ static void peer_abort_upcall(struct c4iw_ep *ep)
+ ep->com.cm_id->event_handler(ep->com.cm_id, &event);
+ ep->com.cm_id->rem_ref(ep->com.cm_id);
+ ep->com.cm_id = NULL;
+- ep->com.qp = NULL;
+ set_bit(ABORT_UPCALL, &ep->com.history);
+ }
+ }
+@@ -947,7 +959,6 @@ static void connect_reply_upcall(struct c4iw_ep *ep, int status)
+ if (status < 0) {
+ ep->com.cm_id->rem_ref(ep->com.cm_id);
+ ep->com.cm_id = NULL;
+- ep->com.qp = NULL;
+ }
+ }
+
+@@ -2435,6 +2446,7 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
+ cm_id->add_ref(cm_id);
+ ep->com.cm_id = cm_id;
+ ep->com.qp = qp;
++ ref_qp(ep);
+
+ /* bind QP to EP and move to RTS */
+ attrs.mpa_attr = ep->mpa_attr;
+@@ -2465,7 +2477,6 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
+ return 0;
+ err1:
+ ep->com.cm_id = NULL;
+- ep->com.qp = NULL;
+ cm_id->rem_ref(cm_id);
+ err:
+ c4iw_put_ep(&ep->com);
+@@ -2506,6 +2517,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
+ ep->com.cm_id = cm_id;
+ ep->com.qp = get_qhp(dev, conn_param->qpn);
+ BUG_ON(!ep->com.qp);
++ ref_qp(ep);
+ PDBG("%s qpn 0x%x qp %p cm_id %p\n", __func__, conn_param->qpn,
+ ep->com.qp, cm_id);
+
+diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+index 9c1644f..0aaaa0e 100644
+--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
++++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+@@ -716,6 +716,7 @@ enum c4iw_ep_flags {
+ ABORT_REQ_IN_PROGRESS = 1,
+ RELEASE_RESOURCES = 2,
+ CLOSE_SENT = 3,
++ QP_REFERENCED = 5,
+ };
+
+ enum c4iw_ep_history {
+--
+1.7.1
+
--- /dev/null
+From 06c3accf85a24991e09114d53fa84eaaa77890bf Mon Sep 17 00:00:00 2001
+From: Vipul Pandya <vipul@chelsio.com>
+Date: Thu, 8 Nov 2012 14:37:26 +0530
+Subject: [PATCH 10/11] RDMA/cxgb4: Always log async errors.
+
+Log AEs even if the QP isn't in RTS. It is useful
+information.
+
+Signed-off-by: Vipul Pandya <vipul@chelsio.com>
+---
+ drivers/infiniband/hw/cxgb4/cm.c | 6 +++---
+ drivers/infiniband/hw/cxgb4/ev.c | 8 +++++---
+ 2 files changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
+index dbe79cf..6164268 100644
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -1420,9 +1420,9 @@ static int rx_data(struct c4iw_dev *dev, struct sk_buff *skb)
+ BUG_ON(!ep->com.qp);
+ if (ep->com.qp->attr.state == C4IW_QP_STATE_RTS)
+ pr_err("%s Unexpected streaming data." \
+- " ep %p state %d tid %u status %d\n",
+- __func__, ep, state_read(&ep->com),
+- ep->hwtid, status);
++ " qpid %u ep %p state %d tid %u status %d\n",
++ __func__, ep->com.qp->wq.sq.qid, ep,
++ state_read(&ep->com), ep->hwtid, status);
+ attrs.next_state = C4IW_QP_STATE_ERROR;
+ c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
+ C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
+diff --git a/drivers/infiniband/hw/cxgb4/ev.c b/drivers/infiniband/hw/cxgb4/ev.c
+index cf2f6b4..6f158c3 100644
+--- a/drivers/infiniband/hw/cxgb4/ev.c
++++ b/drivers/infiniband/hw/cxgb4/ev.c
+@@ -46,9 +46,11 @@ static void post_qp_event(struct c4iw_dev *dev, struct c4iw_cq *chp,
+
+ if ((qhp->attr.state == C4IW_QP_STATE_ERROR) ||
+ (qhp->attr.state == C4IW_QP_STATE_TERMINATE)) {
+- PDBG("%s AE received after RTS - "
+- "qp state %d qpid 0x%x status 0x%x\n", __func__,
+- qhp->attr.state, qhp->wq.sq.qid, CQE_STATUS(err_cqe));
++ pr_err("%s AE after RTS - qpid 0x%x opcode %d status 0x%x "
++ "type %d wrid.hi 0x%x wrid.lo 0x%x\n",
++ __func__, CQE_QPID(err_cqe), CQE_OPCODE(err_cqe),
++ CQE_STATUS(err_cqe), CQE_TYPE(err_cqe),
++ CQE_WRID_HI(err_cqe), CQE_WRID_LOW(err_cqe));
+ return;
+ }
+
+--
+1.7.1
+
--- /dev/null
+From 7064cb784a8515d6c65deec78eb6e839820434e8 Mon Sep 17 00:00:00 2001
+From: Vipul Pandya <vipul@chelsio.com>
+Date: Thu, 8 Nov 2012 14:39:46 +0530
+Subject: [PATCH] RDMA/cxgb4: only log rx_data warnings if cpl status is non zero.
+
+With newer firmware, we can get streaming data due to connection
+errors before the driver moves the QP out of RTS.
+
+Signed-off-by: Vipul Pandya <vipul@chelsio.com>
+---
+ drivers/infiniband/hw/cxgb4/cm.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
+index 6164268..7a216ed 100644
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -1418,7 +1418,7 @@ static int rx_data(struct c4iw_dev *dev, struct sk_buff *skb)
+ case FPDU_MODE: {
+ struct c4iw_qp_attributes attrs;
+ BUG_ON(!ep->com.qp);
+- if (ep->com.qp->attr.state == C4IW_QP_STATE_RTS)
++ if (status)
+ pr_err("%s Unexpected streaming data." \
+ " qpid %u ep %p state %d tid %u status %d\n",
+ __func__, ep->com.qp->wq.sq.qid, ep,
+--
+1.7.1
+