Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 26 Mar 2009 22:47:08 +0000 (15:47 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 26 Mar 2009 22:47:08 +0000 (15:47 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband: (30 commits)
  RDMA/cxgb3: Enforce required firmware
  IB/mlx4: Unregister IB device prior to CLOSE PORT command
  mlx4_core: Add link type autosensing
  mlx4_core: Don't perform SET_PORT command for Ethernet ports
  RDMA/nes: Handle MPA Reject message properly
  RDMA/nes: Improve use of PBLs
  RDMA/nes: Remove LLTX
  RDMA/nes: Inform hardware that asynchronous event has been handled
  RDMA/nes: Fix tmp_addr compilation warning
  RDMA/nes: Report correct vendor_id and vendor_part_id
  RDMA/nes: Update copyright to new legal entity and year
  RDMA/nes: Account for freed PBL after HW operation
  IB: Remove useless ibdev_is_alive() tests from sysfs code
  IB/sa_query: Fix AH leak due to update_sm_ah() race
  IB/mad: Fix ib_post_send_mad() returning 0 with no generate send comp
  IB/mad: initialize mad_agent_priv before putting on lists
  IB/mad: Fix null pointer dereference in local_completions()
  IB/mad: Fix RMPP header RRespTime manipulation
  IB/iser: Remove hard setting of path MTU
  mlx4_core: Add device IDs for MT25458 10GigE devices
  ...

1  2 
drivers/infiniband/hw/nes/nes_cm.c
drivers/infiniband/hw/nes/nes_verbs.c
drivers/infiniband/hw/nes/nes_verbs.h

index 4a65b96db2c8f07ea8de3a286155bc3e0cfce6c7,5327f2bec6bfeeecff2dcf13e96449efa8371dda..52425154acd48f9d4a8e3043d9b10295fe59440a
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+  * Copyright (c) 2006 - 2009 Intel-NE, Inc.  All rights reserved.
   *
   * This software is available to you under a choice of one of two
   * licenses.  You may choose to be licensed under the terms of the GNU
@@@ -103,6 -103,7 +103,7 @@@ static int nes_disconnect(struct nes_q
  static void nes_disconnect_worker(struct work_struct *work);
  
  static int send_mpa_request(struct nes_cm_node *, struct sk_buff *);
+ static int send_mpa_reject(struct nes_cm_node *);
  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);
@@@ -113,8 -114,7 +114,7 @@@ static void process_packet(struct nes_c
  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 handle_rcv_mpa(struct nes_cm_node *, struct sk_buff *);
  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);
@@@ -124,6 -124,8 +124,8 @@@ static void cm_event_connected(struct n
  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 cm_event_mpa_reject(struct nes_cm_event *);
+ static void handle_recv_entry(struct nes_cm_node *cm_node, u32 rem_node);
  
  static void print_core(struct nes_cm_core *core);
  
@@@ -196,7 -198,6 +198,6 @@@ static struct nes_cm_event *create_even
   */
  static int send_mpa_request(struct nes_cm_node *cm_node, struct sk_buff *skb)
  {
-       int ret;
        if (!skb) {
                nes_debug(NES_DBG_CM, "skb set to NULL\n");
                return -1;
        form_cm_frame(skb, cm_node, NULL, 0, &cm_node->mpa_frame,
                        cm_node->mpa_frame_size, SET_ACK);
  
-       ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
-       if (ret < 0)
-               return ret;
+       return schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
+ }
  
-       return 0;
+ static int send_mpa_reject(struct nes_cm_node *cm_node)
+ {
+       struct sk_buff  *skb = NULL;
+       skb = dev_alloc_skb(MAX_CM_BUFFER);
+       if (!skb) {
+               nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+               return -ENOMEM;
+       }
+       /* send an MPA reject frame */
+       form_cm_frame(skb, cm_node, NULL, 0, &cm_node->mpa_frame,
+                       cm_node->mpa_frame_size, SET_ACK | SET_FIN);
+       cm_node->state = NES_CM_STATE_FIN_WAIT1;
+       return schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
  }
  
  
   * recv_mpa - process a received TCP pkt, we are expecting an
   * IETF MPA frame
   */
- static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 len)
+ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 *type,
+               u32 len)
  {
        struct ietf_mpa_frame *mpa_frame;
  
+       *type = NES_MPA_REQUEST_ACCEPT;
        /* assume req frame is in tcp data payload */
        if (len < sizeof(struct ietf_mpa_frame)) {
                nes_debug(NES_DBG_CM, "The received ietf buffer was too small (%x)\n", len);
-               return -1;
+               return -EINVAL;
        }
  
        mpa_frame = (struct ietf_mpa_frame *)buffer;
        if (cm_node->mpa_frame_size + sizeof(struct ietf_mpa_frame) != len) {
                nes_debug(NES_DBG_CM, "The received ietf buffer was not right"
                                " complete (%x + %x != %x)\n",
-                               cm_node->mpa_frame_size, (u32)sizeof(struct ietf_mpa_frame), len);
-               return -1;
+                               cm_node->mpa_frame_size,
+                               (u32)sizeof(struct ietf_mpa_frame), len);
+               return -EINVAL;
+       }
+       /* make sure it does not exceed the max size */
+       if (len > MAX_CM_BUFFER) {
+               nes_debug(NES_DBG_CM, "The received ietf buffer was too large"
+                               " (%x + %x != %x)\n",
+                               cm_node->mpa_frame_size,
+                               (u32)sizeof(struct ietf_mpa_frame), len);
+               return -EINVAL;
        }
  
        /* copy entire MPA frame to our cm_node's frame */
        memcpy(cm_node->mpa_frame_buf, buffer + sizeof(struct ietf_mpa_frame),
                        cm_node->mpa_frame_size);
  
+       if (mpa_frame->flags & IETF_MPA_FLAGS_REJECT)
+               *type = NES_MPA_REQUEST_REJECT;
        return 0;
  }
  
@@@ -380,7 -411,7 +411,7 @@@ int schedule_nes_timer(struct nes_cm_no
  
        new_send = kzalloc(sizeof(*new_send), GFP_ATOMIC);
        if (!new_send)
-               return -1;
+               return -ENOMEM;
  
        /* new_send->timetosend = currenttime */
        new_send->retrycount = NES_DEFAULT_RETRYS;
  
        if (type == NES_TIMER_TYPE_CLOSE) {
                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);
+               if (cm_node->recv_entry) {
+                       WARN_ON(1);
+                       return -EINVAL;
+               }
+               cm_node->recv_entry = new_send;
        }
  
        if (type == NES_TIMER_TYPE_SEND) {
        return ret;
  }
  
+ static void nes_retrans_expired(struct nes_cm_node *cm_node)
+ {
+       switch (cm_node->state) {
+       case NES_CM_STATE_SYN_RCVD:
+       case NES_CM_STATE_CLOSING:
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
+               break;
+       case NES_CM_STATE_LAST_ACK:
+       case NES_CM_STATE_FIN_WAIT1:
+       case NES_CM_STATE_MPAREJ_RCVD:
+               send_reset(cm_node, NULL);
+               break;
+       default:
+               create_event(cm_node, NES_CM_EVENT_ABORTED);
+       }
+ }
+ static void handle_recv_entry(struct nes_cm_node *cm_node, u32 rem_node)
+ {
+       struct nes_timer_entry *recv_entry = cm_node->recv_entry;
+       struct iw_cm_id *cm_id = cm_node->cm_id;
+       struct nes_qp *nesqp;
+       unsigned long qplockflags;
+       if (!recv_entry)
+               return;
+       nesqp = (struct nes_qp *)recv_entry->skb;
+       if (nesqp) {
+               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));
+               }
+       } else if (rem_node) {
+               /* TIME_WAIT state */
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
+       }
+       if (cm_node->cm_id)
+               cm_id->rem_ref(cm_id);
+       kfree(recv_entry);
+       cm_node->recv_entry = NULL;
+ }
  
  /**
   * nes_cm_timer_tick
   */
  static void nes_cm_timer_tick(unsigned long pass)
  {
-       unsigned long flags, qplockflags;
+       unsigned long flags;
        unsigned long nexttimeout = jiffies + NES_LONG_TIME;
-       struct iw_cm_id *cm_id;
        struct nes_cm_node *cm_node;
        struct nes_timer_entry *send_entry, *recv_entry;
-       struct list_head *list_core, *list_core_temp;
-       struct list_head *list_node, *list_node_temp;
+       struct list_head *list_core_temp;
+       struct list_head *list_node;
        struct nes_cm_core *cm_core = g_cm_core;
-       struct nes_qp *nesqp;
        u32 settimer = 0;
        int ret = NETDEV_TX_OK;
-       enum nes_cm_node_state last_state;
  
        struct list_head timer_list;
        INIT_LIST_HEAD(&timer_list);
        list_for_each_safe(list_node, list_core_temp,
                                &cm_core->connected_nodes) {
                cm_node = container_of(list_node, struct nes_cm_node, list);
-               if (!list_empty(&cm_node->recv_list) || (cm_node->send_entry)) {
+               if ((cm_node->recv_entry) || (cm_node->send_entry)) {
                        add_ref_cm_node(cm_node);
                        list_add(&cm_node->timer_entry, &timer_list);
                }
        list_for_each_safe(list_node, list_core_temp, &timer_list) {
                cm_node = container_of(list_node, struct nes_cm_node,
                                        timer_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);
-                       if (!recv_entry)
-                               break;
+               recv_entry = cm_node->recv_entry;
+               if (recv_entry) {
                        if (time_after(recv_entry->timetosend, jiffies)) {
                                if (nexttimeout > recv_entry->timetosend ||
-                                       !settimer) {
+                                               !settimer) {
                                        nexttimeout = recv_entry->timetosend;
                                        settimer = 1;
                                }
-                               continue;
-                       }
-                       list_del(&recv_entry->list);
-                       cm_id = cm_node->cm_id;
-                       spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
-                       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);
+                       } else
+                               handle_recv_entry(cm_node, 1);
                }
-               spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
  
                spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
                do {
                                                nexttimeout =
                                                        send_entry->timetosend;
                                                settimer = 1;
-                                               break;
                                        }
                                } else {
                                        free_retrans_entry(cm_node);
-                                       break;
                                }
+                               break;
                        }
  
                        if ((cm_node->state == NES_CM_STATE_TSA) ||
                        if (!send_entry->retranscount ||
                                !send_entry->retrycount) {
                                cm_packets_dropped++;
-                               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
-                                       create_event(cm_node,
-                                               NES_CM_EVENT_ABORTED);
+                               nes_retrans_expired(cm_node);
+                               cm_node->state = NES_CM_STATE_CLOSED;
                                spin_lock_irqsave(&cm_node->retrans_list_lock,
                                        flags);
                                break;
@@@ -714,7 -760,7 +760,7 @@@ static int send_reset(struct nes_cm_nod
                skb = dev_alloc_skb(MAX_CM_BUFFER);
        if (!skb) {
                nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
-               return -1;
+               return -ENOMEM;
        }
  
        form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, flags);
@@@ -778,14 -824,10 +824,10 @@@ static struct nes_cm_node *find_node(st
        unsigned long flags;
        struct list_head *hte;
        struct nes_cm_node *cm_node;
-       __be32 tmp_addr = cpu_to_be32(loc_addr);
  
        /* get a handle on the hte */
        hte = &cm_core->connected_nodes;
  
-       nes_debug(NES_DBG_CM, "Searching for an owner node: %pI4:%x from core %p->%p\n",
-                 &tmp_addr, loc_port, cm_core, hte);
        /* walk list and find cm_node associated with this session ID */
        spin_lock_irqsave(&cm_core->ht_lock, flags);
        list_for_each_entry(cm_node, hte, list) {
@@@ -875,7 -917,8 +917,8 @@@ static int add_hte_node(struct nes_cm_c
  static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
        struct nes_cm_listener *listener, int free_hanging_nodes)
  {
-       int ret = 1;
+       int ret = -EINVAL;
+       int err = 0;
        unsigned long flags;
        struct list_head *list_pos = NULL;
        struct list_head *list_temp = NULL;
  
        list_for_each_safe(list_pos, list_temp, &reset_list) {
                cm_node = container_of(list_pos, struct nes_cm_node,
-                                       reset_entry);
-               cleanup_retrans_entry(cm_node);
-               send_reset(cm_node, NULL);
-               rem_ref_cm_node(cm_node->cm_core, cm_node);
+                               reset_entry);
+               {
+                       struct nes_cm_node *loopback = cm_node->loopbackpartner;
+                       if (NES_CM_STATE_FIN_WAIT1 <= cm_node->state) {
+                               rem_ref_cm_node(cm_node->cm_core, cm_node);
+                       } else {
+                               if (!loopback) {
+                                       cleanup_retrans_entry(cm_node);
+                                       err = send_reset(cm_node, NULL);
+                                       if (err) {
+                                               cm_node->state =
+                                                        NES_CM_STATE_CLOSED;
+                                               WARN_ON(1);
+                                       } else {
+                                               cm_node->state =
+                                                       NES_CM_STATE_CLOSED;
+                                               rem_ref_cm_node(
+                                                       cm_node->cm_core,
+                                                       cm_node);
+                                       }
+                               } else {
+                                       struct nes_cm_event event;
+                                       event.cm_node = loopback;
+                                       event.cm_info.rem_addr =
+                                                       loopback->rem_addr;
+                                       event.cm_info.loc_addr =
+                                                       loopback->loc_addr;
+                                       event.cm_info.rem_port =
+                                                       loopback->rem_port;
+                                       event.cm_info.loc_port =
+                                                        loopback->loc_port;
+                                       event.cm_info.cm_id = loopback->cm_id;
+                                       cm_event_connect_error(&event);
+                                       loopback->state = NES_CM_STATE_CLOSED;
+                                       event.cm_node = cm_node;
+                                       event.cm_info.rem_addr =
+                                                        cm_node->rem_addr;
+                                       event.cm_info.loc_addr =
+                                                        cm_node->loc_addr;
+                                       event.cm_info.rem_port =
+                                                        cm_node->rem_port;
+                                       event.cm_info.loc_port =
+                                                        cm_node->loc_port;
+                                       event.cm_info.cm_id = cm_node->cm_id;
+                                       cm_event_reset(&event);
+                                       rem_ref_cm_node(cm_node->cm_core,
+                                                        cm_node);
+                               }
+                       }
+               }
        }
  
        spin_lock_irqsave(&cm_core->listen_list_lock, flags);
@@@ -968,6 -1061,7 +1061,7 @@@ static inline int mini_cm_accelerated(s
        if (cm_node->accept_pend) {
                BUG_ON(!cm_node->listener);
                atomic_dec(&cm_node->listener->pend_accepts_cnt);
+               cm_node->accept_pend = 0;
                BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
        }
  
@@@ -994,7 -1088,7 +1088,7 @@@ static int nes_addr_resolve_neigh(struc
        memset(&fl, 0, sizeof fl);
        fl.nl_u.ip4_u.daddr = htonl(dst_ip);
        if (ip_route_output_key(&init_net, &rt, &fl)) {
-               printk("%s: ip_route_output_key failed for 0x%08X\n",
+               printk(KERN_ERR "%s: ip_route_output_key failed for 0x%08X\n",
                                __func__, dst_ip);
                return rc;
        }
@@@ -1057,8 -1151,6 +1151,6 @@@ static struct nes_cm_node *make_cm_node
                        cm_node->cm_id);
  
        spin_lock_init(&cm_node->retrans_list_lock);
-       INIT_LIST_HEAD(&cm_node->recv_list);
-       spin_lock_init(&cm_node->recv_list_lock);
  
        cm_node->loopbackpartner = NULL;
        atomic_set(&cm_node->ref_count, 1);
@@@ -1126,10 -1218,7 +1218,7 @@@ static int add_ref_cm_node(struct nes_c
  static int rem_ref_cm_node(struct nes_cm_core *cm_core,
        struct nes_cm_node *cm_node)
  {
-       unsigned long flags, qplockflags;
-       struct nes_timer_entry *recv_entry;
-       struct iw_cm_id *cm_id;
-       struct list_head *list_core, *list_node_temp;
+       unsigned long flags;
        struct nes_qp *nesqp;
  
        if (!cm_node)
                atomic_dec(&cm_node->listener->pend_accepts_cnt);
                BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
        }
-       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);
-               list_del(&recv_entry->list);
-               cm_id = cm_node->cm_id;
-               spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
-               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);
-       }
-       spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
+       WARN_ON(cm_node->send_entry);
+       if (cm_node->recv_entry)
+               handle_recv_entry(cm_node, 0);
        if (cm_node->listener) {
                mini_cm_dec_refcnt_listen(cm_core, cm_node->listener, 0);
        } else {
@@@ -1266,8 -1326,7 +1326,7 @@@ static void drop_packet(struct sk_buff 
        dev_kfree_skb_any(skb);
  }
  
- static void handle_fin_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
-       struct tcphdr *tcph)
+ static void handle_fin_pkt(struct nes_cm_node *cm_node)
  {
        nes_debug(NES_DBG_CM, "Received FIN, cm_node = %p, state = %u. "
                "refcnt=%d\n", cm_node, cm_node->state,
        case NES_CM_STATE_SYN_SENT:
        case NES_CM_STATE_ESTABLISHED:
        case NES_CM_STATE_MPAREQ_SENT:
+       case NES_CM_STATE_MPAREJ_RCVD:
                cm_node->state = NES_CM_STATE_LAST_ACK;
-               send_fin(cm_node, skb);
+               send_fin(cm_node, NULL);
                break;
        case NES_CM_STATE_FIN_WAIT1:
                cm_node->state = NES_CM_STATE_CLOSING;
-               send_ack(cm_node, skb);
+               send_ack(cm_node, NULL);
+               /* Wait for ACK as this is simultanous close..
+               * After we receive ACK, do not send anything..
+               * Just rm the node.. Done.. */
                break;
        case NES_CM_STATE_FIN_WAIT2:
                cm_node->state = NES_CM_STATE_TIME_WAIT;
-               send_ack(cm_node, skb);
+               send_ack(cm_node, NULL);
+               schedule_nes_timer(cm_node, NULL,  NES_TIMER_TYPE_CLOSE, 1, 0);
+               break;
+       case NES_CM_STATE_TIME_WAIT:
                cm_node->state = NES_CM_STATE_CLOSED;
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
                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;
        }
  }
@@@ -1341,23 -1407,35 +1407,35 @@@ static void handle_rst_pkt(struct nes_c
                cleanup_retrans_entry(cm_node);
                drop_packet(skb);
                break;
+       case NES_CM_STATE_TIME_WAIT:
+               cleanup_retrans_entry(cm_node);
+               cm_node->state = NES_CM_STATE_CLOSED;
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
+               drop_packet(skb);
+               break;
+       case NES_CM_STATE_FIN_WAIT1:
+               cleanup_retrans_entry(cm_node);
+               nes_debug(NES_DBG_CM, "Bad state %s[%u]\n", __func__, __LINE__);
        default:
                drop_packet(skb);
                break;
        }
  }
  
- static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb,
      enum nes_cm_event_type type)
static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb)
  {
  
-       int     ret;
+       int     ret = 0;
        int datasize = skb->len;
        u8 *dataloc = skb->data;
-       ret = parse_mpa(cm_node, dataloc, datasize);
-       if (ret < 0) {
+       enum nes_cm_event_type type = NES_CM_EVENT_UNKNOWN;
+       u32     res_type;
+       ret = parse_mpa(cm_node, dataloc, &res_type, datasize);
+       if (ret) {
                nes_debug(NES_DBG_CM, "didn't like MPA Request\n");
-               if (type == NES_CM_EVENT_CONNECTED) {
+               if (cm_node->state == 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,
                } else {
                        passive_open_err(cm_node, skb, 1);
                }
-       } else {
-               cleanup_retrans_entry(cm_node);
-               dev_kfree_skb_any(skb);
-               if (type == NES_CM_EVENT_CONNECTED)
+               return;
+       }
+       switch (cm_node->state) {
+       case NES_CM_STATE_ESTABLISHED:
+               if (res_type == NES_MPA_REQUEST_REJECT) {
+                       /*BIG problem as we are receiving the MPA.. So should
+                       * not be REJECT.. This is Passive Open.. We can
+                       * only receive it Reject for Active Open...*/
+                       WARN_ON(1);
+               }
+               cm_node->state = NES_CM_STATE_MPAREQ_RCVD;
+               type = NES_CM_EVENT_MPA_REQ;
+               atomic_set(&cm_node->passive_state,
+                               NES_PASSIVE_STATE_INDICATED);
+               break;
+       case NES_CM_STATE_MPAREQ_SENT:
+               if (res_type == NES_MPA_REQUEST_REJECT) {
+                       type = NES_CM_EVENT_MPA_REJECT;
+                       cm_node->state = NES_CM_STATE_MPAREJ_RCVD;
+               } else {
+                       type = NES_CM_EVENT_CONNECTED;
                        cm_node->state = NES_CM_STATE_TSA;
-               else
-                       atomic_set(&cm_node->passive_state,
-                                       NES_PASSIVE_STATE_INDICATED);
-               create_event(cm_node, type);
+               }
  
+               break;
+       default:
+               WARN_ON(1);
+               break;
        }
-       return ;
+       dev_kfree_skb_any(skb);
+       create_event(cm_node, type);
  }
  
  static void indicate_pkt_err(struct nes_cm_node *cm_node, struct sk_buff *skb)
@@@ -1465,8 -1563,6 +1563,6 @@@ static void handle_syn_pkt(struct nes_c
                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 "
                }
                cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;
                BUG_ON(cm_node->send_entry);
+               cm_node->accept_pend = 1;
+               atomic_inc(&cm_node->listener->pend_accepts_cnt);
                cm_node->state = NES_CM_STATE_SYN_RCVD;
                send_syn(cm_node, 1, skb);
                break;
@@@ -1518,6 -1617,7 +1617,7 @@@ static void handle_synack_pkt(struct ne
        inc_sequence = ntohl(tcph->seq);
        switch (cm_node->state) {
        case NES_CM_STATE_SYN_SENT:
+               cleanup_retrans_entry(cm_node);
                /* active open */
                if (check_syn(cm_node, tcph, skb))
                        return;
@@@ -1567,10 -1667,7 +1667,7 @@@ static void handle_ack_pkt(struct nes_c
        u32 rem_seq;
        int ret;
        int optionsize;
-       u32 temp_seq = cm_node->tcp_cntxt.loc_seq_num;
        optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
-       cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
  
        if (check_seq(cm_node, tcph, skb))
                return;
        rem_seq = ntohl(tcph->seq);
        rem_seq_ack =  ntohl(tcph->ack_seq);
        datasize = skb->len;
+       cleanup_retrans_entry(cm_node);
        switch (cm_node->state) {
        case NES_CM_STATE_SYN_RCVD:
                /* Passive OPEN */
                if (ret)
                        break;
                cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
-               cm_node->tcp_cntxt.loc_seq_num = temp_seq;
                if (cm_node->tcp_cntxt.rem_ack_num !=
                    cm_node->tcp_cntxt.loc_seq_num) {
                        nes_debug(NES_DBG_CM, "rem_ack_num != loc_seq_num\n");
                        return;
                }
                cm_node->state = NES_CM_STATE_ESTABLISHED;
+               cleanup_retrans_entry(cm_node);
                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 */
+                       handle_rcv_mpa(cm_node, skb);
+               } 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 */
+               cleanup_retrans_entry(cm_node);
                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);
+                       handle_rcv_mpa(cm_node, skb);
                } else
                        drop_packet(skb);
                break;
        case NES_CM_STATE_MPAREQ_SENT:
+               cleanup_retrans_entry(cm_node);
                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);
+                       handle_rcv_mpa(cm_node, skb);
                } else { /* Could be just an ack pkt.. */
                        cleanup_retrans_entry(cm_node);
                        dev_kfree_skb_any(skb);
                cleanup_retrans_entry(cm_node);
                send_reset(cm_node, skb);
                break;
+       case NES_CM_STATE_LAST_ACK:
+               cleanup_retrans_entry(cm_node);
+               cm_node->state = NES_CM_STATE_CLOSED;
+               cm_node->cm_id->rem_ref(cm_node->cm_id);
+       case NES_CM_STATE_CLOSING:
+               cleanup_retrans_entry(cm_node);
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
+               drop_packet(skb);
+               break;
        case NES_CM_STATE_FIN_WAIT1:
+               cleanup_retrans_entry(cm_node);
+               drop_packet(skb);
+               cm_node->state = NES_CM_STATE_FIN_WAIT2;
+               break;
        case NES_CM_STATE_SYN_SENT:
        case NES_CM_STATE_FIN_WAIT2:
        case NES_CM_STATE_TSA:
        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);
@@@ -1748,6 -1854,7 +1854,7 @@@ static void process_packet(struct nes_c
  {
        enum nes_tcpip_pkt_type pkt_type = NES_PKT_TYPE_UNKNOWN;
        struct tcphdr *tcph = tcp_hdr(skb);
+       u32     fin_set = 0;
        skb_pull(skb, ip_hdr(skb)->ihl << 2);
  
        nes_debug(NES_DBG_CM, "process_packet: cm_node=%p state =%d syn=%d "
                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)
+       } else if (tcph->ack)
                pkt_type = NES_PKT_TYPE_ACK;
+       if (tcph->fin)
+               fin_set = 1;
  
        switch (pkt_type) {
        case NES_PKT_TYPE_SYN:
                break;
        case NES_PKT_TYPE_ACK:
                handle_ack_pkt(cm_node, skb, tcph);
+               if (fin_set)
+                       handle_fin_pkt(cm_node);
                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);
+               if (fin_set)
+                       handle_fin_pkt(cm_node);
                break;
        }
  }
@@@ -1925,7 -2033,7 +2033,7 @@@ static struct nes_cm_node *mini_cm_conn
                                loopbackremotenode->tcp_cntxt.rcv_wscale;
                        loopbackremotenode->tcp_cntxt.snd_wscale =
                                cm_node->tcp_cntxt.rcv_wscale;
+                       loopbackremotenode->state = NES_CM_STATE_MPAREQ_RCVD;
                        create_event(loopbackremotenode, NES_CM_EVENT_MPA_REQ);
                }
                return cm_node;
@@@ -1980,7 -2088,11 +2088,11 @@@ static int mini_cm_reject(struct nes_cm
        struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node)
  {
        int ret = 0;
+       int err = 0;
        int passive_state;
+       struct nes_cm_event event;
+       struct iw_cm_id *cm_id = cm_node->cm_id;
+       struct nes_cm_node *loopback = cm_node->loopbackpartner;
  
        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);
                return ret;
        cleanup_retrans_entry(cm_node);
  
-       passive_state = atomic_add_return(1, &cm_node->passive_state);
-       cm_node->state = NES_CM_STATE_CLOSED;
-       if (passive_state == NES_SEND_RESET_EVENT)
+       if (!loopback) {
+               passive_state = atomic_add_return(1, &cm_node->passive_state);
+               if (passive_state == NES_SEND_RESET_EVENT) {
+                       cm_node->state = NES_CM_STATE_CLOSED;
+                       rem_ref_cm_node(cm_core, cm_node);
+               } else {
+                       ret = send_mpa_reject(cm_node);
+                       if (ret) {
+                               cm_node->state = NES_CM_STATE_CLOSED;
+                               err = send_reset(cm_node, NULL);
+                               if (err)
+                                       WARN_ON(1);
+                       } else
+                               cm_id->add_ref(cm_id);
+               }
+       } else {
+               cm_node->cm_id = NULL;
+               event.cm_node = loopback;
+               event.cm_info.rem_addr = loopback->rem_addr;
+               event.cm_info.loc_addr = loopback->loc_addr;
+               event.cm_info.rem_port = loopback->rem_port;
+               event.cm_info.loc_port = loopback->loc_port;
+               event.cm_info.cm_id = loopback->cm_id;
+               cm_event_mpa_reject(&event);
                rem_ref_cm_node(cm_core, cm_node);
-       else
-               ret = send_reset(cm_node, NULL);
+               loopback->state = NES_CM_STATE_CLOSING;
+               cm_id = loopback->cm_id;
+               rem_ref_cm_node(cm_core, loopback);
+               cm_id->rem_ref(cm_id);
+       }
        return ret;
  }
  
@@@ -2031,6 -2169,7 +2169,7 @@@ static int mini_cm_close(struct nes_cm_
        case NES_CM_STATE_CLOSING:
                ret = -1;
                break;
+       case NES_CM_STATE_MPAREJ_RCVD:
        case NES_CM_STATE_LISTENING:
        case NES_CM_STATE_UNKNOWN:
        case NES_CM_STATE_INITED:
@@@ -2227,15 -2366,15 +2366,15 @@@ static int mini_cm_set(struct nes_cm_co
        int ret = 0;
  
        switch (type) {
-               case NES_CM_SET_PKT_SIZE:
-                       cm_core->mtu = value;
-                       break;
-               case NES_CM_SET_FREE_PKT_Q_SIZE:
-                       cm_core->free_tx_pkt_max = value;
-                       break;
-               default:
-                       /* unknown set option */
-                       ret = -EINVAL;
+       case NES_CM_SET_PKT_SIZE:
+               cm_core->mtu = value;
+               break;
+       case NES_CM_SET_FREE_PKT_Q_SIZE:
+               cm_core->free_tx_pkt_max = value;
+               break;
+       default:
+               /* unknown set option */
+               ret = -EINVAL;
        }
  
        return ret;
@@@ -2490,14 -2629,12 +2629,14 @@@ static int nes_disconnect(struct nes_q
        int ret = 0;
        struct nes_vnic *nesvnic;
        struct nes_device *nesdev;
 +      struct nes_ib_device *nesibdev;
  
        nesvnic = to_nesvnic(nesqp->ibqp.device);
        if (!nesvnic)
                return -EINVAL;
  
        nesdev = nesvnic->nesdev;
 +      nesibdev = nesvnic->nesibdev;
  
        nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",
                        atomic_read(&nesvnic->netdev->refcnt));
        } else {
                /* Need to free the Last Streaming Mode Message */
                if (nesqp->ietf_frame) {
 +                      if (nesqp->lsmm_mr)
 +                              nesibdev->ibdev.dereg_mr(nesqp->lsmm_mr);
                        pci_free_consistent(nesdev->pcidev,
                                        nesqp->private_data_len+sizeof(struct ietf_mpa_frame),
                                        nesqp->ietf_frame, nesqp->ietf_frame_pbase);
@@@ -2547,12 -2682,6 +2686,12 @@@ int nes_accept(struct iw_cm_id *cm_id, 
        u32 crc_value;
        int ret;
        int passive_state;
 +      struct nes_ib_device *nesibdev;
 +      struct ib_mr *ibmr = NULL;
 +      struct ib_phys_buf ibphysbuf;
 +      struct nes_pd *nespd;
 +
 +
  
        ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
        if (!ibqp)
        if (cm_id->remote_addr.sin_addr.s_addr !=
                        cm_id->local_addr.sin_addr.s_addr) {
                u64temp = (unsigned long)nesqp;
 +              nesibdev = nesvnic->nesibdev;
 +              nespd = nesqp->nespd;
 +              ibphysbuf.addr = nesqp->ietf_frame_pbase;
 +              ibphysbuf.size = conn_param->private_data_len +
 +                                      sizeof(struct ietf_mpa_frame);
 +              ibmr = nesibdev->ibdev.reg_phys_mr((struct ib_pd *)nespd,
 +                                              &ibphysbuf, 1,
 +                                              IB_ACCESS_LOCAL_WRITE,
 +                                              (u64 *)&nesqp->ietf_frame);
 +              if (!ibmr) {
 +                      nes_debug(NES_DBG_CM, "Unable to register memory region"
 +                                      "for lSMM for cm_node = %p \n",
 +                                      cm_node);
 +                      return -ENOMEM;
 +              }
 +
 +              ibmr->pd = &nespd->ibpd;
 +              ibmr->device = nespd->ibpd.device;
 +              nesqp->lsmm_mr = ibmr;
 +
                u64temp |= NES_SW_CONTEXT_ALIGN>>1;
                set_wqe_64bit_value(wqe->wqe_words,
                        NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX,
                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));
 +              set_wqe_64bit_value(wqe->wqe_words,
 +                                      NES_IWARP_SQ_WQE_FRAG0_LOW_IDX,
 +                                      (u64)nesqp->ietf_frame);
                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;
 +              wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = ibmr->lkey;
  
                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));
+                       cpu_to_le32(NES_QPCONTEXT_ORDIRD_WRPDU);
        }
        nesqp->skip_lsmm = 1;
  
  int nes_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
  {
        struct nes_cm_node *cm_node;
+       struct nes_cm_node *loopback;
        struct nes_cm_core *cm_core;
  
        atomic_inc(&cm_rejects);
        cm_node = (struct nes_cm_node *) cm_id->provider_data;
+       loopback = cm_node->loopbackpartner;
        cm_core = cm_node->cm_core;
+       cm_node->cm_id = cm_id;
        cm_node->mpa_frame_size = sizeof(struct ietf_mpa_frame) + pdata_len;
  
+       if (cm_node->mpa_frame_size > MAX_CM_BUFFER)
+               return -EINVAL;
        strcpy(&cm_node->mpa_frame.key[0], IEFT_MPA_KEY_REP);
-       memcpy(&cm_node->mpa_frame.priv_data, pdata, pdata_len);
+       if (loopback) {
+               memcpy(&loopback->mpa_frame.priv_data, pdata, pdata_len);
+               loopback->mpa_frame.priv_data_len = pdata_len;
+               loopback->mpa_frame_size = sizeof(struct ietf_mpa_frame) +
+                               pdata_len;
+       } else {
+               memcpy(&cm_node->mpa_frame.priv_data, pdata, pdata_len);
+               cm_node->mpa_frame.priv_data_len = cpu_to_be16(pdata_len);
+       }
  
-       cm_node->mpa_frame.priv_data_len = cpu_to_be16(pdata_len);
        cm_node->mpa_frame.rev = mpa_version;
        cm_node->mpa_frame.flags = IETF_MPA_FLAGS_CRC | IETF_MPA_FLAGS_REJECT;
  
-       cm_core->api->reject(cm_core, &cm_node->mpa_frame, cm_node);
-       return 0;
+       return cm_core->api->reject(cm_core, &cm_node->mpa_frame, cm_node);
  }
  
  
@@@ -3300,16 -3420,59 +3449,59 @@@ static void cm_event_mpa_req(struct nes
        cm_event.local_addr.sin_port = htons(event->cm_info.loc_port);
        cm_event.local_addr.sin_addr.s_addr = htonl(event->cm_info.loc_addr);
  
+       cm_event.remote_addr.sin_family = AF_INET;
+       cm_event.remote_addr.sin_port = htons(event->cm_info.rem_port);
+       cm_event.remote_addr.sin_addr.s_addr = htonl(event->cm_info.rem_addr);
+       cm_event.private_data = cm_node->mpa_frame_buf;
+       cm_event.private_data_len  = (u8) cm_node->mpa_frame_size;
+       ret = cm_id->event_handler(cm_id, &cm_event);
+       if (ret)
+               printk(KERN_ERR "%s[%u] OFA CM event_handler returned, ret=%d\n",
+                               __func__, __LINE__, ret);
+       return;
+ }
+ static void cm_event_mpa_reject(struct nes_cm_event *event)
+ {
+       struct iw_cm_id   *cm_id;
+       struct iw_cm_event cm_event;
+       struct nes_cm_node *cm_node;
+       int ret;
+       cm_node = event->cm_node;
+       if (!cm_node)
+               return;
+       cm_id = cm_node->cm_id;
+       atomic_inc(&cm_connect_reqs);
+       nes_debug(NES_DBG_CM, "cm_node = %p - cm_id = %p, jiffies = %lu\n",
+                       cm_node, cm_id, jiffies);
+       cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
+       cm_event.status = -ECONNREFUSED;
+       cm_event.provider_data = cm_id->provider_data;
+       cm_event.local_addr.sin_family = AF_INET;
+       cm_event.local_addr.sin_port = htons(event->cm_info.loc_port);
+       cm_event.local_addr.sin_addr.s_addr = htonl(event->cm_info.loc_addr);
        cm_event.remote_addr.sin_family = AF_INET;
        cm_event.remote_addr.sin_port = htons(event->cm_info.rem_port);
        cm_event.remote_addr.sin_addr.s_addr = htonl(event->cm_info.rem_addr);
  
-               cm_event.private_data                = cm_node->mpa_frame_buf;
-               cm_event.private_data_len            = (u8) cm_node->mpa_frame_size;
+       cm_event.private_data = cm_node->mpa_frame_buf;
+       cm_event.private_data_len = (u8) cm_node->mpa_frame_size;
+       nes_debug(NES_DBG_CM, "call CM_EVENT_MPA_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);
        if (ret)
-               printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+               printk(KERN_ERR "%s[%u] OFA CM event_handler returned, ret=%d\n",
                                __func__, __LINE__, ret);
  
        return;
@@@ -3374,6 -3537,14 +3566,14 @@@ static void nes_cm_event_handler(struc
                cm_event_connected(event);
                nes_debug(NES_DBG_CM, "CM Event: CONNECTED\n");
                break;
+       case NES_CM_EVENT_MPA_REJECT:
+               if ((!event->cm_node->cm_id) ||
+                               (event->cm_node->state == NES_CM_STATE_TSA))
+                       break;
+               cm_event_mpa_reject(event);
+               nes_debug(NES_DBG_CM, "CM Event: REJECT\n");
+               break;
        case NES_CM_EVENT_ABORTED:
                if ((!event->cm_node->cm_id) ||
                        (event->cm_node->state == NES_CM_STATE_TSA))
index d93a6562817ce2e0bfb27caeef26024544731971,96d953540a2c5e16fd157c766cd77104f0c4b7d0..7e5b5ba13a74f83b227959475a751273ab6b3bce
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+  * Copyright (c) 2006 - 2009 Intel-NE, Inc.  All rights reserved.
   *
   * This software is available to you under a choice of one of two
   * licenses.  You may choose to be licensed under the terms of the GNU
@@@ -551,6 -551,7 +551,7 @@@ static int nes_dealloc_fmr(struct ib_fm
        struct nes_device *nesdev = nesvnic->nesdev;
        struct nes_adapter *nesadapter = nesdev->nesadapter;
        int i = 0;
+       int rc;
  
        /* free the resources */
        if (nesfmr->leaf_pbl_cnt == 0) {
        nesmr->ibmw.rkey = ibfmr->rkey;
        nesmr->ibmw.uobject = NULL;
  
-       if (nesfmr->nesmr.pbls_used != 0) {
+       rc = nes_dealloc_mw(&nesmr->ibmw);
+       if ((rc == 0) && (nesfmr->nesmr.pbls_used != 0)) {
                spin_lock_irqsave(&nesadapter->pbl_lock, flags);
                if (nesfmr->nesmr.pbl_4k) {
                        nesadapter->free_4kpbl += nesfmr->nesmr.pbls_used;
                spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
        }
  
-       return nes_dealloc_mw(&nesmr->ibmw);
+       return rc;
  }
  
  
@@@ -1360,10 -1363,8 +1363,10 @@@ static struct ib_qp *nes_create_qp(stru
                                        NES_QPCONTEXT_MISC_RQ_SIZE_SHIFT);
                        nesqp->nesqp_context->misc |= cpu_to_le32((u32)nesqp->hwqp.sq_encoded_size <<
                                        NES_QPCONTEXT_MISC_SQ_SIZE_SHIFT);
 +                      if (!udata) {
                                nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_PRIV_EN);
                                nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_FAST_REGISTER_EN);
 +                      }
                        nesqp->nesqp_context->cqs = cpu_to_le32(nesqp->nesscq->hw_cq.cq_number +
                                        ((u32)nesqp->nesrcq->hw_cq.cq_number << 16));
                        u64temp = (u64)nesqp->hwqp.sq_pbase;
@@@ -1886,21 -1887,75 +1889,75 @@@ static int nes_destroy_cq(struct ib_cq 
        return ret;
  }
  
+ /**
+  * root_256
+  */
+ static u32 root_256(struct nes_device *nesdev,
+                   struct nes_root_vpbl *root_vpbl,
+                   struct nes_root_vpbl *new_root,
+                   u16 pbl_count_4k,
+                   u16 pbl_count_256)
+ {
+       u64 leaf_pbl;
+       int i, j, k;
+       if (pbl_count_4k == 1) {
+               new_root->pbl_vbase = pci_alloc_consistent(nesdev->pcidev,
+                                               512, &new_root->pbl_pbase);
+               if (new_root->pbl_vbase == NULL)
+                       return 0;
+               leaf_pbl = (u64)root_vpbl->pbl_pbase;
+               for (i = 0; i < 16; i++) {
+                       new_root->pbl_vbase[i].pa_low =
+                               cpu_to_le32((u32)leaf_pbl);
+                       new_root->pbl_vbase[i].pa_high =
+                               cpu_to_le32((u32)((((u64)leaf_pbl) >> 32)));
+                       leaf_pbl += 256;
+               }
+       } else {
+               for (i = 3; i >= 0; i--) {
+                       j = i * 16;
+                       root_vpbl->pbl_vbase[j] = root_vpbl->pbl_vbase[i];
+                       leaf_pbl = le32_to_cpu(root_vpbl->pbl_vbase[j].pa_low) +
+                           (((u64)le32_to_cpu(root_vpbl->pbl_vbase[j].pa_high))
+                               << 32);
+                       for (k = 1; k < 16; k++) {
+                               leaf_pbl += 256;
+                               root_vpbl->pbl_vbase[j + k].pa_low =
+                                               cpu_to_le32((u32)leaf_pbl);
+                               root_vpbl->pbl_vbase[j + k].pa_high =
+                                   cpu_to_le32((u32)((((u64)leaf_pbl) >> 32)));
+                       }
+               }
+       }
+       return 1;
+ }
  
  /**
   * nes_reg_mr
   */
  static int nes_reg_mr(struct nes_device *nesdev, struct nes_pd *nespd,
                u32 stag, u64 region_length, struct nes_root_vpbl *root_vpbl,
-               dma_addr_t single_buffer, u16 pbl_count, u16 residual_page_count,
-               int acc, u64 *iova_start)
+               dma_addr_t single_buffer, u16 pbl_count_4k,
+               u16 residual_page_count_4k, int acc, u64 *iova_start,
+               u16 *actual_pbl_cnt, u8 *used_4k_pbls)
  {
        struct nes_hw_cqp_wqe *cqp_wqe;
        struct nes_cqp_request *cqp_request;
        unsigned long flags;
        int ret;
        struct nes_adapter *nesadapter = nesdev->nesadapter;
-       /* int count; */
+       uint pg_cnt = 0;
+       u16 pbl_count_256;
+       u16 pbl_count = 0;
+       u8  use_256_pbls = 0;
+       u8  use_4k_pbls = 0;
+       u16 use_two_level = (pbl_count_4k > 1) ? 1 : 0;
+       struct nes_root_vpbl new_root = {0, 0, 0};
        u32 opcode = 0;
        u16 major_code;
  
        cqp_request->waiting = 1;
        cqp_wqe = &cqp_request->cqp_wqe;
  
-       spin_lock_irqsave(&nesadapter->pbl_lock, flags);
-       /* track PBL resources */
-       if (pbl_count != 0) {
-               if (pbl_count > 1) {
-                       /* Two level PBL */
-                       if ((pbl_count+1) > nesadapter->free_4kpbl) {
-                               nes_debug(NES_DBG_MR, "Out of 4KB Pbls for two level request.\n");
-                               spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
-                               nes_free_cqp_request(nesdev, cqp_request);
-                               return -ENOMEM;
-                       } else {
-                               nesadapter->free_4kpbl -= pbl_count+1;
-                       }
-               } else if (residual_page_count > 32) {
-                       if (pbl_count > nesadapter->free_4kpbl) {
-                               nes_debug(NES_DBG_MR, "Out of 4KB Pbls.\n");
-                               spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
-                               nes_free_cqp_request(nesdev, cqp_request);
-                               return -ENOMEM;
-                       } else {
-                               nesadapter->free_4kpbl -= pbl_count;
+       if (pbl_count_4k) {
+               spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+               pg_cnt = ((pbl_count_4k - 1) * 512) + residual_page_count_4k;
+               pbl_count_256 = (pg_cnt + 31) / 32;
+               if (pg_cnt <= 32) {
+                       if (pbl_count_256 <= nesadapter->free_256pbl)
+                               use_256_pbls = 1;
+                       else if (pbl_count_4k <= nesadapter->free_4kpbl)
+                               use_4k_pbls = 1;
+               } else if (pg_cnt <= 2048) {
+                       if (((pbl_count_4k + use_two_level) <= nesadapter->free_4kpbl) &&
+                           (nesadapter->free_4kpbl > (nesadapter->max_4kpbl >> 1))) {
+                               use_4k_pbls = 1;
+                       } else if ((pbl_count_256 + 1) <= nesadapter->free_256pbl) {
+                               use_256_pbls = 1;
+                               use_two_level = 1;
+                       } else if ((pbl_count_4k + use_two_level) <= nesadapter->free_4kpbl) {
+                               use_4k_pbls = 1;
                        }
                } else {
-                       if (pbl_count > nesadapter->free_256pbl) {
-                               nes_debug(NES_DBG_MR, "Out of 256B Pbls.\n");
-                               spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
-                               nes_free_cqp_request(nesdev, cqp_request);
-                               return -ENOMEM;
-                       } else {
-                               nesadapter->free_256pbl -= pbl_count;
-                       }
+                       if ((pbl_count_4k + 1) <= nesadapter->free_4kpbl)
+                               use_4k_pbls = 1;
                }
+               if (use_256_pbls) {
+                       pbl_count = pbl_count_256;
+                       nesadapter->free_256pbl -= pbl_count + use_two_level;
+               } else if (use_4k_pbls) {
+                       pbl_count =  pbl_count_4k;
+                       nesadapter->free_4kpbl -= pbl_count + use_two_level;
+               } else {
+                       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+                       nes_debug(NES_DBG_MR, "Out of Pbls\n");
+                       nes_free_cqp_request(nesdev, cqp_request);
+                       return -ENOMEM;
+               }
+               spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
        }
  
-       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+       if (use_256_pbls && use_two_level) {
+               if (root_256(nesdev, root_vpbl, &new_root, pbl_count_4k, pbl_count_256) == 1) {
+                       if (new_root.pbl_pbase != 0)
+                               root_vpbl = &new_root;
+               } else {
+                       spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+                       nesadapter->free_256pbl += pbl_count_256 + use_two_level;
+                       use_256_pbls = 0;
+                       if (pbl_count_4k == 1)
+                               use_two_level = 0;
+                       pbl_count = pbl_count_4k;
+                       if ((pbl_count_4k + use_two_level) <= nesadapter->free_4kpbl) {
+                               nesadapter->free_4kpbl -= pbl_count + use_two_level;
+                               use_4k_pbls = 1;
+                       }
+                       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+                       if (use_4k_pbls == 0)
+                               return -ENOMEM;
+               }
+       }
  
        opcode = NES_CQP_REGISTER_STAG | NES_CQP_STAG_RIGHTS_LOCAL_READ |
                                        NES_CQP_STAG_VA_TO | NES_CQP_STAG_MR;
        } else {
                set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PA_LOW_IDX, root_vpbl->pbl_pbase);
                set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX, pbl_count);
-               set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PBL_LEN_IDX,
-                               (((pbl_count - 1) * 4096) + (residual_page_count*8)));
+               set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PBL_LEN_IDX, (pg_cnt * 8));
  
-               if ((pbl_count > 1) || (residual_page_count > 32))
+               if (use_4k_pbls)
                        cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(NES_CQP_STAG_PBL_BLK_SIZE);
        }
        barrier();
        major_code = cqp_request->major_code;
        nes_put_cqp_request(nesdev, cqp_request);
  
+       if ((!ret || major_code) && pbl_count != 0) {
+               spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+               if (use_256_pbls)
+                       nesadapter->free_256pbl += pbl_count + use_two_level;
+               else if (use_4k_pbls)
+                       nesadapter->free_4kpbl += pbl_count + use_two_level;
+               spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+       }
+       if (new_root.pbl_pbase)
+               pci_free_consistent(nesdev->pcidev, 512, new_root.pbl_vbase,
+                                   new_root.pbl_pbase);
        if (!ret)
                return -ETIME;
        else if (major_code)
                return -EIO;
-       else
-               return 0;
  
+       *actual_pbl_cnt = pbl_count + use_two_level;
+       *used_4k_pbls = use_4k_pbls;
        return 0;
  }
  
@@@ -2167,18 -2262,14 +2264,14 @@@ static struct ib_mr *nes_reg_phys_mr(st
                pbl_count = root_pbl_index;
        }
        ret = nes_reg_mr(nesdev, nespd, stag, region_length, &root_vpbl,
-                       buffer_list[0].addr, pbl_count, (u16)cur_pbl_index, acc, iova_start);
+                       buffer_list[0].addr, pbl_count, (u16)cur_pbl_index, acc, iova_start,
+                       &nesmr->pbls_used, &nesmr->pbl_4k);
  
        if (ret == 0) {
                nesmr->ibmr.rkey = stag;
                nesmr->ibmr.lkey = stag;
                nesmr->mode = IWNES_MEMREG_TYPE_MEM;
                ibmr = &nesmr->ibmr;
-               nesmr->pbl_4k = ((pbl_count > 1) || (cur_pbl_index > 32)) ? 1 : 0;
-               nesmr->pbls_used = pbl_count;
-               if (pbl_count > 1) {
-                       nesmr->pbls_used++;
-               }
        } else {
                kfree(nesmr);
                ibmr = ERR_PTR(-ENOMEM);
@@@ -2456,8 -2547,9 +2549,9 @@@ static struct ib_mr *nes_reg_user_mr(st
                                        stag, (unsigned int)iova_start,
                                        (unsigned int)region_length, stag_index,
                                        (unsigned long long)region->length, pbl_count);
-                       ret = nes_reg_mr( nesdev, nespd, stag, region->length, &root_vpbl,
-                                       first_dma_addr, pbl_count, (u16)cur_pbl_index, acc, &iova_start);
+                       ret = nes_reg_mr(nesdev, nespd, stag, region->length, &root_vpbl,
+                                        first_dma_addr, pbl_count, (u16)cur_pbl_index, acc,
+                                        &iova_start, &nesmr->pbls_used, &nesmr->pbl_4k);
  
                        nes_debug(NES_DBG_MR, "ret=%d\n", ret);
  
                                nesmr->ibmr.lkey = stag;
                                nesmr->mode = IWNES_MEMREG_TYPE_MEM;
                                ibmr = &nesmr->ibmr;
-                               nesmr->pbl_4k = ((pbl_count > 1) || (cur_pbl_index > 32)) ? 1 : 0;
-                               nesmr->pbls_used = pbl_count;
-                               if (pbl_count > 1) {
-                                       nesmr->pbls_used++;
-                               }
                        } else {
                                ib_umem_release(region);
                                kfree(nesmr);
@@@ -2609,24 -2696,6 +2698,6 @@@ static int nes_dereg_mr(struct ib_mr *i
        cqp_request->waiting = 1;
        cqp_wqe = &cqp_request->cqp_wqe;
  
-       spin_lock_irqsave(&nesadapter->pbl_lock, flags);
-       if (nesmr->pbls_used != 0) {
-               if (nesmr->pbl_4k) {
-                       nesadapter->free_4kpbl += nesmr->pbls_used;
-                       if (nesadapter->free_4kpbl > nesadapter->max_4kpbl) {
-                               printk(KERN_ERR PFX "free 4KB PBLs(%u) has exceeded the max(%u)\n",
-                                               nesadapter->free_4kpbl, nesadapter->max_4kpbl);
-                       }
-               } else {
-                       nesadapter->free_256pbl += nesmr->pbls_used;
-                       if (nesadapter->free_256pbl > nesadapter->max_256pbl) {
-                               printk(KERN_ERR PFX "free 256B PBLs(%u) has exceeded the max(%u)\n",
-                                               nesadapter->free_256pbl, nesadapter->max_256pbl);
-                       }
-               }
-       }
-       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
        nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
        set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
                        NES_CQP_DEALLOCATE_STAG | NES_CQP_STAG_VA_TO |
                        " CQP Major:Minor codes = 0x%04X:0x%04X\n",
                        ib_mr->rkey, ret, cqp_request->major_code, cqp_request->minor_code);
  
-       nes_free_resource(nesadapter, nesadapter->allocated_mrs,
-                       (ib_mr->rkey & 0x0fffff00) >> 8);
-       kfree(nesmr);
        major_code = cqp_request->major_code;
        minor_code = cqp_request->minor_code;
  
                                " to destroy STag, ib_mr=%p, rkey = 0x%08X\n",
                                major_code, minor_code, ib_mr, ib_mr->rkey);
                return -EIO;
-       } else
-               return 0;
+       }
+       if (nesmr->pbls_used != 0) {
+               spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+               if (nesmr->pbl_4k) {
+                       nesadapter->free_4kpbl += nesmr->pbls_used;
+                       if (nesadapter->free_4kpbl > nesadapter->max_4kpbl)
+                               printk(KERN_ERR PFX "free 4KB PBLs(%u) has "
+                                       "exceeded the max(%u)\n",
+                                       nesadapter->free_4kpbl,
+                                       nesadapter->max_4kpbl);
+               } else {
+                       nesadapter->free_256pbl += nesmr->pbls_used;
+                       if (nesadapter->free_256pbl > nesadapter->max_256pbl)
+                               printk(KERN_ERR PFX "free 256B PBLs(%u) has "
+                                       "exceeded the max(%u)\n",
+                                       nesadapter->free_256pbl,
+                                       nesadapter->max_256pbl);
+               }
+               spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+       }
+       nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+                       (ib_mr->rkey & 0x0fffff00) >> 8);
+       kfree(nesmr);
+       return 0;
  }
  
  
index ae0ca9bc83bd9aae7a8fd83dd4c9165939af051e,da3c368f1ef86be95133887751fe57bebf4867ff..5e48f67fbe8dcd458018243084989648d2bfd778
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+  * Copyright (c) 2006 - 2009 Intel-NE, Inc.  All rights reserved.
   * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
   *
   * This software is available to you under a choice of one of two
@@@ -134,7 -134,6 +134,7 @@@ struct nes_qp 
        struct ietf_mpa_frame *ietf_frame;
        dma_addr_t            ietf_frame_pbase;
        wait_queue_head_t     state_waitq;
 +      struct ib_mr          *lsmm_mr;
        unsigned long         socket;
        struct nes_hw_qp      hwqp;
        struct work_struct    work;