RDMA/nes: CM connection setup/teardown rework
authorFaisal Latif <flatif@neteffect.com>
Fri, 25 Jul 2008 03:50:45 +0000 (20:50 -0700)
committerRoland Dreier <rolandd@cisco.com>
Fri, 25 Jul 2008 03:50:45 +0000 (20:50 -0700)
Major rework of CM connection setup/teardown.  We had a number of issues
with MPI applications not starting/terminating properly over time.
With these changes we were able to run longer on larger clusters.

* Remove memory allocation from nes_connect() and nes_cm_connect().
* Fix mini_cm_dec_refcnt_listen() when destroying listener.
* Remove unnecessary code from schedule_nes_timer() and nes_cm_timer_tick().
* Functionalize mini_cm_recv_pkt() and process_packet().
* Clean up cm_node->ref_count usage.
* Reuse skbs if available.

Signed-off-by: Faisal Latif <flatif@neteffect.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
drivers/infiniband/hw/nes/nes.c
drivers/infiniband/hw/nes/nes_cm.c
drivers/infiniband/hw/nes/nes_cm.h
drivers/infiniband/hw/nes/nes_hw.c
drivers/infiniband/hw/nes/nes_verbs.c

index d2884e7..b0cab64 100644 (file)
@@ -276,6 +276,7 @@ static void nes_cqp_rem_ref_callback(struct nes_device *nesdev, struct nes_cqp_r
        }
        nes_free_resource(nesadapter, nesadapter->allocated_qps, nesqp->hwqp.qp_id);
 
+       nesadapter->qp_table[nesqp->hwqp.qp_id-NES_FIRST_QPN] = NULL;
        kfree(nesqp->allocated_buffer);
 
 }
@@ -289,7 +290,6 @@ void nes_rem_ref(struct ib_qp *ibqp)
        struct nes_qp *nesqp;
        struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
        struct nes_device *nesdev = nesvnic->nesdev;
-       struct nes_adapter *nesadapter = nesdev->nesadapter;
        struct nes_hw_cqp_wqe *cqp_wqe;
        struct nes_cqp_request *cqp_request;
        u32 opcode;
@@ -303,8 +303,6 @@ void nes_rem_ref(struct ib_qp *ibqp)
        }
 
        if (atomic_dec_and_test(&nesqp->refcount)) {
-               nesadapter->qp_table[nesqp->hwqp.qp_id-NES_FIRST_QPN] = NULL;
-
                /* Destroy the QP */
                cqp_request = nes_get_cqp_request(nesdev);
                if (cqp_request == NULL) {
index 6aa531d..9f0b964 100644 (file)
@@ -74,36 +74,59 @@ atomic_t cm_nodes_destroyed;
 atomic_t cm_accel_dropped_pkts;
 atomic_t cm_resets_recvd;
 
-static inline int mini_cm_accelerated(struct nes_cm_core *, struct nes_cm_node *);
+static inline int mini_cm_accelerated(struct nes_cm_core *,
+       struct nes_cm_node *);
 static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *,
-               struct nes_vnic *, struct nes_cm_info *);
-static int add_ref_cm_node(struct nes_cm_node *);
-static int rem_ref_cm_node(struct nes_cm_core *, struct nes_cm_node *);
+       struct nes_vnic *, struct nes_cm_info *);
 static int mini_cm_del_listen(struct nes_cm_core *, struct nes_cm_listener *);
-static struct sk_buff *form_cm_frame(struct sk_buff *, struct nes_cm_node *,
-                                    void *, u32, void *, u32, u8);
-static struct sk_buff *get_free_pkt(struct nes_cm_node *cm_node);
-
 static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *,
-                                          struct nes_vnic *,
-                                          struct ietf_mpa_frame *,
-                                          struct nes_cm_info *);
+       struct nes_vnic *, u16, void *, struct nes_cm_info *);
+static int mini_cm_close(struct nes_cm_core *, struct nes_cm_node *);
 static int mini_cm_accept(struct nes_cm_core *, struct ietf_mpa_frame *,
-                         struct nes_cm_node *);
+       struct nes_cm_node *);
 static int mini_cm_reject(struct nes_cm_core *, struct ietf_mpa_frame *,
-                         struct nes_cm_node *);
-static int mini_cm_close(struct nes_cm_core *, struct nes_cm_node *);
-static int mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *,
-                           struct sk_buff *);
+       struct nes_cm_node *);
+static void mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *,
+       struct sk_buff *);
 static int mini_cm_dealloc_core(struct nes_cm_core *);
 static int mini_cm_get(struct nes_cm_core *);
 static int mini_cm_set(struct nes_cm_core *, u32, u32);
+
+static struct sk_buff *form_cm_frame(struct sk_buff *, struct nes_cm_node *,
+       void *, u32, void *, u32, u8);
+static struct sk_buff *get_free_pkt(struct nes_cm_node *cm_node);
+static int add_ref_cm_node(struct nes_cm_node *);
+static int rem_ref_cm_node(struct nes_cm_core *, struct nes_cm_node *);
+
 static int nes_cm_disconn_true(struct nes_qp *);
 static int nes_cm_post_event(struct nes_cm_event *event);
 static int nes_disconnect(struct nes_qp *nesqp, int abrupt);
 static void nes_disconnect_worker(struct work_struct *work);
-static int send_ack(struct nes_cm_node *cm_node);
+
+static int send_mpa_request(struct nes_cm_node *, struct sk_buff *);
+static int send_syn(struct nes_cm_node *, u32, struct sk_buff *);
+static int send_reset(struct nes_cm_node *, struct sk_buff *);
+static int send_ack(struct nes_cm_node *cm_node, struct sk_buff *skb);
 static int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb);
+static void process_packet(struct nes_cm_node *, struct sk_buff *,
+       struct nes_cm_core *);
+
+static void active_open_err(struct nes_cm_node *, struct sk_buff *, int);
+static void passive_open_err(struct nes_cm_node *, struct sk_buff *, int);
+static void cleanup_retrans_entry(struct nes_cm_node *);
+static void handle_rcv_mpa(struct nes_cm_node *, struct sk_buff *,
+       enum nes_cm_event_type);
+static void free_retrans_entry(struct nes_cm_node *cm_node);
+static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph,
+       struct sk_buff *skb, int optionsize, int passive);
+
+/* CM event handler functions */
+static void cm_event_connected(struct nes_cm_event *);
+static void cm_event_connect_error(struct nes_cm_event *);
+static void cm_event_reset(struct nes_cm_event *);
+static void cm_event_mpa_req(struct nes_cm_event *);
+
+static void print_core(struct nes_cm_core *core);
 
 /* External CM API Interface */
 /* instance of function pointers for client API */
@@ -158,11 +181,11 @@ static struct nes_cm_event *create_event(struct nes_cm_node *cm_node,
        event->cm_info.loc_port = cm_node->loc_port;
        event->cm_info.cm_id = cm_node->cm_id;
 
-       nes_debug(NES_DBG_CM, "Created event=%p, type=%u, dst_addr=%08x[%x],"
-                       " src_addr=%08x[%x]\n",
-                       event, type,
-                       event->cm_info.loc_addr, event->cm_info.loc_port,
-                       event->cm_info.rem_addr, event->cm_info.rem_port);
+       nes_debug(NES_DBG_CM, "cm_node=%p Created event=%p, type=%u, "
+               "dst_addr=%08x[%x], src_addr=%08x[%x]\n",
+               cm_node, event, type, event->cm_info.loc_addr,
+               event->cm_info.loc_port, event->cm_info.rem_addr,
+               event->cm_info.rem_port);
 
        nes_cm_post_event(event);
        return event;
@@ -172,14 +195,11 @@ static struct nes_cm_event *create_event(struct nes_cm_node *cm_node,
 /**
  * send_mpa_request
  */
-static int send_mpa_request(struct nes_cm_node *cm_node)
+static int send_mpa_request(struct nes_cm_node *cm_node, struct sk_buff *skb)
 {
-       struct sk_buff *skb;
        int ret;
-
-       skb = get_free_pkt(cm_node);
        if (!skb) {
-               nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+               nes_debug(NES_DBG_CM, "skb set to NULL\n");
                return -1;
        }
 
@@ -188,9 +208,8 @@ static int send_mpa_request(struct nes_cm_node *cm_node)
                        cm_node->mpa_frame_size, SET_ACK);
 
        ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
-       if (ret < 0) {
+       if (ret < 0)
                return ret;
-       }
 
        return 0;
 }
@@ -228,47 +247,13 @@ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 len)
 }
 
 
-/**
- * handle_exception_pkt - process an exception packet.
- * We have been in a TSA state, and we have now received SW
- * TCP/IP traffic should be a FIN request or IP pkt with options
- */
-static int handle_exception_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb)
-{
-       int ret = 0;
-       struct tcphdr *tcph = tcp_hdr(skb);
-
-       /* first check to see if this a FIN pkt */
-       if (tcph->fin) {
-               /* we need to ACK the FIN request */
-               send_ack(cm_node);
-
-               /* check which side we are (client/server) and set next state accordingly */
-               if (cm_node->tcp_cntxt.client)
-                       cm_node->state = NES_CM_STATE_CLOSING;
-               else {
-                       /* we are the server side */
-                       cm_node->state = NES_CM_STATE_CLOSE_WAIT;
-                       /* since this is a self contained CM we don't wait for */
-                       /* an APP to close us, just send final FIN immediately */
-                       ret = send_fin(cm_node, NULL);
-                       cm_node->state = NES_CM_STATE_LAST_ACK;
-               }
-       } else {
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-
 /**
  * form_cm_frame - get a free packet and build empty frame Use
  * node info to build.
  */
-static struct sk_buff *form_cm_frame(struct sk_buff *skb, struct nes_cm_node *cm_node,
-                                    void *options, u32 optionsize, void *data,
-                                    u32 datasize, u8 flags)
+static struct sk_buff *form_cm_frame(struct sk_buff *skb,
+       struct nes_cm_node *cm_node, void *options, u32 optionsize,
+       void *data, u32 datasize, u8 flags)
 {
        struct tcphdr *tcph;
        struct iphdr *iph;
@@ -332,10 +317,12 @@ static struct sk_buff *form_cm_frame(struct sk_buff *skb, struct nes_cm_node *cm
                cm_node->tcp_cntxt.loc_seq_num++;
                tcph->syn = 1;
        } else
-               cm_node->tcp_cntxt.loc_seq_num += datasize;     /* data (no headers) */
+               cm_node->tcp_cntxt.loc_seq_num += datasize;
 
-       if (flags & SET_FIN)
+       if (flags & SET_FIN) {
+               cm_node->tcp_cntxt.loc_seq_num++;
                tcph->fin = 1;
+       }
 
        if (flags & SET_RST)
                tcph->rst = 1;
@@ -389,7 +376,7 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
                int close_when_complete)
 {
        unsigned long  flags;
-       struct nes_cm_core *cm_core;
+       struct nes_cm_core *cm_core = cm_node->cm_core;
        struct nes_timer_entry *new_send;
        int ret = 0;
        u32 was_timer_set;
@@ -411,7 +398,7 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
        new_send->close_when_complete = close_when_complete;
 
        if (type == NES_TIMER_TYPE_CLOSE) {
-               new_send->timetosend += (HZ/2); /* TODO: decide on the correct value here */
+               new_send->timetosend += (HZ/10);
                spin_lock_irqsave(&cm_node->recv_list_lock, flags);
                list_add_tail(&new_send->list, &cm_node->recv_list);
                spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
@@ -420,36 +407,28 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
        if (type == NES_TIMER_TYPE_SEND) {
                new_send->seq_num = ntohl(tcp_hdr(skb)->seq);
                atomic_inc(&new_send->skb->users);
+               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+               cm_node->send_entry = new_send;
+               add_ref_cm_node(cm_node);
+               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+               new_send->timetosend = jiffies + NES_RETRY_TIMEOUT;
 
                ret = nes_nic_cm_xmit(new_send->skb, cm_node->netdev);
                if (ret != NETDEV_TX_OK) {
-                       nes_debug(NES_DBG_CM, "Error sending packet %p (jiffies = %lu)\n",
-                                       new_send, jiffies);
+                       nes_debug(NES_DBG_CM, "Error sending packet %p "
+                               "(jiffies = %lu)\n", new_send, jiffies);
                        atomic_dec(&new_send->skb->users);
                        new_send->timetosend = jiffies;
                } else {
                        cm_packets_sent++;
                        if (!send_retrans) {
+                               cleanup_retrans_entry(cm_node);
                                if (close_when_complete)
-                                       rem_ref_cm_node(cm_node->cm_core, cm_node);
-                               dev_kfree_skb_any(new_send->skb);
-                               kfree(new_send);
+                                       rem_ref_cm_node(cm_core, cm_node);
                                return ret;
                        }
-                       new_send->timetosend = jiffies + NES_RETRY_TIMEOUT;
                }
-               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
-               list_add_tail(&new_send->list, &cm_node->retrans_list);
-               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-       }
-       if (type == NES_TIMER_TYPE_RECV) {
-               new_send->seq_num = ntohl(tcp_hdr(skb)->seq);
-               new_send->timetosend = jiffies;
-               spin_lock_irqsave(&cm_node->recv_list_lock, flags);
-               list_add_tail(&new_send->list, &cm_node->recv_list);
-               spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
        }
-       cm_core = cm_node->cm_core;
 
        was_timer_set = timer_pending(&cm_core->tcp_timer);
 
@@ -476,23 +455,27 @@ static void nes_cm_timer_tick(unsigned long pass)
        struct list_head *list_node, *list_node_temp;
        struct nes_cm_core *cm_core = g_cm_core;
        struct nes_qp *nesqp;
-       struct sk_buff *skb;
        u32 settimer = 0;
        int ret = NETDEV_TX_OK;
-       int    node_done;
+       enum nes_cm_node_state last_state;
 
        spin_lock_irqsave(&cm_core->ht_lock, flags);
 
-       list_for_each_safe(list_node, list_core_temp, &cm_core->connected_nodes) {
+       list_for_each_safe(list_node, list_core_temp,
+               &cm_core->connected_nodes) {
                cm_node = container_of(list_node, struct nes_cm_node, list);
                add_ref_cm_node(cm_node);
                spin_unlock_irqrestore(&cm_core->ht_lock, flags);
                spin_lock_irqsave(&cm_node->recv_list_lock, flags);
-               list_for_each_safe(list_core, list_node_temp, &cm_node->recv_list) {
-                       recv_entry = container_of(list_core, struct nes_timer_entry, list);
-                       if ((time_after(recv_entry->timetosend, jiffies)) &&
-                                       (recv_entry->type == NES_TIMER_TYPE_CLOSE)) {
-                               if (nexttimeout > recv_entry->timetosend || !settimer) {
+               list_for_each_safe(list_core, list_node_temp,
+                       &cm_node->recv_list) {
+                       recv_entry = container_of(list_core,
+                               struct nes_timer_entry, list);
+                       if (!recv_entry)
+                               break;
+                       if (time_after(recv_entry->timetosend, jiffies)) {
+                               if (nexttimeout > recv_entry->timetosend ||
+                                       !settimer) {
                                        nexttimeout = recv_entry->timetosend;
                                        settimer = 1;
                                }
@@ -501,157 +484,143 @@ static void nes_cm_timer_tick(unsigned long pass)
                        list_del(&recv_entry->list);
                        cm_id = cm_node->cm_id;
                        spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
-                       if (recv_entry->type == NES_TIMER_TYPE_CLOSE) {
-                               nesqp = (struct nes_qp *)recv_entry->skb;
-                               spin_lock_irqsave(&nesqp->lock, qplockflags);
-                               if (nesqp->cm_id) {
-                                       nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, refcount = %d: "
-                                                       "****** HIT A NES_TIMER_TYPE_CLOSE"
-                                                       " with something to do!!! ******\n",
-                                                       nesqp->hwqp.qp_id, cm_id,
-                                                       atomic_read(&nesqp->refcount));
-                                       nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
-                                       nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
-                                       nesqp->ibqp_state = IB_QPS_ERR;
-                                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
-                                       nes_cm_disconn(nesqp);
-                               } else {
-                                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
-                                       nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, refcount = %d:"
-                                                       " ****** HIT A NES_TIMER_TYPE_CLOSE"
-                                                       " with nothing to do!!! ******\n",
-                                                       nesqp->hwqp.qp_id, cm_id,
-                                                       atomic_read(&nesqp->refcount));
-                                       nes_rem_ref(&nesqp->ibqp);
-                               }
-                               if (cm_id)
-                                       cm_id->rem_ref(cm_id);
+                       nesqp = (struct nes_qp *)recv_entry->skb;
+                       spin_lock_irqsave(&nesqp->lock, qplockflags);
+                       if (nesqp->cm_id) {
+                               nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, "
+                                       "refcount = %d: HIT A "
+                                       "NES_TIMER_TYPE_CLOSE with something "
+                                       "to do!!!\n", nesqp->hwqp.qp_id, cm_id,
+                                       atomic_read(&nesqp->refcount));
+                               nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+                               nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
+                               nesqp->ibqp_state = IB_QPS_ERR;
+                               spin_unlock_irqrestore(&nesqp->lock,
+                                       qplockflags);
+                               nes_cm_disconn(nesqp);
+                       } else {
+                               spin_unlock_irqrestore(&nesqp->lock,
+                                       qplockflags);
+                               nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, "
+                                       "refcount = %d: HIT A "
+                                       "NES_TIMER_TYPE_CLOSE with nothing "
+                                       "to do!!!\n", nesqp->hwqp.qp_id, cm_id,
+                                       atomic_read(&nesqp->refcount));
                        }
+                       if (cm_id)
+                               cm_id->rem_ref(cm_id);
+
                        kfree(recv_entry);
                        spin_lock_irqsave(&cm_node->recv_list_lock, flags);
                }
                spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
 
                spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
-               node_done = 0;
-               list_for_each_safe(list_core, list_node_temp, &cm_node->retrans_list) {
-                       if (node_done) {
-                               break;
-                       }
-                       send_entry = container_of(list_core, struct nes_timer_entry, list);
+               do {
+                       send_entry = cm_node->send_entry;
+                       if (!send_entry)
+                               continue;
                        if (time_after(send_entry->timetosend, jiffies)) {
                                if (cm_node->state != NES_CM_STATE_TSA) {
-                                       if ((nexttimeout > send_entry->timetosend) || !settimer) {
-                                               nexttimeout = send_entry->timetosend;
+                                       if ((nexttimeout >
+                                               send_entry->timetosend) ||
+                                               !settimer) {
+                                               nexttimeout =
+                                                       send_entry->timetosend;
                                                settimer = 1;
+                                               continue;
                                        }
-                                       node_done = 1;
-                                       continue;
                                } else {
-                                       list_del(&send_entry->list);
-                                       skb = send_entry->skb;
-                                       spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-                                       dev_kfree_skb_any(skb);
-                                       kfree(send_entry);
-                                       spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+                                       free_retrans_entry(cm_node);
                                        continue;
                                }
                        }
-                       if (send_entry->type == NES_TIMER_NODE_CLEANUP) {
-                               list_del(&send_entry->list);
-                               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-                               kfree(send_entry);
-                               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
-                               continue;
-                       }
-                       if ((send_entry->seq_num < cm_node->tcp_cntxt.rem_ack_num) ||
-                                       (cm_node->state == NES_CM_STATE_TSA) ||
-                                       (cm_node->state == NES_CM_STATE_CLOSED)) {
-                               skb = send_entry->skb;
-                               list_del(&send_entry->list);
-                               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-                               kfree(send_entry);
-                               dev_kfree_skb_any(skb);
-                               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+
+                       if ((cm_node->state == NES_CM_STATE_TSA) ||
+                               (cm_node->state == NES_CM_STATE_CLOSED)) {
+                               free_retrans_entry(cm_node);
                                continue;
                        }
 
-                       if (!send_entry->retranscount || !send_entry->retrycount) {
+                       if (!send_entry->retranscount ||
+                               !send_entry->retrycount) {
                                cm_packets_dropped++;
-                               skb = send_entry->skb;
-                               list_del(&send_entry->list);
-                               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-                               dev_kfree_skb_any(skb);
-                               kfree(send_entry);
-                               if (cm_node->state == NES_CM_STATE_SYN_RCVD) {
-                                       /* this node never even generated an indication up to the cm */
+                               last_state = cm_node->state;
+                               cm_node->state = NES_CM_STATE_CLOSED;
+                               free_retrans_entry(cm_node);
+                               spin_unlock_irqrestore(
+                                       &cm_node->retrans_list_lock, flags);
+                               if (last_state == NES_CM_STATE_SYN_RCVD)
                                        rem_ref_cm_node(cm_core, cm_node);
-                               } else {
-                                       cm_node->state = NES_CM_STATE_CLOSED;
-                                       create_event(cm_node, NES_CM_EVENT_ABORTED);
-                               }
-                               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+                               else
+                                       create_event(cm_node,
+                                               NES_CM_EVENT_ABORTED);
+                               spin_lock_irqsave(&cm_node->retrans_list_lock,
+                                       flags);
                                continue;
                        }
-                       /* this seems like the correct place, but leave send entry unprotected */
-                       /* spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); */
                        atomic_inc(&send_entry->skb->users);
                        cm_packets_retrans++;
-                       nes_debug(NES_DBG_CM, "Retransmitting send_entry %p for node %p,"
-                                       " jiffies = %lu, time to send =  %lu, retranscount = %u, "
-                                       "send_entry->seq_num = 0x%08X, cm_node->tcp_cntxt.rem_ack_num = 0x%08X\n",
-                                       send_entry, cm_node, jiffies, send_entry->timetosend, send_entry->retranscount,
-                                       send_entry->seq_num, cm_node->tcp_cntxt.rem_ack_num);
-
-                       spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+                       nes_debug(NES_DBG_CM, "Retransmitting send_entry %p "
+                               "for node %p, jiffies = %lu, time to send = "
+                               "%lu, retranscount = %u, send_entry->seq_num = "
+                               "0x%08X, cm_node->tcp_cntxt.rem_ack_num = "
+                               "0x%08X\n", send_entry, cm_node, jiffies,
+                               send_entry->timetosend,
+                               send_entry->retranscount,
+                               send_entry->seq_num,
+                               cm_node->tcp_cntxt.rem_ack_num);
+
+                       spin_unlock_irqrestore(&cm_node->retrans_list_lock,
+                               flags);
                        ret = nes_nic_cm_xmit(send_entry->skb, cm_node->netdev);
+                       spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
                        if (ret != NETDEV_TX_OK) {
+                               nes_debug(NES_DBG_CM, "rexmit failed for "
+                                       "node=%p\n", cm_node);
                                cm_packets_bounced++;
                                atomic_dec(&send_entry->skb->users);
                                send_entry->retrycount--;
                                nexttimeout = jiffies + NES_SHORT_TIME;
                                settimer = 1;
-                               node_done = 1;
-                               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
                                continue;
                        } else {
                                cm_packets_sent++;
                        }
-                       spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
-                       list_del(&send_entry->list);
-                       nes_debug(NES_DBG_CM, "Packet Sent: retrans count = %u, retry count = %u.\n",
-                                       send_entry->retranscount, send_entry->retrycount);
+                       nes_debug(NES_DBG_CM, "Packet Sent: retrans count = "
+                               "%u, retry count = %u.\n",
+                               send_entry->retranscount,
+                               send_entry->retrycount);
                        if (send_entry->send_retrans) {
                                send_entry->retranscount--;
-                               send_entry->timetosend = jiffies + NES_RETRY_TIMEOUT;
-                               if (nexttimeout > send_entry->timetosend || !settimer) {
+                               send_entry->timetosend = jiffies +
+                                       NES_RETRY_TIMEOUT;
+                               if (nexttimeout > send_entry->timetosend ||
+                                       !settimer) {
                                        nexttimeout = send_entry->timetosend;
                                        settimer = 1;
                                }
-                               list_add(&send_entry->list, &cm_node->retrans_list);
-                               continue;
                        } else {
                                int close_when_complete;
-                               skb = send_entry->skb;
-                               close_when_complete = send_entry->close_when_complete;
-                               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-                               if (close_when_complete) {
-                                       BUG_ON(atomic_read(&cm_node->ref_count) == 1);
-                                       rem_ref_cm_node(cm_core, cm_node);
-                               }
-                               dev_kfree_skb_any(skb);
-                               kfree(send_entry);
-                               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
-                               continue;
+                               close_when_complete =
+                                       send_entry->close_when_complete;
+                               nes_debug(NES_DBG_CM, "cm_node=%p state=%d\n",
+                                       cm_node, cm_node->state);
+                               free_retrans_entry(cm_node);
+                               if (close_when_complete)
+                                       rem_ref_cm_node(cm_node->cm_core,
+                                               cm_node);
                        }
-               }
-               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-
-               rem_ref_cm_node(cm_core, cm_node);
+               } while (0);
 
+               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
                spin_lock_irqsave(&cm_core->ht_lock, flags);
-               if (ret != NETDEV_TX_OK)
+               if (ret != NETDEV_TX_OK) {
+                       nes_debug(NES_DBG_CM, "rexmit failed for cm_node=%p\n",
+                               cm_node);
                        break;
+               }
        }
        spin_unlock_irqrestore(&cm_core->ht_lock, flags);
 
@@ -667,14 +636,14 @@ static void nes_cm_timer_tick(unsigned long pass)
 /**
  * send_syn
  */
-static int send_syn(struct nes_cm_node *cm_node, u32 sendack)
+static int send_syn(struct nes_cm_node *cm_node, u32 sendack,
+       struct sk_buff *skb)
 {
        int ret;
        int flags = SET_SYN;
-       struct sk_buff *skb;
        char optionsbuffer[sizeof(struct option_mss) +
-                       sizeof(struct option_windowscale) +
-                       sizeof(struct option_base) + 1];
+               sizeof(struct option_windowscale) + sizeof(struct option_base) +
+               TCP_OPTIONS_PADDING];
 
        int optionssize = 0;
        /* Sending MSS option */
@@ -695,8 +664,7 @@ static int send_syn(struct nes_cm_node *cm_node, u32 sendack)
        options->as_windowscale.shiftcount = cm_node->tcp_cntxt.rcv_wscale;
        optionssize += sizeof(struct option_windowscale);
 
-       if (sendack && !(NES_DRV_OPT_SUPRESS_OPTION_BC & nes_drv_opt)
-                       ) {
+       if (sendack && !(NES_DRV_OPT_SUPRESS_OPTION_BC & nes_drv_opt)) {
                options = (union all_known_options *)&optionsbuffer[optionssize];
                options->as_base.optionnum = OPTION_NUMBER_WRITE0;
                options->as_base.length = sizeof(struct option_base);
@@ -714,7 +682,8 @@ static int send_syn(struct nes_cm_node *cm_node, u32 sendack)
        options->as_end = OPTION_NUMBER_END;
        optionssize += 1;
 
-       skb = get_free_pkt(cm_node);
+       if (!skb)
+               skb = get_free_pkt(cm_node);
        if (!skb) {
                nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
                return -1;
@@ -733,18 +702,18 @@ static int send_syn(struct nes_cm_node *cm_node, u32 sendack)
 /**
  * send_reset
  */
-static int send_reset(struct nes_cm_node *cm_node)
+static int send_reset(struct nes_cm_node *cm_node, struct sk_buff *skb)
 {
        int ret;
-       struct sk_buff *skb = get_free_pkt(cm_node);
        int flags = SET_RST | SET_ACK;
 
+       if (!skb)
+               skb = get_free_pkt(cm_node);
        if (!skb) {
                nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
                return -1;
        }
 
-       add_ref_cm_node(cm_node);
        form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, flags);
        ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 0, 1);
 
@@ -755,10 +724,12 @@ static int send_reset(struct nes_cm_node *cm_node)
 /**
  * send_ack
  */
-static int send_ack(struct nes_cm_node *cm_node)
+static int send_ack(struct nes_cm_node *cm_node, struct sk_buff *skb)
 {
        int ret;
-       struct sk_buff *skb = get_free_pkt(cm_node);
+
+       if (!skb)
+               skb = get_free_pkt(cm_node);
 
        if (!skb) {
                nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
@@ -922,7 +893,8 @@ static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node
        if (!cm_node || !cm_core)
                return -EINVAL;
 
-       nes_debug(NES_DBG_CM, "Adding Node to Active Connection HT\n");
+       nes_debug(NES_DBG_CM, "Adding Node %p to Active Connection HT\n",
+               cm_node);
 
        /* first, make an index into our hash table */
        hashkey = make_hashkey(cm_node->loc_port, cm_node->loc_addr,
@@ -946,10 +918,35 @@ static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node
  * mini_cm_dec_refcnt_listen
  */
 static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
-               struct nes_cm_listener *listener, int free_hanging_nodes)
+       struct nes_cm_listener *listener, int free_hanging_nodes)
 {
        int ret = 1;
        unsigned long flags;
+       struct list_head *list_pos = NULL;
+       struct list_head *list_temp = NULL;
+       struct nes_cm_node *cm_node = NULL;
+
+       nes_debug(NES_DBG_CM, "attempting listener= %p free_nodes= %d, "
+               "refcnt=%d\n", listener, free_hanging_nodes,
+               atomic_read(&listener->ref_count));
+       /* free non-accelerated child nodes for this listener */
+       if (free_hanging_nodes) {
+               spin_lock_irqsave(&cm_core->ht_lock, flags);
+               list_for_each_safe(list_pos, list_temp,
+                       &g_cm_core->connected_nodes) {
+                       cm_node = container_of(list_pos, struct nes_cm_node,
+                               list);
+                       if ((cm_node->listener == listener) &&
+                               (!cm_node->accelerated)) {
+                               cleanup_retrans_entry(cm_node);
+                               spin_unlock_irqrestore(&cm_core->ht_lock,
+                                       flags);
+                               send_reset(cm_node, NULL);
+                               spin_lock_irqsave(&cm_core->ht_lock, flags);
+                       }
+               }
+               spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+       }
        spin_lock_irqsave(&cm_core->listen_list_lock, flags);
        if (!atomic_dec_return(&listener->ref_count)) {
                list_del(&listener->list);
@@ -1067,18 +1064,18 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
        cm_node->loc_port = cm_info->loc_port;
        cm_node->rem_port = cm_info->rem_port;
        cm_node->send_write0 = send_first;
-       nes_debug(NES_DBG_CM, "Make node addresses : loc = " NIPQUAD_FMT ":%x, rem = " NIPQUAD_FMT ":%x\n",
-                 HIPQUAD(cm_node->loc_addr), cm_node->loc_port,
-                 HIPQUAD(cm_node->rem_addr), cm_node->rem_port);
+       nes_debug(NES_DBG_CM, "Make node addresses : loc = " NIPQUAD_FMT
+                       ":%x, rem = " NIPQUAD_FMT ":%x\n",
+                       HIPQUAD(cm_node->loc_addr), cm_node->loc_port,
+                       HIPQUAD(cm_node->rem_addr), cm_node->rem_port);
        cm_node->listener = listener;
        cm_node->netdev = nesvnic->netdev;
        cm_node->cm_id = cm_info->cm_id;
        memcpy(cm_node->loc_mac, nesvnic->netdev->dev_addr, ETH_ALEN);
 
-       nes_debug(NES_DBG_CM, "listener=%p, cm_id=%p\n",
-                       cm_node->listener, cm_node->cm_id);
+       nes_debug(NES_DBG_CM, "listener=%p, cm_id=%p\n", cm_node->listener,
+                       cm_node->cm_id);
 
-       INIT_LIST_HEAD(&cm_node->retrans_list);
        spin_lock_init(&cm_node->retrans_list_lock);
        INIT_LIST_HEAD(&cm_node->recv_list);
        spin_lock_init(&cm_node->recv_list_lock);
@@ -1142,10 +1139,9 @@ static int add_ref_cm_node(struct nes_cm_node *cm_node)
  * rem_ref_cm_node - destroy an instance of a cm node
  */
 static int rem_ref_cm_node(struct nes_cm_core *cm_core,
-               struct nes_cm_node *cm_node)
+       struct nes_cm_node *cm_node)
 {
        unsigned long flags, qplockflags;
-       struct nes_timer_entry *send_entry;
        struct nes_timer_entry *recv_entry;
        struct iw_cm_id *cm_id;
        struct list_head *list_core, *list_node_temp;
@@ -1169,48 +1165,33 @@ static int rem_ref_cm_node(struct nes_cm_core *cm_core,
                atomic_dec(&cm_node->listener->pend_accepts_cnt);
                BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
        }
-
-       spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
-       list_for_each_safe(list_core, list_node_temp, &cm_node->retrans_list) {
-               send_entry = container_of(list_core, struct nes_timer_entry, list);
-               list_del(&send_entry->list);
-               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-               dev_kfree_skb_any(send_entry->skb);
-               kfree(send_entry);
-               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
-               continue;
-       }
-       spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-
+       BUG_ON(cm_node->send_entry);
        spin_lock_irqsave(&cm_node->recv_list_lock, flags);
        list_for_each_safe(list_core, list_node_temp, &cm_node->recv_list) {
-               recv_entry = container_of(list_core, struct nes_timer_entry, list);
+               recv_entry = container_of(list_core, struct nes_timer_entry,
+                               list);
                list_del(&recv_entry->list);
                cm_id = cm_node->cm_id;
                spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
-               if (recv_entry->type == NES_TIMER_TYPE_CLOSE) {
-                       nesqp = (struct nes_qp *)recv_entry->skb;
-                       spin_lock_irqsave(&nesqp->lock, qplockflags);
-                       if (nesqp->cm_id) {
-                               nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: ****** HIT A NES_TIMER_TYPE_CLOSE"
-                                               " with something to do!!! ******\n",
-                                               nesqp->hwqp.qp_id, cm_id);
-                               nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
-                               nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
-                               nesqp->ibqp_state = IB_QPS_ERR;
-                               spin_unlock_irqrestore(&nesqp->lock, qplockflags);
-                               nes_cm_disconn(nesqp);
-                       } else {
-                               spin_unlock_irqrestore(&nesqp->lock, qplockflags);
-                               nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: ****** HIT A NES_TIMER_TYPE_CLOSE"
-                                               " with nothing to do!!! ******\n",
-                                               nesqp->hwqp.qp_id, cm_id);
-                               nes_rem_ref(&nesqp->ibqp);
-                       }
-                       cm_id->rem_ref(cm_id);
-               } else if (recv_entry->type == NES_TIMER_TYPE_RECV) {
-                       dev_kfree_skb_any(recv_entry->skb);
+               nesqp = (struct nes_qp *)recv_entry->skb;
+               spin_lock_irqsave(&nesqp->lock, qplockflags);
+               if (nesqp->cm_id) {
+                       nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: HIT A "
+                               "NES_TIMER_TYPE_CLOSE with something to do!\n",
+                               nesqp->hwqp.qp_id, cm_id);
+                       nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+                       nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
+                       nesqp->ibqp_state = IB_QPS_ERR;
+                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                       nes_cm_disconn(nesqp);
+               } else {
+                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                       nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: HIT A "
+                               "NES_TIMER_TYPE_CLOSE with nothing to do!\n",
+                               nesqp->hwqp.qp_id, cm_id);
                }
+               cm_id->rem_ref(cm_id);
+
                kfree(recv_entry);
                spin_lock_irqsave(&cm_node->recv_list_lock, flags);
        }
@@ -1221,23 +1202,31 @@ static int rem_ref_cm_node(struct nes_cm_core *cm_core,
        } else {
                if (cm_node->apbvt_set && cm_node->nesvnic) {
                        nes_manage_apbvt(cm_node->nesvnic, cm_node->loc_port,
-                                       PCI_FUNC(cm_node->nesvnic->nesdev->pcidev->devfn),
-                                       NES_MANAGE_APBVT_DEL);
+                               PCI_FUNC(
+                               cm_node->nesvnic->nesdev->pcidev->devfn),
+                               NES_MANAGE_APBVT_DEL);
                }
        }
 
-       kfree(cm_node);
        atomic_dec(&cm_core->node_cnt);
        atomic_inc(&cm_nodes_destroyed);
+       nesqp = cm_node->nesqp;
+       if (nesqp) {
+               nesqp->cm_node = NULL;
+               nes_rem_ref(&nesqp->ibqp);
+               cm_node->nesqp = NULL;
+       }
 
+       cm_node->freed = 1;
+       kfree(cm_node);
        return 0;
 }
 
-
 /**
  * process_options
  */
-static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, u32 optionsize, u32 syn_packet)
+static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc,
+       u32 optionsize, u32 syn_packet)
 {
        u32 tmp;
        u32 offset = 0;
@@ -1247,35 +1236,37 @@ static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, u32 opti
        while (offset < optionsize) {
                all_options = (union all_known_options *)(optionsloc + offset);
                switch (all_options->as_base.optionnum) {
-                       case OPTION_NUMBER_END:
-                               offset = optionsize;
-                               break;
-                       case OPTION_NUMBER_NONE:
-                               offset += 1;
-                               continue;
-                       case OPTION_NUMBER_MSS:
-                               nes_debug(NES_DBG_CM, "%s: MSS Length: %d Offset: %d Size: %d\n",
-                                               __func__,
-                                               all_options->as_mss.length, offset, optionsize);
-                               got_mss_option = 1;
-                               if (all_options->as_mss.length != 4) {
-                                       return 1;
-                               } else {
-                                       tmp = ntohs(all_options->as_mss.mss);
-                                       if (tmp > 0 && tmp < cm_node->tcp_cntxt.mss)
-                                               cm_node->tcp_cntxt.mss = tmp;
-                               }
-                               break;
-                       case OPTION_NUMBER_WINDOW_SCALE:
-                               cm_node->tcp_cntxt.snd_wscale = all_options->as_windowscale.shiftcount;
-                               break;
-                       case OPTION_NUMBER_WRITE0:
-                               cm_node->send_write0 = 1;
-                               break;
-                       default:
-                               nes_debug(NES_DBG_CM, "TCP Option not understood: %x\n",
-                                               all_options->as_base.optionnum);
-                               break;
+               case OPTION_NUMBER_END:
+                       offset = optionsize;
+                       break;
+               case OPTION_NUMBER_NONE:
+                       offset += 1;
+                       continue;
+               case OPTION_NUMBER_MSS:
+                       nes_debug(NES_DBG_CM, "%s: MSS Length: %d Offset: %d "
+                               "Size: %d\n", __func__,
+                               all_options->as_mss.length, offset, optionsize);
+                       got_mss_option = 1;
+                       if (all_options->as_mss.length != 4) {
+                               return 1;
+                       } else {
+                               tmp = ntohs(all_options->as_mss.mss);
+                               if (tmp > 0 && tmp <
+                                       cm_node->tcp_cntxt.mss)
+                                       cm_node->tcp_cntxt.mss = tmp;
+                       }
+                       break;
+               case OPTION_NUMBER_WINDOW_SCALE:
+                       cm_node->tcp_cntxt.snd_wscale =
+                               all_options->as_windowscale.shiftcount;
+                       break;
+               case OPTION_NUMBER_WRITE0:
+                       cm_node->send_write0 = 1;
+                       break;
+               default:
+                       nes_debug(NES_DBG_CM, "TCP Option not understood: %x\n",
+                               all_options->as_base.optionnum);
+                       break;
                }
                offset += all_options->as_base.length;
        }
@@ -1284,300 +1275,491 @@ static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, u32 opti
        return 0;
 }
 
+static void drop_packet(struct sk_buff *skb)
+{
+       atomic_inc(&cm_accel_dropped_pkts);
+       dev_kfree_skb_any(skb);
+}
 
-/**
- * process_packet
- */
-static int process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
-                         struct nes_cm_core *cm_core)
+static void handle_fin_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
+       struct tcphdr *tcph)
 {
-       int optionsize;
-       int datasize;
-       int ret = 0;
-       struct tcphdr *tcph = tcp_hdr(skb);
-       u32 inc_sequence;
-       if (cm_node->state == NES_CM_STATE_SYN_SENT && tcph->syn) {
-               inc_sequence = ntohl(tcph->seq);
-               cm_node->tcp_cntxt.rcv_nxt = inc_sequence;
+       atomic_inc(&cm_resets_recvd);
+       nes_debug(NES_DBG_CM, "Received FIN, cm_node = %p, state = %u. "
+               "refcnt=%d\n", cm_node, cm_node->state,
+               atomic_read(&cm_node->ref_count));
+       cm_node->tcp_cntxt.rcv_nxt++;
+       cleanup_retrans_entry(cm_node);
+       switch (cm_node->state) {
+       case NES_CM_STATE_SYN_RCVD:
+       case NES_CM_STATE_SYN_SENT:
+       case NES_CM_STATE_ESTABLISHED:
+       case NES_CM_STATE_MPAREQ_SENT:
+               cm_node->state = NES_CM_STATE_LAST_ACK;
+               send_fin(cm_node, skb);
+               break;
+       case NES_CM_STATE_FIN_WAIT1:
+               cm_node->state = NES_CM_STATE_CLOSING;
+               send_ack(cm_node, skb);
+               break;
+       case NES_CM_STATE_FIN_WAIT2:
+               cm_node->state = NES_CM_STATE_TIME_WAIT;
+               send_ack(cm_node, skb);
+               cm_node->state = NES_CM_STATE_CLOSED;
+               break;
+       case NES_CM_STATE_TSA:
+       default:
+               nes_debug(NES_DBG_CM, "Error Rcvd FIN for node-%p state = %d\n",
+                       cm_node, cm_node->state);
+               drop_packet(skb);
+               break;
        }
+}
 
-       if ((!tcph) || (cm_node->state == NES_CM_STATE_TSA)) {
-               BUG_ON(!tcph);
-               atomic_inc(&cm_accel_dropped_pkts);
-               return -1;
-       }
 
-       if (tcph->rst) {
-               atomic_inc(&cm_resets_recvd);
-               nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u. refcnt=%d\n",
-                               cm_node, cm_node->state, atomic_read(&cm_node->ref_count));
-               switch (cm_node->state) {
-                       case NES_CM_STATE_LISTENING:
-                               rem_ref_cm_node(cm_core, cm_node);
-                               break;
-                       case NES_CM_STATE_TSA:
-                       case NES_CM_STATE_CLOSED:
-                               break;
-                       case NES_CM_STATE_SYN_RCVD:
-                                       nes_debug(NES_DBG_CM, "Received a reset for local 0x%08X:%04X,"
-                                                       " remote 0x%08X:%04X, node state = %u\n",
-                                                       cm_node->loc_addr, cm_node->loc_port,
-                                                       cm_node->rem_addr, cm_node->rem_port,
-                                                       cm_node->state);
-                               rem_ref_cm_node(cm_core, cm_node);
-                               break;
-                       case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
-                       case NES_CM_STATE_ESTABLISHED:
-                       case NES_CM_STATE_MPAREQ_SENT:
-                       default:
-                                       nes_debug(NES_DBG_CM, "Received a reset for local 0x%08X:%04X,"
-                                                       " remote 0x%08X:%04X, node state = %u refcnt=%d\n",
-                                                       cm_node->loc_addr, cm_node->loc_port,
-                                                       cm_node->rem_addr, cm_node->rem_port,
-                                                       cm_node->state, atomic_read(&cm_node->ref_count));
-                               /* create event */
-                               cm_node->state = NES_CM_STATE_CLOSED;
+static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
+       struct tcphdr *tcph)
+{
 
-                               create_event(cm_node, NES_CM_EVENT_ABORTED);
-                               break;
+       int     reset = 0;      /* whether to send reset in case of err.. */
+       atomic_inc(&cm_resets_recvd);
+       nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u."
+                       " refcnt=%d\n", cm_node, cm_node->state,
+                       atomic_read(&cm_node->ref_count));
+       cleanup_retrans_entry(cm_node);
+       switch (cm_node->state) {
+       case NES_CM_STATE_SYN_SENT:
+       case NES_CM_STATE_MPAREQ_SENT:
+               nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p "
+                       "listener=%p state=%d\n", __func__, __LINE__, cm_node,
+                       cm_node->listener, cm_node->state);
+               active_open_err(cm_node, skb, reset);
+               break;
+       /* For PASSIVE open states, remove the cm_node event */
+       case NES_CM_STATE_ESTABLISHED:
+       case NES_CM_STATE_SYN_RCVD:
+       case NES_CM_STATE_LISTENING:
+               nes_debug(NES_DBG_CM, "Bad state %s[%u]\n", __func__, __LINE__);
+               passive_open_err(cm_node, skb, reset);
+               break;
+       case NES_CM_STATE_TSA:
+       default:
+               break;
+       }
+}
 
+static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb,
+       enum nes_cm_event_type type)
+{
+
+       int     ret;
+       int datasize = skb->len;
+       u8 *dataloc = skb->data;
+       ret = parse_mpa(cm_node, dataloc, datasize);
+       if (ret < 0) {
+               nes_debug(NES_DBG_CM, "didn't like MPA Request\n");
+               if (type == NES_CM_EVENT_CONNECTED) {
+                       nes_debug(NES_DBG_CM, "%s[%u] create abort for "
+                               "cm_node=%p listener=%p state=%d\n", __func__,
+                               __LINE__, cm_node, cm_node->listener,
+                               cm_node->state);
+                       active_open_err(cm_node, skb, 1);
+               } else {
+                       passive_open_err(cm_node, skb, 1);
                }
-               return -1;
+       } else {
+               cleanup_retrans_entry(cm_node);
+               dev_kfree_skb_any(skb);
+               if (type == NES_CM_EVENT_CONNECTED)
+                       cm_node->state = NES_CM_STATE_TSA;
+               create_event(cm_node, type);
+
+       }
+       return ;
+}
+
+static void indicate_pkt_err(struct nes_cm_node *cm_node, struct sk_buff *skb)
+{
+       switch (cm_node->state) {
+       case NES_CM_STATE_SYN_SENT:
+       case NES_CM_STATE_MPAREQ_SENT:
+               nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p "
+                       "listener=%p state=%d\n", __func__, __LINE__, cm_node,
+                       cm_node->listener, cm_node->state);
+               active_open_err(cm_node, skb, 1);
+               break;
+       case NES_CM_STATE_ESTABLISHED:
+       case NES_CM_STATE_SYN_RCVD:
+               passive_open_err(cm_node, skb, 1);
+               break;
+       case NES_CM_STATE_TSA:
+       default:
+               drop_packet(skb);
        }
+}
+
+static int check_syn(struct nes_cm_node *cm_node, struct tcphdr *tcph,
+       struct sk_buff *skb)
+{
+       int err;
+
+       err = ((ntohl(tcph->ack_seq) == cm_node->tcp_cntxt.loc_seq_num))? 0 : 1;
+       if (err)
+               active_open_err(cm_node, skb, 1);
+
+       return err;
+}
+
+static int check_seq(struct nes_cm_node *cm_node, struct tcphdr *tcph,
+       struct sk_buff *skb)
+{
+       int err = 0;
+       u32 seq;
+       u32 ack_seq;
+       u32 loc_seq_num = cm_node->tcp_cntxt.loc_seq_num;
+       u32 rcv_nxt = cm_node->tcp_cntxt.rcv_nxt;
+       u32 rcv_wnd;
+       seq = ntohl(tcph->seq);
+       ack_seq = ntohl(tcph->ack_seq);
+       rcv_wnd = cm_node->tcp_cntxt.rcv_wnd;
+       if (ack_seq != loc_seq_num)
+               err = 1;
+       else if ((seq + rcv_wnd) < rcv_nxt)
+               err = 1;
+       if (err) {
+               nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p "
+                       "listener=%p state=%d\n", __func__, __LINE__, cm_node,
+                       cm_node->listener, cm_node->state);
+               indicate_pkt_err(cm_node, skb);
+               nes_debug(NES_DBG_CM, "seq ERROR cm_node =%p seq=0x%08X "
+                       "rcv_nxt=0x%08X rcv_wnd=0x%x\n", cm_node, seq, rcv_nxt,
+                       rcv_wnd);
+       }
+       return err;
+}
+
+/*
+ * handle_syn_pkt() is for Passive node. The syn packet is received when a node
+ * is created with a listener or it may comein as rexmitted packet which in
+ * that case will be just dropped.
+ */
+
+static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
+       struct tcphdr *tcph)
+{
+       int ret;
+       u32 inc_sequence;
+       int optionsize;
 
        optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
+       skb_pull(skb, tcph->doff << 2);
+       inc_sequence = ntohl(tcph->seq);
 
-       skb_pull(skb, ip_hdr(skb)->ihl << 2);
+       switch (cm_node->state) {
+       case NES_CM_STATE_SYN_SENT:
+       case NES_CM_STATE_MPAREQ_SENT:
+               /* Rcvd syn on active open connection*/
+               active_open_err(cm_node, skb, 1);
+               break;
+       case NES_CM_STATE_LISTENING:
+               /* Passive OPEN */
+               cm_node->accept_pend = 1;
+               atomic_inc(&cm_node->listener->pend_accepts_cnt);
+               if (atomic_read(&cm_node->listener->pend_accepts_cnt) >
+                               cm_node->listener->backlog) {
+                       nes_debug(NES_DBG_CM, "drop syn due to backlog "
+                               "pressure \n");
+                       cm_backlog_drops++;
+                       passive_open_err(cm_node, skb, 0);
+                       break;
+               }
+               ret = handle_tcp_options(cm_node, tcph, skb, optionsize,
+                       1);
+               if (ret) {
+                       passive_open_err(cm_node, skb, 0);
+                       /* drop pkt */
+                       break;
+               }
+               cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;
+               BUG_ON(cm_node->send_entry);
+               cm_node->state = NES_CM_STATE_SYN_RCVD;
+               send_syn(cm_node, 1, skb);
+               break;
+       case NES_CM_STATE_TSA:
+       case NES_CM_STATE_ESTABLISHED:
+       case NES_CM_STATE_FIN_WAIT1:
+       case NES_CM_STATE_FIN_WAIT2:
+       case NES_CM_STATE_MPAREQ_RCVD:
+       case NES_CM_STATE_LAST_ACK:
+       case NES_CM_STATE_CLOSING:
+       case NES_CM_STATE_UNKNOWN:
+       case NES_CM_STATE_CLOSED:
+       default:
+               drop_packet(skb);
+               break;
+       }
+}
+
+static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
+       struct tcphdr *tcph)
+{
+
+       int ret;
+       u32 inc_sequence;
+       int optionsize;
+
+       optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
        skb_pull(skb, tcph->doff << 2);
+       inc_sequence = ntohl(tcph->seq);
+       switch (cm_node->state) {
+       case NES_CM_STATE_SYN_SENT:
+               /* active open */
+               if (check_syn(cm_node, tcph, skb))
+                       return;
+               cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
+               /* setup options */
+               ret = handle_tcp_options(cm_node, tcph, skb, optionsize, 0);
+               if (ret) {
+                       nes_debug(NES_DBG_CM, "cm_node=%p tcp_options failed\n",
+                               cm_node);
+                       break;
+               }
+               cleanup_retrans_entry(cm_node);
+               cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;
+               send_mpa_request(cm_node, skb);
+               cm_node->state = NES_CM_STATE_MPAREQ_SENT;
+               break;
+       case NES_CM_STATE_MPAREQ_RCVD:
+               /* passive open, so should not be here */
+               passive_open_err(cm_node, skb, 1);
+               break;
+       case NES_CM_STATE_ESTABLISHED:
+       case NES_CM_STATE_FIN_WAIT1:
+       case NES_CM_STATE_FIN_WAIT2:
+       case NES_CM_STATE_LAST_ACK:
+       case NES_CM_STATE_TSA:
+       case NES_CM_STATE_CLOSING:
+       case NES_CM_STATE_UNKNOWN:
+       case NES_CM_STATE_CLOSED:
+       case NES_CM_STATE_MPAREQ_SENT:
+       default:
+               drop_packet(skb);
+               break;
+       }
+}
 
-       datasize = skb->len;
+static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
+       struct tcphdr *tcph)
+{
+       int datasize = 0;
+       u32 inc_sequence;
+       u32 rem_seq_ack;
+       u32 rem_seq;
+       if (check_seq(cm_node, tcph, skb))
+               return;
+
+       skb_pull(skb, tcph->doff << 2);
        inc_sequence = ntohl(tcph->seq);
-       nes_debug(NES_DBG_CM, "datasize = %u, sequence = 0x%08X, ack_seq = 0x%08X,"
-                       " rcv_nxt = 0x%08X Flags: %s %s.\n",
-                       datasize, inc_sequence, ntohl(tcph->ack_seq),
-                       cm_node->tcp_cntxt.rcv_nxt, (tcph->syn ? "SYN":""),
-                       (tcph->ack ? "ACK":""));
-
-       if (!tcph->syn && (inc_sequence != cm_node->tcp_cntxt.rcv_nxt)
-               ) {
-               nes_debug(NES_DBG_CM, "dropping packet, datasize = %u, sequence = 0x%08X,"
-                               " ack_seq = 0x%08X, rcv_nxt = 0x%08X Flags: %s.\n",
-                               datasize, inc_sequence, ntohl(tcph->ack_seq),
-                               cm_node->tcp_cntxt.rcv_nxt, (tcph->ack ? "ACK":""));
-               if (cm_node->state == NES_CM_STATE_LISTENING) {
-                       rem_ref_cm_node(cm_core, cm_node);
+       rem_seq = ntohl(tcph->seq);
+       rem_seq_ack =  ntohl(tcph->ack_seq);
+       datasize = skb->len;
+
+       switch (cm_node->state) {
+       case NES_CM_STATE_SYN_RCVD:
+               /* Passive OPEN */
+               cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
+               cm_node->state = NES_CM_STATE_ESTABLISHED;
+               if (datasize) {
+                       cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
+                       cm_node->state = NES_CM_STATE_MPAREQ_RCVD;
+                       handle_rcv_mpa(cm_node, skb, NES_CM_EVENT_MPA_REQ);
+                } else { /* rcvd ACK only */
+                       dev_kfree_skb_any(skb);
+                       cleanup_retrans_entry(cm_node);
+                }
+               break;
+       case NES_CM_STATE_ESTABLISHED:
+               /* Passive OPEN */
+               /* We expect mpa frame to be received only */
+               if (datasize) {
+                       cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
+                       cm_node->state = NES_CM_STATE_MPAREQ_RCVD;
+                       handle_rcv_mpa(cm_node, skb,
+                               NES_CM_EVENT_MPA_REQ);
+               } else
+                       drop_packet(skb);
+               break;
+       case NES_CM_STATE_MPAREQ_SENT:
+               cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
+               if (datasize) {
+                       cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
+                       handle_rcv_mpa(cm_node, skb, NES_CM_EVENT_CONNECTED);
+               } else { /* Could be just an ack pkt.. */
+                       cleanup_retrans_entry(cm_node);
+                       dev_kfree_skb_any(skb);
                }
-               return -1;
+               break;
+       case NES_CM_STATE_FIN_WAIT1:
+       case NES_CM_STATE_SYN_SENT:
+       case NES_CM_STATE_FIN_WAIT2:
+       case NES_CM_STATE_TSA:
+       case NES_CM_STATE_CLOSED:
+       case NES_CM_STATE_MPAREQ_RCVD:
+       case NES_CM_STATE_LAST_ACK:
+       case NES_CM_STATE_CLOSING:
+       case NES_CM_STATE_UNKNOWN:
+       default:
+               drop_packet(skb);
+               break;
        }
+}
 
-               cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
 
 
+static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph,
+       struct sk_buff *skb, int optionsize, int passive)
+{
+       u8 *optionsloc = (u8 *)&tcph[1];
        if (optionsize) {
-               u8 *optionsloc = (u8 *)&tcph[1];
-               if (process_options(cm_node, optionsloc, optionsize, (u32)tcph->syn)) {
-                       nes_debug(NES_DBG_CM, "%s: Node %p, Sending RESET\n", __func__, cm_node);
-                       send_reset(cm_node);
-                       if (cm_node->state != NES_CM_STATE_SYN_SENT)
-                       rem_ref_cm_node(cm_core, cm_node);
-                       return 0;
+               if (process_options(cm_node, optionsloc, optionsize,
+                       (u32)tcph->syn)) {
+                       nes_debug(NES_DBG_CM, "%s: Node %p, Sending RESET\n",
+                               __func__, cm_node);
+                       if (passive)
+                               passive_open_err(cm_node, skb, 0);
+                       else
+                               active_open_err(cm_node, skb, 0);
+                       return 1;
                }
-       } else if (tcph->syn)
-               cm_node->tcp_cntxt.mss = NES_CM_DEFAULT_MSS;
+       }
 
        cm_node->tcp_cntxt.snd_wnd = ntohs(tcph->window) <<
                        cm_node->tcp_cntxt.snd_wscale;
 
-       if (cm_node->tcp_cntxt.snd_wnd > cm_node->tcp_cntxt.max_snd_wnd) {
+       if (cm_node->tcp_cntxt.snd_wnd > cm_node->tcp_cntxt.max_snd_wnd)
                cm_node->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.snd_wnd;
-       }
+       return 0;
+}
 
-       if (tcph->ack) {
-               cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
-               switch (cm_node->state) {
-                       case NES_CM_STATE_SYN_RCVD:
-                       case NES_CM_STATE_SYN_SENT:
-                               /* read and stash current sequence number */
-                               if (cm_node->tcp_cntxt.rem_ack_num != cm_node->tcp_cntxt.loc_seq_num) {
-                                       nes_debug(NES_DBG_CM, "ERROR - cm_node->tcp_cntxt.rem_ack_num !="
-                                                       " cm_node->tcp_cntxt.loc_seq_num\n");
-                                       send_reset(cm_node);
-                                       return 0;
-                               }
-                               if (cm_node->state == NES_CM_STATE_SYN_SENT)
-                                       cm_node->state = NES_CM_STATE_ONE_SIDE_ESTABLISHED;
-                               else {
-                                               cm_node->state = NES_CM_STATE_ESTABLISHED;
-                               }
-                               break;
-                       case NES_CM_STATE_LAST_ACK:
-                               cm_node->state = NES_CM_STATE_CLOSED;
-                               break;
-                       case NES_CM_STATE_FIN_WAIT1:
-                               cm_node->state = NES_CM_STATE_FIN_WAIT2;
-                               break;
-                       case NES_CM_STATE_CLOSING:
-                               cm_node->state = NES_CM_STATE_TIME_WAIT;
-                               /* need to schedule this to happen in 2MSL timeouts */
-                               cm_node->state = NES_CM_STATE_CLOSED;
-                               break;
-                       case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
-                       case NES_CM_STATE_ESTABLISHED:
-                       case NES_CM_STATE_MPAREQ_SENT:
-                       case NES_CM_STATE_CLOSE_WAIT:
-                       case NES_CM_STATE_TIME_WAIT:
-                       case NES_CM_STATE_CLOSED:
-                               break;
-                       case NES_CM_STATE_LISTENING:
-                               nes_debug(NES_DBG_CM, "Received an ACK on a listening port (SYN %d)\n", tcph->syn);
-                               cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
-                               send_reset(cm_node);
-                               /* send_reset bumps refcount, this should have been a new node */
-                               rem_ref_cm_node(cm_core, cm_node);
-                               return -1;
-                               break;
-                       case NES_CM_STATE_TSA:
-                               nes_debug(NES_DBG_CM, "Received a packet with the ack bit set while in TSA state\n");
-                               break;
-                       case NES_CM_STATE_UNKNOWN:
-                       case NES_CM_STATE_INITED:
-                       case NES_CM_STATE_ACCEPTING:
-                       case NES_CM_STATE_FIN_WAIT2:
-                       default:
-                               nes_debug(NES_DBG_CM, "Received ack from unknown state: %x\n",
-                                               cm_node->state);
-                               send_reset(cm_node);
-                               break;
-               }
-       }
+/*
+ * active_open_err() will send reset() if flag set..
+ * It will also send ABORT event.
+ */
 
-       if (tcph->syn) {
-               if (cm_node->state == NES_CM_STATE_LISTENING) {
-                       /* do not exceed backlog */
-                       atomic_inc(&cm_node->listener->pend_accepts_cnt);
-                       if (atomic_read(&cm_node->listener->pend_accepts_cnt) >
-                                       cm_node->listener->backlog) {
-                               nes_debug(NES_DBG_CM, "drop syn due to backlog pressure \n");
-                               cm_backlog_drops++;
-                               atomic_dec(&cm_node->listener->pend_accepts_cnt);
-                               rem_ref_cm_node(cm_core, cm_node);
-                               return 0;
-                       }
-                       cm_node->accept_pend = 1;
+static void active_open_err(struct nes_cm_node *cm_node, struct sk_buff *skb,
+       int reset)
+{
+       cleanup_retrans_entry(cm_node);
+       if (reset) {
+               nes_debug(NES_DBG_CM, "ERROR active err called for cm_node=%p, "
+                               "state=%d\n", cm_node, cm_node->state);
+               add_ref_cm_node(cm_node);
+               send_reset(cm_node, skb);
+       } else
+               dev_kfree_skb_any(skb);
 
-               }
-               if (datasize == 0)
-                       cm_node->tcp_cntxt.rcv_nxt ++;
+       cm_node->state = NES_CM_STATE_CLOSED;
+       create_event(cm_node, NES_CM_EVENT_ABORTED);
+}
 
-               if (cm_node->state == NES_CM_STATE_LISTENING) {
-                       cm_node->state = NES_CM_STATE_SYN_RCVD;
-                       send_syn(cm_node, 1);
-               }
-               if (cm_node->state == NES_CM_STATE_ONE_SIDE_ESTABLISHED) {
-                       cm_node->state = NES_CM_STATE_ESTABLISHED;
-                       /* send final handshake ACK */
-                       ret = send_ack(cm_node);
-                       if (ret < 0)
-                               return ret;
+/*
+ * passive_open_err() will either do a reset() or will free up the skb and
+ * remove the cm_node.
+ */
 
-                               cm_node->state = NES_CM_STATE_MPAREQ_SENT;
-                               ret = send_mpa_request(cm_node);
-                               if (ret < 0)
-                                       return ret;
-               }
+static void passive_open_err(struct nes_cm_node *cm_node, struct sk_buff *skb,
+       int reset)
+{
+       cleanup_retrans_entry(cm_node);
+       cm_node->state = NES_CM_STATE_CLOSED;
+       if (reset) {
+               nes_debug(NES_DBG_CM, "passive_open_err sending RST for "
+                       "cm_node=%p state =%d\n", cm_node, cm_node->state);
+               send_reset(cm_node, skb);
+       } else {
+               dev_kfree_skb_any(skb);
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
        }
+}
 
-       if (tcph->fin) {
-               cm_node->tcp_cntxt.rcv_nxt++;
-               switch (cm_node->state) {
-                       case NES_CM_STATE_SYN_RCVD:
-                       case NES_CM_STATE_SYN_SENT:
-                       case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
-                       case NES_CM_STATE_ESTABLISHED:
-                       case NES_CM_STATE_ACCEPTING:
-                       case NES_CM_STATE_MPAREQ_SENT:
-                               cm_node->state = NES_CM_STATE_CLOSE_WAIT;
-                               cm_node->state = NES_CM_STATE_LAST_ACK;
-                               ret = send_fin(cm_node, NULL);
-                               break;
-                       case NES_CM_STATE_FIN_WAIT1:
-                               cm_node->state = NES_CM_STATE_CLOSING;
-                               ret = send_ack(cm_node);
-                               break;
-                       case NES_CM_STATE_FIN_WAIT2:
-                               cm_node->state = NES_CM_STATE_TIME_WAIT;
-                               cm_node->tcp_cntxt.loc_seq_num ++;
-                               ret = send_ack(cm_node);
-                               /* need to schedule this to happen in 2MSL timeouts */
-                               cm_node->state = NES_CM_STATE_CLOSED;
-                               break;
-                       case NES_CM_STATE_CLOSE_WAIT:
-                       case NES_CM_STATE_LAST_ACK:
-                       case NES_CM_STATE_CLOSING:
-                       case NES_CM_STATE_TSA:
-                       default:
-                               nes_debug(NES_DBG_CM, "Received a fin while in %x state\n",
-                                               cm_node->state);
-                               ret = -EINVAL;
-                               break;
-               }
+/*
+ * free_retrans_entry() routines assumes that the retrans_list_lock has
+ * been acquired before calling.
+ */
+static void free_retrans_entry(struct nes_cm_node *cm_node)
+{
+       struct nes_timer_entry *send_entry;
+       send_entry = cm_node->send_entry;
+       if (send_entry) {
+               cm_node->send_entry = NULL;
+               dev_kfree_skb_any(send_entry->skb);
+               kfree(send_entry);
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
        }
+}
 
-       if (datasize) {
-               u8 *dataloc = skb->data;
-               /* figure out what state we are in and handle transition to next state */
-               switch (cm_node->state) {
-                       case NES_CM_STATE_LISTENING:
-                       case NES_CM_STATE_SYN_RCVD:
-                       case NES_CM_STATE_SYN_SENT:
-                       case NES_CM_STATE_FIN_WAIT1:
-                       case NES_CM_STATE_FIN_WAIT2:
-                       case NES_CM_STATE_CLOSE_WAIT:
-                       case NES_CM_STATE_LAST_ACK:
-                       case NES_CM_STATE_CLOSING:
-                               break;
-                       case  NES_CM_STATE_MPAREQ_SENT:
-                               /* recv the mpa res frame, ret=frame len (incl priv data) */
-                               ret = parse_mpa(cm_node, dataloc, datasize);
-                               if (ret < 0)
-                                       break;
-                               /* set the req frame payload len in skb */
-                               /* we are done handling this state, set node to a TSA state */
-                               cm_node->state = NES_CM_STATE_TSA;
-                               send_ack(cm_node);
-                               create_event(cm_node, NES_CM_EVENT_CONNECTED);
-                               break;
-
-                       case  NES_CM_STATE_ESTABLISHED:
-                               /* we are expecting an MPA req frame */
-                               ret = parse_mpa(cm_node, dataloc, datasize);
-                               if (ret < 0) {
-                                       break;
-                               }
-                               cm_node->state = NES_CM_STATE_TSA;
-                               send_ack(cm_node);
-                               /* we got a valid MPA request, create an event */
-                               create_event(cm_node, NES_CM_EVENT_MPA_REQ);
-                               break;
-                       case  NES_CM_STATE_TSA:
-                               handle_exception_pkt(cm_node, skb);
-                               break;
-                       case NES_CM_STATE_UNKNOWN:
-                       case NES_CM_STATE_INITED:
-                       default:
-                               ret = -1;
-               }
-       }
+static void cleanup_retrans_entry(struct nes_cm_node *cm_node)
+{
+       unsigned long flags;
 
-       return ret;
+       spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+       free_retrans_entry(cm_node);
+       spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
 }
 
+/**
+ * process_packet
+ * Returns skb if to be freed, else it will return NULL if already used..
+ */
+static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
+       struct nes_cm_core *cm_core)
+{
+       enum nes_tcpip_pkt_type pkt_type = NES_PKT_TYPE_UNKNOWN;
+       struct tcphdr *tcph = tcp_hdr(skb);
+       skb_pull(skb, ip_hdr(skb)->ihl << 2);
+
+       nes_debug(NES_DBG_CM, "process_packet: cm_node=%p state =%d syn=%d "
+               "ack=%d rst=%d fin=%d\n", cm_node, cm_node->state, tcph->syn,
+               tcph->ack, tcph->rst, tcph->fin);
+
+       if (tcph->rst)
+               pkt_type = NES_PKT_TYPE_RST;
+       else if (tcph->syn) {
+               pkt_type = NES_PKT_TYPE_SYN;
+               if (tcph->ack)
+                       pkt_type = NES_PKT_TYPE_SYNACK;
+       } else if (tcph->fin)
+               pkt_type = NES_PKT_TYPE_FIN;
+       else if (tcph->ack)
+               pkt_type = NES_PKT_TYPE_ACK;
+
+       switch (pkt_type) {
+       case NES_PKT_TYPE_SYN:
+               handle_syn_pkt(cm_node, skb, tcph);
+               break;
+       case NES_PKT_TYPE_SYNACK:
+               handle_synack_pkt(cm_node, skb, tcph);
+               break;
+       case NES_PKT_TYPE_ACK:
+               handle_ack_pkt(cm_node, skb, tcph);
+               break;
+       case NES_PKT_TYPE_RST:
+               handle_rst_pkt(cm_node, skb, tcph);
+               break;
+       case NES_PKT_TYPE_FIN:
+               handle_fin_pkt(cm_node, skb, tcph);
+               break;
+       default:
+               drop_packet(skb);
+               break;
+       }
+}
 
 /**
  * mini_cm_listen - create a listen node with params
  */
 static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
-               struct nes_vnic *nesvnic, struct nes_cm_info *cm_info)
+       struct nes_vnic *nesvnic, struct nes_cm_info *cm_info)
 {
        struct nes_cm_listener *listener;
        unsigned long flags;
@@ -1644,37 +1826,36 @@ static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
 /**
  * mini_cm_connect - make a connection node with params
  */
-static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
-                                          struct nes_vnic *nesvnic,
-                                          struct ietf_mpa_frame *mpa_frame,
-                                          struct nes_cm_info *cm_info)
+struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
+       struct nes_vnic *nesvnic, u16 private_data_len,
+       void *private_data, struct nes_cm_info *cm_info)
 {
        int ret = 0;
        struct nes_cm_node *cm_node;
        struct nes_cm_listener *loopbackremotelistener;
        struct nes_cm_node *loopbackremotenode;
        struct nes_cm_info loopback_cm_info;
-
-       u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) +
-                       ntohs(mpa_frame->priv_data_len);
-
-       cm_info->loc_addr = htonl(cm_info->loc_addr);
-       cm_info->rem_addr = htonl(cm_info->rem_addr);
-       cm_info->loc_port = htons(cm_info->loc_port);
-       cm_info->rem_port = htons(cm_info->rem_port);
+       u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) + private_data_len;
+       struct ietf_mpa_frame *mpa_frame = NULL;
 
        /* create a CM connection node */
        cm_node = make_cm_node(cm_core, nesvnic, cm_info, NULL);
        if (!cm_node)
                return NULL;
+       mpa_frame = &cm_node->mpa_frame;
+       strcpy(mpa_frame->key, IEFT_MPA_KEY_REQ);
+       mpa_frame->flags = IETF_MPA_FLAGS_CRC;
+       mpa_frame->rev =  IETF_MPA_VERSION;
+       mpa_frame->priv_data_len = htons(private_data_len);
 
        /* set our node side to client (active) side */
        cm_node->tcp_cntxt.client = 1;
        cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;
 
        if (cm_info->loc_addr == cm_info->rem_addr) {
-               loopbackremotelistener = find_listener(cm_core, cm_node->rem_addr,
-                               cm_node->rem_port, NES_CM_LISTENER_ACTIVE_STATE);
+               loopbackremotelistener = find_listener(cm_core,
+                               ntohl(nesvnic->local_ipaddr), cm_node->rem_port,
+                               NES_CM_LISTENER_ACTIVE_STATE);
                if (loopbackremotelistener == NULL) {
                        create_event(cm_node, NES_CM_EVENT_ABORTED);
                } else {
@@ -1683,26 +1864,35 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
                        loopback_cm_info.loc_port = cm_info->rem_port;
                        loopback_cm_info.rem_port = cm_info->loc_port;
                        loopback_cm_info.cm_id = loopbackremotelistener->cm_id;
-                       loopbackremotenode = make_cm_node(cm_core, nesvnic, &loopback_cm_info,
-                                       loopbackremotelistener);
+                       loopbackremotenode = make_cm_node(cm_core, nesvnic,
+                               &loopback_cm_info, loopbackremotelistener);
                        loopbackremotenode->loopbackpartner = cm_node;
-                       loopbackremotenode->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;
+                       loopbackremotenode->tcp_cntxt.rcv_wscale =
+                               NES_CM_DEFAULT_RCV_WND_SCALE;
                        cm_node->loopbackpartner = loopbackremotenode;
-                       memcpy(loopbackremotenode->mpa_frame_buf, &mpa_frame->priv_data,
-                                       mpa_frame_size);
-                       loopbackremotenode->mpa_frame_size = mpa_frame_size -
-                                       sizeof(struct ietf_mpa_frame);
+                       memcpy(loopbackremotenode->mpa_frame_buf, private_data,
+                               private_data_len);
+                       loopbackremotenode->mpa_frame_size = private_data_len;
 
-                       /* we are done handling this state, set node to a TSA state */
+                       /* we are done handling this state. */
+                       /* set node to a TSA state */
                        cm_node->state = NES_CM_STATE_TSA;
-                       cm_node->tcp_cntxt.rcv_nxt = loopbackremotenode->tcp_cntxt.loc_seq_num;
-                       loopbackremotenode->tcp_cntxt.rcv_nxt = cm_node->tcp_cntxt.loc_seq_num;
-                       cm_node->tcp_cntxt.max_snd_wnd = loopbackremotenode->tcp_cntxt.rcv_wnd;
-                       loopbackremotenode->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.rcv_wnd;
-                       cm_node->tcp_cntxt.snd_wnd = loopbackremotenode->tcp_cntxt.rcv_wnd;
-                       loopbackremotenode->tcp_cntxt.snd_wnd = cm_node->tcp_cntxt.rcv_wnd;
-                       cm_node->tcp_cntxt.snd_wscale = loopbackremotenode->tcp_cntxt.rcv_wscale;
-                       loopbackremotenode->tcp_cntxt.snd_wscale = cm_node->tcp_cntxt.rcv_wscale;
+                       cm_node->tcp_cntxt.rcv_nxt =
+                               loopbackremotenode->tcp_cntxt.loc_seq_num;
+                       loopbackremotenode->tcp_cntxt.rcv_nxt =
+                               cm_node->tcp_cntxt.loc_seq_num;
+                       cm_node->tcp_cntxt.max_snd_wnd =
+                               loopbackremotenode->tcp_cntxt.rcv_wnd;
+                       loopbackremotenode->tcp_cntxt.max_snd_wnd =
+                               cm_node->tcp_cntxt.rcv_wnd;
+                       cm_node->tcp_cntxt.snd_wnd =
+                               loopbackremotenode->tcp_cntxt.rcv_wnd;
+                       loopbackremotenode->tcp_cntxt.snd_wnd =
+                               cm_node->tcp_cntxt.rcv_wnd;
+                       cm_node->tcp_cntxt.snd_wscale =
+                               loopbackremotenode->tcp_cntxt.rcv_wscale;
+                       loopbackremotenode->tcp_cntxt.snd_wscale =
+                               cm_node->tcp_cntxt.rcv_wscale;
 
                        create_event(loopbackremotenode, NES_CM_EVENT_MPA_REQ);
                }
@@ -1712,16 +1902,29 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
        /* set our node side to client (active) side */
        cm_node->tcp_cntxt.client = 1;
        /* init our MPA frame ptr */
-       memcpy(&cm_node->mpa_frame, mpa_frame, mpa_frame_size);
+       memcpy(mpa_frame->priv_data, private_data, private_data_len);
+
        cm_node->mpa_frame_size = mpa_frame_size;
 
        /* send a syn and goto syn sent state */
        cm_node->state = NES_CM_STATE_SYN_SENT;
-       ret = send_syn(cm_node, 0);
+       ret = send_syn(cm_node, 0, NULL);
+
+       if (ret) {
+               /* error in sending the syn free up the cm_node struct */
+               nes_debug(NES_DBG_CM, "Api - connect() FAILED: dest "
+                       "addr=0x%08X, port=0x%04x, cm_node=%p, cm_id = %p.\n",
+                       cm_node->rem_addr, cm_node->rem_port, cm_node,
+                       cm_node->cm_id);
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
+               cm_node = NULL;
+       }
 
-       nes_debug(NES_DBG_CM, "Api - connect(): dest addr=0x%08X, port=0x%04x,"
-                       " cm_node=%p, cm_id = %p.\n",
-                       cm_node->rem_addr, cm_node->rem_port, cm_node, cm_node->cm_id);
+       if (cm_node)
+               nes_debug(NES_DBG_CM, "Api - connect(): dest addr=0x%08X,"
+                       "port=0x%04x, cm_node=%p, cm_id = %p.\n",
+                       cm_node->rem_addr, cm_node->rem_port, cm_node,
+                       cm_node->cm_id);
 
        return cm_node;
 }
@@ -1731,8 +1934,8 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
  * mini_cm_accept - accept a connection
  * This function is never called
  */
-static int mini_cm_accept(struct nes_cm_core *cm_core, struct ietf_mpa_frame *mpa_frame,
-                         struct nes_cm_node *cm_node)
+static int mini_cm_accept(struct nes_cm_core *cm_core,
+       struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node)
 {
        return 0;
 }
@@ -1742,32 +1945,26 @@ static int mini_cm_accept(struct nes_cm_core *cm_core, struct ietf_mpa_frame *mp
  * mini_cm_reject - reject and teardown a connection
  */
 static int mini_cm_reject(struct nes_cm_core *cm_core,
-                         struct ietf_mpa_frame *mpa_frame,
-                         struct nes_cm_node *cm_node)
+       struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node)
 {
        int ret = 0;
-       struct sk_buff *skb;
-       u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) +
-                       ntohs(mpa_frame->priv_data_len);
 
-       skb = get_free_pkt(cm_node);
-       if (!skb) {
-               nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
-               return -1;
-       }
-
-       /* send an MPA Request frame */
-       form_cm_frame(skb, cm_node, NULL, 0, mpa_frame, mpa_frame_size, SET_ACK | SET_FIN);
-       ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
+       nes_debug(NES_DBG_CM, "%s cm_node=%p type=%d state=%d\n",
+               __func__, cm_node, cm_node->tcp_cntxt.client, cm_node->state);
 
+       if (cm_node->tcp_cntxt.client)
+               return ret;
+       cleanup_retrans_entry(cm_node);
        cm_node->state = NES_CM_STATE_CLOSED;
        ret = send_fin(cm_node, NULL);
 
-       if (ret < 0) {
-               printk(KERN_INFO PFX "failed to send MPA Reply (reject)\n");
-               return ret;
+       if (cm_node->accept_pend) {
+               BUG_ON(!cm_node->listener);
+               atomic_dec(&cm_node->listener->pend_accepts_cnt);
+               BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
        }
 
+       ret = send_reset(cm_node, NULL);
        return ret;
 }
 
@@ -1783,35 +1980,39 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod
                return -EINVAL;
 
        switch (cm_node->state) {
-               /* if passed in node is null, create a reference key node for node search */
-               /* check if we found an owner node for this pkt */
-               case NES_CM_STATE_SYN_RCVD:
-               case NES_CM_STATE_SYN_SENT:
-               case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
-               case NES_CM_STATE_ESTABLISHED:
-               case NES_CM_STATE_ACCEPTING:
-               case NES_CM_STATE_MPAREQ_SENT:
-                       cm_node->state = NES_CM_STATE_FIN_WAIT1;
-                       send_fin(cm_node, NULL);
-                       break;
-               case NES_CM_STATE_CLOSE_WAIT:
-                       cm_node->state = NES_CM_STATE_LAST_ACK;
-                       send_fin(cm_node, NULL);
-                       break;
-               case NES_CM_STATE_FIN_WAIT1:
-               case NES_CM_STATE_FIN_WAIT2:
-               case NES_CM_STATE_LAST_ACK:
-               case NES_CM_STATE_TIME_WAIT:
-               case NES_CM_STATE_CLOSING:
-                       ret = -1;
-                       break;
-               case NES_CM_STATE_LISTENING:
-               case NES_CM_STATE_UNKNOWN:
-               case NES_CM_STATE_INITED:
-               case NES_CM_STATE_CLOSED:
-               case NES_CM_STATE_TSA:
-                       ret = rem_ref_cm_node(cm_core, cm_node);
-                       break;
+       case NES_CM_STATE_SYN_RCVD:
+       case NES_CM_STATE_SYN_SENT:
+       case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
+       case NES_CM_STATE_ESTABLISHED:
+       case NES_CM_STATE_ACCEPTING:
+       case NES_CM_STATE_MPAREQ_SENT:
+       case NES_CM_STATE_MPAREQ_RCVD:
+               cleanup_retrans_entry(cm_node);
+               send_reset(cm_node, NULL);
+               break;
+       case NES_CM_STATE_CLOSE_WAIT:
+               cm_node->state = NES_CM_STATE_LAST_ACK;
+               send_fin(cm_node, NULL);
+               break;
+       case NES_CM_STATE_FIN_WAIT1:
+       case NES_CM_STATE_FIN_WAIT2:
+       case NES_CM_STATE_LAST_ACK:
+       case NES_CM_STATE_TIME_WAIT:
+       case NES_CM_STATE_CLOSING:
+               ret = -1;
+               break;
+       case NES_CM_STATE_LISTENING:
+       case NES_CM_STATE_UNKNOWN:
+       case NES_CM_STATE_INITED:
+       case NES_CM_STATE_CLOSED:
+               ret = rem_ref_cm_node(cm_core, cm_node);
+               break;
+       case NES_CM_STATE_TSA:
+               if (cm_node->send_entry)
+                       printk(KERN_ERR "ERROR Close got called from STATE_TSA "
+                               "send_entry=%p\n", cm_node->send_entry);
+               ret = rem_ref_cm_node(cm_core, cm_node);
+               break;
        }
        cm_node->cm_id = NULL;
        return ret;
@@ -1822,25 +2023,30 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod
  * recv_pkt - recv an ETHERNET packet, and process it through CM
  * node state machine
  */
-static int mini_cm_recv_pkt(struct nes_cm_core *cm_core, struct nes_vnic *nesvnic,
-                           struct sk_buff *skb)
+static void mini_cm_recv_pkt(struct nes_cm_core *cm_core,
+       struct nes_vnic *nesvnic, struct sk_buff *skb)
 {
        struct nes_cm_node *cm_node = NULL;
        struct nes_cm_listener *listener = NULL;
        struct iphdr *iph;
        struct tcphdr *tcph;
        struct nes_cm_info nfo;
-       int ret = 0;
 
-       if (!skb || skb->len < sizeof(struct iphdr) + sizeof(struct tcphdr)) {
-               ret = -EINVAL;
-               goto out;
+       if (!skb)
+               return;
+       if (skb->len < sizeof(struct iphdr) + sizeof(struct tcphdr)) {
+               dev_kfree_skb_any(skb);
+               return;
        }
 
        iph = (struct iphdr *)skb->data;
        tcph = (struct tcphdr *)(skb->data + sizeof(struct iphdr));
        skb_reset_network_header(skb);
        skb_set_transport_header(skb, sizeof(*tcph));
+       if (!tcph) {
+               dev_kfree_skb_any(skb);
+               return;
+       }
        skb->len = ntohs(iph->tot_len);
 
        nfo.loc_addr = ntohl(iph->daddr);
@@ -1853,61 +2059,60 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core, struct nes_vnic *nesvni
                  NIPQUAD(iph->daddr), tcph->dest,
                  NIPQUAD(iph->saddr), tcph->source);
 
-       /* note: this call is going to increment cm_node ref count */
-       cm_node = find_node(cm_core,
+       do {
+               cm_node = find_node(cm_core,
                        nfo.rem_port, nfo.rem_addr,
                        nfo.loc_port, nfo.loc_addr);
 
-       if (!cm_node) {
-               listener = find_listener(cm_core, nfo.loc_addr, nfo.loc_port,
-                               NES_CM_LISTENER_ACTIVE_STATE);
-               if (listener) {
-                       nfo.cm_id = listener->cm_id;
-                       nfo.conn_type = listener->conn_type;
-               } else {
-                       nfo.cm_id = NULL;
-                       nfo.conn_type = 0;
-               }
-
-               cm_node = make_cm_node(cm_core, nesvnic, &nfo, listener);
                if (!cm_node) {
-                       nes_debug(NES_DBG_CM, "Unable to allocate node\n");
+                       /* Only type of packet accepted are for */
+                       /* the PASSIVE open (syn only) */
+                       if ((!tcph->syn) || (tcph->ack)) {
+                               cm_packets_dropped++;
+                               break;
+                       }
+                       listener = find_listener(cm_core, nfo.loc_addr,
+                               nfo.loc_port,
+                               NES_CM_LISTENER_ACTIVE_STATE);
                        if (listener) {
-                               nes_debug(NES_DBG_CM, "unable to allocate node and decrementing listener refcount\n");
+                               nfo.cm_id = listener->cm_id;
+                               nfo.conn_type = listener->conn_type;
+                       } else {
+                               nes_debug(NES_DBG_CM, "Unable to find listener "
+                                       "for the pkt\n");
+                               cm_packets_dropped++;
+                               dev_kfree_skb_any(skb);
+                               break;
+                       }
+
+                       cm_node = make_cm_node(cm_core, nesvnic, &nfo,
+                               listener);
+                       if (!cm_node) {
+                               nes_debug(NES_DBG_CM, "Unable to allocate "
+                                       "node\n");
+                               cm_packets_dropped++;
                                atomic_dec(&listener->ref_count);
+                               dev_kfree_skb_any(skb);
+                               break;
                        }
-                       ret = -1;
-                       goto out;
-               }
-               if (!listener) {
-                       nes_debug(NES_DBG_CM, "Packet found for unknown port %x refcnt=%d\n",
-                                       nfo.loc_port, atomic_read(&cm_node->ref_count));
-                       if (!tcph->rst) {
-                               nes_debug(NES_DBG_CM, "Packet found for unknown port=%d"
-                                               " rem_port=%d refcnt=%d\n",
-                                               nfo.loc_port, nfo.rem_port, atomic_read(&cm_node->ref_count));
-
-                               cm_node->tcp_cntxt.rcv_nxt = ntohl(tcph->seq);
-                               cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
-                               send_reset(cm_node);
+                       if (!tcph->rst && !tcph->fin) {
+                               cm_node->state = NES_CM_STATE_LISTENING;
+                       } else {
+                               cm_packets_dropped++;
+                               rem_ref_cm_node(cm_core, cm_node);
+                               dev_kfree_skb_any(skb);
+                               break;
                        }
+                       add_ref_cm_node(cm_node);
+               } else if (cm_node->state == NES_CM_STATE_TSA) {
                        rem_ref_cm_node(cm_core, cm_node);
-                       ret = -1;
-                       goto out;
+                       atomic_inc(&cm_accel_dropped_pkts);
+                       dev_kfree_skb_any(skb);
+                       break;
                }
-               add_ref_cm_node(cm_node);
-               cm_node->state = NES_CM_STATE_LISTENING;
-       }
-
-       nes_debug(NES_DBG_CM, "Processing Packet for node %p, data = (%p):\n",
-                       cm_node, skb->data);
-       process_packet(cm_node, skb, cm_core);
-
-       rem_ref_cm_node(cm_core, cm_node);
-       out:
-       if (skb)
-               dev_kfree_skb_any(skb);
-       return ret;
+               process_packet(cm_node, skb, cm_core);
+               rem_ref_cm_node(cm_core, cm_node);
+       } while (0);
 }
 
 
@@ -2107,15 +2312,12 @@ int nes_cm_disconn(struct nes_qp *nesqp)
        if (nesqp->disconn_pending == 0) {
                nesqp->disconn_pending++;
                spin_unlock_irqrestore(&nesqp->lock, flags);
-               /* nes_add_ref(&nesqp->ibqp); */
                /* init our disconnect work element, to */
                INIT_WORK(&nesqp->disconn_work, nes_disconnect_worker);
 
                queue_work(g_cm_core->disconn_wq, &nesqp->disconn_work);
-       } else {
+       } else
                spin_unlock_irqrestore(&nesqp->lock, flags);
-               nes_rem_ref(&nesqp->ibqp);
-       }
 
        return 0;
 }
@@ -2161,7 +2363,6 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
                nes_debug(NES_DBG_CM, "QP%u disconnect_worker cmid is NULL\n",
                                nesqp->hwqp.qp_id);
                spin_unlock_irqrestore(&nesqp->lock, flags);
-               nes_rem_ref(&nesqp->ibqp);
                return -1;
        }
 
@@ -2182,30 +2383,31 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
                        atomic_inc(&cm_disconnects);
                        cm_event.event = IW_CM_EVENT_DISCONNECT;
                        if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) {
-                               issued_disconnect_reset = 1;
                                cm_event.status = IW_CM_EVENT_STATUS_RESET;
-                               nes_debug(NES_DBG_CM, "Generating a CM Disconnect Event (status reset) for "
-                                               " QP%u, cm_id = %p. \n",
-                                               nesqp->hwqp.qp_id, cm_id);
-                       } else {
+                               nes_debug(NES_DBG_CM, "Generating a CM "
+                                       "Disconnect Event (status reset) for "
+                                       "QP%u, cm_id = %p. \n",
+                                       nesqp->hwqp.qp_id, cm_id);
+                       } else
                                cm_event.status = IW_CM_EVENT_STATUS_OK;
-                       }
 
                        cm_event.local_addr = cm_id->local_addr;
                        cm_event.remote_addr = cm_id->remote_addr;
                        cm_event.private_data = NULL;
                        cm_event.private_data_len = 0;
 
-                       nes_debug(NES_DBG_CM, "Generating a CM Disconnect Event for "
-                                       " QP%u, SQ Head = %u, SQ Tail = %u. cm_id = %p, refcount = %u.\n",
-                                       nesqp->hwqp.qp_id,
-                                       nesqp->hwqp.sq_head, nesqp->hwqp.sq_tail, cm_id,
-                                       atomic_read(&nesqp->refcount));
+                       nes_debug(NES_DBG_CM, "Generating a CM Disconnect Event"
+                               " for  QP%u, SQ Head = %u, SQ Tail = %u. "
+                               "cm_id = %p, refcount = %u.\n",
+                               nesqp->hwqp.qp_id, nesqp->hwqp.sq_head,
+                               nesqp->hwqp.sq_tail, cm_id,
+                               atomic_read(&nesqp->refcount));
 
                        spin_unlock_irqrestore(&nesqp->lock, flags);
                        ret = cm_id->event_handler(cm_id, &cm_event);
                        if (ret)
-                               nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
+                               nes_debug(NES_DBG_CM, "OFA CM event_handler "
+                                       "returned, ret=%d\n", ret);
                        spin_lock_irqsave(&nesqp->lock, flags);
                }
 
@@ -2247,31 +2449,24 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
                        if (nesqp->flush_issued == 0) {
                                nesqp->flush_issued = 1;
                                spin_unlock_irqrestore(&nesqp->lock, flags);
-                               flush_wqes(nesvnic->nesdev, nesqp, NES_CQP_FLUSH_RQ, 1);
-                       } else {
+                               flush_wqes(nesvnic->nesdev, nesqp,
+                                       NES_CQP_FLUSH_RQ, 1);
+                       } else
                                spin_unlock_irqrestore(&nesqp->lock, flags);
-                       }
-
-                       /* This reference is from either ModifyQP or the AE processing,
-                                       there is still a race here with modifyqp */
-                       nes_rem_ref(&nesqp->ibqp);
-
                } else {
                        cm_id = nesqp->cm_id;
                        spin_unlock_irqrestore(&nesqp->lock, flags);
                        /* check to see if the inbound reset beat the outbound reset */
                        if ((!cm_id) && (last_ae==NES_AEQE_AEID_RESET_SENT)) {
-                               nes_debug(NES_DBG_CM, "QP%u: Decing refcount due to inbound reset"
-                                               " beating the outbound reset.\n",
-                                               nesqp->hwqp.qp_id);
-                               nes_rem_ref(&nesqp->ibqp);
+                               nes_debug(NES_DBG_CM, "QP%u: Decing refcount "
+                                       "due to inbound reset beating the "
+                                       "outbound reset.\n", nesqp->hwqp.qp_id);
                        }
                }
        } else {
                nesqp->disconn_pending = 0;
                spin_unlock_irqrestore(&nesqp->lock, flags);
        }
-       nes_rem_ref(&nesqp->ibqp);
 
        return 0;
 }
@@ -2349,71 +2544,82 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        nesdev = nesvnic->nesdev;
        adapter = nesdev->nesadapter;
 
-       nes_debug(NES_DBG_CM, "nesvnic=%p, netdev=%p, %s\n",
-                       nesvnic, nesvnic->netdev, nesvnic->netdev->name);
-
-       /* since this is from a listen, we were able to put node handle into cm_id */
        cm_node = (struct nes_cm_node *)cm_id->provider_data;
+       nes_debug(NES_DBG_CM, "nes_accept: cm_node= %p nesvnic=%p, netdev=%p,"
+               "%s\n", cm_node, nesvnic, nesvnic->netdev,
+               nesvnic->netdev->name);
 
        /* associate the node with the QP */
        nesqp->cm_node = (void *)cm_node;
+       cm_node->nesqp = nesqp;
+       nes_add_ref(&nesqp->ibqp);
 
-       nes_debug(NES_DBG_CM, "QP%u, cm_node=%p, jiffies = %lu\n",
-                       nesqp->hwqp.qp_id, cm_node, jiffies);
+       nes_debug(NES_DBG_CM, "QP%u, cm_node=%p, jiffies = %lu listener = %p\n",
+               nesqp->hwqp.qp_id, cm_node, jiffies, cm_node->listener);
        atomic_inc(&cm_accepts);
 
        nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",
                        atomic_read(&nesvnic->netdev->refcnt));
 
-               /* allocate the ietf frame and space for private data */
-               nesqp->ietf_frame = pci_alloc_consistent(nesdev->pcidev,
-                               sizeof(struct ietf_mpa_frame) + conn_param->private_data_len,
-                               &nesqp->ietf_frame_pbase);
-
-               if (!nesqp->ietf_frame) {
-                       nes_debug(NES_DBG_CM, "Unable to allocate memory for private data\n");
-                       return -ENOMEM;
-               }
+       /* allocate the ietf frame and space for private data */
+       nesqp->ietf_frame = pci_alloc_consistent(nesdev->pcidev,
+               sizeof(struct ietf_mpa_frame) + conn_param->private_data_len,
+               &nesqp->ietf_frame_pbase);
 
+       if (!nesqp->ietf_frame) {
+               nes_debug(NES_DBG_CM, "Unable to allocate memory for private "
+                       "data\n");
+               return -ENOMEM;
+       }
 
-               /* setup the MPA frame */
-               nesqp->private_data_len = conn_param->private_data_len;
-               memcpy(nesqp->ietf_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE);
 
-               memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data,
-                               conn_param->private_data_len);
+       /* setup the MPA frame */
+       nesqp->private_data_len = conn_param->private_data_len;
+       memcpy(nesqp->ietf_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE);
 
-               nesqp->ietf_frame->priv_data_len = cpu_to_be16(conn_param->private_data_len);
-               nesqp->ietf_frame->rev = mpa_version;
-               nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC;
+       memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data,
+                       conn_param->private_data_len);
 
-               /* setup our first outgoing iWarp send WQE (the IETF frame response) */
-               wqe = &nesqp->hwqp.sq_vbase[0];
+       nesqp->ietf_frame->priv_data_len =
+               cpu_to_be16(conn_param->private_data_len);
+       nesqp->ietf_frame->rev = mpa_version;
+       nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC;
 
-               if (cm_id->remote_addr.sin_addr.s_addr != cm_id->local_addr.sin_addr.s_addr) {
-                       u64temp = (unsigned long)nesqp;
-                       u64temp |= NES_SW_CONTEXT_ALIGN>>1;
-                       set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX,
-                                           u64temp);
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] =
-                                       cpu_to_le32(NES_IWARP_SQ_WQE_STREAMING | NES_IWARP_SQ_WQE_WRPDU);
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] =
-                                       cpu_to_le32(conn_param->private_data_len + sizeof(struct ietf_mpa_frame));
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] =
-                                       cpu_to_le32((u32)nesqp->ietf_frame_pbase);
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] =
-                                       cpu_to_le32((u32)((u64)nesqp->ietf_frame_pbase >> 32));
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] =
-                                       cpu_to_le32(conn_param->private_data_len + sizeof(struct ietf_mpa_frame));
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;
-
-                       nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32(
-                                       NES_QPCONTEXT_ORDIRD_LSMM_PRESENT | NES_QPCONTEXT_ORDIRD_WRPDU);
-               } else {
-                       nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
-                                       NES_QPCONTEXT_ORDIRD_WRPDU | NES_QPCONTEXT_ORDIRD_ALSMM));
-               }
-               nesqp->skip_lsmm = 1;
+       /* setup our first outgoing iWarp send WQE (the IETF frame response) */
+       wqe = &nesqp->hwqp.sq_vbase[0];
+
+       if (cm_id->remote_addr.sin_addr.s_addr !=
+                       cm_id->local_addr.sin_addr.s_addr) {
+               u64temp = (unsigned long)nesqp;
+               u64temp |= NES_SW_CONTEXT_ALIGN>>1;
+               set_wqe_64bit_value(wqe->wqe_words,
+                       NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX,
+                       u64temp);
+               wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] =
+                       cpu_to_le32(NES_IWARP_SQ_WQE_STREAMING |
+                       NES_IWARP_SQ_WQE_WRPDU);
+               wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] =
+                       cpu_to_le32(conn_param->private_data_len +
+                       sizeof(struct ietf_mpa_frame));
+               wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] =
+                       cpu_to_le32((u32)nesqp->ietf_frame_pbase);
+               wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] =
+                       cpu_to_le32((u32)((u64)nesqp->ietf_frame_pbase >> 32));
+               wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] =
+                       cpu_to_le32(conn_param->private_data_len +
+                       sizeof(struct ietf_mpa_frame));
+               wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;
+
+               nesqp->nesqp_context->ird_ord_sizes |=
+                       cpu_to_le32(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
+                       NES_QPCONTEXT_ORDIRD_WRPDU);
+       } else {
+               nesqp->nesqp_context->ird_ord_sizes |=
+                       cpu_to_le32((NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
+                       NES_QPCONTEXT_ORDIRD_WRPDU |
+                       NES_QPCONTEXT_ORDIRD_ALSMM));
+       }
+       nesqp->skip_lsmm = 1;
 
 
        /* Cache the cm_id in the qp */
@@ -2424,55 +2630,75 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        cm_id->provider_data = nesqp;
        nesqp->active_conn   = 0;
 
+       if (cm_node->state == NES_CM_STATE_TSA)
+               nes_debug(NES_DBG_CM, "Already state = TSA for cm_node=%p\n",
+                       cm_node);
+
        nes_cm_init_tsa_conn(nesqp, cm_node);
 
-       nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(ntohs(cm_id->local_addr.sin_port));
-       nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(ntohs(cm_id->remote_addr.sin_port));
-       nesqp->nesqp_context->ip0 = cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr));
+       nesqp->nesqp_context->tcpPorts[0] =
+               cpu_to_le16(ntohs(cm_id->local_addr.sin_port));
+       nesqp->nesqp_context->tcpPorts[1] =
+               cpu_to_le16(ntohs(cm_id->remote_addr.sin_port));
+
+       if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr))
+               nesqp->nesqp_context->ip0 =
+                       cpu_to_le32(ntohl(nesvnic->local_ipaddr));
+       else
+               nesqp->nesqp_context->ip0 =
+                       cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr));
 
        nesqp->nesqp_context->misc2 |= cpu_to_le32(
-                       (u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);
+                       (u32)PCI_FUNC(nesdev->pcidev->devfn) <<
+                       NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);
 
-       nesqp->nesqp_context->arp_index_vlan |= cpu_to_le32(
-                       nes_arp_table(nesdev, le32_to_cpu(nesqp->nesqp_context->ip0), NULL,
+       nesqp->nesqp_context->arp_index_vlan |=
+               cpu_to_le32(nes_arp_table(nesdev,
+                       le32_to_cpu(nesqp->nesqp_context->ip0), NULL,
                        NES_ARP_RESOLVE) << 16);
 
        nesqp->nesqp_context->ts_val_delta = cpu_to_le32(
-                       jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW));
+               jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW));
 
        nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id);
 
        nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32(
-                       ((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT));
-       nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)conn_param->ord);
+               ((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT));
+       nesqp->nesqp_context->ird_ord_sizes |=
+               cpu_to_le32((u32)conn_param->ord);
 
        memset(&nes_quad, 0, sizeof(nes_quad));
-       nes_quad.DstIpAdrIndex = cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
-       nes_quad.SrcIpadr      = cm_id->remote_addr.sin_addr.s_addr;
-       nes_quad.TcpPorts[0]   = cm_id->remote_addr.sin_port;
-       nes_quad.TcpPorts[1]   = cm_id->local_addr.sin_port;
+       nes_quad.DstIpAdrIndex =
+               cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
+       if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr))
+               nes_quad.SrcIpadr = nesvnic->local_ipaddr;
+       else
+               nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr;
+       nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port;
+       nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port;
 
        /* Produce hash key */
        crc_value = get_crc_value(&nes_quad);
        nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff);
        nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, CRC = 0x%08X\n",
-                       nesqp->hte_index, nesqp->hte_index & adapter->hte_index_mask);
+               nesqp->hte_index, nesqp->hte_index & adapter->hte_index_mask);
 
        nesqp->hte_index &= adapter->hte_index_mask;
        nesqp->nesqp_context->hte_index = cpu_to_le32(nesqp->hte_index);
 
        cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node);
 
-       nes_debug(NES_DBG_CM, "QP%u, Destination IP = 0x%08X:0x%04X, local = 0x%08X:0x%04X,"
-                       " rcv_nxt=0x%08X, snd_nxt=0x%08X, mpa + private data length=%zu.\n",
-                       nesqp->hwqp.qp_id,
+       nes_debug(NES_DBG_CM, "QP%u, Destination IP = 0x%08X:0x%04X, local = "
+                       "0x%08X:0x%04X, rcv_nxt=0x%08X, snd_nxt=0x%08X, mpa + "
+                       "private data length=%zu.\n", nesqp->hwqp.qp_id,
                        ntohl(cm_id->remote_addr.sin_addr.s_addr),
                        ntohs(cm_id->remote_addr.sin_port),
                        ntohl(cm_id->local_addr.sin_addr.s_addr),
                        ntohs(cm_id->local_addr.sin_port),
                        le32_to_cpu(nesqp->nesqp_context->rcv_nxt),
                        le32_to_cpu(nesqp->nesqp_context->snd_nxt),
-                       conn_param->private_data_len+sizeof(struct ietf_mpa_frame));
+                       conn_param->private_data_len +
+                       sizeof(struct ietf_mpa_frame));
 
        attr.qp_state = IB_QPS_RTS;
        nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
@@ -2489,15 +2715,16 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        cm_event.private_data_len = 0;
        ret = cm_id->event_handler(cm_id, &cm_event);
        if (cm_node->loopbackpartner) {
-               cm_node->loopbackpartner->mpa_frame_size = nesqp->private_data_len;
+               cm_node->loopbackpartner->mpa_frame_size =
+                       nesqp->private_data_len;
                /* copy entire MPA frame to our cm_node's frame */
-               memcpy(cm_node->loopbackpartner->mpa_frame_buf, nesqp->ietf_frame->priv_data,
-                          nesqp->private_data_len);
+               memcpy(cm_node->loopbackpartner->mpa_frame_buf,
+                       nesqp->ietf_frame->priv_data, nesqp->private_data_len);
                create_event(cm_node->loopbackpartner, NES_CM_EVENT_CONNECTED);
        }
        if (ret)
-               printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
-                               __func__, __LINE__, ret);
+               printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "
+                       "ret=%d\n", __func__, __LINE__, ret);
 
        return 0;
 }
@@ -2555,74 +2782,61 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        if (!nesdev)
                return -EINVAL;
 
-       atomic_inc(&cm_connects);
-
-       nesqp->ietf_frame = kzalloc(sizeof(struct ietf_mpa_frame) +
-                       conn_param->private_data_len, GFP_KERNEL);
-       if (!nesqp->ietf_frame)
-               return -ENOMEM;
+       nes_debug(NES_DBG_CM, "QP%u, current IP = 0x%08X, Destination IP = "
+               "0x%08X:0x%04X, local = 0x%08X:0x%04X.\n", nesqp->hwqp.qp_id,
+               ntohl(nesvnic->local_ipaddr),
+               ntohl(cm_id->remote_addr.sin_addr.s_addr),
+               ntohs(cm_id->remote_addr.sin_port),
+               ntohl(cm_id->local_addr.sin_addr.s_addr),
+               ntohs(cm_id->local_addr.sin_port));
 
-       /* set qp as having an active connection */
+       atomic_inc(&cm_connects);
        nesqp->active_conn = 1;
 
-       nes_debug(NES_DBG_CM, "QP%u, Destination IP = 0x%08X:0x%04X, local = 0x%08X:0x%04X.\n",
-                       nesqp->hwqp.qp_id,
-                       ntohl(cm_id->remote_addr.sin_addr.s_addr),
-                       ntohs(cm_id->remote_addr.sin_port),
-                       ntohl(cm_id->local_addr.sin_addr.s_addr),
-                       ntohs(cm_id->local_addr.sin_port));
-
        /* cache the cm_id in the qp */
        nesqp->cm_id = cm_id;
 
        cm_id->provider_data = nesqp;
 
-       /* copy the private data */
-       if (conn_param->private_data_len) {
-               memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data,
-                               conn_param->private_data_len);
-       }
-
        nesqp->private_data_len = conn_param->private_data_len;
        nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)conn_param->ord);
        nes_debug(NES_DBG_CM, "requested ord = 0x%08X.\n", (u32)conn_param->ord);
-       nes_debug(NES_DBG_CM, "mpa private data len =%u\n", conn_param->private_data_len);
-
-       strcpy(&nesqp->ietf_frame->key[0], IEFT_MPA_KEY_REQ);
-       nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC;
-       nesqp->ietf_frame->rev = IETF_MPA_VERSION;
-       nesqp->ietf_frame->priv_data_len = htons(conn_param->private_data_len);
+       nes_debug(NES_DBG_CM, "mpa private data len =%u\n",
+               conn_param->private_data_len);
 
-       if (cm_id->local_addr.sin_addr.s_addr != cm_id->remote_addr.sin_addr.s_addr)
+       if (cm_id->local_addr.sin_addr.s_addr !=
+               cm_id->remote_addr.sin_addr.s_addr)
                nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),
-                               PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);
+                       PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);
 
        /* set up the connection params for the node */
-       cm_info.loc_addr = (cm_id->local_addr.sin_addr.s_addr);
-       cm_info.loc_port = (cm_id->local_addr.sin_port);
-       cm_info.rem_addr = (cm_id->remote_addr.sin_addr.s_addr);
-       cm_info.rem_port = (cm_id->remote_addr.sin_port);
+       cm_info.loc_addr = htonl(cm_id->local_addr.sin_addr.s_addr);
+       cm_info.loc_port = htons(cm_id->local_addr.sin_port);
+       cm_info.rem_addr = htonl(cm_id->remote_addr.sin_addr.s_addr);
+       cm_info.rem_port = htons(cm_id->remote_addr.sin_port);
        cm_info.cm_id = cm_id;
        cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
 
        cm_id->add_ref(cm_id);
-       nes_add_ref(&nesqp->ibqp);
 
        /* create a connect CM node connection */
-       cm_node = g_cm_core->api->connect(g_cm_core, nesvnic, nesqp->ietf_frame, &cm_info);
+       cm_node = g_cm_core->api->connect(g_cm_core, nesvnic,
+               conn_param->private_data_len, (void *)conn_param->private_data,
+               &cm_info);
        if (!cm_node) {
-               if (cm_id->local_addr.sin_addr.s_addr != cm_id->remote_addr.sin_addr.s_addr)
+               if (cm_id->local_addr.sin_addr.s_addr !=
+                               cm_id->remote_addr.sin_addr.s_addr)
                        nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),
-                                       PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_DEL);
-               nes_rem_ref(&nesqp->ibqp);
-               kfree(nesqp->ietf_frame);
-               nesqp->ietf_frame = NULL;
+                               PCI_FUNC(nesdev->pcidev->devfn),
+                               NES_MANAGE_APBVT_DEL);
+
                cm_id->rem_ref(cm_id);
                return -ENOMEM;
        }
 
        cm_node->apbvt_set = 1;
        nesqp->cm_node = cm_node;
+       cm_node->nesqp = nesqp;
 
        return 0;
 }
@@ -2664,7 +2878,7 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
 
        cm_node = g_cm_core->api->listen(g_cm_core, nesvnic, &cm_info);
        if (!cm_node) {
-               printk("%s[%u] Error returned from listen API call\n",
+               printk(KERN_ERR "%s[%u] Error returned from listen API call\n",
                                __func__, __LINE__);
                return -ENOMEM;
        }
@@ -2672,10 +2886,13 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
        cm_id->provider_data = cm_node;
 
        if (!cm_node->reused_node) {
-               err = nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),
-                               PCI_FUNC(nesvnic->nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);
+               err = nes_manage_apbvt(nesvnic,
+                       ntohs(cm_id->local_addr.sin_port),
+                       PCI_FUNC(nesvnic->nesdev->pcidev->devfn),
+                       NES_MANAGE_APBVT_ADD);
                if (err) {
-                       printk("nes_manage_apbvt call returned %d.\n", err);
+                       printk(KERN_ERR "nes_manage_apbvt call returned %d.\n",
+                               err);
                        g_cm_core->api->stop_listener(g_cm_core, (void *)cm_node);
                        return err;
                }
@@ -2795,53 +3012,70 @@ static void cm_event_connected(struct nes_cm_event *event)
        nes_cm_init_tsa_conn(nesqp, cm_node);
 
        /* set the QP tsa context */
-       nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(ntohs(cm_id->local_addr.sin_port));
-       nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(ntohs(cm_id->remote_addr.sin_port));
-       nesqp->nesqp_context->ip0 = cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr));
+       nesqp->nesqp_context->tcpPorts[0] =
+               cpu_to_le16(ntohs(cm_id->local_addr.sin_port));
+       nesqp->nesqp_context->tcpPorts[1] =
+               cpu_to_le16(ntohs(cm_id->remote_addr.sin_port));
+       if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr))
+               nesqp->nesqp_context->ip0 =
+                       cpu_to_le32(ntohl(nesvnic->local_ipaddr));
+       else
+               nesqp->nesqp_context->ip0 =
+                       cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr));
 
        nesqp->nesqp_context->misc2 |= cpu_to_le32(
-                       (u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);
+                       (u32)PCI_FUNC(nesdev->pcidev->devfn) <<
+                       NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);
        nesqp->nesqp_context->arp_index_vlan |= cpu_to_le32(
-                       nes_arp_table(nesdev, le32_to_cpu(nesqp->nesqp_context->ip0),
+                       nes_arp_table(nesdev,
+                       le32_to_cpu(nesqp->nesqp_context->ip0),
                        NULL, NES_ARP_RESOLVE) << 16);
        nesqp->nesqp_context->ts_val_delta = cpu_to_le32(
                        jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW));
        nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id);
        nesqp->nesqp_context->ird_ord_sizes |=
-                       cpu_to_le32((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT);
+                       cpu_to_le32((u32)1 <<
+                       NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT);
 
        /* Adjust tail for not having a LSMM */
        nesqp->hwqp.sq_tail = 1;
 
 #if defined(NES_SEND_FIRST_WRITE)
-               if (cm_node->send_write0) {
-                       nes_debug(NES_DBG_CM, "Sending first write.\n");
-                       wqe = &nesqp->hwqp.sq_vbase[0];
-                       u64temp = (unsigned long)nesqp;
-                       u64temp |= NES_SW_CONTEXT_ALIGN>>1;
-                       set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX,
-                                           u64temp);
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] = cpu_to_le32(NES_IWARP_SQ_OP_RDMAW);
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] = 0;
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] = 0;
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] = 0;
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] = 0;
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;
-
-                       /* use the reserved spot on the WQ for the extra first WQE */
-                       nesqp->nesqp_context->ird_ord_sizes &= cpu_to_le32(~(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
-                                       NES_QPCONTEXT_ORDIRD_WRPDU | NES_QPCONTEXT_ORDIRD_ALSMM));
-                       nesqp->skip_lsmm = 1;
-                       nesqp->hwqp.sq_tail = 0;
-                       nes_write32(nesdev->regs + NES_WQE_ALLOC,
-                                       (1 << 24) | 0x00800000 | nesqp->hwqp.qp_id);
-               }
+       if (cm_node->send_write0) {
+               nes_debug(NES_DBG_CM, "Sending first write.\n");
+               wqe = &nesqp->hwqp.sq_vbase[0];
+               u64temp = (unsigned long)nesqp;
+               u64temp |= NES_SW_CONTEXT_ALIGN>>1;
+               set_wqe_64bit_value(wqe->wqe_words,
+                               NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, u64temp);
+               wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] =
+                       cpu_to_le32(NES_IWARP_SQ_OP_RDMAW);
+               wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] = 0;
+               wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] = 0;
+               wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] = 0;
+               wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] = 0;
+               wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;
+
+               /* use the reserved spot on the WQ for the extra first WQE */
+               nesqp->nesqp_context->ird_ord_sizes &=
+                       cpu_to_le32(~(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
+                                               NES_QPCONTEXT_ORDIRD_WRPDU |
+                                               NES_QPCONTEXT_ORDIRD_ALSMM));
+               nesqp->skip_lsmm = 1;
+               nesqp->hwqp.sq_tail = 0;
+               nes_write32(nesdev->regs + NES_WQE_ALLOC,
+                               (1 << 24) | 0x00800000 | nesqp->hwqp.qp_id);
+       }
 #endif
 
        memset(&nes_quad, 0, sizeof(nes_quad));
 
-       nes_quad.DstIpAdrIndex = cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
-       nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr;
+       nes_quad.DstIpAdrIndex =
+               cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
+       if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr))
+               nes_quad.SrcIpadr = nesvnic->local_ipaddr;
+       else
+               nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr;
        nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port;
        nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port;
 
@@ -2858,10 +3092,6 @@ static void cm_event_connected(struct nes_cm_event *event)
        nesqp->private_data_len = (u8) cm_node->mpa_frame_size;
        cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node);
 
-       /* modify QP state to rts */
-       attr.qp_state = IB_QPS_RTS;
-       nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
-
        /* notify OF layer we successfully created the requested connection */
        cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
        cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED;
@@ -2870,20 +3100,21 @@ static void cm_event_connected(struct nes_cm_event *event)
        cm_event.local_addr.sin_port = cm_id->local_addr.sin_port;
        cm_event.remote_addr = cm_id->remote_addr;
 
-               cm_event.private_data = (void *)event->cm_node->mpa_frame_buf;
-               cm_event.private_data_len = (u8) event->cm_node->mpa_frame_size;
+       cm_event.private_data = (void *)event->cm_node->mpa_frame_buf;
+       cm_event.private_data_len = (u8) event->cm_node->mpa_frame_size;
 
        cm_event.local_addr.sin_addr.s_addr = event->cm_info.rem_addr;
        ret = cm_id->event_handler(cm_id, &cm_event);
        nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
 
        if (ret)
-               printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
-                               __func__, __LINE__, ret);
-       nes_debug(NES_DBG_CM, "Exiting connect thread for QP%u. jiffies = %lu\n",
-                       nesqp->hwqp.qp_id, jiffies );
+               printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "
+                       "ret=%d\n", __func__, __LINE__, ret);
+       attr.qp_state = IB_QPS_RTS;
+       nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
 
-       nes_rem_ref(&nesqp->ibqp);
+       nes_debug(NES_DBG_CM, "Exiting connect thread for QP%u. jiffies = "
+               "%lu\n", nesqp->hwqp.qp_id, jiffies);
 
        return;
 }
@@ -2927,17 +3158,19 @@ static void cm_event_connect_error(struct nes_cm_event *event)
        cm_event.private_data = NULL;
        cm_event.private_data_len = 0;
 
-       nes_debug(NES_DBG_CM, "call CM_EVENT REJECTED, local_addr=%08x, remove_addr=%08x\n",
-                       cm_event.local_addr.sin_addr.s_addr, cm_event.remote_addr.sin_addr.s_addr);
+       nes_debug(NES_DBG_CM, "call CM_EVENT REJECTED, local_addr=%08x, "
+               "remove_addr=%08x\n", cm_event.local_addr.sin_addr.s_addr,
+               cm_event.remote_addr.sin_addr.s_addr);
 
        ret = cm_id->event_handler(cm_id, &cm_event);
        nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
        if (ret)
-               printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
-                               __func__, __LINE__, ret);
+               printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "
+                       "ret=%d\n", __func__, __LINE__, ret);
        nes_rem_ref(&nesqp->ibqp);
-               cm_id->rem_ref(cm_id);
+       cm_id->rem_ref(cm_id);
 
+       rem_ref_cm_node(event->cm_node->cm_core, event->cm_node);
        return;
 }
 
@@ -3040,7 +3273,8 @@ static int nes_cm_post_event(struct nes_cm_event *event)
        add_ref_cm_node(event->cm_node);
        event->cm_info.cm_id->add_ref(event->cm_info.cm_id);
        INIT_WORK(&event->event_work, nes_cm_event_handler);
-       nes_debug(NES_DBG_CM, "queue_work, event=%p\n", event);
+       nes_debug(NES_DBG_CM, "cm_node=%p queue_work, event=%p\n",
+               event->cm_node, event);
 
        queue_work(event->cm_node->cm_core->event_wq, &event->event_work);
 
@@ -3056,46 +3290,48 @@ static int nes_cm_post_event(struct nes_cm_event *event)
  */
 static void nes_cm_event_handler(struct work_struct *work)
 {
-       struct nes_cm_event *event = container_of(work, struct nes_cm_event, event_work);
+       struct nes_cm_event *event = container_of(work, struct nes_cm_event,
+                       event_work);
        struct nes_cm_core *cm_core;
 
-       if ((!event) || (!event->cm_node) || (!event->cm_node->cm_core)) {
+       if ((!event) || (!event->cm_node) || (!event->cm_node->cm_core))
                return;
-       }
+
        cm_core = event->cm_node->cm_core;
        nes_debug(NES_DBG_CM, "event=%p, event->type=%u, events posted=%u\n",
-                       event, event->type, atomic_read(&cm_core->events_posted));
+               event, event->type, atomic_read(&cm_core->events_posted));
 
        switch (event->type) {
-               case NES_CM_EVENT_MPA_REQ:
-                       cm_event_mpa_req(event);
-                       nes_debug(NES_DBG_CM, "CM Event: MPA REQUEST\n");
-                       break;
-               case NES_CM_EVENT_RESET:
-                       nes_debug(NES_DBG_CM, "CM Event: RESET\n");
-                       cm_event_reset(event);
-                       break;
-               case NES_CM_EVENT_CONNECTED:
-                       if ((!event->cm_node->cm_id) ||
-                               (event->cm_node->state != NES_CM_STATE_TSA)) {
-                               break;
-                       }
-                       cm_event_connected(event);
-                       nes_debug(NES_DBG_CM, "CM Event: CONNECTED\n");
+       case NES_CM_EVENT_MPA_REQ:
+               cm_event_mpa_req(event);
+               nes_debug(NES_DBG_CM, "cm_node=%p CM Event: MPA REQUEST\n",
+                       event->cm_node);
+               break;
+       case NES_CM_EVENT_RESET:
+               nes_debug(NES_DBG_CM, "cm_node = %p CM Event: RESET\n",
+                       event->cm_node);
+               cm_event_reset(event);
+               break;
+       case NES_CM_EVENT_CONNECTED:
+               if ((!event->cm_node->cm_id) ||
+                       (event->cm_node->state != NES_CM_STATE_TSA))
                        break;
-               case NES_CM_EVENT_ABORTED:
-                       if ((!event->cm_node->cm_id) || (event->cm_node->state == NES_CM_STATE_TSA)) {
-                               break;
-                       }
-                       cm_event_connect_error(event);
-                       nes_debug(NES_DBG_CM, "CM Event: ABORTED\n");
-                       break;
-               case NES_CM_EVENT_DROPPED_PKT:
-                       nes_debug(NES_DBG_CM, "CM Event: DROPPED PKT\n");
-                       break;
-               default:
-                       nes_debug(NES_DBG_CM, "CM Event: UNKNOWN EVENT TYPE\n");
+               cm_event_connected(event);
+               nes_debug(NES_DBG_CM, "CM Event: CONNECTED\n");
+               break;
+       case NES_CM_EVENT_ABORTED:
+               if ((!event->cm_node->cm_id) ||
+                       (event->cm_node->state == NES_CM_STATE_TSA))
                        break;
+               cm_event_connect_error(event);
+               nes_debug(NES_DBG_CM, "CM Event: ABORTED\n");
+               break;
+       case NES_CM_EVENT_DROPPED_PKT:
+               nes_debug(NES_DBG_CM, "CM Event: DROPPED PKT\n");
+               break;
+       default:
+               nes_debug(NES_DBG_CM, "CM Event: UNKNOWN EVENT TYPE\n");
+               break;
        }
 
        atomic_dec(&cm_core->events_posted);
index 7717cb2..367b3d2 100644 (file)
@@ -83,6 +83,8 @@ enum nes_timer_type {
 #define SET_FIN 4
 #define SET_RST 8
 
+#define TCP_OPTIONS_PADDING    3
+
 struct option_base {
        u8 optionnum;
        u8 length;
@@ -177,6 +179,7 @@ enum nes_cm_node_state {
        NES_CM_STATE_ESTABLISHED,
        NES_CM_STATE_ACCEPTING,
        NES_CM_STATE_MPAREQ_SENT,
+       NES_CM_STATE_MPAREQ_RCVD,
        NES_CM_STATE_TSA,
        NES_CM_STATE_FIN_WAIT1,
        NES_CM_STATE_FIN_WAIT2,
@@ -187,6 +190,16 @@ enum nes_cm_node_state {
        NES_CM_STATE_CLOSED
 };
 
+enum nes_tcpip_pkt_type {
+       NES_PKT_TYPE_UNKNOWN,
+       NES_PKT_TYPE_SYN,
+       NES_PKT_TYPE_SYNACK,
+       NES_PKT_TYPE_ACK,
+       NES_PKT_TYPE_FIN,
+       NES_PKT_TYPE_RST
+};
+
+
 /* type of nes connection */
 enum nes_cm_conn_type {
        NES_CM_IWARP_CONN_TYPE,
@@ -257,7 +270,9 @@ struct nes_cm_node {
        struct net_device         *netdev;
 
        struct nes_cm_node        *loopbackpartner;
-       struct list_head          retrans_list;
+
+       struct nes_timer_entry  *send_entry;
+
        spinlock_t                retrans_list_lock;
        struct list_head          recv_list;
        spinlock_t                recv_list_lock;
@@ -276,6 +291,8 @@ struct nes_cm_node {
        struct nes_vnic           *nesvnic;
        int                       apbvt_set;
        int                       accept_pend;
+       int                     freed;
+       struct nes_qp           *nesqp;
 };
 
 /* structure for client or CM to fill when making CM api calls. */
@@ -366,14 +383,14 @@ struct nes_cm_ops {
                        struct nes_cm_info *);
        int (*stop_listener)(struct nes_cm_core *, struct nes_cm_listener *);
        struct nes_cm_node * (*connect)(struct nes_cm_core *,
-                       struct nes_vnic *, struct ietf_mpa_frame *,
+                       struct nes_vnic *, u16, void *,
                        struct nes_cm_info *);
        int (*close)(struct nes_cm_core *, struct nes_cm_node *);
        int (*accept)(struct nes_cm_core *, struct ietf_mpa_frame *,
                        struct nes_cm_node *);
        int (*reject)(struct nes_cm_core *, struct ietf_mpa_frame *,
                        struct nes_cm_node *);
-       int (*recv_pkt)(struct nes_cm_core *, struct nes_vnic *,
+       void (*recv_pkt)(struct nes_cm_core *, struct nes_vnic *,
                        struct sk_buff *);
        int (*destroy_cm_core)(struct nes_cm_core *);
        int (*get)(struct nes_cm_core *);
index 85f26d1..1513d40 100644 (file)
@@ -2814,7 +2814,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
                        nesqp = *((struct nes_qp **)&context);
                        if (atomic_inc_return(&nesqp->close_timer_started) == 1) {
                                nesqp->cm_id->add_ref(nesqp->cm_id);
-                               nes_add_ref(&nesqp->ibqp);
                                schedule_nes_timer(nesqp->cm_node, (struct sk_buff *)nesqp,
                                                NES_TIMER_TYPE_CLOSE, 1, 0);
                                nes_debug(NES_DBG_AEQ, "QP%u Not decrementing QP refcount (%d),"
@@ -2838,7 +2837,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
                        if (async_event_id == NES_AEQE_AEID_RESET_SENT) {
                                tcp_state = NES_AEQE_TCP_STATE_CLOSED;
                        }
-                       nes_add_ref(&nesqp->ibqp);
                        spin_lock_irqsave(&nesqp->lock, flags);
                        nesqp->hw_iwarp_state = iwarp_state;
                        nesqp->hw_tcp_state = tcp_state;
@@ -2876,7 +2874,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
                                }
                                spin_unlock_irqrestore(&nesqp->lock, flags);
                                if (next_iwarp_state) {
-                                       nes_add_ref(&nesqp->ibqp);
                                        nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X,"
                                                        " also added another reference\n",
                                                        nesqp->hwqp.qp_id, next_iwarp_state);
@@ -2888,7 +2885,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
                                        /* FIN Received but ib state not RTS,
                                                        close complete will be on its way */
                                        spin_unlock_irqrestore(&nesqp->lock, flags);
-                                       nes_rem_ref(&nesqp->ibqp);
                                        return;
                                }
                                spin_unlock_irqrestore(&nesqp->lock, flags);
@@ -2922,7 +2918,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
                        if ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
                                        ((nesqp->ibqp_state == IB_QPS_RTS)&&
                                        (async_event_id == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
-                               nes_add_ref(&nesqp->ibqp);
                                nes_cm_disconn(nesqp);
                        } else {
                                nesqp->in_disconnect = 0;
@@ -2931,7 +2926,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
                        break;
                case NES_AEQE_AEID_LLP_TOO_MANY_RETRIES:
                        nesqp = *((struct nes_qp **)&context);
-                       nes_add_ref(&nesqp->ibqp);
                        spin_lock_irqsave(&nesqp->lock, flags);
                        nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_ERROR;
                        nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
@@ -3042,7 +3036,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
                                nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
                        }
                        /* tell cm to disconnect, cm will queue work to thread */
-                       nes_add_ref(&nesqp->ibqp);
                        nes_cm_disconn(nesqp);
                        break;
                case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE:
@@ -3062,7 +3055,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
                                nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
                        }
                        /* tell cm to disconnect, cm will queue work to thread */
-                       nes_add_ref(&nesqp->ibqp);
                        nes_cm_disconn(nesqp);
                        break;
                case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR:
@@ -3082,7 +3074,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
                                nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
                        }
                        /* tell cm to disconnect, cm will queue work to thread */
-                       nes_add_ref(&nesqp->ibqp);
                        nes_cm_disconn(nesqp);
                        break;
                        /* TODO: additional AEs need to be here */
index e3939d1..d79942e 100644 (file)
@@ -2867,7 +2867,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                        nesqp->hwqp.qp_id, attr->qp_state, nesqp->ibqp_state,
                        nesqp->iwarp_state, atomic_read(&nesqp->refcount));
 
-       nes_add_ref(&nesqp->ibqp);
        spin_lock_irqsave(&nesqp->lock, qplockflags);
 
        nes_debug(NES_DBG_MOD_QP, "QP%u: hw_iwarp_state=0x%X, hw_tcp_state=0x%X,"
@@ -2882,7 +2881,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                                                nesqp->hwqp.qp_id);
                                if (nesqp->iwarp_state > (u32)NES_CQP_QP_IWARP_STATE_IDLE) {
                                        spin_unlock_irqrestore(&nesqp->lock, qplockflags);
-                                       nes_rem_ref(&nesqp->ibqp);
                                        return -EINVAL;
                                }
                                next_iwarp_state = NES_CQP_QP_IWARP_STATE_IDLE;
@@ -2893,7 +2891,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                                                nesqp->hwqp.qp_id);
                                if (nesqp->iwarp_state>(u32)NES_CQP_QP_IWARP_STATE_IDLE) {
                                        spin_unlock_irqrestore(&nesqp->lock, qplockflags);
-                                       nes_rem_ref(&nesqp->ibqp);
                                        return -EINVAL;
                                }
                                next_iwarp_state = NES_CQP_QP_IWARP_STATE_IDLE;
@@ -2904,14 +2901,12 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                                                nesqp->hwqp.qp_id);
                                if (nesqp->iwarp_state>(u32)NES_CQP_QP_IWARP_STATE_RTS) {
                                        spin_unlock_irqrestore(&nesqp->lock, qplockflags);
-                                       nes_rem_ref(&nesqp->ibqp);
                                        return -EINVAL;
                                }
                                if (nesqp->cm_id == NULL) {
                                        nes_debug(NES_DBG_MOD_QP, "QP%u: Failing attempt to move QP to RTS without a CM_ID. \n",
                                                        nesqp->hwqp.qp_id );
                                        spin_unlock_irqrestore(&nesqp->lock, qplockflags);
-                                       nes_rem_ref(&nesqp->ibqp);
                                        return -EINVAL;
                                }
                                next_iwarp_state = NES_CQP_QP_IWARP_STATE_RTS;
@@ -2929,7 +2924,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                                                nesqp->hwqp.qp_id, nesqp->hwqp.sq_head, nesqp->hwqp.sq_tail);
                                if (nesqp->iwarp_state == (u32)NES_CQP_QP_IWARP_STATE_CLOSING) {
                                        spin_unlock_irqrestore(&nesqp->lock, qplockflags);
-                                       nes_rem_ref(&nesqp->ibqp);
                                        return 0;
                                } else {
                                        if (nesqp->iwarp_state > (u32)NES_CQP_QP_IWARP_STATE_CLOSING) {
@@ -2937,7 +2931,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                                                                " ignored due to current iWARP state\n",
                                                                nesqp->hwqp.qp_id);
                                                spin_unlock_irqrestore(&nesqp->lock, qplockflags);
-                                               nes_rem_ref(&nesqp->ibqp);
                                                return -EINVAL;
                                        }
                                        if (nesqp->hw_iwarp_state != NES_AEQE_IWARP_STATE_RTS) {
@@ -2969,7 +2962,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                                                nesqp->hwqp.qp_id);
                                if (nesqp->iwarp_state>=(u32)NES_CQP_QP_IWARP_STATE_TERMINATE) {
                                        spin_unlock_irqrestore(&nesqp->lock, qplockflags);
-                                       nes_rem_ref(&nesqp->ibqp);
                                        return -EINVAL;
                                }
                                /* next_iwarp_state = (NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000); */
@@ -2982,7 +2974,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                        case IB_QPS_RESET:
                                if (nesqp->iwarp_state == (u32)NES_CQP_QP_IWARP_STATE_ERROR) {
                                        spin_unlock_irqrestore(&nesqp->lock, qplockflags);
-                                       nes_rem_ref(&nesqp->ibqp);
                                        return -EINVAL;
                                }
                                nes_debug(NES_DBG_MOD_QP, "QP%u: new state = error\n",
@@ -3008,7 +2999,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                                break;
                        default:
                                spin_unlock_irqrestore(&nesqp->lock, qplockflags);
-                               nes_rem_ref(&nesqp->ibqp);
                                return -EINVAL;
                                break;
                }
@@ -3088,7 +3078,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                                                        nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
                                                        original_last_aeq, nesqp->last_aeq);
                                        /* this one is for the cm_disconnect thread */
-                                       nes_add_ref(&nesqp->ibqp);
                                        spin_lock_irqsave(&nesqp->lock, qplockflags);
                                        nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
                                        nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
@@ -3097,14 +3086,12 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                                } else {
                                        nes_debug(NES_DBG_MOD_QP, "QP%u No fake disconnect, QP refcount=%d\n",
                                                        nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount));
-                                       nes_rem_ref(&nesqp->ibqp);
                                }
                        } else {
                                spin_lock_irqsave(&nesqp->lock, qplockflags);
                                if (nesqp->cm_id) {
                                        /* These two are for the timer thread */
                                        if (atomic_inc_return(&nesqp->close_timer_started) == 1) {
-                                               nes_add_ref(&nesqp->ibqp);
                                                nesqp->cm_id->add_ref(nesqp->cm_id);
                                                nes_debug(NES_DBG_MOD_QP, "QP%u Not decrementing QP refcount (%d),"
                                                                " need ae to finish up, original_last_aeq = 0x%04X."
@@ -3128,14 +3115,12 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                                        " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
                                        nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
                                        original_last_aeq, nesqp->last_aeq);
-                       nes_rem_ref(&nesqp->ibqp);
                }
        } else {
                nes_debug(NES_DBG_MOD_QP, "QP%u Decrementing QP refcount (%d), No ae to finish up,"
                                " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
                                nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
                                original_last_aeq, nesqp->last_aeq);
-               nes_rem_ref(&nesqp->ibqp);
        }
 
        err = 0;