RDMA/cxgb4: Update snd_seq when sending MPA messages
[linux-2.6-block.git] / drivers / infiniband / hw / cxgb4 / cm.c
index d286bdebe2ab90fc613c7696d41690909247da52..a1bc41d04620d900e57e5166fb7ac821437cd914 100644 (file)
@@ -98,9 +98,9 @@ int c4iw_debug;
 module_param(c4iw_debug, int, 0644);
 MODULE_PARM_DESC(c4iw_debug, "Enable debug logging (default=0)");
 
-static int peer2peer;
+static int peer2peer = 1;
 module_param(peer2peer, int, 0644);
-MODULE_PARM_DESC(peer2peer, "Support peer2peer ULPs (default=0)");
+MODULE_PARM_DESC(peer2peer, "Support peer2peer ULPs (default=1)");
 
 static int p2p_type = FW_RI_INIT_P2PTYPE_READ_REQ;
 module_param(p2p_type, int, 0644);
@@ -400,7 +400,8 @@ static struct dst_entry *find_route(struct c4iw_dev *dev, __be32 local_ip,
        n = dst_neigh_lookup(&rt->dst, &peer_ip);
        if (!n)
                return NULL;
-       if (!our_interface(dev, n->dev)) {
+       if (!our_interface(dev, n->dev) &&
+           !(n->dev->flags & IFF_LOOPBACK)) {
                dst_release(&rt->dst);
                return NULL;
        }
@@ -761,6 +762,7 @@ static void send_mpa_req(struct c4iw_ep *ep, struct sk_buff *skb,
        start_ep_timer(ep);
        state_set(&ep->com, MPA_REQ_SENT);
        ep->mpa_attr.initiator = 1;
+       ep->snd_seq += mpalen;
        return;
 }
 
@@ -840,6 +842,7 @@ static int send_mpa_reject(struct c4iw_ep *ep, const void *pdata, u8 plen)
        t4_set_arp_err_handler(skb, NULL, arp_failure_discard);
        BUG_ON(ep->mpa_skb);
        ep->mpa_skb = skb;
+       ep->snd_seq += mpalen;
        return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
 }
 
@@ -924,6 +927,7 @@ static int send_mpa_reply(struct c4iw_ep *ep, const void *pdata, u8 plen)
        t4_set_arp_err_handler(skb, NULL, arp_failure_discard);
        ep->mpa_skb = skb;
        state_set(&ep->com, MPA_REP_SENT);
+       ep->snd_seq += mpalen;
        return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
 }
 
@@ -967,13 +971,14 @@ static int act_establish(struct c4iw_dev *dev, struct sk_buff *skb)
        return 0;
 }
 
-static void close_complete_upcall(struct c4iw_ep *ep)
+static void close_complete_upcall(struct c4iw_ep *ep, int status)
 {
        struct iw_cm_event event;
 
        PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
        memset(&event, 0, sizeof(event));
        event.event = IW_CM_EVENT_CLOSE;
+       event.status = status;
        if (ep->com.cm_id) {
                PDBG("close complete delivered ep %p cm_id %p tid %u\n",
                     ep, ep->com.cm_id, ep->hwtid);
@@ -987,7 +992,6 @@ static void close_complete_upcall(struct c4iw_ep *ep)
 static int abort_connection(struct c4iw_ep *ep, struct sk_buff *skb, gfp_t gfp)
 {
        PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
-       close_complete_upcall(ep);
        state_set(&ep->com, ABORTING);
        set_bit(ABORT_CONN, &ep->com.history);
        return send_abort(ep, skb, gfp);
@@ -1066,9 +1070,10 @@ static void connect_reply_upcall(struct c4iw_ep *ep, int status)
        }
 }
 
-static void connect_request_upcall(struct c4iw_ep *ep)
+static int connect_request_upcall(struct c4iw_ep *ep)
 {
        struct iw_cm_event event;
+       int ret;
 
        PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
        memset(&event, 0, sizeof(event));
@@ -1093,15 +1098,14 @@ static void connect_request_upcall(struct c4iw_ep *ep)
                event.private_data_len = ep->plen;
                event.private_data = ep->mpa_pkt + sizeof(struct mpa_message);
        }
-       if (state_read(&ep->parent_ep->com) != DEAD) {
-               c4iw_get_ep(&ep->com);
-               ep->parent_ep->com.cm_id->event_handler(
-                                               ep->parent_ep->com.cm_id,
-                                               &event);
-       }
+       c4iw_get_ep(&ep->com);
+       ret = ep->parent_ep->com.cm_id->event_handler(ep->parent_ep->com.cm_id,
+                                                     &event);
+       if (ret)
+               c4iw_put_ep(&ep->com);
        set_bit(CONNREQ_UPCALL, &ep->com.history);
        c4iw_put_ep(&ep->parent_ep->com);
-       ep->parent_ep = NULL;
+       return ret;
 }
 
 static void established_upcall(struct c4iw_ep *ep)
@@ -1400,7 +1404,6 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)
                return;
 
        PDBG("%s enter (%s line %u)\n", __func__, __FILE__, __LINE__);
-       stop_ep_timer(ep);
        mpa = (struct mpa_message *) ep->mpa_pkt;
 
        /*
@@ -1493,9 +1496,17 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)
             ep->mpa_attr.p2p_type);
 
        state_set(&ep->com, MPA_REQ_RCVD);
+       stop_ep_timer(ep);
 
        /* drive upcall */
-       connect_request_upcall(ep);
+       mutex_lock(&ep->parent_ep->com.mutex);
+       if (ep->parent_ep->com.state != DEAD) {
+               if (connect_request_upcall(ep))
+                       abort_connection(ep, skb, GFP_KERNEL);
+       } else {
+               abort_connection(ep, skb, GFP_KERNEL);
+       }
+       mutex_unlock(&ep->parent_ep->com.mutex);
        return;
 }
 
@@ -2246,7 +2257,7 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
                        c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
                                       C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
                }
-               close_complete_upcall(ep);
+               close_complete_upcall(ep, 0);
                __state_set(&ep->com, DEAD);
                release = 1;
                disconnect = 0;
@@ -2425,7 +2436,7 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
                                             C4IW_QP_ATTR_NEXT_STATE,
                                             &attrs, 1);
                }
-               close_complete_upcall(ep);
+               close_complete_upcall(ep, 0);
                __state_set(&ep->com, DEAD);
                release = 1;
                break;
@@ -2980,7 +2991,7 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
        rdev = &ep->com.dev->rdev;
        if (c4iw_fatal_error(rdev)) {
                fatal = 1;
-               close_complete_upcall(ep);
+               close_complete_upcall(ep, -EIO);
                ep->com.state = DEAD;
        }
        switch (ep->com.state) {
@@ -3022,7 +3033,7 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
        if (close) {
                if (abrupt) {
                        set_bit(EP_DISC_ABORT, &ep->com.history);
-                       close_complete_upcall(ep);
+                       close_complete_upcall(ep, -ECONNRESET);
                        ret = send_abort(ep, NULL, gfp);
                } else {
                        set_bit(EP_DISC_CLOSE, &ep->com.history);
@@ -3203,6 +3214,7 @@ static void send_fw_pass_open_req(struct c4iw_dev *dev, struct sk_buff *skb,
        struct sk_buff *req_skb;
        struct fw_ofld_connection_wr *req;
        struct cpl_pass_accept_req *cpl = cplhdr(skb);
+       int ret;
 
        req_skb = alloc_skb(sizeof(struct fw_ofld_connection_wr), GFP_KERNEL);
        req = (struct fw_ofld_connection_wr *)__skb_put(req_skb, sizeof(*req));
@@ -3239,7 +3251,13 @@ static void send_fw_pass_open_req(struct c4iw_dev *dev, struct sk_buff *skb,
        req->cookie = (unsigned long)skb;
 
        set_wr_txq(req_skb, CPL_PRIORITY_CONTROL, port_id);
-       cxgb4_ofld_send(dev->rdev.lldi.ports[0], req_skb);
+       ret = cxgb4_ofld_send(dev->rdev.lldi.ports[0], req_skb);
+       if (ret < 0) {
+               pr_err("%s - cxgb4_ofld_send error %d - dropping\n", __func__,
+                      ret);
+               kfree_skb(skb);
+               kfree_skb(req_skb);
+       }
 }
 
 /*
@@ -3346,13 +3364,13 @@ static int rx_pkt(struct c4iw_dev *dev, struct sk_buff *skb)
                pi = (struct port_info *)netdev_priv(pdev);
                tx_chan = cxgb4_port_chan(pdev);
        }
+       neigh_release(neigh);
        if (!e) {
                pr_err("%s - failed to allocate l2t entry!\n",
                       __func__);
                goto free_dst;
        }
 
-       neigh_release(neigh);
        step = dev->rdev.lldi.nrxq / dev->rdev.lldi.nchan;
        rss_qid = dev->rdev.lldi.rxq_ids[pi->port_id * step];
        window = (__force u16) htons((__force u16)tcph->window);
@@ -3427,6 +3445,7 @@ static void process_timeout(struct c4iw_ep *ep)
                                     &attrs, 1);
                }
                __state_set(&ep->com, ABORTING);
+               close_complete_upcall(ep, -ETIMEDOUT);
                break;
        default:
                WARN(1, "%s unexpected state ep %p tid %u state %u\n",