i40iw: Tear-down connection after CQP Modify QP failure
authorHenry Orosco <henry.orosco@intel.com>
Wed, 14 Mar 2018 19:45:23 +0000 (14:45 -0500)
committerJason Gunthorpe <jgg@mellanox.com>
Thu, 15 Mar 2018 21:58:05 +0000 (15:58 -0600)
There is no explicit tear-down sequence initiated on
connections if the Control QP OP, Modify QP to close,
fails. Fix this by triggering a driver generated
Asynchronous Event (AE) on Modify QP failures and
tear-down the connection on receipt of the AE.

This fix can be generalized to other Modify QP failures
(i.e. RTS->TERM, IDLE->RTS, etc) as any modify failure
will require a connection tear-down.

Fixes: d37498417947 ("i40iw: add files for iwarp interface")
Signed-off-by: Henry Orosco <henry.orosco@intel.com>
Signed-off-by: Shiraz Saleem <shiraz.saleem@intel.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
drivers/infiniband/hw/i40iw/i40iw.h
drivers/infiniband/hw/i40iw/i40iw_cm.c
drivers/infiniband/hw/i40iw/i40iw_hw.c
drivers/infiniband/hw/i40iw/i40iw_verbs.c

index 45e97dd323ad007693c1b13c1eefabf7582dafd9..d5d8c1be345a64ec0de46ddac9e54bc7d13fa95e 100644 (file)
@@ -559,6 +559,7 @@ void i40iw_next_iw_state(struct i40iw_qp *iwqp,
                         u8 state, u8 del_hash,
                         u8 term, u8 term_len);
 int i40iw_send_syn(struct i40iw_cm_node *cm_node, u32 sendack);
+int i40iw_send_reset(struct i40iw_cm_node *cm_node);
 struct i40iw_cm_node *i40iw_find_node(struct i40iw_cm_core *cm_core,
                                      u16 rem_port,
                                      u32 *rem_addr,
index d4780d3887cac04ec25ae95674f623ab3536bc15..4cfa8f4647e222ea3ef35fdc699fbe3e0ad9281e 100644 (file)
@@ -539,7 +539,7 @@ static struct i40iw_puda_buf *i40iw_form_cm_frame(struct i40iw_cm_node *cm_node,
  * i40iw_send_reset - Send RST packet
  * @cm_node: connection's node
  */
-static int i40iw_send_reset(struct i40iw_cm_node *cm_node)
+int i40iw_send_reset(struct i40iw_cm_node *cm_node)
 {
        struct i40iw_puda_buf *sqbuf;
        int flags = SET_RST | SET_ACK;
index d7af9a25bf1acaac2510683a0a8b8ae4c735c4f7..6139836fb533adf194ede3ee693aefcbe55471d8 100644 (file)
@@ -352,6 +352,8 @@ void i40iw_process_aeq(struct i40iw_device *iwdev)
                        else
                                i40iw_cm_disconn(iwqp);
                        break;
+               case I40IW_AE_BAD_CLOSE:
+                       /* fall through */
                case I40IW_AE_RESET_SENT:
                        i40iw_next_iw_state(iwqp, I40IW_QP_STATE_ERROR, 1, 0, 0);
                        i40iw_cm_disconn(iwqp);
index f3af952402e96013facd32d424be4779d6180ca3..60e004d2100e893cea0a6f07a59e997534a4ae5e 100644 (file)
@@ -831,10 +831,10 @@ static int i40iw_query_qp(struct ib_qp *ibqp,
 void i40iw_hw_modify_qp(struct i40iw_device *iwdev, struct i40iw_qp *iwqp,
                        struct i40iw_modify_qp_info *info, bool wait)
 {
-       enum i40iw_status_code status;
        struct i40iw_cqp_request *cqp_request;
        struct cqp_commands_info *cqp_info;
        struct i40iw_modify_qp_info *m_info;
+       struct i40iw_gen_ae_info ae_info;
 
        cqp_request = i40iw_get_cqp_request(&iwdev->cqp, wait);
        if (!cqp_request)
@@ -847,9 +847,25 @@ void i40iw_hw_modify_qp(struct i40iw_device *iwdev, struct i40iw_qp *iwqp,
        cqp_info->post_sq = 1;
        cqp_info->in.u.qp_modify.qp = &iwqp->sc_qp;
        cqp_info->in.u.qp_modify.scratch = (uintptr_t)cqp_request;
-       status = i40iw_handle_cqp_op(iwdev, cqp_request);
-       if (status)
-               i40iw_pr_err("CQP-OP Modify QP fail");
+       if (!i40iw_handle_cqp_op(iwdev, cqp_request))
+               return;
+
+       switch (m_info->next_iwarp_state) {
+       case I40IW_QP_STATE_RTS:
+               if (iwqp->iwarp_state == I40IW_QP_STATE_IDLE)
+                       i40iw_send_reset(iwqp->cm_node);
+               /* fall through */
+       case I40IW_QP_STATE_IDLE:
+       case I40IW_QP_STATE_TERMINATE:
+       case I40IW_QP_STATE_CLOSING:
+               ae_info.ae_code = I40IW_AE_BAD_CLOSE;
+               ae_info.ae_source = 0;
+               i40iw_gen_ae(iwdev, &iwqp->sc_qp, &ae_info, false);
+               break;
+       case I40IW_QP_STATE_ERROR:
+       default:
+               break;
+       }
 }
 
 /**
@@ -962,10 +978,6 @@ int i40iw_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
 
                iwqp->ibqp_state = attr->qp_state;
 
-               if (issue_modify_qp)
-                       iwqp->iwarp_state = info.next_iwarp_state;
-               else
-                       info.next_iwarp_state = iwqp->iwarp_state;
        }
        if (attr_mask & IB_QP_ACCESS_FLAGS) {
                ctx_info->iwarp_info_valid = true;
@@ -1003,9 +1015,14 @@ int i40iw_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
 
        spin_unlock_irqrestore(&iwqp->lock, flags);
 
-       if (issue_modify_qp)
+       if (issue_modify_qp) {
                i40iw_hw_modify_qp(iwdev, iwqp, &info, true);
 
+               spin_lock_irqsave(&iwqp->lock, flags);
+               iwqp->iwarp_state = info.next_iwarp_state;
+               spin_unlock_irqrestore(&iwqp->lock, flags);
+       }
+
        if (issue_modify_qp && (iwqp->ibqp_state > IB_QPS_RTS)) {
                if (dont_wait) {
                        if (iwqp->cm_id && iwqp->hw_tcp_state) {